Refactor counting of windows with IndexedWindowName, and IndexedIconName
[fvwm.git] / fvwm / add_window.c
blob361a6863ad469eab6e1fbbfc7e8a8f64e9b56907
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 /* This module is based on Twm, but has been siginificantly modified
17 * by Rob Nation
20 * Copyright 1988 by Evans & Sutherland Computer Corporation,
21 * Salt Lake City, Utah
22 * Portions Copyright 1989 by the Massachusetts Institute of Technology
23 * Cambridge, Massachusetts
25 * All Rights Reserved
27 * Permission to use, copy, modify, and distribute this software and
28 * its documentation for any purpose and without fee is hereby
29 * granted, provided that the above copyright notice appear in all
30 * copies and that both that copyright notice and this permis-
31 * sion notice appear in supporting documentation, and that the
32 * names of Evans & Sutherland and M.I.T. not be used in advertising
33 * in publicity pertaining to distribution of the software without
34 * specific, written prior permission.
36 * EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD
37 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
38 * ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR
39 * M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM-
40 * AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
41 * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
42 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
43 * OR PERFORMANCE OF THIS SOFTWARE.
46 /* ---------------------------- included header files ---------------------- */
48 #include "config.h"
50 #include <stdio.h>
52 #include "libs/fvwmlib.h"
53 #include "libs/FShape.h"
54 #include "libs/FScreen.h"
55 #include "libs/Picture.h"
56 #include "libs/PictureUtils.h"
57 #include "libs/charmap.h"
58 #include "libs/wcontext.h"
59 #include "libs/Grab.h"
60 #include "libs/Strings.h"
61 #include "libs/XResource.h"
62 #include "fvwm.h"
63 #include "externs.h"
64 #include "cursor.h"
65 #include "execcontext.h"
66 #include "commands.h"
67 #include "bindings.h"
68 #include "misc.h"
69 #include "screen.h"
70 #include "add_window.h"
71 #include "events.h"
72 #include "eventhandler.h"
73 #include "eventmask.h"
74 #include "module_interface.h"
75 #include "stack.h"
76 #include "update.h"
77 #include "style.h"
78 #include "icons.h"
79 #include "gnome.h"
80 #include "ewmh.h"
81 #include "focus.h"
82 #include "placement.h"
83 #include "geometry.h"
84 #include "session.h"
85 #include "move_resize.h"
86 #include "borders.h"
87 #include "frame.h"
88 #include "colormaps.h"
89 #include "decorations.h"
90 #include "functions.h"
92 /* ---------------------------- local definitions -------------------------- */
94 /* ---------------------------- local macros ------------------------------- */
96 /* ---------------------------- imports ------------------------------------ */
98 /* ---------------------------- included code files ------------------------ */
100 /* ---------------------------- local types -------------------------------- */
102 /* ---------------------------- forward declarations ----------------------- */
104 /* ---------------------------- local variables ---------------------------- */
106 /* ---------------------------- exported variables (globals) --------------- */
108 char NoName[] = "Untitled"; /* name if no name in XA_WM_NAME */
109 char NoClass[] = "NoClass"; /* Class if no res_class in class hints */
110 char NoResource[] = "NoResource"; /* Class if no res_name in class hints */
112 /* ---------------------------- local functions ---------------------------- */
114 static void delete_client_context(FvwmWindow *fw)
116 FvwmWindow *cw;
118 /* We can not simply delete the context. X might have reused the
119 * window structure so we would delete the context that was established
120 * by another FvwmWindow structure in the mean time. */
121 if (XFindContext(
122 dpy, FW_W(fw), FvwmContext, (caddr_t *)&cw) !=
123 XCNOENT && cw == fw)
125 XDeleteContext(dpy, FW_W(fw), FvwmContext);
128 return;
133 * Procedure:
134 * CaptureOneWindow
135 * CaptureAllWindows
137 * Decorates windows at start-up and during recaptures
141 static void CaptureOneWindow(
142 const exec_context_t *exc, FvwmWindow *fw, Window window,
143 Window keep_on_top_win, Window parent_win, Bool is_recapture)
145 Window w;
146 unsigned long data[1];
147 initial_window_options_t win_opts;
148 evh_args_t ea;
149 exec_context_changes_t ecc;
150 XEvent e;
152 if (fw == NULL)
154 return;
156 if (IS_SCHEDULED_FOR_DESTROY(fw))
158 /* Fvwm might crash in complex functions if we really try to
159 * the dying window here because AddWindow() may fail and leave
160 * a destroyed window in some structures. By the way, it is
161 * pretty useless to recapture a window that will vanish in a
162 * moment. */
163 return;
165 /* Grab the server to make sure the window does not die during the
166 * recapture. */
167 MyXGrabServer(dpy);
168 if (
169 !XGetGeometry(
170 dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY,
171 (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
172 (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth))
174 /* The window has already died, do not recapture it! */
175 MyXUngrabServer(dpy);
176 return;
178 if (XFindContext(dpy, window, FvwmContext, (caddr_t *)&fw) != XCNOENT)
180 Bool is_mapped = IS_MAPPED(fw);
182 memset(&win_opts, 0, sizeof(win_opts));
183 win_opts.initial_state = DontCareState;
184 win_opts.flags.do_override_ppos = 1;
185 win_opts.flags.is_recapture = 1;
186 if (IS_ICONIFIED(fw))
188 win_opts.initial_state = IconicState;
189 win_opts.flags.is_iconified_by_parent =
190 IS_ICONIFIED_BY_PARENT(fw);
192 else
194 win_opts.initial_state = NormalState;
195 win_opts.flags.is_iconified_by_parent = 0;
196 if (Scr.CurrentDesk != fw->Desk)
198 SetMapStateProp(fw, NormalState);
201 data[0] = (unsigned long) fw->Desk;
202 XChangeProperty(
203 dpy, FW_W(fw), _XA_WM_DESKTOP, _XA_WM_DESKTOP, 32,
204 PropModeReplace, (unsigned char *) data, 1);
206 /* are all these really needed ? */
207 /* EWMH_SetWMDesktop(fw); */
208 GNOME_SetHints(fw);
209 GNOME_SetDesk(fw);
210 GNOME_SetLayer(fw);
211 GNOME_SetWinArea(fw);
213 XSelectInput(dpy, FW_W(fw), NoEventMask);
214 w = FW_W(fw);
215 XUnmapWindow(dpy, FW_W_FRAME(fw));
216 border_undraw_decorations(fw);
217 RestoreWithdrawnLocation(fw, is_recapture, parent_win);
218 SET_DO_REUSE_DESTROYED(fw, 1); /* RBW - 1999/03/20 */
219 destroy_window(fw);
220 win_opts.flags.is_menu =
221 (is_recapture && fw != NULL && IS_TEAR_OFF_MENU(fw));
224 fev_make_null_event(&e, dpy);
225 e.xmaprequest.window = w;
226 e.xmaprequest.parent = Scr.Root;
227 ecc.x.etrigger = &e;
228 ecc.w.fw = NULL;
229 ecc.w.w = w;
230 ecc.w.wcontext = C_ROOT;
231 ea.exc = exc_clone_context(
232 exc, &ecc, ECC_ETRIGGER | ECC_FW | ECC_W |
233 ECC_WCONTEXT);
234 HandleMapRequestKeepRaised(&ea, keep_on_top_win, fw, &win_opts);
235 exc_destroy_context(ea.exc);
237 /* HandleMapRequestKeepRaised may have destroyed the fw if the
238 * window vanished while in AddWindow(), so don't access fw
239 * anymore before checking if it is a valid window. */
240 if (check_if_fvwm_window_exists(fw))
242 if (!fFvwmInStartup)
244 SET_MAP_PENDING(fw, 0);
245 SET_MAPPED(fw, is_mapped);
249 MyXUngrabServer(dpy);
251 return;
254 /* Put a transparent window all over the screen to hide what happens below. */
255 static void hide_screen(
256 Bool do_hide, Window *ret_hide_win, Window *ret_parent_win)
258 static Bool is_hidden = False;
259 static Window hide_win = None;
260 static Window parent_win = None;
261 XSetWindowAttributes xswa;
262 unsigned long valuemask;
264 if (do_hide == is_hidden)
266 /* nothing to do */
267 if (ret_hide_win)
269 *ret_hide_win = hide_win;
271 if (ret_parent_win)
273 *ret_parent_win = parent_win;
276 return;
278 is_hidden = do_hide;
279 if (do_hide)
281 xswa.override_redirect = True;
282 xswa.cursor = Scr.FvwmCursors[CRS_WAIT];
283 xswa.backing_store = NotUseful;
284 xswa.save_under = False;
285 xswa.background_pixmap = None;
286 valuemask = CWOverrideRedirect | CWCursor | CWSaveUnder |
287 CWBackingStore | CWBackPixmap;
288 hide_win = XCreateWindow(
289 dpy, Scr.Root, 0, 0, Scr.MyDisplayWidth,
290 Scr.MyDisplayHeight, 0, Pdepth, InputOutput,
291 Pvisual, valuemask, &xswa);
292 if (hide_win)
294 /* When recapturing, all windows are reparented to this
295 * window. If they are reparented to the root window,
296 * they will flash over the hide_win with XFree. So
297 * reparent them to an unmapped window that looks like
298 * the root window. */
299 parent_win = XCreateWindow(
300 dpy, Scr.Root, 0, 0, Scr.MyDisplayWidth,
301 Scr.MyDisplayHeight, 0, CopyFromParent,
302 InputOutput, CopyFromParent, valuemask, &xswa);
303 if (!parent_win)
305 XDestroyWindow(dpy, hide_win);
306 hide_win = None;
308 else
310 XMapWindow(dpy, hide_win);
311 XFlush(dpy);
315 else
317 if (hide_win != None)
319 XDestroyWindow(dpy, hide_win);
321 if (parent_win != None)
323 XDestroyWindow(dpy, parent_win);
325 XFlush(dpy);
326 hide_win = None;
327 parent_win = None;
329 if (ret_hide_win)
331 *ret_hide_win = hide_win;
333 if (ret_parent_win)
335 *ret_parent_win = parent_win;
338 return;
343 * Procedure:
344 * MappedNotOverride - checks to see if we should really
345 * put a fvwm frame on the window
347 * Returned Value:
348 * 1 - go ahead and frame the window
349 * 0 - don't frame the window
351 * Inputs:
352 * w - the window to check
356 static int MappedNotOverride(
357 Window w, initial_window_options_t *win_opts)
359 XWindowAttributes wa;
360 Atom atype;
361 int aformat;
362 unsigned long nitems, bytes_remain;
363 unsigned char *prop;
365 win_opts->initial_state = DontCareState;
366 if ((w==Scr.NoFocusWin)||(!XGetWindowAttributes(dpy, w, &wa)))
368 return 0;
370 if (XGetWindowProperty(
371 dpy,w,_XA_WM_STATE,0L,3L,False,_XA_WM_STATE,
372 &atype,&aformat,&nitems,&bytes_remain,&prop)==Success)
374 if (prop != NULL)
376 win_opts->initial_state = *(long *)prop;
377 XFree(prop);
380 if (wa.override_redirect == True)
382 XSelectInput(dpy, w, XEVMASK_ORW);
383 XFlush(dpy);
386 return (((win_opts->initial_state == IconicState) ||
387 (wa.map_state != IsUnmapped)) &&
388 (wa.override_redirect != True));
391 static void do_recapture(F_CMD_ARGS, Bool fSingle)
393 FvwmWindow *fw = exc->w.fw;
395 MyXGrabServer(dpy);
396 if (fSingle)
398 CaptureOneWindow(
399 exc, fw, FW_W(fw), None, None, True);
401 else
403 CaptureAllWindows(exc, True);
405 /* Throw away queued up events. We don't want user input during a
406 * recapture. The window the user clicks in might disapper at the very
407 * same moment and the click goes through to the root window. Not good
409 XAllowEvents(dpy, AsyncPointer, CurrentTime);
410 discard_events(
411 ButtonPressMask|ButtonReleaseMask|ButtonMotionMask| \
412 PointerMotionMask|KeyPressMask|KeyReleaseMask);
413 #ifdef DEBUG_STACK_RING
414 verify_stack_ring_consistency();
415 #endif
416 MyXUngrabServer(dpy);
418 return;
421 static void setup_window_structure(
422 FvwmWindow **pfw, Window w, FvwmWindow *ReuseWin)
424 FvwmWindow save_state;
425 FvwmWindow *savewin = NULL;
428 Allocate space for the FvwmWindow struct, or reuse an
429 old one (on Recapture).
431 if (ReuseWin == NULL)
433 *pfw = (FvwmWindow *)safemalloc(sizeof(FvwmWindow));
435 else
437 *pfw = ReuseWin;
438 savewin = &save_state;
439 memcpy(savewin, ReuseWin, sizeof(FvwmWindow));
443 RBW - 1999/05/28 - modify this when we implement the preserving of
444 various states across a Recapture. The Destroy function in misc.c may
445 also need tweaking, depending on what you want to preserve.
446 For now, just zap any old information, except the desk.
448 memset(*pfw, '\0', sizeof(FvwmWindow));
449 FW_W(*pfw) = w;
450 if (savewin != NULL)
452 (*pfw)->Desk = savewin->Desk;
453 SET_SHADED(*pfw, IS_SHADED(savewin));
454 SET_USED_TITLE_DIR_FOR_SHADING(
455 *pfw, USED_TITLE_DIR_FOR_SHADING(savewin));
456 SET_SHADED_DIR(*pfw, SHADED_DIR(savewin));
457 SET_NAME_CHANGED(*pfw,IS_NAME_CHANGED(savewin));
458 (*pfw)->placed_by_button = savewin->placed_by_button;
459 SET_PLACED_BY_FVWM(*pfw, IS_PLACED_BY_FVWM(savewin));
460 SET_HAS_EWMH_WM_ICON_HINT(*pfw, HAS_EWMH_WM_ICON_HINT(savewin));
461 (*pfw)->ewmh_mini_icon_width = savewin->ewmh_mini_icon_width;
462 (*pfw)->ewmh_mini_icon_height = savewin->ewmh_mini_icon_height;
463 (*pfw)->ewmh_icon_width = savewin->ewmh_icon_width;
464 (*pfw)->ewmh_icon_height = savewin->ewmh_icon_height;
465 (*pfw)->ewmh_hint_desktop = savewin->ewmh_hint_desktop;
466 /* restore ewmh state */
467 EWMH_SetWMState(savewin, True);
468 SET_HAS_EWMH_INIT_WM_DESKTOP(
469 *pfw, HAS_EWMH_INIT_WM_DESKTOP(savewin));
470 SET_HAS_EWMH_INIT_FULLSCREEN_STATE(
471 *pfw, HAS_EWMH_INIT_FULLSCREEN_STATE(savewin));
472 SET_HAS_EWMH_INIT_HIDDEN_STATE(
473 *pfw, HAS_EWMH_INIT_HIDDEN_STATE(savewin));
474 SET_HAS_EWMH_INIT_MAXHORIZ_STATE(
475 *pfw, HAS_EWMH_INIT_MAXHORIZ_STATE(savewin));
476 SET_HAS_EWMH_INIT_MAXVERT_STATE(
477 *pfw, HAS_EWMH_INIT_MAXVERT_STATE(savewin));
478 SET_HAS_EWMH_INIT_SHADED_STATE(
479 *pfw, HAS_EWMH_INIT_SHADED_STATE(savewin));
480 SET_HAS_EWMH_INIT_STICKY_STATE(
481 *pfw, HAS_EWMH_INIT_STICKY_STATE(savewin));
482 CLEAR_USER_STATES(*pfw, ~0);
483 SET_USER_STATES(*pfw, GET_USER_STATES(savewin));
485 else
487 /* make sure that new windows *remember* being shaded with
488 * title dir last */
489 SET_USED_TITLE_DIR_FOR_SHADING(*pfw,1);
492 (*pfw)->cmap_windows = (Window *)NULL;
493 if (FMiniIconsSupported)
495 (*pfw)->mini_pixmap_file = NULL;
496 (*pfw)->mini_icon = NULL;
499 return;
502 static void setup_name_count(FvwmWindow *fw, Bool is_icon)
504 FvwmWindow *t;
505 int count = 0;
506 int win_count;
507 int win_count_counterpart;
508 Bool done = False;
509 FlocaleNameString *titlename, *title_counterpart;
510 FlocaleNameString *t_titlename, *t_title_counterpart;
512 titlename = (is_icon) ?
513 &(fw->icon_name) : &(fw->name);
515 title_counterpart = (is_icon) ?
516 &(fw->name) : &(fw->icon_name);
518 if (!titlename->name)
520 done = True;
523 if (titlename->name && title_counterpart->name &&
524 strcmp(titlename->name, title_counterpart->name) == 0)
526 count = is_icon ? fw->icon_name_count :
527 fw->name_count;
530 while (!done)
532 done = True;
533 for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
535 if (t == fw)
537 continue;
539 win_count = is_icon ? t->icon_name_count :
540 t->name_count;
541 win_count_counterpart = is_icon ?
542 t->name_count : t->icon_name_count;
544 t_titlename = is_icon ? &(t->icon_name) :
545 &(t->name);
546 t_title_counterpart = is_icon ? &(t->name) :
547 &(t->icon_name);
549 if ((t_titlename->name &&
550 strcmp(titlename->name,
551 t_titlename->name) == 0 &&
552 win_count == count) ||
553 (t_title_counterpart->name &&
554 strcmp(t_title_counterpart->name,
555 titlename->name) == 0 &&
556 win_count_counterpart == count))
559 count++;
560 done = False;
565 if (is_icon)
567 fw->icon_name_count = count;
568 } else {
569 fw->name_count = count;
572 return;
575 static void setup_class_and_resource(FvwmWindow *fw)
577 /* removing NoClass change for now... */
578 fw->class.res_name = NoResource;
579 fw->class.res_class = NoClass;
580 XGetClassHint(dpy, FW_W(fw), &fw->class);
581 if (fw->class.res_name == NULL)
583 fw->class.res_name = NoResource;
585 if (fw->class.res_class == NULL)
587 fw->class.res_class = NoClass;
589 FetchWmProtocols (fw);
590 FetchWmColormapWindows (fw);
592 return;
595 static void setup_window_attr(
596 FvwmWindow *fw, XWindowAttributes *ret_attr)
598 if (XGetWindowAttributes(dpy, FW_W(fw), ret_attr) == 0)
600 /* can't happen because fvwm has grabbed the server and does
601 * not destroy the window itself */
603 fw->attr_backup.backing_store = ret_attr->backing_store;
604 fw->attr_backup.border_width = ret_attr->border_width;
605 fw->attr_backup.depth = ret_attr->depth;
606 fw->attr_backup.bit_gravity = ret_attr->bit_gravity;
607 fw->attr_backup.is_bit_gravity_stored = 0;
608 fw->attr_backup.visual = ret_attr->visual;
609 fw->attr_backup.colormap = ret_attr->colormap;
611 return;
614 static void destroy_window_font(FvwmWindow *fw)
616 if (IS_WINDOW_FONT_LOADED(fw) && !USING_DEFAULT_WINDOW_FONT(fw) &&
617 fw->title_font != Scr.DefaultFont)
619 FlocaleUnloadFont(dpy, fw->title_font);
621 SET_WINDOW_FONT_LOADED(fw, 0);
622 /* Fall back to default font. There are some race conditions when a
623 * window is destroyed and recaptured where an invalid font might be
624 * accessed otherwise. */
625 fw->title_font = Scr.DefaultFont;
626 SET_USING_DEFAULT_WINDOW_FONT(fw, 1);
628 return;
631 static void destroy_icon_font(FvwmWindow *fw)
633 if (IS_ICON_FONT_LOADED(fw) && !USING_DEFAULT_ICON_FONT(fw) &&
634 fw->icon_font != Scr.DefaultFont)
636 FlocaleUnloadFont(dpy, fw->icon_font);
638 SET_ICON_FONT_LOADED(fw, 0);
639 /* Fall back to default font (see comment above). */
640 fw->icon_font = Scr.DefaultFont;
641 SET_USING_DEFAULT_ICON_FONT(fw, 1);
643 return;
646 static void adjust_fvwm_internal_windows(FvwmWindow *fw)
648 if (fw == Scr.Hilite)
650 Scr.Hilite = NULL;
652 update_last_screen_focus_window(fw);
653 restore_focus_after_unmap(fw, False);
654 frame_destroyed_frame(FW_W(fw));
655 if (FW_W(fw) == Scr.StolenFocusWin)
657 Scr.StolenFocusWin = None;
659 if (Scr.focus_in_pending_window == fw)
661 Scr.focus_in_pending_window = NULL;
663 if (Scr.cascade_window == fw)
665 Scr.cascade_window = NULL;
668 return;
671 static void broadcast_mini_icon(FvwmWindow *fw)
673 if (!FMiniIconsSupported)
675 return;
677 if (fw->mini_pixmap_file && fw->mini_icon)
679 BroadcastFvwmPicture(
680 M_MINI_ICON,
681 FW_W(fw), FW_W_FRAME(fw), (unsigned long)fw,
682 fw->mini_icon, fw->mini_pixmap_file);
685 return;
688 static void setup_mini_icon(FvwmWindow *fw, window_style *pstyle)
690 FvwmPictureAttributes fpa;
692 if (!FMiniIconsSupported)
694 return;
696 if (SHAS_MINI_ICON(&pstyle->flags))
698 fw->mini_pixmap_file = SGET_MINI_ICON_NAME(*pstyle);
700 else
702 fw->mini_pixmap_file = NULL;
704 if (fw->mini_pixmap_file)
706 fpa.mask = 0;
707 fw->mini_icon = PCacheFvwmPicture(
708 dpy, Scr.NoFocusWin, NULL, fw->mini_pixmap_file, fpa);
710 else
712 fw->mini_icon = NULL;
715 return;
719 * Copy icon size limits from window_style structure to FvwmWindow
720 * structure.
722 void setup_icon_size_limits(FvwmWindow *fw, window_style *pstyle)
724 if (SHAS_ICON_SIZE_LIMITS(&pstyle->flags))
726 fw->min_icon_width = SGET_MIN_ICON_WIDTH(*pstyle);
727 fw->min_icon_height = SGET_MIN_ICON_HEIGHT(*pstyle);
728 fw->max_icon_width = SGET_MAX_ICON_WIDTH(*pstyle);
729 fw->max_icon_height = SGET_MAX_ICON_HEIGHT(*pstyle);
730 fw->icon_resize_type = SGET_ICON_RESIZE_TYPE(*pstyle);
732 else
734 fw->min_icon_width = MIN_ALLOWABLE_ICON_DIMENSION;
735 fw->min_icon_height = MIN_ALLOWABLE_ICON_DIMENSION;
736 fw->max_icon_width = MAX_ALLOWABLE_ICON_DIMENSION;
737 fw->max_icon_height = MAX_ALLOWABLE_ICON_DIMENSION;
738 fw->icon_resize_type = ICON_RESIZE_TYPE_NONE;
741 return;
744 void setup_icon_background_parameters(FvwmWindow *fw, window_style *pstyle)
746 if (SHAS_ICON_BACKGROUND_PADDING(&pstyle->flags))
748 fw->icon_background_padding =
749 SGET_ICON_BACKGROUND_PADDING(*pstyle);
751 else
753 fw->icon_background_padding = ICON_BACKGROUND_PADDING;
755 if (SHAS_ICON_BACKGROUND_RELIEF(&pstyle->flags))
757 fw->icon_background_relief =
758 SGET_ICON_BACKGROUND_RELIEF(*pstyle);
760 else
762 fw->icon_background_relief = ICON_RELIEF_WIDTH;
764 return;
767 void setup_icon_title_parameters(FvwmWindow *fw, window_style *pstyle)
769 if (SHAS_ICON_TITLE_RELIEF(&pstyle->flags))
771 fw->icon_title_relief =
772 SGET_ICON_TITLE_RELIEF(*pstyle);
774 else
776 fw->icon_title_relief = ICON_RELIEF_WIDTH;
778 return;
781 void setup_numeric_vals(FvwmWindow *fw, window_style *pstyle)
783 /****** window shading ******/
784 fw->shade_anim_steps = pstyle->shade_anim_steps;
786 /****** snapattraction, snapgrid, paging ******/
787 fw->snap_proximity = pstyle->snap_proximity;
788 fw->snap_mode = pstyle->snap_mode;
789 fw->snap_grid_x = pstyle->snap_grid_x;
790 fw->snap_grid_y = pstyle->snap_grid_y;
791 if (pstyle->flags.has_edge_delay_ms_move)
793 fw->edge_delay_ms_move = pstyle->edge_delay_ms_move;
795 else
797 fw->edge_delay_ms_move = DEFAULT_MOVE_DELAY;
799 if (pstyle->flags.has_edge_delay_ms_resize)
801 fw->edge_delay_ms_resize = pstyle->edge_delay_ms_resize;
803 else
805 fw->edge_delay_ms_resize = DEFAULT_RESIZE_DELAY;
807 fw->edge_resistance_move = pstyle->edge_resistance_move;
808 fw->edge_resistance_xinerama_move =
809 pstyle->edge_resistance_xinerama_move;
811 return;
814 static void setup_frame_window(
815 FvwmWindow *fw)
817 XSetWindowAttributes attributes;
818 int valuemask;
819 int depth;
820 Visual *visual;
821 FRenderPictFormat *format;
823 valuemask = CWBackingStore | CWBackPixmap | CWEventMask | CWSaveUnder
824 | CWCursor;
826 /* This adds preliminary support for ARGB windows in fvwm. It should
827 evolve to proper ARGB support in frames, menus and modules */
828 format=FRenderFindVisualFormat(dpy, fw->attr_backup.visual);
829 if (format != NULL && format->type == FRenderPictTypeDirect &&
830 format->direct.alphaMask > 0)
832 depth = fw->attr_backup.depth;
833 visual = fw->attr_backup.visual;
834 attributes.colormap = fw->attr_backup.colormap;
835 attributes.background_pixel = -1;
836 attributes.border_pixel = -1;
837 valuemask |= CWColormap | CWBackPixel | CWBorderPixel;
839 else
841 depth = CopyFromParent;
842 visual = CopyFromParent;
844 attributes.backing_store = NotUseful;
845 attributes.background_pixmap = None;
846 attributes.cursor = Scr.FvwmCursors[CRS_DEFAULT];
847 attributes.event_mask = XEVMASK_FRAMEW_CAPTURE;
848 attributes.save_under = False;
849 /* create the frame window, child of root, grandparent of client */
850 FW_W_FRAME(fw) = XCreateWindow(
851 dpy, Scr.Root, fw->g.frame.x, fw->g.frame.y,
852 fw->g.frame.width, fw->g.frame.height, 0, depth,
853 InputOutput, visual, valuemask, &attributes);
854 XSaveContext(dpy, FW_W(fw), FvwmContext, (caddr_t) fw);
855 XSaveContext(dpy, FW_W_FRAME(fw), FvwmContext, (caddr_t) fw);
857 return;
860 static void setup_title_window(
861 FvwmWindow *fw, int valuemask, XSetWindowAttributes *pattributes)
863 valuemask |= CWCursor | CWEventMask;
864 pattributes->cursor = Scr.FvwmCursors[CRS_TITLE];
865 pattributes->event_mask = XEVMASK_TITLEW;
867 FW_W_TITLE(fw) = XCreateWindow(
868 dpy, FW_W_FRAME(fw), 0, 0, 1, 1, 0, Pdepth, InputOutput,
869 Pvisual, valuemask, pattributes);
870 XSaveContext(dpy, FW_W_TITLE(fw), FvwmContext, (caddr_t) fw);
872 return;
875 static void destroy_title_window(FvwmWindow *fw, Bool do_only_delete_context)
877 if (!do_only_delete_context)
879 XDestroyWindow(dpy, FW_W_TITLE(fw));
880 FW_W_TITLE(fw) = None;
882 XDeleteContext(dpy, FW_W_TITLE(fw), FvwmContext);
883 XFlush(dpy);
884 FW_W_TITLE(fw) = None;
886 return;
889 static void change_title_window(
890 FvwmWindow *fw, int valuemask, XSetWindowAttributes *pattributes)
892 if (HAS_TITLE(fw) && FW_W_TITLE(fw) == None)
894 setup_title_window(fw, valuemask, pattributes);
896 else if (!HAS_TITLE(fw) && FW_W_TITLE(fw) != None)
898 destroy_title_window(fw, False);
901 return;
904 static void setup_button_windows(
905 FvwmWindow *fw, int valuemask, XSetWindowAttributes *pattributes,
906 short buttons)
908 int i;
909 Bool has_button;
910 Bool is_deleted = False;
912 valuemask |= CWCursor | CWEventMask;
913 pattributes->cursor = Scr.FvwmCursors[CRS_SYS];
914 pattributes->event_mask = XEVMASK_BUTTONW;
916 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
918 has_button = (((!(i & 1) && i / 2 < Scr.nr_left_buttons) ||
919 ( (i & 1) && i / 2 < Scr.nr_right_buttons)) &&
920 (buttons & (1 << i)));
921 if (FW_W_BUTTON(fw, i) == None && has_button)
923 FW_W_BUTTON(fw, i) =
924 XCreateWindow(
925 dpy, FW_W_FRAME(fw), 0, 0, 1, 1, 0,
926 Pdepth, InputOutput, Pvisual,
927 valuemask, pattributes);
928 XSaveContext(
929 dpy, FW_W_BUTTON(fw, i), FvwmContext,
930 (caddr_t)fw);
932 else if (FW_W_BUTTON(fw, i) != None && !has_button)
934 /* destroy the current button window */
935 XDestroyWindow(dpy, FW_W_BUTTON(fw, i));
936 XDeleteContext(dpy, FW_W_BUTTON(fw, i), FvwmContext);
937 is_deleted = True;
938 FW_W_BUTTON(fw, i) = None;
941 if (is_deleted == True)
943 XFlush(dpy);
946 return;
949 static void destroy_button_windows(FvwmWindow *fw, Bool do_only_delete_context)
951 int i;
952 Bool is_deleted = False;
954 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
956 if (FW_W_BUTTON(fw, i) != None)
958 if (!do_only_delete_context)
960 XDestroyWindow(dpy, FW_W_BUTTON(fw, i));
961 FW_W_BUTTON(fw, i) = None;
963 XDeleteContext(dpy, FW_W_BUTTON(fw, i), FvwmContext);
964 is_deleted = True;
965 FW_W_BUTTON(fw, i) = None;
968 if (is_deleted == True)
970 XFlush(dpy);
973 return;
976 static void change_button_windows(
977 FvwmWindow *fw, int valuemask, XSetWindowAttributes *pattributes,
978 short buttons)
980 if (HAS_TITLE(fw))
982 setup_button_windows(
983 fw, valuemask, pattributes, buttons);
985 else
987 destroy_button_windows(fw, False);
990 return;
993 static void setup_parent_window(FvwmWindow *fw)
995 size_borders b;
997 XSetWindowAttributes attributes;
998 int valuemask;
1000 valuemask = CWBackingStore | CWBackPixmap | CWCursor | CWEventMask |
1001 CWSaveUnder;
1002 attributes.backing_store = NotUseful;
1003 attributes.background_pixmap = None;
1004 attributes.cursor = Scr.FvwmCursors[CRS_DEFAULT];
1005 attributes.event_mask = XEVMASK_PARENTW;
1006 attributes.save_under = False;
1008 /* This window is exactly the same size as the client for the benefit
1009 * of some clients */
1010 get_window_borders(fw, &b);
1011 FW_W_PARENT(fw) = XCreateWindow(
1012 dpy, FW_W_FRAME(fw), b.top_left.width, b.top_left.height,
1013 fw->g.frame.width - b.total_size.width,
1014 fw->g.frame.height - b.total_size.height,
1015 0, CopyFromParent, InputOutput, CopyFromParent, valuemask,
1016 &attributes);
1018 XSaveContext(dpy, FW_W_PARENT(fw), FvwmContext, (caddr_t) fw);
1020 return;
1023 static void setup_resize_handle_cursors(FvwmWindow *fw)
1025 unsigned long valuemask;
1026 XSetWindowAttributes attributes;
1027 int i;
1029 if (HAS_NO_BORDER(fw))
1031 return;
1033 valuemask = CWCursor;
1034 attributes.cursor = Scr.FvwmCursors[CRS_DEFAULT];
1036 for (i = 0; i < 4; i++)
1038 if (HAS_HANDLES(fw))
1040 attributes.cursor = Scr.FvwmCursors[CRS_TOP_LEFT + i];
1042 XChangeWindowAttributes(
1043 dpy, FW_W_CORNER(fw, i), valuemask, &attributes);
1044 if (HAS_HANDLES(fw))
1046 attributes.cursor = Scr.FvwmCursors[CRS_TOP + i];
1048 XChangeWindowAttributes(
1049 dpy, FW_W_SIDE(fw, i), valuemask, &attributes);
1052 return;
1055 static void setup_resize_handle_windows(FvwmWindow *fw)
1057 unsigned long valuemask;
1058 XSetWindowAttributes attributes;
1059 int i;
1060 int c_grav[4] = {
1061 NorthWestGravity,
1062 NorthEastGravity,
1063 SouthWestGravity,
1064 SouthEastGravity
1066 int s_grav[4] = {
1067 NorthWestGravity,
1068 NorthEastGravity,
1069 SouthWestGravity,
1070 NorthWestGravity
1073 if (HAS_NO_BORDER(fw))
1075 return;
1077 valuemask = CWEventMask | CWBackingStore | CWSaveUnder | CWWinGravity |
1078 CWBorderPixel | CWColormap;
1079 attributes.event_mask = XEVMASK_BORDERW;
1080 attributes.backing_store = NotUseful;
1081 attributes.save_under = False;
1082 attributes.border_pixel = 0;
1083 attributes.colormap = Pcmap;
1084 /* Just dump the windows any old place and let frame_setup_window take
1085 * care of the mess */
1086 for (i = 0; i < 4; i++)
1088 attributes.win_gravity = c_grav[i];
1089 FW_W_CORNER(fw, i) = XCreateWindow(
1090 dpy, FW_W_FRAME(fw), -1, -1, 1, 1, 0, Pdepth,
1091 InputOutput, Pvisual, valuemask, &attributes);
1092 XSaveContext(
1093 dpy, FW_W_CORNER(fw, i), FvwmContext, (caddr_t)fw);
1094 attributes.win_gravity = s_grav[i];
1095 FW_W_SIDE(fw, i) = XCreateWindow(
1096 dpy, FW_W_FRAME(fw), -1, -1, 1, 1, 0, Pdepth,
1097 InputOutput, Pvisual, valuemask, &attributes);
1098 XSaveContext(dpy, FW_W_SIDE(fw, i), FvwmContext, (caddr_t)fw);
1100 setup_resize_handle_cursors(fw);
1102 return;
1105 static void destroy_resize_handle_windows(
1106 FvwmWindow *fw, Bool do_only_delete_context)
1108 int i;
1110 for (i = 0; i < 4 ; i++)
1112 XDeleteContext(dpy, FW_W_SIDE(fw, i), FvwmContext);
1113 XDeleteContext(dpy, FW_W_CORNER(fw, i), FvwmContext);
1114 if (!do_only_delete_context)
1116 XDestroyWindow(dpy, FW_W_SIDE(fw, i));
1117 XDestroyWindow(dpy, FW_W_CORNER(fw, i));
1118 FW_W_SIDE(fw, i) = None;
1119 FW_W_CORNER(fw, i) = None;
1122 XFlush(dpy);
1124 return;
1127 static void change_resize_handle_windows(FvwmWindow *fw)
1129 if (!HAS_NO_BORDER(fw) && FW_W_SIDE(fw, 0) == None)
1131 setup_resize_handle_windows(fw);
1133 else if (HAS_NO_BORDER(fw) && FW_W_SIDE(fw, 0) != None)
1135 destroy_resize_handle_windows(fw, False);
1137 else
1139 setup_resize_handle_cursors(fw);
1142 return;
1145 static void setup_frame_stacking(FvwmWindow *fw)
1147 int i;
1148 int n;
1149 Window w[10 + NUMBER_OF_TITLE_BUTTONS];
1151 /* Stacking order (top to bottom):
1152 * - Parent window
1153 * - Title and buttons
1154 * - Corner handles
1155 * - Side handles
1157 n = 0;
1158 if (!IS_SHADED(fw))
1160 w[n] = FW_W_PARENT(fw);
1161 n++;
1163 if (HAS_TITLE(fw))
1165 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i += 2)
1167 if (FW_W_BUTTON(fw, i) != None)
1169 w[n] = FW_W_BUTTON(fw, i);
1170 n++;
1173 for (i = 2 * NR_RIGHT_BUTTONS - 1; i > 0; i -= 2)
1175 if (FW_W_BUTTON(fw, i) != None)
1177 w[n] = FW_W_BUTTON(fw, i);
1178 n++;
1181 if (FW_W_TITLE(fw) != None)
1183 w[n] = FW_W_TITLE(fw);
1184 n++;
1187 for (i = 0; i < 4; i++)
1189 if (FW_W_CORNER(fw, i) != None)
1191 w[n] = FW_W_CORNER(fw, i);
1192 n++;
1195 for (i = 0; i < 4; i++)
1197 if (FW_W_SIDE(fw, i) != None)
1199 w[n] = FW_W_SIDE(fw, i);
1200 n++;
1203 if (IS_SHADED(fw))
1205 w[n] = FW_W_PARENT(fw);
1206 n++;
1208 XRestackWindows(dpy, w, n);
1210 return;
1213 static void get_default_window_attributes(
1214 FvwmWindow *fw, unsigned long *pvaluemask,
1215 XSetWindowAttributes *pattributes)
1217 *pvaluemask |= CWBackingStore | CWCursor | CWSaveUnder | CWBorderPixel |
1218 CWColormap | CWBackPixmap;
1219 pattributes->background_pixel = 0;
1220 pattributes->background_pixmap = None;
1221 pattributes->backing_store = NotUseful;
1222 pattributes->cursor = Scr.FvwmCursors[CRS_DEFAULT];
1223 pattributes->save_under = False;
1224 pattributes->border_pixel = 0;
1225 pattributes->colormap = Pcmap;
1227 return;
1230 static void setup_auxiliary_windows(
1231 FvwmWindow *fw, Bool setup_frame_and_parent, short buttons)
1233 unsigned long valuemask_save = 0;
1234 XSetWindowAttributes attributes;
1236 get_default_window_attributes(fw, &valuemask_save, &attributes);
1238 if (setup_frame_and_parent)
1240 setup_frame_window(fw);
1241 setup_parent_window(fw);
1243 setup_resize_handle_windows(fw);
1244 if (HAS_TITLE(fw))
1246 setup_title_window(fw, valuemask_save, &attributes);
1247 setup_button_windows(fw, valuemask_save, &attributes, buttons);
1249 setup_frame_stacking(fw);
1250 XMapSubwindows (dpy, FW_W_FRAME(fw));
1252 return;
1255 static void destroy_auxiliary_windows(
1256 FvwmWindow *fw, Bool destroy_frame_and_parent)
1258 if (destroy_frame_and_parent)
1260 XDeleteContext(dpy, FW_W_FRAME(fw), FvwmContext);
1261 XDeleteContext(dpy, FW_W_PARENT(fw), FvwmContext);
1262 delete_client_context(fw);
1263 XDestroyWindow(dpy, FW_W_FRAME(fw));
1265 if (HAS_TITLE(fw))
1267 destroy_title_window(fw, True);
1269 if (HAS_TITLE(fw))
1271 destroy_button_windows(fw, True);
1273 if (!HAS_NO_BORDER(fw))
1275 destroy_resize_handle_windows(fw, True);
1277 XFlush(dpy);
1279 return;
1282 static void setup_icon(FvwmWindow *fw, window_style *pstyle)
1284 increase_icon_hint_count(fw);
1285 /* find a suitable icon pixmap */
1286 if ((fw->wmhints) && (fw->wmhints->flags & IconWindowHint))
1288 if (SHAS_ICON(&pstyle->flags) &&
1289 S_ICON_OVERRIDE(SCF(*pstyle)) == ICON_OVERRIDE)
1291 ICON_DBG((stderr,"si: iwh ignored '%s'\n",
1292 fw->name.name));
1293 fw->icon_bitmap_file = SGET_ICON_NAME(*pstyle);
1295 else
1297 ICON_DBG((stderr,"si: using iwh '%s'\n",
1298 fw->name.name));
1299 fw->icon_bitmap_file = NULL;
1302 else if ((fw->wmhints) && (fw->wmhints->flags & IconPixmapHint))
1304 if (SHAS_ICON(&pstyle->flags) &&
1305 S_ICON_OVERRIDE(SCF(*pstyle)) != NO_ICON_OVERRIDE)
1307 ICON_DBG((stderr,"si: iph ignored '%s'\n",
1308 fw->name.name));
1309 fw->icon_bitmap_file = SGET_ICON_NAME(*pstyle);
1311 else
1313 ICON_DBG((stderr,"si: using iph '%s'\n",
1314 fw->name.name));
1315 fw->icon_bitmap_file = NULL;
1318 else if (SHAS_ICON(&pstyle->flags))
1320 /* an icon was specified */
1321 ICON_DBG((stderr,"si: using style '%s'\n", fw->name.name));
1322 fw->icon_bitmap_file = SGET_ICON_NAME(*pstyle);
1324 else
1326 /* use default icon */
1327 ICON_DBG((stderr,"si: using default '%s'\n", fw->name.name));
1328 fw->icon_bitmap_file = Scr.DefaultIcon;
1331 /* icon name */
1332 if (!EWMH_WMIconName(fw, NULL, NULL, 0))
1334 fw->icon_name.name = NoName;
1335 fw->icon_name.name_list = NULL;
1336 FlocaleGetNameProperty(
1337 XGetWMIconName, dpy, FW_W(fw), &(fw->icon_name));
1339 if (fw->icon_name.name == NoName)
1341 fw->icon_name.name = fw->name.name;
1342 SET_WAS_ICON_NAME_PROVIDED(fw, 0);
1344 setup_visible_name(fw, True);
1347 /* wait until the window is iconified and the icon window is mapped
1348 * before creating the icon window
1350 FW_W_ICON_TITLE(fw) = None;
1352 EWMH_SetVisibleName(fw, True);
1353 BroadcastWindowIconNames(fw, False, True);
1354 if (fw->icon_bitmap_file != NULL &&
1355 fw->icon_bitmap_file != Scr.DefaultIcon)
1357 BroadcastName(M_ICON_FILE,FW_W(fw),FW_W_FRAME(fw),
1358 (unsigned long)fw,fw->icon_bitmap_file);
1361 return;
1364 static void destroy_icon(FvwmWindow *fw)
1366 free_window_names(fw, False, True);
1367 if (IS_PIXMAP_OURS(fw))
1369 XFreePixmap(dpy, fw->iconPixmap);
1370 fw->iconPixmap = None;
1371 if (fw->icon_maskPixmap != None)
1373 XFreePixmap(dpy, fw->icon_maskPixmap);
1374 fw->icon_maskPixmap = None;
1376 if (fw->icon_alphaPixmap != None)
1378 XFreePixmap(dpy, fw->icon_alphaPixmap);
1379 fw->icon_alphaPixmap = None;
1381 if (fw->icon_alloc_pixels != NULL)
1383 if (fw->icon_nalloc_pixels != 0)
1385 PictureFreeColors(
1386 dpy, Pcmap, fw->icon_alloc_pixels,
1387 fw->icon_nalloc_pixels, 0,
1388 fw->icon_no_limit);
1390 free(fw->icon_alloc_pixels);
1391 fw->icon_alloc_pixels = NULL;
1392 fw->icon_nalloc_pixels = 0;
1393 fw->icon_no_limit = 0;
1396 if (FW_W_ICON_TITLE(fw))
1398 XDestroyWindow(dpy, FW_W_ICON_TITLE(fw));
1399 XDeleteContext(dpy, FW_W_ICON_TITLE(fw), FvwmContext);
1400 XFlush(dpy);
1402 if (FW_W_ICON_PIXMAP(fw) != None)
1404 if (IS_ICON_OURS(fw))
1406 XDestroyWindow(dpy, FW_W_ICON_PIXMAP(fw));
1408 else
1410 XUnmapWindow(dpy, FW_W_ICON_PIXMAP(fw));
1412 XDeleteContext(dpy, FW_W_ICON_PIXMAP(fw), FvwmContext);
1414 clear_icon(fw);
1415 XFlush(dpy);
1417 return;
1420 static void setup_icon_boxes(FvwmWindow *fw, window_style *pstyle)
1422 icon_boxes *ib;
1424 /* copy iconboxes ptr (if any) */
1425 if (SHAS_ICON_BOXES(&pstyle->flags))
1427 fw->IconBoxes = SGET_ICON_BOXES(*pstyle);
1428 for (ib = fw->IconBoxes; ib; ib = ib->next)
1430 ib->use_count++;
1433 else
1435 fw->IconBoxes = NULL;
1438 return;
1441 static void destroy_icon_boxes(FvwmWindow *fw)
1443 if (fw->IconBoxes)
1445 fw->IconBoxes->use_count--;
1446 if (fw->IconBoxes->use_count == 0 && fw->IconBoxes->is_orphan)
1448 /* finally destroy the icon box */
1449 free_icon_boxes(fw->IconBoxes);
1450 fw->IconBoxes = NULL;
1454 return;
1457 static void setup_layer(FvwmWindow *fw, window_style *pstyle)
1459 FvwmWindow *tf;
1460 int layer;
1462 if (SUSE_LAYER(&pstyle->flags))
1464 /* use layer from style */
1465 layer = SGET_LAYER(*pstyle);
1467 else if ((tf = get_transientfor_fvwmwindow(fw)) != NULL)
1469 /* inherit layer from transientfor window */
1470 layer = get_layer(tf);
1472 else
1474 /* use default layer */
1475 layer = Scr.DefaultLayer;
1477 set_default_layer(fw, layer);
1478 set_layer(fw, layer);
1480 return;
1483 static void destroy_mini_icon(FvwmWindow *fw)
1485 if (fw->mini_icon)
1487 PDestroyFvwmPicture(dpy, fw->mini_icon);
1488 fw->mini_icon = 0;
1491 return;
1494 static void setup_key_and_button_grabs(FvwmWindow *fw)
1496 #ifdef BUGS_ARE_COOL
1497 /* dv (29-May-2001): If keys are grabbed separately for C_WINDOW and
1498 * the other contexts, new windows have problems when bindings are
1499 * removed. Therefore, grab all keys in a single pass through the
1500 * list. */
1501 GrabAllWindowKeys(
1502 dpy, FW_W_FRAME(fw), Scr.AllBindings,
1503 C_WINDOW|C_TITLE|C_RALL|C_LALL|C_SIDEBAR, GetUnusedModifiers(),
1504 True);
1505 #endif
1506 GrabAllWindowKeys(
1507 dpy, FW_W_FRAME(fw), Scr.AllBindings,
1508 C_TITLE|C_RALL|C_LALL|C_SIDEBAR|C_WINDOW, GetUnusedModifiers(),
1509 True);
1510 setup_focus_policy(fw);
1512 return;
1515 static void __add_window_handle_x_resources(FvwmWindow *fw)
1517 int client_argc = 0;
1518 char **client_argv = NULL;
1519 XrmValue rm_value;
1520 XrmDatabase db = NULL;
1521 static XrmOptionDescRec table [] = {
1522 {"-xrn", NULL, XrmoptionResArg, (caddr_t) NULL},
1523 {"-xrm", NULL, XrmoptionResArg, (caddr_t) NULL},
1525 /* Get global X resources */
1526 MergeXResources(dpy, &db, False);
1527 /* Find out if the client requested a specific style on the command
1528 * line.
1530 if (XGetCommand(dpy, FW_W(fw), &client_argv, &client_argc))
1532 if (client_argc > 0 && client_argv != NULL)
1534 /* command line takes precedence over all */
1535 MergeCmdLineResources(
1536 &db, table, 2, fw->class.res_name,
1537 &client_argc, client_argv, True);
1542 /* parse the database values */
1543 if (GetResourceString(db, "fvwmstyle", fw->class.res_name, &rm_value)
1544 && rm_value.size != 0)
1546 char *style_name;
1547 int name_len;
1548 style_name = rm_value.addr;
1549 name_len = rm_value.size-1;
1550 /* Trim spaces at the start of the name */
1551 while (name_len>0 && isspace(*style_name))
1553 style_name++;
1554 name_len--;
1556 /* Trim spaces at the end of the name */
1557 while (name_len>0 && isspace(*(style_name+name_len-1)))
1559 name_len--;
1561 if (name_len>0) {
1562 fw->style_name = (char*)safemalloc(sizeof(char)*
1563 (name_len+1));
1564 memcpy(fw->style_name,style_name,name_len);
1565 fw->style_name[name_len] = 0;
1568 XFreeStringList(client_argv);
1569 XrmDestroyDatabase(db);
1570 return;
1573 /* ---------------------------- interface functions ------------------------ */
1575 void setup_visible_name(FvwmWindow *fw, Bool is_icon)
1577 char *ext_name;
1578 char *name;
1579 int count;
1580 int len;
1582 if (fw == NULL)
1584 /* should never happen */
1585 return;
1588 setup_name_count(fw, is_icon);
1590 if (is_icon)
1592 if (fw->visible_icon_name != NULL &&
1593 fw->visible_icon_name != fw->icon_name.name &&
1594 fw->visible_icon_name != fw->name.name &&
1595 fw->visible_icon_name != NoName)
1597 free(fw->visible_icon_name);
1598 fw->visible_icon_name = NULL;
1600 name = fw->icon_name.name;
1601 count = fw->icon_name_count;
1603 else
1605 if (fw->visible_name != NULL &&
1606 fw->visible_name != fw->name.name &&
1607 fw->visible_name != NoName)
1609 free(fw->visible_name);
1610 fw->visible_name = NULL;
1612 name = fw->name.name;
1613 count = fw->name_count;
1616 if (name == NULL)
1618 return; /* should never happen */
1621 if (count > MAX_WINDOW_NAME_NUMBER - 1)
1623 count = MAX_WINDOW_NAME_NUMBER - 1;
1626 if (count != 0 &&
1627 ((is_icon && USE_INDEXED_ICON_NAME(fw)) ||
1628 (!is_icon && USE_INDEXED_WINDOW_NAME(fw))))
1630 len = strlen(name);
1631 count++;
1632 ext_name = (char *)safemalloc(
1633 len + MAX_WINDOW_NAME_NUMBER_DIGITS + 4);
1634 sprintf(ext_name,"%s (%d)", name, count);
1636 else
1638 ext_name = name;
1641 if (is_icon)
1643 fw->visible_icon_name = ext_name;
1645 else
1647 fw->visible_name = ext_name;
1650 return;
1653 void setup_window_name(FvwmWindow *fw)
1655 if (!EWMH_WMName(fw, NULL, NULL, 0))
1657 fw->name.name = NoName;
1658 fw->name.name_list = NULL;
1659 FlocaleGetNameProperty(XGetWMName, dpy, FW_W(fw), &(fw->name));
1662 return;
1665 void setup_wm_hints(FvwmWindow *fw)
1667 fw->wmhints = XGetWMHints(dpy, FW_W(fw));
1668 set_focus_model(fw);
1670 return;
1673 void setup_title_geometry(
1674 FvwmWindow *fw, window_style *pstyle)
1676 int width;
1677 int offset;
1679 get_title_font_size_and_offset(
1680 fw, S_TITLE_DIR(SCF(*pstyle)),
1681 S_IS_LEFT_TITLE_ROTATED_CW(SCF(*pstyle)),
1682 S_IS_RIGHT_TITLE_ROTATED_CW(SCF(*pstyle)),
1683 S_IS_TOP_TITLE_ROTATED(SCF(*pstyle)),
1684 S_IS_BOTTOM_TITLE_ROTATED(SCF(*pstyle)),
1685 &width, &offset);
1686 fw->title_thickness = width;
1687 fw->title_text_offset = offset;
1688 fw->corner_width = fw->title_thickness + fw->boundary_width;
1689 if (!HAS_TITLE(fw))
1691 fw->title_thickness = 0;
1694 return;
1697 void setup_window_font(
1698 FvwmWindow *fw, window_style *pstyle, Bool do_destroy)
1700 /* get rid of old font */
1701 if (do_destroy)
1703 destroy_window_font(fw);
1704 /* destroy_window_font resets the IS_WINDOW_FONT_LOADED flag */
1706 /* load new font */
1707 if (!IS_WINDOW_FONT_LOADED(fw))
1709 if (S_HAS_WINDOW_FONT(SCF(*pstyle)) &&
1710 SGET_WINDOW_FONT(*pstyle) &&
1711 (fw->title_font =
1712 FlocaleLoadFont(dpy, SGET_WINDOW_FONT(*pstyle), "fvwm")))
1714 SET_USING_DEFAULT_WINDOW_FONT(fw, 0);
1716 else
1718 /* no explicit font or failed to load, use default font
1719 * instead */
1720 fw->title_font = Scr.DefaultFont;
1721 SET_USING_DEFAULT_WINDOW_FONT(fw, 1);
1723 SET_WINDOW_FONT_LOADED(fw, 1);
1725 setup_title_geometry(fw, pstyle);
1727 return;
1730 void setup_icon_font(
1731 FvwmWindow *fw, window_style *pstyle, Bool do_destroy)
1733 int height = 0;
1735 if (IS_ICON_SUPPRESSED(fw) || HAS_NO_ICON_TITLE(fw))
1737 if (IS_ICON_FONT_LOADED(fw))
1739 destroy_icon_font(fw);
1740 /* destroy_icon_font resets the IS_ICON_FONT_LOADED
1741 * flag */
1743 return;
1745 /* get rid of old font */
1746 if (do_destroy && IS_ICON_FONT_LOADED(fw))
1748 destroy_icon_font(fw);
1749 /* destroy_icon_font resets the IS_ICON_FONT_LOADED flag */
1751 /* load new font */
1752 if (!IS_ICON_FONT_LOADED(fw))
1754 if (S_HAS_ICON_FONT(SCF(*pstyle)) && SGET_ICON_FONT(*pstyle) &&
1755 (fw->icon_font =
1756 FlocaleLoadFont(dpy, SGET_ICON_FONT(*pstyle), "fvwm")))
1758 SET_USING_DEFAULT_ICON_FONT(fw, 0);
1760 else
1762 /* no explicit font or failed to load, use default font
1763 * instead */
1764 fw->icon_font = Scr.DefaultFont;
1765 SET_USING_DEFAULT_ICON_FONT(fw, 1);
1767 SET_ICON_FONT_LOADED(fw, 1);
1769 /* adjust y position of existing icons */
1770 height = (IS_ICON_FONT_LOADED(fw)) ? fw->icon_font->height : 0;
1771 if (height)
1773 resize_icon_title_height(fw, height - fw->icon_font->height);
1774 /* this repositions the icon even if the window is not
1775 * iconified */
1776 DrawIconWindow(fw, True, True, False, False, NULL);
1779 return;
1782 void setup_style_and_decor(
1783 FvwmWindow *fw, window_style *pstyle, short *buttons)
1785 /* first copy the static styles into the window struct */
1786 memcpy(&(FW_COMMON_FLAGS(fw)), &(SCF(*pstyle)),
1787 sizeof(common_flags_t));
1788 fw->wShaped = None;
1789 if (FShapesSupported)
1791 int i;
1792 unsigned int u;
1793 Bool b;
1794 int boundingShaped;
1796 /* suppress compiler warnings w/o shape extension */
1797 i = 0;
1798 u = 0;
1799 b = False;
1801 FShapeSelectInput(dpy, FW_W(fw), FShapeNotifyMask);
1802 if (FShapeQueryExtents(
1803 dpy, FW_W(fw), &boundingShaped, &i, &i, &u, &u, &b,
1804 &i, &i, &u, &u))
1806 fw->wShaped = boundingShaped;
1810 #ifdef USEDECOR
1811 /* search for a UseDecor tag in the style */
1812 if (!IS_DECOR_CHANGED(fw))
1814 FvwmDecor *decor = &Scr.DefaultDecor;
1816 for (; decor; decor = decor->next)
1818 if (StrEquals(SGET_DECOR_NAME(*pstyle), decor->tag))
1820 fw->decor = decor;
1821 break;
1825 if (fw->decor == NULL)
1827 fw->decor = &Scr.DefaultDecor;
1829 #endif
1831 GetMwmHints(fw);
1832 GetOlHints(fw);
1834 fw->buttons = SIS_BUTTON_DISABLED(&pstyle->flags);
1835 SelectDecor(fw, pstyle, buttons);
1837 if (IS_TRANSIENT(fw) && !pstyle->flags.do_decorate_transient)
1839 SET_HAS_HANDLES(fw, 0);
1840 SET_HAS_TITLE(fw, 0);
1842 /* set boundary width to zero for shaped windows */
1843 if (FHaveShapeExtension)
1845 if (fw->wShaped)
1847 set_window_border_size(fw, fw->unshaped_boundary_width);
1848 SET_HAS_NO_BORDER(fw, 1);
1849 SET_HAS_HANDLES(fw, 0);
1853 /****** window colors ******/
1854 update_window_color_style(fw, pstyle);
1855 update_window_color_hi_style(fw, pstyle);
1857 /***** icons colorsets *****/
1858 update_icon_title_cs_style(fw, pstyle);
1859 update_icon_title_cs_hi_style(fw, pstyle);
1860 update_icon_background_cs_style(fw, pstyle);
1862 /***** icons title/background parameters ****/
1863 setup_icon_background_parameters(fw, pstyle);
1864 setup_icon_title_parameters(fw, pstyle);
1866 /****** some numeric values ******/
1867 setup_numeric_vals(fw, pstyle);
1869 /****** GNOME style hints ******/
1870 if (!S_DO_IGNORE_GNOME_HINTS(SCF(*pstyle)))
1872 GNOME_GetStyle(fw, pstyle);
1875 /* ConfigureNotify motion method */
1876 if (SCR_MOTION_METHOD(&pstyle->flag_mask))
1878 CR_MOTION_METHOD(fw) = SCR_MOTION_METHOD(&pstyle->flags);
1881 return;
1884 void change_icon_boxes(FvwmWindow *fw, window_style *pstyle)
1886 destroy_icon_boxes(fw);
1887 setup_icon_boxes(fw, pstyle);
1889 return;
1892 void setup_frame_size_limits(FvwmWindow *fw, window_style *pstyle)
1894 if (SHAS_MIN_WINDOW_SIZE(&pstyle->flags))
1896 fw->min_window_width = SGET_MIN_WINDOW_WIDTH(*pstyle);
1897 fw->min_window_height = SGET_MIN_WINDOW_HEIGHT(*pstyle);
1899 else
1901 fw->min_window_width = 0;
1902 fw->min_window_height = 0;
1904 if (SHAS_MAX_WINDOW_SIZE(&pstyle->flags))
1906 fw->max_window_width = SGET_MAX_WINDOW_WIDTH(*pstyle);
1907 fw->max_window_height = SGET_MAX_WINDOW_HEIGHT(*pstyle);
1909 else
1911 fw->max_window_width = DEFAULT_MAX_MAX_WINDOW_WIDTH;
1912 fw->max_window_height = DEFAULT_MAX_MAX_WINDOW_HEIGHT;
1915 return;
1918 void setup_placement_penalty(FvwmWindow *fw, window_style *pstyle)
1920 if (!SHAS_PLACEMENT_PENALTY(&pstyle->flags))
1922 pl_penalty_struct *p;
1924 p = SGET_PLACEMENT_PENALTY_PTR(*pstyle);
1925 *p = default_pl_penalty;
1927 if (!SHAS_PLACEMENT_PERCENTAGE_PENALTY(&pstyle->flags))
1929 pl_percent_penalty_struct *p;
1931 p = SGET_PLACEMENT_PERCENTAGE_PENALTY_PTR(*pstyle);
1932 *p = default_pl_percent_penalty;
1934 fw->pl_penalty = (*pstyle).pl_penalty;
1935 fw->pl_percent_penalty = (*pstyle).pl_percent_penalty;
1937 return;
1940 void setup_frame_attributes(
1941 FvwmWindow *fw, window_style *pstyle)
1943 XSetWindowAttributes xswa;
1945 /* Backing_store is controlled on the client, borders, title & buttons
1947 switch (pstyle->flags.use_backing_store)
1949 case BACKINGSTORE_DEFAULT:
1950 xswa.backing_store = fw->attr_backup.backing_store;
1951 break;
1952 case BACKINGSTORE_ON:
1953 xswa.backing_store = Scr.use_backing_store;
1954 break;
1955 case BACKINGSTORE_OFF:
1956 default:
1957 xswa.backing_store = NotUseful;
1958 break;
1960 /* parent_relative is applied to the frame and the parent */
1961 xswa.background_pixmap = pstyle->flags.use_parent_relative
1962 ? ParentRelative : None;
1963 /* Save_under is only useful on the frame */
1964 xswa.save_under = pstyle->flags.do_save_under
1965 ? Scr.flags.do_save_under : NotUseful;
1966 XChangeWindowAttributes(dpy, FW_W(fw), CWBackingStore, &xswa);
1967 XChangeWindowAttributes(
1968 dpy, FW_W_PARENT(fw), CWBackPixmap | CWBackingStore, &xswa);
1969 XChangeWindowAttributes(
1970 dpy, FW_W_FRAME(fw),
1971 CWBackPixmap | CWBackingStore | CWSaveUnder, &xswa);
1973 return;
1976 void change_auxiliary_windows(FvwmWindow *fw, short buttons)
1978 unsigned long valuemask_save = 0;
1979 XSetWindowAttributes attributes;
1981 get_default_window_attributes(fw, &valuemask_save, &attributes);
1982 change_title_window(fw, valuemask_save, &attributes);
1983 change_button_windows(fw, valuemask_save, &attributes, buttons);
1984 change_resize_handle_windows(fw);
1985 setup_frame_stacking(fw);
1986 XMapSubwindows (dpy, FW_W_FRAME(fw));
1988 return;
1991 void increase_icon_hint_count(FvwmWindow *fw)
1993 if (fw->wmhints &&
1994 (fw->wmhints->flags & (IconWindowHint | IconPixmapHint)))
1996 switch (WAS_ICON_HINT_PROVIDED(fw))
1998 case ICON_HINT_NEVER:
1999 SET_WAS_ICON_HINT_PROVIDED(fw, ICON_HINT_ONCE);
2000 break;
2001 case ICON_HINT_ONCE:
2002 SET_WAS_ICON_HINT_PROVIDED(fw, ICON_HINT_MULTIPLE);
2003 break;
2004 case ICON_HINT_MULTIPLE:
2005 default:
2006 break;
2008 ICON_DBG((stderr,"icon hint count++ (%d) '%s'\n",
2009 (int)WAS_ICON_HINT_PROVIDED(fw), fw->name.name));
2012 return;
2015 void change_icon(FvwmWindow *fw, window_style *pstyle)
2017 destroy_icon(fw);
2018 setup_icon(fw, pstyle);
2020 return;
2023 void change_mini_icon(FvwmWindow *fw, window_style *pstyle)
2025 FvwmPicture *old_mi = fw->mini_icon;
2026 destroy_mini_icon(fw);
2027 setup_mini_icon(fw, pstyle);
2028 broadcast_mini_icon(fw);
2029 if (old_mi != NULL && fw->mini_icon == 0)
2031 /* this case is not handled in setup_mini_icon, so we must
2032 * broadcast here explicitly */
2033 BroadcastFvwmPicture(
2034 M_MINI_ICON, FW_W(fw), FW_W_FRAME(fw),
2035 (unsigned long)fw, NULL, "");
2038 return;
2041 void setup_focus_policy(FvwmWindow *fw)
2043 focus_grab_buttons(fw);
2045 return;
2048 Bool validate_transientfor(FvwmWindow *fw)
2050 XWindowAttributes wa;
2051 FvwmWindow *cw;
2052 Window w;
2054 w = FW_W_TRANSIENTFOR(fw);
2055 if (w == None || w == FW_W(fw) || w == IS_EWMH_DESKTOP(w))
2057 FW_W_TRANSIENTFOR(fw) = Scr.Root;
2058 return False;
2060 else if (XFindContext(dpy, w, FvwmContext, (caddr_t *)&cw) != XCNOENT)
2062 if (cw == fw)
2064 /* It's a transient of itself, ignore the hint */
2065 FW_W_TRANSIENTFOR(fw) = Scr.Root;
2066 return False;
2068 /* Check for transient loops */
2069 while (XFindContext(
2070 dpy, FW_W_TRANSIENTFOR(cw), FvwmContext,
2071 (caddr_t *)&cw) != XCNOENT &&
2072 IS_TRANSIENT(cw))
2074 if (FW_W_TRANSIENTFOR(cw) == FW_W(fw) || cw == fw)
2076 /* loop detected, ignore the hint */
2077 FW_W_TRANSIENTFOR(fw) = Scr.Root;
2078 return False;
2082 else if (!XGetWindowAttributes(dpy, w, &wa) ||
2083 wa.map_state != IsViewable)
2085 /* transientfor does not exist or is not viewable or unmapped */
2086 FW_W_TRANSIENTFOR(fw) = Scr.Root;
2087 return False;
2090 return True;
2093 Bool setup_transientfor(FvwmWindow *fw)
2095 Bool rc;
2097 rc = XGetTransientForHint(dpy, FW_W(fw), &FW_W_TRANSIENTFOR(fw));
2098 SET_TRANSIENT(fw, rc);
2099 if (rc == False)
2101 FW_W_TRANSIENTFOR(fw) = Scr.Root;
2103 validate_transientfor(fw);
2105 return rc;
2110 * Procedure:
2111 * AddWindow - add a new window to the fvwm list
2114 FvwmWindow *AddWindow(
2115 const char **ret_initial_map_command, const exec_context_t *exc,
2116 FvwmWindow *ReuseWin, initial_window_options_t * win_opts)
2118 /* new fvwm window structure */
2119 register FvwmWindow *fw;
2120 FvwmWindow *tmp;
2121 /* mask for create windows */
2122 unsigned long valuemask;
2123 /* attributes for create windows */
2124 XSetWindowAttributes attributes;
2125 XWindowAttributes wattr;
2126 /* area for merged styles */
2127 window_style style;
2128 /* used for faster access */
2129 style_flags *sflags;
2130 short buttons;
2131 Bool used_sm = False;
2132 Bool do_resize_too = False;
2133 size_borders b;
2134 frame_move_resize_args mr_args;
2135 mwtsm_state_args state_args;
2136 Window w = exc->w.w;
2137 const exec_context_t *exc2;
2138 exec_context_changes_t ecc;
2140 /****** init window structure ******/
2141 setup_window_structure(&tmp, w, ReuseWin);
2142 fw = tmp;
2144 /****** Make sure the client window still exists. We don't want to
2145 * leave an orphan frame window if it doesn't. Since we now have the
2146 * server grabbed, the window can't disappear later without having been
2147 * reparented, so we'll get a DestroyNotify for it. We won't have
2148 * gotten one for anything up to here, however. ******/
2149 MyXGrabServer(dpy);
2150 if (XGetGeometry(
2151 dpy, w, &JunkRoot, &JunkX, &JunkY,
2152 (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
2153 (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth) == 0)
2155 if (Scr.bo.do_display_new_window_names)
2157 fvwm_msg(INFO, "AddWindow", "new window disappeared");
2159 free(fw);
2160 MyXUngrabServer(dpy);
2161 return NULL;
2164 /****** window name ******/
2165 setup_window_name(fw);
2166 setup_class_and_resource(fw);
2168 /****** style setup ******/
2169 __add_window_handle_x_resources(fw);
2170 /* get merged styles */
2171 lookup_style(fw, &style);
2172 sflags = SGET_FLAGS_POINTER(style);
2173 if (SIS_UNMANAGED(sflags))
2175 if (Scr.bo.do_display_new_window_names)
2177 fvwm_msg(
2178 INFO, "AddWindow", "new window is unmanaged:\n"
2179 " name: %s\n"
2180 " icon name: (unknown)\n"
2181 " resource: %s\n"
2182 " class: %s",
2183 fw->name.name, fw->class.res_name,
2184 fw->class.res_class);
2186 free_window_names(fw, True, True);
2187 if (fw->style_name)
2189 free(fw->style_name);
2191 free(fw);
2192 MyXUngrabServer(dpy);
2193 return AW_UNMANAGED;
2196 /****** window attributes and hints ******/
2197 setup_window_attr(fw, &wattr);
2198 setup_wm_hints(fw);
2200 /****** basic style and decor ******/
2201 /* If the window is in the NoTitle list, or is a transient, dont
2202 * decorate it. If its a transient, and DecorateTransients was
2203 * specified, decorate anyway. */
2204 setup_transientfor(fw);
2205 if (win_opts->flags.is_menu)
2207 SET_TEAR_OFF_MENU(fw, 1);
2209 fw->decor = NULL;
2210 setup_style_and_decor(fw, &style, &buttons);
2212 /****** fonts ******/
2213 setup_window_font(fw, &style, False);
2214 setup_icon_font(fw, &style, False);
2216 /***** visible window name ****/
2217 setup_visible_name(fw, False);
2218 EWMH_SetVisibleName(fw, False);
2219 if (Scr.bo.do_display_new_window_names)
2221 fvwm_msg(
2222 INFO, "AddWindow", "new window:\n"
2223 " name: %s\n"
2224 " icon name: %s\n"
2225 " resource: %s\n"
2226 " class: %s",
2227 fw->name.name, (fw->icon_name.name == NULL) ?
2228 "(unknown)" : fw->icon_name.name, fw->class.res_name,
2229 fw->class.res_class);
2232 /****** InitialMapCommand ******/
2233 *ret_initial_map_command =
2234 (style.flags.has_initial_map_command_string) ?
2235 SGET_INITIAL_MAP_COMMAND_STRING(style) : NULL;
2237 /****** state setup ******/
2238 setup_icon_boxes(fw, &style);
2239 SET_ICONIFIED(fw, 0);
2240 SET_ICON_UNMAPPED(fw, 0);
2241 SET_MAXIMIZED(fw, 0);
2243 * Reparenting generates an UnmapNotify event, followed by a MapNotify.
2244 * Set the map state to 0 to prevent a transition back to
2245 * WithdrawnState in HandleUnmapNotify. Map state gets set corrected
2246 * again in HandleMapNotify.
2248 SET_MAPPED(fw, 0);
2250 /****** window list and stack ring ******/
2251 /* add the window to the end of the fvwm list */
2252 fw->next = Scr.FvwmRoot.next;
2253 fw->prev = &Scr.FvwmRoot;
2254 while (fw->next != NULL)
2256 fw->prev = fw->next;
2257 fw->next = fw->next->next;
2259 /* fw->prev points to the last window in the list, fw->next is
2260 * NULL. Now fix the last window to point to fw */
2261 fw->prev->next = fw;
2263 * RBW - 11/13/1998 - add it into the stacking order chain also.
2264 * This chain is anchored at both ends on Scr.FvwmRoot, there are
2265 * no null pointers.
2267 add_window_to_stack_ring_after(fw, &Scr.FvwmRoot);
2269 /****** calculate frame size ******/
2270 fw->hints.win_gravity = NorthWestGravity;
2271 GetWindowSizeHints(fw);
2273 /****** border width ******/
2274 XSetWindowBorderWidth(dpy, FW_W(fw), 0);
2276 /****** icon size limits ******/
2277 setup_icon_size_limits(fw, &style);
2279 /***** placement penalities *****/
2280 setup_placement_penalty(fw, &style);
2282 * MatchWinToSM changes fw->attr and the stacking order.
2283 * Thus it is important have this call *after* PlaceWindow and the
2284 * stacking order initialization.
2286 get_window_borders(fw, &b);
2287 memset(&state_args, 0, sizeof(state_args));
2288 used_sm = MatchWinToSM(fw, &state_args, win_opts);
2289 if (used_sm)
2291 /* read the requested absolute geometry */
2292 gravity_translate_to_northwest_geometry_no_bw(
2293 fw->hints.win_gravity, fw, &fw->g.normal,
2294 &fw->g.normal);
2295 gravity_resize(
2296 fw->hints.win_gravity, &fw->g.normal,
2297 b.total_size.width, b.total_size.height);
2298 fw->g.frame = fw->g.normal;
2299 fw->g.frame.x -= Scr.Vx;
2300 fw->g.frame.y -= Scr.Vy;
2302 /****** calculate frame size ******/
2303 setup_frame_size_limits(fw, &style);
2304 constrain_size(
2305 fw, NULL, &fw->g.frame.width,
2306 &fw->g.frame.height, 0, 0, 0);
2308 /****** maximize ******/
2309 if (state_args.do_max)
2311 SET_MAXIMIZED(fw, 1);
2312 constrain_size(
2313 fw, NULL, &fw->g.max.width, &fw->g.max.height,
2314 0, 0, CS_UPDATE_MAX_DEFECT);
2315 get_relative_geometry(&fw->g.frame, &fw->g.max);
2317 else
2319 get_relative_geometry(&fw->g.frame, &fw->g.normal);
2322 else
2324 rectangle attr_g;
2326 if (IS_SHADED(fw))
2328 state_args.do_shade = 1;
2329 state_args.used_title_dir_for_shading =
2330 USED_TITLE_DIR_FOR_SHADING(fw);
2331 state_args.shade_dir = SHADED_DIR(fw);
2332 SET_SHADED(fw, 0);
2334 /* Tentative size estimate */
2335 fw->g.frame.width = wattr.width + b.total_size.width;
2336 fw->g.frame.height = wattr.height + b.total_size.height;
2338 /****** calculate frame size ******/
2339 setup_frame_size_limits(fw, &style);
2341 /****** layer ******/
2342 setup_layer(fw, &style);
2344 /****** window placement ******/
2345 attr_g.x = wattr.x;
2346 attr_g.y = wattr.y;
2347 attr_g.width = wattr.width;
2348 attr_g.height = wattr.height;
2349 do_resize_too = setup_window_placement(
2350 fw, &style, &attr_g, win_opts, PLACE_INITIAL);
2351 wattr.x = attr_g.x;
2352 wattr.y = attr_g.y;
2354 /* set up geometry */
2355 fw->g.frame.x = wattr.x;
2356 fw->g.frame.y = wattr.y;
2357 fw->g.frame.width = wattr.width + b.total_size.width;
2358 fw->g.frame.height = wattr.height + b.total_size.height;
2359 gravity_constrain_size(
2360 fw->hints.win_gravity, fw, &fw->g.frame, 0);
2361 update_absolute_geometry(fw);
2364 /****** auxiliary window setup ******/
2365 setup_auxiliary_windows(fw, True, buttons);
2367 /****** 'backing store' and 'save under' window setup ******/
2368 setup_frame_attributes(fw, &style);
2370 /****** reparent the window ******/
2371 XReparentWindow(dpy, FW_W(fw), FW_W_PARENT(fw), 0, 0);
2373 /****** select events ******/
2374 valuemask = CWEventMask | CWDontPropagate;
2375 if (IS_TEAR_OFF_MENU(fw))
2377 attributes.event_mask = XEVMASK_TEAR_OFF_MENUW;
2379 else
2381 attributes.event_mask = XEVMASK_CLIENTW;
2383 attributes.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
2384 XChangeWindowAttributes(dpy, FW_W(fw), valuemask, &attributes);
2385 /****** make sure the window is not destroyed when fvwm dies ******/
2386 if (!IS_TEAR_OFF_MENU(fw))
2388 /* menus were created by fvwm itself, don't add them to the
2389 * save set */
2390 XAddToSaveSet(dpy, FW_W(fw));
2393 /****** now we can sefely ungrab the server ******/
2394 MyXUngrabServer(dpy);
2396 /* need to set up the mini icon before drawing */
2397 if (FMiniIconsSupported)
2399 setup_mini_icon(fw, &style);
2402 /****** arrange the frame ******/
2404 if (is_resizing_event_pending(fw) == True)
2406 SET_FORCE_NEXT_CR(fw, 1);
2407 SET_FORCE_NEXT_PN(fw, 1);
2408 mr_args = frame_create_move_resize_args(
2409 fw, FRAME_MR_FORCE_SETUP_NO_W | FRAME_MR_DONT_DRAW,
2410 NULL, &fw->g.frame, 0, DIR_NONE);
2412 else
2414 mr_args = frame_create_move_resize_args(
2415 fw, FRAME_MR_FORCE_SETUP | FRAME_MR_DONT_DRAW, NULL,
2416 &fw->g.frame, 0, DIR_NONE);
2418 frame_move_resize(fw, mr_args);
2419 frame_free_move_resize_args(fw, mr_args);
2420 /* draw later */
2421 SET_WAS_NEVER_DRAWN(fw, 1);
2423 /****** grab keys and buttons ******/
2424 setup_key_and_button_grabs(fw);
2426 /****** inform modules of new window ******/
2427 BroadcastConfig(M_ADD_WINDOW,fw);
2428 BroadcastWindowIconNames(fw, True, False);
2430 /****** place the window in the stack ring ******/
2431 if (!position_new_window_in_stack_ring(fw, SDO_START_LOWERED(sflags)))
2433 XWindowChanges xwc;
2434 xwc.sibling = FW_W_FRAME(get_next_window_in_stack_ring(fw));
2435 xwc.stack_mode = Above;
2436 XConfigureWindow(
2437 dpy, FW_W_FRAME(fw), CWSibling|CWStackMode, &xwc);
2440 /* these are sent and broadcast before res_{class,name} for the benefit
2441 * of FvwmIconBox which can't handle M_ICON_FILE after M_RES_NAME */
2442 /****** icon and mini icon ******/
2443 /* migo (20-Jan-2000): the logic is to unset this flag on NULL values */
2444 SET_WAS_ICON_NAME_PROVIDED(fw, 1);
2445 setup_icon(fw, &style);
2446 if (FMiniIconsSupported)
2448 broadcast_mini_icon(fw);
2450 BroadcastName(M_RES_CLASS,FW_W(fw),FW_W_FRAME(fw),
2451 (unsigned long)fw,fw->class.res_class);
2452 BroadcastName(M_RES_NAME,FW_W(fw),FW_W_FRAME(fw),
2453 (unsigned long)fw,fw->class.res_name);
2455 /****** stick window ******/
2456 if (!(fw->hints.flags & USPosition) || used_sm)
2458 int stick_page;
2459 int stick_desk;
2461 stick_page = is_window_sticky_across_pages(fw);
2462 stick_desk = is_window_sticky_across_desks(fw);
2463 if ((stick_page &&
2464 !IsRectangleOnThisPage(&fw->g.frame, Scr.CurrentDesk)) ||
2465 (stick_desk && fw->Desk != Scr.CurrentDesk))
2467 /* If it's sticky and the user didn't ask for an
2468 * explicit position, force it on screen now. Don't do
2469 * that with USPosition because we have to assume the
2470 * user knows what (s)he is doing. This is necessary
2471 * e.g. if we want a sticky 'panel' in FvwmButtons but
2472 * don't want to see when it's mapped in the void. */
2473 ecc.w.fw = fw;
2474 ecc.w.w = FW_W_FRAME(fw);
2475 ecc.w.wcontext = C_FRAME;
2476 exc2 = exc_clone_context(
2477 exc, &ecc, ECC_FW | ECC_W | ECC_WCONTEXT);
2478 SET_STICKY_ACROSS_PAGES(fw, 0);
2479 SET_STICKY_ACROSS_DESKS(fw, 0);
2480 handle_stick(
2481 NULL, exc2, "", stick_page, stick_desk, 1, 0);
2482 exc_destroy_context(exc2);
2486 /****** resize window ******/
2487 if (do_resize_too)
2489 XEvent e;
2491 memset(&e, 0, sizeof(e));
2492 FWarpPointer(
2493 dpy, Scr.Root, Scr.Root, 0, 0, Scr.MyDisplayWidth,
2494 Scr.MyDisplayHeight,
2495 fw->g.frame.x + (fw->g.frame.width>>1),
2496 fw->g.frame.y + (fw->g.frame.height>>1));
2497 e.xany.type = ButtonPress;
2498 e.xbutton.button = 1;
2499 e.xbutton.state = Button1Mask;
2500 e.xbutton.x_root = fw->g.frame.x + (fw->g.frame.width>>1);
2501 e.xbutton.y_root = fw->g.frame.y + (fw->g.frame.height>>1);
2502 e.xbutton.x = (fw->g.frame.width>>1);
2503 e.xbutton.y = (fw->g.frame.height>>1);
2504 e.xbutton.subwindow = None;
2505 e.xany.window = FW_W(fw);
2506 fev_fake_event(&e);
2507 ecc.x.etrigger = &e;
2508 ecc.w.fw = fw;
2509 ecc.w.wcontext = C_WINDOW;
2510 exc2 = exc_clone_context(
2511 exc, &ecc, ECC_ETRIGGER | ECC_FW | ECC_WCONTEXT);
2512 CMD_Resize(NULL, exc2, "");
2513 exc_destroy_context(exc2);
2516 /****** window colormap ******/
2517 ReInstallActiveColormap();
2519 /****** ewmh setup *******/
2520 EWMH_WindowInit(fw);
2522 /****** gnome setup ******/
2523 /* set GNOME hints on the window from flags set on fw */
2524 GNOME_SetHints(fw);
2525 GNOME_SetLayer(fw);
2526 GNOME_SetDesk(fw);
2527 GNOME_SetWinArea(fw);
2529 /****** windowshade ******/
2530 if (state_args.do_shade || SDO_START_SHADED(sflags))
2532 rectangle big_g;
2533 rectangle new_g;
2534 frame_move_resize_args mr_args;
2536 if (state_args.used_title_dir_for_shading)
2538 state_args.shade_dir = GET_TITLE_DIR(fw);
2540 /* If we've set a style for StartShaded, ensure we override
2541 * the state for it here. -- TA.
2543 if (SDO_START_SHADED(sflags) && !state_args.do_shade)
2545 state_args.shade_dir = SGET_STARTS_SHADED_DIR(style);
2547 big_g = (IS_MAXIMIZED(fw)) ? fw->g.max : fw->g.frame;
2548 new_g = big_g;
2549 get_shaded_geometry_with_dir(
2550 fw, &new_g, &new_g, state_args.shade_dir);
2551 mr_args = frame_create_move_resize_args(
2552 fw, FRAME_MR_SHRINK | FRAME_MR_DONT_DRAW, &big_g,
2553 &new_g, 0, state_args.shade_dir);
2554 frame_move_resize(fw, mr_args);
2555 SET_SHADED(fw, 1);
2556 SET_SHADED_DIR(fw, state_args.shade_dir);
2557 frame_free_move_resize_args(fw, mr_args);
2559 if (!IS_SHADED(fw) && !IS_ICONIFIED(fw))
2561 /* TK always wants some special treatment: If the window is
2562 * simply mapped, the tk menus come up at funny Y coordinates.
2563 * Tell it it's geometry *again* to work around this problem.
2565 SendConfigureNotify(
2566 fw, fw->g.frame.x, fw->g.frame.y, fw->g.frame.width,
2567 fw->g.frame.height, 0, False);
2569 if (
2570 HAS_EWMH_INIT_MAXVERT_STATE(fw) == EWMH_STATE_HAS_HINT ||
2571 HAS_EWMH_INIT_MAXHORIZ_STATE(fw) == EWMH_STATE_HAS_HINT)
2573 int h;
2574 int v;
2575 char cmd[256];
2577 if (
2578 is_function_allowed(
2579 F_MAXIMIZE, NULL, fw, RQORIG_PROGRAM_US,
2580 False))
2582 h = (HAS_EWMH_INIT_MAXHORIZ_STATE(fw) ==
2583 EWMH_STATE_HAS_HINT) ? 100 : 0;
2584 v = (HAS_EWMH_INIT_MAXVERT_STATE(fw) ==
2585 EWMH_STATE_HAS_HINT) ? 100 : 0;
2586 sprintf(cmd,"Maximize on %i %i", h, v);
2587 execute_function_override_window(
2588 NULL, NULL, cmd, 0, fw);
2591 if (HAS_EWMH_INIT_FULLSCREEN_STATE(fw) == EWMH_STATE_HAS_HINT)
2593 EWMH_fullscreen(fw);
2595 if (!XGetGeometry(
2596 dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY,
2597 (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
2598 (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth))
2600 /* The window has disappeared somehow. For some reason we do
2601 * not always get a DestroyNotify on the window, so make sure
2602 * it is destroyed. */
2603 destroy_window(fw);
2604 fw = NULL;
2607 return fw;
2613 * Procedure:
2614 * FetchWMProtocols - finds out which protocols the window supports
2616 * Inputs:
2617 * tmp - the fvwm window structure to use
2620 void FetchWmProtocols(FvwmWindow *tmp)
2622 Atom *protocols = NULL, *ap;
2623 unsigned long *l_protocols;
2624 int i, n;
2625 Atom atype;
2626 int aformat;
2627 unsigned long bytes_remain,nitems;
2629 if (tmp == NULL)
2631 return;
2633 /* First, try the Xlib function to read the protocols.
2634 * This is what Twm uses. */
2635 if (XGetWMProtocols (dpy, FW_W(tmp), &protocols, &n))
2637 for (i = 0, ap = protocols; i < n; i++, ap++)
2639 if (*ap == (Atom)_XA_WM_TAKE_FOCUS)
2641 SET_WM_TAKES_FOCUS(tmp, 1);
2642 set_focus_model(tmp);
2644 if (*ap == (Atom)_XA_WM_DELETE_WINDOW)
2646 SET_WM_DELETES_WINDOW(tmp, 1);
2649 if (protocols)
2651 XFree((char *)protocols);
2654 else
2656 /* Next, read it the hard way. mosaic from Coreldraw needs to
2657 * be read in this way. */
2658 if ((XGetWindowProperty(
2659 dpy, FW_W(tmp), _XA_WM_PROTOCOLS, 0L, 10L, False,
2660 _XA_WM_PROTOCOLS, &atype, &aformat, &nitems,
2661 &bytes_remain,
2662 (unsigned char **)&l_protocols)) == Success)
2664 for (i = 0; i < nitems; i++)
2666 ap = &(l_protocols[i]);
2667 if (*ap == (Atom)_XA_WM_TAKE_FOCUS)
2669 SET_WM_TAKES_FOCUS(tmp, 1);
2670 set_focus_model(tmp);
2672 if (*ap == (Atom)_XA_WM_DELETE_WINDOW)
2674 SET_WM_DELETES_WINDOW(tmp, 1);
2677 if (protocols)
2679 XFree((char *)protocols);
2684 return;
2691 * Procedure:
2692 * GetWindowSizeHints - gets application supplied size info
2694 * Inputs:
2695 * tmp - the fvwm window structure to use
2699 void GetWindowSizeHints(FvwmWindow *fw)
2701 long supplied = 0;
2702 char *broken_cause ="";
2703 XSizeHints orig_hints;
2704 Status rc;
2706 fw->orig_hints.width_inc = 1;
2707 fw->orig_hints.height_inc = 1;
2708 rc = XGetWMNormalHints(dpy, FW_W(fw), &orig_hints, &supplied);
2709 if (rc == 0)
2711 fw->hints.flags = 0;
2712 memset(&orig_hints, 0, sizeof(orig_hints));
2714 else
2716 fw->hints = orig_hints;
2717 if (fw->hints.flags & PResizeInc)
2719 fw->orig_hints.width_inc = fw->hints.width_inc;
2720 fw->orig_hints.height_inc = fw->hints.height_inc;
2722 if (HAS_OVERRIDE_SIZE_HINTS(fw))
2724 /* ignore the WMNormal hints */
2725 fw->hints.flags &= ~(PMinSize | PMaxSize | PResizeInc);
2726 fw->hints.min_width = 0;
2727 fw->hints.min_height = 0;
2728 fw->hints.max_width = 0;
2729 fw->hints.max_height = 0;
2730 fw->hints.width_inc = 1;
2731 fw->hints.height_inc = 1;
2735 /* Beat up our copy of the hints, so that all important field are
2736 * filled in! */
2737 if (fw->hints.flags & PResizeInc)
2739 SET_SIZE_INC_SET(fw, 1);
2740 if (fw->hints.width_inc <= 0)
2742 if (fw->hints.width_inc < 0 ||
2743 (fw->hints.width_inc == 0 &&
2744 (fw->hints.flags & PMinSize) &&
2745 (fw->hints.flags & PMaxSize) &&
2746 fw->hints.min_width != fw->hints.max_width))
2748 broken_cause = "width_inc";
2750 fw->hints.width_inc = 1;
2751 SET_SIZE_INC_SET(fw, 0);
2753 if (fw->hints.height_inc <= 0)
2755 if (fw->hints.height_inc < 0 ||
2756 (fw->hints.height_inc == 0 &&
2757 (fw->hints.flags & PMinSize) &&
2758 (fw->hints.flags & PMaxSize) &&
2759 fw->hints.min_height != fw->hints.max_height))
2761 if (!*broken_cause)
2763 broken_cause = "height_inc";
2766 fw->hints.height_inc = 1;
2767 SET_SIZE_INC_SET(fw, 0);
2770 else
2772 SET_SIZE_INC_SET(fw, 0);
2773 fw->hints.width_inc = 1;
2774 fw->hints.height_inc = 1;
2777 if (fw->hints.flags & PMinSize)
2779 if (fw->hints.min_width < 0 && !*broken_cause)
2781 broken_cause = "min_width";
2783 if (fw->hints.min_height < 0 && !*broken_cause)
2785 broken_cause = "min_height";
2788 else
2790 if (fw->hints.flags & PBaseSize)
2792 fw->hints.min_width = fw->hints.base_width;
2793 fw->hints.min_height = fw->hints.base_height;
2795 else
2797 fw->hints.min_width = 1;
2798 fw->hints.min_height = 1;
2801 if (fw->hints.min_width <= 0)
2803 fw->hints.min_width = 1;
2805 if (fw->hints.min_height <= 0)
2807 fw->hints.min_height = 1;
2810 if (fw->hints.flags & PMaxSize)
2812 if (fw->hints.max_width < fw->hints.min_width)
2814 fw->hints.max_width = DEFAULT_MAX_MAX_WINDOW_WIDTH;
2815 if (!*broken_cause)
2817 broken_cause = "max_width";
2820 if (fw->hints.max_height < fw->hints.min_height)
2822 fw->hints.max_height = DEFAULT_MAX_MAX_WINDOW_HEIGHT;
2823 if (!*broken_cause)
2825 broken_cause = "max_height";
2829 else
2831 fw->hints.max_width = DEFAULT_MAX_MAX_WINDOW_WIDTH;
2832 fw->hints.max_height = DEFAULT_MAX_MAX_WINDOW_HEIGHT;
2836 * ICCCM says that PMinSize is the default if no PBaseSize is given,
2837 * and vice-versa.
2840 if (fw->hints.flags & PBaseSize)
2842 if (fw->hints.base_width < 0)
2844 fw->hints.base_width = 0;
2845 if (!*broken_cause)
2847 broken_cause = "base_width";
2850 if (fw->hints.base_height < 0)
2852 fw->hints.base_height = 0;
2853 if (!*broken_cause)
2855 broken_cause = "base_height";
2858 if ((fw->hints.base_width > fw->hints.min_width) ||
2859 (fw->hints.base_height > fw->hints.min_height))
2861 /* In this case, doing the aspect ratio calculation
2862 for window_size - base_size as prescribed by the
2863 ICCCM is going to fail.
2864 Resetting the flag disables the use of base_size
2865 in aspect ratio calculation while it is still used
2866 for grid sizing.
2868 fw->hints.flags &= ~PBaseSize;
2869 #if 0
2870 /* Keep silent about this, since the Xlib manual
2871 * actually recommends making min <= base <= max ! */
2872 broken_cause = "";
2873 #endif
2876 else
2878 if (fw->hints.flags & PMinSize)
2880 fw->hints.base_width = fw->hints.min_width;
2881 fw->hints.base_height = fw->hints.min_height;
2883 else
2885 fw->hints.base_width = 0;
2886 fw->hints.base_height = 0;
2890 if (!(fw->hints.flags & PWinGravity))
2892 fw->hints.win_gravity = NorthWestGravity;
2895 if ((fw->hints.flags & PMaxSize) &&
2896 ((fw->hints.flags & PMinSize) || (fw->hints.flags & PBaseSize)))
2898 if (fw->hints.max_width < fw->hints.base_width)
2900 fw->hints.max_width = DEFAULT_MAX_MAX_WINDOW_WIDTH;
2901 if (!*broken_cause)
2903 broken_cause = "max_width";
2906 if (fw->hints.max_height < fw->hints.base_height)
2908 fw->hints.max_height = DEFAULT_MAX_MAX_WINDOW_HEIGHT;
2909 if (!*broken_cause)
2911 broken_cause = "max_height";
2916 if (fw->hints.flags & PAspect)
2919 ** check to make sure min/max aspect ratios look valid
2921 #define maxAspectX fw->hints.max_aspect.x
2922 #define maxAspectY fw->hints.max_aspect.y
2923 #define minAspectX fw->hints.min_aspect.x
2924 #define minAspectY fw->hints.min_aspect.y
2928 ** The math looks like this:
2930 ** minAspectX maxAspectX
2931 ** ---------- <= ----------
2932 ** minAspectY maxAspectY
2934 ** If that is multiplied out, this must be satisfied:
2936 ** minAspectX * maxAspectY <= maxAspectX * minAspectY
2938 ** So, what to do if this isn't met? Ignoring it entirely
2939 ** seems safest.
2943 /* We also ignore people who put negative entries into
2944 * their aspect ratios. They deserve it.
2946 * We cast to double here, since the values may be large.
2948 if ((maxAspectX < 0) || (maxAspectY < 0) ||
2949 (minAspectX < 0) || (minAspectY < 0) ||
2950 (((double)minAspectX * (double)maxAspectY) >
2951 ((double)maxAspectX * (double)minAspectY)))
2953 if (!*broken_cause)
2955 broken_cause = "aspect ratio";
2957 fw->hints.flags &= ~PAspect;
2958 fvwm_msg(
2959 WARN, "GetWindowSizeHints",
2960 "The applicaton window (window id %#lx)\n"
2961 " \"%s\" has broken aspect ratio: "
2962 "%d/%d - %d/%d\n"
2963 " fvwm is ignoring this aspect ratio. ",
2964 FW_W(fw), fw->name.name, minAspectX,
2965 minAspectY, maxAspectX, maxAspectY);
2966 fvwm_msg_report_app();
2968 else
2970 /* protect against overflow */
2971 if ((maxAspectX > 65536) || (maxAspectY > 65536))
2973 double ratio =
2974 (double) maxAspectX /
2975 (double) maxAspectY;
2976 if (ratio > 1.0)
2978 maxAspectX = 65536;
2979 maxAspectY = 65536 / ratio;
2981 else
2983 maxAspectX = 65536 * ratio;
2984 maxAspectY = 65536;
2987 if ((minAspectX > 65536) || (minAspectY > 65536))
2989 double ratio =
2990 (double) minAspectX /
2991 (double) minAspectY;
2992 if (ratio > 1.0)
2994 minAspectX = 65536;
2995 minAspectY = 65536 / ratio;
2997 else
2999 minAspectX = 65536 * ratio;
3000 minAspectY = 65536;
3004 #undef maxAspectX
3005 #undef maxAspectY
3006 #undef minAspectX
3007 #undef minAspectY
3010 if (*broken_cause != 0)
3012 fvwm_msg(
3013 WARN, "GetWindowSizeHints",
3014 "The application window (id %#lx)\n"
3015 " \"%s\" has broken size hints (%s).\n"
3016 " fvwm is ignoring those hints. "
3017 " hint override = %d, flags = %lx\n"
3018 " min_width = %d, min_height = %d, "
3019 "max_width = %d, max_height = %d\n"
3020 " width_inc = %d, height_inc = %d\n"
3021 " min_aspect = %d/%d, max_aspect = %d/%d\n"
3022 " base_width = %d, base_height = %d\n"
3023 " win_gravity = %d\n",
3024 FW_W(fw), fw->name.name, broken_cause,
3025 HAS_OVERRIDE_SIZE_HINTS(fw),
3026 orig_hints.flags,
3027 orig_hints.min_width, orig_hints.min_height,
3028 orig_hints.max_width, orig_hints.max_height,
3029 orig_hints.width_inc, orig_hints.height_inc,
3030 orig_hints.min_aspect.x, orig_hints.min_aspect.y,
3031 orig_hints.max_aspect.x, orig_hints.max_aspect.y,
3032 orig_hints.base_width, orig_hints.base_height,
3033 orig_hints.win_gravity);
3034 fvwm_msg_report_app();
3037 return;
3042 * Releases dynamically allocated space used to store window/icon names
3045 void free_window_names(FvwmWindow *fw, Bool nukename, Bool nukeicon)
3047 if (!fw)
3049 return;
3052 if (nukename)
3054 if (fw->visible_name && fw->visible_name != fw->name.name &&
3055 fw->visible_name != NoName)
3057 free(fw->visible_name);
3059 fw->visible_name = NoName;
3060 if (fw->name.name)
3062 if (fw->icon_name.name == fw->name.name)
3064 fw->icon_name.name = NoName;
3066 if (fw->visible_icon_name == fw->name.name)
3068 fw->visible_icon_name = fw->icon_name.name;
3070 if (fw->name.name != NoName)
3072 FlocaleFreeNameProperty(&(fw->name));
3073 fw->visible_name = NULL;
3077 if (nukeicon)
3079 if (fw->visible_icon_name &&
3080 fw->visible_icon_name != fw->name.name &&
3081 fw->visible_icon_name != fw->icon_name.name &&
3082 fw->visible_icon_name != NoName)
3084 free(fw->visible_icon_name);
3086 fw->visible_icon_name = NoName;
3087 if (fw->icon_name.name)
3089 if ((fw->icon_name.name != fw->name.name) &&
3090 fw->icon_name.name != NoName)
3092 FlocaleFreeNameProperty(&(fw->icon_name));
3093 fw->visible_icon_name = NULL;
3098 return;
3105 * Handles destruction of a window
3108 void destroy_window(FvwmWindow *fw)
3110 /* Warning, this is also called by HandleUnmapNotify; if it ever needs
3111 * to look at the event, HandleUnmapNotify will have to mash the
3112 * UnmapNotify into a DestroyNotify. */
3113 if (!fw)
3115 return;
3118 /* remove window style */
3119 if (!IS_SCHEDULED_FOR_DESTROY(fw) && !DO_REUSE_DESTROYED(fw))
3121 style_id_t s_id;
3123 memset(&s_id, 0, sizeof(style_id_t));
3124 SID_SET_WINDOW_ID(s_id, (XID)FW_W(fw));
3125 SID_SET_HAS_WINDOW_ID(s_id, True);
3127 style_destroy_style(s_id);
3130 /****** remove from window list ******/
3131 /* if the window is sheduled fro destroy the window has been already
3132 * removed from list */
3133 if (!IS_SCHEDULED_FOR_DESTROY(fw))
3135 /* first, remove the window from the list of all windows! */
3136 if (fw->prev != NULL)
3138 fw->prev->next = fw->next;
3140 if (fw->next != NULL)
3142 fw->next->prev = fw->prev;
3144 fw->next = NULL;
3145 fw->prev = NULL;
3147 /****** also remove it from the stack ring ******/
3150 * RBW - 11/13/1998 - new: have to unhook the stacking order
3151 chain also. There's always a prev and next, since this is a
3152 ring anchored on Scr.FvwmRoot
3154 remove_window_from_stack_ring(fw);
3157 /****** check if we have to delay window destruction ******/
3159 if ((Scr.flags.is_executing_complex_function ||
3160 Scr.flags.is_executing_menu_function) &&
3161 !DO_REUSE_DESTROYED(fw))
3163 if (IS_SCHEDULED_FOR_DESTROY(fw))
3165 return;
3167 /* mark window for destruction */
3168 SET_SCHEDULED_FOR_DESTROY(fw, 1);
3169 Scr.flags.is_window_scheduled_for_destroy = 1;
3170 /* this is necessary in case the application destroys the
3171 * client window and a new window is created with the same
3172 * window id */
3173 delete_client_context(fw);
3174 XFlush(dpy);
3175 /* unmap the the window to fake that it was already removed */
3176 if (IS_ICONIFIED(fw))
3178 if (FW_W_ICON_TITLE(fw))
3180 XUnmapWindow(dpy, FW_W_ICON_TITLE(fw));
3182 if (FW_W_ICON_PIXMAP(fw) != None)
3184 XUnmapWindow(dpy, FW_W_ICON_PIXMAP(fw));
3187 else
3189 XUnmapWindow(dpy, FW_W_FRAME(fw));
3191 adjust_fvwm_internal_windows(fw);
3192 BroadcastPacket(
3193 M_DESTROY_WINDOW, 3, (long)FW_W(fw),
3194 (long)FW_W_FRAME(fw), (unsigned long)fw);
3195 EWMH_DestroyWindow(fw);
3196 focus_grab_buttons_on_layer(fw->layer);
3197 Scr.FWScheduledForDestroy = flist_append_obj(
3198 Scr.FWScheduledForDestroy, fw);
3199 return;
3202 /****** unmap the frame ******/
3204 XUnmapWindow(dpy, FW_W_FRAME(fw));
3205 XFlush(dpy);
3206 /* already done above? */
3207 if (!IS_SCHEDULED_FOR_DESTROY(fw))
3209 SET_SCHEDULED_FOR_DESTROY(fw, 1);
3210 adjust_fvwm_internal_windows(fw);
3211 BroadcastPacket(
3212 M_DESTROY_WINDOW, 3, (long)FW_W(fw),
3213 (long)FW_W_FRAME(fw), (unsigned long)fw);
3214 EWMH_DestroyWindow(fw);
3216 focus_grab_buttons_on_layer(fw->layer);
3218 /****** destroy auxiliary windows ******/
3220 destroy_auxiliary_windows(fw, True);
3222 /****** destroy icon ******/
3224 destroy_icon_boxes(fw);
3225 destroy_icon(fw);
3227 /****** destroy mini icon ******/
3229 #ifdef MINI_ICON
3230 destroy_mini_icon(fw);
3231 #endif
3233 /****** free strings ******/
3235 free_window_names(fw, True, True);
3237 if (fw->style_name)
3239 free(fw->style_name);
3240 fw->style_name = NULL;
3242 if (fw->class.res_name && fw->class.res_name != NoResource)
3244 XFree ((char *)fw->class.res_name);
3245 fw->class.res_name = NoResource;
3247 if (fw->class.res_class && fw->class.res_class != NoClass)
3249 XFree ((char *)fw->class.res_class);
3250 fw->class.res_class = NoClass;
3252 if (fw->mwm_hints)
3254 XFree((char *)fw->mwm_hints);
3255 fw->mwm_hints = NULL;
3258 /****** free fonts ******/
3260 destroy_window_font(fw);
3261 destroy_icon_font(fw);
3263 /****** free wmhints ******/
3265 if (fw->wmhints)
3267 XFree ((char *)fw->wmhints);
3268 fw->wmhints = NULL;
3271 /****** free colormap windows ******/
3273 if (fw->cmap_windows != (Window *)NULL)
3275 XFree((void *)fw->cmap_windows);
3276 fw->cmap_windows = NULL;
3279 /****** throw away the structure ******/
3281 /* Recapture reuses this struct, so don't free it. */
3282 if (!DO_REUSE_DESTROYED(fw))
3284 free((char *)fw);
3287 /****** cleanup ******/
3289 XFlush(dpy);
3291 return;
3297 * Procedure:
3298 * RestoreWithdrawnLocation
3300 * Puts windows back where they were before fvwm took over
3303 void RestoreWithdrawnLocation(
3304 FvwmWindow *fw, Bool is_restart_or_recapture, Window parent)
3306 int w2,h2;
3307 unsigned int mask;
3308 XWindowChanges xwc;
3309 rectangle naked_g;
3310 rectangle unshaded_g;
3311 XSetWindowAttributes xswa;
3313 if (!fw)
3315 return;
3318 /* always get the latest size hints in case the application changed
3319 * the gravity and we do not yet know about it */
3320 XSync(dpy, 0);
3321 GetWindowSizeHints(fw);
3322 SET_HAS_NEW_WM_NORMAL_HINTS(fw, 0);
3323 get_unshaded_geometry(fw, &unshaded_g);
3324 gravity_get_naked_geometry(
3325 fw->hints.win_gravity, fw, &naked_g, &unshaded_g);
3326 gravity_translate_to_northwest_geometry(
3327 fw->hints.win_gravity, fw, &naked_g, &naked_g);
3328 xwc.x = naked_g.x;
3329 xwc.y = naked_g.y;
3330 xwc.width = naked_g.width;
3331 xwc.height = naked_g.height;
3332 xwc.border_width = fw->attr_backup.border_width;
3333 mask = (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
3335 /* We can not assume that the window is currently on the screen.
3336 * Although this is normally the case, it is not always true. The
3337 * most common example is when the user does something in an
3338 * application which will, after some amount of computational delay,
3339 * cause the window to be unmapped, but then switches screens before
3340 * this happens. The XTranslateCoordinates call above will set the
3341 * window coordinates to either be larger than the screen, or negative.
3342 * This will result in the window being placed in odd, or even
3343 * unviewable locations when the window is remapped. The following
3344 * code forces the "relative" location to be within the bounds of the
3345 * display.
3347 * gpw -- 11/11/93
3349 * Unfortunately, this does horrendous things during re-starts,
3350 * hence the "if (restart)" clause (RN)
3352 * Also, fixed so that it only does this stuff if a window is more than
3353 * half off the screen. (RN)
3356 if (!is_restart_or_recapture)
3358 /* Don't mess with it if its partially on the screen now */
3359 if (unshaded_g.x < 0 || unshaded_g.y < 0 ||
3360 unshaded_g.x >= Scr.MyDisplayWidth ||
3361 unshaded_g.y >= Scr.MyDisplayHeight)
3363 w2 = (unshaded_g.width >> 1);
3364 h2 = (unshaded_g.height >> 1);
3365 if ( xwc.x < -w2 || xwc.x > Scr.MyDisplayWidth - w2)
3367 xwc.x = xwc.x % Scr.MyDisplayWidth;
3368 if (xwc.x < -w2)
3370 xwc.x += Scr.MyDisplayWidth;
3373 if (xwc.y < -h2 || xwc.y > Scr.MyDisplayHeight - h2)
3375 xwc.y = xwc.y % Scr.MyDisplayHeight;
3376 if (xwc.y < -h2)
3378 xwc.y += Scr.MyDisplayHeight;
3384 /* restore initial backing store setting on window */
3385 xswa.backing_store = fw->attr_backup.backing_store;
3386 XChangeWindowAttributes(dpy, FW_W(fw), CWBackingStore, &xswa);
3387 /* reparent to root window */
3388 XReparentWindow(
3389 dpy, FW_W(fw), (parent == None) ? Scr.Root : parent, xwc.x,
3390 xwc.y);
3392 if (IS_ICONIFIED(fw) && !IS_ICON_SUPPRESSED(fw))
3394 if (FW_W_ICON_TITLE(fw))
3396 XUnmapWindow(dpy, FW_W_ICON_TITLE(fw));
3398 if (FW_W_ICON_PIXMAP(fw))
3400 XUnmapWindow(dpy, FW_W_ICON_PIXMAP(fw));
3404 XConfigureWindow(dpy, FW_W(fw), mask, &xwc);
3405 if (!is_restart_or_recapture)
3407 /* must be initial capture */
3408 XFlush(dpy);
3411 return;
3417 * Procedure:
3418 * Reborder - Removes fvwm border windows
3421 void Reborder(void)
3423 FvwmWindow *fw;
3425 /* put a border back around all windows */
3426 MyXGrabServer (dpy);
3428 /* force reinstall */
3429 InstallWindowColormaps (&Scr.FvwmRoot);
3431 /* RBW - 05/15/1998
3432 * Grab the last window and work backwards: preserve stacking order on
3433 * restart. */
3434 for (fw = get_prev_window_in_stack_ring(&Scr.FvwmRoot);
3435 fw != &Scr.FvwmRoot; fw = get_prev_window_in_stack_ring(fw))
3437 if (!IS_ICONIFIED(fw) && Scr.CurrentDesk != fw->Desk)
3439 XMapWindow(dpy, FW_W(fw));
3440 SetMapStateProp(fw, NormalState);
3442 RestoreWithdrawnLocation (fw, True, Scr.Root);
3443 XUnmapWindow(dpy,FW_W_FRAME(fw));
3444 XDestroyWindow(dpy,FW_W_FRAME(fw));
3447 MyXUngrabServer (dpy);
3448 FOCUS_RESET();
3449 XFlush(dpy);
3451 return;
3454 void CaptureAllWindows(const exec_context_t *exc, Bool is_recapture)
3456 int i,j;
3457 unsigned int nchildren;
3458 Window root, parent, *children;
3459 initial_window_options_t win_opts;
3460 FvwmWindow *fw;
3462 MyXGrabServer(dpy);
3463 if (!XQueryTree(dpy, Scr.Root, &root, &parent, &children, &nchildren))
3465 MyXUngrabServer(dpy);
3466 return;
3468 memset(&win_opts, 0, sizeof(win_opts));
3469 win_opts.flags.do_override_ppos = 1;
3470 win_opts.flags.is_recapture = 1;
3471 if (!(Scr.flags.are_windows_captured)) /* initial capture? */
3473 evh_args_t ea;
3474 exec_context_changes_t ecc;
3475 XEvent e;
3477 /* weed out icon windows */
3478 for (i = 0; i < nchildren; i++)
3480 if (children[i])
3482 XWMHints *wmhintsp = XGetWMHints(
3483 dpy, children[i]);
3485 if (wmhintsp &&
3486 wmhintsp->flags & IconWindowHint)
3488 for (j = 0; j < nchildren; j++)
3490 if (children[j] ==
3491 wmhintsp->icon_window)
3493 children[j] = None;
3494 break;
3498 if (wmhintsp)
3500 XFree ((char *) wmhintsp);
3504 /* map all of the non-override, non-icon windows */
3505 e.type = MapRequest;
3506 ecc.x.etrigger = &e;
3507 for (i = 0; i < nchildren; i++)
3510 if (children[i] &&
3511 MappedNotOverride(children[i], &win_opts))
3513 XUnmapWindow(dpy, children[i]);
3514 e.xmaprequest.window = children[i];
3515 e.xmaprequest.parent = Scr.Root;
3516 ecc.w.fw = NULL;
3517 ecc.w.w = children[i];
3518 ecc.w.wcontext = C_ROOT;
3519 ea.exc = exc_clone_context(
3520 exc, &ecc, ECC_ETRIGGER | ECC_FW |
3521 ECC_W | ECC_WCONTEXT);
3522 HandleMapRequestKeepRaised(
3523 &ea, None, NULL, &win_opts);
3524 exc_destroy_context(ea.exc);
3527 Scr.flags.are_windows_captured = 1;
3529 else /* must be recapture */
3531 Window keep_on_top_win;
3532 Window parent_win;
3533 Window focus_w;
3534 FvwmWindow *t;
3536 t = get_focus_window();
3537 focus_w = (t) ? FW_W(t) : None;
3538 hide_screen(True, &keep_on_top_win, &parent_win);
3539 /* reborder all windows */
3540 for (i=0;i<nchildren;i++)
3542 if (XFindContext(
3543 dpy, children[i], FvwmContext,
3544 (caddr_t *)&fw) != XCNOENT)
3546 CaptureOneWindow(
3547 exc, fw, children[i], keep_on_top_win,
3548 parent_win, is_recapture);
3551 hide_screen(False, NULL, NULL);
3552 /* find the window that had the focus and focus it again */
3553 if (focus_w)
3555 for (t = Scr.FvwmRoot.next; t && FW_W(t) != focus_w;
3556 t = t->next)
3560 if (t)
3562 SetFocusWindow(t, True, FOCUS_SET_FORCE);
3566 if (nchildren > 0)
3568 XFree((char *)children);
3570 MyXUngrabServer(dpy);
3572 return;
3575 /* ---------------------------- builtin commands --------------------------- */
3577 void CMD_Recapture(F_CMD_ARGS)
3579 do_recapture(F_PASS_ARGS, False);
3581 return;
3584 void CMD_RecaptureWindow(F_CMD_ARGS)
3586 do_recapture(F_PASS_ARGS, True);
3588 return;