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

Generated on Sun Nov 11 15:52:55 2007 for AllegroGL by  doxygen 1.5.2