From 98c3c84c004c65ca97f1b9118554bc8e694e0e5f Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 21 Jun 2010 15:43:31 +0100 Subject: [PATCH] x11: Add the XSETTINGS machinery Use the XSETTINGS machinery to get notification from foreign environments about settings that might interest Clutter itself - namely: the default font name, the font DPI, and the Xft font options that can be mapped on cairo_font_options_t. --- clutter/x11/Makefile.am | 6 + clutter/x11/clutter-backend-x11.c | 87 +++- clutter/x11/clutter-backend-x11.h | 4 + clutter/x11/clutter-settings-x11.h | 24 + clutter/x11/xsettings/xsettings-client.c | 609 +++++++++++++++++++++++ clutter/x11/xsettings/xsettings-client.h | 79 +++ clutter/x11/xsettings/xsettings-common.c | 265 ++++++++++ clutter/x11/xsettings/xsettings-common.h | 132 +++++ 8 files changed, 1199 insertions(+), 7 deletions(-) create mode 100644 clutter/x11/clutter-settings-x11.h create mode 100644 clutter/x11/xsettings/xsettings-client.c create mode 100644 clutter/x11/xsettings/xsettings-client.h create mode 100644 clutter/x11/xsettings/xsettings-common.c create mode 100644 clutter/x11/xsettings/xsettings-common.h diff --git a/clutter/x11/Makefile.am b/clutter/x11/Makefile.am index 12a0c64bd..e626ca663 100644 --- a/clutter/x11/Makefile.am +++ b/clutter/x11/Makefile.am @@ -8,6 +8,7 @@ INCLUDES = \ -I$(top_srcdir) \ -I$(top_srcdir)/clutter \ -I$(top_srcdir)/clutter/cogl \ + -I$(srcdir)/xsettings \ -I$(top_builddir)/clutter \ -I$(top_builddir)/clutter/cogl \ $(CLUTTER_CFLAGS) \ @@ -44,9 +45,14 @@ libclutter_x11_la_SOURCES = \ $(srcdir)/clutter-event-x11.c \ $(srcdir)/clutter-input-device-x11.h \ $(srcdir)/clutter-input-device-x11.c \ + $(srcdir)/clutter-settings-x11.h \ $(srcdir)/clutter-stage-x11.h \ $(srcdir)/clutter-stage-x11.c \ $(srcdir)/clutter-x11-texture-pixmap.c \ + $(srcdir)/xsettings/xsettings-client.c \ + $(srcdir)/xsettings/xsettings-client.h \ + $(srcdir)/xsettings/xsettings-common.c \ + $(srcdir)/xsettings/xsettings-common.h \ clutter-x11-enum-types.h \ clutter-x11-enum-types.c \ $(NULL) diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c index 24c72a106..8be21b795 100644 --- a/clutter/x11/clutter-backend-x11.c +++ b/clutter/x11/clutter-backend-x11.c @@ -40,9 +40,12 @@ #include "clutter-backend-x11.h" #include "clutter-device-manager-x11.h" #include "clutter-input-device-x11.h" +#include "clutter-settings-x11.h" #include "clutter-stage-x11.h" #include "clutter-x11.h" +#include "xsettings/xsettings-common.h" + #include #ifdef HAVE_XINPUT @@ -97,6 +100,71 @@ static gboolean clutter_synchronise = FALSE; static int TrappedErrorCode = 0; static int (* old_error_handler) (Display *, XErrorEvent *); +static void +clutter_backend_x11_xsettings_notify (const char *name, + XSettingsAction action, + XSettingsSetting *setting, + void *cb_data) +{ + ClutterSettings *settings = clutter_settings_get_default (); + gint i; + + if (name == NULL || *name == '\0') + return; + + for (i = 0; i < _n_clutter_settings_map; i++) + { + if (g_strcmp0 (name, CLUTTER_SETTING_X11_NAME (i)) == 0) + { + GValue value = { 0, }; + + switch (setting->type) + { + case XSETTINGS_TYPE_INT: + g_value_init (&value, G_TYPE_INT); + g_value_set_int (&value, setting->data.v_int); + break; + + case XSETTINGS_TYPE_STRING: + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, setting->data.v_string); + break; + + case XSETTINGS_TYPE_COLOR: + { + ClutterColor color; + + color.red = (guint8) ((float) setting->data.v_color.red + / 65535.0 * 255); + color.green = (guint8) ((float) setting->data.v_color.green + / 65535.0 * 255); + color.blue = (guint8) ((float) setting->data.v_color.blue + / 65535.0 * 255); + color.alpha = (guint8) ((float) setting->data.v_color.alpha + / 65535.0 * 255); + + g_value_init (&value, G_TYPE_BOXED); + clutter_value_set_color (&value, &color); + } + break; + } + + CLUTTER_NOTE (BACKEND, + "Mapping XSETTING '%s' to 'ClutterSettings:%s'", + CLUTTER_SETTING_X11_NAME (i), + CLUTTER_SETTING_PROPERTY (i)); + + g_object_set_property (G_OBJECT (settings), + CLUTTER_SETTING_PROPERTY (i), + &value); + + g_value_unset (&value); + + break; + } + } +} + gboolean clutter_backend_x11_pre_parse (ClutterBackend *backend, GError **error) @@ -194,6 +262,14 @@ clutter_backend_x11_post_parse (ClutterBackend *backend, "backend", backend_x11, NULL); + /* create XSETTINGS client */ + backend_x11->xsettings = + _clutter_xsettings_client_new (backend_x11->xdpy, + backend_x11->xscreen_num, + clutter_backend_x11_xsettings_notify, + NULL, + backend_x11); + if (clutter_synchronise) XSynchronize (backend_x11->xdpy, True); @@ -281,6 +357,8 @@ clutter_backend_x11_finalize (GObject *gobject) g_free (backend_x11->display_name); + xsettings_client_destroy (backend_x11->xsettings); + XCloseDisplay (backend_x11->xdpy); if (backend_singleton) @@ -344,6 +422,8 @@ gboolean clutter_backend_x11_handle_event (ClutterBackendX11 *backend_x11, XEvent *xevent) { + xsettings_client_process_event (backend_x11->xsettings, xevent); + return FALSE; } @@ -388,13 +468,6 @@ clutter_backend_x11_class_init (ClutterBackendX11Class *klass) static void clutter_backend_x11_init (ClutterBackendX11 *backend_x11) { - ClutterBackend *backend = CLUTTER_BACKEND (backend_x11); - - /* FIXME: get from xsettings */ - clutter_backend_set_double_click_time (backend, 250); - clutter_backend_set_double_click_distance (backend, 5); - clutter_backend_set_resolution (backend, 96.0); - backend_x11->last_event_time = CurrentTime; } diff --git a/clutter/x11/clutter-backend-x11.h b/clutter/x11/clutter-backend-x11.h index 6dc111f6d..31325218c 100644 --- a/clutter/x11/clutter-backend-x11.h +++ b/clutter/x11/clutter-backend-x11.h @@ -30,6 +30,8 @@ #include "clutter-x11.h" +#include "xsettings/xsettings-client.h" + G_BEGIN_DECLS #define CLUTTER_TYPE_BACKEND_X11 (clutter_backend_x11_get_type ()) @@ -83,6 +85,8 @@ struct _ClutterBackendX11 Time last_event_time; ClutterDeviceManager *device_manager; + + XSettingsClient *xsettings; }; struct _ClutterBackendX11Class diff --git a/clutter/x11/clutter-settings-x11.h b/clutter/x11/clutter-settings-x11.h new file mode 100644 index 000000000..6214ed705 --- /dev/null +++ b/clutter/x11/clutter-settings-x11.h @@ -0,0 +1,24 @@ +#ifndef __CLUTTER_SETTINGS_X11_H__ +#define __CLUTTER_SETTINGS_X11_H__ + +/* XSETTINGS key names to ClutterSettings properties */ +static const struct { + const char *xsetting_name; + const char *settings_property; +} _clutter_settings_map[] = { + { "Net/DoubleClickTime", "double-click-time" }, + { "Net/DoubleClickDistance", "double-click-distance" }, + { "Gtk/FontName", "font-name" }, + { "Xft/Antialias", "font-antialias" }, + { "Xft/DPI", "font-dpi" }, + { "Xft/Hinting", "font-hinting" }, + { "Xft/HintStyle", "font-hint-style" }, + { "Xft/RGBA", "font-subpixel-order" } +}; + +static const gint _n_clutter_settings_map = G_N_ELEMENTS (_clutter_settings_map); + +#define CLUTTER_SETTING_X11_NAME(id) (_clutter_settings_map[(id)].xsetting_name) +#define CLUTTER_SETTING_PROPERTY(id) (_clutter_settings_map[(id)].settings_property) + +#endif /* __CLUTTER_SETTINGS_X11_H__ */ diff --git a/clutter/x11/xsettings/xsettings-client.c b/clutter/x11/xsettings/xsettings-client.c new file mode 100644 index 000000000..753e46105 --- /dev/null +++ b/clutter/x11/xsettings/xsettings-client.c @@ -0,0 +1,609 @@ +/* + * Copyright © 2001, 2007 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Red Hat not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Red Hat makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Owen Taylor, Red Hat, Inc. + */ +#include "config.h" +#include +#include +#include +#include + +#include +#include /* For CARD16 */ + +#include "xsettings-client.h" + +struct _XSettingsClient +{ + Display *display; + int screen; + XSettingsNotifyFunc notify; + XSettingsWatchFunc watch; + void *cb_data; + + XSettingsGrabFunc grab; + XSettingsGrabFunc ungrab; + + Window manager_window; + Atom manager_atom; + Atom selection_atom; + Atom xsettings_atom; + + XSettingsList *settings; +}; + +static void +notify_changes (XSettingsClient *client, + XSettingsList *old_list) +{ + XSettingsList *old_iter = old_list; + XSettingsList *new_iter = client->settings; + + if (!client->notify) + return; + + while (old_iter || new_iter) + { + int cmp; + + if (old_iter && new_iter) + cmp = strcmp (old_iter->setting->name, new_iter->setting->name); + else if (old_iter) + cmp = -1; + else + cmp = 1; + + if (cmp < 0) + { + client->notify (old_iter->setting->name, + XSETTINGS_ACTION_DELETED, + NULL, + client->cb_data); + } + else if (cmp == 0) + { + if (!xsettings_setting_equal (old_iter->setting, + new_iter->setting)) + client->notify (old_iter->setting->name, + XSETTINGS_ACTION_CHANGED, + new_iter->setting, + client->cb_data); + } + else + { + client->notify (new_iter->setting->name, + XSETTINGS_ACTION_NEW, + new_iter->setting, + client->cb_data); + } + + if (old_iter) + old_iter = old_iter->next; + if (new_iter) + new_iter = new_iter->next; + } +} + +static int +ignore_errors (Display *display, XErrorEvent *event) +{ + return True; +} + +static char local_byte_order = '\0'; + +#define BYTES_LEFT(buffer) ((buffer)->data + (buffer)->len - (buffer)->pos) + +static XSettingsResult +fetch_card16 (XSettingsBuffer *buffer, + CARD16 *result) +{ + CARD16 x; + + if (BYTES_LEFT (buffer) < 2) + return XSETTINGS_ACCESS; + + x = *(CARD16 *)buffer->pos; + buffer->pos += 2; + + if (buffer->byte_order == local_byte_order) + *result = x; + else + *result = (x << 8) | (x >> 8); + + return XSETTINGS_SUCCESS; +} + +static XSettingsResult +fetch_ushort (XSettingsBuffer *buffer, + unsigned short *result) +{ + CARD16 x; + XSettingsResult r; + + r = fetch_card16 (buffer, &x); + if (r == XSETTINGS_SUCCESS) + *result = x; + + return r; +} + +static XSettingsResult +fetch_card32 (XSettingsBuffer *buffer, + CARD32 *result) +{ + CARD32 x; + + if (BYTES_LEFT (buffer) < 4) + return XSETTINGS_ACCESS; + + x = *(CARD32 *)buffer->pos; + buffer->pos += 4; + + if (buffer->byte_order == local_byte_order) + *result = x; + else + *result = (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24); + + return XSETTINGS_SUCCESS; +} + +static XSettingsResult +fetch_card8 (XSettingsBuffer *buffer, + CARD8 *result) +{ + if (BYTES_LEFT (buffer) < 1) + return XSETTINGS_ACCESS; + + *result = *(CARD8 *)buffer->pos; + buffer->pos += 1; + + return XSETTINGS_SUCCESS; +} + +#define XSETTINGS_PAD(n,m) ((n + m - 1) & (~(m-1))) + +static XSettingsList * +parse_settings (unsigned char *data, + size_t len) +{ + XSettingsBuffer buffer; + XSettingsResult result = XSETTINGS_SUCCESS; + XSettingsList *settings = NULL; + CARD32 serial; + CARD32 n_entries; + CARD32 i; + XSettingsSetting *setting = NULL; + + local_byte_order = xsettings_byte_order (); + + buffer.pos = buffer.data = data; + buffer.len = len; + + result = fetch_card8 (&buffer, (unsigned char *)&buffer.byte_order); + if (buffer.byte_order != MSBFirst && + buffer.byte_order != LSBFirst) + { + fprintf (stderr, "Invalid byte order in XSETTINGS property\n"); + result = XSETTINGS_FAILED; + goto out; + } + + buffer.pos += 3; + + result = fetch_card32 (&buffer, &serial); + if (result != XSETTINGS_SUCCESS) + goto out; + + result = fetch_card32 (&buffer, &n_entries); + if (result != XSETTINGS_SUCCESS) + goto out; + + for (i = 0; i < n_entries; i++) + { + CARD8 type; + CARD16 name_len; + CARD32 v_int; + size_t pad_len; + + result = fetch_card8 (&buffer, &type); + if (result != XSETTINGS_SUCCESS) + goto out; + + buffer.pos += 1; + + result = fetch_card16 (&buffer, &name_len); + if (result != XSETTINGS_SUCCESS) + goto out; + + pad_len = XSETTINGS_PAD(name_len, 4); + if (BYTES_LEFT (&buffer) < pad_len) + { + result = XSETTINGS_ACCESS; + goto out; + } + + setting = malloc (sizeof *setting); + if (!setting) + { + result = XSETTINGS_NO_MEM; + goto out; + } + setting->type = XSETTINGS_TYPE_INT; /* No allocated memory */ + + setting->name = malloc (name_len + 1); + if (!setting->name) + { + result = XSETTINGS_NO_MEM; + goto out; + } + + memcpy (setting->name, buffer.pos, name_len); + setting->name[name_len] = '\0'; + buffer.pos += pad_len; + + result = fetch_card32 (&buffer, &v_int); + if (result != XSETTINGS_SUCCESS) + goto out; + setting->last_change_serial = v_int; + + switch (type) + { + case XSETTINGS_TYPE_INT: + result = fetch_card32 (&buffer, &v_int); + if (result != XSETTINGS_SUCCESS) + goto out; + + setting->data.v_int = (INT32)v_int; + break; + case XSETTINGS_TYPE_STRING: + result = fetch_card32 (&buffer, &v_int); + if (result != XSETTINGS_SUCCESS) + goto out; + + pad_len = XSETTINGS_PAD (v_int, 4); + if (v_int + 1 == 0 || /* Guard against wrap-around */ + BYTES_LEFT (&buffer) < pad_len) + { + result = XSETTINGS_ACCESS; + goto out; + } + + setting->data.v_string = malloc (v_int + 1); + if (!setting->data.v_string) + { + result = XSETTINGS_NO_MEM; + goto out; + } + + memcpy (setting->data.v_string, buffer.pos, v_int); + setting->data.v_string[v_int] = '\0'; + buffer.pos += pad_len; + + break; + case XSETTINGS_TYPE_COLOR: + result = fetch_ushort (&buffer, &setting->data.v_color.red); + if (result != XSETTINGS_SUCCESS) + goto out; + result = fetch_ushort (&buffer, &setting->data.v_color.green); + if (result != XSETTINGS_SUCCESS) + goto out; + result = fetch_ushort (&buffer, &setting->data.v_color.blue); + if (result != XSETTINGS_SUCCESS) + goto out; + result = fetch_ushort (&buffer, &setting->data.v_color.alpha); + if (result != XSETTINGS_SUCCESS) + goto out; + + break; + default: + /* Quietly ignore unknown types */ + break; + } + + setting->type = type; + + result = xsettings_list_insert (&settings, setting); + if (result != XSETTINGS_SUCCESS) + goto out; + + setting = NULL; + } + + out: + + if (result != XSETTINGS_SUCCESS) + { + switch (result) + { + case XSETTINGS_NO_MEM: + fprintf(stderr, "Out of memory reading XSETTINGS property\n"); + break; + case XSETTINGS_ACCESS: + fprintf(stderr, "Invalid XSETTINGS property (read off end)\n"); + break; + case XSETTINGS_DUPLICATE_ENTRY: + fprintf (stderr, "Duplicate XSETTINGS entry for '%s'\n", setting->name); + case XSETTINGS_FAILED: + case XSETTINGS_SUCCESS: + case XSETTINGS_NO_ENTRY: + break; + } + + if (setting) + xsettings_setting_free (setting); + + xsettings_list_free (settings); + settings = NULL; + + } + + return settings; +} + +static void +read_settings (XSettingsClient *client) +{ + Atom type; + int format; + unsigned long n_items; + unsigned long bytes_after; + unsigned char *data; + int result; + + int (*old_handler) (Display *, XErrorEvent *); + + XSettingsList *old_list = client->settings; + + client->settings = NULL; + + if (client->manager_window) + { + old_handler = XSetErrorHandler (ignore_errors); + result = XGetWindowProperty (client->display, client->manager_window, + client->xsettings_atom, 0, LONG_MAX, + False, client->xsettings_atom, + &type, &format, &n_items, &bytes_after, &data); + XSetErrorHandler (old_handler); + + if (result == Success && type != None) + { + if (type != client->xsettings_atom) + { + fprintf (stderr, "Invalid type for XSETTINGS property"); + } + else if (format != 8) + { + fprintf (stderr, "Invalid format for XSETTINGS property %d", format); + } + else + client->settings = parse_settings (data, n_items); + + XFree (data); + } + } + + notify_changes (client, old_list); + xsettings_list_free (old_list); +} + +static void +add_events (Display *display, + Window window, + long mask) +{ + XWindowAttributes attr; + + XGetWindowAttributes (display, window, &attr); + XSelectInput (display, window, attr.your_event_mask | mask); +} + +static void +check_manager_window (XSettingsClient *client) +{ + if (client->manager_window && client->watch) + client->watch (client->manager_window, False, 0, client->cb_data); + + if (client->grab) + client->grab (client->display); + else + XGrabServer (client->display); + + client->manager_window = XGetSelectionOwner (client->display, + client->selection_atom); + if (client->manager_window) + XSelectInput (client->display, client->manager_window, + PropertyChangeMask | StructureNotifyMask); + + if (client->ungrab) + client->ungrab (client->display); + else + XUngrabServer (client->display); + + XFlush (client->display); + + if (client->manager_window && client->watch) + { + if (!client->watch (client->manager_window, True, + PropertyChangeMask | StructureNotifyMask, + client->cb_data)) + { + /* Inability to watch the window probably means that it was destroyed + * after we ungrabbed + */ + client->manager_window = None; + return; + } + } + + + read_settings (client); +} + +XSettingsClient * +xsettings_client_new (Display *display, + int screen, + XSettingsNotifyFunc notify, + XSettingsWatchFunc watch, + void *cb_data) +{ + return xsettings_client_new_with_grab_funcs (display, screen, notify, watch, cb_data, + NULL, NULL); +} + +XSettingsClient * +xsettings_client_new_with_grab_funcs (Display *display, + int screen, + XSettingsNotifyFunc notify, + XSettingsWatchFunc watch, + void *cb_data, + XSettingsGrabFunc grab, + XSettingsGrabFunc ungrab) +{ + XSettingsClient *client; + char buffer[256]; + char *atom_names[3]; + Atom atoms[3]; + + client = malloc (sizeof *client); + if (!client) + return NULL; + + client->display = display; + client->screen = screen; + client->notify = notify; + client->watch = watch; + client->cb_data = cb_data; + client->grab = grab; + client->ungrab = ungrab; + + client->manager_window = None; + client->settings = NULL; + + sprintf(buffer, "_XSETTINGS_S%d", screen); + atom_names[0] = buffer; + atom_names[1] = "_XSETTINGS_SETTINGS"; + atom_names[2] = "MANAGER"; + +#ifdef HAVE_XINTERNATOMS + XInternAtoms (display, atom_names, 3, False, atoms); +#else + atoms[0] = XInternAtom (display, atom_names[0], False); + atoms[1] = XInternAtom (display, atom_names[1], False); + atoms[2] = XInternAtom (display, atom_names[2], False); +#endif + + client->selection_atom = atoms[0]; + client->xsettings_atom = atoms[1]; + client->manager_atom = atoms[2]; + + /* Select on StructureNotify so we get MANAGER events + */ + add_events (display, RootWindow (display, screen), StructureNotifyMask); + + if (client->watch) + client->watch (RootWindow (display, screen), True, StructureNotifyMask, + client->cb_data); + + check_manager_window (client); + + return client; +} + + +void +xsettings_client_set_grab_func (XSettingsClient *client, + XSettingsGrabFunc grab) +{ + client->grab = grab; +} + +void +xsettings_client_set_ungrab_func (XSettingsClient *client, + XSettingsGrabFunc ungrab) +{ + client->ungrab = ungrab; +} + +void +xsettings_client_destroy (XSettingsClient *client) +{ + if (client->watch) + client->watch (RootWindow (client->display, client->screen), + False, 0, client->cb_data); + if (client->manager_window && client->watch) + client->watch (client->manager_window, False, 0, client->cb_data); + + xsettings_list_free (client->settings); + free (client); +} + +XSettingsResult +xsettings_client_get_setting (XSettingsClient *client, + const char *name, + XSettingsSetting **setting) +{ + XSettingsSetting *search = xsettings_list_lookup (client->settings, name); + if (search) + { + *setting = xsettings_setting_copy (search); + return *setting ? XSETTINGS_SUCCESS : XSETTINGS_NO_MEM; + } + else + return XSETTINGS_NO_ENTRY; +} + +Bool +xsettings_client_process_event (XSettingsClient *client, + XEvent *xev) +{ + /* The checks here will not unlikely cause us to reread + * the properties from the manager window a number of + * times when the manager changes from A->B. But manager changes + * are going to be pretty rare. + */ + if (xev->xany.window == RootWindow (client->display, client->screen)) + { + if (xev->xany.type == ClientMessage && + xev->xclient.message_type == client->manager_atom && + xev->xclient.data.l[1] == client->selection_atom) + { + check_manager_window (client); + return True; + } + } + else if (xev->xany.window == client->manager_window) + { + if (xev->xany.type == DestroyNotify) + { + check_manager_window (client); + /* let GDK do its cleanup */ + return False; + } + else if (xev->xany.type == PropertyNotify) + { + read_settings (client); + return True; + } + } + + return False; +} diff --git a/clutter/x11/xsettings/xsettings-client.h b/clutter/x11/xsettings/xsettings-client.h new file mode 100644 index 000000000..710ed1248 --- /dev/null +++ b/clutter/x11/xsettings/xsettings-client.h @@ -0,0 +1,79 @@ +/* + * Copyright © 2001, 2007 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Red Hat not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Red Hat makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Owen Taylor, Red Hat, Inc. + */ +#ifndef XSETTINGS_CLIENT_H +#define XSETTINGS_CLIENT_H + +#include +#include "xsettings-common.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _XSettingsClient XSettingsClient; + +typedef enum +{ + XSETTINGS_ACTION_NEW, + XSETTINGS_ACTION_CHANGED, + XSETTINGS_ACTION_DELETED +} XSettingsAction; + +typedef void (*XSettingsNotifyFunc) (const char *name, + XSettingsAction action, + XSettingsSetting *setting, + void *cb_data); +typedef Bool (*XSettingsWatchFunc) (Window window, + Bool is_start, + long mask, + void *cb_data); +typedef void (*XSettingsGrabFunc) (Display *display); + +XSettingsClient *xsettings_client_new (Display *display, + int screen, + XSettingsNotifyFunc notify, + XSettingsWatchFunc watch, + void *cb_data); +XSettingsClient *xsettings_client_new_with_grab_funcs (Display *display, + int screen, + XSettingsNotifyFunc notify, + XSettingsWatchFunc watch, + void *cb_data, + XSettingsGrabFunc grab, + XSettingsGrabFunc ungrab); +void xsettings_client_set_grab_func (XSettingsClient *client, + XSettingsGrabFunc grab); +void xsettings_client_set_ungrab_func (XSettingsClient *client, + XSettingsGrabFunc ungrab); +void xsettings_client_destroy (XSettingsClient *client); +Bool xsettings_client_process_event (XSettingsClient *client, + XEvent *xev); +XSettingsResult xsettings_client_get_setting (XSettingsClient *client, + const char *name, + XSettingsSetting **setting); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* XSETTINGS_CLIENT_H */ diff --git a/clutter/x11/xsettings/xsettings-common.c b/clutter/x11/xsettings/xsettings-common.c new file mode 100644 index 000000000..1831324fa --- /dev/null +++ b/clutter/x11/xsettings/xsettings-common.c @@ -0,0 +1,265 @@ +/* + * Copyright © 2001 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Red Hat not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Red Hat makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Owen Taylor, Red Hat, Inc. + */ +#include "config.h" +#include "string.h" +#include "stdlib.h" + +#include +#include /* For CARD32 */ + +#include "xsettings-common.h" + +XSettingsSetting * +xsettings_setting_copy (XSettingsSetting *setting) +{ + XSettingsSetting *result; + size_t str_len; + + result = malloc (sizeof *result); + if (!result) + return NULL; + + str_len = strlen (setting->name); + result->name = malloc (str_len + 1); + if (!result->name) + goto err; + + memcpy (result->name, setting->name, str_len + 1); + + result->type = setting->type; + + switch (setting->type) + { + case XSETTINGS_TYPE_INT: + result->data.v_int = setting->data.v_int; + break; + case XSETTINGS_TYPE_COLOR: + result->data.v_color = setting->data.v_color; + break; + case XSETTINGS_TYPE_STRING: + str_len = strlen (setting->data.v_string); + result->data.v_string = malloc (str_len + 1); + if (!result->data.v_string) + goto err; + + memcpy (result->data.v_string, setting->data.v_string, str_len + 1); + break; + } + + result->last_change_serial = setting->last_change_serial; + + return result; + + err: + if (result->name) + free (result->name); + free (result); + + return NULL; +} + +XSettingsList * +xsettings_list_copy (XSettingsList *list) +{ + XSettingsList *new = NULL; + XSettingsList *old_iter = list; + XSettingsList *new_iter = NULL; + + while (old_iter) + { + XSettingsList *new_node; + + new_node = malloc (sizeof *new_node); + if (!new_node) + goto error; + + new_node->setting = xsettings_setting_copy (old_iter->setting); + if (!new_node->setting) + { + free (new_node); + goto error; + } + + if (new_iter) + new_iter->next = new_node; + else + new = new_node; + + new_iter = new_node; + + old_iter = old_iter->next; + } + + return new; + + error: + xsettings_list_free (new); + return NULL; +} + +int +xsettings_setting_equal (XSettingsSetting *setting_a, + XSettingsSetting *setting_b) +{ + if (setting_a->type != setting_b->type) + return 0; + + if (strcmp (setting_a->name, setting_b->name) != 0) + 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) + free (setting->data.v_string); + + if (setting->name) + free (setting->name); + + free (setting); +} + +void +xsettings_list_free (XSettingsList *list) +{ + while (list) + { + XSettingsList *next = list->next; + + xsettings_setting_free (list->setting); + free (list); + + list = next; + } +} + +XSettingsResult +xsettings_list_insert (XSettingsList **list, + XSettingsSetting *setting) +{ + XSettingsList *node; + XSettingsList *iter; + XSettingsList *last = NULL; + + node = malloc (sizeof *node); + if (!node) + return XSETTINGS_NO_MEM; + node->setting = setting; + + iter = *list; + while (iter) + { + int cmp = strcmp (setting->name, iter->setting->name); + + if (cmp < 0) + break; + else if (cmp == 0) + { + free (node); + return XSETTINGS_DUPLICATE_ENTRY; + } + + last = iter; + iter = iter->next; + } + + if (last) + last->next = node; + else + *list = node; + + node->next = iter; + + return XSETTINGS_SUCCESS; +} + +XSettingsResult +xsettings_list_delete (XSettingsList **list, + const char *name) +{ + XSettingsList *iter; + XSettingsList *last = NULL; + + iter = *list; + while (iter) + { + if (strcmp (name, iter->setting->name) == 0) + { + if (last) + last->next = iter->next; + else + *list = iter->next; + + xsettings_setting_free (iter->setting); + free (iter); + + return XSETTINGS_SUCCESS; + } + + last = iter; + iter = iter->next; + } + + return XSETTINGS_FAILED; +} + +XSettingsSetting * +xsettings_list_lookup (XSettingsList *list, + const char *name) +{ + XSettingsList *iter; + + iter = list; + while (iter) + { + if (strcmp (name, iter->setting->name) == 0) + return iter->setting; + + iter = iter->next; + } + + return NULL; +} + +char +xsettings_byte_order (void) +{ + CARD32 myint = 0x01020304; + return (*(char *)&myint == 1) ? MSBFirst : LSBFirst; +} diff --git a/clutter/x11/xsettings/xsettings-common.h b/clutter/x11/xsettings/xsettings-common.h new file mode 100644 index 000000000..d8b544b36 --- /dev/null +++ b/clutter/x11/xsettings/xsettings-common.h @@ -0,0 +1,132 @@ +/* + * Copyright © 2001 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Red Hat not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Red Hat makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Owen Taylor, Red Hat, Inc. + * + * Modified by: Emmanuele Bassi, Intel Corp. + */ +#ifndef XSETTINGS_COMMON_H +#define XSETTINGS_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Renames for Clutter inclusion */ + +#define xsettings_byte_order _clutter_xsettings_byte_order +#define xsettings_client_destroy _clutter_xsettings_client_destroy +#define xsettings_client_get_setting _clutter_xsettings_client_get_setting +#define xsettings_client_new _clutter_xsettings_client_new +#define xsettings_client_new_with_grab_funcs _clutter_xsettings_client_new_with_grab_funcs +#define xsettings_client_set_grab_func _clutter_xsettings_client_set_grab_func +#define xsettings_client_set_ungrab_func _clutter_xsettings_client_set_ungrab_func +#define xsettings_client_process_event _clutter_xsettings_client_process_event +#define xsettings_list_copy _clutter_xsettings_list_copy +#define xsettings_list_delete _clutter_xsettings_list_delete +#define xsettings_list_free _clutter_xsettings_list_free +#define xsettings_list_insert _clutter_xsettings_list_insert +#define xsettings_list_lookup _clutter_xsettings_list_lookup +#define xsettings_setting_copy _clutter_xsettings_setting_copy +#define xsettings_setting_equal _clutter_xsettings_setting_equal +#define xsettings_setting_free _clutter_xsettings_setting_free + + +typedef struct _XSettingsBuffer XSettingsBuffer; +typedef struct _XSettingsColor XSettingsColor; +typedef struct _XSettingsList XSettingsList; +typedef struct _XSettingsSetting XSettingsSetting; + +/* 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 enum +{ + XSETTINGS_SUCCESS, + XSETTINGS_NO_MEM, + XSETTINGS_ACCESS, + XSETTINGS_FAILED, + XSETTINGS_NO_ENTRY, + XSETTINGS_DUPLICATE_ENTRY +} XSettingsResult; + +struct _XSettingsBuffer +{ + char byte_order; + size_t len; + unsigned char *data; + unsigned char *pos; +}; + +struct _XSettingsColor +{ + unsigned short red, green, blue, alpha; +}; + +struct _XSettingsList +{ + XSettingsSetting *setting; + XSettingsList *next; +}; + +struct _XSettingsSetting +{ + char *name; + XSettingsType type; + + union { + int v_int; + char *v_string; + XSettingsColor v_color; + } data; + + unsigned long last_change_serial; +}; + +XSettingsSetting *xsettings_setting_copy (XSettingsSetting *setting); +void xsettings_setting_free (XSettingsSetting *setting); +int xsettings_setting_equal (XSettingsSetting *setting_a, + XSettingsSetting *setting_b); + +void xsettings_list_free (XSettingsList *list); +XSettingsList *xsettings_list_copy (XSettingsList *list); +XSettingsResult xsettings_list_insert (XSettingsList **list, + XSettingsSetting *setting); +XSettingsSetting *xsettings_list_lookup (XSettingsList *list, + const char *name); +XSettingsResult xsettings_list_delete (XSettingsList **list, + const char *name); + +char xsettings_byte_order (void); + +#define XSETTINGS_PAD(n,m) ((n + m - 1) & (~(m-1))) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* XSETTINGS_COMMON_H */