7
* Copyright (c) 2008 Dennis Kasprzyk <racarr@opencompositing.org>
8
* Copyright (c) 2006 Robert Carr <racarr@beryl-project.org>
11
* Robert Carr <racarr@beryl-project.org>
12
* Dennis Kasprzyk <onestone@opencompositing.org>
14
* This program is free software; you can redistribute it and/or
15
* modify it under the terms of the GNU General Public License
16
* as published by the Free Software Foundation; either version 2
17
* of the License, or (at your option) any later version.
19
* This program is distributed in the hope that it will be useful,
20
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
* GNU General Public License for more details.
29
#include <X11/cursorfont.h>
31
COMPIZ_PLUGIN_20090315 (expo, ExpoPluginVTable);
33
#define sigmoid(x) (1.0f / (1.0f + exp (-5.5f * 2 * ((x) - 0.5))))
34
#define sigmoidProgress(x) ((sigmoid (x) - sigmoid (0)) / \
35
(sigmoid (1) - sigmoid (0)))
37
#define interpolate(a, b, val) (((val) * (a)) + ((1 - (val)) * (b)))
40
ExpoScreen::dndInit (CompAction *action,
41
CompAction::State state,
42
CompOption::Vector& options)
44
Window xid = CompOption::getIntOptionNamed (options, "root", 0);
45
if (xid != screen->root ())
51
action->setState (action->state () | CompAction::StateTermButton);
52
cScreen->damageScreen ();
61
ExpoScreen::dndFini (CompAction *action,
62
CompAction::State state,
63
CompOption::Vector& options)
65
Window xid = CompOption::getIntOptionNamed (options, "root", 0);
66
if (xid != screen->root ())
69
if (dndState == DnDDuring || dndState == DnDStart)
71
if (dndWindows.size ())
72
finishWindowMovement ();
76
action->setState (action->state () & CompAction::StateInitButton);
77
cScreen->damageScreen ();
86
ExpoScreen::doExpo (CompAction *action,
87
CompAction::State state,
88
CompOption::Vector& options)
90
Window xid = CompOption::getIntOptionNamed (options, "root", 0);
91
if (xid != screen->root ())
94
if (screen->otherGrabExist ("expo", NULL))
100
grabIndex = screen->pushGrab (None, "expo");
111
selectedVp = screen->vp ();
112
origVp = screen->vp ();
114
screen->addAction (&optionGetDndButton ());
115
screen->addAction (&optionGetExitButton ());
116
screen->addAction (&optionGetNextVpButton ());
117
screen->addAction (&optionGetPrevVpButton ());
119
cScreen->damageScreen ();
123
termExpo (action, state, options);
130
ExpoScreen::termExpo (CompAction *action,
131
CompAction::State state,
132
CompOption::Vector& options)
134
Window xid = CompOption::getIntOptionNamed (options, "root", 0);
135
if (xid && xid != screen->root ())
143
if (dndState != DnDNone)
144
dndFini (action, state, options);
146
if (state & CompAction::StateCancel)
147
vpUpdateMode = VPUpdatePrevious;
149
vpUpdateMode = VPUpdateMouseOver;
153
screen->removeAction (&optionGetDndButton ());
154
screen->removeAction (&optionGetExitButton ());
155
screen->removeAction (&optionGetNextVpButton ());
156
screen->removeAction (&optionGetPrevVpButton ());
158
cScreen->damageScreen ();
159
screen->focusDefaultWindow ();
165
ExpoScreen::exitExpo (CompAction *action,
166
CompAction::State state,
167
CompOption::Vector& options)
169
Window xid = CompOption::getIntOptionNamed (options, "root", 0);
170
if (xid != screen->root ())
176
termExpo (action, 0, noOptions);
178
cScreen->damageScreen ();
184
ExpoScreen::nextVp (CompAction *action,
185
CompAction::State state,
186
CompOption::Vector& options)
188
unsigned int newX, newY;
189
Window xid = CompOption::getIntOptionNamed (options, "root", 0);
190
if (xid != screen->root ())
196
newX = selectedVp.x () + 1;
197
newY = selectedVp.y ();
199
if (newX >= (unsigned int) screen->vpSize ().width ())
203
if (newY >= (unsigned int) screen->vpSize ().height ())
207
moveFocusViewport (newX - selectedVp.x (),
208
newY - selectedVp.y ());
209
cScreen->damageScreen ();
215
ExpoScreen::prevVp (CompAction *action,
216
CompAction::State state,
217
CompOption::Vector& options)
219
unsigned int newX, newY;
220
Window xid = CompOption::getIntOptionNamed (options, "root", 0);
221
if (xid != screen->root ())
227
newX = selectedVp.x () - 1;
228
newY = selectedVp.y ();
232
newX = screen->vpSize ().width () - 1;
235
newY = screen->vpSize ().height () - 1;
238
moveFocusViewport (newX - selectedVp.x (),
239
newY - selectedVp.y ());
240
cScreen->damageScreen ();
246
ExpoScreen::moveFocusViewport (int dx,
251
newX = selectedVp.x () + dx;
252
newY = selectedVp.y () + dy;
254
newX = MAX (0, MIN ((int) screen->vpSize ().width () - 1, newX));
255
newY = MAX (0, MIN ((int) screen->vpSize ().height () - 1, newY));
257
selectedVp.set (newX, newY);
258
cScreen->damageScreen ();
262
ExpoScreen::finishWindowMovement ()
264
foreach (CompWindow *dndWindow, dndWindows)
266
if (dndWindow->grabbed ())
268
dndWindow->syncPosition ();
269
dndWindow->ungrabNotify ();
271
screen->updateGrab (grabIndex, None);
273
screen->moveViewport (screen->vp ().x () - selectedVp.x (),
274
screen->vp ().y () - selectedVp.y (), true);
276
/* update saved window attributes in case we moved the
277
window to a new viewport */
278
if (dndWindow->saveMask () & CWX)
280
dndWindow->saveWc ().x = dndWindow->saveWc ().x % screen->width ();
281
if (dndWindow->saveWc ().x < 0)
282
dndWindow->saveWc ().x += screen->width ();
284
if (dndWindow->saveMask () & CWY)
286
dndWindow->saveWc ().y = dndWindow->saveWc ().y % screen->height ();
287
if (dndWindow->saveWc ().y < 0)
288
dndWindow->saveWc ().y += screen->height ();
291
/* update window attibutes to make sure a moved maximized window
292
is properly snapped to the work area */
293
if (dndWindow->state () & MAXIMIZE_STATE)
294
dndWindow->updateAttributes (CompStackingUpdateModeNone);
300
ExpoScreen::handleEvent (XEvent *event)
302
switch (event->type) {
304
if (expoMode && event->xkey.root == screen->root ())
306
if (event->xkey.keycode == leftKey)
307
moveFocusViewport (-1, 0);
308
else if (event->xkey.keycode == rightKey)
309
moveFocusViewport (1, 0);
310
else if (event->xkey.keycode == upKey)
311
moveFocusViewport (0, -1);
312
else if (event->xkey.keycode == downKey)
313
moveFocusViewport (0, 1);
318
if (expoMode && event->xbutton.button == Button1 &&
319
event->xbutton.root == screen->root ())
324
clickTime = event->xbutton.time;
326
else if (event->xbutton.time - clickTime <=
327
(unsigned int) optionGetDoubleClickTime ())
333
clickTime = event->xbutton.time;
336
cScreen->damageScreen ();
341
if (expoMode && event->xbutton.button == Button1 &&
342
event->xbutton.root == screen->root ())
344
if (event->xbutton.time - clickTime >
345
(unsigned int) optionGetDoubleClickTime ())
350
else if (doubleClick)
352
CompAction& action = optionGetExpoKey ();
357
termExpo (&action, 0, noOptions);
364
screen->handleEvent (event);
368
ExpoScreen::windowsOnVp (CompPoint &p)
370
foreach (CompWindow *w, screen->clientList (true))
374
screen->viewportForGeometry (w->geometry (), viewport);
377
w->type () != CompWindowTypeDesktopMask &&
378
w->type () != CompWindowTypeDockMask)
388
ExpoScreen::preparePaint (int msSinceLastPaint)
390
float val = ((float) msSinceLastPaint / 1000.0) / optionGetZoomTime ();
393
expoCam = MIN (1.0, expoCam + val);
395
expoCam = MAX (0.0, expoCam - val);
397
if (dndState == DnDDuring)
399
foreach (CompWindow *w, dndWindows)
400
ExpoWindow::get (w)->dndOpacity = MIN (1.0, ExpoWindow::get (w)->dndOpacity + val);
402
else if (dndState == DnDNone)
404
CompWindowList::iterator it = dndWindows.begin ();
406
while (it != dndWindows.end ())
408
ExpoWindow::get ((*it))->dndOpacity = MAX (0.0, ExpoWindow::get ((*it))->dndOpacity - val);
410
if (ExpoWindow::get ((*it))->dndOpacity <= 0.0f)
412
dndWindows.erase (it);
413
it = dndWindows.begin ();
422
unsigned int i, j, vp;
423
unsigned int vpCount = screen->vpSize ().width () *
424
screen->vpSize ().height ();
426
if (vpActivity.size () < vpCount)
428
vpActivity.resize (vpCount);
429
foreach (float& activity, vpActivity)
433
for (i = 0; i < (unsigned int) screen->vpSize ().width (); i++)
435
for (j = 0; j < (unsigned int) screen->vpSize ().height (); j++)
437
vp = (j * screen->vpSize ().width ()) + i;
438
CompPoint vpPos = CompPoint (i, j);
440
if (windowsOnVp (vpPos))
441
vpActivity[vp] = MIN (1.0, vpActivity[vp] + val);
443
vpActivity[vp] = MAX (0.0, vpActivity[vp] - val);
447
for (i = 0; i < 360; i++)
449
float fi = (float) i;
451
vpNormals[i * 3] = (-sin (fi * DEG2RAD) / screen->width ()) *
453
vpNormals[(i * 3) + 1] = 0.0;
454
vpNormals[(i * 3) + 2] = (-cos (fi * DEG2RAD) * expoCam) -
459
cScreen->preparePaint (msSinceLastPaint);
463
ExpoScreen::updateWraps (bool enable)
465
screen->handleEventSetEnabled (this, enable);
466
cScreen->preparePaintSetEnabled (this, enable);
467
cScreen->paintSetEnabled (this, enable);
468
cScreen->getWindowPaintListSetEnabled (this, false);
469
cScreen->donePaintSetEnabled (this, enable);
470
gScreen->glPaintOutputSetEnabled (this, enable);
471
gScreen->glPaintTransformedOutputSetEnabled (this, enable);
473
foreach (CompWindow *w, screen->windows ())
475
ExpoWindow *ew = ExpoWindow::get (w);
477
ew->cWindow->damageRectSetEnabled (ew, enable);
478
ew->gWindow->glPaintSetEnabled (ew, enable);
479
ew->gWindow->glDrawSetEnabled (ew, enable);
480
ew->gWindow->glAddGeometrySetEnabled (ew, enable);
481
ew->gWindow->glDrawTextureSetEnabled (ew, enable);
486
ExpoScreen::paint (CompOutput::ptrList& outputs,
489
int width = outputs.front ()->width ();
490
int height = outputs.front ()->height ();
491
bool sizeDiff = false;
493
/* "One big wall" does not make sense where outputs are different
494
* sizes, so force multiple walls in this case
496
* TODO: Is it possible to re-create "one big wall" using
497
* independent output painting in this case? */
499
foreach (CompOutput *o, outputs)
501
if (o->width () != width || o->height () != height)
508
if (expoCam > 0.0 && outputs.size () > 1 &&
509
optionGetMultioutputMode () == MultioutputModeOneBigWall &&
513
outputs.push_back (&screen->fullscreenOutput ());
516
cScreen->paint (outputs, mask);
520
ExpoScreen::donePaint ()
522
switch (vpUpdateMode) {
523
case VPUpdateMouseOver:
524
screen->moveViewport (screen->vp ().x () - selectedVp.x (),
525
screen->vp ().y () - selectedVp.y (), true);
526
screen->focusDefaultWindow ();
527
vpUpdateMode = VPUpdateNone;
529
case VPUpdatePrevious:
530
screen->moveViewport (screen->vp ().x () - origVp.x (),
531
screen->vp ().y () - origVp.y (), true);
533
screen->focusDefaultWindow ();
534
vpUpdateMode = VPUpdateNone;
540
if ((expoCam > 0.0f && expoCam < 1.0f) || dndState != DnDNone)
541
cScreen->damageScreen ();
545
foreach (float& vp, vpActivity)
546
if (vp != 0.0 && vp != 1.0)
547
cScreen->damageScreen ();
549
foreach (CompWindow *w, dndWindows)
550
if (ExpoWindow::get (w)->dndOpacity != 0.0f &&
551
ExpoWindow::get (w)->dndOpacity != 1.0f)
552
cScreen->damageScreen ();
555
if (grabIndex && expoCam <= 0.0f && !expoMode)
557
screen->removeGrab (grabIndex, NULL);
562
cScreen->donePaint ();
567
if (dndWindows.size ())
569
foreach (CompWindow *dndWindow, dndWindows)
571
if (dndWindow->grabbed ())
573
dndWindow->move (newCursor.x () - prevCursor.x (),
574
newCursor.y () - prevCursor.y (),
575
optionGetExpoImmediateMove ());
580
prevCursor = newCursor;
581
cScreen->damageScreen ();
587
int xOffset, yOffset;
588
CompWindowList::reverse_iterator iter;
590
xOffset = screen->vpSize ().width () * screen->width ();
591
yOffset = screen->vpSize ().height () * screen->height ();
595
for (iter = screen->windows ().rbegin ();
596
iter != screen->windows ().rend (); ++iter)
598
CompWindow *w = *iter;
599
CompRect input (w->inputRect ());
606
if (!w->shaded () && !w->isViewable ())
609
if (w->onAllViewports ())
611
nx = (newCursor.x () + xOffset) % screen->width ();
612
ny = (newCursor.y () + yOffset) % screen->height ();
616
nx = newCursor.x () -
617
(screen->vp ().x () * screen->width ());
618
ny = newCursor.y () -
619
(screen->vp ().y () * screen->height ());
622
inWindow = (nx >= input.left () && nx <= input.right ()) ||
623
(nx >= (input.left () + xOffset) &&
624
nx <= (input.right () + xOffset));
626
inWindow &= (ny >= input.top () && ny <= input.bottom ()) ||
627
(ny >= (input.top () + yOffset) &&
628
ny <= (input.bottom () + yOffset));
633
/* make sure we never move windows we're not allowed to move */
636
else if (!(w->actions () & CompWindowActionMoveMask))
638
else if (w->type () & (CompWindowTypeDockMask |
639
CompWindowTypeDesktopMask))
642
dndState = DnDDuring;
643
dndWindows.push_back (w);
645
w->grabNotify (nx, ny, 0,
646
CompWindowGrabMoveMask |
647
CompWindowGrabButtonMask);
649
screen->updateGrab (grabIndex, mMoveCursor);
652
w->moveInputFocusTo ();
656
prevCursor = newCursor;
665
ExpoScreen::invertTransformedVertex (const GLScreenPaintAttrib& attrib,
666
const GLMatrix& transform,
670
GLMatrix sTransform (transform);
671
GLdouble p1[3], p2[3], v[3], alpha;
672
GLdouble mvm[16], pm[16];
676
gScreen->glApplyTransform (attrib, output, &sTransform);
677
sTransform.toScreenSpace (output, -attrib.zTranslate);
679
glGetIntegerv (GL_VIEWPORT, viewport);
680
for (i = 0; i < 16; i++)
682
mvm[i] = sTransform[i];
683
pm[i] = gScreen->projectionMatrix ()[i];
686
gluUnProject (vertex[0], screen->height () - vertex[1], 0, mvm, pm,
687
viewport, &p1[0], &p1[1], &p1[2]);
688
gluUnProject (vertex[0], screen->height () - vertex[1], -1.0, mvm, pm,
689
viewport, &p2[0], &p2[1], &p2[2]);
691
for (i = 0; i < 3; i++)
692
v[i] = p1[i] - p2[i];
694
alpha = -p1[2] / v[2];
696
if (optionGetDeform () == DeformCurve && screen->desktopWindowCount ())
698
const float sws = screen->width () * screen->width ();
699
const float rs = (curveDistance * curveDistance) + 0.25;
700
const float p = ((2.0 * sws * (p1[2] - curveDistance) * v[2]) +
701
(2.0 * p1[0] * v[0]) -
702
(v[0] * (float) screen->width ())) /
703
((v[2] * v[2] * sws) + (v[0] * v[0]));
704
const float q = (-(sws * rs) + (sws * (p1[2] - curveDistance) *
705
(p1[2] - curveDistance)) +
706
(0.25 * sws) + (p1[0] * p1[0]) -
707
(p1[0] * (float) screen->width ())) /
708
((v[2] * v[2] * sws) + (v[0] * v[0]));
710
const float rq = (0.25 * p * p) - q;
711
const float ph = -p * 0.5;
721
alpha = ph + sqrt(rq);
722
if (p1[2] + (alpha * v[2]) > 0.0)
731
vertex[0] = ceil (p1[0] + (alpha * v[0]));
732
vertex[1] = ceil (p1[1] + (alpha * v[1]));
736
ExpoScreen::paintViewport (const GLScreenPaintAttrib& attrib,
737
const GLMatrix& transform,
738
const CompRegion& region,
745
GLMatrix sTransform (transform);
746
GLMatrix sTransform2, sTransform3;
747
float sx = (float) screen->width () / output->width ();
748
float sy = (float) screen->height () / output->height ();
750
float progress = sigmoidProgress (expoCam);
752
CompPoint vpSize (screen->vpSize ().width (), screen->vpSize ().height ());
754
const float gapY = optionGetVpDistance () * 0.1f * expoCam;
755
const float gapX = optionGetVpDistance () * 0.1f * screen->height () /
756
screen->width () * expoCam;
758
/* not sure this will work with different resolutions */
759
sTransform.translate (0.0, MAX (0, vpPos.y ()) * -(sy + gapY), 0.0f);
761
sTransform2 = sTransform;
763
/* not sure this will work with different resolutions */
764
if (optionGetDeform () != DeformCurve)
765
sTransform2.translate (MAX (0, vpPos.x ()) * (sx + gapX), 0.0f, 0.0);
768
if (optionGetExpoAnimation () == ExpoAnimationVortex)
769
sTransform2.rotate (360 * expoCam,
770
0.0f, 1.0f, 2.0f * expoCam);
772
sTransform3 = sTransform2;
774
sTransform3.translate (output->x () / output->width (),
775
-output->y () / output->height (), 0.0);
777
cScreen->setWindowPaintOffset ((screen->vp ().x () - vpPos.x ()) *
779
(screen->vp ().y () - vpPos.y ()) *
782
vp = (vpPos.y () * vpSize.x ()) + vpPos.x ();
784
vpp = (expoCam * vpActivity[vp]) + (1 - expoCam);
785
vpp = sigmoidProgress (vpp);
787
vpBrightness = vpp + ((1.0 - vpp) *
788
optionGetVpBrightness () / 100.0);
789
vpSaturation = vpp + ((1.0 - vpp) *
790
optionGetVpSaturation () / 100.0);
794
if (optionGetDeform () == DeformCurve)
798
sTransform3.translate (-vpCamPos[GLVector::x], 0.0f,
799
curveDistance - DEFAULT_Z_CAMERA);
801
rotateX = -vpPos.x () + interpolate (((float) vpSize.x () / 2.0) - 0.5,
802
screen->vp ().x (), progress);
804
sTransform3.rotate (curveAngle * rotateX, 0.0, 1.0, 0.0);
806
sTransform3.translate (vpCamPos[GLVector::x], 0.0f,
807
DEFAULT_Z_CAMERA - curveDistance);
810
cScreen->getWindowPaintListSetEnabled (this, paintingDndWindow);
812
gScreen->glPaintTransformedOutput (attrib, sTransform3,
813
screen->region (), output,
816
cScreen->getWindowPaintListSetEnabled (this, !paintingDndWindow);
818
if (!reflection && !paintingDndWindow)
820
int cursor[2] = { pointerX, pointerY };
822
invertTransformedVertex (attrib, sTransform3,
825
if ((cursor[0] > 0) && (cursor[0] < (int) screen->width ()) &&
826
(cursor[1] > 0) && (cursor[1] < (int) screen->height ()))
828
newCursor.setX (vpPos.x () * screen->width () + cursor[0]);
829
newCursor.setY (vpPos.y () * screen->height () + cursor[1]);
831
if (anyClick || dndState != DnDNone)
833
/* Used to save last viewport interaction was in */
840
/* Calculate the current viewport size */
841
int tl[2] = { 0, 0 };
842
int br[2] = { screen->width (), screen->height () };
844
invertTransformedVertex (attrib, sTransform3, output, tl);
845
invertTransformedVertex (attrib, sTransform3, output, br);
847
viewport_size = CompSize (br[0] - tl[0], br[1] - tl[1]);
851
ExpoScreen::paintWall (const GLScreenPaintAttrib& attrib,
852
const GLMatrix& transform,
853
const CompRegion& region,
858
GLMatrix sTransformW, sTransform (transform);
859
GLenum oldFilter = gScreen->textureFilter ();
860
float sx = (float) screen->width () / output->width ();
861
float sy = (float) screen->height () / output->height ();
863
float oScale, rotation = 0.0f, progress;
864
float aspectX = 1.0f, aspectY = 1.0f;
866
CompPoint vpSize (screen->vpSize ().width (), screen->vpSize ().height ());
868
/* amount of gap between viewports */
869
const float gapY = optionGetVpDistance () * 0.1f * expoCam;
870
const float gapX = optionGetVpDistance () * 0.1f * screen->height () /
871
screen->width () * expoCam;
873
int glPaintTransformedOutputIndex =
874
gScreen->glPaintTransformedOutputGetCurrentIndex ();
876
// Make sure that the base glPaintTransformedOutput function is called
877
gScreen->glPaintTransformedOutputSetCurrentIndex (MAXSHORT);
879
/* Zoom animation stuff */
880
/* camera position for the selected viewport */
881
GLVector vpCamPos (0, 0, 0, 0);
883
/* camera position during expo mode */
884
GLVector expoCamPos (0, 0, 0, 0);
886
if (optionGetDeform () == DeformCurve)
888
vpCamPos[GLVector::x] = -sx * (0.5 - (((float) output->x () +
889
(output->width () / 2.0)) /
890
(float) screen->width ()));
894
vpCamPos[GLVector::x] = (screen->vp ().x () * sx) + 0.5 +
895
(output->x () / output->width ()) -
896
(vpSize.x () * 0.5 * sx) +
897
gapX * screen->vp ().x ();
899
vpCamPos[GLVector::y] = -((screen->vp ().y () * sy) + 0.5 +
900
(output->y () / output->height ())) +
901
(vpSize.y () * 0.5 * sy) -
902
gapY * screen->vp ().y ();
904
biasZ = MAX (vpSize.x () * sx, vpSize.y () * sy);
905
if (optionGetDeform () == DeformTilt || optionGetReflection ())
906
biasZ *= (0.15 + optionGetDistance ());
908
biasZ *= optionGetDistance ();
910
progress = sigmoidProgress (expoCam);
912
if (optionGetDeform () != DeformCurve)
913
expoCamPos[GLVector::x] = gapX * (vpSize.x () - 1) * 0.5;
915
expoCamPos[GLVector::y] = -gapY * (vpSize.y () - 1) * 0.5;
916
expoCamPos[GLVector::z] = -DEFAULT_Z_CAMERA + DEFAULT_Z_CAMERA *
917
(MAX (vpSize.x () + (vpSize.x () - 1) * gapX,
918
vpSize.y () + (vpSize.y () - 1) * gapY) +
921
/* interpolate between vpCamPos and expoCamPos */
922
cam[GLVector::x] = vpCamPos[GLVector::x] * (1 - progress) +
923
expoCamPos[GLVector::x] * progress;
924
cam[GLVector::y] = vpCamPos[GLVector::y] * (1 - progress) +
925
expoCamPos[GLVector::y] * progress;
926
cam[GLVector::z] = vpCamPos[GLVector::z] * (1 - progress) +
927
expoCamPos[GLVector::z] * progress;
929
if (vpSize.x () > vpSize.y ())
931
aspectY = (float) vpSize.x () / (float) vpSize.y ();
933
aspectY *= -optionGetAspectRatio () + 1.0;
939
aspectX = (float) vpSize.y () / (float) vpSize.x ();
941
aspectX *= -optionGetAspectRatio () + 1.0;
946
/* End of Zoom animation stuff */
948
if (optionGetDeform () == DeformTilt)
950
if (optionGetExpoAnimation () == ExpoAnimationZoom)
951
rotation = 10.0 * sigmoidProgress (expoCam);
953
rotation = 10.0 * expoCam;
956
if (optionGetMipmaps ())
957
gScreen->setTextureFilter (GL_LINEAR_MIPMAP_LINEAR);
959
/* ALL TRANSFORMATION ARE EXECUTED FROM BOTTOM TO TOP */
961
oScale = 1 / (1 + ((MAX (sx, sy) - 1) * progress));
963
sTransform.scale (oScale, oScale, 1.0);
966
oScale = DEFAULT_Z_CAMERA / (cam[GLVector::z] + DEFAULT_Z_CAMERA);
967
sTransform.scale (oScale, oScale, oScale);
968
glNormal3f (0.0, 0.0, -oScale);
969
sTransform.translate (-cam[GLVector::x], -cam[GLVector::y],
970
-cam[GLVector::z] - DEFAULT_Z_CAMERA);
974
float scaleFactor = optionGetScaleFactor ();
976
sTransform.translate (0.0,
977
(vpSize.y () + ((vpSize.y () - 1) * gapY * 2)) *
980
sTransform.scale (1.0, -1.0, 1.0);
981
sTransform.translate (0.0,
982
- (1 - scaleFactor) / 2 * sy * aspectY *
983
(vpSize.y () + ((vpSize.y () - 1) * gapY * 2)),
985
sTransform.scale (1.0, scaleFactor, 1.0);
986
glCullFace (GL_FRONT);
990
sTransform.rotate (rotation, 0.0f, 1.0f, 0.0f);
991
sTransform.scale (aspectX, aspectY, 1.0);
998
if (output->left () == 0)
1000
xoffset = ((vpSize.x () * sx) / ((float) output->width ()) * (optionGetXOffset ()) * sigmoidProgress (expoCam));
1001
xadjs = 1.0f - ((float) (optionGetXOffset ()) / (float) (output->width ())) * sigmoidProgress (expoCam);
1004
if (output->top () == 0)
1006
yoffset = ((vpSize.y () * sy) / ((float) output->height ()) * (optionGetYOffset ()) * sigmoidProgress (expoCam));
1008
yadjs = 1.0f - ((float) (optionGetYOffset ()) / (float) output->height ()) * sigmoidProgress (expoCam);
1011
/* translate expo to center */
1012
sTransform.translate (vpSize.x () * sx * -0.5 + xoffset,
1013
vpSize.y () * sy * 0.5 - yoffset, 0.0f);
1014
sTransform.scale (xadjs, yadjs, 1.0f);
1016
if (optionGetDeform () == DeformCurve)
1017
sTransform.translate ((vpSize.x () - 1) * sx * 0.5, 0.0, 0.0);
1019
sTransformW = sTransform;
1021
/* revert prepareXCoords region shift. Now all screens display the same */
1022
sTransform.translate (0.5f, -0.5f, DEFAULT_Z_CAMERA);
1024
if (vpSize.x () > 2)
1025
/* we can't have 90 degree for the left/right most viewport */
1026
curveAngle = interpolate (359 / ((vpSize.x () - 1) * 2), 1,
1029
curveAngle = interpolate (180 / vpSize.x (), 1, optionGetCurve ());
1031
curveDistance = ((0.5f * sx) + (gapX / 2.0)) /
1032
tanf (DEG2RAD * curveAngle / 2.0);
1033
curveRadius = ((0.5f * sx) + (gapX / 2.0)) /
1034
sinf (DEG2RAD * curveAngle / 2.0);
1038
for (int j = 0; j < screen->vpSize ().height (); j++)
1039
for (int i = 0; i < screen->vpSize().width (); i++)
1040
paintViewport (attrib, sTransform, region, output, mask, CompPoint (i, j), vpCamPos, reflection);
1042
paintingDndWindow = true;
1044
foreach (CompWindow *dndWindow, dndWindows)
1048
screen->viewportForGeometry (dndWindow->geometry (), vp);
1051
vp.setX (screen->vpSize ().width () + vp.x ());
1054
vp.setY (screen->vpSize ().height () + vp.y ());
1056
paintViewport (attrib, sTransform, infiniteRegion, output, mask, vp, vpCamPos, reflection);
1059
paintingDndWindow = false;
1061
glNormal3f (0.0, 0.0, -1.0);
1065
glEnable (GL_BLEND);
1066
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1070
if (optionGetDeform () != DeformCurve)
1072
glLoadMatrixf (sTransformW.getMatrix ());
1075
glColor4f (0.0, 0.0, 0.0, 1.0);
1076
glVertex2f (0.0, 0.0);
1077
glColor4f (0.0, 0.0, 0.0, 0.5);
1078
glVertex2f (0.0, -vpSize.y () * (sy + gapY));
1079
glVertex2f (vpSize.x () * sx * (1.0 + gapX),
1080
-vpSize.y () * sy * (1.0 + gapY));
1081
glColor4f (0.0, 0.0, 0.0, 1.0);
1082
glVertex2f (vpSize.x () * sx * (1.0 + gapX), 0.0);
1087
glCullFace (GL_BACK);
1089
glTranslatef (0.0, 0.0, -DEFAULT_Z_CAMERA);
1092
glColor4f (0.0, 0.0, 0.0, 1.0 * expoCam);
1093
glVertex2f (-0.5, -0.5);
1094
glVertex2f (0.5, -0.5);
1095
glColor4f (0.0, 0.0, 0.0, 0.5 * expoCam);
1096
glVertex2f (0.5, 0.0);
1097
glVertex2f (-0.5, 0.0);
1098
glColor4f (0.0, 0.0, 0.0, 0.5 * expoCam);
1099
glVertex2f (-0.5, 0.0);
1100
glVertex2f (0.5, 0.0);
1101
glColor4f (0.0, 0.0, 0.0, 0.0);
1102
glVertex2f (0.5, 0.5);
1103
glVertex2f (-0.5, 0.5);
1106
glCullFace (GL_BACK);
1109
glTranslatef (0.0, 0.0, -DEFAULT_Z_CAMERA);
1111
if (optionGetGroundSize () > 0.0)
1114
glColor4usv (optionGetGroundColor1 ());
1115
glVertex2f (-0.5, -0.5);
1116
glVertex2f (0.5, -0.5);
1117
glColor4usv (optionGetGroundColor2 ());
1118
glVertex2f (0.5, -0.5 + optionGetGroundSize ());
1119
glVertex2f (-0.5, -0.5 + optionGetGroundSize ());
1123
glColor4usv (defaultColor);
1125
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1126
glDisable (GL_BLEND);
1132
cScreen->setWindowPaintOffset (0, 0);
1134
gScreen->glPaintTransformedOutputSetCurrentIndex (glPaintTransformedOutputIndex);
1135
gScreen->setTextureFilter (oldFilter);
1138
const CompWindowList &
1139
ExpoScreen::getWindowPaintList ()
1145
ExpoScreen::glPaintOutput (const GLScreenPaintAttrib& attrib,
1146
const GLMatrix& transform,
1147
const CompRegion& region,
1152
mask |= PAINT_SCREEN_TRANSFORMED_MASK | PAINT_SCREEN_CLEAR_MASK;
1154
return gScreen->glPaintOutput (attrib, transform, region, output, mask);
1158
ExpoScreen::glPaintTransformedOutput (const GLScreenPaintAttrib& attrib,
1159
const GLMatrix& transform,
1160
const CompRegion& region,
1167
mask |= PAINT_SCREEN_CLEAR_MASK;
1169
if (expoCam <= 0 || (expoCam > 0.0 && expoCam < 1.0 &&
1170
optionGetExpoAnimation () != ExpoAnimationZoom))
1172
gScreen->glPaintTransformedOutput (attrib, transform, region,
1177
gScreen->clearOutput (output, GL_COLOR_BUFFER_BIT);
1180
mask &= ~PAINT_SCREEN_CLEAR_MASK;
1184
if (optionGetReflection ())
1185
paintWall (attrib, transform, region, output, mask, true);
1187
paintWall (attrib, transform, region, output, mask, false);
1193
ExpoWindow::glDraw (const GLMatrix& transform,
1194
GLFragment::Attrib& fragment,
1195
const CompRegion& region,
1198
GLMatrix wTransform (transform);
1201
screen->viewportForGeometry (window->geometry (), vp);
1203
if (eScreen->expoCam == 0.0f)
1204
return gWindow->glDraw (transform, fragment, region, mask);
1206
GLFragment::Attrib fA (fragment);
1209
expoAnimation = eScreen->optionGetExpoAnimation ();
1211
if (eScreen->expoActive)
1213
if (expoAnimation != ExpoScreen::ExpoAnimationZoom)
1214
fA.setOpacity (fragment.getOpacity () * eScreen->expoCam);
1216
if (window->wmType () & CompWindowTypeDockMask &&
1217
eScreen->optionGetHideDocks ())
1219
if (expoAnimation == ExpoScreen::ExpoAnimationZoom &&
1220
eScreen->paintingVp == eScreen->selectedVp)
1222
fA.setOpacity (fragment.getOpacity () *
1223
(1 - sigmoidProgress (eScreen->expoCam)));
1231
if (vp == eScreen->paintingVp || window->onAllViewports ())
1233
fA.setBrightness (fragment.getBrightness () * eScreen->vpBrightness);
1234
fA.setSaturation (fragment.getSaturation () * eScreen->vpSaturation);
1239
if (expoAnimation == ExpoScreen::ExpoAnimationZoom)
1240
fA.setBrightness (0);
1242
fA.setBrightness (fragment.getBrightness () *
1243
(1 - sigmoidProgress (eScreen->expoCam)));
1246
bool status = gWindow->glDraw (wTransform, fA, region, mask);
1248
if (window->type () & CompWindowTypeDesktopMask)
1250
/* We want to set the geometry of the polka dots to the window
1252
CompRegion reg = CompRegion (0, 0, window->width (), window->height ());
1254
foreach(GLTexture * tex, eScreen->polkadots_texture)
1256
GLTexture::MatrixList matl;
1257
GLTexture::Matrix mat = tex->matrix();
1258
CompRegion paintRegion(region);
1260
/* We can reset the window geometry since it will be
1262
gWindow->geometry().reset();
1264
float xScale = screen->width () / (float) eScreen->viewport_size.width ();
1265
float yScale = screen->height () / (float) eScreen->viewport_size.height ();
1270
/* Not sure what this does, but it is necessary
1271
* (adjusts for scale?) */
1272
mat.x0 -= mat.xx * reg.boundingRect().x1();
1273
mat.y0 -= mat.yy * reg.boundingRect().y1();
1275
matl.push_back(mat);
1277
if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
1278
paintRegion = infiniteRegion;
1280
/* Now allow plugins to mess with the geometry of our
1281
* dim (so we get a nice render for things like
1283
gWindow->glAddGeometry(matl, reg, paintRegion);
1285
/* Did it succeed? */
1286
if (gWindow->geometry().vertices)
1288
unsigned int glDrawTextureIndex = gWindow->glDrawTextureGetCurrentIndex();
1289
fA.setOpacity (fragment.getOpacity () * (((1.0 - eScreen->vpBrightness) + (1.0 - eScreen->vpSaturation) / 2.0)));
1290
/* Texture rendering set-up */
1291
eScreen->gScreen->setTexEnvMode(GL_MODULATE);
1292
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1293
/* Draw the dim texture with all of it's modified
1295
gWindow->glDrawTextureSetCurrentIndex(MAXSHORT);
1296
gWindow->glDrawTexture(tex, fA, mask | PAINT_WINDOW_BLEND_MASK
1297
| PAINT_WINDOW_TRANSLUCENT_MASK |
1298
PAINT_WINDOW_TRANSFORMED_MASK);
1299
gWindow->glDrawTextureSetCurrentIndex(glDrawTextureIndex);
1300
/* Texture rendering tear-down */
1301
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1302
eScreen->gScreen->setTexEnvMode(GL_REPLACE);
1306
/* Paint the outline */
1307
if (mGlowQuads && eScreen->paintingVp == eScreen->selectedVp)
1309
if (region.numRects ())
1311
/* reset geometry and paint */
1312
gWindow->geometry ().reset ();
1314
paintGlow (fragment, infiniteRegion, mask);
1324
#define EXPO_GRID_SIZE 100
1327
ExpoWindow::glAddGeometry (const GLTexture::MatrixList& matrices,
1328
const CompRegion& region,
1329
const CompRegion& clip,
1330
unsigned int maxGridWidth,
1331
unsigned int maxGridHeight)
1333
if (eScreen->expoCam > 0.0 &&
1334
screen->desktopWindowCount () &&
1335
eScreen->optionGetDeform () == ExpoScreen::DeformCurve)
1337
int i, oldVCount = gWindow->geometry ().vCount;
1340
float lastX, lastZ = 0.0;
1341
const float radSquare = pow (eScreen->curveDistance, 2) + 0.25;
1344
gWindow->glAddGeometry (matrices, region, clip,
1345
MIN(maxGridWidth , EXPO_GRID_SIZE),
1348
v = gWindow->geometry ().vertices;
1349
v += gWindow->geometry ().vertexStride - 3;
1350
v += gWindow->geometry ().vertexStride * oldVCount;
1352
if (!window->onAllViewports ())
1354
offset = eScreen->cScreen->windowPaintOffset ();
1355
offset = window->getMovementForOffset (offset);
1358
lastX = -1000000000.0;
1360
for (i = oldVCount; i < gWindow->geometry ().vCount; i++)
1366
else if (v[0] + offset.x () >= -EXPO_GRID_SIZE &&
1367
v[0] + offset.x () < screen->width () + EXPO_GRID_SIZE)
1369
ang = (((v[0] + offset.x ()) / (float) screen->width ()) - 0.5);
1371
if (ang < radSquare)
1373
v[2] = eScreen->curveDistance - sqrt (radSquare - ang);
1374
v[2] *= sigmoidProgress (eScreen->expoCam);
1381
v += gWindow->geometry ().vertexStride;
1386
gWindow->glAddGeometry (matrices, region, clip, maxGridWidth, maxGridHeight);
1391
ExpoWindow::glDrawTexture (GLTexture *texture,
1392
GLFragment::Attrib& attrib,
1395
if (eScreen->expoCam > 0.0 &&
1396
eScreen->optionGetDeform () == ExpoScreen::DeformCurve &&
1397
eScreen->gScreen->lighting () &&
1398
screen->desktopWindowCount ())
1400
unsigned int i, idx, vCount;
1405
vCount = gWindow->geometry ().vCount;
1407
if (eScreen->winNormals.size () < vCount * 3)
1408
eScreen->winNormals.resize (vCount * 3);
1410
if (!window->onAllViewports ())
1412
offset = eScreen->cScreen->windowPaintOffset ();
1413
offset = window->getMovementForOffset (offset);
1416
v = gWindow->geometry ().vertices +
1417
(gWindow->geometry ().vertexStride - 3);
1419
for (i = 0; i < vCount; i++)
1421
x = (float) (v[0] + offset.x () - screen->width () / 2) *
1422
eScreen->curveAngle / screen->width ();
1429
eScreen->winNormals[i * 3] = -eScreen->vpNormals[idx * 3];
1430
eScreen->winNormals[(i * 3) + 1] =
1431
eScreen->vpNormals[(idx * 3) + 1];
1432
eScreen->winNormals[(i * 3) + 2] =
1433
eScreen->vpNormals[(idx * 3) + 2];
1435
v += gWindow->geometry ().vertexStride;
1438
glEnable (GL_NORMALIZE);
1439
glNormalPointer (GL_FLOAT,0, &eScreen->winNormals.at (0));
1441
glEnableClientState (GL_NORMAL_ARRAY);
1443
gWindow->glDrawTexture (texture, attrib, mask);
1445
glDisable (GL_NORMALIZE);
1446
glDisableClientState (GL_NORMAL_ARRAY);
1447
glNormal3f (0.0, 0.0, -1.0);
1451
glEnable (GL_NORMALIZE);
1452
gWindow->glDrawTexture (texture, attrib, mask);
1453
glDisable (GL_NORMALIZE);
1458
ExpoWindow::glPaint (const GLWindowPaintAttrib& attrib,
1459
const GLMatrix& transform,
1460
const CompRegion& region,
1463
GLMatrix wTransform (transform);
1464
GLWindowPaintAttrib wAttrib (attrib);
1467
screen->viewportForGeometry (window->geometry (), vp);
1469
if (eScreen->expoActive)
1471
float opacity = 1.0;
1475
zoomAnim = eScreen->optionGetExpoAnimation () ==
1476
ExpoScreen::ExpoAnimationZoom;
1477
hide = eScreen->optionGetHideDocks () &&
1478
(window->wmType () & CompWindowTypeDockMask);
1480
if (eScreen->expoCam > 0.0)
1482
if (eScreen->expoCam < 1.0 && !zoomAnim)
1483
mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
1485
mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
1489
opacity = attrib.opacity * eScreen->expoCam;
1493
if (zoomAnim && eScreen->paintingVp == eScreen->selectedVp)
1494
opacity = attrib.opacity *
1495
(1 - sigmoidProgress (eScreen->expoCam));
1501
mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
1503
wAttrib.opacity = wAttrib.opacity * opacity;
1506
/* Stretch maximized windows a little so that you don't
1507
* have an awkward gap */
1508
if (window->state () & MAXIMIZE_STATE)
1510
CompOutput *o = &screen->outputDevs ()[screen->outputDeviceForGeometry(window->geometry())];
1511
float yS = 1.0 + ((o->height () / (float) window->height ()) - 1.0f) * sigmoidProgress (eScreen->expoCam);
1512
wTransform.translate (window->x () + window->width () / 2,
1513
window->y () + window->height (),
1515
wTransform.scale (1.0f, yS, 1.0f);
1516
wTransform.translate (-(window->x () + window->width () / 2),
1517
-(window->y () + window->height ()),
1520
if (eScreen->paintingVp != vp)
1521
mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
1523
mask |= PAINT_WINDOW_TRANSFORMED_MASK;
1526
if (std::find (eScreen->dndWindows.begin(), eScreen->dndWindows.end (), window) != eScreen->dndWindows.end ())
1528
if (!eScreen->paintingDndWindow)
1530
if ((1.0f - dndOpacity) <= 0.0f || (eScreen->paintingVp == vp &&
1531
eScreen->dndState != ExpoScreen::DnDNone))
1532
mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
1533
else if (!window->region ().subtracted (screen->region ()).isEmpty () &&
1534
eScreen->paintingVp != vp)
1535
wAttrib.opacity = wAttrib.opacity * (1.0f - dndOpacity);
1539
mask |= PAINT_WINDOW_TRANSFORMED_MASK;
1540
if (!window->region ().subtracted (screen->region ()).isEmpty ())
1541
wAttrib.opacity = wAttrib.opacity * dndOpacity;
1545
bool status = gWindow->glPaint (wAttrib, wTransform, region, mask);
1551
ExpoWindow::damageRect (bool initial,
1552
const CompRect& rect)
1554
if (eScreen->expoCam > 0.0f)
1555
eScreen->cScreen->damageScreen ();
1557
return cWindow->damageRect (initial, rect);
1560
#define EXPOINITBIND(opt, func) \
1561
optionSet##opt##Initiate (boost::bind (&ExpoScreen::func, \
1563
#define EXPOTERMBIND(opt, func) \
1564
optionSet##opt##Terminate (boost::bind (&ExpoScreen::func, \
1567
ExpoScreen::ExpoScreen (CompScreen *s) :
1568
PluginClassHandler<ExpoScreen, CompScreen> (s),
1570
cScreen (CompositeScreen::get (s)),
1571
gScreen (GLScreen::get (s)),
1578
selectedVp (s->vp ()),
1579
vpUpdateMode (VPUpdateNone),
1581
doubleClick (false),
1582
vpNormals (360 * 3),
1584
paintingDndWindow (false),
1585
mGlowTextureProperties (&glowTextureProperties)
1588
CompString pname = "expo";
1592
leftKey = XKeysymToKeycode (s->dpy (), XStringToKeysym ("Left"));
1593
rightKey = XKeysymToKeycode (s->dpy (), XStringToKeysym ("Right"));
1594
upKey = XKeysymToKeycode (s->dpy (), XStringToKeysym ("Up"));
1595
downKey = XKeysymToKeycode (s->dpy (), XStringToKeysym ("Down"));
1597
mMoveCursor = XCreateFontCursor (screen->dpy (), XC_fleur);
1599
EXPOINITBIND (ExpoKey, doExpo);
1600
EXPOTERMBIND (ExpoKey, termExpo);
1601
EXPOINITBIND (ExpoButton, doExpo);
1602
EXPOTERMBIND (ExpoButton, termExpo);
1603
EXPOINITBIND (ExpoEdge, doExpo);
1604
EXPOTERMBIND (ExpoButton, termExpo);
1606
EXPOINITBIND (DndButton, dndInit);
1607
EXPOTERMBIND (DndButton, dndFini);
1608
EXPOINITBIND (ExitButton, exitExpo);
1609
EXPOINITBIND (NextVpButton, nextVp);
1610
EXPOINITBIND (PrevVpButton, prevVp);
1612
ScreenInterface::setHandler (screen, false);
1613
CompositeScreenInterface::setHandler (cScreen, false);
1614
GLScreenInterface::setHandler (gScreen, false);
1616
outline_texture = GLTexture::imageDataToTexture (mGlowTextureProperties->textureData,
1617
CompSize (mGlowTextureProperties->textureSize,
1618
mGlowTextureProperties->textureSize),
1619
GL_RGBA, GL_UNSIGNED_BYTE);
1620
fname = "texture_tile.png";
1621
polkadots_texture = GLTexture::readImageToTexture (fname, pname, polkadots_texture_size);
1623
if (polkadots_texture.empty ())
1624
compLogMessage ("expo", CompLogLevelWarn, "failed to bind image to texture");
1627
foreach (GLTexture *tex, polkadots_texture)
1629
tex->enable (GLTexture::Good);
1630
glTexParameteri (tex->target (), GL_TEXTURE_WRAP_S, GL_REPEAT);
1631
glTexParameteri (tex->target (), GL_TEXTURE_WRAP_T, GL_REPEAT);
1637
ExpoScreen::~ExpoScreen ()
1640
XFreeCursor (screen->dpy (), mMoveCursor);
1644
ExpoWindow::resizeNotify(int dx, int dy, int dw, int dh)
1646
window->resizeNotify (dx, dy, dw, dh);
1648
/* mGlowQuads contains positional info, so we need to recalc that */
1651
/* FIXME: we need to find a more multitexture friendly way
1653
GLTexture::Matrix tMat = eScreen->outline_texture.at (0)->matrix ();
1654
computeGlowQuads (&tMat);
1658
ExpoWindow::ExpoWindow (CompWindow *w) :
1659
PluginClassHandler<ExpoWindow, CompWindow> (w),
1661
cWindow (CompositeWindow::get (w)),
1662
gWindow (GLWindow::get (w)),
1663
eScreen (ExpoScreen::get (screen)),
1667
CompositeWindowInterface::setHandler (cWindow, false);
1668
GLWindowInterface::setHandler (gWindow, false);
1669
WindowInterface::setHandler (window, true);
1671
if (window->type () & CompWindowTypeDesktopMask)
1673
foreach (GLTexture *tex, eScreen->outline_texture)
1675
GLTexture::Matrix mat = tex->matrix ();
1676
computeGlowQuads (&mat);
1681
ExpoWindow::~ExpoWindow ()
1683
eScreen->dndWindows.remove (window);
1684
computeGlowQuads (NULL);
1688
ExpoPluginVTable::init ()
1690
if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
1691
!CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) ||
1692
!CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))