1 /**
2  *
3  * Compiz group plugin
4  *
5  * paint.c
6  *
7  * Copyright : (C) 2006-2007 by Patrick Niklaus, Roi Cohen, Danny Baumann
8  * Authors: Patrick Niklaus <patrick.niklaus@googlemail.com>
9  *          Roi Cohen       <roico.beryl@gmail.com>
10  *          Danny Baumann   <maniac@opencompositing.org>
11  *
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  **/
24 
25 #include "group-internal.h"
26 
27 /*
28  * groupPaintThumb - taken from switcher and modified for tab bar
29  *
30  */
31 static void
groupPaintThumb(GroupSelection * group,GroupTabBarSlot * slot,const CompTransform * transform,int targetOpacity)32 groupPaintThumb (GroupSelection      *group,
33 		 GroupTabBarSlot     *slot,
34 		 const CompTransform *transform,
35 		 int                 targetOpacity)
36 {
37     CompWindow            *w = slot->window;
38     CompScreen            *s = w->screen;
39     AddWindowGeometryProc oldAddWindowGeometry;
40     WindowPaintAttrib     wAttrib = w->paint;
41     int                   tw, th;
42 
43     tw = slot->region->extents.x2 - slot->region->extents.x1;
44     th = slot->region->extents.y2 - slot->region->extents.y1;
45 
46     /* Wrap drawWindowGeometry to make sure the general
47        drawWindowGeometry function is used */
48     oldAddWindowGeometry = s->addWindowGeometry;
49     s->addWindowGeometry = addWindowGeometry;
50 
51     /* animate fade */
52     if (group && group->tabBar->state == PaintFadeIn)
53     {
54 	wAttrib.opacity -= wAttrib.opacity * group->tabBar->animationTime /
55 	                   (groupGetFadeTime (s) * 1000);
56     }
57     else if (group && group->tabBar->state == PaintFadeOut)
58     {
59 	wAttrib.opacity = wAttrib.opacity * group->tabBar->animationTime /
60 	                  (groupGetFadeTime (s) * 1000);
61     }
62 
63     wAttrib.opacity = wAttrib.opacity * targetOpacity / OPAQUE;
64 
65     if (w->mapNum)
66     {
67 	FragmentAttrib fragment;
68 	CompTransform  wTransform = *transform;
69 	int            width, height;
70 	int            vx, vy;
71 
72 	width = w->width + w->output.left + w->output.right;
73 	height = w->height + w->output.top + w->output.bottom;
74 
75 	if (width > tw)
76 	    wAttrib.xScale = (float) tw / width;
77 	else
78 	    wAttrib.xScale = 1.0f;
79 	if (height > th)
80 	    wAttrib.yScale = (float) tw / height;
81 	else
82 	    wAttrib.yScale = 1.0f;
83 
84 	if (wAttrib.xScale < wAttrib.yScale)
85 	    wAttrib.yScale = wAttrib.xScale;
86 	else
87 	    wAttrib.xScale = wAttrib.yScale;
88 
89 	/* FIXME: do some more work on the highlight on hover feature
90 	// Highlight on hover
91 	if (group && group->tabBar && group->tabBar->hoveredSlot == slot) {
92 	wAttrib.saturation = 0;
93 	wAttrib.brightness /= 1.25f;
94 	}*/
95 
96 	groupGetDrawOffsetForSlot (slot, &vx, &vy);
97 
98 	wAttrib.xTranslate = (slot->region->extents.x1 +
99 			      slot->region->extents.x2) / 2 + vx;
100 	wAttrib.yTranslate = slot->region->extents.y1 + vy;
101 
102 	initFragmentAttrib (&fragment, &wAttrib);
103 
104 	matrixTranslate (&wTransform,
105 			 wAttrib.xTranslate, wAttrib.yTranslate, 0.0f);
106 	matrixScale (&wTransform, wAttrib.xScale, wAttrib.yScale, 1.0f);
107 	matrixTranslate (&wTransform, -(WIN_X (w) + WIN_WIDTH (w) / 2),
108 			 -(WIN_Y (w) - w->output.top), 0.0f);
109 
110 	glPushMatrix ();
111 	glLoadMatrixf (wTransform.m);
112 
113 	(*s->drawWindow) (w, &wTransform, &fragment, &infiniteRegion,
114 			  PAINT_WINDOW_TRANSFORMED_MASK |
115 			  PAINT_WINDOW_TRANSLUCENT_MASK);
116 
117 	glPopMatrix ();
118     }
119 
120     s->addWindowGeometry = oldAddWindowGeometry;
121 }
122 
123 /*
124  * groupPaintTabBar
125  *
126  */
127 static void
groupPaintTabBar(GroupSelection * group,const WindowPaintAttrib * wAttrib,const CompTransform * transform,unsigned int mask,Region clipRegion)128 groupPaintTabBar (GroupSelection          *group,
129 		  const WindowPaintAttrib *wAttrib,
130 		  const CompTransform     *transform,
131 		  unsigned int            mask,
132 		  Region                  clipRegion)
133 {
134     CompWindow      *topTab;
135     CompScreen      *s = group->screen;
136     GroupTabBar     *bar = group->tabBar;
137     int             count;
138     REGION          box;
139 
140     GROUP_SCREEN (s);
141 
142     if (HAS_TOP_WIN (group))
143 	topTab = TOP_TAB (group);
144     else
145 	topTab = PREV_TOP_TAB (group);
146 
147 #define PAINT_BG     0
148 #define PAINT_SEL    1
149 #define PAINT_THUMBS 2
150 #define PAINT_TEXT   3
151 #define PAINT_MAX    4
152 
153     box.rects = &box.extents;
154     box.numRects = 1;
155 
156     for (count = 0; count < PAINT_MAX; count++)
157     {
158 	int             alpha = OPAQUE;
159 	float           wScale = 1.0f, hScale = 1.0f;
160 	GroupCairoLayer *layer = NULL;
161 
162 	if (bar->state == PaintFadeIn)
163 	    alpha -= alpha * bar->animationTime / (groupGetFadeTime (s) * 1000);
164 	else if (bar->state == PaintFadeOut)
165 	    alpha = alpha * bar->animationTime / (groupGetFadeTime (s) * 1000);
166 
167 	switch (count) {
168 	case PAINT_BG:
169 	    {
170 		int newWidth;
171 
172 		layer = bar->bgLayer;
173 
174 		/* handle the repaint of the background */
175 		newWidth = bar->region->extents.x2 - bar->region->extents.x1;
176 		if (layer && (newWidth > layer->texWidth))
177 		    newWidth = layer->texWidth;
178 
179 		wScale = (double) (bar->region->extents.x2 -
180 				   bar->region->extents.x1) / (double) newWidth;
181 
182 		/* FIXME: maybe move this over to groupResizeTabBarRegion -
183 		   the only problem is that we would have 2 redraws if
184 		   there is an animation */
185 		if (newWidth != bar->oldWidth || bar->bgAnimation)
186 		    groupRenderTabBarBackground (group);
187 
188 		bar->oldWidth = newWidth;
189 		box.extents = bar->region->extents;
190 	    }
191 	    break;
192 
193 	case PAINT_SEL:
194 	    if (group->topTab != gs->draggedSlot)
195 	    {
196 		layer = bar->selectionLayer;
197 		box.extents = group->topTab->region->extents;
198 	    }
199 	    break;
200 
201 	case PAINT_THUMBS:
202 	    {
203 		GLenum          oldTextureFilter;
204 		GroupTabBarSlot *slot;
205 
206 		oldTextureFilter = s->display->textureFilter;
207 
208 		if (groupGetMipmaps (s))
209 		    s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;
210 
211 		for (slot = bar->slots; slot; slot = slot->next)
212 		{
213 		    if (slot != gs->draggedSlot || !gs->dragged)
214 			groupPaintThumb (group, slot, transform,
215 					 wAttrib->opacity);
216 		}
217 
218 		s->display->textureFilter = oldTextureFilter;
219 	    }
220 	    break;
221 
222 	case PAINT_TEXT:
223 	    if (bar->textLayer && (bar->textLayer->state != PaintOff))
224 	    {
225 		layer = bar->textLayer;
226 
227 		box.extents.x1 = bar->region->extents.x1 + 5;
228 		box.extents.x2 = bar->region->extents.x1 +
229 		                 bar->textLayer->texWidth + 5;
230 		box.extents.y1 = bar->region->extents.y2 -
231 		                 bar->textLayer->texHeight - 5;
232 		box.extents.y2 = bar->region->extents.y2 - 5;
233 
234 		if (box.extents.x2 > bar->region->extents.x2)
235 		    box.extents.x2 = bar->region->extents.x2;
236 
237 		/* recalculate the alpha again for text fade... */
238 		if (layer->state == PaintFadeIn)
239 		    alpha -= alpha * layer->animationTime /
240 			     (groupGetFadeTextTime(s) * 1000);
241 		else if (layer->state == PaintFadeOut)
242 		    alpha = alpha * layer->animationTime /
243 			    (groupGetFadeTextTime(s) * 1000);
244 	    }
245 	    break;
246 	}
247 
248 	if (layer)
249 	{
250 	    CompMatrix matrix = layer->texture.matrix;
251 
252 	    /* remove the old x1 and y1 so we have a relative value */
253 	    box.extents.x2 -= box.extents.x1;
254 	    box.extents.y2 -= box.extents.y1;
255 	    box.extents.x1 = (box.extents.x1 - topTab->attrib.x) / wScale +
256 		             topTab->attrib.x;
257 	    box.extents.y1 = (box.extents.y1 - topTab->attrib.y) / hScale +
258 		             topTab->attrib.y;
259 
260 	    /* now add the new x1 and y1 so we have a absolute value again,
261 	       also we don't want to stretch the texture... */
262 	    if (box.extents.x2 * wScale < layer->texWidth)
263 		box.extents.x2 += box.extents.x1;
264 	    else
265 		box.extents.x2 = box.extents.x1 + layer->texWidth;
266 
267 	    if (box.extents.y2 * hScale < layer->texHeight)
268 		box.extents.y2 += box.extents.y1;
269 	    else
270 		box.extents.y2 = box.extents.y1 + layer->texHeight;
271 
272 	    matrix.x0 -= box.extents.x1 * matrix.xx;
273 	    matrix.y0 -= box.extents.y1 * matrix.yy;
274 	    topTab->vCount = topTab->indexCount = 0;
275 
276 	    addWindowGeometry (topTab, &matrix, 1, &box, clipRegion);
277 
278 	    if (topTab->vCount)
279 	    {
280 		FragmentAttrib fragment;
281 		CompTransform  wTransform = *transform;
282 
283 		matrixTranslate (&wTransform,
284 				 WIN_X (topTab), WIN_Y (topTab), 0.0f);
285 		matrixScale (&wTransform, wScale, hScale, 1.0f);
286 		matrixTranslate (&wTransform,
287 				 wAttrib->xTranslate / wScale - WIN_X (topTab),
288 				 wAttrib->yTranslate / hScale - WIN_Y (topTab),
289 				 0.0f);
290 
291 		glPushMatrix ();
292 		glLoadMatrixf (wTransform.m);
293 
294 		alpha = alpha * ((float)wAttrib->opacity / OPAQUE);
295 
296 		initFragmentAttrib (&fragment, wAttrib);
297 		fragment.opacity = alpha;
298 
299 		(*s->drawWindowTexture) (topTab, &layer->texture,
300 					 &fragment, mask |
301 					 PAINT_WINDOW_BLEND_MASK |
302 					 PAINT_WINDOW_TRANSFORMED_MASK |
303 					 PAINT_WINDOW_TRANSLUCENT_MASK);
304 
305 		glPopMatrix ();
306 	    }
307 	}
308     }
309 }
310 
311 /*
312  * groupPaintSelectionOutline
313  *
314  */
315 static void
groupPaintSelectionOutline(CompScreen * s,const ScreenPaintAttrib * sa,const CompTransform * transform,CompOutput * output,Bool transformed)316 groupPaintSelectionOutline (CompScreen              *s,
317 			    const ScreenPaintAttrib *sa,
318 			    const CompTransform     *transform,
319 			    CompOutput              *output,
320 			    Bool                    transformed)
321 {
322     int x1, x2, y1, y2;
323 
324     GROUP_SCREEN (s);
325 
326     x1 = MIN (gs->x1, gs->x2);
327     y1 = MIN (gs->y1, gs->y2);
328     x2 = MAX (gs->x1, gs->x2);
329     y2 = MAX (gs->y1, gs->y2);
330 
331     if (gs->grabState == ScreenGrabSelect)
332     {
333 	CompTransform sTransform = *transform;
334 
335 	if (transformed)
336 	{
337 	    (*s->applyScreenTransform) (s, sa, output, &sTransform);
338 	    transformToScreenSpace (s, output, -sa->zTranslate, &sTransform);
339 	} else
340 	    transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &sTransform);
341 
342 	glPushMatrix ();
343 	glLoadMatrixf (sTransform.m);
344 
345 	glDisableClientState (GL_TEXTURE_COORD_ARRAY);
346 	glEnable (GL_BLEND);
347 
348 	glColor4usv (groupGetFillColorOption (s)->value.c);
349 	glRecti (x1, y2, x2, y1);
350 
351 	glColor4usv (groupGetLineColorOption (s)->value.c);
352 	glBegin (GL_LINE_LOOP);
353 	glVertex2i (x1, y1);
354 	glVertex2i (x2, y1);
355 	glVertex2i (x2, y2);
356 	glVertex2i (x1, y2);
357 	glEnd ();
358 
359 	glColor4usv (defaultColor);
360 	glDisable (GL_BLEND);
361 	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
362 	glPopMatrix ();
363     }
364 }
365 
366 /*
367  * groupPreparePaintScreen
368  *
369  */
370 void
groupPreparePaintScreen(CompScreen * s,int msSinceLastPaint)371 groupPreparePaintScreen (CompScreen *s,
372 			 int        msSinceLastPaint)
373 {
374     GroupSelection *group, *next;
375 
376     GROUP_SCREEN (s);
377 
378     UNWRAP (gs, s, preparePaintScreen);
379     (*s->preparePaintScreen) (s, msSinceLastPaint);
380     WRAP (gs, s, preparePaintScreen, groupPreparePaintScreen);
381 
382     group = gs->groups;
383     while (group)
384     {
385 	GroupTabBar *bar = group->tabBar;
386 
387 	if (bar)
388 	{
389 	    groupApplyForces (s, bar, (gs->dragged) ? gs->draggedSlot : NULL);
390 	    groupApplySpeeds (s, group, msSinceLastPaint);
391 
392 	    if ((bar->state != PaintOff) && HAS_TOP_WIN (group))
393 		groupHandleHoverDetection (group);
394 
395 	    if (bar->state == PaintFadeIn || bar->state == PaintFadeOut)
396 		groupHandleTabBarFade (group, msSinceLastPaint);
397 
398 	    if (bar->textLayer)
399 		groupHandleTextFade (group, msSinceLastPaint);
400 
401 	    if (bar->bgAnimation)
402 		groupHandleTabBarAnimation (group, msSinceLastPaint);
403 	}
404 
405 	if (group->changeState != NoTabChange)
406 	{
407 	    group->changeAnimationTime -= msSinceLastPaint;
408 	    if (group->changeAnimationTime <= 0)
409 		groupHandleAnimation (group);
410 	}
411 
412 	/* groupDrawTabAnimation may delete the group, so better
413 	   save the pointer to the next chain element */
414 	next = group->next;
415 
416 	if (group->tabbingState != NoTabbing)
417 	    groupDrawTabAnimation (group, msSinceLastPaint);
418 
419 	group = next;
420     }
421 }
422 
423 /*
424  * groupPaintOutput
425  *
426  */
427 Bool
groupPaintOutput(CompScreen * s,const ScreenPaintAttrib * sAttrib,const CompTransform * transform,Region region,CompOutput * output,unsigned int mask)428 groupPaintOutput (CompScreen              *s,
429 		  const ScreenPaintAttrib *sAttrib,
430 		  const CompTransform     *transform,
431 		  Region                  region,
432 		  CompOutput              *output,
433 		  unsigned int            mask)
434 {
435     GroupSelection *group;
436     Bool           status;
437 
438     GROUP_SCREEN (s);
439     GROUP_DISPLAY (s->display);
440 
441     gs->painted = FALSE;
442     gs->vpX = s->x;
443     gs->vpY = s->y;
444 
445     if (gd->resizeInfo)
446     {
447 	mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
448     }
449     else
450     {
451 	for (group = gs->groups; group; group = group->next)
452 	{
453 	    if (group->changeState != NoTabChange ||
454 		group->tabbingState != NoTabbing)
455 	    {
456 		mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
457 	    }
458 	    else if (group->tabBar && (group->tabBar->state != PaintOff))
459 	    {
460 		mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
461 	    }
462 	}
463     }
464 
465     UNWRAP (gs, s, paintOutput);
466     status = (*s->paintOutput) (s, sAttrib, transform, region, output, mask);
467     WRAP (gs, s, paintOutput, groupPaintOutput);
468 
469     if (status && !gs->painted)
470     {
471 	if ((gs->grabState == ScreenGrabTabDrag) && gs->draggedSlot)
472 	{
473 	    CompTransform wTransform = *transform;
474 	    PaintState    state;
475 
476 	    GROUP_WINDOW (gs->draggedSlot->window);
477 
478 	    transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &wTransform);
479 
480 	    glPushMatrix ();
481 	    glLoadMatrixf (wTransform.m);
482 
483 	    /* prevent tab bar drawing.. */
484 	    state = gw->group->tabBar->state;
485 	    gw->group->tabBar->state = PaintOff;
486 	    groupPaintThumb (NULL, gs->draggedSlot, &wTransform, OPAQUE);
487 	    gw->group->tabBar->state = state;
488 
489 	    glPopMatrix ();
490 	}
491 	else  if (gs->grabState == ScreenGrabSelect)
492 	{
493 	    groupPaintSelectionOutline (s, sAttrib, transform, output, FALSE);
494 	}
495     }
496 
497     return status;
498 }
499 
500 /*
501  * groupaintTransformedOutput
502  *
503  */
504 void
groupPaintTransformedOutput(CompScreen * s,const ScreenPaintAttrib * sa,const CompTransform * transform,Region region,CompOutput * output,unsigned int mask)505 groupPaintTransformedOutput (CompScreen              *s,
506 			     const ScreenPaintAttrib *sa,
507 			     const CompTransform     *transform,
508 			     Region                  region,
509 			     CompOutput              *output,
510 			     unsigned int            mask)
511 {
512     GROUP_SCREEN (s);
513 
514     UNWRAP (gs, s, paintTransformedOutput);
515     (*s->paintTransformedOutput) (s, sa, transform, region, output, mask);
516     WRAP (gs, s, paintTransformedOutput, groupPaintTransformedOutput);
517 
518     if ((gs->vpX == s->x) && (gs->vpY == s->y))
519     {
520 	gs->painted = TRUE;
521 
522 	if ((gs->grabState == ScreenGrabTabDrag) &&
523 	    gs->draggedSlot && gs->dragged)
524 	{
525 	    CompTransform wTransform = *transform;
526 
527 	    (*s->applyScreenTransform) (s, sa, output, &wTransform);
528 	    transformToScreenSpace (s, output, -sa->zTranslate, &wTransform);
529 	    glPushMatrix ();
530 	    glLoadMatrixf (wTransform.m);
531 
532 	    groupPaintThumb (NULL, gs->draggedSlot, &wTransform, OPAQUE);
533 
534 	    glPopMatrix ();
535 	}
536 	else if (gs->grabState == ScreenGrabSelect)
537 	{
538 	    groupPaintSelectionOutline (s, sa, transform, output, TRUE);
539 	}
540     }
541 }
542 
543 /*
544  * groupDonePaintScreen
545  *
546  */
547 void
groupDonePaintScreen(CompScreen * s)548 groupDonePaintScreen (CompScreen *s)
549 {
550     GroupSelection *group;
551 
552     GROUP_SCREEN (s);
553 
554     UNWRAP (gs, s, donePaintScreen);
555     (*s->donePaintScreen) (s);
556     WRAP (gs, s, donePaintScreen, groupDonePaintScreen);
557 
558     for (group = gs->groups; group; group = group->next)
559     {
560 	if (group->tabbingState != NoTabbing)
561 	    damageScreen (s);
562 	else if (group->changeState != NoTabChange)
563 	    damageScreen (s);
564 	else if (group->tabBar)
565 	{
566 	    Bool needDamage = FALSE;
567 
568 	    if ((group->tabBar->state == PaintFadeIn) ||
569 		(group->tabBar->state == PaintFadeOut))
570 	    {
571 		needDamage = TRUE;
572 	    }
573 
574 	    if (group->tabBar->textLayer)
575 	    {
576 		if ((group->tabBar->textLayer->state == PaintFadeIn) ||
577 		    (group->tabBar->textLayer->state == PaintFadeOut))
578 		{
579 		    needDamage = TRUE;
580 		}
581 	    }
582 
583 	    if (group->tabBar->bgAnimation)
584 		needDamage = TRUE;
585 
586 	    if (gs->draggedSlot)
587 		needDamage = TRUE;
588 
589 	    if (needDamage)
590 		groupDamageTabBarRegion (group);
591 	}
592     }
593 }
594 
595 void
groupComputeGlowQuads(CompWindow * w,CompMatrix * matrix)596 groupComputeGlowQuads (CompWindow *w,
597 		       CompMatrix *matrix)
598 {
599     BoxRec            *box;
600     CompMatrix        *quadMatrix;
601     int               glowSize, glowOffset;
602     GroupGlowTypeEnum glowType;
603 
604     GROUP_WINDOW (w);
605 
606     if (groupGetGlow (w->screen) && matrix)
607     {
608 	if (!gw->glowQuads)
609 	    gw->glowQuads = malloc (NUM_GLOWQUADS * sizeof (GlowQuad));
610 	if (!gw->glowQuads)
611 	    return;
612     }
613     else
614     {
615 	if (gw->glowQuads)
616 	{
617 	    free (gw->glowQuads);
618 	    gw->glowQuads = NULL;
619 	}
620 	return;
621     }
622 
623     GROUP_DISPLAY (w->screen->display);
624 
625     glowSize = groupGetGlowSize (w->screen);
626     glowType = groupGetGlowType (w->screen);
627     glowOffset = (glowSize * gd->glowTextureProperties[glowType].glowOffset /
628 		  gd->glowTextureProperties[glowType].textureSize) + 1;
629 
630     /* Top left corner */
631     box = &gw->glowQuads[GLOWQUAD_TOPLEFT].box;
632     gw->glowQuads[GLOWQUAD_TOPLEFT].matrix = *matrix;
633     quadMatrix = &gw->glowQuads[GLOWQUAD_TOPLEFT].matrix;
634 
635     box->x1 = WIN_REAL_X (w) - glowSize + glowOffset;
636     box->y1 = WIN_REAL_Y (w) - glowSize + glowOffset;
637     box->x2 = WIN_REAL_X (w) + glowOffset;
638     box->y2 = WIN_REAL_Y (w) + glowOffset;
639 
640     quadMatrix->xx = 1.0f / glowSize;
641     quadMatrix->yy = -1.0f / glowSize;
642     quadMatrix->x0 = -(box->x1 * quadMatrix->xx);
643     quadMatrix->y0 = 1.0 -(box->y1 * quadMatrix->yy);
644 
645     box->x2 = MIN (WIN_REAL_X (w) + glowOffset,
646 		   WIN_REAL_X (w) + (WIN_REAL_WIDTH (w) / 2));
647     box->y2 = MIN (WIN_REAL_Y (w) + glowOffset,
648 		   WIN_REAL_Y (w) + (WIN_REAL_HEIGHT (w) / 2));
649 
650     /* Top right corner */
651     box = &gw->glowQuads[GLOWQUAD_TOPRIGHT].box;
652     gw->glowQuads[GLOWQUAD_TOPRIGHT].matrix = *matrix;
653     quadMatrix = &gw->glowQuads[GLOWQUAD_TOPRIGHT].matrix;
654 
655     box->x1 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset;
656     box->y1 = WIN_REAL_Y (w) - glowSize + glowOffset;
657     box->x2 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) + glowSize - glowOffset;
658     box->y2 = WIN_REAL_Y (w) + glowOffset;
659 
660     quadMatrix->xx = -1.0f / glowSize;
661     quadMatrix->yy = -1.0f / glowSize;
662     quadMatrix->x0 = 1.0 - (box->x1 * quadMatrix->xx);
663     quadMatrix->y0 = 1.0 - (box->y1 * quadMatrix->yy);
664 
665     box->x1 = MAX (WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset,
666 		   WIN_REAL_X (w) + (WIN_REAL_WIDTH (w) / 2));
667     box->y2 = MIN (WIN_REAL_Y (w) + glowOffset,
668 		   WIN_REAL_Y (w) + (WIN_REAL_HEIGHT (w) / 2));
669 
670     /* Bottom left corner */
671     box = &gw->glowQuads[GLOWQUAD_BOTTOMLEFT].box;
672     gw->glowQuads[GLOWQUAD_BOTTOMLEFT].matrix = *matrix;
673     quadMatrix = &gw->glowQuads[GLOWQUAD_BOTTOMLEFT].matrix;
674 
675     box->x1 = WIN_REAL_X (w) - glowSize + glowOffset;
676     box->y1 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset;
677     box->x2 = WIN_REAL_X (w) + glowOffset;
678     box->y2 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) + glowSize - glowOffset;
679 
680     quadMatrix->xx = 1.0f / glowSize;
681     quadMatrix->yy = 1.0f / glowSize;
682     quadMatrix->x0 = -(box->x1 * quadMatrix->xx);
683     quadMatrix->y0 = -(box->y1 * quadMatrix->yy);
684 
685     box->y1 = MAX (WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset,
686 		   WIN_REAL_Y (w) + (WIN_REAL_HEIGHT (w) / 2));
687     box->x2 = MIN (WIN_REAL_X (w) + glowOffset,
688 		   WIN_REAL_X (w) + (WIN_REAL_WIDTH (w) / 2));
689 
690     /* Bottom right corner */
691     box = &gw->glowQuads[GLOWQUAD_BOTTOMRIGHT].box;
692     gw->glowQuads[GLOWQUAD_BOTTOMRIGHT].matrix = *matrix;
693     quadMatrix = &gw->glowQuads[GLOWQUAD_BOTTOMRIGHT].matrix;
694 
695     box->x1 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset;
696     box->y1 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset;
697     box->x2 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) + glowSize - glowOffset;
698     box->y2 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) + glowSize - glowOffset;
699 
700     quadMatrix->xx = -1.0f / glowSize;
701     quadMatrix->yy = 1.0f / glowSize;
702     quadMatrix->x0 = 1.0 - (box->x1 * quadMatrix->xx);
703     quadMatrix->y0 = -(box->y1 * quadMatrix->yy);
704 
705     box->x1 = MAX (WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset,
706 		   WIN_REAL_X (w) + (WIN_REAL_WIDTH (w) / 2));
707     box->y1 = MAX (WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset,
708 		   WIN_REAL_Y (w) + (WIN_REAL_HEIGHT (w) / 2));
709 
710     /* Top edge */
711     box = &gw->glowQuads[GLOWQUAD_TOP].box;
712     gw->glowQuads[GLOWQUAD_TOP].matrix = *matrix;
713     quadMatrix = &gw->glowQuads[GLOWQUAD_TOP].matrix;
714 
715     box->x1 = WIN_REAL_X (w) + glowOffset;
716     box->y1 = WIN_REAL_Y (w) - glowSize + glowOffset;
717     box->x2 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset;
718     box->y2 = WIN_REAL_Y (w) + glowOffset;
719 
720     quadMatrix->xx = 0.0f;
721     quadMatrix->yy = -1.0f / glowSize;
722     quadMatrix->x0 = 1.0;
723     quadMatrix->y0 = 1.0 - (box->y1 * quadMatrix->yy);
724 
725     /* Bottom edge */
726     box = &gw->glowQuads[GLOWQUAD_BOTTOM].box;
727     gw->glowQuads[GLOWQUAD_BOTTOM].matrix = *matrix;
728     quadMatrix = &gw->glowQuads[GLOWQUAD_BOTTOM].matrix;
729 
730     box->x1 = WIN_REAL_X (w) + glowOffset;
731     box->y1 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset;
732     box->x2 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset;
733     box->y2 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) + glowSize - glowOffset;
734 
735     quadMatrix->xx = 0.0f;
736     quadMatrix->yy = 1.0f / glowSize;
737     quadMatrix->x0 = 1.0;
738     quadMatrix->y0 = -(box->y1 * quadMatrix->yy);
739 
740     /* Left edge */
741     box = &gw->glowQuads[GLOWQUAD_LEFT].box;
742     gw->glowQuads[GLOWQUAD_LEFT].matrix = *matrix;
743     quadMatrix = &gw->glowQuads[GLOWQUAD_LEFT].matrix;
744 
745     box->x1 = WIN_REAL_X (w) - glowSize + glowOffset;
746     box->y1 = WIN_REAL_Y (w) + glowOffset;
747     box->x2 = WIN_REAL_X (w) + glowOffset;
748     box->y2 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset;
749 
750     quadMatrix->xx = 1.0f / glowSize;
751     quadMatrix->yy = 0.0f;
752     quadMatrix->x0 = -(box->x1 * quadMatrix->xx);
753     quadMatrix->y0 = 0.0;
754 
755     /* Right edge */
756     box = &gw->glowQuads[GLOWQUAD_RIGHT].box;
757     gw->glowQuads[GLOWQUAD_RIGHT].matrix = *matrix;
758     quadMatrix = &gw->glowQuads[GLOWQUAD_RIGHT].matrix;
759 
760     box->x1 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) - glowOffset;
761     box->y1 = WIN_REAL_Y (w) + glowOffset;
762     box->x2 = WIN_REAL_X (w) + WIN_REAL_WIDTH (w) + glowSize - glowOffset;
763     box->y2 = WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) - glowOffset;
764 
765     quadMatrix->xx = -1.0f / glowSize;
766     quadMatrix->yy = 0.0f;
767     quadMatrix->x0 = 1.0 - (box->x1 * quadMatrix->xx);
768     quadMatrix->y0 = 0.0;
769 }
770 
771 /*
772  * groupDrawWindow
773  *
774  */
775 Bool
groupDrawWindow(CompWindow * w,const CompTransform * transform,const FragmentAttrib * attrib,Region region,unsigned int mask)776 groupDrawWindow (CompWindow           *w,
777 		 const CompTransform  *transform,
778 		 const FragmentAttrib *attrib,
779 		 Region               region,
780 		 unsigned int         mask)
781 {
782     Bool       status;
783     CompScreen *s = w->screen;
784 
785     GROUP_WINDOW (w);
786     GROUP_SCREEN (s);
787 
788     if (gw->group && (gw->group->nWins > 1) && gw->glowQuads)
789     {
790 	if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
791 	    region = &infiniteRegion;
792 
793 	if (region->numRects)
794 	{
795 	    REGION box;
796 	    int    i;
797 
798 	    box.rects = &box.extents;
799 	    box.numRects = 1;
800 
801 	    w->vCount = w->indexCount = 0;
802 
803 	    for (i = 0; i < NUM_GLOWQUADS; i++)
804 	    {
805 		box.extents = gw->glowQuads[i].box;
806 
807 		if (box.extents.x1 < box.extents.x2 &&
808 		    box.extents.y1 < box.extents.y2)
809 		{
810 		    (*s->addWindowGeometry) (w, &gw->glowQuads[i].matrix,
811 					     1, &box, region);
812 		}
813 	    }
814 
815 	    if (w->vCount)
816 	    {
817 		FragmentAttrib fAttrib = *attrib;
818 		GLushort       average;
819 		GLushort       color[3] = {gw->group->color[0],
820 		                           gw->group->color[1],
821 		                           gw->group->color[2]};
822 
823 		/* Apply brightness to color. */
824 		color[0] *= (float)attrib->brightness / BRIGHT;
825 		color[1] *= (float)attrib->brightness / BRIGHT;
826 		color[2] *= (float)attrib->brightness / BRIGHT;
827 
828 		/* Apply saturation to color. */
829 		average = (color[0] + color[1] + color[2]) / 3;
830 		color[0] = average + (color[0] - average) *
831 		           attrib->saturation / COLOR;
832 		color[1] = average + (color[1] - average) *
833 		           attrib->saturation / COLOR;
834 		color[2] = average + (color[2] - average) *
835 		           attrib->saturation / COLOR;
836 
837 		fAttrib.opacity = OPAQUE;
838 		fAttrib.saturation = COLOR;
839 		fAttrib.brightness = BRIGHT;
840 
841 		screenTexEnvMode (s, GL_MODULATE);
842 		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
843 		glColor4us (color[0], color[1], color[2], attrib->opacity);
844 
845 		/* we use PAINT_WINDOW_TRANSFORMED_MASK here to force
846 		   the usage of a good texture filter */
847 		(*s->drawWindowTexture) (w, &gs->glowTexture, &fAttrib,
848 					 mask | PAINT_WINDOW_BLEND_MASK |
849 					 PAINT_WINDOW_TRANSLUCENT_MASK |
850 					 PAINT_WINDOW_TRANSFORMED_MASK);
851 
852 		glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
853 		screenTexEnvMode (s, GL_REPLACE);
854 		glColor4usv (defaultColor);
855 	    }
856 	}
857     }
858 
859     UNWRAP (gs, s, drawWindow);
860     status = (*s->drawWindow) (w, transform, attrib, region, mask);
861     WRAP (gs, s, drawWindow, groupDrawWindow);
862 
863     return status;
864 }
865 
866 void
groupGetStretchRectangle(CompWindow * w,BoxPtr pBox,float * xScaleRet,float * yScaleRet)867 groupGetStretchRectangle (CompWindow *w,
868 			  BoxPtr     pBox,
869 			  float      *xScaleRet,
870 			  float      *yScaleRet)
871 {
872     BoxRec box;
873     int    width, height;
874     float  xScale, yScale;
875 
876     GROUP_WINDOW (w);
877 
878     box.x1 = gw->resizeGeometry->x - w->input.left;
879     box.y1 = gw->resizeGeometry->y - w->input.top;
880     box.x2 = gw->resizeGeometry->x + gw->resizeGeometry->width +
881 	     w->serverBorderWidth * 2 + w->input.right;
882 
883     if (w->shaded)
884     {
885 	box.y2 = gw->resizeGeometry->y + w->height + w->input.bottom;
886     }
887     else
888     {
889 	box.y2 = gw->resizeGeometry->y + gw->resizeGeometry->height +
890 	         w->serverBorderWidth * 2 + w->input.bottom;
891     }
892 
893     width  = w->width  + w->input.left + w->input.right;
894     height = w->height + w->input.top  + w->input.bottom;
895 
896     xScale = (width)  ? (box.x2 - box.x1) / (float) width  : 1.0f;
897     yScale = (height) ? (box.y2 - box.y1) / (float) height : 1.0f;
898 
899     pBox->x1 = box.x1 - (w->output.left - w->input.left) * xScale;
900     pBox->y1 = box.y1 - (w->output.top - w->input.top) * yScale;
901     pBox->x2 = box.x2 + w->output.right * xScale;
902     pBox->y2 = box.y2 + w->output.bottom * yScale;
903 
904     if (xScaleRet)
905 	*xScaleRet = xScale;
906     if (yScaleRet)
907 	*yScaleRet = yScale;
908 }
909 
910 void
groupDamagePaintRectangle(CompScreen * s,BoxPtr pBox)911 groupDamagePaintRectangle (CompScreen *s,
912 			   BoxPtr     pBox)
913 {
914     REGION reg;
915 
916     reg.rects    = &reg.extents;
917     reg.numRects = 1;
918 
919     reg.extents = *pBox;
920 
921     reg.extents.x1 -= 1;
922     reg.extents.y1 -= 1;
923     reg.extents.x2 += 1;
924     reg.extents.y2 += 1;
925 
926     damageScreenRegion (s, &reg);
927 }
928 
929 /*
930  * groupPaintWindow
931  *
932  */
933 Bool
groupPaintWindow(CompWindow * w,const WindowPaintAttrib * attrib,const CompTransform * transform,Region region,unsigned int mask)934 groupPaintWindow (CompWindow              *w,
935 		  const WindowPaintAttrib *attrib,
936 		  const CompTransform     *transform,
937 		  Region                  region,
938 		  unsigned int            mask)
939 {
940     Bool       status;
941     Bool       doRotate, doTabbing, showTabbar;
942     CompScreen *s = w->screen;
943 
944     GROUP_SCREEN (s);
945     GROUP_WINDOW (w);
946 
947     if (gw->group)
948     {
949 	GroupSelection *group = gw->group;
950 
951 	doRotate = (group->changeState != NoTabChange) &&
952 	           HAS_TOP_WIN (group) && HAS_PREV_TOP_WIN (group) &&
953 	           (IS_TOP_TAB (w, group) || IS_PREV_TOP_TAB (w, group));
954 
955 	doTabbing = (gw->animateState & (IS_ANIMATED | FINISHED_ANIMATION)) &&
956 	            !(IS_TOP_TAB (w, group) &&
957 		      (group->tabbingState == Tabbing));
958 
959 	showTabbar = group->tabBar && (group->tabBar->state != PaintOff) &&
960 	             (((IS_TOP_TAB (w, group)) &&
961 		       ((group->changeState == NoTabChange) ||
962 			(group->changeState == TabChangeNewIn))) ||
963 		      (IS_PREV_TOP_TAB (w, group) &&
964 		       (group->changeState == TabChangeOldOut)));
965     }
966     else
967     {
968 	doRotate   = FALSE;
969 	doTabbing  = FALSE;
970 	showTabbar = FALSE;
971     }
972 
973     if (gw->windowHideInfo)
974 	mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
975 
976     if (gw->inSelection || gw->resizeGeometry || doRotate ||
977 	doTabbing || showTabbar)
978     {
979 	WindowPaintAttrib wAttrib = *attrib;
980 	CompTransform     wTransform = *transform;
981 	float             animProgress = 0.0f;
982 	int               drawnPosX = 0, drawnPosY = 0;
983 
984 	if (gw->inSelection)
985 	{
986 	    wAttrib.opacity    = OPAQUE * groupGetSelectOpacity (s) / 100;
987 	    wAttrib.saturation = COLOR * groupGetSelectSaturation (s) / 100;
988 	    wAttrib.brightness = BRIGHT * groupGetSelectBrightness (s) / 100;
989 	}
990 
991 	if (doTabbing)
992 	{
993 	    /* fade the window out */
994 	    float progress;
995 	    int   distanceX, distanceY;
996 	    float origDistance, distance;
997 
998 	    if (gw->animateState & FINISHED_ANIMATION)
999 	    {
1000 		drawnPosX = gw->destination.x;
1001 		drawnPosY = gw->destination.y;
1002 	    }
1003 	    else
1004 	    {
1005 		drawnPosX = gw->orgPos.x + gw->tx;
1006 		drawnPosY = gw->orgPos.y + gw->ty;
1007 	    }
1008 
1009 	    distanceX = drawnPosX - gw->destination.x;
1010 	    distanceY = drawnPosY - gw->destination.y;
1011 	    distance = sqrt (pow (distanceX, 2) + pow (distanceY, 2));
1012 
1013 	    distanceX = (gw->orgPos.x - gw->destination.x);
1014 	    distanceY = (gw->orgPos.y - gw->destination.y);
1015 	    origDistance = sqrt (pow (distanceX, 2) + pow (distanceY, 2));
1016 
1017 	    if (!distanceX && !distanceY)
1018 		progress = 1.0f;
1019 	    else
1020 		progress = 1.0f - (distance / origDistance);
1021 
1022 	    animProgress = progress;
1023 
1024 	    progress = MAX (progress, 0.0f);
1025 	    if (gw->group->tabbingState == Tabbing)
1026 		progress = 1.0f - progress;
1027 
1028 	    wAttrib.opacity = (float)wAttrib.opacity * progress;
1029 	}
1030 
1031 	if (doRotate)
1032 	{
1033 	    float timeLeft = gw->group->changeAnimationTime;
1034 	    int   animTime = groupGetChangeAnimationTime (s) * 500;
1035 
1036 	    if (gw->group->changeState == TabChangeOldOut)
1037 		timeLeft += animTime;
1038 
1039 	    /* 0 at the beginning, 1 at the end */
1040 	    animProgress = 1 - (timeLeft / (2 * animTime));
1041 	}
1042 
1043 	if (gw->resizeGeometry)
1044 	{
1045 	    int    xOrigin, yOrigin;
1046 	    float  xScale, yScale;
1047 	    BoxRec box;
1048 
1049 	    groupGetStretchRectangle (w, &box, &xScale, &yScale);
1050 
1051 	    xOrigin = w->attrib.x - w->input.left;
1052 	    yOrigin = w->attrib.y - w->input.top;
1053 
1054 	    matrixTranslate (&wTransform, xOrigin, yOrigin, 0.0f);
1055 	    matrixScale (&wTransform, xScale, yScale, 1.0f);
1056 	    matrixTranslate (&wTransform,
1057 			     (gw->resizeGeometry->x - w->attrib.x) /
1058 			     xScale - xOrigin,
1059 			     (gw->resizeGeometry->y - w->attrib.y) /
1060 			     yScale - yOrigin,
1061 			     0.0f);
1062 
1063 	    mask |= PAINT_WINDOW_TRANSFORMED_MASK;
1064 	}
1065 	else if (doRotate || doTabbing)
1066 	{
1067 	    float      animWidth, animHeight;
1068 	    float      animScaleX, animScaleY;
1069 	    CompWindow *morphBase, *morphTarget;
1070 
1071 	    if (doTabbing)
1072 	    {
1073 		if (gw->group->tabbingState == Tabbing)
1074 		{
1075 		    morphBase   = w;
1076 		    morphTarget = TOP_TAB (gw->group);
1077 		}
1078 		else
1079 		{
1080 		    morphTarget = w;
1081 		    if (HAS_TOP_WIN (gw->group))
1082 			morphBase = TOP_TAB (gw->group);
1083 		    else
1084 			morphBase = gw->group->lastTopTab;
1085 		}
1086 	    }
1087 	    else
1088 	    {
1089 		morphBase   = PREV_TOP_TAB (gw->group);
1090 		morphTarget = TOP_TAB (gw->group);
1091 	    }
1092 
1093 	    animWidth = (1 - animProgress) * WIN_REAL_WIDTH (morphBase) +
1094 		        animProgress * WIN_REAL_WIDTH (morphTarget);
1095 	    animHeight = (1 - animProgress) * WIN_REAL_HEIGHT (morphBase) +
1096 		         animProgress * WIN_REAL_HEIGHT (morphTarget);
1097 
1098 	    animWidth = MAX (1.0f, animWidth);
1099 	    animHeight = MAX (1.0f, animHeight);
1100 	    animScaleX = animWidth / WIN_REAL_WIDTH (w);
1101 	    animScaleY = animHeight / WIN_REAL_HEIGHT (w);
1102 
1103 	    if (doRotate)
1104 		matrixScale (&wTransform, 1.0f, 1.0f, 1.0f / s->width);
1105 
1106 	    matrixTranslate (&wTransform,
1107 			     WIN_REAL_X (w) + WIN_REAL_WIDTH (w) / 2.0f,
1108 			     WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) / 2.0f,
1109 			     0.0f);
1110 
1111 	    if (doRotate)
1112 	    {
1113 		float rotateAngle = animProgress * 180.0f;
1114 		if (IS_TOP_TAB (w, gw->group))
1115 		    rotateAngle += 180.0f;
1116 
1117 		if (gw->group->changeAnimationDirection < 0)
1118 		    rotateAngle *= -1.0f;
1119 
1120 		matrixRotate (&wTransform, rotateAngle, 0.0f, 1.0f, 0.0f);
1121 	    }
1122 
1123 	    if (doTabbing)
1124 		matrixTranslate (&wTransform,
1125 				 drawnPosX - WIN_X (w),
1126 				 drawnPosY - WIN_Y (w), 0.0f);
1127 
1128 	    matrixScale (&wTransform, animScaleX, animScaleY, 1.0f);
1129 
1130 	    matrixTranslate (&wTransform,
1131 			     -(WIN_REAL_X (w) + WIN_REAL_WIDTH (w) / 2.0f),
1132 			     -(WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) / 2.0f),
1133 			     0.0f);
1134 
1135 	    mask |= PAINT_WINDOW_TRANSFORMED_MASK;
1136 	}
1137 
1138 	UNWRAP (gs, s, paintWindow);
1139 	status = (*s->paintWindow) (w, &wAttrib, &wTransform, region, mask);
1140 
1141 	if (showTabbar)
1142 	    groupPaintTabBar (gw->group, &wAttrib, &wTransform, mask, region);
1143 
1144 	WRAP (gs, s, paintWindow, groupPaintWindow);
1145     }
1146     else
1147     {
1148 	UNWRAP (gs, s, paintWindow);
1149 	status = (*s->paintWindow) (w, attrib, transform, region, mask);
1150 	WRAP (gs, s, paintWindow, groupPaintWindow);
1151     }
1152 
1153     return status;
1154 }
1155