[gnome-applets/wip/windowpicker] windowpicker: fix item assignment on workarea change



commit f9ffc045eb957a5786b6d8b76a8d6855f6454623
Author: Sebastian Geiger <sbastig gmx net>
Date:   Sun Dec 9 17:16:56 2018 +0100

    windowpicker: fix item assignment on workarea change
    
    This fixes a long standing issue on multi-monitor setups.
    When a panel moves to another monitor then the assignment
    of task items to the task list needs to be recomputed.
    
    This patch fixes the issue by listening for changes
    of the workarea and reinitializes the task lists.

 configure.ac                 |   3 ++
 windowpicker/src/Makefile.am |   2 +
 windowpicker/src/task-list.c | 108 +++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 108 insertions(+), 5 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 358c4f49c..cf90abbd8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -129,6 +129,9 @@ fi
 AC_MSG_NOTICE([installing applets in $LIBPANEL_APPLET_DIR])
 AC_SUBST(LIBPANEL_APPLET_DIR)
 
+dnl -- check for X11 (required) -----------------------------------------------
+PKG_CHECK_MODULES([X11], [x11])
+
 dnl -- check for libgtop (optional) -------------------------------------------
 build_gtop_applets=false
 PKG_CHECK_MODULES(GTOP_APPLETS,
diff --git a/windowpicker/src/Makefile.am b/windowpicker/src/Makefile.am
index 352e159c4..cb55229cd 100644
--- a/windowpicker/src/Makefile.am
+++ b/windowpicker/src/Makefile.am
@@ -13,6 +13,7 @@ libwindow_picker_applet_la_CFLAGS = \
        -I$(top_srcdir) \
        $(GNOME_APPLETS_CFLAGS) \
        $(LIBWNCK_CFLAGS) \
+       $(X11_CFLAGS) \
        $(GCC_FLAGS) \
        $(WARN_CFLAGS) \
        $(AM_CFLAGS) \
@@ -27,6 +28,7 @@ libwindow_picker_applet_la_LDFLAGS = \
 libwindow_picker_applet_la_LIBADD = \
        $(GNOME_APPLETS_LIBS) \
        $(LIBWNCK_LIBS) \
+       $(X11_LIBS) \
        $(LIBM) \
        $(NULL)
 
diff --git a/windowpicker/src/task-list.c b/windowpicker/src/task-list.c
index 312f59c60..3f8742fc7 100644
--- a/windowpicker/src/task-list.c
+++ b/windowpicker/src/task-list.c
@@ -23,6 +23,7 @@
 
 #include <libwnck/libwnck.h>
 #include <panel-applet.h>
+#include <X11/Xlib.h>
 
 struct _TaskListPrivate {
     WnckScreen *screen;
@@ -32,6 +33,8 @@ struct _TaskListPrivate {
 G_DEFINE_TYPE_WITH_PRIVATE (TaskList, task_list, GTK_TYPE_BOX);
 
 static GSList *task_lists;
+static gboolean has_filter;
+guint size_update_event_source;
 
 static TaskList *
 get_task_list_for_monitor (TaskList *task_list,
@@ -61,11 +64,8 @@ static void on_task_item_closed (
     TaskItem *item,
     TaskList *list)
 {
-    gtk_container_remove (
-        GTK_CONTAINER (list),
-        GTK_WIDGET (item)
-    );
-    gtk_widget_destroy (GTK_WIDGET (item));
+    gtk_container_remove (GTK_CONTAINER (list),
+                          GTK_WIDGET (item));
 }
 
 static gint
@@ -211,6 +211,92 @@ static void on_task_list_orient_changed(PanelApplet *applet,
     gtk_widget_queue_resize(GTK_WIDGET(box));
 }
 
+static void
+remove_task_item (GtkWidget *item, gpointer list)
+{
+  g_return_if_fail (TASK_IS_LIST (list));
+
+  gtk_container_remove (GTK_CONTAINER (list), item);
+}
+
+static gboolean
+on_monitors_changed (gpointer user_data)
+{
+  GList *current_list = task_lists;
+
+  while (current_list != NULL)
+  {
+    TaskList *list = current_list->data;
+    GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (list));
+    gint list_monitor;
+
+    g_signal_handlers_block_by_func (list->priv->screen,
+                                     on_window_opened,
+                                     list);
+
+    list_monitor = gdk_screen_get_monitor_at_window (gdk_screen_get_default (),
+                                                     window);
+
+    if (task_list_get_monitor (list) == list_monitor)
+    {
+      gtk_container_foreach (GTK_CONTAINER (list), remove_task_item, list);
+    }
+
+    GList *windows = wnck_screen_get_windows (list->priv->screen);
+
+    while (windows != NULL)
+    {
+      on_window_opened (list->priv->screen, windows->data, list);
+      windows = windows->next;
+    }
+
+    g_signal_handlers_unblock_by_func (list->priv->screen,
+                                       on_window_opened,
+                                       NULL);
+
+    current_list = current_list->next;
+  }
+
+  size_update_event_source = 0;
+
+  return G_SOURCE_REMOVE;
+}
+
+
+static GdkFilterReturn window_filter_function (GdkXEvent *gdk_xevent,
+                                               GdkEvent *event,
+                                               gpointer user_data)
+{
+  XEvent *xevent = (XEvent *) gdk_xevent;
+
+  switch (xevent->type)
+  {
+    case PropertyNotify:
+    {
+      XPropertyEvent *propertyEvent;
+
+      propertyEvent = xevent;
+
+      const Atom WORKAREA_ATOM = XInternAtom (propertyEvent->display,
+                                              "_NET_WORKAREA", True);
+
+      if (propertyEvent->atom != WORKAREA_ATOM)
+        return GDK_FILTER_CONTINUE;
+
+      if (size_update_event_source != 0)
+        return GDK_FILTER_CONTINUE;
+
+      size_update_event_source = g_idle_add (on_monitors_changed,
+                                             user_data);
+
+      break;
+    }
+    default:break;
+  }
+
+  return GDK_FILTER_CONTINUE;
+}
+
 static void
 task_list_dispose (GObject *object)
 {
@@ -238,6 +324,9 @@ task_list_class_init(TaskListClass *class) {
 
     obj_class->dispose = task_list_dispose;
     obj_class->finalize = task_list_finalize;
+
+    task_lists = NULL;
+    has_filter = FALSE;
 }
 
 static void task_list_init (TaskList *list) {
@@ -276,6 +365,15 @@ GtkWidget *task_list_new (WpApplet *windowPickerApplet) {
     g_signal_connect (taskList->priv->screen, "window-opened",
             G_CALLBACK (on_window_opened), taskList);
 
+    if (!has_filter)
+      {
+        has_filter = TRUE;
+
+        gdk_window_add_filter (gtk_widget_get_window (GTK_WIDGET (taskList)),
+                               window_filter_function,
+                               taskList);
+      }
+
     GList *windows = wnck_screen_get_windows (taskList->priv->screen);
     while (windows != NULL) {
         on_window_opened (taskList->priv->screen, windows->data, taskList);


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