diff options
Diffstat (limited to 'xsettings/xsettings-manager.c')
-rw-r--r-- | xsettings/xsettings-manager.c | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/xsettings/xsettings-manager.c b/xsettings/xsettings-manager.c new file mode 100644 index 0000000..0dcfb02 --- /dev/null +++ b/xsettings/xsettings-manager.c @@ -0,0 +1,424 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <X11/Xmd.h> /* For CARD16 */ + +#include "xsettings-manager.h" + +struct _XSettingsManager +{ + Display *display; + int screen; + + Window window; + Atom manager_atom; + Atom selection_atom; + Atom xsettings_atom; + + XSettingsTerminateFunc terminate; + void *cb_data; + + XSettingsList *settings; + unsigned long serial; +}; + +XSettingsList *settings; + +typedef struct +{ + Window window; + Atom timestamp_prop_atom; +} TimeStampInfo; + +static Bool +timestamp_predicate (Display *display, + XEvent *xevent, + XPointer arg) +{ + TimeStampInfo *info = (TimeStampInfo *)arg; + + if (xevent->type == PropertyNotify && + xevent->xproperty.window == info->window && + xevent->xproperty.atom == info->timestamp_prop_atom) + return True; + + return False; +} + +/** + * get_server_time: + * @display: display from which to get the time + * @window: a #Window, used for communication with the server. + * The window must have PropertyChangeMask in its + * events mask or a hang will result. + * + * Routine to get the current X server time stamp. + * + * Return value: the time stamp. + **/ +static Time +get_server_time (Display *display, + Window window) +{ + unsigned char c = 'a'; + XEvent xevent; + TimeStampInfo info; + + info.timestamp_prop_atom = XInternAtom (display, "_TIMESTAMP_PROP", False); + info.window = window; + + XChangeProperty (display, window, + info.timestamp_prop_atom, info.timestamp_prop_atom, + 8, PropModeReplace, &c, 1); + + XIfEvent (display, &xevent, + timestamp_predicate, (XPointer)&info); + + return xevent.xproperty.time; +} + +Bool +xsettings_manager_check_running (Display *display, + int screen) +{ + char buffer[256]; + Atom selection_atom; + + sprintf(buffer, "_XSETTINGS_S%d", screen); + selection_atom = XInternAtom (display, buffer, False); + + if (XGetSelectionOwner (display, selection_atom)) + return True; + else + return False; +} + +XSettingsManager * +xsettings_manager_new (Display *display, + int screen, + XSettingsTerminateFunc terminate, + void *cb_data) +{ + XSettingsManager *manager; + Time timestamp; + XClientMessageEvent xev; + + char buffer[256]; + + manager = malloc (sizeof *manager); + if (!manager) + return NULL; + + manager->display = display; + manager->screen = screen; + + sprintf(buffer, "_XSETTINGS_S%d", screen); + manager->selection_atom = XInternAtom (display, buffer, False); + manager->xsettings_atom = XInternAtom (display, "_XSETTINGS_SETTINGS", False); + manager->manager_atom = XInternAtom (display, "MANAGER", False); + + manager->terminate = terminate; + manager->cb_data = cb_data; + + manager->settings = NULL; + manager->serial = 0; + + manager->window = XCreateSimpleWindow (display, + RootWindow (display, screen), + 0, 0, 10, 10, 0, + WhitePixel (display, screen), + WhitePixel (display, screen)); + + XSelectInput (display, manager->window, PropertyChangeMask); + timestamp = get_server_time (display, manager->window); + + XSetSelectionOwner (display, manager->selection_atom, + manager->window, timestamp); + + /* Check to see if we managed to claim the selection. If not, + * we treat it as if we got it then immediately lost it + */ + + if (XGetSelectionOwner (display, manager->selection_atom) == + manager->window) + { + xev.type = ClientMessage; + xev.window = RootWindow (display, screen); + xev.message_type = manager->manager_atom; + xev.format = 32; + xev.data.l[0] = timestamp; + xev.data.l[1] = manager->selection_atom; + xev.data.l[2] = manager->window; + xev.data.l[3] = 0; /* manager specific data */ + xev.data.l[4] = 0; /* manager specific data */ + + XSendEvent (display, RootWindow (display, screen), + False, StructureNotifyMask, (XEvent *)&xev); + } + else + { + manager->terminate (manager->cb_data); + } + + return manager; +} + +void +xsettings_manager_destroy (XSettingsManager *manager) +{ + XDestroyWindow (manager->display, manager->window); + + xsettings_list_free (manager->settings); + free (manager); +} + +Window +xsettings_manager_get_window (XSettingsManager *manager) +{ + return manager->window; +} + +Bool +xsettings_manager_process_event (XSettingsManager *manager, + XEvent *xev) +{ + if (xev->xany.window == manager->window && + xev->xany.type == SelectionClear && + xev->xselectionclear.selection == manager->selection_atom) + { + manager->terminate (manager->cb_data); + return True; + } + + return False; +} + +XSettingsResult +xsettings_manager_set_setting (XSettingsManager *manager, + XSettingsSetting *setting) +{ + XSettingsSetting *old_setting = xsettings_list_lookup (settings, setting->name); + XSettingsSetting *new_setting; + XSettingsResult result; + + if (old_setting) + { + if (xsettings_setting_equal (old_setting, setting)) + return XSETTINGS_SUCCESS; + + xsettings_list_delete (&settings, setting->name); + } + + new_setting = xsettings_setting_copy (setting); + if (!new_setting) + return XSETTINGS_NO_MEM; + + new_setting->last_change_serial = manager->serial; + + result = xsettings_list_insert (&settings, new_setting); + + if (result != XSETTINGS_SUCCESS) + xsettings_setting_free (new_setting); + + return result; +} + +XSettingsResult +xsettings_manager_delete_setting (XSettingsManager *manager, + const char *name) +{ + return xsettings_list_delete (&settings, name); +} + +XSettingsResult +xsettings_manager_set_int (XSettingsManager *manager, + const char *name, + int value) +{ + XSettingsSetting setting; + + setting.name = (char *)name; + setting.type = XSETTINGS_TYPE_INT; + setting.data.v_int = value; + + return xsettings_manager_set_setting (manager, &setting); +} + +XSettingsResult +xsettings_manager_set_string (XSettingsManager *manager, + const char *name, + const char *value) +{ + XSettingsSetting setting; + + setting.name = (char *)name; + setting.type = XSETTINGS_TYPE_STRING; + setting.data.v_string = (char *)value; + + return xsettings_manager_set_setting (manager, &setting); +} + +XSettingsResult +xsettings_manager_set_color (XSettingsManager *manager, + const char *name, + XSettingsColor *value) +{ + XSettingsSetting setting; + + setting.name = (char *)name; + setting.type = XSETTINGS_TYPE_COLOR; + setting.data.v_color = *value; + + return xsettings_manager_set_setting (manager, &setting); +} + +size_t +setting_length (XSettingsSetting *setting) +{ + size_t length = 8; /* type + pad + name-len + last-change-serial */ + length += XSETTINGS_PAD (strlen (setting->name), 4); + + switch (setting->type) + { + case XSETTINGS_TYPE_INT: + length += 4; + break; + case XSETTINGS_TYPE_STRING: + length += 4 + XSETTINGS_PAD (strlen (setting->data.v_string), 4); + break; + case XSETTINGS_TYPE_COLOR: + length += 8; + break; + } + + return length; +} + +void +setting_store (XSettingsSetting *setting, + XSettingsBuffer *buffer) +{ + size_t string_len; + size_t length; + + *(buffer->pos++) = setting->type; + *(buffer->pos++) = 0; + + string_len = strlen (setting->name); + *(CARD16 *)(buffer->pos) = string_len; + buffer->pos += 2; + + length = XSETTINGS_PAD (string_len, 4); + memcpy (buffer->pos, setting->name, string_len); + length -= string_len; + buffer->pos += string_len; + + while (length > 0) + { + *(buffer->pos++) = 0; + length--; + } + + *(CARD32 *)(buffer->pos) = setting->last_change_serial; + buffer->pos += 4; + + switch (setting->type) + { + case XSETTINGS_TYPE_INT: + *(CARD32 *)(buffer->pos) = setting->data.v_int; + buffer->pos += 4; + break; + case XSETTINGS_TYPE_STRING: + string_len = strlen (setting->data.v_string); + *(CARD32 *)(buffer->pos) = string_len; + buffer->pos += 4; + + length = XSETTINGS_PAD (string_len, 4); + memcpy (buffer->pos, setting->data.v_string, string_len); + length -= string_len; + buffer->pos += string_len; + + while (length > 0) + { + *(buffer->pos++) = 0; + length--; + } + break; + case XSETTINGS_TYPE_COLOR: + *(CARD16 *)(buffer->pos) = setting->data.v_color.red; + *(CARD16 *)(buffer->pos + 2) = setting->data.v_color.green; + *(CARD16 *)(buffer->pos + 4) = setting->data.v_color.blue; + *(CARD16 *)(buffer->pos + 6) = setting->data.v_color.alpha; + buffer->pos += 8; + break; + } +} + +XSettingsResult +xsettings_manager_notify (XSettingsManager *manager) +{ + XSettingsBuffer buffer; + XSettingsList *iter; + int n_settings = 0; + + buffer.len = 12; /* byte-order + pad + SERIAL + N_SETTINGS */ + + iter = settings; + while (iter) + { + buffer.len += setting_length (iter->setting); + n_settings++; + iter = iter->next; + } + + buffer.data = buffer.pos = malloc (buffer.len); + if (!buffer.data) + return XSETTINGS_NO_MEM; + + *buffer.pos = xsettings_byte_order (); + + buffer.pos += 4; + *(CARD32 *)buffer.pos = manager->serial++; + buffer.pos += 4; + *(CARD32 *)buffer.pos = n_settings; + buffer.pos += 4; + + iter = settings; + while (iter) + { + setting_store (iter->setting, &buffer); + iter = iter->next; + } + + XChangeProperty (manager->display, manager->window, + manager->xsettings_atom, manager->xsettings_atom, + 8, PropModeReplace, buffer.data, buffer.len); + + free (buffer.data); + + return XSETTINGS_SUCCESS; +} + |