/* * Copyright © 2006 Novell, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Author: David Reveman */ #include #include #include #define DBUS_API_SUBJECT_TO_CHANGE #include #include #define BERYL_DBUS_SERVICE_NAME "org.freedesktop.beryl" #define BERYL_DBUS_ACTIVATE_MEMBER_NAME "activate" #define BERYL_DBUS_DEACTIVATE_MEMBER_NAME "deactivate" #define BERYL_DBUS_SET_MEMBER_NAME "set" #define BERYL_DBUS_GET_MEMBER_NAME "get" #define BERYL_DBUS_GET_METADATA_MEMBER_NAME "getMetadata" #define BERYL_DBUS_LIST_MEMBER_NAME "list" #define BERYL_DBUS_GET_PLUGINS_MEMBER_NAME "getPlugins" #define BERYL_DBUS_CHANGED_SIGNAL_NAME "changed" typedef enum { DbusActionIndexKeyBinding = 0, DbusActionIndexButtonBinding = 1, DbusActionIndexBell = 2, DbusActionIndexEdge = 3, DbusActionIndexEdgeButton = 4 } DbusActionIndex; static int displayPrivateIndex; typedef struct _DbusDisplay { int screenPrivateIndex; DBusConnection *connection; CompWatchFdHandle watchFdHandle; SetDisplayOptionProc setDisplayOption; SetDisplayOptionForPluginProc setDisplayOptionForPlugin; } DbusDisplay; typedef struct _DbusScreen { SetScreenOptionProc setScreenOption; SetScreenOptionForPluginProc setScreenOptionForPlugin; } DbusScreen; #define GET_DBUS_DISPLAY(d) \ ((DbusDisplay *) (d)->privates[displayPrivateIndex].ptr) #define DBUS_DISPLAY(d) \ DbusDisplay *dd = GET_DBUS_DISPLAY (d) #define GET_DBUS_SCREEN(s, dd) \ ((DbusScreen *) (s)->privates[(dd)->screenPrivateIndex].ptr) #define DBUS_SCREEN(s) \ DbusScreen *ds = GET_DBUS_SCREEN (s, GET_DBUS_DISPLAY (s->display)) static CompOption *dbusGetOptionsFromPath(CompDisplay * d, char **path, CompScreen ** return_screen, int *nOption) { CompScreen *s = NULL; if (strcmp(path[1], "allscreens")) { int screenNum; if (sscanf(path[1], "screen%d", &screenNum) != 1) return FALSE; for (s = d->screens; s; s = s->next) if (s->screenNum == screenNum) break; if (!s) return NULL; } if (return_screen) *return_screen = s; if (strcmp(path[0], "core") == 0) { if (s) return compGetScreenOptions(s, nOption); else return compGetDisplayOptions(d, nOption); } else { CompPlugin *p; for (p = getPlugins(); p; p = p->next) if (strcmp(p->vTable->name, path[0]) == 0) break; if (!p) return NULL; if (s) { if (p->vTable->getScreenOptions) return (*p->vTable->getScreenOptions) (s, nOption); } else { if (p->vTable->getDisplayOptions) return (*p->vTable->getDisplayOptions) (d, nOption); } } return NULL; } /* * Activate can be used to trigger any existing action. Arguments * should be a pair of { string, bool|int32|double|string }. * * Example (rotate to face 1): * * dbus-send --type=method_call --dest=org.freedesktop.beryl \ * /org/beryl-project/beryl/rotate/allscreens/rotate_to \ * org.freedesktop.beryl.activate \ * string:'root' \ * int32:`xwininfo -root | grep id: | awk '{ print $4 }'` \ * string:'face' int32:1 * * * You can also call the terminate function * * Example unfold and refold cube: * dbus-send --type=method_call --dest=org.freedesktop.beryl \ * /org/beryl-project/beryl/cube/allscreens/unfold \ * org.freedesktop.beryl.activate \ * string:'root' \ * int32:`xwininfo -root | grep id: | awk '{ print $4 }'` \ * * dbus-send --type=method_call --dest=org.freedesktop.beryl \ * /org/beryl-project/beryl/cube/allscreens/unfold \ * org.freedesktop.beryl.deactivate \ * string:'root' \ * int32:`xwininfo -root | grep id: | awk '{ print $4 }'` \ */ static Bool dbusHandleActionMessage(DBusConnection * connection, DBusMessage * message, CompDisplay * d, char **path, Bool activate) { CompOption *option; int nOption; option = dbusGetOptionsFromPath(d, path, NULL, &nOption); if (!option) return FALSE; while (nOption--) { if (strcmp(option->name, path[2]) == 0) { CompOption *argument = NULL; int nArgument = 0; DBusMessageIter iter; if (option->type != CompOptionTypeAction) return FALSE; if (activate) { if (!option->value.action.initiate) return FALSE; } else { if (!option->value.action.terminate) return FALSE; } if (dbus_message_iter_init(message, &iter)) { CompOptionValue value; CompOptionType type = 0; char *name; Bool hasValue; do { name = NULL; hasValue = FALSE; while (!name) { switch (dbus_message_iter_get_arg_type(&iter)) { case DBUS_TYPE_STRING: dbus_message_iter_get_basic(&iter, &name); default: break; } if (!dbus_message_iter_next(&iter)) break; } while (!hasValue) { double tmp; switch (dbus_message_iter_get_arg_type(&iter)) { case DBUS_TYPE_BOOLEAN: hasValue = TRUE; type = CompOptionTypeBool; dbus_message_iter_get_basic(&iter, &value.b); break; case DBUS_TYPE_INT32: hasValue = TRUE; type = CompOptionTypeInt; dbus_message_iter_get_basic(&iter, &value.i); break; case DBUS_TYPE_DOUBLE: hasValue = TRUE; type = CompOptionTypeFloat; dbus_message_iter_get_basic(&iter, &tmp); value.f = tmp; break; case DBUS_TYPE_STRING: hasValue = TRUE; type = CompOptionTypeString; dbus_message_iter_get_basic(&iter, &value.s); default: break; } if (!dbus_message_iter_next(&iter)) break; } if (name && hasValue) { CompOption *a; a = realloc(argument, sizeof(CompOption) * (nArgument + 1)); if (a) { argument = a; argument[nArgument].name = name; argument[nArgument].type = type; argument[nArgument].value = value; nArgument++; } } } while (dbus_message_iter_has_next(&iter)); } if (activate) { (*option->value.action.initiate) (d, &option->value.action, 0, argument, nArgument); } else { (*option->value.action.terminate) (d, &option->value.action, 0, argument, nArgument); } if (argument) free(argument); if (!dbus_message_get_no_reply(message)) { DBusMessage * reply; reply = dbus_message_new_method_return (message); dbus_connection_send(connection,reply,NULL); dbus_connection_flush(connection); dbus_message_unref(reply); } return TRUE; } option++; } return FALSE; } static Bool dbusTryGetValueWithType(DBusMessageIter * iter, int type, void *value) { if (dbus_message_iter_get_arg_type(iter) == type) { dbus_message_iter_get_basic(iter, value); return TRUE; } return FALSE; } static Bool dbusGetOptionValue(DBusMessageIter * iter, CompOptionType type, CompOptionValue * value) { double d; char *s; switch (type) { case CompOptionTypeBool: return dbusTryGetValueWithType(iter, DBUS_TYPE_BOOLEAN, &value->b); break; case CompOptionTypeInt: return dbusTryGetValueWithType(iter, DBUS_TYPE_INT32, &value->i); break; case CompOptionTypeFloat: if (dbusTryGetValueWithType(iter, DBUS_TYPE_DOUBLE, &d)) { value->f = d; return TRUE; } break; case CompOptionTypeString: return dbusTryGetValueWithType(iter, DBUS_TYPE_STRING, &value->s); break; case CompOptionTypeColor: if (dbusTryGetValueWithType(iter, DBUS_TYPE_STRING, &s)) { if (stringToColor(s, value->c)) return TRUE; } default: break; } return FALSE; } /* * 'Set' can be used to change any existing option. Argument * should be the new value for the option. * * Example (will set command0 option to firefox): * * dbus-send --type=method_call --dest=org.freedesktop.beryl \ * /org/beryl-project/beryl/core/allscreens/command0 \ * org.freedesktop.beryl.set \ * string:'firefox' * * List and action options can be changed using more than one * argument. * * Example (will set active_plugins option to * [dbus,decoration,place]): * * dbus-send --type=method_call --dest=org.freedesktop.beryl \ * /org/beryl-project/beryl/core/allscreens/active_plugins \ * org.freedesktop.beryl.set \ * string:'dbus' string:'decoration' string:'place' * * Example (will set run_command0 option to trigger on key * binding Return and not trigger on any button * bindings, screen edges or bell notifications): * * dbus-send --type=method_call --dest=org.freedesktop.beryl \ * /org/beryl-project/beryl/core/allscreens/run_command0 \ * org.freedesktop.beryl.set \ * string:'Return' \ * string:'Disabled' \ * boolean:'false' \ * string:'' \ * int:'0' */ static Bool dbusHandleSetOptionMessage(DBusConnection * connection, DBusMessage * message, CompDisplay * d, char **path) { CompScreen *s; CompOption *option; int nOption; option = dbusGetOptionsFromPath(d, path, &s, &nOption); if (!option) return FALSE; while (nOption--) { if (strcmp(option->name, path[2]) == 0) { DBusMessageIter iter; if (dbus_message_iter_init(message, &iter)) { CompOptionValue value, tmpValue; DbusActionIndex actionIndex = DbusActionIndexKeyBinding; Bool status = FALSE; memset(&value, 0, sizeof(value)); do { if (option->type == CompOptionTypeList) { if (dbusGetOptionValue (&iter, option->type, &tmpValue)) { CompOptionValue *v; v = realloc(value.list.value, sizeof(CompOptionValue) * (value.list.nValue + 1)); if (v) { v[value.list.nValue++] = tmpValue; value.list.value = v; status |= TRUE; } } } else if (option->type == CompOptionTypeAction) { CompAction *a = &value.action; char *str; status = TRUE; switch (actionIndex) { case DbusActionIndexKeyBinding: if (dbusTryGetValueWithType(&iter, DBUS_TYPE_STRING, &str)) { if (stringToKeyBinding(d, str, &a->key)) a->type |= CompBindingTypeKey; } break; case DbusActionIndexButtonBinding: if (dbusTryGetValueWithType(&iter, DBUS_TYPE_STRING, &str)) { if (stringToButtonBinding(d, str, &a->button)) a->type |= CompBindingTypeButton; } break; case DbusActionIndexBell: dbusTryGetValueWithType(&iter, DBUS_TYPE_BOOLEAN, &a->bell); break; case DbusActionIndexEdge: if (dbusTryGetValueWithType(&iter, DBUS_TYPE_STRING, &str)) { status |= TRUE; while (strlen(str)) { char *edge; int len, i = SCREEN_EDGE_NUM; for (;;) { edge = edgeToString(--i); len = strlen(edge); if (strncasecmp(str, edge, len) == 0) { a->edgeMask |= 1 << i; str += len; break; } if (!i) { str++; break; } } } } default: break; } actionIndex++; } else if (dbusGetOptionValue(&iter, option->type, &value)) { status |= TRUE; } } while (dbus_message_iter_next(&iter)); if (status) { if (s) { if (strcmp(path[0], "core")) status = (*s->setScreenOptionForPlugin) (s, path[0], option-> name, &value); else status = (*s->setScreenOption) (s, option->name, &value); } else { if (strcmp(path[0], "core")) status = (*d->setDisplayOptionForPlugin) (d, path[0], option-> name, &value); else status = (*d->setDisplayOption) (d, option->name, &value); } return status; } else { return FALSE; } } } option++; } return FALSE; } static void dbusAppendSimpleOptionValue(DBusMessage * message, CompOptionType type, CompOptionValue * value) { double d; char *s; switch (type) { case CompOptionTypeBool: dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &value->b, DBUS_TYPE_INVALID); break; case CompOptionTypeInt: dbus_message_append_args(message, DBUS_TYPE_INT32, &value->i, DBUS_TYPE_INVALID); break; case CompOptionTypeFloat: d = value->f; dbus_message_append_args(message, DBUS_TYPE_DOUBLE, &d, DBUS_TYPE_INVALID); break; case CompOptionTypeString: dbus_message_append_args(message, DBUS_TYPE_STRING, &value->s, DBUS_TYPE_INVALID); break; case CompOptionTypeColor: s = colorToString(value->c); if (s) { dbus_message_append_args(message, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID); free(s); } default: break; } } static void dbusAppendOptionValue(CompDisplay * d, DBusMessage * message, CompOptionType type, CompOptionValue * value) { int i; if (type == CompOptionTypeList) { for (i = 0; i < value->list.nValue; i++) dbusAppendSimpleOptionValue(message, value->list.type, &value->list.value[i]); } else if (type == CompOptionTypeAction) { CompAction *a = &value->action; char *key = "Disabled"; char *button = "Disabled"; char *edge = "Disabled"; int edgeButton = 0; if (a->type & CompBindingTypeKey) key = keyBindingToString(d, &a->key); if (a->type & CompBindingTypeButton) button = buttonBindingToString(d, &a->button); for (i = 0; i < SCREEN_EDGE_NUM; i++) if (a->edgeMask & (1 << i)) edge = edgeToString(i); dbus_message_append_args(message, DBUS_TYPE_STRING, &key, DBUS_TYPE_STRING, &button, DBUS_TYPE_BOOLEAN, &a->bell, DBUS_TYPE_STRING, &edge, DBUS_TYPE_INT32, &edgeButton, DBUS_TYPE_INVALID); } else { dbusAppendSimpleOptionValue(message, type, value); } } /* * 'Get' can be used to retrieve the value of any existing option. * * Example (will retrieve the current value of command0 option): * * dbus-send --print-reply --type=method_call \ * --dest=org.freedesktop.beryl \ * /org/beryl-project/beryl/core/allscreens/command0 \ * org.freedesktop.beryl.get */ static Bool dbusHandleGetOptionMessage(DBusConnection * connection, DBusMessage * message, CompDisplay * d, char **path) { CompScreen *s; CompOption *option; int nOption = 0; DBusMessage *reply = NULL; option = dbusGetOptionsFromPath(d, path, &s, &nOption); while (nOption--) { if (strcmp(option->name, path[2]) == 0) { reply = dbus_message_new_method_return(message); dbusAppendOptionValue(d, reply, option->type, &option->value); break; } option++; } if (!reply) reply = dbus_message_new_error(message, DBUS_ERROR_FAILED, "No such option"); dbus_connection_send(connection, reply, NULL); dbus_connection_flush(connection); dbus_message_unref(reply); return TRUE; } static Bool dbusHandleListMessage(DBusConnection * connection, DBusMessage * message, CompDisplay * d, char **path) { CompScreen *s; CompOption *option; int nOption = 0; DBusMessage *reply; option = dbusGetOptionsFromPath(d, path, &s, &nOption); reply = dbus_message_new_method_return(message); while (nOption--) { dbus_message_append_args(reply, DBUS_TYPE_STRING, &option->name, DBUS_TYPE_INVALID); option++; } dbus_connection_send(connection, reply, NULL); dbus_connection_flush(connection); dbus_message_unref(reply); return TRUE; } static Bool dbusHandleGetMetadataMessage(DBusConnection * connection, DBusMessage * message, CompDisplay * d, char **path) { CompScreen *s; CompOption *option; int nOption = 0; DBusMessage *reply = NULL; reply = dbus_message_new_method_return(message); //check to see if we've been called on a plugin if (!path[1]) { if (!strcmp(path[0], "core")) { char *shortDesc = "General Options"; char *longDesc = "Options for Beryl as a whole"; dbus_message_append_args(reply, DBUS_TYPE_STRING, &shortDesc, DBUS_TYPE_STRING, &longDesc, DBUS_TYPE_INVALID); } else { CompPlugin *p; p = findActivePlugin(path[0]); if (p) { dbus_message_append_args(reply, DBUS_TYPE_STRING, &p->vTable->shortDesc, DBUS_TYPE_STRING, &p->vTable->longDesc, DBUS_TYPE_INVALID); } } } else { option = dbusGetOptionsFromPath(d, path, &s, &nOption); while (nOption--) { if (strcmp(option->name, path[2]) == 0) { CompOptionType restrictionType = option->type; char *type; type = optionTypeToString(option->type); dbus_message_append_args(reply, DBUS_TYPE_STRING, &option->shortDesc, DBUS_TYPE_STRING, &option->longDesc, DBUS_TYPE_STRING, &type, DBUS_TYPE_INVALID); if (restrictionType == CompOptionTypeList) { type = optionTypeToString(option->value.list.type); restrictionType = option->value.list.type; dbus_message_append_args(reply, DBUS_TYPE_STRING, &type, DBUS_TYPE_INVALID); } switch (restrictionType) { case CompOptionTypeInt: dbus_message_append_args(reply, DBUS_TYPE_INT32, &option->rest.i.min, DBUS_TYPE_INT32, &option->rest.i.max, DBUS_TYPE_INVALID); break; case CompOptionTypeFloat: { double min, max, precision; min = option->rest.f.min; max = option->rest.f.max; precision = option->rest.f.precision; dbus_message_append_args(reply, DBUS_TYPE_DOUBLE, &min, DBUS_TYPE_DOUBLE, &max, DBUS_TYPE_DOUBLE, &precision, DBUS_TYPE_INVALID); } break; case CompOptionTypeString: { DBusMessageIter iter; DBusMessageIter listIter; char sig[2]; sig[0] = DBUS_TYPE_STRING; sig[1] = '\0'; dbus_message_iter_init_append (reply, &iter); dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, sig, &listIter); if (option->rest.s.nString) { char *possible; int i; for (i = 0; i < option->rest.s.nString; i++) { possible = option->rest.s.string[i]; dbus_message_iter_append_basic(&listIter,DBUS_TYPE_STRING,&possible); } } dbus_message_iter_close_container(&iter,&listIter); } default: break; } break; } option++; } } if (!reply) reply = dbus_message_new_error(message, DBUS_ERROR_FAILED, "No such option"); dbus_connection_send(connection, reply, NULL); dbus_connection_flush(connection); dbus_message_unref(reply); return TRUE; } static Bool dbusHandleGetPluginsMessage( DBusConnection *connection, DBusMessage *message, CompDisplay *d) { DBusMessage *reply; char **plugins, **p; int n; reply = dbus_message_new_method_return ( message ); plugins = availablePlugins(&n); if (plugins) { p=plugins; while (n--) { dbus_message_append_args(reply,DBUS_TYPE_STRING,p,DBUS_TYPE_INVALID); free(*p); p++; } free (plugins); } dbus_connection_send(connection,reply,NULL); dbus_connection_flush(connection); return TRUE; } static DBusHandlerResult dbusHandleMessage(DBusConnection * connection, DBusMessage * message, void *userData) { CompDisplay *d = (CompDisplay *) userData; Bool status = FALSE; char **path; const char *service, *interface, *member; service = dbus_message_get_destination(message); interface = dbus_message_get_interface(message); member = dbus_message_get_member(message); if (!service || !interface || !member) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; if (!dbus_message_is_method_call(message, interface, member)) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; if (!dbus_message_has_destination(message, BERYL_DBUS_SERVICE_NAME)) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; if (!dbus_message_get_path_decomposed(message, &path)) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; if (!path[0] || !path[1] || !path[2]) { dbus_free_string_array (path); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } if (strcmp(path[0], "org") || strcmp(path[1], "freedesktop") || strcmp(path[2], "beryl")) { dbus_free_string_array (path); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } if (dbus_message_has_member (message, BERYL_DBUS_GET_PLUGINS_MEMBER_NAME)) { if (dbusHandleGetPluginsMessage(connection,message,d)) { dbus_free_string_array(path); return DBUS_HANDLER_RESULT_HANDLED; } } if (!path[3] || !path[4]) { dbus_free_string_array(path); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } if (dbus_message_has_member (message, BERYL_DBUS_LIST_MEMBER_NAME)) { if (dbusHandleListMessage(connection,message,d, &path[4])) { dbus_free_string_array(path); return DBUS_HANDLER_RESULT_HANDLED; } } if (!path[5]) { dbus_free_string_array(path); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } if (dbus_message_has_member(message, BERYL_DBUS_ACTIVATE_MEMBER_NAME) ) { status = dbusHandleActionMessage(connection, message, d, &path[3], TRUE); } else if (dbus_message_has_member(message, BERYL_DBUS_DEACTIVATE_MEMBER_NAME) ) { status = dbusHandleActionMessage(connection, message, d, &path[3], FALSE); } else if (dbus_message_has_member(message, BERYL_DBUS_SET_MEMBER_NAME) ) { status = dbusHandleSetOptionMessage(connection, message, d, &path[3]); } else if (dbus_message_has_member(message, BERYL_DBUS_GET_MEMBER_NAME)) { status = dbusHandleGetOptionMessage(connection, message, d, &path[3]); } else if (dbus_message_has_member(message, BERYL_DBUS_GET_METADATA_MEMBER_NAME)) { status = dbusHandleGetMetadataMessage(connection, message, d, &path[3]); } dbus_free_string_array(path); if (status) return DBUS_HANDLER_RESULT_HANDLED; return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static Bool dbusProcessMessages(void *data) { CompDisplay *d = (CompDisplay *) data; DBusDispatchStatus status; DBUS_DISPLAY(d); do { dbus_connection_read_write_dispatch(dd->connection, 0); status = dbus_connection_get_dispatch_status(dd->connection); } while (status == DBUS_DISPATCH_DATA_REMAINS); return TRUE; } static void dbusSendChangeSignalForOption(CompDisplay * d, CompOptionType type, CompOptionValue * value, char *path) { DBusMessage *signal; DBUS_DISPLAY(d); signal = dbus_message_new_signal(path, BERYL_DBUS_SERVICE_NAME, BERYL_DBUS_CHANGED_SIGNAL_NAME); dbusAppendOptionValue(d, signal, type, value); dbus_connection_send(dd->connection, signal, NULL); dbus_connection_flush(dd->connection); dbus_message_unref(signal); } static void dbusSendChangeSignalForDisplayOption(CompDisplay * d, CompOption * o, char *plugin) { char path[256]; if (o) { sprintf(path, "/org/freedesktop/beryl/%s/allscreens/%s", plugin, o->name); dbusSendChangeSignalForOption(d, o->type, &o->value, path); } } static void dbusSendChangeSignalForScreenOption(CompScreen * s, CompOption * o, char *plugin) { char path[256]; if (o) { sprintf(path, "/org/freedesktop/beryl/%s/screens%d/%s", plugin, s->screenNum, o->name); dbusSendChangeSignalForOption(s->display, o->type, &o->value, path); } } static Bool dbusSetDisplayOption(CompDisplay * d, char *name, CompOptionValue * value) { Bool status; DBUS_DISPLAY(d); UNWRAP(dd, d, setDisplayOption); status = (*d->setDisplayOption) (d, name, value); WRAP(dd, d, setDisplayOption, dbusSetDisplayOption); if (status) { CompOption *option; int nOption; option = compGetDisplayOptions(d, &nOption); dbusSendChangeSignalForDisplayOption(d, compFindOption(option, nOption, name, 0), "core"); } return status; } static Bool dbusSetDisplayOptionForPlugin(CompDisplay * d, char *plugin, char *name, CompOptionValue * value) { Bool status; DBUS_DISPLAY(d); UNWRAP(dd, d, setDisplayOptionForPlugin); status = (*d->setDisplayOptionForPlugin) (d, plugin, name, value); WRAP(dd, d, setDisplayOptionForPlugin, dbusSetDisplayOptionForPlugin); if (status) { CompPlugin *p; p = findActivePlugin(plugin); if (p && p->vTable->getDisplayOptions) { CompOption *option; int nOption; option = (*p->vTable->getDisplayOptions) (d, &nOption); dbusSendChangeSignalForDisplayOption(d, compFindOption(option, nOption, name, 0), p->vTable->name); } } return status; } static Bool dbusSetScreenOption(CompScreen * s, char *name, CompOptionValue * value) { Bool status; DBUS_SCREEN(s); UNWRAP(ds, s, setScreenOption); status = (*s->setScreenOption) (s, name, value); WRAP(ds, s, setScreenOption, dbusSetScreenOption); if (status) { CompOption *option; int nOption; option = compGetScreenOptions(s, &nOption); dbusSendChangeSignalForScreenOption(s, compFindOption(option, nOption, name, 0), "core"); } return status; } static Bool dbusSetScreenOptionForPlugin(CompScreen * s, char *plugin, char *name, CompOptionValue * value) { Bool status; DBUS_SCREEN(s); UNWRAP(ds, s, setScreenOptionForPlugin); status = (*s->setScreenOptionForPlugin) (s, plugin, name, value); WRAP(ds, s, setScreenOptionForPlugin, dbusSetScreenOptionForPlugin); if (status) { CompPlugin *p; p = findActivePlugin(plugin); if (p && p->vTable->getScreenOptions) { CompOption *option; int nOption; option = (*p->vTable->getScreenOptions) (s, &nOption); dbusSendChangeSignalForScreenOption(s, compFindOption(option, nOption, name, 0), p->vTable->name); } } return status; } static Bool dbusInitDisplay(CompPlugin * p, CompDisplay * d) { DbusDisplay *dd; DBusError error; dbus_bool_t status; int fd, ret; dd = malloc(sizeof(DbusDisplay)); if (!dd) return FALSE; dd->screenPrivateIndex = allocateScreenPrivateIndex(d); if (dd->screenPrivateIndex < 0) { free(dd); return FALSE; } dbus_error_init(&error); dd->connection = dbus_bus_get(DBUS_BUS_SESSION, &error); if (dbus_error_is_set(&error)) { fprintf(stderr, "%s: dbus_bus_get error: %s\n", getProgramName(), error.message); dbus_error_free(&error); free(dd); return FALSE; } ret = dbus_bus_request_name(dd->connection, BERYL_DBUS_SERVICE_NAME, DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_ALLOW_REPLACEMENT, &error); if (dbus_error_is_set(&error)) { fprintf(stderr, "%s: dbus_bus_request_name error: %s\n", getProgramName(), error.message); /* dbus_connection_unref (dd->connection); */ dbus_error_free(&error); free(dd); return FALSE; } dbus_error_free(&error); if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { fprintf(stderr, "%s: dbus_bus_request_name reply is not " "primary owner\n", getProgramName()); /* dbus_connection_unref (dd->connection); */ free(dd); return FALSE; } status = dbus_connection_add_filter(dd->connection, dbusHandleMessage, d, NULL); if (!status) { fprintf(stderr, "%s: dbus_connection_add_filter failed\n", getProgramName()); /* dbus_connection_unref (dd->connection); */ free(dd); return FALSE; } status = dbus_connection_get_unix_fd(dd->connection, &fd); if (!status) { fprintf(stderr, "%s: dbus_connection_get_unix_fd failed\n", getProgramName()); /* dbus_connection_unref (dd->connection); */ free(dd); return FALSE; } dd->watchFdHandle = compAddWatchFd(fd, POLLIN | POLLPRI | POLLHUP | POLLERR, dbusProcessMessages, d); WRAP(dd, d, setDisplayOption, dbusSetDisplayOption); WRAP(dd, d, setDisplayOptionForPlugin, dbusSetDisplayOptionForPlugin); d->privates[displayPrivateIndex].ptr = dd; return TRUE; } static void dbusFiniDisplay(CompPlugin * p, CompDisplay * d) { DBUS_DISPLAY(d); compRemoveWatchFd(dd->watchFdHandle); dbus_bus_release_name(dd->connection, BERYL_DBUS_SERVICE_NAME, NULL); /* can't unref the connection returned by dbus_bus_get as it's shared and we can't know if it's closed or not. dbus_connection_unref (dd->connection); */ UNWRAP(dd, d, setDisplayOption); UNWRAP(dd, d, setDisplayOptionForPlugin); free(dd); } static Bool dbusInitScreen(CompPlugin * p, CompScreen * s) { DbusScreen *ds; DBUS_DISPLAY(s->display); ds = malloc(sizeof(DbusScreen)); if (!ds) return FALSE; WRAP(ds, s, setScreenOption, dbusSetScreenOption); WRAP(ds, s, setScreenOptionForPlugin, dbusSetScreenOptionForPlugin); s->privates[dd->screenPrivateIndex].ptr = ds; return TRUE; } static void dbusFiniScreen(CompPlugin * p, CompScreen * s) { DBUS_SCREEN(s); UNWRAP(ds, s, setScreenOption); UNWRAP(ds, s, setScreenOptionForPlugin); free(ds); } static Bool dbusInit(CompPlugin * p) { displayPrivateIndex = allocateDisplayPrivateIndex(); if (displayPrivateIndex < 0) return FALSE; return TRUE; } static void dbusFini(CompPlugin * p) { if (displayPrivateIndex >= 0) freeDisplayPrivateIndex(displayPrivateIndex); } CompPluginVTable dbusVTable = { "dbus", "Dbus", "Dbus Control Backend", dbusInit, dbusFini, dbusInitDisplay, dbusFiniDisplay, dbusInitScreen, dbusFiniScreen, 0, /* InitWindow */ 0, /* FiniWindow */ 0, /* GetDisplayOptions */ 0, /* SetDisplayOption */ 0, /* GetScreenOptions */ 0, /* SetScreenOption */ 0, /* Deps */ 0, /* nDeps */ 0, /* Features */ 0, /* nFeatures */ BERYL_ABI_INFO, "beryl-dbus", "misc", 0, 0, True, }; CompPluginVTable *getCompPluginInfo(void) { return &dbusVTable; }