AllegroGL: x.c Source File

- Main Page
- Related Pages
- Modules
- Files

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