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 #include <stdio.h>
20 
21 #include "libs/fvwmlib.h"
22 #include "libs/charmap.h"
23 #include "libs/wcontext.h"
24 #include "libs/Grab.h"
25 #include "fvwm.h"
26 #include "externs.h"
27 #include "execcontext.h"
28 #include "cursor.h"
29 #include "bindings.h"
30 #include "misc.h"
31 #include "screen.h"
32 #include "update.h"
33 #include "style.h"
34 #include "builtins.h"
35 #include "borders.h"
36 #include "frame.h"
37 #include "ewmh.h"
38 #include "icons.h"
39 #include "geometry.h"
40 #include "move_resize.h"
41 #include "add_window.h"
42 #include "module_interface.h"
43 #include "focus.h"
44 #include "stack.h"
45 #include "icons.h"
46 
47 /* ---------------------------- local definitions -------------------------- */
48 
49 /* ---------------------------- local macros ------------------------------- */
50 
51 /* ---------------------------- imports ------------------------------------ */
52 
53 /* ---------------------------- included code files ------------------------ */
54 
55 /* ---------------------------- local types -------------------------------- */
56 
57 /* ---------------------------- forward declarations ----------------------- */
58 
59 /* ---------------------------- local variables ---------------------------- */
60 
61 /* ---------------------------- exported variables (globals) --------------- */
62 
63 /* ---------------------------- local functions ---------------------------- */
64 
65 /* ---------------------------- interface functions ------------------------ */
66 
init_style(FvwmWindow * old_t,FvwmWindow * t,window_style * pstyle,short * pbuttons)67 static void init_style(
68 	FvwmWindow *old_t, FvwmWindow *t, window_style *pstyle,
69 	short *pbuttons)
70 {
71 	/* copy the window structure because we still need some old values. */
72 	memcpy(old_t, t, sizeof(FvwmWindow));
73 	/* determine level of decoration */
74 	setup_style_and_decor(t, pstyle, pbuttons);
75 	/* restore some old values */
76 	IS_STICKY_ACROSS_PAGES(t) = IS_STICKY_ACROSS_PAGES(old_t);
77 	IS_STICKY_ACROSS_DESKS(t) = IS_STICKY_ACROSS_DESKS(old_t);
78 	GET_USER_STATES(t) = GET_USER_STATES(old_t);
79 
80 	return;
81 }
82 
apply_window_updates(FvwmWindow * t,update_win * flags,window_style * pstyle,FvwmWindow * focus_w)83 static void apply_window_updates(
84 	FvwmWindow *t, update_win *flags, window_style *pstyle,
85 	FvwmWindow *focus_w)
86 {
87 	FvwmWindow old_t;
88 	short buttons;
89 	Bool is_style_initialised = False;
90 	rectangle frame_g;
91 	const exec_context_t *exc;
92 	exec_context_changes_t ecc;
93 
94 	frame_g.x = t->g.frame.x;
95 	frame_g.y = t->g.frame.y;
96 	frame_g.width = t->g.frame.width;
97 	frame_g.height = t->g.frame.height;
98 
99 	/* TA:  2010-07-28:  Conditionally update window states if they're
100 	 * present -- i.e., we're preserving states set via Windowstyle.
101 	 */
102 	CLEAR_USER_STATES(t, S_USER_STATES(SCM(*pstyle)));
103 	SET_USER_STATES(t, S_USER_STATES(SCF(*pstyle)));
104 
105 	if (flags->do_setup_focus_policy)
106 	{
107 		setup_focus_policy(t);
108 		if (t == focus_w &&
109 		    !fpol_query_allow_user_focus(&FW_FOCUS_POLICY(t)))
110 		{
111 			focus_w = NULL;
112 			if (Scr.Hilite == t)
113 			{
114 				Scr.Hilite = NULL;
115 			}
116 			flags->do_redraw_decoration = True;
117 		}
118 	}
119 	if (flags->do_update_window_grabs)
120 	{
121 		focus_grab_buttons(t);
122 	}
123 	if (IS_TRANSIENT(t) && flags->do_redecorate_transient)
124 	{
125 		flags->do_redecorate = True;
126 		flags->do_update_window_font = True;
127 	}
128 
129 	/*
130 	 * is_sticky
131 	 * is_icon_sticky
132 	 *
133 	 * These are a bit complicated because they can move windows to a
134 	 * different page or desk. */
135 	ecc.type = EXCT_NULL;
136 	ecc.w.fw = t;
137 	ecc.w.w = FW_W_FRAME(t);
138 	ecc.w.wcontext = C_FRAME;
139 	exc = exc_create_context(
140 		&ecc, ECC_TYPE | ECC_FW | ECC_W | ECC_WCONTEXT);
141 	if (flags->do_update_stick_icon && IS_ICONIFIED(t) &&
142 	    !(IS_STICKY_ACROSS_PAGES(t) || IS_STICKY_ACROSS_DESKS(t)))
143 	{
144 		if (IS_ICON_STICKY_ACROSS_PAGES(pstyle) ||
145 		    IS_ICON_STICKY_ACROSS_DESKS(pstyle))
146 		{
147 			/* stick and unstick the window to force the icon on
148 			 * the current page */
149 			handle_stick(
150 				NULL, exc, "",
151 				S_IS_STICKY_ACROSS_PAGES(SCF(*pstyle)),
152 				S_IS_STICKY_ACROSS_DESKS(SCF(*pstyle)), 1, 1);
153 			handle_stick(NULL, exc, "", 0, 0, 1, 0);
154 		}
155 		flags->do_update_icon_title = True;
156 	}
157 	else if (flags->do_update_stick)
158 	{
159 		handle_stick(
160 			NULL, exc, "", S_IS_STICKY_ACROSS_PAGES(SCF(*pstyle)),
161 			S_IS_STICKY_ACROSS_DESKS(SCF(*pstyle)), 0, 0);
162 	}
163 	exc_destroy_context(exc);
164 	if (FMiniIconsSupported && flags->do_update_mini_icon)
165 	{
166 		if (!HAS_EWMH_MINI_ICON(t) || DO_EWMH_MINI_ICON_OVERRIDE(t))
167 		{
168 			change_mini_icon(t, pstyle);
169 		}
170 		else
171 		{
172 			if (EWMH_SetIconFromWMIcon(t, NULL, 0, True))
173 			{
174 				SET_HAS_EWMH_MINI_ICON(t, True);
175 			}
176 			else
177 			{
178 				/* "should" not happen */
179 				SET_HAS_EWMH_MINI_ICON(t, False);
180 				change_mini_icon(t, pstyle);
181 			}
182 		}
183 	}
184 	if (flags->do_update_visible_window_name)
185 	{
186 		setup_visible_names(t, 4);
187 		BroadcastName(M_VISIBLE_NAME,FW_W(t),FW_W_FRAME(t),
188 			      (unsigned long)t,t->visible_name);
189 		EWMH_SetVisibleName(t, False);
190 	}
191 
192 	if (flags->do_update_visible_icon_name)
193 	{
194 		setup_visible_names(t, 8);
195 		BroadcastName(MX_VISIBLE_ICON_NAME,FW_W(t),FW_W_FRAME(t),
196 			      (unsigned long)t,t->visible_icon_name);
197 		EWMH_SetVisibleName(t, True);
198 	}
199 
200 	if (flags->do_update_window_font || flags->do_update_window_font_height)
201 	{
202 		if (!is_style_initialised)
203 		{
204 			init_style(&old_t, t, pstyle, &buttons);
205 			is_style_initialised = True;
206 		}
207 		setup_window_font(t, pstyle, flags->do_update_window_font);
208 		flags->do_redecorate = True;
209 	}
210 	if (flags->do_update_title_text_dir)
211 	{
212 		flags->do_redecorate = True;
213 	}
214 	if (flags->do_redecorate || flags->do_update_title_dir)
215 	{
216 		size_borders b_old;
217 		size_borders b_new;
218 		int dw = 0;
219 		int dh = 0;
220 		rectangle naked_g;
221 		rectangle *new_g;
222 
223 		if (flags->do_redecorate)
224 		{
225 			if (!is_style_initialised)
226 			{
227 				init_style(&old_t, t, pstyle, &buttons);
228 				is_style_initialised = True;
229 			}
230 
231 			/* redecorate */
232 			change_auxiliary_windows(t, buttons);
233 
234 			/* calculate the new offsets */
235 			/* naked_g: geometry without decor */
236 			gravity_get_naked_geometry(
237 				old_t.hints.win_gravity, &old_t, &naked_g,
238 				&t->g.normal);
239 			/* gravity without decor */
240 			gravity_translate_to_northwest_geometry_no_bw(
241 				old_t.hints.win_gravity, &old_t, &naked_g,
242 				&naked_g);
243 			/* set g.normal with the decor */
244 			gravity_add_decoration(
245 				old_t.hints.win_gravity, t, &t->g.normal,
246 				&naked_g);
247 		}
248 		if (flags->do_update_title_dir)
249 		{
250 			/* new border sizes */
251 			get_window_borders(t, &b_old);
252 			SET_TITLE_DIR(t, S_TITLE_DIR(SCF(*pstyle)));
253 			setup_title_geometry(t, pstyle);
254 			get_window_borders(t, &b_new);
255 
256 			/* resizing */
257 			dw = b_new.total_size.width - b_old.total_size.width;
258 			dh = b_new.total_size.height - b_old.total_size.height;
259 			gravity_resize(
260 				t->hints.win_gravity, &t->g.normal, dw, dh);
261 			gravity_constrain_size(
262 				t->hints.win_gravity, t, &t->g.normal, 0);
263 		}
264 
265 		if (IS_MAXIMIZED(t))
266 		{
267 			if (flags->do_redecorate)
268 			{
269 				int off_x = old_t.g.normal.x - old_t.g.max.x;
270 				int off_y = old_t.g.normal.y - old_t.g.max.y;
271 				int new_off_x;
272 				int new_off_y;
273 
274 				/* maximized windows are always considered to
275 				 * have NorthWestGravity */
276 				gravity_get_naked_geometry(
277 					NorthWestGravity, &old_t, &naked_g,
278 					&t->g.max);
279 				gravity_translate_to_northwest_geometry_no_bw(
280 					NorthWestGravity, &old_t, &naked_g,
281 					&naked_g);
282 				gravity_add_decoration(
283 					NorthWestGravity, t, &t->g.max,
284 					&naked_g);
285 				/* prevent random paging when unmaximizing
286 				 * after e.g. the border width has changed */
287 				new_off_x = t->g.normal.x - t->g.max.x;
288 				new_off_y = t->g.normal.y - t->g.max.y;
289 				t->g.max_offset.x += new_off_x - off_x;
290 				t->g.max_offset.y += new_off_y - off_y;
291 			}
292 			if (flags->do_update_title_dir)
293 			{
294 				frame_g = t->g.max;
295 				gravity_resize(
296 					t->hints.win_gravity, &t->g.max, dw,
297 					dh);
298 				gravity_constrain_size(
299 					t->hints.win_gravity, t, &t->g.max,
300 					CS_UPDATE_MAX_DEFECT);
301 			}
302 			new_g = &t->g.max;
303 		}
304 		else
305 		{
306 			new_g = &t->g.normal;
307 		}
308 		if (IS_SHADED(t))
309 		{
310 			get_unshaded_geometry(t, new_g);
311 			if (USED_TITLE_DIR_FOR_SHADING(t))
312 			{
313 				SET_SHADED_DIR(t, GET_TITLE_DIR(t));
314 			}
315 			get_shaded_geometry(t, &frame_g, new_g);
316 		}
317 		else
318 		{
319 			get_relative_geometry(&frame_g, new_g);
320 		}
321 		flags->do_setup_frame = True;
322 		flags->do_redraw_decoration = True;
323 	}
324 	if (flags->do_update_rotated_title)
325 	{
326 		if (t->title_text_rotation != ROTATION_0)
327 		{
328 			flags->do_setup_frame = True;
329 			flags->do_redraw_decoration = True;
330 		}
331 	}
332 	if (flags->do_resize_window)
333 	{
334 		rectangle old_g;
335 
336 		setup_frame_size_limits(t, pstyle);
337 		old_g = frame_g;
338 		frame_g = t->g.normal;
339 		gravity_constrain_size(t->hints.win_gravity, t, &frame_g, 0);
340 		t->g.normal = frame_g;
341 		if (IS_MAXIMIZED(t))
342 		{
343 			frame_g = t->g.max;
344 			gravity_constrain_size(
345 				t->hints.win_gravity, t, &frame_g,
346 				CS_UPDATE_MAX_DEFECT);
347 			t->g.max = frame_g;
348 		}
349 		frame_g = old_g;
350 		gravity_constrain_size(
351 			t->hints.win_gravity, t, &frame_g, 0);
352 
353 		flags->do_setup_frame = True;
354 		flags->do_redraw_decoration = True;
355 	}
356 	if (flags->do_setup_frame)
357 	{
358 		FvwmWindow *tmp;
359 
360 		setup_title_geometry(t, pstyle);
361 		/* frame_force_setup_window needs to know if the window is
362 		 * hilighted */
363 		tmp = get_focus_window();
364 		set_focus_window(focus_w);
365 		frame_force_setup_window(
366 			t, frame_g.x, frame_g.y, frame_g.width, frame_g.height,
367 			True);
368 		set_focus_window(tmp);
369 		EWMH_SetFrameStrut(t);
370 	}
371 	if (flags->do_update_window_color)
372 	{
373 		if (t != focus_w)
374 		{
375 			flags->do_redraw_decoration = True;
376 		}
377 		update_window_color_style(t, pstyle);
378 		if (t != Scr.Hilite)
379 		{
380 			flags->do_broadcast_focus = True;
381 		}
382 	}
383 	if (flags->do_update_window_color_hi)
384 	{
385 		if (t == focus_w)
386 		{
387 			flags->do_redraw_decoration = True;
388 		}
389 		update_window_color_hi_style(t, pstyle);
390 		flags->do_broadcast_focus = True;
391 		if (t == Scr.Hilite)
392 		{
393 			flags->do_broadcast_focus = True;
394 		}
395 	}
396 	if (flags->do_update_icon_title_cs_hi)
397 	{
398 		if (t == focus_w && IS_ICONIFIED(t))
399 		{
400 			flags->do_redraw_icon = True;
401 		}
402 		update_icon_title_cs_hi_style(t, pstyle);
403 	}
404 	if (flags->do_update_icon_title_cs)
405 	{
406 		if (t != focus_w && IS_ICONIFIED(t))
407 		{
408 			flags->do_redraw_icon = True;
409 		}
410 		update_icon_title_cs_style(t, pstyle);
411 	}
412 	if (flags->do_update_icon_background_cs)
413 	{
414 		int old_cs = t->icon_background_cs;
415 
416 		update_icon_background_cs_style(t, pstyle);
417 		if ((old_cs < 0 && t->icon_background_cs >= 0) ||
418 		    (old_cs >= 0 && t->icon_background_cs < 0))
419 		{
420 			flags->do_update_icon = True;
421 		}
422 		else
423 		{
424 			flags->do_redraw_icon = True;
425 		}
426 	}
427 	if (flags->do_update_icon_size_limits)
428 	{
429 		setup_icon_size_limits(t, pstyle);
430 		flags->do_update_icon = True;
431 	}
432 	if (flags->do_update_icon_font)
433 	{
434 		if (!is_style_initialised)
435 		{
436 			init_style(&old_t, t, pstyle, &buttons);
437 			is_style_initialised = True;
438 		}
439 		setup_icon_font(t, pstyle, flags->do_update_icon_font);
440 		flags->do_update_icon_title = True;
441 	}
442 	if (flags->do_update_icon_boxes)
443 	{
444 		change_icon_boxes(t, pstyle);
445 	}
446 	if (flags->do_update_icon)
447 	{
448 		setup_icon_background_parameters(t, pstyle);
449 		setup_icon_title_parameters(t, pstyle);
450 		change_icon(t, pstyle);
451 		flags->do_update_icon_placement = True;
452 		flags->do_update_icon_title = False;
453 		flags->do_redraw_icon = False;
454 		flags->do_update_ewmh_icon = True;
455 	}
456 	if (flags->do_redraw_icon)
457 	{
458 		/* should not test if the window is iconified */
459 		DrawIconWindow(t, True, True, False, True, NULL);;
460 		flags->do_redraw_decoration = False;
461 		flags->do_update_icon_title = False;
462 	}
463 	if (flags->do_update_icon_title)
464 	{
465 		RedoIconName(t);
466 	}
467 	if (flags->do_update_icon_placement)
468 	{
469 		if (IS_ICONIFIED(t))
470 		{
471 			initial_window_options_t win_opts;
472 
473 			memset(&win_opts, 0, sizeof(win_opts));
474 			SET_ICONIFIED(t, 0);
475 			Iconify(t, &win_opts);
476 			flags->do_redraw_decoration = False;
477 		}
478 	}
479 	if (flags->do_redraw_decoration)
480 	{
481 		FvwmWindow *tmp;
482 
483 		/* frame_redraw_decorations needs to know if the window is
484 		 * hilighted */
485 		tmp = get_focus_window();
486 		set_focus_window(focus_w);
487 		if (IS_ICONIFIED(t))
488 		{
489 			DrawIconWindow(t, True, True, False, False, NULL);
490 		}
491 		else
492 		{
493 			border_redraw_decorations(t);
494 		}
495 		set_focus_window(tmp);
496 	}
497 	if (flags->do_update_frame_attributes)
498 	{
499 		setup_frame_attributes(t, pstyle);
500 	}
501 	if (flags->do_update_ewmh_state_hints)
502 	{
503 		EWMH_SetWMState(t, False);
504 	}
505 	if (flags->do_update_modules_flags)
506 	{
507 		BroadcastConfig(M_CONFIGURE_WINDOW,t);
508 	}
509 	if (flags->do_update_ewmh_mini_icon || flags->do_update_ewmh_icon)
510 	{
511 		EWMH_DoUpdateWmIcon(
512 			t, flags->do_update_ewmh_mini_icon,
513 			flags->do_update_ewmh_icon);
514 	}
515 	if (flags->do_update_placement_penalty)
516 	{
517 		setup_placement_penalty(t, pstyle);
518 	}
519 	if (flags->do_update_working_area)
520 	{
521 		EWMH_UpdateWorkArea();
522 	}
523 	if (flags->do_update_ewmh_stacking_hints)
524 	{
525 		if (DO_EWMH_USE_STACKING_HINTS(t))
526 		{
527 			if (t->ewmh_hint_layer > 0 &&
528 			    t->layer != t->ewmh_hint_layer)
529 			{
530 				t->ewmh_normal_layer = t->layer;
531 				new_layer(t, t->ewmh_hint_layer);
532 			}
533 		}
534 		else
535 		{
536 			if (t->ewmh_hint_layer > 0 && t->ewmh_normal_layer)
537 			{
538 				if (t->ewmh_normal_layer)
539 				{
540 					new_layer(t, t->ewmh_normal_layer);
541 				}
542 				else
543 				{
544 					new_layer(t, Scr.DefaultLayer);
545 				}
546 			}
547 		}
548 	}
549 	if (flags->do_update_ewmh_allowed_actions)
550 	{
551 		EWMH_SetAllowedActions(t);
552 	}
553 	if (flags->do_broadcast_focus)
554 	{
555 		if (Scr.Hilite != NULL && t == Scr.Hilite)
556 		{
557 			BroadcastPacket(
558 				M_FOCUS_CHANGE, 5, (long)FW_W(Scr.Hilite),
559 				(long)FW_W_FRAME(Scr.Hilite), (long)0,
560 				(long)Scr.Hilite->hicolors.fore,
561 				(long)Scr.Hilite->hicolors.back);
562 		}
563 	}
564 	if (flags->do_refresh)
565 	{
566 		if (!IS_ICONIFIED(t))
567 		{
568 			refresh_window(FW_W_FRAME(t), False);
569 		}
570 	}
571 	setup_numeric_vals(t, pstyle);
572 	if (flags->do_update_cr_motion_method)
573 	{
574 		switch (SCR_MOTION_METHOD(&pstyle->flags))
575 		{
576 		case WS_CR_MOTION_METHOD_AUTO:
577 			if (WAS_CR_MOTION_METHOD_DETECTED(t))
578 			{
579 				/* method was already detected, keep it */
580 				break;
581 			}
582 			/* fall through */
583 		case WS_CR_MOTION_METHOD_USE_GRAV:
584 		case WS_CR_MOTION_METHOD_STATIC_GRAV:
585 			SET_CR_MOTION_METHOD(
586 				t, SCR_MOTION_METHOD(&pstyle->flags));
587 			SET_CR_MOTION_METHOD_DETECTED(t, 0);
588 			break;
589 		}
590 	}
591 
592 	if (flags->do_update_layer)
593 	{
594 		int layer = get_layer(t);
595 
596 		if (SUSE_LAYER(&pstyle->flags))
597 		{
598 			/* use layer from style */
599 			layer = SGET_LAYER(*pstyle);
600 		}
601 
602 		/* Set the layer, and modify the stack ring. */
603 		new_layer(t, layer);
604 	}
605 
606 	return;
607 }
608 
609 /* ---------------------------- builtin commands --------------------------- */
610 
611 /* takes only care of destroying windows that have to go away. */
destroy_scheduled_windows(void)612 void destroy_scheduled_windows(void)
613 {
614 	flist *t;
615 	Bool do_need_ungrab = False;
616 
617 	if (Scr.flags.is_executing_complex_function ||
618 	    Scr.flags.is_executing_menu_function ||
619 	    !Scr.flags.is_window_scheduled_for_destroy)
620 	{
621 		return;
622 	}
623 	/* Grab the server during the style update! */
624 	if (GrabEm(CRS_WAIT, GRAB_BUSY))
625 	{
626 		do_need_ungrab = True;
627 	}
628 	MyXGrabServer(dpy);
629 	Scr.flags.is_window_scheduled_for_destroy = 0;
630 	/* need to destroy one or more windows before looking at the window
631 	 * list */
632 	for (t = Scr.FWScheduledForDestroy; t != NULL; t = t->next)
633 	{
634 		destroy_window(t->object);
635 	}
636 	Scr.FWScheduledForDestroy = flist_free_list(Scr.FWScheduledForDestroy);
637 	MyXUngrabServer(dpy);
638 	if (do_need_ungrab)
639 	{
640 		UngrabEm(GRAB_BUSY);
641 	}
642 
643 	return;
644 }
645 
646 /* similar to the flush_window_updates() function, but does only the updates
647  * for a single window whose decor has been changed. */
apply_decor_change(FvwmWindow * fw)648 void apply_decor_change(FvwmWindow *fw)
649 {
650 	window_style style;
651 	update_win flags;
652 
653 	lookup_style(fw, &style);
654 	memset(&flags, 0, sizeof(flags));
655 	flags.do_redecorate = True;
656 	flags.do_update_window_font_height = True;
657 	apply_window_updates(fw, &flags, &style, get_focus_window());
658 
659 	return;
660 }
661 
662 /* Check and apply new style to each window if the style has changed. */
flush_window_updates(void)663 void flush_window_updates(void)
664 {
665 	FvwmWindow *t;
666 	window_style style;
667 	FvwmWindow *focus_fw;
668 	Bool do_need_ungrab = False;
669 	update_win flags;
670 
671 	/* Grab the server during the style update! */
672 	if (GrabEm(CRS_WAIT, GRAB_BUSY))
673 	{
674 		do_need_ungrab = True;
675 	}
676 	MyXGrabServer(dpy);
677 
678 	/* This is necessary in case the focus policy changes. With
679 	 * ClickToFocus some buttons have to be grabbed/ungrabbed. */
680 	focus_fw = get_focus_window();
681 	DeleteFocus(False);
682 
683 	/* Apply the new default font and colours first */
684 	if (Scr.flags.has_default_color_changed ||
685 	    Scr.flags.has_default_font_changed)
686 	{
687 		ApplyDefaultFontAndColors();
688 	}
689 
690 	/* update styles for all windows */
691 	for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
692 	{
693 		memset(&flags, 0, sizeof(update_win));
694 		check_window_style_change(t, &flags, &style);
695 		if (Scr.flags.has_xinerama_state_changed)
696 		{
697 			flags.do_update_icon_boxes = True;
698 			flags.do_update_icon_placement = True;
699 		}
700 		if (Scr.flags.has_nr_buttons_changed)
701 		{
702 			flags.do_redecorate = True;
703 		}
704 		/* TODO: this is not optimised for minimal redrawing yet*/
705 		if (t->decor->flags.has_changed)
706 		{
707 			flags.do_redecorate = True;
708 			flags.do_update_window_font_height = True;
709 		}
710 		if (Scr.flags.has_default_font_changed && !HAS_ICON_FONT(t))
711 		{
712 			flags.do_update_icon_font = True;
713 		}
714 		if (Scr.flags.has_default_font_changed && !HAS_WINDOW_FONT(t))
715 		{
716 			flags.do_update_window_font = True;
717 		}
718 		if (t->decor->flags.has_title_height_changed)
719 		{
720 			flags.do_update_window_font_height = True;
721 		}
722 		if (Scr.flags.has_mouse_binding_changed)
723 		{
724 			flags.do_update_window_grabs = True;
725 		}
726 		/* now apply the changes */
727 		apply_window_updates(t, &flags, &style, focus_fw);
728 	}
729 
730 	/* restore the focus; also handles the case that the previously focused
731 	 * window is now NeverFocus */
732 	if (focus_fw)
733 	{
734 		SetFocusWindow(focus_fw, False, FOCUS_SET_FORCE);
735 		if (Scr.flags.has_mouse_binding_changed)
736 		{
737 			focus_grab_buttons(focus_fw);
738 		}
739 	}
740 	else
741 	{
742 		DeleteFocus(True);
743 	}
744 
745 	/* finally clean up the change flags */
746 	reset_style_changes();
747 	reset_decor_changes();
748 	Scr.flags.do_need_window_update = 0;
749 	Scr.flags.has_default_font_changed = 0;
750 	Scr.flags.has_default_color_changed = 0;
751 	Scr.flags.has_mouse_binding_changed = 0;
752 	Scr.flags.has_nr_buttons_changed = 0;
753 	Scr.flags.has_xinerama_state_changed = 0;
754 
755 	MyXUngrabServer(dpy);
756 	if (do_need_ungrab)
757 	{
758 		UngrabEm(GRAB_BUSY);
759 	}
760 
761 	return;
762 }
763 
CMD_UpdateStyles(F_CMD_ARGS)764 void CMD_UpdateStyles(F_CMD_ARGS)
765 {
766 	if (Scr.flags.do_need_window_update)
767 	{
768 		flush_window_updates();
769 	}
770 
771 	return;
772 }
773