/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT * Copyright 1989 Massachusetts Institute of Technology */ /*********************************************************\ * * * BULL WINDOW MANAGER for X11 . * * * * MODULE defining the ClientWindow Object Class. * * * \*********************************************************/ /* includes */ #include #include #include "EXTERN.h" #include "wool.h" #include "wl_atom.h" #include "wl_string.h" #include "wl_list.h" #include "wl_number.h" #include "wl_func.h" #include "gwm.h" #include "wl_event.h" #include "wl_fsm.h" #include "wl_pixmap.h" #include "wl_cursor.h" #include "wl_client.h" #ifdef SHAPE #include extern WindowIsShaped(); #endif /* SHAPE */ /* local constants */ /* external */ extern Wob SetUpClientWindow(); extern Bar NewBar(), BarOpen(); extern Wob LookUpWob(); extern ClientWindow LookUpClient(); extern UserAskWindow(); extern UserMessage(); extern FSMAction(); extern WOOL_METHOD WLMenu[]; extern XError(), NoXError(); extern Window FindToplevelWindow(); extern ClientWindow DecoratedWindow(); /* local */ extern ClientWindowEventHandler(), UpdateClientWindowGeometry(); extern ReconfigureClientWindow(); ClientWindow NewClientWindow(), NewClientWindowIcon(), window_is_still_alive(), NewIconWindow(); extern ClientWindowOpen(), ClientWindowClose(); WOB_METHOD ClientWindowClass[] = { 0, /* METHODS_ARRAY */ WobEval, WobPrint, WobRelease, WobExecute, WobSet, WobGetCValue, ClientWindowOpen, ClientWindowClose, ClientWindowEventHandler, (WOB_METHOD) wool_undefined_method_1, WobGetDimensions, (WOB_METHOD) wool_undefined_method_2, (WOB_METHOD) wool_undefined_method_2, ReconfigureClientWindow, (WOB_METHOD) wool_undefined_method_2, (WOB_METHOD) wool_undefined_method_1, (WOB_METHOD) wool_undefined_method_1, (WOB_METHOD) wool_undefined_method_1, (WOB_METHOD) wool_undefined_method_1, (WOB_METHOD) wool_undefined_method_1 }; /* routines */ /* * To decorate a window, we must: * - see if it is decorable * - get all info about it * - decorate it via NewClientWindow */ ClientWindow DecorateWindow(window, parent, must_save_set, being_mapped) Window window; ClientWindow parent; int must_save_set; /* 0 for screen, 1 for windows */ int being_mapped; /* 0 for decorating by reference */ { ClientWindow cw; WOOL_Client wl_client; int local_zrt_size = zrt_size; XWindowAttributes wa; Wob oldTargetWob = TargetWob; wa.override_redirect = 0; /* if window has died meanwhile, abort */ if (TrapXErrors(XGetWindowAttributes(dpy, window, &wa)) || wa.override_redirect) /* do not manage override_redirect wins */ return NULL; /* be careful, we might have decorated it in beetween */ if(cw = (ClientWindow) LookUpClient(window)) return cw; GWM_window_being_decorated = cw = NewClientWindow(parent, window); { save_wool_error_resume_point(); /* contains decls */ if (set_wool_error_resume_point()) { restore_wool_error_resume_point(); return 0; /* aborts if window dies */ } SetTarget(cw); UpdateAllCachedProperties(cw); /* some preliminar get_properties */ cw -> colormap = wa.colormap; /* update attributes */ MatchWoolDescription(cw, &wl_client); /* get the descriptions */ UpdateClientWindowFields(cw, wl_client); UpdateClientWindowGeometry(cw); /* sets bars,etc */ if (must_save_set && !(cw -> client_wob)) /* in case of GWM dying */ XChangeSaveSet(dpy, window, SetModeInsert); ClientWindowRecordClient(cw); /* it */ ClientWindowOpen(cw, being_mapped); /* create the windows */ zrt_gc(local_zrt_size); SetTarget(oldTargetWob); restore_wool_error_resume_point(); return cw; } } /* The icon window is realized only on the first call to "iconify-window" or * "window-icon". * return icon or 0 if wool error */ ClientWindow RealizeIconWindow(cw) ClientWindow cw; { WOOL_Client wl_icon; ClientWindow icon; wl_icon = (WOOL_Client) (cw -> icon_description -> type == WLClient ? cw -> icon_description : (WOOL_OBJECT) wool_eval_and_catch_errors(cw -> icon_description)); if (!wl_icon || wl_icon -> type != WLClient) { ShowUndecoratedWindow(cw); wool_print(wl_icon ? wl_icon : (WOOL_Client) NIL_STRING); wool_newline(); wool_error("bad %s description!", "icon"); } GWM_window_being_decorated = icon = NewIconWindow(cw); SetTarget(icon); icon -> cached_props = cw -> cached_props; UpdateClientWindowFields(icon, wl_icon); MakeIconWindow(cw); /* makes central plug */ if(icon -> client) { ClientWindowRecordClient(icon); if (!icon -> client_wob) XChangeSaveSet(dpy, icon->client, SetModeInsert); } UpdateClientWindowGeometry(icon); decrease_reference(cw -> icon_description); cw -> icon_description = NULL; UpdateClientWindowIconSize(icon); ClientWindowOpen(icon, 1); return icon; } /* Creates a wob for that new client window. */ ClientWindow NewClientWindow(parent, window) ClientWindow parent; Window window; { ClientWindow cw = (ClientWindow) NewWob(sizeof(struct _ClientWindow)); cw -> parent = (Wob) parent; cw -> screen = parent -> screen; cw -> status = ClientWindowStatus; cw -> client = window; cw -> window = cw; cw -> client_wob = LookUpWob(window); cw -> type = ClientWindowClass; return cw; } ClientWindow NewIconWindow(cw) ClientWindow cw; { ClientWindow icon = (ClientWindow) NewWob(sizeof(struct _ClientWindow)); cw -> icon = icon; icon -> parent = cw -> parent; icon -> screen = cw -> screen; icon -> window = cw; icon -> icon = icon; icon -> status = IconStatus; icon -> type = ClientWindowClass; return icon; } /* * updates now the properties cached in the ClientWindow structure and icon */ #define CWSTR(a) (((WOOL_String)(cw -> a)) -> string) UpdateAllCachedProperties(cw) ClientWindow cw; { Window window = cw -> client; char *machinename; XClassHint classhints; Atom actualtype; int actualformat; unsigned long nitems; unsigned long bytesafter; CWCachedProperties cprops = (CWCachedProperties) Malloc(sizeof(struct _CWCachedProperties)); /* get all fixed properties */ bzero(cprops, sizeof(struct _CWCachedProperties)); cw -> cached_props = cprops; classhints.res_name = classhints.res_class = NULL; if(XGetWindowProperty(dpy, window, XA_WM_CLIENT_MACHINE, 0, MAX_TEMP_STRING_SIZE, False, XA_STRING, &actualtype, &actualformat, &nitems, &bytesafter, (unsigned char **) &machinename)) longjmp(wool_goes_here_on_error, 1); if (machinename) { char *p = machinename; while(*p) { /* truncates to first dot field */ if (*p == '.') { *p = '\0'; break; } p++; } increase_reference(cprops -> machinename = (WOOL_OBJECT) WLString_make(machinename)); XFree(machinename); } else increase_reference(cprops -> machinename = (WOOL_OBJECT) DefaultMachineName); XGetClassHint(dpy, window, &classhints); increase_reference(cprops -> clientclass = (classhints.res_class ? (WOOL_OBJECT) WLString_make(classhints.res_class) : (WOOL_OBJECT) DefaultClientClass)); increase_reference(cprops -> clientname = (classhints.res_name ? (WOOL_OBJECT) WLString_make(classhints.res_name) : (WOOL_OBJECT) DefaultClientName)); if (classhints.res_name) XFree(classhints.res_name); if (classhints.res_class) XFree(classhints.res_class); /* update all variable props */ Update_XA_WM_NAME(cw); Update_XA_WM_ICON_NAME(cw); Update_XA_WM_HINTS(cw); Update_XA_WM_NORMAL_HINTS(cw); Update_XA_WM_TRANSIENT_FOR(cw); Update_XA_WM_COLORMAP_WINDOWS(cw); Update_XA_WM_PROTOCOLS(cw); GetPreviousWM_STATE(cw); /* get the previous WM_STATE if any */ UpdateClientWindowSize(cw); /* check window real size */ } /* * update ONE property * cw MUST be a window, not an icon */ UpdateCachedProperty(cw, property_atom) ClientWindow cw; Atom property_atom; { switch (property_atom) { /* predefined atoms */ case XA_WM_NAME: Update_XA_WM_NAME(cw); break; case XA_WM_ICON_NAME: Update_XA_WM_ICON_NAME(cw); break; case XA_WM_HINTS: Update_XA_WM_HINTS(cw); break; case XA_WM_NORMAL_HINTS: Update_XA_WM_NORMAL_HINTS(cw); break; case XA_WM_TRANSIENT_FOR: Update_XA_WM_TRANSIENT_FOR(cw); break; default: /* non-predefined props */ if (property_atom == XA_WM_COLORMAP_WINDOWS) Update_XA_WM_COLORMAP_WINDOWS(cw); else if (property_atom == XA_WM_PROTOCOLS) Update_XA_WM_PROTOCOLS(cw); } } /* individual methods to update or create cached properties */ #if defined(X11R1)||defined(X11R2)||defined(X11R3)||defined(X11R4)||defined(X11R5) Update_XA_WM_NAME(cw) ClientWindow cw; { char *name = 0; XFetchName(dpy, cw -> client, &(name)); decrease_reference(cw -> cached_props -> windowname); if (!(name) || (*(name) == '\0')) increase_reference(cw -> cached_props -> windowname = (WOOL_OBJECT) DefaultWindowName); else { increase_reference(cw -> cached_props -> windowname = (WOOL_OBJECT) WLString_make(name)); XFree(name); } } Update_XA_WM_ICON_NAME(cw) ClientWindow cw; { char *name = 0; XGetIconName(dpy, cw -> client, &name); if (cw -> cached_props -> iconname) { decrease_reference(cw -> cached_props -> iconname); } if (!(name) || (*(name) == '\0')) { increase_reference(cw -> cached_props -> iconname = (WOOL_OBJECT) DefaultIconName); } else { increase_reference(cw -> cached_props -> iconname = (WOOL_OBJECT) WLString_make(name)); XFree(name); } } #else /* X11R6 or later */ Update_XA_WM_NAME(cw) ClientWindow cw; { char *name = 0; XTextProperty text_prop; char **list_return = 0; int count_return; if (! XGetWMName(dpy, cw -> client, &text_prop)); else { /* incantation from twm/add_window.c */ if (text_prop.value) text_prop.nitems = strlen((char *)text_prop.value); if ( XmbTextPropertyToTextList( dpy, &text_prop, &list_return, &count_return) < Success); else { if (!list_return || !(*list_return)); else name = *list_return; } } decrease_reference(cw -> cached_props -> windowname); if (!(name) || (*(name) == '\0')) increase_reference(cw -> cached_props -> windowname = (WOOL_OBJECT) DefaultWindowName); else { increase_reference(cw -> cached_props -> windowname = (WOOL_OBJECT) WLString_make(name)); } if (list_return) XFreeStringList(list_return); } Update_XA_WM_ICON_NAME(cw) ClientWindow cw; { char *name = 0; XTextProperty text_prop; char **list_return = 0; int count_return; if (! XGetWMIconName(dpy, cw -> client, &text_prop)); else { /* incantation from twm/add_window.c */ if (text_prop.value) text_prop.nitems = strlen((char *)text_prop.value); if ( XmbTextPropertyToTextList( dpy, &text_prop, &list_return, &count_return) < Success); else { if (!list_return || !(*list_return)); else name = *list_return; } } if (cw -> cached_props -> iconname) { decrease_reference(cw -> cached_props -> iconname); } if (!(name) || (*(name) == '\0')) { increase_reference(cw -> cached_props -> iconname = (WOOL_OBJECT) DefaultIconName); } else { increase_reference(cw -> cached_props -> iconname = (WOOL_OBJECT) WLString_make(name)); } if (list_return) XFreeStringList(list_return); } #endif /* X11R6 or later */ Update_XA_WM_HINTS(cw) ClientWindow cw; { XWMHints *windowhints, *wm_hints; ClientWindow group_leader; if (windowhints = XGetWMHints(dpy, cw -> client)) { if (GWM_backup_old_property) bcopy(&(cw -> cached_props -> wm_hints), &GWM_backup_of_old_property, sizeof(XWMHints)); bcopy(windowhints, wm_hints = &(cw -> cached_props -> wm_hints), sizeof(XWMHints)); /* window groups */ if ((windowhints -> flags & WindowGroupHint) && windowhints -> window_group && (cw -> status & ClientWindowStatus)) { if (windowhints -> window_group == cw->client) AddWindowToGroupLeader(cw, cw); else if (group_leader = DecoratedWindow(windowhints -> window_group)) { if (group_leader -> status & ClientWindowStatus) AddWindowToGroupLeader(cw, group_leader); } } /* check validity of hints */ if (wm_hints->flags & IconWindowHint && !(wm_hints->icon_window)) wm_hints->flags &= ~IconWindowHint; if (wm_hints->flags & IconPixmapHint && !(wm_hints->icon_pixmap)) wm_hints->flags &= ~IconPixmapHint; if (wm_hints->flags & IconMaskHint && !(wm_hints->icon_mask)) wm_hints->flags &= ~IconMaskHint; XFree(windowhints); } } Update_XA_WM_NORMAL_HINTS(cw) ClientWindow cw; { long supplied = 0; #ifdef NOBASEDIMS if (!XGetNormalHints(dpy, cw -> client, &(cw -> cached_props -> normal_hints))) { cw -> cached_props -> normal_hints.flags = 0; } #else /* NOBASEDIMS */ if (!XGetWMNormalHints(dpy, cw -> client, &(cw -> cached_props -> normal_hints), &supplied)) { cw -> cached_props -> normal_hints.flags = 0; } if (supplied & PBaseSize) { supplied = 1; } else { supplied = 0; } #endif /* NOBASEDIMS */ cw -> cached_props -> new_normal_hints = supplied; CheckConsistency(&(cw -> cached_props -> normal_hints)); } Update_XA_WM_TRANSIENT_FOR(cw) ClientWindow cw; { ClientWindow main_cw; Window transient_for; decrease_reference(cw -> cached_props -> transient_for); XSync(dpy, 0); XSetErrorHandler(NoXError); ErrorStatus = 0; XGetTransientForHint(dpy, cw -> client, &transient_for); XSync(dpy, 0); XSetErrorHandler(XError); if (ErrorStatus) longjmp(wool_goes_here_on_error, 1); /* problem appeared */ if (transient_for) { if (transient_for != Context -> root && transient_for != cw -> client && (main_cw = DecoratedWindow(transient_for))) { increase_reference(cw -> cached_props -> transient_for = (WOOL_OBJECT) WLNumber_make(main_cw)); } else { cw -> cached_props -> transient_for = 0; } } else { cw -> cached_props -> transient_for = 0; } } Update_XA_WM_COLORMAP_WINDOWS(cw) ClientWindow cw; { Atom actualtype; int actualformat; unsigned long nitems; unsigned long bytesafter; Window *colormap_windows = NULL, *old_colormap_windows; int result, i; result = GwmSilentXGetWindowProperty(dpy, cw -> client, XA_WM_COLORMAP_WINDOWS, 0, WM_COLORMAP_WINDOWS_PROP_Length, False, XA_WM_COLORMAP_WINDOWS, &actualtype, &actualformat, &nitems, &bytesafter, &colormap_windows); if(result == Success && nitems && actualtype != None && actualformat == 32){ old_colormap_windows = cw -> cached_props -> colormap_windows; cw -> cached_props -> colormap_windows = (Window *) Malloc ((nitems+1) * sizeof (Window)); cw -> cached_props -> colormap_windows_size = 1; cw -> cached_props -> colormap_windows[0] = cw -> client; for(i = 0; i< nitems; i++) if(colormap_windows[i] != cw -> client && !LookUpClient(colormap_windows[i])) { cw -> cached_props -> colormap_windows[ cw -> cached_props -> colormap_windows_size++] = colormap_windows[i]; if (colormap_windows[i] != cw -> client) { XSelectInput(dpy, colormap_windows[i], ColormapChangeMask); } } if(cw -> cached_props -> colormap_windows_size == 1){ Free(cw -> cached_props -> colormap_windows); cw -> cached_props -> colormap_windows_size = 0; } else { if (Context -> InstalledColormapCW == cw) XInstallColormap(dpy, cw -> cached_props -> colormap_windows[0]); } cw -> cached_props -> colormap_windows_index = 0; if(old_colormap_windows) Free(old_colormap_windows); } if(colormap_windows && result == Success) XFree(colormap_windows); } Update_XA_WM_PROTOCOLS(cw) ClientWindow cw; { Atom actualtype; int actualformat; unsigned long nitems; unsigned long bytesafter; Window *protocols = NULL; int result, i; result = GwmSilentXGetWindowProperty(dpy, cw -> client, XA_WM_PROTOCOLS, 0, WM_PROTOCOLS_PROP_Length, False, XA_ATOM, &actualtype, &actualformat, &nitems, &bytesafter, &protocols); if (result == Success && nitems && actualtype != None && actualformat == 32) { cw -> cached_props -> wm_take_focus = 0; cw -> cached_props -> wm_save_yourself = 0; cw -> cached_props -> wm_delete_window = 0; for (i = 0; i < nitems; i++) { if ((protocols[i] == XA_WM_TAKE_FOCUS) && !(cw -> ignore_take_focus)) cw -> cached_props -> wm_take_focus = 1; else if (protocols[i] == XA_WM_SAVE_YOURSELF) cw -> cached_props -> wm_save_yourself = 1; else if (protocols[i] == XA_WM_DELETE_WINDOW) cw -> cached_props -> wm_delete_window = 1; } } if (protocols && result == Success) XFree(protocols); } /* * release their storage */ FreeCachedProperties(cprops) CWCachedProperties cprops; { int local_zrt_size = zrt_size; decrease_reference(cprops -> machinename); decrease_reference(cprops -> clientclass); decrease_reference(cprops -> clientname); decrease_reference(cprops -> windowname); decrease_reference(cprops -> iconname); decrease_reference(cprops -> transient_for); DelayedFree(cprops); zrt_gc(local_zrt_size); } void Set_XA_WM_STATE(cw, state) ClientWindow cw; int state; { struct _WM_STATE_PROP wm_state; int trap_x_errors = 0; if (state == -1) { if (cw -> mapped) wm_state.state = WM_STATE_Normal; else if ((cw -> icon && cw -> icon -> mapped) || (cw -> cached_props -> user_icon && cw -> cached_props -> user_icon -> mapped)) wm_state.state = WM_STATE_Iconified; else { wm_state.state = WM_STATE_Withdrawn; trap_x_errors = 1; } } else { wm_state.state = state; if (state == WM_STATE_Withdrawn) trap_x_errors = 1; } if (wm_state.state != cw -> cached_props -> wm_state) { cw -> cached_props -> wm_state = wm_state.state; wm_state.icon = (cw -> icon ? cw -> icon -> hook : (cw -> cached_props -> user_icon ? cw -> cached_props -> user_icon -> hook : 0)); if (trap_x_errors) XSetErrorHandler(NoXError); XChangeProperty(dpy, cw -> client, XA_WM_STATE, XA_WM_STATE, 32, PropModeReplace, (unsigned char *)&wm_state, WM_STATE_PROP_Length); if (trap_x_errors) { XSync(dpy, 0); XSetErrorHandler(XError); } } } /* Updating WM_STATE is setting it on the window * returns state */ int Update_XA_WM_STATE(cw) ClientWindow cw; { cw = cw -> window; if (!(cw -> client_wob || cw -> cached_props -> user_icon)) { Set_XA_WM_STATE(cw, -1); return cw -> cached_props -> wm_state; } else return WM_STATE_Normal; } /* first time a window is mapped, decode the WM_STATE from previous wm */ GetPreviousWM_STATE(cw) ClientWindow cw; { Atom actualtype; int actualformat; unsigned long nitems; unsigned long bytesafter; WM_STATE_PROP wm_state; if (GWM_ProcessingExistingWindows && Success == XGetWindowProperty(dpy, cw -> client, XA_WM_STATE, 0, WM_STATE_PROP_Length, False, XA_WM_STATE, &actualtype, &actualformat, &nitems, &bytesafter, (unsigned char **)&wm_state) && nitems && wm_state) { cw -> cached_props -> wm_hints.flags |= StateHint; cw -> cached_props -> wm_hints.initial_state = wm_state -> state; XFree(wm_state); } } /* * copies information from descriptor to client */ UpdateClientWindowBar(parent, field, wl_bar, dir) ClientWindow parent; Bar *field; WOOL_Bar wl_bar; int dir; { wl_bar = (WOOL_Bar) wool_type_or_evaluate(wl_bar, WLBar); if (wl_bar == (WOOL_Bar) NIL) *field = NULL; else { *field = NewBar(parent, wl_bar, dir); } } UpdateClientWindowFields(cw, wl_client) ClientWindow cw; WOOL_Client wl_client; { cw -> inner_borderwidth = wl_client -> inner_borderwidth; cw -> box.borderwidth = wl_client -> borderwidth; cw -> box.borderpixel = wl_client -> borderpixel; cw -> box.background = wl_client -> background; UpdateClientWindowBar(cw, &(cw -> titlebar), wl_client -> titlebar, HORIZONTAL); UpdateClientWindowBar(cw, &(cw -> leftbar), wl_client -> leftbar, VERTICAL); UpdateClientWindowBar(cw, &(cw -> rightbar), wl_client -> rightbar, VERTICAL); UpdateClientWindowBar(cw, &(cw -> basebar), wl_client -> basebar, HORIZONTAL); increase_reference(cw -> cursor = wool_type_or_evaluate(wl_client -> cursor, WLCursor)); increase_reference(cw -> bordertile = wool_type_or_evaluate(wl_client -> bordertile, WLPixmap)); increase_reference(cw -> fsm = wool_type_or_evaluate(wl_client -> fsm, WLFsm)); increase_reference(cw -> menu = wool_type_or_evaluate(wl_client -> menu, WLMenu)); increase_reference(cw -> property = (WOOL_OBJECT) wl_client -> property); increase_reference(cw -> opening = (WOOL_OBJECT) wl_client -> opening); increase_reference(cw -> closing = (WOOL_OBJECT) wl_client -> closing); increase_reference(cw -> grabs = (WOOL_OBJECT) wl_client -> grabs); increase_reference(cw -> icon_plug = (WOOL_OBJECT) wl_client -> icon_plug); cw -> map_on_raise = wl_client -> map_on_raise; cw -> ignore_take_focus = wl_client -> map_on_raise; } /* * here we create or get the XWindow to put in the icon -> client field */ MakeIconWindow(cw) ClientWindow cw; { WOOL_Plug wl_plug = (WOOL_Plug) cw -> icon -> icon_plug; Plug plug; wl_plug = (WOOL_Plug) WOOL_send(WOOL_eval, wl_plug, (wl_plug)); if (wl_plug -> type == WLNumber) { /* icon window managed by client */ cw -> icon -> client = (Window) ((WOOL_Number) wl_plug) -> number; } else if (wl_plug -> type == WLPlug) { /* icon field is plug */ plug = (Plug) NewPlug(Context->rootWob, wl_plug); UpdatePlugGeometry(plug); PlugOpen(plug); cw -> icon -> client = plug -> hook; cw -> icon -> client_wob = (Wob) plug; } } /* * we set here the size of the cw before calling MatchWool, for dims queries */ UpdateClientWindowSize(cw) ClientWindow cw; { Window root; unsigned int depth, width, height; int must_resize = 0; if (!XGetGeometry(dpy, cw -> client, &root, &(cw -> box.x), &(cw -> box.y), &(cw -> box.width), &(cw -> box.height), &(cw -> box.borderwidth), &depth)) longjmp(wool_goes_here_on_error, 1); /* update cw fields */ cw -> inner_width = cw -> box.width; cw -> inner_height = cw -> box.height; cw -> old_inner_borderwidth = cw -> inner_borderwidth = cw -> box.borderwidth; /* update the size according to hints */ if (!GWM_ProcessingExistingWindows) { if(!cw -> cached_props -> new_normal_hints) { if (cw -> cached_props -> normal_hints.flags & USSize) { if (cw -> inner_width != cw -> cached_props -> normal_hints.width) { must_resize = 1; cw -> inner_width = cw -> cached_props -> normal_hints.width; } if (cw -> inner_height != cw -> cached_props -> normal_hints.height) { must_resize = 1; cw -> inner_height = cw -> cached_props -> normal_hints.height; } } else if (cw -> cached_props -> normal_hints.flags & PSize) { if (cw -> inner_width != cw -> cached_props -> normal_hints.width && cw -> inner_width > 1) { must_resize = 1; cw -> inner_width = cw -> cached_props -> normal_hints.width; } if (cw -> inner_height != cw -> cached_props -> normal_hints.height && cw -> inner_height > 1) { must_resize = 1; cw -> inner_height = cw -> cached_props -> normal_hints.height; } } } else { width = cw -> inner_width; height = cw -> inner_height; conform_to_hints(&(cw -> cached_props -> normal_hints), &width, &height); if ((cw -> inner_width != width) || (cw -> inner_height != height)) { must_resize = 1; cw -> inner_width = width; cw -> inner_height = height; } } } if (must_resize) XResizeWindow(dpy, cw -> client, cw -> inner_width, cw -> inner_height); } /* before opening an icon, place it according to hints */ UpdateClientWindowIconSize(icon) ClientWindow icon; { if (icon -> cached_props -> wm_hints.flags & IconPositionHint) { icon -> box.x = icon -> cached_props -> wm_hints.icon_x; icon -> box.y = icon -> cached_props -> wm_hints.icon_y; } } /* * Here we add physically all the gadgets around a client window. * A new window is opened. (First Map Request, called from SetUpClient.) * The description of the window to be created is in setup. * Create the surrounding window. * Set up window geometry, bars, plugs if any, * reparent the client window. */ ClientWindowOpen(cw, being_mapped) ClientWindow cw; int being_mapped; { check_window_size(cw); /* create the WOB windows, and map them */ cw -> curstate = (int) WOOL_send(WOOL_open, cw -> fsm, (cw -> fsm)); ObeyWinGravityHint(cw, 1); /* sets reparenting offsets */ { XSetWindowAttributes xsw; xsw.background_pixmap = None; xsw.border_pixel = cw->box.borderpixel; xsw.backing_store = NotUseful; xsw.save_under = NotUseful; cw -> hook = XCreateWindow(dpy, Context -> root, cw -> box.x, cw -> box.y, cw -> box.width, cw -> box.height, cw -> box.borderwidth, CopyFromParent, CopyFromParent, CopyFromParent, CWBackPixmap | CWBorderPixel | CWBackingStore | CWSaveUnder, &xsw); } cw -> status |= TopLevelXWindowStatus; WobRecordHook(cw); BarOpen(cw -> titlebar); BarOpen(cw -> leftbar); BarOpen(cw -> rightbar); BarOpen(cw -> basebar); if (cw -> cursor != NIL) XDefineCursor(dpy, cw -> hook, ((WOOL_Cursor) cw -> cursor) -> cursor); if (cw -> bordertile != NIL) XSetWindowBorderPixmap(dpy, cw -> hook, ((WOOL_Pixmap) cw -> bordertile) -> pixmap); /* put window in window list */ Context -> WindowCount++; if (Context -> rootWob -> next) Context -> rootWob -> next -> previous = cw; cw -> next = Context -> rootWob -> next; Context -> rootWob -> next = cw; cw -> previous = Context -> rootWob; #ifdef SHAPE /* if we decorate a shaped window, reshape ourselves */ if (WindowIsShaped(cw)) ClientWindowSetShape(cw); #endif /* SHAPE */ if (cw -> client) { /* Replace client Window */ unsigned int client_height, client_width, client_borderwidth; int dummy; XUnmapWindow(dpy, cw -> client); XSetWindowBorderWidth(dpy, cw -> client, cw -> inner_borderwidth); if (cw -> client_wob) { cw -> client_wob -> parent = (Wob) cw; cw -> client_wob -> status &= ~TopLevelXWindowStatus; cw -> client_wob -> input_mask |= ClientClientMask; XSelectInput(dpy, cw -> client, cw -> client_wob -> input_mask); } else { XSelectInput(dpy, cw -> client, ClientClientMask); } if (TrapXErrors(XReparentWindow(dpy, cw -> client, cw -> hook, cw -> inner_x, cw -> inner_y))) { cw -> client = 0; ClientWindowClose(cw); SetTarget(Context->rootWob); return; } /* check if window hasn't been resized since deco */ if (!XGetGeometry(dpy, cw -> client, (Window *)&dummy, &dummy, &dummy, &client_width, &client_height, &client_borderwidth, (unsigned int *)&dummy)) longjmp(wool_goes_here_on_error, 1); if (client_height != cw -> inner_height || client_width != cw -> inner_width || client_borderwidth != cw -> inner_borderwidth) ReconfigureClientWindow(cw, cw -> client); else SendSyntheticMoveEvent(cw); } XSelectInput(dpy, cw -> hook, ClientMask | ((WOOL_Fsm) cw -> fsm) -> mask); /* set global grabs */ WLClient_set_grabs(cw -> grabs, cw -> hook); XSync(dpy, 0); if (!GWM_window_being_decorated) { /* error while decorating? abort! */ SetTarget(Context->rootWob); return; } GWM_window_being_decorated = 0; /* process pending events */ if (!GWM_ProcessingExistingWindows && GWM_reenter_on_opens) GWM_ProcessEvents(0); /* execute "opening" WOOL code */ if (being_mapped && WobIsValid(cw)) { ClientWindowExecuteOpening(cw); } } ClientWindowExecuteOpening(cw) ClientWindow cw; { int local_zrt_size = zrt_size; if (cw -> opening) { SetTarget(cw); GWM_Window_being_opened = cw; wool_eval_and_catch_errors_proc(cw -> opening); GWM_Window_being_opened = 0; decrease_reference(cw -> opening); cw -> opening = NULL; } SetTarget(cw); zrt_gc(local_zrt_size); } /* * Take a client window, recursivly set geometry by the sons, and then * set the bars geometry */ UpdateClientWindowGeometry(cw) ClientWindow cw; { UpdateBarWidth(cw -> titlebar); UpdateBarWidth(cw -> leftbar); UpdateBarWidth(cw -> rightbar); UpdateBarWidth(cw -> basebar); ClientWindowComputeGeometry(cw); ClientWindowComputeBarDims(cw); UpdateBarLength(cw -> titlebar); UpdateBarLength(cw -> leftbar); UpdateBarLength(cw -> rightbar); UpdateBarLength(cw -> basebar); } ClientWindowComputeGeometry(cw) ClientWindow cw; { Window root; int client_x, client_y; unsigned int client_width, client_height; unsigned int client_borderwidth, client_depth; if (cw -> client) { if (!XGetGeometry(dpy, cw -> client, &root, &client_x, &client_y, &client_width, &client_height, &client_borderwidth, &client_depth)) longjmp(wool_goes_here_on_error, 1); #ifdef SHAPE /* if we decorate a shaped window, do not touch borderwidth */ if (GWM_ShapeExtension) { int xws, yws, xbs, ybs; unsigned int wws, hws, wbs, hbs; int boundingShaped, clipShaped; XShapeSelectInput (dpy, cw -> client, True); if (XShapeQueryExtents (dpy, cw -> client, &boundingShaped, &xws, &yws, &wws, &hws, &clipShaped, &xbs, &ybs, &wbs, &hbs) &&boundingShaped) { cw -> client_shaped = 1; cw -> inner_borderwidth = 0; } } #endif /* SHAPE */ cw -> old_inner_borderwidth = client_borderwidth; if (cw -> inner_borderwidth == ((short) ANY)) cw -> inner_borderwidth = client_borderwidth; else client_borderwidth = cw -> inner_borderwidth; cw -> inner_width = client_width; cw -> inner_height = client_height; } else { NaturalBarLength(cw -> titlebar); NaturalBarLength(cw -> leftbar); NaturalBarLength(cw -> rightbar); NaturalBarLength(cw -> basebar); cw -> inner_borderwidth = 0; if (cw -> leftbar || cw -> rightbar) { cw -> inner_width = 0; cw -> inner_height = Max((cw -> leftbar ? cw -> leftbar -> box.height : 0), (cw -> rightbar ? cw -> rightbar -> box.height : 0)); } else { cw -> inner_height = 0; cw -> inner_width = Max((cw -> titlebar ? cw -> titlebar -> box.width : 0), (cw -> basebar ? cw -> basebar -> box.width : 0)); } } } ClientWindowComputeBarDims(cw) ClientWindow cw; { int titleheight, baseheight, leftwidth, rightwidth; cw -> box.width = cw -> inner_width + 2 * cw -> inner_borderwidth; cw -> box.height = cw -> inner_height + 2 * cw -> inner_borderwidth; /* Special hack */ if ((cw -> leftbar && cw -> leftbar -> ewidth) || (cw -> rightbar && cw -> rightbar -> ewidth)) { int len; UpdateBarWidth(cw -> leftbar); UpdateBarWidth(cw -> rightbar); len = Max(NaturalBarLength(cw -> titlebar), NaturalBarLength(cw -> basebar)); len = len - cw -> inner_width - (cw -> leftbar ? cw -> leftbar -> box.width + 2 * cw -> leftbar -> box.borderwidth : 0) - (cw -> rightbar ? cw -> rightbar -> box.width + 2 * cw -> rightbar -> box.borderwidth : 0); if (len < 0) len = 0; if (!cw -> leftbar || !cw -> leftbar -> ewidth) cw -> rightbar -> box.width += len; else if (!cw -> rightbar || !cw -> rightbar -> ewidth) cw -> leftbar -> box.width += len; else { int llen = len / 2, rlen = len - llen; cw -> leftbar -> box.width += llen; cw -> rightbar -> box.width += rlen; } } titleheight = (cw -> titlebar ? cw -> titlebar -> box.height + 2 * cw -> titlebar -> box.borderwidth : 0); baseheight = (cw -> basebar ? cw -> basebar -> box.height + 2 * cw -> basebar -> box.borderwidth : 0); leftwidth = (cw -> leftbar ? cw -> leftbar -> box.width + 2 * cw -> leftbar -> box.borderwidth : 0); rightwidth = (cw -> rightbar ? cw -> rightbar -> box.width + 2 * cw -> rightbar -> box.borderwidth : 0); /* sets the dimensions of the box itself */ cw -> inner_x = leftwidth; cw -> inner_y = titleheight; cw -> box.width += leftwidth + rightwidth; cw -> box.height += titleheight + baseheight; /* set the titlebar (height and borderwidth are already set) */ if(cw -> titlebar) { cw -> titlebar -> box.x = 0; cw -> titlebar -> box.y = 0; cw -> titlebar -> box.width = cw -> box.width - 2 * cw -> titlebar -> box.borderwidth; } /* set the leftbar (width and borderwidth are already set) */ if(cw -> leftbar) { cw -> leftbar -> box.x = 0; cw -> leftbar -> box.y = titleheight; cw -> leftbar -> box.height = cw -> box.height - titleheight - baseheight - 2 * cw -> leftbar -> box.borderwidth; } /* set the rightbar (width and borderwidth are already set) */ if(cw -> rightbar) { cw -> rightbar -> box.x = cw -> box.width - 2 * cw -> rightbar -> box.borderwidth - cw -> rightbar -> box.width; cw -> rightbar -> box.y = titleheight; cw -> rightbar -> box.height = cw -> box.height - titleheight - baseheight - 2 * cw -> rightbar -> box.borderwidth; } /* set the basebar (height and borderwidth are already set) */ if(cw -> basebar) { cw -> basebar -> box.x = 0; cw -> basebar -> box.y = cw -> box.height - baseheight; cw -> basebar -> box.width = cw -> box.width - 2 * cw -> basebar -> box.borderwidth; } } /* destroys all data concerning the window * suppose that the client window is already destroyed, so we do not need to * destroy it ourselves */ ClientWindowClose(cw) ClientWindow cw; { int closeflag; ClientWindow icon = cw -> icon; CWCachedProperties cprops = cw -> cached_props; if (cprops -> client_group) RemoveWindowFromGroup(cw); if (Context -> InstalledColormapCW == cw) Context -> InstalledColormapCW = 0; closeflag = ClientWindowClose_aux(cw -> window); if (icon) ClientWindowClose_aux(icon); if (closeflag) FreeCachedProperties(cprops); if (TargetWindow == cw || TargetWindow == icon) SetTarget(Context -> rootWob); } int ClientWindowClose_aux(cw) ClientWindow cw; { int local_zrt_size = zrt_size; WOOL_OBJECT closing; if (cw -> closing) { /* Otherwise this is already done */ SetTarget(cw); closing = cw -> closing; cw -> closing = 0; if (!(GWM_is_ending || GWM_is_restarting)) wool_eval_and_catch_errors_proc(closing); if (cw->client_wob) WOOL_send(WOOL_close, cw->client_wob, (cw->client_wob)); BarClose(cw -> titlebar); BarClose(cw -> leftbar); BarClose(cw -> rightbar); BarClose(cw -> basebar); decrease_reference(cw -> opening); decrease_reference(closing); decrease_reference(cw -> grabs); decrease_reference(cw -> icon_plug); decrease_reference(cw -> icon_description); /* remove from list */ if (cw -> previous) { Context -> WindowCount--; cw -> previous -> next = cw -> next; if (cw -> next) cw -> next -> previous = cw -> previous; } if (cw -> client) XDeleteContext(dpy, cw -> client, client_context); WobRelease(cw); zrt_gc(local_zrt_size); return 1; } return 0; } ClientWindowMap(cw) ClientWindow cw; { if (cw && !(cw -> mapped)) { if (cw -> client) XMapWindow(dpy, cw -> client); XMapWindow(dpy, cw -> hook); cw -> mapped = 1; Update_XA_WM_STATE(cw); } return; } ClientWindowUnmap(cw) ClientWindow cw; { if (cw && cw -> mapped) { XUnmapWindow(dpy, cw -> hook); if (cw -> client && !cw -> client_wob) XUnmapWindow(dpy, cw -> client); cw -> mapped = 0; Update_XA_WM_STATE(cw); } return; } ClientWindowInitialMap(cw) ClientWindow cw; { int mapping = 1; if (!cw || cw -> status & IconStatus) return; if (cw -> cached_props -> wm_hints.flags & StateHint) { switch (cw -> cached_props -> wm_hints.initial_state) { case WM_STATE_Iconified: { int local_zrt_size = zrt_size; WOOL_OBJECT res; if (TargetWindow != cw) SetTarget(cw); res = (WOOL_OBJECT) wool_eval_and_catch_errors(WL_iconify_window_call); zrt_gc(local_zrt_size); mapping = res ? 0 : 1; /* map in case of errors */ } break; case WM_STATE_Withdrawn: /* ERROR! buggy clients */ /* we map, ignoring the bogus hint but printing a warning */ wool_warning1("GWM: window %s has a bogus hint WM_STATE_Withdrawn as its initial_map field in its WM_HINTS property!\n", ((WOOL_String) (cw -> cached_props -> windowname)) -> string); break; } } if (mapping) { XMapWindow(dpy, cw -> hook); cw -> mapped = 1; if (cw -> client) XMapWindow(dpy, cw -> client); } Update_XA_WM_STATE(cw); } int Mapped(w) Window w; { XWindowAttributes wa; if (TrapXErrors(XGetWindowAttributes(dpy, w, &wa))) return 0; else return (wa.map_state != IsUnmapped); } /* to make a window appear, we may have to de-iconify it*/ ShowClientWindow(cw) ClientWindow cw; { if (!(cw->opening)) { if(!(cw->mapped) && !(cw->status & IconStatus)) { /* client is mapping its window */ if (cw->icon) { SetTarget(cw->icon); { int local_zrt_size = zrt_size; WOOL_send(WOOL_eval, WL_iconify_window_call, (WL_iconify_window_call)); zrt_gc(local_zrt_size); } } else { XMapWindow(dpy, cw->hook); cw->mapped = 1; Update_XA_WM_STATE(cw); } } } else { /* initial map */ ClientWindowExecuteOpening(cw); ClientWindowInitialMap(cw); } } ClientWindowEventHandler(cw, evt) ClientWindow cw; Event evt; { switch (evt -> type) { case MapNotify: /* hook is mapped and were waiting for it */ if (evt -> xmap.window == cw -> hook && ((WOOL_Fsm) cw -> fsm) -> mask & StructureNotifyMask) { WLFsm_action(cw -> fsm, cw, evt); } break; case MapRequest: XMapWindow(dpy, cw -> client); ShowClientWindow(cw); break; /* case UnmapNotify: if (evt -> xunmap.window == cw -> client && cw -> mapped) { XUnmapWindow(dpy, cw -> hook); cw -> mapped = 0; Update_XA_WM_STATE(cw); } break; */ case UnmapNotify: /* Withdraw the window */ if (evt -> xunmap.window == cw -> client && cw -> mapped) { if (cw->icon) ClientWindowUnmap(cw->icon); ClientWindowUnmap(cw); cw->cached_props->user_icon = 0; UnDecorateWindow(cw, 1, 0); } break; case ConfigureNotify: if (evt -> xconfigure.window == cw -> client && evt -> xconfigure.event == cw -> hook && ((WOOL_Fsm) cw -> fsm) -> mask & SubstructureNotifyMask) { WLFsm_action(cw -> fsm, cw, evt); } break; case ConfigureRequest: ConfigureRequestEventHandler(cw, evt); break; case DestroyNotify: if (evt -> xdestroywindow.window == cw -> client && evt -> xdestroywindow.event == cw -> client) { ClientWindowClose(cw); } break; case ColormapNotify: /* if is the active one, re-install */ if (evt -> xcolormap.new) { Colormap old_colormap = cw -> colormap; SetTarget(cw); cw -> colormap = evt -> xcolormap.colormap; if (Context -> InstalledColormapCW == cw) if (cw -> colormap) XInstallColormap(dpy, cw -> colormap); else if (old_colormap) XInstallColormap(dpy, Context -> rootWob -> colormap); } /* else install/uninstall result */ break; case GWMUserEvent: WLFsm_action(cw -> fsm, cw, evt); if (GWM_Propagate_user_events) { if (cw -> client_wob) WOOL_send(WOOL_process_event, cw -> client_wob, (cw -> client_wob, evt)); if (cw -> titlebar) WOOL_send(WOOL_process_event, cw -> titlebar, (cw -> titlebar, evt)); if (cw -> leftbar) WOOL_send(WOOL_process_event, cw -> leftbar, (cw -> leftbar, evt)); if (cw -> rightbar) WOOL_send(WOOL_process_event, cw -> rightbar, (cw -> rightbar, evt)); if (cw -> basebar) WOOL_send(WOOL_process_event, cw -> basebar, (cw -> basebar, evt)); } break; case ClientMessage: /* iccc: for iconifying window */ SetTarget(cw); if (evt -> xclient.message_type == XA_WM_CHANGE_STATE && evt -> xclient.data.l[0] == IconicState) { int local_zrt_size = zrt_size; WOOL_send(WOOL_eval, WL_iconify_window_call, (WL_iconify_window_call)); zrt_gc(local_zrt_size); /* iccc: for deleting window */ } else if (evt -> xclient.message_type == XA_WM_PROTOCOLS && evt -> xclient.data.l[0] == (long) XA_WM_DELETE_WINDOW) { ClientWindow icon = cw -> icon; Wob old_wob = TargetWob; ClientWindow old_client = TargetWindow; ClientWindowClose(cw); if (TargetWob == (Wob) Context -> rootWob && old_client != cw && old_client != icon) SetTarget(old_wob); } else { WLFsm_action(cw -> fsm, cw, evt); } break; case PropertyNotify: SetTarget(cw); if (evt -> xproperty.atom == XA_GWM_EXECUTE) { WlExecGWM_EXECUTE(); } else { GWM_backup_old_property = 1; UpdateCachedProperty(cw -> window, evt -> xproperty.atom); GWM_backup_old_property = 0; WLFsm_action(cw -> fsm, cw, evt); } break; default: #ifdef SHAPE if (GWM_ShapeExtension && evt -> type == GWM_ShapeEventBase + ShapeNotify) ShapeNotifyEventHandler(cw, evt); else #endif /* SHAPE */ { WLFsm_action(cw -> fsm, cw, evt); } } } /* * ConfigureRequestEventHandler is used to decode what operation is really * intended by the configure event to only perform the appropriate action */ /* TO_DO: do only one XConfigure...*/ ConfigureRequestEventHandler(cw, evt) ClientWindow cw; XConfigureRequestEvent *evt; { XWindowChanges values; int real_configure_sent = evt -> value_mask & (CWWidth | CWHeight | CWBorderWidth); /* move: move hook */ /* MOVE HOOK */ if (evt -> value_mask & (CWX | CWY)) { int xgrav, ygrav; GetWinGravityHint(cw, &xgrav, &ygrav); XMoveWindow(dpy, cw -> hook, (evt -> value_mask & CWX ? cw -> box.x = (xgrav == 0 ? evt -> x - cw -> box.borderwidth : evt -> x - cw -> inner_x - cw -> box.borderwidth) : cw -> box.x), (evt -> value_mask & CWY ? cw -> box.y = (ygrav == 0 ? evt -> y - cw -> box.borderwidth : evt -> y - cw -> inner_y - cw -> box.borderwidth) : cw -> box.y)); if(!real_configure_sent) SendSyntheticMoveEvent(cw); } /* resize is handled via recomputing */ if (real_configure_sent) { values.width = evt -> width; values.height = evt -> height; values.border_width = evt -> border_width; XSync(dpy, 0); XSetErrorHandler(NoXError); ErrorStatus = 0; XConfigureWindow(dpy, cw -> client, evt -> value_mask & (CWWidth | CWHeight | CWBorderWidth), &values); XSync(dpy, 0); XSetErrorHandler(XError); if (ErrorStatus) return; /* problem appeared */ ReconfigureClientWindow(cw, cw -> client); } /* stacking change is independant of the rest and done last */ if (evt -> value_mask & CWStackMode) { Wob sibling = 0; if (evt -> value_mask & CWSibling) { /* % to a sibling */ sibling = (Wob) LookUpClient(evt -> above); if (!sibling) sibling = (Wob) LookUpWob(evt -> above); } if (sibling) { values.sibling = sibling->hook; } values.stack_mode = evt -> detail; XConfigureWindow(dpy, cw -> hook, evt -> value_mask & (CWStackMode | (sibling ? CWSibling : 0)), &values); if (cw->map_on_raise && (evt -> value_mask & CWStackMode) && (values.stack_mode == Above || values.stack_mode == TopIf)) { ShowClientWindow(cw); } } } UnDecorateWindow(cw, must_reparent, remap) ClientWindow cw; int must_reparent; /* must reparent window back to root? */ int remap; /* must try to re-map window? */ { Window client = cw -> window -> client; Wob wob = cw -> window -> client_wob; int oldbw = cw -> window -> old_inner_borderwidth; int must_remap; cw = cw -> window; if (wob) { wob -> parent = (Wob) Context -> rootWob; } if (remap) must_remap = (Update_XA_WM_STATE(cw) == WM_STATE_Withdrawn ? 0 : 1); else must_remap = 0; XSetErrorHandler(NoXError); if (cw -> mapped) XUnmapWindow(dpy, cw -> hook); if (must_reparent) { ObeyWinGravityHint(cw, 0); XReparentWindow(dpy, client, Context -> root, cw -> box.x, cw -> box.y); SendSyntheticMoveEvent(cw); if (!wob) XRemoveFromSaveSet(dpy, client); } /* reparent icon-window if client created it */ if (cw->icon && cw->icon->client && (!cw->icon->client_wob)) { XReparentWindow(dpy, cw->icon->client, Context -> root, 0, 0); XRemoveFromSaveSet(dpy, cw->icon->client); XUnmapWindow(dpy, cw->icon->client); } if (!cw -> client_shaped) XSetWindowBorderWidth(dpy, client, oldbw); if (cw -> client_wob) cw -> client_wob -> status &= TopLevelXWindowStatus; if (must_remap) XMapWindow(dpy, cw -> client); ClientWindowClose(cw); XSync(dpy, 0); XSetErrorHandler(XError); } /* if a decoration aborts, we must put it back on screen! */ ShowUndecoratedWindow(cw) ClientWindow cw; { XSync(dpy, 0); GWM_ProcessEvents(0); /* empty events */ if (cw) { cw->mapped = 0; /* forces a remap */ ClientWindowMap(cw); } } ReconfigureClientWindow(cw, culprit) ClientWindow cw; Wob culprit; /* cw, client or bar */ { int x = cw -> box.x, y = cw -> box.y; int inner_x = cw -> inner_x, inner_y = cw -> inner_y; if (culprit == (Wob) cw -> client || culprit == cw -> client_wob || (!cw -> client)) { ClientWindowComputeGeometry(cw); } ClientWindowComputeBarDims(cw); /* if (culprit != (Wob) cw -> titlebar) */ ReconfigureBar(cw -> titlebar, cw); /* if (culprit != (Wob) cw -> leftbar) */ ReconfigureBar(cw -> leftbar, cw); /* if (culprit != (Wob) cw -> rightbar) */ ReconfigureBar(cw -> rightbar, cw); /* if (culprit != (Wob) cw -> basebar) */ ReconfigureBar(cw -> basebar, cw); XMoveResizeWindow(dpy, cw -> hook, cw -> box.x = x, cw -> box.y = y, cw -> box.width, cw -> box.height); if (inner_x != cw -> inner_x || inner_y != cw -> inner_y) XMoveWindow(dpy, cw -> client, cw -> inner_x, cw -> inner_y); #ifdef SHAPE /* do not reshape if client reshaped, it will send an event later */ if (WindowIsShaped(cw) && !((culprit == (Wob) cw -> client) && !cw -> client_wob && cw -> client_shaped)) ClientWindowSetShape(cw); #endif /* SHAPE */ } /* * transforms outer sizes in inner ones */ dims_outer_to_inner(cw, pw, ph) ClientWindow cw; int *pw, *ph; { *pw = *pw - (cw -> box.width - cw -> inner_width) - 2 * cw -> box.borderwidth; *ph = *ph - (cw -> box.height - cw -> inner_height) - 2 * cw -> box.borderwidth; } /****************\ * * * window groups * * * \****************/ /* Maintains the group list of a group_leader * In the client_group field of the cw, we find: * - for the leaded, the cw of the leader. * - for the leader, the list (WOOL_List) of grouped sons * first one being the leader itself */ AddWindowToGroupLeader(cw, group_leader) ClientWindow cw, group_leader; { WOOL_List *gwlgp = (WOOL_List *) & (group_leader -> cached_props -> client_group); /* if leader's group is not yet initialised, do it */ if (!(*gwlgp)) { if (cw != group_leader) { /* follower */ AddWindowToGroupLeader(group_leader, group_leader); AddWindowToGroupLeader(cw, group_leader); } else { /* leader */ increase_reference(*gwlgp = wool_list_make(1)); increase_reference((*gwlgp) -> list[0] = (WOOL_OBJECT) WLNumber_make(group_leader)); } /* leader is initialized */ } else if ((*gwlgp) -> type == WLList) { int i; WOOL_List old_list; for (i = 0; i < (*gwlgp) -> size; i++) if ((*gwlgp) -> list[i] == (WOOL_OBJECT) cw) return; old_list = *gwlgp; increase_reference(*gwlgp = wool_list_make((*gwlgp) -> size + 1)); copy_n_objects(old_list -> list, (*gwlgp) -> list, old_list -> size); decrease_reference(old_list); increase_reference((*gwlgp) -> list[(*gwlgp) -> size - 1] = (WOOL_OBJECT) WLNumber_make(cw)); if((cw -> cached_props -> client_group) && (cw -> cached_props -> client_group -> type == WLList)) decrease_reference(cw -> cached_props -> client_group); cw -> cached_props -> client_group = (WOOL_OBJECT) group_leader; } } /* called when a window is closed if client_group not void */ RemoveWindowFromGroup(cw) ClientWindow cw; { WOOL_List *gwlgp = (WOOL_List *) & (cw -> cached_props -> client_group), list; int i; if ((*gwlgp) -> type == WLList) { /* leader */ ClientWindow son; list = (*gwlgp); for (i = 0; i < list -> size; i++) { son = (ClientWindow) ((WOOL_Number) list -> list[i]) -> number; if (WobIsValid(son)) son -> cached_props -> client_group = NULL; } decrease_reference(list); } else { /* follower */ ClientWindow leader = (ClientWindow) cw->cached_props->client_group; list = (WOOL_List) leader -> cached_props -> client_group; if (list -> type == WLList) { cw -> cached_props -> client_group = NULL; i = 0; while (i < list -> size) { if (((WOOL_Number) list -> list[i]) -> number == (Num) cw) break; i++; } if (i == list -> size) /* not in list (should not happen) */ return; if (--(list -> size) == 1) { /* only leader remains in list so destroy the list */ leader -> cached_props -> client_group = NULL; decrease_reference(list); } else { /* remove window from leader's list */ while (i++ < list -> size) list -> list[i - 1] = list -> list[i]; } } } } /* * wool interface */ WOOL_OBJECT wool_window_group_get() { ClientWindow cw = TargetWindow -> window; if (cw -> cached_props -> client_group) { /* group exists */ if (cw -> cached_props -> client_group -> type == WLList) { /* lead */ return cw -> cached_props -> client_group; } else { /* follower */ WOOL_OBJECT group = ((ClientWindow) (cw -> cached_props -> client_group)) -> cached_props -> client_group; if (group -> type == WLList) { /* sanity check */ return group; } else { cw -> cached_props -> client_group = 0; return NIL; } } } else { /* no group */ return NIL; } } WOOL_OBJECT wool_window_group_set(group_leader_num) WOOL_Number group_leader_num; { ClientWindow cw = TargetWindow -> window; ClientWindow group_leader; if (group_leader_num -> type == WLNumber) { group_leader = (ClientWindow) group_leader_num -> number; } else if (group_leader_num -> type == WLList) { group_leader = (ClientWindow) ((WOOL_Number) ((WOOL_List) group_leader_num) -> list[0]) -> number; } else if(cw-> cached_props -> client_group) { RemoveWindowFromGroup(cw); return NIL; } AddWindowToGroupLeader(cw, group_leader); return (WOOL_OBJECT) group_leader_num; } ClientWindow ClientWindowLeader(cw) ClientWindow cw; { if (cw->cached_props->client_group) { /* group exists */ if (cw->cached_props->client_group->type == WLList) { /* lead */ return cw; } else { /* follower */ return (ClientWindow) (cw->cached_props->client_group); } } else { return 0; } } ClientWindowRecordClient(cw) ClientWindow cw; { XSaveContext(dpy, cw -> client, client_context, (caddr_t)cw); } #ifdef SHAPE /* non-rectangular extension: * set the frame to the shape of client +bars */ WindowIsShaped(cw) ClientWindow cw; { if (cw -> client_shaped) return 1; if (((cw -> titlebar) && (cw -> titlebar -> shaped)) || ((cw -> basebar) && (cw -> basebar -> shaped)) || ((cw -> leftbar) && (cw -> leftbar -> shaped)) || ((cw -> rightbar) && (cw -> rightbar -> shaped))) return 1; return 0; } ClientWindowSetShape(cw) ClientWindow cw; { XRectangle rect; int initop = ShapeSet; if (cw -> box.borderwidth && GWM_allow_border_on_shaped_windows) { /* disabled for back compat */ rect.x = - cw -> box.borderwidth; rect.y = - cw -> box.borderwidth; rect.width = cw -> box.width + 2 * cw -> box.borderwidth; rect.height = cw -> box.height + 2 * cw -> box.borderwidth; XShapeCombineRectangles(dpy, cw -> hook, ShapeBounding, 0, 0, &rect, 1, ShapeSet, 0); rect.x = 0; rect.y = 0; rect.width = cw -> box.width; rect.height = cw -> box.height; XShapeCombineRectangles(dpy, cw -> hook, ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0); initop = ShapeUnion; } if (cw -> client_shaped) XShapeCombineShape (dpy, cw -> hook, ShapeBounding, cw -> inner_x, cw -> inner_y, cw -> client, ShapeBounding, initop); else { rect.x = cw -> inner_x; rect.y = cw -> inner_y; rect.width = cw -> inner_width + 2 * cw -> inner_borderwidth; rect.height = cw -> inner_height + 2 * cw -> inner_borderwidth; XShapeCombineRectangles(dpy, cw -> hook, ShapeBounding, 0, 0, &rect, 1, initop, 0); } if (cw -> titlebar) XShapeCombineShape (dpy, cw -> hook, ShapeBounding, cw -> titlebar -> box.borderwidth, cw -> titlebar -> box.borderwidth, cw -> titlebar -> hook, ShapeBounding, ShapeUnion); if (cw -> leftbar) XShapeCombineShape (dpy, cw -> hook, ShapeBounding, cw -> leftbar -> box.borderwidth, cw -> leftbar -> box.borderwidth + cw -> inner_y, cw -> leftbar -> hook, ShapeBounding, ShapeUnion); if (cw -> rightbar) XShapeCombineShape (dpy, cw -> hook, ShapeBounding, cw -> inner_x + cw -> inner_width + cw -> rightbar -> box.borderwidth + 2 * cw -> inner_borderwidth, cw -> rightbar -> box.borderwidth + cw -> inner_y, cw -> rightbar -> hook, ShapeBounding, ShapeUnion); if (cw -> basebar) XShapeCombineShape (dpy, cw -> hook, ShapeBounding, cw -> basebar -> box.borderwidth, cw -> inner_y + cw -> inner_height + cw -> basebar -> box.borderwidth + 2 * cw -> inner_borderwidth, cw -> basebar -> hook, ShapeBounding, ShapeUnion); } /* what to do if shape changes */ ShapeNotifyEventHandler(cw, evt) ClientWindow cw; XShapeEvent *evt; { if (evt -> kind == ShapeBounding && evt -> window == cw -> client) { cw -> client_shaped = evt -> shaped; if (WindowIsShaped(cw)) ClientWindowSetShape(cw); else XShapeCombineMask (dpy, cw -> hook, ShapeBounding, 0, 0, None, ShapeSet); } } WOOL_OBJECT wool_window_has_shaped_client() { if (TargetWindow -> client_shaped) return TRU; else return NIL; } #endif /* SHAPE */