#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
struct _XSettingsClient
{
GdkScreen *screen;
- Display *display;
- Window manager_window;
+ GdkWindow *manager_window;
Atom selection_atom;
GHashTable *settings; /* string of GDK settings name => XSettingsSetting */
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;
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)
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)
/* 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);
}
}
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)
CARD32 serial;
CARD32 n_entries;
CARD32 i;
- XSettingsSetting *setting = NULL;
+ GValue *value = NULL;
char *x_name = NULL;
const char *gdk_name;
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))
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;
- 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));
+ 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, alpha,red, green, blue));
+ }
break;
default:
/* Quietly ignore unknown types */
break;
}
- setting->type = type;
-
gdk_name = gdk_from_xsettings_name (x_name);
g_free (x_name);
x_name = NULL;
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)
{
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);
}
static void
-read_settings (XSettingsClient *client)
+read_settings (XSettingsClient *client,
+ gboolean do_notify)
{
Atom type;
int format;
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);
}
}
- 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 (GdkScreen *screen,
- Window window);
-static Bool
-gdk_xsettings_unwatch (GdkScreen *screen,
- Window window);
+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_unwatch (client->screen, client->manager_window);
+ {
+ gdk_window_remove_filter (client->manager_window, gdk_xsettings_manager_window_filter, client->screen);
+ g_object_unref (client->manager_window);
+ }
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 (display);
if (client->manager_window)
{
- if (!gdk_xsettings_watch (client->screen, client->manager_window))
- {
- /* 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
* 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)
- {
- check_manager_window (client);
- return GDK_FILTER_REMOVE;
- }
- }
- else if (xev->xany.window == client->manager_window)
+ 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 == 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 (GdkScreen *screen,
- Window window)
+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 (gdkwin)
- g_object_ref (gdkwin);
- else
+ if (xev->xany.type == DestroyNotify)
{
- 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;
+ check_manager_window (client, TRUE);
+ /* let GDK do its cleanup */
+ return GDK_FILTER_CONTINUE;
}
-
- gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
-
- return True;
-}
-
-static Bool
-gdk_xsettings_unwatch (GdkScreen *screen,
- Window window)
-{
- GdkWindow *gdkwin;
-
- gdkwin = gdk_x11_window_lookup_for_display (gdk_screen_get_display (screen), window);
-
- if (!gdkwin)
+ else if (xev->xany.type == PropertyNotify)
{
- /* 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_unwatch(): Couldn't find window to unwatch");
- return False;
+ read_settings (client, TRUE);
+ return GDK_FILTER_REMOVE;
}
- gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
- g_object_unref (gdkwin);
-
- 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;
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;
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 (screen, gdk_x11_window_get_xid (gdk_screen_get_root_window (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_unwatch (client->screen, gdk_x11_window_get_xid (gdk_screen_get_root_window (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_unwatch (client->screen, client->manager_window);
+ {
+ 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);
-}
-