Re: [AD] More X Mode Setting

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


On January 12, 2011, Thomas Fjellstrom wrote:
> On January 12, 2011, Peter Wang wrote:
> > On 2011-01-12, Thomas Fjellstrom <tfjellstrom@xxxxxxxxxx> wrote:
> > > On January 12, 2011, Peter Wang wrote:
> > > > On 2011-01-12, Thomas Fjellstrom <tfjellstrom@xxxxxxxxxx> wrote:
> > > > > I'm in the middle of refactoring the XRandR code. Not entirely sure
> > > > > when it'll be done (soonish), but it is necessary.
> > > > > 
> > > > > Seems XRandR doesn't do anything without you telling it, and
> > > > > doesn't have any notion about what relation one monitor is to the
> > > > > next, ie: theres no LeftOf or Above type flags, so we have to
> > > > > calculate the right monitor origins for each set of modes, to make
> > > > > sure multiple full screen displays are right next to each other.
> > > > > And re-querying Xrandr can be a tad expensive so I've added in the
> > > > > code to handle XRR notify events. But it turns out it'll be more
> > > > > efficient to store our own custom XRR structures rather than
> > > > > pointing to XRROutput structures, this way we'll be able to detect
> > > > > what exactly changed (the change events in XRR are rather coarse,
> > > > > just tells you that a CRTC or Output changed, and not what inside
> > > > > changed).
> > > > 
> > > > I don't know if it would help you, but reconfiguring monitor setups
> > > > is not something people do very often (if ever), so efficiency isn't
> > > > a high priority.
> > > 
> > > True, but the XRandR query takes about half a second on my laptop, and
> > > we'd probably have to re do it every time we get an event. I don't
> > > think thats something we want to do. As we get an event for every
> > > change we make ourselves. So 2-4 events at least just for ex_dualies.
> > > 
> > > One thing I'm somewhat disappointed about is that all that work you did
> > > to make mmon display init lazy, has been made mostly redundant. Since
> > > now xdpy_create_display needs to init the mmon code. If we had a way to
> > > tell allegro to "ignore" multi monitor, we could make it so regular
> > > windowed allegro apps don't init it, but as of right now, we need to
> > > init the mmon code just to know if we want to init it. Its pretty
> > > silly.
> > 
> > Hmm, that could be rather bad.  I added that lazy init stuff because
> > (sometimes, not sure when) it would cause monitors to blank when probed,
> > or add a noticeable delay when starting a program.
> 
> I've only seen delays on the order of half a second with my intel based
> laptop, and less with the nvidia binary driver. And no blanks. I do
> remember seeing those kinds of things in the past, with very old crappy
> versions of X and drivers, but nothing at all while working on the new
> fixes.
> 
> > Can you post a patch at some point so I could have a look?
> > Doesn't matter if it's incomplete.
> 
> Sure. Attached what I have now, minus the randr re-factor.

re-factor working now, at least on my laptop, attached the new patch.

I'll remove the old xrandr code in a second commit, just to make sure the code 
is around some place. right now its just #if 0'ed out.

All of the new xrandr code lives in src/x/xrandr.c now, split out from 
src/x/xfullscreen.c, its considerably cleaner, makes it a lot easier to work 
with and improve. And it works at least as well as the old code did, if not 
better (it will for sure once I add the logic to detect monitor relationships 
and change monitor origins, to fix mouse behavior with multiple monitors).

We also need to figure out a way to fix the mouse grabbing. The way it was, 
totally broke multi monitor. The way it is now, breaks single monitor full 
screen (it just doesn't grab the mouse at all right now).

Oh, the new xrandr code gets a little "creative" with the _AL_VECTOR type, if 
you don't mind that, we can leave it, or possibly add a 
_al_vector_append_array(_AL_VECTOR *vec, int num, TYPE *arr) type function to 
make the query code a little less creative.

> > Peter
> > 


-- 
Thomas Fjellstrom
tfjellstrom@xxxxxxxxxx
Index: cmake/FileList.cmake
===================================================================
--- cmake/FileList.cmake	(revision 14262)
+++ cmake/FileList.cmake	(working copy)
@@ -116,6 +116,7 @@
     src/x/xdisplay.c
     src/x/xfullscreen.c
     src/x/xglx_config.c
+    src/x/xrandr.c
     src/x/xsystem.c
     src/linux/ljoynu.c
     )
Index: include/allegro5/internal/aintern_xglx.h
===================================================================
--- include/allegro5/internal/aintern_xglx.h	(revision 14262)
+++ include/allegro5/internal/aintern_xglx.h	(working copy)
@@ -84,13 +84,32 @@
 #endif
 #ifdef ALLEGRO_XWINDOWS_WITH_XRANDR
    int xrandr_available;
-   XRRScreenResources *xrandr_res;
+   int xrandr_event_base;
+   
+   _AL_VECTOR xrandr_screens;
+   _AL_VECTOR xrandr_adaptermap;
+   
+#if 0
+   int xrandr_res_count;
+   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;
+   struct xrandr_output_s {
+      int res_id;
+      XRROutputInfo *output;
+      RRMode mode;
+      RRMode set_mode;
+   } **xrandr_outputs;
+   XRRScreenSize *saved_size;
+#endif /* 0 */
+   
 #endif
+   
+   /* used to keep track of how many adapters are in use,
+    * so the multi-head code can bail if we try to use more than one. */
+   uint32_t adapter_use_count;
+   int adapter_map[32]; /* really can't think of a better way to track which adapters are in use ::) */
 };
 
 /* This is our version of ALLEGRO_DISPLAY with driver specific extra data. */
@@ -101,7 +120,8 @@
    /* Driver specifics. */
 
    Window window;
-   int xscreen; /* TODO: what is this? something with multi-monitor? */
+   int xscreen; /* X Screen ID */
+   int adapter; /* allegro virtual adapter id/index */
    GLXWindow glxwindow;
    GLXContext context;
    Atom wm_delete_window_atom;
@@ -164,6 +184,26 @@
 
 /* fullscreen and multi monitor stuff */
 
+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 *);
+    int (*get_default_adapter)(ALLEGRO_SYSTEM_XGLX *);
+    int (*get_adapter)(ALLEGRO_SYSTEM_XGLX *, ALLEGRO_DISPLAY_XGLX *);
+    int (*get_xscreen)(ALLEGRO_SYSTEM_XGLX *, int);
+    void (*post_setup)(ALLEGRO_SYSTEM_XGLX *, ALLEGRO_DISPLAY_XGLX *);
+    void (*handle_xevent)(ALLEGRO_SYSTEM_XGLX *, ALLEGRO_DISPLAY_XGLX *, XEvent *e);
+};
+
+extern _ALLEGRO_XGLX_MMON_INTERFACE mmon_interface;
+
 void _al_xsys_mmon_exit(ALLEGRO_SYSTEM_XGLX *s);
 
 int _al_xglx_get_num_display_modes(ALLEGRO_SYSTEM_XGLX *s, int adapter);
@@ -184,7 +224,15 @@
 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);
 
+int _al_xglx_get_default_adapter(ALLEGRO_SYSTEM_XGLX *s);
+int _al_xglx_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter);
 
+void _al_xglx_toggle_above(ALLEGRO_DISPLAY *display, int value);
+
+int _al_xglx_get_adapter(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, bool recalc);
+
+void _al_xglx_handle_xevent(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, XEvent *e);
+
 /* glx_config */
 void _al_xglx_config_select_visual(ALLEGRO_DISPLAY_XGLX *glx);
 bool _al_xglx_config_create_context(ALLEGRO_DISPLAY_XGLX *glx);
Index: include/allegro5/internal/aintern_vector.h
===================================================================
--- include/allegro5/internal/aintern_vector.h	(revision 14262)
+++ include/allegro5/internal/aintern_vector.h	(working copy)
@@ -19,6 +19,7 @@
 
 
 AL_FUNC(void,  _al_vector_init, (_AL_VECTOR*, size_t itemsize));
+AL_FUNC(bool, _al_vector_reserve, (_AL_VECTOR *vec, int num));
 AL_INLINE(size_t, _al_vector_size, (const _AL_VECTOR *vec),
 {
    return vec->_size;
Index: src/misc/vector.c
===================================================================
--- src/misc/vector.c	(revision 14262)
+++ src/misc/vector.c	(working copy)
@@ -60,8 +60,24 @@
    vec->_unused = 0;
 }
 
+/* Internal function: _al_vector_reserve
+ * 
+ *  Reserve or pre-allocate 'num' items in the vector.
+ */
+bool _al_vector_reserve(_AL_VECTOR *vec, int num)
+{
+   ASSERT(vec);
+   ASSERT(num > 0);
+   
+   vec->_items = al_malloc(vec->_itemsize * num);
+   if(!vec->_items)
+      return false;
+   
+   vec->_unused = num;
+   
+   return true;
+}
 
-
 /*
  * Simple inline functions:
  *
Index: src/x/xrandr.c
===================================================================
--- src/x/xrandr.c	(revision 0)
+++ src/x/xrandr.c	(revision 0)
@@ -0,0 +1,787 @@
+#include "allegro5/allegro.h"
+#include "allegro5/internal/aintern_xglx.h"
+
+#ifdef ALLEGRO_XWINDOWS_WITH_XRANDR
+
+int _al_xsys_mheadx_get_default_adapter(ALLEGRO_SYSTEM_XGLX *s);
+int _al_xsys_mheadx_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter);
+void _al_xsys_get_active_window_center(ALLEGRO_SYSTEM_XGLX *s, int *x, int *y);
+
+ALLEGRO_DEBUG_CHANNEL("xrandr")
+
+typedef struct xrandr_screen xrandr_screen;
+typedef struct xrandr_crtc xrandr_crtc;
+typedef struct xrandr_output xrandr_output;
+typedef struct xrandr_mode xrandr_mode;
+
+struct xrandr_screen {
+   int id;
+   Time timestamp;
+   Time configTimestamp;
+   _AL_VECTOR crtcs; // xrandr_crtc
+   _AL_VECTOR outputs; // xrandr_output
+   _AL_VECTOR modes; // xrandr_mode
+   
+   XRRScreenResources *res;
+};
+
+struct xrandr_crtc {
+   RRCrtc id;
+   Time timestamp;
+   int x, y;
+   unsigned int width, height;
+   RRMode mode;
+   Rotation rotation;
+   _AL_VECTOR connected;
+   _AL_VECTOR possible;
+   
+   RRMode original_mode;
+   int original_xoff;
+   int original_yoff;
+};
+
+struct xrandr_output {
+   RROutput id;
+   Time timestamp;
+   RRCrtc crtc;
+   char *name;
+   int namelen;
+   unsigned long mm_width;
+   unsigned long mm_height;
+   Connection connection;
+   SubpixelOrder subpixel_order;
+   _AL_VECTOR crtcs; // RRCrtc
+   _AL_VECTOR clones; // RROutput
+   RRMode preffered_mode;
+   _AL_VECTOR modes; // RRMode
+};
+
+struct xrandr_mode {
+   RRMode id;
+   unsigned int width;
+   unsigned int height;
+   unsigned int refresh;
+};
+
+struct xrandr_rect {
+   int x1;
+   int y1;
+   int x2;
+   int y2;
+};
+
+static void _al_xsys_xrandr_copy_mode(xrandr_mode *mode, XRRModeInfo *rrmode)
+{
+   mode->id     = rrmode->id;
+   mode->width  = rrmode->width;
+   mode->height = rrmode->height;
+   
+   if (rrmode->hTotal && rrmode->vTotal) {
+      mode->refresh = ((float) rrmode->dotClock / ((float) rrmode->hTotal * (float) rrmode->vTotal));
+   }
+   else {
+      mode->refresh = 0;
+   }
+}
+
+static void _al_xsys_xrandr_copy_output(xrandr_output *output, RROutput id, XRROutputInfo *rroutput)
+{
+   output->id             = id;
+   output->timestamp      = rroutput->timestamp;
+   output->crtc           = rroutput->crtc;
+   output->name           = strdup(rroutput->name);
+   output->namelen        = rroutput->nameLen;
+   output->mm_width       = rroutput->mm_width;
+   output->mm_height      = rroutput->mm_height;
+   output->connection     = rroutput->connection;
+   output->subpixel_order = rroutput->subpixel_order;
+   
+   ALLEGRO_DEBUG("output[%s] %s.\n", output->name, output->connection == RR_Connected ? "Connected" : "Not Connected");
+   
+   _al_vector_init(&output->crtcs, sizeof(RRCrtc));
+   if(rroutput->ncrtc) {
+      _al_vector_reserve(&output->crtcs, rroutput->ncrtc);
+      memcpy(output->crtcs._items, rroutput->crtcs, sizeof(RRCrtc) * rroutput->ncrtc);
+      output->crtcs._size = rroutput->ncrtc;
+      output->crtcs._unused = 0;
+   }
+   
+   _al_vector_init(&output->clones, sizeof(RROutput));
+   if(rroutput->nclone) {
+      _al_vector_reserve(&output->clones, rroutput->nclone);
+      memcpy(output->clones._items, rroutput->clones, sizeof(RROutput) * rroutput->nclone);
+      output->clones._size = rroutput->nclone;
+      output->clones._unused = 0;
+   }
+   
+   _al_vector_init(&output->modes, sizeof(RRMode));
+   if(rroutput->nmode) {
+      _al_vector_reserve(&output->modes, rroutput->nmode);
+      memcpy(output->modes._items, rroutput->modes, sizeof(RRMode) * rroutput->nmode);
+      output->modes._size = rroutput->nmode;
+      output->modes._unused = 0;
+   }
+   
+   output->preffered_mode = rroutput->modes[rroutput->npreferred];
+   
+}
+
+static void _al_xsys_xrandr_copy_crtc(xrandr_crtc *crtc, RRCrtc id, XRRCrtcInfo *rrcrtc)
+{
+   crtc->id        = id;
+   crtc->timestamp = rrcrtc->timestamp;
+   crtc->x         = rrcrtc->x;
+   crtc->y         = rrcrtc->y;
+   crtc->width     = rrcrtc->width;
+   crtc->height    = rrcrtc->height;
+   crtc->mode      = rrcrtc->mode;
+   crtc->rotation  = rrcrtc->rotation;
+   
+   _al_vector_init(&crtc->connected, sizeof(RROutput));
+   if(rrcrtc->noutput) {
+      _al_vector_reserve(&crtc->connected, rrcrtc->noutput);
+      memcpy(crtc->connected._items, rrcrtc->outputs, sizeof(RROutput) * rrcrtc->noutput);
+      crtc->connected._size = rrcrtc->noutput;
+   }
+   
+   _al_vector_init(&crtc->possible, sizeof(RROutput));
+   if(rrcrtc->npossible) {
+      _al_vector_reserve(&crtc->possible, rrcrtc->npossible);
+      memcpy(crtc->possible._items, rrcrtc->possible, sizeof(RROutput) * rrcrtc->npossible);
+      crtc->possible._size = rrcrtc->npossible;
+   }
+   
+   crtc->original_mode = crtc->mode;
+   crtc->original_xoff = crtc->x;
+   crtc->original_yoff = crtc->y;
+   
+}
+
+static void _al_xsys_xrandr_copy_screen(ALLEGRO_SYSTEM_XGLX *s, xrandr_screen *screen, XRRScreenResources *res)
+{
+   int j;
+
+   _al_vector_init(&screen->modes, sizeof(xrandr_mode));
+   if(res->nmode) {
+      _al_vector_reserve(&screen->modes, res->nmode);
+      memset(screen->modes._items, 0, sizeof(xrandr_mode) * res->nmode);
+   
+      for(j = 0; j < res->nmode; j++) {
+         xrandr_mode *mode = _al_vector_alloc_back(&screen->modes);
+         _al_xsys_xrandr_copy_mode(mode, &res->modes[j]);
+      }
+   }
+   
+   _al_vector_init(&screen->crtcs, sizeof(xrandr_crtc));
+   if(res->ncrtc) {
+      _al_vector_reserve(&screen->crtcs, res->ncrtc);
+      memset(screen->crtcs._items, 0, sizeof(xrandr_crtc) * res->ncrtc);
+   
+      ALLEGRO_DEBUG("fount %i crtcs.\n", res->ncrtc);
+      for(j = 0; j < res->ncrtc; j++) {
+         ALLEGRO_DEBUG("crtc[%i] %i.\n", j, res->crtcs[j]);
+         xrandr_crtc *crtc = _al_vector_alloc_back(&screen->crtcs);
+         XRRCrtcInfo *rrcrtc = XRRGetCrtcInfo(s->x11display, res, res->crtcs[j]);
+      
+         _al_xsys_xrandr_copy_crtc(crtc, res->crtcs[j], rrcrtc);
+      
+         XRRFreeCrtcInfo(rrcrtc);
+      }
+   }
+   
+   _al_vector_init(&screen->outputs, sizeof(xrandr_output));
+   if(res->noutput) {
+      _al_vector_reserve(&screen->outputs, res->noutput);
+      memset(screen->outputs._items, 0, sizeof(xrandr_output) * res->noutput);
+   
+      ALLEGRO_DEBUG("found %i outputs.\n", res->noutput);
+      for(j = 0; j < res->noutput; j++) {
+         ALLEGRO_DEBUG("output[%i] %i.\n", j, res->outputs[j]);
+         xrandr_output *output = _al_vector_alloc_back(&screen->outputs);
+         XRROutputInfo *rroutput = XRRGetOutputInfo(s->x11display, res, res->outputs[j]);
+      
+         _al_xsys_xrandr_copy_output(output, res->outputs[j], rroutput);
+      
+         XRRFreeOutputInfo(rroutput);
+         XSync(s->x11display, False);
+      }
+   }
+}
+
+static xrandr_crtc *_al_xsys_xrandr_fetch_crtc(ALLEGRO_SYSTEM_XGLX *s, int sid, RRCrtc id)
+{
+   unsigned int i;
+   
+   xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, sid);
+   
+   for(i = 0; i < _al_vector_size(&screen->crtcs); i++) {
+      xrandr_crtc *crtc = _al_vector_ref(&screen->crtcs, i);
+      if(crtc->id == id)
+         return crtc;
+   }
+   
+   return NULL;
+}
+
+static xrandr_output *_al_xsys_xrandr_fetch_output(ALLEGRO_SYSTEM_XGLX *s, int sid, RROutput id)
+{
+   unsigned int i;
+   
+   xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, sid);
+   
+   for(i = 0; i < _al_vector_size(&screen->outputs); i++) {
+      xrandr_output *output = _al_vector_ref(&screen->outputs, i);
+      if(output->id == id)
+         return output;
+   }
+   
+   return NULL;
+}
+
+static xrandr_mode *_al_xsys_xrandr_fetch_mode(ALLEGRO_SYSTEM_XGLX *s, int sid, RRMode id)
+{
+   unsigned int i;
+   
+   xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, sid);
+
+   for(i = 0; i < _al_vector_size(&screen->modes); i++) {
+      xrandr_mode *mode = _al_vector_ref(&screen->modes, i);
+      if(mode->id == id)
+         return mode;
+   }
+   
+   return NULL;
+}
+
+static inline xrandr_output *_al_xsys_xrandr_map_adapter(ALLEGRO_SYSTEM_XGLX *s, int sid, int adapter)
+{
+   // This doesn't look right at first glance, but the adaptermap setup ought to do the right thing here.
+   return _al_xsys_xrandr_fetch_output(s, sid, *(RROutput*)_al_vector_ref(&s->xrandr_adaptermap, adapter));
+}
+
+static void _al_xsys_xrandr_combine_output_rect(struct xrandr_rect *rect, xrandr_crtc *crtc)
+{
+   if(rect->x1 > crtc->x)
+      rect->x1 = crtc->x;
+   
+   if(rect->y1 > crtc->y)
+      rect->y1 = crtc->y;
+   
+   if(crtc->x + (int)crtc->width > rect->x2)
+      rect->x2 = crtc->x + crtc->width;
+   
+   if(crtc->y + (int)crtc->height > rect->y2)
+      rect->y2 = crtc->y + crtc->height;
+}
+
+/* begin vtable methods */
+
+static bool _al_xsys_xrandr_query(ALLEGRO_SYSTEM_XGLX *s)
+{
+   int screen_count = ScreenCount(s->x11display);
+   int i;
+   bool ret = true;
+   
+   _al_vector_init(&s->xrandr_screens, sizeof(xrandr_screen));
+   _al_vector_reserve(&s->xrandr_screens, screen_count);
+   memset(s->xrandr_screens._items, 0, sizeof(xrandr_screen) * screen_count);
+   
+   _al_vector_init(&s->xrandr_adaptermap, sizeof(RROutput));
+   _al_vector_reserve(&s->xrandr_adaptermap, 4); // Seems like a good initial default
+   memset(s->xrandr_adaptermap._items, 0, sizeof(RROutput) * 4);
+   
+   for(i = 0; i < screen_count; i++) {
+      xrandr_screen *screen = _al_vector_alloc_back(&s->xrandr_screens);
+      
+      XRRScreenResources *res = XRRGetScreenResources(s->x11display, XRootWindow(s->x11display, i));
+      if(!res) {
+         ALLEGRO_DEBUG("failed to get screen resources for screen %i\n", i);
+         continue;
+      }
+      
+      if(!res->noutput) {
+         ALLEGRO_DEBUG("screen %i doesn't have any outputs.\n", i);
+         continue;
+      }
+      
+      _al_xsys_xrandr_copy_screen(s, screen, res);
+      
+      screen->res = res;
+      
+      unsigned int j;
+      // XXX test with cloned outputs... this won't work properly with clones
+      // clones should not show up as separate outputs.
+      for(j = 0; j < _al_vector_size(&screen->outputs); j++) {
+         xrandr_output *output = _al_vector_ref(&screen->outputs, j);
+         if(output->connection == RR_Connected) {
+            RROutput *oid = _al_vector_alloc_back(&s->xrandr_adaptermap);
+            *oid = output->id;
+         }
+      }
+      
+      int mask = RRScreenChangeNotifyMask | 
+              RRCrtcChangeNotifyMask   | 
+              RROutputChangeNotifyMask | 
+              RROutputPropertyNotifyMask;
+   
+      XRRSelectInput( s->x11display, RootWindow(s->x11display, i), 0);
+      XRRSelectInput( s->x11display, RootWindow(s->x11display, i), mask); 
+      
+   }
+   
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+   if (s->xinerama_available && s->xinerama_screen_count != (int)_al_vector_size(&s->xrandr_adaptermap)) {
+      ALLEGRO_WARN("XRandR and Xinerama seem to disagree on how many screens there are (%i vs %i), going to ignore XRandR.\n", (int)_al_vector_size(&s->xrandr_adaptermap), s->xinerama_screen_count);
+      // only actually going to ignore the output count, and setting of modes on the extra xinerama screens.
+      ret = false;
+   }
+#endif
+
+   return ret;
+}
+
+static int _al_xsys_xrandr_get_num_modes(ALLEGRO_SYSTEM_XGLX *s, int adapter)
+{
+   if(adapter < 0 || adapter >= (int)_al_vector_size(&s->xrandr_adaptermap))
+      return 0;
+   
+   int xscreen = _al_xglx_get_xscreen(s, adapter);
+   xrandr_output *output = _al_xsys_xrandr_map_adapter(s, xscreen, adapter);
+   return _al_vector_size(&output->modes);
+}
+
+static ALLEGRO_DISPLAY_MODE *_al_xsys_xrandr_get_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter, int id, ALLEGRO_DISPLAY_MODE *amode)
+{
+   if(adapter < 0 || adapter >= (int)_al_vector_size(&s->xrandr_adaptermap))
+      return NULL;
+   
+   int xscreen = _al_xglx_get_xscreen(s, adapter);
+   xrandr_output *output = _al_xsys_xrandr_map_adapter(s, xscreen, adapter);
+   
+   if(id < 0 || id > (int)_al_vector_size(&output->modes))
+      return NULL;
+      
+   RRMode *mp = (RRMode*)_al_vector_ref(&output->modes, id);
+   ALLEGRO_ASSERT(mp != NULL);
+   ALLEGRO_DEBUG("mode %i ptr==%p\n", id, mp);
+   xrandr_mode *mode = _al_xsys_xrandr_fetch_mode(s, xscreen, *(RRMode*)_al_vector_ref(&output->modes, id));
+   
+   amode->width = mode->width;
+   amode->height = mode->height;
+   amode->format = 0;
+   amode->refresh_rate = mode->refresh;
+   
+   return amode;
+}
+
+static bool _al_xsys_xrandr_set_mode(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, int w, int h, int format, int refresh)
+{
+   int adapter = _al_xglx_get_adapter(s, d, false);
+   int xscreen = _al_xglx_get_xscreen(s, adapter);
+   
+   if(adapter < 0 || adapter >= (int)_al_vector_size(&s->xrandr_adaptermap))
+      return false;
+   
+   xrandr_output *output = _al_xsys_xrandr_map_adapter(s, xscreen, adapter);
+   xrandr_crtc *crtc = _al_xsys_xrandr_fetch_crtc(s, xscreen, output->crtc);
+   xrandr_mode *cur_mode = _al_xsys_xrandr_fetch_mode(s, xscreen, crtc->mode);
+   
+   if((int)cur_mode->width == w && (int)cur_mode->height == h && (refresh == 0 || cur_mode->refresh)) {
+      ALLEGRO_DEBUG("mode already set, good to go\n");
+      return true;
+   }
+   else {
+      ALLEGRO_DEBUG("new mode: %dx%d@xxxxxxxxxx old mode: %dx%d@xxxxxxxxxx", w, h, refresh, cur_mode->width, cur_mode->height, cur_mode->refresh);
+   }
+   
+   int mode_idx = _al_xglx_fullscreen_select_mode(s, adapter, w, h, format, refresh);
+   if(mode_idx == -1) {
+      ALLEGRO_DEBUG("mode %dx%d@xxxxxxxxxx not found\n", w, h, refresh);
+      return false;
+   }
+   
+   xrandr_mode *mode = _al_xsys_xrandr_fetch_mode(s, xscreen, *(RRMode*)_al_vector_ref(&output->modes, mode_idx));
+   ALLEGRO_ASSERT(mode != NULL);
+   
+   xrandr_crtc *crtc_info = _al_xsys_xrandr_fetch_crtc(s, xscreen, output->crtc);
+   ALLEGRO_ASSERT(crtc_info != NULL);
+   ALLEGRO_DEBUG("xrandr: set mode %i+%i-%ix%i on adapter %i\n", crtc_info->x, crtc_info->y, w, h, adapter);
+   
+   xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, xscreen);
+   ALLEGRO_ASSERT(screen != NULL);
+   
+   _al_mutex_lock(&s->lock);
+   
+   int ok = XRRSetCrtcConfig(
+      s->x11display,
+      screen->res,
+      crtc_info->id,
+      crtc_info->timestamp,
+      crtc_info->x,
+      crtc_info->y,
+      mode->id,
+      crtc_info->rotation,
+      (RROutput*)crtc_info->connected._items,
+      _al_vector_size(&crtc_info->connected)
+   );
+   
+   if (ok != RRSetConfigSuccess) {
+      ALLEGRO_ERROR("XRandR failed to set mode.\n");
+      _al_mutex_unlock(&s->lock);
+      return false;
+   }
+   
+   /* make sure the virtual screen size is large enough after setting our mode */
+   int i;
+   struct xrandr_rect rect = { 0, 0, 0, 0 };
+   for(i = 0; i < (int)_al_vector_size(&screen->outputs); i++) {
+      xrandr_output *o = _al_vector_ref(&screen->outputs, i);
+      if(o->connection == RR_Connected) {
+         xrandr_crtc *crtc = _al_xsys_xrandr_fetch_crtc(s, xscreen, o->crtc);
+      
+         _al_xsys_xrandr_combine_output_rect(&rect, crtc);
+      }
+   }
+   
+   int new_width = rect.x2 - rect.x1;
+   int new_height = rect.y2 - rect.y1;
+   
+   if(new_width > DisplayWidth(s->x11display, xscreen) ||
+      new_height > DisplayHeight(s->x11display, xscreen))
+   {
+      XRRSetScreenSize(s->x11display,
+                       RootWindow(s->x11display, xscreen),
+                       new_width, new_height,
+                       DisplayWidthMM(s->x11display, xscreen),
+                       DisplayHeightMM(s->x11display, xscreen));
+   }
+   
+   _al_mutex_unlock(&s->lock);
+   
+   return true;
+}
+
+static void _al_xsys_xrandr_restore_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter)
+{
+   if(adapter < 0 || adapter >= (int)_al_vector_size(&s->xrandr_adaptermap))
+      return;
+   
+   int xscreen = _al_xglx_get_xscreen(s, adapter);
+   xrandr_output *output = _al_xsys_xrandr_map_adapter(s, xscreen, adapter);
+   
+   xrandr_crtc *crtc = _al_xsys_xrandr_fetch_crtc(s, xscreen, output->crtc);
+   
+   if(crtc->mode == crtc->original_mode) {
+      ALLEGRO_DEBUG("current crtc mode (%i) equals the original mode (%i), not restoring.\n", (int)crtc->mode, (int)crtc->original_mode);
+      return;
+   }
+   
+   xrandr_mode *orig_mode = _al_xsys_xrandr_fetch_mode(s, xscreen, crtc->original_mode);
+   
+   ALLEGRO_DEBUG("restore mode %i+%i-%ix%i@xxxxxxxxxx on adapter %i\n", crtc->x, crtc->y, orig_mode->width, orig_mode->height, orig_mode->refresh, adapter);
+   
+   xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, xscreen);
+   
+   _al_mutex_lock(&s->lock);
+   
+   int ok = XRRSetCrtcConfig
+   (
+      s->x11display,
+      screen->res,
+      crtc->id,
+      crtc->timestamp,
+      crtc->x,
+      crtc->y,
+      orig_mode->id,
+      crtc->rotation,
+      (RROutput*)crtc->connected._items,
+      _al_vector_size(&crtc->connected)
+   );
+   
+   if(ok != RRSetConfigSuccess) {
+      ALLEGRO_ERROR("failed to restore mode.\n");
+   }
+   
+   // XSync(s->x11display, False);
+   
+   _al_mutex_unlock(&s->lock);
+}
+
+static void _al_xsys_xrandr_get_display_offset(ALLEGRO_SYSTEM_XGLX *s, int adapter, int *x, int *y)
+{
+   if(adapter < 0 || adapter >= (int)_al_vector_size(&s->xrandr_adaptermap))
+      return;
+   
+   int xscreen = _al_xglx_get_xscreen(s, adapter);
+   xrandr_output *output = _al_xsys_xrandr_map_adapter(s, xscreen, adapter);
+   
+   xrandr_crtc *crtc = _al_xsys_xrandr_fetch_crtc(s, xscreen, output->crtc);
+   
+   // XXX Should we always return original_[xy]off here?
+   // When does a user want to query the offset after the modes are set?
+   
+   *x = crtc->x;
+   *y = crtc->y;
+   
+   ALLEGRO_DEBUG("display offset: %ix%i.\n", *x, *y);
+}
+
+static int _al_xsys_xrandr_get_num_adapters(ALLEGRO_SYSTEM_XGLX *s)
+{
+   return _al_vector_size(&s->xrandr_adaptermap);
+}
+
+static void _al_xsys_xrandr_get_monitor_info(ALLEGRO_SYSTEM_XGLX *s, int adapter, ALLEGRO_MONITOR_INFO *mi)
+{
+   if(adapter < 0 || adapter >= (int)_al_vector_size(&s->xrandr_adaptermap))
+      return;
+   
+   int xscreen = _al_xglx_get_xscreen(s, adapter);
+   xrandr_output *output = _al_xsys_xrandr_map_adapter(s, xscreen, adapter);
+   
+   xrandr_crtc *crtc = _al_xsys_xrandr_fetch_crtc(s, xscreen, output->crtc);
+   
+   mi->x1 = crtc->x;
+   mi->y1 = crtc->y;
+   mi->x2 = crtc->x + crtc->width;
+   mi->y2 = crtc->y + crtc->height;
+}
+
+static int _al_xsys_xrandr_get_default_adapter(ALLEGRO_SYSTEM_XGLX *s)
+{
+   // if we have more than one xrandr_screen, we're in multi-head x mode
+   if(_al_vector_size(&s->xrandr_screens) > 1)
+      return _al_xsys_mheadx_get_default_adapter(s);
+   
+   int center_x = 0, center_y = 0;
+   _al_xsys_get_active_window_center(s, &center_x, &center_y);
+   
+   int i, default_adapter = 0;
+   for(i = 0; i < (int)_al_vector_size(&s->xrandr_adaptermap); i++) {
+      xrandr_output *output = _al_xsys_xrandr_map_adapter(s, 0, i);
+      xrandr_crtc *crtc = _al_xsys_xrandr_fetch_crtc(s, 0, output->crtc);
+      
+      if(center_x >= (int)crtc->x && center_x <= (int)(crtc->x + crtc->width) &&
+         center_y >= (int)crtc->y && center_y <= (int)(crtc->y + crtc->height))
+      {
+         default_adapter = i;
+         break;
+      }
+   }
+   
+   ALLEGRO_DEBUG("selected default adapter: %i.\n", default_adapter);
+   
+   return default_adapter;
+}
+
+static int _al_xsys_xrandr_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter)
+{
+   // more than one screen means we have multi-head x mode
+   if(_al_vector_size(&s->xrandr_screens) > 1)
+      return _al_xsys_mheadx_get_xscreen(s, adapter);
+   
+   // Normal XRandR will normally give us one X screen, so return 0 always.
+   return 0;
+}
+
+static void _al_xsys_xrandr_handle_xevent(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, XEvent *e)
+{
+   if(e->type == s->xrandr_event_base + RRNotify) {
+      XRRNotifyEvent *rre = (XRRNotifyEvent*)e;
+      if(rre->subtype == RRNotify_CrtcChange) {
+         XRRCrtcChangeNotifyEvent *rrce = (XRRCrtcChangeNotifyEvent*)rre;
+         ALLEGRO_DEBUG("RRNotify_CrtcChange!\n");
+         
+         xrandr_crtc *crtc = _al_xsys_xrandr_fetch_crtc(s, d->xscreen, rrce->crtc);
+         if(!crtc) {
+            ALLEGRO_DEBUG("invalid RRCrtc(%i).\n", (int)rrce->crtc);
+            return;
+         }
+         
+         if(rrce->mode != crtc->mode) {
+            ALLEGRO_DEBUG("mode changed from %i to %i.\n", (int)crtc->mode, (int)rrce->mode);
+            crtc->mode = rrce->mode;
+         }
+         
+         if(rrce->rotation != crtc->rotation) {
+            ALLEGRO_DEBUG("rotation changed from %i to %i.\n", crtc->rotation, rrce->rotation);
+            crtc->rotation = rrce->rotation;
+         }
+         
+         if(rrce->x != crtc->x || rrce->y != crtc->y) {
+            ALLEGRO_DEBUG("origin changed from %i+%i to %i+%i.\n", crtc->x, crtc->y, rrce->x, rrce->y);
+            crtc->x = rrce->x;
+            crtc->y = rrce->y;
+         }
+         
+         if(rrce->width != crtc->width || rrce->height != crtc->height) {
+            ALLEGRO_DEBUG("size changed from %ix%i to %ix%i.\n", crtc->width, crtc->height, rrce->width, rrce->height);
+            crtc->width = rrce->width;
+            crtc->height = rrce->height;
+         }
+         
+         xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, d->xscreen);
+         crtc->timestamp = screen->timestamp;
+         
+      } else
+      if(rre->subtype == RRNotify_OutputChange) {
+         XRROutputChangeNotifyEvent *rroe = (XRROutputChangeNotifyEvent*)rre;
+                                                      
+         xrandr_output *output = _al_xsys_xrandr_fetch_output(s, d->xscreen, rroe->output);
+         if(!output) {
+            ALLEGRO_DEBUG("invalid RROutput(%i).\n", (int)rroe->output);
+            return;
+         }
+         
+         ALLEGRO_DEBUG("xrandr: RRNotify_OutputChange %s!\n", output->name);
+         
+         if(rroe->crtc != output->crtc) {
+            ALLEGRO_DEBUG("crtc changed from %i to %i.\n", (int)output->crtc, (int)rroe->crtc);
+            output->crtc = rroe->crtc;
+         }
+         
+         if(rroe->connection != output->connection) {
+            ALLEGRO_DEBUG("connection changed from %i to %i.\n", output->connection, rroe->connection);
+            output->connection = rroe->connection;
+         }
+         
+         xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, d->xscreen);
+         output->timestamp = screen->timestamp;
+         
+      } else
+      if(rre->subtype == RRNotify_OutputProperty) {
+         ALLEGRO_DEBUG("xrandr: RRNotify_OutputProperty!\n");
+      }
+      else {
+         ALLEGRO_DEBUG("xrandr: RRNotify_Unknown(%i)!\n", rre->subtype);  
+      }
+      
+   } else
+   if(e->type == s->xrandr_event_base + RRScreenChangeNotify) {
+      XRRScreenChangeNotifyEvent *rre = (XRRScreenChangeNotifyEvent*)e;
+      XRRUpdateConfiguration( e );
+      
+      ALLEGRO_DEBUG("RRScreenChangeNotify!\n");
+      
+      /* XXX I don't think we need to actually handle this event fully,
+       * it only really deals with the virtual screen as a whole it seems
+       * The interesting changes get sent with the RRNotify event.
+       */
+
+      /* update the timestamps */
+      xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, d->xscreen);
+      screen->timestamp = rre->timestamp;
+      screen->configTimestamp = rre->config_timestamp;
+   }
+}
+
+/* begin "public" ctor/dtor methods */
+
+void _al_xsys_xrandr_init(ALLEGRO_SYSTEM_XGLX *s)
+{
+   int error_base = 0;
+   
+   _al_mutex_lock(&s->lock);
+   
+   if (XRRQueryExtension(s->x11display, &s->xrandr_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");
+      }
+      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");
+   }
+
+   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.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;
+      mmon_interface.get_default_adapter   = _al_xsys_xrandr_get_default_adapter;
+      mmon_interface.get_xscreen           = _al_xsys_xrandr_get_xscreen;
+      mmon_interface.handle_xevent         = _al_xsys_xrandr_handle_xevent;
+      
+   }
+
+   _al_mutex_unlock(&s->lock);
+}
+
+void _al_xsys_xrandr_exit(ALLEGRO_SYSTEM_XGLX *s)
+{
+#if 0
+   // int i;
+   ALLEGRO_DEBUG("XRandR exiting.\n");
+   
+   // for (i = 0; i < s->xrandr_output_count; i++) {
+   //   XRRFreeOutputInfo(s->xrandr_outputs[i]);
+   // }
+
+   // for (i = 0; i < s->xrandr_res_count; i++) {
+   //    XRRFreeScreenResources(s->xrandr_res[i]);
+   // }
+
+   ALLEGRO_DEBUG("XRRFreeScreenResources\n");
+   //if (s->xrandr_res)
+   //   XRRFreeScreenResources(s->xrandr_res);
+
+   al_free(s->xrandr_outputs);
+   al_free(s->xrandr_res);
+   
+   s->xrandr_available = 0;
+   s->xrandr_res_count = 0;
+   s->xrandr_res = NULL;
+   s->xrandr_output_count = 0;
+   s->xrandr_outputs = NULL;
+
+   ALLEGRO_DEBUG("XRandR exit finished.\n");
+#endif /* 0 */
+
+   int i;
+   for(i = 0; i < (int)_al_vector_size(&s->xrandr_screens); i++) {
+      xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, i);
+      int j;
+      
+      for(j = 0; j < (int)_al_vector_size(&screen->outputs); j++) {
+         xrandr_output *output = _al_vector_ref(&screen->outputs, j);
+         free(output->name);
+      }
+      
+      _al_vector_free(&screen->crtcs);
+      _al_vector_free(&screen->outputs);
+      _al_vector_free(&screen->modes);
+      
+      XRRFreeScreenResources(screen->res);
+      screen->res = NULL;
+      
+   }
+
+   _al_vector_free(&s->xrandr_screens);
+   _al_vector_free(&s->xrandr_adaptermap);
+   
+}
+
+#endif /* ALLEGRO_XWINDOWS_WITH_XRANDR */
+
Index: src/x/xfullscreen.c
===================================================================
--- src/x/xfullscreen.c	(revision 14262)
+++ src/x/xfullscreen.c	(working copy)
@@ -3,25 +3,162 @@
 
 ALLEGRO_DEBUG_CHANNEL("display")
 
-typedef struct _ALLEGRO_XGLX_MMON_INTERFACE _ALLEGRO_XGLX_MMON_INTERFACE;
+/* globals - this might be better in ALLEGRO_SYSTEM_XGLX */
+_ALLEGRO_XGLX_MMON_INTERFACE 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 *);
-};
+/* generic multi-head x */
+int _al_xsys_mheadx_get_default_adapter(ALLEGRO_SYSTEM_XGLX *s)
+{
+   int i;
+ 
+   ALLEGRO_DEBUG("mhead get default adapter\n");
+   
+   if(ScreenCount(s->x11display) == 1)
+      return 0;
 
+   _al_mutex_lock(&s->lock);
+   
+   Window focus;
+   int revert_to = 0;
+   XWindowAttributes attr;
+   Screen *focus_screen;
 
-/* globals - this might be better in ALLEGRO_SYSTEM_XGLX */
-static _ALLEGRO_XGLX_MMON_INTERFACE mmon_interface;
+   if(!XGetInputFocus(s->x11display, &focus, &revert_to)) {
+      ALLEGRO_ERROR("XGetInputFocus failed!");
+		_al_mutex_unlock(&s->lock);
+      return 0;
+   }
+   
+   if(focus == None) {
+      ALLEGRO_ERROR("XGetInputFocus returned None!\n");
+		_al_mutex_unlock(&s->lock);
+      return 0;
+   } else
+   if(focus == PointerRoot) {
+      ALLEGRO_DEBUG("XGetInputFocus returned PointerRoot.\n");
+      /* XXX TEST THIS >:( */
+      Window root, child;
+      int root_x, root_y;
+      int win_x, win_y;
+      unsigned int mask;
+      
+      if(XQueryPointer(s->x11display, focus, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask) == False) {
+         ALLEGRO_ERROR("XQueryPointer failed :(");
+			_al_mutex_unlock(&s->lock);
+         return 0;
+      }
+      
+      focus = root;
 
+   }
+   else {
+      ALLEGRO_DEBUG("XGetInputFocus returned %i!\n", (int)focus);
+   }
+   
+   XGetWindowAttributes(s->x11display, focus, &attr);
+   focus_screen = attr.screen;
+   
+	int ret = 0;
+   for(i = 0; i < ScreenCount(s->x11display); i++) {
+      if(ScreenOfDisplay(s->x11display, i) == focus_screen) {
+         _al_mutex_unlock(&s->lock);
+         ret = i;
+         break;
+      }
+   }
+   
+   _al_mutex_unlock(&s->lock);
+   return ret;
+}
 
+/* in pure multi-head mode, allegro's virtual adapters map directly to X Screens. */
+int _al_xsys_mheadx_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter)
+{
+   (void)s;
+   ALLEGRO_DEBUG("mhead get screen %i\n", adapter);
+   return adapter;
+}
 
+/*
+Returns the parent window of "window" (i.e. the ancestor of window
+that is a direct child of the root, or window itself if it is a direct child).
+If window is the root window, returns window.
+*/
+Window _al_xsys_get_toplevel_parent(ALLEGRO_SYSTEM_XGLX *s, Window window)
+{
+   Window parent;
+   Window root;
+   Window * children;
+   unsigned int num_children;
+
+   while (1) {
+      /* XXX enlightenment shows some very strange errors here,
+       * for some reason 'window' isn't valid when the mouse happens
+       * to be over the windeco when this is called.. */
+      if (0 == XQueryTree(s->x11display, window, &root, &parent, &children, &num_children)) {
+         ALLEGRO_ERROR("XQueryTree error\n");
+         return None;
+      }
+      if (children) { /* must test for NULL */
+         XFree(children);
+      }
+      if (window == root || parent == root) {
+         return window;
+      }
+      else {
+         window = parent;
+      }
+   }
+   
+   return None;
+}
+
+/* used for xinerama and pure xrandr modes */
+void _al_xsys_get_active_window_center(ALLEGRO_SYSTEM_XGLX *s, int *x, int *y)
+{
+   Window focus;
+   int revert_to = 0;
+   
+   _al_mutex_lock(&s->lock);
+   
+   if(!XGetInputFocus(s->x11display, &focus, &revert_to)) {
+      ALLEGRO_ERROR("XGetInputFocus failed!\n");
+		_al_mutex_unlock(&s->lock);
+      return;
+   }
+   
+   if(focus == None || focus == PointerRoot) {
+      ALLEGRO_DEBUG("XGetInputFocus returned special window, selecting default root!\n");
+      focus = DefaultRootWindow(s->x11display);
+   }
+   else {
+      /* this horribleness is due to toolkits like GTK (and probably Qt) creating
+       * a 1x1 window under the window you're looking at that actually accepts
+       * all input, so we need to grab the top level parent window rather than
+       * whatever happens to have focus */
+   
+      focus = _al_xsys_get_toplevel_parent(s, focus);
+   }
+   
+   ALLEGRO_DEBUG("XGetInputFocus returned %i\n", (int)focus);
+   
+   XWindowAttributes attr;
+   
+   if(XGetWindowAttributes(s->x11display, focus, &attr) == 0) {
+      ALLEGRO_ERROR("XGetWindowAttributes failed :(\n");
+      _al_mutex_unlock(&s->lock);
+      return;
+   }
+
+   _al_mutex_unlock(&s->lock);
+   
+   /* check the center of the window with focus
+    * might be a bit more useful than just checking the top left */
+   ALLEGRO_DEBUG("focus geom: %ix%i %ix%i\n", attr.x, attr.y, attr.width, attr.height);
+   *x = (attr.x + (attr.x + attr.width)) / 2;
+   *y = (attr.y + (attr.y + attr.height)) / 2;  
+}
+
 /*---------------------------------------------------------------------------
  *
  * Xinerama
@@ -88,6 +225,7 @@
    ALLEGRO_ASSERT(adapter >= 0 && adapter < s->xinerama_screen_count);
    *x = s->xinerama_screen_info[adapter].x_org;
    *y = s->xinerama_screen_info[adapter].y_org;
+   ALLEGRO_DEBUG("xinerama dpy off %ix%i\n", *x, *y);
 }
 
 static void _al_xsys_xinerama_get_monitor_info(ALLEGRO_SYSTEM_XGLX *s, int adapter, ALLEGRO_MONITOR_INFO *mi)
@@ -101,6 +239,52 @@
    mi->y2 = mi->y1 + s->xinerama_screen_info[adapter].height;
 }
 
+static ALLEGRO_DISPLAY_MODE *_al_xsys_xinerama_get_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter, int i, ALLEGRO_DISPLAY_MODE *mode)
+{
+   if (adapter < 0 || adapter >= s->xinerama_screen_count)
+      return NULL;
+   
+   if(i != 0)
+      return NULL;
+   
+   mode->width = s->xinerama_screen_info[adapter].width;
+   mode->height = s->xinerama_screen_info[adapter].height;
+   mode->format = 0;
+   mode->refresh_rate = 0;
+   
+   return mode;
+}
+
+static int _al_xsys_xinerama_get_default_adapter(ALLEGRO_SYSTEM_XGLX *s)
+{
+   int center_x = 0, center_y = 0;
+   ALLEGRO_DEBUG("xinerama get default adapter\n");
+   
+   _al_xsys_get_active_window_center(s, &center_x, &center_y);
+   ALLEGRO_DEBUG("xinerama got active center: %ix%i\n", center_x, center_y);
+   
+   int i;
+   for(i = 0; i < s->xinerama_screen_count; i++) {
+      if(center_x >= s->xinerama_screen_info[i].x_org && center_x <= s->xinerama_screen_info[i].x_org + s->xinerama_screen_info[i].width &&
+         center_y >= s->xinerama_screen_info[i].y_org && center_y <= s->xinerama_screen_info[i].y_org + s->xinerama_screen_info[i].height)
+      {
+         ALLEGRO_DEBUG("center is inside (%i) %ix%i %ix%i\n", i, s->xinerama_screen_info[i].x_org, s->xinerama_screen_info[i].y_org, s->xinerama_screen_info[i].width, s->xinerama_screen_info[i].height);
+         return i;
+      }
+   }
+   
+   ALLEGRO_DEBUG("xinerama returning default 0\n");
+   return 0;
+}
+
+/* similar to multi-head x, but theres only one X Screen, so we return 0 always */
+static int _al_xsys_xinerama_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter)
+{
+   (void)s;
+   (void)adapter;
+   return 0;
+}
+
 #endif /* ALLEGRO_XWINDOWS_WITH_XINERAMA */
 
 
@@ -113,99 +297,166 @@
 
 #ifdef ALLEGRO_XWINDOWS_WITH_XRANDR
 
+#if 0
 static bool _al_xsys_xrandr_query(ALLEGRO_SYSTEM_XGLX *s)
 {
    XRRScreenResources *res = NULL;
    bool ret = 0;
-
-   if (s->xrandr_res) {
-      XRRFreeScreenResources(s->xrandr_res);
-   }
-
+   int xscr = 0;
+   int res_idx = 0;
+   RRMode *modes = NULL;
+   RRMode *set_modes = NULL;
+   
    if (s->xrandr_outputs) {
       int i;
+      modes = al_calloc(s->xrandr_output_count, sizeof(RRMode));
+      if(!modes)
+         return false;
+      
+      set_modes = al_calloc(s->xrandr_output_count, sizeof(RRMode));
+      if(!set_modes)
+         return false;
+      
       for (i = 0; i < s->xrandr_output_count; i++) {
-         XRRFreeOutputInfo(s->xrandr_outputs[i]);
-         s->xrandr_outputs[i] = NULL;
+         XRRFreeOutputInfo(s->xrandr_outputs[i]->output);
+         s->xrandr_outputs[i]->output = NULL;
+         modes[i] = s->xrandr_outputs[i]->mode;
+         set_modes[i] = s->xrandr_outputs[i]->set_mode;
       }
       al_free(s->xrandr_outputs);
       s->xrandr_outputs = NULL;
       s->xrandr_output_count = 0;
    }
 
+   if(s->xrandr_res) {
+      for(res_idx = 0; res_idx < s->xrandr_res_count; res_idx++) {
+         XRRFreeScreenResources(s->xrandr_res[res_idx]);
+      }
+      free(s->xrandr_res);
+   }
+   
    /* XXX This causes an annoying flicker with the intel driver and a secondary
     * display (at least) so should be deferred until required.
     */
-   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;
-         }
+   s->xrandr_res = al_calloc(ScreenCount(s->x11display), sizeof(*s->xrandr_res));
+   if(!s->xrandr_res) {
+      ALLEGRO_ERROR("xrandr: failed to allocate array for XRRScreenResources structures.\n");
+      return 0;
+   }
 
-         ALLEGRO_DEBUG("xrandr: got crtc %d.\n", ncrtc);
+   s->xrandr_res_count = ScreenCount(s->x11display);
+   
+   s->xrandr_output_count = 0; // just in case
+   for(xscr = 0; xscr < ScreenCount(s->x11display); xscr++) {
 
-         if (crtc_info->noutput > 0) {
-            XRROutputInfo **new_output_info = s->xrandr_outputs;
-            int new_output_count = s->xrandr_output_count + crtc_info->noutput;
+      res = s->xrandr_res[xscr] = XRRGetScreenResources (s->x11display, XRootWindow(s->x11display, xscr));
+      if (res && res->nmode) {
+         
+         // 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;
+            }
 
-            new_output_info = al_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);
+            ALLEGRO_DEBUG("xrandr: got crtc %d (%i+%i-%ix%i).\n", ncrtc, crtc_info->x, crtc_info->y, crtc_info->width, crtc_info->height);
 
-               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;
+            if (crtc_info->noutput > 0) {
+               struct xrandr_output_s **new_output_info = s->xrandr_outputs;
+               int new_output_count = s->xrandr_output_count + crtc_info->noutput;
+
+               new_output_info = al_realloc(new_output_info, sizeof(s->xrandr_outputs) * new_output_count);
+               if (new_output_info) {
+                  memset(new_output_info+s->xrandr_output_count, 0, sizeof(s->xrandr_outputs)*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] = al_calloc(1, sizeof(**s->xrandr_outputs));
+                     if(!new_output_info[s->xrandr_output_count + nout]) {
+                        ALLEGRO_ERROR("xrandr: failed to allocate output structure.\n");
+                        continue;
+                     }
+                     
+                     new_output_info[s->xrandr_output_count + nout]->output = info;
+                     new_output_info[s->xrandr_output_count + nout]->res_id = xscr;
+                     
+                     if(modes) {
+                        new_output_info[s->xrandr_output_count + nout]->mode = modes[s->xrandr_output_count + nout];
+                     }
+                     
+                     if(set_modes) {
+                        new_output_info[s->xrandr_output_count + nout]->set_mode = set_modes[s->xrandr_output_count + nout];
+                     }
                   }
 
-                  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;
+               }
+            }
 
-               s->xrandr_outputs = new_output_info;
-               s->xrandr_output_count = new_output_count;
+            XRRFreeCrtcInfo(crtc_info);
+         }
 
+         if (s->xrandr_output_count > 0) {
+            
+            ret = 1;
+            
+   #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);
+               // only actually going to ignore the output count, and setting of modes on the extra xinerama screens.
+               ret = 0;
             }
-            else {
-               ALLEGRO_ERROR("xrandr: failed to allocate array for output structures.\n");
-               continue;
-            }
+   #else
+            // XXX verify xrandr isn't borked here because of stupidity
+            // XXX  like the nvidia binary driver only implementing XRandR 1.1
+   #endif
+
          }
-
-         XRRFreeCrtcInfo(crtc_info);
+         else {
+            ALLEGRO_WARN("XRandR has no outputs.\n");
+            ret = 0;
+         }
       }
 
-      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);
-            // only actually going to ignore the output count, and setting of modes on the extra xinerama screens.
-         }
-#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;
-      }
    }
 
+   ALLEGRO_DEBUG("xrandr: found %d outputs.\n",s->xrandr_output_count);
+
+   al_free(modes);
+   al_free(set_modes);
+   
    return ret;
 }
 
+static XRRModeInfo *_al_xsys_xrandr_fetch_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter, RRMode id)
+{
+   int i;
+   XRRScreenResources *res = s->xrandr_res[s->xrandr_outputs[adapter]->res_id];
+   
+   for(i = 0; i < res->nmode; i++) {
+      if(res->modes[i].id == id)
+         return &res->modes[i];
+   }
+   
+   return NULL;
+}
+
 // 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)
@@ -213,7 +464,7 @@
    if (adapter < 0 || adapter >= s->xrandr_output_count)
       return 0;
 
-   return s->xrandr_outputs[adapter]->nmode;
+   return s->xrandr_outputs[adapter]->output->nmode;
 }
 
 static ALLEGRO_DISPLAY_MODE *_al_xsys_xrandr_get_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter, int id, ALLEGRO_DISPLAY_MODE *mode)
@@ -224,9 +475,13 @@
       return 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];
+
+   /* should we validate res_id here? only way it would be invalid is if the array got stomped on... so a crash would be imminent anyhow */
+   XRRScreenResources *res = s->xrandr_res[s->xrandr_outputs[adapter]->res_id];
+   
+   for (i = 0; i < res->nmode; i++) {
+      if (res->modes[i].id == s->xrandr_outputs[adapter]->output->modes[id]) {
+         mi = &res->modes[i];
          break;
       }
    }
@@ -244,50 +499,95 @@
       mode->refresh_rate = 0;
    }
 
-   ALLEGRO_INFO("XRandR got mode: %dx%d@xxxxxxxxxx", mode->width, mode->height, mode->refresh_rate);
+   //ALLEGRO_INFO("xrandr: got mode %dx%d@xxxxxxxxxx", mode->width, mode->height, mode->refresh_rate);
 
    return mode;
 }
 
+struct xrr_rect {
+   int x1;
+   int y1;
+   int x2;
+   int y2;
+};
+
+static void _al_xsys_xrandr_combine_output_rect(struct xrr_rect *r1, XRRCrtcInfo *crtc)
+{
+   if(r1->x1 > crtc->x)
+      r1->x1 = crtc->x;
+   
+   if(r1->y1 > crtc->y)
+      r1->y1 = crtc->y;
+   
+   if(crtc->x + crtc->width > r1->x2)
+      r1->x2 = crtc->x + crtc->width;
+   
+   if(crtc->y + crtc->height > r1->y2)
+      r1->y2 = crtc->y + crtc->height;
+
+}
+
 static bool _al_xsys_xrandr_set_mode(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, int w, int h, int format, int refresh)
 {
    int mode_idx = -1;
    XRRModeInfo *mi = NULL;
-
-   if (d->xscreen < 0 || d->xscreen >= s->xrandr_output_count)
+   XRRScreenResources *res = NULL;
+   
+   int adapter = _al_xglx_get_adapter(s, d, false);
+   if (adapter < 0 || adapter >= s->xrandr_output_count)
       return false;
+   
+   _al_mutex_lock(&s->lock);
 
-   XRRModeInfo *cur_mode = s->xrandr_stored_modes[d->xscreen];
+   //XSync(s->x11display, False);
+   
+   /* if we have already set the mode once, look that up, if not, use the original mode */
+   XRRModeInfo *cur_mode = _al_xsys_xrandr_fetch_mode(s, adapter, s->xrandr_outputs[adapter]->set_mode ? s->xrandr_outputs[adapter]->set_mode : s->xrandr_outputs[adapter]->mode);
    int cur_refresh_rate;
    if (cur_mode->hTotal && cur_mode->vTotal)
       cur_refresh_rate = ((float) cur_mode->dotClock / ((float) cur_mode->hTotal * (float) cur_mode->vTotal));
    else
       cur_refresh_rate = 0;
-   if ((int)cur_mode->width == w && (int)cur_mode->height == h && cur_refresh_rate == refresh) {
+   if ((int)cur_mode->width == w && (int)cur_mode->height == h && (refresh == 0 || cur_refresh_rate == refresh)) {
       ALLEGRO_DEBUG("xrandr: mode already set, we're good to go.\n");
+      _al_mutex_unlock(&s->lock);
       return true;
    }
    else {
       ALLEGRO_DEBUG("xrandr: new mode: %dx%d@xxxxxxxxxx old mode: %dx%d@xxxxxxxxxx", w,h,refresh, cur_mode->width, cur_mode->height, cur_refresh_rate);
    }
    
-   mode_idx = _al_xglx_fullscreen_select_mode(s, d->xscreen, w, h, format, refresh);
+   mode_idx = _al_xglx_fullscreen_select_mode(s, adapter, w, h, format, refresh);
    if (mode_idx == -1) {
       ALLEGRO_DEBUG("xrandr: mode %dx%d@xxxxxxxxxx not found.\n", w,h,refresh);
+      _al_mutex_unlock(&s->lock);
       return false;
    }
 
-   mi = &s->xrandr_res->modes[mode_idx];
+   res = s->xrandr_res[s->xrandr_outputs[adapter]->res_id];
 
-   _al_mutex_lock(&s->lock);
+   int i;
+   for (i = 0; i < res->nmode; i++) {
+      if (res->modes[i].id == s->xrandr_outputs[adapter]->output->modes[mode_idx]) {
+         mi = &res->modes[i];
+         break;
+      }
+   }
 
    // 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);
+   XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, res, s->xrandr_outputs[adapter]->output->crtc);
 
+   ALLEGRO_DEBUG("xrandr: set mode %i+%i-%ix%i on adapter %i\n", crtc_info->x, crtc_info->y, w, h, adapter);
+   
+   int xscr = s->xrandr_outputs[adapter]->res_id;
+   
+   ALLEGRO_DEBUG("xrandr: screen size: %ix%i\n", DisplayWidth(s->x11display, xscr),
+                     DisplayHeight(s->x11display, xscr));
+   
    // 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,
+   int ok = XRRSetCrtcConfig(s->x11display, res,
+                    s->xrandr_outputs[adapter]->output->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
@@ -297,47 +597,84 @@
                     crtc_info->rotation,
                     crtc_info->outputs,
                     crtc_info->noutput);
+   
+   /* now make sure the framebuffer is large enough */
+   int output;
+   struct xrr_rect rect = { 0, 0, 0, 0 };
+   for(output = 0; output < s->xrandr_output_count; output++) {
+      XRRCrtcInfo *crtc;
+      XRRScreenResources *r = s->xrandr_res[s->xrandr_outputs[output]->res_id];
+      if(output != adapter)
+         crtc = XRRGetCrtcInfo(s->x11display, r, s->xrandr_outputs[adapter]->output->crtc);
+      else
+         crtc = crtc_info;
+      
+      _al_xsys_xrandr_combine_output_rect(&rect, crtc);
+      
+      XRRFreeCrtcInfo(crtc);
+   }
 
-   XRRFreeCrtcInfo(crtc_info);
-
-   XFlush(s->x11display);
+   int new_width = rect.x2 - rect.x1;
+   int new_height = rect.y2 - rect.y1;
+   
+   if(new_width > DisplayWidth(s->x11display, xscr) ||
+      new_height > DisplayWidth(s->x11display, xscr))
+   {
+      XRRSetScreenSize (s->x11display,
+                     RootWindow(s->x11display, xscr),
+                     new_width, new_height,
+                     DisplayWidthMM(s->x11display, xscr),
+                     DisplayHeightMM(s->x11display, xscr));
+   }
+   
+   ALLEGRO_DEBUG("xrandr: screen size: %ix%i\n", DisplayWidth(s->x11display, xscr),
+                     DisplayHeight(s->x11display, xscr));
+   
+   //XSync(s->x11display, False);
+   
    _al_mutex_unlock(&s->lock);
 
    if (ok != 0) {
       ALLEGRO_ERROR("XRandR failed to set mode.\n");
       return false;
    }
-
+   
+   s->xrandr_outputs[adapter]->set_mode = mi->id;
+   
    return true;
 }
 
 static void _al_xsys_xrandr_store_modes(ALLEGRO_SYSTEM_XGLX *s)
 {
-   al_free(s->xrandr_stored_modes);
-   s->xrandr_stored_modes = al_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;
+	
+	_al_mutex_lock(&s->lock);
+	
    for (i = 0; i < s->xrandr_output_count; i++) {
-      XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, s->xrandr_res, s->xrandr_outputs[i]->crtc);
-
+      XRRScreenResources *res = s->xrandr_res[s->xrandr_outputs[i]->res_id];
+      
+      XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, res, s->xrandr_outputs[i]->output->crtc);
+      ALLEGRO_DEBUG("xrandr: got %i modes.\n",  res->nmode);
+      
       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];
+      for (j = 0; j < res->nmode; j++) {
+         ALLEGRO_DEBUG("xrandr: modecmp %i == %i.\n", (int)res->modes[j].id, (int)crtc_info->mode);
+         if (res->modes[j].id == crtc_info->mode) {
+            ALLEGRO_DEBUG("xrandr: matched mode!\n");
+            s->xrandr_outputs[i]->mode = res->modes[j].id;
+            break;
          }
       }
 
       XRRFreeCrtcInfo(crtc_info);
 
-      if (!s->xrandr_stored_modes[i]) {
+      if (!s->xrandr_outputs[i]->mode) {
          ALLEGRO_WARN("XRandR failed to store mode for adapter %d.\n", i);
       }
    }
+   
+   _al_mutex_unlock(&s->lock);
 }
 
 static void _al_xsys_xrandr_restore_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter)
@@ -345,31 +682,33 @@
    if (adapter < 0 || adapter >= s->xrandr_output_count)
       return;
    
-   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);
+   XRRModeInfo *mode = _al_xsys_xrandr_fetch_mode(s, adapter, s->xrandr_outputs[adapter]->mode);
+   ASSERT(mode);
+   ALLEGRO_DEBUG("xfullscreen: _al_xsys_xrandr_restore_mode (%d, %d)\n", mode->width, mode->height);
 
-   XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, s->xrandr_res, s->xrandr_outputs[adapter]->crtc);
+   XRRScreenResources *res = s->xrandr_res[s->xrandr_outputs[adapter]->res_id];
+	
+	_al_mutex_lock(&s->lock);
+	
+   XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, res, s->xrandr_outputs[adapter]->output->crtc);
    if (!crtc_info) {
+		_al_mutex_unlock(&s->lock);
       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;
-   }
+   
+   ALLEGRO_DEBUG("xrandr: restore mode %i+%i-%ix%i on adapter %i\n", crtc_info->x, crtc_info->y, mode->width, mode->height, adapter);
+   
    // actually changes the mode, what a name.
    int ok = XRRSetCrtcConfig(s->x11display,
-                    s->xrandr_res,
-                    s->xrandr_outputs[adapter]->crtc,
+                    res,
+                    s->xrandr_outputs[adapter]->output->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!
+                    mode->id, // Set the Mode!
                     crtc_info->rotation,
                     crtc_info->outputs,
                     crtc_info->noutput);
@@ -381,24 +720,37 @@
    }
 
    XFlush(s->x11display);
+
+   _al_mutex_unlock(&s->lock);
+   
+   s->xrandr_outputs[adapter]->set_mode = mode->id;
+    
 }
 
 static void _al_xsys_xrandr_get_display_offset(ALLEGRO_SYSTEM_XGLX *s, int adapter, int *x, int *y)
 {
 #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
-   if (s->xinerama_available) {
-      _al_xsys_xinerama_get_display_offset(s, adapter, x, y);
-   } else
+   //if (s->xinerama_available) {
+   //   _al_xsys_xinerama_get_display_offset(s, adapter, x, y);
+   //} else
 #endif
    {
-      XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, s->xrandr_res, s->xrandr_outputs[adapter]->crtc);
+      XRRScreenResources *res = s->xrandr_res[s->xrandr_outputs[adapter]->res_id];
+		
+		_al_mutex_lock(&s->lock);
+		
+      XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, res, s->xrandr_outputs[adapter]->output->crtc);
       if (!crtc_info) {
+			_al_mutex_unlock(&s->lock);
          ALLEGRO_ERROR("XRandR failed to get CrtcInfo, can't get display offset.\n");
          return;
       }
 
+		_al_mutex_unlock(&s->lock);
+		
       *x = crtc_info->x;
       *y = crtc_info->y;
+      ALLEGRO_DEBUG("xrandr: display offset: %ix%i.\n", *x, *y);
       XRRFreeCrtcInfo(crtc_info);
    }
 }
@@ -406,9 +758,9 @@
 static int _al_xsys_xrandr_get_num_adapters(ALLEGRO_SYSTEM_XGLX *s)
 {
 #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
-   if (s->xinerama_available) {
-      return s->xinerama_screen_count;
-   }
+  //if (s->xinerama_available) {
+   //   return s->xinerama_screen_count;
+   //}
 #endif
 
    return s->xrandr_output_count;
@@ -417,18 +769,25 @@
 static void _al_xsys_xrandr_get_monitor_info(ALLEGRO_SYSTEM_XGLX *s, int adapter, ALLEGRO_MONITOR_INFO *monitor_info)
 {
 #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
-   if (s->xinerama_available) {
-      _al_xsys_xinerama_get_monitor_info(s, adapter, monitor_info);
-      return;
-   }
+   //if (s->xinerama_available) {
+   //   _al_xsys_xinerama_get_monitor_info(s, adapter, monitor_info);
+   //   return;
+   //}
 #endif
 
-   XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, s->xrandr_res, s->xrandr_outputs[adapter]->crtc);
+   XRRScreenResources *res = s->xrandr_res[s->xrandr_outputs[adapter]->res_id];
+	
+	_al_mutex_lock(&s->lock);
+	
+   XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, res, s->xrandr_outputs[adapter]->output->crtc);
    if (!crtc_info) {
+		_al_mutex_unlock(&s->lock);
       ALLEGRO_ERROR("XRandR failed to get CrtcInfo, can't get monitor info.\n");
       return;
    }
 
+	_al_mutex_unlock(&s->lock);
+
    monitor_info->x1 = crtc_info->x;
    monitor_info->y1 = crtc_info->y;
    monitor_info->x2 = crtc_info->x + crtc_info->width;
@@ -437,6 +796,62 @@
    XRRFreeCrtcInfo(crtc_info);
 }
 
+static int _al_xsys_xrandr_get_default_adapter(ALLEGRO_SYSTEM_XGLX *s)
+{
+   ALLEGRO_DEBUG("xrandr get default adapter\n");
+   
+   /* if we have more than one res, means we're in hybrid multi-head X + xrandr mode
+    * use multi-head X code to get default adapter */
+   if(s->xrandr_res_count > 1)
+      return _al_xsys_mheadx_get_default_adapter(s);
+   
+   int center_x = 0, center_y = 0;
+   _al_xsys_get_active_window_center(s, &center_x, &center_y);
+   
+   int i, default_adapter = 0;
+	
+	_al_mutex_lock(&s->lock);
+	
+   for(i = 0; i < s->xrandr_output_count; i++) {
+      XRRScreenResources *res = s->xrandr_res[s->xrandr_outputs[i]->res_id];
+      XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, res, s->xrandr_outputs[i]->output->crtc);
+      if(center_x >= (int)crtc_info->x && center_x <= (int)(crtc_info->x + crtc_info->width) &&
+         center_y >= (int)crtc_info->y && center_y <= (int)(crtc_info->y + crtc_info->height))
+      {
+         default_adapter = i;
+			break;
+      }
+   }
+   
+   _al_mutex_unlock(&s->lock);
+	
+   ALLEGRO_DEBUG("xrandr selected default: %i\n", default_adapter);
+   
+   return default_adapter;
+}
+
+static int _al_xsys_xrandr_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter)
+{
+   ALLEGRO_DEBUG("xrandr get xscreen for adapter %i\n", adapter);
+   if(s->xrandr_res_count > 1)
+      return _al_xsys_mheadx_get_xscreen(s, adapter);
+   
+   ALLEGRO_DEBUG("xrandr selected default xscreen (ScreenCount:%i res_count:%i)\n", ScreenCount(s->x11display), s->xrandr_res_count);
+   /* should always only be one X Screen with normal xrandr */
+   return 0;
+}
+
+static void _al_xsys_xrandr_create_display(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d)
+{
+   int mask = RRScreenChangeNotifyMask | 
+              RRCrtcChangeNotifyMask   | 
+              RROutputChangeNotifyMask | 
+              RROutputPropertyNotifyMask;
+   
+   XRRSelectInput( s->x11display, d->window, 0);
+   XRRSelectInput( s->x11display, d->window, mask); 
+}
+
 static void _al_xsys_xrandr_init(ALLEGRO_SYSTEM_XGLX *s)
 {
    int event_base = 0;
@@ -444,12 +859,14 @@
 
    /* init xrandr info to defaults */
    s->xrandr_available = 0;
+   s->xrandr_res_count = 0;
+   s->xrandr_res = NULL;
    s->xrandr_output_count = 0;
    s->xrandr_outputs = NULL;
 
    _al_mutex_lock(&s->lock);
 
-   if (XRRQueryExtension(s->x11display, &event_base, &error_base)) {
+   if (XRRQueryExtension(s->x11display, &s->xrandr_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);
@@ -487,6 +904,9 @@
       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;
+      mmon_interface.get_default_adapter   = _al_xsys_xrandr_get_default_adapter;
+      mmon_interface.get_xscreen           = _al_xsys_xrandr_get_xscreen;
+      mmon_interface.create_display        = _al_xsys_xrandr_create_display;
    }
 
    _al_mutex_unlock(&s->lock);
@@ -494,27 +914,38 @@
 
 static void _al_xsys_xrandr_exit(ALLEGRO_SYSTEM_XGLX *s)
 {
-   int i;
+   // int i;
    ALLEGRO_DEBUG("xfullscreen: XRandR exiting.\n");
-
-   for (i = 0; i < s->xrandr_output_count; i++) {
+   
+   // for (i = 0; i < s->xrandr_output_count; i++) {
    //   XRRFreeOutputInfo(s->xrandr_outputs[i]);
-   }
+   // }
 
+   // for (i = 0; i < s->xrandr_res_count; i++) {
+   //    XRRFreeScreenResources(s->xrandr_res[i]);
+   // }
+
    ALLEGRO_DEBUG("xfullscreen: XRRFreeScreenResources\n");
    //if (s->xrandr_res)
    //   XRRFreeScreenResources(s->xrandr_res);
 
    al_free(s->xrandr_outputs);
-   al_free(s->xrandr_stored_modes);
-
+   al_free(s->xrandr_res);
+   
    s->xrandr_available = 0;
+   s->xrandr_res_count = 0;
+   s->xrandr_res = NULL;
    s->xrandr_output_count = 0;
    s->xrandr_outputs = NULL;
 
    ALLEGRO_DEBUG("xfullscreen: XRandR exit finished.\n");
 }
 
+#endif /* 0 */
+
+void _al_xsys_xrandr_init(ALLEGRO_SYSTEM_XGLX *s);
+void _al_xsys_xrandr_exit(ALLEGRO_SYSTEM_XGLX *s);
+
 #endif /* ALLEGRO_XWINDOWS_WITH_XRANDR */
 
 
@@ -527,9 +958,26 @@
 
 #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
 
-// XXX This code is completely untested. Preferably it should be tested on a machine that doesn't have any XRandR support.
+// XXX retest under multi-head!
 static int _al_xsys_xfvm_get_num_modes(ALLEGRO_SYSTEM_XGLX *s, int adapter)
 {
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+   if(s->xinerama_available && s->xinerama_screen_count != s->xfvm_screen_count) {
+      if(adapter < 0 || adapter > s->xinerama_screen_count)
+         return 0;
+    
+      /* due to braindeadedness of the NVidia binary driver we can't know what an individual
+       * monitor's modes are, as the NVidia binary driver only reports combined "BigDesktop"
+       * or "TwinView" modes to user-space. There is no way to set modes on individual screens.
+       * As such, we can only do one thing here and report one single mode,
+       * which will end up being the xinerama size for the requested adapter */
+      return 1;
+   }
+#endif
+
+   if(adapter < 0 || adapter > s->xfvm_screen_count)
+      return 0;
+   
    return s->xfvm_screen[adapter].mode_count;
 }
 
@@ -537,6 +985,21 @@
 {
    int denom;
 
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+   /* TwinView gives us one large screen via xfvm, and no way to
+    * properly change modes on individual monitors, so we want to query
+    * xinerama for the lone mode. */
+   if (s->xinerama_available && s->xfvm_screen_count != s->xinerama_screen_count) {
+      return _al_xsys_xinerama_get_mode(s, adapter, i, mode);
+   }
+#endif
+
+   if(adapter < 0 || adapter > s->xfvm_screen_count)
+      return NULL;
+   
+   if(i < 0 || i > s->xfvm_screen[adapter].mode_count)
+      return NULL;
+   
    mode->width = s->xfvm_screen[adapter].modes[i]->hdisplay;
    mode->height = s->xfvm_screen[adapter].modes[i]->vdisplay;
    mode->format = 0;
@@ -552,12 +1015,24 @@
 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;
+   int adapter = _al_xglx_get_adapter(s, d, false);
+   
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+   /* TwinView work arrounds, nothing to do here, since we can't really change or restore modes */
+   if (s->xinerama_available && s->xinerama_screen_count != s->xfvm_screen_count) {
+      /* at least pretend we set a mode if its the current mode */
+      if(s->xinerama_screen_info[adapter].width != w || s->xinerama_screen_info[adapter].height != h)
+         return false;
+      
+      return true;
+   }
+#endif
 
-   mode_idx = _al_xglx_fullscreen_select_mode(s, d->xscreen, w, h, format, refresh_rate);
+   mode_idx = _al_xglx_fullscreen_select_mode(s, adapter, 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])) {
+   
+   if (!XF86VidModeSwitchToMode(s->x11display, adapter, s->xfvm_screen[adapter].modes[mode_idx])) {
       ALLEGRO_ERROR("xfullscreen: XF86VidModeSwitchToMode failed\n");
       return false;
    }
@@ -565,31 +1040,19 @@
    return true;
 }
 
-/* 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;
-
-
-
-   // grab the root window that contains d->window
-   XGetXwindowAttributes(s->gfxdisplay, d->window, &xwa);
-   XTranslateCoordinates(s->gfxdisplay, d->window,
-      xwa.root, 0, 0, &x, &y, &child);
-
-   XF86VidModeSetViewPort(s->gfxdisplay, d->xscreen, x, y);
-}
-*/
-
 static void _al_xsys_xfvm_store_video_mode(ALLEGRO_SYSTEM_XGLX *s)
 {
    int n;
 
    ALLEGRO_DEBUG("xfullscreen: _al_xsys_xfvm_store_video_mode\n");
 
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+   /* TwinView work arrounds, nothing to do here, since we can't really change or restore modes */
+   if (s->xinerama_available && s->xinerama_screen_count != s->xfvm_screen_count) {
+      return;
+   }
+#endif
+
    // save all original modes
    int i;
    for (i = 0; i < s->xfvm_screen_count; i++) {
@@ -614,12 +1077,22 @@
 static void _al_xsys_xfvm_restore_video_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter)
 {
    Bool ok;
+   
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+   /* TwinView work arrounds, nothing to do here, since we can't really change or restore modes */
+   if (s->xinerama_available && s->xinerama_screen_count != s->xfvm_screen_count) {
+      return;
+   }
+#endif
 
+   if(adapter < 0 || adapter > s->xfvm_screen_count)
+      return;
+
    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, adapter, s->xfvm_screen[adapter].original_mode);
+   ok = XF86VidModeSwitchToMode(s->x11display, adapter, s->xfvm_screen[adapter].original_mode);
    if (!ok) {
       ALLEGRO_ERROR("xfullscreen: XF86VidModeSwitchToMode failed\n");
    }
@@ -632,10 +1105,10 @@
    /* This is needed, at least on my machine, or the program may terminate
     * before the screen mode is actually reset. --pw
     */
+   /* can we move this into shutdown_system? It could speed up mode restores -TF */
    XFlush(s->gfxdisplay);
 }
 
-/* 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;
@@ -643,18 +1116,29 @@
 #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
    if (s->xinerama_available) {
       _al_xsys_xinerama_get_display_offset(s, adapter, &tmp_x, &tmp_y);
-   } else
+   } //else 
 #endif
    /* don't set the output params if function fails */
-   if (!XF86VidModeGetViewPort(s->x11display, adapter, &tmp_x, &tmp_y))
-      return;
+   /* XXX I don't think this part makes sense at all.
+    * in multi-head mode, the origin is always 0x0
+    * in Xinerama, its caught by xinerama, and xfvm is NEVER
+    * used when xrandr is active -TF */
+   //if (!XF86VidModeGetViewPort(s->x11display, adapter, &tmp_x, &tmp_y))
+   //   return;
 
    *x = tmp_x;
    *y = tmp_y;
+   
+   ALLEGRO_DEBUG("xfvm dpy off %ix%i\n", *x, *y);
 }
 
 static int _al_xsys_xfvm_get_num_adapters(ALLEGRO_SYSTEM_XGLX *s)
 {
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+   if (s->xinerama_available) {
+      return s->xinerama_screen_count;
+   }
+#endif
    return s->xfvm_screen_count;
 }
 
@@ -667,6 +1151,9 @@
    }
 #endif
 
+   if(adapter < 0 || adapter > s->xfvm_screen_count)
+      return;
+
    XWindowAttributes xwa;
    Window root;
 
@@ -684,6 +1171,61 @@
    mi->y2 = xwa.height;
 }
 
+static int _al_xsys_xfvm_get_default_adapter(ALLEGRO_SYSTEM_XGLX *s)
+{
+   ALLEGRO_DEBUG("xfvm get default adapter\n");
+   
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+   if (s->xinerama_available) {
+      return _al_xsys_xinerama_get_default_adapter(s);
+   }
+#endif
+
+   return _al_xsys_mheadx_get_default_adapter(s);
+}
+
+static int _al_xsys_xfvm_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter)
+{
+   ALLEGRO_DEBUG("xfvm get xscreen for adapter %i\n", adapter);
+   
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+   if (s->xinerama_available) {
+      return _al_xsys_xinerama_get_xscreen(s, adapter);
+   }
+#endif
+
+   return _al_xsys_mheadx_get_xscreen(s, adapter);
+}
+
+static void _al_xsys_xfvm_post_setup(ALLEGRO_SYSTEM_XGLX *s,
+   ALLEGRO_DISPLAY_XGLX *d)
+{
+   int x = 0, y = 0;
+   XWindowAttributes xwa;
+   
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+   /* TwinView work arrounds, nothing to do here, since we can't really change or restore modes */
+   if (s->xinerama_available && s->xinerama_screen_count != s->xfvm_screen_count) {
+      return;
+   }
+#endif
+   
+   int adapter = _al_xglx_get_adapter(s, d, false);
+   
+   XGetWindowAttributes(s->x11display, d->window, &xwa);
+   _al_xsys_xfvm_get_display_offset(s, adapter, &x, &y);
+   
+   /* some window managers like to move our window even if we explicitly tell it not to
+    * so we need to get the correct offset here */
+   x = xwa.x - x;
+   y = xwa.y - y;
+   
+   ALLEGRO_DEBUG("xfvm set view port: %ix%i\n", x, y);
+   
+   XF86VidModeSetViewPort(s->x11display, adapter, x, y);
+}
+
+
 static void _al_xsys_xfvm_init(ALLEGRO_SYSTEM_XGLX *s)
 {
    int event_base = 0;
@@ -717,11 +1259,19 @@
    if (s->xfvm_available) {
       int num_screens;
 #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
-      // This is some fun stuff right here, if XRANDR is available, we can't use the xinerama screen count
-      // and we really want the xrandr init in xglx_initialize to come last so it overrides xf86vm if available
-      // and I really don't want to add more XRRQuery* or #ifdefs here.
-      // I don't think XRandR can be disabled once its loaded,
-      // so just seeing if its in the extension list should be fine.
+      /* This is some fun stuff right here, if XRANDR is available, we can't use the xinerama screen count
+       * and we really want the xrandr init in xglx_initialize to come last so it overrides xf86vm if available
+       * and I really don't want to add more XRRQuery* or #ifdefs here.
+       * I don't think XRandR can be disabled once its loaded,
+       * so just seeing if its in the extension list should be fine. */
+      /* interesting thing to note is if XRandR is available, that means we have TwinView,
+       * and not multi-head Xinerama mode, as True Xinerama disables XRandR on my NVidia.
+       * which means all of those xfvm_screen_count != xinerama_screen_count tests
+       * only apply to TwinView. As this code below sets xfvm_screen_count to xinerama_screen_count
+       * making all those compares fail, and make us fall back to the normal xfvm multi-head code. */
+      /* second note, if FakeXinerama is disabled on TwinView setups, we will end up using
+       * XRandR, as there is no other way to detect TwinView outside of libNVCtrl */
+      
       int ext_op, ext_evt, ext_err;
       Bool ext_ret = XQueryExtension(s->x11display, "RANDR", &ext_op, &ext_evt, &ext_err);
 
@@ -756,6 +1306,9 @@
          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;
+         mmon_interface.get_default_adapter   = _al_xsys_xfvm_get_default_adapter;
+         mmon_interface.get_xscreen           = _al_xsys_xfvm_get_xscreen;
+         mmon_interface.post_setup            = _al_xsys_xfvm_post_setup;
       }
    }
 
@@ -810,6 +1363,11 @@
       return true;
 
    /* Shouldn't we avoid initing any more of these than we need? */
+   /* nope, no way to tell which is going to be used on any given system
+    * this way, xrandr always overrides everything else should it succeed.
+    * And when xfvm is chosen, it needs xinerama inited,
+    * incase there are multiple screens.
+    */
 
 #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
    _al_xsys_xinerama_init(s);
@@ -851,19 +1409,13 @@
    s->mmon_interface_inited = false;
 }
 
-static int get_default_adapter(void)
-{
-   /* FIXME: the default adapter is not necessarily 0. */
-   return 0;
-}
-
 int _al_xglx_get_num_display_modes(ALLEGRO_SYSTEM_XGLX *s, int adapter)
 {
    if (!init_mmon_interface(s))
       return 0;
 
    if (adapter == -1)
-      adapter = get_default_adapter();
+      adapter = _al_xglx_get_default_adapter(s);
 
    if (!mmon_interface.get_num_display_modes) {
       if (adapter != 0)
@@ -882,7 +1434,7 @@
       return NULL;
 
    if (adapter == -1)
-      adapter = get_default_adapter();
+      adapter = _al_xglx_get_default_adapter(s);
 
    if (!mmon_interface.get_display_mode) {
       mode->width = DisplayWidth(s->x11display, DefaultScreen(s->x11display));
@@ -907,7 +1459,7 @@
       return -1;
    
    if (adapter == -1)
-      adapter = get_default_adapter();
+      adapter = _al_xglx_get_default_adapter(s);
 
    n = _al_xglx_get_num_display_modes(s, adapter);
    if (!n)
@@ -964,11 +1516,21 @@
    ALLEGRO_DISPLAY_XGLX *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);
+   /* XXX We don't want to do it this way, for say a dual monitor setup... */
+   //XGrabPointer(s->x11display, d->window, False,
+   //   PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+   //   GrabModeAsync, GrabModeAsync, d->window, None, CurrentTime);
    //FIXME: handle possible errors here
    s->pointer_grabbed = true;
+   
+   if (!init_mmon_interface(s))
+      return;
+   
+   if (!mmon_interface.post_setup)
+      return;
+   
+   mmon_interface.post_setup(s, d);
+   
 }
 
 void _al_xglx_store_video_mode(ALLEGRO_SYSTEM_XGLX *s)
@@ -1033,8 +1595,62 @@
    return mmon_interface.get_num_adapters(s);
 }
 
+int _al_xglx_get_default_adapter(ALLEGRO_SYSTEM_XGLX *s)
+{
+   ALLEGRO_DEBUG("get default adapter\n");
+   
+   if (!init_mmon_interface(s))
+      return 0;
 
+   if (!mmon_interface.get_default_adapter)
+      return 0;
 
+   return mmon_interface.get_default_adapter(s);
+}
+
+int _al_xglx_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter)
+{
+   ALLEGRO_DEBUG("get xscreen\n");
+   
+   if (!init_mmon_interface(s))
+      return 0;
+
+   if (!mmon_interface.get_xscreen)
+      return 0;
+   
+   return mmon_interface.get_xscreen(s, adapter);
+}
+
+int _al_xglx_get_adapter(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, bool recalc)
+{
+   if (!init_mmon_interface(s))
+      return 0;
+      
+   if(d->adapter != -1 && !recalc)
+      return d->adapter;
+   
+   if(!mmon_interface.get_adapter)
+      return 0;
+   
+   return mmon_interface.get_adapter(s, d);
+}
+
+void _al_xglx_handle_xevent(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, XEvent *e)
+{
+   ALLEGRO_DEBUG("got event %i\n", e->type);
+   // if we haven't setup the mmon interface, just bail
+   if(!s->mmon_interface_inited)
+      return;
+   
+   // bail if the current mmon interface doesn't implement the handle_xevent method
+   if(!mmon_interface.handle_xevent)
+      return;
+   
+   
+   mmon_interface.handle_xevent(s, d, e);
+
+}
+
 #define X11_ATOM(x)  XInternAtom(x11, #x, False);
 
 /* Note: The system mutex must be locked (exactly once) before
@@ -1066,7 +1682,7 @@
    xev.xclient.data.l[3] = 0;
    xev.xclient.data.l[4] = 1;
 
-   XSendEvent(x11, DefaultRootWindow(x11), False,
+   XSendEvent(x11, RootWindowOfScreen(ScreenOfDisplay(x11, glx->xscreen)), False,
       SubstructureRedirectMask | SubstructureNotifyMask, &xev);
    
    if (value == 2) {
@@ -1075,4 +1691,34 @@
    }
 }
 
+void _al_xglx_toggle_above(ALLEGRO_DISPLAY *display, int value)
+{
+   ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver();
+   ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display;
+   Display *x11 = system->x11display;
+
+   ALLEGRO_DEBUG("Toggling _NET_WM_STATE_ABOVE hint: %d\n", value);
+
+   XEvent xev;
+   xev.xclient.type = ClientMessage;
+   xev.xclient.serial = 0;
+   xev.xclient.send_event = True;
+   xev.xclient.message_type = X11_ATOM(_NET_WM_STATE);
+   xev.xclient.window = glx->window;
+   xev.xclient.format = 32;
+
+   // Note: It seems 0 is not reliable except when mapping a window -
+   // 2 is all we need though.
+   xev.xclient.data.l[0] = value; /* 0 = off, 1 = on, 2 = toggle */
+
+   xev.xclient.data.l[1] = X11_ATOM(_NET_WM_STATE_ABOVE);
+   xev.xclient.data.l[2] = 0;
+   xev.xclient.data.l[3] = 0;
+   xev.xclient.data.l[4] = 1;
+
+   XSendEvent(x11, DefaultRootWindow(x11), False,
+      SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+   
+}
+
 /* vim: set sts=3 sw=3 et: */
Index: src/x/xsystem.c
===================================================================
--- src/x/xsystem.c	(revision 14262)
+++ src/x/xsystem.c	(working copy)
@@ -96,6 +96,11 @@
             d->mouse_warp = true;
             break;
          }
+         break;
+         
+      default:
+         _al_xglx_handle_xevent(s, d, &event);
+         break;
    }
 }
 
@@ -252,6 +257,10 @@
    }
    _al_vector_free(&s->displays);
 
+   // Makes sure we wait for any commands sent to the X server when destroying the displays.
+   // Should make sure we don't shutdown before modes are restored.
+   XSync(sx->x11display, False);
+   
    _al_xsys_mmon_exit(sx);
 
    if (sx->x11display) {
Index: src/x/xdisplay.c
===================================================================
--- src/x/xdisplay.c	(revision 14262)
+++ src/x/xdisplay.c	(working copy)
@@ -35,9 +35,11 @@
 {
    ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver();
    ALLEGRO_DISPLAY_XGLX *glx = (void *)d;
-   XSizeHints *hints = XAllocSizeHints();;
+   XSizeHints *hints = XAllocSizeHints();
 
-   if (!(d->flags & ALLEGRO_RESIZABLE)) {
+   /* Do not force the size of the window on resizeable or fullscreen windows */
+   /* on fullscreen windows, it confuses most X Window Managers */
+   if (!(d->flags & ALLEGRO_RESIZABLE) && !(d->flags & ALLEGRO_FULLSCREEN)) {
       hints->flags = PMinSize | PMaxSize | PBaseSize;
       hints->min_width  = hints->max_width  = hints->base_width  = d->w;
       hints->min_height = hints->max_height = hints->base_height = d->h;
@@ -48,8 +50,20 @@
    if (x_off != INT_MAX && y_off != INT_MAX) {
       ALLEGRO_DEBUG("Force window position to %d, %d.\n", x_off, y_off);
       hints->flags |= PPosition;
+      hints->x = x_off;
+      hints->y = y_off;
    }
 
+   if(d->flags & ALLEGRO_FULLSCREEN) {
+      /* kwin will improperly layer a panel over our window on a second display without this.
+       * some other Size flags may cause glitches with various WMs, but this seems to be ok
+       * with metacity and kwin. As noted in xdpy_create_display, compiz is just broken.
+       */
+      hints->flags |= PBaseSize;
+      hints->base_width  = d->w;
+      hints->base_height = d->h;
+   }
+
    XSetWMNormalHints(system->x11display, glx->window, hints);
 
    XFree(hints);
@@ -61,7 +75,7 @@
 {
    ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver();
    ALLEGRO_DISPLAY_XGLX *glx = (void *)d;
-   XSizeHints *hints = XAllocSizeHints();;
+   XSizeHints *hints = XAllocSizeHints();
 
    hints->flags = PMinSize | PMaxSize;
    hints->min_width  = 0;
@@ -230,7 +244,19 @@
    return false;
 }
 
+static void _al_xglx_use_adapter(ALLEGRO_SYSTEM_XGLX *s, int adapter)
+{
+   ALLEGRO_DEBUG("use adapter %i\n", adapter);
+   s->adapter_use_count++;
+   s->adapter_map[adapter]++;
+}
 
+static void _al_xglx_unuse_adapter(ALLEGRO_SYSTEM_XGLX *s, int adapter)
+{
+   ALLEGRO_DEBUG("unuse adapter %i\n", adapter);
+   s->adapter_use_count--;
+   s->adapter_map[adapter]--;
+}
 
 static void xdpy_destroy_display(ALLEGRO_DISPLAY *d);
 
@@ -241,7 +267,7 @@
 {
    ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver();
    int adapter = al_get_new_display_adapter();
-
+   
    if (system->x11display == NULL) {
       ALLEGRO_WARN("Not connected to X server.\n");
       return NULL;
@@ -254,13 +280,6 @@
 
    _al_mutex_lock(&system->lock);
 
-   if (adapter >= ScreenCount(system->x11display)) {
-      /* Fail early, as glXGetFBConfigs may crash otherwise. */
-      ALLEGRO_DEBUG("Requested display adapter more than ScreenCount.\n");
-      _al_mutex_unlock(&system->lock);
-      return NULL;
-   }
-
    ALLEGRO_DISPLAY_XGLX *d = al_malloc(sizeof *d);
    ALLEGRO_DISPLAY *display = (void*)d;
    ALLEGRO_OGL_EXTRAS *ogl = al_malloc(sizeof *ogl);
@@ -282,11 +301,52 @@
    // FIXME: default? Is this the right place to set this?
    display->flags |= ALLEGRO_OPENGL;
 
-   // store our initial screen, used by fullscreen and glx visual code
-   d->xscreen = adapter;
-   if (d->xscreen < 0)
-      d->xscreen = DefaultScreen(system->x11display);
+   // store our initial virtual adapter, used by fullscreen and positioning code
+   d->adapter = adapter;
+   ALLEGRO_DEBUG("selected adapter %i\n", adapter);
+   if(d->adapter < 0) {
+      d->adapter = _al_xglx_get_default_adapter(system);
+   }
 
+   _al_xglx_use_adapter(system, d->adapter);
+   
+   /* if we're in multi-head X mode, bail if we try to use more than one display
+    * as there are bugs in X/glX that cause us to hang in X if we try to use more than one. */
+   /* if we're in real xinerama mode, also bail, x makes mouse use evil */
+   
+   bool true_xinerama_active = false;
+   bool xrandr_active = false;
+
+#ifdef ALLEGRO_XWINDOWS_WITH_XRANDR
+   xrandr_active = system->xrandr_available;
+#endif
+   
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+   true_xinerama_active = !xrandr_active && system->xinerama_available;
+#endif
+   
+   if((true_xinerama_active || ScreenCount(system->x11display) > 1) && system->adapter_use_count) {
+      uint32_t i, adapter_use_count = 0;
+      for(i = 0; i < 32; i++) {
+         if(system->adapter_map[i])
+            adapter_use_count++;
+      }
+      
+      if(adapter_use_count > 1) {
+         ALLEGRO_ERROR("Use of more than one adapter at once in multi-head X or X with true Xinerama active is not possible.\n");
+         al_free(d);
+         al_free(ogl);
+         _al_mutex_unlock(&system->lock);
+         return NULL;
+      }
+   }
+   ALLEGRO_DEBUG("xdpy: selected adapter %i\n", d->adapter);
+   
+   // store or initial X Screen, used by window creation, fullscreen, and glx visual code
+   d->xscreen = _al_xglx_get_xscreen(system, d->adapter);
+   
+   ALLEGRO_DEBUG("xdpy: selected xscreen %i\n", d->xscreen);
+   
    d->is_mapped = false;
    _al_cond_init(&d->mapped);
 
@@ -349,10 +409,23 @@
 
    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);
+      _al_xglx_get_display_offset(system, d->adapter, &x_off, &y_off);
    }
    else {
+      /* we want new_display_adapter's offset to add to the new_window_position */
+      int xscr_x = 0, xscr_y = 0;
+
       al_get_new_window_position(&x_off, &y_off);
+      
+      if(adapter != -1) { 
+         /* non default adapter. I'm assuming this means the user wants the window to be placed on the adapter offset by new display pos */
+         _al_xglx_get_display_offset(system, d->adapter, &xscr_x, &xscr_y);
+         if(x_off != INT_MAX)
+            x_off += xscr_x;
+         
+         if(y_off != INT_MAX)
+            y_off += xscr_y;
+      }
    }
 
    d->window = XCreateWindow(system->x11display,
@@ -361,30 +434,34 @@
       y_off != INT_MAX ? y_off : 0,
       w, h, 0, d->xvinfo->depth,
       InputOutput, d->xvinfo->visual, mask, &swa);
-
+      
    // Try to set full screen mode if requested, fail if we can't
    if (display->flags & ALLEGRO_FULLSCREEN) {
       /* According to the spec, the window manager is supposed to disable
        * window decorations when _NET_WM_STATE_FULLSCREEN is in effect.
        * However, some WMs may not be fully compliant, e.g. Fluxbox.
        */
+      
       xdpy_toggle_frame(display, false);
 
+      _al_xglx_toggle_above(display, 1);
+      
       if (!_al_xglx_fullscreen_set_mode(system, d, w, h, 0, display->refresh_rate)) {
          ALLEGRO_DEBUG("xdpy: failed to set fullscreen mode.\n");
          xdpy_destroy_display(display);
          _al_mutex_unlock(&system->lock);
          return NULL;
       }
+      //XSync(system->x11display, False);
    }
 
    if (display->flags & ALLEGRO_NOFRAME)
       xdpy_toggle_frame(display, false);
 
    ALLEGRO_DEBUG("X11 window created.\n");
-
+   
    set_size_hints(display, x_off, y_off);
-
+   
    d->wm_delete_window_atom = XInternAtom(system->x11display,
       "WM_DELETE_WINDOW", False);
    XSetWMProtocols(system->x11display, d->window, &d->wm_delete_window_atom, 1);
@@ -394,6 +471,7 @@
 
    /* Send the pending request to the X server. */
    XSync(system->x11display, False);
+   
    /* To avoid race conditions where some X11 functions fail before the window
     * is mapped, we wait here until it is mapped. Note that the thread is
     * locked, so the event could not possibly have been processed yet in the
@@ -408,7 +486,7 @@
     * window when switching to fullscreen it will use the same
     * monitor (with the MetaCity version I'm using here right now).
     */
-   if ((display->flags & ALLEGRO_FULLSCREEN_WINDOW) || (display->flags & ALLEGRO_FULLSCREEN)) {
+   if ((display->flags & ALLEGRO_FULLSCREEN_WINDOW)) {
       ALLEGRO_INFO("Toggling fullscreen flag for %d x %d window.\n",
          display->w, display->h);
       reset_size_hints(display);
@@ -423,16 +501,24 @@
          display->w, display->h);
    }
 
+   if (display->flags & ALLEGRO_FULLSCREEN) {
+      /* kwin wants these here */
+      /* metacity wants these here too */
+      /* XXX compiz is quiky, can't seem to find a combination of hints that
+       * make sure we are layerd over panels, and are positioned properly */
+
+      //_al_xglx_toggle_fullscreen_window(display, 1);
+      _al_xglx_toggle_above(display, 1);
+      
+      _al_xglx_fullscreen_to_display(system, d);
+   }
+   
    if (!_al_xglx_config_create_context(d)) {
       xdpy_destroy_display(display);
       _al_mutex_unlock(&system->lock);
       return NULL;
    }
 
-   if (display->flags & ALLEGRO_FULLSCREEN) {
-      _al_xglx_fullscreen_to_display(system, d);
-   }
-
    /* Make our GLX context current for reading and writing in the current
     * thread.
     */
@@ -564,6 +650,8 @@
       }
    }
 
+   _al_xglx_unuse_adapter(s, glx->adapter);
+   
    _al_ogl_unmanage_extensions(d);
    ALLEGRO_DEBUG("unmanaged extensions.\n");
 
@@ -577,18 +665,26 @@
       size_t i;
       ALLEGRO_DISPLAY **living = NULL;
       bool last_fullscreen = true;
-      /* If any other fullscreen display is still active, we must
-       * not touch the video mode.
+      /* If any other fullscreen display is still active on the same adapter,
+       * we must not touch the video mode.
        */
       for (i = 0; i < s->system.displays._size; i++) {
          living = _al_vector_ref(&s->system.displays, i);
+         ALLEGRO_DISPLAY_XGLX *living_glx = (void*)*living;
+         
          if (*living == d) continue;
-         if (al_get_display_flags(*living) & ALLEGRO_FULLSCREEN)
+         
+         /* check for fullscreen displays on the same adapter */
+         if (living_glx->adapter == glx->adapter &&
+             al_get_display_flags(*living) & ALLEGRO_FULLSCREEN)
+         {
             last_fullscreen = false;
+         }
       }
+      
       if (last_fullscreen) {
          ALLEGRO_DEBUG("restore modes.\n");
-         _al_xglx_restore_video_mode(s, glx->xscreen);
+         _al_xglx_restore_video_mode(s, glx->adapter);
       }
       else {
          ALLEGRO_DEBUG("*not* restoring modes.\n");
@@ -841,7 +937,9 @@
 
    if (d->flags & ALLEGRO_FULLSCREEN) {
       _al_xglx_toggle_fullscreen_window(d, 1);
+      _al_xglx_toggle_above(d, 1);
       _al_xglx_fullscreen_to_display(system, glx);
+      ALLEGRO_DEBUG("xdpy: resize fullscreen?\n");
    }
 
    _al_mutex_unlock(&system->lock);
@@ -890,8 +988,36 @@
       glx->x = xevent->xconfigure.x;
       glx->y = xevent->xconfigure.y;
    }
+   
 
+   ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX*)al_get_system_driver();
+   ALLEGRO_MONITOR_INFO mi;
+   int center_x = (glx->x + (glx->x + xevent->xconfigure.width)) / 2;
+   int center_y = (glx->y + (glx->y + xevent->xconfigure.height)) / 2;
+         
+   _al_xglx_get_monitor_info(system, glx->adapter, &mi);
+   
+   ALLEGRO_DEBUG("xconfigure event! %ix%i\n", xevent->xconfigure.x, xevent->xconfigure.y);
+   
+   /* check if we're no longer inside the stored adapter */
+   if((center_x < mi.x1 && center_x > mi.x2) ||
+      (center_y < mi.y1 && center_y > mi.x2))
+   {
+      
+      int new_adapter = _al_xglx_get_adapter(system, glx, true);
+      if(new_adapter != glx->adapter) {
+         ALLEGRO_DEBUG("xdpy: adapter change!\n");
+         _al_xglx_unuse_adapter(system, glx->adapter);
+         if(d->flags & ALLEGRO_FULLSCREEN)
+            _al_xglx_restore_video_mode(system, glx->adapter);
+         glx->adapter = new_adapter;
+         _al_xglx_use_adapter(system, glx->adapter);
+      }
+      
+   }
+   
    _al_event_source_unlock(es);
+   
 }
 
 
Index: docs/src/refman/display.txt
===================================================================
--- docs/src/refman/display.txt	(revision 14262)
+++ docs/src/refman/display.txt	(working copy)
@@ -172,9 +172,17 @@
 ALLEGRO_WINDOWED
 :   Prefer a windowed mode.
 
+    Under multi-head X (not XRandR/TwinView), the use of more than one adapter is
+    impossible due to bugs in X and glX. [al_create_display] will fail if more than one
+    adapter is attempted to be used.
+    
 ALLEGRO_FULLSCREEN
 :   Prefer a fullscreen mode.
 
+    Under X the use of more than one FULLSCREEN display when using multi-head X,
+    or true Xinerama is not possible due to bugs in X and glX,
+    display creation will fail if more than one adapter is attempted to be used.
+   
 ALLEGRO_FULLSCREEN_WINDOW
 :   Make the window span the entire screen. Unlike ALLEGRO_FULLSCREEN this
     will never attempt to modify the screen resolution. Instead the pixel
@@ -191,6 +199,10 @@
     toggle between fullscreen/windowed mode or how additional monitors
     behave while your display is in fullscreen mode.
 
+    Additionally under X, the use of more than one adapter in multi-head mode
+    or with true Xinerama enabled is impossible due to bugs in X/glX,
+    creation will fail if more than one adapter is attempted to be used.
+    
 ALLEGRO_RESIZABLE
 :   The display is resizable (only applicable if combined with
     ALLEGRO_WINDOWED).
Index: examples/ex_display_options.c
===================================================================
--- examples/ex_display_options.c	(revision 14262)
+++ examples/ex_display_options.c	(working copy)
@@ -81,6 +81,8 @@
    int dw = al_get_display_width(display);
    int dh = al_get_display_height(display);
 
+   modes_count = al_get_num_display_modes();
+   
    ALLEGRO_COLOR c;
    c = al_map_rgb_f(0.8, 0.8, 1);
    al_draw_textf(font, c, x, y, 0, "Create new display");


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