1 /*
2 *
3 * Compiz shift switcher plugin
4 *
5 * shift.c
6 *
7 * Copyright : (C) 2007 by Dennis Kasprzyk
8 * E-mail : onestone@opencompositing.org
9 *
10 *
11 * Based on ring.c:
12 * Copyright : (C) 2007 by Danny Baumann
13 * E-mail : maniac@opencompositing.org
14 *
15 * Based on scale.c and switcher.c:
16 * Copyright : (C) 2007 David Reveman
17 * E-mail : davidr@novell.com
18 *
19 * Rounded corner drawing taken from wall.c:
20 * Copyright : (C) 2007 Robert Carr
21 * E-mail : racarr@beryl-project.org
22 *
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * as published by the Free Software Foundation; either version 2
26 * of the License, or (at your option) any later version.
27 *
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
32 *
33 */
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <math.h>
40 #include <sys/time.h>
41
42 #include <X11/Xatom.h>
43 #include <X11/cursorfont.h>
44
45 #include <compiz-core.h>
46 #include <compiz-text.h>
47 #include "shift_options.h"
48
49 typedef enum {
50 ShiftStateNone = 0,
51 ShiftStateOut,
52 ShiftStateSwitching,
53 ShiftStateFinish,
54 ShiftStateIn
55 } ShiftState;
56
57 typedef enum {
58 ShiftTypeNormal = 0,
59 ShiftTypeGroup,
60 ShiftTypeAll
61 } ShiftType;
62
63 static int displayPrivateIndex;
64
65 typedef struct _ShiftSlot {
66 int x, y; /* thumb center coordinates */
67 float z;
68 float scale; /* size scale (fit to maximal thumb size */
69 float opacity;
70 float rotation;
71
72 GLfloat tx;
73 GLfloat ty;
74
75 Bool primary;
76
77 } ShiftSlot;
78
79 typedef struct _ShiftDrawSlot {
80 CompWindow *w;
81 ShiftSlot *slot;
82 float distance;
83 } ShiftDrawSlot;
84
85 typedef struct _ShiftDisplay {
86 int screenPrivateIndex;
87 HandleEventProc handleEvent;
88
89 TextFunc *textFunc;
90
91 KeyCode leftKey;
92 KeyCode rightKey;
93 KeyCode upKey;
94 KeyCode downKey;
95 } ShiftDisplay;
96
97 typedef struct _ShiftScreen {
98 int windowPrivateIndex;
99
100 PreparePaintScreenProc preparePaintScreen;
101 DonePaintScreenProc donePaintScreen;
102 PaintScreenProc paintScreen;
103 PaintOutputProc paintOutput;
104 PaintWindowProc paintWindow;
105 DamageWindowRectProc damageWindowRect;
106
107 int grabIndex;
108
109 ShiftState state;
110 ShiftType type;
111
112 Bool moreAdjust;
113 Bool moveAdjust;
114
115 float mvTarget;
116 float mvAdjust;
117 GLfloat mvVelocity;
118 Bool invert;
119
120 Cursor cursor;
121
122 /* only used for sorting */
123 CompWindow **windows;
124 int windowsSize;
125 int nWindows;
126
127 ShiftDrawSlot *drawSlots;
128 int slotsSize;
129 int nSlots;
130 ShiftDrawSlot *activeSlot;
131
132 Window clientLeader;
133
134 CompWindow *selectedWindow;
135
136 /* text display support */
137 CompTextData *textData;
138
139 CompMatch match;
140 CompMatch *currentMatch;
141
142 CompOutput *output;
143 int usedOutput;
144
145 float anim;
146 float animVelocity;
147
148 float reflectBrightness;
149 Bool reflectActive;
150
151 int buttonPressTime;
152 Bool buttonPressed;
153 int startX;
154 int startY;
155 float startTarget;
156 float lastTitle;
157
158 Bool paintingAbove;
159
160 Bool canceled;
161
162 int maxThumbWidth;
163 int maxThumbHeight;
164 } ShiftScreen;
165
166 typedef struct _ShiftWindow {
167 ShiftSlot slots[2];
168
169 float opacity;
170 float brightness;
171 float opacityVelocity;
172 float brightnessVelocity;
173
174 Bool active;
175 } ShiftWindow;
176
177 #define PI 3.1415926
178 #define ICON_SIZE 64
179 #define MAX_ICON_SIZE 256
180
181 #define GET_SHIFT_DISPLAY(d) \
182 ((ShiftDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
183
184 #define SHIFT_DISPLAY(d) \
185 ShiftDisplay *sd = GET_SHIFT_DISPLAY (d)
186
187 #define GET_SHIFT_SCREEN(s, sd) \
188 ((ShiftScreen *) (s)->base.privates[(sd)->screenPrivateIndex].ptr)
189
190 #define SHIFT_SCREEN(s) \
191 ShiftScreen *ss = GET_SHIFT_SCREEN (s, GET_SHIFT_DISPLAY (s->display))
192
193 #define GET_SHIFT_WINDOW(w, ss) \
194 ((ShiftWindow *) (w)->base.privates[(ss)->windowPrivateIndex].ptr)
195
196 #define SHIFT_WINDOW(w) \
197 ShiftWindow *sw = GET_SHIFT_WINDOW (w, \
198 GET_SHIFT_SCREEN (w->screen, \
199 GET_SHIFT_DISPLAY (w->screen->display)))
200
201 static void
shiftActivateEvent(CompScreen * s,Bool activating)202 shiftActivateEvent (CompScreen *s,
203 Bool activating)
204 {
205 CompOption o[2];
206
207 o[0].type = CompOptionTypeInt;
208 o[0].name = "root";
209 o[0].value.i = s->root;
210
211 o[1].type = CompOptionTypeBool;
212 o[1].name = "active";
213 o[1].value.b = activating;
214
215 (*s->display->handleCompizEvent) (s->display, "shift", "activate", o, 2);
216 }
217
218 static Bool
isShiftWin(CompWindow * w)219 isShiftWin (CompWindow *w)
220 {
221 SHIFT_SCREEN (w->screen);
222
223 if (w->destroyed)
224 return FALSE;
225
226 if (w->attrib.override_redirect)
227 return FALSE;
228
229 if (w->wmType & (CompWindowTypeDockMask | CompWindowTypeDesktopMask))
230 return FALSE;
231
232 if (!w->mapNum || w->attrib.map_state != IsViewable)
233 {
234 if (shiftGetMinimized (w->screen))
235 {
236 if (!w->minimized && !w->inShowDesktopMode && !w->shaded)
237 return FALSE;
238 }
239 else
240 return FALSE;
241 }
242
243 if (ss->type == ShiftTypeNormal)
244 {
245 if (!w->mapNum || w->attrib.map_state != IsViewable)
246 {
247 if (w->serverX + w->width <= 0 ||
248 w->serverY + w->height <= 0 ||
249 w->serverX >= w->screen->width ||
250 w->serverY >= w->screen->height)
251 return FALSE;
252 }
253 else
254 {
255 if (!(*w->screen->focusWindow) (w))
256 return FALSE;
257 }
258 }
259 else if (ss->type == ShiftTypeGroup &&
260 ss->clientLeader != w->clientLeader &&
261 ss->clientLeader != w->id)
262 {
263 return FALSE;
264 }
265
266 if (w->state & CompWindowStateSkipTaskbarMask)
267 return FALSE;
268
269 if (!matchEval (ss->currentMatch, w))
270 return FALSE;
271
272 return TRUE;
273 }
274
275 static void
shiftFreeWindowTitle(CompScreen * s)276 shiftFreeWindowTitle (CompScreen *s)
277 {
278 SHIFT_SCREEN (s);
279 SHIFT_DISPLAY (s->display);
280
281 if (!ss->textData)
282 return;
283
284 (sd->textFunc->finiTextData) (s, ss->textData);
285 ss->textData = NULL;
286 }
287
288 static void
shiftRenderWindowTitle(CompScreen * s)289 shiftRenderWindowTitle (CompScreen *s)
290 {
291 CompTextAttrib tA;
292 int ox1, ox2, oy1, oy2;
293
294 SHIFT_SCREEN (s);
295 SHIFT_DISPLAY (s->display);
296
297 shiftFreeWindowTitle (s);
298
299 if (!sd->textFunc)
300 return;
301
302 if (!shiftGetWindowTitle (s))
303 return;
304
305 if (shiftGetMultioutputMode (s) == MultioutputModeOneBigSwitcher)
306 {
307 ox1 = oy1 = 0;
308 ox2 = s->width;
309 oy2 = s->height;
310 }
311 else
312 getCurrentOutputExtents (s, &ox1, &oy1, &ox2, &oy2);
313
314 /* 75% of the output device as maximum width */
315 tA.maxWidth = (ox2 - ox1) * 3 / 4;
316 tA.maxHeight = 100;
317
318 tA.family = "Sans";
319 tA.size = shiftGetTitleFontSize (s);
320 tA.color[0] = shiftGetTitleFontColorRed (s);
321 tA.color[1] = shiftGetTitleFontColorGreen (s);
322 tA.color[2] = shiftGetTitleFontColorBlue (s);
323 tA.color[3] = shiftGetTitleFontColorAlpha (s);
324
325 tA.flags = CompTextFlagWithBackground | CompTextFlagEllipsized;
326 if (shiftGetTitleFontBold (s))
327 tA.flags |= CompTextFlagStyleBold;
328
329 tA.bgHMargin = 15;
330 tA.bgVMargin = 15;
331 tA.bgColor[0] = shiftGetTitleBackColorRed (s);
332 tA.bgColor[1] = shiftGetTitleBackColorGreen (s);
333 tA.bgColor[2] = shiftGetTitleBackColorBlue (s);
334 tA.bgColor[3] = shiftGetTitleBackColorAlpha (s);
335
336 ss->textData = (sd->textFunc->renderWindowTitle) (s,
337 (ss->selectedWindow ?
338 ss->selectedWindow->id :
339 None),
340 ss->type == ShiftTypeAll,
341 &tA);
342 }
343
344 static void
shiftDrawWindowTitle(CompScreen * s)345 shiftDrawWindowTitle (CompScreen *s)
346 {
347 float width, height, border = 10.0f;
348 int ox1, ox2, oy1, oy2;
349
350 SHIFT_SCREEN (s);
351 SHIFT_DISPLAY (s->display);
352
353 width = ss->textData->width;
354 height = ss->textData->height;
355
356 if (shiftGetMultioutputMode (s) == MultioutputModeOneBigSwitcher)
357 {
358 ox1 = oy1 = 0;
359 ox2 = s->width;
360 oy2 = s->height;
361 }
362 else
363 {
364 ox1 = s->outputDev[ss->usedOutput].region.extents.x1;
365 ox2 = s->outputDev[ss->usedOutput].region.extents.x2;
366 oy1 = s->outputDev[ss->usedOutput].region.extents.y1;
367 oy2 = s->outputDev[ss->usedOutput].region.extents.y2;
368 }
369
370 float x = ox1 + ((ox2 - ox1) / 2) - ((int)ss->textData->width / 2);
371 float y;
372
373 /* assign y (for the lower corner!) according to the setting */
374 switch (shiftGetTitleTextPlacement (s))
375 {
376 case TitleTextPlacementCenteredOnScreen:
377 y = oy1 + ((oy2 - oy1) / 2) + (height / 2);
378 break;
379 case TitleTextPlacementAbove:
380 case TitleTextPlacementBelow:
381 {
382 XRectangle workArea;
383 getWorkareaForOutput (s, s->currentOutputDev, &workArea);
384
385 if (shiftGetTitleTextPlacement (s) ==
386 TitleTextPlacementAbove)
387 y = oy1 + workArea.y + (2 * border) + height;
388 else
389 y = oy1 + workArea.y + workArea.height - (2 * border);
390 }
391 break;
392 default:
393 return;
394 }
395
396 (sd->textFunc->drawText) (s, ss->textData, floor (x), floor (y), 1.0f);
397 }
398
399 static Bool
shiftPaintWindow(CompWindow * w,const WindowPaintAttrib * attrib,const CompTransform * transform,Region region,unsigned int mask)400 shiftPaintWindow (CompWindow *w,
401 const WindowPaintAttrib *attrib,
402 const CompTransform *transform,
403 Region region,
404 unsigned int mask)
405 {
406 CompScreen *s = w->screen;
407 Bool status;
408
409 SHIFT_SCREEN (s);
410 SHIFT_WINDOW (w);
411
412 if (ss->state != ShiftStateNone && !ss->paintingAbove)
413 {
414 WindowPaintAttrib sAttrib = *attrib;
415 Bool scaled = FALSE;
416
417 if (w->mapNum)
418 {
419 if (!w->texture->pixmap && !w->bindFailed)
420 bindWindow (w);
421 }
422
423
424 if (sw->active)
425 scaled = (ss->activeSlot != NULL);
426
427 if (sw->opacity > 0.01 && (ss->activeSlot == NULL))
428 {
429 sAttrib.brightness = sAttrib.brightness * sw->brightness;
430 sAttrib.opacity = sAttrib.opacity * sw->opacity;
431 }
432 else
433 mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
434
435 if (sw->active &&
436 (ss->output->id == ss->usedOutput || ss->output->id == ~0))
437 mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
438
439
440 UNWRAP (ss, s, paintWindow);
441 status = (*s->paintWindow) (w, &sAttrib, transform, region, mask);
442 WRAP (ss, s, paintWindow, shiftPaintWindow);
443
444 if (scaled && w->texture->pixmap)
445 {
446 FragmentAttrib fragment;
447 CompTransform wTransform = *transform;
448 ShiftSlot *slot = ss->activeSlot->slot;
449
450 float sx = ss->anim * slot->tx;
451 float sy = ss->anim * slot->ty;
452 float sz = ss->anim * slot->z;
453 float srot = (ss->anim * slot->rotation);
454 float anim = MIN (1.0, MAX (0.0, ss->anim));
455
456 float sscale;
457 float sopacity;
458
459
460 if (slot->primary)
461 sscale = (ss->anim * slot->scale) + (1 - ss->anim);
462 else
463 sscale = ss->anim * slot->scale;
464
465 if (slot->primary && !ss->reflectActive)
466 sopacity = (ss->anim * slot->opacity) + (1 - ss->anim);
467 else
468 sopacity = anim * anim * slot->opacity;
469
470 if (sopacity <= 0.05)
471 return status;
472
473 if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
474 return FALSE;
475
476 initFragmentAttrib (&fragment, attrib);
477
478 fragment.opacity = (float)fragment.opacity * sopacity;
479 fragment.brightness = (float)fragment.brightness *
480 ss->reflectBrightness;
481
482 if (w->alpha || fragment.opacity != OPAQUE)
483 mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
484
485 matrixTranslate (&wTransform, sx, sy, sz);
486
487 matrixTranslate (&wTransform,
488 w->attrib.x + (w->attrib.width * sscale / 2),
489 w->attrib.y + (w->attrib.height * sscale / 2.0),
490 0.0f);
491
492 matrixScale (&wTransform, ss->output->width, -ss->output->height,
493 1.0f);
494
495 matrixRotate (&wTransform, srot, 0.0, 1.0, 0.0);
496
497 matrixScale (&wTransform, 1.0f / ss->output->width,
498 -1.0f / ss->output->height, 1.0f);
499
500 matrixScale (&wTransform, sscale, sscale, 1.0f);
501 matrixTranslate (&wTransform, -w->attrib.x - (w->width / 2),
502 -w->attrib.y - (w->attrib.height / 2), 0.0f);
503
504 glPushMatrix ();
505 glLoadMatrixf (wTransform.m);
506
507 (*s->drawWindow) (w, &wTransform, &fragment, region,
508 mask | PAINT_WINDOW_TRANSFORMED_MASK);
509
510 glPopMatrix ();
511 }
512
513 if (scaled && ((shiftGetOverlayIcon (s) != OverlayIconNone) ||
514 !w->texture->pixmap))
515 {
516 CompIcon *icon;
517
518 icon = getWindowIcon (w, MAX_ICON_SIZE, MAX_ICON_SIZE);
519 if (!icon)
520 icon = w->screen->defaultIcon;
521
522 if (icon && (icon->texture.name || iconToTexture (w->screen, icon)))
523 {
524 REGION iconReg;
525 float scale;
526 float x, y;
527 int width, height;
528 int scaledWinWidth, scaledWinHeight;
529 ShiftOverlayIconEnum iconOverlay = shiftGetOverlayIcon (s);
530 ShiftSlot *slot = ss->activeSlot->slot;
531
532 float sx = ss->anim * slot->tx;
533 float sy = ss->anim * slot->ty;
534 float sz = ss->anim * slot->z;
535 float srot = (ss->anim * slot->rotation);
536 float sopacity = ss->anim * slot->opacity;
537
538 float sscale;
539
540 if (slot->primary)
541 sscale = (ss->anim * slot->scale) + (1 - ss->anim);
542 else
543 sscale = ss->anim * ss->anim * slot->scale;
544
545 scaledWinWidth = w->attrib.width * sscale;
546 scaledWinHeight = w->attrib.height * sscale;
547
548 if (!w->texture->pixmap)
549 iconOverlay = OverlayIconBig;
550
551 switch (iconOverlay)
552 {
553 case OverlayIconNone:
554 case OverlayIconEmblem:
555 scale = MIN (((float) ICON_SIZE / icon->width),
556 ((float) ICON_SIZE / icon->height));
557 break;
558 case OverlayIconBig:
559 default:
560 if (w->texture->pixmap)
561 {
562 /* only change opacity if not painting an
563 icon for a minimized window */
564 sAttrib.opacity /= 3;
565 scale = MIN (((float) scaledWinWidth / icon->width),
566 ((float) scaledWinHeight / icon->height));
567 }
568 else
569 {
570 scale = MIN (((float) 128 / icon->width),
571 ((float) 128 / icon->height));
572 }
573 break;
574 }
575
576 width = icon->width * scale;
577 height = icon->height * scale;
578
579 switch (iconOverlay)
580 {
581 case OverlayIconNone:
582 case OverlayIconEmblem:
583 x = scaledWinWidth - width;
584 y = scaledWinHeight - height;
585 break;
586 case OverlayIconBig:
587 default:
588 x = scaledWinWidth / 2 - width / 2;
589 if (w->texture->pixmap)
590 y = scaledWinHeight / 2 - height / 2;
591 else
592 y = scaledWinHeight - height;
593 break;
594 }
595
596 mask |= PAINT_WINDOW_BLEND_MASK | PAINT_WINDOW_TRANSFORMED_MASK;
597
598 iconReg.rects = &iconReg.extents;
599 iconReg.numRects = 1;
600
601 iconReg.extents.x1 = 0;
602 iconReg.extents.y1 = 0;
603 iconReg.extents.x2 = icon->width;
604 iconReg.extents.y2 = icon->height;
605
606 w->vCount = w->indexCount = 0;
607 (*w->screen->addWindowGeometry) (w, &icon->texture.matrix, 1,
608 &iconReg, &infiniteRegion);
609
610 if (w->vCount)
611 {
612 FragmentAttrib fragment;
613 CompTransform wTransform = *transform;
614
615 if (!w->texture->pixmap)
616 sAttrib.opacity = w->paint.opacity;
617
618 initFragmentAttrib (&fragment, &sAttrib);
619
620 fragment.opacity = (float)fragment.opacity * sopacity;
621 fragment.brightness = (float)fragment.brightness *
622 ss->reflectBrightness;
623
624 matrixTranslate (&wTransform, sx, sy, sz);
625
626 matrixTranslate (&wTransform, w->attrib.x +
627 (w->width * sscale / 2),
628 w->attrib.y +
629 (w->attrib.height * sscale / 2.0), 0.0f);
630
631 matrixScale (&wTransform, ss->output->width,
632 -ss->output->height, 1.0f);
633
634 matrixRotate (&wTransform, srot, 0.0, 1.0, 0.0);
635
636 matrixScale (&wTransform, 1.0f / ss->output->width,
637 -1.0f / ss->output->height, 1.0f);
638
639 matrixTranslate (&wTransform, x -
640 (w->attrib.width * sscale / 2), y -
641 (w->attrib.height * sscale / 2.0), 0.0f);
642 matrixScale (&wTransform, scale, scale, 1.0f);
643
644 glPushMatrix ();
645 glLoadMatrixf (wTransform.m);
646
647 (*w->screen->drawWindowTexture) (w,
648 &icon->texture, &fragment,
649 mask);
650
651 glPopMatrix ();
652 }
653 }
654 }
655
656 }
657 else
658 {
659 WindowPaintAttrib sAttrib = *attrib;
660
661 if (ss->paintingAbove)
662 {
663 sAttrib.opacity = sAttrib.opacity * (1.0 - ss->anim);
664
665 if (ss->anim > 0.99)
666 mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
667 }
668
669 UNWRAP (ss, s, paintWindow);
670 status = (*s->paintWindow) (w, &sAttrib, transform, region, mask);
671 WRAP (ss, s, paintWindow, shiftPaintWindow);
672 }
673
674 return status;
675 }
676
677 static void
switchActivateEvent(CompScreen * s,Bool activating)678 switchActivateEvent (CompScreen *s,
679 Bool activating)
680 {
681 return;
682 CompOption o[2];
683
684 o[0].type = CompOptionTypeInt;
685 o[0].name = "root";
686 o[0].value.i = s->root;
687
688 o[1].type = CompOptionTypeBool;
689 o[1].name = "active";
690 o[1].value.b = activating;
691
692 (*s->display->handleCompizEvent) (s->display, "switcher", "activate", o, 2);
693 }
694
695 static int
compareWindows(const void * elem1,const void * elem2)696 compareWindows (const void *elem1,
697 const void *elem2)
698 {
699 CompWindow *w1 = *((CompWindow **) elem1);
700 CompWindow *w2 = *((CompWindow **) elem2);
701 CompWindow *w = w1;
702
703 if (w1 == w2)
704 return 0;
705
706 if (!w1->shaded && w1->attrib.map_state != IsViewable &&
707 (w2->shaded || w2->attrib.map_state == IsViewable))
708 {
709 return 1;
710 }
711
712 if (!w2->shaded && w2->attrib.map_state != IsViewable &&
713 (w1->shaded || w1->attrib.map_state == IsViewable))
714 {
715 return -1;
716 }
717
718 while (w)
719 {
720 if (w == w2)
721 return 1;
722 w = w->next;
723 }
724 return -1;
725 }
726
727 static int
compareShiftWindowDistance(const void * elem1,const void * elem2)728 compareShiftWindowDistance (const void *elem1,
729 const void *elem2)
730 {
731 float a1 = ((ShiftDrawSlot *) elem1)->distance;
732 float a2 = ((ShiftDrawSlot *) elem2)->distance;
733 float ab = fabs (a1 - a2);
734
735 if (ab > 0.3 && a1 > a2)
736 return -1;
737 else if (ab > 0.3 && a1 < a2)
738 return 1;
739 else
740 return compareWindows (&((ShiftDrawSlot *) elem2)->w,
741 &((ShiftDrawSlot *) elem1)->w);
742 }
743
744 static Bool
layoutThumbsCover(CompScreen * s)745 layoutThumbsCover (CompScreen *s)
746 {
747 SHIFT_SCREEN (s);
748 CompWindow *w;
749 int index;
750 int ww, wh;
751 float xScale, yScale;
752 float distance;
753 int i;
754
755 int ox1, ox2, oy1, oy2;
756
757 if (shiftGetMultioutputMode (s) == MultioutputModeOneBigSwitcher)
758 {
759 ox1 = oy1 = 0;
760 ox2 = s->width;
761 oy2 = s->height;
762 }
763 else
764 {
765 ox1 = s->outputDev[ss->usedOutput].region.extents.x1;
766 ox2 = s->outputDev[ss->usedOutput].region.extents.x2;
767 oy1 = s->outputDev[ss->usedOutput].region.extents.y1;
768 oy2 = s->outputDev[ss->usedOutput].region.extents.y2;
769 }
770
771 /* the center of the ellipse is in the middle
772 of the used output device */
773 int centerX = ox1 + (ox2 - ox1) / 2;
774 int centerY = oy1 + (oy2 - oy1) / 2;
775
776 ss->maxThumbWidth = (ox2 - ox1) * shiftGetSize(s) / 100;
777 ss->maxThumbHeight = (oy2 - oy1) * shiftGetSize(s) / 100;
778
779 for (index = 0; index < ss->nWindows; index++)
780 {
781 w = ss->windows[index];
782 SHIFT_WINDOW (w);
783
784 ww = w->attrib.width + w->input.left + w->input.right;
785 wh = w->attrib.height + w->input.top + w->input.bottom;
786
787 if (ww > ss->maxThumbWidth)
788 xScale = (float)(ss->maxThumbWidth) / (float)ww;
789 else
790 xScale = 1.0f;
791
792 if (wh > ss->maxThumbHeight)
793 yScale = (float)(ss->maxThumbHeight) / (float)wh;
794 else
795 yScale = 1.0f;
796
797
798 float val1 = floor((float)ss->nWindows / 2.0);
799
800 float pos;
801 float space = ss->maxThumbWidth / 2;
802 space *= cos (sin (PI / 4) * PI / 3);
803 space *= 2;
804 //space += (space / sin (PI / 4)) - space;
805
806 for (i = 0; i < 2; i++)
807 {
808
809
810 if (ss->invert ^ (i == 0))
811 {
812 distance = ss->mvTarget - index;
813 distance += shiftGetCoverOffset (s);
814 }
815 else
816 {
817 distance = ss->mvTarget - index + ss->nWindows;
818 distance += shiftGetCoverOffset (s);
819 if (distance > ss->nWindows)
820 distance -= ss->nWindows * 2;
821 }
822
823
824 pos = MIN (1.0, MAX (-1.0, distance));
825
826 sw->slots[i].opacity = 1.0 - MIN (1.0,
827 MAX (0.0, fabs(distance) - val1));
828 sw->slots[i].scale = MIN (xScale, yScale);
829
830 sw->slots[i].y = centerY + (ss->maxThumbHeight / 2.0) -
831 (((w->attrib.height / 2.0) + w->input.bottom) *
832 sw->slots[i].scale);
833
834 if (fabs(distance) < 1.0)
835 {
836 sw->slots[i].x = centerX + (sin(pos * PI * 0.5) * space);
837 sw->slots[i].z = fabs (distance);
838 sw->slots[i].z *= -(ss->maxThumbWidth / (2.0 * (ox2 - ox1)));
839
840 sw->slots[i].rotation = sin(pos * PI * 0.5) * -60;
841 }
842 else
843 {
844 float rad = (space / (ox2 - ox1)) / sin(PI / 6.0);
845
846 float ang = (PI / MAX(72.0, ss->nWindows * 2)) *
847 (distance - pos) + (pos * (PI / 6.0));
848
849 sw->slots[i].x = centerX;
850 sw->slots[i].x += sin(ang) * rad * (ox2 - ox1);
851
852 sw->slots[i].rotation = 90;
853 sw->slots[i].rotation -= fabs(ang) * 180.0 / PI;
854 sw->slots[i].rotation *= -pos;
855
856 sw->slots[i].z = -(ss->maxThumbWidth / (2.0 * (ox2 - ox1)));
857 sw->slots[i].z += -(cos(PI / 6.0) * rad);
858 sw->slots[i].z += (cos(ang) * rad);
859 }
860
861 ss->drawSlots[index * 2 + i].w = w;
862 ss->drawSlots[index * 2 + i].slot = &sw->slots[i];
863 ss->drawSlots[index * 2 + i].distance = fabs(distance);
864
865 }
866
867 if (ss->drawSlots[index * 2].distance >
868 ss->drawSlots[index * 2 + 1].distance)
869 {
870 ss->drawSlots[index * 2].slot->primary = FALSE;
871 ss->drawSlots[index * 2 + 1].slot->primary = TRUE;
872 }
873 else
874 {
875 ss->drawSlots[index * 2].slot->primary = TRUE;
876 ss->drawSlots[index * 2 + 1].slot->primary = FALSE;
877 }
878
879 }
880
881 ss->nSlots = ss->nWindows * 2;
882
883 qsort (ss->drawSlots, ss->nSlots, sizeof (ShiftDrawSlot),
884 compareShiftWindowDistance);
885
886 return TRUE;
887 }
888
889 static Bool
layoutThumbsFlip(CompScreen * s)890 layoutThumbsFlip (CompScreen *s)
891 {
892 SHIFT_SCREEN (s);
893 CompWindow *w;
894 int index;
895 int ww, wh;
896 float xScale, yScale;
897 float distance;
898 int i;
899 float angle;
900 int slotNum;
901
902 int ox1, ox2, oy1, oy2;
903
904 if (shiftGetMultioutputMode (s) == MultioutputModeOneBigSwitcher)
905 {
906 ox1 = oy1 = 0;
907 ox2 = s->width;
908 oy2 = s->height;
909 }
910 else
911 {
912 ox1 = s->outputDev[ss->usedOutput].region.extents.x1;
913 ox2 = s->outputDev[ss->usedOutput].region.extents.x2;
914 oy1 = s->outputDev[ss->usedOutput].region.extents.y1;
915 oy2 = s->outputDev[ss->usedOutput].region.extents.y2;
916 }
917
918 /* the center of the ellipse is in the middle
919 of the used output device */
920 int centerX = ox1 + (ox2 - ox1) / 2;
921 int centerY = oy1 + (oy2 - oy1) / 2;
922
923 ss->maxThumbWidth = (ox2 - ox1) * shiftGetSize(s) / 100;
924 ss->maxThumbHeight = (oy2 - oy1) * shiftGetSize(s) / 100;
925
926 slotNum = 0;
927
928 for (index = 0; index < ss->nWindows; index++)
929 {
930 w = ss->windows[index];
931 SHIFT_WINDOW (w);
932
933 ww = w->attrib.width + w->input.left + w->input.right;
934 wh = w->attrib.height + w->input.top + w->input.bottom;
935
936 if (ww > ss->maxThumbWidth)
937 xScale = (float)(ss->maxThumbWidth) / (float)ww;
938 else
939 xScale = 1.0f;
940
941 if (wh > ss->maxThumbHeight)
942 yScale = (float)(ss->maxThumbHeight) / (float)wh;
943 else
944 yScale = 1.0f;
945
946 angle = shiftGetFlipRotation (s) * PI / 180.0;
947
948 for (i = 0; i < 2; i++)
949 {
950
951 if (ss->invert ^ (i == 0))
952 distance = ss->mvTarget - index;
953 else
954 {
955 distance = ss->mvTarget - index + ss->nWindows;
956 if (distance > 1.0)
957 distance -= ss->nWindows * 2;
958 }
959
960 if (distance > 0.0)
961 sw->slots[i].opacity = MAX (0.0, 1.0 - (distance * 1.0));
962 else
963 {
964 if (distance < -(ss->nWindows - 1))
965 sw->slots[i].opacity = MAX (0.0, ss->nWindows +
966 distance);
967 else
968 sw->slots[i].opacity = 1.0;
969 }
970
971 if (distance > 0.0 && w != ss->selectedWindow)
972 sw->slots[i].primary = FALSE;
973 else
974 sw->slots[i].primary = TRUE;
975
976
977 sw->slots[i].scale = MIN (xScale, yScale);
978
979 sw->slots[i].y = centerY + (ss->maxThumbHeight / 2.0) -
980 (((w->attrib.height / 2.0) + w->input.bottom) *
981 sw->slots[i].scale);
982
983 sw->slots[i].x = sin(angle) * distance * (ss->maxThumbWidth / 2);
984 if (distance > 0 && FALSE)
985 sw->slots[i].x *= 1.5;
986 sw->slots[i].x += centerX;
987
988 sw->slots[i].z = cos(angle) * distance;
989 if (distance > 0)
990 sw->slots[i].z *= 1.5;
991 sw->slots[i].z *= (ss->maxThumbWidth / (2.0 * (ox2 - ox1)));
992
993 sw->slots[i].rotation = shiftGetFlipRotation (s);
994
995 if (sw->slots[i].opacity > 0.0)
996 {
997 ss->drawSlots[slotNum].w = w;
998 ss->drawSlots[slotNum].slot = &sw->slots[i];
999 ss->drawSlots[slotNum].distance = -distance;
1000 slotNum++;
1001 }
1002 }
1003 }
1004
1005 ss->nSlots = slotNum;
1006
1007 qsort (ss->drawSlots, ss->nSlots, sizeof (ShiftDrawSlot),
1008 compareShiftWindowDistance);
1009
1010 return TRUE;
1011 }
1012
1013
1014 static Bool
layoutThumbs(CompScreen * s)1015 layoutThumbs (CompScreen *s)
1016 {
1017 Bool result = FALSE;
1018
1019 SHIFT_SCREEN (s);
1020
1021 if (ss->state == ShiftStateNone)
1022 return FALSE;
1023
1024 switch (shiftGetMode (s))
1025 {
1026 case ModeCover:
1027 result = layoutThumbsCover (s);
1028 break;
1029 case ModeFlip:
1030 result = layoutThumbsFlip (s);
1031 break;
1032 }
1033
1034 if (ss->state == ShiftStateIn)
1035 return FALSE;
1036
1037 return result;
1038 }
1039
1040
1041 static void
shiftAddWindowToList(CompScreen * s,CompWindow * w)1042 shiftAddWindowToList (CompScreen *s,
1043 CompWindow *w)
1044 {
1045 SHIFT_SCREEN (s);
1046
1047 if (ss->windowsSize <= ss->nWindows)
1048 {
1049 ss->windows = realloc (ss->windows,
1050 sizeof (CompWindow *) * (ss->nWindows + 32));
1051 if (!ss->windows)
1052 return;
1053
1054 ss->windowsSize = ss->nWindows + 32;
1055 }
1056
1057 if (ss->slotsSize <= ss->nWindows * 2)
1058 {
1059 ss->drawSlots = realloc (ss->drawSlots,
1060 sizeof (ShiftDrawSlot) *
1061 ((ss->nWindows * 2) + 64));
1062
1063 if (!ss->drawSlots)
1064 return;
1065
1066 ss->slotsSize = (ss->nWindows * 2) + 64;
1067 }
1068
1069 ss->windows[ss->nWindows++] = w;
1070 }
1071
1072 static Bool
shiftUpdateWindowList(CompScreen * s)1073 shiftUpdateWindowList (CompScreen *s)
1074 {
1075 SHIFT_SCREEN (s);
1076
1077 int i, idx;
1078 CompWindow **wins;
1079
1080 qsort (ss->windows, ss->nWindows, sizeof (CompWindow *), compareWindows);
1081
1082 ss->mvTarget = 0;
1083 ss->mvAdjust = 0;
1084 ss->mvVelocity = 0;
1085 for (i = 0; i < ss->nWindows; i++)
1086 {
1087 if (ss->windows[i] == ss->selectedWindow)
1088 break;
1089
1090 ss->mvTarget++;
1091 }
1092 if (ss->mvTarget == ss->nWindows)
1093 ss->mvTarget = 0;
1094
1095 /* create spetial window order to create a good animation
1096 A,B,C,D,E --> A,B,D,E,C to get B,D,E,C,(A),B,D,E,C as initial state */
1097 if (shiftGetMode (s) == ModeCover)
1098 {
1099 wins = malloc(ss->nWindows * sizeof (CompWindow *));
1100 if (!wins)
1101 return FALSE;
1102
1103 memcpy(wins, ss->windows, ss->nWindows * sizeof (CompWindow *));
1104 for (i = 0; i < ss->nWindows; i++)
1105 {
1106 idx = ceil (i * 0.5);
1107 idx *= (i & 1) ? 1 : -1;
1108 if (idx < 0)
1109 idx += ss->nWindows;
1110 ss->windows[idx] = wins[i];
1111 }
1112 free (wins);
1113 }
1114
1115 return layoutThumbs (s);
1116 }
1117
1118 static Bool
shiftCreateWindowList(CompScreen * s)1119 shiftCreateWindowList (CompScreen *s)
1120 {
1121 CompWindow *w;
1122 SHIFT_SCREEN (s);
1123
1124 ss->nWindows = 0;
1125
1126 for (w = s->windows; w; w = w->next)
1127 {
1128 if (isShiftWin (w))
1129 {
1130 SHIFT_WINDOW (w);
1131
1132 shiftAddWindowToList (s, w);
1133 sw->active = TRUE;
1134 }
1135 }
1136
1137 return shiftUpdateWindowList (s);
1138 }
1139
1140 static void
switchToWindow(CompScreen * s,Bool toNext)1141 switchToWindow (CompScreen *s,
1142 Bool toNext)
1143 {
1144 CompWindow *w;
1145 int cur;
1146
1147 SHIFT_SCREEN (s);
1148
1149 if (!ss->grabIndex)
1150 return;
1151
1152 for (cur = 0; cur < ss->nWindows; cur++)
1153 {
1154 if (ss->windows[cur] == ss->selectedWindow)
1155 break;
1156 }
1157
1158 if (cur == ss->nWindows)
1159 return;
1160
1161 if (toNext)
1162 w = ss->windows[(cur + 1) % ss->nWindows];
1163 else
1164 w = ss->windows[(cur + ss->nWindows - 1) % ss->nWindows];
1165
1166 if (w)
1167 {
1168 CompWindow *old = ss->selectedWindow;
1169 ss->selectedWindow = w;
1170
1171 if (old != w)
1172 {
1173 if (toNext)
1174 ss->mvAdjust += 1;
1175 else
1176 ss->mvAdjust -= 1;
1177
1178 ss->moveAdjust = TRUE;
1179 damageScreen (s);
1180 shiftRenderWindowTitle (s);
1181 }
1182 }
1183 }
1184
1185 static int
shiftCountWindows(CompScreen * s)1186 shiftCountWindows (CompScreen *s)
1187 {
1188 CompWindow *w;
1189 int count = 0;
1190
1191 for (w = s->windows; w; w = w->next)
1192 {
1193 if (isShiftWin (w))
1194 count++;
1195 }
1196
1197 return count;
1198 }
1199
adjustShiftMovement(CompScreen * s,float chunk)1200 static int adjustShiftMovement (CompScreen *s, float chunk)
1201 {
1202 float dx, adjust, amount;
1203 float change;
1204
1205 SHIFT_SCREEN(s);
1206
1207 dx = ss->mvAdjust;
1208
1209 adjust = dx * 0.15f;
1210 amount = fabs(dx) * 1.5f;
1211 if (amount < 0.2f)
1212 amount = 0.2f;
1213 else if (amount > 2.0f)
1214 amount = 2.0f;
1215
1216 ss->mvVelocity = (amount * ss->mvVelocity + adjust) / (amount + 1.0f);
1217
1218 if (fabs (dx) < 0.002f && fabs (ss->mvVelocity) < 0.004f)
1219 {
1220 ss->mvVelocity = 0.0f;
1221 ss->mvTarget = ss->mvTarget + ss->mvAdjust;
1222 ss->mvAdjust = 0;
1223 layoutThumbs (s);
1224 return FALSE;
1225 }
1226
1227 change = ss->mvVelocity * chunk;
1228 if (!change)
1229 {
1230 if (ss->mvVelocity)
1231 change = (ss->mvAdjust > 0) ? 0.01 : -0.01;
1232 }
1233
1234 ss->mvAdjust -= change;
1235 ss->mvTarget += change;
1236
1237 while (ss->mvTarget >= ss->nWindows)
1238 {
1239 ss->mvTarget -= ss->nWindows;
1240 ss->invert = !ss->invert;
1241 }
1242
1243 while (ss->mvTarget < 0)
1244 {
1245 ss->mvTarget += ss->nWindows;
1246 ss->invert = !ss->invert;
1247 }
1248
1249 if (!layoutThumbs (s))
1250 return FALSE;
1251
1252 return TRUE;
1253 }
1254
1255 static Bool
adjustShiftWindowAttribs(CompWindow * w,float chunk)1256 adjustShiftWindowAttribs (CompWindow *w, float chunk)
1257 {
1258 float dp, db, adjust, amount;
1259 float opacity, brightness;
1260
1261 SHIFT_WINDOW (w);
1262 SHIFT_SCREEN (w->screen);
1263
1264 if ((sw->active && ss->state != ShiftStateIn &&
1265 ss->state != ShiftStateNone) ||
1266 (shiftGetHideAll(w->screen) && !(w->type & CompWindowTypeDesktopMask) &&
1267 (ss->state == ShiftStateOut || ss->state == ShiftStateSwitching ||
1268 ss->state == ShiftStateFinish)))
1269 opacity = 0.0;
1270 else
1271 opacity = 1.0;
1272
1273 if (ss->state == ShiftStateIn || ss->state == ShiftStateNone)
1274 brightness = 1.0;
1275 else
1276 brightness = shiftGetBackgroundIntensity (w->screen);
1277
1278 dp = opacity - sw->opacity;
1279 adjust = dp * 0.1f;
1280 amount = fabs (dp) * 7.0f;
1281 if (amount < 0.01f)
1282 amount = 0.01f;
1283 else if (amount > 0.15f)
1284 amount = 0.15f;
1285
1286 sw->opacityVelocity = (amount * sw->opacityVelocity + adjust) /
1287 (amount + 1.0f);
1288
1289 db = brightness - sw->brightness;
1290 adjust = db * 0.1f;
1291 amount = fabs (db) * 7.0f;
1292 if (amount < 0.01f)
1293 amount = 0.01f;
1294 else if (amount > 0.15f)
1295 amount = 0.15f;
1296
1297 sw->brightnessVelocity = (amount * sw->brightnessVelocity + adjust) /
1298 (amount + 1.0f);
1299
1300
1301 if (fabs (dp) < 0.01f && fabs (sw->opacityVelocity) < 0.02f &&
1302 fabs (db) < 0.01f && fabs (sw->brightnessVelocity) < 0.02f)
1303 {
1304
1305 sw->brightness = brightness;
1306 sw->opacity = opacity;
1307 return FALSE;
1308 }
1309
1310 sw->brightness += sw->brightnessVelocity * chunk;
1311 sw->opacity += sw->opacityVelocity * chunk;
1312
1313 return TRUE;
1314 }
1315
1316 static Bool
adjustShiftAnimationAttribs(CompScreen * s,float chunk)1317 adjustShiftAnimationAttribs (CompScreen *s, float chunk)
1318 {
1319 float dr, adjust, amount;
1320 float anim;
1321
1322 SHIFT_SCREEN (s);
1323
1324 if (ss->state != ShiftStateIn && ss->state != ShiftStateNone)
1325 anim = 1.0;
1326 else
1327 anim = 0.0;
1328
1329 dr = anim - ss->anim;
1330 adjust = dr * 0.1f;
1331 amount = fabs (dr) * 7.0f;
1332 if (amount < 0.002f)
1333 amount = 0.002f;
1334 else if (amount > 0.15f)
1335 amount = 0.15f;
1336
1337 ss->animVelocity = (amount * ss->animVelocity + adjust) /
1338 (amount + 1.0f);
1339
1340 if (fabs (dr) < 0.002f && fabs (ss->animVelocity) < 0.004f)
1341 {
1342
1343 ss->anim = anim;
1344 return FALSE;
1345 }
1346
1347 ss->anim += ss->animVelocity * chunk;
1348 return TRUE;
1349 }
1350
1351 static Bool
shiftPaintOutput(CompScreen * s,const ScreenPaintAttrib * sAttrib,const CompTransform * transform,Region region,CompOutput * output,unsigned int mask)1352 shiftPaintOutput (CompScreen *s,
1353 const ScreenPaintAttrib *sAttrib,
1354 const CompTransform *transform,
1355 Region region,
1356 CompOutput *output,
1357 unsigned int mask)
1358 {
1359 Bool status;
1360
1361 SHIFT_SCREEN (s);
1362
1363 if (ss->state != ShiftStateNone)
1364 mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
1365
1366 ss->paintingAbove = FALSE;
1367
1368 ss->output = output;
1369
1370 UNWRAP (ss, s, paintOutput);
1371 status = (*s->paintOutput) (s, sAttrib, transform, region, output, mask);
1372 WRAP (ss, s, paintOutput, shiftPaintOutput);
1373
1374 if (ss->state != ShiftStateNone &&
1375 (output->id == ss->usedOutput || output->id == ~0))
1376 {
1377 CompWindow *w;
1378 CompTransform sTransform = *transform;
1379 int i;
1380 int oy1 = s->outputDev[ss->usedOutput].region.extents.y1;
1381 int oy2 = s->outputDev[ss->usedOutput].region.extents.y2;
1382 int maxThumbHeight = (oy2 - oy1) * shiftGetSize(s) / 100;
1383 int oldFilter = s->display->textureFilter;
1384
1385 if (shiftGetMultioutputMode (s) == MultioutputModeOneBigSwitcher)
1386 {
1387 oy1 = 0;
1388 oy2 = s->height;
1389 }
1390
1391 transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &sTransform);
1392
1393 GLdouble clip[4] = { 0.0, -1.0, 0.0, 0.0};
1394
1395 clip[3] = ((oy1 + (oy2 - oy1) / 2)) + (maxThumbHeight / 2.0);
1396
1397 if (shiftGetReflection (s))
1398 {
1399 CompTransform rTransform = sTransform;
1400 unsigned short color[4];
1401 int cull, cullInv;
1402 glGetIntegerv (GL_CULL_FACE_MODE, &cull);
1403 cullInv = (cull == GL_BACK)? GL_FRONT : GL_BACK;
1404
1405 matrixTranslate (&rTransform, 0.0, oy1 + oy2 + maxThumbHeight,
1406 0.0);
1407 matrixScale (&rTransform, 1.0, -1.0, 1.0);
1408
1409 glPushMatrix ();
1410 glLoadMatrixf (rTransform.m);
1411
1412 glCullFace (cullInv);
1413
1414 if (shiftGetMipmaps (s))
1415 s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;
1416
1417
1418 if (ss->anim == 1.0)
1419 {
1420 glClipPlane (GL_CLIP_PLANE0, clip);
1421 glEnable (GL_CLIP_PLANE0);
1422 }
1423
1424 ss->reflectActive = TRUE;
1425 ss->reflectBrightness = shiftGetIntensity(s);
1426 for (i = 0; i < ss->nSlots; i++)
1427 {
1428 w = ss->drawSlots[i].w;
1429
1430 ss->activeSlot = &ss->drawSlots[i];
1431 {
1432 (*s->paintWindow) (w, &w->paint, &rTransform,
1433 &infiniteRegion, 0);
1434 }
1435 }
1436
1437 glDisable (GL_CLIP_PLANE0);
1438 glCullFace (cull);
1439
1440 glLoadIdentity();
1441 glTranslatef (0.0, 0.0, -DEFAULT_Z_CAMERA);
1442
1443 glEnable(GL_BLEND);
1444 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1445
1446 glBegin (GL_QUADS);
1447 glColor4f (0.0, 0.0, 0.0, 0.0);
1448 glVertex2f (0.5, 0.0);
1449 glVertex2f (-0.5, 0.0);
1450 glColor4f (0.0, 0.0, 0.0,
1451 MIN (1.0, 1.0 - shiftGetIntensity (s)) * 2.0 *
1452 ss->anim);
1453 glVertex2f (-0.5, -0.5);
1454 glVertex2f (0.5, -0.5);
1455 glEnd();
1456
1457 if (shiftGetGroundSize (s) > 0.0)
1458 {
1459 glBegin (GL_QUADS);
1460 color[0] = shiftGetGroundColor1 (s)[0];
1461 color[1] = shiftGetGroundColor1 (s)[1];
1462 color[2] = shiftGetGroundColor1 (s)[2];
1463 color[3] = (float)shiftGetGroundColor1 (s)[3] * ss->anim;
1464 glColor4usv (color);
1465 glVertex2f (-0.5, -0.5);
1466 glVertex2f (0.5, -0.5);
1467 color[0] = shiftGetGroundColor2 (s)[0];
1468 color[1] = shiftGetGroundColor2 (s)[1];
1469 color[2] = shiftGetGroundColor2 (s)[2];
1470 color[3] = (float)shiftGetGroundColor2 (s)[3] * ss->anim;
1471 glColor4usv (color);
1472 glVertex2f (0.5, -0.5 + shiftGetGroundSize (s));
1473 glVertex2f (-0.5, -0.5 + shiftGetGroundSize (s));
1474 glEnd();
1475 }
1476
1477 glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1478 glDisable(GL_BLEND);
1479 glColor4f (1.0, 1.0, 1.0, 1.0);
1480 glPopMatrix ();
1481 }
1482
1483 glPushMatrix ();
1484 glLoadMatrixf (sTransform.m);
1485
1486 if (shiftGetReflection (s) && ss->anim == 1.0)
1487 {
1488 glClipPlane (GL_CLIP_PLANE0, clip);
1489 glEnable (GL_CLIP_PLANE0);
1490 }
1491
1492 ss->reflectBrightness = 1.0;
1493 ss->reflectActive = FALSE;
1494
1495 for (i = 0; i < ss->nSlots; i++)
1496 {
1497 w = ss->drawSlots[i].w;
1498
1499 ss->activeSlot = &ss->drawSlots[i];
1500 {
1501 (*s->paintWindow) (w, &w->paint, &sTransform,
1502 &infiniteRegion, 0);
1503 }
1504 }
1505
1506 glDisable (GL_CLIP_PLANE0);
1507
1508 ss->activeSlot = NULL;
1509
1510 s->display->textureFilter = oldFilter;
1511
1512 if (ss->textData && (ss->state != ShiftStateIn))
1513 shiftDrawWindowTitle (s);
1514
1515 if (ss->state == ShiftStateIn || ss->state == ShiftStateOut)
1516 {
1517 Bool found;
1518 ss->paintingAbove = TRUE;
1519
1520 for (w = ss->selectedWindow; w; w = w->next)
1521 {
1522 if (w->destroyed)
1523 continue;
1524
1525 if (!w->shaded)
1526 {
1527 if (w->attrib.map_state != IsViewable || !w->damaged)
1528 continue;
1529 }
1530 found = FALSE;
1531 for (i = 0; i < ss->nWindows; i++)
1532 if (ss->windows[i] == w)
1533 found = TRUE;
1534 if (found)
1535 continue;
1536 (*s->paintWindow) (w, &w->paint, &sTransform,
1537 &infiniteRegion, 0);
1538 }
1539
1540 ss->paintingAbove = FALSE;
1541 }
1542
1543 glPopMatrix ();
1544 }
1545
1546 return status;
1547 }
1548
1549 static void
shiftPaintScreen(CompScreen * s,CompOutput * outputs,int numOutputs,unsigned int mask)1550 shiftPaintScreen (CompScreen *s,
1551 CompOutput *outputs,
1552 int numOutputs,
1553 unsigned int mask)
1554 {
1555 SHIFT_SCREEN (s);
1556
1557 if (ss->state != ShiftStateNone && numOutputs > 0 &&
1558 shiftGetMultioutputMode (s) != MultioutputModeDisabled)
1559 {
1560 outputs = &s->fullscreenOutput;
1561 numOutputs = 1;
1562 }
1563
1564 UNWRAP (ss, s, paintScreen);
1565 (*s->paintScreen) (s, outputs, numOutputs, mask);
1566 WRAP (ss, s, paintScreen, shiftPaintScreen);
1567 }
1568
1569 static void
shiftPreparePaintScreen(CompScreen * s,int msSinceLastPaint)1570 shiftPreparePaintScreen (CompScreen *s,
1571 int msSinceLastPaint)
1572 {
1573 SHIFT_SCREEN (s);
1574
1575 if (ss->state != ShiftStateNone &&
1576 (ss->moreAdjust || ss->moveAdjust))
1577 {
1578 CompWindow *w;
1579 int steps;
1580 float amount, chunk;
1581 int i;
1582
1583 amount = msSinceLastPaint * 0.05f * shiftGetShiftSpeed (s);
1584 steps = amount / (0.5f * shiftGetTimestep (s));
1585
1586 if (!steps)
1587 steps = 1;
1588 chunk = amount / (float) steps;
1589
1590
1591 while (steps--)
1592 {
1593 ss->moveAdjust = adjustShiftMovement (s, chunk);
1594 if (!ss->moveAdjust)
1595 break;
1596 }
1597
1598 amount = msSinceLastPaint * 0.05f * shiftGetSpeed (s);
1599 steps = amount / (0.5f * shiftGetTimestep (s));
1600
1601 if (!steps)
1602 steps = 1;
1603 chunk = amount / (float) steps;
1604
1605 while (steps--)
1606 {
1607 ss->moreAdjust = adjustShiftAnimationAttribs (s, chunk);
1608
1609 for (w = s->windows; w; w = w->next)
1610 {
1611 SHIFT_WINDOW (w);
1612
1613 ss->moreAdjust |= adjustShiftWindowAttribs (w, chunk);
1614 for (i = 0; i < 2; i++)
1615 {
1616 ShiftSlot *slot = &sw->slots[i];
1617 slot->tx = slot->x - w->attrib.x -
1618 (w->attrib.width * slot->scale) / 2;
1619 slot->ty = slot->y - w->attrib.y -
1620 (w->attrib.height * slot->scale) / 2;
1621 }
1622 }
1623
1624 if (!ss->moreAdjust)
1625 break;
1626 }
1627 }
1628
1629 UNWRAP (ss, s, preparePaintScreen);
1630 (*s->preparePaintScreen) (s, msSinceLastPaint);
1631 WRAP (ss, s, preparePaintScreen, shiftPreparePaintScreen);
1632 }
1633
1634 static Bool
canStackRelativeTo(CompWindow * w)1635 canStackRelativeTo (CompWindow *w)
1636 {
1637 if (w->attrib.override_redirect)
1638 return FALSE;
1639
1640 if (!w->shaded && !w->pendingMaps)
1641 {
1642 if (w->attrib.map_state != IsViewable || w->mapNum == 0)
1643 return FALSE;
1644 }
1645
1646 return TRUE;
1647 }
1648
1649 static void
shiftDonePaintScreen(CompScreen * s)1650 shiftDonePaintScreen (CompScreen *s)
1651 {
1652 SHIFT_SCREEN (s);
1653 CompWindow *w;
1654
1655 if (ss->state != ShiftStateNone)
1656 {
1657 if (ss->moreAdjust)
1658 {
1659 damageScreen (s);
1660 }
1661 else
1662 {
1663 if (ss->state == ShiftStateIn)
1664 {
1665 ss->state = ShiftStateNone;
1666 shiftActivateEvent(s, FALSE);
1667 for (w = s->windows; w; w = w->next)
1668 {
1669 SHIFT_WINDOW (w);
1670 sw->active = FALSE;
1671 }
1672 damageScreen (s);
1673 }
1674 else if (ss->state == ShiftStateOut)
1675 ss->state = ShiftStateSwitching;
1676
1677 if (ss->moveAdjust)
1678 damageScreen (s);
1679 }
1680
1681 if (ss->state == ShiftStateFinish)
1682 {
1683 CompWindow *w;
1684
1685 CompWindow *pw = NULL;
1686 int i;
1687
1688 ss->state = ShiftStateIn;
1689 ss->moreAdjust = TRUE;
1690 damageScreen (s);
1691
1692 if (!ss->canceled && ss->mvTarget != 0)
1693 for (i = 0; i < ss->nSlots; i++)
1694 {
1695 w = ss->drawSlots[i].w;
1696 if (ss->drawSlots[i].slot->primary && canStackRelativeTo (w))
1697 {
1698 if (pw)
1699 restackWindowAbove (w,pw);
1700 pw = w;
1701 }
1702 }
1703
1704 if (!ss->canceled && ss->selectedWindow &&
1705 !ss->selectedWindow->destroyed)
1706 {
1707 sendWindowActivationRequest (s, ss->selectedWindow->id);
1708 }
1709 }
1710
1711 if (ss->state == ShiftStateNone)
1712 switchActivateEvent (s, FALSE);
1713 }
1714
1715 UNWRAP (ss, s, donePaintScreen);
1716 (*s->donePaintScreen) (s);
1717 WRAP (ss, s, donePaintScreen, shiftDonePaintScreen);
1718 }
1719
1720 static void
shiftTerm(CompScreen * s,Bool cancel)1721 shiftTerm (CompScreen *s, Bool cancel)
1722 {
1723 SHIFT_SCREEN (s);
1724
1725 if (ss->grabIndex)
1726 {
1727 removeScreenGrab (s, ss->grabIndex, 0);
1728 ss->grabIndex = 0;
1729 }
1730
1731 if (ss->state != ShiftStateNone &&
1732 ss->state != ShiftStateFinish &&
1733 ss->state != ShiftStateIn)
1734 {
1735
1736 if (cancel && ss->mvTarget != 0)
1737 {
1738 if (ss->nWindows - ss->mvTarget > ss->mvTarget)
1739 ss->mvAdjust = -ss->mvTarget;
1740 else
1741 ss->mvAdjust = ss->nWindows - ss->mvTarget;
1742 ss->moveAdjust = TRUE;
1743 }
1744
1745 ss->moreAdjust = TRUE;
1746 ss->state = ShiftStateFinish;
1747 ss->canceled = cancel;
1748 damageScreen (s);
1749 }
1750 }
1751
1752 static Bool
shiftTerminate(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)1753 shiftTerminate (CompDisplay *d,
1754 CompAction *action,
1755 CompActionState state,
1756 CompOption *option,
1757 int nOption)
1758 {
1759 CompScreen *s;
1760 Window xid;
1761
1762 xid = getIntOptionNamed (option, nOption, "root", 0);
1763
1764 for (s = d->screens; s; s = s->next)
1765 {
1766 if (xid && s->root != xid)
1767 continue;
1768
1769 shiftTerm (s, (state & CompActionStateCancel));
1770
1771 if (state & CompActionStateTermButton)
1772 action->state &= ~CompActionStateTermButton;
1773
1774 if (state & CompActionStateTermKey)
1775 action->state &= ~CompActionStateTermKey;
1776 }
1777
1778 return FALSE;
1779 }
1780
1781 static Bool
shiftInitiateScreen(CompScreen * s,CompAction * action,CompActionState state,CompOption * option,int nOption)1782 shiftInitiateScreen (CompScreen *s,
1783 CompAction *action,
1784 CompActionState state,
1785 CompOption *option,
1786 int nOption)
1787 {
1788 CompMatch *match;
1789 int count;
1790
1791 SHIFT_SCREEN (s);
1792
1793 if (otherScreenGrabExist (s, "shift", NULL))
1794 return FALSE;
1795
1796 ss->currentMatch = shiftGetWindowMatch (s);
1797
1798 match = getMatchOptionNamed (option, nOption, "match", NULL);
1799 if (match)
1800 {
1801 matchFini (&ss->match);
1802 matchInit (&ss->match);
1803 if (matchCopy (&ss->match, match))
1804 {
1805 matchUpdate (s->display, &ss->match);
1806 ss->currentMatch = &ss->match;
1807 }
1808 }
1809
1810 count = shiftCountWindows (s);
1811
1812 if (count < 1)
1813 return FALSE;
1814
1815 if (!ss->grabIndex)
1816 ss->grabIndex = pushScreenGrab (s, s->invisibleCursor, "shift");
1817
1818
1819 if (ss->grabIndex)
1820 {
1821 ss->state = ShiftStateOut;
1822 shiftActivateEvent(s, TRUE);
1823
1824 if (!shiftCreateWindowList (s))
1825 return FALSE;
1826
1827 ss->selectedWindow = ss->windows[0];
1828 shiftRenderWindowTitle (s);
1829 ss->mvTarget = 0;
1830 ss->mvAdjust = 0;
1831 ss->mvVelocity = 0;
1832
1833 ss->moreAdjust = TRUE;
1834 damageScreen (s);
1835
1836 switchActivateEvent (s, TRUE);
1837 }
1838
1839 ss->usedOutput = s->currentOutputDev;
1840
1841 return TRUE;
1842 }
1843
1844 static Bool
shiftDoSwitch(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption,Bool nextWindow,ShiftType type)1845 shiftDoSwitch (CompDisplay *d,
1846 CompAction *action,
1847 CompActionState state,
1848 CompOption *option,
1849 int nOption,
1850 Bool nextWindow,
1851 ShiftType type)
1852 {
1853 CompScreen *s;
1854 Window xid;
1855 Bool ret = TRUE;
1856 Bool initial = FALSE;
1857
1858 xid = getIntOptionNamed (option, nOption, "root", 0);
1859
1860 s = findScreenAtDisplay (d, xid);
1861 if (s)
1862 {
1863 SHIFT_SCREEN (s);
1864
1865 if ((ss->state == ShiftStateNone) || (ss->state == ShiftStateIn))
1866 {
1867 if (type == ShiftTypeGroup)
1868 {
1869 CompWindow *w;
1870 w = findWindowAtDisplay (d, getIntOptionNamed (option, nOption,
1871 "window", 0));
1872 if (w)
1873 {
1874 ss->type = ShiftTypeGroup;
1875 ss->clientLeader =
1876 (w->clientLeader) ? w->clientLeader : w->id;
1877 ret = shiftInitiateScreen (s, action, state, option,
1878 nOption);
1879 }
1880 }
1881 else
1882 {
1883 ss->type = type;
1884 ret = shiftInitiateScreen (s, action, state, option, nOption);
1885 }
1886
1887 if (state & CompActionStateInitKey)
1888 action->state |= CompActionStateTermKey;
1889
1890 if (state & CompActionStateInitButton)
1891 action->state |= CompActionStateTermButton;
1892
1893 if (state & CompActionStateInitEdge)
1894 action->state |= CompActionStateTermEdge;
1895
1896 initial = TRUE;
1897 }
1898
1899 if (ret)
1900 {
1901 switchToWindow (s, nextWindow);
1902 if (initial && FALSE)
1903 {
1904 ss->mvTarget += ss->mvAdjust;
1905 ss->mvAdjust = 0.0;
1906 }
1907 }
1908 }
1909
1910 return ret;
1911 }
1912
1913 static Bool
shiftInitiate(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)1914 shiftInitiate (CompDisplay *d,
1915 CompAction *action,
1916 CompActionState state,
1917 CompOption *option,
1918 int nOption)
1919 {
1920 CompScreen *s;
1921 Window xid;
1922 Bool ret = TRUE;
1923
1924 xid = getIntOptionNamed (option, nOption, "root", 0);
1925
1926 s = findScreenAtDisplay (d, xid);
1927 if (s)
1928 {
1929 SHIFT_SCREEN (s);
1930
1931 ss->type = ShiftTypeNormal;
1932
1933 if ((ss->state == ShiftStateNone) || (ss->state == ShiftStateIn) ||
1934 (ss->state == ShiftStateFinish))
1935 ret = shiftInitiateScreen (s, action, state, option, nOption);
1936 else
1937 ret = shiftTerminate (d, action, state, option, nOption);
1938
1939 if (state & CompActionStateTermButton)
1940 action->state &= ~CompActionStateTermButton;
1941
1942 if (state & CompActionStateTermKey)
1943 action->state &= ~CompActionStateTermKey;
1944 }
1945
1946 return ret;
1947 }
1948
1949 static Bool
shiftInitiateAll(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)1950 shiftInitiateAll (CompDisplay *d,
1951 CompAction *action,
1952 CompActionState state,
1953 CompOption *option,
1954 int nOption)
1955 {
1956 CompScreen *s;
1957 Window xid;
1958 Bool ret = TRUE;
1959
1960 xid = getIntOptionNamed (option, nOption, "root", 0);
1961
1962 s = findScreenAtDisplay (d, xid);
1963 if (s)
1964 {
1965 SHIFT_SCREEN (s);
1966
1967 ss->type = ShiftTypeAll;
1968
1969 if ((ss->state == ShiftStateNone) || (ss->state == ShiftStateIn) ||
1970 (ss->state == ShiftStateFinish))
1971 ret = shiftInitiateScreen (s, action, state, option, nOption);
1972 else
1973 ret = shiftTerminate (d, action, state, option, nOption);
1974
1975 if (state & CompActionStateTermButton)
1976 action->state &= ~CompActionStateTermButton;
1977
1978 if (state & CompActionStateTermKey)
1979 action->state &= ~CompActionStateTermKey;
1980 }
1981
1982 return ret;
1983 }
1984
1985 static Bool
shiftNext(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)1986 shiftNext (CompDisplay *d,
1987 CompAction *action,
1988 CompActionState state,
1989 CompOption *option,
1990 int nOption)
1991 {
1992 return shiftDoSwitch (d, action, state, option, nOption,
1993 TRUE, ShiftTypeNormal);
1994 }
1995
1996 static Bool
shiftPrev(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)1997 shiftPrev (CompDisplay *d,
1998 CompAction *action,
1999 CompActionState state,
2000 CompOption *option,
2001 int nOption)
2002 {
2003 return shiftDoSwitch (d, action, state, option, nOption,
2004 FALSE, ShiftTypeNormal);
2005 }
2006
2007 static Bool
shiftNextAll(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)2008 shiftNextAll (CompDisplay *d,
2009 CompAction *action,
2010 CompActionState state,
2011 CompOption *option,
2012 int nOption)
2013 {
2014 return shiftDoSwitch (d, action, state, option, nOption,
2015 TRUE, ShiftTypeAll);
2016 }
2017
2018 static Bool
shiftPrevAll(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)2019 shiftPrevAll (CompDisplay *d,
2020 CompAction *action,
2021 CompActionState state,
2022 CompOption *option,
2023 int nOption)
2024 {
2025 return shiftDoSwitch (d, action, state, option, nOption,
2026 FALSE, ShiftTypeAll);
2027 }
2028
2029 static Bool
shiftNextGroup(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)2030 shiftNextGroup (CompDisplay *d,
2031 CompAction *action,
2032 CompActionState state,
2033 CompOption *option,
2034 int nOption)
2035 {
2036 return shiftDoSwitch (d, action, state, option, nOption,
2037 TRUE, ShiftTypeGroup);
2038 }
2039
2040 static Bool
shiftPrevGroup(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)2041 shiftPrevGroup (CompDisplay *d,
2042 CompAction *action,
2043 CompActionState state,
2044 CompOption *option,
2045 int nOption)
2046 {
2047 return shiftDoSwitch (d, action, state, option, nOption,
2048 FALSE, ShiftTypeGroup);
2049 }
2050
2051
2052 static void
shiftWindowRemove(CompDisplay * d,CompWindow * w)2053 shiftWindowRemove (CompDisplay * d,
2054 CompWindow *w)
2055 {
2056 if (w)
2057 {
2058 Bool inList = FALSE;
2059 int j, i = 0;
2060 CompWindow *selected;
2061
2062 SHIFT_SCREEN(w->screen);
2063
2064 if (ss->state == ShiftStateNone)
2065 return;
2066
2067 if (isShiftWin(w))
2068 return;
2069
2070 selected = ss->selectedWindow;
2071
2072 while (i < ss->nWindows)
2073 {
2074 if (w == ss->windows[i])
2075 {
2076 inList = TRUE;
2077
2078 if (w == selected)
2079 {
2080 if (i < (ss->nWindows - 1))
2081 selected = ss->windows[i + 1];
2082 else
2083 selected = ss->windows[0];
2084
2085 ss->selectedWindow = selected;
2086 shiftRenderWindowTitle (w->screen);
2087 }
2088
2089 ss->nWindows--;
2090 for (j = i; j < ss->nWindows; j++)
2091 ss->windows[j] = ss->windows[j + 1];
2092 }
2093 else
2094 {
2095 i++;
2096 }
2097 }
2098
2099 if (!inList)
2100 return;
2101
2102 if (ss->nWindows == 0)
2103 {
2104 CompOption o;
2105
2106 o.type = CompOptionTypeInt;
2107 o.name = "root";
2108 o.value.i = w->screen->root;
2109
2110 shiftTerminate (d, NULL, 0, &o, 1);
2111 return;
2112 }
2113
2114 // Let the window list be updated to avoid crash
2115 // when a window is closed while ending shift (ShiftStateIn).
2116 if (!ss->grabIndex && ss->state != ShiftStateIn)
2117 return;
2118
2119 if (shiftUpdateWindowList (w->screen))
2120 {
2121 ss->moreAdjust = TRUE;
2122 ss->state = ShiftStateOut;
2123 damageScreen (w->screen);
2124 }
2125 }
2126 }
2127
2128 static void
shiftHandleEvent(CompDisplay * d,XEvent * event)2129 shiftHandleEvent (CompDisplay *d,
2130 XEvent *event)
2131 {
2132 SHIFT_DISPLAY (d);
2133 CompScreen *s;
2134 CompWindow *w = NULL;
2135
2136 switch (event->type) {
2137 case DestroyNotify:
2138 /* We need to get the CompWindow * for event->xdestroywindow.window
2139 here because in the (*d->handleEvent) call below, that CompWindow's
2140 id will become 1, so findWindowAtDisplay won't be able to find the
2141 CompWindow after that. */
2142 w = findWindowAtDisplay (d, event->xdestroywindow.window);
2143 break;
2144 }
2145
2146 UNWRAP (sd, d, handleEvent);
2147 (*d->handleEvent) (d, event);
2148 WRAP (sd, d, handleEvent, shiftHandleEvent);
2149
2150 switch (event->type) {
2151 case PropertyNotify:
2152 if (event->xproperty.atom == XA_WM_NAME)
2153 {
2154 w = findWindowAtDisplay (d, event->xproperty.window);
2155 if (w)
2156 {
2157 SHIFT_SCREEN (w->screen);
2158 if (ss->grabIndex && (w == ss->selectedWindow))
2159 {
2160 shiftRenderWindowTitle (w->screen);
2161 damageScreen (w->screen);
2162 }
2163 }
2164 }
2165 break;
2166 case UnmapNotify:
2167 w = findWindowAtDisplay (d, event->xunmap.window);
2168 shiftWindowRemove (d, w);
2169 break;
2170 case DestroyNotify:
2171 shiftWindowRemove (d, w);
2172 break;
2173 case KeyPress:
2174 s = findScreenAtDisplay (d, event->xkey.root);
2175
2176 if (s)
2177 {
2178 SHIFT_SCREEN (s);
2179
2180 if (ss->state == ShiftStateSwitching)
2181 {
2182 if (event->xkey.keycode == sd->leftKey)
2183 switchToWindow (s, FALSE);
2184 else if (event->xkey.keycode == sd->rightKey)
2185 switchToWindow (s, TRUE);
2186 else if (event->xkey.keycode == sd->upKey)
2187 switchToWindow (s, FALSE);
2188 else if (event->xkey.keycode == sd->downKey)
2189 switchToWindow (s, TRUE);
2190 }
2191 }
2192
2193 break;
2194 case ButtonPress:
2195 s = findScreenAtDisplay (d, event->xbutton.root);
2196
2197 if (s)
2198 {
2199 SHIFT_SCREEN (s);
2200
2201 if (ss->state == ShiftStateSwitching || ss->state == ShiftStateOut)
2202 {
2203 if (event->xbutton.button == Button5)
2204 switchToWindow (s, FALSE);
2205 else if (event->xbutton.button == Button4)
2206 switchToWindow (s, TRUE);
2207 if (event->xbutton.button == Button1)
2208 {
2209 ss->buttonPressTime = event->xbutton.time;
2210 ss->buttonPressed = TRUE;
2211 ss->startX = event->xbutton.x_root;
2212 ss->startY = event->xbutton.y_root;
2213 ss->startTarget = ss->mvTarget + ss->mvAdjust;
2214 }
2215 }
2216 }
2217 break;
2218 case ButtonRelease:
2219 s = findScreenAtDisplay (d, event->xbutton.root);
2220
2221 if (s)
2222 {
2223 SHIFT_SCREEN (s);
2224
2225 if (ss->state == ShiftStateSwitching || ss->state == ShiftStateOut)
2226 {
2227 if (event->xbutton.button == Button1 && ss->buttonPressed)
2228 {
2229 int new;
2230 if ((int)(event->xbutton.time - ss->buttonPressTime) <
2231 shiftGetClickDuration (s))
2232 shiftTerm (s, FALSE);
2233
2234 ss->buttonPressTime = 0;
2235 ss->buttonPressed = FALSE;
2236
2237 if (ss->mvTarget - floor (ss->mvTarget) >= 0.5)
2238 {
2239 ss->mvAdjust = ceil(ss->mvTarget) - ss->mvTarget;
2240 new = ceil(ss->mvTarget);
2241 }
2242 else
2243 {
2244 ss->mvAdjust = floor(ss->mvTarget) - ss->mvTarget;
2245 new = floor(ss->mvTarget);
2246 }
2247
2248 while (new < 0)
2249 new += ss->nWindows;
2250 new = new % ss->nWindows;
2251
2252 ss->selectedWindow = ss->windows[new];
2253
2254 shiftRenderWindowTitle (s);
2255 ss->moveAdjust = TRUE;
2256 damageScreen(s);
2257 }
2258
2259 }
2260 }
2261 break;
2262 case MotionNotify:
2263 s = findScreenAtDisplay (d, event->xbutton.root);
2264
2265 if (s)
2266 {
2267 SHIFT_SCREEN (s);
2268
2269 if (ss->state == ShiftStateSwitching || ss->state == ShiftStateOut)
2270 {
2271 if (ss->buttonPressed)
2272 {
2273 int ox1 = s->outputDev[ss->usedOutput].region.extents.x1;
2274 int ox2 = s->outputDev[ss->usedOutput].region.extents.x2;
2275 int oy1 = s->outputDev[ss->usedOutput].region.extents.y1;
2276 int oy2 = s->outputDev[ss->usedOutput].region.extents.y2;
2277
2278 float div = 0;
2279 int wx = 0;
2280 int wy = 0;
2281 int new;
2282
2283 switch (shiftGetMode (s))
2284 {
2285 case ModeCover:
2286 div = event->xmotion.x_root - ss->startX;
2287 div /= (ox2 - ox1) / shiftGetMouseSpeed (s);
2288 break;
2289 case ModeFlip:
2290 div = event->xmotion.y_root - ss->startY;
2291 div /= (oy2 - oy1) / shiftGetMouseSpeed (s);
2292 break;
2293 }
2294
2295 ss->mvTarget = ss->startTarget + div - ss->mvAdjust;
2296 ss->moveAdjust = TRUE;
2297 while (ss->mvTarget >= ss->nWindows)
2298 {
2299 ss->mvTarget -= ss->nWindows;
2300 ss->invert = !ss->invert;
2301 }
2302
2303 while (ss->mvTarget < 0)
2304 {
2305 ss->mvTarget += ss->nWindows;
2306 ss->invert = !ss->invert;
2307 }
2308
2309 if (ss->mvTarget - floor (ss->mvTarget) >= 0.5)
2310 new = ceil(ss->mvTarget);
2311 else
2312 new = floor(ss->mvTarget);
2313
2314 while (new < 0)
2315 new += ss->nWindows;
2316 new = new % ss->nWindows;
2317
2318 if (ss->selectedWindow != ss->windows[new])
2319 {
2320 ss->selectedWindow = ss->windows[new];
2321 shiftRenderWindowTitle (s);
2322 }
2323
2324 if (event->xmotion.x_root < 50)
2325 wx = 50;
2326 if (s->width - event->xmotion.x_root < 50)
2327 wx = -50;
2328 if (event->xmotion.y_root < 50)
2329 wy = 50;
2330 if (s->height - event->xmotion.y_root < 50)
2331 wy = -50;
2332 if (wx != 0 || wy != 0)
2333 {
2334 warpPointer (s, wx, wy);
2335 ss->startX += wx;
2336 ss->startY += wy;
2337 }
2338
2339 damageScreen(s);
2340 }
2341
2342 }
2343 }
2344 break;
2345 }
2346 }
2347
2348 static Bool
shiftDamageWindowRect(CompWindow * w,Bool initial,BoxPtr rect)2349 shiftDamageWindowRect (CompWindow *w,
2350 Bool initial,
2351 BoxPtr rect)
2352 {
2353 Bool status = FALSE;
2354
2355 SHIFT_SCREEN (w->screen);
2356
2357 if (initial)
2358 {
2359 if (ss->grabIndex && isShiftWin (w))
2360 {
2361 shiftAddWindowToList (w->screen, w);
2362 if (shiftUpdateWindowList (w->screen))
2363 {
2364 SHIFT_WINDOW (w);
2365
2366 sw->active = TRUE;
2367 ss->moreAdjust = TRUE;
2368 ss->state = ShiftStateOut;
2369 damageScreen (w->screen);
2370 }
2371 }
2372 }
2373 else if (ss->state == ShiftStateSwitching)
2374 {
2375 SHIFT_WINDOW (w);
2376
2377 if (sw->active)
2378 {
2379 damageScreen (w->screen);
2380 status = TRUE;
2381 }
2382 }
2383
2384 UNWRAP (ss, w->screen, damageWindowRect);
2385 status |= (*w->screen->damageWindowRect) (w, initial, rect);
2386 WRAP (ss, w->screen, damageWindowRect, shiftDamageWindowRect);
2387
2388 return status;
2389 }
2390
2391 static Bool
shiftInitDisplay(CompPlugin * p,CompDisplay * d)2392 shiftInitDisplay (CompPlugin *p,
2393 CompDisplay *d)
2394 {
2395 ShiftDisplay *sd;
2396 int index;
2397
2398 if (!checkPluginABI ("core", CORE_ABIVERSION))
2399 return FALSE;
2400
2401 sd = malloc (sizeof (ShiftDisplay));
2402 if (!sd)
2403 return FALSE;
2404
2405 sd->screenPrivateIndex = allocateScreenPrivateIndex (d);
2406 if (sd->screenPrivateIndex < 0)
2407 {
2408 free (sd);
2409 return FALSE;
2410 }
2411
2412 if (checkPluginABI ("text", TEXT_ABIVERSION) &&
2413 getPluginDisplayIndex (d, "text", &index))
2414 {
2415 sd->textFunc = d->base.privates[index].ptr;
2416 }
2417 else
2418 {
2419 compLogMessage ("shift", CompLogLevelWarn,
2420 "No compatible text plugin loaded.");
2421 sd->textFunc = NULL;
2422 }
2423
2424 sd->leftKey = XKeysymToKeycode (d->display, XStringToKeysym ("Left"));
2425 sd->rightKey = XKeysymToKeycode (d->display, XStringToKeysym ("Right"));
2426 sd->upKey = XKeysymToKeycode (d->display, XStringToKeysym ("Up"));
2427 sd->downKey = XKeysymToKeycode (d->display, XStringToKeysym ("Down"));
2428
2429 shiftSetInitiateKeyInitiate (d, shiftInitiate);
2430 shiftSetInitiateKeyTerminate (d, shiftTerminate);
2431 shiftSetInitiateAllKeyInitiate (d, shiftInitiateAll);
2432 shiftSetInitiateAllKeyTerminate (d, shiftTerminate);
2433 shiftSetNextKeyInitiate (d, shiftNext);
2434 shiftSetNextKeyTerminate (d, shiftTerminate);
2435 shiftSetPrevKeyInitiate (d, shiftPrev);
2436 shiftSetPrevKeyTerminate (d, shiftTerminate);
2437 shiftSetNextAllKeyInitiate (d, shiftNextAll);
2438 shiftSetNextAllKeyTerminate (d, shiftTerminate);
2439 shiftSetPrevAllKeyInitiate (d, shiftPrevAll);
2440 shiftSetPrevAllKeyTerminate (d, shiftTerminate);
2441 shiftSetNextGroupKeyInitiate (d, shiftNextGroup);
2442 shiftSetNextGroupKeyTerminate (d, shiftTerminate);
2443 shiftSetPrevGroupKeyInitiate (d, shiftPrevGroup);
2444 shiftSetPrevGroupKeyTerminate (d, shiftTerminate);
2445
2446 shiftSetInitiateButtonInitiate (d, shiftInitiate);
2447 shiftSetInitiateButtonTerminate (d, shiftTerminate);
2448 shiftSetInitiateAllButtonInitiate (d, shiftInitiateAll);
2449 shiftSetInitiateAllButtonTerminate (d, shiftTerminate);
2450 shiftSetNextButtonInitiate (d, shiftNext);
2451 shiftSetNextButtonTerminate (d, shiftTerminate);
2452 shiftSetPrevButtonInitiate (d, shiftPrev);
2453 shiftSetPrevButtonTerminate (d, shiftTerminate);
2454 shiftSetNextAllButtonInitiate (d, shiftNextAll);
2455 shiftSetNextAllButtonTerminate (d, shiftTerminate);
2456 shiftSetPrevAllButtonInitiate (d, shiftPrevAll);
2457 shiftSetPrevAllButtonTerminate (d, shiftTerminate);
2458 shiftSetNextGroupButtonInitiate (d, shiftNextGroup);
2459 shiftSetNextGroupButtonTerminate (d, shiftTerminate);
2460 shiftSetPrevGroupButtonInitiate (d, shiftPrevGroup);
2461 shiftSetPrevGroupButtonTerminate (d, shiftTerminate);
2462
2463 shiftSetInitiateEdgeInitiate (d, shiftInitiate);
2464 shiftSetInitiateEdgeTerminate (d, shiftTerminate);
2465 shiftSetInitiateAllEdgeInitiate (d, shiftInitiateAll);
2466 shiftSetInitiateAllEdgeTerminate (d, shiftTerminate);
2467
2468 shiftSetTerminateButtonInitiate (d, shiftTerminate);
2469
2470 WRAP (sd, d, handleEvent, shiftHandleEvent);
2471
2472 d->base.privates[displayPrivateIndex].ptr = sd;
2473
2474 return TRUE;
2475 }
2476
2477 static void
shiftFiniDisplay(CompPlugin * p,CompDisplay * d)2478 shiftFiniDisplay (CompPlugin *p,
2479 CompDisplay *d)
2480 {
2481 SHIFT_DISPLAY (d);
2482
2483 freeScreenPrivateIndex (d, sd->screenPrivateIndex);
2484
2485 UNWRAP (sd, d, handleEvent);
2486
2487 free (sd);
2488 }
2489
2490 static Bool
shiftInitScreen(CompPlugin * p,CompScreen * s)2491 shiftInitScreen (CompPlugin *p,
2492 CompScreen *s)
2493 {
2494 ShiftScreen *ss;
2495
2496 SHIFT_DISPLAY (s->display);
2497
2498 ss = malloc (sizeof (ShiftScreen));
2499 if (!ss)
2500 return FALSE;
2501
2502 ss->windowPrivateIndex = allocateWindowPrivateIndex (s);
2503 if (ss->windowPrivateIndex < 0)
2504 {
2505 free (ss);
2506 return FALSE;
2507 }
2508
2509 ss->grabIndex = 0;
2510
2511 ss->state = ShiftStateNone;
2512
2513 ss->windows = NULL;
2514 ss->windowsSize = 0;
2515
2516 ss->drawSlots = NULL;
2517 ss->slotsSize = 0;
2518
2519 ss->activeSlot = NULL;
2520
2521 ss->selectedWindow = NULL;
2522
2523 ss->moreAdjust = FALSE;
2524
2525 ss->usedOutput = 0;
2526
2527 ss->mvAdjust = 0;
2528 ss->mvVelocity = 0;
2529 ss->mvTarget = 0;
2530 ss->invert = FALSE;
2531
2532 ss->textData = NULL;
2533
2534 ss->anim = 0.0;
2535 ss->animVelocity = 0.0;
2536
2537 ss->buttonPressed = FALSE;
2538
2539 matchInit (&ss->match);
2540
2541 WRAP (ss, s, preparePaintScreen, shiftPreparePaintScreen);
2542 WRAP (ss, s, donePaintScreen, shiftDonePaintScreen);
2543 WRAP (ss, s, paintScreen, shiftPaintScreen);
2544 WRAP (ss, s, paintOutput, shiftPaintOutput);
2545 WRAP (ss, s, paintWindow, shiftPaintWindow);
2546 WRAP (ss, s, damageWindowRect, shiftDamageWindowRect);
2547
2548 ss->cursor = XCreateFontCursor (s->display->display, XC_left_ptr);
2549
2550 s->base.privates[sd->screenPrivateIndex].ptr = ss;
2551
2552 return TRUE;
2553 }
2554
2555 static void
shiftFiniScreen(CompPlugin * p,CompScreen * s)2556 shiftFiniScreen (CompPlugin *p,
2557 CompScreen *s)
2558 {
2559 SHIFT_SCREEN (s);
2560
2561 freeWindowPrivateIndex (s, ss->windowPrivateIndex);
2562
2563 UNWRAP (ss, s, preparePaintScreen);
2564 UNWRAP (ss, s, donePaintScreen);
2565 UNWRAP (ss, s, paintScreen);
2566 UNWRAP (ss, s, paintOutput);
2567 UNWRAP (ss, s, paintWindow);
2568 UNWRAP (ss, s, damageWindowRect);
2569
2570 matchFini (&ss->match);
2571
2572 shiftFreeWindowTitle (s);
2573
2574 XFreeCursor (s->display->display, ss->cursor);
2575
2576 if (ss->windows)
2577 free (ss->windows);
2578
2579 if (ss->drawSlots)
2580 free (ss->drawSlots);
2581
2582 free (ss);
2583 }
2584
2585 static Bool
shiftInitWindow(CompPlugin * p,CompWindow * w)2586 shiftInitWindow (CompPlugin *p,
2587 CompWindow *w)
2588 {
2589 ShiftWindow *sw;
2590
2591 SHIFT_SCREEN (w->screen);
2592
2593 sw = calloc (1, sizeof (ShiftWindow));
2594 if (!sw)
2595 return FALSE;
2596
2597 sw->slots[0].scale = 1.0;
2598 sw->slots[1].scale = 1.0;
2599
2600 sw->brightness = 1.0;
2601 sw->opacity = 1.0;
2602
2603 w->base.privates[ss->windowPrivateIndex].ptr = sw;
2604
2605 return TRUE;
2606 }
2607
2608 static void
shiftFiniWindow(CompPlugin * p,CompWindow * w)2609 shiftFiniWindow (CompPlugin *p,
2610 CompWindow *w)
2611 {
2612 SHIFT_WINDOW (w);
2613
2614 free (sw);
2615 }
2616
2617 static Bool
shiftInit(CompPlugin * p)2618 shiftInit (CompPlugin *p)
2619 {
2620 displayPrivateIndex = allocateDisplayPrivateIndex ();
2621 if (displayPrivateIndex < 0)
2622 return FALSE;
2623
2624 return TRUE;
2625 }
2626
2627 static void
shiftFini(CompPlugin * p)2628 shiftFini (CompPlugin *p)
2629 {
2630 if (displayPrivateIndex >= 0)
2631 freeDisplayPrivateIndex (displayPrivateIndex);
2632 }
2633
2634 static CompBool
shiftInitObject(CompPlugin * p,CompObject * o)2635 shiftInitObject (CompPlugin *p,
2636 CompObject *o)
2637 {
2638 static InitPluginObjectProc dispTab[] = {
2639 (InitPluginObjectProc) 0, /* InitCore */
2640 (InitPluginObjectProc) shiftInitDisplay,
2641 (InitPluginObjectProc) shiftInitScreen,
2642 (InitPluginObjectProc) shiftInitWindow
2643 };
2644
2645 RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
2646 }
2647
2648 static void
shiftFiniObject(CompPlugin * p,CompObject * o)2649 shiftFiniObject (CompPlugin *p,
2650 CompObject *o)
2651 {
2652 static FiniPluginObjectProc dispTab[] = {
2653 (FiniPluginObjectProc) 0, /* FiniCore */
2654 (FiniPluginObjectProc) shiftFiniDisplay,
2655 (FiniPluginObjectProc) shiftFiniScreen,
2656 (FiniPluginObjectProc) shiftFiniWindow
2657 };
2658
2659 DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
2660 }
2661
2662 CompPluginVTable shiftVTable = {
2663 "shift",
2664 0,
2665 shiftInit,
2666 shiftFini,
2667 shiftInitObject,
2668 shiftFiniObject,
2669 0,
2670 0
2671 };
2672
2673 CompPluginVTable *
getCompPluginInfo(void)2674 getCompPluginInfo (void)
2675 {
2676 return &shiftVTable;
2677 }
2678