/**
*
* Compiz group plugin
*
* paint.c
*
* Copyright : (C) 2006-2007 by Patrick Niklaus, Roi Cohen, Danny Baumann
* Authors: Patrick Niklaus <patrick.niklaus@googlemail.com>
* Roi Cohen <roico.beryl@gmail.com>
* Danny Baumann <maniac@opencompositing.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.
*
**/
#include "group-internal.h"
/*
* groupPaintThumb - taken from switcher and modified for tab bar
*
*/
static void
groupPaintThumb (GroupSelection *group,
GroupTabBarSlot *slot,
const CompTransform *transform,
int targetOpacity)
{
CompWindow *w = slot->window;
AddWindowGeometryProc oldAddWindowGeometry;
WindowPaintAttrib wAttrib = w->paint;
int tw, th;
tw = slot->region->extents.x2 - slot->region->extents.x1;
th = slot->region->extents.y2 - slot->region->extents.y1;
/* Wrap drawWindowGeometry to make sure the general
drawWindowGeometry function is used */
oldAddWindowGeometry = w->screen->addWindowGeometry;
w->screen->addWindowGeometry = addWindowGeometry;
/* animate fade */
if (group && group->tabBar->state == PaintFadeIn)
{
wAttrib.opacity -= wAttrib.opacity * group->tabBar->animationTime /
(groupGetFadeTime (w->screen) * 1000);
}
else if (group && group->tabBar->state == PaintFadeOut)
{
wAttrib.opacity = wAttrib.opacity * group->tabBar->animationTime /
(groupGetFadeTime (w->screen) * 1000);
}
wAttrib.opacity = wAttrib.opacity * targetOpacity / OPAQUE;
if (w->mapNum)
{
FragmentAttrib fragment;
CompTransform wTransform = *transform;
int width, height;
int vx, vy;
width = w->width + w->output.left + w->output.right;
height = w->height + w->output.top + w->output.bottom;
if (width > tw)
wAttrib.xScale = (float) tw / width;
else
wAttrib.xScale = 1.0f;
if (height > th)
wAttrib.yScale = (float) tw / height;
else
wAttrib.yScale = 1.0f;
if (wAttrib.xScale < wAttrib.yScale)
wAttrib.yScale = wAttrib.xScale;
else
wAttrib.xScale = wAttrib.yScale;
/* FIXME: do some more work on the highlight on hover feature
// Highlight on hover
if (group && group->tabBar && group->tabBar->hoveredSlot == slot) {
wAttrib.saturation = 0;
wAttrib.brightness /= 1.25f;
}*/
groupGetDrawOffsetForSlot (slot, &vx, &vy);
wAttrib.xTranslate = (slot->region->extents.x1 +
slot->region->extents.x2) / 2 + vx;
wAttrib.yTranslate = slot->region->extents.y1 + vy;
initFragmentAttrib (&fragment, &wAttrib);
matrixTranslate (&wTransform,
wAttrib.xTranslate, wAttrib.yTranslate, 0.0f);
matrixScale (&wTransform, wAttrib.xScale, wAttrib.yScale, 1.0f);
matrixTranslate (&wTransform, -(WIN_X (w) + WIN_WIDTH (w) / 2),
-(WIN_Y (w) - w->output.top), 0.0f);
glPushMatrix ();
glLoadMatrixf (wTransform.m);
(*w->screen->drawWindow) (w, &wTransform, &fragment, &infiniteRegion,
PAINT_WINDOW_TRANSFORMED_MASK |
PAINT_WINDOW_TRANSLUCENT_MASK);
glPopMatrix ();
}
w->screen->addWindowGeometry = oldAddWindowGeometry;
}
/*
* groupRenderTopTabHighlight
*
*/
void
groupRenderTopTabHighlight (GroupSelection *group)
{
GroupTabBar *bar;
GroupCairoLayer *layer;
cairo_t *cr;
int width, height;
if (!group->tabBar || !HAS_TOP_WIN (group) ||
!group->tabBar->selectionLayer ||
!group->tabBar->selectionLayer->cairo)
{
return;
}
bar = group->tabBar;
width = group->topTab->region->extents.x2 -
group->topTab->region->extents.x1;
height = group->topTab->region->extents.y2 -
group->topTab->region->extents.y1;
bar->selectionLayer = groupRebuildCairoLayer (group->screen,
bar->selectionLayer,
width, height);
if (!bar->selectionLayer)
return;
layer = bar->selectionLayer;
cr = bar->selectionLayer->cairo;
/* fill */
cairo_set_line_width (cr, 2);
cairo_set_source_rgba (cr,
(group->color[0] / 65535.0f),
(group->color[1] / 65535.0f),
(group->color[2] / 65535.0f),
(group->color[3] / (65535.0f*2)));
cairo_move_to (cr, 0, 0);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill_preserve (cr);
/* outline */
cairo_set_source_rgba (cr,
(group->color[0] / 65535.0f),
(group->color[1] / 65535.0f),
(group->color[2] / 65535.0f),
(group->color[3] / 65535.0f));
cairo_stroke (cr);
imageBufferToTexture (group->screen,
&layer->texture, (char*) layer->buffer,
layer->texWidth, layer->texHeight);
}
/*
* groupRenderTabBarBackground
*
*/
void
groupRenderTabBarBackground(GroupSelection *group)
{
GroupTabBar *bar;
GroupCairoLayer *layer;
cairo_t *cr;
int width, height, radius;
int borderWidth;
float r, g, b, a;
double x0, y0, x1, y1;
if (!group->tabBar || !HAS_TOP_WIN (group) ||
!group->tabBar->bgLayer ||
!group->tabBar->bgLayer->cairo)
{
return;
}
bar = group->tabBar;
width = bar->region->extents.x2 - bar->region->extents.x1;
height = bar->region->extents.y2 - bar->region->extents.y1;
radius = groupGetBorderRadius (group->screen);
if (width > bar->bgLayer->texWidth)
width = bar->bgLayer->texWidth;
if (radius > width / 2)
radius = width / 2;
layer = bar->bgLayer;
cr = layer->cairo;
groupClearCairoLayer (layer);
borderWidth = groupGetBorderWidth (group->screen);
cairo_set_line_width (cr, borderWidth);
cairo_save (cr);
x0 = borderWidth / 2.0f;
y0 = borderWidth / 2.0f;
x1 = width - borderWidth / 2.0f;
y1 = height - borderWidth / 2.0f;
cairo_move_to (cr, x0 + radius, y0);
cairo_arc (cr, x1 - radius, y0 + radius, radius, M_PI * 1.5, M_PI * 2.0);
cairo_arc (cr, x1 - radius, y1 - radius, radius, 0.0, M_PI * 0.5);
cairo_arc (cr, x0 + radius, y1 - radius, radius, M_PI * 0.5, M_PI);
cairo_arc (cr, x0 + radius, y0 + radius, radius, M_PI, M_PI * 1.5);
cairo_close_path (cr);
switch (groupGetTabStyle (group->screen))
{
case TabStyleSimple:
{
/* base color */
r = groupGetTabBaseColorRed (group->screen) / 65535.0f;
g = groupGetTabBaseColorGreen (group->screen) / 65535.0f;
b = groupGetTabBaseColorBlue (group->screen) / 65535.0f;
a = groupGetTabBaseColorAlpha (group->screen) / 65535.0f;
cairo_set_source_rgba (cr, r, g, b, a);
cairo_fill_preserve (cr);
break;
}
case TabStyleGradient:
{
/* fill */
cairo_pattern_t *pattern;
pattern = cairo_pattern_create_linear (0, 0, width, height);
/* highlight color */
r = groupGetTabHighlightColorRed (group->screen) / 65535.0f;
g = groupGetTabHighlightColorGreen (group->screen) / 65535.0f;
b = groupGetTabHighlightColorBlue (group->screen) / 65535.0f;
a = groupGetTabHighlightColorAlpha (group->screen) / 65535.0f;
cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a);
/* base color */
r = groupGetTabBaseColorRed (group->screen) / 65535.0f;
g = groupGetTabBaseColorGreen (group->screen) / 65535.0f;
b = groupGetTabBaseColorBlue (group->screen) / 65535.0f;
a = groupGetTabBaseColorAlpha (group->screen) / 65535.0f;
cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a);
cairo_set_source (cr, pattern);
cairo_fill_preserve (cr);
cairo_pattern_destroy (pattern);
break;
}
case TabStyleGlass:
{
cairo_pattern_t *pattern;
cairo_save (cr);
/* clip width rounded rectangle */
cairo_clip (cr);
/* ===== HIGHLIGHT ===== */
/* make draw the shape for the highlight and
create a pattern for it */
cairo_rectangle (cr, 0, 0, width, height / 2);
pattern = cairo_pattern_create_linear (0, 0, 0, height);
/* highlight color */
r = groupGetTabHighlightColorRed (group->screen) / 65535.0f;
g = groupGetTabHighlightColorGreen (group->screen) / 65535.0f;
b = groupGetTabHighlightColorBlue (group->screen) / 65535.0f;
a = groupGetTabHighlightColorAlpha (group->screen) / 65535.0f;
cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a);
/* base color */
r = groupGetTabBaseColorRed (group->screen) / 65535.0f;
g = groupGetTabBaseColorGreen (group->screen) / 65535.0f;
b = groupGetTabBaseColorBlue (group->screen) / 65535.0f;
a = groupGetTabBaseColorAlpha (group->screen) / 65535.0f;
cairo_pattern_add_color_stop_rgba (pattern, 0.6f, r, g, b, a);
cairo_set_source (cr, pattern);
cairo_fill (cr);
cairo_pattern_destroy (pattern);
/* ==== SHADOW ===== */
/* make draw the shape for the show and create a pattern for it */
cairo_rectangle (cr, 0, height / 2, width, height);
pattern = cairo_pattern_create_linear (0, 0, 0, height);
/* we don't want to use a full highlight here
so we mix the colors */
r = (groupGetTabHighlightColorRed (group->screen) +
groupGetTabBaseColorRed (group->screen)) / (2 * 65535.0f);
g = (groupGetTabHighlightColorGreen (group->screen) +
groupGetTabBaseColorGreen (group->screen)) / (2 * 65535.0f);
b = (groupGetTabHighlightColorBlue (group->screen) +
groupGetTabBaseColorBlue (group->screen)) / (2 * 65535.0f);
a = (groupGetTabHighlightColorAlpha (group->screen) +
groupGetTabBaseColorAlpha (group->screen)) / (2 * 65535.0f);
cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a);
/* base color */
r = groupGetTabBaseColorRed (group->screen) / 65535.0f;
g = groupGetTabBaseColorGreen (group->screen) / 65535.0f;
b = groupGetTabBaseColorBlue (group->screen) / 65535.0f;
a = groupGetTabBaseColorAlpha (group->screen) / 65535.0f;
cairo_pattern_add_color_stop_rgba (pattern, 0.5f, r, g, b, a);
cairo_set_source (cr, pattern);
cairo_fill (cr);
cairo_pattern_destroy (pattern);
cairo_restore (cr);
/* draw shape again for the outline */
cairo_move_to (cr, x0 + radius, y0);
cairo_arc (cr, x1 - radius, y0 + radius,
radius, M_PI * 1.5, M_PI * 2.0);
cairo_arc (cr, x1 - radius, y1 - radius, radius, 0.0, M_PI * 0.5);
cairo_arc (cr, x0 + radius, y1 - radius, radius, M_PI * 0.5, M_PI);
cairo_arc (cr, x0 + radius, y0 + radius, radius, M_PI, M_PI * 1.5);
break;
}
case TabStyleMetal:
{
/* fill */
cairo_pattern_t *pattern;
pattern = cairo_pattern_create_linear (0, 0, 0, height);
/* base color #1 */
r = groupGetTabBaseColorRed (group->screen) / 65535.0f;
g = groupGetTabBaseColorGreen (group->screen) / 65535.0f;
b = groupGetTabBaseColorBlue (group->screen) / 65535.0f;
a = groupGetTabBaseColorAlpha (group->screen) / 65535.0f;
cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a);
/* highlight color */
r = groupGetTabHighlightColorRed (group->screen) / 65535.0f;
g = groupGetTabHighlightColorGreen (group->screen) / 65535.0f;
b = groupGetTabHighlightColorBlue (group->screen) / 65535.0f;
a = groupGetTabHighlightColorAlpha (group->screen) / 65535.0f;
cairo_pattern_add_color_stop_rgba (pattern, 0.55f, r, g, b, a);
/* base color #2 */
r = groupGetTabBaseColorRed (group->screen) / 65535.0f;
g = groupGetTabBaseColorGreen (group->screen) / 65535.0f;
b = groupGetTabBaseColorBlue (group->screen) / 65535.0f;
a = groupGetTabBaseColorAlpha (group->screen) / 65535.0f;
cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a);
cairo_set_source (cr, pattern);
cairo_fill_preserve (cr);
cairo_pattern_destroy (pattern);
break;
}
case TabStyleMurrina:
{
double ratio, transX;
cairo_pattern_t *pattern;
cairo_save (cr);
/* clip width rounded rectangle */
cairo_clip_preserve (cr);
/* ==== TOP ==== */
x0 = borderWidth / 2.0;
y0 = borderWidth / 2.0;
x1 = width - borderWidth / 2.0;
y1 = height - borderWidth / 2.0;
radius = (y1 - y0) / 2;
/* setup pattern */
pattern = cairo_pattern_create_linear (0, 0, 0, height);
/* we don't want to use a full highlight here
so we mix the colors */
r = (groupGetTabHighlightColorRed (group->screen) +
groupGetTabBaseColorRed (group->screen)) / (2 * 65535.0f);
g = (groupGetTabHighlightColorGreen (group->screen) +
groupGetTabBaseColorGreen (group->screen)) / (2 * 65535.0f);
b = (groupGetTabHighlightColorBlue (group->screen) +
groupGetTabBaseColorBlue (group->screen)) / (2 * 65535.0f);
a = (groupGetTabHighlightColorAlpha (group->screen) +
groupGetTabBaseColorAlpha (group->screen)) / (2 * 65535.0f);
cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a);
/* highlight color */
r = groupGetTabHighlightColorRed (group->screen) / 65535.0f;
g = groupGetTabHighlightColorGreen (group->screen) / 65535.0f;
b = groupGetTabHighlightColorBlue (group->screen) / 65535.0f;
a = groupGetTabHighlightColorAlpha (group->screen) / 65535.0f;
cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a);
cairo_set_source (cr, pattern);
cairo_fill (cr);
cairo_pattern_destroy (pattern);
/* ==== BOTTOM ===== */
x0 = borderWidth / 2.0;
y0 = borderWidth / 2.0;
x1 = width - borderWidth / 2.0;
y1 = height - borderWidth / 2.0;
radius = (y1 - y0) / 2;
ratio = (double)width / (double)height;
transX = width - (width * ratio);
cairo_move_to (cr, x1, y1);
cairo_line_to (cr, x1, y0);
if (width < height)
{
cairo_translate (cr, transX, 0);
cairo_scale (cr, ratio, 1.0);
}
cairo_arc (cr, x1 - radius, y0, radius, 0.0, M_PI * 0.5);
if (width < height)
{
cairo_scale (cr, 1.0 / ratio, 1.0);
cairo_translate (cr, -transX, 0);
cairo_scale (cr, ratio, 1.0);
}
cairo_arc_negative (cr, x0 + radius, y1, radius, M_PI * 1.5, M_PI);
cairo_close_path (cr);
/* setup pattern */
pattern = cairo_pattern_create_linear (0, 0, 0, height);
/* base color */
r = groupGetTabBaseColorRed (group->screen) / 65535.0f;
g = groupGetTabBaseColorGreen (group->screen) / 65535.0f;
b = groupGetTabBaseColorBlue (group->screen) / 65535.0f;
a = groupGetTabBaseColorAlpha (group->screen) / 65535.0f;
cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a);
/* we don't want to use a full highlight here
so we mix the colors */
r = (groupGetTabHighlightColorRed (group->screen) +
groupGetTabBaseColorRed (group->screen)) / (2 * 65535.0f);
g = (groupGetTabHighlightColorGreen (group->screen) +
groupGetTabBaseColorGreen (group->screen)) / (2 * 65535.0f);
b = (groupGetTabHighlightColorBlue (group->screen) +
groupGetTabBaseColorBlue (group->screen)) / (2 * 65535.0f);
a = (groupGetTabHighlightColorAlpha (group->screen) +
groupGetTabBaseColorAlpha (group->screen)) / (2 * 65535.0f);
cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source (cr, pattern);
cairo_fill (cr);
cairo_pattern_destroy (pattern);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_restore (cr);
/* draw shape again for the outline */
x0 = borderWidth / 2.0;
y0 = borderWidth / 2.0;
x1 = width - borderWidth / 2.0;
y1 = height - borderWidth / 2.0;
radius = groupGetBorderRadius (group->screen);
cairo_move_to (cr, x0 + radius, y0);
cairo_arc (cr, x1 - radius, y0 + radius,
radius, M_PI * 1.5, M_PI * 2.0);
cairo_arc (cr, x1 - radius, y1 - radius, radius, 0.0, M_PI * 0.5);
cairo_arc (cr, x0 + radius, y1 - radius, radius, M_PI * 0.5, M_PI);
cairo_arc (cr, x0 + radius, y0 + radius, radius, M_PI, M_PI * 1.5);
break;
}
default:
break;
}
/* outline */
r = groupGetTabBorderColorRed (group->screen) / 65535.0f;
g = groupGetTabBorderColorGreen (group->screen) / 65535.0f;
b = groupGetTabBorderColorBlue (group->screen) / 65535.0f;
a = groupGetTabBorderColorAlpha (group->screen) / 65535.0f;
cairo_set_source_rgba (cr, r, g, b, a);
if (bar->bgAnimation != AnimationNone)
cairo_stroke_preserve (cr);
else
cairo_stroke (cr);
switch (bar->bgAnimation)
{
case AnimationPulse:
{
double animationProgress;
double alpha;
animationProgress = bar->bgAnimationTime /
(groupGetPulseTime (group->screen) * 1000.0);
alpha = fabs (sin (PI * animationProgress)) * 0.75;
if (alpha <= 0)
break;
cairo_save (cr);
cairo_clip (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_XOR);
cairo_rectangle (cr, 0.0, 0.0, width, height);
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, alpha);
cairo_fill (cr);
cairo_restore (cr);
break;
}
case AnimationReflex:
{
double animationProgress;
double reflexWidth;
double posX, alpha;
cairo_pattern_t *pattern;
animationProgress = bar->bgAnimationTime /
(groupGetReflexTime (group->screen) * 1000.0);
reflexWidth = (bar->nSlots / 2.0) * 30;
posX = (width + reflexWidth * 2.0) * animationProgress;
alpha = sin (PI * animationProgress) * 0.55;
if (alpha <= 0)
break;
cairo_save (cr);
cairo_clip (cr);
pattern = cairo_pattern_create_linear (posX - reflexWidth,
0.0, posX, height);
cairo_pattern_add_color_stop_rgba (pattern,
0.0f, 1.0, 1.0, 1.0, 0.0);
cairo_pattern_add_color_stop_rgba (pattern,
0.5f, 1.0, 1.0, 1.0, alpha);
cairo_pattern_add_color_stop_rgba (pattern,
1.0f, 1.0, 1.0, 1.0, 0.0);
cairo_rectangle (cr, 0.0, 0.0, width, height);
cairo_set_source (cr, pattern);
cairo_fill (cr);
cairo_restore (cr);
break;
}
case AnimationNone:
default:
break;
}
cairo_restore (cr);
imageBufferToTexture (group->screen,
&layer->texture, (char*) layer->buffer,
layer->texWidth, layer->texHeight);
}
/*
* groupRenderWindowTitle
*
*/
void
groupRenderWindowTitle (GroupSelection *group)
{
GroupTabBar *bar;
GroupCairoLayer *layer;
void *data = NULL;
int width, height;
int stride;
CompTextAttrib textAttrib;
CompDisplay *d;
if (!group->tabBar || !HAS_TOP_WIN(group) || !group->tabBar->textLayer)
return;
bar = group->tabBar;
width = bar->region->extents.x2 - bar->region->extents.x1;
height = bar->region->extents.y2 - bar->region->extents.y1;
bar->textLayer = groupRebuildCairoLayer (group->screen,
bar->textLayer, width, height);
layer = bar->textLayer;
if (!layer)
return;
textAttrib.family = "Sans";
textAttrib.size = groupGetTabbarFontSize (group->screen);
textAttrib.style = TEXT_STYLE_BOLD;
textAttrib.color[0] = groupGetTabbarFontColorRed (group->screen);
textAttrib.color[1] = groupGetTabbarFontColorGreen (group->screen);
textAttrib.color[2] = groupGetTabbarFontColorBlue (group->screen);
textAttrib.color[3] = groupGetTabbarFontColorAlpha (group->screen);
textAttrib.ellipsize = TRUE;
textAttrib.maxwidth = width;
textAttrib.maxheight = height;
textAttrib.screen = group->screen;
textAttrib.renderMode = TextRenderWindowTitle;
if (bar->textSlot && bar->textSlot->window)
textAttrib.data = (void*) bar->textSlot->window->id;
else
textAttrib.data = 0;
d = group->screen->display;
if (!((*d->fileToImage) (d, TEXT_ID, (const char*) &textAttrib,
&width, &height, &stride, &data)))
{
/* getting the pixmap failed, so create an empty one */
Pixmap emptyPixmap;
emptyPixmap = XCreatePixmap (d->display, group->screen->root,
width, height, 32);
if (emptyPixmap)
{
XGCValues gcv;
GC gc;
gcv.foreground = 0x00000000;
gcv.plane_mask = 0xffffffff;
gc = XCreateGC(d->display, emptyPixmap,
GCForeground, &gcv);
XFillRectangle (d->display, emptyPixmap, gc,
0, 0, width, height);
XFreeGC (d->display, gc);
data = (void*) emptyPixmap;
}
}
layer->texWidth = width;
layer->texHeight = height;
if (data)
bindPixmapToTexture (group->screen, &layer->texture, (Pixmap) data,
layer->texWidth, layer->texHeight, 32);
}
/*
* groupPaintTabBar
*
*/
static void
groupPaintTabBar (GroupSelection *group,
const WindowPaintAttrib *wAttrib,
const CompTransform *transform,
unsigned int mask,
Region clipRegion)
{
CompWindow *topTab = TOP_TAB (group);
CompScreen *s = group->screen;
GroupTabBar *bar = group->tabBar;
GroupTabBarSlot *slot;
int i, alpha;
float wScale, hScale;
GroupCairoLayer *layer;
REGION box;
if (!group || !HAS_TOP_WIN (group) || !group->tabBar ||
(group->tabBar->state == PaintOff))
{
return;
}
GROUP_SCREEN (s);
#define PAINT_BG 0
#define PAINT_SEL 1
#define PAINT_THUMBS 2
#define PAINT_TEXT 3
#define PAINT_MAX 4
box.rects = &box.extents;
box.numRects = 1;
for (i = 0; i < PAINT_MAX; i++)
{
alpha = OPAQUE;
if (bar->state == PaintFadeIn)
alpha -= alpha * bar->animationTime /
(groupGetFadeTime (s) * 1000);
else if (bar->state == PaintFadeOut)
alpha = alpha * bar->animationTime /
(groupGetFadeTime (s) * 1000);
wScale = hScale = 1.0f;
layer = NULL;
switch (i) {
case PAINT_BG:
{
int newWidth;
layer = bar->bgLayer;
/* handle the repaint of the background */
newWidth = bar->region->extents.x2 - bar->region->extents.x1;
if (layer && (newWidth > layer->texWidth))
newWidth = layer->texWidth;
wScale = (double) (bar->region->extents.x2 -
bar->region->extents.x1) / (double) newWidth;
/* FIXME: maybe move this over to groupResizeTabBarRegion -
the only problem is that we would have 2 redraws if
there is an animation */
if (newWidth != bar->oldWidth || bar->bgAnimation)
groupRenderTabBarBackground (group);
bar->oldWidth = newWidth;
box.extents = bar->region->extents;
break;
}
case PAINT_SEL:
if (group->topTab != gs->draggedSlot)
{
layer = bar->selectionLayer;
box.extents = group->topTab->region->extents;
}
break;
case PAINT_THUMBS:
{
GLenum oldTextureFilter;
oldTextureFilter = s->display->textureFilter;
if (groupGetMipmaps (s))
s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;
for (slot = bar->slots; slot; slot = slot->next)
{
if (slot != gs->draggedSlot || !gs->dragged)
groupPaintThumb (group, slot, transform,
wAttrib->opacity);
}
s->display->textureFilter = oldTextureFilter;
break;
}
case PAINT_TEXT:
if (bar->textLayer && (bar->textLayer->state != PaintOff))
{
layer = bar->textLayer;
box.extents.x1 = bar->region->extents.x1 + 5;
box.extents.x2 = bar->region->extents.x1 +
bar->textLayer->texWidth + 5;
box.extents.y1 = bar->region->extents.y2 -
bar->textLayer->texHeight - 5;
box.extents.y2 = bar->region->extents.y2 - 5;
if (box.extents.x2 > bar->region->extents.x2)
box.extents.x2 = bar->region->extents.x2;
/* recalculate the alpha again for text fade... */
if (layer->state == PaintFadeIn)
alpha -= alpha * layer->animationTime /
(groupGetFadeTextTime(s) * 1000);
else if (layer->state == PaintFadeOut)
alpha = alpha * layer->animationTime /
(groupGetFadeTextTime(s) * 1000);
}
break;
}
if (layer)
{
CompMatrix matrix = layer->texture.matrix;
/* remove the old x1 and y1 so we have a relative value */
box.extents.x2 -= box.extents.x1;
box.extents.y2 -= box.extents.y1;
box.extents.x1 = (box.extents.x1 - topTab->attrib.x) / wScale +
topTab->attrib.x;
box.extents.y1 = (box.extents.y1 - topTab->attrib.y) / hScale +
topTab->attrib.y;
/* now add the new x1 and y1 so we have a absolute value again,
also we don't want to stretch the texture... */
if (box.extents.x2 * wScale < layer->texWidth)
box.extents.x2 += box.extents.x1;
else
box.extents.x2 = box.extents.x1 + layer->texWidth;
if (box.extents.y2 * hScale < layer->texHeight)
box.extents.y2 += box.extents.y1;
else
box.extents.y2 = box.extents.y1 + layer->texHeight;
matrix.x0 -= box.extents.x1 * matrix.xx;
matrix.y0 -= box.extents.y1 * matrix.yy;
topTab->vCount = topTab->indexCount = 0;
addWindowGeometry (topTab, &matrix, 1, &box, clipRegion);
if (topTab->vCount)
{
FragmentAttrib fragment;
CompTransform wTransform = *transform;
matrixTranslate (&wTransform,
WIN_X (topTab), WIN_Y (topTab), 0.0f);
matrixScale (&wTransform, wScale, hScale, 1.0f);
matrixTranslate (&wTransform,
wAttrib->xTranslate / wScale - WIN_X (topTab),
wAttrib->yTranslate / hScale - WIN_Y (topTab),
0.0f);
glPushMatrix ();
glLoadMatrixf (wTransform.m);
alpha = alpha * ((float)wAttrib->opacity / OPAQUE);
initFragmentAttrib (&fragment, wAttrib);
fragment.opacity = alpha;
(*s->drawWindowTexture) (topTab, &layer->texture,
&fragment, mask |
PAINT_WINDOW_BLEND_MASK |
PAINT_WINDOW_TRANSFORMED_MASK |
PAINT_WINDOW_TRANSLUCENT_MASK);
glPopMatrix ();
}
}
}
}
/*
* groupPaintSelectionOutline
*
*/
static void
groupPaintSelectionOutline (CompScreen *s,
const ScreenPaintAttrib *sa,
const CompTransform *transform,
CompOutput *output,
Bool transformed)
{
int x1, x2, y1, y2;
GROUP_SCREEN (s);
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->grabState == ScreenGrabSelect)
{
CompTransform sTransform = *transform;
if (transformed)
{
(*s->applyScreenTransform) (s, sa, output, &sTransform);
transformToScreenSpace (s, output, -sa->zTranslate, &sTransform);
} else
transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &sTransform);
glPushMatrix ();
glLoadMatrixf (sTransform.m);
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
glEnable (GL_BLEND);
glColor4usv (groupGetFillColorOption (s)->value.c);
glRecti (x1, y2, x2, y1);
glLineWidth (3);
glEnable (GL_LINE_SMOOTH);
glColor4usv (groupGetLineColorOption (s)->value.c);
glBegin (GL_LINE_LOOP);
glVertex2i (x1, y1);
glVertex2i (x2, y1);
glVertex2i (x2, y2);
glVertex2i (x1, y2);
glEnd ();
glDisable (GL_LINE_SMOOTH);
glLineWidth (1); /* back to default */
glColor4usv (defaultColor);
glDisable (GL_BLEND);
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
glPopMatrix ();
}
}
/*
* groupPreparePaintScreen
*
*/
void
groupPreparePaintScreen (CompScreen *s,
int msSinceLastPaint)
{
GroupSelection *group;
GROUP_SCREEN (s);
UNWRAP (gs, s, preparePaintScreen);
(*s->preparePaintScreen) (s, msSinceLastPaint);
WRAP (gs, s, preparePaintScreen, groupPreparePaintScreen);
for (group = gs->groups; group; group = group->next)
{
GroupTabBar *bar = group->tabBar;
if (group->changeState != PaintOff)
group->changeAnimationTime -= msSinceLastPaint;
if (!bar)
continue;
groupApplyForces (s, bar, (gs->dragged) ? gs->draggedSlot: NULL);
groupApplySpeeds (s, group, msSinceLastPaint);
groupHandleHoverDetection (group);
groupHandleTabBarFade (group, msSinceLastPaint);
groupHandleTextFade (group, msSinceLastPaint);
groupHandleTabBarAnimation (group, msSinceLastPaint);
}
groupHandleChanges (s);
groupDrawTabAnimation (s, msSinceLastPaint);
}
/*
* groupPaintOutput
*
*/
Bool
groupPaintOutput (CompScreen *s,
const ScreenPaintAttrib *sAttrib,
const CompTransform *transform,
Region region,
CompOutput *output,
unsigned int mask)
{
GroupSelection *group;
Bool status;
GROUP_SCREEN (s);
GROUP_DISPLAY (s->display);
gs->painted = FALSE;
gs->vpX = s->x;
gs->vpY = s->y;
for (group = gs->groups; group; group = group->next)
{
if (group->changeState != PaintOff ||
group->tabbingState != PaintOff)
{
mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
}
}
if (gs->tabBarVisible || gd->resizeInfo)
mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
UNWRAP (gs, s, paintOutput);
status = (*s->paintOutput) (s, sAttrib, transform, region, output, mask);
WRAP (gs, s, paintOutput, groupPaintOutput);
if (status && !gs->painted)
{
if ((gs->grabState == ScreenGrabTabDrag) && gs->draggedSlot)
{
CompTransform wTransform = *transform;
PaintState state;
GROUP_WINDOW (gs->draggedSlot->window);
transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &wTransform);
glPushMatrix ();
glLoadMatrixf (wTransform.m);
/* prevent tab bar drawing.. */
state = gw->group->tabBar->state;
gw->group->tabBar->state = PaintOff;
groupPaintThumb (NULL, gs->draggedSlot, &wTransform, OPAQUE);
gw->group->tabBar->state = state;
glPopMatrix ();
}
else if (gs->grabState == ScreenGrabSelect)
{
groupPaintSelectionOutline (s, sAttrib, transform, output, FALSE);
}
}
return status;
}
/*
* groupaintTransformedOutput
*
*/
void
groupPaintTransformedOutput (CompScreen *s,
const ScreenPaintAttrib *sa,
const CompTransform *transform,
Region region,
CompOutput *output,
unsigned int mask)
{
GROUP_SCREEN (s);
UNWRAP (gs, s, paintTransformedOutput);
(*s->paintTransformedOutput) (s, sa, transform, region, output, mask);
WRAP (gs, s, paintTransformedOutput, groupPaintTransformedOutput);
if ((gs->vpX == s->x) && (gs->vpY == s->y))
{
gs->painted = TRUE;
if ((gs->grabState == ScreenGrabTabDrag) &&
gs->draggedSlot && gs->dragged)
{
CompTransform wTransform = *transform;
(*s->applyScreenTransform) (s, sa, output, &wTransform);
transformToScreenSpace (s, output, -sa->zTranslate, &wTransform);
glPushMatrix ();
glLoadMatrixf (wTransform.m);
groupPaintThumb (NULL, gs->draggedSlot, &wTransform, OPAQUE);
glPopMatrix ();
}
else if (gs->grabState == ScreenGrabSelect)
{
groupPaintSelectionOutline (s, sa, transform, output, TRUE);
}
}
}
void
groupRecomputeGlow (CompScreen *s)
{
CompWindow *w;
GROUP_SCREEN (s);
for (w = s->windows; w; w = w->next)
groupComputeGlowQuads (w, &gs->glowTexture.matrix);
}
/*
* groupDonePaintScreen
*
*/
void
groupDonePaintScreen (CompScreen *s)
{
GroupSelection *group;
GROUP_SCREEN (s);
UNWRAP (gs, s, donePaintScreen);
(*s->donePaintScreen) (s);
WRAP (gs, s, donePaintScreen, groupDonePaintScreen);
for (group = gs->groups; group; group = group->next)
{
if (group->doTabbing)
damageScreen (s);
if (group->changeState != PaintOff)
damageScreen (s);
if (group->tabBar)
{
Bool needDamage = FALSE;
if ((group->tabBar->state == PaintFadeIn) ||
(group->tabBar->state == PaintFadeOut))
{
needDamage = TRUE;
}
if (group->tabBar->textLayer)
{
if ((group->tabBar->textLayer->state == PaintFadeIn) ||
(group->tabBar->textLayer->state == PaintFadeOut))
{
needDamage = TRUE;
}
}
if (group->tabBar->bgAnimation)
needDamage = TRUE;
if (gs->draggedSlot)
needDamage = TRUE;
if (needDamage)
groupDamageTabBarRegion (group);
}
}
}
void
groupComputeGlowQuads (CompWindow *w,
CompMatrix *matrix)
{
BoxRec *box;
CompMatrix *quadMatrix;
int glowSize, glowOffset;
GroupGlowTypeEnum glowType;
GROUP_WINDOW (w);
if (groupGetGlow (w->screen) && matrix)
{
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;
}
GROUP_DISPLAY (w->screen->display);
glowSize = groupGetGlowSize (w->screen);
glowType = groupGetGlowType (w->screen);
glowOffset = (glowSize * gd->glowTextureProperties[glowType].glowOffset /
gd->glowTextureProperties[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_REAL_X (w) - glowSize + glowOffset;
box->y1 = WIN_REAL_Y (w) - glowSize + glowOffset;
box->x2 = WIN_REAL_X (w) + glowOffset;
box->y2 = WIN_REAL_Y (w) + glowOffset;
quadMatrix->xx = 1.0f / glowSize;
quadMatrix->yy = -1.0f / glowSize;
quadMatrix->x0 = -(box->x1 * quadMatrix->xx);
quadMatrix->y0 = 1.0 -(box->y1 * quadMatrix->yy);
box->x2 = MIN (WIN_REAL_X (w) + glowOffset,
WIN_REAL_X (w) + (WIN_REAL_WIDTH (w) / 2));
box->y2 = MIN (WIN_REAL_Y (w) + glowOffset,
WIN_REAL_Y (w) + (WIN_REAL_HEIGHT (w) / 2));
/* Top right corner */
box = &gw->glowQuads[GLOWQUAD_TOPRIGHT].box;
gw->glowQuads[GLOWQUAD_TOPRIGHT].matrix = *matrix;
quadMatrix = &gw->glowQuads[GLOWQUAD_TOPRIGHT].matrix;
box->x1 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset;
box->y1 = WIN_REAL_Y (w) - glowSize + glowOffset;
box->x2 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) + glowSize - glowOffset;
box->y2 = WIN_REAL_Y (w) + glowOffset;
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);
box->x1 = MAX (WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset,
WIN_REAL_X (w) + (WIN_REAL_WIDTH (w) / 2));
box->y2 = MIN (WIN_REAL_Y (w) + glowOffset,
WIN_REAL_Y (w) + (WIN_REAL_HEIGHT (w) / 2));
/* Bottom left corner */
box = &gw->glowQuads[GLOWQUAD_BOTTOMLEFT].box;
gw->glowQuads[GLOWQUAD_BOTTOMLEFT].matrix = *matrix;
quadMatrix = &gw->glowQuads[GLOWQUAD_BOTTOMLEFT].matrix;
box->x1 = WIN_REAL_X (w) - glowSize + glowOffset;
box->y1 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset;
box->x2 = WIN_REAL_X (w) + glowOffset;
box->y2 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) + glowSize - glowOffset;
quadMatrix->xx = 1.0f / glowSize;
quadMatrix->yy = 1.0f / glowSize;
quadMatrix->x0 = -(box->x1 * quadMatrix->xx);
quadMatrix->y0 = -(box->y1 * quadMatrix->yy);
box->y1 = MAX (WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset,
WIN_REAL_Y (w) + (WIN_REAL_HEIGHT (w) / 2));
box->x2 = MIN (WIN_REAL_X (w) + glowOffset,
WIN_REAL_X (w) + (WIN_REAL_WIDTH (w) / 2));
/* Bottom right corner */
box = &gw->glowQuads[GLOWQUAD_BOTTOMRIGHT].box;
gw->glowQuads[GLOWQUAD_BOTTOMRIGHT].matrix = *matrix;
quadMatrix = &gw->glowQuads[GLOWQUAD_BOTTOMRIGHT].matrix;
box->x1 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset;
box->y1 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset;
box->x2 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) + glowSize - glowOffset;
box->y2 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) + 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);
box->x1 = MAX (WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset,
WIN_REAL_X (w) + (WIN_REAL_WIDTH (w) / 2));
box->y1 = MAX (WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset,
WIN_REAL_Y (w) + (WIN_REAL_HEIGHT (w) / 2));
/* Top edge */
box = &gw->glowQuads[GLOWQUAD_TOP].box;
gw->glowQuads[GLOWQUAD_TOP].matrix = *matrix;
quadMatrix = &gw->glowQuads[GLOWQUAD_TOP].matrix;
box->x1 = WIN_REAL_X (w) + glowOffset;
box->y1 = WIN_REAL_Y (w) - glowSize + glowOffset;
box->x2 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset;
box->y2 = WIN_REAL_Y (w) + 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_REAL_X (w) + glowOffset;
box->y1 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset;
box->x2 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset;
box->y2 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) + 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_REAL_X (w) - glowSize + glowOffset;
box->y1 = WIN_REAL_Y (w) + glowOffset;
box->x2 = WIN_REAL_X (w) + glowOffset;
box->y2 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - 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_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset;
box->y1 = WIN_REAL_Y (w) + glowOffset;
box->x2 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) + glowSize - glowOffset;
box->y2 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - 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 CompTransform *transform,
const FragmentAttrib *attrib,
Region region,
unsigned int mask)
{
Bool status;
CompScreen *s = w->screen;
GROUP_WINDOW (w);
GROUP_SCREEN (s);
if (gw->group && (gw->group->nWins > 1) && gw->glowQuads)
{
if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
region = &infiniteRegion;
if (region->numRects)
{
REGION box;
int i;
box.rects = &box.extents;
box.numRects = 1;
w->vCount = w->indexCount = 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)
{
(*s->addWindowGeometry) (w,
&gw->glowQuads[i].matrix,
1, &box, region);
}
}
if (w->vCount)
{
FragmentAttrib fAttrib = *attrib;
GLushort average;
GLushort color[3] = {gw->group->color[0],
gw->group->color[1],
gw->group->color[2]};
/* Apply brightness to color. */
color[0] *= (float)attrib->brightness / BRIGHT;
color[1] *= (float)attrib->brightness / BRIGHT;
color[2] *= (float)attrib->brightness / BRIGHT;
/* Apply saturation to color. */
average = (color[0] + color[1] + color[2]) / 3;
color[0] = average +
(color[0] - average) * attrib->saturation / COLOR;
color[1] = average +
(color[1] - average) * attrib->saturation / COLOR;
color[2] = average +
(color[2] - average) * attrib->saturation / COLOR;
fAttrib.opacity = OPAQUE;
fAttrib.saturation = COLOR;
fAttrib.brightness = BRIGHT;
screenTexEnvMode (w->screen, GL_MODULATE);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4us (color[0], color[1], color[2], attrib->opacity);
/* we use PAINT_WINDOW_TRANSFORMED_MASK here to force
the usage of a good texture filter */
(*s->drawWindowTexture) (w, &gs->glowTexture, &fAttrib,
mask | PAINT_WINDOW_BLEND_MASK |
PAINT_WINDOW_TRANSLUCENT_MASK |
PAINT_WINDOW_TRANSFORMED_MASK);
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
screenTexEnvMode (s, GL_REPLACE);
glColor4usv (defaultColor);
}
}
}
UNWRAP (gs, s, drawWindow);
status = (*s->drawWindow) (w, transform, attrib, region, mask);
WRAP (gs, s, drawWindow, groupDrawWindow);
return status;
}
void
groupGetStretchRectangle (CompWindow *w,
BoxPtr pBox,
float *xScaleRet,
float *yScaleRet)
{
BoxRec box;
int width, height;
float xScale, yScale;
GROUP_WINDOW (w);
box.x1 = gw->resizeGeometry->x - w->input.left;
box.y1 = gw->resizeGeometry->y - w->input.top;
box.x2 = gw->resizeGeometry->x +
gw->resizeGeometry->width + w->serverBorderWidth * 2 +
w->input.right;
if (w->shaded)
{
box.y2 = gw->resizeGeometry->y + w->height + w->input.bottom;
}
else
{
box.y2 = gw->resizeGeometry->y +
gw->resizeGeometry->height + w->serverBorderWidth * 2 +
w->input.bottom;
}
width = w->width + w->input.left + w->input.right;
height = w->height + w->input.top + w->input.bottom;
xScale = (width) ? (box.x2 - box.x1) / (float) width : 1.0f;
yScale = (height) ? (box.y2 - box.y1) / (float) height : 1.0f;
pBox->x1 = box.x1 - (w->output.left - w->input.left) * xScale;
pBox->y1 = box.y1 - (w->output.top - w->input.top) * yScale;
pBox->x2 = box.x2 + w->output.right * xScale;
pBox->y2 = box.y2 + w->output.bottom * yScale;
if (xScaleRet)
*xScaleRet = xScale;
if (yScaleRet)
*yScaleRet = yScale;
}
void
groupDamagePaintRectangle (CompScreen *s,
BoxPtr pBox)
{
REGION reg;
reg.rects = ®.extents;
reg.numRects = 1;
reg.extents = *pBox;
reg.extents.x1 -= 1;
reg.extents.y1 -= 1;
reg.extents.x2 += 1;
reg.extents.y2 += 1;
damageScreenRegion (s, ®);
}
/*
* groupPaintWindow
*
*/
Bool
groupPaintWindow (CompWindow *w,
const WindowPaintAttrib *attrib,
const CompTransform *transform,
Region region,
unsigned int mask)
{
Bool status;
Bool doRotate, doTabbing, showTabbar;
CompScreen *s = w->screen;
GROUP_SCREEN (s);
GROUP_WINDOW (w);
doRotate = gw->group && (gw->group->changeState != PaintOff) &&
(IS_TOP_TAB (w, gw->group) || IS_PREV_TOP_TAB (w, gw->group));
doTabbing = gw->group && (gw->group->tabbingState != PaintOff) &&
(gw->animateState & (IS_ANIMATED | FINISHED_ANIMATION)) &&
!(IS_TOP_TAB (w, gw->group) &&
(gw->group->tabbingState == PaintFadeIn));
showTabbar = gw->group && gw->group->tabBar &&
(((HAS_TOP_WIN (gw->group) && IS_TOP_TAB (w, gw->group)) &&
((gw->group->changeState == PaintOff) ||
(gw->group->changeState == PaintFadeOut))) ||
(IS_PREV_TOP_TAB (w, gw->group) &&
(gw->group->changeState == PaintFadeIn)));
if (gw->windowHideInfo)
mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
if (gw->inSelection || gw->resizeGeometry || doRotate || doTabbing || showTabbar)
{
WindowPaintAttrib wAttrib = *attrib;
CompTransform wTransform = *transform;
float animProgress = 0.0f;
if (gw->inSelection)
{
wAttrib.opacity = OPAQUE * groupGetSelectOpacity (s) / 100;
wAttrib.saturation = COLOR * groupGetSelectSaturation (s) / 100;
wAttrib.brightness = BRIGHT * groupGetSelectBrightness (s) / 100;
}
if (doTabbing)
{
/* fade the window out */
float progress;
int distanceX, distanceY;
float origDistance, distance;
distanceX = (WIN_X (w) + gw->tx - gw->destination.x);
distanceY = (WIN_Y (w) + gw->ty - gw->destination.y);
distance = sqrt(pow (distanceX, 2) + pow (distanceY, 2));
distanceX = (gw->orgPos.x - gw->destination.x);
distanceY = (gw->orgPos.y - gw->destination.y);
origDistance = sqrt (pow (distanceX, 2) + pow (distanceY, 2));
if (!distanceX && !distanceY)
progress = 1.0f;
else
progress = 1.0f - (distance / origDistance);
animProgress = progress;
progress = MAX (progress, 0.0f);
if (gw->group->tabbingState == PaintFadeIn)
progress = 1.0f - progress;
wAttrib.opacity = (float)wAttrib.opacity * progress;
}
if (doRotate)
{
float timeLeft = gw->group->changeAnimationTime;
int animTime = groupGetChangeAnimationTime (s) * 500;
if (gw->group->changeState == PaintFadeIn)
timeLeft += animTime;
/* 0 at the beginning, 1 at the end */
animProgress = 1 - (timeLeft / (2 * animTime));
}
if (gw->resizeGeometry)
{
int xOrigin, yOrigin;
float xScale, yScale;
BoxRec box;
groupGetStretchRectangle (w, &box, &xScale, &yScale);
xOrigin = w->attrib.x - w->input.left;
yOrigin = w->attrib.y - w->input.top;
matrixTranslate (&wTransform, xOrigin, yOrigin, 0.0f);
matrixScale (&wTransform, xScale, yScale, 1.0f);
matrixTranslate (&wTransform,
(gw->resizeGeometry->x - w->attrib.x) /
xScale - xOrigin,
(gw->resizeGeometry->y - w->attrib.y) /
yScale - yOrigin,
0.0f);
mask |= PAINT_WINDOW_TRANSFORMED_MASK;
}
else if (doRotate || doTabbing)
{
float animWidth, animHeight;
float animScaleX, animScaleY;
CompWindow *morphBase, *morphTarget;
if (doTabbing)
{
if (gw->group->tabbingState == PaintFadeIn)
{
morphBase = w;
morphTarget = TOP_TAB (gw->group);
}
else
{
morphTarget = w;
if (HAS_TOP_WIN (gw->group))
morphBase = TOP_TAB (gw->group);
else
morphBase = gw->group->lastTopTab;
}
}
else
{
morphBase = PREV_TOP_TAB (gw->group);
morphTarget = TOP_TAB (gw->group);
}
animWidth = (1 - animProgress) * WIN_REAL_WIDTH (morphBase) +
animProgress * WIN_REAL_WIDTH (morphTarget);
animHeight = (1 - animProgress) * WIN_REAL_HEIGHT (morphBase) +
animProgress * WIN_REAL_HEIGHT (morphTarget);
animWidth = MAX (1.0f, animWidth);
animHeight = MAX (1.0f, animHeight);
animScaleX = animWidth / WIN_REAL_WIDTH (w);
animScaleY = animHeight / WIN_REAL_HEIGHT (w);
if (doRotate)
matrixScale (&wTransform, 1.0f, 1.0f, 1.0f / s->width);
matrixTranslate (&wTransform,
WIN_REAL_X (w) + WIN_REAL_WIDTH (w) / 2.0f,
WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) / 2.0f,
0.0f);
if (doRotate)
{
float rotateAngle = animProgress * 180.0f;
if (IS_TOP_TAB (w, gw->group))
rotateAngle += 180.0f;
if (gw->group->changeAnimationDirection < 0)
rotateAngle *= -1.0f;
matrixRotate (&wTransform, rotateAngle, 0.0f, 1.0f, 0.0f);
}
if (doTabbing)
matrixTranslate (&wTransform,
gw->orgPos.x + gw->tx - WIN_X (w),
gw->orgPos.y + gw->ty - WIN_Y (w), 0.0f);
matrixScale (&wTransform, animScaleX, animScaleY, 1.0f);
matrixTranslate (&wTransform,
-(WIN_REAL_X (w) + WIN_REAL_WIDTH (w) / 2.0f),
-(WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) / 2.0f),
0.0f);
mask |= PAINT_WINDOW_TRANSFORMED_MASK;
}
UNWRAP (gs, s, paintWindow);
status = (*s->paintWindow) (w, &wAttrib, &wTransform, region, mask);
if (showTabbar)
groupPaintTabBar (gw->group, &wAttrib, &wTransform, mask, region);
WRAP (gs, s, paintWindow, groupPaintWindow);
}
else
{
UNWRAP (gs, s, paintWindow);
status = (*s->paintWindow) (w, attrib, transform, region, mask);
WRAP (gs, s, paintWindow, groupPaintWindow);
}
return status;
}
syntax highlighted by Code2HTML, v. 0.9.1