~linaro-graphics-wg/compiz-plugins-main/oneiric-gles2

« back to all changes in this revision

Viewing changes to grid/src/grid.cpp

  • Committer: Sam Spilsbury
  • Date: 2011-09-29 11:34:08 UTC
  • Revision ID: sam.spilsbury@canonical.com-20110929113408-vnew477gska3l802
Sync in changes from upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Compiz Fusion Grid plugin
 
3
 *
 
4
 * Copyright (c) 2008 Stephen Kennedy <suasol@gmail.com>
 
5
 * Copyright (c) 2010 Scott Moreau <oreaus@gmail.com>
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU General Public License
 
9
 * as published by the Free Software Foundation; either version 2
 
10
 * of the License, or (at your option) any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * Description:
 
18
 *
 
19
 * Plugin to act like winsplit revolution (http://www.winsplit-revolution.com/)
 
20
 * use <Control><Alt>NUMPAD_KEY to move and tile your windows.
 
21
 *
 
22
 * Press the tiling keys several times to cycle through some tiling options.
 
23
 */
 
24
 
 
25
#include "grid.h"
 
26
 
 
27
using namespace GridWindowType;
 
28
 
 
29
static std::map <unsigned int, GridProps> gridProps;
 
30
 
 
31
void
 
32
GridScreen::handleCompizEvent(const char*    plugin,
 
33
                              const char*    event,
 
34
                              CompOption::Vector&  o)
 
35
{
 
36
    if (strcmp(event, "start_viewport_switch") == 0)
 
37
    {
 
38
        mSwitchingVp = true;
 
39
    }
 
40
    else if (strcmp(event, "end_viewport_switch") == 0)
 
41
    {
 
42
        mSwitchingVp = false;
 
43
    }
 
44
 
 
45
  screen->handleCompizEvent(plugin, event, o);
 
46
}
 
47
 
 
48
CompRect
 
49
GridScreen::slotToRect (CompWindow      *w,
 
50
                        const CompRect& slot)
 
51
{
 
52
    return CompRect (slot.x () + w->border ().left,
 
53
                     slot.y () + w->border ().top,
 
54
                     slot.width () - (w->border ().left + w->border ().right),
 
55
                     slot.height () - (w->border ().top + w->border ().bottom));
 
56
}
 
57
 
 
58
CompRect
 
59
GridScreen::constrainSize (CompWindow      *w,
 
60
                           const CompRect& slot)
 
61
{
 
62
    CompRect result;
 
63
    int      cw, ch;
 
64
 
 
65
    result = slotToRect (w, slot);
 
66
 
 
67
    if (w->constrainNewWindowSize (result.width (), result.height (), &cw, &ch))
 
68
    {
 
69
        /* constrained size may put window offscreen, adjust for that case */
 
70
        int dx = result.x () + cw - workarea.right () + w->border ().right;
 
71
        int dy = result.y () + ch - workarea.bottom () + w->border ().bottom;
 
72
 
 
73
        if (dx > 0)
 
74
            result.setX (result.x () - dx);
 
75
        if (dy > 0)
 
76
            result.setY (result.y () - dy);
 
77
 
 
78
        result.setWidth (cw);
 
79
        result.setHeight (ch);
 
80
    }
 
81
 
 
82
    return result;
 
83
}
 
84
 
 
85
void
 
86
GridScreen::getPaintRectangle (CompRect &cRect)
 
87
{
 
88
    if (typeToMask (edgeToGridType ()) != GridUnknown && optionGetDrawIndicator ())
 
89
        cRect = desiredSlot;
 
90
    else
 
91
        cRect.setGeometry (0, 0, 0, 0);
 
92
}
 
93
 
 
94
int
 
95
applyProgress (int a, int b, float progress)
 
96
{
 
97
        return a < b ?
 
98
         b - (ABS (a - b) * progress) :
 
99
         b + (ABS (a - b) * progress);
 
100
}
 
101
 
 
102
void
 
103
GridScreen::setCurrentRect (Animation &anim)
 
104
{
 
105
        anim.currentRect.setLeft (applyProgress (anim.targetRect.x1 (),
 
106
                                                                                                        anim.fromRect.x1 (),
 
107
                                                                                                        anim.progress));
 
108
        anim.currentRect.setRight (applyProgress (anim.targetRect.x2 (),
 
109
                                                                                                        anim.fromRect.x2 (),
 
110
                                                                                                        anim.progress));
 
111
        anim.currentRect.setTop (applyProgress (anim.targetRect.y1 (),
 
112
                                                                                                        anim.fromRect.y1 (),
 
113
                                                                                                        anim.progress));
 
114
        anim.currentRect.setBottom (applyProgress (anim.targetRect.y2 (),
 
115
                                                                                                        anim.fromRect.y2 (),
 
116
                                                                                                        anim.progress));
 
117
}
 
118
 
 
119
bool
 
120
GridScreen::initiateCommon (CompAction         *action,
 
121
                            CompAction::State  state,
 
122
                            CompOption::Vector &option,
 
123
                            unsigned int                where,
 
124
                            bool               resize,
 
125
                            bool               key)
 
126
{
 
127
    Window     xid;
 
128
    CompWindow *cw = 0;
 
129
 
 
130
    xid = CompOption::getIntOptionNamed (option, "window");
 
131
    cw  = screen->findWindow (xid);
 
132
 
 
133
    if (cw)
 
134
    {
 
135
        XWindowChanges xwc;
 
136
        bool maximizeH = where & (GridBottom | GridTop | GridMaximize);
 
137
        bool maximizeV = where & (GridLeft | GridRight | GridMaximize);
 
138
 
 
139
        if (!(cw->actions () & CompWindowActionResizeMask))
 
140
            return false;
 
141
 
 
142
        if (maximizeH && !(cw->actions () & CompWindowActionMaximizeHorzMask))
 
143
            return false;
 
144
 
 
145
        if (maximizeV && !(cw->actions () & CompWindowActionMaximizeVertMask))
 
146
            return false;
 
147
 
 
148
        if (where & GridUnknown)
 
149
            return false;
 
150
 
 
151
        GRID_WINDOW (cw);
 
152
 
 
153
        if (gw->lastTarget & ~(where))
 
154
            gw->resizeCount = 0;
 
155
        else if (!key)
 
156
            return false;
 
157
 
 
158
        props = gridProps[where];
 
159
 
 
160
        /* get current available area */
 
161
        if (cw == mGrabWindow)
 
162
            workarea = screen->getWorkareaForOutput
 
163
                            (screen->outputDeviceForPoint (pointerX, pointerY));
 
164
        else
 
165
        {
 
166
            workarea = screen->getWorkareaForOutput (cw->outputDevice ());
 
167
 
 
168
            if (props.numCellsX == 1)
 
169
                centerCheck = true;
 
170
 
 
171
            if (!gw->isGridResized)
 
172
                /* Store size not including borders when using a keybinding */
 
173
                gw->originalSize = slotToRect(cw, cw->serverBorderRect ());
 
174
        }
 
175
 
 
176
        if ((cw->state () & MAXIMIZE_STATE) &&
 
177
            (resize || optionGetSnapoffMaximized ()))
 
178
        {
 
179
            /* maximized state interferes with us, clear it */
 
180
            cw->maximize (0);
 
181
        }
 
182
 
 
183
        if ((where & GridMaximize) && resize)
 
184
        {
 
185
            /* move the window to the correct output */
 
186
            if (cw == mGrabWindow)
 
187
            {
 
188
                xwc.x = workarea.x () + 50;
 
189
                xwc.y = workarea.y () + 50;
 
190
                xwc.width = workarea.width ();
 
191
                xwc.height = workarea.height ();
 
192
                cw->configureXWindow (CWX | CWY, &xwc);
 
193
            }
 
194
            cw->maximize (MAXIMIZE_STATE);
 
195
            gw->isGridResized = true;
 
196
            gw->isGridMaximized = true;
 
197
                for (unsigned int i = 0; i < animations.size (); i++)
 
198
                        animations.at (i).fadingOut = true;
 
199
            return true;
 
200
        }
 
201
 
 
202
        /* Convention:
 
203
         * xxxSlot include decorations (it's the screen area occupied)
 
204
         * xxxRect are undecorated (it's the constrained position
 
205
                                    of the contents)
 
206
         */
 
207
 
 
208
        /* slice and dice to get desired slot - including decorations */
 
209
        desiredSlot.setY (workarea.y () + props.gravityDown *
 
210
                          (workarea.height () / props.numCellsY));
 
211
        desiredSlot.setHeight (workarea.height () / props.numCellsY);
 
212
        desiredSlot.setX (workarea.x () + props.gravityRight *
 
213
                          (workarea.width () / props.numCellsX));
 
214
        desiredSlot.setWidth (workarea.width () / props.numCellsX);
 
215
 
 
216
        /* Adjust for constraints and decorations */
 
217
        desiredRect = constrainSize (cw, desiredSlot);
 
218
        /* Get current rect not including decorations */
 
219
        currentRect.setGeometry (cw->serverX (), cw->serverY (),
 
220
                                 cw->serverWidth (),
 
221
                                 cw->serverHeight ());
 
222
 
 
223
        if (desiredRect.y () == currentRect.y () &&
 
224
            desiredRect.height () == currentRect.height () &&
 
225
            where & ~(GridMaximize) && gw->lastTarget & where)
 
226
        {
 
227
            int slotWidth25  = workarea.width () / 4;
 
228
            int slotWidth33  = (workarea.width () / 3) + cw->border ().left;
 
229
            int slotWidth17  = slotWidth33 - slotWidth25;
 
230
            int slotWidth66  = workarea.width () - slotWidth33;
 
231
            int slotWidth75  = workarea.width () - slotWidth25;
 
232
 
 
233
            if (props.numCellsX == 2) /* keys (1, 4, 7, 3, 6, 9) */
 
234
            {
 
235
                if ((currentRect.width () == desiredRect.width () &&
 
236
                    currentRect.x () == desiredRect.x ()) ||
 
237
                    (gw->resizeCount < 1) || (gw->resizeCount > 5))
 
238
                    gw->resizeCount = 3;
 
239
 
 
240
                /* tricky, have to allow for window constraints when
 
241
                 * computing what the 33% and 66% offsets would be
 
242
                 */
 
243
                switch (gw->resizeCount)
 
244
                {
 
245
                    case 1:
 
246
                        desiredSlot.setWidth (slotWidth66);
 
247
                        desiredSlot.setX (workarea.x () +
 
248
                                          props.gravityRight * slotWidth33);
 
249
                        gw->resizeCount++;
 
250
                        break;
 
251
                    case 2:
 
252
                        gw->resizeCount++;
 
253
                        break;
 
254
                    case 3:
 
255
                        desiredSlot.setWidth (slotWidth33);
 
256
                        desiredSlot.setX (workarea.x () +
 
257
                                          props.gravityRight * slotWidth66);
 
258
                        gw->resizeCount++;
 
259
                        break;
 
260
                    case 4:
 
261
                        desiredSlot.setWidth (slotWidth25);
 
262
                        desiredSlot.setX (workarea.x () +
 
263
                                          props.gravityRight * slotWidth75);
 
264
                        gw->resizeCount++;
 
265
                        break;
 
266
                    case 5:
 
267
                        desiredSlot.setWidth (slotWidth75);
 
268
                        desiredSlot.setX (workarea.x () +
 
269
                                          props.gravityRight * slotWidth25);
 
270
                        gw->resizeCount++;
 
271
                        break;
 
272
                    default:
 
273
                        break;
 
274
                }
 
275
            }
 
276
            else /* keys (2, 5, 8) */
 
277
            {
 
278
 
 
279
                if ((currentRect.width () == desiredRect.width () &&
 
280
                    currentRect.x () == desiredRect.x ()) ||
 
281
                    (gw->resizeCount < 1) || (gw->resizeCount > 5))
 
282
                    gw->resizeCount = 1;
 
283
            
 
284
                switch (gw->resizeCount)
 
285
                {
 
286
                    case 1:
 
287
                        desiredSlot.setWidth (workarea.width () -
 
288
                                             (slotWidth17 * 2));
 
289
                        desiredSlot.setX (workarea.x () + slotWidth17);
 
290
                        gw->resizeCount++;
 
291
                        break;
 
292
                    case 2:
 
293
                        desiredSlot.setWidth ((slotWidth25 * 2) +
 
294
                                              (slotWidth17 * 2));
 
295
                        desiredSlot.setX (workarea.x () +
 
296
                                         (slotWidth25 - slotWidth17));
 
297
                        gw->resizeCount++;
 
298
                        break;
 
299
                    case 3:
 
300
                        desiredSlot.setWidth ((slotWidth25 * 2));
 
301
                        desiredSlot.setX (workarea.x () + slotWidth25);
 
302
                        gw->resizeCount++;
 
303
                        break;
 
304
                    case 4:
 
305
                        desiredSlot.setWidth (slotWidth33 -
 
306
                            (cw->border ().left + cw->border ().right));
 
307
                        desiredSlot.setX (workarea.x () + slotWidth33);
 
308
                        gw->resizeCount++;
 
309
                        break;
 
310
                    case 5:
 
311
                        gw->resizeCount++;
 
312
                        break;
 
313
                    default:
 
314
                        break;
 
315
                }
 
316
            }
 
317
 
 
318
            if (gw->resizeCount == 6)
 
319
                gw->resizeCount = 1;
 
320
 
 
321
            desiredRect = constrainSize (cw, desiredSlot);
 
322
        }
 
323
 
 
324
        xwc.x = desiredRect.x ();
 
325
        xwc.y = desiredRect.y ();
 
326
        xwc.width  = desiredRect.width ();
 
327
        xwc.height = desiredRect.height ();
 
328
 
 
329
        /* Store a copy of xwc since configureXWindow changes it's values */
 
330
        XWindowChanges wc = xwc;
 
331
 
 
332
        if (cw->mapNum ())
 
333
            cw->sendSyncRequest ();
 
334
 
 
335
        /* TODO: animate move+resize */
 
336
        if (resize)
 
337
        {
 
338
            unsigned int valueMask = CWX | CWY | CWWidth | CWHeight;
 
339
            gw->lastTarget = where;
 
340
            gw->currentSize = CompRect (wc.x, wc.y, wc.width, wc.height);
 
341
 
 
342
            /* Special case for left and right, actually vertically maximize
 
343
             * the window */
 
344
            if (where & GridLeft || where & GridRight)
 
345
            {
 
346
                /* First restore the window to its original size */
 
347
                XWindowChanges rwc;
 
348
 
 
349
                rwc.x = gw->originalSize.x ();
 
350
                rwc.y = gw->originalSize.y ();
 
351
                rwc.width = gw->originalSize.width ();
 
352
                rwc.height = gw->originalSize.height ();
 
353
 
 
354
                cw->configureXWindow (CWX | CWY | CWWidth | CWHeight, &rwc);
 
355
 
 
356
                gw->isGridMaximized = true;
 
357
                gw->isGridResized = false;
 
358
 
 
359
                gw->lastBorder = cw->border ();
 
360
                /* Maximize the window */
 
361
                printf ("maximizing window\n");
 
362
                cw->maximize (CompWindowStateMaximizedVertMask);
 
363
            }
 
364
            else
 
365
            {
 
366
                gw->isGridResized = true;
 
367
                gw->isGridMaximized = false;
 
368
            }
 
369
 
 
370
            /* Make window the size that we want */
 
371
            cw->configureXWindow (valueMask, &xwc);
 
372
 
 
373
            for (unsigned int i = 0; i < animations.size (); i++)
 
374
                animations.at (i).fadingOut = true;
 
375
        }
 
376
 
 
377
        /* This centers a window if it could not be resized to the desired
 
378
         * width. Without this, it can look buggy when desired width is
 
379
         * beyond the minimum or maximum width of the window.
 
380
         */
 
381
        if (centerCheck)
 
382
        {
 
383
            if ((cw->serverBorderRect ().width () >
 
384
                 desiredSlot.width ()) ||
 
385
                 cw->serverBorderRect ().width () <
 
386
                 desiredSlot.width ())
 
387
            {
 
388
                wc.x = (workarea.width () >> 1) -
 
389
                      ((cw->serverBorderRect ().width () >> 1) -
 
390
                        cw->border ().left);
 
391
                cw->configureXWindow (CWX, &wc);
 
392
            }
 
393
 
 
394
            centerCheck = false;
 
395
        }
 
396
    }
 
397
 
 
398
    return true;
 
399
}
 
400
 
 
401
void
 
402
GridScreen::glPaintRectangle (const GLScreenPaintAttrib &sAttrib,
 
403
                              const GLMatrix            &transform,
 
404
                              CompOutput                *output)
 
405
{
 
406
    CompRect rect;
 
407
    GLMatrix sTransform (transform);
 
408
        std::vector<Animation>::iterator iter;
 
409
 
 
410
    getPaintRectangle (rect);
 
411
 
 
412
        for (unsigned int i = 0; i < animations.size (); i++)
 
413
                setCurrentRect (animations.at (i));
 
414
 
 
415
    glPushMatrix ();
 
416
 
 
417
    sTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
 
418
 
 
419
    glLoadMatrixf (sTransform.getMatrix ());
 
420
 
 
421
    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
 
422
    glEnable (GL_BLEND);
 
423
 
 
424
        for (iter = animations.begin (); iter != animations.end () && animating; iter++)
 
425
        {
 
426
                Animation& anim = *iter;
 
427
                float alpha = ((float) optionGetFillColorAlpha () / 65535.0f) * anim.opacity;
 
428
 
 
429
                /* fill rectangle */
 
430
                glColor4f (((float) optionGetFillColorRed () / 65535.0f) * alpha,
 
431
                           ((float) optionGetFillColorGreen () / 65535.0f) * alpha,
 
432
                           ((float) optionGetFillColorBlue () / 65535.0f) * alpha,
 
433
                           alpha);
 
434
 
 
435
                /* fill rectangle */
 
436
                glRecti (anim.currentRect.x1 (), anim.currentRect.y2 (),
 
437
                                 anim.currentRect.x2 (), anim.currentRect.y1 ());
 
438
 
 
439
                /* Set outline rect smaller to avoid damage issues */
 
440
                anim.currentRect.setGeometry (anim.currentRect.x () + 1,
 
441
                                              anim.currentRect.y () + 1,
 
442
                                              anim.currentRect.width () - 2,
 
443
                                              anim.currentRect.height () - 2);
 
444
 
 
445
                alpha = (float) (optionGetOutlineColorAlpha () / 65535.0f) * anim.opacity;
 
446
 
 
447
                /* draw outline */
 
448
                glColor4f (((float) optionGetOutlineColorRed () / 65535.0f) * alpha,
 
449
                           ((float) optionGetOutlineColorGreen () / 65535.0f) * alpha,
 
450
                           ((float) optionGetOutlineColorBlue () / 65535.0f) * alpha,
 
451
                           alpha);
 
452
 
 
453
                glLineWidth (2.0);
 
454
 
 
455
                glBegin (GL_LINE_LOOP);
 
456
                glVertex2i (anim.currentRect.x1 (),     anim.currentRect.y1 ());
 
457
                glVertex2i (anim.currentRect.x2 (),     anim.currentRect.y1 ());
 
458
                glVertex2i (anim.currentRect.x2 (),     anim.currentRect.y2 ());
 
459
                glVertex2i (anim.currentRect.x1 (),     anim.currentRect.y2 ());
 
460
                glEnd ();
 
461
        }
 
462
 
 
463
        if (!animating)
 
464
        {
 
465
                /* fill rectangle */
 
466
                float alpha = (float) optionGetFillColorAlpha () / 65535.0f;
 
467
 
 
468
                /* fill rectangle */
 
469
                glColor4f (((float) optionGetFillColorRed () / 65535.0f) * alpha,
 
470
                           ((float) optionGetFillColorGreen () / 65535.0f) * alpha,
 
471
                           ((float) optionGetFillColorBlue () / 65535.0f) * alpha,
 
472
                           alpha);
 
473
                glRecti (rect.x1 (), rect.y2 (), rect.x2 (), rect.y1 ());
 
474
 
 
475
                /* Set outline rect smaller to avoid damage issues */
 
476
                rect.setGeometry (rect.x () + 1, rect.y () + 1,
 
477
                                  rect.width () - 2, rect.height () - 2);
 
478
 
 
479
                /* draw outline */
 
480
                alpha = (float) optionGetOutlineColorAlpha () / 65535.0f;
 
481
 
 
482
                /* draw outline */
 
483
                glColor4f (((float) optionGetOutlineColorRed () / 65535.0f) * alpha,
 
484
                           ((float) optionGetOutlineColorGreen () / 65535.0f) * alpha,
 
485
                           ((float) optionGetOutlineColorBlue () / 65535.0f) * alpha,
 
486
                           alpha);
 
487
 
 
488
                glLineWidth (2.0);
 
489
                glBegin (GL_LINE_LOOP);
 
490
                glVertex2i (rect.x1 (), rect.y1 ());
 
491
                glVertex2i (rect.x2 (), rect.y1 ());
 
492
                glVertex2i (rect.x2 (), rect.y2 ());
 
493
                glVertex2i (rect.x1 (), rect.y2 ());
 
494
                glEnd ();
 
495
        }
 
496
 
 
497
    /* clean up */
 
498
    glColor4usv (defaultColor);
 
499
    glDisable (GL_BLEND);
 
500
    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
 
501
    glPopMatrix ();
 
502
}
 
503
 
 
504
bool
 
505
GridScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
 
506
                           const GLMatrix            &matrix,
 
507
                           const CompRegion          &region,
 
508
                           CompOutput                *output,
 
509
                           unsigned int              mask)
 
510
{
 
511
    bool status;
 
512
 
 
513
    status = glScreen->glPaintOutput (attrib, matrix, region, output, mask);
 
514
 
 
515
    glPaintRectangle (attrib, matrix, output);
 
516
 
 
517
    return status;
 
518
}
 
519
 
 
520
unsigned int
 
521
GridScreen::typeToMask (int t)
 
522
{
 
523
    typedef struct {
 
524
        unsigned int mask;
 
525
        int type;
 
526
    } GridTypeMask;
 
527
 
 
528
    std::vector <GridTypeMask> type =
 
529
    {
 
530
        { GridWindowType::GridUnknown, 0 },
 
531
        { GridWindowType::GridBottomLeft, 1 },
 
532
        { GridWindowType::GridBottom, 2 },
 
533
        { GridWindowType::GridBottomRight, 3 },
 
534
        { GridWindowType::GridLeft, 4 },
 
535
        { GridWindowType::GridCenter, 5 },
 
536
        { GridWindowType::GridRight, 6 },
 
537
        { GridWindowType::GridTopLeft, 7 },
 
538
        { GridWindowType::GridTop, 8 },
 
539
        { GridWindowType::GridTopRight, 9 },
 
540
        { GridWindowType::GridMaximize, 10 }
 
541
    };
 
542
 
 
543
    for (unsigned int i = 0; i < type.size (); i++)
 
544
    {
 
545
        GridTypeMask &tm = type[i];
 
546
        if (tm.type == t)
 
547
            return tm.mask;
 
548
    }
 
549
 
 
550
    return GridWindowType::GridUnknown;
 
551
}
 
552
 
 
553
int
 
554
GridScreen::edgeToGridType ()
 
555
{
 
556
    int ret;
 
557
 
 
558
    switch (edge) {
 
559
    case Left:
 
560
        ret = (int) optionGetLeftEdgeAction ();
 
561
        break;
 
562
    case Right:
 
563
        ret = (int) optionGetRightEdgeAction ();
 
564
        break;
 
565
    case Top:
 
566
        ret = (int) optionGetTopEdgeAction ();
 
567
        break;
 
568
    case Bottom:
 
569
        ret = (int) optionGetBottomEdgeAction ();
 
570
        break;
 
571
    case TopLeft:
 
572
        ret = (int) optionGetTopLeftCornerAction ();
 
573
        break;
 
574
    case TopRight:
 
575
        ret = (int) optionGetTopRightCornerAction ();
 
576
        break;
 
577
    case BottomLeft:
 
578
        ret = (int) optionGetBottomLeftCornerAction ();
 
579
        break;
 
580
    case BottomRight:
 
581
        ret = (int) optionGetBottomRightCornerAction ();
 
582
        break;
 
583
    case NoEdge:
 
584
    default:
 
585
        ret = -1;
 
586
        break;
 
587
    }
 
588
 
 
589
    return ret;
 
590
}
 
591
 
 
592
void
 
593
GridScreen::handleEvent (XEvent *event)
 
594
{
 
595
    CompOutput out;
 
596
    CompWindow *w;
 
597
    bool       check = false;
 
598
 
 
599
    screen->handleEvent (event);
 
600
 
 
601
    if (event->type != MotionNotify || !mGrabWindow)
 
602
        return;
 
603
 
 
604
    out = screen->outputDevs ().at (
 
605
                   screen->outputDeviceForPoint (CompPoint (pointerX, pointerY)));
 
606
 
 
607
    /* Detect corners first */
 
608
    /* Bottom Left */
 
609
    if (pointerY > (out.y () + out.height () - optionGetBottomEdgeThreshold()) &&
 
610
        pointerX < out.x () + optionGetLeftEdgeThreshold())
 
611
        edge = BottomLeft;
 
612
    /* Bottom Right */
 
613
    else if (pointerY > (out.y () + out.height () - optionGetBottomEdgeThreshold()) &&
 
614
             pointerX > (out.x () + out.width () - optionGetRightEdgeThreshold()))
 
615
        edge = BottomRight;
 
616
    /* Top Left */
 
617
    else if (pointerY < optionGetTopEdgeThreshold() &&
 
618
            pointerX < optionGetLeftEdgeThreshold())
 
619
        edge = TopLeft;
 
620
    /* Top Right */
 
621
    else if (pointerY < out.y () + optionGetTopEdgeThreshold() &&
 
622
             pointerX > (out.x () + out.width () - optionGetRightEdgeThreshold()))
 
623
        edge = TopRight;
 
624
    /* Left */
 
625
    else if (pointerX < out.x () + optionGetLeftEdgeThreshold())
 
626
        edge = Left;
 
627
    /* Right */
 
628
    else if (pointerX > (out.x () + out.width () - optionGetRightEdgeThreshold()))
 
629
        edge = Right;
 
630
    /* Top */
 
631
    else if (pointerY < out.y () + optionGetTopEdgeThreshold())
 
632
        edge = Top;
 
633
    /* Bottom */
 
634
    else if (pointerY > (out.y () + out.height () - optionGetBottomEdgeThreshold()))
 
635
        edge = Bottom;
 
636
    /* No Edge */
 
637
    else
 
638
        edge = NoEdge;
 
639
 
 
640
    /* Detect when cursor enters another output */
 
641
 
 
642
    currentWorkarea = screen->getWorkareaForOutput
 
643
                            (screen->outputDeviceForPoint (pointerX, pointerY));
 
644
    if (lastWorkarea != currentWorkarea)
 
645
    {
 
646
        lastWorkarea = currentWorkarea;
 
647
 
 
648
        if (cScreen)
 
649
            cScreen->damageRegion (desiredSlot);
 
650
 
 
651
        initiateCommon (0, 0, o, typeToMask (edgeToGridType ()), false, false);
 
652
 
 
653
        if (cScreen)
 
654
            cScreen->damageRegion (desiredSlot);
 
655
    }
 
656
 
 
657
    /* Detect edge region change */
 
658
 
 
659
    if (lastEdge != edge)
 
660
    {
 
661
                lastSlot = desiredSlot;
 
662
 
 
663
                if (edge == NoEdge)
 
664
                        desiredSlot.setGeometry (0, 0, 0, 0);
 
665
 
 
666
                if (cScreen)
 
667
                        cScreen->damageRegion (desiredSlot);
 
668
 
 
669
                check = initiateCommon (NULL, 0, o, typeToMask (edgeToGridType ()), false, false);
 
670
 
 
671
                if (cScreen)
 
672
                        cScreen->damageRegion (desiredSlot);
 
673
 
 
674
                if (lastSlot != desiredSlot)
 
675
                {
 
676
                        if (animations.size ())
 
677
                                /* Begin fading previous animation instance */
 
678
                                animations.at (animations.size () - 1).fadingOut = true;
 
679
 
 
680
                        if (edge != NoEdge && check)
 
681
                        {
 
682
                                CompWindow *cw = screen->findWindow (screen->activeWindow ());
 
683
                                animations.push_back (Animation ());
 
684
                                int current = animations.size () - 1;
 
685
                                animations.at (current).fromRect        = cw->serverBorderRect ();
 
686
                                animations.at (current).currentRect     = cw->serverBorderRect ();
 
687
                                animations.at (current).timer = animations.at (current).duration;
 
688
                                animations.at (current).targetRect = desiredSlot;
 
689
 
 
690
                                if (lastEdge == NoEdge || !animating)
 
691
                                {
 
692
                                        /* Cursor has entered edge region from non-edge region */
 
693
                                        animating = true;
 
694
                                        glScreen->glPaintOutputSetEnabled (this, true);
 
695
                                        cScreen->preparePaintSetEnabled (this, true);
 
696
                                        cScreen->donePaintSetEnabled (this, true);
 
697
                                }
 
698
                        }
 
699
                }
 
700
 
 
701
                lastEdge = edge;
 
702
    }
 
703
 
 
704
    w = screen->findWindow (CompOption::getIntOptionNamed (o, "window"));
 
705
 
 
706
    if (w)
 
707
    {
 
708
        GRID_WINDOW (w);
 
709
 
 
710
        if ((gw->pointerBufDx > SNAPOFF_THRESHOLD ||
 
711
             gw->pointerBufDy > SNAPOFF_THRESHOLD ||
 
712
             gw->pointerBufDx < -SNAPOFF_THRESHOLD ||
 
713
             gw->pointerBufDy < -SNAPOFF_THRESHOLD) &&
 
714
             gw->isGridResized &&
 
715
             optionGetSnapbackWindows ())
 
716
                restoreWindow (0, 0, o);
 
717
    }
 
718
}
 
719
 
 
720
void
 
721
GridWindow::grabNotify (int          x,
 
722
                        int          y,
 
723
                        unsigned int state,
 
724
                        unsigned int mask)
 
725
{
 
726
    if (mask & (CompWindowGrabMoveMask | CompWindowGrabButtonMask))
 
727
    {
 
728
        gScreen->o[0].value ().set ((int) window->id ());
 
729
 
 
730
        screen->handleEventSetEnabled (gScreen, true);
 
731
        gScreen->mGrabWindow = window;
 
732
        pointerBufDx = pointerBufDy = 0;
 
733
        grabMask = mask;
 
734
 
 
735
        if (!isGridResized && !isGridMaximized && gScreen->optionGetSnapbackWindows ())
 
736
            /* Store size not including borders when grabbing with cursor */
 
737
            originalSize = gScreen->slotToRect(window,
 
738
                                                    window->serverBorderRect ());
 
739
    }
 
740
 
 
741
    if (mask & CompWindowGrabResizeMask)
 
742
    {
 
743
        isGridResized = false;
 
744
        resizeCount = 0;
 
745
    }
 
746
 
 
747
    window->grabNotify (x, y, state, mask);
 
748
}
 
749
 
 
750
void
 
751
GridWindow::ungrabNotify ()
 
752
{
 
753
    if (window == gScreen->mGrabWindow)
 
754
    {
 
755
        gScreen->initiateCommon
 
756
                        (NULL, 0, gScreen->o, gScreen->typeToMask (gScreen->edgeToGridType ()), true,
 
757
                         gScreen->edge != gScreen->lastResizeEdge);
 
758
 
 
759
        screen->handleEventSetEnabled (gScreen, false);
 
760
        grabMask = 0;
 
761
        gScreen->mGrabWindow = NULL;
 
762
        gScreen->o[0].value ().set (0);
 
763
        gScreen->cScreen->damageRegion (gScreen->desiredSlot);
 
764
    }
 
765
 
 
766
    gScreen->lastResizeEdge = gScreen->edge;
 
767
    gScreen->edge = NoEdge;
 
768
 
 
769
    window->ungrabNotify ();
 
770
}
 
771
 
 
772
void
 
773
GridWindow::moveNotify (int dx, int dy, bool immediate)
 
774
{
 
775
    window->moveNotify (dx, dy, immediate);
 
776
 
 
777
    if (isGridResized && !isGridMaximized && !GridScreen::get (screen)->mSwitchingVp)
 
778
    {
 
779
        if (window->grabbed () && (grabMask & CompWindowGrabMoveMask))
 
780
        {
 
781
            pointerBufDx += dx;
 
782
            pointerBufDy += dy;
 
783
        }
 
784
 
 
785
        /* Do not allow the window to be moved while it
 
786
         * is resized */
 
787
        dx = currentSize.x () - window->geometry ().x ();
 
788
        dy = currentSize.y () - window->geometry ().y ();
 
789
 
 
790
        printf ("offset move\n");
 
791
 
 
792
        window->move (dx, dy);
 
793
    }
 
794
}
 
795
 
 
796
void
 
797
GridWindow::stateChangeNotify (unsigned int lastState)
 
798
{
 
799
    if (lastState & MAXIMIZE_STATE &&
 
800
        !(window->state () & MAXIMIZE_STATE))
 
801
        lastTarget = GridUnknown;
 
802
    else if (!(lastState & MAXIMIZE_STATE) &&
 
803
             window->state () & MAXIMIZE_STATE)
 
804
    {
 
805
        lastTarget = GridMaximize;
 
806
        if (window->grabbed ())
 
807
        {
 
808
            originalSize = gScreen->slotToRect (window,
 
809
                                                window->serverBorderRect ());
 
810
        }
 
811
    }
 
812
 
 
813
    window->stateChangeNotify (lastState);
 
814
}
 
815
 
 
816
void
 
817
GridWindow::windowNotify (CompWindowNotify n)
 
818
{
 
819
    if (n == CompWindowNotifyFrameUpdate)
 
820
    {
 
821
        if (isGridMaximized && !((window->state () & MAXIMIZE_STATE) == MAXIMIZE_STATE))
 
822
        {
 
823
            unsigned int valueMask = 0;
 
824
            XWindowChanges xwc;
 
825
 
 
826
            int dw = (lastBorder.left + lastBorder.right) - 
 
827
                      (window->border ().left + window->border ().right);
 
828
                        
 
829
            int dh = (lastBorder.top + lastBorder.bottom) - 
 
830
                        (window->border ().top + window->border ().bottom);
 
831
 
 
832
            if (dw != 0)
 
833
                valueMask |= CWWidth;
 
834
            if (dh != 0)
 
835
                valueMask |= CWHeight;
 
836
            xwc.width = window->serverGeometry ().width () + dw;
 
837
            xwc.height = window->serverGeometry ().height () + dh;
 
838
 
 
839
            window->configureXWindow (valueMask, &xwc);
 
840
        }
 
841
 
 
842
        lastBorder = window->border ();
 
843
    }
 
844
 
 
845
    window->windowNotify (n);
 
846
}
 
847
bool
 
848
GridScreen::restoreWindow (CompAction         *action,
 
849
                           CompAction::State  state,
 
850
                           CompOption::Vector &option)
 
851
{
 
852
    XWindowChanges xwc;
 
853
    CompWindow *cw = screen->findWindow (screen->activeWindow ());
 
854
 
 
855
    if (!cw)
 
856
        return false;
 
857
 
 
858
    GRID_WINDOW (cw);
 
859
 
 
860
    if (!gw->isGridResized)
 
861
        return false;
 
862
 
 
863
    if (gw->isGridMaximized & !(cw->state () & MAXIMIZE_STATE))
 
864
            gw->isGridMaximized = false;
 
865
    else
 
866
    {
 
867
        if (cw == mGrabWindow)
 
868
        {
 
869
            xwc.x = pointerX - (gw->originalSize.width () >> 1);
 
870
            xwc.y = pointerY + (cw->border ().top >> 1);
 
871
        }
 
872
        else
 
873
        {
 
874
            xwc.x = gw->originalSize.x ();
 
875
            xwc.y = gw->originalSize.y ();
 
876
        }
 
877
        xwc.width  = gw->originalSize.width ();
 
878
        xwc.height = gw->originalSize.height ();
 
879
        cw->maximize (0);
 
880
        gw->currentSize = CompRect ();
 
881
        printf ("attempting snapBack\n");
 
882
        cw->configureXWindow (CWX | CWY | CWWidth | CWHeight, &xwc);
 
883
        gw->pointerBufDx = 0;
 
884
        gw->pointerBufDy = 0;
 
885
    }
 
886
    gw->isGridResized = false;
 
887
    gw->resizeCount = 0;
 
888
    gw->lastTarget = GridUnknown;
 
889
 
 
890
    return true;
 
891
}
 
892
 
 
893
void
 
894
GridScreen::snapbackOptionChanged (CompOption *option,
 
895
                                    Options    num)
 
896
{
 
897
    GRID_WINDOW (screen->findWindow
 
898
                    (CompOption::getIntOptionNamed (o, "window")));
 
899
    gw->isGridResized = false;
 
900
    gw->isGridMaximized = false;
 
901
    gw->resizeCount = 0;
 
902
}
 
903
 
 
904
void
 
905
GridScreen::preparePaint (int msSinceLastPaint)
 
906
{
 
907
        std::vector<Animation>::iterator iter;
 
908
 
 
909
        for (iter = animations.begin (); iter != animations.end (); iter++)
 
910
        {
 
911
                Animation& anim = *iter;
 
912
                anim.timer -= msSinceLastPaint;
 
913
 
 
914
                if (anim.timer < 0)
 
915
                        anim.timer = 0;
 
916
 
 
917
                if (anim.fadingOut)
 
918
                        anim.opacity -= msSinceLastPaint * 0.002;
 
919
                else
 
920
                        if (anim.opacity < 1.0f)
 
921
                                anim.opacity = anim.progress * anim.progress;
 
922
                        else
 
923
                                anim.opacity = 1.0f;
 
924
 
 
925
                if (anim.opacity < 0)
 
926
                {
 
927
                        anim.opacity = 0.0f;
 
928
                        anim.fadingOut = false;
 
929
                        anim.complete = true;
 
930
                }
 
931
 
 
932
                anim.progress = (anim.duration - anim.timer) / anim.duration;
 
933
        }
 
934
 
 
935
    cScreen->preparePaint (msSinceLastPaint);
 
936
}
 
937
 
 
938
void
 
939
GridScreen::donePaint ()
 
940
{
 
941
        std::vector<Animation>::iterator iter;
 
942
 
 
943
        for (iter = animations.begin (); iter != animations.end (); )
 
944
        {
 
945
                Animation& anim = *iter;
 
946
                if (anim.complete)
 
947
                        iter = animations.erase(iter);
 
948
                else
 
949
                        iter++;
 
950
        }
 
951
 
 
952
        if (animations.empty ())
 
953
        {
 
954
                cScreen->preparePaintSetEnabled (this, false);
 
955
                cScreen->donePaintSetEnabled (this, false);
 
956
                if (edge == NoEdge)
 
957
                        glScreen->glPaintOutputSetEnabled (this, false);
 
958
                animations.clear ();
 
959
                animating = false;
 
960
        }
 
961
 
 
962
        cScreen->damageScreen ();
 
963
 
 
964
    cScreen->donePaint ();
 
965
}
 
966
 
 
967
Animation::Animation ()
 
968
{
 
969
        progress = 0.0f;
 
970
        fromRect = CompRect (0, 0, 0, 0);
 
971
        targetRect = CompRect (0, 0, 0, 0);
 
972
        currentRect = CompRect (0, 0, 0, 0);
 
973
        opacity = 0.0f;
 
974
        timer = 0.0f;
 
975
        duration = 250;
 
976
        complete = false;
 
977
        fadingOut = false;
 
978
}
 
979
 
 
980
 
 
981
GridScreen::GridScreen (CompScreen *screen) :
 
982
    PluginClassHandler<GridScreen, CompScreen> (screen),
 
983
    cScreen (CompositeScreen::get (screen)),
 
984
    glScreen (GLScreen::get (screen)),
 
985
    centerCheck (false),
 
986
    mGrabWindow (NULL),
 
987
    animating (false),
 
988
    mSwitchingVp (false)
 
989
{
 
990
    o.push_back (CompOption ("window", CompOption::TypeInt));
 
991
 
 
992
    ScreenInterface::setHandler (screen, false);
 
993
    screen->handleCompizEventSetEnabled (this, true);
 
994
    CompositeScreenInterface::setHandler (cScreen, false);
 
995
    GLScreenInterface::setHandler (glScreen, false);
 
996
 
 
997
    edge = lastEdge = lastResizeEdge = NoEdge;
 
998
    currentWorkarea = lastWorkarea = screen->getWorkareaForOutput
 
999
                            (screen->outputDeviceForPoint (pointerX, pointerY));
 
1000
    gridProps[GridUnknown] = GridProps {0,1, 1,1};
 
1001
    gridProps[GridBottomLeft]  = GridProps {0,1, 2,2};
 
1002
    gridProps[GridBottom]  = GridProps {0,1, 1,2};
 
1003
    gridProps[GridBottomRight] = GridProps {1,1, 2,2};
 
1004
    gridProps[GridLeft]  = GridProps {0,0, 2,1};
 
1005
    gridProps[GridCenter]  = GridProps{0,0, 1,1};
 
1006
    gridProps[GridRight]  = GridProps {1,0, 2,1};
 
1007
    gridProps[GridTopLeft]  = GridProps{0,0, 2,2};
 
1008
    gridProps[GridTop]  = GridProps {0,0, 1,2};
 
1009
    gridProps[GridTopRight]  = GridProps {0,0, 1,2};
 
1010
    gridProps[GridMaximize]  = GridProps {0,0, 1,1};
 
1011
 
 
1012
        animations.clear ();
 
1013
 
 
1014
#define GRIDSET(opt,where,resize,key)                                          \
 
1015
    optionSet##opt##Initiate (boost::bind (&GridScreen::initiateCommon, this,  \
 
1016
                                           _1, _2, _3, where, resize, key))
 
1017
 
 
1018
    GRIDSET (PutCenterKey, GridWindowType::GridCenter, true, true);
 
1019
    GRIDSET (PutLeftKey, GridWindowType::GridLeft, true, true);
 
1020
    GRIDSET (PutRightKey, GridWindowType::GridRight, true, true);
 
1021
    GRIDSET (PutTopKey, GridWindowType::GridTop, true, true);
 
1022
    GRIDSET (PutBottomKey, GridWindowType::GridBottom, true, true);
 
1023
    GRIDSET (PutTopleftKey, GridWindowType::GridTopLeft, true, true);
 
1024
    GRIDSET (PutToprightKey, GridWindowType::GridTopRight, true, true);
 
1025
    GRIDSET (PutBottomleftKey, GridWindowType::GridBottomLeft, true, true);
 
1026
    GRIDSET (PutBottomrightKey, GridWindowType::GridBottomRight, true, true);
 
1027
    GRIDSET (PutMaximizeKey, GridWindowType::GridMaximize, true, true);
 
1028
 
 
1029
#undef GRIDSET
 
1030
 
 
1031
    optionSetSnapbackWindowsNotify (boost::bind (&GridScreen::
 
1032
                                    snapbackOptionChanged, this, _1, _2));
 
1033
 
 
1034
    optionSetPutRestoreKeyInitiate (boost::bind (&GridScreen::
 
1035
                                            restoreWindow, this, _1, _2, _3));
 
1036
 
 
1037
}
 
1038
 
 
1039
GridWindow::GridWindow (CompWindow *window) :
 
1040
    PluginClassHandler <GridWindow, CompWindow> (window),
 
1041
    window (window),
 
1042
    gScreen (GridScreen::get (screen)),
 
1043
    isGridResized (false),
 
1044
    isGridMaximized (false),
 
1045
    grabMask (0),
 
1046
    pointerBufDx (0),
 
1047
    pointerBufDy (0),
 
1048
    resizeCount (0),
 
1049
    lastTarget (GridUnknown)
 
1050
{
 
1051
    WindowInterface::setHandler (window);
 
1052
}
 
1053
 
 
1054
GridWindow::~GridWindow ()
 
1055
{
 
1056
    if (gScreen->mGrabWindow == window)
 
1057
        gScreen->mGrabWindow = NULL;
 
1058
 
 
1059
    gScreen->o[0].value ().set (0);
 
1060
}
 
1061
 
 
1062
/* Initial plugin init function called. Checks to see if we are ABI
 
1063
 * compatible with core, otherwise unload */
 
1064
 
 
1065
bool
 
1066
GridPluginVTable::init ()
 
1067
{
 
1068
    if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
 
1069
        return false;
 
1070
 
 
1071
    return true;
 
1072
}