#include "group.h"
/**
*
* Beryl group plugin
*
* selection.c
*
* Copyright : (C) 2006 by Patrick Niklaus, Roi Cohen, Danny Baumann
* Authors: Patrick Niklaus <patrick.niklaus@googlemail.com>
* Roi Cohen <roico@beryl-project.org>
* Danny Baumann <maniac@beryl-project.org>
*
*
* 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.
*
**/
/*
* groupWindowInRegion
*
*/
static Bool
groupWindowInRegion(CompWindow *w, Region src, float precision)
{
Region buf = XCreateRegion();
XIntersectRegion(w->region, src, buf);
// buf area
int i;
int area = 0;
BOX *box;
for(i = 0; i < buf->numRects; i++) {
box = &buf->rects[i];
area += (box->x2 - box->x1) * (box->y2 - box->y1); // width * height
}
XDestroyRegion(buf);
if (area >= WIN_WIDTH(w) * WIN_HEIGHT(w) * precision) {
XSubtractRegion(src, w->region, src);
return TRUE;
}
return FALSE;
}
/*
* groupFindGroupInWindows
*
*/
static Bool groupFindGroupInWindows(GroupSelection *group, CompWindow **windows, int nWins)
{
int i;
for (i = 0; i < nWins; i++) {
CompWindow *cw = windows[i];
GROUP_WINDOW(cw);
if (gw->group == group)
return TRUE;
}
return FALSE;
}
/*
* groupFindWindowsInRegion
*
*/
CompWindow **groupFindWindowsInRegion(CompScreen * s, Region reg, int *c)
{
GROUP_SCREEN(s);
float precision = gs->opt[GROUP_SCREEN_OPTION_PRECISION].value.i / 100.0f;
CompWindow **ret = NULL;
int count = 0;
CompWindow *w;
for (w = s->reverseWindows; w; w = w->prev) {
if ((gs->wMask & w->type) && !w->invisible &&
groupWindowInRegion(w, reg, precision))
{
GROUP_WINDOW(w);
if (gw->group && groupFindGroupInWindows(gw->group, ret, count))
continue;
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;
}
/*
* groupDeleteSelectionWindow
*
*/
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
*
*/
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++;
}
/*
* groupSelectWindow
*
*/
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->group) {
groupAddWindowToSelection(d, w);
gw->inSelection = TRUE;
addWindowDamage(w);
}
// unselect single window
else if ((gs->wMask & w->type) &&
!w->invisible && gw->inSelection && !gw->group) {
groupDeleteSelectionWindow(d, w);
gw->inSelection = FALSE;
addWindowDamage(w);
}
// select group
else if ((gs->wMask & w->type) &&
!w->invisible && !gw->inSelection && gw->group) {
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->group) {
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->group == group) {
gw->inSelection = FALSE;
addWindowDamage(cw);
continue;
}
gd->tmpSel.windows[counter++] = buf[i];
}
gd->tmpSel.nWins = counter;
free(buf);
}
}
/*
* groupSelectSingle
*
*/
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
*
*/
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->grabState == ScreenGrabNone) {
groupGrabScreen(w->screen, ScreenGrabSelect);
if (state & CompActionStateInitKey)
action->state |= CompActionStateTermKey;
if (state & CompActionStateInitButton)
action->state |= CompActionStateTermButton;
gs->x1 = gs->x2 = d->pointerX;
gs->y1 = gs->y2 = d->pointerY;
}
return TRUE;
}
/*
* groupSelectTerminate
*
*/
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->grabState == ScreenGrabSelect) {
groupGrabScreen(s, ScreenGrabNone);
if (gs->x1 != gs->x2 && gs->y1 != gs->y2) {
Region reg = XCreateRegion();
XRectangle rect;
rect.x = MIN(gs->x1, gs->x2) - 2;
rect.y = MIN(gs->y1, gs->y2) - 2;
rect.width = MAX(gs->x1, gs->x2) - MIN(gs->x1, gs->x2) + 4;
rect.height = MAX(gs->y1, gs->y2) - MIN(gs->y1, gs->y2) + 4;
XUnionRectWithRegion(&rect, reg, reg);
damageScreenRegion(s, reg);
int count;
CompWindow **ws = groupFindWindowsInRegion(s, reg, &count);
if (ws) {
// select windows
int i;
for (i = 0; i < count; i++) {
CompWindow *cw = ws[i];
groupSelectWindow(d, cw);
}
if (gs->opt[GROUP_SCREEN_OPTION_AUTO_GROUP].value.b) {
groupGroupWindows(d, NULL, 0, NULL, 0);
}
free(ws);
}
XDestroyRegion(reg);
}
}
}
action->state &=
~(CompActionStateTermKey | CompActionStateTermButton);
return FALSE;
}
/*
* groupDamageSelectionRect
*
*/
void
groupDamageSelectionRect(CompScreen* s, int xRoot, int yRoot)
{
GROUP_SCREEN(s);
REGION reg;
reg.rects = ®.extents;
reg.numRects = 1;
reg.extents.x1 = MIN(gs->x1, gs->x2) - 5;
reg.extents.y1 = MIN(gs->y1, gs->y2) - 5;
reg.extents.x2 = MAX(gs->x1, gs->x2) + 5;
reg.extents.y2 = MAX(gs->y1, gs->y2) + 5;
damageScreenRegion(s, ®);
gs->x2 = xRoot;
gs->y2 = yRoot;
reg.extents.x1 = MIN(gs->x1, gs->x2) - 5;
reg.extents.y1 = MIN(gs->y1, gs->y2) - 5;
reg.extents.x2 = MAX(gs->x1, gs->x2) + 5;
reg.extents.y2 = MAX(gs->y1, gs->y2) + 5;
damageScreenRegion(s, ®);
}
syntax highlighted by Code2HTML, v. 0.9.1