/*****************************************************************************/ /** 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. **/ /*****************************************************************************/ /********************************************************************** * * $XConsortium: add_window.c,v 1.140 90/03/23 11:42:33 jim Exp $ * * Add a new window, put the titlbar and other stuff around * the window * * 31-Mar-88 Tom LaStrange Initial Version. * **********************************************************************/ #if !defined(lint) && !defined(SABER) static char RCSinfo[]= "$XConsortium: add_window.c,v 1.140 90/03/23 11:42:33 jim Exp $"; #endif #include #include "twm.h" #include #include "add_window.h" #include "util.h" #include "resize.h" #include "parse.h" #include "list.h" #include "events.h" #include "menus.h" #include "screen.h" #include "iconmgr.h" #include "move.h" #define gray_width 2 #define gray_height 2 static char gray_bits[] = { 0x02, 0x01}; extern int FromVirtualDesktop; int AddingX; int AddingY; int AddingW; int AddingH; static int PlaceX = 50; static int PlaceY = 50; static void CreateWindowTitlebarButtons(); static void getTWM_FLAGS(); void GetUserMenu(); char NoName[] = "Untitled"; /* name if no name is specified */ /************************************************************************ * * Procedure: * GetGravityOffsets - map gravity to (x,y) offset signs for adding * to x and y when window is mapped to get proper placement. * ************************************************************************ */ GetGravityOffsets (tmp, xp, yp) TwmWindow *tmp; /* window from which to get gravity */ int *xp, *yp; /* return values */ { static struct _gravity_offset { int x, y; } gravity_offsets[11] = { { 0, 0 }, /* ForgetGravity */ { -1, -1 }, /* NorthWestGravity */ { 0, -1 }, /* NorthGravity */ { 1, -1 }, /* NorthEastGravity */ { -1, 0 }, /* WestGravity */ { 0, 0 }, /* CenterGravity */ { 1, 0 }, /* EastGravity */ { -1, 1 }, /* SouthWestGravity */ { 0, 1 }, /* SouthGravity */ { 1, 1 }, /* SouthEastGravity */ { 0, 0 }, /* StaticGravity */ }; register int g = ((tmp->hints.flags & PWinGravity) ? tmp->hints.win_gravity : NorthWestGravity); if (g < ForgetGravity || g > StaticGravity) { *xp = *yp = 0; } else { *xp = gravity_offsets[g].x; *yp = gravity_offsets[g].y; } } /*********************************************************************** * * Procedure: * AddWindow - add a new window to the twm list * * Returned Value: * (TwmWindow *) - pointer to the TwmWindow structure * * Inputs: * w - the window id of the window to add * iconm - flag to tell if this is an icon manager window * iconp - pointer to icon manager struct * *********************************************************************** */ TwmWindow * AddWindow(w, iconm, iconp) Window w; int iconm; IconMgr *iconp; { TwmWindow *tmp_win; /* new twm window structure */ int stat; XEvent event; unsigned long valuemask; /* mask for create windows */ XSetWindowAttributes attributes; /* attributes for create windows */ int width, height; /* tmp variable */ Atom actual_type; int actual_format; unsigned long nitems, bytesafter; int ask_user; /* don't know where to put the window */ long supplied = 0; int gravx, gravy; /* gravity signs for positioning */ int namelen; int bw2; int cancel; /* cancel flag for window move */ int tmpX; /* temp variable */ int saveDelta; /* save the Scr->MoveDelta */ int saveOpaque; /* save the Scr->OpaqueMove */ #ifdef DEBUG fprintf(stderr, "AddWindow: w = 0x%x\n", w); #endif /* allocate space for the twm window */ tmp_win = (TwmWindow *)calloc(1, sizeof(TwmWindow)); tmp_win->w = w; tmp_win->zoomed = ZOOM_NONE; tmp_win->iconmgr = iconm; tmp_win->iconmgrp = iconp; tmp_win->cmaps.number_cwins = 0; XSelectInput(dpy, tmp_win->w, PropertyChangeMask); XGetWindowAttributes(dpy, tmp_win->w, &tmp_win->attr); XFetchName(dpy, tmp_win->w, &tmp_win->name); tmp_win->class = NoClass; XGetClassHint(dpy, tmp_win->w, &tmp_win->class); FetchWmProtocols (tmp_win); FetchWmColormapWindows (tmp_win); /* * do initial clip; should look at window gravity */ if (tmp_win->attr.width > Scr->MaxWindowWidth) tmp_win->attr.width = Scr->MaxWindowWidth; if (tmp_win->attr.height > Scr->MaxWindowHeight) tmp_win->attr.height = Scr->MaxWindowHeight; tmp_win->wmhints = XGetWMHints(dpy, tmp_win->w); if (tmp_win->wmhints && (tmp_win->wmhints->flags & WindowGroupHint)) tmp_win->group = tmp_win->wmhints->window_group; else tmp_win->group = None; if (!XGetWMNormalHints (dpy, tmp_win->w, &tmp_win->hints, &supplied)) tmp_win->hints.flags = 0; /* * The July 27, 1988 draft of the ICCCM ignores the size and position * fields in the WM_NORMAL_HINTS property. */ tmp_win->transient = Transient(tmp_win->w); /* * Don't bother user if: * * o the window is a transient, or * * o a USPosition was requested, or * * o a PPosition was requested and UsePPosition is ON or * NON_ZERO if the window is at other than (0,0) */ ask_user = TRUE; if (tmp_win->transient || (tmp_win->hints.flags & USPosition) || ((tmp_win->hints.flags & PPosition) && Scr->UsePPosition && (Scr->UsePPosition == PPOS_ON || tmp_win->attr.x != 0 || tmp_win->attr.y != 0))) ask_user = FALSE; if (tmp_win->name == NULL) tmp_win->name = NoName; if (tmp_win->class.res_name == NULL) tmp_win->class.res_name = NoName; if (tmp_win->class.res_class == NULL) tmp_win->class.res_class = NoName; tmp_win->full_name = tmp_win->name; namelen = strlen (tmp_win->name); if (RestartPreviousState) getTWM_FLAGS(tmp_win->w, &tmp_win->flags); if (Scr->VirtualDesktop) { tmp_win->sticky = (short)LookInList(Scr->StickyL, tmp_win->full_name, &tmp_win->class); if (tmp_win->w == Scr->Panner) tmp_win->sticky = True; if (tmp_win->flags & TWM_FLAGS_VALID) { if (tmp_win->flags & TWM_FLAGS_STICKY) tmp_win->sticky = True; else tmp_win->sticky = False; } } /* set flags for twm restart */ SetTWM_FLAGS(tmp_win); tmp_win->highlight = Scr->Highlight && (!(short)LookInList(Scr->NoHighlight, tmp_win->full_name, &tmp_win->class)); tmp_win->stackmode = Scr->StackMode && (!(short)LookInList(Scr->NoStackModeL, tmp_win->full_name, &tmp_win->class)); tmp_win->titlehighlight = Scr->TitleHighlight && (!(short)LookInList(Scr->NoTitleHighlight, tmp_win->full_name, &tmp_win->class)); tmp_win->auto_raise = (short)LookInList(Scr->AutoRaise, tmp_win->full_name, &tmp_win->class); if (tmp_win->auto_raise) Scr->NumAutoRaises++; tmp_win->iconify_by_unmapping = Scr->IconifyByUnmapping; if (Scr->IconifyByUnmapping) { tmp_win->iconify_by_unmapping = iconm ? FALSE : !(short)LookInList(Scr->DontIconify, tmp_win->full_name, &tmp_win->class); } tmp_win->iconify_by_unmapping |= (short)LookInList(Scr->IconifyByUn, tmp_win->full_name, &tmp_win->class); if (LookInList(Scr->WindowRingL, tmp_win->full_name, &tmp_win->class)) { if (Scr->Ring) { tmp_win->ring.next = Scr->Ring->ring.next; if (Scr->Ring->ring.next->ring.prev) Scr->Ring->ring.next->ring.prev = tmp_win; Scr->Ring->ring.next = tmp_win; tmp_win->ring.prev = Scr->Ring; } else { tmp_win->ring.next = tmp_win->ring.prev = Scr->Ring = tmp_win; } } else tmp_win->ring.next = tmp_win->ring.prev = NULL; tmp_win->ring.cursor_valid = False; tmp_win->squeeze_info = NULL; #ifdef SHAPE /* * get the squeeze information; note that this does not have to be freed * since it is coming from the screen list */ if (HasShape) { if (!LookInList (Scr->DontSqueezeTitleL, tmp_win->full_name, &tmp_win->class)) { tmp_win->squeeze_info = (SqueezeInfo *) LookInList (Scr->SqueezeTitleL, tmp_win->full_name, &tmp_win->class); if (!tmp_win->squeeze_info) { static SqueezeInfo default_squeeze = { J_LEFT, 0, 0 }; if (Scr->SqueezeTitle) tmp_win->squeeze_info = &default_squeeze; } } } #endif tmp_win->old_bw = tmp_win->attr.border_width; if (Scr->ClientBorderWidth) { tmp_win->frame_bw = tmp_win->old_bw; } else { tmp_win->frame_bw = Scr->BorderWidth; } bw2 = tmp_win->frame_bw * 2; tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw; if (Scr->NoTitlebar) tmp_win->title_height = 0; if (LookInList(Scr->MakeTitle, tmp_win->full_name, &tmp_win->class)) tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw; if (LookInList(Scr->NoTitle, tmp_win->full_name, &tmp_win->class)) tmp_win->title_height = 0; tmp_win->icon_title = !Scr->NoIconTitle; if (LookInList(Scr->NoIconTitleL, tmp_win->full_name, &tmp_win->class)) tmp_win->icon_title = False; if (LookInList(Scr->IconTitleL, tmp_win->full_name, &tmp_win->class)) tmp_win->icon_title = True; /* if it is a transient window, don't put a title on it */ if (tmp_win->transient && !Scr->DecorateTransients) tmp_win->title_height = 0; if (LookInList(Scr->StartIconified, tmp_win->full_name, &tmp_win->class)) { if (!tmp_win->wmhints) { tmp_win->wmhints = (XWMHints *)malloc(sizeof(XWMHints)); tmp_win->wmhints->flags = 0; } tmp_win->wmhints->initial_state = IconicState; tmp_win->wmhints->flags |= StateHint; } if (!(supplied & PWinGravity)) SimulateWinGravity (tmp_win); GetGravityOffsets (tmp_win, &gravx, &gravy); #ifdef DEBUG fprintf(stderr, " position window %d, %d %dx%d\n", tmp_win->attr.x, tmp_win->attr.y, tmp_win->attr.width, tmp_win->attr.height); #endif if (!Scr->ClientBorderWidth) { /* need to adjust for twm borders */ int delta = tmp_win->attr.border_width - tmp_win->frame_bw; tmp_win->attr.x += gravx * delta; tmp_win->attr.y += gravy * delta; } tmp_win->title_width = tmp_win->attr.width; if (tmp_win->old_bw) XSetWindowBorderWidth (dpy, tmp_win->w, 0); tmp_win->name_width = XTextWidth(Scr->TitleBarFont.font, tmp_win->name, namelen); if (XGetWindowProperty (dpy, tmp_win->w, XA_WM_ICON_NAME, 0L, 200L, False, XA_STRING, &actual_type, &actual_format, &nitems, &bytesafter,(unsigned char **)&tmp_win->icon_name)) tmp_win->icon_name = tmp_win->name; if (tmp_win->icon_name == NULL) tmp_win->icon_name = tmp_win->name; tmp_win->iconified = FALSE; tmp_win->icon = FALSE; tmp_win->icon_on = FALSE; GetUserMenu(tmp_win); XGrabServer(dpy); /* * 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. */ if (XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0) { free((char *)tmp_win); XUngrabServer(dpy); return(NULL); } /* add the window into the twm list */ tmp_win->next = Scr->TwmRoot.next; if (Scr->TwmRoot.next != NULL) Scr->TwmRoot.next->prev = tmp_win; tmp_win->prev = &Scr->TwmRoot; Scr->TwmRoot.next = tmp_win; /* get all the colors for the window */ tmp_win->border = Scr->BorderColor; tmp_win->icon_border = Scr->IconBorderColor; tmp_win->border_tile.fore = Scr->BorderTileC.fore; tmp_win->border_tile.back = Scr->BorderTileC.back; tmp_win->title.fore = Scr->TitleC.fore; tmp_win->title.back = Scr->TitleC.back; tmp_win->iconc.fore = Scr->IconC.fore; tmp_win->iconc.back = Scr->IconC.back; /* * for compatibility reasons, let the virtual colors default * to the titlebar colors if no virtual colors have been specified. */ if (Scr->VirtualC.fore != UNKNOWN_PIXEL) tmp_win->virtual.fore = Scr->VirtualC.fore; else tmp_win->virtual.fore = Scr->TitleC.fore; if (Scr->VirtualC.back != UNKNOWN_PIXEL) tmp_win->virtual.back = Scr->VirtualC.back; else tmp_win->virtual.back = Scr->TitleC.back; if (Scr->VirtualDesktop) { GetColorFromList(Scr->TitleForegroundL, tmp_win->full_name, &tmp_win->class, &tmp_win->virtual.fore); GetColorFromList(Scr->TitleBackgroundL, tmp_win->full_name, &tmp_win->class, &tmp_win->virtual.back); GetColorFromList(Scr->VirtualForegroundL, tmp_win->full_name, &tmp_win->class, &tmp_win->virtual.fore); GetColorFromList(Scr->VirtualBackgroundL, tmp_win->full_name, &tmp_win->class, &tmp_win->virtual.back); } GetColorFromList(Scr->BorderColorL, tmp_win->full_name, &tmp_win->class, &tmp_win->border); GetColorFromList(Scr->IconBorderColorL, tmp_win->full_name, &tmp_win->class, &tmp_win->icon_border); GetColorFromList(Scr->BorderTileForegroundL, tmp_win->full_name, &tmp_win->class, &tmp_win->border_tile.fore); GetColorFromList(Scr->BorderTileBackgroundL, tmp_win->full_name, &tmp_win->class, &tmp_win->border_tile.back); GetColorFromList(Scr->TitleForegroundL, tmp_win->full_name, &tmp_win->class, &tmp_win->title.fore); GetColorFromList(Scr->TitleBackgroundL, tmp_win->full_name, &tmp_win->class, &tmp_win->title.back); GetColorFromList(Scr->IconForegroundL, tmp_win->full_name, &tmp_win->class, &tmp_win->iconc.fore); GetColorFromList(Scr->IconBackgroundL, tmp_win->full_name, &tmp_win->class, &tmp_win->iconc.back); /* create windows */ tmp_win->frame_width = tmp_win->attr.width; tmp_win->frame_height = tmp_win->attr.height + tmp_win->title_height; valuemask = CWBackPixmap | CWBorderPixel | CWCursor | CWEventMask; attributes.background_pixmap = None; attributes.border_pixel = tmp_win->border; attributes.cursor = Scr->FrameCursor; attributes.event_mask = (SubstructureRedirectMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask); if (tmp_win->attr.save_under) { attributes.save_under = True; valuemask |= CWSaveUnder; } if (Scr->VirtualDesktop) { if (tmp_win->sticky && Scr->StickyAbove) tmp_win->root = Scr->Root; else tmp_win->root = Scr->VirtualDesktop; tmp_win->virtualWindow = MakeVirtual(tmp_win, tmp_win->frame_x, tmp_win->frame_y, tmp_win->frame_width, tmp_win->frame_height, tmp_win->virtual.back, tmp_win->border); } else tmp_win->root = Scr->Root; tmp_win->frame = XCreateWindow (dpy, tmp_win->root, 0, 0, (unsigned int) tmp_win->frame_width, (unsigned int) tmp_win->frame_height, (unsigned int) tmp_win->frame_bw, Scr->d_depth, (unsigned int) CopyFromParent, Scr->d_visual, valuemask, &attributes); if (tmp_win->title_height) { valuemask = (CWEventMask | CWBorderPixel | CWBackPixel); attributes.event_mask = (KeyPressMask | ButtonPressMask | ButtonReleaseMask | ExposureMask); attributes.border_pixel = tmp_win->border; attributes.background_pixel = tmp_win->title.back; tmp_win->title_w = XCreateWindow (dpy, tmp_win->frame, -tmp_win->frame_bw, -tmp_win->frame_bw, (unsigned int) tmp_win->attr.width, (unsigned int) Scr->TitleHeight, (unsigned int) tmp_win->frame_bw, Scr->d_depth, (unsigned int) CopyFromParent, Scr->d_visual, valuemask, &attributes); } else { tmp_win->title_w = 0; tmp_win->squeeze_info = NULL; } if (tmp_win->highlight) { tmp_win->gray = XCreatePixmapFromBitmapData(dpy, Scr->Root, gray_bits, gray_width, gray_height, tmp_win->border_tile.fore, tmp_win->border_tile.back, Scr->d_depth); SetBorder (tmp_win, False); } else tmp_win->gray = None; if (tmp_win->title_w) { CreateWindowTitlebarButtons (tmp_win); ComputeTitleLocation (tmp_win); XMoveWindow (dpy, tmp_win->title_w, tmp_win->title_x, tmp_win->title_y); XDefineCursor(dpy, tmp_win->title_w, Scr->TitleCursor); } valuemask = (CWEventMask | CWDontPropagate); attributes.event_mask = (StructureNotifyMask | PropertyChangeMask | ColormapChangeMask | VisibilityChangeMask | EnterWindowMask | LeaveWindowMask); if (tmp_win->w == Scr->Panner) attributes.event_mask |= ExposureMask; attributes.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask; XChangeWindowAttributes (dpy, tmp_win->w, valuemask, &attributes); #ifdef SHAPE if (HasShape) XShapeSelectInput (dpy, tmp_win->w, ShapeNotifyMask); #endif if (tmp_win->title_w) { XMapWindow (dpy, tmp_win->title_w); } #ifdef SHAPE if (HasShape) { int xws, yws, xbs, ybs; unsigned wws, hws, wbs, hbs; int boundingShaped, clipShaped; XShapeSelectInput (dpy, tmp_win->w, ShapeNotifyMask); XShapeQueryExtents (dpy, tmp_win->w, &boundingShaped, &xws, &yws, &wws, &hws, &clipShaped, &xbs, &ybs, &wbs, &hbs); tmp_win->wShaped = boundingShaped; } #endif if (!tmp_win->iconmgr) XAddToSaveSet(dpy, tmp_win->w); XReparentWindow(dpy, tmp_win->w, tmp_win->frame, 0, tmp_win->title_height); /* * Reparenting generates an UnmapNotify event, followed by a MapNotify. * Set the map state to FALSE to prevent a transition back to * WithdrawnState in HandleUnmapNotify. Map state gets set correctly * again in HandleMapNotify. */ tmp_win->mapped = FALSE; /* * do any prompting for position */ if (HandlingEvents && ask_user) { if (Scr->RandomPlacement) { /* just stick it somewhere */ if ((PlaceX + tmp_win->attr.width) > Scr->MyDisplayWidth) PlaceX = 50; if ((PlaceY + tmp_win->attr.height) > Scr->MyDisplayHeight) PlaceY = 50; tmp_win->attr.x = PlaceX; tmp_win->attr.y = PlaceY; PlaceX += 30; PlaceY += 30; if (tmp_win->root == Scr->VirtualDesktop) { tmp_win->attr.x += Scr->vdtPositionX; tmp_win->attr.y += Scr->vdtPositionY; } } else { /* else prompt */ if (!(tmp_win->wmhints && tmp_win->wmhints->flags & StateHint && tmp_win->wmhints->initial_state == IconicState)) { Bool firsttime = True; /* better wait until all the mouse buttons have been * released. */ while (TRUE) { XUngrabServer(dpy); XSync(dpy, 0); XGrabServer(dpy); JunkMask = 0; if (!XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild, &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask)) JunkMask = 0; JunkMask &= (Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask); /* * watch out for changing screens */ if (firsttime) { if (JunkRoot != Scr->Root) { register int scrnum; for (scrnum = 0; scrnum < NumScreens; scrnum++) { if (JunkRoot == RootWindow (dpy, scrnum)) break; } if (scrnum != NumScreens) PreviousScreen = scrnum; } firsttime = False; } /* * wait for buttons to come up; yuck */ if (JunkMask != 0) continue; /* * this will cause a warp to the indicated root */ stat = XGrabPointer(dpy, Scr->Root, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask, GrabModeAsync, GrabModeAsync, Scr->Root, UpperLeftCursor, CurrentTime); if (stat == GrabSuccess) break; } width = (SIZE_HINDENT + XTextWidth (Scr->SizeFont.font, tmp_win->name, namelen)); height = Scr->SizeFont.height + SIZE_VINDENT * 2; XResizeWindow (dpy, Scr->SizeWindow, width + SIZE_HINDENT, height); XMapRaised(dpy, Scr->SizeWindow); InstallRootColormap(); FBF(Scr->DefaultC.fore, Scr->DefaultC.back, Scr->SizeFont.font->fid); XDrawImageString (dpy, Scr->SizeWindow, Scr->NormalGC, SIZE_HINDENT, SIZE_VINDENT + Scr->SizeFont.font->ascent, tmp_win->name, namelen); AddingW = tmp_win->attr.width + bw2; AddingH = tmp_win->attr.height + tmp_win->title_height + bw2; XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild, &AddingX, &AddingY, &JunkX, &JunkY, &JunkMask); if (tmp_win->root == Scr->VirtualDesktop) XMoveWindow(dpy, tmp_win->frame, AddingX+Scr->vdtPositionX, AddingY+Scr->vdtPositionY); else XMoveWindow(dpy, tmp_win->frame, AddingX, AddingY); saveDelta = Scr->MoveDelta; saveOpaque = Scr->OpaqueMove; Scr->MoveDelta = 0; Scr->OpaqueMove = False; StartMove(tmp_win, tmp_win->frame, tmp_win->title_height, &AddingX, &AddingY, &cancel, OUT_PANNER, 1, 0, 0, True, False); Scr->MoveDelta = saveDelta; Scr->OpaqueMove = saveOpaque; if (cancel == Button2) { int lastx, lasty; Scr->SizeStringOffset = width + XTextWidth(Scr->SizeFont.font, ": ", 2); XResizeWindow (dpy, Scr->SizeWindow, Scr->SizeStringOffset + Scr->SizeStringWidth, height); XDrawImageString (dpy, Scr->SizeWindow, Scr->NormalGC, width, SIZE_VINDENT + Scr->SizeFont.font->ascent, ": ", 2); if (Scr->AutoRelativeResize) { int dx = (tmp_win->attr.width / 4); int dy = (tmp_win->attr.height / 4); int offsetx, offsety; if (tmp_win->root == Scr->VirtualDesktop) { offsetx = Scr->vdtPositionX; offsety = Scr->vdtPositionY; } else { offsetx = 0; offsety = 0; } #define HALF_AVE_CURSOR_SIZE 8 /* so that it is visible */ if (dx < HALF_AVE_CURSOR_SIZE) dx = HALF_AVE_CURSOR_SIZE; if (dy < HALF_AVE_CURSOR_SIZE) dy = HALF_AVE_CURSOR_SIZE; #undef HALF_AVE_CURSOR_SIZE dx += (tmp_win->frame_bw + 1); dy += (bw2 + tmp_win->title_height + 1); if (AddingX + dx >= (Scr->MyDisplayWidth + offsetx)) dx = Scr->MyDisplayWidth - AddingX - 1 + offsetx; if (AddingY + dy >= (Scr->MyDisplayHeight + offsety)) dy = Scr->MyDisplayHeight - AddingY - 1 + offsety; if (dx > 0 && dy > 0) XWarpPointer (dpy, None, None, 0, 0, 0, 0, dx, dy); } else { XWarpPointer (dpy, None, tmp_win->root, 0, 0, 0, 0, AddingX + AddingW/2, AddingY + AddingH/2); } AddStartResize(tmp_win, AddingX, AddingY, AddingW, AddingH); lastx = -10000; lasty = -10000; while (TRUE) { /* * XXX - if we are going to do a loop, we ought to consider * using multiple GXxor lines so that we don't need to * grab the server. */ XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild, &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask); if (lastx != AddingX || lasty != AddingY) { DoResize(AddingX, AddingY, tmp_win); lastx = AddingX; lasty = AddingY; } if (XCheckMaskEvent(dpy, ButtonReleaseMask, &event)) { AddEndResize(tmp_win); break; } } MoveOutline(tmp_win->root, 0, 0, 0, 0, 0, 0); } else if (cancel == Button3) { int maxw = Scr->MyDisplayWidth - AddingX - bw2; int maxh = Scr->MyDisplayHeight - AddingY - bw2; if (tmp_win->root == Scr->VirtualDesktop) { maxw += Scr->vdtPositionX; maxh += Scr->vdtPositionY; } /* * Make window go to bottom of screen, and clip to right edge. * This is useful when popping up large windows and fixed * column text windows. */ if (AddingW > maxw) AddingW = maxw; AddingH = maxh; ConstrainSize (tmp_win, &AddingW, &AddingH); /* w/o borders */ AddingW += bw2; AddingH += bw2; } else { XMaskEvent(dpy, ButtonReleaseMask, &event); } XUnmapWindow(dpy, Scr->SizeWindow); UninstallRootColormap(); XUngrabPointer(dpy, CurrentTime); tmp_win->attr.x = AddingX; tmp_win->attr.y = AddingY + tmp_win->title_height; tmp_win->attr.width = AddingW - bw2; tmp_win->attr.height = AddingH - tmp_win->title_height - bw2; XUngrabServer(dpy); } } } else { /* put it where asked, mod title bar */ /* if the gravity is towards the top, move it by the title height */ if (gravy < 0) tmp_win->attr.y -= gravy * tmp_win->title_height; } tmp_win->frame_x = tmp_win->attr.x + tmp_win->old_bw - tmp_win->frame_bw; tmp_win->frame_y = tmp_win->attr.y - tmp_win->title_height + tmp_win->old_bw - tmp_win->frame_bw; tmp_win->frame_width = tmp_win->attr.width; tmp_win->frame_height = tmp_win->attr.height + tmp_win->title_height; /* Possibly adjust the position of the window if PPosition is * being used. In our case, if PPosition is set, we will translate * the coordinates of the window into virtual desktop coordinates */ if ((tmp_win->root == Scr->VirtualDesktop) && ((!FromVirtualDesktop && tmp_win->transient) || (ask_user == FALSE && (tmp_win->hints.flags & PPosition)))) { tmp_win->frame_x += Scr->vdtPositionX; tmp_win->frame_y += Scr->vdtPositionY; } /* tell the window what his root window id is */ /* this MUST com before SetupFrame so the synthetic ConfigureNotify * event follows this property */ SetSWM_ROOT(tmp_win); tmpX = tmp_win->frame_x; tmp_win->frame_x = -tmpX; /* this will case a synthetice ConfigureNotify event */ SetupFrame (tmp_win, tmpX, tmp_win->frame_y, tmp_win->frame_width, tmp_win->frame_height, -1, True); /* wait until the window is iconified and the icon window is mapped * before creating the icon window */ tmp_win->icon_w = None; if (!tmp_win->iconmgr) { GrabButtons(tmp_win); GrabKeys(tmp_win); } (void) AddIconManager(tmp_win); XSaveContext(dpy, tmp_win->w, TwmContext, (caddr_t) tmp_win); XSaveContext(dpy, tmp_win->w, ScreenContext, (caddr_t) Scr); XSaveContext(dpy, tmp_win->frame, TwmContext, (caddr_t) tmp_win); XSaveContext(dpy, tmp_win->frame, ScreenContext, (caddr_t) Scr); if (tmp_win->title_height) { int i; int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; XSaveContext(dpy, tmp_win->title_w, TwmContext, (caddr_t) tmp_win); XSaveContext(dpy, tmp_win->title_w, ScreenContext, (caddr_t) Scr); for (i = 0; i < nb; i++) { XSaveContext(dpy, tmp_win->titlebuttons[i].window, TwmContext, (caddr_t) tmp_win); XSaveContext(dpy, tmp_win->titlebuttons[i].window, ScreenContext, (caddr_t) Scr); } if (tmp_win->hilite_w) { XSaveContext(dpy, tmp_win->hilite_w, TwmContext, (caddr_t)tmp_win); XSaveContext(dpy, tmp_win->hilite_w, ScreenContext, (caddr_t)Scr); } } XUngrabServer(dpy); /* if we were in the middle of a menu activated function, regrab * the pointer */ if (RootFunction) ReGrab(); return (tmp_win); } /*********************************************************************** * * Procedure: * MappedNotOverride - checks to see if we should really * put a twm frame on the window * * Returned Value: * TRUE - go ahead and frame the window * FALSE - don't frame the window * * Inputs: * w - the window to check * *********************************************************************** */ int MappedNotOverride(w) Window w; { XWindowAttributes wa; XGetWindowAttributes(dpy, w, &wa); return ((wa.map_state != IsUnmapped) && (wa.override_redirect != True)); } /*********************************************************************** * * Procedure: * AddDefaultBindings - attach default bindings so that naive users * don't get messed up if they provide a minimal twmrc. */ static void do_add_binding (button, context, modifier, func) int button, context, modifier; int func; { MouseButton *mb = &Scr->Mouse[button][context][modifier]; if (mb->func) return; /* already defined */ mb->func = func; mb->item = NULL; } AddDefaultBindings () { /* * The bindings are stored in Scr->Mouse, indexed by * Mouse[button_number][C_context][modifier]. */ #define NoModifierMask 0 do_add_binding (Button1, C_TITLE, NoModifierMask, F_MOVE); do_add_binding (Button1, C_ICON, NoModifierMask, F_ICONIFY); do_add_binding (Button1, C_ICONMGR, NoModifierMask, F_ICONIFY); do_add_binding (Button2, C_TITLE, NoModifierMask, F_RAISELOWER); do_add_binding (Button2, C_ICON, NoModifierMask, F_ICONIFY); do_add_binding (Button2, C_ICONMGR, NoModifierMask, F_ICONIFY); #undef NoModifierMask } /*********************************************************************** * * Procedure: * GrabButtons - grab needed buttons for the window * * Inputs: * tmp_win - the twm window structure to use * *********************************************************************** */ void GrabButtons(tmp_win) TwmWindow *tmp_win; { int i, j; for (i = 0; i < MAX_BUTTONS+1; i++) { for (j = 0; j < MOD_SIZE; j++) { if (Scr->Mouse[i][C_WINDOW][j].func != 0) { XGrabButton(dpy, i, j, tmp_win->w, True, ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, Scr->FrameCursor); } } } } /*********************************************************************** * * Procedure: * GrabKeys - grab needed keys for the window * * Inputs: * tmp_win - the twm window structure to use * *********************************************************************** */ void GrabKeys(tmp_win) TwmWindow *tmp_win; { FuncKey *tmp; IconMgr *p; for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next) { switch (tmp->cont) { case C_WINDOW: XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->w, True, GrabModeAsync, GrabModeAsync); break; case C_ICON: if (tmp_win->icon_w) XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->icon_w, True, GrabModeAsync, GrabModeAsync); case C_TITLE: if (tmp_win->title_w) XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->title_w, True, GrabModeAsync, GrabModeAsync); break; case C_NAME: XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->w, True, GrabModeAsync, GrabModeAsync); if (tmp_win->icon_w) XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->icon_w, True, GrabModeAsync, GrabModeAsync); if (tmp_win->title_w) XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->title_w, True, GrabModeAsync, GrabModeAsync); break; /* case C_ROOT: XGrabKey(dpy, tmp->keycode, tmp->mods, Scr->Root, True, GrabModeAsync, GrabModeAsync); break; */ } } for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next) { if (tmp->cont == C_ICONMGR && !Scr->NoIconManagers) { for (p = &Scr->iconmgr; p != NULL; p = p->next) { XUngrabKey(dpy, tmp->keycode, tmp->mods, p->twm_win->w); } } } } static Window CreateHighlightWindow (tmp_win) TwmWindow *tmp_win; { XSetWindowAttributes attributes; /* attributes for create windows */ Pixmap pm = None; GC gc; XGCValues gcv; unsigned long valuemask; int h = (Scr->TitleHeight - 2 * Scr->FramePadding); Window w; /* * If a special highlight pixmap was given, use that. Otherwise, * use a nice, even gray pattern. The old horizontal lines look really * awful on interlaced monitors (as well as resembling other looks a * little bit too closely), but can be used by putting * * Pixmaps { TitleHighlight "hline2" } * * (or whatever the horizontal line bitmap is named) in the startup * file. If all else fails, use the foreground color to look like a * solid line. */ if (!Scr->hilitePm) { Scr->hilitePm = XCreateBitmapFromData (dpy, tmp_win->title_w, gray_bits, gray_width, gray_height); Scr->hilite_pm_width = gray_width; Scr->hilite_pm_height = gray_height; #ifdef XPM Scr->hilite_pm_isXpm = False; #endif } if (Scr->hilitePm) { #ifdef XPM if (Scr->hilite_pm_isXpm == False) { #endif pm = XCreatePixmap (dpy, tmp_win->title_w, Scr->hilite_pm_width, Scr->hilite_pm_height, Scr->d_depth); gcv.foreground = tmp_win->title.fore; gcv.background = tmp_win->title.back; gcv.graphics_exposures = False; gc = XCreateGC (dpy, pm, (GCForeground|GCBackground|GCGraphicsExposures), &gcv); if (gc) { XCopyPlane (dpy, Scr->hilitePm, pm, gc, 0, 0, Scr->hilite_pm_width, Scr->hilite_pm_height, 0, 0, 1); XFreeGC (dpy, gc); } else { XFreePixmap (dpy, pm); pm = None; } #ifdef XPM } else { pm = XCreatePixmap (dpy, tmp_win->title_w, Scr->hilite_pm_width, Scr->hilite_pm_height, Scr->d_depth); gcv.foreground = tmp_win->title.fore; gcv.background = tmp_win->title.back; gcv.graphics_exposures = False; gc = XCreateGC (dpy, pm, (GCForeground|GCBackground|GCGraphicsExposures), &gcv); if (gc) { XCopyArea (dpy, Scr->hilitePm, pm, gc, 0, 0, Scr->hilite_pm_width, Scr->hilite_pm_height, 0, 0); XFreeGC (dpy, gc); } else { XFreePixmap (dpy, pm); pm = None; } } #endif } if (pm) { valuemask = CWBackPixmap; attributes.background_pixmap = pm; } else { valuemask = CWBackPixel; attributes.background_pixel = tmp_win->title.fore; } valuemask |= CWBackingStore; attributes.backing_store= NotUseful; w = XCreateWindow (dpy, tmp_win->title_w, 0, Scr->FramePadding, (unsigned int) Scr->TBInfo.width, (unsigned int) h, (unsigned int) 0, Scr->d_depth, (unsigned int) CopyFromParent, Scr->d_visual, valuemask, &attributes); if (pm) XFreePixmap (dpy, pm); return w; } void ComputeCommonTitleOffsets () { int buttonwidth = (Scr->TBInfo.width + Scr->TBInfo.pad); Scr->TBInfo.leftx = Scr->TBInfo.rightoff = Scr->FramePadding; if (Scr->TBInfo.nleft > 0) Scr->TBInfo.leftx += Scr->ButtonIndent; Scr->TBInfo.titlex = (Scr->TBInfo.leftx + (Scr->TBInfo.nleft * buttonwidth) - Scr->TBInfo.pad + Scr->TitlePadding); if (Scr->TBInfo.nright > 0) Scr->TBInfo.rightoff += (Scr->ButtonIndent + ((Scr->TBInfo.nright * buttonwidth) - Scr->TBInfo.pad)); return; } void ComputeWindowTitleOffsets (tmp_win, width, squeeze) TwmWindow *tmp_win; Bool squeeze; { tmp_win->highlightx = (Scr->TBInfo.titlex + tmp_win->name_width); if (tmp_win->hilite_w || Scr->TBInfo.nright > 0) tmp_win->highlightx += Scr->TitlePadding; tmp_win->rightx = width - Scr->TBInfo.rightoff; if (squeeze && tmp_win->squeeze_info) { int rx = (tmp_win->highlightx + (tmp_win->hilite_w ? Scr->TBInfo.width * 2 : 0) + (Scr->TBInfo.nright > 0 ? Scr->TitlePadding : 0) + Scr->FramePadding); if (rx < tmp_win->rightx) tmp_win->rightx = rx; } return; } /* * ComputeTitleLocation - calculate the position of the title window; we need * to take the frame_bw into account since we want (0,0) of the title window * to line up with (0,0) of the frame window. */ void ComputeTitleLocation (tmp) register TwmWindow *tmp; { tmp->title_x = -tmp->frame_bw; tmp->title_y = -tmp->frame_bw; #ifdef SHAPE if (tmp->squeeze_info) { register SqueezeInfo *si = tmp->squeeze_info; int basex; int maxwidth = tmp->frame_width; int tw = tmp->title_width; /* * figure label base from squeeze info (justification fraction) */ if (si->denom == 0) { /* num is pixel based */ if ((basex = si->num) == 0) { /* look for special cases */ switch (si->justify) { case J_RIGHT: basex = maxwidth; break; case J_CENTER: basex = maxwidth / 2; break; } } } else { /* num/denom is fraction */ basex = ((si->num * maxwidth) / si->denom); if (si->num < 0) basex += maxwidth; } /* * adjust for left (nop), center, right justify and clip */ switch (si->justify) { case J_CENTER: basex -= tw / 2; break; case J_RIGHT: basex -= tw - 1; break; } if (basex > maxwidth - tw + 1) basex = maxwidth - tw + 1; if (basex < 0) basex = 0; tmp->title_x = basex - tmp->frame_bw; } #endif } static void CreateWindowTitlebarButtons (tmp_win) TwmWindow *tmp_win; { unsigned long valuemask; /* mask for create windows */ XSetWindowAttributes attributes; /* attributes for create windows */ int leftx, rightx, y; TitleButton *tb; int nb; if (tmp_win->title_height == 0) { tmp_win->hilite_w = 0; return; } /* * create the title bar windows; let the event handler deal with painting * so that we don't have to spend two pixmaps (or deal with hashing) */ ComputeWindowTitleOffsets (tmp_win, tmp_win->attr.width, False); leftx = y = Scr->TBInfo.leftx; rightx = tmp_win->rightx; attributes.win_gravity = NorthWestGravity; attributes.background_pixel = tmp_win->title.back; attributes.border_pixel = tmp_win->title.fore; attributes.event_mask = (ButtonPressMask | ButtonReleaseMask | ExposureMask); attributes.cursor = Scr->ButtonCursor; valuemask = (CWWinGravity | CWBackPixel | CWBorderPixel | CWEventMask | CWCursor); tmp_win->titlebuttons = NULL; nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; if (nb > 0) { tmp_win->titlebuttons = (TBWindow *) malloc (nb * sizeof(TBWindow)); if (!tmp_win->titlebuttons) { fprintf (stderr, "%s: unable to allocate %d titlebuttons\n", ProgramName, nb); } else { TBWindow *tbw; int boxwidth = (Scr->TBInfo.width + Scr->TBInfo.pad); unsigned int h = (Scr->TBInfo.width - Scr->TBInfo.border * 2); for (tb = Scr->TBInfo.head, tbw = tmp_win->titlebuttons; tb; tb = tb->next, tbw++) { int x; if (tb->rightside) { x = rightx; rightx += boxwidth; attributes.win_gravity = NorthEastGravity; } else { x = leftx; leftx += boxwidth; attributes.win_gravity = NorthWestGravity; } tbw->window = XCreateWindow (dpy, tmp_win->title_w, x, y, h, h, (unsigned int) Scr->TBInfo.border, 0, (unsigned int) CopyFromParent, (Visual *) CopyFromParent, valuemask, &attributes); tbw->info = tb; } } } tmp_win->hilite_w = (tmp_win->titlehighlight ? CreateHighlightWindow (tmp_win) : None); XMapSubwindows(dpy, tmp_win->title_w); if (tmp_win->hilite_w) XUnmapWindow(dpy, tmp_win->hilite_w); return; } FetchWmProtocols (tmp) TwmWindow *tmp; { unsigned long flags = 0L; Atom *protocols = NULL; int n; if (XGetWMProtocols (dpy, tmp->w, &protocols, &n)) { register int i; register Atom *ap; for (i = 0, ap = protocols; i < n; i++, ap++) { if (*ap == _XA_WM_TAKE_FOCUS) flags |= DoesWmTakeFocus; if (*ap == _XA_WM_SAVE_YOURSELF) flags |= DoesWmSaveYourself; if (*ap == _XA_WM_DELETE_WINDOW) flags |= DoesWmDeleteWindow; } if (protocols) XFree ((char *) protocols); } tmp->protocols = flags; } TwmColormap * CreateTwmColormap(c) Colormap c; { TwmColormap *cmap; cmap = (TwmColormap *) malloc(sizeof(TwmColormap)); if (!cmap || XSaveContext(dpy, c, ColormapContext, (caddr_t) cmap)) { if (cmap) free((char *) cmap); return (NULL); } cmap->c = c; cmap->state = 0; cmap->install_req = 0; cmap->w = None; cmap->refcnt = 1; return (cmap); } ColormapWindow * CreateColormapWindow(w, creating_parent, property_window) Window w; Bool creating_parent; Bool property_window; { ColormapWindow *cwin; TwmColormap *cmap; XWindowAttributes attributes; cwin = (ColormapWindow *) malloc(sizeof(ColormapWindow)); if (cwin) { if (!XGetWindowAttributes(dpy, w, &attributes) || XSaveContext(dpy, w, ColormapContext, (caddr_t) cwin)) { free((char *) cwin); return (NULL); } if (XFindContext(dpy, attributes.colormap, ColormapContext, (caddr_t *)&cwin->colormap) == XCNOENT) { cwin->colormap = cmap = CreateTwmColormap(attributes.colormap); if (!cmap) { XDeleteContext(dpy, w, ColormapContext); free((char *) cwin); return (NULL); } } else { cwin->colormap->refcnt++; } cwin->w = w; /* * Assume that windows in colormap list are * obscured if we are creating the parent window. * Otherwise, we assume they are unobscured. */ cwin->visibility = creating_parent ? VisibilityFullyObscured : VisibilityUnobscured; cwin->refcnt = 1; /* * If this is a ColormapWindow property window and we * are not monitoring ColormapNotify or VisibilityNotify * events, we need to. */ if (property_window && (attributes.your_event_mask & (ColormapChangeMask|VisibilityChangeMask)) != (ColormapChangeMask|VisibilityChangeMask)) { XSelectInput(dpy, w, attributes.your_event_mask | (ColormapChangeMask|VisibilityChangeMask)); } } return (cwin); } FetchWmColormapWindows (tmp) TwmWindow *tmp; { register int i, j; Window *cmap_windows = NULL; Bool can_free_cmap_windows = False; int number_cmap_windows = 0; ColormapWindow **cwins = NULL; int previously_installed; extern void free_cwins(); number_cmap_windows = 0; if (previously_installed = (Scr->cmapInfo.cmaps == &tmp->cmaps && tmp->cmaps.number_cwins)) { cwins = tmp->cmaps.cwins; for (i = 0; i < tmp->cmaps.number_cwins; i++) cwins[i]->colormap->state = 0; } if (XGetWMColormapWindows (dpy, tmp->w, &cmap_windows, &number_cmap_windows) && number_cmap_windows > 0) { can_free_cmap_windows = False; /* * check if the top level is in the list, add to front if not */ for (i = 0; i < number_cmap_windows; i++) { if (cmap_windows[i] == tmp->w) break; } if (i == number_cmap_windows) { /* not in list */ Window *new_cmap_windows = (Window *) malloc (sizeof(Window) * (number_cmap_windows + 1)); if (!new_cmap_windows) { fprintf (stderr, "%s: unable to allocate %d element colormap window array\n", ProgramName, number_cmap_windows+1); goto done; } new_cmap_windows[0] = tmp->w; /* add to front */ for (i = 0; i < number_cmap_windows; i++) { /* append rest */ new_cmap_windows[i+1] = cmap_windows[i]; } XFree ((char *) cmap_windows); can_free_cmap_windows = True; /* do not use XFree any more */ cmap_windows = new_cmap_windows; number_cmap_windows++; } cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *) * number_cmap_windows); if (cwins) { for (i = 0; i < number_cmap_windows; i++) { /* * Copy any existing entries into new list. */ for (j = 0; j < tmp->cmaps.number_cwins; j++) { if (tmp->cmaps.cwins[j]->w == cmap_windows[i]) { cwins[i] = tmp->cmaps.cwins[j]; cwins[i]->refcnt++; break; } } /* * If the colormap window is not being pointed by * some other applications colormap window list, * create a new entry. */ if (j == tmp->cmaps.number_cwins) { if (XFindContext(dpy, cmap_windows[i], ColormapContext, (caddr_t *)&cwins[i]) == XCNOENT) { if ((cwins[i] = CreateColormapWindow(cmap_windows[i], (Bool) tmp->cmaps.number_cwins == 0, True)) == NULL) { int k; for (k = i + 1; k < number_cmap_windows; k++) cmap_windows[k-1] = cmap_windows[k]; i--; number_cmap_windows--; } } else cwins[i]->refcnt++; } } } } /* No else here, in case we bailed out of clause above. */ if (number_cmap_windows == 0) { number_cmap_windows = 1; cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *)); if (XFindContext(dpy, tmp->w, ColormapContext, (caddr_t *)&cwins[0]) == XCNOENT) cwins[0] = CreateColormapWindow(tmp->w, (Bool) tmp->cmaps.number_cwins == 0, False); else cwins[0]->refcnt++; } if (tmp->cmaps.number_cwins) free_cwins(tmp); tmp->cmaps.cwins = cwins; tmp->cmaps.number_cwins = number_cmap_windows; if (number_cmap_windows > 1) tmp->cmaps.scoreboard = (char *) calloc(1, ColormapsScoreboardLength(&tmp->cmaps)); if (previously_installed) InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL); done: if (cmap_windows) { if (can_free_cmap_windows) free ((char *) cmap_windows); else XFree ((char *) cmap_windows); } return; } SimulateWinGravity (tmp) TwmWindow *tmp; { if (tmp->hints.flags & USPosition) { static int gravs[] = { SouthEastGravity, SouthWestGravity, NorthEastGravity, NorthWestGravity }; int right = tmp->attr.x + tmp->attr.width + 2 * tmp->old_bw; int bottom = tmp->attr.y + tmp->attr.height + 2 * tmp->old_bw; tmp->hints.win_gravity = gravs[((Scr->MyDisplayHeight - bottom < tmp->title_height) ? 0 : 2) | ((Scr->MyDisplayWidth - right < tmp->title_height) ? 0 : 1)]; tmp->hints.flags |= PWinGravity; } } static void getTWM_FLAGS (w, flags) Window w; unsigned long *flags; { Atom actual_type; int actual_format; unsigned long nitems, bytesafter; unsigned long *datap = NULL; if (XGetWindowProperty (dpy, w, _XA_TWM_FLAGS, 0L, 1L, False, _XA_TWM_FLAGS, &actual_type, &actual_format, &nitems, &bytesafter, (unsigned char **) &datap) != Success || !datap) { *flags = 0; return; } /* OR in the valid bit */ *datap |= TWM_FLAGS_VALID; *flags = *datap; XFree ((char *) datap); return; } void SetTWM_FLAGS(tmp_win) TwmWindow *tmp_win; { unsigned long data; data = 0; if (tmp_win->sticky) data |= TWM_FLAGS_STICKY; XChangeProperty (dpy, tmp_win->w, _XA_TWM_FLAGS, _XA_TWM_FLAGS, 32, PropModeReplace, (unsigned char *) &data, 1); } void GetUserMenu (tmp_win) TwmWindow *tmp_win; { Atom actual_type; int actual_format; unsigned long nitems, bytesafter; XGetWindowProperty (dpy, tmp_win->w, _XA_TWM_USER_MENU, 0L, 200L, False, XA_STRING, &actual_type, &actual_format, &nitems, &bytesafter, (unsigned char **)&tmp_win->user_menu); if (tmp_win->user_menu != NULL) { printf("Got user menu \"%s\" from window \"%s\".\n", tmp_win->user_menu, tmp_win->full_name); } return; }