All pastes #267418 Raw Edit

Group

public c v1 · immutable
·published 2006-12-04 21:18 UTC
rendered paste body
/** * * Beryl group plugin * * group.c * * Copyright : (C) 2006 by Patrick Niklaus * E-mail    : patrick.niklaus [ a t ] googlemail.com * * * 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. * * * TODO: *      * glow effect *      * tab like switching between the windows *      * a lot of other tab stuff... *      * provide a tree system for groups * **/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <malloc.h>#include <time.h>#include <X11/Xlib.h>#include <beryl.h>#include <beryl_ipcs.h>#include <math.h>#define PI 3.1415926535897/* * Defaults * */#define GROUP_SELECT_MODIFIERS_DEFAULT          (CompSuperMask)#define GROUP_SELECT_BUTTON_DEFAULT             Button1#define GROUP_SELECT_SINGLE_MODIFIERS_DEFAULT   (CompSuperMask)#define GROUP_SELECT_SINGLE_KEY_DEFAULT         "s"#define GROUP_GROUPING_MODIFIERS_DEFAULT        (CompSuperMask)#define GROUP_GROUPING_KEY_DEFAULT              "g"#define GROUP_UNGROUPING_MODIFIERS_DEFAULT      (CompSuperMask)#define GROUP_UNGROUPING_KEY_DEFAULT            "u"#define GROUP_TABMODE_MODIFIERS_DEFAULT         (CompSuperMask)#define GROUP_TABMODE_KEY_DEFAULT               "t"#define GROUP_CHANGE_TAB_MODIFIERS_DEFAULT      (CompSuperMask)#define GROUP_CHANGE_TAB_KEY_DEFAULT            "Left"#define GROUP_REMOVEING_MODIFIERS_DEFAULT       (CompSuperMask)#define GROUP_REMOVEING_KEY_DEFAULT             "r"#define GROUP_CLOSEING_MODIFIERS_DEFAULT        (CompSuperMask)#define GROUP_CLOSEING_KEY_DEFAULT              "c"#define GROUP_MINIMIZEING_MODIFIERS_DEFAULT     (CompSuperMask)#define GROUP_MINIMIZEING_KEY_DEFAULT           "b"#define GROUP_IGNORE_MODIFIERS_DEFAULT          (CompAltMask)#define GROUP_IGNORE_KEY_DEFAULT                "x"#define GROUP_DISPLAY_OPTION_SELECT         0#define GROUP_DISPLAY_OPTION_SELECT_SINGLE  1#define GROUP_DISPLAY_OPTION_GROUPING       2#define GROUP_DISPLAY_OPTION_UNGROUPING     3#define GROUP_DISPLAY_OPTION_REMOVEING      4#define GROUP_DISPLAY_OPTION_CLOSEING       5#define GROUP_DISPLAY_OPTION_MINIMIZEING    6#define GROUP_DISPLAY_OPTION_IGNORE         7#define GROUP_DISPLAY_OPTION_TABMODE        8#define GROUP_DISPLAY_OPTION_CHANGE_TAB     9#define GROUP_DISPLAY_OPTION_NUM            10#define GROUP_OPACITY_DEFAULT            80#define GROUP_OPACITY_MIN                0#define GROUP_OPACITY_MAX                100#define GROUP_SATURATION_DEFAULT         20#define GROUP_SATURATION_MIN             0#define GROUP_SATURATION_MAX             100#define GROUP_BRIGHTNESS_DEFAULT         70#define GROUP_BRIGHTNESS_MIN             0#define GROUP_BRIGHTNESS_MAX             100#define GROUP_TOLERANCE_DEFAULT          0#define GROUP_TOLERANCE_MIN              0#define GROUP_TOLERANCE_MAX              10#define GROUP_STEPS_DEFAULT              10#define GROUP_STEPS_MIN                  1#define GROUP_STEPS_MAX                  10#define GROUP_MOVE_DEFAULT               TRUE#define GROUP_RESIZE_DEFAULT             TRUE#define GROUP_RAISE_DEFAULT              TRUE#define GROUP_AUTO_UNGROUP_DEFAULT       FALSE#define GROUP_AUTO_GROUP_DEFAULT         FALSE#define GROUP_RELATIVE_DISTANCE_DEFAULT  FALSE#define GROUP_COLOR_SELECTION_RED_DEFAULT       0x0000#define GROUP_COLOR_SELECTION_GREEN_DEFAULT     0x0000#define GROUP_COLOR_SELECTION_BLUE_DEFAULT      0x0000#define GROUP_COLOR_SELECTION_ALPHA_DEFAULT     0x9999#define GROUP_COLOR_LINE_RED_DEFAULT            0x0000#define GROUP_COLOR_LINE_GREEN_DEFAULT          0x0000#define GROUP_COLOR_LINE_BLUE_DEFAULT           0x0000#define GROUP_COLOR_LINE_ALPHA_DEFAULT          0xABAB#define GROUP_SCREEN_OPTION_TYPES               0#define GROUP_SCREEN_OPTION_OPACITY             1#define GROUP_SCREEN_OPTION_SATURATION          2  #define GROUP_SCREEN_OPTION_BRIGHTNESS          3  #define GROUP_SCREEN_OPTION_MOVE                4#define GROUP_SCREEN_OPTION_RESIZE              5#define GROUP_SCREEN_OPTION_RAISE               6#define GROUP_SCREEN_OPTION_AUTO_UNGROUP        7#define GROUP_SCREEN_OPTION_AUTO_GROUP          8#define GROUP_SCREEN_OPTION_RELATIVE_DISTANCE   9#define GROUP_SCREEN_OPTION_SELECTION_COLOR     10#define GROUP_SCREEN_OPTION_LINE_COLOR          11#define GROUP_SCREEN_OPTION_TOLERANCE           12#define GROUP_SCREEN_OPTION_STEPS               13#define GROUP_SCREEN_OPTION_NUM                 14/* * Helpers * */#define GET_GROUP_DISPLAY(d) ((GroupDisplay *) (d)->privates[displayPrivateIndex].ptr)#define GROUP_DISPLAY(d) GroupDisplay *gd = GET_GROUP_DISPLAY (d)#define GET_GROUP_SCREEN(s, gd) ((GroupScreen *) (s)->privates[ (gd)->screenPrivateIndex].ptr)#define GROUP_SCREEN(s) GroupScreen *gs = GET_GROUP_SCREEN (s, GET_GROUP_DISPLAY (s->display))#define GET_GROUP_WINDOW(w, gs) ((GroupWindow *) (w)->privates[ (gs)->windowPrivateIndex].ptr)#define GROUP_WINDOW(w) GroupWindow *gw = GET_GROUP_WINDOW (w, GET_GROUP_SCREEN  (w->screen, GET_GROUP_DISPLAY (w->screen->display)))#define WIN_X(w) (w->attrib.x)#define WIN_Y(w) (w->attrib.y)#define WIN_WIDTH(w) (w->attrib.width)#define WIN_HEIGHT(w) (w->attrib.height)#define WIN_BORDER(w) (w->attrib.border_width)#define NUM_OPTIONS(s) (sizeof ( (s)->opt) / sizeof (CompOption))#define N_WIN_TYPE (sizeof (groupDefaultTypes) / sizeof (groupDefaultTypes[0]))#define N_SEL_MODE (sizeof (groupSelectionModes) / sizeof (groupSelectionModes[0]))/* * default windows for selection */static char* groupDefaultTypes[] = {    N_("Normal"),    N_("Dialog"),    N_("ModalDialog"),    N_("Dnd")};/* * pointer to display list */static int displayPrivateIndex;/* * Call-Back for state */typedef void (*AddWindowToGroupProc) (CompDisplay *d, CompWindow *w, int groupID);/* * GroupSelection */typedef struct _GroupSelection {    Window*         windows;    int             nWins;    int             id;    CompWindow*     topTab;    Bool            tabbed;} GroupSelection;/* * GroupDisplay structure */typedef struct _GroupDisplay {    int                     screenPrivateIndex;    CompOption              opt[GROUP_DISPLAY_OPTION_NUM];    HandleEventProc         handleEvent;    GroupSelection          tmpSel;    GroupSelection*         groups;    int                     nGroups;    Bool                    inAction;    int                     lastActiveGroup;    int                     animatedGroup;    Bool                    ignoreMode;} GroupDisplay;/* * GroupScreen structure */typedef struct _GroupScreen {    int                         windowPrivateIndex;    CompOption                  opt[GROUP_SCREEN_OPTION_NUM];    WindowMoveNotifyProc        windowMoveNotify;    WindowResizeNotifyProc      windowResizeNotify;    PreparePaintScreenProc             preparePaintScreen;    PaintScreenProc             paintScreen;    PaintWindowProc             paintWindow;    PaintTransformedScreenProc  paintTransformedScreen;     int                         wMask;    // for selection    Bool                        grab;    Bool                        wasTransformed;    int                         grabIndex;    int                         x1;    int                         y1;    int                         x2;    int                         y2;} GroupScreen;/* * GroupWindow structure */typedef struct _GroupWindow {    int     groupID;    Bool    inGroup;    Bool    inSelection;    // for scale notify...    int     oldWidth;    int     oldHeight;    int     oldX;    int     oldY;    // for tab animation    Bool    animate;    int     steps;    int     orgPosX;    int     orgPosY;    int     destinationX;    int     destinationY;} GroupWindow;/* * groupFindGroupAtDisplay * Note: Returns the index of the group in gd->groups! * */static intgroupFindGroupAtDisplay (GroupDisplay *gd, int id){    int i;    for (i = 0; i < gd->nGroups; i++)    {        if (gd->groups[i].id == id)            return i;    }        return -1;}#define TOLRNC_MIN(n1, n2, t) (n1 - t < n2)#define TOLRNC_MAX(n1, n2, t) (n1 + t > n2)/* * groupFindWindowsInRegion * */static Window*groupFindWindowsInRegion (CompScreen *s, REGION reg, int *c){    GROUP_SCREEN(s);    float tolerance = gs->opt[GROUP_SCREEN_OPTION_TOLERANCE].value.i / 10.0f;    Window *ret = NULL;    int count = 0;    CompWindow *w;    for (w = s->windows; w; w = w->next)    {        if ((gs->wMask & w->type) &&            !w->invisible &&            TOLRNC_MIN(reg.extents.x1, WIN_X (w), tolerance * WIN_WIDTH  (w)) &&            TOLRNC_MIN(reg.extents.y1, WIN_Y (w), tolerance * WIN_HEIGHT (w)) &&            TOLRNC_MAX(reg.extents.x2, (WIN_X (w) + WIN_WIDTH  (w)), tolerance * WIN_WIDTH  (w)) &&            TOLRNC_MAX(reg.extents.y2, (WIN_Y (w) + WIN_HEIGHT (w)), tolerance * WIN_HEIGHT (w)))        {            if (count == 0) {                ret = calloc (1, sizeof (Window));                ret[0] = w->id;            } else {                ret = realloc (ret, sizeof (Window) * (count+1));                ret[count] = w->id;            }            count++;        }    }    (*c) = count;         return ret;}/* * groupTabGroup * */static voidgroupTabGroup (CompDisplay *d, CompWindow *main, int groupID){    GROUP_DISPLAY (d);    GROUP_SCREEN  (main->screen);    int index = groupFindGroupAtDisplay (gd, groupID);    if (index == -1)        return;        gd->groups[index].tabbed = TRUE;    gd->animatedGroup = groupID;    // main window    GROUP_WINDOW (main);    gd->groups[index].topTab = main;    gw->animate = FALSE;    int i;    int steps = gs->opt[GROUP_SCREEN_OPTION_STEPS].value.i;    for (i = 0; i < gd->groups[index].nWins; i++)    {        CompWindow *cw = findWindowAtDisplay (d, gd->groups[index].windows[i]);        if (!cw || cw->id == main->id)            continue;        GROUP_WINDOW (cw);        gw->steps = steps;        gw->orgPosX = WIN_X (cw);        gw->orgPosY = WIN_Y (cw);        // center the window to the main window        gw->destinationX = WIN_X (main) + (WIN_WIDTH  (main) / 2) - (WIN_WIDTH  (cw) / 2);        gw->destinationY = WIN_Y (main) + (WIN_HEIGHT (main) / 2) - (WIN_HEIGHT (cw) / 2);        gw->animate = TRUE;    }    damageScreen (main->screen);}/* * groupUntabGroup * */static voidgroupUntabGroup (CompDisplay *d, CompWindow *main, int groupID){    GROUP_DISPLAY (d);    GROUP_SCREEN  (main->screen);    int index = groupFindGroupAtDisplay (gd, groupID);    if (index == -1)        return;        gd->groups[index].tabbed = FALSE;    gd->animatedGroup = groupID;    // main window    GROUP_WINDOW (main);    gd->groups[index].topTab = main;    gw->animate = FALSE;    int i;    int steps = gs->opt[GROUP_SCREEN_OPTION_STEPS].value.i;    for (i = 0; i < gd->groups[index].nWins; i++)    {        CompWindow *cw = findWindowAtDisplay (d, gd->groups[index].windows[i]);        if (!cw || cw->id == main->id)            continue;        GROUP_WINDOW (cw);        gw->steps = steps;        gw->destinationX = gw->orgPosX;        gw->destinationY = gw->orgPosY;        gw->orgPosX = WIN_X (cw);        gw->orgPosY = WIN_Y (cw);        cw->hidden = FALSE;        showWindow (cw);        unsigned int state = getWindowState (d, cw->id);        state &= ~CompWindowStateSkipTaskbarMask;        state &= ~CompWindowStateSkipPagerMask;        setWindowState (d, state, cw->id);        gw->animate = TRUE;    }    damageScreen (main->screen);}/* * groupDeleteGroup - pre-definition for groupDeleteGroupWindow * */static void groupDeleteGroup (CompDisplay *d, int id);/* * groupDeleteGroupWindow * */static voidgroupDeleteGroupWindow (CompDisplay *d, CompWindow *w){    GROUP_DISPLAY (d);    GROUP_WINDOW (w);    GROUP_SCREEN (w->screen);    int index = groupFindGroupAtDisplay (gd, gw->groupID);    if (index == -1)         return;    if (gd->groups[index].tabbed &&        gd->groups[index].topTab->id == w->id)    {        groupUntabGroup (d, w, gw->groupID);        gd->groups[index].topTab = NULL;    }    if (gd->groups[index].nWins != 0 && gd->groups[index].windows != NULL)    {        Window *buf = gd->groups[index].windows;                gd->groups[index].windows = (Window*) calloc (gd->groups[index].nWins-1, sizeof (Window));        int counter = 0;        int i;        for (i = 0; i < gd->groups[index].nWins; i++)        {            if (buf[i] == w->id)                continue;            gd->groups[index].windows[counter++] = buf[i];        }        gd->groups[index].nWins = counter;                if (gd->groups[index].nWins == 1 &&           gs->opt[GROUP_SCREEN_OPTION_AUTO_UNGROUP].value.b)        {            groupDeleteGroup (d, gw->groupID);        }        else if (gd->groups[index].nWins <= 0)        {            free (gd->groups[index].windows);            gd->groups[index].windows = NULL;            groupDeleteGroup (d, gw->groupID);        }        free (buf);        gw->inGroup = FALSE;    }}/* * groupDeleteGroup * */static voidgroupDeleteGroup (CompDisplay *d, int id){    GROUP_DISPLAY (d);    gd->inAction = TRUE;    gd->lastActiveGroup = -1;    int index = groupFindGroupAtDisplay (gd, id);    if (index == -1) {        gd->inAction = FALSE;        return;    }    if (gd->groups[index].windows != NULL)    {        if (gd->groups[index].tabbed)        {            groupUntabGroup (d, gd->groups[index].topTab, id);            // we don't want an animation here because it won't work...            gd->groups[index].topTab = NULL;            gd->animatedGroup = -1;        }        int i;        for (i = 0; i < gd->groups[index].nWins; i++)        {            CompWindow *cw = findWindowAtDisplay (d, gd->groups[index].windows[i]);            if (!cw)                continue;            GROUP_WINDOW (cw);            gw->inGroup = FALSE;        }        free (gd->groups[index].windows);    }    GroupSelection *groupsBuf = gd->groups;    gd->groups = calloc (gd->nGroups-1, sizeof (GroupSelection));    int counter = 0;    int i;    for (i = 0; i < gd->nGroups; i++)    {        if (groupsBuf[i].id == id) {            continue;        }                gd->groups[counter++] = groupsBuf[i];    }    gd->nGroups--;    free (groupsBuf);    gd->inAction = FALSE;}/* * groupAddWindowToGroup * */static voidgroupAddWindowToGroup (CompDisplay *d, CompWindow *w, int groupID){    GROUP_DISPLAY (d);    GROUP_WINDOW (w);    if (gw->inGroup) {        groupDeleteGroupWindow (d, w);    }    int index = groupFindGroupAtDisplay (gd, groupID);     if (index == -1)    {        GroupSelection g;        g.id = groupID;        g.windows = (Window*) calloc (1, sizeof (Window));        g.windows[0] = w->id;        g.nWins = 1;        g.topTab = NULL;        g.tabbed = FALSE;                gd->groups = (GroupSelection*) realloc (gd->groups, sizeof (GroupSelection)* (gd->nGroups+1));        gd->groups[gd->nGroups] = g;        gd->nGroups++;         gw->groupID = groupID;        gw->inGroup = TRUE;    }    else    {        gd->groups[index].windows = (Window*) realloc (gd->groups[index].windows, sizeof (Window)* (gd->groups[index].nWins+1));        gd->groups[index].windows[gd->groups[index].nWins] = w->id;        gd->groups[index].nWins++;        gw->groupID = groupID;        gw->inGroup = TRUE;    }}/* * groupDeleteSelectionWindow * */static voidgroupDeleteSelectionWindow (CompDisplay *d, CompWindow *w){    GROUP_DISPLAY (d);    if (gd->tmpSel.nWins > 0 && gd->tmpSel.windows)    {        Window *buf = gd->tmpSel.windows;        gd->tmpSel.windows = (Window*) calloc (gd->tmpSel.nWins-1, sizeof (Window));        int counter = 0;        int i;        for (i = 0; i < gd->tmpSel.nWins; i++)        {            if (buf[i] == w->id)                continue;            gd->tmpSel.windows[counter++] = buf[i];        }        gd->tmpSel.nWins = counter;        free (buf);    }}/* * groupAddWindowToSelection * */static voidgroupAddWindowToSelection (CompDisplay *d, CompWindow *w){    GROUP_DISPLAY (d);    gd->tmpSel.windows = (Window*) realloc (gd->tmpSel.windows,                                                sizeof (Window)* (gd->tmpSel.nWins+1));    gd->tmpSel.windows[gd->tmpSel.nWins] = w->id;    gd->tmpSel.nWins++;}/* * groupSyncWindows * */static voidgroupSyncWindows (CompDisplay *d, int groupID){    GROUP_DISPLAY (d);    int index = groupFindGroupAtDisplay (gd, groupID);    if (index == -1)        return;    int i;    for (i = 0; i < gd->groups[index].nWins; i++)    {        CompWindow *w = findWindowAtDisplay (d, gd->groups[index].windows[i]);        if (!w)            continue;        syncWindowPosition (w);    }}/* * groupUpdatePosBuffer * */static voidgroupUpdatePosBuffer (CompWindow *w, int x, int y, int width, int height){    GROUP_WINDOW (w);    gw->oldX = x;    gw->oldY = y;    gw->oldWidth = width;    gw->oldHeight = height;}/* * groupRaiseWindows * */static voidgroupRaiseWindows (CompDisplay *d, CompWindow *top, int groupID){    GROUP_DISPLAY (d);    int index = groupFindGroupAtDisplay (gd, groupID);    if (index == -1)        return;        int i;    for (i = 0; i < gd->groups[index].nWins; i++)    {        CompWindow *w = findWindowAtDisplay (d, gd->groups[index].windows[i]);        if (!w || w->id == top->id)            continue;        restackWindowBelow (w, top);    }}/* * groupScreenInitOptions * */static voidgroupScreenInitOptions (GroupScreen *gs){    CompOption *o;    int         i;    o = &gs->opt[GROUP_SCREEN_OPTION_TYPES];    o->name              = "mask";    o->group             = N_("");    o->subGroup          = N_("");    o->displayHints      = "";    o->shortDesc         = N_("Window Types");    o->longDesc          = N_("The types of windows which will be grouped");    o->type              = CompOptionTypeList;    o->value.list.type   = CompOptionTypeString;    o->value.list.nValue = N_WIN_TYPE;    o->value.list.value  = malloc (sizeof (CompOptionValue) * N_WIN_TYPE);    for (i = 0; i < N_WIN_TYPE; i++) {        o->value.list.value[i].s = strdup (groupDefaultTypes[i]);        o->rest.s.string     = (char**) windowTypeString;        o->rest.s.nString    = nWindowTypeString;    }    gs->wMask = compWindowTypeMaskFromStringList (&o->value);    o = &gs->opt[GROUP_SCREEN_OPTION_OPACITY];    o->name = "opacity";    o->group = N_("");    o->subGroup = N_("");    o->displayHints = "";    o->shortDesc = N_("Opacity");    o->longDesc = N_("Opacity of selected windows");    o->type = CompOptionTypeInt;    o->value.i = GROUP_OPACITY_DEFAULT;    o->rest.i.min = GROUP_OPACITY_MIN;    o->rest.i.max = GROUP_OPACITY_MAX;         o = &gs->opt[GROUP_SCREEN_OPTION_SATURATION];    o->name = "saturation";    o->group = N_("");    o->subGroup = N_("");    o->displayHints = "";    o->shortDesc = N_("Saturation");    o->longDesc = N_("Saturation of selected windows");    o->type = CompOptionTypeInt;    o->value.i = GROUP_SATURATION_DEFAULT;    o->rest.i.min = GROUP_SATURATION_MIN;    o->rest.i.max = GROUP_SATURATION_MAX;        o = &gs->opt[GROUP_SCREEN_OPTION_BRIGHTNESS];    o->name = "brightness";    o->group = N_("");    o->subGroup = N_("");    o->displayHints = "";    o->shortDesc = N_("Brightness");    o->longDesc = N_("Brightness of selected windows");    o->type = CompOptionTypeInt;    o->value.i = GROUP_BRIGHTNESS_DEFAULT;    o->rest.i.min = GROUP_BRIGHTNESS_MIN;    o->rest.i.max = GROUP_BRIGHTNESS_MAX;    o = &gs->opt[GROUP_SCREEN_OPTION_TOLERANCE];    o->name = "tolerance";    o->group = N_("");    o->subGroup = N_("");    o->displayHints = "";    o->shortDesc = N_("Tolerance");    o->longDesc = N_("Tolerance of the seletion.");    o->type = CompOptionTypeInt;    o->value.i = GROUP_TOLERANCE_DEFAULT;    o->rest.i.min = GROUP_TOLERANCE_MIN;    o->rest.i.max = GROUP_TOLERANCE_MAX;    o = &gs->opt[GROUP_SCREEN_OPTION_STEPS];    o->name = "steps";    o->group = N_("");    o->subGroup = N_("");    o->displayHints = "";    o->shortDesc = N_("Steps");    o->longDesc = N_("The animation steps that are needed for animation.");    o->type = CompOptionTypeInt;    o->value.i = GROUP_STEPS_DEFAULT;    o->rest.i.min = GROUP_STEPS_MIN;    o->rest.i.max = GROUP_STEPS_MAX;    o = &gs->opt[GROUP_SCREEN_OPTION_MOVE];    o->name = "move";    o->group = N_("");    o->subGroup = N_("");    o->displayHints = "";    o->shortDesc = N_("Move every window in the group");    o->longDesc = N_("If one window in the group gets moved, "                  "every other window in the group gets moved as well.");    o->type = CompOptionTypeBool;    o->value.b = GROUP_MOVE_DEFAULT;    o = &gs->opt[GROUP_SCREEN_OPTION_RESIZE];    o->name = "resize";    o->group = N_("");    o->subGroup = N_("");    o->displayHints = "";    o->shortDesc = N_("Resize every window in the group");    o->longDesc = N_("If one window in the group gets resized, "                  "every other window in the group gets resized as well.");    o->type = CompOptionTypeBool;    o->value.b = GROUP_RESIZE_DEFAULT;    o = &gs->opt[GROUP_SCREEN_OPTION_RAISE];    o->name = "raise";    o->group = N_("");    o->subGroup = N_("");    o->displayHints   = "";    o->shortDesc = N_("Raise every window in the group");    o->longDesc = N_("If one window in the group gets selected, "                  "every window in the group gets raised.");    o->type = CompOptionTypeBool;    o->value.b = GROUP_RAISE_DEFAULT;    o = &gs->opt[GROUP_SCREEN_OPTION_AUTO_GROUP];    o->name = "auto_group";    o->group = N_("");    o->subGroup = N_("");    o->displayHints = "";    o->shortDesc = N_("Group the windows after selection");    o->longDesc = N_("If you have selected your windows,"                      "this automatically groups them. "                     "(Doesn't work with selection mode 'normal')");    o->type = CompOptionTypeBool;    o->value.b = GROUP_AUTO_GROUP_DEFAULT;    o = &gs->opt[GROUP_SCREEN_OPTION_AUTO_UNGROUP];    o->name = "auto_ungroup";    o->group = N_("");    o->subGroup = N_("");    o->displayHints = "";    o->shortDesc = N_("Ungroup the windows if only one window is left");    o->longDesc = N_("If there is only 1 window in the group left, it will be ungrouped.");    o->type = CompOptionTypeBool;    o->value.b = GROUP_AUTO_UNGROUP_DEFAULT;    o = &gs->opt[GROUP_SCREEN_OPTION_RELATIVE_DISTANCE];    o->name = "relative_distance";    o->group = N_("");    o->subGroup = N_("");    o->displayHints = "";    o->shortDesc = N_("Compute distance relative");    o->longDesc = N_("The distance between the windows is computed relative to the window size. "                      "This allows you to have windows staying next to eachother.");    o->type = CompOptionTypeBool;    o->value.b = GROUP_RELATIVE_DISTANCE_DEFAULT;    o             = &gs->opt[GROUP_SCREEN_OPTION_SELECTION_COLOR];    o->name       = "fill_color";    o->group      = N_("");    o->subGroup   = N_("");    o->displayHints = "";    o->shortDesc  = N_("Selection Color");    o->longDesc   = N_("Fill color of the selection.");    o->type       = CompOptionTypeColor;    o->value.c[0] = GROUP_COLOR_SELECTION_RED_DEFAULT;    o->value.c[1] = GROUP_COLOR_SELECTION_GREEN_DEFAULT;    o->value.c[2] = GROUP_COLOR_SELECTION_BLUE_DEFAULT;    o->value.c[3] = GROUP_COLOR_SELECTION_ALPHA_DEFAULT;    o             = &gs->opt[GROUP_SCREEN_OPTION_LINE_COLOR];    o->name       = "line_color";    o->group      = N_("");    o->subGroup   = N_("");    o->displayHints = "";    o->shortDesc  = N_("Line Color");    o->longDesc   = N_("Line color of the selection.");    o->type       = CompOptionTypeColor;    o->value.c[0] = GROUP_COLOR_LINE_RED_DEFAULT;    o->value.c[1] = GROUP_COLOR_LINE_GREEN_DEFAULT;    o->value.c[2] = GROUP_COLOR_LINE_BLUE_DEFAULT;    o->value.c[3] = GROUP_COLOR_LINE_ALPHA_DEFAULT;}/* * groupGetScreenOptions * */static CompOption *groupGetScreenOptions (CompScreen *s, int *count){    if (s)    {        GROUP_SCREEN (s);            *count = NUM_OPTIONS (gs);        return gs->opt;    }    else    {        GroupScreen *gs = malloc (sizeof (GroupScreen));        groupScreenInitOptions (gs);        *count = NUM_OPTIONS (gs);        return gs->opt;    }}/* * groupSetScreenOption * */static BoolgroupSetScreenOption (CompScreen *s, char *name, CompOptionValue *value){    CompOption *o;    int         index;    GROUP_SCREEN (s);    o = compFindOption (gs->opt, NUM_OPTIONS (gs), name, &index);    if (!o)        return FALSE;    switch (index)     {        case GROUP_SCREEN_OPTION_TYPES:        if (compSetOptionList (o, value))        {            gs->wMask = compWindowTypeMaskFromStringList (&o->value);            return TRUE;        }        break;        case GROUP_SCREEN_OPTION_SELECTION_COLOR:        case GROUP_SCREEN_OPTION_LINE_COLOR:        if (compSetColorOption (o, value))        {            return TRUE;        }        break;        case GROUP_SCREEN_OPTION_OPACITY:        case GROUP_SCREEN_OPTION_BRIGHTNESS:        case GROUP_SCREEN_OPTION_SATURATION:        case GROUP_SCREEN_OPTION_TOLERANCE:        case GROUP_SCREEN_OPTION_STEPS:        if (compSetIntOption (o, value)) {            return TRUE;        }        break;        case GROUP_SCREEN_OPTION_MOVE:        case GROUP_SCREEN_OPTION_RESIZE:        case GROUP_SCREEN_OPTION_RAISE:        case GROUP_SCREEN_OPTION_AUTO_UNGROUP:        case GROUP_SCREEN_OPTION_AUTO_GROUP:        case GROUP_SCREEN_OPTION_RELATIVE_DISTANCE:        if (compSetBoolOption (o, value)) {            return TRUE;        }        break;        default:            break;    }        return FALSE;}/* * groupSelectWindow * */static voidgroupSelectWindow (CompDisplay *d, CompWindow *w){    GROUP_DISPLAY (d);    GROUP_SCREEN (w->screen);    GROUP_WINDOW (w);    // select singe window    if ((gs->wMask & w->type) &&        !w->invisible &&        !gw->inSelection &&        !gw->inGroup)    {       groupAddWindowToSelection (d, w);        gw->inSelection = TRUE;       addWindowDamage (w);    }    // unselect single window    else if ((gs->wMask & w->type) &&             !w->invisible &&             gw->inSelection &&             !gw->inGroup)    {           groupDeleteSelectionWindow (d, w);                gw->inSelection = FALSE;        addWindowDamage (w);    }    // select group    else if ((gs->wMask & w->type) &&             !w->invisible &&             !gw->inSelection &&             gw->inGroup)    {        int index = groupFindGroupAtDisplay (gd, gw->groupID);        if (index == -1)            return;                int i;        for (i = 0; i < gd->groups[index].nWins; i++)        {             CompWindow *cw = findWindowAtDisplay (d, gd->groups[index].windows[i]);             if (!cw)                 continue;             GROUP_WINDOW (cw);                         groupAddWindowToSelection (d, cw);                         gw->inSelection = TRUE;             addWindowDamage (cw);        }    }    // Unselect group    else if ((gs->wMask & w->type) &&             !w->invisible &&             gw->inSelection &&             gw->inGroup)    {         int index = groupFindGroupAtDisplay (gd, gw->groupID);         if (index == -1)             return;         Window *buf = gd->tmpSel.windows;         gd->tmpSel.windows = (Window*) calloc (gd->tmpSel.nWins - gd->groups[index].nWins, sizeof (Window));         int counter = 0;         int i;         for (i = 0; i < gd->tmpSel.nWins; i++)         {              CompWindow *cw = findWindowAtDisplay (d, buf[i]);              if (!cw)                  continue;              GROUP_WINDOW (cw);                          if (gw->inGroup && gw->groupID == gd->groups[index].id)              {                  gw->inSelection = FALSE;                  addWindowDamage (cw);                  continue;              }              gd->tmpSel.windows[counter++] = buf[i];          }          gd->tmpSel.nWins = counter;          free (buf);    }}/* * groupSelectSingle * */static BoolgroupSelectSingle (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption){    CompWindow *w = (CompWindow*) findWindowAtDisplay (d, d->activeWindow);    if (w)        groupSelectWindow(d, w);    return TRUE;}/* * groupSelect * */static BoolgroupSelect (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption){    CompWindow *w = (CompWindow*) findWindowAtDisplay (d, d->activeWindow);    if (!w)         return FALSE;    GROUP_SCREEN (w->screen);        if(!gs->grab)    {        if (otherScreenGrabExist (w->screen, "group", 0))            return FALSE;        if (!gs->grabIndex)            gs->grabIndex = pushScreenGrab (w->screen, None, "group");        if (state & CompActionStateInitKey)            action->state |= CompActionStateTermKey;        if (state & CompActionStateInitButton)            action->state |= CompActionStateTermButton;        gs->x1 = gs->x2 = d->pointerX;        gs->y1 = gs->y2 = d->pointerY;        gs->grab = TRUE;     }    return TRUE;}/* * groupGroupWindows - pre-definition for groupSelectTerminate * */static BoolgroupGroupWindows (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption);/* * groupSelectTerminate * */static BoolgroupSelectTerminate (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption){    CompScreen *s;    Window xid;    xid = getIntOptionNamed (option, nOption, "root", 0);    for (s = d->screens; s; s = s->next)    {        if (xid && s->root != xid)            continue;        break;    }    if (s) {        GROUP_SCREEN(s);    if(gs->grab)    {        if(gs->grabIndex)        {            removeScreenGrab (s, gs->grabIndex, NULL);            gs->grabIndex = 0;        }        if (gs->x1 != gs->x2 &&            gs->y1 != gs->y2)        {            REGION reg;            reg.rects = &reg.extents;            reg.numRects = 1;            reg.extents.x1 = MIN (gs->x1, gs->x2) - 1;            reg.extents.y1 = MIN (gs->y1, gs->y2) - 1;            reg.extents.x2 = MAX (gs->x1, gs->x2) + 1;            reg.extents.y2 = MAX (gs->y1, gs->y2) + 1;            damageScreenRegion (s, &reg);            int count;            Window *ws = groupFindWindowsInRegion (s, reg, &count);            if (ws) {            // select windows            int i;            for (i = 0; i < count; i++)            {                CompWindow *cw = findWindowAtDisplay (d, ws[i]);                if (!cw)                    continue;                groupSelectWindow(d, cw);            }            if (gs->opt[GROUP_SCREEN_OPTION_AUTO_GROUP].value.b)            {                groupGroupWindows(d, NULL, 0, NULL, 0);            }                free(ws);            }        }                gs->grab = FALSE;    }    }    action->state &= ~(CompActionStateTermKey | CompActionStateTermButton);    return FALSE;}/* * groupGroupWindows * */static BoolgroupGroupWindows (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption){    GROUP_DISPLAY (d);    if (gd->tmpSel.nWins > 0)    {        int id = gd->nGroups;        int index = groupFindGroupAtDisplay (gd, id);        while (index != -1) {            id++;            index = groupFindGroupAtDisplay (gd, id);        }        int i;        for (i = 0; i < gd->tmpSel.nWins; i++)        {            CompWindow* cw = (CompWindow*) findWindowAtDisplay (d, gd->tmpSel.windows[i]);            if (!cw)                continue;            GROUP_WINDOW (cw);            groupAddWindowToGroup(d, cw, id);            gw->inSelection = FALSE;            addWindowDamage (cw);        }        // exit selection        free (gd->tmpSel.windows);        gd->tmpSel.windows = NULL;        gd->tmpSel.nWins = 0;    }    return FALSE;}/* * groupUnGroupWindows * */static BoolgroupUnGroupWindows (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption){    CompWindow *cw = findWindowAtDisplay (d, d->activeWindow);    if (!cw)        return FALSE;    GROUP_WINDOW (cw);    if (gw->inGroup)        groupDeleteGroup (d, gw->groupID);    return FALSE;}/* * groupInitTab * */static BoolgroupInitTab (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption){    GROUP_DISPLAY (d);    CompWindow *w = findWindowAtDisplay (d, d->activeWindow);    if (!w)        return FALSE;        GROUP_WINDOW (w);    if (!gw->inGroup)        return FALSE;    int index = groupFindGroupAtDisplay (gd, gw->groupID);    if (index == -1)        return FALSE;    if (gd->groups[index].tabbed) {        groupUntabGroup (d, w, gw->groupID);    } else {        groupTabGroup (d, w, gw->groupID);    }    return TRUE;}/* * groupChangeTab * */static BoolgroupChangeTab (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption){    GROUP_DISPLAY (d);    CompWindow *w = findWindowAtDisplay (d, d->activeWindow);    if (!w)        return FALSE;    GROUP_SCREEN (w->screen);        GroupWindow *mgw = GET_GROUP_WINDOW (w, gs);    if (!mgw->inGroup)        return FALSE;    int index = groupFindGroupAtDisplay (gd, mgw->groupID);    if (index == -1)        return FALSE;    if (gd->groups[index].tabbed)    {         int i;        for (i = 0; i < gd->groups[index].nWins; i++)        {            CompWindow *cw = findWindowAtDisplay (d, gd->groups[index].windows[i]);            if (!cw || cw->id == w->id)                continue;            GROUP_WINDOW (cw);            if (gw->inGroup &&                gw->groupID == mgw->groupID)            {                cw->hidden = FALSE;                showWindow (cw);                raiseWindow (cw);                lowerWindow (w);                w->hidden = TRUE;                hideWindow (w);                moveInputFocusToWindow (cw);                groupSyncWindows (d, gw->groupID);                gd->groups[index].topTab = cw;                break;            }        }    }    return TRUE;}/* * groupRemoveWindow * */static BoolgroupRemoveWindow (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption){    CompWindow *cw = findWindowAtDisplay (d, d->activeWindow);    if (!cw)        return FALSE;    GROUP_WINDOW (cw);    if (gw->inGroup)        groupDeleteGroupWindow (d, cw);    return FALSE;}/* * groupCloseWindows * */static BoolgroupCloseWindows (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption){    CompWindow *w = findWindowAtDisplay (d, d->activeWindow);    if (!w)        return FALSE;    GROUP_WINDOW (w);    GROUP_DISPLAY (w->screen->display);    if (gw->inGroup)    {        int index = groupFindGroupAtDisplay (gd, gw->groupID);        if (index == -1)            return FALSE;        int nWins = gd->groups[index].nWins;        int i;        for (i = 0; i < nWins; i++)        {            CompWindow *cw = findWindowAtDisplay (d, gd->groups[index].windows[i]);            if (!cw)                continue;            closeWindow (cw, getCurrentTimeFromDisplay (d));        }    }    return FALSE;}/* * groupMinimizeWindows * */static BoolgroupMinimizeWindows (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption){    CompWindow *w = findWindowAtDisplay (d, d->activeWindow);    if (!w)        return FALSE;    GROUP_WINDOW (w);    GROUP_DISPLAY (w->screen->display);    if (gw->inGroup)    {        int index = groupFindGroupAtDisplay (gd, gw->groupID);        if (index == -1)            return FALSE;        int nWins = gd->groups[index].nWins;        int i;        for (i = 0; i < nWins; i++)        {            CompWindow *cw = findWindowAtDisplay (d, gd->groups[index].windows[i]);            if (!cw)                continue;            minimizeWindow (cw);        }    }    return FALSE;}/* * groupSetIgnore * */static BoolgroupSetIgnore (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption){    GROUP_DISPLAY (d);    gd->ignoreMode = TRUE;    if (state & CompActionStateInitKey)        action->state |= CompActionStateTermKey;    return FALSE;}/* * groupUnsetIgnore * */static BoolgroupUnsetIgnore (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption){    GROUP_DISPLAY (d);    gd->ignoreMode = FALSE;    action->state &= ~CompActionStateTermKey;    return FALSE;}/* * groupHandleMotionEvent - pre-definition for groupHandleEvent * */static voidgroupHandleMotionEvent (CompScreen *s, int xRoot, int yRoot);/* * groupHandleEvent * */static voidgroupHandleEvent (CompDisplay *d, XEvent *event){    GROUP_DISPLAY (d);    switch (event->type)     {        case MotionNotify:            {                CompScreen *s = findScreenAtDisplay (d, event->xmotion.root);                if (s)                    groupHandleMotionEvent (s, d->pointerX, d->pointerY);                break;            }        case ButtonRelease:            // update windows            if (event->xbutton.button == 1)            {                if (gd->inAction && gd->lastActiveGroup != -1) {                    groupSyncWindows (d, gd->lastActiveGroup);                    gd->lastActiveGroup = -1;                    gd->inAction = FALSE;                }            }            break;        case UnmapNotify:            {                CompWindow *w = findWindowAtDisplay (d, event->xunmap.window);                if (!w)                    break;                GROUP_WINDOW (w);                // close event                if (gw->inGroup && !w->pendingUnmaps) {                    groupDeleteGroupWindow (d, w);                }                break;            }        default:            break;    }    UNWRAP (gd, d, handleEvent);    (*d->handleEvent) (d, event);    WRAP (gd, d, handleEvent, groupHandleEvent);    switch (event->type)    {        case PropertyNotify:            // focus event            if (event->xproperty.atom == d->winActiveAtom)            {                if (!gd->inAction)                {                    CompWindow *w = (CompWindow*) findWindowAtDisplay (d, d->activeWindow);                    if (!w)                         break;                    GROUP_WINDOW (w);                    GROUP_SCREEN (w->screen);                    if (gw->inGroup &&                        !IPCS_GetBoolND (IPCS_OBJECT (w->screen->display), "SCALE_INIT", FALSE) &&                        gs->opt[GROUP_SCREEN_OPTION_RAISE].value.b)                    {                        groupRaiseWindows (d, w, gw->groupID);                    }                }            }            break;        default:            break;    }}/* * groupWindowMoveNotify * */static void groupWindowMoveNotify (CompWindow *w, int dx, int dy, Bool immediate){    GROUP_SCREEN (w->screen);    GROUP_DISPLAY (w->screen->display);    GROUP_WINDOW (w);        UNWRAP (gs, w->screen, windowMoveNotify);    (*w->screen->windowMoveNotify) (w, dx, dy, immediate);    WRAP (gs, w->screen, windowMoveNotify, groupWindowMoveNotify);    // workaround for viewports    Bool vpMove = FALSE;    if ( (dx % w->screen->workArea.width == 0 && dx != 0) ||        (dy % w->screen->workArea.height == 0 && dy != 0))    {        vpMove = TRUE;    }       if (gw->inGroup &&       !gw->animate &&       !vpMove &&        !IPCS_GetBoolND (IPCS_OBJECT (w), "SHOWDESKTOP_MOVE", FALSE) &&        !IPCS_GetBoolND (IPCS_OBJECT (w->screen->display), "SCALE_INIT", FALSE) &&       gs->opt[GROUP_SCREEN_OPTION_MOVE].value.b &&       !gd->ignoreMode)    {        int index = groupFindGroupAtDisplay (gd, gw->groupID);        if (index != -1)        {            int i;            for (i = 0; i < gd->groups[index].nWins; i++)            {                CompWindow *cw = findWindowAtDisplay (w->screen->display, gd->groups[index].windows[i]);                if (!cw)                    continue;                if (cw->id != w->id)                {                    UNWRAP (gs, cw->screen, windowMoveNotify);                    moveWindow (cw, dx, dy, TRUE, FALSE);                    WRAP (gs, cw->screen, windowMoveNotify, groupWindowMoveNotify);                                        groupUpdatePosBuffer (cw,  WIN_X (cw) + dx, WIN_Y (cw) + dy, WIN_WIDTH (cw), WIN_HEIGHT (cw));                }            }        }        gd->lastActiveGroup = gw->groupID;        gd->inAction = TRUE;    }        groupUpdatePosBuffer (w,  WIN_X (w) + dx, WIN_Y (w) + dy, WIN_WIDTH (w), WIN_HEIGHT (w));}/* * groupWindowResizeNotify * */static void groupWindowResizeNotify (CompWindow *w){    GROUP_SCREEN (w->screen);    GROUP_DISPLAY (w->screen->display);    GROUP_WINDOW (w);    UNWRAP (gs, w->screen, windowResizeNotify);    (*w->screen->windowResizeNotify) (w);    WRAP (gs, w->screen, windowResizeNotify, groupWindowResizeNotify);    if (gw->inGroup && !gd->ignoreMode &&       gs->opt[GROUP_SCREEN_OPTION_RESIZE].value.b)    {        int rw = WIN_WIDTH (w) - gw->oldWidth;        int rh = WIN_HEIGHT (w) - gw->oldHeight;        int rx = WIN_X (w) - gw->oldX;        int ry = WIN_Y (w) - gw->oldY;        int index = groupFindGroupAtDisplay (gd, gw->groupID);        if (index != -1)        {            int i;            for (i = 0; i < gd->groups[index].nWins; i++)            {                CompWindow *cw = findWindowAtDisplay (w->screen->display, gd->groups[index].windows[i]);                if (!cw)                    continue;                if (cw->id != w->id)                {                                        UNWRAP (gs, cw->screen, windowResizeNotify);                    UNWRAP (gs, cw->screen, windowMoveNotify);                    int nx = 0;                    int ny = 0;                    if (gs->opt[GROUP_SCREEN_OPTION_RELATIVE_DISTANCE].value.b)                    {                        int distX = WIN_X (cw) - gw->oldX;                        int distY = WIN_Y (cw) - gw->oldY;                        int ndistX = distX * ( (float) WIN_WIDTH (w) / (float) gw->oldWidth);                        int ndistY = distY * ( (float) WIN_HEIGHT (w) / (float) gw->oldHeight);                        nx = WIN_X (w) + ndistX;                        ny = WIN_Y (w) + ndistY;                    }                    else                    {                        nx = WIN_X (cw) + rx;                        ny = WIN_Y (cw) + ry;                    }                    int nwidth = WIN_WIDTH (cw) + rw;                    int nheight = WIN_HEIGHT (cw) + rh;                    XWindowChanges xwc;                    xwc.x = nx;                    xwc.y = ny;                    xwc.width = nwidth;                    xwc.height = nheight;                    configureXWindow (cw, CWX | CWY | CWWidth | CWHeight, &xwc);                    resizeWindow (cw, nx, ny, nwidth, nheight, WIN_BORDER (cw));                    groupUpdatePosBuffer (cw, nx, ny, nwidth, nheight);                    WRAP (gs, cw->screen, windowMoveNotify, groupWindowMoveNotify);                    WRAP (gs, cw->screen, windowResizeNotify, groupWindowResizeNotify);                }            }            gd->lastActiveGroup = gw->groupID;            gd->inAction = TRUE;        }    }        groupUpdatePosBuffer (w,  WIN_X (w), WIN_Y (w), WIN_WIDTH (w), WIN_HEIGHT (w));}/* * groupDrawTabAnimation * */static voidgroupDrawTabAnimation (CompScreen *s){    GROUP_SCREEN  (s);    GROUP_DISPLAY (s->display);    int index = groupFindGroupAtDisplay (gd, gd->animatedGroup);    if (index == -1)        return;    int stepX, stepY;    int i;    for (i = 0; i < gd->groups[index].nWins; i++)    {        CompWindow *cw = findWindowAtDisplay (s->display, gd->groups[index].windows[i]);        if(!cw)            continue;        GROUP_WINDOW (cw);        if (!gw->steps && gw->animate)        {           gw->animate = FALSE;           gd->animatedGroup = -1;           if (gd->groups[index].tabbed &&               gd->groups[index].topTab != NULL &&               gd->groups[index].topTab->id != cw->id)           {                cw->hidden = TRUE;                hideWindow (cw);                                                unsigned int state = getWindowState (s->display, cw->id);                state |= CompWindowStateSkipTaskbarMask;                state |= CompWindowStateSkipPagerMask;                setWindowState (s->display, state, cw->id);           }        }                if (gw->animate)        {            stepX = (gw->destinationX - WIN_X (cw)) / gw->steps;            stepY = (gw->destinationY - WIN_Y (cw)) / gw->steps;            UNWRAP (gs, cw->screen, windowMoveNotify);            moveWindow (cw, stepX, stepY, TRUE, FALSE);            WRAP (gs, cw->screen, windowMoveNotify, groupWindowMoveNotify);                      gw->steps--;        }        // last window and animation has finished        if (i == gd->groups[index].nWins-1 && gd->animatedGroup == -1)        {            groupSyncWindows (s->display, gw->groupID);            if (gd->groups[index].topTab)                raiseWindow (gd->groups[index].topTab);        }    }}#define THUMB_SIZE 128#define SPACING 20 #define BORDER_COLOR 0.0f, 0.0f, 0.0f, 1.0f#define BAR_COLOR 0.8f, 0.8f, 0.8f, 0.5f#define BORDER_WIDTH 5#define CIRCLE_POINTS 25#define REAL_POSITION(x, s) ( (x >= 0)? x: x + (s)->hsize * (s)->width )#define VIEWPORT(x, s) ( ( REAL_POSITION(x, s) / (s)->width ) % (s)->hsize )/* * groupPaintThumb - taken from switcher and modified for tab bar * */static voidgroupPaintThumb (CompWindow *w,         const WindowPaintAttrib * attrib,         unsigned int mask,         int tx, int ty, int tw, int th){    DrawWindowGeometryProc oldDrawWindowGeometry;    WindowPaintAttrib sAttrib = *attrib;    /* Wrap drawWindowGeometry to make sure the general       drawWindowGeometry function is used */    oldDrawWindowGeometry = w->screen->drawWindowGeometry;    w->screen->drawWindowGeometry = getBaseDrawWindowGeometry();    mask |= PAINT_WINDOW_TRANSFORMED_MASK;    if (w->mapNum) {        if (WIN_WIDTH (w) > tw)            sAttrib.xScale = (float) tw / WIN_WIDTH (w);        else            sAttrib.xScale = 1.0f;        if (WIN_HEIGHT (w) > th)            sAttrib.yScale = (float) tw / WIN_HEIGHT (w);        else            sAttrib.yScale = 1.0f;        /*        if (sAttrib.xScale < sAttrib.yScale)            sAttrib.yScale = sAttrib.xScale;        else            sAttrib.xScale = sAttrib.yScale;        */        float nx = tx/* * sAttrib.xScale*/;        float ny = ty/* * sAttrib.yScale*/;        sAttrib.xTranslate = nx;        sAttrib.yTranslate = ny;        (w->screen->drawWindow) (w, &sAttrib, getInfiniteRegion(),                     mask);    }    w->screen->drawWindowGeometry = oldDrawWindowGeometry;}/* * groupPaintTabBar * */static void groupPaintTabBar (CompScreen *s, GroupSelection* group,                  const WindowPaintAttrib * attrib,                  unsigned int mask){    GROUP_SCREEN (s);    if(!group->tabbed)        return;        if(VIEWPORT(group->topTab->attrib.x, group->topTab->screen))        return;    glDisableClientState (GL_TEXTURE_COORD_ARRAY);    glEnable (GL_BLEND);        int x1, x2, y1, y2, width, height;    width = BORDER_WIDTH * (group->nWins+1) + THUMB_SIZE * group->nWins;    height = BORDER_WIDTH * 2 + THUMB_SIZE;    x1 = WIN_X (group->topTab) + WIN_WIDTH (group->topTab) / 2 - width / 2;    y1 = WIN_Y (group->topTab) + 10;    x2 = x1 + width;    y2 = y1 + height;    // for testing use the option of select    glColor4usv (gs->opt[GROUP_SCREEN_OPTION_SELECTION_COLOR].value.c);    glBegin (GL_QUADS);        glVertex2i (x1, y1);        glVertex2i (x1, y2);        glVertex2i (x2, y2);        glVertex2i (x2, y1);    glEnd ();    // draw thumbs    int i;    for (i = 0; i < group->nWins; i++)    {        CompWindow *cw = findWindowAtDisplay (s->display, group->windows[i]);        if (!cw)            continue;        // calculate coords        int tx1, ty1;        tx1 = x1 + BORDER_WIDTH;        ty1 = y1;        tx1 += (THUMB_SIZE + BORDER_WIDTH) * i;        ty1 += BORDER_WIDTH;        groupPaintThumb (cw, attrib, mask, tx1, ty1, THUMB_SIZE, THUMB_SIZE);    }        glColor4usv (defaultColor);      glDisable (GL_BLEND);    glEnableClientState (GL_TEXTURE_COORD_ARRAY);            addWindowDamage(group->topTab);}/* * groupPreparePaintScreen * */static void groupPreparePaintScreen (CompScreen *s, int msSinceLastPaint){    GROUP_SCREEN (s);    UNWRAP (gs, s, preparePaintScreen);    (*s->preparePaintScreen) (s, msSinceLastPaint);    WRAP (gs, s, preparePaintScreen, groupPreparePaintScreen);    groupDrawTabAnimation (s);    }/*  * groupPaintScreen * */static BoolgroupPaintScreen (CompScreen * s,                  const ScreenPaintAttrib * sAttrib,                 Region region, int output, unsigned int mask){    GROUP_SCREEN  (s);    GROUP_DISPLAY (s->display);    Bool status;    gs->wasTransformed = FALSE;    //mask &= ~PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK;    //mask |= PAINT_SCREEN_ORDER_BACK_TO_FRONT_MASK;    UNWRAP (gs, s, paintScreen);    status = (*s->paintScreen) (s, sAttrib, region, output, mask);    WRAP (gs, s, paintScreen, groupPaintScreen);    if (status &&        gs->grab &&        !gs->wasTransformed)    {        int x1, x2, y1, y2;        x1 = MIN (gs->x1, gs->x2);        y1 = MIN (gs->y1, gs->y2);        x2 = MAX (gs->x1, gs->x2);        y2 = MAX (gs->y1, gs->y2);        if (gs->grabIndex)        {            glPushMatrix ();            prepareXCoords (s, output, -DEFAULT_Z_CAMERA);            glDisableClientState (GL_TEXTURE_COORD_ARRAY);            glEnable (GL_BLEND);            glColor4usv (gs->opt[GROUP_SCREEN_OPTION_SELECTION_COLOR].value.c);            glRecti (x1, y2, x2, y1);            glColor4usv (gs->opt[GROUP_SCREEN_OPTION_LINE_COLOR].value.c);            glBegin (GL_LINE_LOOP);            glVertex2i (x1, y1);            glVertex2i (x2, y1);            glVertex2i (x2, y2);            glVertex2i (x1, y2);            glEnd ();            glColor4usv (defaultColor);            glDisable (GL_BLEND);            glEnableClientState (GL_TEXTURE_COORD_ARRAY);            glPopMatrix ();        }    }    // for the animation    if(gd->animatedGroup != -1)        damageScreen (s);    return status;}/*  * groupPaintTransformedScreen * */static voidgroupPaintTransformedScreen (CompScreen * s, const ScreenPaintAttrib * sa,                              Region region, int output, unsigned int mask){    GROUP_SCREEN (s);    UNWRAP (gs, s, paintTransformedScreen);    (*s->paintTransformedScreen) (s, sa, region, output, mask);    WRAP (gs, s, paintTransformedScreen, groupPaintTransformedScreen);    if (gs->grab)    {        gs->wasTransformed = TRUE;        int x1, x2, y1, y2;        x1 = MIN (gs->x1, gs->x2);        y1 = MIN (gs->y1, gs->y2);        x2 = MAX (gs->x1, gs->x2);        y2 = MAX (gs->y1, gs->y2);        if (gs->grabIndex)        {            glPushMatrix ();            glLoadIdentity();            (s->applyScreenTransform) (s, sa, output);            prepareXCoords(s, output, -sa->zTranslate);            glDisableClientState (GL_TEXTURE_COORD_ARRAY);            glEnable (GL_BLEND);            glColor4usv (gs->opt[GROUP_SCREEN_OPTION_SELECTION_COLOR].value.c);            glRecti (x1, y2, x2, y1);            glColor4usv (gs->opt[GROUP_SCREEN_OPTION_LINE_COLOR].value.c);            glBegin (GL_LINE_LOOP);            glVertex2i (x1, y1);            glVertex2i (x2, y1);            glVertex2i (x2, y2);            glVertex2i (x1, y2);            glEnd ();            glColor4usv (defaultColor);            glDisable (GL_BLEND);            glEnableClientState (GL_TEXTURE_COORD_ARRAY);            glPopMatrix ();        }    }}/* * groupDrawWindow * */static BoolgroupPaintWindow (CompWindow * w,                  const WindowPaintAttrib * attrib,                  Region region, unsigned int mask){    Bool status;    GROUP_WINDOW  (w);    GROUP_SCREEN  (w->screen);    GROUP_DISPLAY (w->screen->display);    WindowPaintAttrib gAttrib = *attrib;    if (gw->inSelection)    {        int opacity = gs->opt[GROUP_SCREEN_OPTION_OPACITY].value.i;        int saturation = gs->opt[GROUP_SCREEN_OPTION_SATURATION].value.i;        int brightness = gs->opt[GROUP_SCREEN_OPTION_BRIGHTNESS].value.i;                opacity = OPAQUE * opacity / 100;        saturation = COLOR * saturation / 100;        brightness = BRIGHT * brightness / 100;                gAttrib.opacity = opacity;        gAttrib.saturation = saturation;        gAttrib.brightness = brightness;    }       UNWRAP (gs, w->screen, paintWindow);    status = (*w->screen->paintWindow) (w, &gAttrib, region, mask);    WRAP (gs, w->screen, paintWindow, groupPaintWindow);        int index = groupFindGroupAtDisplay (gd, gw->groupID);    if (index != -1)        groupPaintTabBar(w->screen, &gd->groups[index], &gAttrib, mask);    return status;}/* * groupHandleMotionEvent * */static voidgroupHandleMotionEvent (CompScreen * s, int xRoot, int yRoot){    GROUP_SCREEN (s);    if (gs->grab && gs->grabIndex)    {        REGION reg;        reg.rects = &reg.extents;        reg.numRects = 1;        reg.extents.x1 = MIN (gs->x1, gs->x2) - 1;        reg.extents.y1 = MIN (gs->y1, gs->y2) - 1;        reg.extents.x2 = MAX (gs->x1, gs->x2) + 1;        reg.extents.y2 = MAX (gs->y1, gs->y2) + 1;        damageScreenRegion (s, &reg);        gs->x2 = xRoot;        gs->y2 = yRoot;        reg.extents.x1 = MIN (gs->x1, gs->x2) - 1;        reg.extents.y1 = MIN (gs->y1, gs->y2) - 1;        reg.extents.x2 = MAX (gs->x1, gs->x2) + 1;        reg.extents.y2 = MAX (gs->y1, gs->y2) + 1;        damageScreenRegion (s, &reg);    }}/* * groupDisplayInitOptions  * */static voidgroupDisplayInitOptions (GroupDisplay *gd){    CompOption *o;    o = &gd->opt[GROUP_DISPLAY_OPTION_SELECT];    o->name                             = "select";    o->group                            = N_("");    o->subGroup                         = N_("");    o->displayHints                     = "";    o->shortDesc                        = N_("Select");    o->longDesc                         = N_("The key for starting selecting windows.");    o->type                             = CompOptionTypeAction;    o->value.action.initiate            = groupSelect;    o->value.action.terminate           = groupSelectTerminate;    o->value.action.bell                = FALSE;    o->value.action.edgeMask            = 0;    o->value.action.state               = CompActionStateInitButton;       o->value.action.type                = CompBindingTypeButton;    o->value.action.button.modifiers    = GROUP_SELECT_MODIFIERS_DEFAULT;    o->value.action.button.button       = GROUP_SELECT_BUTTON_DEFAULT;    o = &gd->opt[GROUP_DISPLAY_OPTION_SELECT_SINGLE];    o->name                             = "select_single";    o->group                            = N_("");    o->subGroup                         = N_("");    o->displayHints                     = "";    o->shortDesc                        = N_("Select single window");    o->longDesc                         = N_("The key for selecting the current window.");    o->type                             = CompOptionTypeAction;    o->value.action.initiate            = groupSelectSingle;    o->value.action.terminate           = 0;    o->value.action.bell                = FALSE;    o->value.action.edgeMask            = 0;    o->value.action.state               = CompActionStateInitKey;       o->value.action.type                = CompBindingTypeKey;    o->value.action.key.modifiers       = GROUP_SELECT_SINGLE_MODIFIERS_DEFAULT;    o->value.action.key.keysym          = XStringToKeysym (GROUP_SELECT_SINGLE_KEY_DEFAULT);    o = &gd->opt[GROUP_DISPLAY_OPTION_GROUPING];    o->name                             = "group";    o->group                            = N_("");    o->subGroup                         = N_("");    o->displayHints                     = "";    o->shortDesc                        = N_("Group");    o->longDesc                         = N_("The key for grouing windows.");    o->type                             = CompOptionTypeAction;    o->value.action.initiate            = groupGroupWindows;    o->value.action.terminate           = 0;    o->value.action.bell                = FALSE;    o->value.action.edgeMask            = 0;    o->value.action.state               = CompActionStateInitKey;    o->value.action.type                = CompBindingTypeKey;    o->value.action.key.modifiers       = GROUP_GROUPING_MODIFIERS_DEFAULT;    o->value.action.key.keysym          = XStringToKeysym (GROUP_GROUPING_KEY_DEFAULT);    o = &gd->opt[GROUP_DISPLAY_OPTION_UNGROUPING];    o->name                             = "ungroup";    o->group                            = N_("");    o->subGroup                         = N_("");    o->displayHints                     = "";    o->shortDesc                        = N_("Ungroup");    o->longDesc                         = N_("The key for ungrouing windows.");    o->type                             = CompOptionTypeAction;    o->value.action.initiate            = groupUnGroupWindows;    o->value.action.terminate           = 0;    o->value.action.bell                = FALSE;    o->value.action.edgeMask            = 0;    o->value.action.state               = CompActionStateInitKey;     o->value.action.type                = CompBindingTypeKey;    o->value.action.key.modifiers       = GROUP_UNGROUPING_MODIFIERS_DEFAULT;    o->value.action.key.keysym          = XStringToKeysym (GROUP_UNGROUPING_KEY_DEFAULT);    o = &gd->opt[GROUP_DISPLAY_OPTION_TABMODE];    o->name                             = "tabmode";    o->group                            = N_("");    o->subGroup                         = N_("");    o->displayHints                     = "";    o->shortDesc                        = N_("Tab");    o->longDesc                         = N_("The key for entering the tab mode.");    o->type                             = CompOptionTypeAction;    o->value.action.initiate            = groupInitTab;    o->value.action.terminate           = 0;    o->value.action.bell                = FALSE;    o->value.action.edgeMask            = 0;    o->value.action.state               = CompActionStateInitKey;    o->value.action.type                = CompBindingTypeKey;    o->value.action.key.modifiers       = GROUP_TABMODE_MODIFIERS_DEFAULT;    o->value.action.key.keysym          = XStringToKeysym (GROUP_TABMODE_KEY_DEFAULT);    o = &gd->opt[GROUP_DISPLAY_OPTION_CHANGE_TAB];    o->name                             = "change_tab";    o->group                            = N_("");    o->subGroup                         = N_("");    o->displayHints                     = "";    o->shortDesc                        = N_("Change Tab");    o->longDesc                         = N_("The key for changing the tab.");    o->type                             = CompOptionTypeAction;    o->value.action.initiate            = groupChangeTab;    o->value.action.terminate           = 0;    o->value.action.bell                = FALSE;    o->value.action.edgeMask            = 0;    o->value.action.state               = CompActionStateInitKey;    o->value.action.type                = CompBindingTypeKey;    o->value.action.key.modifiers       = GROUP_CHANGE_TAB_MODIFIERS_DEFAULT;    o->value.action.key.keysym          = XStringToKeysym (GROUP_CHANGE_TAB_KEY_DEFAULT);    o = &gd->opt[GROUP_DISPLAY_OPTION_REMOVEING];    o->name                             = "remove";    o->group                            = N_("");    o->subGroup                         = N_("");    o->displayHints                     = "";    o->shortDesc                        = N_("Remove Window");    o->longDesc                         = N_("The key for removing the selected window.");    o->type                             = CompOptionTypeAction;    o->value.action.initiate            = groupRemoveWindow;    o->value.action.terminate           = 0;    o->value.action.bell                = FALSE;    o->value.action.edgeMask            = 0;    o->value.action.state               = CompActionStateInitKey;      o->value.action.type                = CompBindingTypeKey;    o->value.action.key.modifiers       = GROUP_REMOVEING_MODIFIERS_DEFAULT;    o->value.action.key.keysym          = XStringToKeysym (GROUP_REMOVEING_KEY_DEFAULT);    o = &gd->opt[GROUP_DISPLAY_OPTION_CLOSEING];    o->name                             = "close";    o->group                            = N_("");    o->subGroup                         = N_("");    o->displayHints                     = "";    o->shortDesc                        = N_("Close Windows");    o->longDesc                         = N_("The key for closing all windows in the group.");    o->type                             = CompOptionTypeAction;    o->value.action.initiate            = groupCloseWindows;    o->value.action.terminate           = 0;    o->value.action.bell                = FALSE;    o->value.action.edgeMask            = 0;    o->value.action.state               = CompActionStateInitKey;      o->value.action.type                = CompBindingTypeKey;    o->value.action.key.modifiers       = GROUP_CLOSEING_MODIFIERS_DEFAULT;    o->value.action.key.keysym          = XStringToKeysym (GROUP_CLOSEING_KEY_DEFAULT);    o = &gd->opt[GROUP_DISPLAY_OPTION_MINIMIZEING];    o->name                             = "minimize";    o->group                            = N_("");    o->subGroup                         = N_("");    o->displayHints                     = "";    o->shortDesc                        = N_("Minimize Windows");    o->longDesc                         = N_("The key for minimizeing all windows in the group.");    o->type                             = CompOptionTypeAction;    o->value.action.initiate            = groupMinimizeWindows;    o->value.action.terminate           = 0;    o->value.action.bell                = FALSE;    o->value.action.edgeMask            = 0;    o->value.action.state               = CompActionStateInitKey;      o->value.action.type                = CompBindingTypeKey;    o->value.action.key.modifiers       = GROUP_MINIMIZEING_MODIFIERS_DEFAULT;    o->value.action.key.keysym          = XStringToKeysym (GROUP_MINIMIZEING_KEY_DEFAULT);    o = &gd->opt[GROUP_DISPLAY_OPTION_IGNORE];    o->name                             = "ignore";    o->group                            = N_("");    o->subGroup                         = N_("");    o->displayHints                     = "";    o->shortDesc                        = N_("Ignore Group");    o->longDesc                         = N_("The key for ignoring the group."                                             "If this key is pressed you can resize/move a single"                                              "window in the group.");    o->type                             = CompOptionTypeAction;    o->value.action.initiate            = groupSetIgnore;    o->value.action.terminate           = groupUnsetIgnore;    o->value.action.bell                = FALSE;    o->value.action.edgeMask            = 0;    o->value.action.state               = CompActionStateInitKey;      o->value.action.type                = CompBindingTypeKey;    o->value.action.key.modifiers       = GROUP_IGNORE_MODIFIERS_DEFAULT;    o->value.action.key.keysym          = XStringToKeysym (GROUP_IGNORE_KEY_DEFAULT); }/* * groupGetDisplayOptions * */static CompOption *groupGetDisplayOptions (CompDisplay *d, int *count){    if (d)    {        GROUP_DISPLAY (d);            *count = NUM_OPTIONS (gd);        return gd->opt;    }    else    {        GroupDisplay * gd = malloc (sizeof (GroupDisplay));        groupDisplayInitOptions (gd);        *count = NUM_OPTIONS (gd);        return gd->opt;    }}/* * groupSetDisplayOption * */static BoolgroupSetDisplayOption (CompDisplay *d, char *name, CompOptionValue *value){    CompOption *o;    int         index;    GROUP_DISPLAY (d);    o = compFindOption (gd->opt, NUM_OPTIONS (gd), name, &index);    if (!o)        return FALSE;    switch (index)     {        case GROUP_DISPLAY_OPTION_SELECT:        case GROUP_DISPLAY_OPTION_SELECT_SINGLE:        case GROUP_DISPLAY_OPTION_GROUPING:        case GROUP_DISPLAY_OPTION_UNGROUPING:        case GROUP_DISPLAY_OPTION_REMOVEING:        case GROUP_DISPLAY_OPTION_CLOSEING:        case GROUP_DISPLAY_OPTION_MINIMIZEING:        case GROUP_DISPLAY_OPTION_IGNORE:        case GROUP_DISPLAY_OPTION_TABMODE:        case GROUP_DISPLAY_OPTION_CHANGE_TAB:            if (setDisplayAction (d, o, value))            return TRUE;            break;            default:            break;    }    return FALSE;}/* * groupInitDisplay * */static BoolgroupInitDisplay (CompPlugin *p, CompDisplay *d){        GroupDisplay *gd;    gd = malloc (sizeof (GroupDisplay));    if (!gd)        return FALSE;    gd->screenPrivateIndex = allocateScreenPrivateIndex (d);    if (gd->screenPrivateIndex < 0)    {        free (gd);        return FALSE;    }    gd->inAction = FALSE;    gd->lastActiveGroup = -1;    gd->animatedGroup = -1;    gd->tmpSel.windows = NULL;    gd->tmpSel.nWins = 0;    gd->groups = NULL;    gd->nGroups = 0;    gd->ignoreMode = FALSE;    groupDisplayInitOptions (gd);    WRAP (gd, d, handleEvent, groupHandleEvent);    d->privates[displayPrivateIndex].ptr = gd;    return TRUE;}/* * groupFiniDisplay * */static voidgroupFiniDisplay (CompPlugin *p, CompDisplay *d){    GROUP_DISPLAY (d);    if (gd->groups && gd->groups != NULL && gd->nGroups != 0) {        free (gd->groups);    }    freeScreenPrivateIndex (d, gd->screenPrivateIndex);    UNWRAP (gd, d, handleEvent);    free (gd);}/* * groupInitScreen * */static BoolgroupInitScreen (CompPlugin *p, CompScreen *s){        GroupScreen *gs;    GROUP_DISPLAY (s->display);    gs = malloc (sizeof (GroupScreen));    if (!gs)        return FALSE;    gs->windowPrivateIndex = allocateWindowPrivateIndex (s);    if (gs->windowPrivateIndex < 0)    {        free (gs);        return FALSE;    }    groupScreenInitOptions (gs);    addScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_SELECT].value.action);    addScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_SELECT_SINGLE].value.action);    addScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_GROUPING].value.action);    addScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_UNGROUPING].value.action);    addScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_REMOVEING].value.action);    addScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_CLOSEING].value.action);    addScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_MINIMIZEING].value.action);    WRAP (gs, s, windowMoveNotify,   groupWindowMoveNotify);    WRAP (gs, s, windowResizeNotify, groupWindowResizeNotify);    WRAP (gs, s, preparePaintScreen, groupPreparePaintScreen);    WRAP (gs, s, paintScreen, groupPaintScreen);    WRAP (gs, s, paintWindow, groupPaintWindow);    WRAP (gs, s, paintTransformedScreen, groupPaintTransformedScreen);    s->privates[gd->screenPrivateIndex].ptr = gs;    gs->grab = FALSE;    gs->grabIndex = 0;    return TRUE;}/* * groupFiniScreen * */static voidgroupFiniScreen (CompPlugin *p, CompScreen *s){    GROUP_SCREEN (s);    GROUP_DISPLAY (s->display);    freeWindowPrivateIndex (s, gs->windowPrivateIndex);    removeScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_SELECT].value.action);    removeScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_SELECT_SINGLE].value.action);    removeScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_GROUPING].value.action);    removeScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_UNGROUPING].value.action);    removeScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_REMOVEING].value.action);    removeScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_CLOSEING].value.action);    removeScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_MINIMIZEING].value.action);    UNWRAP (gs, s, windowMoveNotify);    UNWRAP (gs, s, windowResizeNotify);    UNWRAP (gs, s, preparePaintScreen);    UNWRAP (gs, s, paintScreen);    UNWRAP (gs, s, paintWindow);    UNWRAP (gs, s, paintTransformedScreen);    free (gs);}/* * groupInitWindow * */static BoolgroupInitWindow (CompPlugin *p, CompWindow *w){    GroupWindow *gw;    GROUP_SCREEN (w->screen);    gw = malloc (sizeof (GroupWindow));    if (!gw)        return FALSE;    gw->inGroup = FALSE;    gw->inSelection = FALSE;    // for move/resize    gw->oldWidth = WIN_WIDTH (w);    gw->oldHeight = WIN_HEIGHT (w);    gw->oldX = WIN_X (w);    gw->oldY = WIN_Y (w);    // for tab    gw->animate = FALSE;    gw->steps = 0;    gw->orgPosX = 0;    gw->orgPosY = 0;    gw->destinationX = 0;    gw->destinationY = 0;    w->privates[gs->windowPrivateIndex].ptr = gw;    return TRUE;}/* * groupFiniWindow * */static voidgroupFiniWindow (CompPlugin *p, CompWindow *w){    GROUP_WINDOW (w);    free (gw);}/* * groupInit  * */static BoolgroupInit (CompPlugin *p){    displayPrivateIndex = allocateDisplayPrivateIndex ();    if (displayPrivateIndex < 0)        return FALSE;        return TRUE;}/* * groupFini * */static voidgroupFini (CompPlugin *p){    if (displayPrivateIndex >= 0)        freeDisplayPrivateIndex (displayPrivateIndex);}/* * groupDeps array * *//*CompPluginDep groupDeps[] = {        { CompPluginRuleBefore, "state" }    };*//* * groupVTable * */CompPluginVTable groupVTable = {    "group",    N_("Window Grouper"),    N_("With this plugin you can group windows."),    groupInit,    groupFini,    groupInitDisplay,    groupFiniDisplay,    groupInitScreen,    groupFiniScreen,    groupInitWindow,    groupFiniWindow,    groupGetDisplayOptions,    groupSetDisplayOption,    groupGetScreenOptions,    groupSetScreenOption,    0 /* groupDeps */,    0 /* sizeof (groupDeps) / sizeof (groupDeps[0]) */,    0,    0,    BERYL_ABI_INFO,    "beryl-plugins"};/* * getCompPluginInfo * */CompPluginVTable *getCompPluginInfo (void){    return &groupVTable;}