All pastes #278128 Raw Edit

Anonymous

public c v1 · immutable
·published 2006-12-13 21:30 UTC
rendered paste body
/** * * Beryl group plugin * * group.c * * Copyright : (C) 2006 by Patrick Niklaus * E-mail    : patrick.niklaus [ a t ] googlemail.com * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * * TODO: *      * glow effect *      * tab like switching between the windows *      * a lot of other tab stuff... *      * provide a tree system for groups * **/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <malloc.h>#include <time.h>#include <X11/Xlib.h>#include <beryl.h>#include <beryl_ipcs.h>#include <X11/Xatom.h>#include <math.h>#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")};/* * 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;	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;	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;	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 {	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	Bool animate;	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 voidgroupUpdatePosBuffer(CompWindow * w, int x, int y, int width, int height){	GROUP_WINDOW(w);	gw->oldX = x;	gw->oldY = y;	gw->oldWidth = width;	gw->oldHeight = height;}/* * groupAddSkipMasks * */static voidgroupAddSkipMasks(CompWindow *w){	unsigned int state = getWindowState (w->screen->display, w->id);	state |= CompWindowStateSkipTaskbarMask;	state |= CompWindowStateSkipPagerMask;	setWindowState (w->screen->display, state, w->id);}/* * groupRemoveSkipMasks * */static voidgroupRemoveSkipMasks(CompWindow *w){	unsigned int state = getWindowState (w->screen->display, w->id);	state &= ~CompWindowStateSkipTaskbarMask;	state &= ~CompWindowStateSkipPagerMask;	setWindowState (w->screen->display, state, w->id);}/* * groupFindWindowIndex * */static intgroupFindWindowIndex(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 voidgroupWindowMoveNotify(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));	// 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->group->tabbed &&			gw->group->topTab != -1)		{			if (TOP_TAB(gw->group)->id != w->id)			{				UNWRAP(gs, w->screen, windowMoveNotify);				moveWindow(w, -dx, -dy, TRUE, FALSE);				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->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) {					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->group;	gd->inAction = TRUE;}/* * groupRecalcTabBarPos * */static void groupRecalcTabBarPos(GroupSelection *group){	if (group->topTab < 0 || !group->tabbed || !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;		// calculate the space which the tabs need	int tabs_width = 0;	int tabs_height = 0;	GroupTabBarSlot *slot;	for(slot = group->tabBar->slots; slot; slot = slot->next)	{		tabs_width += slot->width;		if(slot->height > tabs_height)			tabs_height = slot->height;	}	bar->width = border_width * (bar->nSlots + 1) + tabs_width;	bar->height = border_width * 2 + tabs_height;	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;	bar->nSlots++;	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);}/* * groupCreateSlot * */static void groupCreateSlot(GroupSelection *group, CompWindow *w){	if(!group->tabbed || !group->tabBar)		return;	GROUP_WINDOW(w);	GROUP_SCREEN(w->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;				GroupTabBarSlot *slot = (GroupTabBarSlot*) malloc(sizeof(GroupTabBarSlot));	slot->window = w;	slot->width = thumb_size;	slot->height = thumb_size;	slot->rx = border_width + ((slot->width + border_width) * (group->tabBar->nSlots));	slot->ry = border_width;	groupInsertTabBarSlot(group->tabBar, slot);	gw->slot = slot;}/* * groupInitTabBar * */static void	groupInitTabBar(GroupSelection *group){	// error	if (group->topTab < 0 && group->tabbed)		return;	GroupTabBar *bar = (GroupTabBar*) malloc(sizeof(GroupTabBar));	bar->slots = NULL;	bar->nSlots = 0;	bar->visible = FALSE;	group->tabBar = bar;	int i;	for(i = 0; i < group->nWins; i++)	{		groupCreateSlot(group, group->windows[i]);	}	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;		gw->animate = TRUE;	}		damageScreen(main->screen);}/* * groupUntabGroup * */static voidgroupUntabGroup(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 -= mainOrgPosX + (WIN_WIDTH(PREV_TOP_TAB(group)) / 2) - (WIN_WIDTH(cw) / 2) - WIN_X(cw);		}						if(gw->destinationY > maxY)			maxY = gw->destinationY;					if(gw->destinationY < minY)			minY = gw->destinationY;				gw->orgPosX = 0;		gw->orgPosY = 0;		gw->animate = TRUE;	}		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 voidgroupAddWindowToGroup(CompDisplay * d, CompWindow * w, GroupSelection *group){	GROUP_DISPLAY(d);	GROUP_WINDOW(w);	GROUP_SCREEN(w->screen);	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;		if (group->tabbed && group->topTab >= 0)		{			CompWindow *topTab = TOP_TAB(group);			groupCreateSlot(group, w);			gw->destinationX = WIN_X(topTab) + (WIN_WIDTH(topTab) / 2) - (WIN_WIDTH(w) / 2);			gw->destinationY = WIN_Y(topTab) + (WIN_HEIGHT(topTab) / 2) - (WIN_HEIGHT(w) / 2);			gw->orgPosX = WIN_X(w) - gw->destinationX;			gw->orgPosY = WIN_Y(w) - gw->destinationY;			UNWRAP(gs, w->screen, windowMoveNotify);			moveWindow(w, w->screen->width, 0, FALSE, FALSE);			WRAP(gs, w->screen, windowMoveNotify, groupWindowMoveNotify);			syncWindowPosition(w);			groupUpdatePosBuffer(w, WIN_X(w), WIN_Y(w), WIN_WIDTH(w), WIN_HEIGHT(w));			groupAddSkipMasks(w);			//gw->animate = TRUE;			//group->animationSteps = gs->opt[GROUP_SCREEN_OPTION_STEPS].value.i;			damageScreen(w->screen);		}	} 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;		// 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 voidgroupRaiseWindows(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 BoolgroupSetScreenOption(CompScreen * s, char *name, CompOptionValue * value){	CompOption *o;	int index;	GROUP_SCREEN(s);	o = compFindOption(gs->opt, NUM_OPTIONS(gs), name, &index);	if (!o)		return FALSE;	switch (index) {	case GROUP_SCREEN_OPTION_TYPES:		if (compSetOptionList(o, value)) {			gs->wMask =			    compWindowTypeMaskFromStringList(&o->value);			return TRUE;		}		break;	case GROUP_SCREEN_OPTION_SELECTION_COLOR:	case GROUP_SCREEN_OPTION_LINE_COLOR:	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 BoolgroupSelectSingle(CompDisplay * d, CompAction * action,		  CompActionState state, CompOption * option, int nOption){	CompWindow *w = (CompWindow *) findWindowAtDisplay(d, d->activeWindow);	if (w)		groupSelectWindow(d, w);	return TRUE;}/* * groupSelect * */static BoolgroupSelect(CompDisplay * d, CompAction * action, CompActionState state,	    CompOption * option, int nOption){	CompWindow *w = (CompWindow *) findWindowAtDisplay(d, d->activeWindow);	if (!w)		return FALSE;	GROUP_SCREEN(w->screen);	if (!gs->grab) {		if (otherScreenGrabExist(w->screen, "group", 0))			return FALSE;		if (!gs->grabIndex)			gs->grabIndex =			    pushScreenGrab(w->screen, None, "group");		if (state & CompActionStateInitKey)			action->state |= CompActionStateTermKey;		if (state & CompActionStateInitButton)			action->state |= CompActionStateTermButton;		gs->x1 = gs->x2 = d->pointerX;		gs->y1 = gs->y2 = d->pointerY;		gs->grab = TRUE;	}	return TRUE;}/* * groupGroupWindows - pre-definition for groupSelectTerminate * */static BoolgroupGroupWindows(CompDisplay * d, CompAction * action,		  CompActionState state, CompOption * option, int nOption);/* * groupSelectTerminate * */static BoolgroupSelectTerminate(CompDisplay * d, CompAction * action,		     CompActionState state, CompOption * option,		     int nOption){	CompScreen *s;	Window xid;	xid = getIntOptionNamed(option, nOption, "root", 0);	for (s = d->screens; s; s = s->next) {		if (xid && s->root != xid)			continue;		break;	}	if (s) {		GROUP_SCREEN(s);		if (gs->grab) {			if (gs->grabIndex) {				removeScreenGrab(s, gs->grabIndex, NULL);				gs->grabIndex = 0;			}			if (gs->x1 != gs->x2 && gs->y1 != gs->y2) {				REGION reg;				reg.rects = &reg.extents;				reg.numRects = 1;				reg.extents.x1 = MIN(gs->x1, gs->x2) - 1;				reg.extents.y1 = MIN(gs->y1, gs->y2) - 1;				reg.extents.x2 = MAX(gs->x1, gs->x2) + 1;				reg.extents.y2 = MAX(gs->y1, gs->y2) + 1;				damageScreenRegion(s, &reg);				int count;				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 BoolgroupGroupWindows(CompDisplay * d, CompAction * action,		  CompActionState state, CompOption * option, int nOption){	GROUP_DISPLAY(d);	if (gd->tmpSel.nWins > 0) {		int i;		CompWindow *cw;		GroupSelection *group = NULL;		for(i = 0; i < gd->tmpSel.nWins; i++)		{			cw = gd->tmpSel.windows[i];			GROUP_WINDOW(cw);			if (gw->inGroup)			{				if (group == NULL)					group = gw->group;								if (group != gw->group) {					group = NULL;					break;				}			}		}		// we need to do one first to get the pointer of a new group		cw = gd->tmpSel.windows[0];		groupAddWindowToGroup(d, cw, group);		GROUP_WINDOW (cw);		gw->inSelection = FALSE;		damageScreen(cw->screen);		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 BoolgroupUnGroupWindows(CompDisplay * d, CompAction * action,		    CompActionState state, CompOption * option,		    int nOption){	CompWindow *cw = findWindowAtDisplay(d, d->activeWindow);	if (!cw)		return FALSE;	GROUP_WINDOW(cw);	if (gw->inGroup)		groupDeleteGroup(d, gw->group);	return FALSE;}/* * groupInitTab * */static BoolgroupInitTab(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 BoolgroupChangeTab(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 BoolgroupChangeTabLeft(CompDisplay * d, CompAction * action, CompActionState state,	       CompOption * option, int nOption){	return groupChangeTab(d, LEFT);}	       /* * groupChangeTabRight * */static BoolgroupChangeTabRight(CompDisplay * d, CompAction * action, CompActionState state,	       CompOption * option, int nOption){	return groupChangeTab(d, RIGHT);}/* * groupRemoveWindow * */static BoolgroupRemoveWindow(CompDisplay * d, CompAction * action,		  CompActionState state, CompOption * option, int nOption){	CompWindow *cw = findWindowAtDisplay(d, d->activeWindow);	if (!cw)		return FALSE;	GROUP_WINDOW(cw);	if (gw->inGroup)		groupDeleteGroupWindow(d, cw);	return FALSE;}/* * groupCloseWindows * */static BoolgroupCloseWindows(CompDisplay * d, CompAction * action,		  CompActionState state, CompOption * option, int nOption){	CompWindow *w = findWindowAtDisplay(d, d->activeWindow);	if (!w)		return FALSE;	GROUP_WINDOW(w);	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 BoolgroupMinimizeWindows(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 BoolgroupSetIgnore(CompDisplay * d, CompAction * action, CompActionState state,	       CompOption * option, int nOption){	GROUP_DISPLAY(d);	gd->ignoreMode = TRUE;	if (state & CompActionStateInitKey)		action->state |= CompActionStateTermKey;	return FALSE;}/* * groupUnsetIgnore * */static BoolgroupUnsetIgnore(CompDisplay * d, CompAction * action,		 CompActionState state, CompOption * option, int nOption){	GROUP_DISPLAY(d);	gd->ignoreMode = FALSE;	action->state &= ~CompActionStateTermKey;	return FALSE;}/* * groupHandleMotionEvent - pre-definition for groupHandleEvent * */static 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->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) {				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->group;		gd->inAction = TRUE;	}	groupUpdatePosBuffer(w, WIN_X(w), WIN_Y(w), WIN_WIDTH(w), WIN_HEIGHT(w));}static voidgroupWindowGrabNotify(CompWindow * w,                       int x, int y, unsigned int state, unsigned int mask){        GROUP_SCREEN(w->screen);        GROUP_DISPLAY(w->screen->display);        GROUP_WINDOW(w);        UNWRAP(gs, w->screen, windowGrabNotify);        (*w->screen->windowGrabNotify) (w, x, y, state, mask);        WRAP(gs, w->screen, windowGrabNotify, groupWindowGrabNotify);        if (gw->inGroup && !gd->ignoreMode) {        	int i;                for (i = 0; i < gw->group->nWins; i++) {                	CompWindow *cw = gw->group->windows[i];                        if (!cw)                        	continue;                        if (cw->id != w->id) {                        	UNWRAP(gs, cw->screen, windowGrabNotify);				(*cw->screen->windowGrabNotify) (cw, x, y, state, mask);				WRAP(gs, cw->screen, windowGrabNotify,                                             groupWindowGrabNotify);			}		}	}}static void groupWindowUngrabNotify(CompWindow * w){        GROUP_SCREEN(w->screen);        GROUP_DISPLAY(w->screen->display);        GROUP_WINDOW(w);        UNWRAP(gs, w->screen, windowUngrabNotify);        (*w->screen->windowUngrabNotify) (w);        WRAP(gs, w->screen, windowUngrabNotify, groupWindowUngrabNotify);        if (gw->inGroup && !gd->ignoreMode) {        	int i;                for (i = 0; i < gw->group->nWins; i++) {                	CompWindow *cw = gw->group->windows[i];                        if (!cw)                                continue;                        if (cw->id != w->id) {                                UNWRAP(gs, cw->screen, windowUngrabNotify);				(*cw->screen->windowUngrabNotify) (cw);				WRAP(gs, cw->screen, windowUngrabNotify,                                             groupWindowUngrabNotify);			}		}	}}/* * groupHandleChanges * */static voidgroupHandleChanges(CompScreen* s){	int i;	GROUP_SCREEN(s);	GROUP_DISPLAY(s->display);		GroupSelection *group;	CompWindow* w;	UNWRAP(gs, s, windowMoveNotify);	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;			}		}		// we can skip everything else..		if (group->topTab == group->prevTopTab)			continue;				if (group->animationSteps == 0)		{			if (group->prevTopTab == -1) // Tab			{				printf ("Tab!\n");				for(i = 0; i < group->nWins; i++)				{										if (i == group->topTab)						continue;					w = group->windows[i];					GROUP_WINDOW(w);					if (!gw->animate)						continue;									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);										gw->animate = FALSE;				}				group->prevTopTab = group->topTab;			}						else if(group->topTab != -1) // Change Tab			{				printf ("Change Tab!\n");				CompWindow  *topTab = TOP_TAB(group);				GROUP_WINDOW(topTab);				CompWindow  *prevTopTab = PREV_TOP_TAB(group);								int startX, startY;				startX = WIN_X(prevTopTab) - WIN_X(topTab);				startY = WIN_Y(prevTopTab) - WIN_Y(topTab);				moveWindow(topTab, startX, startY, 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;			}		}		else		{			// Untab			if (group->topTab == -1)			{				printf ("Untab!\n");				CompWindow  *prevTopTab = PREV_TOP_TAB(group);				for(i = 0; i < group->nWins; i++) {					w = group->windows[i];								if(i == group->prevTopTab)						continue;					GROUP_WINDOW(w);										int startX, startY;					startX = WIN_X(prevTopTab) - (WIN_X(w) / (VIEWPORT(WIN_X(w), w->screen)+1));					startY = WIN_Y(prevTopTab) - (WIN_Y(w) / (VIEWPORT(WIN_Y(w), w->screen)+1));					moveWindow(w, startX, startY, FALSE, FALSE);					syncWindowPosition(w);					groupUpdatePosBuffer(w, WIN_X(w), WIN_Y(w), WIN_WIDTH(w), WIN_HEIGHT(w));					groupRemoveSkipMasks(w);				}						group->prevTopTab = group->topTab;			}		}	}		WRAP(gs, s, windowMoveNotify, groupWindowMoveNotify);}/* * groupDrawTabAnimation * */static void groupDrawTabAnimation(CompScreen * s){	GROUP_SCREEN(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);			if (!gw->animate)				continue;			stepX = (gw->destinationX - WIN_X(cw)) / group->animationSteps;			stepY = (gw->destinationY - WIN_Y(cw)) / group->animationSteps;			UNWRAP(gs, cw->screen, windowMoveNotify);			moveWindow(cw, stepX, stepY, TRUE, FALSE);			WRAP(gs, cw->screen, windowMoveNotify, groupWindowMoveNotify);		}				group->animationSteps--;			groupSyncWindows(group);	}}/* * groupTabBarVertices * */static voidgroupTabBarVertices(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);	groupHandleChanges(s);		groupDrawTabAnimation(s);}/*  * groupPaintScreen * */static BoolgroupPaintScreen(CompScreen * s,		 const ScreenPaintAttrib * sAttrib,		 Region region, int output, unsigned int mask){	GROUP_SCREEN(s);	GROUP_DISPLAY(s->display);	Bool status;	gs->wasTransformed = FALSE;	// 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 voidgroupPaintTransformedScreen(CompScreen * s, const ScreenPaintAttrib * sa,			    Region region, int output, unsigned int mask){	GROUP_SCREEN(s);	UNWRAP(gs, s, paintTransformedScreen);	(*s->paintTransformedScreen) (s, sa, region, output, mask);	WRAP(gs, s, paintTransformedScreen, groupPaintTransformedScreen);	if (gs->grab) {		gs->wasTransformed = TRUE;		int x1, x2, y1, y2;		x1 = MIN(gs->x1, gs->x2);		y1 = MIN(gs->y1, gs->y2);		x2 = MAX(gs->x1, gs->x2);		y2 = MAX(gs->y1, gs->y2);		if (gs->grabIndex) {			glPushMatrix();			glLoadIdentity();			(s->applyScreenTransform) (s, sa, output);			prepareXCoords(s, output, -sa->zTranslate);			glDisableClientState(GL_TEXTURE_COORD_ARRAY);			glEnable(GL_BLEND);			glColor4usv(gs->opt[GROUP_SCREEN_OPTION_SELECTION_COLOR].value.c);			glRecti(x1, y2, x2, y1);			glColor4usv(gs->opt[GROUP_SCREEN_OPTION_LINE_COLOR].value.c);			glBegin(GL_LINE_LOOP);			glVertex2i(x1, y1);			glVertex2i(x2, y1);			glVertex2i(x2, y2);			glVertex2i(x1, y2);			glEnd();			glColor4usv(defaultColor);			glDisable(GL_BLEND);			glEnableClientState(GL_TEXTURE_COORD_ARRAY);			glPopMatrix();		}	}}/* * groupDrawWindow * */static BoolgroupDrawWindow(CompWindow * w,		const WindowPaintAttrib * attrib,		Region region, unsigned int mask){	Bool status;	GROUP_WINDOW(w);	GROUP_SCREEN(w->screen);	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 BoolgroupPaintWindow(CompWindow * w,		const WindowPaintAttrib * attrib,		Region region, unsigned int mask){	Bool status;	GROUP_SCREEN(w->screen);	GROUP_WINDOW(w);	WindowPaintAttrib gAttrib = *attrib;	if (gw->inGroup &&		gw->group->tabbed && gw->group->topTab != -1 &&		!gw->group->animationSteps &&		TOP_TAB(gw->group)->id != w->id) {		return TRUE;	}	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;	}	// paint glow	if (gw->inGroup && gs->opt[GROUP_SCREEN_OPTION_GLOW].value.b) {		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(gw->group->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) - w->input.left - overlapX;		y1 = WIN_Y(w) - w->input.top - overlapY;		x2 = WIN_X(w) + w->input.right + WIN_WIDTH(w) + overlapX;		y2 = WIN_Y(w) + w->input.right + 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, 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 = &reg.extents;		reg.numRects = 1;		reg.extents.x1 = MIN(gs->x1, gs->x2) - 1;		reg.extents.y1 = MIN(gs->y1, gs->y2) - 1;		reg.extents.x2 = MAX(gs->x1, gs->x2) + 1;		reg.extents.y2 = MAX(gs->y1, gs->y2) + 1;		damageScreenRegion(s, &reg);		gs->x2 = xRoot;		gs->y2 = yRoot;		reg.extents.x1 = MIN(gs->x1, gs->x2) - 1;		reg.extents.y1 = MIN(gs->y1, gs->y2) - 1;		reg.extents.x2 = MAX(gs->x1, gs->x2) + 1;		reg.extents.y2 = MAX(gs->y1, gs->y2) + 1;		damageScreenRegion(s, &reg);	}}/* * 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 BoolgroupSetDisplayOption(CompDisplay * d, char *name, CompOptionValue * value){	CompOption *o;	int index;	GROUP_DISPLAY(d);	o = compFindOption(gd->opt, NUM_OPTIONS(gd), name, &index);	if (!o)		return FALSE;	switch (index) {	case GROUP_DISPLAY_OPTION_SELECT:	case GROUP_DISPLAY_OPTION_SELECT_SINGLE:	case GROUP_DISPLAY_OPTION_GROUPING:	case GROUP_DISPLAY_OPTION_UNGROUPING:	case GROUP_DISPLAY_OPTION_REMOVEING:	case GROUP_DISPLAY_OPTION_CLOSEING:	case GROUP_DISPLAY_OPTION_MINIMIZEING:	case GROUP_DISPLAY_OPTION_IGNORE:	case GROUP_DISPLAY_OPTION_TABMODE:	case GROUP_DISPLAY_OPTION_CHANGE_TAB_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;		for(group = gd->groups; group; group = group->next)		{			if (group->prev)				free(group->prev);			if (!group->next) {				free(group);				break;			}		}	}	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;	// 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_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->animate = FALSE;	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;}