~hypodermia/ubuntu/oneiric/compiz/fix-for-bug-301174

« back to all changes in this revision

Viewing changes to .pc/01_bzr_fix_grid_on_multimonitor.patch/plugins/grid/src/grid.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2011-04-07 18:06:44 UTC
  • mfrom: (0.168.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20110407180644-7xwnirf7k3zotc2w
Tags: 1:0.9.4+bzr20110407-0ubuntu2
* New upstream snapshot:
  - fix unity-window-decorator crashed with SIGSEGV in event_filter_funct
    (LP: #711561)
* debian/patches/086_new_grid_defaults.patch:
  - change threshold to 15 on sides and 20 on top to work well with the new
    animtion
* debian/patches/01_bzr_fix_grid_on_multimonitor.patch,
  01_bzr_fix_resize.patch, 01_bzr_fix_grid_premultiply.patch:
  - from upstream bzr, fix grid on multimonitor and colors handling
* debian/patches/086_new_grid_defaults.patch,
  debian/patches/029_default_options.patch:
  - set the resize grid shadow to orange (LP: #752711)

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