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/FScreen.h"
31 #include "libs/FShape.h"
32 #include "libs/Parse.h"
33 #include "libs/Picture.h"
34 #include "libs/Graphics.h"
35 #include "libs/PictureGraphics.h"
36 #include "libs/FRenderInit.h"
37 #include "libs/Rectangles.c"
38 #include "libs/charmap.h"
39 #include "libs/wcontext.h"
40 #include "fvwm.h"
41 #include "externs.h"
42 #include "cursor.h"
43 #include "execcontext.h"
44 #include "commands.h"
45 #include "bindings.h"
46 #include "events.h"
47 #include "eventmask.h"
48 #include "eventhandler.h"
49 #include "misc.h"
50 #include "screen.h"
51 #include "icons.h"
52 #include "borders.h"
53 #include "frame.h"
54 #include "focus.h"
55 #include "colormaps.h"
56 #include "stack.h"
57 #include "virtual.h"
58 #include "decorations.h"
59 #include "module_interface.h"
60 #include "ewmh.h"
61 #include "geometry.h"
62 
63 static int do_all_iconboxes(FvwmWindow *t, icon_boxes **icon_boxes_ptr);
64 static void GetIconFromFile(FvwmWindow *fw);
65 static void GetIconWindow(FvwmWindow *fw);
66 static void GetIconBitmap(FvwmWindow *fw);
67 
clear_icon_dimensions(FvwmWindow * fw)68 static void clear_icon_dimensions(FvwmWindow *fw)
69 {
70 	int px;
71 	int py;
72 	int tx;
73 	int ty;
74 
75 	px = fw->icon_g.picture_w_g.x;
76 	py = fw->icon_g.picture_w_g.y;
77 	tx = fw->icon_g.title_w_g.x;
78 	ty = fw->icon_g.title_w_g.y;
79 	memset(&fw->icon_g, 0, sizeof(fw->icon_g));
80 	fw->icon_g.picture_w_g.x = px;
81 	fw->icon_g.picture_w_g.y = py;
82 	fw->icon_g.title_w_g.x = tx;
83 	fw->icon_g.title_w_g.y = ty;
84 
85 	return;
86 }
87 /* erase all traces of the last used icon in the window structure */
clear_icon(FvwmWindow * fw)88 void clear_icon(FvwmWindow *fw)
89 {
90 	FW_W_ICON_PIXMAP(fw) = None;
91 	fw->iconPixmap = None;
92 	fw->icon_maskPixmap = None;
93 	fw->icon_alphaPixmap = None;
94 	fw->icon_nalloc_pixels = 0;
95 	fw->icon_alloc_pixels = NULL;
96 	fw->icon_no_limit = 0;
97 	if (IS_ICON_MOVED(fw))
98 	{
99 		clear_icon_dimensions(fw);
100 	}
101 	else
102 	{
103 		memset(&fw->icon_g, 0, sizeof(fw->icon_g));
104 	}
105 
106 	return;
107 }
108 
get_visible_icon_window_count(FvwmWindow * fw)109 int get_visible_icon_window_count(FvwmWindow *fw)
110 {
111 	int count = 0;
112 
113 	if (fw == NULL || !IS_ICONIFIED(fw) ||
114 	    IS_ICON_SUPPRESSED(fw))
115 	{
116 		return 0;
117 	}
118 	if (FW_W_ICON_PIXMAP(fw) != None)
119 	{
120 		count++;
121 	}
122 	if (FW_W_ICON_TITLE(fw) != None)
123 	{
124 		count++;
125 	}
126 
127 	return count;
128 }
129 
setup_icon_title_size(FvwmWindow * fw)130 void setup_icon_title_size(FvwmWindow *fw)
131 {
132 	if (HAS_NO_ICON_TITLE(fw))
133 	{
134 		fw->icon_g.title_text_width = 0;
135 		fw->icon_g.title_w_g.width = 0;
136 		fw->icon_g.title_w_g.height = 0;
137 	}
138 	else
139 	{
140 		fw->icon_g.title_text_width =
141 			FlocaleTextWidth(
142 				fw->icon_font, fw->visible_icon_name,
143 				strlen(fw->visible_icon_name));
144 		fw->icon_g.title_w_g.height = ICON_HEIGHT(fw);
145 		if (fw->icon_g.picture_w_g.width == 0)
146 		{
147 			fw->icon_g.title_w_g.width =
148 				fw->icon_g.title_text_width +
149 				2 * (ICON_TITLE_TEXT_GAP_COLLAPSED +
150 				     abs(fw->icon_title_relief));
151 			if (IS_STICKY_ACROSS_PAGES(fw) ||
152 			    IS_ICON_STICKY_ACROSS_PAGES(fw) ||
153 			    IS_STICKY_ACROSS_DESKS(fw) ||
154 			    IS_ICON_STICKY_ACROSS_DESKS(fw))
155 			{
156 				fw->icon_g.title_w_g.width +=
157 					2 * (ICON_TITLE_TO_STICK_EXTRA_GAP +
158 					     ICON_TITLE_STICK_MIN_WIDTH);
159 			}
160 		}
161 		else
162 		{
163 			fw->icon_g.title_w_g.width =
164 				fw->icon_g.picture_w_g.width;
165 		}
166 	}
167 
168 	return;
169 }
170 
171 /*
172  *
173  * Resizes the given icon Pixmap.
174  *
175  */
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)176 static void SetIconPixmapSize(
177 	Pixmap *icon, int width, int height, int depth, int newWidth,
178 	int newHeight, Bool force_centering, int resize_type, int *nrx,
179 	int *nry, int freeOldPixmap)
180 {
181 	Pixmap oldPixmap;
182 	Pixmap resizedPixmap = None;
183 	int r_w,r_h;
184 	GC gc;
185 	XGCValues gc_init;
186 
187 	*nrx = 0;
188 	*nry = 0;
189 
190 	/* Check for invalid dimensions */
191 	if (newWidth == 0 || newHeight == 0)
192 	{
193 		return;
194 	}
195 
196 	/* Save the existing Pixmap */
197 	oldPixmap = *icon;
198 
199 	gc = XCreateGC(dpy, oldPixmap, 0, &gc_init);
200 
201 	switch(resize_type)
202 	{
203 	case ICON_RESIZE_TYPE_ADJUSTED:
204 		if (newWidth != width || newHeight != height)
205 		{
206 			*icon = CreateStretchPixmap(
207 				dpy, oldPixmap, width, height, depth, newWidth,
208 				newHeight, gc);
209 		}
210 		break;
211 	case ICON_RESIZE_TYPE_STRETCHED:
212 		if (width < newWidth || height < newHeight)
213 		{
214 			r_w = max(newWidth, width);
215 			r_h = max(newHeight, height);
216 			resizedPixmap = CreateStretchPixmap(
217 				dpy, oldPixmap, width, height, depth, r_w, r_h,
218 				gc);
219 			width = r_w;
220 			height = r_h;
221 		}
222 		break;
223 	case ICON_RESIZE_TYPE_SHRUNK:
224 		if (width > newWidth || height > newHeight)
225 		{
226 			r_w = min(newWidth, width);
227 			r_h = min(newHeight, height);
228 			resizedPixmap = CreateStretchPixmap(
229 				dpy, oldPixmap, width, height, depth, r_w, r_h,
230 				gc);
231 			width = r_w;
232 			height = r_h;
233 		}
234 		break;
235 	default:
236 		break;
237 	}
238 
239 	if (resize_type != ICON_RESIZE_TYPE_ADJUSTED)
240 	{
241 		*icon = XCreatePixmap(
242 			dpy, oldPixmap, newWidth, newHeight, depth);
243 		XSetForeground(dpy, gc, 0);
244 		XFillRectangle(dpy, *icon, gc, 0, 0, newWidth, newHeight);
245 
246 		/*
247 		 * Copy old Pixmap onto new.  Center horizontally.  Center
248 		 * vertically if the new height is smaller than the old.
249 		 * Otherwise, place the icon on the bottom, along the title bar.
250 		 */
251 		*nrx = (newWidth - width) / 2;
252 		*nry = (newHeight > height && !force_centering) ?
253 			newHeight - height : (newHeight - height) / 2;
254 		XCopyArea(
255 			dpy, (resizedPixmap)? resizedPixmap:oldPixmap, *icon,
256 			gc, 0, 0, width, height, *nrx, *nry);
257 	}
258 
259 	XFreeGC(dpy, gc);
260 
261 	if (freeOldPixmap)
262 	{
263 		XFreePixmap(dpy, oldPixmap);
264 	}
265 }
266 
267 /* Move the icon of a window by dx/dy pixels */
268 /*
269  *
270  * Get the Icon for the icon window (also used by ewmh_icon)
271  *
272  */
GetIconPicture(FvwmWindow * fw,Bool no_icon_window)273 void GetIconPicture(FvwmWindow *fw, Bool no_icon_window)
274 {
275 	char icon_order[4];
276 	int i;
277 
278 	/* First, see if it was specified in the .fvwmrc */
279 	if (ICON_OVERRIDE_MODE(fw) == ICON_OVERRIDE)
280 	{
281 		/* try fvwm provided icons before application provided icons */
282 		icon_order[0] = 0;
283 		icon_order[1] = 1;
284 		icon_order[2] = 2;
285 		icon_order[3] = 3;
286 ICON_DBG((stderr,"ciw: hint order: file iwh iph '%s'\n", fw->name.name));
287 	}
288 	else if (ICON_OVERRIDE_MODE(fw) == NO_ACTIVE_ICON_OVERRIDE)
289 	{
290 		if (fw->wmhints && (fw->wmhints->flags & IconPixmapHint) &&
291 		    WAS_ICON_HINT_PROVIDED(fw) == ICON_HINT_MULTIPLE)
292 		{
293 			/* use application provided icon window or pixmap
294 			 * first, then fvwm provided icons. */
295 			icon_order[0] = 1;
296 			icon_order[1] = 2;
297 			icon_order[2] = 3;
298 			icon_order[3] = 0;
299 ICON_DBG((stderr,"ciw: hint order: iwh iph file '%s'\n", fw->name.name));
300 		}
301 		else if (Scr.DefaultIcon &&
302 			 fw->icon_bitmap_file == Scr.DefaultIcon)
303 		{
304 			/* use application provided icon window/pixmap first,
305 			 * then fvwm provided default icon */
306 			icon_order[0] = 1;
307 			icon_order[1] = 2;
308 			icon_order[2] = 3;
309 			icon_order[3] = 0;
310 ICON_DBG((stderr,"ciw: hint order: iwh iph file '%s'\n", fw->name.name));
311 		}
312 		else
313 		{
314 			/* use application provided icon window or ewmh icon
315 			 * first, then fvwm provided icons and then application
316 			 * provided icon pixmap */
317 			icon_order[0] = 1;
318 			icon_order[1] = 2;
319 			icon_order[2] = 0;
320 			icon_order[3] = 3;
321 ICON_DBG((stderr,"ciw: hint order: iwh file iph '%s'\n", fw->name.name));
322 		}
323 	}
324 	else
325 	{
326 		/* use application provided icon rather than fvwm provided
327 		 * icon */
328 		icon_order[0] = 1;
329 		icon_order[1] = 2;
330 		icon_order[2] = 3;
331 		icon_order[3] = 0;
332 ICON_DBG((stderr,"ciw: hint order: iwh iph file '%s'\n", fw->name.name));
333 	}
334 
335 	fw->icon_g.picture_w_g.width = 0;
336 	fw->icon_g.picture_w_g.height = 0;
337 	fw->iconPixmap = None;
338 	fw->icon_maskPixmap = None;
339 	fw->icon_alphaPixmap= None;
340 	FW_W_ICON_PIXMAP(fw) = None;
341 	for (i = 0; i < 4 && fw->icon_g.picture_w_g.width == 0 &&
342 		     fw->icon_g.picture_w_g.height == 0; i++)
343 	{
344 		switch (icon_order[i])
345 		{
346 		case 0:
347 			/* Next, check for a color pixmap */
348 			if (fw->icon_bitmap_file)
349 			{
350 				GetIconFromFile(fw);
351 			}
352 ICON_DBG((stderr,"ciw: file%s used '%s'\n",
353 	  (fw->icon_g.picture_w_g.height)?"":" not", fw->name.name));
354 			break;
355 		case 1:
356 			/* Next, See if the app supplies its own icon window */
357 			if (no_icon_window)
358 			{
359 				break;
360 			}
361 			if (fw->wmhints &&
362 			    (fw->wmhints->flags & IconWindowHint))
363 			{
364 				GetIconWindow(fw);
365 			}
366 ICON_DBG((stderr,"ciw: iwh%s used '%s'\n",
367 	  (fw->icon_g.picture_w_g.height)?"":" not",fw->name.name));
368 			break;
369 		case 2:
370 			/* try an ewmh icon */
371 			if (HAS_EWMH_WM_ICON_HINT(fw) == EWMH_TRUE_ICON)
372 			{
373 				if (EWMH_SetIconFromWMIcon(fw, NULL, 0, False))
374 				{
375 					SET_USE_EWMH_ICON(fw, True);
376 				}
377 			}
378 ICON_DBG((stderr,"ciw: inh%s used '%s'\n",
379 	  (fw->icon_g.picture_w_g.height)?"":" not",fw->name.name));
380 			break;
381 		case 3:
382 			/* Finally, try to get icon bitmap from the
383 			 * application */
384 			if (fw->wmhints &&
385 			    (fw->wmhints->flags & IconPixmapHint))
386 			{
387 				GetIconBitmap(fw);
388 			}
389 ICON_DBG((stderr,"ciw: iph%s used '%s'\n",
390 	  (fw->icon_g.picture_w_g.height)?"":" not",fw->name.name));
391 			break;
392 		default:
393 			/* can't happen */
394 			break;
395 		}
396 	}
397 
398 	/* Resize icon if necessary */
399 	if ((IS_ICON_OURS(fw)) && fw->icon_g.picture_w_g.height > 0 &&
400 	    fw->icon_g.picture_w_g.height > 0)
401 	{
402 		int newWidth = fw->icon_g.picture_w_g.width;
403 		int newHeight = fw->icon_g.picture_w_g.height;
404 		Boolean resize = False;
405 
406 		if (newWidth < fw->min_icon_width)
407 		{
408 			newWidth = fw->min_icon_width;
409 			resize = True;
410 		}
411 		else
412 		{
413 			if (newWidth > fw->max_icon_width)
414 			{
415 				newWidth = fw->max_icon_width;
416 				resize = True;
417 			}
418 		}
419 		if (newHeight < fw->min_icon_height)
420 		{
421 			newHeight = fw->min_icon_height;
422 			resize = True;
423 		}
424 		else
425 		{
426 			if (newHeight > fw->max_icon_height)
427 			{
428 				newHeight = fw->max_icon_height;
429 				resize = True;
430 			}
431 		}
432 		if (resize)
433 		{
434 			/* Resize the icon Pixmap */
435 			int force_centering = False;
436 			int nrx, nry;
437 
438 			ICON_DBG((stderr,
439 				  "ciw: Changing icon (%s) from %dx%d to"
440 				  " %dx%d\n", fw->name.name,
441 				  fw->icon_g.picture_w_g.width,
442 				  fw->icon_g.picture_w_g.height,
443 				  newWidth, newHeight));
444 			/* Resize the icon Pixmap */
445 			/* force to center if the icon has a bg */
446 			if (fw->icon_background_cs >= 0 ||
447 			    fw->icon_maskPixmap == None)
448 			{
449 				force_centering = True;
450 			}
451 			SetIconPixmapSize(
452 				&(fw->iconPixmap),
453 				fw->icon_g.picture_w_g.width,
454 				fw->icon_g.picture_w_g.height, fw->iconDepth,
455 				newWidth, newHeight, force_centering,
456 				fw->icon_resize_type, &nrx, &nry,
457 				IS_PIXMAP_OURS(fw));
458 
459 			/* Resize the icon mask Pixmap if one was defined */
460 			if (fw->icon_maskPixmap)
461 			{
462 				SetIconPixmapSize(
463 					&(fw->icon_maskPixmap),
464 					fw->icon_g.picture_w_g.width,
465 					fw->icon_g.picture_w_g.height, 1,
466 					newWidth, newHeight, force_centering,
467 					fw->icon_resize_type, &nrx, &nry,
468 					IS_PIXMAP_OURS(fw));
469 			}
470 			else if ((nrx > 0 || nry > 0) && fw->iconDepth > 1)
471 			{
472 				fw->icon_maskPixmap = XCreatePixmap(
473 					dpy, fw->iconPixmap,
474 					newWidth, newHeight, 1);
475 				XSetForeground(dpy, Scr.MonoGC, 0);
476 				XFillRectangle(
477 					dpy, fw->icon_maskPixmap, Scr.MonoGC,
478 					0, 0, newWidth, newHeight);
479 				XSetForeground(dpy, Scr.MonoGC, 1);
480 				XFillRectangle(
481 					dpy, fw->icon_maskPixmap, Scr.MonoGC,
482 					nrx, nry, fw->icon_g.picture_w_g.width,
483 					fw->icon_g.picture_w_g.height);
484 				XSetForeground(dpy, Scr.MonoGC, 0);
485 				/* set it shaped ? YES */
486 				SET_ICON_SHAPED(fw, 1);
487 			}
488 
489 			/* Resize the icon alpha Pixmap if one was defined */
490 			if (fw->icon_alphaPixmap)
491 			{
492 				SetIconPixmapSize(
493 					&(fw->icon_alphaPixmap),
494 					fw->icon_g.picture_w_g.width,
495 					fw->icon_g.picture_w_g.height,
496 					FRenderGetAlphaDepth(), newWidth,
497 					newHeight, force_centering,
498 					fw->icon_resize_type, &nrx, &nry,
499 					IS_PIXMAP_OURS(fw));
500 			}
501 
502 			/* Set the new dimensions of the icon window */
503 			fw->icon_g.picture_w_g.width = newWidth;
504 			fw->icon_g.picture_w_g.height = newHeight;
505 		}
506 	}
507 
508 	return;
509 }
510 
511 /*
512  *
513  * set the icon pixmap window background
514  *
515  */
set_icon_pixmap_background(FvwmWindow * fw)516 static void set_icon_pixmap_background(FvwmWindow *fw)
517 {
518 	if (fw->iconPixmap != None &&
519 	    (Pdefault || fw->iconDepth == 1 || fw->iconDepth == Pdepth ||
520 	     IS_PIXMAP_OURS(fw)))
521 	{
522 		if (fw->icon_background_cs >= 0)
523 		{
524 			SetWindowBackground(
525 				dpy, FW_W_ICON_PIXMAP(fw),
526 				fw->icon_g.picture_w_g.width,
527 				fw->icon_g.picture_w_g.height,
528 				&Colorset[fw->icon_background_cs],
529 				Pdepth, Scr.StdGC, False);
530 		}
531 		else if (FShapesSupported &&
532 			 Pdepth == DefaultDepth(dpy, (DefaultScreen(dpy))))
533 		{
534 			XSetWindowBackgroundPixmap(
535 				dpy, FW_W_ICON_PIXMAP(fw), ParentRelative);
536 		}
537 		else if (Scr.DefaultColorset >= 0)
538 		{
539 			SetWindowBackground(
540 				dpy, FW_W_ICON_PIXMAP(fw),
541 				fw->icon_g.picture_w_g.width,
542 				fw->icon_g.picture_w_g.height,
543 				&Colorset[Scr.DefaultColorset], Pdepth,
544 				Scr.StdGC, False);
545 		}
546 	}
547 }
548 
549 /*
550  *
551  * Creates an icon window as needed
552  *
553  */
CreateIconWindow(FvwmWindow * fw,int def_x,int def_y)554 void CreateIconWindow(FvwmWindow *fw, int def_x, int def_y)
555 {
556 	/* mask for create windows */
557 	unsigned long valuemask;
558 	/* attributes for create windows */
559 	XSetWindowAttributes attributes;
560 	XWindowChanges xwc;
561 	Window old_icon_pixmap_w;
562 	Window old_icon_w;
563 	Bool is_old_icon_shaped = IS_ICON_SHAPED(fw);
564 
565 	old_icon_w = FW_W_ICON_TITLE(fw);
566 	old_icon_pixmap_w = (IS_ICON_OURS(fw)) ? FW_W_ICON_PIXMAP(fw) : None;
567 	if (!IS_ICON_OURS(fw) && FW_W_ICON_PIXMAP(fw))
568 	{
569 		XUnmapWindow(dpy, FW_W_ICON_PIXMAP(fw));
570 	}
571 	SET_ICON_OURS(fw, 1);
572 	SET_PIXMAP_OURS(fw, 0);
573 	SET_ICON_SHAPED(fw, 0);
574 	FW_W_ICON_PIXMAP(fw) = None;
575 	fw->iconPixmap = None;
576 	fw->iconDepth = 0;
577 
578 	if (IS_ICON_SUPPRESSED(fw))
579 	{
580 		return;
581 	}
582 
583 	/*
584 	 * set up the icon picture
585 	 */
586 	GetIconPicture(fw, False);
587 	/* make space for relief to be drawn outside the icon */
588 	/* this does not happen if fvwm is using a non-default visual (with
589 	 * private colormap) and the client has supplied a pixmap (not a
590 	 * bitmap) */
591 	if ((IS_ICON_OURS(fw)) && (fw->icon_g.picture_w_g.height > 0)
592 	    && (Pdefault || fw->iconDepth == 1 || fw->iconDepth == Pdepth ||
593 		IS_PIXMAP_OURS(fw)))
594 	{
595 		fw->icon_g.picture_w_g.width +=
596 			2 * abs(fw->icon_background_relief)
597 			+ 2 * fw->icon_background_padding;
598 		fw->icon_g.picture_w_g.height +=
599 			2 * abs(fw->icon_background_relief)
600 			+ 2 * fw->icon_background_padding;
601 	}
602 
603 	/*
604 	 * set up the icon title geometry
605 	 */
606 	setup_icon_title_size(fw);
607 
608 	/*
609 	 * set up icon position
610 	 */
611 	set_icon_position(fw, def_x, def_y);
612 
613 	/*
614 	 * create the icon title window
615 	 */
616 	valuemask = CWColormap | CWBorderPixel | CWBackPixel | CWCursor |
617 		CWEventMask;
618 	attributes.colormap = Pcmap;
619 	attributes.background_pixel = Scr.StdBack;
620 	attributes.cursor = Scr.FvwmCursors[CRS_DEFAULT];
621 	attributes.border_pixel = 0;
622 	attributes.event_mask = XEVMASK_ICONW;
623 	if (HAS_NO_ICON_TITLE(fw))
624 	{
625 		if (FW_W_ICON_TITLE(fw))
626 		{
627 			XDeleteContext(dpy, FW_W_ICON_TITLE(fw), FvwmContext);
628 			XDestroyWindow(dpy, FW_W_ICON_TITLE(fw));
629 			XFlush(dpy);
630 			FW_W_ICON_TITLE(fw) = None;
631 		}
632 	}
633 	else
634 	{
635 		if (FW_W_ICON_TITLE(fw) == None)
636 		{
637 			FW_W_ICON_TITLE(fw) = XCreateWindow(
638 				dpy, Scr.Root, fw->icon_g.title_w_g.x,
639 				fw->icon_g.title_w_g.y,
640 				fw->icon_g.title_w_g.width,
641 				fw->icon_g.title_w_g.height, 0, Pdepth,
642 				InputOutput, Pvisual, valuemask, &attributes);
643 		}
644 		else
645 		{
646 			XMoveResizeWindow(
647 				dpy, FW_W_ICON_TITLE(fw),
648 				fw->icon_g.title_w_g.x, fw->icon_g.title_w_g.y,
649 				fw->icon_g.title_w_g.width,
650 				fw->icon_g.title_w_g.height);
651 		}
652 	}
653 	if (Scr.DefaultColorset >= 0)
654 	{
655 		SetWindowBackground(
656 			dpy, FW_W_ICON_TITLE(fw), fw->icon_g.title_w_g.width,
657 			fw->icon_g.title_w_g.height,
658 			&Colorset[Scr.DefaultColorset], Pdepth, Scr.StdGC,
659 			False);
660 	}
661 
662 	/*
663 	 * create the icon picture window
664 	 */
665 	if (IS_ICON_OURS(fw) && fw->icon_g.picture_w_g.width > 0 &&
666 	    fw->icon_g.picture_w_g.height > 0)
667 	{
668 		/* use fvwm's visuals in these cases */
669 		if (Pdefault || fw->iconDepth == 1 || fw->iconDepth == Pdepth ||
670 		    IS_PIXMAP_OURS(fw))
671 		{
672 			if (!old_icon_pixmap_w)
673 			{
674 				FW_W_ICON_PIXMAP(fw) = XCreateWindow(
675 					dpy, Scr.Root, fw->icon_g.picture_w_g.x,
676 					fw->icon_g.picture_w_g.y,
677 					fw->icon_g.picture_w_g.width,
678 					fw->icon_g.picture_w_g.height, 0,
679 					Pdepth, InputOutput, Pvisual,
680 					valuemask, &attributes);
681 			}
682 			else
683 			{
684 				FW_W_ICON_PIXMAP(fw) = old_icon_pixmap_w;
685 				XMoveResizeWindow(
686 					dpy, FW_W_ICON_PIXMAP(fw),
687 					fw->icon_g.picture_w_g.x,
688 					fw->icon_g.picture_w_g.y,
689 					fw->icon_g.picture_w_g.width,
690 					fw->icon_g.picture_w_g.height);
691 			}
692 			set_icon_pixmap_background(fw);
693 		}
694 		else
695 		{
696 			/* client supplied icon pixmap and fvwm is using
697 			 * another visual.
698 			 * use it as the background pixmap, don't try to put
699 			 * relief on it because fvwm will not have the correct
700 			 * colors the Exceed server has problems maintaining
701 			 * the icon window, it usually fails to refresh the
702 			 * icon leaving it black so ask for expose events */
703 			attributes.background_pixmap = fw->iconPixmap;
704 			attributes.colormap = DefaultColormap(dpy, Scr.screen);
705 			valuemask &= ~CWBackPixel;
706 			valuemask |= CWBackPixmap;
707 			FW_W_ICON_PIXMAP(fw) = XCreateWindow(
708 				dpy, Scr.Root, fw->icon_g.picture_w_g.x,
709 				fw->icon_g.picture_w_g.y,
710 				fw->icon_g.picture_w_g.width,
711 				fw->icon_g.picture_w_g.height, 0,
712 				DefaultDepth(dpy, Scr.screen), InputOutput,
713 				DefaultVisual(dpy, Scr.screen), valuemask,
714 				&attributes);
715 		}
716 	}
717 	else if (FW_W_ICON_PIXMAP(fw) != None)
718 	{
719 		/* client supplied icon window: select events on it */
720 		attributes.event_mask = XEVMASK_ICONPW;
721 		valuemask = CWEventMask;
722 		XChangeWindowAttributes(
723 			dpy, FW_W_ICON_PIXMAP(fw), valuemask,&attributes);
724 		if (!IS_ICON_OURS(fw))
725 		{
726 			XMoveWindow(
727 				dpy, FW_W_ICON_PIXMAP(fw),
728 				fw->icon_g.picture_w_g.x,
729 				fw->icon_g.picture_w_g.y);
730 		}
731 	}
732 	if (old_icon_pixmap_w != None &&
733 	    old_icon_pixmap_w != FW_W_ICON_PIXMAP(fw))
734 	{
735 		/* destroy the old window */
736 		XDestroyWindow(dpy, old_icon_pixmap_w);
737 		XDeleteContext(dpy, old_icon_pixmap_w, FvwmContext);
738 		XFlush(dpy);
739 		is_old_icon_shaped = False;
740 	}
741 
742 	if (FShapesSupported)
743 	{
744 		if (IS_ICON_SHAPED(fw) && fw->icon_background_cs < 0)
745 		{
746 			/* when fvwm is using the non-default visual client
747 			 * supplied icon pixmaps are drawn in a window with no
748 			 * relief */
749 			int off = 0;
750 
751 			if (Pdefault || fw->iconDepth == 1 ||
752 			    fw->iconDepth == Pdepth || IS_PIXMAP_OURS(fw))
753 			{
754 				off = abs(fw->icon_background_relief) +
755 					fw->icon_background_padding;
756 			}
757 			SUPPRESS_UNUSED_VAR_WARNING(off);
758 			FShapeCombineMask(
759 				dpy, FW_W_ICON_PIXMAP(fw), FShapeBounding, off,
760 				off, fw->icon_maskPixmap, FShapeSet);
761 		}
762 		else if (is_old_icon_shaped &&
763 			 FW_W_ICON_PIXMAP(fw) == old_icon_pixmap_w)
764 		{
765 			/* remove the shape */
766 			XRectangle r;
767 
768 			r.x = 0;
769 			r.y = 0;
770 			r.width = fw->icon_g.picture_w_g.width;
771 			r.height = fw->icon_g.picture_w_g.height;
772 			SUPPRESS_UNUSED_VAR_WARNING(r);
773 			FShapeCombineRectangles(
774 				dpy, FW_W_ICON_PIXMAP(fw), FShapeBounding, 0,
775 				0, &r, 1, FShapeSet, 0);
776 		}
777 	}
778 
779 	if (FW_W_ICON_TITLE(fw) != None && FW_W_ICON_TITLE(fw) != old_icon_w)
780 	{
781 		XSaveContext(
782 			dpy, FW_W_ICON_TITLE(fw), FvwmContext, (caddr_t)fw);
783 		XDefineCursor(
784 			dpy, FW_W_ICON_TITLE(fw), Scr.FvwmCursors[CRS_DEFAULT]);
785 		GrabAllWindowKeysAndButtons(
786 			dpy, FW_W_ICON_TITLE(fw), Scr.AllBindings, C_ICON,
787 			GetUnusedModifiers(), Scr.FvwmCursors[CRS_DEFAULT],
788 			True);
789 		xwc.sibling = FW_W_FRAME(fw);
790 		xwc.stack_mode = Below;
791 		XConfigureWindow(
792 			dpy, FW_W_ICON_TITLE(fw), CWSibling|CWStackMode, &xwc);
793 	}
794 	if (FW_W_ICON_PIXMAP(fw) != None &&
795 	    FW_W_ICON_PIXMAP(fw) != old_icon_pixmap_w)
796 	{
797 		XSaveContext(
798 			dpy, FW_W_ICON_PIXMAP(fw), FvwmContext, (caddr_t)fw);
799 		XDefineCursor(
800 			dpy, FW_W_ICON_PIXMAP(fw),
801 			Scr.FvwmCursors[CRS_DEFAULT]);
802 		GrabAllWindowKeysAndButtons(
803 			dpy, FW_W_ICON_PIXMAP(fw), Scr.AllBindings, C_ICON,
804 			GetUnusedModifiers(), Scr.FvwmCursors[CRS_DEFAULT],
805 			True);
806 		xwc.sibling = FW_W_FRAME(fw);
807 		xwc.stack_mode = Below;
808 		XConfigureWindow(
809 			dpy,FW_W_ICON_PIXMAP(fw),CWSibling|CWStackMode,&xwc);
810 	}
811 
812 	return;
813 }
814 
815 /*
816  *
817  * Draws the icon window
818  *
819  */
820 static
DrawIconTitleWindow(FvwmWindow * fw,XEvent * pev,Pixel BackColor,GC Shadow,GC Relief,int cs,int title_cs)821 void DrawIconTitleWindow(
822 	FvwmWindow *fw, XEvent *pev, Pixel BackColor, GC Shadow, GC Relief,
823 	int cs, int title_cs)
824 {
825 	int is_expanded = IS_ICON_ENTERED(fw);
826 	FlocaleWinString fstr;
827 	Region region = None;
828 	XRectangle clip, r;
829 	int relief = abs(fw->icon_title_relief);
830 	int x_title;
831 	int x_title_min = 0;
832 	int w_title = fw->icon_g.title_text_width;
833 	int x_title_w = fw->icon_g.picture_w_g.x;
834 	int w_title_w = fw->icon_g.picture_w_g.width;
835 	int x_stipple = relief;
836 	int w_title_text_gap = 0;
837 	int w_stipple = 0;
838 	int is_sticky;
839 	int is_stippled;
840 	int use_unexpanded_size = 1;
841 	Bool draw_string = True;
842 
843 	is_sticky =
844 		(IS_STICKY_ACROSS_PAGES(fw) || IS_ICON_STICKY_ACROSS_PAGES(fw));
845 	is_sticky |=
846 		(IS_STICKY_ACROSS_DESKS(fw) || IS_ICON_STICKY_ACROSS_DESKS(fw));
847 	is_stippled = ((is_sticky && HAS_STICKY_STIPPLED_ICON_TITLE(fw)) ||
848 		HAS_STIPPLED_ICON_TITLE(fw));
849 	if (is_expanded && FW_W_ICON_PIXMAP(fw) != None)
850 	{
851 		int sx;
852 		int sy;
853 		int sw;
854 		int sh;
855 
856 		use_unexpanded_size = 0;
857 		w_title_text_gap = ICON_TITLE_TEXT_GAP_EXPANDED;
858 		x_title_min = w_title_text_gap + relief;
859 		if (is_stippled)
860 		{
861 			w_stipple = ICON_TITLE_STICK_MIN_WIDTH;
862 			x_title_min +=
863 				w_stipple + ICON_TITLE_TO_STICK_EXTRA_GAP;
864 		}
865 		/* resize the icon name window */
866 		w_title_w = w_title + 2 * x_title_min;
867 		if (w_title_w <= fw->icon_g.picture_w_g.width)
868 		{
869 			/* the expanded title is smaller, so do not
870 			 * expand at all */
871 			is_expanded = 1;
872 			w_stipple = 0;
873 			use_unexpanded_size = 1;
874 		}
875 		else
876 		{
877 			x_title_w = fw->icon_g.picture_w_g.x -
878 				(w_title_w - fw->icon_g.picture_w_g.width) / 2;
879 			FScreenGetScrRect(
880 				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 != 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 == 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 = 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 % Scr.MyDisplayWidth;
1665     new_y = t->g.frame.y % Scr.MyDisplayHeight;
1666     if (new_x + t->g.frame.width <= 0)
1667       new_x += Scr.MyDisplayWidth;
1668     if (new_y + t->g.frame.height <= 0)
1669       new_y += Scr.MyDisplayHeight;
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->g.frame), t->Desk))
1674   {
1675     base_x = 0;
1676     base_y = 0;
1677   }
1678   else
1679   {
1680     base_x = ((t->g.frame.x + Scr.Vx + (t->g.frame.width >> 1)) /
1681       Scr.MyDisplayWidth) * Scr.MyDisplayWidth;
1682     base_y= ((t->g.frame.y + Scr.Vy + (t->g.frame.height >> 1)) /
1683       Scr.MyDisplayHeight) * Scr.MyDisplayHeight;
1684     /* limit icon position to desktop */
1685     if (base_x > Scr.VxMax)
1686       base_x = Scr.VxMax;
1687     if (base_x < 0)
1688       base_x = 0;
1689     if (base_y > Scr.VyMax)
1690       base_y = Scr.VyMax;
1691     if (base_y < 0)
1692       base_y = 0;
1693     base_x -= Scr.Vx;
1694     base_y -= 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 % Scr.MyDisplayWidth + base_x;
1714     g.y = g.y % Scr.MyDisplayHeight + base_y;
1715     if (g.x < 0)
1716     {
1717       g.x += Scr.MyDisplayWidth;
1718     }
1719     if (g.y < 0)
1720     {
1721       g.y += Scr.MyDisplayHeight;
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.xypos.x = t->g.frame.x + (t->g.frame.width / 2) - base_x;
1796     fscr.xypos.y = t->g.frame.y + (t->g.frame.height / 2) - base_y;
1797     get_icon_geometry(t, &g);
1798     /* unnecessary copy of width */
1799     width = g.width;
1800     /* total height */
1801     height = g.height;
1802     /* no slot found yet */
1803     loc_ok = False;
1804     loc_ok_wrong_screen = False;
1805 
1806     /* check all boxes in order */
1807     icon_boxes_ptr = NULL;              /* init */
1808     while(do_all_iconboxes(t, &icon_boxes_ptr))
1809     {
1810       if (loc_ok == True)
1811       {
1812 	/* leave for loop */
1813 	break;
1814       }
1815       /* get the screen dimensions for the icon box */
1816       if (icon_boxes_ptr->IconScreen == FSCREEN_CURRENT)
1817 	fscr.mouse_ev = NULL;
1818       FScreenGetScrRect(
1819 	&fscr,
1820 	icon_boxes_ptr->IconScreen,
1821 	&ref.x, &ref.y, &ref.width, &ref.height);
1822       dim[1].screen_offset = ref.y;
1823       dim[1].screen_dimension = ref.height;
1824       dim[2].screen_offset = ref.x;
1825       dim[2].screen_dimension = ref.width;
1826       /* y amount */
1827       dim[1].step = icon_boxes_ptr->IconGrid[1];
1828       /* init start from */
1829       dim[1].start_at = ICONBOX_TOP + dim[1].screen_offset;
1830       if (icon_boxes_ptr->IconSign[1] == '-') {
1831 	dim[1].start_at += dim[1].screen_dimension;
1832       }
1833       /* init end at */
1834       dim[1].end_at = ICONBOX_BOT + dim[1].screen_offset;
1835       if (icon_boxes_ptr->IconSign[3] == '-') {
1836 	dim[1].end_at += dim[1].screen_dimension;
1837       }
1838       /* save base */
1839       dim[1].base = base_y;
1840       /* save dimension */
1841       dim[1].icon_dimension = height;
1842       if (BOT_FILL)
1843       {
1844 	/* fill from bottom */
1845 	/* reverse step */
1846 	dim[1].step = 0 - dim[1].step;
1847       } /* end fill from bottom */
1848 
1849       /* x amount */
1850       dim[2].step = icon_boxes_ptr->IconGrid[0];
1851       /* init start from */
1852       dim[2].start_at = ICONBOX_LFT + dim[2].screen_offset;
1853       if (icon_boxes_ptr->IconSign[0] == '-') {
1854 	dim[2].start_at += dim[2].screen_dimension;
1855       }
1856       /* init end at */
1857       dim[2].end_at = ICONBOX_RGT + dim[2].screen_offset;
1858       if (icon_boxes_ptr->IconSign[2] == '-') {
1859 	dim[2].end_at += dim[2].screen_dimension;
1860       }
1861       /* save base */
1862       dim[2].base   = base_x;
1863       /* save dimension */
1864       dim[2].icon_dimension = width;
1865       if (RGT_FILL)
1866       {
1867 	/* fill from right */
1868 	/* reverse step */
1869 	dim[2].step = 0 - dim[2].step;
1870       } /* end fill from right */
1871       for (i=1;i<=2;i++)
1872       {
1873 	/* for dimensions 1 and 2 */
1874 	/* If the window is taller than the icon box, ignore the icon height
1875 	 * when figuring where to put it. Same goes for the width
1876 	 * This should permit reasonably graceful handling of big icons. */
1877 	dim[i].nom_dimension = dim[i].icon_dimension;
1878 	if (dim[i].icon_dimension >= dim[i].end_at - dim[i].start_at)
1879 	{
1880 	  dim[i].nom_dimension = dim[i].end_at - dim[i].start_at - 1;
1881 	}
1882 	if (dim[i].step < 0)
1883 	{
1884 	  /* if moving backwards */
1885 	  /* save */
1886 	  dim[0].start_at = dim[i].start_at;
1887 	  /* swap one */
1888 	  dim[i].start_at = dim[i].end_at;
1889 	  /* swap the other */
1890 	  dim[i].end_at = dim[0].start_at;
1891 	  dim[i].start_at -= dim[i].icon_dimension;
1892 	} /* end moving backwards */
1893 	/* adjust both to base */
1894 	dim[i].start_at += dim[i].base;
1895 	dim[i].end_at += dim[i].base;
1896       } /* end 2 dimensions */
1897       if (HRZ_FILL)
1898       {
1899 	/* if hrz first */
1900 	/* save */
1901 	memcpy(&dim[0],&dim[1],sizeof(dimension));
1902 	/* switch one */
1903 	memcpy(&dim[1],&dim[2],sizeof(dimension));
1904 	/* switch the other */
1905 	memcpy(&dim[2],&dim[0],sizeof(dimension));
1906       } /* end horizontal dimension first */
1907       /* save for reseting inner loop */
1908       dim[0].start_at = dim[2].start_at;
1909       loc_ok_wrong_screen2 = False;
1910       while((dim[1].step < 0            /* filling reversed */
1911 	     ? (dim[1].start_at + dim[1].icon_dimension - dim[1].nom_dimension
1912 		> dim[1].end_at)        /* check back edge */
1913 	     : (dim[1].start_at + dim[1].nom_dimension
1914 		< dim[1].end_at))       /* check front edge */
1915 	    && (!loc_ok)
1916 	    && (!loc_ok_wrong_screen2)) {  /* nothing found yet */
1917 	dim[1].real_start = dim[1].start_at; /* init */
1918 	if (dim[1].start_at + dim[1].icon_dimension >
1919 	    dim[1].screen_offset + dim[1].screen_dimension - 2 + dim[1].base)
1920 	{
1921 	  /* off screen, move on screen */
1922 	  dim[1].real_start = dim[1].screen_offset + dim[1].screen_dimension
1923 	    - dim[1].icon_dimension + dim[1].base;
1924 	} /* end off screen */
1925 	if (dim[1].start_at < dim[1].screen_offset + dim[1].base)
1926 	{
1927 	  /* if off other edge, move on screen */
1928 	  dim[1].real_start = dim[1].screen_offset + dim[1].base;
1929 	} /* end off other edge */
1930 	/* reset inner loop */
1931 	dim[2].start_at = dim[0].start_at;
1932 	while((dim[2].step < 0            /* filling reversed */
1933 	       ? (dim[2].start_at + dim[2].icon_dimension-dim[2].nom_dimension
1934 		  > dim[2].end_at)        /* check back edge */
1935 	       : (dim[2].start_at + dim[2].nom_dimension
1936 		  < dim[2].end_at))       /* check front edge */
1937 	      && (!loc_ok)
1938 	      && (!loc_ok_wrong_screen2)) { /* nothing found yet */
1939 	  dim[2].real_start = dim[2].start_at; /* init */
1940 	  if (dim[2].start_at + dim[2].icon_dimension >
1941 	      dim[2].screen_offset + dim[2].screen_dimension - 2 + dim[2].base)
1942 	  {
1943 	    /* if off screen, move on screen */
1944 	    dim[2].real_start = dim[2].screen_offset + dim[2].screen_dimension
1945 	      - dim[2].icon_dimension + dim[2].base;
1946 	  } /* end off screen */
1947 	  if (dim[2].start_at < dim[2].screen_offset + dim[2].base)
1948 	  {
1949 	    /* if off other edge, move on screen */
1950 	    dim[2].real_start = dim[2].screen_offset + dim[2].base;
1951 	  } /* end off other edge */
1952 
1953 	  if (HRZ_FILL)
1954 	  {
1955 	    /* hrz first */
1956 	    /* unreverse them */
1957 	    real_x = dim[1].real_start;
1958 	    real_y = dim[2].real_start;
1959 	  }
1960 	  else
1961 	  {
1962 	    /* reverse them */
1963 	    real_x = dim[2].real_start;
1964 	    real_y = dim[1].real_start;
1965 	  }
1966 
1967 	  /* this may be a good location */
1968 	  if (FScreenIsRectangleOnScreen(&fscr, FSCREEN_XYPOS, &ref))
1969 	  {
1970 	    loc_ok = True;
1971 	  }
1972 	  else
1973 	  {
1974 	    loc_ok_wrong_screen2 = True;
1975 	  }
1976 	  test_fw = Scr.FvwmRoot.next;
1977 	  while((test_fw != (FvwmWindow *)0)
1978 		&&(loc_ok == True || loc_ok_wrong_screen2))
1979 	  {
1980 	    /* test overlap */
1981 	    if (test_fw->Desk == t->Desk)
1982 	    {
1983 	      rectangle g;
1984 
1985 	      if ((IS_ICONIFIED(test_fw)) &&
1986 		 (!IS_TRANSIENT(test_fw) ||
1987 		  !IS_ICONIFIED_BY_PARENT(test_fw)) &&
1988 		 (FW_W_ICON_TITLE(test_fw)||FW_W_ICON_PIXMAP(test_fw)) &&
1989 		 (test_fw != t)) {
1990 		get_icon_geometry(test_fw, &g);
1991 		if ((g.x<(real_x+width+MIN_ICON_BOX_DIST))&&
1992 		   ((g.x+g.width+MIN_ICON_BOX_DIST) > real_x)&&
1993 		   (g.y<(real_y+height+MIN_ICON_BOX_DIST))&&
1994 		   ((g.y+g.height + MIN_ICON_BOX_DIST)>real_y))
1995 		{
1996 		  /* don't accept this location */
1997 		  loc_ok = False;
1998 		  loc_ok_wrong_screen2 = False;
1999 		} /* end if icons overlap */
2000 	      } /* end if its an icon */
2001 	    } /* end if same desk */
2002 	    test_fw = test_fw->next;
2003 	  } /* end while icons that may overlap */
2004 	  if (loc_ok_wrong_screen2)
2005 	  {
2006 	    loc_ok_wrong_screen = True;
2007 	  }
2008 	  /* Grid inner value & direction */
2009 	  dim[2].start_at += dim[2].step;
2010 	} /* end while room inner dimension */
2011 	/* Grid outer value & direction */
2012 	dim[1].start_at += dim[1].step;
2013       } /* end while room outer dimension */
2014     } /* end for all icon boxes, or found space */
2015     if (!loc_ok && !loc_ok_wrong_screen)
2016       /* If icon never found a home just leave it */
2017       return;
2018     set_icon_position(t, real_x, real_y);
2019     broadcast_icon_geometry(t, True);
2020     do_move_icon = True;
2021   }
2022   if (do_move_icon && do_move_immediately)
2023   {
2024     move_icon_to_position(t);
2025   }
2026 
2027   return;
2028 }
2029 
2030 static icon_boxes *global_icon_box_ptr;
2031 /* Find next icon box to try to place icon in.
2032    Goes thru chain that the window got thru style matching,
2033    then the global icon box.
2034    Create the global icon box on first call.
2035    Return code indicates when the boxes are used up.
2036    The boxes could only get completely used up when you fill the screen
2037    with them.
2038 */
2039 static int
do_all_iconboxes(FvwmWindow * t,icon_boxes ** icon_boxes_ptr)2040 do_all_iconboxes(FvwmWindow *t, icon_boxes **icon_boxes_ptr)
2041 {
2042 	if (global_icon_box_ptr == 0)
2043 	{
2044 		/* if first time */
2045 		int sx;
2046 		int sy;
2047 		int sw;
2048 		int sh;
2049 		/* Right now, the global box is hard-coded, fills the primary
2050 		 * screen, uses an 80x80 grid, and fills top-bottom,
2051 		 * left-right */
2052 		FScreenGetScrRect(NULL, FSCREEN_PRIMARY, &sx, &sy, &sw, &sh);
2053 		global_icon_box_ptr = calloc(1, sizeof(icon_boxes));
2054 		global_icon_box_ptr->IconBox[0] = sx;
2055 		global_icon_box_ptr->IconBox[1] = sy;
2056 		global_icon_box_ptr->IconBox[2] = sx + sw;
2057 		global_icon_box_ptr->IconBox[3] = sy + sh;
2058 		global_icon_box_ptr->IconGrid[0] = 80;
2059 		global_icon_box_ptr->IconGrid[1] = 80;
2060 		global_icon_box_ptr->IconFlags = ICONFILLHRZ;
2061 	}
2062 	if (*icon_boxes_ptr == NULL)
2063 	{
2064 		/* first time? */
2065 		/* start at windows box */
2066 		*icon_boxes_ptr = t->IconBoxes;
2067 		if (!*icon_boxes_ptr)
2068 		{
2069 			/* if window has no box */
2070 			/* use global box */
2071 			*icon_boxes_ptr = global_icon_box_ptr;
2072 		}
2073 		/* use box */
2074 		return (1);
2075 	}
2076 
2077 	/* Here its not the first call, we are either on the chain or at
2078 	 * the global box */
2079 	if (*icon_boxes_ptr == global_icon_box_ptr)
2080 	{
2081 		/* if the global box */
2082 		/* completely out of boxes (unlikely) */
2083 		return (0);
2084 	}
2085 	/* move to next one on chain */
2086 	*icon_boxes_ptr = (*icon_boxes_ptr)->next;
2087 	if (*icon_boxes_ptr)
2088 	{
2089                 /* if there is a next one */
2090 		/* return it */
2091 		return (1);
2092 	}
2093 	/* global box */
2094 	*icon_boxes_ptr = global_icon_box_ptr;
2095 
2096 	/* use it */
2097 	return (1);
2098 }
2099 
2100 /*
2101  *
2102  * Looks for icon from a file
2103  *
2104  */
GetIconFromFile(FvwmWindow * fw)2105 static void GetIconFromFile(FvwmWindow *fw)
2106 {
2107 	char *path = NULL;
2108 	FvwmPictureAttributes fpa;
2109 
2110 	fpa.mask = 0;
2111 	if (fw->cs >= 0 && Colorset[fw->cs].do_dither_icon)
2112 	{
2113 		fpa.mask |= FPAM_DITHER;
2114 	}
2115 	fw->icon_g.picture_w_g.width = 0;
2116 	fw->icon_g.picture_w_g.height = 0;
2117 	path = PictureFindImageFile(fw->icon_bitmap_file, NULL, R_OK);
2118 	if (path == NULL)
2119 	{
2120 		return;
2121 	}
2122 	if (!PImageLoadPixmapFromFile(
2123 		dpy, Scr.NoFocusWin, path, &fw->iconPixmap,
2124 		&fw->icon_maskPixmap, &fw->icon_alphaPixmap,
2125 		&fw->icon_g.picture_w_g.width, &fw->icon_g.picture_w_g.height,
2126 		&fw->iconDepth, &fw->icon_nalloc_pixels, &fw->icon_alloc_pixels,
2127 		&fw->icon_no_limit, fpa))
2128 	{
2129 		fvwm_msg(ERR, "GetIconFromFile", "Failed to load %s", path);
2130 		free(path);
2131 		return;
2132 	}
2133 	SET_PIXMAP_OURS(fw, 1);
2134 	free(path);
2135 	if (FShapesSupported && fw->icon_maskPixmap)
2136 	{
2137 		SET_ICON_SHAPED(fw, 1);
2138 	}
2139 
2140 	return;
2141 }
2142 
2143 /*
2144  *
2145  * Looks for an application supplied icon window
2146  *
2147  */
GetIconWindow(FvwmWindow * fw)2148 static void GetIconWindow(FvwmWindow *fw)
2149 {
2150 	int w;
2151 	int h;
2152 	int bw;
2153 
2154 	fw->icon_g.picture_w_g.width = 0;
2155 	fw->icon_g.picture_w_g.height = 0;
2156 
2157 	/* We are guaranteed that wmhints is non-null when calling this
2158 	 * routine */
2159 	if (XGetGeometry(
2160 		    dpy, fw->wmhints->icon_window, &JunkRoot, &JunkX, &JunkY,
2161 		    (unsigned int*)&w, (unsigned int*)&h,(unsigned int*)&bw,
2162 		    (unsigned int*)&JunkDepth) == 0)
2163 	{
2164 		fvwm_msg(
2165 			ERR,"GetIconWindow",
2166 			"Window '%s' has a bad icon window! Ignoring icon"
2167 			" window.", fw->name.name);
2168 		/* disable the icon window hint */
2169 		fw->wmhints->icon_window = None;
2170 		fw->wmhints->flags &= ~IconWindowHint;
2171 		return;
2172 	}
2173 	fw->icon_border_width = bw;
2174 	fw->icon_g.picture_w_g.width = w + 2 * bw;
2175 	fw->icon_g.picture_w_g.height = h + 2 * bw;
2176 	/*
2177 	 * Now make the new window the icon window for this window,
2178 	 * and set it up to work as such (select for key presses
2179 	 * and button presses/releases, set up the contexts for it,
2180 	 * and define the cursor for it).
2181 	 */
2182 	FW_W_ICON_PIXMAP(fw) = fw->wmhints->icon_window;
2183 	if (FShapesSupported)
2184 	{
2185 		if (fw->wmhints->flags & IconMaskHint)
2186 		{
2187 			SET_ICON_SHAPED(fw, 1);
2188 			fw->icon_maskPixmap = fw->wmhints->icon_mask;
2189 		}
2190 	}
2191 	/* Make sure that the window is a child of the root window ! */
2192 	/* Olwais screws this up, maybe others do too! */
2193 	XReparentWindow(dpy, FW_W_ICON_PIXMAP(fw), Scr.Root, 0,0);
2194 	SET_ICON_OURS(fw, 0);
2195 
2196 	return;
2197 }
2198 
2199 
2200 /*
2201  *
2202  * Looks for an application supplied bitmap or pixmap
2203  *
2204  */
GetIconBitmap(FvwmWindow * fw)2205 static void GetIconBitmap(FvwmWindow *fw)
2206 {
2207 	int width, height, depth;
2208 
2209 	fw->icon_g.picture_w_g.width = 0;
2210 	fw->icon_g.picture_w_g.height = 0;
2211 
2212 	/* We are guaranteed that wmhints is non-null when calling this routine
2213 	 */
2214 	if (!XGetGeometry(
2215 		    dpy, fw->wmhints->icon_pixmap, &JunkRoot, &JunkX, &JunkY,
2216 		    (unsigned int*)&width, (unsigned int*)&height,
2217 		    (unsigned int*)&JunkBW, (unsigned int*)&depth))
2218 	{
2219 		fvwm_msg(
2220 			ERR,"GetIconBitmap",
2221 			"Window '%s' has a bad icon pixmap! Ignoring icon.",
2222 			fw->name.name);
2223 		/* disable icon pixmap hint */
2224 		fw->wmhints->icon_pixmap = None;
2225 		fw->wmhints->flags &= ~IconPixmapHint;
2226 		return;
2227 	}
2228 	/* sanity check the pixmap depth, it must be the same as the root or 1
2229 	 */
2230 	if (depth != 1 && depth != Pdepth &&
2231 	    depth != DefaultDepth(dpy,Scr.screen))
2232 	{
2233 		fvwm_msg(
2234 			ERR, "GetIconBitmap",
2235 			"Window '%s' has a bad icon bitmap depth %d (should"
2236 			" be 1, %d or %d)! Ignoring icon bitmap.",
2237 			fw->name.name, depth, Pdepth,
2238 			DefaultDepth(dpy,Scr.screen));
2239 		/* disable icon pixmap hint */
2240 		fw->wmhints->icon_pixmap = None;
2241 		fw->wmhints->flags &= ~IconPixmapHint;
2242 		return;
2243 	}
2244 	fw->iconPixmap = fw->wmhints->icon_pixmap;
2245 	fw->icon_g.picture_w_g.width = width;
2246 	fw->icon_g.picture_w_g.height = height;
2247 	fw->iconDepth = depth;
2248 	if (FShapesSupported)
2249 	{
2250 		if (fw->wmhints->flags & IconMaskHint)
2251 		{
2252 			SET_ICON_SHAPED(fw, 1);
2253 			fw->icon_maskPixmap = fw->wmhints->icon_mask;
2254 		}
2255 	}
2256 	SET_PIXMAP_OURS(fw, 0);
2257 
2258 	return;
2259 }
2260 
2261 /*
2262  *
2263  *  Procedure:
2264  *      DeIconify a window
2265  *
2266  */
DeIconify(FvwmWindow * fw)2267 void DeIconify(FvwmWindow *fw)
2268 {
2269 	FvwmWindow *t, *tmp, *ofw;
2270 	FvwmWindow *sf = get_focus_window();
2271 	rectangle icon_rect;
2272 	XWindowAttributes winattrs = {0};
2273 
2274 	if (!fw)
2275 	{
2276 		return;
2277 	}
2278 	if (!XGetWindowAttributes(dpy, FW_W(fw), &winattrs))
2279 	{
2280 		return;
2281 	}
2282 
2283 	/* make sure fw->flags.is_map_pending is OK */
2284 	if (winattrs.map_state == IsViewable && IS_MAP_PENDING(fw))
2285 	{
2286 		SET_MAP_PENDING(fw, 0);
2287 	}
2288 	else if (IS_MAP_PENDING(fw))
2289 	{
2290 		/* final state: de-iconified */
2291 		SET_ICONIFY_AFTER_MAP(fw, 0);
2292 		return;
2293 	}
2294 	for (ofw = NULL; fw != ofw && IS_ICONIFIED_BY_PARENT(fw); )
2295 	{
2296 		t = get_transientfor_fvwmwindow(fw);
2297 		if (t == NULL)
2298 		{
2299 			break;
2300 		}
2301 		ofw = fw;
2302 		fw = t;
2303 	}
2304 	if (IS_ICONIFIED_BY_PARENT(fw))
2305 	{
2306 		SET_ICONIFIED_BY_PARENT(fw, 0);
2307 	}
2308 
2309 	/* AS dje  RaiseWindow(fw); */
2310 
2311 	if (fw == sf)
2312 	{
2313 		/* take away the focus before mapping */
2314 		DeleteFocus(True);
2315 	}
2316 	/* Note: DeleteFocus may delete the flags set by
2317 	 * mark_transient_subtree(), so do it later. */
2318 	mark_transient_subtree(fw, MARK_ALL_LAYERS, MARK_ALL, False, True);
2319 	/* now de-iconify transients */
2320 	for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
2321 	{
2322 		if (t == fw || IS_IN_TRANSIENT_SUBTREE(t))
2323 		{
2324 			SET_IN_TRANSIENT_SUBTREE(t, 0);
2325 			SET_MAPPED(t, 1);
2326 			SET_ICONIFIED_BY_PARENT(t, 0);
2327 			if (Scr.Hilite == t)
2328 			{
2329 				border_draw_decorations(
2330 					t, PART_ALL, False, True, CLEAR_ALL,
2331 					NULL, NULL);
2332 			}
2333 
2334 			/* AS stuff starts here dje */
2335 			if (FW_W_ICON_PIXMAP(t))
2336 			{
2337 				XUnmapWindow(dpy, FW_W_ICON_PIXMAP(t));
2338 			}
2339 			if (FW_W_ICON_TITLE(t))
2340 			{
2341 				XUnmapWindow(dpy, FW_W_ICON_TITLE(t));
2342 			}
2343 			XFlush(dpy);
2344 			/* End AS */
2345 			XMapWindow(dpy, FW_W(t));
2346 			if (t->Desk == Scr.CurrentDesk)
2347 			{
2348 				rectangle r;
2349 
2350 				get_icon_geometry(t, &r);
2351 				/* update absoluthe geometry in case the icon
2352 				 * was moved over a page boundary; the move
2353 				 * code already takes care of keeping the frame
2354 				 * geometry up to date */
2355 				update_absolute_geometry(t);
2356 				if (IsRectangleOnThisPage(&r, t->Desk) &&
2357 				    !IsRectangleOnThisPage(
2358 					    &(t->g.frame), t->Desk))
2359 				{
2360 					/* Make sure we keep it on screen when
2361 					 * de-iconifying. */
2362 					t->g.frame.x -=
2363 						truncate_to_multiple(
2364 							t->g.frame.x,
2365 							Scr.MyDisplayWidth);
2366 					t->g.frame.y -=
2367 						truncate_to_multiple(
2368 							t->g.frame.y,
2369 							Scr.MyDisplayHeight);
2370 					XMoveWindow(
2371 						dpy, FW_W_FRAME(t),
2372 						t->g.frame.x, t->g.frame.y);
2373 					update_absolute_geometry(t);
2374 					maximize_adjust_offset(t);
2375 				}
2376 			}
2377 			/* domivogt (1-Mar-2000): The next block is a hack to
2378 			 * prevent animation if the window has an icon, but
2379 			 * neither a pixmap nor a title. */
2380 			if (HAS_NO_ICON_TITLE(t) && FW_W_ICON_PIXMAP(t) == None)
2381 			{
2382 				memset(&fw->icon_g, 0, sizeof(fw->icon_g));
2383 			}
2384 			get_icon_geometry(t, &icon_rect);
2385 			/* if this fails it does not overwrite icon_rect */
2386 			EWMH_GetIconGeometry(t, &icon_rect);
2387 			if (t == fw)
2388 			{
2389 				BroadcastPacket(
2390 					M_DEICONIFY, 11, (long)FW_W(t),
2391 					(long)FW_W_FRAME(t), (unsigned long)t,
2392 					(long)icon_rect.x, (long)icon_rect.y,
2393 					(long)icon_rect.width,
2394 					(long)icon_rect.height,
2395 					(long)t->g.frame.x,
2396 					(long)t->g.frame.y,
2397 					(long)t->g.frame.width,
2398 					(long)t->g.frame.height);
2399 			}
2400 			else
2401 			{
2402 				BroadcastPacket(
2403 					M_DEICONIFY, 7, (long)FW_W(t),
2404 					(long)FW_W_FRAME(t),
2405 					(unsigned long)t, (long)icon_rect.x,
2406 					(long)icon_rect.y,
2407 					(long)icon_rect.width,
2408 					(long)icon_rect.height);
2409 			}
2410 			XMapWindow(dpy, FW_W_PARENT(t));
2411 			if (t->Desk == Scr.CurrentDesk)
2412 			{
2413 				XMapWindow(dpy, FW_W_FRAME(t));
2414 				SET_MAP_PENDING(t, 1);
2415 			}
2416 			SetMapStateProp(t, NormalState);
2417 			SET_ICONIFIED(t, 0);
2418 			SET_ICON_UNMAPPED(t, 0);
2419 			SET_ICON_ENTERED(t, 0);
2420 			/* Need to make sure the border is colored correctly,
2421 			 * in case it was stuck or unstuck while iconified. */
2422 			tmp = Scr.Hilite;
2423 			Scr.Hilite = t;
2424 			border_draw_decorations(
2425 				t, PART_ALL, (sf == t) ? True : False, True,
2426 				CLEAR_ALL, NULL, NULL);
2427 			Scr.Hilite = tmp;
2428 		}
2429 	}
2430 
2431 #if 1
2432 	RaiseWindow(fw, False); /* moved dje */
2433 #endif
2434 	if (sf == fw)
2435 	{
2436 		/* update the focus to make sure the application knows its
2437 		 * state */
2438 		if (!FP_DO_UNFOCUS_LEAVE(FW_FOCUS_POLICY(fw)))
2439 		{
2440 			SetFocusWindow(fw, True, FOCUS_SET_FORCE);
2441 		}
2442 	}
2443 	else if (FP_DO_SORT_WINDOWLIST_BY(FW_FOCUS_POLICY(fw)) ==
2444 		 FPOL_SORT_WL_BY_OPEN)
2445 	{
2446 		SetFocusWindow(fw, True, FOCUS_SET_FORCE);
2447 	}
2448 	focus_grab_buttons_on_layer(fw->layer);
2449 
2450 	return;
2451 }
2452 
2453 
2454 /*
2455  *
2456  * Iconifies the selected window
2457  *
2458  */
Iconify(FvwmWindow * fw,initial_window_options_t * win_opts)2459 void Iconify(FvwmWindow *fw, initial_window_options_t *win_opts)
2460 {
2461 	FvwmWindow *t;
2462 	FvwmWindow *sf;
2463 	XWindowAttributes winattrs = {0};
2464 	unsigned long eventMask;
2465 	rectangle icon_rect;
2466 
2467 	if (!fw)
2468 	{
2469 		return;
2470 	}
2471 	if (!XGetWindowAttributes(dpy, FW_W(fw), &winattrs))
2472 	{
2473 		return;
2474 	}
2475 
2476 	/* make sure fw->flags.is_map_pending is OK */
2477 	if ((winattrs.map_state == IsViewable) && IS_MAP_PENDING(fw))
2478 	{
2479 		SET_MAP_PENDING(fw, 0);
2480 	}
2481 
2482 	if (IS_MAP_PENDING(fw))
2483 	{
2484 		/* final state: iconified */
2485 		SET_ICONIFY_AFTER_MAP(fw, 1);
2486 		return;
2487 	}
2488 	eventMask = winattrs.your_event_mask;
2489 
2490 	mark_transient_subtree(fw, MARK_ALL_LAYERS, MARK_ALL, False, True);
2491 	sf = get_focus_window();
2492 	if (sf && IS_IN_TRANSIENT_SUBTREE(sf))
2493 	{
2494 		restore_focus_after_unmap(sf, True);
2495 		/* restore_focus_after_unmap() destorys the flags set by
2496 		 * mark_transient_subtree(), so we have to unfortunately call
2497 		 * it again. */
2498 		mark_transient_subtree(
2499 			fw, MARK_ALL_LAYERS, MARK_ALL, False, True);
2500 	}
2501 	/* iconify transients first */
2502 	for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
2503 	{
2504 		if (t == fw || IS_IN_TRANSIENT_SUBTREE(t))
2505 		{
2506 			SET_IN_TRANSIENT_SUBTREE(t, 0);
2507 			SET_ICON_ENTERED(t, 0);
2508 			/* Prevent the receipt of an UnmapNotify, since that
2509 			 * would cause a transition to the Withdrawn state. */
2510 			SET_MAPPED(t, 0);
2511 			XSelectInput(
2512 				dpy, FW_W(t), eventMask & ~StructureNotifyMask);
2513 			XUnmapWindow(dpy, FW_W(t));
2514 			XSelectInput(dpy, FW_W(t), eventMask);
2515 			XUnmapWindow(dpy, FW_W_FRAME(t));
2516 			border_undraw_decorations(t);
2517 			t->DeIconifyDesk = t->Desk;
2518 			if (FW_W_ICON_TITLE(t))
2519 			{
2520 				XUnmapWindow(dpy, FW_W_ICON_TITLE(t));
2521 			}
2522 			if (FW_W_ICON_PIXMAP(t))
2523 			{
2524 				XUnmapWindow(dpy, FW_W_ICON_PIXMAP(t));
2525 			}
2526 
2527 			SetMapStateProp(t, IconicState);
2528 			border_draw_decorations(
2529 				t, PART_ALL, False, False, CLEAR_ALL, NULL,
2530 				NULL);
2531 			if (t == fw && !IS_ICONIFIED_BY_PARENT(fw))
2532 			{
2533 				SET_ICONIFY_PENDING(t, 1);
2534 			}
2535 			else
2536 			{
2537 				rectangle g;
2538 
2539 				SET_ICONIFIED(t, 1);
2540 				SET_ICON_UNMAPPED(t, 1);
2541 				SET_ICONIFIED_BY_PARENT(t, 1);
2542 				get_icon_geometry(t, &g);
2543 				BroadcastPacket(
2544 					M_ICONIFY, 7, (long)FW_W(t),
2545 					(long)FW_W_FRAME(t),
2546 					(unsigned long)t, (long)-32768,
2547 					(long)-32768, (long)g.width,
2548 					(long)g.height);
2549 				BroadcastConfig(M_CONFIGURE_WINDOW,t);
2550 			}
2551 		} /* if */
2552 	} /* for */
2553 
2554 	/* necessary during a recapture */
2555 	if (IS_ICONIFIED_BY_PARENT(fw))
2556 	{
2557 		return;
2558 	}
2559 
2560 	if (FW_W_ICON_TITLE(fw) == None || HAS_ICON_CHANGED(fw))
2561 	{
2562 		if (IS_ICON_MOVED(fw) || win_opts->flags.use_initial_icon_xy)
2563 		{
2564 			rectangle g;
2565 
2566 			get_icon_geometry(fw, &g);
2567 			if (win_opts->flags.use_initial_icon_xy)
2568 			{
2569 				g.x = win_opts->initial_icon_x;
2570 				g.y = win_opts->initial_icon_y;
2571 			}
2572 			CreateIconWindow(fw, g.x, g.y);
2573 		}
2574 		else
2575 		{
2576 			CreateIconWindow(
2577 				fw, win_opts->default_icon_x,
2578 				win_opts->default_icon_y);
2579 		}
2580 		SET_HAS_ICON_CHANGED(fw, 0);
2581 	}
2582 	else if (FW_W_ICON_TITLE(fw) && !FW_W_ICON_PIXMAP(fw))
2583 	{
2584 		/* if no pixmap we want icon width to change to text width
2585 		 * every iconify; not necessary if the icon was created above */
2586 		setup_icon_title_size(fw);
2587 	}
2588 
2589 	/* this condition will be true unless we restore a window to
2590 	 * iconified state from a saved session. */
2591 	if (win_opts->initial_state != IconicState ||
2592 	    (!IS_ICON_MOVED(fw) && !win_opts->flags.use_initial_icon_xy))
2593 	{
2594 		AutoPlaceIcon(fw, win_opts, True);
2595 	}
2596 	/* domivogt (12-Mar-2003): Clean out the icon geometry if there is no
2597 	 * icon.  Necessary to initialise the values and to suppress animation
2598 	 * if there is no icon. */
2599 	if (HAS_NO_ICON_TITLE(fw) && FW_W_ICON_PIXMAP(fw) == None)
2600 	{
2601 		clear_icon_dimensions(fw);
2602 	}
2603 	SET_ICONIFIED(fw, 1);
2604 	SET_ICON_UNMAPPED(fw, 0);
2605 	get_icon_geometry(fw, &icon_rect);
2606 	/* if this fails it does not overwrite icon_rect */
2607 	EWMH_GetIconGeometry(fw, &icon_rect);
2608 	BroadcastPacket(
2609 		M_ICONIFY, 11, (long)FW_W(fw), (long)FW_W_FRAME(fw),
2610 		(unsigned long)fw, (long)icon_rect.x, (long)icon_rect.y,
2611 		(long)icon_rect.width, (long)icon_rect.height,
2612 		/* next 4 added for Animate module */
2613 		(long)fw->g.frame.x, (long)fw->g.frame.y,
2614 		(long)fw->g.frame.width, (long)fw->g.frame.height);
2615 	BroadcastConfig(M_CONFIGURE_WINDOW,fw);
2616 
2617 	if (win_opts->initial_state != IconicState ||
2618 	    (!IS_ICON_MOVED(fw) && !win_opts->flags.use_initial_icon_xy))
2619 	{
2620 		LowerWindow(fw, False);
2621 	}
2622 	if (IS_ICON_STICKY_ACROSS_DESKS(fw) || IS_STICKY_ACROSS_DESKS(fw))
2623 	{
2624 		fw->Desk = Scr.CurrentDesk;
2625 	}
2626 	if (fw->Desk == Scr.CurrentDesk)
2627 	{
2628 		if (FW_W_ICON_TITLE(fw) != None)
2629 		{
2630 			XMapWindow(dpy, FW_W_ICON_TITLE(fw));
2631 		}
2632 		if (FW_W_ICON_PIXMAP(fw) != None)
2633 		{
2634 			XMapWindow(dpy, FW_W_ICON_PIXMAP(fw));
2635 		}
2636 	}
2637 	focus_grab_buttons_on_layer(fw->layer);
2638 
2639 	return;
2640 }
2641 
2642 /*
2643  *
2644  * This is used to tell applications which windows on the screen are
2645  * top level appication windows, and which windows are the icon windows
2646  * that go with them.
2647  *
2648  */
SetMapStateProp(const FvwmWindow * fw,int state)2649 void SetMapStateProp(const FvwmWindow *fw, int state)
2650 {
2651 	/* "suggested" by ICCCM version 1 */
2652 	unsigned long data[2];
2653 
2654 	data[0] = (unsigned long) state;
2655 	data[1] = (unsigned long) FW_W_ICON_TITLE(fw);
2656 	/*  data[2] = (unsigned long) FW_W_ICON_PIXMAP(fw);*/
2657 
2658 	XChangeProperty(
2659 		dpy, FW_W(fw), _XA_WM_STATE, _XA_WM_STATE, 32, PropModeReplace,
2660 		(unsigned char *) data, 2);
2661 
2662 	return;
2663 }
2664 
CMD_Iconify(F_CMD_ARGS)2665 void CMD_Iconify(F_CMD_ARGS)
2666 {
2667 	int toggle;
2668 	FvwmWindow * const fw = exc->w.fw;
2669 
2670 	toggle = ParseToggleArgument(action, NULL, -1, 0);
2671 	if (toggle == -1)
2672 	{
2673 		if (GetIntegerArguments(action, NULL, &toggle, 1) > 0)
2674 		{
2675 			if (toggle > 0)
2676 			{
2677 				toggle = 1;
2678 			}
2679 			else if (toggle < 0)
2680 			{
2681 				toggle = 0;
2682 			}
2683 			else
2684 			{
2685 				toggle = -1;
2686 			}
2687 		}
2688 	}
2689 	if (toggle == -1)
2690 	{
2691 		toggle = (IS_ICONIFIED(fw)) ? 0 : 1;
2692 	}
2693 
2694 	if (IS_ICONIFIED(fw))
2695 	{
2696 		if (toggle == 0)
2697 		{
2698 			DeIconify(fw);
2699 			EWMH_SetWMState(fw, False);
2700 		}
2701 	}
2702 	else
2703 	{
2704 		if (toggle == 1)
2705 		{
2706 			initial_window_options_t win_opts;
2707 
2708 			if (
2709 				!is_function_allowed(
2710 					F_ICONIFY, NULL, fw, RQORIG_PROGRAM,
2711 					True))
2712 			{
2713 				XBell(dpy, 0);
2714 
2715 				return;
2716 			}
2717 			memset(&win_opts, 0, sizeof(win_opts));
2718 			fev_get_evpos_or_query(
2719 				dpy, Scr.Root, NULL, &win_opts.default_icon_x,
2720 				&win_opts.default_icon_y);
2721 			Iconify(fw, &win_opts);
2722 			EWMH_SetWMState(fw, False);
2723 		}
2724 	}
2725 
2726 	return;
2727 }
2728