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

Generated on Sun Dec 3 18:06:50 2006 for AllegroGL by  doxygen 1.5.1