rendered paste body/**
*
* Beryl group plugin
*
* group.c
*
* Copyright : (C) 2006 by Patrick Niklaus
* E-mail : patrick.niklaus [ a t ] googlemail.com
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* TODO:
* * glow effect
* * tab like switching between the windows
* * a lot of other tab stuff...
* * provide a tree system for groups
*
**/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <X11/Xlib.h>
#include <beryl.h>
#include <beryl_ipcs.h>
#include <X11/Xatom.h>
#include <math.h>
#include "group_glow.h"
#define PI 3.1415926535897
#define NUM_CORNER_POINTS 25
/*
* Defaults
*
*/
#define GROUP_SELECT_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_SELECT_BUTTON_DEFAULT Button1
#define GROUP_SELECT_SINGLE_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_SELECT_SINGLE_KEY_DEFAULT "s"
#define GROUP_GROUPING_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_GROUPING_KEY_DEFAULT "g"
#define GROUP_UNGROUPING_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_UNGROUPING_KEY_DEFAULT "u"
#define GROUP_TABMODE_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_TABMODE_KEY_DEFAULT "t"
#define GROUP_CHANGE_TAB_LEFT_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_CHANGE_TAB_LEFT_KEY_DEFAULT "Left"
#define GROUP_CHANGE_TAB_RIGHT_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_CHANGE_TAB_RIGHT_KEY_DEFAULT "Right"
#define GROUP_REMOVEING_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_REMOVEING_KEY_DEFAULT "r"
#define GROUP_CLOSEING_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_CLOSEING_KEY_DEFAULT "c"
#define GROUP_MINIMIZEING_MODIFIERS_DEFAULT (CompSuperMask)
#define GROUP_MINIMIZEING_KEY_DEFAULT "b"
#define GROUP_IGNORE_MODIFIERS_DEFAULT (CompAltMask)
#define GROUP_IGNORE_KEY_DEFAULT "x"
#define GROUP_DISPLAY_OPTION_SELECT 0
#define GROUP_DISPLAY_OPTION_SELECT_SINGLE 1
#define GROUP_DISPLAY_OPTION_GROUPING 2
#define GROUP_DISPLAY_OPTION_UNGROUPING 3
#define GROUP_DISPLAY_OPTION_REMOVEING 4
#define GROUP_DISPLAY_OPTION_CLOSEING 5
#define GROUP_DISPLAY_OPTION_MINIMIZEING 6
#define GROUP_DISPLAY_OPTION_IGNORE 7
#define GROUP_DISPLAY_OPTION_TABMODE 8
#define GROUP_DISPLAY_OPTION_CHANGE_TAB_LEFT 9
#define GROUP_DISPLAY_OPTION_CHANGE_TAB_RIGHT 10
#define GROUP_DISPLAY_OPTION_NUM 11
#define GROUP_OPACITY_DEFAULT 80
#define GROUP_OPACITY_MIN 0
#define GROUP_OPACITY_MAX 100
#define GROUP_SATURATION_DEFAULT 20
#define GROUP_SATURATION_MIN 0
#define GROUP_SATURATION_MAX 100
#define GROUP_BRIGHTNESS_DEFAULT 70
#define GROUP_BRIGHTNESS_MIN 0
#define GROUP_BRIGHTNESS_MAX 100
#define GROUP_TOLERANCE_DEFAULT 0
#define GROUP_TOLERANCE_MIN 0
#define GROUP_TOLERANCE_MAX 10
#define GROUP_STEPS_DEFAULT 10
#define GROUP_STEPS_MIN 1
#define GROUP_STEPS_MAX 10
#define GROUP_THUMB_SIZE_DEFAULT 64
#define GROUP_THUMB_SIZE_MIN 16
#define GROUP_THUMB_SIZE_MAX 128
#define GROUP_BORDER_WIDTH_DEFAULT 10
#define GROUP_BORDER_WIDTH_MIN 1
#define GROUP_BORDER_WIDTH_MAX 20
#define GROUP_BORDER_RADIUS_DEFAULT 10
#define GROUP_BORDER_RADIUS_MIN 1
#define GROUP_BORDER_RADIUS_MAX 20
#define GROUP_MOVE_DEFAULT TRUE
#define GROUP_RESIZE_DEFAULT TRUE
#define GROUP_RAISE_DEFAULT TRUE
#define GROUP_AUTO_UNGROUP_DEFAULT FALSE
#define GROUP_AUTO_GROUP_DEFAULT FALSE
#define GROUP_RELATIVE_DISTANCE_DEFAULT FALSE
#define GROUP_COLOR_SELECTION_RED_DEFAULT 0x0000
#define GROUP_COLOR_SELECTION_GREEN_DEFAULT 0x0000
#define GROUP_COLOR_SELECTION_BLUE_DEFAULT 0x0000
#define GROUP_COLOR_SELECTION_ALPHA_DEFAULT 0x9999
#define GROUP_COLOR_LINE_RED_DEFAULT 0x0000
#define GROUP_COLOR_LINE_GREEN_DEFAULT 0x0000
#define GROUP_COLOR_LINE_BLUE_DEFAULT 0x0000
#define GROUP_COLOR_LINE_ALPHA_DEFAULT 0xABAB
#define GROUP_COLOR_TAB_FILL_RED_DEFAULT 0x0000
#define GROUP_COLOR_TAB_FILL_GREEN_DEFAULT 0x0000
#define GROUP_COLOR_TAB_FILL_BLUE_DEFAULT 0x0000
#define GROUP_COLOR_TAB_FILL_ALPHA_DEFAULT 0x9999
#define GROUP_COLOR_TAB_BORDER_RED_DEFAULT 0x0000
#define GROUP_COLOR_TAB_BORDER_GREEN_DEFAULT 0x0000
#define GROUP_COLOR_TAB_BORDER_BLUE_DEFAULT 0x0000
#define GROUP_COLOR_TAB_BORDER_ALPHA_DEFAULT 0xABAB
#define GROUP_TAB_CREATE_MIPMAPS_DEFAULT TRUE
#define GROUP_GLOW_DEFAULT TRUE
#define GROUP_SCREEN_OPTION_TYPES 0
#define GROUP_SCREEN_OPTION_OPACITY 1
#define GROUP_SCREEN_OPTION_SATURATION 2
#define GROUP_SCREEN_OPTION_BRIGHTNESS 3
#define GROUP_SCREEN_OPTION_GLOW 4
#define GROUP_SCREEN_OPTION_MOVE 5
#define GROUP_SCREEN_OPTION_RESIZE 6
#define GROUP_SCREEN_OPTION_RAISE 7
#define GROUP_SCREEN_OPTION_AUTO_UNGROUP 8
#define GROUP_SCREEN_OPTION_AUTO_GROUP 9
#define GROUP_SCREEN_OPTION_RELATIVE_DISTANCE 10
#define GROUP_SCREEN_OPTION_SELECTION_COLOR 11
#define GROUP_SCREEN_OPTION_LINE_COLOR 12
#define GROUP_SCREEN_OPTION_TOLERANCE 13
#define GROUP_SCREEN_OPTION_STEPS 14
#define GROUP_SCREEN_OPTION_THUMB_SIZE 15
#define GROUP_SCREEN_OPTION_BORDER_WIDTH 16
#define GROUP_SCREEN_OPTION_BORDER_RADIUS 17
#define GROUP_SCREEN_OPTION_TAB_BORDER_COLOR 18
#define GROUP_SCREEN_OPTION_TAB_FILL_COLOR 19
#define GROUP_SCREEN_OPTION_TAB_CREATE_MIPMAPS 20
#define GROUP_SCREEN_OPTION_NUM 21
/*
* Helpers
*
*/
#define GET_GROUP_DISPLAY(d) ((GroupDisplay *) (d)->privates[displayPrivateIndex].ptr)
#define GROUP_DISPLAY(d) GroupDisplay *gd = GET_GROUP_DISPLAY (d)
#define GET_GROUP_SCREEN(s, gd) ((GroupScreen *) (s)->privates[ (gd)->screenPrivateIndex].ptr)
#define GROUP_SCREEN(s) GroupScreen *gs = GET_GROUP_SCREEN (s, GET_GROUP_DISPLAY (s->display))
#define GET_GROUP_WINDOW(w, gs) ((GroupWindow *) (w)->privates[ (gs)->windowPrivateIndex].ptr)
#define GROUP_WINDOW(w) GroupWindow *gw = GET_GROUP_WINDOW (w, GET_GROUP_SCREEN (w->screen, GET_GROUP_DISPLAY (w->screen->display)))
#define WIN_X(w) (w->attrib.x)
#define WIN_Y(w) (w->attrib.y)
#define WIN_WIDTH(w) (w->attrib.width)
#define WIN_HEIGHT(w) (w->attrib.height)
#define WIN_BORDER(w) (w->attrib.border_width)
#define NUM_OPTIONS(s) (sizeof ( (s)->opt) / sizeof (CompOption))
#define N_WIN_TYPE (sizeof (groupDefaultTypes) / sizeof (groupDefaultTypes[0]))
#define N_SEL_MODE (sizeof (groupSelectionModes) / sizeof (groupSelectionModes[0]))
#define REAL_POSITION(x, s) ( (x >= 0)? x: x + (s)->hsize * (s)->width )
#define VIEWPORT(x, s) ( ( REAL_POSITION(x, s) / (s)->width ) % (s)->hsize )
#define TOP_TAB(g) ((g)->windows[(g)->topTab])
#define PREV_TOP_TAB(g) ((g)->windows[(g)->prevTopTab])
/*
* default windows for selection
*/
static char *groupDefaultTypes[] = {
N_("Normal"),
N_("Dialog"),
N_("ModalDialog"),
N_("Dnd")
};
/*
* structs for pending callbacks
*/
typedef struct _GroupPendingMoves GroupPendingMoves;
struct _GroupPendingMoves {
CompWindow *w;
int dx;
int dy;
GroupPendingMoves *next;
};
typedef struct _GroupPendingResizes GroupPendingResizes;
struct _GroupPendingResizes {
CompWindow *w;
int x;
int y;
int width;
int height;
int borderWidth;
GroupPendingResizes *next;
};
typedef struct _GroupPendingGrabs GroupPendingGrabs;
struct _GroupPendingGrabs {
CompWindow *w;
int x;
int y;
unsigned int state;
unsigned int mask;
GroupPendingGrabs *next;
};
typedef struct _GroupPendingUngrabs GroupPendingUngrabs;
struct _GroupPendingUngrabs {
CompWindow *w;
GroupPendingUngrabs *next;
};
/*
* pointer to display list
*/
static int displayPrivateIndex;
/*
* GroupTabBarSlot
*/
typedef struct _GroupTabBarSlot GroupTabBarSlot;
struct _GroupTabBarSlot {
GroupTabBarSlot *prev;
GroupTabBarSlot *next;
int rx;
int ry;
int height;
int width;
CompWindow *window;
};
/*
* GroupTabBar
*/
typedef struct _GroupTabBar {
GroupTabBarSlot *slots;
GroupTabBarSlot *revSlots;
int nSlots;
Bool visible;
int rx;
int ry;
int height;
int width;
} GroupTabBar;
/*
* GroupSelection
*/
typedef struct _GroupSelection GroupSelection;
struct _GroupSelection {
GroupSelection *prev;
GroupSelection *next;
CompWindow **windows;
int nWins;
int topTab;
int prevTopTab;
Bool tabbed;
GroupTabBar *tabBar;
int animationSteps;
int dx, dy; //For tabbed windows.
Bool ungroup;
GLushort color[4];
};
/*
* GroupDisplay structure
*/
typedef struct _GroupDisplay {
int screenPrivateIndex;
CompOption opt[GROUP_DISPLAY_OPTION_NUM];
HandleEventProc handleEvent;
GroupSelection tmpSel;
GroupSelection *groups;
//GroupSelection *revGroups;
Bool inAction;
GroupSelection *lastActiveGroup;
//int animatedGroup;
Bool ignoreMode;
float cornerPointsX[NUM_CORNER_POINTS];
float cornerPointsY[NUM_CORNER_POINTS];
} GroupDisplay;
/*
* GroupScreen structure
*/
typedef struct _GroupScreen {
int windowPrivateIndex;
CompOption opt[GROUP_SCREEN_OPTION_NUM];
WindowMoveNotifyProc windowMoveNotify;
WindowResizeNotifyProc windowResizeNotify;
PreparePaintScreenProc preparePaintScreen;
PaintScreenProc paintScreen;
DrawWindowProc drawWindow;
PaintWindowProc paintWindow;
PaintTransformedScreenProc paintTransformedScreen;
WindowGrabNotifyProc windowGrabNotify;
WindowUngrabNotifyProc windowUngrabNotify;
GroupPendingMoves *pendingMoves;
GroupPendingResizes *pendingResizes;
GroupPendingGrabs *pendingGrabs;
GroupPendingUngrabs *pendingUngrabs;
int wMask;
Bool ignoreCallback;
// for selection
Bool grab;
Bool wasTransformed;
int grabIndex;
int x1;
int y1;
int x2;
int y2;
CompTexture glowTexture;
} GroupScreen;
/*
* GroupWindow structure
*/
typedef struct _GroupWindow {
GroupSelection *group;
Bool inGroup;
Bool inSelection;
// for the tab bar
GroupTabBarSlot *slot;
// for scale notify...
int oldWidth;
int oldHeight;
int oldX;
int oldY;
// for tab animation
int orgPosX; //Relative to the tabbed window.
int orgPosY; //Relative to the tabbed window.
int destinationX;
int destinationY;
} GroupWindow;
#define TOLRNC_MIN(n1, n2, t) (n1 - t < n2)
#define TOLRNC_MAX(n1, n2, t) (n1 + t > n2)
/*
* groupFindWindowsInRegion
*
*/
static CompWindow **groupFindWindowsInRegion(CompScreen * s, REGION reg, int *c)
{
GROUP_SCREEN(s);
float tolerance = gs->opt[GROUP_SCREEN_OPTION_TOLERANCE].value.i / 10.0f;
CompWindow **ret = NULL;
int count = 0;
CompWindow *w;
for (w = s->windows; w; w = w->next) {
if ((gs->wMask & w->type) &&
!w->invisible &&
TOLRNC_MIN(reg.extents.x1, WIN_X(w), tolerance * WIN_WIDTH(w)) &&
TOLRNC_MIN(reg.extents.y1, WIN_Y(w), tolerance * WIN_HEIGHT(w)) &&
TOLRNC_MAX(reg.extents.x2, (WIN_X(w) + WIN_WIDTH(w)), tolerance * WIN_WIDTH(w)) &&
TOLRNC_MAX(reg.extents.y2, (WIN_Y(w) + WIN_HEIGHT(w)), tolerance * WIN_HEIGHT(w))) {
if (count == 0) {
ret = calloc(1, sizeof(CompWindow));
ret[0] = w;
} else {
ret = realloc(ret, sizeof(CompWindow) * (count + 1));
ret[count] = w;
}
count++;
}
}
(*c) = count;
return ret;
}
/*
* groupUpdatePosBuffer
*
*/
static void
groupUpdatePosBuffer(CompWindow * w, int x, int y, int width, int height)
{
GROUP_WINDOW(w);
gw->oldX = x;
gw->oldY = y;
gw->oldWidth = width;
gw->oldHeight = height;
}
/*
* functions enqueuing pending notifies
*
*/
static void groupEnqueueMoveNotify (CompScreen *s, CompWindow *w, int dx, int dy)
{
GroupPendingMoves *move;
GROUP_SCREEN (s);
move = malloc (sizeof(GroupPendingMoves));
if (!move)
return;
move->w = w;
move->dx = dx;
move->dy = dy;
move->next = NULL;
if (gs->pendingMoves) {
GroupPendingMoves *temp;
for (temp = gs->pendingMoves; temp->next; temp = temp->next);
temp->next = move;
} else {
gs->pendingMoves = move;
}
}
static void groupDequeueMoveNotifies (CompScreen *s)
{
GroupPendingMoves *move, *next;
GROUP_SCREEN (s);
gs->ignoreCallback = TRUE;
move = gs->pendingMoves;
while (move) {
moveWindow (move->w, move->dx, move->dy, TRUE, FALSE);
groupUpdatePosBuffer (move->w, WIN_X(move->w) + move->dx,
WIN_Y(move->w) + move->dy, WIN_WIDTH(move->w), WIN_HEIGHT(move->w));
next = move->next;
free (move);
move = next;
}
gs->pendingMoves = NULL;
gs->ignoreCallback = FALSE;
}
static void groupEnqueueResizeNotify (CompScreen *s, CompWindow *w, int x, int y,
int width, int height, int border_width)
{
GroupPendingResizes *resize;
GROUP_SCREEN (s);
resize = malloc (sizeof(GroupPendingResizes));
if (!resize)
return;
resize->w = w;
resize->x = x;
resize->y = y;
resize->width = width;
resize->height = height;
resize->borderWidth = border_width;
resize->next = NULL;
if (gs->pendingResizes) {
GroupPendingResizes *temp;
for (temp = gs->pendingResizes; temp->next; temp = temp->next);
temp->next = resize;
} else {
gs->pendingResizes = resize;
}
}
static void groupDequeueResizeNotifies (CompScreen *s)
{
GroupPendingResizes *resize, *next;
GROUP_SCREEN (s);
gs->ignoreCallback = TRUE;
resize = gs->pendingResizes;
while (resize) {
resizeWindow (resize->w, resize->x, resize->y, resize->width,
resize->height, resize->borderWidth);
groupUpdatePosBuffer (resize->w, resize->x, resize->y, resize->width, resize->height);
next = resize->next;
free (resize);
resize = next;
}
gs->pendingResizes = NULL;
gs->ignoreCallback = FALSE;
}
static void groupEnqueueGrabNotify (CompScreen *s, CompWindow *w, int x, int y,
unsigned int state, unsigned int mask)
{
GroupPendingGrabs *grab;
GROUP_SCREEN (s);
grab = malloc (sizeof(GroupPendingGrabs));
if (!grab)
return;
grab->w = w;
grab->x = x;
grab->y = y;
grab->state = state;
grab->mask = mask;
grab->next = NULL;
if (gs->pendingGrabs) {
GroupPendingGrabs *temp;
for (temp = gs->pendingGrabs; temp->next; temp = temp->next);
temp->next = grab;
} else {
gs->pendingGrabs = grab;
}
}
static void groupDequeueGrabNotifies (CompScreen *s)
{
GroupPendingGrabs *grab, *next;
GROUP_SCREEN (s);
gs->ignoreCallback = TRUE;
grab = gs->pendingGrabs;
while (grab) {
(*(grab->w)->screen->windowGrabNotify) (grab->w, grab->x, grab->y, grab->state, grab->mask);
next = grab->next;
free (grab);
grab = next;
}
gs->pendingGrabs = NULL;
gs->ignoreCallback = FALSE;
}
static void groupEnqueueUngrabNotify (CompScreen *s, CompWindow *w)
{
GroupPendingUngrabs *ungrab;
GROUP_SCREEN (s);
ungrab = malloc (sizeof(GroupPendingUngrabs));
if (!ungrab)
return;
ungrab->w = w;
ungrab->next = NULL;
if (gs->pendingUngrabs) {
GroupPendingUngrabs *temp;
for (temp = gs->pendingUngrabs; temp->next; temp = temp->next);
temp->next = ungrab;
} else {
gs->pendingUngrabs = ungrab;
}
}
static void groupDequeueUngrabNotifies (CompScreen *s)
{
GroupPendingUngrabs *ungrab, *next;
GROUP_SCREEN (s);
gs->ignoreCallback = TRUE;
ungrab = gs->pendingUngrabs;
while (ungrab) {
(*(ungrab->w)->screen->windowUngrabNotify) (ungrab->w);
next = ungrab->next;
free (ungrab);
ungrab = next;
}
gs->pendingUngrabs = NULL;
gs->ignoreCallback = FALSE;
}
/*
* groupAddSkipMasks
*
*/
static void
groupAddSkipMasks(CompWindow *w)
{
unsigned int state = getWindowState (w->screen->display, w->id);
state |= CompWindowStateSkipTaskbarMask;
state |= CompWindowStateSkipPagerMask;
setWindowState (w->screen->display, state, w->id);
}
/*
* groupRemoveSkipMasks
*
*/
static void
groupRemoveSkipMasks(CompWindow *w)
{
unsigned int state = getWindowState (w->screen->display, w->id);
state &= ~CompWindowStateSkipTaskbarMask;
state &= ~CompWindowStateSkipPagerMask;
setWindowState (w->screen->display, state, w->id);
}
/*
* groupFindWindowIndex
*
*/
static int
groupFindWindowIndex(CompWindow *w, GroupSelection *g)
{
int i;
for(i = 0; i < g->nWins; i++)
{
if(g->windows[i]->id == w->id)
return i;
}
return -1;
}
/*
* groupWindowMoveNotify
*
*/
static void
groupWindowMoveNotify(CompWindow * w, int dx, int dy, Bool immediate)
{
GROUP_SCREEN(w->screen);
GROUP_DISPLAY(w->screen->display);
GROUP_WINDOW(w);
UNWRAP(gs, w->screen, windowMoveNotify);
(*w->screen->windowMoveNotify) (w, dx, dy, immediate);
WRAP(gs, w->screen, windowMoveNotify, groupWindowMoveNotify);
groupUpdatePosBuffer(w, WIN_X(w) + dx, WIN_Y(w) + dy, WIN_WIDTH(w), WIN_HEIGHT(w));
if (gw->inGroup && gw->group->tabbed &&
gw->group->topTab != -1)
{
if (TOP_TAB(gw->group)->id != w->id)
{
groupEnqueueMoveNotify (w->screen, w, -dx, -dy);
}
else
{
gw->group->dx += dx;
gw->group->dy += dy;
}
return;
}
// workaround for viewports
Bool vpMove = FALSE;
if ((dx % w->screen->workArea.width == 0 && dx != 0) ||
(dy % w->screen->workArea.height == 0 && dy != 0))
vpMove = TRUE;
if (!gw->inGroup || gs->ignoreCallback ||
gw->group->animationSteps ||
vpMove ||
IPCS_GetBoolND(IPCS_OBJECT(w), "SHOWDESKTOP_MOVE", FALSE) ||
IPCS_GetBoolND(IPCS_OBJECT(w->screen->display), "SCALE_INIT", FALSE) ||
!gs->opt[GROUP_SCREEN_OPTION_MOVE].value.b ||
gd->ignoreMode)
return;
int i;
for (i = 0; i < gw->group->nWins; i++) {
CompWindow *cw = gw->group->windows[i];
if (!cw)
continue;
if (cw->id != w->id) {
groupEnqueueMoveNotify (cw->screen, cw, dx, dy);
}
}
gd->lastActiveGroup = gw->group;
gd->inAction = TRUE;
}
/*
* groupRecalcTabBarPos
*
*/
static void groupRecalcTabBarPos(GroupSelection *group)
{
if (group->topTab < 0 || !group->tabBar)
return;
GroupTabBar *bar = group->tabBar;
CompWindow *topTab = TOP_TAB(group);
GROUP_SCREEN(topTab->screen);
int border_width = gs->opt[GROUP_SCREEN_OPTION_BORDER_WIDTH].value.i;
int thumb_size = gs->opt[GROUP_SCREEN_OPTION_THUMB_SIZE].value.i;
bar->width = border_width * (bar->nSlots + 1) + thumb_size * bar->nSlots;
bar->height = border_width * 2 + thumb_size;
bar->rx = WIN_WIDTH(topTab) / 2 - bar->width / 2;
bar->ry = 0;
}
/*
* groupInsertTabBarSlot
*
*/
static void groupInsertTabBarSlot(GroupTabBar *bar, GroupTabBarSlot *slot)
{
if (bar->slots != NULL) {
bar->revSlots->next = slot;
slot->prev = bar->revSlots;
slot->next = NULL;
} else {
slot->prev = NULL;
slot->next = NULL;
bar->slots = slot;
}
bar->revSlots = slot;
CompWindow *w = slot->window;
GROUP_WINDOW(w);
groupRecalcTabBarPos(gw->group);
}
/*
* groupUnhookTabBarSlot
*
*/
static void groupUnhookTabBarSlot(GroupTabBar *bar, GroupTabBarSlot *slot)
{
GroupTabBarSlot *prev = slot->prev;
GroupTabBarSlot *next = slot->next;
if (prev || next) {
if (prev)
{
if (next)
prev->next = next;
else
prev->next = NULL;
}
if (next)
{
if (prev)
next->prev = prev;
else
next->prev = NULL;
}
} else {
bar->slots = NULL;
bar->revSlots = NULL;
}
bar->nSlots--;
CompWindow *w = slot->window;
GROUP_WINDOW(w);
groupRecalcTabBarPos(gw->group);
free(slot);
}
/*
* groupInitTabBar
*
*/
static void groupInitTabBar(GroupSelection *group)
{
// error
if (group->topTab < 0)
return;
CompWindow *topTab = group->windows[group->topTab];
GROUP_SCREEN(topTab->screen);
int border_width = gs->opt[GROUP_SCREEN_OPTION_BORDER_WIDTH].value.i;
int thumb_size = gs->opt[GROUP_SCREEN_OPTION_THUMB_SIZE].value.i;
GroupTabBar *bar = (GroupTabBar*) malloc(sizeof(GroupTabBar));
bar->slots = NULL;
bar->visible = FALSE;
int i;
for(i = 0; i < group->nWins; i++)
{
GroupTabBarSlot *slot = (GroupTabBarSlot*) malloc(sizeof(GroupTabBarSlot));
slot->window = group->windows[i];
slot->width = thumb_size;
slot->height = thumb_size;
slot->rx = border_width + ((slot->width + border_width) * i);
slot->ry = border_width;
groupInsertTabBarSlot(bar, slot);
GROUP_WINDOW(group->windows[i]);
gw->slot = slot;
}
bar->nSlots = group->nWins;
group->tabBar = bar;
groupRecalcTabBarPos(group);
}
/*
* groupDeleteTabBar
*
*/
static void groupDeleteTabBar(GroupSelection *group)
{
GroupTabBar *bar = group->tabBar;
GroupTabBarSlot *slot;
for(slot = bar->slots; slot; slot = slot->next)
{
if (slot->prev) {
free(slot->prev);
}
if (!slot->next) {
free(slot);
break;
}
}
free(bar);
group->tabBar = NULL;
}
/*
* groupTabGroup
*
*/
static void groupTabGroup(CompWindow * main)
{
GROUP_WINDOW(main);
GROUP_SCREEN(main->screen);
GroupSelection *group = gw->group;
if(!group || !gw->inGroup)
return;
int steps = gs->opt[GROUP_SCREEN_OPTION_STEPS].value.i;
group->tabbed = TRUE;
group->animationSteps = steps;
// main window
group->topTab = groupFindWindowIndex(main, group);
group->prevTopTab = -1;
if(group->topTab == -1)
return;
groupInitTabBar(group);
group->tabBar->visible = TRUE;
int i;
for (i = 0; i < group->nWins; i++) {
CompWindow *cw = group->windows[i];
GROUP_WINDOW(cw);
// center the window to the main window
gw->destinationX = WIN_X(main) + (WIN_WIDTH(main) / 2) - (WIN_WIDTH(cw) / 2);
gw->destinationY = WIN_Y(main) + (WIN_HEIGHT(main) / 2) - (WIN_HEIGHT(cw) / 2);
gw->orgPosX = WIN_X(cw) - gw->destinationX;
gw->orgPosY = WIN_Y(cw) - gw->destinationY;
}
damageScreen(main->screen);
}
/*
* groupUntabGroup
*
*/
static void
groupUntabGroup(CompDisplay *d, GroupSelection *group)
{
//TODO: Respect window borders, struts and constrain y options...
if(group->topTab == -1)
return;
GROUP_SCREEN(d->screens);
GROUP_WINDOW(TOP_TAB(group));
int maxY = 0, minY = TOP_TAB(group)->screen->height;
int decreaseY = 0;
int steps = gs->opt[GROUP_SCREEN_OPTION_STEPS].value.i;
int mainOrgPosX = gw->orgPosX;
int mainOrgPosY = gw->orgPosY;
group->tabbed = FALSE;
group->animationSteps = steps;
// main window
group->prevTopTab = group->topTab;
group->topTab = -1;
group->tabBar->visible = FALSE;
groupDeleteTabBar(group);
int i;
for (i = 0; i < group->nWins; i++) {
CompWindow *cw = group->windows[i];
GROUP_WINDOW(cw);
gw->destinationX = WIN_X(cw) + gw->orgPosX - mainOrgPosX;
gw->destinationY = WIN_Y(cw) + gw->orgPosY - mainOrgPosY;
if(i != group->prevTopTab) //Window is offscreen.
{
gw->destinationX -= cw->screen->width;
gw->destinationX += group->dx;
gw->destinationY += group->dy;
}
if(gw->destinationY > maxY)
maxY = gw->destinationY;
if(gw->destinationY < minY)
minY = gw->destinationY;
gw->orgPosX = 0;
gw->orgPosY = 0;
}
if(maxY > PREV_TOP_TAB(group)->screen->height)
decreaseY = maxY - PREV_TOP_TAB(group)->screen->height;
else if(minY < 0)
decreaseY = minY;
for (i = 0; i < group->nWins; i++) {
CompWindow *cw = group->windows[i];
GROUP_WINDOW(cw);
gw->destinationY -= decreaseY;
}
damageScreen(PREV_TOP_TAB(group)->screen);
}
/*
* groupDeleteGroup - pre-definition for groupDeleteGroupWindow
*
*/
static void groupDeleteGroup(CompDisplay * d, GroupSelection *group);
/*
* groupDeleteGroupWindow
*
*/
static void groupDeleteGroupWindow(CompDisplay * d, CompWindow * w)
{
GROUP_WINDOW(w);
GROUP_SCREEN(w->screen);
GroupSelection *group = gw->group;
if (group->tabbed) {
if (group->topTab >= 0 &&
TOP_TAB(group)->id == w->id)
groupUntabGroup(d, group);
else
groupUnhookTabBarSlot(group->tabBar, gw->slot);
}
if (group->nWins != 0
&& group->windows != NULL) {
CompWindow **buf = group->windows;
group->windows = (CompWindow **) calloc(group->nWins - 1, sizeof(CompWindow *));
int counter = 0;
int i;
for (i = 0; i < group->nWins; i++) {
if (buf[i]->id == w->id)
continue;
group->windows[counter++] = buf[i];
}
group->nWins = counter;
if (group->nWins == 1 &&
gs->opt[GROUP_SCREEN_OPTION_AUTO_UNGROUP].value.b) {
groupDeleteGroup(d, gw->group);
} else if (group->nWins <= 0) {
free(group->windows);
group->windows = NULL;
groupDeleteGroup(d, group);
}
free(buf);
gw->inGroup = FALSE;
}
}
/*
* groupDeleteGroup
*
*/
static void groupDeleteGroup(CompDisplay * d, GroupSelection *group)
{
GROUP_DISPLAY(d);
gd->inAction = TRUE;
gd->lastActiveGroup = NULL;
if (group->windows != NULL) {
if (group->tabbed) {
groupUntabGroup(d, group);
group->ungroup = TRUE;
return;
}
int i;
for (i = 0; i < group->nWins; i++) {
CompWindow *cw = group->windows[i];
GROUP_WINDOW(cw);
gw->inGroup = FALSE;
}
free(group->windows);
}
GroupSelection *prev = group->prev;
GroupSelection *next = group->next;
// relink stack
if (prev || next) {
if (prev) {
if (next)
prev->next = next;
else {
prev->next = NULL;
//gd->revGroups = prev;
}
}
if (next) {
if (prev)
next->prev = prev;
else {
next->prev = NULL;
gd->groups = next;
}
}
} else {
gd->groups = NULL;
}
free(group);
gd->inAction = FALSE;
}
/*
* groupAddWindowToGroup
*
*/
static void
groupAddWindowToGroup(CompDisplay * d, CompWindow * w, GroupSelection *group)
{
GROUP_DISPLAY(d);
GROUP_WINDOW(w);
if (gw->inGroup)
groupDeleteGroupWindow(d, w);
if (group) {
group->windows = (CompWindow **) realloc(group->windows, sizeof(CompWindow *) * (group->nWins + 1));
group->windows[group->nWins] = w;
group->nWins++;
gw->group = group;
gw->inGroup = TRUE;
} else {
GroupSelection *g = malloc(sizeof(GroupSelection));
g->windows = (CompWindow **) calloc(1, sizeof(CompWindow *));
g->windows[0] = w;
g->nWins = 1;
g->topTab = -1;
g->prevTopTab = -1;
g->animationSteps = 0;
g->tabbed = FALSE;
g->ungroup = FALSE;
g->tabBar = NULL;
g->dx = 0;
g->dy = 0;
// glow color
srand(time(NULL));
g->color[0] = rand() % 0xFFFF;
g->color[1] = rand() % 0xFFFF;
g->color[2] = rand() % 0xFFFF;
g->color[3] = 0xFFFF;
// relink stack
if (gd->groups) {
gd->groups->prev = g;
g->next = gd->groups;
g->prev = NULL;
gd->groups = g;
} else {
g->prev = NULL;
g->next = NULL;
gd->groups = g;
}
gw->group = g;
gw->inGroup = TRUE;
}
}
/*
* groupDeleteSelectionWindow
*
*/
static void groupDeleteSelectionWindow(CompDisplay * d, CompWindow * w)
{
GROUP_DISPLAY(d);
if (gd->tmpSel.nWins > 0 && gd->tmpSel.windows) {
CompWindow **buf = gd->tmpSel.windows;
gd->tmpSel.windows = (CompWindow **) calloc(gd->tmpSel.nWins - 1, sizeof(CompWindow *));
int counter = 0;
int i;
for (i = 0; i < gd->tmpSel.nWins; i++) {
if (buf[i]->id == w->id)
continue;
gd->tmpSel.windows[counter++] = buf[i];
}
gd->tmpSel.nWins = counter;
free(buf);
}
}
/*
* groupAddWindowToSelection
*
*/
static void groupAddWindowToSelection(CompDisplay * d, CompWindow * w)
{
GROUP_DISPLAY(d);
gd->tmpSel.windows = (CompWindow **) realloc(gd->tmpSel.windows, sizeof(CompWindow *) * (gd->tmpSel.nWins + 1));
gd->tmpSel.windows[gd->tmpSel.nWins] = w;
gd->tmpSel.nWins++;
}
/*
* groupSyncWindows
*
*/
static void groupSyncWindows(GroupSelection *group)
{
int i;
for (i = 0; i < group->nWins; i++) {
CompWindow *w = group->windows[i];
syncWindowPosition(w);
}
}
/*
* groupRaiseWindows
*
*/
static void
groupRaiseWindows(CompWindow * top, GroupSelection *group)
{
int i;
for (i = 0; i < group->nWins; i++) {
CompWindow *w = group->windows[i];
if (w->id == top->id)
continue;
restackWindowBelow(w, top);
}
}
/*
* groupScreenInitOptions
*
*/
static void groupScreenInitOptions(GroupScreen * gs)
{
CompOption *o;
int i;
o = &gs->opt[GROUP_SCREEN_OPTION_TYPES];
o->name = "mask";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Window Types");
o->longDesc = N_("The types of windows which will be grouped");
o->type = CompOptionTypeList;
o->value.list.type = CompOptionTypeString;
o->value.list.nValue = N_WIN_TYPE;
o->value.list.value = malloc(sizeof(CompOptionValue) * N_WIN_TYPE);
for (i = 0; i < N_WIN_TYPE; i++) {
o->value.list.value[i].s = strdup(groupDefaultTypes[i]);
o->rest.s.string = (char **) windowTypeString;
o->rest.s.nString = nWindowTypeString;
}
gs->wMask = compWindowTypeMaskFromStringList(&o->value);
o = &gs->opt[GROUP_SCREEN_OPTION_OPACITY];
o->name = "opacity";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Opacity");
o->longDesc = N_("Opacity of selected windows");
o->type = CompOptionTypeInt;
o->value.i = GROUP_OPACITY_DEFAULT;
o->rest.i.min = GROUP_OPACITY_MIN;
o->rest.i.max = GROUP_OPACITY_MAX;
o = &gs->opt[GROUP_SCREEN_OPTION_SATURATION];
o->name = "saturation";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Saturation");
o->longDesc = N_("Saturation of selected windows");
o->type = CompOptionTypeInt;
o->value.i = GROUP_SATURATION_DEFAULT;
o->rest.i.min = GROUP_SATURATION_MIN;
o->rest.i.max = GROUP_SATURATION_MAX;
o = &gs->opt[GROUP_SCREEN_OPTION_BRIGHTNESS];
o->name = "brightness";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Brightness");
o->longDesc = N_("Brightness of selected windows");
o->type = CompOptionTypeInt;
o->value.i = GROUP_BRIGHTNESS_DEFAULT;
o->rest.i.min = GROUP_BRIGHTNESS_MIN;
o->rest.i.max = GROUP_BRIGHTNESS_MAX;
o = &gs->opt[GROUP_SCREEN_OPTION_TOLERANCE];
o->name = "tolerance";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Tolerance");
o->longDesc = N_("Tolerance of the seletion.");
o->type = CompOptionTypeInt;
o->value.i = GROUP_TOLERANCE_DEFAULT;
o->rest.i.min = GROUP_TOLERANCE_MIN;
o->rest.i.max = GROUP_TOLERANCE_MAX;
o = &gs->opt[GROUP_SCREEN_OPTION_STEPS];
o->name = "steps";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Steps");
o->longDesc =
N_("The animation steps that are needed for animation.");
o->type = CompOptionTypeInt;
o->value.i = GROUP_STEPS_DEFAULT;
o->rest.i.min = GROUP_STEPS_MIN;
o->rest.i.max = GROUP_STEPS_MAX;
o = &gs->opt[GROUP_SCREEN_OPTION_THUMB_SIZE];
o->name = "thumb_size";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Thumb Size");
o->longDesc =
N_("The size of the window thumbs in the tab bar.");
o->type = CompOptionTypeInt;
o->value.i = GROUP_THUMB_SIZE_DEFAULT;
o->rest.i.min = GROUP_THUMB_SIZE_MIN;
o->rest.i.max = GROUP_THUMB_SIZE_MAX;
o = &gs->opt[GROUP_SCREEN_OPTION_BORDER_WIDTH];
o->name = "broder_width";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Border Width");
o->longDesc =
N_("The width of the border around the tab bar.");
o->type = CompOptionTypeInt;
o->value.i = GROUP_BORDER_WIDTH_DEFAULT;
o->rest.i.min = GROUP_BORDER_WIDTH_MIN;
o->rest.i.max = GROUP_BORDER_WIDTH_MAX;
o = &gs->opt[GROUP_SCREEN_OPTION_BORDER_RADIUS];
o->name = "broder_radius";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Border Radius");
o->longDesc =
N_("The radius for the edges of the tab bar.");
o->type = CompOptionTypeInt;
o->value.i = GROUP_BORDER_RADIUS_DEFAULT;
o->rest.i.min = GROUP_BORDER_RADIUS_MIN;
o->rest.i.max = GROUP_BORDER_RADIUS_MAX;
o = &gs->opt[GROUP_SCREEN_OPTION_MOVE];
o->name = "move";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Move every window in the group");
o->longDesc = N_("If one window in the group gets moved, "
"every other window in the group gets moved as well.");
o->type = CompOptionTypeBool;
o->value.b = GROUP_MOVE_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_RESIZE];
o->name = "resize";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Resize every window in the group");
o->longDesc = N_("If one window in the group gets resized, "
"every other window in the group gets resized as well.");
o->type = CompOptionTypeBool;
o->value.b = GROUP_RESIZE_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_RAISE];
o->name = "raise";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Raise every window in the group");
o->longDesc = N_("If one window in the group gets selected, "
"every window in the group gets raised.");
o->type = CompOptionTypeBool;
o->value.b = GROUP_RAISE_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_AUTO_GROUP];
o->name = "auto_group";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Group the windows after selection");
o->longDesc = N_("If you have selected your windows,"
"this automatically groups them. "
"(Doesn't work with selection mode 'normal')");
o->type = CompOptionTypeBool;
o->value.b = GROUP_AUTO_GROUP_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_AUTO_UNGROUP];
o->name = "auto_ungroup";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc =
N_("Ungroup the windows if only one window is left");
o->longDesc =
N_
("If there is only 1 window in the group left, it will be ungrouped.");
o->type = CompOptionTypeBool;
o->value.b = GROUP_AUTO_UNGROUP_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_RELATIVE_DISTANCE];
o->name = "relative_distance";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Compute distance relative");
o->longDesc =
N_
("The distance between the windows is computed relative to the window size. "
"This allows you to have windows staying next to eachother.");
o->type = CompOptionTypeBool;
o->value.b = GROUP_RELATIVE_DISTANCE_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_SELECTION_COLOR];
o->name = "fill_color";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Selection Color");
o->longDesc = N_("Fill color of the selection.");
o->type = CompOptionTypeColor;
o->value.c[0] = GROUP_COLOR_SELECTION_RED_DEFAULT;
o->value.c[1] = GROUP_COLOR_SELECTION_GREEN_DEFAULT;
o->value.c[2] = GROUP_COLOR_SELECTION_BLUE_DEFAULT;
o->value.c[3] = GROUP_COLOR_SELECTION_ALPHA_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_LINE_COLOR];
o->name = "line_color";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Line Color");
o->longDesc = N_("Line color of the selection.");
o->type = CompOptionTypeColor;
o->value.c[0] = GROUP_COLOR_LINE_RED_DEFAULT;
o->value.c[1] = GROUP_COLOR_LINE_GREEN_DEFAULT;
o->value.c[2] = GROUP_COLOR_LINE_BLUE_DEFAULT;
o->value.c[3] = GROUP_COLOR_LINE_ALPHA_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_TAB_FILL_COLOR];
o->name = "tab_color";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Tab Color");
o->longDesc = N_("Fill color of the tab bar.");
o->type = CompOptionTypeColor;
o->value.c[0] = GROUP_COLOR_TAB_FILL_RED_DEFAULT;
o->value.c[1] = GROUP_COLOR_TAB_FILL_GREEN_DEFAULT;
o->value.c[2] = GROUP_COLOR_TAB_FILL_BLUE_DEFAULT;
o->value.c[3] = GROUP_COLOR_TAB_FILL_ALPHA_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_TAB_BORDER_COLOR];
o->name = "border_color";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Tab Border Color");
o->longDesc = N_("Border color of the tab bar.");
o->type = CompOptionTypeColor;
o->value.c[0] = GROUP_COLOR_TAB_BORDER_RED_DEFAULT;
o->value.c[1] = GROUP_COLOR_TAB_BORDER_GREEN_DEFAULT;
o->value.c[2] = GROUP_COLOR_TAB_BORDER_BLUE_DEFAULT;
o->value.c[3] = GROUP_COLOR_TAB_BORDER_ALPHA_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_TAB_CREATE_MIPMAPS];
o->name = "mipmaps";
o->shortDesc = N_("create mipmaps for thumbnails.");
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->longDesc = N_("Create mipmaps for thumbnails in the tab-bar.");
o->type = CompOptionTypeBool;
o->value.b = GROUP_TAB_CREATE_MIPMAPS_DEFAULT;
o = &gs->opt[GROUP_SCREEN_OPTION_GLOW];
o->name = "glow";
o->shortDesc = N_("Enable Glow");
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->longDesc = N_("Enable grouped window glowing.");
o->type = CompOptionTypeBool;
o->value.b = GROUP_GLOW_DEFAULT;
}
/*
* groupGetScreenOptions
*
*/
static CompOption *groupGetScreenOptions(CompScreen * s, int *count)
{
if (s) {
GROUP_SCREEN(s);
*count = NUM_OPTIONS(gs);
return gs->opt;
} else {
GroupScreen *gs = malloc(sizeof(GroupScreen));
groupScreenInitOptions(gs);
*count = NUM_OPTIONS(gs);
return gs->opt;
}
}
/*
* groupSetScreenOption
*
*/
static Bool
groupSetScreenOption(CompScreen * s, char *name, CompOptionValue * value)
{
CompOption *o;
int index;
GROUP_SCREEN(s);
o = compFindOption(gs->opt, NUM_OPTIONS(gs), name, &index);
if (!o)
return FALSE;
switch (index) {
case GROUP_SCREEN_OPTION_TYPES:
if (compSetOptionList(o, value)) {
gs->wMask =
compWindowTypeMaskFromStringList(&o->value);
return TRUE;
}
break;
case GROUP_SCREEN_OPTION_SELECTION_COLOR:
case GROUP_SCREEN_OPTION_LINE_COLOR:
case GROUP_SCREEN_OPTION_TAB_FILL_COLOR:
case GROUP_SCREEN_OPTION_TAB_BORDER_COLOR:
if (compSetColorOption(o, value)) {
return TRUE;
}
break;
case GROUP_SCREEN_OPTION_OPACITY:
case GROUP_SCREEN_OPTION_BRIGHTNESS:
case GROUP_SCREEN_OPTION_SATURATION:
case GROUP_SCREEN_OPTION_TOLERANCE:
case GROUP_SCREEN_OPTION_STEPS:
case GROUP_SCREEN_OPTION_THUMB_SIZE:
case GROUP_SCREEN_OPTION_BORDER_WIDTH:
case GROUP_SCREEN_OPTION_BORDER_RADIUS:
if (compSetIntOption(o, value)) {
return TRUE;
}
break;
case GROUP_SCREEN_OPTION_GLOW:
case GROUP_SCREEN_OPTION_MOVE:
case GROUP_SCREEN_OPTION_RESIZE:
case GROUP_SCREEN_OPTION_RAISE:
case GROUP_SCREEN_OPTION_AUTO_UNGROUP:
case GROUP_SCREEN_OPTION_AUTO_GROUP:
case GROUP_SCREEN_OPTION_RELATIVE_DISTANCE:
case GROUP_SCREEN_OPTION_TAB_CREATE_MIPMAPS:
if (compSetBoolOption(o, value)) {
return TRUE;
}
break;
default:
break;
}
return FALSE;
}
/*
* groupSelectWindow
*
*/
static void groupSelectWindow(CompDisplay * d, CompWindow * w)
{
GROUP_DISPLAY(d);
GROUP_SCREEN(w->screen);
GROUP_WINDOW(w);
// select singe window
if ((gs->wMask & w->type) &&
!w->invisible && !gw->inSelection && !gw->inGroup) {
groupAddWindowToSelection(d, w);
gw->inSelection = TRUE;
addWindowDamage(w);
}
// unselect single window
else if ((gs->wMask & w->type) &&
!w->invisible && gw->inSelection && !gw->inGroup) {
groupDeleteSelectionWindow(d, w);
gw->inSelection = FALSE;
addWindowDamage(w);
}
// select group
else if ((gs->wMask & w->type) &&
!w->invisible && !gw->inSelection && gw->inGroup) {
int i;
for (i = 0; i < gw->group->nWins; i++) {
CompWindow *cw = gw->group->windows[i];
GROUP_WINDOW(cw);
groupAddWindowToSelection(d, cw);
gw->inSelection = TRUE;
addWindowDamage(cw);
}
}
// Unselect group
else if ((gs->wMask & w->type) &&
!w->invisible && gw->inSelection && gw->inGroup) {
GroupSelection *group = gw->group;
CompWindow **buf = gd->tmpSel.windows;
gd->tmpSel.windows = (CompWindow **) calloc(gd->tmpSel.nWins - gw->group->nWins, sizeof(CompWindow *));
int counter = 0;
int i;
for (i = 0; i < gd->tmpSel.nWins; i++) {
CompWindow *cw = buf[i];
GROUP_WINDOW(cw);
if (gw->inGroup
&& gw->group == group) {
gw->inSelection = FALSE;
addWindowDamage(cw);
continue;
}
gd->tmpSel.windows[counter++] = buf[i];
}
gd->tmpSel.nWins = counter;
free(buf);
}
}
/*
* groupSelectSingle
*
*/
static Bool
groupSelectSingle(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompWindow *w = (CompWindow *) findWindowAtDisplay(d, d->activeWindow);
if (w)
groupSelectWindow(d, w);
return TRUE;
}
/*
* groupSelect
*
*/
static Bool
groupSelect(CompDisplay * d, CompAction * action, CompActionState state,
CompOption * option, int nOption)
{
CompWindow *w = (CompWindow *) findWindowAtDisplay(d, d->activeWindow);
if (!w)
return FALSE;
GROUP_SCREEN(w->screen);
if (!gs->grab) {
if (otherScreenGrabExist(w->screen, "group", 0))
return FALSE;
if (!gs->grabIndex)
gs->grabIndex =
pushScreenGrab(w->screen, None, "group");
if (state & CompActionStateInitKey)
action->state |= CompActionStateTermKey;
if (state & CompActionStateInitButton)
action->state |= CompActionStateTermButton;
gs->x1 = gs->x2 = d->pointerX;
gs->y1 = gs->y2 = d->pointerY;
gs->grab = TRUE;
}
return TRUE;
}
/*
* groupGroupWindows - pre-definition for groupSelectTerminate
*
*/
static Bool
groupGroupWindows(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option, int nOption);
/*
* groupSelectTerminate
*
*/
static Bool
groupSelectTerminate(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option,
int nOption)
{
CompScreen *s;
Window xid;
xid = getIntOptionNamed(option, nOption, "root", 0);
for (s = d->screens; s; s = s->next) {
if (xid && s->root != xid)
continue;
break;
}
if (s) {
GROUP_SCREEN(s);
if (gs->grab) {
if (gs->grabIndex) {
removeScreenGrab(s, gs->grabIndex, NULL);
gs->grabIndex = 0;
}
if (gs->x1 != gs->x2 && gs->y1 != gs->y2) {
REGION reg;
reg.rects = ®.extents;
reg.numRects = 1;
reg.extents.x1 = MIN(gs->x1, gs->x2) - 1;
reg.extents.y1 = MIN(gs->y1, gs->y2) - 1;
reg.extents.x2 = MAX(gs->x1, gs->x2) + 1;
reg.extents.y2 = MAX(gs->y1, gs->y2) + 1;
damageScreenRegion(s, ®);
int count;
CompWindow **ws = groupFindWindowsInRegion(s, reg, &count);
if (ws) {
// select windows
int i;
for (i = 0; i < count; i++) {
CompWindow *cw = ws[i];
groupSelectWindow(d, cw);
}
if (gs->opt[GROUP_SCREEN_OPTION_AUTO_GROUP].value.b) {
groupGroupWindows(d, NULL, 0, NULL, 0);
}
free(ws);
}
}
gs->grab = FALSE;
}
}
action->state &=
~(CompActionStateTermKey | CompActionStateTermButton);
return FALSE;
}
/*
* groupGroupWindows
*
*/
static Bool
groupGroupWindows(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
GROUP_DISPLAY(d);
if (gd->tmpSel.nWins > 0) {
int i;
CompWindow *cw;
// we need to do one first to get the pointer of a new group
cw = gd->tmpSel.windows[0];
groupAddWindowToGroup(d, cw, NULL);
GROUP_WINDOW (cw);
gw->inSelection = FALSE;
damageScreen(cw->screen);
GroupSelection *group = gw->group;
for (i = 1; i < gd->tmpSel.nWins; i++) {
cw = gd->tmpSel.windows[i];
GROUP_WINDOW(cw);
groupAddWindowToGroup(d, cw, group);
gw->inSelection = FALSE;
damageScreen(cw->screen);
}
// exit selection
free(gd->tmpSel.windows);
gd->tmpSel.windows = NULL;
gd->tmpSel.nWins = 0;
}
return FALSE;
}
/*
* groupUnGroupWindows
*
*/
static Bool
groupUnGroupWindows(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option,
int nOption)
{
CompWindow *cw = findWindowAtDisplay(d, d->activeWindow);
if (!cw)
return FALSE;
GROUP_WINDOW(cw);
GROUP_SCREEN(cw->screen);
if (gw->inGroup) {
groupDeleteGroup(d, gw->group);
if (gs->opt[GROUP_SCREEN_OPTION_GLOW].value.b)
damageScreen(cw->screen);
}
return FALSE;
}
/*
* groupInitTab
*
*/
static Bool
groupInitTab(CompDisplay * d, CompAction * action, CompActionState state,
CompOption * option, int nOption)
{
CompWindow *w = findWindowAtDisplay(d, d->activeWindow);
if (!w)
return FALSE;
GROUP_WINDOW(w);
if (!gw->inGroup)
return FALSE;
if (gw->group->tabbed) {
groupUntabGroup(d, gw->group);
} else {
groupTabGroup(w);
}
return TRUE;
}
#define LEFT TRUE
#define RIGHT FALSE
/*
* groupChangeTab
*
*/
static Bool
groupChangeTab(CompDisplay * d, Bool direction)
{
//TODO: return better values... :P
//
CompWindow *w = findWindowAtDisplay(d, d->activeWindow);
if (!w)
return TRUE;
GROUP_WINDOW(w);
if (!gw->inGroup || !gw->group->tabbed || gw->group->topTab == -1)
return TRUE;
gw->group->prevTopTab = gw->group->topTab;
if(direction == RIGHT)
gw->group->topTab++;
else
gw->group->topTab--;
if(gw->group->topTab == gw->group->nWins)
gw->group->topTab = 0;
else if(gw->group->topTab == -1)
gw->group->topTab = gw->group->nWins - 1;
return TRUE;
}
/*
* groupChangeTabLeft
*
*/
static Bool
groupChangeTabLeft(CompDisplay * d, CompAction * action, CompActionState state,
CompOption * option, int nOption)
{
return groupChangeTab(d, LEFT);
}
/*
* groupChangeTabRight
*
*/
static Bool
groupChangeTabRight(CompDisplay * d, CompAction * action, CompActionState state,
CompOption * option, int nOption)
{
return groupChangeTab(d, RIGHT);
}
/*
* groupRemoveWindow
*
*/
static Bool
groupRemoveWindow(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompWindow *cw = findWindowAtDisplay(d, d->activeWindow);
if (!cw)
return FALSE;
GROUP_WINDOW(cw);
if (gw->inGroup)
groupDeleteGroupWindow(d, cw);
return FALSE;
}
/*
* groupCloseWindows
*
*/
static Bool
groupCloseWindows(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompWindow *w = findWindowAtDisplay(d, d->activeWindow);
if (!w)
return FALSE;
GROUP_WINDOW(w);
if (gw->inGroup) {
int nWins = gw->group->nWins;
int i;
for (i = 0; i < nWins; i++) {
CompWindow *cw = gw->group->windows[i];
closeWindow(cw, getCurrentTimeFromDisplay(d));
}
}
return FALSE;
}
/*
* groupMinimizeWindows
*
*/
static Bool
groupMinimizeWindows(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option,
int nOption)
{
CompWindow *w = findWindowAtDisplay(d, d->activeWindow);
if (!w)
return FALSE;
GROUP_WINDOW(w);
if (gw->inGroup) {
int nWins = gw->group->nWins;
int i;
for (i = 0; i < nWins; i++) {
CompWindow *cw = gw->group->windows[i];
minimizeWindow(cw);
}
}
return FALSE;
}
/*
* groupSetIgnore
*
*/
static Bool
groupSetIgnore(CompDisplay * d, CompAction * action, CompActionState state,
CompOption * option, int nOption)
{
GROUP_DISPLAY(d);
gd->ignoreMode = TRUE;
if (state & CompActionStateInitKey)
action->state |= CompActionStateTermKey;
return FALSE;
}
/*
* groupUnsetIgnore
*
*/
static Bool
groupUnsetIgnore(CompDisplay * d, CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
GROUP_DISPLAY(d);
gd->ignoreMode = FALSE;
action->state &= ~CompActionStateTermKey;
return FALSE;
}
/*
* groupHandleMotionEvent - pre-definition for groupHandleEvent
*
*/
static void groupHandleMotionEvent(CompScreen * s, int xRoot, int yRoot);
/*
* groupHandleEvent
*
*/
static void groupHandleEvent(CompDisplay * d, XEvent * event)
{
GROUP_DISPLAY(d);
switch (event->type) {
case MotionNotify:
{
CompScreen *s = findScreenAtDisplay(d, event->xmotion.root);
if (s)
groupHandleMotionEvent(s, d->pointerX, d->pointerY);
break;
}
case ButtonRelease:
// update windows
if (event->xbutton.button == 1) {
if (gd->inAction && gd->lastActiveGroup) {
groupSyncWindows(gd->lastActiveGroup);
gd->lastActiveGroup = NULL;
gd->inAction = FALSE;
}
}
break;
case UnmapNotify:
{
CompWindow *w = findWindowAtDisplay(d, event->xunmap.window);
if (!w)
break;
GROUP_WINDOW(w);
// close event
if (gw->inGroup && !w->pendingUnmaps) {
groupDeleteGroupWindow(d, w);
damageScreen(w->screen);
}
break;
}
default:
break;
}
UNWRAP(gd, d, handleEvent);
(*d->handleEvent) (d, event);
WRAP(gd, d, handleEvent, groupHandleEvent);
switch (event->type) {
case PropertyNotify:
// focus event
if (event->xproperty.atom == d->winActiveAtom) {
if (!gd->inAction) {
CompWindow *w = (CompWindow *) findWindowAtDisplay(d, d->activeWindow);
if (!w)
break;
GROUP_WINDOW(w);
GROUP_SCREEN(w->screen);
if (gw->inGroup &&
!gw->group->tabbed &&
!IPCS_GetBoolND(IPCS_OBJECT(w->screen->display), "SCALE_INIT", FALSE) &&
gs->opt[GROUP_SCREEN_OPTION_RAISE].value.b) {
groupRaiseWindows(w, gw->group);
} else if(gw->inGroup && gw->group->tabbed) {
focusWindow(TOP_TAB(gw->group));
moveInputFocusToWindow(TOP_TAB(gw->group));
}
}
}
break;
default:
break;
}
}
/*
* groupWindowResizeNotify
*
*/
static void groupWindowResizeNotify(CompWindow * w)
{
GROUP_SCREEN(w->screen);
GROUP_DISPLAY(w->screen->display);
GROUP_WINDOW(w);
UNWRAP(gs, w->screen, windowResizeNotify);
(*w->screen->windowResizeNotify) (w);
WRAP(gs, w->screen, windowResizeNotify, groupWindowResizeNotify);
if (gw->inGroup && !gd->ignoreMode && !gs->ignoreCallback &&
gs->opt[GROUP_SCREEN_OPTION_RESIZE].value.b) {
int rw = WIN_WIDTH(w) - gw->oldWidth;
int rh = WIN_HEIGHT(w) - gw->oldHeight;
int rx = WIN_X(w) - gw->oldX;
int ry = WIN_Y(w) - gw->oldY;
int i;
for (i = 0; i < gw->group->nWins; i++) {
CompWindow *cw = gw->group->windows[i];
if (!cw)
continue;
if (cw->id != w->id) {
int nx = 0;
int ny = 0;
if (gs->opt[GROUP_SCREEN_OPTION_RELATIVE_DISTANCE].value.b) {
int distX = WIN_X(cw) - gw->oldX;
int distY = WIN_Y(cw) - gw->oldY;
int ndistX = distX * ((float) WIN_WIDTH (w) / (float) gw->oldWidth);
int ndistY = distY * ((float) WIN_HEIGHT(w) / (float) gw->oldHeight);
nx = WIN_X(w) + ndistX;
ny = WIN_Y(w) + ndistY;
} else {
nx = WIN_X(cw) + rx;
ny = WIN_Y(cw) + ry;
}
int nwidth = WIN_WIDTH(cw) + rw;
int nheight = WIN_HEIGHT(cw) + rh;
XWindowChanges xwc;
xwc.x = nx;
xwc.y = ny;
xwc.width = nwidth;
xwc.height = nheight;
configureXWindow(cw, CWX | CWY | CWWidth |CWHeight, &xwc);
groupEnqueueResizeNotify (cw->screen, cw, nx, ny, nwidth, nheight, WIN_BORDER(cw));
}
}
gd->lastActiveGroup = gw->group;
gd->inAction = TRUE;
}
groupUpdatePosBuffer(w, WIN_X(w), WIN_Y(w), WIN_WIDTH(w), WIN_HEIGHT(w));
}
static void
groupWindowGrabNotify(CompWindow * w,
int x, int y, unsigned int state, unsigned int mask)
{
GROUP_SCREEN(w->screen);
GROUP_DISPLAY(w->screen->display);
GROUP_WINDOW(w);
if (gw->inGroup && !gd->ignoreMode && !gs->ignoreCallback) {
int i;
for (i = 0; i < gw->group->nWins; i++) {
CompWindow *cw = gw->group->windows[i];
if (!cw)
continue;
if (cw->id != w->id) {
groupEnqueueGrabNotify (cw->screen, cw, x, y, state, mask);
}
}
}
UNWRAP(gs, w->screen, windowGrabNotify);
(*w->screen->windowGrabNotify) (w, x, y, state, mask);
WRAP(gs, w->screen, windowGrabNotify, groupWindowGrabNotify);
}
static void groupWindowUngrabNotify(CompWindow * w)
{
GROUP_SCREEN(w->screen);
GROUP_DISPLAY(w->screen->display);
GROUP_WINDOW(w);
if (gw->inGroup && !gd->ignoreMode && !gs->ignoreCallback) {
int i;
for (i = 0; i < gw->group->nWins; i++) {
CompWindow *cw = gw->group->windows[i];
if (!cw)
continue;
if (cw->id != w->id) {
groupEnqueueUngrabNotify (cw->screen, cw);
}
}
}
UNWRAP(gs, w->screen, windowUngrabNotify);
(*w->screen->windowUngrabNotify) (w);
WRAP(gs, w->screen, windowUngrabNotify, groupWindowUngrabNotify);
}
/*
* groupHandleChanges
*
*/
static void
groupHandleChanges(CompScreen* s)
{
int i;
GROUP_SCREEN(s);
GROUP_DISPLAY(s->display);
GroupSelection *group;
CompWindow* w;
gs->ignoreCallback = TRUE;
for(group = gd->groups; group; group = group->next)
{
// Ungroup
if (group->prev)
{
if (group->prev->ungroup && !group->prev->animationSteps)
groupDeleteGroup(s->display, group->prev);
}
if (!group->next) {
if (group->ungroup && !group->animationSteps) {
groupDeleteGroup(s->display, group);
break;
}
}
if (group->topTab == group->prevTopTab)
continue;
if (group->animationSteps == 0)
{
if (group->prevTopTab == -1) // Tab
{
for(i = 0; i < group->nWins; i++)
{
if (i == group->topTab)
continue;
w = group->windows[i];
moveWindow(w, w->screen->width, 0, FALSE, FALSE);
syncWindowPosition(w);
groupUpdatePosBuffer(w, WIN_X(w), WIN_Y(w), WIN_WIDTH(w), WIN_HEIGHT(w));
groupAddSkipMasks(w);
}
group->prevTopTab = group->topTab;
group->dx = 0;
group->dy = 0;
}
else if(group->topTab != -1) // Change Tab
{
CompWindow* topTab = TOP_TAB(group);
CompWindow* prevTopTab = PREV_TOP_TAB(group);
moveWindow(topTab, group->dx - topTab->screen->width, group->dy, FALSE, FALSE);
syncWindowPosition(topTab);
groupUpdatePosBuffer(topTab, WIN_X(topTab), WIN_Y(topTab),
WIN_WIDTH(topTab), WIN_HEIGHT(topTab));
groupRemoveSkipMasks(topTab);
activateWindow (topTab);
moveWindow(prevTopTab, prevTopTab->screen->width, 0, FALSE, FALSE);
syncWindowPosition(prevTopTab);
groupUpdatePosBuffer(prevTopTab, WIN_X(prevTopTab), WIN_Y(prevTopTab),
WIN_WIDTH(prevTopTab), WIN_HEIGHT(prevTopTab));
groupAddSkipMasks(prevTopTab);
group->prevTopTab = group->topTab;
group->dx = 0;
group->dy = 0;
}
}
else
{
// Untab
if (group->topTab == -1)
{
for(i = 0; i < group->nWins; i++) {
w = group->windows[i];
if(i == group->prevTopTab)
continue;
moveWindow(w, group->dx - w->screen->width, group->dy, FALSE, FALSE);
syncWindowPosition(w);
groupUpdatePosBuffer(w, WIN_X(w), WIN_Y(w), WIN_WIDTH(w), WIN_HEIGHT(w));
groupRemoveSkipMasks(w);
}
group->prevTopTab = group->topTab;
group->dx = 0;
group->dy = 0;
}
}
}
gs->ignoreCallback = FALSE;
}
/*
* groupDrawTabAnimation
*
*/
static void groupDrawTabAnimation(CompScreen * s)
{
GROUP_DISPLAY(s->display);
int stepX, stepY;
int i;
GroupSelection *group;
for(group = gd->groups; group; group = group->next)
{
if(!group->animationSteps)
continue;
for(i = 0; i < group->nWins; i++)
{
CompWindow *cw = group->windows[i];
if( i == group->topTab || i == group->prevTopTab)
continue;
if (!cw)
continue;
GROUP_WINDOW(cw);
stepX = (gw->destinationX - WIN_X(cw)) / group->animationSteps;
stepY = (gw->destinationY - WIN_Y(cw)) / group->animationSteps;
moveWindow(cw, stepX, stepY, TRUE, FALSE);
}
group->animationSteps--;
groupSyncWindows(group);
}
}
/*
* groupTabBarVertices
*
*/
static void
groupTabBarVertices(CompScreen *s, int x, int y, int width, int height)
{
GROUP_SCREEN(s);
GROUP_DISPLAY(s->display);
int i;
int border_radius = gs->opt[GROUP_SCREEN_OPTION_BORDER_RADIUS].value.i;
for (i = 0; i < NUM_CORNER_POINTS; i++)
glVertex2f(border_radius * gd->cornerPointsX[i] + x +
width - border_radius,
-border_radius * gd->cornerPointsY[i] +
border_radius + y);
for (i = NUM_CORNER_POINTS - 1; i >= 0; i--)
glVertex2f(-border_radius * gd->cornerPointsX[i] + x +
border_radius,
-border_radius * gd->cornerPointsY[i] +
border_radius + y);
for (i = 0; i < NUM_CORNER_POINTS; i++)
glVertex2f(-border_radius * gd->cornerPointsX[i] + x +
border_radius,
border_radius * gd->cornerPointsY[i] + y +
height - border_radius);
for (i = NUM_CORNER_POINTS - 1; i >= 0; i--)
glVertex2f(border_radius * gd->cornerPointsX[i] + x +
width - border_radius,
border_radius * gd->cornerPointsY[i] + y +
height - border_radius);
}
/*
* groupPaintThumb - taken from switcher and modified for tab bar
*
*/
static void groupPaintThumb(GroupSelection *group, GroupTabBarSlot *slot)
{
CompWindow *w = slot->window;
CompWindow *topTab = TOP_TAB(group);
int tw, th, tx, ty;
tw = slot->width;
th = slot->height;
tx = slot->rx + group->tabBar->rx + WIN_X(topTab);
ty = slot->ry + group->tabBar->ry + WIN_Y(topTab);
WindowPaintAttrib sAttrib = w->lastPaint;
if (w->mapNum) {
if (WIN_WIDTH(w) > tw)
sAttrib.xScale = (float) tw / WIN_WIDTH(w);
else
sAttrib.xScale = 1.0f;
if (WIN_HEIGHT(w) > th)
sAttrib.yScale = (float) tw / WIN_HEIGHT(w);
else
sAttrib.yScale = 1.0f;
if (sAttrib.xScale < sAttrib.yScale)
sAttrib.yScale = sAttrib.xScale;
else
sAttrib.xScale = sAttrib.yScale;
sAttrib.xTranslate = tx - w->attrib.x;
sAttrib.yTranslate = ty - w->attrib.y;
(w->screen->drawWindow) (w, &sAttrib, getInfiniteRegion(),
PAINT_WINDOW_TRANSFORMED_MASK);
addWindowDamage(w);
}
}
/*
* groupPaintTabBar
*
*/
static void groupPaintTabBar(GroupSelection * group)
{
if(group->topTab < 0 ||
!group->tabBar->visible)
return;
CompWindow *topTab = group->windows[group->topTab];
CompScreen *s = topTab->screen;
GROUP_SCREEN(s);
if (VIEWPORT(topTab->attrib.x, s))
return;
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_BLEND);
int x1, x2, y1, y2, width, height;
width = group->tabBar->width;
height = group->tabBar->height;
x1 = group->tabBar->rx + WIN_X(topTab);
y1 = group->tabBar->ry + WIN_Y(topTab);
x2 = x1 + width;
y2 = y1 + height;
glColor4usv(gs->opt[GROUP_SCREEN_OPTION_TAB_FILL_COLOR].value.c);
glBegin(GL_POLYGON);
groupTabBarVertices(s, x1, y1, width, height);
glEnd();
glColor4usv(gs->opt[GROUP_SCREEN_OPTION_TAB_BORDER_COLOR].value.c);
glBegin(GL_LINE_LOOP);
groupTabBarVertices(s, x1, y1, width, height);
glEnd();
glColor4usv(defaultColor);
glDisable(GL_BLEND);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// draw thumbs
if(gs->opt[GROUP_SCREEN_OPTION_TAB_CREATE_MIPMAPS].value.b)
s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;
GroupTabBarSlot *slot;
for(slot = group->tabBar->slots; slot; slot = slot->next)
{
groupPaintThumb(group, slot);
}
addWindowDamage(topTab);
}
/*
* groupPreparePaintScreen
*
*/
static void groupPreparePaintScreen(CompScreen * s, int msSinceLastPaint)
{
GROUP_SCREEN(s);
UNWRAP(gs, s, preparePaintScreen);
(*s->preparePaintScreen) (s, msSinceLastPaint);
WRAP(gs, s, preparePaintScreen, groupPreparePaintScreen);
groupDequeueMoveNotifies (s);
groupDequeueResizeNotifies (s);
groupDequeueGrabNotifies (s);
groupDequeueUngrabNotifies (s);
groupHandleChanges(s);
groupDrawTabAnimation(s);
}
/*
* groupPaintScreen
*
*/
static Bool
groupPaintScreen(CompScreen * s,
const ScreenPaintAttrib * sAttrib,
Region region, int output, unsigned int mask)
{
GROUP_SCREEN(s);
GROUP_DISPLAY(s->display);
Bool status;
gs->wasTransformed = FALSE;
// if we draw groups use BTF
if (gd->groups) {
mask &= ~PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK;
mask |= PAINT_SCREEN_ORDER_BACK_TO_FRONT_MASK;
}
UNWRAP(gs, s, paintScreen);
status = (*s->paintScreen) (s, sAttrib, region, output, mask);
WRAP(gs, s, paintScreen, groupPaintScreen);
if (status && gs->grab && !gs->wasTransformed) {
int x1, x2, y1, y2;
x1 = MIN(gs->x1, gs->x2);
y1 = MIN(gs->y1, gs->y2);
x2 = MAX(gs->x1, gs->x2);
y2 = MAX(gs->y1, gs->y2);
if (gs->grabIndex) {
glPushMatrix();
prepareXCoords(s, output, -DEFAULT_Z_CAMERA);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_BLEND);
glColor4usv(gs->opt[GROUP_SCREEN_OPTION_SELECTION_COLOR].value.c);
glRecti(x1, y2, x2, y1);
glColor4usv(gs->opt[GROUP_SCREEN_OPTION_LINE_COLOR].value.c);
glBegin(GL_LINE_LOOP);
glVertex2i(x1, y1);
glVertex2i(x2, y1);
glVertex2i(x2, y2);
glVertex2i(x1, y2);
glEnd();
glColor4usv(defaultColor);
glDisable(GL_BLEND);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glPopMatrix();
}
}
return status;
}
/*
* groupPaintTransformedScreen
*
*/
static void
groupPaintTransformedScreen(CompScreen * s, const ScreenPaintAttrib * sa,
Region region, int output, unsigned int mask)
{
GROUP_SCREEN(s);
UNWRAP(gs, s, paintTransformedScreen);
(*s->paintTransformedScreen) (s, sa, region, output, mask);
WRAP(gs, s, paintTransformedScreen, groupPaintTransformedScreen);
if (gs->grab) {
gs->wasTransformed = TRUE;
int x1, x2, y1, y2;
x1 = MIN(gs->x1, gs->x2);
y1 = MIN(gs->y1, gs->y2);
x2 = MAX(gs->x1, gs->x2);
y2 = MAX(gs->y1, gs->y2);
if (gs->grabIndex) {
glPushMatrix();
glLoadIdentity();
(s->applyScreenTransform) (s, sa, output);
prepareXCoords(s, output, -sa->zTranslate);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_BLEND);
glColor4usv(gs->opt[GROUP_SCREEN_OPTION_SELECTION_COLOR].value.c);
glRecti(x1, y2, x2, y1);
glColor4usv(gs->opt[GROUP_SCREEN_OPTION_LINE_COLOR].value.c);
glBegin(GL_LINE_LOOP);
glVertex2i(x1, y1);
glVertex2i(x2, y1);
glVertex2i(x2, y2);
glVertex2i(x1, y2);
glEnd();
glColor4usv(defaultColor);
glDisable(GL_BLEND);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glPopMatrix();
}
}
}
/*
* groupDrawWindow
*
*/
static Bool
groupDrawWindow(CompWindow * w,
const WindowPaintAttrib * attrib,
Region region, unsigned int mask)
{
Bool status;
GROUP_WINDOW(w);
GROUP_SCREEN(w->screen);
if (!(mask & PAINT_WINDOW_SOLID_MASK)) {
if (gw->inGroup && gs->opt[GROUP_SCREEN_OPTION_GLOW].value.b) {
if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
region = getInfiniteRegion();
if (region->numRects) {
REGION box;
CompMatrix matrix;
box.rects = &box.extents;
box.numRects = 1;
w->vCount = 0;
int glowBorderX = 12;
int glowBorderY = 12;
int glowWidth = 128;
int glowHeight = 128;
int overlapX, overlapY;
overlapX = (WIN_WIDTH(w) * glowBorderX) / (glowWidth - glowBorderX * 2);
overlapY = (WIN_HEIGHT(w) * glowBorderY) / (glowHeight - glowBorderY * 2);
box.extents.x1 = WIN_X(w) - w->input.left - overlapX;
box.extents.y1 = WIN_Y(w) - w->input.top - overlapY;
box.extents.x2 = WIN_X(w) + w->input.right + WIN_WIDTH(w) + overlapX;
box.extents.y2 = WIN_Y(w) + w->input.right + WIN_HEIGHT(w) + overlapY;
matrix = gs->glowTexture.matrix;
matrix.xx = 1.0f / (box.extents.x2 - box.extents.x1);
matrix.yy = -1.0f / (box.extents.y2 - box.extents.y1);
matrix.x0 -= (box.extents.x1 * matrix.xx);
matrix.y0 -= (box.extents.y1 * matrix.yy);
if (box.extents.x1 < box.extents.x2 &&
box.extents.y1 < box.extents.y2) {
(*w->screen->addWindowGeometry) (w, &matrix, 1, &box, region);
}
}
if (w->vCount) {
WindowPaintAttrib wAttrib;
wAttrib.opacity = attrib->opacity;
wAttrib.saturation = COLOR;
wAttrib.brightness = BRIGHT;
wAttrib.opacity = gw->group->color[3];
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glColor4us(gw->group->color[0], gw->group->color[1],
gw->group->color[2],
((gw->group->color[3] * wAttrib.opacity) / 0xFFFF));
(*w->screen->drawWindowTexture) (w, &gs->glowTexture, &wAttrib,
mask | PAINT_WINDOW_TRANSLUCENT_MASK);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
screenTexEnvMode (w->screen, GL_REPLACE);
glColor4usv(defaultColor);
}
}
}
UNWRAP(gs, w->screen, drawWindow);
status = (*w->screen->drawWindow) (w, attrib, region, mask);
if (gw->inGroup &&
gw->group->tabbed && gw->group->topTab != -1 &&
TOP_TAB(gw->group)->id == w->id) {
groupPaintTabBar(gw->group);
}
WRAP(gs, w->screen, drawWindow, groupDrawWindow);
return status;
}
/*
* groupPaintWindow
*
*/
static Bool
groupPaintWindow(CompWindow * w,
const WindowPaintAttrib * attrib,
Region region, unsigned int mask)
{
Bool status;
GROUP_SCREEN(w->screen);
GROUP_WINDOW(w);
WindowPaintAttrib gAttrib = *attrib;
if (gw->inSelection) {
int opacity = gs->opt[GROUP_SCREEN_OPTION_OPACITY].value.i;
int saturation = gs->opt[GROUP_SCREEN_OPTION_SATURATION].value.i;
int brightness = gs->opt[GROUP_SCREEN_OPTION_BRIGHTNESS].value.i;
opacity = OPAQUE * opacity / 100;
saturation = COLOR * saturation / 100;
brightness = BRIGHT * brightness / 100;
gAttrib.opacity = opacity;
gAttrib.saturation = saturation;
gAttrib.brightness = brightness;
}
if (gw->inGroup &&
gw->group->tabbed && gw->group->topTab != -1 &&
!gw->group->animationSteps &&
TOP_TAB(gw->group)->id != w->id) {
return TRUE;
}
UNWRAP(gs, w->screen, paintWindow);
status = (*w->screen->paintWindow) (w, &gAttrib, region, mask);
WRAP(gs, w->screen, paintWindow, groupPaintWindow);
return status;
}
/*
* groupHandleMotionEvent
*
*/
static void groupHandleMotionEvent(CompScreen * s, int xRoot, int yRoot)
{
GROUP_SCREEN(s);
if (gs->grab && gs->grabIndex) {
REGION reg;
reg.rects = ®.extents;
reg.numRects = 1;
reg.extents.x1 = MIN(gs->x1, gs->x2) - 1;
reg.extents.y1 = MIN(gs->y1, gs->y2) - 1;
reg.extents.x2 = MAX(gs->x1, gs->x2) + 1;
reg.extents.y2 = MAX(gs->y1, gs->y2) + 1;
damageScreenRegion(s, ®);
gs->x2 = xRoot;
gs->y2 = yRoot;
reg.extents.x1 = MIN(gs->x1, gs->x2) - 1;
reg.extents.y1 = MIN(gs->y1, gs->y2) - 1;
reg.extents.x2 = MAX(gs->x1, gs->x2) + 1;
reg.extents.y2 = MAX(gs->y1, gs->y2) + 1;
damageScreenRegion(s, ®);
}
}
/*
* reloadCornerPoints
*
*/
static void initCornerPoints(GroupDisplay * gd)
{
int i;
float angle;
for (i = 0; i < NUM_CORNER_POINTS; i++) {
angle = (PI / 2) * ((float) i / (NUM_CORNER_POINTS - 1));
gd->cornerPointsY[i] = sin(angle);
gd->cornerPointsX[i] = cos(angle);
}
}
/*
* groupDisplayInitOptions
*
*/
static void groupDisplayInitOptions(GroupDisplay * gd)
{
CompOption *o;
o = &gd->opt[GROUP_DISPLAY_OPTION_SELECT];
o->name = "select";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Select");
o->longDesc = N_("The key for starting selecting windows.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupSelect;
o->value.action.terminate = groupSelectTerminate;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitButton;
o->value.action.type = CompBindingTypeButton;
o->value.action.button.modifiers = GROUP_SELECT_MODIFIERS_DEFAULT;
o->value.action.button.button = GROUP_SELECT_BUTTON_DEFAULT;
o = &gd->opt[GROUP_DISPLAY_OPTION_SELECT_SINGLE];
o->name = "select_single";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Select single window");
o->longDesc = N_("The key for selecting the current window.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupSelectSingle;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers =
GROUP_SELECT_SINGLE_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_SELECT_SINGLE_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_GROUPING];
o->name = "group";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Group");
o->longDesc = N_("The key for grouing windows.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupGroupWindows;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers = GROUP_GROUPING_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_GROUPING_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_UNGROUPING];
o->name = "ungroup";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Ungroup");
o->longDesc = N_("The key for ungrouing windows.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupUnGroupWindows;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers = GROUP_UNGROUPING_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_UNGROUPING_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_TABMODE];
o->name = "tabmode";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Tab");
o->longDesc = N_("The key for entering the tab mode.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupInitTab;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers = GROUP_TABMODE_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_TABMODE_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_CHANGE_TAB_LEFT];
o->name = "change_tab_left";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Change Tab");
o->longDesc = N_("The key for changing the tab to the left.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupChangeTabLeft;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers = GROUP_CHANGE_TAB_LEFT_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_CHANGE_TAB_LEFT_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_CHANGE_TAB_RIGHT];
o->name = "change_tab_right";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Change Tab");
o->longDesc = N_("The key for changing the tab to the right.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupChangeTabRight;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers = GROUP_CHANGE_TAB_RIGHT_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_CHANGE_TAB_RIGHT_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_REMOVEING];
o->name = "remove";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Remove Window");
o->longDesc = N_("The key for removing the selected window.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupRemoveWindow;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers = GROUP_REMOVEING_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_REMOVEING_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_CLOSEING];
o->name = "close";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Close Windows");
o->longDesc = N_("The key for closing all windows in the group.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupCloseWindows;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers = GROUP_CLOSEING_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_CLOSEING_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_MINIMIZEING];
o->name = "minimize";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Minimize Windows");
o->longDesc =
N_("The key for minimizeing all windows in the group.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupMinimizeWindows;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers =
GROUP_MINIMIZEING_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_MINIMIZEING_KEY_DEFAULT);
o = &gd->opt[GROUP_DISPLAY_OPTION_IGNORE];
o->name = "ignore";
o->group = N_("");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Ignore Group");
o->longDesc = N_("The key for ignoring the group."
"If this key is pressed you can resize/move a single"
"window in the group.");
o->type = CompOptionTypeAction;
o->value.action.initiate = groupSetIgnore;
o->value.action.terminate = groupUnsetIgnore;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.state = CompActionStateInitKey;
o->value.action.type = CompBindingTypeKey;
o->value.action.key.modifiers = GROUP_IGNORE_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(GROUP_IGNORE_KEY_DEFAULT);
}
/*
* groupGetDisplayOptions
*
*/
static CompOption *groupGetDisplayOptions(CompDisplay * d, int *count)
{
if (d) {
GROUP_DISPLAY(d);
*count = NUM_OPTIONS(gd);
return gd->opt;
} else {
GroupDisplay *gd = malloc(sizeof(GroupDisplay));
groupDisplayInitOptions(gd);
*count = NUM_OPTIONS(gd);
return gd->opt;
}
}
/*
* groupSetDisplayOption
*
*/
static Bool
groupSetDisplayOption(CompDisplay * d, char *name, CompOptionValue * value)
{
CompOption *o;
int index;
GROUP_DISPLAY(d);
o = compFindOption(gd->opt, NUM_OPTIONS(gd), name, &index);
if (!o)
return FALSE;
switch (index) {
case GROUP_DISPLAY_OPTION_SELECT:
case GROUP_DISPLAY_OPTION_SELECT_SINGLE:
case GROUP_DISPLAY_OPTION_GROUPING:
case GROUP_DISPLAY_OPTION_UNGROUPING:
case GROUP_DISPLAY_OPTION_REMOVEING:
case GROUP_DISPLAY_OPTION_CLOSEING:
case GROUP_DISPLAY_OPTION_MINIMIZEING:
case GROUP_DISPLAY_OPTION_IGNORE:
case GROUP_DISPLAY_OPTION_TABMODE:
case GROUP_DISPLAY_OPTION_CHANGE_TAB_LEFT:
case GROUP_DISPLAY_OPTION_CHANGE_TAB_RIGHT:
if (setDisplayAction(d, o, value))
return TRUE;
break;
default:
break;
}
return FALSE;
}
/*
* groupInitDisplay
*
*/
static Bool groupInitDisplay(CompPlugin * p, CompDisplay * d)
{
GroupDisplay *gd;
gd = malloc(sizeof(GroupDisplay));
if (!gd)
return FALSE;
gd->screenPrivateIndex = allocateScreenPrivateIndex(d);
if (gd->screenPrivateIndex < 0) {
free(gd);
return FALSE;
}
gd->inAction = FALSE;
gd->lastActiveGroup = NULL;
//gd->animatedGroup = -1;
gd->tmpSel.windows = NULL;
gd->tmpSel.nWins = 0;
gd->groups = NULL;
//gd->revGroups = NULL;
gd->ignoreMode = FALSE;
groupDisplayInitOptions(gd);
initCornerPoints(gd);
WRAP(gd, d, handleEvent, groupHandleEvent);
d->privates[displayPrivateIndex].ptr = gd;
return TRUE;
}
/*
* groupFiniDisplay
*
*/
static void groupFiniDisplay(CompPlugin * p, CompDisplay * d)
{
GROUP_DISPLAY(d);
if (gd->groups) {
GroupSelection *group;
GroupSelection *following;
for(group = gd->groups; group; group = following)
{
if (group) {
following = group->next;
free(group);
} else {
following = 0;
}
}
}
freeScreenPrivateIndex(d, gd->screenPrivateIndex);
UNWRAP(gd, d, handleEvent);
free(gd);
}
/*
* groupInitScreen
*
*/
static Bool groupInitScreen(CompPlugin * p, CompScreen * s)
{
GroupScreen *gs;
GROUP_DISPLAY(s->display);
gs = malloc(sizeof(GroupScreen));
if (!gs)
return FALSE;
gs->windowPrivateIndex = allocateWindowPrivateIndex(s);
if (gs->windowPrivateIndex < 0) {
free(gs);
return FALSE;
}
groupScreenInitOptions(gs);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_SELECT].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_SELECT_SINGLE].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_GROUPING].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_UNGROUPING].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_REMOVEING].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_CLOSEING].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_MINIMIZEING].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_TABMODE].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_CHANGE_TAB_LEFT].value.action);
addScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_CHANGE_TAB_RIGHT].value.action);
WRAP(gs, s, windowMoveNotify, groupWindowMoveNotify);
WRAP(gs, s, windowResizeNotify, groupWindowResizeNotify);
WRAP(gs, s, preparePaintScreen, groupPreparePaintScreen);
WRAP(gs, s, paintScreen, groupPaintScreen);
WRAP(gs, s, drawWindow, groupDrawWindow);
WRAP(gs, s, paintWindow, groupPaintWindow);
WRAP(gs, s, paintTransformedScreen, groupPaintTransformedScreen);
WRAP(gs, s, windowGrabNotify, groupWindowGrabNotify);
WRAP(gs, s, windowUngrabNotify, groupWindowUngrabNotify);
s->privates[gd->screenPrivateIndex].ptr = gs;
gs->grab = FALSE;
gs->grabIndex = 0;
gs->ignoreCallback = FALSE;
gs->pendingMoves = NULL;
gs->pendingResizes = NULL;
gs->pendingGrabs = NULL;
gs->pendingUngrabs = NULL;
// bind texture for glow
initTexture (s, &gs->glowTexture);
imageToTexture (s, &gs->glowTexture, (char*) glowTex, 128, 128);
return TRUE;
}
/*
* groupFiniScreen
*
*/
static void groupFiniScreen(CompPlugin * p, CompScreen * s)
{
GROUP_SCREEN(s);
GROUP_DISPLAY(s->display);
freeWindowPrivateIndex(s, gs->windowPrivateIndex);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_SELECT].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_SELECT_SINGLE].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_GROUPING].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_UNGROUPING].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_REMOVEING].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_CLOSEING].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_MINIMIZEING].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_TABMODE].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_CHANGE_TAB_LEFT].value.action);
removeScreenAction(s, &gd->opt[GROUP_DISPLAY_OPTION_CHANGE_TAB_RIGHT].value.action);
UNWRAP(gs, s, windowMoveNotify);
UNWRAP(gs, s, windowResizeNotify);
UNWRAP(gs, s, preparePaintScreen);
UNWRAP(gs, s, paintScreen);
UNWRAP(gs, s, drawWindow);
UNWRAP(gs, s, paintWindow);
UNWRAP(gs, s, paintTransformedScreen);
UNWRAP(gs, s, windowGrabNotify);
UNWRAP(gs, s, windowUngrabNotify);
free(gs);
}
/*
* groupInitWindow
*
*/
static Bool groupInitWindow(CompPlugin * p, CompWindow * w)
{
GroupWindow *gw;
GROUP_SCREEN(w->screen);
gw = malloc(sizeof(GroupWindow));
if (!gw)
return FALSE;
gw->inGroup = FALSE;
gw->inSelection = FALSE;
// for move/resize
gw->oldWidth = WIN_WIDTH(w);
gw->oldHeight = WIN_HEIGHT(w);
gw->oldX = WIN_X(w);
gw->oldY = WIN_Y(w);
// for tab
gw->slot = NULL;
gw->orgPosX = 0;
gw->orgPosY = 0;
gw->destinationX = 0;
gw->destinationY = 0;
//gw->offscreen = FALSE;
w->privates[gs->windowPrivateIndex].ptr = gw;
return TRUE;
}
/*
* groupFiniWindow
*
*/
static void groupFiniWindow(CompPlugin * p, CompWindow * w)
{
GROUP_WINDOW(w);
free(gw);
}
/*
* groupInit
*
*/
static Bool groupInit(CompPlugin * p)
{
displayPrivateIndex = allocateDisplayPrivateIndex();
if (displayPrivateIndex < 0)
return FALSE;
return TRUE;
}
/*
* groupFini
*
*/
static void groupFini(CompPlugin * p)
{
if (displayPrivateIndex >= 0)
freeDisplayPrivateIndex(displayPrivateIndex);
}
/*
* groupDeps array
*
*/
CompPluginDep groupDeps[] = {
{CompPluginRuleBefore, "cube"}
};
/*
* groupVTable
*
*/
CompPluginVTable groupVTable = {
"group",
N_("Window Grouper"),
N_("With this plugin you can group windows."),
groupInit,
groupFini,
groupInitDisplay,
groupFiniDisplay,
groupInitScreen,
groupFiniScreen,
groupInitWindow,
groupFiniWindow,
groupGetDisplayOptions,
groupSetDisplayOption,
groupGetScreenOptions,
groupSetScreenOption,
groupDeps,
sizeof(groupDeps) / sizeof(groupDeps[0]),
0,
0,
BERYL_ABI_INFO,
"beryl-plugins"
};
/*
* getCompPluginInfo
*
*/
CompPluginVTable *getCompPluginInfo(void)
{
return &groupVTable;
}