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.
34
#include <compiz-core.h>
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];
103
unsigned int edgeMask;
104
unsigned int snapCnt[4];
107
#define WOBBLY_EFFECT_NONE 0
108
#define WOBBLY_EFFECT_SHIVER 1
109
#define WOBBLY_EFFECT_LAST WOBBLY_EFFECT_SHIVER
111
static CompMetadata wobblyMetadata;
113
static int displayPrivateIndex;
115
#define WOBBLY_DISPLAY_OPTION_SNAP_KEY 0
116
#define WOBBLY_DISPLAY_OPTION_SNAP_INVERTED 1
117
#define WOBBLY_DISPLAY_OPTION_SHIVER 2
118
#define WOBBLY_DISPLAY_OPTION_NUM 3
120
typedef struct _WobblyDisplay {
121
int screenPrivateIndex;
122
HandleEventProc handleEvent;
124
CompOption opt[WOBBLY_DISPLAY_OPTION_NUM];
129
#define WOBBLY_SCREEN_OPTION_FRICTION 0
130
#define WOBBLY_SCREEN_OPTION_SPRING_K 1
131
#define WOBBLY_SCREEN_OPTION_GRID_RESOLUTION 2
132
#define WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE 3
133
#define WOBBLY_SCREEN_OPTION_MAP_EFFECT 4
134
#define WOBBLY_SCREEN_OPTION_FOCUS_EFFECT 5
135
#define WOBBLY_SCREEN_OPTION_MAP_WINDOW_MATCH 6
136
#define WOBBLY_SCREEN_OPTION_FOCUS_WINDOW_MATCH 7
137
#define WOBBLY_SCREEN_OPTION_GRAB_WINDOW_MATCH 8
138
#define WOBBLY_SCREEN_OPTION_MOVE_WINDOW_MATCH 9
139
#define WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT 10
140
#define WOBBLY_SCREEN_OPTION_NUM 11
142
typedef struct _WobblyScreen {
143
int windowPrivateIndex;
145
PreparePaintScreenProc preparePaintScreen;
146
DonePaintScreenProc donePaintScreen;
147
PaintOutputProc paintOutput;
148
PaintWindowProc paintWindow;
149
DamageWindowRectProc damageWindowRect;
150
AddWindowGeometryProc addWindowGeometry;
152
WindowResizeNotifyProc windowResizeNotify;
153
WindowMoveNotifyProc windowMoveNotify;
154
WindowGrabNotifyProc windowGrabNotify;
155
WindowUngrabNotifyProc windowUngrabNotify;
157
CompOption opt[WOBBLY_SCREEN_OPTION_NUM];
161
unsigned int grabMask;
162
CompWindow *grabWindow;
166
#define WobblyInitial (1L << 0)
167
#define WobblyForce (1L << 1)
168
#define WobblyVelocity (1L << 2)
170
typedef struct _WobblyWindow {
178
#define GET_WOBBLY_DISPLAY(d) \
179
((WobblyDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
181
#define WOBBLY_DISPLAY(d) \
182
WobblyDisplay *wd = GET_WOBBLY_DISPLAY (d)
184
#define GET_WOBBLY_SCREEN(s, wd) \
185
((WobblyScreen *) (s)->base.privates[(wd)->screenPrivateIndex].ptr)
187
#define WOBBLY_SCREEN(s) \
188
WobblyScreen *ws = GET_WOBBLY_SCREEN (s, GET_WOBBLY_DISPLAY (s->display))
190
#define GET_WOBBLY_WINDOW(w, ws) \
191
((WobblyWindow *) (w)->base.privates[(ws)->windowPrivateIndex].ptr)
193
#define WOBBLY_WINDOW(w) \
194
WobblyWindow *ww = GET_WOBBLY_WINDOW (w, \
195
GET_WOBBLY_SCREEN (w->screen, \
196
GET_WOBBLY_DISPLAY (w->screen->display)))
198
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
201
wobblyGetScreenOptions (CompPlugin *plugin,
205
WOBBLY_SCREEN (screen);
207
*count = NUM_OPTIONS (ws);
212
wobblySetScreenOption (CompPlugin *plugin,
215
CompOptionValue *value)
219
WOBBLY_SCREEN (screen);
221
o = compFindOption (ws->opt, NUM_OPTIONS (ws), name, NULL);
225
return compSetScreenOption (screen, o, value);
228
static const CompMetadataOptionInfo wobblyScreenOptionInfo[] = {
229
{ "friction", "float", "<min>0.1</min>", 0, 0 },
230
{ "spring_k", "float", "<min>0.1</min>", 0, 0 },
231
{ "grid_resolution", "int", "<min>1</min><max>64</max>", 0, 0 },
232
{ "min_grid_size", "int", "<min>4</min><max>128</max>", 0, 0 },
233
{ "map_effect", "int", RESTOSTRING (0, WOBBLY_EFFECT_LAST), 0, 0 },
234
{ "focus_effect", "int", RESTOSTRING (0, WOBBLY_EFFECT_LAST), 0, 0 },
235
{ "map_window_match", "match", 0, 0, 0 },
236
{ "focus_window_match", "match", 0, 0, 0 },
237
{ "grab_window_match", "match", 0, 0, 0 },
238
{ "move_window_match", "match", 0, 0, 0 },
239
{ "maximize_effect", "bool", 0, 0, 0 }
242
#define SNAP_WINDOW_TYPE (CompWindowTypeNormalMask | \
243
CompWindowTypeToolbarMask | \
244
CompWindowTypeMenuMask | \
245
CompWindowTypeUtilMask)
248
findNextWestEdge (CompWindow *w,
263
x = object->position.x + w->output.left - w->input.left;
265
output = outputDeviceForPoint (w->screen, x, object->position.y);
267
if (x >= w->screen->outputDev[output].region.extents.x1)
271
v1 = w->screen->outputDev[output].region.extents.x1;
273
for (p = w->screen->windows; p; p = p->next)
278
if (p->mapNum && p->struts)
280
s = p->struts->left.y - w->output.top;
281
e = p->struts->left.y + p->struts->left.height +
284
else if (!p->invisible && (p->type & SNAP_WINDOW_TYPE))
286
s = p->attrib.y - p->input.top - w->output.top;
287
e = p->attrib.y + p->height + p->input.bottom +
295
if (s > object->position.y)
300
else if (e < object->position.y)
313
if (p->mapNum && p->struts)
314
v = p->struts->left.x + p->struts->left.width;
316
v = p->attrib.x + p->width + p->input.right;
333
v2 = w->screen->outputDev[output].region.extents.x1;
336
v1 = v1 - w->output.left + w->input.left;
337
v2 = v2 - w->output.left + w->input.left;
339
if (v1 != (int) object->vertEdge.next)
340
object->vertEdge.snapped = FALSE;
342
object->vertEdge.start = start;
343
object->vertEdge.end = end;
345
object->vertEdge.next = v1;
346
object->vertEdge.prev = v2;
348
object->vertEdge.attract = v1 + EDGE_DISTANCE;
349
object->vertEdge.velocity = EDGE_VELOCITY;
353
findNextEastEdge (CompWindow *w,
368
x = object->position.x - w->output.right + w->input.right;
370
output = outputDeviceForPoint (w->screen, x, object->position.y);
372
if (x <= w->screen->outputDev[output].region.extents.x2)
376
v1 = w->screen->outputDev[output].region.extents.x2;
378
for (p = w->screen->windows; p; p = p->next)
383
if (p->mapNum && p->struts)
385
s = p->struts->right.y - w->output.top;
386
e = p->struts->right.y + p->struts->right.height +
389
else if (!p->invisible && (p->type & SNAP_WINDOW_TYPE))
391
s = p->attrib.y - p->input.top - w->output.top;
392
e = p->attrib.y + p->height + p->input.bottom +
400
if (s > object->position.y)
405
else if (e < object->position.y)
418
if (p->mapNum && p->struts)
419
v = p->struts->right.x;
421
v = p->attrib.x - p->input.left;
438
v2 = w->screen->outputDev[output].region.extents.x2;
441
v1 = v1 + w->output.right - w->input.right;
442
v2 = v2 + w->output.right - w->input.right;
444
if (v1 != (int) object->vertEdge.next)
445
object->vertEdge.snapped = FALSE;
447
object->vertEdge.start = start;
448
object->vertEdge.end = end;
450
object->vertEdge.next = v1;
451
object->vertEdge.prev = v2;
453
object->vertEdge.attract = v1 - EDGE_DISTANCE;
454
object->vertEdge.velocity = EDGE_VELOCITY;
458
findNextNorthEdge (CompWindow *w,
473
y = object->position.y + w->output.top - w->input.top;
475
output = outputDeviceForPoint (w->screen, object->position.x, y);
477
if (y >= w->screen->outputDev[output].region.extents.y1)
481
v1 = w->screen->outputDev[output].region.extents.y1;
483
for (p = w->screen->windows; p; p = p->next)
488
if (p->mapNum && p->struts)
490
s = p->struts->top.x - w->output.left;
491
e = p->struts->top.x + p->struts->top.width + w->output.right;
493
else if (!p->invisible && (p->type & SNAP_WINDOW_TYPE))
495
s = p->attrib.x - p->input.left - w->output.left;
496
e = p->attrib.x + p->width + p->input.right + w->output.right;
503
if (s > object->position.x)
508
else if (e < object->position.x)
521
if (p->mapNum && p->struts)
522
v = p->struts->top.y + p->struts->top.height;
524
v = p->attrib.y + p->height + p->input.bottom;
541
v2 = w->screen->outputDev[output].region.extents.y1;
544
v1 = v1 - w->output.top + w->input.top;
545
v2 = v2 - w->output.top + w->input.top;
547
if (v1 != (int) object->horzEdge.next)
548
object->horzEdge.snapped = FALSE;
550
object->horzEdge.start = start;
551
object->horzEdge.end = end;
553
object->horzEdge.next = v1;
554
object->horzEdge.prev = v2;
556
object->horzEdge.attract = v1 + EDGE_DISTANCE;
557
object->horzEdge.velocity = EDGE_VELOCITY;
561
findNextSouthEdge (CompWindow *w,
576
y = object->position.y - w->output.bottom + w->input.bottom;
578
output = outputDeviceForPoint (w->screen, object->position.x, y);
580
if (y <= w->screen->outputDev[output].region.extents.y2)
584
v1 = w->screen->outputDev[output].region.extents.y2;
586
for (p = w->screen->windows; p; p = p->next)
591
if (p->mapNum && p->struts)
593
s = p->struts->bottom.x - w->output.left;
594
e = p->struts->bottom.x + p->struts->bottom.width +
597
else if (!p->invisible && (p->type & SNAP_WINDOW_TYPE))
599
s = p->attrib.x - p->input.left - w->output.left;
600
e = p->attrib.x + p->width + p->input.right + w->output.right;
607
if (s > object->position.x)
612
else if (e < object->position.x)
625
if (p->mapNum && p->struts)
626
v = p->struts->bottom.y;
628
v = p->attrib.y - p->input.top;
645
v2 = w->screen->outputDev[output].region.extents.y2;
648
v1 = v1 + w->output.bottom - w->input.bottom;
649
v2 = v2 + w->output.bottom - w->input.bottom;
651
if (v1 != (int) object->horzEdge.next)
652
object->horzEdge.snapped = FALSE;
654
object->horzEdge.start = start;
655
object->horzEdge.end = end;
657
object->horzEdge.next = v1;
658
object->horzEdge.prev = v2;
660
object->horzEdge.attract = v1 - EDGE_DISTANCE;
661
object->horzEdge.velocity = EDGE_VELOCITY;
665
objectInit (Object *object,
674
object->position.x = positionX;
675
object->position.y = positionY;
677
object->velocity.x = velocityX;
678
object->velocity.y = velocityY;
681
object->immobile = FALSE;
683
object->edgeMask = 0;
685
object->vertEdge.snapped = FALSE;
686
object->horzEdge.snapped = FALSE;
688
object->vertEdge.next = 0.0f;
689
object->horzEdge.next = 0.0f;
693
springInit (Spring *spring,
701
spring->offset.x = offsetX;
702
spring->offset.y = offsetY;
706
modelCalcBounds (Model *model)
710
model->topLeft.x = MAXSHORT;
711
model->topLeft.y = MAXSHORT;
712
model->bottomRight.x = MINSHORT;
713
model->bottomRight.y = MINSHORT;
715
for (i = 0; i < model->numObjects; i++)
717
if (model->objects[i].position.x < model->topLeft.x)
718
model->topLeft.x = model->objects[i].position.x;
719
else if (model->objects[i].position.x > model->bottomRight.x)
720
model->bottomRight.x = model->objects[i].position.x;
722
if (model->objects[i].position.y < model->topLeft.y)
723
model->topLeft.y = model->objects[i].position.y;
724
else if (model->objects[i].position.y > model->bottomRight.y)
725
model->bottomRight.y = model->objects[i].position.y;
730
modelAddSpring (Model *model,
738
spring = &model->springs[model->numSprings];
741
springInit (spring, a, b, offsetX, offsetY);
745
modelSetMiddleAnchor (Model *model,
753
gx = ((GRID_WIDTH - 1) / 2 * width) / (float) (GRID_WIDTH - 1);
754
gy = ((GRID_HEIGHT - 1) / 2 * height) / (float) (GRID_HEIGHT - 1);
756
if (model->anchorObject)
757
model->anchorObject->immobile = FALSE;
759
model->anchorObject = &model->objects[GRID_WIDTH *
760
((GRID_HEIGHT - 1) / 2) +
761
(GRID_WIDTH - 1) / 2];
762
model->anchorObject->position.x = x + gx;
763
model->anchorObject->position.y = y + gy;
765
model->anchorObject->immobile = TRUE;
769
modelSetTopAnchor (Model *model,
776
gx = ((GRID_WIDTH - 1) / 2 * width) / (float) (GRID_WIDTH - 1);
778
if (model->anchorObject)
779
model->anchorObject->immobile = FALSE;
781
model->anchorObject = &model->objects[(GRID_WIDTH - 1) / 2];
782
model->anchorObject->position.x = x + gx;
783
model->anchorObject->position.y = y;
785
model->anchorObject->immobile = TRUE;
789
modelAddEdgeAnchors (Model *model,
797
o = &model->objects[0];
802
o = &model->objects[GRID_WIDTH - 1];
803
o->position.x = x + width;
807
o = &model->objects[GRID_WIDTH * (GRID_HEIGHT - 1)];
809
o->position.y = y + height;
812
o = &model->objects[model->numObjects - 1];
813
o->position.x = x + width;
814
o->position.y = y + height;
817
if (!model->anchorObject)
818
model->anchorObject = &model->objects[0];
822
modelRemoveEdgeAnchors (Model *model,
830
o = &model->objects[0];
833
if (o != model->anchorObject)
836
o = &model->objects[GRID_WIDTH - 1];
837
o->position.x = x + width;
839
if (o != model->anchorObject)
842
o = &model->objects[GRID_WIDTH * (GRID_HEIGHT - 1)];
844
o->position.y = y + height;
845
if (o != model->anchorObject)
848
o = &model->objects[model->numObjects - 1];
849
o->position.x = x + width;
850
o->position.y = y + height;
851
if (o != model->anchorObject)
856
modelAdjustObjectPosition (Model *model,
864
int gridX, gridY, i = 0;
866
for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
868
for (gridX = 0; gridX < GRID_WIDTH; gridX++)
870
o = &model->objects[i];
873
o->position.x = x + (gridX * width) / (GRID_WIDTH - 1);
874
o->position.y = y + (gridY * height) / (GRID_HEIGHT - 1);
885
modelInitObjects (Model *model,
891
int gridX, gridY, i = 0;
895
gh = GRID_HEIGHT - 1;
897
for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
899
for (gridX = 0; gridX < GRID_WIDTH; gridX++)
901
objectInit (&model->objects[i],
902
x + (gridX * width) / gw,
903
y + (gridY * height) / gh,
909
modelSetMiddleAnchor (model, x, y, width, height);
913
modelUpdateSnapping (CompWindow *window,
916
unsigned int edgeMask, gridMask, mask;
917
int gridX, gridY, i = 0;
919
edgeMask = model->edgeMask;
921
if (model->snapCnt[NORTH])
922
edgeMask &= ~SouthEdgeMask;
923
else if (model->snapCnt[SOUTH])
924
edgeMask &= ~NorthEdgeMask;
926
if (model->snapCnt[WEST])
927
edgeMask &= ~EastEdgeMask;
928
else if (model->snapCnt[EAST])
929
edgeMask &= ~WestEdgeMask;
931
for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
934
gridMask = edgeMask & NorthEdgeMask;
935
else if (gridY == GRID_HEIGHT - 1)
936
gridMask = edgeMask & SouthEdgeMask;
940
for (gridX = 0; gridX < GRID_WIDTH; gridX++)
945
mask |= edgeMask & WestEdgeMask;
946
else if (gridX == GRID_WIDTH - 1)
947
mask |= edgeMask & EastEdgeMask;
949
if (mask != model->objects[i].edgeMask)
951
model->objects[i].edgeMask = mask;
953
if (mask & WestEdgeMask)
955
if (!model->objects[i].vertEdge.snapped)
956
findNextWestEdge (window, &model->objects[i]);
958
else if (mask & EastEdgeMask)
960
if (!model->objects[i].vertEdge.snapped)
961
findNextEastEdge (window, &model->objects[i]);
964
model->objects[i].vertEdge.snapped = FALSE;
966
if (mask & NorthEdgeMask)
968
if (!model->objects[i].horzEdge.snapped)
969
findNextNorthEdge (window, &model->objects[i]);
971
else if (mask & SouthEdgeMask)
973
if (!model->objects[i].horzEdge.snapped)
974
findNextSouthEdge (window, &model->objects[i]);
977
model->objects[i].horzEdge.snapped = FALSE;
986
modelReduceEdgeEscapeVelocity (Model *model)
988
int gridX, gridY, i = 0;
990
for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
992
for (gridX = 0; gridX < GRID_WIDTH; gridX++)
994
if (model->objects[i].vertEdge.snapped)
995
model->objects[i].vertEdge.velocity *= drand48 () * 0.25f;
997
if (model->objects[i].horzEdge.snapped)
998
model->objects[i].horzEdge.velocity *= drand48 () * 0.25f;
1006
modelDisableSnapping (CompWindow *window,
1009
int gridX, gridY, i = 0;
1010
Bool snapped = FALSE;
1012
for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
1014
for (gridX = 0; gridX < GRID_WIDTH; gridX++)
1016
if (model->objects[i].vertEdge.snapped ||
1017
model->objects[i].horzEdge.snapped)
1020
model->objects[i].vertEdge.snapped = FALSE;
1021
model->objects[i].horzEdge.snapped = FALSE;
1023
model->objects[i].edgeMask = 0;
1029
memset (model->snapCnt, 0, sizeof (model->snapCnt));
1035
modelAdjustObjectsForShiver (Model *model,
1041
int gridX, gridY, i = 0;
1049
for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
1051
for (gridX = 0; gridX < GRID_WIDTH; gridX++)
1053
if (!model->objects[i].immobile)
1055
vX = model->objects[i].position.x - (x + w / 2);
1056
vY = model->objects[i].position.y - (y + h / 2);
1061
scale = ((float) rand () * 7.5f) / RAND_MAX;
1063
model->objects[i].velocity.x += vX * scale;
1064
model->objects[i].velocity.y += vY * scale;
1073
modelInitSprings (Model *model,
1079
int gridX, gridY, i = 0;
1082
model->numSprings = 0;
1084
hpad = ((float) width) / (GRID_WIDTH - 1);
1085
vpad = ((float) height) / (GRID_HEIGHT - 1);
1087
for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
1089
for (gridX = 0; gridX < GRID_WIDTH; gridX++)
1092
modelAddSpring (model,
1093
&model->objects[i - 1],
1098
modelAddSpring (model,
1099
&model->objects[i - GRID_WIDTH],
1109
modelMove (Model *model,
1115
for (i = 0; i < model->numObjects; i++)
1117
model->objects[i].position.x += tx;
1118
model->objects[i].position.y += ty;
1127
unsigned int edgeMask)
1131
model = malloc (sizeof (Model));
1135
model->numObjects = GRID_WIDTH * GRID_HEIGHT;
1136
model->objects = malloc (sizeof (Object) * model->numObjects);
1137
if (!model->objects)
1143
model->anchorObject = 0;
1144
model->numSprings = 0;
1148
memset (model->snapCnt, 0, sizeof (model->snapCnt));
1150
model->edgeMask = edgeMask;
1152
modelInitObjects (model, x, y, width, height);
1153
modelInitSprings (model, x, y, width, height);
1155
modelCalcBounds (model);
1161
objectApplyForce (Object *object,
1165
object->force.x += fx;
1166
object->force.y += fy;
1170
springExertForces (Spring *spring,
1176
a = spring->a->position;
1177
b = spring->b->position;
1179
da.x = 0.5f * (b.x - a.x - spring->offset.x);
1180
da.y = 0.5f * (b.y - a.y - spring->offset.y);
1182
db.x = 0.5f * (a.x - b.x + spring->offset.x);
1183
db.y = 0.5f * (a.y - b.y + spring->offset.y);
1185
objectApplyForce (spring->a, k * da.x, k * da.y);
1186
objectApplyForce (spring->b, k * db.x, k * db.y);
1190
objectReleaseWestEdge (CompWindow *w,
1194
if (fabs (object->velocity.x) > object->vertEdge.velocity)
1196
object->position.x += object->velocity.x * 2.0f;
1198
model->snapCnt[WEST]--;
1200
object->vertEdge.snapped = FALSE;
1201
object->edgeMask = 0;
1203
modelUpdateSnapping (w, model);
1208
object->velocity.x = 0.0f;
1214
objectReleaseEastEdge (CompWindow *w,
1218
if (fabs (object->velocity.x) > object->vertEdge.velocity)
1220
object->position.x += object->velocity.x * 2.0f;
1222
model->snapCnt[EAST]--;
1224
object->vertEdge.snapped = FALSE;
1225
object->edgeMask = 0;
1227
modelUpdateSnapping (w, model);
1232
object->velocity.x = 0.0f;
1238
objectReleaseNorthEdge (CompWindow *w,
1242
if (fabs (object->velocity.y) > object->horzEdge.velocity)
1244
object->position.y += object->velocity.y * 2.0f;
1246
model->snapCnt[NORTH]--;
1248
object->horzEdge.snapped = FALSE;
1249
object->edgeMask = 0;
1251
modelUpdateSnapping (w, model);
1256
object->velocity.y = 0.0f;
1262
objectReleaseSouthEdge (CompWindow *w,
1266
if (fabs (object->velocity.y) > object->horzEdge.velocity)
1268
object->position.y += object->velocity.y * 2.0f;
1270
model->snapCnt[SOUTH]--;
1272
object->horzEdge.snapped = FALSE;
1273
object->edgeMask = 0;
1275
modelUpdateSnapping (w, model);
1280
object->velocity.y = 0.0f;
1286
modelStepObject (CompWindow *window,
1292
object->theta += 0.05f;
1294
if (object->immobile)
1296
object->velocity.x = 0.0f;
1297
object->velocity.y = 0.0f;
1299
object->force.x = 0.0f;
1300
object->force.y = 0.0f;
1308
object->force.x -= friction * object->velocity.x;
1309
object->force.y -= friction * object->velocity.y;
1311
object->velocity.x += object->force.x / MASS;
1312
object->velocity.y += object->force.y / MASS;
1314
if (object->edgeMask)
1316
if (object->edgeMask & WestEdgeMask)
1318
if (object->position.y < object->vertEdge.start ||
1319
object->position.y > object->vertEdge.end)
1320
findNextWestEdge (window, object);
1322
if (!object->vertEdge.snapped ||
1323
objectReleaseWestEdge (window, model, object))
1325
object->position.x += object->velocity.x;
1327
if (object->velocity.x < 0.0f &&
1328
object->position.x < object->vertEdge.attract)
1330
if (object->position.x < object->vertEdge.next)
1332
object->vertEdge.snapped = TRUE;
1333
object->position.x = object->vertEdge.next;
1334
object->velocity.x = 0.0f;
1336
model->snapCnt[WEST]++;
1338
modelUpdateSnapping (window, model);
1342
object->velocity.x -=
1343
object->vertEdge.attract - object->position.x;
1347
if (object->position.x > object->vertEdge.prev)
1348
findNextWestEdge (window, object);
1351
else if (object->edgeMask & EastEdgeMask)
1353
if (object->position.y < object->vertEdge.start ||
1354
object->position.y > object->vertEdge.end)
1355
findNextEastEdge (window, object);
1357
if (!object->vertEdge.snapped ||
1358
objectReleaseEastEdge (window, model, object))
1360
object->position.x += object->velocity.x;
1362
if (object->velocity.x > 0.0f &&
1363
object->position.x > object->vertEdge.attract)
1365
if (object->position.x > object->vertEdge.next)
1367
object->vertEdge.snapped = TRUE;
1368
object->position.x = object->vertEdge.next;
1369
object->velocity.x = 0.0f;
1371
model->snapCnt[EAST]++;
1373
modelUpdateSnapping (window, model);
1377
object->velocity.x =
1378
object->position.x - object->vertEdge.attract;
1382
if (object->position.x < object->vertEdge.prev)
1383
findNextEastEdge (window, object);
1387
object->position.x += object->velocity.x;
1389
if (object->edgeMask & NorthEdgeMask)
1391
if (object->position.x < object->horzEdge.start ||
1392
object->position.x > object->horzEdge.end)
1393
findNextNorthEdge (window, object);
1395
if (!object->horzEdge.snapped ||
1396
objectReleaseNorthEdge (window, model, object))
1398
object->position.y += object->velocity.y;
1400
if (object->velocity.y < 0.0f &&
1401
object->position.y < object->horzEdge.attract)
1403
if (object->position.y < object->horzEdge.next)
1405
object->horzEdge.snapped = TRUE;
1406
object->position.y = object->horzEdge.next;
1407
object->velocity.y = 0.0f;
1409
model->snapCnt[NORTH]++;
1411
modelUpdateSnapping (window, model);
1415
object->velocity.y -=
1416
object->horzEdge.attract - object->position.y;
1420
if (object->position.y > object->horzEdge.prev)
1421
findNextNorthEdge (window, object);
1424
else if (object->edgeMask & SouthEdgeMask)
1426
if (object->position.x < object->horzEdge.start ||
1427
object->position.x > object->horzEdge.end)
1428
findNextSouthEdge (window, object);
1430
if (!object->horzEdge.snapped ||
1431
objectReleaseSouthEdge (window, model, object))
1433
object->position.y += object->velocity.y;
1435
if (object->velocity.y > 0.0f &&
1436
object->position.y > object->horzEdge.attract)
1438
if (object->position.y > object->horzEdge.next)
1440
object->horzEdge.snapped = TRUE;
1441
object->position.y = object->horzEdge.next;
1442
object->velocity.y = 0.0f;
1444
model->snapCnt[SOUTH]++;
1446
modelUpdateSnapping (window, model);
1450
object->velocity.y =
1451
object->position.y - object->horzEdge.attract;
1455
if (object->position.y < object->horzEdge.prev)
1456
findNextSouthEdge (window, object);
1460
object->position.y += object->velocity.y;
1464
object->position.x += object->velocity.x;
1465
object->position.y += object->velocity.y;
1468
*force = fabs (object->force.x) + fabs (object->force.y);
1470
object->force.x = 0.0f;
1471
object->force.y = 0.0f;
1473
return fabs (object->velocity.x) + fabs (object->velocity.y);
1478
modelStep (CompWindow *window,
1484
int i, j, steps, wobbly = 0;
1485
float velocitySum = 0.0f;
1486
float force, forceSum = 0.0f;
1488
model->steps += time / 15.0f;
1489
steps = floor (model->steps);
1490
model->steps -= steps;
1495
for (j = 0; j < steps; j++)
1497
for (i = 0; i < model->numSprings; i++)
1498
springExertForces (&model->springs[i], k);
1500
for (i = 0; i < model->numObjects; i++)
1502
velocitySum += modelStepObject (window,
1511
modelCalcBounds (model);
1513
if (velocitySum > 0.5f)
1514
wobbly |= WobblyVelocity;
1516
if (forceSum > 20.0f)
1517
wobbly |= WobblyForce;
1523
bezierPatchEvaluate (Model *model,
1529
float coeffsU[4], coeffsV[4];
1533
coeffsU[0] = (1 - u) * (1 - u) * (1 - u);
1534
coeffsU[1] = 3 * u * (1 - u) * (1 - u);
1535
coeffsU[2] = 3 * u * u * (1 - u);
1536
coeffsU[3] = u * u * u;
1538
coeffsV[0] = (1 - v) * (1 - v) * (1 - v);
1539
coeffsV[1] = 3 * v * (1 - v) * (1 - v);
1540
coeffsV[2] = 3 * v * v * (1 - v);
1541
coeffsV[3] = v * v * v;
1545
for (i = 0; i < 4; i++)
1547
for (j = 0; j < 4; j++)
1549
x += coeffsU[i] * coeffsV[j] *
1550
model->objects[j * GRID_WIDTH + i].position.x;
1551
y += coeffsU[i] * coeffsV[j] *
1552
model->objects[j * GRID_WIDTH + i].position.y;
1561
wobblyEnsureModel (CompWindow *w)
1567
unsigned int edgeMask = 0;
1569
if (w->type & CompWindowTypeNormalMask)
1570
edgeMask = WestEdgeMask | EastEdgeMask | NorthEdgeMask |
1573
ww->model = createModel (WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w),
1583
objectDistance (Object *object,
1589
dx = object->position.x - x;
1590
dy = object->position.y - y;
1592
return sqrt (dx * dx + dy * dy);
1596
modelFindNearestObject (Model *model,
1600
Object *object = &model->objects[0];
1601
float distance, minDistance = 0.0;
1604
for (i = 0; i < model->numObjects; i++)
1606
distance = objectDistance (&model->objects[i], x, y);
1607
if (i == 0 || distance < minDistance)
1609
minDistance = distance;
1610
object = &model->objects[i];
1618
isWobblyWin (CompWindow *w)
1625
/* avoid tiny windows */
1626
if (w->width == 1 && w->height == 1)
1629
/* avoid fullscreen windows */
1630
if (w->attrib.x <= 0 &&
1632
w->attrib.x + w->width >= w->screen->width &&
1633
w->attrib.y + w->height >= w->screen->height)
1640
wobblyPreparePaintScreen (CompScreen *s,
1641
int msSinceLastPaint)
1648
if (ws->wobblyWindows & (WobblyInitial | WobblyVelocity))
1651
Point topLeft, bottomRight;
1652
float friction, springK;
1655
friction = ws->opt[WOBBLY_SCREEN_OPTION_FRICTION].value.f;
1656
springK = ws->opt[WOBBLY_SCREEN_OPTION_SPRING_K].value.f;
1658
ws->wobblyWindows = 0;
1659
for (w = s->windows; w; w = w->next)
1661
ww = GET_WOBBLY_WINDOW (w, ws);
1665
if (ww->wobbly & (WobblyInitial | WobblyVelocity))
1669
topLeft = model->topLeft;
1670
bottomRight = model->bottomRight;
1672
ww->wobbly = modelStep (w, model, friction, springK,
1673
(ww->wobbly & WobblyVelocity) ?
1677
if ((ww->state & MAXIMIZE_STATE) && ww->grabbed)
1678
ww->wobbly |= WobblyForce;
1682
/* snapped to more than one edge, we have to reduce
1683
edge escape velocity until only one edge is snapped */
1684
if (ww->wobbly == WobblyForce && !ww->grabbed)
1686
modelReduceEdgeEscapeVelocity (ww->model);
1687
ww->wobbly |= WobblyInitial;
1694
if (w->attrib.x == w->serverX &&
1695
w->attrib.y == w->serverY)
1698
model->topLeft.x + w->output.left -
1700
model->topLeft.y + w->output.top -
1703
syncWindowPosition (w);
1709
if (!(s->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK))
1713
if (ww->model->topLeft.x < topLeft.x)
1714
topLeft.x = ww->model->topLeft.x;
1715
if (ww->model->topLeft.y < topLeft.y)
1716
topLeft.y = ww->model->topLeft.y;
1717
if (ww->model->bottomRight.x > bottomRight.x)
1718
bottomRight.x = ww->model->bottomRight.x;
1719
if (ww->model->bottomRight.y > bottomRight.y)
1720
bottomRight.y = ww->model->bottomRight.y;
1723
addWindowDamage (w);
1727
box.x2 = bottomRight.x + 0.5f;
1728
box.y2 = bottomRight.y + 0.5f;
1730
box.x1 -= w->attrib.x + w->attrib.border_width;
1731
box.y1 -= w->attrib.y + w->attrib.border_width;
1732
box.x2 -= w->attrib.x + w->attrib.border_width;
1733
box.y2 -= w->attrib.y + w->attrib.border_width;
1735
addWindowDamageRect (w, &box);
1739
ws->wobblyWindows |= ww->wobbly;
1744
UNWRAP (ws, s, preparePaintScreen);
1745
(*s->preparePaintScreen) (s, msSinceLastPaint);
1746
WRAP (ws, s, preparePaintScreen, wobblyPreparePaintScreen);
1750
wobblyDonePaintScreen (CompScreen *s)
1754
if (ws->wobblyWindows & (WobblyVelocity | WobblyInitial))
1755
damagePendingOnScreen (s);
1757
UNWRAP (ws, s, donePaintScreen);
1758
(*s->donePaintScreen) (s);
1759
WRAP (ws, s, donePaintScreen, wobblyDonePaintScreen);
1763
wobblyDrawWindowGeometry (CompWindow *w)
1765
int texUnit = w->texUnits;
1766
int currentTexUnit = 0;
1767
int stride = w->vertexStride;
1768
GLfloat *vertices = w->vertices + (stride - 3);
1770
stride *= sizeof (GLfloat);
1772
glVertexPointer (3, GL_FLOAT, stride, vertices);
1776
if (texUnit != currentTexUnit)
1778
w->screen->clientActiveTexture (GL_TEXTURE0_ARB + texUnit);
1779
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
1780
currentTexUnit = texUnit;
1782
vertices -= w->texCoordSize;
1783
glTexCoordPointer (w->texCoordSize, GL_FLOAT, stride, vertices);
1786
glDrawElements (GL_QUADS, w->indexCount, GL_UNSIGNED_SHORT, w->indices);
1788
/* disable all texture coordinate arrays except 0 */
1789
texUnit = w->texUnits;
1794
(*w->screen->clientActiveTexture) (GL_TEXTURE0_ARB + texUnit);
1795
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
1798
(*w->screen->clientActiveTexture) (GL_TEXTURE0_ARB);
1803
wobblyAddWindowGeometry (CompWindow *w,
1810
WOBBLY_SCREEN (w->screen);
1815
int nClip, nVertices, nIndices;
1819
float width, height;
1820
float deformedX, deformedY;
1821
int x, y, iw, ih, wx, wy;
1826
for (it = 0; it < nMatrix; it++)
1828
if (matrix[it].xy != 0.0f || matrix[it].yx != 0.0f)
1840
gridW = width / ws->opt[WOBBLY_SCREEN_OPTION_GRID_RESOLUTION].value.i;
1841
if (gridW < ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i)
1842
gridW = ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i;
1844
gridH = height / ws->opt[WOBBLY_SCREEN_OPTION_GRID_RESOLUTION].value.i;
1845
if (gridH < ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i)
1846
gridH = ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i;
1848
nClip = region->numRects;
1849
pClip = region->rects;
1851
w->texUnits = nMatrix;
1853
vSize = 3 + nMatrix * 2;
1855
nVertices = w->vCount;
1856
nIndices = w->indexCount;
1858
v = w->vertices + (nVertices * vSize);
1859
i = w->indices + nIndices;
1868
iw = ((x2 - x1 - 1) / gridW) + 1;
1869
ih = ((y2 - y1 - 1) / gridH) + 1;
1871
if (nIndices + (iw * ih * 4) > w->indexSize)
1873
if (!moreWindowIndices (w, nIndices + (iw * ih * 4)))
1876
i = w->indices + nIndices;
1882
for (y = 0; y < ih - 1; y++)
1884
for (x = 0; x < iw - 1; x++)
1886
*i++ = nVertices + iw * (y + 1) + x;
1887
*i++ = nVertices + iw * (y + 1) + x + 1;
1888
*i++ = nVertices + iw * y + x + 1;
1889
*i++ = nVertices + iw * y + x;
1895
if (((nVertices + iw * ih) * vSize) > w->vertexSize)
1897
if (!moreWindowVertices (w, (nVertices + iw * ih) * vSize))
1900
v = w->vertices + (nVertices * vSize);
1903
for (y = y1;; y += gridH)
1908
for (x = x1;; x += gridW)
1913
bezierPatchEvaluate (ww->model,
1921
for (it = 0; it < nMatrix; it++)
1923
*v++ = COMP_TEX_COORD_X (&matrix[it], x);
1924
*v++ = COMP_TEX_COORD_Y (&matrix[it], y);
1929
for (it = 0; it < nMatrix; it++)
1931
*v++ = COMP_TEX_COORD_XY (&matrix[it], x, y);
1932
*v++ = COMP_TEX_COORD_YX (&matrix[it], x, y);
1953
w->vCount = nVertices;
1954
w->vertexStride = vSize;
1955
w->texCoordSize = 2;
1956
w->indexCount = nIndices;
1957
w->drawWindowGeometry = wobblyDrawWindowGeometry;
1961
UNWRAP (ws, w->screen, addWindowGeometry);
1962
(*w->screen->addWindowGeometry) (w, matrix, nMatrix, region, clip);
1963
WRAP (ws, w->screen, addWindowGeometry, wobblyAddWindowGeometry);
1968
wobblyPaintWindow (CompWindow *w,
1969
const WindowPaintAttrib *attrib,
1970
const CompTransform *transform,
1976
WOBBLY_SCREEN (w->screen);
1980
mask |= PAINT_WINDOW_TRANSFORMED_MASK;
1982
UNWRAP (ws, w->screen, paintWindow);
1983
status = (*w->screen->paintWindow) (w, attrib, transform, region, mask);
1984
WRAP (ws, w->screen, paintWindow, wobblyPaintWindow);
1990
wobblyEnableSnapping (CompDisplay *d,
1992
CompActionState state,
2001
for (s = d->screens; s; s = s->next)
2003
for (w = s->windows; w; w = w->next)
2007
if (ww->grabbed && ww->model)
2008
modelUpdateSnapping (w, ww->model);
2012
wd->snapping = TRUE;
2018
wobblyDisableSnapping (CompDisplay *d,
2020
CompActionState state,
2032
for (s = d->screens; s; s = s->next)
2034
for (w = s->windows; w; w = w->next)
2038
if (ww->grabbed && ww->model)
2040
if (modelDisableSnapping (w, ww->model))
2042
WOBBLY_SCREEN (w->screen);
2044
ww->wobbly |= WobblyInitial;
2045
ws->wobblyWindows |= ww->wobbly;
2047
damagePendingOnScreen (w->screen);
2053
wd->snapping = FALSE;
2059
wobblyShiver (CompDisplay *d,
2061
CompActionState state,
2068
xid = getIntOptionNamed (option, nOption, "window", 0);
2070
w = findWindowAtDisplay (d, xid);
2071
if (w && isWobblyWin (w) && wobblyEnsureModel (w))
2073
WOBBLY_SCREEN (w->screen);
2076
modelSetMiddleAnchor (ww->model,
2077
WIN_X (w), WIN_Y (w),
2078
WIN_W (w), WIN_H (w));
2079
modelAdjustObjectsForShiver (ww->model,
2080
WIN_X (w), WIN_Y (w),
2081
WIN_W (w), WIN_H (w));
2083
ww->wobbly |= WobblyInitial;
2084
ws->wobblyWindows |= ww->wobbly;
2086
damagePendingOnScreen (w->screen);
2093
wobblyHandleEvent (CompDisplay *d,
2096
Window activeWindow = d->activeWindow;
2102
switch (event->type) {
2104
w = findWindowAtDisplay (d, event->xmap.window);
2111
modelInitObjects (ww->model,
2112
WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
2114
modelInitSprings (ww->model,
2115
WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
2120
if (event->type == d->xkbEvent)
2122
XkbAnyEvent *xkbEvent = (XkbAnyEvent *) event;
2124
if (xkbEvent->xkb_type == XkbStateNotify)
2126
XkbStateNotifyEvent *stateEvent = (XkbStateNotifyEvent *) event;
2129
unsigned int mods = 0xffffffff;
2132
&wd->opt[WOBBLY_DISPLAY_OPTION_SNAP_KEY].value.action;
2133
inverted = wd->opt[WOBBLY_DISPLAY_OPTION_SNAP_INVERTED].value.b;
2135
if (action->type & CompBindingTypeKey)
2136
mods = action->key.modifiers;
2138
if ((stateEvent->mods & mods) == mods)
2141
wobblyDisableSnapping (d, NULL, 0, NULL, 0);
2143
wobblyEnableSnapping (d, NULL, 0, NULL, 0);
2148
wobblyEnableSnapping (d, NULL, 0, NULL, 0);
2150
wobblyDisableSnapping (d, NULL, 0, NULL, 0);
2157
UNWRAP (wd, d, handleEvent);
2158
(*d->handleEvent) (d, event);
2159
WRAP (wd, d, handleEvent, wobblyHandleEvent);
2161
switch (event->type) {
2163
s = findScreenAtDisplay (d, event->xmotion.root);
2168
if (ws->grabWindow &&
2170
ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b)
2172
WOBBLY_WINDOW (ws->grabWindow);
2174
if (ww->state & MAXIMIZE_STATE)
2176
if (ww->model && ww->grabbed)
2180
if (ww->state & CompWindowStateMaximizedHorzMask)
2181
dx = pointerX - lastPointerX;
2185
if (ww->state & CompWindowStateMaximizedVertMask)
2186
dy = pointerY - lastPointerY;
2190
ww->model->anchorObject->position.x += dx;
2191
ww->model->anchorObject->position.y += dy;
2193
ww->wobbly |= WobblyInitial;
2194
ws->wobblyWindows |= ww->wobbly;
2196
damagePendingOnScreen (s);
2205
if (d->activeWindow != activeWindow)
2207
w = findWindowAtDisplay (d, d->activeWindow);
2208
if (w && isWobblyWin (w))
2214
WOBBLY_SCREEN (w->screen);
2216
mIndex = WOBBLY_SCREEN_OPTION_FOCUS_WINDOW_MATCH;
2217
focusEffect = ws->opt[WOBBLY_SCREEN_OPTION_FOCUS_EFFECT].value.i;
2219
if ((focusEffect != WOBBLY_EFFECT_NONE) &&
2220
matchEval (&ws->opt[mIndex].value.match, w) &&
2221
wobblyEnsureModel (w))
2223
switch (focusEffect) {
2224
case WOBBLY_EFFECT_SHIVER:
2225
modelAdjustObjectsForShiver (ww->model,
2234
ww->wobbly |= WobblyInitial;
2235
ws->wobblyWindows |= ww->wobbly;
2237
damagePendingOnScreen (w->screen);
2244
wobblyDamageWindowRect (CompWindow *w,
2250
WOBBLY_SCREEN (w->screen);
2256
if (ww->wobbly == WobblyForce)
2260
region.rects = ®ion.extents;
2261
region.numRects = region.size = 1;
2263
region.extents.x1 = ww->model->topLeft.x;
2264
region.extents.y1 = ww->model->topLeft.y;
2265
region.extents.x2 = ww->model->bottomRight.x + 0.5f;
2266
region.extents.y2 = ww->model->bottomRight.y + 0.5f;
2268
damageScreenRegion (w->screen, ®ion);
2274
UNWRAP (ws, w->screen, damageWindowRect);
2275
status = (*w->screen->damageWindowRect) (w, initial, rect);
2276
WRAP (ws, w->screen, damageWindowRect, wobblyDamageWindowRect);
2280
if (isWobblyWin (w))
2286
WOBBLY_SCREEN (w->screen);
2288
mIndex = WOBBLY_SCREEN_OPTION_MAP_WINDOW_MATCH;
2289
mapEffect = ws->opt[WOBBLY_SCREEN_OPTION_MAP_EFFECT].value.i;
2291
if (ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b)
2292
wobblyEnsureModel (w);
2294
if ((mapEffect != WOBBLY_EFFECT_NONE) &&
2295
matchEval (&ws->opt[mIndex].value.match, w) &&
2296
wobblyEnsureModel (w))
2298
switch (mapEffect) {
2299
case WOBBLY_EFFECT_SHIVER:
2300
modelAdjustObjectsForShiver (ww->model,
2301
WIN_X (w), WIN_Y (w),
2302
WIN_W (w), WIN_H (w));
2307
ww->wobbly |= WobblyInitial;
2308
ws->wobblyWindows |= ww->wobbly;
2310
damagePendingOnScreen (w->screen);
2319
wobblyWindowResizeNotify (CompWindow *w,
2325
WOBBLY_SCREEN (w->screen);
2328
if (ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b &&
2330
/* prevent wobbling when shading maximized windows - assuming that
2331
the height difference shaded - non-shaded will hardly be -1 and
2332
a lack of wobbly animation in that corner case is tolerable */
2334
((w->state | ww->state) & MAXIMIZE_STATE))
2336
ww->state &= ~MAXIMIZE_STATE;
2337
ww->state |= w->state & MAXIMIZE_STATE;
2339
if (wobblyEnsureModel (w))
2341
if (w->state & MAXIMIZE_STATE)
2343
if (!ww->grabbed && ww->model->anchorObject)
2345
ww->model->anchorObject->immobile = FALSE;
2346
ww->model->anchorObject = NULL;
2349
modelAddEdgeAnchors (ww->model,
2350
WIN_X (w), WIN_Y (w),
2351
WIN_W (w), WIN_H (w));
2355
modelRemoveEdgeAnchors (ww->model,
2356
WIN_X (w), WIN_Y (w),
2357
WIN_W (w), WIN_H (w));
2358
modelSetMiddleAnchor (ww->model,
2359
WIN_X (w), WIN_Y (w),
2360
WIN_W (w), WIN_H (w));
2363
modelInitSprings (ww->model,
2364
WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
2366
ww->wobbly |= WobblyInitial;
2367
ws->wobblyWindows |= ww->wobbly;
2369
damagePendingOnScreen (w->screen);
2376
if (!(ww->state & MAXIMIZE_STATE))
2377
modelSetTopAnchor (ww->model, WIN_X (w), WIN_Y (w), WIN_W (w));
2381
modelInitObjects (ww->model,
2382
WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
2385
modelInitSprings (ww->model,
2386
WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
2390
if (ww->model && ww->grabbed)
2392
if (ww->model->anchorObject)
2393
ww->model->anchorObject->immobile = FALSE;
2395
ww->model->anchorObject = modelFindNearestObject (ww->model,
2398
ww->model->anchorObject->immobile = TRUE;
2400
modelAdjustObjectPosition (ww->model,
2401
ww->model->anchorObject,
2402
WIN_X (w), WIN_Y (w),
2403
WIN_W (w), WIN_H (w));
2406
UNWRAP (ws, w->screen, windowResizeNotify);
2407
(*w->screen->windowResizeNotify) (w, dx, dy, dwidth, dheight);
2408
WRAP (ws, w->screen, windowResizeNotify, wobblyWindowResizeNotify);
2412
wobblyWindowMoveNotify (CompWindow *w,
2417
WOBBLY_SCREEN (w->screen);
2422
if (ww->grabbed && !immediate)
2424
if (ww->state & MAXIMIZE_STATE)
2428
for (i = 0; i < ww->model->numObjects; i++)
2430
if (ww->model->objects[i].immobile)
2432
ww->model->objects[i].position.x += dx;
2433
ww->model->objects[i].position.y += dy;
2439
ww->model->anchorObject->position.x += dx;
2440
ww->model->anchorObject->position.y += dy;
2443
ww->wobbly |= WobblyInitial;
2444
ws->wobblyWindows |= ww->wobbly;
2446
damagePendingOnScreen (w->screen);
2449
modelMove (ww->model, dx, dy);
2452
UNWRAP (ws, w->screen, windowMoveNotify);
2453
(*w->screen->windowMoveNotify) (w, dx, dy, immediate);
2454
WRAP (ws, w->screen, windowMoveNotify, wobblyWindowMoveNotify);
2458
wobblyWindowGrabNotify (CompWindow *w,
2466
WOBBLY_SCREEN (w->screen);
2468
mIndex = WOBBLY_SCREEN_OPTION_MOVE_WINDOW_MATCH;
2470
if (!ws->grabWindow)
2472
ws->grabMask = mask;
2475
ws->moveWindow = FALSE;
2477
if ((mask & CompWindowGrabButtonMask) &&
2478
matchEval (&ws->opt[mIndex].value.match, w) &&
2483
ws->moveWindow = TRUE;
2485
if (wobblyEnsureModel (w))
2490
if (ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b)
2492
if (w->state & MAXIMIZE_STATE)
2494
modelAddEdgeAnchors (ww->model,
2495
WIN_X (w), WIN_Y (w),
2496
WIN_W (w), WIN_H (w));
2500
modelRemoveEdgeAnchors (ww->model,
2501
WIN_X (w), WIN_Y (w),
2502
WIN_W (w), WIN_H (w));
2504
if (ww->model->anchorObject)
2505
ww->model->anchorObject->immobile = FALSE;
2510
if (ww->model->anchorObject)
2511
ww->model->anchorObject->immobile = FALSE;
2514
ww->model->anchorObject = modelFindNearestObject (ww->model, x, y);
2515
ww->model->anchorObject->immobile = TRUE;
2519
if (mask & CompWindowGrabMoveMask)
2521
WOBBLY_DISPLAY (w->screen->display);
2523
modelDisableSnapping (w, ww->model);
2525
modelUpdateSnapping (w, ww->model);
2528
mIndex = WOBBLY_SCREEN_OPTION_GRAB_WINDOW_MATCH;
2530
if (matchEval (&ws->opt[mIndex].value.match, w))
2532
for (i = 0; i < ww->model->numSprings; i++)
2534
s = &ww->model->springs[i];
2536
if (s->a == ww->model->anchorObject)
2538
s->b->velocity.x -= s->offset.x * 0.05f;
2539
s->b->velocity.y -= s->offset.y * 0.05f;
2541
else if (s->b == ww->model->anchorObject)
2543
s->a->velocity.x += s->offset.x * 0.05f;
2544
s->a->velocity.y += s->offset.y * 0.05f;
2548
ww->wobbly |= WobblyInitial;
2549
ws->wobblyWindows |= ww->wobbly;
2551
damagePendingOnScreen (w->screen);
2556
UNWRAP (ws, w->screen, windowGrabNotify);
2557
(*w->screen->windowGrabNotify) (w, x, y, state, mask);
2558
WRAP (ws, w->screen, windowGrabNotify, wobblyWindowGrabNotify);
2562
wobblyWindowUngrabNotify (CompWindow *w)
2564
WOBBLY_SCREEN (w->screen);
2567
if (w == ws->grabWindow)
2570
ws->grabWindow = NULL;
2577
if (ww->model->anchorObject)
2578
ww->model->anchorObject->immobile = FALSE;
2580
ww->model->anchorObject = NULL;
2582
if (ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b)
2584
if (ww->state & MAXIMIZE_STATE)
2585
modelAddEdgeAnchors (ww->model,
2586
WIN_X (w), WIN_Y (w),
2587
WIN_W (w), WIN_H (w));
2590
ww->wobbly |= WobblyInitial;
2591
ws->wobblyWindows |= ww->wobbly;
2593
damagePendingOnScreen (w->screen);
2596
ww->grabbed = FALSE;
2599
UNWRAP (ws, w->screen, windowUngrabNotify);
2600
(*w->screen->windowUngrabNotify) (w);
2601
WRAP (ws, w->screen, windowUngrabNotify, wobblyWindowUngrabNotify);
2606
wobblyPaintOutput (CompScreen *s,
2607
const ScreenPaintAttrib *sAttrib,
2608
const CompTransform *transform,
2617
if (ws->wobblyWindows)
2618
mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
2620
UNWRAP (ws, s, paintOutput);
2621
status = (*s->paintOutput) (s, sAttrib, transform, region, output, mask);
2622
WRAP (ws, s, paintOutput, wobblyPaintOutput);
2628
wobblyGetDisplayOptions (CompPlugin *plugin,
2629
CompDisplay *display,
2632
WOBBLY_DISPLAY (display);
2634
*count = NUM_OPTIONS (wd);
2639
wobblySetDisplayOption (CompPlugin *plugin,
2640
CompDisplay *display,
2642
CompOptionValue *value)
2647
WOBBLY_DISPLAY (display);
2649
o = compFindOption (wd->opt, NUM_OPTIONS (wd), name, &index);
2654
case WOBBLY_DISPLAY_OPTION_SNAP_KEY:
2655
/* ignore the key */
2656
value->action.key.keycode = 0;
2658
if (compSetActionOption (o, value))
2662
return compSetDisplayOption (display, o, value);
2668
static const CompMetadataOptionInfo wobblyDisplayOptionInfo[] = {
2669
{ "snap_key", "key", "<passive_grab>false</passive_grab>",
2670
wobblyEnableSnapping, wobblyDisableSnapping },
2671
{ "snap_inverted", "bool", 0, 0, 0 },
2672
{ "shiver", "bell", 0, wobblyShiver, 0 }
2676
wobblyInitDisplay (CompPlugin *p,
2681
if (!checkPluginABI ("core", CORE_ABIVERSION))
2684
wd = malloc (sizeof (WobblyDisplay));
2688
if (!compInitDisplayOptionsFromMetadata (d,
2690
wobblyDisplayOptionInfo,
2692
WOBBLY_DISPLAY_OPTION_NUM))
2698
wd->screenPrivateIndex = allocateScreenPrivateIndex (d);
2699
if (wd->screenPrivateIndex < 0)
2701
compFiniDisplayOptions (d, wd->opt, WOBBLY_DISPLAY_OPTION_NUM);
2706
WRAP (wd, d, handleEvent, wobblyHandleEvent);
2708
wd->snapping = FALSE;
2710
d->base.privates[displayPrivateIndex].ptr = wd;
2716
wobblyFiniDisplay (CompPlugin *p,
2721
freeScreenPrivateIndex (d, wd->screenPrivateIndex);
2723
UNWRAP (wd, d, handleEvent);
2725
compFiniDisplayOptions (d, wd->opt, WOBBLY_DISPLAY_OPTION_NUM);
2731
wobblyInitScreen (CompPlugin *p,
2736
WOBBLY_DISPLAY (s->display);
2738
ws = malloc (sizeof (WobblyScreen));
2742
if (!compInitScreenOptionsFromMetadata (s,
2744
wobblyScreenOptionInfo,
2746
WOBBLY_SCREEN_OPTION_NUM))
2752
ws->windowPrivateIndex = allocateWindowPrivateIndex (s);
2753
if (ws->windowPrivateIndex < 0)
2755
compFiniScreenOptions (s, ws->opt, WOBBLY_SCREEN_OPTION_NUM);
2760
ws->wobblyWindows = FALSE;
2763
ws->grabWindow = NULL;
2764
ws->moveWindow = FALSE;
2766
WRAP (ws, s, preparePaintScreen, wobblyPreparePaintScreen);
2767
WRAP (ws, s, donePaintScreen, wobblyDonePaintScreen);
2768
WRAP (ws, s, paintOutput, wobblyPaintOutput);
2769
WRAP (ws, s, paintWindow, wobblyPaintWindow);
2770
WRAP (ws, s, damageWindowRect, wobblyDamageWindowRect);
2771
WRAP (ws, s, addWindowGeometry, wobblyAddWindowGeometry);
2772
WRAP (ws, s, windowResizeNotify, wobblyWindowResizeNotify);
2773
WRAP (ws, s, windowMoveNotify, wobblyWindowMoveNotify);
2774
WRAP (ws, s, windowGrabNotify, wobblyWindowGrabNotify);
2775
WRAP (ws, s, windowUngrabNotify, wobblyWindowUngrabNotify);
2777
s->base.privates[wd->screenPrivateIndex].ptr = ws;
2783
wobblyFiniScreen (CompPlugin *p,
2788
freeWindowPrivateIndex (s, ws->windowPrivateIndex);
2790
UNWRAP (ws, s, preparePaintScreen);
2791
UNWRAP (ws, s, donePaintScreen);
2792
UNWRAP (ws, s, paintOutput);
2793
UNWRAP (ws, s, paintWindow);
2794
UNWRAP (ws, s, damageWindowRect);
2795
UNWRAP (ws, s, addWindowGeometry);
2796
UNWRAP (ws, s, windowResizeNotify);
2797
UNWRAP (ws, s, windowMoveNotify);
2798
UNWRAP (ws, s, windowGrabNotify);
2799
UNWRAP (ws, s, windowUngrabNotify);
2801
compFiniScreenOptions (s, ws->opt, WOBBLY_SCREEN_OPTION_NUM);
2807
wobblyInitWindow (CompPlugin *p,
2812
WOBBLY_SCREEN (w->screen);
2814
ww = malloc (sizeof (WobblyWindow));
2820
ww->grabbed = FALSE;
2821
ww->state = w->state;
2823
w->base.privates[ws->windowPrivateIndex].ptr = ww;
2825
if (w->mapNum && ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b)
2827
if (isWobblyWin (w))
2828
wobblyEnsureModel (w);
2835
wobblyFiniWindow (CompPlugin *p,
2839
WOBBLY_SCREEN (w->screen);
2841
if (ws->grabWindow == w)
2843
ws->grabWindow = NULL;
2849
free (ww->model->objects);
2857
wobblyInitObject (CompPlugin *p,
2860
static InitPluginObjectProc dispTab[] = {
2861
(InitPluginObjectProc) 0, /* InitCore */
2862
(InitPluginObjectProc) wobblyInitDisplay,
2863
(InitPluginObjectProc) wobblyInitScreen,
2864
(InitPluginObjectProc) wobblyInitWindow
2867
RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
2871
wobblyFiniObject (CompPlugin *p,
2874
static FiniPluginObjectProc dispTab[] = {
2875
(FiniPluginObjectProc) 0, /* FiniCore */
2876
(FiniPluginObjectProc) wobblyFiniDisplay,
2877
(FiniPluginObjectProc) wobblyFiniScreen,
2878
(FiniPluginObjectProc) wobblyFiniWindow
2881
DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
2885
wobblyGetObjectOptions (CompPlugin *plugin,
2889
static GetPluginObjectOptionsProc dispTab[] = {
2890
(GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
2891
(GetPluginObjectOptionsProc) wobblyGetDisplayOptions,
2892
(GetPluginObjectOptionsProc) wobblyGetScreenOptions
2895
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
2896
(void *) (*count = 0), (plugin, object, count));
2900
wobblySetObjectOption (CompPlugin *plugin,
2903
CompOptionValue *value)
2905
static SetPluginObjectOptionProc dispTab[] = {
2906
(SetPluginObjectOptionProc) 0, /* SetCoreOption */
2907
(SetPluginObjectOptionProc) wobblySetDisplayOption,
2908
(SetPluginObjectOptionProc) wobblySetScreenOption
2911
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
2912
(plugin, object, name, value));
2916
wobblyInit (CompPlugin *p)
2918
if (!compInitPluginMetadataFromInfo (&wobblyMetadata,
2920
wobblyDisplayOptionInfo,
2921
WOBBLY_DISPLAY_OPTION_NUM,
2922
wobblyScreenOptionInfo,
2923
WOBBLY_SCREEN_OPTION_NUM))
2926
displayPrivateIndex = allocateDisplayPrivateIndex ();
2927
if (displayPrivateIndex < 0)
2929
compFiniMetadata (&wobblyMetadata);
2933
compAddMetadataFromFile (&wobblyMetadata, p->vTable->name);
2939
wobblyFini (CompPlugin *p)
2941
freeDisplayPrivateIndex (displayPrivateIndex);
2942
compFiniMetadata (&wobblyMetadata);
2945
static CompMetadata *
2946
wobblyGetMetadata (CompPlugin *plugin)
2948
return &wobblyMetadata;
2951
CompPluginVTable wobblyVTable = {
2958
wobblyGetObjectOptions,
2959
wobblySetObjectOption
2963
getCompPluginInfo20070830 (void)
2965
return &wobblyVTable;