Fix ExplainWindowPlacement when using "NoUSPosition" style.
[fvwm.git] / fvwm / update.c
blob0c033313872f08a448caf255470bcc897bb45818
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"
20 #include <stdio.h>
22 #include "libs/fvwmlib.h"
23 #include "libs/charmap.h"
24 #include "libs/wcontext.h"
25 #include "libs/Grab.h"
26 #include "fvwm.h"
27 #include "externs.h"
28 #include "execcontext.h"
29 #include "cursor.h"
30 #include "bindings.h"
31 #include "misc.h"
32 #include "screen.h"
33 #include "update.h"
34 #include "style.h"
35 #include "builtins.h"
36 #include "borders.h"
37 #include "frame.h"
38 #include "gnome.h"
39 #include "ewmh.h"
40 #include "icons.h"
41 #include "geometry.h"
42 #include "move_resize.h"
43 #include "add_window.h"
44 #include "module_interface.h"
45 #include "focus.h"
46 #include "stack.h"
47 #include "icons.h"
49 /* ---------------------------- local definitions -------------------------- */
51 /* ---------------------------- local macros ------------------------------- */
53 /* ---------------------------- imports ------------------------------------ */
55 /* ---------------------------- included code files ------------------------ */
57 /* ---------------------------- local types -------------------------------- */
59 /* ---------------------------- forward declarations ----------------------- */
61 /* ---------------------------- local variables ---------------------------- */
63 /* ---------------------------- exported variables (globals) --------------- */
65 /* ---------------------------- local functions ---------------------------- */
67 /* ---------------------------- interface functions ------------------------ */
69 static void init_style(
70 FvwmWindow *old_t, FvwmWindow *t, window_style *pstyle,
71 short *pbuttons)
73 /* copy the window structure because we still need some old values. */
74 memcpy(old_t, t, sizeof(FvwmWindow));
75 /* determine level of decoration */
76 setup_style_and_decor(t, pstyle, pbuttons);
77 /* restore some old values */
78 IS_STICKY_ACROSS_PAGES(t) = IS_STICKY_ACROSS_PAGES(old_t);
79 IS_STICKY_ACROSS_DESKS(t) = IS_STICKY_ACROSS_DESKS(old_t);
80 GET_USER_STATES(t) = GET_USER_STATES(old_t);
82 return;
85 static void apply_window_updates(
86 FvwmWindow *t, update_win *flags, window_style *pstyle,
87 FvwmWindow *focus_w)
89 FvwmWindow old_t;
90 short buttons;
91 Bool is_style_initialised = False;
92 rectangle frame_g;
93 const exec_context_t *exc;
94 exec_context_changes_t ecc;
96 frame_g.x = t->g.frame.x;
97 frame_g.y = t->g.frame.y;
98 frame_g.width = t->g.frame.width;
99 frame_g.height = t->g.frame.height;
101 /* TA: 2010-07-28: Conditionally update window states if they're
102 * present -- i.e., we're preserving states set via Windowstyle.
104 GET_USER_STATES(t) = S_USER_STATES(SCF(*pstyle));
106 if (flags->do_setup_focus_policy)
108 setup_focus_policy(t);
109 if (t == focus_w &&
110 !fpol_query_allow_user_focus(&FW_FOCUS_POLICY(t)))
112 focus_w = NULL;
113 if (Scr.Hilite == t)
115 Scr.Hilite = NULL;
117 flags->do_redraw_decoration = True;
120 if (flags->do_update_gnome_styles)
122 if (!S_DO_IGNORE_GNOME_HINTS(SCF(*pstyle)))
124 GNOME_GetStyle(t, pstyle);
127 if (flags->do_update_window_grabs)
129 focus_grab_buttons(t);
131 if (IS_TRANSIENT(t) && flags->do_redecorate_transient)
133 flags->do_redecorate = True;
134 flags->do_update_window_font = True;
138 * is_sticky
139 * is_icon_sticky
141 * These are a bit complicated because they can move windows to a
142 * different page or desk. */
143 ecc.type = EXCT_NULL;
144 ecc.w.fw = t;
145 ecc.w.w = FW_W_FRAME(t);
146 ecc.w.wcontext = C_FRAME;
147 exc = exc_create_context(
148 &ecc, ECC_TYPE | ECC_FW | ECC_W | ECC_WCONTEXT);
149 if (flags->do_update_stick_icon && IS_ICONIFIED(t) &&
150 !(IS_STICKY_ACROSS_PAGES(t) || IS_STICKY_ACROSS_DESKS(t)))
152 if (IS_ICON_STICKY_ACROSS_PAGES(pstyle) ||
153 IS_ICON_STICKY_ACROSS_DESKS(pstyle))
155 /* stick and unstick the window to force the icon on
156 * the current page */
157 handle_stick(
158 NULL, exc, "",
159 S_IS_STICKY_ACROSS_PAGES(SCF(*pstyle)),
160 S_IS_STICKY_ACROSS_DESKS(SCF(*pstyle)), 1, 1);
161 handle_stick(NULL, exc, "", 0, 0, 1, 0);
163 flags->do_update_icon_title = True;
165 else if (flags->do_update_stick)
167 handle_stick(
168 NULL, exc, "", S_IS_STICKY_ACROSS_PAGES(SCF(*pstyle)),
169 S_IS_STICKY_ACROSS_DESKS(SCF(*pstyle)), 0, 0);
171 exc_destroy_context(exc);
172 if (FMiniIconsSupported && flags->do_update_mini_icon)
174 if (!HAS_EWMH_MINI_ICON(t) || DO_EWMH_MINI_ICON_OVERRIDE(t))
176 change_mini_icon(t, pstyle);
178 else
180 if (EWMH_SetIconFromWMIcon(t, NULL, 0, True))
182 SET_HAS_EWMH_MINI_ICON(t, True);
184 else
186 /* "should" not happen */
187 SET_HAS_EWMH_MINI_ICON(t, False);
188 change_mini_icon(t, pstyle);
192 if (flags->do_update_visible_window_name)
194 setup_visible_name(t, False);
195 BroadcastName(M_VISIBLE_NAME,FW_W(t),FW_W_FRAME(t),
196 (unsigned long)t,t->visible_name);
197 EWMH_SetVisibleName(t, False);
200 if (flags->do_update_visible_icon_name)
202 setup_visible_name(t, True);
203 BroadcastName(MX_VISIBLE_ICON_NAME,FW_W(t),FW_W_FRAME(t),
204 (unsigned long)t,t->visible_icon_name);
205 EWMH_SetVisibleName(t, True);
208 if (flags->do_update_window_font || flags->do_update_window_font_height)
210 if (!is_style_initialised)
212 init_style(&old_t, t, pstyle, &buttons);
213 is_style_initialised = True;
215 setup_window_font(t, pstyle, flags->do_update_window_font);
216 flags->do_redecorate = True;
218 if (flags->do_update_title_text_dir)
220 flags->do_redecorate = True;
222 if (flags->do_redecorate || flags->do_update_title_dir)
224 size_borders b_old;
225 size_borders b_new;
226 int dw = 0;
227 int dh = 0;
228 rectangle naked_g;
229 rectangle *new_g;
231 if (flags->do_redecorate)
233 if (!is_style_initialised)
235 init_style(&old_t, t, pstyle, &buttons);
236 is_style_initialised = True;
239 /* redecorate */
240 change_auxiliary_windows(t, buttons);
242 /* calculate the new offsets */
243 /* naked_g: geometry without decor */
244 gravity_get_naked_geometry(
245 old_t.hints.win_gravity, &old_t, &naked_g,
246 &t->g.normal);
247 /* gravity without decor */
248 gravity_translate_to_northwest_geometry_no_bw(
249 old_t.hints.win_gravity, &old_t, &naked_g,
250 &naked_g);
251 /* set g.normal with the decor */
252 gravity_add_decoration(
253 old_t.hints.win_gravity, t, &t->g.normal,
254 &naked_g);
256 if (flags->do_update_title_dir)
258 /* new border sizes */
259 get_window_borders(t, &b_old);
260 SET_TITLE_DIR(t, S_TITLE_DIR(SCF(*pstyle)));
261 setup_title_geometry(t, pstyle);
262 get_window_borders(t, &b_new);
264 /* resizing */
265 dw = b_new.total_size.width - b_old.total_size.width;
266 dh = b_new.total_size.height - b_old.total_size.height;
267 gravity_resize(
268 t->hints.win_gravity, &t->g.normal, dw, dh);
269 gravity_constrain_size(
270 t->hints.win_gravity, t, &t->g.normal, 0);
273 if (IS_MAXIMIZED(t))
275 if (flags->do_redecorate)
277 int off_x = old_t.g.normal.x - old_t.g.max.x;
278 int off_y = old_t.g.normal.y - old_t.g.max.y;
279 int new_off_x;
280 int new_off_y;
282 /* maximized windows are always considered to
283 * have NorthWestGravity */
284 gravity_get_naked_geometry(
285 NorthWestGravity, &old_t, &naked_g,
286 &t->g.max);
287 gravity_translate_to_northwest_geometry_no_bw(
288 NorthWestGravity, &old_t, &naked_g,
289 &naked_g);
290 gravity_add_decoration(
291 NorthWestGravity, t, &t->g.max,
292 &naked_g);
293 /* prevent random paging when unmaximizing
294 * after e.g. the border width has changed */
295 new_off_x = t->g.normal.x - t->g.max.x;
296 new_off_y = t->g.normal.y - t->g.max.y;
297 t->g.max_offset.x += new_off_x - off_x;
298 t->g.max_offset.y += new_off_y - off_y;
300 if (flags->do_update_title_dir)
302 frame_g = t->g.max;
303 gravity_resize(
304 t->hints.win_gravity, &t->g.max, dw,
305 dh);
306 gravity_constrain_size(
307 t->hints.win_gravity, t, &t->g.max,
308 CS_UPDATE_MAX_DEFECT);
310 new_g = &t->g.max;
312 else
314 new_g = &t->g.normal;
316 if (IS_SHADED(t))
318 get_unshaded_geometry(t, new_g);
319 if (USED_TITLE_DIR_FOR_SHADING(t))
321 SET_SHADED_DIR(t, GET_TITLE_DIR(t));
323 get_shaded_geometry(t, &frame_g, new_g);
325 else
327 get_relative_geometry(&frame_g, new_g);
329 flags->do_setup_frame = True;
330 flags->do_redraw_decoration = True;
332 if (flags->do_update_rotated_title)
334 if (t->title_text_rotation != ROTATION_0)
336 flags->do_setup_frame = True;
337 flags->do_redraw_decoration = True;
340 if (flags->do_resize_window)
342 rectangle old_g;
344 setup_frame_size_limits(t, pstyle);
345 old_g = frame_g;
346 frame_g = t->g.normal;
347 gravity_constrain_size(t->hints.win_gravity, t, &frame_g, 0);
348 t->g.normal = frame_g;
349 if (IS_MAXIMIZED(t))
351 frame_g = t->g.max;
352 gravity_constrain_size(
353 t->hints.win_gravity, t, &frame_g,
354 CS_UPDATE_MAX_DEFECT);
355 t->g.max = frame_g;
357 frame_g = old_g;
358 gravity_constrain_size(
359 t->hints.win_gravity, t, &frame_g, 0);
361 flags->do_setup_frame = True;
362 flags->do_redraw_decoration = True;
364 if (flags->do_setup_frame)
366 FvwmWindow *tmp;
368 setup_title_geometry(t, pstyle);
369 /* frame_force_setup_window needs to know if the window is
370 * hilighted */
371 tmp = get_focus_window();
372 set_focus_window(focus_w);
373 frame_force_setup_window(
374 t, frame_g.x, frame_g.y, frame_g.width, frame_g.height,
375 True);
376 set_focus_window(tmp);
377 GNOME_SetWinArea(t);
378 EWMH_SetFrameStrut(t);
380 if (flags->do_update_window_color)
382 if (t != focus_w)
384 flags->do_redraw_decoration = True;
386 update_window_color_style(t, pstyle);
387 if (t != Scr.Hilite)
389 flags->do_broadcast_focus = True;
392 if (flags->do_update_window_color_hi)
394 if (t == focus_w)
396 flags->do_redraw_decoration = True;
398 update_window_color_hi_style(t, pstyle);
399 flags->do_broadcast_focus = True;
400 if (t == Scr.Hilite)
402 flags->do_broadcast_focus = True;
405 if (flags->do_update_icon_title_cs_hi)
407 if (t == focus_w && IS_ICONIFIED(t))
409 flags->do_redraw_icon = True;
411 update_icon_title_cs_hi_style(t, pstyle);
413 if (flags->do_update_icon_title_cs)
415 if (t != focus_w && IS_ICONIFIED(t))
417 flags->do_redraw_icon = True;
419 update_icon_title_cs_style(t, pstyle);
421 if (flags->do_update_icon_background_cs)
423 int old_cs = t->icon_background_cs;
425 update_icon_background_cs_style(t, pstyle);
426 if ((old_cs < 0 && t->icon_background_cs >= 0) ||
427 (old_cs >= 0 && t->icon_background_cs < 0))
429 flags->do_update_icon = True;
431 else
433 flags->do_redraw_icon = True;
436 if (flags->do_update_icon_size_limits)
438 setup_icon_size_limits(t, pstyle);
439 flags->do_update_icon = True;
441 if (flags->do_update_icon_font)
443 if (!is_style_initialised)
445 init_style(&old_t, t, pstyle, &buttons);
446 is_style_initialised = True;
448 setup_icon_font(t, pstyle, flags->do_update_icon_font);
449 flags->do_update_icon_title = True;
451 if (flags->do_update_icon_boxes)
453 change_icon_boxes(t, pstyle);
455 if (flags->do_update_icon)
457 setup_icon_background_parameters(t, pstyle);
458 setup_icon_title_parameters(t, pstyle);
459 change_icon(t, pstyle);
460 flags->do_update_icon_placement = True;
461 flags->do_update_icon_title = False;
462 flags->do_redraw_icon = False;
463 flags->do_update_ewmh_icon = True;
465 if (flags->do_redraw_icon)
467 /* should not test if the window is iconified */
468 DrawIconWindow(t, True, True, False, True, NULL);;
469 flags->do_redraw_decoration = False;
470 flags->do_update_icon_title = False;
472 if (flags->do_update_icon_title)
474 RedoIconName(t);
476 if (flags->do_update_icon_placement)
478 if (IS_ICONIFIED(t))
480 initial_window_options_t win_opts;
482 memset(&win_opts, 0, sizeof(win_opts));
483 SET_ICONIFIED(t, 0);
484 Iconify(t, &win_opts);
485 flags->do_redraw_decoration = False;
488 if (flags->do_redraw_decoration)
490 FvwmWindow *tmp;
492 /* frame_redraw_decorations needs to know if the window is
493 * hilighted */
494 tmp = get_focus_window();
495 set_focus_window(focus_w);
496 if (IS_ICONIFIED(t))
498 DrawIconWindow(t, True, True, False, False, NULL);
500 else
502 border_redraw_decorations(t);
504 set_focus_window(tmp);
506 if (flags->do_update_frame_attributes)
508 setup_frame_attributes(t, pstyle);
510 if (flags->do_update_ewmh_state_hints)
512 EWMH_SetWMState(t, False);
514 if (flags->do_update_modules_flags)
516 BroadcastConfig(M_CONFIGURE_WINDOW,t);
518 if (flags->do_update_ewmh_mini_icon || flags->do_update_ewmh_icon)
520 EWMH_DoUpdateWmIcon(
521 t, flags->do_update_ewmh_mini_icon,
522 flags->do_update_ewmh_icon);
524 if (flags->do_update_placement_penalty)
526 setup_placement_penalty(t, pstyle);
528 if (flags->do_update_working_area)
530 EWMH_UpdateWorkArea();
532 if (flags->do_update_ewmh_stacking_hints)
534 if (DO_EWMH_USE_STACKING_HINTS(t))
536 if (t->ewmh_hint_layer > 0 &&
537 t->layer != t->ewmh_hint_layer)
539 t->ewmh_normal_layer = t->layer;
540 new_layer(t, t->ewmh_hint_layer);
543 else
545 if (t->ewmh_hint_layer > 0 && t->ewmh_normal_layer)
547 if (t->ewmh_normal_layer)
549 new_layer(t, t->ewmh_normal_layer);
551 else
553 new_layer(t, Scr.DefaultLayer);
558 if (flags->do_update_ewmh_allowed_actions)
560 EWMH_SetAllowedActions(t);
562 if (flags->do_broadcast_focus)
564 if (Scr.Hilite != NULL && t == Scr.Hilite)
566 BroadcastPacket(
567 M_FOCUS_CHANGE, 5, (long)FW_W(Scr.Hilite),
568 (long)FW_W_FRAME(Scr.Hilite), (long)0,
569 (long)Scr.Hilite->hicolors.fore,
570 (long)Scr.Hilite->hicolors.back);
573 if (flags->do_refresh)
575 if (!IS_ICONIFIED(t))
577 refresh_window(FW_W_FRAME(t), False);
580 setup_numeric_vals(t, pstyle);
581 if (flags->do_update_cr_motion_method)
583 switch (SCR_MOTION_METHOD(&pstyle->flags))
585 case WS_CR_MOTION_METHOD_AUTO:
586 if (WAS_CR_MOTION_METHOD_DETECTED(t))
588 /* method was already detected, keep it */
589 break;
591 /* fall through */
592 case WS_CR_MOTION_METHOD_USE_GRAV:
593 case WS_CR_MOTION_METHOD_STATIC_GRAV:
594 SET_CR_MOTION_METHOD(
595 t, SCR_MOTION_METHOD(&pstyle->flags));
596 SET_CR_MOTION_METHOD_DETECTED(t, 0);
597 break;
601 if (flags->do_update_layer)
603 int layer = get_layer(t);
605 if (SUSE_LAYER(&pstyle->flags))
607 /* use layer from style */
608 layer = SGET_LAYER(*pstyle);
611 /* Set the layer, and modify the stack ring. */
612 new_layer(t, layer);
615 return;
618 /* ---------------------------- builtin commands --------------------------- */
620 /* takes only care of destroying windows that have to go away. */
621 void destroy_scheduled_windows(void)
623 flist *t;
624 Bool do_need_ungrab = False;
626 if (Scr.flags.is_executing_complex_function ||
627 Scr.flags.is_executing_menu_function ||
628 !Scr.flags.is_window_scheduled_for_destroy)
630 return;
632 /* Grab the server during the style update! */
633 if (GrabEm(CRS_WAIT, GRAB_BUSY))
635 do_need_ungrab = True;
637 MyXGrabServer(dpy);
638 Scr.flags.is_window_scheduled_for_destroy = 0;
639 /* need to destroy one or more windows before looking at the window
640 * list */
641 for (t = Scr.FWScheduledForDestroy; t != NULL; t = t->next)
643 destroy_window(t->object);
645 Scr.FWScheduledForDestroy = flist_free_list(Scr.FWScheduledForDestroy);
646 MyXUngrabServer(dpy);
647 if (do_need_ungrab)
649 UngrabEm(GRAB_BUSY);
652 return;
655 /* similar to the flush_window_updates() function, but does only the updates
656 * for a single window whose decor has been changed. */
657 void apply_decor_change(FvwmWindow *fw)
659 window_style style;
660 update_win flags;
662 lookup_style(fw, &style);
663 memset(&flags, 0, sizeof(flags));
664 flags.do_redecorate = True;
665 flags.do_update_window_font_height = True;
666 apply_window_updates(fw, &flags, &style, get_focus_window());
668 return;
671 /* Check and apply new style to each window if the style has changed. */
672 void flush_window_updates(void)
674 FvwmWindow *t;
675 window_style style;
676 FvwmWindow *focus_fw;
677 Bool do_need_ungrab = False;
678 update_win flags;
680 /* Grab the server during the style update! */
681 if (GrabEm(CRS_WAIT, GRAB_BUSY))
683 do_need_ungrab = True;
685 MyXGrabServer(dpy);
687 /* This is necessary in case the focus policy changes. With
688 * ClickToFocus some buttons have to be grabbed/ungrabbed. */
689 focus_fw = get_focus_window();
690 DeleteFocus(False);
692 /* Apply the new default font and colours first */
693 if (Scr.flags.has_default_color_changed ||
694 Scr.flags.has_default_font_changed)
696 ApplyDefaultFontAndColors();
699 /* update styles for all windows */
700 for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
702 memset(&flags, 0, sizeof(update_win));
703 check_window_style_change(t, &flags, &style);
704 if (Scr.flags.has_xinerama_state_changed)
706 flags.do_update_icon_boxes = True;
707 flags.do_update_icon_placement = True;
709 if (Scr.flags.has_nr_buttons_changed)
711 flags.do_redecorate = True;
713 /* TODO: this is not optimised for minimal redrawing yet*/
714 if (t->decor->flags.has_changed)
716 flags.do_redecorate = True;
717 flags.do_update_window_font_height = True;
719 if (Scr.flags.has_default_font_changed && !HAS_ICON_FONT(t))
721 flags.do_update_icon_font = True;
723 if (Scr.flags.has_default_font_changed && !HAS_WINDOW_FONT(t))
725 flags.do_update_window_font = True;
727 if (t->decor->flags.has_title_height_changed)
729 flags.do_update_window_font_height = True;
731 if (Scr.flags.has_mouse_binding_changed)
733 flags.do_update_window_grabs = True;
735 /* now apply the changes */
736 apply_window_updates(t, &flags, &style, focus_fw);
739 /* restore the focus; also handles the case that the previously focused
740 * window is now NeverFocus */
741 if (focus_fw)
743 SetFocusWindow(focus_fw, False, FOCUS_SET_FORCE);
744 if (Scr.flags.has_mouse_binding_changed)
746 focus_grab_buttons(focus_fw);
749 else
751 DeleteFocus(True);
754 /* finally clean up the change flags */
755 reset_style_changes();
756 reset_decor_changes();
757 Scr.flags.do_need_window_update = 0;
758 Scr.flags.has_default_font_changed = 0;
759 Scr.flags.has_default_color_changed = 0;
760 Scr.flags.has_mouse_binding_changed = 0;
761 Scr.flags.has_nr_buttons_changed = 0;
762 Scr.flags.has_xinerama_state_changed = 0;
764 MyXUngrabServer(dpy);
765 if (do_need_ungrab)
767 UngrabEm(GRAB_BUSY);
770 return;
773 void CMD_UpdateStyles(F_CMD_ARGS)
775 if (Scr.flags.do_need_window_update)
777 flush_window_updates();
780 return;