/*
* 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 <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_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 <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:
{
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;
}
syntax highlighted by Code2HTML, v. 0.9.1