[notification-daemon] Also respond to monitor size changes



commit 7889698ec9041c0979869e6d9230acc29dee159d
Author: William Jon McCann <jmccann redhat com>
Date:   Thu Jun 24 14:35:17 2010 -0400

    Also respond to monitor size changes
    
    By watching for changes to _NET_WORKAREA.  Responding to changes
    in screen or monitor size isn't enough since we compute the position
    relative to the work area.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=622552

 src/daemon/daemon.c |   63 +++++++++++++++++++++++++++++++++++---------------
 src/daemon/stack.c  |   54 +++++++++++++++++++++++++++++++++++--------
 src/daemon/stack.h  |    1 +
 3 files changed, 89 insertions(+), 29 deletions(-)
---
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
index a96c274..af93fce 100644
--- a/src/daemon/daemon.c
+++ b/src/daemon/daemon.c
@@ -97,6 +97,7 @@ typedef struct
 {
         NotifyStack   **stacks;
         int             n_stacks;
+        Atom            workarea_atom;
 } NotifyScreen;
 
 struct _NotifyDaemonPrivate
@@ -233,13 +234,7 @@ on_screen_monitors_changed (GdkScreen    *screen,
 
         n_monitors = gdk_screen_get_n_monitors (screen);
 
-        g_debug ("Monitors changed for screen %d: num=%d",
-                 screen_num,
-                 n_monitors);
-
-        if (n_monitors == nscreen->n_stacks) {
-                return;
-        } else if (n_monitors > nscreen->n_stacks) {
+        if (n_monitors > nscreen->n_stacks) {
                 /* grow */
                 nscreen->stacks = g_renew (NotifyStack *,
                                            nscreen->stacks,
@@ -251,7 +246,7 @@ on_screen_monitors_changed (GdkScreen    *screen,
                 }
 
                 nscreen->n_stacks = n_monitors;
-        } else {
+        } else if (n_monitors < nscreen->n_stacks) {
                 NotifyStack *last_stack;
 
                 last_stack = nscreen->stacks[n_monitors - 1];
@@ -265,11 +260,6 @@ on_screen_monitors_changed (GdkScreen    *screen,
                         stack = nscreen->stacks[i];
                         windows = g_list_copy (notify_stack_get_windows (stack));
                         for (l = windows; l != NULL; l = l->next) {
-                                g_debug ("Transferring window %p from %d to %d",
-                                         l->data,
-                                         i,
-                                         n_monitors - 1);
-
                                 /* skip removing the window from the
                                    old stack since it will try to
                                    unrealize the window.  And the
@@ -306,15 +296,32 @@ create_stacks_for_screen (NotifyDaemon *daemon,
                                    nscreen->stacks,
                                    nscreen->n_stacks);
 
-        g_debug ("Creating %d stacks for screen %d",
-                 nscreen->n_stacks,
-                 screen_num);
-
         for (i = 0; i < nscreen->n_stacks; i++) {
                 create_stack_for_monitor (daemon, screen, i);
         }
 }
 
+static GdkFilterReturn
+screen_xevent_filter (GdkXEvent    *xevent,
+                      GdkEvent     *event,
+                      NotifyScreen *nscreen)
+{
+        XEvent *xev;
+
+        xev = (XEvent *) xevent;
+
+        if (xev->type == PropertyNotify &&
+            xev->xproperty.atom == nscreen->workarea_atom) {
+                int i;
+
+                for (i = 0; i < nscreen->n_stacks; i++) {
+                        notify_stack_queue_update_position (nscreen->stacks[i]);
+                }
+        }
+
+        return GDK_FILTER_CONTINUE;
+}
+
 static void
 create_screens (NotifyDaemon *daemon)
 {
@@ -329,11 +336,22 @@ create_screens (NotifyDaemon *daemon)
         daemon->priv->screens = g_new0 (NotifyScreen *, daemon->priv->n_screens);
 
         for (i = 0; i < daemon->priv->n_screens; i++) {
-                g_signal_connect (gdk_display_get_screen (display, i),
+                GdkScreen *screen;
+                GdkWindow *gdkwindow;
+
+                screen = gdk_display_get_screen (display, i);
+                g_signal_connect (screen,
                                   "monitors-changed",
                                   G_CALLBACK (on_screen_monitors_changed),
                                   daemon);
+
                 daemon->priv->screens[i] = g_new0 (NotifyScreen, 1);
+
+                daemon->priv->screens[i]->workarea_atom = XInternAtom (GDK_DISPLAY (), "_NET_WORKAREA", True);
+                gdkwindow = gdk_screen_get_root_window (screen);
+                gdk_window_add_filter (gdkwindow, (GdkFilterFunc) screen_xevent_filter, daemon->priv->screens[i]);
+                gdk_window_set_events (gdkwindow, gdk_window_get_events (gdkwindow) | GDK_PROPERTY_CHANGE_MASK);
+
                 create_stacks_for_screen (daemon, gdk_display_get_screen (display, i));
         }
 }
@@ -434,9 +452,16 @@ destroy_screens (NotifyDaemon *daemon)
         display = gdk_display_get_default ();
 
         for (i = 0; i < daemon->priv->n_screens; i++) {
-                g_signal_handlers_disconnect_by_func (gdk_display_get_screen (display, i),
+                GdkScreen *screen;
+                GdkWindow *gdkwindow;
+
+                screen = gdk_display_get_screen (display, i);
+                g_signal_handlers_disconnect_by_func (screen,
                                                       G_CALLBACK (on_screen_monitors_changed),
                                                       daemon);
+
+                gdkwindow = gdk_screen_get_root_window (screen);
+                gdk_window_remove_filter (gdkwindow, (GdkFilterFunc) screen_xevent_filter, daemon->priv->screens[i]);
                 for (j = 0; i < daemon->priv->screens[i]->n_stacks; j++) {
                         notify_stack_destroy (daemon->priv->screens[i]->stacks[j]);
                         daemon->priv->screens[i]->stacks[j] = NULL;
diff --git a/src/daemon/stack.c b/src/daemon/stack.c
index 20447a4..936edbe 100644
--- a/src/daemon/stack.c
+++ b/src/daemon/stack.c
@@ -39,6 +39,7 @@ struct _NotifyStack
         guint               monitor;
         NotifyStackLocation location;
         GList              *windows;
+        guint               update_id;
 };
 
 GList *
@@ -48,7 +49,7 @@ notify_stack_get_windows (NotifyStack *stack)
 }
 
 static gboolean
-get_work_area (GtkWidget    *nw,
+get_work_area (NotifyStack  *stack,
                GdkRectangle *rect)
 {
         Atom            workarea;
@@ -61,19 +62,17 @@ get_work_area (GtkWidget    *nw,
         guchar         *ret_workarea;
         long           *workareas;
         int             result;
-        GdkScreen      *screen;
         int             disp_screen;
 
         workarea = XInternAtom (GDK_DISPLAY (), "_NET_WORKAREA", True);
-        gtk_widget_realize (nw);
-        screen = gdk_drawable_get_screen (GDK_DRAWABLE (nw->window));
-        disp_screen = GDK_SCREEN_XNUMBER (screen);
+
+        disp_screen = GDK_SCREEN_XNUMBER (stack->screen);
 
         /* Defaults in case of error */
         rect->x = 0;
         rect->y = 0;
-        rect->width = gdk_screen_get_width (screen);
-        rect->height = gdk_screen_get_height (screen);
+        rect->width = gdk_screen_get_width (stack->screen);
+        rect->height = gdk_screen_get_height (stack->screen);
 
         if (workarea == None)
                 return FALSE;
@@ -214,6 +213,10 @@ notify_stack_destroy (NotifyStack *stack)
 {
         g_assert (stack != NULL);
 
+        if (stack->update_id != 0) {
+                g_source_remove (stack->update_id);
+        }
+
         g_list_free (stack->windows);
         g_free (stack);
 }
@@ -258,7 +261,7 @@ notify_stack_shift_notifications (NotifyStack *stack,
         int             i;
         int             n_wins;
 
-        get_work_area (GTK_WIDGET (nw), &workarea);
+        get_work_area (stack, &workarea);
         gdk_screen_get_monitor_geometry (stack->screen,
                                          stack->monitor,
                                          &monitor);
@@ -287,7 +290,7 @@ notify_stack_shift_notifications (NotifyStack *stack,
                 GtkWindow      *nw2 = GTK_WINDOW (l->data);
                 GtkRequisition  req;
 
-                if (nw2 != nw) {
+                if (nw == NULL || nw2 != nw) {
                         gtk_widget_size_request (GTK_WIDGET (nw2), &req);
 
                         translate_coordinates (stack->location,
@@ -312,7 +315,7 @@ notify_stack_shift_notifications (NotifyStack *stack,
         for (i = n_wins - 1, l = g_list_last (stack->windows); l != NULL; i--, l = l->prev) {
                 GtkWindow *nw2 = GTK_WINDOW (l->data);
 
-                if (nw2 != nw) {
+                if (nw == NULL || nw2 != nw) {
                         theme_move_notification (nw2, positions[i].x, positions[i].y);
                 }
         }
@@ -320,6 +323,37 @@ notify_stack_shift_notifications (NotifyStack *stack,
         g_free (positions);
 }
 
+static void
+update_position (NotifyStack *stack)
+{
+        notify_stack_shift_notifications (stack,
+                                          NULL, /* window */
+                                          NULL, /* list pointer */
+                                          0, /* init width */
+                                          0, /* init height */
+                                          NULL, /* out window x */
+                                          NULL); /* out window y */
+}
+
+static gboolean
+update_position_idle (NotifyStack *stack)
+{
+        update_position (stack);
+
+        stack->update_id = 0;
+        return FALSE;
+}
+
+void
+notify_stack_queue_update_position (NotifyStack *stack)
+{
+        if (stack->update_id != 0) {
+                return;
+        }
+
+        stack->update_id = g_idle_add ((GSourceFunc) update_position_idle, stack);
+}
+
 void
 notify_stack_add_window (NotifyStack *stack,
                          GtkWindow   *nw,
diff --git a/src/daemon/stack.h b/src/daemon/stack.h
index cc043a2..f9f9172 100644
--- a/src/daemon/stack.h
+++ b/src/daemon/stack.h
@@ -52,5 +52,6 @@ void            notify_stack_add_window    (NotifyStack        *stack,
 void            notify_stack_remove_window (NotifyStack        *stack,
                                             GtkWindow          *nw);
 GList *         notify_stack_get_windows   (NotifyStack        *stack);
+void            notify_stack_queue_update_position (NotifyStack        *stack);
 
 #endif /* _NOTIFY_STACK_H_ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]