Re: [AD] More X Mode Setting

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


On January 4, 2011, Thomas Fjellstrom wrote:
> On January 4, 2011, Peter Wang wrote:
> > On 2011-01-04, Thomas Fjellstrom <tfjellstrom@xxxxxxxxxx> wrote:
> > > Another issue. Window movement. Seems with compiz, and a window with a
> > > border/titlebar, we get sane amounts of window movement events, but in
> > > ex_noframe, we get a ton. (I'm assuming the wm is compressing all the
> > > events into just a few per window move)
> > > 
> > > At least thats what happens if I comment out that if at the bottom of
> > > the configure event handler. Otherwise we never update the window's
> > > position at all. It seems I don't even get that bogus configure event
> > > the comment above mentions.
> > > 
> > > I'd like to also flag the code to update the display's new adapter
> > > property there, but if that if is really needed, we never get a chance.
> > > Can I just remove that check?
> > 
> > No, that's required.  I tried to remove it once, but confirmed the
> > problem for myself.
> 
> It has to be done in some other way, or we never update the window
> position. At least with compiz.

I just found out something interesting. the set_size_hint function seems to be 
breaking the fullscreen window positioning (window gets moved to not overlap 
gnome's top panel) and layering (panels layer over it). I ifed it out for 
fullscreen, and tested several wm's, including: kwin4, flwm, fluxbox, 
enlightenment, openbox, compiz and metacity. With the change, I think all of 
that stuff is fixed.

I've got a mostly complete patch now. Except I'm getting a deadlock (I think) 
on my laptop here, and I'm not sure how to track down whats causing it. 
valgrind (drd or hellgrind) only show data races (in the keyboard event, and 
ogl transforms code), not any deadlocks.

So, I'm posting the patch here, to see if anyone can find the deadlock before I 
can (going to bed soon, so it won't be for > 12 hours).

It still needs more native xrandr testing, this deadlock has stopped my 
testing in its tracks. Can't really test it if all it does is lock up.

oh, one important detail, ex_display_options locks up when you go fullscreen, 
then back to a window. It finishes destroying the fullscreen display, and 
updating the windowed display, /then/ it locks up. 

> > Peter
> > 
> > -------------------------------------------------------------------------
> > -- --- Learn how Oracle Real Application Clusters (RAC) One Node allows
> > customers to consolidate database storage, standardize their database
> > environment, and, should the need arise, upgrade to a full multi-node
> > Oracle RAC database without downtime or disruption
> > 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 14233)
+++ include/allegro5/internal/aintern_xglx.h	(working copy)
@@ -84,13 +84,23 @@
 #endif
 #ifdef ALLEGRO_XWINDOWS_WITH_XRANDR
    int xrandr_available;
-   XRRScreenResources *xrandr_res;
+   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;
+      XRRModeInfo *mode;
+   } **xrandr_outputs;
+   
 #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 +111,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 +195,13 @@
 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);
+
 /* glx_config */
 void _al_xglx_config_select_visual(ALLEGRO_DISPLAY_XGLX *glx);
 bool _al_xglx_config_create_context(ALLEGRO_DISPLAY_XGLX *glx);
Index: src/x/xfullscreen.c
===================================================================
--- src/x/xfullscreen.c	(revision 14233)
+++ src/x/xfullscreen.c	(working copy)
@@ -14,14 +14,164 @@
     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_xscreen)(ALLEGRO_SYSTEM_XGLX *, int);
+    void (*post_setup)(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!");
+      return 0;
+   }
+   
+   if(focus == None) {
+      ALLEGRO_ERROR("XGetInputFocus returned None!\n");
+      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 :(");
+         return 0;
+      }
+      
+      focus = root;
+
+   }
+   else {
+      ALLEGRO_DEBUG("XGetInputFocus returned %i!\n", (int)focus);
+   }
+   
+   XGetWindowAttributes(s->x11display, focus, &attr);
+   focus_screen = attr.screen;
+   
+   for(i = 0; i < ScreenCount(s->x11display); i++) {
+      if(ScreenOfDisplay(s->x11display, i) == focus_screen) {
+         _al_mutex_unlock(&s->lock);
+         return i;
+      }
+   }
+   
+   _al_mutex_unlock(&s->lock);
+   return 0;
+}
+
+/* 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");
+      return;
+   }
+   
+   if(focus == None) {
+      ALLEGRO_DEBUG("XGetInputFocus returned None!\n");
+      return;
+   } else
+   if(focus == PointerRoot) {
+      ALLEGRO_DEBUG("XGetInputFocus returned PointerRoot!\n");
+      focus = DefaultRootWindow(s->x11display);
+   }
+
+   ALLEGRO_DEBUG("XGetInputFocus returned %i\n", (int)focus);
+   
+   /* 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);
+   
+   XWindowAttributes attr;
+   
+   if(XGetWindowAttributes(s->x11display, focus, &attr) == 0) {
+      ALLEGRO_ERROR("XGetWindowAttributes failed :(\n");
+      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 +238,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 +252,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,16 +314,21 @@
 {
    XRRScreenResources *res = NULL;
    bool ret = 0;
+   int xscr = 0;
+   int res_idx = 0;
 
-   if (s->xrandr_res) {
-      XRRFreeScreenResources(s->xrandr_res);
+   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);
    }
-
+   
    if (s->xrandr_outputs) {
       int i;
       for (i = 0; i < s->xrandr_output_count; i++) {
-         XRRFreeOutputInfo(s->xrandr_outputs[i]);
-         s->xrandr_outputs[i] = NULL;
+         XRRFreeOutputInfo(s->xrandr_outputs[i]->output);
+         s->xrandr_outputs[i]->output = NULL;
       }
       al_free(s->xrandr_outputs);
       s->xrandr_outputs = NULL;
@@ -136,73 +338,97 @@
    /* 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.\n", ncrtc);
 
-               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;
                   }
 
-                  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);
+
    return ret;
 }
 
@@ -213,7 +439,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 +450,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;
       }
    }
@@ -253,11 +483,13 @@
 {
    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);
+   if (adapter < 0 || adapter >= s->xrandr_output_count)
       return false;
-
-   XRRModeInfo *cur_mode = s->xrandr_stored_modes[d->xscreen];
+   
+   XRRModeInfo *cur_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));
@@ -271,23 +503,25 @@
       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);
       return false;
    }
 
-   mi = &s->xrandr_res->modes[mode_idx];
+   res = s->xrandr_res[s->xrandr_outputs[adapter]->res_id];
 
+   mi = &res->modes[mode_idx];
+
    _al_mutex_lock(&s->lock);
 
    // grab the Crtc info so we can get the info we ARENT changing to pass back to SetCrtcConfig
-   XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, s->xrandr_res, s->xrandr_outputs[d->xscreen]->crtc);
+   XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, res, s->xrandr_outputs[adapter]->output->crtc);
 
    // actually changes the mode, what a name.
    // XXX actually check for failure...
-   int ok = XRRSetCrtcConfig(s->x11display, s->xrandr_res,
-                    s->xrandr_outputs[d->xscreen]->crtc,
+   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
@@ -313,28 +547,27 @@
 
 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;
    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];
+            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);
       }
    }
@@ -345,31 +578,32 @@
    if (adapter < 0 || adapter >= s->xrandr_output_count)
       return;
    
-   ASSERT(s->xrandr_stored_modes[adapter]);
+   ASSERT(s->xrandr_outputs[adapter]->mode);
    ALLEGRO_DEBUG("xfullscreen: _al_xsys_xrandr_restore_mode (%d, %d)\n",
-                 s->xrandr_stored_modes[adapter]->width, s->xrandr_stored_modes[adapter]->height);
+                 s->xrandr_outputs[adapter]->mode->width, s->xrandr_outputs[adapter]->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];
+   XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, res, s->xrandr_outputs[adapter]->output->crtc);
    if (!crtc_info) {
       ALLEGRO_ERROR("xfullscreen: XRRGetCrtcInfo failed.\n");
       return;
    }
 
-   if (s->xrandr_stored_modes[adapter]->width == crtc_info->width &&
-      s->xrandr_stored_modes[adapter]->height == crtc_info->height) {
+   if (s->xrandr_outputs[adapter]->mode->width == crtc_info->width &&
+      s->xrandr_outputs[adapter]->mode->height == crtc_info->height) {
       ALLEGRO_INFO("xfullscreen: mode already restored.\n");
       return;
    }
    // actually changes the mode, what a name.
    int ok = XRRSetCrtcConfig(s->x11display,
-                    s->xrandr_res,
-                    s->xrandr_outputs[adapter]->crtc,
+                    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!
+                    s->xrandr_outputs[adapter]->mode->id, // Set the Mode!
                     crtc_info->rotation,
                     crtc_info->outputs,
                     crtc_info->noutput);
@@ -391,7 +625,8 @@
    } 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];
+      XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, res, s->xrandr_outputs[adapter]->output->crtc);
       if (!crtc_info) {
          ALLEGRO_ERROR("XRandR failed to get CrtcInfo, can't get display offset.\n");
          return;
@@ -399,6 +634,7 @@
 
       *x = crtc_info->x;
       *y = crtc_info->y;
+      ALLEGRO_DEBUG("xrandr: display offset: %ix%i.\n", *x, *y);
       XRRFreeCrtcInfo(crtc_info);
    }
 }
@@ -423,7 +659,8 @@
    }
 #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];
+   XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(s->x11display, res, s->xrandr_outputs[adapter]->output->crtc);
    if (!crtc_info) {
       ALLEGRO_ERROR("XRandR failed to get CrtcInfo, can't get monitor info.\n");
       return;
@@ -437,6 +674,46 @@
    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;
+   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))
+      {
+         ALLEGRO_DEBUG("xrandr selected default: %i\n", i);
+         return i;
+      }
+   }
+   
+   ALLEGRO_DEBUG("xrandr selected fallback: 0\n");
+   
+   return 0;
+}
+
+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_init(ALLEGRO_SYSTEM_XGLX *s)
 {
    int event_base = 0;
@@ -444,6 +721,8 @@
 
    /* 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;
 
@@ -487,6 +766,8 @@
       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;
    }
 
    _al_mutex_unlock(&s->lock);
@@ -494,21 +775,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;
 
@@ -530,6 +817,17 @@
 // XXX This code is completely untested. Preferably it should be tested on a machine that doesn't have any XRandR support.
 static int _al_xsys_xfvm_get_num_modes(ALLEGRO_SYSTEM_XGLX *s, int adapter)
 {
+#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) {
+      /* theres always one mode */
+      return 1;
+   }
+#endif
+
+   if(adapter < 0 || adapter > s->xfvm_screen_count)
+      return 0;
+   
    return s->xfvm_screen[adapter].mode_count;
 }
 
@@ -537,6 +835,24 @@
 {
    int denom;
 
+#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
+   /* NVidia on TwinView gives us one large screen via xfvm, and now way to
+    * properly change modes on individual monitors, so we want to query
+    * xinerama for the lone mode. */
+   /* This doesn't actually catch the case if FakeXinerama is disabled,
+    * but we can't really do much about that, especially since the code
+    * will then prefer xrandr rather than xfvm */
+   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 +868,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);
+   
+#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 +893,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 +930,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 +958,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 +969,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 +1004,9 @@
    }
 #endif
 
+   if(adapter < 0 || adapter > s->xfvm_screen_count)
+      return;
+
    XWindowAttributes xwa;
    Window root;
 
@@ -684,6 +1024,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);
+   
+   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;
@@ -756,6 +1151,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 +1208,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 +1254,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 +1279,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 +1304,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 +1361,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 +1440,41 @@
    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)
+{
+   if(d->adapter != -1)
+      return d->adapter;
+   
+   /* XXX god I hope this works */
+   return _al_xglx_get_default_adapter(s);
+}
+
 #define X11_ATOM(x)  XInternAtom(x11, #x, False);
 
 /* Note: The system mutex must be locked (exactly once) before
@@ -1066,7 +1506,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 +1515,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/xdisplay.c
===================================================================
--- src/x/xdisplay.c	(revision 14233)
+++ src/x/xdisplay.c	(working copy)
@@ -48,6 +48,8 @@
    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;
    }
 
    XSetWMNormalHints(system->x11display, glx->window, hints);
@@ -230,7 +232,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 +255,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 +268,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 +289,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;
+   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
+   // XXX Really needs to change when window is moved...
+   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 +397,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,
@@ -368,8 +429,17 @@
        * 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);
 
+      /* The version of compiz debian unstable has as I write this seems to be
+       * quirky. It needs these toggles to happen before the MapWindow or 
+       * it /sometimes/ doesn't properly position and layer our window */
+      /* where as with metacity and kwin4, they never layer correctly if
+       * these toggles don't happen /after/ the MapWindow. go figure. */
+      _al_xglx_toggle_fullscreen_window(display, 1);
+      _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);
@@ -383,8 +453,11 @@
 
    ALLEGRO_DEBUG("X11 window created.\n");
 
-   set_size_hints(display, x_off, y_off);
-
+   /* only call for windowed displays, it seems to break FULLSCREEN displays
+    * it doesn't seem to harm FULLSCREEN_WINDOW displays, but I figure it doesn't hurt to be safe */
+   if(!(display->flags & (ALLEGRO_FULLSCREEN | ALLEGRO_FULLSCREEN_WINDOW)))
+      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);
@@ -408,7 +481,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 +496,26 @@
          display->w, display->h);
    }
 
+   if (display->flags & ALLEGRO_FULLSCREEN) {
+      /* apparently the _NET_WM_STATE_FULLSCREEN flag isn't enough for metacity,
+       * it needs the _NET_WM_STATE_ABOVE flag as well, and we need to make sure
+       * to set the flags after the window is mapped, or metacity won't notice them */
+      /* kwin wants these here */
+      /* metacity wants these here too */
+      /* compiz is quiky, it will sometimes layer gnome's panel over our window
+       * with the toggle only here. */
+      _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 +647,8 @@
       }
    }
 
+   _al_xglx_unuse_adapter(s, glx->adapter);
+   
    _al_ogl_unmanage_extensions(d);
    ALLEGRO_DEBUG("unmanaged extensions.\n");
 
@@ -577,18 +662,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");
@@ -890,8 +983,17 @@
       glx->x = xevent->xconfigure.x;
       glx->y = xevent->xconfigure.y;
    }
-
+   
    _al_event_source_unlock(es);
+   
+   ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX*)al_get_system_driver();
+   int new_adapter = _al_xglx_get_default_adapter(system);
+   if(new_adapter != glx->adapter) {
+      _al_xglx_unuse_adapter(system, glx->adapter);
+      glx->adapter = new_adapter;
+      _al_xglx_use_adapter(system, glx->adapter);
+   }
+   
 }
 
 
Index: docs/src/refman/display.txt
===================================================================
--- docs/src/refman/display.txt	(revision 14233)
+++ 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).


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