/[pearpc]/src/system/ui/x11/sysdisplay.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /src/system/ui/x11/sysdisplay.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 14279 byte(s)
import upstream CVS
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 }

  ViewVC Help
Powered by ViewVC 1.1.26