AllegroGL 0.4.4

x.c

00001 /* This code is (C) AllegroGL contributors, and double licensed under
00002  * the GPL and zlib licenses. See gpl.txt or zlib.txt for details.
00003  */
00004 /*----------------------------------------------------------------
00005  * x.c -- Allegro-GLX interfacing
00006  *----------------------------------------------------------------
00007  *  This is the interface module for use under X.
00008  */
00009 #include <string.h>
00010 #include <stdio.h>
00011 
00012 #include <allegro.h>
00013 #include <xalleg.h>
00014 
00015 #include <allegro/platform/aintunix.h>
00016 
00017 #include "alleggl.h"
00018 #include "allglint.h"
00019 #include "glvtable.h"
00020 
00021 
00022 #ifndef XLOCK
00023     #define OLD_ALLEGRO
00024     #define XLOCK() DISABLE()
00025     #undef XUNLOCK
00026     #define XUNLOCK() ENABLE()
00027 #endif
00028 
00029 #define PREFIX_I                "agl-x INFO: "
00030 #define PREFIX_E                "agl-x ERROR: "
00031 
00032 
00033 #ifdef ALLEGRO_XWINDOWS_WITH_XPM
00034 #include <X11/xpm.h>
00035 extern void *allegro_icon;
00036 #endif
00037 
00038 
00039 static BITMAP *allegro_gl_x_windowed_init(int w, int h, int vw, int vh,
00040                                           int color_depth);
00041 static void allegro_gl_x_exit(BITMAP *bmp);
00042 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00043 static GFX_MODE_LIST* allegro_gl_x_fetch_mode_list(void);
00044 #endif
00045 static void allegro_gl_x_vsync(void);
00046 static void allegro_gl_x_hide_mouse(void);
00047 
00048 static BITMAP *allegro_gl_screen = NULL;
00049 
00050 /* TODO: Revamp the whole window handling under X11 in Allegro and
00051  * AllegroGL. We really shouldn't have to duplicate code or hack on
00052  * Allegro internals in AllegroGL - the *only* difference for the AllegroGL
00053  * window should be the GLX visual (e.g. cursor, icon, VidModeExtension and
00054  * so on should never have been touched in this file).
00055  */
00056 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
00057 static Window backup_allegro_window = None;
00058 static Colormap backup_allegro_colormap = None;
00059 #endif
00060 
00061 
00062 static BITMAP *allegro_gl_x_fullscreen_init(int w, int h, int vw, int vh,
00063                                             int color_depth);
00064 
00065 GFX_DRIVER gfx_allegro_gl_fullscreen =
00066 {
00067    GFX_OPENGL_FULLSCREEN,
00068    empty_string,
00069    empty_string,
00070    "AllegroGL Fullscreen (X)",
00071    allegro_gl_x_fullscreen_init,
00072    allegro_gl_x_exit,
00073    NULL,
00074    allegro_gl_x_vsync,
00075    NULL,
00076    NULL, NULL, NULL,
00077    allegro_gl_create_video_bitmap,
00078    allegro_gl_destroy_video_bitmap,
00079    NULL, NULL,                  /* No show/request video bitmaps */
00080    NULL, NULL,
00081    allegro_gl_set_mouse_sprite,
00082    allegro_gl_show_mouse,
00083    allegro_gl_x_hide_mouse,
00084    allegro_gl_move_mouse,
00085    allegro_gl_drawing_mode,
00086    NULL, NULL,
00087    allegro_gl_set_blender_mode,
00088 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00089    allegro_gl_x_fetch_mode_list,
00090 #else
00091    NULL,
00092 #endif
00093    0, 0,
00094    0,
00095    0, 0,
00096    0,
00097    0,
00098    FALSE                        /* Windowed mode */
00099 };
00100 
00101 
00102 
00103 GFX_DRIVER gfx_allegro_gl_windowed =
00104 {
00105    GFX_OPENGL_WINDOWED,
00106    empty_string,
00107    empty_string,
00108    "AllegroGL Windowed (X)",
00109    allegro_gl_x_windowed_init,
00110    allegro_gl_x_exit,
00111    NULL,
00112    allegro_gl_x_vsync,
00113    NULL,
00114    NULL, NULL, NULL,
00115    allegro_gl_create_video_bitmap,
00116    allegro_gl_destroy_video_bitmap,
00117    NULL, NULL,                  /* No show/request video bitmaps */
00118    NULL, NULL,
00119    allegro_gl_set_mouse_sprite,
00120    allegro_gl_show_mouse,
00121    allegro_gl_x_hide_mouse,
00122    allegro_gl_move_mouse,
00123    allegro_gl_drawing_mode,
00124    NULL, NULL,
00125    allegro_gl_set_blender_mode,
00126    NULL,                        /* No fetch_mode_list */
00127    0, 0,
00128    0,
00129    0, 0,
00130    0,
00131    0,
00132    TRUE                         /* Windowed mode */
00133 };
00134 
00135 
00136 
00137 static struct allegro_gl_driver allegro_gl_x;
00138 
00139 static XVisualInfo *allegro_gl_x_windowed_choose_visual (void);
00140 static int allegro_gl_x_create_window (int fullscreen);
00141 static BITMAP *allegro_gl_x_windowed_create_screen (GFX_DRIVER *drv, int w, int h, int depth);
00142 
00143 static int decode_visual (XVisualInfo *v, struct allegro_gl_display_info *i);
00144 struct {
00145     int fullscreen;
00146     GLXContext ctx;
00147     int major, minor;   /* Major and minor GLX version */
00148     int error_base, event_base;
00149     int use_glx_window;
00150     GLXWindow window;
00151 } _glxwin;
00152 
00153 static void (*old_window_redrawer)(int, int, int, int);
00154 extern void (*_xwin_window_redrawer)(int, int, int, int);
00155 static int (*old_x_error_handler)(Display*, XErrorEvent*);
00156 
00157 
00158 
00159 /* allegro_gl_redraw_window :
00160  *  Redraws the window when an Expose event is processed
00161  *  Important note : no GL commands should be processed in this function
00162  *  since it may be called by a thread which is different from the main thread.
00163  *  In order to be able to process GL commands, we should create another context
00164  *  and make it current to the other thread. IMHO it would be overkill.
00165  */
00166 static void allegro_gl_redraw_window(int x, int y, int w, int h)
00167 {
00168     /* Does nothing */
00169     return;
00170 }
00171 
00172 
00173 
00174 #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
00175 /* _xwin_hide_x_mouse:
00176  * Create invisible X cursor
00177  */
00178 static void _xwin_hide_x_mouse(void)
00179 {
00180     unsigned long gcmask;
00181     XGCValues gcvalues;
00182     Pixmap pixmap;
00183 
00184     XUndefineCursor(_xwin.display, _xwin.window);
00185 
00186     if (_xwin.cursor != None) {
00187         XFreeCursor(_xwin.display, _xwin.cursor);
00188         _xwin.cursor = None;
00189     }
00190 
00191     if (_xwin.xcursor_image != None) {
00192         XcursorImageDestroy(_xwin.xcursor_image);
00193         _xwin.xcursor_image = None;
00194     }
00195 
00196     pixmap = XCreatePixmap(_xwin.display, _xwin.window, 1, 1, 1);
00197     if (pixmap != None) {
00198         GC temp_gc;
00199         XColor color;
00200 
00201         gcmask = GCFunction | GCForeground | GCBackground;
00202         gcvalues.function = GXcopy;
00203         gcvalues.foreground = 0;
00204         gcvalues.background = 0;
00205         temp_gc = XCreateGC(_xwin.display, pixmap, gcmask, &gcvalues);
00206         XDrawPoint(_xwin.display, pixmap, temp_gc, 0, 0);
00207         XFreeGC(_xwin.display, temp_gc);
00208         color.pixel = 0;
00209         color.red = color.green = color.blue = 0;
00210         color.flags = DoRed | DoGreen | DoBlue;
00211         _xwin.cursor = XCreatePixmapCursor(_xwin.display, pixmap, pixmap, &color, &color, 0, 0);
00212         XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
00213         XFreePixmap(_xwin.display, pixmap);
00214     }
00215     else {
00216         _xwin.cursor = XCreateFontCursor(_xwin.display, _xwin.cursor_shape);
00217         XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
00218     }
00219 }
00220 #endif
00221 
00222 
00223 
00224 /* hide_mouse:
00225  *  Hide the custom X cursor (if supported)
00226  */
00227 static void hide_mouse(void)
00228 {
00229    #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
00230    if (_xwin.support_argb_cursor) {
00231       XLOCK();
00232       _xwin_hide_x_mouse();
00233       XUNLOCK();
00234    }
00235    #endif
00236    return;
00237 }
00238 
00239 
00240 
00241 /* If Allegro's X11 mouse driver enabled hw cursors, we shouldn't use
00242  * allegro_gl_hide_mouse();
00243  */
00244 static void allegro_gl_x_hide_mouse(void)
00245 {
00246     if (_xwin.hw_cursor_ok) {
00247         hide_mouse();
00248     }
00249     else {
00250         allegro_gl_hide_mouse();
00251     }
00252 }
00253 
00254 
00255 
00256 /* allegro_gl_x_windowed_init:
00257  *  Creates screen bitmap.
00258  */
00259 static BITMAP *allegro_gl_x_create_screen(int w, int h, int vw, int vh,
00260                                           int depth, int fullscreen)
00261 {
00262     int _keyboard_was_installed = FALSE;
00263     int _mouse_was_installed = FALSE;
00264     int create_window_ret;
00265 
00266     /* test if Allegro have pthread support enabled */
00267     if (!_unix_bg_man->multi_threaded) {
00268         ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
00269                get_config_text("Fatal Error : pthread support is not enabled"));
00270         return NULL;
00271     }
00272     
00273     if (keyboard_driver) {
00274         _keyboard_was_installed = TRUE;
00275         remove_keyboard();
00276         TRACE(PREFIX_I "x_create_screen: Removing Keyboard...\n");
00277     }
00278     
00279     if (mouse_driver) {
00280         _mouse_was_installed = TRUE;
00281         remove_mouse();
00282         TRACE(PREFIX_I "x_create_screen: Removing Mouse...\n");
00283     }
00284     
00285     XLOCK();
00286 
00287     if (!glXQueryExtension(_xwin.display, &_glxwin.error_base,
00288                           &_glxwin.event_base)) {
00289 
00290         ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
00291                      get_config_text("GLX Extension not supported by display"));
00292         XUNLOCK();
00293         goto failure;
00294     }
00295 
00296     sscanf(glXQueryServerString(_xwin.display, _xwin.screen, GLX_VERSION),
00297             "%i.%i", &_glxwin.major, &_glxwin.minor);
00298 
00299     if ((w == 0) && (h == 0)) {
00300         w = 640;
00301         h = 480;
00302     }
00303 
00304     if ((vw > w) || (vh > h)) {
00305         ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
00306              get_config_text ("OpenGL drivers do not support virtual screens"));
00307         XUNLOCK();
00308         goto failure;
00309     }
00310 
00311     allegro_gl_display_info.w = w;
00312     allegro_gl_display_info.h = h;
00313 
00314     old_window_redrawer = _xwin_window_redrawer;
00315     _xwin_window_redrawer = allegro_gl_redraw_window;
00316     _glxwin.fullscreen = FALSE;
00317     _glxwin.use_glx_window = FALSE;
00318 
00319     create_window_ret = allegro_gl_x_create_window(fullscreen);
00320     if (create_window_ret) {
00321         if (fullscreen && create_window_ret == -2) {
00322             ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
00323                       get_config_text ("Unable to switch in GLX fullscreen"));
00324         }
00325         else if (create_window_ret == -2) {
00326             ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
00327                       get_config_text ("Unable to create GLX window"));
00328         }
00329         XUNLOCK();
00330         allegro_gl_x_exit(NULL);
00331         goto failure;
00332     }
00333 
00334     /* If pixel format is Allegro compatible, set up Allegro correctly. */
00335     set_color_depth(allegro_gl_display_info.colour_depth);
00336 
00337     /* XXX <rohannessian> X can run on Big-Endian systems. We need to 
00338      * make a check for that and pass TRUE to
00339      * __allegro_gl_set_allegro_image_format() in that case.
00340      */
00341     __allegro_gl_set_allegro_image_format(FALSE);
00342 
00343     if (fullscreen) {
00344         allegro_gl_screen =
00345                allegro_gl_x_windowed_create_screen (&gfx_allegro_gl_fullscreen,
00346                        allegro_gl_display_info.w, allegro_gl_display_info.h,
00347                        _color_depth);
00348     }
00349     else {
00350         allegro_gl_screen =
00351                 allegro_gl_x_windowed_create_screen (&gfx_allegro_gl_windowed,
00352                         allegro_gl_display_info.w, allegro_gl_display_info.h,
00353                         _color_depth);
00354     }
00355 
00356     if (!allegro_gl_screen) {
00357         ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
00358                   get_config_text ("Error creating screen bitmap"));
00359         XUNLOCK();
00360         allegro_gl_x_exit(NULL);
00361         goto failure;
00362     }
00363     
00364     __allegro_gl_valid_context = TRUE;
00365     __allegro_gl_driver = &allegro_gl_x;
00366 
00367     /* Print out OpenGL version info */
00368     TRACE(PREFIX_I "OpenGL Version: %s\n", (AL_CONST char*)glGetString(GL_VERSION));
00369     TRACE(PREFIX_I "OpenGL Vendor: %s\n", (AL_CONST char*)glGetString(GL_VENDOR));
00370     TRACE(PREFIX_I "OpenGL Renderer: %s\n", (AL_CONST char*)glGetString(GL_RENDERER));
00371     
00372     /* Detect if the GL driver is based on Mesa */
00373     allegro_gl_info.is_mesa_driver = FALSE;
00374     if (strstr((AL_CONST char*)glGetString(GL_VERSION),"Mesa")) {
00375         AGL_LOG(1, "OpenGL driver based on Mesa\n");
00376         allegro_gl_info.is_mesa_driver = TRUE;
00377     }
00378 
00379     /* Print out GLX version info */
00380     TRACE(PREFIX_I "GLX Version: %d.%d\n", _glxwin.major, _glxwin.minor);
00381 
00382 #ifdef LOGLEVEL
00383     if (glXIsDirect(_xwin.display, _glxwin.ctx)) {
00384         AGL_LOG(1, "GLX Direct Rendering is enabled\n");
00385     }
00386     else {
00387         AGL_LOG(1, "GLX Direct Rendering is disabled\n");
00388     }
00389 #endif
00390 
00391     /* Prints out GLX extensions info */
00392     AGL_LOG(1, "glX Extensions:\n");
00393 #ifdef LOGLEVEL
00394     __allegro_gl_print_extensions(
00395         (AL_CONST char*)glXQueryExtensionsString(_xwin.display, _xwin.screen));
00396 #endif
00397     /* Prints out OpenGL extensions info and activates needed extensions */
00398     __allegro_gl_manage_extensions();
00399     
00400     /* Update screen vtable in order to use AGL's */
00401     __allegro_gl__glvtable_update_vtable (&allegro_gl_screen->vtable);
00402     memcpy(&_screen_vtable, allegro_gl_screen->vtable, sizeof(GFX_VTABLE));
00403     allegro_gl_screen->vtable = &_screen_vtable;
00404 
00405     XUNLOCK();
00406 
00407     if (_keyboard_was_installed) {
00408         TRACE(PREFIX_I "x_create_screen: Installing Keyboard...\n");
00409         install_keyboard();
00410     }
00411 
00412     if (_mouse_was_installed) {
00413         TRACE(PREFIX_I "x_create_screen: Installing Mouse...\n");
00414         install_mouse();
00415     }
00416     gfx_capabilities |= GFX_HW_CURSOR;
00417 
00418     return allegro_gl_screen;
00419 
00420 failure:
00421     if (_keyboard_was_installed) {
00422         install_keyboard();
00423     }
00424 
00425     if (_mouse_was_installed) {
00426         install_mouse();
00427     }
00428 
00429     return NULL;
00430 }
00431 
00432 
00433 
00434 /* allegro_gl_x_windowed_init:
00435  *  Creates screen bitmap for windowed driver.
00436  */
00437 static BITMAP *allegro_gl_x_windowed_init(int w, int h, int vw, int vh,
00438                                           int depth)
00439 {
00440     return allegro_gl_x_create_screen(w, h, vw, vh, depth, FALSE);
00441 }
00442 
00443 
00444 
00445 /* allegro_gl_x_fullscreen_init:
00446  *  Creates screen bitmap for fullscreen driver.
00447  */
00448 static BITMAP *allegro_gl_x_fullscreen_init(int w, int h, int vw, int vh,
00449                                             int depth)
00450 {
00451     return allegro_gl_x_create_screen(w, h, vw, vh, depth, TRUE);
00452 }
00453 
00454 
00455 
00456 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00457 /* free_modelines:
00458  *  Free mode lines.
00459  */
00460 static void free_modelines(XF86VidModeModeInfo **modesinfo, int num_modes)
00461 {
00462    int i;
00463 
00464    for (i = 0; i < num_modes; i++)
00465       if (modesinfo[i]->privsize > 0)
00466      XFree(modesinfo[i]->private);
00467    XFree(modesinfo);
00468 }
00469 #endif
00470 
00471 
00472 
00473 /* allegro_gl_x_exit:
00474  *  Shuts down the driver (shared between windowed and full-screen)
00475  */
00476 static void allegro_gl_x_exit(BITMAP *bmp)
00477 {
00478 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00479     XSetWindowAttributes setattr;
00480 #endif
00481 
00482     XLOCK();
00483     /* We politely wait for OpenGL to finish its current operations before
00484        shutting down the driver */
00485     glXWaitGL();
00486 
00487     __allegro_gl_unmanage_extensions(); 
00488 
00489     if (_glxwin.ctx) {
00490         if (!allegro_gl_info.is_ati_r200_chip) {
00491             /* The DRI drivers for ATI cards with R200 chip
00492              * seem to be broken since they crash at this point.
00493              * As a workaround AGL does not release the GLX context
00494              * here. This should not hurt since the GLX specs don't
00495              * require the context to be released before the program
00496              * ends or before another context is made current to the
00497              * thread.
00498              */
00499             if (!glXMakeCurrent(_xwin.display, None, NULL)) {
00500                 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
00501                           get_config_text ("Could not release drawing context.\n"));
00502             }
00503         }
00504 
00505         glXDestroyContext(_xwin.display, _glxwin.ctx);
00506         _glxwin.ctx = NULL;
00507     }
00508 
00509     if (_xwin.mouse_grabbed) {
00510         XUngrabPointer(_xwin.display, CurrentTime);
00511         _xwin.mouse_grabbed = 0;
00512     }
00513 
00514     if (_xwin.keyboard_grabbed) {
00515         XUngrabKeyboard(_xwin.display, CurrentTime);
00516         _xwin.keyboard_grabbed = 0;
00517     }
00518 
00519 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00520     if (_glxwin.fullscreen) {
00521         if (_xwin.mode_switched) {
00522             XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, False);
00523             XF86VidModeSwitchToMode(_xwin.display, _xwin.screen,
00524                                     _xwin.modesinfo[0]);
00525             XF86VidModeSetViewPort(_xwin.display, _xwin.screen, 0, 0);
00526             _xwin.mode_switched = 0;
00527         }
00528         if (_xwin.override_redirected) {
00529             setattr.override_redirect = False;
00530             XChangeWindowAttributes(_xwin.display, _xwin.window,
00531                                     CWOverrideRedirect, &setattr);
00532             _xwin.override_redirected = 0;
00533         }
00534 
00535         /* Free modelines.  */
00536         free_modelines(_xwin.modesinfo, _xwin.num_modes);
00537         _xwin.num_modes = 0;
00538         _xwin.modesinfo = NULL;
00539     }
00540 #endif
00541 
00542     /* Note: Allegro will destroy screen (== allegro_gl_screen),
00543      * so don't destroy it here.
00544      */
00545     //destroy_bitmap(allegro_gl_screen);
00546     ASSERT(allegro_gl_screen == screen);
00547     allegro_gl_screen = NULL;
00548 
00549     /* Unmap the window in order not to see the cursor when quitting.
00550        The window *must not* be destroyed and _xwin.visual must be left
00551        to its current value otherwise the program will crash when exiting */
00552     if (_xwin.window != None)
00553         XUnmapWindow(_xwin.display, _xwin.window);
00554 
00555     if (_glxwin.use_glx_window) {
00556         glXDestroyWindow(_xwin.display, _glxwin.window);
00557         _glxwin.window = 0;
00558         _glxwin.use_glx_window = FALSE;
00559     }
00560 
00561     __allegro_gl_valid_context = FALSE;
00562 
00563     _xwin_window_redrawer = old_window_redrawer;
00564     XSetErrorHandler(old_x_error_handler);
00565 
00566 
00567 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
00568     /* Hack: Allegro 4.2.1 uses a persistent window, we need to restore it. */
00569     if (backup_allegro_window != None) {
00570         if (_xwin.colormap != None) {
00571             XUninstallColormap(_xwin.display, _xwin.colormap);
00572             XFreeColormap(_xwin.display, _xwin.colormap);
00573         }
00574         _xwin.colormap = backup_allegro_colormap;
00575 
00576         if (_xwin.window != None)
00577             XDestroyWindow(_xwin.display, _xwin.window);
00578         _xwin.window = backup_allegro_window;
00579         backup_allegro_window = None;
00580         XMapWindow(_xwin.display, _xwin.window);
00581     }
00582 #endif
00583 
00584     XUNLOCK();
00585 }
00586 
00587 
00588 
00589 /* get_shift:
00590  *  Returns the shift value for a given mask.
00591  */
00592 static int get_shift (int mask)
00593 {
00594     int i = 0, j = 1;
00595     if (!mask) return -1;
00596     while (!(j & mask)) {
00597         i++;
00598         j <<= 1;
00599     }
00600     return i;
00601 }
00602 
00603 
00604 
00605 static int decode_fbconfig (GLXFBConfig fbc, struct allegro_gl_display_info *i) {
00606     int render_type, visual_type, buffer_size, sbuffers, samples;
00607     int drawable_type, renderable;
00608     XVisualInfo *v;
00609 
00610     TRACE(PREFIX_I "decode_fbconfig: Decoding:\n");
00611     i->rmethod = 2;
00612 
00613     if (glXGetFBConfigAttrib (_xwin.display, fbc, GLX_RENDER_TYPE,
00614                             &render_type)
00615      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_X_RENDERABLE,
00616                             &renderable)
00617      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_DRAWABLE_TYPE,
00618                             &drawable_type)
00619      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_X_VISUAL_TYPE,
00620                             &visual_type)
00621      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_BUFFER_SIZE,
00622                             &buffer_size)
00623      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_DEPTH_SIZE,
00624                             &i->depth_size)
00625      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_STEREO,
00626                             &i->stereo)
00627      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_RED_SIZE,
00628                             &i->pixel_size.rgba.r)
00629      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_GREEN_SIZE,
00630                             &i->pixel_size.rgba.g)
00631      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_BLUE_SIZE,
00632                             &i->pixel_size.rgba.b)
00633      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ALPHA_SIZE,
00634                             &i->pixel_size.rgba.a)
00635      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_DOUBLEBUFFER,
00636                             &i->doublebuffered)
00637      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_AUX_BUFFERS,
00638                             &i->aux_buffers)
00639      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_STENCIL_SIZE,
00640                             &i->stencil_size)
00641      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_RED_SIZE,
00642                             &i->accum_size.rgba.r)
00643      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_GREEN_SIZE,
00644                             &i->accum_size.rgba.g)
00645      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_BLUE_SIZE,
00646                             &i->accum_size.rgba.b)
00647      || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_ALPHA_SIZE,
00648                       &i->accum_size.rgba.a)) {
00649         TRACE(PREFIX_I "decode_fbconfig: Incomplete glX mode ...\n");
00650         return -1;
00651     }
00652 
00653     if (!(render_type & GLX_RGBA_BIT) && !(render_type & GLX_RGBA_FLOAT_BIT)) {
00654         TRACE(PREFIX_I "decode_fbconfig: Not RGBA mode\n");
00655         return -1;
00656     }
00657 
00658     if (!(drawable_type & GLX_WINDOW_BIT)) {
00659         TRACE(PREFIX_I "decode_fbconfig: Cannot render to a window.\n");
00660         return -1;
00661     }
00662     
00663     if (renderable == False) {
00664         TRACE(PREFIX_I "decode_fbconfig: GLX windows not supported.\n");
00665         return -1;
00666     }
00667 
00668     if (visual_type != GLX_TRUE_COLOR && visual_type != GLX_DIRECT_COLOR) {
00669         TRACE(PREFIX_I "decode_fbconfig: visual type other than TrueColor and "
00670                         "DirectColor.\n");
00671         return -1;
00672     }
00673 
00674     /* Floating-point depth is not supported as glx extension (yet). */
00675     i->float_depth = 0;
00676 
00677     i->float_color = (render_type & GLX_RGBA_FLOAT_BIT);
00678 
00679     v = glXGetVisualFromFBConfig(_xwin.display, fbc);
00680     if (!v) {
00681         TRACE(PREFIX_I "decode_fbconfig: Cannot get associated visual for the "
00682                         "FBConfig.\n");
00683         return -1;
00684     }
00685     i->r_shift = get_shift (v->red_mask);
00686     i->g_shift = get_shift (v->green_mask);
00687     i->b_shift = get_shift (v->blue_mask);
00688     i->a_shift = 0;
00689 
00690     /* If we are going to need to setup a palette we need bit shifts */
00691     if ((visual_type == GLX_DIRECT_COLOR)
00692         && ((i->r_shift == -1) || (i->g_shift == -1) || (i->b_shift == -1))
00693         && (i->pixel_size.rgba.r + i->pixel_size.rgba.g + i->pixel_size.rgba.b
00694            <= 12)) {
00695         /* XXX <rohannessian> Report something here? */
00696         XFree(v);
00697         return -1;
00698     }
00699 
00700     i->colour_depth = 0;
00701 
00702     if (i->pixel_size.rgba.r == 3
00703      && i->pixel_size.rgba.g == 3
00704      && i->pixel_size.rgba.b == 2) {
00705         i->colour_depth = 8;
00706     }
00707 
00708     if (i->pixel_size.rgba.r == 5
00709      && i->pixel_size.rgba.b == 5) {
00710         if (i->pixel_size.rgba.g == 5) {
00711             i->colour_depth = 15;
00712         }
00713         if (i->pixel_size.rgba.g == 6) {
00714             i->colour_depth = 16;
00715         }
00716     }
00717 
00718     if (i->pixel_size.rgba.r == 8
00719      && i->pixel_size.rgba.g == 8
00720      && i->pixel_size.rgba.b == 8) {
00721         if (i->pixel_size.rgba.a == 0) {
00722             i->colour_depth = 24;
00723         }
00724         if (i->pixel_size.rgba.a == 8) {
00725             i->colour_depth = 32;
00726             /* small hack that tries to guess alpha shifting */
00727             i->a_shift = 48 - i->r_shift - i->g_shift - i->b_shift;
00728         }
00729     }
00730 
00731     i->allegro_format = (i->colour_depth != 0)
00732                      && (i->g_shift == i->pixel_size.rgba.b)
00733                      && (i->r_shift * i->b_shift == 0)
00734                      && (i->r_shift + i->b_shift
00735                                 == i->pixel_size.rgba.b + i->pixel_size.rgba.g);
00736 
00737     if (glXGetConfig(_xwin.display, v, GLX_SAMPLE_BUFFERS, &sbuffers)) {
00738         /* Multisample extension is not supported */
00739         i->sample_buffers = 0;
00740     }
00741     else {
00742         i->sample_buffers = sbuffers;
00743     }
00744     if (glXGetConfig(_xwin.display, v, GLX_SAMPLES, &samples)) {
00745         /* Multisample extension is not supported */
00746         i->samples = 0;
00747     }
00748     else {
00749         i->samples = samples;
00750     }
00751 
00752     XFree(v);
00753 
00754     TRACE(PREFIX_I "Color Depth: %i\n", buffer_size);
00755     TRACE(PREFIX_I "RGBA Type: %s point\n", i->float_color ? "floating" : "fixed");
00756     TRACE(PREFIX_I "RGBA: %i.%i.%i.%i\n", i->pixel_size.rgba.r, i->pixel_size.rgba.g,
00757           i->pixel_size.rgba.b, i->pixel_size.rgba.a);
00758     TRACE(PREFIX_I "Accum: %i.%i.%i.%i\n", i->accum_size.rgba.r, i->accum_size.rgba.g,
00759           i->accum_size.rgba.b, i->accum_size.rgba.a);
00760     TRACE(PREFIX_I "DblBuf: %i Zbuf: %i Stereo: %i Aux: %i Stencil: %i\n",
00761           i->doublebuffered, i->depth_size, i->stereo,
00762           i->aux_buffers, i->stencil_size);
00763     TRACE(PREFIX_I "Shift: %i.%i.%i.%i\n", i->r_shift, i->g_shift, i->b_shift,
00764           i->a_shift);
00765     TRACE(PREFIX_I "Sample Buffers: %i Samples: %i\n", i->sample_buffers, i->samples);
00766     TRACE(PREFIX_I "Decoded bpp: %i\n", i->colour_depth);
00767 
00768     return 0;
00769 }
00770 
00771 
00772 
00773 int allegro_gl_x_windowed_choose_fbconfig (GLXFBConfig *ret_fbconfig) {
00774     int num_fbconfigs, i;
00775     GLXFBConfig *fbconfig;
00776     struct allegro_gl_display_info dinfo;
00777 
00778     fbconfig = glXGetFBConfigs (_xwin.display, _xwin.screen, &num_fbconfigs);
00779     if (!fbconfig || !num_fbconfigs)
00780         return FALSE;
00781 
00782     TRACE(PREFIX_I "x_windowed_choose_fbconfig: %i formats.\n", num_fbconfigs);
00783     __allegro_gl_reset_scorer();
00784 
00785     for (i = 0; i < num_fbconfigs; i++) {
00786         TRACE(PREFIX_I "x_windowed_choose_fbconfig: Mode %i\n", i);
00787         if (decode_fbconfig (*(fbconfig + i), &dinfo) != -1) {
00788             __allegro_gl_score_config (i, &dinfo);
00789         }
00790     }
00791 
00792     i = __allegro_gl_best_config();
00793     TRACE(PREFIX_I "x_windowed_choose_fbconfig: Best FBConfig is: %i\n", i);
00794 
00795     if (i < 0) {
00796         XFree(fbconfig);
00797         return FALSE;
00798     }
00799 
00800     *ret_fbconfig = *(fbconfig + i);
00801     XFree(fbconfig);
00802 
00803     return TRUE;
00804 }
00805 
00806 
00807 
00808 /* windowed_choose_visual:
00809  *  Chooses a visual to use.
00810  */
00811 static XVisualInfo *allegro_gl_x_windowed_choose_visual (void)
00812 {
00813     int num_visuals, i;
00814     XVisualInfo *vinfo;
00815     struct allegro_gl_display_info dinfo;
00816     static XVisualInfo ret_vinfo;
00817 
00818     vinfo = XGetVisualInfo (_xwin.display, 0, NULL, &num_visuals);
00819     if (!vinfo) return NULL;
00820     
00821     TRACE(PREFIX_I "x_windowed_choose_visual: %i formats.\n", num_visuals);
00822     __allegro_gl_reset_scorer();
00823 
00824     for (i = 0; i < num_visuals; i++) {
00825         TRACE(PREFIX_I "x_windowed_choose_visual: Mode %i\n", i);
00826         if (decode_visual (vinfo + i, &dinfo) != -1) {
00827             __allegro_gl_score_config (i, &dinfo);
00828         }
00829     }
00830 
00831     i = __allegro_gl_best_config();
00832     TRACE(PREFIX_I "x_windowed_choose_visual: Best config is: %i\n", i);
00833 
00834     if (i < 0) return NULL;
00835 
00836     memcpy (&ret_vinfo, vinfo+i, sizeof ret_vinfo);
00837     XFree (vinfo);
00838 
00839     return &ret_vinfo;
00840 }
00841 
00842 
00843 
00844 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00845 /* get_xf86_modes:
00846  *  Test if the XF86VidMode extension is available and get the gfx modes
00847  *  that can be queried.
00848  */
00849 static int get_xf86_modes(XF86VidModeModeInfo ***modesinfo, int *num_modes)
00850 {
00851     int vid_event_base, vid_error_base;
00852     int vid_major_version, vid_minor_version;
00853 
00854     /* Test for presence of VidMode extension.  */
00855     if (!XF86VidModeQueryExtension(_xwin.display, &vid_event_base,
00856                                    &vid_error_base)
00857      || !XF86VidModeQueryVersion(_xwin.display, &vid_major_version,
00858                                  &vid_minor_version)) {
00859 
00860         ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
00861                   get_config_text("VidMode extension is not supported"));
00862         return -1;
00863     }
00864 
00865     if (!XF86VidModeGetAllModeLines(_xwin.display, _xwin.screen, num_modes,
00866                                     modesinfo)) {
00867         ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
00868                   get_config_text("Can not Get ModeLines"));
00869         return -1;
00870     }
00871 
00872     return 0;
00873 }
00874 #endif
00875 
00876 
00877 static int allegro_gl_x_error_handler(Display *display, XErrorEvent *err_event)
00878 {
00879     char buffer[256];
00880 
00881     XGetErrorText(display, err_event->error_code, buffer, 256);
00882     TRACE(PREFIX_E "%s\n", buffer);
00883     return 0;
00884 }
00885 
00886 
00887 /* create_window:
00888  *  Based on Michael's `_xwin[_private]_create_window' and the xdemos
00889  *  from the Mesa distribution (I don't remember which one).
00890  */
00891 static int allegro_gl_x_create_window (int fullscreen)
00892 {
00893     Window root;
00894     XVisualInfo *visinfo;
00895     XSetWindowAttributes setattr;
00896     unsigned long valuemask = CWBackPixel | CWBorderPixel | CWColormap
00897                             | CWEventMask;
00898     XSizeHints *hints;
00899     GLXFBConfig fbconfig;
00900     int use_fbconfig;
00901 
00902     if (_xwin.display == 0) {
00903         return -2;
00904     }
00905 
00906     old_x_error_handler = XSetErrorHandler(allegro_gl_x_error_handler);
00907 
00908     /* Fill in missing color depth info */
00909     __allegro_gl_fill_in_info();
00910 
00911     use_fbconfig = (_glxwin.major > 1 || (_glxwin.major == 1 && _glxwin.minor >= 3));
00912 
00913     if (use_fbconfig) {
00914         TRACE(PREFIX_I "x_create_window: using FBConfig routines\n");
00915 
00916         if (!allegro_gl_x_windowed_choose_fbconfig(&fbconfig)) {
00917             TRACE(PREFIX_I "x_create_window: Failed using FBConfig, switching "
00918                             "back to VisualInfo routines\n");
00919             use_fbconfig = FALSE;
00920             goto old_choose_visual;
00921         }
00922 
00923         /* Query back FBConfig components */
00924         if (decode_fbconfig(fbconfig, &allegro_gl_display_info)) {
00925             TRACE(PREFIX_E "x_create_window: Cannot decode FBConfig, switching "
00926                             "back to VisualInfo routines\n");
00927             use_fbconfig = FALSE;
00928             goto old_choose_visual;
00929         }
00930 
00931         visinfo = glXGetVisualFromFBConfig(_xwin.display, fbconfig);
00932         if (!visinfo) {
00933             TRACE(PREFIX_I "x_create_window: Failed to convert FBConfig to "
00934                         "visual, switching back to VisualInfo routines\n");
00935             use_fbconfig = FALSE;
00936             goto old_choose_visual;
00937         }
00938     }
00939     else {
00940 old_choose_visual:
00941         TRACE(PREFIX_I "x_create_window: using VisualInfo routines\n");
00942 
00943         /* Find best visual */
00944         visinfo = allegro_gl_x_windowed_choose_visual();
00945         if (!visinfo) {
00946             TRACE(PREFIX_E "x_create_window: Can not get visual.\n");
00947             XSetErrorHandler(old_x_error_handler);
00948             return -2;
00949         }
00950 
00951         /* Query back visual components */
00952         if (decode_visual (visinfo, &allegro_gl_display_info)) {
00953             TRACE(PREFIX_E "x_create_window: Can not decode visual.\n");
00954             XSetErrorHandler(old_x_error_handler);
00955             return -2;
00956         }
00957     }
00958 
00959     /* Log some information about it */
00960     switch (visinfo->class) {
00961         case TrueColor:
00962             AGL_LOG (1, "x.c: visual class: TrueColor\n");
00963             break;
00964         case DirectColor:
00965             AGL_LOG (1, "x.c: visual class: DirectColor\n");
00966             break;
00967         default:
00968             AGL_LOG (1, "x.c: visual class: invalid(!)\n");
00969     }
00970 
00971 
00972     /* Begin window creation. */
00973 
00974 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
00975     /* Hack: For Allegro 4.2.1, we need to keep the existing window. */
00976     if (backup_allegro_window == None) {
00977         backup_allegro_window = _xwin.window;
00978         backup_allegro_colormap = _xwin.colormap;
00979         _xwin.colormap = None;
00980         XUnmapWindow(_xwin.display, _xwin.window);
00981     }
00982     else
00983 #endif
00984         XDestroyWindow (_xwin.display, _xwin.window);
00985 
00986     _xwin.window = None;
00987 
00988     root = RootWindow (_xwin.display, _xwin.screen);
00989 
00990     /* Recreate window. */
00991     setattr.background_pixel = XBlackPixel (_xwin.display, _xwin.screen);
00992     setattr.border_pixel = XBlackPixel (_xwin.display, _xwin.screen);
00993     setattr.colormap = XCreateColormap (_xwin.display, root, visinfo->visual, AllocNone);
00994     setattr.event_mask =
00995         ( KeyPressMask | KeyReleaseMask
00996         | EnterWindowMask | LeaveWindowMask
00997         | FocusChangeMask | ExposureMask
00998         | ButtonPressMask | ButtonReleaseMask | PointerMotionMask
00999         /*| MappingNotifyMask (SubstructureRedirectMask?)*/
01000     );
01001 
01002 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
01003     if (fullscreen) {
01004         int i;
01005         int bestmode = 0;
01006         _xwin.num_modes = 0;
01007         _xwin.modesinfo = NULL;
01008         _glxwin.fullscreen = TRUE;
01009 
01010         if (get_xf86_modes(&_xwin.modesinfo, &_xwin.num_modes)) {
01011             ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
01012                       get_config_text("x_create_window: Can't get"
01013                                       "XF86VidMode info.\n"));
01014             XSetErrorHandler(old_x_error_handler);
01015             return -2;
01016         }
01017 
01018         /* look for mode with requested resolution */
01019         for (i = 0; i < _xwin.num_modes; i++)
01020         {
01021             if ((_xwin.modesinfo[i]->hdisplay == allegro_gl_display_info.w)
01022              && (_xwin.modesinfo[i]->vdisplay == allegro_gl_display_info.h))
01023                 bestmode = i;
01024         }
01025 
01026         setattr.override_redirect = True;
01027         if (!XF86VidModeSwitchToMode(_xwin.display, _xwin.screen,
01028                                      _xwin.modesinfo[bestmode])) {
01029 
01030             ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
01031                       get_config_text("Can not set XF86VidMode mode"));
01032             XSetErrorHandler(old_x_error_handler);
01033             return -1;
01034         }
01035 
01036         XF86VidModeSetViewPort(_xwin.display, _xwin.screen, 0, 0);
01037 
01038         /* Lock Mode switching */
01039         XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, True);
01040         _xwin.mode_switched = 1;
01041 
01042         allegro_gl_display_info.x = 0;
01043         allegro_gl_display_info.y = 0;
01044         allegro_gl_display_info.w = _xwin.modesinfo[bestmode]->hdisplay;
01045         allegro_gl_display_info.h = _xwin.modesinfo[bestmode]->vdisplay;
01046 
01047         valuemask |= CWOverrideRedirect;
01048         _xwin.override_redirected = 1;
01049     }
01050 
01051     _xwin.window = XCreateWindow (
01052         _xwin.display, root,
01053         allegro_gl_display_info.x, allegro_gl_display_info.y,
01054         allegro_gl_display_info.w, allegro_gl_display_info.h, 0,
01055         visinfo->depth,
01056         InputOutput,
01057         visinfo->visual,
01058         valuemask, &setattr
01059     );
01060 
01061 #else //ALLEGROGL_HAVE_XF86VIDMODE
01062     if (fullscreen) {
01063         /* Without Xf86VidMode extension we support only fullscreen modes which
01064          * match current resolution. */
01065         int fs_width  = DisplayWidth(_xwin.display, _xwin.screen);
01066         int fs_height = DisplayHeight(_xwin.display, _xwin.screen);
01067 
01068         if (fs_width  != allegro_gl_display_info.w
01069          || fs_height != allegro_gl_display_info.h) {
01070             TRACE(PREFIX_E "Only desktop resolution fullscreen available.");
01071             ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
01072                 get_config_text("Compiled without Xf86VidMode extension support.\n"
01073                                 "Only desktop resolution fullscreen available."));
01074             XSetErrorHandler(old_x_error_handler);
01075             return -1;
01076         }
01077 
01078         _glxwin.fullscreen = TRUE;
01079 
01080         /* Create the fullscreen window.  */
01081         _xwin.window = XCreateWindow(_xwin.display, root,
01082                                     allegro_gl_display_info.x, allegro_gl_display_info.y,
01083                                     fs_width, fs_height, 0,
01084                                     visinfo->depth,
01085                                     InputOutput,
01086                                     visinfo->visual,
01087                                     valuemask, &setattr);
01088 
01089         /* Map the fullscreen window.  */
01090         XMapRaised(_xwin.display, _xwin.window);
01091 
01092         /* Make sure we got to the top of the window stack.  */
01093         XRaiseWindow(_xwin.display, _xwin.fs_window);
01094     }
01095     else {
01096         _xwin.window = XCreateWindow (
01097             _xwin.display, root,
01098             allegro_gl_display_info.x, allegro_gl_display_info.y,
01099             allegro_gl_display_info.w, allegro_gl_display_info.h, 0,
01100             visinfo->depth,
01101             InputOutput,
01102             visinfo->visual,
01103             valuemask, &setattr
01104         );
01105     }
01106 #endif //ALLEGROGL_HAVE_XF86VIDMODE
01107 
01108     /* Set size and position hints for Window Manager :
01109      * prevents the window to be resized
01110      */
01111     hints = XAllocSizeHints();
01112     if (hints) {
01113         /* This code chunk comes from Allegro's src/x/xwin.c */
01114         hints->flags = PMinSize | PMaxSize | PBaseSize;
01115         hints->min_width  = hints->max_width  = hints->base_width
01116                           = allegro_gl_display_info.w;
01117         hints->min_height = hints->max_height = hints->base_height
01118                           = allegro_gl_display_info.h;
01119 
01120         XSetWMNormalHints(_xwin.display, _xwin.window, hints);
01121         XFree(hints);
01122     }
01123     
01124 
01125     /* Set WM_DELETE_WINDOW atom in WM_PROTOCOLS property
01126      * (to get window_delete requests).
01127      */
01128     {
01129         Atom wm_delete_window = XInternAtom(_xwin.display, "WM_DELETE_WINDOW", False);
01130         XSetWMProtocols(_xwin.display, _xwin.window, &wm_delete_window, 1);
01131     }
01132 
01133     /* Finish off the GLX setup */
01134     if (use_fbconfig)
01135         _glxwin.ctx = glXCreateNewContext (_xwin.display, fbconfig, GLX_RGBA_TYPE, NULL, True);
01136     else
01137         _glxwin.ctx = glXCreateContext (_xwin.display, visinfo, NULL, True);
01138 
01139     if (use_fbconfig) {
01140         _glxwin.window = glXCreateWindow(_xwin.display, fbconfig, _xwin.window, 0); 
01141         if (!_glxwin.window) {
01142             ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
01143                       get_config_text("Cannot create GLX window."));
01144             XSetErrorHandler(old_x_error_handler);
01145             return -1;
01146         }
01147         _glxwin.use_glx_window = TRUE;
01148     }
01149 
01150     if (!_glxwin.ctx) {
01151         ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
01152                   get_config_text("Can not create GLX context."));
01153         XSetErrorHandler(old_x_error_handler);
01154         return -1;
01155     }
01156     else {
01157         Bool ret;
01158 
01159         if (use_fbconfig)
01160             ret = glXMakeContextCurrent(_xwin.display, _glxwin.window, _glxwin.window, _glxwin.ctx);
01161         else
01162             ret = glXMakeCurrent (_xwin.display, _xwin.window, _glxwin.ctx);
01163 
01164         if (!ret) {
01165             ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
01166                       get_config_text("Cannot make GLX context current."));
01167             XSetErrorHandler(old_x_error_handler);
01168             return -1;
01169         }
01170     }
01171 
01172     /* Finish off the Allegro setup */
01173 
01174     /* Get associated visual and window depth (bits per pixel), and
01175      * store window size  */
01176     {
01177         XWindowAttributes getattr;
01178         XGetWindowAttributes(_xwin.display, _xwin.window, &getattr);
01179         _xwin.visual = getattr.visual;
01180         _xwin.window_depth = getattr.depth;
01181         _xwin.window_width = allegro_gl_display_info.w;
01182         _xwin.window_height = allegro_gl_display_info.h;
01183         _xwin.screen_depth = getattr.depth;
01184         _xwin.screen_width = allegro_gl_display_info.w;
01185         _xwin.screen_height = allegro_gl_display_info.h;
01186     }
01187 
01188     /* Destroy the current colormap (if any) */
01189     if (_xwin.colormap != None) {
01190         XUninstallColormap(_xwin.display, _xwin.colormap);
01191         XFreeColormap(_xwin.display, _xwin.colormap);
01192     }
01193 
01194     /* Create and install colormap.  */
01195     if (_xwin.visual->class == DirectColor) {
01196         _xwin.colormap = XCreateColormap(_xwin.display, _xwin.window,
01197                                          _xwin.visual, AllocAll);
01198     }
01199     else { /* must be TrueColor */
01200         _xwin.colormap = XCreateColormap(_xwin.display, _xwin.window,
01201                                          _xwin.visual, AllocNone);
01202     }
01203     XSetWindowColormap(_xwin.display, _xwin.window, _xwin.colormap);
01204     XInstallColormap(_xwin.display, _xwin.colormap);
01205 
01206     /* Setup a palette if needed */
01207     if (_xwin.visual->class == DirectColor) {
01208         XColor color;
01209         int rsize, gsize, bsize;
01210         int rmax, gmax, bmax;
01211         int rshift, gshift, bshift;
01212         int r, g, b;
01213 
01214         AGL_LOG (1, "x.c: Using DirectColor visual, setting palette...\n");
01215 
01216         rsize = 1 << allegro_gl_display_info.pixel_size.rgba.r;
01217         gsize = 1 << allegro_gl_display_info.pixel_size.rgba.g;
01218         bsize = 1 << allegro_gl_display_info.pixel_size.rgba.b;
01219 
01220         rshift = allegro_gl_display_info.r_shift;
01221         bshift = allegro_gl_display_info.b_shift;
01222         gshift = allegro_gl_display_info.g_shift;
01223 
01224         rmax = rsize - 1;
01225         gmax = gsize - 1;
01226         bmax = bsize - 1;
01227 
01228         color.flags = DoRed | DoGreen | DoBlue;
01229         for (r = 0; r < rsize; r++) {
01230             for (g = 0; g < gsize; g++) {
01231                 for (b = 0; b < bsize; b++) {
01232                     color.pixel = (r << rshift) | (g << gshift) | (b << bshift);
01233                     color.red = ((rmax <= 0) ? 0 : ((r * 65535L) / rmax));
01234                     color.green = ((gmax <= 0) ? 0 : ((g * 65535L) / gmax));
01235                     color.blue = ((bmax <= 0) ? 0 : ((b * 65535L) / bmax));
01236                     XStoreColor(_xwin.display, _xwin.colormap, &color);
01237                 }
01238             }
01239         }
01240     }
01241 
01242     /* Configure the window a bit */
01243     {
01244         XClassHint hint;
01245         XWMHints wm_hints;
01246 
01247         /* Set title.  */
01248         XStoreName(_xwin.display, _xwin.window, _xwin.window_title);
01249 
01250         /* Set hints.  */
01251         hint.res_name = _xwin.application_name;
01252         hint.res_class = _xwin.application_class;
01253         XSetClassHint(_xwin.display, _xwin.window, &hint);
01254 
01255         wm_hints.flags = InputHint | StateHint;
01256         wm_hints.input = True;
01257         wm_hints.initial_state = NormalState;
01258 
01259 #ifdef ALLEGRO_XWINDOWS_WITH_XPM
01260         if (allegro_icon) {
01261             wm_hints.flags |= IconPixmapHint | IconMaskHint  | WindowGroupHint;
01262             XpmCreatePixmapFromData(_xwin.display, _xwin.window, allegro_icon,&wm_hints.icon_pixmap, &wm_hints.icon_mask, NULL);
01263         }
01264 #endif
01265 
01266         XSetWMHints(_xwin.display, _xwin.window, &wm_hints);
01267     }
01268 
01269     /* Map window.  */
01270     XMapWindow(_xwin.display, _xwin.window);
01271 
01272 
01273     if (fullscreen) {
01274         AL_CONST char *fc = NULL;
01275         char tmp1[64], tmp2[128];
01276         int c = 0;
01277         int h = allegro_gl_display_info.h;
01278         int w = allegro_gl_display_info.w;
01279         
01280         /* This chunk is disabled by default because of problems on KDE
01281            desktops.  */
01282         fc = get_config_string(uconvert_ascii("graphics", tmp1),
01283             uconvert_ascii("force_centering", tmp2), NULL);
01284         if ((fc) && ((c = ugetc(fc)) != 0) && ((c == 'y') || (c == 'Y')
01285             || (c == '1'))) {
01286             /* Hack: make the window fully visible and center cursor.  */
01287             XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, 0, 0);
01288             XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
01289                          w - 1, 0);
01290             XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
01291                          0, h - 1);
01292             XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
01293                          w - 1, h - 1);
01294         }
01295         XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
01296                      w / 2, h / 2);
01297         XSync(_xwin.display, False);
01298         
01299         /* Grab keyboard and mouse.  */
01300         if (XGrabKeyboard(_xwin.display, _xwin.window, False, GrabModeAsync,
01301             GrabModeAsync, CurrentTime) != GrabSuccess) {
01302             ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
01303                       get_config_text("Can not grab keyboard"));
01304             XSetErrorHandler(old_x_error_handler);
01305             return -1;
01306         }
01307         _xwin.keyboard_grabbed = 1;
01308         
01309         if (XGrabPointer(_xwin.display, _xwin.window, False, 
01310             PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
01311             GrabModeAsync, GrabModeAsync, _xwin.window, None, CurrentTime)
01312          != GrabSuccess) {
01313 
01314             ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
01315                       get_config_text("Can not grab mouse"));
01316             XSetErrorHandler(old_x_error_handler);
01317             return -1;
01318         }
01319         _xwin.mouse_grabbed = 1;
01320     }
01321 
01322 
01323     /* Destroy current cursor (if any) */
01324     if (_xwin.cursor != None) {
01325         XUndefineCursor(_xwin.display, _xwin.window);
01326         XFreeCursor(_xwin.display, _xwin.cursor);
01327     }
01328 
01329     {
01330         /* Create invisible X cursor.  */
01331         Pixmap pixmap = XCreatePixmap(_xwin.display, _xwin.window, 1, 1, 1);
01332         if (pixmap != None) {
01333             GC temp_gc;
01334             XColor color;
01335             XGCValues gcvalues;
01336 
01337             int gcmask = GCFunction | GCForeground | GCBackground;
01338             gcvalues.function = GXcopy;
01339             gcvalues.foreground = 0;
01340             gcvalues.background = 0;
01341             temp_gc = XCreateGC(_xwin.display, pixmap, gcmask, &gcvalues);
01342             XDrawPoint(_xwin.display, pixmap, temp_gc, 0, 0);
01343             XFreeGC(_xwin.display, temp_gc);
01344             color.pixel = 0;
01345             color.red = color.green = color.blue = 0;
01346             color.flags = DoRed | DoGreen | DoBlue;
01347             _xwin.cursor = XCreatePixmapCursor(_xwin.display, pixmap, pixmap,
01348                                                &color, &color, 0, 0);
01349             XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
01350             XFreePixmap(_xwin.display, pixmap);
01351         }
01352         else {
01353             _xwin.cursor = XCreateFontCursor(_xwin.display, _xwin.cursor_shape);
01354             XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
01355         }
01356     }
01357 
01358     /* Wait for the first exposure event. See comment in Allegro's
01359      * xwin.c about why no blocking X11 function is used.
01360      */
01361     while (1) {
01362        XEvent e;
01363        if (XCheckTypedEvent(_xwin.display, Expose, &e)) {
01364           if (e.xexpose.count == 0) break;
01365        }
01366        rest(1);
01367    }
01368 
01369     return 0;
01370 }
01371 
01372 
01373 
01374 static BITMAP *allegro_gl_x_windowed_create_screen (GFX_DRIVER *drv, int w, int h, int depth)
01375 {
01376     BITMAP *bmp;
01377     int is_linear = drv->linear;
01378 
01379     drv->linear = 1;
01380     bmp = _make_bitmap (w, h, 0, drv, depth, 0);
01381     bmp->id = BMP_ID_VIDEO | BMP_ID_MASK;
01382     drv->linear = is_linear;
01383 
01384     if (bmp == 0) {
01385         ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
01386                   get_config_text("Not enough memory"));
01387         return NULL;
01388     }
01389     
01390     drv->w = w;
01391     drv->h = h;
01392 
01393     return bmp;
01394 }
01395 
01396 
01397 
01398 /* decode_visual:
01399  *  Used to read back the information in the visual.  0 = ok.
01400  */
01401 static int decode_visual (XVisualInfo *v, struct allegro_gl_display_info *i)
01402 {
01403     int rgba, buffer_size, use_gl, sbuffers, samples;
01404 
01405     TRACE(PREFIX_I "decode_visual: Decoding:\n");
01406     i->rmethod = 2;
01407 
01408     /* We can only support TrueColor and DirectColor visuals --
01409      * we only support RGBA mode */
01410     if (v->class != TrueColor && v->class != DirectColor)
01411         return -1;
01412 
01413     if (glXGetConfig (_xwin.display, v, GLX_RGBA, &rgba)
01414      || glXGetConfig (_xwin.display, v, GLX_USE_GL,       &use_gl)
01415      || glXGetConfig (_xwin.display, v, GLX_BUFFER_SIZE,  &buffer_size)
01416      || glXGetConfig (_xwin.display, v, GLX_RED_SIZE,     &i->pixel_size.rgba.r)
01417      || glXGetConfig (_xwin.display, v, GLX_GREEN_SIZE,   &i->pixel_size.rgba.g)
01418      || glXGetConfig (_xwin.display, v, GLX_BLUE_SIZE,    &i->pixel_size.rgba.b)
01419      || glXGetConfig (_xwin.display, v, GLX_ALPHA_SIZE,   &i->pixel_size.rgba.a)
01420      || glXGetConfig (_xwin.display, v, GLX_DOUBLEBUFFER, &i->doublebuffered)
01421      || glXGetConfig (_xwin.display, v, GLX_STEREO,       &i->stereo)
01422      || glXGetConfig (_xwin.display, v, GLX_AUX_BUFFERS,  &i->aux_buffers)
01423      || glXGetConfig (_xwin.display, v, GLX_DEPTH_SIZE,   &i->depth_size)
01424      || glXGetConfig (_xwin.display, v, GLX_STENCIL_SIZE, &i->stencil_size)
01425      || glXGetConfig (_xwin.display, v, GLX_ACCUM_RED_SIZE,
01426                       &i->accum_size.rgba.r)
01427      || glXGetConfig (_xwin.display, v, GLX_ACCUM_GREEN_SIZE,
01428                       &i->accum_size.rgba.g)
01429      || glXGetConfig (_xwin.display, v, GLX_ACCUM_BLUE_SIZE,
01430                       &i->accum_size.rgba.b)
01431      || glXGetConfig (_xwin.display, v, GLX_ACCUM_ALPHA_SIZE,
01432                       &i->accum_size.rgba.a)) {
01433         TRACE(PREFIX_I "x_create_window: Incomplete glX mode ...\n");
01434         return -1;
01435     }
01436 
01437     if (!rgba) {
01438         TRACE(PREFIX_I "x_create_window: Not RGBA mode\n");
01439         return -1;
01440     }
01441     
01442     if (!use_gl) {
01443         ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
01444                   get_config_text("OpenGL Unsupported"));
01445         return -1;
01446     }
01447     
01448     i->r_shift = get_shift (v->red_mask);
01449     i->g_shift = get_shift (v->green_mask);
01450     i->b_shift = get_shift (v->blue_mask);
01451     i->a_shift = 0;
01452     
01453     /* If we are going to need to setup a palette we need bit shifts */
01454     if ((v->class == DirectColor)
01455         && ((i->r_shift == -1) || (i->g_shift == -1) || (i->b_shift == -1))
01456         && (i->pixel_size.rgba.r + i->pixel_size.rgba.g + i->pixel_size.rgba.b
01457            <= 12)) {
01458         /* XXX <rohannessian> Report something here? */
01459         return -1;
01460     }
01461 
01462     i->float_color = 0;
01463     i->float_depth = 0;
01464 
01465     i->colour_depth = 0;
01466 
01467     if (i->pixel_size.rgba.r == 3
01468      && i->pixel_size.rgba.g == 3
01469      && i->pixel_size.rgba.b == 2) {
01470         i->colour_depth = 8;
01471     }
01472 
01473     if (i->pixel_size.rgba.r == 5
01474      && i->pixel_size.rgba.b == 5) {
01475         if (i->pixel_size.rgba.g == 5) {
01476             i->colour_depth = 15;
01477         }
01478         if (i->pixel_size.rgba.g == 6) {
01479             i->colour_depth = 16;
01480         }
01481     }
01482 
01483     if (i->pixel_size.rgba.r == 8
01484      && i->pixel_size.rgba.g == 8
01485      && i->pixel_size.rgba.b == 8) {
01486         if (i->pixel_size.rgba.a == 0) {
01487             i->colour_depth = 24;
01488         }
01489         if (i->pixel_size.rgba.a == 8) {
01490             i->colour_depth = 32;
01491             /* small hack that tries to guess alpha shifting */
01492             i->a_shift = 48 - i->r_shift - i->g_shift - i->b_shift;
01493         }
01494     }
01495 
01496     i->allegro_format = (i->colour_depth != 0)
01497                      && (i->g_shift == i->pixel_size.rgba.b)
01498                      && (i->r_shift * i->b_shift == 0)
01499                      && (i->r_shift + i->b_shift
01500                                 == i->pixel_size.rgba.b + i->pixel_size.rgba.g);
01501     
01502     if (glXGetConfig(_xwin.display, v, GLX_SAMPLE_BUFFERS, &sbuffers)
01503                                                          == GLX_BAD_ATTRIBUTE) {
01504         /* Multisample extension is not supported */
01505         i->sample_buffers = 0;
01506     }
01507     else {
01508         i->sample_buffers = sbuffers;
01509     }
01510     if (glXGetConfig(_xwin.display, v, GLX_SAMPLES, &samples)
01511                                                          == GLX_BAD_ATTRIBUTE) {
01512         /* Multisample extension is not supported */
01513         i->samples = 0;
01514     }
01515     else {
01516         i->samples = samples;
01517     }
01518 
01519     
01520     TRACE(PREFIX_I "Color Depth: %i\n", buffer_size);
01521     TRACE(PREFIX_I "RGBA: %i.%i.%i.%i\n", i->pixel_size.rgba.r, i->pixel_size.rgba.g,
01522           i->pixel_size.rgba.b, i->pixel_size.rgba.a);
01523     TRACE(PREFIX_I "Accum: %i.%i.%i.%i\n", i->accum_size.rgba.r, i->accum_size.rgba.g,
01524           i->accum_size.rgba.b, i->accum_size.rgba.a);
01525     TRACE(PREFIX_I "DblBuf: %i Zbuf: %i Stereo: %i Aux: %i Stencil: %i\n",
01526           i->doublebuffered, i->depth_size, i->stereo,
01527           i->aux_buffers, i->stencil_size);
01528     TRACE(PREFIX_I "Shift: %i.%i.%i.%i\n", i->r_shift, i->g_shift, i->b_shift,
01529           i->a_shift);
01530     TRACE(PREFIX_I "Sample Buffers: %i Samples: %i\n", i->sample_buffers, i->samples);
01531     TRACE(PREFIX_I "Decoded bpp: %i\n", i->colour_depth);
01532     
01533     return 0;
01534 }
01535 
01536 
01537 
01538 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
01539 /* allegro_gl_x_fetch_mode_list:
01540  *  Generates a list of valid video modes (made after 
01541  *  _xvidmode_private_fetch_mode_list of Allegro)
01542  */
01543 static GFX_MODE_LIST* allegro_gl_x_fetch_mode_list(void)
01544 {
01545     int num_modes = 0;
01546     XF86VidModeModeInfo **modesinfo = NULL;
01547     GFX_MODE_LIST *mode_list;
01548     int i;
01549 
01550     XLOCK();
01551 
01552     if (get_xf86_modes(&modesinfo, &num_modes)) {
01553         XUNLOCK();
01554         return NULL;
01555     }
01556 
01557     /* Allocate space for mode list.  */
01558     mode_list = malloc(sizeof(GFX_MODE_LIST));
01559     if (!mode_list) {
01560         free_modelines(modesinfo, num_modes);
01561         XUNLOCK();
01562         return NULL;
01563     }
01564 
01565     mode_list->mode = malloc(sizeof(GFX_MODE) * (num_modes + 1));
01566     if (!mode_list->mode) {
01567         free(mode_list);
01568         free_modelines(modesinfo, num_modes);
01569         XUNLOCK();
01570         return NULL;
01571     }
01572 
01573     /* Fill in mode list.  */
01574     for (i = 0; i < num_modes; i++) {
01575         mode_list->mode[i].width = modesinfo[i]->hdisplay;
01576         mode_list->mode[i].height = modesinfo[i]->vdisplay;
01577         /* Since XF86VidMode can not change the color depth of
01578          * the screen, there is no need to define modes for other
01579          * color depth than the desktop's.
01580          */
01581         mode_list->mode[i].bpp = desktop_color_depth();
01582     }
01583 
01584     mode_list->mode[num_modes].width = 0;
01585     mode_list->mode[num_modes].height = 0;
01586     mode_list->mode[num_modes].bpp = 0;
01587     mode_list->num_modes = num_modes;
01588 
01589     free_modelines(modesinfo, num_modes);
01590 
01591     XUNLOCK();
01592     return mode_list;
01593 }
01594 #endif
01595 
01596 
01597 
01598 /* allegro_gl_x_vsync:
01599  *  Wait for a vertical retrace. GLX_SGI_video_sync is needed.
01600  */
01601 static void allegro_gl_x_vsync(void)
01602 {
01603     XLOCK();
01604     if (allegro_gl_extensions_GLX.SGI_video_sync) {
01605         unsigned int count;
01606 
01607         glXGetVideoSyncSGI(&count);
01608         glXWaitVideoSyncSGI(2, (count+1) & 1, &count);
01609     }
01610     XUNLOCK();
01611 }
01612 
01613 
01614 
01615 /******************************/
01616 /* AllegroGL driver functions */
01617 /******************************/
01618 
01619 /* flip:
01620  *  Does a page flip / double buffer copy / whatever it really is.
01621  */
01622 static void flip (void)
01623 {
01624     XLOCK();
01625     if (_glxwin.use_glx_window)
01626         glXSwapBuffers (_xwin.display, _glxwin.window);
01627     else
01628         glXSwapBuffers (_xwin.display, _xwin.window);
01629     XUNLOCK();
01630 }
01631 
01632 
01633 
01634 /* gl_on, gl_off:
01635  *  Switches to/from GL mode.
01636  */
01637 static void gl_on (void)
01638 {
01639 #ifdef OLD_ALLEGRO
01640     DISABLE();
01641 #endif
01642 }
01643 
01644 
01645 
01646 static void gl_off (void)
01647 {
01648 #ifdef OLD_ALLEGRO
01649     ENABLE();
01650     _xwin_handle_input();
01651 #endif
01652 }
01653 
01654 
01655 
01656 /*****************/
01657 /* Driver struct */
01658 /*****************/
01659 
01660 static struct allegro_gl_driver allegro_gl_x = {
01661     flip,
01662     gl_on,
01663     gl_off,
01664     NULL
01665 };
01666