[beryl-commits] r1488 - in branches: . beryl-group-with-tab-plugin
marex at server.beryl-project.org
marex at server.beryl-project.org
Sat Dec 2 00:22:55 CET 2006
Author: marex
Date: 2006-12-02 00:22:54 +0100 (Sat, 02 Dec 2006)
New Revision: 1488
Added:
branches/beryl-group-with-tab-plugin/
branches/beryl-group-with-tab-plugin/Makefile
branches/beryl-group-with-tab-plugin/README
branches/beryl-group-with-tab-plugin/group.c
Log:
group-tab-branch: init working branch (the animation works already)
Added: branches/beryl-group-with-tab-plugin/Makefile
===================================================================
--- branches/beryl-group-with-tab-plugin/Makefile (rev 0)
+++ branches/beryl-group-with-tab-plugin/Makefile 2006-12-01 23:22:54 UTC (rev 1488)
@@ -0,0 +1,26 @@
+DESTDIR = /usr/lib/beryl
+
+PLUGIN = group
+
+CC = gcc
+LIBTOOL = libtool
+INSTALL = install
+
+CFLAGS = -g -Wall `pkg-config --cflags beryl`
+LDFLAGS = `pkg-config --libs beryl`
+
+%.lo: %.c
+ $(LIBTOOL) --mode=compile $(CC) $(CFLAGS) -c -o $@ $<
+
+%.la: $(PLUGIN).lo
+ $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -rpath $(DESTDIR) -o $@ $<
+
+all: lib$(PLUGIN).la
+
+install: lib$(PLUGIN).la
+ $(LIBTOOL) --mode=install $(INSTALL) lib$(PLUGIN).la \
+ $(DESTDIR)/lib$(PLUGIN).la
+
+clean:
+ rm -rf *.lo *.o lib$(PLUGIN).* .libs
+
Property changes on: branches/beryl-group-with-tab-plugin/Makefile
___________________________________________________________________
Name: svn:executable
+ *
Added: branches/beryl-group-with-tab-plugin/README
===================================================================
--- branches/beryl-group-with-tab-plugin/README (rev 0)
+++ branches/beryl-group-with-tab-plugin/README 2006-12-01 23:22:54 UTC (rev 1488)
@@ -0,0 +1,6 @@
+=============== !!! =================
+!!! DO NOT ACTUALLY USE THIS CODE !!!
+IT'S A WORKING BRANCH WITH REALLY
+UNSTABLE AND UNFINISHED CODE.
+IT'S NEEDED FOR CODE SYNC ONLY.
+=============== ... =================
Added: branches/beryl-group-with-tab-plugin/group.c
===================================================================
--- branches/beryl-group-with-tab-plugin/group.c (rev 0)
+++ branches/beryl-group-with-tab-plugin/group.c 2006-12-01 23:22:54 UTC (rev 1488)
@@ -0,0 +1,2316 @@
+/**
+ *
+ * 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>
+
+/*
+ * 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_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_NUM 9
+
+#define GROUP_OPACITY_DEFAULT 80
+#define GROUP_OPACITY_MIN 0
+#define GROUP_OPACITY_MAX 100
+
+#define GROUP_SATURATION_DEFAULT 20
+#define GROUP_SATURATION_MIN 0
+#define GROUP_SATURATION_MAX 100
+
+#define GROUP_BRIGHTNESS_DEFAULT 70
+#define GROUP_BRIGHTNESS_MIN 0
+#define GROUP_BRIGHTNESS_MAX 100
+
+#define GROUP_TOLERANCE_DEFAULT 0
+#define GROUP_TOLERANCE_MIN 0
+#define GROUP_TOLERANCE_MAX 10
+
+#define GROUP_STEPS_DEFAULT 10
+#define GROUP_STEPS_MIN 1
+#define GROUP_STEPS_MAX 10
+
+#define GROUP_MOVE_DEFAULT TRUE
+#define GROUP_RESIZE_DEFAULT TRUE
+#define GROUP_RAISE_DEFAULT TRUE
+#define GROUP_AUTO_UNGROUP_DEFAULT FALSE
+#define GROUP_AUTO_GROUP_DEFAULT FALSE
+#define GROUP_RELATIVE_DISTANCE_DEFAULT FALSE
+
+#define GROUP_COLOR_SELECTION_RED_DEFAULT 0x0000
+#define GROUP_COLOR_SELECTION_GREEN_DEFAULT 0x0000
+#define GROUP_COLOR_SELECTION_BLUE_DEFAULT 0x0000
+#define GROUP_COLOR_SELECTION_ALPHA_DEFAULT 0x9999
+
+#define GROUP_COLOR_LINE_RED_DEFAULT 0x0000
+#define GROUP_COLOR_LINE_GREEN_DEFAULT 0x0000
+#define GROUP_COLOR_LINE_BLUE_DEFAULT 0x0000
+#define GROUP_COLOR_LINE_ALPHA_DEFAULT 0xABAB
+
+#define GROUP_SCREEN_OPTION_TYPES 0
+#define GROUP_SCREEN_OPTION_OPACITY 1
+#define GROUP_SCREEN_OPTION_SATURATION 2
+#define GROUP_SCREEN_OPTION_BRIGHTNESS 3
+#define GROUP_SCREEN_OPTION_MOVE 4
+#define GROUP_SCREEN_OPTION_RESIZE 5
+#define GROUP_SCREEN_OPTION_RAISE 6
+#define GROUP_SCREEN_OPTION_AUTO_UNGROUP 7
+#define GROUP_SCREEN_OPTION_AUTO_GROUP 8
+#define GROUP_SCREEN_OPTION_RELATIVE_DISTANCE 9
+#define GROUP_SCREEN_OPTION_SELECTION_COLOR 10
+#define GROUP_SCREEN_OPTION_LINE_COLOR 11
+#define GROUP_SCREEN_OPTION_TOLERANCE 12
+#define GROUP_SCREEN_OPTION_STEPS 13
+#define GROUP_SCREEN_OPTION_NUM 14
+
+/*
+ * Helpers
+ *
+ */
+#define GET_GROUP_DISPLAY(d) ((GroupDisplay *) (d)->privates[displayPrivateIndex].ptr)
+#define GROUP_DISPLAY(d) GroupDisplay *gd = GET_GROUP_DISPLAY (d)
+#define GET_GROUP_SCREEN(s, gd) ((GroupScreen *) (s)->privates[ (gd)->screenPrivateIndex].ptr)
+#define GROUP_SCREEN(s) GroupScreen *gs = GET_GROUP_SCREEN (s, GET_GROUP_DISPLAY (s->display))
+#define GET_GROUP_WINDOW(w, gs) ((GroupWindow *) (w)->privates[ (gs)->windowPrivateIndex].ptr)
+#define GROUP_WINDOW(w) GroupWindow *gw = GET_GROUP_WINDOW (w, GET_GROUP_SCREEN (w->screen, GET_GROUP_DISPLAY (w->screen->display)))
+
+#define WIN_X(w) (w->attrib.x)
+#define WIN_Y(w) (w->attrib.y)
+#define WIN_WIDTH(w) (w->attrib.width)
+#define WIN_HEIGHT(w) (w->attrib.height)
+#define WIN_BORDER(w) (w->attrib.border_width)
+
+#define NUM_OPTIONS(s) (sizeof ( (s)->opt) / sizeof (CompOption))
+#define N_WIN_TYPE (sizeof (groupDefaultTypes) / sizeof (groupDefaultTypes[0]))
+#define N_SEL_MODE (sizeof (groupSelectionModes) / sizeof (groupSelectionModes[0]))
+
+/*
+ * default windows for selection
+ */
+static char* groupDefaultTypes[] = {
+ N_("Normal"),
+ N_("Dialog"),
+ N_("ModalDialog"),
+ N_("Dnd")
+};
+
+/*
+ * pointer to display list
+ */
+static int displayPrivateIndex;
+
+/*
+ * Call-Back for state
+ */
+typedef void (*AddWindowToGroupProc) (CompDisplay *d, CompWindow *w, int groupID);
+
+/*
+ * GroupSelection
+ */
+typedef struct _GroupSelection {
+ Window* windows;
+ int nWins;
+ int id;
+
+ Bool tabbed;
+} GroupSelection;
+
+/*
+ * GroupDisplay structure
+ */
+typedef struct _GroupDisplay {
+ int screenPrivateIndex;
+ CompOption opt[GROUP_DISPLAY_OPTION_NUM];
+ HandleEventProc handleEvent;
+
+ GroupSelection tmpSel;
+
+ GroupSelection* groups;
+ int nGroups;
+
+ Bool inAction;
+ int lastActiveGroup;
+
+ Bool ignoreMode;
+
+} GroupDisplay;
+
+/*
+ * GroupScreen structure
+ */
+typedef struct _GroupScreen {
+ int windowPrivateIndex;
+ CompOption opt[GROUP_SCREEN_OPTION_NUM];
+
+ WindowMoveNotifyProc windowMoveNotify;
+ WindowResizeNotifyProc windowResizeNotify;
+ PaintScreenProc paintScreen;
+ PaintWindowProc paintWindow;
+ PaintTransformedScreenProc paintTransformedScreen;
+
+ int wMask;
+
+ // for selection
+ Bool grab;
+ Bool wasTransformed;
+ int grabIndex;
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+
+} GroupScreen;
+
+/*
+ * GroupWindow structure
+ */
+typedef struct _GroupWindow {
+ int groupID;
+ Bool inGroup;
+ Bool inSelection;
+
+ // for scale notify...
+ int oldWidth;
+ int oldHeight;
+ int oldX;
+ int oldY;
+
+ // for tab animation
+ Bool animate;
+ Bool tabWindow;
+ float stepX;
+ float stepY;
+ int steps;
+ int orgPosX;
+ int orgPosY;
+ int destinationX;
+ int destinationY;
+
+} GroupWindow;
+
+/*
+ * groupFindGroupAtDisplay
+ * Note: Returns the index of the group in gd->groups!
+ *
+ */
+static int
+groupFindGroupAtDisplay (GroupDisplay *gd, int id)
+{
+ int i;
+ for (i = 0; i < gd->nGroups; i++)
+ {
+ if (gd->groups[i].id == id)
+ return i;
+ }
+
+ return -1;
+}
+
+#define TOLRNC_MIN(n1, n2, t) (n1 - t < n2)
+#define TOLRNC_MAX(n1, n2, t) (n1 + t > n2)
+
+/*
+ * groupFindWindowsInRegion
+ *
+ */
+static Window*
+groupFindWindowsInRegion (CompScreen *s, REGION reg, int *c)
+{
+ GROUP_SCREEN(s);
+
+ float tolerance = gs->opt[GROUP_SCREEN_OPTION_TOLERANCE].value.i / 10.0f;
+
+ Window *ret = NULL;
+ int count = 0;
+ CompWindow *w;
+ for (w = s->windows; w; w = w->next)
+ {
+ if ((gs->wMask & w->type) &&
+ !w->invisible &&
+ TOLRNC_MIN(reg.extents.x1, WIN_X (w), tolerance * WIN_WIDTH (w)) &&
+ TOLRNC_MIN(reg.extents.y1, WIN_Y (w), tolerance * WIN_HEIGHT (w)) &&
+ TOLRNC_MAX(reg.extents.x2, (WIN_X (w) + WIN_WIDTH (w)), tolerance * WIN_WIDTH (w)) &&
+ TOLRNC_MAX(reg.extents.y2, (WIN_Y (w) + WIN_HEIGHT (w)), tolerance * WIN_HEIGHT (w)))
+ {
+ if (count == 0) {
+ ret = calloc (1, sizeof (Window));
+ ret[0] = w->id;
+ } else {
+ ret = realloc (ret, sizeof (Window) * (count+1));
+ ret[count] = w->id;
+ }
+ count++;
+ }
+ }
+ (*c) = count;
+ return ret;
+}
+
+/*
+ * groupTabGroup
+ *
+ */
+static void
+groupTabGroup (CompDisplay *d, CompWindow *main, int groupID)
+{
+ GROUP_DISPLAY (d);
+ GROUP_SCREEN (main->screen);
+
+ int index = groupFindGroupAtDisplay (gd, groupID);
+ if (index == -1)
+ return;
+
+ gd->groups[index].tabbed = TRUE;
+ gd->lastActiveGroup = groupID;
+
+ // main window
+ GROUP_WINDOW (main);
+ gw->tabWindow = TRUE;
+ gw->animate = FALSE;
+ gw->stepX = 0.0f;
+ gw->stepY = 0.0f;
+ gw->orgPosX = 0;
+ gw->orgPosY = 0;
+ gw->destinationX = 0;
+ gw->destinationY = 0;
+
+ int i;
+ int steps = gs->opt[GROUP_SCREEN_OPTION_STEPS].value.i;
+ for (i = 0; i < gd->groups[index].nWins; i++)
+ {
+ CompWindow *cw = findWindowAtDisplay (d, gd->groups[index].windows[i]);
+ if (!cw || cw->id == main->id)
+ continue;
+ GROUP_WINDOW (cw);
+
+ gw->stepX = (float) (WIN_X (main) - WIN_X (cw)) / (float) steps;
+ gw->stepY = (float) (WIN_Y (main) - WIN_Y (cw)) / (float) steps;
+ gw->steps = steps;
+ gw->orgPosX = WIN_X (cw);
+ gw->orgPosY = WIN_Y (cw);
+ gw->destinationX = WIN_X (main);
+ gw->destinationY = WIN_Y (main);
+ gw->animate = TRUE;
+ }
+
+ damageScreen (main->screen);
+}
+
+/*
+ * groupUntabGroup
+ *
+ */
+static void
+groupUntabGroup (CompDisplay *d, CompWindow *main, int groupID)
+{
+ GROUP_DISPLAY (d);
+ GROUP_SCREEN (main->screen);
+
+ int index = groupFindGroupAtDisplay (gd, groupID);
+ if (index == -1)
+ return;
+
+ gd->groups[index].tabbed = FALSE;
+ gd->lastActiveGroup = groupID;
+
+ // main window
+ GROUP_WINDOW (main);
+ gw->tabWindow = TRUE;
+ gw->animate = FALSE;
+ gw->stepX = 0.0f;
+ gw->stepY = 0.0f;
+ gw->orgPosX = 0;
+ gw->orgPosY = 0;
+ gw->destinationX = 0;
+ gw->destinationY = 0;
+
+ int i;
+ int steps = gs->opt[GROUP_SCREEN_OPTION_STEPS].value.i;
+ for (i = 0; i < gd->groups[index].nWins; i++)
+ {
+ CompWindow *cw = findWindowAtDisplay (d, gd->groups[index].windows[i]);
+ if (!cw || cw->id == main->id)
+ continue;
+ GROUP_WINDOW (cw);
+
+ gw->stepX = (float) (gw->orgPosX - WIN_X (main)) / (float) steps;
+ gw->stepY = (float) (gw->orgPosY - WIN_Y (main)) / (float) steps;
+ gw->steps = steps;
+ gw->destinationX = gw->orgPosX;
+ gw->destinationY = gw->orgPosY;
+ gw->orgPosX = WIN_X (cw);
+ gw->orgPosY = WIN_Y (cw);
+ gw->animate = TRUE;
+ }
+
+ damageScreen (main->screen);
+}
+
+/*
+ * groupDeleteGroup - pre-definition for groupDeleteGroupWindow
+ *
+ */
+static void groupDeleteGroup (CompDisplay *d, int id);
+
+/*
+ * groupDeleteGroupWindow
+ *
+ */
+static void
+groupDeleteGroupWindow (CompDisplay *d, CompWindow *w)
+{
+ GROUP_DISPLAY (d);
+ GROUP_WINDOW (w);
+ GROUP_SCREEN (w->screen);
+
+ int index = groupFindGroupAtDisplay (gd, gw->groupID);
+ if (index == -1)
+ return;
+
+ if (gd->groups[index].nWins != 0 && gd->groups[index].windows != NULL)
+ {
+ Window *buf = gd->groups[index].windows;
+
+ gd->groups[index].windows = (Window*) calloc (gd->groups[index].nWins-1, sizeof (Window));
+
+ int counter = 0;
+ int i;
+ for (i = 0; i < gd->groups[index].nWins; i++)
+ {
+ if (buf[i] == w->id)
+ continue;
+ gd->groups[index].windows[counter++] = buf[i];
+ }
+ gd->groups[index].nWins = counter;
+
+ if (gd->groups[index].nWins == 1 &&
+ gs->opt[GROUP_SCREEN_OPTION_AUTO_UNGROUP].value.b)
+ {
+ groupDeleteGroup (d, gw->groupID);
+ }
+ else if (gd->groups[index].nWins <= 0)
+ {
+ free (gd->groups[index].windows);
+ gd->groups[index].windows = NULL;
+ groupDeleteGroup (d, gw->groupID);
+ }
+
+ free (buf);
+
+ gw->inGroup = FALSE;
+ }
+}
+
+/*
+ * groupDeleteGroup
+ *
+ */
+static void
+groupDeleteGroup (CompDisplay *d, int id)
+{
+ GROUP_DISPLAY (d);
+ gd->inAction = TRUE;
+ gd->lastActiveGroup = -1;
+
+ int index = groupFindGroupAtDisplay (gd, id);
+ if (index == -1) {
+ gd->inAction = FALSE;
+ return;
+ }
+
+ if (gd->groups[index].windows != NULL)
+ {
+ int i;
+ for (i = 0; i < gd->groups[index].nWins; i++)
+ {
+ CompWindow *cw = findWindowAtDisplay (d, gd->groups[index].windows[i]);
+ if (!cw)
+ continue;
+
+ GROUP_WINDOW (cw);
+ gw->inGroup = FALSE;
+ }
+ free (gd->groups[index].windows);
+ }
+
+ GroupSelection *groupsBuf = gd->groups;
+ gd->groups = calloc (gd->nGroups-1, sizeof (GroupSelection));
+ int counter = 0;
+ int i;
+ for (i = 0; i < gd->nGroups; i++)
+ {
+ if (groupsBuf[i].id == id) {
+ continue;
+ }
+
+ gd->groups[counter++] = groupsBuf[i];
+ }
+ gd->nGroups--;
+ free (groupsBuf);
+
+ gd->inAction = FALSE;
+}
+
+/*
+ * groupAddWindowToGroup
+ *
+ */
+static void
+groupAddWindowToGroup (CompDisplay *d, CompWindow *w, int groupID)
+{
+ GROUP_DISPLAY (d);
+ GROUP_WINDOW (w);
+
+ if (gw->inGroup) {
+ groupDeleteGroupWindow (d, w);
+ }
+
+ int index = groupFindGroupAtDisplay (gd, groupID);
+ if (index == -1)
+ {
+ GroupSelection g;
+
+ g.id = groupID;
+ g.windows = (Window*) calloc (1, sizeof (Window));
+ g.windows[0] = w->id;
+ g.nWins = 1;
+ g.tabbed = FALSE;
+
+ gd->groups = (GroupSelection*) realloc (gd->groups, sizeof (GroupSelection)* (gd->nGroups+1));
+ gd->groups[gd->nGroups] = g;
+ gd->nGroups++;
+
+ gw->groupID = groupID;
+ gw->inGroup = TRUE;
+ }
+ else
+ {
+ gd->groups[index].windows = (Window*) realloc (gd->groups[index].windows, sizeof (Window)* (gd->groups[index].nWins+1));
+ gd->groups[index].windows[gd->groups[index].nWins] = w->id;
+ gd->groups[index].nWins++;
+
+ gw->groupID = groupID;
+ gw->inGroup = TRUE;
+ }
+}
+
+/*
+ * groupDeleteSelectionWindow
+ *
+ */
+static void
+groupDeleteSelectionWindow (CompDisplay *d, CompWindow *w)
+{
+ GROUP_DISPLAY (d);
+
+ if (gd->tmpSel.nWins > 0 && gd->tmpSel.windows)
+ {
+ Window *buf = gd->tmpSel.windows;
+ gd->tmpSel.windows = (Window*) calloc (gd->tmpSel.nWins-1, sizeof (Window));
+
+ int counter = 0;
+ int i;
+ for (i = 0; i < gd->tmpSel.nWins; i++)
+ {
+ if (buf[i] == w->id)
+ continue;
+ gd->tmpSel.windows[counter++] = buf[i];
+ }
+
+ gd->tmpSel.nWins = counter;
+ free (buf);
+ }
+}
+
+/*
+ * groupAddWindowToSelection
+ *
+ */
+static void
+groupAddWindowToSelection (CompDisplay *d, CompWindow *w)
+{
+ GROUP_DISPLAY (d);
+
+ gd->tmpSel.windows = (Window*) realloc (gd->tmpSel.windows,
+ sizeof (Window)* (gd->tmpSel.nWins+1));
+
+ gd->tmpSel.windows[gd->tmpSel.nWins] = w->id;
+ gd->tmpSel.nWins++;
+}
+
+/*
+ * groupSyncWindows
+ *
+ */
+static void
+groupSyncWindows (CompDisplay *d, int groupID)
+{
+ GROUP_DISPLAY (d);
+
+ int index = groupFindGroupAtDisplay (gd, groupID);
+ if (index == -1)
+ return;
+
+ int i;
+ for (i = 0; i < gd->groups[index].nWins; i++)
+ {
+ CompWindow *w = findWindowAtDisplay (d, gd->groups[index].windows[i]);
+ if (!w)
+ continue;
+ syncWindowPosition (w);
+ }
+}
+
+/*
+ * 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;
+}
+
+/*
+ * groupRaiseWindows
+ *
+ */
+static void
+groupRaiseWindows (CompDisplay *d, CompWindow *top, int groupID)
+{
+ GROUP_DISPLAY (d);
+
+ int index = groupFindGroupAtDisplay (gd, groupID);
+ if (index == -1)
+ return;
+
+ int i;
+ for (i = 0; i < gd->groups[index].nWins; i++)
+ {
+ CompWindow *w = findWindowAtDisplay (d, gd->groups[index].windows[i]);
+ if (!w || w->id == top->id)
+ continue;
+ restackWindowBelow (w, top);
+ }
+}
+
+/*
+ * groupScreenInitOptions
+ *
+ */
+static void
+groupScreenInitOptions (GroupScreen *gs)
+{
+
+ CompOption *o;
+ int i;
+
+ o = &gs->opt[GROUP_SCREEN_OPTION_TYPES];
+ o->name = "mask";
+ o->group = N_("");
+ o->subGroup = N_("");
+ o->displayHints = "";
+ o->shortDesc = N_("Window Types");
+ o->longDesc = N_("The types of windows which will be grouped");
+ o->type = CompOptionTypeList;
+ o->value.list.type = CompOptionTypeString;
+ o->value.list.nValue = N_WIN_TYPE;
+ o->value.list.value = malloc (sizeof (CompOptionValue) * N_WIN_TYPE);
+ for (i = 0; i < N_WIN_TYPE; i++) {
+ o->value.list.value[i].s = strdup (groupDefaultTypes[i]);
+ o->rest.s.string = (char**) windowTypeString;
+ o->rest.s.nString = nWindowTypeString;
+ }
+ gs->wMask = compWindowTypeMaskFromStringList (&o->value);
+
+ o = &gs->opt[GROUP_SCREEN_OPTION_OPACITY];
+ o->name = "opacity";
+ o->group = N_("");
+ o->subGroup = N_("");
+ o->displayHints = "";
+ o->shortDesc = N_("Opacity");
+ o->longDesc = N_("Opacity of selected windows");
+ o->type = CompOptionTypeInt;
+ o->value.i = GROUP_OPACITY_DEFAULT;
+ o->rest.i.min = GROUP_OPACITY_MIN;
+ o->rest.i.max = GROUP_OPACITY_MAX;
+
+ o = &gs->opt[GROUP_SCREEN_OPTION_SATURATION];
+ o->name = "saturation";
+ o->group = N_("");
+ o->subGroup = N_("");
+ o->displayHints = "";
+ o->shortDesc = N_("Saturation");
+ o->longDesc = N_("Saturation of selected windows");
+ o->type = CompOptionTypeInt;
+ o->value.i = GROUP_SATURATION_DEFAULT;
+ o->rest.i.min = GROUP_SATURATION_MIN;
+ o->rest.i.max = GROUP_SATURATION_MAX;
+
+ o = &gs->opt[GROUP_SCREEN_OPTION_BRIGHTNESS];
+ o->name = "brightness";
+ o->group = N_("");
+ o->subGroup = N_("");
+ o->displayHints = "";
+ o->shortDesc = N_("Brightness");
+ o->longDesc = N_("Brightness of selected windows");
+ o->type = CompOptionTypeInt;
+ o->value.i = GROUP_BRIGHTNESS_DEFAULT;
+ o->rest.i.min = GROUP_BRIGHTNESS_MIN;
+ o->rest.i.max = GROUP_BRIGHTNESS_MAX;
+
+ o = &gs->opt[GROUP_SCREEN_OPTION_TOLERANCE];
+ o->name = "tolerance";
+ o->group = N_("");
+ o->subGroup = N_("");
+ o->displayHints = "";
+ o->shortDesc = N_("Tolerance");
+ o->longDesc = N_("Tolerance of the seletion.");
+ o->type = CompOptionTypeInt;
+ o->value.i = GROUP_TOLERANCE_DEFAULT;
+ o->rest.i.min = GROUP_TOLERANCE_MIN;
+ o->rest.i.max = GROUP_TOLERANCE_MAX;
+
+ o = &gs->opt[GROUP_SCREEN_OPTION_STEPS];
+ o->name = "steps";
+ o->group = N_("");
+ o->subGroup = N_("");
+ o->displayHints = "";
+ o->shortDesc = N_("Steps");
+ o->longDesc = N_("The animation steps that are needed for animation.");
+ o->type = CompOptionTypeInt;
+ o->value.i = GROUP_STEPS_DEFAULT;
+ o->rest.i.min = GROUP_STEPS_MIN;
+ o->rest.i.max = GROUP_STEPS_MAX;
+
+ o = &gs->opt[GROUP_SCREEN_OPTION_MOVE];
+ o->name = "move";
+ o->group = N_("");
+ o->subGroup = N_("");
+ o->displayHints = "";
+ o->shortDesc = N_("Move every window in the group");
+ o->longDesc = N_("If one window in the group gets moved, "
+ "every other window in the group gets moved as well.");
+ o->type = CompOptionTypeBool;
+ o->value.b = GROUP_MOVE_DEFAULT;
+
+ o = &gs->opt[GROUP_SCREEN_OPTION_RESIZE];
+ o->name = "resize";
+ o->group = N_("");
+ o->subGroup = N_("");
+ o->displayHints = "";
+ o->shortDesc = N_("Resize every window in the group");
+ o->longDesc = N_("If one window in the group gets resized, "
+ "every other window in the group gets resized as well.");
+ o->type = CompOptionTypeBool;
+ o->value.b = GROUP_RESIZE_DEFAULT;
+
+ o = &gs->opt[GROUP_SCREEN_OPTION_RAISE];
+ o->name = "raise";
+ o->group = N_("");
+ o->subGroup = N_("");
+ o->displayHints = "";
+ o->shortDesc = N_("Raise every window in the group");
+ o->longDesc = N_("If one window in the group gets selected, "
+ "every window in the group gets raised.");
+ o->type = CompOptionTypeBool;
+ o->value.b = GROUP_RAISE_DEFAULT;
+
+ o = &gs->opt[GROUP_SCREEN_OPTION_AUTO_GROUP];
+ o->name = "auto_group";
+ o->group = N_("");
+ o->subGroup = N_("");
+ o->displayHints = "";
+ o->shortDesc = N_("Group the windows after selection");
+ o->longDesc = N_("If you have selected your windows,"
+ "this automatically groups them. "
+ "(Doesn't work with selection mode 'normal')");
+ o->type = CompOptionTypeBool;
+ o->value.b = GROUP_AUTO_GROUP_DEFAULT;
+
+ o = &gs->opt[GROUP_SCREEN_OPTION_AUTO_UNGROUP];
+ o->name = "auto_ungroup";
+ o->group = N_("");
+ o->subGroup = N_("");
+ o->displayHints = "";
+ o->shortDesc = N_("Ungroup the windows if only one window is left");
+ o->longDesc = N_("If there is only 1 window in the group left, it will be ungrouped.");
+ o->type = CompOptionTypeBool;
+ o->value.b = GROUP_AUTO_UNGROUP_DEFAULT;
+
+ o = &gs->opt[GROUP_SCREEN_OPTION_RELATIVE_DISTANCE];
+ o->name = "relative_distance";
+ o->group = N_("");
+ o->subGroup = N_("");
+ o->displayHints = "";
+ o->shortDesc = N_("Compute distance relative");
+ o->longDesc = N_("The distance between the windows is computed relative to the window size. "
+ "This allows you to have windows staying next to eachother.");
+ o->type = CompOptionTypeBool;
+ o->value.b = GROUP_RELATIVE_DISTANCE_DEFAULT;
+
+ o = &gs->opt[GROUP_SCREEN_OPTION_SELECTION_COLOR];
+ o->name = "fill_color";
+ o->group = N_("");
+ o->subGroup = N_("");
+ o->displayHints = "";
+ o->shortDesc = N_("Selection Color");
+ o->longDesc = N_("Fill color of the selection.");
+ o->type = CompOptionTypeColor;
+ o->value.c[0] = GROUP_COLOR_SELECTION_RED_DEFAULT;
+ o->value.c[1] = GROUP_COLOR_SELECTION_GREEN_DEFAULT;
+ o->value.c[2] = GROUP_COLOR_SELECTION_BLUE_DEFAULT;
+ o->value.c[3] = GROUP_COLOR_SELECTION_ALPHA_DEFAULT;
+
+ o = &gs->opt[GROUP_SCREEN_OPTION_LINE_COLOR];
+ o->name = "line_color";
+ o->group = N_("");
+ o->subGroup = N_("");
+ o->displayHints = "";
+ o->shortDesc = N_("Line Color");
+ o->longDesc = N_("Line color of the selection.");
+ o->type = CompOptionTypeColor;
+ o->value.c[0] = GROUP_COLOR_LINE_RED_DEFAULT;
+ o->value.c[1] = GROUP_COLOR_LINE_GREEN_DEFAULT;
+ o->value.c[2] = GROUP_COLOR_LINE_BLUE_DEFAULT;
+ o->value.c[3] = GROUP_COLOR_LINE_ALPHA_DEFAULT;
+}
+
+/*
+ * groupGetScreenOptions
+ *
+ */
+static CompOption *
+groupGetScreenOptions (CompScreen *s, int *count)
+{
+ if (s)
+ {
+ GROUP_SCREEN (s);
+
+ *count = NUM_OPTIONS (gs);
+ return gs->opt;
+ }
+ else
+ {
+ GroupScreen *gs = malloc (sizeof (GroupScreen));
+ groupScreenInitOptions (gs);
+ *count = NUM_OPTIONS (gs);
+ return gs->opt;
+ }
+}
+
+
+/*
+ * groupSetScreenOption
+ *
+ */
+static Bool
+groupSetScreenOption (CompScreen *s, char *name, CompOptionValue *value)
+{
+
+ CompOption *o;
+ int index;
+
+ GROUP_SCREEN (s);
+
+ o = compFindOption (gs->opt, NUM_OPTIONS (gs), name, &index);
+ if (!o)
+ return FALSE;
+
+ switch (index)
+ {
+ case GROUP_SCREEN_OPTION_TYPES:
+ if (compSetOptionList (o, value))
+ {
+ gs->wMask = compWindowTypeMaskFromStringList (&o->value);
+ return TRUE;
+ }
+ break;
+
+ case GROUP_SCREEN_OPTION_SELECTION_COLOR:
+ case GROUP_SCREEN_OPTION_LINE_COLOR:
+ if (compSetColorOption (o, value))
+ {
+ return TRUE;
+ }
+ break;
+
+ case GROUP_SCREEN_OPTION_OPACITY:
+ case GROUP_SCREEN_OPTION_BRIGHTNESS:
+ case GROUP_SCREEN_OPTION_SATURATION:
+ case GROUP_SCREEN_OPTION_TOLERANCE:
+ case GROUP_SCREEN_OPTION_STEPS:
+ if (compSetIntOption (o, value)) {
+ return TRUE;
+ }
+ break;
+
+ case GROUP_SCREEN_OPTION_MOVE:
+ case GROUP_SCREEN_OPTION_RESIZE:
+ case GROUP_SCREEN_OPTION_RAISE:
+ case GROUP_SCREEN_OPTION_AUTO_UNGROUP:
+ case GROUP_SCREEN_OPTION_AUTO_GROUP:
+ case GROUP_SCREEN_OPTION_RELATIVE_DISTANCE:
+ if (compSetBoolOption (o, value)) {
+ return TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+/*
+ * groupSelectWindow
+ *
+ */
+static void
+groupSelectWindow (CompDisplay *d, CompWindow *w)
+{
+ GROUP_DISPLAY (d);
+ GROUP_SCREEN (w->screen);
+ GROUP_WINDOW (w);
+
+ // select singe window
+ if ((gs->wMask & w->type) &&
+ !w->invisible &&
+ !gw->inSelection &&
+ !gw->inGroup)
+ {
+
+ groupAddWindowToSelection (d, w);
+
+ gw->inSelection = TRUE;
+ addWindowDamage (w);
+ }
+
+ // unselect single window
+ else if ((gs->wMask & w->type) &&
+ !w->invisible &&
+ gw->inSelection &&
+ !gw->inGroup)
+ {
+ groupDeleteSelectionWindow (d, w);
+
+ gw->inSelection = FALSE;
+ addWindowDamage (w);
+ }
+
+ // select group
+ else if ((gs->wMask & w->type) &&
+ !w->invisible &&
+ !gw->inSelection &&
+ gw->inGroup)
+ {
+ int index = groupFindGroupAtDisplay (gd, gw->groupID);
+ if (index == -1)
+ return;
+
+ int i;
+ for (i = 0; i < gd->groups[index].nWins; i++)
+ {
+ CompWindow *cw = findWindowAtDisplay (d, gd->groups[index].windows[i]);
+ if (!cw)
+ continue;
+ GROUP_WINDOW (cw);
+
+ groupAddWindowToSelection (d, cw);
+
+ gw->inSelection = TRUE;
+ addWindowDamage (cw);
+ }
+ }
+
+ // Unselect group
+ else if ((gs->wMask & w->type) &&
+ !w->invisible &&
+ gw->inSelection &&
+ gw->inGroup)
+ {
+ int index = groupFindGroupAtDisplay (gd, gw->groupID);
+ if (index == -1)
+ return;
+
+ Window *buf = gd->tmpSel.windows;
+ gd->tmpSel.windows = (Window*) calloc (gd->tmpSel.nWins - gd->groups[index].nWins, sizeof (Window));
+
+ int counter = 0;
+ int i;
+ for (i = 0; i < gd->tmpSel.nWins; i++)
+ {
+ CompWindow *cw = findWindowAtDisplay (d, buf[i]);
+ if (!cw)
+ continue;
+ GROUP_WINDOW (cw);
+
+ if (gw->inGroup && gw->groupID == gd->groups[index].id)
+ {
+ gw->inSelection = FALSE;
+ addWindowDamage (cw);
+ continue;
+ }
+
+ gd->tmpSel.windows[counter++] = buf[i];
+ }
+ gd->tmpSel.nWins = counter;
+ free (buf);
+ }
+
+}
+
+/*
+ * groupSelect
+ *
+ */
+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;
+ Window *ws = groupFindWindowsInRegion (s, reg, &count);
+
+ if (ws) {
+ // select windows
+ int i;
+ for (i = 0; i < count; i++)
+ {
+ CompWindow *cw = findWindowAtDisplay (d, ws[i]);
+ if (!cw)
+ continue;
+
+ groupSelectWindow(d, cw);
+ }
+ if (gs->opt[GROUP_SCREEN_OPTION_AUTO_GROUP].value.b)
+ {
+ groupGroupWindows(d, NULL, 0, NULL, 0);
+ }
+ free(ws);
+ }
+ }
+
+ gs->grab = FALSE;
+ }
+
+ }
+
+ action->state &= ~(CompActionStateTermKey | CompActionStateTermButton);
+
+ return FALSE;
+}
+
+/*
+ * groupGroupWindows
+ *
+ */
+static Bool
+groupGroupWindows (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption)
+{
+ GROUP_DISPLAY (d);
+
+ if (gd->tmpSel.nWins > 0)
+ {
+ int id = gd->nGroups;
+ int index = groupFindGroupAtDisplay (gd, id);
+ while (index != -1) {
+ id++;
+ index = groupFindGroupAtDisplay (gd, id);
+ }
+
+ int i;
+ for (i = 0; i < gd->tmpSel.nWins; i++)
+ {
+ CompWindow* cw = (CompWindow*) findWindowAtDisplay (d, gd->tmpSel.windows[i]);
+ if (!cw)
+ continue;
+ GROUP_WINDOW (cw);
+
+ groupAddWindowToGroup(d, cw, id);
+
+ gw->inSelection = FALSE;
+ addWindowDamage (cw);
+ }
+
+ // exit selection
+ free (gd->tmpSel.windows);
+ gd->tmpSel.windows = NULL;
+ gd->tmpSel.nWins = 0;
+ }
+
+ return FALSE;
+}
+
+/*
+ * groupUnGroupWindows
+ *
+ */
+static Bool
+groupUnGroupWindows (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption)
+{
+ CompWindow *cw = findWindowAtDisplay (d, d->activeWindow);
+ if (!cw)
+ return FALSE;
+ GROUP_WINDOW (cw);
+ if (gw->inGroup)
+ groupDeleteGroup (d, gw->groupID);
+
+ return FALSE;
+}
+
+/*
+ * groupInitTab
+ *
+ */
+static Bool
+groupInitTab (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption)
+{
+ GROUP_DISPLAY (d);
+ CompWindow *w = findWindowAtDisplay (d, d->activeWindow);
+ if (!w)
+ return FALSE;
+
+ GROUP_WINDOW (w);
+ if (!gw->inGroup)
+ return FALSE;
+
+ int index = groupFindGroupAtDisplay (gd, gw->groupID);
+ if (index == -1)
+ return FALSE;
+
+ if (gd->groups[index].tabbed) {
+ groupUntabGroup (d, w, gw->groupID);
+ } else {
+ groupTabGroup (d, w, gw->groupID);
+ }
+
+ return TRUE;
+}
+
+/*
+ * groupRemoveWindow
+ *
+ */
+static Bool
+groupRemoveWindow (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption)
+{
+ CompWindow *cw = findWindowAtDisplay (d, d->activeWindow);
+ if (!cw)
+ return FALSE;
+ GROUP_WINDOW (cw);
+
+ if (gw->inGroup)
+ groupDeleteGroupWindow (d, cw);
+
+ return FALSE;
+}
+
+/*
+ * groupCloseWindows
+ *
+ */
+static Bool
+groupCloseWindows (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption)
+{
+ CompWindow *w = findWindowAtDisplay (d, d->activeWindow);
+ if (!w)
+ return FALSE;
+ GROUP_WINDOW (w);
+ GROUP_DISPLAY (w->screen->display);
+
+ if (gw->inGroup)
+ {
+ int index = groupFindGroupAtDisplay (gd, gw->groupID);
+ if (index == -1)
+ return FALSE;
+
+ int nWins = gd->groups[index].nWins;
+ int i;
+ for (i = 0; i < nWins; i++)
+ {
+ CompWindow *cw = findWindowAtDisplay (d, gd->groups[index].windows[i]);
+ if (!cw)
+ continue;
+ closeWindow (cw, getCurrentTimeFromDisplay (d));
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * groupMinimizeWindows
+ *
+ */
+static Bool
+groupMinimizeWindows (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption)
+{
+ CompWindow *w = findWindowAtDisplay (d, d->activeWindow);
+ if (!w)
+ return FALSE;
+ GROUP_WINDOW (w);
+ GROUP_DISPLAY (w->screen->display);
+
+ if (gw->inGroup)
+ {
+ int index = groupFindGroupAtDisplay (gd, gw->groupID);
+ if (index == -1)
+ return FALSE;
+
+ int nWins = gd->groups[index].nWins;
+ int i;
+ for (i = 0; i < nWins; i++)
+ {
+ CompWindow *cw = findWindowAtDisplay (d, gd->groups[index].windows[i]);
+ if (!cw)
+ continue;
+ minimizeWindow (cw);
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * groupSetIgnore
+ *
+ */
+static Bool
+groupSetIgnore (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption)
+{
+ GROUP_DISPLAY (d);
+
+ gd->ignoreMode = TRUE;
+
+ if (state & CompActionStateInitKey)
+ action->state |= CompActionStateTermKey;
+
+ return FALSE;
+}
+
+/*
+ * groupUnsetIgnore
+ *
+ */
+static Bool
+groupUnsetIgnore (CompDisplay *d, CompAction *action, CompActionState state, CompOption *option, int nOption)
+{
+ GROUP_DISPLAY (d);
+
+ gd->ignoreMode = FALSE;
+
+ action->state &= ~CompActionStateTermKey;
+
+ return FALSE;
+}
+
+/*
+ * groupHandleMotionEvent - pre-definition for groupHandleEvent
+ *
+ */
+static void
+groupHandleMotionEvent (CompScreen *s, int xRoot, int yRoot);
+
+/*
+ * groupHandleEvent
+ *
+ */
+static void
+groupHandleEvent (CompDisplay *d, XEvent *event)
+{
+ GROUP_DISPLAY (d);
+
+ switch (event->type)
+ {
+ case MotionNotify:
+ {
+ CompScreen *s = findScreenAtDisplay (d, event->xmotion.root);
+ if (s)
+ groupHandleMotionEvent (s, d->pointerX, d->pointerY);
+ break;
+ }
+
+ case ButtonRelease:
+ // update windows
+ if (event->xbutton.button == 1)
+ {
+ if (gd->inAction && gd->lastActiveGroup != -1) {
+ groupSyncWindows (d, gd->lastActiveGroup);
+ gd->lastActiveGroup = -1;
+ gd->inAction = FALSE;
+ }
+ }
+ break;
+
+ case UnmapNotify:
+ {
+ CompWindow *w = findWindowAtDisplay (d, event->xunmap.window);
+ if (!w)
+ break;
+ GROUP_WINDOW (w);
+
+ // close event
+ if (gw->inGroup && !w->pendingUnmaps) {
+ groupDeleteGroupWindow (d, w);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ UNWRAP (gd, d, handleEvent);
+ (*d->handleEvent) (d, event);
+ WRAP (gd, d, handleEvent, groupHandleEvent);
+
+ switch (event->type)
+ {
+ case PropertyNotify:
+ // focus event
+ if (event->xproperty.atom == d->winActiveAtom)
+ {
+ if (!gd->inAction)
+ {
+ CompWindow *w = (CompWindow*) findWindowAtDisplay (d, d->activeWindow);
+ if (!w)
+ break;
+
+ GROUP_WINDOW (w);
+ GROUP_SCREEN (w->screen);
+
+ if (gw->inGroup &&
+ !IPCS_GetBoolND (IPCS_OBJECT (w->screen->display), "SCALE_INIT", FALSE) &&
+ gs->opt[GROUP_SCREEN_OPTION_RAISE].value.b)
+ {
+ groupRaiseWindows (d, w, gw->groupID);
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*
+ * groupWindowMoveNotify
+ *
+ */
+static void
+groupWindowMoveNotify (CompWindow *w, int dx, int dy, Bool immediate)
+{
+ GROUP_SCREEN (w->screen);
+ GROUP_DISPLAY (w->screen->display);
+ GROUP_WINDOW (w);
+
+ UNWRAP (gs, w->screen, windowMoveNotify);
+ (*w->screen->windowMoveNotify) (w, dx, dy, immediate);
+ WRAP (gs, w->screen, windowMoveNotify, groupWindowMoveNotify);
+
+ // workaround for viewports
+ Bool vpMove = FALSE;
+ if ( (dx % w->screen->workArea.width == 0 && dx != 0) ||
+ (dy % w->screen->workArea.height == 0 && dy != 0))
+ {
+ vpMove = TRUE;
+ }
+
+ if (gw->inGroup &&
+ !vpMove &&
+ !IPCS_GetBoolND (IPCS_OBJECT (w), "SHOWDESKTOP_MOVE", FALSE) &&
+ !IPCS_GetBoolND (IPCS_OBJECT (w->screen->display), "SCALE_INIT", FALSE) &&
+ gs->opt[GROUP_SCREEN_OPTION_MOVE].value.b &&
+ !gd->ignoreMode)
+ {
+ int index = groupFindGroupAtDisplay (gd, gw->groupID);
+ if (index != -1)
+ {
+ int i;
+ for (i = 0; i < gd->groups[index].nWins; i++)
+ {
+ CompWindow *cw = findWindowAtDisplay (w->screen->display, gd->groups[index].windows[i]);
+ if (!cw)
+ continue;
+
+ if (cw->id != w->id)
+ {
+ UNWRAP (gs, cw->screen, windowMoveNotify);
+ moveWindow (cw, dx, dy, TRUE, FALSE);
+ WRAP (gs, cw->screen, windowMoveNotify, groupWindowMoveNotify);
+
+ groupUpdatePosBuffer (cw, WIN_X (cw) + dx, WIN_Y (cw) + dy, WIN_WIDTH (cw), WIN_HEIGHT (cw));
+ }
+ }
+ }
+
+ gd->lastActiveGroup = gw->groupID;
+ gd->inAction = TRUE;
+ }
+
+ groupUpdatePosBuffer (w, WIN_X (w) + dx, WIN_Y (w) + dy, WIN_WIDTH (w), WIN_HEIGHT (w));
+}
+
+/*
+ * groupWindowResizeNotify
+ *
+ */
+static void
+groupWindowResizeNotify (CompWindow *w)
+{
+
+ GROUP_SCREEN (w->screen);
+ GROUP_DISPLAY (w->screen->display);
+ GROUP_WINDOW (w);
+
+ UNWRAP (gs, w->screen, windowResizeNotify);
+ (*w->screen->windowResizeNotify) (w);
+ WRAP (gs, w->screen, windowResizeNotify, groupWindowResizeNotify);
+
+ if (gw->inGroup && !gd->ignoreMode &&
+ gs->opt[GROUP_SCREEN_OPTION_RESIZE].value.b)
+ {
+ int rw = WIN_WIDTH (w) - gw->oldWidth;
+ int rh = WIN_HEIGHT (w) - gw->oldHeight;
+ int rx = WIN_X (w) - gw->oldX;
+ int ry = WIN_Y (w) - gw->oldY;
+
+ int index = groupFindGroupAtDisplay (gd, gw->groupID);
+ if (index != -1)
+ {
+ int i;
+ for (i = 0; i < gd->groups[index].nWins; i++)
+ {
+ CompWindow *cw = findWindowAtDisplay (w->screen->display, gd->groups[index].windows[i]);
+ if (!cw)
+ continue;
+
+ if (cw->id != w->id)
+ {
+
+ UNWRAP (gs, cw->screen, windowResizeNotify);
+ UNWRAP (gs, cw->screen, windowMoveNotify);
+
+ int nx = 0;
+ int ny = 0;
+ if (gs->opt[GROUP_SCREEN_OPTION_RELATIVE_DISTANCE].value.b)
+ {
+ int distX = WIN_X (cw) - gw->oldX;
+ int distY = WIN_Y (cw) - gw->oldY;
+ int ndistX = distX * ( (float) WIN_WIDTH (w) / (float) gw->oldWidth);
+ int ndistY = distY * ( (float) WIN_HEIGHT (w) / (float) gw->oldHeight);
+
+ nx = WIN_X (w) + ndistX;
+ ny = WIN_Y (w) + ndistY;
+ }
+ else
+ {
+ nx = WIN_X (cw) + rx;
+ ny = WIN_Y (cw) + ry;
+ }
+
+ int nwidth = WIN_WIDTH (cw) + rw;
+ int nheight = WIN_HEIGHT (cw) + rh;
+
+ XWindowChanges xwc;
+ xwc.x = nx;
+ xwc.y = ny;
+ xwc.width = nwidth;
+ xwc.height = nheight;
+ configureXWindow (cw, CWX | CWY | CWWidth | CWHeight, &xwc);
+
+ resizeWindow (cw, nx, ny, nwidth, nheight, WIN_BORDER (cw));
+ groupUpdatePosBuffer (cw, nx, ny, nwidth, nheight);
+
+ WRAP (gs, cw->screen, windowMoveNotify, groupWindowMoveNotify);
+ WRAP (gs, cw->screen, windowResizeNotify, groupWindowResizeNotify);
+ }
+
+ }
+ gd->lastActiveGroup = gw->groupID;
+ gd->inAction = TRUE;
+ }
+ }
+
+ groupUpdatePosBuffer (w, WIN_X (w), WIN_Y (w), WIN_WIDTH (w), WIN_HEIGHT (w));
+}
+
+/*
+ * 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;
+
+ 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 ();
+ }
+ }
+ else if (status)
+ {
+ int index = groupFindGroupAtDisplay (gd, gd->lastActiveGroup);
+ if (index == -1)
+ return status;
+
+ int i;
+ for (i = 0; i < gd->groups[index].nWins; i++)
+ {
+ CompWindow *cw = findWindowAtDisplay (s->display, gd->groups[index].windows[i]);
+ if(!cw)
+ continue;
+ GROUP_WINDOW (cw);
+
+ if (!gw->animate)
+ continue;
+
+ if (!gw->steps) {
+ // move them the remaining distance, it's needed because we are off a few pixels
+ UNWRAP (gs, cw->screen, windowMoveNotify);
+ moveWindow (cw,
+ gw->destinationX - WIN_X (cw), gw->destinationY - WIN_Y (cw),
+ TRUE, FALSE);
+ WRAP (gs, cw->screen, windowMoveNotify, groupWindowMoveNotify);
+ gw->animate = FALSE;
+ continue;
+ }
+
+ // do a step for every window
+ UNWRAP (gs, cw->screen, windowMoveNotify);
+ moveWindow (cw, gw->stepX, gw->stepY, TRUE, FALSE);
+ WRAP (gs, cw->screen, windowMoveNotify, groupWindowMoveNotify);
+
+ gw->steps--;
+ }
+ }
+
+ 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
+groupPaintWindow (CompWindow * w,
+ const WindowPaintAttrib * attrib,
+ Region region, unsigned int mask)
+{
+ Bool status;
+ GROUP_WINDOW (w);
+ GROUP_SCREEN (w->screen);
+
+ WindowPaintAttrib gAttrib = *attrib;
+
+ if (gw->inSelection)
+ {
+ int opacity = gs->opt[GROUP_SCREEN_OPTION_OPACITY].value.i;
+ int saturation = gs->opt[GROUP_SCREEN_OPTION_SATURATION].value.i;
+ int brightness = gs->opt[GROUP_SCREEN_OPTION_BRIGHTNESS].value.i;
+
+ opacity = OPAQUE * opacity / 100;
+ saturation = COLOR * saturation / 100;
+ brightness = BRIGHT * brightness / 100;
+
+ gAttrib.opacity = opacity;
+ gAttrib.saturation = saturation;
+ gAttrib.brightness = brightness;
+ }
+
+ UNWRAP (gs, w->screen, paintWindow);
+ status = (*w->screen->paintWindow) (w, &gAttrib, region, mask);
+ WRAP (gs, w->screen, paintWindow, groupPaintWindow);
+
+ 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, ®);
+ }
+}
+
+/*
+ * 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_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:
+ if (setDisplayAction (d, o, value))
+ return TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+/*
+ * groupInitDisplay
+ *
+ */
+static Bool
+groupInitDisplay (CompPlugin *p, CompDisplay *d)
+{
+
+ GroupDisplay *gd;
+
+ gd = malloc (sizeof (GroupDisplay));
+ if (!gd)
+ return FALSE;
+
+ gd->screenPrivateIndex = allocateScreenPrivateIndex (d);
+ if (gd->screenPrivateIndex < 0)
+ {
+ free (gd);
+ return FALSE;
+ }
+
+ gd->inAction = FALSE;
+ gd->lastActiveGroup = -1;
+
+ gd->tmpSel.windows = NULL;
+ gd->tmpSel.nWins = 0;
+
+ gd->groups = NULL;
+ gd->nGroups = 0;
+
+ gd->ignoreMode = FALSE;
+
+ groupDisplayInitOptions (gd);
+
+ WRAP (gd, d, handleEvent, groupHandleEvent);
+
+ d->privates[displayPrivateIndex].ptr = gd;
+
+ return TRUE;
+}
+
+/*
+ * groupFiniDisplay
+ *
+ */
+static void
+groupFiniDisplay (CompPlugin *p, CompDisplay *d)
+{
+ GROUP_DISPLAY (d);
+
+ if (gd->groups && gd->groups != NULL && gd->nGroups != 0) {
+ free (gd->groups);
+ }
+ freeScreenPrivateIndex (d, gd->screenPrivateIndex);
+
+ UNWRAP (gd, d, handleEvent);
+
+ free (gd);
+}
+
+/*
+ * groupInitScreen
+ *
+ */
+static Bool
+groupInitScreen (CompPlugin *p, CompScreen *s)
+{
+
+ GroupScreen *gs;
+
+ GROUP_DISPLAY (s->display);
+
+ gs = malloc (sizeof (GroupScreen));
+ if (!gs)
+ return FALSE;
+
+ gs->windowPrivateIndex = allocateWindowPrivateIndex (s);
+ if (gs->windowPrivateIndex < 0)
+ {
+ free (gs);
+ return FALSE;
+ }
+
+ groupScreenInitOptions (gs);
+
+ addScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_SELECT].value.action);
+ addScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_SELECT_SINGLE].value.action);
+ addScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_GROUPING].value.action);
+ addScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_UNGROUPING].value.action);
+ addScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_REMOVEING].value.action);
+ addScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_CLOSEING].value.action);
+ addScreenAction (s, &gd->opt[GROUP_DISPLAY_OPTION_MINIMIZEING].value.action);
+
+ WRAP (gs, s, windowMoveNotify, groupWindowMoveNotify);
+ WRAP (gs, s, windowResizeNotify, groupWindowResizeNotify);
+ WRAP (gs, s, paintScreen, groupPaintScreen);
+ WRAP (gs, s, paintWindow, groupPaintWindow);
+ WRAP (gs, s, paintTransformedScreen, groupPaintTransformedScreen);
+
+ s->privates[gd->screenPrivateIndex].ptr = gs;
+
+ gs->grab = FALSE;
+ gs->grabIndex = 0;
+
+ return TRUE;
+}
+
+/*
+ * groupFiniScreen
+ *
+ */
+static 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);
+
+ UNWRAP (gs, s, windowMoveNotify);
+ UNWRAP (gs, s, windowResizeNotify);
+ UNWRAP (gs, s, paintScreen);
+ UNWRAP (gs, s, paintWindow);
+ UNWRAP (gs, s, paintTransformedScreen);
+
+ free (gs);
+}
+
+/*
+ * groupInitWindow
+ *
+ */
+static Bool
+groupInitWindow (CompPlugin *p, CompWindow *w)
+{
+ GroupWindow *gw;
+
+ GROUP_SCREEN (w->screen);
+
+ gw = malloc (sizeof (GroupWindow));
+ if (!gw)
+ return FALSE;
+ gw->inGroup = FALSE;
+ gw->inSelection = FALSE;
+
+ // for move/resize
+ gw->oldWidth = WIN_WIDTH (w);
+ gw->oldHeight = WIN_HEIGHT (w);
+ gw->oldX = WIN_X (w);
+ gw->oldY = WIN_Y (w);
+
+ // for tab
+ gw->tabWindow = FALSE;
+ gw->animate = FALSE;
+ gw->stepX = 0.0f;
+ gw->stepY = 0.0f;
+ gw->steps = 0;
+ gw->orgPosX = 0;
+ gw->orgPosY = 0;
+ gw->destinationX = 0;
+ gw->destinationY = 0;
+
+ w->privates[gs->windowPrivateIndex].ptr = gw;
+
+ return TRUE;
+}
+
+/*
+ * groupFiniWindow
+ *
+ */
+static 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, "state" }
+
+};
+*/
+
+/*
+ * groupVTable
+ *
+ */
+CompPluginVTable groupVTable = {
+ "group",
+ "Window Grouper",
+ "With this plugin you can group windows.",
+ groupInit,
+ groupFini,
+ groupInitDisplay,
+ groupFiniDisplay,
+ groupInitScreen,
+ groupFiniScreen,
+ groupInitWindow,
+ groupFiniWindow,
+ groupGetDisplayOptions,
+ groupSetDisplayOption,
+ groupGetScreenOptions,
+ groupSetScreenOption,
+ 0 /* groupDeps */,
+ 0 /* sizeof (groupDeps) / sizeof (groupDeps[0]) */,
+ 0,
+ 0,
+ BERYL_ABI_INFO,
+ "beryl-plugins"
+};
+
+/*
+ * getCompPluginInfo
+ *
+ */
+CompPluginVTable *
+getCompPluginInfo (void)
+{
+ return &groupVTable;
+}
+
More information about the commits
mailing list