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 /*
17  *
18  * fvwm icon code
19  *
20  */
21 
22 #include "config.h"
23 
24 #include <stdio.h>
25 #ifdef HAVE_FCNTL_H
26 #include <fcntl.h>
27 #endif
28 
29 #include "libs/fvwmlib.h"
30 #include "libs/FShape.h"
31 #include "libs/Parse.h"
32 #include "libs/Picture.h"
33 #include "libs/Graphics.h"
34 #include "libs/PictureGraphics.h"
35 #include "libs/FRenderInit.h"
36 #include "libs/FEvent.h"
37 #include "libs/Rectangles.c"
38 #include "libs/charmap.h"
39 #include "libs/wcontext.h"
40 #include "libs/safemalloc.h"
41 #include "fvwm.h"
42 #include "externs.h"
43 #include "cursor.h"
44 #include "execcontext.h"
45 #include "commands.h"
46 #include "bindings.h"
47 #include "events.h"
48 #include "eventmask.h"
49 #include "eventhandler.h"
50 #include "misc.h"
51 #include "screen.h"
52 #include "icons.h"
53 #include "borders.h"
54 #include "frame.h"
55 #include "focus.h"
56 #include "colormaps.h"
57 #include "stack.h"
58 #include "virtual.h"
59 #include "decorations.h"
60 #include "module_interface.h"
61 #include "ewmh.h"
62 #include "geometry.h"
63 
64 static int do_all_iconboxes(FvwmWindow *t, icon_boxes **icon_boxes_ptr);
65 static void GetIconFromFile(FvwmWindow *fw);
66 static void GetIconWindow(FvwmWindow *fw);
67 static void GetIconBitmap(FvwmWindow *fw);
68 
clear_icon_dimensions(FvwmWindow * fw)69 static void clear_icon_dimensions(FvwmWindow *fw)
70 {
71 	int px;
72 	int py;
73 	int tx;
74 	int ty;
75 
76 	px = fw->icon_g.picture_w_g.x;
77 	py = fw->icon_g.picture_w_g.y;
78 	tx = fw->icon_g.title_w_g.x;
79 	ty = fw->icon_g.title_w_g.y;
80 	memset(&fw->icon_g, 0, sizeof(fw->icon_g));
81 	fw->icon_g.picture_w_g.x = px;
82 	fw->icon_g.picture_w_g.y = py;
83 	fw->icon_g.title_w_g.x = tx;
84 	fw->icon_g.title_w_g.y = ty;
85 
86 	return;
87 }
88 /* erase all traces of the last used icon in the window structure */
clear_icon(FvwmWindow * fw)89 void clear_icon(FvwmWindow *fw)
90 {
91 	FW_W_ICON_PIXMAP(fw) = None;
92 	fw->iconPixmap = None;
93 	fw->icon_maskPixmap = None;
94 	fw->icon_alphaPixmap = None;
95 	fw->icon_nalloc_pixels = 0;
96 	fw->icon_alloc_pixels = NULL;
97 	fw->icon_no_limit = 0;
98 	if (IS_ICON_MOVED(fw))
99 	{
100 		clear_icon_dimensions(fw);
101 	}
102 	else
103 	{
104 		memset(&fw->icon_g, 0, sizeof(fw->icon_g));
105 	}
106 
107 	return;
108 }
109 
get_visible_icon_window_count(FvwmWindow * fw)110 int get_visible_icon_window_count(FvwmWindow *fw)
111 {
112 	int count = 0;
113 
114 	if (fw == NULL || !IS_ICONIFIED(fw) ||
115 	    IS_ICON_SUPPRESSED(fw))
116 	{
117 		return 0;
118 	}
119 	if (FW_W_ICON_PIXMAP(fw) != None)
120 	{
121 		count++;
122 	}
123 	if (FW_W_ICON_TITLE(fw) != None)
124 	{
125 		count++;
126 	}
127 
128 	return count;
129 }
130 
setup_icon_title_size(FvwmWindow * fw)131 void setup_icon_title_size(FvwmWindow *fw)
132 {
133 	if (HAS_NO_ICON_TITLE(fw))
134 	{
135 		fw->icon_g.title_text_width = 0;
136 		fw->icon_g.title_w_g.width = 0;
137 		fw->icon_g.title_w_g.height = 0;
138 	}
139 	else
140 	{
141 		fw->icon_g.title_text_width =
142 			FlocaleTextWidth(
143 				fw->icon_font, fw->visible_icon_name,
144 				strlen(fw->visible_icon_name));
145 		fw->icon_g.title_w_g.height = ICON_HEIGHT(fw);
146 		if (fw->icon_g.picture_w_g.width == 0)
147 		{
148 			fw->icon_g.title_w_g.width =
149 				fw->icon_g.title_text_width +
150 				2 * (ICON_TITLE_TEXT_GAP_COLLAPSED +
151 				     abs(fw->icon_title_relief));
152 			if (IS_STICKY_ACROSS_PAGES(fw) ||
153 			    IS_ICON_STICKY_ACROSS_PAGES(fw) ||
154 			    IS_STICKY_ACROSS_DESKS(fw) ||
155 			    IS_ICON_STICKY_ACROSS_DESKS(fw))
156 			{
157 				fw->icon_g.title_w_g.width +=
158 					2 * (ICON_TITLE_TO_STICK_EXTRA_GAP +
159 					     ICON_TITLE_STICK_MIN_WIDTH);
160 			}
161 		}
162 		else
163 		{
164 			fw->icon_g.title_w_g.width =
165 				fw->icon_g.picture_w_g.width;
166 		}
167 	}
168 
169 	return;
170 }
171 
172 /*
173  *
174  * Resizes the given icon Pixmap.
175  *
176  */
SetIconPixmapSize(Pixmap * icon,int width,int height,int depth,int newWidth,int newHeight,Bool force_centering,int resize_type,int * nrx,int * nry,int freeOldPixmap)177 static void SetIconPixmapSize(
178 	Pixmap *icon, int width, int height, int depth, int newWidth,
179 	int newHeight, Bool force_centering, int resize_type, int *nrx,
180 	int *nry, int freeOldPixmap)
181 {
182 	Pixmap oldPixmap;
183 	Pixmap resizedPixmap = None;
184 	int r_w,r_h;
185 	GC gc;
186 	XGCValues gc_init;
187 
188 	*nrx = 0;
189 	*nry = 0;
190 
191 	/* Check for invalid dimensions */
192 	if (newWidth == 0 || newHeight == 0)
193 	{
194 		return;
195 	}
196 
197 	/* Save the existing Pixmap */
198 	oldPixmap = *icon;
199 
200 	gc = XCreateGC(dpy, oldPixmap, 0, &gc_init);
201 
202 	switch(resize_type)
203 	{
204 	case ICON_RESIZE_TYPE_ADJUSTED:
205 		if (newWidth != width || newHeight != height)
206 		{
207 			*icon = CreateStretchPixmap(
208 				dpy, oldPixmap, width, height, depth, newWidth,
209 				newHeight, gc);
210 		}
211 		break;
212 	case ICON_RESIZE_TYPE_STRETCHED:
213 		if (width < newWidth || height < newHeight)
214 		{
215 			r_w = max(newWidth, width);
216 			r_h = max(newHeight, height);
217 			resizedPixmap = CreateStretchPixmap(
218 				dpy, oldPixmap, width, height, depth, r_w, r_h,
219 				gc);
220 			width = r_w;
221 			height = r_h;
222 		}
223 		break;
224 	case ICON_RESIZE_TYPE_SHRUNK:
225 		if (width > newWidth || height > newHeight)
226 		{
227 			r_w = min(newWidth, width);
228 			r_h = min(newHeight, height);
229 			resizedPixmap = CreateStretchPixmap(
230 				dpy, oldPixmap, width, height, depth, r_w, r_h,
231 				gc);
232 			width = r_w;
233 			height = r_h;
234 		}
235 		break;
236 	default:
237 		break;
238 	}
239 
240 	if (resize_type != ICON_RESIZE_TYPE_ADJUSTED)
241 	{
242 		*icon = XCreatePixmap(
243 			dpy, oldPixmap, newWidth, newHeight, depth);
244 		XSetForeground(dpy, gc, 0);
245 		XFillRectangle(dpy, *icon, gc, 0, 0, newWidth, newHeight);
246 
247 		/*
248 		 * Copy old Pixmap onto new.  Center horizontally.  Center
249 		 * vertically if the new height is smaller than the old.
250 		 * Otherwise, place the icon on the bottom, along the title bar.
251 		 */
252 		*nrx = (newWidth - width) / 2;
253 		*nry = (newHeight > height && !force_centering) ?
254 			newHeight - height : (newHeight - height) / 2;
255 		XCopyArea(
256 			dpy, (resizedPixmap)? resizedPixmap:oldPixmap, *icon,
257 			gc, 0, 0, width, height, *nrx, *nry);
258 	}
259 
260 	XFreeGC(dpy, gc);
261 
262 	if (freeOldPixmap)
263 	{
264 		XFreePixmap(dpy, oldPixmap);
265 	}
266 }
267 
268 /* Move the icon of a window by dx/dy pixels */
269 /*
270  *
271  * Get the Icon for the icon window (also used by ewmh_icon)
272  *
273  */
GetIconPicture(FvwmWindow * fw,Bool no_icon_window)274 void GetIconPicture(FvwmWindow *fw, Bool no_icon_window)
275 {
276 	char icon_order[4];
277 	int i;
278 
279 	/* First, see if it was specified in the .fvwmrc */
280 	if (ICON_OVERRIDE_MODE(fw) == ICON_OVERRIDE)
281 	{
282 		/* try fvwm provided icons before application provided icons */
283 		icon_order[0] = 0;
284 		icon_order[1] = 1;
285 		icon_order[2] = 2;
286 		icon_order[3] = 3;
287 ICON_DBG((stderr,"ciw: hint order: file iwh iph '%s'\n", fw->name.name));
288 	}
289 	else if (ICON_OVERRIDE_MODE(fw) == NO_ACTIVE_ICON_OVERRIDE)
290 	{
291 		if (fw->wmhints && (fw->wmhints->flags & IconPixmapHint) &&
292 		    WAS_ICON_HINT_PROVIDED(fw) == ICON_HINT_MULTIPLE)
293 		{
294 			/* use application provided icon window or pixmap
295 			 * first, then fvwm provided icons. */
296 			icon_order[0] = 1;
297 			icon_order[1] = 2;
298 			icon_order[2] = 3;
299 			icon_order[3] = 0;
300 ICON_DBG((stderr,"ciw: hint order: iwh iph file '%s'\n", fw->name.name));
301 		}
302 		else if (Scr.DefaultIcon &&
303 			 fw->icon_bitmap_file == Scr.DefaultIcon)
304 		{
305 			/* use application provided icon window/pixmap first,
306 			 * then fvwm provided default icon */
307 			icon_order[0] = 1;
308 			icon_order[1] = 2;
309 			icon_order[2] = 3;
310 			icon_order[3] = 0;
311 ICON_DBG((stderr,"ciw: hint order: iwh iph file '%s'\n", fw->name.name));
312 		}
313 		else
314 		{
315 			/* use application provided icon window or ewmh icon
316 			 * first, then fvwm provided icons and then application
317 			 * provided icon pixmap */
318 			icon_order[0] = 1;
319 			icon_order[1] = 2;
320 			icon_order[2] = 0;
321 			icon_order[3] = 3;
322 ICON_DBG((stderr,"ciw: hint order: iwh file iph '%s'\n", fw->name.name));
323 		}
324 	}
325 	else
326 	{
327 		/* use application provided icon rather than fvwm provided
328 		 * icon */
329 		icon_order[0] = 1;
330 		icon_order[1] = 2;
331 		icon_order[2] = 3;
332 		icon_order[3] = 0;
333 ICON_DBG((stderr,"ciw: hint order: iwh iph file '%s'\n", fw->name.name));
334 	}
335 
336 	fw->icon_g.picture_w_g.width = 0;
337 	fw->icon_g.picture_w_g.height = 0;
338 	fw->iconPixmap = None;
339 	fw->icon_maskPixmap = None;
340 	fw->icon_alphaPixmap= None;
341 	FW_W_ICON_PIXMAP(fw) = None;
342 	for (i = 0; i < 4 && fw->icon_g.picture_w_g.width == 0 &&
343 		     fw->icon_g.picture_w_g.height == 0; i++)
344 	{
345 		switch (icon_order[i])
346 		{
347 		case 0:
348 			/* Next, check for a color pixmap */
349 			if (fw->icon_bitmap_file)
350 			{
351 				GetIconFromFile(fw);
352 			}
353 ICON_DBG((stderr,"ciw: file%s used '%s'\n",
354 	  (fw->icon_g.picture_w_g.height)?"":" not", fw->name.name));
355 			break;
356 		case 1:
357 			/* Next, See if the app supplies its own icon window */
358 			if (no_icon_window)
359 			{
360 				break;
361 			}
362 			if (fw->wmhints &&
363 			    (fw->wmhints->flags & IconWindowHint))
364 			{
365 				GetIconWindow(fw);
366 			}
367 ICON_DBG((stderr,"ciw: iwh%s used '%s'\n",
368 	  (fw->icon_g.picture_w_g.height)?"":" not",fw->name.name));
369 			break;
370 		case 2:
371 			/* try an ewmh icon */
372 			if (HAS_EWMH_WM_ICON_HINT(fw) == EWMH_TRUE_ICON)
373 			{
374 				if (EWMH_SetIconFromWMIcon(fw, NULL, 0, False))
375 				{
376 					SET_USE_EWMH_ICON(fw, True);
377 				}
378 			}
379 ICON_DBG((stderr,"ciw: inh%s used '%s'\n",
380 	  (fw->icon_g.picture_w_g.height)?"":" not",fw->name.name));
381 			break;
382 		case 3:
383 			/* Finally, try to get icon bitmap from the
384 			 * application */
385 			if (fw->wmhints &&
386 			    (fw->wmhints->flags & IconPixmapHint))
387 			{
388 				GetIconBitmap(fw);
389 			}
390 ICON_DBG((stderr,"ciw: iph%s used '%s'\n",
391 	  (fw->icon_g.picture_w_g.height)?"":" not",fw->name.name));
392 			break;
393 		default:
394 			/* can't happen */
395 			break;
396 		}
397 	}
398 
399 	/* Resize icon if necessary */
400 	if ((IS_ICON_OURS(fw)) && fw->icon_g.picture_w_g.height > 0 &&
401 	    fw->icon_g.picture_w_g.height > 0)
402 	{
403 		int newWidth = fw->icon_g.picture_w_g.width;
404 		int newHeight = fw->icon_g.picture_w_g.height;
405 		Bool resize = False;
406 
407 		if (newWidth < fw->min_icon_width)
408 		{
409 			newWidth = fw->min_icon_width;
410 			resize = True;
411 		}
412 		else
413 		{
414 			if (newWidth > fw->max_icon_width)
415 			{
416 				newWidth = fw->max_icon_width;
417 				resize = True;
418 			}
419 		}
420 		if (newHeight < fw->min_icon_height)
421 		{
422 			newHeight = fw->min_icon_height;
423 			resize = True;
424 		}
425 		else
426 		{
427 			if (newHeight > fw->max_icon_height)
428 			{
429 				newHeight = fw->max_icon_height;
430 				resize = True;
431 			}
432 		}
433 		if (resize)
434 		{
435 			/* Resize the icon Pixmap */
436 			int force_centering = False;
437 			int nrx, nry;
438 
439 			ICON_DBG((stderr,
440 				  "ciw: Changing icon (%s) from %dx%d to"
441 				  " %dx%d\n", fw->name.name,
442 				  fw->icon_g.picture_w_g.width,
443 				  fw->icon_g.picture_w_g.height,
444 				  newWidth, newHeight));
445 			/* Resize the icon Pixmap */
446 			/* force to center if the icon has a bg */
447 			if (fw->icon_background_cs >= 0 ||
448 			    fw->icon_maskPixmap == None)
449 			{
450 				force_centering = True;
451 			}
452 			SetIconPixmapSize(
453 				&(fw->iconPixmap),
454 				fw->icon_g.picture_w_g.width,
455 				fw->icon_g.picture_w_g.height, fw->iconDepth,
456 				newWidth, newHeight, force_centering,
457 				fw->icon_resize_type, &nrx, &nry,
458 				IS_PIXMAP_OURS(fw));
459 
460 			/* Resize the icon mask Pixmap if one was defined */
461 			if (fw->icon_maskPixmap)
462 			{
463 				SetIconPixmapSize(
464 					&(fw->icon_maskPixmap),
465 					fw->icon_g.picture_w_g.width,
466 					fw->icon_g.picture_w_g.height, 1,
467 					newWidth, newHeight, force_centering,
468 					fw->icon_resize_type, &nrx, &nry,
469 					IS_PIXMAP_OURS(fw));
470 			}
471 			else if ((nrx > 0 || nry > 0) && fw->iconDepth > 1)
472 			{
473 				fw->icon_maskPixmap = XCreatePixmap(
474 					dpy, fw->iconPixmap,
475 					newWidth, newHeight, 1);
476 				XSetForeground(dpy, Scr.MonoGC, 0);
477 				XFillRectangle(
478 					dpy, fw->icon_maskPixmap, Scr.MonoGC,
479 					0, 0, newWidth, newHeight);
480 				XSetForeground(dpy, Scr.MonoGC, 1);
481 				XFillRectangle(
482 					dpy, fw->icon_maskPixmap, Scr.MonoGC,
483 					nrx, nry, fw->icon_g.picture_w_g.width,
484 					fw->icon_g.picture_w_g.height);
485 				XSetForeground(dpy, Scr.MonoGC, 0);
486 				/* set it shaped ? YES */
487 				SET_ICON_SHAPED(fw, 1);
488 			}
489 
490 			/* Resize the icon alpha Pixmap if one was defined */
491 			if (fw->icon_alphaPixmap)
492 			{
493 				SetIconPixmapSize(
494 					&(fw->icon_alphaPixmap),
495 					fw->icon_g.picture_w_g.width,
496 					fw->icon_g.picture_w_g.height,
497 					FRenderGetAlphaDepth(), newWidth,
498 					newHeight, force_centering,
499 					fw->icon_resize_type, &nrx, &nry,
500 					IS_PIXMAP_OURS(fw));
501 			}
502 
503 			/* Set the new dimensions of the icon window */
504 			fw->icon_g.picture_w_g.width = newWidth;
505 			fw->icon_g.picture_w_g.height = newHeight;
506 		}
507 	}
508 
509 	return;
510 }
511 
512 /*
513  *
514  * set the icon pixmap window background
515  *
516  */
set_icon_pixmap_background(FvwmWindow * fw)517 static void set_icon_pixmap_background(FvwmWindow *fw)
518 {
519 	if (fw->iconPixmap != None &&
520 	    (Pdefault || fw->iconDepth == 1 || fw->iconDepth == Pdepth ||
521 	     IS_PIXMAP_OURS(fw)))
522 	{
523 		if (fw->icon_background_cs >= 0)
524 		{
525 			SetWindowBackground(
526 				dpy, FW_W_ICON_PIXMAP(fw),
527 				fw->icon_g.picture_w_g.width,
528 				fw->icon_g.picture_w_g.height,
529 				&Colorset[fw->icon_background_cs],
530 				Pdepth, Scr.StdGC, False);
531 		}
532 		else if (FShapesSupported &&
533 			 Pdepth == DefaultDepth(dpy, (DefaultScreen(dpy))))
534 		{
535 			XSetWindowBackgroundPixmap(
536 				dpy, FW_W_ICON_PIXMAP(fw), ParentRelative);
537 		}
538 		else if (Scr.DefaultColorset >= 0)
539 		{
540 			SetWindowBackground(
541 				dpy, FW_W_ICON_PIXMAP(fw),
542 				fw->icon_g.picture_w_g.width,
543 				fw->icon_g.picture_w_g.height,
544 				&Colorset[Scr.DefaultColorset], Pdepth,
545 				Scr.StdGC, False);
546 		}
547 	}
548 }
549 
550 /*
551  *
552  * Creates an icon window as needed
553  *
554  */
CreateIconWindow(FvwmWindow * fw,int def_x,int def_y)555 void CreateIconWindow(FvwmWindow *fw, int def_x, int def_y)
556 {
557 	/* mask for create windows */
558 	unsigned long valuemask;
559 	/* attributes for create windows */
560 	XSetWindowAttributes attributes;
561 	XWindowChanges xwc;
562 	Window old_icon_pixmap_w;
563 	Window old_icon_w;
564 	Bool is_old_icon_shaped = IS_ICON_SHAPED(fw);
565 
566 	old_icon_w = FW_W_ICON_TITLE(fw);
567 	old_icon_pixmap_w = (IS_ICON_OURS(fw)) ? FW_W_ICON_PIXMAP(fw) : None;
568 	if (!IS_ICON_OURS(fw) && FW_W_ICON_PIXMAP(fw))
569 	{
570 		XUnmapWindow(dpy, FW_W_ICON_PIXMAP(fw));
571 	}
572 	SET_ICON_OURS(fw, 1);
573 	SET_PIXMAP_OURS(fw, 0);
574 	SET_ICON_SHAPED(fw, 0);
575 	FW_W_ICON_PIXMAP(fw) = None;
576 	fw->iconPixmap = None;
577 	fw->iconDepth = 0;
578 
579 	if (IS_ICON_SUPPRESSED(fw))
580 	{
581 		return;
582 	}
583 
584 	/*
585 	 * set up the icon picture
586 	 */
587 	GetIconPicture(fw, False);
588 	/* make space for relief to be drawn outside the icon */
589 	/* this does not happen if fvwm is using a non-default visual (with
590 	 * private colormap) and the client has supplied a pixmap (not a
591 	 * bitmap) */
592 	if ((IS_ICON_OURS(fw)) && (fw->icon_g.picture_w_g.height > 0)
593 	    && (Pdefault || fw->iconDepth == 1 || fw->iconDepth == Pdepth ||
594 		IS_PIXMAP_OURS(fw)))
595 	{
596 		fw->icon_g.picture_w_g.width +=
597 			2 * abs(fw->icon_background_relief)
598 			+ 2 * fw->icon_background_padding;
599 		fw->icon_g.picture_w_g.height +=
600 			2 * abs(fw->icon_background_relief)
601 			+ 2 * fw->icon_background_padding;
602 	}
603 
604 	/*
605 	 * set up the icon title geometry
606 	 */
607 	setup_icon_title_size(fw);
608 
609 	/*
610 	 * set up icon position
611 	 */
612 	set_icon_position(fw, def_x, def_y);
613 
614 	/*
615 	 * create the icon title window
616 	 */
617 	valuemask = CWColormap | CWBorderPixel | CWBackPixel | CWCursor |
618 		CWEventMask;
619 	attributes.colormap = Pcmap;
620 	attributes.background_pixel = Scr.StdBack;
621 	attributes.cursor = Scr.FvwmCursors[CRS_DEFAULT];
622 	attributes.border_pixel = 0;
623 	attributes.event_mask = XEVMASK_ICONW;
624 	if (HAS_NO_ICON_TITLE(fw))
625 	{
626 		if (FW_W_ICON_TITLE(fw))
627 		{
628 			XDeleteContext(dpy, FW_W_ICON_TITLE(fw), FvwmContext);
629 			XDestroyWindow(dpy, FW_W_ICON_TITLE(fw));
630 			XFlush(dpy);
631 			FW_W_ICON_TITLE(fw) = None;
632 		}
633 	}
634 	else
635 	{
636 		if (FW_W_ICON_TITLE(fw) == None)
637 		{
638 			FW_W_ICON_TITLE(fw) = XCreateWindow(
639 				dpy, Scr.Root, fw->icon_g.title_w_g.x,
640 				fw->icon_g.title_w_g.y,
641 				fw->icon_g.title_w_g.width,
642 				fw->icon_g.title_w_g.height, 0, Pdepth,
643 				InputOutput, Pvisual, valuemask, &attributes);
644 		}
645 		else
646 		{
647 			XMoveResizeWindow(
648 				dpy, FW_W_ICON_TITLE(fw),
649 				fw->icon_g.title_w_g.x, fw->icon_g.title_w_g.y,
650 				fw->icon_g.title_w_g.width,
651 				fw->icon_g.title_w_g.height);
652 		}
653 	}
654 	if (Scr.DefaultColorset >= 0)
655 	{
656 		SetWindowBackground(
657 			dpy, FW_W_ICON_TITLE(fw), fw->icon_g.title_w_g.width,
658 			fw->icon_g.title_w_g.height,
659 			&Colorset[Scr.DefaultColorset], Pdepth, Scr.StdGC,
660 			False);
661 	}
662 
663 	/*
664 	 * create the icon picture window
665 	 */
666 	if (IS_ICON_OURS(fw) && fw->icon_g.picture_w_g.width > 0 &&
667 	    fw->icon_g.picture_w_g.height > 0)
668 	{
669 		/* use fvwm's visuals in these cases */
670 		if (Pdefault || fw->iconDepth == 1 || fw->iconDepth == Pdepth ||
671 		    IS_PIXMAP_OURS(fw))
672 		{
673 			if (!old_icon_pixmap_w)
674 			{
675 				FW_W_ICON_PIXMAP(fw) = XCreateWindow(
676 					dpy, Scr.Root, fw->icon_g.picture_w_g.x,
677 					fw->icon_g.picture_w_g.y,
678 					fw->icon_g.picture_w_g.width,
679 					fw->icon_g.picture_w_g.height, 0,
680 					Pdepth, InputOutput, Pvisual,
681 					valuemask, &attributes);
682 			}
683 			else
684 			{
685 				FW_W_ICON_PIXMAP(fw) = old_icon_pixmap_w;
686 				XMoveResizeWindow(
687 					dpy, FW_W_ICON_PIXMAP(fw),
688 					fw->icon_g.picture_w_g.x,
689 					fw->icon_g.picture_w_g.y,
690 					fw->icon_g.picture_w_g.width,
691 					fw->icon_g.picture_w_g.height);
692 			}
693 			set_icon_pixmap_background(fw);
694 		}
695 		else
696 		{
697 			/* client supplied icon pixmap and fvwm is using
698 			 * another visual.
699 			 * use it as the background pixmap, don't try to put
700 			 * relief on it because fvwm will not have the correct
701 			 * colors the Exceed server has problems maintaining
702 			 * the icon window, it usually fails to refresh the
703 			 * icon leaving it black so ask for expose events */
704 			attributes.background_pixmap = fw->iconPixmap;
705 			attributes.colormap = DefaultColormap(dpy, Scr.screen);
706 			valuemask &= ~CWBackPixel;
707 			valuemask |= CWBackPixmap;
708 			FW_W_ICON_PIXMAP(fw) = XCreateWindow(
709 				dpy, Scr.Root, fw->icon_g.picture_w_g.x,
710 				fw->icon_g.picture_w_g.y,
711 				fw->icon_g.picture_w_g.width,
712 				fw->icon_g.picture_w_g.height, 0,
713 				DefaultDepth(dpy, Scr.screen), InputOutput,
714 				DefaultVisual(dpy, Scr.screen), valuemask,
715 				&attributes);
716 		}
717 	}
718 	else if (FW_W_ICON_PIXMAP(fw) != None)
719 	{
720 		/* client supplied icon window: select events on it */
721 		attributes.event_mask = XEVMASK_ICONPW;
722 		valuemask = CWEventMask;
723 		XChangeWindowAttributes(
724 			dpy, FW_W_ICON_PIXMAP(fw), valuemask,&attributes);
725 		if (!IS_ICON_OURS(fw))
726 		{
727 			XMoveWindow(
728 				dpy, FW_W_ICON_PIXMAP(fw),
729 				fw->icon_g.picture_w_g.x,
730 				fw->icon_g.picture_w_g.y);
731 		}
732 	}
733 	if (old_icon_pixmap_w != None &&
734 	    old_icon_pixmap_w != FW_W_ICON_PIXMAP(fw))
735 	{
736 		/* destroy the old window */
737 		XDestroyWindow(dpy, old_icon_pixmap_w);
738 		XDeleteContext(dpy, old_icon_pixmap_w, FvwmContext);
739 		XFlush(dpy);
740 		is_old_icon_shaped = False;
741 	}
742 
743 	if (FShapesSupported)
744 	{
745 		if (IS_ICON_SHAPED(fw) && fw->icon_background_cs < 0)
746 		{
747 			/* when fvwm is using the non-default visual client
748 			 * supplied icon pixmaps are drawn in a window with no
749 			 * relief */
750 			int off = 0;
751 
752 			if (Pdefault || fw->iconDepth == 1 ||
753 			    fw->iconDepth == Pdepth || IS_PIXMAP_OURS(fw))
754 			{
755 				off = abs(fw->icon_background_relief) +
756 					fw->icon_background_padding;
757 			}
758 			SUPPRESS_UNUSED_VAR_WARNING(off);
759 			FShapeCombineMask(
760 				dpy, FW_W_ICON_PIXMAP(fw), FShapeBounding, off,
761 				off, fw->icon_maskPixmap, FShapeSet);
762 		}
763 		else if (is_old_icon_shaped &&
764 			 FW_W_ICON_PIXMAP(fw) == old_icon_pixmap_w)
765 		{
766 			/* remove the shape */
767 			XRectangle r;
768 
769 			r.x = 0;
770 			r.y = 0;
771 			r.width = fw->icon_g.picture_w_g.width;
772 			r.height = fw->icon_g.picture_w_g.height;
773 			SUPPRESS_UNUSED_VAR_WARNING(r);
774 			FShapeCombineRectangles(
775 				dpy, FW_W_ICON_PIXMAP(fw), FShapeBounding, 0,
776 				0, &r, 1, FShapeSet, 0);
777 		}
778 	}
779 
780 	if (FW_W_ICON_TITLE(fw) != None && FW_W_ICON_TITLE(fw) != old_icon_w)
781 	{
782 		XSaveContext(
783 			dpy, FW_W_ICON_TITLE(fw), FvwmContext, (caddr_t)fw);
784 		XDefineCursor(
785 			dpy, FW_W_ICON_TITLE(fw), Scr.FvwmCursors[CRS_DEFAULT]);
786 		GrabAllWindowKeysAndButtons(
787 			dpy, FW_W_ICON_TITLE(fw), Scr.AllBindings, C_ICON,
788 			GetUnusedModifiers(), Scr.FvwmCursors[CRS_DEFAULT],
789 			True);
790 		xwc.sibling = FW_W_FRAME(fw);
791 		xwc.stack_mode = Below;
792 		XConfigureWindow(
793 			dpy, FW_W_ICON_TITLE(fw), CWSibling|CWStackMode, &xwc);
794 	}
795 	if (FW_W_ICON_PIXMAP(fw) != None &&
796 	    FW_W_ICON_PIXMAP(fw) != old_icon_pixmap_w)
797 	{
798 		XSaveContext(
799 			dpy, FW_W_ICON_PIXMAP(fw), FvwmContext, (caddr_t)fw);
800 		XDefineCursor(
801 			dpy, FW_W_ICON_PIXMAP(fw),
802 			Scr.FvwmCursors[CRS_DEFAULT]);
803 		GrabAllWindowKeysAndButtons(
804 			dpy, FW_W_ICON_PIXMAP(fw), Scr.AllBindings, C_ICON,
805 			GetUnusedModifiers(), Scr.FvwmCursors[CRS_DEFAULT],
806 			True);
807 		xwc.sibling = FW_W_FRAME(fw);
808 		xwc.stack_mode = Below;
809 		XConfigureWindow(
810 			dpy,FW_W_ICON_PIXMAP(fw),CWSibling|CWStackMode,&xwc);
811 	}
812 
813 	return;
814 }
815 
816 /*
817  *
818  * Draws the icon window
819  *
820  */
821 static
DrawIconTitleWindow(FvwmWindow * fw,XEvent * pev,Pixel BackColor,GC Shadow,GC Relief,int cs,int title_cs)822 void DrawIconTitleWindow(
823 	FvwmWindow *fw, XEvent *pev, Pixel BackColor, GC Shadow, GC Relief,
824 	int cs, int title_cs)
825 {
826 	int is_expanded = IS_ICON_ENTERED(fw);
827 	FlocaleWinString fstr;
828 	Region region = None;
829 	XRectangle clip, r;
830 	int relief = abs(fw->icon_title_relief);
831 	int x_title;
832 	int x_title_min = 0;
833 	int w_title = fw->icon_g.title_text_width;
834 	int x_title_w = fw->icon_g.picture_w_g.x;
835 	int w_title_w = fw->icon_g.picture_w_g.width;
836 	int x_stipple = relief;
837 	int w_title_text_gap = 0;
838 	int w_stipple = 0;
839 	int is_sticky;
840 	int is_stippled;
841 	int use_unexpanded_size = 1;
842 	Bool draw_string = True;
843 
844 	is_sticky =
845 		(IS_STICKY_ACROSS_PAGES(fw) || IS_ICON_STICKY_ACROSS_PAGES(fw));
846 	is_sticky |=
847 		(IS_STICKY_ACROSS_DESKS(fw) || IS_ICON_STICKY_ACROSS_DESKS(fw));
848 	is_stippled = ((is_sticky && HAS_STICKY_STIPPLED_ICON_TITLE(fw)) ||
849 		HAS_STIPPLED_ICON_TITLE(fw));
850 	if (is_expanded && FW_W_ICON_PIXMAP(fw) != None)
851 	{
852 		int sx;
853 		int sy;
854 		int sw;
855 		int sh;
856 
857 		use_unexpanded_size = 0;
858 		w_title_text_gap = ICON_TITLE_TEXT_GAP_EXPANDED;
859 		x_title_min = w_title_text_gap + relief;
860 		if (is_stippled)
861 		{
862 			w_stipple = ICON_TITLE_STICK_MIN_WIDTH;
863 			x_title_min +=
864 				w_stipple + ICON_TITLE_TO_STICK_EXTRA_GAP;
865 		}
866 		/* resize the icon name window */
867 		w_title_w = w_title + 2 * x_title_min;
868 		if (w_title_w <= fw->icon_g.picture_w_g.width)
869 		{
870 			/* the expanded title is smaller, so do not
871 			 * expand at all */
872 			is_expanded = 1;
873 			w_stipple = 0;
874 			use_unexpanded_size = 1;
875 		}
876 		else
877 		{
878 			x_title_w = fw->icon_g.picture_w_g.x -
879 				(w_title_w - fw->icon_g.picture_w_g.width) / 2;
880 			FScreenGetScrRect(NULL, FSCREEN_CURRENT,
881 					  &sx, &sy, &sw, &sh);
882 			/* start keep label on screen. dje 8/7/97 */
883 			if (x_title_w < sx) {
884 				/* if new loc neg (off left edge) */
885 				x_title_w = sx;      /* move to edge */
886 			}
887 			else
888 			{
889 				/* if not on left edge */
890 				/* if (new loc + width) > screen width
891 				 * (off edge on right) */
892 				if ((x_title_w + w_title_w) >sx + sw) {
893 					/* off right */
894 					/* position up against right
895 					 * edge */
896 					x_title_w = sx + sw - w_title_w;
897 				}
898 				/* end keep label on screen. dje
899 				 * 8/7/97 */
900 			}
901 		}
902 	}
903 	if (use_unexpanded_size)
904 	{
905 		w_title_text_gap = ICON_TITLE_TEXT_GAP_COLLAPSED;
906 		x_title_min = w_title_text_gap + relief;
907 		/* resize the icon name window */
908 		if (FW_W_ICON_PIXMAP(fw) != None)
909 		{
910 			w_title_w = fw->icon_g.picture_w_g.width;
911 			x_title_w = fw->icon_g.picture_w_g.x;
912 		}
913 		else
914 		{
915 			w_title_w = fw->icon_g.title_w_g.width;
916 			x_title_w = fw->icon_g.title_w_g.x;
917 		}
918 	}
919 
920 	if (fw->icon_g.title_w_g.width != w_title_w ||
921 	    fw->icon_g.title_w_g.x != x_title_w ||
922 	    fw->icon_g.title_w_g.height != ICON_HEIGHT(fw))
923 	{
924 		fw->icon_g.title_w_g.width = w_title_w;
925 		fw->icon_g.title_w_g.x = x_title_w;
926 		fw->icon_g.title_w_g.height = ICON_HEIGHT(fw);
927 		pev = NULL; /* resize && redraw all */
928 	}
929 
930 	if (!pev)
931 	{
932 		XMoveResizeWindow(
933 			dpy, FW_W_ICON_TITLE(fw), fw->icon_g.title_w_g.x,
934 			fw->icon_g.title_w_g.y, w_title_w,
935 			ICON_HEIGHT(fw));
936 	}
937 
938 	if (title_cs >= 0)
939 	{
940 		SetWindowBackground(
941 			dpy, FW_W_ICON_TITLE(fw), w_title_w,
942 			ICON_HEIGHT(fw), &Colorset[title_cs], Pdepth,
943 			Scr.TitleGC, False);
944 	}
945 	else
946 	{
947 		XSetWindowBackground(
948 			dpy, FW_W_ICON_TITLE(fw), BackColor);
949 	}
950 
951 	/* text position */
952 	x_title = (w_title_w - w_title) / 2;
953 	if (x_title < x_title_min)
954 		x_title = x_title_min;
955 	/* text rectangle */
956 	r.x = x_title;
957 	r.y = relief;
958 	r.width = w_title_w - x_title - relief;
959 	r.height = ICON_HEIGHT(fw) - 2*relief;
960 	if (is_stippled)
961 	{
962 
963 		if (w_stipple == 0)
964 		{
965 			w_stipple = ((w_title_w - 2 *
966 				      (x_stipple + w_title_text_gap) -
967 				      w_title) + 1) / 2;
968 		}
969 		if (w_stipple < ICON_TITLE_STICK_MIN_WIDTH)
970 		{
971 			w_stipple = ICON_TITLE_STICK_MIN_WIDTH;
972 		}
973 		if (x_title < x_stipple + w_stipple + w_title_text_gap)
974 		{
975 			x_title = x_stipple + w_stipple +
976 				w_title_text_gap;
977 		}
978 		r.x = x_title;
979 		r.width = w_title_w - 2 * x_title;
980 		if (r.width < 1)
981 			r.width = 1;
982 	}
983 
984 	memset(&fstr, 0, sizeof(fstr));
985 
986 	if (pev || is_stippled)
987 	{
988 		if (pev)
989 		{
990 			if (!frect_get_intersection(
991 				pev->xexpose.x, pev->xexpose.y,
992 				pev->xexpose.width,
993 				pev->xexpose.height,
994 				r.x, r.y, r.width, r.height, &clip))
995 			{
996 				draw_string = False;
997 			}
998 		}
999 		else
1000 		{
1001 			clip.x = r.x;
1002 			clip.y = r.y;
1003 			clip.width = r.width;
1004 			clip.height = r.height;
1005 		}
1006 		if (draw_string)
1007 		{
1008 			XSetClipRectangles(
1009 				dpy, Scr.TitleGC, 0, 0, &clip, 1, Unsorted);
1010 			region = XCreateRegion();
1011 			XUnionRectWithRegion (&clip, region, region);
1012 			fstr.flags.has_clip_region = True;
1013 			fstr.clip_region = region;
1014 		}
1015 	}
1016 	if (!pev)
1017 	{
1018 		clip.x = relief;
1019 		clip.y = relief;
1020 		clip.width = w_title_w - 2*relief;
1021 		clip.height = ICON_HEIGHT(fw) - 2*relief;
1022 		XClearWindow(dpy, FW_W_ICON_TITLE(fw));
1023 	}
1024 	else
1025 	{
1026 		/* needed for first drawing */
1027 		if (x_title - relief >= 1)
1028 		{
1029 			/* clear before the text */
1030 			XClearArea(
1031 				dpy, FW_W_ICON_TITLE(fw),
1032 				relief, relief, x_title - relief,
1033 				ICON_HEIGHT(fw) - 2*relief, False);
1034 		}
1035 		if (is_stippled)
1036 		{
1037 			/* clear the stippled area after the text */
1038 			XClearArea(
1039 				dpy, FW_W_ICON_TITLE(fw),
1040 				w_title_w - x_stipple - w_stipple -1, relief,
1041 				w_stipple + 2, ICON_HEIGHT(fw) - 2*relief,
1042 				False);
1043 		}
1044 	}
1045 
1046 	if (draw_string)
1047 	{
1048 		if (pev)
1049 		{
1050 			/* needed by xft font and at first drawing */
1051 			XClearArea(
1052 				dpy, FW_W_ICON_TITLE(fw),
1053 				clip.x, clip.y, clip.width, clip.height,
1054 				False);
1055 		}
1056 		fstr.str = fw->visible_icon_name;
1057 		fstr.win =  FW_W_ICON_TITLE(fw);
1058 		fstr.gc = Scr.TitleGC;
1059 		if (title_cs >= 0)
1060 		{
1061 			fstr.colorset = &Colorset[title_cs];
1062 			fstr.flags.has_colorset = 1;
1063 		}
1064 		else if (cs >= 0)
1065 		{
1066 			fstr.colorset = &Colorset[cs];
1067 			fstr.flags.has_colorset = 1;
1068 		}
1069 		fstr.x = x_title;
1070 		fstr.y = fw->icon_g.title_w_g.height - relief
1071 			- fw->icon_font->height + fw->icon_font->ascent;
1072 		FlocaleDrawString(dpy, fw->icon_font, &fstr, 0);
1073 		if (pev || is_stippled)
1074 		{
1075 			XSetClipMask(dpy, Scr.TitleGC, None);
1076 			if (region)
1077 			{
1078 				XDestroyRegion(region);
1079 			}
1080 		}
1081 	}
1082 	RelieveRectangle(
1083 		dpy, FW_W_ICON_TITLE(fw), 0, 0, w_title_w - 1,
1084 		ICON_HEIGHT(fw) - 1,
1085 		(fw->icon_title_relief > 0)? Relief:Shadow,
1086 		(fw->icon_title_relief > 0)? Shadow:Relief, relief);
1087 	if (is_stippled)
1088 	{
1089 		/* an odd number of lines every 4 pixels */
1090 		int pseudo_height = ICON_HEIGHT(fw)- 2*relief + 2;
1091 		int num = (pseudo_height /
1092 			   ICON_TITLE_STICK_VERT_DIST / 2) * 2 - 1;
1093 		int min = ICON_HEIGHT(fw) / 2 -
1094 			num * 2 + 1;
1095 		int max = ICON_HEIGHT(fw) / 2 +
1096 			num * 2 - ICON_TITLE_STICK_VERT_DIST + 1;
1097 		int i;
1098 
1099 		for(i = min; w_stipple > 0 && i <= max;
1100 		    i += ICON_TITLE_STICK_VERT_DIST)
1101 		{
1102 			RelieveRectangle(
1103 				dpy, FW_W_ICON_TITLE(fw), x_stipple,
1104 				i, w_stipple - 1, 1, Shadow,
1105 				Relief, ICON_TITLE_STICK_HEIGHT);
1106 			RelieveRectangle(
1107 				dpy, FW_W_ICON_TITLE(fw),
1108 				w_title_w - x_stipple - w_stipple, i,
1109 				w_stipple - 1, 1, Shadow, Relief,
1110 				ICON_TITLE_STICK_HEIGHT);
1111 		}
1112 	}
1113 
1114 	return;
1115 }
1116 
1117 static
DrawIconPixmapWindow(FvwmWindow * fw,Bool reset_bg,XEvent * pev,GC Shadow,GC Relief,int cs)1118 void DrawIconPixmapWindow(
1119 	FvwmWindow *fw, Bool reset_bg, XEvent *pev, GC Shadow, GC Relief, int cs)
1120 {
1121 	XRectangle r,clip;
1122 	Bool cleared = False;
1123 
1124 	if (!pev)
1125 	{
1126 		XMoveWindow(
1127 			dpy, FW_W_ICON_PIXMAP(fw), fw->icon_g.picture_w_g.x,
1128 			fw->icon_g.picture_w_g.y);
1129 		if (reset_bg &&
1130 		    (fw->iconDepth == 1 || fw->iconDepth == Pdepth || Pdefault ||
1131 		     IS_PIXMAP_OURS(fw)))
1132 		{
1133 			set_icon_pixmap_background(fw);
1134 			XClearArea(dpy, FW_W_ICON_PIXMAP(fw), 0, 0, 0, 0, False);
1135 			cleared = True;
1136 		}
1137 	}
1138 
1139 	/* need to locate the icon pixmap */
1140 	if (fw->iconPixmap != None)
1141 	{
1142 		if (fw->iconDepth == 1 || fw->iconDepth == Pdepth || Pdefault ||
1143 		    IS_PIXMAP_OURS(fw))
1144 		{
1145 			FvwmRenderAttributes fra;
1146 			Bool draw_icon = True;
1147 
1148 			memset(&fra, 0, sizeof(fra));
1149 			fra.mask = FRAM_DEST_IS_A_WINDOW;
1150 			if (cs >= 0)
1151 			{
1152 				fra.mask |= FRAM_HAVE_ICON_CSET;
1153 				fra.colorset = &Colorset[cs];
1154 			}
1155 			r.x = r.y = abs(fw->icon_background_relief) +
1156 				fw->icon_background_padding;
1157 			r.width = fw->icon_g.picture_w_g.width -
1158 				2 * (abs(fw->icon_background_relief) +
1159 				     fw->icon_background_padding);
1160 			r.height = fw->icon_g.picture_w_g.height -
1161 				2 * (abs(fw->icon_background_relief) +
1162 				     fw->icon_background_padding);
1163 			if (pev)
1164 			{
1165 				if (!frect_get_intersection(
1166 					pev->xexpose.x, pev->xexpose.y,
1167 					pev->xexpose.width, pev->xexpose.height,
1168 					r.x, r.y, r.width, r.height, &clip))
1169 				{
1170 					draw_icon = False;
1171 				}
1172 			}
1173 			else
1174 			{
1175 				clip.x = r.x;
1176 				clip.y = r.y;
1177 				clip.width = r.width;
1178 				clip.height = r.height;
1179 			}
1180 			if (draw_icon)
1181 			{
1182 				if (!cleared &&
1183 				    (fw->icon_alphaPixmap ||
1184 				     (cs >= 0 &&
1185 				      Colorset[cs].icon_alpha_percent < 100)))
1186 				{
1187 					XClearArea(
1188 						dpy, FW_W_ICON_PIXMAP(fw),
1189 						clip.x, clip.y, clip.width,
1190 						clip.height, False);
1191 				}
1192 				PGraphicsRenderPixmaps(
1193 					dpy, FW_W_ICON_PIXMAP(fw),
1194 					fw->iconPixmap, fw->icon_maskPixmap,
1195 					fw->icon_alphaPixmap, fw->iconDepth,
1196 					&fra, FW_W_ICON_PIXMAP(fw),
1197 					Scr.TitleGC, Scr.MonoGC, Scr.AlphaGC,
1198 					clip.x - r.x, clip.y - r.y,
1199 					clip.width, clip.height,
1200 					clip.x, clip.y, clip.width, clip.height,
1201 					False);
1202 			}
1203 		}
1204 		else
1205 		{
1206 			/* it's a client pixmap and fvwm is not using
1207 			 * the root visual The icon window has no 3d
1208 			 * border so copy to (0,0) install the root
1209 			 * colormap temporarily to help the Exceed
1210 			 * server */
1211 			if (Scr.bo.do_install_root_cmap)
1212 				InstallRootColormap();
1213 			XCopyArea(
1214 				dpy, fw->iconPixmap, FW_W_ICON_PIXMAP(fw),
1215 				DefaultGC(dpy, Scr.screen), 0, 0,
1216 				fw->icon_g.picture_w_g.width,
1217 				fw->icon_g.picture_w_g.height, 0, 0);
1218 			if (Scr.bo.do_install_root_cmap)
1219 				UninstallRootColormap();
1220 		}
1221 	}
1222 	/* only relieve unshaped icons or icons with a bg that share fvwm's
1223 	 * visual */
1224 	if ((fw->iconPixmap != None) &&
1225 	    (!IS_ICON_SHAPED(fw) || fw->icon_background_cs >= 0) &&
1226 	    (Pdefault || fw->iconDepth == 1 || fw->iconDepth == Pdepth ||
1227 	     IS_PIXMAP_OURS(fw)))
1228 	{
1229 		RelieveRectangle(
1230 			dpy, FW_W_ICON_PIXMAP(fw), 0, 0,
1231 			fw->icon_g.picture_w_g.width - 1,
1232 			fw->icon_g.picture_w_g.height - 1,
1233 			(fw->icon_background_relief > 0)? Relief:Shadow,
1234 			(fw->icon_background_relief > 0)? Shadow:Relief,
1235 			abs(fw->icon_background_relief));
1236 	}
1237 
1238 }
1239 
DrawIconWindow(FvwmWindow * fw,Bool draw_title,Bool draw_pixmap,Bool focus_change,Bool reset_bg,XEvent * pev)1240 void DrawIconWindow(
1241 	FvwmWindow *fw, Bool draw_title, Bool draw_pixmap, Bool focus_change,
1242 	Bool reset_bg, XEvent *pev)
1243 {
1244 	GC Shadow;
1245 	GC Relief;
1246 	Pixel TextColor;
1247 	Pixel BackColor;
1248 	color_quad draw_colors;
1249 	color_quad co_draw_colors;
1250 	int cs, co_cs;
1251 	int title_cs = -1;
1252 	int co_title_cs = -1;
1253 	int is_expanded = IS_ICON_ENTERED(fw);
1254 
1255 	if (IS_ICON_SUPPRESSED(fw) || (pev && fw->Desk != fw->m->virtual_scr.CurrentDesk))
1256 	{
1257 		return;
1258 	}
1259 
1260 	if (Scr.Hilite == fw)
1261 	{
1262 		if (fw->icon_title_cs_hi >= 0)
1263 		{
1264 			title_cs = fw->icon_title_cs_hi;
1265 			draw_colors.hilight = Colorset[title_cs].hilite;
1266 			draw_colors.shadow = Colorset[title_cs].shadow;
1267 			draw_colors.back = Colorset[title_cs].bg;
1268 			draw_colors.fore = Colorset[title_cs].fg;
1269 		}
1270 		else
1271 		{
1272 			draw_colors.hilight = fw->hicolors.hilight;
1273 			draw_colors.shadow = fw->hicolors.shadow;
1274 			draw_colors.back = fw->hicolors.back;
1275 			draw_colors.fore = fw->hicolors.fore;
1276 		}
1277 		if (fw->icon_title_cs >= 0)
1278 		{
1279 			co_title_cs = fw->icon_title_cs;
1280 			co_draw_colors.hilight = Colorset[co_title_cs].hilite;
1281 			co_draw_colors.shadow = Colorset[co_title_cs].shadow;
1282 			co_draw_colors.back = Colorset[co_title_cs].bg;
1283 			co_draw_colors.fore = Colorset[co_title_cs].fg;
1284 		}
1285 		else
1286 		{
1287 			co_draw_colors.hilight = fw->colors.hilight;
1288 			co_draw_colors.shadow = fw->colors.shadow;
1289 			co_draw_colors.back = fw->colors.back;
1290 			co_draw_colors.fore = fw->colors.fore;
1291 		}
1292 		cs = fw->cs_hi;
1293 		co_cs = fw->cs;
1294 	}
1295 	else
1296 	{
1297 		if (fw->icon_title_cs >= 0)
1298 		{
1299 			title_cs = fw->icon_title_cs;
1300 			draw_colors.hilight = Colorset[title_cs].hilite;
1301 			draw_colors.shadow = Colorset[title_cs].shadow;
1302 			draw_colors.back = Colorset[title_cs].bg;
1303 			draw_colors.fore = Colorset[title_cs].fg;
1304 		}
1305 		else
1306 		{
1307 			draw_colors.hilight = fw->colors.hilight;
1308 			draw_colors.shadow = fw->colors.shadow;
1309 			draw_colors.back = fw->colors.back;
1310 			draw_colors.fore = fw->colors.fore;
1311 		}
1312 		if (fw->icon_title_cs_hi >= 0)
1313 		{
1314 			co_title_cs = fw->icon_title_cs_hi;
1315 			co_draw_colors.hilight = Colorset[co_title_cs].hilite;
1316 			co_draw_colors.shadow = Colorset[co_title_cs].shadow;
1317 			co_draw_colors.back = Colorset[co_title_cs].bg;
1318 			co_draw_colors.fore = Colorset[co_title_cs].fg;
1319 		}
1320 		else
1321 		{
1322 			co_draw_colors.hilight = fw->hicolors.hilight;
1323 			co_draw_colors.shadow = fw->hicolors.shadow;
1324 			co_draw_colors.back = fw->hicolors.back;
1325 			co_draw_colors.fore = fw->hicolors.fore;
1326 		}
1327 		cs = fw->cs;
1328 		co_cs = fw->cs_hi;
1329 	}
1330 	if (Pdepth < 2 && Scr.Hilite != fw)
1331 	{
1332 		Relief = Scr.StdReliefGC;
1333 		Shadow = Scr.StdShadowGC;
1334 	}
1335 	else
1336 	{
1337 		if (Pdepth < 2 && Scr.Hilite == fw)
1338 		{
1339 			Relief = Scr.ScratchGC2;
1340 		}
1341 		else
1342 		{
1343 			Globalgcv.foreground = draw_colors.hilight;
1344 			Globalgcm = GCForeground;
1345 			XChangeGC(dpy,Scr.ScratchGC1,Globalgcm,&Globalgcv);
1346 			Relief = Scr.ScratchGC1;
1347 		}
1348 		Globalgcv.foreground = draw_colors.shadow;
1349 		XChangeGC(dpy,Scr.ScratchGC2, Globalgcm, &Globalgcv);
1350 		Shadow = Scr.ScratchGC2;
1351 	}
1352 	TextColor = draw_colors.fore;
1353 	BackColor = draw_colors.back;
1354 	/* set up TitleGC for drawing the icon label */
1355 	if (fw->icon_font != NULL)
1356 	{
1357 		NewFontAndColor(fw->icon_font, TextColor, BackColor);
1358 	}
1359 
1360 	if (draw_title && FW_W_ICON_TITLE(fw) != None)
1361 	{
1362 		if (pev && pev->xexpose.window != FW_W_ICON_TITLE(fw))
1363 		{
1364 			XEvent e;
1365 			if (FCheckTypedWindowEvent(
1366 			    dpy, FW_W_ICON_TITLE(fw), Expose, &e))
1367 			{
1368 				flush_accumulate_expose(
1369 					FW_W_ICON_TITLE(fw), &e);
1370 				DrawIconTitleWindow(
1371 					fw, &e, BackColor, Shadow, Relief, cs,
1372 					title_cs);
1373 			}
1374 		}
1375 		else
1376 		{
1377 			if (!pev)
1378 			{
1379 				FCheckWeedTypedWindowEvents(
1380 					dpy, FW_W_ICON_TITLE(fw), Expose,
1381 					NULL);
1382 			}
1383 			DrawIconTitleWindow(
1384 				fw, pev, BackColor, Shadow, Relief, cs,
1385 				title_cs);
1386 		}
1387 	}
1388 
1389 	if (draw_pixmap)
1390 	{
1391 		int bg_cs = fw->icon_background_cs;
1392 
1393 		if (bg_cs >= 0 &&
1394 		    (fw->iconDepth != 1 ||
1395 		     fw->icon_background_padding > 0 ||
1396 		     fw->icon_maskPixmap != None ||
1397 		     fw->icon_alphaPixmap != None))
1398 		{
1399 			if (Pdepth < 2 && Scr.Hilite == fw)
1400 			{
1401 				Relief = Scr.ScratchGC2;
1402 			}
1403 			else
1404 			{
1405 				Globalgcv.foreground = Colorset[bg_cs].hilite;
1406 				Globalgcm = GCForeground;
1407 				XChangeGC(
1408 					dpy,Scr.ScratchGC1,Globalgcm,&Globalgcv);
1409 				Relief = Scr.ScratchGC1;
1410 			}
1411 			Globalgcv.foreground = Colorset[bg_cs].shadow;
1412 			XChangeGC(dpy,Scr.ScratchGC2, Globalgcm, &Globalgcv);
1413 			Shadow = Scr.ScratchGC2;
1414 		}
1415 	}
1416 
1417 	if (focus_change && draw_pixmap)
1418 	{
1419 		Bool alpha_change = False;
1420 		Bool tint_change = False;
1421 		Bool relief_change = False;
1422 		Bool color_change = False;
1423 
1424 		draw_pixmap = False;
1425 		/* check if we have to draw the icons */
1426 
1427 		if (Pdepth < 2)
1428 		{
1429 			relief_change = True;
1430 		}
1431 		else if (fw->iconDepth == 1)
1432 		{
1433 			color_change =
1434 				(draw_colors.fore !=
1435 				 co_draw_colors.back) ||
1436 				(draw_colors.fore !=
1437 				 co_draw_colors.back);
1438 		}
1439 		if (!relief_change &&
1440 		    (fw->iconPixmap != None) && !IS_ICON_SHAPED(fw)
1441 		    && (Pdefault || fw->iconDepth == Pdepth || fw->iconDepth == 1
1442 			|| IS_PIXMAP_OURS(fw)))
1443 		{
1444 			relief_change =
1445 				(draw_colors.hilight !=
1446 				 co_draw_colors.hilight) ||
1447 				(draw_colors.shadow !=
1448 				 co_draw_colors.shadow);
1449 		}
1450 		if (cs >= 0 && co_cs >= 0)
1451 		{
1452 			alpha_change =
1453 				(Colorset[cs].icon_alpha_percent !=
1454 				 Colorset[co_cs].icon_alpha_percent);
1455 			tint_change =
1456 				(Colorset[cs].icon_tint_percent !=
1457 				 Colorset[co_cs].icon_tint_percent) ||
1458 				(Colorset[cs].icon_tint_percent > 0 &&
1459 				 Colorset[cs].icon_tint !=
1460 				 Colorset[co_cs].icon_tint);
1461 		}
1462 		else if (cs >= 0 && co_cs < 0)
1463 		{
1464 			alpha_change = (Colorset[cs].icon_alpha_percent < 100);
1465 			tint_change = (Colorset[cs].icon_tint_percent > 0);
1466 		}
1467 		else if (cs < 0 && co_cs >= 0)
1468 		{
1469 			alpha_change =
1470 				(Colorset[co_cs].icon_alpha_percent < 100);
1471 			tint_change = (Colorset[co_cs].icon_tint_percent > 0);
1472 		}
1473 		if (alpha_change || tint_change || relief_change ||
1474 		    color_change)
1475 		{
1476 			draw_pixmap = True;
1477 		}
1478 	}
1479 
1480 	if (draw_pixmap && FW_W_ICON_PIXMAP(fw) != None)
1481 	{
1482 		if (pev && pev->xexpose.window != FW_W_ICON_PIXMAP(fw))
1483 		{
1484 			XEvent e;
1485 			if (FCheckTypedWindowEvent(
1486 			    dpy, FW_W_ICON_PIXMAP(fw), Expose, &e))
1487 			{
1488 				flush_accumulate_expose(
1489 					FW_W_ICON_PIXMAP(fw), &e);
1490 				DrawIconPixmapWindow(
1491 					fw, reset_bg, &e, Shadow, Relief, cs);
1492 			}
1493 		}
1494 		else
1495 		{
1496 			if (!pev)
1497 			{
1498 				FCheckWeedTypedWindowEvents(
1499 					dpy, FW_W_ICON_PIXMAP(fw), Expose,
1500 					NULL);
1501 			}
1502 			DrawIconPixmapWindow(
1503 				fw, reset_bg, pev, Shadow, Relief, cs);
1504 		}
1505 	}
1506 
1507 	if (is_expanded)
1508 	{
1509 		if (FW_W_ICON_TITLE(fw) != None)
1510 		{
1511 			XRaiseWindow(dpy, FW_W_ICON_TITLE(fw));
1512 			raisePanFrames();
1513 		}
1514 	}
1515 	else
1516 	{
1517 		XWindowChanges xwc;
1518 		int mask;
1519 		xwc.sibling = FW_W_FRAME(fw);
1520 		xwc.stack_mode = Below;
1521 		mask = CWSibling|CWStackMode;
1522 		if (FW_W_ICON_TITLE(fw) != None)
1523 		{
1524 			XConfigureWindow(dpy, FW_W_ICON_TITLE(fw), mask, &xwc);
1525 		}
1526 		if (FW_W_ICON_PIXMAP(fw) != None)
1527 		{
1528 			XConfigureWindow(dpy, FW_W_ICON_PIXMAP(fw), mask, &xwc);
1529 		}
1530 	}
1531 	/* wait for pending EnterNotify/LeaveNotify events to suppress race
1532 	 * condition w/ expanding/collapsing icon titles */
1533 	XFlush(dpy);
1534 }
1535 
1536 /*
1537  *
1538  *  Procedure:
1539  *    ChangeIconPixmap - procedure change the icon pixmap or "pixmap"
1540  *      window. Called in events.c and ewmh_events.c
1541  *
1542  */
ChangeIconPixmap(FvwmWindow * fw)1543 void ChangeIconPixmap(FvwmWindow *fw)
1544 {
1545 	rectangle g;
1546 
1547 	if (!IS_ICONIFIED(fw))
1548 	{
1549 		ICON_DBG((stderr,"hpn: postpone icon change '%s'\n",
1550 			  fw->name.name));
1551 		/* update the icon later when application is iconified */
1552 		SET_HAS_ICON_CHANGED(fw, 1);
1553 	}
1554 	else if (IS_ICONIFIED(fw))
1555 	{
1556 		ICON_DBG((stderr,"hpn: applying new icon '%s'\n",
1557 			  fw->name.name));
1558 		SET_ICONIFIED(fw, 0);
1559 		SET_ICON_UNMAPPED(fw, 0);
1560 		get_icon_geometry(fw, &g);
1561 		CreateIconWindow(fw, g.x, g.y);
1562 		broadcast_icon_geometry(fw, False);
1563 		/* domivogt (15-Sep-1999): BroadcastConfig informs modules of
1564 		 * the configuration change including the iconified flag. So
1565 		 * this flag must be set here. I'm not sure if the two calls of
1566 		 * the SET_ICONIFIED macro after BroadcastConfig are necessary,
1567 		 * but since it's only minimal overhead I prefer to be on the
1568 		 * safe side. */
1569 		SET_ICONIFIED(fw, 1);
1570 		BroadcastConfig(M_CONFIGURE_WINDOW, fw);
1571 		SET_ICONIFIED(fw, 0);
1572 
1573 		if (!IS_ICON_SUPPRESSED(fw))
1574 		{
1575 			LowerWindow(fw, False);
1576 			AutoPlaceIcon(fw, NULL, True);
1577 			if (fw->Desk == fw->m->virtual_scr.CurrentDesk)
1578 			{
1579 				if (FW_W_ICON_TITLE(fw))
1580 				{
1581 					XMapWindow(dpy, FW_W_ICON_TITLE(fw));
1582 				}
1583 				if (FW_W_ICON_PIXMAP(fw) != None)
1584 				{
1585 					XMapWindow(dpy, FW_W_ICON_PIXMAP(fw));
1586 				}
1587 			}
1588 		}
1589 		SET_ICONIFIED(fw, 1);
1590 		DrawIconWindow(fw, False, True, False, False, NULL);
1591 	}
1592 
1593 	return;
1594 }
1595 
1596 /*
1597  *
1598  *  Procedure:
1599  *      RedoIconName - procedure to re-position the icon window and name
1600  *
1601  */
RedoIconName(FvwmWindow * fw)1602 void RedoIconName(FvwmWindow *fw)
1603 {
1604 	if (IS_ICON_SUPPRESSED(fw))
1605 	{
1606 		return;
1607 	}
1608 	if (FW_W_ICON_TITLE(fw) == None)
1609 	{
1610 		return;
1611 	}
1612 	setup_icon_title_size(fw);
1613 	/* clear the icon window, and trigger a re-draw via an expose event */
1614 	if (IS_ICONIFIED(fw))
1615 	{
1616 		DrawIconWindow(fw, True, False, False, False, NULL);
1617 		XClearArea(dpy, FW_W_ICON_TITLE(fw), 0, 0, 0, 0, True);
1618 	}
1619 
1620 	return;
1621 }
1622 
1623 /*
1624  *
1625  *  Procedure:
1626  *      AutoPlace - Find a home for an icon
1627  *
1628  */
AutoPlaceIcon(FvwmWindow * t,initial_window_options_t * win_opts,Bool do_move_immediately)1629 void AutoPlaceIcon(
1630 	FvwmWindow *t, initial_window_options_t *win_opts,
1631 	Bool do_move_immediately)
1632 {
1633   int base_x, base_y;
1634   int width,height;
1635   FvwmWindow *test_fw;
1636   Bool loc_ok;
1637   Bool loc_ok_wrong_screen;
1638   Bool loc_ok_wrong_screen2;
1639   int real_x=10, real_y=10;
1640   int new_x, new_y;
1641   Bool do_move_icon = False;
1642 
1643 #if 0
1644   /* dv (16-Mar-2003):  We need to place the icon even if there is no icon so
1645    * the 'position' can be communicated to the modules to decide whether to show
1646    * the icon or not. */
1647   if (FW_W_ICON_PIXMAP(t) == None && FW_W_ICON_TITLE(t) == None)
1648   {
1649 	  return;
1650   }
1651 #endif
1652   /* New! Put icon in same page as the center of the window */
1653   /* Not a good idea for StickyIcons. Neither for icons of windows that are
1654    * visible on the current page. */
1655   if (IS_ICON_STICKY_ACROSS_DESKS(t) || IS_STICKY_ACROSS_DESKS(t))
1656   {
1657     t->Desk = t->m->virtual_scr.CurrentDesk;
1658   }
1659   if (IS_ICON_STICKY_ACROSS_PAGES(t) || IS_STICKY_ACROSS_PAGES(t))
1660   {
1661     base_x = 0;
1662     base_y = 0;
1663     /*Also, if its a stickyWindow, put it on the current page! */
1664     new_x = t->g.frame.x % monitor_get_all_widths();
1665     new_y = t->g.frame.y % monitor_get_all_heights();
1666     if (new_x + t->g.frame.width <= 0)
1667       new_x += monitor_get_all_widths();
1668     if (new_y + t->g.frame.height <= 0)
1669       new_y += monitor_get_all_heights();
1670     frame_setup_window(
1671 	    t, new_x, new_y, t->g.frame.width, t->g.frame.height, False);
1672   }
1673   else if (IsRectangleOnThisPage(t->m, &(t->g.frame), t->Desk))
1674   {
1675     base_x = 0;
1676     base_y = 0;
1677   }
1678   else
1679   {
1680     base_x = ((t->g.frame.x + t->m->virtual_scr.Vx + (t->g.frame.width >> 1)) /
1681       monitor_get_all_widths()) * monitor_get_all_widths();
1682     base_y= ((t->g.frame.y + t->m->virtual_scr.Vy + (t->g.frame.height >> 1)) /
1683       monitor_get_all_heights()) * monitor_get_all_heights();
1684     /* limit icon position to desktop */
1685     if (base_x > t->m->virtual_scr.VxMax)
1686       base_x = t->m->virtual_scr.VxMax;
1687     if (base_x < 0)
1688       base_x = 0;
1689     if (base_y > t->m->virtual_scr.VyMax)
1690       base_y = t->m->virtual_scr.VyMax;
1691     if (base_y < 0)
1692       base_y = 0;
1693     base_x -= t->m->virtual_scr.Vx;
1694     base_y -= t->m->virtual_scr.Vy;
1695   }
1696   if (IS_ICON_MOVED(t) ||
1697       (win_opts != NULL && win_opts->flags.use_initial_icon_xy))
1698   {
1699     rectangle g;
1700     int dx;
1701     int dy;
1702 
1703     get_icon_geometry(t, &g);
1704     if (win_opts != NULL && win_opts->flags.use_initial_icon_xy)
1705     {
1706       g.x = win_opts->initial_icon_x;
1707       g.y = win_opts->initial_icon_y;
1708     }
1709     dx = g.x;
1710     dy = g.y;
1711 
1712     /* just make sure the icon is on this page */
1713     g.x = g.x % monitor_get_all_widths() + base_x;
1714     g.y = g.y % monitor_get_all_heights() + base_y;
1715     if (g.x < 0)
1716     {
1717       g.x += monitor_get_all_widths();
1718     }
1719     if (g.y < 0)
1720     {
1721       g.y += monitor_get_all_heights();
1722     }
1723     dx = g.x - dx;
1724     dy = g.y - dy;
1725     modify_icon_position(t, dx, dy);
1726     do_move_icon = True;
1727   }
1728   else if (USE_ICON_POSITION_HINT(t) && t->wmhints &&
1729 	   t->wmhints->flags & IconPositionHint)
1730   {
1731     set_icon_position(t, t->wmhints->icon_x, t->wmhints->icon_y);
1732     do_move_icon = True;
1733   }
1734   /* dje 10/12/97:
1735      Look thru chain of icon boxes assigned to window.
1736      Add logic for grids and fill direction.
1737   */
1738   else if (DO_IGNORE_ICON_BOXES(t))
1739   {
1740     int sx;
1741     int sy;
1742     int sw;
1743     int sh;
1744     fscreen_scr_arg fscr;
1745     rectangle g;
1746 
1747     get_icon_geometry(t, &g);
1748     get_icon_corner(t, &g);
1749     fscr.xypos.x = g.x + g.width / 2;
1750     fscr.xypos.y = g.y + g.height / 2;
1751     FScreenGetScrRect(&fscr, FSCREEN_XYPOS, &sx, &sy, &sw, &sh);
1752     if (g.x < sx)
1753       g.x = sx;
1754     else if (g.x + g.width > sx + sw)
1755       g.x = sx + sw - g.width;
1756     if (g.y < sy)
1757       g.y = sy;
1758     else if (g.y + g.height > sy + sh)
1759       g.y = sy + sh - g.height;
1760     set_icon_position(t, g.x, g.y);
1761     do_move_icon = True;
1762   }
1763   else
1764   {
1765     /* A place to hold inner and outer loop variables. */
1766     typedef struct dimension_struct
1767     {
1768       int step;                         /* grid size (may be negative) */
1769       int start_at;                     /* starting edge */
1770       int real_start;                   /* on screen starting edge */
1771       int end_at;                       /* ending edge */
1772       int base;                         /* base for screen */
1773       int icon_dimension;               /* height or width */
1774       int nom_dimension;                /* nonminal height or width */
1775       int screen_dimension;             /* screen height or width */
1776       int screen_offset;                /* screen offset */
1777     } dimension;
1778     dimension dim[3];                   /* space for work, 1st, 2nd dimen */
1779     icon_boxes *icon_boxes_ptr;         /* current icon box */
1780     int i;                              /* index for inner/outer loop data */
1781     fscreen_scr_arg *fscr;
1782     rectangle ref;
1783     rectangle g;
1784 
1785     /* Hopefully this makes the following more readable. */
1786 #define ICONBOX_LFT icon_boxes_ptr->IconBox[0]
1787 #define ICONBOX_TOP icon_boxes_ptr->IconBox[1]
1788 #define ICONBOX_RGT icon_boxes_ptr->IconBox[2]
1789 #define ICONBOX_BOT icon_boxes_ptr->IconBox[3]
1790 #define BOT_FILL icon_boxes_ptr->IconFlags & ICONFILLBOT
1791 #define RGT_FILL icon_boxes_ptr->IconFlags & ICONFILLRGT
1792 #define HRZ_FILL icon_boxes_ptr->IconFlags & ICONFILLHRZ
1793 
1794     /* needed later */
1795     fscr = fxcalloc(1, sizeof *fscr);
1796     fscr->xypos.x = t->g.frame.x + (t->g.frame.width / 2) - base_x;
1797     fscr->xypos.y = t->g.frame.y + (t->g.frame.height / 2) - base_y;
1798     get_icon_geometry(t, &g);
1799     /* unnecessary copy of width */
1800     width = g.width;
1801     /* total height */
1802     height = g.height;
1803     /* no slot found yet */
1804     loc_ok = False;
1805     loc_ok_wrong_screen = False;
1806 
1807     /* check all boxes in order */
1808     icon_boxes_ptr = NULL;              /* init */
1809     while(do_all_iconboxes(t, &icon_boxes_ptr))
1810     {
1811       if (loc_ok == True)
1812       {
1813 	/* leave for loop */
1814 	break;
1815       }
1816       /* get the screen dimensions for the icon box */
1817       FScreenGetScrRect(fscr, FSCREEN_CURRENT,
1818 		        &ref.x, &ref.y, &ref.width, &ref.height);
1819       dim[1].screen_offset = ref.y;
1820       dim[1].screen_dimension = ref.height;
1821       dim[2].screen_offset = ref.x;
1822       dim[2].screen_dimension = ref.width;
1823       /* y amount */
1824       dim[1].step = icon_boxes_ptr->IconGrid[1];
1825       /* init start from */
1826       dim[1].start_at = ICONBOX_TOP + dim[1].screen_offset;
1827       if (icon_boxes_ptr->IconSign[1] == '-') {
1828 	dim[1].start_at += dim[1].screen_dimension;
1829       }
1830       /* init end at */
1831       dim[1].end_at = ICONBOX_BOT + dim[1].screen_offset;
1832       if (icon_boxes_ptr->IconSign[3] == '-') {
1833 	dim[1].end_at += dim[1].screen_dimension;
1834       }
1835       /* save base */
1836       dim[1].base = base_y;
1837       /* save dimension */
1838       dim[1].icon_dimension = height;
1839       if (BOT_FILL)
1840       {
1841 	/* fill from bottom */
1842 	/* reverse step */
1843 	dim[1].step = 0 - dim[1].step;
1844       } /* end fill from bottom */
1845 
1846       /* x amount */
1847       dim[2].step = icon_boxes_ptr->IconGrid[0];
1848       /* init start from */
1849       dim[2].start_at = ICONBOX_LFT + dim[2].screen_offset;
1850       if (icon_boxes_ptr->IconSign[0] == '-') {
1851 	dim[2].start_at += dim[2].screen_dimension;
1852       }
1853       /* init end at */
1854       dim[2].end_at = ICONBOX_RGT + dim[2].screen_offset;
1855       if (icon_boxes_ptr->IconSign[2] == '-') {
1856 	dim[2].end_at += dim[2].screen_dimension;
1857       }
1858       /* save base */
1859       dim[2].base   = base_x;
1860       /* save dimension */
1861       dim[2].icon_dimension = width;
1862       if (RGT_FILL)
1863       {
1864 	/* fill from right */
1865 	/* reverse step */
1866 	dim[2].step = 0 - dim[2].step;
1867       } /* end fill from right */
1868       for (i=1;i<=2;i++)
1869       {
1870 	/* for dimensions 1 and 2 */
1871 	/* If the window is taller than the icon box, ignore the icon height
1872 	 * when figuring where to put it. Same goes for the width
1873 	 * This should permit reasonably graceful handling of big icons. */
1874 	dim[i].nom_dimension = dim[i].icon_dimension;
1875 	if (dim[i].icon_dimension >= dim[i].end_at - dim[i].start_at)
1876 	{
1877 	  dim[i].nom_dimension = dim[i].end_at - dim[i].start_at - 1;
1878 	}
1879 	if (dim[i].step < 0)
1880 	{
1881 	  /* if moving backwards */
1882 	  /* save */
1883 	  dim[0].start_at = dim[i].start_at;
1884 	  /* swap one */
1885 	  dim[i].start_at = dim[i].end_at;
1886 	  /* swap the other */
1887 	  dim[i].end_at = dim[0].start_at;
1888 	  dim[i].start_at -= dim[i].icon_dimension;
1889 	} /* end moving backwards */
1890 	/* adjust both to base */
1891 	dim[i].start_at += dim[i].base;
1892 	dim[i].end_at += dim[i].base;
1893       } /* end 2 dimensions */
1894       if (HRZ_FILL)
1895       {
1896 	/* if hrz first */
1897 	/* save */
1898 	memcpy(&dim[0],&dim[1],sizeof(dimension));
1899 	/* switch one */
1900 	memcpy(&dim[1],&dim[2],sizeof(dimension));
1901 	/* switch the other */
1902 	memcpy(&dim[2],&dim[0],sizeof(dimension));
1903       } /* end horizontal dimension first */
1904       /* save for reseting inner loop */
1905       dim[0].start_at = dim[2].start_at;
1906       loc_ok_wrong_screen2 = False;
1907       while((dim[1].step < 0            /* filling reversed */
1908 	     ? (dim[1].start_at + dim[1].icon_dimension - dim[1].nom_dimension
1909 		> dim[1].end_at)        /* check back edge */
1910 	     : (dim[1].start_at + dim[1].nom_dimension
1911 		< dim[1].end_at))       /* check front edge */
1912 	    && (!loc_ok)
1913 	    && (!loc_ok_wrong_screen2)) {  /* nothing found yet */
1914 	dim[1].real_start = dim[1].start_at; /* init */
1915 	if (dim[1].start_at + dim[1].icon_dimension >
1916 	    dim[1].screen_offset + dim[1].screen_dimension - 2 + dim[1].base)
1917 	{
1918 	  /* off screen, move on screen */
1919 	  dim[1].real_start = dim[1].screen_offset + dim[1].screen_dimension
1920 	    - dim[1].icon_dimension + dim[1].base;
1921 	} /* end off screen */
1922 	if (dim[1].start_at < dim[1].screen_offset + dim[1].base)
1923 	{
1924 	  /* if off other edge, move on screen */
1925 	  dim[1].real_start = dim[1].screen_offset + dim[1].base;
1926 	} /* end off other edge */
1927 	/* reset inner loop */
1928 	dim[2].start_at = dim[0].start_at;
1929 	while((dim[2].step < 0            /* filling reversed */
1930 	       ? (dim[2].start_at + dim[2].icon_dimension-dim[2].nom_dimension
1931 		  > dim[2].end_at)        /* check back edge */
1932 	       : (dim[2].start_at + dim[2].nom_dimension
1933 		  < dim[2].end_at))       /* check front edge */
1934 	      && (!loc_ok)
1935 	      && (!loc_ok_wrong_screen2)) { /* nothing found yet */
1936 	  dim[2].real_start = dim[2].start_at; /* init */
1937 	  if (dim[2].start_at + dim[2].icon_dimension >
1938 	      dim[2].screen_offset + dim[2].screen_dimension - 2 + dim[2].base)
1939 	  {
1940 	    /* if off screen, move on screen */
1941 	    dim[2].real_start = dim[2].screen_offset + dim[2].screen_dimension
1942 	      - dim[2].icon_dimension + dim[2].base;
1943 	  } /* end off screen */
1944 	  if (dim[2].start_at < dim[2].screen_offset + dim[2].base)
1945 	  {
1946 	    /* if off other edge, move on screen */
1947 	    dim[2].real_start = dim[2].screen_offset + dim[2].base;
1948 	  } /* end off other edge */
1949 
1950 	  if (HRZ_FILL)
1951 	  {
1952 	    /* hrz first */
1953 	    /* unreverse them */
1954 	    real_x = dim[1].real_start;
1955 	    real_y = dim[2].real_start;
1956 	  }
1957 	  else
1958 	  {
1959 	    /* reverse them */
1960 	    real_x = dim[2].real_start;
1961 	    real_y = dim[1].real_start;
1962 	  }
1963 
1964 	  /* this may be a good location */
1965 	  if (FScreenIsRectangleOnScreen(fscr, FSCREEN_XYPOS, &ref))
1966 	  {
1967 	    loc_ok = True;
1968 	  }
1969 	  else
1970 	  {
1971 	    loc_ok_wrong_screen2 = True;
1972 	  }
1973 	  test_fw = Scr.FvwmRoot.next;
1974 	  while((test_fw != (FvwmWindow *)0)
1975 		&&(loc_ok == True || loc_ok_wrong_screen2))
1976 	  {
1977 	    /* test overlap */
1978 	    if (test_fw->Desk == t->Desk)
1979 	    {
1980 	      rectangle g;
1981 
1982 	      if ((IS_ICONIFIED(test_fw)) &&
1983 		 (!IS_TRANSIENT(test_fw) ||
1984 		  !IS_ICONIFIED_BY_PARENT(test_fw)) &&
1985 		 (FW_W_ICON_TITLE(test_fw)||FW_W_ICON_PIXMAP(test_fw)) &&
1986 		 (test_fw != t)) {
1987 		get_icon_geometry(test_fw, &g);
1988 		if ((g.x<(real_x+width+MIN_ICON_BOX_DIST))&&
1989 		   ((g.x+g.width+MIN_ICON_BOX_DIST) > real_x)&&
1990 		   (g.y<(real_y+height+MIN_ICON_BOX_DIST))&&
1991 		   ((g.y+g.height + MIN_ICON_BOX_DIST)>real_y))
1992 		{
1993 		  /* don't accept this location */
1994 		  loc_ok = False;
1995 		  loc_ok_wrong_screen2 = False;
1996 		} /* end if icons overlap */
1997 	      } /* end if its an icon */
1998 	    } /* end if same desk */
1999 	    test_fw = test_fw->next;
2000 	  } /* end while icons that may overlap */
2001 	  if (loc_ok_wrong_screen2)
2002 	  {
2003 	    loc_ok_wrong_screen = True;
2004 	  }
2005 	  /* Grid inner value & direction */
2006 	  dim[2].start_at += dim[2].step;
2007 	} /* end while room inner dimension */
2008 	/* Grid outer value & direction */
2009 	dim[1].start_at += dim[1].step;
2010       } /* end while room outer dimension */
2011     } /* end for all icon boxes, or found space */
2012     if (!loc_ok && !loc_ok_wrong_screen)
2013       /* If icon never found a home just leave it */
2014       return;
2015     set_icon_position(t, real_x, real_y);
2016     broadcast_icon_geometry(t, True);
2017     do_move_icon = True;
2018     free(fscr);
2019 
2020   }
2021   if (do_move_icon && do_move_immediately)
2022   {
2023     move_icon_to_position(t);
2024   }
2025 
2026   return;
2027 }
2028 
2029 static icon_boxes *global_icon_box_ptr;
2030 /* Find next icon box to try to place icon in.
2031    Goes thru chain that the window got thru style matching,
2032    then the global icon box.
2033    Create the global icon box on first call.
2034    Return code indicates when the boxes are used up.
2035    The boxes could only get completely used up when you fill the screen
2036    with them.
2037 */
2038 static int
do_all_iconboxes(FvwmWindow * t,icon_boxes ** icon_boxes_ptr)2039 do_all_iconboxes(FvwmWindow *t, icon_boxes **icon_boxes_ptr)
2040 {
2041 	if (global_icon_box_ptr == 0)
2042 	{
2043 		/* if first time */
2044 		int sx;
2045 		int sy;
2046 		int sw;
2047 		int sh;
2048 		/* Right now, the global box is hard-coded, fills the primary
2049 		 * screen, uses an 80x80 grid, and fills top-bottom,
2050 		 * left-right */
2051 		FScreenGetScrRect(NULL, FSCREEN_PRIMARY, &sx, &sy, &sw, &sh);
2052 		global_icon_box_ptr = fxcalloc(1, sizeof(icon_boxes));
2053 		global_icon_box_ptr->IconBox[0] = sx;
2054 		global_icon_box_ptr->IconBox[1] = sy;
2055 		global_icon_box_ptr->IconBox[2] = sx + sw;
2056 		global_icon_box_ptr->IconBox[3] = sy + sh;
2057 		global_icon_box_ptr->IconGrid[0] = 80;
2058 		global_icon_box_ptr->IconGrid[1] = 80;
2059 		global_icon_box_ptr->IconFlags = ICONFILLHRZ;
2060 	}
2061 	if (*icon_boxes_ptr == NULL)
2062 	{
2063 		/* first time? */
2064 		/* start at windows box */
2065 		*icon_boxes_ptr = t->IconBoxes;
2066 		if (!*icon_boxes_ptr)
2067 		{
2068 			/* if window has no box */
2069 			/* use global box */
2070 			*icon_boxes_ptr = global_icon_box_ptr;
2071 		}
2072 		/* use box */
2073 		return (1);
2074 	}
2075 
2076 	/* Here its not the first call, we are either on the chain or at
2077 	 * the global box */
2078 	if (*icon_boxes_ptr == global_icon_box_ptr)
2079 	{
2080 		/* if the global box */
2081 		/* completely out of boxes (unlikely) */
2082 		return (0);
2083 	}
2084 	/* move to next one on chain */
2085 	*icon_boxes_ptr = (*icon_boxes_ptr)->next;
2086 	if (*icon_boxes_ptr)
2087 	{
2088                 /* if there is a next one */
2089 		/* return it */
2090 		return (1);
2091 	}
2092 	/* global box */
2093 	*icon_boxes_ptr = global_icon_box_ptr;
2094 
2095 	/* use it */
2096 	return (1);
2097 }
2098 
2099 /*
2100  *
2101  * Looks for icon from a file
2102  *
2103  */
GetIconFromFile(FvwmWindow * fw)2104 static void GetIconFromFile(FvwmWindow *fw)
2105 {
2106 	char *path = NULL;
2107 	FvwmPictureAttributes fpa;
2108 
2109 	fpa.mask = 0;
2110 	if (fw->cs >= 0 && Colorset[fw->cs].do_dither_icon)
2111 	{
2112 		fpa.mask |= FPAM_DITHER;
2113 	}
2114 	fw->icon_g.picture_w_g.width = 0;
2115 	fw->icon_g.picture_w_g.height = 0;
2116 	path = PictureFindImageFile(fw->icon_bitmap_file, NULL, R_OK);
2117 	if (path == NULL)
2118 	{
2119 		return;
2120 	}
2121 	if (!PImageLoadPixmapFromFile(
2122 		dpy, Scr.NoFocusWin, path, &fw->iconPixmap,
2123 		&fw->icon_maskPixmap, &fw->icon_alphaPixmap,
2124 		&fw->icon_g.picture_w_g.width, &fw->icon_g.picture_w_g.height,
2125 		&fw->iconDepth, &fw->icon_nalloc_pixels, &fw->icon_alloc_pixels,
2126 		&fw->icon_no_limit, fpa))
2127 	{
2128 		fvwm_debug(__func__, "Failed to load %s", path);
2129 		free(path);
2130 		return;
2131 	}
2132 	SET_PIXMAP_OURS(fw, 1);
2133 	free(path);
2134 	if (FShapesSupported && fw->icon_maskPixmap)
2135 	{
2136 		SET_ICON_SHAPED(fw, 1);
2137 	}
2138 
2139 	return;
2140 }
2141 
2142 /*
2143  *
2144  * Looks for an application supplied icon window
2145  *
2146  */
GetIconWindow(FvwmWindow * fw)2147 static void GetIconWindow(FvwmWindow *fw)
2148 {
2149 	int w;
2150 	int h;
2151 	int bw;
2152 
2153 	fw->icon_g.picture_w_g.width = 0;
2154 	fw->icon_g.picture_w_g.height = 0;
2155 
2156 	/* We are guaranteed that wmhints is non-null when calling this
2157 	 * routine */
2158 	if (XGetGeometry(
2159 		    dpy, fw->wmhints->icon_window, &JunkRoot, &JunkX, &JunkY,
2160 		    (unsigned int*)&w, (unsigned int*)&h,(unsigned int*)&bw,
2161 		    (unsigned int*)&JunkDepth) == 0)
2162 	{
2163 		fvwm_debug(__func__,
2164 			   "Window '%s' has a bad icon window! Ignoring icon"
2165 			   " window.", fw->name.name);
2166 		/* disable the icon window hint */
2167 		fw->wmhints->icon_window = None;
2168 		fw->wmhints->flags &= ~IconWindowHint;
2169 		return;
2170 	}
2171 	fw->icon_border_width = bw;
2172 	fw->icon_g.picture_w_g.width = w + 2 * bw;
2173 	fw->icon_g.picture_w_g.height = h + 2 * bw;
2174 	/*
2175 	 * Now make the new window the icon window for this window,
2176 	 * and set it up to work as such (select for key presses
2177 	 * and button presses/releases, set up the contexts for it,
2178 	 * and define the cursor for it).
2179 	 */
2180 	FW_W_ICON_PIXMAP(fw) = fw->wmhints->icon_window;
2181 	if (FShapesSupported)
2182 	{
2183 		if (fw->wmhints->flags & IconMaskHint)
2184 		{
2185 			SET_ICON_SHAPED(fw, 1);
2186 			fw->icon_maskPixmap = fw->wmhints->icon_mask;
2187 		}
2188 	}
2189 	/* Make sure that the window is a child of the root window ! */
2190 	/* Olwais screws this up, maybe others do too! */
2191 	XReparentWindow(dpy, FW_W_ICON_PIXMAP(fw), Scr.Root, 0,0);
2192 	SET_ICON_OURS(fw, 0);
2193 
2194 	return;
2195 }
2196 
2197 
2198 /*
2199  *
2200  * Looks for an application supplied bitmap or pixmap
2201  *
2202  */
GetIconBitmap(FvwmWindow * fw)2203 static void GetIconBitmap(FvwmWindow *fw)
2204 {
2205 	int width, height, depth;
2206 
2207 	fw->icon_g.picture_w_g.width = 0;
2208 	fw->icon_g.picture_w_g.height = 0;
2209 
2210 	/* We are guaranteed that wmhints is non-null when calling this routine
2211 	 */
2212 	if (!XGetGeometry(
2213 		    dpy, fw->wmhints->icon_pixmap, &JunkRoot, &JunkX, &JunkY,
2214 		    (unsigned int*)&width, (unsigned int*)&height,
2215 		    (unsigned int*)&JunkBW, (unsigned int*)&depth))
2216 	{
2217 		fvwm_debug(__func__,
2218 			   "Window '%s' has a bad icon pixmap! Ignoring icon.",
2219 			   fw->name.name);
2220 		/* disable icon pixmap hint */
2221 		fw->wmhints->icon_pixmap = None;
2222 		fw->wmhints->flags &= ~IconPixmapHint;
2223 		return;
2224 	}
2225 	/* sanity check the pixmap depth, it must be the same as the root or 1
2226 	 */
2227 	if (depth != 1 && depth != Pdepth &&
2228 	    depth != DefaultDepth(dpy,Scr.screen))
2229 	{
2230 		fvwm_debug(__func__,
2231 			   "Window '%s' has a bad icon bitmap depth %d (should"
2232 			   " be 1, %d or %d)! Ignoring icon bitmap.",
2233 			   fw->name.name, depth, Pdepth,
2234 			   DefaultDepth(dpy,Scr.screen));
2235 		/* disable icon pixmap hint */
2236 		fw->wmhints->icon_pixmap = None;
2237 		fw->wmhints->flags &= ~IconPixmapHint;
2238 		return;
2239 	}
2240 	fw->iconPixmap = fw->wmhints->icon_pixmap;
2241 	fw->icon_g.picture_w_g.width = width;
2242 	fw->icon_g.picture_w_g.height = height;
2243 	fw->iconDepth = depth;
2244 	if (FShapesSupported)
2245 	{
2246 		if (fw->wmhints->flags & IconMaskHint)
2247 		{
2248 			SET_ICON_SHAPED(fw, 1);
2249 			fw->icon_maskPixmap = fw->wmhints->icon_mask;
2250 		}
2251 	}
2252 	SET_PIXMAP_OURS(fw, 0);
2253 
2254 	return;
2255 }
2256 
2257 /*
2258  *
2259  *  Procedure:
2260  *      DeIconify a window
2261  *
2262  */
DeIconify(FvwmWindow * fw)2263 void DeIconify(FvwmWindow *fw)
2264 {
2265 	FvwmWindow *t, *tmp, *ofw;
2266 	FvwmWindow *sf = get_focus_window();
2267 	rectangle icon_rect;
2268 	XWindowAttributes winattrs = {0};
2269 
2270 	if (!fw)
2271 	{
2272 		return;
2273 	}
2274 	if (!XGetWindowAttributes(dpy, FW_W(fw), &winattrs))
2275 	{
2276 		return;
2277 	}
2278 
2279 	/* make sure fw->flags.is_map_pending is OK */
2280 	if (winattrs.map_state == IsViewable && IS_MAP_PENDING(fw))
2281 	{
2282 		SET_MAP_PENDING(fw, 0);
2283 	}
2284 	else if (IS_MAP_PENDING(fw))
2285 	{
2286 		/* final state: de-iconified */
2287 		SET_ICONIFY_AFTER_MAP(fw, 0);
2288 		return;
2289 	}
2290 	for (ofw = NULL; fw != ofw && IS_ICONIFIED_BY_PARENT(fw); )
2291 	{
2292 		t = get_transientfor_fvwmwindow(fw);
2293 		if (t == NULL)
2294 		{
2295 			break;
2296 		}
2297 		ofw = fw;
2298 		fw = t;
2299 	}
2300 	if (IS_ICONIFIED_BY_PARENT(fw))
2301 	{
2302 		SET_ICONIFIED_BY_PARENT(fw, 0);
2303 	}
2304 
2305 	/* AS dje  RaiseWindow(fw); */
2306 
2307 	if (fw == sf)
2308 	{
2309 		/* take away the focus before mapping */
2310 		DeleteFocus(True);
2311 	}
2312 	/* Note: DeleteFocus may delete the flags set by
2313 	 * mark_transient_subtree(), so do it later. */
2314 	mark_transient_subtree(fw, MARK_ALL_LAYERS, MARK_ALL, False, True);
2315 	/* now de-iconify transients */
2316 	for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
2317 	{
2318 		if (t == fw || IS_IN_TRANSIENT_SUBTREE(t))
2319 		{
2320 			SET_IN_TRANSIENT_SUBTREE(t, 0);
2321 			SET_MAPPED(t, 1);
2322 			SET_ICONIFIED_BY_PARENT(t, 0);
2323 			if (Scr.Hilite == t)
2324 			{
2325 				border_draw_decorations(
2326 					t, PART_ALL, False, True, CLEAR_ALL,
2327 					NULL, NULL);
2328 			}
2329 
2330 			/* AS stuff starts here dje */
2331 			if (FW_W_ICON_PIXMAP(t))
2332 			{
2333 				XUnmapWindow(dpy, FW_W_ICON_PIXMAP(t));
2334 			}
2335 			if (FW_W_ICON_TITLE(t))
2336 			{
2337 				XUnmapWindow(dpy, FW_W_ICON_TITLE(t));
2338 			}
2339 			XFlush(dpy);
2340 			/* End AS */
2341 			XMapWindow(dpy, FW_W(t));
2342 			if (t->Desk == t->m->virtual_scr.CurrentDesk)
2343 			{
2344 				rectangle r;
2345 
2346 				get_icon_geometry(t, &r);
2347 				/* update absoluthe geometry in case the icon
2348 				 * was moved over a page boundary; the move
2349 				 * code already takes care of keeping the frame
2350 				 * geometry up to date */
2351 				update_absolute_geometry(t);
2352 				if (IsRectangleOnThisPage(t->m, &r, t->Desk) &&
2353 				    !IsRectangleOnThisPage(t->m,
2354 					    &(t->g.frame), t->Desk))
2355 				{
2356 					/* Make sure we keep it on screen when
2357 					 * de-iconifying. */
2358 					t->g.frame.x -=
2359 						truncate_to_multiple(
2360 							t->g.frame.x,
2361 							monitor_get_all_widths());
2362 					t->g.frame.y -=
2363 						truncate_to_multiple(
2364 							t->g.frame.y,
2365 							monitor_get_all_heights());
2366 					XMoveWindow(
2367 						dpy, FW_W_FRAME(t),
2368 						t->g.frame.x, t->g.frame.y);
2369 					update_absolute_geometry(t);
2370 					maximize_adjust_offset(t);
2371 				}
2372 			}
2373 			/* domivogt (1-Mar-2000): The next block is a hack to
2374 			 * prevent animation if the window has an icon, but
2375 			 * neither a pixmap nor a title. */
2376 			if (HAS_NO_ICON_TITLE(t) && FW_W_ICON_PIXMAP(t) == None)
2377 			{
2378 				memset(&fw->icon_g, 0, sizeof(fw->icon_g));
2379 			}
2380 			get_icon_geometry(t, &icon_rect);
2381 			/* if this fails it does not overwrite icon_rect */
2382 			EWMH_GetIconGeometry(t, &icon_rect);
2383 			if (t == fw)
2384 			{
2385 				BroadcastPacket(
2386 					M_DEICONIFY, 11, (long)FW_W(t),
2387 					(long)FW_W_FRAME(t), (unsigned long)t,
2388 					(long)icon_rect.x, (long)icon_rect.y,
2389 					(long)icon_rect.width,
2390 					(long)icon_rect.height,
2391 					(long)t->g.frame.x,
2392 					(long)t->g.frame.y,
2393 					(long)t->g.frame.width,
2394 					(long)t->g.frame.height);
2395 			}
2396 			else
2397 			{
2398 				BroadcastPacket(
2399 					M_DEICONIFY, 7, (long)FW_W(t),
2400 					(long)FW_W_FRAME(t),
2401 					(unsigned long)t, (long)icon_rect.x,
2402 					(long)icon_rect.y,
2403 					(long)icon_rect.width,
2404 					(long)icon_rect.height);
2405 			}
2406 			XMapWindow(dpy, FW_W_PARENT(t));
2407 			if (t->Desk == t->m->virtual_scr.CurrentDesk)
2408 			{
2409 				XMapWindow(dpy, FW_W_FRAME(t));
2410 				SET_MAP_PENDING(t, 1);
2411 			}
2412 			SetMapStateProp(t, NormalState);
2413 			SET_ICONIFIED(t, 0);
2414 			SET_ICON_UNMAPPED(t, 0);
2415 			SET_ICON_ENTERED(t, 0);
2416 			/* Need to make sure the border is colored correctly,
2417 			 * in case it was stuck or unstuck while iconified. */
2418 			tmp = Scr.Hilite;
2419 			Scr.Hilite = t;
2420 			border_draw_decorations(
2421 				t, PART_ALL, (sf == t) ? True : False, True,
2422 				CLEAR_ALL, NULL, NULL);
2423 			Scr.Hilite = tmp;
2424 		}
2425 	}
2426 
2427 #if 1
2428 	RaiseWindow(fw, False); /* moved dje */
2429 #endif
2430 	if (sf == fw)
2431 	{
2432 		/* update the focus to make sure the application knows its
2433 		 * state */
2434 		if (!FP_DO_UNFOCUS_LEAVE(FW_FOCUS_POLICY(fw)))
2435 		{
2436 			SetFocusWindow(fw, True, FOCUS_SET_FORCE);
2437 		}
2438 	}
2439 	else if (FP_DO_SORT_WINDOWLIST_BY(FW_FOCUS_POLICY(fw)) ==
2440 		 FPOL_SORT_WL_BY_OPEN)
2441 	{
2442 		SetFocusWindow(fw, True, FOCUS_SET_FORCE);
2443 	}
2444 	focus_grab_buttons_on_layer(fw->layer);
2445 
2446 	return;
2447 }
2448 
2449 
2450 /*
2451  *
2452  * Iconifies the selected window
2453  *
2454  */
Iconify(FvwmWindow * fw,initial_window_options_t * win_opts)2455 void Iconify(FvwmWindow *fw, initial_window_options_t *win_opts)
2456 {
2457 	FvwmWindow *t;
2458 	FvwmWindow *sf;
2459 	XWindowAttributes winattrs = {0};
2460 	unsigned long eventMask;
2461 	rectangle icon_rect;
2462 
2463 	if (!fw)
2464 	{
2465 		return;
2466 	}
2467 	if (!XGetWindowAttributes(dpy, FW_W(fw), &winattrs))
2468 	{
2469 		return;
2470 	}
2471 
2472 	/* make sure fw->flags.is_map_pending is OK */
2473 	if ((winattrs.map_state == IsViewable) && IS_MAP_PENDING(fw))
2474 	{
2475 		SET_MAP_PENDING(fw, 0);
2476 	}
2477 
2478 	if (IS_MAP_PENDING(fw))
2479 	{
2480 		/* final state: iconified */
2481 		SET_ICONIFY_AFTER_MAP(fw, 1);
2482 		return;
2483 	}
2484 	eventMask = winattrs.your_event_mask;
2485 
2486 	mark_transient_subtree(fw, MARK_ALL_LAYERS, MARK_ALL, False, True);
2487 	sf = get_focus_window();
2488 	if (sf && IS_IN_TRANSIENT_SUBTREE(sf))
2489 	{
2490 		restore_focus_after_unmap(sf, True);
2491 		/* restore_focus_after_unmap() destorys the flags set by
2492 		 * mark_transient_subtree(), so we have to unfortunately call
2493 		 * it again. */
2494 		mark_transient_subtree(
2495 			fw, MARK_ALL_LAYERS, MARK_ALL, False, True);
2496 	}
2497 	/* iconify transients first */
2498 	for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
2499 	{
2500 		if (t == fw || IS_IN_TRANSIENT_SUBTREE(t))
2501 		{
2502 			SET_IN_TRANSIENT_SUBTREE(t, 0);
2503 			SET_ICON_ENTERED(t, 0);
2504 			/* Prevent the receipt of an UnmapNotify, since that
2505 			 * would cause a transition to the Withdrawn state. */
2506 			SET_MAPPED(t, 0);
2507 			XSelectInput(
2508 				dpy, FW_W(t), eventMask & ~StructureNotifyMask);
2509 			XUnmapWindow(dpy, FW_W(t));
2510 			XSelectInput(dpy, FW_W(t), eventMask);
2511 			XUnmapWindow(dpy, FW_W_FRAME(t));
2512 			border_undraw_decorations(t);
2513 			t->DeIconifyDesk = t->Desk;
2514 			if (FW_W_ICON_TITLE(t))
2515 			{
2516 				XUnmapWindow(dpy, FW_W_ICON_TITLE(t));
2517 			}
2518 			if (FW_W_ICON_PIXMAP(t))
2519 			{
2520 				XUnmapWindow(dpy, FW_W_ICON_PIXMAP(t));
2521 			}
2522 
2523 			SetMapStateProp(t, IconicState);
2524 			border_draw_decorations(
2525 				t, PART_ALL, False, False, CLEAR_ALL, NULL,
2526 				NULL);
2527 			if (t == fw && !IS_ICONIFIED_BY_PARENT(fw))
2528 			{
2529 				SET_ICONIFY_PENDING(t, 1);
2530 			}
2531 			else
2532 			{
2533 				rectangle g;
2534 
2535 				SET_ICONIFIED(t, 1);
2536 				SET_ICON_UNMAPPED(t, 1);
2537 				SET_ICONIFIED_BY_PARENT(t, 1);
2538 				get_icon_geometry(t, &g);
2539 				BroadcastPacket(
2540 					M_ICONIFY, 7, (long)FW_W(t),
2541 					(long)FW_W_FRAME(t),
2542 					(unsigned long)t, (long)-32768,
2543 					(long)-32768, (long)g.width,
2544 					(long)g.height);
2545 				BroadcastConfig(M_CONFIGURE_WINDOW,t);
2546 			}
2547 		} /* if */
2548 	} /* for */
2549 
2550 	/* necessary during a recapture */
2551 	if (IS_ICONIFIED_BY_PARENT(fw))
2552 	{
2553 		return;
2554 	}
2555 
2556 	if (FW_W_ICON_TITLE(fw) == None || HAS_ICON_CHANGED(fw))
2557 	{
2558 		if (IS_ICON_MOVED(fw) || win_opts->flags.use_initial_icon_xy)
2559 		{
2560 			rectangle g;
2561 
2562 			get_icon_geometry(fw, &g);
2563 			if (win_opts->flags.use_initial_icon_xy)
2564 			{
2565 				g.x = win_opts->initial_icon_x;
2566 				g.y = win_opts->initial_icon_y;
2567 			}
2568 			CreateIconWindow(fw, g.x, g.y);
2569 		}
2570 		else
2571 		{
2572 			CreateIconWindow(
2573 				fw, win_opts->default_icon_x,
2574 				win_opts->default_icon_y);
2575 		}
2576 		SET_HAS_ICON_CHANGED(fw, 0);
2577 	}
2578 	else if (FW_W_ICON_TITLE(fw) && !FW_W_ICON_PIXMAP(fw))
2579 	{
2580 		/* if no pixmap we want icon width to change to text width
2581 		 * every iconify; not necessary if the icon was created above */
2582 		setup_icon_title_size(fw);
2583 	}
2584 
2585 	/* this condition will be true unless we restore a window to
2586 	 * iconified state from a saved session. */
2587 	if (win_opts->initial_state != IconicState ||
2588 	    (!IS_ICON_MOVED(fw) && !win_opts->flags.use_initial_icon_xy))
2589 	{
2590 		AutoPlaceIcon(fw, win_opts, True);
2591 	}
2592 	/* domivogt (12-Mar-2003): Clean out the icon geometry if there is no
2593 	 * icon.  Necessary to initialise the values and to suppress animation
2594 	 * if there is no icon. */
2595 	if (HAS_NO_ICON_TITLE(fw) && FW_W_ICON_PIXMAP(fw) == None)
2596 	{
2597 		clear_icon_dimensions(fw);
2598 	}
2599 	SET_ICONIFIED(fw, 1);
2600 	SET_ICON_UNMAPPED(fw, 0);
2601 	get_icon_geometry(fw, &icon_rect);
2602 	/* if this fails it does not overwrite icon_rect */
2603 	EWMH_GetIconGeometry(fw, &icon_rect);
2604 	BroadcastPacket(
2605 		M_ICONIFY, 11, (long)FW_W(fw), (long)FW_W_FRAME(fw),
2606 		(unsigned long)fw, (long)icon_rect.x, (long)icon_rect.y,
2607 		(long)icon_rect.width, (long)icon_rect.height,
2608 		/* next 4 added for Animate module */
2609 		(long)fw->g.frame.x, (long)fw->g.frame.y,
2610 		(long)fw->g.frame.width, (long)fw->g.frame.height);
2611 	BroadcastConfig(M_CONFIGURE_WINDOW,fw);
2612 
2613 	if (win_opts->initial_state != IconicState ||
2614 	    (!IS_ICON_MOVED(fw) && !win_opts->flags.use_initial_icon_xy))
2615 	{
2616 		LowerWindow(fw, False);
2617 	}
2618 	if (IS_ICON_STICKY_ACROSS_DESKS(fw) || IS_STICKY_ACROSS_DESKS(fw))
2619 	{
2620 		fw->Desk = fw->m->virtual_scr.CurrentDesk;
2621 	}
2622 	if (fw->Desk == fw->m->virtual_scr.CurrentDesk)
2623 	{
2624 		if (FW_W_ICON_TITLE(fw) != None)
2625 		{
2626 			XMapWindow(dpy, FW_W_ICON_TITLE(fw));
2627 		}
2628 		if (FW_W_ICON_PIXMAP(fw) != None)
2629 		{
2630 			XMapWindow(dpy, FW_W_ICON_PIXMAP(fw));
2631 		}
2632 	}
2633 	focus_grab_buttons_on_layer(fw->layer);
2634 
2635 	return;
2636 }
2637 
2638 /*
2639  *
2640  * This is used to tell applications which windows on the screen are
2641  * top level appication windows, and which windows are the icon windows
2642  * that go with them.
2643  *
2644  */
SetMapStateProp(const FvwmWindow * fw,int state)2645 void SetMapStateProp(const FvwmWindow *fw, int state)
2646 {
2647 	/* "suggested" by ICCCM version 1 */
2648 	unsigned long data[2];
2649 
2650 	data[0] = (unsigned long) state;
2651 	data[1] = (unsigned long) FW_W_ICON_TITLE(fw);
2652 	/*  data[2] = (unsigned long) FW_W_ICON_PIXMAP(fw);*/
2653 
2654 	XChangeProperty(
2655 		dpy, FW_W(fw), _XA_WM_STATE, _XA_WM_STATE, 32, PropModeReplace,
2656 		(unsigned char *) data, 2);
2657 
2658 	return;
2659 }
2660 
CMD_Iconify(F_CMD_ARGS)2661 void CMD_Iconify(F_CMD_ARGS)
2662 {
2663 	int toggle;
2664 	FvwmWindow * const fw = exc->w.fw;
2665 
2666 	toggle = ParseToggleArgument(action, NULL, -1, 0);
2667 	if (toggle == -1)
2668 	{
2669 		if (GetIntegerArguments(action, NULL, &toggle, 1) > 0)
2670 		{
2671 			if (toggle > 0)
2672 			{
2673 				toggle = 1;
2674 			}
2675 			else if (toggle < 0)
2676 			{
2677 				toggle = 0;
2678 			}
2679 			else
2680 			{
2681 				toggle = -1;
2682 			}
2683 		}
2684 	}
2685 	if (toggle == -1)
2686 	{
2687 		toggle = (IS_ICONIFIED(fw)) ? 0 : 1;
2688 	}
2689 
2690 	if (IS_ICONIFIED(fw))
2691 	{
2692 		if (toggle == 0)
2693 		{
2694 			DeIconify(fw);
2695 			EWMH_SetWMState(fw, False);
2696 		}
2697 	}
2698 	else
2699 	{
2700 		if (toggle == 1)
2701 		{
2702 			initial_window_options_t win_opts;
2703 
2704 			if (
2705 				!is_function_allowed(
2706 					F_ICONIFY, NULL, fw, RQORIG_PROGRAM,
2707 					True))
2708 			{
2709 				XBell(dpy, 0);
2710 
2711 				return;
2712 			}
2713 			memset(&win_opts, 0, sizeof(win_opts));
2714 			fev_get_evpos_or_query(
2715 				dpy, Scr.Root, NULL, &win_opts.default_icon_x,
2716 				&win_opts.default_icon_y);
2717 			Iconify(fw, &win_opts);
2718 			EWMH_SetWMState(fw, False);
2719 		}
2720 	}
2721 
2722 	return;
2723 }
2724