1 /* -*-c-*- */
2 /* Copyright (C) 2001  Olivier Chapuis */
3 /* This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, see: <http://www.gnu.org/licenses/>
15  */
16 
17 #include "config.h"
18 
19 #include <stdio.h>
20 
21 #include "libs/fvwmlib.h"
22 #include "libs/FShape.h"
23 #include "libs/PictureBase.h"
24 #include "libs/Picture.h"
25 #include "libs/PictureUtils.h"
26 #include "libs/PictureImageLoader.h"
27 #include "libs/FRenderInit.h"
28 #include "libs/Graphics.h"
29 #include "libs/Strings.h"
30 #include "fvwm.h"
31 #include "externs.h"
32 #include "window_flags.h"
33 #include "cursor.h"
34 #include "functions.h"
35 #include "misc.h"
36 #include "screen.h"
37 #include "module_interface.h"
38 #include "borders.h"
39 #include "icons.h"
40 #include "ewmh.h"
41 #include "ewmh_intern.h"
42 
43 /*
44  * net icon handler
45  */
ewmh_WMIcon(FvwmWindow * fw,XEvent * ev,window_style * style,unsigned long any)46 int ewmh_WMIcon(
47 	FvwmWindow *fw, XEvent *ev, window_style *style, unsigned long any)
48 {
49 	CARD32 *list = NULL;
50 	CARD32 *new_list = NULL;
51 	CARD32 *dummy = NULL;
52 	int size = 0;
53 
54 	if (ev != NULL && HAS_EWMH_WM_ICON_HINT(fw) == EWMH_FVWM_ICON)
55 	{
56 		/* this event has been produced by fvwm itself */
57 		return 0;
58 	}
59 
60 	list = ewmh_AtomGetByName(FW_W(fw),"_NET_WM_ICON",
61 				  EWMH_ATOM_LIST_PROPERTY_NOTIFY, &size);
62 
63 	if (list != NULL && HAS_EWMH_WM_ICON_HINT(fw) == EWMH_NO_ICON)
64 	{
65 		/* the application have a true _NET_WM_ICON */
66 		SET_HAS_EWMH_WM_ICON_HINT(fw, EWMH_TRUE_ICON);
67 	}
68 
69 	if (list == NULL || HAS_EWMH_WM_ICON_HINT(fw) != EWMH_TRUE_ICON)
70 	{
71 		/* No net icon or we have set the net icon */
72 		if (DO_EWMH_DONATE_ICON(fw) &&
73 		    (new_list =
74 		     ewmh_SetWmIconFromPixmap(
75 			     fw, list, &size, False)) != NULL)
76 		{
77 			SET_HAS_EWMH_WM_ICON_HINT(fw, EWMH_FVWM_ICON);
78 		}
79 	}
80 	else if (ev != NULL && USE_EWMH_ICON(fw))
81 	{
82 		/* client message. the application change its net icon */
83 		ChangeIconPixmap(fw);
84 	}
85 	if (FMiniIconsSupported)
86 	{
87 		if (list == NULL ||
88 		    HAS_EWMH_WM_ICON_HINT(fw) != EWMH_TRUE_ICON)
89 		{
90 			/* No net icon or we have set the net icon */
91 			if (DO_EWMH_DONATE_MINI_ICON(fw) &&
92 			    (dummy = ewmh_SetWmIconFromPixmap(
93 				    fw, (new_list != NULL)? new_list : list,
94 				    &size, True)) != NULL)
95 			{
96 				SET_HAS_EWMH_WM_ICON_HINT(
97 					fw, EWMH_FVWM_ICON);
98 				free(dummy);
99 			}
100 		}
101 		else
102 		{
103 			/* the application has a true ewmh icon */
104 			if (EWMH_SetIconFromWMIcon(fw, list, size, True))
105 			{
106 				SET_HAS_EWMH_MINI_ICON(fw, True);
107 			}
108 		}
109 	}
110 
111 	if (list != NULL)
112 	{
113 		free(list);
114 	}
115 	if (new_list != NULL)
116 	{
117 		free(new_list);
118 	}
119 	return 0;
120 }
121 
122 /*
123  * update
124  */
EWMH_DoUpdateWmIcon(FvwmWindow * fw,Bool mini_icon,Bool icon)125 void EWMH_DoUpdateWmIcon(FvwmWindow *fw, Bool mini_icon, Bool icon)
126 {
127 	CARD32 *list = NULL;
128 	CARD32 *new_list = NULL;
129 	CARD32 *dummy = NULL;
130 	int size = 0;
131 	Bool icon_too = False;
132 
133 	if (HAS_EWMH_WM_ICON_HINT(fw) == EWMH_TRUE_ICON)
134 	{
135 		return;
136 	}
137 
138 	/* first see if we have to delete */
139 	if (FMiniIconsSupported && mini_icon &&
140 	    !DO_EWMH_DONATE_MINI_ICON(fw))
141 	{
142 		if (icon && !DO_EWMH_DONATE_ICON(fw))
143 		{
144 			icon_too = True;
145 		}
146 		EWMH_DeleteWmIcon(fw, True, icon_too);
147 	}
148 	if (!icon_too && icon && !DO_EWMH_DONATE_ICON(fw))
149 	{
150 		EWMH_DeleteWmIcon(fw, False, True);
151 	}
152 
153 	/* now set if needed */
154 	if ((mini_icon && DO_EWMH_DONATE_MINI_ICON(fw)) ||
155 	    (icon && DO_EWMH_DONATE_ICON(fw)))
156 	{
157 		list = ewmh_AtomGetByName(
158 			FW_W(fw),"_NET_WM_ICON",
159 			EWMH_ATOM_LIST_PROPERTY_NOTIFY, &size);
160 	}
161 	else
162 	{
163 		return;
164 	}
165 
166 	/* we have to reset */
167 	if (icon && DO_EWMH_DONATE_ICON(fw))
168 	{
169 		if ((new_list = ewmh_SetWmIconFromPixmap(
170 			     fw, list, &size, False)) != NULL)
171 		{
172 			SET_HAS_EWMH_WM_ICON_HINT(fw, EWMH_FVWM_ICON);
173 		}
174 	}
175 	if (FMiniIconsSupported && mini_icon && DO_EWMH_DONATE_MINI_ICON(fw))
176 	{
177 		if ((dummy = ewmh_SetWmIconFromPixmap(
178 			     fw, (new_list != NULL)? new_list : list, &size,
179 			     True)) != NULL)
180 		{
181 			SET_HAS_EWMH_WM_ICON_HINT(fw, EWMH_FVWM_ICON);
182 			free(dummy);
183 		}
184 	}
185 	if (list != NULL)
186 	{
187 		free(list);
188 	}
189 	if (new_list != NULL)
190 	{
191 		free(new_list);
192 	}
193 }
194 
195 /*
196  * build and set a net icon from a pixmap
197  */
ewmh_SetWmIconFromPixmap(FvwmWindow * fw,CARD32 * orig_icon,int * orig_size,Bool is_mini_icon)198 CARD32 *ewmh_SetWmIconFromPixmap(
199 	FvwmWindow *fw, CARD32 *orig_icon, int *orig_size, Bool is_mini_icon)
200 {
201 	CARD32 *new_icon = NULL;
202 	int keep_start = 0, keep_length = 0;
203 	int width = 0, height = 0;
204 	int i,j,k,l,m;
205 	int s;
206 	Pixmap pixmap = None;
207 	Pixmap mask = None;
208 	Pixmap alpha = None;
209 	XImage *image;
210 	XImage *m_image = NULL;
211 	XImage *a_image = NULL;
212 	int save_picture_w_g_width = 0;
213 	int save_picture_w_g_height = 0;
214 	int save_icon_depth = 0;
215 	Pixmap save_icon_pixmap = None;
216 	Pixmap save_icon_mask = None;
217 	Pixmap save_icon_alpha = None;
218 	int save_icon_nalloc_pixels = 0;
219 	Pixel *save_icon_alloc_pixels = NULL;
220 	int save_icon_no_limit = 0;
221 	Window save_icon_pixmap_w = None;
222 	Bool is_pixmap_ours = False;
223 	Bool is_icon_ours = False;
224 	Bool is_icon_shaped = False;
225 	Bool destroy_icon_pix = False;
226 
227 	s = *orig_size / sizeof(CARD32);
228 	*orig_size = 0;
229 
230 	if (is_mini_icon)
231 	{
232 		if (FMiniIconsSupported && fw->mini_icon != NULL)
233 		{
234 			pixmap = fw->mini_icon->picture;
235 			mask = fw->mini_icon->mask;
236 			alpha = fw->mini_icon->alpha;
237 			width = fw->mini_icon->width;
238 			height = fw->mini_icon->height;
239 		}
240 	}
241 	else
242 	{
243 		/* should save and restore any iformation modified by
244 		 * a call to GetIconPicture */
245 		save_picture_w_g_width = fw->icon_g.picture_w_g.width;
246 		save_picture_w_g_height = fw->icon_g.picture_w_g.height;
247 		save_icon_depth = fw->iconDepth;
248 		save_icon_pixmap = fw->iconPixmap;
249 		save_icon_mask = fw->icon_maskPixmap;
250 		save_icon_alpha = fw->icon_alphaPixmap;
251 		save_icon_nalloc_pixels = fw->icon_nalloc_pixels;
252 		save_icon_alloc_pixels = fw->icon_alloc_pixels;
253 		save_icon_no_limit = fw->icon_no_limit;
254 		save_icon_pixmap_w =  FW_W_ICON_PIXMAP(fw);
255 		is_pixmap_ours = IS_PIXMAP_OURS(fw);
256 		is_icon_ours = IS_ICON_OURS(fw);
257 		is_icon_shaped = IS_ICON_SHAPED(fw);
258 		GetIconPicture(fw, True);
259 		if (IS_PIXMAP_OURS(fw))
260 		{
261 			destroy_icon_pix = True;
262 		}
263 		pixmap = fw->iconPixmap;
264 		mask = fw->icon_maskPixmap;
265 		alpha = fw->icon_alphaPixmap;
266 		width = fw->icon_g.picture_w_g.width;
267 		height = fw->icon_g.picture_w_g.height;
268 		if (fw->icon_alloc_pixels != NULL)
269 		{
270 			if (fw->icon_nalloc_pixels != 0)
271 			{
272 				PictureFreeColors(
273 					dpy, Pcmap, fw->icon_alloc_pixels,
274 					fw->icon_nalloc_pixels, 0,
275 					fw->icon_no_limit);
276 			}
277 			free(fw->icon_alloc_pixels);
278 		}
279 
280 		fw->icon_g.picture_w_g.width = save_picture_w_g_width;
281 		fw->icon_g.picture_w_g.height = save_picture_w_g_height;
282 		fw->iconDepth = save_icon_depth;
283 		fw->iconPixmap = save_icon_pixmap;
284 		fw->icon_maskPixmap = save_icon_mask;
285 		fw->icon_alphaPixmap = save_icon_alpha;
286 		fw->icon_nalloc_pixels = save_icon_nalloc_pixels;
287 		fw->icon_alloc_pixels = save_icon_alloc_pixels;
288 		fw->icon_no_limit = save_icon_no_limit;
289 		FW_W_ICON_PIXMAP(fw) = save_icon_pixmap_w;
290 		SET_ICON_OURS(fw, is_icon_ours);
291 		SET_PIXMAP_OURS(fw, is_pixmap_ours);
292 		SET_ICON_SHAPED(fw, is_icon_shaped);
293 	}
294 
295 	if (pixmap == None)
296 	{
297 		return NULL;
298 	}
299 
300 	if (FMiniIconsSupported && orig_icon != NULL)
301 	{
302 		int k_width = (is_mini_icon)?
303 			fw->ewmh_icon_width : fw->ewmh_mini_icon_width;
304 		int k_height = (is_mini_icon)?
305 			fw->ewmh_icon_height : fw->ewmh_mini_icon_height;
306 
307 		for (i = 0; i < s - 1 && i >= 0; )
308 		{
309 			if (i + 1 + orig_icon[i]*orig_icon[i+1] < s)
310 			{
311 				if (orig_icon[i] == k_width &&
312 				    orig_icon[i+1] == k_height)
313 				{
314 					keep_start = i;
315 					keep_length = 2 +
316 						orig_icon[i] * orig_icon[i+1];
317 					i = s;
318 				}
319 			}
320 			if (i != s && orig_icon[i]*orig_icon[i+1] > 0)
321 			{
322 				i = i + 2 + orig_icon[i]*orig_icon[i+1];
323 			}
324 			else
325 			{
326 				i = s;
327 			}
328 		}
329 	}
330 
331 	image = XGetImage(
332 		dpy, pixmap, 0, 0, width, height, AllPlanes, ZPixmap);
333 	if (image == NULL)
334 	{
335 		fvwm_msg(
336 			ERR, "EWMH_SetWmIconFromPixmap",
337 			"cannot create XImage\n");
338 		if (destroy_icon_pix)
339 		{
340 			XFreePixmap(dpy, pixmap);
341 			if (mask != None)
342 			{
343 				XFreePixmap(dpy, mask);
344 			}
345 			if (alpha != None)
346 			{
347 				XFreePixmap(dpy, alpha);
348 			}
349 		}
350 		return NULL;
351 	}
352 
353 	if (mask != None)
354 	{
355 		m_image = XGetImage(dpy, mask, 0, 0, width, height,
356 				    AllPlanes, ZPixmap);
357 	}
358 	if (alpha != None)
359 	{
360 		a_image = XGetImage(dpy, alpha, 0, 0, width, height,
361 				    AllPlanes, ZPixmap);
362 	}
363 	*orig_size = (height*width + 2 + keep_length) * sizeof(CARD32);
364 	new_icon = (CARD32 *)safemalloc(*orig_size);
365 	if (keep_length > 0)
366 	{
367 		memcpy(new_icon, &orig_icon[keep_start],
368 		       keep_length * sizeof(CARD32));
369 	}
370 	new_icon[keep_length] = width;
371 	new_icon[1+keep_length] = height;
372 
373 	k = 0;
374 	l = (2 + keep_length);
375 	m = 0;
376 
377 	switch(image->depth)
378 	{
379 	case 1:
380 	{
381 		XColor colors[2];
382 		CARD32 fg, bg;
383 
384 		colors[0].pixel = fw->colors.fore;
385 		colors[1].pixel = fw->colors.back;
386 		XQueryColors(dpy, Pcmap, colors, 2);
387 		fg = 0xff000000 + (((colors[0].red >> 8) & 0xff) << 16) +
388 			(((colors[0].green >> 8) & 0xff) << 8) +
389 			((colors[0].blue >> 8) & 0xff);
390 		bg = 0xff000000 + (((colors[1].red >> 8) & 0xff) << 16) +
391 			(((colors[1].green >> 8) & 0xff) << 8) +
392 			((colors[1].blue >> 8) & 0xff);
393 		for (j = 0; j < height; j++)
394 		{
395 			for (i = 0; i < width; i++)
396 			{
397 				if (m_image != NULL &&
398 				    (XGetPixel(m_image, i, j) == 0))
399 				{
400 					new_icon[l++] = 0;
401 				}
402 				else if (XGetPixel(image, i, j) == 0)
403 				{
404 					new_icon[l++] = bg;
405 				}
406 				else
407 				{
408 					new_icon[l++] = fg;
409 				}
410 			}
411 		}
412 		break;
413 
414 	}
415 	default: /* depth = Pdepth */
416 	{
417 		unsigned char *cm;
418 		XColor *colors;
419 
420 		colors = (XColor *)safemalloc(width * height * sizeof(XColor));
421 		cm = (unsigned char *)safemalloc(
422 			width * height * sizeof(char));
423 		for (j = 0; j < height; j++)
424 		{
425 			for (i = 0; i < width; i++)
426 			{
427 				if (m_image != NULL &&
428 				    (XGetPixel(m_image, i, j) == 0))
429 				{
430 					cm[m++] = 0;
431 				}
432 				else if (a_image != NULL)
433 				{
434 					cm[m++] = (unsigned char)XGetPixel(
435 						a_image, i, j);
436 					colors[k++].pixel = XGetPixel(
437 						image, i, j);
438 				}
439 				else
440 				{
441 					cm[m++] = 255;
442 					colors[k++].pixel = XGetPixel(
443 						image, i, j);
444 				}
445 			}
446 		}
447 		for (i = 0; i < k; i += 256)
448 			XQueryColors(dpy, Pcmap, &colors[i], min(k - i, 256));
449 
450 		k = 0;m = 0;
451 		for (j = 0; j < height; j++)
452 		{
453 			for (i = 0; i < width; i++)
454 			{
455 				if (cm[m] > 0)
456 				{
457 					new_icon[l++] =
458 						((cm[m] & 0xff) << 24) +
459 						(((colors[k].red >> 8) & 0xff)
460 						 << 16) +
461 						(((colors[k].green >> 8) &
462 						  0xff) << 8) +
463 						((colors[k].blue >> 8) & 0xff);
464 					k++;
465 				}
466 				else
467 				{
468 					new_icon[l++] = 0;
469 				}
470 				m++;
471 			}
472 		}
473 		free(colors);
474 		free(cm);
475 		break;
476 	}
477 	} /* switch */
478 
479 
480 	if (is_mini_icon)
481 	{
482 		fw->ewmh_mini_icon_width = width;
483 		fw->ewmh_mini_icon_height = height;
484 	}
485 	else
486 	{
487 		fw->ewmh_icon_width = width;
488 		fw->ewmh_icon_height = height;
489 	}
490 
491 	ewmh_ChangeProperty(
492 		FW_W(fw), "_NET_WM_ICON", EWMH_ATOM_LIST_PROPERTY_NOTIFY,
493 		(unsigned char *)new_icon, height*width + 2 + keep_length);
494 
495 	if (destroy_icon_pix)
496 	{
497 		XFreePixmap(dpy, pixmap);
498 		if (mask != None)
499 		{
500 			XFreePixmap(dpy, mask);
501 		}
502 		if (alpha != None)
503 		{
504 			XFreePixmap(dpy, alpha);
505 		}
506 	}
507 
508 	XDestroyImage(image);
509 	if (m_image != None)
510 	{
511 		XDestroyImage(m_image);
512 	}
513 	if (a_image != None)
514 	{
515 		XDestroyImage(a_image);
516 	}
517 
518 	return new_icon;
519 }
520 
521 /*
522  * delete the mini icon and/or the icon from a ewmh icon
523  */
EWMH_DeleteWmIcon(FvwmWindow * fw,Bool mini_icon,Bool icon)524 void EWMH_DeleteWmIcon(FvwmWindow *fw, Bool mini_icon, Bool icon)
525 {
526 	CARD32 *list;
527 	CARD32 *new_list = NULL;
528 	int keep_start = 0, keep_length = 0;
529 	int s;
530 	int i;
531 
532 	if (mini_icon && icon)
533 	{
534 		ewmh_DeleteProperty(
535 			FW_W(fw), "_NET_WM_ICON",
536 			EWMH_ATOM_LIST_PROPERTY_NOTIFY);
537 		fw->ewmh_mini_icon_width = 0;
538 		fw->ewmh_mini_icon_height = 0;
539 		fw->ewmh_icon_width = 0;
540 		fw->ewmh_icon_height = 0;
541 		/*SET_HAS_EWMH_WM_ICON_HINT(fw, EWMH_NO_ICON);*/
542 		return;
543 	}
544 
545 	list = ewmh_AtomGetByName(
546 		FW_W(fw),"_NET_WM_ICON", EWMH_ATOM_LIST_PROPERTY_NOTIFY, &s);
547 	if (list == NULL)
548 	{
549 		return;
550 	}
551 	s = s / sizeof(CARD32);
552 
553 	if (FMiniIconsSupported && list != NULL)
554 	{
555 		int k_width = (mini_icon) ? fw->ewmh_icon_width :
556 			fw->ewmh_mini_icon_width;
557 		int k_height = (mini_icon) ? fw->ewmh_icon_height :
558 			fw->ewmh_mini_icon_height;
559 
560 		for (i = 0; i < s - 1; )
561 		{
562 			if (i + 1 + list[i]*list[i+1] < s)
563 			{
564 				if (list[i] == k_width &&
565 				    list[i+1] == k_height)
566 				{
567 					keep_start = i;
568 					keep_length =  2 + list[i]*list[i+1];
569 					i = s;
570 				}
571 			}
572 			if (i != s && list[i]*list[i+1] > 0)
573 			{
574 				i = i + 2 + list[i]*list[i+1];
575 			}
576 			else
577 			{
578 				i = s;
579 			}
580 		}
581 	}
582 
583 	if (keep_length > 0)
584 	{
585 		new_list = (CARD32 *)safemalloc(keep_length * sizeof(CARD32));
586 		memcpy(
587 			new_list, &list[keep_start],
588 			keep_length * sizeof(CARD32));
589 	}
590 
591 	if (new_list != NULL)
592 	{
593 		ewmh_ChangeProperty(
594 			FW_W(fw),"_NET_WM_ICON",
595 			EWMH_ATOM_LIST_PROPERTY_NOTIFY,
596 			(unsigned char *)new_list, keep_length);
597 	}
598 	else
599 	{
600 		/*SET_HAS_EWMH_WM_ICON_HINT(fw, EWMH_NO_ICON);*/
601 		ewmh_DeleteProperty(
602 			FW_W(fw), "_NET_WM_ICON",
603 			EWMH_ATOM_LIST_PROPERTY_NOTIFY);
604 	}
605 
606 	if (mini_icon)
607 	{
608 		fw->ewmh_mini_icon_width = 0;
609 		fw->ewmh_mini_icon_height = 0;
610 	}
611 	if (icon)
612 	{
613 		fw->ewmh_icon_width = 0;
614 		fw->ewmh_icon_height = 0;
615 	}
616 	if (new_list != NULL)
617 	{
618 		free(new_list);
619 	}
620 	free(list);
621 }
622 
623 /*
624  * Create an x image from a NET icon
625  */
626 
627 #define SQUARE(X) ((X)*(X))
628 static
extract_wm_icon(CARD32 * list,int size,int wanted_w,int wanted_h,int * start_best,int * best_w,int * best_h)629 void extract_wm_icon(
630 	CARD32 *list, int size, int wanted_w, int wanted_h,
631 	int *start_best, int *best_w, int *best_h)
632 {
633 	int i;
634 	int dist = 0;
635 
636 	*start_best = 0;
637 	*best_w = 0;
638 	*best_h = 0;
639 	size = size / (sizeof(CARD32));
640 
641 	for (i = 0; i < size - 1; )
642 	{
643 		if (i + 1 + list[i]*list[i+1] < size)
644 		{
645 			if (*best_w == 0 && *best_h == 0)
646 			{
647 				*start_best = i+2;
648 				*best_w = list[i];
649 				*best_h = list[i+1];
650 				dist = SQUARE(
651 					list[i]-wanted_w) +
652 					SQUARE(list[i+1]-wanted_h);
653 			}
654 			else if (SQUARE(list[i]-wanted_w) +
655 				 SQUARE(list[i+1]-wanted_h) < dist)
656 			{
657 				*start_best = i+2;
658 				*best_w = list[i];
659 				*best_h = list[i+1];
660 				dist = SQUARE(
661 					list[i]-wanted_w) +
662 					SQUARE(list[i+1]-wanted_h);
663 			}
664 		}
665 		if (list[i]*list[i+1] > 0)
666 		{
667 			i = i + 2 + list[i]*list[i+1];
668 		}
669 		else
670 		{
671 			i = size;
672 		}
673 	}
674 
675 	return;
676 }
677 
678 #define MINI_ICON_WANTED_WIDTH  16
679 #define MINI_ICON_WANTED_HEIGHT 16
680 #define MINI_ICON_MAX_WIDTH 22
681 #define MINI_ICON_MAX_HEIGHT 22
682 #define ICON_WANTED_WIDTH 56
683 #define ICON_WANTED_HEIGHT 56
684 #define ICON_MAX_WIDTH 100
685 #define ICON_MAX_HEIGHT 100
686 
EWMH_SetIconFromWMIcon(FvwmWindow * fw,CARD32 * list,int size,Bool is_mini_icon)687 int EWMH_SetIconFromWMIcon(
688 	FvwmWindow *fw, CARD32 *list, int size, Bool is_mini_icon)
689 {
690 	int start, width, height;
691 	int wanted_w, wanted_h;
692 	int max_w, max_h;
693 	Pixmap pixmap = None;
694 	Pixmap mask = None;
695 	Pixmap alpha = None;
696 	Bool free_list = False;
697 	int nalloc_pixels;
698 	Pixel *alloc_pixels;
699 	int no_limit;
700 	FvwmPictureAttributes fpa;
701 
702 	if (list == NULL)
703 	{
704 		/* we are called from icons.c or update.c */
705 		list = ewmh_AtomGetByName(
706 			FW_W(fw),"_NET_WM_ICON",
707 			EWMH_ATOM_LIST_PROPERTY_NOTIFY, &size);
708 		free_list = True;
709 		if (list == NULL)
710 		{
711 			return 0;
712 		}
713 	}
714 
715 	if (is_mini_icon)
716 	{
717 		wanted_w = MINI_ICON_WANTED_WIDTH;
718 		wanted_h = MINI_ICON_WANTED_HEIGHT;
719 		max_w = MINI_ICON_MAX_WIDTH;
720 		max_h = ICON_MAX_HEIGHT;
721 		fpa.mask = 0;
722 	}
723 	else
724 	{
725 		wanted_w = ICON_WANTED_WIDTH;
726 		wanted_h = ICON_WANTED_HEIGHT;
727 		max_w = ICON_MAX_WIDTH;
728 		max_h = ICON_MAX_HEIGHT;
729 		if (fw->cs >= 0 && Colorset[fw->cs].do_dither_icon)
730 		{
731 			fpa.mask = FPAM_DITHER;
732 		}
733 		else
734 		{
735 			fpa.mask = 0;
736 		}
737 	}
738 
739 	extract_wm_icon(
740 		list, size, wanted_w, wanted_h, &start, &width, &height);
741 	if (width == 0 || height == 0)
742 	{
743 		if (free_list)
744 		{
745 			free(list);
746 		}
747 		return 0;
748 	}
749 
750 	if (!PImageCreatePixmapFromArgbData(
751 		dpy, Scr.NoFocusWin, list, start, width, height,
752 		&pixmap, &mask, &alpha, &nalloc_pixels,
753 		&alloc_pixels, &no_limit, fpa))
754 	{
755 		fvwm_msg(ERR, "EWMH_SetIconFromWMIcon",
756 			 "fail to create a pixmap\n");
757 		if (free_list)
758 		{
759 			free(list);
760 		}
761 		return 0;
762 	}
763 
764 	if (width > max_w || height > max_h)
765 	{
766 		Pixmap np = None,nm =None, na = None;
767 
768 		if (pixmap)
769 		{
770 			np = CreateStretchPixmap(
771 				dpy, pixmap, width, height, Pdepth, wanted_w,
772 				wanted_h, Scr.TitleGC);
773 			XFreePixmap(dpy, pixmap);
774 			pixmap = np;
775 		}
776 		if (mask)
777 		{
778 			nm = CreateStretchPixmap(
779 				dpy, mask, width, height, 1, wanted_w,
780 				wanted_h, Scr.MonoGC);
781 			XFreePixmap(dpy, mask);
782 			mask = nm;
783 		}
784 		if (alpha)
785 		{
786 			na = CreateStretchPixmap(
787 				dpy, alpha, width, height,
788 				FRenderGetAlphaDepth(), wanted_w, wanted_h,
789 				Scr.AlphaGC);
790 			XFreePixmap(dpy, alpha);
791 			alpha = na;
792 		}
793 		width = wanted_w;
794 		height = wanted_h;
795 	}
796 	if (FMiniIconsSupported && is_mini_icon &&
797 	    !DO_EWMH_MINI_ICON_OVERRIDE(fw))
798 	{
799 		char *name = NULL;
800 
801 		CopyString(&name,"ewmh_mini_icon");
802 		if (fw->mini_icon)
803 		{
804 			PDestroyFvwmPicture(dpy,fw->mini_icon);
805 			fw->mini_icon = 0;
806 		}
807 		fw->mini_icon = PCacheFvwmPictureFromPixmap(
808 			dpy, Scr.NoFocusWin, name, pixmap,mask,alpha, width,
809 			height, nalloc_pixels, alloc_pixels, no_limit);
810 		if (fw->mini_icon != NULL)
811 		{
812 			fw->mini_pixmap_file = name;
813 			BroadcastFvwmPicture(
814 				M_MINI_ICON, FW_W(fw), FW_W_FRAME(fw),
815 				(unsigned long)fw, fw->mini_icon,
816 				fw->mini_pixmap_file);
817 			border_redraw_decorations(fw);
818 		}
819 	}
820 	if (!is_mini_icon)
821 	{
822 		fw->iconPixmap = pixmap;
823 		fw->icon_maskPixmap = mask;
824 		fw->icon_alphaPixmap = alpha;
825 		fw->icon_nalloc_pixels = nalloc_pixels;
826 		fw->icon_alloc_pixels = alloc_pixels;
827 		fw->icon_no_limit = no_limit;
828 		fw->icon_g.picture_w_g.width = width;
829 		fw->icon_g.picture_w_g.height = height;
830 		fw->iconDepth = Pdepth;
831 		SET_PIXMAP_OURS(fw, 1);
832 		if (FShapesSupported && mask)
833 		{
834 			SET_ICON_SHAPED(fw, 1);
835 		}
836 	}
837 	if (free_list)
838 	{
839 		free(list);
840 	}
841 	return 1;
842 }
843