All pastes #283522 Raw Edit

Miscellany

public text v1 · immutable
#283522 ·published 2006-12-18 12:22 UTC
rendered paste body
#include "group.h"

/*
 * groupHandleChanges
 *
 */
void
groupHandleChanges(CompScreen* s)
{
	int i;
	GROUP_DISPLAY(s->display);
	GROUP_SCREEN(s);

	GroupSelection *group;
	CompWindow* w;

	for(group = gd->groups; group; group = group ? group->next : NULL)
	{
		// 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);
				group = NULL;
				continue;
			}
		}

		if (group->animated && group->animationSteps != 0)
		{
			if(group->topTab == -1 && group->prevTopTab != -1)	//Untab
			{
				//no need to commit changes, we already did in groupUntabGroup.
			
				for(i = 0; i < group->nWins; i++) {
					w = group->windows[i];
					GROUP_WINDOW(w);

					if(i == group->prevTopTab || !gw->animate)
						continue;
					
					//groupEnqueueMoveNotify (w, group->dx - w->screen->width, group->dy, TRUE);
					
					gs->queued = TRUE;
					moveWindow (w, group->dx - w->screen->width, group->dy, FALSE, FALSE);
					syncWindowPosition(w);
					gs->queued = FALSE;
					
					groupRemoveSkipMasks(w);
				}

				group->prevTopTab = group->topTab;
				
				group->x = 0;
				group->y = 0;
				group->dx = 0;
				group->dy = 0;

				if (gs->opt[GROUP_SCREEN_OPTION_GLOW].value.b)
					damageScreen (s);
			}
		}

		else if (group->animated && group->animationSteps == 0)
		{
			if(group->topTab != -1)	//Tab + addWindowToGroup
			{
				COMMIT_XY_CHANGES(group);
			
				for(i = 0; i < group->nWins; i++)
				{
					w = group->windows[i];
					GROUP_WINDOW(w);

					if (i == group->topTab || !gw->animate)
						continue;
					
					//groupEnqueueMoveNotify (w, w->screen->width - group->dx, -group->dy, TRUE);
					
					gs->queued = TRUE;
					moveWindow (w, w->screen->width - group->dx, -group->dy, FALSE, FALSE);
					syncWindowPosition(w);
					gs->queued = FALSE;
					
					groupAddSkipMasks(w);
				}

				group->prevTopTab = group->topTab;

				if (gs->opt[GROUP_SCREEN_OPTION_GLOW].value.b)
					damageScreen (s);
			}

			//Not animated any more.
			group->animated = FALSE;

			for(i = 0; i < group->nWins; i++)
			{
				w = group->windows[i];
				GROUP_WINDOW(w);

				gw->animate = FALSE;
			}
		}

		else
		{
			if(group->topTab != group->prevTopTab && group->topTab != -1 && group->prevTopTab != -1)	//Change Tab
			{
				group->dx += PREV_TOP_TAB(group)->attrib.x - group->x;
				group->dy += PREV_TOP_TAB(group)->attrib.y - group->y;
			
				CompWindow* topTab = TOP_TAB(group);
				CompWindow* prevTopTab = PREV_TOP_TAB(group);
				
				//groupEnqueueMoveNotify (topTab, group->dx - topTab->screen->width, group->dy, TRUE);
				gs->queued = TRUE;
				moveWindow (topTab, group->dx - topTab->screen->width, group->dy, FALSE, FALSE);
				syncWindowPosition(topTab);
				gs->queued = FALSE;
				
				groupRemoveSkipMasks(topTab);

				activateWindow (topTab);
				
				//groupEnqueueMoveNotify (prevTopTab, prevTopTab->screen->width - group->dx, -group->dy, TRUE);
				gs->queued = TRUE;
				moveWindow (prevTopTab, prevTopTab->screen->width - group->dx, -group->dy, FALSE, FALSE);
				syncWindowPosition(prevTopTab);
				gs->queued = FALSE;
				
				groupAddSkipMasks(prevTopTab);
				
				group->x = TOP_TAB(group)->attrib.x;
				group->y = TOP_TAB(group)->attrib.y;
				
				group->prevTopTab = group->topTab;

				if (gs->opt[GROUP_SCREEN_OPTION_GLOW].value.b)
					damageScreen (s);
			}
		}
	}
}

/*
 * groupDrawTabAnimation
 *
 */
void groupDrawTabAnimation(CompScreen * s)
{
	GROUP_DISPLAY(s->display);
	GROUP_SCREEN(s);

	int stepX, stepY;
	int i;
	
	GroupSelection  *group;
	for(group = gd->groups; group; group = group->next)
	{
		if(!group->animated || group->animationSteps == 0)
			continue;

		for(i = 0; i < group->nWins; i++)
		{
			CompWindow *cw = group->windows[i];

			if(!cw || i == group->topTab || i == group->prevTopTab)
				continue;

			GROUP_WINDOW(cw);

			if (!gw->animate)
				continue;

			stepX = (gw->destinationX - WIN_X(cw)) / group->animationSteps;
			stepY = (gw->destinationY - WIN_Y(cw)) / group->animationSteps;

			gs->queued = TRUE;
			moveWindow (cw, stepX, stepY, FALSE, FALSE);
			gs->queued = FALSE;
			if (gs->opt[GROUP_SCREEN_OPTION_GLOW].value.b)
				damageScreen (s);
		}

		group->animationSteps--;

		groupSyncWindows(group);
	}
}

/*
 * groupTabBarVertices
 *
 */
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
 *
 */
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;

	// animate fade
	if (group->tabBar->animationSteps)
	{
		if (group->tabBar->visible) // fade in
			sAttrib.opacity = sAttrib.opacity / group->tabBar->animationSteps;
		else // fade out
			sAttrib.opacity = sAttrib.opacity - (sAttrib.opacity / group->tabBar->animationSteps);
	}

	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
 *
 */
void groupPaintTabBar(GroupSelection * group)
{
	if (group->topTab < 0 ||
	   (!group->tabBar->visible && !group->tabBar->animationSteps))
		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;

	// fade
	int alpha_fill = gs->opt[GROUP_SCREEN_OPTION_TAB_FILL_COLOR].value.c[3];
	int alpha_line = gs->opt[GROUP_SCREEN_OPTION_TAB_BORDER_COLOR].value.c[3];
	if (group->tabBar->animationSteps) {
		// fade in
		if (group->tabBar->visible) { 
			alpha_fill  = alpha_fill  / group->tabBar->animationSteps;
			alpha_line  = alpha_line  / group->tabBar->animationSteps;
		// fade out
		} else {
			alpha_fill  = alpha_fill  - (alpha_fill / group->tabBar->animationSteps);
			alpha_line  = alpha_line  - (alpha_line / group->tabBar->animationSteps);
		}
	}

	//glColor4usv(gs->opt[GROUP_SCREEN_OPTION_TAB_FILL_COLOR].value.c);
	glColor4us(gs->opt[GROUP_SCREEN_OPTION_TAB_FILL_COLOR].value.c[0],
			   gs->opt[GROUP_SCREEN_OPTION_TAB_FILL_COLOR].value.c[1],
			   gs->opt[GROUP_SCREEN_OPTION_TAB_FILL_COLOR].value.c[2],
			   alpha_fill);
	glBegin(GL_POLYGON);
	groupTabBarVertices(s, x1, y1, width, height);
	glEnd();

	//glColor4usv(gs->opt[GROUP_SCREEN_OPTION_TAB_BORDER_COLOR].value.c);
	glColor4us(gs->opt[GROUP_SCREEN_OPTION_TAB_BORDER_COLOR].value.c[0],
			   gs->opt[GROUP_SCREEN_OPTION_TAB_BORDER_COLOR].value.c[0],
			   gs->opt[GROUP_SCREEN_OPTION_TAB_BORDER_COLOR].value.c[0],
			   alpha_line);
	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);
	}

	if (group->tabBar->animationSteps)
		group->tabBar->animationSteps--;

	addWindowDamage(topTab);
}

/*
 * groupPreparePaintScreen
 *
 */
void groupPreparePaintScreen(CompScreen * s, int msSinceLastPaint)
{
	GROUP_SCREEN(s);

	UNWRAP(gs, s, preparePaintScreen);
	(*s->preparePaintScreen) (s, msSinceLastPaint);
	WRAP(gs, s, preparePaintScreen, groupPreparePaintScreen);

	groupHandleChanges(s);
	groupDrawTabAnimation(s);

	groupDequeueMoveNotifies (s);
	groupDequeueResizeNotifies (s);
	groupDequeueGrabNotifies (s);
	groupDequeueUngrabNotifies (s);
}

/*
 * groupPaintScreen
 *
 */
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
 *
 */
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();
		}
	}
}

void groupRecomputeGlow (CompScreen *s)
{
	GROUP_SCREEN(s);
	CompWindow *w;

	for (w = s->windows; w; w = w->next)
		groupComputeGlowQuads (w, &gs->glowTexture.matrix);
}

void
groupComputeGlowQuads (CompWindow *w, CompMatrix *matrix)
{
	GROUP_WINDOW(w);
	GROUP_SCREEN(w->screen);

	BoxRec *box;
	CompMatrix *quadMatrix;

	if (gs->opt[GROUP_SCREEN_OPTION_GLOW].value.b) {
		if (!gw->glowQuads)
			gw->glowQuads = malloc (NUM_GLOWQUADS * sizeof(GlowQuad));
		if (!gw->glowQuads)
			return;
	} else {
		if (gw->glowQuads) {
			free (gw->glowQuads);
			gw->glowQuads = NULL;
		}
		return;
	}

	int glowSize = gs->opt[GROUP_SCREEN_OPTION_GLOW_SIZE].value.i;
	int glowOffset = (glowSize * glowTextureProperties[gs->glowType].glowOffset /
		      glowTextureProperties[gs->glowType].textureSize) + 1; 

	/* Top left corner */
	box = &gw->glowQuads[GLOWQUAD_TOPLEFT].box;
	gw->glowQuads[GLOWQUAD_TOPLEFT].matrix = *matrix;
	quadMatrix = &gw->glowQuads[GLOWQUAD_TOPLEFT].matrix;

	box->x1 = WIN_X(w) - w->input.left - glowSize + glowOffset;
	box->y1 = WIN_Y(w) - w->input.top - glowSize + glowOffset;
	box->x2 = MIN(WIN_X(w) - w->input.left + glowOffset, 
		WIN_X(w) - w->input.left + ((WIN_WIDTH(w) + w->input.left + w->input.right) / 2));
	box->y2 = MIN(WIN_Y(w) - w->input.top + glowOffset,
		WIN_Y(w) - w->input.top + ((WIN_HEIGHT(w) + w->input.top + w->input.bottom) / 2));

	quadMatrix->xx = 1.0f / glowSize;
	quadMatrix->yy = -1.0f / glowSize;
	quadMatrix->x0 = -(box->x1 * quadMatrix->xx);
	quadMatrix->y0 = 1.0 -(box->y1 * quadMatrix->yy);

	/* Top right corner */
	box = &gw->glowQuads[GLOWQUAD_TOPRIGHT].box;
	gw->glowQuads[GLOWQUAD_TOPRIGHT].matrix = *matrix;
	quadMatrix = &gw->glowQuads[GLOWQUAD_TOPRIGHT].matrix;

	box->x1 = MAX(WIN_X(w) + WIN_WIDTH(w) + w->input.right - glowOffset,
		WIN_X(w) - w->input.left + ((WIN_WIDTH(w) + w->input.left + w->input.right) / 2));
	box->y1 = WIN_Y(w) - w->input.top - glowSize + glowOffset;
	box->x2 = WIN_X(w) + WIN_WIDTH(w) + w->input.right + glowSize - glowOffset;
	box->y2 = MIN(WIN_Y(w) - w->input.top + glowOffset,
		WIN_Y(w) - w->input.top + ((WIN_HEIGHT(w) + w->input.top + w->input.bottom) / 2));

	quadMatrix->xx = -1.0f / glowSize;
	quadMatrix->yy = -1.0f / glowSize;
	quadMatrix->x0 = 1.0 - (box->x1 * quadMatrix->xx);
	quadMatrix->y0 = 1.0 - (box->y1 * quadMatrix->yy);

	/* Bottom left corner */
	box = &gw->glowQuads[GLOWQUAD_BOTTOMLEFT].box;
	gw->glowQuads[GLOWQUAD_BOTTOMLEFT].matrix = *matrix;
	quadMatrix = &gw->glowQuads[GLOWQUAD_BOTTOMLEFT].matrix;

	box->x1 = WIN_X(w) - w->input.left - glowSize + glowOffset;
	box->y1 = MAX(WIN_Y(w) + WIN_HEIGHT(w) + w->input.bottom - glowOffset,
		WIN_Y(w) - w->input.top + ((WIN_HEIGHT(w) + w->input.top + w->input.bottom) / 2));
	box->x2 = MIN(WIN_X(w) - w->input.left + glowOffset, 
		WIN_X(w) - w->input.left + ((WIN_WIDTH(w) + w->input.left + w->input.right) / 2));
	box->y2 = WIN_Y(w) + WIN_HEIGHT(w) + w->input.bottom + glowSize - glowOffset;

	quadMatrix->xx = 1.0f / glowSize;
	quadMatrix->yy = 1.0f / glowSize;
	quadMatrix->x0 = -(box->x1 * quadMatrix->xx);
	quadMatrix->y0 = -(box->y1 * quadMatrix->yy);

	/* Bottom right corner */
	box = &gw->glowQuads[GLOWQUAD_BOTTOMRIGHT].box;
	gw->glowQuads[GLOWQUAD_BOTTOMRIGHT].matrix = *matrix;
	quadMatrix = &gw->glowQuads[GLOWQUAD_BOTTOMRIGHT].matrix;

	box->x1 = MAX(WIN_X(w) + WIN_WIDTH(w) + w->input.right - glowOffset, 
		WIN_X(w) - w->input.left + ((WIN_WIDTH(w) + w->input.left + w->input.right) / 2));
	box->y1 = MAX(WIN_Y(w) + WIN_HEIGHT(w) + w->input.bottom - glowOffset,
		WIN_Y(w) - w->input.top + ((WIN_HEIGHT(w) + w->input.top + w->input.bottom) / 2));
	box->x2 = WIN_X(w) + WIN_WIDTH(w) + w->input.right + glowSize - glowOffset;
	box->y2 = WIN_Y(w) + WIN_HEIGHT(w) + w->input.bottom + glowSize - glowOffset;

	quadMatrix->xx = -1.0f / glowSize;
	quadMatrix->yy = 1.0f / glowSize;
	quadMatrix->x0 = 1.0 - (box->x1 * quadMatrix->xx);
	quadMatrix->y0 = -(box->y1 * quadMatrix->yy);

	/* Top edge */
	box = &gw->glowQuads[GLOWQUAD_TOP].box;
	gw->glowQuads[GLOWQUAD_TOP].matrix = *matrix;
	quadMatrix = &gw->glowQuads[GLOWQUAD_TOP].matrix;

	box->x1 = WIN_X(w) - w->input.left + glowOffset;
	box->y1 = WIN_Y(w) - w->input.top - glowSize + glowOffset;
	box->x2 = WIN_X(w) + WIN_WIDTH(w) + w->input.right - glowOffset;
	box->y2 = WIN_Y(w) - w->input.top + glowOffset;

	quadMatrix->xx = 0.0f;
	quadMatrix->yy = -1.0f / glowSize;
	quadMatrix->x0 = 1.0;
	quadMatrix->y0 = 1.0 - (box->y1 * quadMatrix->yy);

	/* Bottom edge */
	box = &gw->glowQuads[GLOWQUAD_BOTTOM].box;
	gw->glowQuads[GLOWQUAD_BOTTOM].matrix = *matrix;
	quadMatrix = &gw->glowQuads[GLOWQUAD_BOTTOM].matrix;

	box->x1 = WIN_X(w) - w->input.left + glowOffset;
	box->y1 = WIN_Y(w) + WIN_HEIGHT(w) + w->input.bottom - glowOffset;
	box->x2 = WIN_X(w) + WIN_WIDTH(w) + w->input.right - glowOffset;
	box->y2 = WIN_Y(w) + WIN_HEIGHT(w) + w->input.bottom + glowSize - glowOffset;

	quadMatrix->xx = 0.0f;
	quadMatrix->yy = 1.0f / glowSize;
	quadMatrix->x0 = 1.0;
	quadMatrix->y0 = -(box->y1 * quadMatrix->yy);

	/* Left edge */
	box = &gw->glowQuads[GLOWQUAD_LEFT].box;
	gw->glowQuads[GLOWQUAD_LEFT].matrix = *matrix;
	quadMatrix = &gw->glowQuads[GLOWQUAD_LEFT].matrix;

	box->x1 = WIN_X(w) - w->input.left - glowSize + glowOffset;
	box->y1 = WIN_Y(w) - w->input.top + glowOffset;
	box->x2 = WIN_X(w) - w->input.left + glowOffset;
	box->y2 = WIN_Y(w) + WIN_HEIGHT(w) + w->input.bottom - glowOffset;

	quadMatrix->xx = 1.0f / glowSize;
	quadMatrix->yy = 0.0f;
	quadMatrix->x0 = -(box->x1 * quadMatrix->xx);
	quadMatrix->y0 = 0.0;

	/* Right edge */
	box = &gw->glowQuads[GLOWQUAD_RIGHT].box;
	gw->glowQuads[GLOWQUAD_RIGHT].matrix = *matrix;
	quadMatrix = &gw->glowQuads[GLOWQUAD_RIGHT].matrix;

	box->x1 = WIN_X(w) + WIN_WIDTH(w) + w->input.right - glowOffset;
	box->y1 = WIN_Y(w) - w->input.top + glowOffset;
	box->x2 = WIN_X(w) + WIN_WIDTH(w) + w->input.right + glowSize - glowOffset;
	box->y2 = WIN_Y(w) + WIN_HEIGHT(w) + w->input.bottom - glowOffset;

	quadMatrix->xx = -1.0f / glowSize;
	quadMatrix->yy = 0.0f;
	quadMatrix->x0 = 1.0 - (box->x1 * quadMatrix->xx);
	quadMatrix->y0 = 0.0;
}

/*
 * groupDrawWindow
 *
 */
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) && gw->inGroup && gw->glowQuads) {

		if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
			region = getInfiniteRegion();

		if (region->numRects) {
			REGION box;
			int i;

			box.rects = &box.extents;
			box.numRects = 1;

			w->vCount = 0;

			for (i = 0; i < NUM_GLOWQUADS; i++) {
				box.extents = gw->glowQuads[i].box;

				if (box.extents.x1 < box.extents.x2 &&
				    box.extents.y1 < box.extents.y2) {
					(*w->screen->addWindowGeometry) (w, 
						&gw->glowQuads[i].matrix, 1, &box, region);
				}

				if (attrib->opacity != gw->oldOpacity)
					damageScreenRegion (w->screen, &box);
			}
			gw->oldOpacity = attrib->opacity;

			if (w->vCount) {
				WindowPaintAttrib wAttrib = *attrib;

				wAttrib.opacity = OPAQUE;
				wAttrib.saturation = COLOR;
				wAttrib.brightness = BRIGHT;

				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
				glColor4us(gw->group->color[0], gw->group->color[1],
					gw->group->color[2], attrib->opacity);

				/* we use PAINT_WINDOW_TRANSFORMED_MASK here to force
				   the usage of a good texture filter */
				(*w->screen->drawWindowTexture) (w, &gs->glowTexture, &wAttrib,
					mask | PAINT_WINDOW_TRANSLUCENT_MASK | PAINT_WINDOW_TRANSFORMED_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) {

		GroupTabBar *bar = gw->group->tabBar;
		Bool state = XPointInRegion(w->region,   w->screen->display->pointerX, w->screen->display->pointerY) ||
					 XPointInRegion(bar->region, w->screen->display->pointerX, w->screen->display->pointerY);
		if (state != bar->visible) { // state changed, animate
			bar->animationSteps = 20;
			bar->visible = state;
		}

    	groupPaintTabBar(gw->group);
    }

    WRAP(gs, w->screen, drawWindow, groupDrawWindow);

    return status;
}

/*
 * groupPaintWindow
 *
 */
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->inGroup &&
		gw->group->tabbed && gw->group->topTab != -1 &&
		!gw->group->animationSteps &&
		TOP_TAB(gw->group)->id != w->id) {

		return TRUE;
	}

	if (gw->inSelection) {
		int opacity = gs->opt[GROUP_SCREEN_OPTION_OPACITY].value.i;
		int saturation = gs->opt[GROUP_SCREEN_OPTION_SATURATION].value.i;
		int brightness = gs->opt[GROUP_SCREEN_OPTION_BRIGHTNESS].value.i;

		opacity = OPAQUE * opacity / 100;
		saturation = COLOR * saturation / 100;
		brightness = BRIGHT * brightness / 100;

		gAttrib.opacity = opacity;
		gAttrib.saturation = saturation;
		gAttrib.brightness = brightness;
	}

	UNWRAP(gs, w->screen, paintWindow);
	status = (*w->screen->paintWindow) (w, &gAttrib, region, mask);
	WRAP(gs, w->screen, paintWindow, groupPaintWindow);

	return status;
}

/*
 * groupHandleMotionEvent
 *
 */
void groupHandleMotionEvent(CompScreen * s, int xRoot, int yRoot)
{
	GROUP_SCREEN(s);

	if (gs->grab && gs->grabIndex) {
		REGION reg;

		reg.rects = &reg.extents;
		reg.numRects = 1;

		reg.extents.x1 = MIN(gs->x1, gs->x2) - 1;
		reg.extents.y1 = MIN(gs->y1, gs->y2) - 1;
		reg.extents.x2 = MAX(gs->x1, gs->x2) + 1;
		reg.extents.y2 = MAX(gs->y1, gs->y2) + 1;

		damageScreenRegion(s, &reg);

		gs->x2 = xRoot;
		gs->y2 = yRoot;

		reg.extents.x1 = MIN(gs->x1, gs->x2) - 1;
		reg.extents.y1 = MIN(gs->y1, gs->y2) - 1;
		reg.extents.x2 = MAX(gs->x1, gs->x2) + 1;
		reg.extents.y2 = MAX(gs->y1, gs->y2) + 1;

		damageScreenRegion(s, &reg);
	}
}

/*
 * reloadCornerPoints
 *
 */
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);
	}
}