Re: [AD] More X Mode Setting

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


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.

> Peter
> 
> ---------------------------------------------------------------------------
> --- Protect Your Site and Customers from Malware Attacks
> Learn about various malware tactics and how to avoid them. Understand
> malware threats, the impact they can have on your business, and how you
> can protect your company and customers by using code signing.
> http://p.sf.net/sfu/oracle-sfdevnl


-- 
Thomas Fjellstrom
tfjellstrom@xxxxxxxxxx
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,25 @@
 #endif
 #ifdef ALLEGRO_XWINDOWS_WITH_XRANDR
    int xrandr_available;
-   XRRScreenResources *xrandr_res;
+   int xrandr_event_base;
+   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
+   
+   /* 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 +113,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;
@@ -184,7 +197,17 @@
 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_create_display(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d);
+
+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/xfullscreen.c
===================================================================
--- src/x/xfullscreen.c	(revision 14262)
+++ src/x/xfullscreen.c	(working copy)
@@ -14,14 +14,170 @@
     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 (*create_display)(ALLEGRO_SYSTEM_XGLX *, ALLEGRO_DISPLAY_XGLX *);
 };
 
 
 /* globals - this might be better in ALLEGRO_SYSTEM_XGLX */
 static _ALLEGRO_XGLX_MMON_INTERFACE mmon_interface;
 
+/* generic multi-head x */
+static 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;
 
+   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. */
+static 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 */
+static 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 +244,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 +258,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 */
 
 
@@ -117,95 +320,161 @@
 {
    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 +482,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 +493,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 +517,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 +615,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 +700,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 +738,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 +776,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 +787,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 +814,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 +877,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 +922,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,21 +932,27 @@
 
 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;
 
@@ -527,9 +971,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 +998,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 +1028,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 +1053,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 +1090,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 +1118,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 +1129,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 +1164,9 @@
    }
 #endif
 
+   if(adapter < 0 || adapter > s->xfvm_screen_count)
+      return;
+
    XWindowAttributes xwa;
    Window root;
 
@@ -684,6 +1184,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 +1272,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 +1319,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 +1376,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 +1422,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 +1447,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 +1472,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 +1529,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 +1608,97 @@
    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_create_display(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d)
+{
+   if (!init_mmon_interface(s))
+      return;
+   
+   if(!mmon_interface.get_adapter)
+      return;
+   
+   mmon_interface.create_display(s, d);
+}
+
+void _al_xglx_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("xrandr: RRNotify_CrtcChange!\n");
+         ALLEGRO_DEBUG("xrandr: crtc geom: %i+%i-%ix%i\n", rrce->x, rrce->y, rrce->width, rrce->height);
+      } else
+      if(rre->subtype == RRNotify_OutputChange) {
+         ALLEGRO_DEBUG("xrandr: RRNotify_OutputChange!\n");
+      } 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;
+      ALLEGRO_DEBUG("xrandr: RRScreenChangeNotify!\n");
+      XRRUpdateConfiguration( e );
+      
+      ALLEGRO_DEBUG("xrandr: RRScreenChangeNotify!\n");
+      ALLEGRO_DEBUG("xrandr: screen size %ix%i\n", rre->width, rre->height);
+      
+      // HACK!
+      //_al_xsys_xrandr_query(s);
+      
+      XRRScreenResources *res = s->xrandr_res[s->xrandr_outputs[d->adapter]->res_id];
+      XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, res, s->xrandr_outputs[d->adapter]->output->crtc);
+      
+      ALLEGRO_DEBUG("xrandr: adapter %i geom %i+%i-%ix%i\n", d->adapter, crtc_info->x, crtc_info->y, crtc_info->width, crtc_info->height);
+      
+      XRRFreeCrtcInfo(crtc_info);
+   }
+}
+
 #define X11_ATOM(x)  XInternAtom(x11, #x, False);
 
 /* Note: The system mutex must be locked (exactly once) before
@@ -1066,7 +1730,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 +1739,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;
    }
 }
 
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
@@ -404,11 +482,13 @@
       _al_cond_wait(&d->mapped, &system->lock);
    }
 
+   _al_xglx_create_display(system, d);
+
    /* We can do this at any time, but if we already have a mapped
     * 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 +503,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 +652,8 @@
       }
    }
 
+   _al_xglx_unuse_adapter(s, glx->adapter);
+   
    _al_ogl_unmanage_extensions(d);
    ALLEGRO_DEBUG("unmanaged extensions.\n");
 
@@ -577,18 +667,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 +939,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 +990,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/