378732a
--- allegro-4.2.0/include/xalleg.h.fullscreen	2004-12-02 02:02:31.000000000 +0100
378732a
+++ allegro-4.2.0/include/xalleg.h	2006-03-03 23:10:18.000000000 +0100
378732a
@@ -124,8 +124,8 @@
378732a
 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
    XF86VidModeModeInfo **modesinfo;
378732a
    int num_modes;
378732a
-   int mode_switched;
378732a
-   int override_redirected;
378732a
+   int mode_switched;       /* only kept around and set for ABI compat */
378732a
+   int override_redirected; /* no longer used, kept for ABI compat */
378732a
 #endif
378732a
 
378732a
    char window_title[1024];
378732a
@@ -139,6 +139,18 @@
378732a
 #endif
378732a
 
378732a
    void (*close_button_callback)(void);
378732a
+   
378732a
+   /* These are at the end of the struct to maintain abi compat with
378732a
+      allegro-4.2.0 (if and only if compiled with the same configuration).
378732a
+      Notice that IMHO apps really shouldnot be using _xwin, but we export it,
378732a
+      so its fair game. */
378732a
+#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
+   XF86VidModeModeInfo *orig_modeinfo;
378732a
+#endif
378732a
+   /* Seperate fullscreen and managed window id's, see
378732a
+      _xwin_private_create_window in src/x/xwin.c for more details. */
378732a
+   Window fs_window;
378732a
+   Window wm_window;
378732a
 } _xwin;
378732a
 
378732a
 
378732a
--- allegro-4.2.0/src/x/xwin.c.fullscreen	2005-10-27 23:23:40.000000000 +0200
378732a
+++ allegro-4.2.0/src/x/xwin.c	2006-03-03 23:52:22.000000000 +0100
378732a
@@ -142,7 +142,12 @@
378732a
    NULL,        /* mutex */
378732a
 #endif
378732a
 
378732a
-   NULL         /* window close hook */
378732a
+   NULL,        /* window close hook */
378732a
+#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
+   0,           /* orig_modeinfo */
378732a
+#endif
378732a
+   None,        /* fs_window */
378732a
+   None         /* wm_window */
378732a
 };
378732a
 
378732a
 void *allegro_icon = alex_xpm;
378732a
@@ -199,7 +204,6 @@
378732a
 static void _xwin_private_set_palette_range(AL_CONST PALETTE p, int from, int to);
378732a
 static void _xwin_private_set_window_defaults(void);
378732a
 static void _xwin_private_flush_buffers(void);
378732a
-static void _xwin_private_resize_window(int w, int h);
378732a
 static void _xwin_private_process_event(XEvent *event);
378732a
 static void _xwin_private_set_warped_mouse_mode(int permanent);
378732a
 static void _xwin_private_redraw_window(int x, int y, int w, int h);
378732a
@@ -261,7 +265,8 @@
378732a
 static void _xwin_private_slow_palette_32(int sx, int sy, int sw, int sh);
378732a
 
378732a
 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
-static int _xvidmode_private_set_fullscreen(int w, int h);
378732a
+static void _xvidmode_private_set_fullscreen(int w, int h, int *vidmode_width,
378732a
+   int *vidmode_height);
378732a
 static void _xvidmode_private_unset_fullscreen(void);
378732a
 #endif
378732a
 
378732a
@@ -372,10 +377,31 @@
378732a
    }
378732a
 }
378732a
 
378732a
-
378732a
+/* _xwin_wait_mapped:
378732a
+ * wait for a window to become mapped. (shamelessly borrowed from SDL)
378732a
+ */
378732a
+static void _xwin_wait_mapped(Window win)
378732a
+{
378732a
+   XEvent event;
378732a
+   do {
378732a
+      XMaskEvent(_xwin.display, StructureNotifyMask, &event); 
378732a
+   } while ( (event.type != MapNotify) || (event.xmap.event != win) );
378732a
+}
378732a
 
378732a
 /* _xwin_create_window:
378732a
- *  Wrapper for XCreateWindow.
378732a
+ * We use 3 windows:
378732a
+ * -fs_window (for fullscreen)
378732a
+ * -wm_window (window managed)
378732a
+ * -window    (the real window)
378732a
+ * 2 of which will be created here: wm_window and window. The fullscreen
378732a
+ * window gets (re)created when needed, because reusing it causes trouble see:
378732a
+ * http://sourceforge.net/tracker/index.php?func=detail&aid=1441740&group_id=5665&atid=105665
378732a
+ * The real window uses wm_window as parent initially and will be reparened to
378732a
+ * the (freshly created) fullscreen window when requested and reparented
378732a
+ * back again in screen_destroy.
378732a
+ * 
378732a
+ * Idea / concept of 3 windows borrowed from SDL. But somehow SDL manages
378732a
+ * to reuse the fullscreen window too.
378732a
  */
378732a
 static int _xwin_private_create_window(void)
378732a
 {
378732a
@@ -389,21 +415,23 @@
378732a
 
378732a
    _mouse_on = FALSE;
378732a
 
378732a
-   /* Create window.  */
378732a
+   /* Create the managed window. */
378732a
+   setattr.background_pixel = XBlackPixel(_xwin.display, _xwin.screen);
378732a
    setattr.border_pixel = XBlackPixel(_xwin.display, _xwin.screen);
378732a
-   setattr.event_mask = (KeyPressMask | KeyReleaseMask
378732a
+   setattr.event_mask = (KeyPressMask | KeyReleaseMask | StructureNotifyMask
378732a
 			 | EnterWindowMask | LeaveWindowMask
378732a
 			 | FocusChangeMask | ExposureMask | PropertyChangeMask
378732a
 			 | ButtonPressMask | ButtonReleaseMask | PointerMotionMask
378732a
 			 /*| MappingNotifyMask (SubstructureRedirectMask?)*/);
378732a
-   _xwin.window = XCreateWindow(_xwin.display, XDefaultRootWindow(_xwin.display),
378732a
+   _xwin.wm_window = XCreateWindow(_xwin.display,
378732a
+				XDefaultRootWindow(_xwin.display),
378732a
 				0, 0, 320, 200, 0,
378732a
 				CopyFromParent, InputOutput, CopyFromParent,
378732a
-				CWBorderPixel | CWEventMask, &setattr);
378732a
-
378732a
+				CWBackPixel | CWBorderPixel | CWEventMask,
378732a
+				&setattr);
378732a
 
378732a
    /* Get associated visual and window depth (bits per pixel).  */
378732a
-   XGetWindowAttributes(_xwin.display, _xwin.window, &getattr);
378732a
+   XGetWindowAttributes(_xwin.display, _xwin.wm_window, &getattr);
378732a
    _xwin.visual = getattr.visual;
378732a
    _xwin.window_depth = getattr.depth;
378732a
 
378732a
@@ -411,15 +439,27 @@
378732a
    if ((_xwin.visual->class == PseudoColor)
378732a
        || (_xwin.visual->class == GrayScale)
378732a
        || (_xwin.visual->class == DirectColor))
378732a
-      _xwin.colormap = XCreateColormap(_xwin.display, _xwin.window, _xwin.visual, AllocAll);
378732a
+      _xwin.colormap = XCreateColormap(_xwin.display, _xwin.wm_window, _xwin.visual, AllocAll);
378732a
    else
378732a
-      _xwin.colormap = XCreateColormap(_xwin.display, _xwin.window, _xwin.visual, AllocNone);
378732a
-   XSetWindowColormap(_xwin.display, _xwin.window, _xwin.colormap);
378732a
+      _xwin.colormap = XCreateColormap(_xwin.display, _xwin.wm_window, _xwin.visual, AllocNone);
378732a
+   XSetWindowColormap(_xwin.display, _xwin.wm_window, _xwin.colormap);
378732a
    XInstallColormap(_xwin.display, _xwin.colormap);
378732a
+   
378732a
+   /* Create the real / drawing window (reuses setattr). */
378732a
+   setattr.colormap = _xwin.colormap;
378732a
+   _xwin.window = XCreateWindow(_xwin.display,
378732a
+				_xwin.wm_window,
378732a
+				0, 0, 320, 200, 0,
378732a
+				CopyFromParent, InputOutput, CopyFromParent,
378732a
+				CWBackPixel | CWBorderPixel | CWEventMask |
378732a
+				CWColormap, &setattr);
378732a
 
378732a
+   /* Map the real / drawing window it won't appear untill the parent does */
378732a
+   XMapWindow(_xwin.display, _xwin.window);
378732a
+   
378732a
    /* Set WM_DELETE_WINDOW atom in WM_PROTOCOLS property (to get window_delete requests).  */
378732a
    wm_delete_window = XInternAtom (_xwin.display, "WM_DELETE_WINDOW", False);
378732a
-   XSetWMProtocols (_xwin.display, _xwin.window, &wm_delete_window, 1);
378732a
+   XSetWMProtocols (_xwin.display, _xwin.wm_window, &wm_delete_window, 1);
378732a
 
378732a
    /* Set default window parameters.  */
378732a
    (*_xwin_window_defaultor)();
378732a
@@ -494,6 +534,11 @@
378732a
       XDestroyWindow(_xwin.display, _xwin.window);
378732a
       _xwin.window = None;
378732a
    }
378732a
+
378732a
+   if (_xwin.wm_window != None) {
378732a
+      XDestroyWindow(_xwin.display, _xwin.wm_window);
378732a
+      _xwin.wm_window = None;
378732a
+   }
378732a
 }
378732a
 
378732a
 void _xwin_destroy_window(void)
378732a
@@ -673,10 +718,6 @@
378732a
 static BITMAP *_xwin_private_create_screen(GFX_DRIVER *drv, int w, int h,
378732a
 					   int vw, int vh, int depth, int fullscreen)
378732a
 {
378732a
-#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
-   XSetWindowAttributes setattr;
378732a
-#endif
378732a
-
378732a
    if (_xwin.window == None) {
378732a
       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("No window"));
378732a
       return 0;
378732a
@@ -711,55 +752,48 @@
378732a
       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported color depth"));
378732a
       return 0;
378732a
    }
378732a
-
378732a
-#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
-   /* If we are going fullscreen, disable window decorations.  */
378732a
-   if (fullscreen) {
378732a
-      setattr.override_redirect = True;
378732a
-      XChangeWindowAttributes(_xwin.display, _xwin.window,
378732a
-			      CWOverrideRedirect, &setattr);
378732a
-      _xwin.override_redirected = 1;
378732a
-   }
378732a
-#endif
378732a
-
378732a
-   /* Set window size and save dimensions.  */
378732a
-   _xwin_private_resize_window(w, h);
378732a
+   
378732a
+   /* Save dimensions.  */
378732a
+   _xwin.window_width = w;
378732a
+   _xwin.window_height = h;
378732a
    _xwin.screen_width = w;
378732a
    _xwin.screen_height = h;
378732a
    _xwin.screen_depth = depth;
378732a
    _xwin.virtual_width = vw;
378732a
    _xwin.virtual_height = vh;
378732a
 
378732a
-#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
-   if (fullscreen) {
378732a
-      AL_CONST char *fc;
378732a
-      char tmp1[64], tmp2[128];
378732a
-      int i;
378732a
-
378732a
-      /* Switch video mode.  */
378732a
-      if (!_xvidmode_private_set_fullscreen(w, h)) {
378732a
-	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not set video mode"));
378732a
-	 return 0;
378732a
-      }
378732a
+   /* Resize the (real) window */
378732a
+   XResizeWindow(_xwin.display, _xwin.window, w, h);
378732a
 
378732a
-      /* Hack: make the window fully visible and center cursor.  */
378732a
-      XMoveWindow(_xwin.display, _xwin.window, 0, 0);
378732a
-      XF86VidModeSetViewPort(_xwin.display, _xwin.screen, 0, 0);
378732a
-
378732a
-      /* This chunk is disabled by default because of problems on KDE desktops.  */
378732a
-      fc = get_config_string(uconvert_ascii("graphics", tmp1),
378732a
-			     uconvert_ascii("force_centering", tmp2),
378732a
-			     NULL);
378732a
-
378732a
-      if ((fc) && ((i = ugetc(fc)) != 0) && ((i == 'y') || (i == 'Y') || (i == '1'))) {
378732a
-	 XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, 0, 0);
378732a
-	 XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, w - 1, 0);
378732a
-	 XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, 0, h - 1);
378732a
-	 XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, w - 1, h - 1);
378732a
-      }
378732a
+   if (fullscreen) {
378732a
+      XSetWindowAttributes setattr;
378732a
+      /* local width and height vars used for fullscreen window size and for
378732a
+         storing the video_mode size which is then used to center the window */
378732a
+      int fs_width  = DisplayWidth(_xwin.display, _xwin.screen);
378732a
+      int fs_height = DisplayHeight(_xwin.display, _xwin.screen);
378732a
 
378732a
-      XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, w / 2, h / 2);
378732a
-      XSync(_xwin.display, False);
378732a
+      /* Create the fullscreen window */
378732a
+      setattr.override_redirect = True;
378732a
+      setattr.background_pixel = XBlackPixel(_xwin.display, _xwin.screen);
378732a
+      setattr.border_pixel = XBlackPixel(_xwin.display, _xwin.screen);
378732a
+      setattr.event_mask = StructureNotifyMask;
378732a
+      setattr.colormap = _xwin.colormap;
378732a
+      _xwin.fs_window = XCreateWindow(_xwin.display,
378732a
+                                   XDefaultRootWindow(_xwin.display),
378732a
+                                   0, 0, fs_width, fs_height, 0,
378732a
+                                   CopyFromParent, InputOutput,
378732a
+                                   CopyFromParent, CWOverrideRedirect |
378732a
+                                   CWBackPixel | CWColormap | CWBorderPixel |
378732a
+                                   CWEventMask, &setattr);
378732a
+
378732a
+      /* Map the fullscreen window */
378732a
+      XMapRaised(_xwin.display, _xwin.fs_window);
378732a
+      _xwin_wait_mapped(_xwin.fs_window);
378732a
+      /* Make sure we got to the top of the window stack */
378732a
+      XRaiseWindow(_xwin.display, _xwin.fs_window);
378732a
+      
378732a
+      /* Reparent the real window */
378732a
+      XReparentWindow(_xwin.display, _xwin.window, _xwin.fs_window, 0, 0);
378732a
 
378732a
       /* Grab the keyboard and mouse.  */
378732a
       if (XGrabKeyboard(_xwin.display, XDefaultRootWindow(_xwin.display), False,
378732a
@@ -775,8 +809,45 @@
378732a
 	 return 0;
378732a
       }
378732a
       _xwin.mouse_grabbed = 1;
378732a
-   }
378732a
+
378732a
+#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
+      /* Try to switch video mode. This must be done after the pointer is
378732a
+         grabbed, because otherwise it can be outside the window negating the
378732a
+         XF86VidModeSetViewPort done in set_fullscreen. This makes the old
378732a
+         center the window hack unnescesarry. Notice that since the XF86VM
378732a
+         extension requests do not go through the regular X output buffer? We
378732a
+         need to make sure that all above requests are processed first.  */
378732a
+      XSync(_xwin.display, False);
378732a
+      _xvidmode_private_set_fullscreen(w, h, &fs_width, &fs_height);
378732a
 #endif
378732a
+      
378732a
+      /* Center the window (if nescesarry) */
378732a
+      if ((fs_width != w) || (fs_height != h))
378732a
+         XMoveWindow(_xwin.display, _xwin.window, (fs_width - w) / 2,
378732a
+            (fs_height - h) / 2);
378732a
+
378732a
+      /* Last: center the cursor */
378732a
+      XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, w / 2, h / 2);
378732a
+   } else {
378732a
+      XSizeHints *hints = XAllocSizeHints();;
378732a
+
378732a
+      /* Resize managed window.  */
378732a
+      XResizeWindow(_xwin.display, _xwin.wm_window, w, h);
378732a
+      
378732a
+      /* Set size and position hints for Window Manager.  */
378732a
+      if (hints) {
378732a
+         hints->flags = PMinSize | PMaxSize | PBaseSize;
378732a
+         hints->min_width  = hints->max_width  = hints->base_width  = w;
378732a
+         hints->min_height = hints->max_height = hints->base_height = h;
378732a
+         XSetWMNormalHints(_xwin.display, _xwin.wm_window, hints);
378732a
+
378732a
+         XFree(hints);
378732a
+      }
378732a
+      
378732a
+      /* Map the window managed window */
378732a
+      XMapWindow(_xwin.display, _xwin.wm_window);
378732a
+      _xwin_wait_mapped(_xwin.wm_window);
378732a
+   }
378732a
 
378732a
    /* Create XImage with the size of virtual screen.  */
378732a
    if (_xwin_private_create_ximage(vw, vh) != 0) {
378732a
@@ -804,12 +875,6 @@
378732a
    bmp = _xwin_private_create_screen(drv, w, h, vw, vh, depth, fullscreen);
378732a
    if (bmp == 0) {
378732a
       _xwin_private_destroy_screen();
378732a
-      /* Work around a weird bug with some window managers (KWin, Window Maker).  */
378732a
-      if (fullscreen) {
378732a
-	 bmp = _xwin_private_create_screen(drv, w, h, vw, vh, depth, fullscreen);
378732a
-	 if (bmp == 0)
378732a
-	    _xwin_private_destroy_screen();
378732a
-      }
378732a
    }
378732a
    XUNLOCK();
378732a
    return bmp;
378732a
@@ -843,7 +908,6 @@
378732a
 
378732a
    _xwin_private_destroy_ximage();
378732a
 
378732a
-#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
    if (_xwin.mouse_grabbed) {
378732a
       XUngrabPointer(_xwin.display, CurrentTime);
378732a
       _xwin.mouse_grabbed = 0;
378732a
@@ -854,14 +918,8 @@
378732a
       _xwin.keyboard_grabbed = 0;
378732a
    }
378732a
 
378732a
+#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
    _xvidmode_private_unset_fullscreen();
378732a
-
378732a
-   if (_xwin.override_redirected) {
378732a
-      setattr.override_redirect = False;
378732a
-      XChangeWindowAttributes(_xwin.display, _xwin.window,
378732a
-			      CWOverrideRedirect, &setattr);
378732a
-      _xwin.override_redirected = 0;
378732a
-   }
378732a
 #endif
378732a
 
378732a
    /* whack color-conversion blitter */
378732a
@@ -869,8 +927,16 @@
378732a
       _release_colorconv_blitter(blitter_func);
378732a
       blitter_func = NULL;
378732a
    }
378732a
-
378732a
-   XUnmapWindow (_xwin.display, _xwin.window);
378732a
+   
378732a
+   if (_xwin.fs_window != None) {
378732a
+      /* Reparent the real window! */
378732a
+      XReparentWindow(_xwin.display, _xwin.window, _xwin.wm_window, 0, 0);
378732a
+      XUnmapWindow(_xwin.display, _xwin.fs_window);
378732a
+      XDestroyWindow(_xwin.display, _xwin.fs_window);
378732a
+      _xwin.fs_window = None;
378732a
+   }
378732a
+   else
378732a
+      XUnmapWindow (_xwin.display, _xwin.wm_window);
378732a
 
378732a
    (*_xwin_window_defaultor)();
378732a
 }
378732a
@@ -2139,31 +2205,31 @@
378732a
    XpmAttributes attributes;
378732a
 #endif
378732a
 
378732a
-   if (_xwin.window == None)
378732a
+   if (_xwin.wm_window == None)
378732a
       return;
378732a
 
378732a
    /* Set window title.  */
378732a
-   XStoreName(_xwin.display, _xwin.window, _xwin.window_title);
378732a
+   XStoreName(_xwin.display, _xwin.wm_window, _xwin.window_title);
378732a
 
378732a
    /* Set hints.  */
378732a
    hint.res_name = _xwin.application_name;
378732a
    hint.res_class = _xwin.application_class;
378732a
-   XSetClassHint(_xwin.display, _xwin.window, &hint);
378732a
+   XSetClassHint(_xwin.display, _xwin.wm_window, &hint);
378732a
 
378732a
    wm_hints.flags = InputHint | StateHint | WindowGroupHint;
378732a
    wm_hints.input = True;
378732a
    wm_hints.initial_state = NormalState;
378732a
-   wm_hints.window_group = _xwin.window;
378732a
+   wm_hints.window_group = _xwin.wm_window;
378732a
 
378732a
 #ifdef ALLEGRO_XWINDOWS_WITH_XPM
378732a
    if (allegro_icon) {
378732a
       wm_hints.flags |= IconPixmapHint | IconMaskHint;
378732a
       attributes.valuemask = XpmReturnAllocPixels | XpmReturnExtensions;
378732a
-      XpmCreatePixmapFromData(_xwin.display,_xwin.window,allegro_icon,&wm_hints.icon_pixmap,&wm_hints.icon_mask, &attributes);
378732a
+      XpmCreatePixmapFromData(_xwin.display,_xwin.wm_window,allegro_icon,&wm_hints.icon_pixmap,&wm_hints.icon_mask, &attributes);
378732a
    }
378732a
 #endif
378732a
 
378732a
-   XSetWMHints(_xwin.display, _xwin.window, &wm_hints);
378732a
+   XSetWMHints(_xwin.display, _xwin.wm_window, &wm_hints);
378732a
 }
378732a
 
378732a
 
378732a
@@ -2213,41 +2279,6 @@
378732a
 }
378732a
 
378732a
 
378732a
-
378732a
-/* _xwin_resize_window:
378732a
- *  Wrapper for XResizeWindow.
378732a
- */
378732a
-static void _xwin_private_resize_window(int w, int h)
378732a
-{
378732a
-   XSizeHints *hints;
378732a
-
378732a
-   if (_xwin.window == None)
378732a
-      return;
378732a
-
378732a
-   /* New window size.  */
378732a
-   _xwin.window_width = w;
378732a
-   _xwin.window_height = h;
378732a
-
378732a
-   /* Resize window.  */
378732a
-   XUnmapWindow(_xwin.display, _xwin.window);
378732a
-   XResizeWindow(_xwin.display, _xwin.window, w, h);
378732a
-   XMapWindow(_xwin.display, _xwin.window);
378732a
-
378732a
-   hints = XAllocSizeHints();
378732a
-   if (hints == 0)
378732a
-      return;
378732a
-
378732a
-   /* Set size and position hints for Window Manager.  */
378732a
-   hints->flags = PMinSize | PMaxSize | PBaseSize;
378732a
-   hints->min_width  = hints->max_width  = hints->base_width  = w;
378732a
-   hints->min_height = hints->max_height = hints->base_height = h;
378732a
-   XSetWMNormalHints(_xwin.display, _xwin.window, hints);
378732a
-
378732a
-   XFree(hints);
378732a
-}
378732a
-
378732a
-
378732a
-
378732a
 /* _xwin_process_event:
378732a
  *  Process one event.
378732a
  */
378732a
@@ -2723,51 +2754,93 @@
378732a
  * Support for XF86VidMode extension.
378732a
  */
378732a
 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
+/* qsort comparison function for sorting the modes */
378732a
+static int cmpmodes(const void *va, const void *vb)
378732a
+{
378732a
+    const XF86VidModeModeInfo *a = *(const XF86VidModeModeInfo **)va;
378732a
+    const XF86VidModeModeInfo *b = *(const XF86VidModeModeInfo **)vb;
378732a
+    if ( a->hdisplay == b->hdisplay )
378732a
+        return b->vdisplay - a->vdisplay;  
378732a
+    else
378732a
+        return b->hdisplay - a->hdisplay;
378732a
+}
378732a
+
378732a
 /* _xvidmode_private_set_fullscreen:
378732a
- *  Attempt to switch video mode and make window fullscreen.
378732a
+ *  Attempt to switch to a better matching video mode.
378732a
+ *  Matching code for non exact match (smallest bigger res) rather shamelessly
378732a
+ *  taken from SDL.
378732a
  */
378732a
-static int _xvidmode_private_set_fullscreen(int w, int h)
378732a
+static void _xvidmode_private_set_fullscreen(int w, int h, int *vidmode_width,
378732a
+   int *vidmode_height)
378732a
 {
378732a
    int vid_event_base, vid_error_base;
378732a
    int vid_major_version, vid_minor_version;
378732a
-   XF86VidModeModeInfo *mode;
378732a
    int i;
378732a
-
378732a
+   
378732a
    /* Test that display is local.  */
378732a
-   if (!_xwin_private_display_is_local()) {
378732a
-      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("VidMode extension requires local display"));
378732a
-      return 0;
378732a
-   }
378732a
+   if (!_xwin_private_display_is_local())
378732a
+      return;
378732a
 
378732a
    /* Test for presence of VidMode extension.  */
378732a
    if (!XF86VidModeQueryExtension(_xwin.display, &vid_event_base, &vid_error_base)
378732a
-       || !XF86VidModeQueryVersion(_xwin.display, &vid_major_version, &vid_minor_version)) {
378732a
-      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("VidMode extension is not supported"));
378732a
-      return 0;
378732a
-   }
378732a
+       || !XF86VidModeQueryVersion(_xwin.display, &vid_major_version, &vid_minor_version))
378732a
+      return;
378732a
 
378732a
    /* Get list of modelines.  */
378732a
    if (!XF86VidModeGetAllModeLines(_xwin.display, _xwin.screen,
378732a
 				   &_xwin.num_modes, &_xwin.modesinfo))
378732a
-      return 0;
378732a
-
378732a
-   /* Search for a matching video mode.  */
378732a
-   for (i = 0; i < _xwin.num_modes; i++) {
378732a
-      mode = _xwin.modesinfo[i];
378732a
-      if ((mode->hdisplay == w) && (mode->vdisplay == h)) {
378732a
-	 /* Switch video mode.  */
378732a
-	 if (!XF86VidModeSwitchToMode(_xwin.display, _xwin.screen, mode))
378732a
-	    return 0;
378732a
+      return;
378732a
 
378732a
-	 /* Lock mode switching.  */
378732a
-	 XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, True);
378732a
+   /* Remember the mode to restore */
378732a
+   _xwin.orig_modeinfo = _xwin.modesinfo[0];
378732a
 
378732a
-	 _xwin.mode_switched = 1;
378732a
-	 return 1;
378732a
-      }
378732a
+   /* Search for an exact matching video mode.  */
378732a
+   for (i = 0; i < _xwin.num_modes; i++) {
378732a
+      if ((_xwin.modesinfo[i]->hdisplay == w) && 
378732a
+          (_xwin.modesinfo[i]->vdisplay == h))
378732a
+         break;
378732a
    }
378732a
 
378732a
-   return 0;
378732a
+   /* Search for a non exact match (smallest bigger res).  */
378732a
+   if (i == _xwin.num_modes) {
378732a
+      int best_width = 0, best_height = 0;
378732a
+      qsort(_xwin.modesinfo, _xwin.num_modes, sizeof(void *), cmpmodes);
378732a
+      for (i = _xwin.num_modes-1; i > 0; i--) {
378732a
+          if ( ! best_width ) {
378732a
+              if ( (_xwin.modesinfo[i]->hdisplay >= w) &&
378732a
+                   (_xwin.modesinfo[i]->vdisplay >= h) ) {
378732a
+                  best_width = _xwin.modesinfo[i]->hdisplay;   
378732a
+                  best_height = _xwin.modesinfo[i]->vdisplay;  
378732a
+              }
378732a
+          } else {
378732a
+              if ( (_xwin.modesinfo[i]->hdisplay != best_width) ||
378732a
+                   (_xwin.modesinfo[i]->vdisplay != best_height) ) {
378732a
+                  i++;
378732a
+                  break;
378732a
+              }
378732a
+          }
378732a
+      }
378732a
+   }
378732a
+      
378732a
+   /* Switch video mode.  */
378732a
+   if ((_xwin.modesinfo[i] == _xwin.orig_modeinfo) ||
378732a
+       !XF86VidModeSwitchToMode(_xwin.display, _xwin.screen,
378732a
+         _xwin.modesinfo[i])) {
378732a
+      *vidmode_width  = _xwin.orig_modeinfo->hdisplay;
378732a
+      *vidmode_height = _xwin.orig_modeinfo->vdisplay;
378732a
+      _xwin.orig_modeinfo = NULL;
378732a
+   } else {
378732a
+      *vidmode_width  = _xwin.modesinfo[i]->hdisplay;
378732a
+      *vidmode_height = _xwin.modesinfo[i]->vdisplay;
378732a
+      /* only kept / set for compatibility with apps which check this */
378732a
+      _xwin.mode_switched = 1;
378732a
+   }
378732a
+   
378732a
+   /* Lock mode switching.  */
378732a
+   XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, True);
378732a
+	 
378732a
+   /* Set viewport. */
378732a
+   XF86VidModeSetViewPort(_xwin.display, _xwin.screen, 0, 0);
378732a
 }
378732a
 
378732a
 
378732a
@@ -2793,13 +2866,15 @@
378732a
 static void _xvidmode_private_unset_fullscreen(void)
378732a
 {
378732a
    if (_xwin.num_modes > 0) {
378732a
-      if (_xwin.mode_switched) {
378732a
-	 /* Unlock mode switching.  */
378732a
-	 XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, False);
378732a
+      /* Unlock mode switching.  */
378732a
+      XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, False);
378732a
 
378732a
+      if (_xwin.orig_modeinfo) {
378732a
 	 /* Restore the original video mode.  */
378732a
-	 XF86VidModeSwitchToMode(_xwin.display, _xwin.screen, _xwin.modesinfo[0]);
378732a
-
378732a
+	 XF86VidModeSwitchToMode(_xwin.display, _xwin.screen,
378732a
+            _xwin.orig_modeinfo);
378732a
+         _xwin.orig_modeinfo = 0;
378732a
+         /* only kept / set for compatibility with apps which check this */
378732a
 	 _xwin.mode_switched = 0;
378732a
       }
378732a
 
378732a
@@ -2809,36 +2884,35 @@
378732a
       _xwin.modesinfo = 0;
378732a
    }
378732a
 }
378732a
+#endif
378732a
 
378732a
 
378732a
 
378732a
-/* _xvidmode_private_fetch_mode_list:
378732a
+/* _xwin_private_fetch_mode_list:
378732a
  *  Generates a list of valid video modes.
378732a
  */
378732a
-static GFX_MODE_LIST *_xvidmode_private_fetch_mode_list(void)
378732a
+static GFX_MODE_LIST *_xwin_private_fetch_mode_list(void)
378732a
 {
378732a
+   int num_modes = 1, num_bpp = 0;
378732a
+   GFX_MODE_LIST *mode_list;
378732a
+   int i, j;
378732a
+#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
+   int has_vidmode = 0;
378732a
    int vid_event_base, vid_error_base;
378732a
    int vid_major_version, vid_minor_version;
378732a
    XF86VidModeModeInfo **modesinfo;
378732a
-   int num_modes, num_bpp;
378732a
-   GFX_MODE_LIST *mode_list;
378732a
-   int i, j;
378732a
-
378732a
-   /* Test that display is local.  */
378732a
-   if (!_xwin_private_display_is_local())
378732a
-      return 0;
378732a
-
378732a
-   /* Test for presence of VidMode extension.  */
378732a
-   if (!XF86VidModeQueryExtension(_xwin.display, &vid_event_base, &vid_error_base)
378732a
-       || !XF86VidModeQueryVersion(_xwin.display, &vid_major_version, &vid_minor_version))
378732a
-      return 0;
378732a
-
378732a
-   /* Get list of modelines.  */
378732a
-   if (!XF86VidModeGetAllModeLines(_xwin.display, _xwin.screen, &num_modes, &modesinfo))
378732a
-      return 0;
378732a
+   
378732a
+         /* Test that display is local.  */
378732a
+   if (  _xwin_private_display_is_local() && 
378732a
+         /* Test for presence of VidMode extension.  */
378732a
+         XF86VidModeQueryExtension(_xwin.display, &vid_event_base, &vid_error_base) &&
378732a
+         XF86VidModeQueryVersion(_xwin.display, &vid_major_version, &vid_minor_version) &&
378732a
+         /* Get list of modelines.  */
378732a
+         XF86VidModeGetAllModeLines(_xwin.display, _xwin.screen, &num_modes, &modesinfo))
378732a
+      has_vidmode = 1;
378732a
+#endif
378732a
 
378732a
    /* Calculate the number of color depths we have to support.  */
378732a
-   num_bpp = 0;
378732a
 #ifdef ALLEGRO_COLOR8
378732a
    num_bpp++;
378732a
 #endif
378732a
@@ -2857,25 +2931,48 @@
378732a
    /* Allocate space for mode list.  */
378732a
    mode_list = malloc(sizeof(GFX_MODE_LIST));
378732a
    if (!mode_list) {
378732a
-      free_modelines(modesinfo, num_modes);
378732a
+#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
+      if (has_vidmode)
378732a
+         free_modelines(modesinfo, num_modes);
378732a
+#endif
378732a
       return 0;
378732a
    }
378732a
 
378732a
    mode_list->mode = malloc(sizeof(GFX_MODE) * ((num_modes * num_bpp) + 1));
378732a
    if (!mode_list->mode) {
378732a
       free(mode_list);
378732a
-      free_modelines(modesinfo, num_modes);
378732a
+#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
+      if (has_vidmode)
378732a
+         free_modelines(modesinfo, num_modes);
378732a
+#endif
378732a
       return 0;
378732a
    }
378732a
 
378732a
    /* Fill in mode list.  */
378732a
    j = 0;
378732a
    for (i = 0; i < num_modes; i++) {
378732a
-#define ADD_MODE(BPP)					    \
378732a
+
378732a
+#define ADD_SCREEN_MODE(BPP)                                                  \
378732a
+      mode_list->mode[j].width  = DisplayWidth(_xwin.display, _xwin.screen);  \
378732a
+      mode_list->mode[j].height = DisplayHeight(_xwin.display, _xwin.screen); \
378732a
+      mode_list->mode[j].bpp = BPP;			                      \
378732a
+      j++
378732a
+#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
+#define ADD_VIDMODE_MODE(BPP)			            \
378732a
       mode_list->mode[j].width = modesinfo[i]->hdisplay;    \
378732a
       mode_list->mode[j].height = modesinfo[i]->vdisplay;   \
378732a
       mode_list->mode[j].bpp = BPP;			    \
378732a
       j++
378732a
+#define ADD_MODE(BPP)                                       \
378732a
+      if (has_vidmode) {                                    \
378732a
+         ADD_VIDMODE_MODE(BPP);                             \
378732a
+      } else {                                              \
378732a
+         ADD_SCREEN_MODE(BPP);                              \
378732a
+      }
378732a
+#else
378732a
+#define ADD_MODE(BPP) ADD_SCREEN_MODE(BPP)
378732a
+#endif
378732a
+
378732a
 #ifdef ALLEGRO_COLOR8
378732a
       ADD_MODE(8);
378732a
 #endif
378732a
@@ -2896,11 +2993,13 @@
378732a
    mode_list->mode[j].bpp = 0;
378732a
    mode_list->num_modes = j;
378732a
 
378732a
-   free_modelines(modesinfo, num_modes);
378732a
+#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
+   if (has_vidmode)
378732a
+      free_modelines(modesinfo, num_modes);
378732a
+#endif
378732a
 
378732a
    return mode_list;
378732a
 }
378732a
-#endif
378732a
 
378732a
 
378732a
 
378732a
@@ -2909,15 +3008,11 @@
378732a
  */
378732a
 GFX_MODE_LIST *_xwin_fetch_mode_list(void)
378732a
 {
378732a
-#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
    GFX_MODE_LIST *list;
378732a
    XLOCK();
378732a
-   list = _xvidmode_private_fetch_mode_list();
378732a
+   list = _xwin_private_fetch_mode_list();
378732a
    XUNLOCK();
378732a
    return list;
378732a
-#else
378732a
-   return 0;
378732a
-#endif
378732a
 }
378732a
 
378732a
 
378732a
--- allegro-4.2.0/src/x/xgfxdrv.c~	2006-03-08 22:47:27.000000000 +0100
378732a
+++ allegro-4.2.0/src/x/xgfxdrv.c	2006-03-08 22:47:27.000000000 +0100
378732a
@@ -61,7 +61,6 @@
378732a
 
378732a
 
378732a
 
378732a
-#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
 static BITMAP *_xwin_fullscreen_gfxdrv_init(int w, int h, int vw, int vh, int color_depth);
378732a
 
378732a
 
378732a
@@ -98,7 +97,6 @@
378732a
    0,
378732a
    FALSE
378732a
 };
378732a
-#endif
378732a
 
378732a
 
378732a
 
378732a
@@ -109,9 +107,7 @@
378732a
    {  GFX_XDGA2,               &gfx_xdga2,           FALSE  },
378732a
    {  GFX_XDGA2_SOFT,          &gfx_xdga2_soft,      FALSE  },
378732a
 #endif
378732a
-#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
    {  GFX_XWINDOWS_FULLSCREEN, &gfx_xwin_fullscreen, TRUE  },
378732a
-#endif
378732a
    {  GFX_XWINDOWS,            &gfx_xwin,            TRUE  },
378732a
    {  0,                       NULL,                 0     }
378732a
 };
378732a
@@ -138,7 +134,6 @@
378732a
 
378732a
 
378732a
 
378732a
-#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
378732a
 /* _xwin_fullscreen_gfxdrv_init:
378732a
  *  Creates screen bitmap (with video mode extension).
378732a
  */
378732a
@@ -146,4 +141,3 @@
378732a
 {
378732a
    return _xwin_create_screen(&gfx_xwin_fullscreen, w, h, vw, vh, color_depth, TRUE);
378732a
 }
378732a
-#endif