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.

845 lines
18 KiB

/*
* Compiz configuration system library plugin
*
* Copyright (C) 2007 Dennis Kasprzyk <onestone@opencompositing.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library 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
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define _GNU_SOURCE
#ifdef HAVE_CONFIG_H
# include "../config.h"
#endif
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <compiz-core.h>
#include <ccs.h>
static int corePrivateIndex;
static CompMetadata ccpMetadata;
typedef struct _CCPCore
{
CCSContext *context;
Bool applyingSettings;
CompTimeoutHandle timeoutHandle;
CompTimeoutHandle reloadHandle;
InitPluginForObjectProc initPluginForObject;
SetOptionForPluginProc setOptionForPlugin;
}
CCPCore;
#define GET_CCP_CORE(c) \
((CCPCore *) (c)->base.privates[corePrivateIndex].ptr)
#define CCP_CORE(c) \
CCPCore *cc = GET_CCP_CORE (c)
#define CCP_UPDATE_MIN_TIMEOUT 250
#define CCP_UPDATE_MAX_TIMEOUT 4000
#define CORE_VTABLE_NAME "core"
static void
ccpSetValueToValue (CompObject *object,
CCSSettingValue *sv,
CompOptionValue *v,
CCSSettingType type)
{
switch (type)
{
case TypeInt:
v->i = sv->value.asInt;
break;
case TypeFloat:
v->f = sv->value.asFloat;
break;
case TypeBool:
v->b = sv->value.asBool;
break;
case TypeColor:
{
int i;
for (i = 0; i < 4; i++)
v->c[i] = sv->value.asColor.array.array[i];
}
break;
case TypeString:
v->s = strdup (sv->value.asString);
break;
case TypeMatch:
matchInit (&v->match);
matchAddFromString (&v->match, sv->value.asMatch);
break;
case TypeKey:
{
CompDisplay *d;
while (object && object->type != COMP_OBJECT_TYPE_DISPLAY)
object = object->parent;
if (!object)
return;
d = GET_CORE_DISPLAY (object);
v->action.key.keycode =
(sv->value.asKey.keysym != NoSymbol) ?
XKeysymToKeycode (d->display, sv->value.asKey.keysym) : 0;
v->action.key.modifiers = sv->value.asKey.keyModMask;
if (v->action.key.keycode || v->action.key.modifiers)
v->action.type = CompBindingTypeKey;
else
v->action.type = CompBindingTypeNone;
}
break;
case TypeButton:
{
v->action.button.button = sv->value.asButton.button;
v->action.button.modifiers = sv->value.asButton.buttonModMask;
v->action.edgeMask = sv->value.asButton.edgeMask;
if (v->action.button.button || v->action.button.modifiers)
{
if (sv->value.asButton.edgeMask)
v->action.type = CompBindingTypeEdgeButton;
else
v->action.type = CompBindingTypeButton;
}
else
v->action.type = CompBindingTypeNone;
}
break;
case TypeEdge:
{
v->action.edgeMask = sv->value.asEdge;
}
break;
case TypeBell:
{
v->action.bell = sv->value.asBell;
}
break;
default:
break;
}
}
static CompOptionType
ccpCCSTypeToCompizType (CCSSettingType st, CompOptionType *ct)
{
switch (st) {
case TypeBool:
*ct = CompOptionTypeBool;
break;
case TypeInt:
*ct = CompOptionTypeInt;
break;
case TypeFloat:
*ct = CompOptionTypeFloat;
break;
case TypeColor:
*ct = CompOptionTypeColor;
break;
case TypeString:
*ct = CompOptionTypeString;
break;
case TypeMatch:
*ct = CompOptionTypeMatch;
break;
case TypeKey:
*ct = CompOptionTypeKey;
break;
case TypeButton:
*ct = CompOptionTypeButton;
break;
case TypeEdge:
*ct = CompOptionTypeEdge;
break;
case TypeBell:
*ct = CompOptionTypeBell;
break;
case TypeList:
*ct = CompOptionTypeList;
break;
default:
return FALSE;
}
return TRUE;
}
static void
ccpConvertPluginList (CCSSetting *s,
CCSSettingValueList list,
CompOptionValue *v)
{
CCSStringList sl, l;
int i;
sl = ccsGetStringListFromValueList (list);
while (ccsStringListFind(sl,"ccp"))
sl = ccsStringListRemove (sl, "ccp", TRUE);
while (ccsStringListFind(sl,"core"))
sl = ccsStringListRemove (sl, "core", TRUE);
sl = ccsStringListPrepend (sl, strdup ("ccp"));
sl = ccsStringListPrepend (sl, strdup ("core"));
v->list.nValue = ccsStringListLength (sl);
v->list.value = calloc (v->list.nValue, sizeof (CompOptionValue));
if (!v->list.value)
{
v->list.nValue = 0;
return;
}
for (l = sl, i = 0; l; l = l->next)
{
if (l->data)
v->list.value[i].s = strdup (l->data);
i++;
}
ccsStringListFree (sl, TRUE);
}
static void
ccpSettingToValue (CompObject *object,
CCSSetting *s,
CompOptionValue *v)
{
if (s->type != TypeList)
ccpSetValueToValue (object, s->value, v, s->type);
else
{
CCSSettingValueList list;
int i = 0;
ccsGetList (s, &list);
if (!ccpCCSTypeToCompizType (s->info.forList.listType, &v->list.type))
v->list.type = CompOptionTypeBool;
if ((strcmp (s->name, "active_plugins") == 0) &&
(strcmp (s->parent->name, CORE_VTABLE_NAME) == 0))
{
ccpConvertPluginList (s, list, v);
}
else
{
v->list.nValue = ccsSettingValueListLength (list);
v->list.value = calloc (v->list.nValue, sizeof (CompOptionValue));
while (list)
{
ccpSetValueToValue (object, list->data,
&v->list.value[i],
s->info.forList.listType);
list = list->next;
i++;
}
}
}
}
static void
ccpInitValue (CompObject *object,
CCSSettingValue *value,
CompOptionValue *from,
CCSSettingType type)
{
switch (type)
{
case TypeInt:
value->value.asInt = from->i;
break;
case TypeFloat:
value->value.asFloat = from->f;
break;
case TypeBool:
value->value.asBool = from->b;
break;
case TypeColor:
{
int i;
for (i = 0; i < 4; i++)
value->value.asColor.array.array[i] = from->c[i];
}
break;
case TypeString:
value->value.asString = strdup (from->s);
break;
case TypeMatch:
value->value.asMatch = matchToString (&from->match);
break;
case TypeKey:
if (from->action.type & CompBindingTypeKey)
{
CompDisplay *d;
while (object && object->type != COMP_OBJECT_TYPE_DISPLAY)
object = object->parent;
if (!object)
return;
d = GET_CORE_DISPLAY (object);
value->value.asKey.keysym =
XKeycodeToKeysym (d->display, from->action.key.keycode, 0);
value->value.asKey.keyModMask = from->action.key.modifiers;
}
else
{
value->value.asKey.keysym = 0;
value->value.asKey.keyModMask = 0;
}
case TypeButton:
if (from->action.type & CompBindingTypeButton)
{
value->value.asButton.button = from->action.button.button;
value->value.asButton.buttonModMask =
from->action.button.modifiers;
value->value.asButton.edgeMask = 0;
}
else if (from->action.type & CompBindingTypeEdgeButton)
{
value->value.asButton.button = from->action.button.button;
value->value.asButton.buttonModMask =
from->action.button.modifiers;
value->value.asButton.edgeMask = from->action.edgeMask;
}
else
{
value->value.asButton.button = 0;
value->value.asButton.buttonModMask = 0;
value->value.asButton.edgeMask = 0;
}
break;
case TypeEdge:
value->value.asEdge = from->action.edgeMask;
break;
case TypeBell:
value->value.asBell = from->action.bell;
break;
default:
break;
}
}
static void
ccpValueToSetting (CompObject *object,
CCSSetting *s,
CompOptionValue *v)
{
CCSSettingValue *value;
value = calloc (1, sizeof (CCSSettingValue));
if (!value)
return;
value->parent = s;
if (s->type == TypeList)
{
int i;
for (i = 0; i < v->list.nValue; i++)
{
CCSSettingValue *val;
val = calloc (1, sizeof (CCSSettingValue));
if (val)
{
val->parent = s;
val->isListChild = TRUE;
ccpInitValue (object, val, &v->list.value[i],
s->info.forList.listType);
value->value.asList =
ccsSettingValueListAppend (value->value.asList, val);
}
}
}
else
ccpInitValue (object, value, v, s->type);
ccsSetValue (s, value);
ccsFreeSettingValue (value);
}
static Bool
ccpTypeCheck (CCSSetting *s, CompOption *o)
{
CompOptionType ot;
switch (s->type)
{
case TypeList:
return ccpCCSTypeToCompizType (s->type, &ot) && (ot == o->type) &&
ccpCCSTypeToCompizType (s->info.forList.listType, &ot) &&
(ot == o->value.list.type);
break;
default:
return ccpCCSTypeToCompizType (s->type, &ot) && (ot == o->type);
break;
}
return FALSE;
}
static void
ccpSetOptionFromContext (CompObject *object,
CompOption *o,
const char *plugin)
{
CCP_CORE (&core);
CCSPlugin *bsp;
CCSSetting *setting;
CompOptionValue value;
Bool screen = (object->type == COMP_OBJECT_TYPE_SCREEN);
int screenNum = 0;
/* we currently only support screen and display opton types */
if (object->type != COMP_OBJECT_TYPE_SCREEN &&
object->type != COMP_OBJECT_TYPE_DISPLAY)
return;
if (screen)
{
char *name = compObjectName (object);
if (name)
{
screenNum = atoi (name);
free (name);
}
}
bsp = ccsFindPlugin (cc->context, (plugin) ? plugin : CORE_VTABLE_NAME);
if (!bsp)
return;
setting = ccsFindSetting (bsp, o->name, screen, screenNum);
if (!setting)
return;
if (!ccpTypeCheck (setting, o))
return;
compInitOptionValue (&value);
ccpSettingToValue (object, setting, &value);
cc->applyingSettings = TRUE;
(*core.setOptionForPlugin) (object, plugin, o->name, &value);
cc->applyingSettings = FALSE;
compFiniOptionValue (&value, o->type);
}
static void
ccpSetContextFromOption (CompObject *object,
CompOption *o,
const char *plugin)
{
CCP_CORE (&core);
CCSPlugin *bsp;
CCSSetting *setting;
Bool screen = (object->type == COMP_OBJECT_TYPE_SCREEN);
int screenNum = 0;
/* we currently only support screen and display opton types */
if (object->type != COMP_OBJECT_TYPE_SCREEN &&
object->type != COMP_OBJECT_TYPE_DISPLAY)
return;
if (screen)
{
char *name = compObjectName (object);
if (name)
{
screenNum = atoi (name);
free (name);
}
}
bsp = ccsFindPlugin (cc->context, (plugin) ? plugin : CORE_VTABLE_NAME);
if (!bsp)
return;
setting = ccsFindSetting (bsp, o->name, screen, screenNum);
if (!setting)
return;
if (!ccpTypeCheck (setting, o))
return;
ccpValueToSetting (object, setting, &o->value);
ccsWriteChangedSettings (cc->context);
}
static CompBool
ccpReloadObjectTree (CompObject *object,
void *closure);
static CompBool
ccpReloadObjectsWithType (CompObjectType type,
CompObject *parent,
void *closure)
{
compObjectForEach (parent, type, ccpReloadObjectTree, closure);
return TRUE;
}
static CompBool
ccpReloadObjectTree (CompObject *object,
void *closure)
{
CompPlugin *p = (CompPlugin *) closure;
CompOption *option;
int nOption;
option = (*p->vTable->getObjectOptions) (p, object, &nOption);
while (nOption--)
ccpSetOptionFromContext (object, option++, p->vTable->name);
compObjectForEachType (object, ccpReloadObjectsWithType, closure);
return TRUE;
}
static Bool
ccpReload (void *closure)
{
CompPlugin *p;
CCP_CORE (&core);
for (p = getPlugins (); p; p = p->next)
{
if (!p->vTable->getObjectOptions)
continue;
ccpReloadObjectTree (&core.base, (void *) p);
}
cc->reloadHandle = 0;
return FALSE;
}
static Bool
ccpTimeout (void *closure)
{
unsigned int flags = 0;
CCP_CORE (&core);
if (findActivePlugin ("glib"))
flags |= ProcessEventsNoGlibMainLoopMask;
ccsProcessEvents (cc->context, flags);
if (ccsSettingListLength (cc->context->changedSettings))
{
CCSSettingList list = cc->context->changedSettings;
CCSSettingList l = list;
CCSSetting *s;
CompObject *object;
CompPlugin *p;
CompOption *option;
int nOption;
char tmp[256];
cc->context->changedSettings = NULL;
while (l)
{
s = l->data;
l = l->next;
if (s->isScreen)
{
snprintf (tmp, 256, "%d", s->screenNum);
object = compObjectFind (&core.base, COMP_OBJECT_TYPE_DISPLAY,
NULL);
object = compObjectFind (object, COMP_OBJECT_TYPE_SCREEN,
tmp);
}
else
{
object = compObjectFind (&core.base, COMP_OBJECT_TYPE_DISPLAY,
NULL);
}
if (!object)
continue;
p = findActivePlugin (s->parent->name);
if (!p)
continue;
option = (*p->vTable->getObjectOptions) (p, object, &nOption);
option = compFindOption (option, nOption, s->name, 0);
if (option)
ccpSetOptionFromContext (object, option, s->parent->name);
D (D_FULL, "Setting Update \"%s\"\n", s->name);
}
ccsSettingListFree (list, FALSE);
cc->context->changedSettings =
ccsSettingListFree (cc->context->changedSettings, FALSE);
}
return TRUE;
}
static CompBool
ccpSetOptionForPlugin (CompObject *object,
const char *plugin,
const char *name,
CompOptionValue *value)
{
CompBool status;
CCP_CORE (&core);
UNWRAP (cc, &core, setOptionForPlugin);
status = (*core.setOptionForPlugin) (object, plugin, name, value);
WRAP (cc, &core, setOptionForPlugin, ccpSetOptionForPlugin);
if (status && !cc->applyingSettings && !cc->reloadHandle)
{
CompPlugin *p;
p = findActivePlugin (plugin);
if (p && p->vTable->getObjectOptions)
{
CompOption *option;
int nOption;
option = (*p->vTable->getObjectOptions) (p, object, &nOption);
option = compFindOption (option, nOption, name, 0);
if (option)
ccpSetContextFromOption (object, option, p->vTable->name);
}
}
return status;
}
static CompBool
ccpInitPluginForObject (CompPlugin *p,
CompObject *o)
{
CompBool status;
CCP_CORE (&core);
UNWRAP (cc, &core, initPluginForObject);
status = (*core.initPluginForObject) (p, o);
WRAP (cc, &core, initPluginForObject, ccpInitPluginForObject);
if (status && p->vTable->getObjectOptions)
{
CompOption *option;
int nOption;
option = (*p->vTable->getObjectOptions) (p, o, &nOption);
while (nOption--)
ccpSetOptionFromContext (o, option++, p->vTable->name);
}
return status;
}
static Bool
ccpInitCore (CompPlugin *p,
CompCore *c)
{
CCPCore *cc;
CompObject *o;
int i;
unsigned int *screens;
if (!checkPluginABI ("core", CORE_ABIVERSION))
return FALSE;
cc = malloc (sizeof (CCPCore));
if (!cc)
return FALSE;
ccsSetBasicMetadata (TRUE);
o = compObjectFind (&core.base, COMP_OBJECT_TYPE_DISPLAY, NULL);
if (o)
{
CompScreen *s;
CORE_DISPLAY (o);
for (s = d->screens, i = 0; s; s = s->next, i++);
screens = calloc (i, sizeof (unsigned int));
if (!screens)
{
free (cc);
return FALSE;
}
for (s = d->screens, i = 0; s; s = s->next)
screens[i++] = s->screenNum;
cc->context = ccsContextNew (screens, i);
free (screens);
}
else
cc->context = ccsContextNew (NULL, 0);
if (!cc->context)
{
free (cc);
return FALSE;
}
ccsReadSettings (cc->context);
cc->context->changedSettings =
ccsSettingListFree (cc->context->changedSettings, FALSE);
cc->applyingSettings = FALSE;
cc->reloadHandle = compAddTimeout (0, 0, ccpReload, 0);
cc->timeoutHandle = compAddTimeout (CCP_UPDATE_MIN_TIMEOUT,
CCP_UPDATE_MAX_TIMEOUT,
ccpTimeout, 0);
core.base.privates[corePrivateIndex].ptr = cc;
WRAP (cc, c, initPluginForObject, ccpInitPluginForObject);
WRAP (cc, c, setOptionForPlugin, ccpSetOptionForPlugin);
return TRUE;
}
static void
ccpFiniCore (CompPlugin *p,
CompCore *c)
{
CCP_CORE (&core);
UNWRAP (cc, c, initPluginForObject);
UNWRAP (cc, c, setOptionForPlugin);
compRemoveTimeout (cc->timeoutHandle);
ccsContextDestroy (cc->context);
free (cc);
}
static CompBool
ccpInitObject (CompPlugin *p,
CompObject *o)
{
static InitPluginObjectProc dispTab[] = {
(InitPluginObjectProc) ccpInitCore,
};
RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
}
static void
ccpFiniObject (CompPlugin *p,
CompObject *o)
{
static FiniPluginObjectProc dispTab[] = {
(FiniPluginObjectProc) ccpFiniCore,
};
DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
}
static Bool
ccpInit (CompPlugin *p)
{
if (!compInitPluginMetadataFromInfo (&ccpMetadata, p->vTable->name,
0, 0, 0, 0))
return FALSE;
corePrivateIndex = allocateCorePrivateIndex ();
if (corePrivateIndex < 0)
{
compFiniMetadata (&ccpMetadata);
return FALSE;
}
compAddMetadataFromFile (&ccpMetadata, p->vTable->name);
return TRUE;
}
static void
ccpFini (CompPlugin *p)
{
freeCorePrivateIndex (corePrivateIndex);
compFiniMetadata (&ccpMetadata);
}
static CompMetadata*
ccpGetMetadata (CompPlugin *plugin)
{
return &ccpMetadata;
}
CompPluginVTable ccpVTable = {
"ccp",
ccpGetMetadata,
ccpInit,
ccpFini,
ccpInitObject,
ccpFiniObject,
0,
0
};
CompPluginVTable *
getCompPluginInfo20070830 (void)
{
return &ccpVTable;
}