~vanvugt/compiz-plugins-main/fix-1084386

« back to all changes in this revision

Viewing changes to ezoom/src/ezoom.cpp

  • Committer: Sam Spilsbury
  • Date: 2011-08-12 06:36:10 UTC
  • Revision ID: sam.spilsbury@canonical.com-20110812063610-8mcxo2xohctyp2ak
Sync - Remove Plugins

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright © 2005 Novell, Inc.
3
 
 * Copyright (C) 2007, 2008,2010 Kristian Lyngstøl
4
 
 *
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
14
 
 * implied warranty.
15
 
 *
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.
23
 
 *
24
 
 *
25
 
 * Author(s):
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>
30
 
 *
31
 
 * Description:
32
 
 *
33
 
 * This plug-in offers zoom functionality with focus tracking,
34
 
 * fit-to-window actions, mouse panning, zoom area locking. Without
35
 
 * disabling input.
36
 
 *
37
 
 * Note on actual zoom process
38
 
 *
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.
43
 
 *
44
 
 * Note on input
45
 
 *
46
 
 * We can not redirect input yet, but this plug-in offers two fundamentally
47
 
 * different approaches to achieve input enabled zoom:
48
 
 *
49
 
 * 1.
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.
54
 
 *
55
 
 * 2.
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.
60
 
 *
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.
64
 
 *
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.
67
 
 *
68
 
 * Todo:
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
73
 
 */
74
 
 
75
 
#include "ezoom.h"
76
 
 
77
 
COMPIZ_PLUGIN_20090315 (ezoom, ZoomPluginVTable)
78
 
 
79
 
 
80
 
/*
81
 
 * This toggles paint functions. We don't need to continually run code when we
82
 
 * are not doing anything
83
 
 */
84
 
static inline void
85
 
toggleFunctions (bool state)
86
 
{
87
 
    ZOOM_SCREEN (screen);
88
 
 
89
 
    screen->handleEventSetEnabled (zs, state);
90
 
    zs->cScreen->preparePaintSetEnabled (zs, state);
91
 
    zs->gScreen->glPaintOutputSetEnabled (zs, state);
92
 
    zs->cScreen->donePaintSetEnabled (zs, state);
93
 
}
94
 
 
95
 
/* Check if the output is valid */
96
 
static inline bool
97
 
outputIsZoomArea (int out)
98
 
{
99
 
    ZOOM_SCREEN (screen);
100
 
 
101
 
    if (out < 0)
102
 
        return false;
103
 
    else if ((unsigned int) out >= zs->zooms.size ())
104
 
        zs->zooms.resize (screen->outputDevs ().size ());
105
 
    return true;
106
 
}
107
 
 
108
 
/* Check if zoom is active on the output specified */
109
 
static inline bool
110
 
isActive (int out)
111
 
{
112
 
    ZOOM_SCREEN (screen);
113
 
 
114
 
    if (!outputIsZoomArea (out))
115
 
        return false;
116
 
    if (zs->grabbed & (1 << zs->zooms.at (out).output))
117
 
        return true;
118
 
    return false;
119
 
}
120
 
 
121
 
/* Check if we are zoomed out and not going anywhere
122
 
 * (similar to isActive but based on actual zoom, not grab)
123
 
 */
124
 
static inline bool
125
 
isZoomed (int out)
126
 
{
127
 
    ZOOM_SCREEN (screen);
128
 
 
129
 
    if (!outputIsZoomArea (out))
130
 
        return false;
131
 
 
132
 
    if (zs->zooms.at (out).currentZoom != 1.0f
133
 
        || zs->zooms.at (out).newZoom != 1.0f)
134
 
        return true;
135
 
 
136
 
    if (zs->zooms.at (out).zVelocity != 0.0f)
137
 
        return true;
138
 
 
139
 
    return false;
140
 
}
141
 
 
142
 
/* Returns the distance to the defined edge in zoomed pixels.  */
143
 
int
144
 
EZoomScreen::distanceToEdge (int out, EZoomScreen::ZoomEdge edge)
145
 
{
146
 
    int        x1,y1,x2,y2;
147
 
    CompOutput *o = &screen->outputDevs ().at (out);
148
 
 
149
 
    if (!isActive (out))
150
 
        return 0;
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);
155
 
    switch (edge)
156
 
    {
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;
161
 
    }
162
 
    return 0; // Never reached.
163
 
}
164
 
 
165
 
/* Update/set translations based on zoom level and real translate.  */
166
 
void
167
 
EZoomScreen::ZoomArea::updateActualTranslates ()
168
 
{
169
 
    xtrans = -realXTranslate * (1.0f - currentZoom);
170
 
    ytrans = realYTranslate * (1.0f - currentZoom);
171
 
}
172
 
 
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.
177
 
 */
178
 
bool
179
 
EZoomScreen::isInMovement (int out)
180
 
{
181
 
    if (zooms.at (out).currentZoom == 1.0f &&
182
 
        zooms.at (out).newZoom == 1.0f &&
183
 
        zooms.at (out).zVelocity == 0.0f)
184
 
        return false;
185
 
    if (zooms.at (out).currentZoom != zooms.at (out).newZoom ||
186
 
        zooms.at (out).xVelocity || zooms.at (out).yVelocity ||
187
 
        zooms.at (out).zVelocity)
188
 
        return true;
189
 
    if (zooms.at (out).xTranslate != zooms.at (out).realXTranslate ||
190
 
        zooms.at (out).yTranslate != zooms.at (out).realYTranslate)
191
 
        return true;
192
 
    return false;
193
 
}
194
 
 
195
 
/* Set the initial values of a zoom area.  */
196
 
EZoomScreen::ZoomArea::ZoomArea (int out) :
197
 
    output (out),
198
 
    viewport (~0),
199
 
    currentZoom (1.0f),
200
 
    newZoom (1.0f),
201
 
    xVelocity (0.0f),
202
 
    yVelocity (0.0f),
203
 
    zVelocity (0.0f),
204
 
    xTranslate (0.0f),
205
 
    yTranslate (0.0f),
206
 
    realXTranslate (0.0f),
207
 
    realYTranslate (0.0f),
208
 
    locked (false)
209
 
{
210
 
    updateActualTranslates ();
211
 
}
212
 
 
213
 
EZoomScreen::ZoomArea::ZoomArea () :
214
 
    viewport (~0),
215
 
    currentZoom (1.0f),
216
 
    newZoom (1.0f),
217
 
    xVelocity (0.0f),
218
 
    yVelocity (0.0f),
219
 
    zVelocity (0.0f),
220
 
    xTranslate (0.0f),
221
 
    yTranslate (0.0f),
222
 
    realXTranslate (0.0f),
223
 
    realYTranslate (0.0f),
224
 
    locked (false)
225
 
{
226
 
}
227
 
/* Adjust the velocity in the z-direction.  */
228
 
void
229
 
EZoomScreen::adjustZoomVelocity (int out, float chunk)
230
 
{
231
 
    float d, adjust, amount;
232
 
 
233
 
    d = (zooms.at (out).newZoom - zooms.at (out).currentZoom) * 75.0f;
234
 
 
235
 
    adjust = d * 0.002f;
236
 
    amount = fabs (d);
237
 
    if (amount < 1.0f)
238
 
        amount = 1.0f;
239
 
    else if (amount > 5.0f)
240
 
        amount = 5.0f;
241
 
 
242
 
    zooms.at (out).zVelocity =
243
 
        (amount * zooms.at (out).zVelocity + adjust) / (amount + 1.0f);
244
 
 
245
 
    if (fabs (d) < 0.1f && fabs (zooms.at (out).zVelocity) < 0.005f)
246
 
    {
247
 
        zooms.at (out).currentZoom = zooms.at (out).newZoom;
248
 
        zooms.at (out).zVelocity = 0.0f;
249
 
    }
250
 
    else
251
 
    {
252
 
        zooms.at (out).currentZoom += (zooms.at (out).zVelocity * chunk) /
253
 
            cScreen->redrawTime ();
254
 
    }
255
 
}
256
 
 
257
 
/* Adjust the X/Y velocity based on target translation and real
258
 
 * translation. */
259
 
void
260
 
EZoomScreen::adjustXYVelocity (int out, float chunk)
261
 
{
262
 
    float xdiff, ydiff;
263
 
    float xadjust, yadjust;
264
 
    float xamount, yamount;
265
 
 
266
 
    zooms.at (out).xVelocity /= 1.25f;
267
 
    zooms.at (out).yVelocity /= 1.25f;
268
 
    xdiff =
269
 
        (zooms.at (out).xTranslate - zooms.at (out).realXTranslate) *
270
 
        75.0f;
271
 
    ydiff =
272
 
        (zooms.at (out).yTranslate - zooms.at (out).realYTranslate) *
273
 
        75.0f;
274
 
    xadjust = xdiff * 0.002f;
275
 
    yadjust = ydiff * 0.002f;
276
 
    xamount = fabs (xdiff);
277
 
    yamount = fabs (ydiff);
278
 
 
279
 
    if (xamount < 1.0f)
280
 
            xamount = 1.0f;
281
 
    else if (xamount > 5.0)
282
 
            xamount = 5.0f;
283
 
 
284
 
    if (yamount < 1.0f)
285
 
            yamount = 1.0f;
286
 
    else if (yamount > 5.0)
287
 
            yamount = 5.0f;
288
 
 
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);
293
 
 
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))
296
 
    {
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;
301
 
        return;
302
 
    }
303
 
 
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 ();
308
 
}
309
 
 
310
 
/* Animate the movement (if any) in preparation of a paint screen.  */
311
 
void
312
 
EZoomScreen::preparePaint (int     msSinceLastPaint)
313
 
{
314
 
    if (grabbed)
315
 
    {
316
 
        int   steps;
317
 
        float amount, chunk;
318
 
 
319
 
        amount = msSinceLastPaint * 0.05f * optionGetSpeed ();
320
 
        steps  = amount / (0.5f * optionGetTimestep ());
321
 
        if (!steps)
322
 
                steps = 1;
323
 
        chunk  = amount / (float) steps;
324
 
        while (steps--)
325
 
        {
326
 
            unsigned int out;
327
 
            for (out = 0; out < zooms.size (); out++)
328
 
            {
329
 
                if (!isInMovement (out) || !isActive (out))
330
 
                    continue;
331
 
 
332
 
                adjustXYVelocity (out, chunk);
333
 
                adjustZoomVelocity (out, chunk);
334
 
                zooms.at (out).updateActualTranslates ();
335
 
                if (!isZoomed (out))
336
 
                {
337
 
                    zooms.at (out).xVelocity = zooms.at (out).yVelocity =
338
 
                        0.0f;
339
 
                    grabbed &= ~(1 << zooms.at (out).output);
340
 
                    if (!grabbed)
341
 
                    {
342
 
                        cScreen->damageScreen ();
343
 
                        toggleFunctions (false);
344
 
                    }
345
 
                }
346
 
            }
347
 
        }
348
 
        if (optionGetZoomMode () == EzoomOptions::ZoomModeSyncMouse)
349
 
            syncCenterToMouse ();
350
 
    }
351
 
 
352
 
    cScreen->preparePaint (msSinceLastPaint);
353
 
}
354
 
 
355
 
/* Damage screen if we're still moving.  */
356
 
void
357
 
EZoomScreen::donePaint ()
358
 
{
359
 
    if (grabbed)
360
 
    {
361
 
        unsigned int out;
362
 
        for (out = 0; out < zooms.size (); out++)
363
 
        {
364
 
            if (isInMovement (out) && isActive (out))
365
 
            {
366
 
                cScreen->damageScreen ();
367
 
                break;
368
 
            }
369
 
        }
370
 
    }
371
 
    else if (grabIndex)
372
 
        cScreen->damageScreen ();
373
 
    else
374
 
        toggleFunctions (false);
375
 
 
376
 
    cScreen->donePaint ();
377
 
}
378
 
/* Draws a box from the screen coordinates inx1,iny1 to inx2,iny2 */
379
 
void
380
 
EZoomScreen::drawBox (const GLMatrix &transform,
381
 
                     CompOutput          *output,
382
 
                     CompRect             box)
383
 
{
384
 
    GLMatrix zTransform = transform;
385
 
    int           x1,x2,y1,y2;
386
 
    int           inx1, inx2, iny1, iny2;
387
 
    int           out = output->id ();
388
 
 
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);
392
 
 
393
 
    x1 = MIN (inx1, inx2);
394
 
    y1 = MIN (iny1, iny2);
395
 
    x2 = MAX (inx1, inx2);
396
 
    y2 = MAX (iny1, iny2);
397
 
    glPushMatrix ();
398
 
    glLoadMatrixf (zTransform.getMatrix ());
399
 
    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
400
 
    glEnable (GL_BLEND);
401
 
    glColor4us (0x2fff, 0x2fff, 0x4fff, 0x4fff);
402
 
    glRecti (x1,y2,x2,y1);
403
 
    glColor4us (0x2fff, 0x2fff, 0x4fff, 0x9fff);
404
 
    glBegin (GL_LINE_LOOP);
405
 
    glVertex2i (x1, y1);
406
 
    glVertex2i (x2, y1);
407
 
    glVertex2i (x2, y2);
408
 
    glVertex2i (x1, y2);
409
 
    glEnd ();
410
 
    glColor4usv (defaultColor);
411
 
    glDisable (GL_BLEND);
412
 
    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
413
 
    glPopMatrix ();
414
 
}
415
 
/* Apply the zoom if we are grabbed.
416
 
 * Make sure to use the correct filter.
417
 
 */
418
 
bool
419
 
EZoomScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
420
 
                           const GLMatrix            &transform,
421
 
                           const CompRegion          &region,
422
 
                           CompOutput                *output,
423
 
                           unsigned int              mask)
424
 
{
425
 
    bool status;
426
 
    int  out = output->id ();
427
 
 
428
 
    if (isActive (out))
429
 
    {
430
 
        GLScreenPaintAttrib sa = attrib;
431
 
        GLMatrix            zTransform = transform;
432
 
 
433
 
        mask &= ~PAINT_SCREEN_REGION_MASK;
434
 
        mask |= PAINT_SCREEN_CLEAR_MASK;
435
 
 
436
 
        zTransform.scale (1.0f / zooms.at (out).currentZoom,
437
 
                          1.0f / zooms.at (out).currentZoom,
438
 
                          1.0f);
439
 
        zTransform.translate (zooms.at (out).xtrans,
440
 
                              zooms.at (out).ytrans,
441
 
                              0);
442
 
 
443
 
        mask |= PAINT_SCREEN_TRANSFORMED_MASK;
444
 
 
445
 
        status = gScreen->glPaintOutput (sa, zTransform, region, output, mask);
446
 
 
447
 
        drawCursor (output, transform);
448
 
 
449
 
    }
450
 
    else
451
 
    {
452
 
        status = gScreen->glPaintOutput (attrib, transform, region, output,
453
 
                                                                        mask);
454
 
    }
455
 
    if (grabIndex)
456
 
        drawBox (transform, output, box);
457
 
 
458
 
    return status;
459
 
}
460
 
 
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.  */
464
 
static inline void
465
 
constrainZoomTranslate ()
466
 
{
467
 
    unsigned int out;
468
 
    ZOOM_SCREEN (screen);
469
 
 
470
 
    for (out = 0; out < zs->zooms.size (); out++)
471
 
    {
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;
476
 
 
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;
481
 
    }
482
 
}
483
 
 
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.  */
488
 
 
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.
497
 
 */
498
 
void
499
 
EZoomScreen::setCenter (int x, int y, bool instant)
500
 
{
501
 
    int         out = screen->outputDeviceForPoint (x, y);
502
 
    CompOutput  *o = &screen->outputDevs ().at (out);
503
 
 
504
 
    if (zooms.at (out).locked)
505
 
        return;
506
 
 
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 ());
511
 
 
512
 
    if (instant)
513
 
    {
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 ();
519
 
    }
520
 
 
521
 
    if (optionGetZoomMode () == EzoomOptions::ZoomModePanArea)
522
 
        restrainCursor (out);
523
 
}
524
 
 
525
 
/* Zooms the area described.
526
 
 * The math could probably be cleaned up, but should be correct now. */
527
 
void
528
 
EZoomScreen::setZoomArea (int        x,
529
 
                         int        y,
530
 
                         int        width,
531
 
                         int        height,
532
 
                         bool       instant)
533
 
{
534
 
    CompWindow::Geometry outGeometry (x, y, width, height, 0);
535
 
    int         out = screen->outputDeviceForGeometry (outGeometry);
536
 
    CompOutput  *o = &screen->outputDevs ().at (out);
537
 
 
538
 
    if (zooms.at (out).newZoom == 1.0f)
539
 
        return;
540
 
 
541
 
    if (zooms.at (out).locked)
542
 
        return;
543
 
    zooms.at (out).xTranslate =
544
 
         (float) -((o->width () / 2) - (x + (width / 2) - o->x1 ()))
545
 
        / (o->width ());
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 ()))
549
 
        / (o->height ());
550
 
    zooms.at (out).yTranslate /= (1.0f - zooms.at (out).newZoom);
551
 
    constrainZoomTranslate ();
552
 
 
553
 
    if (instant)
554
 
    {
555
 
        zooms.at (out).realXTranslate = zooms.at (out).xTranslate;
556
 
        zooms.at (out).realYTranslate = zooms.at (out).yTranslate;
557
 
        zooms.at (out).updateActualTranslates ();
558
 
    }
559
 
 
560
 
    if (optionGetZoomMode () == EzoomOptions::ZoomModePanArea)
561
 
        restrainCursor (out);
562
 
}
563
 
 
564
 
/* Moves the zoom area to the window specified */
565
 
void
566
 
EZoomScreen::areaToWindow (CompWindow *w)
567
 
{
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;
572
 
 
573
 
    setZoomArea (left, top, width, height, false);
574
 
}
575
 
 
576
 
/* Pans the zoomed area vertically/horizontally by * value * zs->panFactor
577
 
 * TODO: Fix output. */
578
 
void
579
 
EZoomScreen::panZoom (int xvalue, int yvalue)
580
 
{
581
 
    unsigned int out;
582
 
 
583
 
    for (out = 0; out < zooms.size (); out++)
584
 
    {
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;
591
 
    }
592
 
 
593
 
    constrainZoomTranslate ();
594
 
}
595
 
 
596
 
/* Enables polling of mouse position, and refreshes currently
597
 
 * stored values.
598
 
 */
599
 
void
600
 
EZoomScreen::enableMousePolling ()
601
 
{
602
 
    pollHandle.start ();
603
 
    lastChange = time(NULL);
604
 
    mouse = MousePoller::getCurrentPosition ();
605
 
}
606
 
 
607
 
/* Sets the zoom (or scale) level.
608
 
 * Cleans up if we are suddenly zoomed out.
609
 
 */
610
 
void
611
 
EZoomScreen::setScale (int out, float value)
612
 
{
613
 
    if (zooms.at (out).locked)
614
 
        return;
615
 
 
616
 
    if (value >= 1.0f)
617
 
        value = 1.0f;
618
 
    else
619
 
    {
620
 
        if (!pollHandle.active ())
621
 
            enableMousePolling ();
622
 
        grabbed |= (1 << zooms.at (out).output);
623
 
        cursorZoomActive (out);
624
 
    }
625
 
 
626
 
    if (value == 1.0f)
627
 
    {
628
 
        zooms.at (out).xTranslate = 0.0f;
629
 
        zooms.at (out).yTranslate = 0.0f;
630
 
        cursorZoomInactive ();
631
 
    }
632
 
 
633
 
    if (value < optionGetMinimumZoom ())
634
 
        value = optionGetMinimumZoom ();
635
 
 
636
 
    zooms.at (out).newZoom = value;
637
 
    cScreen->damageScreen();
638
 
}
639
 
 
640
 
/* Sets the zoom factor to the bigger of the two floats supplied.
641
 
 * Convenience function for setting the scale factor for an area.
642
 
 */
643
 
static inline void
644
 
setScaleBigger (int out, float x, float y)
645
 
{
646
 
    ZOOM_SCREEN (screen);
647
 
    zs->setScale (out, x > y ? x : y);
648
 
}
649
 
 
650
 
/* Mouse code...
651
 
 * This takes care of keeping the mouse in sync with the zoomed area and
652
 
 * vice versa.
653
 
 * See heading for description.
654
 
 */
655
 
 
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.
659
 
 */
660
 
void
661
 
EZoomScreen::syncCenterToMouse ()
662
 
{
663
 
    int         x, y;
664
 
    int         out;
665
 
    CompOutput  *o;
666
 
 
667
 
    out = screen->outputDeviceForPoint (mouse.x (), mouse.y ());
668
 
    o = &screen->outputDevs ().at (out);
669
 
 
670
 
    if (!isInMovement (out))
671
 
        return;
672
 
 
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 ());
677
 
 
678
 
    if ((x != mouse.x () || y != mouse.y ())
679
 
        && grabbed && zooms.at (out).newZoom != 1.0f)
680
 
    {
681
 
        screen->warpPointer (x - pointerX , y - pointerY );
682
 
        mouse.setX (x);
683
 
        mouse.setY (y);
684
 
    }
685
 
}
686
 
 
687
 
/* Convert the point X,Y to where it would be when zoomed.  */
688
 
void
689
 
EZoomScreen::convertToZoomed (int        out,
690
 
                             int        x,
691
 
                             int        y,
692
 
                             int        *resultX,
693
 
                             int        *resultY)
694
 
{
695
 
    CompOutput *o;
696
 
 
697
 
    if (!outputIsZoomArea (out))
698
 
    {
699
 
        *resultX = x;
700
 
        *resultY = y;
701
 
    }
702
 
 
703
 
    o = &screen->outputDevs ()[out];
704
 
    ZoomArea    &za = zooms.at (out);
705
 
 
706
 
    x -= o->x1 ();
707
 
    y -= o->y1 ();
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 ();
718
 
}
719
 
 
720
 
/* Same but use targeted translation, not real */
721
 
void
722
 
EZoomScreen::convertToZoomedTarget (int   out,
723
 
                                   int    x,
724
 
                                   int    y,
725
 
                                   int    *resultX,
726
 
                                   int    *resultY)
727
 
{
728
 
    CompOutput *o = &screen->outputDevs ().at (out);
729
 
 
730
 
    if (!outputIsZoomArea (out))
731
 
    {
732
 
        *resultX = x;
733
 
        *resultY = y;
734
 
    }
735
 
 
736
 
    ZoomArea    &za = zooms.at (out);
737
 
 
738
 
    x -= o->x1 ();
739
 
    y -= o->y1 ();
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 ();
750
 
}
751
 
 
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. */
756
 
bool
757
 
EZoomScreen::ensureVisibility (int x, int y, int margin)
758
 
{
759
 
    int         zoomX, zoomY;
760
 
    int         out;
761
 
    CompOutput  *o;
762
 
 
763
 
    out = screen->outputDeviceForPoint (x, y);
764
 
    if (!isActive (out))
765
 
        return false;
766
 
 
767
 
    o = &screen->outputDevs ().at (out);
768
 
    convertToZoomedTarget (out, x, y, &zoomX, &zoomY);
769
 
    ZoomArea &za = zooms.at (out);
770
 
    if (za.locked)
771
 
        return false;
772
 
 
773
 
#define FACTOR (za.newZoom / (1.0f - za.newZoom))
774
 
    if (zoomX + margin > o->x2 ())
775
 
        za.xTranslate +=
776
 
            (FACTOR * (float) (zoomX + margin - o->x2 ())) /
777
 
            (float) o->width ();
778
 
    else if (zoomX - margin < o->x1 ())
779
 
        za.xTranslate +=
780
 
            (FACTOR * (float) (zoomX - margin - o->x1 ())) /
781
 
            (float) o->width ();
782
 
 
783
 
    if (zoomY + margin > o->y2 ())
784
 
        za.yTranslate +=
785
 
            (FACTOR * (float) (zoomY + margin - o->y2 ())) /
786
 
            (float) o->height ();
787
 
    else if (zoomY - margin < o->y1 ())
788
 
        za.yTranslate +=
789
 
            (FACTOR * (float) (zoomY - margin - o->y1 ())) /
790
 
            (float) o->height ();
791
 
#undef FACTOR
792
 
    constrainZoomTranslate ();
793
 
    return true;
794
 
}
795
 
 
796
 
/* Attempt to ensure the visibility of an area defined by x1/y1 and x2/y2.
797
 
 * See ensureVisibility () for details.
798
 
 *
799
 
 * This attempts to find the translations that leaves the biggest part of
800
 
 * the area visible.
801
 
 *
802
 
 * gravity defines what part of the window that should get
803
 
 * priority if it isn't possible to fit all of it.
804
 
 */
805
 
void
806
 
EZoomScreen::ensureVisibilityArea (int         x1,
807
 
                                  int         y1,
808
 
                                  int         x2,
809
 
                                  int         y2,
810
 
                                  int         margin,
811
 
                                  ZoomGravity gravity)
812
 
{
813
 
    int        targetX, targetY, targetW, targetH;
814
 
    int        out;
815
 
    CompOutput *o;
816
 
 
817
 
    out = screen->outputDeviceForPoint (x1 + (x2-x1/2), y1 + (y2-y1/2));
818
 
    o = &screen->outputDevs ().at (out);
819
 
 
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
822
 
 
823
 
    if (WIDTHOK &&
824
 
        HEIGHTOK) {
825
 
        ensureVisibility (x1, y1, margin);
826
 
        ensureVisibility (x2, y2, margin);
827
 
        return;
828
 
    }
829
 
 
830
 
    switch (gravity)
831
 
    {
832
 
        case NORTHWEST:
833
 
            targetX = x1;
834
 
            targetY = y1;
835
 
            if (WIDTHOK)
836
 
                targetW = x2 - x1;
837
 
            else
838
 
                targetW = o->width () * zooms.at (out).newZoom;
839
 
            if (HEIGHTOK)
840
 
                targetH = y2 - y1;
841
 
            else
842
 
                targetH = o->height () * zooms.at (out).newZoom;
843
 
            break;
844
 
        case NORTHEAST:
845
 
            targetY = y1;
846
 
            if (WIDTHOK)
847
 
            {
848
 
                targetX = x1;
849
 
                targetW = x2-x1;
850
 
            }
851
 
            else
852
 
            {
853
 
                targetX = x2 - o->width () * zooms.at (out).newZoom;
854
 
                targetW = o->width () * zooms.at (out).newZoom;
855
 
            }
856
 
 
857
 
            if (HEIGHTOK)
858
 
                targetH = y2-y1;
859
 
            else
860
 
                targetH = o->height () * zooms.at (out).newZoom;
861
 
            break;
862
 
        case SOUTHWEST:
863
 
            targetX = x1;
864
 
            if (WIDTHOK)
865
 
                targetW = x2-x1;
866
 
            else
867
 
                targetW = o->width () * zooms.at (out).newZoom;
868
 
            if (HEIGHTOK)
869
 
            {
870
 
                targetY = y1;
871
 
                targetH = y2-y1;
872
 
            }
873
 
            else
874
 
            {
875
 
                targetY = y2 - (o->width () * zooms.at (out).newZoom);
876
 
                targetH = o->width () * zooms.at (out).newZoom;
877
 
            }
878
 
            break;
879
 
        case SOUTHEAST:
880
 
            if (WIDTHOK)
881
 
            {
882
 
                targetX = x1;
883
 
                targetW = x2-x1;
884
 
            }
885
 
            else
886
 
            {
887
 
                targetW = o->width () * zooms.at (out).newZoom;
888
 
                targetX = x2 - targetW;
889
 
            }
890
 
 
891
 
            if (HEIGHTOK)
892
 
            {
893
 
                targetY = y1;
894
 
                targetH = y2 - y1;
895
 
            }
896
 
            else
897
 
            {
898
 
                targetH = o->height () * zooms.at (out).newZoom;
899
 
                targetY = y2 - targetH;
900
 
            }
901
 
            break;
902
 
        case CENTER:
903
 
        default:
904
 
            setCenter (x1 + (x2 - x1 / 2), y1 + (y2 - y1 / 2), false);
905
 
            return;
906
 
            break;
907
 
    }
908
 
 
909
 
    setZoomArea (targetX, targetY, targetW, targetH, false);
910
 
    return ;
911
 
}
912
 
 
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
916
 
 * started).
917
 
 */
918
 
void
919
 
EZoomScreen::restrainCursor (int out)
920
 
{
921
 
    int         x1, y1, x2, y2, margin;
922
 
    int         diffX = 0, diffY = 0;
923
 
    int         north, south, east, west;
924
 
    float       z;
925
 
    CompOutput  *o = &screen->outputDevs ().at (out);
926
 
 
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);
933
 
 
934
 
    if (zooms.at (out).currentZoom == 1.0f)
935
 
    {
936
 
        lastChange = time(NULL);
937
 
        mouse = MousePoller::getCurrentPosition ();
938
 
    }
939
 
 
940
 
    convertToZoomedTarget (out, mouse.x () - cursor.hotX,
941
 
                           mouse.y () - cursor.hotY, &x1, &y1);
942
 
    convertToZoomedTarget
943
 
        (out,
944
 
         mouse.x () - cursor.hotX + cursor.width,
945
 
         mouse.y () - cursor.hotY + cursor.height,
946
 
         &x2, &y2);
947
 
 
948
 
    if ((x2 - x1 > o->x2 () - o->x1 ()) ||
949
 
       (y2 - y1 > o->y2 () - o->y1 ()))
950
 
        return;
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;
955
 
 
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;
960
 
 
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));
966
 
}
967
 
 
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).
973
 
 */
974
 
void
975
 
EZoomScreen::cursorMoved ()
976
 
{
977
 
    int         out;
978
 
 
979
 
    out = screen->outputDeviceForPoint (mouse.x (), mouse.y ());
980
 
    if (isActive (out))
981
 
    {
982
 
        if (optionGetRestrainMouse ())
983
 
            restrainCursor (out);
984
 
 
985
 
        if (optionGetZoomMode () == EzoomOptions::ZoomModePanArea)
986
 
        {
987
 
            ensureVisibilityArea (mouse.x () - cursor.hotX,
988
 
                                  mouse.y () - cursor.hotY,
989
 
                                  mouse.x () + cursor.width -
990
 
                                  cursor.hotX,
991
 
                                  mouse.y () + cursor.height -
992
 
                                  cursor.hotY,
993
 
                                  optionGetRestrainMargin (),
994
 
                                  NORTHWEST);
995
 
        }
996
 
 
997
 
        cursorZoomActive (out);
998
 
    }
999
 
    else
1000
 
    {
1001
 
        cursorZoomInactive ();
1002
 
    }
1003
 
}
1004
 
 
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.
1008
 
 */
1009
 
void
1010
 
EZoomScreen::updateMousePosition (const CompPoint &p)
1011
 
{
1012
 
    int out;
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);
1020
 
    cursorMoved ();
1021
 
    cScreen->damageScreen ();
1022
 
}
1023
 
 
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. */
1026
 
void
1027
 
EZoomScreen::updateMouseInterval (const CompPoint &p)
1028
 
{
1029
 
    updateMousePosition (p);
1030
 
 
1031
 
    if (!grabbed)
1032
 
    {
1033
 
        cursorMoved ();
1034
 
        if (pollHandle.active ())
1035
 
            pollHandle.stop ();
1036
 
    }
1037
 
}
1038
 
 
1039
 
/* Free a cursor */
1040
 
void
1041
 
EZoomScreen::freeCursor (CursorTexture * cursor)
1042
 
{
1043
 
    if (!cursor->isSet)
1044
 
        return;
1045
 
 
1046
 
    cursor->isSet = false;
1047
 
    glDeleteTextures (1, &cursor->texture);
1048
 
    cursor->texture = 0;
1049
 
}
1050
 
 
1051
 
/* Translate into place and draw the scaled cursor.  */
1052
 
void
1053
 
EZoomScreen::drawCursor (CompOutput          *output,
1054
 
                        const GLMatrix      &transform)
1055
 
{
1056
 
    int         out = output->id ();
1057
 
 
1058
 
    if (cursor.isSet)
1059
 
    {
1060
 
        GLMatrix      sTransform = transform;
1061
 
        float         scaleFactor;
1062
 
        int           ax, ay, x, y;
1063
 
 
1064
 
        /*
1065
 
         * XXX: expo knows how to handle mouse when zoomed, so we back off
1066
 
         * when expo is active.
1067
 
         */
1068
 
        if (screen->grabExist ( "expo"))
1069
 
        {
1070
 
            cursorZoomInactive ();
1071
 
            return;
1072
 
        }
1073
 
 
1074
 
        sTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
1075
 
        convertToZoomed (out, mouse.x (), mouse.y (), &ax, &ay);
1076
 
        glPushMatrix ();
1077
 
        glLoadMatrixf (sTransform.getMatrix ());
1078
 
        glTranslatef ((float) ax, (float) ay, 0.0f);
1079
 
        if (optionGetScaleMouseDynamic ())
1080
 
            scaleFactor = 1.0f / zooms.at (out).currentZoom;
1081
 
        else
1082
 
            scaleFactor = 1.0f / optionGetScaleMouseStatic ();
1083
 
        glScalef (scaleFactor,
1084
 
                  scaleFactor,
1085
 
                  1.0f);
1086
 
        x = -cursor.hotX;
1087
 
        y = -cursor.hotY;
1088
 
 
1089
 
        glEnable (GL_BLEND);
1090
 
        glBindTexture (GL_TEXTURE_RECTANGLE_ARB, cursor.texture);
1091
 
        glEnable (GL_TEXTURE_RECTANGLE_ARB);
1092
 
 
1093
 
        glBegin (GL_QUADS);
1094
 
        glTexCoord2d (0, 0);
1095
 
        glVertex2f (x, y);
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);
1102
 
        glEnd ();
1103
 
        glDisable (GL_BLEND);
1104
 
        glBindTexture (GL_TEXTURE_RECTANGLE_ARB, 0);
1105
 
        glDisable (GL_TEXTURE_RECTANGLE_ARB);
1106
 
        glPopMatrix ();
1107
 
    }
1108
 
}
1109
 
 
1110
 
/* Create (if necessary) a texture to store the cursor,
1111
 
 * fetch the cursor with XFixes. Store it.  */
1112
 
void
1113
 
EZoomScreen::updateCursor (CursorTexture * cursor)
1114
 
{
1115
 
    unsigned char *pixels;
1116
 
    int           i;
1117
 
    Display       *dpy = screen->dpy ();
1118
 
 
1119
 
    if (!cursor->isSet)
1120
 
    {
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);
1126
 
 
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);
1131
 
    } else {
1132
 
        glEnable (GL_TEXTURE_RECTANGLE_ARB);
1133
 
    }
1134
 
 
1135
 
    XFixesCursorImage *ci = XFixesGetCursorImage (dpy);
1136
 
 
1137
 
    if (ci)
1138
 
    {
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);
1144
 
 
1145
 
        if (!pixels)
1146
 
        {
1147
 
            XFree (ci);
1148
 
            return;
1149
 
        }
1150
 
 
1151
 
        for (i = 0; i < ci->width * ci->height; i++)
1152
 
        {
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;
1158
 
        }
1159
 
 
1160
 
        XFree (ci);
1161
 
    }
1162
 
    else
1163
 
    {
1164
 
        /* Fallback R: 255 G: 255 B: 255 A: 255
1165
 
         * FIXME: Draw a cairo mouse cursor */
1166
 
 
1167
 
        cursor->width = 1;
1168
 
        cursor->height = 1;
1169
 
        cursor->hotX = 0;
1170
 
        cursor->hotY = 0;
1171
 
        pixels = (unsigned char *) malloc (cursor->width * cursor->height * 4);
1172
 
 
1173
 
        if (!pixels)
1174
 
            return;
1175
 
 
1176
 
        for (i = 0; i < cursor->width * cursor->height; i++)
1177
 
        {
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;
1183
 
        }
1184
 
 
1185
 
        compLogMessage ("ezoom", CompLogLevelWarn, "unable to get system cursor image!");
1186
 
    }
1187
 
 
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);
1193
 
        
1194
 
    free (pixels);
1195
 
}
1196
 
 
1197
 
/* We are no longer zooming the cursor, so display it.  */
1198
 
void
1199
 
EZoomScreen::cursorZoomInactive ()
1200
 
{
1201
 
    if (!fixesSupported)
1202
 
        return;
1203
 
 
1204
 
    if (cursorInfoSelected)
1205
 
    {
1206
 
        cursorInfoSelected = false;
1207
 
        XFixesSelectCursorInput (screen->dpy (), screen->root (), 0);
1208
 
    }
1209
 
 
1210
 
    if (cursor.isSet)
1211
 
    {
1212
 
        freeCursor (&cursor);
1213
 
    }
1214
 
 
1215
 
    if (cursorHidden)
1216
 
    {
1217
 
        cursorHidden = false;
1218
 
        XFixesShowCursor (screen->dpy (), screen->root ());
1219
 
    }
1220
 
}
1221
 
 
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
1225
 
 * activation.
1226
 
 */
1227
 
void
1228
 
EZoomScreen::cursorZoomActive (int out)
1229
 
{
1230
 
    if (!fixesSupported)
1231
 
        return;
1232
 
 
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
1235
 
     */
1236
 
 
1237
 
    if (!optionGetScaleMouse () &&
1238
 
        (optionGetZoomMode () == EzoomOptions::ZoomModeSyncMouse &&
1239
 
         optionGetHideOriginalMouse () &&
1240
 
         !zooms.at (out).locked))
1241
 
        return;
1242
 
 
1243
 
    if (!cursorInfoSelected)
1244
 
    {
1245
 
        cursorInfoSelected = true;
1246
 
        XFixesSelectCursorInput (screen->dpy (), screen->root (),
1247
 
                                 XFixesDisplayCursorNotifyMask);
1248
 
        updateCursor (&cursor);
1249
 
    }
1250
 
    if (canHideCursor && !cursorHidden &&
1251
 
        (optionGetHideOriginalMouse () ||
1252
 
         zooms.at (out).locked))
1253
 
    {
1254
 
        cursorHidden = true;
1255
 
        XFixesHideCursor (screen->dpy (), screen->root ());
1256
 
    }
1257
 
}
1258
 
 
1259
 
/* Set the zoom area
1260
 
 * This is an interface for scripting.
1261
 
 * int32:x1: left x coordinate
1262
 
 * int32:y1: top y coordinate
1263
 
 * int32:x2: right x
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.
1269
 
 */
1270
 
bool
1271
 
EZoomScreen::setZoomAreaAction (CompAction         *action,
1272
 
                               CompAction::State  state,
1273
 
                               CompOption::Vector options)
1274
 
{
1275
 
    int        x1, y1, x2, y2, out;
1276
 
    bool       scale, restrain;
1277
 
    CompOutput *o;
1278
 
 
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);
1285
 
 
1286
 
    if (x1 < 0 || y1 < 0)
1287
 
        return false;
1288
 
 
1289
 
    if (x2 < 0)
1290
 
        x2 = x1 + 1;
1291
 
 
1292
 
    if (y2 < 0)
1293
 
        y2 = y1 + 1;
1294
 
 
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 ());
1303
 
#undef WIDTH
1304
 
#undef HEIGHT
1305
 
        if (restrain)
1306
 
            restrainCursor (out);
1307
 
 
1308
 
    toggleFunctions (true);
1309
 
 
1310
 
    return true;
1311
 
}
1312
 
 
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.
1322
 
 */
1323
 
bool
1324
 
EZoomScreen::ensureVisibilityAction (CompAction         *action,
1325
 
                                    CompAction::State  state,
1326
 
                                    CompOption::Vector options)
1327
 
{
1328
 
    int        x1, y1, x2, y2, margin, out;
1329
 
    bool       scale, restrain;
1330
 
    CompOutput *o;
1331
 
 
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)
1340
 
        return false;
1341
 
    if (x2 < 0)
1342
 
        y2 = y1 + 1;
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 ());
1353
 
#undef WIDTH
1354
 
#undef HEIGHT
1355
 
    if (restrain)
1356
 
        restrainCursor (out);
1357
 
 
1358
 
    toggleFunctions (true);
1359
 
 
1360
 
    return true;
1361
 
}
1362
 
 
1363
 
/* Finished here */
1364
 
 
1365
 
bool
1366
 
EZoomScreen::zoomBoxActivate (CompAction         *action,
1367
 
                             CompAction::State  state,
1368
 
                             CompOption::Vector options)
1369
 
{
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);
1376
 
 
1377
 
    toggleFunctions (true);
1378
 
 
1379
 
    return true;
1380
 
}
1381
 
 
1382
 
bool
1383
 
EZoomScreen::zoomBoxDeactivate (CompAction         *action,
1384
 
                               CompAction::State  state,
1385
 
                               CompOption::Vector options)
1386
 
{
1387
 
    if (grabIndex)
1388
 
    {
1389
 
        int        out;
1390
 
        int        x, y, width, height;
1391
 
        CompOutput *o;
1392
 
 
1393
 
        screen->removeGrab (grabIndex, NULL);
1394
 
        grabIndex = 0;
1395
 
 
1396
 
        if (pointerX < clickPos.x ())
1397
 
        {
1398
 
            box.setX (pointerX);
1399
 
            box.setWidth (clickPos.x () - pointerX);
1400
 
        }
1401
 
        else
1402
 
        {
1403
 
            box.setWidth (pointerX - clickPos.x ());
1404
 
        }
1405
 
 
1406
 
        if (pointerY < clickPos.y ())
1407
 
        {
1408
 
            box.setY (pointerY);
1409
 
            box.setHeight (clickPos.y () - pointerY);
1410
 
        }
1411
 
        else
1412
 
        {
1413
 
            box.setHeight (pointerY - clickPos.y ());
1414
 
        }
1415
 
 
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;
1420
 
 
1421
 
        CompWindow::Geometry outGeometry (x, y, width, height, 0);
1422
 
 
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);
1428
 
    }
1429
 
 
1430
 
    toggleFunctions (true);
1431
 
 
1432
 
    return true;
1433
 
}
1434
 
 
1435
 
/* Zoom in to the area pointed to by the mouse.
1436
 
 */
1437
 
bool
1438
 
EZoomScreen::zoomIn (CompAction         *action,
1439
 
                    CompAction::State  state,
1440
 
                    CompOption::Vector options)
1441
 
{
1442
 
    int out = screen->outputDeviceForPoint (pointerX, pointerY);
1443
 
 
1444
 
    if (optionGetZoomMode () == EzoomOptions::ZoomModeSyncMouse &&
1445
 
        !isInMovement (out))
1446
 
        setCenter (pointerX, pointerY, true);
1447
 
 
1448
 
    setScale (out,
1449
 
              zooms.at (out).newZoom /
1450
 
              optionGetZoomFactor ());
1451
 
 
1452
 
    toggleFunctions (true);
1453
 
 
1454
 
    return true;
1455
 
}
1456
 
 
1457
 
/* Locks down the current zoom area
1458
 
 */
1459
 
bool
1460
 
EZoomScreen::lockZoomAction (CompAction         *action,
1461
 
                            CompAction::State  state,
1462
 
                            CompOption::Vector options)
1463
 
{
1464
 
    int out = screen->outputDeviceForPoint (pointerX, pointerY);
1465
 
    zooms.at (out).locked = !zooms.at (out).locked;
1466
 
 
1467
 
    return true;
1468
 
}
1469
 
 
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...
1476
 
 */
1477
 
bool
1478
 
EZoomScreen::zoomSpecific (CompAction         *action,
1479
 
                          CompAction::State  state,
1480
 
                          CompOption::Vector options,
1481
 
                          float              target)
1482
 
{
1483
 
    int          x, y;
1484
 
    int          out = screen->outputDeviceForPoint (pointerX, pointerY);
1485
 
    CompWindow   *w;
1486
 
 
1487
 
    if (target == 1.0f && zooms.at (out).newZoom == 1.0f)
1488
 
        return false;
1489
 
    if (screen->otherGrabExist (NULL))
1490
 
        return false;
1491
 
 
1492
 
    setScale (out, target);
1493
 
 
1494
 
    w = screen->findWindow (screen->activeWindow ());
1495
 
    if (optionGetSpecTargetFocus ()
1496
 
        && w)
1497
 
    {
1498
 
        areaToWindow (w);
1499
 
    }
1500
 
    else
1501
 
    {
1502
 
        x = CompOption::getIntOptionNamed (options, "x", 0);
1503
 
        y = CompOption::getIntOptionNamed (options, "y", 0);
1504
 
        setCenter (x, y, false);
1505
 
    }
1506
 
 
1507
 
    toggleFunctions (true);
1508
 
 
1509
 
    return true;
1510
 
}
1511
 
 
1512
 
/* TODO: Add specific zoom boost::bind's */
1513
 
 
1514
 
/* Zooms to fit the active window to the screen without cutting
1515
 
 * it off and targets it.
1516
 
 */
1517
 
bool
1518
 
EZoomScreen::zoomToWindow (CompAction         *action,
1519
 
                          CompAction::State  state,
1520
 
                          CompOption::Vector options)
1521
 
{
1522
 
    int        width, height, out;
1523
 
    Window     xid;
1524
 
    CompWindow *w;
1525
 
    CompOutput *o;
1526
 
 
1527
 
    xid = CompOption::getIntOptionNamed (options, "window", 0);
1528
 
    w = screen->findWindow (xid);
1529
 
    if (!w)
1530
 
        return true;
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 ());
1537
 
    areaToWindow (w);
1538
 
    toggleFunctions (true);
1539
 
 
1540
 
    return true;
1541
 
}
1542
 
 
1543
 
bool
1544
 
EZoomScreen::zoomPan (CompAction         *action,
1545
 
                     CompAction::State  state,
1546
 
                     CompOption::Vector options,
1547
 
                     float              horizAmount,
1548
 
                     float              vertAmount)
1549
 
{
1550
 
    panZoom (horizAmount, vertAmount);
1551
 
 
1552
 
    return true;
1553
 
}
1554
 
 
1555
 
/* Centers the mouse based on zoom level and translation.
1556
 
 */
1557
 
bool
1558
 
EZoomScreen::zoomCenterMouse (CompAction         *action,
1559
 
                             CompAction::State  state,
1560
 
                             CompOption::Vector options)
1561
 
{
1562
 
    int        out;
1563
 
 
1564
 
 
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));
1574
 
    return true;
1575
 
}
1576
 
 
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.
1581
 
 */
1582
 
bool
1583
 
EZoomScreen::zoomFitWindowToZoom (CompAction         *action,
1584
 
                                 CompAction::State  state,
1585
 
                                 CompOption::Vector options)
1586
 
{
1587
 
    int            out;
1588
 
    unsigned int   mask = CWWidth | CWHeight;
1589
 
    XWindowChanges xwc;
1590
 
    CompWindow     *w;
1591
 
 
1592
 
    w = screen->findWindow (CompOption::getIntOptionNamed (
1593
 
                                                         options, "window", 0));
1594
 
    if (!w)
1595
 
        return true;
1596
 
 
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)));
1606
 
 
1607
 
    w->constrainNewWindowSize (xwc.width,
1608
 
                               xwc.height,
1609
 
                               &xwc.width,
1610
 
                               &xwc.height);
1611
 
 
1612
 
 
1613
 
    if (xwc.width == w->serverWidth ())
1614
 
        mask &= ~CWWidth;
1615
 
 
1616
 
    if (xwc.height == w->serverHeight ())
1617
 
        mask &= ~CWHeight;
1618
 
 
1619
 
    if (w->mapNum () && (mask & (CWWidth | CWHeight)))
1620
 
        w->sendSyncRequest ();
1621
 
 
1622
 
    w->configureXWindow (mask, &xwc);
1623
 
 
1624
 
    toggleFunctions (true);
1625
 
 
1626
 
    return true;
1627
 
}
1628
 
 
1629
 
bool
1630
 
EZoomScreen::initiate (CompAction         *action,
1631
 
                      CompAction::State  state,
1632
 
                      CompOption::Vector options)
1633
 
{
1634
 
    zoomIn (action, state, options);
1635
 
 
1636
 
    if (state & CompAction::StateInitKey)
1637
 
        action->setState (action->state () | CompAction::StateTermKey);
1638
 
 
1639
 
    if (state & CompAction::StateInitButton)
1640
 
        action->setState (action->state () | CompAction::StateTermButton);
1641
 
 
1642
 
    toggleFunctions (true);
1643
 
 
1644
 
    return true;
1645
 
}
1646
 
 
1647
 
bool
1648
 
EZoomScreen::zoomOut (CompAction         *action,
1649
 
                     CompAction::State  state,
1650
 
                     CompOption::Vector options)
1651
 
{
1652
 
    int out = screen->outputDeviceForPoint (pointerX, pointerY);
1653
 
 
1654
 
    setScale (out,
1655
 
              zooms.at (out).newZoom *
1656
 
              optionGetZoomFactor ());
1657
 
 
1658
 
    toggleFunctions (true);
1659
 
 
1660
 
    return true;
1661
 
}
1662
 
 
1663
 
bool
1664
 
EZoomScreen::terminate (CompAction         *action,
1665
 
                       CompAction::State  state,
1666
 
                       CompOption::Vector options)
1667
 
{
1668
 
    int out;
1669
 
 
1670
 
    out = screen->outputDeviceForPoint (pointerX, pointerY);
1671
 
 
1672
 
    if (grabbed)
1673
 
    {
1674
 
        zooms.at (out).newZoom = 1.0f;
1675
 
        cScreen->damageScreen ();
1676
 
    }
1677
 
 
1678
 
    toggleFunctions (true);
1679
 
 
1680
 
    action->setState (action->state () & ~(CompAction::StateTermKey |
1681
 
                                           CompAction::StateTermButton));
1682
 
    return false;
1683
 
 
1684
 
}
1685
 
 
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.
1692
 
 * FIXME: Cleanup.
1693
 
 * TODO: Avoid maximized windows.
1694
 
 */
1695
 
void
1696
 
EZoomScreen::focusTrack (XEvent *event)
1697
 
{
1698
 
    int           out;
1699
 
    static Window lastMapped = 0;
1700
 
 
1701
 
    CompWindow    *w;
1702
 
 
1703
 
    if (event->type == MapNotify)
1704
 
    {
1705
 
        lastMapped = event->xmap.window;
1706
 
        return;
1707
 
    }
1708
 
    else if (event->type != FocusIn)
1709
 
        return;
1710
 
 
1711
 
    if ((event->xfocus.mode != NotifyNormal)
1712
 
        && (lastMapped != event->xfocus.window))
1713
 
        return;
1714
 
 
1715
 
    lastMapped = 0;
1716
 
    w = screen->findWindow (event->xfocus.window);
1717
 
    if (w == NULL || w->id () == screen->activeWindow ())
1718
 
        return;
1719
 
 
1720
 
    if (time(NULL) - lastChange < optionGetFollowFocusDelay () ||
1721
 
        !optionGetFollowFocus ())
1722
 
        return;
1723
 
 
1724
 
    out = screen->outputDeviceForGeometry (w->geometry ());
1725
 
    if (!isActive (out) &&
1726
 
        !optionGetAlwaysFocusFitWindow ())
1727
 
        return;
1728
 
    if (optionGetFocusFitWindow ())
1729
 
    {
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);
1736
 
    }
1737
 
 
1738
 
    areaToWindow (w);
1739
 
 
1740
 
    toggleFunctions (true);
1741
 
}
1742
 
 
1743
 
 
1744
 
/* Event handler. Pass focus-related events on and handle XFixes events. */
1745
 
void
1746
 
EZoomScreen::handleEvent (XEvent *event)
1747
 
{
1748
 
    XMotionEvent *mev;
1749
 
 
1750
 
    switch (event->type) {
1751
 
        case MotionNotify:
1752
 
            mev =  (XMotionEvent *) event;
1753
 
            if (grabIndex)
1754
 
            {
1755
 
                if (pointerX < clickPos.x ())
1756
 
                {
1757
 
                    box.setX (pointerX);
1758
 
                    box.setWidth (clickPos.x () - pointerX);
1759
 
                }
1760
 
                else
1761
 
                {
1762
 
                    box.setWidth (pointerX - clickPos.x ());
1763
 
                }
1764
 
 
1765
 
                if (pointerY < clickPos.y ())
1766
 
                {
1767
 
                    box.setY (pointerY);
1768
 
                    box.setHeight (clickPos.y () - pointerY);
1769
 
                }
1770
 
                else
1771
 
                {
1772
 
                    box.setHeight (pointerY - clickPos.y ());
1773
 
                }
1774
 
                cScreen->damageScreen ();
1775
 
            }
1776
 
            break;
1777
 
 
1778
 
        case FocusIn:
1779
 
        case MapNotify:
1780
 
            focusTrack (event);
1781
 
            break;
1782
 
        default:
1783
 
            if (event->type == fixesEventBase + XFixesCursorNotify)
1784
 
            {
1785
 
                //XFixesCursorNotifyEvent *cev = (XFixesCursorNotifyEvent *)
1786
 
                    //event;
1787
 
                    if (cursor.isSet)
1788
 
                        updateCursor (&cursor);
1789
 
            }
1790
 
            break;
1791
 
    }
1792
 
 
1793
 
    screen->handleEvent (event);
1794
 
}
1795
 
 
1796
 
/* TODO: Use this ctor carefully */
1797
 
 
1798
 
EZoomScreen::CursorTexture::CursorTexture () :
1799
 
    isSet (false)
1800
 
{
1801
 
}
1802
 
 
1803
 
void
1804
 
EZoomScreen::postLoad ()
1805
 
{
1806
 
    const CompPoint &m = pollHandle.getCurrentPosition ();
1807
 
    int         out = screen->outputDeviceForPoint (m.x (), m.y ());
1808
 
 
1809
 
    if (!grabbed)
1810
 
        return;
1811
 
 
1812
 
    toggleFunctions (true);
1813
 
 
1814
 
    if (!pollHandle.active ())
1815
 
        enableMousePolling ();
1816
 
 
1817
 
    foreach (ZoomArea &za, zooms)
1818
 
    {
1819
 
        grabbed |= (1 << za.output);
1820
 
    }
1821
 
 
1822
 
    cursorZoomActive (out);
1823
 
    updateCursor (&cursor);
1824
 
 
1825
 
    cScreen->damageScreen ();
1826
 
 
1827
 
}
1828
 
 
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)),
1834
 
    grabbed (0),
1835
 
    grabIndex (0),
1836
 
    lastChange (0),
1837
 
    cursorInfoSelected (false),
1838
 
    cursorHidden (false)
1839
 
{
1840
 
    ScreenInterface::setHandler (screen, false);
1841
 
    CompositeScreenInterface::setHandler (cScreen, false);
1842
 
    GLScreenInterface::setHandler (gScreen, false);
1843
 
 
1844
 
    int major, minor;
1845
 
    unsigned int n;
1846
 
    fixesSupported =
1847
 
        XFixesQueryExtension(screen->dpy (),
1848
 
                             &fixesEventBase,
1849
 
                             &fixesErrorBase);
1850
 
 
1851
 
    XFixesQueryVersion (screen->dpy (), &major, &minor);
1852
 
 
1853
 
    if (major >= 4)
1854
 
        canHideCursor = true;
1855
 
    else
1856
 
        canHideCursor = false;
1857
 
 
1858
 
    n = screen->outputDevs ().size ();
1859
 
 
1860
 
    for (unsigned int i = 0; i < n; i++)
1861
 
    {
1862
 
        /* zs->grabbed is a mask ... Thus this limit */
1863
 
        if (i > sizeof (long int) * 8)
1864
 
            break;
1865
 
        ZoomArea za (i);
1866
 
        zooms.push_back (za);
1867
 
    }
1868
 
 
1869
 
    pollHandle.setCallback (boost::bind (
1870
 
                                &EZoomScreen::updateMouseInterval, this, _1));
1871
 
 
1872
 
    optionSetZoomInButtonInitiate (boost::bind (&EZoomScreen::zoomIn, this, _1,
1873
 
                                                _2, _3));
1874
 
    optionSetZoomOutButtonInitiate (boost::bind (&EZoomScreen::zoomOut, this, _1,
1875
 
                                                 _2, _3));
1876
 
    optionSetZoomInKeyInitiate (boost::bind (&EZoomScreen::zoomIn, this, _1,
1877
 
                                                _2, _3));
1878
 
    optionSetZoomOutKeyInitiate (boost::bind (&EZoomScreen::zoomOut, this, _1,
1879
 
                                                _2, _3));
1880
 
 
1881
 
    optionSetZoomSpecific1KeyInitiate (boost::bind (&EZoomScreen::zoomSpecific,
1882
 
                                                    this, _1, _2, _3,
1883
 
                                                    optionGetZoomSpec1 ()));
1884
 
    optionSetZoomSpecific2KeyInitiate (boost::bind (&EZoomScreen::zoomSpecific,
1885
 
                                                    this, _1, _2, _3,
1886
 
                                                    optionGetZoomSpec2 ()));
1887
 
    optionSetZoomSpecific3KeyInitiate (boost::bind (&EZoomScreen::zoomSpecific,
1888
 
                                                    this, _1, _2, _3,
1889
 
                                                    optionGetZoomSpec3 ()));
1890
 
 
1891
 
    optionSetPanLeftKeyInitiate (boost::bind (&EZoomScreen::zoomPan, this, _1,
1892
 
                                              _2, _3, -1, 0));
1893
 
    optionSetPanRightKeyInitiate (boost::bind (&EZoomScreen::zoomPan, this, _1,
1894
 
                                                _2, _3, 1, 0));
1895
 
    optionSetPanUpKeyInitiate (boost::bind (&EZoomScreen::zoomPan, this, _1, _2,
1896
 
                                             _3, 0, -1));
1897
 
    optionSetPanDownKeyInitiate (boost::bind (&EZoomScreen::zoomPan, this, _1,
1898
 
                                               _2, _3, 0, 1));
1899
 
 
1900
 
    optionSetFitToWindowKeyInitiate (boost::bind (&EZoomScreen::zoomToWindow,
1901
 
                                                  this, _1, _2, _3));
1902
 
    optionSetCenterMouseKeyInitiate (boost::bind (&EZoomScreen::zoomCenterMouse,
1903
 
                                                  this, _1, _2, _3));
1904
 
    optionSetFitToZoomKeyInitiate (boost::bind (
1905
 
                                        &EZoomScreen::zoomFitWindowToZoom, this,
1906
 
                                        _1, _2, _3));
1907
 
 
1908
 
 
1909
 
    optionSetLockZoomKeyInitiate (boost::bind (&EZoomScreen::lockZoomAction,
1910
 
                                                this, _1, _2, _3));
1911
 
    optionSetZoomBoxButtonInitiate (boost::bind (&EZoomScreen::zoomBoxActivate,
1912
 
                                                 this, _1, _2, _3));
1913
 
    optionSetZoomBoxButtonTerminate (boost::bind (
1914
 
                                        &EZoomScreen::zoomBoxDeactivate, this,
1915
 
                                        _1, _2, _3));
1916
 
    optionSetSetZoomAreaInitiate (boost::bind (
1917
 
                                        &EZoomScreen::setZoomAreaAction, this,
1918
 
                                        _1, _2, _3));
1919
 
    optionSetEnsureVisibilityInitiate (boost::bind (
1920
 
                                        &EZoomScreen::ensureVisibilityAction, this,
1921
 
                                        _1, _2, _3));
1922
 
 
1923
 
}
1924
 
 
1925
 
EZoomScreen::~EZoomScreen ()
1926
 
{
1927
 
    writeSerializedData ();
1928
 
 
1929
 
    if (pollHandle.active ())
1930
 
        pollHandle.stop ();
1931
 
 
1932
 
    if (zooms.size ())
1933
 
        zooms.clear ();
1934
 
 
1935
 
    cScreen->damageScreen ();
1936
 
    cursorZoomInactive ();
1937
 
}
1938
 
 
1939
 
bool
1940
 
ZoomPluginVTable::init ()
1941
 
{
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))
1946
 
        return false;
1947
 
 
1948
 
    return true;
1949
 
}