1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Wrappers for Xlib functions.
12  *
13  *      By Michael Bukin.
14  *
15  *      Video mode switching by Peter Wang and Benjamin Stover.
16  *
17  *      X icon selection by Evert Glebbeek
18  *
19  *      See readme.txt for copyright information.
20  */
21 
22 
23 #include "allegro.h"
24 #include "allegro/internal/aintern.h"
25 #include "allegro/platform/aintunix.h"
26 #include "xwin.h"
27 
28 #include <string.h>
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <X11/cursorfont.h>
32 #include <X11/keysym.h>
33 
34 #ifdef ALLEGRO_XWINDOWS_WITH_SHM
35 #include <sys/ipc.h>
36 #include <sys/shm.h>
37 #include <X11/extensions/XShm.h>
38 #endif
39 
40 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
41 #include <X11/extensions/xf86vmode.h>
42 #endif
43 
44 #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
45 #include <X11/Xcursor/Xcursor.h>
46 #endif
47 
48 
49 #ifdef ALLEGRO_XWINDOWS_WITH_XPM
50 #include <X11/xpm.h>
51 #endif
52 #include "icon.xpm"
53 
54 
55 #define XWIN_DEFAULT_WINDOW_TITLE "Allegro application"
56 #define XWIN_DEFAULT_APPLICATION_NAME "allegro"
57 #define XWIN_DEFAULT_APPLICATION_CLASS "Allegro"
58 
59 
60 struct _xwin_type _xwin =
61 {
62    0,           /* display */
63    0,           /* lock count */
64    0,           /* screen */
65    None,        /* window */
66    None,        /* gc */
67    0,           /* visual */
68    None,        /* colormap */
69    0,           /* ximage */
70 #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
71    None,        /* ARGB cursor image */
72    XcursorFalse,/* Are ARGB cursors supported? */
73 #endif
74    None,        /* cursor */
75    XC_heart,    /* cursor_shape */
76    1,           /* hw_cursor_ok */
77 
78    0,           /* screen_to_buffer */
79    0,           /* set_colors */
80 
81    0,           /* screen_data */
82    0,           /* screen_line */
83    0,           /* buffer_line */
84 
85    0,           /* scroll_x */
86    0,           /* scroll_y */
87 
88    320,         /* window_width */
89    200,         /* window_height */
90    8,           /* window_depth */
91 
92    320,         /* screen_width */
93    200,         /* screen_height */
94    8,           /* screen_depth */
95 
96    320,         /* virtual width */
97    200,         /* virtual_height */
98 
99    0,           /* mouse_warped */
100    { 0 },       /* keycode_to_scancode */
101 
102    0,           /* matching formats */
103    0,           /* fast_visual_depth */
104    0,           /* visual_is_truecolor */
105 
106    1,           /* rsize */
107    1,           /* gsize */
108    1,           /* bsize */
109    0,           /* rshift */
110    0,           /* gshift */
111    0,           /* bshift */
112 
113    { 0 },       /* cmap */
114    { 0 },       /* rmap */
115    { 0 },       /* gmap */
116    { 0 },       /* bmap */
117 
118 #ifdef ALLEGRO_XWINDOWS_WITH_SHM
119    { 0, 0, 0, 0 },  /* shminfo */
120 #endif
121    0,           /* use_shm */
122 
123    0,           /* in_dga_mode */
124 
125    0,           /* keyboard_grabbed */
126    0,           /* mouse_grabbed */
127 
128 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
129    0,           /* modesinfo */
130    0,           /* num_modes */
131    0,           /* mode_switched */
132    0,           /* override_redirected */
133 #endif
134 
135    XWIN_DEFAULT_WINDOW_TITLE,           /* window_title */
136    XWIN_DEFAULT_APPLICATION_NAME,       /* application_name */
137    XWIN_DEFAULT_APPLICATION_CLASS,      /* application_class */
138 
139    FALSE,       /* drawing_mode_ok */
140 
141 #ifdef ALLEGRO_MULTITHREADED
142    NULL,        /* mutex */
143 #endif
144 
145    NULL,        /* window close hook */
146 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
147    0,           /* orig_modeinfo */
148 #endif
149    None,        /* fs_window */
150    None         /* wm_window */
151 };
152 
153 void *allegro_icon = icon_xpm;
154 
155 int _xwin_last_line = -1;
156 int _xwin_in_gfx_call = 0;
157 
158 static COLORCONV_BLITTER_FUNC *blitter_func = NULL;
159 static int use_bgr_palette_hack = FALSE; /* use BGR hack for color conversion palette? */
160 
161 #ifndef ALLEGRO_MULTITHREADED
162 int _xwin_missed_input;
163 #endif
164 
165 #define X_MAX_EVENTS   50
166 #define MOUSE_WARP_DELAY   200
167 
168 static char _xwin_driver_desc[256] = EMPTY_STRING;
169 
170 /* This is used to intercept window closing requests.  */
171 static Atom wm_delete_window;
172 
173 #define PREFIX_I                "al-xwin INFO: "
174 #define PREFIX_W                "al-xwin WARNING: "
175 #define PREFIX_E                "al-xwin ERROR: "
176 
177 
178 /* Forward declarations for private functions.  */
179 static int _xwin_private_open_display(char *name);
180 static int _xwin_private_create_window(void);
181 static void _xwin_private_destroy_window(void);
182 static void _xwin_private_select_screen_to_buffer_function(void);
183 static void _xwin_private_select_set_colors_function(void);
184 static void _xwin_private_setup_driver_desc(GFX_DRIVER *drv);
185 static BITMAP *_xwin_private_create_screen(GFX_DRIVER *drv, int w, int h,
186 					   int vw, int vh, int depth, int fullscreen);
187 static void _xwin_private_destroy_screen(void);
188 static BITMAP *_xwin_private_create_screen_bitmap(GFX_DRIVER *drv,
189 						  unsigned char *frame_buffer,
190 						  int bytes_per_buffer_line);
191 static void _xwin_private_create_mapping_tables(void);
192 static void _xwin_private_create_mapping(unsigned long *map, int ssize, int dsize, int dshift);
193 static int _xwin_private_display_is_local(void);
194 static int _xwin_private_create_ximage(int w, int h);
195 static void _xwin_private_destroy_ximage(void);
196 static void _xwin_private_prepare_visual(void);
197 static int _xwin_private_matching_formats(void);
198 static void _xwin_private_hack_shifts(void);
199 static int _xwin_private_colorconv_usable(void);
200 static int _xwin_private_fast_visual_depth(void);
201 static void _xwin_private_set_matching_colors(AL_CONST PALETTE p, int from, int to);
202 static void _xwin_private_set_truecolor_colors(AL_CONST PALETTE p, int from, int to);
203 static void _xwin_private_set_palette_colors(AL_CONST PALETTE p, int from, int to);
204 static void _xwin_private_set_palette_range(AL_CONST PALETTE p, int from, int to);
205 static void _xwin_private_set_window_defaults(void);
206 static void _xwin_private_flush_buffers(void);
207 static void _xwin_private_process_event(XEvent *event);
208 static void _xwin_private_set_warped_mouse_mode(int permanent);
209 static void _xwin_private_redraw_window(int x, int y, int w, int h);
210 static int _xwin_private_scroll_screen(int x, int y);
211 static void _xwin_private_update_screen(int x, int y, int w, int h);
212 static void _xwin_private_set_window_title(AL_CONST char *name);
213 static void _xwin_private_set_window_name(AL_CONST char *name, AL_CONST char *group);
214 static int _xwin_private_get_pointer_mapping(unsigned char map[], int nmap);
215 
216 static void _xwin_private_fast_colorconv(int sx, int sy, int sw, int sh);
217 
218 static void _xwin_private_fast_truecolor_8_to_8(int sx, int sy, int sw, int sh);
219 static void _xwin_private_fast_truecolor_8_to_16(int sx, int sy, int sw, int sh);
220 static void _xwin_private_fast_truecolor_8_to_24(int sx, int sy, int sw, int sh);
221 static void _xwin_private_fast_truecolor_8_to_32(int sx, int sy, int sw, int sh);
222 static void _xwin_private_fast_truecolor_15_to_8(int sx, int sy, int sw, int sh);
223 static void _xwin_private_fast_truecolor_15_to_16(int sx, int sy, int sw, int sh);
224 static void _xwin_private_fast_truecolor_15_to_24(int sx, int sy, int sw, int sh);
225 static void _xwin_private_fast_truecolor_15_to_32(int sx, int sy, int sw, int sh);
226 static void _xwin_private_fast_truecolor_16_to_8(int sx, int sy, int sw, int sh);
227 static void _xwin_private_fast_truecolor_16_to_16(int sx, int sy, int sw, int sh);
228 static void _xwin_private_fast_truecolor_16_to_24(int sx, int sy, int sw, int sh);
229 static void _xwin_private_fast_truecolor_16_to_32(int sx, int sy, int sw, int sh);
230 static void _xwin_private_fast_truecolor_24_to_8(int sx, int sy, int sw, int sh);
231 static void _xwin_private_fast_truecolor_24_to_16(int sx, int sy, int sw, int sh);
232 static void _xwin_private_fast_truecolor_24_to_24(int sx, int sy, int sw, int sh);
233 static void _xwin_private_fast_truecolor_24_to_32(int sx, int sy, int sw, int sh);
234 static void _xwin_private_fast_truecolor_32_to_8(int sx, int sy, int sw, int sh);
235 static void _xwin_private_fast_truecolor_32_to_16(int sx, int sy, int sw, int sh);
236 static void _xwin_private_fast_truecolor_32_to_24(int sx, int sy, int sw, int sh);
237 static void _xwin_private_fast_truecolor_32_to_32(int sx, int sy, int sw, int sh);
238 
239 static void _xwin_private_slow_truecolor_8(int sx, int sy, int sw, int sh);
240 static void _xwin_private_slow_truecolor_15(int sx, int sy, int sw, int sh);
241 static void _xwin_private_slow_truecolor_16(int sx, int sy, int sw, int sh);
242 static void _xwin_private_slow_truecolor_24(int sx, int sy, int sw, int sh);
243 static void _xwin_private_slow_truecolor_32(int sx, int sy, int sw, int sh);
244 
245 static void _xwin_private_fast_palette_8_to_8(int sx, int sy, int sw, int sh);
246 static void _xwin_private_fast_palette_8_to_16(int sx, int sy, int sw, int sh);
247 static void _xwin_private_fast_palette_8_to_32(int sx, int sy, int sw, int sh);
248 static void _xwin_private_fast_palette_15_to_8(int sx, int sy, int sw, int sh);
249 static void _xwin_private_fast_palette_15_to_16(int sx, int sy, int sw, int sh);
250 static void _xwin_private_fast_palette_15_to_32(int sx, int sy, int sw, int sh);
251 static void _xwin_private_fast_palette_16_to_8(int sx, int sy, int sw, int sh);
252 static void _xwin_private_fast_palette_16_to_16(int sx, int sy, int sw, int sh);
253 static void _xwin_private_fast_palette_16_to_32(int sx, int sy, int sw, int sh);
254 static void _xwin_private_fast_palette_24_to_8(int sx, int sy, int sw, int sh);
255 static void _xwin_private_fast_palette_24_to_16(int sx, int sy, int sw, int sh);
256 static void _xwin_private_fast_palette_24_to_32(int sx, int sy, int sw, int sh);
257 static void _xwin_private_fast_palette_32_to_8(int sx, int sy, int sw, int sh);
258 static void _xwin_private_fast_palette_32_to_16(int sx, int sy, int sw, int sh);
259 static void _xwin_private_fast_palette_32_to_32(int sx, int sy, int sw, int sh);
260 
261 static void _xwin_private_slow_palette_8(int sx, int sy, int sw, int sh);
262 static void _xwin_private_slow_palette_15(int sx, int sy, int sw, int sh);
263 static void _xwin_private_slow_palette_16(int sx, int sy, int sw, int sh);
264 static void _xwin_private_slow_palette_24(int sx, int sy, int sw, int sh);
265 static void _xwin_private_slow_palette_32(int sx, int sy, int sw, int sh);
266 
267 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
268 static void _xvidmode_private_set_fullscreen(int w, int h, int *vidmode_width,
269    int *vidmode_height);
270 static void _xvidmode_private_unset_fullscreen(void);
271 #endif
272 
273 uintptr_t _xwin_write_line(BITMAP *bmp, int line);
274 void _xwin_unwrite_line(BITMAP *bmp);
275 #ifndef ALLEGRO_NO_ASM
276 uintptr_t _xwin_write_line_asm(BITMAP *bmp, int line);
277 void _xwin_unwrite_line_asm(BITMAP *bmp);
278 #endif
279 
280 
281 
282 /* _xwin_open_display:
283  *  Wrapper for XOpenDisplay.
284  */
_xwin_private_open_display(char * name)285 static int _xwin_private_open_display(char *name)
286 {
287    if (_xwin.display != 0)
288       return -1;
289 
290    _xwin.display = XOpenDisplay(name);
291    _xwin.screen = ((_xwin.display == 0) ? 0 : XDefaultScreen(_xwin.display));
292 
293    return ((_xwin.display != 0) ? 0 : -1);
294 }
295 
_xwin_open_display(char * name)296 int _xwin_open_display(char *name)
297 {
298    int result;
299    XLOCK();
300    result = _xwin_private_open_display(name);
301    XUNLOCK();
302    return result;
303 }
304 
305 
306 
307 /* _xwin_close_display:
308  *  Wrapper for XCloseDisplay.
309  */
_xwin_close_display(void)310 void _xwin_close_display(void)
311 {
312    Display *dpy;
313 
314    if (!_unix_bg_man->multi_threaded) {
315       XLOCK();
316    }
317 
318    if (_xwin.display != 0) {
319       _xwin_destroy_window();
320       dpy = _xwin.display;
321       _xwin.display = 0;
322       XCloseDisplay(dpy);
323    }
324 
325    if (!_unix_bg_man->multi_threaded) {
326       XUNLOCK();
327    }
328 }
329 
330 
331 
332 /* _xwin_hide_x_mouse:
333  *  Create invisible X cursor.
334  */
_xwin_hide_x_mouse(void)335 static void _xwin_hide_x_mouse(void)
336 {
337    unsigned long gcmask;
338    XGCValues gcvalues;
339    Pixmap pixmap;
340 
341    XUndefineCursor(_xwin.display, _xwin.window);
342 
343    if (_xwin.cursor != None) {
344       XFreeCursor(_xwin.display, _xwin.cursor);
345       _xwin.cursor = None;
346    }
347 
348 #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
349    if (_xwin.xcursor_image != None) {
350       XcursorImageDestroy(_xwin.xcursor_image);
351       _xwin.xcursor_image = None;
352    }
353 #endif
354 
355    pixmap = XCreatePixmap(_xwin.display, _xwin.window, 1, 1, 1);
356    if (pixmap != None) {
357       GC temp_gc;
358       XColor color;
359 
360       gcmask = GCFunction | GCForeground | GCBackground;
361       gcvalues.function = GXcopy;
362       gcvalues.foreground = 0;
363       gcvalues.background = 0;
364       temp_gc = XCreateGC(_xwin.display, pixmap, gcmask, &gcvalues);
365       XDrawPoint(_xwin.display, pixmap, temp_gc, 0, 0);
366       XFreeGC(_xwin.display, temp_gc);
367       color.pixel = 0;
368       color.red = color.green = color.blue = 0;
369       color.flags = DoRed | DoGreen | DoBlue;
370       _xwin.cursor = XCreatePixmapCursor(_xwin.display, pixmap, pixmap, &color, &color, 0, 0);
371       XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
372       XFreePixmap(_xwin.display, pixmap);
373    }
374    else {
375       _xwin.cursor = XCreateFontCursor(_xwin.display, _xwin.cursor_shape);
376       XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
377    }
378 }
379 
380 
381 
382 /* _xwin_wait_mapped:
383  *  Wait for a window to become mapped.
384  */
_xwin_wait_mapped(Window win)385 static void _xwin_wait_mapped(Window win)
386 {
387    /* Note:
388     * The busy loop below is just a hack to work around my broken X11.
389     * A call to XMaskEvent will block indefinitely and no Allegro
390     * programs (which create a window) will start up at all. Replacing
391     * XMaskEvent with a busy loop calling XCheckMaskEvent repeatedly
392     * somehow works though..
393     */
394    while (1) {
395        XEvent e;
396        if (XCheckTypedEvent(_xwin.display, MapNotify, &e)) {
397           if (e.xmap.event == win) break;
398        }
399        rest(1);
400    }
401 }
402 
403 
404 
405 /* _xwin_create_window:
406  *  We use 3 windows:
407  *  - fs_window (for fullscreen)
408  *  - wm_window (window managed)
409  *  - window    (the real window)
410  *
411  *  Two of which will be created here: wm_window and window. The fullscreen
412  *  window gets (re)created when needed, because reusing it causes trouble see
413  *  http://sourceforge.net/tracker/index.php?func=detail&aid=1441740&group_id=5665&atid=105665
414  *  The real window uses wm_window as parent initially and will be reparented
415  *  to the (freshly created) fullscreen window when requested and reparented
416  *  back again in screen_destroy.
417  *
418  *  Idea/concept of three windows borrowed from SDL. But somehow SDL manages
419  *  to reuse the fullscreen window too.
420  */
_xwin_private_create_window(void)421 static int _xwin_private_create_window(void)
422 {
423    unsigned long gcmask;
424    XGCValues gcvalues;
425    XSetWindowAttributes setattr;
426    XWindowAttributes getattr;
427 
428    if (_xwin.display == 0)
429       return -1;
430 
431    _mouse_on = FALSE;
432 
433    /* Create the managed window. */
434    setattr.background_pixel = XBlackPixel(_xwin.display, _xwin.screen);
435    setattr.border_pixel = XBlackPixel(_xwin.display, _xwin.screen);
436    setattr.event_mask = (KeyPressMask | KeyReleaseMask | StructureNotifyMask
437 			 | EnterWindowMask | LeaveWindowMask
438 			 | FocusChangeMask | ExposureMask | PropertyChangeMask
439 			 | ButtonPressMask | ButtonReleaseMask | PointerMotionMask
440 			 /*| MappingNotifyMask (SubstructureRedirectMask?)*/);
441    _xwin.wm_window = XCreateWindow(_xwin.display,
442 				XDefaultRootWindow(_xwin.display),
443 				0, 0, 320, 200, 0,
444 				CopyFromParent, InputOutput, CopyFromParent,
445 				CWBackPixel | CWBorderPixel | CWEventMask,
446 				&setattr);
447 
448    /* Get associated visual and window depth (bits per pixel).  */
449    XGetWindowAttributes(_xwin.display, _xwin.wm_window, &getattr);
450    _xwin.visual = getattr.visual;
451    _xwin.window_depth = getattr.depth;
452 
453    /* Create and install colormap.  */
454    if ((_xwin.visual->class == PseudoColor)
455        || (_xwin.visual->class == GrayScale)
456        || (_xwin.visual->class == DirectColor))
457    {
458       _xwin.colormap = XCreateColormap(_xwin.display, _xwin.wm_window, _xwin.visual, AllocAll);
459    }
460    else {
461       _xwin.colormap = XCreateColormap(_xwin.display, _xwin.wm_window, _xwin.visual, AllocNone);
462    }
463    XSetWindowColormap(_xwin.display, _xwin.wm_window, _xwin.colormap);
464    XInstallColormap(_xwin.display, _xwin.colormap);
465 
466    /* Create the real / drawing window (reuses setattr). */
467    setattr.colormap = _xwin.colormap;
468    _xwin.window = XCreateWindow(_xwin.display,
469 				_xwin.wm_window,
470 				0, 0, 320, 200, 0,
471 				CopyFromParent, InputOutput, CopyFromParent,
472 				CWBackPixel | CWBorderPixel | CWEventMask |
473 				CWColormap, &setattr);
474 
475    /* Map the real / drawing window it won't appear untill the parent does */
476    XMapWindow(_xwin.display, _xwin.window);
477 
478    /* Set WM_DELETE_WINDOW atom in WM_PROTOCOLS property (to get window_delete requests).  */
479    wm_delete_window = XInternAtom(_xwin.display, "WM_DELETE_WINDOW", False);
480    XSetWMProtocols(_xwin.display, _xwin.wm_window, &wm_delete_window, 1);
481 
482    /* Set default window parameters.  */
483    (*_xwin_window_defaultor)();
484 
485    /* Create graphics context.  */
486    gcmask = GCFunction | GCForeground | GCBackground | GCFillStyle | GCPlaneMask;
487    gcvalues.function = GXcopy;
488    gcvalues.foreground = setattr.border_pixel;
489    gcvalues.background = setattr.border_pixel;
490    gcvalues.fill_style = FillSolid;
491    gcvalues.plane_mask = AllPlanes;
492    _xwin.gc = XCreateGC(_xwin.display, _xwin.window, gcmask, &gcvalues);
493 
494    /* Create invisible X cursor.  */
495    _xwin_hide_x_mouse();
496 
497 #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
498    /* Detect if ARGB cursors are supported */
499    _xwin.support_argb_cursor = XcursorSupportsARGB(_xwin.display);
500 #endif
501    _xwin.hw_cursor_ok = 0;
502 
503    return 0;
504 }
505 
_xwin_create_window(void)506 int _xwin_create_window(void)
507 {
508    int result;
509    XLOCK();
510    result = (*_xwin_window_creator)();
511    XUNLOCK();
512    return result;
513 }
514 
515 
516 
517 /* _xwin_destroy_window:
518  *  Wrapper for XDestroyWindow.
519  */
_xwin_private_destroy_window(void)520 static void _xwin_private_destroy_window(void)
521 {
522    _xwin_private_destroy_screen();
523 
524    if (_xwin.cursor != None) {
525       XUndefineCursor(_xwin.display, _xwin.window);
526       XFreeCursor(_xwin.display, _xwin.cursor);
527       _xwin.cursor = None;
528    }
529 
530 #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
531    if (_xwin.xcursor_image != None) {
532       XcursorImageDestroy(_xwin.xcursor_image);
533       _xwin.xcursor_image = None;
534    }
535 #endif
536 
537    _xwin.visual = 0;
538 
539    if (_xwin.gc != None) {
540       XFreeGC(_xwin.display, _xwin.gc);
541       _xwin.gc = None;
542    }
543 
544    if (_xwin.colormap != None) {
545       XUninstallColormap(_xwin.display, _xwin.colormap);
546       XFreeColormap(_xwin.display, _xwin.colormap);
547       _xwin.colormap = None;
548    }
549 
550    if (_xwin.window != None) {
551       XUnmapWindow(_xwin.display, _xwin.window);
552       XDestroyWindow(_xwin.display, _xwin.window);
553       _xwin.window = None;
554    }
555 
556    if (_xwin.wm_window != None) {
557       XDestroyWindow(_xwin.display, _xwin.wm_window);
558       _xwin.wm_window = None;
559    }
560 }
561 
_xwin_destroy_window(void)562 void _xwin_destroy_window(void)
563 {
564    XLOCK();
565    _xwin_private_destroy_window();
566    XUNLOCK();
567 }
568 
569 
570 
571 typedef void (*_XWIN_SCREEN_TO_BUFFER)(int x, int y, int w, int h);
572 static _XWIN_SCREEN_TO_BUFFER _xwin_screen_to_buffer_function[5][10] =
573 {
574    {
575       _xwin_private_slow_truecolor_8,
576       _xwin_private_fast_truecolor_8_to_8,
577       _xwin_private_fast_truecolor_8_to_16,
578       _xwin_private_fast_truecolor_8_to_24,
579       _xwin_private_fast_truecolor_8_to_32,
580       _xwin_private_slow_palette_8,
581       _xwin_private_fast_palette_8_to_8,
582       _xwin_private_fast_palette_8_to_16,
583       0,
584       _xwin_private_fast_palette_8_to_32
585    },
586    {
587       _xwin_private_slow_truecolor_15,
588       _xwin_private_fast_truecolor_15_to_8,
589       _xwin_private_fast_truecolor_15_to_16,
590       _xwin_private_fast_truecolor_15_to_24,
591       _xwin_private_fast_truecolor_15_to_32,
592       _xwin_private_slow_palette_15,
593       _xwin_private_fast_palette_15_to_8,
594       _xwin_private_fast_palette_15_to_16,
595       0,
596       _xwin_private_fast_palette_15_to_32
597    },
598    {
599       _xwin_private_slow_truecolor_16,
600       _xwin_private_fast_truecolor_16_to_8,
601       _xwin_private_fast_truecolor_16_to_16,
602       _xwin_private_fast_truecolor_16_to_24,
603       _xwin_private_fast_truecolor_16_to_32,
604       _xwin_private_slow_palette_16,
605       _xwin_private_fast_palette_16_to_8,
606       _xwin_private_fast_palette_16_to_16,
607       0,
608       _xwin_private_fast_palette_16_to_32
609    },
610    {
611       _xwin_private_slow_truecolor_24,
612       _xwin_private_fast_truecolor_24_to_8,
613       _xwin_private_fast_truecolor_24_to_16,
614       _xwin_private_fast_truecolor_24_to_24,
615       _xwin_private_fast_truecolor_24_to_32,
616       _xwin_private_slow_palette_24,
617       _xwin_private_fast_palette_24_to_8,
618       _xwin_private_fast_palette_24_to_16,
619       0,
620       _xwin_private_fast_palette_24_to_32
621    },
622    {
623       _xwin_private_slow_truecolor_32,
624       _xwin_private_fast_truecolor_32_to_8,
625       _xwin_private_fast_truecolor_32_to_16,
626       _xwin_private_fast_truecolor_32_to_24,
627       _xwin_private_fast_truecolor_32_to_32,
628       _xwin_private_slow_palette_32,
629       _xwin_private_fast_palette_32_to_8,
630       _xwin_private_fast_palette_32_to_16,
631       0,
632       _xwin_private_fast_palette_32_to_32
633    },
634 };
635 
636 
637 
638 /* _xwin_select_screen_to_buffer_function:
639  *  Select which function should be used for updating frame buffer with screen data.
640  */
_xwin_private_select_screen_to_buffer_function(void)641 static void _xwin_private_select_screen_to_buffer_function(void)
642 {
643    int i, j;
644 
645    if (_xwin.matching_formats) {
646       _xwin.screen_to_buffer = 0;
647    }
648    else {
649       switch (_xwin.screen_depth) {
650 	 case 8: i = 0; break;
651 	 case 15: i = 1; break;
652 	 case 16: i = 2; break;
653 	 case 24: i = 3; break;
654 	 case 32: i = 4; break;
655 	 default: i = 0; break;
656       }
657       switch (_xwin.fast_visual_depth) {
658 	 case 0: j = 0; break;
659 	 case 8: j = 1; break;
660 	 case 16: j = 2; break;
661 	 case 24: j = 3; break;
662 	 case 32: j = 4; break;
663 	 default: j = 0; break;
664       }
665       if (!_xwin.visual_is_truecolor)
666 	 j += 5;
667 
668       if (_xwin_private_colorconv_usable()) {
669 	 TRACE(PREFIX_I "Using generic color conversion blitter (%u, %u).\n",
670 	       _xwin.screen_depth, _xwin.fast_visual_depth);
671 	 blitter_func = _get_colorconv_blitter(_xwin.screen_depth,
672 					       _xwin.fast_visual_depth);
673 	 _xwin.screen_to_buffer = _xwin_private_fast_colorconv;
674       }
675       else {
676 	 _xwin.screen_to_buffer = _xwin_screen_to_buffer_function[i][j];
677       }
678    }
679 }
680 
681 
682 
683 /* _xwin_select_set_colors_function:
684  *  Select which function should be used for setting hardware colors.
685  */
_xwin_private_select_set_colors_function(void)686 static void _xwin_private_select_set_colors_function(void)
687 {
688    if (_xwin.screen_depth != 8) {
689       _xwin.set_colors = 0;
690    }
691    else {
692       if (_xwin.matching_formats) {
693 	 _xwin.set_colors = _xwin_private_set_matching_colors;
694       }
695       else if (_xwin.visual_is_truecolor) {
696 	 _xwin.set_colors = _xwin_private_set_truecolor_colors;
697       }
698       else {
699 	 _xwin.set_colors = _xwin_private_set_palette_colors;
700       }
701    }
702 }
703 
704 
705 
706 /* _xwin_setup_driver_desc:
707  *  Sets up the X-Windows driver description string.
708  */
_xwin_private_setup_driver_desc(GFX_DRIVER * drv)709 static void _xwin_private_setup_driver_desc(GFX_DRIVER *drv)
710 {
711    char tmp1[256], tmp2[128], tmp3[128], tmp4[128];
712 
713    /* Prepare driver description.  */
714    if (_xwin.matching_formats) {
715       uszprintf(_xwin_driver_desc, sizeof(_xwin_driver_desc),
716 	        uconvert_ascii("X-Windows graphics, in matching, %d bpp %s", tmp1),
717 	        _xwin.window_depth,
718 	        uconvert_ascii("real depth", tmp2));
719    }
720    else {
721       uszprintf(_xwin_driver_desc, sizeof(_xwin_driver_desc),
722 	        uconvert_ascii("X-Windows graphics, in %s %s, %d bpp %s", tmp1),
723 	        uconvert_ascii((_xwin.fast_visual_depth ? "fast" : "slow"), tmp2),
724 	        uconvert_ascii((_xwin.visual_is_truecolor ? "truecolor" : "paletted"), tmp3),
725 	        _xwin.window_depth,
726 	        uconvert_ascii("real depth", tmp4));
727    }
728    drv->desc = _xwin_driver_desc;
729 }
730 
731 
732 
733 /* _xwin_create_screen:
734  *  Creates screen data and other resources.
735  */
_xwin_private_create_screen(GFX_DRIVER * drv,int w,int h,int vw,int vh,int depth,int fullscreen)736 static BITMAP *_xwin_private_create_screen(GFX_DRIVER *drv, int w, int h,
737 					   int vw, int vh, int depth, int fullscreen)
738 {
739    if (_xwin.window == None) {
740       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("No window"));
741       return 0;
742    }
743 
744    /* Choose convenient size.  */
745    if ((w == 0) && (h == 0)) {
746       w = 320;
747       h = 200;
748    }
749 
750    if (vw < w)
751       vw = w;
752    if (vh < h)
753       vh = h;
754 
755    if (1
756 #ifdef ALLEGRO_COLOR8
757        && (depth != 8)
758 #endif
759 #ifdef ALLEGRO_COLOR16
760        && (depth != 15)
761        && (depth != 16)
762 #endif
763 #ifdef ALLEGRO_COLOR24
764        && (depth != 24)
765 #endif
766 #ifdef ALLEGRO_COLOR32
767        && (depth != 32)
768 #endif
769        ) {
770       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported color depth"));
771       return 0;
772    }
773 
774    /* Save dimensions.  */
775    _xwin.window_width = w;
776    _xwin.window_height = h;
777    _xwin.screen_width = w;
778    _xwin.screen_height = h;
779    _xwin.screen_depth = depth;
780    _xwin.virtual_width = vw;
781    _xwin.virtual_height = vh;
782 
783    /* Resize the (real) window */
784    XResizeWindow(_xwin.display, _xwin.window, w, h);
785 
786    if (fullscreen) {
787       XSetWindowAttributes setattr;
788       /* Local width and height vars used for fullscreen window size and for
789        * storing the video_mode size which is then used to center the window.
790        */
791       int fs_width  = DisplayWidth(_xwin.display, _xwin.screen);
792       int fs_height = DisplayHeight(_xwin.display, _xwin.screen);
793 
794       /* Create the fullscreen window.  */
795       setattr.override_redirect = True;
796       setattr.background_pixel = XBlackPixel(_xwin.display, _xwin.screen);
797       setattr.border_pixel = XBlackPixel(_xwin.display, _xwin.screen);
798       setattr.event_mask = StructureNotifyMask;
799       setattr.colormap = _xwin.colormap;
800       _xwin.fs_window = XCreateWindow(_xwin.display,
801                                    XDefaultRootWindow(_xwin.display),
802                                    0, 0, fs_width, fs_height, 0,
803                                    CopyFromParent, InputOutput,
804                                    CopyFromParent, CWOverrideRedirect |
805                                    CWBackPixel | CWColormap | CWBorderPixel |
806                                    CWEventMask, &setattr);
807 
808       /* Map the fullscreen window.  */
809       XMapRaised(_xwin.display, _xwin.fs_window);
810       _xwin_wait_mapped(_xwin.fs_window);
811 
812       /* Make sure we got to the top of the window stack.  */
813       XRaiseWindow(_xwin.display, _xwin.fs_window);
814 
815       /* Reparent the real window.  */
816       XReparentWindow(_xwin.display, _xwin.window, _xwin.fs_window, 0, 0);
817 
818       /* Grab the keyboard and mouse.  */
819       if (XGrabKeyboard(_xwin.display, XDefaultRootWindow(_xwin.display), False,
820 			GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) {
821 	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not grab keyboard"));
822 	 return 0;
823       }
824       _xwin.keyboard_grabbed = 1;
825       if (XGrabPointer(_xwin.display, _xwin.window, False,
826 		       PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
827 		       GrabModeAsync, GrabModeAsync, _xwin.window, None, CurrentTime) != GrabSuccess) {
828 	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not grab mouse"));
829 	 return 0;
830       }
831       _xwin.mouse_grabbed = 1;
832 
833 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
834       /* Try to switch video mode. This must be done after the pointer is
835        * grabbed, because otherwise it can be outside the window negating the
836        * XF86VidModeSetViewPort done in set_fullscreen. This makes the old
837        * center the window hack unnescesarry. Notice that since the XF86VM
838        * extension requests do not go through the regular X output buffer? We
839        * need to make sure that all above requests are processed first.
840        */
841       XSync(_xwin.display, False);
842       _xvidmode_private_set_fullscreen(w, h, &fs_width, &fs_height);
843 #endif
844 
845       /* Center the window (if necessary).  */
846       if ((fs_width != w) || (fs_height != h))
847          XMoveWindow(_xwin.display, _xwin.window, (fs_width - w) / 2,
848             (fs_height - h) / 2);
849 
850       /* Last: center the cursor.  */
851       XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, w / 2, h / 2);
852    }
853    else {
854       XSizeHints *hints = XAllocSizeHints();;
855 
856       /* Resize managed window.  */
857       XResizeWindow(_xwin.display, _xwin.wm_window, w, h);
858 
859       /* Set size and position hints for Window Manager.  */
860       if (hints) {
861          hints->flags = PMinSize | PMaxSize | PBaseSize;
862          hints->min_width  = hints->max_width  = hints->base_width  = w;
863          hints->min_height = hints->max_height = hints->base_height = h;
864          XSetWMNormalHints(_xwin.display, _xwin.wm_window, hints);
865 
866          XFree(hints);
867       }
868 
869       /* Map the window managed window.  */
870       XMapWindow(_xwin.display, _xwin.wm_window);
871       _xwin_wait_mapped(_xwin.wm_window);
872    }
873 
874    /* Create XImage with the size of virtual screen.  */
875    if (_xwin_private_create_ximage(vw, vh) != 0) {
876       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not create XImage"));
877       return 0;
878    }
879 
880    /* Prepare visual for further use.  */
881    _xwin_private_prepare_visual();
882 
883    /* Test that frame buffer is fast (can be accessed directly).  */
884    _xwin.fast_visual_depth = _xwin_private_fast_visual_depth();
885 
886    /* Create screen bitmap from frame buffer.  */
887    return _xwin_private_create_screen_bitmap(drv,
888 					     (unsigned char *)_xwin.ximage->data + _xwin.ximage->xoffset,
889 					     _xwin.ximage->bytes_per_line);
890 }
891 
_xwin_create_screen(GFX_DRIVER * drv,int w,int h,int vw,int vh,int depth,int fullscreen)892 BITMAP *_xwin_create_screen(GFX_DRIVER *drv, int w, int h,
893 			    int vw, int vh, int depth, int fullscreen)
894 {
895    BITMAP *bmp;
896    XLOCK();
897    bmp = _xwin_private_create_screen(drv, w, h, vw, vh, depth, fullscreen);
898    if (bmp == 0) {
899       _xwin_private_destroy_screen();
900    }
901    XUNLOCK();
902    return bmp;
903 }
904 
905 
906 
907 /* _xwin_destroy_screen:
908  *  Destroys screen resources.
909  */
_xwin_private_destroy_screen(void)910 static void _xwin_private_destroy_screen(void)
911 {
912    if (_xwin.buffer_line != 0) {
913       _AL_FREE(_xwin.buffer_line);
914       _xwin.buffer_line = 0;
915    }
916 
917    if (_xwin.screen_line != 0) {
918       _AL_FREE(_xwin.screen_line);
919       _xwin.screen_line = 0;
920    }
921 
922    if (_xwin.screen_data != 0) {
923       _AL_FREE(_xwin.screen_data);
924       _xwin.screen_data = 0;
925    }
926 
927    _xwin_private_destroy_ximage();
928 
929    if (_xwin.mouse_grabbed) {
930       XUngrabPointer(_xwin.display, CurrentTime);
931       _xwin.mouse_grabbed = 0;
932    }
933 
934    if (_xwin.keyboard_grabbed) {
935       XUngrabKeyboard(_xwin.display, CurrentTime);
936       _xwin.keyboard_grabbed = 0;
937    }
938 
939 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
940    _xvidmode_private_unset_fullscreen();
941 #endif
942 
943    /* whack color-conversion blitter */
944    if (blitter_func) {
945       _release_colorconv_blitter(blitter_func);
946       blitter_func = NULL;
947    }
948 
949    if (_xwin.fs_window != None) {
950       /* Reparent the real window! */
951       XReparentWindow(_xwin.display, _xwin.window, _xwin.wm_window, 0, 0);
952       XUnmapWindow(_xwin.display, _xwin.fs_window);
953       XDestroyWindow(_xwin.display, _xwin.fs_window);
954       _xwin.fs_window = None;
955    }
956    else {
957       XUnmapWindow(_xwin.display, _xwin.wm_window);
958    }
959 
960    (*_xwin_window_defaultor)();
961 }
962 
_xwin_destroy_screen(void)963 void _xwin_destroy_screen(void)
964 {
965    XLOCK();
966    _xwin_private_destroy_screen();
967    XUNLOCK();
968 }
969 
970 
971 
972 /* _xwin_create_screen_bitmap:
973  *  Create screen bitmap from frame buffer.
974  */
_xwin_private_create_screen_bitmap(GFX_DRIVER * drv,unsigned char * frame_buffer,int bytes_per_buffer_line)975 static BITMAP *_xwin_private_create_screen_bitmap(GFX_DRIVER *drv,
976 						  unsigned char *frame_buffer,
977 						  int bytes_per_buffer_line)
978 {
979    int line;
980    int bytes_per_screen_line;
981    BITMAP *bmp;
982 
983    /* Test that Allegro and X-Windows pixel formats are the same.  */
984    _xwin.matching_formats = _xwin_private_matching_formats();
985 
986    /* Create mapping tables for color components.  */
987    _xwin_private_create_mapping_tables();
988 
989    /* Determine how to update frame buffer with screen data.  */
990    _xwin_private_select_screen_to_buffer_function();
991 
992    /* Determine how to set colors in "hardware".  */
993    _xwin_private_select_set_colors_function();
994 
995    /* Create line accelerators for screen data.  */
996    _xwin.screen_line = _AL_MALLOC_ATOMIC(_xwin.virtual_height * sizeof(unsigned char*));
997    if (_xwin.screen_line == 0) {
998       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory"));
999       return 0;
1000    }
1001 
1002    /* If formats match, then use frame buffer as screen data, otherwise malloc.  */
1003    if (_xwin.matching_formats) {
1004       bytes_per_screen_line = bytes_per_buffer_line;
1005       _xwin.screen_data = 0;
1006       _xwin.screen_line[0] = frame_buffer;
1007    }
1008    else {
1009       bytes_per_screen_line = _xwin.virtual_width * BYTES_PER_PIXEL(_xwin.screen_depth);
1010       _xwin.screen_data = _AL_MALLOC_ATOMIC(_xwin.virtual_height * bytes_per_screen_line);
1011       if (_xwin.screen_data == 0) {
1012 	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory"));
1013 	 return 0;
1014       }
1015       _xwin.screen_line[0] = _xwin.screen_data;
1016    }
1017 
1018    /* Initialize line starts.  */
1019    for (line = 1; line < _xwin.virtual_height; line++)
1020       _xwin.screen_line[line] = _xwin.screen_line[line - 1] + bytes_per_screen_line;
1021 
1022    /* Create line accelerators for frame buffer.  */
1023    if (!_xwin.matching_formats && _xwin.fast_visual_depth) {
1024       _xwin.buffer_line = _AL_MALLOC(_xwin.virtual_height * sizeof(unsigned char*));
1025       if (_xwin.buffer_line == 0) {
1026 	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory"));
1027 	 return 0;
1028       }
1029 
1030       _xwin.buffer_line[0] = frame_buffer;
1031       for (line = 1; line < _xwin.virtual_height; line++)
1032 	 _xwin.buffer_line[line] = _xwin.buffer_line[line - 1] + bytes_per_buffer_line;
1033    }
1034 
1035    /* Create bitmap.  */
1036    bmp = _make_bitmap(_xwin.virtual_width, _xwin.virtual_height,
1037 		      (uintptr_t) (_xwin.screen_line[0]), drv,
1038 		      _xwin.screen_depth, bytes_per_screen_line);
1039    if (bmp == 0) {
1040       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory"));
1041       return 0;
1042    }
1043 
1044    /* Fixup bitmap fields.  */
1045    drv->w = bmp->cr = _xwin.screen_width;
1046    drv->h = bmp->cb = _xwin.screen_height;
1047    drv->vid_mem = _xwin.virtual_width * _xwin.virtual_height * BYTES_PER_PIXEL(_xwin.screen_depth);
1048 
1049    /* Need some magic for updating frame buffer.  */
1050 #ifndef ALLEGRO_NO_ASM
1051    bmp->write_bank = _xwin_write_line_asm;
1052    bmp->vtable->unwrite_bank = _xwin_unwrite_line_asm;
1053 #else
1054    bmp->write_bank = _xwin_write_line;
1055    bmp->vtable->unwrite_bank = _xwin_unwrite_line;
1056 #endif
1057 
1058    /* Replace entries in vtable with magical wrappers.  */
1059    _xwin_replace_vtable(bmp->vtable);
1060 
1061    /* The drawing mode may not be ok for direct updates anymore. */
1062    _xwin_drawing_mode();
1063 
1064    /* Initialize other fields in _xwin structure.  */
1065    _xwin_last_line = -1;
1066    _xwin_in_gfx_call = 0;
1067    _xwin.scroll_x = 0;
1068    _xwin.scroll_y = 0;
1069 
1070    /* Setup driver description string.  */
1071    _xwin_private_setup_driver_desc(drv);
1072 
1073    return bmp;
1074 }
1075 
1076 
1077 
1078 /* _xwin_create_mapping_tables:
1079  *  Create mapping between Allegro color component and X-Windows color component.
1080  */
_xwin_private_create_mapping_tables(void)1081 static void _xwin_private_create_mapping_tables(void)
1082 {
1083    if (!_xwin.matching_formats) {
1084       if (_xwin.visual_is_truecolor) {
1085 	 switch (_xwin.screen_depth) {
1086 	    case 8:
1087 	       /* Will be modified later in set_palette.  */
1088 	       _xwin_private_create_mapping(_xwin.rmap, 256, 0, 0);
1089 	       _xwin_private_create_mapping(_xwin.gmap, 256, 0, 0);
1090 	       _xwin_private_create_mapping(_xwin.bmap, 256, 0, 0);
1091 	       break;
1092 	    case 15:
1093 	       _xwin_private_create_mapping(_xwin.rmap, 32, _xwin.rsize, _xwin.rshift);
1094 	       _xwin_private_create_mapping(_xwin.gmap, 32, _xwin.gsize, _xwin.gshift);
1095 	       _xwin_private_create_mapping(_xwin.bmap, 32, _xwin.bsize, _xwin.bshift);
1096 	       break;
1097 	    case 16:
1098 	       _xwin_private_create_mapping(_xwin.rmap, 32, _xwin.rsize, _xwin.rshift);
1099 	       _xwin_private_create_mapping(_xwin.gmap, 64, _xwin.gsize, _xwin.gshift);
1100 	       _xwin_private_create_mapping(_xwin.bmap, 32, _xwin.bsize, _xwin.bshift);
1101 	       break;
1102 	    case 24:
1103 	    case 32:
1104 	       _xwin_private_create_mapping(_xwin.rmap, 256, _xwin.rsize, _xwin.rshift);
1105 	       _xwin_private_create_mapping(_xwin.gmap, 256, _xwin.gsize, _xwin.gshift);
1106 	       _xwin_private_create_mapping(_xwin.bmap, 256, _xwin.bsize, _xwin.bshift);
1107 	       break;
1108 	 }
1109       }
1110       else {
1111 	 int i;
1112 
1113 	 /* Might be modified later in set_palette.  */
1114 	 for (i = 0; i < 256; i++)
1115 	    _xwin.rmap[i] = _xwin.gmap[i] = _xwin.bmap[i] = 0;
1116       }
1117    }
1118 }
1119 
1120 
1121 
1122 /* _xwin_create_mapping:
1123  *  Create mapping between Allegro color component and X-Windows color component.
1124  */
_xwin_private_create_mapping(unsigned long * map,int ssize,int dsize,int dshift)1125 static void _xwin_private_create_mapping(unsigned long *map, int ssize, int dsize, int dshift)
1126 {
1127    int i, smax, dmax;
1128 
1129    smax = ssize - 1;
1130    dmax = dsize - 1;
1131    for (i = 0; i < ssize; i++)
1132       map[i] = ((dmax * i) / smax) << dshift;
1133    for (; i < 256; i++)
1134       map[i] = map[i % ssize];
1135 }
1136 
1137 
1138 
1139 /* _xwin_display_is_local:
1140  *  Tests that display connection is local.
1141  *  (Note: this is duplicated in xdga2.c).
1142  */
_xwin_private_display_is_local(void)1143 static int _xwin_private_display_is_local(void)
1144 {
1145    char *name;
1146 
1147    if (_xwin.display == 0)
1148       return 0;
1149 
1150    /* Get display name and test for local display.  */
1151    name = XDisplayName(0);
1152 
1153    return (((name == 0) || (name[0] == ':') || (strncmp(name, "unix:", 5) == 0)) ? 1 : 0);
1154 }
1155 
1156 
1157 
1158 /* _xwin_create_ximage:
1159  *  Create XImage for accessing window.
1160  */
_xwin_private_create_ximage(int w,int h)1161 static int _xwin_private_create_ximage(int w, int h)
1162 {
1163    XImage *image = 0; /* I'm mage or I'm old?  */
1164 
1165    if (_xwin.display == 0)
1166       return -1;
1167 
1168 #ifdef ALLEGRO_XWINDOWS_WITH_SHM
1169    if (_xwin_private_display_is_local() && XShmQueryExtension(_xwin.display))
1170       _xwin.use_shm = 1;
1171    else
1172       _xwin.use_shm = 0;
1173 #else
1174    _xwin.use_shm = 0;
1175 #endif
1176 
1177 #ifdef ALLEGRO_XWINDOWS_WITH_SHM
1178    if (_xwin.use_shm) {
1179       /* Try to create shared memory XImage.  */
1180       image = XShmCreateImage(_xwin.display, _xwin.visual, _xwin.window_depth,
1181 			      ZPixmap, 0, &_xwin.shminfo, w, h);
1182       do {
1183 	 if (image != 0) {
1184 	    /* Create shared memory segment.  */
1185 	    _xwin.shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height,
1186 					 IPC_CREAT | 0777);
1187 	    if (_xwin.shminfo.shmid != -1) {
1188 	       /* Attach shared memory to our address space.  */
1189 	       _xwin.shminfo.shmaddr = image->data = shmat(_xwin.shminfo.shmid, 0, 0);
1190 	       if (_xwin.shminfo.shmaddr != (char*) -1) {
1191 		  _xwin.shminfo.readOnly = True;
1192 
1193 		  /* Attach shared memory to the X-server address space.  */
1194 		  if (XShmAttach(_xwin.display, &_xwin.shminfo)) {
1195 		     XSync(_xwin.display, False);
1196 		     break;
1197 		   }
1198 
1199 		  shmdt(_xwin.shminfo.shmaddr);
1200 	       }
1201 	       shmctl(_xwin.shminfo.shmid, IPC_RMID, 0);
1202 	    }
1203 	    XDestroyImage(image);
1204 	    image = 0;
1205 	 }
1206 	 _xwin.use_shm = 0;
1207       } while (0);
1208    }
1209 #endif
1210 
1211    if (image == 0) {
1212       /* Try to create ordinary XImage.  */
1213 #if 0
1214       Pixmap pixmap;
1215 
1216       pixmap = XCreatePixmap(_xwin.display, _xwin.window, w, h, _xwin.window_depth);
1217       if (pixmap != None) {
1218 	 image = XGetImage(_xwin.display, pixmap, 0, 0, w, h, AllPlanes, ZPixmap);
1219 	 XFreePixmap(_xwin.display, pixmap);
1220       }
1221 #else
1222       image = XCreateImage(_xwin.display, _xwin.visual, _xwin.window_depth,
1223 			   ZPixmap, 0, 0, w, h, 32, 0);
1224       if (image != 0) {
1225 	 image->data = _AL_MALLOC_ATOMIC(image->bytes_per_line * image->height);
1226 	 if (image->data == 0) {
1227 	    XDestroyImage(image);
1228 	    image = 0;
1229 	 }
1230       }
1231 #endif
1232    }
1233 
1234    _xwin.ximage = image;
1235 
1236    return ((image != 0) ? 0 : -1);
1237 }
1238 
1239 
1240 
1241 /* _xwin_destroy_ximage:
1242  *  Destroy XImage.
1243  */
_xwin_private_destroy_ximage(void)1244 static void _xwin_private_destroy_ximage(void)
1245 {
1246    if (_xwin.ximage != 0) {
1247 #ifdef ALLEGRO_XWINDOWS_WITH_SHM
1248       if (_xwin.use_shm) {
1249 	 XShmDetach(_xwin.display, &_xwin.shminfo);
1250 	 shmdt(_xwin.shminfo.shmaddr);
1251 	 shmctl(_xwin.shminfo.shmid, IPC_RMID, 0);
1252       }
1253 #endif
1254       XDestroyImage(_xwin.ximage);
1255       _xwin.ximage = 0;
1256    }
1257 }
1258 
1259 
1260 
1261 /* _xwin_prepare_visual:
1262  *  Prepare visual for further use.
1263  */
_xwin_private_prepare_visual(void)1264 static void _xwin_private_prepare_visual(void)
1265 {
1266    int i, r, g, b;
1267    int rmax, gmax, bmax;
1268    unsigned long mask;
1269    XColor color;
1270 
1271    if ((_xwin.visual->class == TrueColor)
1272        || (_xwin.visual->class == DirectColor)) {
1273       /* Use TrueColor and DirectColor visuals as truecolor.  */
1274 
1275       /* Red shift and size.  */
1276       for (mask = _xwin.visual->red_mask, i = 0; (mask & 1) != 1; mask >>= 1)
1277 	 i++;
1278       _xwin.rshift = i;
1279       for (i = 0; mask != 0; mask >>= 1)
1280 	 i++;
1281       _xwin.rsize = 1 << i;
1282 
1283       /* Green shift and size.  */
1284       for (mask = _xwin.visual->green_mask, i = 0; (mask & 1) != 1; mask >>= 1)
1285 	 i++;
1286       _xwin.gshift = i;
1287       for (i = 0; mask != 0; mask >>= 1)
1288 	 i++;
1289       _xwin.gsize = 1 << i;
1290 
1291       /* Blue shift and size.  */
1292       for (mask = _xwin.visual->blue_mask, i = 0; (mask & 1) != 1; mask >>= 1)
1293 	 i++;
1294       _xwin.bshift = i;
1295       for (i = 0; mask != 0; mask >>= 1)
1296 	 i++;
1297       _xwin.bsize = 1 << i;
1298 
1299       /* Convert DirectColor visual into true color visual.  */
1300       if (_xwin.visual->class == DirectColor) {
1301 	 color.flags = DoRed;
1302 	 rmax = _xwin.rsize - 1;
1303 	 gmax = _xwin.gsize - 1;
1304 	 bmax = _xwin.bsize - 1;
1305 	 for (i = 0; i < _xwin.rsize; i++) {
1306 	    color.pixel = i << _xwin.rshift;
1307 	    color.red = ((rmax <= 0) ? 0 : ((i * 65535L) / rmax));
1308 	    XStoreColor(_xwin.display, _xwin.colormap, &color);
1309 	 }
1310 	 color.flags = DoGreen;
1311 	 for (i = 0; i < _xwin.gsize; i++) {
1312 	    color.pixel = i << _xwin.gshift;
1313 	    color.green = ((gmax <= 0) ? 0 : ((i * 65535L) / gmax));
1314 	    XStoreColor(_xwin.display, _xwin.colormap, &color);
1315 	 }
1316 	 color.flags = DoBlue;
1317 	 for (i = 0; i < _xwin.bsize; i++) {
1318 	    color.pixel = i << _xwin.bshift;
1319 	    color.blue = ((bmax <= 0) ? 0 : ((i * 65535L) / bmax));
1320 	    XStoreColor(_xwin.display, _xwin.colormap, &color);
1321 	 }
1322       }
1323 
1324       _xwin.visual_is_truecolor = 1;
1325    }
1326    else if ((_xwin.visual->class == PseudoColor)
1327 	    || (_xwin.visual->class == GrayScale)) {
1328       /* Convert read-write palette visual into true color visual.  */
1329       b = _xwin.window_depth / 3;
1330       r = (_xwin.window_depth - b) / 2;
1331       g = _xwin.window_depth - r - b;
1332 
1333       _xwin.rsize = 1 << r;
1334       _xwin.gsize = 1 << g;
1335       _xwin.bsize = 1 << b;
1336       _xwin.rshift = g + b;
1337       _xwin.gshift = b;
1338       _xwin.bshift = 0;
1339 
1340       _xwin.visual_is_truecolor = 1;
1341 
1342       rmax = _xwin.rsize - 1;
1343       gmax = _xwin.gsize - 1;
1344       bmax = _xwin.bsize - 1;
1345 
1346       color.flags = DoRed | DoGreen | DoBlue;
1347       for (r = 0; r < _xwin.rsize; r++) {
1348 	 for (g = 0; g < _xwin.gsize; g++) {
1349 	    for (b = 0; b < _xwin.bsize; b++) {
1350 	       color.pixel = (r << _xwin.rshift) | (g << _xwin.gshift) | (b << _xwin.bshift);
1351 	       color.red = ((rmax <= 0) ? 0 : ((r * 65535L) / rmax));
1352 	       color.green = ((gmax <= 0) ? 0 : ((g * 65535L) / gmax));
1353 	       color.blue = ((bmax <= 0) ? 0 : ((b * 65535L) / bmax));
1354 	       XStoreColor(_xwin.display, _xwin.colormap, &color);
1355 	    }
1356 	 }
1357       }
1358    }
1359    else {
1360       /* All other visual types are paletted.  */
1361       _xwin.rsize = 1;
1362       _xwin.bsize = 1;
1363       _xwin.gsize = 1;
1364       _xwin.rshift = 0;
1365       _xwin.gshift = 0;
1366       _xwin.bshift = 0;
1367 
1368       _xwin.visual_is_truecolor = 0;
1369 
1370       /* Make fixed palette and create mapping RRRRGGGGBBBB -> palette index.  */
1371       for (r = 0; r < 16; r++) {
1372 	 for (g = 0; g < 16; g++) {
1373 	    for (b = 0; b < 16; b++) {
1374 	       color.red = (r * 65535L) / 15;
1375 	       color.green = (g * 65535L) / 15;
1376 	       color.blue = (b * 65535L) / 15;
1377 	       XAllocColor(_xwin.display, _xwin.colormap, &color);
1378 	       _xwin.cmap[(r << 8) | (g << 4) | b] = color.pixel;
1379 	    }
1380 	 }
1381       }
1382    }
1383 }
1384 
1385 
1386 
1387 /* _xwin_matching_formats:
1388  *  Find if color formats match.
1389  */
_xwin_private_matching_formats(void)1390 static int _xwin_private_matching_formats(void)
1391 {
1392    if (_xwin.fast_visual_depth == 0)
1393       return 0;
1394 
1395    if (_xwin.screen_depth == 8) {
1396       /* For matching 8 bpp modes visual must be PseudoColor or GrayScale.  */
1397       if (((_xwin.visual->class != PseudoColor)
1398 	   && (_xwin.visual->class != GrayScale))
1399 	  || (_xwin.fast_visual_depth != 8)
1400 	  || (_xwin.window_depth != 8))
1401 	 return 0;
1402    }
1403    else if ((_xwin.visual->class != TrueColor)
1404 	    && (_xwin.visual->class != DirectColor)) {
1405       /* For matching true color modes visual must be TrueColor or DirectColor.  */
1406       return 0;
1407    }
1408    else if (_xwin.screen_depth == 15) {
1409       if ((_xwin.fast_visual_depth != 16)
1410 	  || (_xwin.rsize != 32) || (_xwin.gsize != 32) || (_xwin.bsize != 32)
1411 	  || ((_xwin.rshift != 0) && (_xwin.rshift != 10))
1412 	  || ((_xwin.bshift != 0) && (_xwin.bshift != 10))
1413 	  || (_xwin.gshift != 5))
1414 	 return 0;
1415       _rgb_r_shift_15 = _xwin.rshift;
1416       _rgb_g_shift_15 = _xwin.gshift;
1417       _rgb_b_shift_15 = _xwin.bshift;
1418    }
1419    else if (_xwin.screen_depth == 16) {
1420       if ((_xwin.fast_visual_depth != 16)
1421 	  || (_xwin.rsize != 32) || (_xwin.gsize != 64) || (_xwin.bsize != 32)
1422 	  || ((_xwin.rshift != 0) && (_xwin.rshift != 11))
1423 	  || ((_xwin.bshift != 0) && (_xwin.bshift != 11))
1424 	  || (_xwin.gshift != 5))
1425 	 return 0;
1426       _rgb_r_shift_16 = _xwin.rshift;
1427       _rgb_g_shift_16 = _xwin.gshift;
1428       _rgb_b_shift_16 = _xwin.bshift;
1429    }
1430    else if (_xwin.screen_depth == 24){
1431       if ((_xwin.fast_visual_depth != 24)
1432 	  || (_xwin.rsize != 256) || (_xwin.gsize != 256) || (_xwin.bsize != 256)
1433 	  || ((_xwin.rshift != 0) && (_xwin.rshift != 16))
1434 	  || ((_xwin.bshift != 0) && (_xwin.bshift != 16))
1435 	  || (_xwin.gshift != 8))
1436 	 return 0;
1437       _rgb_r_shift_24 = _xwin.rshift;
1438       _rgb_g_shift_24 = _xwin.gshift;
1439       _rgb_b_shift_24 = _xwin.bshift;
1440    }
1441    else if (_xwin.screen_depth == 32) {
1442       if ((_xwin.fast_visual_depth != 32)
1443 	  || (_xwin.rsize != 256) || (_xwin.gsize != 256) || (_xwin.bsize != 256)
1444 	  || ((_xwin.rshift != 0) && (_xwin.rshift != 16))
1445 	  || ((_xwin.bshift != 0) && (_xwin.bshift != 16))
1446 	  || (_xwin.gshift != 8))
1447 	 return 0;
1448       _rgb_r_shift_32 = _xwin.rshift;
1449       _rgb_g_shift_32 = _xwin.gshift;
1450       _rgb_b_shift_32 = _xwin.bshift;
1451    }
1452    else {
1453       /* How did you get in here?  */
1454       return 0;
1455    }
1456 
1457    return 1;
1458 }
1459 
1460 
1461 
1462 /* _xwin_private_hack_shifts:
1463  *  Make Allegro draw in BGR format if X uses BGR instead of RGB.
1464  */
_xwin_private_hack_shifts(void)1465 static void _xwin_private_hack_shifts(void)
1466 {
1467    switch(_xwin.screen_depth) {
1468       case 8:
1469          use_bgr_palette_hack = TRUE;
1470          break;
1471       case 15:
1472          _rgb_r_shift_15 = 10;
1473          _rgb_g_shift_15 = 5;
1474          _rgb_b_shift_15 = 0;
1475          break;
1476       case 16:
1477          _rgb_r_shift_16 = 11;
1478          _rgb_g_shift_16 = 5;
1479          _rgb_b_shift_16 = 0;
1480          break;
1481       case 24:
1482          _rgb_r_shift_24 = 16;
1483          _rgb_g_shift_24 = 8;
1484          _rgb_b_shift_24 = 0;
1485          break;
1486       case 32:
1487          _rgb_r_shift_32 = 16;
1488          _rgb_g_shift_32 = 8;
1489          _rgb_b_shift_32 = 0;
1490          break;
1491    }
1492 }
1493 
1494 
1495 
1496 /* _xwin_private_colorconv_usable:
1497  *  Find out if generic color conversion blitter can be used.
1498  */
_xwin_private_colorconv_usable(void)1499 static int _xwin_private_colorconv_usable(void)
1500 {
1501    use_bgr_palette_hack = FALSE; /* make sure this is initialized */
1502 
1503    if (_xwin.fast_visual_depth == 0) {
1504       return 0;
1505    }
1506    else if (_xwin.fast_visual_depth == 8) {
1507 #if 0
1508       /* TODO: check this out later. */
1509 
1510       /* For usable 8 bpp modes visual must be PseudoColor or GrayScale.  */
1511       if ((_xwin.visual->class == PseudoColor)
1512 	   || (_xwin.visual->class == GrayScale))
1513 	 return 1;
1514 #else
1515       return 0;
1516 #endif
1517    }
1518    else if ((_xwin.visual->class != TrueColor)
1519 	    && (_xwin.visual->class != DirectColor)) {
1520       /* For usable true color modes visual must be TrueColor or DirectColor.  */
1521       return 0;
1522    }
1523    else if ((_xwin.fast_visual_depth == 16)
1524        && (_xwin.rsize == 32) && ((_xwin.gsize == 32) || (_xwin.gsize == 64)) && (_xwin.bsize == 32)
1525        && ((_xwin.rshift == 0) || (_xwin.rshift == 10) || (_xwin.rshift == 11))
1526        && ((_xwin.bshift == 0) || (_xwin.bshift == 10) || (_xwin.bshift == 11))
1527        && (_xwin.gshift == 5)) {
1528       if (_xwin.bshift == 0)
1529 	 _xwin_private_hack_shifts();
1530       return 1;
1531    }
1532    else if ((_xwin.fast_visual_depth == 24)
1533        && (_xwin.rsize == 256) && (_xwin.gsize == 256) && (_xwin.bsize == 256)
1534        && ((_xwin.rshift == 0) || (_xwin.rshift == 16))
1535        && ((_xwin.bshift == 0) || (_xwin.bshift == 16))
1536        && (_xwin.gshift == 8)) {
1537       if (_xwin.bshift == 0)
1538 	 _xwin_private_hack_shifts();
1539       return 1;
1540    }
1541    else if ((_xwin.fast_visual_depth == 32)
1542        && (_xwin.rsize == 256) && (_xwin.gsize == 256) && (_xwin.bsize == 256)
1543        && ((_xwin.rshift == 0) || (_xwin.rshift == 16))
1544        && ((_xwin.bshift == 0) || (_xwin.bshift == 16))
1545        && (_xwin.gshift == 8)) {
1546       if (_xwin.bshift == 0)
1547 	 _xwin_private_hack_shifts();
1548       return 1;
1549    }
1550 
1551    /* Too bad... Muahahaha! */
1552    return 0;
1553 }
1554 
1555 
1556 
1557 /* _xwin_fast_visual_depth:
1558  *  Find which depth is fast (when XImage can be accessed directly).
1559  */
_xwin_private_fast_visual_depth(void)1560 static int _xwin_private_fast_visual_depth(void)
1561 {
1562    int ok, x, sizex;
1563    int test_depth;
1564    uint8_t *p8;
1565    uint16_t *p16;
1566    uint32_t *p32;
1567 
1568    if (_xwin.ximage == 0)
1569       return 0;
1570 
1571    /* Use first line of XImage for test.  */
1572    p8 = (uint8_t *) _xwin.ximage->data + _xwin.ximage->xoffset;
1573    p16 = (uint16_t*) p8;
1574    p32 = (uint32_t*) p8;
1575 
1576    sizex = _xwin.ximage->bytes_per_line - _xwin.ximage->xoffset;
1577 
1578    if ((_xwin.window_depth < 1) || (_xwin.window_depth > 32)) {
1579       return 0;
1580    }
1581    else if (_xwin.window_depth > 16) {
1582       test_depth = 32;
1583       sizex /= sizeof (uint32_t);
1584    }
1585    else if (_xwin.window_depth > 8) {
1586       test_depth = 16;
1587       sizex /= sizeof (uint16_t);
1588    }
1589    else {
1590       test_depth = 8;
1591    }
1592    if (sizex > _xwin.ximage->width)
1593       sizex = _xwin.ximage->width;
1594 
1595    /* Need at least two pixels wide line for test.  */
1596    if (sizex < 2)
1597       return 0;
1598 
1599    ok = 1;
1600    for (x = 0; x < sizex; x++) {
1601       int bit;
1602 
1603       for (bit = -1; bit < _xwin.window_depth; bit++) {
1604 	 unsigned long color = ((bit < 0) ? 0 : ((unsigned long) 1 << bit));
1605 
1606 	 /* Write color through XImage API.  */
1607 	 XPutPixel(_xwin.ximage, x, 0, color);
1608 
1609 	 /* Read color with direct access.  */
1610 	 switch (test_depth) {
1611 	    case 8:
1612 	       if (p8[x] != color)
1613 		  ok = 0;
1614 	       break;
1615 	    case 16:
1616 	       if (p16[x] != color)
1617 		  ok = 0;
1618 	       break;
1619 	    case 32:
1620 	       if (p32[x] != color)
1621 		  ok = 0;
1622 	       break;
1623 	    default:
1624 	       ok = 0;
1625 	       break;
1626 	 }
1627 	 XPutPixel(_xwin.ximage, x, 0, 0);
1628 
1629 	 if (!ok)
1630 	    return 0;
1631       }
1632    }
1633 
1634    return test_depth;
1635 }
1636 
1637 
1638 
1639 /* _xwin_enable_hardware_cursor:
1640  *  enable the hardware cursor; this disables the mouse mickey warping hack
1641  */
_xwin_enable_hardware_cursor(int mode)1642 void _xwin_enable_hardware_cursor(int mode)
1643 {
1644 #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
1645    if (_xwin.support_argb_cursor) {
1646       _xwin.hw_cursor_ok = mode;
1647    }
1648    else
1649 #endif
1650    {
1651       _xwin.hw_cursor_ok = 0;
1652    }
1653 
1654    /* Switch to non-warped mode */
1655    if (_xwin.hw_cursor_ok) {
1656       _xwin.mouse_warped = 0;
1657       /* Move X-cursor to Allegro cursor.  */
1658       XLOCK();
1659       XWarpPointer(_xwin.display, _xwin.window, _xwin.window,
1660 		   0, 0, _xwin.window_width, _xwin.window_height,
1661 		   _mouse_x - (_xwin_mouse_extended_range ? _xwin.scroll_x : 0),
1662 		   _mouse_y - (_xwin_mouse_extended_range ? _xwin.scroll_y : 0));
1663       XUNLOCK();
1664    }
1665 }
1666 
1667 
1668 
1669 #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
1670 
1671 /* _xwin_set_mouse_sprite:
1672  *  Set custom X cursor (if supported).
1673  */
_xwin_set_mouse_sprite(struct BITMAP * sprite,int xfocus,int yfocus)1674 int _xwin_set_mouse_sprite(struct BITMAP *sprite, int xfocus, int yfocus)
1675 {
1676 #define GET_PIXEL_DATA(depth, getpix)                                \
1677                case depth:                                           \
1678                   c = 0;                                             \
1679                   for (iy = 0; iy < sprite->h; iy++) {               \
1680                      for(ix = 0; ix < sprite->w; ix++) {             \
1681                         col = getpix(sprite, ix, iy);                \
1682                         if (col == (MASK_COLOR_ ## depth)) {         \
1683                            r = g = b = a = 0;                        \
1684                         }                                            \
1685                         else {                                       \
1686                            r = getr ## depth(col);                   \
1687                            g = getg ## depth(col);                   \
1688                            b = getb ## depth(col);                   \
1689                            a = 255;                                  \
1690                         }                                            \
1691                         _xwin.xcursor_image->pixels[c++] =           \
1692                                     (a<<24)|(r<<16)|(g<<8)|(b);      \
1693                      }                                               \
1694                   }
1695 
1696    if (!_xwin.support_argb_cursor) {
1697       return -1;
1698    }
1699 
1700    if (_xwin.xcursor_image != None) {
1701       XLOCK();
1702       XcursorImageDestroy(_xwin.xcursor_image);
1703       XUNLOCK();
1704       _xwin.xcursor_image = None;
1705    }
1706 
1707    if (sprite) {
1708       int ix, iy;
1709       int r = 0, g = 0, b = 0, a = 0, c, col;
1710 
1711       _xwin.xcursor_image = XcursorImageCreate(sprite->w, sprite->h);
1712       if (_xwin.xcursor_image == None) {
1713          return -1;
1714       }
1715 
1716       switch (bitmap_color_depth(sprite)) {
1717          GET_PIXEL_DATA(8, _getpixel)
1718             break;
1719 
1720          GET_PIXEL_DATA(15, _getpixel15)
1721             break;
1722 
1723          GET_PIXEL_DATA(16, _getpixel16)
1724             break;
1725 
1726          GET_PIXEL_DATA(24, _getpixel24)
1727             break;
1728 
1729          GET_PIXEL_DATA(32, _getpixel32)
1730             break;
1731       } /* End switch */
1732 
1733       _xwin.xcursor_image->xhot = xfocus;
1734       _xwin.xcursor_image->yhot = yfocus;
1735 
1736       return 0;
1737    }
1738 
1739    return -1;
1740 
1741 #undef GET_PIXEL_DATA
1742 }
1743 
1744 
1745 
1746 /* _xwin_show_mouse:
1747  *  Show the custom X cursor (if supported)
1748  */
_xwin_show_mouse(struct BITMAP * bmp,int x,int y)1749 int _xwin_show_mouse(struct BITMAP *bmp, int x, int y)
1750 {
1751    /* Only draw on screen */
1752    if (!is_same_bitmap(bmp, screen))
1753       return -1;
1754 
1755    if (!_xwin.support_argb_cursor) {
1756       return -1;
1757    }
1758 
1759    if (_xwin.xcursor_image == None) {
1760       return -1;
1761    }
1762 
1763    /* Hardware cursor is disabled (mickey mode) */
1764    if (!_xwin.hw_cursor_ok) {
1765       return -1;
1766    }
1767 
1768    XLOCK();
1769    if (_xwin.cursor != None) {
1770       XUndefineCursor(_xwin.display, _xwin.window);
1771       XFreeCursor(_xwin.display, _xwin.cursor);
1772    }
1773 
1774    _xwin.cursor = XcursorImageLoadCursor(_xwin.display, _xwin.xcursor_image);
1775    XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
1776 
1777    XUNLOCK();
1778    return 0;
1779 }
1780 
1781 
1782 
1783 /* _xwin_hide_mouse:
1784  *  Hide the custom X cursor (if supported)
1785  */
_xwin_hide_mouse(void)1786 void _xwin_hide_mouse(void)
1787 {
1788    if (_xwin.support_argb_cursor) {
1789       XLOCK();
1790       _xwin_hide_x_mouse();
1791       XUNLOCK();
1792    }
1793    return;
1794 }
1795 
1796 
1797 
1798 /* _xwin_move_mouse:
1799  *  Get mouse move notification. Not that we need it...
1800  */
_xwin_move_mouse(int x,int y)1801 void _xwin_move_mouse(int x, int y)
1802 {
1803 }
1804 
1805 #endif   /* ALLEGRO_XWINDOWS_WITH_XCURSOR */
1806 
1807 
1808 
1809 /*
1810  * Functions for copying screen data to frame buffer.
1811  */
_xwin_private_fast_colorconv(int sx,int sy,int sw,int sh)1812 static void _xwin_private_fast_colorconv(int sx, int sy, int sw, int sh)
1813 {
1814    GRAPHICS_RECT src_rect, dest_rect;
1815 
1816    /* set up source and destination rectangles */
1817    src_rect.height = sh;
1818    src_rect.width  = sw;
1819    src_rect.pitch  = _xwin.screen_line[1] - _xwin.screen_line[0];
1820    src_rect.data   = _xwin.screen_line[sy] + sx * BYTES_PER_PIXEL(_xwin.screen_depth);
1821 
1822    dest_rect.height = sh;
1823    dest_rect.width  = sw;
1824    dest_rect.pitch  = _xwin.buffer_line[1] - _xwin.buffer_line[0];
1825    dest_rect.data   = _xwin.buffer_line[sy] + sx * BYTES_PER_PIXEL(_xwin.fast_visual_depth);
1826 
1827    /* Update frame buffer with screen contents.  */
1828    ASSERT(blitter_func);
1829    blitter_func(&src_rect, &dest_rect);
1830 }
1831 
1832 #ifdef ALLEGRO_LITTLE_ENDIAN
1833    #define DEFAULT_RGB_R_POS_24  (DEFAULT_RGB_R_SHIFT_24/8)
1834    #define DEFAULT_RGB_G_POS_24  (DEFAULT_RGB_G_SHIFT_24/8)
1835    #define DEFAULT_RGB_B_POS_24  (DEFAULT_RGB_B_SHIFT_24/8)
1836 #elif defined ALLEGRO_BIG_ENDIAN
1837    #define DEFAULT_RGB_R_POS_24  (2-DEFAULT_RGB_R_SHIFT_24/8)
1838    #define DEFAULT_RGB_G_POS_24  (2-DEFAULT_RGB_G_SHIFT_24/8)
1839    #define DEFAULT_RGB_B_POS_24  (2-DEFAULT_RGB_B_SHIFT_24/8)
1840 #else
1841    #error endianess not defined
1842 #endif
1843 
1844 #define MAKE_FAST_TRUECOLOR(name,stype,dtype,rshift,gshift,bshift,rmask,gmask,bmask)    \
1845 static void name(int sx, int sy, int sw, int sh)                                        \
1846 {                                                                                       \
1847    int y, x;                                                                            \
1848    for (y = sy; y < (sy + sh); y++) {                                                   \
1849       stype *s = (stype*) (_xwin.screen_line[y]) + sx;                                  \
1850       dtype *d = (dtype*) (_xwin.buffer_line[y]) + sx;                                  \
1851       for (x = sw - 1; x >= 0; x--) {                                                   \
1852 	 unsigned long color = *s++;                                                    \
1853 	 *d++ = (_xwin.rmap[(color >> (rshift)) & (rmask)]                              \
1854 		 | _xwin.gmap[(color >> (gshift)) & (gmask)]                            \
1855 		 | _xwin.bmap[(color >> (bshift)) & (bmask)]);                          \
1856       }                                                                                 \
1857    }                                                                                    \
1858 }
1859 
1860 #define MAKE_FAST_TRUECOLOR24(name,dtype)                                               \
1861 static void name(int sx, int sy, int sw, int sh)                                        \
1862 {                                                                                       \
1863    int x, y;                                                                            \
1864    for (y = sy; y < (sy + sh); y++) {                                                   \
1865       unsigned char *s = _xwin.screen_line[y] + 3 * sx;                                 \
1866       dtype *d = (dtype*) (_xwin.buffer_line[y]) + sx;                                  \
1867       for (x = sw - 1; x >= 0; s += 3, x--) {                                           \
1868 	 *d++ = (_xwin.rmap[s[DEFAULT_RGB_R_POS_24]]                                    \
1869 		 | _xwin.gmap[s[DEFAULT_RGB_G_POS_24]]                                  \
1870 		 | _xwin.bmap[s[DEFAULT_RGB_B_POS_24]]);                                \
1871       }                                                                                 \
1872    }                                                                                    \
1873 }
1874 
1875 #define MAKE_FAST_TRUECOLOR_TO24(name,stype,rshift,gshift,bshift,rmask,gmask,bmask)     \
1876 static void name(int sx, int sy, int sw, int sh)                                        \
1877 {                                                                                       \
1878    int x, y;                                                                            \
1879    for (y = sy; y < (sy + sh); y++) {                                                   \
1880       stype *s = (stype*) (_xwin.screen_line[y]) + sx;                                  \
1881       unsigned char *d = _xwin.buffer_line[y] + 3 * sx;                                 \
1882       for (x = sw - 1; x >= 0; d += 3, x--) {                                           \
1883 	 unsigned long color = *s++;                                                    \
1884 	 color = (_xwin.rmap[(color >> (rshift)) & (rmask)]                             \
1885 		  | _xwin.gmap[(color >> (gshift)) & (gmask)]                           \
1886 		  | _xwin.bmap[(color >> (bshift)) & (bmask)]);                         \
1887 	 WRITE3BYTES(d, color);                                                         \
1888       }                                                                                 \
1889    }                                                                                    \
1890 }
1891 
1892 #define MAKE_FAST_TRUECOLOR24_TO24(name)                                                \
1893 static void name(int sx, int sy, int sw, int sh)                                        \
1894 {                                                                                       \
1895    int x, y;                                                                            \
1896    for (y = sy; y < (sy + sh); y++) {                                                   \
1897       unsigned char *s = _xwin.screen_line[y] + 3 * sx;                                 \
1898       unsigned char *d = _xwin.buffer_line[y] + 3 * sx;                                 \
1899       for (x = sw - 1; x >= 0; s += 3, d += 3, x--) {                                   \
1900 	 unsigned long color = _xwin.rmap[s[DEFAULT_RGB_R_POS_24]]                      \
1901 	 		       | _xwin.gmap[s[DEFAULT_RGB_G_POS_24]]                    \
1902 			       | _xwin.bmap[s[DEFAULT_RGB_B_POS_24]];                   \
1903 	 WRITE3BYTES(d, color);                                                         \
1904       }                                                                                 \
1905    }                                                                                    \
1906 }
1907 
1908 MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_8_to_8,
1909 		    unsigned char, unsigned char, 0, 0, 0, 0xFF, 0xFF, 0xFF);
1910 MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_8_to_16,
1911 		    unsigned char, unsigned short, 0, 0, 0, 0xFF, 0xFF, 0xFF);
1912 MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_8_to_32,
1913 		    unsigned char, uint32_t, 0, 0, 0, 0xFF, 0xFF, 0xFF);
1914 
1915 MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_15_to_8,
1916 		    unsigned short, unsigned char, 0, 5, 10, 0x1F, 0x1F, 0x1F);
1917 MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_15_to_16,
1918 		    unsigned short, unsigned short, 0, 5, 10, 0x1F, 0x1F, 0x1F);
1919 MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_15_to_32,
1920 		    unsigned short, uint32_t, 0, 5, 10, 0x1F, 0x1F, 0x1F);
1921 
1922 MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_16_to_8,
1923 		    unsigned short, unsigned char, 0, 5, 11, 0x1F, 0x3F, 0x1F);
1924 MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_16_to_16,
1925 		    unsigned short, unsigned short, 0, 5, 11, 0x1F, 0x3F, 0x1F);
1926 MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_16_to_32,
1927 		    unsigned short, uint32_t, 0, 5, 11, 0x1F, 0x3F, 0x1F);
1928 
1929 MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_32_to_8,
1930 		    uint32_t, unsigned char, 0, 8, 16, 0xFF, 0xFF, 0xFF);
1931 MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_32_to_16,
1932 		    uint32_t, unsigned short, 0, 8, 16, 0xFF, 0xFF, 0xFF);
1933 MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_32_to_32,
1934 		    uint32_t, uint32_t, 0, 8, 16, 0xFF, 0xFF, 0xFF);
1935 
1936 MAKE_FAST_TRUECOLOR24(_xwin_private_fast_truecolor_24_to_8,
1937 		      unsigned char);
1938 MAKE_FAST_TRUECOLOR24(_xwin_private_fast_truecolor_24_to_16,
1939 		      unsigned short);
1940 MAKE_FAST_TRUECOLOR24(_xwin_private_fast_truecolor_24_to_32,
1941 		      uint32_t);
1942 
1943 MAKE_FAST_TRUECOLOR_TO24(_xwin_private_fast_truecolor_8_to_24,
1944 			 unsigned char, 0, 0, 0, 0xFF, 0xFF, 0xFF);
1945 MAKE_FAST_TRUECOLOR_TO24(_xwin_private_fast_truecolor_15_to_24,
1946 			 unsigned short, 0, 5, 10, 0x1F, 0x1F, 0x1F);
1947 MAKE_FAST_TRUECOLOR_TO24(_xwin_private_fast_truecolor_16_to_24,
1948 			 unsigned short, 0, 5, 11, 0x1F, 0x3F, 0x1F);
1949 MAKE_FAST_TRUECOLOR_TO24(_xwin_private_fast_truecolor_32_to_24,
1950 			 uint32_t, 0, 8, 16, 0xFF, 0xFF, 0xFF);
1951 
1952 MAKE_FAST_TRUECOLOR24_TO24(_xwin_private_fast_truecolor_24_to_24);
1953 
1954 #define MAKE_FAST_PALETTE8(name,dtype)                                                  \
1955 static void name(int sx, int sy, int sw, int sh)                                        \
1956 {                                                                                       \
1957    int x, y;                                                                            \
1958    for (y = sy; y < (sy + sh); y++) {                                                   \
1959       unsigned char *s = _xwin.screen_line[y] + sx;                                     \
1960       dtype *d = (dtype*) (_xwin.buffer_line[y]) + sx;                                  \
1961       for (x = sw - 1; x >= 0; x--) {                                                   \
1962 	 unsigned long color = *s++;                                                    \
1963 	 *d++ = _xwin.cmap[(_xwin.rmap[color]                                           \
1964 			    | _xwin.gmap[color]                                         \
1965 			    | _xwin.bmap[color])];                                      \
1966       }                                                                                 \
1967    }                                                                                    \
1968 }
1969 
1970 #define MAKE_FAST_PALETTE(name,stype,dtype,rshift,gshift,bshift)                        \
1971 static void name(int sx, int sy, int sw, int sh)                                        \
1972 {                                                                                       \
1973    int x, y;                                                                            \
1974    for (y = sy; y < (sy + sh); y++) {                                                   \
1975       stype *s = (stype*) (_xwin.screen_line[y]) + sx;                                  \
1976       dtype *d = (dtype*) (_xwin.buffer_line[y]) + sx;                                  \
1977       for (x = sw - 1; x >= 0; x--) {                                                   \
1978 	 unsigned long color = *s++;                                                    \
1979 	 *d++ = _xwin.cmap[((((color >> (rshift)) & 0x0F) << 8)                         \
1980 			    | (((color >> (gshift)) & 0x0F) << 4)                       \
1981 			    | ((color >> (bshift)) & 0x0F))];                           \
1982       }                                                                                 \
1983    }                                                                                    \
1984 }
1985 
1986 #define MAKE_FAST_PALETTE24(name,dtype)                                                 \
1987 static void name(int sx, int sy, int sw, int sh)                                        \
1988 {                                                                                       \
1989    int x, y;                                                                            \
1990    for (y = sy; y < (sy + sh); y++) {                                                   \
1991       unsigned char *s = _xwin.screen_line[y] + 3 * sx;                                 \
1992       dtype *d = (dtype*) (_xwin.buffer_line[y]) + sx;                                  \
1993       for (x = sw - 1; x >= 0; s += 3, x--) {                                           \
1994 	 *d++ = _xwin.cmap[((((unsigned long) s[DEFAULT_RGB_R_POS_24] << 4) & 0xF00)    \
1995 			    | ((unsigned long) s[DEFAULT_RGB_G_POS_24] & 0xF0)          \
1996 			    | (((unsigned long) s[DEFAULT_RGB_B_POS_24] >> 4) & 0x0F))];\
1997       }                                                                                 \
1998    }                                                                                    \
1999 }
2000 
2001 MAKE_FAST_PALETTE8(_xwin_private_fast_palette_8_to_8,
2002 		   unsigned char);
2003 MAKE_FAST_PALETTE8(_xwin_private_fast_palette_8_to_16,
2004 		   unsigned short);
2005 MAKE_FAST_PALETTE8(_xwin_private_fast_palette_8_to_32,
2006 		   uint32_t);
2007 
2008 MAKE_FAST_PALETTE(_xwin_private_fast_palette_15_to_8,
2009 		  unsigned short, unsigned char, 1, 6, 11);
2010 MAKE_FAST_PALETTE(_xwin_private_fast_palette_15_to_16,
2011 		  unsigned short, unsigned short, 1, 6, 11);
2012 MAKE_FAST_PALETTE(_xwin_private_fast_palette_15_to_32,
2013 		  unsigned short, uint32_t, 1, 6, 11);
2014 
2015 MAKE_FAST_PALETTE(_xwin_private_fast_palette_16_to_8,
2016 		  unsigned short, unsigned char, 1, 7, 12);
2017 MAKE_FAST_PALETTE(_xwin_private_fast_palette_16_to_16,
2018 		  unsigned short, unsigned short, 1, 7, 12);
2019 MAKE_FAST_PALETTE(_xwin_private_fast_palette_16_to_32,
2020 		  unsigned short, uint32_t, 1, 7, 12);
2021 
2022 MAKE_FAST_PALETTE(_xwin_private_fast_palette_32_to_8,
2023 		  uint32_t, unsigned char, 4, 12, 20);
2024 MAKE_FAST_PALETTE(_xwin_private_fast_palette_32_to_16,
2025 		  uint32_t, unsigned short, 4, 12, 20);
2026 MAKE_FAST_PALETTE(_xwin_private_fast_palette_32_to_32,
2027 		  uint32_t, uint32_t, 4, 12, 20);
2028 
2029 MAKE_FAST_PALETTE24(_xwin_private_fast_palette_24_to_8,
2030 		    unsigned char);
2031 MAKE_FAST_PALETTE24(_xwin_private_fast_palette_24_to_16,
2032 		    unsigned short);
2033 MAKE_FAST_PALETTE24(_xwin_private_fast_palette_24_to_32,
2034 		    uint32_t);
2035 
2036 #define MAKE_SLOW_TRUECOLOR(name,stype,rshift,gshift,bshift,rmask,gmask,bmask)          \
2037 static void name(int sx, int sy, int sw, int sh)                                        \
2038 {                                                                                       \
2039    int x, y;                                                                            \
2040    for (y = sy; y < (sy + sh); y++) {                                                   \
2041       stype *s = (stype*) (_xwin.screen_line[y]) + sx;                                  \
2042       for (x = sx; x < (sx + sw); x++) {                                                \
2043 	 unsigned long color = *s++;                                                    \
2044 	 XPutPixel (_xwin.ximage, x, y,                                                 \
2045 		    (_xwin.rmap[(color >> (rshift)) & (rmask)]                          \
2046 		     | _xwin.gmap[(color >> (gshift)) & (gmask)]                        \
2047 		     | _xwin.bmap[(color >> (bshift)) & (bmask)]));                     \
2048       }                                                                                 \
2049    }                                                                                    \
2050 }
2051 
2052 #define MAKE_SLOW_TRUECOLOR24(name)                                                     \
2053 static void name(int sx, int sy, int sw, int sh)                                        \
2054 {                                                                                       \
2055    int x, y;                                                                            \
2056    for (y = sy; y < (sy + sh); y++) {                                                   \
2057       unsigned char *s = _xwin.screen_line[y] + 3 * sx;                                 \
2058       for (x = sx; x < (sx + sw); s += 3, x++) {                                        \
2059 	 XPutPixel(_xwin.ximage, x, y,                                                  \
2060 		   (_xwin.rmap[s[DEFAULT_RGB_R_POS_24]]                                 \
2061 		    | _xwin.gmap[s[DEFAULT_RGB_G_POS_24]]                               \
2062 		    | _xwin.bmap[s[DEFAULT_RGB_B_POS_24]]));                            \
2063       }                                                                                 \
2064    }                                                                                    \
2065 }
2066 
2067 MAKE_SLOW_TRUECOLOR(_xwin_private_slow_truecolor_8, unsigned char, 0, 0, 0, 0xFF, 0xFF, 0xFF);
2068 MAKE_SLOW_TRUECOLOR(_xwin_private_slow_truecolor_15, unsigned short, 0, 5, 10, 0x1F, 0x1F, 0x1F);
2069 MAKE_SLOW_TRUECOLOR(_xwin_private_slow_truecolor_16, unsigned short, 0, 5, 11, 0x1F, 0x3F, 0x1F);
2070 MAKE_SLOW_TRUECOLOR(_xwin_private_slow_truecolor_32, uint32_t, 0, 8, 16, 0xFF, 0xFF, 0xFF);
2071 MAKE_SLOW_TRUECOLOR24(_xwin_private_slow_truecolor_24);
2072 
2073 #define MAKE_SLOW_PALETTE8(name)                                                        \
2074 static void name(int sx, int sy, int sw, int sh)                                        \
2075 {                                                                                       \
2076    int x, y;                                                                            \
2077    for (y = sy; y < (sy + sh); y++) {                                                   \
2078       unsigned char *s = _xwin.screen_line[y] + sx;                                     \
2079       for (x = sx; x < (sx + sw); x++) {                                                \
2080 	 unsigned long color = *s++;                                                    \
2081 	 XPutPixel(_xwin.ximage, x, y,                                                  \
2082 		   _xwin.cmap[(_xwin.rmap[color]                                        \
2083 			       | _xwin.gmap[color]                                      \
2084 			       | _xwin.bmap[color])]);                                  \
2085       }                                                                                 \
2086    }                                                                                    \
2087 }
2088 
2089 #define MAKE_SLOW_PALETTE(name,stype,rshift,gshift,bshift)                              \
2090 static void name(int sx, int sy, int sw, int sh)                                        \
2091 {                                                                                       \
2092    int x, y;                                                                            \
2093    for (y = sy; y < (sy + sh); y++) {                                                   \
2094       stype *s = (stype*) (_xwin.screen_line[y]) + sx;                                  \
2095       for (x = sx; x < (sx + sw); x++) {                                                \
2096 	 unsigned long color = *s++;                                                    \
2097 	 XPutPixel(_xwin.ximage, x, y,                                                  \
2098 		   _xwin.cmap[((((color >> (rshift)) & 0x0F) << 8)                      \
2099 			       | (((color >> (gshift)) & 0x0F) << 4)                    \
2100 			       | ((color >> (bshift)) & 0x0F))]);                       \
2101       }                                                                                 \
2102    }                                                                                    \
2103 }
2104 
2105 #define MAKE_SLOW_PALETTE24(name)                                                       \
2106 static void name(int sx, int sy, int sw, int sh)                                        \
2107 {                                                                                       \
2108    int x, y;                                                                            \
2109    for (y = sy; y < (sy + sh); y++) {                                                   \
2110       unsigned char *s = _xwin.screen_line[y] + 3 * sx;                                 \
2111       for (x = sx; x < (sx + sw); s += 3, x++) {                                        \
2112 	 XPutPixel(_xwin.ximage, x, y,                                                  \
2113 		   _xwin.cmap[((((unsigned long) s[DEFAULT_RGB_R_POS_24] << 4) & 0xF00) \
2114 			       | ((unsigned long) s[DEFAULT_RGB_G_POS_24] & 0xF0)       \
2115 			       | (((unsigned long) s[DEFAULT_RGB_B_POS_24] >> 4) & 0x0F))]); \
2116       }                                                                                 \
2117    }                                                                                    \
2118 }
2119 
2120 MAKE_SLOW_PALETTE8(_xwin_private_slow_palette_8);
2121 MAKE_SLOW_PALETTE(_xwin_private_slow_palette_15, unsigned short, 1, 6, 11);
2122 MAKE_SLOW_PALETTE(_xwin_private_slow_palette_16, unsigned short, 1, 7, 12);
2123 MAKE_SLOW_PALETTE(_xwin_private_slow_palette_32, uint32_t, 4, 12, 20);
2124 MAKE_SLOW_PALETTE24(_xwin_private_slow_palette_24);
2125 
2126 /*
2127  * Functions for setting "hardware" colors in 8bpp modes.
2128  */
_xwin_private_set_matching_colors(AL_CONST PALETTE p,int from,int to)2129 static void _xwin_private_set_matching_colors(AL_CONST PALETTE p, int from, int to)
2130 {
2131    int i;
2132    static XColor color[256];
2133 
2134    for (i = from; i <= to; i++) {
2135       color[i].flags = DoRed | DoGreen | DoBlue;
2136       color[i].pixel = i;
2137       color[i].red = ((p[i].r & 0x3F) * 65535L) / 0x3F;
2138       color[i].green = ((p[i].g & 0x3F) * 65535L) / 0x3F;
2139       color[i].blue = ((p[i].b & 0x3F) * 65535L) / 0x3F;
2140    }
2141    XStoreColors(_xwin.display, _xwin.colormap, color + from, to - from + 1);
2142 }
2143 
_xwin_private_set_truecolor_colors(AL_CONST PALETTE p,int from,int to)2144 static void _xwin_private_set_truecolor_colors(AL_CONST PALETTE p, int from, int to)
2145 {
2146    int i, rmax, gmax, bmax;
2147 
2148    rmax = _xwin.rsize - 1;
2149    gmax = _xwin.gsize - 1;
2150    bmax = _xwin.bsize - 1;
2151    for (i = from; i <= to; i++) {
2152       _xwin.rmap[i] = (((p[i].r & 0x3F) * rmax) / 0x3F) << _xwin.rshift;
2153       _xwin.gmap[i] = (((p[i].g & 0x3F) * gmax) / 0x3F) << _xwin.gshift;
2154       _xwin.bmap[i] = (((p[i].b & 0x3F) * bmax) / 0x3F) << _xwin.bshift;
2155    }
2156 }
2157 
_xwin_private_set_palette_colors(AL_CONST PALETTE p,int from,int to)2158 static void _xwin_private_set_palette_colors(AL_CONST PALETTE p, int from, int to)
2159 {
2160    int i;
2161 
2162    for (i = from; i <= to; i++) {
2163       _xwin.rmap[i] = (((p[i].r & 0x3F) * 15) / 0x3F) << 8;
2164       _xwin.gmap[i] = (((p[i].g & 0x3F) * 15) / 0x3F) << 4;
2165       _xwin.bmap[i] = (((p[i].b & 0x3F) * 15) / 0x3F);
2166    }
2167 }
2168 
_xwin_private_set_palette_range(AL_CONST PALETTE p,int from,int to)2169 static void _xwin_private_set_palette_range(AL_CONST PALETTE p, int from, int to)
2170 {
2171    RGB *pal;
2172    int c;
2173    unsigned char temp;
2174 
2175    if (_xwin.set_colors != 0) {
2176       if (blitter_func) {
2177          if (use_bgr_palette_hack && (from >= 0) && (to < 256)) {
2178             pal = _AL_MALLOC_ATOMIC(sizeof(RGB)*256);
2179             ASSERT(pal);
2180             ASSERT(p);
2181             if (!pal || !p)
2182 	       return; /* ... in shame and disgrace */
2183             memcpy(&pal[from], &p[from], sizeof(RGB)*(to-from+1));
2184             for (c = from; c <= to; c++) {
2185                temp = pal[c].r;
2186                pal[c].r = pal[c].b;
2187                pal[c].b = temp;
2188             }
2189             _set_colorconv_palette(pal, from, to);
2190 	    _AL_FREE(pal);
2191          }
2192          else {
2193             _set_colorconv_palette(p, from, to);
2194          }
2195       }
2196 
2197       /* Set "hardware" colors.  */
2198       (*(_xwin.set_colors))(p, from, to);
2199 
2200       /* Update XImage and window.  */
2201       if (!_xwin.matching_formats)
2202 	 _xwin_private_update_screen(0, 0, _xwin.virtual_width, _xwin.virtual_height);
2203    }
2204 }
2205 
_xwin_set_palette_range(AL_CONST PALETTE p,int from,int to,int vsync)2206 void _xwin_set_palette_range(AL_CONST PALETTE p, int from, int to, int vsync)
2207 {
2208    if (vsync) {
2209       _xwin_vsync();
2210    }
2211 
2212    XLOCK();
2213    _xwin_private_set_palette_range(p, from, to);
2214    XUNLOCK();
2215 }
2216 
2217 
2218 
2219 /* _xwin_set_window_defaults:
2220  *  Set default window parameters.
2221  */
_xwin_private_set_window_defaults(void)2222 static void _xwin_private_set_window_defaults(void)
2223 {
2224    XClassHint hint;
2225    XWMHints wm_hints;
2226 
2227    if (_xwin.wm_window == None)
2228       return;
2229 
2230    /* Set window title.  */
2231    XStoreName(_xwin.display, _xwin.wm_window, _xwin.window_title);
2232 
2233    /* Set hints.  */
2234    hint.res_name = _xwin.application_name;
2235    hint.res_class = _xwin.application_class;
2236    XSetClassHint(_xwin.display, _xwin.wm_window, &hint);
2237 
2238    wm_hints.flags = InputHint | StateHint | WindowGroupHint;
2239    wm_hints.input = True;
2240    wm_hints.initial_state = NormalState;
2241    wm_hints.window_group = _xwin.wm_window;
2242 
2243 #ifdef ALLEGRO_XWINDOWS_WITH_XPM
2244    if (allegro_icon) {
2245       wm_hints.flags |= IconPixmapHint | IconMaskHint;
2246       XpmCreatePixmapFromData(_xwin.display, _xwin.wm_window, allegro_icon,
2247          &wm_hints.icon_pixmap, &wm_hints.icon_mask, NULL);
2248    }
2249 #endif
2250 
2251    XSetWMHints(_xwin.display, _xwin.wm_window, &wm_hints);
2252 }
2253 
2254 
2255 
2256 /* _xwin_flush_buffers:
2257  *  Flush input and output X-buffers.
2258  */
_xwin_private_flush_buffers(void)2259 static void _xwin_private_flush_buffers(void)
2260 {
2261    if (_xwin.display != 0)
2262       XSync(_xwin.display, False);
2263 }
2264 
_xwin_flush_buffers(void)2265 void _xwin_flush_buffers(void)
2266 {
2267    XLOCK();
2268    _xwin_private_flush_buffers();
2269    XUNLOCK();
2270 }
2271 
2272 
2273 
2274 /* _xwin_vsync:
2275  *  Emulation of vsync.
2276  */
_xwin_vsync(void)2277 void _xwin_vsync(void)
2278 {
2279    if (_timer_installed) {
2280       int prev = retrace_count;
2281 
2282       XLOCK();
2283       XSync(_xwin.display, False);
2284       XUNLOCK();
2285 
2286       do {
2287          rest(1);
2288       } while (retrace_count == prev);
2289    }
2290    else {
2291       /* This does not wait for the VBI - but it waits until X11 has
2292        * synchronized, i.e. until actual changes are visible. So it
2293        * has a similar effect.
2294        */
2295       XLOCK();
2296       XSync(_xwin.display, False);
2297       XUNLOCK();
2298    }
2299 }
2300 
2301 
2302 /* _xwin_process_event:
2303  *  Process one event.
2304  */
_xwin_private_process_event(XEvent * event)2305 static void _xwin_private_process_event(XEvent *event)
2306 {
2307    int dx, dy, dz = 0, dw = 0;
2308    static int mouse_buttons = 0;
2309    static int mouse_savedx = 0;
2310    static int mouse_savedy = 0;
2311    static int mouse_warp_now = 0;
2312    static int mouse_was_warped = 0;
2313 
2314    switch (event->type) {
2315       case KeyPress:
2316          _xwin_keyboard_handler(&event->xkey, FALSE);
2317 	 break;
2318       case KeyRelease:
2319          _xwin_keyboard_handler(&event->xkey, FALSE);
2320 	 break;
2321       case FocusIn:
2322 	 _switch_in();
2323          _xwin_keyboard_focus_handler(&event->xfocus);
2324 	 break;
2325       case FocusOut:
2326 	 _switch_out();
2327          _xwin_keyboard_focus_handler(&event->xfocus);
2328 	 break;
2329       case ButtonPress:
2330 	 /* Mouse button pressed.  */
2331 	 if (event->xbutton.button == Button1)
2332 	    mouse_buttons |= 1;
2333 	 else if (event->xbutton.button == Button3)
2334 	    mouse_buttons |= 2;
2335 	 else if (event->xbutton.button == Button2)
2336 	    mouse_buttons |= 4;
2337 	 else if (event->xbutton.button == Button4) {
2338 	    dz = 1;
2339          }
2340          else if (event->xbutton.button == Button5) {
2341             dz = -1;
2342          }
2343          else if (event->xbutton.button == 6) {
2344             dw = -1;
2345          }
2346          else if (event->xbutton.button == 7) {
2347             dw = 1;
2348          }
2349          else if (event->xbutton.button == 8)
2350 	    mouse_buttons |= 8;
2351          else if (event->xbutton.button == 9)
2352 	    mouse_buttons |= 16;
2353 	 if (_xwin_mouse_interrupt)
2354 	    (*_xwin_mouse_interrupt)(0, 0, dz, dw, mouse_buttons);
2355 	 break;
2356       case ButtonRelease:
2357 	 /* Mouse button released.  */
2358 	 if (event->xbutton.button == Button1)
2359 	    mouse_buttons &= ~1;
2360 	 else if (event->xbutton.button == Button3)
2361 	    mouse_buttons &= ~2;
2362 	 else if (event->xbutton.button == Button2)
2363 	    mouse_buttons &= ~4;
2364          else if (event->xbutton.button == 8)
2365 	    mouse_buttons &= ~8;
2366          else if (event->xbutton.button == 9)
2367 	    mouse_buttons &= ~16;
2368 	 if (_xwin_mouse_interrupt)
2369 	    (*_xwin_mouse_interrupt)(0, 0, 0, 0, mouse_buttons);
2370 	 break;
2371       case MotionNotify:
2372 	 /* Mouse moved.  */
2373 	 dx = event->xmotion.x - mouse_savedx;
2374 	 dy = event->xmotion.y - mouse_savedy;
2375 	 /* Discard some events after warp.  */
2376 	 if (mouse_was_warped && ((dx != 0) || (dy != 0)) && (mouse_was_warped++ < 16))
2377 	    break;
2378 	 mouse_savedx = event->xmotion.x;
2379 	 mouse_savedy = event->xmotion.y;
2380 	 mouse_was_warped = 0;
2381 	 if (!_xwin.mouse_warped) {
2382 	    /* Move Allegro cursor to X-cursor.  */
2383 	    dx = event->xmotion.x - (_mouse_x - (_xwin_mouse_extended_range ? _xwin.scroll_x : 0));
2384 	    dy = event->xmotion.y - (_mouse_y - (_xwin_mouse_extended_range ? _xwin.scroll_y : 0));
2385 	 }
2386 	 if (((dx != 0) || (dy != 0)) && _xwin_mouse_interrupt) {
2387 	    if (_xwin.mouse_warped && (mouse_warp_now++ & 4)) {
2388 	       /* Warp X-cursor to the center of the window.  */
2389 	       mouse_savedx = _xwin.window_width / 2;
2390 	       mouse_savedy = _xwin.window_height / 2;
2391 	       mouse_was_warped = 1;
2392 	       XWarpPointer(_xwin.display, _xwin.window, _xwin.window,
2393 			    0, 0, _xwin.window_width, _xwin.window_height,
2394 			    mouse_savedx, mouse_savedy);
2395 	    }
2396 	    /* Move Allegro cursor.  */
2397 	    (*_xwin_mouse_interrupt)(dx, dy, 0, 0, mouse_buttons);
2398 	 }
2399 	 break;
2400       case EnterNotify:
2401 	 /* Mouse entered window.  */
2402 	 _mouse_on = TRUE;
2403 	 _xwin_mouse_enter_notify();
2404 	 mouse_savedx = event->xcrossing.x;
2405 	 mouse_savedy = event->xcrossing.y;
2406 	 mouse_was_warped = 0;
2407 	 if (!_xwin.mouse_warped) {
2408 	    /* Move Allegro cursor to X-cursor.  */
2409 	    dx = event->xcrossing.x - (_mouse_x - (_xwin_mouse_extended_range ? _xwin.scroll_x : 0));
2410 	    dy = event->xcrossing.y - (_mouse_y - (_xwin_mouse_extended_range ? _xwin.scroll_y : 0));
2411 	    if (((dx != 0) || (dy != 0)) && _xwin_mouse_interrupt)
2412 	       (*_xwin_mouse_interrupt)(dx, dy, 0, 0, mouse_buttons);
2413 	 }
2414 	 else if (_xwin_mouse_interrupt)
2415 	    (*_xwin_mouse_interrupt)(0, 0, 0, 0, mouse_buttons);
2416 	 break;
2417       case LeaveNotify:
2418 	 _mouse_on = FALSE;
2419 	 if (_xwin_mouse_interrupt)
2420 	    (*_xwin_mouse_interrupt)(0, 0, 0, 0, mouse_buttons);
2421 	 _xwin_mouse_leave_notify();
2422 	 break;
2423       case Expose:
2424 	 /* Request to redraw part of the window.  */
2425 	 (*_xwin_window_redrawer)(event->xexpose.x, event->xexpose.y,
2426 				     event->xexpose.width, event->xexpose.height);
2427 	 break;
2428       case MappingNotify:
2429 	 /* Keyboard mapping changed.  */
2430 	 if (event->xmapping.request == MappingKeyboard)
2431 	    _xwin_get_keyboard_mapping();
2432 	 break;
2433       case ClientMessage:
2434          /* Window close request */
2435          if ((Atom)event->xclient.data.l[0] == wm_delete_window) {
2436             if (_xwin.close_button_callback)
2437                _xwin.close_button_callback();
2438          }
2439          break;
2440    }
2441 }
2442 
2443 
2444 
2445 /* _xwin_handle_input:
2446  *  Handle events from the queue.
2447  */
_xwin_private_handle_input(void)2448 void _xwin_private_handle_input(void)
2449 {
2450    int i, events, events_queued;
2451    static XEvent event[X_MAX_EVENTS + 1]; /* +1 for possible extra event, see below. */
2452 
2453    if (_xwin.display == 0)
2454       return;
2455 
2456    /* Switch mouse to non-warped mode if mickeys were not used recently (~2 seconds).  */
2457    if (_xwin.mouse_warped && (_xwin.mouse_warped++ > MOUSE_WARP_DELAY)) {
2458       _xwin.mouse_warped = 0;
2459       /* Move X-cursor to Allegro cursor.  */
2460       XWarpPointer(_xwin.display, _xwin.window, _xwin.window,
2461 		   0, 0, _xwin.window_width, _xwin.window_height,
2462 		   _mouse_x - (_xwin_mouse_extended_range ? _xwin.scroll_x : 0),
2463 		   _mouse_y - (_xwin_mouse_extended_range ? _xwin.scroll_y : 0));
2464    }
2465 
2466    /* Flush X-buffers.  */
2467    _xwin_private_flush_buffers();
2468 
2469    /* How much events are available in the queue.  */
2470    events = events_queued = XEventsQueued(_xwin.display, QueuedAlready);
2471    if (events <= 0)
2472       return;
2473 
2474    /* Limit amount of events we read at once.  */
2475    if (events > X_MAX_EVENTS)
2476       events = X_MAX_EVENTS;
2477 
2478    /* Read pending events.  */
2479    for (i = 0; i < events; i++)
2480       XNextEvent(_xwin.display, &event[i]);
2481 
2482    /* Can't have a KeyRelease as last event, since it might be only half
2483     * of a key repeat pair. Also see comment below.
2484     */
2485    if (events_queued > events && event[i - 1].type == KeyRelease) {
2486       XNextEvent(_xwin.display, &event[i]);
2487       events++;
2488    }
2489 
2490    /* Process all events.  */
2491    for (i = 0; i < events; i++) {
2492 
2493       /* Hack to make Allegro's key[] array work despite of key repeat.
2494        * If a KeyRelease is sent at the same time as a KeyPress following
2495        * it with the same keycode, we ignore the release event.
2496        */
2497       if (event[i].type == KeyRelease && (i + 1) < events) {
2498 	 if (event[i + 1].type == KeyPress) {
2499 	    if (event[i].xkey.keycode == event[i + 1].xkey.keycode &&
2500 	       event[i].xkey.time == event[i + 1].xkey.time)
2501 	       continue;
2502 	 }
2503       }
2504 
2505       _xwin_private_process_event(&event[i]);
2506    }
2507 }
2508 
_xwin_handle_input(void)2509 void _xwin_handle_input(void)
2510 {
2511 #ifndef ALLEGRO_MULTITHREADED
2512    if (_xwin.lock_count) {
2513       ++_xwin_missed_input;
2514       return;
2515    }
2516 #endif
2517 
2518    XLOCK();
2519 
2520    if (_xwin_input_handler)
2521       _xwin_input_handler();
2522    else
2523       _xwin_private_handle_input();
2524 
2525    XUNLOCK();
2526 }
2527 
2528 
2529 
2530 /* _xwin_set_warped_mouse_mode:
2531  *  Switch mouse handling into warped mode.
2532  */
_xwin_private_set_warped_mouse_mode(int permanent)2533 static void _xwin_private_set_warped_mouse_mode(int permanent)
2534 {
2535    /* Don't enable warp mode if the hardware cursor is being displayed */
2536    if (!_xwin.hw_cursor_ok)
2537       _xwin.mouse_warped = ((permanent) ? 1 : (MOUSE_WARP_DELAY*7/8));
2538 }
2539 
_xwin_set_warped_mouse_mode(int permanent)2540 void _xwin_set_warped_mouse_mode(int permanent)
2541 {
2542    XLOCK();
2543    _xwin_private_set_warped_mouse_mode(permanent);
2544    XUNLOCK();
2545 }
2546 
2547 
2548 
2549 /* _xwin_redraw_window:
2550  *  Redraws part of the window.
2551  */
_xwin_private_redraw_window(int x,int y,int w,int h)2552 static void _xwin_private_redraw_window(int x, int y, int w, int h)
2553 {
2554    if (_xwin.window == None)
2555       return;
2556 
2557    /* Clip updated region.  */
2558    if (x >= _xwin.screen_width)
2559       return;
2560    if (x < 0) {
2561       w += x;
2562       x = 0;
2563    }
2564    if (w >= (_xwin.screen_width - x))
2565       w = _xwin.screen_width - x;
2566    if (w <= 0)
2567       return;
2568 
2569    if (y >= _xwin.screen_height)
2570       return;
2571    if (y < 0) {
2572       h += y;
2573       y = 0;
2574    }
2575    if (h >= (_xwin.screen_height - y))
2576       h = _xwin.screen_height - y;
2577    if (h <= 0)
2578       return;
2579 
2580    if (!_xwin.ximage)
2581       XFillRectangle(_xwin.display, _xwin.window, _xwin.gc, x, y, w, h);
2582    else {
2583 #ifdef ALLEGRO_XWINDOWS_WITH_SHM
2584       if (_xwin.use_shm)
2585 	 XShmPutImage(_xwin.display, _xwin.window, _xwin.gc, _xwin.ximage,
2586 		      x + _xwin.scroll_x, y + _xwin.scroll_y, x, y, w, h, False);
2587       else
2588 #endif
2589 	 XPutImage(_xwin.display, _xwin.window, _xwin.gc, _xwin.ximage,
2590 		   x + _xwin.scroll_x, y + _xwin.scroll_y, x, y, w, h);
2591    }
2592 }
2593 
_xwin_redraw_window(int x,int y,int w,int h)2594 void _xwin_redraw_window(int x, int y, int w, int h)
2595 {
2596    _xwin_lock(NULL);
2597    (*_xwin_window_redrawer)(x, y, w, h);
2598    _xwin_unlock(NULL);
2599 }
2600 
2601 
2602 
2603 /* _xwin_scroll_screen:
2604  *  Scroll visible screen in window.
2605  */
_xwin_private_scroll_screen(int x,int y)2606 static int _xwin_private_scroll_screen(int x, int y)
2607 {
2608    _xwin.scroll_x = x;
2609    _xwin.scroll_y = y;
2610    (*_xwin_window_redrawer)(0, 0, _xwin.screen_width, _xwin.screen_height);
2611    _xwin_private_flush_buffers();
2612 
2613    return 0;
2614 }
2615 
_xwin_scroll_screen(int x,int y)2616 int _xwin_scroll_screen(int x, int y)
2617 {
2618    int result;
2619 
2620    if (x < 0)
2621       x = 0;
2622    else if (x >= (_xwin.virtual_width - _xwin.screen_width))
2623       x = _xwin.virtual_width - _xwin.screen_width;
2624    if (y < 0)
2625       y = 0;
2626    else if (y >= (_xwin.virtual_height - _xwin.screen_height))
2627       y = _xwin.virtual_height - _xwin.screen_height;
2628    if ((_xwin.scroll_x == x) && (_xwin.scroll_y == y))
2629       return 0;
2630 
2631    _xwin_lock(NULL);
2632    result = _xwin_private_scroll_screen(x, y);
2633    _xwin_unlock(NULL);
2634    return result;
2635 }
2636 
2637 
2638 
2639 /* _xwin_update_screen:
2640  *  Update part of the screen.
2641  */
_xwin_private_update_screen(int x,int y,int w,int h)2642 static void _xwin_private_update_screen(int x, int y, int w, int h)
2643 {
2644    /* Update frame buffer with screen contents.  */
2645    if (_xwin.screen_to_buffer != 0) {
2646       /* Clip updated region.  */
2647       if (x >= _xwin.virtual_width)
2648 	 return;
2649       if (x < 0) {
2650 	 w += x;
2651 	 x = 0;
2652       }
2653       if (w >= (_xwin.virtual_width - x))
2654 	 w = _xwin.virtual_width - x;
2655       if (w <= 0)
2656 	 return;
2657 
2658       if (y >= _xwin.virtual_height)
2659 	 return;
2660       if (y < 0) {
2661 	 h += y;
2662 	 y = 0;
2663       }
2664       if (h >= (_xwin.virtual_height - y))
2665 	 h = _xwin.virtual_height - y;
2666       if (h <= 0)
2667 	 return;
2668 
2669       (*(_xwin.screen_to_buffer))(x, y, w, h);
2670    }
2671 
2672    /* Update window.  */
2673    (*_xwin_window_redrawer)(x - _xwin.scroll_x, y - _xwin.scroll_y, w, h);
2674 }
2675 
_xwin_update_screen(int x,int y,int w,int h)2676 void _xwin_update_screen(int x, int y, int w, int h)
2677 {
2678    _xwin_lock(NULL);
2679    _xwin_private_update_screen(x, y, w, h);
2680    _xwin_unlock(NULL);
2681 }
2682 
2683 
2684 
2685 /* _xwin_set_window_title:
2686  *  Wrapper for XStoreName.
2687  */
_xwin_private_set_window_title(AL_CONST char * name)2688 static void _xwin_private_set_window_title(AL_CONST char *name)
2689 {
2690    if (!name)
2691       _al_sane_strncpy(_xwin.window_title, XWIN_DEFAULT_WINDOW_TITLE, sizeof(_xwin.window_title));
2692    else
2693       _al_sane_strncpy(_xwin.window_title, name, sizeof(_xwin.window_title));
2694 
2695    if (_xwin.wm_window != None)
2696       XStoreName(_xwin.display, _xwin.wm_window, _xwin.window_title);
2697 }
2698 
_xwin_set_window_title(AL_CONST char * name)2699 void _xwin_set_window_title(AL_CONST char *name)
2700 {
2701    XLOCK();
2702    _xwin_private_set_window_title(name);
2703    XUNLOCK();
2704 }
2705 
2706 
2707 
2708 /* _xwin_sysdrv_set_window_name:
2709  *  Sets window name and group.
2710  */
_xwin_private_set_window_name(AL_CONST char * name,AL_CONST char * group)2711 static void _xwin_private_set_window_name(AL_CONST char *name, AL_CONST char *group)
2712 {
2713    XClassHint hint;
2714 
2715    if (!name)
2716       _al_sane_strncpy(_xwin.application_name, XWIN_DEFAULT_APPLICATION_NAME, sizeof(_xwin.application_name));
2717    else
2718       _al_sane_strncpy(_xwin.application_name, name, sizeof(_xwin.application_name));
2719 
2720    if (!group)
2721       _al_sane_strncpy(_xwin.application_class, XWIN_DEFAULT_APPLICATION_CLASS, sizeof(_xwin.application_class));
2722    else
2723       _al_sane_strncpy(_xwin.application_class, group, sizeof(_xwin.application_class));
2724 
2725    if (_xwin.window != None) {
2726       hint.res_name = _xwin.application_name;
2727       hint.res_class = _xwin.application_class;
2728       XSetClassHint(_xwin.display, _xwin.window, &hint);
2729    }
2730 }
2731 
xwin_set_window_name(AL_CONST char * name,AL_CONST char * group)2732 void xwin_set_window_name(AL_CONST char *name, AL_CONST char *group)
2733 {
2734    char tmp1[128], tmp2[128];
2735 
2736    do_uconvert(name, U_CURRENT, tmp1, U_ASCII, sizeof(tmp1));
2737    do_uconvert(group, U_CURRENT, tmp2, U_ASCII, sizeof(tmp2));
2738 
2739    XLOCK();
2740    _xwin_private_set_window_name(tmp1, tmp2);
2741    XUNLOCK();
2742 }
2743 
2744 
2745 
2746 /* _xwin_get_pointer_mapping:
2747  *  Wrapper for XGetPointerMapping.
2748  */
_xwin_private_get_pointer_mapping(unsigned char map[],int nmap)2749 static int _xwin_private_get_pointer_mapping(unsigned char map[], int nmap)
2750 {
2751    return ((_xwin.display == 0) ? -1 : XGetPointerMapping(_xwin.display, map, nmap));
2752 }
2753 
_xwin_get_pointer_mapping(unsigned char map[],int nmap)2754 int _xwin_get_pointer_mapping(unsigned char map[], int nmap)
2755 {
2756    int num;
2757    XLOCK();
2758    num = _xwin_private_get_pointer_mapping(map, nmap);
2759    XUNLOCK();
2760    return num;
2761 }
2762 
2763 
2764 
2765 /* _xwin_write_line:
2766  *  Update last selected line and select new line.
2767  */
_xwin_write_line(BITMAP * bmp,int line)2768 uintptr_t _xwin_write_line(BITMAP *bmp, int line)
2769 {
2770    int new_line = line + bmp->y_ofs;
2771    if ((new_line != _xwin_last_line) && (!_xwin_in_gfx_call) && (_xwin_last_line >= 0))
2772       _xwin_update_screen(0, _xwin_last_line, _xwin.virtual_width, 1);
2773    _xwin_last_line = new_line;
2774    return (uintptr_t) (bmp->line[line]);
2775 }
2776 
2777 
2778 
2779 /* _xwin_unwrite_line:
2780  *  Update last selected line.
2781  */
_xwin_unwrite_line(BITMAP * bmp)2782 void _xwin_unwrite_line(BITMAP *bmp)
2783 {
2784    if ((!_xwin_in_gfx_call) && (_xwin_last_line >= 0))
2785       _xwin_update_screen(0, _xwin_last_line, _xwin.virtual_width, 1);
2786    _xwin_last_line = -1;
2787 }
2788 
2789 
2790 
2791 /*
2792  * Support for XF86VidMode extension.
2793  */
2794 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
2795 /* qsort comparison function for sorting the modes */
cmpmodes(const void * va,const void * vb)2796 static int cmpmodes(const void *va, const void *vb)
2797 {
2798     const XF86VidModeModeInfo *a = *(const XF86VidModeModeInfo **)va;
2799     const XF86VidModeModeInfo *b = *(const XF86VidModeModeInfo **)vb;
2800 
2801     if (a->hdisplay == b->hdisplay)
2802         return b->vdisplay - a->vdisplay;
2803     else
2804         return b->hdisplay - a->hdisplay;
2805 }
2806 
2807 /* _xvidmode_private_set_fullscreen:
2808  *  Attempt to switch to a better matching video mode.
2809  *  Matching code for non exact match (smallest bigger res) rather shamelessly
2810  *  taken from SDL.
2811  */
_xvidmode_private_set_fullscreen(int w,int h,int * vidmode_width,int * vidmode_height)2812 static void _xvidmode_private_set_fullscreen(int w, int h, int *vidmode_width,
2813    int *vidmode_height)
2814 {
2815    int vid_event_base, vid_error_base;
2816    int vid_major_version, vid_minor_version;
2817    int i;
2818 
2819    /* Test that display is local.  */
2820    if (!_xwin_private_display_is_local())
2821       return;
2822 
2823    /* Test for presence of VidMode extension.  */
2824    if (!XF86VidModeQueryExtension(_xwin.display, &vid_event_base, &vid_error_base)
2825        || !XF86VidModeQueryVersion(_xwin.display, &vid_major_version, &vid_minor_version))
2826       return;
2827 
2828    /* Get list of modelines.  */
2829    if (!XF86VidModeGetAllModeLines(_xwin.display, _xwin.screen,
2830 				   &_xwin.num_modes, &_xwin.modesinfo))
2831       return;
2832 
2833    /* Remember the mode to restore.  */
2834    _xwin.orig_modeinfo = _xwin.modesinfo[0];
2835 
2836    /* Search for an exact matching video mode.  */
2837    for (i = 0; i < _xwin.num_modes; i++) {
2838       if ((_xwin.modesinfo[i]->hdisplay == w) &&
2839           (_xwin.modesinfo[i]->vdisplay == h))
2840          break;
2841    }
2842 
2843    /* Search for a non exact match (smallest bigger res).  */
2844    if (i == _xwin.num_modes) {
2845       int best_width = 0, best_height = 0;
2846       qsort(_xwin.modesinfo, _xwin.num_modes, sizeof(void *), cmpmodes);
2847       for (i = _xwin.num_modes-1; i > 0; i--) {
2848           if (!best_width) {
2849               if ((_xwin.modesinfo[i]->hdisplay >= w) &&
2850                   (_xwin.modesinfo[i]->vdisplay >= h)) {
2851                   best_width = _xwin.modesinfo[i]->hdisplay;
2852                   best_height = _xwin.modesinfo[i]->vdisplay;
2853               }
2854           }
2855 	  else {
2856               if ((_xwin.modesinfo[i]->hdisplay != best_width) ||
2857                   (_xwin.modesinfo[i]->vdisplay != best_height)) {
2858                   i++;
2859                   break;
2860               }
2861           }
2862       }
2863    }
2864 
2865    /* Switch video mode.  */
2866    if ((_xwin.modesinfo[i] == _xwin.orig_modeinfo) ||
2867        !XF86VidModeSwitchToMode(_xwin.display, _xwin.screen,
2868          _xwin.modesinfo[i])) {
2869       *vidmode_width  = _xwin.orig_modeinfo->hdisplay;
2870       *vidmode_height = _xwin.orig_modeinfo->vdisplay;
2871       _xwin.orig_modeinfo = NULL;
2872    }
2873    else {
2874       *vidmode_width  = _xwin.modesinfo[i]->hdisplay;
2875       *vidmode_height = _xwin.modesinfo[i]->vdisplay;
2876       /* Only kept / set for compatibility with apps which check this.  */
2877       _xwin.mode_switched = 1;
2878    }
2879 
2880    /* Lock mode switching.  */
2881    XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, True);
2882 
2883    /* Set viewport. */
2884    XF86VidModeSetViewPort(_xwin.display, _xwin.screen, 0, 0);
2885 }
2886 
2887 
2888 
2889 /* free_modelines:
2890  *  Free mode lines.
2891  */
free_modelines(XF86VidModeModeInfo ** modesinfo,int num_modes)2892 static void free_modelines(XF86VidModeModeInfo **modesinfo, int num_modes)
2893 {
2894    int i;
2895 
2896    for (i = 0; i < num_modes; i++)
2897       if (modesinfo[i]->privsize > 0)
2898 	 XFree(modesinfo[i]->private);
2899    XFree(modesinfo);
2900 }
2901 
2902 
2903 
2904 /* _xvidmode_private_unset_fullscreen:
2905  *  Restore original video mode and window attributes.
2906  */
_xvidmode_private_unset_fullscreen(void)2907 static void _xvidmode_private_unset_fullscreen(void)
2908 {
2909    if (_xwin.num_modes > 0) {
2910       /* Unlock mode switching.  */
2911       XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, False);
2912 
2913       if (_xwin.orig_modeinfo) {
2914 	 /* Restore the original video mode.  */
2915 	 XF86VidModeSwitchToMode(_xwin.display, _xwin.screen,
2916             _xwin.orig_modeinfo);
2917          _xwin.orig_modeinfo = 0;
2918          /* only kept / set for compatibility with apps which check this */
2919 	 _xwin.mode_switched = 0;
2920       }
2921 
2922       /* Free modelines.  */
2923       free_modelines(_xwin.modesinfo, _xwin.num_modes);
2924       _xwin.num_modes = 0;
2925       _xwin.modesinfo = 0;
2926    }
2927 }
2928 #endif
2929 
2930 
2931 
2932 /* _xwin_private_fetch_mode_list:
2933  *  Generates a list of valid video modes.
2934  */
_xwin_private_fetch_mode_list(void)2935 static GFX_MODE_LIST *_xwin_private_fetch_mode_list(void)
2936 {
2937    int num_modes = 1, num_bpp = 0;
2938    GFX_MODE_LIST *mode_list;
2939    int i, j;
2940 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
2941    int has_vidmode = 0;
2942    int vid_event_base, vid_error_base;
2943    int vid_major_version, vid_minor_version;
2944    XF86VidModeModeInfo **modesinfo;
2945 
2946    /* Test that display is local.  */
2947    if (_xwin_private_display_is_local() &&
2948        /* Test for presence of VidMode extension.  */
2949        XF86VidModeQueryExtension(_xwin.display, &vid_event_base, &vid_error_base) &&
2950        XF86VidModeQueryVersion(_xwin.display, &vid_major_version, &vid_minor_version) &&
2951        /* Get list of modelines.  */
2952        XF86VidModeGetAllModeLines(_xwin.display, _xwin.screen, &num_modes, &modesinfo))
2953       has_vidmode = 1;
2954 #endif
2955 
2956    /* Calculate the number of color depths we have to support.  */
2957 #ifdef ALLEGRO_COLOR8
2958    num_bpp++;
2959 #endif
2960 #ifdef ALLEGRO_COLOR16
2961    num_bpp += 2;     /* 15, 16 */
2962 #endif
2963 #ifdef ALLEGRO_COLOR24
2964    num_bpp++;
2965 #endif
2966 #ifdef ALLEGRO_COLOR32
2967    num_bpp++;
2968 #endif
2969    if (num_bpp == 0) /* ha! */
2970       return 0;
2971 
2972    /* Allocate space for mode list.  */
2973    mode_list = _AL_MALLOC(sizeof(GFX_MODE_LIST));
2974    if (!mode_list) {
2975 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
2976       if (has_vidmode)
2977          free_modelines(modesinfo, num_modes);
2978 #endif
2979       return 0;
2980    }
2981 
2982    mode_list->mode = _AL_MALLOC(sizeof(GFX_MODE) * ((num_modes * num_bpp) + 1));
2983    if (!mode_list->mode) {
2984       _AL_FREE(mode_list);
2985 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
2986       if (has_vidmode)
2987          free_modelines(modesinfo, num_modes);
2988 #endif
2989       return 0;
2990    }
2991 
2992    /* Fill in mode list.  */
2993    j = 0;
2994    for (i = 0; i < num_modes; i++) {
2995 
2996 #define ADD_SCREEN_MODE(BPP)                                                  \
2997       mode_list->mode[j].width  = DisplayWidth(_xwin.display, _xwin.screen);  \
2998       mode_list->mode[j].height = DisplayHeight(_xwin.display, _xwin.screen); \
2999       mode_list->mode[j].bpp = BPP;			                      \
3000       j++
3001 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
3002 #define ADD_VIDMODE_MODE(BPP)			            \
3003       mode_list->mode[j].width = modesinfo[i]->hdisplay;    \
3004       mode_list->mode[j].height = modesinfo[i]->vdisplay;   \
3005       mode_list->mode[j].bpp = BPP;			    \
3006       j++
3007 #define ADD_MODE(BPP)                                       \
3008       if (has_vidmode) {                                    \
3009          ADD_VIDMODE_MODE(BPP);                             \
3010       } else {                                              \
3011          ADD_SCREEN_MODE(BPP);                              \
3012       }
3013 #else
3014 #define ADD_MODE(BPP) ADD_SCREEN_MODE(BPP)
3015 #endif
3016 
3017 #ifdef ALLEGRO_COLOR8
3018       ADD_MODE(8);
3019 #endif
3020 #ifdef ALLEGRO_COLOR16
3021       ADD_MODE(15);
3022       ADD_MODE(16);
3023 #endif
3024 #ifdef ALLEGRO_COLOR24
3025       ADD_MODE(24);
3026 #endif
3027 #ifdef ALLEGRO_COLOR32
3028       ADD_MODE(32);
3029 #endif
3030    }
3031 
3032    mode_list->mode[j].width = 0;
3033    mode_list->mode[j].height = 0;
3034    mode_list->mode[j].bpp = 0;
3035    mode_list->num_modes = j;
3036 
3037 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
3038    if (has_vidmode)
3039       free_modelines(modesinfo, num_modes);
3040 #endif
3041 
3042    return mode_list;
3043 }
3044 
3045 
3046 
3047 /* _xwin_fetch_mode_list:
3048  *  Fetch mode list.
3049  */
_xwin_fetch_mode_list(void)3050 GFX_MODE_LIST *_xwin_fetch_mode_list(void)
3051 {
3052    GFX_MODE_LIST *list;
3053    XLOCK();
3054    list = _xwin_private_fetch_mode_list();
3055    XUNLOCK();
3056    return list;
3057 }
3058 
3059 
3060 
3061 /* Hook functions */
3062 int (*_xwin_window_creator)(void) = &_xwin_private_create_window;
3063 void (*_xwin_window_defaultor)(void) = &_xwin_private_set_window_defaults;
3064 void (*_xwin_window_redrawer)(int, int, int, int) = &_xwin_private_redraw_window;
3065 void (*_xwin_input_handler)(void) = 0;
3066 
3067 void (*_xwin_keyboard_callback)(int, int) = 0;
3068