Fix ExplainWindowPlacement when using "NoUSPosition" style.
[fvwm.git] / fvwm / frame.c
bloba42efa9b14fc57e8c6e0b3ea7f32385c8c11ef2d
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>
22 #include <signal.h>
24 #include "libs/fvwmlib.h"
25 #include "libs/FShape.h"
26 #include "libs/Grab.h"
27 #include "libs/charmap.h"
28 #include "libs/wcontext.h"
29 #include "fvwm.h"
30 #include "externs.h"
31 #include "execcontext.h"
32 #include "events.h"
33 #include "misc.h"
34 #include "screen.h"
35 #include "geometry.h"
36 #include "module_interface.h"
37 #include "focus.h"
38 #include "borders.h"
39 #include "frame.h"
40 #include "gnome.h"
41 #include "ewmh.h"
43 /* ---------------------------- local definitions -------------------------- */
45 /* ---------------------------- local macros ------------------------------- */
47 /* ---------------------------- imports ------------------------------------ */
49 /* ---------------------------- included code files ------------------------ */
51 /* ---------------------------- local types -------------------------------- */
53 typedef struct
55 int decor_grav;
56 int title_grav;
57 int lbutton_grav;
58 int rbutton_grav;
59 int parent_grav;
60 int client_grav;
61 } frame_decor_gravities_type;
63 typedef struct
65 /* filled when args are created */
66 frame_move_resize_mode mode;
67 frame_decor_gravities_type grav;
68 size_borders b_g;
69 size_borders b_no_title_g;
70 rectangle curr_sidebar_g;
71 rectangle start_g;
72 rectangle end_g;
73 rectangle delta_g;
74 rectangle current_g;
75 rectangle client_g;
76 int anim_steps;
77 Window w_with_focus;
78 int current_step;
79 int curr_titlebar_compression;
80 direction_t shade_dir;
81 window_parts trans_parts;
82 struct
84 unsigned do_force : 1;
85 unsigned do_not_configure_client : 1;
86 unsigned do_not_draw : 1;
87 unsigned do_restore_gravity : 1;
88 unsigned do_set_bit_gravity : 1;
89 unsigned do_update_shape : 1;
90 unsigned had_handles : 1;
91 unsigned is_lazy_shading : 1;
92 unsigned is_setup : 1;
93 unsigned is_shading : 1;
94 unsigned was_moved : 1;
95 } flags;
96 /* used during the animation */
97 int next_titlebar_compression;
98 rectangle next_sidebar_g;
99 rectangle next_g;
100 rectangle dstep_g;
101 size_rect parent_s;
102 int minimal_w_offset;
103 int minimal_h_offset;
104 struct
106 /* cleared before each step */
107 unsigned do_hide_parent : 1;
108 unsigned do_unhide_parent : 1;
109 unsigned is_hidden : 1;
110 unsigned was_hidden : 1;
111 } step_flags;
112 } mr_args_internal;
114 /* ---------------------------- forward declarations ----------------------- */
116 /* ---------------------------- local variables ---------------------------- */
118 /* windows used to hide animation steps */
119 static struct
121 Window parent;
122 Window w[4];
123 } hide_wins;
125 /* ---------------------------- exported variables (globals) --------------- */
127 /* ---------------------------- local functions ---------------------------- */
129 #if 0
130 static void print_g(char *text, rectangle *g)
132 if (g == NULL)
134 fprintf(stderr, "%s: (null)", (text == NULL) ? "" : text);
136 else
138 fprintf(stderr, "%s: %4d %4d %4dx%4d (%4d - %4d %4d - %4d)\n",
139 (text == NULL) ? "" : text,
140 g->x, g->y, g->width, g->height,
141 g->x, g->x + g->width - 1, g->y, g->y + g->height - 1);
144 #endif
146 static void combine_gravities(
147 frame_decor_gravities_type *ret_grav,
148 frame_decor_gravities_type *grav_x,
149 frame_decor_gravities_type *grav_y)
151 ret_grav->decor_grav = gravity_combine_xy_grav(
152 grav_x->decor_grav, grav_y->decor_grav);
153 ret_grav->title_grav = gravity_combine_xy_grav(
154 grav_x->title_grav, grav_y->title_grav);
155 ret_grav->lbutton_grav = gravity_combine_xy_grav(
156 grav_x->lbutton_grav, grav_y->lbutton_grav);
157 ret_grav->rbutton_grav = gravity_combine_xy_grav(
158 grav_x->rbutton_grav, grav_y->rbutton_grav);
159 ret_grav->parent_grav = gravity_combine_xy_grav(
160 grav_x->parent_grav, grav_y->parent_grav);
161 ret_grav->client_grav = gravity_combine_xy_grav(
162 grav_x->client_grav, grav_y->client_grav);
164 return;
167 static void get_resize_decor_gravities_one_axis(
168 frame_decor_gravities_type *ret_grav, direction_t title_dir,
169 frame_move_resize_mode axis_mode, direction_t neg_dir,
170 direction_t pos_dir, int is_moving)
173 int title_grav;
174 int neg_grav;
175 int pos_grav;
177 title_grav = gravity_dir_to_grav(title_dir);
178 neg_grav = gravity_dir_to_grav(neg_dir);
179 pos_grav = gravity_dir_to_grav(pos_dir);
180 if (title_dir != DIR_NONE)
182 ret_grav->decor_grav = title_grav;
183 ret_grav->lbutton_grav = title_grav;
184 ret_grav->title_grav = title_grav;
185 ret_grav->rbutton_grav = title_grav;
187 else
189 ret_grav->decor_grav = neg_grav;
190 ret_grav->lbutton_grav = neg_grav;
191 ret_grav->title_grav = neg_grav;
192 ret_grav->rbutton_grav = pos_grav;
194 switch (axis_mode)
196 case FRAME_MR_SCROLL:
197 ret_grav->client_grav = (is_moving) ? neg_grav : pos_grav;
198 break;
199 case FRAME_MR_SHRINK:
200 ret_grav->client_grav = (is_moving) ? pos_grav : neg_grav;
201 break;
202 case FRAME_MR_OPAQUE:
203 case FRAME_MR_FORCE_SETUP:
204 case FRAME_MR_FORCE_SETUP_NO_W:
205 case FRAME_MR_SETUP:
206 case FRAME_MR_SETUP_BY_APP:
207 ret_grav->client_grav = neg_grav;
208 break;
209 case FRAME_MR_DONT_DRAW:
210 /* can not happen, just a dummy to keep -Wall happy */
211 break;
213 ret_grav->parent_grav = ret_grav->client_grav;
215 return;
218 static void frame_get_titlebar_dimensions_only(
219 FvwmWindow *fw, rectangle *frame_g, size_borders *bs,
220 rectangle *ret_titlebar_g)
222 if (!HAS_TITLE(fw))
224 return;
226 switch (GET_TITLE_DIR(fw))
228 case DIR_W:
229 case DIR_E:
230 ret_titlebar_g->x = (GET_TITLE_DIR(fw) == DIR_W) ?
231 bs->top_left.width :
232 frame_g->width - bs->bottom_right.width -
233 fw->title_thickness;
234 ret_titlebar_g->y = bs->top_left.height;
235 ret_titlebar_g->width = fw->title_thickness;
236 ret_titlebar_g->height =
237 frame_g->height - bs->total_size.height;
238 break;
239 case DIR_N:
240 case DIR_S:
241 default: /* default makes gcc4 happy */
242 ret_titlebar_g->y = (GET_TITLE_DIR(fw) == DIR_N) ?
243 bs->top_left.height :
244 frame_g->height - bs->bottom_right.height -
245 fw->title_thickness;
246 ret_titlebar_g->x = bs->top_left.width;
247 ret_titlebar_g->width = frame_g->width - bs->total_size.width;
248 ret_titlebar_g->height = fw->title_thickness;
249 break;
252 return;
255 static void frame_setup_border(
256 FvwmWindow *fw, rectangle *frame_g, window_parts setup_parts,
257 rectangle *diff_g)
259 XWindowChanges xwc;
260 Window w;
261 window_parts part;
262 rectangle sidebar_g;
263 rectangle part_g;
264 Bool dummy;
266 if (HAS_NO_BORDER(fw))
268 return;
270 frame_get_sidebar_geometry(
271 fw, NULL, frame_g, &sidebar_g, &dummy, &dummy);
272 for (part = PART_BORDER_N; (part & PART_FRAME);
273 part <<= 1)
275 if ((part & PART_FRAME & setup_parts) == PART_NONE)
277 continue;
279 border_get_part_geometry(fw, part, &sidebar_g, &part_g, &w);
280 if (part_g.width <= 0 || part_g.height <= 0)
282 xwc.x = -1;
283 xwc.y = -1;
284 xwc.width = 1;
285 xwc.height = 1;
287 else
289 xwc.x = part_g.x;
290 xwc.y = part_g.y;
291 xwc.width = part_g.width;
292 xwc.height = part_g.height;
294 if (diff_g != NULL)
296 if (part == PART_BORDER_NE || part == PART_BORDER_E ||
297 part == PART_BORDER_SE)
299 xwc.x -= diff_g->width;
301 if (part == PART_BORDER_SW || part == PART_BORDER_S ||
302 part == PART_BORDER_SE)
304 xwc.y -= diff_g->height;
307 XConfigureWindow(dpy, w, CWWidth | CWHeight | CWX | CWY, &xwc);
310 return;
313 static void frame_setup_titlebar(
314 FvwmWindow *fw, rectangle *frame_g, window_parts setup_parts,
315 rectangle *diff_g)
317 frame_title_layout_t title_layout;
318 int i;
320 if (!HAS_TITLE(fw))
322 return;
324 frame_get_titlebar_dimensions(fw, frame_g, diff_g, &title_layout);
325 /* configure buttons */
326 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
328 if (FW_W_BUTTON(fw, i) != None && (setup_parts & PART_BUTTONS))
330 XMoveResizeWindow(
331 dpy, FW_W_BUTTON(fw, i),
332 title_layout.button_g[i].x,
333 title_layout.button_g[i].y,
334 title_layout.button_g[i].width,
335 title_layout.button_g[i].height);
338 /* configure title */
339 if (setup_parts & PART_TITLE)
341 XMoveResizeWindow(
342 dpy, FW_W_TITLE(fw),
343 title_layout.title_g.x, title_layout.title_g.y,
344 title_layout.title_g.width,
345 title_layout.title_g.height);
348 return;
351 static void __frame_setup_window(
352 FvwmWindow *fw, rectangle *frame_g, Bool do_send_configure_notify,
353 Bool do_force, Bool is_application_request)
355 frame_move_resize_args mr_args;
356 Bool is_resized = False;
357 Bool is_moved = False;
358 rectangle new_g;
360 new_g = *frame_g;
361 /* sanity checks */
362 if (new_g.width < 1)
364 new_g.width = 1;
366 if (new_g.height < 1)
368 new_g.height = 1;
370 /* set some flags */
371 if (new_g.width != fw->g.frame.width ||
372 new_g.height != fw->g.frame.height)
374 is_resized = True;
376 if (new_g.x != fw->g.frame.x || new_g.y != fw->g.frame.y)
378 is_moved = True;
380 /* setup the window */
381 if (is_resized || do_force)
383 frame_move_resize_mode mode;
385 if (is_application_request)
387 mode = FRAME_MR_SETUP_BY_APP;
389 else if (do_force)
391 mode = FRAME_MR_FORCE_SETUP;
393 else
395 mode = FRAME_MR_SETUP;
397 mr_args = frame_create_move_resize_args(
398 fw, mode, NULL, &new_g, 0, DIR_NONE);
399 frame_move_resize(fw, mr_args);
400 ((mr_args_internal *)mr_args)->flags.was_moved = 0;
401 frame_free_move_resize_args(fw, mr_args);
402 fw->g.frame = *frame_g;
404 else if (is_moved)
406 unsigned int draw_parts = PART_NONE;
408 /* inform the application of the change
410 * According to the July 27, 1988 ICCCM draft, we should send a
411 * synthetic ConfigureNotify event to the client if the window
412 * was moved but not resized. */
413 XMoveWindow(dpy, FW_W_FRAME(fw), frame_g->x, frame_g->y);
414 fw->g.frame = *frame_g;
415 if ((draw_parts = border_get_transparent_decorations_part(fw))
416 != PART_NONE)
418 border_draw_decorations(
419 fw, draw_parts,
420 ((fw == get_focus_window())) ? True : False,
421 True, CLEAR_ALL, NULL, NULL);
423 fw->g.frame = *frame_g;
424 do_send_configure_notify = True;
426 /* must not send events to shaded windows because this might cause them
427 * to look at their current geometry */
428 if (do_send_configure_notify && !IS_SHADED(fw))
430 SendConfigureNotify(
431 fw, new_g.x, new_g.y, new_g.width, new_g.height, 0,
432 True);
434 /* get things updated */
435 XFlush(dpy);
436 /* inform the modules of the change */
437 BroadcastConfig(M_CONFIGURE_WINDOW,fw);
439 return;
442 static void frame_reparent_hide_windows(
443 Window w)
445 int i;
447 hide_wins.parent = w;
448 for (i = 0; i < 4 ; i++)
450 if (w == Scr.Root)
452 XUnmapWindow(dpy, hide_wins.w[i]);
454 XReparentWindow(dpy, hide_wins.w[i], w, -1, -1);
456 if (w != Scr.Root)
458 XRaiseWindow(dpy, hide_wins.w[0]);
459 XRestackWindows(dpy, hide_wins.w, 4);
462 return;
465 /* Returns True if the frame is so small that the parent window would have a
466 * width or height smaller than one pixel. */
467 static Bool frame_is_parent_hidden(
468 FvwmWindow *fw, rectangle *frame_g)
470 size_borders b;
472 get_window_borders(fw, &b);
473 if (frame_g->width <= b.total_size.width ||
474 frame_g->height <= b.total_size.height)
476 return True;
479 return False;
482 /* Returns the number of pixels that the title bar is too short to accomodate
483 * all the title buttons and a title window that has at least a length of one
484 * pixel. */
485 static int frame_get_titlebar_compression(
486 FvwmWindow *fw, rectangle *frame_g)
488 size_borders b;
489 int space;
490 int need_space;
492 if (!HAS_TITLE(fw))
494 return 0;
496 get_window_borders(fw, &b);
497 if (HAS_VERTICAL_TITLE(fw))
499 space = frame_g->height - b.total_size.height;
501 else
503 space = frame_g->width - b.total_size.width;
505 need_space = (fw->nr_left_buttons + fw->nr_right_buttons) *
506 fw->title_thickness + MIN_WINDOW_TITLE_LENGTH;
507 if (space < need_space)
509 return need_space - space;
512 return 0;
515 /* Calculates the gravities for the various parts of the decor through ret_grav.
516 * This can be passed to frame_set_decor_gravities.
518 * title_dir
519 * The direction of the title in the frame.
520 * rmode
521 * The mode for the resize operation
523 static void frame_get_resize_decor_gravities(
524 frame_decor_gravities_type *ret_grav, direction_t title_dir,
525 frame_move_resize_mode rmode, rectangle *delta_g)
527 frame_decor_gravities_type grav_x;
528 frame_decor_gravities_type grav_y;
529 direction_t title_dir_x;
530 direction_t title_dir_y;
532 gravity_split_xy_dir(&title_dir_x, &title_dir_y, title_dir);
533 get_resize_decor_gravities_one_axis(
534 &grav_x, title_dir_x, rmode, DIR_W, DIR_E, (delta_g->x != 0));
535 get_resize_decor_gravities_one_axis(
536 &grav_y, title_dir_y, rmode, DIR_N, DIR_S, (delta_g->y != 0));
537 combine_gravities(ret_grav, &grav_x, &grav_y);
539 return;
542 /* sets the gravity for the various parts of the window */
543 static void frame_set_decor_gravities(
544 FvwmWindow *fw, frame_decor_gravities_type *grav,
545 int do_set1_restore2_bit_gravity)
547 int valuemask;
548 XSetWindowAttributes xcwa;
549 int i;
550 Bool button_reverted = False;
552 /* using bit gravity can reduce redrawing dramatically */
553 valuemask = CWWinGravity;
554 xcwa.win_gravity = grav->client_grav;
555 if (do_set1_restore2_bit_gravity == 1)
557 XWindowAttributes xwa;
559 if (!fw->attr_backup.is_bit_gravity_stored &&
560 XGetWindowAttributes(dpy, FW_W(fw), &xwa))
562 fw->attr_backup.bit_gravity = xwa.bit_gravity;
564 fw->attr_backup.is_bit_gravity_stored = 1;
565 valuemask |= CWBitGravity;
566 xcwa.bit_gravity = grav->client_grav;
568 else if (do_set1_restore2_bit_gravity == 2)
570 fw->attr_backup.is_bit_gravity_stored = 0;
571 valuemask |= CWBitGravity;
572 xcwa.bit_gravity = fw->attr_backup.bit_gravity;
574 XChangeWindowAttributes(dpy, FW_W(fw), valuemask, &xcwa);
575 xcwa.win_gravity = grav->parent_grav;
576 valuemask = CWWinGravity;
577 XChangeWindowAttributes(dpy, FW_W_PARENT(fw), valuemask, &xcwa);
578 if (!HAS_TITLE(fw))
580 return;
582 xcwa.win_gravity = grav->title_grav;
583 XChangeWindowAttributes(dpy, FW_W_TITLE(fw), valuemask, &xcwa);
584 if (fw->title_text_rotation == ROTATION_270 ||
585 fw->title_text_rotation == ROTATION_180)
587 button_reverted = True;
589 if (button_reverted)
591 xcwa.win_gravity = grav->rbutton_grav;
593 else
595 xcwa.win_gravity = grav->lbutton_grav;
597 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i += 2)
599 if (FW_W_BUTTON(fw, i))
601 XChangeWindowAttributes(
602 dpy, FW_W_BUTTON(fw, i), valuemask, &xcwa);
605 if (button_reverted)
607 xcwa.win_gravity = grav->lbutton_grav;
609 else
611 xcwa.win_gravity = grav->rbutton_grav;
613 for (i = 1; i < NUMBER_OF_TITLE_BUTTONS; i += 2)
615 if (FW_W_BUTTON(fw, i))
617 XChangeWindowAttributes(
618 dpy, FW_W_BUTTON(fw, i), valuemask, &xcwa);
622 return;
625 /* Just restore the win and bit gravities on the client window. */
626 static void frame_restore_client_gravities(FvwmWindow *fw)
628 XSetWindowAttributes xcwa;
629 long valuemask;
631 valuemask = CWWinGravity;
632 if (fw->attr_backup.is_bit_gravity_stored)
634 fw->attr_backup.is_bit_gravity_stored = 0;
635 xcwa.bit_gravity = fw->attr_backup.bit_gravity;
636 valuemask |= CWBitGravity;
638 xcwa.win_gravity = fw->hints.win_gravity;
639 XChangeWindowAttributes(dpy, FW_W(fw), valuemask, &xcwa);
641 return;
644 /* Prepares the structure for the next animation step. */
645 static void frame_next_move_resize_args(
646 frame_move_resize_args mr_args)
648 mr_args_internal *mra;
650 mra = (mr_args_internal *)mr_args;
651 mra->curr_sidebar_g = mra->next_sidebar_g;
652 mra->current_g = mra->next_g;
653 mra->step_flags.was_hidden = mra->step_flags.is_hidden;
654 mra->curr_titlebar_compression = mra->next_titlebar_compression;
656 return;
659 static rectangle *frame_get_hidden_pos(
660 FvwmWindow *fw, mr_args_internal *mra, Bool do_unhide,
661 rectangle *ret_hidden_g)
663 rectangle *target_g;
664 direction_t dir_x;
665 direction_t dir_y;
667 if (do_unhide == False)
669 gravity_split_xy_dir(&dir_x, &dir_y, mra->shade_dir);
670 ret_hidden_g->x = (dir_x == DIR_E) ?
671 -mra->client_g.width + mra->parent_s.width : 0;
672 ret_hidden_g->y = (dir_y == DIR_S) ?
673 -mra->client_g.height + mra->parent_s.height : 0;
674 target_g = &mra->next_g;
676 else
678 gravity_split_xy_dir(&dir_x, &dir_y, SHADED_DIR(fw));
679 if (mra->mode == FRAME_MR_SCROLL)
681 ret_hidden_g->x = (dir_x == DIR_W) ?
682 -mra->client_g.width + mra->parent_s.width : 0;
683 ret_hidden_g->y = (dir_y == DIR_N) ?
684 -mra->client_g.height + mra->parent_s.height :
687 else
689 ret_hidden_g->x = (dir_x == DIR_E) ?
690 -mra->client_g.width + mra->parent_s.width : 0;
691 ret_hidden_g->y = (dir_y == DIR_S) ?
692 -mra->client_g.height + mra->parent_s.height :
695 target_g = &mra->next_g;
698 return target_g;
701 static void frame_update_hidden_window_pos(
702 FvwmWindow *fw, mr_args_internal *mra, Bool do_unhide)
704 rectangle *target_g;
705 rectangle hidden_g;
707 target_g = frame_get_hidden_pos(fw, mra, do_unhide, &hidden_g);
708 XMoveResizeWindow(
709 dpy, FW_W_PARENT(fw), mra->b_g.top_left.width,
710 mra->b_g.top_left.height,
711 max(1, target_g->width - mra->b_g.total_size.width),
712 max(1, target_g->height - mra->b_g.total_size.height));
713 XMoveResizeWindow(
714 dpy, FW_W(fw), hidden_g.x, hidden_g.y, mra->client_g.width,
715 mra->client_g.height);
716 mra->flags.was_moved = 1;
718 return;
721 static void frame_prepare_animation_shape(
722 FvwmWindow *fw, mr_args_internal *mra, int parent_x, int parent_y)
724 rectangle parent_g;
725 rectangle client_g;
727 if (!FShapesSupported)
729 return;
731 parent_g.x = parent_x;
732 parent_g.y = parent_y;
733 parent_g.width = mra->parent_s.width;
734 parent_g.height = mra->parent_s.height;
735 gravity_move_resize_parent_child(
736 mra->grav.parent_grav, &mra->dstep_g, &parent_g);
737 client_g = mra->client_g;
738 frame_get_hidden_pos(fw, mra, True, &client_g);
739 client_g.x += parent_g.x;
740 client_g.y += parent_g.y;
741 FShapeCombineShape(
742 dpy, Scr.NoFocusWin, FShapeBounding, client_g.x, client_g.y,
743 FW_W(fw), FShapeBounding, FShapeSet);
744 if (HAS_TITLE(fw))
746 rectangle tb_g;
747 XRectangle rect;
749 frame_get_titlebar_dimensions_only(
750 fw, &mra->next_g, &mra->b_no_title_g, &tb_g);
751 /* windows w/ titles */
752 rect.x = tb_g.x;
753 rect.y = tb_g.y;
754 rect.width = tb_g.width;
755 rect.height = tb_g.height;
756 FShapeCombineRectangles(
757 dpy, Scr.NoFocusWin, FShapeBounding, 0, 0, &rect, 1,
758 FShapeUnion, Unsorted);
761 return;
764 static void frame_mrs_prepare_vars(
765 FvwmWindow *fw, mr_args_internal *mra)
767 Bool dummy;
768 int i;
770 /* preparations */
771 i = mra->current_step;
772 mra->next_g = mra->start_g;
773 mra->next_g.x += (mra->delta_g.x * i) / mra->anim_steps;
774 mra->next_g.y += (mra->delta_g.y * i) / mra->anim_steps;
775 mra->next_g.width += (mra->delta_g.width * i) / mra->anim_steps;
776 mra->next_g.height += (mra->delta_g.height * i) / mra->anim_steps;
777 frame_get_sidebar_geometry(
778 fw, NULL, &mra->next_g, &mra->next_sidebar_g, &dummy, &dummy);
779 fvwmrect_subtract_rectangles(
780 &mra->dstep_g, &mra->next_g, &mra->current_g);
781 mra->next_titlebar_compression =
782 frame_get_titlebar_compression(fw, &mra->next_g);
783 mra->step_flags.is_hidden =
784 (frame_is_parent_hidden(fw, &mra->next_g) == True);
785 mra->step_flags.do_hide_parent =
786 ((!mra->step_flags.was_hidden || mra->flags.do_force) &&
787 mra->step_flags.is_hidden);
788 mra->step_flags.do_unhide_parent =
789 ((mra->step_flags.was_hidden || mra->flags.do_force) &&
790 !mra->step_flags.is_hidden);
791 /* get the parent's dimensions */
792 mra->parent_s.width = mra->next_g.width - mra->b_g.total_size.width;
793 if (mra->parent_s.width < 1)
795 mra->minimal_w_offset = 1 - mra->parent_s.width;
796 mra->parent_s.width = 1;
798 else
800 mra->minimal_w_offset = 0;
802 mra->parent_s.height = mra->next_g.height - mra->b_g.total_size.height;
803 if (mra->parent_s.height < 1)
805 mra->minimal_h_offset = 1 - mra->parent_s.height;
806 mra->parent_s.height = 1;
808 else
810 mra->minimal_h_offset = 0;
813 return;
816 static void frame_mrs_hide_changing_parts(
817 mr_args_internal *mra)
819 int l_add;
820 int t_add;
821 int r_add;
822 int b_add;
823 int w;
824 int h;
826 t_add = 0;
827 l_add = 0;
828 b_add = 0;
829 r_add = 0;
830 if (mra->mode == FRAME_MR_SHRINK)
832 if (mra->dstep_g.x > 0)
834 l_add = mra->dstep_g.x;
836 if (mra->dstep_g.y > 0)
838 t_add = mra->dstep_g.y;
841 else if (mra->mode == FRAME_MR_SCROLL)
843 if (mra->dstep_g.x == 0 && mra->dstep_g.width < 0)
845 l_add = -mra->dstep_g.width;
847 if (mra->dstep_g.y == 0 && mra->dstep_g.height < 0)
849 t_add = -mra->dstep_g.height;
852 if (l_add > 0)
854 l_add -= mra->minimal_w_offset;
856 else
858 r_add = (mra->dstep_g.width < 0) ? -mra->dstep_g.width : 0;
859 r_add -= mra->minimal_w_offset;
861 if (t_add > 0)
863 t_add -= mra->minimal_h_offset;
865 else
867 b_add = (mra->dstep_g.height < 0) ? -mra->dstep_g.height : 0;
868 b_add -= mra->minimal_h_offset;
870 /* cover top border */
871 w = mra->current_g.width;
872 h = mra->b_g.top_left.height + t_add;
873 if (w > 0 && h > 0)
875 XMoveResizeWindow(dpy, hide_wins.w[0], 0, 0, w, h);
876 XMapWindow(dpy, hide_wins.w[0]);
878 /* cover left border */
879 w = mra->b_g.top_left.width + l_add;
880 h = mra->current_g.height;
881 if (w > 0 && h > 0)
883 XMoveResizeWindow(dpy, hide_wins.w[1], 0, 0, w, h);
884 XMapWindow(dpy, hide_wins.w[1]);
886 /* cover bottom border and possibly part of the client */
887 w = mra->current_g.width;
888 h = mra->b_g.bottom_right.height + b_add;
889 if (w > 0 && h > 0)
891 XMoveResizeWindow(
892 dpy, hide_wins.w[2], 0, mra->current_g.height -
893 mra->b_g.bottom_right.height - b_add, w, h);
894 XMapWindow(dpy, hide_wins.w[2]);
896 /* cover right border and possibly part of the client */
897 w = mra->b_g.bottom_right.width + r_add;
898 h = mra->current_g.height;
899 if (w > 0 && h > 0)
901 XMoveResizeWindow(
902 dpy, hide_wins.w[3], mra->current_g.width -
903 mra->b_g.bottom_right.width - r_add, 0, w, h);
904 XMapWindow(dpy, hide_wins.w[3]);
907 return;
910 static void frame_mrs_hide_unhide_parent(
911 FvwmWindow *fw, mr_args_internal *mra)
913 XSetWindowAttributes xswa;
915 if (mra->step_flags.do_unhide_parent)
917 Window w[2];
919 /* update the hidden position of the client */
920 frame_update_hidden_window_pos(fw, mra, True);
921 w[0] = hide_wins.w[3];
922 w[1] = FW_W_PARENT(fw);
923 XRestackWindows(dpy, w, 2);
925 else if (mra->step_flags.do_hide_parent)
927 /* When the parent gets hidden, unmap it automatically, lower
928 * it while hidden, then remap it. Necessary to eliminate
929 * flickering. */
930 xswa.win_gravity = UnmapGravity;
931 XChangeWindowAttributes(
932 dpy, FW_W_PARENT(fw), CWWinGravity, &xswa);
935 return;
938 static void frame_mrs_hide_unhide_parent2(
939 FvwmWindow *fw, mr_args_internal *mra)
941 XSetWindowAttributes xswa;
943 /* finish hiding the parent */
944 if (mra->step_flags.do_hide_parent)
946 xswa.win_gravity = mra->grav.parent_grav;
947 XChangeWindowAttributes(
948 dpy, FW_W_PARENT(fw), CWWinGravity, &xswa);
949 /* update the hidden position of the client */
950 frame_update_hidden_window_pos(fw, mra, False);
951 XLowerWindow(dpy, FW_W_PARENT(fw));
952 XMapWindow(dpy, FW_W_PARENT(fw));
955 return;
958 static void frame_mrs_setup_draw_decorations(
959 FvwmWindow *fw, mr_args_internal *mra)
961 window_parts setup_parts;
963 /* setup the title bar and the border */
964 setup_parts = PART_TITLE;
965 if (mra->curr_titlebar_compression != mra->next_titlebar_compression ||
966 mra->mode == FRAME_MR_FORCE_SETUP)
968 setup_parts |= PART_BUTTONS;
970 frame_setup_titlebar(fw, &mra->next_g, setup_parts, &mra->dstep_g);
971 frame_setup_border(fw, &mra->next_g, PART_ALL, &mra->dstep_g);
972 /* draw the border and the titlebar */
973 if (mra->flags.do_not_draw == 1)
975 /* nothing */
977 else if (!mra->flags.is_shading || !mra->flags.is_lazy_shading)
979 /* draw as usual */
980 border_draw_decorations(
981 fw, PART_ALL,
982 (mra->w_with_focus != None) ? True : False,
983 (mra->flags.do_force) ? True : False, CLEAR_ALL,
984 &mra->current_g, &mra->next_g);
986 else /* lazy shading */
988 /* Lazy shading relies on the proper window gravities and does
989 * not redraw the decorations during the animation. Only draw
990 * on the first step. */
991 if (mra->current_step == 1)
993 rectangle lazy_g;
995 /* Use the larger width and height values from the
996 * current and the final geometry to get proper
997 * decorations. */
998 lazy_g.x = mra->current_g.x;
999 lazy_g.y = mra->current_g.y;
1000 lazy_g.width = max(
1001 mra->current_g.width, mra->end_g.width);
1002 lazy_g.height = max(
1003 mra->current_g.height, mra->end_g.height);
1004 border_draw_decorations(
1005 fw, PART_ALL,
1006 (mra->w_with_focus != None) ? True : False,
1007 True, CLEAR_ALL, &mra->current_g, &lazy_g);
1011 return;
1014 static void frame_mrs_resize_move_windows(
1015 FvwmWindow *fw, mr_args_internal *mra)
1017 /* setup the parent, the frame and the client window */
1018 if (!mra->flags.is_shading)
1020 if (!mra->step_flags.is_hidden &&
1021 !mra->flags.do_not_configure_client)
1023 XMoveResizeWindow(
1024 dpy, FW_W(fw), 0, 0, mra->parent_s.width,
1025 mra->parent_s.height);
1026 mra->client_g.width = mra->parent_s.width;
1027 mra->client_g.height = mra->parent_s.height;
1029 else
1031 XMoveWindow(dpy, FW_W(fw), 0, 0);
1033 mra->flags.was_moved = 1;
1034 #if 0
1035 /* reduces flickering */
1036 /* dv (11-Aug-2002): ... and slows down large scripts
1037 * dramatically. Rather let it flicker */
1038 if (mra->flags.is_setup)
1040 usleep(1000);
1042 #endif
1043 XSync(dpy, 0);
1044 XMoveResizeWindow(
1045 dpy, FW_W_PARENT(fw), mra->b_g.top_left.width,
1046 mra->b_g.top_left.height, mra->parent_s.width,
1047 mra->parent_s.height);
1049 else
1051 int x;
1052 int y;
1054 x = mra->b_g.top_left.width;
1055 y = mra->b_g.top_left.height;
1056 if (mra->mode == FRAME_MR_SCROLL)
1058 if (mra->dstep_g.x == 0)
1060 x -= mra->dstep_g.width -
1061 mra->minimal_w_offset;
1063 if (mra->dstep_g.y == 0)
1065 y -= mra->dstep_g.height -
1066 mra->minimal_h_offset;;
1069 else if (mra->mode == FRAME_MR_SHRINK)
1071 x += mra->dstep_g.x;
1072 y += mra->dstep_g.y;
1074 if (x > 0)
1076 x -= mra->minimal_w_offset;
1078 else if (x < 0)
1080 x += mra->minimal_w_offset;
1082 if (y > 0)
1084 y -= mra->minimal_h_offset;
1086 else if (y < 0)
1088 y += mra->minimal_h_offset;
1090 XMoveResizeWindow(
1091 dpy, FW_W_PARENT(fw), x, y, mra->parent_s.width,
1092 mra->parent_s.height);
1093 if (mra->flags.do_update_shape)
1095 /* Step 1: apply the union of the old and new shapes.
1096 * This way so that the client stays visible - rather
1097 * let the background show through than force an
1098 * Expose event. */
1099 frame_prepare_animation_shape(fw, mra, x, y);
1100 FShapeCombineShape(
1101 dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0,
1102 Scr.NoFocusWin, FShapeBounding, FShapeUnion);
1105 XMoveResizeWindow(
1106 dpy, FW_W_FRAME(fw), mra->next_g.x, mra->next_g.y,
1107 mra->next_g.width, mra->next_g.height);
1108 if (mra->flags.do_update_shape)
1110 /* Step 2: clip the previous shape. */
1111 FShapeCombineShape(
1112 dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0,
1113 Scr.NoFocusWin, FShapeBounding, FShapeSet);
1116 return;
1119 static void frame_move_resize_step(
1120 FvwmWindow *fw, mr_args_internal *mra)
1122 frame_mrs_prepare_vars(fw, mra);
1123 frame_mrs_hide_changing_parts(mra);
1124 frame_mrs_hide_unhide_parent(fw, mra);
1125 frame_mrs_setup_draw_decorations(fw, mra);
1126 frame_mrs_resize_move_windows(fw, mra);
1127 frame_mrs_hide_unhide_parent2(fw, mra);
1128 fw->g.frame = mra->next_g;
1130 return;
1134 static void frame_has_handles_and_tiled_border(
1135 FvwmWindow *fw, int *ret_has_handles, int *ret_has_tiled_border)
1137 DecorFace *df;
1139 *ret_has_handles = 1;
1140 if (!HAS_HANDLES(fw))
1142 *ret_has_handles = 0;
1144 df = border_get_border_style(fw, (fw == Scr.Hilite) ? True : False);
1145 if (DFS_HAS_HIDDEN_HANDLES(df->style))
1147 *ret_has_handles = 0;
1149 *ret_has_tiled_border =
1150 (DFS_FACE_TYPE(df->style) == TiledPixmapButton) ||
1151 (DFS_FACE_TYPE(df->style) == ColorsetButton &&
1152 !CSET_IS_TRANSPARENT_PR(df->u.acs.cs) &&
1153 CSET_HAS_PIXMAP(df->u.acs.cs));
1155 return;
1158 static int frame_get_shading_laziness(
1159 FvwmWindow *fw, mr_args_internal *mra)
1161 int has_handles;
1162 int has_tiled_pixmap_border;
1163 int using_border_style;
1165 if (!mra->flags.is_shading || mra->anim_steps <= 2)
1167 return 0;
1169 frame_has_handles_and_tiled_border(
1170 fw, &has_handles, &has_tiled_pixmap_border);
1171 if (HAS_TITLE(fw) && has_tiled_pixmap_border)
1173 using_border_style = border_is_using_border_style(
1174 fw, (fw == Scr.Hilite) ? True : False);
1176 else
1178 using_border_style = 0;
1180 switch (WINDOWSHADE_LAZINESS(fw))
1182 case WINDOWSHADE_ALWAYS_LAZY:
1183 return 1;
1184 case WINDOWSHADE_BUSY:
1185 if (has_handles)
1187 return 0;
1189 /* fall through */
1190 case WINDOWSHADE_LAZY:
1191 default:
1192 if (has_tiled_pixmap_border && !HAS_NO_BORDER(fw))
1194 return 0;
1196 else if (has_tiled_pixmap_border && HAS_TITLE(fw) &&
1197 using_border_style)
1199 return 0;
1201 return 1;
1205 void frame_reshape_border(FvwmWindow *fw)
1207 int grav;
1208 int off_x = 0;
1209 int off_y = 0;
1210 rectangle naked_g;
1211 rectangle *new_g;
1213 /* calculate the new offsets */
1214 if (!IS_MAXIMIZED(fw))
1216 grav = fw->hints.win_gravity;
1217 new_g = &fw->g.normal;
1219 else
1221 /* maximized windows are always considered to have
1222 * NorthWestGravity */
1223 grav = NorthWestGravity;
1224 new_g = &fw->g.max;
1225 off_x = fw->g.normal.x - fw->g.max.x;
1226 off_y = fw->g.normal.y - fw->g.max.y;
1228 gravity_get_naked_geometry(grav, fw, &naked_g, new_g);
1229 gravity_translate_to_northwest_geometry_no_bw(
1230 grav, fw, &naked_g, &naked_g);
1231 set_window_border_size(fw, fw->unshaped_boundary_width);
1232 gravity_add_decoration(grav, fw, new_g, &naked_g);
1233 if (IS_MAXIMIZED(fw))
1235 /* prevent random paging when unmaximizing after the border
1236 * width has changed */
1237 fw->g.max_offset.x += fw->g.normal.x - fw->g.max.x - off_x;
1238 fw->g.max_offset.y += fw->g.normal.y - fw->g.max.y - off_y;
1240 if (IS_SHADED(fw))
1242 get_unshaded_geometry(fw, new_g);
1243 if (USED_TITLE_DIR_FOR_SHADING(fw))
1245 SET_SHADED_DIR(fw, GET_TITLE_DIR(fw));
1247 get_shaded_geometry(fw, &fw->g.frame, new_g);
1248 frame_force_setup_window(
1249 fw, fw->g.frame.x, fw->g.frame.y, fw->g.frame.width,
1250 fw->g.frame.height, False);
1252 else
1254 get_relative_geometry(new_g, new_g);
1255 frame_force_setup_window(
1256 fw, new_g->x, new_g->y, new_g->width, new_g->height,
1257 True);
1260 return;
1263 /* ---------------------------- interface functions ------------------------ */
1265 /* Initialise structures local to frame.c */
1266 void frame_init(void)
1268 XSetWindowAttributes xswa;
1269 unsigned long valuemask;
1270 int i;
1272 xswa.override_redirect = True;
1273 xswa.backing_store = NotUseful;
1274 xswa.save_under = False;
1275 xswa.win_gravity = UnmapGravity;
1276 xswa.background_pixmap = None;
1277 valuemask = CWOverrideRedirect | CWSaveUnder | CWBackingStore |
1278 CWBackPixmap | CWWinGravity;
1279 hide_wins.parent = Scr.Root;
1280 for (i = 0; i < 4; i++)
1282 hide_wins.w[i] = XCreateWindow(
1283 dpy, Scr.Root, -1, -1, 1, 1, 0, CopyFromParent,
1284 InputOutput, CopyFromParent, valuemask, &xswa);
1285 if (hide_wins.w[i] == None)
1287 fvwm_msg(ERR, "frame_init",
1288 "Could not create internal windows. Exiting");
1289 MyXUngrabServer(dpy);
1290 exit(1);
1294 return;
1297 Bool is_frame_hide_window(
1298 Window w)
1300 int i;
1302 if (w == None)
1304 return False;
1306 for (i = 0; i < 4; i++)
1308 if (w == hide_wins.w[i])
1310 return True;
1314 return False;
1317 void frame_destroyed_frame(
1318 Window frame_w)
1320 if (hide_wins.parent == frame_w)
1322 /* Oops, the window containing the hide windows was destroyed!
1323 * Let it die and create them from scratch. */
1324 frame_init();
1327 return;
1330 void frame_get_titlebar_dimensions(
1331 FvwmWindow *fw, rectangle *frame_g, rectangle *diff_g,
1332 frame_title_layout_t *title_layout)
1334 size_borders b;
1335 int i;
1336 int tb_length;
1337 int tb_thick;
1338 int tb_x;
1339 int tb_y;
1340 int tb_w;
1341 int tb_h;
1342 int b_length;
1343 int b_w;
1344 int b_h;
1345 int t_length;
1346 int t_w;
1347 int t_h;
1348 int br_sub;
1349 int nbuttons;
1350 int nbuttons_big;
1351 int *padd_coord;
1352 int *b_l;
1353 Bool revert_button = False;
1355 if (!HAS_TITLE(fw))
1357 return;
1359 get_window_borders_no_title(fw, &b);
1360 if (HAS_VERTICAL_TITLE(fw))
1362 tb_length = frame_g->height - b.total_size.height;
1364 else
1366 tb_length = frame_g->width - b.total_size.width;
1368 /* find out the length of the title and the buttons */
1369 tb_thick = fw->title_thickness;
1370 nbuttons = fw->nr_left_buttons + fw->nr_right_buttons;
1371 nbuttons_big = 0;
1372 b_length = tb_thick;
1373 t_length = tb_length - nbuttons * b_length;
1374 if (nbuttons > 0 && t_length < MIN_WINDOW_TITLE_LENGTH)
1376 int diff = MIN_WINDOW_TITLE_LENGTH - t_length;
1377 int pixels = diff / nbuttons;
1379 b_length -= pixels;
1380 t_length += nbuttons * pixels;
1381 nbuttons_big = nbuttons - (MIN_WINDOW_TITLE_LENGTH - t_length);
1382 t_length = MIN_WINDOW_TITLE_LENGTH;
1384 if (b_length < MIN_WINDOW_TITLEBUTTON_LENGTH)
1386 /* don't draw the buttons */
1387 nbuttons = 0;
1388 nbuttons_big = 0;
1389 b_length = 0;
1390 t_length = tb_length;
1392 if (t_length < 0)
1394 t_length = 0;
1396 fw->title_length = t_length;
1397 /* prepare variables */
1398 if (HAS_VERTICAL_TITLE(fw))
1400 tb_y = b.top_left.height;
1401 br_sub = (diff_g != NULL) ? diff_g->height : 0;
1402 if (GET_TITLE_DIR(fw) == DIR_W)
1404 tb_x = b.top_left.width;
1406 else
1408 tb_x = frame_g->width - b.bottom_right.width -
1409 tb_thick;
1410 if (diff_g != NULL)
1412 tb_x -= diff_g->width;
1415 padd_coord = &tb_y;
1416 b_w = tb_thick;
1417 b_h = b_length;
1418 t_w = tb_thick;
1419 t_h = t_length;
1420 b_l = &b_h;
1421 tb_w = tb_thick;
1422 tb_h = tb_length;
1424 else
1426 tb_x = b.top_left.width;
1427 br_sub = (diff_g != NULL) ? diff_g->width : 0;
1428 if (GET_TITLE_DIR(fw) == DIR_N)
1430 tb_y = b.top_left.height;
1432 else
1434 tb_y = frame_g->height - b.bottom_right.height -
1435 tb_thick;
1436 if (diff_g != NULL)
1438 tb_y -= diff_g->height;
1441 padd_coord = &tb_x;
1442 b_w = b_length;
1443 b_h = tb_thick;
1444 t_w = t_length;
1445 t_h = tb_thick;
1446 b_l = &b_w;
1447 tb_w = tb_length;
1448 tb_h = tb_thick;
1450 if (fw->title_text_rotation == ROTATION_270 ||
1451 fw->title_text_rotation == ROTATION_180)
1453 revert_button = True;
1456 /* configure left buttons */
1457 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
1459 if ((revert_button && !(i & 1)) ||
1460 (!revert_button && (i & 1)) || FW_W_BUTTON(fw, i) == None)
1462 continue;
1464 if (b_length <= 0)
1466 title_layout->button_g[i].x = -1;
1467 title_layout->button_g[i].y = -1;
1468 title_layout->button_g[i].width = 1;
1469 title_layout->button_g[i].height = 1;
1471 else
1473 title_layout->button_g[i].x = tb_x;
1474 title_layout->button_g[i].y = tb_y;
1475 title_layout->button_g[i].width = b_w;
1476 title_layout->button_g[i].height = b_h;
1478 *padd_coord += b_length;
1479 nbuttons_big--;
1480 if (nbuttons_big == 0)
1482 b_length--;
1483 (*b_l)--;
1486 /* configure title */
1487 if (t_length == 0)
1489 title_layout->title_g.x = -1;
1490 title_layout->title_g.y = -1;
1491 title_layout->title_g.width = 1;
1492 title_layout->title_g.height = 1;
1494 else
1496 title_layout->title_g.x = tb_x;
1497 title_layout->title_g.y = tb_y;
1498 title_layout->title_g.width = t_w;
1499 title_layout->title_g.height = t_h;
1501 *padd_coord += t_length;
1502 /* configure right buttons */
1503 *padd_coord -= br_sub;
1504 for (i = NUMBER_OF_TITLE_BUTTONS-1; i > -1; i--)
1506 if ((revert_button && (i & 1)) ||
1507 (!revert_button && !(i & 1)) || FW_W_BUTTON(fw, i) == None)
1509 continue;
1511 if (b_length <= 0)
1513 title_layout->button_g[i].x = -1;
1514 title_layout->button_g[i].y = -1;
1515 title_layout->button_g[i].width = 1;
1516 title_layout->button_g[i].height = 1;
1518 else
1520 title_layout->button_g[i].x = tb_x;
1521 title_layout->button_g[i].y = tb_y;
1522 title_layout->button_g[i].width = b_w;
1523 title_layout->button_g[i].height = b_h;
1525 *padd_coord += b_length;
1526 nbuttons_big--;
1527 if (nbuttons_big == 0)
1529 b_length--;
1530 (*b_l)--;
1534 return;
1537 void frame_get_sidebar_geometry(
1538 FvwmWindow *fw, DecorFaceStyle *borderstyle, rectangle *frame_g,
1539 rectangle *ret_g, Bool *ret_has_x_marks, Bool *ret_has_y_marks)
1541 int min_w;
1542 size_borders b;
1544 ret_g->x = 0;
1545 ret_g->y = 0;
1546 ret_g->width = 0;
1547 ret_g->height = 0;
1548 *ret_has_x_marks = False;
1549 *ret_has_y_marks = False;
1550 if (HAS_NO_BORDER(fw))
1552 return;
1554 /* get the corner size */
1555 if (!HAS_HANDLES(fw))
1557 *ret_has_x_marks = False;
1558 *ret_has_y_marks = False;
1560 else if (borderstyle == NULL)
1562 if (fw->decor_state.parts_drawn & PART_X_HANDLES)
1564 *ret_has_x_marks = True;
1566 if (fw->decor_state.parts_drawn & PART_Y_HANDLES)
1568 *ret_has_y_marks = True;
1571 else if (!DFS_HAS_HIDDEN_HANDLES(*borderstyle))
1573 *ret_has_x_marks = True;
1574 *ret_has_y_marks = True;
1576 ret_g->x = fw->corner_width;
1577 ret_g->y = fw->corner_width;
1578 min_w = 2 * fw->corner_width + 4;
1579 /* limit by available space, remove handle marks if necessary */
1580 if (frame_g->width < min_w)
1582 ret_g->x = frame_g->width / 3;
1583 *ret_has_y_marks = False;
1585 if (frame_g->height < min_w)
1587 ret_g->y = frame_g->height / 3;
1588 *ret_has_x_marks = False;
1590 get_window_borders_no_title(fw, &b);
1591 if (ret_g->x < b.top_left.width)
1593 ret_g->x = b.top_left.width;
1595 if (ret_g->y < b.top_left.height)
1597 ret_g->y = b.top_left.height;
1599 /* length of the side bars */
1600 ret_g->width = frame_g->width - 2 * ret_g->x;
1601 ret_g->height = frame_g->height - 2 * ret_g->y;
1603 return;
1606 int frame_window_id_to_context(
1607 FvwmWindow *fw, Window w, int *ret_num)
1609 int context = C_ROOT;
1611 *ret_num = -1;
1612 if (fw == NULL || w == None)
1614 return C_ROOT;
1616 if (w == FW_W_TITLE(fw))
1618 context = C_TITLE;
1620 else if (Scr.EwmhDesktop &&
1621 (w == FW_W(Scr.EwmhDesktop) ||
1622 w == FW_W_PARENT(Scr.EwmhDesktop) ||
1623 w == FW_W_FRAME(Scr.EwmhDesktop)))
1625 context = C_EWMH_DESKTOP;
1627 else if (w == FW_W(fw) || w == FW_W_PARENT(fw) || w == FW_W_FRAME(fw))
1629 context = C_WINDOW;
1631 else if (w == FW_W_ICON_TITLE(fw) || w == FW_W_ICON_PIXMAP(fw))
1633 context = C_ICON;
1635 else if (w == FW_W_CORNER(fw, 0))
1637 *ret_num = 0;
1638 context = C_F_TOPLEFT;
1640 else if (w == FW_W_CORNER(fw, 1))
1642 *ret_num = 1;
1643 context = C_F_TOPRIGHT;
1645 else if (w == FW_W_CORNER(fw, 2))
1647 *ret_num = 2;
1648 context = C_F_BOTTOMLEFT;
1650 else if (w == FW_W_CORNER(fw, 3))
1652 *ret_num = 3;
1653 context = C_F_BOTTOMRIGHT;
1655 else if (w == FW_W_SIDE(fw, 0))
1657 *ret_num = 0;
1658 context = C_SB_TOP;
1660 else if (w == FW_W_SIDE(fw, 1))
1662 *ret_num = 1;
1663 context = C_SB_RIGHT;
1665 else if (w == FW_W_SIDE(fw, 2))
1667 *ret_num = 2;
1668 context = C_SB_BOTTOM;
1670 else if (w == FW_W_SIDE(fw, 3))
1672 *ret_num = 3;
1673 context = C_SB_LEFT;
1675 else
1677 int i;
1679 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
1681 if (w == FW_W_BUTTON(fw, i) &&
1682 ((!(i & 1) && i / 2 < Scr.nr_left_buttons) ||
1683 ( (i & 1) && i / 2 < Scr.nr_right_buttons)))
1685 context = (1 << i) * C_L1;
1686 *ret_num = i;
1687 break;
1691 if (!HAS_HANDLES(fw) && (context & (C_SIDEBAR | C_FRAME)))
1693 context = C_SIDEBAR;
1696 return context;
1699 /* Creates a structure that must be passed to frame_move_resize(). The
1700 * structure *must* be deleted with frame_free_move_resize_args() as soon as the
1701 * move or resize operation is finished. Prepares the window for a move/resize
1702 * operation.
1704 * Arguments:
1705 * fw
1706 * The window to move or resize.
1707 * mr_mode
1708 * The mode of operation:
1709 * FRAME_MR_SETUP: setup the frame
1710 * FRAME_MR_FORCE_SETUP: same, but forces all updates
1711 * FRAME_MR_OPAQUE: resize the frame in an opaque fashion
1712 * FRAME_MR_SHRINK: shrink the client window (useful for shading only)
1713 * FRAME_MR_SCROLL: scroll the client window (useful for shading only)
1714 * start_g
1715 * The initial geometry of the frame. If a NULL pointer is passed, the
1716 * frame_g member of the window is used instead.
1717 * end_g
1718 * The desired new geometry of the frame.
1719 * anim_steps
1720 * The number of animation steps in between
1721 * = 0: The operation is finished in a single step.
1722 * > 0: The given number of steps are drawn in between.
1723 * < 0: Each step resizes the window by the given number of pixels.
1724 * (the sign of the number is flipped first).
1725 * This argument is used only with FRAME_MR_SHRINK and FRAME_MR_SCROLL.
1727 frame_move_resize_args frame_create_move_resize_args(
1728 FvwmWindow *fw, frame_move_resize_mode mr_mode,
1729 rectangle *start_g, rectangle *end_g, int anim_steps, int shade_dir)
1731 mr_args_internal *mra;
1732 Bool dummy;
1733 Bool rc;
1734 int whdiff;
1735 int xydiff;
1736 int diff;
1738 /* set some variables */
1739 mra = (mr_args_internal *)safecalloc(1, sizeof(mr_args_internal));
1740 memset(mra, 0, sizeof(*mra));
1741 if (mr_mode & FRAME_MR_DONT_DRAW)
1743 mr_mode &= ~FRAME_MR_DONT_DRAW;
1744 mra->flags.do_not_draw = 1;
1746 else
1748 mra->flags.do_not_draw = 0;
1750 if (mr_mode == FRAME_MR_SETUP_BY_APP)
1752 mr_mode = FRAME_MR_SETUP;
1753 mra->flags.do_set_bit_gravity = 0;
1755 else
1757 mra->flags.do_set_bit_gravity = 1;
1759 if (mr_mode == FRAME_MR_FORCE_SETUP_NO_W)
1761 mr_mode = FRAME_MR_FORCE_SETUP;
1762 mra->flags.do_not_configure_client = 1;
1764 mra->mode = mr_mode;
1765 mra->shade_dir = (direction_t)shade_dir;
1766 mra->w_with_focus = (fw == get_focus_window()) ? FW_W(fw) : None;
1768 /* calculate various geometries */
1769 if (!IS_SHADED(fw))
1771 rc = XGetGeometry(
1772 dpy, FW_W(fw), &JunkRoot, &mra->client_g.x,
1773 &mra->client_g.y, (unsigned int*)&mra->client_g.width,
1774 (unsigned int*)&mra->client_g.height,
1775 (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth);
1776 if (rc == True)
1778 rc = XTranslateCoordinates(
1779 dpy, FW_W_PARENT(fw), Scr.Root,
1780 mra->client_g.x, mra->client_g.y,
1781 &mra->client_g.x, &mra->client_g.y,
1782 &JunkChild);
1784 if (rc == False)
1786 /* Can only happen if the window died */
1787 get_client_geometry(fw, &mra->client_g);
1790 else
1792 /* If the window was reisez while shaded the client window
1793 * will not have been resized. Use the frame to get the
1794 * geometry */
1795 get_client_geometry(fw, &mra->client_g);
1797 get_window_borders(fw, &mra->b_g);
1798 get_window_borders_no_title(fw, &mra->b_no_title_g);
1799 mra->start_g = (start_g != NULL) ? *start_g : fw->g.frame;
1800 frame_get_sidebar_geometry(
1801 fw, NULL, &mra->start_g, &mra->curr_sidebar_g, &dummy, &dummy);
1802 mra->end_g = *end_g;
1803 mra->current_g = mra->start_g;
1804 mra->next_g = mra->end_g;
1805 mra->curr_titlebar_compression =
1806 frame_get_titlebar_compression(fw, &mra->start_g);
1807 fvwmrect_subtract_rectangles(
1808 &mra->delta_g, &mra->end_g, &mra->start_g);
1810 /* calcuate the number of animation steps */
1811 switch (mra->mode)
1813 case FRAME_MR_SHRINK:
1814 case FRAME_MR_SCROLL:
1815 whdiff = max(abs(mra->delta_g.width), abs(mra->delta_g.height));
1816 xydiff = max(abs(mra->delta_g.x), abs(mra->delta_g.y));
1817 diff = max(whdiff, xydiff);
1818 if (diff == 0)
1820 mra->anim_steps = 0;
1822 else if (anim_steps < 0)
1824 mra->anim_steps = -(diff - 1) / anim_steps;
1826 else if (anim_steps > 0 && anim_steps >= diff)
1828 mra->anim_steps = diff - 1;
1830 else
1832 mra->anim_steps = anim_steps;
1834 mra->anim_steps++;
1835 break;
1836 case FRAME_MR_FORCE_SETUP:
1837 case FRAME_MR_SETUP:
1838 case FRAME_MR_OPAQUE:
1839 default:
1840 mra->anim_steps = 1;
1841 break;
1844 /* various flags */
1845 mra->flags.was_moved = 0;
1846 mra->step_flags.was_hidden =
1847 (frame_is_parent_hidden(fw, &mra->start_g) == True);
1848 mra->flags.is_setup =
1849 (mra->mode == FRAME_MR_FORCE_SETUP ||
1850 mra->mode == FRAME_MR_SETUP);
1851 mra->flags.do_force = (mra->mode == FRAME_MR_FORCE_SETUP);
1852 mra->flags.is_shading =
1853 !(mra->flags.is_setup || mra->mode == FRAME_MR_OPAQUE);
1854 mra->flags.do_update_shape =
1855 (FShapesSupported && mra->flags.is_shading && fw->wShaped);
1856 /* Lazy shading does not draw the hadle marks. Disable them in the
1857 * window flags if necessary. Restores the marks when mr_args are
1858 * freed. Lazy shading is considerably faster but causes funny looks
1859 * if either the border uses a tiled pixmap background. */
1860 mra->flags.had_handles = HAS_HANDLES(fw);
1861 mra->flags.is_lazy_shading = frame_get_shading_laziness(fw, mra);
1862 mra->trans_parts = border_get_transparent_decorations_part(fw);
1863 if (mra->flags.is_lazy_shading)
1865 SET_HAS_HANDLES(fw, 0);
1868 /* Set gravities for the window parts. */
1869 frame_get_resize_decor_gravities(
1870 &mra->grav, GET_TITLE_DIR(fw), mra->mode, &mra->delta_g);
1871 if (mra->flags.is_setup && mra->delta_g.x == 0 && mra->delta_g.y == 0 &&
1872 mra->delta_g.width == 0 && mra->delta_g.height == 0)
1874 frame_decor_gravities_type grav;
1876 /* The caller has already set the frame geometry. Use
1877 * StaticGravity so the sub windows are not moved to funny
1878 * places. */
1879 grav.decor_grav = StaticGravity;
1880 grav.title_grav = StaticGravity;
1881 grav.lbutton_grav = StaticGravity;
1882 grav.rbutton_grav = StaticGravity;
1883 grav.parent_grav = StaticGravity;
1884 grav.client_grav = StaticGravity;
1885 frame_set_decor_gravities(
1886 fw, &grav, (mra->flags.do_set_bit_gravity) ? 1 : 0);
1887 mra->flags.do_restore_gravity = 1;
1888 mra->flags.do_force = 1;
1890 else
1892 frame_set_decor_gravities(
1893 fw, &mra->grav,
1894 (mra->flags.do_set_bit_gravity) ? 1 : 0);
1896 frame_reparent_hide_windows(FW_W_FRAME(fw));
1898 return (frame_move_resize_args)mra;
1901 /* Changes the final_geometry in a frame_move_resize_args structure. This is
1902 * useful during opaque resize operations to avoid creating and destroying the
1903 * args for each animation step.
1905 * If FRAME_MR_SHRINK or FRAME_MR_SCROLL was used to greate the mr_args, the
1906 * function does nothing.
1908 void frame_update_move_resize_args(
1909 frame_move_resize_args mr_args, rectangle *end_g)
1911 mr_args_internal *mra;
1913 mra = (mr_args_internal *)mr_args;
1914 mra->end_g = *end_g;
1915 fvwmrect_subtract_rectangles(
1916 &mra->delta_g, &mra->end_g, &mra->start_g);
1918 return;
1921 /* Destroys the structure allocated with frame_create_move_resize_args(). Does
1922 * some clean up operations on the modified window first. */
1923 void frame_free_move_resize_args(
1924 FvwmWindow *fw, frame_move_resize_args mr_args)
1926 mr_args_internal *mra;
1928 mra = (mr_args_internal *)mr_args;
1929 SET_HAS_HANDLES(fw, mra->flags.had_handles);
1930 fw->g.frame = mra->end_g;
1931 if (mra->flags.is_lazy_shading)
1933 border_draw_decorations(
1934 fw, PART_ALL,
1935 (mra->w_with_focus != None) ? True : False, True,
1936 CLEAR_ALL, &mra->current_g, &mra->end_g);
1938 else if (mra->trans_parts != PART_NONE)
1940 border_draw_decorations(
1941 fw, mra->trans_parts,
1942 (mra->w_with_focus != None) ? True : False, True,
1943 CLEAR_ALL, &mra->current_g, &mra->end_g);
1945 update_absolute_geometry(fw);
1946 frame_reparent_hide_windows(Scr.NoFocusWin);
1947 if (mra->w_with_focus != None)
1949 /* domivogt (28-Dec-1999): For some reason the XMoveResize() on
1950 * the frame window removes the input focus from the client
1951 * window. I have no idea why, but if we explicitly restore
1952 * the focus here everything works fine. */
1953 FOCUS_SET(mra->w_with_focus);
1955 if (mra->flags.do_update_shape)
1957 /* unset shape */
1958 FShapeCombineMask(
1959 dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0, None,
1960 FShapeSet);
1962 frame_setup_shape(fw, mra->end_g.width, mra->end_g.height, fw->wShaped);
1963 if (mra->flags.do_restore_gravity)
1965 mra->grav.client_grav = fw->hints.win_gravity;
1966 frame_set_decor_gravities(
1967 fw, &mra->grav,
1968 (mra->flags.do_set_bit_gravity) ? 2 : 0);
1970 else
1972 frame_restore_client_gravities(fw);
1974 if (!IS_SHADED(fw) && mra->flags.was_moved)
1976 SendConfigureNotify(
1977 fw, fw->g.frame.x, fw->g.frame.y, fw->g.frame.width,
1978 fw->g.frame.height, 0, True);
1979 mra->flags.was_moved = 0;
1981 focus_grab_buttons_on_layer(fw->layer);
1982 /* free the memory */
1983 free(mr_args);
1985 return;
1988 void frame_move_resize(
1989 FvwmWindow *fw, frame_move_resize_args mr_args)
1991 mr_args_internal *mra;
1992 Bool is_grabbed = False;
1993 int i;
1995 mra = (mr_args_internal *)mr_args;
1996 /* freeze the cursor shape; otherwise it may flash to a different shape
1997 * during the animation */
1998 if (mra->anim_steps > 1)
2000 is_grabbed = GrabEm(None, GRAB_FREEZE_CURSOR);
2002 /* animation */
2003 for (i = 1; i <= mra->anim_steps; i++, frame_next_move_resize_args(mra))
2005 mra->current_step = i;
2006 frame_move_resize_step(fw, mra);
2008 if (is_grabbed == True)
2010 UngrabEm(GRAB_FREEZE_CURSOR);
2013 return;
2016 /***********************************************************************
2018 * Procedure:
2019 * frame_setup_window - set window sizes
2021 * Inputs:
2022 * fw - the FvwmWindow pointer
2023 * x - the x coordinate of the upper-left outer corner of the frame
2024 * y - the y coordinate of the upper-left outer corner of the frame
2025 * w - the width of the frame window w/o border
2026 * h - the height of the frame window w/o border
2028 * Special Considerations:
2029 * This routine will check to make sure the window is not completely
2030 * off the display, if it is, it'll bring some of it back on.
2032 * The fw->frame_XXX variables should NOT be updated with the
2033 * values of x,y,w,h prior to calling this routine, since the new
2034 * values are compared against the old to see whether a synthetic
2035 * ConfigureNotify event should be sent. (It should be sent if the
2036 * window was moved but not resized.)
2038 ************************************************************************/
2039 void frame_setup_window(
2040 FvwmWindow *fw, int x, int y, int w, int h,
2041 Bool do_send_configure_notify)
2043 rectangle g;
2045 g.x = x;
2046 g.y = y;
2047 g.width = w;
2048 g.height = h;
2049 __frame_setup_window(fw, &g, do_send_configure_notify, False, False);
2051 return;
2054 void frame_setup_window_app_request(
2055 FvwmWindow *fw, int x, int y, int w, int h,
2056 Bool do_send_configure_notify)
2058 rectangle g;
2060 g.x = x;
2061 g.y = y;
2062 g.width = w;
2063 g.height = h;
2064 __frame_setup_window(fw, &g, do_send_configure_notify, False, True);
2066 return;
2069 void frame_force_setup_window(
2070 FvwmWindow *fw, int x, int y, int w, int h,
2071 Bool do_send_configure_notify)
2073 rectangle g;
2075 g.x = x;
2076 g.y = y;
2077 g.width = w;
2078 g.height = h;
2079 __frame_setup_window(fw, &g, do_send_configure_notify, True, False);
2081 return;
2084 /****************************************************************************
2086 * Sets up the shaped window borders
2088 ****************************************************************************/
2089 void frame_setup_shape(FvwmWindow *fw, int w, int h, int shape_mode)
2091 XRectangle rect;
2092 rectangle r;
2093 size_borders b;
2095 if (!FShapesSupported)
2097 return;
2099 if (fw->wShaped != shape_mode)
2101 fw->wShaped = shape_mode;
2102 frame_reshape_border(fw);
2104 if (!shape_mode)
2106 /* unset shape */
2107 FShapeCombineMask(
2108 dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0, None,
2109 FShapeSet);
2111 else
2113 /* shape the window */
2114 get_window_borders(fw, &b);
2115 FShapeCombineShape(
2116 dpy, FW_W_FRAME(fw), FShapeBounding, b.top_left.width,
2117 b.top_left.height, FW_W(fw), FShapeBounding, FShapeSet);
2118 if (FW_W_TITLE(fw))
2120 /* windows w/ titles */
2121 r.width = w;
2122 r.height = h;
2123 get_title_geometry(fw, &r);
2124 rect.x = r.x;
2125 rect.y = r.y;
2126 rect.width = r.width;
2127 rect.height = r.height;
2128 FShapeCombineRectangles(
2129 dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0,
2130 &rect, 1, FShapeUnion, Unsorted);
2134 return;
2137 /* ---------------------------- builtin commands --------------------------- */