Fix move command parsing.
[fvwm.git] / libs / WinMagic.c
blob752ffc3f1f05b2e7069f3fbb5ed44fdbfa8d415e
1 /* -*-c-*- */
2 /* Copyright (C) 1999 Dominik Vogt */
3 /* This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 ** WinMagic.c:
20 ** This file supplies routines for moving and resizing windows in an animated
21 ** fashion.
24 #include "config.h"
26 #include <X11/Xlib.h>
27 #include <fvwmlib.h>
28 #include <stdio.h>
29 #include "WinMagic.h"
31 /* Continuously moves and resized window win from start geometry (s_?) to end
32 * geometry (e_?). Waits for delay_ms milliseconds after each step except the
33 * last (max. 10 seconds per step). The number of steps is determined by the
34 * steps argument (min. 1 and max. 10000). If the pointer ppctMovement is NULL
35 * the steps are all the same width, if it is given it is interpreted as a
36 * pointer to an array of float percent values. These are used to determine the
37 * distance of each step counted from the start position, i.e. 0.0 means the
38 * start position itself, 50.0 is halfway between start and end position and
39 * 100.0 is the end position. Values smaller than 0.0 or bigger than 100.0 are
40 * allowed too. The do_flush flag determines of all requests are sent to the
41 * X server immediately (True) or not (False). The use_hints detrmines if the
42 * min size and resize hints are used */
43 void SlideWindow(
44 Display *dpy, Window win,
45 int s_x, int s_y, int s_w, int s_h,
46 int e_x, int e_y, int e_w, int e_h,
47 int steps, int delay_ms, float *ppctMovement,
48 Bool do_sync, Bool use_hints)
50 int x = 0;
51 int y = 0;
52 int w = 0;
53 int h = 0;
54 int g_w = 0;
55 int g_h = 0; /* -Wall fixes :o( */
56 int min_w = 1;
57 int min_h = 1;
58 int inc_w = 1;
59 int inc_h = 1;
60 int i;
61 unsigned int us;
62 Bool is_mapped;
63 Bool keep_x1 = False;
64 Bool keep_x2 = False;
65 Bool keep_y1 = False;
66 Bool keep_y2 = False;
67 XSizeHints hints;
68 long dummy;
70 /* check limits */
71 if (delay_ms > 10000)
73 /* max. 10 seconds per step */
74 us = 10000000;
76 else if (delay_ms < 0)
78 us = 0;
80 else
82 us = 1000 * delay_ms;
85 if (steps > 10000)
87 /* max. 10000 steps */
88 steps = 10000;
90 if (steps <= 0)
92 /* no steps, no animation */
93 if (e_w == 0 || e_h == 0)
95 XUnmapWindow(dpy, win);
97 else
99 XMoveResizeWindow(dpy, win, e_x, e_y, e_w, e_h);
100 XMapWindow(dpy, win);
101 XMapSubwindows(dpy, win);
103 if (do_sync)
104 XSync(dpy, 0);
105 return;
108 is_mapped = False;
110 /* Get the mini (re)size hints and do some check consistency */
111 if (use_hints && XGetWMNormalHints(dpy, win, &hints, &dummy))
113 if (hints.flags & PMinSize)
115 if (hints.min_width >= 1 && hints.min_width <=
116 max(e_w,s_w))
117 min_w = hints.min_width;
118 if (hints.min_height >= 1 && hints.min_height <=
119 max(e_h,s_h))
120 min_h = hints.min_height;
122 if (hints.flags & PResizeInc)
124 if (hints.width_inc >= 1 && hints.width_inc <=
125 max(e_w,s_w))
126 inc_w = hints.width_inc;
127 if (hints.height_inc >= 1 && hints.width_inc <=
128 max(e_h,s_h))
129 inc_h = hints.height_inc;
133 if (s_x == e_x)
134 keep_x1 = True;
135 if (s_y == e_y)
136 keep_y1 = True;
137 if (s_x + s_w == e_x + e_w)
138 keep_x2 = True;
139 if (s_y + s_h == e_y + e_h)
140 keep_y2 = True;
142 /* animate the window */
143 for (i = 0; i <= steps; i++)
145 if (i == steps)
147 x = e_x;
148 y = e_y;
150 else
152 float f;
154 if (ppctMovement == NULL)
156 f = (float)i / (float)steps;
158 else
160 f = ppctMovement[i] / (float)steps;
162 x = (int)((float)s_x + (float)(e_x - s_x) * f);
163 y = (int)((float)s_y + (float)(e_y - s_y) * f);
165 w = s_w + (int)(e_w - s_w) * i / steps;
166 h = s_h + (int)(e_h - s_h) * i / steps;
168 /* take the resize inc in account */
169 g_w = w - ((w - min_w) % inc_w);
170 x += w-g_w;
171 g_h = h - ((h - min_h) % inc_h);
172 y += h-g_h;
174 /* prevent annoying flickering */
175 if (keep_x1)
176 x = s_x;
177 if (keep_y1)
178 y = s_y;
179 if (keep_x2)
180 g_w = s_x + s_w - x;
181 if (keep_y2)
182 g_h = s_y + s_h - y;
184 if (g_w < min_w || g_h < min_h)
186 /* don't show zero width/height windows */
187 if (is_mapped)
189 XUnmapWindow(dpy, win);
190 is_mapped = False;
193 else
195 XMoveResizeWindow(dpy, win, x, y, g_w, g_h);
196 if (!is_mapped)
198 XMapWindow(dpy, win);
199 XMapSubwindows(dpy, win);
200 is_mapped = True;
203 /* make sure everything is updated */
204 if (do_sync)
205 XSync(dpy, 0);
206 if (us && i < steps && is_mapped)
208 /* don't sleep after the last step */
209 usleep(us);
211 } /* for */
213 /* if hints and asked size do not agree try to respect the caller */
214 if (e_w > 0 && e_h > 0 && (!is_mapped || g_w != w || g_h != w))
216 XMoveResizeWindow(dpy, win, x, y, w, h);
217 if (!is_mapped)
219 XMapWindow(dpy, win);
220 XMapSubwindows(dpy, win);
222 if (do_sync)
223 XSync(dpy, 0);
225 return;
228 /* This function returns the top level ancestor of the window 'child'. It
229 * returns None if an error occurs or if the window is a top level window. */
230 Window GetTopAncestorWindow(Display *dpy, Window child)
232 Window root = None;
233 Window ancestor = child;
234 Window last_child = child;
235 Window *children;
236 unsigned int nchildren;
238 if (child == None)
239 return None;
241 while (ancestor != root)
243 last_child = ancestor;
244 children = NULL;
245 if (
246 !XQueryTree(
247 dpy, last_child, &root, &ancestor, &children,
248 &nchildren))
250 return None;
252 if (children)
254 XFree(children);
258 return (last_child == child) ? None : last_child;
261 /* Given a parent window this function returns a list of children of the
262 * parent window that have the same size, depth, visual and colormap as the
263 * parent window and that have position +0+0 within the parent. If the 'depth'
264 * argument is non-zero it must match the depth of the window. The 'visualid'
265 * and 'colormap' arguments work just the same. The number of matching
266 * children is returned. The list of children is returned in *children. If this
267 * list is non-NULL, it must be free'd with XFree. If an error occurs or the
268 * parent window does not match the required depth, colormap or visualid, the
269 * function returns -1 and NULL in *children. */
270 int GetEqualSizeChildren(
271 Display *dpy, Window parent, int depth, VisualID visualid,
272 Colormap colormap, Window **ret_children)
274 XWindowAttributes pxwa;
275 XWindowAttributes cxwa;
276 Window JunkW;
277 Window *children;
278 unsigned int nchildren;
279 int i;
280 int j;
282 if (!XGetWindowAttributes(dpy, parent, &pxwa))
283 return -1;
284 if (!XQueryTree(dpy, parent, &JunkW, &JunkW, &children, &nchildren))
285 return -1;
286 if (depth && pxwa.depth != depth)
287 return -1;
288 if (visualid && XVisualIDFromVisual(pxwa.visual) != visualid)
289 return -1;
290 if (colormap && pxwa.colormap != colormap)
291 return -1;
293 for (i = 0, j = 0; i < nchildren; i++)
295 if (XGetWindowAttributes(dpy, children[i], &cxwa) &&
296 cxwa.x == 0 &&
297 cxwa.y == 0 &&
298 cxwa.width == pxwa.width &&
299 cxwa.height == pxwa.height &&
300 (!depth || cxwa.depth == depth) &&
302 !visualid ||
303 XVisualIDFromVisual(cxwa.visual) == visualid) &&
304 cxwa.class == InputOutput &&
305 (!colormap || cxwa.colormap == colormap))
307 children[j++] = children[i];
309 } /* for */
311 if (j == 0)
313 if (children)
315 XFree(children);
316 children = NULL;
319 *ret_children = children;
321 return j;