Convert over to use GetOpt::Long and introduce -f and -h.
[fvwm.git] / libs / gravity.c
blob96ef3e48630b09786e8aab86cdd51d3fe50986c5
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_NW:
309 case DIR_SW:
310 dir_x = DIR_W;
311 break;
312 case DIR_NE:
313 case DIR_SE:
314 dir_x = DIR_E;
315 break;
316 default:
317 dir_x = DIR_NONE;
318 break;
320 switch (dir_y)
322 case DIR_NW:
323 case DIR_NE:
324 dir_y = DIR_N;
325 break;
326 case DIR_SW:
327 case DIR_SE:
328 dir_y = DIR_S;
329 break;
330 default:
331 dir_y = DIR_NONE;
332 break;
334 if (dir_x == DIR_NONE)
336 return dir_y;
338 switch (dir_y)
340 case DIR_N:
341 return (dir_x == DIR_W) ? DIR_NW : DIR_NE;
342 case DIR_S:
343 return (dir_x == DIR_W) ? DIR_SW : DIR_SE;
344 case DIR_NONE:
345 default:
346 return dir_x;
350 void gravity_split_xy_dir(
351 int *ret_dir_x, int *ret_dir_y, int in_dir)
353 switch (in_dir)
355 case DIR_W:
356 case DIR_SW:
357 case DIR_NW:
358 *ret_dir_x = DIR_W;
359 break;
360 case DIR_E:
361 case DIR_NE:
362 case DIR_SE:
363 *ret_dir_x = DIR_E;
364 break;
365 case DIR_N:
366 case DIR_S:
367 case DIR_NONE:
368 default:
369 *ret_dir_x = DIR_NONE;
370 break;
372 switch (in_dir)
374 case DIR_N:
375 case DIR_NW:
376 case DIR_NE:
377 *ret_dir_y = DIR_N;
378 break;
379 case DIR_S:
380 case DIR_SW:
381 case DIR_SE:
382 *ret_dir_y = DIR_S;
383 break;
384 case DIR_W:
385 case DIR_E:
386 case DIR_NONE:
387 default:
388 *ret_dir_y = DIR_NONE;
389 break;
393 int gravity_dir_to_sign_one_axis(
394 direction_t dir)
396 switch (dir)
398 case DIR_N:
399 case DIR_W:
400 return -1;
401 case DIR_S:
402 case DIR_E:
403 return 1;
404 default:
405 return 0;
409 /* Parses the next token in action and returns
411 * 0 if it is N, North, Top or Up
412 * 1 if it is E, East, Right or Right
413 * 2 if it is S, South, Bottom or Down
414 * 3 if it is E, West, Left or Left
415 * 4 if it is NE, NorthEast, TopRight or UpRight
416 * 5 if it is SE, SouthEast, BottomRight or DownRight
417 * 6 if it is SW, SouthWest, BottomLeft or DownLeft
418 * 7 if it is NW, NorthWest, TopLeft or UpLeft
419 * 8 if it is C, Center or Centre
420 * default_ret if no string matches.
422 * A pointer to the first character in action behind the token is returned
423 * through ret_action in this case. ret_action may be NULL. If the token
424 * matches none of these strings the default_ret value is returned and the
425 * action itself is passed back in ret_action. */
426 direction_t gravity_parse_dir_argument(
427 char *action, char **ret_action, direction_t default_ret)
429 int index;
430 int rc;
431 char *next;
433 next = GetNextTokenIndex(action, gravity_dir_optlist, 0, &index);
434 if (index == -1)
436 /* nothing selected, use default and don't modify action */
437 rc = default_ret;
438 next = action;
440 else
442 rc = index / STRINGS_PER_DIR;
444 if (ret_action)
446 *ret_action = next;
449 return (direction_t)rc;
452 char *gravity_dir_to_string(direction_t dir, char *default_str)
454 char *str = NULL;
455 int d = dir * STRINGS_PER_DIR;
457 if (d >= sizeof(gravity_dir_optlist)/sizeof(gravity_dir_optlist[0]))
459 return default_str;
461 str = gravity_dir_optlist[d];
463 if (str == NULL)
465 return default_str;
468 return str;
471 multi_direction_t gravity_parse_multi_dir_argument(
472 char *action, char **ret_action)
474 int rc = MULTI_DIR_NONE;
475 char *token, *str;
476 direction_t dir = gravity_parse_dir_argument(action, ret_action, -1);
478 if (dir != -1)
480 rc = (1 << dir);
482 else
484 token = PeekToken(action, &str);
485 if (StrEquals(token, "all"))
487 rc = MULTI_DIR_ALL;
488 *ret_action = str;
490 else
492 rc = MULTI_DIR_NONE;
496 return (multi_direction_t)rc;
499 void gravity_get_next_multi_dir(int dir_set, multi_direction_t *dir)
501 if (*dir == MULTI_DIR_NONE)
503 *dir = MULTI_DIR_FIRST;
504 if (dir_set & *dir)
506 return;
509 while(*dir != MULTI_DIR_LAST)
511 *dir = (*dir << 1);
512 if (dir_set & *dir)
514 return;
517 *dir = MULTI_DIR_NONE;
519 return;
522 direction_t gravity_multi_dir_to_dir(multi_direction_t mdir)
524 direction_t dir = DIR_NONE;
526 for ( ; mdir != 0; dir++)
528 mdir = (mdir >> 1);
530 if (dir > DIR_ALL_MASK)
532 dir = DIR_NONE;
535 return dir;
538 void gravity_rotate_xy(rotation_t rot, int x, int y, int *ret_x, int *ret_y)
540 int tx;
541 int ty;
543 switch (rot)
545 case ROTATION_90:
546 /* CW */
547 tx = -y;
548 ty = x;
549 break;
550 case ROTATION_180:
551 tx = -x;
552 ty = -y;
553 break;
554 case ROTATION_270:
555 /* CCW */
556 tx = y;
557 ty = -x;
558 break;
559 default:
560 case ROTATION_0:
561 tx = x;
562 ty = y;
563 break;
565 *ret_x = tx;
566 *ret_y = ty;
568 return;
571 rotation_t gravity_add_rotations(rotation_t rot1, rotation_t rot2)
573 rotation_t rot;
575 rot = ((rot1 + rot2) & ROTATION_MASK);
577 return rot;