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, ¢er_x, ¢er_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, ¢er_x, ¢er_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");