1 |
dpavlin |
1 |
/* |
2 |
|
|
* PearPC |
3 |
|
|
* sysdisplay.cc - screen access functions for X11 |
4 |
|
|
* |
5 |
|
|
* Copyright (C) 1999-2002 Stefan Weyergraf |
6 |
|
|
* Copyright (C) 1999-2004 Sebastian Biallas (sb@biallas.net) |
7 |
|
|
* |
8 |
|
|
* This program is free software; you can redistribute it and/or modify |
9 |
|
|
* it under the terms of the GNU General Public License version 2 as |
10 |
|
|
* published by the Free Software Foundation. |
11 |
|
|
* |
12 |
|
|
* This program is distributed in the hope that it will be useful, |
13 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
|
|
* GNU General Public License for more details. |
16 |
|
|
* |
17 |
|
|
* You should have received a copy of the GNU General Public License |
18 |
|
|
* along with this program; if not, write to the Free Software |
19 |
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
20 |
|
|
*/ |
21 |
|
|
|
22 |
|
|
#include <csignal> |
23 |
|
|
#include <cstdlib> |
24 |
|
|
#include <unistd.h> |
25 |
|
|
#include <cstring> |
26 |
|
|
|
27 |
|
|
#include <X11/Xutil.h> |
28 |
|
|
|
29 |
|
|
#include "system/display.h" |
30 |
|
|
#include "system/types.h" |
31 |
|
|
#include "system/systhread.h" |
32 |
|
|
#include "system/sysexcept.h" |
33 |
|
|
#include "system/sysvaccel.h" |
34 |
|
|
#include "tools/data.h" |
35 |
|
|
#include "tools/snprintf.h" |
36 |
|
|
//#include "configparser.h" |
37 |
|
|
|
38 |
|
|
#include "sysx11.h" |
39 |
|
|
|
40 |
|
|
#define DPRINTF(a...) |
41 |
|
|
//#define DPRINTF(a...) ht_printf(a) |
42 |
|
|
|
43 |
|
|
static void findMaskShiftAndSize(int &shift, int &size, uint bitmask) |
44 |
|
|
{ |
45 |
|
|
if (!bitmask) { |
46 |
|
|
shift = 0; |
47 |
|
|
size = 0; |
48 |
|
|
return; |
49 |
|
|
} |
50 |
|
|
shift = 0; |
51 |
|
|
while (!(bitmask & 1)) { |
52 |
|
|
shift++; |
53 |
|
|
bitmask >>= 1; |
54 |
|
|
} |
55 |
|
|
size = 0; |
56 |
|
|
while (bitmask & 1) { |
57 |
|
|
size++; |
58 |
|
|
bitmask >>= 1; |
59 |
|
|
} |
60 |
|
|
} |
61 |
|
|
|
62 |
|
|
class X11SystemDisplay: public SystemDisplay |
63 |
|
|
{ |
64 |
|
|
byte * mXFrameBuffer; |
65 |
|
|
GC mXGC; |
66 |
|
|
XImage * mXImage; |
67 |
|
|
XImage * mMenuXImage; |
68 |
|
|
XImage * mMouseXImage; |
69 |
|
|
Colormap mDefaultColormap; |
70 |
|
|
|
71 |
|
|
DisplayCharacteristics mXChar; |
72 |
|
|
char *mTitle; |
73 |
|
|
char mCurTitle[200]; |
74 |
|
|
byte *mouseData; |
75 |
|
|
byte *menuData; |
76 |
|
|
|
77 |
|
|
int bitsPerPixelToXBitmapPad(int bitsPerPixel) |
78 |
|
|
{ |
79 |
|
|
if (bitsPerPixel <= 8) { |
80 |
|
|
return 8; |
81 |
|
|
} else if (bitsPerPixel <= 16) { |
82 |
|
|
return 16; |
83 |
|
|
} else { |
84 |
|
|
return 32; |
85 |
|
|
} |
86 |
|
|
} |
87 |
|
|
public: |
88 |
|
|
X11SystemDisplay(const char *name, const DisplayCharacteristics &aClientChar, int redraw_ms) |
89 |
|
|
:SystemDisplay(aClientChar, redraw_ms) |
90 |
|
|
{ |
91 |
|
|
if (bitsPerPixelToXBitmapPad(mClientChar.bytesPerPixel*8) != mClientChar.bytesPerPixel*8) { |
92 |
|
|
ht_printf("nope. bytes per pixel is: %d. only 1,2 or 4 are allowed.\n", mClientChar.bytesPerPixel); |
93 |
|
|
exit(1); |
94 |
|
|
} |
95 |
|
|
|
96 |
|
|
// mouse |
97 |
|
|
mouseData = (byte*)malloc(2 * 2 * mClientChar.bytesPerPixel); |
98 |
|
|
memset(mouseData, 0, 2 * 2 * mClientChar.bytesPerPixel); |
99 |
|
|
|
100 |
|
|
// menu |
101 |
|
|
// mMenuHeight = 28; |
102 |
|
|
mMenuHeight = 0; |
103 |
|
|
menuData = NULL; |
104 |
|
|
|
105 |
|
|
mXImage = NULL; |
106 |
|
|
|
107 |
|
|
mClientChar = aClientChar; |
108 |
|
|
convertCharacteristicsToHost(mXChar, mClientChar); |
109 |
|
|
|
110 |
|
|
int screen_num = DefaultScreen(gX11Display); |
111 |
|
|
gX11Window = XCreateSimpleWindow(gX11Display, |
112 |
|
|
RootWindow(gX11Display, screen_num), 0, 0, |
113 |
|
|
mClientChar.width, mClientChar.height+mMenuHeight, |
114 |
|
|
0, BlackPixel(gX11Display, screen_num), |
115 |
|
|
BlackPixel(gX11Display, screen_num)); |
116 |
|
|
|
117 |
|
|
XStoreName(gX11Display, gX11Window, name); |
118 |
|
|
|
119 |
|
|
XSetWindowAttributes attr; |
120 |
|
|
attr.save_under = 1; |
121 |
|
|
attr.backing_store = Always; |
122 |
|
|
XChangeWindowAttributes(gX11Display, gX11Window, CWSaveUnder|CWBackingStore, &attr); |
123 |
|
|
|
124 |
|
|
mDefaultColormap = DefaultColormap(gX11Display, screen_num); |
125 |
|
|
|
126 |
|
|
XSelectInput(gX11Display, gX11Window, |
127 |
|
|
ExposureMask | KeyPressMask | KeyReleaseMask |
128 |
|
|
| ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
129 |
|
|
| EnterWindowMask | LeaveWindowMask | StructureNotifyMask |
130 |
|
|
| VisibilityChangeMask | FocusChangeMask); |
131 |
|
|
|
132 |
|
|
XMapWindow(gX11Display, gX11Window); |
133 |
|
|
|
134 |
|
|
XEvent event; |
135 |
|
|
XNextEvent(gX11Display, &event); |
136 |
|
|
|
137 |
|
|
uint XDepth = mXChar.redSize + mXChar.greenSize + mXChar.blueSize; |
138 |
|
|
|
139 |
|
|
mMouseXImage = XCreateImage(gX11Display, DefaultVisual(gX11Display, screen_num), |
140 |
|
|
XDepth, ZPixmap, 0, (char*)mouseData, |
141 |
|
|
2, 2, |
142 |
|
|
mXChar.bytesPerPixel*8, 0); |
143 |
|
|
|
144 |
|
|
mXGC = DefaultGC(gX11Display, screen_num); |
145 |
|
|
|
146 |
|
|
// setup interna |
147 |
|
|
gFrameBuffer = NULL; |
148 |
|
|
reinitChar(); |
149 |
|
|
|
150 |
|
|
// clear fb once on startup |
151 |
|
|
memset(gFrameBuffer, 0, mClientChar.width * |
152 |
|
|
mClientChar.height * mClientChar.bytesPerPixel); |
153 |
|
|
|
154 |
|
|
#if 0 |
155 |
|
|
fprintf(stderr, "X Server display characteristics:\n"); |
156 |
|
|
dumpDisplayChar(mXChar); |
157 |
|
|
fprintf(stderr, "Client display characteristics:\n"); |
158 |
|
|
dumpDisplayChar(mClientChar); |
159 |
|
|
#endif |
160 |
|
|
|
161 |
|
|
// finally set title |
162 |
|
|
mTitle = strdup(name); |
163 |
|
|
} |
164 |
|
|
|
165 |
|
|
virtual ~X11SystemDisplay() |
166 |
|
|
{ |
167 |
|
|
gX11Display = NULL; |
168 |
|
|
free(mTitle); |
169 |
|
|
free(mouseData); |
170 |
|
|
free(gFrameBuffer); |
171 |
|
|
if (menuData) free(menuData); |
172 |
|
|
} |
173 |
|
|
|
174 |
|
|
virtual void finishMenu() |
175 |
|
|
{ |
176 |
|
|
menuData = (byte*)malloc(mXChar.width * |
177 |
|
|
mMenuHeight * mXChar.bytesPerPixel); |
178 |
|
|
mMenuXImage = XCreateImage(gX11Display, DefaultVisual(gX11Display, DefaultScreen(gX11Display)), |
179 |
|
|
mXChar.redSize+mXChar.greenSize+mXChar.blueSize, ZPixmap, 0, (char*)menuData, |
180 |
|
|
mXChar.width, mMenuHeight, |
181 |
|
|
mXChar.bytesPerPixel*8, 0); |
182 |
|
|
|
183 |
|
|
// Is this ugly? Yes! |
184 |
|
|
fillRGB(0, 0, mClientChar.width, mClientChar.height, MK_RGB(0xff, 0xff, 0xff)); |
185 |
|
|
drawMenu(); |
186 |
|
|
// convertDisplayClientToServer(0, mClientChar.height-1); |
187 |
|
|
if (mXFrameBuffer) { |
188 |
|
|
sys_convert_display(mClientChar, mXChar, gFrameBuffer, mXFrameBuffer, 0, mClientChar.height-1); |
189 |
|
|
memmove(menuData, mXFrameBuffer, mXChar.width * mMenuHeight |
190 |
|
|
* mXChar.bytesPerPixel); |
191 |
|
|
} else { |
192 |
|
|
memmove(menuData, gFrameBuffer, mXChar.width * mMenuHeight |
193 |
|
|
* mXChar.bytesPerPixel); |
194 |
|
|
} |
195 |
|
|
} |
196 |
|
|
|
197 |
|
|
/* |
198 |
|
|
* must be called with gX11Mutex locked |
199 |
|
|
*/ |
200 |
|
|
void reinitChar() |
201 |
|
|
{ |
202 |
|
|
gFrameBuffer = (byte*)realloc(gFrameBuffer, mClientChar.width * |
203 |
|
|
mClientChar.height * mClientChar.bytesPerPixel); |
204 |
|
|
damageFrameBufferAll(); |
205 |
|
|
|
206 |
|
|
mHomeMouseX = mClientChar.width / 2; |
207 |
|
|
mHomeMouseY = mClientChar.height / 2; |
208 |
|
|
|
209 |
|
|
uint XDepth = mXChar.redSize + mXChar.greenSize + mXChar.blueSize; |
210 |
|
|
int screen_num = DefaultScreen(gX11Display); |
211 |
|
|
|
212 |
|
|
if (mXImage) XDestroyImage(mXImage); // no need to free gXFrameBuffer. XDeleteImage does this. |
213 |
|
|
|
214 |
|
|
// Maybe client and (X-)server display characteristics match |
215 |
|
|
if (0 && memcmp(&mClientChar, &mXChar, sizeof (mClientChar)) == 0) { |
216 |
|
|
// fprintf(stderr, "client and server display characteristics match!!\n"); |
217 |
|
|
mXFrameBuffer = NULL; |
218 |
|
|
|
219 |
|
|
mXImage = XCreateImage(gX11Display, DefaultVisual(gX11Display, screen_num), |
220 |
|
|
XDepth, ZPixmap, 0, (char*)gFrameBuffer, |
221 |
|
|
mXChar.width, mXChar.height, |
222 |
|
|
mXChar.bytesPerPixel*8, 0); |
223 |
|
|
} else { |
224 |
|
|
// Otherwise we need a second framebuffer |
225 |
|
|
// fprintf(stderr, "client and server display characteristics DONT match :-(\n"); |
226 |
|
|
mXFrameBuffer = (byte*)malloc(mXChar.width |
227 |
|
|
* mXChar.height * mXChar.bytesPerPixel); |
228 |
|
|
|
229 |
|
|
mXImage = XCreateImage(gX11Display, DefaultVisual(gX11Display, screen_num), |
230 |
|
|
XDepth, ZPixmap, 0, (char*)mXFrameBuffer, |
231 |
|
|
mXChar.width, mXChar.height, |
232 |
|
|
mXChar.bytesPerPixel*8, 0); |
233 |
|
|
} |
234 |
|
|
} |
235 |
|
|
|
236 |
|
|
virtual void convertCharacteristicsToHost(DisplayCharacteristics &aHostChar, const DisplayCharacteristics &aClientChar) |
237 |
|
|
{ |
238 |
|
|
sys_lock_mutex(gX11Mutex); |
239 |
|
|
int screen_num = DefaultScreen(gX11Display); |
240 |
|
|
|
241 |
|
|
XVisualInfo info_tmpl; |
242 |
|
|
int ninfo; |
243 |
|
|
info_tmpl.screen = screen_num; |
244 |
|
|
info_tmpl.visualid = XVisualIDFromVisual(DefaultVisual(gX11Display, screen_num)); |
245 |
|
|
XVisualInfo *info = XGetVisualInfo(gX11Display, |
246 |
|
|
VisualScreenMask | VisualIDMask, &info_tmpl, &ninfo); |
247 |
|
|
/* |
248 |
|
|
fprintf(stderr, "got %d XVisualInfo's:\n", ninfo); |
249 |
|
|
for (int i=0; i<ninfo; i++) { |
250 |
|
|
fprintf(stderr, "XVisualInfo %d:\n", i); |
251 |
|
|
fprintf(stderr, "\tscreen = %d:\n", info[i].screen); |
252 |
|
|
fprintf(stderr, "\tdepth = %d:\n", info[i].depth); |
253 |
|
|
fprintf(stderr, "\tred = %x:\n", info[i].red_mask); |
254 |
|
|
fprintf(stderr, "\tgreen = %x:\n", info[i].green_mask); |
255 |
|
|
fprintf(stderr, "\tblue = %x:\n", info[i].blue_mask); |
256 |
|
|
} |
257 |
|
|
*/ |
258 |
|
|
// generate X characteristics from visual info |
259 |
|
|
aHostChar = aClientChar; |
260 |
|
|
if (ninfo) { |
261 |
|
|
aHostChar.bytesPerPixel = bitsPerPixelToXBitmapPad(info->depth) >> 3; |
262 |
|
|
aHostChar.scanLineLength = aHostChar.bytesPerPixel * aHostChar.width; |
263 |
|
|
findMaskShiftAndSize(aHostChar.redShift, aHostChar.redSize, info->red_mask); |
264 |
|
|
findMaskShiftAndSize(aHostChar.greenShift, aHostChar.greenSize, info->green_mask); |
265 |
|
|
findMaskShiftAndSize(aHostChar.blueShift, aHostChar.blueSize, info->blue_mask); |
266 |
|
|
} else { |
267 |
|
|
sys_unlock_mutex(gX11Mutex); |
268 |
|
|
printf("ARGH! Couldn't get XVisualInfo...\n"); |
269 |
|
|
exit(1); |
270 |
|
|
} |
271 |
|
|
XFree(info); |
272 |
|
|
sys_unlock_mutex(gX11Mutex); |
273 |
|
|
} |
274 |
|
|
|
275 |
|
|
virtual bool changeResolution(const DisplayCharacteristics &aClientChar) |
276 |
|
|
{ |
277 |
|
|
if (aClientChar.width == mClientChar.width |
278 |
|
|
&& aClientChar.height == mClientChar.height |
279 |
|
|
&& aClientChar.bytesPerPixel == mClientChar.bytesPerPixel) { |
280 |
|
|
return true; |
281 |
|
|
} else { |
282 |
|
|
return false; |
283 |
|
|
} |
284 |
|
|
} |
285 |
|
|
|
286 |
|
|
virtual bool doChangeResolution(const DisplayCharacteristics &aClientChar) |
287 |
|
|
{ |
288 |
|
|
/* |
289 |
|
|
* I don't understand how XResizeWindow is supposed to work |
290 |
|
|
* If you understand, feel free to fix this: |
291 |
|
|
*/ |
292 |
|
|
DisplayCharacteristics oldClientChar = mClientChar; |
293 |
|
|
DisplayCharacteristics oldHostChar = mXChar; |
294 |
|
|
DisplayCharacteristics newXChar; |
295 |
|
|
|
296 |
|
|
convertCharacteristicsToHost(newXChar, aClientChar); |
297 |
|
|
sys_lock_mutex(gX11Mutex); |
298 |
|
|
mXChar = newXChar; |
299 |
|
|
mClientChar = aClientChar; |
300 |
|
|
if (bitsPerPixelToXBitmapPad(mXChar.bytesPerPixel*8) != mXChar.bytesPerPixel*8) { |
301 |
|
|
fprintf(stderr, "bitsPerPixelToXBitmapPad(%d) failed\n", mXChar.bytesPerPixel*8); |
302 |
|
|
mClientChar = oldClientChar; |
303 |
|
|
mXChar = oldHostChar; |
304 |
|
|
sys_unlock_mutex(gX11Mutex); |
305 |
|
|
return false; |
306 |
|
|
} |
307 |
|
|
|
308 |
|
|
XResizeWindow(gX11Display, gX11Window, mXChar.width, mXChar.height+mMenuHeight); |
309 |
|
|
|
310 |
|
|
XSync(gX11Display, False); |
311 |
|
|
|
312 |
|
|
XWindowAttributes attr; |
313 |
|
|
if (!XGetWindowAttributes(gX11Display, gX11Window, &attr)) { |
314 |
|
|
fprintf(stderr, "Couldn't get X window size\n"); |
315 |
|
|
mClientChar = oldClientChar; |
316 |
|
|
mXChar = oldHostChar; |
317 |
|
|
XResizeWindow(gX11Display, gX11Window, mXChar.width, mXChar.height+mMenuHeight); |
318 |
|
|
sys_unlock_mutex(gX11Mutex); |
319 |
|
|
return false; |
320 |
|
|
} |
321 |
|
|
|
322 |
|
|
if ((int)attr.width < mXChar.width || (int)attr.height < (mXChar.height+mMenuHeight)) { |
323 |
|
|
fprintf(stderr, "Couldn't change X window size to %dx%d\n", mXChar.width, mXChar.height); |
324 |
|
|
fprintf(stderr, "Reported new size: %dx(%d+%d)\n", attr.width, attr.height-mMenuHeight, mMenuHeight); |
325 |
|
|
mClientChar = oldClientChar; |
326 |
|
|
mXChar = oldHostChar; |
327 |
|
|
XResizeWindow(gX11Display, gX11Window, mXChar.width, mXChar.height+mMenuHeight); |
328 |
|
|
sys_unlock_mutex(gX11Mutex); |
329 |
|
|
return false; |
330 |
|
|
} |
331 |
|
|
|
332 |
|
|
reinitChar(); |
333 |
|
|
sys_unlock_mutex(gX11Mutex); |
334 |
|
|
fprintf(stderr, "Change resolution OK\n"); |
335 |
|
|
return true; |
336 |
|
|
} |
337 |
|
|
|
338 |
|
|
virtual void getHostCharacteristics(Container &modes) |
339 |
|
|
{ |
340 |
|
|
// FIXME: implement me |
341 |
|
|
} |
342 |
|
|
|
343 |
|
|
virtual int getKeybLEDs() |
344 |
|
|
{ |
345 |
|
|
return 0; |
346 |
|
|
} |
347 |
|
|
|
348 |
|
|
virtual void setKeybLEDs(int leds) |
349 |
|
|
{ |
350 |
|
|
} |
351 |
|
|
|
352 |
|
|
virtual void updateTitle() |
353 |
|
|
{ |
354 |
|
|
String key; |
355 |
|
|
int key_toggle_mouse_grab = gKeyboard->getKeyConfig().key_toggle_mouse_grab; |
356 |
|
|
SystemKeyboard::convertKeycodeToString(key, key_toggle_mouse_grab); |
357 |
|
|
ht_snprintf(mCurTitle, sizeof mCurTitle, "%s - [%s %s mouse]", mTitle,key.contentChar(), (isMouseGrabbed() ? "disables" : "enables")); |
358 |
|
|
XTextProperty name_prop; |
359 |
|
|
char *mCurTitlep = mCurTitle; |
360 |
|
|
XStringListToTextProperty(&mCurTitlep, 1, &name_prop); |
361 |
|
|
XSetWMName(gX11Display, gX11Window, &name_prop); |
362 |
|
|
} |
363 |
|
|
|
364 |
|
|
virtual int toString(char *buf, int buflen) const |
365 |
|
|
{ |
366 |
|
|
return snprintf(buf, buflen, "POSIX X11"); |
367 |
|
|
} |
368 |
|
|
|
369 |
|
|
virtual void setMouseGrab(bool enable) |
370 |
|
|
{ |
371 |
|
|
SystemDisplay::setMouseGrab(enable); |
372 |
|
|
updateTitle(); |
373 |
|
|
if (enable) { |
374 |
|
|
mResetMouseX = mCurMouseX; |
375 |
|
|
mResetMouseY = mCurMouseY; |
376 |
|
|
|
377 |
|
|
static Cursor cursor; |
378 |
|
|
static bool cursor_created = false; |
379 |
|
|
|
380 |
|
|
static char shape_bits[16*16] = {0, }; |
381 |
|
|
static char mask_bits[16*16] = {0, }; |
382 |
|
|
|
383 |
|
|
if (!cursor_created) { |
384 |
|
|
Pixmap shape, mask; |
385 |
|
|
XColor white, black; |
386 |
|
|
shape = XCreatePixmapFromBitmapData(gX11Display, |
387 |
|
|
RootWindow(gX11Display, DefaultScreen(gX11Display)), |
388 |
|
|
shape_bits, 16, 16, 1, 0, 1); |
389 |
|
|
mask = XCreatePixmapFromBitmapData(gX11Display, |
390 |
|
|
RootWindow(gX11Display, DefaultScreen(gX11Display)), |
391 |
|
|
mask_bits, 16, 16, 1, 0, 1); |
392 |
|
|
XParseColor(gX11Display, mDefaultColormap, "black", &black); |
393 |
|
|
XParseColor(gX11Display, mDefaultColormap, "white", &white); |
394 |
|
|
cursor = XCreatePixmapCursor(gX11Display, shape, mask, |
395 |
|
|
&white, &black, 1, 1); |
396 |
|
|
cursor_created = true; |
397 |
|
|
} |
398 |
|
|
|
399 |
|
|
XDefineCursor(gX11Display, gX11Window, cursor); |
400 |
|
|
XWarpPointer(gX11Display, gX11Window, gX11Window, 0, 0, 0, 0, mHomeMouseX, mHomeMouseY); |
401 |
|
|
} else { |
402 |
|
|
XWarpPointer(gX11Display, gX11Window, gX11Window, 0, 0, 0, 0, mResetMouseX, mResetMouseY); |
403 |
|
|
XUndefineCursor(gX11Display, gX11Window); |
404 |
|
|
} |
405 |
|
|
} |
406 |
|
|
|
407 |
|
|
virtual void displayShow() |
408 |
|
|
{ |
409 |
|
|
if (!isExposed()) return; |
410 |
|
|
|
411 |
|
|
int firstDamagedLine, lastDamagedLine; |
412 |
|
|
// We've got problems with races here because gcard_write1/2/4 |
413 |
|
|
// might set gDamageAreaFirstAddr, gDamageAreaLastAddr. |
414 |
|
|
// We can't use mutexes in gcard for speed reasons. So we'll |
415 |
|
|
// try to minimize the probability of loosing the race. |
416 |
|
|
if (gDamageAreaFirstAddr > gDamageAreaLastAddr+3) { |
417 |
|
|
return; |
418 |
|
|
} |
419 |
|
|
uint damageAreaFirstAddr = gDamageAreaFirstAddr; |
420 |
|
|
uint damageAreaLastAddr = gDamageAreaLastAddr; |
421 |
|
|
healFrameBuffer(); |
422 |
|
|
// end of race |
423 |
|
|
damageAreaLastAddr += 3; // this is a hack. For speed reasons we |
424 |
|
|
// inaccurately set gDamageAreaLastAddr |
425 |
|
|
// to the first (not last) byte accessed |
426 |
|
|
// accesses are up to 4 bytes "long". |
427 |
|
|
|
428 |
|
|
firstDamagedLine = damageAreaFirstAddr / (mClientChar.width * mClientChar.bytesPerPixel); |
429 |
|
|
lastDamagedLine = damageAreaLastAddr / (mClientChar.width * mClientChar.bytesPerPixel); |
430 |
|
|
// Overflow may happen, because of the hack used above |
431 |
|
|
// and others, that set lastAddr = 0xfffffff0 (damageFrameBufferAll()) |
432 |
|
|
if (lastDamagedLine >= mClientChar.height) { |
433 |
|
|
lastDamagedLine = mClientChar.height-1; |
434 |
|
|
} |
435 |
|
|
|
436 |
|
|
if (mXFrameBuffer) { |
437 |
|
|
sys_convert_display(mClientChar, mXChar, gFrameBuffer, mXFrameBuffer, firstDamagedLine, lastDamagedLine); |
438 |
|
|
} |
439 |
|
|
|
440 |
|
|
sys_lock_mutex(gX11Mutex); |
441 |
|
|
// draw menu |
442 |
|
|
/* XPutImage(gX11Display, gX11Window, mXGC, mMenuXImage, 0, 0, 0, 0, |
443 |
|
|
mClientChar.width, |
444 |
|
|
mMenuHeight);*/ |
445 |
|
|
|
446 |
|
|
XPutImage(gX11Display, gX11Window, mXGC, mXImage, |
447 |
|
|
0, |
448 |
|
|
firstDamagedLine, |
449 |
|
|
0, |
450 |
|
|
mMenuHeight+firstDamagedLine, |
451 |
|
|
mClientChar.width, |
452 |
|
|
lastDamagedLine-firstDamagedLine+1); |
453 |
|
|
|
454 |
|
|
/* if (mHWCursorVisible) { |
455 |
|
|
XPutImage(gX11Display, gX11Window, mXGC, mMouseXImage, 0, 0, |
456 |
|
|
mHWCursorX, mHWCursorY, 2, 2); |
457 |
|
|
}*/ |
458 |
|
|
sys_unlock_mutex(gX11Mutex); |
459 |
|
|
} |
460 |
|
|
}; |
461 |
|
|
|
462 |
|
|
SystemDisplay *allocSystemDisplay(const char *title, const DisplayCharacteristics &chr, int redraw_ms, bool fullscreen) |
463 |
|
|
{ |
464 |
|
|
if (gDisplay) return NULL; |
465 |
|
|
return new X11SystemDisplay(title, chr, redraw_ms); |
466 |
|
|
} |