2
* Copyright © 2005 Novell, Inc.
4
* Permission to use, copy, modify, distribute, and sell this software
5
* and its documentation for any purpose is hereby granted without
6
* fee, provided that the above copyright notice appear in all copies
7
* and that both that copyright notice and this permission notice
8
* appear in supporting documentation, and that the name of
9
* Novell, Inc. not be used in advertising or publicity pertaining to
10
* distribution of the software without specific, written prior permission.
11
* Novell, Inc. makes no representations about the suitability of this
12
* software for any purpose. It is provided "as is" without express or
15
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23
* Author: David Reveman <davidr@novell.com>
32
#include <X11/Xatom.h>
33
#include <X11/cursorfont.h>
35
#include <core/atoms.h>
36
#include <scale/scale.h>
39
#define EDGE_STATE (CompAction::StateInitEdge)
41
class ScalePluginVTable :
42
public CompPlugin::VTableForScreenAndWindow<ScaleScreen, ScaleWindow>
50
COMPIZ_PLUGIN_20090315 (scale, ScalePluginVTable)
53
PrivateScaleWindow::isNeverScaleWin () const
55
if (window->overrideRedirect ())
58
if (window->wmType () & (CompWindowTypeDockMask |
59
CompWindowTypeDesktopMask))
66
PrivateScaleWindow::isScaleWin () const
68
if (isNeverScaleWin ())
71
if (!spScreen->type || spScreen->type == ScaleTypeOutput)
73
if (!window->focus ())
77
if (window->state () & CompWindowStateSkipPagerMask)
80
if (window->state () & CompWindowStateShadedMask)
83
if (!window->mapNum () || !window->isViewable ())
86
switch (sScreen->priv->type) {
88
if (spScreen->clientLeader != window->clientLeader () &&
89
spScreen->clientLeader != window->id ())
93
if ((unsigned int) window->outputDevice () !=
94
(unsigned int) screen->currentOutputDev ().id ())
100
if (!spScreen->currentMatch.evaluate (window))
107
PrivateScaleScreen::activateEvent (bool activating)
109
CompOption::Vector o (0);
111
o.push_back (CompOption ("root", CompOption::TypeInt));
112
o.push_back (CompOption ("active", CompOption::TypeBool));
114
o[0].value ().set ((int) screen->root ());
115
o[1].value ().set (activating);
117
screen->handleCompizEvent ("scale", "activate", o);
121
ScaleWindowInterface::scalePaintDecoration (const GLWindowPaintAttrib& attrib,
122
const GLMatrix& transform,
123
const CompRegion& region,
125
WRAPABLE_DEF (scalePaintDecoration, attrib, transform, region, mask)
128
ScaleWindow::scalePaintDecoration (const GLWindowPaintAttrib& attrib,
129
const GLMatrix& transform,
130
const CompRegion& region,
133
WRAPABLE_HND_FUNC (0, scalePaintDecoration, attrib, transform, region, mask)
135
if (priv->spScreen->optionGetOverlayIcon () != ScaleOptions::OverlayIconNone)
137
GLWindowPaintAttrib sAttrib (attrib);
140
icon = priv->gWindow->getIcon (96, 96);
142
icon = priv->spScreen->gScreen->defaultIcon ();
149
int scaledWinWidth, scaledWinHeight;
151
scaledWinWidth = priv->window->width () * priv->scale;
152
scaledWinHeight = priv->window->height () * priv->scale;
154
switch (priv->spScreen->optionGetOverlayIcon ()) {
155
case ScaleOptions::OverlayIconNone:
156
case ScaleOptions::OverlayIconEmblem:
159
case ScaleOptions::OverlayIconBig:
161
sAttrib.opacity /= 3;
162
scale = MIN (((float) scaledWinWidth / icon->width ()),
163
((float) scaledWinHeight / icon->height ()));
167
width = icon->width () * scale;
168
height = icon->height () * scale;
170
switch (priv->spScreen->optionGetOverlayIcon ()) {
171
case ScaleOptions::OverlayIconNone:
172
case ScaleOptions::OverlayIconEmblem:
173
x = priv->window->x () + scaledWinWidth - icon->width ();
174
y = priv->window->y () + scaledWinHeight - icon->height ();
176
case ScaleOptions::OverlayIconBig:
178
x = priv->window->x () + scaledWinWidth / 2 - width / 2;
179
y = priv->window->y () + scaledWinHeight / 2 - height / 2;
188
priv->delta = fabs (priv->slot->x1 () - priv->window->x ()) +
189
fabs (priv->slot->y1 () - priv->window->y ()) +
190
fabs (1.0f - priv->slot->scale) * 500.0f;
198
ds = fabs (priv->tx) +
200
fabs (1.0f - priv->scale) * 500.0f;
202
if (ds > priv->delta)
205
o = ds / priv->delta;
209
if (o < priv->lastThumbOpacity)
210
o = priv->lastThumbOpacity;
214
if (o > priv->lastThumbOpacity)
218
priv->lastThumbOpacity = o;
220
sAttrib.opacity = sAttrib.opacity * o;
223
mask |= PAINT_WINDOW_BLEND_MASK;
225
CompRegion iconReg (0, 0, width, height);
226
GLTexture::MatrixList ml (1);
228
ml[0] = icon->matrix ();
229
priv->gWindow->geometry ().reset ();
232
priv->gWindow->glAddGeometry (ml, iconReg, iconReg);
234
if (priv->gWindow->geometry ().vCount)
236
GLFragment::Attrib fragment (sAttrib);
237
GLMatrix wTransform (transform);
239
wTransform.scale (scale, scale, 1.0f);
240
wTransform.translate (x / scale, y / scale, 0.0f);
243
glLoadMatrixf (wTransform.getMatrix ());
245
priv->gWindow->glDrawTexture (icon, fragment, mask);
254
ScaleWindowInterface::setScaledPaintAttributes (GLWindowPaintAttrib& attrib)
255
WRAPABLE_DEF (setScaledPaintAttributes, attrib)
258
ScaleWindow::setScaledPaintAttributes (GLWindowPaintAttrib& attrib)
260
WRAPABLE_HND_FUNC_RETURN (1, bool, setScaledPaintAttributes, attrib)
262
bool drawScaled = false;
264
if (priv->adjust || priv->slot)
266
if (priv->window->id () != priv->spScreen->selectedWindow &&
267
priv->spScreen->opacity != OPAQUE &&
268
priv->spScreen->state != ScaleScreen::In)
270
/* modify opacity of windows that are not active */
271
attrib.opacity = (attrib.opacity * priv->spScreen->opacity) >> 16;
276
else if (priv->spScreen->state != ScaleScreen::In)
278
if (priv->spScreen->optionGetDarkenBack ())
280
/* modify brightness of the other windows */
281
attrib.brightness = attrib.brightness / 2;
284
/* hide windows on the outputs used for scaling
285
that are not in scale mode */
286
if (!priv->isNeverScaleWin ())
290
moMode = priv->spScreen->getMultioutputMode ();
293
case ScaleOptions::MultioutputModeOnCurrentOutputDevice:
294
output = screen->currentOutputDev ().id ();
295
if (priv->window->outputDevice () == output)
309
PrivateScaleWindow::glPaint (const GLWindowPaintAttrib& attrib,
310
const GLMatrix& transform,
311
const CompRegion& region,
316
if (spScreen->state != ScaleScreen::Idle)
318
GLWindowPaintAttrib sAttrib (attrib);
321
scaled = sWindow->setScaledPaintAttributes (sAttrib);
324
mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
326
status = gWindow->glPaint (sAttrib, transform, region, mask);
330
GLFragment::Attrib fragment (gWindow->lastPaintAttrib ());
331
GLMatrix wTransform (transform);
333
if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
336
if (window->alpha () || fragment.getOpacity () != OPAQUE)
337
mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
339
wTransform.translate (window->x (), window->y (), 0.0f);
340
wTransform.scale (scale, scale, 1.0f);
341
wTransform.translate (tx / scale - window->x (),
342
ty / scale - window->y (), 0.0f);
345
glLoadMatrixf (wTransform.getMatrix ());
347
gWindow->glDraw (wTransform, fragment, region,
348
mask | PAINT_WINDOW_TRANSFORMED_MASK);
352
sWindow->scalePaintDecoration (sAttrib, transform, region, mask);
357
status = gWindow->glPaint (attrib, transform, region, mask);
364
PrivateScaleWindow::compareWindowsDistance (ScaleWindow *w1,
367
return w1->priv->distance < w2->priv->distance;
371
PrivateScaleScreen::layoutSlotsForArea (const CompRect& workArea,
375
int x, y, width, height;
376
int lines, n, nSlots;
382
lines = sqrt (nWindows + 1);
383
spacing = optionGetSpacing ();
386
y = workArea.y () + spacing;
387
height = (workArea.height () - (lines + 1) * spacing) / lines;
389
for (i = 0; i < lines; i++)
391
n = MIN (nWindows - nSlots, ceilf ((float) nWindows / lines));
393
x = workArea.x () + spacing;
394
width = (workArea.width () - (n + 1) * spacing) / n;
396
for (j = 0; j < n; j++)
398
slots[this->nSlots].setGeometry (x, y, width, height);
400
slots[this->nSlots].filled = false;
402
x += width + spacing;
408
y += height + spacing;
413
PrivateScaleScreen::getSlotAreas ()
417
std::vector<float> size;
418
float sizePerWindow, sum = 0.0f;
420
SlotArea::vector slotAreas;
422
slotAreas.resize (screen->outputDevs ().size ());
423
size.resize (screen->outputDevs ().size ());
425
left = windows.size ();
427
foreach (CompOutput &o, screen->outputDevs ())
429
/* determine the size of the workarea for each output device */
430
workArea = CompRect (o.workArea ());
432
size[i] = workArea.width () * workArea.height ();
435
slotAreas[i].nWindows = 0;
436
slotAreas[i].workArea = workArea;
441
/* calculate size available for each window */
442
sizePerWindow = sum / windows.size ();
444
for (i = 0; i < screen->outputDevs ().size () && left; i++)
446
/* fill the areas with windows */
447
int nw = floor (size[i] / sizePerWindow);
450
size[i] -= nw * sizePerWindow;
451
slotAreas[i].nWindows = nw;
455
/* add left windows to output devices with the biggest free space */
461
for (i = 0; i < screen->outputDevs ().size (); i++)
470
size[num] -= sizePerWindow;
471
slotAreas[num].nWindows++;
479
PrivateScaleScreen::layoutSlots ()
483
moMode = getMultioutputMode ();
485
/* if we have only one head, we don't need the
486
additional effort of the all outputs mode */
487
if (screen->outputDevs ().size () == 1)
488
moMode = ScaleOptions::MultioutputModeOnCurrentOutputDevice;
494
case ScaleOptions::MultioutputModeOnAllOutputDevices:
496
SlotArea::vector slotAreas = getSlotAreas ();
497
if (slotAreas.size ())
499
foreach (SlotArea &sa, slotAreas)
500
layoutSlotsForArea (sa.workArea, sa.nWindows);
504
case ScaleOptions::MultioutputModeOnCurrentOutputDevice:
507
CompRect workArea (screen->currentOutputDev ().workArea ());
508
layoutSlotsForArea (workArea, windows.size ());
515
PrivateScaleScreen::findBestSlots ()
519
float sx, sy, cx, cy;
521
foreach (ScaleWindow *sw, windows)
523
w = sw->priv->window;
529
sw->priv->distance = MAXSHORT;
531
for (i = 0; i < nSlots; i++)
533
if (!slots[i].filled)
535
sx = (slots[i].x2 () + slots[i].x1 ()) / 2;
536
sy = (slots[i].y2 () + slots[i].y1 ()) / 2;
538
cx = w->serverX () + w->width () / 2;
539
cy = w->serverY () + w->height () / 2;
544
d = sqrt (cx * cx + cy * cy);
545
if (d0 + d < sw->priv->distance)
548
sw->priv->distance = d0 + d;
553
d0 += sw->priv->distance;
558
PrivateScaleScreen::fillInWindows ()
562
float sx, sy, cx, cy;
564
foreach (ScaleWindow *sw, windows)
566
w = sw->priv->window;
570
if (slots[sw->priv->sid].filled)
573
sw->priv->slot = &slots[sw->priv->sid];
575
/* Auxilary items reparented into windows are clickable so we want to care about
576
* them when calculating the slot size */
578
width = w->width () + w->input ().left + w->input ().right;
579
height = w->height () + w->input ().top + w->input ().bottom;
581
sx = (float) (sw->priv->slot->x2 () - sw->priv->slot->x1 ()) / width;
582
sy = (float) (sw->priv->slot->y2 () - sw->priv->slot->y1 ()) / height;
584
sw->priv->slot->scale = MIN (MIN (sx, sy), 1.0f);
586
sx = width * sw->priv->slot->scale;
587
sy = height * sw->priv->slot->scale;
588
cx = (sw->priv->slot->x1 () + sw->priv->slot->x2 ()) / 2;
589
cy = (sw->priv->slot->y1 () + sw->priv->slot->y2 ()) / 2;
591
cx += w->input ().left * sw->priv->slot->scale;
592
cy += w->input ().top * sw->priv->slot->scale;
594
sw->priv->slot->setGeometry (cx - sx / 2, cy - sy / 2, sx, sy);
596
sw->priv->slot->filled = true;
598
sw->priv->lastThumbOpacity = 0.0f;
600
sw->priv->adjust = true;
608
ScaleScreenInterface::layoutSlotsAndAssignWindows ()
609
WRAPABLE_DEF (layoutSlotsAndAssignWindows)
612
ScaleScreen::layoutSlotsAndAssignWindows ()
614
WRAPABLE_HND_FUNC_RETURN (0, bool, layoutSlotsAndAssignWindows)
616
/* create a grid of slots */
617
priv->layoutSlots ();
621
/* find most appropriate slots for windows */
622
priv->findBestSlots ();
624
/* sort windows, window with closest distance to a slot first */
625
priv->windows.sort (PrivateScaleWindow::compareWindowsDistance);
626
} while (priv->fillInWindows ());
632
ScaleScreen::hasGrab () const
638
ScaleScreen::getState () const
644
ScaleScreen::getType () const
650
ScaleScreen::getCustomMatch () const
655
const ScaleScreen::WindowList&
656
ScaleScreen::getWindows () const
658
return priv->windows;
662
PrivateScaleScreen::layoutThumbs ()
666
/* add windows scale list, top most window first */
667
foreach (CompWindow *w, screen->windows ())
672
sw->priv->adjust = true;
674
sw->priv->slot = NULL;
676
if (!sw->priv->isScaleWin ())
679
windows.push_back (sw);
682
if (windows.empty ())
685
slots.resize (windows.size ());
687
return ScaleScreen::get (screen)->layoutSlotsAndAssignWindows ();
691
PrivateScaleWindow::adjustScaleVelocity ()
693
float dx, dy, ds, adjust, amount;
709
dx = x1 - (window->x () + tx);
712
amount = fabs (dx) * 1.5f;
715
else if (amount > 5.0f)
718
xVelocity = (amount * xVelocity + adjust) / (amount + 1.0f);
720
dy = y1 - (window->y () + ty);
723
amount = fabs (dy) * 1.5f;
726
else if (amount > 5.0f)
729
yVelocity = (amount * yVelocity + adjust) / (amount + 1.0f);
731
ds = scale - this->scale;
734
amount = fabs (ds) * 7.0f;
737
else if (amount > 0.15f)
740
scaleVelocity = (amount * scaleVelocity + adjust) / (amount + 1.0f);
742
if (fabs (dx) < 0.1f && fabs (xVelocity) < 0.2f &&
743
fabs (dy) < 0.1f && fabs (yVelocity) < 0.2f &&
744
fabs (ds) < 0.001f && fabs (scaleVelocity) < 0.002f)
746
xVelocity = yVelocity = scaleVelocity = 0.0f;
747
tx = x1 - window->x ();
748
ty = y1 - window->y ();
758
PrivateScaleScreen::glPaintOutput (const GLScreenPaintAttrib& sAttrib,
759
const GLMatrix& transform,
760
const CompRegion& region,
764
if (state != ScaleScreen::Idle)
765
mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
767
return gScreen->glPaintOutput (sAttrib, transform, region, output, mask);
771
PrivateScaleScreen::preparePaint (int msSinceLastPaint)
773
if (state != ScaleScreen::Idle && state != ScaleScreen::Wait)
778
amount = msSinceLastPaint * 0.05f * optionGetSpeed ();
779
steps = amount / (0.5f * optionGetTimestep ());
783
chunk = amount / (float) steps;
789
foreach (CompWindow *w, screen->windows ())
793
if (sw->priv->adjust)
795
sw->priv->adjust = sw->priv->adjustScaleVelocity ();
797
moreAdjust |= sw->priv->adjust;
799
sw->priv->tx += sw->priv->xVelocity * chunk;
800
sw->priv->ty += sw->priv->yVelocity * chunk;
801
sw->priv->scale += sw->priv->scaleVelocity * chunk;
810
cScreen->preparePaint (msSinceLastPaint);
814
PrivateScaleScreen::donePaint ()
816
if (state != ScaleScreen::Idle)
820
cScreen->damageScreen ();
824
if (state == ScaleScreen::In)
826
/* The false activate event is sent when scale state
827
goes back to normal, to avoid animation conflicts
828
with other plugins. */
829
activateEvent (false);
830
state = ScaleScreen::Idle;
832
cScreen->preparePaintSetEnabled (this, false);
833
cScreen->donePaintSetEnabled (this, false);
834
gScreen->glPaintOutputSetEnabled (this, false);
836
foreach (CompWindow *w, screen->windows ())
839
sw->priv->cWindow->damageRectSetEnabled (sw->priv, false);
840
sw->priv->gWindow->glPaintSetEnabled (sw->priv, false);
843
else if (state == ScaleScreen::Out)
844
state = ScaleScreen::Wait;
848
cScreen->donePaint ();
852
PrivateScaleScreen::checkForWindowAt (int x, int y)
855
CompWindowList::reverse_iterator rit = screen->windows ().rbegin ();
857
for (; rit != screen->windows ().rend (); rit++)
859
CompWindow *w = *rit;
864
x1 = w->x () - w->input ().left * sw->priv->scale;
865
y1 = w->y () - w->input ().top * sw->priv->scale;
867
(w->width () + w->input ().right) * sw->priv->scale;
869
(w->height () + w->input ().bottom) * sw->priv->scale;
876
if (x1 <= x && y1 <= y && x2 > x && y2 > y)
885
PrivateScaleScreen::sendDndStatusMessage (Window source)
889
xev.xclient.type = ClientMessage;
890
xev.xclient.display = screen->dpy ();
891
xev.xclient.format = 32;
893
xev.xclient.message_type = Atoms::xdndStatus;
894
xev.xclient.window = source;
896
xev.xclient.data.l[0] = dndTarget;
897
xev.xclient.data.l[1] = 2;
898
xev.xclient.data.l[2] = 0;
899
xev.xclient.data.l[3] = 0;
900
xev.xclient.data.l[4] = None;
902
XSendEvent (screen->dpy (), source, false, 0, &xev);
906
PrivateScaleScreen::scaleTerminate (CompAction *action,
907
CompAction::State state,
908
CompOption::Vector &options)
910
SCALE_SCREEN (screen);
914
if (ss->priv->actionShouldToggle (action, state))
917
xid = CompOption::getIntOptionNamed (options, "root");
918
if (xid && ::screen->root () != xid)
924
if (ss->priv->grabIndex)
926
::screen->removeGrab (ss->priv->grabIndex, 0);
927
ss->priv->grabIndex = 0;
930
if (ss->priv->dndTarget)
931
XUnmapWindow (::screen->dpy (), ss->priv->dndTarget);
933
ss->priv->grab = false;
935
if (ss->priv->state != ScaleScreen::Idle)
937
foreach (CompWindow *w, ::screen->windows ())
943
sw->priv->slot = NULL;
944
sw->priv->adjust = true;
948
if (state & CompAction::StateCancel)
950
if (::screen->activeWindow () != ss->priv->previousActiveWindow)
954
w = ::screen->findWindow (ss->priv->previousActiveWindow);
956
w->moveInputFocusTo ();
959
else if (ss->priv->state != ScaleScreen::In)
961
CompWindow *w = ::screen->findWindow (ss->priv->selectedWindow);
966
ss->priv->state = ScaleScreen::In;
967
ss->priv->cScreen->damageScreen ();
970
if (state & CompAction::StateInitKey)
971
action->setState (action->state () | CompAction::StateTermKey);
973
ss->priv->lastActiveNum = 0;
979
PrivateScaleScreen::ensureDndRedirectWindow ()
983
XSetWindowAttributes attr;
984
long xdndVersion = 3;
986
attr.override_redirect = true;
988
dndTarget = XCreateWindow (screen->dpy (), screen->root (),
989
0, 0, 1, 1, 0, CopyFromParent,
990
InputOnly, CopyFromParent,
991
CWOverrideRedirect, &attr);
993
XChangeProperty (screen->dpy (), dndTarget,
995
XA_ATOM, 32, PropModeReplace,
996
(unsigned char *) &xdndVersion, 1);
999
XMoveResizeWindow (screen->dpy (), dndTarget,
1000
0, 0, screen->width (), screen->height ());
1001
XMapRaised (screen->dpy (), dndTarget);
1007
PrivateScaleScreen::actionShouldToggle (CompAction *action,
1008
CompAction::State state)
1010
if (state & EDGE_STATE)
1013
if (state & (CompAction::StateInitKey | CompAction::StateTermKey))
1015
if (optionGetKeyBindingsToggle ())
1017
else if (!action->key ().modifiers ())
1021
if (state & (CompAction::StateInitButton | CompAction::StateTermButton))
1022
if (optionGetButtonBindingsToggle ())
1029
PrivateScaleScreen::scaleInitiate (CompAction *action,
1030
CompAction::State state,
1031
CompOption::Vector &options,
1036
xid = CompOption::getIntOptionNamed (options, "root");
1038
if (::screen->root () == xid)
1040
SCALE_SCREEN (::screen);
1042
if (ss->priv->actionShouldToggle (action, state) &&
1043
(ss->priv->state == ScaleScreen::Wait ||
1044
ss->priv->state == ScaleScreen::Out))
1046
if (ss->priv->type == type)
1047
return scaleTerminate (action,
1048
CompAction::StateCancel,
1053
ss->priv->type = type;
1054
return ss->priv->scaleInitiateCommon (action, state, options);
1062
PrivateScaleScreen::scaleInitiateCommon (CompAction *action,
1063
CompAction::State state,
1064
CompOption::Vector &options)
1066
if (screen->otherGrabExist ("scale", NULL))
1069
match = CompOption::getMatchOptionNamed (options, "match",
1070
CompMatch::emptyMatch);
1071
if (match.isEmpty ())
1072
match = optionGetWindowMatch ();
1074
currentMatch = match;
1076
if (!layoutThumbs ())
1079
if (state & CompAction::StateInitEdgeDnd)
1081
if (ensureDndRedirectWindow ())
1084
else if (!grabIndex)
1086
grabIndex = screen->pushGrab (cursor, "scale");
1094
lastActiveNum = screen->activeNum () - 1;
1096
previousActiveWindow = screen->activeWindow ();
1097
lastActiveWindow = screen->activeWindow ();
1098
selectedWindow = screen->activeWindow ();
1099
hoveredWindow = None;
1101
this->state = ScaleScreen::Out;
1103
activateEvent (true);
1105
cScreen->damageScreen ();
1107
cScreen->preparePaintSetEnabled (this, true);
1108
cScreen->donePaintSetEnabled (this, true);
1109
gScreen->glPaintOutputSetEnabled (this, true);
1111
foreach (CompWindow *w, screen->windows ())
1114
sw->priv->cWindow->damageRectSetEnabled (sw->priv, true);
1115
sw->priv->gWindow->glPaintSetEnabled (sw->priv, true);
1119
if ((state & (CompAction::StateInitButton | EDGE_STATE)) ==
1120
CompAction::StateInitButton)
1122
action->setState (action->state () | CompAction::StateTermButton);
1125
if (state & CompAction::StateInitKey)
1126
action->setState (action->state () | CompAction::StateTermKey);
1132
ScaleWindowInterface::scaleSelectWindow ()
1133
WRAPABLE_DEF (scaleSelectWindow)
1136
ScaleWindow::scaleSelectWindow ()
1138
WRAPABLE_HND_FUNC (2, scaleSelectWindow)
1140
if (priv->spScreen->selectedWindow != priv->window->id ())
1142
CompWindow *oldW, *newW;
1144
oldW = screen->findWindow (priv->spScreen->selectedWindow);
1145
newW = screen->findWindow (priv->window->id ());
1147
priv->spScreen->selectedWindow = priv->window->id ();
1150
CompositeWindow::get (oldW)->addDamage ();
1153
CompositeWindow::get (newW)->addDamage ();
1158
ScaleWindow::hasSlot () const
1160
return priv->slot != NULL;
1164
ScaleWindow::getSlot () const
1176
ScaleWindow::setSlot (const ScaleSlot &newSlot)
1178
SCALE_SCREEN (screen);
1180
priv->adjust = true;
1183
priv->slot = new ScaleSlot ();
1184
*priv->slot = newSlot;
1186
/* Trigger the animation to this point */
1188
if (ss->priv->state == ScaleScreen::Wait)
1189
ss->priv->state = ScaleScreen::Out;
1190
else if (ss->priv->state == ScaleScreen::Idle)
1191
ss->priv->state = ScaleScreen::In;
1193
priv->cWindow->addDamage ();
1197
ScaleWindow::getCurrentPosition () const
1201
pos.setX (priv->tx);
1202
pos.setY (priv->ty);
1204
pos.scale = priv->scale;
1210
ScaleWindow::setCurrentPosition (const ScalePosition &newPos)
1212
SCALE_SCREEN (screen);
1214
priv->tx = newPos.x ();
1215
priv->ty = newPos.y ();
1216
priv->scale = newPos.scale;
1218
/* Trigger the animation to this point */
1220
if (ss->priv->state == ScaleScreen::Wait)
1221
ss->priv->state = ScaleScreen::Out;
1222
else if (ss->priv->state == ScaleScreen::Idle)
1223
ss->priv->state = ScaleScreen::In;
1225
priv->cWindow->addDamage ();
1227
priv->adjust = true;
1231
ScaleScreen::getHoveredWindow ()
1233
return priv->hoveredWindow;
1237
PrivateScaleScreen::selectWindowAt (int x,
1239
bool moveInputFocus)
1241
ScaleWindow *w = checkForWindowAt (x, y);
1242
if (w && w->priv->isScaleWin ())
1244
w->scaleSelectWindow ();
1248
lastActiveNum = w->priv->window->activeNum ();
1249
lastActiveWindow = w->priv->window->id ();
1251
w->priv->window->moveInputFocusTo ();
1254
hoveredWindow = w->priv->window->id ();
1259
hoveredWindow = None;
1265
PrivateScaleScreen::moveFocusWindow (int dx,
1269
CompWindow *focus = NULL;
1271
active = screen->findWindow (screen->activeWindow ());
1274
SCALE_WINDOW (active);
1279
int x, y, cx, cy, d, min = MAXSHORT;
1281
cx = (sw->priv->slot->x1 () + sw->priv->slot->x2 ()) / 2;
1282
cy = (sw->priv->slot->y1 () + sw->priv->slot->y2 ()) / 2;
1284
foreach (CompWindow *w, screen->windows ())
1286
slot = ScaleWindow::get (w)->priv->slot;
1290
x = (slot->x1 () + slot->x2 ()) / 2;
1291
y = (slot->y1 () + slot->y2 ()) / 2;
1293
d = abs (x - cx) + abs (y - cy);
1296
if ((dx > 0 && slot->x1 () < sw->priv->slot->x2 ()) ||
1297
(dx < 0 && slot->x2 () > sw->priv->slot->x1 ()) ||
1298
(dy > 0 && slot->y1 () < sw->priv->slot->y2 ()) ||
1299
(dy < 0 && slot->y2 () > sw->priv->slot->y1 ()))
1309
/* move focus to the last focused window if no slot window is currently
1313
foreach (CompWindow *w, screen->windows ())
1315
if (!ScaleWindow::get (w)->priv->slot)
1318
if (!focus || focus->activeNum () < w->activeNum ())
1325
ScaleWindow::get (focus)->scaleSelectWindow ();
1327
lastActiveNum = focus->activeNum ();
1328
lastActiveWindow = focus->id ();
1330
focus->moveInputFocusTo ();
1335
ScaleScreen::relayoutSlots (const CompMatch& match)
1337
if (match.isEmpty ())
1338
priv->currentMatch = priv->match;
1340
priv->currentMatch = match;
1342
if (priv->state == ScaleScreen::Idle || priv->state == ScaleScreen::In)
1345
if (priv->layoutThumbs ())
1347
priv->state = ScaleScreen::Out;
1348
priv->moveFocusWindow (0, 0);
1351
priv->cScreen->damageScreen ();
1355
PrivateScaleScreen::windowRemove (CompWindow *w)
1360
if (state == ScaleScreen::Idle || state == ScaleScreen::In)
1363
foreach (ScaleWindow *lw, windows)
1365
if (lw->priv->window == w)
1367
if (layoutThumbs ())
1369
state = ScaleScreen::Out;
1370
cScreen->damageScreen ();
1375
CompOption::Vector o (0);
1378
/* terminate scale mode if the recently closed
1379
* window was the last scaled window */
1381
o.push_back (CompOption ("root", CompOption::TypeInt));
1382
o[0].value ().set ((int) screen->root ());
1384
action = &optionGetInitiateEdge ();
1385
scaleTerminate (action, CompAction::StateCancel, o);
1387
action = &optionGetInitiateKey ();
1388
scaleTerminate (action, CompAction::StateCancel, o);
1396
PrivateScaleScreen::hoverTimeout ()
1398
if (grab && state != ScaleScreen::In)
1401
CompOption::Vector o (0);
1403
w = screen->findWindow (selectedWindow);
1406
lastActiveNum = w->activeNum ();
1407
lastActiveWindow = w->id ();
1409
w->moveInputFocusTo ();
1412
o.push_back (CompOption ("root", CompOption::TypeInt));
1413
o[0].value ().set ((int) screen->root ());
1415
scaleTerminate (&optionGetInitiateEdge (), 0, o);
1416
scaleTerminate (&optionGetInitiateKey (), 0, o);
1423
PrivateScaleScreen::handleEvent (XEvent *event)
1425
CompWindow *w = NULL;
1427
switch (event->type) {
1429
if (screen->root () == event->xkey.root)
1433
if (event->xkey.keycode == leftKeyCode)
1434
moveFocusWindow (-1, 0);
1435
else if (event->xkey.keycode == rightKeyCode)
1436
moveFocusWindow (1, 0);
1437
else if (event->xkey.keycode == upKeyCode)
1438
moveFocusWindow (0, -1);
1439
else if (event->xkey.keycode == downKeyCode)
1440
moveFocusWindow (0, 1);
1445
if (screen->root () == event->xbutton.root &&
1447
state != ScaleScreen::In)
1449
XButtonEvent *button = &event->xbutton;
1450
CompOption::Vector o (0);
1452
o.push_back (CompOption ("root", CompOption::TypeInt));
1453
o[0].value ().set ((int) screen->root ());
1455
/* Button1 terminates scale mode, other buttons can select
1457
if (selectWindowAt (button->x_root, button->y_root, true) &&
1458
event->xbutton.button == Button1)
1460
scaleTerminate (&optionGetInitiateEdge (), 0, o);
1461
scaleTerminate (&optionGetInitiateKey (), 0, o);
1463
else if (optionGetShowDesktop () &&
1464
event->xbutton.button == Button1)
1466
CompPoint pointer (button->x_root, button->y_root);
1467
CompRect workArea (screen->workArea ());
1469
if (workArea.contains (pointer))
1471
scaleTerminate (&optionGetInitiateEdge (), 0, o);
1472
scaleTerminate (&optionGetInitiateKey (), 0, o);
1473
screen->enterShowDesktopMode ();
1479
if (screen->root () == event->xmotion.root &&
1481
state != ScaleScreen::In)
1484
CompOption *o = screen->getOption ("click_to_focus");
1486
if (o && o->value ().b ())
1489
selectWindowAt (event->xmotion.x_root,
1490
event->xmotion.y_root,
1496
/* We need to get the CompWindow * for event->xdestroywindow.window
1497
* here because in the ::handleEvent call below that CompWindow's
1498
* id will become "1" so CompScreen::findWindow won't
1499
* be able to find teh window after that
1502
w = screen->findWindow (event->xdestroywindow.window);
1506
w = screen->findWindow (event->xunmap.window);
1509
if (event->xclient.message_type == Atoms::xdndPosition)
1511
w = screen->findWindow (event->xclient.window);
1515
CompOption *o = screen->getOption ("click_to_focus");
1517
if (o && o->value ().b ())
1520
if (w->id () == dndTarget)
1521
sendDndStatusMessage (event->xclient.data.l[0]);
1524
state != ScaleScreen::In &&
1525
w->id () == dndTarget)
1527
ScaleWindow *sw = checkForWindowAt (pointerX, pointerY);
1528
if (sw && sw->priv->isScaleWin ())
1532
time = optionGetHoverTime ();
1534
if (hover.active ())
1536
int lastMotion = sqrt (pow (pointerX - lastPointerX, 2) + pow (pointerY - lastPointerY, 2));
1538
if (sw->window->id () != selectedWindow || lastMotion > optionGetDndDistance ())
1542
if (!hover.active ())
1544
hover.start (time, (float) time * 1.2);
1547
selectWindowAt (pointerX, pointerY, focus);
1551
if (hover.active ())
1557
else if (event->xclient.message_type == Atoms::xdndDrop ||
1558
event->xclient.message_type == Atoms::xdndLeave)
1560
w = screen->findWindow (event->xclient.window);
1564
state != ScaleScreen::In &&
1565
w->id () == dndTarget)
1567
CompOption::Vector o (0);
1568
o.push_back (CompOption ("root", CompOption::TypeInt));
1569
o[0].value ().set ((int) screen->root ());
1571
scaleTerminate (&optionGetInitiateEdge (), 0, o);
1572
scaleTerminate (&optionGetInitiateKey (), 0, o);
1580
screen->handleEvent (event);
1582
/* Only safe to remove the window after all events have been
1583
* handled, so that we don't get race conditions on calls
1584
* to scale functions */
1586
switch (event->type) {
1599
PrivateScaleWindow::damageRect (bool initial,
1600
const CompRect& rect)
1602
bool status = false;
1606
if (spScreen->grab && isScaleWin ())
1608
if (spScreen->layoutThumbs ())
1610
spScreen->state = ScaleScreen::Out;
1611
spScreen->cScreen->damageScreen ();
1615
else if (spScreen->state == ScaleScreen::Wait)
1619
cWindow->damageTransformedRect (scale, scale, tx, ty, rect);
1625
status |= cWindow->damageRect (initial, rect);
1630
ScaleScreen::ScaleScreen (CompScreen *s) :
1631
PluginClassHandler<ScaleScreen, CompScreen, COMPIZ_SCALE_ABI> (s),
1632
priv (new PrivateScaleScreen (s))
1636
ScaleScreen::~ScaleScreen ()
1641
ScaleWindow::ScaleWindow (CompWindow *w) :
1642
PluginClassHandler<ScaleWindow, CompWindow, COMPIZ_SCALE_ABI> (w),
1644
priv (new PrivateScaleWindow (w))
1648
ScaleWindow::~ScaleWindow ()
1653
PrivateScaleScreen::PrivateScaleScreen (CompScreen *s) :
1654
cScreen (CompositeScreen::get (s)),
1655
gScreen (GLScreen::get (s)),
1658
lastActiveWindow (None),
1660
selectedWindow (None),
1661
hoveredWindow (None),
1662
previousActiveWindow (None),
1666
state (ScaleScreen::Idle),
1671
leftKeyCode = XKeysymToKeycode (screen->dpy (), XStringToKeysym ("Left"));
1672
rightKeyCode = XKeysymToKeycode (screen->dpy (), XStringToKeysym ("Right"));
1673
upKeyCode = XKeysymToKeycode (screen->dpy (), XStringToKeysym ("Up"));
1674
downKeyCode = XKeysymToKeycode (screen->dpy (), XStringToKeysym ("Down"));
1676
cursor = XCreateFontCursor (screen->dpy (), XC_left_ptr);
1678
opacity = (OPAQUE * optionGetOpacity ()) / 100;
1680
hover.setCallback (boost::bind (&PrivateScaleScreen::hoverTimeout, this));
1682
optionSetOpacityNotify (boost::bind (&PrivateScaleScreen::updateOpacity, this));
1684
#define SCALEBIND(a) \
1685
boost::bind (PrivateScaleScreen::scaleInitiate, _1, _2, _3, a)
1687
optionSetInitiateEdgeInitiate (SCALEBIND (ScaleTypeNormal));
1688
optionSetInitiateEdgeTerminate (PrivateScaleScreen::scaleTerminate);
1689
optionSetInitiateButtonInitiate (SCALEBIND (ScaleTypeNormal));
1690
optionSetInitiateButtonTerminate (PrivateScaleScreen::scaleTerminate);
1691
optionSetInitiateKeyInitiate (SCALEBIND (ScaleTypeNormal));
1692
optionSetInitiateKeyTerminate (PrivateScaleScreen::scaleTerminate);
1694
optionSetInitiateAllEdgeInitiate (SCALEBIND (ScaleTypeAll));
1695
optionSetInitiateAllEdgeTerminate (PrivateScaleScreen::scaleTerminate);
1696
optionSetInitiateAllButtonInitiate (SCALEBIND (ScaleTypeAll));
1697
optionSetInitiateAllButtonTerminate (PrivateScaleScreen::scaleTerminate);
1698
optionSetInitiateAllKeyInitiate (SCALEBIND (ScaleTypeAll));
1699
optionSetInitiateAllKeyTerminate (PrivateScaleScreen::scaleTerminate);
1701
optionSetInitiateGroupEdgeInitiate (SCALEBIND (ScaleTypeGroup));
1702
optionSetInitiateGroupEdgeTerminate (PrivateScaleScreen::scaleTerminate);
1703
optionSetInitiateGroupButtonInitiate (SCALEBIND (ScaleTypeGroup));
1704
optionSetInitiateGroupButtonTerminate (PrivateScaleScreen::scaleTerminate);
1705
optionSetInitiateGroupKeyInitiate (SCALEBIND (ScaleTypeGroup));
1706
optionSetInitiateGroupKeyTerminate (PrivateScaleScreen::scaleTerminate);
1708
optionSetInitiateOutputEdgeInitiate (SCALEBIND (ScaleTypeOutput));
1709
optionSetInitiateOutputEdgeTerminate (PrivateScaleScreen::scaleTerminate);
1710
optionSetInitiateOutputButtonInitiate (SCALEBIND (ScaleTypeOutput));
1711
optionSetInitiateOutputButtonTerminate (PrivateScaleScreen::scaleTerminate);
1712
optionSetInitiateOutputKeyInitiate (SCALEBIND (ScaleTypeOutput));
1713
optionSetInitiateOutputKeyTerminate (PrivateScaleScreen::scaleTerminate);
1717
ScreenInterface::setHandler (s);
1718
CompositeScreenInterface::setHandler (cScreen, false);
1719
GLScreenInterface::setHandler (gScreen, false);
1722
PrivateScaleScreen::~PrivateScaleScreen ()
1725
XFreeCursor (screen->dpy (), cursor);
1729
PrivateScaleScreen::updateOpacity ()
1731
opacity = (OPAQUE * optionGetOpacity ()) / 100;
1734
/* When we are only scaling windows on the current output, over-ride the
1735
* multioutput mode so that windows will only be displayed on the current
1736
* output, regardless of the setting.
1739
PrivateScaleScreen::getMultioutputMode ()
1741
if (type == ScaleTypeOutput)
1742
return MultioutputModeOnCurrentOutputDevice;
1744
return optionGetMultioutputMode ();
1748
PrivateScaleWindow::PrivateScaleWindow (CompWindow *w) :
1750
cWindow (CompositeWindow::get (w)),
1751
gWindow (GLWindow::get (w)),
1752
sWindow (ScaleWindow::get (w)),
1753
sScreen (ScaleScreen::get (screen)),
1754
spScreen (sScreen->priv),
1760
scaleVelocity (0.0),
1766
lastThumbOpacity (0.0)
1768
CompositeWindowInterface::setHandler (cWindow,
1769
spScreen->state != ScaleScreen::Idle);
1770
GLWindowInterface::setHandler (gWindow,
1771
spScreen->state != ScaleScreen::Idle);
1774
PrivateScaleWindow::~PrivateScaleWindow ()
1778
CompOption::Vector &
1779
ScaleScreen::getOptions ()
1781
return priv->getOptions ();
1785
ScaleScreen::setOption (const CompString &name,
1786
CompOption::Value &value)
1788
return priv->setOption (name, value);
1792
ScalePluginVTable::init ()
1794
if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
1795
!CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) ||
1796
!CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))
1800
p.uval = COMPIZ_SCALE_ABI;
1801
screen->storeValue ("scale_ABI", p);
1807
ScalePluginVTable::fini ()
1809
screen->eraseValue ("scale_ABI");