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.
568 lines
12 KiB
568 lines
12 KiB
4 years ago
|
/*
|
||
|
* Copyright © 2007 Novell, Inc.
|
||
|
*
|
||
|
* Permission to use, copy, modify, distribute, and sell this software
|
||
|
* and its documentation for any purpose is hereby granted without
|
||
|
* fee, provided that the above copyright notice appear in all copies
|
||
|
* and that both that copyright notice and this permission notice
|
||
|
* appear in supporting documentation, and that the name of
|
||
|
* Novell, Inc. not be used in advertising or publicity pertaining to
|
||
|
* distribution of the software without specific, written prior permission.
|
||
|
* Novell, Inc. makes no representations about the suitability of this
|
||
|
* software for any purpose. It is provided "as is" without express or
|
||
|
* implied warranty.
|
||
|
*
|
||
|
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
|
||
|
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||
|
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||
|
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
|
*
|
||
|
* Author: David Reveman <davidr@novell.com>
|
||
|
*/
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <limits.h>
|
||
|
|
||
|
#include <regex.h>
|
||
|
|
||
|
#include <X11/Xatom.h>
|
||
|
|
||
|
#include <compiz-core.h>
|
||
|
|
||
|
static CompMetadata regexMetadata;
|
||
|
|
||
|
static int displayPrivateIndex;
|
||
|
|
||
|
typedef struct _RegexDisplay {
|
||
|
int screenPrivateIndex;
|
||
|
HandleEventProc handleEvent;
|
||
|
MatchInitExpProc matchInitExp;
|
||
|
Atom roleAtom;
|
||
|
Atom visibleNameAtom;
|
||
|
CompTimeoutHandle timeoutHandle;
|
||
|
} RegexDisplay;
|
||
|
|
||
|
typedef struct _RegexScreen {
|
||
|
int windowPrivateIndex;
|
||
|
} RegexScreen;
|
||
|
|
||
|
typedef struct _RegexWindow {
|
||
|
char *title;
|
||
|
char *role;
|
||
|
} RegexWindow;
|
||
|
|
||
|
#define GET_REGEX_DISPLAY(d) \
|
||
|
((RegexDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
|
||
|
|
||
|
#define REGEX_DISPLAY(d) \
|
||
|
RegexDisplay *rd = GET_REGEX_DISPLAY (d)
|
||
|
|
||
|
#define GET_REGEX_SCREEN(s, rd) \
|
||
|
((RegexScreen *) (s)->base.privates[(rd)->screenPrivateIndex].ptr)
|
||
|
|
||
|
#define REGEX_SCREEN(s) \
|
||
|
RegexScreen *rs = GET_REGEX_SCREEN (s, GET_REGEX_DISPLAY (s->display))
|
||
|
|
||
|
#define GET_REGEX_WINDOW(w, rs) \
|
||
|
((RegexWindow *) (w)->base.privates[(rs)->windowPrivateIndex].ptr)
|
||
|
|
||
|
#define REGEX_WINDOW(w) \
|
||
|
RegexWindow *rw = GET_REGEX_WINDOW (w, \
|
||
|
GET_REGEX_SCREEN (w->screen, \
|
||
|
GET_REGEX_DISPLAY (w->screen->display)))
|
||
|
|
||
|
static void
|
||
|
regexMatchExpFini (CompDisplay *d,
|
||
|
CompPrivate private)
|
||
|
{
|
||
|
regex_t *preg = (regex_t *) private.ptr;
|
||
|
|
||
|
if (preg)
|
||
|
{
|
||
|
regfree (preg);
|
||
|
free (preg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
regexMatchExpEvalTitle (CompDisplay *d,
|
||
|
CompWindow *w,
|
||
|
CompPrivate private)
|
||
|
{
|
||
|
regex_t *preg = (regex_t *) private.ptr;
|
||
|
int status;
|
||
|
|
||
|
REGEX_WINDOW (w);
|
||
|
|
||
|
if (!preg)
|
||
|
return FALSE;
|
||
|
|
||
|
if (!rw->title)
|
||
|
return FALSE;
|
||
|
|
||
|
status = regexec (preg, rw->title, 0, NULL, 0);
|
||
|
if (status)
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
regexMatchExpEvalRole (CompDisplay *d,
|
||
|
CompWindow *w,
|
||
|
CompPrivate private)
|
||
|
{
|
||
|
regex_t *preg = (regex_t *) private.ptr;
|
||
|
int status;
|
||
|
|
||
|
REGEX_WINDOW (w);
|
||
|
|
||
|
if (!preg)
|
||
|
return FALSE;
|
||
|
|
||
|
if (!rw->role)
|
||
|
return FALSE;
|
||
|
|
||
|
status = regexec (preg, rw->role, 0, NULL, 0);
|
||
|
if (status)
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
regexMatchExpEvalClass (CompDisplay *d,
|
||
|
CompWindow *w,
|
||
|
CompPrivate private)
|
||
|
{
|
||
|
regex_t *preg = (regex_t *) private.ptr;
|
||
|
int status;
|
||
|
|
||
|
if (!preg)
|
||
|
return FALSE;
|
||
|
|
||
|
if (!w->resClass)
|
||
|
return FALSE;
|
||
|
|
||
|
status = regexec (preg, w->resClass, 0, NULL, 0);
|
||
|
if (status)
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
regexMatchExpEvalName (CompDisplay *d,
|
||
|
CompWindow *w,
|
||
|
CompPrivate private)
|
||
|
{
|
||
|
regex_t *preg = (regex_t *) private.ptr;
|
||
|
int status;
|
||
|
|
||
|
if (!preg)
|
||
|
return FALSE;
|
||
|
|
||
|
if (!w->resName)
|
||
|
return FALSE;
|
||
|
|
||
|
status = regexec (preg, w->resName, 0, NULL, 0);
|
||
|
if (status)
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
regexMatchInitExp (CompDisplay *d,
|
||
|
CompMatchExp *exp,
|
||
|
const char *value)
|
||
|
{
|
||
|
static struct _Prefix {
|
||
|
char *s;
|
||
|
int len;
|
||
|
CompMatchExpEvalProc eval;
|
||
|
unsigned int flags;
|
||
|
} prefix[] = {
|
||
|
{ "title=", 6, regexMatchExpEvalTitle, 0 },
|
||
|
{ "role=", 5, regexMatchExpEvalRole, 0 },
|
||
|
{ "class=", 6, regexMatchExpEvalClass, 0 },
|
||
|
{ "name=", 5, regexMatchExpEvalName, 0 },
|
||
|
{ "ititle=", 7, regexMatchExpEvalTitle, REG_ICASE },
|
||
|
{ "irole=", 6, regexMatchExpEvalRole, REG_ICASE },
|
||
|
{ "iclass=", 7, regexMatchExpEvalClass, REG_ICASE },
|
||
|
{ "iname=", 6, regexMatchExpEvalName, REG_ICASE },
|
||
|
};
|
||
|
int i;
|
||
|
|
||
|
REGEX_DISPLAY (d);
|
||
|
|
||
|
for (i = 0; i < sizeof (prefix) / sizeof (prefix[0]); i++)
|
||
|
if (strncmp (value, prefix[i].s, prefix[i].len) == 0)
|
||
|
break;
|
||
|
|
||
|
if (i < sizeof (prefix) / sizeof (prefix[0]))
|
||
|
{
|
||
|
regex_t *preg;
|
||
|
|
||
|
preg = malloc (sizeof (regex_t));
|
||
|
if (preg)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
value += prefix[i].len;
|
||
|
|
||
|
status = regcomp (preg, value, REG_NOSUB | prefix[i].flags);
|
||
|
if (status)
|
||
|
{
|
||
|
char errMsg[1024];
|
||
|
|
||
|
regerror (status, preg, errMsg, sizeof (errMsg));
|
||
|
|
||
|
compLogMessage ("regex", CompLogLevelWarn,
|
||
|
"%s = %s", errMsg, value);
|
||
|
|
||
|
regfree (preg);
|
||
|
free (preg);
|
||
|
preg = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
exp->fini = regexMatchExpFini;
|
||
|
exp->eval = prefix[i].eval;
|
||
|
exp->priv.ptr = preg;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UNWRAP (rd, d, matchInitExp);
|
||
|
(*d->matchInitExp) (d, exp, value);
|
||
|
WRAP (rd, d, matchInitExp, regexMatchInitExp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static char *
|
||
|
regexGetStringProperty (CompWindow *w,
|
||
|
Atom propAtom,
|
||
|
Atom formatAtom)
|
||
|
{
|
||
|
Atom type;
|
||
|
unsigned long nItems;
|
||
|
unsigned long bytesAfter;
|
||
|
unsigned char *str = NULL;
|
||
|
int format, result;
|
||
|
char *retval;
|
||
|
|
||
|
result = XGetWindowProperty (w->screen->display->display,
|
||
|
w->id, propAtom, 0, LONG_MAX,
|
||
|
FALSE, formatAtom, &type, &format, &nItems,
|
||
|
&bytesAfter, (unsigned char **) &str);
|
||
|
|
||
|
if (result != Success)
|
||
|
return NULL;
|
||
|
|
||
|
if (type != formatAtom)
|
||
|
{
|
||
|
XFree (str);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
retval = strdup ((char *) str);
|
||
|
|
||
|
XFree (str);
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
static char *
|
||
|
regexGetWindowTitle (CompWindow *w)
|
||
|
{
|
||
|
CompDisplay *d = w->screen->display;
|
||
|
char *title;
|
||
|
|
||
|
REGEX_DISPLAY (d);
|
||
|
|
||
|
title = regexGetStringProperty (w, rd->visibleNameAtom, d->utf8StringAtom);
|
||
|
if (title)
|
||
|
return title;
|
||
|
|
||
|
title = regexGetStringProperty (w, d->wmNameAtom, d->utf8StringAtom);
|
||
|
if (title)
|
||
|
return title;
|
||
|
|
||
|
return regexGetStringProperty (w, XA_WM_NAME, XA_STRING);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
regexHandleEvent (CompDisplay *d,
|
||
|
XEvent *event)
|
||
|
{
|
||
|
REGEX_DISPLAY (d);
|
||
|
|
||
|
UNWRAP (rd, d, handleEvent);
|
||
|
(*d->handleEvent) (d, event);
|
||
|
WRAP (rd, d, handleEvent, regexHandleEvent);
|
||
|
|
||
|
if (event->type == PropertyNotify)
|
||
|
{
|
||
|
CompWindow *w;
|
||
|
|
||
|
if (event->xproperty.atom == XA_WM_NAME)
|
||
|
{
|
||
|
w = findWindowAtDisplay (d, event->xproperty.window);
|
||
|
if (w)
|
||
|
{
|
||
|
REGEX_WINDOW (w);
|
||
|
|
||
|
if (rw->title)
|
||
|
free (rw->title);
|
||
|
|
||
|
rw->title = regexGetWindowTitle (w);
|
||
|
|
||
|
(*d->matchPropertyChanged) (d, w);
|
||
|
}
|
||
|
}
|
||
|
if (event->xproperty.atom == rd->roleAtom)
|
||
|
{
|
||
|
w = findWindowAtDisplay (d, event->xproperty.window);
|
||
|
if (w)
|
||
|
{
|
||
|
REGEX_WINDOW (w);
|
||
|
|
||
|
if (rw->role)
|
||
|
free (rw->role);
|
||
|
|
||
|
rw->role = regexGetStringProperty (w, rd->roleAtom, XA_STRING);
|
||
|
|
||
|
(*d->matchPropertyChanged) (d, w);
|
||
|
}
|
||
|
}
|
||
|
else if (event->xproperty.atom == XA_WM_CLASS)
|
||
|
{
|
||
|
w = findWindowAtDisplay (d, event->xproperty.window);
|
||
|
if (w)
|
||
|
(*d->matchPropertyChanged) (d, w);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
regexRegisterExpHandler (void *closure)
|
||
|
{
|
||
|
CompDisplay *display = (CompDisplay *) closure;
|
||
|
|
||
|
(*display->matchExpHandlerChanged) (display);
|
||
|
|
||
|
REGEX_DISPLAY (display);
|
||
|
|
||
|
rd->timeoutHandle = 0;
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
regexInitDisplay (CompPlugin *p,
|
||
|
CompDisplay *d)
|
||
|
{
|
||
|
RegexDisplay *rd;
|
||
|
|
||
|
if (!checkPluginABI ("core", CORE_ABIVERSION))
|
||
|
return FALSE;
|
||
|
|
||
|
rd = malloc (sizeof (RegexDisplay));
|
||
|
if (!rd)
|
||
|
return FALSE;
|
||
|
|
||
|
rd->screenPrivateIndex = allocateScreenPrivateIndex (d);
|
||
|
if (rd->screenPrivateIndex < 0)
|
||
|
{
|
||
|
free (rd);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
rd->roleAtom = XInternAtom (d->display, "WM_WINDOW_ROLE", 0);
|
||
|
rd->visibleNameAtom = XInternAtom (d->display, "_NET_WM_VISIBLE_NAME", 0);
|
||
|
|
||
|
WRAP (rd, d, handleEvent, regexHandleEvent);
|
||
|
WRAP (rd, d, matchInitExp, regexMatchInitExp);
|
||
|
|
||
|
d->base.privates[displayPrivateIndex].ptr = rd;
|
||
|
|
||
|
/* one shot timeout to which will register the expression handler
|
||
|
after all screens and windows have been initialized */
|
||
|
rd->timeoutHandle =
|
||
|
compAddTimeout (0, 0, regexRegisterExpHandler, (void *) d);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
regexFiniDisplay (CompPlugin *p,
|
||
|
CompDisplay *d)
|
||
|
{
|
||
|
REGEX_DISPLAY (d);
|
||
|
|
||
|
freeScreenPrivateIndex (d, rd->screenPrivateIndex);
|
||
|
|
||
|
if (rd->timeoutHandle)
|
||
|
compRemoveTimeout (rd->timeoutHandle);
|
||
|
|
||
|
UNWRAP (rd, d, handleEvent);
|
||
|
UNWRAP (rd, d, matchInitExp);
|
||
|
|
||
|
if (d->base.parent)
|
||
|
(*d->matchExpHandlerChanged) (d);
|
||
|
|
||
|
free (rd);
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
regexInitScreen (CompPlugin *p,
|
||
|
CompScreen *s)
|
||
|
{
|
||
|
RegexScreen *rs;
|
||
|
|
||
|
REGEX_DISPLAY (s->display);
|
||
|
|
||
|
rs = malloc (sizeof (RegexScreen));
|
||
|
if (!rs)
|
||
|
return FALSE;
|
||
|
|
||
|
rs->windowPrivateIndex = allocateWindowPrivateIndex (s);
|
||
|
if (rs->windowPrivateIndex < 0)
|
||
|
{
|
||
|
free (rs);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
s->base.privates[rd->screenPrivateIndex].ptr = rs;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
regexFiniScreen (CompPlugin *p,
|
||
|
CompScreen *s)
|
||
|
{
|
||
|
REGEX_SCREEN (s);
|
||
|
|
||
|
freeWindowPrivateIndex (s, rs->windowPrivateIndex);
|
||
|
|
||
|
free (rs);
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
regexInitWindow (CompPlugin *p,
|
||
|
CompWindow *w)
|
||
|
{
|
||
|
RegexWindow *rw;
|
||
|
|
||
|
REGEX_DISPLAY (w->screen->display);
|
||
|
REGEX_SCREEN (w->screen);
|
||
|
|
||
|
rw = malloc (sizeof (RegexWindow));
|
||
|
if (!rw)
|
||
|
return FALSE;
|
||
|
|
||
|
rw->title = regexGetWindowTitle (w);
|
||
|
rw->role = regexGetStringProperty (w, rd->roleAtom, XA_STRING);
|
||
|
|
||
|
w->base.privates[rs->windowPrivateIndex].ptr = rw;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
regexFiniWindow (CompPlugin *p,
|
||
|
CompWindow *w)
|
||
|
{
|
||
|
REGEX_WINDOW (w);
|
||
|
|
||
|
if (rw->title)
|
||
|
free (rw->title);
|
||
|
|
||
|
if (rw->role)
|
||
|
free (rw->role);
|
||
|
|
||
|
free (rw);
|
||
|
}
|
||
|
|
||
|
static CompBool
|
||
|
regexInitObject (CompPlugin *p,
|
||
|
CompObject *o)
|
||
|
{
|
||
|
static InitPluginObjectProc dispTab[] = {
|
||
|
(InitPluginObjectProc) 0, /* InitCore */
|
||
|
(InitPluginObjectProc) regexInitDisplay,
|
||
|
(InitPluginObjectProc) regexInitScreen,
|
||
|
(InitPluginObjectProc) regexInitWindow
|
||
|
};
|
||
|
|
||
|
RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
regexFiniObject (CompPlugin *p,
|
||
|
CompObject *o)
|
||
|
{
|
||
|
static FiniPluginObjectProc dispTab[] = {
|
||
|
(FiniPluginObjectProc) 0, /* FiniCore */
|
||
|
(FiniPluginObjectProc) regexFiniDisplay,
|
||
|
(FiniPluginObjectProc) regexFiniScreen,
|
||
|
(FiniPluginObjectProc) regexFiniWindow
|
||
|
};
|
||
|
|
||
|
DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
regexInit (CompPlugin *p)
|
||
|
{
|
||
|
if (!compInitPluginMetadataFromInfo (®exMetadata, p->vTable->name,
|
||
|
0, 0, 0, 0))
|
||
|
return FALSE;
|
||
|
|
||
|
displayPrivateIndex = allocateDisplayPrivateIndex ();
|
||
|
if (displayPrivateIndex < 0)
|
||
|
{
|
||
|
compFiniMetadata (®exMetadata);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
compAddMetadataFromFile (®exMetadata, p->vTable->name);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
regexFini (CompPlugin *p)
|
||
|
{
|
||
|
freeDisplayPrivateIndex (displayPrivateIndex);
|
||
|
compFiniMetadata (®exMetadata);
|
||
|
}
|
||
|
|
||
|
static CompMetadata *
|
||
|
regexGetMetadata (CompPlugin *plugin)
|
||
|
{
|
||
|
return ®exMetadata;
|
||
|
}
|
||
|
|
||
|
static CompPluginVTable regexVTable = {
|
||
|
"regex",
|
||
|
regexGetMetadata,
|
||
|
regexInit,
|
||
|
regexFini,
|
||
|
regexInitObject,
|
||
|
regexFiniObject,
|
||
|
0, /* GetObjectOptions */
|
||
|
0 /* SetObjectOption */
|
||
|
};
|
||
|
|
||
|
CompPluginVTable *
|
||
|
getCompPluginInfo20070830 (void)
|
||
|
{
|
||
|
return ®exVTable;
|
||
|
}
|