[Xfce4-commits] <xfwm4:master> Fix bug #6902

Olivier Fourdan noreply at xfce.org
Wed Dec 15 19:04:06 CET 2010


Updating branch refs/heads/master
         to b71a3b996e4bffeb14eec2799f7214c00af26583 (commit)
       from 9f01853ab8406f2ee8e4261094da556c800ea999 (commit)

commit b71a3b996e4bffeb14eec2799f7214c00af26583
Author: Olivier Fourdan <fourdan at xfce.org>
Date:   Wed Dec 15 14:56:00 2010 +0100

    Fix bug #6902
    
    Implements clone monitor detection and other general xrandr
    improvements.

 src/client.c     |   41 +++++++++++++++----------
 src/client.h     |    3 +-
 src/events.c     |   75 +++++++++++++++++++++++++++++++++------------
 src/placement.c  |    2 +-
 src/screen.c     |   88 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/screen.h     |    6 ++++
 src/tabwin.c     |    7 +++-
 src/workspaces.c |    2 +-
 8 files changed, 178 insertions(+), 46 deletions(-)

diff --git a/src/client.c b/src/client.c
index f3d135a..fc6886b 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 acba0c4..00a3edd 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 8fdd867..64f3d71 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 f66f177..0a76c12 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 8b8bd1c..f210349 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 3f0348f..2c6c1b1 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 0ba290c..0be875d 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 d8fc596..1dbd555 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);
     }
 }



More information about the Xfce4-commits mailing list