~alan-griffiths/compiz-core/Bug-931283

« back to all changes in this revision

Viewing changes to plugins/wobbly.c

  • Committer: David Reveman
  • Date: 2006-02-09 06:03:09 UTC
  • Revision ID: git-v1:9959c2b13ded64a5e66359a8097250dc9d87fc1c
Initial revision

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.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
    Vector       scale;
 
102
    Bool         transformed;
 
103
    Point        topLeft;
 
104
    Point        bottomRight;
 
105
    unsigned int edgeMask;
 
106
    unsigned int snapCnt[4];
 
107
} Model;
 
108
 
 
109
#define WOBBLY_FRICTION_DEFAULT    3.0f
 
110
#define WOBBLY_FRICTION_MIN        0.1f
 
111
#define WOBBLY_FRICTION_MAX       10.0f
 
112
#define WOBBLY_FRICTION_PRECISION  0.1f
 
113
 
 
114
#define WOBBLY_SPRING_K_DEFAULT    8.0f
 
115
#define WOBBLY_SPRING_K_MIN        0.1f
 
116
#define WOBBLY_SPRING_K_MAX       10.0f
 
117
#define WOBBLY_SPRING_K_PRECISION  0.1f
 
118
 
 
119
#define WOBBLY_GRID_RESOLUTION_DEFAULT  8
 
120
#define WOBBLY_GRID_RESOLUTION_MIN      1
 
121
#define WOBBLY_GRID_RESOLUTION_MAX      64
 
122
 
 
123
#define WOBBLY_MIN_GRID_SIZE_DEFAULT  8
 
124
#define WOBBLY_MIN_GRID_SIZE_MIN      4
 
125
#define WOBBLY_MIN_GRID_SIZE_MAX      128
 
126
 
 
127
#define WOBBLY_WOBBLE_ON_GRAB_DEFAULT   FALSE
 
128
 
 
129
#define WOBBLY_WOBBLE_ON_MOVE_DEFAULT   TRUE
 
130
 
 
131
#define WOBBLY_WOBBLE_ON_RESIZE_DEFAULT FALSE
 
132
 
 
133
typedef enum {
 
134
    WobblyEffectNone = 0,
 
135
    WobblyEffectShiver
 
136
} WobblyEffect;
 
137
 
 
138
static char *effectName[] = {
 
139
    "None",
 
140
    "Shiver"
 
141
};
 
142
 
 
143
static WobblyEffect effectType[] = {
 
144
    WobblyEffectNone,
 
145
    WobblyEffectShiver
 
146
};
 
147
 
 
148
#define NUM_EFFECT (sizeof (effectType) / sizeof (effectType[0]))
 
149
 
 
150
#define WOBBLY_MAP_DEFAULT   (effectName[0])
 
151
#define WOBBLY_FOCUS_DEFAULT (effectName[0])
 
152
 
 
153
static char *winType[] = {
 
154
    "Toolbar",
 
155
    "Menu",
 
156
    "Utility",
 
157
    "Splash",
 
158
    "Dialog",
 
159
    "Normal",
 
160
    "Unknown"
 
161
};
 
162
#define N_WIN_TYPE (sizeof (winType) / sizeof (winType[0]))
 
163
 
 
164
#define WOBBLY_SNAP_KEY_DEFAULT       "Control_L"
 
165
#define WOBBLY_SNAP_MODIFIERS_DEFAULT (CompPressMask | ControlMask)
 
166
 
 
167
static int displayPrivateIndex;
 
168
 
 
169
typedef struct _WobblyDisplay {
 
170
    int             screenPrivateIndex;
 
171
    HandleEventProc handleEvent;
 
172
} WobblyDisplay;
 
173
 
 
174
#define WOBBLY_SCREEN_OPTION_FRICTION         0
 
175
#define WOBBLY_SCREEN_OPTION_SPRING_K         1
 
176
#define WOBBLY_SCREEN_OPTION_GRID_RESOLUTION  2
 
177
#define WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE    3
 
178
#define WOBBLY_SCREEN_OPTION_MAP_EFFECT       4
 
179
#define WOBBLY_SCREEN_OPTION_FOCUS_EFFECT     5
 
180
#define WOBBLY_SCREEN_OPTION_WINDOW_TYPE      6
 
181
#define WOBBLY_SCREEN_OPTION_WOBBLE_ON_GRAB   7
 
182
#define WOBBLY_SCREEN_OPTION_WOBBLE_ON_MOVE   8
 
183
#define WOBBLY_SCREEN_OPTION_WOBBLE_ON_RESIZE 9
 
184
#define WOBBLY_SCREEN_OPTION_SNAP             10
 
185
#define WOBBLY_SCREEN_OPTION_NUM              11
 
186
 
 
187
typedef struct _WobblyScreen {
 
188
    int windowPrivateIndex;
 
189
 
 
190
    PreparePaintScreenProc preparePaintScreen;
 
191
    DonePaintScreenProc    donePaintScreen;
 
192
    PaintScreenProc        paintScreen;
 
193
    PaintWindowProc        paintWindow;
 
194
    DamageWindowRectProc   damageWindowRect;
 
195
    AddWindowGeometryProc  addWindowGeometry;
 
196
    DrawWindowGeometryProc drawWindowGeometry;
 
197
    SetWindowScaleProc     setWindowScale;
 
198
 
 
199
    WindowResizeNotifyProc windowResizeNotify;
 
200
    WindowMoveNotifyProc   windowMoveNotify;
 
201
    WindowGrabNotifyProc   windowGrabNotify;
 
202
    WindowUngrabNotifyProc windowUngrabNotify;
 
203
 
 
204
    CompOption opt[WOBBLY_SCREEN_OPTION_NUM];
 
205
 
 
206
    Bool wobblyWindows;
 
207
 
 
208
    WobblyEffect mapEffect;
 
209
    WobblyEffect focusEffect;
 
210
 
 
211
    unsigned int wMask;
 
212
} WobblyScreen;
 
213
 
 
214
#define WobblyInitial  (1L << 0)
 
215
#define WobblyForce    (1L << 1)
 
216
#define WobblyVelocity (1L << 2)
 
217
 
 
218
typedef struct _WobblyWindow {
 
219
    Model *model;
 
220
    int   wobbly;
 
221
    Bool  grabbed;
 
222
    Bool  velocity;
 
223
} WobblyWindow;
 
224
 
 
225
#define GET_WOBBLY_DISPLAY(d)                                  \
 
226
    ((WobblyDisplay *) (d)->privates[displayPrivateIndex].ptr)
 
227
 
 
228
#define WOBBLY_DISPLAY(d)                      \
 
229
    WobblyDisplay *wd = GET_WOBBLY_DISPLAY (d)
 
230
 
 
231
#define GET_WOBBLY_SCREEN(s, wd)                                   \
 
232
    ((WobblyScreen *) (s)->privates[(wd)->screenPrivateIndex].ptr)
 
233
 
 
234
#define WOBBLY_SCREEN(s)                                                      \
 
235
    WobblyScreen *ws = GET_WOBBLY_SCREEN (s, GET_WOBBLY_DISPLAY (s->display))
 
236
 
 
237
#define GET_WOBBLY_WINDOW(w, ws)                                   \
 
238
    ((WobblyWindow *) (w)->privates[(ws)->windowPrivateIndex].ptr)
 
239
 
 
240
#define WOBBLY_WINDOW(w)                                         \
 
241
    WobblyWindow *ww = GET_WOBBLY_WINDOW  (w,                    \
 
242
                       GET_WOBBLY_SCREEN  (w->screen,            \
 
243
                       GET_WOBBLY_DISPLAY (w->screen->display)))
 
244
 
 
245
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
 
246
 
 
247
static CompOption *
 
248
wobblyGetScreenOptions (CompScreen *screen,
 
249
                        int        *count)
 
250
{
 
251
    WOBBLY_SCREEN (screen);
 
252
 
 
253
    *count = NUM_OPTIONS (ws);
 
254
    return ws->opt;
 
255
}
 
256
 
 
257
static Bool
 
258
wobblySetScreenOption (CompScreen      *screen,
 
259
                     char            *name,
 
260
                     CompOptionValue *value)
 
261
{
 
262
    CompOption *o;
 
263
    int        index;
 
264
 
 
265
    WOBBLY_SCREEN (screen);
 
266
 
 
267
    o = compFindOption (ws->opt, NUM_OPTIONS (ws), name, &index);
 
268
    if (!o)
 
269
        return FALSE;
 
270
 
 
271
    switch (index) {
 
272
    case WOBBLY_SCREEN_OPTION_FRICTION:
 
273
    case WOBBLY_SCREEN_OPTION_SPRING_K:
 
274
        if (compSetFloatOption (o, value))
 
275
            return TRUE;
 
276
        break;
 
277
    case WOBBLY_SCREEN_OPTION_GRID_RESOLUTION:
 
278
        if (compSetIntOption (o, value))
 
279
            return TRUE;
 
280
        break;
 
281
    case WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE:
 
282
        if (compSetIntOption (o, value))
 
283
            return TRUE;
 
284
        break;
 
285
    case WOBBLY_SCREEN_OPTION_MAP_EFFECT:
 
286
        if (compSetStringOption (o, value))
 
287
        {
 
288
            int i;
 
289
 
 
290
            for (i = 0; i < NUM_EFFECT; i++)
 
291
            {
 
292
                if (strcmp (o->value.s, effectName[i]) == 0)
 
293
                {
 
294
                    ws->mapEffect = effectType[i];
 
295
                    return TRUE;
 
296
                }
 
297
            }
 
298
        }
 
299
        break;
 
300
    case WOBBLY_SCREEN_OPTION_FOCUS_EFFECT:
 
301
        if (compSetStringOption (o, value))
 
302
        {
 
303
            int i;
 
304
 
 
305
            for (i = 0; i < NUM_EFFECT; i++)
 
306
            {
 
307
                if (strcmp (o->value.s, effectName[i]) == 0)
 
308
                {
 
309
                    ws->focusEffect = effectType[i];
 
310
                    return TRUE;
 
311
                }
 
312
            }
 
313
        }
 
314
        break;
 
315
    case WOBBLY_SCREEN_OPTION_WINDOW_TYPE:
 
316
        if (compSetOptionList (o, value))
 
317
        {
 
318
            ws->wMask = compWindowTypeMaskFromStringList (&o->value);
 
319
            return TRUE;
 
320
        }
 
321
        break;
 
322
    case WOBBLY_SCREEN_OPTION_WOBBLE_ON_GRAB:
 
323
    case WOBBLY_SCREEN_OPTION_WOBBLE_ON_MOVE:
 
324
    case WOBBLY_SCREEN_OPTION_WOBBLE_ON_RESIZE:
 
325
        if (compSetBoolOption (o, value))
 
326
            return TRUE;
 
327
        break;
 
328
    case WOBBLY_SCREEN_OPTION_SNAP:
 
329
        if (value->bind.type == CompBindingTypeButton)
 
330
            return FALSE;
 
331
 
 
332
        if (compSetBindingOption (o, value))
 
333
            return TRUE;
 
334
    default:
 
335
        break;
 
336
    }
 
337
 
 
338
    return FALSE;
 
339
}
 
340
 
 
341
static void
 
342
wobblyScreenInitOptions (WobblyScreen *ws,
 
343
                         Display      *display)
 
344
{
 
345
    CompOption *o;
 
346
    int        i;
 
347
 
 
348
    o = &ws->opt[WOBBLY_SCREEN_OPTION_FRICTION];
 
349
    o->name             = "friction";
 
350
    o->shortDesc        = "Friction";
 
351
    o->longDesc         = "Spring Friction";
 
352
    o->type             = CompOptionTypeFloat;
 
353
    o->value.f          = WOBBLY_FRICTION_DEFAULT;
 
354
    o->rest.f.min       = WOBBLY_FRICTION_MIN;
 
355
    o->rest.f.max       = WOBBLY_FRICTION_MAX;
 
356
    o->rest.f.precision = WOBBLY_FRICTION_PRECISION;
 
357
 
 
358
    o = &ws->opt[WOBBLY_SCREEN_OPTION_SPRING_K];
 
359
    o->name             = "spring_k";
 
360
    o->shortDesc        = "Spring K";
 
361
    o->longDesc         = "Spring Konstant";
 
362
    o->type             = CompOptionTypeFloat;
 
363
    o->value.f          = WOBBLY_SPRING_K_DEFAULT;
 
364
    o->rest.f.min       = WOBBLY_SPRING_K_MIN;
 
365
    o->rest.f.max       = WOBBLY_SPRING_K_MAX;
 
366
    o->rest.f.precision = WOBBLY_SPRING_K_PRECISION;
 
367
 
 
368
    o = &ws->opt[WOBBLY_SCREEN_OPTION_GRID_RESOLUTION];
 
369
    o->name       = "grid_resolution";
 
370
    o->shortDesc  = "Grid Resolution";
 
371
    o->longDesc   = "Vertex Grid Resolution";
 
372
    o->type       = CompOptionTypeInt;
 
373
    o->value.i    = WOBBLY_GRID_RESOLUTION_DEFAULT;
 
374
    o->rest.i.min = WOBBLY_GRID_RESOLUTION_MIN;
 
375
    o->rest.i.max = WOBBLY_GRID_RESOLUTION_MAX;
 
376
 
 
377
    o = &ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE];
 
378
    o->name       = "min_grid_size";
 
379
    o->shortDesc  = "Minimum Grid Size";
 
380
    o->longDesc   = "Minimum Vertex Grid Size";
 
381
    o->type       = CompOptionTypeInt;
 
382
    o->value.i    = WOBBLY_MIN_GRID_SIZE_DEFAULT;
 
383
    o->rest.i.min = WOBBLY_MIN_GRID_SIZE_MIN;
 
384
    o->rest.i.max = WOBBLY_MIN_GRID_SIZE_MAX;
 
385
 
 
386
    o = &ws->opt[WOBBLY_SCREEN_OPTION_MAP_EFFECT];
 
387
    o->name           = "map_effect";
 
388
    o->shortDesc      = "Map Effect";
 
389
    o->longDesc       = "Map Window Effect";
 
390
    o->type           = CompOptionTypeString;
 
391
    o->value.s        = strdup (WOBBLY_MAP_DEFAULT);
 
392
    o->rest.s.string  = effectName;
 
393
    o->rest.s.nString = NUM_EFFECT;
 
394
 
 
395
    o = &ws->opt[WOBBLY_SCREEN_OPTION_FOCUS_EFFECT];
 
396
    o->name           = "focus_effect";
 
397
    o->shortDesc      = "Focus Effect";
 
398
    o->longDesc       = "Focus Window Effect";
 
399
    o->type           = CompOptionTypeString;
 
400
    o->value.s        = strdup (WOBBLY_FOCUS_DEFAULT);
 
401
    o->rest.s.string  = effectName;
 
402
    o->rest.s.nString = NUM_EFFECT;
 
403
 
 
404
    o = &ws->opt[WOBBLY_SCREEN_OPTION_WINDOW_TYPE];
 
405
    o->name              = "window_types";
 
406
    o->shortDesc         = "Window Types";
 
407
    o->longDesc          = "Window types that should wobbly";
 
408
    o->type              = CompOptionTypeList;
 
409
    o->value.list.type   = CompOptionTypeString;
 
410
    o->value.list.nValue = N_WIN_TYPE;
 
411
    o->value.list.value  = malloc (sizeof (CompOptionValue) * N_WIN_TYPE);
 
412
    for (i = 0; i < N_WIN_TYPE; i++)
 
413
        o->value.list.value[i].s = strdup (winType[i]);
 
414
    o->rest.s.string     = windowTypeString;
 
415
    o->rest.s.nString    = nWindowTypeString;
 
416
 
 
417
    ws->wMask = compWindowTypeMaskFromStringList (&o->value);
 
418
 
 
419
    o = &ws->opt[WOBBLY_SCREEN_OPTION_WOBBLE_ON_GRAB];
 
420
    o->name      = "wobble_on_grab";
 
421
    o->shortDesc = "Wobble On Grab";
 
422
    o->longDesc  = "Wobble when windows are grabbed";
 
423
    o->type      = CompOptionTypeBool;
 
424
    o->value.b   = WOBBLY_WOBBLE_ON_GRAB_DEFAULT;
 
425
 
 
426
    o = &ws->opt[WOBBLY_SCREEN_OPTION_WOBBLE_ON_MOVE];
 
427
    o->name      = "wobble_on_move";
 
428
    o->shortDesc = "Wobble On Move";
 
429
    o->longDesc  = "Wobble when windows are moved";
 
430
    o->type      = CompOptionTypeBool;
 
431
    o->value.b   = WOBBLY_WOBBLE_ON_MOVE_DEFAULT;
 
432
 
 
433
    o = &ws->opt[WOBBLY_SCREEN_OPTION_WOBBLE_ON_RESIZE];
 
434
    o->name      = "wobble_on_resize";
 
435
    o->shortDesc = "Wobble On Resize";
 
436
    o->longDesc  = "Wobble when windows are resize";
 
437
    o->type      = CompOptionTypeBool;
 
438
    o->value.b   = WOBBLY_WOBBLE_ON_RESIZE_DEFAULT;
 
439
 
 
440
    o = &ws->opt[WOBBLY_SCREEN_OPTION_SNAP];
 
441
    o->name                       = "snap";
 
442
    o->shortDesc                  = "Snap windows";
 
443
    o->longDesc                   = "Toggle window snapping";
 
444
    o->type                       = CompOptionTypeBinding;
 
445
    o->value.bind.type            = CompBindingTypeKey;
 
446
    o->value.bind.u.key.modifiers = WOBBLY_SNAP_MODIFIERS_DEFAULT;
 
447
    o->value.bind.u.key.keycode   =
 
448
        XKeysymToKeycode (display,
 
449
                          XStringToKeysym (WOBBLY_SNAP_KEY_DEFAULT));
 
450
}
 
451
 
 
452
static void
 
453
findNextWestEdge (CompWindow *w,
 
454
                  Object     *object)
 
455
{
 
456
    int v, v1, v2;
 
457
    int s, start;
 
458
    int e, end;
 
459
    int x;
 
460
 
 
461
    start = -65535.0f;
 
462
    end   =  65535.0f;
 
463
 
 
464
    v1 = -65535.0f;
 
465
    v2 =  65535.0f;
 
466
 
 
467
    x = object->position.x + w->output.left - w->input.left;
 
468
 
 
469
    if (x >= w->screen->workArea.x)
 
470
    {
 
471
        CompWindow *p;
 
472
 
 
473
        v1 = w->screen->workArea.x;
 
474
 
 
475
        for (p = w->screen->windows; p; p = p->next)
 
476
        {
 
477
            if (p->invisible || w == p || p->type != CompWindowTypeNormalMask)
 
478
                continue;
 
479
 
 
480
            s = p->attrib.y - p->output.top;
 
481
            e = p->attrib.y + p->height + p->output.bottom;
 
482
 
 
483
            if (s > object->position.y)
 
484
            {
 
485
                if (s < end)
 
486
                    end = s;
 
487
            }
 
488
            else if (e < object->position.y)
 
489
            {
 
490
                if (e > start)
 
491
                    start = e;
 
492
            }
 
493
            else
 
494
            {
 
495
                if (s > start)
 
496
                    start = s;
 
497
 
 
498
                if (e < end)
 
499
                    end = e;
 
500
 
 
501
                v = p->attrib.x + p->width + p->input.right;
 
502
                if (v <= x)
 
503
                {
 
504
                    if (v > v1)
 
505
                        v1 = v;
 
506
                }
 
507
                else
 
508
                {
 
509
                    if (v < v2)
 
510
                        v2 = v;
 
511
                }
 
512
            }
 
513
        }
 
514
    }
 
515
    else
 
516
    {
 
517
        v2 = w->screen->workArea.x;
 
518
    }
 
519
 
 
520
    v1 = v1 - w->output.left + w->input.left;
 
521
    v2 = v2 - w->output.left + w->input.left;
 
522
 
 
523
    if (v1 != (int) object->vertEdge.next)
 
524
        object->vertEdge.snapped = FALSE;
 
525
 
 
526
    object->vertEdge.start = start;
 
527
    object->vertEdge.end   = end;
 
528
 
 
529
    object->vertEdge.next = v1;
 
530
    object->vertEdge.prev = v2;
 
531
 
 
532
    object->vertEdge.attract  = v1 + EDGE_DISTANCE;
 
533
    object->vertEdge.velocity = EDGE_VELOCITY;
 
534
}
 
535
 
 
536
static void
 
537
findNextEastEdge (CompWindow *w,
 
538
                  Object     *object)
 
539
{
 
540
    int v, v1, v2;
 
541
    int s, start;
 
542
    int e, end;
 
543
    int x;
 
544
 
 
545
    start = -65535.0f;
 
546
    end   =  65535.0f;
 
547
 
 
548
    v1 =  65535.0f;
 
549
    v2 = -65535.0f;
 
550
 
 
551
    x = object->position.x - w->output.right + w->input.right;
 
552
 
 
553
    if (x <= w->screen->workArea.x + w->screen->workArea.width)
 
554
    {
 
555
        CompWindow *p;
 
556
 
 
557
        v1 = w->screen->workArea.x + w->screen->workArea.width;
 
558
 
 
559
        for (p = w->screen->windows; p; p = p->next)
 
560
        {
 
561
            if (p->invisible || w == p || p->type != CompWindowTypeNormalMask)
 
562
                continue;
 
563
 
 
564
            s = p->attrib.y - p->output.top;
 
565
            e = p->attrib.y + p->height + p->output.bottom;
 
566
 
 
567
            if (s > object->position.y)
 
568
            {
 
569
                if (s < end)
 
570
                    end = s;
 
571
            }
 
572
            else if (e < object->position.y)
 
573
            {
 
574
                if (e > start)
 
575
                    start = e;
 
576
            }
 
577
            else
 
578
            {
 
579
                if (s > start)
 
580
                    start = s;
 
581
 
 
582
                if (e < end)
 
583
                    end = e;
 
584
 
 
585
                v = p->attrib.x - p->input.left;
 
586
                if (v >= x)
 
587
                {
 
588
                    if (v < v1)
 
589
                        v1 = v;
 
590
                }
 
591
                else
 
592
                {
 
593
                    if (v > v2)
 
594
                        v2 = v;
 
595
                }
 
596
            }
 
597
        }
 
598
    }
 
599
    else
 
600
    {
 
601
        v2 = w->screen->workArea.x + w->screen->workArea.width;
 
602
    }
 
603
 
 
604
    v1 = v1 + w->output.right - w->input.right;
 
605
    v2 = v2 + w->output.right - w->input.right;
 
606
 
 
607
    if (v1 != (int) object->vertEdge.next)
 
608
        object->vertEdge.snapped = FALSE;
 
609
 
 
610
    object->vertEdge.start = start;
 
611
    object->vertEdge.end   = end;
 
612
 
 
613
    object->vertEdge.next = v1;
 
614
    object->vertEdge.prev = v2;
 
615
 
 
616
    object->vertEdge.attract  = v1 - EDGE_DISTANCE;
 
617
    object->vertEdge.velocity = EDGE_VELOCITY;
 
618
}
 
619
 
 
620
static void
 
621
findNextNorthEdge (CompWindow *w,
 
622
                   Object     *object)
 
623
{
 
624
    int v, v1, v2;
 
625
    int s, start;
 
626
    int e, end;
 
627
    int y;
 
628
 
 
629
    start = -65535.0f;
 
630
    end   =  65535.0f;
 
631
 
 
632
    v1 = -65535.0f;
 
633
    v2 =  65535.0f;
 
634
 
 
635
    y = object->position.y + w->output.top - w->input.top;
 
636
 
 
637
    if (y >= w->screen->workArea.y)
 
638
    {
 
639
        CompWindow *p;
 
640
 
 
641
        v1 = w->screen->workArea.y;
 
642
 
 
643
        for (p = w->screen->windows; p; p = p->next)
 
644
        {
 
645
            if (p->invisible || w == p || p->type != CompWindowTypeNormalMask)
 
646
                continue;
 
647
 
 
648
            s = p->attrib.x - p->output.left;
 
649
            e = p->attrib.x + p->width + p->output.right;
 
650
 
 
651
            if (s > object->position.x)
 
652
            {
 
653
                if (s < end)
 
654
                    end = s;
 
655
            }
 
656
            else if (e < object->position.x)
 
657
            {
 
658
                if (e > start)
 
659
                    start = e;
 
660
            }
 
661
            else
 
662
            {
 
663
                if (s > start)
 
664
                    start = s;
 
665
 
 
666
                if (e < end)
 
667
                    end = e;
 
668
 
 
669
                v = p->attrib.y + p->height + p->input.bottom;
 
670
                if (v <= y)
 
671
                {
 
672
                    if (v > v1)
 
673
                        v1 = v;
 
674
                }
 
675
                else
 
676
                {
 
677
                    if (v < v2)
 
678
                        v2 = v;
 
679
                }
 
680
            }
 
681
        }
 
682
    }
 
683
    else
 
684
    {
 
685
        v2 = w->screen->workArea.y;
 
686
    }
 
687
 
 
688
    v1 = v1 - w->output.top + w->input.top;
 
689
    v2 = v2 - w->output.top + w->input.top;
 
690
 
 
691
    if (v1 != (int) object->horzEdge.next)
 
692
        object->horzEdge.snapped = FALSE;
 
693
 
 
694
    object->horzEdge.start = start;
 
695
    object->horzEdge.end   = end;
 
696
 
 
697
    object->horzEdge.next = v1;
 
698
    object->horzEdge.prev = v2;
 
699
 
 
700
    object->horzEdge.attract  = v1 + EDGE_DISTANCE;
 
701
    object->horzEdge.velocity = EDGE_VELOCITY;
 
702
}
 
703
 
 
704
static void
 
705
findNextSouthEdge (CompWindow *w,
 
706
                   Object     *object)
 
707
{
 
708
    int v, v1, v2;
 
709
    int s, start;
 
710
    int e, end;
 
711
    int y;
 
712
 
 
713
    start = -65535.0f;
 
714
    end   =  65535.0f;
 
715
 
 
716
    v1 =  65535.0f;
 
717
    v2 = -65535.0f;
 
718
 
 
719
    y = object->position.y - w->output.bottom + w->input.bottom;
 
720
 
 
721
    if (y <= w->screen->workArea.y + w->screen->workArea.height)
 
722
    {
 
723
        CompWindow *p;
 
724
 
 
725
        v1 = w->screen->workArea.y + w->screen->workArea.height;
 
726
 
 
727
        for (p = w->screen->windows; p; p = p->next)
 
728
        {
 
729
            if (p->invisible || w == p || p->type != CompWindowTypeNormalMask)
 
730
                continue;
 
731
 
 
732
            s = p->attrib.x - p->output.left;
 
733
            e = p->attrib.x + p->width + p->output.right;
 
734
 
 
735
            if (s > object->position.x)
 
736
            {
 
737
                if (s < end)
 
738
                    end = s;
 
739
            }
 
740
            else if (e < object->position.x)
 
741
            {
 
742
                if (e > start)
 
743
                    start = e;
 
744
            }
 
745
            else
 
746
            {
 
747
                if (s > start)
 
748
                    start = s;
 
749
 
 
750
                if (e < end)
 
751
                    end = e;
 
752
 
 
753
                v = p->attrib.y - p->input.top;
 
754
                if (v >= y)
 
755
                {
 
756
                    if (v < v1)
 
757
                        v1 = v;
 
758
                }
 
759
                else
 
760
                {
 
761
                    if (v > v2)
 
762
                        v2 = v;
 
763
                }
 
764
            }
 
765
        }
 
766
    }
 
767
    else
 
768
    {
 
769
        v2 = w->screen->workArea.y + w->screen->workArea.height;
 
770
    }
 
771
 
 
772
    v1 = v1 + w->output.bottom - w->input.bottom;
 
773
    v2 = v2 + w->output.bottom - w->input.bottom;
 
774
 
 
775
    if (v1 != (int) object->horzEdge.next)
 
776
        object->horzEdge.snapped = FALSE;
 
777
 
 
778
    object->horzEdge.start = start;
 
779
    object->horzEdge.end   = end;
 
780
 
 
781
    object->horzEdge.next = v1;
 
782
    object->horzEdge.prev = v2;
 
783
 
 
784
    object->horzEdge.attract  = v1 - EDGE_DISTANCE;
 
785
    object->horzEdge.velocity = EDGE_VELOCITY;
 
786
}
 
787
 
 
788
static void
 
789
objectInit (Object *object,
 
790
            float  positionX,
 
791
            float  positionY,
 
792
            float  velocityX,
 
793
            float  velocityY)
 
794
{
 
795
    object->force.x = 0;
 
796
    object->force.y = 0;
 
797
 
 
798
    object->position.x = positionX;
 
799
    object->position.y = positionY;
 
800
 
 
801
    object->velocity.x = velocityX;
 
802
    object->velocity.y = velocityY;
 
803
 
 
804
    object->theta    = 0;
 
805
    object->immobile = FALSE;
 
806
 
 
807
    object->edgeMask = 0;
 
808
 
 
809
    object->vertEdge.snapped = FALSE;
 
810
    object->horzEdge.snapped = FALSE;
 
811
 
 
812
    object->vertEdge.next = 0.0f;
 
813
    object->horzEdge.next = 0.0f;
 
814
}
 
815
 
 
816
static void
 
817
springInit (Spring *spring,
 
818
            Object *a,
 
819
            Object *b,
 
820
            float  offsetX,
 
821
            float  offsetY)
 
822
{
 
823
    spring->a        = a;
 
824
    spring->b        = b;
 
825
    spring->offset.x = offsetX;
 
826
    spring->offset.y = offsetY;
 
827
}
 
828
 
 
829
static void
 
830
modelCalcBounds (Model *model)
 
831
{
 
832
    int i;
 
833
 
 
834
    model->topLeft.x     = MAXSHORT;
 
835
    model->topLeft.y     = MAXSHORT;
 
836
    model->bottomRight.x = MINSHORT;
 
837
    model->bottomRight.y = MINSHORT;
 
838
 
 
839
    for (i = 0; i < model->numObjects; i++)
 
840
    {
 
841
        if (model->objects[i].position.x < model->topLeft.x)
 
842
            model->topLeft.x = model->objects[i].position.x;
 
843
        else if (model->objects[i].position.x > model->bottomRight.x)
 
844
            model->bottomRight.x = model->objects[i].position.x;
 
845
 
 
846
        if (model->objects[i].position.y < model->topLeft.y)
 
847
            model->topLeft.y = model->objects[i].position.y;
 
848
        else if (model->objects[i].position.y > model->bottomRight.y)
 
849
            model->bottomRight.y = model->objects[i].position.y;
 
850
    }
 
851
}
 
852
 
 
853
static void
 
854
modelAddSpring (Model  *model,
 
855
                Object *a,
 
856
                Object *b,
 
857
                float  offsetX,
 
858
                float  offsetY)
 
859
{
 
860
    Spring *spring;
 
861
 
 
862
    spring = &model->springs[model->numSprings];
 
863
    model->numSprings++;
 
864
 
 
865
    springInit (spring, a, b, offsetX, offsetY);
 
866
}
 
867
 
 
868
static void
 
869
modelSetMiddleAnchor (Model *model,
 
870
                      int   x,
 
871
                      int   y,
 
872
                      int   width,
 
873
                      int   height)
 
874
{
 
875
    float w, h;
 
876
 
 
877
    if (model->anchorObject)
 
878
        model->anchorObject->immobile = FALSE;
 
879
 
 
880
    w = (float) width  * model->scale.x;
 
881
    h = (float) height * model->scale.y;
 
882
 
 
883
    model->anchorObject = &model->objects[GRID_WIDTH *
 
884
                                          ((GRID_HEIGHT - 1) / 2) +
 
885
                                          (GRID_WIDTH - 1) / 2];
 
886
    model->anchorObject->position.x = x +
 
887
        ((GRID_WIDTH - 1) / 2 * w) / (float) (GRID_WIDTH - 1);
 
888
    model->anchorObject->position.y = y +
 
889
        ((GRID_HEIGHT - 1) / 2 * h) / (float) (GRID_HEIGHT - 1);
 
890
 
 
891
    model->anchorObject->immobile = TRUE;
 
892
}
 
893
 
 
894
static void
 
895
modelInitObjects (Model *model,
 
896
                  int   x,
 
897
                  int   y,
 
898
                  int   width,
 
899
                  int   height)
 
900
{
 
901
    int   gridX, gridY, i = 0;
 
902
    float w, h;
 
903
 
 
904
    w = (float) width  * model->scale.x;
 
905
    h = (float) height * model->scale.y;
 
906
 
 
907
    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
 
908
    {
 
909
        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
 
910
        {
 
911
            objectInit (&model->objects[i],
 
912
                        x + (gridX * w) / (float) (GRID_WIDTH - 1),
 
913
                        y + (gridY * h) / (float) (GRID_HEIGHT - 1),
 
914
                        0, 0);
 
915
            i++;
 
916
        }
 
917
    }
 
918
 
 
919
    modelSetMiddleAnchor (model, x, y, width, height);
 
920
}
 
921
 
 
922
static void
 
923
modelUpdateSnapping (CompWindow *window,
 
924
                     Model      *model)
 
925
{
 
926
    unsigned int edgeMask, gridMask, mask;
 
927
    int          gridX, gridY, i = 0;
 
928
 
 
929
    edgeMask = model->edgeMask;
 
930
 
 
931
    if (model->snapCnt[NORTH])
 
932
        edgeMask &= ~SouthEdgeMask;
 
933
    else if (model->snapCnt[SOUTH])
 
934
        edgeMask &= ~NorthEdgeMask;
 
935
 
 
936
    if (model->snapCnt[WEST])
 
937
        edgeMask &= ~EastEdgeMask;
 
938
    else if (model->snapCnt[EAST])
 
939
        edgeMask &= ~WestEdgeMask;
 
940
 
 
941
    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
 
942
    {
 
943
        if (gridY == 0)
 
944
            gridMask = edgeMask & NorthEdgeMask;
 
945
        else if (gridY == GRID_HEIGHT - 1)
 
946
            gridMask = edgeMask & SouthEdgeMask;
 
947
        else
 
948
            gridMask = 0;
 
949
 
 
950
        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
 
951
        {
 
952
            mask = gridMask;
 
953
 
 
954
            if (gridX == 0)
 
955
                mask |= edgeMask & WestEdgeMask;
 
956
            else if (gridX == GRID_WIDTH - 1)
 
957
                mask |= edgeMask & EastEdgeMask;
 
958
 
 
959
            if (mask != model->objects[i].edgeMask)
 
960
            {
 
961
                model->objects[i].edgeMask = mask;
 
962
 
 
963
                if (mask & WestEdgeMask)
 
964
                {
 
965
                    if (!model->objects[i].vertEdge.snapped)
 
966
                        findNextWestEdge (window, &model->objects[i]);
 
967
                }
 
968
                else if (mask & EastEdgeMask)
 
969
                {
 
970
                    if (!model->objects[i].vertEdge.snapped)
 
971
                        findNextEastEdge (window, &model->objects[i]);
 
972
                }
 
973
                else
 
974
                    model->objects[i].vertEdge.snapped = FALSE;
 
975
 
 
976
                if (mask & NorthEdgeMask)
 
977
                {
 
978
                    if (!model->objects[i].horzEdge.snapped)
 
979
                        findNextNorthEdge (window, &model->objects[i]);
 
980
                }
 
981
                else if (mask & SouthEdgeMask)
 
982
                {
 
983
                    if (!model->objects[i].horzEdge.snapped)
 
984
                        findNextSouthEdge (window, &model->objects[i]);
 
985
                }
 
986
                else
 
987
                    model->objects[i].horzEdge.snapped = FALSE;
 
988
            }
 
989
 
 
990
            i++;
 
991
        }
 
992
    }
 
993
}
 
994
 
 
995
static void
 
996
modelReduceEdgeEscapeVelocity (Model *model)
 
997
{
 
998
    int gridX, gridY, i = 0;
 
999
 
 
1000
    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
 
1001
    {
 
1002
        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
 
1003
        {
 
1004
            if (model->objects[i].vertEdge.snapped)
 
1005
                model->objects[i].vertEdge.velocity *= drand48 () * 0.25f;
 
1006
 
 
1007
            if (model->objects[i].horzEdge.snapped)
 
1008
                model->objects[i].horzEdge.velocity *= drand48 () * 0.25f;
 
1009
 
 
1010
            i++;
 
1011
        }
 
1012
    }
 
1013
}
 
1014
 
 
1015
static Bool
 
1016
modelDisableSnapping (CompWindow *window,
 
1017
                      Model      *model)
 
1018
{
 
1019
    int  gridX, gridY, i = 0;
 
1020
    Bool snapped = FALSE;
 
1021
 
 
1022
    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
 
1023
    {
 
1024
        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
 
1025
        {
 
1026
            if (model->objects[i].vertEdge.snapped ||
 
1027
                model->objects[i].horzEdge.snapped)
 
1028
                snapped = TRUE;
 
1029
 
 
1030
            model->objects[i].vertEdge.snapped = FALSE;
 
1031
            model->objects[i].horzEdge.snapped = FALSE;
 
1032
 
 
1033
            model->objects[i].edgeMask = 0;
 
1034
 
 
1035
            i++;
 
1036
        }
 
1037
    }
 
1038
 
 
1039
    memset (model->snapCnt, 0, sizeof (model->snapCnt));
 
1040
 
 
1041
    return snapped;
 
1042
}
 
1043
 
 
1044
static void
 
1045
modelAdjustObjectsForShiver (Model *model,
 
1046
                             int   x,
 
1047
                             int   y,
 
1048
                             int   width,
 
1049
                             int   height)
 
1050
{
 
1051
    int   gridX, gridY, i = 0;
 
1052
    float vX, vY;
 
1053
    float scale;
 
1054
    float w, h;
 
1055
 
 
1056
    w = (float) width  * model->scale.x;
 
1057
    h = (float) height * model->scale.y;
 
1058
 
 
1059
    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
 
1060
    {
 
1061
        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
 
1062
        {
 
1063
            if (!model->objects[i].immobile)
 
1064
            {
 
1065
                vX = model->objects[i].position.x - (x + w / 2);
 
1066
                vY = model->objects[i].position.y - (y + h / 2);
 
1067
 
 
1068
                vX /= w;
 
1069
                vY /= h;
 
1070
 
 
1071
                scale = ((float) rand () * 7.5f) / RAND_MAX;
 
1072
 
 
1073
                model->objects[i].velocity.x += vX * scale;
 
1074
                model->objects[i].velocity.y += vY * scale;
 
1075
            }
 
1076
 
 
1077
            i++;
 
1078
        }
 
1079
    }
 
1080
}
 
1081
 
 
1082
static void
 
1083
modelInitSprings (Model *model,
 
1084
                  int   x,
 
1085
                  int   y,
 
1086
                  int   width,
 
1087
                  int   height)
 
1088
{
 
1089
    int   gridX, gridY, i = 0;
 
1090
    float hp, hpad, vpad;
 
1091
    float w, h;
 
1092
 
 
1093
    model->numSprings = 0;
 
1094
 
 
1095
    w = (float) width  * model->scale.x;
 
1096
    h = (float) height * model->scale.y;
 
1097
 
 
1098
    hpad = w / (GRID_WIDTH - 1);
 
1099
    vpad = h / (GRID_HEIGHT - 1);
 
1100
 
 
1101
    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
 
1102
    {
 
1103
        hp = hpad;
 
1104
 
 
1105
        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
 
1106
        {
 
1107
            if (gridX > 0)
 
1108
                modelAddSpring (model,
 
1109
                                &model->objects[i - 1],
 
1110
                                &model->objects[i],
 
1111
                                hp, 0);
 
1112
 
 
1113
            if (gridY > 0)
 
1114
                modelAddSpring (model,
 
1115
                                &model->objects[i - GRID_WIDTH],
 
1116
                                &model->objects[i],
 
1117
                                0, vpad);
 
1118
 
 
1119
            i++;
 
1120
        }
 
1121
    }
 
1122
}
 
1123
 
 
1124
static void
 
1125
modelMove (Model *model,
 
1126
           float tx,
 
1127
           float ty)
 
1128
{
 
1129
    int i;
 
1130
 
 
1131
    for (i = 0; i < model->numObjects; i++)
 
1132
    {
 
1133
        model->objects[i].position.x += tx;
 
1134
        model->objects[i].position.y += ty;
 
1135
    }
 
1136
}
 
1137
 
 
1138
static Model *
 
1139
createModel (int          x,
 
1140
             int          y,
 
1141
             int          width,
 
1142
             int          height,
 
1143
             unsigned int edgeMask)
 
1144
{
 
1145
    Model *model;
 
1146
 
 
1147
    model = malloc (sizeof (Model));
 
1148
    if (!model)
 
1149
        return 0;
 
1150
 
 
1151
    model->numObjects = GRID_WIDTH * GRID_HEIGHT;
 
1152
    model->objects = malloc (sizeof (Object) * model->numObjects);
 
1153
    if (!model->objects)
 
1154
        return 0;
 
1155
 
 
1156
    model->anchorObject = 0;
 
1157
    model->numSprings = 0;
 
1158
 
 
1159
    model->steps = 0;
 
1160
 
 
1161
    model->scale.x = 1.0f;
 
1162
    model->scale.y = 1.0f;
 
1163
 
 
1164
    model->transformed = FALSE;
 
1165
 
 
1166
    memset (model->snapCnt, 0, sizeof (model->snapCnt));
 
1167
 
 
1168
    model->edgeMask = edgeMask;
 
1169
 
 
1170
    modelInitObjects (model, x, y, width, height);
 
1171
    modelInitSprings (model, x, y, width, height);
 
1172
 
 
1173
    modelCalcBounds (model);
 
1174
 
 
1175
    return model;
 
1176
}
 
1177
 
 
1178
static void
 
1179
objectApplyForce (Object *object,
 
1180
                  float  fx,
 
1181
                  float  fy)
 
1182
{
 
1183
    object->force.x += fx;
 
1184
    object->force.y += fy;
 
1185
}
 
1186
 
 
1187
static void
 
1188
springExertForces (Spring *spring,
 
1189
                   float  k)
 
1190
{
 
1191
    Vector da, db;
 
1192
    Vector a, b;
 
1193
 
 
1194
    a = spring->a->position;
 
1195
    b = spring->b->position;
 
1196
 
 
1197
    da.x = 0.5f * (b.x - a.x - spring->offset.x);
 
1198
    da.y = 0.5f * (b.y - a.y - spring->offset.y);
 
1199
 
 
1200
    db.x = 0.5f * (a.x - b.x + spring->offset.x);
 
1201
    db.y = 0.5f * (a.y - b.y + spring->offset.y);
 
1202
 
 
1203
    objectApplyForce (spring->a, k * da.x, k * da.y);
 
1204
    objectApplyForce (spring->b, k * db.x, k * db.y);
 
1205
}
 
1206
 
 
1207
static Bool
 
1208
objectReleaseWestEdge (CompWindow *w,
 
1209
                       Model      *model,
 
1210
                       Object     *object)
 
1211
{
 
1212
    if (fabs (object->velocity.x) > object->vertEdge.velocity)
 
1213
    {
 
1214
        object->position.x += object->velocity.x * 2.0f;
 
1215
 
 
1216
        model->snapCnt[WEST]--;
 
1217
 
 
1218
        object->vertEdge.snapped = FALSE;
 
1219
        object->edgeMask = 0;
 
1220
 
 
1221
        modelUpdateSnapping (w, model);
 
1222
 
 
1223
        return TRUE;
 
1224
    }
 
1225
 
 
1226
    object->velocity.x = 0.0f;
 
1227
 
 
1228
    return FALSE;
 
1229
}
 
1230
 
 
1231
static Bool
 
1232
objectReleaseEastEdge (CompWindow *w,
 
1233
                       Model      *model,
 
1234
                       Object     *object)
 
1235
{
 
1236
    if (fabs (object->velocity.x) > object->vertEdge.velocity)
 
1237
    {
 
1238
        object->position.x += object->velocity.x * 2.0f;
 
1239
 
 
1240
        model->snapCnt[EAST]--;
 
1241
 
 
1242
        object->vertEdge.snapped = FALSE;
 
1243
        object->edgeMask = 0;
 
1244
 
 
1245
        modelUpdateSnapping (w, model);
 
1246
 
 
1247
        return TRUE;
 
1248
    }
 
1249
 
 
1250
    object->velocity.x = 0.0f;
 
1251
 
 
1252
    return FALSE;
 
1253
}
 
1254
 
 
1255
static Bool
 
1256
objectReleaseNorthEdge (CompWindow *w,
 
1257
                        Model      *model,
 
1258
                        Object     *object)
 
1259
{
 
1260
    if (fabs (object->velocity.y) > object->horzEdge.velocity)
 
1261
    {
 
1262
        object->position.y += object->velocity.y * 2.0f;
 
1263
 
 
1264
        model->snapCnt[NORTH]--;
 
1265
 
 
1266
        object->horzEdge.snapped = FALSE;
 
1267
        object->edgeMask = 0;
 
1268
 
 
1269
        modelUpdateSnapping (w, model);
 
1270
 
 
1271
        return TRUE;
 
1272
    }
 
1273
 
 
1274
    object->velocity.y = 0.0f;
 
1275
 
 
1276
    return FALSE;
 
1277
}
 
1278
 
 
1279
static Bool
 
1280
objectReleaseSouthEdge (CompWindow *w,
 
1281
                        Model      *model,
 
1282
                        Object     *object)
 
1283
{
 
1284
    if (fabs (object->velocity.y) > object->horzEdge.velocity)
 
1285
    {
 
1286
        object->position.y += object->velocity.y * 2.0f;
 
1287
 
 
1288
        model->snapCnt[SOUTH]--;
 
1289
 
 
1290
        object->horzEdge.snapped = FALSE;
 
1291
        object->edgeMask = 0;
 
1292
 
 
1293
        modelUpdateSnapping (w, model);
 
1294
 
 
1295
        return TRUE;
 
1296
    }
 
1297
 
 
1298
    object->velocity.y = 0.0f;
 
1299
 
 
1300
    return FALSE;
 
1301
}
 
1302
 
 
1303
static float
 
1304
modelStepObject (CompWindow *window,
 
1305
                 Model      *model,
 
1306
                 Object     *object,
 
1307
                 float      friction,
 
1308
                 float      *force)
 
1309
{
 
1310
    object->theta += 0.05f;
 
1311
 
 
1312
    if (object->immobile)
 
1313
    {
 
1314
        object->velocity.x = 0.0f;
 
1315
        object->velocity.y = 0.0f;
 
1316
 
 
1317
        object->force.x = 0.0f;
 
1318
        object->force.y = 0.0f;
 
1319
 
 
1320
        *force = 0.0f;
 
1321
 
 
1322
        return 0.0f;
 
1323
    }
 
1324
    else
 
1325
    {
 
1326
        object->force.x -= friction * object->velocity.x;
 
1327
        object->force.y -= friction * object->velocity.y;
 
1328
 
 
1329
        object->velocity.x += object->force.x / MASS;
 
1330
        object->velocity.y += object->force.y / MASS;
 
1331
 
 
1332
        if (object->edgeMask)
 
1333
        {
 
1334
            if (object->edgeMask & WestEdgeMask)
 
1335
            {
 
1336
                if (object->position.y < object->vertEdge.start ||
 
1337
                    object->position.y > object->vertEdge.end)
 
1338
                    findNextWestEdge (window, object);
 
1339
 
 
1340
                if (object->vertEdge.snapped == FALSE ||
 
1341
                    objectReleaseWestEdge (window, model, object))
 
1342
                {
 
1343
                    object->position.x += object->velocity.x;
 
1344
 
 
1345
                    if (object->velocity.x < 0.0f &&
 
1346
                        object->position.x < object->vertEdge.attract)
 
1347
                    {
 
1348
                        if (object->position.x < object->vertEdge.next)
 
1349
                        {
 
1350
                            object->vertEdge.snapped = TRUE;
 
1351
                            object->position.x = object->vertEdge.next;
 
1352
                            object->velocity.x = 0.0f;
 
1353
 
 
1354
                            model->snapCnt[WEST]++;
 
1355
 
 
1356
                            modelUpdateSnapping (window, model);
 
1357
                        }
 
1358
                        else
 
1359
                        {
 
1360
                            object->velocity.x -=
 
1361
                                object->vertEdge.attract - object->position.x;
 
1362
                        }
 
1363
                    }
 
1364
 
 
1365
                    if (object->position.x > object->vertEdge.prev)
 
1366
                        findNextWestEdge (window, object);
 
1367
                }
 
1368
            }
 
1369
            else if (object->edgeMask & EastEdgeMask)
 
1370
            {
 
1371
                if (object->position.y < object->vertEdge.start ||
 
1372
                    object->position.y > object->vertEdge.end)
 
1373
                    findNextEastEdge (window, object);
 
1374
 
 
1375
                if (object->vertEdge.snapped == FALSE ||
 
1376
                    objectReleaseEastEdge (window, model, object))
 
1377
                {
 
1378
                    object->position.x += object->velocity.x;
 
1379
 
 
1380
                    if (object->velocity.x > 0.0f &&
 
1381
                        object->position.x > object->vertEdge.attract)
 
1382
                    {
 
1383
                        if (object->position.x > object->vertEdge.next)
 
1384
                        {
 
1385
                            object->vertEdge.snapped = TRUE;
 
1386
                            object->position.x = object->vertEdge.next;
 
1387
                            object->velocity.x = 0.0f;
 
1388
 
 
1389
                            model->snapCnt[EAST]++;
 
1390
 
 
1391
                            modelUpdateSnapping (window, model);
 
1392
                        }
 
1393
                        else
 
1394
                        {
 
1395
                            object->velocity.x =
 
1396
                                object->position.x - object->vertEdge.attract;
 
1397
                        }
 
1398
                    }
 
1399
 
 
1400
                    if (object->position.x < object->vertEdge.prev)
 
1401
                        findNextEastEdge (window, object);
 
1402
                }
 
1403
            }
 
1404
            else
 
1405
                object->position.x += object->velocity.x;
 
1406
 
 
1407
            if (object->edgeMask & NorthEdgeMask)
 
1408
            {
 
1409
                if (object->position.x < object->horzEdge.start ||
 
1410
                    object->position.x > object->horzEdge.end)
 
1411
                    findNextNorthEdge (window, object);
 
1412
 
 
1413
                if (object->horzEdge.snapped == FALSE ||
 
1414
                    objectReleaseNorthEdge (window, model, object))
 
1415
                {
 
1416
                    object->position.y += object->velocity.y;
 
1417
 
 
1418
                    if (object->velocity.y < 0.0f &&
 
1419
                        object->position.y < object->horzEdge.attract)
 
1420
                    {
 
1421
                        if (object->position.y < object->horzEdge.next)
 
1422
                        {
 
1423
                            object->horzEdge.snapped = TRUE;
 
1424
                            object->position.y = object->horzEdge.next;
 
1425
                            object->velocity.y = 0.0f;
 
1426
 
 
1427
                            model->snapCnt[NORTH]++;
 
1428
 
 
1429
                            modelUpdateSnapping (window, model);
 
1430
                        }
 
1431
                        else
 
1432
                        {
 
1433
                            object->velocity.y -=
 
1434
                                object->horzEdge.attract - object->position.y;
 
1435
                        }
 
1436
                    }
 
1437
 
 
1438
                    if (object->position.y > object->horzEdge.prev)
 
1439
                        findNextNorthEdge (window, object);
 
1440
                }
 
1441
            }
 
1442
            else if (object->edgeMask & SouthEdgeMask)
 
1443
            {
 
1444
                if (object->position.x < object->horzEdge.start ||
 
1445
                    object->position.x > object->horzEdge.end)
 
1446
                    findNextSouthEdge (window, object);
 
1447
 
 
1448
                if (object->horzEdge.snapped == FALSE ||
 
1449
                    objectReleaseSouthEdge (window, model, object))
 
1450
                {
 
1451
                    object->position.y += object->velocity.y;
 
1452
 
 
1453
                    if (object->velocity.y > 0.0f &&
 
1454
                        object->position.y > object->horzEdge.attract)
 
1455
                    {
 
1456
                        if (object->position.y > object->horzEdge.next)
 
1457
                        {
 
1458
                            object->horzEdge.snapped = TRUE;
 
1459
                            object->position.y = object->horzEdge.next;
 
1460
                            object->velocity.y = 0.0f;
 
1461
 
 
1462
                            model->snapCnt[SOUTH]++;
 
1463
 
 
1464
                            modelUpdateSnapping (window, model);
 
1465
                        }
 
1466
                        else
 
1467
                        {
 
1468
                            object->velocity.y =
 
1469
                                object->position.y - object->horzEdge.attract;
 
1470
                        }
 
1471
                    }
 
1472
 
 
1473
                    if (object->position.y < object->horzEdge.prev)
 
1474
                        findNextSouthEdge (window, object);
 
1475
                }
 
1476
            }
 
1477
            else
 
1478
                object->position.y += object->velocity.y;
 
1479
        }
 
1480
        else
 
1481
        {
 
1482
            object->position.x += object->velocity.x;
 
1483
            object->position.y += object->velocity.y;
 
1484
        }
 
1485
 
 
1486
        *force = fabs (object->force.x) + fabs (object->force.y);
 
1487
 
 
1488
        object->force.x = 0.0f;
 
1489
        object->force.y = 0.0f;
 
1490
 
 
1491
        return fabs (object->velocity.x) + fabs (object->velocity.y);
 
1492
    }
 
1493
}
 
1494
 
 
1495
static int
 
1496
modelStep (CompWindow *window,
 
1497
           Model      *model,
 
1498
           float      friction,
 
1499
           float      k,
 
1500
           float      time)
 
1501
{
 
1502
    int   i, j, steps, wobbly = 0;
 
1503
    float velocitySum = 0.0f;
 
1504
    float force, forceSum = 0.0f;
 
1505
 
 
1506
    model->steps += time / 15.0f;
 
1507
    steps = floor (model->steps);
 
1508
    model->steps -= steps;
 
1509
 
 
1510
    if (!steps)
 
1511
        return TRUE;
 
1512
 
 
1513
    for (j = 0; j < steps; j++)
 
1514
    {
 
1515
        for (i = 0; i < model->numSprings; i++)
 
1516
            springExertForces (&model->springs[i], k);
 
1517
 
 
1518
        for (i = 0; i < model->numObjects; i++)
 
1519
        {
 
1520
            velocitySum += modelStepObject (window,
 
1521
                                            model,
 
1522
                                            &model->objects[i],
 
1523
                                            friction,
 
1524
                                            &force);
 
1525
            forceSum += force;
 
1526
        }
 
1527
    }
 
1528
 
 
1529
    modelCalcBounds (model);
 
1530
 
 
1531
    if (velocitySum > 0.5f)
 
1532
        wobbly |= WobblyVelocity;
 
1533
 
 
1534
    if (forceSum > 20.0f)
 
1535
        wobbly |= WobblyForce;
 
1536
 
 
1537
    return wobbly;
 
1538
}
 
1539
 
 
1540
static void
 
1541
bezierPatchEvaluate (Model *model,
 
1542
                     float u,
 
1543
                     float v,
 
1544
                     float *patchX,
 
1545
                     float *patchY)
 
1546
{
 
1547
    float coeffsU[4], coeffsV[4];
 
1548
    float x, y;
 
1549
    int   i, j;
 
1550
 
 
1551
    coeffsU[0] = (1 - u) * (1 - u) * (1 - u);
 
1552
    coeffsU[1] = 3 * u * (1 - u) * (1 - u);
 
1553
    coeffsU[2] = 3 * u * u * (1 - u);
 
1554
    coeffsU[3] = u * u * u;
 
1555
 
 
1556
    coeffsV[0] = (1 - v) * (1 - v) * (1 - v);
 
1557
    coeffsV[1] = 3 * v * (1 - v) * (1 - v);
 
1558
    coeffsV[2] = 3 * v * v * (1 - v);
 
1559
    coeffsV[3] = v * v * v;
 
1560
 
 
1561
    x = y = 0.0f;
 
1562
 
 
1563
    for (i = 0; i < 4; i++)
 
1564
    {
 
1565
        for (j = 0; j < 4; j++)
 
1566
        {
 
1567
            x += coeffsU[i] * coeffsV[j] *
 
1568
                model->objects[j * GRID_WIDTH + i].position.x;
 
1569
            y += coeffsU[i] * coeffsV[j] *
 
1570
                model->objects[j * GRID_WIDTH + i].position.y;
 
1571
        }
 
1572
    }
 
1573
 
 
1574
    *patchX = x;
 
1575
    *patchY = y;
 
1576
}
 
1577
 
 
1578
static Bool
 
1579
wobblyEnsureModel (CompWindow *w)
 
1580
{
 
1581
    WOBBLY_WINDOW (w);
 
1582
 
 
1583
    if (!ww->model)
 
1584
    {
 
1585
        unsigned int edgeMask = 0;
 
1586
 
 
1587
        if (w->type & CompWindowTypeNormalMask)
 
1588
            edgeMask = WestEdgeMask | EastEdgeMask | NorthEdgeMask |
 
1589
                SouthEdgeMask;
 
1590
 
 
1591
        ww->model = createModel (WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w),
 
1592
                                 edgeMask);
 
1593
        if (!ww->model)
 
1594
            return FALSE;
 
1595
    }
 
1596
 
 
1597
    return TRUE;
 
1598
}
 
1599
 
 
1600
static float
 
1601
objectDistance (Object *object,
 
1602
                float  x,
 
1603
                float  y)
 
1604
{
 
1605
    float dx, dy;
 
1606
 
 
1607
    dx = object->position.x - x;
 
1608
    dy = object->position.y - y;
 
1609
 
 
1610
    return sqrt (dx * dx + dy * dy);
 
1611
}
 
1612
 
 
1613
static Object *
 
1614
modelFindNearestObject (Model *model,
 
1615
                        float x,
 
1616
                        float y)
 
1617
{
 
1618
    Object *object = &model->objects[0];
 
1619
    float  distance, minDistance = 0.0;
 
1620
    int    i;
 
1621
 
 
1622
    for (i = 0; i < model->numObjects; i++)
 
1623
    {
 
1624
        distance = objectDistance (&model->objects[i], x, y);
 
1625
        if (i == 0 || distance < minDistance)
 
1626
        {
 
1627
            minDistance = distance;
 
1628
            object = &model->objects[i];
 
1629
        }
 
1630
    }
 
1631
 
 
1632
    return object;
 
1633
}
 
1634
 
 
1635
static Bool
 
1636
isWobblyWin (CompWindow *w)
 
1637
{
 
1638
    WOBBLY_SCREEN (w->screen);
 
1639
    WOBBLY_WINDOW (w);
 
1640
 
 
1641
    if (ww->model)
 
1642
        return TRUE;
 
1643
 
 
1644
    if (!(ws->wMask & w->type))
 
1645
        return FALSE;
 
1646
 
 
1647
    /* avoid tiny windows */
 
1648
    if (w->width == 1 && w->height == 1)
 
1649
        return FALSE;
 
1650
 
 
1651
    /* avoid fullscreen windows */
 
1652
    if (w->attrib.x <= 0 &&
 
1653
        w->attrib.y <= 0 &&
 
1654
        w->attrib.x + w->width >= w->screen->width &&
 
1655
        w->attrib.y + w->height >= w->screen->height)
 
1656
        return FALSE;
 
1657
 
 
1658
    return TRUE;
 
1659
}
 
1660
 
 
1661
static void
 
1662
wobblyPreparePaintScreen (CompScreen *s,
 
1663
                          int        msSinceLastPaint)
 
1664
{
 
1665
    WobblyWindow *ww;
 
1666
    CompWindow   *w;
 
1667
 
 
1668
    WOBBLY_SCREEN (s);
 
1669
 
 
1670
    if (ws->wobblyWindows & (WobblyInitial | WobblyVelocity))
 
1671
    {
 
1672
        REGION region;
 
1673
        Point  topLeft, bottomRight;
 
1674
        float  friction, springK;
 
1675
        Model  *model;
 
1676
 
 
1677
        friction = ws->opt[WOBBLY_SCREEN_OPTION_FRICTION].value.f;
 
1678
        springK  = ws->opt[WOBBLY_SCREEN_OPTION_SPRING_K].value.f;
 
1679
 
 
1680
        region.rects = &region.extents;
 
1681
        region.numRects = region.size = 1;
 
1682
 
 
1683
        ws->wobblyWindows = 0;
 
1684
        for (w = s->windows; w; w = w->next)
 
1685
        {
 
1686
            ww = GET_WOBBLY_WINDOW (w, ws);
 
1687
 
 
1688
            if (ww->wobbly)
 
1689
            {
 
1690
                if (ww->wobbly & (WobblyInitial | WobblyVelocity))
 
1691
                {
 
1692
                    model = ww->model;
 
1693
 
 
1694
                    topLeft     = model->topLeft;
 
1695
                    bottomRight = model->bottomRight;
 
1696
 
 
1697
                    ww->wobbly = modelStep (w, model, friction, springK,
 
1698
                                            (ww->wobbly & WobblyVelocity) ?
 
1699
                                            msSinceLastPaint :
 
1700
                                            s->redrawTime);
 
1701
 
 
1702
                    if (ww->wobbly)
 
1703
                    {
 
1704
                        /* snapped to more than one edge, we have to reduce
 
1705
                           edge escape velocity until only one edge is snapped */
 
1706
                        if (ww->wobbly == WobblyForce && !ww->grabbed)
 
1707
                        {
 
1708
                            modelReduceEdgeEscapeVelocity (ww->model);
 
1709
                            ww->wobbly |= WobblyInitial;
 
1710
                        }
 
1711
                    }
 
1712
                    else
 
1713
                    {
 
1714
                        ww->model = 0;
 
1715
 
 
1716
                        moveWindow (w,
 
1717
                                    model->topLeft.x + w->output.left -
 
1718
                                    w->attrib.x,
 
1719
                                    model->topLeft.y + w->output.top -
 
1720
                                    w->attrib.y,
 
1721
                                    TRUE);
 
1722
 
 
1723
                        ww->model = model;
 
1724
 
 
1725
                        syncWindowPosition (w);
 
1726
                    }
 
1727
 
 
1728
                    if (!(s->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK))
 
1729
                    {
 
1730
                        if (ww->wobbly)
 
1731
                        {
 
1732
                            if (ww->model->topLeft.x < topLeft.x)
 
1733
                                topLeft.x = ww->model->topLeft.x;
 
1734
                            if (ww->model->topLeft.y < topLeft.y)
 
1735
                                topLeft.y = ww->model->topLeft.y;
 
1736
                            if (ww->model->bottomRight.x > bottomRight.x)
 
1737
                                bottomRight.x = ww->model->bottomRight.x;
 
1738
                            if (ww->model->bottomRight.y > bottomRight.y)
 
1739
                                bottomRight.y = ww->model->bottomRight.y;
 
1740
                        }
 
1741
                        else
 
1742
                            addWindowDamage (w);
 
1743
 
 
1744
                        region.extents.x1 = topLeft.x;
 
1745
                        region.extents.y1 = topLeft.y;
 
1746
                        region.extents.x2 = bottomRight.x + 0.5f;
 
1747
                        region.extents.y2 = bottomRight.y + 0.5f;
 
1748
 
 
1749
                        damageScreenRegion (s, &region);
 
1750
                    }
 
1751
                }
 
1752
 
 
1753
                ws->wobblyWindows |= ww->wobbly;
 
1754
            }
 
1755
        }
 
1756
    }
 
1757
 
 
1758
    UNWRAP (ws, s, preparePaintScreen);
 
1759
    (*s->preparePaintScreen) (s, msSinceLastPaint);
 
1760
    WRAP (ws, s, preparePaintScreen, wobblyPreparePaintScreen);
 
1761
}
 
1762
 
 
1763
static void
 
1764
wobblyDonePaintScreen (CompScreen *s)
 
1765
{
 
1766
    WOBBLY_SCREEN (s);
 
1767
 
 
1768
    if (ws->wobblyWindows & WobblyVelocity)
 
1769
        damagePendingOnScreen (s);
 
1770
 
 
1771
    UNWRAP (ws, s, donePaintScreen);
 
1772
    (*s->donePaintScreen) (s);
 
1773
    WRAP (ws, s, donePaintScreen, wobblyDonePaintScreen);
 
1774
}
 
1775
 
 
1776
static void
 
1777
wobblyAddWindowGeometry (CompWindow *w,
 
1778
                         CompMatrix *matrix,
 
1779
                         int        nMatrix,
 
1780
                         Region     region,
 
1781
                         Region     clip)
 
1782
{
 
1783
    WOBBLY_WINDOW (w);
 
1784
    WOBBLY_SCREEN (w->screen);
 
1785
 
 
1786
    if (ww->wobbly)
 
1787
    {
 
1788
        BoxPtr   pClip;
 
1789
        int      nClip, nVertices, nIndices;
 
1790
        GLushort *i;
 
1791
        GLfloat  *v;
 
1792
        int      x1, y1, x2, y2;
 
1793
        float    width, height;
 
1794
        float    deformedX, deformedY;
 
1795
        int      x, y, iw, ih, wx, wy;
 
1796
        int      vSize, it;
 
1797
        int      gridW, gridH;
 
1798
        Bool     rect = TRUE;
 
1799
 
 
1800
        for (it = 0; it < nMatrix; it++)
 
1801
        {
 
1802
            if (matrix[it].xy != 0.0f && matrix[it].yx != 0.0f)
 
1803
            {
 
1804
                rect = FALSE;
 
1805
                break;
 
1806
            }
 
1807
        }
 
1808
 
 
1809
        wx     = WIN_X (w);
 
1810
        wy     = WIN_Y (w);
 
1811
        width  = WIN_W (w);
 
1812
        height = WIN_H (w);
 
1813
 
 
1814
        gridW = width / ws->opt[WOBBLY_SCREEN_OPTION_GRID_RESOLUTION].value.i;
 
1815
        if (gridW < ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i)
 
1816
            gridW = ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i;
 
1817
 
 
1818
        gridH = height / ws->opt[WOBBLY_SCREEN_OPTION_GRID_RESOLUTION].value.i;
 
1819
        if (gridH < ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i)
 
1820
            gridH = ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i;
 
1821
 
 
1822
        nClip = region->numRects;
 
1823
        pClip = region->rects;
 
1824
 
 
1825
        w->texUnits = nMatrix;
 
1826
 
 
1827
        vSize = 2 + nMatrix * 2;
 
1828
 
 
1829
        nVertices = w->vCount;
 
1830
        nIndices  = w->vCount;
 
1831
 
 
1832
        v = w->vertices + (nVertices * vSize);
 
1833
        i = w->indices  + nIndices;
 
1834
 
 
1835
        while (nClip--)
 
1836
        {
 
1837
            x1 = pClip->x1;
 
1838
            y1 = pClip->y1;
 
1839
            x2 = pClip->x2;
 
1840
            y2 = pClip->y2;
 
1841
 
 
1842
            iw = ((x2 - x1 - 1) / gridW) + 1;
 
1843
            ih = ((y2 - y1 - 1) / gridH) + 1;
 
1844
 
 
1845
            if (nIndices + (iw * ih * 4) > w->indexSize)
 
1846
            {
 
1847
                if (!moreWindowIndices (w, nIndices + (iw * ih * 4)))
 
1848
                    return;
 
1849
 
 
1850
                i = w->indices + nIndices;
 
1851
            }
 
1852
 
 
1853
            iw++;
 
1854
            ih++;
 
1855
 
 
1856
            for (y = 0; y < ih - 1; y++)
 
1857
            {
 
1858
                for (x = 0; x < iw - 1; x++)
 
1859
                {
 
1860
                    *i++ = nVertices + iw * (y + 1) + x;
 
1861
                    *i++ = nVertices + iw * (y + 1) + x + 1;
 
1862
                    *i++ = nVertices + iw * y + x + 1;
 
1863
                    *i++ = nVertices + iw * y + x;
 
1864
 
 
1865
                    nIndices += 4;
 
1866
                }
 
1867
            }
 
1868
 
 
1869
            if (((nVertices + iw * ih) * vSize) > w->vertexSize)
 
1870
            {
 
1871
                if (!moreWindowVertices (w, (nVertices + iw * ih) * vSize))
 
1872
                    return;
 
1873
 
 
1874
                v = w->vertices + (nVertices * vSize);
 
1875
            }
 
1876
 
 
1877
            for (y = y1;; y += gridH)
 
1878
            {
 
1879
                if (y > y2)
 
1880
                    y = y2;
 
1881
 
 
1882
                for (x = x1;; x += gridW)
 
1883
                {
 
1884
                    if (x > x2)
 
1885
                        x = x2;
 
1886
 
 
1887
                    bezierPatchEvaluate (ww->model,
 
1888
                                         (x - wx) / width,
 
1889
                                         (y - wy) / height,
 
1890
                                         &deformedX,
 
1891
                                         &deformedY);
 
1892
 
 
1893
                    if (rect)
 
1894
                    {
 
1895
                        for (it = 0; it < nMatrix; it++)
 
1896
                        {
 
1897
                            *v++ = COMP_TEX_COORD_X (&matrix[it], x);
 
1898
                            *v++ = COMP_TEX_COORD_Y (&matrix[it], y);
 
1899
                        }
 
1900
                    }
 
1901
                    else
 
1902
                    {
 
1903
                        for (it = 0; it < nMatrix; it++)
 
1904
                        {
 
1905
                            *v++ = COMP_TEX_COORD_XY (&matrix[it], x, y);
 
1906
                            *v++ = COMP_TEX_COORD_YX (&matrix[it], x, y);
 
1907
                        }
 
1908
                    }
 
1909
 
 
1910
                    *v++ = deformedX;
 
1911
                    *v++ = deformedY;
 
1912
 
 
1913
                    nVertices++;
 
1914
 
 
1915
                    if (x == x2)
 
1916
                        break;
 
1917
                }
 
1918
 
 
1919
                if (y == y2)
 
1920
                    break;
 
1921
            }
 
1922
 
 
1923
            pClip++;
 
1924
        }
 
1925
 
 
1926
        w->vCount = nIndices;
 
1927
    }
 
1928
    else
 
1929
    {
 
1930
        UNWRAP (ws, w->screen, addWindowGeometry);
 
1931
        (*w->screen->addWindowGeometry) (w, matrix, nMatrix, region, clip);
 
1932
        WRAP (ws, w->screen, addWindowGeometry, wobblyAddWindowGeometry);
 
1933
    }
 
1934
}
 
1935
 
 
1936
static void
 
1937
wobblyDrawWindowGeometry (CompWindow *w)
 
1938
{
 
1939
    WOBBLY_WINDOW (w);
 
1940
 
 
1941
    if (ww->wobbly)
 
1942
    {
 
1943
        int     texUnit = w->texUnits;
 
1944
        int     currentTexUnit = 0;
 
1945
        int     stride = (1 + texUnit) * 2;
 
1946
        GLfloat *vertices = w->vertices + (stride - 2);
 
1947
 
 
1948
        stride *= sizeof (GLfloat);
 
1949
 
 
1950
        glVertexPointer (2, GL_FLOAT, stride, vertices);
 
1951
 
 
1952
        while (texUnit--)
 
1953
        {
 
1954
            if (texUnit != currentTexUnit)
 
1955
            {
 
1956
                w->screen->clientActiveTexture (GL_TEXTURE0_ARB + texUnit);
 
1957
                currentTexUnit = texUnit;
 
1958
            }
 
1959
            vertices -= 2;
 
1960
            glTexCoordPointer (2, GL_FLOAT, stride, vertices);
 
1961
        }
 
1962
 
 
1963
        glDrawElements (GL_QUADS, w->vCount, GL_UNSIGNED_SHORT, w->indices);
 
1964
    }
 
1965
    else
 
1966
    {
 
1967
        WOBBLY_SCREEN (w->screen);
 
1968
 
 
1969
        UNWRAP (ws, w->screen, drawWindowGeometry);
 
1970
        (*w->screen->drawWindowGeometry) (w);
 
1971
        WRAP (ws, w->screen, drawWindowGeometry, wobblyDrawWindowGeometry);
 
1972
    }
 
1973
}
 
1974
 
 
1975
static Bool
 
1976
wobblyPaintWindow (CompWindow              *w,
 
1977
                   const WindowPaintAttrib *attrib,
 
1978
                   Region                  region,
 
1979
                   unsigned int            mask)
 
1980
{
 
1981
    Bool status;
 
1982
 
 
1983
    WOBBLY_SCREEN (w->screen);
 
1984
    WOBBLY_WINDOW (w);
 
1985
 
 
1986
    if (ww->wobbly)
 
1987
    {
 
1988
        if (mask & PAINT_WINDOW_SOLID_MASK)
 
1989
            return FALSE;
 
1990
 
 
1991
        mask |= PAINT_WINDOW_TRANSFORMED_MASK;
 
1992
    }
 
1993
 
 
1994
    UNWRAP (ws, w->screen, paintWindow);
 
1995
    status = (*w->screen->paintWindow) (w, attrib, region, mask);
 
1996
    WRAP (ws, w->screen, paintWindow, wobblyPaintWindow);
 
1997
 
 
1998
    return status;
 
1999
}
 
2000
 
 
2001
static void
 
2002
wobblyHandleEvent (CompDisplay *d,
 
2003
                   XEvent      *event)
 
2004
{
 
2005
    Window     activeWindow = 0;
 
2006
    CompWindow *w;
 
2007
    CompScreen *s;
 
2008
 
 
2009
    WOBBLY_DISPLAY (d);
 
2010
 
 
2011
    switch (event->type) {
 
2012
    case PropertyNotify:
 
2013
        if (event->xproperty.atom == d->winActiveAtom)
 
2014
            activeWindow = d->activeWindow;
 
2015
        break;
 
2016
    case MapNotify:
 
2017
        w = findWindowAtDisplay (d, event->xunmap.window);
 
2018
        if (w)
 
2019
        {
 
2020
            WOBBLY_WINDOW (w);
 
2021
 
 
2022
            if (ww->model)
 
2023
            {
 
2024
                modelInitObjects (ww->model,
 
2025
                                  WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
 
2026
 
 
2027
                modelInitSprings (ww->model,
 
2028
                                  WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
 
2029
            }
 
2030
        }
 
2031
        break;
 
2032
    case KeyPress:
 
2033
        s = findScreenAtDisplay (d, event->xkey.root);
 
2034
        if (s)
 
2035
        {
 
2036
            WOBBLY_SCREEN (s);
 
2037
 
 
2038
#define EV_SNAP_KEY(opt, event)                                \
 
2039
    ((opt)->value.bind.type == CompBindingTypeKey &&           \
 
2040
     (opt)->value.bind.u.key.keycode == (event)->xkey.keycode)
 
2041
 
 
2042
            if (EV_SNAP_KEY (&ws->opt[WOBBLY_SCREEN_OPTION_SNAP], event))
 
2043
            {
 
2044
                for (w = s->windows; w; w = w->next)
 
2045
                {
 
2046
                    WOBBLY_WINDOW (w);
 
2047
 
 
2048
                    if (ww->grabbed && ww->model)
 
2049
                        modelUpdateSnapping (w, ww->model);
 
2050
                }
 
2051
            }
 
2052
        }
 
2053
        break;
 
2054
    case KeyRelease:
 
2055
        s = findScreenAtDisplay (d, event->xkey.root);
 
2056
        if (s)
 
2057
        {
 
2058
            WOBBLY_SCREEN (s);
 
2059
 
 
2060
            if (EV_SNAP_KEY (&ws->opt[WOBBLY_SCREEN_OPTION_SNAP], event))
 
2061
            {
 
2062
                WOBBLY_SCREEN (s);
 
2063
 
 
2064
                for (w = s->windows; w; w = w->next)
 
2065
                {
 
2066
                    WOBBLY_WINDOW (w);
 
2067
 
 
2068
                    if (ww->grabbed && ww->model)
 
2069
                    {
 
2070
                        if (modelDisableSnapping (w, ww->model))
 
2071
                        {
 
2072
                            ww->wobbly |= WobblyInitial;
 
2073
                            ws->wobblyWindows |= ww->wobbly;
 
2074
 
 
2075
                            damagePendingOnScreen (w->screen);
 
2076
                        }
 
2077
                    }
 
2078
                }
 
2079
            }
 
2080
        }
 
2081
    default:
 
2082
        break;
 
2083
    }
 
2084
 
 
2085
    UNWRAP (wd, d, handleEvent);
 
2086
    (*d->handleEvent) (d, event);
 
2087
    WRAP (wd, d, handleEvent, wobblyHandleEvent);
 
2088
 
 
2089
    switch (event->type) {
 
2090
    case PropertyNotify:
 
2091
        if (event->xproperty.atom == d->winActiveAtom)
 
2092
        {
 
2093
            if (d->activeWindow != activeWindow)
 
2094
            {
 
2095
                CompWindow *w;
 
2096
 
 
2097
                w = findWindowAtDisplay (d, d->activeWindow);
 
2098
                if (w && isWobblyWin (w))
 
2099
                {
 
2100
                    WOBBLY_WINDOW (w);
 
2101
                    WOBBLY_SCREEN (w->screen);
 
2102
 
 
2103
                    if (ws->focusEffect && wobblyEnsureModel (w))
 
2104
                    {
 
2105
                        switch (ws->focusEffect) {
 
2106
                        case WobblyEffectShiver:
 
2107
                            modelAdjustObjectsForShiver (ww->model,
 
2108
                                                         WIN_X (w),
 
2109
                                                         WIN_Y (w),
 
2110
                                                         WIN_W (w),
 
2111
                                                         WIN_H (w));
 
2112
                        default:
 
2113
                            break;
 
2114
                        }
 
2115
 
 
2116
                        ww->wobbly |= WobblyInitial;
 
2117
                        ws->wobblyWindows |= ww->wobbly;
 
2118
                        damagePendingOnScreen (w->screen);
 
2119
                    }
 
2120
                }
 
2121
            }
 
2122
        }
 
2123
    default:
 
2124
        break;
 
2125
    }
 
2126
}
 
2127
 
 
2128
static Bool
 
2129
wobblyDamageWindowRect (CompWindow *w,
 
2130
                        Bool       initial,
 
2131
                        BoxPtr     rect)
 
2132
{
 
2133
    Bool status;
 
2134
 
 
2135
    WOBBLY_SCREEN (w->screen);
 
2136
 
 
2137
    if (!initial)
 
2138
    {
 
2139
        WOBBLY_WINDOW (w);
 
2140
 
 
2141
        if (ww->wobbly == WobblyForce)
 
2142
        {
 
2143
            REGION region;
 
2144
 
 
2145
            region.rects = &region.extents;
 
2146
            region.numRects = region.size = 1;
 
2147
 
 
2148
            region.extents.x1 = ww->model->topLeft.x;
 
2149
            region.extents.y1 = ww->model->topLeft.y;
 
2150
            region.extents.x2 = ww->model->bottomRight.x + 0.5f;
 
2151
            region.extents.y2 = ww->model->bottomRight.y + 0.5f;
 
2152
 
 
2153
            damageScreenRegion (w->screen, &region);
 
2154
 
 
2155
            return TRUE;
 
2156
        }
 
2157
    }
 
2158
 
 
2159
    UNWRAP (ws, w->screen, damageWindowRect);
 
2160
    status = (*w->screen->damageWindowRect) (w, initial, rect);
 
2161
    WRAP (ws, w->screen, damageWindowRect, wobblyDamageWindowRect);
 
2162
 
 
2163
    if (initial)
 
2164
    {
 
2165
        if (isWobblyWin (w) && (w->type & ~CompWindowTypeNormalMask))
 
2166
        {
 
2167
            WOBBLY_WINDOW (w);
 
2168
            WOBBLY_SCREEN (w->screen);
 
2169
 
 
2170
            if (ws->mapEffect && wobblyEnsureModel (w))
 
2171
            {
 
2172
                switch (ws->mapEffect) {
 
2173
                case WobblyEffectShiver:
 
2174
                    modelAdjustObjectsForShiver (ww->model,
 
2175
                                                 WIN_X (w), WIN_Y (w),
 
2176
                                                 WIN_W (w), WIN_H (w));
 
2177
                default:
 
2178
                    break;
 
2179
                }
 
2180
 
 
2181
                ww->wobbly |= WobblyInitial;
 
2182
                ws->wobblyWindows |= ww->wobbly;
 
2183
 
 
2184
                damagePendingOnScreen (w->screen);
 
2185
            }
 
2186
        }
 
2187
    }
 
2188
 
 
2189
    return status;
 
2190
}
 
2191
 
 
2192
static void
 
2193
wobblySetWindowScale (CompWindow *w,
 
2194
                      float      xScale,
 
2195
                      float      yScale)
 
2196
{
 
2197
    WOBBLY_WINDOW (w);
 
2198
    WOBBLY_SCREEN (w->screen);
 
2199
 
 
2200
    UNWRAP (ws, w->screen, setWindowScale);
 
2201
    (*w->screen->setWindowScale) (w, xScale, yScale);
 
2202
    WRAP (ws, w->screen, setWindowScale, wobblySetWindowScale);
 
2203
 
 
2204
    if (wobblyEnsureModel (w))
 
2205
    {
 
2206
        if (ww->model->scale.x != xScale ||
 
2207
            ww->model->scale.y != yScale)
 
2208
        {
 
2209
            ww->model->scale.x = xScale;
 
2210
            ww->model->scale.y = yScale;
 
2211
 
 
2212
            modelInitObjects (ww->model,
 
2213
                              WIN_X (w), WIN_Y (w),
 
2214
                              WIN_W (w), WIN_H (w));
 
2215
 
 
2216
            modelInitSprings (ww->model,
 
2217
                              WIN_X (w), WIN_Y (w),
 
2218
                              WIN_W (w), WIN_H (w));
 
2219
 
 
2220
            /*
 
2221
            ww->wobbly |= WobblyInitial;
 
2222
            ws->wobblyWindows |= ww->wobbly;
 
2223
            */
 
2224
        }
 
2225
 
 
2226
        if (ww->model->scale.x != 1.0f || ww->model->scale.y != 1.0f)
 
2227
            ww->model->transformed = 1;
 
2228
        else
 
2229
            ww->model->transformed = 0;
 
2230
    }
 
2231
}
 
2232
 
 
2233
static void
 
2234
wobblyWindowResizeNotify (CompWindow *w)
 
2235
{
 
2236
    WOBBLY_SCREEN (w->screen);
 
2237
    WOBBLY_WINDOW (w);
 
2238
 
 
2239
    if (ww->model)
 
2240
    {
 
2241
        modelInitObjects (ww->model,
 
2242
                          WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
 
2243
 
 
2244
        modelInitSprings (ww->model,
 
2245
                          WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
 
2246
    }
 
2247
 
 
2248
    UNWRAP (ws, w->screen, windowResizeNotify);
 
2249
    (*w->screen->windowResizeNotify) (w);
 
2250
    WRAP (ws, w->screen, windowResizeNotify, wobblyWindowResizeNotify);
 
2251
}
 
2252
 
 
2253
static void
 
2254
wobblyWindowMoveNotify (CompWindow *w,
 
2255
                        int        dx,
 
2256
                        int        dy)
 
2257
{
 
2258
    WOBBLY_SCREEN (w->screen);
 
2259
    WOBBLY_WINDOW (w);
 
2260
 
 
2261
    if (ww->model)
 
2262
    {
 
2263
        if (ww->grabbed)
 
2264
        {
 
2265
            ww->model->anchorObject->position.x += dx;
 
2266
            ww->model->anchorObject->position.y += dy;
 
2267
 
 
2268
            ww->wobbly |= WobblyInitial;
 
2269
            ws->wobblyWindows |= ww->wobbly;
 
2270
 
 
2271
            damagePendingOnScreen (w->screen);
 
2272
        }
 
2273
        else
 
2274
            modelMove (ww->model, dx, dy);
 
2275
    }
 
2276
 
 
2277
    UNWRAP (ws, w->screen, windowMoveNotify);
 
2278
    (*w->screen->windowMoveNotify) (w, dx, dy);
 
2279
    WRAP (ws, w->screen, windowMoveNotify, wobblyWindowMoveNotify);
 
2280
}
 
2281
 
 
2282
static void
 
2283
wobblyWindowGrabNotify (CompWindow   *w,
 
2284
                        int          x,
 
2285
                        int          y,
 
2286
                        unsigned int state,
 
2287
                        unsigned int mask)
 
2288
{
 
2289
    WOBBLY_SCREEN (w->screen);
 
2290
 
 
2291
    if ((mask & CompWindowGrabButtonMask)                    &&
 
2292
        ws->opt[WOBBLY_SCREEN_OPTION_WOBBLE_ON_MOVE].value.b &&
 
2293
        isWobblyWin (w))
 
2294
    {
 
2295
        WOBBLY_WINDOW (w);
 
2296
 
 
2297
        if (ww->model || wobblyEnsureModel (w))
 
2298
        {
 
2299
            Spring *s;
 
2300
            int    i;
 
2301
 
 
2302
            if (ww->model->anchorObject)
 
2303
                ww->model->anchorObject->immobile = FALSE;
 
2304
 
 
2305
            ww->model->anchorObject = modelFindNearestObject (ww->model, x, y);
 
2306
            ww->model->anchorObject->immobile = TRUE;
 
2307
 
 
2308
            ww->grabbed = TRUE;
 
2309
 
 
2310
            if (mask & CompWindowGrabMoveMask)
 
2311
            {
 
2312
                CompBinding *bind;
 
2313
 
 
2314
                bind = &ws->opt[WOBBLY_SCREEN_OPTION_SNAP].value.bind;
 
2315
 
 
2316
                modelDisableSnapping (w, ww->model);
 
2317
                if ((state & bind->u.key.modifiers) == bind->u.key.modifiers)
 
2318
                    modelUpdateSnapping (w, ww->model);
 
2319
            }
 
2320
 
 
2321
            if (ws->opt[WOBBLY_SCREEN_OPTION_WOBBLE_ON_GRAB].value.b)
 
2322
            {
 
2323
                for (i = 0; i < ww->model->numSprings; i++)
 
2324
                {
 
2325
                    s = &ww->model->springs[i];
 
2326
 
 
2327
                    if (s->a == ww->model->anchorObject)
 
2328
                    {
 
2329
                        s->b->velocity.x -= s->offset.x * 0.05f;
 
2330
                        s->b->velocity.y -= s->offset.y * 0.05f;
 
2331
                    }
 
2332
                    else if (s->b == ww->model->anchorObject)
 
2333
                    {
 
2334
                        s->a->velocity.x += s->offset.x * 0.05f;
 
2335
                        s->a->velocity.y += s->offset.y * 0.05f;
 
2336
                    }
 
2337
                }
 
2338
 
 
2339
                ww->wobbly |= WobblyInitial;
 
2340
                ws->wobblyWindows |= ww->wobbly;
 
2341
 
 
2342
                damagePendingOnScreen (w->screen);
 
2343
            }
 
2344
        }
 
2345
    }
 
2346
 
 
2347
    UNWRAP (ws, w->screen, windowGrabNotify);
 
2348
    (*w->screen->windowGrabNotify) (w, x, y, state, mask);
 
2349
    WRAP (ws, w->screen, windowGrabNotify, wobblyWindowGrabNotify);
 
2350
}
 
2351
 
 
2352
static void
 
2353
wobblyWindowUngrabNotify (CompWindow *w)
 
2354
{
 
2355
    WOBBLY_SCREEN (w->screen);
 
2356
    WOBBLY_WINDOW (w);
 
2357
 
 
2358
    if (ww->grabbed)
 
2359
    {
 
2360
        if (ww->model)
 
2361
        {
 
2362
            if (ww->model->anchorObject)
 
2363
                ww->model->anchorObject->immobile = FALSE;
 
2364
 
 
2365
            ww->model->anchorObject = NULL;
 
2366
 
 
2367
            ww->wobbly |= WobblyInitial;
 
2368
            ws->wobblyWindows |= ww->wobbly;
 
2369
 
 
2370
            damagePendingOnScreen (w->screen);
 
2371
        }
 
2372
 
 
2373
        ww->grabbed = FALSE;
 
2374
    }
 
2375
 
 
2376
    UNWRAP (ws, w->screen, windowUngrabNotify);
 
2377
    (*w->screen->windowUngrabNotify) (w);
 
2378
    WRAP (ws, w->screen, windowUngrabNotify, wobblyWindowUngrabNotify);
 
2379
}
 
2380
 
 
2381
 
 
2382
static Bool
 
2383
wobblyPaintScreen (CompScreen              *s,
 
2384
                   const ScreenPaintAttrib *sAttrib,
 
2385
                   Region                  region,
 
2386
                   unsigned int            mask)
 
2387
{
 
2388
    Bool status;
 
2389
 
 
2390
    WOBBLY_SCREEN (s);
 
2391
 
 
2392
    if (ws->wobblyWindows)
 
2393
        mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
 
2394
 
 
2395
    UNWRAP (ws, s, paintScreen);
 
2396
    status = (*s->paintScreen) (s, sAttrib, region, mask);
 
2397
    WRAP (ws, s, paintScreen, wobblyPaintScreen);
 
2398
 
 
2399
    return status;
 
2400
}
 
2401
 
 
2402
static Bool
 
2403
wobblyInitDisplay (CompPlugin  *p,
 
2404
                   CompDisplay *d)
 
2405
{
 
2406
    WobblyDisplay *wd;
 
2407
 
 
2408
    wd = malloc (sizeof (WobblyDisplay));
 
2409
    if (!wd)
 
2410
        return FALSE;
 
2411
 
 
2412
    wd->screenPrivateIndex = allocateScreenPrivateIndex (d);
 
2413
    if (wd->screenPrivateIndex < 0)
 
2414
    {
 
2415
        free (wd);
 
2416
        return FALSE;
 
2417
    }
 
2418
 
 
2419
    WRAP (wd, d, handleEvent, wobblyHandleEvent);
 
2420
 
 
2421
    d->privates[displayPrivateIndex].ptr = wd;
 
2422
 
 
2423
    return TRUE;
 
2424
}
 
2425
 
 
2426
static void
 
2427
wobblyFiniDisplay (CompPlugin  *p,
 
2428
                   CompDisplay *d)
 
2429
{
 
2430
    WOBBLY_DISPLAY (d);
 
2431
 
 
2432
    freeScreenPrivateIndex (d, wd->screenPrivateIndex);
 
2433
 
 
2434
    UNWRAP (wd, d, handleEvent);
 
2435
 
 
2436
    free (wd);
 
2437
}
 
2438
 
 
2439
static Bool
 
2440
wobblyInitScreen (CompPlugin *p,
 
2441
                  CompScreen *s)
 
2442
{
 
2443
    WobblyScreen *ws;
 
2444
 
 
2445
    WOBBLY_DISPLAY (s->display);
 
2446
 
 
2447
    ws = malloc (sizeof (WobblyScreen));
 
2448
    if (!ws)
 
2449
        return FALSE;
 
2450
 
 
2451
    ws->windowPrivateIndex = allocateWindowPrivateIndex (s);
 
2452
    if (ws->windowPrivateIndex < 0)
 
2453
    {
 
2454
        free (ws);
 
2455
        return FALSE;
 
2456
    }
 
2457
 
 
2458
    ws->wobblyWindows = FALSE;
 
2459
 
 
2460
    ws->mapEffect   = WobblyEffectShiver;
 
2461
    ws->focusEffect = WobblyEffectNone;
 
2462
 
 
2463
    wobblyScreenInitOptions (ws, s->display->display);
 
2464
 
 
2465
    WRAP (ws, s, preparePaintScreen, wobblyPreparePaintScreen);
 
2466
    WRAP (ws, s, donePaintScreen, wobblyDonePaintScreen);
 
2467
    WRAP (ws, s, paintScreen, wobblyPaintScreen);
 
2468
    WRAP (ws, s, paintWindow, wobblyPaintWindow);
 
2469
    WRAP (ws, s, damageWindowRect, wobblyDamageWindowRect);
 
2470
    WRAP (ws, s, addWindowGeometry, wobblyAddWindowGeometry);
 
2471
    WRAP (ws, s, drawWindowGeometry, wobblyDrawWindowGeometry);
 
2472
    WRAP (ws, s, setWindowScale, wobblySetWindowScale);
 
2473
    WRAP (ws, s, windowResizeNotify, wobblyWindowResizeNotify);
 
2474
    WRAP (ws, s, windowMoveNotify, wobblyWindowMoveNotify);
 
2475
    WRAP (ws, s, windowGrabNotify, wobblyWindowGrabNotify);
 
2476
    WRAP (ws, s, windowUngrabNotify, wobblyWindowUngrabNotify);
 
2477
 
 
2478
    s->privates[wd->screenPrivateIndex].ptr = ws;
 
2479
 
 
2480
    return TRUE;
 
2481
}
 
2482
 
 
2483
static void
 
2484
wobblyFiniScreen (CompPlugin *p,
 
2485
                  CompScreen *s)
 
2486
{
 
2487
    WOBBLY_SCREEN (s);
 
2488
 
 
2489
    freeWindowPrivateIndex (s, ws->windowPrivateIndex);
 
2490
 
 
2491
    free (ws->opt[WOBBLY_SCREEN_OPTION_MAP_EFFECT].value.s);
 
2492
    free (ws->opt[WOBBLY_SCREEN_OPTION_FOCUS_EFFECT].value.s);
 
2493
 
 
2494
    UNWRAP (ws, s, preparePaintScreen);
 
2495
    UNWRAP (ws, s, donePaintScreen);
 
2496
    UNWRAP (ws, s, paintScreen);
 
2497
    UNWRAP (ws, s, paintWindow);
 
2498
    UNWRAP (ws, s, damageWindowRect);
 
2499
    UNWRAP (ws, s, addWindowGeometry);
 
2500
    UNWRAP (ws, s, drawWindowGeometry);
 
2501
    UNWRAP (ws, s, setWindowScale);
 
2502
    UNWRAP (ws, s, windowResizeNotify);
 
2503
    UNWRAP (ws, s, windowMoveNotify);
 
2504
    UNWRAP (ws, s, windowGrabNotify);
 
2505
    UNWRAP (ws, s, windowUngrabNotify);
 
2506
 
 
2507
    free (ws);
 
2508
}
 
2509
 
 
2510
static Bool
 
2511
wobblyInitWindow (CompPlugin *p,
 
2512
                  CompWindow *w)
 
2513
{
 
2514
    WobblyWindow *ww;
 
2515
 
 
2516
    WOBBLY_SCREEN (w->screen);
 
2517
 
 
2518
    ww = malloc (sizeof (WobblyWindow));
 
2519
    if (!ww)
 
2520
        return FALSE;
 
2521
 
 
2522
    ww->model   = 0;
 
2523
    ww->wobbly  = 0;
 
2524
    ww->grabbed = FALSE;
 
2525
 
 
2526
    w->privates[ws->windowPrivateIndex].ptr = ww;
 
2527
 
 
2528
    return TRUE;
 
2529
}
 
2530
 
 
2531
static void
 
2532
wobblyFiniWindow (CompPlugin *p,
 
2533
                  CompWindow *w)
 
2534
{
 
2535
    WOBBLY_WINDOW (w);
 
2536
 
 
2537
    if (ww->model)
 
2538
    {
 
2539
        free (ww->model->objects);
 
2540
        free (ww->model);
 
2541
    }
 
2542
 
 
2543
    free (ww);
 
2544
}
 
2545
 
 
2546
static Bool
 
2547
wobblyInit (CompPlugin *p)
 
2548
{
 
2549
    displayPrivateIndex = allocateDisplayPrivateIndex ();
 
2550
    if (displayPrivateIndex < 0)
 
2551
        return FALSE;
 
2552
 
 
2553
    return TRUE;
 
2554
}
 
2555
 
 
2556
static void
 
2557
wobblyFini (CompPlugin *p)
 
2558
{
 
2559
    if (displayPrivateIndex >= 0)
 
2560
        freeDisplayPrivateIndex (displayPrivateIndex);
 
2561
}
 
2562
 
 
2563
CompPluginDep wobblyDeps[] = {
 
2564
    { CompPluginRuleBefore, "fade" },
 
2565
    { CompPluginRuleBefore, "cube" },
 
2566
    { CompPluginRuleBefore, "expose" }
 
2567
};
 
2568
 
 
2569
CompPluginVTable wobblyVTable = {
 
2570
    "wobbly",
 
2571
    "Wobbly Windows",
 
2572
    "Use spring model for wobbly window effect",
 
2573
    wobblyInit,
 
2574
    wobblyFini,
 
2575
    wobblyInitDisplay,
 
2576
    wobblyFiniDisplay,
 
2577
    wobblyInitScreen,
 
2578
    wobblyFiniScreen,
 
2579
    wobblyInitWindow,
 
2580
    wobblyFiniWindow,
 
2581
    0, /* GetDisplayOptions */
 
2582
    0, /* SetDisplayOption */
 
2583
    wobblyGetScreenOptions,
 
2584
    wobblySetScreenOption,
 
2585
    wobblyDeps,
 
2586
    sizeof (wobblyDeps) / sizeof (wobblyDeps[0])
 
2587
};
 
2588
 
 
2589
CompPluginVTable *
 
2590
getCompPluginInfo (void)
 
2591
{
 
2592
    return &wobblyVTable;
 
2593
}