~compiz-team/compiz/0.9.10

« back to all changes in this revision

Viewing changes to legacy/wobbly.cpp

  • Committer: Dennis kasprzyk
  • Author(s): Dennis Kasprzyk
  • Date: 2009-03-15 05:15:26 UTC
  • Revision ID: git-v1:c579970d3b62220cd2ba54e9330963554769a86c
Moved all not yet ported files into legacy directory.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2005 Novell, Inc.
 
3
 *
 
4
 * Permission to use, copy, modify, distribute, and sell this software
 
5
 * and its documentation for any purpose is hereby granted without
 
6
 * fee, provided that the above copyright notice appear in all copies
 
7
 * and that both that copyright notice and this permission notice
 
8
 * appear in supporting documentation, and that the name of
 
9
 * Novell, Inc. not be used in advertising or publicity pertaining to
 
10
 * distribution of the software without specific, written prior permission.
 
11
 * Novell, Inc. makes no representations about the suitability of this
 
12
 * software for any purpose. It is provided "as is" without express or
 
13
 * implied warranty.
 
14
 *
 
15
 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 
16
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
 
17
 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 
18
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 
19
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 
20
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 
21
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
22
 *
 
23
 * Author: David Reveman <davidr@novell.com>
 
24
 */
 
25
 
 
26
/*
 
27
 * Spring model implemented by Kristian Hogsberg.
 
28
 */
 
29
 
 
30
#include <stdlib.h>
 
31
#include <string.h>
 
32
#include <math.h>
 
33
 
 
34
#include <compiz-core.h>
 
35
 
 
36
#define WIN_X(w) ((w)->attrib.x - (w)->output.left)
 
37
#define WIN_Y(w) ((w)->attrib.y - (w)->output.top)
 
38
#define WIN_W(w) ((w)->width + (w)->output.left + (w)->output.right)
 
39
#define WIN_H(w) ((w)->height + (w)->output.top + (w)->output.bottom)
 
40
 
 
41
#define GRID_WIDTH  4
 
42
#define GRID_HEIGHT 4
 
43
 
 
44
#define MODEL_MAX_SPRINGS (GRID_WIDTH * GRID_HEIGHT * 2)
 
45
 
 
46
#define MASS 15.0f
 
47
 
 
48
typedef struct _xy_pair {
 
49
    float x, y;
 
50
} Point, Vector;
 
51
 
 
52
#define NorthEdgeMask (1L << 0)
 
53
#define SouthEdgeMask (1L << 1)
 
54
#define WestEdgeMask  (1L << 2)
 
55
#define EastEdgeMask  (1L << 3)
 
56
 
 
57
#define EDGE_DISTANCE 25.0f
 
58
#define EDGE_VELOCITY 13.0f
 
59
 
 
60
typedef struct _Edge {
 
61
    float next, prev;
 
62
 
 
63
    float start;
 
64
    float end;
 
65
 
 
66
    float attract;
 
67
    float velocity;
 
68
 
 
69
    Bool  snapped;
 
70
} Edge;
 
71
 
 
72
typedef struct _Object {
 
73
    Vector       force;
 
74
    Point        position;
 
75
    Vector       velocity;
 
76
    float        theta;
 
77
    Bool         immobile;
 
78
    unsigned int edgeMask;
 
79
    Edge         vertEdge;
 
80
    Edge         horzEdge;
 
81
} Object;
 
82
 
 
83
typedef struct _Spring {
 
84
    Object *a;
 
85
    Object *b;
 
86
    Vector offset;
 
87
} Spring;
 
88
 
 
89
#define NORTH 0
 
90
#define SOUTH 1
 
91
#define WEST  2
 
92
#define EAST  3
 
93
 
 
94
typedef struct _Model {
 
95
    Object       *objects;
 
96
    int          numObjects;
 
97
    Spring       springs[MODEL_MAX_SPRINGS];
 
98
    int          numSprings;
 
99
    Object       *anchorObject;
 
100
    float        steps;
 
101
    Point        topLeft;
 
102
    Point        bottomRight;
 
103
    unsigned int edgeMask;
 
104
    unsigned int snapCnt[4];
 
105
} Model;
 
106
 
 
107
#define WOBBLY_EFFECT_NONE   0
 
108
#define WOBBLY_EFFECT_SHIVER 1
 
109
#define WOBBLY_EFFECT_LAST   WOBBLY_EFFECT_SHIVER
 
110
 
 
111
static CompMetadata wobblyMetadata;
 
112
 
 
113
static int displayPrivateIndex;
 
114
 
 
115
#define WOBBLY_DISPLAY_OPTION_SNAP_KEY      0
 
116
#define WOBBLY_DISPLAY_OPTION_SNAP_INVERTED 1
 
117
#define WOBBLY_DISPLAY_OPTION_SHIVER        2
 
118
#define WOBBLY_DISPLAY_OPTION_NUM           3
 
119
 
 
120
typedef struct _WobblyDisplay {
 
121
    int             screenPrivateIndex;
 
122
    HandleEventProc handleEvent;
 
123
 
 
124
    CompOption opt[WOBBLY_DISPLAY_OPTION_NUM];
 
125
 
 
126
    Bool snapping;
 
127
} WobblyDisplay;
 
128
 
 
129
#define WOBBLY_SCREEN_OPTION_FRICTION           0
 
130
#define WOBBLY_SCREEN_OPTION_SPRING_K           1
 
131
#define WOBBLY_SCREEN_OPTION_GRID_RESOLUTION    2
 
132
#define WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE      3
 
133
#define WOBBLY_SCREEN_OPTION_MAP_EFFECT         4
 
134
#define WOBBLY_SCREEN_OPTION_FOCUS_EFFECT       5
 
135
#define WOBBLY_SCREEN_OPTION_MAP_WINDOW_MATCH   6
 
136
#define WOBBLY_SCREEN_OPTION_FOCUS_WINDOW_MATCH 7
 
137
#define WOBBLY_SCREEN_OPTION_GRAB_WINDOW_MATCH  8
 
138
#define WOBBLY_SCREEN_OPTION_MOVE_WINDOW_MATCH  9
 
139
#define WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT    10
 
140
#define WOBBLY_SCREEN_OPTION_NUM                11
 
141
 
 
142
typedef struct _WobblyScreen {
 
143
    int windowPrivateIndex;
 
144
 
 
145
    PreparePaintScreenProc preparePaintScreen;
 
146
    DonePaintScreenProc    donePaintScreen;
 
147
    PaintOutputProc        paintOutput;
 
148
    PaintWindowProc        paintWindow;
 
149
    DamageWindowRectProc   damageWindowRect;
 
150
    AddWindowGeometryProc  addWindowGeometry;
 
151
 
 
152
    WindowResizeNotifyProc windowResizeNotify;
 
153
    WindowMoveNotifyProc   windowMoveNotify;
 
154
    WindowGrabNotifyProc   windowGrabNotify;
 
155
    WindowUngrabNotifyProc windowUngrabNotify;
 
156
 
 
157
    CompOption opt[WOBBLY_SCREEN_OPTION_NUM];
 
158
 
 
159
    Bool wobblyWindows;
 
160
 
 
161
    unsigned int grabMask;
 
162
    CompWindow   *grabWindow;
 
163
    Bool         moveWindow;
 
164
} WobblyScreen;
 
165
 
 
166
#define WobblyInitial  (1L << 0)
 
167
#define WobblyForce    (1L << 1)
 
168
#define WobblyVelocity (1L << 2)
 
169
 
 
170
typedef struct _WobblyWindow {
 
171
    Model        *model;
 
172
    int          wobbly;
 
173
    Bool         grabbed;
 
174
    Bool         velocity;
 
175
    unsigned int state;
 
176
} WobblyWindow;
 
177
 
 
178
#define GET_WOBBLY_DISPLAY(d)                                       \
 
179
    ((WobblyDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
 
180
 
 
181
#define WOBBLY_DISPLAY(d)                      \
 
182
    WobblyDisplay *wd = GET_WOBBLY_DISPLAY (d)
 
183
 
 
184
#define GET_WOBBLY_SCREEN(s, wd)                                        \
 
185
    ((WobblyScreen *) (s)->base.privates[(wd)->screenPrivateIndex].ptr)
 
186
 
 
187
#define WOBBLY_SCREEN(s)                                                      \
 
188
    WobblyScreen *ws = GET_WOBBLY_SCREEN (s, GET_WOBBLY_DISPLAY (s->display))
 
189
 
 
190
#define GET_WOBBLY_WINDOW(w, ws)                                        \
 
191
    ((WobblyWindow *) (w)->base.privates[(ws)->windowPrivateIndex].ptr)
 
192
 
 
193
#define WOBBLY_WINDOW(w)                                         \
 
194
    WobblyWindow *ww = GET_WOBBLY_WINDOW  (w,                    \
 
195
                       GET_WOBBLY_SCREEN  (w->screen,            \
 
196
                       GET_WOBBLY_DISPLAY (w->screen->display)))
 
197
 
 
198
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
 
199
 
 
200
static CompOption *
 
201
wobblyGetScreenOptions (CompPlugin *plugin,
 
202
                        CompScreen *screen,
 
203
                        int        *count)
 
204
{
 
205
    WOBBLY_SCREEN (screen);
 
206
 
 
207
    *count = NUM_OPTIONS (ws);
 
208
    return ws->opt;
 
209
}
 
210
 
 
211
static Bool
 
212
wobblySetScreenOption (CompPlugin      *plugin,
 
213
                       CompScreen      *screen,
 
214
                       const char      *name,
 
215
                       CompOptionValue *value)
 
216
{
 
217
    CompOption *o;
 
218
 
 
219
    WOBBLY_SCREEN (screen);
 
220
 
 
221
    o = compFindOption (ws->opt, NUM_OPTIONS (ws), name, NULL);
 
222
    if (!o)
 
223
        return FALSE;
 
224
 
 
225
    return compSetScreenOption (screen, o, value);
 
226
}
 
227
 
 
228
static const CompMetadataOptionInfo wobblyScreenOptionInfo[] = {
 
229
    { "friction", "float", "<min>0.1</min>", 0, 0 },
 
230
    { "spring_k", "float", "<min>0.1</min>", 0, 0 },
 
231
    { "grid_resolution", "int", "<min>1</min><max>64</max>", 0, 0 },
 
232
    { "min_grid_size", "int", "<min>4</min><max>128</max>", 0, 0 },
 
233
    { "map_effect", "int", RESTOSTRING (0, WOBBLY_EFFECT_LAST), 0, 0 },
 
234
    { "focus_effect", "int", RESTOSTRING (0, WOBBLY_EFFECT_LAST), 0, 0 },
 
235
    { "map_window_match", "match", 0, 0, 0 },
 
236
    { "focus_window_match", "match", 0, 0, 0 },
 
237
    { "grab_window_match", "match", 0, 0, 0 },
 
238
    { "move_window_match", "match", 0, 0, 0 },
 
239
    { "maximize_effect", "bool", 0, 0, 0 }
 
240
};
 
241
 
 
242
#define SNAP_WINDOW_TYPE (CompWindowTypeNormalMask  | \
 
243
                          CompWindowTypeToolbarMask | \
 
244
                          CompWindowTypeMenuMask    | \
 
245
                          CompWindowTypeUtilMask)
 
246
 
 
247
static void
 
248
findNextWestEdge (CompWindow *w,
 
249
                  Object     *object)
 
250
{
 
251
    int v, v1, v2;
 
252
    int s, start;
 
253
    int e, end;
 
254
    int x;
 
255
    int output;
 
256
 
 
257
    start = -65535.0f;
 
258
    end   =  65535.0f;
 
259
 
 
260
    v1 = -65535.0f;
 
261
    v2 =  65535.0f;
 
262
 
 
263
    x = object->position.x + w->output.left - w->input.left;
 
264
 
 
265
    output = outputDeviceForPoint (w->screen, x, object->position.y);
 
266
 
 
267
    if (x >= w->screen->outputDev[output].region.extents.x1)
 
268
    {
 
269
        CompWindow *p;
 
270
 
 
271
        v1 = w->screen->outputDev[output].region.extents.x1;
 
272
 
 
273
        for (p = w->screen->windows; p; p = p->next)
 
274
        {
 
275
            if (w == p)
 
276
                continue;
 
277
 
 
278
            if (p->mapNum && p->struts)
 
279
            {
 
280
                s = p->struts->left.y - w->output.top;
 
281
                e = p->struts->left.y + p->struts->left.height +
 
282
                    w->output.bottom;
 
283
            }
 
284
            else if (!p->invisible && (p->type & SNAP_WINDOW_TYPE))
 
285
            {
 
286
                s = p->attrib.y - p->input.top - w->output.top;
 
287
                e = p->attrib.y + p->height + p->input.bottom +
 
288
                    w->output.bottom;
 
289
            }
 
290
            else
 
291
            {
 
292
                continue;
 
293
            }
 
294
 
 
295
            if (s > object->position.y)
 
296
            {
 
297
                if (s < end)
 
298
                    end = s;
 
299
            }
 
300
            else if (e < object->position.y)
 
301
            {
 
302
                if (e > start)
 
303
                    start = e;
 
304
            }
 
305
            else
 
306
            {
 
307
                if (s > start)
 
308
                    start = s;
 
309
 
 
310
                if (e < end)
 
311
                    end = e;
 
312
 
 
313
                if (p->mapNum && p->struts)
 
314
                    v = p->struts->left.x + p->struts->left.width;
 
315
                else
 
316
                    v = p->attrib.x + p->width + p->input.right;
 
317
 
 
318
                if (v <= x)
 
319
                {
 
320
                    if (v > v1)
 
321
                        v1 = v;
 
322
                }
 
323
                else
 
324
                {
 
325
                    if (v < v2)
 
326
                        v2 = v;
 
327
                }
 
328
            }
 
329
        }
 
330
    }
 
331
    else
 
332
    {
 
333
        v2 = w->screen->outputDev[output].region.extents.x1;
 
334
    }
 
335
 
 
336
    v1 = v1 - w->output.left + w->input.left;
 
337
    v2 = v2 - w->output.left + w->input.left;
 
338
 
 
339
    if (v1 != (int) object->vertEdge.next)
 
340
        object->vertEdge.snapped = FALSE;
 
341
 
 
342
    object->vertEdge.start = start;
 
343
    object->vertEdge.end   = end;
 
344
 
 
345
    object->vertEdge.next = v1;
 
346
    object->vertEdge.prev = v2;
 
347
 
 
348
    object->vertEdge.attract  = v1 + EDGE_DISTANCE;
 
349
    object->vertEdge.velocity = EDGE_VELOCITY;
 
350
}
 
351
 
 
352
static void
 
353
findNextEastEdge (CompWindow *w,
 
354
                  Object     *object)
 
355
{
 
356
    int v, v1, v2;
 
357
    int s, start;
 
358
    int e, end;
 
359
    int x;
 
360
    int output;
 
361
 
 
362
    start = -65535.0f;
 
363
    end   =  65535.0f;
 
364
 
 
365
    v1 =  65535.0f;
 
366
    v2 = -65535.0f;
 
367
 
 
368
    x = object->position.x - w->output.right + w->input.right;
 
369
 
 
370
    output = outputDeviceForPoint (w->screen, x, object->position.y);
 
371
 
 
372
    if (x <= w->screen->outputDev[output].region.extents.x2)
 
373
    {
 
374
        CompWindow *p;
 
375
 
 
376
        v1 = w->screen->outputDev[output].region.extents.x2;
 
377
 
 
378
        for (p = w->screen->windows; p; p = p->next)
 
379
        {
 
380
            if (w == p)
 
381
                continue;
 
382
 
 
383
            if (p->mapNum && p->struts)
 
384
            {
 
385
                s = p->struts->right.y - w->output.top;
 
386
                e = p->struts->right.y + p->struts->right.height +
 
387
                    w->output.bottom;
 
388
            }
 
389
            else if (!p->invisible && (p->type & SNAP_WINDOW_TYPE))
 
390
            {
 
391
                s = p->attrib.y - p->input.top - w->output.top;
 
392
                e = p->attrib.y + p->height + p->input.bottom +
 
393
                    w->output.bottom;
 
394
            }
 
395
            else
 
396
            {
 
397
                continue;
 
398
            }
 
399
 
 
400
            if (s > object->position.y)
 
401
            {
 
402
                if (s < end)
 
403
                    end = s;
 
404
            }
 
405
            else if (e < object->position.y)
 
406
            {
 
407
                if (e > start)
 
408
                    start = e;
 
409
            }
 
410
            else
 
411
            {
 
412
                if (s > start)
 
413
                    start = s;
 
414
 
 
415
                if (e < end)
 
416
                    end = e;
 
417
 
 
418
                if (p->mapNum && p->struts)
 
419
                    v = p->struts->right.x;
 
420
                else
 
421
                    v = p->attrib.x - p->input.left;
 
422
 
 
423
                if (v >= x)
 
424
                {
 
425
                    if (v < v1)
 
426
                        v1 = v;
 
427
                }
 
428
                else
 
429
                {
 
430
                    if (v > v2)
 
431
                        v2 = v;
 
432
                }
 
433
            }
 
434
        }
 
435
    }
 
436
    else
 
437
    {
 
438
        v2 = w->screen->outputDev[output].region.extents.x2;
 
439
    }
 
440
 
 
441
    v1 = v1 + w->output.right - w->input.right;
 
442
    v2 = v2 + w->output.right - w->input.right;
 
443
 
 
444
    if (v1 != (int) object->vertEdge.next)
 
445
        object->vertEdge.snapped = FALSE;
 
446
 
 
447
    object->vertEdge.start = start;
 
448
    object->vertEdge.end   = end;
 
449
 
 
450
    object->vertEdge.next = v1;
 
451
    object->vertEdge.prev = v2;
 
452
 
 
453
    object->vertEdge.attract  = v1 - EDGE_DISTANCE;
 
454
    object->vertEdge.velocity = EDGE_VELOCITY;
 
455
}
 
456
 
 
457
static void
 
458
findNextNorthEdge (CompWindow *w,
 
459
                   Object     *object)
 
460
{
 
461
    int v, v1, v2;
 
462
    int s, start;
 
463
    int e, end;
 
464
    int y;
 
465
    int output;
 
466
 
 
467
    start = -65535.0f;
 
468
    end   =  65535.0f;
 
469
 
 
470
    v1 = -65535.0f;
 
471
    v2 =  65535.0f;
 
472
 
 
473
    y = object->position.y + w->output.top - w->input.top;
 
474
 
 
475
    output = outputDeviceForPoint (w->screen, object->position.x, y);
 
476
 
 
477
    if (y >= w->screen->outputDev[output].region.extents.y1)
 
478
    {
 
479
        CompWindow *p;
 
480
 
 
481
        v1 = w->screen->outputDev[output].region.extents.y1;
 
482
 
 
483
        for (p = w->screen->windows; p; p = p->next)
 
484
        {
 
485
            if (w == p)
 
486
                continue;
 
487
 
 
488
            if (p->mapNum && p->struts)
 
489
            {
 
490
                s = p->struts->top.x - w->output.left;
 
491
                e = p->struts->top.x + p->struts->top.width + w->output.right;
 
492
            }
 
493
            else if (!p->invisible && (p->type & SNAP_WINDOW_TYPE))
 
494
            {
 
495
                s = p->attrib.x - p->input.left - w->output.left;
 
496
                e = p->attrib.x + p->width + p->input.right + w->output.right;
 
497
            }
 
498
            else
 
499
            {
 
500
                continue;
 
501
            }
 
502
 
 
503
            if (s > object->position.x)
 
504
            {
 
505
                if (s < end)
 
506
                    end = s;
 
507
            }
 
508
            else if (e < object->position.x)
 
509
            {
 
510
                if (e > start)
 
511
                    start = e;
 
512
            }
 
513
            else
 
514
            {
 
515
                if (s > start)
 
516
                    start = s;
 
517
 
 
518
                if (e < end)
 
519
                    end = e;
 
520
 
 
521
                if (p->mapNum && p->struts)
 
522
                    v = p->struts->top.y + p->struts->top.height;
 
523
                else
 
524
                    v = p->attrib.y + p->height + p->input.bottom;
 
525
 
 
526
                if (v <= y)
 
527
                {
 
528
                    if (v > v1)
 
529
                        v1 = v;
 
530
                }
 
531
                else
 
532
                {
 
533
                    if (v < v2)
 
534
                        v2 = v;
 
535
                }
 
536
            }
 
537
        }
 
538
    }
 
539
    else
 
540
    {
 
541
        v2 = w->screen->outputDev[output].region.extents.y1;
 
542
    }
 
543
 
 
544
    v1 = v1 - w->output.top + w->input.top;
 
545
    v2 = v2 - w->output.top + w->input.top;
 
546
 
 
547
    if (v1 != (int) object->horzEdge.next)
 
548
        object->horzEdge.snapped = FALSE;
 
549
 
 
550
    object->horzEdge.start = start;
 
551
    object->horzEdge.end   = end;
 
552
 
 
553
    object->horzEdge.next = v1;
 
554
    object->horzEdge.prev = v2;
 
555
 
 
556
    object->horzEdge.attract  = v1 + EDGE_DISTANCE;
 
557
    object->horzEdge.velocity = EDGE_VELOCITY;
 
558
}
 
559
 
 
560
static void
 
561
findNextSouthEdge (CompWindow *w,
 
562
                   Object     *object)
 
563
{
 
564
    int v, v1, v2;
 
565
    int s, start;
 
566
    int e, end;
 
567
    int y;
 
568
    int output;
 
569
 
 
570
    start = -65535.0f;
 
571
    end   =  65535.0f;
 
572
 
 
573
    v1 =  65535.0f;
 
574
    v2 = -65535.0f;
 
575
 
 
576
    y = object->position.y - w->output.bottom + w->input.bottom;
 
577
 
 
578
    output = outputDeviceForPoint (w->screen, object->position.x, y);
 
579
 
 
580
    if (y <= w->screen->outputDev[output].region.extents.y2)
 
581
    {
 
582
        CompWindow *p;
 
583
 
 
584
        v1 = w->screen->outputDev[output].region.extents.y2;
 
585
 
 
586
        for (p = w->screen->windows; p; p = p->next)
 
587
        {
 
588
            if (w == p)
 
589
                continue;
 
590
 
 
591
            if (p->mapNum && p->struts)
 
592
            {
 
593
                s = p->struts->bottom.x - w->output.left;
 
594
                e = p->struts->bottom.x + p->struts->bottom.width +
 
595
                    w->output.right;
 
596
            }
 
597
            else if (!p->invisible && (p->type & SNAP_WINDOW_TYPE))
 
598
            {
 
599
                s = p->attrib.x - p->input.left - w->output.left;
 
600
                e = p->attrib.x + p->width + p->input.right + w->output.right;
 
601
            }
 
602
            else
 
603
            {
 
604
                continue;
 
605
            }
 
606
 
 
607
            if (s > object->position.x)
 
608
            {
 
609
                if (s < end)
 
610
                    end = s;
 
611
            }
 
612
            else if (e < object->position.x)
 
613
            {
 
614
                if (e > start)
 
615
                    start = e;
 
616
            }
 
617
            else
 
618
            {
 
619
                if (s > start)
 
620
                    start = s;
 
621
 
 
622
                if (e < end)
 
623
                    end = e;
 
624
 
 
625
                if (p->mapNum && p->struts)
 
626
                    v = p->struts->bottom.y;
 
627
                else
 
628
                    v = p->attrib.y - p->input.top;
 
629
 
 
630
                if (v >= y)
 
631
                {
 
632
                    if (v < v1)
 
633
                        v1 = v;
 
634
                }
 
635
                else
 
636
                {
 
637
                    if (v > v2)
 
638
                        v2 = v;
 
639
                }
 
640
            }
 
641
        }
 
642
    }
 
643
    else
 
644
    {
 
645
        v2 = w->screen->outputDev[output].region.extents.y2;
 
646
    }
 
647
 
 
648
    v1 = v1 + w->output.bottom - w->input.bottom;
 
649
    v2 = v2 + w->output.bottom - w->input.bottom;
 
650
 
 
651
    if (v1 != (int) object->horzEdge.next)
 
652
        object->horzEdge.snapped = FALSE;
 
653
 
 
654
    object->horzEdge.start = start;
 
655
    object->horzEdge.end   = end;
 
656
 
 
657
    object->horzEdge.next = v1;
 
658
    object->horzEdge.prev = v2;
 
659
 
 
660
    object->horzEdge.attract  = v1 - EDGE_DISTANCE;
 
661
    object->horzEdge.velocity = EDGE_VELOCITY;
 
662
}
 
663
 
 
664
static void
 
665
objectInit (Object *object,
 
666
            float  positionX,
 
667
            float  positionY,
 
668
            float  velocityX,
 
669
            float  velocityY)
 
670
{
 
671
    object->force.x = 0;
 
672
    object->force.y = 0;
 
673
 
 
674
    object->position.x = positionX;
 
675
    object->position.y = positionY;
 
676
 
 
677
    object->velocity.x = velocityX;
 
678
    object->velocity.y = velocityY;
 
679
 
 
680
    object->theta    = 0;
 
681
    object->immobile = FALSE;
 
682
 
 
683
    object->edgeMask = 0;
 
684
 
 
685
    object->vertEdge.snapped = FALSE;
 
686
    object->horzEdge.snapped = FALSE;
 
687
 
 
688
    object->vertEdge.next = 0.0f;
 
689
    object->horzEdge.next = 0.0f;
 
690
}
 
691
 
 
692
static void
 
693
springInit (Spring *spring,
 
694
            Object *a,
 
695
            Object *b,
 
696
            float  offsetX,
 
697
            float  offsetY)
 
698
{
 
699
    spring->a        = a;
 
700
    spring->b        = b;
 
701
    spring->offset.x = offsetX;
 
702
    spring->offset.y = offsetY;
 
703
}
 
704
 
 
705
static void
 
706
modelCalcBounds (Model *model)
 
707
{
 
708
    int i;
 
709
 
 
710
    model->topLeft.x     = MAXSHORT;
 
711
    model->topLeft.y     = MAXSHORT;
 
712
    model->bottomRight.x = MINSHORT;
 
713
    model->bottomRight.y = MINSHORT;
 
714
 
 
715
    for (i = 0; i < model->numObjects; i++)
 
716
    {
 
717
        if (model->objects[i].position.x < model->topLeft.x)
 
718
            model->topLeft.x = model->objects[i].position.x;
 
719
        else if (model->objects[i].position.x > model->bottomRight.x)
 
720
            model->bottomRight.x = model->objects[i].position.x;
 
721
 
 
722
        if (model->objects[i].position.y < model->topLeft.y)
 
723
            model->topLeft.y = model->objects[i].position.y;
 
724
        else if (model->objects[i].position.y > model->bottomRight.y)
 
725
            model->bottomRight.y = model->objects[i].position.y;
 
726
    }
 
727
}
 
728
 
 
729
static void
 
730
modelAddSpring (Model  *model,
 
731
                Object *a,
 
732
                Object *b,
 
733
                float  offsetX,
 
734
                float  offsetY)
 
735
{
 
736
    Spring *spring;
 
737
 
 
738
    spring = &model->springs[model->numSprings];
 
739
    model->numSprings++;
 
740
 
 
741
    springInit (spring, a, b, offsetX, offsetY);
 
742
}
 
743
 
 
744
static void
 
745
modelSetMiddleAnchor (Model *model,
 
746
                      int   x,
 
747
                      int   y,
 
748
                      int   width,
 
749
                      int   height)
 
750
{
 
751
    float gx, gy;
 
752
 
 
753
    gx = ((GRID_WIDTH  - 1) / 2 * width)  / (float) (GRID_WIDTH  - 1);
 
754
    gy = ((GRID_HEIGHT - 1) / 2 * height) / (float) (GRID_HEIGHT - 1);
 
755
 
 
756
    if (model->anchorObject)
 
757
        model->anchorObject->immobile = FALSE;
 
758
 
 
759
    model->anchorObject = &model->objects[GRID_WIDTH *
 
760
                                          ((GRID_HEIGHT - 1) / 2) +
 
761
                                          (GRID_WIDTH - 1) / 2];
 
762
    model->anchorObject->position.x = x + gx;
 
763
    model->anchorObject->position.y = y + gy;
 
764
 
 
765
    model->anchorObject->immobile = TRUE;
 
766
}
 
767
 
 
768
static void
 
769
modelSetTopAnchor (Model *model,
 
770
                   int   x,
 
771
                   int   y,
 
772
                   int   width)
 
773
{
 
774
    float gx;
 
775
 
 
776
    gx = ((GRID_WIDTH - 1) / 2 * width)  / (float) (GRID_WIDTH - 1);
 
777
 
 
778
    if (model->anchorObject)
 
779
        model->anchorObject->immobile = FALSE;
 
780
 
 
781
    model->anchorObject = &model->objects[(GRID_WIDTH - 1) / 2];
 
782
    model->anchorObject->position.x = x + gx;
 
783
    model->anchorObject->position.y = y;
 
784
 
 
785
    model->anchorObject->immobile = TRUE;
 
786
}
 
787
 
 
788
static void
 
789
modelAddEdgeAnchors (Model *model,
 
790
                     int   x,
 
791
                     int   y,
 
792
                     int   width,
 
793
                     int   height)
 
794
{
 
795
    Object *o;
 
796
 
 
797
    o = &model->objects[0];
 
798
    o->position.x = x;
 
799
    o->position.y = y;
 
800
    o->immobile = TRUE;
 
801
 
 
802
    o = &model->objects[GRID_WIDTH - 1];
 
803
    o->position.x = x + width;
 
804
    o->position.y = y;
 
805
    o->immobile = TRUE;
 
806
 
 
807
    o = &model->objects[GRID_WIDTH * (GRID_HEIGHT - 1)];
 
808
    o->position.x = x;
 
809
    o->position.y = y + height;
 
810
    o->immobile = TRUE;
 
811
 
 
812
    o = &model->objects[model->numObjects - 1];
 
813
    o->position.x = x + width;
 
814
    o->position.y = y + height;
 
815
    o->immobile = TRUE;
 
816
 
 
817
    if (!model->anchorObject)
 
818
        model->anchorObject = &model->objects[0];
 
819
}
 
820
 
 
821
static void
 
822
modelRemoveEdgeAnchors (Model *model,
 
823
                        int   x,
 
824
                        int   y,
 
825
                        int   width,
 
826
                        int   height)
 
827
{
 
828
    Object *o;
 
829
 
 
830
    o = &model->objects[0];
 
831
    o->position.x = x;
 
832
    o->position.y = y;
 
833
    if (o != model->anchorObject)
 
834
        o->immobile = FALSE;
 
835
 
 
836
    o = &model->objects[GRID_WIDTH - 1];
 
837
    o->position.x = x + width;
 
838
    o->position.y = y;
 
839
    if (o != model->anchorObject)
 
840
        o->immobile = FALSE;
 
841
 
 
842
    o = &model->objects[GRID_WIDTH * (GRID_HEIGHT - 1)];
 
843
    o->position.x = x;
 
844
    o->position.y = y + height;
 
845
    if (o != model->anchorObject)
 
846
        o->immobile = FALSE;
 
847
 
 
848
    o = &model->objects[model->numObjects - 1];
 
849
    o->position.x = x + width;
 
850
    o->position.y = y + height;
 
851
    if (o != model->anchorObject)
 
852
        o->immobile = FALSE;
 
853
}
 
854
 
 
855
static void
 
856
modelAdjustObjectPosition (Model  *model,
 
857
                           Object *object,
 
858
                           int    x,
 
859
                           int    y,
 
860
                           int    width,
 
861
                           int    height)
 
862
{
 
863
    Object *o;
 
864
    int    gridX, gridY, i = 0;
 
865
 
 
866
    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
 
867
    {
 
868
        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
 
869
        {
 
870
            o = &model->objects[i];
 
871
            if (o == object)
 
872
            {
 
873
                o->position.x = x + (gridX * width) / (GRID_WIDTH - 1);
 
874
                o->position.y = y + (gridY * height) / (GRID_HEIGHT - 1);
 
875
 
 
876
                return;
 
877
            }
 
878
 
 
879
            i++;
 
880
        }
 
881
    }
 
882
}
 
883
 
 
884
static void
 
885
modelInitObjects (Model *model,
 
886
                  int   x,
 
887
                  int   y,
 
888
                  int   width,
 
889
                  int   height)
 
890
{
 
891
    int   gridX, gridY, i = 0;
 
892
    float gw, gh;
 
893
 
 
894
    gw = GRID_WIDTH  - 1;
 
895
    gh = GRID_HEIGHT - 1;
 
896
 
 
897
    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
 
898
    {
 
899
        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
 
900
        {
 
901
            objectInit (&model->objects[i],
 
902
                        x + (gridX * width) / gw,
 
903
                        y + (gridY * height) / gh,
 
904
                        0, 0);
 
905
            i++;
 
906
        }
 
907
    }
 
908
 
 
909
    modelSetMiddleAnchor (model, x, y, width, height);
 
910
}
 
911
 
 
912
static void
 
913
modelUpdateSnapping (CompWindow *window,
 
914
                     Model      *model)
 
915
{
 
916
    unsigned int edgeMask, gridMask, mask;
 
917
    int          gridX, gridY, i = 0;
 
918
 
 
919
    edgeMask = model->edgeMask;
 
920
 
 
921
    if (model->snapCnt[NORTH])
 
922
        edgeMask &= ~SouthEdgeMask;
 
923
    else if (model->snapCnt[SOUTH])
 
924
        edgeMask &= ~NorthEdgeMask;
 
925
 
 
926
    if (model->snapCnt[WEST])
 
927
        edgeMask &= ~EastEdgeMask;
 
928
    else if (model->snapCnt[EAST])
 
929
        edgeMask &= ~WestEdgeMask;
 
930
 
 
931
    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
 
932
    {
 
933
        if (gridY == 0)
 
934
            gridMask = edgeMask & NorthEdgeMask;
 
935
        else if (gridY == GRID_HEIGHT - 1)
 
936
            gridMask = edgeMask & SouthEdgeMask;
 
937
        else
 
938
            gridMask = 0;
 
939
 
 
940
        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
 
941
        {
 
942
            mask = gridMask;
 
943
 
 
944
            if (gridX == 0)
 
945
                mask |= edgeMask & WestEdgeMask;
 
946
            else if (gridX == GRID_WIDTH - 1)
 
947
                mask |= edgeMask & EastEdgeMask;
 
948
 
 
949
            if (mask != model->objects[i].edgeMask)
 
950
            {
 
951
                model->objects[i].edgeMask = mask;
 
952
 
 
953
                if (mask & WestEdgeMask)
 
954
                {
 
955
                    if (!model->objects[i].vertEdge.snapped)
 
956
                        findNextWestEdge (window, &model->objects[i]);
 
957
                }
 
958
                else if (mask & EastEdgeMask)
 
959
                {
 
960
                    if (!model->objects[i].vertEdge.snapped)
 
961
                        findNextEastEdge (window, &model->objects[i]);
 
962
                }
 
963
                else
 
964
                    model->objects[i].vertEdge.snapped = FALSE;
 
965
 
 
966
                if (mask & NorthEdgeMask)
 
967
                {
 
968
                    if (!model->objects[i].horzEdge.snapped)
 
969
                        findNextNorthEdge (window, &model->objects[i]);
 
970
                }
 
971
                else if (mask & SouthEdgeMask)
 
972
                {
 
973
                    if (!model->objects[i].horzEdge.snapped)
 
974
                        findNextSouthEdge (window, &model->objects[i]);
 
975
                }
 
976
                else
 
977
                    model->objects[i].horzEdge.snapped = FALSE;
 
978
            }
 
979
 
 
980
            i++;
 
981
        }
 
982
    }
 
983
}
 
984
 
 
985
static void
 
986
modelReduceEdgeEscapeVelocity (Model *model)
 
987
{
 
988
    int gridX, gridY, i = 0;
 
989
 
 
990
    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
 
991
    {
 
992
        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
 
993
        {
 
994
            if (model->objects[i].vertEdge.snapped)
 
995
                model->objects[i].vertEdge.velocity *= drand48 () * 0.25f;
 
996
 
 
997
            if (model->objects[i].horzEdge.snapped)
 
998
                model->objects[i].horzEdge.velocity *= drand48 () * 0.25f;
 
999
 
 
1000
            i++;
 
1001
        }
 
1002
    }
 
1003
}
 
1004
 
 
1005
static Bool
 
1006
modelDisableSnapping (CompWindow *window,
 
1007
                      Model      *model)
 
1008
{
 
1009
    int  gridX, gridY, i = 0;
 
1010
    Bool snapped = FALSE;
 
1011
 
 
1012
    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
 
1013
    {
 
1014
        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
 
1015
        {
 
1016
            if (model->objects[i].vertEdge.snapped ||
 
1017
                model->objects[i].horzEdge.snapped)
 
1018
                snapped = TRUE;
 
1019
 
 
1020
            model->objects[i].vertEdge.snapped = FALSE;
 
1021
            model->objects[i].horzEdge.snapped = FALSE;
 
1022
 
 
1023
            model->objects[i].edgeMask = 0;
 
1024
 
 
1025
            i++;
 
1026
        }
 
1027
    }
 
1028
 
 
1029
    memset (model->snapCnt, 0, sizeof (model->snapCnt));
 
1030
 
 
1031
    return snapped;
 
1032
}
 
1033
 
 
1034
static void
 
1035
modelAdjustObjectsForShiver (Model *model,
 
1036
                             int   x,
 
1037
                             int   y,
 
1038
                             int   width,
 
1039
                             int   height)
 
1040
{
 
1041
    int   gridX, gridY, i = 0;
 
1042
    float vX, vY;
 
1043
    float w, h;
 
1044
    float scale;
 
1045
 
 
1046
    w = width;
 
1047
    h = height;
 
1048
 
 
1049
    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
 
1050
    {
 
1051
        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
 
1052
        {
 
1053
            if (!model->objects[i].immobile)
 
1054
            {
 
1055
                vX = model->objects[i].position.x - (x + w / 2);
 
1056
                vY = model->objects[i].position.y - (y + h / 2);
 
1057
 
 
1058
                vX /= w;
 
1059
                vY /= h;
 
1060
 
 
1061
                scale = ((float) rand () * 7.5f) / RAND_MAX;
 
1062
 
 
1063
                model->objects[i].velocity.x += vX * scale;
 
1064
                model->objects[i].velocity.y += vY * scale;
 
1065
            }
 
1066
 
 
1067
            i++;
 
1068
        }
 
1069
    }
 
1070
}
 
1071
 
 
1072
static void
 
1073
modelInitSprings (Model *model,
 
1074
                  int   x,
 
1075
                  int   y,
 
1076
                  int   width,
 
1077
                  int   height)
 
1078
{
 
1079
    int   gridX, gridY, i = 0;
 
1080
    float hpad, vpad;
 
1081
 
 
1082
    model->numSprings = 0;
 
1083
 
 
1084
    hpad = ((float) width) / (GRID_WIDTH  - 1);
 
1085
    vpad = ((float) height) / (GRID_HEIGHT - 1);
 
1086
 
 
1087
    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
 
1088
    {
 
1089
        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
 
1090
        {
 
1091
            if (gridX > 0)
 
1092
                modelAddSpring (model,
 
1093
                                &model->objects[i - 1],
 
1094
                                &model->objects[i],
 
1095
                                hpad, 0);
 
1096
 
 
1097
            if (gridY > 0)
 
1098
                modelAddSpring (model,
 
1099
                                &model->objects[i - GRID_WIDTH],
 
1100
                                &model->objects[i],
 
1101
                                0, vpad);
 
1102
 
 
1103
            i++;
 
1104
        }
 
1105
    }
 
1106
}
 
1107
 
 
1108
static void
 
1109
modelMove (Model *model,
 
1110
           float tx,
 
1111
           float ty)
 
1112
{
 
1113
    int i;
 
1114
 
 
1115
    for (i = 0; i < model->numObjects; i++)
 
1116
    {
 
1117
        model->objects[i].position.x += tx;
 
1118
        model->objects[i].position.y += ty;
 
1119
    }
 
1120
}
 
1121
 
 
1122
static Model *
 
1123
createModel (int          x,
 
1124
             int          y,
 
1125
             int          width,
 
1126
             int          height,
 
1127
             unsigned int edgeMask)
 
1128
{
 
1129
    Model *model;
 
1130
 
 
1131
    model = malloc (sizeof (Model));
 
1132
    if (!model)
 
1133
        return 0;
 
1134
 
 
1135
    model->numObjects = GRID_WIDTH * GRID_HEIGHT;
 
1136
    model->objects = malloc (sizeof (Object) * model->numObjects);
 
1137
    if (!model->objects)
 
1138
    {
 
1139
        free (model);
 
1140
        return 0;
 
1141
    }
 
1142
 
 
1143
    model->anchorObject = 0;
 
1144
    model->numSprings = 0;
 
1145
 
 
1146
    model->steps = 0;
 
1147
 
 
1148
    memset (model->snapCnt, 0, sizeof (model->snapCnt));
 
1149
 
 
1150
    model->edgeMask = edgeMask;
 
1151
 
 
1152
    modelInitObjects (model, x, y, width, height);
 
1153
    modelInitSprings (model, x, y, width, height);
 
1154
 
 
1155
    modelCalcBounds (model);
 
1156
 
 
1157
    return model;
 
1158
}
 
1159
 
 
1160
static void
 
1161
objectApplyForce (Object *object,
 
1162
                  float  fx,
 
1163
                  float  fy)
 
1164
{
 
1165
    object->force.x += fx;
 
1166
    object->force.y += fy;
 
1167
}
 
1168
 
 
1169
static void
 
1170
springExertForces (Spring *spring,
 
1171
                   float  k)
 
1172
{
 
1173
    Vector da, db;
 
1174
    Vector a, b;
 
1175
 
 
1176
    a = spring->a->position;
 
1177
    b = spring->b->position;
 
1178
 
 
1179
    da.x = 0.5f * (b.x - a.x - spring->offset.x);
 
1180
    da.y = 0.5f * (b.y - a.y - spring->offset.y);
 
1181
 
 
1182
    db.x = 0.5f * (a.x - b.x + spring->offset.x);
 
1183
    db.y = 0.5f * (a.y - b.y + spring->offset.y);
 
1184
 
 
1185
    objectApplyForce (spring->a, k * da.x, k * da.y);
 
1186
    objectApplyForce (spring->b, k * db.x, k * db.y);
 
1187
}
 
1188
 
 
1189
static Bool
 
1190
objectReleaseWestEdge (CompWindow *w,
 
1191
                       Model      *model,
 
1192
                       Object     *object)
 
1193
{
 
1194
    if (fabs (object->velocity.x) > object->vertEdge.velocity)
 
1195
    {
 
1196
        object->position.x += object->velocity.x * 2.0f;
 
1197
 
 
1198
        model->snapCnt[WEST]--;
 
1199
 
 
1200
        object->vertEdge.snapped = FALSE;
 
1201
        object->edgeMask = 0;
 
1202
 
 
1203
        modelUpdateSnapping (w, model);
 
1204
 
 
1205
        return TRUE;
 
1206
    }
 
1207
 
 
1208
    object->velocity.x = 0.0f;
 
1209
 
 
1210
    return FALSE;
 
1211
}
 
1212
 
 
1213
static Bool
 
1214
objectReleaseEastEdge (CompWindow *w,
 
1215
                       Model      *model,
 
1216
                       Object     *object)
 
1217
{
 
1218
    if (fabs (object->velocity.x) > object->vertEdge.velocity)
 
1219
    {
 
1220
        object->position.x += object->velocity.x * 2.0f;
 
1221
 
 
1222
        model->snapCnt[EAST]--;
 
1223
 
 
1224
        object->vertEdge.snapped = FALSE;
 
1225
        object->edgeMask = 0;
 
1226
 
 
1227
        modelUpdateSnapping (w, model);
 
1228
 
 
1229
        return TRUE;
 
1230
    }
 
1231
 
 
1232
    object->velocity.x = 0.0f;
 
1233
 
 
1234
    return FALSE;
 
1235
}
 
1236
 
 
1237
static Bool
 
1238
objectReleaseNorthEdge (CompWindow *w,
 
1239
                        Model      *model,
 
1240
                        Object     *object)
 
1241
{
 
1242
    if (fabs (object->velocity.y) > object->horzEdge.velocity)
 
1243
    {
 
1244
        object->position.y += object->velocity.y * 2.0f;
 
1245
 
 
1246
        model->snapCnt[NORTH]--;
 
1247
 
 
1248
        object->horzEdge.snapped = FALSE;
 
1249
        object->edgeMask = 0;
 
1250
 
 
1251
        modelUpdateSnapping (w, model);
 
1252
 
 
1253
        return TRUE;
 
1254
    }
 
1255
 
 
1256
    object->velocity.y = 0.0f;
 
1257
 
 
1258
    return FALSE;
 
1259
}
 
1260
 
 
1261
static Bool
 
1262
objectReleaseSouthEdge (CompWindow *w,
 
1263
                        Model      *model,
 
1264
                        Object     *object)
 
1265
{
 
1266
    if (fabs (object->velocity.y) > object->horzEdge.velocity)
 
1267
    {
 
1268
        object->position.y += object->velocity.y * 2.0f;
 
1269
 
 
1270
        model->snapCnt[SOUTH]--;
 
1271
 
 
1272
        object->horzEdge.snapped = FALSE;
 
1273
        object->edgeMask = 0;
 
1274
 
 
1275
        modelUpdateSnapping (w, model);
 
1276
 
 
1277
        return TRUE;
 
1278
    }
 
1279
 
 
1280
    object->velocity.y = 0.0f;
 
1281
 
 
1282
    return FALSE;
 
1283
}
 
1284
 
 
1285
static float
 
1286
modelStepObject (CompWindow *window,
 
1287
                 Model      *model,
 
1288
                 Object     *object,
 
1289
                 float      friction,
 
1290
                 float      *force)
 
1291
{
 
1292
    object->theta += 0.05f;
 
1293
 
 
1294
    if (object->immobile)
 
1295
    {
 
1296
        object->velocity.x = 0.0f;
 
1297
        object->velocity.y = 0.0f;
 
1298
 
 
1299
        object->force.x = 0.0f;
 
1300
        object->force.y = 0.0f;
 
1301
 
 
1302
        *force = 0.0f;
 
1303
 
 
1304
        return 0.0f;
 
1305
    }
 
1306
    else
 
1307
    {
 
1308
        object->force.x -= friction * object->velocity.x;
 
1309
        object->force.y -= friction * object->velocity.y;
 
1310
 
 
1311
        object->velocity.x += object->force.x / MASS;
 
1312
        object->velocity.y += object->force.y / MASS;
 
1313
 
 
1314
        if (object->edgeMask)
 
1315
        {
 
1316
            if (object->edgeMask & WestEdgeMask)
 
1317
            {
 
1318
                if (object->position.y < object->vertEdge.start ||
 
1319
                    object->position.y > object->vertEdge.end)
 
1320
                    findNextWestEdge (window, object);
 
1321
 
 
1322
                if (!object->vertEdge.snapped ||
 
1323
                    objectReleaseWestEdge (window, model, object))
 
1324
                {
 
1325
                    object->position.x += object->velocity.x;
 
1326
 
 
1327
                    if (object->velocity.x < 0.0f &&
 
1328
                        object->position.x < object->vertEdge.attract)
 
1329
                    {
 
1330
                        if (object->position.x < object->vertEdge.next)
 
1331
                        {
 
1332
                            object->vertEdge.snapped = TRUE;
 
1333
                            object->position.x = object->vertEdge.next;
 
1334
                            object->velocity.x = 0.0f;
 
1335
 
 
1336
                            model->snapCnt[WEST]++;
 
1337
 
 
1338
                            modelUpdateSnapping (window, model);
 
1339
                        }
 
1340
                        else
 
1341
                        {
 
1342
                            object->velocity.x -=
 
1343
                                object->vertEdge.attract - object->position.x;
 
1344
                        }
 
1345
                    }
 
1346
 
 
1347
                    if (object->position.x > object->vertEdge.prev)
 
1348
                        findNextWestEdge (window, object);
 
1349
                }
 
1350
            }
 
1351
            else if (object->edgeMask & EastEdgeMask)
 
1352
            {
 
1353
                if (object->position.y < object->vertEdge.start ||
 
1354
                    object->position.y > object->vertEdge.end)
 
1355
                    findNextEastEdge (window, object);
 
1356
 
 
1357
                if (!object->vertEdge.snapped ||
 
1358
                    objectReleaseEastEdge (window, model, object))
 
1359
                {
 
1360
                    object->position.x += object->velocity.x;
 
1361
 
 
1362
                    if (object->velocity.x > 0.0f &&
 
1363
                        object->position.x > object->vertEdge.attract)
 
1364
                    {
 
1365
                        if (object->position.x > object->vertEdge.next)
 
1366
                        {
 
1367
                            object->vertEdge.snapped = TRUE;
 
1368
                            object->position.x = object->vertEdge.next;
 
1369
                            object->velocity.x = 0.0f;
 
1370
 
 
1371
                            model->snapCnt[EAST]++;
 
1372
 
 
1373
                            modelUpdateSnapping (window, model);
 
1374
                        }
 
1375
                        else
 
1376
                        {
 
1377
                            object->velocity.x =
 
1378
                                object->position.x - object->vertEdge.attract;
 
1379
                        }
 
1380
                    }
 
1381
 
 
1382
                    if (object->position.x < object->vertEdge.prev)
 
1383
                        findNextEastEdge (window, object);
 
1384
                }
 
1385
            }
 
1386
            else
 
1387
                object->position.x += object->velocity.x;
 
1388
 
 
1389
            if (object->edgeMask & NorthEdgeMask)
 
1390
            {
 
1391
                if (object->position.x < object->horzEdge.start ||
 
1392
                    object->position.x > object->horzEdge.end)
 
1393
                    findNextNorthEdge (window, object);
 
1394
 
 
1395
                if (!object->horzEdge.snapped ||
 
1396
                    objectReleaseNorthEdge (window, model, object))
 
1397
                {
 
1398
                    object->position.y += object->velocity.y;
 
1399
 
 
1400
                    if (object->velocity.y < 0.0f &&
 
1401
                        object->position.y < object->horzEdge.attract)
 
1402
                    {
 
1403
                        if (object->position.y < object->horzEdge.next)
 
1404
                        {
 
1405
                            object->horzEdge.snapped = TRUE;
 
1406
                            object->position.y = object->horzEdge.next;
 
1407
                            object->velocity.y = 0.0f;
 
1408
 
 
1409
                            model->snapCnt[NORTH]++;
 
1410
 
 
1411
                            modelUpdateSnapping (window, model);
 
1412
                        }
 
1413
                        else
 
1414
                        {
 
1415
                            object->velocity.y -=
 
1416
                                object->horzEdge.attract - object->position.y;
 
1417
                        }
 
1418
                    }
 
1419
 
 
1420
                    if (object->position.y > object->horzEdge.prev)
 
1421
                        findNextNorthEdge (window, object);
 
1422
                }
 
1423
            }
 
1424
            else if (object->edgeMask & SouthEdgeMask)
 
1425
            {
 
1426
                if (object->position.x < object->horzEdge.start ||
 
1427
                    object->position.x > object->horzEdge.end)
 
1428
                    findNextSouthEdge (window, object);
 
1429
 
 
1430
                if (!object->horzEdge.snapped ||
 
1431
                    objectReleaseSouthEdge (window, model, object))
 
1432
                {
 
1433
                    object->position.y += object->velocity.y;
 
1434
 
 
1435
                    if (object->velocity.y > 0.0f &&
 
1436
                        object->position.y > object->horzEdge.attract)
 
1437
                    {
 
1438
                        if (object->position.y > object->horzEdge.next)
 
1439
                        {
 
1440
                            object->horzEdge.snapped = TRUE;
 
1441
                            object->position.y = object->horzEdge.next;
 
1442
                            object->velocity.y = 0.0f;
 
1443
 
 
1444
                            model->snapCnt[SOUTH]++;
 
1445
 
 
1446
                            modelUpdateSnapping (window, model);
 
1447
                        }
 
1448
                        else
 
1449
                        {
 
1450
                            object->velocity.y =
 
1451
                                object->position.y - object->horzEdge.attract;
 
1452
                        }
 
1453
                    }
 
1454
 
 
1455
                    if (object->position.y < object->horzEdge.prev)
 
1456
                        findNextSouthEdge (window, object);
 
1457
                }
 
1458
            }
 
1459
            else
 
1460
                object->position.y += object->velocity.y;
 
1461
        }
 
1462
        else
 
1463
        {
 
1464
            object->position.x += object->velocity.x;
 
1465
            object->position.y += object->velocity.y;
 
1466
        }
 
1467
 
 
1468
        *force = fabs (object->force.x) + fabs (object->force.y);
 
1469
 
 
1470
        object->force.x = 0.0f;
 
1471
        object->force.y = 0.0f;
 
1472
 
 
1473
        return fabs (object->velocity.x) + fabs (object->velocity.y);
 
1474
    }
 
1475
}
 
1476
 
 
1477
static int
 
1478
modelStep (CompWindow *window,
 
1479
           Model      *model,
 
1480
           float      friction,
 
1481
           float      k,
 
1482
           float      time)
 
1483
{
 
1484
    int   i, j, steps, wobbly = 0;
 
1485
    float velocitySum = 0.0f;
 
1486
    float force, forceSum = 0.0f;
 
1487
 
 
1488
    model->steps += time / 15.0f;
 
1489
    steps = floor (model->steps);
 
1490
    model->steps -= steps;
 
1491
 
 
1492
    if (!steps)
 
1493
        return TRUE;
 
1494
 
 
1495
    for (j = 0; j < steps; j++)
 
1496
    {
 
1497
        for (i = 0; i < model->numSprings; i++)
 
1498
            springExertForces (&model->springs[i], k);
 
1499
 
 
1500
        for (i = 0; i < model->numObjects; i++)
 
1501
        {
 
1502
            velocitySum += modelStepObject (window,
 
1503
                                            model,
 
1504
                                            &model->objects[i],
 
1505
                                            friction,
 
1506
                                            &force);
 
1507
            forceSum += force;
 
1508
        }
 
1509
    }
 
1510
 
 
1511
    modelCalcBounds (model);
 
1512
 
 
1513
    if (velocitySum > 0.5f)
 
1514
        wobbly |= WobblyVelocity;
 
1515
 
 
1516
    if (forceSum > 20.0f)
 
1517
        wobbly |= WobblyForce;
 
1518
 
 
1519
    return wobbly;
 
1520
}
 
1521
 
 
1522
static void
 
1523
bezierPatchEvaluate (Model *model,
 
1524
                     float u,
 
1525
                     float v,
 
1526
                     float *patchX,
 
1527
                     float *patchY)
 
1528
{
 
1529
    float coeffsU[4], coeffsV[4];
 
1530
    float x, y;
 
1531
    int   i, j;
 
1532
 
 
1533
    coeffsU[0] = (1 - u) * (1 - u) * (1 - u);
 
1534
    coeffsU[1] = 3 * u * (1 - u) * (1 - u);
 
1535
    coeffsU[2] = 3 * u * u * (1 - u);
 
1536
    coeffsU[3] = u * u * u;
 
1537
 
 
1538
    coeffsV[0] = (1 - v) * (1 - v) * (1 - v);
 
1539
    coeffsV[1] = 3 * v * (1 - v) * (1 - v);
 
1540
    coeffsV[2] = 3 * v * v * (1 - v);
 
1541
    coeffsV[3] = v * v * v;
 
1542
 
 
1543
    x = y = 0.0f;
 
1544
 
 
1545
    for (i = 0; i < 4; i++)
 
1546
    {
 
1547
        for (j = 0; j < 4; j++)
 
1548
        {
 
1549
            x += coeffsU[i] * coeffsV[j] *
 
1550
                model->objects[j * GRID_WIDTH + i].position.x;
 
1551
            y += coeffsU[i] * coeffsV[j] *
 
1552
                model->objects[j * GRID_WIDTH + i].position.y;
 
1553
        }
 
1554
    }
 
1555
 
 
1556
    *patchX = x;
 
1557
    *patchY = y;
 
1558
}
 
1559
 
 
1560
static Bool
 
1561
wobblyEnsureModel (CompWindow *w)
 
1562
{
 
1563
    WOBBLY_WINDOW (w);
 
1564
 
 
1565
    if (!ww->model)
 
1566
    {
 
1567
        unsigned int edgeMask = 0;
 
1568
 
 
1569
        if (w->type & CompWindowTypeNormalMask)
 
1570
            edgeMask = WestEdgeMask | EastEdgeMask | NorthEdgeMask |
 
1571
                SouthEdgeMask;
 
1572
 
 
1573
        ww->model = createModel (WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w),
 
1574
                                 edgeMask);
 
1575
        if (!ww->model)
 
1576
            return FALSE;
 
1577
    }
 
1578
 
 
1579
    return TRUE;
 
1580
}
 
1581
 
 
1582
static float
 
1583
objectDistance (Object *object,
 
1584
                float  x,
 
1585
                float  y)
 
1586
{
 
1587
    float dx, dy;
 
1588
 
 
1589
    dx = object->position.x - x;
 
1590
    dy = object->position.y - y;
 
1591
 
 
1592
    return sqrt (dx * dx + dy * dy);
 
1593
}
 
1594
 
 
1595
static Object *
 
1596
modelFindNearestObject (Model *model,
 
1597
                        float x,
 
1598
                        float y)
 
1599
{
 
1600
    Object *object = &model->objects[0];
 
1601
    float  distance, minDistance = 0.0;
 
1602
    int    i;
 
1603
 
 
1604
    for (i = 0; i < model->numObjects; i++)
 
1605
    {
 
1606
        distance = objectDistance (&model->objects[i], x, y);
 
1607
        if (i == 0 || distance < minDistance)
 
1608
        {
 
1609
            minDistance = distance;
 
1610
            object = &model->objects[i];
 
1611
        }
 
1612
    }
 
1613
 
 
1614
    return object;
 
1615
}
 
1616
 
 
1617
static Bool
 
1618
isWobblyWin (CompWindow *w)
 
1619
{
 
1620
    WOBBLY_WINDOW (w);
 
1621
 
 
1622
    if (ww->model)
 
1623
        return TRUE;
 
1624
 
 
1625
    /* avoid tiny windows */
 
1626
    if (w->width == 1 && w->height == 1)
 
1627
        return FALSE;
 
1628
 
 
1629
    /* avoid fullscreen windows */
 
1630
    if (w->attrib.x <= 0 &&
 
1631
        w->attrib.y <= 0 &&
 
1632
        w->attrib.x + w->width >= w->screen->width &&
 
1633
        w->attrib.y + w->height >= w->screen->height)
 
1634
        return FALSE;
 
1635
 
 
1636
    return TRUE;
 
1637
}
 
1638
 
 
1639
static void
 
1640
wobblyPreparePaintScreen (CompScreen *s,
 
1641
                          int        msSinceLastPaint)
 
1642
{
 
1643
    WobblyWindow *ww;
 
1644
    CompWindow   *w;
 
1645
 
 
1646
    WOBBLY_SCREEN (s);
 
1647
 
 
1648
    if (ws->wobblyWindows & (WobblyInitial | WobblyVelocity))
 
1649
    {
 
1650
        BoxRec box;
 
1651
        Point  topLeft, bottomRight;
 
1652
        float  friction, springK;
 
1653
        Model  *model;
 
1654
 
 
1655
        friction = ws->opt[WOBBLY_SCREEN_OPTION_FRICTION].value.f;
 
1656
        springK  = ws->opt[WOBBLY_SCREEN_OPTION_SPRING_K].value.f;
 
1657
 
 
1658
        ws->wobblyWindows = 0;
 
1659
        for (w = s->windows; w; w = w->next)
 
1660
        {
 
1661
            ww = GET_WOBBLY_WINDOW (w, ws);
 
1662
 
 
1663
            if (ww->wobbly)
 
1664
            {
 
1665
                if (ww->wobbly & (WobblyInitial | WobblyVelocity))
 
1666
                {
 
1667
                    model = ww->model;
 
1668
 
 
1669
                    topLeft     = model->topLeft;
 
1670
                    bottomRight = model->bottomRight;
 
1671
 
 
1672
                    ww->wobbly = modelStep (w, model, friction, springK,
 
1673
                                            (ww->wobbly & WobblyVelocity) ?
 
1674
                                            msSinceLastPaint :
 
1675
                                            s->redrawTime);
 
1676
 
 
1677
                    if ((ww->state & MAXIMIZE_STATE) && ww->grabbed)
 
1678
                        ww->wobbly |= WobblyForce;
 
1679
 
 
1680
                    if (ww->wobbly)
 
1681
                    {
 
1682
                        /* snapped to more than one edge, we have to reduce
 
1683
                           edge escape velocity until only one edge is snapped */
 
1684
                        if (ww->wobbly == WobblyForce && !ww->grabbed)
 
1685
                        {
 
1686
                            modelReduceEdgeEscapeVelocity (ww->model);
 
1687
                            ww->wobbly |= WobblyInitial;
 
1688
                        }
 
1689
                    }
 
1690
                    else
 
1691
                    {
 
1692
                        ww->model = 0;
 
1693
 
 
1694
                        if (w->attrib.x == w->serverX &&
 
1695
                            w->attrib.y == w->serverY)
 
1696
                        {
 
1697
                            moveWindow (w,
 
1698
                                        model->topLeft.x + w->output.left -
 
1699
                                        w->attrib.x,
 
1700
                                        model->topLeft.y + w->output.top -
 
1701
                                        w->attrib.y,
 
1702
                                        TRUE, TRUE);
 
1703
                            syncWindowPosition (w);
 
1704
                        }
 
1705
 
 
1706
                        ww->model = model;
 
1707
                    }
 
1708
 
 
1709
                    if (!(s->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK))
 
1710
                    {
 
1711
                        if (ww->wobbly)
 
1712
                        {
 
1713
                            if (ww->model->topLeft.x < topLeft.x)
 
1714
                                topLeft.x = ww->model->topLeft.x;
 
1715
                            if (ww->model->topLeft.y < topLeft.y)
 
1716
                                topLeft.y = ww->model->topLeft.y;
 
1717
                            if (ww->model->bottomRight.x > bottomRight.x)
 
1718
                                bottomRight.x = ww->model->bottomRight.x;
 
1719
                            if (ww->model->bottomRight.y > bottomRight.y)
 
1720
                                bottomRight.y = ww->model->bottomRight.y;
 
1721
                        }
 
1722
                        else
 
1723
                            addWindowDamage (w);
 
1724
 
 
1725
                        box.x1 = topLeft.x;
 
1726
                        box.y1 = topLeft.y;
 
1727
                        box.x2 = bottomRight.x + 0.5f;
 
1728
                        box.y2 = bottomRight.y + 0.5f;
 
1729
 
 
1730
                        box.x1 -= w->attrib.x + w->attrib.border_width;
 
1731
                        box.y1 -= w->attrib.y + w->attrib.border_width;
 
1732
                        box.x2 -= w->attrib.x + w->attrib.border_width;
 
1733
                        box.y2 -= w->attrib.y + w->attrib.border_width;
 
1734
 
 
1735
                        addWindowDamageRect (w, &box);
 
1736
                    }
 
1737
                }
 
1738
 
 
1739
                ws->wobblyWindows |= ww->wobbly;
 
1740
            }
 
1741
        }
 
1742
    }
 
1743
 
 
1744
    UNWRAP (ws, s, preparePaintScreen);
 
1745
    (*s->preparePaintScreen) (s, msSinceLastPaint);
 
1746
    WRAP (ws, s, preparePaintScreen, wobblyPreparePaintScreen);
 
1747
}
 
1748
 
 
1749
static void
 
1750
wobblyDonePaintScreen (CompScreen *s)
 
1751
{
 
1752
    WOBBLY_SCREEN (s);
 
1753
 
 
1754
    if (ws->wobblyWindows & (WobblyVelocity | WobblyInitial))
 
1755
        damagePendingOnScreen (s);
 
1756
 
 
1757
    UNWRAP (ws, s, donePaintScreen);
 
1758
    (*s->donePaintScreen) (s);
 
1759
    WRAP (ws, s, donePaintScreen, wobblyDonePaintScreen);
 
1760
}
 
1761
 
 
1762
static void
 
1763
wobblyDrawWindowGeometry (CompWindow *w)
 
1764
{
 
1765
    int     texUnit = w->texUnits;
 
1766
    int     currentTexUnit = 0;
 
1767
    int     stride = w->vertexStride;
 
1768
    GLfloat *vertices = w->vertices + (stride - 3);
 
1769
 
 
1770
    stride *= sizeof (GLfloat);
 
1771
 
 
1772
    glVertexPointer (3, GL_FLOAT, stride, vertices);
 
1773
 
 
1774
    while (texUnit--)
 
1775
    {
 
1776
        if (texUnit != currentTexUnit)
 
1777
        {
 
1778
            w->screen->clientActiveTexture (GL_TEXTURE0_ARB + texUnit);
 
1779
            glEnableClientState (GL_TEXTURE_COORD_ARRAY);
 
1780
            currentTexUnit = texUnit;
 
1781
        }
 
1782
        vertices -= w->texCoordSize;
 
1783
        glTexCoordPointer (w->texCoordSize, GL_FLOAT, stride, vertices);
 
1784
    }
 
1785
 
 
1786
    glDrawElements (GL_QUADS, w->indexCount, GL_UNSIGNED_SHORT, w->indices);
 
1787
 
 
1788
    /* disable all texture coordinate arrays except 0 */
 
1789
    texUnit = w->texUnits;
 
1790
    if (texUnit > 1)
 
1791
    {
 
1792
        while (--texUnit)
 
1793
        {
 
1794
            (*w->screen->clientActiveTexture) (GL_TEXTURE0_ARB + texUnit);
 
1795
            glDisableClientState (GL_TEXTURE_COORD_ARRAY);
 
1796
        }
 
1797
 
 
1798
        (*w->screen->clientActiveTexture) (GL_TEXTURE0_ARB);
 
1799
    }
 
1800
}
 
1801
 
 
1802
static void
 
1803
wobblyAddWindowGeometry (CompWindow *w,
 
1804
                         CompMatrix *matrix,
 
1805
                         int        nMatrix,
 
1806
                         Region     region,
 
1807
                         Region     clip)
 
1808
{
 
1809
    WOBBLY_WINDOW (w);
 
1810
    WOBBLY_SCREEN (w->screen);
 
1811
 
 
1812
    if (ww->wobbly)
 
1813
    {
 
1814
        BoxPtr   pClip;
 
1815
        int      nClip, nVertices, nIndices;
 
1816
        GLushort *i;
 
1817
        GLfloat  *v;
 
1818
        int      x1, y1, x2, y2;
 
1819
        float    width, height;
 
1820
        float    deformedX, deformedY;
 
1821
        int      x, y, iw, ih, wx, wy;
 
1822
        int      vSize, it;
 
1823
        int      gridW, gridH;
 
1824
        Bool     rect = TRUE;
 
1825
 
 
1826
        for (it = 0; it < nMatrix; it++)
 
1827
        {
 
1828
            if (matrix[it].xy != 0.0f || matrix[it].yx != 0.0f)
 
1829
            {
 
1830
                rect = FALSE;
 
1831
                break;
 
1832
            }
 
1833
        }
 
1834
 
 
1835
        wx     = WIN_X (w);
 
1836
        wy     = WIN_Y (w);
 
1837
        width  = WIN_W (w);
 
1838
        height = WIN_H (w);
 
1839
 
 
1840
        gridW = width / ws->opt[WOBBLY_SCREEN_OPTION_GRID_RESOLUTION].value.i;
 
1841
        if (gridW < ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i)
 
1842
            gridW = ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i;
 
1843
 
 
1844
        gridH = height / ws->opt[WOBBLY_SCREEN_OPTION_GRID_RESOLUTION].value.i;
 
1845
        if (gridH < ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i)
 
1846
            gridH = ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i;
 
1847
 
 
1848
        nClip = region->numRects;
 
1849
        pClip = region->rects;
 
1850
 
 
1851
        w->texUnits = nMatrix;
 
1852
 
 
1853
        vSize = 3 + nMatrix * 2;
 
1854
 
 
1855
        nVertices = w->vCount;
 
1856
        nIndices  = w->indexCount;
 
1857
 
 
1858
        v = w->vertices + (nVertices * vSize);
 
1859
        i = w->indices  + nIndices;
 
1860
 
 
1861
        while (nClip--)
 
1862
        {
 
1863
            x1 = pClip->x1;
 
1864
            y1 = pClip->y1;
 
1865
            x2 = pClip->x2;
 
1866
            y2 = pClip->y2;
 
1867
 
 
1868
            iw = ((x2 - x1 - 1) / gridW) + 1;
 
1869
            ih = ((y2 - y1 - 1) / gridH) + 1;
 
1870
 
 
1871
            if (nIndices + (iw * ih * 4) > w->indexSize)
 
1872
            {
 
1873
                if (!moreWindowIndices (w, nIndices + (iw * ih * 4)))
 
1874
                    return;
 
1875
 
 
1876
                i = w->indices + nIndices;
 
1877
            }
 
1878
 
 
1879
            iw++;
 
1880
            ih++;
 
1881
 
 
1882
            for (y = 0; y < ih - 1; y++)
 
1883
            {
 
1884
                for (x = 0; x < iw - 1; x++)
 
1885
                {
 
1886
                    *i++ = nVertices + iw * (y + 1) + x;
 
1887
                    *i++ = nVertices + iw * (y + 1) + x + 1;
 
1888
                    *i++ = nVertices + iw * y + x + 1;
 
1889
                    *i++ = nVertices + iw * y + x;
 
1890
 
 
1891
                    nIndices += 4;
 
1892
                }
 
1893
            }
 
1894
 
 
1895
            if (((nVertices + iw * ih) * vSize) > w->vertexSize)
 
1896
            {
 
1897
                if (!moreWindowVertices (w, (nVertices + iw * ih) * vSize))
 
1898
                    return;
 
1899
 
 
1900
                v = w->vertices + (nVertices * vSize);
 
1901
            }
 
1902
 
 
1903
            for (y = y1;; y += gridH)
 
1904
            {
 
1905
                if (y > y2)
 
1906
                    y = y2;
 
1907
 
 
1908
                for (x = x1;; x += gridW)
 
1909
                {
 
1910
                    if (x > x2)
 
1911
                        x = x2;
 
1912
 
 
1913
                    bezierPatchEvaluate (ww->model,
 
1914
                                         (x - wx) / width,
 
1915
                                         (y - wy) / height,
 
1916
                                         &deformedX,
 
1917
                                         &deformedY);
 
1918
 
 
1919
                    if (rect)
 
1920
                    {
 
1921
                        for (it = 0; it < nMatrix; it++)
 
1922
                        {
 
1923
                            *v++ = COMP_TEX_COORD_X (&matrix[it], x);
 
1924
                            *v++ = COMP_TEX_COORD_Y (&matrix[it], y);
 
1925
                        }
 
1926
                    }
 
1927
                    else
 
1928
                    {
 
1929
                        for (it = 0; it < nMatrix; it++)
 
1930
                        {
 
1931
                            *v++ = COMP_TEX_COORD_XY (&matrix[it], x, y);
 
1932
                            *v++ = COMP_TEX_COORD_YX (&matrix[it], x, y);
 
1933
                        }
 
1934
                    }
 
1935
 
 
1936
                    *v++ = deformedX;
 
1937
                    *v++ = deformedY;
 
1938
                    *v++ = 0.0;
 
1939
 
 
1940
                    nVertices++;
 
1941
 
 
1942
                    if (x == x2)
 
1943
                        break;
 
1944
                }
 
1945
 
 
1946
                if (y == y2)
 
1947
                    break;
 
1948
            }
 
1949
 
 
1950
            pClip++;
 
1951
        }
 
1952
 
 
1953
        w->vCount             = nVertices;
 
1954
        w->vertexStride       = vSize;
 
1955
        w->texCoordSize       = 2;
 
1956
        w->indexCount         = nIndices;
 
1957
        w->drawWindowGeometry = wobblyDrawWindowGeometry;
 
1958
    }
 
1959
    else
 
1960
    {
 
1961
        UNWRAP (ws, w->screen, addWindowGeometry);
 
1962
        (*w->screen->addWindowGeometry) (w, matrix, nMatrix, region, clip);
 
1963
        WRAP (ws, w->screen, addWindowGeometry, wobblyAddWindowGeometry);
 
1964
    }
 
1965
}
 
1966
 
 
1967
static Bool
 
1968
wobblyPaintWindow (CompWindow              *w,
 
1969
                   const WindowPaintAttrib *attrib,
 
1970
                   const CompTransform     *transform,
 
1971
                   Region                  region,
 
1972
                   unsigned int            mask)
 
1973
{
 
1974
    Bool status;
 
1975
 
 
1976
    WOBBLY_SCREEN (w->screen);
 
1977
    WOBBLY_WINDOW (w);
 
1978
 
 
1979
    if (ww->wobbly)
 
1980
        mask |= PAINT_WINDOW_TRANSFORMED_MASK;
 
1981
 
 
1982
    UNWRAP (ws, w->screen, paintWindow);
 
1983
    status = (*w->screen->paintWindow) (w, attrib, transform, region, mask);
 
1984
    WRAP (ws, w->screen, paintWindow, wobblyPaintWindow);
 
1985
 
 
1986
    return status;
 
1987
}
 
1988
 
 
1989
static Bool
 
1990
wobblyEnableSnapping (CompDisplay     *d,
 
1991
                      CompAction      *action,
 
1992
                      CompActionState state,
 
1993
                      CompOption      *option,
 
1994
                      int             nOption)
 
1995
{
 
1996
    CompScreen *s;
 
1997
    CompWindow *w;
 
1998
 
 
1999
    WOBBLY_DISPLAY (d);
 
2000
 
 
2001
    for (s = d->screens; s; s = s->next)
 
2002
    {
 
2003
        for (w = s->windows; w; w = w->next)
 
2004
        {
 
2005
            WOBBLY_WINDOW (w);
 
2006
 
 
2007
            if (ww->grabbed && ww->model)
 
2008
                modelUpdateSnapping (w, ww->model);
 
2009
        }
 
2010
    }
 
2011
 
 
2012
    wd->snapping = TRUE;
 
2013
 
 
2014
    return FALSE;
 
2015
}
 
2016
 
 
2017
static Bool
 
2018
wobblyDisableSnapping (CompDisplay     *d,
 
2019
                       CompAction      *action,
 
2020
                       CompActionState state,
 
2021
                       CompOption      *option,
 
2022
                       int             nOption)
 
2023
{
 
2024
    CompScreen *s;
 
2025
    CompWindow *w;
 
2026
 
 
2027
    WOBBLY_DISPLAY (d);
 
2028
 
 
2029
    if (!wd->snapping)
 
2030
        return FALSE;
 
2031
 
 
2032
    for (s = d->screens; s; s = s->next)
 
2033
    {
 
2034
        for (w = s->windows; w; w = w->next)
 
2035
        {
 
2036
            WOBBLY_WINDOW (w);
 
2037
 
 
2038
            if (ww->grabbed && ww->model)
 
2039
            {
 
2040
                if (modelDisableSnapping (w, ww->model))
 
2041
                {
 
2042
                    WOBBLY_SCREEN (w->screen);
 
2043
 
 
2044
                    ww->wobbly |= WobblyInitial;
 
2045
                    ws->wobblyWindows |= ww->wobbly;
 
2046
 
 
2047
                    damagePendingOnScreen (w->screen);
 
2048
                }
 
2049
            }
 
2050
        }
 
2051
    }
 
2052
 
 
2053
    wd->snapping = FALSE;
 
2054
 
 
2055
    return FALSE;
 
2056
}
 
2057
 
 
2058
static Bool
 
2059
wobblyShiver (CompDisplay     *d,
 
2060
              CompAction      *action,
 
2061
              CompActionState state,
 
2062
              CompOption      *option,
 
2063
              int             nOption)
 
2064
{
 
2065
    CompWindow *w;
 
2066
    Window     xid;
 
2067
 
 
2068
    xid = getIntOptionNamed (option, nOption, "window", 0);
 
2069
 
 
2070
    w = findWindowAtDisplay (d, xid);
 
2071
    if (w && isWobblyWin (w) && wobblyEnsureModel (w))
 
2072
    {
 
2073
        WOBBLY_SCREEN (w->screen);
 
2074
        WOBBLY_WINDOW (w);
 
2075
 
 
2076
        modelSetMiddleAnchor (ww->model,
 
2077
                              WIN_X (w), WIN_Y (w),
 
2078
                              WIN_W (w), WIN_H (w));
 
2079
        modelAdjustObjectsForShiver (ww->model,
 
2080
                                     WIN_X (w), WIN_Y (w),
 
2081
                                     WIN_W (w), WIN_H (w));
 
2082
 
 
2083
        ww->wobbly |= WobblyInitial;
 
2084
        ws->wobblyWindows |= ww->wobbly;
 
2085
 
 
2086
        damagePendingOnScreen (w->screen);
 
2087
    }
 
2088
 
 
2089
    return FALSE;
 
2090
}
 
2091
 
 
2092
static void
 
2093
wobblyHandleEvent (CompDisplay *d,
 
2094
                   XEvent      *event)
 
2095
{
 
2096
    Window     activeWindow = d->activeWindow;
 
2097
    CompWindow *w;
 
2098
    CompScreen *s;
 
2099
 
 
2100
    WOBBLY_DISPLAY (d);
 
2101
 
 
2102
    switch (event->type) {
 
2103
    case MapNotify:
 
2104
        w = findWindowAtDisplay (d, event->xmap.window);
 
2105
        if (w)
 
2106
        {
 
2107
            WOBBLY_WINDOW (w);
 
2108
 
 
2109
            if (ww->model)
 
2110
            {
 
2111
                modelInitObjects (ww->model,
 
2112
                                  WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
 
2113
 
 
2114
                modelInitSprings (ww->model,
 
2115
                                  WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
 
2116
            }
 
2117
        }
 
2118
        break;
 
2119
    default:
 
2120
        if (event->type == d->xkbEvent)
 
2121
        {
 
2122
            XkbAnyEvent *xkbEvent = (XkbAnyEvent *) event;
 
2123
 
 
2124
            if (xkbEvent->xkb_type == XkbStateNotify)
 
2125
            {
 
2126
                XkbStateNotifyEvent *stateEvent = (XkbStateNotifyEvent *) event;
 
2127
                CompAction          *action;
 
2128
                Bool                inverted;
 
2129
                unsigned int        mods = 0xffffffff;
 
2130
 
 
2131
                action   =
 
2132
                    &wd->opt[WOBBLY_DISPLAY_OPTION_SNAP_KEY].value.action;
 
2133
                inverted = wd->opt[WOBBLY_DISPLAY_OPTION_SNAP_INVERTED].value.b;
 
2134
 
 
2135
                if (action->type & CompBindingTypeKey)
 
2136
                    mods = action->key.modifiers;
 
2137
 
 
2138
                if ((stateEvent->mods & mods) == mods)
 
2139
                {
 
2140
                    if (inverted)
 
2141
                        wobblyDisableSnapping (d, NULL, 0, NULL, 0);
 
2142
                    else
 
2143
                        wobblyEnableSnapping (d, NULL, 0, NULL, 0);
 
2144
                }
 
2145
                else
 
2146
                {
 
2147
                    if (inverted)
 
2148
                        wobblyEnableSnapping (d, NULL, 0, NULL, 0);
 
2149
                    else
 
2150
                        wobblyDisableSnapping (d, NULL, 0, NULL, 0);
 
2151
                }
 
2152
            }
 
2153
        }
 
2154
        break;
 
2155
    }
 
2156
 
 
2157
    UNWRAP (wd, d, handleEvent);
 
2158
    (*d->handleEvent) (d, event);
 
2159
    WRAP (wd, d, handleEvent, wobblyHandleEvent);
 
2160
 
 
2161
    switch (event->type) {
 
2162
    case MotionNotify:
 
2163
        s = findScreenAtDisplay (d, event->xmotion.root);
 
2164
        if (s)
 
2165
        {
 
2166
            WOBBLY_SCREEN (s);
 
2167
 
 
2168
            if (ws->grabWindow &&
 
2169
                ws->moveWindow &&
 
2170
                ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b)
 
2171
            {
 
2172
                WOBBLY_WINDOW (ws->grabWindow);
 
2173
 
 
2174
                if (ww->state & MAXIMIZE_STATE)
 
2175
                {
 
2176
                    if (ww->model && ww->grabbed)
 
2177
                    {
 
2178
                        int dx, dy;
 
2179
 
 
2180
                        if (ww->state & CompWindowStateMaximizedHorzMask)
 
2181
                            dx = pointerX - lastPointerX;
 
2182
                        else
 
2183
                            dx = 0;
 
2184
 
 
2185
                        if (ww->state & CompWindowStateMaximizedVertMask)
 
2186
                            dy = pointerY - lastPointerY;
 
2187
                        else
 
2188
                            dy = 0;
 
2189
 
 
2190
                        ww->model->anchorObject->position.x += dx;
 
2191
                        ww->model->anchorObject->position.y += dy;
 
2192
 
 
2193
                        ww->wobbly |= WobblyInitial;
 
2194
                        ws->wobblyWindows |= ww->wobbly;
 
2195
 
 
2196
                        damagePendingOnScreen (s);
 
2197
                    }
 
2198
                }
 
2199
            }
 
2200
        }
 
2201
    default:
 
2202
        break;
 
2203
    }
 
2204
 
 
2205
    if (d->activeWindow != activeWindow)
 
2206
    {
 
2207
        w = findWindowAtDisplay (d, d->activeWindow);
 
2208
        if (w && isWobblyWin (w))
 
2209
        {
 
2210
            int mIndex;
 
2211
            int focusEffect;
 
2212
 
 
2213
            WOBBLY_WINDOW (w);
 
2214
            WOBBLY_SCREEN (w->screen);
 
2215
 
 
2216
            mIndex      = WOBBLY_SCREEN_OPTION_FOCUS_WINDOW_MATCH;
 
2217
            focusEffect = ws->opt[WOBBLY_SCREEN_OPTION_FOCUS_EFFECT].value.i;
 
2218
 
 
2219
            if ((focusEffect != WOBBLY_EFFECT_NONE)         &&
 
2220
                matchEval (&ws->opt[mIndex].value.match, w) &&
 
2221
                wobblyEnsureModel (w))
 
2222
            {
 
2223
                switch (focusEffect) {
 
2224
                case WOBBLY_EFFECT_SHIVER:
 
2225
                    modelAdjustObjectsForShiver (ww->model,
 
2226
                                                 WIN_X (w),
 
2227
                                                 WIN_Y (w),
 
2228
                                                 WIN_W (w),
 
2229
                                                 WIN_H (w));
 
2230
                default:
 
2231
                    break;
 
2232
                }
 
2233
 
 
2234
                ww->wobbly |= WobblyInitial;
 
2235
                ws->wobblyWindows |= ww->wobbly;
 
2236
 
 
2237
                damagePendingOnScreen (w->screen);
 
2238
            }
 
2239
        }
 
2240
    }
 
2241
}
 
2242
 
 
2243
static Bool
 
2244
wobblyDamageWindowRect (CompWindow *w,
 
2245
                        Bool       initial,
 
2246
                        BoxPtr     rect)
 
2247
{
 
2248
    Bool status;
 
2249
 
 
2250
    WOBBLY_SCREEN (w->screen);
 
2251
 
 
2252
    if (!initial)
 
2253
    {
 
2254
        WOBBLY_WINDOW (w);
 
2255
 
 
2256
        if (ww->wobbly == WobblyForce)
 
2257
        {
 
2258
            REGION region;
 
2259
 
 
2260
            region.rects = &region.extents;
 
2261
            region.numRects = region.size = 1;
 
2262
 
 
2263
            region.extents.x1 = ww->model->topLeft.x;
 
2264
            region.extents.y1 = ww->model->topLeft.y;
 
2265
            region.extents.x2 = ww->model->bottomRight.x + 0.5f;
 
2266
            region.extents.y2 = ww->model->bottomRight.y + 0.5f;
 
2267
 
 
2268
            damageScreenRegion (w->screen, &region);
 
2269
 
 
2270
            return TRUE;
 
2271
        }
 
2272
    }
 
2273
 
 
2274
    UNWRAP (ws, w->screen, damageWindowRect);
 
2275
    status = (*w->screen->damageWindowRect) (w, initial, rect);
 
2276
    WRAP (ws, w->screen, damageWindowRect, wobblyDamageWindowRect);
 
2277
 
 
2278
    if (initial)
 
2279
    {
 
2280
        if (isWobblyWin (w))
 
2281
        {
 
2282
            int mIndex;
 
2283
            int mapEffect;
 
2284
 
 
2285
            WOBBLY_WINDOW (w);
 
2286
            WOBBLY_SCREEN (w->screen);
 
2287
 
 
2288
            mIndex    = WOBBLY_SCREEN_OPTION_MAP_WINDOW_MATCH;
 
2289
            mapEffect = ws->opt[WOBBLY_SCREEN_OPTION_MAP_EFFECT].value.i;
 
2290
 
 
2291
            if (ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b)
 
2292
                wobblyEnsureModel (w);
 
2293
 
 
2294
            if ((mapEffect != WOBBLY_EFFECT_NONE)           &&
 
2295
                matchEval (&ws->opt[mIndex].value.match, w) &&
 
2296
                wobblyEnsureModel (w))
 
2297
            {
 
2298
                switch (mapEffect) {
 
2299
                case WOBBLY_EFFECT_SHIVER:
 
2300
                    modelAdjustObjectsForShiver (ww->model,
 
2301
                                                 WIN_X (w), WIN_Y (w),
 
2302
                                                 WIN_W (w), WIN_H (w));
 
2303
                default:
 
2304
                    break;
 
2305
                }
 
2306
 
 
2307
                ww->wobbly |= WobblyInitial;
 
2308
                ws->wobblyWindows |= ww->wobbly;
 
2309
 
 
2310
                damagePendingOnScreen (w->screen);
 
2311
            }
 
2312
        }
 
2313
    }
 
2314
 
 
2315
    return status;
 
2316
}
 
2317
 
 
2318
static void
 
2319
wobblyWindowResizeNotify (CompWindow *w,
 
2320
                          int        dx,
 
2321
                          int        dy,
 
2322
                          int        dwidth,
 
2323
                          int        dheight)
 
2324
{
 
2325
    WOBBLY_SCREEN (w->screen);
 
2326
    WOBBLY_WINDOW (w);
 
2327
 
 
2328
    if (ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b &&
 
2329
        isWobblyWin (w)                                       &&
 
2330
        /* prevent wobbling when shading maximized windows - assuming that
 
2331
           the height difference shaded - non-shaded will hardly be -1 and
 
2332
           a lack of wobbly animation in that corner case is tolerable */
 
2333
        (dheight != -1)                                       &&
 
2334
        ((w->state | ww->state) & MAXIMIZE_STATE))
 
2335
    {
 
2336
        ww->state &= ~MAXIMIZE_STATE;
 
2337
        ww->state |= w->state & MAXIMIZE_STATE;
 
2338
 
 
2339
        if (wobblyEnsureModel (w))
 
2340
        {
 
2341
            if (w->state & MAXIMIZE_STATE)
 
2342
            {
 
2343
                if (!ww->grabbed && ww->model->anchorObject)
 
2344
                {
 
2345
                    ww->model->anchorObject->immobile = FALSE;
 
2346
                    ww->model->anchorObject = NULL;
 
2347
                }
 
2348
 
 
2349
                modelAddEdgeAnchors (ww->model,
 
2350
                                     WIN_X (w), WIN_Y (w),
 
2351
                                     WIN_W (w), WIN_H (w));
 
2352
            }
 
2353
            else
 
2354
            {
 
2355
                modelRemoveEdgeAnchors (ww->model,
 
2356
                                        WIN_X (w), WIN_Y (w),
 
2357
                                        WIN_W (w), WIN_H (w));
 
2358
                modelSetMiddleAnchor (ww->model,
 
2359
                                      WIN_X (w), WIN_Y (w),
 
2360
                                      WIN_W (w), WIN_H (w));
 
2361
            }
 
2362
 
 
2363
            modelInitSprings (ww->model,
 
2364
                              WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
 
2365
 
 
2366
            ww->wobbly |= WobblyInitial;
 
2367
            ws->wobblyWindows |= ww->wobbly;
 
2368
 
 
2369
            damagePendingOnScreen (w->screen);
 
2370
        }
 
2371
    }
 
2372
    else if (ww->model)
 
2373
    {
 
2374
        if (ww->wobbly)
 
2375
        {
 
2376
            if (!(ww->state & MAXIMIZE_STATE))
 
2377
                modelSetTopAnchor (ww->model, WIN_X (w), WIN_Y (w), WIN_W (w));
 
2378
        }
 
2379
        else
 
2380
        {
 
2381
            modelInitObjects (ww->model,
 
2382
                              WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
 
2383
        }
 
2384
 
 
2385
        modelInitSprings (ww->model,
 
2386
                          WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
 
2387
    }
 
2388
 
 
2389
    /* update grab */
 
2390
    if (ww->model && ww->grabbed)
 
2391
    {
 
2392
        if (ww->model->anchorObject)
 
2393
            ww->model->anchorObject->immobile = FALSE;
 
2394
 
 
2395
        ww->model->anchorObject = modelFindNearestObject (ww->model,
 
2396
                                                          pointerX,
 
2397
                                                          pointerY);
 
2398
        ww->model->anchorObject->immobile = TRUE;
 
2399
 
 
2400
        modelAdjustObjectPosition (ww->model,
 
2401
                                   ww->model->anchorObject,
 
2402
                                   WIN_X (w), WIN_Y (w),
 
2403
                                   WIN_W (w), WIN_H (w));
 
2404
    }
 
2405
 
 
2406
    UNWRAP (ws, w->screen, windowResizeNotify);
 
2407
    (*w->screen->windowResizeNotify) (w, dx, dy, dwidth, dheight);
 
2408
    WRAP (ws, w->screen, windowResizeNotify, wobblyWindowResizeNotify);
 
2409
}
 
2410
 
 
2411
static void
 
2412
wobblyWindowMoveNotify (CompWindow *w,
 
2413
                        int        dx,
 
2414
                        int        dy,
 
2415
                        Bool       immediate)
 
2416
{
 
2417
    WOBBLY_SCREEN (w->screen);
 
2418
    WOBBLY_WINDOW (w);
 
2419
 
 
2420
    if (ww->model)
 
2421
    {
 
2422
        if (ww->grabbed && !immediate)
 
2423
        {
 
2424
            if (ww->state & MAXIMIZE_STATE)
 
2425
            {
 
2426
                int i;
 
2427
 
 
2428
                for (i = 0; i < ww->model->numObjects; i++)
 
2429
                {
 
2430
                    if (ww->model->objects[i].immobile)
 
2431
                    {
 
2432
                        ww->model->objects[i].position.x += dx;
 
2433
                        ww->model->objects[i].position.y += dy;
 
2434
                    }
 
2435
                }
 
2436
            }
 
2437
            else
 
2438
            {
 
2439
                ww->model->anchorObject->position.x += dx;
 
2440
                ww->model->anchorObject->position.y += dy;
 
2441
            }
 
2442
 
 
2443
            ww->wobbly |= WobblyInitial;
 
2444
            ws->wobblyWindows |= ww->wobbly;
 
2445
 
 
2446
            damagePendingOnScreen (w->screen);
 
2447
        }
 
2448
        else
 
2449
            modelMove (ww->model, dx, dy);
 
2450
    }
 
2451
 
 
2452
    UNWRAP (ws, w->screen, windowMoveNotify);
 
2453
    (*w->screen->windowMoveNotify) (w, dx, dy, immediate);
 
2454
    WRAP (ws, w->screen, windowMoveNotify, wobblyWindowMoveNotify);
 
2455
}
 
2456
 
 
2457
static void
 
2458
wobblyWindowGrabNotify (CompWindow   *w,
 
2459
                        int          x,
 
2460
                        int          y,
 
2461
                        unsigned int state,
 
2462
                        unsigned int mask)
 
2463
{
 
2464
    int mIndex;
 
2465
 
 
2466
    WOBBLY_SCREEN (w->screen);
 
2467
 
 
2468
    mIndex = WOBBLY_SCREEN_OPTION_MOVE_WINDOW_MATCH;
 
2469
 
 
2470
    if (!ws->grabWindow)
 
2471
    {
 
2472
        ws->grabMask   = mask;
 
2473
        ws->grabWindow = w;
 
2474
    }
 
2475
    ws->moveWindow = FALSE;
 
2476
 
 
2477
    if ((mask & CompWindowGrabButtonMask)           &&
 
2478
        matchEval (&ws->opt[mIndex].value.match, w) &&
 
2479
        isWobblyWin (w))
 
2480
    {
 
2481
        WOBBLY_WINDOW (w);
 
2482
 
 
2483
        ws->moveWindow = TRUE;
 
2484
 
 
2485
        if (wobblyEnsureModel (w))
 
2486
        {
 
2487
            Spring *s;
 
2488
            int    i;
 
2489
 
 
2490
            if (ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b)
 
2491
            {
 
2492
                if (w->state & MAXIMIZE_STATE)
 
2493
                {
 
2494
                    modelAddEdgeAnchors (ww->model,
 
2495
                                         WIN_X (w), WIN_Y (w),
 
2496
                                         WIN_W (w), WIN_H (w));
 
2497
                }
 
2498
                else
 
2499
                {
 
2500
                    modelRemoveEdgeAnchors (ww->model,
 
2501
                                            WIN_X (w), WIN_Y (w),
 
2502
                                            WIN_W (w), WIN_H (w));
 
2503
 
 
2504
                    if (ww->model->anchorObject)
 
2505
                        ww->model->anchorObject->immobile = FALSE;
 
2506
                }
 
2507
            }
 
2508
            else
 
2509
            {
 
2510
                if (ww->model->anchorObject)
 
2511
                    ww->model->anchorObject->immobile = FALSE;
 
2512
            }
 
2513
 
 
2514
            ww->model->anchorObject = modelFindNearestObject (ww->model, x, y);
 
2515
            ww->model->anchorObject->immobile = TRUE;
 
2516
 
 
2517
            ww->grabbed = TRUE;
 
2518
 
 
2519
            if (mask & CompWindowGrabMoveMask)
 
2520
            {
 
2521
                WOBBLY_DISPLAY (w->screen->display);
 
2522
 
 
2523
                modelDisableSnapping (w, ww->model);
 
2524
                if (wd->snapping)
 
2525
                    modelUpdateSnapping (w, ww->model);
 
2526
            }
 
2527
 
 
2528
            mIndex = WOBBLY_SCREEN_OPTION_GRAB_WINDOW_MATCH;
 
2529
 
 
2530
            if (matchEval (&ws->opt[mIndex].value.match, w))
 
2531
            {
 
2532
                for (i = 0; i < ww->model->numSprings; i++)
 
2533
                {
 
2534
                    s = &ww->model->springs[i];
 
2535
 
 
2536
                    if (s->a == ww->model->anchorObject)
 
2537
                    {
 
2538
                        s->b->velocity.x -= s->offset.x * 0.05f;
 
2539
                        s->b->velocity.y -= s->offset.y * 0.05f;
 
2540
                    }
 
2541
                    else if (s->b == ww->model->anchorObject)
 
2542
                    {
 
2543
                        s->a->velocity.x += s->offset.x * 0.05f;
 
2544
                        s->a->velocity.y += s->offset.y * 0.05f;
 
2545
                    }
 
2546
                }
 
2547
 
 
2548
                ww->wobbly |= WobblyInitial;
 
2549
                ws->wobblyWindows |= ww->wobbly;
 
2550
 
 
2551
                damagePendingOnScreen (w->screen);
 
2552
            }
 
2553
        }
 
2554
    }
 
2555
 
 
2556
    UNWRAP (ws, w->screen, windowGrabNotify);
 
2557
    (*w->screen->windowGrabNotify) (w, x, y, state, mask);
 
2558
    WRAP (ws, w->screen, windowGrabNotify, wobblyWindowGrabNotify);
 
2559
}
 
2560
 
 
2561
static void
 
2562
wobblyWindowUngrabNotify (CompWindow *w)
 
2563
{
 
2564
    WOBBLY_SCREEN (w->screen);
 
2565
    WOBBLY_WINDOW (w);
 
2566
 
 
2567
    if (w == ws->grabWindow)
 
2568
    {
 
2569
        ws->grabMask   = 0;
 
2570
        ws->grabWindow = NULL;
 
2571
    }
 
2572
 
 
2573
    if (ww->grabbed)
 
2574
    {
 
2575
        if (ww->model)
 
2576
        {
 
2577
            if (ww->model->anchorObject)
 
2578
                ww->model->anchorObject->immobile = FALSE;
 
2579
 
 
2580
            ww->model->anchorObject = NULL;
 
2581
 
 
2582
            if (ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b)
 
2583
            {
 
2584
                if (ww->state & MAXIMIZE_STATE)
 
2585
                    modelAddEdgeAnchors (ww->model,
 
2586
                                         WIN_X (w), WIN_Y (w),
 
2587
                                         WIN_W (w), WIN_H (w));
 
2588
            }
 
2589
 
 
2590
            ww->wobbly |= WobblyInitial;
 
2591
            ws->wobblyWindows |= ww->wobbly;
 
2592
 
 
2593
            damagePendingOnScreen (w->screen);
 
2594
        }
 
2595
 
 
2596
        ww->grabbed = FALSE;
 
2597
    }
 
2598
 
 
2599
    UNWRAP (ws, w->screen, windowUngrabNotify);
 
2600
    (*w->screen->windowUngrabNotify) (w);
 
2601
    WRAP (ws, w->screen, windowUngrabNotify, wobblyWindowUngrabNotify);
 
2602
}
 
2603
 
 
2604
 
 
2605
static Bool
 
2606
wobblyPaintOutput (CompScreen              *s,
 
2607
                   const ScreenPaintAttrib *sAttrib,
 
2608
                   const CompTransform     *transform,
 
2609
                   Region                  region,
 
2610
                   CompOutput              *output,
 
2611
                   unsigned int            mask)
 
2612
{
 
2613
    Bool status;
 
2614
 
 
2615
    WOBBLY_SCREEN (s);
 
2616
 
 
2617
    if (ws->wobblyWindows)
 
2618
        mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
 
2619
 
 
2620
    UNWRAP (ws, s, paintOutput);
 
2621
    status = (*s->paintOutput) (s, sAttrib, transform, region, output, mask);
 
2622
    WRAP (ws, s, paintOutput, wobblyPaintOutput);
 
2623
 
 
2624
    return status;
 
2625
}
 
2626
 
 
2627
static CompOption *
 
2628
wobblyGetDisplayOptions (CompPlugin  *plugin,
 
2629
                         CompDisplay *display,
 
2630
                         int         *count)
 
2631
{
 
2632
    WOBBLY_DISPLAY (display);
 
2633
 
 
2634
    *count = NUM_OPTIONS (wd);
 
2635
    return wd->opt;
 
2636
}
 
2637
 
 
2638
static Bool
 
2639
wobblySetDisplayOption (CompPlugin      *plugin,
 
2640
                        CompDisplay     *display,
 
2641
                        const char      *name,
 
2642
                        CompOptionValue *value)
 
2643
{
 
2644
    CompOption *o;
 
2645
    int        index;
 
2646
 
 
2647
    WOBBLY_DISPLAY (display);
 
2648
 
 
2649
    o = compFindOption (wd->opt, NUM_OPTIONS (wd), name, &index);
 
2650
    if (!o)
 
2651
        return FALSE;
 
2652
 
 
2653
    switch (index) {
 
2654
    case WOBBLY_DISPLAY_OPTION_SNAP_KEY:
 
2655
        /* ignore the key */
 
2656
        value->action.key.keycode = 0;
 
2657
 
 
2658
        if (compSetActionOption (o, value))
 
2659
            return TRUE;
 
2660
        break;
 
2661
    default:
 
2662
        return compSetDisplayOption (display, o, value);
 
2663
    }
 
2664
 
 
2665
    return FALSE;
 
2666
}
 
2667
 
 
2668
static const CompMetadataOptionInfo wobblyDisplayOptionInfo[] = {
 
2669
    { "snap_key", "key", "<passive_grab>false</passive_grab>",
 
2670
      wobblyEnableSnapping, wobblyDisableSnapping },
 
2671
    { "snap_inverted", "bool", 0, 0, 0 },
 
2672
    { "shiver", "bell", 0, wobblyShiver, 0 }
 
2673
};
 
2674
 
 
2675
static Bool
 
2676
wobblyInitDisplay (CompPlugin  *p,
 
2677
                   CompDisplay *d)
 
2678
{
 
2679
    WobblyDisplay *wd;
 
2680
 
 
2681
    if (!checkPluginABI ("core", CORE_ABIVERSION))
 
2682
        return FALSE;
 
2683
 
 
2684
    wd = malloc (sizeof (WobblyDisplay));
 
2685
    if (!wd)
 
2686
        return FALSE;
 
2687
 
 
2688
    if (!compInitDisplayOptionsFromMetadata (d,
 
2689
                                             &wobblyMetadata,
 
2690
                                             wobblyDisplayOptionInfo,
 
2691
                                             wd->opt,
 
2692
                                             WOBBLY_DISPLAY_OPTION_NUM))
 
2693
    {
 
2694
        free (wd);
 
2695
        return FALSE;
 
2696
    }
 
2697
 
 
2698
    wd->screenPrivateIndex = allocateScreenPrivateIndex (d);
 
2699
    if (wd->screenPrivateIndex < 0)
 
2700
    {
 
2701
        compFiniDisplayOptions (d, wd->opt, WOBBLY_DISPLAY_OPTION_NUM);
 
2702
        free (wd);
 
2703
        return FALSE;
 
2704
    }
 
2705
 
 
2706
    WRAP (wd, d, handleEvent, wobblyHandleEvent);
 
2707
 
 
2708
    wd->snapping = FALSE;
 
2709
 
 
2710
    d->base.privates[displayPrivateIndex].ptr = wd;
 
2711
 
 
2712
    return TRUE;
 
2713
}
 
2714
 
 
2715
static void
 
2716
wobblyFiniDisplay (CompPlugin  *p,
 
2717
                   CompDisplay *d)
 
2718
{
 
2719
    WOBBLY_DISPLAY (d);
 
2720
 
 
2721
    freeScreenPrivateIndex (d, wd->screenPrivateIndex);
 
2722
 
 
2723
    UNWRAP (wd, d, handleEvent);
 
2724
 
 
2725
    compFiniDisplayOptions (d, wd->opt, WOBBLY_DISPLAY_OPTION_NUM);
 
2726
 
 
2727
    free (wd);
 
2728
}
 
2729
 
 
2730
static Bool
 
2731
wobblyInitScreen (CompPlugin *p,
 
2732
                  CompScreen *s)
 
2733
{
 
2734
    WobblyScreen *ws;
 
2735
 
 
2736
    WOBBLY_DISPLAY (s->display);
 
2737
 
 
2738
    ws = malloc (sizeof (WobblyScreen));
 
2739
    if (!ws)
 
2740
        return FALSE;
 
2741
 
 
2742
    if (!compInitScreenOptionsFromMetadata (s,
 
2743
                                            &wobblyMetadata,
 
2744
                                            wobblyScreenOptionInfo,
 
2745
                                            ws->opt,
 
2746
                                            WOBBLY_SCREEN_OPTION_NUM))
 
2747
    {
 
2748
        free (ws);
 
2749
        return FALSE;
 
2750
    }
 
2751
 
 
2752
    ws->windowPrivateIndex = allocateWindowPrivateIndex (s);
 
2753
    if (ws->windowPrivateIndex < 0)
 
2754
    {
 
2755
        compFiniScreenOptions (s, ws->opt, WOBBLY_SCREEN_OPTION_NUM);
 
2756
        free (ws);
 
2757
        return FALSE;
 
2758
    }
 
2759
 
 
2760
    ws->wobblyWindows = FALSE;
 
2761
 
 
2762
    ws->grabMask   = 0;
 
2763
    ws->grabWindow = NULL;
 
2764
    ws->moveWindow = FALSE;
 
2765
 
 
2766
    WRAP (ws, s, preparePaintScreen, wobblyPreparePaintScreen);
 
2767
    WRAP (ws, s, donePaintScreen, wobblyDonePaintScreen);
 
2768
    WRAP (ws, s, paintOutput, wobblyPaintOutput);
 
2769
    WRAP (ws, s, paintWindow, wobblyPaintWindow);
 
2770
    WRAP (ws, s, damageWindowRect, wobblyDamageWindowRect);
 
2771
    WRAP (ws, s, addWindowGeometry, wobblyAddWindowGeometry);
 
2772
    WRAP (ws, s, windowResizeNotify, wobblyWindowResizeNotify);
 
2773
    WRAP (ws, s, windowMoveNotify, wobblyWindowMoveNotify);
 
2774
    WRAP (ws, s, windowGrabNotify, wobblyWindowGrabNotify);
 
2775
    WRAP (ws, s, windowUngrabNotify, wobblyWindowUngrabNotify);
 
2776
 
 
2777
    s->base.privates[wd->screenPrivateIndex].ptr = ws;
 
2778
 
 
2779
    return TRUE;
 
2780
}
 
2781
 
 
2782
static void
 
2783
wobblyFiniScreen (CompPlugin *p,
 
2784
                  CompScreen *s)
 
2785
{
 
2786
    WOBBLY_SCREEN (s);
 
2787
 
 
2788
    freeWindowPrivateIndex (s, ws->windowPrivateIndex);
 
2789
 
 
2790
    UNWRAP (ws, s, preparePaintScreen);
 
2791
    UNWRAP (ws, s, donePaintScreen);
 
2792
    UNWRAP (ws, s, paintOutput);
 
2793
    UNWRAP (ws, s, paintWindow);
 
2794
    UNWRAP (ws, s, damageWindowRect);
 
2795
    UNWRAP (ws, s, addWindowGeometry);
 
2796
    UNWRAP (ws, s, windowResizeNotify);
 
2797
    UNWRAP (ws, s, windowMoveNotify);
 
2798
    UNWRAP (ws, s, windowGrabNotify);
 
2799
    UNWRAP (ws, s, windowUngrabNotify);
 
2800
 
 
2801
    compFiniScreenOptions (s, ws->opt, WOBBLY_SCREEN_OPTION_NUM);
 
2802
 
 
2803
    free (ws);
 
2804
}
 
2805
 
 
2806
static Bool
 
2807
wobblyInitWindow (CompPlugin *p,
 
2808
                  CompWindow *w)
 
2809
{
 
2810
    WobblyWindow *ww;
 
2811
 
 
2812
    WOBBLY_SCREEN (w->screen);
 
2813
 
 
2814
    ww = malloc (sizeof (WobblyWindow));
 
2815
    if (!ww)
 
2816
        return FALSE;
 
2817
 
 
2818
    ww->model   = 0;
 
2819
    ww->wobbly  = 0;
 
2820
    ww->grabbed = FALSE;
 
2821
    ww->state   = w->state;
 
2822
 
 
2823
    w->base.privates[ws->windowPrivateIndex].ptr = ww;
 
2824
 
 
2825
    if (w->mapNum && ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b)
 
2826
    {
 
2827
        if (isWobblyWin (w))
 
2828
            wobblyEnsureModel (w);
 
2829
    }
 
2830
 
 
2831
    return TRUE;
 
2832
}
 
2833
 
 
2834
static void
 
2835
wobblyFiniWindow (CompPlugin *p,
 
2836
                  CompWindow *w)
 
2837
{
 
2838
    WOBBLY_WINDOW (w);
 
2839
    WOBBLY_SCREEN (w->screen);
 
2840
 
 
2841
    if (ws->grabWindow == w)
 
2842
    {
 
2843
        ws->grabWindow = NULL;
 
2844
        ws->grabMask   = 0;
 
2845
    }
 
2846
 
 
2847
    if (ww->model)
 
2848
    {
 
2849
        free (ww->model->objects);
 
2850
        free (ww->model);
 
2851
    }
 
2852
 
 
2853
    free (ww);
 
2854
}
 
2855
 
 
2856
static CompBool
 
2857
wobblyInitObject (CompPlugin *p,
 
2858
                 CompObject *o)
 
2859
{
 
2860
    static InitPluginObjectProc dispTab[] = {
 
2861
        (InitPluginObjectProc) 0, /* InitCore */
 
2862
        (InitPluginObjectProc) wobblyInitDisplay,
 
2863
        (InitPluginObjectProc) wobblyInitScreen,
 
2864
        (InitPluginObjectProc) wobblyInitWindow
 
2865
    };
 
2866
 
 
2867
    RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
 
2868
}
 
2869
 
 
2870
static void
 
2871
wobblyFiniObject (CompPlugin *p,
 
2872
                 CompObject *o)
 
2873
{
 
2874
    static FiniPluginObjectProc dispTab[] = {
 
2875
        (FiniPluginObjectProc) 0, /* FiniCore */
 
2876
        (FiniPluginObjectProc) wobblyFiniDisplay,
 
2877
        (FiniPluginObjectProc) wobblyFiniScreen,
 
2878
        (FiniPluginObjectProc) wobblyFiniWindow
 
2879
    };
 
2880
 
 
2881
    DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
 
2882
}
 
2883
 
 
2884
static CompOption *
 
2885
wobblyGetObjectOptions (CompPlugin *plugin,
 
2886
                       CompObject *object,
 
2887
                       int        *count)
 
2888
{
 
2889
    static GetPluginObjectOptionsProc dispTab[] = {
 
2890
        (GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
 
2891
        (GetPluginObjectOptionsProc) wobblyGetDisplayOptions,
 
2892
        (GetPluginObjectOptionsProc) wobblyGetScreenOptions
 
2893
    };
 
2894
 
 
2895
    RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
 
2896
                     (void *) (*count = 0), (plugin, object, count));
 
2897
}
 
2898
 
 
2899
static CompBool
 
2900
wobblySetObjectOption (CompPlugin      *plugin,
 
2901
                      CompObject      *object,
 
2902
                      const char      *name,
 
2903
                      CompOptionValue *value)
 
2904
{
 
2905
    static SetPluginObjectOptionProc dispTab[] = {
 
2906
        (SetPluginObjectOptionProc) 0, /* SetCoreOption */
 
2907
        (SetPluginObjectOptionProc) wobblySetDisplayOption,
 
2908
        (SetPluginObjectOptionProc) wobblySetScreenOption
 
2909
    };
 
2910
 
 
2911
    RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
 
2912
                     (plugin, object, name, value));
 
2913
}
 
2914
 
 
2915
static Bool
 
2916
wobblyInit (CompPlugin *p)
 
2917
{
 
2918
    if (!compInitPluginMetadataFromInfo (&wobblyMetadata,
 
2919
                                         p->vTable->name,
 
2920
                                         wobblyDisplayOptionInfo,
 
2921
                                         WOBBLY_DISPLAY_OPTION_NUM,
 
2922
                                         wobblyScreenOptionInfo,
 
2923
                                         WOBBLY_SCREEN_OPTION_NUM))
 
2924
        return FALSE;
 
2925
 
 
2926
    displayPrivateIndex = allocateDisplayPrivateIndex ();
 
2927
    if (displayPrivateIndex < 0)
 
2928
    {
 
2929
        compFiniMetadata (&wobblyMetadata);
 
2930
        return FALSE;
 
2931
    }
 
2932
 
 
2933
    compAddMetadataFromFile (&wobblyMetadata, p->vTable->name);
 
2934
 
 
2935
    return TRUE;
 
2936
}
 
2937
 
 
2938
static void
 
2939
wobblyFini (CompPlugin *p)
 
2940
{
 
2941
    freeDisplayPrivateIndex (displayPrivateIndex);
 
2942
    compFiniMetadata (&wobblyMetadata);
 
2943
}
 
2944
 
 
2945
static CompMetadata *
 
2946
wobblyGetMetadata (CompPlugin *plugin)
 
2947
{
 
2948
    return &wobblyMetadata;
 
2949
}
 
2950
 
 
2951
CompPluginVTable wobblyVTable = {
 
2952
    "wobbly",
 
2953
    wobblyGetMetadata,
 
2954
    wobblyInit,
 
2955
    wobblyFini,
 
2956
    wobblyInitObject,
 
2957
    wobblyFiniObject,
 
2958
    wobblyGetObjectOptions,
 
2959
    wobblySetObjectOption
 
2960
};
 
2961
 
 
2962
CompPluginVTable *
 
2963
getCompPluginInfo20070830 (void)
 
2964
{
 
2965
    return &wobblyVTable;
 
2966
}