summaryrefslogtreecommitdiff
path: root/beryl-plugins/src/dbus.c
diff options
context:
space:
mode:
authorplayerX <playerX@d7aaf104-2d23-0410-ae22-9d23157bf5a3>2007-01-18 01:04:10 +0000
committerplayerX <playerX@d7aaf104-2d23-0410-ae22-9d23157bf5a3>2007-01-18 01:04:10 +0000
commit3bace23ee9bae0fc5a026da3fc533f1cbb3bdfcb (patch)
tree39edc933a2662c2e3c193f98bdf53e2dd4b8b938 /beryl-plugins/src/dbus.c
parent1d06522cd005d312235b98ea30c25253d2526d12 (diff)
downloadmarex-dev-3bace23ee9bae0fc5a026da3fc533f1cbb3bdfcb.tar.gz
marex-dev-3bace23ee9bae0fc5a026da3fc533f1cbb3bdfcb.tar.bz2
beryl-plugins: Move dbus in.
git-svn-id: file:///beryl/trunk@2809 d7aaf104-2d23-0410-ae22-9d23157bf5a3
Diffstat (limited to 'beryl-plugins/src/dbus.c')
-rw-r--r--beryl-plugins/src/dbus.c1360
1 files changed, 1360 insertions, 0 deletions
diff --git a/beryl-plugins/src/dbus.c b/beryl-plugins/src/dbus.c
new file mode 100644
index 0000000..09bf362
--- /dev/null
+++ b/beryl-plugins/src/dbus.c
@@ -0,0 +1,1360 @@
+/*
+ * Copyright © 2006 Novell, 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. 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: David Reveman <davidr@novell.com>
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <poll.h>
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus.h>
+
+#include <beryl.h>
+
+#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_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);
+
+ 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 <Control><Alt>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:'<Control><Alt>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:
+ 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_append_args (reply,
+ DBUS_TYPE_STRING, &possible,
+ DBUS_TYPE_INVALID);
+ }
+ }
+ 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 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] || !path[3])
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (strcmp (path[0], "org") ||
+ strcmp (path[1], "freedesktop")||
+ strcmp (path[2], "beryl"))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (dbus_message_has_member (message, BERYL_DBUS_ACTIVATE_MEMBER_NAME) &&
+ path[5])
+ {
+ status = dbusHandleActionMessage (connection, message, d, &path[3],
+ TRUE);
+ }
+ else if (dbus_message_has_member (message,
+ BERYL_DBUS_DEACTIVATE_MEMBER_NAME) &&
+ path[5])
+ {
+ status = dbusHandleActionMessage (connection, message, d, &path[3],
+ FALSE);
+ }
+ else if (dbus_message_has_member (message, BERYL_DBUS_SET_MEMBER_NAME) &&
+ path[5])
+ {
+ status = dbusHandleSetOptionMessage (connection, message, d, &path[3]);
+ }
+ else if (dbus_message_has_member (message,
+ BERYL_DBUS_GET_MEMBER_NAME) && path[5])
+ {
+ 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]);
+ }
+ else if (dbus_message_has_member (message,
+ BERYL_DBUS_LIST_MEMBER_NAME))
+ {
+ status = dbusHandleListMessage (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;
+}