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.
6  *
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.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, see: <http://www.gnu.org/licenses/>
14  */
15 
16 /* ---------------------------- included header files ---------------------- */
17 
18 #include "config.h"
19 
20 #include <stdio.h>
21 
22 #include "libs/fvwmlib.h"
23 #include "libs/charmap.h"
24 #include "libs/wcontext.h"
25 #include "fvwm.h"
26 #include "fvwm/ewmh.h"
27 #include "externs.h"
28 #include "execcontext.h"
29 #include "misc.h"
30 #include "screen.h"
31 #include "geometry.h"
32 #include "module_interface.h"
33 #include "borders.h"
34 #include "icons.h"
35 #include "add_window.h"
36 #include "virtual.h"
37 
38 /* ---------------------------- local definitions -------------------------- */
39 
40 /* ---------------------------- local macros ------------------------------- */
41 
42 /* ---------------------------- imports ------------------------------------ */
43 
44 /* ---------------------------- included code files ------------------------ */
45 
46 /* ---------------------------- local types -------------------------------- */
47 
48 /* ---------------------------- forward declarations ----------------------- */
49 
50 /* ---------------------------- local variables ---------------------------- */
51 
52 /* ---------------------------- exported variables (globals) --------------- */
53 
54 /* ---------------------------- local functions ---------------------------- */
55 
56 /* ---------------------------- interface functions ------------------------ */
57 
58 /* Removes decorations from the source rectangle and moves it according to the
59  * gravity specification. */
gravity_get_naked_geometry(int gravity,FvwmWindow * t,rectangle * dest_g,rectangle * orig_g)60 void gravity_get_naked_geometry(
61 	int gravity, FvwmWindow *t, rectangle *dest_g, rectangle *orig_g)
62 {
63 	int xoff;
64 	int yoff;
65 	size_borders b;
66 
67 	get_window_borders(t, &b);
68 	gravity_get_offsets(gravity, &xoff, &yoff);
69 	dest_g->x = orig_g->x + ((xoff + 1) * (orig_g->width - 1)) / 2;
70 	dest_g->y = orig_g->y + ((yoff + 1) * (orig_g->height - 1)) / 2;
71 	dest_g->width = orig_g->width - b.total_size.width;
72 	dest_g->height = orig_g->height - b.total_size.height;
73 
74 	return;
75 }
76 
77 /* Decorate the rectangle.  Resize and shift it according to gravity. */
gravity_add_decoration(int gravity,FvwmWindow * t,rectangle * dest_g,rectangle * orig_g)78 void gravity_add_decoration(
79 	int gravity, FvwmWindow *t, rectangle *dest_g, rectangle *orig_g)
80 {
81 	size_borders b;
82 
83 	get_window_borders(t, &b);
84 	*dest_g = *orig_g;
85 	gravity_resize(
86 		gravity, dest_g, b.total_size.width, b.total_size.height);
87 
88 	return;
89 }
90 
get_relative_geometry(FvwmWindow * fw,rectangle * rel_g,rectangle * abs_g)91 void get_relative_geometry(FvwmWindow *fw, rectangle *rel_g, rectangle *abs_g)
92 {
93 	struct monitor	*m = (fw && fw->m) ? fw->m : monitor_get_current();
94 
95 	rel_g->x = abs_g->x - m->virtual_scr.Vx;
96 	rel_g->y = abs_g->y - m->virtual_scr.Vy;
97 	rel_g->width = abs_g->width;
98 	rel_g->height = abs_g->height;
99 
100 	return;
101 }
102 
get_absolute_geometry(FvwmWindow * fw,rectangle * abs_g,rectangle * rel_g)103 void get_absolute_geometry(FvwmWindow *fw, rectangle *abs_g, rectangle *rel_g)
104 {
105 	/* FIXME - not sure this is correct. */
106 	struct monitor	*m = (fw && fw->m) ? fw->m : monitor_get_current();
107 
108 	abs_g->x = rel_g->x + m->virtual_scr.Vx;
109 	abs_g->y = rel_g->y + m->virtual_scr.Vy;
110 	abs_g->width = rel_g->width;
111 	abs_g->height = rel_g->height;
112 
113 	return;
114 }
115 
gravity_translate_to_northwest_geometry(int gravity,FvwmWindow * t,rectangle * dest_g,rectangle * orig_g)116 void gravity_translate_to_northwest_geometry(
117 	int gravity, FvwmWindow *t, rectangle *dest_g, rectangle *orig_g)
118 {
119 	int xoff;
120 	int yoff;
121 
122 	gravity_get_offsets(gravity, &xoff, &yoff);
123 	dest_g->x = orig_g->x -
124 		((xoff + 1) * (orig_g->width - 1 +
125 			       2 * t->attr_backup.border_width)) / 2;
126 	dest_g->y = orig_g->y -
127 		((yoff + 1) * (orig_g->height - 1 +
128 			       2 * t->attr_backup.border_width)) / 2;
129 	dest_g->width = orig_g->width;
130 	dest_g->height = orig_g->height;
131 
132 	return;
133 }
134 
gravity_translate_to_northwest_geometry_no_bw(int gravity,FvwmWindow * t,rectangle * dest_g,rectangle * orig_g)135 void gravity_translate_to_northwest_geometry_no_bw(
136 	int gravity, FvwmWindow *t, rectangle *dest_g, rectangle *orig_g)
137 {
138 	int bw = t->attr_backup.border_width;
139 
140 	t->attr_backup.border_width = 0;
141 	gravity_translate_to_northwest_geometry(gravity, t, dest_g, orig_g);
142 	t->attr_backup.border_width = bw;
143 
144 	return;
145 }
146 
get_title_geometry(FvwmWindow * fw,rectangle * ret_g)147 void get_title_geometry(
148 	FvwmWindow *fw, rectangle *ret_g)
149 {
150 	size_borders b;
151 	size_borders nt;
152 	int w;
153 	int h;
154 
155 	get_window_borders(fw, &b);
156 	get_window_borders_no_title(fw, &nt);
157 	w = (ret_g->width > 0) ? ret_g->width : fw->g.frame.width;
158 	h = (ret_g->height > 0) ? ret_g->height : fw->g.frame.height;
159 	ret_g->x = nt.top_left.width;
160 	ret_g->y = nt.top_left.height;
161 	switch (GET_TITLE_DIR(fw))
162 	{
163 	case DIR_S:
164 		ret_g->y = h - b.bottom_right.height;
165 		/* fall through */
166 	case DIR_N:
167 		ret_g->width = w - b.total_size.width;
168 		ret_g->height = fw->title_thickness;
169 		break;
170 	case DIR_E:
171 		ret_g->x = w - b.bottom_right.width;
172 		/* fall through */
173 	case DIR_W:
174 		ret_g->width = fw->title_thickness;
175 		ret_g->height = h - b.total_size.height;
176 		break;
177 	default:
178 		break;
179 	}
180 
181 	return;
182 }
183 
get_title_gravity_factors(FvwmWindow * fw,int * ret_fx,int * ret_fy)184 void get_title_gravity_factors(
185 	FvwmWindow *fw, int *ret_fx, int *ret_fy)
186 {
187 	switch (GET_TITLE_DIR(fw))
188 	{
189 	case DIR_N:
190 		*ret_fx = 0;
191 		*ret_fy = 1;
192 		break;
193 	case DIR_S:
194 		*ret_fx = 0;
195 		*ret_fy = -1;
196 		break;
197 	case DIR_W:
198 		*ret_fx = 1;
199 		*ret_fy = 0;
200 		break;
201 	case DIR_E:
202 		*ret_fx = -1;
203 		*ret_fy = 0;
204 		break;
205 	}
206 
207 	return;
208 }
209 
get_title_button_geometry(FvwmWindow * fw,rectangle * ret_g,int context)210 Bool get_title_button_geometry(
211 	FvwmWindow *fw, rectangle *ret_g, int context)
212 {
213 	int bnum;
214 
215 	if (context & C_TITLE)
216 	{
217 		ret_g->width = 0;
218 		ret_g->height = 0;
219 		get_title_geometry(fw, ret_g);
220 		ret_g->x += fw->g.frame.x;
221 		ret_g->y += fw->g.frame.y;
222 
223 		return True;
224 
225 	}
226 	bnum = get_button_number(context);
227 	if (bnum < 0 || FW_W_BUTTON(fw, bnum) == None)
228 	{
229 		return False;
230 	}
231 	if (XGetGeometry(
232 		dpy, FW_W_BUTTON(fw, bnum), &JunkRoot, &ret_g->x, &ret_g->y,
233 		(unsigned int*)&ret_g->width, (unsigned int*)&ret_g->height,
234 		(unsigned int*)&JunkBW, (unsigned int*)&JunkDepth) == 0)
235 	{
236 		return False;
237 	}
238 	XTranslateCoordinates(
239 		dpy, FW_W_FRAME(fw), Scr.Root, ret_g->x, ret_g->y, &ret_g->x,
240 		&ret_g->y, &JunkChild);
241 
242 	return True;
243 }
244 
get_title_font_size_and_offset(FvwmWindow * fw,direction_t title_dir,Bool is_left_title_rotated_cw,Bool is_right_title_rotated_cw,Bool is_top_title_rotated,Bool is_bottom_title_rotated,int * size,int * offset)245 void get_title_font_size_and_offset(
246 	FvwmWindow *fw, direction_t title_dir,
247 	Bool is_left_title_rotated_cw, Bool is_right_title_rotated_cw,
248 	Bool is_top_title_rotated, Bool is_bottom_title_rotated,
249 	int *size, int *offset)
250 {
251 	int decor_size;
252 	int extra_size;
253 	int font_size;
254 	int min_offset;
255 	Bool is_rotated_cw, is_rotated;
256 	rotation_t draw_rotation;
257 
258 	/* adjust font offset according to height specified in title style */
259 	decor_size = fw->decor->title_height;
260 	font_size = fw->title_font->height + EXTRA_TITLE_FONT_HEIGHT;
261 	switch (title_dir)
262 	{
263 	case DIR_W:
264 	case DIR_E:
265 		is_rotated_cw = (title_dir == DIR_W) ?
266 			is_left_title_rotated_cw : is_right_title_rotated_cw;
267 		if (is_rotated_cw)
268 		{
269 			fw->title_text_rotation = ROTATION_90;
270 		}
271 		else
272 		{
273 			fw->title_text_rotation = ROTATION_270;
274 		}
275 		break;
276 	case DIR_N:
277 	case DIR_S:
278 	default:
279 		is_rotated = (title_dir == DIR_N) ?
280 			is_top_title_rotated : is_bottom_title_rotated;
281 		if (is_rotated)
282 		{
283 			fw->title_text_rotation = ROTATION_180;
284 		}
285 		else
286 		{
287 			fw->title_text_rotation = ROTATION_0;
288 		}
289 		break;
290 	}
291 	if (USE_TITLE_DECOR_ROTATION(fw))
292 	{
293 		draw_rotation = ROTATION_0;
294 	}
295 	else
296 	{
297 		draw_rotation = fw->title_text_rotation;
298 	}
299 	min_offset =  FlocaleGetMinOffset(
300 		fw->title_font, draw_rotation);
301 	extra_size = (decor_size > 0) ? decor_size - font_size : 0;
302 	*offset = min_offset;
303 	if (fw->decor->min_title_height > 0 &&
304 	    font_size + extra_size < fw->decor->min_title_height)
305 	{
306 		extra_size = fw->decor->min_title_height - font_size;
307 	}
308 	if (extra_size > 0)
309 	{
310 		*offset += extra_size / 2;
311 	}
312 	*size = font_size + extra_size;
313 
314 	return;
315 }
316 
get_icon_corner(FvwmWindow * fw,rectangle * ret_g)317 void get_icon_corner(
318 	FvwmWindow *fw, rectangle *ret_g)
319 {
320 	switch (GET_TITLE_DIR(fw))
321 	{
322 	case DIR_N:
323 	case DIR_W:
324 		ret_g->x = fw->g.frame.x;
325 		ret_g->y = fw->g.frame.y;
326 		break;
327 	case DIR_S:
328 		ret_g->x = fw->g.frame.x;
329 		ret_g->y = fw->g.frame.y + fw->g.frame.height -
330 			ret_g->height;
331 		break;
332 	case DIR_E:
333 		ret_g->x = fw->g.frame.x + fw->g.frame.width -
334 			ret_g->width;
335 		ret_g->y = fw->g.frame.y;
336 		break;
337 	}
338 
339 	return;
340 }
341 
get_shaded_geometry(FvwmWindow * fw,rectangle * small_g,rectangle * big_g)342 void get_shaded_geometry(
343 	FvwmWindow *fw, rectangle *small_g, rectangle *big_g)
344 {
345 	size_borders b;
346 	/* this variable is necessary so the function can be called with
347 	 * small_g == big_g */
348 	int big_width = big_g->width;
349 	int big_height = big_g->height;
350 	int d;
351 
352 	switch (SHADED_DIR(fw))
353 	{
354 	case DIR_SW:
355 	case DIR_SE:
356 	case DIR_NW:
357 	case DIR_NE:
358 		get_window_borders_no_title(fw, &b);
359 		break;
360 	default:
361 		get_window_borders(fw, &b);
362 		break;
363 	}
364 	*small_g = *big_g;
365 	d = 0;
366 	switch (SHADED_DIR(fw))
367 	{
368 	case DIR_S:
369 	case DIR_SW:
370 	case DIR_SE:
371 		small_g->y = big_g->y + big_height - b.total_size.height;
372 		d = 1;
373 		/* fall through */
374 	case DIR_N:
375 	case DIR_NW:
376 	case DIR_NE:
377 		small_g->height = b.total_size.height;
378 		if (small_g->height == 0)
379 		{
380 			small_g->height = 1;
381 			small_g->y -= d;
382 		}
383 		break;
384 	default:
385 		break;
386 	}
387 	d = 0;
388 	switch (SHADED_DIR(fw))
389 	{
390 	case DIR_E:
391 	case DIR_NE:
392 	case DIR_SE:
393 		small_g->x = big_g->x + big_width - b.total_size.width;
394 		d = 1;
395 		/* fall through */
396 	case DIR_W:
397 	case DIR_NW:
398 	case DIR_SW:
399 		small_g->width = b.total_size.width;
400 		if (small_g->width == 0)
401 		{
402 			small_g->width = 1;
403 			small_g->x -= d;
404 		}
405 		break;
406 	default:
407 		break;
408 	}
409 
410 	return;
411 }
412 
get_shaded_geometry_with_dir(FvwmWindow * fw,rectangle * small_g,rectangle * big_g,direction_t shade_dir)413 void get_shaded_geometry_with_dir(
414 	FvwmWindow *fw, rectangle *small_g, rectangle *big_g,
415 	direction_t shade_dir)
416 {
417 	direction_t old_shade_dir;
418 
419 	old_shade_dir = SHADED_DIR(fw);
420 	SET_SHADED_DIR(fw, shade_dir);
421 	get_shaded_geometry(fw, small_g, big_g);
422 	SET_SHADED_DIR(fw, old_shade_dir);
423 
424 	return;
425 }
426 
get_unshaded_geometry(FvwmWindow * fw,rectangle * ret_g)427 void get_unshaded_geometry(
428 	FvwmWindow *fw, rectangle *ret_g)
429 {
430 	if (IS_SHADED(fw))
431 	{
432 		if (IS_MAXIMIZED(fw))
433 		{
434 			*ret_g = fw->g.max;
435 		}
436 		else
437 		{
438 			*ret_g = fw->g.normal;
439 		}
440 		get_relative_geometry(fw, ret_g, ret_g);
441 	}
442 	else
443 	{
444 		*ret_g = fw->g.frame;
445 	}
446 
447 	return;
448 }
449 
get_shaded_client_window_pos(FvwmWindow * fw,rectangle * ret_g)450 void get_shaded_client_window_pos(
451 	FvwmWindow *fw, rectangle *ret_g)
452 {
453 	rectangle big_g;
454 	size_borders b;
455 
456 	get_window_borders(fw, &b);
457 	big_g = (IS_MAXIMIZED(fw)) ? fw->g.max : fw->g.normal;
458 	get_relative_geometry(fw, &big_g, &big_g);
459 	switch (SHADED_DIR(fw))
460 	{
461 	case DIR_S:
462 	case DIR_SW:
463 	case DIR_SE:
464 		ret_g->y = 1 - big_g.height + b.total_size.height;
465 		break;
466 	default:
467 		ret_g->y = 0;
468 		break;
469 	}
470 	switch (SHADED_DIR(fw))
471 	{
472 	case DIR_E:
473 	case DIR_NE:
474 	case DIR_SE:
475 		ret_g->x = 1 - big_g.width + b.total_size.width;
476 		break;
477 	default:
478 		ret_g->x = 0;
479 		break;
480 	}
481 
482 	return;
483 }
484 
485 /* returns the dimensions of the borders */
get_window_borders(const FvwmWindow * fw,size_borders * borders)486 void get_window_borders(
487 	const FvwmWindow *fw, size_borders *borders)
488 {
489 	borders->top_left.width = fw->boundary_width;
490 	borders->bottom_right.width = fw->boundary_width;
491 	borders->top_left.height = fw->boundary_width;
492 	borders->bottom_right.height = fw->boundary_width;
493 	switch (GET_TITLE_DIR(fw))
494 	{
495 	case DIR_N:
496 		borders->top_left.height += fw->title_thickness;
497 		break;
498 	case DIR_S:
499 		borders->bottom_right.height += fw->title_thickness;
500 		break;
501 	case DIR_W:
502 		borders->top_left.width += fw->title_thickness;
503 		break;
504 	case DIR_E:
505 		borders->bottom_right.width += fw->title_thickness;
506 		break;
507 	}
508 	borders->total_size.width =
509 		borders->top_left.width + borders->bottom_right.width;
510 	borders->total_size.height =
511 		borders->top_left.height + borders->bottom_right.height;
512 
513 	return;
514 }
515 
516 /* returns the dimensions of the borders without the title */
get_window_borders_no_title(const FvwmWindow * fw,size_borders * borders)517 void get_window_borders_no_title(
518 	const FvwmWindow *fw, size_borders *borders)
519 {
520 	borders->top_left.width = fw->boundary_width;
521 	borders->bottom_right.width = fw->boundary_width;
522 	borders->top_left.height = fw->boundary_width;
523 	borders->bottom_right.height = fw->boundary_width;
524 	borders->total_size.width =
525 		borders->top_left.width + borders->bottom_right.width;
526 	borders->total_size.height =
527 		borders->top_left.height + borders->bottom_right.height;
528 
529 	return;
530 }
531 
set_window_border_size(FvwmWindow * fw,int used_width)532 void set_window_border_size(
533 	FvwmWindow *fw, int used_width)
534 {
535 	if (used_width <= 0)
536 	{
537 		fw->boundary_width = 0;
538 		fw->unshaped_boundary_width = 0;
539 	}
540 	else
541 	{
542 		fw->unshaped_boundary_width = used_width;
543 		fw->boundary_width = (fw->wShaped) ? 0 : used_width;
544 	}
545 
546 	return;
547 }
548 
549 /* Returns True if all window borders are only 1 pixel thick (or less). */
is_window_border_minimal(FvwmWindow * fw)550 Bool is_window_border_minimal(
551 	FvwmWindow *fw)
552 {
553 	size_borders nt;
554 
555 	get_window_borders_no_title(fw, &nt);
556 	if (nt.top_left.width > 1 || nt.top_left.height > 1 ||
557 	    nt.bottom_right.width > 1 || nt.bottom_right.height > 1)
558 	{
559 		return False;
560 	}
561 
562 	return True;
563 }
564 
565 
566 /* This function returns the geometry of the client window.  If the window is
567  * shaded, the unshaded geometry is used instead. */
get_client_geometry(FvwmWindow * fw,rectangle * ret_g)568 void get_client_geometry(
569 	FvwmWindow *fw, rectangle *ret_g)
570 {
571 	size_borders borders;
572 
573 	get_unshaded_geometry(fw, ret_g);
574 	get_window_borders(fw, &borders);
575 	ret_g->x += borders.top_left.width;
576 	ret_g->y += borders.top_left.height;
577 	ret_g->width -= borders.total_size.width;
578 	ret_g->height -= borders.total_size.height;
579 
580 	return;
581 }
582 
583 /* update the frame_g according to the window's g.normal or g.max and shaded
584  * state */
update_relative_geometry(FvwmWindow * fw)585 void update_relative_geometry(FvwmWindow *fw)
586 {
587 	get_relative_geometry(fw,
588 		&fw->g.frame,
589 		(IS_MAXIMIZED(fw)) ? &fw->g.max : &fw->g.normal);
590 	if (IS_SHADED(fw))
591 	{
592 		get_shaded_geometry(
593 			fw, &fw->g.frame, &fw->g.frame);
594 	}
595 
596 	return;
597 }
598 
599 /* update the g.normal or g.max according to the window's current position */
update_absolute_geometry(FvwmWindow * fw)600 void update_absolute_geometry(FvwmWindow *fw)
601 {
602 	rectangle *dest_g;
603 	rectangle frame_g;
604 	struct monitor	*m;
605 
606 	/* Tell the client which screen it is on, prior to its geometry being
607 	 * updated here.  Certain callers, when updating a window's geometry,
608 	 * bypass some of the sanity checks, and the screen assignment gets
609 	 * outdated.
610 	 */
611 	if (IS_SHADED(fw))
612 		UPDATE_FVWM_SCREEN(fw);
613 	m = (fw && fw->m) ? fw->m : monitor_get_current();
614 
615 	/* store orig values in absolute coords */
616 	dest_g = (IS_MAXIMIZED(fw)) ? &fw->g.max : &fw->g.normal;
617 	frame_g = *dest_g;
618 	dest_g->x = fw->g.frame.x + m->virtual_scr.Vx;
619 	dest_g->y = fw->g.frame.y + m->virtual_scr.Vy;
620 	dest_g->width = fw->g.frame.width;
621 	dest_g->height = fw->g.frame.height;
622 	if (IS_SHADED(fw))
623 	{
624 		switch (SHADED_DIR(fw))
625 		{
626 		case DIR_SW:
627 		case DIR_S:
628 		case DIR_SE:
629 			dest_g->y += fw->g.frame.height - frame_g.height;
630 			/* fall through */
631 		case DIR_NW:
632 		case DIR_N:
633 		case DIR_NE:
634 			dest_g->height = frame_g.height;
635 			break;
636 		}
637 		switch (SHADED_DIR(fw))
638 		{
639 		case DIR_NE:
640 		case DIR_E:
641 		case DIR_SE:
642 			dest_g->x += fw->g.frame.width - frame_g.width;
643 			/* fall through */
644 		case DIR_NW:
645 		case DIR_W:
646 		case DIR_SW:
647 			dest_g->width = frame_g.width;
648 			break;
649 		}
650 	}
651 
652 	return;
653 }
654 
655 /* make sure a maximized window and it's normal version are never a page or
656  * more apart. */
maximize_adjust_offset(FvwmWindow * fw)657 void maximize_adjust_offset(FvwmWindow *fw)
658 {
659 	int off_x;
660 	int off_y;
661 	int dh;
662 	int dw;
663 
664 	if (!IS_MAXIMIZED(fw))
665 	{
666 		/* otherwise we might corrupt the g.normal */
667 		return;
668 	}
669 	off_x = fw->g.normal.x - fw->g.max.x - fw->g.max_offset.x;
670 	off_y = fw->g.normal.y - fw->g.max.y - fw->g.max_offset.y;
671 	dw = monitor_get_all_widths();
672 	dh = monitor_get_all_heights();
673 	if (off_x >= dw)
674 	{
675 		fw->g.normal.x -= (off_x / dw) * dw;
676 	}
677 	else if (off_x <= -dw)
678 	{
679 		fw->g.normal.x += (-off_x / dw) * dw;
680 	}
681 	if (off_y >= dh)
682 	{
683 		fw->g.normal.y -= (off_y / dh) * dh;
684 	}
685 	else if (off_y <= -dh)
686 	{
687 		fw->g.normal.y += (-off_y / dh) * dh;
688 	}
689 
690 	return;
691 }
692 
693 #define MAKEMULT(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
__cs_handle_aspect_ratio(size_rect * ret_s,FvwmWindow * fw,size_rect s,const size_rect base,const size_rect inc,size_rect min,size_rect max,int xmotion,int ymotion,int flags)694 static void __cs_handle_aspect_ratio(
695 	size_rect *ret_s, FvwmWindow *fw, size_rect s, const size_rect base,
696 	const size_rect inc, size_rect min, size_rect max, int xmotion,
697 	int ymotion, int flags)
698 {
699 	volatile double odefect;
700 	volatile double defect;
701 	volatile double rmax;
702 	volatile double rmin;
703 	volatile int delta;
704 	volatile int ow;
705 	volatile int oh;
706 
707 	if (fw->hints.flags & PBaseSize)
708 	{
709 		/*
710 		 * ICCCM 2 demands that aspect ratio should apply to width -
711 		 * base_width. To prevent funny results, we reset PBaseSize in
712 		 * GetWindowSizeHints, if base is not smaller than min.
713 		 */
714 		s.width -= base.width;
715 		max.width -= base.width;
716 		min.width -= base.width;
717 		s.height -= base.height;
718 		max.height -= base.height;
719 		min.height -= base.height;
720 	}
721 	rmin = (double)fw->hints.min_aspect.x / (double)fw->hints.min_aspect.y;
722 	rmax = (double)fw->hints.max_aspect.x / (double)fw->hints.max_aspect.y;
723 	do
724 	{
725 		double r;
726 
727 		r = (double)s.width / (double)s.height;
728 		ow = s.width;
729 		oh = s.height;
730 		odefect = 0;
731 		if (r < rmin)
732 		{
733 			odefect = rmin - r;
734 		}
735 		else if (r > rmax)
736 		{
737 			odefect = r - rmax;
738 		}
739 		if (r < rmin && (flags & CS_ROUND_UP) && xmotion == 0)
740 		{
741 			/* change width to match */
742 			delta = MAKEMULT(s.height * rmin - s.width, inc.width);
743 			if (s.width + delta <= max.width)
744 			{
745 				s.width += delta;
746 			}
747 			r = (double)s.width / (double)s.height;
748 		}
749 		if (r < rmin)
750 		{
751 			/* change height to match */
752 			delta = MAKEMULT(
753 				s.height - s.width / rmin, inc.height);
754 			if (s.height - delta >= min.height)
755 			{
756 				s.height -= delta;
757 			}
758 			else
759 			{
760 				delta = MAKEMULT(
761 					s.height * rmin - s.width, inc.width);
762 				if (s.width + delta <= max.width)
763 				{
764 					s.width += delta;
765 				}
766 			}
767 			r = (double)s.width / (double)s.height;
768 		}
769 
770 		if (r > rmax && (flags & CS_ROUND_UP) && ymotion == 0)
771 		{
772 			/* change height to match */
773 			delta = MAKEMULT(s.width /rmax - s.height, inc.height);
774 			if (s.height + delta <= max.height)
775 			{
776 				s.height += delta;
777 			}
778 			r = (double)s.width / (double)s.height;
779 		}
780 		if (r > rmax)
781 		{
782 			/* change width to match */
783 			delta = MAKEMULT(s.width - s.height * rmax, inc.width);
784 			if (s.width - delta >= min.width)
785 			{
786 				s.width -= delta;
787 			}
788 			else
789 			{
790 				delta = MAKEMULT(
791 					s.width / rmax - s.height, inc.height);
792 				if (s.height + delta <= max.height)
793 				{
794 					s.height += delta;
795 				}
796 			}
797 			r = (double)s.width / (double)s.height;
798 		}
799 		defect = 0;
800 		if (r < rmin)
801 		{
802 			defect = rmin - r;
803 		}
804 		else if (r > rmax)
805 		{
806 			defect = r - rmax;
807 		}
808 	} while (odefect > defect);
809 	if (fw->hints.flags & PBaseSize)
810 	{
811 		ow += base.width;
812 		oh += base.height;
813 	}
814 	ret_s->width = ow;
815 	ret_s->height = oh;
816 
817 	return;
818 }
819 
820 /*
821  *
822  *  Procedure:
823  *      constrain_size - adjust the given width and height to account for the
824  *              constraints imposed by size hints
825  */
constrain_size(FvwmWindow * fw,const XEvent * e,int * widthp,int * heightp,int xmotion,int ymotion,int flags)826 void constrain_size(
827 	FvwmWindow *fw, const XEvent *e, int *widthp, int *heightp,
828 	int xmotion, int ymotion, int flags)
829 {
830 	int tmp;
831 	window_style style;
832 	size_rect min;
833 	size_rect max;
834 	size_rect inc;
835 	size_rect base;
836 	size_rect round_up;
837 	size_rect d;
838 	size_rect old;
839 	size_borders b;
840 
841 	if (DO_DISABLE_CONSTRAIN_SIZE_FULLSCREEN(fw) == 1)
842 	{
843 		return;
844 	}
845 	if (HAS_NEW_WM_NORMAL_HINTS(fw))
846 	{
847 		/* get the latest size hints */
848 		XSync(dpy, 0);
849 		GetWindowSizeHints(fw);
850 		SET_HAS_NEW_WM_NORMAL_HINTS(fw, 0);
851 	}
852 	if (IS_MAXIMIZED(fw) && (flags & CS_UPDATE_MAX_DEFECT))
853 	{
854 		*widthp += fw->g.max_defect.width;
855 		*heightp += fw->g.max_defect.height;
856 	}
857 	/* gcc 4.1.1 warns about these not being initialized at the end,
858 	 * but the conditions for the use are the same...*/
859 	old.width = *widthp;
860 	old.height = *heightp;
861 
862 	d.width = *widthp;
863 	d.height = *heightp;
864 	get_window_borders(fw, &b);
865 	d.width -= b.total_size.width;
866 	d.height -= b.total_size.height;
867 
868 	/* Need to know if using client size for Min/Max WindowSize
869 	 * styles to decided if border width is included in the size.
870 	 */
871 	lookup_style(fw, &style);
872 
873 	min.width = fw->hints.min_width;
874 	min.height = fw->hints.min_height;
875 	tmp = SGET_MIN_WINDOW_WIDTH_IS_C(style) ? 0 : b.total_size.width;
876 	if (min.width < fw->min_window_width - tmp)
877 	{
878 		min.width = fw->min_window_width - tmp;
879 	}
880 	tmp = SGET_MIN_WINDOW_HEIGHT_IS_C(style) ? 0 : b.total_size.height;
881 	if (min.height < fw->min_window_height - tmp)
882 	{
883 		min.height = fw->min_window_height - tmp;
884 	}
885 
886 	max.width = fw->hints.max_width;
887 	max.height =  fw->hints.max_height;
888 	tmp = SGET_MAX_WINDOW_WIDTH_IS_C(style) ? 0 : b.total_size.width;
889 	if (max.width > fw->max_window_width - tmp)
890 	{
891 		max.width = fw->max_window_width - tmp;
892 	}
893 	tmp = SGET_MAX_WINDOW_HEIGHT_IS_C(style) ? 0 : b.total_size.height;
894 	if (max.height > fw->max_window_height - tmp)
895 	{
896 		max.height = fw->max_window_height - tmp;
897 	}
898 
899 	if (min.width > max.width)
900 	{
901 		min.width = max.width;
902 	}
903 	if (min.height > max.height)
904 	{
905 		min.height = max.height;
906 	}
907 
908 	base.width = fw->hints.base_width;
909 	base.height = fw->hints.base_height;
910 
911 	inc.width = fw->hints.width_inc;
912 	inc.height = fw->hints.height_inc;
913 
914 	/*
915 	 * First, clamp to min and max values
916 	 */
917 	if (d.width < min.width)
918 	{
919 		d.width = min.width;
920 	}
921 	if (d.height < min.height)
922 	{
923 		d.height = min.height;
924 	}
925 	if (d.width > max.width)
926 	{
927 		d.width = max.width;
928 	}
929 	if (d.height > max.height)
930 	{
931 		d.height = max.height;
932 	}
933 
934 	/*
935 	 * Second, round to base + N * inc (up or down depending on resize
936 	 * type) if rounding up store amount
937 	 */
938 	if (!(flags & CS_ROUND_UP))
939 	{
940 		d.width = ((d.width - base.width) / inc.width) *
941 			inc.width + base.width;
942 		d.height = ((d.height - base.height) / inc.height) *
943 			inc.height + base.height;
944 	}
945 	else
946 	{
947 		round_up.width = d.width;
948 		round_up.height = d.height;
949 		d.width = ((d.width - base.width + inc.width - 1) /
950 			   inc.width) * inc.width + base.width;
951 		d.height = ((d.height - base.height + inc.height - 1) /
952 			    inc.height) * inc.height + base.height;
953 		round_up.width = d.width - round_up.width;
954 		round_up.height = d.height - round_up.height;
955 	}
956 
957 	/*
958 	 * Step 2a: check we didn't move the edge off screen in interactive
959 	 * moves
960 	 */
961 	if ((flags & CS_ROUND_UP) && e != NULL && e->type == MotionNotify)
962 	{
963 		if (xmotion > 0 && e->xmotion.x_root < round_up.width)
964 		{
965 			d.width -= inc.width;
966 		}
967 		else if (
968 			xmotion < 0 && e->xmotion.x_root >=
969 			monitor_get_all_widths() - round_up.width)
970 		{
971 			d.width -= inc.width;
972 		}
973 		if (ymotion > 0 && e->xmotion.y_root < round_up.height)
974 		{
975 			d.height -= inc.height;
976 		}
977 		else if (
978 			ymotion < 0 && e->xmotion.y_root >=
979 			monitor_get_all_heights() - round_up.height)
980 		{
981 			d.height -= inc.height;
982 		}
983 	}
984 
985 	/*
986 	 * Step 2b: Check that we didn't violate min and max.
987 	 */
988 	if (d.width < min.width)
989 	{
990 		d.width += inc.width;
991 	}
992 	if (d.height < min.height)
993 	{
994 		d.height += inc.height;
995 	}
996 	if (d.width > max.width)
997 	{
998 		d.width -= inc.width;
999 	}
1000 	if (d.height > max.height)
1001 	{
1002 		d.height -= inc.height;
1003 	}
1004 
1005 	/*
1006 	 * Third, adjust for aspect ratio
1007 	 */
1008 	if (fw->hints.flags & PAspect)
1009 	{
1010 		__cs_handle_aspect_ratio(
1011 			&d, fw, d, base, inc, min, max, xmotion, ymotion,
1012 			flags);
1013 	}
1014 
1015 	/*
1016 	 * Fourth, account for border width and title height
1017 	 */
1018 	*widthp = d.width + b.total_size.width;
1019 	*heightp = d.height + b.total_size.height;
1020 	if (IS_MAXIMIZED(fw) && (flags & CS_UPDATE_MAX_DEFECT))
1021 	{
1022 		/* update size defect for maximized window */
1023 		fw->g.max_defect.width = old.width - *widthp;
1024 		fw->g.max_defect.height = old.height - *heightp;
1025 	}
1026 
1027 	return;
1028 }
1029 
1030 /* This function does roughly the same as constrain_size, but takes into account
1031  * that the window shifts according to gravity if constrain_size actually
1032  * changes the width or height. The frame_g of the window is not changed. The
1033  * target geometry is expected to be in *rect and will be retured through rect.
1034  */
gravity_constrain_size(int gravity,FvwmWindow * t,rectangle * rect,int flags)1035 void gravity_constrain_size(
1036 	int gravity, FvwmWindow *t, rectangle *rect, int flags)
1037 {
1038 	int new_width = rect->width;
1039 	int new_height = rect->height;
1040 
1041 	if (IS_MAXIMIZED(t) && (flags & CS_UPDATE_MAX_DEFECT))
1042 	{
1043 		gravity_resize(
1044 			gravity, rect, t->g.max_defect.width,
1045 			t->g.max_defect.height);
1046 		t->g.max_defect.width = 0;
1047 		t->g.max_defect.height = 0;
1048 		new_width = rect->width;
1049 		new_height = rect->height;
1050 	}
1051 	constrain_size(
1052 		t, NULL, &new_width, &new_height, 0, 0, flags);
1053 	if (rect->width != new_width || rect->height != new_height)
1054 	{
1055 		gravity_resize(
1056 			gravity, rect, new_width - rect->width,
1057 			new_height - rect->height);
1058 	}
1059 
1060 	return;
1061 }
1062 
1063 /* returns the icon title geometry if it is visible */
get_visible_icon_title_geometry(FvwmWindow * fw,rectangle * ret_g)1064 Bool get_visible_icon_title_geometry(
1065 	FvwmWindow *fw, rectangle *ret_g)
1066 {
1067 	if (HAS_NO_ICON_TITLE(fw) || IS_ICON_UNMAPPED(fw) ||
1068 	    !IS_ICONIFIED(fw))
1069 	{
1070 		memset(ret_g, 0, sizeof(*ret_g));
1071 		return False;
1072 	}
1073 	*ret_g = fw->icon_g.title_w_g;
1074 
1075 	return True;
1076 }
1077 
1078 /* returns the icon title geometry if it the icon title window exists */
get_icon_title_geometry(FvwmWindow * fw,rectangle * ret_g)1079 Bool get_icon_title_geometry(
1080 	FvwmWindow *fw, rectangle *ret_g)
1081 {
1082 	if (HAS_NO_ICON_TITLE(fw))
1083 	{
1084 		memset(ret_g, 0, sizeof(*ret_g));
1085 		return False;
1086 	}
1087 	*ret_g = fw->icon_g.title_w_g;
1088 
1089 	return True;
1090 }
1091 
1092 /* returns the icon picture geometry if it is visible */
get_visible_icon_picture_geometry(FvwmWindow * fw,rectangle * ret_g)1093 Bool get_visible_icon_picture_geometry(
1094 	FvwmWindow *fw, rectangle *ret_g)
1095 {
1096 	if (fw->icon_g.picture_w_g.width == 0 ||
1097 	    IS_ICON_UNMAPPED(fw) || !IS_ICONIFIED(fw))
1098 	{
1099 		memset(ret_g, 0, sizeof(*ret_g));
1100 		return False;
1101 	}
1102 	*ret_g = fw->icon_g.picture_w_g;
1103 
1104 	return True;
1105 }
1106 
1107 /* returns the icon picture geometry if it is exists */
get_icon_picture_geometry(FvwmWindow * fw,rectangle * ret_g)1108 Bool get_icon_picture_geometry(
1109 	FvwmWindow *fw, rectangle *ret_g)
1110 {
1111 	if (fw->icon_g.picture_w_g.width == 0)
1112 	{
1113 		memset(ret_g, 0, sizeof(*ret_g));
1114 		return False;
1115 	}
1116 	*ret_g = fw->icon_g.picture_w_g;
1117 
1118 	return True;
1119 }
1120 
1121 /* returns the icon geometry (unexpanded title plus pixmap) if it is visible */
get_visible_icon_geometry(FvwmWindow * fw,rectangle * ret_g)1122 Bool get_visible_icon_geometry(
1123 	FvwmWindow *fw, rectangle *ret_g)
1124 {
1125 	if (IS_ICON_UNMAPPED(fw) || !IS_ICONIFIED(fw))
1126 	{
1127 		memset(ret_g, 0, sizeof(*ret_g));
1128 		return False;
1129 	}
1130 	if (fw->icon_g.picture_w_g.width > 0)
1131 	{
1132 		*ret_g = fw->icon_g.picture_w_g;
1133 		if (!HAS_NO_ICON_TITLE(fw))
1134 		{
1135 			ret_g->height += fw->icon_g.title_w_g.height;
1136 		}
1137 	}
1138 	else if (!HAS_NO_ICON_TITLE(fw))
1139 	{
1140 		*ret_g = fw->icon_g.title_w_g;
1141 	}
1142 	else
1143 	{
1144 		memset(ret_g, 0, sizeof(*ret_g));
1145 		return False;
1146 	}
1147 
1148 	return True;
1149 }
1150 
1151 /* returns the icon geometry (unexpanded title plus pixmap) if it exists */
get_icon_geometry(FvwmWindow * fw,rectangle * ret_g)1152 void get_icon_geometry(
1153 	FvwmWindow *fw, rectangle *ret_g)
1154 {
1155 	/* valid geometry? */
1156 	if (fw->icon_g.picture_w_g.width > 0)
1157 	{
1158 		*ret_g = fw->icon_g.picture_w_g;
1159 		if (!HAS_NO_ICON_TITLE(fw))
1160 		{
1161 			ret_g->height += fw->icon_g.title_w_g.height;
1162 		}
1163 	}
1164 	else if (fw->icon_g.title_w_g.width > 0)
1165 	{
1166 		*ret_g = fw->icon_g.title_w_g;
1167 	}
1168 	/* valid position? */
1169 	else if (fw->icon_g.picture_w_g.x != 0 || fw->icon_g.picture_w_g.y != 0)
1170 	{
1171 		*ret_g = fw->icon_g.picture_w_g;
1172 	}
1173 	else if (fw->icon_g.title_w_g.x != 0 || fw->icon_g.title_w_g.y != 0)
1174 	{
1175 		*ret_g = fw->icon_g.title_w_g;
1176 	}
1177 	else
1178 	{
1179 		memset(ret_g, 0, sizeof(*ret_g));
1180 	}
1181 
1182 	return;
1183 }
1184 
1185 /* Returns the visible geometry of a window or icon.  This can be used to test
1186  * if this region overlaps other windows. */
get_visible_window_or_icon_geometry(FvwmWindow * fw,rectangle * ret_g)1187 Bool get_visible_window_or_icon_geometry(
1188 	FvwmWindow *fw, rectangle *ret_g)
1189 {
1190 	if (IS_ICONIFIED(fw))
1191 	{
1192 		return get_visible_icon_geometry(fw, ret_g);
1193 	}
1194 	*ret_g = fw->g.frame;
1195 
1196 	return True;
1197 }
1198 
move_icon_to_position(FvwmWindow * fw)1199 void move_icon_to_position(
1200 	FvwmWindow *fw)
1201 {
1202 	Bool draw_picture_w = False;
1203 	Bool draw_title_w = False;
1204 
1205 	if (fw->icon_g.picture_w_g.width > 0)
1206 	{
1207 		int cs;
1208 
1209 		if (Scr.Hilite == fw)
1210 		{
1211 			cs = fw->cs_hi;
1212 		}
1213 		else
1214 		{
1215 			cs = fw->cs;
1216 		}
1217 		XMoveWindow(
1218 			dpy, FW_W_ICON_PIXMAP(fw),
1219 			fw->icon_g.picture_w_g.x,
1220 			fw->icon_g.picture_w_g.y);
1221 		if (fw->icon_alphaPixmap ||
1222 		    (cs >= 0 && Colorset[cs].icon_alpha_percent < 100) ||
1223 		    CSET_IS_TRANSPARENT(fw->icon_background_cs) ||
1224 		    (!IS_ICON_SHAPED(fw) && fw->icon_background_padding > 0))
1225 		{
1226 			draw_picture_w = True;
1227 		}
1228 	}
1229 	if (!HAS_NO_ICON_TITLE(fw))
1230 	{
1231 		int cs;
1232 		rectangle dummy;
1233 
1234 		if (Scr.Hilite == fw)
1235 		{
1236 			cs = fw->icon_title_cs_hi;
1237 		}
1238 		else
1239 		{
1240 			cs = fw->icon_title_cs;
1241 		}
1242 		XMoveWindow(
1243 			dpy, FW_W_ICON_TITLE(fw),
1244 			fw->icon_g.title_w_g.x,
1245 			fw->icon_g.title_w_g.y);
1246 		if (CSET_IS_TRANSPARENT(cs) &&
1247 		    !get_visible_icon_picture_geometry(fw, &dummy) &&
1248 		    get_visible_icon_title_geometry(fw, &dummy))
1249 		{
1250 			draw_title_w = True;
1251 		}
1252 	}
1253 
1254 	if (draw_title_w || draw_picture_w)
1255 	{
1256 		DrawIconWindow(
1257 			fw, draw_title_w, draw_picture_w, False, draw_picture_w,
1258 			NULL);
1259 	}
1260 
1261 	return;
1262 }
1263 
broadcast_icon_geometry(FvwmWindow * fw,Bool do_force)1264 void broadcast_icon_geometry(
1265 	FvwmWindow *fw, Bool do_force)
1266 {
1267 	rectangle g;
1268 	Bool rc;
1269 
1270 	rc = get_visible_icon_geometry(fw, &g);
1271 	if (rc == True && (!IS_ICON_UNMAPPED(fw) || do_force == True))
1272 	{
1273 		BroadcastPacket(
1274 			M_ICON_LOCATION, 7, (long)FW_W(fw),
1275 			(long)FW_W_FRAME(fw), (unsigned long)fw,
1276 			(long)g.x, (long)g.y, (long)g.width, (long)g.height);
1277 	}
1278 
1279 	return;
1280 }
1281 
modify_icon_position(FvwmWindow * fw,int dx,int dy)1282 void modify_icon_position(
1283 	FvwmWindow *fw, int dx, int dy)
1284 {
1285 	if (fw->icon_g.picture_w_g.width > 0 || HAS_NO_ICON_TITLE(fw))
1286 	{
1287 		/* picture position is also valid if there is neither a picture
1288 		 * nor a title */
1289 		fw->icon_g.picture_w_g.x += dx;
1290 		fw->icon_g.picture_w_g.y += dy;
1291 	}
1292 	if (!HAS_NO_ICON_TITLE(fw))
1293 	{
1294 		fw->icon_g.title_w_g.x += dx;
1295 		fw->icon_g.title_w_g.y += dy;
1296 	}
1297 
1298 	return;
1299 }
1300 
1301 /* set the icon position to the specified value. take care of the actual icon
1302  * layout */
set_icon_position(FvwmWindow * fw,int x,int y)1303 void set_icon_position(
1304 	FvwmWindow *fw, int x, int y)
1305 {
1306 	if (fw->icon_g.picture_w_g.width > 0)
1307 	{
1308 		fw->icon_g.picture_w_g.x = x;
1309 		fw->icon_g.picture_w_g.y = y;
1310 	}
1311 	else
1312 	{
1313 		fw->icon_g.picture_w_g.x = 0;
1314 		fw->icon_g.picture_w_g.y = 0;
1315 	}
1316 	if (!HAS_NO_ICON_TITLE(fw))
1317 	{
1318 		fw->icon_g.title_w_g.x = x;
1319 		fw->icon_g.title_w_g.y = y;
1320 	}
1321 	else
1322 	{
1323 		fw->icon_g.title_w_g.x = 0;
1324 		fw->icon_g.title_w_g.y = 0;
1325 	}
1326 	if (fw->icon_g.picture_w_g.width > 0 &&
1327 	    !HAS_NO_ICON_TITLE(fw))
1328 	{
1329 		fw->icon_g.title_w_g.x -=
1330 			(fw->icon_g.title_w_g.width -
1331 			 fw->icon_g.picture_w_g.width) / 2;
1332 		fw->icon_g.title_w_g.y +=
1333 			fw->icon_g.picture_w_g.height;
1334 	}
1335 	else if (fw->icon_g.picture_w_g.width <= 0 && HAS_NO_ICON_TITLE(fw))
1336 	{
1337 		/* In case there is no icon, fake the icon position so the
1338 		 * modules know where its window was iconified. */
1339 		fw->icon_g.picture_w_g.x = x;
1340 		fw->icon_g.picture_w_g.y = y;
1341 	}
1342 
1343 	return;
1344 }
1345 
set_icon_picture_size(FvwmWindow * fw,int w,int h)1346 void set_icon_picture_size(
1347 	FvwmWindow *fw, int w, int h)
1348 {
1349 	if (fw->icon_g.picture_w_g.width > 0)
1350 	{
1351 		fw->icon_g.picture_w_g.width = w;
1352 		fw->icon_g.picture_w_g.height = h;
1353 	}
1354 	else
1355 	{
1356 		fw->icon_g.picture_w_g.width = 0;
1357 		fw->icon_g.picture_w_g.height = 0;
1358 	}
1359 
1360 	return;
1361 }
1362 
resize_icon_title_height(FvwmWindow * fw,int dh)1363 void resize_icon_title_height(FvwmWindow *fw, int dh)
1364 {
1365 	if (!HAS_NO_ICON_TITLE(fw))
1366 	{
1367 		fw->icon_g.title_w_g.height += dh;
1368 	}
1369 
1370 	return;
1371 }
1372 
get_page_offset_rectangle(FvwmWindow * fw,int * ret_page_x,int * ret_page_y,rectangle * r)1373 void get_page_offset_rectangle(FvwmWindow *fw,
1374 	int *ret_page_x, int *ret_page_y, rectangle *r)
1375 {
1376 	struct monitor	*m = (fw && fw->m) ? fw->m : monitor_get_current();
1377 
1378 	/* FIXME: broadcast if global monitor in use. */
1379 
1380 	int xoff = m->virtual_scr.Vx % monitor_get_all_widths();
1381 	int yoff = m->virtual_scr.Vy % monitor_get_all_heights();
1382 
1383 	/* maximize on the page where the center of the window is */
1384 	*ret_page_x = truncate_to_multiple(
1385 		r->x + r->width / 2 + xoff, monitor_get_all_widths()) - xoff;
1386 	*ret_page_y = truncate_to_multiple(
1387 		r->y + r->height / 2 + yoff, monitor_get_all_heights()) - yoff;
1388 
1389 	return;
1390 }
1391 
get_page_offset(int * ret_page_x,int * ret_page_y,FvwmWindow * fw)1392 void get_page_offset(
1393 	int *ret_page_x, int *ret_page_y, FvwmWindow *fw)
1394 {
1395 	rectangle r;
1396 
1397 	r.x = fw->g.frame.x;
1398 	r.y = fw->g.frame.y;
1399 	r.width = fw->g.frame.width;
1400 	r.height = fw->g.frame.height;
1401 	get_page_offset_rectangle(fw, ret_page_x, ret_page_y, &r);
1402 
1403 	return;
1404 }
1405 
get_page_offset_check_visible(int * ret_page_x,int * ret_page_y,FvwmWindow * fw)1406 void get_page_offset_check_visible(
1407 	int *ret_page_x, int *ret_page_y, FvwmWindow *fw)
1408 {
1409 	if (IsRectangleOnThisPage(fw->m, &fw->g.frame, fw->Desk))
1410 	{
1411 		/* maximize on visible page if any part of the window is
1412 		 * visible */
1413 		*ret_page_x = 0;
1414 		*ret_page_y = 0;
1415 	}
1416 	else
1417 	{
1418 		get_page_offset(ret_page_x, ret_page_y, fw);
1419 	}
1420 #if 0
1421 	fprintf(stderr, "%s: MON: %s {page_x: %d, page_y: %d}\n",
1422 		__func__, fw->m->si->name, *ret_page_x, *ret_page_y);
1423 #endif
1424 	return;
1425 }
1426 
1427 /* ---------------------------- builtin commands --------------------------- */
1428