diff options
author | Olivier Fourdan <fourdan@xfce.org> | 2010-12-15 14:56:00 +0100 |
---|---|---|
committer | Olivier Fourdan <fourdan@xfce.org> | 2010-12-15 14:57:19 +0100 |
commit | b71a3b996e4bffeb14eec2799f7214c00af26583 (patch) | |
tree | 7eaaab516e29b8fc06c15472ca1c185c46663dbd | |
parent | 9f01853ab8406f2ee8e4261094da556c800ea999 (diff) | |
download | xfwm4-b71a3b996e4bffeb14eec2799f7214c00af26583.tar.gz |
Fix bug #6902
Implements clone monitor detection and other general xrandr
improvements.
-rw-r--r-- | src/client.c | 41 | ||||
-rw-r--r-- | src/client.h | 3 | ||||
-rw-r--r-- | src/events.c | 75 | ||||
-rw-r--r-- | src/placement.c | 2 | ||||
-rw-r--r-- | src/screen.c | 88 | ||||
-rw-r--r-- | src/screen.h | 6 | ||||
-rw-r--r-- | src/tabwin.c | 7 | ||||
-rw-r--r-- | src/workspaces.c | 2 |
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); } } |