You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2597 lines
58 KiB

/*
* 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 <libxml/xmlwriter.h>
#include <compiz-core.h>
static CompMetadata dbusMetadata;
#define COMPIZ_DBUS_SERVICE_NAME "org.freedesktop.compiz"
#define COMPIZ_DBUS_INTERFACE "org.freedesktop.compiz"
#define COMPIZ_DBUS_ROOT_PATH "/org/freedesktop/compiz"
#define COMPIZ_DBUS_ACTIVATE_MEMBER_NAME "activate"
#define COMPIZ_DBUS_DEACTIVATE_MEMBER_NAME "deactivate"
#define COMPIZ_DBUS_SET_MEMBER_NAME "set"
#define COMPIZ_DBUS_GET_MEMBER_NAME "get"
#define COMPIZ_DBUS_GET_METADATA_MEMBER_NAME "getMetadata"
#define COMPIZ_DBUS_LIST_MEMBER_NAME "list"
#define COMPIZ_DBUS_GET_PLUGINS_MEMBER_NAME "getPlugins"
#define COMPIZ_DBUS_GET_PLUGIN_METADATA_MEMBER_NAME "getPluginMetadata"
#define COMPIZ_DBUS_CHANGED_SIGNAL_NAME "changed"
#define COMPIZ_DBUS_PLUGINS_CHANGED_SIGNAL_NAME "pluginsChanged"
#define DBUS_FILE_WATCH_CURRENT 0
#define DBUS_FILE_WATCH_PLUGIN 1
#define DBUS_FILE_WATCH_HOME 2
#define DBUS_FILE_WATCH_NUM 3
static int corePrivateIndex;
static int displayPrivateIndex;
typedef struct _DbusCore {
DBusConnection *connection;
CompWatchFdHandle watchFdHandle;
CompFileWatchHandle fileWatch[DBUS_FILE_WATCH_NUM];
InitPluginForObjectProc initPluginForObject;
SetOptionForPluginProc setOptionForPlugin;
} DbusCore;
typedef struct _DbusDisplay {
char **pluginList;
unsigned int nPlugins;
} DbusDisplay;
static DBusHandlerResult dbusHandleMessage (DBusConnection *,
DBusMessage *,
void *);
static DBusObjectPathVTable dbusMessagesVTable = {
NULL, dbusHandleMessage, /* handler function */
NULL, NULL, NULL, NULL
};
#define GET_DBUS_CORE(c) \
((DbusCore *) (c)->base.privates[corePrivateIndex].ptr)
#define DBUS_CORE(c) \
DbusCore *dc = GET_DBUS_CORE (c)
#define GET_DBUS_DISPLAY(d) \
((DbusDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
#define DBUS_DISPLAY(d) \
DbusDisplay *dd = GET_DBUS_DISPLAY (d)
static void
dbusUpdatePluginList (CompDisplay *d)
{
CompListValue *pl;
unsigned int i;
DBUS_DISPLAY (d);
pl = &d->opt[COMP_DISPLAY_OPTION_ACTIVE_PLUGINS].value.list;
for (i = 0; i < dd->nPlugins; i++)
free (dd->pluginList[i]);
dd->pluginList = realloc (dd->pluginList, pl->nValue * sizeof (char *));
if (!dd->pluginList)
{
dd->nPlugins = 0;
return;
}
for (i = 0; i < pl->nValue; i++)
dd->pluginList[i] = strdup (pl->value[i].s);
dd->nPlugins = pl->nValue;
}
static CompOption *
dbusGetOptionsFromPath (char **path,
CompObject **returnObject,
CompMetadata **returnMetadata,
int *nOption)
{
CompPlugin *p;
CompObject *object;
object = compObjectFind (&core.base, COMP_OBJECT_TYPE_DISPLAY, NULL);
if (!object)
return NULL;
if (strncmp (path[1], "screen", 6) == 0)
{
object = compObjectFind (object, COMP_OBJECT_TYPE_SCREEN,
path[1] + 6);
if (!object)
return NULL;
}
else if (strcmp (path[1], "allscreens") != 0)
{
return NULL;
}
if (returnObject)
*returnObject = object;
for (p = getPlugins (); p; p = p->next)
if (strcmp (p->vTable->name, path[0]) == 0)
break;
if (returnMetadata)
{
if (p && p->vTable->getMetadata)
*returnMetadata = (*p->vTable->getMetadata) (p);
else
*returnMetadata = NULL;
}
if (!p)
return NULL;
if (!p->vTable->getObjectOptions)
return NULL;
return (*p->vTable->getObjectOptions) (p, object, nOption);
}
/* functions to create introspection XML */
static void
dbusIntrospectStartInterface (xmlTextWriterPtr writer)
{
xmlTextWriterStartElement (writer, BAD_CAST "interface");
xmlTextWriterWriteAttribute (writer, BAD_CAST "name",
BAD_CAST COMPIZ_DBUS_SERVICE_NAME);
}
static void
dbusIntrospectEndInterface (xmlTextWriterPtr writer)
{
xmlTextWriterEndElement (writer);
}
static void
dbusIntrospectAddArgument (xmlTextWriterPtr writer,
char *type,
char *direction)
{
xmlTextWriterStartElement (writer, BAD_CAST "arg");
xmlTextWriterWriteAttribute (writer, BAD_CAST "type", BAD_CAST type);
xmlTextWriterWriteAttribute (writer, BAD_CAST "direction",
BAD_CAST direction);
xmlTextWriterEndElement (writer);
}
static void
dbusIntrospectAddMethod (xmlTextWriterPtr writer,
char *name,
int nArgs,
...)
{
va_list var_args;
char *type, *direction;
xmlTextWriterStartElement (writer, BAD_CAST "method");
xmlTextWriterWriteAttribute (writer, BAD_CAST "name", BAD_CAST name);
va_start (var_args, nArgs);
while (nArgs)
{
type = va_arg (var_args, char *);
direction = va_arg (var_args, char *);
dbusIntrospectAddArgument (writer, type, direction);
nArgs--;
}
va_end (var_args);
xmlTextWriterEndElement (writer);
}
static void
dbusIntrospectAddSignal (xmlTextWriterPtr writer,
char *name,
int nArgs,
...)
{
va_list var_args;
char *type;
xmlTextWriterStartElement (writer, BAD_CAST "signal");
xmlTextWriterWriteAttribute (writer, BAD_CAST "name", BAD_CAST name);
va_start (var_args, nArgs);
while (nArgs)
{
type = va_arg (var_args, char *);
dbusIntrospectAddArgument (writer, type, "out");
nArgs--;
}
va_end (var_args);
xmlTextWriterEndElement (writer);
}
static void
dbusIntrospectAddNode (xmlTextWriterPtr writer,
char *name)
{
xmlTextWriterStartElement (writer, BAD_CAST "node");
xmlTextWriterWriteAttribute (writer, BAD_CAST "name", BAD_CAST name);
xmlTextWriterEndElement (writer);
}
static void
dbusIntrospectStartRoot (xmlTextWriterPtr writer)
{
xmlTextWriterStartElement (writer, BAD_CAST "node");
xmlTextWriterStartElement (writer, BAD_CAST "interface");
xmlTextWriterWriteAttribute (writer, BAD_CAST "name",
BAD_CAST "org.freedesktop.DBus.Introspectable");
dbusIntrospectAddMethod (writer, "Introspect", 1, "s", "out");
xmlTextWriterEndElement (writer);
}
static void
dbusIntrospectEndRoot (xmlTextWriterPtr writer)
{
xmlTextWriterEndDocument (writer);
}
/* introspection handlers */
static Bool
dbusHandleRootIntrospectMessage (DBusConnection *connection,
DBusMessage *message)
{
char **plugins, **pluginName;
int nPlugins;
xmlTextWriterPtr writer;
xmlBufferPtr buf;
buf = xmlBufferCreate ();
writer = xmlNewTextWriterMemory (buf, 0);
dbusIntrospectStartRoot (writer);
dbusIntrospectStartInterface (writer);
dbusIntrospectAddMethod (writer, COMPIZ_DBUS_GET_PLUGINS_MEMBER_NAME, 1,
"as", "out");
dbusIntrospectAddMethod (writer,
COMPIZ_DBUS_GET_PLUGIN_METADATA_MEMBER_NAME, 7,
"s", "in", "s", "out", "s", "out", "s", "out",
"b", "out", "as", "out", "as", "out");
dbusIntrospectAddSignal (writer,
COMPIZ_DBUS_PLUGINS_CHANGED_SIGNAL_NAME, 0);
dbusIntrospectEndInterface (writer);
plugins = availablePlugins (&nPlugins);
if (plugins)
{
pluginName = plugins;
while (nPlugins--)
{
dbusIntrospectAddNode (writer, *pluginName);
free (*pluginName);
pluginName++;
}
free (plugins);
}
else
{
xmlFreeTextWriter (writer);
xmlBufferFree (buf);
return FALSE;
}
dbusIntrospectEndRoot (writer);
xmlFreeTextWriter (writer);
DBusMessage *reply = dbus_message_new_method_return (message);
if (!reply)
{
xmlBufferFree (buf);
return FALSE;
}
DBusMessageIter args;
dbus_message_iter_init_append (reply, &args);
if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING,
&buf->content))
{
xmlBufferFree (buf);
return FALSE;
}
xmlBufferFree (buf);
if (!dbus_connection_send (connection, reply, NULL))
{
return FALSE;
}
dbus_connection_flush (connection);
dbus_message_unref (reply);
return TRUE;
}
/* MULTIDPYERROR: only works with one or less displays present */
static Bool
dbusHandlePluginIntrospectMessage (DBusConnection *connection,
DBusMessage *message,
char **path)
{
CompDisplay *d;
CompScreen *s;
char screenName[256];
xmlTextWriterPtr writer;
xmlBufferPtr buf;
buf = xmlBufferCreate ();
writer = xmlNewTextWriterMemory (buf, 0);
dbusIntrospectStartRoot (writer);
for (d = core.displays; d; d = d->next)
{
dbusIntrospectAddNode (writer, "allscreens");
for (s = d->screens; s; s = s->next)
{
sprintf (screenName, "screen%d", s->screenNum);
dbusIntrospectAddNode (writer, screenName);
}
}
dbusIntrospectEndRoot (writer);
xmlFreeTextWriter (writer);
DBusMessage *reply = dbus_message_new_method_return (message);
if (!reply)
{
xmlBufferFree (buf);
return FALSE;
}
DBusMessageIter args;
dbus_message_iter_init_append (reply, &args);
if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING,
&buf->content))
{
xmlBufferFree (buf);
return FALSE;
}
xmlBufferFree (buf);
if (!dbus_connection_send (connection, reply, NULL))
{
return FALSE;
}
dbus_connection_flush (connection);
dbus_message_unref (reply);
return TRUE;
}
static Bool
dbusHandleScreenIntrospectMessage (DBusConnection *connection,
DBusMessage *message,
char **path)
{
CompOption *option = NULL;
int nOptions;
xmlTextWriterPtr writer;
xmlBufferPtr buf;
buf = xmlBufferCreate ();
writer = xmlNewTextWriterMemory (buf, 0);
dbusIntrospectStartRoot (writer);
dbusIntrospectStartInterface (writer);
dbusIntrospectAddMethod (writer, COMPIZ_DBUS_LIST_MEMBER_NAME, 1,
"as", "out");
dbusIntrospectEndInterface (writer);
option = dbusGetOptionsFromPath (path, NULL, NULL, &nOptions);
if (option)
{
while (nOptions--)
{
dbusIntrospectAddNode (writer, option->name);
option++;
}
}
dbusIntrospectEndRoot (writer);
xmlFreeTextWriter (writer);
DBusMessage *reply = dbus_message_new_method_return (message);
if (!reply)
{
xmlBufferFree (buf);
return FALSE;
}
DBusMessageIter args;
dbus_message_iter_init_append (reply, &args);
if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING,
&buf->content))
{
xmlBufferFree (buf);
return FALSE;
}
xmlBufferFree (buf);
if (!dbus_connection_send (connection, reply, NULL))
{
return FALSE;
}
dbus_connection_flush (connection);
dbus_message_unref (reply);
return TRUE;
}
static Bool
dbusHandleOptionIntrospectMessage (DBusConnection *connection,
DBusMessage *message,
char **path)
{
CompOption *option;
int nOptions;
CompOptionType restrictionType;
Bool metadataHandled;
char type[3];
xmlTextWriterPtr writer;
xmlBufferPtr buf;
Bool isList = FALSE;
buf = xmlBufferCreate ();
writer = xmlNewTextWriterMemory (buf, 0);
dbusIntrospectStartRoot (writer);
dbusIntrospectStartInterface (writer);
option = dbusGetOptionsFromPath (path, NULL, NULL, &nOptions);
if (!option)
{
xmlFreeTextWriter (writer);
xmlBufferFree (buf);
return FALSE;
}
while (nOptions--)
{
if (strcmp (option->name, path[2]) == 0)
{
restrictionType = option->type;
if (restrictionType == CompOptionTypeList)
{
restrictionType = option->value.list.type;
isList = TRUE;
}
metadataHandled = FALSE;
switch (restrictionType)
{
case CompOptionTypeInt:
if (isList)
strcpy (type, "ai");
else
strcpy (type, "i");
dbusIntrospectAddMethod (writer,
COMPIZ_DBUS_GET_METADATA_MEMBER_NAME,
6, "s", "out", "s", "out",
"b", "out", "s", "out",
"i", "out", "i", "out");
metadataHandled = TRUE;
break;
case CompOptionTypeFloat:
if (isList)
strcpy (type, "ad");
else
strcpy (type, "d");
dbusIntrospectAddMethod (writer,
COMPIZ_DBUS_GET_METADATA_MEMBER_NAME,
7, "s", "out", "s", "out",
"b", "out", "s", "out",
"d", "out", "d", "out",
"d", "out");
metadataHandled = TRUE;
break;
case CompOptionTypeString:
if (isList)
strcpy (type, "as");
else
strcpy (type, "s");
dbusIntrospectAddMethod (writer,
COMPIZ_DBUS_GET_METADATA_MEMBER_NAME,
5, "s", "out", "s", "out",
"b", "out", "s", "out",
"as", "out");
metadataHandled = TRUE;
break;
case CompOptionTypeBool:
case CompOptionTypeBell:
if (isList)
strcpy (type, "ab");
else
strcpy (type, "b");
break;
case CompOptionTypeColor:
case CompOptionTypeKey:
case CompOptionTypeButton:
case CompOptionTypeEdge:
case CompOptionTypeMatch:
if (isList)
strcpy (type, "as");
else
strcpy (type, "s");
break;
default:
continue;
}
dbusIntrospectAddMethod (writer,
COMPIZ_DBUS_GET_MEMBER_NAME, 1,
type, "out");
dbusIntrospectAddMethod (writer,
COMPIZ_DBUS_SET_MEMBER_NAME, 1,
type, "in");
dbusIntrospectAddSignal (writer,
COMPIZ_DBUS_CHANGED_SIGNAL_NAME, 1,
type, "out");
if (!metadataHandled)
dbusIntrospectAddMethod (writer,
COMPIZ_DBUS_GET_METADATA_MEMBER_NAME,
4, "s", "out", "s", "out",
"b", "out", "s", "out");
break;
}
option++;
}
dbusIntrospectEndInterface (writer);
dbusIntrospectEndRoot (writer);
xmlFreeTextWriter (writer);
DBusMessage *reply = dbus_message_new_method_return (message);
if (!reply)
{
xmlBufferFree (buf);
return FALSE;
}
DBusMessageIter args;
dbus_message_iter_init_append (reply, &args);
if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING,
&buf->content))
{
xmlBufferFree (buf);
return FALSE;
}
xmlBufferFree (buf);
if (!dbus_connection_send (connection, reply, NULL))
{
return FALSE;
}
dbus_connection_flush (connection);
dbus_message_unref (reply);
return TRUE;
}
/*
* 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.compiz \
* /org/freedesktop/compiz/rotate/allscreens/rotate_to \
* org.freedesktop.compiz.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.compiz \
* /org/freedesktop/compiz/cube/allscreens/unfold \
* org.freedesktop.compiz.activate \
* string:'root' \
* int32:`xwininfo -root | grep id: | awk '{ print $4 }'`
*
* dbus-send --type=method_call --dest=org.freedesktop.compiz \
* /org/freedesktop/compiz/cube/allscreens/unfold \
* org.freedesktop.compiz.deactivate \
* string:'root' \
* int32:`xwininfo -root | grep id: | awk '{ print $4 }'`
*
*/
static Bool
dbusHandleActionMessage (DBusConnection *connection,
DBusMessage *message,
char **path,
Bool activate)
{
CompObject *object;
CompOption *option;
int nOption;
option = dbusGetOptionsFromPath (path, &object, NULL, &nOption);
if (!option)
return FALSE;
while (nOption--)
{
if (strcmp (option->name, path[2]) == 0)
{
CompOption *argument = NULL;
int i, nArgument = 0;
DBusMessageIter iter;
if (!isActionOption (option))
return FALSE;
while (object && object->type != COMP_OBJECT_TYPE_DISPLAY)
object = object->parent;
if (!object)
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;
/* XXX: use match option type if name is "match" */
if (name && strcmp (name, "match") == 0)
{
char *s;
type = CompOptionTypeMatch;
dbus_message_iter_get_basic (&iter, &s);
matchInit (&value.match);
matchAddFromString (&value.match, s);
}
else
{
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) (GET_CORE_DISPLAY (object),
&option->value.action,
0,
argument, nArgument);
}
else
{
(*option->value.action.terminate) (GET_CORE_DISPLAY (object),
&option->value.action,
0,
argument, nArgument);
}
for (i = 0; i < nArgument; i++)
if (argument[i].type == CompOptionTypeMatch)
matchFini (&argument[i].value.match);
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 (CompObject *object,
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;
}
break;
case CompOptionTypeKey:
if (dbusTryGetValueWithType (iter,
DBUS_TYPE_STRING,
&s))
{
while (object && object->type != COMP_OBJECT_TYPE_DISPLAY)
object = object->parent;
if (!object)
return FALSE;
stringToKeyAction (GET_CORE_DISPLAY (object), s, &value->action);
return TRUE;
}
break;
case CompOptionTypeButton:
if (dbusTryGetValueWithType (iter,
DBUS_TYPE_STRING,
&s))
{
while (object && object->type != COMP_OBJECT_TYPE_DISPLAY)
object = object->parent;
if (!object)
return FALSE;
stringToButtonAction (GET_CORE_DISPLAY (object),
s, &value->action);
return TRUE;
}
break;
case CompOptionTypeEdge:
if (dbusTryGetValueWithType (iter,
DBUS_TYPE_STRING,
&s))
{
value->action.edgeMask = stringToEdgeMask (s);
return TRUE;
}
break;
case CompOptionTypeBell:
return dbusTryGetValueWithType (iter,
DBUS_TYPE_BOOLEAN,
&value->action.bell);
break;
case CompOptionTypeMatch:
if (dbusTryGetValueWithType (iter,
DBUS_TYPE_STRING,
&s))
{
matchAddFromString (&value->match, s);
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.compiz \
* /org/freedesktop/compiz/core/allscreens/command0 \
* org.freedesktop.compiz.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.compiz \
* /org/freedesktop/compiz/core/allscreens/active_plugins \
* org.freedesktop.compiz.set \
* array:string:'dbus','decoration','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.compiz \
* /org/freedesktop/compiz/core/allscreens/run_command0 \
* org.freedesktop.compiz.set \
* string:'<Control><Alt>Return' \
* string:'Disabled' \
* boolean:'false' \
* string:'' \
* int32:'0'
*/
static Bool
dbusHandleSetOptionMessage (DBusConnection *connection,
DBusMessage *message,
char **path)
{
CompObject *object;
CompOption *option;
int nOption;
option = dbusGetOptionsFromPath (path, &object, NULL, &nOption);
if (!option)
return FALSE;
while (nOption--)
{
if (strcmp (option->name, path[2]) == 0)
{
DBusMessageIter iter, aiter;
CompOptionValue value, tmpValue;
Bool status = FALSE;
memset (&value, 0, sizeof (value));
if (option->type == CompOptionTypeList)
{
if (dbus_message_iter_init (message, &iter) &&
dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_ARRAY)
{
dbus_message_iter_recurse (&iter, &aiter);
do
{
memset (&tmpValue, 0, sizeof (tmpValue));
if (dbusGetOptionValue (object,
&aiter,
option->value.list.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;
}
}
} while (dbus_message_iter_next (&aiter));
status = TRUE;
}
}
else if (dbus_message_iter_init (message, &iter))
{
status = dbusGetOptionValue (object, &iter, option->type,
&value);
}
if (status)
{
(*core.setOptionForPlugin) (object,
path[0],
option->name,
&value);
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;
}
else
{
return FALSE;
}
}
option++;
}
return FALSE;
}
static void
dbusAppendSimpleOptionValue (CompObject *object,
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);
}
break;
case CompOptionTypeKey:
s = keyActionToString ((CompDisplay *) object, &value->action);
if (s)
{
dbus_message_append_args (message,
DBUS_TYPE_STRING, &s,
DBUS_TYPE_INVALID);
free (s);
}
break;
case CompOptionTypeButton:
s = buttonActionToString ((CompDisplay *) object, &value->action);
if (s)
{
dbus_message_append_args (message,
DBUS_TYPE_STRING, &s,
DBUS_TYPE_INVALID);
free (s);
}
break;
case CompOptionTypeEdge:
s = edgeMaskToString (value->action.edgeMask);
if (s)
{
dbus_message_append_args (message,
DBUS_TYPE_STRING, &s,
DBUS_TYPE_INVALID);
free (s);
}
break;
case CompOptionTypeBell:
dbus_message_append_args (message,
DBUS_TYPE_BOOLEAN, &value->action.bell,
DBUS_TYPE_INVALID);
break;
case CompOptionTypeMatch:
s = matchToString (&value->match);
if (s)
{
dbus_message_append_args (message,
DBUS_TYPE_STRING, &s,
DBUS_TYPE_INVALID);
free (s);
}
default:
break;
}
}
static void
dbusAppendListOptionValue (CompObject *object,
DBusMessage *message,
CompOptionType type,
CompOptionValue *value)
{
DBusMessageIter iter;
DBusMessageIter listIter;
char sig[2];
char *s;
int i;
switch (value->list.type) {
case CompOptionTypeInt:
sig[0] = DBUS_TYPE_INT32;
break;
case CompOptionTypeFloat:
sig[0] = DBUS_TYPE_DOUBLE;
break;
case CompOptionTypeBool:
case CompOptionTypeBell:
sig[0] = DBUS_TYPE_BOOLEAN;
break;
default:
sig[0] = DBUS_TYPE_STRING;
break;
}
sig[1] = '\0';
dbus_message_iter_init_append (message, &iter);
if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY,
sig, &listIter))
return;
for (i = 0; i < value->list.nValue; i++)
{
switch (value->list.type) {
case CompOptionTypeInt:
dbus_message_iter_append_basic (&listIter,
sig[0],
&value->list.value[i].i);
break;
case CompOptionTypeFloat:
dbus_message_iter_append_basic (&listIter,
sig[0],
&value->list.value[i].f);
break;
case CompOptionTypeBool:
dbus_message_iter_append_basic (&listIter,
sig[0],
&value->list.value[i].b);
break;
case CompOptionTypeString:
dbus_message_iter_append_basic (&listIter,
sig[0],
&value->list.value[i].s);
break;
case CompOptionTypeKey:
s = keyActionToString ((CompDisplay *) object,
&value->list.value[i].action);
if (s)
{
dbus_message_iter_append_basic (&listIter, sig[0], &s);
free (s);
}
break;
case CompOptionTypeButton:
s = buttonActionToString ((CompDisplay *) object,
&value->list.value[i].action);
if (s)
{
dbus_message_iter_append_basic (&listIter, sig[0], &s);
free (s);
}
break;
case CompOptionTypeEdge:
s = edgeMaskToString (value->list.value[i].action.edgeMask);
if (s)
{
dbus_message_iter_append_basic (&listIter, sig[0], &s);
free (s);
}
break;
case CompOptionTypeBell:
dbus_message_iter_append_basic (&listIter,
sig[0],
&value->list.value[i].action.bell);
break;
case CompOptionTypeMatch:
s = matchToString (&value->list.value[i].match);
if (s)
{
dbus_message_iter_append_basic (&listIter, sig[0], &s);
free (s);
}
break;
case CompOptionTypeColor:
s = colorToString (value->list.value[i].c);
if (s)
{
dbus_message_iter_append_basic (&listIter, sig[0], &s);
free (s);
}
break;
default:
break;
}
}
dbus_message_iter_close_container (&iter, &listIter);
}
static void
dbusAppendOptionValue (CompObject *object,
DBusMessage *message,
CompOptionType type,
CompOptionValue *value)
{
if (type == CompOptionTypeList)
{
dbusAppendListOptionValue (object, message, type, value);
}
else
{
dbusAppendSimpleOptionValue (object, 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.compiz \
* /org/freedesktop/compiz/core/allscreens/command0 \
* org.freedesktop.compiz.get
*/
static Bool
dbusHandleGetOptionMessage (DBusConnection *connection,
DBusMessage *message,
char **path)
{
CompObject *object;
CompOption *option;
int nOption = 0;
DBusMessage *reply = NULL;
option = dbusGetOptionsFromPath (path, &object, NULL, &nOption);
while (nOption--)
{
if (strcmp (option->name, path[2]) == 0)
{
reply = dbus_message_new_method_return (message);
dbusAppendOptionValue (object, 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;
}
/*
* 'List' can be used to retrieve a list of available options.
*
* Example:
*
* dbus-send --print-reply --type=method_call \
* --dest=org.freedesktop.compiz \
* /org/freedesktop/compiz/core/allscreens \
* org.freedesktop.compiz.list
*/
static Bool
dbusHandleListMessage (DBusConnection *connection,
DBusMessage *message,
char **path)
{
CompObject *object;
CompOption *option;
int nOption = 0;
DBusMessage *reply;
option = dbusGetOptionsFromPath (path, &object, NULL, &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;
}
/*
* 'GetMetadata' can be used to retrieve metadata for an option.
*
* Example:
*
* dbus-send --print-reply --type=method_call \
* --dest=org.freedesktop.compiz \
* /org/freedesktop/compiz/core/allscreens/run_command0 \
* org.freedesktop.compiz.getMetadata
*/
static Bool
dbusHandleGetMetadataMessage (DBusConnection *connection,
DBusMessage *message,
char **path)
{
CompObject *object;
CompOption *option;
int nOption = 0;
DBusMessage *reply = NULL;
CompMetadata *m;
option = dbusGetOptionsFromPath (path, &object, &m, &nOption);
while (nOption--)
{
if (strcmp (option->name, path[2]) == 0)
{
CompOptionType restrictionType = option->type;
const char *type;
char *shortDesc = NULL;
char *longDesc = NULL;
const char *blankStr = "";
reply = dbus_message_new_method_return (message);
type = optionTypeToString (option->type);
if (m)
{
if (object->type == COMP_OBJECT_TYPE_SCREEN)
{
shortDesc = compGetShortScreenOptionDescription (m, option);
longDesc = compGetLongScreenOptionDescription (m, option);
}
else
{
shortDesc =
compGetShortDisplayOptionDescription (m, option);
longDesc = compGetLongDisplayOptionDescription (m, option);
}
}
if (shortDesc)
dbus_message_append_args (reply,
DBUS_TYPE_STRING, &shortDesc,
DBUS_TYPE_INVALID);
else
dbus_message_append_args (reply,
DBUS_TYPE_STRING, &blankStr,
DBUS_TYPE_INVALID);
if (longDesc)
dbus_message_append_args (reply,
DBUS_TYPE_STRING, &longDesc,
DBUS_TYPE_INVALID);
else
dbus_message_append_args (reply,
DBUS_TYPE_STRING, &blankStr,
DBUS_TYPE_INVALID);
dbus_message_append_args (reply,
DBUS_TYPE_STRING, &type,
DBUS_TYPE_INVALID);
if (shortDesc)
free (shortDesc);
if (longDesc)
free (longDesc);
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;
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;
}
/*
* 'GetPlugins' can be used to retrieve a list of available plugins. There's
* no guarantee that a plugin in this list can actually be loaded.
*
* Example:
*
* dbus-send --print-reply --type=method_call \
* --dest=org.freedesktop.compiz \
* /org/freedesktop/compiz \
* org.freedesktop.compiz.getPlugins
*/
static Bool
dbusHandleGetPluginsMessage (DBusConnection *connection,
DBusMessage *message)
{
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);
dbus_message_unref (reply);
return TRUE;
}
/*
* 'GetPluginMetadata' can be used to retrieve metadata for a plugin.
*
* Example:
*
* dbus-send --print-reply --type=method_call \
* --dest=org.freedesktop.compiz \
* /org/freedesktop/compiz \
* org.freedesktop.compiz.getPluginMetadata \
* string:'png'
*/
static Bool
dbusHandleGetPluginMetadataMessage (DBusConnection *connection,
DBusMessage *message)
{
DBusMessage *reply;
DBusMessageIter iter;
char *name;
CompPlugin *p, *loadedPlugin = NULL;
if (!dbus_message_iter_init (message, &iter))
return FALSE;
if (!dbusTryGetValueWithType (&iter,
DBUS_TYPE_STRING,
&name))
return FALSE;
p = findActivePlugin (name);
if (!p)
p = loadedPlugin = loadPlugin (name);
if (p)
{
Bool initializedPlugin = TRUE;
char *shortDesc = NULL;
char *longDesc = NULL;
const char *blankStr = "";
reply = dbus_message_new_method_return (message);
if (loadedPlugin)
{
if (!(*p->vTable->init) (p))
initializedPlugin = FALSE;
}
if (initializedPlugin && p->vTable->getMetadata)
{
CompMetadata *m;
m = (*p->vTable->getMetadata) (p);
if (m)
{
shortDesc = compGetShortPluginDescription (m);
longDesc = compGetLongPluginDescription (m);
}
}
dbus_message_append_args (reply,
DBUS_TYPE_STRING, &p->vTable->name,
DBUS_TYPE_INVALID);
if (shortDesc)
dbus_message_append_args (reply,
DBUS_TYPE_STRING, &shortDesc,
DBUS_TYPE_INVALID);
else
dbus_message_append_args (reply,
DBUS_TYPE_STRING, &blankStr,
DBUS_TYPE_INVALID);
if (longDesc)
dbus_message_append_args (reply,
DBUS_TYPE_STRING, &longDesc,
DBUS_TYPE_INVALID);
else
dbus_message_append_args (reply,
DBUS_TYPE_STRING, &blankStr,
DBUS_TYPE_INVALID);
dbus_message_append_args (reply,
DBUS_TYPE_BOOLEAN, &initializedPlugin,
DBUS_TYPE_INVALID);
if (shortDesc)
free (shortDesc);
if (longDesc)
free (longDesc);
if (loadedPlugin && initializedPlugin)
(*p->vTable->fini) (p);
}
else
{
char *str;
str = malloc (strlen (name) + 256);
if (!str)
return FALSE;
sprintf (str, "Plugin '%s' could not be loaded", name);
reply = dbus_message_new_error (message,
DBUS_ERROR_FAILED,
str);
free (str);
}
if (loadedPlugin)
unloadPlugin (loadedPlugin);
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)
{
Bool status = FALSE;
char **path;
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;
}
/* root messages */
if (!path[3])
{
if (dbus_message_is_method_call (message,
DBUS_INTERFACE_INTROSPECTABLE,
"Introspect"))
{
if (dbusHandleRootIntrospectMessage (connection, message))
{
dbus_free_string_array (path);
return DBUS_HANDLER_RESULT_HANDLED;
}
}
else if (dbus_message_is_method_call (message, COMPIZ_DBUS_INTERFACE,
COMPIZ_DBUS_GET_PLUGIN_METADATA_MEMBER_NAME))
{
if (dbusHandleGetPluginMetadataMessage (connection, message))
{
dbus_free_string_array (path);
return DBUS_HANDLER_RESULT_HANDLED;
}
}
else if (dbus_message_is_method_call (message, COMPIZ_DBUS_INTERFACE,
COMPIZ_DBUS_GET_PLUGINS_MEMBER_NAME))
{
if (dbusHandleGetPluginsMessage (connection, message))
{
dbus_free_string_array (path);
return DBUS_HANDLER_RESULT_HANDLED;
}
}
dbus_free_string_array (path);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
/* plugin message */
else if (!path[4])
{
if (dbus_message_is_method_call (message,
DBUS_INTERFACE_INTROSPECTABLE,
"Introspect"))
{
if (dbusHandlePluginIntrospectMessage (connection, message,
&path[3]))
{
dbus_free_string_array (path);
return DBUS_HANDLER_RESULT_HANDLED;
}
}
dbus_free_string_array (path);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
/* screen message */
else if (!path[5])
{
if (dbus_message_is_method_call (message,
DBUS_INTERFACE_INTROSPECTABLE,
"Introspect"))
{
if (dbusHandleScreenIntrospectMessage (connection, message,
&path[3]))
{
dbus_free_string_array (path);
return DBUS_HANDLER_RESULT_HANDLED;
}
}
else if (dbus_message_is_method_call (message, COMPIZ_DBUS_INTERFACE,
COMPIZ_DBUS_LIST_MEMBER_NAME))
{
if (dbusHandleListMessage (connection, message, &path[3]))
{
dbus_free_string_array (path);
return DBUS_HANDLER_RESULT_HANDLED;
}
}
dbus_free_string_array (path);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
/* option message */
if (dbus_message_is_method_call (message, DBUS_INTERFACE_INTROSPECTABLE,
"Introspect"))
{
status = dbusHandleOptionIntrospectMessage (connection, message,
&path[3]);
}
else if (dbus_message_is_method_call (message, COMPIZ_DBUS_INTERFACE,
COMPIZ_DBUS_ACTIVATE_MEMBER_NAME))
{
status = dbusHandleActionMessage (connection, message, &path[3], TRUE);
}
else if (dbus_message_is_method_call (message, COMPIZ_DBUS_INTERFACE,
COMPIZ_DBUS_DEACTIVATE_MEMBER_NAME))
{
status = dbusHandleActionMessage (connection, message, &path[3],
FALSE);
}
else if (dbus_message_is_method_call (message, COMPIZ_DBUS_INTERFACE,
COMPIZ_DBUS_SET_MEMBER_NAME))
{
status = dbusHandleSetOptionMessage (connection, message, &path[3]);
}
else if (dbus_message_is_method_call (message, COMPIZ_DBUS_INTERFACE,
COMPIZ_DBUS_GET_MEMBER_NAME))
{
status = dbusHandleGetOptionMessage (connection, message, &path[3]);
}
else if (dbus_message_is_method_call (message, COMPIZ_DBUS_INTERFACE,
COMPIZ_DBUS_GET_METADATA_MEMBER_NAME))
{
status = dbusHandleGetMetadataMessage (connection, message, &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)
{
DBusDispatchStatus status;
DBUS_CORE (&core);
do
{
dbus_connection_read_write_dispatch (dc->connection, 0);
status = dbus_connection_get_dispatch_status (dc->connection);
}
while (status == DBUS_DISPATCH_DATA_REMAINS);
return TRUE;
}
static void
dbusSendChangeSignalForOption (CompObject *object,
CompOption *o,
const char *plugin)
{
DBusMessage *signal;
char *name, path[256];
DBUS_CORE (&core);
if (!o)
return;
name = compObjectName (object);
if (name)
{
sprintf (path, "%s/%s/%s%s/%s", COMPIZ_DBUS_ROOT_PATH,
plugin, compObjectTypeName (object->type), name, o->name);
free (name);
}
else
sprintf (path, "%s/%s/%s/%s", COMPIZ_DBUS_ROOT_PATH,
plugin, compObjectTypeName (object->type), o->name);
signal = dbus_message_new_signal (path,
COMPIZ_DBUS_SERVICE_NAME,
COMPIZ_DBUS_CHANGED_SIGNAL_NAME);
dbusAppendOptionValue (object, signal, o->type, &o->value);
dbus_connection_send (dc->connection, signal, NULL);
dbus_connection_flush (dc->connection);
dbus_message_unref (signal);
}
static Bool
dbusGetPathDecomposed (char *data,
char ***path,
int *count)
{
char **retval;
char *temp;
char *token;
int nComponents;
int i;
nComponents = 0;
if (strlen (data) > 1)
{
i = 0;
while (i < strlen (data))
{
if (data[i] == '/')
nComponents += 1;
++i;
}
}
retval = malloc (sizeof (char*) * (nComponents + 1));
if (nComponents == 0)
{
retval[0] = malloc (sizeof (char));
retval[0][0] = '\0';
*path = retval;
*count = 1;
return TRUE;
}
temp = strdup (data);
i = 0;
token = strtok (temp, "/");
while (token != NULL)
{
retval[i] = strdup (token);
token = strtok (NULL, "/");
i++;
}
retval[i] = malloc (sizeof (char));
retval[i][0] = '\0';
free (temp);
*path = retval;
*count = i + 1;
return TRUE;
}
static void
dbusFreePathDecomposed (char **path,
int count)
{
int i;
for (i = 0; i < count; i++)
free (path[i]);
free (path);
}
/* dbus registration */
static Bool
dbusRegisterOptions (DBusConnection *connection,
char *screenPath)
{
CompOption *option = NULL;
int nOptions;
char objectPath[256];
char **path;
int count;
dbusGetPathDecomposed (screenPath, &path, &count);
option = dbusGetOptionsFromPath (&path[3], NULL, NULL, &nOptions);
if (!option) {
dbusFreePathDecomposed (path, count);
return FALSE;
}
while (nOptions--)
{
snprintf (objectPath, 256, "%s/%s", screenPath, option->name);
dbus_connection_register_object_path (connection, objectPath,
&dbusMessagesVTable, 0);
option++;
}
dbusFreePathDecomposed (path, count);
return TRUE;
}
static Bool
dbusUnregisterOptions (DBusConnection *connection,
char *screenPath)
{
CompOption *option = NULL;
int nOptions;
char objectPath[256];
char **path;
int count;
dbusGetPathDecomposed (screenPath, &path, &count);
option = dbusGetOptionsFromPath (&path[3], NULL, NULL, &nOptions);
dbusFreePathDecomposed (path, count);
if (!option)
return FALSE;
while (nOptions--)
{
snprintf (objectPath, 256, "%s/%s", screenPath, option->name);
dbus_connection_unregister_object_path (connection, objectPath);
option++;
}
return TRUE;
}
static void
dbusRegisterPluginForDisplay (DBusConnection *connection,
CompDisplay *d,
char *pluginName)
{
char objectPath[256];
/* register plugin root path */
snprintf (objectPath, 256, "%s/%s", COMPIZ_DBUS_ROOT_PATH, pluginName);
dbus_connection_register_object_path (connection, objectPath,
&dbusMessagesVTable, d);
/* register plugin/screen path */
snprintf (objectPath, 256, "%s/%s/%s", COMPIZ_DBUS_ROOT_PATH,
pluginName, "allscreens");
dbus_connection_register_object_path (connection, objectPath,
&dbusMessagesVTable, d);
}
static void
dbusRegisterPluginForScreen (DBusConnection *connection,
CompScreen *s,
char *pluginName)
{
char objectPath[256];
/* register plugin/screen path */
snprintf (objectPath, 256, "%s/%s/screen%d", COMPIZ_DBUS_ROOT_PATH,
pluginName, s->screenNum);
dbus_connection_register_object_path (connection, objectPath,
&dbusMessagesVTable, s->display);
}
static void
dbusRegisterPluginsForDisplay (DBusConnection *connection,
CompDisplay *d)
{
unsigned int i;
char path[256];
DBUS_DISPLAY (d);
for (i = 0; i < dd->nPlugins; i++)
{
snprintf (path, 256, "%s/%s/allscreens",
COMPIZ_DBUS_ROOT_PATH, dd->pluginList[i]);
dbusRegisterPluginForDisplay (connection, d, dd->pluginList[i]);
dbusRegisterOptions (connection, path);
}
}
static void
dbusRegisterPluginsForScreen (DBusConnection *connection,
CompScreen *s)
{
unsigned int i;
char path[256];
DBUS_DISPLAY (s->display);
for (i = 0; i < dd->nPlugins; i++)
{
snprintf (path, 256, "%s/%s/screen%d",
COMPIZ_DBUS_ROOT_PATH, dd->pluginList[i], s->screenNum);
dbusRegisterPluginForScreen (connection, s, dd->pluginList[i]);
dbusRegisterOptions (connection, path);
}
}
static void
dbusUnregisterPluginForDisplay (DBusConnection *connection,
CompDisplay *d,
char *pluginName)
{
char objectPath[256];
snprintf (objectPath, 256, "%s/%s/%s", COMPIZ_DBUS_ROOT_PATH,
pluginName, "allscreens");
dbusUnregisterOptions (connection, objectPath);
dbus_connection_unregister_object_path (connection, objectPath);
snprintf (objectPath, 256, "%s/%s", COMPIZ_DBUS_ROOT_PATH, pluginName);
dbus_connection_unregister_object_path (connection, objectPath);
}
static void
dbusUnregisterPluginsForDisplay (DBusConnection *connection,
CompDisplay *d)
{
unsigned int i;
DBUS_DISPLAY (d);
for (i = 0; i < dd->nPlugins; i++)
dbusUnregisterPluginForDisplay (connection, d, dd->pluginList[i]);
}
static void
dbusUnregisterPluginForScreen (DBusConnection *connection,
CompScreen *s,
char *pluginName)
{
char objectPath[256];
snprintf (objectPath, 256, "%s/%s/screen%d", COMPIZ_DBUS_ROOT_PATH,
pluginName, s->screenNum);
dbusUnregisterOptions (connection, objectPath);
dbus_connection_unregister_object_path (connection, objectPath);
}
static void
dbusUnregisterPluginsForScreen (DBusConnection *connection,
CompScreen *s)
{
unsigned int i;
DBUS_DISPLAY (s->display);
for (i = 0; i < dd->nPlugins; i++)
dbusUnregisterPluginForScreen (connection, s, dd->pluginList[i]);
}
static CompBool
dbusInitPluginForDisplay (CompPlugin *p,
CompDisplay *d)
{
char objectPath[256];
DBUS_CORE (&core);
snprintf (objectPath, 256, "%s/%s/%s", COMPIZ_DBUS_ROOT_PATH,
p->vTable->name, "allscreens");
dbusRegisterOptions (dc->connection, objectPath);
return TRUE;
}
static Bool
dbusInitPluginForScreen (CompPlugin *p,
CompScreen *s)
{
char objectPath[256];
DBUS_CORE (&core);
snprintf (objectPath, 256, "%s/%s/screen%d", COMPIZ_DBUS_ROOT_PATH,
p->vTable->name, s->screenNum);
dbusRegisterOptions (dc->connection, objectPath);
return TRUE;
}
static CompBool
dbusInitPluginForObject (CompPlugin *p,
CompObject *o)
{
CompBool status;
DBUS_CORE (&core);
UNWRAP (dc, &core, initPluginForObject);
status = (*core.initPluginForObject) (p, o);
WRAP (dc, &core, initPluginForObject, dbusInitPluginForObject);
if (status && p->vTable->getObjectOptions)
{
static InitPluginForObjectProc dispTab[] = {
(InitPluginForObjectProc) 0, /* InitPluginForCore */
(InitPluginForObjectProc) dbusInitPluginForDisplay,
(InitPluginForObjectProc) dbusInitPluginForScreen
};
RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
}
return status;
}
static CompBool
dbusSetOptionForPlugin (CompObject *object,
const char *plugin,
const char *name,
CompOptionValue *value)
{
Bool status;
DBUS_CORE (&core);
UNWRAP (dc, &core, setOptionForPlugin);
status = (*core.setOptionForPlugin) (object, plugin, name, value);
WRAP (dc, &core, setOptionForPlugin, dbusSetOptionForPlugin);
if (status)
{
CompPlugin *p;
p = findActivePlugin (plugin);
if (p && p->vTable->getObjectOptions)
{
CompOption *option;
int nOption;
option = (*p->vTable->getObjectOptions) (p, object, &nOption);
dbusSendChangeSignalForOption (object,
compFindOption (option,
nOption,
name, 0),
p->vTable->name);
if (object->type == COMP_OBJECT_TYPE_DISPLAY &&
strcmp (p->vTable->name, "core") == 0 &&
strcmp (name, "active_plugins") == 0)
{
CompScreen *s;
CORE_DISPLAY (object);
dbusUnregisterPluginsForDisplay (dc->connection, d);
for (s = d->screens; s; s = s->next)
dbusUnregisterPluginsForScreen (dc->connection, s);
dbusUpdatePluginList (d);
dbusRegisterPluginsForDisplay (dc->connection, d);
for (s = d->screens; s; s = s->next)
dbusRegisterPluginsForScreen (dc->connection, s);
}
}
}
return status;
}
static void
dbusSendPluginsChangedSignal (const char *name,
void *closure)
{
DBusMessage *signal;
DBUS_CORE (&core);
signal = dbus_message_new_signal (COMPIZ_DBUS_ROOT_PATH,
COMPIZ_DBUS_SERVICE_NAME,
COMPIZ_DBUS_PLUGINS_CHANGED_SIGNAL_NAME);
dbus_connection_send (dc->connection, signal, NULL);
dbus_connection_flush (dc->connection);
dbus_message_unref (signal);
}
static Bool
dbusInitCore (CompPlugin *p,
CompCore *c)
{
DbusCore *dc;
DBusError error;
dbus_bool_t status;
int fd, ret, mask;
char *home, *plugindir;
if (!checkPluginABI ("core", CORE_ABIVERSION))
return FALSE;
dc = malloc (sizeof (DbusCore));
if (!dc)
return FALSE;
displayPrivateIndex = allocateDisplayPrivateIndex ();
if (displayPrivateIndex < 0)
{
free (dc);
return FALSE;
}
dbus_error_init (&error);
dc->connection = dbus_bus_get (DBUS_BUS_SESSION, &error);
if (dbus_error_is_set (&error))
{
compLogMessage ("dbus", CompLogLevelError,
"dbus_bus_get error: %s", error.message);
dbus_error_free (&error);
free (dc);
return FALSE;
}
ret = dbus_bus_request_name (dc->connection,
COMPIZ_DBUS_SERVICE_NAME,
DBUS_NAME_FLAG_REPLACE_EXISTING |
DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
&error);
if (dbus_error_is_set (&error))
{
compLogMessage ("dbus", CompLogLevelError,
"dbus_bus_request_name error: %s", error.message);
/* dbus_connection_unref (dc->connection); */
dbus_error_free (&error);
free (dc);
return FALSE;
}
dbus_error_free (&error);
if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
{
compLogMessage ("dbus", CompLogLevelError,
"dbus_bus_request_name reply is not primary owner");
/* dbus_connection_unref (dc->connection); */
free (dc);
return FALSE;
}
status = dbus_connection_get_unix_fd (dc->connection, &fd);
if (!status)
{
compLogMessage ("dbus", CompLogLevelError,
"dbus_connection_get_unix_fd failed");
/* dbus_connection_unref (dc->connection); */
free (dc);
return FALSE;
}
dc->watchFdHandle = compAddWatchFd (fd,
POLLIN | POLLPRI | POLLHUP | POLLERR,
dbusProcessMessages,
0);
mask = NOTIFY_CREATE_MASK | NOTIFY_DELETE_MASK | NOTIFY_MOVE_MASK;
dc->fileWatch[DBUS_FILE_WATCH_CURRENT] =
addFileWatch (".",
mask,
dbusSendPluginsChangedSignal,
0);
dc->fileWatch[DBUS_FILE_WATCH_PLUGIN] =
addFileWatch (PLUGINDIR,
mask,
dbusSendPluginsChangedSignal,
0);
dc->fileWatch[DBUS_FILE_WATCH_HOME] = 0;
home = getenv ("HOME");
if (home)
{
plugindir = malloc (strlen (home) + strlen (HOME_PLUGINDIR) + 3);
if (plugindir)
{
sprintf (plugindir, "%s/%s", home, HOME_PLUGINDIR);
dc->fileWatch[DBUS_FILE_WATCH_HOME] =
addFileWatch (plugindir,
mask,
dbusSendPluginsChangedSignal,
0);
free (plugindir);
}
}
WRAP (dc, c, initPluginForObject, dbusInitPluginForObject);
WRAP (dc, c, setOptionForPlugin, dbusSetOptionForPlugin);
c->base.privates[corePrivateIndex].ptr = dc;
/* register the objects */
dbus_connection_register_object_path (dc->connection,
COMPIZ_DBUS_ROOT_PATH,
&dbusMessagesVTable, 0);
return TRUE;
}
static void
dbusFiniCore (CompPlugin *p,
CompCore *c)
{
int i;
DBUS_CORE (c);
for (i = 0; i < DBUS_FILE_WATCH_NUM; i++)
removeFileWatch (dc->fileWatch[i]);
freeDisplayPrivateIndex (displayPrivateIndex);
compRemoveWatchFd (dc->watchFdHandle);
dbus_bus_release_name (dc->connection, COMPIZ_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 (dc->connection);
*/
UNWRAP (dc, c, initPluginForObject);
UNWRAP (dc, c, setOptionForPlugin);
free (dc);
}
static Bool
dbusInitDisplay (CompPlugin *p,
CompDisplay *d)
{
DbusDisplay *dd;
DBUS_CORE (&core);
dd = malloc (sizeof (DbusDisplay));
if (!dd)
return FALSE;
dd->pluginList = NULL;
dd->nPlugins = 0;
d->base.privates[displayPrivateIndex].ptr = dd;
dbusUpdatePluginList (d);
dbusRegisterPluginsForDisplay (dc->connection, d);
return TRUE;
}
static void
dbusFiniDisplay (CompPlugin *p,
CompDisplay *d)
{
DBUS_CORE (&core);
DBUS_DISPLAY (d);
dbusUnregisterPluginsForDisplay (dc->connection, d);
if (dd->pluginList)
{
unsigned int i;
for (i = 0; i < dd->nPlugins; i++)
free (dd->pluginList[i]);
free (dd->pluginList);
}
free (dd);
}
static Bool
dbusInitScreen (CompPlugin *p,
CompScreen *s)
{
DBUS_CORE (&core);
dbusRegisterPluginsForScreen (dc->connection, s);
return TRUE;
}
static void
dbusFiniScreen (CompPlugin *p,
CompScreen *s)
{
DBUS_CORE (&core);
dbusUnregisterPluginsForScreen (dc->connection, s);
}
static CompBool
dbusInitObject (CompPlugin *p,
CompObject *o)
{
static InitPluginObjectProc dispTab[] = {
(InitPluginObjectProc) dbusInitCore,
(InitPluginObjectProc) dbusInitDisplay,
(InitPluginObjectProc) dbusInitScreen
};
RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
}
static void
dbusFiniObject (CompPlugin *p,
CompObject *o)
{
static FiniPluginObjectProc dispTab[] = {
(FiniPluginObjectProc) dbusFiniCore,
(FiniPluginObjectProc) dbusFiniDisplay,
(FiniPluginObjectProc) dbusFiniScreen
};
DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
}
static Bool
dbusInit (CompPlugin *p)
{
if (!compInitPluginMetadataFromInfo (&dbusMetadata, p->vTable->name,
0, 0, 0, 0))
return FALSE;
corePrivateIndex = allocateCorePrivateIndex ();
if (corePrivateIndex < 0)
{
compFiniMetadata (&dbusMetadata);
return FALSE;
}
return TRUE;
}
static void
dbusFini (CompPlugin *p)
{
freeCorePrivateIndex (corePrivateIndex);
compFiniMetadata (&dbusMetadata);
}
static CompMetadata *
dbusGetMetadata (CompPlugin *plugin)
{
return &dbusMetadata;
}
CompPluginVTable dbusVTable = {
"dbus",
dbusGetMetadata,
dbusInit,
dbusFini,
dbusInitObject,
dbusFiniObject,
0, /* GetObjectOptions */
0 /* SetObjectOption */
};
CompPluginVTable *
getCompPluginInfo20070830 (void)
{
return &dbusVTable;
}