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 = ®.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, ®); 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 = ®.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, ®); 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, ®); }}/* * 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;}