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

« back to all changes in this revision

Viewing changes to snap/src/snap.cpp

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Compiz snap plugin
3
 
 * Author : Guillaume "iXce" Seguin
4
 
 * Email  : ixce@beryl-project.org
5
 
 *
6
 
 * Ported to compiz by : Patrick "marex" Niklaus
7
 
 * Email               : marex@beryl-project.org
8
 
 *
9
 
 * Ported to C++ by : Travis Watkins
10
 
 * Email            : amaranth@ubuntu.com
11
 
 *
12
 
 * Copyright (C) 2009 Guillaume Seguin
13
 
 *
14
 
 * This program is free software; you can redistribute it and/or
15
 
 * modify it under the terms of the GNU General Public License
16
 
 * as published by the Free Software Foundation; either version 2
17
 
 * of the License, or (at your option) any later version.
18
 
 *
19
 
 * This program is distributed in the hope that it will be useful,
20
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 
 * GNU General Public License for more details.
23
 
 *
24
 
 * You should have received a copy of the GNU General Public License
25
 
 * along with this program; if not, write to the Free Software
26
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
27
 
 */
28
 
 
29
 
/*
30
 
 * TODO
31
 
 *  - Apply Edge Resistance to resize
32
 
 */
33
 
 
34
 
#include <stdlib.h>
35
 
#include <string.h>
36
 
#include <math.h>
37
 
 
38
 
#include "snap.h"
39
 
 
40
 
 
41
 
COMPIZ_PLUGIN_20090315 (snap, SnapPluginVTable);
42
 
 
43
 
// helper functions
44
 
 
45
 
/*
46
 
 * Wrapper functions to avoid infinite notify loops
47
 
 */
48
 
void
49
 
SnapWindow::move (int dx, int dy)
50
 
{
51
 
    skipNotify = true;
52
 
    window->move (dx, dy, true);
53
 
    screen->warpPointer (dx, dy);
54
 
    skipNotify = false;
55
 
}
56
 
 
57
 
void
58
 
SnapWindow::resize (int dx, int dy, int dwidth, int dheight)
59
 
{
60
 
    CompWindow::Geometry geometry = window->geometry ();
61
 
    skipNotify = true;
62
 
    window->resize (geometry.x () + dx, geometry.y () + dy,
63
 
                    geometry.width () + dwidth, geometry.height () + dheight,
64
 
                    geometry.border ());
65
 
    skipNotify = false;
66
 
}
67
 
 
68
 
void
69
 
SnapWindow::addEdge (Window   id,
70
 
                     int       position,
71
 
                     int      start,
72
 
                     int      end,
73
 
                     EdgeType type,
74
 
                     bool     screenEdge)
75
 
{
76
 
    Edge edge;
77
 
 
78
 
    edge.position = position;
79
 
    edge.start = start;
80
 
    edge.end = end;
81
 
    edge.type = type;
82
 
    edge.screenEdge = screenEdge;
83
 
    edge.snapped = false;
84
 
    edge.passed = false;
85
 
    edge.id = id;
86
 
 
87
 
    edges.push_back (edge);
88
 
}
89
 
 
90
 
/*
91
 
 * Add an edge for each rectangle of the region
92
 
 */
93
 
void
94
 
SnapWindow::addRegionEdges (Edge *parent, CompRegion region)
95
 
{
96
 
    int position, start, end;
97
 
 
98
 
    foreach (const CompRect &r, region.rects ())
99
 
    {
100
 
        switch (parent->type)
101
 
        {
102
 
        case LeftEdge:
103
 
        case RightEdge:
104
 
            position = r.x1 ();
105
 
            start = r.y1 ();
106
 
            end = r.y2 ();
107
 
            break;
108
 
        case TopEdge:
109
 
        case BottomEdge:
110
 
        default:
111
 
            position = r.y1 ();
112
 
            start = r.x1 ();
113
 
            end = r.x2 ();
114
 
        }
115
 
        
116
 
        addEdge (parent->id, position, start, end,
117
 
                 parent->type, parent->screenEdge);
118
 
        edges.back ().passed = parent->passed;
119
 
    }
120
 
}
121
 
 
122
 
/* Checks if a window is considered a snap window. If it's
123
 
 * not visible, returns false. If it's a panel and we're
124
 
 * snapping to screen edges, it's considered a snap-window.
125
 
 */
126
 
 
127
 
#define UNLIKELY(x) __builtin_expect(!!(x),0)
128
 
 
129
 
static inline bool
130
 
isSnapWindow (CompWindow *w)
131
 
{
132
 
    SNAP_SCREEN (screen);
133
 
 
134
 
    if (UNLIKELY(!w))
135
 
        return false;
136
 
    if (!w->isViewable ())
137
 
        return false;
138
 
    if ((w->type () & SNAP_WINDOW_TYPE) && 
139
 
        (ss->optionGetEdgesCategoriesMask () & EdgesCategoriesWindowEdgesMask))
140
 
        return true;
141
 
    if (w->struts () && 
142
 
        (ss->optionGetEdgesCategoriesMask () & EdgesCategoriesScreenEdgesMask))
143
 
        return true;
144
 
    return false;
145
 
}
146
 
 
147
 
// Edges update functions ------------------------------------------------------
148
 
/*
149
 
 * Detect visible windows edges
150
 
 */
151
 
void
152
 
SnapWindow::updateWindowsEdges ()
153
 
{
154
 
    CompRegion edgeRegion, resultRegion;
155
 
    CompRect   input;
156
 
    bool       remove = false;
157
 
 
158
 
    // First add all the windows
159
 
    foreach (CompWindow *w, screen->windows ())
160
 
    {
161
 
 
162
 
        // Just check that we're not trying to snap to current window,
163
 
        // that the window is not invisible and of a valid type
164
 
        if (w == window || !isSnapWindow (w))
165
 
        {
166
 
            continue;
167
 
        }
168
 
 
169
 
        input = w->borderRect ();
170
 
        addEdge (w->id (), input.top (), input.left (),
171
 
                 input.right (), TopEdge, false);
172
 
        addEdge (w->id (), input.bottom (), input.left (),
173
 
                 input.right (), BottomEdge, false);
174
 
        addEdge (w->id (), input.left (), input.top (),
175
 
                 input.bottom (), LeftEdge, false);
176
 
        addEdge (w->id (), input.right (), input.top (),
177
 
                 input.bottom (), RightEdge, false);
178
 
    }
179
 
 
180
 
    // Now strip invisible edges
181
 
    // Loop through all the windows stack, and through all the edges
182
 
    // If an edge has been passed, check if it's in the region window,
183
 
    // if the edge is fully under the window, drop it, or if it's only
184
 
    // partly covered, cut it/split it in one/two smaller visible edges
185
 
    foreach (CompWindow *w, screen->windows ())
186
 
    {
187
 
        if (w == window || !isSnapWindow (w))
188
 
            continue;
189
 
 
190
 
        // can't use foreach here because we need the iterator for erase()
191
 
        for (std::list<Edge>::iterator it = edges.begin (); it != edges.end (); )
192
 
        {
193
 
            Edge     *e = &*it;
194
 
            CompRect rect;
195
 
 
196
 
            if (!e->passed)
197
 
            {
198
 
                if (e->id == w->id ())
199
 
                    e->passed = true;
200
 
                it++;
201
 
                continue;
202
 
            }
203
 
 
204
 
            switch (e->type)
205
 
            {
206
 
                case LeftEdge:
207
 
                case RightEdge:
208
 
                    rect.setGeometry (e->position,
209
 
                                      e->start,
210
 
                                      1,
211
 
                                      e->end - e->start);
212
 
                    break;
213
 
                case TopEdge:
214
 
                case BottomEdge:
215
 
                default:
216
 
                    rect.setGeometry (e->start,
217
 
                                      e->position,
218
 
                                      e->end - e->start,
219
 
                                      1);
220
 
            }
221
 
 
222
 
            // If the edge is in the window region, remove it,
223
 
            // if it's partly in the region, split it
224
 
            edgeRegion = CompRegion (rect);
225
 
            resultRegion = edgeRegion - w->region ();
226
 
            if (resultRegion.isEmpty ())
227
 
            {
228
 
                remove = true;
229
 
            }
230
 
            else if (edgeRegion != resultRegion)
231
 
            {
232
 
                addRegionEdges (e, resultRegion);
233
 
                remove = true;
234
 
            }
235
 
 
236
 
            if (remove)
237
 
            {
238
 
                it = edges.erase (it);
239
 
                remove = false;
240
 
            }
241
 
            else
242
 
            {
243
 
                it++;
244
 
            }
245
 
        }
246
 
    }
247
 
}
248
 
 
249
 
/*
250
 
 * Loop on outputDevs and add the extents as edges
251
 
 * Note that left side is a right edge, right side a left edge,
252
 
 * top side a bottom edge and bottom side a top edge,
253
 
 * since they will be snapped as the right/left/bottom/top edge of a window
254
 
 */
255
 
void
256
 
SnapWindow::updateScreenEdges ()
257
 
{
258
 
    CompRegion edgeRegion, resultRegion;
259
 
    bool remove = false;
260
 
 
261
 
    foreach (CompOutput output, screen->outputDevs ())
262
 
    {
263
 
        const CompRect& area = output.workArea ();
264
 
        addEdge (0, area.top (), area.left (), area.right () - 1,
265
 
                 BottomEdge, true);
266
 
        addEdge (0, area.bottom (), area.left (), area.right () - 1,
267
 
                 TopEdge, true);
268
 
        addEdge (0, area.left (), area.top (), area.bottom () - 1,
269
 
                 RightEdge, true);
270
 
        addEdge (0, area.right (), area.top (), area.bottom () - 1,
271
 
                 LeftEdge, true);
272
 
    }
273
 
 
274
 
    // Drop screen edges parts that are under struts, basically apply the
275
 
    // same strategy than for windows edges visibility
276
 
    foreach (CompWindow *w, screen->windows ())
277
 
    {
278
 
        if (w == window || !w->struts ())
279
 
            continue;
280
 
 
281
 
        for (std::list<Edge>::iterator it = edges.begin (); it != edges.end ();)
282
 
        {
283
 
            Edge     *e = &*it;
284
 
            CompRect rect;
285
 
 
286
 
            if (!e->screenEdge)
287
 
            {
288
 
                it++;
289
 
                continue;
290
 
            }
291
 
 
292
 
            switch (e->type)
293
 
            {
294
 
                case LeftEdge:
295
 
                case RightEdge:
296
 
                    rect.setGeometry (e->position,
297
 
                                      e->start,
298
 
                                      1,
299
 
                                      e->end - e->start);
300
 
                    break;
301
 
                case TopEdge:
302
 
                case BottomEdge:
303
 
                default:
304
 
                    rect.setGeometry (e->start,
305
 
                                      e->position,
306
 
                                      e->end - e->start,
307
 
                                      1);
308
 
            }
309
 
 
310
 
            edgeRegion = CompRegion (rect);
311
 
            resultRegion = edgeRegion - w->region ();
312
 
            if (resultRegion.isEmpty ())
313
 
            {
314
 
                remove = true;
315
 
            }
316
 
            else if (edgeRegion != resultRegion)
317
 
            {
318
 
                addRegionEdges (e, resultRegion);
319
 
                remove = true;
320
 
            }
321
 
 
322
 
            if (remove)
323
 
            {
324
 
                it = edges.erase (it);
325
 
                remove = false;
326
 
            }
327
 
            else
328
 
            {
329
 
                it++;
330
 
            }
331
 
        }
332
 
    }
333
 
}
334
 
 
335
 
/*
336
 
 * Clean edges and fill it again with appropriate edges
337
 
 */
338
 
void
339
 
SnapWindow::updateEdges ()
340
 
{
341
 
    SNAP_SCREEN (screen);
342
 
 
343
 
    edges.clear ();
344
 
    updateWindowsEdges ();
345
 
 
346
 
    if (ss->optionGetEdgesCategoriesMask () & EdgesCategoriesScreenEdgesMask)
347
 
        updateScreenEdges ();
348
 
}
349
 
 
350
 
// Edges checking functions (move) ---------------------------------------------
351
 
 
352
 
/*
353
 
 * Find nearest edge in the direction set by "type",
354
 
 * w is the grabbed window, position/start/end are the window edges coordinates
355
 
 * before : if true the window has to be before the edge (top/left being origin)
356
 
 * snapDirection : just an helper, related to type
357
 
 */
358
 
void
359
 
SnapWindow::moveCheckNearestEdge (int position,
360
 
                                  int start,
361
 
                                  int end,
362
 
                                  bool before,
363
 
                                  EdgeType type,
364
 
                                  int snapDirection)
365
 
{
366
 
    SNAP_SCREEN (screen);
367
 
 
368
 
    Edge *edge = &edges.front ();
369
 
    int dist, min = 65535;
370
 
 
371
 
    foreach (Edge &current, edges)
372
 
    {
373
 
        // Skip wrong type or outbound edges
374
 
        if (current.type != type || current.end < start || current.start > end)
375
 
            continue;
376
 
 
377
 
        // Compute distance
378
 
        dist = before ? position - current.position : current.position - position;
379
 
        // Update minimum distance if needed
380
 
        if (dist < min && dist >= 0)
381
 
        {
382
 
            min = dist;
383
 
            edge = &current;
384
 
        }
385
 
        // 0-dist edge, just break
386
 
        if (dist == 0)
387
 
            break;
388
 
        // Unsnap edges that aren't snapped anymore
389
 
        if (current.snapped && dist > ss->optionGetResistanceDistance ())
390
 
            current.snapped = false;
391
 
    }
392
 
    // We found a 0-dist edge, or we have a snapping candidate
393
 
    if (min == 0 || (min <= ss->optionGetAttractionDistance ()
394
 
        && ss->optionGetSnapTypeMask () & SnapTypeEdgeAttractionMask))
395
 
    {
396
 
        // Update snapping data
397
 
        if (ss->optionGetSnapTypeMask () & SnapTypeEdgeResistanceMask)
398
 
        {
399
 
            snapped = true;
400
 
            this->snapDirection |= snapDirection;
401
 
        }
402
 
        // Attract the window if needed, moving it of the correct dist
403
 
        if (min != 0 && !edge->snapped)
404
 
        {
405
 
            edge->snapped = true;
406
 
            switch (type)
407
 
            {
408
 
            case LeftEdge:
409
 
                move (min, 0);
410
 
                break;
411
 
            case RightEdge:
412
 
                move (-min, 0);
413
 
                break;
414
 
            case TopEdge:
415
 
                move (0, min);
416
 
                break;
417
 
            case BottomEdge:
418
 
                move (0, -min);
419
 
                break;
420
 
            default:
421
 
                break;
422
 
            }
423
 
        }
424
 
    }
425
 
}
426
 
 
427
 
/*
428
 
 * Call the previous function for each of the 4 sides of the window
429
 
 */
430
 
void
431
 
SnapWindow::moveCheckEdges ()
432
 
{
433
 
    CompRect input (window->borderRect ());
434
 
    moveCheckNearestEdge (input.left (), input.top (), input.bottom (),
435
 
                          true, RightEdge, HorizontalSnap);
436
 
    moveCheckNearestEdge (input.right (), input.top (), input.bottom (),
437
 
                          false, LeftEdge, HorizontalSnap);
438
 
    moveCheckNearestEdge (input.top (), input.left (), input.right (),
439
 
                          true, BottomEdge, VerticalSnap);
440
 
    moveCheckNearestEdge (input.bottom (), input.left (), input.right (),
441
 
                          false, TopEdge, VerticalSnap);
442
 
}
443
 
 
444
 
// Edges checking functions (resize) -------------------------------------------
445
 
 
446
 
/*
447
 
 * Similar function for Snap on Resize
448
 
 */
449
 
void
450
 
SnapWindow::resizeCheckNearestEdge (int position,
451
 
                                    int start,
452
 
                                    int end,
453
 
                                    bool before,
454
 
                                    EdgeType type,
455
 
                                    int snapDirection)
456
 
{
457
 
    SNAP_SCREEN (screen);
458
 
 
459
 
    Edge *edge = &edges.front ();
460
 
    int dist, min = 65535;
461
 
 
462
 
    foreach (Edge &current, edges)
463
 
    {
464
 
        // Skip wrong type or outbound edges
465
 
        if (current.type != type || current.end < start || current.start > end)
466
 
            continue;
467
 
 
468
 
        // Compute distance
469
 
        dist = before ? position - current.position : current.position - position;
470
 
        // Update minimum distance if needed
471
 
        if (dist < min && dist >= 0)
472
 
        {
473
 
            min = dist;
474
 
            edge = &current;
475
 
        }
476
 
        // 0-dist edge, just break
477
 
        if (dist == 0)
478
 
            break;
479
 
        // Unsnap edges that aren't snapped anymore
480
 
        if (current.snapped && dist > ss->optionGetResistanceDistance ())
481
 
            current.snapped = false;
482
 
    }
483
 
    // We found a 0-dist edge, or we have a snapping candidate
484
 
    if (min == 0 || (min <= ss->optionGetAttractionDistance ()
485
 
        && ss->optionGetSnapTypeMask () & SnapTypeEdgeAttractionMask))
486
 
    {
487
 
        // Update snapping data
488
 
        if (ss->optionGetSnapTypeMask () & SnapTypeEdgeResistanceMask)
489
 
        {
490
 
            snapped = true;
491
 
            this->snapDirection |= snapDirection;
492
 
        }
493
 
        // FIXME : this needs resize-specific code.
494
 
        // Attract the window if needed, moving it of the correct dist
495
 
        if (min != 0 && !edge->snapped)
496
 
        {
497
 
            edge->snapped = true;
498
 
            switch (type)
499
 
            {
500
 
            case LeftEdge:
501
 
                resize (min, 0, 0, 0);
502
 
                break;
503
 
            case RightEdge:
504
 
                resize (-min, 0, 0, 0);
505
 
                break;
506
 
            case TopEdge:
507
 
                resize (0, min, 0, 0);
508
 
                break;
509
 
            case BottomEdge:
510
 
                resize (0, -min, 0, 0);
511
 
                break;
512
 
            default:
513
 
                break;
514
 
            }
515
 
        }
516
 
    }
517
 
}
518
 
 
519
 
/*
520
 
 * Call the previous function for each of the 4 sides of the window
521
 
 */
522
 
void
523
 
SnapWindow::resizeCheckEdges (int dx, int dy, int dwidth, int dheight)
524
 
{
525
 
    CompRect input (window->borderRect ());
526
 
 
527
 
    resizeCheckNearestEdge (input.left (), input.top (), input.bottom (),
528
 
                            true, RightEdge, HorizontalSnap);
529
 
    resizeCheckNearestEdge (input.right (), input.top (), input.bottom (),
530
 
                            false, LeftEdge, HorizontalSnap);
531
 
    resizeCheckNearestEdge (input.top (), input.left (), input.right (),
532
 
                            true, BottomEdge, VerticalSnap);
533
 
    resizeCheckNearestEdge (input.bottom (), input.left (), input.right (),
534
 
                            false, TopEdge, VerticalSnap);
535
 
}
536
 
 
537
 
// Check if avoidSnap is matched, and enable/disable snap consequently
538
 
void
539
 
SnapScreen::handleEvent (XEvent *event)
540
 
{
541
 
    if (event->type == screen->xkbEvent ())
542
 
    {
543
 
        XkbAnyEvent *xkbEvent = (XkbAnyEvent *) event;
544
 
 
545
 
        if (xkbEvent->xkb_type == XkbStateNotify)
546
 
        {
547
 
            XkbStateNotifyEvent *stateEvent = (XkbStateNotifyEvent *) event;
548
 
 
549
 
            unsigned int mods = 0xffffffff;
550
 
            if (avoidSnapMask)
551
 
                mods = avoidSnapMask;
552
 
 
553
 
            if ((stateEvent->mods & mods) == mods)
554
 
                snapping = false;
555
 
            else
556
 
                snapping = true;
557
 
        }
558
 
    }
559
 
 
560
 
    screen->handleEvent (event);
561
 
}
562
 
 
563
 
// Events notifications --------------------------------------------------------
564
 
 
565
 
void
566
 
SnapWindow::resizeNotify (int dx, int dy, int dwidth, int dheight)
567
 
{
568
 
    SNAP_SCREEN (screen);
569
 
 
570
 
    window->resizeNotify (dx, dy, dwidth, dheight);
571
 
 
572
 
    // avoid-infinite-notify-loop mode/not grabbed
573
 
    if (skipNotify || !(grabbed & ResizeGrab))
574
 
        return;
575
 
 
576
 
    // we have to avoid snapping but there's still some buffered moving
577
 
    if (!ss->snapping && (m_dx || m_dy || m_dwidth || m_dheight))
578
 
    {
579
 
        resize (m_dx, m_dy, m_dwidth, m_dheight);
580
 
        m_dx = m_dy = m_dwidth = m_dheight = 0;
581
 
        return;
582
 
    }
583
 
 
584
 
    // avoiding snap, nothing buffered
585
 
    if (!ss->snapping)
586
 
        return;
587
 
 
588
 
    // apply edge resistance
589
 
    if (ss->optionGetSnapTypeMask () & SnapTypeEdgeResistanceMask)
590
 
    {
591
 
        // If there's horizontal snapping, add dx to current buffered
592
 
        // dx and resist (move by -dx) or release the window and move
593
 
        // by buffered dx - dx, same for dh
594
 
        if (snapped && snapDirection & HorizontalSnap)
595
 
        {
596
 
            m_dx += dx;
597
 
            if (m_dx < ss->optionGetResistanceDistance ()
598
 
                && m_dx > -ss->optionGetResistanceDistance ())
599
 
            {
600
 
                resize (-dx, 0, 0, 0);
601
 
            }
602
 
            else
603
 
            {
604
 
                resize (m_dx - dx, 0, 0, 0);
605
 
                m_dx = 0;
606
 
                if (!m_dwidth)
607
 
                    snapDirection &= VerticalSnap;
608
 
            }
609
 
            m_dwidth += dwidth;
610
 
            if (m_dwidth < ss->optionGetResistanceDistance ()
611
 
                && m_dwidth > -ss->optionGetResistanceDistance ())
612
 
            {
613
 
                resize (0, 0, -dwidth, 0);
614
 
            }
615
 
            else
616
 
            {
617
 
                resize (0, 0, m_dwidth - dwidth, 0);
618
 
                m_dwidth = 0;
619
 
                if (!m_dx)
620
 
                    snapDirection &= VerticalSnap;
621
 
            }
622
 
        }
623
 
 
624
 
        // Same for vertical snapping and dy/dh
625
 
        if (snapped && snapDirection & VerticalSnap)
626
 
        {
627
 
            m_dy += dy;
628
 
            if (m_dy < ss->optionGetResistanceDistance ()
629
 
                && m_dy > -ss->optionGetResistanceDistance ())
630
 
            {
631
 
                resize (0, -dy, 0, 0);
632
 
            }
633
 
            else
634
 
            {
635
 
                resize (0, m_dy - dy, 0, 0);
636
 
                m_dy = 0;
637
 
                if (!m_dheight)
638
 
                    snapDirection &= HorizontalSnap;
639
 
            }
640
 
            m_dheight += dheight;
641
 
            if (m_dheight < ss->optionGetResistanceDistance ()
642
 
                && m_dheight > -ss->optionGetResistanceDistance ())
643
 
            {
644
 
                resize (0, 0, 0, -dheight);
645
 
            }
646
 
            else
647
 
            {
648
 
                resize (0, 0, 0, m_dheight - dheight);
649
 
                m_dheight = 0;
650
 
                if (!m_dy)
651
 
                    snapDirection &= HorizontalSnap;
652
 
            }
653
 
        }
654
 
        // If we are no longer snapping in any direction, reset snapped
655
 
        if (snapped && !snapDirection)
656
 
            snapped = false;
657
 
    }
658
 
 
659
 
    // If we don't already snap vertically and horizontally,
660
 
    // check edges status
661
 
    if (snapDirection != (VerticalSnap | HorizontalSnap))
662
 
        resizeCheckEdges (dx, dy, dwidth, dheight);
663
 
}
664
 
 
665
 
void
666
 
SnapWindow::moveNotify (int dx, int dy, bool immediate)
667
 
{
668
 
    SNAP_SCREEN (screen);
669
 
 
670
 
    window->moveNotify (dx, dy, immediate);
671
 
 
672
 
    // avoid-infinite-notify-loop mode/not grabbed
673
 
    if (skipNotify || !(grabbed & MoveGrab))
674
 
        return;
675
 
 
676
 
    // we have to avoid snapping but there's still some buffered moving
677
 
    if (!ss->snapping && (m_dx || m_dy))
678
 
    {
679
 
        move (m_dx, m_dy);
680
 
        m_dx = m_dy = 0;
681
 
        return;
682
 
    }
683
 
 
684
 
    // avoiding snap, nothing buffered
685
 
    if (!ss->snapping)
686
 
        return;
687
 
 
688
 
    // apply edge resistance
689
 
    if (ss->optionGetSnapTypeMask () & SnapTypeEdgeResistanceMask)
690
 
    {
691
 
        // If there's horizontal snapping, add dx to current buffered
692
 
        // dx and resist (move by -dx) or release the window and move
693
 
        // by buffered dx - dx
694
 
        if (snapped && snapDirection & HorizontalSnap)
695
 
        {
696
 
            m_dx += dx;
697
 
            if (m_dx < ss->optionGetResistanceDistance ()
698
 
                && m_dx > -ss->optionGetResistanceDistance ())
699
 
            {
700
 
                move (-dx, 0);
701
 
            }
702
 
            else
703
 
            {
704
 
                move (m_dx - dx, 0);
705
 
                m_dx = 0;
706
 
                snapDirection &= VerticalSnap;
707
 
            }
708
 
        }
709
 
        // Same for vertical snapping and dy
710
 
        if (snapped && snapDirection & VerticalSnap)
711
 
        {
712
 
            m_dy += dy;
713
 
            if (m_dy < ss->optionGetResistanceDistance ()
714
 
                && m_dy > -ss->optionGetResistanceDistance ())
715
 
            {
716
 
                move (0, -dy);
717
 
            }
718
 
            else
719
 
            {
720
 
                move (0, m_dy - dy);
721
 
                m_dy = 0;
722
 
                snapDirection &= HorizontalSnap;
723
 
            }
724
 
        }
725
 
        // If we are no longer snapping in any direction, reset snapped
726
 
        if (snapped && !snapDirection)
727
 
            snapped = false;
728
 
    }
729
 
    // If we don't already snap vertically and horizontally,
730
 
    // check edges status
731
 
    if (snapDirection != (VerticalSnap | HorizontalSnap))
732
 
        moveCheckEdges ();
733
 
}
734
 
 
735
 
/*
736
 
 * Initiate snap, get edges
737
 
 */
738
 
void
739
 
SnapWindow::grabNotify (int x, int y, unsigned int state, unsigned int mask)
740
 
{
741
 
    grabbed = (mask & CompWindowGrabResizeMask) ? ResizeGrab : MoveGrab;
742
 
    updateEdges ();
743
 
 
744
 
    window->grabNotify (x, y, state, mask);
745
 
}
746
 
 
747
 
/*
748
 
 * Clean edges data, reset dx/dy to avoid buggy moves
749
 
 * when snap will be triggered again.
750
 
 */
751
 
void
752
 
SnapWindow::ungrabNotify ()
753
 
{
754
 
    edges.clear ();
755
 
 
756
 
    snapped = false;
757
 
    snapDirection = 0;
758
 
    grabbed = 0;
759
 
    m_dx = m_dy = m_dwidth = m_dheight = 0;
760
 
 
761
 
    window->ungrabNotify ();
762
 
}
763
 
 
764
 
// Internal stuff --------------------------------------------------------------
765
 
 
766
 
void
767
 
SnapScreen::optionChanged (CompOption *opt, SnapOptions::Options num)
768
 
{
769
 
    switch (num)
770
 
    {
771
 
    case SnapOptions::AvoidSnap:
772
 
    {
773
 
        unsigned int mask = optionGetAvoidSnapMask ();
774
 
        avoidSnapMask = 0;
775
 
        if (mask & AvoidSnapShiftMask)
776
 
            avoidSnapMask |= ShiftMask;
777
 
        if (mask & AvoidSnapAltMask)
778
 
            avoidSnapMask |= CompAltMask;
779
 
        if (mask & AvoidSnapControlMask)
780
 
            avoidSnapMask |= ControlMask;
781
 
        if (mask & AvoidSnapMetaMask)
782
 
            avoidSnapMask |= CompMetaMask;
783
 
    }
784
 
 
785
 
    default:
786
 
        break;
787
 
    }
788
 
}
789
 
 
790
 
SnapScreen::SnapScreen (CompScreen *screen) :
791
 
    PluginClassHandler <SnapScreen, CompScreen> (screen),
792
 
    SnapOptions (),
793
 
    snapping (true),
794
 
    avoidSnapMask (0)
795
 
{
796
 
    ScreenInterface::setHandler (screen);
797
 
 
798
 
#define setNotify(func) \
799
 
    optionSet##func##Notify (boost::bind (&SnapScreen::optionChanged, this, _1, _2))
800
 
 
801
 
    setNotify (AvoidSnap);
802
 
}
803
 
 
804
 
SnapWindow::SnapWindow (CompWindow *window) :
805
 
    PluginClassHandler <SnapWindow, CompWindow> (window),
806
 
    window (window),
807
 
    snapDirection (0),
808
 
    m_dx (0),
809
 
    m_dy (0),
810
 
    m_dwidth (0),
811
 
    m_dheight (0),
812
 
    snapped (false),
813
 
    grabbed (0),
814
 
    skipNotify (false)
815
 
{
816
 
    WindowInterface::setHandler (window);
817
 
}
818
 
 
819
 
SnapWindow::~SnapWindow ()
820
 
{
821
 
}
822
 
 
823
 
bool
824
 
SnapPluginVTable::init ()
825
 
{
826
 
    if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
827
 
        return false;
828
 
 
829
 
    return true;
830
 
}
831