/** * * 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 #include #include #include #include #include #include #include #include #include "group_glow.h" #define PI 3.1415926535897 #define NUM_CORNER_POINTS 25 /* * 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 { CompWindow **windows; int nWins; int id; CompWindow *topTab; Bool tabbed; GLushort color[4]; } 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; float cornerPointsX[NUM_CORNER_POINTS]; float cornerPointsY[NUM_CORNER_POINTS]; } GroupDisplay; /* * GroupScreen structure */ typedef struct _GroupScreen { int windowPrivateIndex; CompOption opt[GROUP_SCREEN_OPTION_NUM]; WindowMoveNotifyProc windowMoveNotify; WindowResizeNotifyProc windowResizeNotify; PreparePaintScreenProc preparePaintScreen; PaintScreenProc paintScreen; DrawWindowProc drawWindow; PaintTransformedScreenProc paintTransformedScreen; int wMask; // for selection Bool grab; Bool wasTransformed; int grabIndex; int x1; int y1; int x2; int y2; GLuint glowTexture; } 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; Bool offscreen; } GroupWindow; /* * groupFindGroupAtDisplay * Note: Returns the index of the group in gd->groups! * */ static int groupFindGroupAtDisplay(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 CompWindow **groupFindWindowsInRegion(CompScreen * s, REGION reg, int *c) { GROUP_SCREEN(s); float tolerance = gs->opt[GROUP_SCREEN_OPTION_TOLERANCE].value.i / 10.0f; CompWindow **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(CompWindow)); ret[0] = w; } else { ret = realloc(ret, sizeof(CompWindow) * (count + 1)); ret[count] = w; } count++; } } (*c) = count; return ret; } /* * groupUpdatePosBuffer * */ static void groupUpdatePosBuffer(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; } /* * 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 = 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)); } /* * groupTabGroup * */ static void groupTabGroup(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 = gd->groups[index].windows[i]; if (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 void groupUntabGroup(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 = gd->groups[index].windows[i]; if (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); */ UNWRAP(gs, cw->screen, windowMoveNotify); insertWindowIntoScreen(cw->screen, cw, main->id); if (gw->offscreen) { moveWindow(cw, -1 * cw->screen->width, 0, FALSE, FALSE); syncWindowPosition(cw); gw->offscreen = FALSE; } WRAP(gs, cw->screen, windowMoveNotify, groupWindowMoveNotify); gw->animate = TRUE; } damageScreen(main->screen); } /* * groupDeleteGroup - pre-definition for groupDeleteGroupWindow * */ static void groupDeleteGroup(CompDisplay * d, int id); /* * groupDeleteGroupWindow * */ static void groupDeleteGroupWindow(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) { CompWindow **buf = gd->groups[index].windows; gd->groups[index].windows = (CompWindow **) calloc(gd->groups[index].nWins - 1, sizeof(CompWindow *)); int counter = 0; int i; for (i = 0; i < gd->groups[index].nWins; i++) { if (buf[i]->id == 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 void groupDeleteGroup(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 = gd->groups[index].windows[i]; 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 void groupAddWindowToGroup(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 = (CompWindow **) calloc(1, sizeof(CompWindow *)); g.windows[0] = w; g.nWins = 1; g.topTab = NULL; g.tabbed = FALSE; // glow color srand(time(NULL)); g.color[0] = rand() % 0xFFFF; g.color[1] = rand() % 0xFFFF; g.color[2] = rand() % 0xFFFF; g.color[3] = 0xFFFF; 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 = (CompWindow **) realloc(gd->groups[index].windows, sizeof(CompWindow *) * (gd->groups[index].nWins + 1)); gd->groups[index].windows[gd->groups[index].nWins] = w; gd->groups[index].nWins++; gw->groupID = groupID; gw->inGroup = TRUE; } } /* * groupDeleteSelectionWindow * */ static void groupDeleteSelectionWindow(CompDisplay * d, CompWindow * w) { GROUP_DISPLAY(d); if (gd->tmpSel.nWins > 0 && gd->tmpSel.windows) { CompWindow **buf = gd->tmpSel.windows; gd->tmpSel.windows = (CompWindow **) calloc(gd->tmpSel.nWins - 1, sizeof(CompWindow *)); int counter = 0; int i; for (i = 0; i < gd->tmpSel.nWins; i++) { if (buf[i]->id == w->id) continue; gd->tmpSel.windows[counter++] = buf[i]; } gd->tmpSel.nWins = counter; free(buf); } } /* * groupAddWindowToSelection * */ static void groupAddWindowToSelection(CompDisplay * d, CompWindow * w) { GROUP_DISPLAY(d); gd->tmpSel.windows = (CompWindow **) realloc(gd->tmpSel.windows, sizeof(CompWindow *) * (gd->tmpSel.nWins + 1)); gd->tmpSel.windows[gd->tmpSel.nWins] = w; gd->tmpSel.nWins++; } /* * groupSyncWindows * */ static void groupSyncWindows(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 = gd->groups[index].windows[i]; syncWindowPosition(w); } } /* * groupRaiseWindows * */ static void groupRaiseWindows(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 = gd->groups[index].windows[i]; if (w->id == top->id) continue; restackWindowBelow(w, top); } } /* * groupScreenInitOptions * */ static void groupScreenInitOptions(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 Bool groupSetScreenOption(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 void groupSelectWindow(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 = gd->groups[index].windows[i]; 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; CompWindow **buf = gd->tmpSel.windows; gd->tmpSel.windows = (CompWindow **) calloc(gd->tmpSel.nWins - gd->groups[index].nWins, sizeof(CompWindow *)); int counter = 0; int i; for (i = 0; i < gd->tmpSel.nWins; i++) { CompWindow *cw = buf[i]; 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 Bool groupSelectSingle(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 Bool groupSelect(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 Bool groupGroupWindows(CompDisplay * d, CompAction * action, CompActionState state, CompOption * option, int nOption); /* * groupSelectTerminate * */ static Bool groupSelectTerminate(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; CompWindow **ws = groupFindWindowsInRegion(s, reg, &count); if (ws) { // select windows int i; for (i = 0; i < count; i++) { CompWindow *cw = ws[i]; 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 Bool groupGroupWindows(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 = gd->tmpSel.windows[i]; GROUP_WINDOW(cw); groupAddWindowToGroup(d, cw, id); gw->inSelection = FALSE; damageScreen(cw->screen); } // exit selection free(gd->tmpSel.windows); gd->tmpSel.windows = NULL; gd->tmpSel.nWins = 0; } return FALSE; } /* * groupUnGroupWindows * */ static Bool groupUnGroupWindows(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 Bool groupInitTab(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 Bool groupChangeTab(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 = gd->groups[index].windows[i]; if (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); */ //lowerWindow(w); UNWRAP(gs, cw->screen, windowMoveNotify); insertWindowIntoScreen(cw->screen, cw, w->id); if (gw->offscreen) { moveWindow(cw, -1 * cw->screen->width, 0, FALSE, FALSE); syncWindowPosition(cw); mgw->offscreen = FALSE; } if (!mgw->offscreen) { moveWindow(w, w->screen->width, 0, FALSE, FALSE); syncWindowPosition(w); mgw->offscreen = TRUE; } unhookWindowFromScreen(w->screen, w); //raiseWindow (cw); moveInputFocusToWindow (cw); //groupSyncWindows (d, gw->groupID); gd->groups[index].topTab = cw; WRAP(gs, cw->screen, windowMoveNotify, groupWindowMoveNotify); break; } } } return TRUE; } /* * groupRemoveWindow * */ static Bool groupRemoveWindow(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 Bool groupCloseWindows(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 = gd->groups[index].windows[i]; closeWindow(cw, getCurrentTimeFromDisplay(d)); } } return FALSE; } /* * groupMinimizeWindows * */ static Bool groupMinimizeWindows(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 = gd->groups[index].windows[i]; minimizeWindow(cw); } } return FALSE; } /* * groupSetIgnore * */ static Bool groupSetIgnore(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 Bool groupUnsetIgnore(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 void groupHandleMotionEvent(CompScreen * s, int xRoot, int yRoot); /* * groupHandleEvent * */ static void groupHandleEvent(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); damageScreen(w->screen); } 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; } } /* * 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 = 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 void groupDrawTabAnimation(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 = 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); */ //lowerWindow(cw); UNWRAP(gs, cw->screen, windowMoveNotify); if (!gw->offscreen) { moveWindow(cw, cw->screen->width, 0, FALSE, FALSE); gw->offscreen = TRUE; } syncWindowPosition (cw); unhookWindowFromScreen(s, cw); WRAP(gs, cw->screen, windowMoveNotify, groupWindowMoveNotify); } } 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.3f #define BORDER_WIDTH 5 #define BORDER_RADIUS 10 #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 ) /* * groupTabBarVertices * */ static void groupTabBarVertices(GroupDisplay * gd, int x, int y, int width, int height) { int i; for (i = 0; i < NUM_CORNER_POINTS; i++) glVertex2f(BORDER_RADIUS * gd->cornerPointsX[i] + x + width - BORDER_RADIUS, -BORDER_RADIUS * gd->cornerPointsY[i] + BORDER_RADIUS + y); for (i = NUM_CORNER_POINTS - 1; i >= 0; i--) glVertex2f(-BORDER_RADIUS * gd->cornerPointsX[i] + x + BORDER_RADIUS, -BORDER_RADIUS * gd->cornerPointsY[i] + BORDER_RADIUS + y); for (i = 0; i < NUM_CORNER_POINTS; i++) glVertex2f(-BORDER_RADIUS * gd->cornerPointsX[i] + x + BORDER_RADIUS, BORDER_RADIUS * gd->cornerPointsY[i] + y + height - BORDER_RADIUS); for (i = NUM_CORNER_POINTS - 1; i >= 0; i--) glVertex2f(BORDER_RADIUS * gd->cornerPointsX[i] + x + width - BORDER_RADIUS, BORDER_RADIUS * gd->cornerPointsY[i] + y + height - BORDER_RADIUS); } /* * groupPaintThumb - taken from switcher and modified for tab bar * */ static void groupPaintThumb(CompWindow * w, int tx, int ty, int tw, int th) { DrawWindowGeometryProc oldDrawWindowGeometry; WindowPaintAttrib sAttrib = w->lastPaint; /* Wrap drawWindowGeometry to make sure the general drawWindowGeometry function is used */ oldDrawWindowGeometry = w->screen->drawWindowGeometry; w->screen->drawWindowGeometry = getBaseDrawWindowGeometry(); 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; sAttrib.xTranslate = tx - w->attrib.x; sAttrib.yTranslate = ty - w->attrib.y; (w->screen->drawWindow) (w, &sAttrib, getInfiniteRegion(), PAINT_WINDOW_TRANSFORMED_MASK); addWindowDamage(w); } w->screen->drawWindowGeometry = oldDrawWindowGeometry; } /* * groupPaintTabBar * */ static void groupPaintTabBar(GroupSelection * group) { CompScreen *s = group->topTab->screen; CompDisplay *d = s->display; GROUP_SCREEN(s); GROUP_DISPLAY(d); if (VIEWPORT(group->topTab->attrib.x, s)) 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; //glColor4f(BAR_COLOR); glColor4usv(gs->opt[GROUP_SCREEN_OPTION_SELECTION_COLOR].value.c); glBegin(GL_POLYGON); groupTabBarVertices(gd, x1, y1, width, height); glEnd(); //glColor4f(BORDER_COLOR); glColor4usv(gs->opt[GROUP_SCREEN_OPTION_LINE_COLOR].value.c); glBegin(GL_LINE_LOOP); groupTabBarVertices(gd, x1, y1, width, height); glEnd(); glColor4usv(defaultColor); glDisable(GL_BLEND); glEnableClientState(GL_TEXTURE_COORD_ARRAY); // draw thumbs int i; for (i = 0; i < group->nWins; i++) { CompWindow *cw = 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, tx1, ty1, THUMB_SIZE, THUMB_SIZE); } 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 Bool groupPaintScreen(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 void groupPaintTransformedScreen(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 Bool groupDrawWindow(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; } int index = -1; if (gw->inGroup) index = groupFindGroupAtDisplay(gd, gw->groupID); // paint glow if (gw->inGroup && index != -1) { glPushMatrix(); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glEnable(GL_BLEND); if (gs->glowTexture) { glBindTexture(GL_TEXTURE_2D, gs->glowTexture); glEnable(GL_TEXTURE_2D); } glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glColor4usv(gd->groups[index].color); int glowBorderX = 12; int glowBorderY = 12; int glowWidth = 128; int glowHeight = 128; int overlapX, overlapY; overlapX = (WIN_WIDTH(w) * glowBorderX) / (glowWidth - glowBorderX * 2); overlapY = (WIN_HEIGHT(w) * glowBorderY) / (glowHeight - glowBorderY * 2); int x1, x2, y1, y2; x1 = WIN_X(w) - overlapX; y1 = WIN_Y(w) - overlapY; x2 = WIN_X(w) + WIN_WIDTH(w) + overlapX; y2 = WIN_Y(w) + WIN_HEIGHT(w) + overlapY; glBegin(GL_QUADS); glTexCoord2d(0.0, 1.0); glVertex2i(x1, y1); glTexCoord2d(0.0, 0.0); glVertex2i(x1, y2); glTexCoord2d(1.0, 0.0); glVertex2i(x2, y2); glTexCoord2d(1.0, 1.0); glVertex2i(x2, y1); glEnd(); glDisable(GL_STENCIL_TEST); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glColor4usv(defaultColor); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glPopMatrix(); Region reg = XCreateRegion(); XRectangle rect; rect.x = x1; rect.y = y1; rect.width = x2 - x1; rect.height = y2 - y1; XUnionRectWithRegion(&rect, reg, reg); XSubtractRegion(reg, w->region, reg); damageScreenRegion(w->screen, reg); } UNWRAP(gs, w->screen, drawWindow); status = (*w->screen->drawWindow) (w, &gAttrib, region, mask); if (index != -1 && gd->groups[index].tabbed && gd->groups[index].topTab->id == w->id) groupPaintTabBar(&gd->groups[index]); WRAP(gs, w->screen, drawWindow, groupDrawWindow); return status; } /* * groupHandleMotionEvent * */ static void groupHandleMotionEvent(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, ®); } } /* * reloadCornerPoints * */ static void initCornerPoints(GroupDisplay * gd) { int i; float angle; for (i = 0; i < NUM_CORNER_POINTS; i++) { angle = (PI / 2) * ((float) i / (NUM_CORNER_POINTS - 1)); gd->cornerPointsY[i] = sin(angle); gd->cornerPointsX[i] = cos(angle); } } /* * groupDisplayInitOptions * */ static void groupDisplayInitOptions(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 Bool groupSetDisplayOption(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 Bool groupInitDisplay(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); initCornerPoints(gd); WRAP(gd, d, handleEvent, groupHandleEvent); d->privates[displayPrivateIndex].ptr = gd; return TRUE; } /* * groupFiniDisplay * */ static void groupFiniDisplay(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 Bool groupInitScreen(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); addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_TABMODE].value.action); addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_CHANGE_TAB].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, drawWindow, groupDrawWindow); WRAP(gs, s, paintTransformedScreen, groupPaintTransformedScreen); s->privates[gd->screenPrivateIndex].ptr = gs; gs->grab = FALSE; gs->grabIndex = 0; // bind texture for glow glGenTextures(1, &gs->glowTexture); glBindTexture(GL_TEXTURE_2D, gs->glowTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, glowTex); glBindTexture(GL_TEXTURE_2D, 0); return TRUE; } /* * groupFiniScreen * */ static void groupFiniScreen(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); removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_TABMODE].value.action); removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_CHANGE_TAB].value.action); UNWRAP(gs, s, windowMoveNotify); UNWRAP(gs, s, windowResizeNotify); UNWRAP(gs, s, preparePaintScreen); UNWRAP(gs, s, paintScreen); UNWRAP(gs, s, drawWindow); UNWRAP(gs, s, paintTransformedScreen); free(gs); } /* * groupInitWindow * */ static Bool groupInitWindow(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; gw->offscreen = FALSE; w->privates[gs->windowPrivateIndex].ptr = gw; return TRUE; } /* * groupFiniWindow * */ static void groupFiniWindow(CompPlugin * p, CompWindow * w) { GROUP_WINDOW(w); free(gw); } /* * groupInit * */ static Bool groupInit(CompPlugin * p) { displayPrivateIndex = allocateDisplayPrivateIndex(); if (displayPrivateIndex < 0) return FALSE; return TRUE; } /* * groupFini * */ static void groupFini(CompPlugin * p) { if (displayPrivateIndex >= 0) freeDisplayPrivateIndex(displayPrivateIndex); } /* * groupDeps array * */ CompPluginDep groupDeps[] = { {CompPluginRuleBefore, "cube"} }; /* * 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, groupDeps, sizeof(groupDeps) / sizeof(groupDeps[0]), 0, 0, BERYL_ABI_INFO, "beryl-plugins" }; /* * getCompPluginInfo * */ CompPluginVTable *getCompPluginInfo(void) { return &groupVTable; }