Logo Search packages:      
Sourcecode: beryl-plugins version File versions

dbus.c

/*
 * 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;
}

Generated by  Doxygen 1.6.0   Back to index