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