AllegroGL  0.4.4
x.c
1 /* This code is (C) AllegroGL contributors, and double licensed under
2  * the GPL and zlib licenses. See gpl.txt or zlib.txt for details.
3  */
4 /*----------------------------------------------------------------
5  * x.c -- Allegro-GLX interfacing
6  *----------------------------------------------------------------
7  * This is the interface module for use under X.
8  */
9 #include <string.h>
10 #include <stdio.h>
11 
12 #include <allegro.h>
13 #include <xalleg.h>
14 
15 #include <allegro/platform/aintunix.h>
16 
17 #include "alleggl.h"
18 #include "allglint.h"
19 #include "glvtable.h"
20 
21 
22 #ifndef XLOCK
23  #define OLD_ALLEGRO
24  #define XLOCK() DISABLE()
25  #undef XUNLOCK
26  #define XUNLOCK() ENABLE()
27 #endif
28 
29 #define PREFIX_I "agl-x INFO: "
30 #define PREFIX_E "agl-x ERROR: "
31 
32 
33 #ifdef ALLEGRO_XWINDOWS_WITH_XPM
34 #include <X11/xpm.h>
35 extern void *allegro_icon;
36 #endif
37 
38 
39 static BITMAP *allegro_gl_x_windowed_init(int w, int h, int vw, int vh,
40  int color_depth);
41 static void allegro_gl_x_exit(BITMAP *bmp);
42 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
43 static GFX_MODE_LIST* allegro_gl_x_fetch_mode_list(void);
44 #endif
45 static void allegro_gl_x_vsync(void);
46 static void allegro_gl_x_hide_mouse(void);
47 
48 static BITMAP *allegro_gl_screen = NULL;
49 
50 /* TODO: Revamp the whole window handling under X11 in Allegro and
51  * AllegroGL. We really shouldn't have to duplicate code or hack on
52  * Allegro internals in AllegroGL - the *only* difference for the AllegroGL
53  * window should be the GLX visual (e.g. cursor, icon, VidModeExtension and
54  * so on should never have been touched in this file).
55  */
56 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
57 static Window backup_allegro_window = None;
58 static Colormap backup_allegro_colormap = None;
59 #endif
60 
61 
62 static BITMAP *allegro_gl_x_fullscreen_init(int w, int h, int vw, int vh,
63  int color_depth);
64 
65 GFX_DRIVER gfx_allegro_gl_fullscreen =
66 {
68  empty_string,
69  empty_string,
70  "AllegroGL Fullscreen (X)",
71  allegro_gl_x_fullscreen_init,
72  allegro_gl_x_exit,
73  NULL,
74  allegro_gl_x_vsync,
75  NULL,
76  NULL, NULL, NULL,
79  NULL, NULL, /* No show/request video bitmaps */
80  NULL, NULL,
81  allegro_gl_set_mouse_sprite,
82  allegro_gl_show_mouse,
83  allegro_gl_x_hide_mouse,
84  allegro_gl_move_mouse,
85  allegro_gl_drawing_mode,
86  NULL, NULL,
87  allegro_gl_set_blender_mode,
88 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
89  allegro_gl_x_fetch_mode_list,
90 #else
91  NULL,
92 #endif
93  0, 0,
94  0,
95  0, 0,
96  0,
97  0,
98  FALSE /* Windowed mode */
99 };
100 
101 
102 
103 GFX_DRIVER gfx_allegro_gl_windowed =
104 {
106  empty_string,
107  empty_string,
108  "AllegroGL Windowed (X)",
109  allegro_gl_x_windowed_init,
110  allegro_gl_x_exit,
111  NULL,
112  allegro_gl_x_vsync,
113  NULL,
114  NULL, NULL, NULL,
117  NULL, NULL, /* No show/request video bitmaps */
118  NULL, NULL,
119  allegro_gl_set_mouse_sprite,
120  allegro_gl_show_mouse,
121  allegro_gl_x_hide_mouse,
122  allegro_gl_move_mouse,
123  allegro_gl_drawing_mode,
124  NULL, NULL,
125  allegro_gl_set_blender_mode,
126  NULL, /* No fetch_mode_list */
127  0, 0,
128  0,
129  0, 0,
130  0,
131  0,
132  TRUE /* Windowed mode */
133 };
134 
135 
136 
137 static struct allegro_gl_driver allegro_gl_x;
138 
139 static XVisualInfo *allegro_gl_x_windowed_choose_visual (void);
140 static int allegro_gl_x_create_window (int fullscreen);
141 static BITMAP *allegro_gl_x_windowed_create_screen (GFX_DRIVER *drv, int w, int h, int depth);
142 
143 static int decode_visual (XVisualInfo *v, struct allegro_gl_display_info *i);
144 struct {
145  int fullscreen;
146  GLXContext ctx;
147  int major, minor; /* Major and minor GLX version */
148  int error_base, event_base;
149  int use_glx_window;
150  GLXWindow window;
151 } _glxwin;
152 
153 static void (*old_window_redrawer)(int, int, int, int);
154 extern void (*_xwin_window_redrawer)(int, int, int, int);
155 static int (*old_x_error_handler)(Display*, XErrorEvent*);
156 
157 
158 
159 /* allegro_gl_redraw_window :
160  * Redraws the window when an Expose event is processed
161  * Important note : no GL commands should be processed in this function
162  * since it may be called by a thread which is different from the main thread.
163  * In order to be able to process GL commands, we should create another context
164  * and make it current to the other thread. IMHO it would be overkill.
165  */
166 static void allegro_gl_redraw_window(int x, int y, int w, int h)
167 {
168  /* Does nothing */
169  return;
170 }
171 
172 
173 
174 #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
175 /* _xwin_hide_x_mouse:
176  * Create invisible X cursor
177  */
178 static void _xwin_hide_x_mouse(void)
179 {
180  unsigned long gcmask;
181  XGCValues gcvalues;
182  Pixmap pixmap;
183 
184  XUndefineCursor(_xwin.display, _xwin.window);
185 
186  if (_xwin.cursor != None) {
187  XFreeCursor(_xwin.display, _xwin.cursor);
188  _xwin.cursor = None;
189  }
190 
191  if (_xwin.xcursor_image != None) {
192  XcursorImageDestroy(_xwin.xcursor_image);
193  _xwin.xcursor_image = None;
194  }
195 
196  pixmap = XCreatePixmap(_xwin.display, _xwin.window, 1, 1, 1);
197  if (pixmap != None) {
198  GC temp_gc;
199  XColor color;
200 
201  gcmask = GCFunction | GCForeground | GCBackground;
202  gcvalues.function = GXcopy;
203  gcvalues.foreground = 0;
204  gcvalues.background = 0;
205  temp_gc = XCreateGC(_xwin.display, pixmap, gcmask, &gcvalues);
206  XDrawPoint(_xwin.display, pixmap, temp_gc, 0, 0);
207  XFreeGC(_xwin.display, temp_gc);
208  color.pixel = 0;
209  color.red = color.green = color.blue = 0;
210  color.flags = DoRed | DoGreen | DoBlue;
211  _xwin.cursor = XCreatePixmapCursor(_xwin.display, pixmap, pixmap, &color, &color, 0, 0);
212  XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
213  XFreePixmap(_xwin.display, pixmap);
214  }
215  else {
216  _xwin.cursor = XCreateFontCursor(_xwin.display, _xwin.cursor_shape);
217  XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
218  }
219 }
220 #endif
221 
222 
223 
224 /* hide_mouse:
225  * Hide the custom X cursor (if supported)
226  */
227 static void hide_mouse(void)
228 {
229  #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
230  if (_xwin.support_argb_cursor) {
231  XLOCK();
232  _xwin_hide_x_mouse();
233  XUNLOCK();
234  }
235  #endif
236  return;
237 }
238 
239 
240 
241 /* If Allegro's X11 mouse driver enabled hw cursors, we shouldn't use
242  * allegro_gl_hide_mouse();
243  */
244 static void allegro_gl_x_hide_mouse(void)
245 {
246  if (_xwin.hw_cursor_ok) {
247  hide_mouse();
248  }
249  else {
250  allegro_gl_hide_mouse();
251  }
252 }
253 
254 
255 
256 /* allegro_gl_x_windowed_init:
257  * Creates screen bitmap.
258  */
259 static BITMAP *allegro_gl_x_create_screen(int w, int h, int vw, int vh,
260  int depth, int fullscreen)
261 {
262  int _keyboard_was_installed = FALSE;
263  int _mouse_was_installed = FALSE;
264  int create_window_ret;
265 
266  /* test if Allegro have pthread support enabled */
267  if (!_unix_bg_man->multi_threaded) {
268  ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
269  get_config_text("Fatal Error : pthread support is not enabled"));
270  return NULL;
271  }
272 
273  if (keyboard_driver) {
274  _keyboard_was_installed = TRUE;
275  remove_keyboard();
276  TRACE(PREFIX_I "x_create_screen: Removing Keyboard...\n");
277  }
278 
279  if (mouse_driver) {
280  _mouse_was_installed = TRUE;
281  remove_mouse();
282  TRACE(PREFIX_I "x_create_screen: Removing Mouse...\n");
283  }
284 
285  XLOCK();
286 
287  if (!glXQueryExtension(_xwin.display, &_glxwin.error_base,
288  &_glxwin.event_base)) {
289 
290  ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
291  get_config_text("GLX Extension not supported by display"));
292  XUNLOCK();
293  goto failure;
294  }
295 
296  sscanf(glXQueryServerString(_xwin.display, _xwin.screen, GLX_VERSION),
297  "%i.%i", &_glxwin.major, &_glxwin.minor);
298 
299  if ((w == 0) && (h == 0)) {
300  w = 640;
301  h = 480;
302  }
303 
304  if ((vw > w) || (vh > h)) {
305  ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
306  get_config_text ("OpenGL drivers do not support virtual screens"));
307  XUNLOCK();
308  goto failure;
309  }
310 
311  allegro_gl_display_info.w = w;
312  allegro_gl_display_info.h = h;
313 
314  old_window_redrawer = _xwin_window_redrawer;
315  _xwin_window_redrawer = allegro_gl_redraw_window;
316  _glxwin.fullscreen = FALSE;
317  _glxwin.use_glx_window = FALSE;
318 
319  create_window_ret = allegro_gl_x_create_window(fullscreen);
320  if (create_window_ret) {
321  if (fullscreen && create_window_ret == -2) {
322  ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
323  get_config_text ("Unable to switch in GLX fullscreen"));
324  }
325  else if (create_window_ret == -2) {
326  ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
327  get_config_text ("Unable to create GLX window"));
328  }
329  XUNLOCK();
330  allegro_gl_x_exit(NULL);
331  goto failure;
332  }
333 
334  /* If pixel format is Allegro compatible, set up Allegro correctly. */
335  set_color_depth(allegro_gl_display_info.colour_depth);
336 
337  /* XXX <rohannessian> X can run on Big-Endian systems. We need to
338  * make a check for that and pass TRUE to
339  * __allegro_gl_set_allegro_image_format() in that case.
340  */
341  __allegro_gl_set_allegro_image_format(FALSE);
342 
343  if (fullscreen) {
345  allegro_gl_x_windowed_create_screen (&gfx_allegro_gl_fullscreen,
346  allegro_gl_display_info.w, allegro_gl_display_info.h,
347  _color_depth);
348  }
349  else {
351  allegro_gl_x_windowed_create_screen (&gfx_allegro_gl_windowed,
352  allegro_gl_display_info.w, allegro_gl_display_info.h,
353  _color_depth);
354  }
355 
356  if (!allegro_gl_screen) {
357  ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
358  get_config_text ("Error creating screen bitmap"));
359  XUNLOCK();
360  allegro_gl_x_exit(NULL);
361  goto failure;
362  }
363 
364  __allegro_gl_valid_context = TRUE;
365  __allegro_gl_driver = &allegro_gl_x;
366 
367  /* Print out OpenGL version info */
368  TRACE(PREFIX_I "OpenGL Version: %s\n", (AL_CONST char*)glGetString(GL_VERSION));
369  TRACE(PREFIX_I "OpenGL Vendor: %s\n", (AL_CONST char*)glGetString(GL_VENDOR));
370  TRACE(PREFIX_I "OpenGL Renderer: %s\n", (AL_CONST char*)glGetString(GL_RENDERER));
371 
372  /* Detect if the GL driver is based on Mesa */
373  allegro_gl_info.is_mesa_driver = FALSE;
374  if (strstr((AL_CONST char*)glGetString(GL_VERSION),"Mesa")) {
375  AGL_LOG(1, "OpenGL driver based on Mesa\n");
376  allegro_gl_info.is_mesa_driver = TRUE;
377  }
378 
379  /* Print out GLX version info */
380  TRACE(PREFIX_I "GLX Version: %d.%d\n", _glxwin.major, _glxwin.minor);
381 
382 #ifdef LOGLEVEL
383  if (glXIsDirect(_xwin.display, _glxwin.ctx)) {
384  AGL_LOG(1, "GLX Direct Rendering is enabled\n");
385  }
386  else {
387  AGL_LOG(1, "GLX Direct Rendering is disabled\n");
388  }
389 #endif
390 
391  /* Prints out GLX extensions info */
392  AGL_LOG(1, "glX Extensions:\n");
393 #ifdef LOGLEVEL
394  __allegro_gl_print_extensions(
395  (AL_CONST char*)glXQueryExtensionsString(_xwin.display, _xwin.screen));
396 #endif
397  /* Prints out OpenGL extensions info and activates needed extensions */
398  __allegro_gl_manage_extensions();
399 
400  /* Update screen vtable in order to use AGL's */
401  __allegro_gl__glvtable_update_vtable (&allegro_gl_screen->vtable);
402  memcpy(&_screen_vtable, allegro_gl_screen->vtable, sizeof(GFX_VTABLE));
403  allegro_gl_screen->vtable = &_screen_vtable;
404 
405  XUNLOCK();
406 
407  if (_keyboard_was_installed) {
408  TRACE(PREFIX_I "x_create_screen: Installing Keyboard...\n");
409  install_keyboard();
410  }
411 
412  if (_mouse_was_installed) {
413  TRACE(PREFIX_I "x_create_screen: Installing Mouse...\n");
414  install_mouse();
415  }
416  gfx_capabilities |= GFX_HW_CURSOR;
417 
418  return allegro_gl_screen;
419 
420 failure:
421  if (_keyboard_was_installed) {
422  install_keyboard();
423  }
424 
425  if (_mouse_was_installed) {
426  install_mouse();
427  }
428 
429  return NULL;
430 }
431 
432 
433 
434 /* allegro_gl_x_windowed_init:
435  * Creates screen bitmap for windowed driver.
436  */
437 static BITMAP *allegro_gl_x_windowed_init(int w, int h, int vw, int vh,
438  int depth)
439 {
440  return allegro_gl_x_create_screen(w, h, vw, vh, depth, FALSE);
441 }
442 
443 
444 
445 /* allegro_gl_x_fullscreen_init:
446  * Creates screen bitmap for fullscreen driver.
447  */
448 static BITMAP *allegro_gl_x_fullscreen_init(int w, int h, int vw, int vh,
449  int depth)
450 {
451  return allegro_gl_x_create_screen(w, h, vw, vh, depth, TRUE);
452 }
453 
454 
455 
456 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
457 /* free_modelines:
458  * Free mode lines.
459  */
460 static void free_modelines(XF86VidModeModeInfo **modesinfo, int num_modes)
461 {
462  int i;
463 
464  for (i = 0; i < num_modes; i++)
465  if (modesinfo[i]->privsize > 0)
466  XFree(modesinfo[i]->private);
467  XFree(modesinfo);
468 }
469 #endif
470 
471 
472 
473 /* allegro_gl_x_exit:
474  * Shuts down the driver (shared between windowed and full-screen)
475  */
476 static void allegro_gl_x_exit(BITMAP *bmp)
477 {
478 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
479  XSetWindowAttributes setattr;
480 #endif
481 
482  XLOCK();
483  /* We politely wait for OpenGL to finish its current operations before
484  shutting down the driver */
485  glXWaitGL();
486 
487  __allegro_gl_unmanage_extensions();
488 
489  if (_glxwin.ctx) {
490  if (!allegro_gl_info.is_ati_r200_chip) {
491  /* The DRI drivers for ATI cards with R200 chip
492  * seem to be broken since they crash at this point.
493  * As a workaround AGL does not release the GLX context
494  * here. This should not hurt since the GLX specs don't
495  * require the context to be released before the program
496  * ends or before another context is made current to the
497  * thread.
498  */
499  if (!glXMakeCurrent(_xwin.display, None, NULL)) {
500  ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
501  get_config_text ("Could not release drawing context.\n"));
502  }
503  }
504 
505  glXDestroyContext(_xwin.display, _glxwin.ctx);
506  _glxwin.ctx = NULL;
507  }
508 
509  if (_xwin.mouse_grabbed) {
510  XUngrabPointer(_xwin.display, CurrentTime);
511  _xwin.mouse_grabbed = 0;
512  }
513 
514  if (_xwin.keyboard_grabbed) {
515  XUngrabKeyboard(_xwin.display, CurrentTime);
516  _xwin.keyboard_grabbed = 0;
517  }
518 
519 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
520  if (_glxwin.fullscreen) {
521  if (_xwin.mode_switched) {
522  XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, False);
523  XF86VidModeSwitchToMode(_xwin.display, _xwin.screen,
524  _xwin.modesinfo[0]);
525  XF86VidModeSetViewPort(_xwin.display, _xwin.screen, 0, 0);
526  _xwin.mode_switched = 0;
527  }
528  if (_xwin.override_redirected) {
529  setattr.override_redirect = False;
530  XChangeWindowAttributes(_xwin.display, _xwin.window,
531  CWOverrideRedirect, &setattr);
532  _xwin.override_redirected = 0;
533  }
534 
535  /* Free modelines. */
536  free_modelines(_xwin.modesinfo, _xwin.num_modes);
537  _xwin.num_modes = 0;
538  _xwin.modesinfo = NULL;
539  }
540 #endif
541 
542  /* Note: Allegro will destroy screen (== allegro_gl_screen),
543  * so don't destroy it here.
544  */
545  //destroy_bitmap(allegro_gl_screen);
546  ASSERT(allegro_gl_screen == screen);
547  allegro_gl_screen = NULL;
548 
549  /* Unmap the window in order not to see the cursor when quitting.
550  The window *must not* be destroyed and _xwin.visual must be left
551  to its current value otherwise the program will crash when exiting */
552  if (_xwin.window != None)
553  XUnmapWindow(_xwin.display, _xwin.window);
554 
555  if (_glxwin.use_glx_window) {
556  glXDestroyWindow(_xwin.display, _glxwin.window);
557  _glxwin.window = 0;
558  _glxwin.use_glx_window = FALSE;
559  }
560 
561  __allegro_gl_valid_context = FALSE;
562 
563  _xwin_window_redrawer = old_window_redrawer;
564  XSetErrorHandler(old_x_error_handler);
565 
566 
567 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
568  /* Hack: Allegro 4.2.1 uses a persistent window, we need to restore it. */
569  if (backup_allegro_window != None) {
570  if (_xwin.colormap != None) {
571  XUninstallColormap(_xwin.display, _xwin.colormap);
572  XFreeColormap(_xwin.display, _xwin.colormap);
573  }
574  _xwin.colormap = backup_allegro_colormap;
575 
576  if (_xwin.window != None)
577  XDestroyWindow(_xwin.display, _xwin.window);
578  _xwin.window = backup_allegro_window;
579  backup_allegro_window = None;
580  XMapWindow(_xwin.display, _xwin.window);
581  }
582 #endif
583 
584  XUNLOCK();
585 }
586 
587 
588 
589 /* get_shift:
590  * Returns the shift value for a given mask.
591  */
592 static int get_shift (int mask)
593 {
594  int i = 0, j = 1;
595  if (!mask) return -1;
596  while (!(j & mask)) {
597  i++;
598  j <<= 1;
599  }
600  return i;
601 }
602 
603 
604 
605 static int decode_fbconfig (GLXFBConfig fbc, struct allegro_gl_display_info *i) {
606  int render_type, visual_type, buffer_size, sbuffers, samples;
607  int drawable_type, renderable;
608  XVisualInfo *v;
609 
610  TRACE(PREFIX_I "decode_fbconfig: Decoding:\n");
611  i->rmethod = 2;
612 
613  if (glXGetFBConfigAttrib (_xwin.display, fbc, GLX_RENDER_TYPE,
614  &render_type)
615  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_X_RENDERABLE,
616  &renderable)
617  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_DRAWABLE_TYPE,
618  &drawable_type)
619  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_X_VISUAL_TYPE,
620  &visual_type)
621  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_BUFFER_SIZE,
622  &buffer_size)
623  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_DEPTH_SIZE,
624  &i->depth_size)
625  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_STEREO,
626  &i->stereo)
627  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_RED_SIZE,
628  &i->pixel_size.rgba.r)
629  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_GREEN_SIZE,
630  &i->pixel_size.rgba.g)
631  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_BLUE_SIZE,
632  &i->pixel_size.rgba.b)
633  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ALPHA_SIZE,
634  &i->pixel_size.rgba.a)
635  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_DOUBLEBUFFER,
636  &i->doublebuffered)
637  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_AUX_BUFFERS,
638  &i->aux_buffers)
639  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_STENCIL_SIZE,
640  &i->stencil_size)
641  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_RED_SIZE,
642  &i->accum_size.rgba.r)
643  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_GREEN_SIZE,
644  &i->accum_size.rgba.g)
645  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_BLUE_SIZE,
646  &i->accum_size.rgba.b)
647  || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_ALPHA_SIZE,
648  &i->accum_size.rgba.a)) {
649  TRACE(PREFIX_I "decode_fbconfig: Incomplete glX mode ...\n");
650  return -1;
651  }
652 
653  if (!(render_type & GLX_RGBA_BIT) && !(render_type & GLX_RGBA_FLOAT_BIT)) {
654  TRACE(PREFIX_I "decode_fbconfig: Not RGBA mode\n");
655  return -1;
656  }
657 
658  if (!(drawable_type & GLX_WINDOW_BIT)) {
659  TRACE(PREFIX_I "decode_fbconfig: Cannot render to a window.\n");
660  return -1;
661  }
662 
663  if (renderable == False) {
664  TRACE(PREFIX_I "decode_fbconfig: GLX windows not supported.\n");
665  return -1;
666  }
667 
668  if (visual_type != GLX_TRUE_COLOR && visual_type != GLX_DIRECT_COLOR) {
669  TRACE(PREFIX_I "decode_fbconfig: visual type other than TrueColor and "
670  "DirectColor.\n");
671  return -1;
672  }
673 
674  /* Floating-point depth is not supported as glx extension (yet). */
675  i->float_depth = 0;
676 
677  i->float_color = (render_type & GLX_RGBA_FLOAT_BIT);
678 
679  v = glXGetVisualFromFBConfig(_xwin.display, fbc);
680  if (!v) {
681  TRACE(PREFIX_I "decode_fbconfig: Cannot get associated visual for the "
682  "FBConfig.\n");
683  return -1;
684  }
685  i->r_shift = get_shift (v->red_mask);
686  i->g_shift = get_shift (v->green_mask);
687  i->b_shift = get_shift (v->blue_mask);
688  i->a_shift = 0;
689 
690  /* If we are going to need to setup a palette we need bit shifts */
691  if ((visual_type == GLX_DIRECT_COLOR)
692  && ((i->r_shift == -1) || (i->g_shift == -1) || (i->b_shift == -1))
693  && (i->pixel_size.rgba.r + i->pixel_size.rgba.g + i->pixel_size.rgba.b
694  <= 12)) {
695  /* XXX <rohannessian> Report something here? */
696  XFree(v);
697  return -1;
698  }
699 
700  i->colour_depth = 0;
701 
702  if (i->pixel_size.rgba.r == 3
703  && i->pixel_size.rgba.g == 3
704  && i->pixel_size.rgba.b == 2) {
705  i->colour_depth = 8;
706  }
707 
708  if (i->pixel_size.rgba.r == 5
709  && i->pixel_size.rgba.b == 5) {
710  if (i->pixel_size.rgba.g == 5) {
711  i->colour_depth = 15;
712  }
713  if (i->pixel_size.rgba.g == 6) {
714  i->colour_depth = 16;
715  }
716  }
717 
718  if (i->pixel_size.rgba.r == 8
719  && i->pixel_size.rgba.g == 8
720  && i->pixel_size.rgba.b == 8) {
721  if (i->pixel_size.rgba.a == 0) {
722  i->colour_depth = 24;
723  }
724  if (i->pixel_size.rgba.a == 8) {
725  i->colour_depth = 32;
726  /* small hack that tries to guess alpha shifting */
727  i->a_shift = 48 - i->r_shift - i->g_shift - i->b_shift;
728  }
729  }
730 
731  i->allegro_format = (i->colour_depth != 0)
732  && (i->g_shift == i->pixel_size.rgba.b)
733  && (i->r_shift * i->b_shift == 0)
734  && (i->r_shift + i->b_shift
735  == i->pixel_size.rgba.b + i->pixel_size.rgba.g);
736 
737  if (glXGetConfig(_xwin.display, v, GLX_SAMPLE_BUFFERS, &sbuffers)) {
738  /* Multisample extension is not supported */
739  i->sample_buffers = 0;
740  }
741  else {
742  i->sample_buffers = sbuffers;
743  }
744  if (glXGetConfig(_xwin.display, v, GLX_SAMPLES, &samples)) {
745  /* Multisample extension is not supported */
746  i->samples = 0;
747  }
748  else {
749  i->samples = samples;
750  }
751 
752  XFree(v);
753 
754  TRACE(PREFIX_I "Color Depth: %i\n", buffer_size);
755  TRACE(PREFIX_I "RGBA Type: %s point\n", i->float_color ? "floating" : "fixed");
756  TRACE(PREFIX_I "RGBA: %i.%i.%i.%i\n", i->pixel_size.rgba.r, i->pixel_size.rgba.g,
757  i->pixel_size.rgba.b, i->pixel_size.rgba.a);
758  TRACE(PREFIX_I "Accum: %i.%i.%i.%i\n", i->accum_size.rgba.r, i->accum_size.rgba.g,
759  i->accum_size.rgba.b, i->accum_size.rgba.a);
760  TRACE(PREFIX_I "DblBuf: %i Zbuf: %i Stereo: %i Aux: %i Stencil: %i\n",
761  i->doublebuffered, i->depth_size, i->stereo,
762  i->aux_buffers, i->stencil_size);
763  TRACE(PREFIX_I "Shift: %i.%i.%i.%i\n", i->r_shift, i->g_shift, i->b_shift,
764  i->a_shift);
765  TRACE(PREFIX_I "Sample Buffers: %i Samples: %i\n", i->sample_buffers, i->samples);
766  TRACE(PREFIX_I "Decoded bpp: %i\n", i->colour_depth);
767 
768  return 0;
769 }
770 
771 
772 
773 int allegro_gl_x_windowed_choose_fbconfig (GLXFBConfig *ret_fbconfig) {
774  int num_fbconfigs, i;
775  GLXFBConfig *fbconfig;
776  struct allegro_gl_display_info dinfo;
777 
778  fbconfig = glXGetFBConfigs (_xwin.display, _xwin.screen, &num_fbconfigs);
779  if (!fbconfig || !num_fbconfigs)
780  return FALSE;
781 
782  TRACE(PREFIX_I "x_windowed_choose_fbconfig: %i formats.\n", num_fbconfigs);
783  __allegro_gl_reset_scorer();
784 
785  for (i = 0; i < num_fbconfigs; i++) {
786  TRACE(PREFIX_I "x_windowed_choose_fbconfig: Mode %i\n", i);
787  if (decode_fbconfig (*(fbconfig + i), &dinfo) != -1) {
788  __allegro_gl_score_config (i, &dinfo);
789  }
790  }
791 
792  i = __allegro_gl_best_config();
793  TRACE(PREFIX_I "x_windowed_choose_fbconfig: Best FBConfig is: %i\n", i);
794 
795  if (i < 0) {
796  XFree(fbconfig);
797  return FALSE;
798  }
799 
800  *ret_fbconfig = *(fbconfig + i);
801  XFree(fbconfig);
802 
803  return TRUE;
804 }
805 
806 
807 
808 /* windowed_choose_visual:
809  * Chooses a visual to use.
810  */
811 static XVisualInfo *allegro_gl_x_windowed_choose_visual (void)
812 {
813  int num_visuals, i;
814  XVisualInfo *vinfo;
815  struct allegro_gl_display_info dinfo;
816  static XVisualInfo ret_vinfo;
817 
818  vinfo = XGetVisualInfo (_xwin.display, 0, NULL, &num_visuals);
819  if (!vinfo) return NULL;
820 
821  TRACE(PREFIX_I "x_windowed_choose_visual: %i formats.\n", num_visuals);
822  __allegro_gl_reset_scorer();
823 
824  for (i = 0; i < num_visuals; i++) {
825  TRACE(PREFIX_I "x_windowed_choose_visual: Mode %i\n", i);
826  if (decode_visual (vinfo + i, &dinfo) != -1) {
827  __allegro_gl_score_config (i, &dinfo);
828  }
829  }
830 
831  i = __allegro_gl_best_config();
832  TRACE(PREFIX_I "x_windowed_choose_visual: Best config is: %i\n", i);
833 
834  if (i < 0) return NULL;
835 
836  memcpy (&ret_vinfo, vinfo+i, sizeof ret_vinfo);
837  XFree (vinfo);
838 
839  return &ret_vinfo;
840 }
841 
842 
843 
844 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
845 /* get_xf86_modes:
846  * Test if the XF86VidMode extension is available and get the gfx modes
847  * that can be queried.
848  */
849 static int get_xf86_modes(XF86VidModeModeInfo ***modesinfo, int *num_modes)
850 {
851  int vid_event_base, vid_error_base;
852  int vid_major_version, vid_minor_version;
853 
854  /* Test for presence of VidMode extension. */
855  if (!XF86VidModeQueryExtension(_xwin.display, &vid_event_base,
856  &vid_error_base)
857  || !XF86VidModeQueryVersion(_xwin.display, &vid_major_version,
858  &vid_minor_version)) {
859 
860  ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
861  get_config_text("VidMode extension is not supported"));
862  return -1;
863  }
864 
865  if (!XF86VidModeGetAllModeLines(_xwin.display, _xwin.screen, num_modes,
866  modesinfo)) {
867  ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
868  get_config_text("Can not Get ModeLines"));
869  return -1;
870  }
871 
872  return 0;
873 }
874 #endif
875 
876 
877 static int allegro_gl_x_error_handler(Display *display, XErrorEvent *err_event)
878 {
879  char buffer[256];
880 
881  XGetErrorText(display, err_event->error_code, buffer, 256);
882  TRACE(PREFIX_E "%s\n", buffer);
883  return 0;
884 }
885 
886 
887 /* create_window:
888  * Based on Michael's `_xwin[_private]_create_window' and the xdemos
889  * from the Mesa distribution (I don't remember which one).
890  */
891 static int allegro_gl_x_create_window (int fullscreen)
892 {
893  Window root;
894  XVisualInfo *visinfo;
895  XSetWindowAttributes setattr;
896  unsigned long valuemask = CWBackPixel | CWBorderPixel | CWColormap
897  | CWEventMask;
898  XSizeHints *hints;
899  GLXFBConfig fbconfig;
900  int use_fbconfig;
901 
902  if (_xwin.display == 0) {
903  return -2;
904  }
905 
906  old_x_error_handler = XSetErrorHandler(allegro_gl_x_error_handler);
907 
908  /* Fill in missing color depth info */
909  __allegro_gl_fill_in_info();
910 
911  use_fbconfig = (_glxwin.major > 1 || (_glxwin.major == 1 && _glxwin.minor >= 3));
912 
913  if (use_fbconfig) {
914  TRACE(PREFIX_I "x_create_window: using FBConfig routines\n");
915 
916  if (!allegro_gl_x_windowed_choose_fbconfig(&fbconfig)) {
917  TRACE(PREFIX_I "x_create_window: Failed using FBConfig, switching "
918  "back to VisualInfo routines\n");
919  use_fbconfig = FALSE;
920  goto old_choose_visual;
921  }
922 
923  /* Query back FBConfig components */
924  if (decode_fbconfig(fbconfig, &allegro_gl_display_info)) {
925  TRACE(PREFIX_E "x_create_window: Cannot decode FBConfig, switching "
926  "back to VisualInfo routines\n");
927  use_fbconfig = FALSE;
928  goto old_choose_visual;
929  }
930 
931  visinfo = glXGetVisualFromFBConfig(_xwin.display, fbconfig);
932  if (!visinfo) {
933  TRACE(PREFIX_I "x_create_window: Failed to convert FBConfig to "
934  "visual, switching back to VisualInfo routines\n");
935  use_fbconfig = FALSE;
936  goto old_choose_visual;
937  }
938  }
939  else {
940 old_choose_visual:
941  TRACE(PREFIX_I "x_create_window: using VisualInfo routines\n");
942 
943  /* Find best visual */
944  visinfo = allegro_gl_x_windowed_choose_visual();
945  if (!visinfo) {
946  TRACE(PREFIX_E "x_create_window: Can not get visual.\n");
947  XSetErrorHandler(old_x_error_handler);
948  return -2;
949  }
950 
951  /* Query back visual components */
952  if (decode_visual (visinfo, &allegro_gl_display_info)) {
953  TRACE(PREFIX_E "x_create_window: Can not decode visual.\n");
954  XSetErrorHandler(old_x_error_handler);
955  return -2;
956  }
957  }
958 
959  /* Log some information about it */
960  switch (visinfo->class) {
961  case TrueColor:
962  AGL_LOG (1, "x.c: visual class: TrueColor\n");
963  break;
964  case DirectColor:
965  AGL_LOG (1, "x.c: visual class: DirectColor\n");
966  break;
967  default:
968  AGL_LOG (1, "x.c: visual class: invalid(!)\n");
969  }
970 
971 
972  /* Begin window creation. */
973 
974 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
975  /* Hack: For Allegro 4.2.1, we need to keep the existing window. */
976  if (backup_allegro_window == None) {
977  backup_allegro_window = _xwin.window;
978  backup_allegro_colormap = _xwin.colormap;
979  _xwin.colormap = None;
980  XUnmapWindow(_xwin.display, _xwin.window);
981  }
982  else
983 #endif
984  XDestroyWindow (_xwin.display, _xwin.window);
985 
986  _xwin.window = None;
987 
988  root = RootWindow (_xwin.display, _xwin.screen);
989 
990  /* Recreate window. */
991  setattr.background_pixel = XBlackPixel (_xwin.display, _xwin.screen);
992  setattr.border_pixel = XBlackPixel (_xwin.display, _xwin.screen);
993  setattr.colormap = XCreateColormap (_xwin.display, root, visinfo->visual, AllocNone);
994  setattr.event_mask =
995  ( KeyPressMask | KeyReleaseMask
996  | EnterWindowMask | LeaveWindowMask
997  | FocusChangeMask | ExposureMask
998  | ButtonPressMask | ButtonReleaseMask | PointerMotionMask
999  /*| MappingNotifyMask (SubstructureRedirectMask?)*/
1000  );
1001 
1002 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
1003  if (fullscreen) {
1004  int i;
1005  int bestmode = 0;
1006  _xwin.num_modes = 0;
1007  _xwin.modesinfo = NULL;
1008  _glxwin.fullscreen = TRUE;
1009 
1010  if (get_xf86_modes(&_xwin.modesinfo, &_xwin.num_modes)) {
1011  ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1012  get_config_text("x_create_window: Can't get"
1013  "XF86VidMode info.\n"));
1014  XSetErrorHandler(old_x_error_handler);
1015  return -2;
1016  }
1017 
1018  /* look for mode with requested resolution */
1019  for (i = 0; i < _xwin.num_modes; i++)
1020  {
1021  if ((_xwin.modesinfo[i]->hdisplay == allegro_gl_display_info.w)
1022  && (_xwin.modesinfo[i]->vdisplay == allegro_gl_display_info.h))
1023  bestmode = i;
1024  }
1025 
1026  setattr.override_redirect = True;
1027  if (!XF86VidModeSwitchToMode(_xwin.display, _xwin.screen,
1028  _xwin.modesinfo[bestmode])) {
1029 
1030  ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1031  get_config_text("Can not set XF86VidMode mode"));
1032  XSetErrorHandler(old_x_error_handler);
1033  return -1;
1034  }
1035 
1036  XF86VidModeSetViewPort(_xwin.display, _xwin.screen, 0, 0);
1037 
1038  /* Lock Mode switching */
1039  XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, True);
1040  _xwin.mode_switched = 1;
1041 
1042  allegro_gl_display_info.x = 0;
1043  allegro_gl_display_info.y = 0;
1044  allegro_gl_display_info.w = _xwin.modesinfo[bestmode]->hdisplay;
1045  allegro_gl_display_info.h = _xwin.modesinfo[bestmode]->vdisplay;
1046 
1047  valuemask |= CWOverrideRedirect;
1048  _xwin.override_redirected = 1;
1049  }
1050 
1051  _xwin.window = XCreateWindow (
1052  _xwin.display, root,
1053  allegro_gl_display_info.x, allegro_gl_display_info.y,
1054  allegro_gl_display_info.w, allegro_gl_display_info.h, 0,
1055  visinfo->depth,
1056  InputOutput,
1057  visinfo->visual,
1058  valuemask, &setattr
1059  );
1060 
1061 #else //ALLEGROGL_HAVE_XF86VIDMODE
1062  if (fullscreen) {
1063  /* Without Xf86VidMode extension we support only fullscreen modes which
1064  * match current resolution. */
1065  int fs_width = DisplayWidth(_xwin.display, _xwin.screen);
1066  int fs_height = DisplayHeight(_xwin.display, _xwin.screen);
1067 
1068  if (fs_width != allegro_gl_display_info.w
1069  || fs_height != allegro_gl_display_info.h) {
1070  TRACE(PREFIX_E "Only desktop resolution fullscreen available.");
1071  ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1072  get_config_text("Compiled without Xf86VidMode extension support.\n"
1073  "Only desktop resolution fullscreen available."));
1074  XSetErrorHandler(old_x_error_handler);
1075  return -1;
1076  }
1077 
1078  _glxwin.fullscreen = TRUE;
1079 
1080  /* Create the fullscreen window. */
1081  _xwin.window = XCreateWindow(_xwin.display, root,
1082  allegro_gl_display_info.x, allegro_gl_display_info.y,
1083  fs_width, fs_height, 0,
1084  visinfo->depth,
1085  InputOutput,
1086  visinfo->visual,
1087  valuemask, &setattr);
1088 
1089  /* Map the fullscreen window. */
1090  XMapRaised(_xwin.display, _xwin.window);
1091 
1092  /* Make sure we got to the top of the window stack. */
1093  XRaiseWindow(_xwin.display, _xwin.fs_window);
1094  }
1095  else {
1096  _xwin.window = XCreateWindow (
1097  _xwin.display, root,
1098  allegro_gl_display_info.x, allegro_gl_display_info.y,
1099  allegro_gl_display_info.w, allegro_gl_display_info.h, 0,
1100  visinfo->depth,
1101  InputOutput,
1102  visinfo->visual,
1103  valuemask, &setattr
1104  );
1105  }
1106 #endif //ALLEGROGL_HAVE_XF86VIDMODE
1107 
1108  /* Set size and position hints for Window Manager :
1109  * prevents the window to be resized
1110  */
1111  hints = XAllocSizeHints();
1112  if (hints) {
1113  /* This code chunk comes from Allegro's src/x/xwin.c */
1114  hints->flags = PMinSize | PMaxSize | PBaseSize;
1115  hints->min_width = hints->max_width = hints->base_width
1116  = allegro_gl_display_info.w;
1117  hints->min_height = hints->max_height = hints->base_height
1118  = allegro_gl_display_info.h;
1119 
1120  XSetWMNormalHints(_xwin.display, _xwin.window, hints);
1121  XFree(hints);
1122  }
1123 
1124 
1125  /* Set WM_DELETE_WINDOW atom in WM_PROTOCOLS property
1126  * (to get window_delete requests).
1127  */
1128  {
1129  Atom wm_delete_window = XInternAtom(_xwin.display, "WM_DELETE_WINDOW", False);
1130  XSetWMProtocols(_xwin.display, _xwin.window, &wm_delete_window, 1);
1131  }
1132 
1133  /* Finish off the GLX setup */
1134  if (use_fbconfig)
1135  _glxwin.ctx = glXCreateNewContext (_xwin.display, fbconfig, GLX_RGBA_TYPE, NULL, True);
1136  else
1137  _glxwin.ctx = glXCreateContext (_xwin.display, visinfo, NULL, True);
1138 
1139  if (use_fbconfig) {
1140  _glxwin.window = glXCreateWindow(_xwin.display, fbconfig, _xwin.window, 0);
1141  if (!_glxwin.window) {
1142  ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1143  get_config_text("Cannot create GLX window."));
1144  XSetErrorHandler(old_x_error_handler);
1145  return -1;
1146  }
1147  _glxwin.use_glx_window = TRUE;
1148  }
1149 
1150  if (!_glxwin.ctx) {
1151  ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1152  get_config_text("Can not create GLX context."));
1153  XSetErrorHandler(old_x_error_handler);
1154  return -1;
1155  }
1156  else {
1157  Bool ret;
1158 
1159  if (use_fbconfig)
1160  ret = glXMakeContextCurrent(_xwin.display, _glxwin.window, _glxwin.window, _glxwin.ctx);
1161  else
1162  ret = glXMakeCurrent (_xwin.display, _xwin.window, _glxwin.ctx);
1163 
1164  if (!ret) {
1165  ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1166  get_config_text("Cannot make GLX context current."));
1167  XSetErrorHandler(old_x_error_handler);
1168  return -1;
1169  }
1170  }
1171 
1172  /* Finish off the Allegro setup */
1173 
1174  /* Get associated visual and window depth (bits per pixel), and
1175  * store window size */
1176  {
1177  XWindowAttributes getattr;
1178  XGetWindowAttributes(_xwin.display, _xwin.window, &getattr);
1179  _xwin.visual = getattr.visual;
1180  _xwin.window_depth = getattr.depth;
1181  _xwin.window_width = allegro_gl_display_info.w;
1182  _xwin.window_height = allegro_gl_display_info.h;
1183  _xwin.screen_depth = getattr.depth;
1184  _xwin.screen_width = allegro_gl_display_info.w;
1185  _xwin.screen_height = allegro_gl_display_info.h;
1186  }
1187 
1188  /* Destroy the current colormap (if any) */
1189  if (_xwin.colormap != None) {
1190  XUninstallColormap(_xwin.display, _xwin.colormap);
1191  XFreeColormap(_xwin.display, _xwin.colormap);
1192  }
1193 
1194  /* Create and install colormap. */
1195  if (_xwin.visual->class == DirectColor) {
1196  _xwin.colormap = XCreateColormap(_xwin.display, _xwin.window,
1197  _xwin.visual, AllocAll);
1198  }
1199  else { /* must be TrueColor */
1200  _xwin.colormap = XCreateColormap(_xwin.display, _xwin.window,
1201  _xwin.visual, AllocNone);
1202  }
1203  XSetWindowColormap(_xwin.display, _xwin.window, _xwin.colormap);
1204  XInstallColormap(_xwin.display, _xwin.colormap);
1205 
1206  /* Setup a palette if needed */
1207  if (_xwin.visual->class == DirectColor) {
1208  XColor color;
1209  int rsize, gsize, bsize;
1210  int rmax, gmax, bmax;
1211  int rshift, gshift, bshift;
1212  int r, g, b;
1213 
1214  AGL_LOG (1, "x.c: Using DirectColor visual, setting palette...\n");
1215 
1216  rsize = 1 << allegro_gl_display_info.pixel_size.rgba.r;
1217  gsize = 1 << allegro_gl_display_info.pixel_size.rgba.g;
1218  bsize = 1 << allegro_gl_display_info.pixel_size.rgba.b;
1219 
1220  rshift = allegro_gl_display_info.r_shift;
1221  bshift = allegro_gl_display_info.b_shift;
1222  gshift = allegro_gl_display_info.g_shift;
1223 
1224  rmax = rsize - 1;
1225  gmax = gsize - 1;
1226  bmax = bsize - 1;
1227 
1228  color.flags = DoRed | DoGreen | DoBlue;
1229  for (r = 0; r < rsize; r++) {
1230  for (g = 0; g < gsize; g++) {
1231  for (b = 0; b < bsize; b++) {
1232  color.pixel = (r << rshift) | (g << gshift) | (b << bshift);
1233  color.red = ((rmax <= 0) ? 0 : ((r * 65535L) / rmax));
1234  color.green = ((gmax <= 0) ? 0 : ((g * 65535L) / gmax));
1235  color.blue = ((bmax <= 0) ? 0 : ((b * 65535L) / bmax));
1236  XStoreColor(_xwin.display, _xwin.colormap, &color);
1237  }
1238  }
1239  }
1240  }
1241 
1242  /* Configure the window a bit */
1243  {
1244  XClassHint hint;
1245  XWMHints wm_hints;
1246 
1247  /* Set title. */
1248  XStoreName(_xwin.display, _xwin.window, _xwin.window_title);
1249 
1250  /* Set hints. */
1251  hint.res_name = _xwin.application_name;
1252  hint.res_class = _xwin.application_class;
1253  XSetClassHint(_xwin.display, _xwin.window, &hint);
1254 
1255  wm_hints.flags = InputHint | StateHint;
1256  wm_hints.input = True;
1257  wm_hints.initial_state = NormalState;
1258 
1259 #ifdef ALLEGRO_XWINDOWS_WITH_XPM
1260  if (allegro_icon) {
1261  wm_hints.flags |= IconPixmapHint | IconMaskHint | WindowGroupHint;
1262  XpmCreatePixmapFromData(_xwin.display, _xwin.window, allegro_icon,&wm_hints.icon_pixmap, &wm_hints.icon_mask, NULL);
1263  }
1264 #endif
1265 
1266  XSetWMHints(_xwin.display, _xwin.window, &wm_hints);
1267  }
1268 
1269  /* Map window. */
1270  XMapWindow(_xwin.display, _xwin.window);
1271 
1272 
1273  if (fullscreen) {
1274  AL_CONST char *fc = NULL;
1275  char tmp1[64], tmp2[128];
1276  int c = 0;
1277  int h = allegro_gl_display_info.h;
1278  int w = allegro_gl_display_info.w;
1279 
1280  /* This chunk is disabled by default because of problems on KDE
1281  desktops. */
1282  fc = get_config_string(uconvert_ascii("graphics", tmp1),
1283  uconvert_ascii("force_centering", tmp2), NULL);
1284  if ((fc) && ((c = ugetc(fc)) != 0) && ((c == 'y') || (c == 'Y')
1285  || (c == '1'))) {
1286  /* Hack: make the window fully visible and center cursor. */
1287  XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, 0, 0);
1288  XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
1289  w - 1, 0);
1290  XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
1291  0, h - 1);
1292  XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
1293  w - 1, h - 1);
1294  }
1295  XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
1296  w / 2, h / 2);
1297  XSync(_xwin.display, False);
1298 
1299  /* Grab keyboard and mouse. */
1300  if (XGrabKeyboard(_xwin.display, _xwin.window, False, GrabModeAsync,
1301  GrabModeAsync, CurrentTime) != GrabSuccess) {
1302  ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1303  get_config_text("Can not grab keyboard"));
1304  XSetErrorHandler(old_x_error_handler);
1305  return -1;
1306  }
1307  _xwin.keyboard_grabbed = 1;
1308 
1309  if (XGrabPointer(_xwin.display, _xwin.window, False,
1310  PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1311  GrabModeAsync, GrabModeAsync, _xwin.window, None, CurrentTime)
1312  != GrabSuccess) {
1313 
1314  ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1315  get_config_text("Can not grab mouse"));
1316  XSetErrorHandler(old_x_error_handler);
1317  return -1;
1318  }
1319  _xwin.mouse_grabbed = 1;
1320  }
1321 
1322 
1323  /* Destroy current cursor (if any) */
1324  if (_xwin.cursor != None) {
1325  XUndefineCursor(_xwin.display, _xwin.window);
1326  XFreeCursor(_xwin.display, _xwin.cursor);
1327  }
1328 
1329  {
1330  /* Create invisible X cursor. */
1331  Pixmap pixmap = XCreatePixmap(_xwin.display, _xwin.window, 1, 1, 1);
1332  if (pixmap != None) {
1333  GC temp_gc;
1334  XColor color;
1335  XGCValues gcvalues;
1336 
1337  int gcmask = GCFunction | GCForeground | GCBackground;
1338  gcvalues.function = GXcopy;
1339  gcvalues.foreground = 0;
1340  gcvalues.background = 0;
1341  temp_gc = XCreateGC(_xwin.display, pixmap, gcmask, &gcvalues);
1342  XDrawPoint(_xwin.display, pixmap, temp_gc, 0, 0);
1343  XFreeGC(_xwin.display, temp_gc);
1344  color.pixel = 0;
1345  color.red = color.green = color.blue = 0;
1346  color.flags = DoRed | DoGreen | DoBlue;
1347  _xwin.cursor = XCreatePixmapCursor(_xwin.display, pixmap, pixmap,
1348  &color, &color, 0, 0);
1349  XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
1350  XFreePixmap(_xwin.display, pixmap);
1351  }
1352  else {
1353  _xwin.cursor = XCreateFontCursor(_xwin.display, _xwin.cursor_shape);
1354  XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
1355  }
1356  }
1357 
1358  /* Wait for the first exposure event. See comment in Allegro's
1359  * xwin.c about why no blocking X11 function is used.
1360  */
1361  while (1) {
1362  XEvent e;
1363  if (XCheckTypedEvent(_xwin.display, Expose, &e)) {
1364  if (e.xexpose.count == 0) break;
1365  }
1366  rest(1);
1367  }
1368 
1369  return 0;
1370 }
1371 
1372 
1373 
1374 static BITMAP *allegro_gl_x_windowed_create_screen (GFX_DRIVER *drv, int w, int h, int depth)
1375 {
1376  BITMAP *bmp;
1377  int is_linear = drv->linear;
1378 
1379  drv->linear = 1;
1380  bmp = _make_bitmap (w, h, 0, drv, depth, 0);
1381  bmp->id = BMP_ID_VIDEO | BMP_ID_MASK;
1382  drv->linear = is_linear;
1383 
1384  if (bmp == 0) {
1385  ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1386  get_config_text("Not enough memory"));
1387  return NULL;
1388  }
1389 
1390  drv->w = w;
1391  drv->h = h;
1392 
1393  return bmp;
1394 }
1395 
1396 
1397 
1398 /* decode_visual:
1399  * Used to read back the information in the visual. 0 = ok.
1400  */
1401 static int decode_visual (XVisualInfo *v, struct allegro_gl_display_info *i)
1402 {
1403  int rgba, buffer_size, use_gl, sbuffers, samples;
1404 
1405  TRACE(PREFIX_I "decode_visual: Decoding:\n");
1406  i->rmethod = 2;
1407 
1408  /* We can only support TrueColor and DirectColor visuals --
1409  * we only support RGBA mode */
1410  if (v->class != TrueColor && v->class != DirectColor)
1411  return -1;
1412 
1413  if (glXGetConfig (_xwin.display, v, GLX_RGBA, &rgba)
1414  || glXGetConfig (_xwin.display, v, GLX_USE_GL, &use_gl)
1415  || glXGetConfig (_xwin.display, v, GLX_BUFFER_SIZE, &buffer_size)
1416  || glXGetConfig (_xwin.display, v, GLX_RED_SIZE, &i->pixel_size.rgba.r)
1417  || glXGetConfig (_xwin.display, v, GLX_GREEN_SIZE, &i->pixel_size.rgba.g)
1418  || glXGetConfig (_xwin.display, v, GLX_BLUE_SIZE, &i->pixel_size.rgba.b)
1419  || glXGetConfig (_xwin.display, v, GLX_ALPHA_SIZE, &i->pixel_size.rgba.a)
1420  || glXGetConfig (_xwin.display, v, GLX_DOUBLEBUFFER, &i->doublebuffered)
1421  || glXGetConfig (_xwin.display, v, GLX_STEREO, &i->stereo)
1422  || glXGetConfig (_xwin.display, v, GLX_AUX_BUFFERS, &i->aux_buffers)
1423  || glXGetConfig (_xwin.display, v, GLX_DEPTH_SIZE, &i->depth_size)
1424  || glXGetConfig (_xwin.display, v, GLX_STENCIL_SIZE, &i->stencil_size)
1425  || glXGetConfig (_xwin.display, v, GLX_ACCUM_RED_SIZE,
1426  &i->accum_size.rgba.r)
1427  || glXGetConfig (_xwin.display, v, GLX_ACCUM_GREEN_SIZE,
1428  &i->accum_size.rgba.g)
1429  || glXGetConfig (_xwin.display, v, GLX_ACCUM_BLUE_SIZE,
1430  &i->accum_size.rgba.b)
1431  || glXGetConfig (_xwin.display, v, GLX_ACCUM_ALPHA_SIZE,
1432  &i->accum_size.rgba.a)) {
1433  TRACE(PREFIX_I "x_create_window: Incomplete glX mode ...\n");
1434  return -1;
1435  }
1436 
1437  if (!rgba) {
1438  TRACE(PREFIX_I "x_create_window: Not RGBA mode\n");
1439  return -1;
1440  }
1441 
1442  if (!use_gl) {
1443  ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1444  get_config_text("OpenGL Unsupported"));
1445  return -1;
1446  }
1447 
1448  i->r_shift = get_shift (v->red_mask);
1449  i->g_shift = get_shift (v->green_mask);
1450  i->b_shift = get_shift (v->blue_mask);
1451  i->a_shift = 0;
1452 
1453  /* If we are going to need to setup a palette we need bit shifts */
1454  if ((v->class == DirectColor)
1455  && ((i->r_shift == -1) || (i->g_shift == -1) || (i->b_shift == -1))
1456  && (i->pixel_size.rgba.r + i->pixel_size.rgba.g + i->pixel_size.rgba.b
1457  <= 12)) {
1458  /* XXX <rohannessian> Report something here? */
1459  return -1;
1460  }
1461 
1462  i->float_color = 0;
1463  i->float_depth = 0;
1464 
1465  i->colour_depth = 0;
1466 
1467  if (i->pixel_size.rgba.r == 3
1468  && i->pixel_size.rgba.g == 3
1469  && i->pixel_size.rgba.b == 2) {
1470  i->colour_depth = 8;
1471  }
1472 
1473  if (i->pixel_size.rgba.r == 5
1474  && i->pixel_size.rgba.b == 5) {
1475  if (i->pixel_size.rgba.g == 5) {
1476  i->colour_depth = 15;
1477  }
1478  if (i->pixel_size.rgba.g == 6) {
1479  i->colour_depth = 16;
1480  }
1481  }
1482 
1483  if (i->pixel_size.rgba.r == 8
1484  && i->pixel_size.rgba.g == 8
1485  && i->pixel_size.rgba.b == 8) {
1486  if (i->pixel_size.rgba.a == 0) {
1487  i->colour_depth = 24;
1488  }
1489  if (i->pixel_size.rgba.a == 8) {
1490  i->colour_depth = 32;
1491  /* small hack that tries to guess alpha shifting */
1492  i->a_shift = 48 - i->r_shift - i->g_shift - i->b_shift;
1493  }
1494  }
1495 
1496  i->allegro_format = (i->colour_depth != 0)
1497  && (i->g_shift == i->pixel_size.rgba.b)
1498  && (i->r_shift * i->b_shift == 0)
1499  && (i->r_shift + i->b_shift
1500  == i->pixel_size.rgba.b + i->pixel_size.rgba.g);
1501 
1502  if (glXGetConfig(_xwin.display, v, GLX_SAMPLE_BUFFERS, &sbuffers)
1503  == GLX_BAD_ATTRIBUTE) {
1504  /* Multisample extension is not supported */
1505  i->sample_buffers = 0;
1506  }
1507  else {
1508  i->sample_buffers = sbuffers;
1509  }
1510  if (glXGetConfig(_xwin.display, v, GLX_SAMPLES, &samples)
1511  == GLX_BAD_ATTRIBUTE) {
1512  /* Multisample extension is not supported */
1513  i->samples = 0;
1514  }
1515  else {
1516  i->samples = samples;
1517  }
1518 
1519 
1520  TRACE(PREFIX_I "Color Depth: %i\n", buffer_size);
1521  TRACE(PREFIX_I "RGBA: %i.%i.%i.%i\n", i->pixel_size.rgba.r, i->pixel_size.rgba.g,
1522  i->pixel_size.rgba.b, i->pixel_size.rgba.a);
1523  TRACE(PREFIX_I "Accum: %i.%i.%i.%i\n", i->accum_size.rgba.r, i->accum_size.rgba.g,
1524  i->accum_size.rgba.b, i->accum_size.rgba.a);
1525  TRACE(PREFIX_I "DblBuf: %i Zbuf: %i Stereo: %i Aux: %i Stencil: %i\n",
1526  i->doublebuffered, i->depth_size, i->stereo,
1527  i->aux_buffers, i->stencil_size);
1528  TRACE(PREFIX_I "Shift: %i.%i.%i.%i\n", i->r_shift, i->g_shift, i->b_shift,
1529  i->a_shift);
1530  TRACE(PREFIX_I "Sample Buffers: %i Samples: %i\n", i->sample_buffers, i->samples);
1531  TRACE(PREFIX_I "Decoded bpp: %i\n", i->colour_depth);
1532 
1533  return 0;
1534 }
1535 
1536 
1537 
1538 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
1539 /* allegro_gl_x_fetch_mode_list:
1540  * Generates a list of valid video modes (made after
1541  * _xvidmode_private_fetch_mode_list of Allegro)
1542  */
1543 static GFX_MODE_LIST* allegro_gl_x_fetch_mode_list(void)
1544 {
1545  int num_modes = 0;
1546  XF86VidModeModeInfo **modesinfo = NULL;
1547  GFX_MODE_LIST *mode_list;
1548  int i;
1549 
1550  XLOCK();
1551 
1552  if (get_xf86_modes(&modesinfo, &num_modes)) {
1553  XUNLOCK();
1554  return NULL;
1555  }
1556 
1557  /* Allocate space for mode list. */
1558  mode_list = malloc(sizeof(GFX_MODE_LIST));
1559  if (!mode_list) {
1560  free_modelines(modesinfo, num_modes);
1561  XUNLOCK();
1562  return NULL;
1563  }
1564 
1565  mode_list->mode = malloc(sizeof(GFX_MODE) * (num_modes + 1));
1566  if (!mode_list->mode) {
1567  free(mode_list);
1568  free_modelines(modesinfo, num_modes);
1569  XUNLOCK();
1570  return NULL;
1571  }
1572 
1573  /* Fill in mode list. */
1574  for (i = 0; i < num_modes; i++) {
1575  mode_list->mode[i].width = modesinfo[i]->hdisplay;
1576  mode_list->mode[i].height = modesinfo[i]->vdisplay;
1577  /* Since XF86VidMode can not change the color depth of
1578  * the screen, there is no need to define modes for other
1579  * color depth than the desktop's.
1580  */
1581  mode_list->mode[i].bpp = desktop_color_depth();
1582  }
1583 
1584  mode_list->mode[num_modes].width = 0;
1585  mode_list->mode[num_modes].height = 0;
1586  mode_list->mode[num_modes].bpp = 0;
1587  mode_list->num_modes = num_modes;
1588 
1589  free_modelines(modesinfo, num_modes);
1590 
1591  XUNLOCK();
1592  return mode_list;
1593 }
1594 #endif
1595 
1596 
1597 
1598 /* allegro_gl_x_vsync:
1599  * Wait for a vertical retrace. GLX_SGI_video_sync is needed.
1600  */
1601 static void allegro_gl_x_vsync(void)
1602 {
1603  XLOCK();
1604  if (allegro_gl_extensions_GLX.SGI_video_sync) {
1605  unsigned int count;
1606 
1607  glXGetVideoSyncSGI(&count);
1608  glXWaitVideoSyncSGI(2, (count+1) & 1, &count);
1609  }
1610  XUNLOCK();
1611 }
1612 
1613 
1614 
1615 /******************************/
1616 /* AllegroGL driver functions */
1617 /******************************/
1618 
1619 /* flip:
1620  * Does a page flip / double buffer copy / whatever it really is.
1621  */
1622 static void flip (void)
1623 {
1624  XLOCK();
1625  if (_glxwin.use_glx_window)
1626  glXSwapBuffers (_xwin.display, _glxwin.window);
1627  else
1628  glXSwapBuffers (_xwin.display, _xwin.window);
1629  XUNLOCK();
1630 }
1631 
1632 
1633 
1634 /* gl_on, gl_off:
1635  * Switches to/from GL mode.
1636  */
1637 static void gl_on (void)
1638 {
1639 #ifdef OLD_ALLEGRO
1640  DISABLE();
1641 #endif
1642 }
1643 
1644 
1645 
1646 static void gl_off (void)
1647 {
1648 #ifdef OLD_ALLEGRO
1649  ENABLE();
1650  _xwin_handle_input();
1651 #endif
1652 }
1653 
1654 
1655 
1656 /*****************/
1657 /* Driver struct */
1658 /*****************/
1659 
1660 static struct allegro_gl_driver allegro_gl_x = {
1661  flip,
1662  gl_on,
1663  gl_off,
1664  NULL
1665 };
1666 
#define GFX_OPENGL_FULLSCREEN
Fullscreen OpenGL graphics driver for Allegro.
Definition: alleggl.h:435
#define GFX_OPENGL_WINDOWED
Windowed OpenGL graphics driver for Allegro.
Definition: alleggl.h:433
void allegro_gl_destroy_video_bitmap(BITMAP *bmp)
destroy_video_bitmap() overload.
Definition: videovtb.c:308
Main header file for AllegroGL.
BITMAP * allegro_gl_screen
Direct-mode GL `screen&#39; bitmap.
Definition: alleggl.c:62
BITMAP * allegro_gl_create_video_bitmap(int w, int h)
create_video_bitmap() overload.
Definition: videovtb.c:344