/* -*-c-*- */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* This module is based on Twm, but has been siginificantly modified * by Rob Nation */ /* * Copyright 1988 by Evans & Sutherland Computer Corporation, * Salt Lake City, Utah * Portions Copyright 1989 by the Massachusetts Institute of Technology * Cambridge, Massachusetts * * All Rights Reserved * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby * granted, provided that the above copyright notice appear in all * copies and that both that copyright notice and this permis- * sion notice appear in supporting documentation, and that the * names of Evans & Sutherland and M.I.T. not be used in advertising * in publicity pertaining to distribution of the software without * specific, written prior permission. * * EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- * ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR * M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- * AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE * OR PERFORMANCE OF THIS SOFTWARE. */ /* ---------------------------- included header files ---------------------- */ #include "config.h" #include #include "libs/fvwmlib.h" #include "libs/FShape.h" #include "libs/FScreen.h" #include "libs/Picture.h" #include "libs/PictureUtils.h" #include "libs/charmap.h" #include "libs/wcontext.h" #include "libs/Grab.h" #include "libs/Strings.h" #include "libs/XResource.h" #include "fvwm.h" #include "externs.h" #include "cursor.h" #include "execcontext.h" #include "commands.h" #include "bindings.h" #include "misc.h" #include "screen.h" #include "add_window.h" #include "events.h" #include "eventhandler.h" #include "eventmask.h" #include "module_interface.h" #include "stack.h" #include "update.h" #include "style.h" #include "icons.h" #include "gnome.h" #include "ewmh.h" #include "focus.h" #include "placement.h" #include "geometry.h" #include "session.h" #include "move_resize.h" #include "borders.h" #include "frame.h" #include "colormaps.h" #include "decorations.h" #include "functions.h" /* ---------------------------- local definitions -------------------------- */ /* ---------------------------- local macros ------------------------------- */ /* ---------------------------- imports ------------------------------------ */ /* ---------------------------- included code files ------------------------ */ /* ---------------------------- local types -------------------------------- */ /* ---------------------------- forward declarations ----------------------- */ /* ---------------------------- local variables ---------------------------- */ /* ---------------------------- exported variables (globals) --------------- */ char NoName[] = "Untitled"; /* name if no name in XA_WM_NAME */ char NoClass[] = "NoClass"; /* Class if no res_class in class hints */ char NoResource[] = "NoResource"; /* Class if no res_name in class hints */ /* ---------------------------- local functions ---------------------------- */ static void delete_client_context(FvwmWindow *fw) { FvwmWindow *cw; /* We can not simply delete the context. X might have reused the * window structure so we would delete the context that was established * by another FvwmWindow structure in the mean time. */ if (XFindContext( dpy, FW_W(fw), FvwmContext, (caddr_t *)&cw) != XCNOENT && cw == fw) { XDeleteContext(dpy, FW_W(fw), FvwmContext); } return; } /* * * Procedure: * CaptureOneWindow * CaptureAllWindows * * Decorates windows at start-up and during recaptures * */ static void CaptureOneWindow( const exec_context_t *exc, FvwmWindow *fw, Window window, Window keep_on_top_win, Window parent_win, Bool is_recapture) { Window w; unsigned long data[1]; initial_window_options_t win_opts; evh_args_t ea; exec_context_changes_t ecc; XEvent e; if (fw == NULL) { return; } if (IS_SCHEDULED_FOR_DESTROY(fw)) { /* Fvwm might crash in complex functions if we really try to * the dying window here because AddWindow() may fail and leave * a destroyed window in some structures. By the way, it is * pretty useless to recapture a window that will vanish in a * moment. */ return; } /* Grab the server to make sure the window does not die during the * recapture. */ MyXGrabServer(dpy); if ( !XGetGeometry( dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY, (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight, (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth)) { /* The window has already died, do not recapture it! */ MyXUngrabServer(dpy); return; } if (XFindContext(dpy, window, FvwmContext, (caddr_t *)&fw) != XCNOENT) { Bool is_mapped = IS_MAPPED(fw); memset(&win_opts, 0, sizeof(win_opts)); win_opts.initial_state = DontCareState; win_opts.flags.do_override_ppos = 1; win_opts.flags.is_recapture = 1; if (IS_ICONIFIED(fw)) { win_opts.initial_state = IconicState; win_opts.flags.is_iconified_by_parent = IS_ICONIFIED_BY_PARENT(fw); } else { win_opts.initial_state = NormalState; win_opts.flags.is_iconified_by_parent = 0; if (Scr.CurrentDesk != fw->Desk) { SetMapStateProp(fw, NormalState); } } data[0] = (unsigned long) fw->Desk; XChangeProperty( dpy, FW_W(fw), _XA_WM_DESKTOP, _XA_WM_DESKTOP, 32, PropModeReplace, (unsigned char *) data, 1); /* are all these really needed ? */ /* EWMH_SetWMDesktop(fw); */ GNOME_SetHints(fw); GNOME_SetDesk(fw); GNOME_SetLayer(fw); GNOME_SetWinArea(fw); XSelectInput(dpy, FW_W(fw), NoEventMask); w = FW_W(fw); XUnmapWindow(dpy, FW_W_FRAME(fw)); border_undraw_decorations(fw); RestoreWithdrawnLocation(fw, is_recapture, parent_win); SET_DO_REUSE_DESTROYED(fw, 1); /* RBW - 1999/03/20 */ destroy_window(fw); win_opts.flags.is_menu = (is_recapture && fw != NULL && IS_TEAR_OFF_MENU(fw)); fev_make_null_event(&e, dpy); e.xmaprequest.window = w; e.xmaprequest.parent = Scr.Root; ecc.x.etrigger = &e; ecc.w.fw = NULL; ecc.w.w = w; ecc.w.wcontext = C_ROOT; ea.exc = exc_clone_context( exc, &ecc, ECC_ETRIGGER | ECC_FW | ECC_W | ECC_WCONTEXT); HandleMapRequestKeepRaised(&ea, keep_on_top_win, fw, &win_opts); exc_destroy_context(ea.exc); /* HandleMapRequestKeepRaised may have destroyed the fw if the * window vanished while in AddWindow(), so don't access fw * anymore before checking if it is a valid window. */ if (check_if_fvwm_window_exists(fw)) { if (!fFvwmInStartup) { SET_MAP_PENDING(fw, 0); SET_MAPPED(fw, is_mapped); } } } MyXUngrabServer(dpy); return; } /* Put a transparent window all over the screen to hide what happens below. */ static void hide_screen( Bool do_hide, Window *ret_hide_win, Window *ret_parent_win) { static Bool is_hidden = False; static Window hide_win = None; static Window parent_win = None; XSetWindowAttributes xswa; unsigned long valuemask; if (do_hide == is_hidden) { /* nothing to do */ if (ret_hide_win) { *ret_hide_win = hide_win; } if (ret_parent_win) { *ret_parent_win = parent_win; } return; } is_hidden = do_hide; if (do_hide) { xswa.override_redirect = True; xswa.cursor = Scr.FvwmCursors[CRS_WAIT]; xswa.backing_store = NotUseful; xswa.save_under = False; xswa.background_pixmap = None; valuemask = CWOverrideRedirect | CWCursor | CWSaveUnder | CWBackingStore | CWBackPixmap; hide_win = XCreateWindow( dpy, Scr.Root, 0, 0, Scr.MyDisplayWidth, Scr.MyDisplayHeight, 0, Pdepth, InputOutput, Pvisual, valuemask, &xswa); if (hide_win) { /* When recapturing, all windows are reparented to this * window. If they are reparented to the root window, * they will flash over the hide_win with XFree. So * reparent them to an unmapped window that looks like * the root window. */ parent_win = XCreateWindow( dpy, Scr.Root, 0, 0, Scr.MyDisplayWidth, Scr.MyDisplayHeight, 0, CopyFromParent, InputOutput, CopyFromParent, valuemask, &xswa); if (!parent_win) { XDestroyWindow(dpy, hide_win); hide_win = None; } else { XMapWindow(dpy, hide_win); XFlush(dpy); } } } else { if (hide_win != None) { XDestroyWindow(dpy, hide_win); } if (parent_win != None) { XDestroyWindow(dpy, parent_win); } XFlush(dpy); hide_win = None; parent_win = None; } if (ret_hide_win) { *ret_hide_win = hide_win; } if (ret_parent_win) { *ret_parent_win = parent_win; } return; } /* * * Procedure: * MappedNotOverride - checks to see if we should really * put a fvwm frame on the window * * Returned Value: * 1 - go ahead and frame the window * 0 - don't frame the window * * Inputs: * w - the window to check * */ static int MappedNotOverride( Window w, initial_window_options_t *win_opts) { XWindowAttributes wa; Atom atype; int aformat; unsigned long nitems, bytes_remain; unsigned char *prop; win_opts->initial_state = DontCareState; if ((w==Scr.NoFocusWin)||(!XGetWindowAttributes(dpy, w, &wa))) { return 0; } if (XGetWindowProperty( dpy,w,_XA_WM_STATE,0L,3L,False,_XA_WM_STATE, &atype,&aformat,&nitems,&bytes_remain,&prop)==Success) { if (prop != NULL) { win_opts->initial_state = *(long *)prop; XFree(prop); } } if (wa.override_redirect == True) { XSelectInput(dpy, w, XEVMASK_ORW); XFlush(dpy); } return (((win_opts->initial_state == IconicState) || (wa.map_state != IsUnmapped)) && (wa.override_redirect != True)); } static void do_recapture(F_CMD_ARGS, Bool fSingle) { FvwmWindow *fw = exc->w.fw; MyXGrabServer(dpy); if (fSingle) { CaptureOneWindow( exc, fw, FW_W(fw), None, None, True); } else { CaptureAllWindows(exc, True); } /* Throw away queued up events. We don't want user input during a * recapture. The window the user clicks in might disapper at the very * same moment and the click goes through to the root window. Not good */ XAllowEvents(dpy, AsyncPointer, CurrentTime); discard_events( ButtonPressMask|ButtonReleaseMask|ButtonMotionMask| \ PointerMotionMask|KeyPressMask|KeyReleaseMask); #ifdef DEBUG_STACK_RING verify_stack_ring_consistency(); #endif MyXUngrabServer(dpy); return; } static void setup_window_structure( FvwmWindow **pfw, Window w, FvwmWindow *ReuseWin) { FvwmWindow save_state; FvwmWindow *savewin = NULL; /* Allocate space for the FvwmWindow struct, or reuse an old one (on Recapture). */ if (ReuseWin == NULL) { *pfw = (FvwmWindow *)safemalloc(sizeof(FvwmWindow)); } else { *pfw = ReuseWin; savewin = &save_state; memcpy(savewin, ReuseWin, sizeof(FvwmWindow)); } /* RBW - 1999/05/28 - modify this when we implement the preserving of various states across a Recapture. The Destroy function in misc.c may also need tweaking, depending on what you want to preserve. For now, just zap any old information, except the desk. */ memset(*pfw, '\0', sizeof(FvwmWindow)); FW_W(*pfw) = w; if (savewin != NULL) { (*pfw)->Desk = savewin->Desk; SET_SHADED(*pfw, IS_SHADED(savewin)); SET_USED_TITLE_DIR_FOR_SHADING( *pfw, USED_TITLE_DIR_FOR_SHADING(savewin)); SET_SHADED_DIR(*pfw, SHADED_DIR(savewin)); SET_NAME_CHANGED(*pfw,IS_NAME_CHANGED(savewin)); (*pfw)->placed_by_button = savewin->placed_by_button; SET_PLACED_BY_FVWM(*pfw, IS_PLACED_BY_FVWM(savewin)); SET_HAS_EWMH_WM_ICON_HINT(*pfw, HAS_EWMH_WM_ICON_HINT(savewin)); (*pfw)->ewmh_mini_icon_width = savewin->ewmh_mini_icon_width; (*pfw)->ewmh_mini_icon_height = savewin->ewmh_mini_icon_height; (*pfw)->ewmh_icon_width = savewin->ewmh_icon_width; (*pfw)->ewmh_icon_height = savewin->ewmh_icon_height; (*pfw)->ewmh_hint_desktop = savewin->ewmh_hint_desktop; /* restore ewmh state */ EWMH_SetWMState(savewin, True); SET_HAS_EWMH_INIT_WM_DESKTOP( *pfw, HAS_EWMH_INIT_WM_DESKTOP(savewin)); SET_HAS_EWMH_INIT_FULLSCREEN_STATE( *pfw, HAS_EWMH_INIT_FULLSCREEN_STATE(savewin)); SET_HAS_EWMH_INIT_HIDDEN_STATE( *pfw, HAS_EWMH_INIT_HIDDEN_STATE(savewin)); SET_HAS_EWMH_INIT_MAXHORIZ_STATE( *pfw, HAS_EWMH_INIT_MAXHORIZ_STATE(savewin)); SET_HAS_EWMH_INIT_MAXVERT_STATE( *pfw, HAS_EWMH_INIT_MAXVERT_STATE(savewin)); SET_HAS_EWMH_INIT_SHADED_STATE( *pfw, HAS_EWMH_INIT_SHADED_STATE(savewin)); SET_HAS_EWMH_INIT_STICKY_STATE( *pfw, HAS_EWMH_INIT_STICKY_STATE(savewin)); CLEAR_USER_STATES(*pfw, ~0); SET_USER_STATES(*pfw, GET_USER_STATES(savewin)); } else { /* make sure that new windows *remember* being shaded with * title dir last */ SET_USED_TITLE_DIR_FOR_SHADING(*pfw,1); } (*pfw)->cmap_windows = (Window *)NULL; if (FMiniIconsSupported) { (*pfw)->mini_pixmap_file = NULL; (*pfw)->mini_icon = NULL; } return; } static void setup_name_count(FvwmWindow *fw, Bool is_icon) { FvwmWindow *t; int count = 0; int win_count; int win_count_counterpart; Bool done = False; FlocaleNameString *titlename, *title_counterpart; FlocaleNameString *t_titlename, *t_title_counterpart; titlename = (is_icon) ? &(fw->icon_name) : &(fw->name); title_counterpart = (is_icon) ? &(fw->name) : &(fw->icon_name); if (!titlename->name) { done = True; } if (titlename->name && title_counterpart->name && strcmp(titlename->name, title_counterpart->name) == 0) { count = is_icon ? fw->icon_name_count : fw->name_count; } while (!done) { done = True; for (t = Scr.FvwmRoot.next; t != NULL; t = t->next) { if (t == fw) { continue; } win_count = is_icon ? t->icon_name_count : t->name_count; win_count_counterpart = is_icon ? t->name_count : t->icon_name_count; t_titlename = is_icon ? &(t->icon_name) : &(t->name); t_title_counterpart = is_icon ? &(t->name) : &(t->icon_name); if ((t_titlename->name && strcmp(titlename->name, t_titlename->name) == 0 && win_count == count) || (t_title_counterpart->name && strcmp(t_title_counterpart->name, titlename->name) == 0 && win_count_counterpart == count)) { count++; done = False; } } } if (is_icon) { fw->icon_name_count = count; } else { fw->name_count = count; } return; } static void setup_class_and_resource(FvwmWindow *fw) { /* removing NoClass change for now... */ fw->class.res_name = NoResource; fw->class.res_class = NoClass; XGetClassHint(dpy, FW_W(fw), &fw->class); if (fw->class.res_name == NULL) { fw->class.res_name = NoResource; } if (fw->class.res_class == NULL) { fw->class.res_class = NoClass; } FetchWmProtocols (fw); FetchWmColormapWindows (fw); return; } static void setup_window_attr( FvwmWindow *fw, XWindowAttributes *ret_attr) { if (XGetWindowAttributes(dpy, FW_W(fw), ret_attr) == 0) { /* can't happen because fvwm has grabbed the server and does * not destroy the window itself */ } fw->attr_backup.backing_store = ret_attr->backing_store; fw->attr_backup.border_width = ret_attr->border_width; fw->attr_backup.depth = ret_attr->depth; fw->attr_backup.bit_gravity = ret_attr->bit_gravity; fw->attr_backup.is_bit_gravity_stored = 0; fw->attr_backup.visual = ret_attr->visual; fw->attr_backup.colormap = ret_attr->colormap; return; } static void destroy_window_font(FvwmWindow *fw) { if (IS_WINDOW_FONT_LOADED(fw) && !USING_DEFAULT_WINDOW_FONT(fw) && fw->title_font != Scr.DefaultFont) { FlocaleUnloadFont(dpy, fw->title_font); } SET_WINDOW_FONT_LOADED(fw, 0); /* Fall back to default font. There are some race conditions when a * window is destroyed and recaptured where an invalid font might be * accessed otherwise. */ fw->title_font = Scr.DefaultFont; SET_USING_DEFAULT_WINDOW_FONT(fw, 1); return; } static void destroy_icon_font(FvwmWindow *fw) { if (IS_ICON_FONT_LOADED(fw) && !USING_DEFAULT_ICON_FONT(fw) && fw->icon_font != Scr.DefaultFont) { FlocaleUnloadFont(dpy, fw->icon_font); } SET_ICON_FONT_LOADED(fw, 0); /* Fall back to default font (see comment above). */ fw->icon_font = Scr.DefaultFont; SET_USING_DEFAULT_ICON_FONT(fw, 1); return; } static void adjust_fvwm_internal_windows(FvwmWindow *fw) { if (fw == Scr.Hilite) { Scr.Hilite = NULL; } update_last_screen_focus_window(fw); restore_focus_after_unmap(fw, False); frame_destroyed_frame(FW_W(fw)); if (FW_W(fw) == Scr.StolenFocusWin) { Scr.StolenFocusWin = None; } if (Scr.focus_in_pending_window == fw) { Scr.focus_in_pending_window = NULL; } if (Scr.cascade_window == fw) { Scr.cascade_window = NULL; } return; } static void broadcast_mini_icon(FvwmWindow *fw) { if (!FMiniIconsSupported) { return; } if (fw->mini_pixmap_file && fw->mini_icon) { BroadcastFvwmPicture( M_MINI_ICON, FW_W(fw), FW_W_FRAME(fw), (unsigned long)fw, fw->mini_icon, fw->mini_pixmap_file); } return; } static void setup_mini_icon(FvwmWindow *fw, window_style *pstyle) { FvwmPictureAttributes fpa; if (!FMiniIconsSupported) { return; } if (SHAS_MINI_ICON(&pstyle->flags)) { fw->mini_pixmap_file = SGET_MINI_ICON_NAME(*pstyle); } else { fw->mini_pixmap_file = NULL; } if (fw->mini_pixmap_file) { fpa.mask = 0; fw->mini_icon = PCacheFvwmPicture( dpy, Scr.NoFocusWin, NULL, fw->mini_pixmap_file, fpa); } else { fw->mini_icon = NULL; } return; } /* * Copy icon size limits from window_style structure to FvwmWindow * structure. */ void setup_icon_size_limits(FvwmWindow *fw, window_style *pstyle) { if (SHAS_ICON_SIZE_LIMITS(&pstyle->flags)) { fw->min_icon_width = SGET_MIN_ICON_WIDTH(*pstyle); fw->min_icon_height = SGET_MIN_ICON_HEIGHT(*pstyle); fw->max_icon_width = SGET_MAX_ICON_WIDTH(*pstyle); fw->max_icon_height = SGET_MAX_ICON_HEIGHT(*pstyle); fw->icon_resize_type = SGET_ICON_RESIZE_TYPE(*pstyle); } else { fw->min_icon_width = MIN_ALLOWABLE_ICON_DIMENSION; fw->min_icon_height = MIN_ALLOWABLE_ICON_DIMENSION; fw->max_icon_width = MAX_ALLOWABLE_ICON_DIMENSION; fw->max_icon_height = MAX_ALLOWABLE_ICON_DIMENSION; fw->icon_resize_type = ICON_RESIZE_TYPE_NONE; } return; } void setup_icon_background_parameters(FvwmWindow *fw, window_style *pstyle) { if (SHAS_ICON_BACKGROUND_PADDING(&pstyle->flags)) { fw->icon_background_padding = SGET_ICON_BACKGROUND_PADDING(*pstyle); } else { fw->icon_background_padding = ICON_BACKGROUND_PADDING; } if (SHAS_ICON_BACKGROUND_RELIEF(&pstyle->flags)) { fw->icon_background_relief = SGET_ICON_BACKGROUND_RELIEF(*pstyle); } else { fw->icon_background_relief = ICON_RELIEF_WIDTH; } return; } void setup_icon_title_parameters(FvwmWindow *fw, window_style *pstyle) { if (SHAS_ICON_TITLE_RELIEF(&pstyle->flags)) { fw->icon_title_relief = SGET_ICON_TITLE_RELIEF(*pstyle); } else { fw->icon_title_relief = ICON_RELIEF_WIDTH; } return; } void setup_numeric_vals(FvwmWindow *fw, window_style *pstyle) { /****** window shading ******/ fw->shade_anim_steps = pstyle->shade_anim_steps; /****** snapattraction, snapgrid, paging ******/ fw->snap_attraction.proximity = pstyle->snap_attraction.proximity; fw->snap_attraction.mode = pstyle->snap_attraction.mode; fw->snap_grid_x = pstyle->snap_grid_x; fw->snap_grid_y = pstyle->snap_grid_y; if (pstyle->flags.has_edge_delay_ms_move) { fw->edge_delay_ms_move = pstyle->edge_delay_ms_move; } else { fw->edge_delay_ms_move = DEFAULT_MOVE_DELAY; } if (pstyle->flags.has_edge_delay_ms_resize) { fw->edge_delay_ms_resize = pstyle->edge_delay_ms_resize; } else { fw->edge_delay_ms_resize = DEFAULT_RESIZE_DELAY; } fw->edge_resistance_move = pstyle->edge_resistance_move; fw->edge_resistance_xinerama_move = pstyle->edge_resistance_xinerama_move; return; } static void setup_frame_window( FvwmWindow *fw) { XSetWindowAttributes attributes; int valuemask; int depth; Visual *visual; FRenderPictFormat *format; valuemask = CWBackingStore | CWBackPixmap | CWEventMask | CWSaveUnder | CWCursor; /* This adds preliminary support for ARGB windows in fvwm. It should evolve to proper ARGB support in frames, menus and modules */ format=FRenderFindVisualFormat(dpy, fw->attr_backup.visual); if (format != NULL && format->type == FRenderPictTypeDirect && format->direct.alphaMask > 0) { depth = fw->attr_backup.depth; visual = fw->attr_backup.visual; attributes.colormap = fw->attr_backup.colormap; attributes.background_pixel = -1; attributes.border_pixel = -1; valuemask |= CWColormap | CWBackPixel | CWBorderPixel; } else { depth = CopyFromParent; visual = CopyFromParent; } attributes.backing_store = NotUseful; attributes.background_pixmap = None; attributes.cursor = Scr.FvwmCursors[CRS_DEFAULT]; attributes.event_mask = XEVMASK_FRAMEW_CAPTURE; attributes.save_under = False; /* create the frame window, child of root, grandparent of client */ FW_W_FRAME(fw) = XCreateWindow( dpy, Scr.Root, fw->g.frame.x, fw->g.frame.y, fw->g.frame.width, fw->g.frame.height, 0, depth, InputOutput, visual, valuemask, &attributes); XSaveContext(dpy, FW_W(fw), FvwmContext, (caddr_t) fw); XSaveContext(dpy, FW_W_FRAME(fw), FvwmContext, (caddr_t) fw); return; } static void setup_title_window( FvwmWindow *fw, int valuemask, XSetWindowAttributes *pattributes) { valuemask |= CWCursor | CWEventMask; pattributes->cursor = Scr.FvwmCursors[CRS_TITLE]; pattributes->event_mask = XEVMASK_TITLEW; FW_W_TITLE(fw) = XCreateWindow( dpy, FW_W_FRAME(fw), 0, 0, 1, 1, 0, Pdepth, InputOutput, Pvisual, valuemask, pattributes); XSaveContext(dpy, FW_W_TITLE(fw), FvwmContext, (caddr_t) fw); return; } static void destroy_title_window(FvwmWindow *fw, Bool do_only_delete_context) { if (!do_only_delete_context) { XDestroyWindow(dpy, FW_W_TITLE(fw)); FW_W_TITLE(fw) = None; } XDeleteContext(dpy, FW_W_TITLE(fw), FvwmContext); XFlush(dpy); FW_W_TITLE(fw) = None; return; } static void change_title_window( FvwmWindow *fw, int valuemask, XSetWindowAttributes *pattributes) { if (HAS_TITLE(fw) && FW_W_TITLE(fw) == None) { setup_title_window(fw, valuemask, pattributes); } else if (!HAS_TITLE(fw) && FW_W_TITLE(fw) != None) { destroy_title_window(fw, False); } return; } static void setup_button_windows( FvwmWindow *fw, int valuemask, XSetWindowAttributes *pattributes, short buttons) { int i; Bool has_button; Bool is_deleted = False; valuemask |= CWCursor | CWEventMask; pattributes->cursor = Scr.FvwmCursors[CRS_SYS]; pattributes->event_mask = XEVMASK_BUTTONW; for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++) { has_button = (((!(i & 1) && i / 2 < Scr.nr_left_buttons) || ( (i & 1) && i / 2 < Scr.nr_right_buttons)) && (buttons & (1 << i))); if (FW_W_BUTTON(fw, i) == None && has_button) { FW_W_BUTTON(fw, i) = XCreateWindow( dpy, FW_W_FRAME(fw), 0, 0, 1, 1, 0, Pdepth, InputOutput, Pvisual, valuemask, pattributes); XSaveContext( dpy, FW_W_BUTTON(fw, i), FvwmContext, (caddr_t)fw); } else if (FW_W_BUTTON(fw, i) != None && !has_button) { /* destroy the current button window */ XDestroyWindow(dpy, FW_W_BUTTON(fw, i)); XDeleteContext(dpy, FW_W_BUTTON(fw, i), FvwmContext); is_deleted = True; FW_W_BUTTON(fw, i) = None; } } if (is_deleted == True) { XFlush(dpy); } return; } static void destroy_button_windows(FvwmWindow *fw, Bool do_only_delete_context) { int i; Bool is_deleted = False; for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++) { if (FW_W_BUTTON(fw, i) != None) { if (!do_only_delete_context) { XDestroyWindow(dpy, FW_W_BUTTON(fw, i)); FW_W_BUTTON(fw, i) = None; } XDeleteContext(dpy, FW_W_BUTTON(fw, i), FvwmContext); is_deleted = True; FW_W_BUTTON(fw, i) = None; } } if (is_deleted == True) { XFlush(dpy); } return; } static void change_button_windows( FvwmWindow *fw, int valuemask, XSetWindowAttributes *pattributes, short buttons) { if (HAS_TITLE(fw)) { setup_button_windows( fw, valuemask, pattributes, buttons); } else { destroy_button_windows(fw, False); } return; } static void setup_parent_window(FvwmWindow *fw) { size_borders b; XSetWindowAttributes attributes; int valuemask; valuemask = CWBackingStore | CWBackPixmap | CWCursor | CWEventMask | CWSaveUnder; attributes.backing_store = NotUseful; attributes.background_pixmap = None; attributes.cursor = Scr.FvwmCursors[CRS_DEFAULT]; attributes.event_mask = XEVMASK_PARENTW; attributes.save_under = False; /* This window is exactly the same size as the client for the benefit * of some clients */ get_window_borders(fw, &b); FW_W_PARENT(fw) = XCreateWindow( dpy, FW_W_FRAME(fw), b.top_left.width, b.top_left.height, fw->g.frame.width - b.total_size.width, fw->g.frame.height - b.total_size.height, 0, CopyFromParent, InputOutput, CopyFromParent, valuemask, &attributes); XSaveContext(dpy, FW_W_PARENT(fw), FvwmContext, (caddr_t) fw); return; } static void setup_resize_handle_cursors(FvwmWindow *fw) { unsigned long valuemask; XSetWindowAttributes attributes; int i; if (HAS_NO_BORDER(fw)) { return; } valuemask = CWCursor; attributes.cursor = Scr.FvwmCursors[CRS_DEFAULT]; for (i = 0; i < 4; i++) { if (HAS_HANDLES(fw)) { attributes.cursor = Scr.FvwmCursors[CRS_TOP_LEFT + i]; } XChangeWindowAttributes( dpy, FW_W_CORNER(fw, i), valuemask, &attributes); if (HAS_HANDLES(fw)) { attributes.cursor = Scr.FvwmCursors[CRS_TOP + i]; } XChangeWindowAttributes( dpy, FW_W_SIDE(fw, i), valuemask, &attributes); } return; } static void setup_resize_handle_windows(FvwmWindow *fw) { unsigned long valuemask; XSetWindowAttributes attributes; int i; int c_grav[4] = { NorthWestGravity, NorthEastGravity, SouthWestGravity, SouthEastGravity }; int s_grav[4] = { NorthWestGravity, NorthEastGravity, SouthWestGravity, NorthWestGravity }; if (HAS_NO_BORDER(fw)) { return; } valuemask = CWEventMask | CWBackingStore | CWSaveUnder | CWWinGravity | CWBorderPixel | CWColormap; attributes.event_mask = XEVMASK_BORDERW; attributes.backing_store = NotUseful; attributes.save_under = False; attributes.border_pixel = 0; attributes.colormap = Pcmap; /* Just dump the windows any old place and let frame_setup_window take * care of the mess */ for (i = 0; i < 4; i++) { attributes.win_gravity = c_grav[i]; FW_W_CORNER(fw, i) = XCreateWindow( dpy, FW_W_FRAME(fw), -1, -1, 1, 1, 0, Pdepth, InputOutput, Pvisual, valuemask, &attributes); XSaveContext( dpy, FW_W_CORNER(fw, i), FvwmContext, (caddr_t)fw); attributes.win_gravity = s_grav[i]; FW_W_SIDE(fw, i) = XCreateWindow( dpy, FW_W_FRAME(fw), -1, -1, 1, 1, 0, Pdepth, InputOutput, Pvisual, valuemask, &attributes); XSaveContext(dpy, FW_W_SIDE(fw, i), FvwmContext, (caddr_t)fw); } setup_resize_handle_cursors(fw); return; } static void destroy_resize_handle_windows( FvwmWindow *fw, Bool do_only_delete_context) { int i; for (i = 0; i < 4 ; i++) { XDeleteContext(dpy, FW_W_SIDE(fw, i), FvwmContext); XDeleteContext(dpy, FW_W_CORNER(fw, i), FvwmContext); if (!do_only_delete_context) { XDestroyWindow(dpy, FW_W_SIDE(fw, i)); XDestroyWindow(dpy, FW_W_CORNER(fw, i)); FW_W_SIDE(fw, i) = None; FW_W_CORNER(fw, i) = None; } } XFlush(dpy); return; } static void change_resize_handle_windows(FvwmWindow *fw) { if (!HAS_NO_BORDER(fw) && FW_W_SIDE(fw, 0) == None) { setup_resize_handle_windows(fw); } else if (HAS_NO_BORDER(fw) && FW_W_SIDE(fw, 0) != None) { destroy_resize_handle_windows(fw, False); } else { setup_resize_handle_cursors(fw); } return; } static void setup_frame_stacking(FvwmWindow *fw) { int i; int n; Window w[10 + NUMBER_OF_TITLE_BUTTONS]; /* Stacking order (top to bottom): * - Parent window * - Title and buttons * - Corner handles * - Side handles */ n = 0; if (!IS_SHADED(fw)) { w[n] = FW_W_PARENT(fw); n++; } if (HAS_TITLE(fw)) { for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i += 2) { if (FW_W_BUTTON(fw, i) != None) { w[n] = FW_W_BUTTON(fw, i); n++; } } for (i = 2 * NR_RIGHT_BUTTONS - 1; i > 0; i -= 2) { if (FW_W_BUTTON(fw, i) != None) { w[n] = FW_W_BUTTON(fw, i); n++; } } if (FW_W_TITLE(fw) != None) { w[n] = FW_W_TITLE(fw); n++; } } for (i = 0; i < 4; i++) { if (FW_W_CORNER(fw, i) != None) { w[n] = FW_W_CORNER(fw, i); n++; } } for (i = 0; i < 4; i++) { if (FW_W_SIDE(fw, i) != None) { w[n] = FW_W_SIDE(fw, i); n++; } } if (IS_SHADED(fw)) { w[n] = FW_W_PARENT(fw); n++; } XRestackWindows(dpy, w, n); return; } static void get_default_window_attributes( FvwmWindow *fw, unsigned long *pvaluemask, XSetWindowAttributes *pattributes) { *pvaluemask |= CWBackingStore | CWCursor | CWSaveUnder | CWBorderPixel | CWColormap | CWBackPixmap; pattributes->background_pixel = 0; pattributes->background_pixmap = None; pattributes->backing_store = NotUseful; pattributes->cursor = Scr.FvwmCursors[CRS_DEFAULT]; pattributes->save_under = False; pattributes->border_pixel = 0; pattributes->colormap = Pcmap; return; } static void setup_auxiliary_windows( FvwmWindow *fw, Bool setup_frame_and_parent, short buttons) { unsigned long valuemask_save = 0; XSetWindowAttributes attributes; get_default_window_attributes(fw, &valuemask_save, &attributes); if (setup_frame_and_parent) { setup_frame_window(fw); setup_parent_window(fw); } setup_resize_handle_windows(fw); if (HAS_TITLE(fw)) { setup_title_window(fw, valuemask_save, &attributes); setup_button_windows(fw, valuemask_save, &attributes, buttons); } setup_frame_stacking(fw); XMapSubwindows (dpy, FW_W_FRAME(fw)); return; } static void destroy_auxiliary_windows( FvwmWindow *fw, Bool destroy_frame_and_parent) { if (destroy_frame_and_parent) { XDeleteContext(dpy, FW_W_FRAME(fw), FvwmContext); XDeleteContext(dpy, FW_W_PARENT(fw), FvwmContext); delete_client_context(fw); XDestroyWindow(dpy, FW_W_FRAME(fw)); } if (HAS_TITLE(fw)) { destroy_title_window(fw, True); } if (HAS_TITLE(fw)) { destroy_button_windows(fw, True); } if (!HAS_NO_BORDER(fw)) { destroy_resize_handle_windows(fw, True); } XFlush(dpy); return; } static void setup_icon(FvwmWindow *fw, window_style *pstyle) { increase_icon_hint_count(fw); /* find a suitable icon pixmap */ if ((fw->wmhints) && (fw->wmhints->flags & IconWindowHint)) { if (SHAS_ICON(&pstyle->flags) && S_ICON_OVERRIDE(SCF(*pstyle)) == ICON_OVERRIDE) { ICON_DBG((stderr,"si: iwh ignored '%s'\n", fw->name.name)); fw->icon_bitmap_file = SGET_ICON_NAME(*pstyle); } else { ICON_DBG((stderr,"si: using iwh '%s'\n", fw->name.name)); fw->icon_bitmap_file = NULL; } } else if ((fw->wmhints) && (fw->wmhints->flags & IconPixmapHint)) { if (SHAS_ICON(&pstyle->flags) && S_ICON_OVERRIDE(SCF(*pstyle)) != NO_ICON_OVERRIDE) { ICON_DBG((stderr,"si: iph ignored '%s'\n", fw->name.name)); fw->icon_bitmap_file = SGET_ICON_NAME(*pstyle); } else { ICON_DBG((stderr,"si: using iph '%s'\n", fw->name.name)); fw->icon_bitmap_file = NULL; } } else if (SHAS_ICON(&pstyle->flags)) { /* an icon was specified */ ICON_DBG((stderr,"si: using style '%s'\n", fw->name.name)); fw->icon_bitmap_file = SGET_ICON_NAME(*pstyle); } else { /* use default icon */ ICON_DBG((stderr,"si: using default '%s'\n", fw->name.name)); fw->icon_bitmap_file = Scr.DefaultIcon; } /* icon name */ if (!EWMH_WMIconName(fw, NULL, NULL, 0)) { fw->icon_name.name = NoName; fw->icon_name.name_list = NULL; FlocaleGetNameProperty( XGetWMIconName, dpy, FW_W(fw), &(fw->icon_name)); } if (fw->icon_name.name == NoName) { fw->icon_name.name = fw->name.name; SET_WAS_ICON_NAME_PROVIDED(fw, 0); } setup_visible_name(fw, True); /* wait until the window is iconified and the icon window is mapped * before creating the icon window */ FW_W_ICON_TITLE(fw) = None; EWMH_SetVisibleName(fw, True); BroadcastWindowIconNames(fw, False, True); if (fw->icon_bitmap_file != NULL && fw->icon_bitmap_file != Scr.DefaultIcon) { BroadcastName(M_ICON_FILE,FW_W(fw),FW_W_FRAME(fw), (unsigned long)fw,fw->icon_bitmap_file); } return; } static void destroy_icon(FvwmWindow *fw) { free_window_names(fw, False, True); if (IS_PIXMAP_OURS(fw)) { XFreePixmap(dpy, fw->iconPixmap); fw->iconPixmap = None; if (fw->icon_maskPixmap != None) { XFreePixmap(dpy, fw->icon_maskPixmap); fw->icon_maskPixmap = None; } if (fw->icon_alphaPixmap != None) { XFreePixmap(dpy, fw->icon_alphaPixmap); fw->icon_alphaPixmap = None; } if (fw->icon_alloc_pixels != NULL) { if (fw->icon_nalloc_pixels != 0) { PictureFreeColors( dpy, Pcmap, fw->icon_alloc_pixels, fw->icon_nalloc_pixels, 0, fw->icon_no_limit); } free(fw->icon_alloc_pixels); fw->icon_alloc_pixels = NULL; fw->icon_nalloc_pixels = 0; fw->icon_no_limit = 0; } } if (FW_W_ICON_TITLE(fw)) { XDestroyWindow(dpy, FW_W_ICON_TITLE(fw)); XDeleteContext(dpy, FW_W_ICON_TITLE(fw), FvwmContext); XFlush(dpy); } if (FW_W_ICON_PIXMAP(fw) != None) { if (IS_ICON_OURS(fw)) { XDestroyWindow(dpy, FW_W_ICON_PIXMAP(fw)); } else { XUnmapWindow(dpy, FW_W_ICON_PIXMAP(fw)); } XDeleteContext(dpy, FW_W_ICON_PIXMAP(fw), FvwmContext); } clear_icon(fw); XFlush(dpy); return; } static void setup_icon_boxes(FvwmWindow *fw, window_style *pstyle) { icon_boxes *ib; /* copy iconboxes ptr (if any) */ if (SHAS_ICON_BOXES(&pstyle->flags)) { fw->IconBoxes = SGET_ICON_BOXES(*pstyle); for (ib = fw->IconBoxes; ib; ib = ib->next) { ib->use_count++; } } else { fw->IconBoxes = NULL; } return; } static void destroy_icon_boxes(FvwmWindow *fw) { if (fw->IconBoxes) { fw->IconBoxes->use_count--; if (fw->IconBoxes->use_count == 0 && fw->IconBoxes->is_orphan) { /* finally destroy the icon box */ free_icon_boxes(fw->IconBoxes); fw->IconBoxes = NULL; } } return; } static void setup_layer(FvwmWindow *fw, window_style *pstyle) { FvwmWindow *tf; int layer; if (SUSE_LAYER(&pstyle->flags)) { /* use layer from style */ layer = SGET_LAYER(*pstyle); } else if ((tf = get_transientfor_fvwmwindow(fw)) != NULL) { /* inherit layer from transientfor window */ layer = get_layer(tf); } else { /* use default layer */ layer = Scr.DefaultLayer; } set_default_layer(fw, layer); set_layer(fw, layer); return; } static void destroy_mini_icon(FvwmWindow *fw) { if (fw->mini_icon) { PDestroyFvwmPicture(dpy, fw->mini_icon); fw->mini_icon = 0; } return; } static void setup_key_and_button_grabs(FvwmWindow *fw) { #ifdef BUGS_ARE_COOL /* dv (29-May-2001): If keys are grabbed separately for C_WINDOW and * the other contexts, new windows have problems when bindings are * removed. Therefore, grab all keys in a single pass through the * list. */ GrabAllWindowKeys( dpy, FW_W_FRAME(fw), Scr.AllBindings, C_WINDOW|C_TITLE|C_RALL|C_LALL|C_SIDEBAR, GetUnusedModifiers(), True); #endif GrabAllWindowKeys( dpy, FW_W_FRAME(fw), Scr.AllBindings, C_TITLE|C_RALL|C_LALL|C_SIDEBAR|C_WINDOW, GetUnusedModifiers(), True); setup_focus_policy(fw); return; } static void __add_window_handle_x_resources(FvwmWindow *fw) { int client_argc = 0; char **client_argv = NULL; XrmValue rm_value; XrmDatabase db = NULL; static XrmOptionDescRec table [] = { {"-xrn", NULL, XrmoptionResArg, (caddr_t) NULL}, {"-xrm", NULL, XrmoptionResArg, (caddr_t) NULL}, }; /* Get global X resources */ MergeXResources(dpy, &db, False); /* Find out if the client requested a specific style on the command * line. */ if (XGetCommand(dpy, FW_W(fw), &client_argv, &client_argc)) { if (client_argc > 0 && client_argv != NULL) { /* command line takes precedence over all */ MergeCmdLineResources( &db, table, 2, fw->class.res_name, &client_argc, client_argv, True); } } /* parse the database values */ if (GetResourceString(db, "fvwmstyle", fw->class.res_name, &rm_value) && rm_value.size != 0) { char *style_name; int name_len; style_name = rm_value.addr; name_len = rm_value.size-1; /* Trim spaces at the start of the name */ while (name_len>0 && isspace(*style_name)) { style_name++; name_len--; } /* Trim spaces at the end of the name */ while (name_len>0 && isspace(*(style_name+name_len-1))) { name_len--; } if (name_len>0) { fw->style_name = (char*)safemalloc(sizeof(char)* (name_len+1)); memcpy(fw->style_name,style_name,name_len); fw->style_name[name_len] = 0; } } XFreeStringList(client_argv); XrmDestroyDatabase(db); return; } /* ---------------------------- interface functions ------------------------ */ void setup_visible_name(FvwmWindow *fw, Bool is_icon) { char *ext_name; char *name; int count; int len; if (fw == NULL) { /* should never happen */ return; } setup_name_count(fw, is_icon); if (is_icon) { if (fw->visible_icon_name != NULL && fw->visible_icon_name != fw->icon_name.name && fw->visible_icon_name != fw->name.name && fw->visible_icon_name != NoName) { free(fw->visible_icon_name); fw->visible_icon_name = NULL; } name = fw->icon_name.name; count = fw->icon_name_count; } else { if (fw->visible_name != NULL && fw->visible_name != fw->name.name && fw->visible_name != NoName) { free(fw->visible_name); fw->visible_name = NULL; } name = fw->name.name; count = fw->name_count; } if (name == NULL) { return; /* should never happen */ } if (count > MAX_WINDOW_NAME_NUMBER - 1) { count = MAX_WINDOW_NAME_NUMBER - 1; } if (count != 0 && ((is_icon && USE_INDEXED_ICON_NAME(fw)) || (!is_icon && USE_INDEXED_WINDOW_NAME(fw)))) { len = strlen(name); count++; ext_name = (char *)safemalloc( len + MAX_WINDOW_NAME_NUMBER_DIGITS + 4); sprintf(ext_name,"%s (%d)", name, count); } else { ext_name = name; } if (is_icon) { fw->visible_icon_name = ext_name; } else { fw->visible_name = ext_name; } return; } void setup_window_name(FvwmWindow *fw) { if (!EWMH_WMName(fw, NULL, NULL, 0)) { fw->name.name = NoName; fw->name.name_list = NULL; FlocaleGetNameProperty(XGetWMName, dpy, FW_W(fw), &(fw->name)); } return; } void setup_wm_hints(FvwmWindow *fw) { fw->wmhints = XGetWMHints(dpy, FW_W(fw)); set_focus_model(fw); return; } void setup_title_geometry( FvwmWindow *fw, window_style *pstyle) { int width; int offset; get_title_font_size_and_offset( fw, S_TITLE_DIR(SCF(*pstyle)), S_IS_LEFT_TITLE_ROTATED_CW(SCF(*pstyle)), S_IS_RIGHT_TITLE_ROTATED_CW(SCF(*pstyle)), S_IS_TOP_TITLE_ROTATED(SCF(*pstyle)), S_IS_BOTTOM_TITLE_ROTATED(SCF(*pstyle)), &width, &offset); fw->title_thickness = width; fw->title_text_offset = offset; fw->corner_width = fw->title_thickness + fw->boundary_width; if (!HAS_TITLE(fw)) { fw->title_thickness = 0; } return; } void setup_window_font( FvwmWindow *fw, window_style *pstyle, Bool do_destroy) { /* get rid of old font */ if (do_destroy) { destroy_window_font(fw); /* destroy_window_font resets the IS_WINDOW_FONT_LOADED flag */ } /* load new font */ if (!IS_WINDOW_FONT_LOADED(fw)) { if (S_HAS_WINDOW_FONT(SCF(*pstyle)) && SGET_WINDOW_FONT(*pstyle) && (fw->title_font = FlocaleLoadFont(dpy, SGET_WINDOW_FONT(*pstyle), "fvwm"))) { SET_USING_DEFAULT_WINDOW_FONT(fw, 0); } else { /* no explicit font or failed to load, use default font * instead */ fw->title_font = Scr.DefaultFont; SET_USING_DEFAULT_WINDOW_FONT(fw, 1); } SET_WINDOW_FONT_LOADED(fw, 1); } setup_title_geometry(fw, pstyle); return; } void setup_icon_font( FvwmWindow *fw, window_style *pstyle, Bool do_destroy) { int height = 0; if (IS_ICON_SUPPRESSED(fw) || HAS_NO_ICON_TITLE(fw)) { if (IS_ICON_FONT_LOADED(fw)) { destroy_icon_font(fw); /* destroy_icon_font resets the IS_ICON_FONT_LOADED * flag */ } return; } /* get rid of old font */ if (do_destroy && IS_ICON_FONT_LOADED(fw)) { destroy_icon_font(fw); /* destroy_icon_font resets the IS_ICON_FONT_LOADED flag */ } /* load new font */ if (!IS_ICON_FONT_LOADED(fw)) { if (S_HAS_ICON_FONT(SCF(*pstyle)) && SGET_ICON_FONT(*pstyle) && (fw->icon_font = FlocaleLoadFont(dpy, SGET_ICON_FONT(*pstyle), "fvwm"))) { SET_USING_DEFAULT_ICON_FONT(fw, 0); } else { /* no explicit font or failed to load, use default font * instead */ fw->icon_font = Scr.DefaultFont; SET_USING_DEFAULT_ICON_FONT(fw, 1); } SET_ICON_FONT_LOADED(fw, 1); } /* adjust y position of existing icons */ height = (IS_ICON_FONT_LOADED(fw)) ? fw->icon_font->height : 0; if (height) { resize_icon_title_height(fw, height - fw->icon_font->height); /* this repositions the icon even if the window is not * iconified */ DrawIconWindow(fw, True, True, False, False, NULL); } return; } void setup_style_and_decor( FvwmWindow *fw, window_style *pstyle, short *buttons) { /* first copy the static styles into the window struct */ memcpy(&(FW_COMMON_FLAGS(fw)), &(SCF(*pstyle)), sizeof(common_flags_t)); fw->wShaped = None; if (FShapesSupported) { int i; unsigned int u; Bool b; int boundingShaped; /* suppress compiler warnings w/o shape extension */ i = 0; u = 0; b = False; FShapeSelectInput(dpy, FW_W(fw), FShapeNotifyMask); if (FShapeQueryExtents( dpy, FW_W(fw), &boundingShaped, &i, &i, &u, &u, &b, &i, &i, &u, &u)) { fw->wShaped = boundingShaped; } } #ifdef USEDECOR /* search for a UseDecor tag in the style */ if (!IS_DECOR_CHANGED(fw)) { FvwmDecor *decor = &Scr.DefaultDecor; for (; decor; decor = decor->next) { if (StrEquals(SGET_DECOR_NAME(*pstyle), decor->tag)) { fw->decor = decor; break; } } } if (fw->decor == NULL) { fw->decor = &Scr.DefaultDecor; } #endif GetMwmHints(fw); GetOlHints(fw); fw->buttons = SIS_BUTTON_DISABLED(&pstyle->flags); SelectDecor(fw, pstyle, buttons); if (IS_TRANSIENT(fw) && !pstyle->flags.do_decorate_transient) { SET_HAS_HANDLES(fw, 0); SET_HAS_TITLE(fw, 0); } /* set boundary width to zero for shaped windows */ if (FHaveShapeExtension) { if (fw->wShaped) { set_window_border_size(fw, fw->unshaped_boundary_width); SET_HAS_NO_BORDER(fw, 1); SET_HAS_HANDLES(fw, 0); } } /****** window colors ******/ update_window_color_style(fw, pstyle); update_window_color_hi_style(fw, pstyle); /***** icons colorsets *****/ update_icon_title_cs_style(fw, pstyle); update_icon_title_cs_hi_style(fw, pstyle); update_icon_background_cs_style(fw, pstyle); /***** icons title/background parameters ****/ setup_icon_background_parameters(fw, pstyle); setup_icon_title_parameters(fw, pstyle); /****** some numeric values ******/ setup_numeric_vals(fw, pstyle); /****** GNOME style hints ******/ if (!S_DO_IGNORE_GNOME_HINTS(SCF(*pstyle))) { GNOME_GetStyle(fw, pstyle); } /* ConfigureNotify motion method */ if (SCR_MOTION_METHOD(&pstyle->flag_mask)) { CR_MOTION_METHOD(fw) = SCR_MOTION_METHOD(&pstyle->flags); } return; } void change_icon_boxes(FvwmWindow *fw, window_style *pstyle) { destroy_icon_boxes(fw); setup_icon_boxes(fw, pstyle); return; } void setup_frame_size_limits(FvwmWindow *fw, window_style *pstyle) { if (SHAS_MIN_WINDOW_SIZE(&pstyle->flags)) { fw->min_window_width = SGET_MIN_WINDOW_WIDTH(*pstyle); fw->min_window_height = SGET_MIN_WINDOW_HEIGHT(*pstyle); } else { fw->min_window_width = 0; fw->min_window_height = 0; } if (SHAS_MAX_WINDOW_SIZE(&pstyle->flags)) { fw->max_window_width = SGET_MAX_WINDOW_WIDTH(*pstyle); fw->max_window_height = SGET_MAX_WINDOW_HEIGHT(*pstyle); } else { fw->max_window_width = DEFAULT_MAX_MAX_WINDOW_WIDTH; fw->max_window_height = DEFAULT_MAX_MAX_WINDOW_HEIGHT; } return; } void setup_placement_penalty(FvwmWindow *fw, window_style *pstyle) { if (!SHAS_PLACEMENT_PENALTY(&pstyle->flags)) { pl_penalty_struct *p; p = SGET_PLACEMENT_PENALTY_PTR(*pstyle); *p = default_pl_penalty; } if (!SHAS_PLACEMENT_PERCENTAGE_PENALTY(&pstyle->flags)) { pl_percent_penalty_struct *p; p = SGET_PLACEMENT_PERCENTAGE_PENALTY_PTR(*pstyle); *p = default_pl_percent_penalty; } fw->pl_penalty = (*pstyle).pl_penalty; fw->pl_percent_penalty = (*pstyle).pl_percent_penalty; return; } void setup_frame_attributes( FvwmWindow *fw, window_style *pstyle) { XSetWindowAttributes xswa; /* Backing_store is controlled on the client, borders, title & buttons */ switch (pstyle->flags.use_backing_store) { case BACKINGSTORE_DEFAULT: xswa.backing_store = fw->attr_backup.backing_store; break; case BACKINGSTORE_ON: xswa.backing_store = Scr.use_backing_store; break; case BACKINGSTORE_OFF: default: xswa.backing_store = NotUseful; break; } /* parent_relative is applied to the frame and the parent */ xswa.background_pixmap = pstyle->flags.use_parent_relative ? ParentRelative : None; /* Save_under is only useful on the frame */ xswa.save_under = pstyle->flags.do_save_under ? Scr.flags.do_save_under : NotUseful; XChangeWindowAttributes(dpy, FW_W(fw), CWBackingStore, &xswa); XChangeWindowAttributes( dpy, FW_W_PARENT(fw), CWBackPixmap | CWBackingStore, &xswa); XChangeWindowAttributes( dpy, FW_W_FRAME(fw), CWBackPixmap | CWBackingStore | CWSaveUnder, &xswa); return; } void change_auxiliary_windows(FvwmWindow *fw, short buttons) { unsigned long valuemask_save = 0; XSetWindowAttributes attributes; get_default_window_attributes(fw, &valuemask_save, &attributes); change_title_window(fw, valuemask_save, &attributes); change_button_windows(fw, valuemask_save, &attributes, buttons); change_resize_handle_windows(fw); setup_frame_stacking(fw); XMapSubwindows (dpy, FW_W_FRAME(fw)); return; } void increase_icon_hint_count(FvwmWindow *fw) { if (fw->wmhints && (fw->wmhints->flags & (IconWindowHint | IconPixmapHint))) { switch (WAS_ICON_HINT_PROVIDED(fw)) { case ICON_HINT_NEVER: SET_WAS_ICON_HINT_PROVIDED(fw, ICON_HINT_ONCE); break; case ICON_HINT_ONCE: SET_WAS_ICON_HINT_PROVIDED(fw, ICON_HINT_MULTIPLE); break; case ICON_HINT_MULTIPLE: default: break; } ICON_DBG((stderr,"icon hint count++ (%d) '%s'\n", (int)WAS_ICON_HINT_PROVIDED(fw), fw->name.name)); } return; } void change_icon(FvwmWindow *fw, window_style *pstyle) { destroy_icon(fw); setup_icon(fw, pstyle); return; } void change_mini_icon(FvwmWindow *fw, window_style *pstyle) { FvwmPicture *old_mi = fw->mini_icon; destroy_mini_icon(fw); setup_mini_icon(fw, pstyle); broadcast_mini_icon(fw); if (old_mi != NULL && fw->mini_icon == 0) { /* this case is not handled in setup_mini_icon, so we must * broadcast here explicitly */ BroadcastFvwmPicture( M_MINI_ICON, FW_W(fw), FW_W_FRAME(fw), (unsigned long)fw, NULL, ""); } return; } void setup_focus_policy(FvwmWindow *fw) { focus_grab_buttons(fw); return; } Bool validate_transientfor(FvwmWindow *fw) { XWindowAttributes wa; FvwmWindow *cw; Window w; w = FW_W_TRANSIENTFOR(fw); if (w == None || w == FW_W(fw) || w == IS_EWMH_DESKTOP(w)) { FW_W_TRANSIENTFOR(fw) = Scr.Root; return False; } else if (XFindContext(dpy, w, FvwmContext, (caddr_t *)&cw) != XCNOENT) { if (cw == fw) { /* It's a transient of itself, ignore the hint */ FW_W_TRANSIENTFOR(fw) = Scr.Root; return False; } /* Check for transient loops */ while (XFindContext( dpy, FW_W_TRANSIENTFOR(cw), FvwmContext, (caddr_t *)&cw) != XCNOENT && IS_TRANSIENT(cw)) { if (FW_W_TRANSIENTFOR(cw) == FW_W(fw) || cw == fw) { /* loop detected, ignore the hint */ FW_W_TRANSIENTFOR(fw) = Scr.Root; return False; } } } else if (!XGetWindowAttributes(dpy, w, &wa) || wa.map_state != IsViewable) { /* transientfor does not exist or is not viewable or unmapped */ FW_W_TRANSIENTFOR(fw) = Scr.Root; return False; } return True; } Bool setup_transientfor(FvwmWindow *fw) { Bool rc; rc = XGetTransientForHint(dpy, FW_W(fw), &FW_W_TRANSIENTFOR(fw)); SET_TRANSIENT(fw, rc); if (rc == False) { FW_W_TRANSIENTFOR(fw) = Scr.Root; } validate_transientfor(fw); return rc; } /* * * Procedure: * AddWindow - add a new window to the fvwm list * */ FvwmWindow *AddWindow( const char **ret_initial_map_command, const exec_context_t *exc, FvwmWindow *ReuseWin, initial_window_options_t * win_opts) { /* new fvwm window structure */ register FvwmWindow *fw; FvwmWindow *tmp; /* mask for create windows */ unsigned long valuemask; /* attributes for create windows */ XSetWindowAttributes attributes; XWindowAttributes wattr; /* area for merged styles */ window_style style; /* used for faster access */ style_flags *sflags; short buttons; Bool used_sm = False; Bool do_resize_too = False; size_borders b; frame_move_resize_args mr_args; mwtsm_state_args state_args; Window w = exc->w.w; const exec_context_t *exc2; exec_context_changes_t ecc; /****** init window structure ******/ setup_window_structure(&tmp, w, ReuseWin); fw = tmp; /****** Make sure the client window still exists. We don't want to * leave an orphan frame window if it doesn't. Since we now have the * server grabbed, the window can't disappear later without having been * reparented, so we'll get a DestroyNotify for it. We won't have * gotten one for anything up to here, however. ******/ MyXGrabServer(dpy); if (XGetGeometry( dpy, w, &JunkRoot, &JunkX, &JunkY, (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight, (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth) == 0) { if (Scr.bo.do_display_new_window_names) { fvwm_msg(INFO, "AddWindow", "new window disappeared"); } free(fw); MyXUngrabServer(dpy); return NULL; } /****** window name ******/ setup_window_name(fw); setup_class_and_resource(fw); /****** style setup ******/ __add_window_handle_x_resources(fw); /* get merged styles */ lookup_style(fw, &style); sflags = SGET_FLAGS_POINTER(style); if (SIS_UNMANAGED(sflags)) { if (Scr.bo.do_display_new_window_names) { fvwm_msg( INFO, "AddWindow", "new window is unmanaged:\n" " name: %s\n" " icon name: (unknown)\n" " resource: %s\n" " class: %s", fw->name.name, fw->class.res_name, fw->class.res_class); } free_window_names(fw, True, True); if (fw->style_name) { free(fw->style_name); } free(fw); MyXUngrabServer(dpy); return AW_UNMANAGED; } /****** window attributes and hints ******/ setup_window_attr(fw, &wattr); setup_wm_hints(fw); /****** basic style and decor ******/ /* If the window is in the NoTitle list, or is a transient, dont * decorate it. If its a transient, and DecorateTransients was * specified, decorate anyway. */ setup_transientfor(fw); if (win_opts->flags.is_menu) { SET_TEAR_OFF_MENU(fw, 1); } fw->decor = NULL; setup_style_and_decor(fw, &style, &buttons); /****** fonts ******/ setup_window_font(fw, &style, False); setup_icon_font(fw, &style, False); /***** visible window name ****/ setup_visible_name(fw, False); EWMH_SetVisibleName(fw, False); if (Scr.bo.do_display_new_window_names) { fvwm_msg( INFO, "AddWindow", "new window:\n" " name: %s\n" " icon name: %s\n" " resource: %s\n" " class: %s", fw->name.name, (fw->icon_name.name == NULL) ? "(unknown)" : fw->icon_name.name, fw->class.res_name, fw->class.res_class); } /****** InitialMapCommand ******/ *ret_initial_map_command = (style.flags.has_initial_map_command_string) ? SGET_INITIAL_MAP_COMMAND_STRING(style) : NULL; /****** state setup ******/ setup_icon_boxes(fw, &style); SET_ICONIFIED(fw, 0); SET_ICON_UNMAPPED(fw, 0); SET_MAXIMIZED(fw, 0); /* * Reparenting generates an UnmapNotify event, followed by a MapNotify. * Set the map state to 0 to prevent a transition back to * WithdrawnState in HandleUnmapNotify. Map state gets set corrected * again in HandleMapNotify. */ SET_MAPPED(fw, 0); /****** window list and stack ring ******/ /* add the window to the end of the fvwm list */ fw->next = Scr.FvwmRoot.next; fw->prev = &Scr.FvwmRoot; while (fw->next != NULL) { fw->prev = fw->next; fw->next = fw->next->next; } /* fw->prev points to the last window in the list, fw->next is * NULL. Now fix the last window to point to fw */ fw->prev->next = fw; /* * RBW - 11/13/1998 - add it into the stacking order chain also. * This chain is anchored at both ends on Scr.FvwmRoot, there are * no null pointers. */ add_window_to_stack_ring_after(fw, &Scr.FvwmRoot); /****** calculate frame size ******/ fw->hints.win_gravity = NorthWestGravity; GetWindowSizeHints(fw); /****** border width ******/ XSetWindowBorderWidth(dpy, FW_W(fw), 0); /****** icon size limits ******/ setup_icon_size_limits(fw, &style); /***** placement penalities *****/ setup_placement_penalty(fw, &style); /* * MatchWinToSM changes fw->attr and the stacking order. * Thus it is important have this call *after* PlaceWindow and the * stacking order initialization. */ get_window_borders(fw, &b); memset(&state_args, 0, sizeof(state_args)); used_sm = MatchWinToSM(fw, &state_args, win_opts); if (used_sm) { /* read the requested absolute geometry */ gravity_translate_to_northwest_geometry_no_bw( fw->hints.win_gravity, fw, &fw->g.normal, &fw->g.normal); gravity_resize( fw->hints.win_gravity, &fw->g.normal, b.total_size.width, b.total_size.height); fw->g.frame = fw->g.normal; fw->g.frame.x -= Scr.Vx; fw->g.frame.y -= Scr.Vy; /****** calculate frame size ******/ setup_frame_size_limits(fw, &style); constrain_size( fw, NULL, &fw->g.frame.width, &fw->g.frame.height, 0, 0, 0); /****** maximize ******/ if (state_args.do_max) { SET_MAXIMIZED(fw, 1); constrain_size( fw, NULL, &fw->g.max.width, &fw->g.max.height, 0, 0, CS_UPDATE_MAX_DEFECT); get_relative_geometry(&fw->g.frame, &fw->g.max); } else { get_relative_geometry(&fw->g.frame, &fw->g.normal); } } else { rectangle attr_g; if (IS_SHADED(fw)) { state_args.do_shade = 1; state_args.used_title_dir_for_shading = USED_TITLE_DIR_FOR_SHADING(fw); state_args.shade_dir = SHADED_DIR(fw); SET_SHADED(fw, 0); } /* Tentative size estimate */ fw->g.frame.width = wattr.width + b.total_size.width; fw->g.frame.height = wattr.height + b.total_size.height; /****** calculate frame size ******/ setup_frame_size_limits(fw, &style); /****** layer ******/ setup_layer(fw, &style); /****** window placement ******/ attr_g.x = wattr.x; attr_g.y = wattr.y; attr_g.width = wattr.width; attr_g.height = wattr.height; do_resize_too = setup_window_placement( fw, &style, &attr_g, win_opts, PLACE_INITIAL); wattr.x = attr_g.x; wattr.y = attr_g.y; /* set up geometry */ fw->g.frame.x = wattr.x; fw->g.frame.y = wattr.y; fw->g.frame.width = wattr.width + b.total_size.width; fw->g.frame.height = wattr.height + b.total_size.height; gravity_constrain_size( fw->hints.win_gravity, fw, &fw->g.frame, 0); update_absolute_geometry(fw); } /****** auxiliary window setup ******/ setup_auxiliary_windows(fw, True, buttons); /****** 'backing store' and 'save under' window setup ******/ setup_frame_attributes(fw, &style); /****** reparent the window ******/ XReparentWindow(dpy, FW_W(fw), FW_W_PARENT(fw), 0, 0); /****** select events ******/ valuemask = CWEventMask | CWDontPropagate; if (IS_TEAR_OFF_MENU(fw)) { attributes.event_mask = XEVMASK_TEAR_OFF_MENUW; } else { attributes.event_mask = XEVMASK_CLIENTW; } attributes.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask; XChangeWindowAttributes(dpy, FW_W(fw), valuemask, &attributes); /****** make sure the window is not destroyed when fvwm dies ******/ if (!IS_TEAR_OFF_MENU(fw)) { /* menus were created by fvwm itself, don't add them to the * save set */ XAddToSaveSet(dpy, FW_W(fw)); } /****** now we can sefely ungrab the server ******/ MyXUngrabServer(dpy); /* need to set up the mini icon before drawing */ if (FMiniIconsSupported) { setup_mini_icon(fw, &style); } /****** arrange the frame ******/ if (is_resizing_event_pending(fw) == True) { SET_FORCE_NEXT_CR(fw, 1); SET_FORCE_NEXT_PN(fw, 1); mr_args = frame_create_move_resize_args( fw, FRAME_MR_FORCE_SETUP_NO_W | FRAME_MR_DONT_DRAW, NULL, &fw->g.frame, 0, DIR_NONE); } else { mr_args = frame_create_move_resize_args( fw, FRAME_MR_FORCE_SETUP | FRAME_MR_DONT_DRAW, NULL, &fw->g.frame, 0, DIR_NONE); } frame_move_resize(fw, mr_args); frame_free_move_resize_args(fw, mr_args); /* draw later */ SET_WAS_NEVER_DRAWN(fw, 1); /****** grab keys and buttons ******/ setup_key_and_button_grabs(fw); /****** inform modules of new window ******/ BroadcastConfig(M_ADD_WINDOW,fw); BroadcastWindowIconNames(fw, True, False); /****** place the window in the stack ring ******/ if (!position_new_window_in_stack_ring(fw, SDO_START_LOWERED(sflags))) { XWindowChanges xwc; xwc.sibling = FW_W_FRAME(get_next_window_in_stack_ring(fw)); xwc.stack_mode = Above; XConfigureWindow( dpy, FW_W_FRAME(fw), CWSibling|CWStackMode, &xwc); } /* these are sent and broadcast before res_{class,name} for the benefit * of FvwmIconBox which can't handle M_ICON_FILE after M_RES_NAME */ /****** icon and mini icon ******/ /* migo (20-Jan-2000): the logic is to unset this flag on NULL values */ SET_WAS_ICON_NAME_PROVIDED(fw, 1); setup_icon(fw, &style); if (FMiniIconsSupported) { broadcast_mini_icon(fw); } BroadcastName(M_RES_CLASS,FW_W(fw),FW_W_FRAME(fw), (unsigned long)fw,fw->class.res_class); BroadcastName(M_RES_NAME,FW_W(fw),FW_W_FRAME(fw), (unsigned long)fw,fw->class.res_name); /****** stick window ******/ if (!(fw->hints.flags & USPosition) || used_sm) { int stick_page; int stick_desk; stick_page = is_window_sticky_across_pages(fw); stick_desk = is_window_sticky_across_desks(fw); if ((stick_page && !IsRectangleOnThisPage(&fw->g.frame, Scr.CurrentDesk)) || (stick_desk && fw->Desk != Scr.CurrentDesk)) { /* If it's sticky and the user didn't ask for an * explicit position, force it on screen now. Don't do * that with USPosition because we have to assume the * user knows what (s)he is doing. This is necessary * e.g. if we want a sticky 'panel' in FvwmButtons but * don't want to see when it's mapped in the void. */ ecc.w.fw = fw; ecc.w.w = FW_W_FRAME(fw); ecc.w.wcontext = C_FRAME; exc2 = exc_clone_context( exc, &ecc, ECC_FW | ECC_W | ECC_WCONTEXT); SET_STICKY_ACROSS_PAGES(fw, 0); SET_STICKY_ACROSS_DESKS(fw, 0); handle_stick( NULL, exc2, "", stick_page, stick_desk, 1, 0); exc_destroy_context(exc2); } } /****** resize window ******/ if (do_resize_too) { XEvent e; memset(&e, 0, sizeof(e)); FWarpPointer( dpy, Scr.Root, Scr.Root, 0, 0, Scr.MyDisplayWidth, Scr.MyDisplayHeight, fw->g.frame.x + (fw->g.frame.width>>1), fw->g.frame.y + (fw->g.frame.height>>1)); e.xany.type = ButtonPress; e.xbutton.button = 1; e.xbutton.state = Button1Mask; e.xbutton.x_root = fw->g.frame.x + (fw->g.frame.width>>1); e.xbutton.y_root = fw->g.frame.y + (fw->g.frame.height>>1); e.xbutton.x = (fw->g.frame.width>>1); e.xbutton.y = (fw->g.frame.height>>1); e.xbutton.subwindow = None; e.xany.window = FW_W(fw); fev_fake_event(&e); ecc.x.etrigger = &e; ecc.w.fw = fw; ecc.w.wcontext = C_WINDOW; exc2 = exc_clone_context( exc, &ecc, ECC_ETRIGGER | ECC_FW | ECC_WCONTEXT); CMD_Resize(NULL, exc2, ""); exc_destroy_context(exc2); } /****** window colormap ******/ ReInstallActiveColormap(); /****** ewmh setup *******/ EWMH_WindowInit(fw); /****** gnome setup ******/ /* set GNOME hints on the window from flags set on fw */ GNOME_SetHints(fw); GNOME_SetLayer(fw); GNOME_SetDesk(fw); GNOME_SetWinArea(fw); /****** windowshade ******/ if (state_args.do_shade || SDO_START_SHADED(sflags)) { rectangle big_g; rectangle new_g; frame_move_resize_args mr_args; if (state_args.used_title_dir_for_shading) { state_args.shade_dir = GET_TITLE_DIR(fw); } /* If we've set a style for StartShaded, ensure we override * the state for it here. -- TA. */ if (SDO_START_SHADED(sflags) && !state_args.do_shade) { state_args.shade_dir = SGET_STARTS_SHADED_DIR(style); } big_g = (IS_MAXIMIZED(fw)) ? fw->g.max : fw->g.frame; new_g = big_g; get_shaded_geometry_with_dir( fw, &new_g, &new_g, state_args.shade_dir); mr_args = frame_create_move_resize_args( fw, FRAME_MR_SHRINK | FRAME_MR_DONT_DRAW, &big_g, &new_g, 0, state_args.shade_dir); frame_move_resize(fw, mr_args); SET_SHADED(fw, 1); SET_SHADED_DIR(fw, state_args.shade_dir); frame_free_move_resize_args(fw, mr_args); } if (!IS_SHADED(fw) && !IS_ICONIFIED(fw)) { /* TK always wants some special treatment: If the window is * simply mapped, the tk menus come up at funny Y coordinates. * Tell it it's geometry *again* to work around this problem. */ SendConfigureNotify( fw, fw->g.frame.x, fw->g.frame.y, fw->g.frame.width, fw->g.frame.height, 0, False); } if ( HAS_EWMH_INIT_MAXVERT_STATE(fw) == EWMH_STATE_HAS_HINT || HAS_EWMH_INIT_MAXHORIZ_STATE(fw) == EWMH_STATE_HAS_HINT) { int h; int v; char cmd[256]; if ( is_function_allowed( F_MAXIMIZE, NULL, fw, RQORIG_PROGRAM_US, False)) { h = (HAS_EWMH_INIT_MAXHORIZ_STATE(fw) == EWMH_STATE_HAS_HINT) ? 100 : 0; v = (HAS_EWMH_INIT_MAXVERT_STATE(fw) == EWMH_STATE_HAS_HINT) ? 100 : 0; sprintf(cmd,"Maximize on %i %i", h, v); execute_function_override_window( NULL, NULL, cmd, 0, fw); } } if (HAS_EWMH_INIT_FULLSCREEN_STATE(fw) == EWMH_STATE_HAS_HINT) { EWMH_fullscreen(fw); } if (!XGetGeometry( dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY, (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight, (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth)) { /* The window has disappeared somehow. For some reason we do * not always get a DestroyNotify on the window, so make sure * it is destroyed. */ destroy_window(fw); fw = NULL; } return fw; } /* * * Procedure: * FetchWMProtocols - finds out which protocols the window supports * * Inputs: * tmp - the fvwm window structure to use * */ void FetchWmProtocols(FvwmWindow *tmp) { Atom *protocols = NULL, *ap; unsigned long *l_protocols; int i, n; Atom atype; int aformat; unsigned long bytes_remain,nitems; if (tmp == NULL) { return; } /* First, try the Xlib function to read the protocols. * This is what Twm uses. */ if (XGetWMProtocols (dpy, FW_W(tmp), &protocols, &n)) { for (i = 0, ap = protocols; i < n; i++, ap++) { if (*ap == (Atom)_XA_WM_TAKE_FOCUS) { SET_WM_TAKES_FOCUS(tmp, 1); set_focus_model(tmp); } if (*ap == (Atom)_XA_WM_DELETE_WINDOW) { SET_WM_DELETES_WINDOW(tmp, 1); } } if (protocols) { XFree((char *)protocols); } } else { /* Next, read it the hard way. mosaic from Coreldraw needs to * be read in this way. */ if ((XGetWindowProperty( dpy, FW_W(tmp), _XA_WM_PROTOCOLS, 0L, 10L, False, _XA_WM_PROTOCOLS, &atype, &aformat, &nitems, &bytes_remain, (unsigned char **)&l_protocols)) == Success) { for (i = 0; i < nitems; i++) { ap = &(l_protocols[i]); if (*ap == (Atom)_XA_WM_TAKE_FOCUS) { SET_WM_TAKES_FOCUS(tmp, 1); set_focus_model(tmp); } if (*ap == (Atom)_XA_WM_DELETE_WINDOW) { SET_WM_DELETES_WINDOW(tmp, 1); } } if (protocols) { XFree((char *)protocols); } } } return; } /* * * Procedure: * GetWindowSizeHints - gets application supplied size info * * Inputs: * tmp - the fvwm window structure to use * */ void GetWindowSizeHints(FvwmWindow *fw) { long supplied = 0; char *broken_cause =""; XSizeHints orig_hints; Status rc; fw->orig_hints.width_inc = 1; fw->orig_hints.height_inc = 1; rc = XGetWMNormalHints(dpy, FW_W(fw), &orig_hints, &supplied); if (rc == 0) { fw->hints.flags = 0; memset(&orig_hints, 0, sizeof(orig_hints)); } else { fw->hints = orig_hints; if (fw->hints.flags & PResizeInc) { fw->orig_hints.width_inc = fw->hints.width_inc; fw->orig_hints.height_inc = fw->hints.height_inc; } if (HAS_OVERRIDE_SIZE_HINTS(fw)) { /* ignore the WMNormal hints */ fw->hints.flags &= ~(PMinSize | PMaxSize | PResizeInc); fw->hints.min_width = 0; fw->hints.min_height = 0; fw->hints.max_width = 0; fw->hints.max_height = 0; fw->hints.width_inc = 1; fw->hints.height_inc = 1; } } /* Beat up our copy of the hints, so that all important field are * filled in! */ if (fw->hints.flags & PResizeInc) { SET_SIZE_INC_SET(fw, 1); if (fw->hints.width_inc <= 0) { if (fw->hints.width_inc < 0 || (fw->hints.width_inc == 0 && (fw->hints.flags & PMinSize) && (fw->hints.flags & PMaxSize) && fw->hints.min_width != fw->hints.max_width)) { broken_cause = "width_inc"; } fw->hints.width_inc = 1; SET_SIZE_INC_SET(fw, 0); } if (fw->hints.height_inc <= 0) { if (fw->hints.height_inc < 0 || (fw->hints.height_inc == 0 && (fw->hints.flags & PMinSize) && (fw->hints.flags & PMaxSize) && fw->hints.min_height != fw->hints.max_height)) { if (!*broken_cause) { broken_cause = "height_inc"; } } fw->hints.height_inc = 1; SET_SIZE_INC_SET(fw, 0); } } else { SET_SIZE_INC_SET(fw, 0); fw->hints.width_inc = 1; fw->hints.height_inc = 1; } if (fw->hints.flags & PMinSize) { if (fw->hints.min_width < 0 && !*broken_cause) { broken_cause = "min_width"; } if (fw->hints.min_height < 0 && !*broken_cause) { broken_cause = "min_height"; } } else { if (fw->hints.flags & PBaseSize) { fw->hints.min_width = fw->hints.base_width; fw->hints.min_height = fw->hints.base_height; } else { fw->hints.min_width = 1; fw->hints.min_height = 1; } } if (fw->hints.min_width <= 0) { fw->hints.min_width = 1; } if (fw->hints.min_height <= 0) { fw->hints.min_height = 1; } if (fw->hints.flags & PMaxSize) { if (fw->hints.max_width < fw->hints.min_width) { fw->hints.max_width = DEFAULT_MAX_MAX_WINDOW_WIDTH; if (!*broken_cause) { broken_cause = "max_width"; } } if (fw->hints.max_height < fw->hints.min_height) { fw->hints.max_height = DEFAULT_MAX_MAX_WINDOW_HEIGHT; if (!*broken_cause) { broken_cause = "max_height"; } } } else { fw->hints.max_width = DEFAULT_MAX_MAX_WINDOW_WIDTH; fw->hints.max_height = DEFAULT_MAX_MAX_WINDOW_HEIGHT; } /* * ICCCM says that PMinSize is the default if no PBaseSize is given, * and vice-versa. */ if (fw->hints.flags & PBaseSize) { if (fw->hints.base_width < 0) { fw->hints.base_width = 0; if (!*broken_cause) { broken_cause = "base_width"; } } if (fw->hints.base_height < 0) { fw->hints.base_height = 0; if (!*broken_cause) { broken_cause = "base_height"; } } if ((fw->hints.base_width > fw->hints.min_width) || (fw->hints.base_height > fw->hints.min_height)) { /* In this case, doing the aspect ratio calculation for window_size - base_size as prescribed by the ICCCM is going to fail. Resetting the flag disables the use of base_size in aspect ratio calculation while it is still used for grid sizing. */ fw->hints.flags &= ~PBaseSize; #if 0 /* Keep silent about this, since the Xlib manual * actually recommends making min <= base <= max ! */ broken_cause = ""; #endif } } else { if (fw->hints.flags & PMinSize) { fw->hints.base_width = fw->hints.min_width; fw->hints.base_height = fw->hints.min_height; } else { fw->hints.base_width = 0; fw->hints.base_height = 0; } } if (!(fw->hints.flags & PWinGravity)) { fw->hints.win_gravity = NorthWestGravity; } if ((fw->hints.flags & PMaxSize) && ((fw->hints.flags & PMinSize) || (fw->hints.flags & PBaseSize))) { if (fw->hints.max_width < fw->hints.base_width) { fw->hints.max_width = DEFAULT_MAX_MAX_WINDOW_WIDTH; if (!*broken_cause) { broken_cause = "max_width"; } } if (fw->hints.max_height < fw->hints.base_height) { fw->hints.max_height = DEFAULT_MAX_MAX_WINDOW_HEIGHT; if (!*broken_cause) { broken_cause = "max_height"; } } } if (fw->hints.flags & PAspect) { /* ** check to make sure min/max aspect ratios look valid */ #define maxAspectX fw->hints.max_aspect.x #define maxAspectY fw->hints.max_aspect.y #define minAspectX fw->hints.min_aspect.x #define minAspectY fw->hints.min_aspect.y /* ** The math looks like this: ** ** minAspectX maxAspectX ** ---------- <= ---------- ** minAspectY maxAspectY ** ** If that is multiplied out, this must be satisfied: ** ** minAspectX * maxAspectY <= maxAspectX * minAspectY ** ** So, what to do if this isn't met? Ignoring it entirely ** seems safest. ** */ /* We also ignore people who put negative entries into * their aspect ratios. They deserve it. * * We cast to double here, since the values may be large. */ if ((maxAspectX < 0) || (maxAspectY < 0) || (minAspectX < 0) || (minAspectY < 0) || (((double)minAspectX * (double)maxAspectY) > ((double)maxAspectX * (double)minAspectY))) { if (!*broken_cause) { broken_cause = "aspect ratio"; } fw->hints.flags &= ~PAspect; fvwm_msg( WARN, "GetWindowSizeHints", "The applicaton window (window id %#lx)\n" " \"%s\" has broken aspect ratio: " "%d/%d - %d/%d\n" " fvwm is ignoring this aspect ratio. ", FW_W(fw), fw->name.name, minAspectX, minAspectY, maxAspectX, maxAspectY); fvwm_msg_report_app(); } else { /* protect against overflow */ if ((maxAspectX > 65536) || (maxAspectY > 65536)) { double ratio = (double) maxAspectX / (double) maxAspectY; if (ratio > 1.0) { maxAspectX = 65536; maxAspectY = 65536 / ratio; } else { maxAspectX = 65536 * ratio; maxAspectY = 65536; } } if ((minAspectX > 65536) || (minAspectY > 65536)) { double ratio = (double) minAspectX / (double) minAspectY; if (ratio > 1.0) { minAspectX = 65536; minAspectY = 65536 / ratio; } else { minAspectX = 65536 * ratio; minAspectY = 65536; } } } #undef maxAspectX #undef maxAspectY #undef minAspectX #undef minAspectY } if (*broken_cause != 0) { fvwm_msg( WARN, "GetWindowSizeHints", "The application window (id %#lx)\n" " \"%s\" has broken size hints (%s).\n" " fvwm is ignoring those hints. " " hint override = %d, flags = %lx\n" " min_width = %d, min_height = %d, " "max_width = %d, max_height = %d\n" " width_inc = %d, height_inc = %d\n" " min_aspect = %d/%d, max_aspect = %d/%d\n" " base_width = %d, base_height = %d\n" " win_gravity = %d\n", FW_W(fw), fw->name.name, broken_cause, HAS_OVERRIDE_SIZE_HINTS(fw), orig_hints.flags, orig_hints.min_width, orig_hints.min_height, orig_hints.max_width, orig_hints.max_height, orig_hints.width_inc, orig_hints.height_inc, orig_hints.min_aspect.x, orig_hints.min_aspect.y, orig_hints.max_aspect.x, orig_hints.max_aspect.y, orig_hints.base_width, orig_hints.base_height, orig_hints.win_gravity); fvwm_msg_report_app(); } return; } /* * * Releases dynamically allocated space used to store window/icon names * */ void free_window_names(FvwmWindow *fw, Bool nukename, Bool nukeicon) { if (!fw) { return; } if (nukename) { if (fw->visible_name && fw->visible_name != fw->name.name && fw->visible_name != NoName) { free(fw->visible_name); } fw->visible_name = NoName; if (fw->name.name) { if (fw->icon_name.name == fw->name.name) { fw->icon_name.name = NoName; } if (fw->visible_icon_name == fw->name.name) { fw->visible_icon_name = fw->icon_name.name; } if (fw->name.name != NoName) { FlocaleFreeNameProperty(&(fw->name)); fw->visible_name = NULL; } } } if (nukeicon) { if (fw->visible_icon_name && fw->visible_icon_name != fw->name.name && fw->visible_icon_name != fw->icon_name.name && fw->visible_icon_name != NoName) { free(fw->visible_icon_name); } fw->visible_icon_name = NoName; if (fw->icon_name.name) { if ((fw->icon_name.name != fw->name.name) && fw->icon_name.name != NoName) { FlocaleFreeNameProperty(&(fw->icon_name)); fw->visible_icon_name = NULL; } } } return; } /* * * Handles destruction of a window * */ void destroy_window(FvwmWindow *fw) { /* Warning, this is also called by HandleUnmapNotify; if it ever needs * to look at the event, HandleUnmapNotify will have to mash the * UnmapNotify into a DestroyNotify. */ if (!fw) { return; } /* remove window style */ if (!IS_SCHEDULED_FOR_DESTROY(fw) && !DO_REUSE_DESTROYED(fw)) { style_id_t s_id; memset(&s_id, 0, sizeof(style_id_t)); SID_SET_WINDOW_ID(s_id, (XID)FW_W(fw)); SID_SET_HAS_WINDOW_ID(s_id, True); style_destroy_style(s_id); } /****** remove from window list ******/ /* if the window is sheduled fro destroy the window has been already * removed from list */ if (!IS_SCHEDULED_FOR_DESTROY(fw)) { /* first, remove the window from the list of all windows! */ if (fw->prev != NULL) { fw->prev->next = fw->next; } if (fw->next != NULL) { fw->next->prev = fw->prev; } fw->next = NULL; fw->prev = NULL; /****** also remove it from the stack ring ******/ /* * RBW - 11/13/1998 - new: have to unhook the stacking order chain also. There's always a prev and next, since this is a ring anchored on Scr.FvwmRoot */ remove_window_from_stack_ring(fw); } /****** check if we have to delay window destruction ******/ if ((Scr.flags.is_executing_complex_function || Scr.flags.is_executing_menu_function) && !DO_REUSE_DESTROYED(fw)) { if (IS_SCHEDULED_FOR_DESTROY(fw)) { return; } /* mark window for destruction */ SET_SCHEDULED_FOR_DESTROY(fw, 1); Scr.flags.is_window_scheduled_for_destroy = 1; /* this is necessary in case the application destroys the * client window and a new window is created with the same * window id */ delete_client_context(fw); XFlush(dpy); /* unmap the the window to fake that it was already removed */ if (IS_ICONIFIED(fw)) { if (FW_W_ICON_TITLE(fw)) { XUnmapWindow(dpy, FW_W_ICON_TITLE(fw)); } if (FW_W_ICON_PIXMAP(fw) != None) { XUnmapWindow(dpy, FW_W_ICON_PIXMAP(fw)); } } else { XUnmapWindow(dpy, FW_W_FRAME(fw)); } adjust_fvwm_internal_windows(fw); BroadcastPacket( M_DESTROY_WINDOW, 3, (long)FW_W(fw), (long)FW_W_FRAME(fw), (unsigned long)fw); EWMH_DestroyWindow(fw); focus_grab_buttons_on_layer(fw->layer); Scr.FWScheduledForDestroy = flist_append_obj( Scr.FWScheduledForDestroy, fw); return; } /****** unmap the frame ******/ XUnmapWindow(dpy, FW_W_FRAME(fw)); XFlush(dpy); /* already done above? */ if (!IS_SCHEDULED_FOR_DESTROY(fw)) { SET_SCHEDULED_FOR_DESTROY(fw, 1); adjust_fvwm_internal_windows(fw); BroadcastPacket( M_DESTROY_WINDOW, 3, (long)FW_W(fw), (long)FW_W_FRAME(fw), (unsigned long)fw); EWMH_DestroyWindow(fw); } focus_grab_buttons_on_layer(fw->layer); /****** destroy auxiliary windows ******/ destroy_auxiliary_windows(fw, True); /****** destroy icon ******/ destroy_icon_boxes(fw); destroy_icon(fw); /****** destroy mini icon ******/ #ifdef MINI_ICON destroy_mini_icon(fw); #endif /****** free strings ******/ free_window_names(fw, True, True); if (fw->style_name) { free(fw->style_name); fw->style_name = NULL; } if (fw->class.res_name && fw->class.res_name != NoResource) { XFree ((char *)fw->class.res_name); fw->class.res_name = NoResource; } if (fw->class.res_class && fw->class.res_class != NoClass) { XFree ((char *)fw->class.res_class); fw->class.res_class = NoClass; } if (fw->mwm_hints) { XFree((char *)fw->mwm_hints); fw->mwm_hints = NULL; } /****** free fonts ******/ destroy_window_font(fw); destroy_icon_font(fw); /****** free wmhints ******/ if (fw->wmhints) { XFree ((char *)fw->wmhints); fw->wmhints = NULL; } /****** free colormap windows ******/ if (fw->cmap_windows != (Window *)NULL) { XFree((void *)fw->cmap_windows); fw->cmap_windows = NULL; } /****** throw away the structure ******/ /* Recapture reuses this struct, so don't free it. */ if (!DO_REUSE_DESTROYED(fw)) { free((char *)fw); } /****** cleanup ******/ XFlush(dpy); return; } /* * * Procedure: * RestoreWithdrawnLocation * * Puts windows back where they were before fvwm took over * */ void RestoreWithdrawnLocation( FvwmWindow *fw, Bool is_restart_or_recapture, Window parent) { int w2,h2; unsigned int mask; XWindowChanges xwc; rectangle naked_g; rectangle unshaded_g; XSetWindowAttributes xswa; if (!fw) { return; } /* always get the latest size hints in case the application changed * the gravity and we do not yet know about it */ XSync(dpy, 0); GetWindowSizeHints(fw); SET_HAS_NEW_WM_NORMAL_HINTS(fw, 0); get_unshaded_geometry(fw, &unshaded_g); gravity_get_naked_geometry( fw->hints.win_gravity, fw, &naked_g, &unshaded_g); gravity_translate_to_northwest_geometry( fw->hints.win_gravity, fw, &naked_g, &naked_g); xwc.x = naked_g.x; xwc.y = naked_g.y; xwc.width = naked_g.width; xwc.height = naked_g.height; xwc.border_width = fw->attr_backup.border_width; mask = (CWX | CWY | CWWidth | CWHeight | CWBorderWidth); /* We can not assume that the window is currently on the screen. * Although this is normally the case, it is not always true. The * most common example is when the user does something in an * application which will, after some amount of computational delay, * cause the window to be unmapped, but then switches screens before * this happens. The XTranslateCoordinates call above will set the * window coordinates to either be larger than the screen, or negative. * This will result in the window being placed in odd, or even * unviewable locations when the window is remapped. The following * code forces the "relative" location to be within the bounds of the * display. * * gpw -- 11/11/93 * * Unfortunately, this does horrendous things during re-starts, * hence the "if (restart)" clause (RN) * * Also, fixed so that it only does this stuff if a window is more than * half off the screen. (RN) */ if (!is_restart_or_recapture) { /* Don't mess with it if its partially on the screen now */ if (unshaded_g.x < 0 || unshaded_g.y < 0 || unshaded_g.x >= Scr.MyDisplayWidth || unshaded_g.y >= Scr.MyDisplayHeight) { w2 = (unshaded_g.width >> 1); h2 = (unshaded_g.height >> 1); if ( xwc.x < -w2 || xwc.x > Scr.MyDisplayWidth - w2) { xwc.x = xwc.x % Scr.MyDisplayWidth; if (xwc.x < -w2) { xwc.x += Scr.MyDisplayWidth; } } if (xwc.y < -h2 || xwc.y > Scr.MyDisplayHeight - h2) { xwc.y = xwc.y % Scr.MyDisplayHeight; if (xwc.y < -h2) { xwc.y += Scr.MyDisplayHeight; } } } } /* restore initial backing store setting on window */ xswa.backing_store = fw->attr_backup.backing_store; XChangeWindowAttributes(dpy, FW_W(fw), CWBackingStore, &xswa); /* reparent to root window */ XReparentWindow( dpy, FW_W(fw), (parent == None) ? Scr.Root : parent, xwc.x, xwc.y); if (IS_ICONIFIED(fw) && !IS_ICON_SUPPRESSED(fw)) { if (FW_W_ICON_TITLE(fw)) { XUnmapWindow(dpy, FW_W_ICON_TITLE(fw)); } if (FW_W_ICON_PIXMAP(fw)) { XUnmapWindow(dpy, FW_W_ICON_PIXMAP(fw)); } } XConfigureWindow(dpy, FW_W(fw), mask, &xwc); if (!is_restart_or_recapture) { /* must be initial capture */ XFlush(dpy); } return; } /* * * Procedure: * Reborder - Removes fvwm border windows * */ void Reborder(void) { FvwmWindow *fw; /* put a border back around all windows */ MyXGrabServer (dpy); /* force reinstall */ InstallWindowColormaps (&Scr.FvwmRoot); /* RBW - 05/15/1998 * Grab the last window and work backwards: preserve stacking order on * restart. */ for (fw = get_prev_window_in_stack_ring(&Scr.FvwmRoot); fw != &Scr.FvwmRoot; fw = get_prev_window_in_stack_ring(fw)) { if (!IS_ICONIFIED(fw) && Scr.CurrentDesk != fw->Desk) { XMapWindow(dpy, FW_W(fw)); SetMapStateProp(fw, NormalState); } RestoreWithdrawnLocation (fw, True, Scr.Root); XUnmapWindow(dpy,FW_W_FRAME(fw)); XDestroyWindow(dpy,FW_W_FRAME(fw)); } MyXUngrabServer (dpy); FOCUS_RESET(); XFlush(dpy); return; } void CaptureAllWindows(const exec_context_t *exc, Bool is_recapture) { int i,j; unsigned int nchildren; Window root, parent, *children; initial_window_options_t win_opts; FvwmWindow *fw; MyXGrabServer(dpy); if (!XQueryTree(dpy, Scr.Root, &root, &parent, &children, &nchildren)) { MyXUngrabServer(dpy); return; } memset(&win_opts, 0, sizeof(win_opts)); win_opts.flags.do_override_ppos = 1; win_opts.flags.is_recapture = 1; if (!(Scr.flags.are_windows_captured)) /* initial capture? */ { evh_args_t ea; exec_context_changes_t ecc; XEvent e; /* weed out icon windows */ for (i = 0; i < nchildren; i++) { if (children[i]) { XWMHints *wmhintsp = XGetWMHints( dpy, children[i]); if (wmhintsp && wmhintsp->flags & IconWindowHint) { for (j = 0; j < nchildren; j++) { if (children[j] == wmhintsp->icon_window) { children[j] = None; break; } } } if (wmhintsp) { XFree ((char *) wmhintsp); } } } /* map all of the non-override, non-icon windows */ e.type = MapRequest; ecc.x.etrigger = &e; for (i = 0; i < nchildren; i++) { if (children[i] && MappedNotOverride(children[i], &win_opts)) { XUnmapWindow(dpy, children[i]); e.xmaprequest.window = children[i]; e.xmaprequest.parent = Scr.Root; ecc.w.fw = NULL; ecc.w.w = children[i]; ecc.w.wcontext = C_ROOT; ea.exc = exc_clone_context( exc, &ecc, ECC_ETRIGGER | ECC_FW | ECC_W | ECC_WCONTEXT); HandleMapRequestKeepRaised( &ea, None, NULL, &win_opts); exc_destroy_context(ea.exc); } } Scr.flags.are_windows_captured = 1; } else /* must be recapture */ { Window keep_on_top_win; Window parent_win; Window focus_w; FvwmWindow *t; t = get_focus_window(); focus_w = (t) ? FW_W(t) : None; hide_screen(True, &keep_on_top_win, &parent_win); /* reborder all windows */ for (i=0;inext) { ; } if (t) { SetFocusWindow(t, True, FOCUS_SET_FORCE); } } } if (nchildren > 0) { XFree((char *)children); } MyXUngrabServer(dpy); return; } /* ---------------------------- builtin commands --------------------------- */ void CMD_Recapture(F_CMD_ARGS) { do_recapture(F_PASS_ARGS, False); return; } void CMD_RecaptureWindow(F_CMD_ARGS) { do_recapture(F_PASS_ARGS, True); return; }