remove a dispatch.h
[dana/openbox.git] / openbox / resist.c
1 #include "client.h"
2 #include "frame.h"
3 #include "stacking.h"
4 #include "screen.h"
5 #include "config.h"
6 #include "parser/parse.h"
7
8 #include <glib.h>
9
10 void resist_move(ObClient *c, gint *x, gint *y)
11 {
12     GList *it;
13     Rect *area;
14     guint i;
15     gint l, t, r, b; /* requested edges */
16     gint al, at, ar, ab; /* screen area edges */
17     gint cl, ct, cr, cb; /* current edges */
18     gint w, h; /* current size */
19     ObClient *snapx = NULL, *snapy = NULL;
20
21     w = c->frame->area.width;
22     h = c->frame->area.height;
23
24     l = *x;
25     t = *y;
26     r = l + w - 1;
27     b = t + h - 1;
28
29     cl = c->frame->area.x;
30     ct = c->frame->area.y;
31     cr = cl + c->frame->area.width - 1;
32     cb = ct + c->frame->area.height - 1;
33     
34     /* snap to other clients */
35     if (config_resist_win)
36         for (it = stacking_list; it != NULL; it = it->next) {
37             ObClient *target;
38             int tl, tt, tr, tb; /* 1 past the target's edges on each side */
39
40             if (!WINDOW_IS_CLIENT(it->data))
41                 continue;
42             target = it->data;
43             /* don't snap to self or non-visibles */
44             if (!target->frame->visible || target == c) continue; 
45
46             tl = target->frame->area.x - 1;
47             tt = target->frame->area.y - 1;
48             tr = tl + target->frame->area.width + 1;
49             tb = tt + target->frame->area.height + 1;
50
51             /* snapx and snapy ensure that the window snaps to the top-most
52                window edge available, without going all the way from
53                bottom-to-top in the stacking list
54             */
55             if (snapx == NULL) {
56                 if (ct < tb && cb > tt) {
57                     if (cl >= tr && l < tr && l >= tr - config_resist_win)
58                         *x = tr, snapx = target;
59                     else if (cr <= tl && r > tl &&
60                              r <= tl + config_resist_win)
61                         *x = tl - w + 1, snapx = target;
62                     if (snapx != NULL) {
63                         /* try to corner snap to the window */
64                         if (ct > tt && t <= tt &&
65                             t > tt - config_resist_win)
66                             *y = tt + 1, snapy = target;
67                         else if (cb < tb && b >= tb &&
68                                  b < tb + config_resist_win)
69                             *y = tb - h, snapy = target;
70                     }
71                 }
72             }
73             if (snapy == NULL) {
74                 if (cl < tr && cr > tl) {
75                     if (ct >= tb && t < tb && t >= tb - config_resist_win)
76                         *y = tb, snapy = target;
77                     else if (cb <= tt && b > tt &&
78                              b <= tt + config_resist_win)
79                         *y = tt - h + 1, snapy = target;
80                     if (snapy != NULL) {
81                         /* try to corner snap to the window */
82                         if (cl > tl && l <= tl &&
83                             l > tl - config_resist_win)
84                             *x = tl + 1, snapx = target;
85                         else if (cr < tr && r >= tr &&
86                                  r < tr + config_resist_win)
87                             *x = tr - w, snapx = target;
88                     }
89                 }
90             }
91
92             if (snapx && snapy) break;
93         }
94
95     /* get the screen boundaries */
96     if (config_resist_edge) {
97         for (i = 0; i < screen_num_monitors; ++i) {
98             area = screen_area_monitor(c->desktop, i);
99
100             if (!RECT_INTERSECTS_RECT(*area, c->frame->area))
101                 continue;
102
103             al = area->x;
104             at = area->y;
105             ar = al + area->width - 1;
106             ab = at + area->height - 1;
107
108             /* snap to screen edges */
109             if (cl >= al && l < al && l >= al - config_resist_edge)
110                 *x = al;
111             else if (cr <= ar && r > ar && r <= ar + config_resist_edge)
112                 *x = ar - w + 1;
113             if (ct >= at && t < at && t >= at - config_resist_edge)
114                 *y = at;
115             else if (cb <= ab && b > ab && b < ab + config_resist_edge)
116                 *y = ab - h + 1;
117         }
118     }
119 }
120
121 void resist_size(ObClient *c, gint *w, gint *h, ObCorner corn)
122 {
123     GList *it;
124     ObClient *target; /* target */
125     gint l, t, r, b; /* my left, top, right and bottom sides */
126     gint dlt, drb; /* my destination left/top and right/bottom sides */
127     gint tl, tt, tr, tb; /* target's left, top, right and bottom bottom sides*/
128     Rect *area;
129     gint al, at, ar, ab; /* screen boundaries */
130     ObClient *snapx = NULL, *snapy = NULL;
131
132     /* don't snap windows with size increments */
133     if (c->size_inc.width > 1 || c->size_inc.height > 1)
134         return;
135
136     l = c->frame->area.x;
137     r = l + c->frame->area.width - 1;
138     t = c->frame->area.y;
139     b = t + c->frame->area.height - 1;
140
141     /* get the screen boundaries */
142     area = screen_area(c->desktop);
143     al = area->x;
144     at = area->y;
145     ar = al + area->width - 1;
146     ab = at + area->height - 1;
147
148     /* snap to other windows */
149     if (config_resist_win) {
150         for (it = stacking_list; it != NULL; it = it->next) {
151             if (!WINDOW_IS_CLIENT(it->data))
152                 continue;
153             target = it->data;
154
155             /* don't snap to invisibles or ourself */
156             if (!target->frame->visible || target == c) continue;
157
158             tl = target->frame->area.x;
159             tr = target->frame->area.x + target->frame->area.width - 1;
160             tt = target->frame->area.y;
161             tb = target->frame->area.y + target->frame->area.height - 1;
162
163             if (snapx == NULL) {
164                 /* horizontal snapping */
165                 if (t < tb && b > tt) {
166                     switch (corn) {
167                     case OB_CORNER_TOPLEFT:
168                     case OB_CORNER_BOTTOMLEFT:
169                         dlt = l;
170                         drb = r + *w - c->frame->area.width;
171                         if (r < tl && drb >= tl &&
172                             drb < tl + config_resist_win)
173                             *w = tl - l, snapx = target;
174                         break;
175                     case OB_CORNER_TOPRIGHT:
176                     case OB_CORNER_BOTTOMRIGHT:
177                         dlt = l - *w + c->frame->area.width;
178                         drb = r;
179                         if (l > tr && dlt <= tr &&
180                             dlt > tr - config_resist_win)
181                             *w = r - tr, snapx = target;
182                         break;
183                     }
184                 }
185             }
186
187             if (snapy == NULL) {
188                 /* vertical snapping */
189                 if (l < tr && r > tl) {
190                     switch (corn) {
191                     case OB_CORNER_TOPLEFT:
192                     case OB_CORNER_TOPRIGHT:
193                         dlt = t;
194                         drb = b + *h - c->frame->area.height;
195                         if (b < tt && drb >= tt &&
196                             drb < tt + config_resist_win)
197                             *h = tt - t, snapy = target;
198                         break;
199                     case OB_CORNER_BOTTOMLEFT:
200                     case OB_CORNER_BOTTOMRIGHT:
201                         dlt = t - *h + c->frame->area.height;
202                         drb = b;
203                         if (t > tb && dlt <= tb &&
204                             dlt > tb - config_resist_win)
205                             *h = b - tb, snapy = target;
206                         break;
207                     }
208                 }
209             }
210
211             /* snapped both ways */
212             if (snapx && snapy) break;
213         }
214     }
215
216     /* snap to screen edges */
217
218     if (config_resist_edge) {
219         /* horizontal snapping */
220         switch (corn) {
221         case OB_CORNER_TOPLEFT:
222         case OB_CORNER_BOTTOMLEFT:
223             dlt = l;
224             drb = r + *w - c->frame->area.width;
225             if (r <= ar && drb > ar && drb <= ar + config_resist_edge)
226                 *w = ar - l + 1;
227             break;
228         case OB_CORNER_TOPRIGHT:
229         case OB_CORNER_BOTTOMRIGHT:
230             dlt = l - *w + c->frame->area.width;
231             drb = r;
232             if (l >= al && dlt < al && dlt >= al - config_resist_edge)
233                 *w = r - al + 1;
234             break;
235         }
236
237         /* vertical snapping */
238         switch (corn) {
239         case OB_CORNER_TOPLEFT:
240         case OB_CORNER_TOPRIGHT:
241             dlt = t;
242             drb = b + *h - c->frame->area.height;
243             if (b <= ab && drb > ab && drb <= ab + config_resist_edge)
244                 *h = ab - t + 1;
245             break;
246         case OB_CORNER_BOTTOMLEFT:
247         case OB_CORNER_BOTTOMRIGHT:
248             dlt = t - *h + c->frame->area.height;
249             drb = b;
250             if (t >= at && dlt < at && dlt >= at - config_resist_edge)
251                 *h = b - at + 1;
252             break;
253         }
254     }
255 }