2
* Copyright © 2005 Novell, Inc.
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
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.
23
* Author: David Reveman <davidr@novell.com>
27
* Spring model implemented by Kristian Hogsberg.
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)
44
#define MODEL_MAX_SPRINGS (GRID_WIDTH * GRID_HEIGHT * 2)
48
typedef struct _xy_pair {
52
#define NorthEdgeMask (1L << 0)
53
#define SouthEdgeMask (1L << 1)
54
#define WestEdgeMask (1L << 2)
55
#define EastEdgeMask (1L << 3)
57
#define EDGE_DISTANCE 25.0f
58
#define EDGE_VELOCITY 13.0f
60
typedef struct _Edge {
72
typedef struct _Object {
78
unsigned int edgeMask;
83
typedef struct _Spring {
94
typedef struct _Model {
97
Spring springs[MODEL_MAX_SPRINGS];
105
unsigned int edgeMask;
106
unsigned int snapCnt[4];
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
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
119
#define WOBBLY_GRID_RESOLUTION_DEFAULT 8
120
#define WOBBLY_GRID_RESOLUTION_MIN 1
121
#define WOBBLY_GRID_RESOLUTION_MAX 64
123
#define WOBBLY_MIN_GRID_SIZE_DEFAULT 8
124
#define WOBBLY_MIN_GRID_SIZE_MIN 4
125
#define WOBBLY_MIN_GRID_SIZE_MAX 128
127
#define WOBBLY_WOBBLE_ON_GRAB_DEFAULT FALSE
129
#define WOBBLY_WOBBLE_ON_MOVE_DEFAULT TRUE
131
#define WOBBLY_WOBBLE_ON_RESIZE_DEFAULT FALSE
134
WobblyEffectNone = 0,
138
static char *effectName[] = {
143
static WobblyEffect effectType[] = {
148
#define NUM_EFFECT (sizeof (effectType) / sizeof (effectType[0]))
150
#define WOBBLY_MAP_DEFAULT (effectName[0])
151
#define WOBBLY_FOCUS_DEFAULT (effectName[0])
153
static char *winType[] = {
162
#define N_WIN_TYPE (sizeof (winType) / sizeof (winType[0]))
164
#define WOBBLY_SNAP_KEY_DEFAULT "Control_L"
165
#define WOBBLY_SNAP_MODIFIERS_DEFAULT (CompPressMask | ControlMask)
167
static int displayPrivateIndex;
169
typedef struct _WobblyDisplay {
170
int screenPrivateIndex;
171
HandleEventProc handleEvent;
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
187
typedef struct _WobblyScreen {
188
int windowPrivateIndex;
190
PreparePaintScreenProc preparePaintScreen;
191
DonePaintScreenProc donePaintScreen;
192
PaintScreenProc paintScreen;
193
PaintWindowProc paintWindow;
194
DamageWindowRectProc damageWindowRect;
195
AddWindowGeometryProc addWindowGeometry;
196
DrawWindowGeometryProc drawWindowGeometry;
197
SetWindowScaleProc setWindowScale;
199
WindowResizeNotifyProc windowResizeNotify;
200
WindowMoveNotifyProc windowMoveNotify;
201
WindowGrabNotifyProc windowGrabNotify;
202
WindowUngrabNotifyProc windowUngrabNotify;
204
CompOption opt[WOBBLY_SCREEN_OPTION_NUM];
208
WobblyEffect mapEffect;
209
WobblyEffect focusEffect;
214
#define WobblyInitial (1L << 0)
215
#define WobblyForce (1L << 1)
216
#define WobblyVelocity (1L << 2)
218
typedef struct _WobblyWindow {
225
#define GET_WOBBLY_DISPLAY(d) \
226
((WobblyDisplay *) (d)->privates[displayPrivateIndex].ptr)
228
#define WOBBLY_DISPLAY(d) \
229
WobblyDisplay *wd = GET_WOBBLY_DISPLAY (d)
231
#define GET_WOBBLY_SCREEN(s, wd) \
232
((WobblyScreen *) (s)->privates[(wd)->screenPrivateIndex].ptr)
234
#define WOBBLY_SCREEN(s) \
235
WobblyScreen *ws = GET_WOBBLY_SCREEN (s, GET_WOBBLY_DISPLAY (s->display))
237
#define GET_WOBBLY_WINDOW(w, ws) \
238
((WobblyWindow *) (w)->privates[(ws)->windowPrivateIndex].ptr)
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)))
245
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
248
wobblyGetScreenOptions (CompScreen *screen,
251
WOBBLY_SCREEN (screen);
253
*count = NUM_OPTIONS (ws);
258
wobblySetScreenOption (CompScreen *screen,
260
CompOptionValue *value)
265
WOBBLY_SCREEN (screen);
267
o = compFindOption (ws->opt, NUM_OPTIONS (ws), name, &index);
272
case WOBBLY_SCREEN_OPTION_FRICTION:
273
case WOBBLY_SCREEN_OPTION_SPRING_K:
274
if (compSetFloatOption (o, value))
277
case WOBBLY_SCREEN_OPTION_GRID_RESOLUTION:
278
if (compSetIntOption (o, value))
281
case WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE:
282
if (compSetIntOption (o, value))
285
case WOBBLY_SCREEN_OPTION_MAP_EFFECT:
286
if (compSetStringOption (o, value))
290
for (i = 0; i < NUM_EFFECT; i++)
292
if (strcmp (o->value.s, effectName[i]) == 0)
294
ws->mapEffect = effectType[i];
300
case WOBBLY_SCREEN_OPTION_FOCUS_EFFECT:
301
if (compSetStringOption (o, value))
305
for (i = 0; i < NUM_EFFECT; i++)
307
if (strcmp (o->value.s, effectName[i]) == 0)
309
ws->focusEffect = effectType[i];
315
case WOBBLY_SCREEN_OPTION_WINDOW_TYPE:
316
if (compSetOptionList (o, value))
318
ws->wMask = compWindowTypeMaskFromStringList (&o->value);
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))
328
case WOBBLY_SCREEN_OPTION_SNAP:
329
if (value->bind.type == CompBindingTypeButton)
332
if (compSetBindingOption (o, value))
342
wobblyScreenInitOptions (WobblyScreen *ws,
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;
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;
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;
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;
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;
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;
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;
417
ws->wMask = compWindowTypeMaskFromStringList (&o->value);
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;
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;
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;
440
o = &ws->opt[WOBBLY_SCREEN_OPTION_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));
453
findNextWestEdge (CompWindow *w,
467
x = object->position.x + w->output.left - w->input.left;
469
if (x >= w->screen->workArea.x)
473
v1 = w->screen->workArea.x;
475
for (p = w->screen->windows; p; p = p->next)
477
if (p->invisible || w == p || p->type != CompWindowTypeNormalMask)
480
s = p->attrib.y - p->output.top;
481
e = p->attrib.y + p->height + p->output.bottom;
483
if (s > object->position.y)
488
else if (e < object->position.y)
501
v = p->attrib.x + p->width + p->input.right;
517
v2 = w->screen->workArea.x;
520
v1 = v1 - w->output.left + w->input.left;
521
v2 = v2 - w->output.left + w->input.left;
523
if (v1 != (int) object->vertEdge.next)
524
object->vertEdge.snapped = FALSE;
526
object->vertEdge.start = start;
527
object->vertEdge.end = end;
529
object->vertEdge.next = v1;
530
object->vertEdge.prev = v2;
532
object->vertEdge.attract = v1 + EDGE_DISTANCE;
533
object->vertEdge.velocity = EDGE_VELOCITY;
537
findNextEastEdge (CompWindow *w,
551
x = object->position.x - w->output.right + w->input.right;
553
if (x <= w->screen->workArea.x + w->screen->workArea.width)
557
v1 = w->screen->workArea.x + w->screen->workArea.width;
559
for (p = w->screen->windows; p; p = p->next)
561
if (p->invisible || w == p || p->type != CompWindowTypeNormalMask)
564
s = p->attrib.y - p->output.top;
565
e = p->attrib.y + p->height + p->output.bottom;
567
if (s > object->position.y)
572
else if (e < object->position.y)
585
v = p->attrib.x - p->input.left;
601
v2 = w->screen->workArea.x + w->screen->workArea.width;
604
v1 = v1 + w->output.right - w->input.right;
605
v2 = v2 + w->output.right - w->input.right;
607
if (v1 != (int) object->vertEdge.next)
608
object->vertEdge.snapped = FALSE;
610
object->vertEdge.start = start;
611
object->vertEdge.end = end;
613
object->vertEdge.next = v1;
614
object->vertEdge.prev = v2;
616
object->vertEdge.attract = v1 - EDGE_DISTANCE;
617
object->vertEdge.velocity = EDGE_VELOCITY;
621
findNextNorthEdge (CompWindow *w,
635
y = object->position.y + w->output.top - w->input.top;
637
if (y >= w->screen->workArea.y)
641
v1 = w->screen->workArea.y;
643
for (p = w->screen->windows; p; p = p->next)
645
if (p->invisible || w == p || p->type != CompWindowTypeNormalMask)
648
s = p->attrib.x - p->output.left;
649
e = p->attrib.x + p->width + p->output.right;
651
if (s > object->position.x)
656
else if (e < object->position.x)
669
v = p->attrib.y + p->height + p->input.bottom;
685
v2 = w->screen->workArea.y;
688
v1 = v1 - w->output.top + w->input.top;
689
v2 = v2 - w->output.top + w->input.top;
691
if (v1 != (int) object->horzEdge.next)
692
object->horzEdge.snapped = FALSE;
694
object->horzEdge.start = start;
695
object->horzEdge.end = end;
697
object->horzEdge.next = v1;
698
object->horzEdge.prev = v2;
700
object->horzEdge.attract = v1 + EDGE_DISTANCE;
701
object->horzEdge.velocity = EDGE_VELOCITY;
705
findNextSouthEdge (CompWindow *w,
719
y = object->position.y - w->output.bottom + w->input.bottom;
721
if (y <= w->screen->workArea.y + w->screen->workArea.height)
725
v1 = w->screen->workArea.y + w->screen->workArea.height;
727
for (p = w->screen->windows; p; p = p->next)
729
if (p->invisible || w == p || p->type != CompWindowTypeNormalMask)
732
s = p->attrib.x - p->output.left;
733
e = p->attrib.x + p->width + p->output.right;
735
if (s > object->position.x)
740
else if (e < object->position.x)
753
v = p->attrib.y - p->input.top;
769
v2 = w->screen->workArea.y + w->screen->workArea.height;
772
v1 = v1 + w->output.bottom - w->input.bottom;
773
v2 = v2 + w->output.bottom - w->input.bottom;
775
if (v1 != (int) object->horzEdge.next)
776
object->horzEdge.snapped = FALSE;
778
object->horzEdge.start = start;
779
object->horzEdge.end = end;
781
object->horzEdge.next = v1;
782
object->horzEdge.prev = v2;
784
object->horzEdge.attract = v1 - EDGE_DISTANCE;
785
object->horzEdge.velocity = EDGE_VELOCITY;
789
objectInit (Object *object,
798
object->position.x = positionX;
799
object->position.y = positionY;
801
object->velocity.x = velocityX;
802
object->velocity.y = velocityY;
805
object->immobile = FALSE;
807
object->edgeMask = 0;
809
object->vertEdge.snapped = FALSE;
810
object->horzEdge.snapped = FALSE;
812
object->vertEdge.next = 0.0f;
813
object->horzEdge.next = 0.0f;
817
springInit (Spring *spring,
825
spring->offset.x = offsetX;
826
spring->offset.y = offsetY;
830
modelCalcBounds (Model *model)
834
model->topLeft.x = MAXSHORT;
835
model->topLeft.y = MAXSHORT;
836
model->bottomRight.x = MINSHORT;
837
model->bottomRight.y = MINSHORT;
839
for (i = 0; i < model->numObjects; i++)
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;
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;
854
modelAddSpring (Model *model,
862
spring = &model->springs[model->numSprings];
865
springInit (spring, a, b, offsetX, offsetY);
869
modelSetMiddleAnchor (Model *model,
877
if (model->anchorObject)
878
model->anchorObject->immobile = FALSE;
880
w = (float) width * model->scale.x;
881
h = (float) height * model->scale.y;
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);
891
model->anchorObject->immobile = TRUE;
895
modelInitObjects (Model *model,
901
int gridX, gridY, i = 0;
904
w = (float) width * model->scale.x;
905
h = (float) height * model->scale.y;
907
for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
909
for (gridX = 0; gridX < GRID_WIDTH; gridX++)
911
objectInit (&model->objects[i],
912
x + (gridX * w) / (float) (GRID_WIDTH - 1),
913
y + (gridY * h) / (float) (GRID_HEIGHT - 1),
919
modelSetMiddleAnchor (model, x, y, width, height);
923
modelUpdateSnapping (CompWindow *window,
926
unsigned int edgeMask, gridMask, mask;
927
int gridX, gridY, i = 0;
929
edgeMask = model->edgeMask;
931
if (model->snapCnt[NORTH])
932
edgeMask &= ~SouthEdgeMask;
933
else if (model->snapCnt[SOUTH])
934
edgeMask &= ~NorthEdgeMask;
936
if (model->snapCnt[WEST])
937
edgeMask &= ~EastEdgeMask;
938
else if (model->snapCnt[EAST])
939
edgeMask &= ~WestEdgeMask;
941
for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
944
gridMask = edgeMask & NorthEdgeMask;
945
else if (gridY == GRID_HEIGHT - 1)
946
gridMask = edgeMask & SouthEdgeMask;
950
for (gridX = 0; gridX < GRID_WIDTH; gridX++)
955
mask |= edgeMask & WestEdgeMask;
956
else if (gridX == GRID_WIDTH - 1)
957
mask |= edgeMask & EastEdgeMask;
959
if (mask != model->objects[i].edgeMask)
961
model->objects[i].edgeMask = mask;
963
if (mask & WestEdgeMask)
965
if (!model->objects[i].vertEdge.snapped)
966
findNextWestEdge (window, &model->objects[i]);
968
else if (mask & EastEdgeMask)
970
if (!model->objects[i].vertEdge.snapped)
971
findNextEastEdge (window, &model->objects[i]);
974
model->objects[i].vertEdge.snapped = FALSE;
976
if (mask & NorthEdgeMask)
978
if (!model->objects[i].horzEdge.snapped)
979
findNextNorthEdge (window, &model->objects[i]);
981
else if (mask & SouthEdgeMask)
983
if (!model->objects[i].horzEdge.snapped)
984
findNextSouthEdge (window, &model->objects[i]);
987
model->objects[i].horzEdge.snapped = FALSE;
996
modelReduceEdgeEscapeVelocity (Model *model)
998
int gridX, gridY, i = 0;
1000
for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
1002
for (gridX = 0; gridX < GRID_WIDTH; gridX++)
1004
if (model->objects[i].vertEdge.snapped)
1005
model->objects[i].vertEdge.velocity *= drand48 () * 0.25f;
1007
if (model->objects[i].horzEdge.snapped)
1008
model->objects[i].horzEdge.velocity *= drand48 () * 0.25f;
1016
modelDisableSnapping (CompWindow *window,
1019
int gridX, gridY, i = 0;
1020
Bool snapped = FALSE;
1022
for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
1024
for (gridX = 0; gridX < GRID_WIDTH; gridX++)
1026
if (model->objects[i].vertEdge.snapped ||
1027
model->objects[i].horzEdge.snapped)
1030
model->objects[i].vertEdge.snapped = FALSE;
1031
model->objects[i].horzEdge.snapped = FALSE;
1033
model->objects[i].edgeMask = 0;
1039
memset (model->snapCnt, 0, sizeof (model->snapCnt));
1045
modelAdjustObjectsForShiver (Model *model,
1051
int gridX, gridY, i = 0;
1056
w = (float) width * model->scale.x;
1057
h = (float) height * model->scale.y;
1059
for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
1061
for (gridX = 0; gridX < GRID_WIDTH; gridX++)
1063
if (!model->objects[i].immobile)
1065
vX = model->objects[i].position.x - (x + w / 2);
1066
vY = model->objects[i].position.y - (y + h / 2);
1071
scale = ((float) rand () * 7.5f) / RAND_MAX;
1073
model->objects[i].velocity.x += vX * scale;
1074
model->objects[i].velocity.y += vY * scale;
1083
modelInitSprings (Model *model,
1089
int gridX, gridY, i = 0;
1090
float hp, hpad, vpad;
1093
model->numSprings = 0;
1095
w = (float) width * model->scale.x;
1096
h = (float) height * model->scale.y;
1098
hpad = w / (GRID_WIDTH - 1);
1099
vpad = h / (GRID_HEIGHT - 1);
1101
for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
1105
for (gridX = 0; gridX < GRID_WIDTH; gridX++)
1108
modelAddSpring (model,
1109
&model->objects[i - 1],
1114
modelAddSpring (model,
1115
&model->objects[i - GRID_WIDTH],
1125
modelMove (Model *model,
1131
for (i = 0; i < model->numObjects; i++)
1133
model->objects[i].position.x += tx;
1134
model->objects[i].position.y += ty;
1143
unsigned int edgeMask)
1147
model = malloc (sizeof (Model));
1151
model->numObjects = GRID_WIDTH * GRID_HEIGHT;
1152
model->objects = malloc (sizeof (Object) * model->numObjects);
1153
if (!model->objects)
1156
model->anchorObject = 0;
1157
model->numSprings = 0;
1161
model->scale.x = 1.0f;
1162
model->scale.y = 1.0f;
1164
model->transformed = FALSE;
1166
memset (model->snapCnt, 0, sizeof (model->snapCnt));
1168
model->edgeMask = edgeMask;
1170
modelInitObjects (model, x, y, width, height);
1171
modelInitSprings (model, x, y, width, height);
1173
modelCalcBounds (model);
1179
objectApplyForce (Object *object,
1183
object->force.x += fx;
1184
object->force.y += fy;
1188
springExertForces (Spring *spring,
1194
a = spring->a->position;
1195
b = spring->b->position;
1197
da.x = 0.5f * (b.x - a.x - spring->offset.x);
1198
da.y = 0.5f * (b.y - a.y - spring->offset.y);
1200
db.x = 0.5f * (a.x - b.x + spring->offset.x);
1201
db.y = 0.5f * (a.y - b.y + spring->offset.y);
1203
objectApplyForce (spring->a, k * da.x, k * da.y);
1204
objectApplyForce (spring->b, k * db.x, k * db.y);
1208
objectReleaseWestEdge (CompWindow *w,
1212
if (fabs (object->velocity.x) > object->vertEdge.velocity)
1214
object->position.x += object->velocity.x * 2.0f;
1216
model->snapCnt[WEST]--;
1218
object->vertEdge.snapped = FALSE;
1219
object->edgeMask = 0;
1221
modelUpdateSnapping (w, model);
1226
object->velocity.x = 0.0f;
1232
objectReleaseEastEdge (CompWindow *w,
1236
if (fabs (object->velocity.x) > object->vertEdge.velocity)
1238
object->position.x += object->velocity.x * 2.0f;
1240
model->snapCnt[EAST]--;
1242
object->vertEdge.snapped = FALSE;
1243
object->edgeMask = 0;
1245
modelUpdateSnapping (w, model);
1250
object->velocity.x = 0.0f;
1256
objectReleaseNorthEdge (CompWindow *w,
1260
if (fabs (object->velocity.y) > object->horzEdge.velocity)
1262
object->position.y += object->velocity.y * 2.0f;
1264
model->snapCnt[NORTH]--;
1266
object->horzEdge.snapped = FALSE;
1267
object->edgeMask = 0;
1269
modelUpdateSnapping (w, model);
1274
object->velocity.y = 0.0f;
1280
objectReleaseSouthEdge (CompWindow *w,
1284
if (fabs (object->velocity.y) > object->horzEdge.velocity)
1286
object->position.y += object->velocity.y * 2.0f;
1288
model->snapCnt[SOUTH]--;
1290
object->horzEdge.snapped = FALSE;
1291
object->edgeMask = 0;
1293
modelUpdateSnapping (w, model);
1298
object->velocity.y = 0.0f;
1304
modelStepObject (CompWindow *window,
1310
object->theta += 0.05f;
1312
if (object->immobile)
1314
object->velocity.x = 0.0f;
1315
object->velocity.y = 0.0f;
1317
object->force.x = 0.0f;
1318
object->force.y = 0.0f;
1326
object->force.x -= friction * object->velocity.x;
1327
object->force.y -= friction * object->velocity.y;
1329
object->velocity.x += object->force.x / MASS;
1330
object->velocity.y += object->force.y / MASS;
1332
if (object->edgeMask)
1334
if (object->edgeMask & WestEdgeMask)
1336
if (object->position.y < object->vertEdge.start ||
1337
object->position.y > object->vertEdge.end)
1338
findNextWestEdge (window, object);
1340
if (object->vertEdge.snapped == FALSE ||
1341
objectReleaseWestEdge (window, model, object))
1343
object->position.x += object->velocity.x;
1345
if (object->velocity.x < 0.0f &&
1346
object->position.x < object->vertEdge.attract)
1348
if (object->position.x < object->vertEdge.next)
1350
object->vertEdge.snapped = TRUE;
1351
object->position.x = object->vertEdge.next;
1352
object->velocity.x = 0.0f;
1354
model->snapCnt[WEST]++;
1356
modelUpdateSnapping (window, model);
1360
object->velocity.x -=
1361
object->vertEdge.attract - object->position.x;
1365
if (object->position.x > object->vertEdge.prev)
1366
findNextWestEdge (window, object);
1369
else if (object->edgeMask & EastEdgeMask)
1371
if (object->position.y < object->vertEdge.start ||
1372
object->position.y > object->vertEdge.end)
1373
findNextEastEdge (window, object);
1375
if (object->vertEdge.snapped == FALSE ||
1376
objectReleaseEastEdge (window, model, object))
1378
object->position.x += object->velocity.x;
1380
if (object->velocity.x > 0.0f &&
1381
object->position.x > object->vertEdge.attract)
1383
if (object->position.x > object->vertEdge.next)
1385
object->vertEdge.snapped = TRUE;
1386
object->position.x = object->vertEdge.next;
1387
object->velocity.x = 0.0f;
1389
model->snapCnt[EAST]++;
1391
modelUpdateSnapping (window, model);
1395
object->velocity.x =
1396
object->position.x - object->vertEdge.attract;
1400
if (object->position.x < object->vertEdge.prev)
1401
findNextEastEdge (window, object);
1405
object->position.x += object->velocity.x;
1407
if (object->edgeMask & NorthEdgeMask)
1409
if (object->position.x < object->horzEdge.start ||
1410
object->position.x > object->horzEdge.end)
1411
findNextNorthEdge (window, object);
1413
if (object->horzEdge.snapped == FALSE ||
1414
objectReleaseNorthEdge (window, model, object))
1416
object->position.y += object->velocity.y;
1418
if (object->velocity.y < 0.0f &&
1419
object->position.y < object->horzEdge.attract)
1421
if (object->position.y < object->horzEdge.next)
1423
object->horzEdge.snapped = TRUE;
1424
object->position.y = object->horzEdge.next;
1425
object->velocity.y = 0.0f;
1427
model->snapCnt[NORTH]++;
1429
modelUpdateSnapping (window, model);
1433
object->velocity.y -=
1434
object->horzEdge.attract - object->position.y;
1438
if (object->position.y > object->horzEdge.prev)
1439
findNextNorthEdge (window, object);
1442
else if (object->edgeMask & SouthEdgeMask)
1444
if (object->position.x < object->horzEdge.start ||
1445
object->position.x > object->horzEdge.end)
1446
findNextSouthEdge (window, object);
1448
if (object->horzEdge.snapped == FALSE ||
1449
objectReleaseSouthEdge (window, model, object))
1451
object->position.y += object->velocity.y;
1453
if (object->velocity.y > 0.0f &&
1454
object->position.y > object->horzEdge.attract)
1456
if (object->position.y > object->horzEdge.next)
1458
object->horzEdge.snapped = TRUE;
1459
object->position.y = object->horzEdge.next;
1460
object->velocity.y = 0.0f;
1462
model->snapCnt[SOUTH]++;
1464
modelUpdateSnapping (window, model);
1468
object->velocity.y =
1469
object->position.y - object->horzEdge.attract;
1473
if (object->position.y < object->horzEdge.prev)
1474
findNextSouthEdge (window, object);
1478
object->position.y += object->velocity.y;
1482
object->position.x += object->velocity.x;
1483
object->position.y += object->velocity.y;
1486
*force = fabs (object->force.x) + fabs (object->force.y);
1488
object->force.x = 0.0f;
1489
object->force.y = 0.0f;
1491
return fabs (object->velocity.x) + fabs (object->velocity.y);
1496
modelStep (CompWindow *window,
1502
int i, j, steps, wobbly = 0;
1503
float velocitySum = 0.0f;
1504
float force, forceSum = 0.0f;
1506
model->steps += time / 15.0f;
1507
steps = floor (model->steps);
1508
model->steps -= steps;
1513
for (j = 0; j < steps; j++)
1515
for (i = 0; i < model->numSprings; i++)
1516
springExertForces (&model->springs[i], k);
1518
for (i = 0; i < model->numObjects; i++)
1520
velocitySum += modelStepObject (window,
1529
modelCalcBounds (model);
1531
if (velocitySum > 0.5f)
1532
wobbly |= WobblyVelocity;
1534
if (forceSum > 20.0f)
1535
wobbly |= WobblyForce;
1541
bezierPatchEvaluate (Model *model,
1547
float coeffsU[4], coeffsV[4];
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;
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;
1563
for (i = 0; i < 4; i++)
1565
for (j = 0; j < 4; j++)
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;
1579
wobblyEnsureModel (CompWindow *w)
1585
unsigned int edgeMask = 0;
1587
if (w->type & CompWindowTypeNormalMask)
1588
edgeMask = WestEdgeMask | EastEdgeMask | NorthEdgeMask |
1591
ww->model = createModel (WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w),
1601
objectDistance (Object *object,
1607
dx = object->position.x - x;
1608
dy = object->position.y - y;
1610
return sqrt (dx * dx + dy * dy);
1614
modelFindNearestObject (Model *model,
1618
Object *object = &model->objects[0];
1619
float distance, minDistance = 0.0;
1622
for (i = 0; i < model->numObjects; i++)
1624
distance = objectDistance (&model->objects[i], x, y);
1625
if (i == 0 || distance < minDistance)
1627
minDistance = distance;
1628
object = &model->objects[i];
1636
isWobblyWin (CompWindow *w)
1638
WOBBLY_SCREEN (w->screen);
1644
if (!(ws->wMask & w->type))
1647
/* avoid tiny windows */
1648
if (w->width == 1 && w->height == 1)
1651
/* avoid fullscreen windows */
1652
if (w->attrib.x <= 0 &&
1654
w->attrib.x + w->width >= w->screen->width &&
1655
w->attrib.y + w->height >= w->screen->height)
1662
wobblyPreparePaintScreen (CompScreen *s,
1663
int msSinceLastPaint)
1670
if (ws->wobblyWindows & (WobblyInitial | WobblyVelocity))
1673
Point topLeft, bottomRight;
1674
float friction, springK;
1677
friction = ws->opt[WOBBLY_SCREEN_OPTION_FRICTION].value.f;
1678
springK = ws->opt[WOBBLY_SCREEN_OPTION_SPRING_K].value.f;
1680
region.rects = ®ion.extents;
1681
region.numRects = region.size = 1;
1683
ws->wobblyWindows = 0;
1684
for (w = s->windows; w; w = w->next)
1686
ww = GET_WOBBLY_WINDOW (w, ws);
1690
if (ww->wobbly & (WobblyInitial | WobblyVelocity))
1694
topLeft = model->topLeft;
1695
bottomRight = model->bottomRight;
1697
ww->wobbly = modelStep (w, model, friction, springK,
1698
(ww->wobbly & WobblyVelocity) ?
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)
1708
modelReduceEdgeEscapeVelocity (ww->model);
1709
ww->wobbly |= WobblyInitial;
1717
model->topLeft.x + w->output.left -
1719
model->topLeft.y + w->output.top -
1725
syncWindowPosition (w);
1728
if (!(s->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK))
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;
1742
addWindowDamage (w);
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;
1749
damageScreenRegion (s, ®ion);
1753
ws->wobblyWindows |= ww->wobbly;
1758
UNWRAP (ws, s, preparePaintScreen);
1759
(*s->preparePaintScreen) (s, msSinceLastPaint);
1760
WRAP (ws, s, preparePaintScreen, wobblyPreparePaintScreen);
1764
wobblyDonePaintScreen (CompScreen *s)
1768
if (ws->wobblyWindows & WobblyVelocity)
1769
damagePendingOnScreen (s);
1771
UNWRAP (ws, s, donePaintScreen);
1772
(*s->donePaintScreen) (s);
1773
WRAP (ws, s, donePaintScreen, wobblyDonePaintScreen);
1777
wobblyAddWindowGeometry (CompWindow *w,
1784
WOBBLY_SCREEN (w->screen);
1789
int nClip, nVertices, nIndices;
1793
float width, height;
1794
float deformedX, deformedY;
1795
int x, y, iw, ih, wx, wy;
1800
for (it = 0; it < nMatrix; it++)
1802
if (matrix[it].xy != 0.0f && matrix[it].yx != 0.0f)
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;
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;
1822
nClip = region->numRects;
1823
pClip = region->rects;
1825
w->texUnits = nMatrix;
1827
vSize = 2 + nMatrix * 2;
1829
nVertices = w->vCount;
1830
nIndices = w->vCount;
1832
v = w->vertices + (nVertices * vSize);
1833
i = w->indices + nIndices;
1842
iw = ((x2 - x1 - 1) / gridW) + 1;
1843
ih = ((y2 - y1 - 1) / gridH) + 1;
1845
if (nIndices + (iw * ih * 4) > w->indexSize)
1847
if (!moreWindowIndices (w, nIndices + (iw * ih * 4)))
1850
i = w->indices + nIndices;
1856
for (y = 0; y < ih - 1; y++)
1858
for (x = 0; x < iw - 1; x++)
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;
1869
if (((nVertices + iw * ih) * vSize) > w->vertexSize)
1871
if (!moreWindowVertices (w, (nVertices + iw * ih) * vSize))
1874
v = w->vertices + (nVertices * vSize);
1877
for (y = y1;; y += gridH)
1882
for (x = x1;; x += gridW)
1887
bezierPatchEvaluate (ww->model,
1895
for (it = 0; it < nMatrix; it++)
1897
*v++ = COMP_TEX_COORD_X (&matrix[it], x);
1898
*v++ = COMP_TEX_COORD_Y (&matrix[it], y);
1903
for (it = 0; it < nMatrix; it++)
1905
*v++ = COMP_TEX_COORD_XY (&matrix[it], x, y);
1906
*v++ = COMP_TEX_COORD_YX (&matrix[it], x, y);
1926
w->vCount = nIndices;
1930
UNWRAP (ws, w->screen, addWindowGeometry);
1931
(*w->screen->addWindowGeometry) (w, matrix, nMatrix, region, clip);
1932
WRAP (ws, w->screen, addWindowGeometry, wobblyAddWindowGeometry);
1937
wobblyDrawWindowGeometry (CompWindow *w)
1943
int texUnit = w->texUnits;
1944
int currentTexUnit = 0;
1945
int stride = (1 + texUnit) * 2;
1946
GLfloat *vertices = w->vertices + (stride - 2);
1948
stride *= sizeof (GLfloat);
1950
glVertexPointer (2, GL_FLOAT, stride, vertices);
1954
if (texUnit != currentTexUnit)
1956
w->screen->clientActiveTexture (GL_TEXTURE0_ARB + texUnit);
1957
currentTexUnit = texUnit;
1960
glTexCoordPointer (2, GL_FLOAT, stride, vertices);
1963
glDrawElements (GL_QUADS, w->vCount, GL_UNSIGNED_SHORT, w->indices);
1967
WOBBLY_SCREEN (w->screen);
1969
UNWRAP (ws, w->screen, drawWindowGeometry);
1970
(*w->screen->drawWindowGeometry) (w);
1971
WRAP (ws, w->screen, drawWindowGeometry, wobblyDrawWindowGeometry);
1976
wobblyPaintWindow (CompWindow *w,
1977
const WindowPaintAttrib *attrib,
1983
WOBBLY_SCREEN (w->screen);
1988
if (mask & PAINT_WINDOW_SOLID_MASK)
1991
mask |= PAINT_WINDOW_TRANSFORMED_MASK;
1994
UNWRAP (ws, w->screen, paintWindow);
1995
status = (*w->screen->paintWindow) (w, attrib, region, mask);
1996
WRAP (ws, w->screen, paintWindow, wobblyPaintWindow);
2002
wobblyHandleEvent (CompDisplay *d,
2005
Window activeWindow = 0;
2011
switch (event->type) {
2012
case PropertyNotify:
2013
if (event->xproperty.atom == d->winActiveAtom)
2014
activeWindow = d->activeWindow;
2017
w = findWindowAtDisplay (d, event->xunmap.window);
2024
modelInitObjects (ww->model,
2025
WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
2027
modelInitSprings (ww->model,
2028
WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
2033
s = findScreenAtDisplay (d, event->xkey.root);
2038
#define EV_SNAP_KEY(opt, event) \
2039
((opt)->value.bind.type == CompBindingTypeKey && \
2040
(opt)->value.bind.u.key.keycode == (event)->xkey.keycode)
2042
if (EV_SNAP_KEY (&ws->opt[WOBBLY_SCREEN_OPTION_SNAP], event))
2044
for (w = s->windows; w; w = w->next)
2048
if (ww->grabbed && ww->model)
2049
modelUpdateSnapping (w, ww->model);
2055
s = findScreenAtDisplay (d, event->xkey.root);
2060
if (EV_SNAP_KEY (&ws->opt[WOBBLY_SCREEN_OPTION_SNAP], event))
2064
for (w = s->windows; w; w = w->next)
2068
if (ww->grabbed && ww->model)
2070
if (modelDisableSnapping (w, ww->model))
2072
ww->wobbly |= WobblyInitial;
2073
ws->wobblyWindows |= ww->wobbly;
2075
damagePendingOnScreen (w->screen);
2085
UNWRAP (wd, d, handleEvent);
2086
(*d->handleEvent) (d, event);
2087
WRAP (wd, d, handleEvent, wobblyHandleEvent);
2089
switch (event->type) {
2090
case PropertyNotify:
2091
if (event->xproperty.atom == d->winActiveAtom)
2093
if (d->activeWindow != activeWindow)
2097
w = findWindowAtDisplay (d, d->activeWindow);
2098
if (w && isWobblyWin (w))
2101
WOBBLY_SCREEN (w->screen);
2103
if (ws->focusEffect && wobblyEnsureModel (w))
2105
switch (ws->focusEffect) {
2106
case WobblyEffectShiver:
2107
modelAdjustObjectsForShiver (ww->model,
2116
ww->wobbly |= WobblyInitial;
2117
ws->wobblyWindows |= ww->wobbly;
2118
damagePendingOnScreen (w->screen);
2129
wobblyDamageWindowRect (CompWindow *w,
2135
WOBBLY_SCREEN (w->screen);
2141
if (ww->wobbly == WobblyForce)
2145
region.rects = ®ion.extents;
2146
region.numRects = region.size = 1;
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;
2153
damageScreenRegion (w->screen, ®ion);
2159
UNWRAP (ws, w->screen, damageWindowRect);
2160
status = (*w->screen->damageWindowRect) (w, initial, rect);
2161
WRAP (ws, w->screen, damageWindowRect, wobblyDamageWindowRect);
2165
if (isWobblyWin (w) && (w->type & ~CompWindowTypeNormalMask))
2168
WOBBLY_SCREEN (w->screen);
2170
if (ws->mapEffect && wobblyEnsureModel (w))
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));
2181
ww->wobbly |= WobblyInitial;
2182
ws->wobblyWindows |= ww->wobbly;
2184
damagePendingOnScreen (w->screen);
2193
wobblySetWindowScale (CompWindow *w,
2198
WOBBLY_SCREEN (w->screen);
2200
UNWRAP (ws, w->screen, setWindowScale);
2201
(*w->screen->setWindowScale) (w, xScale, yScale);
2202
WRAP (ws, w->screen, setWindowScale, wobblySetWindowScale);
2204
if (wobblyEnsureModel (w))
2206
if (ww->model->scale.x != xScale ||
2207
ww->model->scale.y != yScale)
2209
ww->model->scale.x = xScale;
2210
ww->model->scale.y = yScale;
2212
modelInitObjects (ww->model,
2213
WIN_X (w), WIN_Y (w),
2214
WIN_W (w), WIN_H (w));
2216
modelInitSprings (ww->model,
2217
WIN_X (w), WIN_Y (w),
2218
WIN_W (w), WIN_H (w));
2221
ww->wobbly |= WobblyInitial;
2222
ws->wobblyWindows |= ww->wobbly;
2226
if (ww->model->scale.x != 1.0f || ww->model->scale.y != 1.0f)
2227
ww->model->transformed = 1;
2229
ww->model->transformed = 0;
2234
wobblyWindowResizeNotify (CompWindow *w)
2236
WOBBLY_SCREEN (w->screen);
2241
modelInitObjects (ww->model,
2242
WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
2244
modelInitSprings (ww->model,
2245
WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
2248
UNWRAP (ws, w->screen, windowResizeNotify);
2249
(*w->screen->windowResizeNotify) (w);
2250
WRAP (ws, w->screen, windowResizeNotify, wobblyWindowResizeNotify);
2254
wobblyWindowMoveNotify (CompWindow *w,
2258
WOBBLY_SCREEN (w->screen);
2265
ww->model->anchorObject->position.x += dx;
2266
ww->model->anchorObject->position.y += dy;
2268
ww->wobbly |= WobblyInitial;
2269
ws->wobblyWindows |= ww->wobbly;
2271
damagePendingOnScreen (w->screen);
2274
modelMove (ww->model, dx, dy);
2277
UNWRAP (ws, w->screen, windowMoveNotify);
2278
(*w->screen->windowMoveNotify) (w, dx, dy);
2279
WRAP (ws, w->screen, windowMoveNotify, wobblyWindowMoveNotify);
2283
wobblyWindowGrabNotify (CompWindow *w,
2289
WOBBLY_SCREEN (w->screen);
2291
if ((mask & CompWindowGrabButtonMask) &&
2292
ws->opt[WOBBLY_SCREEN_OPTION_WOBBLE_ON_MOVE].value.b &&
2297
if (ww->model || wobblyEnsureModel (w))
2302
if (ww->model->anchorObject)
2303
ww->model->anchorObject->immobile = FALSE;
2305
ww->model->anchorObject = modelFindNearestObject (ww->model, x, y);
2306
ww->model->anchorObject->immobile = TRUE;
2310
if (mask & CompWindowGrabMoveMask)
2314
bind = &ws->opt[WOBBLY_SCREEN_OPTION_SNAP].value.bind;
2316
modelDisableSnapping (w, ww->model);
2317
if ((state & bind->u.key.modifiers) == bind->u.key.modifiers)
2318
modelUpdateSnapping (w, ww->model);
2321
if (ws->opt[WOBBLY_SCREEN_OPTION_WOBBLE_ON_GRAB].value.b)
2323
for (i = 0; i < ww->model->numSprings; i++)
2325
s = &ww->model->springs[i];
2327
if (s->a == ww->model->anchorObject)
2329
s->b->velocity.x -= s->offset.x * 0.05f;
2330
s->b->velocity.y -= s->offset.y * 0.05f;
2332
else if (s->b == ww->model->anchorObject)
2334
s->a->velocity.x += s->offset.x * 0.05f;
2335
s->a->velocity.y += s->offset.y * 0.05f;
2339
ww->wobbly |= WobblyInitial;
2340
ws->wobblyWindows |= ww->wobbly;
2342
damagePendingOnScreen (w->screen);
2347
UNWRAP (ws, w->screen, windowGrabNotify);
2348
(*w->screen->windowGrabNotify) (w, x, y, state, mask);
2349
WRAP (ws, w->screen, windowGrabNotify, wobblyWindowGrabNotify);
2353
wobblyWindowUngrabNotify (CompWindow *w)
2355
WOBBLY_SCREEN (w->screen);
2362
if (ww->model->anchorObject)
2363
ww->model->anchorObject->immobile = FALSE;
2365
ww->model->anchorObject = NULL;
2367
ww->wobbly |= WobblyInitial;
2368
ws->wobblyWindows |= ww->wobbly;
2370
damagePendingOnScreen (w->screen);
2373
ww->grabbed = FALSE;
2376
UNWRAP (ws, w->screen, windowUngrabNotify);
2377
(*w->screen->windowUngrabNotify) (w);
2378
WRAP (ws, w->screen, windowUngrabNotify, wobblyWindowUngrabNotify);
2383
wobblyPaintScreen (CompScreen *s,
2384
const ScreenPaintAttrib *sAttrib,
2392
if (ws->wobblyWindows)
2393
mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
2395
UNWRAP (ws, s, paintScreen);
2396
status = (*s->paintScreen) (s, sAttrib, region, mask);
2397
WRAP (ws, s, paintScreen, wobblyPaintScreen);
2403
wobblyInitDisplay (CompPlugin *p,
2408
wd = malloc (sizeof (WobblyDisplay));
2412
wd->screenPrivateIndex = allocateScreenPrivateIndex (d);
2413
if (wd->screenPrivateIndex < 0)
2419
WRAP (wd, d, handleEvent, wobblyHandleEvent);
2421
d->privates[displayPrivateIndex].ptr = wd;
2427
wobblyFiniDisplay (CompPlugin *p,
2432
freeScreenPrivateIndex (d, wd->screenPrivateIndex);
2434
UNWRAP (wd, d, handleEvent);
2440
wobblyInitScreen (CompPlugin *p,
2445
WOBBLY_DISPLAY (s->display);
2447
ws = malloc (sizeof (WobblyScreen));
2451
ws->windowPrivateIndex = allocateWindowPrivateIndex (s);
2452
if (ws->windowPrivateIndex < 0)
2458
ws->wobblyWindows = FALSE;
2460
ws->mapEffect = WobblyEffectShiver;
2461
ws->focusEffect = WobblyEffectNone;
2463
wobblyScreenInitOptions (ws, s->display->display);
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);
2478
s->privates[wd->screenPrivateIndex].ptr = ws;
2484
wobblyFiniScreen (CompPlugin *p,
2489
freeWindowPrivateIndex (s, ws->windowPrivateIndex);
2491
free (ws->opt[WOBBLY_SCREEN_OPTION_MAP_EFFECT].value.s);
2492
free (ws->opt[WOBBLY_SCREEN_OPTION_FOCUS_EFFECT].value.s);
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);
2511
wobblyInitWindow (CompPlugin *p,
2516
WOBBLY_SCREEN (w->screen);
2518
ww = malloc (sizeof (WobblyWindow));
2524
ww->grabbed = FALSE;
2526
w->privates[ws->windowPrivateIndex].ptr = ww;
2532
wobblyFiniWindow (CompPlugin *p,
2539
free (ww->model->objects);
2547
wobblyInit (CompPlugin *p)
2549
displayPrivateIndex = allocateDisplayPrivateIndex ();
2550
if (displayPrivateIndex < 0)
2557
wobblyFini (CompPlugin *p)
2559
if (displayPrivateIndex >= 0)
2560
freeDisplayPrivateIndex (displayPrivateIndex);
2563
CompPluginDep wobblyDeps[] = {
2564
{ CompPluginRuleBefore, "fade" },
2565
{ CompPluginRuleBefore, "cube" },
2566
{ CompPluginRuleBefore, "expose" }
2569
CompPluginVTable wobblyVTable = {
2572
"Use spring model for wobbly window effect",
2581
0, /* GetDisplayOptions */
2582
0, /* SetDisplayOption */
2583
wobblyGetScreenOptions,
2584
wobblySetScreenOption,
2586
sizeof (wobblyDeps) / sizeof (wobblyDeps[0])
2590
getCompPluginInfo (void)
2592
return &wobblyVTable;