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