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 = ®.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, ®);
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