3
* Compiz scale plugin addon plugin
7
* Copyright : (C) 2007 by Danny Baumann
8
* E-mail : maniac@opencompositing.org
10
* Organic scale mode taken from Beryl's scale.c, written by
11
* Copyright : (C) 2006 Diogo Ferreira
12
* E-mail : diogo@underdev.org
14
* Ported to Compiz 0.9 by:
15
* Copyright : (C) 2009 by Sam Spilsbury
16
* E-mail : smspillaz@gmail.com
18
* This program is free software; you can redistribute it and/or
19
* modify it under the terms of the GNU General Public License
20
* as published by the Free Software Foundation; either version 2
21
* of the License, or (at your option) any later version.
23
* This program is distributed in the hope that it will be useful,
24
* but WITHOUT ANY WARRANTY; without even the implied warranty of
25
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
* GNU General Public License for more details.
31
#include "scaleaddon.h"
34
COMPIZ_PLUGIN_20090315 (scaleaddon, ScaleAddonPluginVTable);
39
ScaleAddonWindow::renderTitle ()
41
CompText::Attrib attrib;
45
ADDON_SCREEN (screen);
52
if (!sWindow->hasSlot ())
55
titleOpt = as->optionGetWindowTitle ();
57
if (titleOpt == ScaleaddonOptions::WindowTitleNoDisplay)
60
if (titleOpt == ScaleaddonOptions::WindowTitleHighlightedWindowOnly &&
61
as->highlightedWindow != window->id ())
66
scale = sWindow->getSlot ().scale;
67
attrib.maxWidth = window->width () * scale;
68
attrib.maxHeight = window->height () * scale;
70
attrib.family = "Sans";
71
attrib.size = as->optionGetTitleSize ();
72
attrib.color[0] = as->optionGetFontColorRed ();
73
attrib.color[1] = as->optionGetFontColorGreen ();
74
attrib.color[2] = as->optionGetFontColorBlue ();
75
attrib.color[3] = as->optionGetFontColorAlpha ();
77
attrib.flags = CompText::WithBackground | CompText::Ellipsized;
78
if (as->optionGetTitleBold ())
79
attrib.flags |= CompText::StyleBold;
81
attrib.bgHMargin = as->optionGetBorderSize ();
82
attrib.bgVMargin = as->optionGetBorderSize ();
83
attrib.bgColor[0] = as->optionGetBackColorRed ();
84
attrib.bgColor[1] = as->optionGetBackColorGreen ();
85
attrib.bgColor[2] = as->optionGetBackColorBlue ();
86
attrib.bgColor[3] = as->optionGetBackColorAlpha ();
88
text.renderWindowTitle (window->id (),
89
as->sScreen->getType () == ScaleTypeAll,
94
ScaleAddonWindow::drawTitle ()
96
float x, y, width, height;
97
ScalePosition pos = sWindow->getCurrentPosition ();
98
CompRect geom = window->borderRect ();
100
width = text.getWidth ();
101
height = text.getHeight ();
103
x = pos.x () + window->x () + geom.width () * pos.scale / 2 - width / 2;
104
y = pos.y () + window->y () + geom.height () * pos.scale / 2 - height / 2;
106
text.draw (floor (x), floor (y), 1.0f);
110
ScaleAddonWindow::drawHighlight ()
113
GLint oldBlendSrc, oldBlendDst;
114
float x, y, width, height;
115
ScalePosition pos = sWindow->getCurrentPosition ();
116
CompRect geom = window->borderRect ();
118
ADDON_SCREEN (screen);
123
x = pos.x () + window->x () - (window->border ().left * pos.scale);
124
y = pos.y () + window->y () - (window->border ().top * pos.scale);
125
width = geom.width () * pos.scale;
126
height = geom.height () * pos.scale;
128
/* we use a poor replacement for roundf()
129
* (available in C99 only) here */
130
x = floor (x + 0.5f);
131
y = floor (y + 0.5f);
133
wasBlend = glIsEnabled (GL_BLEND);
134
glGetIntegerv (GL_BLEND_SRC, &oldBlendSrc);
135
glGetIntegerv (GL_BLEND_DST, &oldBlendDst);
140
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
142
glColor4us (as->optionGetHighlightColorRed (),
143
as->optionGetHighlightColorGreen (),
144
as->optionGetHighlightColorBlue (),
145
as->optionGetHighlightColorAlpha ());
147
glRectf (x, y + height, x + width, y);
149
glColor4usv (defaultColor);
152
glDisable (GL_BLEND);
153
glBlendFunc (oldBlendSrc, oldBlendDst);
157
ScaleAddonScreen::checkWindowHighlight ()
159
if (highlightedWindow != lastHighlightedWindow)
163
w = screen->findWindow (highlightedWindow);
168
aw->cWindow->addDamage ();
171
w = screen->findWindow (lastHighlightedWindow);
176
aw->cWindow->addDamage (w);
179
lastHighlightedWindow = highlightedWindow;
184
ScaleAddonScreen::closeWindow (CompAction *action,
185
CompAction::State state,
186
CompOption::Vector options)
190
if (!sScreen->hasGrab ())
193
w = screen->findWindow (highlightedWindow);
195
w->close (screen->getCurrentTime ());
201
ScaleAddonScreen::pullWindow (CompAction *action,
202
CompAction::State state,
203
CompOption::Vector options)
207
if (!sScreen->hasGrab ())
210
w = screen->findWindow (highlightedWindow);
213
int x, y, xOffset, yOffset;
216
vp = w->defaultViewport ();
218
xOffset = (screen->vp ().x () - vp.x ()) * screen->width ();
219
yOffset = (screen->vp ().y () - vp.y ()) * screen->height ();
221
x = w->x () + xOffset;
222
y = w->y () + yOffset;
224
if (optionGetConstrainPullToScreen ())
226
CompRect workArea, extents;
228
workArea = screen->outputDevs ()[w->outputDevice ()].workArea ();
229
extents = w->borderRect ();
231
extents.setX (extents.x () + xOffset);
232
extents.setY (extents.y () + yOffset);
234
if (extents.x1 () < workArea.x1 ())
235
x += workArea.x1 () - extents.x1 ();
236
else if (extents.x2 () > workArea.x2 ())
237
x += workArea.x2 () - extents.x2 ();
239
if (extents.y1 () < workArea.y1 ())
240
y += workArea.y1 () - extents.y1 ();
241
else if (extents.y2 () > workArea.y2 ())
242
y += workArea.y2 () - extents.y2 ();
245
if (x != w->x () || y != w->y ())
247
ScalePosition pos, oldPos;
250
oldPos = aw->sWindow->getCurrentPosition ();
252
w->moveToViewportPosition (x, y, true);
254
/* Select this window when ending scale */
255
aw->sWindow->scaleSelectWindow ();
257
/* stop scaled window dissapearing */
258
pos.setX (oldPos.x () - xOffset);
259
pos.setY (oldPos.y () - yOffset);
261
if (optionGetExitAfterPull ())
264
CompOption::Vector o;
267
o.push_back (CompOption ("root", CompOption::TypeInt));
268
o[0].value ().set ((int) screen->root ());
270
opt = CompOption::findOption (sScreen->getOptions (),
272
action = &opt->value ().action ();
274
if (action->terminate ())
275
action->terminate () (action, 0, o);
279
ScaleSlot slot = aw->sWindow->getSlot ();
281
/* provide a simple animation */
282
aw->cWindow->addDamage ();
284
pos.setX (oldPos.x () - slot.width () / 20);
285
pos.setY (oldPos.y () - slot.height () / 20);
286
pos.scale = oldPos.scale * 1.1f;
288
aw->sWindow->setCurrentPosition (pos);
290
aw->cWindow->addDamage ();
299
ScaleAddonScreen::zoomWindow (CompAction *action,
300
CompAction::State state,
301
CompOption::Vector options)
305
if (!sScreen->hasGrab ())
308
w = screen->findWindow (highlightedWindow);
316
if (!aw->sWindow->hasSlot ())
319
head = screen->outputDeviceForPoint (aw->sWindow->getSlot ().pos ());
320
output = screen->outputDevs ()[head];
322
/* damage old rect */
323
aw->cWindow->addDamage ();
327
ScaleSlot slot = aw->sWindow->getSlot ();
329
CompRect geom = w->borderRect ();
331
aw->oldAbove = w->next;
334
/* backup old values */
338
x1 = output.centerX () - geom.width () / 2 + w->border ().left;
339
y1 = output.centerY () - geom.height () / 2 + w->border ().top;
340
x2 = slot.x () + geom.width ();
341
y2 = slot.y () + geom.height ();
344
slot.setGeometry (x1, y1, x2 - x1, y2 - y1);
346
aw->sWindow->setSlot (slot);
351
w->restackBelow (aw->oldAbove);
353
aw->rescaled = false;
354
aw->sWindow->setSlot (aw->origSlot);
357
/* slot size may have changed, so
358
* update window title */
361
aw->cWindow->addDamage ();
368
ScaleAddonScreen::handleEvent (XEvent *event)
370
screen->handleEvent (event);
375
if (event->xproperty.atom == XA_WM_NAME && sScreen->hasGrab ())
379
w = screen->findWindow (event->xproperty.window);
384
aw->cWindow->addDamage ();
389
if (sScreen->hasGrab ())
391
highlightedWindow = sScreen->getHoveredWindow ();
392
checkWindowHighlight ();
401
ScaleAddonWindow::scalePaintDecoration (const GLWindowPaintAttrib &attrib,
402
const GLMatrix &transform,
403
const CompRegion ®ion,
406
ScaleScreen::State state;
408
ADDON_SCREEN (screen);
410
state = as->sScreen->getState ();
411
sWindow->scalePaintDecoration (attrib, transform, region, mask);
413
if (state == ScaleScreen::Wait || state == ScaleScreen::Out)
415
if (as->optionGetWindowHighlight ())
417
if (window->id () == as->highlightedWindow)
427
ScaleAddonWindow::scaleSelectWindow ()
429
ADDON_SCREEN (screen);
431
as->highlightedWindow = window->id ();
432
as->checkWindowHighlight ();
434
sWindow->scaleSelectWindow ();
438
ScaleAddonScreen::donePaint ()
440
ScaleScreen::State state = sScreen->getState ();
442
if (state != ScaleScreen::Idle && lastState == ScaleScreen::Idle)
444
foreach (CompWindow *w, screen->windows ())
445
ScaleAddonWindow::get (w)->renderTitle ();
447
else if (state == ScaleScreen::Idle && lastState != ScaleScreen::Idle)
449
foreach (CompWindow *w, screen->windows ())
450
ScaleAddonWindow::get (w)->text.clear ();
453
if (state == ScaleScreen::Out && lastState != ScaleScreen::Out)
455
lastHighlightedWindow = None;
456
checkWindowHighlight ();
461
cScreen->donePaint ();
465
ScaleAddonScreen::handleCompizEvent (const char *pluginName,
466
const char *eventName,
467
CompOption::Vector &options)
469
screen->handleCompizEvent (pluginName, eventName, options);
471
if ((strcmp (pluginName, "scale") == 0) &&
472
(strcmp (eventName, "activate") == 0))
475
CompOption::getBoolOptionNamed (options, "active", false);
479
screen->addAction (&optionGetCloseKey ());
480
screen->addAction (&optionGetZoomKey ());
481
screen->addAction (&optionGetPullKey ());
482
screen->addAction (&optionGetCloseButton ());
483
screen->addAction (&optionGetZoomButton ());
484
screen->addAction (&optionGetPullButton ());
487
ad->highlightedWindow = sd->selectedWindow;
488
here? do we want to show up the highlight without
489
mouse move initially? */
491
highlightedWindow = None;
492
lastHighlightedWindow = None;
493
checkWindowHighlight ();
497
foreach (CompWindow *w, screen->windows ())
500
aw->rescaled = false;
503
screen->removeAction (&optionGetCloseKey ());
504
screen->removeAction (&optionGetZoomKey ());
505
screen->removeAction (&optionGetPullKey ());
506
screen->removeAction (&optionGetCloseButton ());
507
screen->removeAction (&optionGetZoomButton ());
508
screen->removeAction (&optionGetPullButton ());
514
* experimental organic layout method
515
* inspired by smallwindows (smallwindows.sf.net) by Jens Egeblad
518
#define ORGANIC_STEP 0.05
521
organicCompareWindows (const void *elem1,
524
CompWindow *w1 = *((CompWindow **) elem1);
525
CompWindow *w2 = *((CompWindow **) elem2);
527
return (WIN_X (w1) + WIN_Y (w1)) - (WIN_X (w2) + WIN_Y (w2));
531
layoutOrganicCalculateOverlap (CompScreen *s,
538
int overlapX, overlapY;
539
int xMin, xMax, yMin, yMax;
540
double result = -0.01;
547
x2 = x1 + WIN_W (ss->windows[win]) * as->scale;
548
y2 = y1 + WIN_H (ss->windows[win]) * as->scale;
550
for (i = 0; i < ss->nWindows; i++)
555
overlapX = overlapY = 0;
556
xMax = MAX (ss->slots[i].x1, x1);
557
xMin = MIN (ss->slots[i].x1 + WIN_W (ss->windows[i]) * as->scale, x2);
559
overlapX = xMin - xMax;
561
yMax = MAX (ss->slots[i].y1, y1);
562
yMin = MIN (ss->slots[i].y1 + WIN_H (ss->windows[i]) * as->scale, y2);
565
overlapY = yMin - yMax;
567
result += (double)overlapX * overlapY;
574
layoutOrganicFindBestHorizontalPosition (CompScreen *s,
580
double bestOverlap = 1e31, overlap;
585
y1 = ss->slots[win].y1;
586
y2 = ss->slots[win].y1 + WIN_H (ss->windows[win]) * as->scale;
588
w = WIN_W (ss->windows[win]) * as->scale;
589
*bestX = ss->slots[win].x1;
591
for (i = 0; i < ss->nWindows; i++)
593
CompWindow *lw = ss->windows[i];
597
if (ss->slots[i].y1 < y2 &&
598
ss->slots[i].y1 + WIN_H (lw) * as->scale > y1)
600
if (ss->slots[i].x1 - w >= 0)
604
overlap = layoutOrganicCalculateOverlap (s, win,
608
if (overlap < bestOverlap)
610
*bestX = ss->slots[i].x1 - w;
611
bestOverlap = overlap;
614
if (WIN_W (lw) * as->scale + ss->slots[i].x1 + w < areaWidth)
618
overlap = layoutOrganicCalculateOverlap (s, win,
620
WIN_W (lw) * as->scale,
623
if (overlap < bestOverlap)
625
*bestX = ss->slots[i].x1 + WIN_W (lw) * as->scale;
626
bestOverlap = overlap;
632
overlap = layoutOrganicCalculateOverlap (s, win, 0, y1);
633
if (overlap < bestOverlap)
636
bestOverlap = overlap;
639
overlap = layoutOrganicCalculateOverlap (s, win, areaWidth - w, y1);
640
if (overlap < bestOverlap)
642
*bestX = areaWidth - w;
643
bestOverlap = overlap;
650
layoutOrganicFindBestVerticalPosition (CompScreen *s,
656
double bestOverlap = 1e31, overlap;
661
x1 = ss->slots[win].x1;
662
x2 = ss->slots[win].x1 + WIN_W (ss->windows[win]) * as->scale;
663
h = WIN_H (ss->windows[win]) * as->scale;
664
*bestY = ss->slots[win].y1;
666
for (i = 0; i < ss->nWindows; i++)
668
CompWindow *w = ss->windows[i];
673
if (ss->slots[i].x1 < x2 &&
674
ss->slots[i].x1 + WIN_W (w) * as->scale > x1)
676
if (ss->slots[i].y1 - h >= 0 && ss->slots[i].y1 < areaHeight)
679
overlap = layoutOrganicCalculateOverlap (s, win, x1,
680
ss->slots[i].y1 - h);
681
if (overlap < bestOverlap)
683
*bestY = ss->slots[i].y1 - h;
684
bestOverlap = overlap;
687
if (WIN_H (w) * as->scale + ss->slots[i].y1 > 0 &&
688
WIN_H (w) * as->scale + h + ss->slots[i].y1 < areaHeight)
692
overlap = layoutOrganicCalculateOverlap (s, win, x1,
693
WIN_H (w) * as->scale +
696
if (overlap < bestOverlap)
698
*bestY = ss->slots[i].y1 + WIN_H(w) * as->scale;
699
bestOverlap = overlap;
705
overlap = layoutOrganicCalculateOverlap (s, win, x1, 0);
706
if (overlap < bestOverlap)
709
bestOverlap = overlap;
712
overlap = layoutOrganicCalculateOverlap (s, win, x1, areaHeight - h);
713
if (overlap < bestOverlap)
715
*bestY = areaHeight - h;
716
bestOverlap = overlap;
723
layoutOrganicLocalSearch (CompScreen *s,
736
for (i = 0; i < ss->nWindows; i++)
743
double oldOverlap, overlapH, overlapV;
746
oldOverlap = layoutOrganicCalculateOverlap (s, i,
750
overlapH = layoutOrganicFindBestHorizontalPosition (s, i,
753
overlapV = layoutOrganicFindBestVerticalPosition (s, i,
757
if (overlapH < oldOverlap - 0.1 ||
758
overlapV < oldOverlap - 0.1)
762
if (overlapV > overlapH)
763
ss->slots[i].x1 = newX;
765
ss->slots[i].y1 = newY;
774
for (i = 0; i < ss->nWindows; i++)
776
totalOverlap += layoutOrganicCalculateOverlap (s, i,
781
return (totalOverlap > 0.1);
785
layoutOrganicRemoveOverlap (CompScreen *s,
795
spacing = ss->opt[SCALE_SCREEN_OPTION_SPACING].value.i;
797
while (layoutOrganicLocalSearch (s, areaWidth, areaHeight))
799
for (i = 0; i < ss->nWindows; i++)
801
int centerX, centerY;
802
int newX, newY, newWidth, newHeight;
806
centerX = ss->slots[i].x1 + WIN_W (w) / 2;
807
centerY = ss->slots[i].y1 + WIN_H (w) / 2;
809
newWidth = (int)((1.0 - ORGANIC_STEP) *
810
(double)WIN_W (w)) - spacing / 2;
811
newHeight = (int)((1.0 - ORGANIC_STEP) *
812
(double)WIN_H (w)) - spacing / 2;
813
newX = centerX - (newWidth / 2);
814
newY = centerY - (newHeight / 2);
816
ss->slots[i].x1 = newX;
817
ss->slots[i].y1 = newY;
818
ss->slots[i].x2 = newX + WIN_W (w);
819
ss->slots[i].y2 = newY + WIN_H (w);
821
as->scale -= ORGANIC_STEP;
826
layoutOrganicThumbs (CompScreen *s)
835
moMode = ss->opt[SCALE_SCREEN_OPTION_MULTIOUTPUT_MODE].value.i;
838
case SCALE_MOMODE_ALL:
839
workArea = s->workArea;
841
case SCALE_MOMODE_CURRENT:
843
workArea = s->outputDev[s->currentOutputDev].workArea;
849
qsort (ss->windows, ss->nWindows, sizeof(CompWindow *),
850
organicCompareWindows);
852
for (i = 0; i < ss->nWindows; i++)
857
sWindow->slot = &ss->slots[i];
858
ss->slots[i].x1 = WIN_X (w) - workArea.x;
859
ss->slots[i].y1 = WIN_Y (w) - workArea.y;
860
ss->slots[i].x2 = WIN_X (w) + WIN_W (w) - workArea.x;
861
ss->slots[i].y2 = WIN_Y (w) + WIN_H (w) - workArea.y;
863
if (ss->slots[i].x1 < 0)
865
ss->slots[i].x2 += abs (ss->slots[i].x1);
868
if (ss->slots[i].x2 > workArea.width - workArea.x)
870
ss->slots[i].x1 -= abs (ss->slots[i].x2 - workArea.width);
871
ss->slots[i].x2 = workArea.width - workArea.x;
874
if (ss->slots[i].y1 < 0)
876
ss->slots[i].y2 += abs (ss->slots[i].y1);
879
if (ss->slots[i].y2 > workArea.height - workArea.y)
881
ss->slots[i].y1 -= abs (ss->slots[i].y2 -
882
workArea.height - workArea.y);
883
ss->slots[i].y2 = workArea.height - workArea.y;
887
ss->nSlots = ss->nWindows;
889
layoutOrganicRemoveOverlap (s, workArea.width - workArea.x,
890
workArea.height - workArea.y);
891
for (i = 0; i < ss->nWindows; i++)
896
if (ss->type == ScaleTypeGroup)
897
raiseWindow (ss->windows[i]);
899
ss->slots[i].x1 += w->input.left + workArea.x;
900
ss->slots[i].x2 += w->input.left + workArea.x;
901
ss->slots[i].y1 += w->input.top + workArea.y;
902
ss->slots[i].y2 += w->input.top + workArea.y;
903
sWindow->adjust = true;
912
* Inspired by KWin - the KDE Window Manager
914
* Copyright (C) 2007 Rivo Laks <rivolaks@hot.ee>
915
* Copyright (C) 2008 Lucas Murray <lmurray@undefinedfire.com>
920
ScaleAddonScreen::isOverlappingAny (ScaleWindow *w,
921
std::map <ScaleWindow *, CompRegion> targets,
922
const CompRegion &border)
924
if (border.intersects (targets[w]))
926
// Is there a better way to do this?
927
std::map <ScaleWindow *, CompRegion>::const_iterator i;
928
for (i = targets.begin (); i != targets.end (); ++i)
932
if (targets[w].intersects ((*i).second))
939
ScaleAddonScreen::layoutNaturalThumbs ()
941
ScaleScreen::WindowList windows = ScaleScreen::get (screen)->getWindows ();
943
CompRect area = screen->workArea ();
944
CompRect bounds = area;
945
std::map <ScaleWindow *, CompRegion> targets;
946
std::map <ScaleWindow *, int> directions;
950
if (windows.size () == 1)
952
// Just move the window to its original location to save time
953
if (screen->fullscreenOutput ().workArea ().contains (windows.front ()->window->geometry ()))
955
ScaleSlot slot ((CompRect &) windows.front ()->window->geometry ());
956
windows.front ()->setSlot (slot);
961
foreach (ScaleWindow *w, windows)
963
bounds = CompRegion (bounds).united (w->window->outputRect ()).boundingRect ();
964
targets[w] = CompRegion (w->window->outputRect ());
965
// Reuse the unused "slot" as a preferred direction attribute. This is used when the window
966
// is on the edge of the screen to try to use as much screen real estate as possible.
967
directions[w] = direction;
976
foreach (ScaleWindow *w, windows)
978
foreach (ScaleWindow *e, windows)
980
if (e->window->id () != w->window->id () && targets[w].intersects (targets[e]))
982
int moveX = targets[w].boundingRect ().centerX () - targets[e].boundingRect ().centerX ();
983
int moveY = targets[w].boundingRect ().centerY () - targets[e].boundingRect ().centerY ();
984
//int xSection, ySection;
985
// Overlap detected, determine direction to push
989
moveX /= optionGetNaturalPrecision ();
990
moveY /= optionGetNaturalPrecision ();
994
moveX = optionGetNaturalPrecision ();
996
moveY = optionGetNaturalPrecision ();
998
targets[w] = targets[w].translated (moveX, moveY);
999
targets[e] = targets[e].translated (-moveX, -moveY);
1001
/* Try to keep the bounding rect the same aspect as the screen so that more
1002
* screen real estate is utilised. We do this by splitting the screen into nine
1003
* equal sections, if the window center is in any of the corner sections pull the
1004
* window towards the outer corner. If it is in any of the other edge sections
1005
* alternate between each corner on that edge. We don't want to determine it
1006
* randomly as it will not produce consistant locations when using the filter.
1007
* Only move one window so we don't cause large amounts of unnecessary zooming
1008
* in some situations. We need to do this even when expanding later just in case
1009
* all windows are the same size.
1010
* (We are using an old bounding rect for this, hopefully it doesn't matter)
1011
* FIXME: Disabled for now
1013
xSection = (targets[w].boundingRect ().x () - bounds.x ()) / (bounds.width () / 3);
1014
ySection = (targets[w].boundingRect ().y () - bounds.y ()) / (bounds.height () / 3);
1017
if (xSection != 1 || ySection != 1) // Remove this if you want the center to pull as well
1020
xSection = (directions[w] / 2 ? 2 : 0);
1022
ySection = (directions[w] % 2 ? 2 : 0);
1025
if (xSection == 0 && ySection == 0)
1027
moveX = bounds.left () - targets[w].boundingRect ().centerX ();
1028
moveY = bounds.top () - targets[w].boundingRect ().centerY ();
1030
if (xSection == 2 && ySection == 0)
1032
moveX = bounds.right () - targets[w].boundingRect ().centerX ();
1033
moveY = bounds.top () - targets[w].boundingRect ().centerY ();
1035
if (xSection == 2 && ySection == 2)
1037
moveX = bounds.right () - targets[w].boundingRect ().centerX ();
1038
moveY = bounds.bottom () - targets[w].boundingRect ().centerY ();
1040
if (xSection == 0 && ySection == 2)
1042
moveX = bounds.left () - targets[w].boundingRect ().centerX ();
1043
moveY = bounds.right () - targets[w].boundingRect ().centerY ();
1045
if (moveX != 0 || moveY != 0)
1046
targets[w].translate (moveX, moveY);
1050
// Update bounding rect
1051
bounds = CompRegion (bounds).united (targets[w]).boundingRect ();
1052
bounds = CompRegion (bounds).united (targets[e]).boundingRect ();
1056
while (overlapping);
1058
// Work out scaling by getting the most top-left and most bottom-right window coords.
1059
// The 20's and 10's are so that the windows don't touch the edge of the screen.
1062
scale = 1.0; // Don't add borders to the screen
1063
else if (area.width () / double (bounds.width ()) < area.height () / double (bounds.height ()))
1064
scale = (area.width () - 20) / double (bounds.width ());
1066
scale = (area.height () - 20) / double (bounds.height ());
1067
// Make bounding rect fill the screen size for later steps
1069
bounds.x () - (area.width () - 20 - bounds.width () * scale ) / 2 - 10 / scale,
1070
bounds.y () - (area.height () - 20 - bounds.height () * scale ) / 2 - 10 / scale,
1071
area.width () / scale,
1072
area.height () / scale
1075
// Move all windows back onto the screen and set their scale
1076
foreach (ScaleWindow *w, windows)
1078
targets[w] = CompRect (
1079
(targets[w].boundingRect ().x () - bounds.x () ) * scale + area.x (),
1080
(targets[w].boundingRect ().y () - bounds.y ()) * scale + area.y (),
1081
targets[w].boundingRect ().width () * scale,
1082
targets[w].boundingRect ().height () * scale
1084
ScaleSlot slt (targets[w].boundingRect ());
1091
// Don't expand onto or over the border
1092
CompRegion borderRegion = CompRegion (area);
1093
CompRegion areaRegion = CompRegion (area);
1094
borderRegion.translate (-200, -200);
1095
borderRegion.shrink (-200, -200); // actually expands the region
1096
areaRegion.translate (10 / scale, 10 / scale);
1097
areaRegion.shrink (10 / scale, 10 / scale);
1099
borderRegion ^= areaRegion;
1105
foreach (ScaleWindow *w, windows)
1107
CompRegion oldRegion;
1109
// This may cause some slight distortion if the windows are enlarged a large amount
1110
int widthDiff = optionGetNaturalPrecision ();
1111
int heightDiff = ((w->window->height () / w->window->width ()) *
1112
(targets[w].boundingRect ().width() + widthDiff)) - targets[w].boundingRect ().height ();
1113
int xDiff = widthDiff / 2; // Also move a bit in the direction of the enlarge, allows the
1114
int yDiff = heightDiff / 2; // center windows to be enlarged if there is gaps on the side.
1116
// Attempt enlarging to the top-right
1117
oldRegion = targets[w];
1118
targets[w] = CompRegion (
1119
targets[w].boundingRect ().x () + xDiff,
1120
targets[w].boundingRect ().y () - yDiff - heightDiff,
1121
targets[w].boundingRect ().width () + widthDiff,
1122
targets[w].boundingRect ().height () + heightDiff
1124
if (isOverlappingAny (w, targets, borderRegion))
1125
targets[w] = oldRegion;
1129
// Attempt enlarging to the bottom-right
1130
oldRegion = targets[w];
1131
targets[w] = CompRegion(
1132
targets[w].boundingRect ().x () + xDiff,
1133
targets[w].boundingRect ().y () + yDiff,
1134
targets[w].boundingRect ().width () + widthDiff,
1135
targets[w].boundingRect ().height () + heightDiff
1137
if (isOverlappingAny (w, targets, borderRegion))
1138
targets[w] = oldRegion;
1142
// Attempt enlarging to the bottom-left
1143
oldRegion = targets[w];
1144
targets[w] = CompRegion (
1145
targets[w].boundingRect ().x() - xDiff - widthDiff,
1146
targets[w].boundingRect ().y() + yDiff,
1147
targets[w].boundingRect ().width() + widthDiff,
1148
targets[w].boundingRect ().height() + heightDiff
1150
if (isOverlappingAny (w, targets, borderRegion))
1151
targets[w] = oldRegion;
1155
// Attempt enlarging to the top-left
1156
oldRegion = targets[w];
1157
targets[w] = CompRegion (
1158
targets[w].boundingRect ().x() - xDiff - widthDiff,
1159
targets[w].boundingRect ().y() - yDiff - heightDiff,
1160
targets[w].boundingRect ().width() + widthDiff,
1161
targets[w].boundingRect ().height() + heightDiff
1163
if (isOverlappingAny (w, targets, borderRegion))
1164
targets[w] = oldRegion;
1171
while (moved && iterCount < 100);
1173
// The expanding code above can actually enlarge windows over 1.0/2.0 scale, we don't like this
1174
// We can't add this to the loop above as it would cause a never-ending loop so we have to make
1175
// do with the less-than-optimal space usage with using this method.
1176
foreach (ScaleWindow *w, windows)
1178
double scale = targets[w].boundingRect ().width() / double( w->window->width());
1179
if (scale > 2.0 || (scale > 1.0 && (w->window->width() > 300 || w->window->height() > 300)))
1181
scale = (w->window->width () > 300 || w->window->height () > 300) ? 1.0 : 2.0;
1182
targets[w] = CompRegion (
1183
targets[w].boundingRect ().center().x() - int (w->window->width() * scale) / 2,
1184
targets[w].boundingRect ().center().y() - int (w->window->height () * scale) / 2,
1185
w->window->width() * scale,
1186
w->window->height() * scale
1196
ScaleAddonScreen::layoutSlotsAndAssignWindows ()
1200
switch (optionGetLayoutMode ())
1202
case LayoutModeNatural:
1203
status = layoutNaturalThumbs ();
1205
case LayoutModeNormal:
1207
status = sScreen->layoutSlotsAndAssignWindows ();
1215
ScaleAddonScreen::optionChanged (CompOption *opt,
1216
ScaleaddonOptions::Options num)
1220
case ScaleaddonOptions::WindowTitle:
1221
case ScaleaddonOptions::TitleBold:
1222
case ScaleaddonOptions::TitleSize:
1223
case ScaleaddonOptions::BorderSize:
1224
case ScaleaddonOptions::FontColor:
1225
case ScaleaddonOptions::BackColor:
1228
foreach (CompWindow *w, screen->windows ())
1240
ScaleAddonScreen::ScaleAddonScreen (CompScreen *) :
1241
PluginClassHandler <ScaleAddonScreen, CompScreen> (screen),
1242
cScreen (CompositeScreen::get (screen)),
1243
sScreen (ScaleScreen::get (screen)),
1244
highlightedWindow (0),
1245
lastHighlightedWindow (0),
1246
lastState (ScaleScreen::Idle),
1249
CompAction::CallBack cb;
1250
ChangeNotify notify;
1252
ScreenInterface::setHandler (screen, true);
1253
CompositeScreenInterface::setHandler (cScreen, true);
1254
ScaleScreenInterface::setHandler (sScreen, true);
1256
cb = boost::bind (&ScaleAddonScreen::closeWindow, this, _1, _2, _3);
1257
optionSetCloseKeyInitiate (cb);
1258
optionSetCloseButtonInitiate (cb);
1260
cb = boost::bind (&ScaleAddonScreen::zoomWindow, this, _1, _2, _3);
1261
optionSetZoomKeyInitiate (cb);
1262
optionSetZoomButtonInitiate (cb);
1264
cb = boost::bind (&ScaleAddonScreen::pullWindow, this, _1, _2, _3);
1265
optionSetPullKeyInitiate (cb);
1266
optionSetPullButtonInitiate (cb);
1268
notify = boost::bind (&ScaleAddonScreen::optionChanged, this, _1, _2);
1269
optionSetWindowTitleNotify (notify);
1270
optionSetTitleBoldNotify (notify);
1271
optionSetTitleSizeNotify (notify);
1272
optionSetBorderSizeNotify (notify);
1273
optionSetFontColorNotify (notify);
1274
optionSetBackColorNotify (notify);
1277
ScaleAddonWindow::ScaleAddonWindow (CompWindow *window) :
1278
PluginClassHandler <ScaleAddonWindow, CompWindow> (window),
1280
sWindow (ScaleWindow::get (window)),
1281
cWindow (CompositeWindow::get (window)),
1285
ScaleWindowInterface::setHandler (sWindow);
1289
ScaleAddonPluginVTable::init ()
1291
if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
1292
!CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) ||
1293
!CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI) ||
1294
!CompPlugin::checkPluginABI ("scale", COMPIZ_SCALE_ABI))
1297
if (!CompPlugin::checkPluginABI ("text", COMPIZ_TEXT_ABI))
1299
compLogMessage ("scaleaddon", CompLogLevelInfo,
1300
"Text Plugin not loaded, no text will be drawn.");
1301
textAvailable = false;
1304
textAvailable = true;