]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/xsettings-client.c
x11: Don't keep an "in_init" variable
[~andy/gtk] / gdk / x11 / xsettings-client.c
index 5edeb46622e836f7e8086cdc6a045e6a858d4b4b..5eb168163a5160df9c311742a26d2e9d786bf838 100644 (file)
 
 #include "gdksettings.c"
 
+/* Types of settings possible. Enum values correspond to
+ * protocol values.
+ */
+typedef enum 
+{
+  XSETTINGS_TYPE_INT     = 0,
+  XSETTINGS_TYPE_STRING  = 1,
+  XSETTINGS_TYPE_COLOR   = 2
+} XSettingsType;
+
 typedef struct _XSettingsBuffer  XSettingsBuffer;
 
 struct _XSettingsBuffer
@@ -53,9 +63,8 @@ struct _XSettingsBuffer
 struct _XSettingsClient
 {
   GdkScreen *screen;
-  Display *display;
 
-  Window manager_window;
+  GdkWindow *manager_window;
   Atom selection_atom;
 
   GHashTable *settings; /* string of GDK settings name => XSettingsSetting */
@@ -64,15 +73,10 @@ struct _XSettingsClient
 static void
 gdk_xsettings_notify (const char       *name,
                      GdkSettingAction  action,
-                     XSettingsSetting *setting,
                      GdkScreen        *screen)
 {
   GdkEvent new_event;
-  GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
 
-  if (x11_screen->xsettings_in_init)
-    return;
-  
   new_event.type = GDK_SETTING;
   new_event.setting.window = gdk_screen_get_root_window (screen);
   new_event.setting.send_event = FALSE;
@@ -82,12 +86,33 @@ gdk_xsettings_notify (const char       *name,
   gdk_event_put (&new_event);
 }
 
+static gboolean
+value_equal (const GValue *value_a,
+             const GValue *value_b)
+{
+  if (G_VALUE_TYPE (value_a) != G_VALUE_TYPE (value_b))
+    return FALSE;
+
+  switch (G_VALUE_TYPE (value_a))
+    {
+    case G_TYPE_INT:
+      return g_value_get_int (value_a) == g_value_get_int (value_b);
+    case XSETTINGS_TYPE_COLOR:
+      return gdk_rgba_equal (g_value_get_boxed (value_a), g_value_get_boxed (value_b));
+    case G_TYPE_STRING:
+      return g_str_equal (g_value_get_string (value_a), g_value_get_string (value_b));
+    default:
+      g_warning ("unable to compare values of type %s", g_type_name (G_VALUE_TYPE (value_a)));
+      return FALSE;
+    }
+}
+
 static void
 notify_changes (XSettingsClient *client,
                GHashTable      *old_list)
 {
   GHashTableIter iter;
-  XSettingsSetting *setting, *old_setting;
+  GValue *setting, *old_setting;
   const char *name;
 
   if (client->settings != NULL)
@@ -98,9 +123,9 @@ notify_changes (XSettingsClient *client,
          old_setting = old_list ? g_hash_table_lookup (old_list, name) : NULL;
 
          if (old_setting == NULL)
-           gdk_xsettings_notify (name, GDK_SETTING_ACTION_NEW, setting, client->screen);
-         else if (!xsettings_setting_equal (setting, old_setting))
-           gdk_xsettings_notify (name, GDK_SETTING_ACTION_CHANGED, setting, client->screen);
+           gdk_xsettings_notify (name, GDK_SETTING_ACTION_NEW, client->screen);
+         else if (!value_equal (setting, old_setting))
+           gdk_xsettings_notify (name, GDK_SETTING_ACTION_CHANGED, client->screen);
            
          /* remove setting from old_list */
          if (old_setting != NULL)
@@ -113,7 +138,7 @@ notify_changes (XSettingsClient *client,
       /* old_list now contains only deleted settings */
       g_hash_table_iter_init (&iter, old_list);
       while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer*) &old_setting))
-       gdk_xsettings_notify (name, GDK_SETTING_ACTION_DELETED, NULL, client->screen);
+       gdk_xsettings_notify (name, GDK_SETTING_ACTION_DELETED, client->screen);
     }
 }
 
@@ -216,6 +241,15 @@ fetch_string (XSettingsBuffer  *buffer,
   return TRUE;
 }
 
+static void
+free_value (gpointer data)
+{
+  GValue *value = data;
+
+  g_value_unset (value);
+  g_free (value);
+}
+
 static GHashTable *
 parse_settings (unsigned char *data,
                size_t         len)
@@ -225,7 +259,7 @@ parse_settings (unsigned char *data,
   CARD32 serial;
   CARD32 n_entries;
   CARD32 i;
-  XSettingsSetting *setting = NULL;
+  GValue *value = NULL;
   char *x_name = NULL;
   const char *gdk_name;
   
@@ -264,9 +298,6 @@ parse_settings (unsigned char *data,
       if (!fetch_card16 (&buffer, &name_len))
        goto out;
 
-      setting = g_new (XSettingsSetting, 1);
-      setting->type = XSETTINGS_TYPE_INT; /* No allocated memory */
-
       if (!fetch_string (&buffer, name_len, &x_name) ||
           /* last change serial (we ignore it) */
           !fetch_card32 (&buffer, &v_int))
@@ -278,26 +309,49 @@ parse_settings (unsigned char *data,
          if (!fetch_card32 (&buffer, &v_int))
            goto out;
 
-         setting->data.v_int = (INT32)v_int;
-          GDK_NOTE(SETTINGS, g_print("  %s = %d\n", x_name, (gint) setting->data.v_int));
+          value = g_new0 (GValue, 1);
+          g_value_init (value, G_TYPE_INT);
+          g_value_set_int (value, (gint32) v_int);
+
+          GDK_NOTE(SETTINGS, g_print("  %s = %d\n", x_name, (gint32) v_int));
          break;
        case XSETTINGS_TYPE_STRING:
-         if (!fetch_card32 (&buffer, &v_int) ||
-              !fetch_string (&buffer, v_int, &setting->data.v_string))
-           goto out;
-         
-          GDK_NOTE(SETTINGS, g_print("  %s = \"%s\"\n", x_name, setting->data.v_string));
+          {
+            char *s;
+
+            if (!fetch_card32 (&buffer, &v_int) ||
+                !fetch_string (&buffer, v_int, &s))
+              goto out;
+            
+            value = g_new0 (GValue, 1);
+            g_value_init (value, G_TYPE_STRING);
+            g_value_take_string (value, s);
+
+            GDK_NOTE(SETTINGS, g_print("  %s = \"%s\"\n", x_name, s));
+          }
          break;
        case XSETTINGS_TYPE_COLOR:
-         if (!fetch_ushort (&buffer, &setting->data.v_color.red) ||
-             !fetch_ushort (&buffer, &setting->data.v_color.green) ||
-             !fetch_ushort (&buffer, &setting->data.v_color.blue) ||
-             !fetch_ushort (&buffer, &setting->data.v_color.alpha))
-           goto out;
+          {
+            unsigned short red, green, blue, alpha;
+            GdkRGBA rgba;
+
+            if (!fetch_ushort (&buffer, &red) ||
+                !fetch_ushort (&buffer, &green) ||
+                !fetch_ushort (&buffer, &blue) ||
+                !fetch_ushort (&buffer, &alpha))
+              goto out;
+
+            rgba.red = red / 65535.0;
+            rgba.green = green / 65535.0;
+            rgba.blue = blue / 65535.0;
+            rgba.alpha = alpha / 65535.0;
+
+            value = g_new0 (GValue, 1);
+            g_value_init (value, G_TYPE_STRING);
+            g_value_set_boxed (value, &rgba);
 
-          GDK_NOTE(SETTINGS, g_print("  %s = #%02X%02X%02X%02X\n", x_name, 
-                                 setting->data.v_color.alpha, setting->data.v_color.red,
-                                 setting->data.v_color.green, setting->data.v_color.blue));
+            GDK_NOTE(SETTINGS, g_print("  %s = #%02X%02X%02X%02X\n", x_name, alpha,red, green, blue));
+          }
          break;
        default:
          /* Quietly ignore unknown types */
@@ -305,8 +359,6 @@ parse_settings (unsigned char *data,
          break;
        }
 
-      setting->type = type;
-
       gdk_name = gdk_from_xsettings_name (x_name);
       g_free (x_name);
       x_name = NULL;
@@ -322,7 +374,7 @@ parse_settings (unsigned char *data,
           if (settings == NULL)
             settings = g_hash_table_new_full (g_str_hash, g_str_equal,
                                               NULL,
-                                              (GDestroyNotify) xsettings_setting_free);
+                                              free_value);
 
           if (g_hash_table_lookup (settings, gdk_name) != NULL)
             {
@@ -330,18 +382,18 @@ parse_settings (unsigned char *data,
               goto out;
             }
 
-          g_hash_table_insert (settings, (gpointer) gdk_name, setting);
+          g_hash_table_insert (settings, (gpointer) gdk_name, value);
         }
 
-      setting = NULL;
+      value = NULL;
     }
 
   return settings;
 
  out:
 
-  if (setting)
-    xsettings_setting_free (setting);
+  if (value)
+    free_value (value);
 
   if (settings)
     g_hash_table_unref (settings);
@@ -352,7 +404,8 @@ parse_settings (unsigned char *data,
 }
 
 static void
-read_settings (XSettingsClient *client)
+read_settings (XSettingsClient *client,
+               gboolean         do_notify)
 {
   Atom type;
   int format;
@@ -371,7 +424,8 @@ read_settings (XSettingsClient *client)
       Atom xsettings_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XSETTINGS_SETTINGS");
 
       gdk_x11_display_error_trap_push (display);
-      result = XGetWindowProperty (client->display, client->manager_window,
+      result = XGetWindowProperty (gdk_x11_display_get_xdisplay (display),
+                                   gdk_x11_window_get_xid (client->manager_window),
                                   xsettings_atom, 0, LONG_MAX,
                                   False, xsettings_atom,
                                   &type, &format, &n_items, &bytes_after, &data);
@@ -394,57 +448,67 @@ read_settings (XSettingsClient *client)
        }
     }
 
-  notify_changes (client, old_list);
+  if (do_notify)
+    notify_changes (client, old_list);
   if (old_list)
     g_hash_table_unref (old_list);
 }
 
-static Bool
-gdk_xsettings_watch (Window     window,
-                    Bool       is_start,
-                    GdkScreen *screen);
+static GdkFilterReturn
+gdk_xsettings_manager_window_filter (GdkXEvent *xevent,
+                                     GdkEvent  *event,
+                                     gpointer   data);
 
 static void
-check_manager_window (XSettingsClient *client)
+check_manager_window (XSettingsClient *client,
+                      gboolean         notify_changes)
 {
+  GdkDisplay *display;
+  Display *xdisplay;
+  Window manager_window_xid;
+
+  display = gdk_screen_get_display (client->screen);
+  xdisplay = gdk_x11_display_get_xdisplay (display);
+
   if (client->manager_window)
-    gdk_xsettings_watch (client->manager_window, False, client->screen);
+    {
+      gdk_window_remove_filter (client->manager_window, gdk_xsettings_manager_window_filter, client->screen);
+      g_object_unref (client->manager_window);
+    }
 
-  gdk_x11_display_grab (gdk_screen_get_display (client->screen));
+  gdk_x11_display_grab (display);
 
-  client->manager_window = XGetSelectionOwner (client->display,
-                                              client->selection_atom);
+  manager_window_xid = XGetSelectionOwner (xdisplay,
+                                          client->selection_atom);
+  client->manager_window = gdk_x11_window_foreign_new_for_display (display,
+                                                                   manager_window_xid);
+  /* XXX: Can't use gdk_window_set_events() here because the first call to this
+   * function happens too early in gdk_init() */
   if (client->manager_window)
-    XSelectInput (client->display, client->manager_window,
-                 PropertyChangeMask | StructureNotifyMask);
+    XSelectInput (xdisplay,
+                  gdk_x11_window_get_xid (client->manager_window),
+                  PropertyChangeMask | StructureNotifyMask);
 
-  gdk_x11_display_ungrab (gdk_screen_get_display (client->screen));
+  gdk_x11_display_ungrab (display);
   
-  XFlush (client->display);
+  gdk_display_flush (display);
 
   if (client->manager_window)
     {
-      if (!gdk_xsettings_watch (client->manager_window, True,  client->screen))
-       {
-         /* Inability to watch the window probably means that it was destroyed
-          * after we ungrabbed
-          */
-         client->manager_window = None;
-         return;
-       }
+      gdk_window_add_filter (client->manager_window, gdk_xsettings_manager_window_filter, client->screen);
     }
       
-  read_settings (client);
+  read_settings (client, notify_changes);
 }
 
 static GdkFilterReturn
-gdk_xsettings_client_event_filter (GdkXEvent *xevent,
-                                  GdkEvent  *event,
-                                  gpointer   data)
+gdk_xsettings_root_window_filter (GdkXEvent *xevent,
+                                  GdkEvent  *event,
+                                  gpointer   data)
 {
   GdkScreen *screen = data;
-  GdkDisplay *display = gdk_screen_get_display (screen);
   XSettingsClient *client = GDK_X11_SCREEN (screen)->xsettings_client;
+  GdkDisplay *display = gdk_screen_get_display (screen);
   XEvent *xev = xevent;
 
   /* The checks here will not unlikely cause us to reread
@@ -452,82 +516,43 @@ gdk_xsettings_client_event_filter (GdkXEvent *xevent,
    * times when the manager changes from A->B. But manager changes
    * are going to be pretty rare.
    */
-  if (xev->xany.window == gdk_x11_window_get_xid (gdk_screen_get_root_window (screen)))
+  if (xev->xany.type == ClientMessage &&
+      xev->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "MANAGER") &&
+      xev->xclient.data.l[1] == client->selection_atom)
     {
-      if (xev->xany.type == ClientMessage &&
-         xev->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "MANAGER") &&
-         xev->xclient.data.l[1] == client->selection_atom)
-       {
-         check_manager_window (client);
-         return GDK_FILTER_REMOVE;
-       }
-    }
-  else if (xev->xany.window == client->manager_window)
-    {
-      if (xev->xany.type == DestroyNotify)
-       {
-         check_manager_window (client);
-          /* let GDK do its cleanup */
-         return GDK_FILTER_CONTINUE; 
-       }
-      else if (xev->xany.type == PropertyNotify)
-       {
-         read_settings (client);
-         return GDK_FILTER_REMOVE;
-       }
+      check_manager_window (client, TRUE);
+      return GDK_FILTER_REMOVE;
     }
   
-  return GDK_FILTER_CONTINUE;;
+  return GDK_FILTER_CONTINUE;
 }
 
-static Bool
-gdk_xsettings_watch (Window     window,
-                    Bool       is_start,
-                    GdkScreen *screen)
+static GdkFilterReturn
+gdk_xsettings_manager_window_filter (GdkXEvent *xevent,
+                                     GdkEvent  *event,
+                                     gpointer   data)
 {
-  GdkWindow *gdkwin;
-
-  gdkwin = gdk_x11_window_lookup_for_display (gdk_screen_get_display (screen), window);
+  GdkScreen *screen = data;
+  XSettingsClient *client = GDK_X11_SCREEN (screen)->xsettings_client;
+  XEvent *xev = xevent;
 
-  if (is_start)
+  if (xev->xany.type == DestroyNotify)
     {
-      if (gdkwin)
-       g_object_ref (gdkwin);
-      else
-       {
-         gdkwin = gdk_x11_window_foreign_new_for_display (gdk_screen_get_display (screen), window);
-         
-         /* gdk_window_foreign_new_for_display() can fail and return NULL if the
-          * window has already been destroyed.
-          */
-         if (!gdkwin)
-           return False;
-       }
-
-      gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
+      check_manager_window (client, TRUE);
+      /* let GDK do its cleanup */
+      return GDK_FILTER_CONTINUE; 
     }
-  else
+  else if (xev->xany.type == PropertyNotify)
     {
-      if (!gdkwin)
-       {
-         /* gdkwin should not be NULL here, since if starting the watch succeeded
-          * we have a reference on the window. It might mean that the caller didn't
-          * remove the watch when it got a DestroyNotify event. Or maybe the
-          * caller ignored the return value when starting the watch failed.
-          */
-         g_warning ("gdk_xsettings_watch_cb(): Couldn't find window to unwatch");
-         return False;
-       }
-      
-      gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
-      g_object_unref (gdkwin);
+      read_settings (client, TRUE);
+      return GDK_FILTER_REMOVE;
     }
-
-  return True;
+  
+  return GDK_FILTER_CONTINUE;;
 }
 
 XSettingsClient *
-xsettings_client_new (GdkScreen *screen)
+_gdk_x11_xsettings_client_new (GdkScreen *screen)
 {
   XSettingsClient *client;
   char *selection_atom_name;
@@ -536,8 +561,6 @@ xsettings_client_new (GdkScreen *screen)
   if (!client)
     return NULL;
 
-  client->screen = screen;
-  client->display = gdk_x11_display_get_xdisplay (gdk_screen_get_display (screen));
   client->screen = screen;
   client->manager_window = None;
   client->settings = NULL;
@@ -546,61 +569,32 @@ xsettings_client_new (GdkScreen *screen)
   client->selection_atom = gdk_x11_get_xatom_by_name_for_display (gdk_screen_get_display (screen), selection_atom_name);
   g_free (selection_atom_name);
 
-  gdk_xsettings_watch (gdk_x11_window_get_xid (gdk_screen_get_root_window (screen)), True, client->screen);
+  gdk_window_add_filter (gdk_screen_get_root_window (screen), gdk_xsettings_root_window_filter, screen);
 
-  check_manager_window (client);
+  check_manager_window (client, FALSE);
 
   return client;
 }
 
 void
-xsettings_client_destroy (XSettingsClient *client)
+_gdk_x11_xsettings_client_destroy (XSettingsClient *client)
 {
-  gdk_xsettings_watch (gdk_x11_window_get_xid (gdk_screen_get_root_window (client->screen)), False, client->screen);
+  gdk_window_remove_filter (gdk_screen_get_root_window (client->screen), gdk_xsettings_root_window_filter, client->screen);
   if (client->manager_window)
-    gdk_xsettings_watch (client->manager_window, False, client->screen);
+    {
+      gdk_window_remove_filter (client->manager_window, gdk_xsettings_manager_window_filter, client->screen);
+      g_object_unref (client->manager_window);
+    }
   
   if (client->settings)
     g_hash_table_unref (client->settings);
   g_free (client);
 }
 
-const XSettingsSetting *
-xsettings_client_get_setting (XSettingsClient   *client,
-                             const char        *name)
+const GValue *
+_gdk_x11_xsettings_client_get_setting (XSettingsClient   *client,
+                                      const char        *name)
 {
   return g_hash_table_lookup (client->settings, name);
 }
 
-int
-xsettings_setting_equal (XSettingsSetting *setting_a,
-                        XSettingsSetting *setting_b)
-{
-  if (setting_a->type != setting_b->type)
-    return 0;
-
-  switch (setting_a->type)
-    {
-    case XSETTINGS_TYPE_INT:
-      return setting_a->data.v_int == setting_b->data.v_int;
-    case XSETTINGS_TYPE_COLOR:
-      return (setting_a->data.v_color.red == setting_b->data.v_color.red &&
-             setting_a->data.v_color.green == setting_b->data.v_color.green &&
-             setting_a->data.v_color.blue == setting_b->data.v_color.blue &&
-             setting_a->data.v_color.alpha == setting_b->data.v_color.alpha);
-    case XSETTINGS_TYPE_STRING:
-      return strcmp (setting_a->data.v_string, setting_b->data.v_string) == 0;
-    }
-
-  return 0;
-}
-
-void
-xsettings_setting_free (XSettingsSetting *setting)
-{
-  if (setting->type == XSETTINGS_TYPE_STRING)
-    g_free (setting->data.v_string);
-
-  g_free (setting);
-}
-