rendered paste body/**
*
* Beryl group plugin
*
* group.c
*
* Copyright : (C) 2006 by Patrick Niklaus
* E-mail : patrick.niklaus [ a t ] googlemail.com
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* TODO:
* * glow effect
* * tab like switching between the windows
* * a lot of other tab stuff...
* * provide a tree system for groups
*
**/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <X11/Xlib.h>
#include <beryl.h>
#include <beryl_ipcs.h>
#include <math.h>
#include "group_glow.h"
#define PI 3.1415926535897
#define NUM_CORNER_POINTS 25
/*
* Defaults
*
*/
#define GROUP_SELECT_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_SELECT_BUTTON_DEFAULT Button1
#define GROUP_SELECT_SINGLE_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_SELECT_SINGLE_KEY_DEFAULT "s"
#define GROUP_GROUPING_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_GROUPING_KEY_DEFAULT "g"
#define GROUP_UNGROUPING_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_UNGROUPING_KEY_DEFAULT "u"
#define GROUP_TABMODE_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_TABMODE_KEY_DEFAULT "t"
#define GROUP_CHANGE_TAB_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_CHANGE_TAB_KEY_DEFAULT "Left"
#define GROUP_REMOVEING_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_REMOVEING_KEY_DEFAULT "r"
#define GROUP_CLOSEING_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_CLOSEING_KEY_DEFAULT "c"
#define GROUP_MINIMIZEING_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_MINIMIZEING_KEY_DEFAULT "b"
#define GROUP_IGNORE_MODIFIERS_DEFAULT (CompAltMask)
#define GROUP_IGNORE_KEY_DEFAULT "x"
#define GROUP_DISPLAY_OPTION_SELECT 0
#define GROUP_DISPLAY_OPTION_SELECT_SINGLE 1
#define GROUP_DISPLAY_OPTION_GROUPING 2
#define GROUP_DISPLAY_OPTION_UNGROUPING 3
#define GROUP_DISPLAY_OPTION_REMOVEING 4
#define GROUP_DISPLAY_OPTION_CLOSEING 5
#define GROUP_DISPLAY_OPTION_MINIMIZEING 6
#define GROUP_DISPLAY_OPTION_IGNORE 7
#define GROUP_DISPLAY_OPTION_TABMODE 8
#define GROUP_DISPLAY_OPTION_CHANGE_TAB 9
#define GROUP_DISPLAY_OPTION_NUM 10
#define GROUP_OPACITY_DEFAULT 80
#define GROUP_OPACITY_MIN 0
#define GROUP_OPACITY_MAX 100
#define GROUP_SATURATION_DEFAULT 20
#define GROUP_SATURATION_MIN 0
#define GROUP_SATURATION_MAX 100
#define GROUP_BRIGHTNESS_DEFAULT 70
#define GROUP_BRIGHTNESS_MIN 0
#define GROUP_BRIGHTNESS_MAX 100
#define GROUP_TOLERANCE_DEFAULT 0
#define GROUP_TOLERANCE_MIN 0
#define GROUP_TOLERANCE_MAX 10
#define GROUP_STEPS_DEFAULT 10
#define GROUP_STEPS_MIN 1
#define GROUP_STEPS_MAX 10
#define GROUP_MOVE_DEFAULT TRUE
#define GROUP_RESIZE_DEFAULT TRUE
#define GROUP_RAISE_DEFAULT TRUE
#define GROUP_AUTO_UNGROUP_DEFAULT FALSE
#define GROUP_AUTO_GROUP_DEFAULT FALSE
#define GROUP_RELATIVE_DISTANCE_DEFAULT FALSE
#define GROUP_COLOR_SELECTION_RED_DEFAULT 0x0000
#define GROUP_COLOR_SELECTION_GREEN_DEFAULT 0x0000
#define GROUP_COLOR_SELECTION_BLUE_DEFAULT 0x0000
#define GROUP_COLOR_SELECTION_ALPHA_DEFAULT 0x9999
#define GROUP_COLOR_LINE_RED_DEFAULT 0x0000
#define GROUP_COLOR_LINE_GREEN_DEFAULT 0x0000
#define GROUP_COLOR_LINE_BLUE_DEFAULT 0x0000
#define GROUP_COLOR_LINE_ALPHA_DEFAULT 0xABAB
#define GROUP_SCREEN_OPTION_TYPES 0
#define GROUP_SCREEN_OPTION_OPACITY 1
#define GROUP_SCREEN_OPTION_SATURATION 2
#define GROUP_SCREEN_OPTION_BRIGHTNESS 3
#define GROUP_SCREEN_OPTION_MOVE 4
#define GROUP_SCREEN_OPTION_RESIZE 5
#define GROUP_SCREEN_OPTION_RAISE 6
#define GROUP_SCREEN_OPTION_AUTO_UNGROUP 7
#define GROUP_SCREEN_OPTION_AUTO_GROUP 8
#define GROUP_SCREEN_OPTION_RELATIVE_DISTANCE 9
#define GROUP_SCREEN_OPTION_SELECTION_COLOR 10
#define GROUP_SCREEN_OPTION_LINE_COLOR 11
#define GROUP_SCREEN_OPTION_TOLERANCE 12
#define GROUP_SCREEN_OPTION_STEPS 13
#define GROUP_SCREEN_OPTION_NUM 14
/*
* Helpers
*
*/
#define GET_GROUP_DISPLAY(d) ((GroupDisplay *) (d)->privates[displayPrivateIndex].ptr)
#define GROUP_DISPLAY(d) GroupDisplay *gd = GET_GROUP_DISPLAY (d)
#define GET_GROUP_SCREEN(s, gd) ((GroupScreen *) (s)->privates[ (gd)->screenPrivateIndex].ptr)
#define GROUP_SCREEN(s) GroupScreen *gs = GET_GROUP_SCREEN (s, GET_GROUP_DISPLAY (s->display))
#define GET_GROUP_WINDOW(w, gs) ((GroupWindow *) (w)->privates[ (gs)->windowPrivateIndex].ptr)
#define GROUP_WINDOW(w) GroupWindow *gw = GET_GROUP_WINDOW (w, GET_GROUP_SCREEN (w->screen, GET_GROUP_DISPLAY (w->screen->display)))
#define WIN_X(w) (w->attrib.x)
#define WIN_Y(w) (w->attrib.y)
#define WIN_WIDTH(w) (w->attrib.width)
#define WIN_HEIGHT(w) (w->attrib.height)
#define WIN_BORDER(w) (w->attrib.border_width)
#define NUM_OPTIONS(s) (sizeof ( (s)->opt) / sizeof (CompOption))
#define N_WIN_TYPE (sizeof (groupDefaultTypes) / sizeof (groupDefaultTypes[0]))
#define N_SEL_MODE (sizeof (groupSelectionModes) / sizeof (groupSelectionModes[0]))
/*
* default windows for selection
*/
static char *groupDefaultTypes[] = {
N_("Normal"),
N_("Dialog"),
N_("ModalDialog"),
N_("Dnd")
};
/*
* pointer to display list
*/
static int displayPrivateIndex;
/*
* Call-Back for state
*/
typedef void (*AddWindowToGroupProc) (CompDisplay * d, CompWindow * w,
int groupID);
/*
* GroupSelection
*/
typedef struct _GroupSelection {
CompWindow **windows;
int nWins;
int id;
CompWindow *topTab;
Bool tabbed;
GLushort color[4];
} GroupSelection;
/*
* GroupDisplay structure
*/
typedef struct _GroupDisplay {
int screenPrivateIndex;
CompOption opt[GROUP_DISPLAY_OPTION_NUM];
HandleEventProc handleEvent;
GroupSelection tmpSel;
GroupSelection *groups;
int nGroups;
Bool inAction;
int lastActiveGroup;
int animatedGroup;
Bool ignoreMode;
float cornerPointsX[NUM_CORNER_POINTS];
float cornerPointsY[NUM_CORNER_POINTS];
} GroupDisplay;
/*
* GroupScreen structure
*/
typedef struct _GroupScreen {
int windowPrivateIndex;
CompOption opt[GROUP_SCREEN_OPTION_NUM];
WindowMoveNotifyProc windowMoveNotify;
WindowResizeNotifyProc windowResizeNotify;
PreparePaintScreenProc preparePaintScreen;
PaintScreenProc paintScreen;
DrawWindowProc drawWindow;
PaintTransformedScreenProc paintTransformedScreen;
int wMask;
// for selection
Bool grab;
Bool wasTransformed;
int grabIndex;
int x1;
int y1;
int x2;
int y2;
GLuint glowTexture;
} GroupScreen;
/*
* GroupWindow structure
*/
typedef struct _GroupWindow {
int groupID;
Bool inGroup;
Bool inSelection;
// for scale notify...
int oldWidth;
int oldHeight;
int oldX;
int oldY;
// for tab animation
Bool animate;
int steps;
int orgPosX;
int orgPosY;
int destinationX;
int destinationY;
Bool offscreen;
} GroupWindow;
/*
* groupFindGroupAtDisplay
* Note: Returns the index of the group in gd->groups!
*
*/
static int groupFindGroupAtDisplay(GroupDisplay * gd, int id)
{
int i;
for (i = 0; i < gd->nGroups; i++) {
if (gd->groups[i].id == id)
return i;
}
return -1;
}
#define TOLRNC_MIN(n1, n2, t) (n1 - t < n2)
#define TOLRNC_MAX(n1, n2, t) (n1 + t > n2)
/*
* groupFindWindowsInRegion
*
*/
static CompWindow **groupFindWindowsInRegion(CompScreen * s, REGION reg,
int *c)
{
GROUP_SCREEN(s);
float tolerance =
gs->opt[GROUP_SCREEN_OPTION_TOLERANCE].value.i / 10.0f;
CompWindow **ret = NULL;
int count = 0;
CompWindow *w;
for (w = s->windows; w; w = w->next) {
if ((gs->wMask & w->type) &&
!w->invisible &&
TOLRNC_MIN(reg.extents.x1, WIN_X(w), tolerance * WIN_WIDTH(w)) &&
TOLRNC_MIN(reg.extents.y1, WIN_Y(w), tolerance * WIN_HEIGHT(w)) &&
TOLRNC_MAX(reg.extents.x2, (WIN_X(w) + WIN_WIDTH(w)), tolerance * WIN_WIDTH(w)) &&
TOLRNC_MAX(reg.extents.y2, (WIN_Y(w) + WIN_HEIGHT(w)), tolerance * WIN_HEIGHT(w))) {
if (count == 0) {
ret = calloc(1, sizeof(CompWindow));
ret[0] = w;
} else {
ret =
realloc(ret,
sizeof(CompWindow) * (count +
1));
ret[count] = w;
}
count++;
}
}
(*c) = count;
return ret;
}
/*
* groupUpdatePosBuffer
*
*/
static void
groupUpdatePosBuffer(CompWindow * w, int x, int y, int width, int height)
{
GROUP_WINDOW(w);
gw->oldX = x;
gw->oldY = y;
gw->oldWidth = width;
gw->oldHeight = height;
}
/*
* groupWindowMoveNotify
*
*/
static void
groupWindowMoveNotify(CompWindow * w, int dx, int dy, Bool immediate)
{
GROUP_SCREEN(w->screen);
GROUP_DISPLAY(w->screen->display);
GROUP_WINDOW(w);
UNWRAP(gs, w->screen, windowMoveNotify);
(*w->screen->windowMoveNotify) (w, dx, dy, immediate);
WRAP(gs, w->screen, windowMoveNotify, groupWindowMoveNotify);
// workaround for viewports
Bool vpMove = FALSE;
if ((dx % w->screen->workArea.width == 0 && dx != 0) ||
(dy % w->screen->workArea.height == 0 && dy != 0)) {
vpMove = TRUE;
}
if (gw->inGroup &&
!gw->animate &&
!vpMove &&
!IPCS_GetBoolND(IPCS_OBJECT(w), "SHOWDESKTOP_MOVE", FALSE) &&
!IPCS_GetBoolND(IPCS_OBJECT(w->screen->display), "SCALE_INIT", FALSE) &&
gs->opt[GROUP_SCREEN_OPTION_MOVE].value.b &&
!gd->ignoreMode) {
int index = groupFindGroupAtDisplay(gd, gw->groupID);
if (index != -1) {
int i;
for (i = 0; i < gd->groups[index].nWins; i++) {
CompWindow *cw = gd->groups[index].windows[i];
if (!cw)
continue;
if (cw->id != w->id) {
UNWRAP(gs, cw->screen, windowMoveNotify);
moveWindow(cw, dx, dy, TRUE, FALSE);
WRAP(gs, cw->screen, windowMoveNotify, groupWindowMoveNotify);
groupUpdatePosBuffer(cw, WIN_X(cw) + dx, WIN_Y(cw) + dy, WIN_WIDTH(cw), WIN_HEIGHT(cw));
}
}
}
gd->lastActiveGroup = gw->groupID;
gd->inAction = TRUE;
}
groupUpdatePosBuffer(w, WIN_X(w) + dx, WIN_Y(w) + dy, WIN_WIDTH(w), WIN_HEIGHT(w));
}
/*
* groupTabGroup
*
*/
static void groupTabGroup(CompDisplay * d, CompWindow * main, int groupID)
{
GROUP_DISPLAY(d);
GROUP_SCREEN(main->screen);
int index = groupFindGroupAtDisplay(gd, groupID);
if (index == -1)
return;
gd->groups[index].tabbed = TRUE;
gd->animatedGroup = groupID;
// main window
GROUP_WINDOW(main);
gd->groups[index].topTab = main;
gw->animate = FALSE;
int i;
int steps = gs->opt[GROUP_SCREEN_OPTION_STEPS].value.i;
for (i = 0; i < gd->groups[index].nWins; i++) {
CompWindow *cw = gd->groups[index].windows[i];
if (cw->id == main->id)
continue;
GROUP_WINDOW(cw);
gw->steps = steps;
gw->orgPosX = WIN_X(cw);
gw->orgPosY = WIN_Y(cw);
// center the window to the main window
gw->destinationX = WIN_X(main) + (WIN_WIDTH(main) / 2) - (WIN_WIDTH(cw) / 2);
gw->destinationY = WIN_Y(main) + (WIN_HEIGHT(main) / 2) - (WIN_HEIGHT(cw) / 2);
gw->animate = TRUE;
}
damageScreen(main->screen);
}
/*
* groupUntabGroup
*
*/
static void
groupUntabGroup(CompDisplay * d, CompWindow * main, int groupID)
{
GROUP_DISPLAY(d);
GROUP_SCREEN(main->screen);
int index = groupFindGroupAtDisplay(gd, groupID);
if (index == -1)
return;
gd->groups[index].tabbed = FALSE;
gd->animatedGroup = groupID;
// main window
GROUP_WINDOW(main);
gd->groups[index].topTab = main;
gw->animate = FALSE;
int i;
int steps = gs->opt[GROUP_SCREEN_OPTION_STEPS].value.i;
for (i = 0; i < gd->groups[index].nWins; i++) {
CompWindow *cw = gd->groups[index].windows[i];
if (cw->id == main->id)
continue;
GROUP_WINDOW(cw);
gw->steps = steps;
gw->destinationX = gw->orgPosX;
gw->destinationY = gw->orgPosY;
gw->orgPosX = WIN_X(cw);
gw->orgPosY = WIN_Y(cw);
/*cw->hidden = FALSE;
showWindow (cw);
unsigned int state = getWindowState (d, cw->id);
state &= ~CompWindowStateSkipTaskbarMask;
state &= ~CompWindowStateSkipPagerMask;
setWindowState (d, state, cw->id); */
UNWRAP(gs, cw->screen, windowMoveNotify);
insertWindowIntoScreen(cw->screen, cw, main->id);
if (gw->offscreen) {
moveWindow(cw, -1 * cw->screen->width, 0, FALSE, FALSE);
syncWindowPosition(cw);
gw->offscreen = FALSE;
}
WRAP(gs, cw->screen, windowMoveNotify, groupWindowMoveNotify);
gw->animate = TRUE;
}
damageScreen(main->screen);
}
/*
* groupDeleteGroup - pre-definition for groupDeleteGroupWindow
*
*/
static void groupDeleteGroup(CompDisplay * d, int id);
/*
* groupDeleteGroupWindow
*
*/
static void groupDeleteGroupWindow(CompDisplay * d, CompWindow * w)
{
GROUP_DISPLAY(d);
GROUP_WINDOW(w);
GROUP_SCREEN(w->screen);
int index = groupFindGroupAtDisplay(gd, gw->groupID);
if (index == -1)
return;
if (gd->groups[index].tabbed &&
gd->groups[index].topTab->id == w->id) {
groupUntabGroup(d, w, gw->groupID);
gd->groups[index].topTab = NULL;
}
if (gd->groups[index].nWins != 0
&& gd->groups[index].windows != NULL) {
CompWindow **buf = gd->groups[index].windows;
gd->groups[index].windows = (CompWindow **) calloc(gd->groups[index].nWins - 1, sizeof(CompWindow *));
int counter = 0;
int i;
for (i = 0; i < gd->groups[index].nWins; i++) {
if (buf[i]->id == w->id)
continue;
gd->groups[index].windows[counter++] = buf[i];
}
gd->groups[index].nWins = counter;
if (gd->groups[index].nWins == 1 &&
gs->opt[GROUP_SCREEN_OPTION_AUTO_UNGROUP].value.b) {
groupDeleteGroup(d, gw->groupID);
} else if (gd->groups[index].nWins <= 0) {
free(gd->groups[index].windows);
gd->groups[index].windows = NULL;
groupDeleteGroup(d, gw->groupID);
}
free(buf);
gw->inGroup = FALSE;
}
}
/*
* groupDeleteGroup
*
*/
static void groupDeleteGroup(CompDisplay * d, int id)
{
GROUP_DISPLAY(d);
gd->inAction = TRUE;
gd->lastActiveGroup = -1;
int index = groupFindGroupAtDisplay(gd, id);
if (index == -1) {
gd->inAction = FALSE;
return;
}
if (gd->groups[index].windows != NULL) {
if (gd->groups[index].tabbed) {
groupUntabGroup(d, gd->groups[index].topTab, id);
// we don't want an animation here because it won't work...
gd->groups[index].topTab = NULL;
gd->animatedGroup = -1;
}
int i;
for (i = 0; i < gd->groups[index].nWins; i++) {
CompWindow *cw = gd->groups[index].windows[i];
GROUP_WINDOW(cw);
gw->inGroup = FALSE;
}
free(gd->groups[index].windows);
}
GroupSelection *groupsBuf = gd->groups;
gd->groups = calloc(gd->nGroups - 1, sizeof(GroupSelection));
int counter = 0;
int i;
for (i = 0; i < gd->nGroups; i++) {
if (groupsBuf[i].id == id) {
continue;
}
gd->groups[counter++] = groupsBuf[i];
}
gd->nGroups--;
free(groupsBuf);
gd->inAction = FALSE;
}
/*
* groupAddWindowToGroup
*
*/
static void
groupAddWindowToGroup(CompDisplay * d, CompWindow * w, int groupID)
{
GROUP_DISPLAY(d);
GROUP_WINDOW(w);
if (gw->inGroup) {
groupDeleteGroupWindow(d, w);
}
int index = groupFindGroupAtDisplay(gd, groupID);
if (index == -1) {
GroupSelection g;
g.id = groupID;
g.windows = (CompWindow **) calloc(1, sizeof(CompWindow *));
g.windows[0] = w;
g.nWins = 1;
g.topTab = NULL;
g.tabbed = FALSE;
// glow color
srand(time(NULL));
g.color[0] = rand() % 0xFFFF;
g.color[1] = rand() % 0xFFFF;
g.color[2] = rand() % 0xFFFF;
g.color[3] = 0xFFFF;
gd->groups = (GroupSelection *) realloc(gd->groups, sizeof(GroupSelection) * (gd->nGroups + 1));
gd->groups[gd->nGroups] = g;
gd->nGroups++;
gw->groupID = groupID;
gw->inGroup = TRUE;
} else {
gd->groups[index].windows = (CompWindow **) realloc(gd->groups[index].windows,
sizeof(CompWindow *) * (gd->groups[index].nWins + 1));
gd->groups[index].windows[gd->groups[index].nWins] = w;
gd->groups[index].nWins++;
gw->groupID = groupID;
gw->inGroup = TRUE;
}
}
/*
* groupDeleteSelectionWindow
*
*/
static void groupDeleteSelectionWindow(CompDisplay * d, CompWindow * w)
{
GROUP_DISPLAY(d);
if (gd->tmpSel.nWins > 0 && gd->tmpSel.windows) {
CompWindow **buf = gd->tmpSel.windows;
gd->tmpSel.windows = (CompWindow **) calloc(gd->tmpSel.nWins - 1, sizeof(CompWindow *));
int counter = 0;
int i;
for (i = 0; i < gd->tmpSel.nWins; i++) {
if (buf[i]->id == w->id)
continue;
gd->tmpSel.windows[counter++] = buf[i];
}
gd->tmpSel.nWins = counter;
free(buf);
}
}
/*
* groupAddWindowToSelection
*
*/
static void groupAddWindowToSelection(CompDisplay * d, CompWindow * w)
{
GROUP_DISPLAY(d);
gd->tmpSel.windows = (CompWindow **) realloc(gd->tmpSel.windows, sizeof(CompWindow *) * (gd->tmpSel.nWins + 1));
gd->tmpSel.windows[gd->tmpSel.nWins] = w;
gd->tmpSel.nWins++;
}
/*
* groupSyncWindows
*
*/
static void groupSyncWindows(CompDisplay * d, int groupID)
{
GROUP_DISPLAY(d);
int index = groupFindGroupAtDisplay(gd, groupID);
if (index == -1)
return;
int i;
for (i = 0; i < gd->groups[index].nWins; i++) {
CompWindow *w = gd->groups[index].windows[i];
syncWindowPosition(w);
}
}
/*
* groupRaiseWindows
*
*/
static void
groupRaiseWindows(CompDisplay * d, CompWindow * top, int groupID)
{
GROUP_DISPLAY(d);
int index = groupFindGroupAtDisplay(gd, groupID);
if (index == -1)
return;
int i;
for (i = 0; i < gd->groups[index].nWins; i++) {
CompWindow *w = gd->groups[index].windows[i];
if (w->id == top->id)
continue;
restackWindowBelow(w, top);
}
}
/*
* groupScreenInitOptions
*
*/
static void groupScreenInitOptions(GroupScreen * gs)
{
CompOption *o;
int i;
o = &gs->opt[GROUP_SCREEN_OPTION_TYPES];
o->name = "mask";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Window Types");
o->longDesc = N_("The types of windows which will be grouped");
o->type = CompOptionTypeList;
o->value.list.type = CompOptionTypeString;
o->value.list.nValue = N_WIN_TYPE;
o->value.list.value = malloc(sizeof(CompOptionValue) * N_WIN_TYPE);
for (i = 0; i < N_WIN_TYPE; i++) {
o->value.list.value[i].s = strdup(groupDefaultTypes[i]);
o->rest.s.string = (char **) windowTypeString;
o->rest.s.nString = nWindowTypeString;
}
gs->wMask = compWindowTypeMaskFromStringList(&o->value);
o = &gs->opt[GROUP_SCREEN_OPTION_OPACITY];
o->name = "opacity";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Opacity");
o->longDesc = N_("Opacity of selected windows");
o->type = CompOptionTypeInt;
o->value.i = GROUP_OPACITY_DEFAULT;
o->rest.i.min = GROUP_OPACITY_MIN;
o->rest.i.max = GROUP_OPACITY_MAX;
o = &gs->opt[GROUP_SCREEN_OPTION_SATURATION];
o->name = "saturation";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Saturation");
o->longDesc = N_("Saturation of selected windows");
o->type = CompOptionTypeInt;
o->value.i = GROUP_SATURATION_DEFAULT;
o->rest.i.min = GROUP_SATURATION_MIN;
o->rest.i.max = GROUP_SATURATION_MAX;
o = &gs->opt[GROUP_SCREEN_OPTION_BRIGHTNESS];
o->name = "brightness";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Brightness");
o->longDesc = N_("Brightness of selected windows");
o->type = CompOptionTypeInt;
o->value.i = GROUP_BRIGHTNESS_DEFAULT;
o->rest.i.min = GROUP_BRIGHTNESS_MIN;
o->rest.i.max = GROUP_BRIGHTNESS_MAX;
o = &gs->opt[GROUP_SCREEN_OPTION_TOLERANCE];
o->name = "tolerance";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Tolerance");
o->longDesc = N_("Tolerance of the seletion.");
o->type = CompOptionTypeInt;
o->value.i = GROUP_TOLERANCE_DEFAULT;
o->rest.i.min = GROUP_TOLERANCE_MIN;
o->rest.i.max = GROUP_TOLERANCE_MAX;
o = &gs->opt[GROUP_SCREEN_OPTION_STEPS];
o->name = "steps";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Steps");
o->longDesc =
N_("The animation steps that are needed for animation.");
o->type = CompOptionTypeInt;
o->value.i = GROUP_STEPS_DEFAULT;
o->rest.i.min = GROUP_STEPS_MIN;
o->rest.i.max = GROUP_STEPS_MAX;
o = &gs->opt[GROUP_SCREEN_OPTION_MOVE];
o->name = "move";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Move every window in the group");
o->longDesc = N_("If one window in the group gets moved, "
"every other window in the group gets moved as well.");
o->type = CompOptionTypeBool;
o->value.b = GROUP_MOVE_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_RESIZE];
o->name = "resize";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Resize every window in the group");
o->longDesc = N_("If one window in the group gets resized, "
"every other window in the group gets resized as well.");
o->type = CompOptionTypeBool;
o->value.b = GROUP_RESIZE_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_RAISE];
o->name = "raise";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Raise every window in the group");
o->longDesc = N_("If one window in the group gets selected, "
"every window in the group gets raised.");
o->type = CompOptionTypeBool;
o->value.b = GROUP_RAISE_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_AUTO_GROUP];
o->name = "auto_group";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Group the windows after selection");
o->longDesc = N_("If you have selected your windows,"
"this automatically groups them. "
"(Doesn't work with selection mode 'normal')");
o->type = CompOptionTypeBool;
o->value.b = GROUP_AUTO_GROUP_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_AUTO_UNGROUP];
o->name = "auto_ungroup";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc =
N_("Ungroup the windows if only one window is left");
o->longDesc =
N_
("If there is only 1 window in the group left, it will be ungrouped.");
o->type = CompOptionTypeBool;
o->value.b = GROUP_AUTO_UNGROUP_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_RELATIVE_DISTANCE];
o->name = "relative_distance";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Compute distance relative");
o->longDesc =
N_
("The distance between the windows is computed relative to the window size. "
"This allows you to have windows staying next to eachother.");
o->type = CompOptionTypeBool;
o->value.b = GROUP_RELATIVE_DISTANCE_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_SELECTION_COLOR];
o->name = "fill_color";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Selection Color");
o->longDesc = N_("Fill color of the selection.");
o->type = CompOptionTypeColor;
o->value.c[0] = GROUP_COLOR_SELECTION_RED_DEFAULT;
o->value.c[1] = GROUP_COLOR_SELECTION_GREEN_DEFAULT;
o->value.c[2] = GROUP_COLOR_SELECTION_BLUE_DEFAULT;
o->value.c[3] = GROUP_COLOR_SELECTION_ALPHA_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_LINE_COLOR];
o->name = "line_color";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Line Color");
o->longDesc = N_("Line color of the selection.");
o->type = CompOptionTypeColor;
o->value.c[0] = GROUP_COLOR_LINE_RED_DEFAULT;
o->value.c[1] = GROUP_COLOR_LINE_GREEN_DEFAULT;
o->value.c[2] = GROUP_COLOR_LINE_BLUE_DEFAULT;
o->value.c[3] = GROUP_COLOR_LINE_ALPHA_DEFAULT;
}
/*
* groupGetScreenOptions
*
*/
static CompOption *groupGetScreenOptions(CompScreen * s, int *count)
{
if (s) {
GROUP_SCREEN(s);
*count = NUM_OPTIONS(gs);
return gs->opt;
} else {
GroupScreen *gs = malloc(sizeof(GroupScreen));
groupScreenInitOptions(gs);
*count = NUM_OPTIONS(gs);
return gs->opt;
}
}
/*
* groupSetScreenOption
*
*/
static Bool
groupSetScreenOption(CompScreen * s, char *name, CompOptionValue * value)
{
CompOption *o;
int index;
GROUP_SCREEN(s);
o = compFindOption(gs->opt, NUM_OPTIONS(gs), name, &index);
if (!o)
return FALSE;
switch (index) {
case GROUP_SCREEN_OPTION_TYPES:
if (compSetOptionList(o, value)) {
gs->wMask =
compWindowTypeMaskFromStringList(&o->value);
return TRUE;
}
break;
case GROUP_SCREEN_OPTION_SELECTION_COLOR:
case GROUP_SCREEN_OPTION_LINE_COLOR:
if (compSetColorOption(o, value)) {
return TRUE;
}
break;
case GROUP_SCREEN_OPTION_OPACITY:
case GROUP_SCREEN_OPTION_BRIGHTNESS:
case GROUP_SCREEN_OPTION_SATURATION:
case GROUP_SCREEN_OPTION_TOLERANCE:
case GROUP_SCREEN_OPTION_STEPS:
if (compSetIntOption(o, value)) {
return TRUE;
}
break;
case GROUP_SCREEN_OPTION_MOVE:
case GROUP_SCREEN_OPTION_RESIZE:
case GROUP_SCREEN_OPTION_RAISE:
case GROUP_SCREEN_OPTION_AUTO_UNGROUP:
case GROUP_SCREEN_OPTION_AUTO_GROUP:
case GROUP_SCREEN_OPTION_RELATIVE_DISTANCE:
if (compSetBoolOption(o, value)) {
return TRUE;
}
break;
default:
break;
}
return FALSE;
}
/*
* groupSelectWindow
*
*/
static void groupSelectWindow(CompDisplay * d, CompWindow * w)
{
GROUP_DISPLAY(d);
GROUP_SCREEN(w->screen);
GROUP_WINDOW(w);
// select singe window
if ((gs->wMask & w->type) &&
!w->invisible && !gw->inSelection && !gw->inGroup) {
groupAddWindowToSelection(d, w);
gw->inSelection = TRUE;
addWindowDamage(w);
}
// unselect single window
else if ((gs->wMask & w->type) &&
!w->invisible && gw->inSelection && !gw->inGroup) {
groupDeleteSelectionWindow(d, w);
gw->inSelection = FALSE;
addWindowDamage(w);
}
// select group
else if ((gs->wMask & w->type) &&
!w->invisible && !gw->inSelection && gw->inGroup) {
int index = groupFindGroupAtDisplay(gd, gw->groupID);
if (index == -1)
return;
int i;
for (i = 0; i < gd->groups[index].nWins; i++) {
CompWindow *cw = gd->groups[index].windows[i];
GROUP_WINDOW(cw);
groupAddWindowToSelection(d, cw);
gw->inSelection = TRUE;
addWindowDamage(cw);
}
}
// Unselect group
else if ((gs->wMask & w->type) &&
!w->invisible && gw->inSelection && gw->inGroup) {
int index = groupFindGroupAtDisplay(gd, gw->groupID);
if (index == -1)
return;
CompWindow **buf = gd->tmpSel.windows;
gd->tmpSel.windows = (CompWindow **) calloc(gd->tmpSel.nWins - gd->groups[index].nWins, sizeof(CompWindow *));
int counter = 0;
int i;
for (i = 0; i < gd->tmpSel.nWins; i++) {
CompWindow *cw = buf[i];
GROUP_WINDOW(cw);
if (gw->inGroup
&& gw->groupID == gd->groups[index].id) {
gw->inSelection = FALSE;
addWindowDamage(cw);
continue;
}
gd->tmpSel.windows[counter++] = buf[i];
}
gd->tmpSel.nWins = counter;
free(buf);
}
}
/*
* groupSelectSingle
*
*/
static Bool
groupSelectSingle(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompWindow *w = (CompWindow *) findWindowAtDisplay(d, d->activeWindow);
if (w)
groupSelectWindow(d, w);
return TRUE;
}
/*
* groupSelect
*
*/
static Bool
groupSelect(CompDisplay * d, CompAction * action, CompActionState state,
CompOption * option, int nOption)
{
CompWindow *w = (CompWindow *) findWindowAtDisplay(d, d->activeWindow);
if (!w)
return FALSE;
GROUP_SCREEN(w->screen);
if (!gs->grab) {
if (otherScreenGrabExist(w->screen, "group", 0))
return FALSE;
if (!gs->grabIndex)
gs->grabIndex =
pushScreenGrab(w->screen, None, "group");
if (state & CompActionStateInitKey)
action->state |= CompActionStateTermKey;
if (state & CompActionStateInitButton)
action->state |= CompActionStateTermButton;
gs->x1 = gs->x2 = d->pointerX;
gs->y1 = gs->y2 = d->pointerY;
gs->grab = TRUE;
}
return TRUE;
}
/*
* groupGroupWindows - pre-definition for groupSelectTerminate
*
*/
static Bool
groupGroupWindows(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option, int nOption);
/*
* groupSelectTerminate
*
*/
static Bool
groupSelectTerminate(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option,
int nOption)
{
CompScreen *s;
Window xid;
xid = getIntOptionNamed(option, nOption, "root", 0);
for (s = d->screens; s; s = s->next) {
if (xid && s->root != xid)
continue;
break;
}
if (s) {
GROUP_SCREEN(s);
if (gs->grab) {
if (gs->grabIndex) {
removeScreenGrab(s, gs->grabIndex, NULL);
gs->grabIndex = 0;
}
if (gs->x1 != gs->x2 && gs->y1 != gs->y2) {
REGION reg;
reg.rects = ®.extents;
reg.numRects = 1;
reg.extents.x1 = MIN(gs->x1, gs->x2) - 1;
reg.extents.y1 = MIN(gs->y1, gs->y2) - 1;
reg.extents.x2 = MAX(gs->x1, gs->x2) + 1;
reg.extents.y2 = MAX(gs->y1, gs->y2) + 1;
damageScreenRegion(s, ®);
int count;
CompWindow **ws =
groupFindWindowsInRegion(s, reg,
&count);
if (ws) {
// select windows
int i;
for (i = 0; i < count; i++) {
CompWindow *cw = ws[i];
groupSelectWindow(d, cw);
}
if (gs->
opt
[GROUP_SCREEN_OPTION_AUTO_GROUP].
value.b) {
groupGroupWindows(d, NULL,
0, NULL,
0);
}
free(ws);
}
}
gs->grab = FALSE;
}
}
action->state &=
~(CompActionStateTermKey | CompActionStateTermButton);
return FALSE;
}
/*
* groupGroupWindows
*
*/
static Bool
groupGroupWindows(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
GROUP_DISPLAY(d);
if (gd->tmpSel.nWins > 0) {
int id = gd->nGroups;
int index = groupFindGroupAtDisplay(gd, id);
while (index != -1) {
id++;
index = groupFindGroupAtDisplay(gd, id);
}
int i;
for (i = 0; i < gd->tmpSel.nWins; i++) {
CompWindow *cw = gd->tmpSel.windows[i];
GROUP_WINDOW(cw);
groupAddWindowToGroup(d, cw, id);
gw->inSelection = FALSE;
damageScreen(cw->screen);
}
// exit selection
free(gd->tmpSel.windows);
gd->tmpSel.windows = NULL;
gd->tmpSel.nWins = 0;
}
return FALSE;
}
/*
* groupUnGroupWindows
*
*/
static Bool
groupUnGroupWindows(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option,
int nOption)
{
CompWindow *cw = findWindowAtDisplay(d, d->activeWindow);
if (!cw)
return FALSE;
GROUP_WINDOW(cw);
if (gw->inGroup)
groupDeleteGroup(d, gw->groupID);
return FALSE;
}
/*
* groupInitTab
*
*/
static Bool
groupInitTab(CompDisplay * d, CompAction * action, CompActionState state,
CompOption * option, int nOption)
{
GROUP_DISPLAY(d);
CompWindow *w = findWindowAtDisplay(d, d->activeWindow);
if (!w)
return FALSE;
GROUP_WINDOW(w);
if (!gw->inGroup)
return FALSE;
int index = groupFindGroupAtDisplay(gd, gw->groupID);
if (index == -1)
return FALSE;
if (gd->groups[index].tabbed) {
groupUntabGroup(d, w, gw->groupID);
} else {
groupTabGroup(d, w, gw->groupID);
}
return TRUE;
}
/*
* groupChangeTab
*
*/
static Bool
groupChangeTab(CompDisplay * d, CompAction * action, CompActionState state,
CompOption * option, int nOption)
{
GROUP_DISPLAY(d);
CompWindow *w = findWindowAtDisplay(d, d->activeWindow);
if (!w)
return FALSE;
GROUP_SCREEN(w->screen);
GroupWindow *mgw = GET_GROUP_WINDOW(w, gs);
if (!mgw->inGroup)
return FALSE;
int index = groupFindGroupAtDisplay(gd, mgw->groupID);
if (index == -1)
return FALSE;
if (gd->groups[index].tabbed) {
int i;
for (i = 0; i < gd->groups[index].nWins; i++) {
CompWindow *cw = gd->groups[index].windows[i];
if (cw->id == w->id)
continue;
GROUP_WINDOW(cw);
if (gw->inGroup && gw->groupID == mgw->groupID) {
/*cw->hidden = FALSE;
showWindow (cw);
raiseWindow (cw);
lowerWindow (w);
w->hidden = TRUE;
hideWindow (w);
moveInputFocusToWindow (cw); */
//lowerWindow(w);
UNWRAP(gs, cw->screen, windowMoveNotify);
insertWindowIntoScreen(cw->screen, cw,
w->id);
if (gw->offscreen) {
moveWindow(cw, -1 * cw->screen->width, 0, FALSE, FALSE);
syncWindowPosition(cw);
mgw->offscreen = FALSE;
}
if (!mgw->offscreen) {
moveWindow(w, w->screen->width, 0, FALSE, FALSE);
syncWindowPosition(w);
mgw->offscreen = TRUE;
}
unhookWindowFromScreen(w->screen, w);
//raiseWindow (cw);
moveInputFocusToWindow (cw);
//groupSyncWindows (d, gw->groupID);
gd->groups[index].topTab = cw;
WRAP(gs, cw->screen, windowMoveNotify, groupWindowMoveNotify);
break;
}
}
}
return TRUE;
}
/*
* groupRemoveWindow
*
*/
static Bool
groupRemoveWindow(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompWindow *cw = findWindowAtDisplay(d, d->activeWindow);
if (!cw)
return FALSE;
GROUP_WINDOW(cw);
if (gw->inGroup)
groupDeleteGroupWindow(d, cw);
return FALSE;
}
/*
* groupCloseWindows
*
*/
static Bool
groupCloseWindows(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompWindow *w = findWindowAtDisplay(d, d->activeWindow);
if (!w)
return FALSE;
GROUP_WINDOW(w);
GROUP_DISPLAY(w->screen->display);
if (gw->inGroup) {
int index = groupFindGroupAtDisplay(gd, gw->groupID);
if (index == -1)
return FALSE;
int nWins = gd->groups[index].nWins;
int i;
for (i = 0; i < nWins; i++) {
CompWindow *cw = gd->groups[index].windows[i];
closeWindow(cw, getCurrentTimeFromDisplay(d));
}
}
return FALSE;
}
/*
* groupMinimizeWindows
*
*/
static Bool
groupMinimizeWindows(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option,
int nOption)
{
CompWindow *w = findWindowAtDisplay(d, d->activeWindow);
if (!w)
return FALSE;
GROUP_WINDOW(w);
GROUP_DISPLAY(w->screen->display);
if (gw->inGroup) {
int index = groupFindGroupAtDisplay(gd, gw->groupID);
if (index == -1)
return FALSE;
int nWins = gd->groups[index].nWins;
int i;
for (i = 0; i < nWins; i++) {
CompWindow *cw = gd->groups[index].windows[i];
minimizeWindow(cw);
}
}
return FALSE;
}
/*
* groupSetIgnore
*
*/
static Bool
groupSetIgnore(CompDisplay * d, CompAction * action, CompActionState state,
CompOption * option, int nOption)
{
GROUP_DISPLAY(d);
gd->ignoreMode = TRUE;
if (state & CompActionStateInitKey)
action->state |= CompActionStateTermKey;
return FALSE;
}
/*
* groupUnsetIgnore
*
*/
static Bool
groupUnsetIgnore(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
GROUP_DISPLAY(d);
gd->ignoreMode = FALSE;
action->state &= ~CompActionStateTermKey;
return FALSE;
}
/*
* groupHandleMotionEvent - pre-definition for groupHandleEvent
*
*/
static void groupHandleMotionEvent(CompScreen * s, int xRoot, int yRoot);
/*
* groupHandleEvent
*
*/
static void groupHandleEvent(CompDisplay * d, XEvent * event)
{
GROUP_DISPLAY(d);
switch (event->type) {
case MotionNotify:
{
CompScreen *s =
findScreenAtDisplay(d, event->xmotion.root);
if (s)
groupHandleMotionEvent(s, d->pointerX,
d->pointerY);
break;
}
case ButtonRelease:
// update windows
if (event->xbutton.button == 1) {
if (gd->inAction && gd->lastActiveGroup != -1) {
groupSyncWindows(d, gd->lastActiveGroup);
gd->lastActiveGroup = -1;
gd->inAction = FALSE;
}
}
break;
case UnmapNotify:
{
CompWindow *w =
findWindowAtDisplay(d, event->xunmap.window);
if (!w)
break;
GROUP_WINDOW(w);
// close event
if (gw->inGroup && !w->pendingUnmaps) {
groupDeleteGroupWindow(d, w);
damageScreen(w->screen);
}
break;
}
default:
break;
}
UNWRAP(gd, d, handleEvent);
(*d->handleEvent) (d, event);
WRAP(gd, d, handleEvent, groupHandleEvent);
switch (event->type) {
case PropertyNotify:
// focus event
if (event->xproperty.atom == d->winActiveAtom) {
if (!gd->inAction) {
CompWindow *w = (CompWindow *) findWindowAtDisplay(d, d->activeWindow);
if (!w)
break;
GROUP_WINDOW(w);
GROUP_SCREEN(w->screen);
if (gw->inGroup &&
!IPCS_GetBoolND(IPCS_OBJECT(w->screen->display), "SCALE_INIT", FALSE) &&
gs->opt[GROUP_SCREEN_OPTION_RAISE].value.b) {
groupRaiseWindows(d, w,
gw->groupID);
}
}
}
break;
default:
break;
}
}
/*
* groupWindowResizeNotify
*
*/
static void groupWindowResizeNotify(CompWindow * w)
{
GROUP_SCREEN(w->screen);
GROUP_DISPLAY(w->screen->display);
GROUP_WINDOW(w);
UNWRAP(gs, w->screen, windowResizeNotify);
(*w->screen->windowResizeNotify) (w);
WRAP(gs, w->screen, windowResizeNotify, groupWindowResizeNotify);
if (gw->inGroup && !gd->ignoreMode &&
gs->opt[GROUP_SCREEN_OPTION_RESIZE].value.b) {
int rw = WIN_WIDTH(w) - gw->oldWidth;
int rh = WIN_HEIGHT(w) - gw->oldHeight;
int rx = WIN_X(w) - gw->oldX;
int ry = WIN_Y(w) - gw->oldY;
int index = groupFindGroupAtDisplay(gd, gw->groupID);
if (index != -1) {
int i;
for (i = 0; i < gd->groups[index].nWins; i++) {
CompWindow *cw =
gd->groups[index].windows[i];
if (!cw)
continue;
if (cw->id != w->id) {
UNWRAP(gs, cw->screen,
windowResizeNotify);
UNWRAP(gs, cw->screen,
windowMoveNotify);
int nx = 0;
int ny = 0;
if (gs->opt[GROUP_SCREEN_OPTION_RELATIVE_DISTANCE].value.b) {
int distX = WIN_X(cw) - gw->oldX;
int distY = WIN_Y(cw) - gw->oldY;
int ndistX = distX * ((float) WIN_WIDTH (w) / (float) gw->oldWidth);
int ndistY = distY * ((float) WIN_HEIGHT(w) / (float) gw->oldHeight);
nx = WIN_X(w) + ndistX;
ny = WIN_Y(w) + ndistY;
} else {
nx = WIN_X(cw) + rx;
ny = WIN_Y(cw) + ry;
}
int nwidth = WIN_WIDTH(cw) + rw;
int nheight = WIN_HEIGHT(cw) + rh;
XWindowChanges xwc;
xwc.x = nx;
xwc.y = ny;
xwc.width = nwidth;
xwc.height = nheight;
configureXWindow(cw, CWX | CWY | CWWidth |CWHeight, &xwc);
resizeWindow(cw, nx, ny, nwidth, nheight, WIN_BORDER(cw));
groupUpdatePosBuffer(cw, nx, ny, nwidth, nheight);
WRAP(gs, cw->screen, windowMoveNotify, groupWindowMoveNotify);
WRAP(gs, cw->screen, windowResizeNotify, groupWindowResizeNotify);
}
}
gd->lastActiveGroup = gw->groupID;
gd->inAction = TRUE;
}
}
groupUpdatePosBuffer(w, WIN_X(w), WIN_Y(w), WIN_WIDTH(w),
WIN_HEIGHT(w));
}
/*
* groupDrawTabAnimation
*
*/
static void groupDrawTabAnimation(CompScreen * s)
{
GROUP_SCREEN(s);
GROUP_DISPLAY(s->display);
int index = groupFindGroupAtDisplay(gd, gd->animatedGroup);
if (index == -1)
return;
int stepX, stepY;
int i;
for (i = 0; i < gd->groups[index].nWins; i++) {
CompWindow *cw = gd->groups[index].windows[i];
if (!cw)
continue;
GROUP_WINDOW(cw);
if (!gw->steps && gw->animate) {
gw->animate = FALSE;
gd->animatedGroup = -1;
if (gd->groups[index].tabbed &&
gd->groups[index].topTab != NULL &&
gd->groups[index].topTab->id != cw->id) {
/*cw->hidden = TRUE;
hideWindow (cw);
unsigned int state = getWindowState (s->display, cw->id);
state |= CompWindowStateSkipTaskbarMask;
state |= CompWindowStateSkipPagerMask;
setWindowState (s->display, state, cw->id); */
//lowerWindow(cw);
UNWRAP(gs, cw->screen, windowMoveNotify);
if (!gw->offscreen) {
moveWindow(cw, cw->screen->width, 0, FALSE, FALSE);
gw->offscreen = TRUE;
}
syncWindowPosition (cw);
unhookWindowFromScreen(s, cw);
WRAP(gs, cw->screen, windowMoveNotify, groupWindowMoveNotify);
}
}
if (gw->animate) {
stepX = (gw->destinationX - WIN_X(cw)) / gw->steps;
stepY = (gw->destinationY - WIN_Y(cw)) / gw->steps;
UNWRAP(gs, cw->screen, windowMoveNotify);
moveWindow(cw, stepX, stepY, TRUE, FALSE);
WRAP(gs, cw->screen, windowMoveNotify, groupWindowMoveNotify);
gw->steps--;
}
// last window and animation has finished
if (i == gd->groups[index].nWins - 1 &&
gd->animatedGroup == -1) {
groupSyncWindows(s->display, gw->groupID);
if (gd->groups[index].topTab)
raiseWindow(gd->groups[index].topTab);
}
}
}
#define THUMB_SIZE 128
#define SPACING 20
#define BORDER_COLOR 0.0f, 0.0f, 0.0f, 1.0f
#define BAR_COLOR 0.8f, 0.8f, 0.8f, 0.3f
#define BORDER_WIDTH 5
#define BORDER_RADIUS 10
#define REAL_POSITION(x, s) ( (x >= 0)? x: x + (s)->hsize * (s)->width )
#define VIEWPORT(x, s) ( ( REAL_POSITION(x, s) / (s)->width ) % (s)->hsize )
/*
* groupTabBarVertices
*
*/
static void
groupTabBarVertices(GroupDisplay * gd, int x, int y, int width, int height)
{
int i;
for (i = 0; i < NUM_CORNER_POINTS; i++)
glVertex2f(BORDER_RADIUS * gd->cornerPointsX[i] + x +
width - BORDER_RADIUS,
-BORDER_RADIUS * gd->cornerPointsY[i] +
BORDER_RADIUS + y);
for (i = NUM_CORNER_POINTS - 1; i >= 0; i--)
glVertex2f(-BORDER_RADIUS * gd->cornerPointsX[i] + x +
BORDER_RADIUS,
-BORDER_RADIUS * gd->cornerPointsY[i] +
BORDER_RADIUS + y);
for (i = 0; i < NUM_CORNER_POINTS; i++)
glVertex2f(-BORDER_RADIUS * gd->cornerPointsX[i] + x +
BORDER_RADIUS,
BORDER_RADIUS * gd->cornerPointsY[i] + y +
height - BORDER_RADIUS);
for (i = NUM_CORNER_POINTS - 1; i >= 0; i--)
glVertex2f(BORDER_RADIUS * gd->cornerPointsX[i] + x +
width - BORDER_RADIUS,
BORDER_RADIUS * gd->cornerPointsY[i] + y +
height - BORDER_RADIUS);
}
/*
* groupPaintThumb - taken from switcher and modified for tab bar
*
*/
static void groupPaintThumb(CompWindow * w, int tx, int ty, int tw, int th)
{
DrawWindowGeometryProc oldDrawWindowGeometry;
WindowPaintAttrib sAttrib = w->lastPaint;
/* Wrap drawWindowGeometry to make sure the general
drawWindowGeometry function is used */
oldDrawWindowGeometry = w->screen->drawWindowGeometry;
w->screen->drawWindowGeometry = getBaseDrawWindowGeometry();
if (w->mapNum) {
if (WIN_WIDTH(w) > tw)
sAttrib.xScale = (float) tw / WIN_WIDTH(w);
else
sAttrib.xScale = 1.0f;
if (WIN_HEIGHT(w) > th)
sAttrib.yScale = (float) tw / WIN_HEIGHT(w);
else
sAttrib.yScale = 1.0f;
if (sAttrib.xScale < sAttrib.yScale)
sAttrib.yScale = sAttrib.xScale;
else
sAttrib.xScale = sAttrib.yScale;
sAttrib.xTranslate = tx - w->attrib.x;
sAttrib.yTranslate = ty - w->attrib.y;
(w->screen->drawWindow) (w, &sAttrib, getInfiniteRegion(),
PAINT_WINDOW_TRANSFORMED_MASK);
addWindowDamage(w);
}
w->screen->drawWindowGeometry = oldDrawWindowGeometry;
}
/*
* groupPaintTabBar
*
*/
static void groupPaintTabBar(GroupSelection * group)
{
CompScreen *s = group->topTab->screen;
CompDisplay *d = s->display;
GROUP_SCREEN(s);
GROUP_DISPLAY(d);
if (VIEWPORT(group->topTab->attrib.x, s))
return;
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_BLEND);
int x1, x2, y1, y2, width, height;
width = BORDER_WIDTH * (group->nWins + 1) + THUMB_SIZE * group->nWins;
height = BORDER_WIDTH * 2 + THUMB_SIZE;
x1 = WIN_X(group->topTab) + WIN_WIDTH(group->topTab) / 2 - width / 2;
y1 = WIN_Y(group->topTab) + 10;
x2 = x1 + width;
y2 = y1 + height;
//glColor4f(BAR_COLOR);
glColor4usv(gs->opt[GROUP_SCREEN_OPTION_SELECTION_COLOR].value.c);
glBegin(GL_POLYGON);
groupTabBarVertices(gd, x1, y1, width, height);
glEnd();
//glColor4f(BORDER_COLOR);
glColor4usv(gs->opt[GROUP_SCREEN_OPTION_LINE_COLOR].value.c);
glBegin(GL_LINE_LOOP);
groupTabBarVertices(gd, x1, y1, width, height);
glEnd();
glColor4usv(defaultColor);
glDisable(GL_BLEND);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// draw thumbs
int i;
for (i = 0; i < group->nWins; i++) {
CompWindow *cw = group->windows[i];
if (!cw)
continue;
// calculate coords
int tx1, ty1;
tx1 = x1 + BORDER_WIDTH;
ty1 = y1;
tx1 += (THUMB_SIZE + BORDER_WIDTH) * i;
ty1 += BORDER_WIDTH;
groupPaintThumb(cw, tx1, ty1, THUMB_SIZE, THUMB_SIZE);
}
addWindowDamage(group->topTab);
}
/*
* groupPreparePaintScreen
*
*/
static void groupPreparePaintScreen(CompScreen * s, int msSinceLastPaint)
{
GROUP_SCREEN(s);
UNWRAP(gs, s, preparePaintScreen);
(*s->preparePaintScreen) (s, msSinceLastPaint);
WRAP(gs, s, preparePaintScreen, groupPreparePaintScreen);
groupDrawTabAnimation(s);
}
/*
* groupPaintScreen
*
*/
static Bool
groupPaintScreen(CompScreen * s,
const ScreenPaintAttrib * sAttrib,
Region region, int output, unsigned int mask)
{
GROUP_SCREEN(s);
GROUP_DISPLAY(s->display);
Bool status;
gs->wasTransformed = FALSE;
mask &= ~PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK;
mask |= PAINT_SCREEN_ORDER_BACK_TO_FRONT_MASK;
UNWRAP(gs, s, paintScreen);
status = (*s->paintScreen) (s, sAttrib, region, output, mask);
WRAP(gs, s, paintScreen, groupPaintScreen);
if (status && gs->grab && !gs->wasTransformed) {
int x1, x2, y1, y2;
x1 = MIN(gs->x1, gs->x2);
y1 = MIN(gs->y1, gs->y2);
x2 = MAX(gs->x1, gs->x2);
y2 = MAX(gs->y1, gs->y2);
if (gs->grabIndex) {
glPushMatrix();
prepareXCoords(s, output, -DEFAULT_Z_CAMERA);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_BLEND);
glColor4usv(gs->opt[GROUP_SCREEN_OPTION_SELECTION_COLOR].value.c);
glRecti(x1, y2, x2, y1);
glColor4usv(gs->opt[GROUP_SCREEN_OPTION_LINE_COLOR].value.c);
glBegin(GL_LINE_LOOP);
glVertex2i(x1, y1);
glVertex2i(x2, y1);
glVertex2i(x2, y2);
glVertex2i(x1, y2);
glEnd();
glColor4usv(defaultColor);
glDisable(GL_BLEND);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glPopMatrix();
}
}
// for the animation
if (gd->animatedGroup != -1)
damageScreen(s);
return status;
}
/*
* groupPaintTransformedScreen
*
*/
static void
groupPaintTransformedScreen(CompScreen * s, const ScreenPaintAttrib * sa,
Region region, int output, unsigned int mask)
{
GROUP_SCREEN(s);
UNWRAP(gs, s, paintTransformedScreen);
(*s->paintTransformedScreen) (s, sa, region, output, mask);
WRAP(gs, s, paintTransformedScreen, groupPaintTransformedScreen);
if (gs->grab) {
gs->wasTransformed = TRUE;
int x1, x2, y1, y2;
x1 = MIN(gs->x1, gs->x2);
y1 = MIN(gs->y1, gs->y2);
x2 = MAX(gs->x1, gs->x2);
y2 = MAX(gs->y1, gs->y2);
if (gs->grabIndex) {
glPushMatrix();
glLoadIdentity();
(s->applyScreenTransform) (s, sa, output);
prepareXCoords(s, output, -sa->zTranslate);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_BLEND);
glColor4usv(gs->opt[GROUP_SCREEN_OPTION_SELECTION_COLOR].value.c);
glRecti(x1, y2, x2, y1);
glColor4usv(gs->opt[GROUP_SCREEN_OPTION_LINE_COLOR].value.c);
glBegin(GL_LINE_LOOP);
glVertex2i(x1, y1);
glVertex2i(x2, y1);
glVertex2i(x2, y2);
glVertex2i(x1, y2);
glEnd();
glColor4usv(defaultColor);
glDisable(GL_BLEND);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glPopMatrix();
}
}
}
/*
* groupDrawWindow
*
*/
static Bool
groupDrawWindow(CompWindow * w,
const WindowPaintAttrib * attrib,
Region region, unsigned int mask)
{
Bool status;
GROUP_WINDOW(w);
GROUP_SCREEN(w->screen);
GROUP_DISPLAY(w->screen->display);
WindowPaintAttrib gAttrib = *attrib;
if (gw->inSelection) {
int opacity = gs->opt[GROUP_SCREEN_OPTION_OPACITY].value.i;
int saturation = gs->opt[GROUP_SCREEN_OPTION_SATURATION].value.i;
int brightness = gs->opt[GROUP_SCREEN_OPTION_BRIGHTNESS].value.i;
opacity = OPAQUE * opacity / 100;
saturation = COLOR * saturation / 100;
brightness = BRIGHT * brightness / 100;
gAttrib.opacity = opacity;
gAttrib.saturation = saturation;
gAttrib.brightness = brightness;
}
int index = -1;
if (gw->inGroup)
index = groupFindGroupAtDisplay(gd, gw->groupID);
// paint glow
if (gw->inGroup && index != -1) {
glPushMatrix();
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_BLEND);
if (gs->glowTexture) {
glBindTexture(GL_TEXTURE_2D, gs->glowTexture);
glEnable(GL_TEXTURE_2D);
}
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glColor4usv(gd->groups[index].color);
int glowBorderX = 12;
int glowBorderY = 12;
int glowWidth = 128;
int glowHeight = 128;
int overlapX, overlapY;
overlapX = (WIN_WIDTH(w) * glowBorderX) / (glowWidth - glowBorderX * 2);
overlapY = (WIN_HEIGHT(w) * glowBorderY) / (glowHeight - glowBorderY * 2);
int x1, x2, y1, y2;
x1 = WIN_X(w) - overlapX;
y1 = WIN_Y(w) - overlapY;
x2 = WIN_X(w) + WIN_WIDTH(w) + overlapX;
y2 = WIN_Y(w) + WIN_HEIGHT(w) + overlapY;
glBegin(GL_QUADS);
glTexCoord2d(0.0, 1.0);
glVertex2i(x1, y1);
glTexCoord2d(0.0, 0.0);
glVertex2i(x1, y2);
glTexCoord2d(1.0, 0.0);
glVertex2i(x2, y2);
glTexCoord2d(1.0, 1.0);
glVertex2i(x2, y1);
glEnd();
glDisable(GL_STENCIL_TEST);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glColor4usv(defaultColor);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glPopMatrix();
Region reg = XCreateRegion();
XRectangle rect;
rect.x = x1;
rect.y = y1;
rect.width = x2 - x1;
rect.height = y2 - y1;
XUnionRectWithRegion(&rect, reg, reg);
XSubtractRegion(reg, w->region, reg);
damageScreenRegion(w->screen, reg);
}
UNWRAP(gs, w->screen, drawWindow);
status = (*w->screen->drawWindow) (w, &gAttrib, region, mask);
if (index != -1 &&
gd->groups[index].tabbed &&
gd->groups[index].topTab->id == w->id)
groupPaintTabBar(&gd->groups[index]);
WRAP(gs, w->screen, drawWindow, groupDrawWindow);
return status;
}
/*
* groupHandleMotionEvent
*
*/
static void groupHandleMotionEvent(CompScreen * s, int xRoot, int yRoot)
{
GROUP_SCREEN(s);
if (gs->grab && gs->grabIndex) {
REGION reg;
reg.rects = ®.extents;
reg.numRects = 1;
reg.extents.x1 = MIN(gs->x1, gs->x2) - 1;
reg.extents.y1 = MIN(gs->y1, gs->y2) - 1;
reg.extents.x2 = MAX(gs->x1, gs->x2) + 1;
reg.extents.y2 = MAX(gs->y1, gs->y2) + 1;
damageScreenRegion(s, ®);
gs->x2 = xRoot;
gs->y2 = yRoot;
reg.extents.x1 = MIN(gs->x1, gs->x2) - 1;
reg.extents.y1 = MIN(gs->y1, gs->y2) - 1;
reg.extents.x2 = MAX(gs->x1, gs->x2) + 1;
reg.extents.y2 = MAX(gs->y1, gs->y2) + 1;
damageScreenRegion(s, ®);
}
}
/*
* reloadCornerPoints
*
*/
static void initCornerPoints(GroupDisplay * gd)
{
int i;
float angle;
for (i = 0; i < NUM_CORNER_POINTS; i++) {
angle = (PI / 2) * ((float) i / (NUM_CORNER_POINTS - 1));
gd->cornerPointsY[i] = sin(angle);
gd->cornerPointsX[i] = cos(angle);
}
}
/*
* groupDisplayInitOptions
*
*/
static void groupDisplayInitOptions(GroupDisplay * gd)
{
CompOption *o;
o = &gd->opt[GROUP_DISPLAY_OPTION_SELECT];
o->name = "select";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Select");
o->longDesc = N_("The key for starting selecting windows.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupSelect;
o->value.action.terminate = groupSelectTerminate;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitButton;
o->value.action.type = CompBindingTypeButton;
o->value.action.button.modifiers = GROUP_SELECT_MODIFIERS_DEFAULT;
o->value.action.button.button = GROUP_SELECT_BUTTON_DEFAULT;
o = &gd->opt[GROUP_DISPLAY_OPTION_SELECT_SINGLE];
o->name = "select_single";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Select single window");
o->longDesc = N_("The key for selecting the current window.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupSelectSingle;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers =
GROUP_SELECT_SINGLE_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_SELECT_SINGLE_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_GROUPING];
o->name = "group";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Group");
o->longDesc = N_("The key for grouing windows.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupGroupWindows;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers = GROUP_GROUPING_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_GROUPING_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_UNGROUPING];
o->name = "ungroup";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Ungroup");
o->longDesc = N_("The key for ungrouing windows.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupUnGroupWindows;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers = GROUP_UNGROUPING_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_UNGROUPING_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_TABMODE];
o->name = "tabmode";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Tab");
o->longDesc = N_("The key for entering the tab mode.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupInitTab;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers = GROUP_TABMODE_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_TABMODE_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_CHANGE_TAB];
o->name = "change_tab";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Change Tab");
o->longDesc = N_("The key for changing the tab.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupChangeTab;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers = GROUP_CHANGE_TAB_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_CHANGE_TAB_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_REMOVEING];
o->name = "remove";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Remove Window");
o->longDesc = N_("The key for removing the selected window.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupRemoveWindow;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers = GROUP_REMOVEING_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_REMOVEING_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_CLOSEING];
o->name = "close";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Close Windows");
o->longDesc = N_("The key for closing all windows in the group.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupCloseWindows;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers = GROUP_CLOSEING_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_CLOSEING_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_MINIMIZEING];
o->name = "minimize";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Minimize Windows");
o->longDesc =
N_("The key for minimizeing all windows in the group.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupMinimizeWindows;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers =
GROUP_MINIMIZEING_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_MINIMIZEING_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_IGNORE];
o->name = "ignore";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Ignore Group");
o->longDesc = N_("The key for ignoring the group."
"If this key is pressed you can resize/move a single"
"window in the group.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupSetIgnore;
o->value.action.terminate = groupUnsetIgnore;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers = GROUP_IGNORE_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_IGNORE_KEY_DEFAULT);
}
/*
* groupGetDisplayOptions
*
*/
static CompOption *groupGetDisplayOptions(CompDisplay * d, int *count)
{
if (d) {
GROUP_DISPLAY(d);
*count = NUM_OPTIONS(gd);
return gd->opt;
} else {
GroupDisplay *gd = malloc(sizeof(GroupDisplay));
groupDisplayInitOptions(gd);
*count = NUM_OPTIONS(gd);
return gd->opt;
}
}
/*
* groupSetDisplayOption
*
*/
static Bool
groupSetDisplayOption(CompDisplay * d, char *name, CompOptionValue * value)
{
CompOption *o;
int index;
GROUP_DISPLAY(d);
o = compFindOption(gd->opt, NUM_OPTIONS(gd), name, &index);
if (!o)
return FALSE;
switch (index) {
case GROUP_DISPLAY_OPTION_SELECT:
case GROUP_DISPLAY_OPTION_SELECT_SINGLE:
case GROUP_DISPLAY_OPTION_GROUPING:
case GROUP_DISPLAY_OPTION_UNGROUPING:
case GROUP_DISPLAY_OPTION_REMOVEING:
case GROUP_DISPLAY_OPTION_CLOSEING:
case GROUP_DISPLAY_OPTION_MINIMIZEING:
case GROUP_DISPLAY_OPTION_IGNORE:
case GROUP_DISPLAY_OPTION_TABMODE:
case GROUP_DISPLAY_OPTION_CHANGE_TAB:
if (setDisplayAction(d, o, value))
return TRUE;
break;
default:
break;
}
return FALSE;
}
/*
* groupInitDisplay
*
*/
static Bool groupInitDisplay(CompPlugin * p, CompDisplay * d)
{
GroupDisplay *gd;
gd = malloc(sizeof(GroupDisplay));
if (!gd)
return FALSE;
gd->screenPrivateIndex = allocateScreenPrivateIndex(d);
if (gd->screenPrivateIndex < 0) {
free(gd);
return FALSE;
}
gd->inAction = FALSE;
gd->lastActiveGroup = -1;
gd->animatedGroup = -1;
gd->tmpSel.windows = NULL;
gd->tmpSel.nWins = 0;
gd->groups = NULL;
gd->nGroups = 0;
gd->ignoreMode = FALSE;
groupDisplayInitOptions(gd);
initCornerPoints(gd);
WRAP(gd, d, handleEvent, groupHandleEvent);
d->privates[displayPrivateIndex].ptr = gd;
return TRUE;
}
/*
* groupFiniDisplay
*
*/
static void groupFiniDisplay(CompPlugin * p, CompDisplay * d)
{
GROUP_DISPLAY(d);
if (gd->groups && gd->groups != NULL && gd->nGroups != 0) {
free(gd->groups);
}
freeScreenPrivateIndex(d, gd->screenPrivateIndex);
UNWRAP(gd, d, handleEvent);
free(gd);
}
/*
* groupInitScreen
*
*/
static Bool groupInitScreen(CompPlugin * p, CompScreen * s)
{
GroupScreen *gs;
GROUP_DISPLAY(s->display);
gs = malloc(sizeof(GroupScreen));
if (!gs)
return FALSE;
gs->windowPrivateIndex = allocateWindowPrivateIndex(s);
if (gs->windowPrivateIndex < 0) {
free(gs);
return FALSE;
}
groupScreenInitOptions(gs);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_SELECT].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_SELECT_SINGLE].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_GROUPING].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_UNGROUPING].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_REMOVEING].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_CLOSEING].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_MINIMIZEING].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_TABMODE].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_CHANGE_TAB].value.action);
WRAP(gs, s, windowMoveNotify, groupWindowMoveNotify);
WRAP(gs, s, windowResizeNotify, groupWindowResizeNotify);
WRAP(gs, s, preparePaintScreen, groupPreparePaintScreen);
WRAP(gs, s, paintScreen, groupPaintScreen);
WRAP(gs, s, drawWindow, groupDrawWindow);
WRAP(gs, s, paintTransformedScreen, groupPaintTransformedScreen);
s->privates[gd->screenPrivateIndex].ptr = gs;
gs->grab = FALSE;
gs->grabIndex = 0;
// bind texture for glow
glGenTextures(1, &gs->glowTexture);
glBindTexture(GL_TEXTURE_2D, gs->glowTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 128, 128, 0,
GL_RGBA, GL_UNSIGNED_BYTE, glowTex);
glBindTexture(GL_TEXTURE_2D, 0);
return TRUE;
}
/*
* groupFiniScreen
*
*/
static void groupFiniScreen(CompPlugin * p, CompScreen * s)
{
GROUP_SCREEN(s);
GROUP_DISPLAY(s->display);
freeWindowPrivateIndex(s, gs->windowPrivateIndex);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_SELECT].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_SELECT_SINGLE].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_GROUPING].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_UNGROUPING].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_REMOVEING].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_CLOSEING].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_MINIMIZEING].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_TABMODE].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_CHANGE_TAB].value.action);
UNWRAP(gs, s, windowMoveNotify);
UNWRAP(gs, s, windowResizeNotify);
UNWRAP(gs, s, preparePaintScreen);
UNWRAP(gs, s, paintScreen);
UNWRAP(gs, s, drawWindow);
UNWRAP(gs, s, paintTransformedScreen);
free(gs);
}
/*
* groupInitWindow
*
*/
static Bool groupInitWindow(CompPlugin * p, CompWindow * w)
{
GroupWindow *gw;
GROUP_SCREEN(w->screen);
gw = malloc(sizeof(GroupWindow));
if (!gw)
return FALSE;
gw->inGroup = FALSE;
gw->inSelection = FALSE;
// for move/resize
gw->oldWidth = WIN_WIDTH(w);
gw->oldHeight = WIN_HEIGHT(w);
gw->oldX = WIN_X(w);
gw->oldY = WIN_Y(w);
// for tab
gw->animate = FALSE;
gw->steps = 0;
gw->orgPosX = 0;
gw->orgPosY = 0;
gw->destinationX = 0;
gw->destinationY = 0;
gw->offscreen = FALSE;
w->privates[gs->windowPrivateIndex].ptr = gw;
return TRUE;
}
/*
* groupFiniWindow
*
*/
static void groupFiniWindow(CompPlugin * p, CompWindow * w)
{
GROUP_WINDOW(w);
free(gw);
}
/*
* groupInit
*
*/
static Bool groupInit(CompPlugin * p)
{
displayPrivateIndex = allocateDisplayPrivateIndex();
if (displayPrivateIndex < 0)
return FALSE;
return TRUE;
}
/*
* groupFini
*
*/
static void groupFini(CompPlugin * p)
{
if (displayPrivateIndex >= 0)
freeDisplayPrivateIndex(displayPrivateIndex);
}
/*
* groupDeps array
*
*/
CompPluginDep groupDeps[] = {
{CompPluginRuleBefore, "cube"}
};
/*
* groupVTable
*
*/
CompPluginVTable groupVTable = {
"group",
N_("Window Grouper"),
N_("With this plugin you can group windows."),
groupInit,
groupFini,
groupInitDisplay,
groupFiniDisplay,
groupInitScreen,
groupFiniScreen,
groupInitWindow,
groupFiniWindow,
groupGetDisplayOptions,
groupSetDisplayOption,
groupGetScreenOptions,
groupSetScreenOption,
groupDeps,
sizeof(groupDeps) / sizeof(groupDeps[0]),
0,
0,
BERYL_ABI_INFO,
"beryl-plugins"
};
/*
* getCompPluginInfo
*
*/
CompPluginVTable *getCompPluginInfo(void)
{
return &groupVTable;
}