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



commit ec6edeeb170855726d11d609bc006d3c3839b94d
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 | 103 ++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 103 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..b0deb64bb 100644
--- a/windowpicker/src/task-list.c
+++ b/windowpicker/src/task-list.c
@@ -23,10 +23,12 @@
 
 #include <libwnck/libwnck.h>
 #include <panel-applet.h>
+#include <X11/Xlib.h>
 
 struct _TaskListPrivate {
     WnckScreen *screen;
     WpApplet *windowPickerApplet;
+    guint size_update_event_source;
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE (TaskList, task_list, GTK_TYPE_BOX);
@@ -61,11 +63,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 +210,90 @@ 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)
+{
+  TaskList *list;
+  GdkWindow *window;
+  gint list_monitor;
+
+  list = user_data;
+  window = gtk_widget_get_window (GTK_WIDGET (list));
+
+  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);
+
+  list->priv->size_update_event_source = 0;
+
+  return G_SOURCE_REMOVE;
+}
+
+
+static GdkFilterReturn window_filter_function (GdkXEvent *gdk_xevent,
+                                               GdkEvent *event,
+                                               gpointer user_data)
+{
+  TaskList *list = user_data;
+
+  XEvent *xevent = (XEvent *) gdk_xevent;
+
+  switch (xevent->type)
+  {
+    case PropertyNotify:
+    {
+      XPropertyEvent *propertyEvent;
+
+      propertyEvent = (XPropertyEvent *) xevent;
+
+      const Atom WORKAREA_ATOM = XInternAtom (propertyEvent->display,
+                                              "_NET_WORKAREA", True);
+
+      if (propertyEvent->atom != WORKAREA_ATOM)
+        return GDK_FILTER_CONTINUE;
+
+      if (list->priv->size_update_event_source != 0)
+        return GDK_FILTER_CONTINUE;
+
+      list->priv->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)
 {
@@ -229,6 +312,10 @@ task_list_finalize (GObject *object)
 
     task_lists = g_slist_remove (task_lists, taskList);
 
+    gdk_window_remove_filter (gtk_widget_get_window (GTK_WIDGET (taskList)),
+                              window_filter_function,
+                              taskList);
+
     G_OBJECT_CLASS (task_list_parent_class)->finalize (object);
 }
 
@@ -238,6 +325,8 @@ task_list_class_init(TaskListClass *class) {
 
     obj_class->dispose = task_list_dispose;
     obj_class->finalize = task_list_finalize;
+
+    task_lists = NULL;
 }
 
 static void task_list_init (TaskList *list) {
@@ -276,6 +365,10 @@ GtkWidget *task_list_new (WpApplet *windowPickerApplet) {
     g_signal_connect (taskList->priv->screen, "window-opened",
             G_CALLBACK (on_window_opened), taskList);
 
+    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]