cvsimport
[fvwm.git] / libs / gravity.c
blob7c4f53fd75bb302db6d958b835bbcce11a9ad2e6
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 /* ---------------------------- included header files ---------------------- */
19 #include "config.h"
21 #include <stdio.h>
23 #include <X11/Xlib.h>
24 #include "fvwmlib.h"
25 #include "Parse.h"
26 #include "Strings.h"
27 #include "gravity.h"
29 /* ---------------------------- local definitions -------------------------- */
31 /* ---------------------------- local macros ------------------------------- */
33 /* ---------------------------- imports ------------------------------------ */
35 /* ---------------------------- included code files ------------------------ */
37 /* ---------------------------- local types -------------------------------- */
39 struct _gravity_offset
41 int x, y;
44 /* ---------------------------- forward declarations ----------------------- */
46 /* ---------------------------- local variables ---------------------------- */
48 #define STRINGS_PER_DIR 7
49 static char *gravity_dir_optlist[] = {
50 "-", "N", "North", "Top", "t", "Up", "u",
51 "]", "E", "East", "Right", "r", "Right", "r",
52 "_", "S", "South", "Bottom", "b", "Down", "d",
53 "[", "W", "West", "Left", "l", "Left", "l",
54 "^", "NE", "NorthEast", "TopRight", "tr", "UpRight", "ur",
55 ">", "SE", "SouthEast", "BottomRight", "br", "DownRight", "dr",
56 "v", "SW", "SouthWest", "BottomLeft", "bl", "DownLeft", "dl",
57 "<", "NW", "NorthWest", "TopLeft", "tl", "UpLeft", "ul",
58 ".", "C", "Center", "Centre", NULL, NULL, NULL,
59 NULL
62 /* ---------------------------- exported variables (globals) --------------- */
64 /* ---------------------------- local functions ---------------------------- */
66 /* ---------------------------- interface functions ------------------------ */
68 /* map gravity to (x,y) offset signs for adding to x and y when window is
69 * mapped to get proper placement. */
70 void gravity_get_offsets(int grav, int *xp,int *yp)
72 static struct _gravity_offset gravity_offsets[11] = {
73 { 0, 0 }, /* ForgetGravity */
74 { -1, -1 }, /* NorthWestGravity */
75 { 0, -1 }, /* NorthGravity */
76 { 1, -1 }, /* NorthEastGravity */
77 { -1, 0 }, /* WestGravity */
78 { 0, 0 }, /* CenterGravity */
79 { 1, 0 }, /* EastGravity */
80 { -1, 1 }, /* SouthWestGravity */
81 { 0, 1 }, /* SouthGravity */
82 { 1, 1 }, /* SouthEastGravity */
83 { 0, 0 }, /* StaticGravity */
86 if (grav < ForgetGravity || grav > StaticGravity)
88 *xp = *yp = 0;
90 else
92 *xp = (int)gravity_offsets[grav].x;
93 *yp = (int)gravity_offsets[grav].y;
96 return;
99 /* Move a rectangle while taking gravity into account. */
100 void gravity_move(int gravity, rectangle *rect, int xdiff, int ydiff)
102 int xoff;
103 int yoff;
105 gravity_get_offsets(gravity, &xoff, &yoff);
106 rect->x -= xoff * xdiff;
107 rect->y -= yoff * ydiff;
109 return;
112 /* Resize rectangle while taking gravity into account. */
113 void gravity_resize(int gravity, rectangle *rect, int wdiff, int hdiff)
115 int xoff;
116 int yoff;
118 gravity_get_offsets(gravity, &xoff, &yoff);
119 rect->x -= (wdiff * (xoff + 1)) / 2;
120 rect->width += wdiff;
121 rect->y -= (hdiff * (yoff + 1)) / 2;
122 rect->height += hdiff;
124 return;
127 /* Moves a child rectangle taking its gravity into accout as if the parent
128 * rectangle was moved and resized. */
129 void gravity_move_resize_parent_child(
130 int child_gravity, rectangle *parent_diff_r, rectangle *child_r)
132 int xoff;
133 int yoff;
135 gravity_get_offsets(child_gravity, &xoff, &yoff);
136 child_r->x -= xoff * parent_diff_r->x;
137 child_r->y -= yoff * parent_diff_r->y;
138 child_r->x += ((xoff + 1) * parent_diff_r->width) / 2;
139 child_r->y += ((yoff + 1) * parent_diff_r->height) / 2;
141 return;
144 direction_t gravity_grav_to_dir(
145 int grav)
147 switch (grav)
149 case NorthWestGravity:
150 return DIR_NW;
151 case NorthGravity:
152 return DIR_N;
153 case NorthEastGravity:
154 return DIR_NE;
155 case WestGravity:
156 return DIR_W;
157 case CenterGravity:
158 return DIR_NONE;
159 case EastGravity:
160 return DIR_E;
161 case SouthWestGravity:
162 return DIR_SW;
163 case SouthGravity:
164 return DIR_S;
165 case SouthEastGravity:
166 return DIR_SE;
167 case ForgetGravity:
168 case StaticGravity:
169 default:
170 return DIR_NONE;
174 int gravity_dir_to_grav(
175 direction_t dir)
177 switch (dir)
179 case DIR_N:
180 return NorthGravity;
181 case DIR_E:
182 return EastGravity;
183 case DIR_S:
184 return SouthGravity;
185 case DIR_W:
186 return WestGravity;
187 case DIR_NE:
188 return NorthEastGravity;
189 case DIR_SE:
190 return SouthEastGravity;
191 case DIR_SW:
192 return SouthWestGravity;
193 case DIR_NW:
194 return NorthWestGravity;
195 case DIR_NONE:
196 default:
197 return ForgetGravity;
201 int gravity_combine_xy_grav(
202 int grav_x, int grav_y)
204 switch (grav_x)
206 case NorthWestGravity:
207 case WestGravity:
208 case SouthWestGravity:
209 grav_x = WestGravity;
210 break;
211 case NorthEastGravity:
212 case EastGravity:
213 case SouthEastGravity:
214 grav_x = EastGravity;
215 break;
216 default:
217 grav_x = CenterGravity;
218 break;
220 switch (grav_y)
222 case NorthWestGravity:
223 case NorthGravity:
224 case NorthEastGravity:
225 grav_y = NorthGravity;
226 break;
227 case SouthWestGravity:
228 case SouthGravity:
229 case SouthEastGravity:
230 grav_y = SouthGravity;
231 break;
232 default:
233 grav_y = CenterGravity;
234 break;
236 if (grav_x == CenterGravity)
238 return grav_y;
240 switch (grav_y)
242 case NorthGravity:
243 return (grav_x == WestGravity) ?
244 NorthWestGravity : NorthEastGravity;
245 case SouthGravity:
246 return (grav_x == WestGravity) ?
247 SouthWestGravity : SouthEastGravity;
248 case CenterGravity:
249 default:
250 return grav_x;
253 return 0;
256 void gravity_split_xy_grav(
257 int *ret_grav_x, int *ret_grav_y, int in_grav)
259 switch (in_grav)
261 case NorthWestGravity:
262 case WestGravity:
263 case SouthWestGravity:
264 *ret_grav_x = WestGravity;
265 break;
266 case NorthEastGravity:
267 case EastGravity:
268 case SouthEastGravity:
269 *ret_grav_x = EastGravity;
270 break;
271 case NorthGravity:
272 case CenterGravity:
273 case SouthGravity:
274 case ForgetGravity:
275 case StaticGravity:
276 default:
277 *ret_grav_x = CenterGravity;
278 break;
280 switch (in_grav)
282 case NorthWestGravity:
283 case NorthGravity:
284 case NorthEastGravity:
285 *ret_grav_y = NorthGravity;
286 break;
287 case SouthWestGravity:
288 case SouthGravity:
289 case SouthEastGravity:
290 *ret_grav_y = SouthGravity;
291 break;
292 case WestGravity:
293 case CenterGravity:
294 case EastGravity:
295 case ForgetGravity:
296 case StaticGravity:
297 default:
298 *ret_grav_y = CenterGravity;
299 break;
303 int gravity_combine_xy_dir(
304 int dir_x, int dir_y)
306 switch (dir_x)
308 case DIR_W:
309 case DIR_NW:
310 case DIR_SW:
311 dir_x = DIR_W;
312 break;
313 case DIR_E:
314 case DIR_NE:
315 case DIR_SE:
316 dir_x = DIR_E;
317 break;
318 default:
319 dir_x = DIR_NONE;
320 break;
322 switch (dir_y)
324 case DIR_N:
325 case DIR_NW:
326 case DIR_NE:
327 dir_y = DIR_N;
328 break;
329 case DIR_S:
330 case DIR_SW:
331 case DIR_SE:
332 dir_y = DIR_S;
333 break;
334 default:
335 dir_y = DIR_NONE;
336 break;
338 if (dir_x == DIR_NONE)
340 return dir_y;
342 switch (dir_y)
344 case DIR_N:
345 return (dir_x == DIR_W) ? DIR_NW : DIR_NE;
346 case DIR_S:
347 return (dir_x == DIR_W) ? DIR_SW : DIR_SE;
348 case DIR_NONE:
349 default:
350 return dir_x;
354 void gravity_split_xy_dir(
355 int *ret_dir_x, int *ret_dir_y, int in_dir)
357 switch (in_dir)
359 case DIR_W:
360 case DIR_SW:
361 case DIR_NW:
362 *ret_dir_x = DIR_W;
363 break;
364 case DIR_E:
365 case DIR_NE:
366 case DIR_SE:
367 *ret_dir_x = DIR_E;
368 break;
369 case DIR_N:
370 case DIR_S:
371 case DIR_NONE:
372 default:
373 *ret_dir_x = DIR_NONE;
374 break;
376 switch (in_dir)
378 case DIR_N:
379 case DIR_NW:
380 case DIR_NE:
381 *ret_dir_y = DIR_N;
382 break;
383 case DIR_S:
384 case DIR_SW:
385 case DIR_SE:
386 *ret_dir_y = DIR_S;
387 break;
388 case DIR_W:
389 case DIR_E:
390 case DIR_NONE:
391 default:
392 *ret_dir_y = DIR_NONE;
393 break;
397 static inline int __gravity_override_one_axis(int dir_orig, int dir_mod)
399 int ret_dir;
401 if (dir_mod == DIR_NONE)
403 ret_dir = dir_orig;
405 else
407 ret_dir = dir_mod;
410 return ret_dir;
413 int gravity_override_dir(
414 int dir_orig, int dir_mod)
416 int ret_dir;
417 int ret_x;
418 int ret_y;
419 int orig_x;
420 int orig_y;
421 int mod_x;
422 int mod_y;
424 gravity_split_xy_dir(&orig_x, &orig_y, dir_orig);
425 gravity_split_xy_dir(&mod_x, &mod_y, dir_mod);
426 ret_x = __gravity_override_one_axis(orig_x, mod_x);
427 ret_y = __gravity_override_one_axis(orig_y, mod_y);
428 ret_dir = gravity_combine_xy_dir(ret_x, ret_y);
430 return ret_dir;
433 int gravity_dir_to_sign_one_axis(
434 direction_t dir)
436 switch (dir)
438 case DIR_N:
439 case DIR_W:
440 return -1;
441 case DIR_S:
442 case DIR_E:
443 return 1;
444 default:
445 return 0;
449 /* Parses the next token in action and returns
451 * 0 if it is N, North, Top or Up
452 * 1 if it is E, East, Right or Right
453 * 2 if it is S, South, Bottom or Down
454 * 3 if it is E, West, Left or Left
455 * 4 if it is NE, NorthEast, TopRight or UpRight
456 * 5 if it is SE, SouthEast, BottomRight or DownRight
457 * 6 if it is SW, SouthWest, BottomLeft or DownLeft
458 * 7 if it is NW, NorthWest, TopLeft or UpLeft
459 * 8 if it is C, Center or Centre
460 * default_ret if no string matches.
462 * A pointer to the first character in action behind the token is returned
463 * through ret_action in this case. ret_action may be NULL. If the token
464 * matches none of these strings the default_ret value is returned and the
465 * action itself is passed back in ret_action. */
466 direction_t gravity_parse_dir_argument(
467 char *action, char **ret_action, direction_t default_ret)
469 int index;
470 int rc;
471 char *next;
473 next = GetNextTokenIndex(action, gravity_dir_optlist, 0, &index);
474 if (index == -1)
476 /* nothing selected, use default and don't modify action */
477 rc = default_ret;
478 next = action;
480 else
482 rc = index / STRINGS_PER_DIR;
484 if (ret_action)
486 *ret_action = next;
489 return (direction_t)rc;
492 char *gravity_dir_to_string(direction_t dir, char *default_str)
494 char *str = NULL;
495 int d = dir * STRINGS_PER_DIR;
497 if (d >= sizeof(gravity_dir_optlist)/sizeof(gravity_dir_optlist[0]))
499 return default_str;
501 str = gravity_dir_optlist[d];
503 if (str == NULL)
505 return default_str;
508 return str;
511 multi_direction_t gravity_parse_multi_dir_argument(
512 char *action, char **ret_action)
514 int rc = MULTI_DIR_NONE;
515 char *token, *str;
516 direction_t dir = gravity_parse_dir_argument(action, ret_action, -1);
518 if (dir != -1)
520 rc = (1 << dir);
522 else
524 token = PeekToken(action, &str);
525 if (StrEquals(token, "all"))
527 rc = MULTI_DIR_ALL;
528 *ret_action = str;
530 else
532 rc = MULTI_DIR_NONE;
536 return (multi_direction_t)rc;
539 void gravity_get_next_multi_dir(int dir_set, multi_direction_t *dir)
541 if (*dir == MULTI_DIR_NONE)
543 *dir = MULTI_DIR_FIRST;
544 if (dir_set & *dir)
546 return;
549 while(*dir != MULTI_DIR_LAST)
551 *dir = (*dir << 1);
552 if (dir_set & *dir)
554 return;
557 *dir = MULTI_DIR_NONE;
559 return;
562 direction_t gravity_multi_dir_to_dir(multi_direction_t mdir)
564 direction_t dir = DIR_NONE;
566 for ( ; mdir != 0; dir++)
568 mdir = (mdir >> 1);
570 if (dir > DIR_ALL_MASK)
572 dir = DIR_NONE;
575 return dir;
578 void gravity_rotate_xy(rotation_t rot, int x, int y, int *ret_x, int *ret_y)
580 int tx;
581 int ty;
583 switch (rot)
585 case ROTATION_90:
586 /* CW */
587 tx = -y;
588 ty = x;
589 break;
590 case ROTATION_180:
591 tx = -x;
592 ty = -y;
593 break;
594 case ROTATION_270:
595 /* CCW */
596 tx = y;
597 ty = -x;
598 break;
599 default:
600 case ROTATION_0:
601 tx = x;
602 ty = y;
603 break;
605 *ret_x = tx;
606 *ret_y = ty;
608 return;
611 rotation_t gravity_add_rotations(rotation_t rot1, rotation_t rot2)
613 rotation_t rot;
615 rot = ((rot1 + rot2) & ROTATION_MASK);
617 return rot;