NEWS/Changelog for previous commit.
[fvwm.git] / fvwm / icons.c
bloba9199b8e0f4b5b3733a61dc9e677737c6831b43c
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * This module is mostly all new
19 * by Rob Nation
20 * A little of it is borrowed from ctwm.
21 * Copyright 1993 Robert Nation. No restrictions are placed on this code,
22 * as long as the copyright notice is preserved
26 * fvwm icon code
30 #include "config.h"
32 #include <stdio.h>
33 #ifdef HAVE_FCNTL_H
34 #include <fcntl.h>
35 #endif
37 #include "libs/fvwmlib.h"
38 #include "libs/FScreen.h"
39 #include "libs/FShape.h"
40 #include "libs/Parse.h"
41 #include "libs/Picture.h"
42 #include "libs/Graphics.h"
43 #include "libs/PictureGraphics.h"
44 #include "libs/FRenderInit.h"
45 #include "libs/Rectangles.c"
46 #include "libs/charmap.h"
47 #include "libs/wcontext.h"
48 #include "fvwm.h"
49 #include "externs.h"
50 #include "cursor.h"
51 #include "execcontext.h"
52 #include "commands.h"
53 #include "bindings.h"
54 #include "events.h"
55 #include "eventmask.h"
56 #include "eventhandler.h"
57 #include "misc.h"
58 #include "screen.h"
59 #include "icons.h"
60 #include "borders.h"
61 #include "frame.h"
62 #include "focus.h"
63 #include "colormaps.h"
64 #include "stack.h"
65 #include "virtual.h"
66 #include "decorations.h"
67 #include "module_interface.h"
68 #include "gnome.h"
69 #include "ewmh.h"
70 #include "geometry.h"
72 static int do_all_iconboxes(FvwmWindow *t, icon_boxes **icon_boxes_ptr);
73 static void GetIconFromFile(FvwmWindow *fw);
74 static void GetIconWindow(FvwmWindow *fw);
75 static void GetIconBitmap(FvwmWindow *fw);
77 static void clear_icon_dimensions(FvwmWindow *fw)
79 int px;
80 int py;
81 int tx;
82 int ty;
84 px = fw->icon_g.picture_w_g.x;
85 py = fw->icon_g.picture_w_g.y;
86 tx = fw->icon_g.title_w_g.x;
87 ty = fw->icon_g.title_w_g.y;
88 memset(&fw->icon_g, 0, sizeof(fw->icon_g));
89 fw->icon_g.picture_w_g.x = px;
90 fw->icon_g.picture_w_g.y = py;
91 fw->icon_g.title_w_g.x = tx;
92 fw->icon_g.title_w_g.y = ty;
94 return;
96 /* erase all traces of the last used icon in the window structure */
97 void clear_icon(FvwmWindow *fw)
99 FW_W_ICON_PIXMAP(fw) = None;
100 fw->iconPixmap = None;
101 fw->icon_maskPixmap = None;
102 fw->icon_alphaPixmap = None;
103 fw->icon_nalloc_pixels = 0;
104 fw->icon_alloc_pixels = NULL;
105 fw->icon_no_limit = 0;
106 if (IS_ICON_MOVED(fw))
108 clear_icon_dimensions(fw);
110 else
112 memset(&fw->icon_g, 0, sizeof(fw->icon_g));
115 return;
118 int get_visible_icon_window_count(FvwmWindow *fw)
120 int count = 0;
122 if (fw == NULL || !IS_ICONIFIED(fw) ||
123 IS_ICON_SUPPRESSED(fw))
125 return 0;
127 if (FW_W_ICON_PIXMAP(fw) != None)
129 count++;
131 if (FW_W_ICON_TITLE(fw) != None)
133 count++;
136 return count;
139 void setup_icon_title_size(FvwmWindow *fw)
141 if (HAS_NO_ICON_TITLE(fw))
143 fw->icon_g.title_text_width = 0;
144 fw->icon_g.title_w_g.width = 0;
145 fw->icon_g.title_w_g.height = 0;
147 else
149 fw->icon_g.title_text_width =
150 FlocaleTextWidth(
151 fw->icon_font, fw->visible_icon_name,
152 strlen(fw->visible_icon_name));
153 fw->icon_g.title_w_g.height = ICON_HEIGHT(fw);
154 if (fw->icon_g.picture_w_g.width == 0)
156 fw->icon_g.title_w_g.width =
157 fw->icon_g.title_text_width +
158 2 * (ICON_TITLE_TEXT_GAP_COLLAPSED +
159 abs(fw->icon_title_relief));
160 if (IS_STICKY_ACROSS_PAGES(fw) ||
161 IS_ICON_STICKY_ACROSS_PAGES(fw) ||
162 IS_STICKY_ACROSS_DESKS(fw) ||
163 IS_ICON_STICKY_ACROSS_DESKS(fw))
165 fw->icon_g.title_w_g.width +=
166 2 * (ICON_TITLE_TO_STICK_EXTRA_GAP +
167 ICON_TITLE_STICK_MIN_WIDTH);
170 else
172 fw->icon_g.title_w_g.width =
173 fw->icon_g.picture_w_g.width;
177 return;
182 * Resizes the given icon Pixmap.
185 static void SetIconPixmapSize(
186 Pixmap *icon, int width, int height, int depth, int newWidth,
187 int newHeight, Bool force_centering, int resize_type, int *nrx,
188 int *nry, int freeOldPixmap)
190 Pixmap oldPixmap;
191 Pixmap resizedPixmap = None;
192 int r_w,r_h;
193 GC gc;
194 XGCValues gc_init;
196 *nrx = 0;
197 *nry = 0;
199 /* Check for invalid dimensions */
200 if (newWidth == 0 || newHeight == 0)
202 return;
205 /* Save the existing Pixmap */
206 oldPixmap = *icon;
208 gc = XCreateGC(dpy, oldPixmap, 0, &gc_init);
210 switch(resize_type)
212 case ICON_RESIZE_TYPE_ADJUSTED:
213 if (newWidth != width || newHeight != height)
215 *icon = CreateStretchPixmap(
216 dpy, oldPixmap, width, height, depth, newWidth,
217 newHeight, gc);
219 break;
220 case ICON_RESIZE_TYPE_STRETCHED:
221 if (width < newWidth || height < newHeight)
223 r_w = max(newWidth, width);
224 r_h = max(newHeight, height);
225 resizedPixmap = CreateStretchPixmap(
226 dpy, oldPixmap, width, height, depth, r_w, r_h,
227 gc);
228 width = r_w;
229 height = r_h;
231 break;
232 case ICON_RESIZE_TYPE_SHRUNK:
233 if (width > newWidth || height > newHeight)
235 r_w = min(newWidth, width);
236 r_h = min(newHeight, height);
237 resizedPixmap = CreateStretchPixmap(
238 dpy, oldPixmap, width, height, depth, r_w, r_h,
239 gc);
240 width = r_w;
241 height = r_h;
243 break;
244 default:
245 break;
248 if (resize_type != ICON_RESIZE_TYPE_ADJUSTED)
250 *icon = XCreatePixmap(
251 dpy, oldPixmap, newWidth, newHeight, depth);
252 XSetForeground(dpy, gc, 0);
253 XFillRectangle(dpy, *icon, gc, 0, 0, newWidth, newHeight);
256 * Copy old Pixmap onto new. Center horizontally. Center
257 * vertically if the new height is smaller than the old.
258 * Otherwise, place the icon on the bottom, along the title bar.
260 *nrx = (newWidth - width) / 2;
261 *nry = (newHeight > height && !force_centering) ?
262 newHeight - height : (newHeight - height) / 2;
263 XCopyArea(
264 dpy, (resizedPixmap)? resizedPixmap:oldPixmap, *icon,
265 gc, 0, 0, width, height, *nrx, *nry);
268 XFreeGC(dpy, gc);
270 if (freeOldPixmap)
272 XFreePixmap(dpy, oldPixmap);
276 /* Move the icon of a window by dx/dy pixels */
279 * Get the Icon for the icon window (also used by ewmh_icon)
282 void GetIconPicture(FvwmWindow *fw, Bool no_icon_window)
284 char icon_order[4];
285 int i;
287 /* First, see if it was specified in the .fvwmrc */
288 if (ICON_OVERRIDE_MODE(fw) == ICON_OVERRIDE)
290 /* try fvwm provided icons before application provided icons */
291 icon_order[0] = 0;
292 icon_order[1] = 1;
293 icon_order[2] = 2;
294 icon_order[3] = 3;
295 ICON_DBG((stderr,"ciw: hint order: file iwh iph '%s'\n", fw->name));
297 else if (ICON_OVERRIDE_MODE(fw) == NO_ACTIVE_ICON_OVERRIDE)
299 if (fw->wmhints && (fw->wmhints->flags & IconPixmapHint) &&
300 WAS_ICON_HINT_PROVIDED(fw) == ICON_HINT_MULTIPLE)
302 /* use application provided icon window or pixmap
303 * first, then fvwm provided icons. */
304 icon_order[0] = 1;
305 icon_order[1] = 2;
306 icon_order[2] = 3;
307 icon_order[3] = 0;
308 ICON_DBG((stderr,"ciw: hint order: iwh iph file '%s'\n", fw->name));
310 else if (Scr.DefaultIcon &&
311 fw->icon_bitmap_file == Scr.DefaultIcon)
313 /* use application provided icon window/pixmap first,
314 * then fvwm provided default icon */
315 icon_order[0] = 1;
316 icon_order[1] = 2;
317 icon_order[2] = 3;
318 icon_order[3] = 0;
319 ICON_DBG((stderr,"ciw: hint order: iwh iph file '%s'\n", fw->name));
321 else
323 /* use application provided icon window or ewmh icon
324 * first, then fvwm provided icons and then application
325 * provided icon pixmap */
326 icon_order[0] = 1;
327 icon_order[1] = 2;
328 icon_order[2] = 0;
329 icon_order[3] = 3;
330 ICON_DBG((stderr,"ciw: hint order: iwh file iph '%s'\n", fw->name));
333 else
335 /* use application provided icon rather than fvwm provided
336 * icon */
337 icon_order[0] = 1;
338 icon_order[1] = 2;
339 icon_order[2] = 3;
340 icon_order[3] = 0;
341 ICON_DBG((stderr,"ciw: hint order: iwh iph file '%s'\n", fw->name));
344 fw->icon_g.picture_w_g.width = 0;
345 fw->icon_g.picture_w_g.height = 0;
346 fw->iconPixmap = None;
347 fw->icon_maskPixmap = None;
348 fw->icon_alphaPixmap= None;
349 FW_W_ICON_PIXMAP(fw) = None;
350 for (i = 0; i < 4 && fw->icon_g.picture_w_g.width == 0 &&
351 fw->icon_g.picture_w_g.height == 0; i++)
353 switch (icon_order[i])
355 case 0:
356 /* Next, check for a color pixmap */
357 if (fw->icon_bitmap_file)
359 GetIconFromFile(fw);
361 ICON_DBG((stderr,"ciw: file%s used '%s'\n", (fw->icon_g.picture_w_g.height)?"":" not", fw->name));
362 break;
363 case 1:
364 /* Next, See if the app supplies its own icon window */
365 if (no_icon_window)
367 break;
369 if (fw->wmhints &&
370 (fw->wmhints->flags & IconWindowHint))
372 GetIconWindow(fw);
374 ICON_DBG((stderr,"ciw: iwh%s used '%s'\n", (fw->icon_g.picture_w_g.height)?"":" not",fw->name));
375 break;
376 case 2:
377 /* try an ewmh icon */
378 if (HAS_EWMH_WM_ICON_HINT(fw) == EWMH_TRUE_ICON)
380 if (EWMH_SetIconFromWMIcon(fw, NULL, 0, False))
382 SET_USE_EWMH_ICON(fw, True);
385 ICON_DBG((stderr,"ciw: inh%s used '%s'\n", (fw->icon_g.picture_w_g.height)?"":" not",fw->name));
386 break;
387 case 3:
388 /* Finally, try to get icon bitmap from the
389 * application */
390 if (fw->wmhints &&
391 (fw->wmhints->flags & IconPixmapHint))
393 GetIconBitmap(fw);
395 ICON_DBG((stderr,"ciw: iph%s used '%s'\n", (fw->icon_g.picture_w_g.height)?"":" not",fw->name));
396 break;
397 default:
398 /* can't happen */
399 break;
403 /* Resize icon if necessary */
404 if ((IS_ICON_OURS(fw)) && fw->icon_g.picture_w_g.height > 0 &&
405 fw->icon_g.picture_w_g.height > 0)
407 int newWidth = fw->icon_g.picture_w_g.width;
408 int newHeight = fw->icon_g.picture_w_g.height;
409 Boolean resize = False;
411 if (newWidth < fw->min_icon_width)
413 newWidth = fw->min_icon_width;
414 resize = True;
416 else
418 if (newWidth > fw->max_icon_width)
420 newWidth = fw->max_icon_width;
421 resize = True;
424 if (newHeight < fw->min_icon_height)
426 newHeight = fw->min_icon_height;
427 resize = True;
429 else
431 if (newHeight > fw->max_icon_height)
433 newHeight = fw->max_icon_height;
434 resize = True;
437 if (resize)
439 /* Resize the icon Pixmap */
440 int force_centering = False;
441 int nrx, nry;
443 ICON_DBG((stderr,"ciw: Changing icon (%s) from %dx%d to"
444 " %dx%d\n", fw->name,
445 fw->icon_g.picture_w_g.width,
446 fw->icon_g.picture_w_g.height,
447 newWidth, newHeight));
448 /* Resize the icon Pixmap */
449 /* force to center if the icon has a bg */
450 if (fw->icon_background_cs >= 0 ||
451 fw->icon_maskPixmap == None)
453 force_centering = True;
455 SetIconPixmapSize(
456 &(fw->iconPixmap),
457 fw->icon_g.picture_w_g.width,
458 fw->icon_g.picture_w_g.height, fw->iconDepth,
459 newWidth, newHeight, force_centering,
460 fw->icon_resize_type, &nrx, &nry,
461 IS_PIXMAP_OURS(fw));
463 /* Resize the icon mask Pixmap if one was defined */
464 if (fw->icon_maskPixmap)
466 SetIconPixmapSize(
467 &(fw->icon_maskPixmap),
468 fw->icon_g.picture_w_g.width,
469 fw->icon_g.picture_w_g.height, 1,
470 newWidth, newHeight, force_centering,
471 fw->icon_resize_type, &nrx, &nry,
472 IS_PIXMAP_OURS(fw));
474 else if ((nrx > 0 || nry > 0) && fw->iconDepth > 1)
476 fw->icon_maskPixmap = XCreatePixmap(
477 dpy, fw->iconPixmap,
478 newWidth, newHeight, 1);
479 XSetForeground(dpy, Scr.MonoGC, 0);
480 XFillRectangle(
481 dpy, fw->icon_maskPixmap, Scr.MonoGC,
482 0, 0, newWidth, newHeight);
483 XSetForeground(dpy, Scr.MonoGC, 1);
484 XFillRectangle(
485 dpy, fw->icon_maskPixmap, Scr.MonoGC,
486 nrx, nry, fw->icon_g.picture_w_g.width,
487 fw->icon_g.picture_w_g.height);
488 XSetForeground(dpy, Scr.MonoGC, 0);
489 /* set it shaped ? YES */
490 SET_ICON_SHAPED(fw, 1);
493 /* Resize the icon alpha Pixmap if one was defined */
494 if (fw->icon_alphaPixmap)
496 SetIconPixmapSize(
497 &(fw->icon_alphaPixmap),
498 fw->icon_g.picture_w_g.width,
499 fw->icon_g.picture_w_g.height,
500 FRenderGetAlphaDepth(), newWidth,
501 newHeight, force_centering,
502 fw->icon_resize_type, &nrx, &nry,
503 IS_PIXMAP_OURS(fw));
506 /* Set the new dimensions of the icon window */
507 fw->icon_g.picture_w_g.width = newWidth;
508 fw->icon_g.picture_w_g.height = newHeight;
512 return;
517 * set the icon pixmap window background
520 static void set_icon_pixmap_background(FvwmWindow *fw)
522 if (fw->iconPixmap != None &&
523 (Pdefault || fw->iconDepth == 1 || fw->iconDepth == Pdepth ||
524 IS_PIXMAP_OURS(fw)))
526 if (fw->icon_background_cs >= 0)
528 SetWindowBackground(
529 dpy, FW_W_ICON_PIXMAP(fw),
530 fw->icon_g.picture_w_g.width,
531 fw->icon_g.picture_w_g.height,
532 &Colorset[fw->icon_background_cs],
533 Pdepth, Scr.StdGC, False);
535 else if (FShapesSupported &&
536 Pdepth == DefaultDepth(dpy, (DefaultScreen(dpy))))
538 XSetWindowBackgroundPixmap(
539 dpy, FW_W_ICON_PIXMAP(fw), ParentRelative);
541 else if (Scr.DefaultColorset >= 0)
543 SetWindowBackground(
544 dpy, FW_W_ICON_PIXMAP(fw),
545 fw->icon_g.picture_w_g.width,
546 fw->icon_g.picture_w_g.height,
547 &Colorset[Scr.DefaultColorset], Pdepth,
548 Scr.StdGC, False);
555 * Creates an icon window as needed
558 void CreateIconWindow(FvwmWindow *fw, int def_x, int def_y)
560 /* mask for create windows */
561 unsigned long valuemask;
562 /* attributes for create windows */
563 XSetWindowAttributes attributes;
564 XWindowChanges xwc;
565 Window old_icon_pixmap_w;
566 Window old_icon_w;
567 Bool is_old_icon_shaped = IS_ICON_SHAPED(fw);
569 old_icon_w = FW_W_ICON_TITLE(fw);
570 old_icon_pixmap_w = (IS_ICON_OURS(fw)) ? FW_W_ICON_PIXMAP(fw) : None;
571 if (!IS_ICON_OURS(fw) && FW_W_ICON_PIXMAP(fw))
573 XUnmapWindow(dpy, FW_W_ICON_PIXMAP(fw));
575 SET_ICON_OURS(fw, 1);
576 SET_PIXMAP_OURS(fw, 0);
577 SET_ICON_SHAPED(fw, 0);
578 FW_W_ICON_PIXMAP(fw) = None;
579 fw->iconPixmap = None;
580 fw->iconDepth = 0;
582 if (IS_ICON_SUPPRESSED(fw))
584 return;
588 * set up the icon picture
590 GetIconPicture(fw, False);
591 /* make space for relief to be drawn outside the icon */
592 /* this does not happen if fvwm is using a non-default visual (with
593 * private colormap) and the client has supplied a pixmap (not a
594 * bitmap) */
595 if ((IS_ICON_OURS(fw)) && (fw->icon_g.picture_w_g.height > 0)
596 && (Pdefault || fw->iconDepth == 1 || fw->iconDepth == Pdepth ||
597 IS_PIXMAP_OURS(fw)))
599 fw->icon_g.picture_w_g.width +=
600 2 * abs(fw->icon_background_relief)
601 + 2 * fw->icon_background_padding;
602 fw->icon_g.picture_w_g.height +=
603 2 * abs(fw->icon_background_relief)
604 + 2 * fw->icon_background_padding;
608 * set up the icon title geometry
610 setup_icon_title_size(fw);
613 * set up icon position
615 set_icon_position(fw, def_x, def_y);
618 * create the icon title window
620 valuemask = CWColormap | CWBorderPixel | CWBackPixel | CWCursor |
621 CWEventMask;
622 attributes.colormap = Pcmap;
623 attributes.background_pixel = Scr.StdBack;
624 attributes.cursor = Scr.FvwmCursors[CRS_DEFAULT];
625 attributes.border_pixel = 0;
626 attributes.event_mask = XEVMASK_ICONW;
627 if (HAS_NO_ICON_TITLE(fw))
629 if (FW_W_ICON_TITLE(fw))
631 XDeleteContext(dpy, FW_W_ICON_TITLE(fw), FvwmContext);
632 XDestroyWindow(dpy, FW_W_ICON_TITLE(fw));
633 XFlush(dpy);
634 FW_W_ICON_TITLE(fw) = None;
637 else
639 if (FW_W_ICON_TITLE(fw) == None)
641 FW_W_ICON_TITLE(fw) = XCreateWindow(
642 dpy, Scr.Root, fw->icon_g.title_w_g.x,
643 fw->icon_g.title_w_g.y,
644 fw->icon_g.title_w_g.width,
645 fw->icon_g.title_w_g.height, 0, Pdepth,
646 InputOutput, Pvisual, valuemask, &attributes);
648 else
650 XMoveResizeWindow(
651 dpy, FW_W_ICON_TITLE(fw),
652 fw->icon_g.title_w_g.x, fw->icon_g.title_w_g.y,
653 fw->icon_g.title_w_g.width,
654 fw->icon_g.title_w_g.height);
657 if (Scr.DefaultColorset >= 0)
659 SetWindowBackground(
660 dpy, FW_W_ICON_TITLE(fw), fw->icon_g.title_w_g.width,
661 fw->icon_g.title_w_g.height,
662 &Colorset[Scr.DefaultColorset], Pdepth, Scr.StdGC,
663 False);
667 * create the icon picture window
669 if (IS_ICON_OURS(fw) && fw->icon_g.picture_w_g.width > 0 &&
670 fw->icon_g.picture_w_g.height > 0)
672 /* use fvwm's visuals in these cases */
673 if (Pdefault || fw->iconDepth == 1 || fw->iconDepth == Pdepth ||
674 IS_PIXMAP_OURS(fw))
676 if (!old_icon_pixmap_w)
678 FW_W_ICON_PIXMAP(fw) = XCreateWindow(
679 dpy, Scr.Root, fw->icon_g.picture_w_g.x,
680 fw->icon_g.picture_w_g.y,
681 fw->icon_g.picture_w_g.width,
682 fw->icon_g.picture_w_g.height, 0,
683 Pdepth, InputOutput, Pvisual,
684 valuemask, &attributes);
686 else
688 FW_W_ICON_PIXMAP(fw) = old_icon_pixmap_w;
689 XMoveResizeWindow(
690 dpy, FW_W_ICON_PIXMAP(fw),
691 fw->icon_g.picture_w_g.x,
692 fw->icon_g.picture_w_g.y,
693 fw->icon_g.picture_w_g.width,
694 fw->icon_g.picture_w_g.height);
696 set_icon_pixmap_background(fw);
698 else
700 /* client supplied icon pixmap and fvwm is using
701 * another visual.
702 * use it as the background pixmap, don't try to put
703 * relief on it because fvwm will not have the correct
704 * colors the Exceed server has problems maintaining
705 * the icon window, it usually fails to refresh the
706 * icon leaving it black so ask for expose events */
707 attributes.background_pixmap = fw->iconPixmap;
708 attributes.colormap = DefaultColormap(dpy, Scr.screen);
709 valuemask &= ~CWBackPixel;
710 valuemask |= CWBackPixmap;
711 FW_W_ICON_PIXMAP(fw) = XCreateWindow(
712 dpy, Scr.Root, fw->icon_g.picture_w_g.x,
713 fw->icon_g.picture_w_g.y,
714 fw->icon_g.picture_w_g.width,
715 fw->icon_g.picture_w_g.height, 0,
716 DefaultDepth(dpy, Scr.screen), InputOutput,
717 DefaultVisual(dpy, Scr.screen), valuemask,
718 &attributes);
721 else if (FW_W_ICON_PIXMAP(fw) != None)
723 /* client supplied icon window: select events on it */
724 attributes.event_mask = XEVMASK_ICONPW;
725 valuemask = CWEventMask;
726 XChangeWindowAttributes(
727 dpy, FW_W_ICON_PIXMAP(fw), valuemask,&attributes);
728 if (!IS_ICON_OURS(fw))
730 XMoveWindow(
731 dpy, FW_W_ICON_PIXMAP(fw),
732 fw->icon_g.picture_w_g.x,
733 fw->icon_g.picture_w_g.y);
736 if (old_icon_pixmap_w != None &&
737 old_icon_pixmap_w != FW_W_ICON_PIXMAP(fw))
739 /* destroy the old window */
740 XDestroyWindow(dpy, old_icon_pixmap_w);
741 XDeleteContext(dpy, old_icon_pixmap_w, FvwmContext);
742 XFlush(dpy);
743 is_old_icon_shaped = False;
746 if (FShapesSupported)
748 if (IS_ICON_SHAPED(fw) && fw->icon_background_cs < 0)
750 /* when fvwm is using the non-default visual client
751 * supplied icon pixmaps are drawn in a window with no
752 * relief */
753 int off = 0;
755 if (Pdefault || fw->iconDepth == 1 ||
756 fw->iconDepth == Pdepth || IS_PIXMAP_OURS(fw))
758 off = abs(fw->icon_background_relief) +
759 fw->icon_background_padding;
761 FShapeCombineMask(
762 dpy, FW_W_ICON_PIXMAP(fw), FShapeBounding, off,
763 off, fw->icon_maskPixmap, FShapeSet);
765 else if (is_old_icon_shaped &&
766 FW_W_ICON_PIXMAP(fw) == old_icon_pixmap_w)
768 /* remove the shape */
769 XRectangle r;
771 r.x = 0;
772 r.y = 0;
773 r.width = fw->icon_g.picture_w_g.width;
774 r.height = fw->icon_g.picture_w_g.height;
775 FShapeCombineRectangles(
776 dpy, FW_W_ICON_PIXMAP(fw), FShapeBounding, 0,
777 0, &r, 1, FShapeSet, 0);
781 if (FW_W_ICON_TITLE(fw) != None && FW_W_ICON_TITLE(fw) != old_icon_w)
783 XSaveContext(
784 dpy, FW_W_ICON_TITLE(fw), FvwmContext, (caddr_t)fw);
785 XDefineCursor(
786 dpy, FW_W_ICON_TITLE(fw), Scr.FvwmCursors[CRS_DEFAULT]);
787 GrabAllWindowKeysAndButtons(
788 dpy, FW_W_ICON_TITLE(fw), Scr.AllBindings, C_ICON,
789 GetUnusedModifiers(), Scr.FvwmCursors[CRS_DEFAULT],
790 True);
791 xwc.sibling = FW_W_FRAME(fw);
792 xwc.stack_mode = Below;
793 XConfigureWindow(
794 dpy, FW_W_ICON_TITLE(fw), CWSibling|CWStackMode, &xwc);
796 if (FW_W_ICON_PIXMAP(fw) != None &&
797 FW_W_ICON_PIXMAP(fw) != old_icon_pixmap_w)
799 XSaveContext(
800 dpy, FW_W_ICON_PIXMAP(fw), FvwmContext, (caddr_t)fw);
801 XDefineCursor(
802 dpy, FW_W_ICON_PIXMAP(fw),
803 Scr.FvwmCursors[CRS_DEFAULT]);
804 GrabAllWindowKeysAndButtons(
805 dpy, FW_W_ICON_PIXMAP(fw), Scr.AllBindings, C_ICON,
806 GetUnusedModifiers(), Scr.FvwmCursors[CRS_DEFAULT],
807 True);
808 xwc.sibling = FW_W_FRAME(fw);
809 xwc.stack_mode = Below;
810 XConfigureWindow(
811 dpy,FW_W_ICON_PIXMAP(fw),CWSibling|CWStackMode,&xwc);
814 return;
819 * Draws the icon window
822 static
823 void DrawIconTitleWindow(
824 FvwmWindow *fw, XEvent *pev, Pixel BackColor, GC Shadow, GC Relief,
825 int cs, int title_cs)
827 int is_expanded = IS_ICON_ENTERED(fw);
828 FlocaleWinString fstr;
829 Region region = None;
830 XRectangle clip, r;
831 int relief = abs(fw->icon_title_relief);
832 int x_title;
833 int x_title_min = 0;
834 int w_title = fw->icon_g.title_text_width;
835 int x_title_w = fw->icon_g.picture_w_g.x;
836 int w_title_w = fw->icon_g.picture_w_g.width;
837 int x_stipple = relief;
838 int w_title_text_gap = 0;
839 int w_stipple = 0;
840 int is_sticky;
841 int is_stippled;
842 int use_unexpanded_size = 1;
843 Bool draw_string = True;
845 is_sticky =
846 (IS_STICKY_ACROSS_PAGES(fw) || IS_ICON_STICKY_ACROSS_PAGES(fw));
847 is_sticky |=
848 (IS_STICKY_ACROSS_DESKS(fw) || IS_ICON_STICKY_ACROSS_DESKS(fw));
849 is_stippled = ((is_sticky && HAS_STICKY_STIPPLED_ICON_TITLE(fw)) ||
850 HAS_STIPPLED_ICON_TITLE(fw));
851 if (is_expanded && FW_W_ICON_PIXMAP(fw) != None)
853 int sx;
854 int sy;
855 int sw;
856 int sh;
858 use_unexpanded_size = 0;
859 w_title_text_gap = ICON_TITLE_TEXT_GAP_EXPANDED;
860 x_title_min = w_title_text_gap + relief;
861 if (is_stippled)
863 w_stipple = ICON_TITLE_STICK_MIN_WIDTH;
864 x_title_min +=
865 w_stipple + ICON_TITLE_TO_STICK_EXTRA_GAP;
867 /* resize the icon name window */
868 w_title_w = w_title + 2 * x_title_min;
869 if (w_title_w <= fw->icon_g.picture_w_g.width)
871 /* the expanded title is smaller, so do not
872 * expand at all */
873 is_expanded = 1;
874 w_stipple = 0;
875 use_unexpanded_size = 1;
877 else
879 x_title_w = fw->icon_g.picture_w_g.x -
880 (w_title_w - fw->icon_g.picture_w_g.width) / 2;
881 FScreenGetScrRect(
882 NULL, FSCREEN_CURRENT,
883 &sx, &sy, &sw, &sh);
884 /* start keep label on screen. dje 8/7/97 */
885 if (x_title_w < sx) {
886 /* if new loc neg (off left edge) */
887 x_title_w = sx; /* move to edge */
889 else
891 /* if not on left edge */
892 /* if (new loc + width) > screen width
893 * (off edge on right) */
894 if ((x_title_w + w_title_w) >sx + sw) {
895 /* off right */
896 /* position up against right
897 * edge */
898 x_title_w = sx + sw - w_title_w;
900 /* end keep label on screen. dje
901 * 8/7/97 */
905 if (use_unexpanded_size)
907 w_title_text_gap = ICON_TITLE_TEXT_GAP_COLLAPSED;
908 x_title_min = w_title_text_gap + relief;
909 /* resize the icon name window */
910 if (FW_W_ICON_PIXMAP(fw) != None)
912 w_title_w = fw->icon_g.picture_w_g.width;
913 x_title_w = fw->icon_g.picture_w_g.x;
915 else
917 w_title_w = fw->icon_g.title_w_g.width;
918 x_title_w = fw->icon_g.title_w_g.x;
922 if (fw->icon_g.title_w_g.width != w_title_w ||
923 fw->icon_g.title_w_g.x != x_title_w ||
924 fw->icon_g.title_w_g.height != ICON_HEIGHT(fw))
926 fw->icon_g.title_w_g.width = w_title_w;
927 fw->icon_g.title_w_g.x = x_title_w;
928 fw->icon_g.title_w_g.height = ICON_HEIGHT(fw);
929 pev = NULL; /* resize && redraw all */
932 if (!pev)
934 XMoveResizeWindow(
935 dpy, FW_W_ICON_TITLE(fw), fw->icon_g.title_w_g.x,
936 fw->icon_g.title_w_g.y, w_title_w,
937 ICON_HEIGHT(fw));
940 if (title_cs >= 0)
942 SetWindowBackground(
943 dpy, FW_W_ICON_TITLE(fw), w_title_w,
944 ICON_HEIGHT(fw), &Colorset[title_cs], Pdepth,
945 Scr.TitleGC, False);
947 else
949 XSetWindowBackground(
950 dpy, FW_W_ICON_TITLE(fw), BackColor);
953 /* text position */
954 x_title = (w_title_w - w_title) / 2;
955 if (x_title < x_title_min)
956 x_title = x_title_min;
957 /* text rectangle */
958 r.x = x_title;
959 r.y = relief;
960 r.width = w_title_w - x_title - relief;
961 r.height = ICON_HEIGHT(fw) - 2*relief;
962 if (is_stippled)
965 if (w_stipple == 0)
967 w_stipple = ((w_title_w - 2 *
968 (x_stipple + w_title_text_gap) -
969 w_title) + 1) / 2;
971 if (w_stipple < ICON_TITLE_STICK_MIN_WIDTH)
973 w_stipple = ICON_TITLE_STICK_MIN_WIDTH;
975 if (x_title < x_stipple + w_stipple + w_title_text_gap)
977 x_title = x_stipple + w_stipple +
978 w_title_text_gap;
980 r.x = x_title;
981 r.width = w_title_w - 2 * x_title;
982 if (r.width < 1)
983 r.width = 1;
986 memset(&fstr, 0, sizeof(fstr));
988 if (pev || is_stippled)
990 if (pev)
992 if (!frect_get_intersection(
993 pev->xexpose.x, pev->xexpose.y,
994 pev->xexpose.width,
995 pev->xexpose.height,
996 r.x, r.y, r.width, r.height, &clip))
998 draw_string = False;
1001 else
1003 clip.x = r.x;
1004 clip.y = r.y;
1005 clip.width = r.width;
1006 clip.height = r.height;
1008 if (draw_string)
1010 XSetClipRectangles(
1011 dpy, Scr.TitleGC, 0, 0, &clip, 1, Unsorted);
1012 region = XCreateRegion();
1013 XUnionRectWithRegion (&clip, region, region);
1014 fstr.flags.has_clip_region = True;
1015 fstr.clip_region = region;
1018 if (!pev)
1020 clip.x = relief;
1021 clip.y = relief;
1022 clip.width = w_title_w - 2*relief;
1023 clip.height = ICON_HEIGHT(fw) - 2*relief;
1024 XClearWindow(dpy, FW_W_ICON_TITLE(fw));
1026 else
1028 /* needed for first drawing */
1029 if (x_title - relief >= 1)
1031 /* clear before the text */
1032 XClearArea(
1033 dpy, FW_W_ICON_TITLE(fw),
1034 relief, relief, x_title - relief,
1035 ICON_HEIGHT(fw) - 2*relief, False);
1037 if (is_stippled)
1039 /* clear the stippled area after the text */
1040 XClearArea(
1041 dpy, FW_W_ICON_TITLE(fw),
1042 w_title_w - x_stipple - w_stipple -1, relief,
1043 w_stipple + 2, ICON_HEIGHT(fw) - 2*relief,
1044 False);
1048 if (draw_string)
1050 if (pev)
1052 /* needed by xft font and at first drawing */
1053 XClearArea(
1054 dpy, FW_W_ICON_TITLE(fw),
1055 clip.x, clip.y, clip.width, clip.height,
1056 False);
1058 fstr.str = fw->visible_icon_name;
1059 fstr.win = FW_W_ICON_TITLE(fw);
1060 fstr.gc = Scr.TitleGC;
1061 if (title_cs >= 0)
1063 fstr.colorset = &Colorset[title_cs];
1064 fstr.flags.has_colorset = 1;
1066 else if (cs >= 0)
1068 fstr.colorset = &Colorset[cs];
1069 fstr.flags.has_colorset = 1;
1071 fstr.x = x_title;
1072 fstr.y = fw->icon_g.title_w_g.height - relief
1073 - fw->icon_font->height + fw->icon_font->ascent;
1074 FlocaleDrawString(dpy, fw->icon_font, &fstr, 0);
1075 if (pev || is_stippled)
1077 XSetClipMask(dpy, Scr.TitleGC, None);
1078 if (region)
1080 XDestroyRegion(region);
1084 RelieveRectangle(
1085 dpy, FW_W_ICON_TITLE(fw), 0, 0, w_title_w - 1,
1086 ICON_HEIGHT(fw) - 1,
1087 (fw->icon_title_relief > 0)? Relief:Shadow,
1088 (fw->icon_title_relief > 0)? Shadow:Relief, relief);
1089 if (is_stippled)
1091 /* an odd number of lines every 4 pixels */
1092 int pseudo_height = ICON_HEIGHT(fw)- 2*relief + 2;
1093 int num = (pseudo_height /
1094 ICON_TITLE_STICK_VERT_DIST / 2) * 2 - 1;
1095 int min = ICON_HEIGHT(fw) / 2 -
1096 num * 2 + 1;
1097 int max = ICON_HEIGHT(fw) / 2 +
1098 num * 2 - ICON_TITLE_STICK_VERT_DIST + 1;
1099 int i;
1101 for(i = min; w_stipple > 0 && i <= max;
1102 i += ICON_TITLE_STICK_VERT_DIST)
1104 RelieveRectangle(
1105 dpy, FW_W_ICON_TITLE(fw), x_stipple,
1106 i, w_stipple - 1, 1, Shadow,
1107 Relief, ICON_TITLE_STICK_HEIGHT);
1108 RelieveRectangle(
1109 dpy, FW_W_ICON_TITLE(fw),
1110 w_title_w - x_stipple - w_stipple, i,
1111 w_stipple - 1, 1, Shadow, Relief,
1112 ICON_TITLE_STICK_HEIGHT);
1116 return;
1119 static
1120 void DrawIconPixmapWindow(
1121 FvwmWindow *fw, Bool reset_bg, XEvent *pev, GC Shadow, GC Relief, int cs)
1123 XRectangle r,clip;
1124 Bool cleared = False;
1126 if (!pev)
1128 XMoveWindow(
1129 dpy, FW_W_ICON_PIXMAP(fw), fw->icon_g.picture_w_g.x,
1130 fw->icon_g.picture_w_g.y);
1131 if (reset_bg &&
1132 (fw->iconDepth == 1 || fw->iconDepth == Pdepth || Pdefault ||
1133 IS_PIXMAP_OURS(fw)))
1135 set_icon_pixmap_background(fw);
1136 XClearArea(dpy, FW_W_ICON_PIXMAP(fw), 0, 0, 0, 0, False);
1137 cleared = True;
1141 /* need to locate the icon pixmap */
1142 if (fw->iconPixmap != None)
1144 if (fw->iconDepth == 1 || fw->iconDepth == Pdepth || Pdefault ||
1145 IS_PIXMAP_OURS(fw))
1147 FvwmRenderAttributes fra;
1148 Bool draw_icon = True;
1150 memset(&fra, 0, sizeof(fra));
1151 fra.mask = FRAM_DEST_IS_A_WINDOW;
1152 if (cs >= 0)
1154 fra.mask |= FRAM_HAVE_ICON_CSET;
1155 fra.colorset = &Colorset[cs];
1157 r.x = r.y = abs(fw->icon_background_relief) +
1158 fw->icon_background_padding;
1159 r.width = fw->icon_g.picture_w_g.width -
1160 2 * (abs(fw->icon_background_relief) +
1161 fw->icon_background_padding);
1162 r.height = fw->icon_g.picture_w_g.height -
1163 2 * (abs(fw->icon_background_relief) +
1164 fw->icon_background_padding);
1165 if (pev)
1167 if (!frect_get_intersection(
1168 pev->xexpose.x, pev->xexpose.y,
1169 pev->xexpose.width, pev->xexpose.height,
1170 r.x, r.y, r.width, r.height, &clip))
1172 draw_icon = False;
1175 else
1177 clip.x = r.x;
1178 clip.y = r.y;
1179 clip.width = r.width;
1180 clip.height = r.height;
1182 if (draw_icon)
1184 if (!cleared &&
1185 (fw->icon_alphaPixmap ||
1186 (cs >= 0 &&
1187 Colorset[cs].icon_alpha_percent < 100)))
1189 XClearArea(
1190 dpy, FW_W_ICON_PIXMAP(fw),
1191 clip.x, clip.y, clip.width,
1192 clip.height, False);
1194 PGraphicsRenderPixmaps(
1195 dpy, FW_W_ICON_PIXMAP(fw),
1196 fw->iconPixmap, fw->icon_maskPixmap,
1197 fw->icon_alphaPixmap, fw->iconDepth,
1198 &fra, FW_W_ICON_PIXMAP(fw),
1199 Scr.TitleGC, Scr.MonoGC, Scr.AlphaGC,
1200 clip.x - r.x, clip.y - r.y,
1201 clip.width, clip.height,
1202 clip.x, clip.y, clip.width, clip.height,
1203 False);
1206 else
1208 /* it's a client pixmap and fvwm is not using
1209 * the root visual The icon window has no 3d
1210 * border so copy to (0,0) install the root
1211 * colormap temporarily to help the Exceed
1212 * server */
1213 if (Scr.bo.do_install_root_cmap)
1214 InstallRootColormap();
1215 XCopyArea(
1216 dpy, fw->iconPixmap, FW_W_ICON_PIXMAP(fw),
1217 DefaultGC(dpy, Scr.screen), 0, 0,
1218 fw->icon_g.picture_w_g.width,
1219 fw->icon_g.picture_w_g.height, 0, 0);
1220 if (Scr.bo.do_install_root_cmap)
1221 UninstallRootColormap();
1224 /* only relieve unshaped icons or icons with a bg that share fvwm's
1225 * visual */
1226 if ((fw->iconPixmap != None) &&
1227 (!IS_ICON_SHAPED(fw) || fw->icon_background_cs >= 0) &&
1228 (Pdefault || fw->iconDepth == 1 || fw->iconDepth == Pdepth ||
1229 IS_PIXMAP_OURS(fw)))
1231 RelieveRectangle(
1232 dpy, FW_W_ICON_PIXMAP(fw), 0, 0,
1233 fw->icon_g.picture_w_g.width - 1,
1234 fw->icon_g.picture_w_g.height - 1,
1235 (fw->icon_background_relief > 0)? Relief:Shadow,
1236 (fw->icon_background_relief > 0)? Shadow:Relief,
1237 abs(fw->icon_background_relief));
1242 void DrawIconWindow(
1243 FvwmWindow *fw, Bool draw_title, Bool draw_pixmap, Bool focus_change,
1244 Bool reset_bg, XEvent *pev)
1246 GC Shadow;
1247 GC Relief;
1248 Pixel TextColor;
1249 Pixel BackColor;
1250 color_quad draw_colors;
1251 color_quad co_draw_colors;
1252 int cs, co_cs;
1253 int title_cs = -1;
1254 int co_title_cs = -1;
1255 int is_expanded = IS_ICON_ENTERED(fw);
1257 if (IS_ICON_SUPPRESSED(fw) || (pev && fw->Desk != Scr.CurrentDesk))
1259 return;
1262 if (Scr.Hilite == fw)
1264 if (fw->icon_title_cs_hi >= 0)
1266 title_cs = fw->icon_title_cs_hi;
1267 draw_colors.hilight = Colorset[title_cs].hilite;
1268 draw_colors.shadow = Colorset[title_cs].shadow;
1269 draw_colors.back = Colorset[title_cs].bg;
1270 draw_colors.fore = Colorset[title_cs].fg;
1272 else
1274 draw_colors.hilight = fw->hicolors.hilight;
1275 draw_colors.shadow = fw->hicolors.shadow;
1276 draw_colors.back = fw->hicolors.back;
1277 draw_colors.fore = fw->hicolors.fore;
1279 if (fw->icon_title_cs >= 0)
1281 co_title_cs = fw->icon_title_cs;
1282 co_draw_colors.hilight = Colorset[co_title_cs].hilite;
1283 co_draw_colors.shadow = Colorset[co_title_cs].shadow;
1284 co_draw_colors.back = Colorset[co_title_cs].bg;
1285 co_draw_colors.fore = Colorset[co_title_cs].fg;
1287 else
1289 co_draw_colors.hilight = fw->colors.hilight;
1290 co_draw_colors.shadow = fw->colors.shadow;
1291 co_draw_colors.back = fw->colors.back;
1292 co_draw_colors.fore = fw->colors.fore;
1294 cs = fw->cs_hi;
1295 co_cs = fw->cs;
1297 else
1299 if (fw->icon_title_cs >= 0)
1301 title_cs = fw->icon_title_cs;
1302 draw_colors.hilight = Colorset[title_cs].hilite;
1303 draw_colors.shadow = Colorset[title_cs].shadow;
1304 draw_colors.back = Colorset[title_cs].bg;
1305 draw_colors.fore = Colorset[title_cs].fg;
1307 else
1309 draw_colors.hilight = fw->colors.hilight;
1310 draw_colors.shadow = fw->colors.shadow;
1311 draw_colors.back = fw->colors.back;
1312 draw_colors.fore = fw->colors.fore;
1314 if (fw->icon_title_cs_hi >= 0)
1316 co_title_cs = fw->icon_title_cs_hi;
1317 co_draw_colors.hilight = Colorset[co_title_cs].hilite;
1318 co_draw_colors.shadow = Colorset[co_title_cs].shadow;
1319 co_draw_colors.back = Colorset[co_title_cs].bg;
1320 co_draw_colors.fore = Colorset[co_title_cs].fg;
1322 else
1324 co_draw_colors.hilight = fw->hicolors.hilight;
1325 co_draw_colors.shadow = fw->hicolors.shadow;
1326 co_draw_colors.back = fw->hicolors.back;
1327 co_draw_colors.fore = fw->hicolors.fore;
1329 cs = fw->cs;
1330 co_cs = fw->cs_hi;
1332 if (Pdepth < 2 && Scr.Hilite != fw)
1334 Relief = Scr.StdReliefGC;
1335 Shadow = Scr.StdShadowGC;
1337 else
1339 if (Pdepth < 2 && Scr.Hilite == fw)
1341 Relief = Scr.ScratchGC2;
1343 else
1345 Globalgcv.foreground = draw_colors.hilight;
1346 Globalgcm = GCForeground;
1347 XChangeGC(dpy,Scr.ScratchGC1,Globalgcm,&Globalgcv);
1348 Relief = Scr.ScratchGC1;
1350 Globalgcv.foreground = draw_colors.shadow;
1351 XChangeGC(dpy,Scr.ScratchGC2, Globalgcm, &Globalgcv);
1352 Shadow = Scr.ScratchGC2;
1354 TextColor = draw_colors.fore;
1355 BackColor = draw_colors.back;
1356 /* set up TitleGC for drawing the icon label */
1357 if (fw->icon_font != NULL)
1359 NewFontAndColor(fw->icon_font, TextColor, BackColor);
1362 if (draw_title && FW_W_ICON_TITLE(fw) != None)
1364 if (pev && pev->xexpose.window != FW_W_ICON_TITLE(fw))
1366 XEvent e;
1367 if (FCheckTypedWindowEvent(
1368 dpy, FW_W_ICON_TITLE(fw), Expose, &e))
1370 flush_accumulate_expose(
1371 FW_W_ICON_TITLE(fw), &e);
1372 DrawIconTitleWindow(
1373 fw, &e, BackColor, Shadow, Relief, cs,
1374 title_cs);
1377 else
1379 if (!pev)
1381 flush_expose(FW_W_ICON_TITLE(fw));
1383 DrawIconTitleWindow(
1384 fw, pev, BackColor, Shadow, Relief, cs,
1385 title_cs);
1389 if (draw_pixmap)
1391 int bg_cs = fw->icon_background_cs;
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))
1399 if (Pdepth < 2 && Scr.Hilite == fw)
1401 Relief = Scr.ScratchGC2;
1403 else
1405 Globalgcv.foreground = Colorset[bg_cs].hilite;
1406 Globalgcm = GCForeground;
1407 XChangeGC(
1408 dpy,Scr.ScratchGC1,Globalgcm,&Globalgcv);
1409 Relief = Scr.ScratchGC1;
1411 Globalgcv.foreground = Colorset[bg_cs].shadow;
1412 XChangeGC(dpy,Scr.ScratchGC2, Globalgcm, &Globalgcv);
1413 Shadow = Scr.ScratchGC2;
1417 if (focus_change && draw_pixmap)
1419 Bool alpha_change = False;
1420 Bool tint_change = False;
1421 Bool relief_change = False;
1422 Bool color_change = False;
1424 draw_pixmap = False;
1425 /* check if we have to draw the icons */
1427 if (Pdepth < 2)
1429 relief_change = True;
1431 else if (fw->iconDepth == 1)
1433 color_change =
1434 (draw_colors.fore !=
1435 co_draw_colors.back) ||
1436 (draw_colors.fore !=
1437 co_draw_colors.back);
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)))
1444 relief_change =
1445 (draw_colors.hilight !=
1446 co_draw_colors.hilight) ||
1447 (draw_colors.shadow !=
1448 co_draw_colors.shadow);
1450 if (cs >= 0 && co_cs >= 0)
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);
1462 else if (cs >= 0 && co_cs < 0)
1464 alpha_change = (Colorset[cs].icon_alpha_percent < 100);
1465 tint_change = (Colorset[cs].icon_tint_percent > 0);
1467 else if (cs < 0 && co_cs >= 0)
1469 alpha_change =
1470 (Colorset[co_cs].icon_alpha_percent < 100);
1471 tint_change = (Colorset[co_cs].icon_tint_percent > 0);
1473 if (alpha_change || tint_change || relief_change ||
1474 color_change)
1476 draw_pixmap = True;
1480 if (draw_pixmap && FW_W_ICON_PIXMAP(fw) != None)
1482 if (pev && pev->xexpose.window != FW_W_ICON_PIXMAP(fw))
1484 XEvent e;
1485 if (FCheckTypedWindowEvent(
1486 dpy, FW_W_ICON_PIXMAP(fw), Expose, &e))
1488 flush_accumulate_expose(
1489 FW_W_ICON_PIXMAP(fw), &e);
1490 DrawIconPixmapWindow(
1491 fw, reset_bg, &e, Shadow, Relief, cs);
1494 else
1496 if (!pev)
1498 flush_expose(FW_W_ICON_PIXMAP(fw));
1500 DrawIconPixmapWindow(
1501 fw, reset_bg, pev, Shadow, Relief, cs);
1505 if (is_expanded)
1507 if (FW_W_ICON_TITLE(fw) != None)
1509 XRaiseWindow(dpy, FW_W_ICON_TITLE(fw));
1510 raisePanFrames();
1513 else
1515 XWindowChanges xwc;
1516 int mask;
1517 xwc.sibling = FW_W_FRAME(fw);
1518 xwc.stack_mode = Below;
1519 mask = CWSibling|CWStackMode;
1520 if (FW_W_ICON_TITLE(fw) != None)
1522 XConfigureWindow(dpy, FW_W_ICON_TITLE(fw), mask, &xwc);
1524 if (FW_W_ICON_PIXMAP(fw) != None)
1526 XConfigureWindow(dpy, FW_W_ICON_PIXMAP(fw), mask, &xwc);
1529 /* wait for pending EnterNotify/LeaveNotify events to suppress race
1530 * condition w/ expanding/collapsing icon titles */
1531 XFlush(dpy);
1536 * Procedure:
1537 * ChangeIconPixmap - procedure change the icon pixmap or "pixmap"
1538 * window. Called in events.c and ewmh_events.c
1541 void ChangeIconPixmap(FvwmWindow *fw)
1543 rectangle g;
1545 if (!IS_ICONIFIED(fw))
1547 ICON_DBG((stderr,"hpn: postpone icon change '%s'\n", fw->name));
1548 /* update the icon later when application is iconified */
1549 SET_HAS_ICON_CHANGED(fw, 1);
1551 else if (IS_ICONIFIED(fw))
1553 ICON_DBG((stderr,"hpn: applying new icon '%s'\n", fw->name));
1554 SET_ICONIFIED(fw, 0);
1555 SET_ICON_UNMAPPED(fw, 0);
1556 get_icon_geometry(fw, &g);
1557 CreateIconWindow(fw, g.x, g.y);
1558 broadcast_icon_geometry(fw, False);
1559 /* domivogt (15-Sep-1999): BroadcastConfig informs modules of
1560 * the configuration change including the iconified flag. So
1561 * this flag must be set here. I'm not sure if the two calls of
1562 * the SET_ICONIFIED macro after BroadcastConfig are necessary,
1563 * but since it's only minimal overhead I prefer to be on the
1564 * safe side. */
1565 SET_ICONIFIED(fw, 1);
1566 BroadcastConfig(M_CONFIGURE_WINDOW, fw);
1567 SET_ICONIFIED(fw, 0);
1569 if (!IS_ICON_SUPPRESSED(fw))
1571 LowerWindow(fw, False);
1572 AutoPlaceIcon(fw, NULL, True);
1573 if (fw->Desk == Scr.CurrentDesk)
1575 if (FW_W_ICON_TITLE(fw))
1577 XMapWindow(dpy, FW_W_ICON_TITLE(fw));
1579 if (FW_W_ICON_PIXMAP(fw) != None)
1581 XMapWindow(dpy, FW_W_ICON_PIXMAP(fw));
1585 SET_ICONIFIED(fw, 1);
1586 DrawIconWindow(fw, False, True, False, False, NULL);
1589 return;
1594 * Procedure:
1595 * RedoIconName - procedure to re-position the icon window and name
1598 void RedoIconName(FvwmWindow *fw)
1600 if (IS_ICON_SUPPRESSED(fw))
1602 return;
1604 if (FW_W_ICON_TITLE(fw) == None)
1606 return;
1608 setup_icon_title_size(fw);
1609 /* clear the icon window, and trigger a re-draw via an expose event */
1610 if (IS_ICONIFIED(fw))
1612 DrawIconWindow(fw, True, False, False, False, NULL);
1613 XClearArea(dpy, FW_W_ICON_TITLE(fw), 0, 0, 0, 0, True);
1616 return;
1621 * Procedure:
1622 * AutoPlace - Find a home for an icon
1625 void AutoPlaceIcon(
1626 FvwmWindow *t, initial_window_options_t *win_opts,
1627 Bool do_move_immediately)
1629 int base_x, base_y;
1630 int width,height;
1631 FvwmWindow *test_fw;
1632 Bool loc_ok;
1633 Bool loc_ok_wrong_screen;
1634 Bool loc_ok_wrong_screen2;
1635 int real_x=10, real_y=10;
1636 int new_x, new_y;
1637 Bool do_move_icon = False;
1639 #if 0
1640 /* dv (16-Mar-2003): We need to place the icon even if there is no icon so
1641 * the 'position' can be communicated to the modules to decide whether to show
1642 * the icon or not. */
1643 if (FW_W_ICON_PIXMAP(t) == None && FW_W_ICON_TITLE(t) == None)
1645 return;
1647 #endif
1648 /* New! Put icon in same page as the center of the window */
1649 /* Not a good idea for StickyIcons. Neither for icons of windows that are
1650 * visible on the current page. */
1651 if (IS_ICON_STICKY_ACROSS_DESKS(t) || IS_STICKY_ACROSS_DESKS(t))
1653 t->Desk = Scr.CurrentDesk;
1655 if (IS_ICON_STICKY_ACROSS_PAGES(t) || IS_STICKY_ACROSS_PAGES(t))
1657 base_x = 0;
1658 base_y = 0;
1659 /*Also, if its a stickyWindow, put it on the current page! */
1660 new_x = t->g.frame.x % Scr.MyDisplayWidth;
1661 new_y = t->g.frame.y % Scr.MyDisplayHeight;
1662 if (new_x + t->g.frame.width <= 0)
1663 new_x += Scr.MyDisplayWidth;
1664 if (new_y + t->g.frame.height <= 0)
1665 new_y += Scr.MyDisplayHeight;
1666 frame_setup_window(
1667 t, new_x, new_y, t->g.frame.width, t->g.frame.height, False);
1669 else if (IsRectangleOnThisPage(&(t->g.frame), t->Desk))
1671 base_x = 0;
1672 base_y = 0;
1674 else
1676 base_x = ((t->g.frame.x + Scr.Vx + (t->g.frame.width >> 1)) /
1677 Scr.MyDisplayWidth) * Scr.MyDisplayWidth;
1678 base_y= ((t->g.frame.y + Scr.Vy + (t->g.frame.height >> 1)) /
1679 Scr.MyDisplayHeight) * Scr.MyDisplayHeight;
1680 /* limit icon position to desktop */
1681 if (base_x > Scr.VxMax)
1682 base_x = Scr.VxMax;
1683 if (base_x < 0)
1684 base_x = 0;
1685 if (base_y > Scr.VyMax)
1686 base_y = Scr.VyMax;
1687 if (base_y < 0)
1688 base_y = 0;
1689 base_x -= Scr.Vx;
1690 base_y -= Scr.Vy;
1692 if (IS_ICON_MOVED(t) ||
1693 (win_opts != NULL && win_opts->flags.use_initial_icon_xy))
1695 rectangle g;
1696 int dx;
1697 int dy;
1699 get_icon_geometry(t, &g);
1700 if (win_opts != NULL && win_opts->flags.use_initial_icon_xy)
1702 g.x = win_opts->initial_icon_x;
1703 g.y = win_opts->initial_icon_y;
1705 dx = g.x;
1706 dy = g.y;
1708 /* just make sure the icon is on this page */
1709 g.x = g.x % Scr.MyDisplayWidth + base_x;
1710 g.y = g.y % Scr.MyDisplayHeight + base_y;
1711 if (g.x < 0)
1713 g.x += Scr.MyDisplayWidth;
1715 if (g.y < 0)
1717 g.y += Scr.MyDisplayHeight;
1719 dx = g.x - dx;
1720 dy = g.y - dy;
1721 modify_icon_position(t, dx, dy);
1722 do_move_icon = True;
1724 else if (USE_ICON_POSITION_HINT(t) && t->wmhints &&
1725 t->wmhints->flags & IconPositionHint)
1727 set_icon_position(t, t->wmhints->icon_x, t->wmhints->icon_y);
1728 do_move_icon = True;
1730 /* dje 10/12/97:
1731 Look thru chain of icon boxes assigned to window.
1732 Add logic for grids and fill direction.
1734 else if (DO_IGNORE_ICON_BOXES(t))
1736 int sx;
1737 int sy;
1738 int sw;
1739 int sh;
1740 fscreen_scr_arg fscr;
1741 rectangle g;
1743 get_icon_geometry(t, &g);
1744 get_icon_corner(t, &g);
1745 fscr.xypos.x = g.x + g.width / 2;
1746 fscr.xypos.y = g.y + g.height / 2;
1747 FScreenGetScrRect(&fscr, FSCREEN_XYPOS, &sx, &sy, &sw, &sh);
1748 if (g.x < sx)
1749 g.x = sx;
1750 else if (g.x + g.width > sx + sw)
1751 g.x = sx + sw - g.width;
1752 if (g.y < sy)
1753 g.y = sy;
1754 else if (g.y + g.height > sy + sh)
1755 g.y = sy + sh - g.height;
1756 set_icon_position(t, g.x, g.y);
1757 do_move_icon = True;
1759 else
1761 /* A place to hold inner and outer loop variables. */
1762 typedef struct dimension_struct
1764 int step; /* grid size (may be negative) */
1765 int start_at; /* starting edge */
1766 int real_start; /* on screen starting edge */
1767 int end_at; /* ending edge */
1768 int base; /* base for screen */
1769 int icon_dimension; /* height or width */
1770 int nom_dimension; /* nonminal height or width */
1771 int screen_dimension; /* screen height or width */
1772 int screen_offset; /* screen offset */
1773 } dimension;
1774 dimension dim[3]; /* space for work, 1st, 2nd dimen */
1775 icon_boxes *icon_boxes_ptr; /* current icon box */
1776 int i; /* index for inner/outer loop data */
1777 fscreen_scr_arg fscr;
1778 rectangle ref;
1779 rectangle g;
1781 /* Hopefully this makes the following more readable. */
1782 #define ICONBOX_LFT icon_boxes_ptr->IconBox[0]
1783 #define ICONBOX_TOP icon_boxes_ptr->IconBox[1]
1784 #define ICONBOX_RGT icon_boxes_ptr->IconBox[2]
1785 #define ICONBOX_BOT icon_boxes_ptr->IconBox[3]
1786 #define BOT_FILL icon_boxes_ptr->IconFlags & ICONFILLBOT
1787 #define RGT_FILL icon_boxes_ptr->IconFlags & ICONFILLRGT
1788 #define HRZ_FILL icon_boxes_ptr->IconFlags & ICONFILLHRZ
1790 /* needed later */
1791 fscr.xypos.x = t->g.frame.x + (t->g.frame.width / 2) - base_x;
1792 fscr.xypos.y = t->g.frame.y + (t->g.frame.height / 2) - base_y;
1793 get_icon_geometry(t, &g);
1794 /* unnecessary copy of width */
1795 width = g.width;
1796 /* total height */
1797 height = g.height;
1798 /* no slot found yet */
1799 loc_ok = False;
1800 loc_ok_wrong_screen = False;
1802 /* check all boxes in order */
1803 icon_boxes_ptr = NULL; /* init */
1804 while(do_all_iconboxes(t, &icon_boxes_ptr))
1806 if (loc_ok == True)
1808 /* leave for loop */
1809 break;
1811 /* get the screen dimensions for the icon box */
1812 if (icon_boxes_ptr->IconScreen == FSCREEN_CURRENT)
1813 fscr.mouse_ev = NULL;
1814 FScreenGetScrRect(
1815 &fscr,
1816 icon_boxes_ptr->IconScreen,
1817 &ref.x, &ref.y, &ref.width, &ref.height);
1818 dim[1].screen_offset = ref.y;
1819 dim[1].screen_dimension = ref.height;
1820 dim[2].screen_offset = ref.x;
1821 dim[2].screen_dimension = ref.width;
1822 /* y amount */
1823 dim[1].step = icon_boxes_ptr->IconGrid[1];
1824 /* init start from */
1825 dim[1].start_at = ICONBOX_TOP + dim[1].screen_offset;
1826 if (icon_boxes_ptr->IconSign[1] == '-') {
1827 dim[1].start_at += dim[1].screen_dimension;
1829 /* init end at */
1830 dim[1].end_at = ICONBOX_BOT + dim[1].screen_offset;
1831 if (icon_boxes_ptr->IconSign[3] == '-') {
1832 dim[1].end_at += dim[1].screen_dimension;
1834 /* save base */
1835 dim[1].base = base_y;
1836 /* save dimension */
1837 dim[1].icon_dimension = height;
1838 if (BOT_FILL)
1840 /* fill from bottom */
1841 /* reverse step */
1842 dim[1].step = 0 - dim[1].step;
1843 } /* end fill from bottom */
1845 /* x amount */
1846 dim[2].step = icon_boxes_ptr->IconGrid[0];
1847 /* init start from */
1848 dim[2].start_at = ICONBOX_LFT + dim[2].screen_offset;
1849 if (icon_boxes_ptr->IconSign[0] == '-') {
1850 dim[2].start_at += dim[2].screen_dimension;
1852 /* init end at */
1853 dim[2].end_at = ICONBOX_RGT + dim[2].screen_offset;
1854 if (icon_boxes_ptr->IconSign[2] == '-') {
1855 dim[2].end_at += dim[2].screen_dimension;
1857 /* save base */
1858 dim[2].base = base_x;
1859 /* save dimension */
1860 dim[2].icon_dimension = width;
1861 if (RGT_FILL)
1863 /* fill from right */
1864 /* reverse step */
1865 dim[2].step = 0 - dim[2].step;
1866 } /* end fill from right */
1867 for (i=1;i<=2;i++)
1869 /* for dimensions 1 and 2 */
1870 /* If the window is taller than the icon box, ignore the icon height
1871 * when figuring where to put it. Same goes for the width
1872 * This should permit reasonably graceful handling of big icons. */
1873 dim[i].nom_dimension = dim[i].icon_dimension;
1874 if (dim[i].icon_dimension >= dim[i].end_at - dim[i].start_at)
1876 dim[i].nom_dimension = dim[i].end_at - dim[i].start_at - 1;
1878 if (dim[i].step < 0)
1880 /* if moving backwards */
1881 /* save */
1882 dim[0].start_at = dim[i].start_at;
1883 /* swap one */
1884 dim[i].start_at = dim[i].end_at;
1885 /* swap the other */
1886 dim[i].end_at = dim[0].start_at;
1887 dim[i].start_at -= dim[i].icon_dimension;
1888 } /* end moving backwards */
1889 /* adjust both to base */
1890 dim[i].start_at += dim[i].base;
1891 dim[i].end_at += dim[i].base;
1892 } /* end 2 dimensions */
1893 if (HRZ_FILL)
1895 /* if hrz first */
1896 /* save */
1897 memcpy(&dim[0],&dim[1],sizeof(dimension));
1898 /* switch one */
1899 memcpy(&dim[1],&dim[2],sizeof(dimension));
1900 /* switch the other */
1901 memcpy(&dim[2],&dim[0],sizeof(dimension));
1902 } /* end horizontal dimension first */
1903 /* save for reseting inner loop */
1904 dim[0].start_at = dim[2].start_at;
1905 loc_ok_wrong_screen2 = False;
1906 while((dim[1].step < 0 /* filling reversed */
1907 ? (dim[1].start_at + dim[1].icon_dimension - dim[1].nom_dimension
1908 > dim[1].end_at) /* check back edge */
1909 : (dim[1].start_at + dim[1].nom_dimension
1910 < dim[1].end_at)) /* check front edge */
1911 && (!loc_ok)
1912 && (!loc_ok_wrong_screen2)) { /* nothing found yet */
1913 dim[1].real_start = dim[1].start_at; /* init */
1914 if (dim[1].start_at + dim[1].icon_dimension >
1915 dim[1].screen_offset + dim[1].screen_dimension - 2 + dim[1].base)
1917 /* off screen, move on screen */
1918 dim[1].real_start = dim[1].screen_offset + dim[1].screen_dimension
1919 - dim[1].icon_dimension + dim[1].base;
1920 } /* end off screen */
1921 if (dim[1].start_at < dim[1].screen_offset + dim[1].base)
1923 /* if off other edge, move on screen */
1924 dim[1].real_start = dim[1].screen_offset + dim[1].base;
1925 } /* end off other edge */
1926 /* reset inner loop */
1927 dim[2].start_at = dim[0].start_at;
1928 while((dim[2].step < 0 /* filling reversed */
1929 ? (dim[2].start_at + dim[2].icon_dimension-dim[2].nom_dimension
1930 > dim[2].end_at) /* check back edge */
1931 : (dim[2].start_at + dim[2].nom_dimension
1932 < dim[2].end_at)) /* check front edge */
1933 && (!loc_ok)
1934 && (!loc_ok_wrong_screen2)) { /* nothing found yet */
1935 dim[2].real_start = dim[2].start_at; /* init */
1936 if (dim[2].start_at + dim[2].icon_dimension >
1937 dim[2].screen_offset + dim[2].screen_dimension - 2 + dim[2].base)
1939 /* if off screen, move on screen */
1940 dim[2].real_start = dim[2].screen_offset + dim[2].screen_dimension
1941 - dim[2].icon_dimension + dim[2].base;
1942 } /* end off screen */
1943 if (dim[2].start_at < dim[2].screen_offset + dim[2].base)
1945 /* if off other edge, move on screen */
1946 dim[2].real_start = dim[2].screen_offset + dim[2].base;
1947 } /* end off other edge */
1949 if (HRZ_FILL)
1951 /* hrz first */
1952 /* unreverse them */
1953 real_x = dim[1].real_start;
1954 real_y = dim[2].real_start;
1956 else
1958 /* reverse them */
1959 real_x = dim[2].real_start;
1960 real_y = dim[1].real_start;
1963 /* this may be a good location */
1964 if (FScreenIsRectangleOnScreen(&fscr, FSCREEN_XYPOS, &ref))
1966 loc_ok = True;
1968 else
1970 loc_ok_wrong_screen2 = True;
1972 test_fw = Scr.FvwmRoot.next;
1973 while((test_fw != (FvwmWindow *)0)
1974 &&(loc_ok == True || loc_ok_wrong_screen2))
1976 /* test overlap */
1977 if (test_fw->Desk == t->Desk)
1979 rectangle g;
1981 if ((IS_ICONIFIED(test_fw)) &&
1982 (!IS_TRANSIENT(test_fw) ||
1983 !IS_ICONIFIED_BY_PARENT(test_fw)) &&
1984 (FW_W_ICON_TITLE(test_fw)||FW_W_ICON_PIXMAP(test_fw)) &&
1985 (test_fw != t)) {
1986 get_icon_geometry(test_fw, &g);
1987 if ((g.x<(real_x+width+MIN_ICON_BOX_DIST))&&
1988 ((g.x+g.width+MIN_ICON_BOX_DIST) > real_x)&&
1989 (g.y<(real_y+height+MIN_ICON_BOX_DIST))&&
1990 ((g.y+g.height + MIN_ICON_BOX_DIST)>real_y))
1992 /* don't accept this location */
1993 loc_ok = False;
1994 loc_ok_wrong_screen2 = False;
1995 } /* end if icons overlap */
1996 } /* end if its an icon */
1997 } /* end if same desk */
1998 test_fw = test_fw->next;
1999 } /* end while icons that may overlap */
2000 if (loc_ok_wrong_screen2)
2002 loc_ok_wrong_screen = True;
2004 /* Grid inner value & direction */
2005 dim[2].start_at += dim[2].step;
2006 } /* end while room inner dimension */
2007 /* Grid outer value & direction */
2008 dim[1].start_at += dim[1].step;
2009 } /* end while room outer dimension */
2010 } /* end for all icon boxes, or found space */
2011 if (!loc_ok && !loc_ok_wrong_screen)
2012 /* If icon never found a home just leave it */
2013 return;
2014 set_icon_position(t, real_x, real_y);
2015 broadcast_icon_geometry(t, True);
2016 do_move_icon = True;
2018 if (do_move_icon && do_move_immediately)
2020 move_icon_to_position(t);
2023 return;
2026 static icon_boxes *global_icon_box_ptr;
2027 /* Find next icon box to try to place icon in.
2028 Goes thru chain that the window got thru style matching,
2029 then the global icon box.
2030 Create the global icon box on first call.
2031 Return code indicates when the boxes are used up.
2032 The boxes could only get completely used up when you fill the screen
2033 with them.
2035 static int
2036 do_all_iconboxes(FvwmWindow *t, icon_boxes **icon_boxes_ptr)
2038 if (global_icon_box_ptr == 0)
2040 /* if first time */
2041 int sx;
2042 int sy;
2043 int sw;
2044 int sh;
2045 /* Right now, the global box is hard-coded, fills the primary
2046 * screen, uses an 80x80 grid, and fills top-bottom,
2047 * left-right */
2048 FScreenGetScrRect(NULL, FSCREEN_PRIMARY, &sx, &sy, &sw, &sh);
2049 global_icon_box_ptr = calloc(1, sizeof(icon_boxes));
2050 global_icon_box_ptr->IconBox[0] = sx;
2051 global_icon_box_ptr->IconBox[1] = sy;
2052 global_icon_box_ptr->IconBox[2] = sx + sw;
2053 global_icon_box_ptr->IconBox[3] = sy + sh;
2054 global_icon_box_ptr->IconGrid[0] = 80;
2055 global_icon_box_ptr->IconGrid[1] = 80;
2056 global_icon_box_ptr->IconFlags = ICONFILLHRZ;
2058 if (*icon_boxes_ptr == NULL)
2060 /* first time? */
2061 /* start at windows box */
2062 *icon_boxes_ptr = t->IconBoxes;
2063 if (!*icon_boxes_ptr)
2065 /* if window has no box */
2066 /* use global box */
2067 *icon_boxes_ptr = global_icon_box_ptr;
2069 /* use box */
2070 return (1);
2073 /* Here its not the first call, we are either on the chain or at
2074 * the global box */
2075 if (*icon_boxes_ptr == global_icon_box_ptr)
2077 /* if the global box */
2078 /* completely out of boxes (unlikely) */
2079 return (0);
2081 /* move to next one on chain */
2082 *icon_boxes_ptr = (*icon_boxes_ptr)->next;
2083 if (*icon_boxes_ptr)
2085 /* if there is a next one */
2086 /* return it */
2087 return (1);
2089 /* global box */
2090 *icon_boxes_ptr = global_icon_box_ptr;
2092 /* use it */
2093 return (1);
2098 * Looks for icon from a file
2101 static void GetIconFromFile(FvwmWindow *fw)
2103 char *path = NULL;
2104 FvwmPictureAttributes fpa;
2106 fpa.mask = 0;
2107 if (fw->cs >= 0 && Colorset[fw->cs].do_dither_icon)
2109 fpa.mask |= FPAM_DITHER;
2111 fw->icon_g.picture_w_g.width = 0;
2112 fw->icon_g.picture_w_g.height = 0;
2113 path = PictureFindImageFile(fw->icon_bitmap_file, NULL, R_OK);
2114 if (path == NULL)
2116 return;
2118 if (!PImageLoadPixmapFromFile(
2119 dpy, Scr.NoFocusWin, path, &fw->iconPixmap,
2120 &fw->icon_maskPixmap, &fw->icon_alphaPixmap,
2121 &fw->icon_g.picture_w_g.width, &fw->icon_g.picture_w_g.height,
2122 &fw->iconDepth, &fw->icon_nalloc_pixels, &fw->icon_alloc_pixels,
2123 &fw->icon_no_limit, fpa))
2125 fvwm_msg(ERR, "GetIconFromFile", "Failed to load %s", path);
2126 free(path);
2127 return;
2129 SET_PIXMAP_OURS(fw, 1);
2130 free(path);
2131 if (FShapesSupported && fw->icon_maskPixmap)
2133 SET_ICON_SHAPED(fw, 1);
2136 return;
2141 * Looks for an application supplied icon window
2144 static void GetIconWindow(FvwmWindow *fw)
2146 int w;
2147 int h;
2148 int bw;
2150 fw->icon_g.picture_w_g.width = 0;
2151 fw->icon_g.picture_w_g.height = 0;
2153 /* We are guaranteed that wmhints is non-null when calling this
2154 * routine */
2155 if (XGetGeometry(
2156 dpy, fw->wmhints->icon_window, &JunkRoot, &JunkX, &JunkY,
2157 (unsigned int*)&w, (unsigned int*)&h,(unsigned int*)&bw,
2158 (unsigned int*)&JunkDepth) == 0)
2160 fvwm_msg(
2161 ERR,"GetIconWindow",
2162 "Window '%s' has a bad icon window! Ignoring icon"
2163 " window.", fw->name.name);
2164 /* disable the icon window hint */
2165 fw->wmhints->icon_window = None;
2166 fw->wmhints->flags &= ~IconWindowHint;
2167 return;
2169 fw->icon_border_width = bw;
2170 fw->icon_g.picture_w_g.width = w + 2 * bw;
2171 fw->icon_g.picture_w_g.height = h + 2 * bw;
2173 * Now make the new window the icon window for this window,
2174 * and set it up to work as such (select for key presses
2175 * and button presses/releases, set up the contexts for it,
2176 * and define the cursor for it).
2178 FW_W_ICON_PIXMAP(fw) = fw->wmhints->icon_window;
2179 if (FShapesSupported)
2181 if (fw->wmhints->flags & IconMaskHint)
2183 SET_ICON_SHAPED(fw, 1);
2184 fw->icon_maskPixmap = fw->wmhints->icon_mask;
2187 /* Make sure that the window is a child of the root window ! */
2188 /* Olwais screws this up, maybe others do too! */
2189 XReparentWindow(dpy, FW_W_ICON_PIXMAP(fw), Scr.Root, 0,0);
2190 SET_ICON_OURS(fw, 0);
2192 return;
2198 * Looks for an application supplied bitmap or pixmap
2201 static void GetIconBitmap(FvwmWindow *fw)
2203 int width, height, depth;
2205 fw->icon_g.picture_w_g.width = 0;
2206 fw->icon_g.picture_w_g.height = 0;
2208 /* We are guaranteed that wmhints is non-null when calling this routine
2210 if (!XGetGeometry(
2211 dpy, fw->wmhints->icon_pixmap, &JunkRoot, &JunkX, &JunkY,
2212 (unsigned int*)&width, (unsigned int*)&height,
2213 (unsigned int*)&JunkBW, (unsigned int*)&depth))
2215 fvwm_msg(
2216 ERR,"GetIconBitmap",
2217 "Window '%s' has a bad icon pixmap! Ignoring icon.",
2218 fw->name.name);
2219 /* disable icon pixmap hint */
2220 fw->wmhints->icon_pixmap = None;
2221 fw->wmhints->flags &= ~IconPixmapHint;
2222 return;
2224 /* sanity check the pixmap depth, it must be the same as the root or 1
2226 if (depth != 1 && depth != Pdepth &&
2227 depth != DefaultDepth(dpy,Scr.screen))
2229 fvwm_msg(
2230 ERR, "GetIconBitmap",
2231 "Window '%s' has a bad icon bitmap depth %d (should"
2232 " be 1, %d or %d)! Ignoring icon bitmap.",
2233 fw->name.name, depth, Pdepth,
2234 DefaultDepth(dpy,Scr.screen));
2235 /* disable icon pixmap hint */
2236 fw->wmhints->icon_pixmap = None;
2237 fw->wmhints->flags &= ~IconPixmapHint;
2238 return;
2240 fw->iconPixmap = fw->wmhints->icon_pixmap;
2241 fw->icon_g.picture_w_g.width = width;
2242 fw->icon_g.picture_w_g.height = height;
2243 fw->iconDepth = depth;
2244 if (FShapesSupported)
2246 if (fw->wmhints->flags & IconMaskHint)
2248 SET_ICON_SHAPED(fw, 1);
2249 fw->icon_maskPixmap = fw->wmhints->icon_mask;
2252 SET_PIXMAP_OURS(fw, 0);
2254 return;
2259 * Procedure:
2260 * DeIconify a window
2263 void DeIconify(FvwmWindow *fw)
2265 FvwmWindow *t, *tmp, *ofw;
2266 FvwmWindow *sf = get_focus_window();
2267 rectangle icon_rect;
2268 XWindowAttributes winattrs = {0};
2270 if (!fw)
2272 return;
2274 if (!XGetWindowAttributes(dpy, FW_W(fw), &winattrs))
2276 return;
2279 /* make sure fw->flags.is_map_pending is OK */
2280 if (winattrs.map_state == IsViewable && IS_MAP_PENDING(fw))
2282 SET_MAP_PENDING(fw, 0);
2284 else if (IS_MAP_PENDING(fw))
2286 /* final state: de-iconified */
2287 SET_ICONIFY_AFTER_MAP(fw, 0);
2288 return;
2290 for (ofw = NULL; fw != ofw && IS_ICONIFIED_BY_PARENT(fw); )
2292 t = get_transientfor_fvwmwindow(fw);
2293 if (t == NULL)
2295 break;
2297 ofw = fw;
2298 fw = t;
2300 if (IS_ICONIFIED_BY_PARENT(fw))
2302 SET_ICONIFIED_BY_PARENT(fw, 0);
2305 /* AS dje RaiseWindow(fw); */
2307 if (fw == sf)
2309 /* take away the focus before mapping */
2310 DeleteFocus(True);
2312 /* Note: DeleteFocus may delete the flags set by
2313 * mark_transient_subtree(), so do it later. */
2314 mark_transient_subtree(fw, MARK_ALL_LAYERS, MARK_ALL, False, True);
2315 /* now de-iconify transients */
2316 for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
2318 if (t == fw || IS_IN_TRANSIENT_SUBTREE(t))
2320 SET_IN_TRANSIENT_SUBTREE(t, 0);
2321 SET_MAPPED(t, 1);
2322 SET_ICONIFIED_BY_PARENT(t, 0);
2323 if (Scr.Hilite == t)
2325 border_draw_decorations(
2326 t, PART_ALL, False, True, CLEAR_ALL,
2327 NULL, NULL);
2330 /* AS stuff starts here dje */
2331 if (FW_W_ICON_PIXMAP(t))
2333 XUnmapWindow(dpy, FW_W_ICON_PIXMAP(t));
2335 if (FW_W_ICON_TITLE(t))
2337 XUnmapWindow(dpy, FW_W_ICON_TITLE(t));
2339 XFlush(dpy);
2340 /* End AS */
2341 XMapWindow(dpy, FW_W(t));
2342 if (t->Desk == Scr.CurrentDesk)
2344 rectangle r;
2346 get_icon_geometry(t, &r);
2347 /* update absoluthe geometry in case the icon
2348 * was moved over a page boundary; the move
2349 * code already takes care of keeping the frame
2350 * geometry up to date */
2351 update_absolute_geometry(t);
2352 if (IsRectangleOnThisPage(&r, t->Desk) &&
2353 !IsRectangleOnThisPage(
2354 &(t->g.frame), t->Desk))
2356 /* Make sure we keep it on screen when
2357 * de-iconifying. */
2358 t->g.frame.x -=
2359 truncate_to_multiple(
2360 t->g.frame.x,
2361 Scr.MyDisplayWidth);
2362 t->g.frame.y -=
2363 truncate_to_multiple(
2364 t->g.frame.y,
2365 Scr.MyDisplayHeight);
2366 XMoveWindow(
2367 dpy, FW_W_FRAME(t),
2368 t->g.frame.x, t->g.frame.y);
2369 update_absolute_geometry(t);
2370 maximize_adjust_offset(t);
2373 /* domivogt (1-Mar-2000): The next block is a hack to
2374 * prevent animation if the window has an icon, but
2375 * neither a pixmap nor a title. */
2376 if (HAS_NO_ICON_TITLE(t) && FW_W_ICON_PIXMAP(t) == None)
2378 memset(&fw->icon_g, 0, sizeof(fw->icon_g));
2380 get_icon_geometry(t, &icon_rect);
2381 /* if this fails it does not overwrite icon_rect */
2382 EWMH_GetIconGeometry(t, &icon_rect);
2383 if (t == fw)
2385 BroadcastPacket(
2386 M_DEICONIFY, 11, (long)FW_W(t),
2387 (long)FW_W_FRAME(t), (unsigned long)t,
2388 (long)icon_rect.x, (long)icon_rect.y,
2389 (long)icon_rect.width,
2390 (long)icon_rect.height,
2391 (long)t->g.frame.x,
2392 (long)t->g.frame.y,
2393 (long)t->g.frame.width,
2394 (long)t->g.frame.height);
2396 else
2398 BroadcastPacket(
2399 M_DEICONIFY, 7, (long)FW_W(t),
2400 (long)FW_W_FRAME(t),
2401 (unsigned long)t, (long)icon_rect.x,
2402 (long)icon_rect.y,
2403 (long)icon_rect.width,
2404 (long)icon_rect.height);
2406 XMapWindow(dpy, FW_W_PARENT(t));
2407 if (t->Desk == Scr.CurrentDesk)
2409 XMapWindow(dpy, FW_W_FRAME(t));
2410 SET_MAP_PENDING(t, 1);
2412 SetMapStateProp(t, NormalState);
2413 SET_ICONIFIED(t, 0);
2414 SET_ICON_UNMAPPED(t, 0);
2415 SET_ICON_ENTERED(t, 0);
2416 /* Need to make sure the border is colored correctly,
2417 * in case it was stuck or unstuck while iconified. */
2418 tmp = Scr.Hilite;
2419 Scr.Hilite = t;
2420 border_draw_decorations(
2421 t, PART_ALL, (sf == t) ? True : False, True,
2422 CLEAR_ALL, NULL, NULL);
2423 Scr.Hilite = tmp;
2427 #if 1
2428 RaiseWindow(fw, False); /* moved dje */
2429 #endif
2430 if (sf == fw)
2432 /* update the focus to make sure the application knows its
2433 * state */
2434 if (!FP_DO_UNFOCUS_LEAVE(FW_FOCUS_POLICY(fw)))
2436 SetFocusWindow(fw, True, FOCUS_SET_FORCE);
2439 else if (FP_DO_SORT_WINDOWLIST_BY(FW_FOCUS_POLICY(fw)) ==
2440 FPOL_SORT_WL_BY_OPEN)
2442 SetFocusWindow(fw, True, FOCUS_SET_FORCE);
2444 focus_grab_buttons_on_layer(fw->layer);
2445 GNOME_SetWinArea(fw);
2447 return;
2453 * Iconifies the selected window
2456 void Iconify(FvwmWindow *fw, initial_window_options_t *win_opts)
2458 FvwmWindow *t;
2459 FvwmWindow *sf;
2460 XWindowAttributes winattrs = {0};
2461 unsigned long eventMask;
2462 rectangle icon_rect;
2464 if (!fw)
2466 return;
2468 if (!XGetWindowAttributes(dpy, FW_W(fw), &winattrs))
2470 return;
2473 /* make sure fw->flags.is_map_pending is OK */
2474 if ((winattrs.map_state == IsViewable) && IS_MAP_PENDING(fw))
2476 SET_MAP_PENDING(fw, 0);
2479 if (IS_MAP_PENDING(fw))
2481 /* final state: iconified */
2482 SET_ICONIFY_AFTER_MAP(fw, 1);
2483 return;
2485 eventMask = winattrs.your_event_mask;
2487 mark_transient_subtree(fw, MARK_ALL_LAYERS, MARK_ALL, False, True);
2488 sf = get_focus_window();
2489 if (sf && IS_IN_TRANSIENT_SUBTREE(sf))
2491 restore_focus_after_unmap(sf, True);
2492 /* restore_focus_after_unmap() destorys the flags set by
2493 * mark_transient_subtree(), so we have to unfortunately call
2494 * it again. */
2495 mark_transient_subtree(
2496 fw, MARK_ALL_LAYERS, MARK_ALL, False, True);
2498 /* iconify transients first */
2499 for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
2501 if (t == fw || IS_IN_TRANSIENT_SUBTREE(t))
2503 SET_IN_TRANSIENT_SUBTREE(t, 0);
2504 SET_ICON_ENTERED(t, 0);
2505 /* Prevent the receipt of an UnmapNotify, since that
2506 * would cause a transition to the Withdrawn state. */
2507 SET_MAPPED(t, 0);
2508 XSelectInput(
2509 dpy, FW_W(t), eventMask & ~StructureNotifyMask);
2510 XUnmapWindow(dpy, FW_W(t));
2511 XSelectInput(dpy, FW_W(t), eventMask);
2512 XUnmapWindow(dpy, FW_W_FRAME(t));
2513 border_undraw_decorations(t);
2514 t->DeIconifyDesk = t->Desk;
2515 if (FW_W_ICON_TITLE(t))
2517 XUnmapWindow(dpy, FW_W_ICON_TITLE(t));
2519 if (FW_W_ICON_PIXMAP(t))
2521 XUnmapWindow(dpy, FW_W_ICON_PIXMAP(t));
2524 SetMapStateProp(t, IconicState);
2525 border_draw_decorations(
2526 t, PART_ALL, False, False, CLEAR_ALL, NULL,
2527 NULL);
2528 if (t == fw && !IS_ICONIFIED_BY_PARENT(fw))
2530 SET_ICONIFY_PENDING(t, 1);
2532 else
2534 rectangle g;
2536 SET_ICONIFIED(t, 1);
2537 SET_ICON_UNMAPPED(t, 1);
2538 SET_ICONIFIED_BY_PARENT(t, 1);
2539 get_icon_geometry(t, &g);
2540 BroadcastPacket(
2541 M_ICONIFY, 7, (long)FW_W(t),
2542 (long)FW_W_FRAME(t),
2543 (unsigned long)t, (long)-32768,
2544 (long)-32768, (long)g.width,
2545 (long)g.height);
2546 BroadcastConfig(M_CONFIGURE_WINDOW,t);
2548 } /* if */
2549 } /* for */
2551 /* necessary during a recapture */
2552 if (IS_ICONIFIED_BY_PARENT(fw))
2554 return;
2557 if (FW_W_ICON_TITLE(fw) == None || HAS_ICON_CHANGED(fw))
2559 if (IS_ICON_MOVED(fw) || win_opts->flags.use_initial_icon_xy)
2561 rectangle g;
2563 get_icon_geometry(fw, &g);
2564 if (win_opts->flags.use_initial_icon_xy)
2566 g.x = win_opts->initial_icon_x;
2567 g.y = win_opts->initial_icon_y;
2569 CreateIconWindow(fw, g.x, g.y);
2571 else
2573 CreateIconWindow(
2574 fw, win_opts->default_icon_x,
2575 win_opts->default_icon_y);
2577 SET_HAS_ICON_CHANGED(fw, 0);
2579 else if (FW_W_ICON_TITLE(fw) && !FW_W_ICON_PIXMAP(fw))
2581 /* if no pixmap we want icon width to change to text width
2582 * every iconify; not necessary if the icon was created above */
2583 setup_icon_title_size(fw);
2586 /* this condition will be true unless we restore a window to
2587 * iconified state from a saved session. */
2588 if (win_opts->initial_state != IconicState ||
2589 (!IS_ICON_MOVED(fw) && !win_opts->flags.use_initial_icon_xy))
2591 AutoPlaceIcon(fw, win_opts, True);
2593 /* domivogt (12-Mar-2003): Clean out the icon geometry if there is no
2594 * icon. Necessary to initialise the values and to suppress animation
2595 * if there is no icon. */
2596 if (HAS_NO_ICON_TITLE(fw) && FW_W_ICON_PIXMAP(fw) == None)
2598 clear_icon_dimensions(fw);
2600 SET_ICONIFIED(fw, 1);
2601 SET_ICON_UNMAPPED(fw, 0);
2602 get_icon_geometry(fw, &icon_rect);
2603 /* if this fails it does not overwrite icon_rect */
2604 EWMH_GetIconGeometry(fw, &icon_rect);
2605 BroadcastPacket(
2606 M_ICONIFY, 11, (long)FW_W(fw), (long)FW_W_FRAME(fw),
2607 (unsigned long)fw, (long)icon_rect.x, (long)icon_rect.y,
2608 (long)icon_rect.width, (long)icon_rect.height,
2609 /* next 4 added for Animate module */
2610 (long)fw->g.frame.x, (long)fw->g.frame.y,
2611 (long)fw->g.frame.width, (long)fw->g.frame.height);
2612 BroadcastConfig(M_CONFIGURE_WINDOW,fw);
2614 if (win_opts->initial_state != IconicState ||
2615 (!IS_ICON_MOVED(fw) && !win_opts->flags.use_initial_icon_xy))
2617 LowerWindow(fw, False);
2619 if (IS_ICON_STICKY_ACROSS_DESKS(fw) || IS_STICKY_ACROSS_DESKS(fw))
2621 fw->Desk = Scr.CurrentDesk;
2623 if (fw->Desk == Scr.CurrentDesk)
2625 if (FW_W_ICON_TITLE(fw) != None)
2627 XMapWindow(dpy, FW_W_ICON_TITLE(fw));
2629 if (FW_W_ICON_PIXMAP(fw) != None)
2631 XMapWindow(dpy, FW_W_ICON_PIXMAP(fw));
2634 focus_grab_buttons_on_layer(fw->layer);
2636 return;
2641 * This is used to tell applications which windows on the screen are
2642 * top level appication windows, and which windows are the icon windows
2643 * that go with them.
2646 void SetMapStateProp(const FvwmWindow *fw, int state)
2648 /* "suggested" by ICCCM version 1 */
2649 unsigned long data[2];
2651 data[0] = (unsigned long) state;
2652 data[1] = (unsigned long) FW_W_ICON_TITLE(fw);
2653 /* data[2] = (unsigned long) FW_W_ICON_PIXMAP(fw);*/
2655 XChangeProperty(
2656 dpy, FW_W(fw), _XA_WM_STATE, _XA_WM_STATE, 32, PropModeReplace,
2657 (unsigned char *) data, 2);
2659 return;
2662 void CMD_Iconify(F_CMD_ARGS)
2664 int toggle;
2665 FvwmWindow * const fw = exc->w.fw;
2667 toggle = ParseToggleArgument(action, NULL, -1, 0);
2668 if (toggle == -1)
2670 if (GetIntegerArguments(action, NULL, &toggle, 1) > 0)
2672 if (toggle > 0)
2674 toggle = 1;
2676 else if (toggle < 0)
2678 toggle = 0;
2680 else
2682 toggle = -1;
2686 if (toggle == -1)
2688 toggle = (IS_ICONIFIED(fw)) ? 0 : 1;
2691 if (IS_ICONIFIED(fw))
2693 if (toggle == 0)
2695 DeIconify(fw);
2696 EWMH_SetWMState(fw, False);
2699 else
2701 if (toggle == 1)
2703 initial_window_options_t win_opts;
2705 if (
2706 !is_function_allowed(
2707 F_ICONIFY, NULL, fw, RQORIG_PROGRAM,
2708 True))
2710 XBell(dpy, 0);
2712 return;
2714 memset(&win_opts, 0, sizeof(win_opts));
2715 fev_get_evpos_or_query(
2716 dpy, Scr.Root, NULL, &win_opts.default_icon_x,
2717 &win_opts.default_icon_y);
2718 Iconify(fw, &win_opts);
2719 EWMH_SetWMState(fw, False);
2723 return;