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