[AD] Preliminary X11 fullscreen patch

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


I was hoping this would have been good enough to apply tonight to get into 
the upcoming release, but it seems it wasn't meant to be.

I've got the code more or less "done", except for a minor issue. It crashes 
X on my laptop. Program quits cleanly, X dies a horrible death after two 
windows are closed, the allegro system shutsdown, and the program exits. 
After.

At any rate, its getting late, I'm dead tired and can't figure it out. Some 
people on #xorg-devel say they can't get it to crash at all (minus one dude 
on open solaris that found a bug in upath.c causing it to allocate GBs of 
ram and run in an endless loop, I'll apply it tonight).

So if anyone could try and take a look, see if you can't see something 
stupid I've done (I'm sure theres plenty) I'd appreciate it.

Patch attached.

-- 
Thomas Fjellstrom
tfjellstrom@xxxxxxxxxx
Index: include/allegro5/platform/alplatf.h.cmake
===================================================================
--- include/allegro5/platform/alplatf.h.cmake	(revision 13160)
+++ include/allegro5/platform/alplatf.h.cmake	(working copy)
@@ -117,6 +117,9 @@
 /* Define if XF86VidMode extension is supported. */
 #cmakedefine ALLEGRO_XWINDOWS_WITH_XINERAMA
 
+/* Define if XRandR extension is supported. */
+#cmakedefine ALLEGRO_XWINDOWS_WITH_XRANDR
+
 /* Define if XIM extension is supported. */
 #cmakedefine ALLEGRO_XWINDOWS_WITH_XIM
 
Index: include/allegro5/internal/aintern_xglx.h
===================================================================
--- include/allegro5/internal/aintern_xglx.h	(revision 13160)
+++ include/allegro5/internal/aintern_xglx.h	(working copy)
@@ -25,6 +25,10 @@
 #include <X11/extensions/Xinerama.h>
 #endif
 
+#ifdef ALLEGRO_XWINDOWS_WITH_XRANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+
 typedef struct ALLEGRO_SYSTEM_XGLX ALLEGRO_SYSTEM_XGLX;
 typedef struct ALLEGRO_DISPLAY_XGLX ALLEGRO_DISPLAY_XGLX;
 typedef struct ALLEGRO_MOUSE_CURSOR_XGLX ALLEGRO_MOUSE_CURSOR_XGLX;
@@ -53,11 +57,15 @@
 
    #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
    /* For VidMode extension. */
-   int modes_count;
-   XF86VidModeModeInfo **modes;
-   XF86VidModeModeInfo *original_mode;
+   int xfvm_available;
+   int xfvm_screen_count;
+   struct {
+      int mode_count;
+      XF86VidModeModeInfo **modes;
+      XF86VidModeModeInfo *original_mode;
+   } *xfvm_screen;
    #endif
-   
+
    _AL_THREAD thread; /* background thread. */
    _AL_MUTEX lock; /* thread lock for whenever we access internals. */
    // FIXME: One condition variable really would be enough.
@@ -71,6 +79,16 @@
    XineramaScreenInfo *xinerama_screen_info;
    #endif
 
+   #ifdef ALLEGRO_XWINDOWS_WITH_XRANDR
+   int xrandr_available;
+   XRRScreenResources *xrandr_res;
+   // these are technically changeable at runtime if we handle XRandR events.
+   // or more accurately, they can become stale at runtime if we don't handle XRandR events.
+   int xrandr_output_count;
+   XRROutputInfo **xrandr_outputs;
+   XRRModeInfo **xrandr_stored_modes;
+   #endif
+
    /* Keep all decoded X11 visuals around for users to query. */
    bool using_fbc;
    int visuals_count;
@@ -103,10 +121,10 @@
 
    /* Icon for this window. */
    Pixmap icon, icon_mask;
-   
+
    /* Desktop position. */
    int x, y;
-   
+
    /* al_set_mouse_xy implementation */
    bool mouse_warp;
 };
@@ -140,19 +158,50 @@
 /* cursor */
 void _al_xglx_add_cursor_functions(ALLEGRO_DISPLAY_INTERFACE *vt);
 
-/* fullscreen */
-int _al_xglx_get_num_display_modes(void);
+/* fullscreen and multi monitor stuf */
+
+typedef struct _ALLEGRO_XGLX_MMON_INTERFACE _ALLEGRO_XGLX_MMON_INTERFACE;
+
+struct _ALLEGRO_XGLX_MMON_INTERFACE {
+    int (*get_num_display_modes)(ALLEGRO_SYSTEM_XGLX *s, int adapter);
+    ALLEGRO_DISPLAY_MODE *(*get_display_mode)(ALLEGRO_SYSTEM_XGLX *s, int, int, ALLEGRO_DISPLAY_MODE*);
+    bool (*set_mode)(ALLEGRO_SYSTEM_XGLX *, ALLEGRO_DISPLAY_XGLX *, int, int, int, int);
+    void (*store_mode)(ALLEGRO_SYSTEM_XGLX *);
+    void (*restore_mode)(ALLEGRO_SYSTEM_XGLX *, int);
+    void (*get_display_offset)(ALLEGRO_SYSTEM_XGLX *, int, int *, int *);
+    int (*get_num_adapters)(ALLEGRO_SYSTEM_XGLX *);
+    void (*get_monitor_info)(ALLEGRO_SYSTEM_XGLX *, int, ALLEGRO_MONITOR_INFO *);
+};
+
+extern _ALLEGRO_XGLX_MMON_INTERFACE mmon_interface;
+
+void _al_xsys_xinerama_init(ALLEGRO_SYSTEM_XGLX *s);
+void _al_xsys_xinerama_exit(ALLEGRO_SYSTEM_XGLX *s);
+
+void _al_xsys_xrandr_init(ALLEGRO_SYSTEM_XGLX *s);
+void _al_xsys_xrandr_exit(ALLEGRO_SYSTEM_XGLX *s);
+
+void _al_xsys_xfvm_init(ALLEGRO_SYSTEM_XGLX *s);
+void _al_xsys_xfvm_exit(ALLEGRO_SYSTEM_XGLX *s);
+
+int _al_xglx_get_num_display_modes(ALLEGRO_SYSTEM_XGLX *s, int adapter);
 ALLEGRO_DISPLAY_MODE *_al_xglx_get_display_mode(
-   int index, ALLEGRO_DISPLAY_MODE *mode);
-bool _al_xglx_fullscreen_set_mode(ALLEGRO_SYSTEM_XGLX *s, int w, int h,
+   ALLEGRO_SYSTEM_XGLX *s, int adapter, int index, ALLEGRO_DISPLAY_MODE *mode);
+bool _al_xglx_fullscreen_set_mode(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, int w, int h,
    int format, int refresh_rate);
 void _al_xglx_store_video_mode(ALLEGRO_SYSTEM_XGLX *s);
-void _al_xglx_restore_video_mode(ALLEGRO_SYSTEM_XGLX *s);
-void _al_xglx_free_mode_infos(ALLEGRO_SYSTEM_XGLX *s);
+void _al_xglx_restore_video_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter);
 void _al_xglx_fullscreen_to_display(ALLEGRO_SYSTEM_XGLX *s,
    ALLEGRO_DISPLAY_XGLX *d);
 void _al_xglx_toggle_fullscreen_window(ALLEGRO_DISPLAY *display, bool onoff);
+void _al_xglx_get_display_offset(ALLEGRO_SYSTEM_XGLX *s, int adapter, int *x, int *y);
 
+int _al_xglx_fullscreen_select_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter, int w, int h, int format, int refresh_rate);
+
+void _al_xglx_get_monitor_info(ALLEGRO_SYSTEM_XGLX *s, int adapter, ALLEGRO_MONITOR_INFO *info);
+int _al_xglx_get_num_video_adapters(ALLEGRO_SYSTEM_XGLX *s);
+
+
 /* glx_config */
 void _al_xglx_config_select_visual(ALLEGRO_DISPLAY_XGLX *glx);
 bool _al_xglx_config_create_context(ALLEGRO_DISPLAY_XGLX *glx);
Index: src/display_new.c
===================================================================
--- src/display_new.c	(revision 13160)
+++ src/display_new.c	(working copy)
@@ -1,6 +1,6 @@
-/*         ______   ___    ___ 
- *        /\  _  \ /\_ \  /\_ \ 
- *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___ 
+/*         ______   ___    ___
+ *        /\  _  \ /\_ \  /\_ \
+ *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
@@ -58,18 +58,18 @@
    system = al_get_system_driver();
    driver = system->vt->get_display_driver();
    display = driver->create_display(w, h);
-   
+
    if (!display) {
       ALLEGRO_DEBUG("Failed to create display (NULL)\n");
       return NULL;
    }
-   
+
    display->vertex_cache = 0;
    display->num_cache_vertices = 0;
    display->cache_enabled = false;
    display->vertex_cache_size = 0;
    display->cache_texture = 0;
-   
+
    al_identity_transform(&display->cur_transform);
    _al_initialize_blender(&display->cur_blender);
 
@@ -97,11 +97,11 @@
 #else
    al_clear_to_color(al_map_rgb(0, 0, 0));
 #endif
-   
+
 #ifndef ALLEGRO_IPHONE
    al_flip_display();
 #endif
-   
+
    al_set_window_title(al_get_appname());
 
    return display;
Index: src/x/xfullscreen.c
===================================================================
--- src/x/xfullscreen.c	(revision 13160)
+++ src/x/xfullscreen.c	(working copy)
@@ -2,99 +2,457 @@
 
 ALLEGRO_DEBUG_CHANNEL("display")
 
-#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
+_ALLEGRO_XGLX_MMON_INTERFACE mmon_interface;
 
-static int check_xf86_vidmode_ext(ALLEGRO_SYSTEM_XGLX *s)
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+
+void _al_xsys_xinerama_init(ALLEGRO_SYSTEM_XGLX *s)
 {
-   int x, y;
+   int event_base = 0;
+   int error_base = 0;
 
-   return XF86VidModeQueryExtension(s->gfxdisplay, &x, &y)
-      && XF86VidModeQueryVersion(s->gfxdisplay, &x, &y);
+   /* init xinerama info to defaults */
+   s->xinerama_available = 0;
+   s->xinerama_screen_count = 0;
+   s->xinerama_screen_info = NULL;
+
+   _al_mutex_lock(&s->lock);
+
+   if (XineramaQueryExtension(s->x11display, &event_base, &error_base)) {
+      int minor_version = 0, major_version = 0;
+      int status = XineramaQueryVersion(s->x11display, &major_version, &minor_version);
+      ALLEGRO_INFO("Xinerama version: %i.%i\n", major_version, minor_version);
+
+      if (status && !XineramaIsActive(s->x11display)) {
+         ALLEGRO_WARN("Xinerama is not active\n");
+      }
+      else {
+         s->xinerama_screen_info = XineramaQueryScreens(s->x11display, &s->xinerama_screen_count);
+         if(!s->xinerama_screen_info) {
+            ALLEGRO_ERROR("Xinerama failed to query screens.\n");
+         }
+         else {
+            s->xinerama_available = 1;
+            ALLEGRO_INFO("Xinerama is active\n");
+         }
+      }
+   }
+
+   if(!s->xinerama_available) {
+      ALLEGRO_WARN("Xinerama extension is not available.\n");
+   }
+
+   _al_mutex_unlock(&s->lock);
 }
 
-static int get_num_display_modes(ALLEGRO_SYSTEM_XGLX *s)
+void _al_xsys_xinerama_exit(ALLEGRO_SYSTEM_XGLX *s)
 {
-   if (!check_xf86_vidmode_ext(s))
-      return 0;
+   if (!s->xinerama_available)
+      return;
 
-   if (!XF86VidModeGetAllModeLines(s->gfxdisplay, 0, &s->modes_count, &s->modes))
-      return 0;
+   ALLEGRO_DEBUG("xfullscreen: xinerama exit.\n");
+   if (s->xinerama_screen_info)
+      XFree(s->xinerama_screen_info);
 
-   return s->modes_count;
+   s->xinerama_available = 0;
+   s->xinerama_screen_count = 0;
+   s->xinerama_screen_info = NULL;
 }
 
-int _al_xglx_get_num_display_modes(void)
+#else
+void _al_xsys_xinerama_init(ALLEGRO_SYSTEM_XGLX *s) { (void)s; }
+void _al_xsys_xinerama_exit(ALLEGRO_SYSTEM_XGLX *s) { (void)s; }
+#endif /* ALLEGRO_XWINDOWS_WITH_XINERAMA */
+
+#ifdef ALLEGRO_XWINDOWS_WITH_XRANDR
+
+static bool _al_xsys_xrandr_query(ALLEGRO_SYSTEM_XGLX *s)
 {
-   return get_num_display_modes((void *)al_get_system_driver());
+   XRRScreenResources *res = NULL;
+   bool ret = 0;
+
+   if(s->xrandr_res) {
+      XRRFreeScreenResources(s->xrandr_res);
+   }
+
+   if(s->xrandr_outputs) {
+      int i;
+      for(i = 0; i < s->xrandr_output_count; i++) {
+         XRRFreeOutputInfo(s->xrandr_outputs[i]);
+         s->xrandr_outputs[i] = NULL;
+      }
+      free(s->xrandr_outputs);
+      s->xrandr_outputs = NULL;
+      s->xrandr_output_count = 0;
+   }
+
+   res = s->xrandr_res = XRRGetScreenResources (s->x11display, XRootWindow(s->x11display, DefaultScreen(s->x11display)));
+   if(res && res->nmode) {
+      s->xrandr_output_count = 0; // just in case
+
+      // XXX this may not behave correctly if there are any cloned outputs
+      int ncrtc;
+      for(ncrtc = 0; ncrtc < res->ncrtc; ncrtc++) {
+         XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, res, res->crtcs[ncrtc]);
+         if(!crtc_info) {
+            ALLEGRO_WARN("xrandr: failed to fetch crtc %i\n", ncrtc);
+            continue;
+         }
+
+         ALLEGRO_DEBUG("xrandr: got crtc %d.\n", ncrtc);
+
+         if(crtc_info->noutput > 0) {
+            XRROutputInfo **new_output_info = s->xrandr_outputs;
+            int new_output_count = s->xrandr_output_count + crtc_info->noutput;
+
+            new_output_info = realloc(new_output_info, sizeof(XRROutputInfo *) * new_output_count);
+            if(new_output_info) {
+               memset(new_output_info+s->xrandr_output_count, 0, sizeof(XRROutputInfo*)*crtc_info->noutput);
+
+               int nout;
+               for(nout = 0; nout < crtc_info->noutput; nout++) {
+                  XRROutputInfo *info = XRRGetOutputInfo(s->x11display, res, crtc_info->outputs[nout]);
+                  if(!info) {
+                     ALLEGRO_WARN("xrandr: failed to fetch output %i for crtc %i\n", nout, ncrtc);
+                     continue;
+                  }
+
+                  ALLEGRO_DEBUG("xrandr: added new output[%d].\n", s->xrandr_output_count + nout);
+                  new_output_info[s->xrandr_output_count + nout] = info;
+               }
+
+               s->xrandr_outputs = new_output_info;
+               s->xrandr_output_count = new_output_count;
+
+            }
+            else {
+               ALLEGRO_ERROR("xrandr: failed to allocate array for output structures.\n");
+               continue;
+            }
+         }
+
+         XRRFreeCrtcInfo(crtc_info);
+      }
+
+      if(s->xrandr_output_count > 0) {
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+         if(s->xinerama_available && s->xinerama_screen_count != s->xrandr_output_count) {
+            ALLEGRO_WARN("XRandR and Xinerama seem to disagree on how many screens there are (%i vs %i), going to ignore XRandR.\n", s->xrandr_output_count, s->xinerama_screen_count);
+            ret = 0;
+         }
+         else
+#else
+         // XXX verify xrandr isn't borked here because of stupidity
+         // XXX  like the nvidia binary driver only implementing XRandR 1.1
+#endif
+         {
+            ALLEGRO_DEBUG("xrandr: found %d outputs.\n",s->xrandr_output_count);
+            ret = 1;
+         }
+      }
+      else {
+         ALLEGRO_WARN("XRandR has no outputs.\n");
+         ret = 0;
+      }
+   }
+
+   return ret;
 }
 
-static ALLEGRO_DISPLAY_MODE *get_display_mode(ALLEGRO_SYSTEM_XGLX *s,
-   int i, ALLEGRO_DISPLAY_MODE *mode)
+// XXX I think this is supposed to re query Xrandr
+// XXX  that can wait till Xrandr change events are handled by allegro.
+static int _al_xsys_xrandr_get_num_modes(ALLEGRO_SYSTEM_XGLX *s, int adapter)
 {
-   if (!s->modes)
+   if(adapter < 0 || adapter >= s->xrandr_output_count)
+      return 0;
+
+   return s->xrandr_outputs[adapter]->nmode;
+}
+
+static ALLEGRO_DISPLAY_MODE *_al_xsys_xrandr_get_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter, int id, ALLEGRO_DISPLAY_MODE *mode)
+{
+   XRRModeInfo *mi = NULL;
+
+   int i;
+   for(i = 0; i < s->xrandr_res->nmode; i++) {
+      if(s->xrandr_res->modes[i].id == s->xrandr_outputs[adapter]->modes[id]) {
+         mi = &s->xrandr_res->modes[i];
+         break;
+      }
+   }
+
+   if(!mi)
       return NULL;
 
-   mode->width = s->modes[i]->hdisplay;
-   mode->height = s->modes[i]->vdisplay;
+   mode->width = mi->width;
+   mode->height = mi->height;
    mode->format = 0;
-   mode->refresh_rate = 0;
+   if (mi->hTotal && mi->vTotal) {
+      mode->refresh_rate = ((float) mi->dotClock / ((float) mi->hTotal * (float) mi->vTotal));
+   }
+   else {
+      mode->refresh_rate = 0;
+   }
 
+   ALLEGRO_INFO("XRandR got mode: %dx%d@xxxxxxxxxx", mode->width, mode->height, mode->refresh_rate);
+
    return mode;
 }
 
-ALLEGRO_DISPLAY_MODE *_al_xglx_get_display_mode(
-   int i, ALLEGRO_DISPLAY_MODE *mode)
+static bool _al_xsys_xrandr_set_mode(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, int w, int h, int format, int refresh)
 {
-   return get_display_mode((void *)al_get_system_driver(), i, mode);
+   int mode_idx = -1;
+   XRRModeInfo *mi = NULL;
+
+   mode_idx = _al_xglx_fullscreen_select_mode(s, d->xscreen, w, h, format, refresh);
+   if(mode_idx == -1)
+      return false;
+
+   mi = &s->xrandr_res->modes[mode_idx];
+
+   _al_mutex_lock(&s->lock);
+
+   // grab the Crtc info so we can get the info we ARENT changing to pass back to SetCrtcConfig
+   XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, s->xrandr_res, s->xrandr_outputs[d->xscreen]->crtc);
+
+   // actually changes the mode, what a name.
+   // XXX actually check for failure...
+   int ok = XRRSetCrtcConfig(s->x11display, s->xrandr_res,
+                    s->xrandr_outputs[d->xscreen]->crtc,
+                    // proves to XRandR that our info is up to date, or it'll just ignore us
+                    crtc_info->timestamp,
+                    // we don't want to change any of the config prefixed by crtc_info
+                    crtc_info->x,
+                    crtc_info->y,
+                    mi->id, // Set the Mode!
+                    crtc_info->rotation,
+                    crtc_info->outputs,
+                    crtc_info->noutput);
+
+   XRRFreeCrtcInfo(crtc_info);
+   _al_mutex_unlock(&s->lock);
+
+   if(!ok) {
+      ALLEGRO_ERROR("XRandR failed to set mode.\n");
+      return false;
+   }
+
+   return true;
 }
 
-bool _al_xglx_fullscreen_set_mode(ALLEGRO_SYSTEM_XGLX *s,
-   int w, int h, int format, int refresh_rate)
+static void _al_xsys_xrandr_store_modes(ALLEGRO_SYSTEM_XGLX *s)
 {
-   /* GCC complains about mode being uninitialized without this: */
-   ALLEGRO_DISPLAY_MODE mode = mode; 
-   ALLEGRO_DISPLAY_MODE mode2;
+   free(s->xrandr_stored_modes);
+   s->xrandr_stored_modes = calloc(s->xrandr_output_count, sizeof(XRRModeInfo*));
+   if(!s->xrandr_stored_modes) {
+      ALLEGRO_ERROR("XRandR failed to allocate memory for stored modes array.\n");
+      return;
+   }
+
+   // XXX this might be better placed in xrandr_query, it'd save a bunch of XRRGetCrtcInfo calls.
    int i;
-   int n;
+   for(i = 0; i < s->xrandr_output_count; i++) {
+      XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, s->xrandr_res, s->xrandr_outputs[i]->crtc);
 
-   n = get_num_display_modes(s);
-   if (!n)
-      return false;
+      int j;
+      for(j = 0; j < s->xrandr_res->nmode; j++) {
+         if(s->xrandr_res->modes[j].id == crtc_info->mode) {
+            s->xrandr_stored_modes[i] = &s->xrandr_res->modes[j];
+         }
+      }
 
-   /* Find all modes with correct parameters. */
-   int possible_modes[n];
-   int possible_count = 0;
-   for (i = 0; i < n; i++) {
-      if (!get_display_mode(s, i, &mode)) {
-         continue;
+      XRRFreeCrtcInfo(crtc_info);
+
+      if(!s->xrandr_stored_modes[i]) {
+         ALLEGRO_WARN("XRandR failed to store mode for adapter %d.\n", i);
       }
-      if (mode.width == w && mode.height == h &&
-         (format == 0 || mode.format == format) &&
-         (refresh_rate == 0 || mode.refresh_rate == refresh_rate))
-      {
-         possible_modes[possible_count++] = i;
-      }
    }
-   if (!possible_count)
-      return false;
+}
 
-   /* Choose mode with highest refresh rate. */
-   int best_mode = possible_modes[0];
-   get_display_mode(s, best_mode, &mode);
-   for (i = 1; i < possible_count; i++) {
-      if (!get_display_mode(s, possible_modes[i], &mode2))  {
-         continue;
+static void _al_xsys_xrandr_restore_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter)
+{
+   ASSERT(s->xrandr_stored_modes[adapter]);
+   ALLEGRO_DEBUG("xfullscreen: _al_xsys_xrandr_restore_mode (%d, %d)\n",
+                 s->xrandr_stored_modes[adapter]->width, s->xrandr_stored_modes[adapter]->height);
+
+   XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, s->xrandr_res, s->xrandr_outputs[adapter]->crtc);
+   if(!crtc_info) {
+      ALLEGRO_ERROR("xfullscreen: XRRGetCrtcInfo failed.\n");
+      return;
+   }
+
+   if(s->xrandr_stored_modes[adapter]->width == crtc_info->width &&
+      s->xrandr_stored_modes[adapter]->height == crtc_info->height) {
+      ALLEGRO_INFO("xfullscreen: mode already restored.\n");
+      return;
+   }
+   // actually changes the mode, what a name.
+   int ok = XRRSetCrtcConfig(s->x11display,
+                    s->xrandr_res,
+                    s->xrandr_outputs[adapter]->crtc,
+                    // proves to XRandR that our info is up to date, or it'll just ignore us
+                    crtc_info->timestamp,
+                    // we don't want to change any of the config prefixed by crtc_info
+                    crtc_info->x,
+                    crtc_info->y,
+                    s->xrandr_stored_modes[adapter]->id, // Set the Mode!
+                    crtc_info->rotation,
+                    crtc_info->outputs,
+                    crtc_info->noutput);
+
+   XRRFreeCrtcInfo(crtc_info);
+
+   if(!ok) {
+      ALLEGRO_ERROR("XRandR failed to restore mode.\n");
+   }
+
+   XFlush(s->x11display);
+}
+
+static void _al_xsys_xrandr_get_display_offset(ALLEGRO_SYSTEM_XGLX *s, int adapter, int *x, int *y)
+{
+   XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, s->xrandr_res, s->xrandr_outputs[adapter]->crtc);
+   if(!crtc_info) {
+      ALLEGRO_ERROR("XRandR failed to get CrtcInfo, can't get display offset.\n");
+      return;
+   }
+
+   *x = crtc_info->x;
+   *y = crtc_info->y;
+   XRRFreeCrtcInfo(crtc_info);
+}
+
+static int _al_xsys_xrandr_get_num_adapters(ALLEGRO_SYSTEM_XGLX *s)
+{
+   return s->xrandr_output_count;
+}
+
+static void _al_xsys_xrandr_get_monitor_info(ALLEGRO_SYSTEM_XGLX *s, int adapter, ALLEGRO_MONITOR_INFO *monitor_info)
+{
+   XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, s->xrandr_res, s->xrandr_outputs[adapter]->crtc);
+   if(!crtc_info) {
+      ALLEGRO_ERROR("XRandR failed to get CrtcInfo, can't get monitor info.\n");
+      return;
+   }
+
+   monitor_info->x1 = crtc_info->x;
+   monitor_info->y1 = crtc_info->y;
+   monitor_info->x2 = crtc_info->x + crtc_info->width;
+   monitor_info->y2 = crtc_info->y + crtc_info->height;
+
+   XRRFreeCrtcInfo(crtc_info);
+}
+
+void _al_xsys_xrandr_init(ALLEGRO_SYSTEM_XGLX *s)
+{
+   int event_base = 0;
+   int error_base = 0;
+
+   /* init xrandr info to defaults */
+   s->xrandr_available = 0;
+   s->xrandr_output_count = 0;
+   s->xrandr_outputs = NULL;
+
+   _al_mutex_lock(&s->lock);
+
+   if (XRRQueryExtension(s->x11display, &event_base, &error_base)) {
+      int minor_version = 0, major_version = 0;
+      int status = XRRQueryVersion(s->x11display, &major_version, &minor_version);
+      ALLEGRO_INFO("XRandR version: %i.%i\n", major_version, minor_version);
+
+      if(!status) {
+         ALLEGRO_WARN("XRandR not available, XRRQueryVersion failed.\n");
       }
-      if (mode2.refresh_rate > mode.refresh_rate) {
-         mode = mode2;
-         best_mode = possible_modes[i];
+      else if(major_version == 1 && minor_version < 2) {
+         /* this is unlikely to happen, unless the user has an ancient Xorg,
+         Xorg will just emulate the latest version and return that
+         instead of what the driver actually supports, stupid. */
+         ALLEGRO_WARN("XRandR not available, unsupported version: %i.%i\n", major_version, minor_version);
       }
+      else {
+         bool ret = _al_xsys_xrandr_query(s);
+         if(ret) {
+            ALLEGRO_INFO("XRandR is active\n");
+            s->xrandr_available = 1;
+         }
+         else {
+            ALLEGRO_INFO("XRandR is not active\n");
+         }
+      }
    }
+   else {
+      ALLEGRO_WARN("XRandR extension is not available.\n");
+   }
 
-   ALLEGRO_INFO("best mode [%d] = (%d, %d)\n", best_mode,
-      s->modes[best_mode]->hdisplay, s->modes[best_mode]->vdisplay);
+   if(s->xrandr_available) {
+      mmon_interface.get_num_display_modes = _al_xsys_xrandr_get_num_modes;
+      mmon_interface.get_display_mode      = _al_xsys_xrandr_get_mode;
+      mmon_interface.set_mode              = _al_xsys_xrandr_set_mode;
+      mmon_interface.store_mode            = _al_xsys_xrandr_store_modes;
+      mmon_interface.restore_mode          = _al_xsys_xrandr_restore_mode;
+      mmon_interface.get_display_offset    = _al_xsys_xrandr_get_display_offset;
+      mmon_interface.get_num_adapters      = _al_xsys_xrandr_get_num_adapters;
+      mmon_interface.get_monitor_info      = _al_xsys_xrandr_get_monitor_info;
+   }
 
-   if (!XF86VidModeSwitchToMode(s->gfxdisplay, 0, s->modes[best_mode])) {
+   _al_mutex_unlock(&s->lock);
+}
+
+void _al_xsys_xrandr_exit(ALLEGRO_SYSTEM_XGLX *s)
+{
+   int i;
+   ALLEGRO_DEBUG("xfullscreen: XRandR exit.\n");
+
+   for(i = 0; i < s->xrandr_output_count; i++) {
+   //   XRRFreeOutputInfo(s->xrandr_outputs[i]);
+   }
+
+   ALLEGRO_ERROR("xfullscreen: XRRFreeScreenResources\n");
+   //if (s->xrandr_res)
+   //   XRRFreeScreenResources(s->xrandr_res);
+
+   free(s->xrandr_outputs);
+   free(s->xrandr_stored_modes);
+
+   s->xrandr_available = 0;
+   s->xrandr_output_count = 0;
+   s->xrandr_outputs = NULL;
+
+   ALLEGRO_ERROR("xfullscreen: XRandR exit fin.\n");
+}
+
+#else
+void _al_xsys_xrandr_init(ALLEGRO_SYSTEM_XGLX *s) { (void)s; }
+void _al_xsys_xrandr_exit(ALLEGRO_SYSTEM_XGLX *s) { (void)s; }
+#endif /* ALLEGRO_XWINDOWS_WITH_XRANDR */
+
+#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
+
+static int _al_xsys_xfvm_get_num_modes(ALLEGRO_SYSTEM_XGLX *s, int adapter)
+{
+   return s->xfvm_screen[adapter].mode_count;
+}
+
+static ALLEGRO_DISPLAY_MODE *_al_xsys_xfvm_get_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter, int i, ALLEGRO_DISPLAY_MODE *mode)
+{
+   mode->width = s->xfvm_screen[adapter].modes[i]->hdisplay;
+   mode->height = s->xfvm_screen[adapter].modes[i]->vdisplay;
+   mode->format = 0;
+   mode->refresh_rate = (s->xfvm_screen[adapter].modes[i]->dotclock * 1000L /
+      ( s->xfvm_screen[adapter].modes[i]->htotal * s->xfvm_screen[adapter].modes[i]->vtotal));
+
+   return mode;
+}
+
+static bool _al_xsys_xfvm_set_mode(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, int w, int h, int format, int refresh_rate)
+{
+   int mode_idx = -1;
+
+   mode_idx = _al_xglx_fullscreen_select_mode(s, d->xscreen, w, h, format, refresh_rate);
+   if(mode_idx == -1)
+      return false;
+
+   if (!XF86VidModeSwitchToMode(s->gfxdisplay, d->xscreen, s->xfvm_screen[d->xscreen].modes[mode_idx])) {
       ALLEGRO_ERROR("xfullscreen: XF86VidModeSwitchToMode failed\n");
       return false;
    }
@@ -102,56 +460,61 @@
    return true;
 }
 
-void _al_xglx_fullscreen_to_display(ALLEGRO_SYSTEM_XGLX *s,
+/* no longer used, remove later when tested
+static void _al_xsys_xfvm_fullscreen_to_display(ALLEGRO_SYSTEM_XGLX *s,
    ALLEGRO_DISPLAY_XGLX *d)
 {
    int x, y;
    Window child;
+   XWindowAttributes xwa;
 
-   /* First, make sure the mouse stays inside the window. */
-   XGrabPointer(s->gfxdisplay, d->window, False,
-      PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
-      GrabModeAsync, GrabModeAsync, d->window, None, CurrentTime);
-   //FIXME: handle possible errors here
-   s->pointer_grabbed = true;
 
+
+   // grab the root window that contains d->window
+   XGetXwindowAttributes(s->gfxdisplay, d->window, &xwa);
    XTranslateCoordinates(s->gfxdisplay, d->window,
-      RootWindow(s->gfxdisplay, d->xscreen), 0, 0, &x, &y, &child);
-   XF86VidModeSetViewPort(s->gfxdisplay, 0, x, y);
+      xwa.root, 0, 0, &x, &y, &child);
+
+   XF86VidModeSetViewPort(s->gfxdisplay, d->xscreen, x, y);
 }
+*/
 
-void _al_xglx_store_video_mode(ALLEGRO_SYSTEM_XGLX *s)
+static void _al_xsys_xfvm_store_video_mode(ALLEGRO_SYSTEM_XGLX *s)
 {
    int n;
-   int i;
 
-   ALLEGRO_DEBUG("xfullscreen: _al_xglx_store_video_mode\n");
+   ALLEGRO_DEBUG("xfullscreen: _al_xsys_xfvm_store_video_mode\n");
 
-   n = get_num_display_modes(s);
-   if (n == 0) {
-      /* XXX what to do here? */
-      return;
-   }
+   // save all original modes
+   int i;
+   for(i = 0; i < s->xfvm_screen_count; i++) {
+      n = _al_xsys_xfvm_get_num_modes(s, i);
+      if (n == 0) {
+         /* XXX what to do here? */
+         continue;
+      }
 
-   s->original_mode = s->modes[0];
+      s->xfvm_screen[i].original_mode = s->xfvm_screen[i].modes[0];
 
-   for (i = 0; i < n; i++) {
-      ALLEGRO_DEBUG("mode[%d] = (%d, %d)\n",
-         i, s->modes[i]->hdisplay, s->modes[i]->vdisplay);
+      int j;
+      for (j = 0; j <  s->xfvm_screen[i].mode_count; j++) {
+         ALLEGRO_DEBUG("xfvm: screen[%d] mode[%d] = (%d, %d)\n",
+            i, j, s->xfvm_screen[i].modes[j]->hdisplay, s->xfvm_screen[i].modes[j]->vdisplay);
+      }
+      ALLEGRO_INFO("xfvm: screen[%d] original mode = (%d, %d)\n",
+         i, s->xfvm_screen[i].original_mode->hdisplay, s->xfvm_screen[i].original_mode->vdisplay);
    }
-   ALLEGRO_INFO("xfullscreen: original mode = (%d, %d)\n",
-      s->original_mode->hdisplay, s->original_mode->vdisplay);
 }
 
-void _al_xglx_restore_video_mode(ALLEGRO_SYSTEM_XGLX *s)
+static void _al_xsys_xfvm_restore_video_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter)
 {
    Bool ok;
 
-   ASSERT(s->original_mode);
-   ALLEGRO_DEBUG("xfullscreen: _al_xglx_restore_video_mode (%d, %d)\n",
-      s->original_mode->hdisplay, s->original_mode->vdisplay);
+   ASSERT(s->xfvm_screen[adapter].original_mode);
+   ALLEGRO_DEBUG("xfullscreen: _al_xsys_xfvm_restore_video_mode (%d, %d)\n",
+      s->xfvm_screen[adapter].original_mode->hdisplay, s->xfvm_screen[adapter].original_mode->vdisplay);
 
-   ok = XF86VidModeSwitchToMode(s->gfxdisplay, 0, s->original_mode);
+   ok = XF86VidModeSwitchToMode(s->gfxdisplay, adapter, s->xfvm_screen[adapter].original_mode);
    if (!ok) {
       ALLEGRO_ERROR("xfullscreen: XF86VidModeSwitchToMode failed\n");
    }
@@ -167,74 +530,271 @@
    XFlush(s->gfxdisplay);
 }
 
-void _al_xglx_free_mode_infos(ALLEGRO_SYSTEM_XGLX *s)
+/* XXX this might replace fullscreen_to_display alltogeter */
+static void _al_xsys_xfvm_get_display_offset(ALLEGRO_SYSTEM_XGLX *s, int adapter, int *x, int *y)
 {
+   int tmp_x = 0, tmp_y = 0;
+
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+   if(s->xinerama_available) {
+      tmp_x = s->xinerama_screen_info[adapter].x_org;
+      tmp_y = s->xinerama_screen_info[adapter].y_org;
+   } else
+#endif
+   /* don't set the output params if function fails */
+   if(!XF86VidModeGetViewPort(s->x11display, adapter, &tmp_x, &tmp_y))
+      return;
+
+   *x = tmp_x;
+   *y = tmp_y;
+}
+
+static int _al_xsys_xfvm_get_num_adapters(ALLEGRO_SYSTEM_XGLX *s)
+{
+   return s->xfvm_screen_count;
+}
+
+void _al_xsys_xfvm_get_monitor_info(ALLEGRO_SYSTEM_XGLX *s, int adapter, ALLEGRO_MONITOR_INFO *mi)
+{
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+   if(s->xinerama_available) {
+      mi->x1 = s->xinerama_screen_info[adapter].x_org;
+      mi->x2 = s->xinerama_screen_info[adapter].y_org;
+      mi->x2 = mi->x1 + s->xinerama_screen_info[adapter].width;
+      mi->y2 = mi->y1 + s->xinerama_screen_info[adapter].height;
+      return;
+   }
+#endif
+
+   XWindowAttributes xwa;
+   Window root;
+
+   _al_mutex_lock(&s->lock);
+   root = RootWindow(s->x11display, adapter);
+   XGetWindowAttributes(s->x11display, root, &xwa);
+   _al_mutex_unlock(&s->lock);
+
+   /* under plain X, each screen has its own origin,
+      and theres no way to figure out orientation
+      or relative position */
+   mi->x1 = 0;
+   mi->y1 = 0;
+   mi->x2 = xwa.width;
+   mi->y2 = xwa.height;
+}
+
+void _al_xsys_xfvm_free_mode_infos(ALLEGRO_SYSTEM_XGLX *s)
+{
+   (void)s; /* noop for xfvm, exit clears everything up */
+}
+
+void _al_xsys_xfvm_init(ALLEGRO_SYSTEM_XGLX *s)
+{
+   int event_base = 0;
+   int error_base = 0;
+
+   /* init xfvm info to defaults */
+   s->xfvm_available = 0;
+   s->xfvm_screen_count = 0;
+   s->xfvm_screen = NULL;
+
+   _al_mutex_lock(&s->lock);
+
+   if (XF86VidModeQueryExtension(s->x11display, &event_base, &error_base)) {
+      int minor_version = 0, major_version = 0;
+      int status = XF86VidModeQueryVersion(s->x11display, &major_version, &minor_version);
+      ALLEGRO_INFO("XF86VidMode version: %i.%i\n", major_version, minor_version);
+
+      if(!status) {
+         ALLEGRO_WARN("XF86VidMode not available, XF86VidModeQueryVersion failed.\n");
+      }
+      else {
+         // I don't actually know what versions are required here, just going to assume any is ok for now.
+         ALLEGRO_INFO("XF86VidMode %i.%i is active\n", major_version, minor_version);
+         s->xfvm_available = 1;
+      }
+   }
+   else {
+      ALLEGRO_WARN("XF86VidMode extension is not available.\n");
+   }
+
+   int num_screens;
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+   if(s->xinerama_available) {
+      num_screens = s->xinerama_screen_count;
+   } else
+#endif
+   num_screens = ScreenCount(s->x11display);
+
+   s->xfvm_screen_count = num_screens;
+
+   s->xfvm_screen = calloc(num_screens, sizeof(*s->xfvm_screen));
+   if(!s->xfvm_screen) {
+      ALLEGRO_ERROR("XF86VidMode: failed to allocate screen array.\n");
+      s->xfvm_available = 0;
+   }
+
    int i;
+   for(i = 0; i < num_screens; i++) {
+      if(!XF86VidModeGetAllModeLines(s->x11display, i, &(s->xfvm_screen[i].mode_count), &(s->xfvm_screen[i].modes))) {
+         /* XXX what to do here? */
+      }
+   }
 
-   if (s->modes_count > 0) {
-      for (i = 0; i < s->modes_count; i++) {
-         if (s->modes[i]->privsize > 0) {
-            XFree(s->modes[i]->private);
+   if(s->xfvm_available) {
+      mmon_interface.get_num_display_modes = _al_xsys_xfvm_get_num_modes;
+      mmon_interface.get_display_mode      = _al_xsys_xfvm_get_mode;
+      mmon_interface.set_mode              = _al_xsys_xfvm_set_mode;
+      mmon_interface.store_mode            = _al_xsys_xfvm_store_video_mode;
+      mmon_interface.restore_mode          = _al_xsys_xfvm_restore_video_mode;
+      mmon_interface.get_display_offset    = _al_xsys_xfvm_get_display_offset;
+      mmon_interface.get_num_adapters      = _al_xsys_xfvm_get_num_adapters;
+      mmon_interface.get_monitor_info      = _al_xsys_xfvm_get_monitor_info;
+   }
+
+   _al_mutex_unlock(&s->lock);
+}
+
+void _al_xsys_xfvm_exit(ALLEGRO_SYSTEM_XGLX *s)
+{
+   int adapter;
+   ALLEGRO_DEBUG("xfullscreen: XFVM exit\n");
+
+   for(adapter = 0; adapter < s->xfvm_screen_count; adapter++) {
+      if (s->xfvm_screen[adapter].mode_count > 0) {
+         int i;
+         for (i = 0; i < s->xfvm_screen[adapter].mode_count; i++) {
+            if (s->xfvm_screen[adapter].modes[i]->privsize > 0) {
+               //XFree(s->xfvm_screen[adapter].modes[i]->private);
+            }
          }
+         //XFree(s->xfvm_screen[adapter].modes);
       }
-      XFree(s->modes);
 
-      s->modes_count = 0;
-      s->modes = NULL;
-      s->original_mode = NULL;
+      s->xfvm_screen[adapter].mode_count = 0;
+      s->xfvm_screen[adapter].modes = NULL;
+      s->xfvm_screen[adapter].original_mode = NULL;
+
+      ALLEGRO_DEBUG("xfullscreen: XFVM freed adapter %d.\n", adapter);
    }
+
+   free(s->xfvm_screen);
+   s->xfvm_screen = NULL;
 }
 
-#else /* !ALLEGRO_XWINDOWS_WITH_XF86VIDMODE */
+#else
+void _al_xsys_xfvm_init(ALLEGRO_SYSTEM_XGLX *s) { (void)s; }
+void _al_xsys_xfvm_exit(ALLEGRO_SYSTEM_XGLX *s) { (void)s; }
+#endif /* ALLEGRO_XWINDOWS_WITH_XF86VIDMODE */
 
-int _al_xglx_get_num_display_modes(void)
+int _al_xglx_get_num_display_modes(ALLEGRO_SYSTEM_XGLX *s, int adapter)
 {
-   return 0;
+   ALLEGRO_ASSERT(mmon_interface.get_num_display_modes != NULL);
+   return mmon_interface.get_num_display_modes(s, adapter);
 }
 
-ALLEGRO_DISPLAY_MODE *_al_xglx_get_display_mode(int index,
+ALLEGRO_DISPLAY_MODE *_al_xglx_get_display_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter, int index,
    ALLEGRO_DISPLAY_MODE *mode)
 {
-   (void)index;
-   (void)mode;
-   return NULL;
+   ALLEGRO_ASSERT(mmon_interface.get_display_mode != NULL);
+   return mmon_interface.get_display_mode(s, adapter, index, mode);
 }
 
+int _al_xglx_fullscreen_select_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter, int w, int h, int format, int refresh_rate)
+{
+   /* GCC complains about mode being uninitialized without this: */
+   ALLEGRO_DISPLAY_MODE mode = mode;
+   ALLEGRO_DISPLAY_MODE mode2;
+   int i;
+   int n;
+
+   n = _al_xglx_get_num_display_modes(s, adapter);
+   if (!n)
+      return -1;
+
+   /* Find all modes with correct parameters. */
+   int possible_modes[n];
+   int possible_count = 0;
+   for (i = 0; i < n; i++) {
+      if (!_al_xglx_get_display_mode(s, adapter, i, &mode)) {
+         continue;
+      }
+      if (mode.width == w && mode.height == h &&
+         (format == 0 || mode.format == format) &&
+         (refresh_rate == 0 || mode.refresh_rate == refresh_rate))
+      {
+         possible_modes[possible_count++] = i;
+      }
+   }
+   if (!possible_count)
+      return -1;
+
+   /* Choose mode with highest refresh rate. */
+   int best_mode = possible_modes[0];
+   _al_xglx_get_display_mode(s, adapter, best_mode, &mode);
+   for (i = 1; i < possible_count; i++) {
+      if (!_al_xglx_get_display_mode(s, adapter, possible_modes[i], &mode2))  {
+         continue;
+      }
+      if (mode2.refresh_rate > mode.refresh_rate) {
+         mode = mode2;
+         best_mode = possible_modes[i];
+      }
+   }
+
+   ALLEGRO_INFO("best mode [%d] = (%d, %d)\n", best_mode, mode.width, mode.height);
+
+   return best_mode;
+}
+
 bool _al_xglx_fullscreen_set_mode(ALLEGRO_SYSTEM_XGLX *s,
-   int w, int h, int format, int refresh_rate)
+   ALLEGRO_DISPLAY_XGLX *d, int w, int h, int format, int refresh_rate)
 {
-   (void)s;
-   (void)w;
-   (void)h;
-   (void)format;
-   (void)refresh_rate;
-   return false;
+   ALLEGRO_ASSERT(mmon_interface.set_mode != NULL);
+   return mmon_interface.set_mode(s, d, w, h, format, refresh_rate);
 }
 
 void _al_xglx_fullscreen_to_display(ALLEGRO_SYSTEM_XGLX *s,
    ALLEGRO_DISPLAY_XGLX *d)
 {
-   (void)s;
-   (void)d;
+   /* First, make sure the mouse stays inside the window. */
+   XGrabPointer(s->gfxdisplay, d->window, False,
+      PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+      GrabModeAsync, GrabModeAsync, d->window, None, CurrentTime);
+   //FIXME: handle possible errors here
+   s->pointer_grabbed = true;
 }
 
 void _al_xglx_store_video_mode(ALLEGRO_SYSTEM_XGLX *s)
 {
-   (void)s;
+   ALLEGRO_ASSERT(mmon_interface.store_mode != NULL);
+   mmon_interface.store_mode(s);
 }
 
-void _al_xglx_restore_video_mode(ALLEGRO_SYSTEM_XGLX *s)
+void _al_xglx_restore_video_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter)
 {
-   (void)s;
+   ALLEGRO_ASSERT(mmon_interface.restore_mode != NULL);
+   mmon_interface.restore_mode(s, adapter);
 }
 
-void _al_xglx_free_mode_infos(ALLEGRO_SYSTEM_XGLX *s)
+void _al_xglx_get_display_offset(ALLEGRO_SYSTEM_XGLX *s, int adapter, int *x, int *y)
 {
-   (void)s;
+   ALLEGRO_ASSERT(mmon_interface.get_display_offset != NULL);
+   mmon_interface.get_display_offset(s, adapter, x, y);
 }
 
-#endif /* !ALLEGRO_XWINDOWS_WITH_XF86VIDMODE */
+void _al_xglx_get_monitor_info(ALLEGRO_SYSTEM_XGLX *s, int adapter, ALLEGRO_MONITOR_INFO *info)
+{
+   ALLEGRO_ASSERT(mmon_interface.get_monitor_info != NULL);
+   mmon_interface.get_monitor_info(s, adapter, info);
+}
 
+int _al_xglx_get_num_video_adapters(ALLEGRO_SYSTEM_XGLX *s)
+{
+   ALLEGRO_ASSERT(mmon_interface.get_num_adapters != NULL);
+   return mmon_interface.get_num_adapters(s);
+}
+
 static bool got_atoms;
 static Atom _NET_WM_STATE;
 static Atom _NET_WM_STATE_FULLSCREEN;
@@ -245,7 +805,7 @@
    ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver();
    ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display;
    Display *x11 = system->x11display;
-   
+
    if (!got_atoms) {
       X11_ATOM_STRING(_NET_WM_STATE)
       X11_ATOM_STRING(_NET_WM_STATE_FULLSCREEN)
Index: src/x/xsystem.c
===================================================================
--- src/x/xsystem.c	(revision 13160)
+++ src/x/xsystem.c	(working copy)
@@ -106,20 +106,20 @@
        * Most older X11 implementations are not thread-safe no matter what, so
        * we simply cannot sit inside a blocking XNextEvent from another thread
        * if another thread also uses X11 functions.
-       * 
+       *
        * The usual use of XNextEvent is to only call it from the main thread. We
        * could of course do this for A5, just needs some slight adjustments to
        * the events system (polling for an Allegro event would call a function
        * of the system driver).
-       * 
+       *
        * As an alternative, we can use locking. This however can never fully
        * work, as for example OpenGL implementations also will access X11, in a
        * way we cannot know and cannot control (and we can't require users to
        * only call graphics functions inside a lock).
-       * 
+       *
        * However, most X11 implementations are somewhat thread safe, and do
        * use locking quite a bit themselves, so locking mostly does work.
-       * 
+       *
        * (Yet another alternative might be to use a separate X11 display
        * connection for graphics output.)
        *
@@ -161,52 +161,6 @@
    }
 }
 
-#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
-
-static void _al_xsys_xinerama_init(ALLEGRO_SYSTEM_XGLX *s)
-{
-   int event_base = 0;
-   int error_base = 0;
-
-   /* init xinerama info to defaults */
-   s->xinerama_available = 0;
-   s->xinerama_screen_count = 0;
-   s->xinerama_screen_info = NULL;
-
-   _al_mutex_lock(&s->lock);
-
-   if (XineramaQueryExtension(s->x11display, &event_base, &error_base)) {
-      int minor_version = 0, major_version = 0;
-      int status = XineramaQueryVersion(s->x11display, &major_version, &minor_version);
-      ALLEGRO_INFO("Xinerama version: %i.%i\n", major_version, minor_version);
-
-      if (status && !XineramaIsActive(s->x11display)) {
-         ALLEGRO_WARN("Xinerama is not active\n");
-      }
-      else {
-         ALLEGRO_INFO("Xinerama is active\n");
-         s->xinerama_available = 1;
-      }
-   }
-   else {
-      ALLEGRO_WARN("Xinerama extension is not available.\n");
-   }
-
-   _al_mutex_unlock(&s->lock);
-}
-
-static void _al_xsys_xinerama_exit(ALLEGRO_SYSTEM_XGLX *s)
-{
-   if (s->xinerama_screen_info)
-      XFree(s->xinerama_screen_info);
-
-   s->xinerama_available = 0;
-   s->xinerama_screen_count = 0;
-   s->xinerama_screen_info = NULL;
-}
-
-#endif /* ALLEGRO_XWINDOWS_WITH_XINERAMA */
-
 /* Create a new system object for the dummy X11 driver. */
 static ALLEGRO_SYSTEM *xglx_initialize(int flags)
 {
@@ -268,8 +222,16 @@
    _al_xsys_xinerama_init(s);
 #endif
 
+#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
+   _al_xsys_xfvm_init(s);
+#endif
+
+#ifdef ALLEGRO_XWINDOWS_WITH_XRANDR
+   _al_xsys_xrandr_init(s);
+#endif
+
    _al_xglx_store_video_mode(s);
-   
+
    _al_thread_create(&s->thread, xglx_background_thread, s);
 
    ALLEGRO_INFO("events thread spawned.\n");
@@ -295,15 +257,22 @@
    }
    _al_vector_free(&s->displays);
 
-   _al_xglx_free_mode_infos(sx);
-
 #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
    _al_xsys_xinerama_exit(sx);
 #endif
 
+#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
+   _al_xsys_xfvm_exit(sx);
+#endif
+
+#ifdef ALLEGRO_XWINDOWS_WITH_XRANDR
+   _al_xsys_xrandr_exit(sx);
+#endif
+
    if (sx->x11display) {
       XCloseDisplay(sx->x11display);
       sx->x11display = None;
+      ALLEGRO_DEBUG("xsys: close x11display.\n");
    }
 
    if (sx->gfxdisplay) {
@@ -340,72 +309,18 @@
 
 static int xglx_get_num_video_adapters(void)
 {
-#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
    ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver();
-   if (!system->xinerama_available) {
-      return 1;
-   }
-   
-   if (system->xinerama_screen_info) {
-      XFree(system->xinerama_screen_info);
-      system->xinerama_screen_info = NULL;
-      system->xinerama_screen_count = 0;
-   }
 
-   _al_mutex_lock(&system->lock);
-   system->xinerama_screen_info = XineramaQueryScreens(system->x11display, &(system->xinerama_screen_count));
-   _al_mutex_unlock(&system->lock);
-
-   if (!system->xinerama_screen_info) {
-      system->xinerama_available = 0;
-      system->xinerama_screen_count = 0;
-      return 1;
-   }
-
-   return system->xinerama_screen_count;
-#else    /* !ALLEGRO_XWINDOWS_WITH_XINERAMA */
-   return 1;
-#endif   /* !ALLEGRO_XWINDOWS_WITH_XINERAMA */
+   return _al_xglx_get_num_video_adapters(system);
 }
 
-static void xglx_get_smonitor_info(ALLEGRO_SYSTEM_XGLX *system, ALLEGRO_MONITOR_INFO *info)
-{
-   XWindowAttributes xwa;
-   Window root = RootWindow(system->x11display, 0);
-   _al_mutex_lock(&system->lock);
-   XGetWindowAttributes(system->x11display, root, &xwa);
-   _al_mutex_unlock(&system->lock);
-   
-   info->x1 = 0;
-   info->y1 = 0;
-   info->x2 = xwa.width;
-   info->y2 = xwa.height;
-}
-
 // FIXME: only uses xinerama to get info. Need to extend later and include the xfullscreen code
 // to use xrandr once nvidia gets arround to supporting at least XRandR 1.2
 static void xglx_get_monitor_info(int adapter, ALLEGRO_MONITOR_INFO *info)
 {
    ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver();
 
-#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
-   if (system->xinerama_available) {
-      if (adapter >= system->xinerama_screen_count || adapter < 0)
-         return; // don't fill in single screen info if an invalid adapter number is entered.
-                 // its a bug, and should be noticed.
-
-      info->x1 = system->xinerama_screen_info[adapter].x_org;
-      info->y1 = system->xinerama_screen_info[adapter].y_org;
-      info->x2 = system->xinerama_screen_info[adapter].x_org + system->xinerama_screen_info[adapter].width;
-      info->y2 = system->xinerama_screen_info[adapter].y_org + system->xinerama_screen_info[adapter].height;
-   }
-   else {
-      xglx_get_smonitor_info(system, info);
-   }
-#else /* !ALLEGRO_XWINDOWS_WITH_XINERAMA */
-   (void)adapter;
-   xglx_get_smonitor_info(system, info);
-#endif /* !ALLEGRO_XWINDOWS_WITH_XINERAMA */
+   _al_xglx_get_monitor_info(system, adapter, info);
 }
 
 static bool xglx_get_cursor_position(int *ret_x, int *ret_y)
@@ -431,6 +346,22 @@
    return true;
 }
 
+static int xglx_get_num_display_modes()
+{
+   int adapter = al_get_current_video_adapter();
+   ALLEGRO_SYSTEM_XGLX *s = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver();
+
+   return _al_xglx_get_num_display_modes(s, adapter);
+}
+
+static ALLEGRO_DISPLAY_MODE *xglx_get_display_mode(int mode, ALLEGRO_DISPLAY_MODE *dm)
+{
+   int adapter = al_get_current_video_adapter();
+   ALLEGRO_SYSTEM_XGLX *s = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver();
+
+   return _al_xglx_get_display_mode(s, adapter, mode, dm);
+}
+
 /* Internal function to get a reference to this driver. */
 ALLEGRO_SYSTEM_INTERFACE *_al_system_xglx_driver(void)
 {
@@ -445,8 +376,8 @@
    xglx_vt->get_keyboard_driver = xglx_get_keyboard_driver;
    xglx_vt->get_mouse_driver = xglx_get_mouse_driver;
    xglx_vt->get_joystick_driver = xglx_get_joystick_driver;
-   xglx_vt->get_num_display_modes = _al_xglx_get_num_display_modes;
-   xglx_vt->get_display_mode = _al_xglx_get_display_mode;
+   xglx_vt->get_num_display_modes = xglx_get_num_display_modes;
+   xglx_vt->get_display_mode = xglx_get_display_mode;
    xglx_vt->shutdown_system = xglx_shutdown_system;
    xglx_vt->get_num_video_adapters = xglx_get_num_video_adapters;
    xglx_vt->get_monitor_info = xglx_get_monitor_info;
Index: src/x/xdisplay.c
===================================================================
--- src/x/xdisplay.c	(revision 13160)
+++ src/x/xdisplay.c	(working copy)
@@ -23,7 +23,7 @@
 
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
-   
+
    if (ogl->backbuffer)
       _al_ogl_resize_backbuffer(ogl->backbuffer, d->w, d->h);
    else
@@ -161,7 +161,7 @@
     * would also require special care in the event handler.
     */
    hints = XInternAtom(x11, "_MOTIF_WM_HINTS", True);
-   if (hints) { 
+   if (hints) {
       struct {
          unsigned long flags;
          unsigned long functions;
@@ -191,7 +191,7 @@
    bool onoff)
 {
    switch(flag) {
-      case ALLEGRO_NOFRAME: 
+      case ALLEGRO_NOFRAME:
          xdpy_toggle_frame(display, onoff);
          return true;
       case ALLEGRO_FULLSCREEN_WINDOW:
@@ -231,22 +231,14 @@
    // FIXME: default? Is this the right place to set this?
    display->flags |= ALLEGRO_OPENGL;
 
-   // TODO: What is this?
-   d->xscreen = DefaultScreen(system->x11display);
+   // store our initial screen, used by fullscreen and glx visual code
+   d->xscreen = al_get_current_video_adapter();
+   if(d->xscreen < 0)
+      d->xscreen = 0;
 
    d->is_mapped = false;
    _al_cond_init(&d->mapped);
 
-   // Try to set full screen mode if requested, fail if we can't
-   if (display->flags & ALLEGRO_FULLSCREEN) {
-      if (!_al_xglx_fullscreen_set_mode(system, w, h, 0, 0)) {
-         _AL_FREE(d);
-         _AL_FREE(ogl);
-         _al_mutex_unlock(&system->lock);
-         return NULL;
-      }
-   }
-
    _al_xglx_config_select_visual(d);
 
    if (!d->xvinfo) {
@@ -301,10 +293,41 @@
       swa.background_pixel = BlackPixel(system->x11display, d->xvinfo->screen);
    }
 
+   int x_off = INT_MAX, y_off = INT_MAX;
+   if(display->flags & ALLEGRO_FULLSCREEN) {
+      _al_xglx_get_display_offset(system, d->xscreen, &x_off, &y_off);
+   }
+   else {
+      al_get_new_window_position(&x_off, &y_off);
+   }
+
    d->window = XCreateWindow(system->x11display, RootWindow(
-      system->x11display, d->xvinfo->screen), 0, 0, w, h, 0, d->xvinfo->depth,
+      system->x11display, d->xvinfo->screen), x_off, y_off, w, h, 0, d->xvinfo->depth,
       InputOutput, d->xvinfo->visual, mask, &swa);
 
+   // Tell WMs to respect our chosen position,
+   // otherwise the x_off/y_off positions passed to
+   // XCreateWindow will be ignored by most WMs.
+   if (x_off != INT_MAX && y_off != INT_MAX) {
+      ALLEGRO_DEBUG("Force window position to %d, %d.\n",
+         x_off, y_off);
+
+      XSizeHints sh;
+      sh.flags = PPosition;
+      XSetWMNormalHints(system->x11display, d->window, &sh);
+   }
+
+   // Try to set full screen mode if requested, fail if we can't
+   if (display->flags & ALLEGRO_FULLSCREEN) {
+      if (!_al_xglx_fullscreen_set_mode(system, d, w, h, 0, display->refresh_rate)) {
+         XDestroyWindow(system->x11display, d->window);
+         _AL_FREE(d);
+         _AL_FREE(ogl);
+         _al_mutex_unlock(&system->lock);
+         return NULL;
+      }
+   }
+
    if (display->flags & ALLEGRO_NOFRAME)
       xdpy_toggle_frame(display, false);
 
@@ -319,20 +342,6 @@
    XMapWindow(system->x11display, d->window);
    ALLEGRO_DEBUG("X11 window mapped.\n");
 
-   /* Is there a better way to do this, that positions the window before
-    * mapping it?
-    */
-   int new_x, new_y;
-   al_get_new_window_position(&new_x, &new_y);
-   if (new_x != INT_MAX && new_y != INT_MAX) {
-      ALLEGRO_DEBUG("Force window position to %d, %d.\n",
-         new_x, new_y);
-      XWindowChanges wch;
-      wch.x = new_x;
-      wch.y = new_y;
-      XConfigureWindow(system->x11display, d->window, CWX | CWY, &wch);
-   }
-
    /* Send the pending request to the X server. */
    XSync(system->x11display, False);
    /* To avoid race conditions where some X11 functions fail before the window
@@ -420,11 +429,11 @@
       setup_gl(display);
 
    /* vsync */
-   
+
    /* Fill in the user setting. */
    display->extra_settings.settings[ALLEGRO_VSYNC] =
       _al_get_new_display_settings()->settings[ALLEGRO_VSYNC];
-   
+
    /* We set the swap interval to 0 if vsync is forced off, and to 1
     * if it is forced on.
     * http://www.opengl.org/registry/specs/SGI/swap_control.txt
@@ -469,6 +478,8 @@
    ALLEGRO_DISPLAY_XGLX *glx = (void *)d;
    ALLEGRO_OGL_EXTRAS *ogl = d->ogl_extras;
 
+   ALLEGRO_DEBUG("xdpy: destroy display.\n");
+
    /* If we're the last display, convert all bitmpas to display independent
     * (memory) bitmaps. */
    if (s->system.displays._size == 1) {
@@ -477,6 +488,7 @@
          ALLEGRO_BITMAP *b = *bptr;
          _al_convert_to_memory_bitmap(b);
       }
+      ALLEGRO_DEBUG("xdpy: free visuals info.\n");
       _al_xglx_free_visuals_info();
    }
    else {
@@ -501,23 +513,29 @@
    }
 
    _al_ogl_unmanage_extensions(d);
+   ALLEGRO_DEBUG("xdpy: unmanaged extensions.\n");
 
    _al_mutex_lock(&s->lock);
    _al_vector_find_and_delete(&s->system.displays, &d);
    XDestroyWindow(s->x11display, glx->window);
 
+   ALLEGRO_DEBUG("xdpy: destroy window.\n");
+
    if (d->flags & ALLEGRO_FULLSCREEN) {
-      _al_xglx_restore_video_mode(s);
+      ALLEGRO_DEBUG("xfullscreen: restore modes.\n");
+      _al_xglx_restore_video_mode(s, glx->xscreen);
    }
 
    if (ogl->backbuffer) {
       _al_ogl_destroy_backbuffer(ogl->backbuffer);
       ogl->backbuffer = NULL;
+      ALLEGRO_DEBUG("xdpy: destroy backbuffer.\n");
    }
 
    if (glx->context) {
       glXDestroyContext(s->gfxdisplay, glx->context);
       glx->context = NULL;
+      ALLEGRO_DEBUG("xdpy: destroy context.\n");
    }
 
    /* XXX quick pre-release hack */
@@ -544,6 +562,8 @@
    _AL_FREE(d);
 
    _al_mutex_unlock(&s->lock);
+
+    ALLEGRO_DEBUG("xdpy: destroy display fin.\n");
 }
 
 
@@ -656,8 +676,9 @@
     */
    xdpy_acknowledge_resize(d);
 
+   // XXX is this even a valid action?
    if (d->flags & ALLEGRO_FULLSCREEN) {
-      _al_xglx_fullscreen_set_mode(system, w, h, 0, 0);
+      _al_xglx_fullscreen_set_mode(system, glx, w, h, 0, 0);
       _al_xglx_fullscreen_to_display(system, glx);
    }
 
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt	(revision 13160)
+++ CMakeLists.txt	(working copy)
@@ -423,10 +423,10 @@
     )
 
 check_c_source_compiles("
-    #include <sys/procfs.h> 
+    #include <sys/procfs.h>
     #include <sys/ioctl.h>
     int main(void) {
-        struct prpsinfo psinfo; 
+        struct prpsinfo psinfo;
         ioctl(0, PIOCPSINFO, &psinfo);
         return 0;
     }"
@@ -549,6 +549,12 @@
         list(APPEND X11_LIBRARIES "Xinerama")
     endif(CAN_XINERAMA)
 
+    check_library_exists(Xrandr XRRQueryExtension "" CAN_XRANDR)
+    if(CAN_XRANDR)
+        set(ALLEGRO_XWINDOWS_WITH_XRANDR 1)
+        list(APPEND X11_LIBRARIES "Xrandr")
+    endif(CAN_XRANDR)
+
     check_library_exists(X11 XOpenIM "" CAN_XIM)
     if(CAN_XIM)
         set(ALLEGRO_XWINDOWS_WITH_XIM 1)
@@ -579,7 +585,7 @@
         message(FATAL_ERROR
             "Windows port requires DirectInput (not found).")
     endif(DINPUT_FOUND)
-    
+
     find_package(DXGuid)
     if(NOT DXGUID_FOUND)
         message(FATAL_ERROR


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/