2
* Copyright © 2005 Novell, Inc.
3
* Copyright (C) 2007, 2008,2010 Kristian Lyngstøl
5
* Permission to use, copy, modify, distribute, and sell this software
6
* and its documentation for any purpose is hereby granted without
7
* fee, provided that the above copyright notice appear in all copies
8
* and that both that copyright notice and this permission notice
9
* appear in supporting documentation, and that the name of
10
* Novell, Inc. not be used in advertising or publicity pertaining to
11
* distribution of the software without specific, written prior permission.
12
* Novell, Inc. makes no representations about the suitability of this
13
* software for any purpose. It is provided "as is" without express or
16
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
18
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
20
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
21
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
22
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26
* - Most features beyond basic zoom;
27
* Kristian Lyngstol <kristian@bohemians.org>
28
* - Original zoom plug-in; David Reveman <davidr@novell.com>
29
* - Original port to C++ by Sam Spilsbury <smspillaz@gmail.com>
33
* This plug-in offers zoom functionality with focus tracking,
34
* fit-to-window actions, mouse panning, zoom area locking. Without
37
* Note on actual zoom process
39
* The animation is done in preparePaintScreen, while instant movements
40
* are done by calling updateActualTranslate () after updating the
41
* translations. This causes [xyz]trans to be re-calculated. We keep track
42
* of each head separately.
46
* We can not redirect input yet, but this plug-in offers two fundamentally
47
* different approaches to achieve input enabled zoom:
50
* Always have the zoomed area be in sync with the mouse cursor. This binds
51
* the zoom area to the mouse position at any given time. It allows using
52
* the original mouse cursor drawn by X, and is technically very safe.
53
* First used in Beryl's inputzoom.
56
* Hide the real cursor and draw our own where it would be when zoomed in.
57
* This allows us to navigate with the mouse without constantly moving the
58
* zoom area. This is fairly close to what we want in the end when input
59
* redirection is available.
61
* This second method has one huge issue, which is bugged XFixes. After
62
* hiding the cursor once with XFixes, some mouse cursors will simply be
63
* invisible. The Firefox loading cursor being one of them.
65
* An other minor annoyance is that mouse sensitivity seems to increase as
66
* you zoom in, since the mouse isn't really zoomed at all.
69
* - Walk through C++ port and adjust comments for 2010.
70
* - See if anyone misses the filter setting
71
* - Verify XFixes fix... err.
72
* - Different multi head modes
77
COMPIZ_PLUGIN_20090315 (ezoom, ZoomPluginVTable)
81
* This toggles paint functions. We don't need to continually run code when we
82
* are not doing anything
85
toggleFunctions (bool state)
89
screen->handleEventSetEnabled (zs, state);
90
zs->cScreen->preparePaintSetEnabled (zs, state);
91
zs->gScreen->glPaintOutputSetEnabled (zs, state);
92
zs->cScreen->donePaintSetEnabled (zs, state);
95
/* Check if the output is valid */
97
outputIsZoomArea (int out)
103
else if ((unsigned int) out >= zs->zooms.size ())
104
zs->zooms.resize (screen->outputDevs ().size ());
108
/* Check if zoom is active on the output specified */
112
ZOOM_SCREEN (screen);
114
if (!outputIsZoomArea (out))
116
if (zs->grabbed & (1 << zs->zooms.at (out).output))
121
/* Check if we are zoomed out and not going anywhere
122
* (similar to isActive but based on actual zoom, not grab)
127
ZOOM_SCREEN (screen);
129
if (!outputIsZoomArea (out))
132
if (zs->zooms.at (out).currentZoom != 1.0f
133
|| zs->zooms.at (out).newZoom != 1.0f)
136
if (zs->zooms.at (out).zVelocity != 0.0f)
142
/* Returns the distance to the defined edge in zoomed pixels. */
144
EZoomScreen::distanceToEdge (int out, EZoomScreen::ZoomEdge edge)
147
CompOutput *o = &screen->outputDevs ().at (out);
151
convertToZoomedTarget (out, o->region ()->extents.x2,
152
o->region ()->extents.y2, &x2, &y2);
153
convertToZoomedTarget (out, o->region ()->extents.x1,
154
o->region ()->extents.y1, &x1, &y1);
157
case NORTH: return o->region ()->extents.y1 - y1;
158
case SOUTH: return y2 - o->region ()->extents.y2;
159
case EAST: return x2 - o->region ()->extents.x2;
160
case WEST: return o->region ()->extents.x1 - x1;
162
return 0; // Never reached.
165
/* Update/set translations based on zoom level and real translate. */
167
EZoomScreen::ZoomArea::updateActualTranslates ()
169
xtrans = -realXTranslate * (1.0f - currentZoom);
170
ytrans = realYTranslate * (1.0f - currentZoom);
173
/* Returns true if the head in question is currently moving.
174
* Since we don't always bother resetting everything when
175
* canceling zoom, we check for the condition of being completely
176
* zoomed out and not zooming in/out first.
179
EZoomScreen::isInMovement (int out)
181
if (zooms.at (out).currentZoom == 1.0f &&
182
zooms.at (out).newZoom == 1.0f &&
183
zooms.at (out).zVelocity == 0.0f)
185
if (zooms.at (out).currentZoom != zooms.at (out).newZoom ||
186
zooms.at (out).xVelocity || zooms.at (out).yVelocity ||
187
zooms.at (out).zVelocity)
189
if (zooms.at (out).xTranslate != zooms.at (out).realXTranslate ||
190
zooms.at (out).yTranslate != zooms.at (out).realYTranslate)
195
/* Set the initial values of a zoom area. */
196
EZoomScreen::ZoomArea::ZoomArea (int out) :
206
realXTranslate (0.0f),
207
realYTranslate (0.0f),
210
updateActualTranslates ();
213
EZoomScreen::ZoomArea::ZoomArea () :
222
realXTranslate (0.0f),
223
realYTranslate (0.0f),
227
/* Adjust the velocity in the z-direction. */
229
EZoomScreen::adjustZoomVelocity (int out, float chunk)
231
float d, adjust, amount;
233
d = (zooms.at (out).newZoom - zooms.at (out).currentZoom) * 75.0f;
239
else if (amount > 5.0f)
242
zooms.at (out).zVelocity =
243
(amount * zooms.at (out).zVelocity + adjust) / (amount + 1.0f);
245
if (fabs (d) < 0.1f && fabs (zooms.at (out).zVelocity) < 0.005f)
247
zooms.at (out).currentZoom = zooms.at (out).newZoom;
248
zooms.at (out).zVelocity = 0.0f;
252
zooms.at (out).currentZoom += (zooms.at (out).zVelocity * chunk) /
253
cScreen->redrawTime ();
257
/* Adjust the X/Y velocity based on target translation and real
260
EZoomScreen::adjustXYVelocity (int out, float chunk)
263
float xadjust, yadjust;
264
float xamount, yamount;
266
zooms.at (out).xVelocity /= 1.25f;
267
zooms.at (out).yVelocity /= 1.25f;
269
(zooms.at (out).xTranslate - zooms.at (out).realXTranslate) *
272
(zooms.at (out).yTranslate - zooms.at (out).realYTranslate) *
274
xadjust = xdiff * 0.002f;
275
yadjust = ydiff * 0.002f;
276
xamount = fabs (xdiff);
277
yamount = fabs (ydiff);
281
else if (xamount > 5.0)
286
else if (yamount > 5.0)
289
zooms.at (out).xVelocity =
290
(xamount * zooms.at (out).xVelocity + xadjust) / (xamount + 1.0f);
291
zooms.at (out).yVelocity =
292
(yamount * zooms.at (out).yVelocity + yadjust) / (yamount + 1.0f);
294
if ((fabs(xdiff) < 0.1f && fabs (zooms.at (out).xVelocity) < 0.005f) &&
295
(fabs(ydiff) < 0.1f && fabs (zooms.at (out).yVelocity) < 0.005f))
297
zooms.at (out).realXTranslate = zooms.at (out).xTranslate;
298
zooms.at (out).realYTranslate = zooms.at (out).yTranslate;
299
zooms.at (out).xVelocity = 0.0f;
300
zooms.at (out).yVelocity = 0.0f;
304
zooms.at (out).realXTranslate +=
305
(zooms.at (out).xVelocity * chunk) / cScreen->redrawTime ();
306
zooms.at (out).realYTranslate +=
307
(zooms.at (out).yVelocity * chunk) / cScreen->redrawTime ();
310
/* Animate the movement (if any) in preparation of a paint screen. */
312
EZoomScreen::preparePaint (int msSinceLastPaint)
319
amount = msSinceLastPaint * 0.05f * optionGetSpeed ();
320
steps = amount / (0.5f * optionGetTimestep ());
323
chunk = amount / (float) steps;
327
for (out = 0; out < zooms.size (); out++)
329
if (!isInMovement (out) || !isActive (out))
332
adjustXYVelocity (out, chunk);
333
adjustZoomVelocity (out, chunk);
334
zooms.at (out).updateActualTranslates ();
337
zooms.at (out).xVelocity = zooms.at (out).yVelocity =
339
grabbed &= ~(1 << zooms.at (out).output);
342
cScreen->damageScreen ();
343
toggleFunctions (false);
348
if (optionGetZoomMode () == EzoomOptions::ZoomModeSyncMouse)
349
syncCenterToMouse ();
352
cScreen->preparePaint (msSinceLastPaint);
355
/* Damage screen if we're still moving. */
357
EZoomScreen::donePaint ()
362
for (out = 0; out < zooms.size (); out++)
364
if (isInMovement (out) && isActive (out))
366
cScreen->damageScreen ();
372
cScreen->damageScreen ();
374
toggleFunctions (false);
376
cScreen->donePaint ();
378
/* Draws a box from the screen coordinates inx1,iny1 to inx2,iny2 */
380
EZoomScreen::drawBox (const GLMatrix &transform,
384
GLMatrix zTransform = transform;
386
int inx1, inx2, iny1, iny2;
387
int out = output->id ();
389
zTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
390
convertToZoomed (out, box.x1 (), box.y1 (), &inx1, &iny1);
391
convertToZoomed (out, box.x2 (), box.y2 (), &inx2, &iny2);
393
x1 = MIN (inx1, inx2);
394
y1 = MIN (iny1, iny2);
395
x2 = MAX (inx1, inx2);
396
y2 = MAX (iny1, iny2);
398
glLoadMatrixf (zTransform.getMatrix ());
399
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
401
glColor4us (0x2fff, 0x2fff, 0x4fff, 0x4fff);
402
glRecti (x1,y2,x2,y1);
403
glColor4us (0x2fff, 0x2fff, 0x4fff, 0x9fff);
404
glBegin (GL_LINE_LOOP);
410
glColor4usv (defaultColor);
411
glDisable (GL_BLEND);
412
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
415
/* Apply the zoom if we are grabbed.
416
* Make sure to use the correct filter.
419
EZoomScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
420
const GLMatrix &transform,
421
const CompRegion ®ion,
426
int out = output->id ();
430
GLScreenPaintAttrib sa = attrib;
431
GLMatrix zTransform = transform;
433
mask &= ~PAINT_SCREEN_REGION_MASK;
434
mask |= PAINT_SCREEN_CLEAR_MASK;
436
zTransform.scale (1.0f / zooms.at (out).currentZoom,
437
1.0f / zooms.at (out).currentZoom,
439
zTransform.translate (zooms.at (out).xtrans,
440
zooms.at (out).ytrans,
443
mask |= PAINT_SCREEN_TRANSFORMED_MASK;
445
status = gScreen->glPaintOutput (sa, zTransform, region, output, mask);
447
drawCursor (output, transform);
452
status = gScreen->glPaintOutput (attrib, transform, region, output,
456
drawBox (transform, output, box);
461
/* Makes sure we're not attempting to translate too far.
462
* We are restricted to 0.5 to not go beyond the end
463
* of the screen/head. */
465
constrainZoomTranslate ()
468
ZOOM_SCREEN (screen);
470
for (out = 0; out < zs->zooms.size (); out++)
472
if (zs->zooms.at (out).xTranslate > 0.5f)
473
zs->zooms.at (out).xTranslate = 0.5f;
474
else if (zs->zooms.at (out).xTranslate < -0.5f)
475
zs->zooms.at (out).xTranslate = -0.5f;
477
if (zs->zooms.at (out).yTranslate > 0.5f)
478
zs->zooms.at (out).yTranslate = 0.5f;
479
else if (zs->zooms.at (out).yTranslate < -0.5f)
480
zs->zooms.at (out).yTranslate = -0.5f;
484
/* Functions for adjusting the zoomed area.
485
* These are the core of the zoom plug-in; Anything wanting
486
* to adjust the zoomed area must use setCenter or setZoomArea
487
* and setScale or front ends to them. */
489
/* Sets the center of the zoom area to X,Y.
490
* We have to be able to warp the pointer here: If we are moved by
491
* anything except mouse movement, we have to sync the
492
* mouse pointer. This is to allow input, and is NOT necessary
493
* when input redirection is available to us or if we're cheating
494
* and using a scaled mouse cursor to imitate IR.
495
* The center is not the center of the screen. This is the target-center;
496
* that is, it's the point that's the same regardless of zoom level.
499
EZoomScreen::setCenter (int x, int y, bool instant)
501
int out = screen->outputDeviceForPoint (x, y);
502
CompOutput *o = &screen->outputDevs ().at (out);
504
if (zooms.at (out).locked)
507
zooms.at (out).xTranslate = (float)
508
((x - o->x1 ()) - o->width () / 2) / (o->width ());
509
zooms.at (out).yTranslate = (float)
510
((y - o->y1 ()) - o->height () / 2) / (o->height ());
514
zooms.at (out).realXTranslate = zooms.at (out).xTranslate;
515
zooms.at (out).realYTranslate = zooms.at (out).yTranslate;
516
zooms.at (out).yVelocity = 0.0f;
517
zooms.at (out).xVelocity = 0.0f;
518
zooms.at (out).updateActualTranslates ();
521
if (optionGetZoomMode () == EzoomOptions::ZoomModePanArea)
522
restrainCursor (out);
525
/* Zooms the area described.
526
* The math could probably be cleaned up, but should be correct now. */
528
EZoomScreen::setZoomArea (int x,
534
CompWindow::Geometry outGeometry (x, y, width, height, 0);
535
int out = screen->outputDeviceForGeometry (outGeometry);
536
CompOutput *o = &screen->outputDevs ().at (out);
538
if (zooms.at (out).newZoom == 1.0f)
541
if (zooms.at (out).locked)
543
zooms.at (out).xTranslate =
544
(float) -((o->width () / 2) - (x + (width / 2) - o->x1 ()))
546
zooms.at (out).xTranslate /= (1.0f - zooms.at (out).newZoom);
547
zooms.at (out).yTranslate =
548
(float) -((o->height () / 2) - (y + (height / 2) - o->y1 ()))
550
zooms.at (out).yTranslate /= (1.0f - zooms.at (out).newZoom);
551
constrainZoomTranslate ();
555
zooms.at (out).realXTranslate = zooms.at (out).xTranslate;
556
zooms.at (out).realYTranslate = zooms.at (out).yTranslate;
557
zooms.at (out).updateActualTranslates ();
560
if (optionGetZoomMode () == EzoomOptions::ZoomModePanArea)
561
restrainCursor (out);
564
/* Moves the zoom area to the window specified */
566
EZoomScreen::areaToWindow (CompWindow *w)
568
int left = w->serverX () - w->border ().left;
569
int width = w->width () + w->border ().left + w->border ().right;
570
int top = w->serverY () - w->border ().top;
571
int height = w->height () + w->border ().top + w->border ().bottom;
573
setZoomArea (left, top, width, height, false);
576
/* Pans the zoomed area vertically/horizontally by * value * zs->panFactor
577
* TODO: Fix output. */
579
EZoomScreen::panZoom (int xvalue, int yvalue)
583
for (out = 0; out < zooms.size (); out++)
585
zooms.at (out).xTranslate +=
586
optionGetPanFactor () * xvalue *
587
zooms.at (out).currentZoom;
588
zooms.at (out).yTranslate +=
589
optionGetPanFactor () * yvalue *
590
zooms.at (out).currentZoom;
593
constrainZoomTranslate ();
596
/* Enables polling of mouse position, and refreshes currently
600
EZoomScreen::enableMousePolling ()
603
lastChange = time(NULL);
604
mouse = MousePoller::getCurrentPosition ();
607
/* Sets the zoom (or scale) level.
608
* Cleans up if we are suddenly zoomed out.
611
EZoomScreen::setScale (int out, float value)
613
if (zooms.at (out).locked)
620
if (!pollHandle.active ())
621
enableMousePolling ();
622
grabbed |= (1 << zooms.at (out).output);
623
cursorZoomActive (out);
628
zooms.at (out).xTranslate = 0.0f;
629
zooms.at (out).yTranslate = 0.0f;
630
cursorZoomInactive ();
633
if (value < optionGetMinimumZoom ())
634
value = optionGetMinimumZoom ();
636
zooms.at (out).newZoom = value;
637
cScreen->damageScreen();
640
/* Sets the zoom factor to the bigger of the two floats supplied.
641
* Convenience function for setting the scale factor for an area.
644
setScaleBigger (int out, float x, float y)
646
ZOOM_SCREEN (screen);
647
zs->setScale (out, x > y ? x : y);
651
* This takes care of keeping the mouse in sync with the zoomed area and
653
* See heading for description.
656
/* Syncs the center, based on translations, back to the mouse.
657
* This should be called when doing non-IR zooming and moving the zoom
658
* area based on events other than mouse movement.
661
EZoomScreen::syncCenterToMouse ()
667
out = screen->outputDeviceForPoint (mouse.x (), mouse.y ());
668
o = &screen->outputDevs ().at (out);
670
if (!isInMovement (out))
673
x = (int) ((zooms.at (out).realXTranslate * o->width ()) +
674
(o->width () / 2) + o->x1 ());
675
y = (int) ((zooms.at (out).realYTranslate * o->height ()) +
676
(o->height () / 2) + o->y1 ());
678
if ((x != mouse.x () || y != mouse.y ())
679
&& grabbed && zooms.at (out).newZoom != 1.0f)
681
screen->warpPointer (x - pointerX , y - pointerY );
687
/* Convert the point X,Y to where it would be when zoomed. */
689
EZoomScreen::convertToZoomed (int out,
697
if (!outputIsZoomArea (out))
703
o = &screen->outputDevs ()[out];
704
ZoomArea &za = zooms.at (out);
708
*resultX = x - (za.realXTranslate *
709
(1.0f - za.currentZoom) * o->width ()) - o->width () / 2;
710
*resultX /= za.currentZoom;
711
*resultX += o->width () / 2;
712
*resultX += o->x1 ();
713
*resultY = y - (za.realYTranslate *
714
(1.0f - za.currentZoom) * o->height ()) - o->height ()/ 2;
715
*resultY /= za.currentZoom;
716
*resultY += o->height ()/ 2;
717
*resultY += o->y1 ();
720
/* Same but use targeted translation, not real */
722
EZoomScreen::convertToZoomedTarget (int out,
728
CompOutput *o = &screen->outputDevs ().at (out);
730
if (!outputIsZoomArea (out))
736
ZoomArea &za = zooms.at (out);
740
*resultX = x - (za.xTranslate *
741
(1.0f - za.newZoom) * o->width ()) - o->width () / 2;
742
*resultX /= za.newZoom;
743
*resultX += o->width () / 2;
744
*resultX += o->x1 ();
745
*resultY = y - (za.yTranslate *
746
(1.0f - za.newZoom) * o->height ()) - o->height ()/2;
747
*resultY /= za.newZoom;
748
*resultY += o->height () / 2;
749
*resultY += o->y1 ();
752
/* Make sure the given point + margin is visible;
753
* Translate to make it visible if necessary.
754
* Returns false if the point isn't on a actively zoomed head
755
* or the area is locked. */
757
EZoomScreen::ensureVisibility (int x, int y, int margin)
763
out = screen->outputDeviceForPoint (x, y);
767
o = &screen->outputDevs ().at (out);
768
convertToZoomedTarget (out, x, y, &zoomX, &zoomY);
769
ZoomArea &za = zooms.at (out);
773
#define FACTOR (za.newZoom / (1.0f - za.newZoom))
774
if (zoomX + margin > o->x2 ())
776
(FACTOR * (float) (zoomX + margin - o->x2 ())) /
778
else if (zoomX - margin < o->x1 ())
780
(FACTOR * (float) (zoomX - margin - o->x1 ())) /
783
if (zoomY + margin > o->y2 ())
785
(FACTOR * (float) (zoomY + margin - o->y2 ())) /
786
(float) o->height ();
787
else if (zoomY - margin < o->y1 ())
789
(FACTOR * (float) (zoomY - margin - o->y1 ())) /
790
(float) o->height ();
792
constrainZoomTranslate ();
796
/* Attempt to ensure the visibility of an area defined by x1/y1 and x2/y2.
797
* See ensureVisibility () for details.
799
* This attempts to find the translations that leaves the biggest part of
802
* gravity defines what part of the window that should get
803
* priority if it isn't possible to fit all of it.
806
EZoomScreen::ensureVisibilityArea (int x1,
813
int targetX, targetY, targetW, targetH;
817
out = screen->outputDeviceForPoint (x1 + (x2-x1/2), y1 + (y2-y1/2));
818
o = &screen->outputDevs ().at (out);
820
#define WIDTHOK (float)(x2-x1) / (float)o->width () < zooms.at (out).newZoom
821
#define HEIGHTOK (float)(y2-y1) / (float)o->height () < zooms.at (out).newZoom
825
ensureVisibility (x1, y1, margin);
826
ensureVisibility (x2, y2, margin);
838
targetW = o->width () * zooms.at (out).newZoom;
842
targetH = o->height () * zooms.at (out).newZoom;
853
targetX = x2 - o->width () * zooms.at (out).newZoom;
854
targetW = o->width () * zooms.at (out).newZoom;
860
targetH = o->height () * zooms.at (out).newZoom;
867
targetW = o->width () * zooms.at (out).newZoom;
875
targetY = y2 - (o->width () * zooms.at (out).newZoom);
876
targetH = o->width () * zooms.at (out).newZoom;
887
targetW = o->width () * zooms.at (out).newZoom;
888
targetX = x2 - targetW;
898
targetH = o->height () * zooms.at (out).newZoom;
899
targetY = y2 - targetH;
904
setCenter (x1 + (x2 - x1 / 2), y1 + (y2 - y1 / 2), false);
909
setZoomArea (targetX, targetY, targetW, targetH, false);
913
/* Ensures that the cursor is visible on the given head.
914
* Note that we check if currentZoom is 1.0f, because that often means that
915
* mouseX and mouseY is not up-to-date (since the polling timer just
919
EZoomScreen::restrainCursor (int out)
921
int x1, y1, x2, y2, margin;
922
int diffX = 0, diffY = 0;
923
int north, south, east, west;
925
CompOutput *o = &screen->outputDevs ().at (out);
927
z = zooms.at (out).newZoom;
928
margin = optionGetRestrainMargin ();
929
north = distanceToEdge (out, NORTH);
930
south = distanceToEdge (out, SOUTH);
931
east = distanceToEdge (out, EAST);
932
west = distanceToEdge (out, WEST);
934
if (zooms.at (out).currentZoom == 1.0f)
936
lastChange = time(NULL);
937
mouse = MousePoller::getCurrentPosition ();
940
convertToZoomedTarget (out, mouse.x () - cursor.hotX,
941
mouse.y () - cursor.hotY, &x1, &y1);
942
convertToZoomedTarget
944
mouse.x () - cursor.hotX + cursor.width,
945
mouse.y () - cursor.hotY + cursor.height,
948
if ((x2 - x1 > o->x2 () - o->x1 ()) ||
949
(y2 - y1 > o->y2 () - o->y1 ()))
951
if (x2 > o->x2 () - margin && east > 0)
952
diffX = x2 - o->x2 () + margin;
953
else if (x1 < o->x1 () + margin && west > 0)
954
diffX = x1 - o->x1 () - margin;
956
if (y2 > o->y2 () - margin && south > 0)
957
diffY = y2 - o->y2 () + margin;
958
else if (y1 < o->y1 () + margin && north > 0)
959
diffY = y1 - o->y1 () - margin;
961
if (abs(diffX)*z > 0 || abs(diffY)*z > 0)
962
screen->warpPointer ((int) (mouse.x () - pointerX) -
963
(int) ((float)diffX * z),
964
(int) (mouse.y () - pointerY) -
965
(int) ((float)diffY * z));
968
/* Check if the cursor is still visible.
969
* We also make sure to activate/deactivate cursor scaling here
970
* so we turn on/off the pointer if it moves from one head to another.
971
* FIXME: Detect an actual output change instead of spamming.
972
* FIXME: The second ensureVisibility (sync with restrain).
975
EZoomScreen::cursorMoved ()
979
out = screen->outputDeviceForPoint (mouse.x (), mouse.y ());
982
if (optionGetRestrainMouse ())
983
restrainCursor (out);
985
if (optionGetZoomMode () == EzoomOptions::ZoomModePanArea)
987
ensureVisibilityArea (mouse.x () - cursor.hotX,
988
mouse.y () - cursor.hotY,
989
mouse.x () + cursor.width -
991
mouse.y () + cursor.height -
993
optionGetRestrainMargin (),
997
cursorZoomActive (out);
1001
cursorZoomInactive ();
1005
/* Update the mouse position.
1006
* Based on the zoom engine in use, we will have to move the zoom area.
1007
* This might have to be added to a timer.
1010
EZoomScreen::updateMousePosition (const CompPoint &p)
1013
mouse.setX (p.x ());
1014
mouse.setY (p.y ());
1015
out = screen->outputDeviceForPoint (mouse.x (), mouse.y ());
1016
lastChange = time(NULL);
1017
if (optionGetZoomMode () == EzoomOptions::ZoomModeSyncMouse &&
1018
!isInMovement (out))
1019
setCenter (mouse.x (), mouse.y (), true);
1021
cScreen->damageScreen ();
1024
/* Timeout handler to poll the mouse. Returns false (and thereby does not
1025
* get re-added to the queue) when zoom is not active. */
1027
EZoomScreen::updateMouseInterval (const CompPoint &p)
1029
updateMousePosition (p);
1034
if (pollHandle.active ())
1041
EZoomScreen::freeCursor (CursorTexture * cursor)
1046
cursor->isSet = false;
1047
glDeleteTextures (1, &cursor->texture);
1048
cursor->texture = 0;
1051
/* Translate into place and draw the scaled cursor. */
1053
EZoomScreen::drawCursor (CompOutput *output,
1054
const GLMatrix &transform)
1056
int out = output->id ();
1060
GLMatrix sTransform = transform;
1065
* XXX: expo knows how to handle mouse when zoomed, so we back off
1066
* when expo is active.
1068
if (screen->grabExist ( "expo"))
1070
cursorZoomInactive ();
1074
sTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
1075
convertToZoomed (out, mouse.x (), mouse.y (), &ax, &ay);
1077
glLoadMatrixf (sTransform.getMatrix ());
1078
glTranslatef ((float) ax, (float) ay, 0.0f);
1079
if (optionGetScaleMouseDynamic ())
1080
scaleFactor = 1.0f / zooms.at (out).currentZoom;
1082
scaleFactor = 1.0f / optionGetScaleMouseStatic ();
1083
glScalef (scaleFactor,
1089
glEnable (GL_BLEND);
1090
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, cursor.texture);
1091
glEnable (GL_TEXTURE_RECTANGLE_ARB);
1094
glTexCoord2d (0, 0);
1096
glTexCoord2d (0, cursor.height);
1097
glVertex2f (x, y + cursor.height);
1098
glTexCoord2d (cursor.width, cursor.height);
1099
glVertex2f (x + cursor.width, y + cursor.height);
1100
glTexCoord2d (cursor.width, 0);
1101
glVertex2f (x + cursor.width, y);
1103
glDisable (GL_BLEND);
1104
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, 0);
1105
glDisable (GL_TEXTURE_RECTANGLE_ARB);
1110
/* Create (if necessary) a texture to store the cursor,
1111
* fetch the cursor with XFixes. Store it. */
1113
EZoomScreen::updateCursor (CursorTexture * cursor)
1115
unsigned char *pixels;
1117
Display *dpy = screen->dpy ();
1121
cursor->isSet = true;
1122
cursor->screen = screen;
1123
glEnable (GL_TEXTURE_RECTANGLE_ARB);
1124
glGenTextures (1, &cursor->texture);
1125
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, cursor->texture);
1127
glTexParameteri (GL_TEXTURE_RECTANGLE_ARB,
1128
GL_TEXTURE_WRAP_S, GL_CLAMP);
1129
glTexParameteri (GL_TEXTURE_RECTANGLE_ARB,
1130
GL_TEXTURE_WRAP_T, GL_CLAMP);
1132
glEnable (GL_TEXTURE_RECTANGLE_ARB);
1135
XFixesCursorImage *ci = XFixesGetCursorImage (dpy);
1139
cursor->width = ci->width;
1140
cursor->height = ci->height;
1141
cursor->hotX = ci->xhot;
1142
cursor->hotY = ci->yhot;
1143
pixels = (unsigned char *) malloc (ci->width * ci->height * 4);
1151
for (i = 0; i < ci->width * ci->height; i++)
1153
unsigned long pix = ci->pixels[i];
1154
pixels[i * 4] = pix & 0xff;
1155
pixels[(i * 4) + 1] = (pix >> 8) & 0xff;
1156
pixels[(i * 4) + 2] = (pix >> 16) & 0xff;
1157
pixels[(i * 4) + 3] = (pix >> 24) & 0xff;
1164
/* Fallback R: 255 G: 255 B: 255 A: 255
1165
* FIXME: Draw a cairo mouse cursor */
1171
pixels = (unsigned char *) malloc (cursor->width * cursor->height * 4);
1176
for (i = 0; i < cursor->width * cursor->height; i++)
1178
unsigned long pix = 0x00ffffff;
1179
pixels[i * 4] = pix & 0xff;
1180
pixels[(i * 4) + 1] = (pix >> 8) & 0xff;
1181
pixels[(i * 4) + 2] = (pix >> 16) & 0xff;
1182
pixels[(i * 4) + 3] = (pix >> 24) & 0xff;
1185
compLogMessage ("ezoom", CompLogLevelWarn, "unable to get system cursor image!");
1188
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, cursor->texture);
1189
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, cursor->width,
1190
cursor->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
1191
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, 0);
1192
glDisable (GL_TEXTURE_RECTANGLE_ARB);
1197
/* We are no longer zooming the cursor, so display it. */
1199
EZoomScreen::cursorZoomInactive ()
1201
if (!fixesSupported)
1204
if (cursorInfoSelected)
1206
cursorInfoSelected = false;
1207
XFixesSelectCursorInput (screen->dpy (), screen->root (), 0);
1212
freeCursor (&cursor);
1217
cursorHidden = false;
1218
XFixesShowCursor (screen->dpy (), screen->root ());
1222
/* Cursor zoom is active: We need to hide the original,
1223
* register for Cursor notifies and display the new one.
1224
* This can be called multiple times, not just on initial
1228
EZoomScreen::cursorZoomActive (int out)
1230
if (!fixesSupported)
1233
/* Force cursor hiding and mouse panning if this output is locked
1234
* and cursor hiding is not enabled and we are syncing the mouse
1237
if (!optionGetScaleMouse () &&
1238
(optionGetZoomMode () == EzoomOptions::ZoomModeSyncMouse &&
1239
optionGetHideOriginalMouse () &&
1240
!zooms.at (out).locked))
1243
if (!cursorInfoSelected)
1245
cursorInfoSelected = true;
1246
XFixesSelectCursorInput (screen->dpy (), screen->root (),
1247
XFixesDisplayCursorNotifyMask);
1248
updateCursor (&cursor);
1250
if (canHideCursor && !cursorHidden &&
1251
(optionGetHideOriginalMouse () ||
1252
zooms.at (out).locked))
1254
cursorHidden = true;
1255
XFixesHideCursor (screen->dpy (), screen->root ());
1259
/* Set the zoom area
1260
* This is an interface for scripting.
1261
* int32:x1: left x coordinate
1262
* int32:y1: top y coordinate
1264
* int32:y2: bottom y
1265
* x2 and y2 can be omitted to assume x1==x2+1 y1==y2+1
1266
* boolean:scale: True if we should modify the zoom level, false to just
1267
* adjust the movement/translation.
1268
* boolean:restrain: True to warp the pointer so it's visible.
1271
EZoomScreen::setZoomAreaAction (CompAction *action,
1272
CompAction::State state,
1273
CompOption::Vector options)
1275
int x1, y1, x2, y2, out;
1276
bool scale, restrain;
1279
x1 = CompOption::getIntOptionNamed (options, "x1", -1);
1280
y1 = CompOption::getIntOptionNamed (options, "y1", -1);
1281
x2 = CompOption::getIntOptionNamed (options, "x2", -1);
1282
y2 = CompOption::getIntOptionNamed (options, "y2", -1);
1283
scale = CompOption::getBoolOptionNamed (options, "scale", false);
1284
restrain = CompOption::getBoolOptionNamed (options, "restrain", false);
1286
if (x1 < 0 || y1 < 0)
1295
out = screen->outputDeviceForPoint (x1, y1);
1296
#define WIDTH (x2 - x1)
1297
#define HEIGHT (y2 - y1)
1298
setZoomArea (x1, y1, WIDTH, HEIGHT, false);
1299
o = &screen->outputDevs (). at(out);
1300
if (scale && WIDTH && HEIGHT)
1301
setScaleBigger (out, (float) WIDTH / o->width (),
1302
(float) HEIGHT / o->height ());
1306
restrainCursor (out);
1308
toggleFunctions (true);
1313
/* Ensure visibility of an area defined by x1->x2/y1->y2
1314
* int:x1: left X coordinate
1315
* int:x2: right X Coordinate
1316
* int:y1: top Y coordinate
1317
* int:y2: bottom Y coordinate
1318
* bool:scale: zoom out if necessary to ensure visibility
1319
* bool:restrain: Restrain the mouse cursor
1320
* int:margin: The margin to use (default: 0)
1321
* if x2/y2 is omitted, it is ignored.
1324
EZoomScreen::ensureVisibilityAction (CompAction *action,
1325
CompAction::State state,
1326
CompOption::Vector options)
1328
int x1, y1, x2, y2, margin, out;
1329
bool scale, restrain;
1332
x1 = CompOption::getIntOptionNamed (options, "x1", -1);
1333
y1 = CompOption::getIntOptionNamed (options, "y1", -1);
1334
x2 = CompOption::getIntOptionNamed (options, "x2", -1);
1335
y2 = CompOption::getIntOptionNamed (options, "y2", -1);
1336
margin = CompOption::getBoolOptionNamed (options, "margin", 0);
1337
scale = CompOption::getBoolOptionNamed (options, "scale", false);
1338
restrain = CompOption::getBoolOptionNamed (options, "restrain", false);
1339
if (x1 < 0 || y1 < 0)
1343
out = screen->outputDeviceForPoint (x1, y1);
1344
ensureVisibility (x1, y1, margin);
1345
if (x2 >= 0 && y2 >= 0)
1346
ensureVisibility (x2, y2, margin);
1347
o = &screen->outputDevs (). at(out);
1348
#define WIDTH (x2 - x1)
1349
#define HEIGHT (y2 - y1)
1350
if (scale && WIDTH && HEIGHT)
1351
setScaleBigger (out, (float) WIDTH / o->width (),
1352
(float) HEIGHT / o->height ());
1356
restrainCursor (out);
1358
toggleFunctions (true);
1366
EZoomScreen::zoomBoxActivate (CompAction *action,
1367
CompAction::State state,
1368
CompOption::Vector options)
1370
grabIndex = screen->pushGrab (None, "ezoom");
1371
clickPos.setX (pointerX);
1372
clickPos.setY (pointerY);
1373
box.setGeometry (pointerX, pointerY, 0, 0);
1374
if (state & CompAction::StateInitButton)
1375
action->setState (action->state () | CompAction::StateTermButton);
1377
toggleFunctions (true);
1383
EZoomScreen::zoomBoxDeactivate (CompAction *action,
1384
CompAction::State state,
1385
CompOption::Vector options)
1390
int x, y, width, height;
1393
screen->removeGrab (grabIndex, NULL);
1396
if (pointerX < clickPos.x ())
1398
box.setX (pointerX);
1399
box.setWidth (clickPos.x () - pointerX);
1403
box.setWidth (pointerX - clickPos.x ());
1406
if (pointerY < clickPos.y ())
1408
box.setY (pointerY);
1409
box.setHeight (clickPos.y () - pointerY);
1413
box.setHeight (pointerY - clickPos.y ());
1416
x = MIN (box.x1 (), box.x2 ());
1417
y = MIN (box.y1 (), box.y2 ());
1418
width = MAX (box.x1 (), box.x2 ()) - x;
1419
height = MAX (box.y1 (), box.y2 ()) - y;
1421
CompWindow::Geometry outGeometry (x, y, width, height, 0);
1423
out = screen->outputDeviceForGeometry (outGeometry);
1424
o = &screen->outputDevs (). at (out);
1425
setScaleBigger (out, (float) width/o->width (), (float)
1426
height/o->height ());
1427
setZoomArea (x,y,width,height,false);
1430
toggleFunctions (true);
1435
/* Zoom in to the area pointed to by the mouse.
1438
EZoomScreen::zoomIn (CompAction *action,
1439
CompAction::State state,
1440
CompOption::Vector options)
1442
int out = screen->outputDeviceForPoint (pointerX, pointerY);
1444
if (optionGetZoomMode () == EzoomOptions::ZoomModeSyncMouse &&
1445
!isInMovement (out))
1446
setCenter (pointerX, pointerY, true);
1449
zooms.at (out).newZoom /
1450
optionGetZoomFactor ());
1452
toggleFunctions (true);
1457
/* Locks down the current zoom area
1460
EZoomScreen::lockZoomAction (CompAction *action,
1461
CompAction::State state,
1462
CompOption::Vector options)
1464
int out = screen->outputDeviceForPoint (pointerX, pointerY);
1465
zooms.at (out).locked = !zooms.at (out).locked;
1470
/* Zoom to a specific level.
1471
* target defines the target zoom level.
1472
* First set the scale level and mark the display as grabbed internally (to
1473
* catch the FocusIn event). Either target the focused window or the mouse,
1474
* depending on settings.
1475
* FIXME: A bit of a mess...
1478
EZoomScreen::zoomSpecific (CompAction *action,
1479
CompAction::State state,
1480
CompOption::Vector options,
1484
int out = screen->outputDeviceForPoint (pointerX, pointerY);
1487
if (target == 1.0f && zooms.at (out).newZoom == 1.0f)
1489
if (screen->otherGrabExist (NULL))
1492
setScale (out, target);
1494
w = screen->findWindow (screen->activeWindow ());
1495
if (optionGetSpecTargetFocus ()
1502
x = CompOption::getIntOptionNamed (options, "x", 0);
1503
y = CompOption::getIntOptionNamed (options, "y", 0);
1504
setCenter (x, y, false);
1507
toggleFunctions (true);
1512
/* TODO: Add specific zoom boost::bind's */
1514
/* Zooms to fit the active window to the screen without cutting
1515
* it off and targets it.
1518
EZoomScreen::zoomToWindow (CompAction *action,
1519
CompAction::State state,
1520
CompOption::Vector options)
1522
int width, height, out;
1527
xid = CompOption::getIntOptionNamed (options, "window", 0);
1528
w = screen->findWindow (xid);
1531
width = w->width () + w->border ().left + w->border ().right;
1532
height = w->height () + w->border ().top + w->border ().bottom;
1533
out = screen->outputDeviceForGeometry (w->geometry ());
1534
o = &screen->outputDevs ().at (out);
1535
setScaleBigger (out, (float) width/o->width (),
1536
(float) height/o->height ());
1538
toggleFunctions (true);
1544
EZoomScreen::zoomPan (CompAction *action,
1545
CompAction::State state,
1546
CompOption::Vector options,
1550
panZoom (horizAmount, vertAmount);
1555
/* Centers the mouse based on zoom level and translation.
1558
EZoomScreen::zoomCenterMouse (CompAction *action,
1559
CompAction::State state,
1560
CompOption::Vector options)
1565
out = screen->outputDeviceForPoint (pointerX, pointerY);
1566
screen->warpPointer ((int) (screen->outputDevs ().at (out).width ()/2 +
1567
screen->outputDevs ().at (out).x1 () - pointerX)
1568
+ ((float) screen->outputDevs ().at (out).width () *
1569
-zooms.at (out).xtrans),
1570
(int) (screen->outputDevs ().at (out).height ()/2 +
1571
screen->outputDevs ().at (out).y1 () - pointerY)
1572
+ ((float) screen->outputDevs ().at (out).height () *
1573
zooms.at (out).ytrans));
1577
/* Resize a window to fit the zoomed area.
1578
* This could probably do with some moving-stuff too.
1579
* IE: Move the zoom area afterwards. And ensure
1580
* the window isn't resized off-screen.
1583
EZoomScreen::zoomFitWindowToZoom (CompAction *action,
1584
CompAction::State state,
1585
CompOption::Vector options)
1588
unsigned int mask = CWWidth | CWHeight;
1592
w = screen->findWindow (CompOption::getIntOptionNamed (
1593
options, "window", 0));
1597
out = screen->outputDeviceForGeometry (w->geometry ());
1598
xwc.x = w->serverX ();
1599
xwc.y = w->serverY ();
1600
xwc.width = (int) (screen->outputDevs ().at (out).width () *
1601
zooms.at (out).currentZoom -
1602
(int) ((w->border ().left + w->border ().right)));
1603
xwc.height = (int) (screen->outputDevs ().at (out).height () *
1604
zooms.at (out).currentZoom -
1605
(int) ((w->border ().top + w->border ().bottom)));
1607
w->constrainNewWindowSize (xwc.width,
1613
if (xwc.width == w->serverWidth ())
1616
if (xwc.height == w->serverHeight ())
1619
if (w->mapNum () && (mask & (CWWidth | CWHeight)))
1620
w->sendSyncRequest ();
1622
w->configureXWindow (mask, &xwc);
1624
toggleFunctions (true);
1630
EZoomScreen::initiate (CompAction *action,
1631
CompAction::State state,
1632
CompOption::Vector options)
1634
zoomIn (action, state, options);
1636
if (state & CompAction::StateInitKey)
1637
action->setState (action->state () | CompAction::StateTermKey);
1639
if (state & CompAction::StateInitButton)
1640
action->setState (action->state () | CompAction::StateTermButton);
1642
toggleFunctions (true);
1648
EZoomScreen::zoomOut (CompAction *action,
1649
CompAction::State state,
1650
CompOption::Vector options)
1652
int out = screen->outputDeviceForPoint (pointerX, pointerY);
1655
zooms.at (out).newZoom *
1656
optionGetZoomFactor ());
1658
toggleFunctions (true);
1664
EZoomScreen::terminate (CompAction *action,
1665
CompAction::State state,
1666
CompOption::Vector options)
1670
out = screen->outputDeviceForPoint (pointerX, pointerY);
1674
zooms.at (out).newZoom = 1.0f;
1675
cScreen->damageScreen ();
1678
toggleFunctions (true);
1680
action->setState (action->state () & ~(CompAction::StateTermKey |
1681
CompAction::StateTermButton));
1686
/* Focus-track related event handling.
1687
* The lastMapped is a hack to ensure that newly mapped windows are
1688
* caught even if the grab that (possibly) triggered them affected
1689
* the mode. Windows created by a key binding (like creating a terminal
1690
* on a key binding) tends to trigger FocusIn events with mode other than
1691
* Normal. This works around this problem.
1693
* TODO: Avoid maximized windows.
1696
EZoomScreen::focusTrack (XEvent *event)
1699
static Window lastMapped = 0;
1703
if (event->type == MapNotify)
1705
lastMapped = event->xmap.window;
1708
else if (event->type != FocusIn)
1711
if ((event->xfocus.mode != NotifyNormal)
1712
&& (lastMapped != event->xfocus.window))
1716
w = screen->findWindow (event->xfocus.window);
1717
if (w == NULL || w->id () == screen->activeWindow ())
1720
if (time(NULL) - lastChange < optionGetFollowFocusDelay () ||
1721
!optionGetFollowFocus ())
1724
out = screen->outputDeviceForGeometry (w->geometry ());
1725
if (!isActive (out) &&
1726
!optionGetAlwaysFocusFitWindow ())
1728
if (optionGetFocusFitWindow ())
1730
int width = w->width () + w->border ().left + w->border ().right;
1731
int height = w->height () + w->border ().top + w->border ().bottom;
1732
float scale = MAX ((float) width/screen->outputDevs ().at(out).width (),
1733
(float) height/screen->outputDevs ().at (out).height ());
1734
if (scale > optionGetAutoscaleMin ())
1735
setScale (out, scale);
1740
toggleFunctions (true);
1744
/* Event handler. Pass focus-related events on and handle XFixes events. */
1746
EZoomScreen::handleEvent (XEvent *event)
1750
switch (event->type) {
1752
mev = (XMotionEvent *) event;
1755
if (pointerX < clickPos.x ())
1757
box.setX (pointerX);
1758
box.setWidth (clickPos.x () - pointerX);
1762
box.setWidth (pointerX - clickPos.x ());
1765
if (pointerY < clickPos.y ())
1767
box.setY (pointerY);
1768
box.setHeight (clickPos.y () - pointerY);
1772
box.setHeight (pointerY - clickPos.y ());
1774
cScreen->damageScreen ();
1783
if (event->type == fixesEventBase + XFixesCursorNotify)
1785
//XFixesCursorNotifyEvent *cev = (XFixesCursorNotifyEvent *)
1788
updateCursor (&cursor);
1793
screen->handleEvent (event);
1796
/* TODO: Use this ctor carefully */
1798
EZoomScreen::CursorTexture::CursorTexture () :
1804
EZoomScreen::postLoad ()
1806
const CompPoint &m = pollHandle.getCurrentPosition ();
1807
int out = screen->outputDeviceForPoint (m.x (), m.y ());
1812
toggleFunctions (true);
1814
if (!pollHandle.active ())
1815
enableMousePolling ();
1817
foreach (ZoomArea &za, zooms)
1819
grabbed |= (1 << za.output);
1822
cursorZoomActive (out);
1823
updateCursor (&cursor);
1825
cScreen->damageScreen ();
1829
EZoomScreen::EZoomScreen (CompScreen *screen) :
1830
PluginClassHandler <EZoomScreen, CompScreen> (screen),
1831
PluginStateWriter <EZoomScreen> (this, screen->root ()),
1832
cScreen (CompositeScreen::get (screen)),
1833
gScreen (GLScreen::get (screen)),
1837
cursorInfoSelected (false),
1838
cursorHidden (false)
1840
ScreenInterface::setHandler (screen, false);
1841
CompositeScreenInterface::setHandler (cScreen, false);
1842
GLScreenInterface::setHandler (gScreen, false);
1847
XFixesQueryExtension(screen->dpy (),
1851
XFixesQueryVersion (screen->dpy (), &major, &minor);
1854
canHideCursor = true;
1856
canHideCursor = false;
1858
n = screen->outputDevs ().size ();
1860
for (unsigned int i = 0; i < n; i++)
1862
/* zs->grabbed is a mask ... Thus this limit */
1863
if (i > sizeof (long int) * 8)
1866
zooms.push_back (za);
1869
pollHandle.setCallback (boost::bind (
1870
&EZoomScreen::updateMouseInterval, this, _1));
1872
optionSetZoomInButtonInitiate (boost::bind (&EZoomScreen::zoomIn, this, _1,
1874
optionSetZoomOutButtonInitiate (boost::bind (&EZoomScreen::zoomOut, this, _1,
1876
optionSetZoomInKeyInitiate (boost::bind (&EZoomScreen::zoomIn, this, _1,
1878
optionSetZoomOutKeyInitiate (boost::bind (&EZoomScreen::zoomOut, this, _1,
1881
optionSetZoomSpecific1KeyInitiate (boost::bind (&EZoomScreen::zoomSpecific,
1883
optionGetZoomSpec1 ()));
1884
optionSetZoomSpecific2KeyInitiate (boost::bind (&EZoomScreen::zoomSpecific,
1886
optionGetZoomSpec2 ()));
1887
optionSetZoomSpecific3KeyInitiate (boost::bind (&EZoomScreen::zoomSpecific,
1889
optionGetZoomSpec3 ()));
1891
optionSetPanLeftKeyInitiate (boost::bind (&EZoomScreen::zoomPan, this, _1,
1893
optionSetPanRightKeyInitiate (boost::bind (&EZoomScreen::zoomPan, this, _1,
1895
optionSetPanUpKeyInitiate (boost::bind (&EZoomScreen::zoomPan, this, _1, _2,
1897
optionSetPanDownKeyInitiate (boost::bind (&EZoomScreen::zoomPan, this, _1,
1900
optionSetFitToWindowKeyInitiate (boost::bind (&EZoomScreen::zoomToWindow,
1902
optionSetCenterMouseKeyInitiate (boost::bind (&EZoomScreen::zoomCenterMouse,
1904
optionSetFitToZoomKeyInitiate (boost::bind (
1905
&EZoomScreen::zoomFitWindowToZoom, this,
1909
optionSetLockZoomKeyInitiate (boost::bind (&EZoomScreen::lockZoomAction,
1911
optionSetZoomBoxButtonInitiate (boost::bind (&EZoomScreen::zoomBoxActivate,
1913
optionSetZoomBoxButtonTerminate (boost::bind (
1914
&EZoomScreen::zoomBoxDeactivate, this,
1916
optionSetSetZoomAreaInitiate (boost::bind (
1917
&EZoomScreen::setZoomAreaAction, this,
1919
optionSetEnsureVisibilityInitiate (boost::bind (
1920
&EZoomScreen::ensureVisibilityAction, this,
1925
EZoomScreen::~EZoomScreen ()
1927
writeSerializedData ();
1929
if (pollHandle.active ())
1935
cScreen->damageScreen ();
1936
cursorZoomInactive ();
1940
ZoomPluginVTable::init ()
1942
if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
1943
!CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) ||
1944
!CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI) ||
1945
!CompPlugin::checkPluginABI ("mousepoll", COMPIZ_MOUSEPOLL_ABI))