AllegroGL: x.c Source File

- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

# 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