summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Fourdan <fourdan@xfce.org>2010-12-15 14:56:00 +0100
committerOlivier Fourdan <fourdan@xfce.org>2010-12-15 14:57:19 +0100
commitb71a3b996e4bffeb14eec2799f7214c00af26583 (patch)
tree7eaaab516e29b8fc06c15472ca1c185c46663dbd
parent9f01853ab8406f2ee8e4261094da556c800ea999 (diff)
downloadxfwm4-b71a3b996e4bffeb14eec2799f7214c00af26583.tar.gz
Fix bug #6902
Implements clone monitor detection and other general xrandr improvements.
-rw-r--r--src/client.c41
-rw-r--r--src/client.h3
-rw-r--r--src/events.c75
-rw-r--r--src/placement.c2
-rw-r--r--src/screen.c88
-rw-r--r--src/screen.h6
-rw-r--r--src/tabwin.c7
-rw-r--r--src/workspaces.c2
8 files changed, 178 insertions, 46 deletions
diff --git a/src/client.c b/src/client.c
index f3d135a12..fc6886b6a 100644
--- a/src/client.c
+++ b/src/client.c
@@ -3466,11 +3466,12 @@ clientIncOpacity (Client * c)
/* Xrandr stuff: on screen size change, make sure all clients are still visible */
void
-clientScreenResize(ScreenInfo *screen_info)
+clientScreenResize(ScreenInfo *screen_info, gboolean fully_visible)
{
Client *c = NULL;
GList *list, *list_of_windows;
XWindowChanges wc;
+ unsigned short configure_flags;
list_of_windows = clientGetStackList (screen_info);
@@ -3502,27 +3503,33 @@ clientScreenResize(ScreenInfo *screen_info)
/* Recompute size and position of maximized windows */
if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ | CLIENT_FLAG_MAXIMIZED_VERT))
{
- /* Too bad, the flags used internally are different from the WIN_STATE_* bits */
- maximization_flags |= FLAG_TEST (c->flags,
- CLIENT_FLAG_MAXIMIZED_HORIZ) ? WIN_STATE_MAXIMIZED_HORIZ : 0;
- maximization_flags |= FLAG_TEST (c->flags,
- CLIENT_FLAG_MAXIMIZED_VERT) ? WIN_STATE_MAXIMIZED_VERT : 0;
+ /* Too bad, the flags used internally are different from the WIN_STATE_* bits */
+ maximization_flags |= FLAG_TEST (c->flags,
+ CLIENT_FLAG_MAXIMIZED_HORIZ) ? WIN_STATE_MAXIMIZED_HORIZ : 0;
+ maximization_flags |= FLAG_TEST (c->flags,
+ CLIENT_FLAG_MAXIMIZED_VERT) ? WIN_STATE_MAXIMIZED_VERT : 0;
- /* Force an update by clearing the internal flags */
- FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ | CLIENT_FLAG_MAXIMIZED_VERT);
- clientToggleMaximized (c, maximization_flags, FALSE);
+ /* Force an update by clearing the internal flags */
+ FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ | CLIENT_FLAG_MAXIMIZED_VERT);
+ clientToggleMaximized (c, maximization_flags, FALSE);
- wc.x = c->x;
- wc.y = c->y;
- wc.width = c->width;
- wc.height = c->height;
- clientConfigure (c, &wc, CWX | CWY | CWWidth | CWHeight, CFG_NOTIFY);
+ wc.x = c->x;
+ wc.y = c->y;
+ wc.width = c->width;
+ wc.height = c->height;
+ clientConfigure (c, &wc, CWX | CWY | CWWidth | CWHeight, CFG_NOTIFY);
}
else
{
- wc.x = c->x;
- wc.y = c->y;
- clientConfigure (c, &wc, CWX | CWY, CFG_CONSTRAINED | CFG_REQUEST);
+ configure_flags = CFG_CONSTRAINED | CFG_REQUEST;
+ if (fully_visible)
+ {
+ configure_flags |= CFG_KEEP_VISIBLE;
+ }
+
+ wc.x = c->x;
+ wc.y = c->y;
+ clientConfigure (c, &wc, CWX | CWY, configure_flags);
}
}
diff --git a/src/client.h b/src/client.h
index acba0c4ff..00a3eddd7 100644
--- a/src/client.h
+++ b/src/client.h
@@ -433,7 +433,8 @@ void clientSetOpacity (Client *,
guint, guint);
void clientIncOpacity (Client *);
void clientDecOpacity (Client *);
-void clientScreenResize (ScreenInfo *);
+void clientScreenResize (ScreenInfo *,
+ gboolean);
void clientButtonPress (Client *,
Window,
XButtonEvent *);
diff --git a/src/events.c b/src/events.c
index 8fdd86757..64f3d7172 100644
--- a/src/events.c
+++ b/src/events.c
@@ -2785,6 +2785,10 @@ refresh_font_cb (GObject * obj, GdkEvent * ev, gpointer data)
return (TRUE);
}
+/*
+ * The size-changed signal is emitted when the pixel width or height
+ * of a screen changes.
+ */
static void
size_changed_cb(GdkScreen *gscreen, gpointer data)
{
@@ -2808,45 +2812,76 @@ size_changed_cb(GdkScreen *gscreen, gpointer data)
return;
}
- /*
- * We have added/removed a monitor or even changed the layout,
- * the cache for monitor position we use in our screen structure
- * is not valid anymore and potentially refers to a monitor that
- * was just removed, so invalidate it.
- */
- screen_info->cache_monitor.x = -1;
- screen_info->cache_monitor.y = -1;
- screen_info->cache_monitor.width = 0;
- screen_info->cache_monitor.height = 0;
-
size_changed = myScreenComputeSize (screen_info);
- setNetWorkarea (display_info, screen_info->xroot, screen_info->workspace_count,
- screen_info->width, screen_info->height, screen_info->margins);
- placeSidewalks (screen_info, screen_info->params->wrap_workspaces);
- clientScreenResize (screen_info);
-
if (size_changed)
{
+ myScreenInvalidateMonitorCache (screen_info);
+
+ setNetWorkarea (display_info, screen_info->xroot, screen_info->workspace_count,
+ screen_info->width, screen_info->height, screen_info->margins);
+
+ placeSidewalks (screen_info, screen_info->params->wrap_workspaces);
+
+ clientScreenResize (screen_info, FALSE);
+
compositorUpdateScreenSize (screen_info);
}
}
+/*
+ * The monitors-changed signal is emitted when the number, size or
+ * position of the monitors attached to the screen change.
+ */
static void
monitors_changed_cb(GdkScreen *gscreen, gpointer data)
{
ScreenInfo *screen_info;
+ DisplayInfo *display_info;
+ gint previous_num_monitors;
+ gboolean size_changed;
TRACE ("entering monitors_changed_cb");
screen_info = (ScreenInfo *) data;
g_return_if_fail (screen_info);
+ display_info = screen_info->display_info;
+
+ if (gdk_screen_get_n_monitors (screen_info->gscr) == 0)
+ {
+ /*
+ * Recent Xorg drivers disable the output when the lid
+ * is closed, leaving no active monitor, in that case simply
+ * ignore the event to avoid messing with windows' positions.
+ */
+ return;
+ }
/*
- * From the window manager point of view,
- * a XRand 1.2 monitor change is similar to
- * a screen size change.
+ * We have added/removed a monitor or even changed the layout,
+ * the cache for monitor position we use in our screen structure
+ * is not valid anymore and potentially refers to a monitor that
+ * was just removed, so invalidate it.
*/
- size_changed_cb (gscreen, data);
+ previous_num_monitors = screen_info->num_monitors;
+ myScreenInvalidateMonitorCache (screen_info);
+ myScreenRebuildMonitorIndex (screen_info);
+ size_changed = myScreenComputeSize (screen_info);
+
+ if (size_changed || (screen_info->num_monitors != previous_num_monitors))
+ {
+
+ setNetWorkarea (display_info, screen_info->xroot, screen_info->workspace_count,
+ screen_info->width, screen_info->height, screen_info->margins);
+
+ placeSidewalks (screen_info, screen_info->params->wrap_workspaces);
+
+ clientScreenResize (screen_info, (screen_info->num_monitors < previous_num_monitors));
+ }
+
+ if (size_changed)
+ {
+ compositorUpdateScreenSize (screen_info);
+ }
}
void
diff --git a/src/placement.c b/src/placement.c
index f66f1775e..0a76c1212 100644
--- a/src/placement.c
+++ b/src/placement.c
@@ -664,7 +664,7 @@ clientInitPosition (Client * c)
msy = 0;
position = (c->size->flags & (PPosition | USPosition));
- n_monitors = gdk_screen_get_n_monitors (c->screen_info->gscr);
+ n_monitors = myScreenGetNumMonitors (c->screen_info);
if ((n_monitors > 1) || (screen_info->params->placement_mode == PLACE_MOUSE))
{
getMouseXY (screen_info, screen_info->xroot, &msx, &msy);
diff --git a/src/screen.c b/src/screen.c
index 8b8bd1cb7..f210349c4 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -313,7 +313,9 @@ myScreenInit (DisplayInfo *display_info, GdkScreen *gscr, unsigned long event_ma
xfwmPixmapInit (screen_info, &screen_info->top[i][INACTIVE]);
}
+ screen_info->monitors_index = NULL;
myScreenInvalidateMonitorCache (screen_info);
+ myScreenRebuildMonitorIndex (screen_info);
return (screen_info);
}
@@ -363,6 +365,12 @@ myScreenClose (ScreenInfo *screen_info)
g_list_free (screen_info->windows);
screen_info->windows = NULL;
+ if (screen_info->monitors_index)
+ {
+ g_array_free (screen_info->monitors_index, TRUE);
+ screen_info->monitors_index = NULL;
+ }
+
return (screen_info);
}
@@ -611,14 +619,83 @@ myScreenComputeSize (ScreenInfo *screen_info)
return changed;
}
+gint
+myScreenGetNumMonitors (ScreenInfo *screen_info)
+{
+ g_return_val_if_fail (screen_info != NULL, 0);
+ g_return_val_if_fail (screen_info->monitors_index != NULL, 0);
+ TRACE ("entering myScreenGetNMonitors");
+
+ return (screen_info->monitors_index->len);
+}
+
+gint
+myScreenGetMonitorIndex (ScreenInfo *screen_info, gint idx)
+{
+ g_return_val_if_fail (screen_info != NULL, 0);
+ g_return_val_if_fail (screen_info->monitors_index != NULL, 0);
+ TRACE ("entering myScreenGetMonitorIndex");
+
+ return (g_array_index (screen_info->monitors_index, gint, idx));
+}
+
+gboolean
+myScreenRebuildMonitorIndex (ScreenInfo *screen_info)
+{
+ gint i, j, num_monitors, previous_num_monitors;
+ GdkRectangle monitor, previous;
+ gboolean cloned;
+
+ g_return_val_if_fail (screen_info != NULL, FALSE);
+ TRACE ("entering myScreenRebuildMonitorIndex");
+
+ previous_num_monitors = screen_info->num_monitors;
+ screen_info->num_monitors = 0;
+
+ if (screen_info->monitors_index)
+ {
+ g_array_free (screen_info->monitors_index, TRUE);
+ }
+ screen_info->monitors_index = g_array_new (FALSE, TRUE, sizeof (guint));
+
+ /* GDK already sorts monitors for us, for "cloned" monitors, sort
+ * the bigger ones first (giving preference to taller monitors
+ * over wider monitors)
+ */
+ num_monitors = gdk_screen_get_n_monitors (screen_info->gscr);
+ for (i = 0; i < num_monitors; i++)
+ {
+ gdk_screen_get_monitor_geometry (screen_info->gscr, i, &monitor);
+ cloned = FALSE;
+ for (j = 0; j < (gint) screen_info->monitors_index->len; j++)
+ {
+ gdk_screen_get_monitor_geometry (screen_info->gscr, j, &previous);
+ if ((previous.x == monitor.x) && (previous.y == monitor.y))
+ {
+ cloned = TRUE;
+ }
+ }
+ if (!cloned)
+ {
+ screen_info->num_monitors++;
+ g_array_append_val (screen_info->monitors_index , i);
+ }
+ }
+
+ TRACE ("Physical monitor reported.: %i", num_monitors);
+ TRACE ("Logical views found.......: %i", screen_info->num_monitors);
+
+ return (screen_info->num_monitors != previous_num_monitors);
+}
+
void
myScreenInvalidateMonitorCache (ScreenInfo *screen_info)
{
g_return_if_fail (screen_info != NULL);
TRACE ("entering myScreenInvalidateMonitorCache");
- screen_info->cache_monitor.x = G_MAXINT;
- screen_info->cache_monitor.y = G_MAXINT;
+ screen_info->cache_monitor.x = -1;
+ screen_info->cache_monitor.y = -1;
screen_info->cache_monitor.width = 0;
screen_info->cache_monitor.height = 0;
}
@@ -648,11 +725,14 @@ myScreenFindMonitorAtPoint (ScreenInfo *screen_info, gint x, gint y, GdkRectangl
}
min_distsquare = G_MAXUINT32;
- num_monitors = gdk_screen_get_n_monitors (screen_info->gscr);
+ num_monitors = myScreenGetNumMonitors (screen_info);
for (i = 0; i < num_monitors; i++)
{
- gdk_screen_get_monitor_geometry (screen_info->gscr, i, &monitor);
+ gint monitor_index;
+
+ monitor_index = myScreenGetMonitorIndex (screen_info, i);
+ gdk_screen_get_monitor_geometry (screen_info->gscr, monitor_index, &monitor);
if ((x >= monitor.x) && (x < (monitor.x + monitor.width)) &&
(y >= monitor.y) && (y < (monitor.y + monitor.height)))
diff --git a/src/screen.h b/src/screen.h
index 3f0348f00..2c6c1b1c7 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -118,6 +118,8 @@ struct _ScreenInfo
/* Monitor search caching */
GdkRectangle cache_monitor;
+ gint num_monitors;
+ GArray *monitors_index;
/* Workspace definitions */
guint workspace_count;
@@ -214,6 +216,10 @@ Client *myScreenGetClientFromWindow (ScreenInfo *,
Window,
unsigned short);
gboolean myScreenComputeSize (ScreenInfo *);
+gint myScreenGetNumMonitors (ScreenInfo *);
+gint myScreenGetMonitorIndex (ScreenInfo *,
+ gint);
+gboolean myScreenRebuildMonitorIndex (ScreenInfo *);
void myScreenInvalidateMonitorCache (ScreenInfo *);
void myScreenFindMonitorAtPoint (ScreenInfo *,
gint,
diff --git a/src/tabwin.c b/src/tabwin.c
index 0ba290c81..0be875d08 100644
--- a/src/tabwin.c
+++ b/src/tabwin.c
@@ -402,10 +402,13 @@ tabwinCreate (GList **client_list, GList *selected, gboolean display_workspace)
tabwin->client_list = client_list;
tabwin->selected = selected;
tabwin->tabwin_list = NULL;
- num_monitors = gdk_screen_get_n_monitors (screen_info->gscr);
+ num_monitors = myScreenGetNumMonitors (screen_info);
for (i = 0; i < num_monitors; i++)
{
- tabwin->tabwin_list = g_list_append (tabwin->tabwin_list, tabwinCreateWidget (tabwin, screen_info, i));
+ gint monitor_index;
+
+ monitor_index = myScreenGetMonitorIndex(screen_info, i);
+ tabwin->tabwin_list = g_list_append (tabwin->tabwin_list, tabwinCreateWidget (tabwin, screen_info, monitor_index));
}
return tabwin;
diff --git a/src/workspaces.c b/src/workspaces.c
index d8fc596a5..1dbd555f0 100644
--- a/src/workspaces.c
+++ b/src/workspaces.c
@@ -569,6 +569,6 @@ workspaceUpdateArea (ScreenInfo *screen_info)
setNetWorkarea (display_info, screen_info->xroot, screen_info->workspace_count,
screen_info->width, screen_info->height, screen_info->margins);
/* Also prevent windows from being off screen, just like when screen is resized */
- clientScreenResize(screen_info);
+ clientScreenResize(screen_info, FALSE);
}
}