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