summaryrefslogtreecommitdiff
path: root/src/add_window.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/add_window.c')
-rw-r--r--src/add_window.c1629
1 files changed, 1629 insertions, 0 deletions
diff --git a/src/add_window.c b/src/add_window.c
new file mode 100644
index 0000000..8a2059a
--- /dev/null
+++ b/src/add_window.c
@@ -0,0 +1,1629 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989,1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** 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 **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** 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. **/
+/*****************************************************************************/
+
+
+/**********************************************************************
+ *
+ * $Xorg: add_window.c,v 1.5 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * Add a new window, put the titlbar and other stuff around
+ * the window
+ *
+ * 31-Mar-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include <X11/Xatom.h>
+#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"
+
+#define gray_width 2
+#define gray_height 2
+static char gray_bits[] = {
+ 0x02, 0x01};
+
+int AddingX;
+int AddingY;
+int AddingW;
+int AddingH;
+
+static int PlaceX = 50;
+static int PlaceY = 50;
+static void CreateWindowTitlebarButtons();
+
+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 */
+ int gravx, gravy; /* gravity signs for positioning */
+ int namelen;
+ int bw2;
+ short saved_x, saved_y, restore_icon_x, restore_icon_y;
+ unsigned short saved_width, saved_height;
+ Bool restore_iconified = 0;
+ Bool restore_icon_info_present = 0;
+ int restoredFromPrevSession;
+ Bool width_ever_changed_by_user;
+ Bool height_ever_changed_by_user;
+
+#ifdef DEBUG
+ fprintf(stderr, "AddWindow: w = 0x%x\n", w);
+#endif
+
+ /* allocate space for the twm window */
+ tmp_win = (TwmWindow *)calloc(1, sizeof(TwmWindow));
+ if (tmp_win == 0)
+ {
+ fprintf (stderr, "%s: Unable to allocate memory to manage window ID %lx.\n",
+ ProgramName, w);
+ return NULL;
+ }
+ 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);
+
+ if (GetWindowConfig (tmp_win,
+ &saved_x, &saved_y, &saved_width, &saved_height,
+ &restore_iconified, &restore_icon_info_present,
+ &restore_icon_x, &restore_icon_y,
+ &width_ever_changed_by_user, &height_ever_changed_by_user))
+ {
+ tmp_win->attr.x = saved_x;
+ tmp_win->attr.y = saved_y;
+
+ tmp_win->widthEverChangedByUser = width_ever_changed_by_user;
+ tmp_win->heightEverChangedByUser = height_ever_changed_by_user;
+
+ if (width_ever_changed_by_user)
+ tmp_win->attr.width = saved_width;
+
+ if (height_ever_changed_by_user)
+ tmp_win->attr.height = saved_height;
+
+ restoredFromPrevSession = 1;
+ }
+ else
+ {
+ tmp_win->widthEverChangedByUser = False;
+ tmp_win->heightEverChangedByUser = False;
+
+ restoredFromPrevSession = 0;
+ }
+
+
+ /*
+ * 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)
+ {
+ if (restore_iconified)
+ {
+ tmp_win->wmhints->initial_state = IconicState;
+ tmp_win->wmhints->flags |= StateHint;
+ }
+
+ if (restore_icon_info_present)
+ {
+ tmp_win->wmhints->icon_x = restore_icon_x;
+ tmp_win->wmhints->icon_y = restore_icon_y;
+ tmp_win->wmhints->flags |= IconPositionHint;
+ }
+ }
+
+ if (tmp_win->wmhints && (tmp_win->wmhints->flags & WindowGroupHint))
+ tmp_win->group = tmp_win->wmhints->window_group;
+ else
+ tmp_win->group = tmp_win->w/* NULL */;
+
+ /*
+ * 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, &tmp_win->transientfor);
+
+ tmp_win->nameChanged = 0;
+ 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);
+
+ tmp_win->highlight = Scr->Highlight &&
+ (!(short)(int) LookInList(Scr->NoHighlight, tmp_win->full_name,
+ &tmp_win->class));
+
+ tmp_win->stackmode = Scr->StackMode &&
+ (!(short)(int) LookInList(Scr->NoStackModeL, tmp_win->full_name,
+ &tmp_win->class));
+
+ tmp_win->titlehighlight = Scr->TitleHighlight &&
+ (!(short)(int) LookInList(Scr->NoTitleHighlight, tmp_win->full_name,
+ &tmp_win->class));
+
+ tmp_win->auto_raise = (short)(int) 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)(int) LookInList(Scr->DontIconify, tmp_win->full_name,
+ &tmp_win->class);
+ }
+ tmp_win->iconify_by_unmapping |=
+ (short)(int) 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;
+ /*
+ * 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;
+ }
+ }
+ }
+
+ 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;
+
+ /* 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;
+ }
+
+ GetWindowSizeHints (tmp_win);
+
+ if (restoredFromPrevSession)
+ {
+ /*
+ * When restoring window positions from the previous session,
+ * we always use NorthWest gravity.
+ */
+
+ gravx = gravy = -1;
+ }
+ else
+ {
+ GetGravityOffsets (tmp_win, &gravx, &gravy);
+ }
+
+ /*
+ * 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;
+
+ /*
+ * do any prompting for position
+ */
+ if (HandlingEvents && ask_user && !restoredFromPrevSession) {
+ 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;
+ } 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, False,
+ ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask | PointerMotionHintMask,
+ 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;
+
+ if (Scr->DontMoveOff) {
+ /*
+ * Make sure the initial outline comes up on the screen.
+ */
+ if (AddingX < 0)
+ AddingX = 0;
+ if (AddingX > Scr->MyDisplayWidth - AddingW)
+ AddingX = Scr->MyDisplayWidth - AddingW;
+
+ if (AddingY < 0)
+ AddingY = 0;
+ if (AddingY > Scr->MyDisplayHeight - AddingH)
+ AddingY = Scr->MyDisplayHeight - AddingH;
+ }
+
+ MoveOutline(Scr->Root, AddingX, AddingY, AddingW, AddingH,
+ tmp_win->frame_bw, tmp_win->title_height);
+
+ while (TRUE)
+ {
+ XMaskEvent(dpy, ButtonPressMask | PointerMotionMask, &event);
+
+ if (Event.type == MotionNotify) {
+ /* discard any extra motion events before a release */
+ while(XCheckMaskEvent(dpy,
+ ButtonMotionMask | ButtonPressMask, &Event))
+ if (Event.type == ButtonPress)
+ break;
+ }
+
+ if (event.type == ButtonPress) {
+ AddingX = event.xbutton.x_root;
+ AddingY = event.xbutton.y_root;
+
+ /* DontMoveOff prohibits user form off-screen placement */
+ if (Scr->DontMoveOff)
+ {
+ int AddingR, AddingB;
+
+ AddingR = AddingX + AddingW;
+ AddingB = AddingY + AddingH;
+
+ if (AddingX < 0)
+ AddingX = 0;
+ if (AddingR > Scr->MyDisplayWidth)
+ AddingX = Scr->MyDisplayWidth - AddingW;
+
+ if (AddingY < 0)
+ AddingY = 0;
+ if (AddingB > Scr->MyDisplayHeight)
+ AddingY = Scr->MyDisplayHeight - AddingH;
+
+ }
+ break;
+ }
+
+ if (event.type != MotionNotify) {
+ continue;
+ }
+
+ XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
+ &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
+
+ if (Scr->DontMoveOff)
+ {
+ int AddingR, AddingB;
+
+ AddingR = AddingX + AddingW;
+ AddingB = AddingY + AddingH;
+
+ if (AddingX < 0)
+ AddingX = 0;
+ if (AddingR > Scr->MyDisplayWidth)
+ AddingX = Scr->MyDisplayWidth - AddingW;
+
+ if (AddingY < 0)
+ AddingY = 0;
+ if (AddingB > Scr->MyDisplayHeight)
+ AddingY = Scr->MyDisplayHeight - AddingH;
+ }
+
+ MoveOutline(Scr->Root, AddingX, AddingY, AddingW, AddingH,
+ tmp_win->frame_bw, tmp_win->title_height);
+
+ }
+
+ if (event.xbutton.button == 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 (0/*Scr->AutoRelativeResize*/) {
+ int dx = (tmp_win->attr.width / 4);
+ int dy = (tmp_win->attr.height / 4);
+
+#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)
+ dx = Scr->MyDisplayWidth - AddingX - 1;
+ if (AddingY + dy >= Scr->MyDisplayHeight)
+ dy = Scr->MyDisplayHeight - AddingY - 1;
+ if (dx > 0 && dy > 0)
+ XWarpPointer (dpy, None, None, 0, 0, 0, 0, dx, dy);
+ } else {
+ XWarpPointer (dpy, None, Scr->Root, 0, 0, 0, 0,
+ AddingX + AddingW/2, AddingY + AddingH/2);
+ }
+ AddStartResize(tmp_win, AddingX, AddingY, AddingW, AddingH);
+
+ lastx = -10000;
+ lasty = -10000;
+ while (TRUE)
+ {
+ XMaskEvent(dpy,
+ ButtonReleaseMask | ButtonMotionMask, &event);
+
+ if (Event.type == MotionNotify) {
+ /* discard any extra motion events before a release */
+ while(XCheckMaskEvent(dpy,
+ ButtonMotionMask | ButtonReleaseMask, &Event))
+ if (Event.type == ButtonRelease)
+ break;
+ }
+
+ if (event.type == ButtonRelease)
+ {
+ AddEndResize(tmp_win);
+ break;
+ }
+
+ if (event.type != MotionNotify) {
+ continue;
+ }
+
+ /*
+ * 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;
+ }
+
+ }
+ }
+ else if (event.xbutton.button == Button3)
+ {
+ int maxw = Scr->MyDisplayWidth - AddingX - bw2;
+ int maxh = Scr->MyDisplayHeight - AddingY - bw2;
+
+ /*
+ * 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);
+ }
+
+ MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+ 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;
+ }
+
+
+#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;
+
+ 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;
+
+ 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_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;
+
+ 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;
+ }
+
+ tmp_win->frame = XCreateWindow (dpy, Scr->Root, tmp_win->frame_x,
+ tmp_win->frame_y,
+ (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);
+ attributes.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
+ XChangeWindowAttributes (dpy, tmp_win->w, valuemask, &attributes);
+
+ if (HasShape)
+ XShapeSelectInput (dpy, tmp_win->w, ShapeNotifyMask);
+
+ if (tmp_win->title_w) {
+ XMapWindow (dpy, tmp_win->title_w);
+ }
+
+ 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;
+ }
+
+ 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;
+
+ SetupFrame (tmp_win, tmp_win->frame_x, 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 = (Window) 0;
+
+ 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)
+ {
+ /* twm used to do this grab on the application main window,
+ * tmp_win->w . This was not ICCCM complient and was changed.
+ */
+ XGrabButton(dpy, i, j, tmp_win->frame,
+ 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;
+ }
+ if (Scr->hilitePm) {
+ 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;
+ }
+ }
+ if (pm) {
+ valuemask = CWBackPixmap;
+ attributes.background_pixmap = pm;
+ } else {
+ valuemask = CWBackPixel;
+ attributes.background_pixel = tmp_win->title.fore;
+ }
+
+ 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;
+
+ 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;
+ }
+}
+
+
+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;
+}
+
+
+SetHighlightPixmap (filename)
+ char *filename;
+{
+ Pixmap pm = GetBitmap (filename);
+
+ if (pm) {
+ if (Scr->hilitePm) {
+ XFreePixmap (dpy, Scr->hilitePm);
+ }
+ Scr->hilitePm = pm;
+ Scr->hilite_pm_width = JunkWidth;
+ Scr->hilite_pm_height = JunkHeight;
+ }
+}
+
+
+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 ?
+ VisibilityPartiallyObscured : 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 (/* SUPPRESS 560 */(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;
+}
+
+
+void GetWindowSizeHints (tmp)
+ TwmWindow *tmp;
+{
+ long supplied = 0;
+
+ if (!XGetWMNormalHints (dpy, tmp->w, &tmp->hints, &supplied))
+ tmp->hints.flags = 0;
+
+ if (tmp->hints.flags & PResizeInc) {
+ if (tmp->hints.width_inc == 0) tmp->hints.width_inc = 1;
+ if (tmp->hints.height_inc == 0) tmp->hints.height_inc = 1;
+ }
+
+ if (!(supplied & PWinGravity) && (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;
+ }
+}