/** * * 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 #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_LEFT_MODIFIERS_DEFAULT (CompSuperMask) #define GROUP_CHANGE_TAB_LEFT_KEY_DEFAULT "Left" #define GROUP_CHANGE_TAB_RIGHT_MODIFIERS_DEFAULT (CompSuperMask) #define GROUP_CHANGE_TAB_RIGHT_KEY_DEFAULT "Right" #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_LEFT 9 #define GROUP_DISPLAY_OPTION_CHANGE_TAB_RIGHT 10 #define GROUP_DISPLAY_OPTION_NUM 11 #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_THUMB_SIZE_DEFAULT 64 #define GROUP_THUMB_SIZE_MIN 16 #define GROUP_THUMB_SIZE_MAX 128 #define GROUP_BORDER_WIDTH_DEFAULT 10 #define GROUP_BORDER_WIDTH_MIN 1 #define GROUP_BORDER_WIDTH_MAX 20 #define GROUP_BORDER_RADIUS_DEFAULT 10 #define GROUP_BORDER_RADIUS_MIN 1 #define GROUP_BORDER_RADIUS_MAX 20 #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_COLOR_TAB_FILL_RED_DEFAULT 0x0000 #define GROUP_COLOR_TAB_FILL_GREEN_DEFAULT 0x0000 #define GROUP_COLOR_TAB_FILL_BLUE_DEFAULT 0x0000 #define GROUP_COLOR_TAB_FILL_ALPHA_DEFAULT 0x9999 #define GROUP_COLOR_TAB_BORDER_RED_DEFAULT 0x0000 #define GROUP_COLOR_TAB_BORDER_GREEN_DEFAULT 0x0000 #define GROUP_COLOR_TAB_BORDER_BLUE_DEFAULT 0x0000 #define GROUP_COLOR_TAB_BORDER_ALPHA_DEFAULT 0xABAB #define GROUP_TAB_CREATE_MIPMAPS_DEFAULT TRUE #define GROUP_GLOW_DEFAULT TRUE #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_GLOW 4 #define GROUP_SCREEN_OPTION_MOVE 5 #define GROUP_SCREEN_OPTION_RESIZE 6 #define GROUP_SCREEN_OPTION_RAISE 7 #define GROUP_SCREEN_OPTION_AUTO_UNGROUP 8 #define GROUP_SCREEN_OPTION_AUTO_GROUP 9 #define GROUP_SCREEN_OPTION_RELATIVE_DISTANCE 10 #define GROUP_SCREEN_OPTION_SELECTION_COLOR 11 #define GROUP_SCREEN_OPTION_LINE_COLOR 12 #define GROUP_SCREEN_OPTION_TOLERANCE 13 #define GROUP_SCREEN_OPTION_STEPS 14 #define GROUP_SCREEN_OPTION_THUMB_SIZE 15 #define GROUP_SCREEN_OPTION_BORDER_WIDTH 16 #define GROUP_SCREEN_OPTION_BORDER_RADIUS 17 #define GROUP_SCREEN_OPTION_TAB_BORDER_COLOR 18 #define GROUP_SCREEN_OPTION_TAB_FILL_COLOR 19 #define GROUP_SCREEN_OPTION_TAB_CREATE_MIPMAPS 20 #define GROUP_SCREEN_OPTION_NUM 21 /* * 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])) #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 ) #define TOP_TAB(g) ((g)->windows[(g)->topTab]) #define PREV_TOP_TAB(g) ((g)->windows[(g)->prevTopTab]) /* * default windows for selection */ static char *groupDefaultTypes[] = { N_("Normal"), N_("Dialog"), N_("ModalDialog"), N_("Dnd") }; /* * structs for pending callbacks */ typedef struct _GroupPendingMoves GroupPendingMoves; struct _GroupPendingMoves { CompWindow *w; int dx; int dy; GroupPendingMoves *next; }; typedef struct _GroupPendingResizes GroupPendingResizes; struct _GroupPendingResizes { CompWindow *w; int x; int y; int width; int height; int borderWidth; GroupPendingResizes *next; }; typedef struct _GroupPendingGrabs GroupPendingGrabs; struct _GroupPendingGrabs { CompWindow *w; int x; int y; unsigned int state; unsigned int mask; GroupPendingGrabs *next; }; typedef struct _GroupPendingUngrabs GroupPendingUngrabs; struct _GroupPendingUngrabs { CompWindow *w; GroupPendingUngrabs *next; }; /* * pointer to display list */ static int displayPrivateIndex; /* * GroupTabBarSlot */ typedef struct _GroupTabBarSlot GroupTabBarSlot; struct _GroupTabBarSlot { GroupTabBarSlot *prev; GroupTabBarSlot *next; int rx; int ry; int height; int width; CompWindow *window; }; /* * GroupTabBar */ typedef struct _GroupTabBar { GroupTabBarSlot *slots; GroupTabBarSlot *revSlots; int nSlots; Bool visible; int rx; int ry; int height; int width; } GroupTabBar; /* * GroupSelection */ typedef struct _GroupSelection GroupSelection; struct _GroupSelection { GroupSelection *prev; GroupSelection *next; CompWindow **windows; int nWins; int topTab; int prevTopTab; Bool tabbed; GroupTabBar *tabBar; int animationSteps; int dx, dy; //For tabbed windows. Bool ungroup; GLushort color[4]; }; /* * GroupDisplay structure */ typedef struct _GroupDisplay { int screenPrivateIndex; CompOption opt[GROUP_DISPLAY_OPTION_NUM]; HandleEventProc handleEvent; GroupSelection tmpSel; GroupSelection *groups; //GroupSelection *revGroups; Bool inAction; GroupSelection *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; PaintWindowProc paintWindow; PaintTransformedScreenProc paintTransformedScreen; WindowGrabNotifyProc windowGrabNotify; WindowUngrabNotifyProc windowUngrabNotify; GroupPendingMoves *pendingMoves; GroupPendingResizes *pendingResizes; GroupPendingGrabs *pendingGrabs; GroupPendingUngrabs *pendingUngrabs; int wMask; Bool ignoreCallback; // for selection Bool grab; Bool wasTransformed; int grabIndex; int x1; int y1; int x2; int y2; CompTexture glowTexture; } GroupScreen; /* * GroupWindow structure */ typedef struct _GroupWindow { GroupSelection *group; Bool inGroup; Bool inSelection; // for the tab bar GroupTabBarSlot *slot; // for scale notify... int oldWidth; int oldHeight; int oldX; int oldY; // for tab animation int orgPosX; //Relative to the tabbed window. int orgPosY; //Relative to the tabbed window. int destinationX; int destinationY; } GroupWindow; #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; } /* * functions enqueuing pending notifies * */ static void groupEnqueueMoveNotify (CompScreen *s, CompWindow *w, int dx, int dy) { GroupPendingMoves *move; GROUP_SCREEN (s); move = malloc (sizeof(GroupPendingMoves)); if (!move) return; move->w = w; move->dx = dx; move->dy = dy; move->next = NULL; if (gs->pendingMoves) { GroupPendingMoves *temp; for (temp = gs->pendingMoves; temp->next; temp = temp->next); temp->next = move; } else { gs->pendingMoves = move; } } static void groupDequeueMoveNotifies (CompScreen *s) { GroupPendingMoves *move, *next; GROUP_SCREEN (s); gs->ignoreCallback = TRUE; move = gs->pendingMoves; while (move) { moveWindow (move->w, move->dx, move->dy, TRUE, FALSE); groupUpdatePosBuffer (move->w, WIN_X(move->w) + move->dx, WIN_Y(move->w) + move->dy, WIN_WIDTH(move->w), WIN_HEIGHT(move->w)); next = move->next; free (move); move = next; } gs->pendingMoves = NULL; gs->ignoreCallback = FALSE; } static void groupEnqueueResizeNotify (CompScreen *s, CompWindow *w, int x, int y, int width, int height, int border_width) { GroupPendingResizes *resize; GROUP_SCREEN (s); resize = malloc (sizeof(GroupPendingResizes)); if (!resize) return; resize->w = w; resize->x = x; resize->y = y; resize->width = width; resize->height = height; resize->borderWidth = border_width; resize->next = NULL; if (gs->pendingResizes) { GroupPendingResizes *temp; for (temp = gs->pendingResizes; temp->next; temp = temp->next); temp->next = resize; } else { gs->pendingResizes = resize; } } static void groupDequeueResizeNotifies (CompScreen *s) { GroupPendingResizes *resize, *next; GROUP_SCREEN (s); gs->ignoreCallback = TRUE; resize = gs->pendingResizes; while (resize) { resizeWindow (resize->w, resize->x, resize->y, resize->width, resize->height, resize->borderWidth); groupUpdatePosBuffer (resize->w, resize->x, resize->y, resize->width, resize->height); next = resize->next; free (resize); resize = next; } gs->pendingResizes = NULL; gs->ignoreCallback = FALSE; } static void groupEnqueueGrabNotify (CompScreen *s, CompWindow *w, int x, int y, unsigned int state, unsigned int mask) { GroupPendingGrabs *grab; GROUP_SCREEN (s); grab = malloc (sizeof(GroupPendingGrabs)); if (!grab) return; grab->w = w; grab->x = x; grab->y = y; grab->state = state; grab->mask = mask; grab->next = NULL; if (gs->pendingGrabs) { GroupPendingGrabs *temp; for (temp = gs->pendingGrabs; temp->next; temp = temp->next); temp->next = grab; } else { gs->pendingGrabs = grab; } } static void groupDequeueGrabNotifies (CompScreen *s) { GroupPendingGrabs *grab, *next; GROUP_SCREEN (s); gs->ignoreCallback = TRUE; grab = gs->pendingGrabs; while (grab) { (*(grab->w)->screen->windowGrabNotify) (grab->w, grab->x, grab->y, grab->state, grab->mask); next = grab->next; free (grab); grab = next; } gs->pendingGrabs = NULL; gs->ignoreCallback = FALSE; } static void groupEnqueueUngrabNotify (CompScreen *s, CompWindow *w) { GroupPendingUngrabs *ungrab; GROUP_SCREEN (s); ungrab = malloc (sizeof(GroupPendingUngrabs)); if (!ungrab) return; ungrab->w = w; ungrab->next = NULL; if (gs->pendingUngrabs) { GroupPendingUngrabs *temp; for (temp = gs->pendingUngrabs; temp->next; temp = temp->next); temp->next = ungrab; } else { gs->pendingUngrabs = ungrab; } } static void groupDequeueUngrabNotifies (CompScreen *s) { GroupPendingUngrabs *ungrab, *next; GROUP_SCREEN (s); gs->ignoreCallback = TRUE; ungrab = gs->pendingUngrabs; while (ungrab) { (*(ungrab->w)->screen->windowUngrabNotify) (ungrab->w); next = ungrab->next; free (ungrab); ungrab = next; } gs->pendingUngrabs = NULL; gs->ignoreCallback = FALSE; } /* * groupAddSkipMasks * */ static void groupAddSkipMasks(CompWindow *w) { unsigned int state = getWindowState (w->screen->display, w->id); state |= CompWindowStateSkipTaskbarMask; state |= CompWindowStateSkipPagerMask; setWindowState (w->screen->display, state, w->id); } /* * groupRemoveSkipMasks * */ static void groupRemoveSkipMasks(CompWindow *w) { unsigned int state = getWindowState (w->screen->display, w->id); state &= ~CompWindowStateSkipTaskbarMask; state &= ~CompWindowStateSkipPagerMask; setWindowState (w->screen->display, state, w->id); } /* * groupFindWindowIndex * */ static int groupFindWindowIndex(CompWindow *w, GroupSelection *g) { int i; for(i = 0; i < g->nWins; i++) { if(g->windows[i]->id == w->id) return i; } return -1; } /* * 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); groupUpdatePosBuffer(w, WIN_X(w) + dx, WIN_Y(w) + dy, WIN_WIDTH(w), WIN_HEIGHT(w)); if (gw->inGroup && gw->group->tabbed && gw->group->topTab != -1) { if (TOP_TAB(gw->group)->id != w->id) { groupEnqueueMoveNotify (w->screen, w, -dx, -dy); } else { gw->group->dx += dx; gw->group->dy += dy; } return; } // 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 || gs->ignoreCallback || gw->group->animationSteps || 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) return; int i; for (i = 0; i < gw->group->nWins; i++) { CompWindow *cw = gw->group->windows[i]; if (!cw) continue; if (cw->id != w->id) { groupEnqueueMoveNotify (cw->screen, cw, dx, dy); } } gd->lastActiveGroup = gw->group; gd->inAction = TRUE; } /* * groupRecalcTabBarPos * */ static void groupRecalcTabBarPos(GroupSelection *group) { if (group->topTab < 0 || !group->tabBar) return; GroupTabBar *bar = group->tabBar; CompWindow *topTab = TOP_TAB(group); GROUP_SCREEN(topTab->screen); int border_width = gs->opt[GROUP_SCREEN_OPTION_BORDER_WIDTH].value.i; int thumb_size = gs->opt[GROUP_SCREEN_OPTION_THUMB_SIZE].value.i; bar->width = border_width * (bar->nSlots + 1) + thumb_size * bar->nSlots; bar->height = border_width * 2 + thumb_size; bar->rx = WIN_WIDTH(topTab) / 2 - bar->width / 2; bar->ry = 0; } /* * groupInsertTabBarSlot * */ static void groupInsertTabBarSlot(GroupTabBar *bar, GroupTabBarSlot *slot) { if (bar->slots != NULL) { bar->revSlots->next = slot; slot->prev = bar->revSlots; slot->next = NULL; } else { slot->prev = NULL; slot->next = NULL; bar->slots = slot; } bar->revSlots = slot; CompWindow *w = slot->window; GROUP_WINDOW(w); groupRecalcTabBarPos(gw->group); } /* * groupUnhookTabBarSlot * */ static void groupUnhookTabBarSlot(GroupTabBar *bar, GroupTabBarSlot *slot) { GroupTabBarSlot *prev = slot->prev; GroupTabBarSlot *next = slot->next; if (prev || next) { if (prev) { if (next) prev->next = next; else prev->next = NULL; } if (next) { if (prev) next->prev = prev; else next->prev = NULL; } } else { bar->slots = NULL; bar->revSlots = NULL; } bar->nSlots--; CompWindow *w = slot->window; GROUP_WINDOW(w); groupRecalcTabBarPos(gw->group); free(slot); } /* * groupInitTabBar * */ static void groupInitTabBar(GroupSelection *group) { // error if (group->topTab < 0) return; CompWindow *topTab = group->windows[group->topTab]; GROUP_SCREEN(topTab->screen); int border_width = gs->opt[GROUP_SCREEN_OPTION_BORDER_WIDTH].value.i; int thumb_size = gs->opt[GROUP_SCREEN_OPTION_THUMB_SIZE].value.i; GroupTabBar *bar = (GroupTabBar*) malloc(sizeof(GroupTabBar)); bar->slots = NULL; bar->visible = FALSE; int i; for(i = 0; i < group->nWins; i++) { GroupTabBarSlot *slot = (GroupTabBarSlot*) malloc(sizeof(GroupTabBarSlot)); slot->window = group->windows[i]; slot->width = thumb_size; slot->height = thumb_size; slot->rx = border_width + ((slot->width + border_width) * i); slot->ry = border_width; groupInsertTabBarSlot(bar, slot); GROUP_WINDOW(group->windows[i]); gw->slot = slot; } bar->nSlots = group->nWins; group->tabBar = bar; groupRecalcTabBarPos(group); } /* * groupDeleteTabBar * */ static void groupDeleteTabBar(GroupSelection *group) { GroupTabBar *bar = group->tabBar; GroupTabBarSlot *slot; for(slot = bar->slots; slot; slot = slot->next) { if (slot->prev) { free(slot->prev); } if (!slot->next) { free(slot); break; } } free(bar); group->tabBar = NULL; } /* * groupTabGroup * */ static void groupTabGroup(CompWindow * main) { GROUP_WINDOW(main); GROUP_SCREEN(main->screen); GroupSelection *group = gw->group; if(!group || !gw->inGroup) return; int steps = gs->opt[GROUP_SCREEN_OPTION_STEPS].value.i; group->tabbed = TRUE; group->animationSteps = steps; // main window group->topTab = groupFindWindowIndex(main, group); group->prevTopTab = -1; if(group->topTab == -1) return; groupInitTabBar(group); group->tabBar->visible = TRUE; int i; for (i = 0; i < group->nWins; i++) { CompWindow *cw = group->windows[i]; GROUP_WINDOW(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->orgPosX = WIN_X(cw) - gw->destinationX; gw->orgPosY = WIN_Y(cw) - gw->destinationY; } damageScreen(main->screen); } /* * groupUntabGroup * */ static void groupUntabGroup(CompDisplay *d, GroupSelection *group) { //TODO: Respect window borders, struts and constrain y options... if(group->topTab == -1) return; GROUP_SCREEN(d->screens); GROUP_WINDOW(TOP_TAB(group)); int maxY = 0, minY = TOP_TAB(group)->screen->height; int decreaseY = 0; int steps = gs->opt[GROUP_SCREEN_OPTION_STEPS].value.i; int mainOrgPosX = gw->orgPosX; int mainOrgPosY = gw->orgPosY; group->tabbed = FALSE; group->animationSteps = steps; // main window group->prevTopTab = group->topTab; group->topTab = -1; group->tabBar->visible = FALSE; groupDeleteTabBar(group); int i; for (i = 0; i < group->nWins; i++) { CompWindow *cw = group->windows[i]; GROUP_WINDOW(cw); gw->destinationX = WIN_X(cw) + gw->orgPosX - mainOrgPosX; gw->destinationY = WIN_Y(cw) + gw->orgPosY - mainOrgPosY; if(i != group->prevTopTab) //Window is offscreen. { gw->destinationX -= cw->screen->width; gw->destinationX += group->dx; gw->destinationY += group->dy; } if(gw->destinationY > maxY) maxY = gw->destinationY; if(gw->destinationY < minY) minY = gw->destinationY; gw->orgPosX = 0; gw->orgPosY = 0; } if(maxY > PREV_TOP_TAB(group)->screen->height) decreaseY = maxY - PREV_TOP_TAB(group)->screen->height; else if(minY < 0) decreaseY = minY; for (i = 0; i < group->nWins; i++) { CompWindow *cw = group->windows[i]; GROUP_WINDOW(cw); gw->destinationY -= decreaseY; } damageScreen(PREV_TOP_TAB(group)->screen); } /* * groupDeleteGroup - pre-definition for groupDeleteGroupWindow * */ static void groupDeleteGroup(CompDisplay * d, GroupSelection *group); /* * groupDeleteGroupWindow * */ static void groupDeleteGroupWindow(CompDisplay * d, CompWindow * w) { GROUP_WINDOW(w); GROUP_SCREEN(w->screen); GroupSelection *group = gw->group; if (group->tabbed) { if (group->topTab >= 0 && TOP_TAB(group)->id == w->id) groupUntabGroup(d, group); else groupUnhookTabBarSlot(group->tabBar, gw->slot); } if (group->nWins != 0 && group->windows != NULL) { CompWindow **buf = group->windows; group->windows = (CompWindow **) calloc(group->nWins - 1, sizeof(CompWindow *)); int counter = 0; int i; for (i = 0; i < group->nWins; i++) { if (buf[i]->id == w->id) continue; group->windows[counter++] = buf[i]; } group->nWins = counter; if (group->nWins == 1 && gs->opt[GROUP_SCREEN_OPTION_AUTO_UNGROUP].value.b) { groupDeleteGroup(d, gw->group); } else if (group->nWins <= 0) { free(group->windows); group->windows = NULL; groupDeleteGroup(d, group); } free(buf); gw->inGroup = FALSE; } } /* * groupDeleteGroup * */ static void groupDeleteGroup(CompDisplay * d, GroupSelection *group) { GROUP_DISPLAY(d); gd->inAction = TRUE; gd->lastActiveGroup = NULL; if (group->windows != NULL) { if (group->tabbed) { groupUntabGroup(d, group); group->ungroup = TRUE; return; } int i; for (i = 0; i < group->nWins; i++) { CompWindow *cw = group->windows[i]; GROUP_WINDOW(cw); gw->inGroup = FALSE; } free(group->windows); } GroupSelection *prev = group->prev; GroupSelection *next = group->next; // relink stack if (prev || next) { if (prev) { if (next) prev->next = next; else { prev->next = NULL; //gd->revGroups = prev; } } if (next) { if (prev) next->prev = prev; else { next->prev = NULL; gd->groups = next; } } } else { gd->groups = NULL; } free(group); gd->inAction = FALSE; } /* * groupAddWindowToGroup * */ static void groupAddWindowToGroup(CompDisplay * d, CompWindow * w, GroupSelection *group) { GROUP_DISPLAY(d); GROUP_WINDOW(w); if (gw->inGroup) groupDeleteGroupWindow(d, w); if (group) { group->windows = (CompWindow **) realloc(group->windows, sizeof(CompWindow *) * (group->nWins + 1)); group->windows[group->nWins] = w; group->nWins++; gw->group = group; gw->inGroup = TRUE; } else { GroupSelection *g = malloc(sizeof(GroupSelection)); g->windows = (CompWindow **) calloc(1, sizeof(CompWindow *)); g->windows[0] = w; g->nWins = 1; g->topTab = -1; g->prevTopTab = -1; g->animationSteps = 0; g->tabbed = FALSE; g->ungroup = FALSE; g->tabBar = NULL; g->dx = 0; g->dy = 0; // glow color srand(time(NULL)); g->color[0] = rand() % 0xFFFF; g->color[1] = rand() % 0xFFFF; g->color[2] = rand() % 0xFFFF; g->color[3] = 0xFFFF; // relink stack if (gd->groups) { gd->groups->prev = g; g->next = gd->groups; g->prev = NULL; gd->groups = g; } else { g->prev = NULL; g->next = NULL; gd->groups = g; } gw->group = g; 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(GroupSelection *group) { int i; for (i = 0; i < group->nWins; i++) { CompWindow *w = group->windows[i]; syncWindowPosition(w); } } /* * groupRaiseWindows * */ static void groupRaiseWindows(CompWindow * top, GroupSelection *group) { int i; for (i = 0; i < group->nWins; i++) { CompWindow *w = group->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_THUMB_SIZE]; o->name = "thumb_size"; o->group = N_(""); o->subGroup = N_(""); o->displayHints = ""; o->shortDesc = N_("Thumb Size"); o->longDesc = N_("The size of the window thumbs in the tab bar."); o->type = CompOptionTypeInt; o->value.i = GROUP_THUMB_SIZE_DEFAULT; o->rest.i.min = GROUP_THUMB_SIZE_MIN; o->rest.i.max = GROUP_THUMB_SIZE_MAX; o = &gs->opt[GROUP_SCREEN_OPTION_BORDER_WIDTH]; o->name = "broder_width"; o->group = N_(""); o->subGroup = N_(""); o->displayHints = ""; o->shortDesc = N_("Border Width"); o->longDesc = N_("The width of the border around the tab bar."); o->type = CompOptionTypeInt; o->value.i = GROUP_BORDER_WIDTH_DEFAULT; o->rest.i.min = GROUP_BORDER_WIDTH_MIN; o->rest.i.max = GROUP_BORDER_WIDTH_MAX; o = &gs->opt[GROUP_SCREEN_OPTION_BORDER_RADIUS]; o->name = "broder_radius"; o->group = N_(""); o->subGroup = N_(""); o->displayHints = ""; o->shortDesc = N_("Border Radius"); o->longDesc = N_("The radius for the edges of the tab bar."); o->type = CompOptionTypeInt; o->value.i = GROUP_BORDER_RADIUS_DEFAULT; o->rest.i.min = GROUP_BORDER_RADIUS_MIN; o->rest.i.max = GROUP_BORDER_RADIUS_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; o = &gs->opt[GROUP_SCREEN_OPTION_TAB_FILL_COLOR]; o->name = "tab_color"; o->group = N_(""); o->subGroup = N_(""); o->displayHints = ""; o->shortDesc = N_("Tab Color"); o->longDesc = N_("Fill color of the tab bar."); o->type = CompOptionTypeColor; o->value.c[0] = GROUP_COLOR_TAB_FILL_RED_DEFAULT; o->value.c[1] = GROUP_COLOR_TAB_FILL_GREEN_DEFAULT; o->value.c[2] = GROUP_COLOR_TAB_FILL_BLUE_DEFAULT; o->value.c[3] = GROUP_COLOR_TAB_FILL_ALPHA_DEFAULT; o = &gs->opt[GROUP_SCREEN_OPTION_TAB_BORDER_COLOR]; o->name = "border_color"; o->group = N_(""); o->subGroup = N_(""); o->displayHints = ""; o->shortDesc = N_("Tab Border Color"); o->longDesc = N_("Border color of the tab bar."); o->type = CompOptionTypeColor; o->value.c[0] = GROUP_COLOR_TAB_BORDER_RED_DEFAULT; o->value.c[1] = GROUP_COLOR_TAB_BORDER_GREEN_DEFAULT; o->value.c[2] = GROUP_COLOR_TAB_BORDER_BLUE_DEFAULT; o->value.c[3] = GROUP_COLOR_TAB_BORDER_ALPHA_DEFAULT; o = &gs->opt[GROUP_SCREEN_OPTION_TAB_CREATE_MIPMAPS]; o->name = "mipmaps"; o->shortDesc = N_("create mipmaps for thumbnails."); o->group = N_(""); o->subGroup = N_(""); o->displayHints = ""; o->longDesc = N_("Create mipmaps for thumbnails in the tab-bar."); o->type = CompOptionTypeBool; o->value.b = GROUP_TAB_CREATE_MIPMAPS_DEFAULT; o = &gs->opt[GROUP_SCREEN_OPTION_GLOW]; o->name = "glow"; o->shortDesc = N_("Enable Glow"); o->group = N_(""); o->subGroup = N_(""); o->displayHints = ""; o->longDesc = N_("Enable grouped window glowing."); o->type = CompOptionTypeBool; o->value.b = GROUP_GLOW_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: case GROUP_SCREEN_OPTION_TAB_FILL_COLOR: case GROUP_SCREEN_OPTION_TAB_BORDER_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: case GROUP_SCREEN_OPTION_THUMB_SIZE: case GROUP_SCREEN_OPTION_BORDER_WIDTH: case GROUP_SCREEN_OPTION_BORDER_RADIUS: if (compSetIntOption(o, value)) { return TRUE; } break; case GROUP_SCREEN_OPTION_GLOW: 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: case GROUP_SCREEN_OPTION_TAB_CREATE_MIPMAPS: 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 i; for (i = 0; i < gw->group->nWins; i++) { CompWindow *cw = gw->group->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) { GroupSelection *group = gw->group; CompWindow **buf = gd->tmpSel.windows; gd->tmpSel.windows = (CompWindow **) calloc(gd->tmpSel.nWins - gw->group->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->group == group) { 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 i; CompWindow *cw; // we need to do one first to get the pointer of a new group cw = gd->tmpSel.windows[0]; groupAddWindowToGroup(d, cw, NULL); GROUP_WINDOW (cw); gw->inSelection = FALSE; damageScreen(cw->screen); GroupSelection *group = gw->group; for (i = 1; i < gd->tmpSel.nWins; i++) { cw = gd->tmpSel.windows[i]; GROUP_WINDOW(cw); groupAddWindowToGroup(d, cw, group); 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); GROUP_SCREEN(cw->screen); if (gw->inGroup) { groupDeleteGroup(d, gw->group); if (gs->opt[GROUP_SCREEN_OPTION_GLOW].value.b) damageScreen(cw->screen); } return FALSE; } /* * groupInitTab * */ static Bool groupInitTab(CompDisplay * d, CompAction * action, CompActionState state, CompOption * option, int nOption) { CompWindow *w = findWindowAtDisplay(d, d->activeWindow); if (!w) return FALSE; GROUP_WINDOW(w); if (!gw->inGroup) return FALSE; if (gw->group->tabbed) { groupUntabGroup(d, gw->group); } else { groupTabGroup(w); } return TRUE; } #define LEFT TRUE #define RIGHT FALSE /* * groupChangeTab * */ static Bool groupChangeTab(CompDisplay * d, Bool direction) { //TODO: return better values... :P // CompWindow *w = findWindowAtDisplay(d, d->activeWindow); if (!w) return TRUE; GROUP_WINDOW(w); if (!gw->inGroup || !gw->group->tabbed || gw->group->topTab == -1) return TRUE; gw->group->prevTopTab = gw->group->topTab; if(direction == RIGHT) gw->group->topTab++; else gw->group->topTab--; if(gw->group->topTab == gw->group->nWins) gw->group->topTab = 0; else if(gw->group->topTab == -1) gw->group->topTab = gw->group->nWins - 1; return TRUE; } /* * groupChangeTabLeft * */ static Bool groupChangeTabLeft(CompDisplay * d, CompAction * action, CompActionState state, CompOption * option, int nOption) { return groupChangeTab(d, LEFT); } /* * groupChangeTabRight * */ static Bool groupChangeTabRight(CompDisplay * d, CompAction * action, CompActionState state, CompOption * option, int nOption) { return groupChangeTab(d, RIGHT); } /* * 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); if (gw->inGroup) { int nWins = gw->group->nWins; int i; for (i = 0; i < nWins; i++) { CompWindow *cw = gw->group->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); if (gw->inGroup) { int nWins = gw->group->nWins; int i; for (i = 0; i < nWins; i++) { CompWindow *cw = gw->group->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) { groupSyncWindows(gd->lastActiveGroup); gd->lastActiveGroup = NULL; 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 && !gw->group->tabbed && !IPCS_GetBoolND(IPCS_OBJECT(w->screen->display), "SCALE_INIT", FALSE) && gs->opt[GROUP_SCREEN_OPTION_RAISE].value.b) { groupRaiseWindows(w, gw->group); } else if(gw->inGroup && gw->group->tabbed) { focusWindow(TOP_TAB(gw->group)); moveInputFocusToWindow(TOP_TAB(gw->group)); } } } 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->ignoreCallback && 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 i; for (i = 0; i < gw->group->nWins; i++) { CompWindow *cw = gw->group->windows[i]; if (!cw) continue; if (cw->id != w->id) { 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); groupEnqueueResizeNotify (cw->screen, cw, nx, ny, nwidth, nheight, WIN_BORDER(cw)); } } gd->lastActiveGroup = gw->group; gd->inAction = TRUE; } groupUpdatePosBuffer(w, WIN_X(w), WIN_Y(w), WIN_WIDTH(w), WIN_HEIGHT(w)); } static void groupWindowGrabNotify(CompWindow * w, int x, int y, unsigned int state, unsigned int mask) { GROUP_SCREEN(w->screen); GROUP_DISPLAY(w->screen->display); GROUP_WINDOW(w); if (gw->inGroup && !gd->ignoreMode && !gs->ignoreCallback) { int i; for (i = 0; i < gw->group->nWins; i++) { CompWindow *cw = gw->group->windows[i]; if (!cw) continue; if (cw->id != w->id) { groupEnqueueGrabNotify (cw->screen, cw, x, y, state, mask); } } } UNWRAP(gs, w->screen, windowGrabNotify); (*w->screen->windowGrabNotify) (w, x, y, state, mask); WRAP(gs, w->screen, windowGrabNotify, groupWindowGrabNotify); } static void groupWindowUngrabNotify(CompWindow * w) { GROUP_SCREEN(w->screen); GROUP_DISPLAY(w->screen->display); GROUP_WINDOW(w); if (gw->inGroup && !gd->ignoreMode && !gs->ignoreCallback) { int i; for (i = 0; i < gw->group->nWins; i++) { CompWindow *cw = gw->group->windows[i]; if (!cw) continue; if (cw->id != w->id) { groupEnqueueUngrabNotify (cw->screen, cw); } } } UNWRAP(gs, w->screen, windowUngrabNotify); (*w->screen->windowUngrabNotify) (w); WRAP(gs, w->screen, windowUngrabNotify, groupWindowUngrabNotify); } /* * groupHandleChanges * */ static void groupHandleChanges(CompScreen* s) { int i; GROUP_SCREEN(s); GROUP_DISPLAY(s->display); GroupSelection *group; CompWindow* w; gs->ignoreCallback = TRUE; for(group = gd->groups; group; group = group->next) { // Ungroup if (group->prev) { if (group->prev->ungroup && !group->prev->animationSteps) groupDeleteGroup(s->display, group->prev); } if (!group->next) { if (group->ungroup && !group->animationSteps) { groupDeleteGroup(s->display, group); break; } } if (group->topTab == group->prevTopTab) continue; if (group->animationSteps == 0) { if (group->prevTopTab == -1) // Tab { for(i = 0; i < group->nWins; i++) { if (i == group->topTab) continue; w = group->windows[i]; moveWindow(w, w->screen->width, 0, FALSE, FALSE); syncWindowPosition(w); groupUpdatePosBuffer(w, WIN_X(w), WIN_Y(w), WIN_WIDTH(w), WIN_HEIGHT(w)); groupAddSkipMasks(w); } group->prevTopTab = group->topTab; group->dx = 0; group->dy = 0; } else if(group->topTab != -1) // Change Tab { CompWindow* topTab = TOP_TAB(group); CompWindow* prevTopTab = PREV_TOP_TAB(group); moveWindow(topTab, group->dx - topTab->screen->width, group->dy, FALSE, FALSE); syncWindowPosition(topTab); groupUpdatePosBuffer(topTab, WIN_X(topTab), WIN_Y(topTab), WIN_WIDTH(topTab), WIN_HEIGHT(topTab)); groupRemoveSkipMasks(topTab); activateWindow (topTab); moveWindow(prevTopTab, prevTopTab->screen->width, 0, FALSE, FALSE); syncWindowPosition(prevTopTab); groupUpdatePosBuffer(prevTopTab, WIN_X(prevTopTab), WIN_Y(prevTopTab), WIN_WIDTH(prevTopTab), WIN_HEIGHT(prevTopTab)); groupAddSkipMasks(prevTopTab); group->prevTopTab = group->topTab; group->dx = 0; group->dy = 0; } } else { // Untab if (group->topTab == -1) { for(i = 0; i < group->nWins; i++) { w = group->windows[i]; if(i == group->prevTopTab) continue; moveWindow(w, group->dx - w->screen->width, group->dy, FALSE, FALSE); syncWindowPosition(w); groupUpdatePosBuffer(w, WIN_X(w), WIN_Y(w), WIN_WIDTH(w), WIN_HEIGHT(w)); groupRemoveSkipMasks(w); } group->prevTopTab = group->topTab; group->dx = 0; group->dy = 0; } } } gs->ignoreCallback = FALSE; } /* * groupDrawTabAnimation * */ static void groupDrawTabAnimation(CompScreen * s) { GROUP_DISPLAY(s->display); int stepX, stepY; int i; GroupSelection *group; for(group = gd->groups; group; group = group->next) { if(!group->animationSteps) continue; for(i = 0; i < group->nWins; i++) { CompWindow *cw = group->windows[i]; if( i == group->topTab || i == group->prevTopTab) continue; if (!cw) continue; GROUP_WINDOW(cw); stepX = (gw->destinationX - WIN_X(cw)) / group->animationSteps; stepY = (gw->destinationY - WIN_Y(cw)) / group->animationSteps; moveWindow(cw, stepX, stepY, TRUE, FALSE); } group->animationSteps--; groupSyncWindows(group); } } /* * groupTabBarVertices * */ static void groupTabBarVertices(CompScreen *s, int x, int y, int width, int height) { GROUP_SCREEN(s); GROUP_DISPLAY(s->display); int i; int border_radius = gs->opt[GROUP_SCREEN_OPTION_BORDER_RADIUS].value.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(GroupSelection *group, GroupTabBarSlot *slot) { CompWindow *w = slot->window; CompWindow *topTab = TOP_TAB(group); int tw, th, tx, ty; tw = slot->width; th = slot->height; tx = slot->rx + group->tabBar->rx + WIN_X(topTab); ty = slot->ry + group->tabBar->ry + WIN_Y(topTab); WindowPaintAttrib sAttrib = w->lastPaint; 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); } } /* * groupPaintTabBar * */ static void groupPaintTabBar(GroupSelection * group) { if(group->topTab < 0 || !group->tabBar->visible) return; CompWindow *topTab = group->windows[group->topTab]; CompScreen *s = topTab->screen; GROUP_SCREEN(s); if (VIEWPORT(topTab->attrib.x, s)) return; glDisableClientState(GL_TEXTURE_COORD_ARRAY); glEnable(GL_BLEND); int x1, x2, y1, y2, width, height; width = group->tabBar->width; height = group->tabBar->height; x1 = group->tabBar->rx + WIN_X(topTab); y1 = group->tabBar->ry + WIN_Y(topTab); x2 = x1 + width; y2 = y1 + height; glColor4usv(gs->opt[GROUP_SCREEN_OPTION_TAB_FILL_COLOR].value.c); glBegin(GL_POLYGON); groupTabBarVertices(s, x1, y1, width, height); glEnd(); glColor4usv(gs->opt[GROUP_SCREEN_OPTION_TAB_BORDER_COLOR].value.c); glBegin(GL_LINE_LOOP); groupTabBarVertices(s, x1, y1, width, height); glEnd(); glColor4usv(defaultColor); glDisable(GL_BLEND); glEnableClientState(GL_TEXTURE_COORD_ARRAY); // draw thumbs if(gs->opt[GROUP_SCREEN_OPTION_TAB_CREATE_MIPMAPS].value.b) s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR; GroupTabBarSlot *slot; for(slot = group->tabBar->slots; slot; slot = slot->next) { groupPaintThumb(group, slot); } addWindowDamage(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); groupDequeueMoveNotifies (s); groupDequeueResizeNotifies (s); groupDequeueGrabNotifies (s); groupDequeueUngrabNotifies (s); groupHandleChanges(s); 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; // if we draw groups use BTF if (gd->groups) { 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(); } } 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); if (!(mask & PAINT_WINDOW_SOLID_MASK)) { if (gw->inGroup && gs->opt[GROUP_SCREEN_OPTION_GLOW].value.b) { if (mask & PAINT_WINDOW_TRANSFORMED_MASK) region = getInfiniteRegion(); if (region->numRects) { REGION box; CompMatrix matrix; box.rects = &box.extents; box.numRects = 1; w->vCount = 0; 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); box.extents.x1 = WIN_X(w) - w->input.left - overlapX; box.extents.y1 = WIN_Y(w) - w->input.top - overlapY; box.extents.x2 = WIN_X(w) + w->input.right + WIN_WIDTH(w) + overlapX; box.extents.y2 = WIN_Y(w) + w->input.right + WIN_HEIGHT(w) + overlapY; matrix = gs->glowTexture.matrix; matrix.xx = 1.0f / (box.extents.x2 - box.extents.x1); matrix.yy = -1.0f / (box.extents.y2 - box.extents.y1); matrix.x0 -= (box.extents.x1 * matrix.xx); matrix.y0 -= (box.extents.y1 * matrix.yy); if (box.extents.x1 < box.extents.x2 && box.extents.y1 < box.extents.y2) { (*w->screen->addWindowGeometry) (w, &matrix, 1, &box, region); } } if (w->vCount) { WindowPaintAttrib wAttrib; wAttrib.opacity = attrib->opacity; wAttrib.saturation = COLOR; wAttrib.brightness = BRIGHT; wAttrib.opacity = gw->group->color[3]; glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glColor4us(gw->group->color[0], gw->group->color[1], gw->group->color[2], ((gw->group->color[3] * wAttrib.opacity) / 0xFFFF)); (*w->screen->drawWindowTexture) (w, &gs->glowTexture, &wAttrib, mask | PAINT_WINDOW_TRANSLUCENT_MASK); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); screenTexEnvMode (w->screen, GL_REPLACE); glColor4usv(defaultColor); } } } UNWRAP(gs, w->screen, drawWindow); status = (*w->screen->drawWindow) (w, attrib, region, mask); if (gw->inGroup && gw->group->tabbed && gw->group->topTab != -1 && TOP_TAB(gw->group)->id == w->id) { groupPaintTabBar(gw->group); } WRAP(gs, w->screen, drawWindow, groupDrawWindow); return status; } /* * groupPaintWindow * */ static Bool groupPaintWindow(CompWindow * w, const WindowPaintAttrib * attrib, Region region, unsigned int mask) { Bool status; GROUP_SCREEN(w->screen); GROUP_WINDOW(w); 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; } if (gw->inGroup && gw->group->tabbed && gw->group->topTab != -1 && !gw->group->animationSteps && TOP_TAB(gw->group)->id != w->id) { return TRUE; } UNWRAP(gs, w->screen, paintWindow); status = (*w->screen->paintWindow) (w, &gAttrib, region, mask); WRAP(gs, w->screen, paintWindow, groupPaintWindow); 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_LEFT]; o->name = "change_tab_left"; o->group = N_(""); o->subGroup = N_(""); o->displayHints = ""; o->shortDesc = N_("Change Tab"); o->longDesc = N_("The key for changing the tab to the left."); o->type = CompOptionTypeAction; o->value.action.initiate = groupChangeTabLeft; 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_LEFT_MODIFIERS_DEFAULT; o->value.action.key.keysym = XStringToKeysym(GROUP_CHANGE_TAB_LEFT_KEY_DEFAULT); o = &gd->opt[GROUP_DISPLAY_OPTION_CHANGE_TAB_RIGHT]; o->name = "change_tab_right"; o->group = N_(""); o->subGroup = N_(""); o->displayHints = ""; o->shortDesc = N_("Change Tab"); o->longDesc = N_("The key for changing the tab to the right."); o->type = CompOptionTypeAction; o->value.action.initiate = groupChangeTabRight; 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_RIGHT_MODIFIERS_DEFAULT; o->value.action.key.keysym = XStringToKeysym(GROUP_CHANGE_TAB_RIGHT_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_LEFT: case GROUP_DISPLAY_OPTION_CHANGE_TAB_RIGHT: 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 = NULL; //gd->animatedGroup = -1; gd->tmpSel.windows = NULL; gd->tmpSel.nWins = 0; gd->groups = NULL; //gd->revGroups = NULL; 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) { GroupSelection *group; GroupSelection *following; for(group = gd->groups; group; group = following) { if (group) { following = group->next; free(group); } else { following = 0; } } } 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_LEFT].value.action); addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_CHANGE_TAB_RIGHT].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, paintWindow, groupPaintWindow); WRAP(gs, s, paintTransformedScreen, groupPaintTransformedScreen); WRAP(gs, s, windowGrabNotify, groupWindowGrabNotify); WRAP(gs, s, windowUngrabNotify, groupWindowUngrabNotify); s->privates[gd->screenPrivateIndex].ptr = gs; gs->grab = FALSE; gs->grabIndex = 0; gs->ignoreCallback = FALSE; gs->pendingMoves = NULL; gs->pendingResizes = NULL; gs->pendingGrabs = NULL; gs->pendingUngrabs = NULL; // bind texture for glow initTexture (s, &gs->glowTexture); imageToTexture (s, &gs->glowTexture, (char*) glowTex, 128, 128); 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_LEFT].value.action); removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_CHANGE_TAB_RIGHT].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, paintWindow); UNWRAP(gs, s, paintTransformedScreen); UNWRAP(gs, s, windowGrabNotify); UNWRAP(gs, s, windowUngrabNotify); 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->slot = NULL; 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; }