~3v1n0/ubuntu/precise/compiz/scale-hotkeys-change

« back to all changes in this revision

Viewing changes to .pc/fix-863328.patch/plugins/scale/src/scale.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2011-10-06 17:57:36 UTC
  • Revision ID: james.westby@ubuntu.com-20111006175736-ra3xnpa8tyy3z7vn
Tags: 1:0.9.6+bzr20110929-0ubuntu4
* debian/control:
  - don't suggest nvidia-glx, it's part of the old initial packaging
    and probably a bad hint on non nvidia system (LP: #844218)
* Cherry-pick upstream patches:
  - Windows should not automatically be focused when opened if the focus
    is on another application (LP: #748840)
  - Launcher - If a spread contains minimised windows, when the spread
    exits, the minimised windows momentarily appear on the desktop
    before disappearing (LP: #863328)
  - reproducible stacking bug in compiz (LP: #869316)
  - Click-dragging a window that's stacked above a fullscreen window will
    cause it to go underneath the fullscreen window (LP: #869919)
  - sometimes the keyboard input doesn't go to the apparently focussed
    dialog (LP: #869967)
  - Opening mumble can cause it to be stacked above the dash if you
    open the dash at the same time (LP: #865863)
  - Sometimes configure events are missed and windows move slow as a result
    (LP: #866752)
  - Workaround ubuntu desktop unity. Mouse at the left side doesn't reveal
    launcher (LP: #832150)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2005 Novell, Inc.
 
3
 *
 
4
 * Permission to use, copy, modify, distribute, and sell this software
 
5
 * and its documentation for any purpose is hereby granted without
 
6
 * fee, provided that the above copyright notice appear in all copies
 
7
 * and that both that copyright notice and this permission notice
 
8
 * appear in supporting documentation, and that the name of
 
9
 * Novell, Inc. not be used in advertising or publicity pertaining to
 
10
 * distribution of the software without specific, written prior permission.
 
11
 * Novell, Inc. makes no representations about the suitability of this
 
12
 * software for any purpose. It is provided "as is" without express or
 
13
 * implied warranty.
 
14
 *
 
15
 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 
16
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
 
17
 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 
18
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 
19
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 
20
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 
21
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
22
 *
 
23
 * Author: David Reveman <davidr@novell.com>
 
24
 */
 
25
 
 
26
#include <stdio.h>
 
27
#include <stdlib.h>
 
28
#include <string.h>
 
29
#include <math.h>
 
30
#include <sys/time.h>
 
31
 
 
32
#include <X11/Xatom.h>
 
33
#include <X11/cursorfont.h>
 
34
 
 
35
#include <core/atoms.h>
 
36
#include <scale/scale.h>
 
37
#include "privates.h"
 
38
 
 
39
#define EDGE_STATE (CompAction::StateInitEdge)
 
40
 
 
41
class ScalePluginVTable :
 
42
    public CompPlugin::VTableForScreenAndWindow<ScaleScreen, ScaleWindow>
 
43
{
 
44
    public:
 
45
 
 
46
        bool init ();
 
47
        void fini ();
 
48
};
 
49
 
 
50
COMPIZ_PLUGIN_20090315 (scale, ScalePluginVTable)
 
51
 
 
52
bool
 
53
PrivateScaleWindow::isNeverScaleWin () const
 
54
{
 
55
    if (window->overrideRedirect ())
 
56
        return true;
 
57
 
 
58
    if (window->wmType () & (CompWindowTypeDockMask |
 
59
                             CompWindowTypeDesktopMask))
 
60
        return true;
 
61
 
 
62
    return false;
 
63
}
 
64
 
 
65
bool
 
66
PrivateScaleWindow::isScaleWin () const
 
67
{
 
68
    if (isNeverScaleWin ())
 
69
        return false;
 
70
 
 
71
    if (!spScreen->type || spScreen->type == ScaleTypeOutput)
 
72
    {
 
73
        if (!window->focus ())
 
74
            return false;
 
75
    }
 
76
 
 
77
    if (window->state () & CompWindowStateSkipPagerMask)
 
78
        return false;
 
79
 
 
80
    if (window->state () & CompWindowStateShadedMask)
 
81
        return false;
 
82
 
 
83
    if (!window->mapNum () || !window->isViewable ())
 
84
        return false;
 
85
 
 
86
    switch (sScreen->priv->type) {
 
87
        case ScaleTypeGroup:
 
88
            if (spScreen->clientLeader != window->clientLeader () &&
 
89
                spScreen->clientLeader != window->id ())
 
90
                return false;
 
91
            break;
 
92
        case ScaleTypeOutput:
 
93
            if ((unsigned int) window->outputDevice () !=
 
94
                               (unsigned int) screen->currentOutputDev ().id ())
 
95
                return false;
 
96
        default:
 
97
            break;
 
98
    }
 
99
 
 
100
    if (!spScreen->currentMatch.evaluate (window))
 
101
        return false;
 
102
 
 
103
    return true;
 
104
}
 
105
 
 
106
void
 
107
PrivateScaleScreen::activateEvent (bool activating)
 
108
{
 
109
    CompOption::Vector o (0);
 
110
 
 
111
    o.push_back (CompOption ("root", CompOption::TypeInt));
 
112
    o.push_back (CompOption ("active", CompOption::TypeBool));
 
113
 
 
114
    o[0].value ().set ((int) screen->root ());
 
115
    o[1].value ().set (activating);
 
116
 
 
117
    screen->handleCompizEvent ("scale", "activate", o);
 
118
}
 
119
 
 
120
void
 
121
ScaleWindowInterface::scalePaintDecoration (const GLWindowPaintAttrib& attrib,
 
122
                                            const GLMatrix&           transform,
 
123
                                            const CompRegion&         region,
 
124
                                            unsigned int              mask)
 
125
    WRAPABLE_DEF (scalePaintDecoration, attrib, transform, region, mask)
 
126
 
 
127
void
 
128
ScaleWindow::scalePaintDecoration (const GLWindowPaintAttrib& attrib,
 
129
                                   const GLMatrix&            transform,
 
130
                                   const CompRegion&          region,
 
131
                                   unsigned int               mask)
 
132
{
 
133
    WRAPABLE_HND_FUNC (0, scalePaintDecoration, attrib, transform, region, mask)
 
134
 
 
135
    if (priv->spScreen->optionGetOverlayIcon () != ScaleOptions::OverlayIconNone)
 
136
    {
 
137
        GLWindowPaintAttrib sAttrib (attrib);
 
138
        GLTexture           *icon;
 
139
 
 
140
        icon = priv->gWindow->getIcon (96, 96);
 
141
        if (!icon)
 
142
            icon = priv->spScreen->gScreen->defaultIcon ();
 
143
 
 
144
        if (icon)
 
145
        {
 
146
            float  scale;
 
147
            float  x, y;
 
148
            int    width, height;
 
149
            int    scaledWinWidth, scaledWinHeight;
 
150
 
 
151
            scaledWinWidth  = priv->window->width () * priv->scale;
 
152
            scaledWinHeight = priv->window->height () * priv->scale;
 
153
 
 
154
            switch (priv->spScreen->optionGetOverlayIcon ()) {
 
155
                case ScaleOptions::OverlayIconNone:
 
156
                case ScaleOptions::OverlayIconEmblem:
 
157
                    scale = 1.0f;
 
158
                    break;
 
159
                case ScaleOptions::OverlayIconBig:
 
160
                default:
 
161
                    sAttrib.opacity /= 3;
 
162
                    scale = MIN (((float) scaledWinWidth / icon->width ()),
 
163
                                 ((float) scaledWinHeight / icon->height ()));
 
164
                    break;
 
165
            }
 
166
 
 
167
            width  = icon->width () * scale;
 
168
            height = icon->height () * scale;
 
169
 
 
170
            switch (priv->spScreen->optionGetOverlayIcon ()) {
 
171
                case ScaleOptions::OverlayIconNone:
 
172
                case ScaleOptions::OverlayIconEmblem:
 
173
                    x = priv->window->x () + scaledWinWidth - icon->width ();
 
174
                    y = priv->window->y () + scaledWinHeight - icon->height ();
 
175
                    break;
 
176
                case ScaleOptions::OverlayIconBig:
 
177
                default:
 
178
                    x = priv->window->x () + scaledWinWidth / 2 - width / 2;
 
179
                    y = priv->window->y () + scaledWinHeight / 2 - height / 2;
 
180
                    break;
 
181
            }
 
182
 
 
183
            x += priv->tx;
 
184
            y += priv->ty;
 
185
 
 
186
            if (priv->slot)
 
187
            {
 
188
                priv->delta = fabs (priv->slot->x1 () - priv->window->x ()) +
 
189
                              fabs (priv->slot->y1 () - priv->window->y ()) +
 
190
                              fabs (1.0f - priv->slot->scale) * 500.0f;
 
191
            }
 
192
 
 
193
            if (priv->delta)
 
194
            {
 
195
                float o;
 
196
                float ds;
 
197
 
 
198
                ds = fabs (priv->tx) +
 
199
                     fabs (priv->ty) +
 
200
                     fabs (1.0f - priv->scale) * 500.0f;
 
201
 
 
202
                if (ds > priv->delta)
 
203
                    ds = priv->delta;
 
204
 
 
205
                o = ds / priv->delta;
 
206
 
 
207
                if (priv->slot)
 
208
                {
 
209
                    if (o < priv->lastThumbOpacity)
 
210
                        o = priv->lastThumbOpacity;
 
211
                }
 
212
                else
 
213
                {
 
214
                    if (o > priv->lastThumbOpacity)
 
215
                        o = 0.0f;
 
216
                }
 
217
 
 
218
                priv->lastThumbOpacity = o;
 
219
 
 
220
                sAttrib.opacity = sAttrib.opacity * o;
 
221
            }
 
222
 
 
223
            mask |= PAINT_WINDOW_BLEND_MASK;
 
224
 
 
225
            CompRegion            iconReg (0, 0, width, height);
 
226
            GLTexture::MatrixList ml (1);
 
227
 
 
228
            ml[0] = icon->matrix ();
 
229
            priv->gWindow->geometry ().reset ();
 
230
 
 
231
            if (width && height)
 
232
                priv->gWindow->glAddGeometry (ml, iconReg, iconReg);
 
233
 
 
234
            if (priv->gWindow->geometry ().vCount)
 
235
            {
 
236
                GLFragment::Attrib fragment (sAttrib);
 
237
                GLMatrix           wTransform (transform);
 
238
 
 
239
                wTransform.scale (scale, scale, 1.0f);
 
240
                wTransform.translate (x / scale, y / scale, 0.0f);
 
241
 
 
242
                glPushMatrix ();
 
243
                glLoadMatrixf (wTransform.getMatrix ());
 
244
 
 
245
                priv->gWindow->glDrawTexture (icon, fragment, mask);
 
246
 
 
247
                glPopMatrix ();
 
248
            }
 
249
        }
 
250
    }
 
251
}
 
252
 
 
253
bool
 
254
ScaleWindowInterface::setScaledPaintAttributes (GLWindowPaintAttrib& attrib)
 
255
    WRAPABLE_DEF (setScaledPaintAttributes, attrib)
 
256
 
 
257
bool
 
258
ScaleWindow::setScaledPaintAttributes (GLWindowPaintAttrib& attrib)
 
259
{
 
260
    WRAPABLE_HND_FUNC_RETURN (1, bool, setScaledPaintAttributes, attrib)
 
261
 
 
262
    bool drawScaled = false;
 
263
 
 
264
    if (priv->adjust || priv->slot)
 
265
    {
 
266
        if (priv->window->id ()     != priv->spScreen->selectedWindow &&
 
267
            priv->spScreen->opacity != OPAQUE                         &&
 
268
            priv->spScreen->state   != ScaleScreen::In)
 
269
        {
 
270
            /* modify opacity of windows that are not active */
 
271
            attrib.opacity = (attrib.opacity * priv->spScreen->opacity) >> 16;
 
272
        }
 
273
 
 
274
        drawScaled = true;
 
275
    }
 
276
    else if (priv->spScreen->state != ScaleScreen::In)
 
277
    {
 
278
        if (priv->spScreen->optionGetDarkenBack ())
 
279
        {
 
280
            /* modify brightness of the other windows */
 
281
            attrib.brightness = attrib.brightness / 2;
 
282
        }
 
283
 
 
284
        /* hide windows on the outputs used for scaling
 
285
           that are not in scale mode */
 
286
        if (!priv->isNeverScaleWin ())
 
287
        {
 
288
            int moMode, output;
 
289
 
 
290
            moMode = priv->spScreen->getMultioutputMode ();
 
291
 
 
292
            switch (moMode) {
 
293
                case ScaleOptions::MultioutputModeOnCurrentOutputDevice:
 
294
                    output = screen->currentOutputDev ().id ();
 
295
                    if (priv->window->outputDevice () == output)
 
296
                        attrib.opacity = 0;
 
297
                    break;
 
298
                default:
 
299
                    attrib.opacity = 0;
 
300
                    break;
 
301
            }
 
302
        }
 
303
    }
 
304
 
 
305
    return drawScaled;
 
306
}
 
307
 
 
308
bool
 
309
PrivateScaleWindow::glPaint (const GLWindowPaintAttrib& attrib,
 
310
                             const GLMatrix&            transform,
 
311
                             const CompRegion&          region,
 
312
                             unsigned int               mask)
 
313
{
 
314
    bool status;
 
315
 
 
316
    if (spScreen->state != ScaleScreen::Idle)
 
317
    {
 
318
        GLWindowPaintAttrib sAttrib (attrib);
 
319
        bool                scaled;
 
320
 
 
321
        scaled = sWindow->setScaledPaintAttributes (sAttrib);
 
322
 
 
323
        if (adjust || slot)
 
324
            mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
 
325
 
 
326
        status = gWindow->glPaint (sAttrib, transform, region, mask);
 
327
 
 
328
        if (scaled)
 
329
        {
 
330
            GLFragment::Attrib fragment (gWindow->lastPaintAttrib ());
 
331
            GLMatrix           wTransform (transform);
 
332
 
 
333
            if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
 
334
                return false;
 
335
 
 
336
            if (window->alpha () || fragment.getOpacity () != OPAQUE)
 
337
                mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
 
338
 
 
339
            wTransform.translate (window->x (), window->y (), 0.0f);
 
340
            wTransform.scale (scale, scale, 1.0f);
 
341
            wTransform.translate (tx / scale - window->x (),
 
342
                                  ty / scale - window->y (), 0.0f);
 
343
 
 
344
            glPushMatrix ();
 
345
            glLoadMatrixf (wTransform.getMatrix ());
 
346
 
 
347
            gWindow->glDraw (wTransform, fragment, region,
 
348
                             mask | PAINT_WINDOW_TRANSFORMED_MASK);
 
349
 
 
350
            glPopMatrix ();
 
351
 
 
352
            sWindow->scalePaintDecoration (sAttrib, transform, region, mask);
 
353
        }
 
354
    }
 
355
    else
 
356
    {
 
357
        status = gWindow->glPaint (attrib, transform, region, mask);
 
358
    }
 
359
 
 
360
    return status;
 
361
}
 
362
 
 
363
bool
 
364
PrivateScaleWindow::compareWindowsDistance (ScaleWindow *w1,
 
365
                                            ScaleWindow *w2)
 
366
{
 
367
    return w1->priv->distance < w2->priv->distance;
 
368
}
 
369
 
 
370
void
 
371
PrivateScaleScreen::layoutSlotsForArea (const CompRect& workArea,
 
372
                                        int             nWindows)
 
373
{
 
374
    int i, j;
 
375
    int x, y, width, height;
 
376
    int lines, n, nSlots;
 
377
    int spacing;
 
378
 
 
379
    if (!nWindows)
 
380
        return;
 
381
 
 
382
    lines   = sqrt (nWindows + 1);
 
383
    spacing = optionGetSpacing ();
 
384
    nSlots  = 0;
 
385
 
 
386
    y      = workArea.y () + spacing;
 
387
    height = (workArea.height () - (lines + 1) * spacing) / lines;
 
388
 
 
389
    for (i = 0; i < lines; i++)
 
390
    {
 
391
        n = MIN (nWindows - nSlots, ceilf ((float) nWindows / lines));
 
392
 
 
393
        x     = workArea.x () + spacing;
 
394
        width = (workArea.width () - (n + 1) * spacing) / n;
 
395
 
 
396
        for (j = 0; j < n; j++)
 
397
        {
 
398
            slots[this->nSlots].setGeometry (x, y, width, height);
 
399
 
 
400
            slots[this->nSlots].filled = false;
 
401
 
 
402
            x += width + spacing;
 
403
 
 
404
            this->nSlots++;
 
405
            nSlots++;
 
406
        }
 
407
 
 
408
        y += height + spacing;
 
409
    }
 
410
}
 
411
 
 
412
SlotArea::vector
 
413
PrivateScaleScreen::getSlotAreas ()
 
414
{
 
415
    unsigned int       i = 0;
 
416
    CompRect           workArea;
 
417
    std::vector<float> size;
 
418
    float              sizePerWindow, sum = 0.0f;
 
419
    int                left;
 
420
    SlotArea::vector   slotAreas;
 
421
 
 
422
    slotAreas.resize (screen->outputDevs ().size ());
 
423
    size.resize (screen->outputDevs ().size ());
 
424
 
 
425
    left = windows.size ();
 
426
 
 
427
    foreach (CompOutput &o, screen->outputDevs ())
 
428
    {
 
429
        /* determine the size of the workarea for each output device */
 
430
        workArea = CompRect (o.workArea ());
 
431
 
 
432
        size[i] = workArea.width () * workArea.height ();
 
433
        sum += size[i];
 
434
 
 
435
        slotAreas[i].nWindows = 0;
 
436
        slotAreas[i].workArea = workArea;
 
437
 
 
438
        i++;
 
439
    }
 
440
 
 
441
    /* calculate size available for each window */
 
442
    sizePerWindow = sum / windows.size ();
 
443
 
 
444
    for (i = 0; i < screen->outputDevs ().size () && left; i++)
 
445
    {
 
446
        /* fill the areas with windows */
 
447
        int nw = floor (size[i] / sizePerWindow);
 
448
 
 
449
        nw = MIN (nw, left);
 
450
        size[i] -= nw * sizePerWindow;
 
451
        slotAreas[i].nWindows = nw;
 
452
        left -= nw;
 
453
    }
 
454
 
 
455
    /* add left windows to output devices with the biggest free space */
 
456
    while (left > 0)
 
457
    {
 
458
        int   num = 0;
 
459
        float big = 0;
 
460
 
 
461
        for (i = 0; i < screen->outputDevs ().size (); i++)
 
462
        {
 
463
            if (size[i] > big)
 
464
            {
 
465
                num = i;
 
466
                big = size[i];
 
467
            }
 
468
        }
 
469
 
 
470
        size[num] -= sizePerWindow;
 
471
        slotAreas[num].nWindows++;
 
472
        left--;
 
473
    }
 
474
 
 
475
    return slotAreas;
 
476
}
 
477
 
 
478
void
 
479
PrivateScaleScreen::layoutSlots ()
 
480
{
 
481
    int moMode;
 
482
 
 
483
    moMode  = getMultioutputMode ();
 
484
 
 
485
    /* if we have only one head, we don't need the
 
486
       additional effort of the all outputs mode */
 
487
    if (screen->outputDevs ().size () == 1)
 
488
        moMode = ScaleOptions::MultioutputModeOnCurrentOutputDevice;
 
489
 
 
490
    nSlots = 0;
 
491
 
 
492
    switch (moMode)
 
493
    {
 
494
        case ScaleOptions::MultioutputModeOnAllOutputDevices:
 
495
            {
 
496
                SlotArea::vector slotAreas = getSlotAreas ();
 
497
                if (slotAreas.size ())
 
498
                {
 
499
                    foreach (SlotArea &sa, slotAreas)
 
500
                        layoutSlotsForArea (sa.workArea, sa.nWindows);
 
501
                }
 
502
            }
 
503
            break;
 
504
        case ScaleOptions::MultioutputModeOnCurrentOutputDevice:
 
505
        default:
 
506
            {
 
507
                CompRect workArea (screen->currentOutputDev ().workArea ());
 
508
                layoutSlotsForArea (workArea, windows.size ());
 
509
            }
 
510
            break;
 
511
    }
 
512
}
 
513
 
 
514
void
 
515
PrivateScaleScreen::findBestSlots ()
 
516
{
 
517
    CompWindow *w;
 
518
    int        i, d, d0 = 0;
 
519
    float      sx, sy, cx, cy;
 
520
 
 
521
    foreach (ScaleWindow *sw, windows)
 
522
    {
 
523
        w = sw->priv->window;
 
524
 
 
525
        if (sw->priv->slot)
 
526
            continue;
 
527
 
 
528
        sw->priv->sid      = 0;
 
529
        sw->priv->distance = MAXSHORT;
 
530
 
 
531
        for (i = 0; i < nSlots; i++)
 
532
        {
 
533
            if (!slots[i].filled)
 
534
            {
 
535
                sx = (slots[i].x2 () + slots[i].x1 ()) / 2;
 
536
                sy = (slots[i].y2 () + slots[i].y1 ()) / 2;
 
537
 
 
538
                cx = w->serverX () + w->width () / 2;
 
539
                cy = w->serverY () + w->height () / 2;
 
540
 
 
541
                cx -= sx;
 
542
                cy -= sy;
 
543
 
 
544
                d = sqrt (cx * cx + cy * cy);
 
545
                if (d0 + d < sw->priv->distance)
 
546
                {
 
547
                    sw->priv->sid      = i;
 
548
                    sw->priv->distance = d0 + d;
 
549
                }
 
550
            }
 
551
        }
 
552
 
 
553
        d0 += sw->priv->distance;
 
554
    }
 
555
}
 
556
 
 
557
bool
 
558
PrivateScaleScreen::fillInWindows ()
 
559
{
 
560
    CompWindow *w;
 
561
    int        width, height;
 
562
    float      sx, sy, cx, cy;
 
563
 
 
564
    foreach (ScaleWindow *sw, windows)
 
565
    {
 
566
        w = sw->priv->window;
 
567
 
 
568
        if (!sw->priv->slot)
 
569
        {
 
570
            if (slots[sw->priv->sid].filled)
 
571
                return true;
 
572
 
 
573
            sw->priv->slot = &slots[sw->priv->sid];
 
574
 
 
575
            /* Auxilary items reparented into windows are clickable so we want to care about
 
576
             * them when calculating the slot size */
 
577
 
 
578
            width  = w->width ()  + w->input ().left + w->input ().right;
 
579
            height = w->height () + w->input ().top  + w->input ().bottom;
 
580
 
 
581
            sx = (float) (sw->priv->slot->x2 () - sw->priv->slot->x1 ()) / width;
 
582
            sy = (float) (sw->priv->slot->y2 () - sw->priv->slot->y1 ()) / height;
 
583
 
 
584
            sw->priv->slot->scale = MIN (MIN (sx, sy), 1.0f);
 
585
 
 
586
            sx = width  * sw->priv->slot->scale;
 
587
            sy = height * sw->priv->slot->scale;
 
588
            cx = (sw->priv->slot->x1 () + sw->priv->slot->x2 ()) / 2;
 
589
            cy = (sw->priv->slot->y1 () + sw->priv->slot->y2 ()) / 2;
 
590
 
 
591
            cx += w->input ().left * sw->priv->slot->scale;
 
592
            cy += w->input ().top  * sw->priv->slot->scale;
 
593
 
 
594
            sw->priv->slot->setGeometry (cx - sx / 2, cy - sy / 2, sx, sy);
 
595
 
 
596
            sw->priv->slot->filled = true;
 
597
 
 
598
            sw->priv->lastThumbOpacity = 0.0f;
 
599
 
 
600
            sw->priv->adjust = true;
 
601
        }
 
602
    }
 
603
 
 
604
    return false;
 
605
}
 
606
 
 
607
bool
 
608
ScaleScreenInterface::layoutSlotsAndAssignWindows ()
 
609
    WRAPABLE_DEF (layoutSlotsAndAssignWindows)
 
610
 
 
611
bool
 
612
ScaleScreen::layoutSlotsAndAssignWindows ()
 
613
{
 
614
    WRAPABLE_HND_FUNC_RETURN (0, bool, layoutSlotsAndAssignWindows)
 
615
 
 
616
    /* create a grid of slots */
 
617
    priv->layoutSlots ();
 
618
 
 
619
    do
 
620
    {
 
621
        /* find most appropriate slots for windows */
 
622
        priv->findBestSlots ();
 
623
 
 
624
        /* sort windows, window with closest distance to a slot first */
 
625
        priv->windows.sort (PrivateScaleWindow::compareWindowsDistance);
 
626
    } while (priv->fillInWindows ());
 
627
 
 
628
    return true;
 
629
}
 
630
 
 
631
bool
 
632
ScaleScreen::hasGrab () const
 
633
{
 
634
    return priv->grab;
 
635
}
 
636
 
 
637
ScaleScreen::State
 
638
ScaleScreen::getState () const
 
639
{
 
640
    return priv->state;
 
641
}
 
642
 
 
643
ScaleType
 
644
ScaleScreen::getType () const
 
645
{
 
646
    return priv->type;
 
647
}
 
648
 
 
649
const CompMatch&
 
650
ScaleScreen::getCustomMatch () const
 
651
{
 
652
    return priv->match;
 
653
}
 
654
 
 
655
const ScaleScreen::WindowList&
 
656
ScaleScreen::getWindows () const
 
657
{
 
658
    return priv->windows;
 
659
}
 
660
 
 
661
bool
 
662
PrivateScaleScreen::layoutThumbs ()
 
663
{
 
664
    windows.clear ();
 
665
 
 
666
    /* add windows scale list, top most window first */
 
667
    foreach (CompWindow *w, screen->windows ())
 
668
    {
 
669
        SCALE_WINDOW (w);
 
670
 
 
671
        if (sw->priv->slot)
 
672
            sw->priv->adjust = true;
 
673
 
 
674
        sw->priv->slot = NULL;
 
675
 
 
676
        if (!sw->priv->isScaleWin ())
 
677
            continue;
 
678
 
 
679
        windows.push_back (sw);
 
680
    }
 
681
 
 
682
    if (windows.empty ())
 
683
        return false;
 
684
 
 
685
    slots.resize (windows.size ());
 
686
 
 
687
    return ScaleScreen::get (screen)->layoutSlotsAndAssignWindows ();
 
688
}
 
689
 
 
690
bool
 
691
PrivateScaleWindow::adjustScaleVelocity ()
 
692
{
 
693
    float dx, dy, ds, adjust, amount;
 
694
    float x1, y1, scale;
 
695
 
 
696
    if (slot)
 
697
    {
 
698
        x1 = slot->x1 ();
 
699
        y1 = slot->y1 ();
 
700
        scale = slot->scale;
 
701
    }
 
702
    else
 
703
    {
 
704
        x1 = window->x ();
 
705
        y1 = window->y ();
 
706
        scale = 1.0f;
 
707
    }
 
708
 
 
709
    dx = x1 - (window->x () + tx);
 
710
 
 
711
    adjust = dx * 0.15f;
 
712
    amount = fabs (dx) * 1.5f;
 
713
    if (amount < 0.5f)
 
714
        amount = 0.5f;
 
715
    else if (amount > 5.0f)
 
716
        amount = 5.0f;
 
717
 
 
718
    xVelocity = (amount * xVelocity + adjust) / (amount + 1.0f);
 
719
 
 
720
    dy = y1 - (window->y () + ty);
 
721
 
 
722
    adjust = dy * 0.15f;
 
723
    amount = fabs (dy) * 1.5f;
 
724
    if (amount < 0.5f)
 
725
        amount = 0.5f;
 
726
    else if (amount > 5.0f)
 
727
        amount = 5.0f;
 
728
 
 
729
    yVelocity = (amount * yVelocity + adjust) / (amount + 1.0f);
 
730
 
 
731
    ds = scale - this->scale;
 
732
 
 
733
    adjust = ds * 0.1f;
 
734
    amount = fabs (ds) * 7.0f;
 
735
    if (amount < 0.01f)
 
736
        amount = 0.01f;
 
737
    else if (amount > 0.15f)
 
738
        amount = 0.15f;
 
739
 
 
740
    scaleVelocity = (amount * scaleVelocity + adjust) / (amount + 1.0f);
 
741
 
 
742
    if (fabs (dx) < 0.1f && fabs (xVelocity) < 0.2f &&
 
743
        fabs (dy) < 0.1f && fabs (yVelocity) < 0.2f &&
 
744
        fabs (ds) < 0.001f && fabs (scaleVelocity) < 0.002f)
 
745
    {
 
746
        xVelocity = yVelocity = scaleVelocity = 0.0f;
 
747
        tx = x1 - window->x ();
 
748
        ty = y1 - window->y ();
 
749
        this->scale = scale;
 
750
 
 
751
        return false;
 
752
    }
 
753
 
 
754
    return true;
 
755
}
 
756
 
 
757
bool
 
758
PrivateScaleScreen::glPaintOutput (const GLScreenPaintAttrib& sAttrib,
 
759
                                   const GLMatrix&            transform,
 
760
                                   const CompRegion&          region,
 
761
                                   CompOutput                 *output,
 
762
                                   unsigned int               mask)
 
763
{
 
764
    if (state != ScaleScreen::Idle)
 
765
        mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
 
766
 
 
767
    return gScreen->glPaintOutput (sAttrib, transform, region, output, mask);
 
768
}
 
769
 
 
770
void
 
771
PrivateScaleScreen::preparePaint (int msSinceLastPaint)
 
772
{
 
773
    if (state != ScaleScreen::Idle && state != ScaleScreen::Wait)
 
774
    {
 
775
        int   steps;
 
776
        float amount, chunk;
 
777
 
 
778
        amount = msSinceLastPaint * 0.05f * optionGetSpeed ();
 
779
        steps  = amount / (0.5f * optionGetTimestep ());
 
780
 
 
781
        if (!steps)
 
782
            steps = 1;
 
783
        chunk = amount / (float) steps;
 
784
 
 
785
        while (steps--)
 
786
        {
 
787
            moreAdjust = 0;
 
788
 
 
789
            foreach (CompWindow *w, screen->windows ())
 
790
            {
 
791
                SCALE_WINDOW (w);
 
792
 
 
793
                if (sw->priv->adjust)
 
794
                {
 
795
                    sw->priv->adjust = sw->priv->adjustScaleVelocity ();
 
796
 
 
797
                    moreAdjust |= sw->priv->adjust;
 
798
 
 
799
                    sw->priv->tx += sw->priv->xVelocity * chunk;
 
800
                    sw->priv->ty += sw->priv->yVelocity * chunk;
 
801
                    sw->priv->scale += sw->priv->scaleVelocity * chunk;
 
802
                }
 
803
            }
 
804
 
 
805
            if (!moreAdjust)
 
806
                break;
 
807
        }
 
808
    }
 
809
 
 
810
    cScreen->preparePaint (msSinceLastPaint);
 
811
}
 
812
 
 
813
void
 
814
PrivateScaleScreen::donePaint ()
 
815
{
 
816
    if (state != ScaleScreen::Idle)
 
817
    {
 
818
        if (moreAdjust)
 
819
        {
 
820
            cScreen->damageScreen ();
 
821
        }
 
822
        else
 
823
        {
 
824
            if (state == ScaleScreen::In)
 
825
            {
 
826
                /* The false activate event is sent when scale state
 
827
                   goes back to normal, to avoid animation conflicts
 
828
                   with other plugins. */
 
829
                activateEvent (false);
 
830
                state = ScaleScreen::Idle;
 
831
 
 
832
                cScreen->preparePaintSetEnabled (this, false);
 
833
                cScreen->donePaintSetEnabled (this, false);
 
834
                gScreen->glPaintOutputSetEnabled (this, false);
 
835
 
 
836
                foreach (CompWindow *w, screen->windows ())
 
837
                {
 
838
                    SCALE_WINDOW (w);
 
839
                    sw->priv->cWindow->damageRectSetEnabled (sw->priv, false);
 
840
                    sw->priv->gWindow->glPaintSetEnabled (sw->priv, false);
 
841
                }
 
842
            }
 
843
            else if (state == ScaleScreen::Out)
 
844
                state = ScaleScreen::Wait;
 
845
        }
 
846
    }
 
847
 
 
848
    cScreen->donePaint ();
 
849
}
 
850
 
 
851
ScaleWindow *
 
852
PrivateScaleScreen::checkForWindowAt (int x, int y)
 
853
{
 
854
    int                              x1, y1, x2, y2;
 
855
    CompWindowList::reverse_iterator rit = screen->windows ().rbegin ();
 
856
 
 
857
    for (; rit != screen->windows ().rend (); rit++)
 
858
    {
 
859
        CompWindow *w = *rit;
 
860
        SCALE_WINDOW (w);
 
861
 
 
862
        if (sw->priv->slot)
 
863
        {
 
864
            x1 = w->x () - w->input ().left * sw->priv->scale;
 
865
            y1 = w->y () - w->input ().top  * sw->priv->scale;
 
866
            x2 = w->x () +
 
867
                 (w->width () + w->input ().right) * sw->priv->scale;
 
868
            y2 = w->y () +
 
869
                 (w->height () + w->input ().bottom) * sw->priv->scale;
 
870
 
 
871
            x1 += sw->priv->tx;
 
872
            y1 += sw->priv->ty;
 
873
            x2 += sw->priv->tx;
 
874
            y2 += sw->priv->ty;
 
875
 
 
876
            if (x1 <= x && y1 <= y && x2 > x && y2 > y)
 
877
                return sw;
 
878
        }
 
879
    }
 
880
 
 
881
    return NULL;
 
882
}
 
883
 
 
884
void
 
885
PrivateScaleScreen::sendDndStatusMessage (Window source)
 
886
{
 
887
    XEvent xev;
 
888
 
 
889
    xev.xclient.type    = ClientMessage;
 
890
    xev.xclient.display = screen->dpy ();
 
891
    xev.xclient.format  = 32;
 
892
 
 
893
    xev.xclient.message_type = Atoms::xdndStatus;
 
894
    xev.xclient.window       = source;
 
895
 
 
896
    xev.xclient.data.l[0] = dndTarget;
 
897
    xev.xclient.data.l[1] = 2;
 
898
    xev.xclient.data.l[2] = 0;
 
899
    xev.xclient.data.l[3] = 0;
 
900
    xev.xclient.data.l[4] = None;
 
901
 
 
902
    XSendEvent (screen->dpy (), source, false, 0, &xev);
 
903
}
 
904
 
 
905
bool
 
906
PrivateScaleScreen::scaleTerminate (CompAction         *action,
 
907
                                    CompAction::State  state,
 
908
                                    CompOption::Vector &options)
 
909
{
 
910
    SCALE_SCREEN (screen);
 
911
 
 
912
    Window xid;
 
913
 
 
914
    if (ss->priv->actionShouldToggle (action, state))
 
915
        return false;
 
916
 
 
917
    xid = CompOption::getIntOptionNamed (options, "root");
 
918
    if (xid && ::screen->root () != xid)
 
919
        return false;
 
920
 
 
921
    if (!ss->priv->grab)
 
922
        return false;
 
923
 
 
924
    if (ss->priv->grabIndex)
 
925
    {
 
926
        ::screen->removeGrab (ss->priv->grabIndex, 0);
 
927
        ss->priv->grabIndex = 0;
 
928
    }
 
929
 
 
930
    if (ss->priv->dndTarget)
 
931
        XUnmapWindow (::screen->dpy (), ss->priv->dndTarget);
 
932
 
 
933
    ss->priv->grab = false;
 
934
 
 
935
    if (ss->priv->state != ScaleScreen::Idle)
 
936
    {
 
937
        foreach (CompWindow *w, ::screen->windows ())
 
938
        {
 
939
            SCALE_WINDOW (w);
 
940
 
 
941
            if (sw->priv->slot)
 
942
            {
 
943
                sw->priv->slot   = NULL;
 
944
                sw->priv->adjust = true;
 
945
            }
 
946
        }
 
947
 
 
948
        if (state & CompAction::StateCancel)
 
949
        {
 
950
            if (::screen->activeWindow () != ss->priv->previousActiveWindow)
 
951
            {
 
952
                CompWindow *w;
 
953
 
 
954
                w = ::screen->findWindow (ss->priv->previousActiveWindow);
 
955
                if (w)
 
956
                    w->moveInputFocusTo ();
 
957
            }
 
958
        }
 
959
        else if (ss->priv->state != ScaleScreen::In)
 
960
        {
 
961
            CompWindow *w = ::screen->findWindow (ss->priv->selectedWindow);
 
962
            if (w)
 
963
                w->activate ();
 
964
        }
 
965
 
 
966
        ss->priv->state = ScaleScreen::In;
 
967
        ss->priv->cScreen->damageScreen ();
 
968
    }
 
969
 
 
970
    if (state & CompAction::StateInitKey)
 
971
        action->setState (action->state () | CompAction::StateTermKey);
 
972
 
 
973
    ss->priv->lastActiveNum = 0;
 
974
 
 
975
    return false;
 
976
}
 
977
 
 
978
bool
 
979
PrivateScaleScreen::ensureDndRedirectWindow ()
 
980
{
 
981
    if (!dndTarget)
 
982
    {
 
983
        XSetWindowAttributes attr;
 
984
        long                 xdndVersion = 3;
 
985
 
 
986
        attr.override_redirect = true;
 
987
 
 
988
        dndTarget = XCreateWindow (screen->dpy (), screen->root (),
 
989
                                   0, 0, 1, 1, 0, CopyFromParent,
 
990
                                   InputOnly, CopyFromParent,
 
991
                                   CWOverrideRedirect, &attr);
 
992
 
 
993
        XChangeProperty (screen->dpy (), dndTarget,
 
994
                         Atoms::xdndAware,
 
995
                         XA_ATOM, 32, PropModeReplace,
 
996
                         (unsigned char *) &xdndVersion, 1);
 
997
    }
 
998
 
 
999
    XMoveResizeWindow (screen->dpy (), dndTarget,
 
1000
                       0, 0, screen->width (), screen->height ());
 
1001
    XMapRaised (screen->dpy (), dndTarget);
 
1002
 
 
1003
    return true;
 
1004
}
 
1005
 
 
1006
bool
 
1007
PrivateScaleScreen::actionShouldToggle (CompAction        *action,
 
1008
                                        CompAction::State state)
 
1009
{
 
1010
    if (state & EDGE_STATE)
 
1011
        return TRUE;
 
1012
 
 
1013
    if (state & (CompAction::StateInitKey | CompAction::StateTermKey))
 
1014
    {
 
1015
        if (optionGetKeyBindingsToggle ())
 
1016
            return TRUE;
 
1017
        else if (!action->key ().modifiers ())
 
1018
            return TRUE;
 
1019
    }
 
1020
 
 
1021
    if (state & (CompAction::StateInitButton | CompAction::StateTermButton))
 
1022
        if (optionGetButtonBindingsToggle ())
 
1023
            return TRUE;
 
1024
 
 
1025
    return FALSE;
 
1026
}
 
1027
 
 
1028
bool
 
1029
PrivateScaleScreen::scaleInitiate (CompAction         *action,
 
1030
                                   CompAction::State  state,
 
1031
                                   CompOption::Vector &options,
 
1032
                                   ScaleType          type)
 
1033
{
 
1034
    Window     xid;
 
1035
 
 
1036
    xid = CompOption::getIntOptionNamed (options, "root");
 
1037
 
 
1038
    if (::screen->root () == xid)
 
1039
    {
 
1040
        SCALE_SCREEN (::screen);
 
1041
 
 
1042
        if (ss->priv->actionShouldToggle (action, state) &&
 
1043
            (ss->priv->state == ScaleScreen::Wait ||
 
1044
             ss->priv->state == ScaleScreen::Out))
 
1045
        {
 
1046
            if (ss->priv->type == type)
 
1047
                return scaleTerminate (action,
 
1048
                                       CompAction::StateCancel,
 
1049
                                       options);
 
1050
        }
 
1051
        else
 
1052
        {
 
1053
            ss->priv->type = type;
 
1054
            return ss->priv->scaleInitiateCommon (action, state, options);
 
1055
        }
 
1056
    }
 
1057
 
 
1058
    return false;
 
1059
}
 
1060
 
 
1061
bool
 
1062
PrivateScaleScreen::scaleInitiateCommon (CompAction         *action,
 
1063
                                         CompAction::State  state,
 
1064
                                         CompOption::Vector &options)
 
1065
{
 
1066
    if (screen->otherGrabExist ("scale", NULL))
 
1067
        return false;
 
1068
 
 
1069
    match = CompOption::getMatchOptionNamed (options, "match",
 
1070
                                             CompMatch::emptyMatch);
 
1071
    if (match.isEmpty ())
 
1072
        match = optionGetWindowMatch ();
 
1073
 
 
1074
    currentMatch = match;
 
1075
 
 
1076
    if (!layoutThumbs ())
 
1077
        return false;
 
1078
 
 
1079
    if (state & CompAction::StateInitEdgeDnd)
 
1080
    {
 
1081
        if (ensureDndRedirectWindow ())
 
1082
            grab = true;
 
1083
    }
 
1084
    else if (!grabIndex)
 
1085
    {
 
1086
        grabIndex = screen->pushGrab (cursor, "scale");
 
1087
        if (grabIndex)
 
1088
            grab = true;
 
1089
    }
 
1090
 
 
1091
    if (grab)
 
1092
    {
 
1093
        if (!lastActiveNum)
 
1094
            lastActiveNum = screen->activeNum () - 1;
 
1095
 
 
1096
        previousActiveWindow = screen->activeWindow ();
 
1097
        lastActiveWindow     = screen->activeWindow ();
 
1098
        selectedWindow       = screen->activeWindow ();
 
1099
        hoveredWindow        = None;
 
1100
 
 
1101
        this->state = ScaleScreen::Out;
 
1102
 
 
1103
        activateEvent (true);
 
1104
 
 
1105
        cScreen->damageScreen ();
 
1106
 
 
1107
        cScreen->preparePaintSetEnabled (this, true);
 
1108
        cScreen->donePaintSetEnabled (this, true);
 
1109
        gScreen->glPaintOutputSetEnabled (this, true);
 
1110
 
 
1111
        foreach (CompWindow *w, screen->windows ())
 
1112
        {
 
1113
            SCALE_WINDOW (w);
 
1114
            sw->priv->cWindow->damageRectSetEnabled (sw->priv, true);
 
1115
            sw->priv->gWindow->glPaintSetEnabled (sw->priv, true);
 
1116
        }
 
1117
    }
 
1118
 
 
1119
    if ((state & (CompAction::StateInitButton | EDGE_STATE)) ==
 
1120
        CompAction::StateInitButton)
 
1121
    {
 
1122
        action->setState (action->state () | CompAction::StateTermButton);
 
1123
    }
 
1124
 
 
1125
    if (state & CompAction::StateInitKey)
 
1126
        action->setState (action->state () | CompAction::StateTermKey);
 
1127
 
 
1128
    return false;
 
1129
}
 
1130
 
 
1131
void
 
1132
ScaleWindowInterface::scaleSelectWindow ()
 
1133
    WRAPABLE_DEF (scaleSelectWindow)
 
1134
 
 
1135
void
 
1136
ScaleWindow::scaleSelectWindow ()
 
1137
{
 
1138
    WRAPABLE_HND_FUNC (2, scaleSelectWindow)
 
1139
 
 
1140
    if (priv->spScreen->selectedWindow != priv->window->id ())
 
1141
    {
 
1142
        CompWindow *oldW, *newW;
 
1143
 
 
1144
        oldW = screen->findWindow (priv->spScreen->selectedWindow);
 
1145
        newW = screen->findWindow (priv->window->id ());
 
1146
 
 
1147
        priv->spScreen->selectedWindow = priv->window->id ();
 
1148
 
 
1149
        if (oldW)
 
1150
            CompositeWindow::get (oldW)->addDamage ();
 
1151
 
 
1152
        if (newW)
 
1153
            CompositeWindow::get (newW)->addDamage ();
 
1154
    }
 
1155
}
 
1156
 
 
1157
bool
 
1158
ScaleWindow::hasSlot () const
 
1159
{
 
1160
    return priv->slot != NULL;
 
1161
}
 
1162
 
 
1163
ScaleSlot
 
1164
ScaleWindow::getSlot () const
 
1165
{
 
1166
    if (!priv->slot)
 
1167
    {
 
1168
        ScaleSlot empty;
 
1169
        return empty;
 
1170
    }
 
1171
 
 
1172
    return *priv->slot;
 
1173
}
 
1174
 
 
1175
void
 
1176
ScaleWindow::setSlot (const ScaleSlot &newSlot)
 
1177
{
 
1178
    SCALE_SCREEN (screen);
 
1179
 
 
1180
    priv->adjust = true;
 
1181
 
 
1182
    if (!priv->slot)
 
1183
        priv->slot = new ScaleSlot ();
 
1184
    *priv->slot = newSlot;
 
1185
 
 
1186
    /* Trigger the animation to this point */
 
1187
 
 
1188
    if (ss->priv->state == ScaleScreen::Wait)
 
1189
        ss->priv->state = ScaleScreen::Out;
 
1190
    else if (ss->priv->state == ScaleScreen::Idle)
 
1191
        ss->priv->state = ScaleScreen::In;
 
1192
 
 
1193
    priv->cWindow->addDamage ();
 
1194
}
 
1195
 
 
1196
ScalePosition
 
1197
ScaleWindow::getCurrentPosition () const
 
1198
{
 
1199
    ScalePosition pos;
 
1200
 
 
1201
    pos.setX (priv->tx);
 
1202
    pos.setY (priv->ty);
 
1203
 
 
1204
    pos.scale = priv->scale;
 
1205
 
 
1206
    return pos;
 
1207
}
 
1208
 
 
1209
void
 
1210
ScaleWindow::setCurrentPosition (const ScalePosition &newPos)
 
1211
{
 
1212
    SCALE_SCREEN (screen);
 
1213
 
 
1214
    priv->tx = newPos.x ();
 
1215
    priv->ty = newPos.y ();
 
1216
    priv->scale = newPos.scale;
 
1217
 
 
1218
    /* Trigger the animation to this point */
 
1219
 
 
1220
    if (ss->priv->state == ScaleScreen::Wait)
 
1221
        ss->priv->state = ScaleScreen::Out;
 
1222
    else if (ss->priv->state == ScaleScreen::Idle)
 
1223
        ss->priv->state = ScaleScreen::In;
 
1224
 
 
1225
    priv->cWindow->addDamage ();
 
1226
 
 
1227
    priv->adjust = true;
 
1228
}
 
1229
 
 
1230
const Window &
 
1231
ScaleScreen::getHoveredWindow ()
 
1232
{
 
1233
    return priv->hoveredWindow;
 
1234
}
 
1235
 
 
1236
bool
 
1237
PrivateScaleScreen::selectWindowAt (int  x,
 
1238
                                    int  y,
 
1239
                                    bool moveInputFocus)
 
1240
{
 
1241
    ScaleWindow *w = checkForWindowAt (x, y);
 
1242
    if (w && w->priv->isScaleWin ())
 
1243
    {
 
1244
        w->scaleSelectWindow ();
 
1245
 
 
1246
        if (moveInputFocus)
 
1247
        {
 
1248
            lastActiveNum    = w->priv->window->activeNum ();
 
1249
            lastActiveWindow = w->priv->window->id ();
 
1250
 
 
1251
            w->priv->window->moveInputFocusTo ();
 
1252
        }
 
1253
 
 
1254
        hoveredWindow = w->priv->window->id ();
 
1255
 
 
1256
        return true;
 
1257
    }
 
1258
 
 
1259
    hoveredWindow = None;
 
1260
 
 
1261
    return false;
 
1262
}
 
1263
 
 
1264
void
 
1265
PrivateScaleScreen::moveFocusWindow (int dx,
 
1266
                                     int dy)
 
1267
{
 
1268
    CompWindow *active;
 
1269
    CompWindow *focus = NULL;
 
1270
 
 
1271
    active = screen->findWindow (screen->activeWindow ());
 
1272
    if (active)
 
1273
    {
 
1274
        SCALE_WINDOW (active);
 
1275
 
 
1276
        if (sw->priv->slot)
 
1277
        {
 
1278
            ScaleSlot  *slot;
 
1279
            int        x, y, cx, cy, d, min = MAXSHORT;
 
1280
 
 
1281
            cx = (sw->priv->slot->x1 () + sw->priv->slot->x2 ()) / 2;
 
1282
            cy = (sw->priv->slot->y1 () + sw->priv->slot->y2 ()) / 2;
 
1283
 
 
1284
            foreach (CompWindow *w, screen->windows ())
 
1285
            {
 
1286
                slot = ScaleWindow::get (w)->priv->slot;
 
1287
                if (!slot)
 
1288
                    continue;
 
1289
 
 
1290
                x = (slot->x1 () + slot->x2 ()) / 2;
 
1291
                y = (slot->y1 () + slot->y2 ()) / 2;
 
1292
 
 
1293
                d = abs (x - cx) + abs (y - cy);
 
1294
                if (d < min)
 
1295
                {
 
1296
                    if ((dx > 0 && slot->x1 () < sw->priv->slot->x2 ()) ||
 
1297
                        (dx < 0 && slot->x2 () > sw->priv->slot->x1 ()) ||
 
1298
                        (dy > 0 && slot->y1 () < sw->priv->slot->y2 ()) ||
 
1299
                        (dy < 0 && slot->y2 () > sw->priv->slot->y1 ()))
 
1300
                        continue;
 
1301
 
 
1302
                    min   = d;
 
1303
                    focus = w;
 
1304
                }
 
1305
            }
 
1306
        }
 
1307
    }
 
1308
 
 
1309
    /* move focus to the last focused window if no slot window is currently
 
1310
       focused */
 
1311
    if (!focus)
 
1312
    {
 
1313
        foreach (CompWindow *w, screen->windows ())
 
1314
        {
 
1315
            if (!ScaleWindow::get (w)->priv->slot)
 
1316
                continue;
 
1317
 
 
1318
            if (!focus || focus->activeNum () < w->activeNum ())
 
1319
                focus = w;
 
1320
        }
 
1321
    }
 
1322
 
 
1323
    if (focus)
 
1324
    {
 
1325
        ScaleWindow::get (focus)->scaleSelectWindow ();
 
1326
 
 
1327
        lastActiveNum    = focus->activeNum ();
 
1328
        lastActiveWindow = focus->id ();
 
1329
 
 
1330
        focus->moveInputFocusTo ();
 
1331
    }
 
1332
}
 
1333
 
 
1334
void
 
1335
ScaleScreen::relayoutSlots (const CompMatch& match)
 
1336
{
 
1337
    if (match.isEmpty ())
 
1338
        priv->currentMatch = priv->match;
 
1339
    else
 
1340
        priv->currentMatch = match;
 
1341
 
 
1342
    if (priv->state == ScaleScreen::Idle || priv->state == ScaleScreen::In)
 
1343
        return;
 
1344
 
 
1345
    if (priv->layoutThumbs ())
 
1346
    {
 
1347
        priv->state = ScaleScreen::Out;
 
1348
        priv->moveFocusWindow (0, 0);
 
1349
    }
 
1350
 
 
1351
    priv->cScreen->damageScreen ();
 
1352
}
 
1353
 
 
1354
void
 
1355
PrivateScaleScreen::windowRemove (CompWindow *w)
 
1356
{
 
1357
    if (!w)
 
1358
        return;
 
1359
 
 
1360
    if (state == ScaleScreen::Idle || state == ScaleScreen::In)
 
1361
        return;
 
1362
 
 
1363
    foreach (ScaleWindow *lw, windows)
 
1364
    {
 
1365
        if (lw->priv->window == w)
 
1366
        {
 
1367
            if (layoutThumbs ())
 
1368
            {
 
1369
                state = ScaleScreen::Out;
 
1370
                cScreen->damageScreen ();
 
1371
                break;
 
1372
            }
 
1373
            else
 
1374
            {
 
1375
                CompOption::Vector o (0);
 
1376
                CompAction         *action;
 
1377
 
 
1378
                /* terminate scale mode if the recently closed
 
1379
                 * window was the last scaled window */
 
1380
 
 
1381
                o.push_back (CompOption ("root", CompOption::TypeInt));
 
1382
                o[0].value ().set ((int) screen->root ());
 
1383
 
 
1384
                action = &optionGetInitiateEdge ();
 
1385
                scaleTerminate (action, CompAction::StateCancel, o);
 
1386
 
 
1387
                action = &optionGetInitiateKey ();
 
1388
                scaleTerminate (action, CompAction::StateCancel, o);
 
1389
                break;
 
1390
            }
 
1391
        }
 
1392
    }
 
1393
}
 
1394
 
 
1395
bool
 
1396
PrivateScaleScreen::hoverTimeout ()
 
1397
{
 
1398
    if (grab && state != ScaleScreen::In)
 
1399
    {
 
1400
        CompWindow         *w;
 
1401
        CompOption::Vector o (0);
 
1402
 
 
1403
        w = screen->findWindow (selectedWindow);
 
1404
        if (w)
 
1405
        {
 
1406
            lastActiveNum    = w->activeNum ();
 
1407
            lastActiveWindow = w->id ();
 
1408
 
 
1409
            w->moveInputFocusTo ();
 
1410
        }
 
1411
 
 
1412
        o.push_back (CompOption ("root", CompOption::TypeInt));
 
1413
        o[0].value ().set ((int) screen->root ());
 
1414
 
 
1415
        scaleTerminate (&optionGetInitiateEdge (), 0, o);
 
1416
        scaleTerminate (&optionGetInitiateKey (), 0, o);
 
1417
    }
 
1418
 
 
1419
    return false;
 
1420
}
 
1421
 
 
1422
void
 
1423
PrivateScaleScreen::handleEvent (XEvent *event)
 
1424
{
 
1425
    CompWindow *w = NULL;
 
1426
 
 
1427
    switch (event->type) {
 
1428
        case KeyPress:
 
1429
            if (screen->root () == event->xkey.root)
 
1430
            {
 
1431
                if (grabIndex)
 
1432
                {
 
1433
                    if (event->xkey.keycode == leftKeyCode)
 
1434
                        moveFocusWindow (-1, 0);
 
1435
                    else if (event->xkey.keycode == rightKeyCode)
 
1436
                        moveFocusWindow (1, 0);
 
1437
                    else if (event->xkey.keycode == upKeyCode)
 
1438
                        moveFocusWindow (0, -1);
 
1439
                    else if (event->xkey.keycode == downKeyCode)
 
1440
                        moveFocusWindow (0, 1);
 
1441
                }
 
1442
            }
 
1443
            break;
 
1444
        case ButtonPress:
 
1445
            if (screen->root () == event->xbutton.root &&
 
1446
                grabIndex                              &&
 
1447
                state != ScaleScreen::In)
 
1448
            {
 
1449
                XButtonEvent       *button = &event->xbutton;
 
1450
                CompOption::Vector o (0);
 
1451
 
 
1452
                o.push_back (CompOption ("root", CompOption::TypeInt));
 
1453
                o[0].value ().set ((int) screen->root ());
 
1454
 
 
1455
                /* Button1 terminates scale mode, other buttons can select
 
1456
                 * windows */
 
1457
                if (selectWindowAt (button->x_root, button->y_root, true) &&
 
1458
                    event->xbutton.button == Button1)
 
1459
                {
 
1460
                    scaleTerminate (&optionGetInitiateEdge (), 0, o);
 
1461
                    scaleTerminate (&optionGetInitiateKey (), 0, o);
 
1462
                }
 
1463
                else if (optionGetShowDesktop () &&
 
1464
                         event->xbutton.button == Button1)
 
1465
                {
 
1466
                    CompPoint pointer (button->x_root, button->y_root);
 
1467
                    CompRect  workArea (screen->workArea ());
 
1468
 
 
1469
                    if (workArea.contains (pointer))
 
1470
                    {
 
1471
                        scaleTerminate (&optionGetInitiateEdge (), 0, o);
 
1472
                        scaleTerminate (&optionGetInitiateKey (), 0, o);
 
1473
                        screen->enterShowDesktopMode ();
 
1474
                    }
 
1475
                }
 
1476
            }
 
1477
            break;
 
1478
        case MotionNotify:
 
1479
            if (screen->root () == event->xmotion.root &&
 
1480
                grabIndex                              &&
 
1481
                state != ScaleScreen::In)
 
1482
            {
 
1483
                bool       focus = false;
 
1484
                CompOption *o = screen->getOption ("click_to_focus");
 
1485
 
 
1486
                if (o && o->value ().b ())
 
1487
                    focus = true;
 
1488
 
 
1489
                selectWindowAt (event->xmotion.x_root,
 
1490
                                event->xmotion.y_root,
 
1491
                                focus);
 
1492
            }
 
1493
            break;
 
1494
        case DestroyNotify:
 
1495
 
 
1496
            /* We need to get the CompWindow * for event->xdestroywindow.window
 
1497
             * here because in the ::handleEvent call below that CompWindow's
 
1498
             * id will become "1" so CompScreen::findWindow won't
 
1499
             * be able to find teh window after that
 
1500
             */
 
1501
 
 
1502
            w = screen->findWindow (event->xdestroywindow.window);
 
1503
            break;
 
1504
        case UnmapNotify:
 
1505
 
 
1506
             w = screen->findWindow (event->xunmap.window);
 
1507
             break;
 
1508
        case ClientMessage:
 
1509
            if (event->xclient.message_type == Atoms::xdndPosition)
 
1510
            {
 
1511
                w = screen->findWindow (event->xclient.window);
 
1512
                if (w)
 
1513
                {
 
1514
                    bool       focus = false;
 
1515
                    CompOption *o = screen->getOption ("click_to_focus");
 
1516
 
 
1517
                    if (o && o->value ().b ())
 
1518
                        focus = true;
 
1519
 
 
1520
                    if (w->id () == dndTarget)
 
1521
                        sendDndStatusMessage (event->xclient.data.l[0]);
 
1522
 
 
1523
                    if (grab                     &&
 
1524
                        state != ScaleScreen::In &&
 
1525
                        w->id () == dndTarget)
 
1526
                    {
 
1527
                        ScaleWindow *sw = checkForWindowAt (pointerX, pointerY);
 
1528
                        if (sw && sw->priv->isScaleWin ())
 
1529
                        {
 
1530
                            int time;
 
1531
 
 
1532
                            time = optionGetHoverTime ();
 
1533
 
 
1534
                            if (hover.active ())
 
1535
                            {
 
1536
                                int lastMotion = sqrt (pow (pointerX - lastPointerX, 2) + pow (pointerY - lastPointerY, 2));
 
1537
                                
 
1538
                                if (sw->window->id () != selectedWindow || lastMotion > optionGetDndDistance ())
 
1539
                                    hover.stop ();
 
1540
                            }
 
1541
 
 
1542
                            if (!hover.active ())
 
1543
                            {
 
1544
                                hover.start (time, (float) time * 1.2);
 
1545
                            }
 
1546
 
 
1547
                            selectWindowAt (pointerX, pointerY, focus);
 
1548
                        }
 
1549
                        else
 
1550
                        {
 
1551
                            if (hover.active ())
 
1552
                                hover.stop ();
 
1553
                        }
 
1554
                    }
 
1555
                }
 
1556
            }
 
1557
            else if (event->xclient.message_type == Atoms::xdndDrop ||
 
1558
                     event->xclient.message_type == Atoms::xdndLeave)
 
1559
            {
 
1560
                w = screen->findWindow (event->xclient.window);
 
1561
                if (w)
 
1562
                {
 
1563
                    if (grab                     &&
 
1564
                        state != ScaleScreen::In &&
 
1565
                        w->id () == dndTarget)
 
1566
                    {
 
1567
                        CompOption::Vector o (0);
 
1568
                        o.push_back (CompOption ("root", CompOption::TypeInt));
 
1569
                        o[0].value ().set ((int) screen->root ());
 
1570
 
 
1571
                        scaleTerminate (&optionGetInitiateEdge (), 0, o);
 
1572
                        scaleTerminate (&optionGetInitiateKey (), 0, o);
 
1573
                    }
 
1574
                }
 
1575
            }
 
1576
        default:
 
1577
            break;
 
1578
    }
 
1579
 
 
1580
    screen->handleEvent (event);
 
1581
 
 
1582
    /* Only safe to remove the window after all events have been
 
1583
     * handled, so that we don't get race conditions on calls
 
1584
     * to scale functions */
 
1585
 
 
1586
    switch (event->type) {
 
1587
        case UnmapNotify:
 
1588
            if (w)
 
1589
                windowRemove (w);
 
1590
            break;
 
1591
        case DestroyNotify:
 
1592
            if (w)
 
1593
                windowRemove (w);
 
1594
            break;
 
1595
    }
 
1596
}
 
1597
 
 
1598
bool
 
1599
PrivateScaleWindow::damageRect (bool            initial,
 
1600
                                const CompRect& rect)
 
1601
{
 
1602
    bool status = false;
 
1603
 
 
1604
    if (initial)
 
1605
    {
 
1606
        if (spScreen->grab && isScaleWin ())
 
1607
        {
 
1608
            if (spScreen->layoutThumbs ())
 
1609
            {
 
1610
                spScreen->state = ScaleScreen::Out;
 
1611
                spScreen->cScreen->damageScreen ();
 
1612
            }
 
1613
        }
 
1614
    }
 
1615
    else if (spScreen->state == ScaleScreen::Wait)
 
1616
    {
 
1617
        if (slot)
 
1618
        {
 
1619
            cWindow->damageTransformedRect (scale, scale, tx, ty, rect);
 
1620
 
 
1621
            status = true;
 
1622
        }
 
1623
    }
 
1624
 
 
1625
    status |= cWindow->damageRect (initial, rect);
 
1626
 
 
1627
    return status;
 
1628
}
 
1629
 
 
1630
ScaleScreen::ScaleScreen (CompScreen *s) :
 
1631
    PluginClassHandler<ScaleScreen, CompScreen, COMPIZ_SCALE_ABI> (s),
 
1632
    priv (new PrivateScaleScreen (s))
 
1633
{
 
1634
}
 
1635
 
 
1636
ScaleScreen::~ScaleScreen ()
 
1637
{
 
1638
    delete priv;
 
1639
}
 
1640
 
 
1641
ScaleWindow::ScaleWindow (CompWindow *w) :
 
1642
    PluginClassHandler<ScaleWindow, CompWindow, COMPIZ_SCALE_ABI> (w),
 
1643
    window (w),
 
1644
    priv (new PrivateScaleWindow (w))
 
1645
{
 
1646
}
 
1647
 
 
1648
ScaleWindow::~ScaleWindow ()
 
1649
{
 
1650
    delete priv;
 
1651
}
 
1652
 
 
1653
PrivateScaleScreen::PrivateScaleScreen (CompScreen *s) :
 
1654
    cScreen (CompositeScreen::get (s)),
 
1655
    gScreen (GLScreen::get (s)),
 
1656
 
 
1657
    lastActiveNum (0),
 
1658
    lastActiveWindow (None),
 
1659
 
 
1660
    selectedWindow (None),
 
1661
    hoveredWindow (None),
 
1662
    previousActiveWindow (None),
 
1663
    grab (false),
 
1664
    grabIndex (0),
 
1665
    dndTarget (None),
 
1666
    state (ScaleScreen::Idle),
 
1667
    moreAdjust (false),
 
1668
    cursor (0),
 
1669
    nSlots (0)
 
1670
{
 
1671
    leftKeyCode  = XKeysymToKeycode (screen->dpy (), XStringToKeysym ("Left"));
 
1672
    rightKeyCode = XKeysymToKeycode (screen->dpy (), XStringToKeysym ("Right"));
 
1673
    upKeyCode    = XKeysymToKeycode (screen->dpy (), XStringToKeysym ("Up"));
 
1674
    downKeyCode  = XKeysymToKeycode (screen->dpy (), XStringToKeysym ("Down"));
 
1675
 
 
1676
    cursor = XCreateFontCursor (screen->dpy (), XC_left_ptr);
 
1677
 
 
1678
    opacity = (OPAQUE * optionGetOpacity ()) / 100;
 
1679
 
 
1680
    hover.setCallback (boost::bind (&PrivateScaleScreen::hoverTimeout, this));
 
1681
 
 
1682
    optionSetOpacityNotify (boost::bind (&PrivateScaleScreen::updateOpacity, this));
 
1683
 
 
1684
#define SCALEBIND(a)                                              \
 
1685
    boost::bind (PrivateScaleScreen::scaleInitiate, _1, _2, _3, a)
 
1686
 
 
1687
    optionSetInitiateEdgeInitiate (SCALEBIND (ScaleTypeNormal));
 
1688
    optionSetInitiateEdgeTerminate (PrivateScaleScreen::scaleTerminate);
 
1689
    optionSetInitiateButtonInitiate (SCALEBIND (ScaleTypeNormal));
 
1690
    optionSetInitiateButtonTerminate (PrivateScaleScreen::scaleTerminate);
 
1691
    optionSetInitiateKeyInitiate (SCALEBIND (ScaleTypeNormal));
 
1692
    optionSetInitiateKeyTerminate (PrivateScaleScreen::scaleTerminate);
 
1693
 
 
1694
    optionSetInitiateAllEdgeInitiate (SCALEBIND (ScaleTypeAll));
 
1695
    optionSetInitiateAllEdgeTerminate (PrivateScaleScreen::scaleTerminate);
 
1696
    optionSetInitiateAllButtonInitiate (SCALEBIND (ScaleTypeAll));
 
1697
    optionSetInitiateAllButtonTerminate (PrivateScaleScreen::scaleTerminate);
 
1698
    optionSetInitiateAllKeyInitiate (SCALEBIND (ScaleTypeAll));
 
1699
    optionSetInitiateAllKeyTerminate (PrivateScaleScreen::scaleTerminate);
 
1700
 
 
1701
    optionSetInitiateGroupEdgeInitiate (SCALEBIND (ScaleTypeGroup));
 
1702
    optionSetInitiateGroupEdgeTerminate (PrivateScaleScreen::scaleTerminate);
 
1703
    optionSetInitiateGroupButtonInitiate (SCALEBIND (ScaleTypeGroup));
 
1704
    optionSetInitiateGroupButtonTerminate (PrivateScaleScreen::scaleTerminate);
 
1705
    optionSetInitiateGroupKeyInitiate (SCALEBIND (ScaleTypeGroup));
 
1706
    optionSetInitiateGroupKeyTerminate (PrivateScaleScreen::scaleTerminate);
 
1707
 
 
1708
    optionSetInitiateOutputEdgeInitiate (SCALEBIND (ScaleTypeOutput));
 
1709
    optionSetInitiateOutputEdgeTerminate (PrivateScaleScreen::scaleTerminate);
 
1710
    optionSetInitiateOutputButtonInitiate (SCALEBIND (ScaleTypeOutput));
 
1711
    optionSetInitiateOutputButtonTerminate (PrivateScaleScreen::scaleTerminate);
 
1712
    optionSetInitiateOutputKeyInitiate (SCALEBIND (ScaleTypeOutput));
 
1713
    optionSetInitiateOutputKeyTerminate (PrivateScaleScreen::scaleTerminate);
 
1714
 
 
1715
#undef SCALEBIND
 
1716
 
 
1717
    ScreenInterface::setHandler (s);
 
1718
    CompositeScreenInterface::setHandler (cScreen, false);
 
1719
    GLScreenInterface::setHandler (gScreen, false);
 
1720
}
 
1721
 
 
1722
PrivateScaleScreen::~PrivateScaleScreen ()
 
1723
{
 
1724
    if (cursor)
 
1725
        XFreeCursor (screen->dpy (), cursor);
 
1726
}
 
1727
 
 
1728
void
 
1729
PrivateScaleScreen::updateOpacity ()
 
1730
{
 
1731
    opacity = (OPAQUE * optionGetOpacity ()) / 100;
 
1732
}
 
1733
 
 
1734
/* When we are only scaling windows on the current output, over-ride the
 
1735
 * multioutput mode so that windows will only be displayed on the current
 
1736
 * output, regardless of the setting.
 
1737
 */
 
1738
int
 
1739
PrivateScaleScreen::getMultioutputMode ()
 
1740
{
 
1741
    if (type == ScaleTypeOutput)
 
1742
        return MultioutputModeOnCurrentOutputDevice;
 
1743
 
 
1744
    return optionGetMultioutputMode ();
 
1745
}
 
1746
 
 
1747
 
 
1748
PrivateScaleWindow::PrivateScaleWindow (CompWindow *w) :
 
1749
    window (w),
 
1750
    cWindow (CompositeWindow::get (w)),
 
1751
    gWindow (GLWindow::get (w)),
 
1752
    sWindow (ScaleWindow::get (w)),
 
1753
    sScreen (ScaleScreen::get (screen)),
 
1754
    spScreen (sScreen->priv),
 
1755
    slot (NULL),
 
1756
    sid (0),
 
1757
    distance (0.0),
 
1758
    xVelocity (0.0),
 
1759
    yVelocity (0.0),
 
1760
    scaleVelocity (0.0),
 
1761
    scale (1.0),
 
1762
    tx (0.0),
 
1763
    ty (0.0),
 
1764
    delta (1.0),
 
1765
    adjust (false),
 
1766
    lastThumbOpacity (0.0)
 
1767
{
 
1768
    CompositeWindowInterface::setHandler (cWindow,
 
1769
                                          spScreen->state != ScaleScreen::Idle);
 
1770
    GLWindowInterface::setHandler (gWindow,
 
1771
                                   spScreen->state != ScaleScreen::Idle);
 
1772
}
 
1773
 
 
1774
PrivateScaleWindow::~PrivateScaleWindow ()
 
1775
{
 
1776
}
 
1777
 
 
1778
CompOption::Vector &
 
1779
ScaleScreen::getOptions ()
 
1780
{
 
1781
    return priv->getOptions ();
 
1782
}
 
1783
 
 
1784
bool
 
1785
ScaleScreen::setOption (const CompString  &name,
 
1786
                        CompOption::Value &value)
 
1787
{
 
1788
    return priv->setOption (name, value);
 
1789
}
 
1790
 
 
1791
bool
 
1792
ScalePluginVTable::init ()
 
1793
{
 
1794
    if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
 
1795
        !CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) ||
 
1796
        !CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))
 
1797
        return false;
 
1798
 
 
1799
    CompPrivate p;
 
1800
    p.uval = COMPIZ_SCALE_ABI;
 
1801
    screen->storeValue ("scale_ABI", p);
 
1802
 
 
1803
    return true;
 
1804
}
 
1805
 
 
1806
void
 
1807
ScalePluginVTable::fini ()
 
1808
{
 
1809
    screen->eraseValue ("scale_ABI");
 
1810
}