summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/add_window.c1629
-rw-r--r--src/add_window.h81
-rw-r--r--src/cursor.c175
-rw-r--r--src/events.c2817
-rw-r--r--src/events.h111
-rw-r--r--src/gc.c117
-rw-r--r--src/gc.h68
-rw-r--r--src/gram.y883
-rw-r--r--src/iconmgr.c773
-rw-r--r--src/iconmgr.h93
-rw-r--r--src/icons.c588
-rw-r--r--src/icons.h56
-rw-r--r--src/lex.l145
-rw-r--r--src/list.c258
-rw-r--r--src/list.h75
-rw-r--r--src/menus.c3035
-rw-r--r--src/menus.h178
-rw-r--r--src/parse.c1149
-rw-r--r--src/parse.h135
-rw-r--r--src/resize.c1217
-rw-r--r--src/resize.h77
-rw-r--r--src/screen.h267
-rw-r--r--src/session.c1054
-rw-r--r--src/siconify.bm5
-rw-r--r--src/system.twmrc89
-rw-r--r--src/twm.c898
-rw-r--r--src/twm.h426
-rw-r--r--src/util.c959
-rw-r--r--src/util.h95
-rw-r--r--src/version.c54
-rw-r--r--src/version.h67
31 files changed, 17574 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;
+ }
+}
diff --git a/src/add_window.h b/src/add_window.h
new file mode 100644
index 0000000..36b4428
--- /dev/null
+++ b/src/add_window.h
@@ -0,0 +1,81 @@
+/*****************************************************************************/
+/*
+
+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.h,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * AddWindow include file
+ *
+ * 31-Mar-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#ifndef _ADD_WINDOW_
+#define _ADD_WINDOW_
+
+extern char NoName[];
+
+extern TwmWindow *AddWindow();
+extern int MappedNotOverride();
+extern void GrabButtons();
+extern void GrabKeys();
+extern void UngrabButtons();
+extern void UngrabKeys();
+extern void GetWindowSizeHints();
+extern int AddingX;
+extern int AddingY;
+extern int AddingW;
+extern int AddingH;
+
+#endif /* _ADD_WINDOW_ */
+
diff --git a/src/cursor.c b/src/cursor.c
new file mode 100644
index 0000000..713c236
--- /dev/null
+++ b/src/cursor.c
@@ -0,0 +1,175 @@
+/*
+ *
+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.
+ * */
+
+/***********************************************************************
+ *
+ * $Xorg: cursor.c,v 1.5 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * cursor creation code
+ *
+ * 05-Apr-89 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include <X11/Xos.h>
+#include "screen.h"
+#include "util.h"
+
+static struct _CursorName {
+ char *name;
+ unsigned int shape;
+ Cursor cursor;
+} cursor_names[] = {
+
+{"X_cursor", XC_X_cursor, None},
+{"arrow", XC_arrow, None},
+{"based_arrow_down", XC_based_arrow_down, None},
+{"based_arrow_up", XC_based_arrow_up, None},
+{"boat", XC_boat, None},
+{"bogosity", XC_bogosity, None},
+{"bottom_left_corner", XC_bottom_left_corner, None},
+{"bottom_right_corner", XC_bottom_right_corner, None},
+{"bottom_side", XC_bottom_side, None},
+{"bottom_tee", XC_bottom_tee, None},
+{"box_spiral", XC_box_spiral, None},
+{"center_ptr", XC_center_ptr, None},
+{"circle", XC_circle, None},
+{"clock", XC_clock, None},
+{"coffee_mug", XC_coffee_mug, None},
+{"cross", XC_cross, None},
+{"cross_reverse", XC_cross_reverse, None},
+{"crosshair", XC_crosshair, None},
+{"diamond_cross", XC_diamond_cross, None},
+{"dot", XC_dot, None},
+{"dotbox", XC_dotbox, None},
+{"double_arrow", XC_double_arrow, None},
+{"draft_large", XC_draft_large, None},
+{"draft_small", XC_draft_small, None},
+{"draped_box", XC_draped_box, None},
+{"exchange", XC_exchange, None},
+{"fleur", XC_fleur, None},
+{"gobbler", XC_gobbler, None},
+{"gumby", XC_gumby, None},
+{"hand1", XC_hand1, None},
+{"hand2", XC_hand2, None},
+{"heart", XC_heart, None},
+{"icon", XC_icon, None},
+{"iron_cross", XC_iron_cross, None},
+{"left_ptr", XC_left_ptr, None},
+{"left_side", XC_left_side, None},
+{"left_tee", XC_left_tee, None},
+{"leftbutton", XC_leftbutton, None},
+{"ll_angle", XC_ll_angle, None},
+{"lr_angle", XC_lr_angle, None},
+{"man", XC_man, None},
+{"middlebutton", XC_middlebutton, None},
+{"mouse", XC_mouse, None},
+{"pencil", XC_pencil, None},
+{"pirate", XC_pirate, None},
+{"plus", XC_plus, None},
+{"question_arrow", XC_question_arrow, None},
+{"right_ptr", XC_right_ptr, None},
+{"right_side", XC_right_side, None},
+{"right_tee", XC_right_tee, None},
+{"rightbutton", XC_rightbutton, None},
+{"rtl_logo", XC_rtl_logo, None},
+{"sailboat", XC_sailboat, None},
+{"sb_down_arrow", XC_sb_down_arrow, None},
+{"sb_h_double_arrow", XC_sb_h_double_arrow, None},
+{"sb_left_arrow", XC_sb_left_arrow, None},
+{"sb_right_arrow", XC_sb_right_arrow, None},
+{"sb_up_arrow", XC_sb_up_arrow, None},
+{"sb_v_double_arrow", XC_sb_v_double_arrow, None},
+{"shuttle", XC_shuttle, None},
+{"sizing", XC_sizing, None},
+{"spider", XC_spider, None},
+{"spraycan", XC_spraycan, None},
+{"star", XC_star, None},
+{"target", XC_target, None},
+{"tcross", XC_tcross, None},
+{"top_left_arrow", XC_top_left_arrow, None},
+{"top_left_corner", XC_top_left_corner, None},
+{"top_right_corner", XC_top_right_corner, None},
+{"top_side", XC_top_side, None},
+{"top_tee", XC_top_tee, None},
+{"trek", XC_trek, None},
+{"ul_angle", XC_ul_angle, None},
+{"umbrella", XC_umbrella, None},
+{"ur_angle", XC_ur_angle, None},
+{"watch", XC_watch, None},
+{"xterm", XC_xterm, None},
+};
+
+void NewFontCursor (cp, str)
+ Cursor *cp;
+ char *str;
+{
+ int i;
+
+ for (i = 0; i < sizeof(cursor_names)/sizeof(struct _CursorName); i++)
+ {
+ if (strcmp(str, cursor_names[i].name) == 0)
+ {
+ if (cursor_names[i].cursor == None)
+ cursor_names[i].cursor = XCreateFontCursor(dpy,
+ cursor_names[i].shape);
+ *cp = cursor_names[i].cursor;
+ return;
+ }
+ }
+ fprintf (stderr, "%s: unable to find font cursor \"%s\"\n",
+ ProgramName, str);
+}
+
+NewBitmapCursor(cp, source, mask)
+Cursor *cp;
+char *source, *mask;
+{
+ int hotx, hoty;
+ int sx, sy, mx, my;
+ unsigned int sw, sh, mw, mh;
+ Pixmap spm, mpm;
+
+ spm = GetBitmap(source);
+ if ((hotx = HotX) < 0) hotx = 0;
+ if ((hoty = HotY) < 0) hoty = 0;
+ mpm = GetBitmap(mask);
+
+ /* make sure they are the same size */
+
+ XGetGeometry(dpy, spm, &JunkRoot, &sx, &sy, &sw, &sh, &JunkBW,&JunkDepth);
+ XGetGeometry(dpy, mpm, &JunkRoot, &mx, &my, &mw, &mh, &JunkBW,&JunkDepth);
+ if (sw != mw || sh != mh)
+ {
+ fprintf (stderr,
+ "%s: cursor bitmaps \"%s\" and \"%s\" not the same size\n",
+ ProgramName, source, mask);
+ return;
+ }
+ *cp = XCreatePixmapCursor(dpy, spm, mpm, &Scr->PointerForeground,
+ &Scr->PointerBackground, hotx,hoty);
+}
diff --git a/src/events.c b/src/events.c
new file mode 100644
index 0000000..9b8c348
--- /dev/null
+++ b/src/events.c
@@ -0,0 +1,2817 @@
+/*****************************************************************************/
+/*
+
+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: events.c,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * twm event handling
+ *
+ * 17-Nov-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include <X11/Xatom.h>
+#include "add_window.h"
+#include "menus.h"
+#include "events.h"
+#include "resize.h"
+#include "parse.h"
+#include "gram.h"
+#include "util.h"
+#include "screen.h"
+#include "iconmgr.h"
+#include "version.h"
+
+extern int iconifybox_width, iconifybox_height;
+extern unsigned int mods_used;
+extern int menuFromFrameOrWindowOrTitlebar;
+
+#define MAX_X_EVENT 256
+event_proc EventHandler[MAX_X_EVENT]; /* event handler jump table */
+char *Action;
+int Context = C_NO_CONTEXT; /* current button press context */
+TwmWindow *ButtonWindow; /* button press window structure */
+XEvent ButtonEvent; /* button press event */
+XEvent Event; /* the current event */
+TwmWindow *Tmp_win; /* the current twm window */
+
+/* Used in HandleEnterNotify to remove border highlight from a window
+ * that has not recieved a LeaveNotify event because of a pointer grab
+ */
+TwmWindow *UnHighLight_win = NULL;
+
+Window DragWindow; /* variables used in moving windows */
+int origDragX;
+int origDragY;
+int DragX;
+int DragY;
+int DragWidth;
+int DragHeight;
+int CurrentDragX;
+int CurrentDragY;
+
+/* Vars to tell if the resize has moved. */
+extern int ResizeOrigX;
+extern int ResizeOrigY;
+
+static int enter_flag;
+static int ColortableThrashing;
+static TwmWindow *enter_win, *raise_win;
+
+ScreenInfo *FindScreenInfo();
+int ButtonPressed = -1;
+int Cancel = FALSE;
+
+void HandleCreateNotify();
+
+void HandleShapeNotify ();
+extern int ShapeEventBase, ShapeErrorBase;
+
+void AutoRaiseWindow (tmp)
+ TwmWindow *tmp;
+{
+ XRaiseWindow (dpy, tmp->frame);
+ XSync (dpy, 0);
+ enter_win = NULL;
+ enter_flag = TRUE;
+ raise_win = tmp;
+}
+
+void SetRaiseWindow (tmp)
+ TwmWindow *tmp;
+{
+ enter_flag = TRUE;
+ enter_win = NULL;
+ raise_win = tmp;
+ XSync (dpy, 0);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * InitEvents - initialize the event jump table
+ *
+ ***********************************************************************
+ */
+
+void
+InitEvents()
+{
+ int i;
+
+
+ ResizeWindow = (Window) 0;
+ DragWindow = (Window) 0;
+ enter_flag = FALSE;
+ enter_win = raise_win = NULL;
+
+ for (i = 0; i < MAX_X_EVENT; i++)
+ EventHandler[i] = HandleUnknown;
+
+ EventHandler[Expose] = HandleExpose;
+ EventHandler[CreateNotify] = HandleCreateNotify;
+ EventHandler[DestroyNotify] = HandleDestroyNotify;
+ EventHandler[MapRequest] = HandleMapRequest;
+ EventHandler[MapNotify] = HandleMapNotify;
+ EventHandler[UnmapNotify] = HandleUnmapNotify;
+ EventHandler[MotionNotify] = HandleMotionNotify;
+ EventHandler[ButtonRelease] = HandleButtonRelease;
+ EventHandler[ButtonPress] = HandleButtonPress;
+ EventHandler[EnterNotify] = HandleEnterNotify;
+ EventHandler[LeaveNotify] = HandleLeaveNotify;
+ EventHandler[ConfigureRequest] = HandleConfigureRequest;
+ EventHandler[ClientMessage] = HandleClientMessage;
+ EventHandler[PropertyNotify] = HandlePropertyNotify;
+ EventHandler[KeyPress] = HandleKeyPress;
+ EventHandler[ColormapNotify] = HandleColormapNotify;
+ EventHandler[VisibilityNotify] = HandleVisibilityNotify;
+ if (HasShape)
+ EventHandler[ShapeEventBase+ShapeNotify] = HandleShapeNotify;
+}
+
+
+
+
+Time lastTimestamp = CurrentTime; /* until Xlib does this for us */
+
+Bool StashEventTime (ev)
+ register XEvent *ev;
+{
+ switch (ev->type) {
+ case KeyPress:
+ case KeyRelease:
+ lastTimestamp = ev->xkey.time;
+ return True;
+ case ButtonPress:
+ case ButtonRelease:
+ lastTimestamp = ev->xbutton.time;
+ return True;
+ case MotionNotify:
+ lastTimestamp = ev->xmotion.time;
+ return True;
+ case EnterNotify:
+ case LeaveNotify:
+ lastTimestamp = ev->xcrossing.time;
+ return True;
+ case PropertyNotify:
+ lastTimestamp = ev->xproperty.time;
+ return True;
+ case SelectionClear:
+ lastTimestamp = ev->xselectionclear.time;
+ return True;
+ case SelectionRequest:
+ lastTimestamp = ev->xselectionrequest.time;
+ return True;
+ case SelectionNotify:
+ lastTimestamp = ev->xselection.time;
+ return True;
+ }
+ return False;
+}
+
+
+
+/*
+ * WindowOfEvent - return the window about which this event is concerned; this
+ * window may not be the same as XEvent.xany.window (the first window listed
+ * in the structure).
+ */
+Window WindowOfEvent (e)
+ XEvent *e;
+{
+ /*
+ * Each window subfield is marked with whether or not it is the same as
+ * XEvent.xany.window or is different (which is the case for some of the
+ * notify events).
+ */
+ switch (e->type) {
+ case KeyPress:
+ case KeyRelease: return e->xkey.window; /* same */
+ case ButtonPress:
+ case ButtonRelease: return e->xbutton.window; /* same */
+ case MotionNotify: return e->xmotion.window; /* same */
+ case EnterNotify:
+ case LeaveNotify: return e->xcrossing.window; /* same */
+ case FocusIn:
+ case FocusOut: return e->xfocus.window; /* same */
+ case KeymapNotify: return e->xkeymap.window; /* same */
+ case Expose: return e->xexpose.window; /* same */
+ case GraphicsExpose: return e->xgraphicsexpose.drawable; /* same */
+ case NoExpose: return e->xnoexpose.drawable; /* same */
+ case VisibilityNotify: return e->xvisibility.window; /* same */
+ case CreateNotify: return e->xcreatewindow.window; /* DIFF */
+ case DestroyNotify: return e->xdestroywindow.window; /* DIFF */
+ case UnmapNotify: return e->xunmap.window; /* DIFF */
+ case MapNotify: return e->xmap.window; /* DIFF */
+ case MapRequest: return e->xmaprequest.window; /* DIFF */
+ case ReparentNotify: return e->xreparent.window; /* DIFF */
+ case ConfigureNotify: return e->xconfigure.window; /* DIFF */
+ case ConfigureRequest: return e->xconfigurerequest.window; /* DIFF */
+ case GravityNotify: return e->xgravity.window; /* DIFF */
+ case ResizeRequest: return e->xresizerequest.window; /* same */
+ case CirculateNotify: return e->xcirculate.window; /* DIFF */
+ case CirculateRequest: return e->xcirculaterequest.window; /* DIFF */
+ case PropertyNotify: return e->xproperty.window; /* same */
+ case SelectionClear: return e->xselectionclear.window; /* same */
+ case SelectionRequest: return e->xselectionrequest.requestor; /* DIFF */
+ case SelectionNotify: return e->xselection.requestor; /* same */
+ case ColormapNotify: return e->xcolormap.window; /* same */
+ case ClientMessage: return e->xclient.window; /* same */
+ case MappingNotify: return None;
+ }
+ return None;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * DispatchEvent2 -
+ * handle a single X event stored in global var Event
+ * this rouitine for is for a call during an f.move
+ *
+ ***********************************************************************
+ */
+Bool DispatchEvent2 ()
+{
+ Window w = Event.xany.window;
+ StashEventTime (&Event);
+
+ if (XFindContext (dpy, w, TwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
+ Tmp_win = NULL;
+
+ if (XFindContext (dpy, w, ScreenContext, (caddr_t *)&Scr) == XCNOENT) {
+ Scr = FindScreenInfo (WindowOfEvent (&Event));
+ }
+
+ if (!Scr) return False;
+
+ if (menuFromFrameOrWindowOrTitlebar && Event.type == Expose)
+ HandleExpose();
+
+ if (!menuFromFrameOrWindowOrTitlebar && Event.type>= 0 && Event.type < MAX_X_EVENT) {
+ (*EventHandler[Event.type])();
+ }
+
+ return True;
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * DispatchEvent - handle a single X event stored in global var Event
+ *
+ ***********************************************************************
+ */
+Bool DispatchEvent ()
+{
+ Window w = Event.xany.window;
+ StashEventTime (&Event);
+
+ if (XFindContext (dpy, w, TwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
+ Tmp_win = NULL;
+
+ if (XFindContext (dpy, w, ScreenContext, (caddr_t *)&Scr) == XCNOENT) {
+ Scr = FindScreenInfo (WindowOfEvent (&Event));
+ }
+
+ if (!Scr) return False;
+
+ if (Event.type>= 0 && Event.type < MAX_X_EVENT) {
+ (*EventHandler[Event.type])();
+ }
+
+ return True;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleEvents - handle X events
+ *
+ ***********************************************************************
+ */
+
+void
+HandleEvents()
+{
+ while (TRUE)
+ {
+ if (enter_flag && !QLength(dpy)) {
+ if (enter_win && enter_win != raise_win) {
+ AutoRaiseWindow (enter_win); /* sets enter_flag T */
+ } else {
+ enter_flag = FALSE;
+ }
+ }
+ if (ColortableThrashing && !QLength(dpy) && Scr) {
+ InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
+ }
+ WindowMoved = FALSE;
+ XtAppNextEvent(appContext, &Event);
+ if (Event.type>= 0 && Event.type < MAX_X_EVENT)
+ (void) DispatchEvent ();
+ else
+ XtDispatchEvent (&Event);
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleColormapNotify - colormap notify event handler
+ *
+ * This procedure handles both a client changing its own colormap, and
+ * a client explicitly installing its colormap itself (only the window
+ * manager should do that, so we must set it correctly).
+ *
+ ***********************************************************************
+ */
+
+void
+HandleColormapNotify()
+{
+ XColormapEvent *cevent = (XColormapEvent *) &Event;
+ ColormapWindow *cwin, **cwins;
+ TwmColormap *cmap;
+ int lost, won, n, number_cwins;
+ extern TwmColormap *CreateTwmColormap();
+
+ if (XFindContext(dpy, cevent->window, ColormapContext, (caddr_t *)&cwin) == XCNOENT)
+ return;
+ cmap = cwin->colormap;
+
+ if (cevent->new)
+ {
+ if (XFindContext(dpy, cevent->colormap, ColormapContext,
+ (caddr_t *)&cwin->colormap) == XCNOENT)
+ cwin->colormap = CreateTwmColormap(cevent->colormap);
+ else
+ cwin->colormap->refcnt++;
+
+ cmap->refcnt--;
+
+ if (cevent->state == ColormapUninstalled)
+ cmap->state &= ~CM_INSTALLED;
+ else
+ cmap->state |= CM_INSTALLED;
+
+ if (cmap->state & CM_INSTALLABLE)
+ InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
+
+ if (cmap->refcnt == 0)
+ {
+ XDeleteContext(dpy, cmap->c, ColormapContext);
+ free((char *) cmap);
+ }
+
+ return;
+ }
+
+ if (cevent->state == ColormapUninstalled &&
+ (cmap->state & CM_INSTALLABLE))
+ {
+ if (!(cmap->state & CM_INSTALLED))
+ return;
+ cmap->state &= ~CM_INSTALLED;
+
+ if (!ColortableThrashing)
+ {
+ ColortableThrashing = TRUE;
+ XSync(dpy, 0);
+ }
+
+ if (cevent->serial >= Scr->cmapInfo.first_req)
+ {
+ number_cwins = Scr->cmapInfo.cmaps->number_cwins;
+
+ /*
+ * Find out which colortables collided.
+ */
+
+ cwins = Scr->cmapInfo.cmaps->cwins;
+ for (lost = won = -1, n = 0;
+ (lost == -1 || won == -1) && n < number_cwins;
+ n++)
+ {
+ if (lost == -1 && cwins[n] == cwin)
+ {
+ lost = n; /* This is the window which lost its colormap */
+ continue;
+ }
+
+ if (won == -1 &&
+ cwins[n]->colormap->install_req == cevent->serial)
+ {
+ won = n; /* This is the window whose colormap caused */
+ continue; /* the de-install of the previous colormap */
+ }
+ }
+
+ /*
+ ** Cases are:
+ ** Both the request and the window were found:
+ ** One of the installs made honoring the WM_COLORMAP
+ ** property caused another of the colormaps to be
+ ** de-installed, just mark the scoreboard.
+ **
+ ** Only the request was found:
+ ** One of the installs made honoring the WM_COLORMAP
+ ** property caused a window not in the WM_COLORMAP
+ ** list to lose its map. This happens when the map
+ ** it is losing is one which is trying to be installed,
+ ** but is getting getting de-installed by another map
+ ** in this case, we'll get a scoreable event later,
+ ** this one is meaningless.
+ **
+ ** Neither the request nor the window was found:
+ ** Somebody called installcolormap, but it doesn't
+ ** affect the WM_COLORMAP windows. This case will
+ ** probably never occur.
+ **
+ ** Only the window was found:
+ ** One of the WM_COLORMAP windows lost its colormap
+ ** but it wasn't one of the requests known. This is
+ ** probably because someone did an "InstallColormap".
+ ** The colormap policy is "enforced" by re-installing
+ ** the colormaps which are believed to be correct.
+ */
+
+ if (won != -1)
+ if (lost != -1)
+ {
+ /* lower diagonal index calculation */
+ if (lost > won)
+ n = lost*(lost-1)/2 + won;
+ else
+ n = won*(won-1)/2 + lost;
+ Scr->cmapInfo.cmaps->scoreboard[n] = 1;
+ } else
+ {
+ /*
+ ** One of the cwin installs caused one of the cwin
+ ** colormaps to be de-installed, so I'm sure to get an
+ ** UninstallNotify for the cwin I know about later.
+ ** I haven't got it yet, or the test of CM_INSTALLED
+ ** above would have failed. Turning the CM_INSTALLED
+ ** bit back on makes sure we get back here to score
+ ** the collision.
+ */
+ cmap->state |= CM_INSTALLED;
+ }
+ else if (lost != -1)
+ InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
+ }
+ }
+
+ else if (cevent->state == ColormapUninstalled)
+ cmap->state &= ~CM_INSTALLED;
+
+ else if (cevent->state == ColormapInstalled)
+ cmap->state |= CM_INSTALLED;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleVisibilityNotify - visibility notify event handler
+ *
+ * This routine keeps track of visibility events so that colormap
+ * installation can keep the maximum number of useful colormaps
+ * installed at one time.
+ *
+ ***********************************************************************
+ */
+
+void
+HandleVisibilityNotify()
+{
+ XVisibilityEvent *vevent = (XVisibilityEvent *) &Event;
+ ColormapWindow *cwin;
+ TwmColormap *cmap;
+
+ if (XFindContext(dpy, vevent->window, ColormapContext, (caddr_t *)&cwin) == XCNOENT)
+ return;
+
+ /*
+ * when Saber complains about retreiving an <int> from an <unsigned int>
+ * just type "touch vevent->state" and "cont"
+ */
+ cmap = cwin->colormap;
+ if ((cmap->state & CM_INSTALLABLE) &&
+ vevent->state != cwin->visibility &&
+ (vevent->state == VisibilityFullyObscured ||
+ cwin->visibility == VisibilityFullyObscured) &&
+ cmap->w == cwin->w) {
+ cwin->visibility = vevent->state;
+ InstallWindowColormaps(VisibilityNotify, (TwmWindow *) NULL);
+ } else
+ cwin->visibility = vevent->state;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleKeyPress - key press event handler
+ *
+ ***********************************************************************
+ */
+
+int MovedFromKeyPress = False;
+
+void
+HandleKeyPress()
+{
+ KeySym ks;
+ FuncKey *key;
+ int len;
+ unsigned int modifier;
+
+ if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);
+ Context = C_NO_CONTEXT;
+
+ if (Event.xany.window == Scr->Root)
+ Context = C_ROOT;
+ if (Tmp_win)
+ {
+ if (Event.xany.window == Tmp_win->title_w)
+ Context = C_TITLE;
+ if (Event.xany.window == Tmp_win->w)
+ Context = C_WINDOW;
+ if (Event.xany.window == Tmp_win->icon_w)
+ Context = C_ICON;
+ if (Event.xany.window == Tmp_win->frame)
+ Context = C_FRAME;
+ if (Tmp_win->list && Event.xany.window == Tmp_win->list->w)
+ Context = C_ICONMGR;
+ if (Tmp_win->list && Event.xany.window == Tmp_win->list->icon)
+ Context = C_ICONMGR;
+ }
+
+ modifier = (Event.xkey.state & mods_used);
+ ks = XLookupKeysym((XKeyEvent *) &Event, /* KeySyms index */ 0);
+ for (key = Scr->FuncKeyRoot.next; key != NULL; key = key->next)
+ {
+ if (key->keysym == ks &&
+ key->mods == modifier &&
+ (key->cont == Context || key->cont == C_NAME))
+ {
+ /* weed out the functions that don't make sense to execute
+ * from a key press
+ */
+ if (key->func == F_RESIZE)
+ return;
+ /* special case for F_MOVE/F_FORCEMOVE activated from a keypress */
+ if (key->func == F_MOVE || key->func == F_FORCEMOVE)
+ MovedFromKeyPress = True;
+
+ if (key->cont != C_NAME)
+ {
+ ExecuteFunction(key->func, key->action, Event.xany.window,
+ Tmp_win, &Event, Context, FALSE);
+ XUngrabPointer(dpy, CurrentTime);
+ return;
+ }
+ else
+ {
+ int matched = FALSE;
+ len = strlen(key->win_name);
+
+ /* try and match the name first */
+ for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
+ Tmp_win = Tmp_win->next)
+ {
+ if (!strncmp(key->win_name, Tmp_win->name, len))
+ {
+ matched = TRUE;
+ ExecuteFunction(key->func, key->action, Tmp_win->frame,
+ Tmp_win, &Event, C_FRAME, FALSE);
+ XUngrabPointer(dpy, CurrentTime);
+ }
+ }
+
+ /* now try the res_name */
+ if (!matched)
+ for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
+ Tmp_win = Tmp_win->next)
+ {
+ if (!strncmp(key->win_name, Tmp_win->class.res_name, len))
+ {
+ matched = TRUE;
+ ExecuteFunction(key->func, key->action, Tmp_win->frame,
+ Tmp_win, &Event, C_FRAME, FALSE);
+ XUngrabPointer(dpy, CurrentTime);
+ }
+ }
+
+ /* now try the res_class */
+ if (!matched)
+ for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
+ Tmp_win = Tmp_win->next)
+ {
+ if (!strncmp(key->win_name, Tmp_win->class.res_class, len))
+ {
+ matched = TRUE;
+ ExecuteFunction(key->func, key->action, Tmp_win->frame,
+ Tmp_win, &Event, C_FRAME, FALSE);
+ XUngrabPointer(dpy, CurrentTime);
+ }
+ }
+ if (matched)
+ return;
+ }
+ }
+ }
+
+ /* if we get here, no function key was bound to the key. Send it
+ * to the client if it was in a window we know about.
+ */
+ if (Tmp_win)
+ {
+ if (Event.xany.window == Tmp_win->icon_w ||
+ Event.xany.window == Tmp_win->frame ||
+ Event.xany.window == Tmp_win->title_w ||
+ (Tmp_win->list && (Event.xany.window == Tmp_win->list->w)))
+ {
+ Event.xkey.window = Tmp_win->w;
+ XSendEvent(dpy, Tmp_win->w, False, KeyPressMask, &Event);
+ }
+ }
+
+}
+
+
+
+static void free_window_names (tmp, nukefull, nukename, nukeicon)
+ TwmWindow *tmp;
+ Bool nukefull, nukename, nukeicon;
+{
+/*
+ * XXX - are we sure that nobody ever sets these to another constant (check
+ * twm windows)?
+ */
+ if (tmp->name == tmp->full_name) nukefull = False;
+ if (tmp->icon_name == tmp->name) nukename = False;
+
+#define isokay(v) ((v) && (v) != NoName)
+ if (nukefull && isokay(tmp->full_name)) XFree (tmp->full_name);
+ if (nukename && isokay(tmp->name)) XFree (tmp->name);
+ if (nukeicon && isokay(tmp->icon_name)) XFree (tmp->icon_name);
+#undef isokay
+ return;
+}
+
+
+
+void free_cwins (tmp)
+ TwmWindow *tmp;
+{
+ int i;
+ TwmColormap *cmap;
+
+ if (tmp->cmaps.number_cwins) {
+ for (i = 0; i < tmp->cmaps.number_cwins; i++) {
+ if (--tmp->cmaps.cwins[i]->refcnt == 0) {
+ cmap = tmp->cmaps.cwins[i]->colormap;
+ if (--cmap->refcnt == 0) {
+ XDeleteContext(dpy, cmap->c, ColormapContext);
+ free((char *) cmap);
+ }
+ XDeleteContext(dpy, tmp->cmaps.cwins[i]->w, ColormapContext);
+ free((char *) tmp->cmaps.cwins[i]);
+ }
+ }
+ free((char *) tmp->cmaps.cwins);
+ if (tmp->cmaps.number_cwins > 1) {
+ free(tmp->cmaps.scoreboard);
+ tmp->cmaps.scoreboard = NULL;
+ }
+ tmp->cmaps.number_cwins = 0;
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandlePropertyNotify - property notify event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandlePropertyNotify()
+{
+ char *prop = NULL;
+ Atom actual = None;
+ int actual_format;
+ unsigned long nitems, bytesafter;
+ unsigned long valuemask; /* mask for create windows */
+ XSetWindowAttributes attributes; /* attributes for create windows */
+ Pixmap pm;
+
+ /* watch for standard colormap changes */
+ if (Event.xproperty.window == Scr->Root) {
+ XStandardColormap *maps = NULL;
+ int nmaps;
+
+ switch (Event.xproperty.state) {
+ case PropertyNewValue:
+ if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps,
+ Event.xproperty.atom)) {
+ /* if got one, then replace any existing entry */
+ InsertRGBColormap (Event.xproperty.atom, maps, nmaps, True);
+ }
+ return;
+
+ case PropertyDelete:
+ RemoveRGBColormap (Event.xproperty.atom);
+ return;
+ }
+ }
+
+ if (!Tmp_win) return; /* unknown window */
+
+#define MAX_NAME_LEN 200L /* truncate to this many */
+#define MAX_ICON_NAME_LEN 200L /* ditto */
+
+ switch (Event.xproperty.atom) {
+ case XA_WM_NAME:
+ if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0L,
+ MAX_NAME_LEN, False, XA_STRING, &actual,
+ &actual_format, &nitems, &bytesafter,
+ (unsigned char **) &prop) != Success ||
+ actual == None)
+ return;
+ if (!prop) prop = NoName;
+ free_window_names (Tmp_win, True, True, False);
+
+ Tmp_win->full_name = prop;
+ Tmp_win->name = prop;
+
+ Tmp_win->nameChanged = 1;
+
+ Tmp_win->name_width = XTextWidth (Scr->TitleBarFont.font,
+ Tmp_win->name,
+ strlen (Tmp_win->name));
+
+ SetupWindow (Tmp_win, Tmp_win->frame_x, Tmp_win->frame_y,
+ Tmp_win->frame_width, Tmp_win->frame_height, -1);
+
+ if (Tmp_win->title_w) XClearArea(dpy, Tmp_win->title_w, 0,0,0,0, True);
+
+ /*
+ * if the icon name is NoName, set the name of the icon to be
+ * the same as the window
+ */
+ if (Tmp_win->icon_name == NoName) {
+ Tmp_win->icon_name = Tmp_win->name;
+ RedoIconName();
+ }
+ break;
+
+ case XA_WM_ICON_NAME:
+ if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0,
+ MAX_ICON_NAME_LEN, False, XA_STRING, &actual,
+ &actual_format, &nitems, &bytesafter,
+ (unsigned char **) &prop) != Success ||
+ actual == None)
+ return;
+ if (!prop) prop = NoName;
+ free_window_names (Tmp_win, False, False, True);
+ Tmp_win->icon_name = prop;
+
+ RedoIconName();
+ break;
+
+ case XA_WM_HINTS:
+ if (Tmp_win->wmhints) XFree ((char *) Tmp_win->wmhints);
+ Tmp_win->wmhints = XGetWMHints(dpy, Event.xany.window);
+
+ if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & WindowGroupHint))
+ Tmp_win->group = Tmp_win->wmhints->window_group;
+
+ if (Tmp_win->icon_not_ours && Tmp_win->wmhints &&
+ !(Tmp_win->wmhints->flags & IconWindowHint)) {
+ /* IconWindowHint was formerly on, now off; revert
+ // to a default icon */
+ int icon_x = 0, icon_y = 0;
+ XGetGeometry (dpy, Tmp_win->icon_w, &JunkRoot,
+ &icon_x, &icon_y,
+ &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth);
+ XSelectInput (dpy, Tmp_win->icon_w, None);
+ XDeleteContext (dpy, Tmp_win->icon_w, TwmContext);
+ XDeleteContext (dpy, Tmp_win->icon_w, ScreenContext);
+ CreateIconWindow(Tmp_win, icon_x, icon_y);
+ break;
+ }
+
+ if (!Tmp_win->forced && Tmp_win->wmhints &&
+ Tmp_win->wmhints->flags & IconWindowHint) {
+ if (Tmp_win->icon_w) {
+ int icon_x, icon_y;
+
+ /*
+ * There's already an icon window.
+ * Try to find out where it is; if we succeed, move the new
+ * window to where the old one is.
+ */
+ if (XGetGeometry (dpy, Tmp_win->icon_w, &JunkRoot, &icon_x,
+ &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth)) {
+ /*
+ * Move the new icon window to where the old one was.
+ */
+ XMoveWindow(dpy, Tmp_win->wmhints->icon_window, icon_x,
+ icon_y);
+ }
+
+ /*
+ * If the window is iconic, map the new icon window.
+ */
+ if (Tmp_win->icon)
+ XMapWindow(dpy, Tmp_win->wmhints->icon_window);
+
+ /*
+ * Now, if the old window isn't ours, unmap it, otherwise
+ * just get rid of it completely.
+ */
+ if (Tmp_win->icon_not_ours) {
+ if (Tmp_win->icon_w != Tmp_win->wmhints->icon_window)
+ XUnmapWindow(dpy, Tmp_win->icon_w);
+ } else
+ XDestroyWindow(dpy, Tmp_win->icon_w);
+
+ XDeleteContext(dpy, Tmp_win->icon_w, TwmContext);
+ XDeleteContext(dpy, Tmp_win->icon_w, ScreenContext);
+
+ /*
+ * The new icon window isn't our window, so note that fact
+ * so that we don't treat it as ours.
+ */
+ Tmp_win->icon_not_ours = TRUE;
+
+ /*
+ * Now make the new window the icon window for this window,
+ * and set it up to work as such (select for key presses
+ * and button presses/releases, set up the contexts for it,
+ * and define the cursor for it).
+ */
+ Tmp_win->icon_w = Tmp_win->wmhints->icon_window;
+ XSelectInput (dpy, Tmp_win->icon_w,
+ KeyPressMask | ButtonPressMask | ButtonReleaseMask);
+ XSaveContext(dpy, Tmp_win->icon_w, TwmContext, (caddr_t)Tmp_win);
+ XSaveContext(dpy, Tmp_win->icon_w, ScreenContext, (caddr_t)Scr);
+ XDefineCursor(dpy, Tmp_win->icon_w, Scr->IconCursor);
+ }
+ }
+
+ if (Tmp_win->icon_w && !Tmp_win->forced && Tmp_win->wmhints &&
+ (Tmp_win->wmhints->flags & IconPixmapHint)) {
+ if (!XGetGeometry (dpy, Tmp_win->wmhints->icon_pixmap, &JunkRoot,
+ &JunkX, &JunkY, (unsigned int *)&Tmp_win->icon_width,
+ (unsigned int *)&Tmp_win->icon_height, &JunkBW, &JunkDepth)) {
+ return;
+ }
+
+ pm = XCreatePixmap (dpy, Scr->Root, Tmp_win->icon_width,
+ Tmp_win->icon_height, Scr->d_depth);
+
+ FB(Tmp_win->iconc.fore, Tmp_win->iconc.back);
+ XCopyPlane(dpy, Tmp_win->wmhints->icon_pixmap, pm,
+ Scr->NormalGC,
+ 0,0, Tmp_win->icon_width, Tmp_win->icon_height, 0, 0, 1 );
+
+ valuemask = CWBackPixmap;
+ attributes.background_pixmap = pm;
+
+ if (Tmp_win->icon_bm_w)
+ XDestroyWindow(dpy, Tmp_win->icon_bm_w);
+
+ Tmp_win->icon_bm_w =
+ XCreateWindow (dpy, Tmp_win->icon_w, 0, 0,
+ (unsigned int) Tmp_win->icon_width,
+ (unsigned int) Tmp_win->icon_height,
+ (unsigned int) 0, Scr->d_depth,
+ (unsigned int) CopyFromParent, Scr->d_visual,
+ valuemask, &attributes);
+
+ XFreePixmap (dpy, pm);
+ RedoIconName();
+ }
+ break;
+
+ case XA_WM_NORMAL_HINTS:
+ GetWindowSizeHints (Tmp_win);
+ break;
+
+ default:
+ if (Event.xproperty.atom == _XA_WM_COLORMAP_WINDOWS) {
+ FetchWmColormapWindows (Tmp_win); /* frees old data */
+ break;
+ } else if (Event.xproperty.atom == _XA_WM_PROTOCOLS) {
+ FetchWmProtocols (Tmp_win);
+ break;
+ }
+ break;
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * RedoIconName - procedure to re-position the icon window and name
+ *
+ ***********************************************************************
+ */
+
+RedoIconName()
+{
+ int x, y;
+
+ if (Tmp_win->list)
+ {
+ /* let the expose event cause the repaint */
+ XClearArea(dpy, Tmp_win->list->w, 0,0,0,0, True);
+
+ if (Scr->SortIconMgr)
+ SortIconManager(Tmp_win->list->iconmgr);
+ }
+
+ if (Tmp_win->icon_w == (Window) 0)
+ return;
+
+ if (Tmp_win->icon_not_ours)
+ return;
+
+ Tmp_win->icon_w_width = XTextWidth(Scr->IconFont.font,
+ Tmp_win->icon_name, strlen(Tmp_win->icon_name));
+
+ Tmp_win->icon_w_width += 6;
+ if (Tmp_win->icon_w_width < Tmp_win->icon_width)
+ {
+ Tmp_win->icon_x = (Tmp_win->icon_width - Tmp_win->icon_w_width)/2;
+ Tmp_win->icon_x += 3;
+ Tmp_win->icon_w_width = Tmp_win->icon_width;
+ }
+ else
+ {
+ Tmp_win->icon_x = 3;
+ }
+
+ if (Tmp_win->icon_w_width == Tmp_win->icon_width)
+ x = 0;
+ else
+ x = (Tmp_win->icon_w_width - Tmp_win->icon_width)/2;
+
+ y = 0;
+
+ Tmp_win->icon_w_height = Tmp_win->icon_height + Scr->IconFont.height + 4;
+ Tmp_win->icon_y = Tmp_win->icon_height + Scr->IconFont.height;
+
+ XResizeWindow(dpy, Tmp_win->icon_w, Tmp_win->icon_w_width,
+ Tmp_win->icon_w_height);
+ if (Tmp_win->icon_bm_w)
+ {
+ XMoveWindow(dpy, Tmp_win->icon_bm_w, x, y);
+ XMapWindow(dpy, Tmp_win->icon_bm_w);
+ }
+ if (Tmp_win->icon)
+ {
+ XClearArea(dpy, Tmp_win->icon_w, 0, 0, 0, 0, True);
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleClientMessage - client message event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleClientMessage()
+{
+ if (Event.xclient.message_type == _XA_WM_CHANGE_STATE)
+ {
+ if (Tmp_win != NULL)
+ {
+ if (Event.xclient.data.l[0] == IconicState && !Tmp_win->icon)
+ {
+ XEvent button;
+
+ XQueryPointer( dpy, Scr->Root, &JunkRoot, &JunkChild,
+ &(button.xmotion.x_root),
+ &(button.xmotion.y_root),
+ &JunkX, &JunkY, &JunkMask);
+
+ ExecuteFunction(F_ICONIFY, NULLSTR, Event.xany.window,
+ Tmp_win, &button, FRAME, FALSE);
+ XUngrabPointer(dpy, CurrentTime);
+ }
+ }
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleExpose - expose event handler
+ *
+ ***********************************************************************
+ */
+
+static void flush_expose();
+
+void
+HandleExpose()
+{
+ MenuRoot *tmp;
+ if (XFindContext(dpy, Event.xany.window, MenuContext, (caddr_t *)&tmp) == 0)
+ {
+ PaintMenu(tmp, &Event);
+ return;
+ }
+
+ if (Event.xexpose.count != 0)
+ return;
+
+ if (Event.xany.window == Scr->InfoWindow && InfoLines)
+ {
+ int i;
+ int height;
+
+ FBF(Scr->DefaultC.fore, Scr->DefaultC.back,
+ Scr->DefaultFont.font->fid);
+
+ height = Scr->DefaultFont.height+2;
+ for (i = 0; i < InfoLines; i++)
+ {
+ XDrawString(dpy, Scr->InfoWindow, Scr->NormalGC,
+ 5, (i*height) + Scr->DefaultFont.y, Info[i], strlen(Info[i]));
+ }
+ flush_expose (Event.xany.window);
+ }
+ else if (Tmp_win != NULL)
+ {
+ if (Event.xany.window == Tmp_win->title_w)
+ {
+ FBF(Tmp_win->title.fore, Tmp_win->title.back,
+ Scr->TitleBarFont.font->fid);
+
+ XDrawString (dpy, Tmp_win->title_w, Scr->NormalGC,
+ Scr->TBInfo.titlex, Scr->TitleBarFont.y,
+ Tmp_win->name, strlen(Tmp_win->name));
+ flush_expose (Event.xany.window);
+ }
+ else if (Event.xany.window == Tmp_win->icon_w)
+ {
+ FBF(Tmp_win->iconc.fore, Tmp_win->iconc.back,
+ Scr->IconFont.font->fid);
+
+ XDrawString (dpy, Tmp_win->icon_w,
+ Scr->NormalGC,
+ Tmp_win->icon_x, Tmp_win->icon_y,
+ Tmp_win->icon_name, strlen(Tmp_win->icon_name));
+ flush_expose (Event.xany.window);
+ return;
+ } else if (Tmp_win->titlebuttons) {
+ int i;
+ Window w = Event.xany.window;
+ register TBWindow *tbw;
+ int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
+
+ for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
+ if (w == tbw->window) {
+ register TitleButton *tb = tbw->info;
+
+ FB(Tmp_win->title.fore, Tmp_win->title.back);
+ XCopyPlane (dpy, tb->bitmap, w, Scr->NormalGC,
+ tb->srcx, tb->srcy, tb->width, tb->height,
+ tb->dstx, tb->dsty, 1);
+ flush_expose (w);
+ return;
+ }
+ }
+ }
+ if (Tmp_win->list) {
+ if (Event.xany.window == Tmp_win->list->w)
+ {
+ FBF(Tmp_win->list->fore, Tmp_win->list->back,
+ Scr->IconManagerFont.font->fid);
+ XDrawString (dpy, Event.xany.window, Scr->NormalGC,
+ iconmgr_textx, Scr->IconManagerFont.y+4,
+ Tmp_win->icon_name, strlen(Tmp_win->icon_name));
+ DrawIconManagerBorder(Tmp_win->list);
+ flush_expose (Event.xany.window);
+ return;
+ }
+ if (Event.xany.window == Tmp_win->list->icon)
+ {
+ FB(Tmp_win->list->fore, Tmp_win->list->back);
+ XCopyPlane(dpy, Scr->siconifyPm, Tmp_win->list->icon,
+ Scr->NormalGC,
+ 0,0, iconifybox_width, iconifybox_height, 0, 0, 1);
+ flush_expose (Event.xany.window);
+ return;
+ }
+ }
+ }
+}
+
+
+
+static void remove_window_from_ring (tmp)
+ TwmWindow *tmp;
+{
+ TwmWindow *prev = tmp->ring.prev, *next = tmp->ring.next;
+
+ if (enter_win == tmp) {
+ enter_flag = FALSE;
+ enter_win = NULL;
+ }
+ if (raise_win == Tmp_win) raise_win = NULL;
+
+ /*
+ * 1. Unlink window
+ * 2. If window was only thing in ring, null out ring
+ * 3. If window was ring leader, set to next (or null)
+ */
+ if (prev) prev->ring.next = next;
+ if (next) next->ring.prev = prev;
+ if (Scr->Ring == tmp)
+ Scr->Ring = (next != tmp ? next : (TwmWindow *) NULL);
+
+ if (!Scr->Ring || Scr->RingLeader == tmp) Scr->RingLeader = Scr->Ring;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleDestroyNotify - DestroyNotify event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleDestroyNotify()
+{
+ int i;
+
+ /*
+ * Warning, this is also called by HandleUnmapNotify; if it ever needs to
+ * look at the event, HandleUnmapNotify will have to mash the UnmapNotify
+ * into a DestroyNotify.
+ */
+
+ if (Tmp_win == NULL)
+ return;
+
+ if (Tmp_win == Scr->Focus)
+ {
+ FocusOnRoot();
+ }
+ XDeleteContext(dpy, Tmp_win->w, TwmContext);
+ XDeleteContext(dpy, Tmp_win->w, ScreenContext);
+ XDeleteContext(dpy, Tmp_win->frame, TwmContext);
+ XDeleteContext(dpy, Tmp_win->frame, ScreenContext);
+ if (Tmp_win->icon_w)
+ {
+ XDeleteContext(dpy, Tmp_win->icon_w, TwmContext);
+ XDeleteContext(dpy, Tmp_win->icon_w, ScreenContext);
+ }
+ if (Tmp_win->title_height)
+ {
+ int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
+ XDeleteContext(dpy, Tmp_win->title_w, TwmContext);
+ XDeleteContext(dpy, Tmp_win->title_w, ScreenContext);
+ if (Tmp_win->hilite_w)
+ {
+ XDeleteContext(dpy, Tmp_win->hilite_w, TwmContext);
+ XDeleteContext(dpy, Tmp_win->hilite_w, ScreenContext);
+ }
+ if (Tmp_win->titlebuttons) {
+ for (i = 0; i < nb; i++) {
+ XDeleteContext (dpy, Tmp_win->titlebuttons[i].window,
+ TwmContext);
+ XDeleteContext (dpy, Tmp_win->titlebuttons[i].window,
+ ScreenContext);
+ }
+ }
+ }
+
+ if (Scr->cmapInfo.cmaps == &Tmp_win->cmaps)
+ InstallWindowColormaps(DestroyNotify, &Scr->TwmRoot);
+
+ /*
+ * TwmWindows contain the following pointers
+ *
+ * 1. full_name
+ * 2. name
+ * 3. icon_name
+ * 4. wmhints
+ * 5. class.res_name
+ * 6. class.res_class
+ * 7. list
+ * 8. iconmgrp
+ * 9. cwins
+ * 10. titlebuttons
+ * 11. window ring
+ */
+ if (Tmp_win->gray) XFreePixmap (dpy, Tmp_win->gray);
+
+ XDestroyWindow(dpy, Tmp_win->frame);
+ if (Tmp_win->icon_w && !Tmp_win->icon_not_ours) {
+ XDestroyWindow(dpy, Tmp_win->icon_w);
+ IconDown (Tmp_win);
+ }
+ RemoveIconManager(Tmp_win); /* 7 */
+ Tmp_win->prev->next = Tmp_win->next;
+ if (Tmp_win->next != NULL)
+ Tmp_win->next->prev = Tmp_win->prev;
+ if (Tmp_win->auto_raise) Scr->NumAutoRaises--;
+
+ free_window_names (Tmp_win, True, True, True); /* 1, 2, 3 */
+ if (Tmp_win->wmhints) /* 4 */
+ XFree ((char *)Tmp_win->wmhints);
+ if (Tmp_win->class.res_name && Tmp_win->class.res_name != NoName) /* 5 */
+ XFree ((char *)Tmp_win->class.res_name);
+ if (Tmp_win->class.res_class && Tmp_win->class.res_class != NoName) /* 6 */
+ XFree ((char *)Tmp_win->class.res_class);
+ free_cwins (Tmp_win); /* 9 */
+ if (Tmp_win->titlebuttons) /* 10 */
+ free ((char *) Tmp_win->titlebuttons);
+ remove_window_from_ring (Tmp_win); /* 11 */
+
+ if (UnHighLight_win == Tmp_win)
+ UnHighLight_win = NULL;
+
+ free((char *)Tmp_win);
+}
+
+
+
+void
+HandleCreateNotify()
+{
+#ifdef DEBUG_EVENTS
+ fprintf(stderr, "CreateNotify w = 0x%x\n", Event.xcreatewindow.window);
+ fflush(stderr);
+ Bell(XkbBI_Info,0,Event.xcreatewindow.window);
+ XSync(dpy, 0);
+#endif
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleMapRequest - MapRequest event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleMapRequest()
+{
+ int stat;
+ int zoom_save;
+
+ Event.xany.window = Event.xmaprequest.window;
+ stat = XFindContext(dpy, Event.xany.window, TwmContext, (caddr_t *)&Tmp_win);
+ if (stat == XCNOENT)
+ Tmp_win = NULL;
+
+ /* If the window has never been mapped before ... */
+ if (Tmp_win == NULL)
+ {
+ /* Add decorations. */
+ Tmp_win = AddWindow(Event.xany.window, FALSE, (IconMgr *) NULL);
+ if (Tmp_win == NULL)
+ return;
+ }
+ else
+ {
+ /*
+ * If the window has been unmapped by the client, it won't be listed
+ * in the icon manager. Add it again, if requested.
+ */
+ if (Tmp_win->list == NULL)
+ (void) AddIconManager (Tmp_win);
+ }
+
+ /* If it's not merely iconified, and we have hints, use them. */
+ if ((! Tmp_win->icon) &&
+ Tmp_win->wmhints && (Tmp_win->wmhints->flags & StateHint))
+ {
+ int state;
+ Window icon;
+
+ /* use WM_STATE if enabled */
+ if (!(RestartPreviousState && GetWMState(Tmp_win->w, &state, &icon) &&
+ (state == NormalState || state == IconicState)))
+ state = Tmp_win->wmhints->initial_state;
+
+ switch (state)
+ {
+ case DontCareState:
+ case NormalState:
+ case ZoomState:
+ case InactiveState:
+ XMapWindow(dpy, Tmp_win->w);
+ XMapWindow(dpy, Tmp_win->frame);
+ SetMapStateProp(Tmp_win, NormalState);
+ SetRaiseWindow (Tmp_win);
+ break;
+
+ case IconicState:
+ zoom_save = Scr->DoZoom;
+ Scr->DoZoom = FALSE;
+ Iconify(Tmp_win, 0, 0);
+ Scr->DoZoom = zoom_save;
+ break;
+ }
+ }
+ /* If no hints, or currently an icon, just "deiconify" */
+ else
+ {
+ DeIconify(Tmp_win);
+ SetRaiseWindow (Tmp_win);
+ }
+}
+
+
+
+void SimulateMapRequest (w)
+ Window w;
+{
+ Event.xmaprequest.window = w;
+ HandleMapRequest ();
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleMapNotify - MapNotify event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleMapNotify()
+{
+ if (Tmp_win == NULL)
+ return;
+
+ /*
+ * Need to do the grab to avoid race condition of having server send
+ * MapNotify to client before the frame gets mapped; this is bad because
+ * the client would think that the window has a chance of being viewable
+ * when it really isn't.
+ */
+ XGrabServer (dpy);
+ if (Tmp_win->icon_w)
+ XUnmapWindow(dpy, Tmp_win->icon_w);
+ if (Tmp_win->title_w)
+ XMapSubwindows(dpy, Tmp_win->title_w);
+ XMapSubwindows(dpy, Tmp_win->frame);
+ if (Scr->Focus != Tmp_win && Tmp_win->hilite_w)
+ XUnmapWindow(dpy, Tmp_win->hilite_w);
+
+ XMapWindow(dpy, Tmp_win->frame);
+ XUngrabServer (dpy);
+ XFlush (dpy);
+ Tmp_win->mapped = TRUE;
+ Tmp_win->icon = FALSE;
+ Tmp_win->icon_on = FALSE;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleUnmapNotify - UnmapNotify event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleUnmapNotify()
+{
+ int dstx, dsty;
+ Window dumwin;
+
+ /*
+ * The July 27, 1988 ICCCM spec states that a client wishing to switch
+ * to WithdrawnState should send a synthetic UnmapNotify with the
+ * event field set to (pseudo-)root, in case the window is already
+ * unmapped (which is the case for twm for IconicState). Unfortunately,
+ * we looked for the TwmContext using that field, so try the window
+ * field also.
+ */
+ if (Tmp_win == NULL)
+ {
+ Event.xany.window = Event.xunmap.window;
+ if (XFindContext(dpy, Event.xany.window,
+ TwmContext, (caddr_t *)&Tmp_win) == XCNOENT)
+ Tmp_win = NULL;
+ }
+
+ if (Tmp_win == NULL || (!Tmp_win->mapped && !Tmp_win->icon))
+ return;
+
+ /*
+ * The program may have unmapped the client window, from either
+ * NormalState or IconicState. Handle the transition to WithdrawnState.
+ *
+ * We need to reparent the window back to the root (so that twm exiting
+ * won't cause it to get mapped) and then throw away all state (pretend
+ * that we've received a DestroyNotify).
+ */
+
+ XGrabServer (dpy);
+ if (XTranslateCoordinates (dpy, Event.xunmap.window, Tmp_win->attr.root,
+ 0, 0, &dstx, &dsty, &dumwin)) {
+ XEvent ev;
+ Bool reparented = XCheckTypedWindowEvent (dpy, Event.xunmap.window,
+ ReparentNotify, &ev);
+ SetMapStateProp (Tmp_win, WithdrawnState);
+ if (reparented) {
+ if (Tmp_win->old_bw) XSetWindowBorderWidth (dpy,
+ Event.xunmap.window,
+ Tmp_win->old_bw);
+ if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & IconWindowHint))
+ XUnmapWindow (dpy, Tmp_win->wmhints->icon_window);
+ } else {
+ XReparentWindow (dpy, Event.xunmap.window, Tmp_win->attr.root,
+ dstx, dsty);
+ RestoreWithdrawnLocation (Tmp_win);
+ }
+ XRemoveFromSaveSet (dpy, Event.xunmap.window);
+ XSelectInput (dpy, Event.xunmap.window, NoEventMask);
+ HandleDestroyNotify (); /* do not need to mash event before */
+ } /* else window no longer exists and we'll get a destroy notify */
+ XUngrabServer (dpy);
+ XFlush (dpy);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleMotionNotify - MotionNotify event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleMotionNotify()
+{
+ if (ResizeWindow != (Window) 0)
+ {
+ XQueryPointer( dpy, Event.xany.window,
+ &(Event.xmotion.root), &JunkChild,
+ &(Event.xmotion.x_root), &(Event.xmotion.y_root),
+ &(Event.xmotion.x), &(Event.xmotion.y),
+ &JunkMask);
+
+ /* Set WindowMoved appropriately so that f.deltastop will
+ work with resize as well as move. */
+ if (abs (Event.xmotion.x - ResizeOrigX) >= Scr->MoveDelta
+ || abs (Event.xmotion.y - ResizeOrigY) >= Scr->MoveDelta)
+ WindowMoved = TRUE;
+
+ XFindContext(dpy, ResizeWindow, TwmContext, (caddr_t *)&Tmp_win);
+ DoResize(Event.xmotion.x_root, Event.xmotion.y_root, Tmp_win);
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleButtonRelease - ButtonRelease event handler
+ *
+ ***********************************************************************
+ */
+void
+HandleButtonRelease()
+{
+ int xl, xr, yt, yb, w, h;
+ unsigned mask;
+
+ if (InfoLines) /* delete info box on 2nd button release */
+ if (Context == C_IDENTIFY) {
+ XUnmapWindow(dpy, Scr->InfoWindow);
+ InfoLines = 0;
+ Context = C_NO_CONTEXT;
+ }
+
+ if (DragWindow != None)
+ {
+ MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+
+ XFindContext(dpy, DragWindow, TwmContext, (caddr_t *)&Tmp_win);
+ if (DragWindow == Tmp_win->frame)
+ {
+ xl = Event.xbutton.x_root - DragX - Tmp_win->frame_bw;
+ yt = Event.xbutton.y_root - DragY - Tmp_win->frame_bw;
+ w = DragWidth + 2 * Tmp_win->frame_bw;
+ h = DragHeight + 2 * Tmp_win->frame_bw;
+ }
+ else
+ {
+ xl = Event.xbutton.x_root - DragX - Scr->IconBorderWidth;
+ yt = Event.xbutton.y_root - DragY - Scr->IconBorderWidth;
+ w = DragWidth + 2 * Scr->IconBorderWidth;
+ h = DragHeight + 2 * Scr->IconBorderWidth;
+ }
+
+ if (ConstMove)
+ {
+ if (ConstMoveDir == MOVE_HORIZ)
+ yt = ConstMoveY;
+
+ if (ConstMoveDir == MOVE_VERT)
+ xl = ConstMoveX;
+
+ if (ConstMoveDir == MOVE_NONE)
+ {
+ yt = ConstMoveY;
+ xl = ConstMoveX;
+ }
+ }
+
+ if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
+ {
+ xr = xl + w;
+ yb = yt + h;
+
+ if (xl < 0)
+ xl = 0;
+ if (xr > Scr->MyDisplayWidth)
+ xl = Scr->MyDisplayWidth - w;
+
+ if (yt < 0)
+ yt = 0;
+ if (yb > Scr->MyDisplayHeight)
+ yt = Scr->MyDisplayHeight - h;
+ }
+
+ CurrentDragX = xl;
+ CurrentDragY = yt;
+ if (DragWindow == Tmp_win->frame)
+ SetupWindow (Tmp_win, xl, yt,
+ Tmp_win->frame_width, Tmp_win->frame_height, -1);
+ else
+ XMoveWindow (dpy, DragWindow, xl, yt);
+
+ if (!Scr->NoRaiseMove && !Scr->OpaqueMove) /* opaque already did */
+ XRaiseWindow(dpy, DragWindow);
+
+ if (!Scr->OpaqueMove)
+ UninstallRootColormap();
+ else
+ XSync(dpy, 0);
+
+ if (Scr->NumAutoRaises) {
+ enter_flag = TRUE;
+ enter_win = NULL;
+ raise_win = ((DragWindow == Tmp_win->frame && !Scr->NoRaiseMove)
+ ? Tmp_win : NULL);
+ }
+
+ DragWindow = (Window) 0;
+ ConstMove = FALSE;
+ }
+
+ if (ResizeWindow != (Window) 0)
+ {
+ EndResize();
+ }
+
+ if (ActiveMenu != NULL && RootFunction == 0)
+ {
+ if (ActiveItem != NULL)
+ {
+ int func = ActiveItem->func;
+ Action = ActiveItem->action;
+ switch (func) {
+ case F_MOVE:
+ case F_FORCEMOVE:
+ ButtonPressed = -1;
+ break;
+ case F_CIRCLEUP:
+ case F_CIRCLEDOWN:
+ case F_REFRESH:
+ case F_WARPTOSCREEN:
+ PopDownMenu();
+ break;
+ default:
+ break;
+ }
+ ExecuteFunction(func, Action,
+ ButtonWindow ? ButtonWindow->frame : None,
+ ButtonWindow, &Event/*&ButtonEvent*/, Context, TRUE);
+ Context = C_NO_CONTEXT;
+ ButtonWindow = NULL;
+
+ /* if we are not executing a defered command, then take down the
+ * menu
+ */
+ if (RootFunction == 0)
+ {
+ PopDownMenu();
+ }
+ }
+ else
+ PopDownMenu();
+ }
+
+ mask = (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask);
+ switch (Event.xbutton.button)
+ {
+ case Button1: mask &= ~Button1Mask; break;
+ case Button2: mask &= ~Button2Mask; break;
+ case Button3: mask &= ~Button3Mask; break;
+ case Button4: mask &= ~Button4Mask; break;
+ case Button5: mask &= ~Button5Mask; break;
+ }
+
+ if (RootFunction != 0 ||
+ ResizeWindow != None ||
+ DragWindow != None)
+ ButtonPressed = -1;
+
+ if (RootFunction == 0 &&
+ (Event.xbutton.state & mask) == 0 &&
+ DragWindow == None &&
+ ResizeWindow == None)
+ {
+ XUngrabPointer(dpy, CurrentTime);
+ XUngrabServer(dpy);
+ XFlush(dpy);
+ EventHandler[EnterNotify] = HandleEnterNotify;
+ EventHandler[LeaveNotify] = HandleLeaveNotify;
+ ButtonPressed = -1;
+ if (DownIconManager)
+ {
+ DownIconManager->down = FALSE;
+ if (Scr->Highlight) DrawIconManagerBorder(DownIconManager);
+ DownIconManager = NULL;
+ }
+ Cancel = FALSE;
+ }
+}
+
+
+
+static do_menu (menu, w)
+ MenuRoot *menu; /* menu to pop up */
+ Window w; /* invoking window or None */
+{
+ int x = Event.xbutton.x_root;
+ int y = Event.xbutton.y_root;
+ Bool center;
+
+ if (!Scr->NoGrabServer)
+ XGrabServer(dpy);
+ if (w) {
+ int h = Scr->TBInfo.width - Scr->TBInfo.border;
+ Window child;
+
+ (void) XTranslateCoordinates (dpy, w, Scr->Root, 0, h, &x, &y, &child);
+ center = False;
+ } else {
+ center = True;
+ }
+ if (PopUpMenu (menu, x, y, center)) {
+ UpdateMenu();
+ } else {
+ Bell(XkbBI_MinorError,0,w);
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleButtonPress - ButtonPress event handler
+ *
+ ***********************************************************************
+ */
+void
+HandleButtonPress()
+{
+ unsigned int modifier;
+ Cursor cur;
+
+ /* pop down the menu, if any */
+ if (ActiveMenu != NULL)
+ PopDownMenu();
+
+ XSync(dpy, 0); /* XXX - remove? */
+
+ if (ButtonPressed != -1 && !InfoLines) /* want menus if we have info box */
+ {
+ /* we got another butt press in addition to one still held
+ * down, we need to cancel the operation we were doing
+ */
+ Cancel = TRUE;
+ CurrentDragX = origDragX;
+ CurrentDragY = origDragY;
+ if (!menuFromFrameOrWindowOrTitlebar)
+ if (Scr->OpaqueMove && DragWindow != None) {
+ XMoveWindow (dpy, DragWindow, origDragX, origDragY);
+ } else {
+ MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+ }
+ XUnmapWindow(dpy, Scr->SizeWindow);
+ if (!Scr->OpaqueMove)
+ UninstallRootColormap();
+ ResizeWindow = None;
+ DragWindow = None;
+ cur = LeftButt;
+ if (Event.xbutton.button == Button2)
+ cur = MiddleButt;
+ else if (Event.xbutton.button >= Button3)
+ cur = RightButt;
+
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonReleaseMask | ButtonPressMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, cur, CurrentTime);
+
+ return;
+ }
+ else
+ ButtonPressed = Event.xbutton.button;
+
+ if (ResizeWindow != None ||
+ DragWindow != None ||
+ ActiveMenu != NULL)
+ return;
+
+ /* check the title bar buttons */
+ if (Tmp_win && Tmp_win->title_height && Tmp_win->titlebuttons)
+ {
+ register int i;
+ register TBWindow *tbw;
+ int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
+
+ for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
+ if (Event.xany.window == tbw->window) {
+ if (tbw->info->func == F_MENU) {
+ Context = C_TITLE;
+ ButtonEvent = Event;
+ ButtonWindow = Tmp_win;
+ do_menu (tbw->info->menuroot, tbw->window);
+ } else {
+ ExecuteFunction (tbw->info->func, tbw->info->action,
+ Event.xany.window, Tmp_win, &Event,
+ C_TITLE, FALSE);
+ }
+ return;
+ }
+ }
+ }
+
+ Context = C_NO_CONTEXT;
+
+ if (Event.xany.window == Scr->InfoWindow)
+ Context = C_IDENTIFY;
+
+ if (Event.xany.window == Scr->Root)
+ Context = C_ROOT;
+ if (Tmp_win)
+ {
+ if (Tmp_win->list && RootFunction != 0 &&
+ (Event.xany.window == Tmp_win->list->w ||
+ Event.xany.window == Tmp_win->list->icon))
+ {
+ Tmp_win = Tmp_win->list->iconmgr->twm_win;
+ XTranslateCoordinates(dpy, Event.xany.window, Tmp_win->w,
+ Event.xbutton.x, Event.xbutton.y,
+ &JunkX, &JunkY, &JunkChild);
+
+ Event.xbutton.x = JunkX;
+ Event.xbutton.y = JunkY - Tmp_win->title_height;
+ Event.xany.window = Tmp_win->w;
+ Context = C_WINDOW;
+ }
+ else if (Event.xany.window == Tmp_win->title_w)
+ {
+ Context = C_TITLE;
+ }
+ else if (Event.xany.window == Tmp_win->w)
+ {
+ printf("ERROR! ERROR! ERROR! YOU SHOULD NOT BE HERE!!!\n");
+ Context = C_WINDOW;
+ }
+ else if (Event.xany.window == Tmp_win->icon_w)
+ {
+ Context = C_ICON;
+ }
+ else if (Event.xany.window == Tmp_win->frame)
+ {
+ /* since we now place a button grab on the frame instead
+ * of the window, (see GrabButtons() in add_window.c), we
+ * need to figure out where the pointer exactly is before
+ * assigning Context. If the pointer is on the application
+ * window we will change the event structure to look as if
+ * it came from the application window.
+ */
+ if (Event.xbutton.subwindow == Tmp_win->w) {
+ Event.xbutton.window = Tmp_win->w;
+ Event.xbutton.y -= Tmp_win->title_height;
+/*****
+ Event.xbutton.x -= Tmp_win->frame_bw;
+*****/
+ Context = C_WINDOW;
+ }
+ else Context = C_FRAME;
+ }
+ else if (Tmp_win->list &&
+ (Event.xany.window == Tmp_win->list->w ||
+ Event.xany.window == Tmp_win->list->icon))
+ {
+ Tmp_win->list->down = TRUE;
+ if (Scr->Highlight) DrawIconManagerBorder(Tmp_win->list);
+ DownIconManager = Tmp_win->list;
+ Context = C_ICONMGR;
+ }
+ }
+
+ /* this section of code checks to see if we were in the middle of
+ * a command executed from a menu
+ */
+ if (RootFunction != 0)
+ {
+ if (Event.xany.window == Scr->Root)
+ {
+ /* if the window was the Root, we don't know for sure it
+ * it was the root. We must check to see if it happened to be
+ * inside of a client that was getting button press events.
+ */
+ XTranslateCoordinates(dpy, Scr->Root, Scr->Root,
+ Event.xbutton.x,
+ Event.xbutton.y,
+ &JunkX, &JunkY, &Event.xany.window);
+
+ if (Event.xany.window == 0 ||
+ (XFindContext(dpy, Event.xany.window, TwmContext,
+ (caddr_t *)&Tmp_win) == XCNOENT))
+ {
+ RootFunction = 0;
+ Bell(XkbBI_MinorError,0,Event.xany.window);
+ return;
+ }
+
+ XTranslateCoordinates(dpy, Scr->Root, Event.xany.window,
+ Event.xbutton.x,
+ Event.xbutton.y,
+ &JunkX, &JunkY, &JunkChild);
+
+ Event.xbutton.x = JunkX;
+ Event.xbutton.y = JunkY;
+ Context = C_WINDOW;
+ }
+
+ /* make sure we are not trying to move an identify window */
+ if (Event.xany.window != Scr->InfoWindow)
+ ExecuteFunction(RootFunction, Action, Event.xany.window,
+ Tmp_win, &Event, Context, FALSE);
+
+ RootFunction = 0;
+ return;
+ }
+
+ ButtonEvent = Event;
+ ButtonWindow = Tmp_win;
+
+ /* if we get to here, we have to execute a function or pop up a
+ * menu
+ */
+ modifier = (Event.xbutton.state & mods_used);
+
+ if (Context == C_NO_CONTEXT)
+ return;
+
+ RootFunction = 0;
+ if (Scr->Mouse[Event.xbutton.button][Context][modifier].func == F_MENU)
+ {
+ do_menu (Scr->Mouse[Event.xbutton.button][Context][modifier].menu,
+ (Window) None);
+ }
+ else if (Scr->Mouse[Event.xbutton.button][Context][modifier].func != 0)
+ {
+ Action = Scr->Mouse[Event.xbutton.button][Context][modifier].item ?
+ Scr->Mouse[Event.xbutton.button][Context][modifier].item->action : NULL;
+ ExecuteFunction(Scr->Mouse[Event.xbutton.button][Context][modifier].func,
+ Action, Event.xany.window, Tmp_win, &Event, Context, FALSE);
+ }
+ else if (Scr->DefaultFunction.func != 0)
+ {
+ if (Scr->DefaultFunction.func == F_MENU)
+ {
+ do_menu (Scr->DefaultFunction.menu, (Window) None);
+ }
+ else
+ {
+ Action = Scr->DefaultFunction.item ?
+ Scr->DefaultFunction.item->action : NULL;
+ ExecuteFunction(Scr->DefaultFunction.func, Action,
+ Event.xany.window, Tmp_win, &Event, Context, FALSE);
+ }
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HENQueueScanner - EnterNotify event q scanner
+ *
+ * Looks at the queued events and determines if any matching
+ * LeaveNotify events or EnterEvents deriving from the
+ * termination of a grab are behind this event to allow
+ * skipping of unnecessary processing.
+ *
+ ***********************************************************************
+ */
+
+typedef struct HENScanArgs {
+ Window w; /* Window we are currently entering */
+ Bool leaves; /* Any LeaveNotifies found for this window */
+ Bool inferior; /* Was NotifyInferior the mode for LeaveNotify */
+ Bool enters; /* Any EnterNotify events with NotifyUngrab */
+} HENScanArgs;
+
+/* ARGSUSED*/
+static Bool
+HENQueueScanner(dpy, ev, args)
+ Display *dpy;
+ XEvent *ev;
+ char *args;
+{
+ if (ev->type == LeaveNotify) {
+ if (ev->xcrossing.window == ((HENScanArgs *) args)->w &&
+ ev->xcrossing.mode == NotifyNormal) {
+ ((HENScanArgs *) args)->leaves = True;
+ /*
+ * Only the last event found matters for the Inferior field.
+ */
+ ((HENScanArgs *) args)->inferior =
+ (ev->xcrossing.detail == NotifyInferior);
+ }
+ } else if (ev->type == EnterNotify) {
+ if (ev->xcrossing.mode == NotifyUngrab)
+ ((HENScanArgs *) args)->enters = True;
+ }
+
+ return (False);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleEnterNotify - EnterNotify event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleEnterNotify()
+{
+ MenuRoot *mr;
+ XEnterWindowEvent *ewp = &Event.xcrossing;
+ HENScanArgs scanArgs;
+ XEvent dummy;
+
+ /*
+ * Save the id of the window entered. This will be used to remove
+ * border highlight on entering the next application window.
+ */
+ if (UnHighLight_win && ewp->window != UnHighLight_win->w) {
+ SetBorder (UnHighLight_win, False); /* application window */
+ if (UnHighLight_win->list) /* in the icon box */
+ NotActiveIconManager(UnHighLight_win->list);
+ }
+ if (ewp->window == Scr->Root)
+ UnHighLight_win = NULL;
+ else if (Tmp_win)
+ UnHighLight_win = Tmp_win;
+
+ /*
+ * if we aren't in the middle of menu processing
+ */
+ if (!ActiveMenu) {
+ /*
+ * We're not interested in pseudo Enter/Leave events generated
+ * from grab initiations.
+ */
+ if (ewp->mode == NotifyGrab)
+ return;
+
+ /*
+ * Scan for Leave and Enter Notify events to see if we can avoid some
+ * unnecessary processing.
+ */
+ scanArgs.w = ewp->window;
+ scanArgs.leaves = scanArgs.enters = False;
+ (void) XCheckIfEvent(dpy, &dummy, HENQueueScanner, (char *) &scanArgs);
+
+ /*
+ * if entering root window, restore twm default colormap so that
+ * titlebars are legible
+ */
+ if (ewp->window == Scr->Root) {
+ if (!scanArgs.leaves && !scanArgs.enters)
+ InstallWindowColormaps(EnterNotify, &Scr->TwmRoot);
+ return;
+ }
+
+ /*
+ * if we have an event for a specific one of our windows
+ */
+ if (Tmp_win) {
+ /*
+ * If currently in PointerRoot mode (indicated by FocusRoot), then
+ * focus on this window
+ */
+ if (Scr->FocusRoot && (!scanArgs.leaves || scanArgs.inferior)) {
+ if (Tmp_win->list) ActiveIconManager(Tmp_win->list);
+ if (Tmp_win->mapped) {
+ /*
+ * unhighlight old focus window
+ */
+ if (Scr->Focus &&
+ Scr->Focus != Tmp_win && Tmp_win->hilite_w)
+ XUnmapWindow(dpy, Scr->Focus->hilite_w);
+
+ /*
+ * If entering the frame or the icon manager, then do
+ * "window activation things":
+ *
+ * 1. turn on highlight window (if any)
+ * 2. install frame colormap
+ * 3. set frame and highlight window (if any) border
+ * 4. focus on client window to forward typing
+ * 4a. same as 4 but for icon mgr w/with NoTitlebar on.
+ * 5. send WM_TAKE_FOCUS if requested
+ */
+ if (ewp->window == Tmp_win->frame ||
+ (Tmp_win->list && ewp->window == Tmp_win->list->w)) {
+ if (Tmp_win->hilite_w) /* 1 */
+ XMapWindow (dpy, Tmp_win->hilite_w);
+ if (!scanArgs.leaves && !scanArgs.enters)
+ InstallWindowColormaps (EnterNotify, /* 2 */
+ &Scr->TwmRoot);
+ SetBorder (Tmp_win, True); /* 3 */
+ if (Tmp_win->title_w && Scr->TitleFocus && /* 4 */
+ Tmp_win->wmhints && Tmp_win->wmhints->input)
+ SetFocus (Tmp_win, ewp->time);
+ if (Scr->NoTitlebar && Scr->TitleFocus && /*4a */
+ Tmp_win->wmhints && Tmp_win->wmhints->input)
+ SetFocus (Tmp_win, ewp->time);
+ if (Tmp_win->protocols & DoesWmTakeFocus) /* 5 */
+ SendTakeFocusMessage (Tmp_win, ewp->time);
+ Scr->Focus = Tmp_win;
+ } else if (ewp->window == Tmp_win->w) {
+ /*
+ * If we are entering the application window, install
+ * its colormap(s).
+ */
+ if (!scanArgs.leaves || scanArgs.inferior)
+ InstallWindowColormaps(EnterNotify, Tmp_win);
+ }
+ } /* end if Tmp_win->mapped */
+ if (Tmp_win->wmhints != NULL &&
+ ewp->window == Tmp_win->wmhints->icon_window &&
+ (!scanArgs.leaves || scanArgs.inferior))
+ InstallWindowColormaps(EnterNotify, Tmp_win);
+ } /* end if FocusRoot */
+ /*
+ * If this window is to be autoraised, mark it so
+ */
+ if (Tmp_win->auto_raise) {
+ enter_win = Tmp_win;
+ if (enter_flag == FALSE) AutoRaiseWindow (Tmp_win);
+ } else if (enter_flag && raise_win == Tmp_win)
+ enter_win = Tmp_win;
+ /*
+ * set ring leader
+ */
+ if (Tmp_win->ring.next && (!enter_flag || raise_win == enter_win))
+ Scr->RingLeader = Tmp_win;
+ XSync (dpy, 0);
+ return;
+ } /* end if Tmp_win */
+ } /* end if !ActiveMenu */
+
+ /*
+ * Find the menu that we are dealing with now; punt if unknown
+ */
+ if (XFindContext (dpy, ewp->window, MenuContext, (caddr_t *)&mr) != XCSUCCESS) return;
+
+ mr->entered = TRUE;
+ if (ActiveMenu && mr == ActiveMenu->prev && RootFunction == 0) {
+ if (Scr->Shadow) XUnmapWindow (dpy, ActiveMenu->shadow);
+ XUnmapWindow (dpy, ActiveMenu->w);
+ ActiveMenu->mapped = UNMAPPED;
+ UninstallRootColormap ();
+ if (ActiveItem) {
+ ActiveItem->state = 0;
+ PaintEntry (ActiveMenu, ActiveItem, False);
+ }
+ ActiveItem = NULL;
+ ActiveMenu = mr;
+ MenuDepth--;
+ }
+ return;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HLNQueueScanner - LeaveNotify event q scanner
+ *
+ * Looks at the queued events and determines if any
+ * EnterNotify events are behind this event to allow
+ * skipping of unnecessary processing.
+ *
+ ***********************************************************************
+ */
+
+typedef struct HLNScanArgs {
+ Window w; /* The window getting the LeaveNotify */
+ Bool enters; /* Any EnterNotify event at all */
+ Bool matches; /* Any matching EnterNotify events */
+} HLNScanArgs;
+
+/* ARGSUSED*/
+static Bool
+HLNQueueScanner(dpy, ev, args)
+ Display *dpy;
+ XEvent *ev;
+ char *args;
+{
+ if (ev->type == EnterNotify && ev->xcrossing.mode != NotifyGrab) {
+ ((HLNScanArgs *) args)->enters = True;
+ if (ev->xcrossing.window == ((HLNScanArgs *) args)->w)
+ ((HLNScanArgs *) args)->matches = True;
+ }
+
+ return (False);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleLeaveNotify - LeaveNotify event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleLeaveNotify()
+{
+ HLNScanArgs scanArgs;
+ XEvent dummy;
+
+ if (Tmp_win != NULL)
+ {
+ Bool inicon;
+
+ /*
+ * We're not interested in pseudo Enter/Leave events generated
+ * from grab initiations and terminations.
+ */
+ if (Event.xcrossing.mode != NotifyNormal)
+ return;
+
+ inicon = (Tmp_win->list &&
+ Tmp_win->list->w == Event.xcrossing.window);
+
+ if (Scr->RingLeader && Scr->RingLeader == Tmp_win &&
+ (Event.xcrossing.detail != NotifyInferior &&
+ Event.xcrossing.window != Tmp_win->w)) {
+ if (!inicon) {
+ if (Tmp_win->mapped) {
+ Tmp_win->ring.cursor_valid = False;
+ } else {
+ Tmp_win->ring.cursor_valid = True;
+ Tmp_win->ring.curs_x = (Event.xcrossing.x_root -
+ Tmp_win->frame_x);
+ Tmp_win->ring.curs_y = (Event.xcrossing.y_root -
+ Tmp_win->frame_y);
+ }
+ }
+ Scr->RingLeader = (TwmWindow *) NULL;
+ }
+ if (Scr->FocusRoot) {
+
+ if (Event.xcrossing.detail != NotifyInferior) {
+
+ /*
+ * Scan for EnterNotify events to see if we can avoid some
+ * unnecessary processing.
+ */
+ scanArgs.w = Event.xcrossing.window;
+ scanArgs.enters = scanArgs.matches = False;
+ (void) XCheckIfEvent(dpy, &dummy, HLNQueueScanner,
+ (char *) &scanArgs);
+
+ if ((Event.xcrossing.window == Tmp_win->frame &&
+ !scanArgs.matches) || inicon) {
+ if (Tmp_win->list) NotActiveIconManager(Tmp_win->list);
+ if (Tmp_win->hilite_w)
+ XUnmapWindow (dpy, Tmp_win->hilite_w);
+ SetBorder (Tmp_win, False);
+ if (Scr->TitleFocus ||
+ Tmp_win->protocols & DoesWmTakeFocus)
+ SetFocus ((TwmWindow *) NULL, Event.xcrossing.time);
+ Scr->Focus = NULL;
+ } else if (Event.xcrossing.window == Tmp_win->w &&
+ !scanArgs.enters) {
+ InstallWindowColormaps (LeaveNotify, &Scr->TwmRoot);
+ }
+ }
+ }
+ XSync (dpy, 0);
+ return;
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleConfigureRequest - ConfigureRequest event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleConfigureRequest()
+{
+ XWindowChanges xwc;
+ unsigned long xwcm;
+ int x, y, width, height, bw;
+ int gravx, gravy;
+ XConfigureRequestEvent *cre = &Event.xconfigurerequest;
+
+#ifdef DEBUG_EVENTS
+ fprintf(stderr, "ConfigureRequest\n");
+ if (cre->value_mask & CWX)
+ fprintf(stderr, " x = %d\n", cre->x);
+ if (cre->value_mask & CWY)
+ fprintf(stderr, " y = %d\n", cre->y);
+ if (cre->value_mask & CWWidth)
+ fprintf(stderr, " width = %d\n", cre->width);
+ if (cre->value_mask & CWHeight)
+ fprintf(stderr, " height = %d\n", cre->height);
+ if (cre->value_mask & CWSibling)
+ fprintf(stderr, " above = 0x%x\n", cre->above);
+ if (cre->value_mask & CWStackMode)
+ fprintf(stderr, " stack = %d\n", cre->detail);
+#endif
+
+ /*
+ * Event.xany.window is Event.xconfigurerequest.parent, so Tmp_win will
+ * be wrong
+ */
+ Event.xany.window = cre->window; /* mash parent field */
+ if (XFindContext (dpy, cre->window, TwmContext, (caddr_t *) &Tmp_win) ==
+ XCNOENT)
+ Tmp_win = NULL;
+
+
+ /*
+ * According to the July 27, 1988 ICCCM draft, we should ignore size and
+ * position fields in the WM_NORMAL_HINTS property when we map a window.
+ * Instead, we'll read the current geometry. Therefore, we should respond
+ * to configuration requests for windows which have never been mapped.
+ */
+ if (!Tmp_win || Tmp_win->icon_w == cre->window) {
+ xwcm = cre->value_mask &
+ (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
+ xwc.x = cre->x;
+ xwc.y = cre->y;
+ xwc.width = cre->width;
+ xwc.height = cre->height;
+ xwc.border_width = cre->border_width;
+ XConfigureWindow(dpy, Event.xany.window, xwcm, &xwc);
+ return;
+ }
+
+ if ((cre->value_mask & CWStackMode) && Tmp_win->stackmode) {
+ TwmWindow *otherwin;
+
+ xwc.sibling = (((cre->value_mask & CWSibling) &&
+ (XFindContext (dpy, cre->above, TwmContext,
+ (caddr_t *) &otherwin) == XCSUCCESS))
+ ? otherwin->frame : cre->above);
+ xwc.stack_mode = cre->detail;
+ XConfigureWindow (dpy, Tmp_win->frame,
+ cre->value_mask & (CWSibling | CWStackMode), &xwc);
+ }
+
+
+ /* Don't modify frame_XXX fields before calling SetupWindow! */
+ x = Tmp_win->frame_x;
+ y = Tmp_win->frame_y;
+ width = Tmp_win->frame_width;
+ height = Tmp_win->frame_height;
+ bw = Tmp_win->frame_bw;
+
+ /*
+ * Section 4.1.5 of the ICCCM states that the (x,y) coordinates in the
+ * configure request are for the upper-left outer corner of the window.
+ * This means that we need to adjust for the additional title height as
+ * well as for any border width changes that we decide to allow. The
+ * current window gravity is to be used in computing the adjustments, just
+ * as when initially locating the window. Note that if we do decide to
+ * allow border width changes, we will need to send the synthetic
+ * ConfigureNotify event.
+ */
+ GetGravityOffsets (Tmp_win, &gravx, &gravy);
+
+ if (cre->value_mask & CWBorderWidth) {
+ int bwdelta = cre->border_width - Tmp_win->old_bw; /* posit growth */
+ if (bwdelta && Scr->ClientBorderWidth) { /* if change allowed */
+ x += gravx * bwdelta; /* change default values only */
+ y += gravy * bwdelta; /* ditto */
+ bw = cre->border_width;
+ if (Tmp_win->title_height) height += bwdelta;
+ x += (gravx < 0) ? bwdelta : -bwdelta;
+ y += (gravy < 0) ? bwdelta : -bwdelta;
+ }
+ Tmp_win->old_bw = cre->border_width; /* for restoring */
+ }
+
+ if (cre->value_mask & CWX) { /* override even if border change */
+ x = cre->x - bw;
+ }
+ if (cre->value_mask & CWY) {
+ y = cre->y - ((gravy < 0) ? 0 : Tmp_win->title_height) - bw;
+ }
+
+ if (cre->value_mask & CWWidth) {
+ width = cre->width;
+ }
+ if (cre->value_mask & CWHeight) {
+ height = cre->height + Tmp_win->title_height;
+ }
+
+ if (width != Tmp_win->frame_width || height != Tmp_win->frame_height)
+ Tmp_win->zoomed = ZOOM_NONE;
+
+ /*
+ * SetupWindow (x,y) are the location of the upper-left outer corner and
+ * are passed directly to XMoveResizeWindow (frame). The (width,height)
+ * are the inner size of the frame. The inner width is the same as the
+ * requested client window width; the inner height is the same as the
+ * requested client window height plus any title bar slop.
+ */
+ SetupWindow (Tmp_win, x, y, width, height, bw);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleShapeNotify - shape notification event handler
+ *
+ ***********************************************************************
+ */
+void
+HandleShapeNotify ()
+{
+ XShapeEvent *sev = (XShapeEvent *) &Event;
+
+ if (Tmp_win == NULL)
+ return;
+ if (sev->kind != ShapeBounding)
+ return;
+ if (!Tmp_win->wShaped && sev->shaped) {
+ XShapeCombineMask (dpy, Tmp_win->frame, ShapeClip, 0, 0, None,
+ ShapeSet);
+ }
+ Tmp_win->wShaped = sev->shaped;
+ SetFrameShape (Tmp_win);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleUnknown - unknown event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleUnknown()
+{
+#ifdef DEBUG_EVENTS
+ fprintf(stderr, "type = %d\n", Event.type);
+#endif
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * Transient - checks to see if the window is a transient
+ *
+ * Returned Value:
+ * TRUE - window is a transient
+ * FALSE - window is not a transient
+ *
+ * Inputs:
+ * w - the window to check
+ *
+ ***********************************************************************
+ */
+
+int
+Transient(w, propw)
+ Window w, *propw;
+{
+ return (XGetTransientForHint(dpy, w, propw));
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * FindScreenInfo - get ScreenInfo struct associated with a given window
+ *
+ * Returned Value:
+ * ScreenInfo struct
+ *
+ * Inputs:
+ * w - the window
+ *
+ ***********************************************************************
+ */
+
+ScreenInfo *
+FindScreenInfo(w)
+ Window w;
+{
+ XWindowAttributes attr;
+ int scrnum;
+
+ attr.screen = NULL;
+ if (XGetWindowAttributes(dpy, w, &attr)) {
+ for (scrnum = 0; scrnum < NumScreens; scrnum++) {
+ if (ScreenList[scrnum] != NULL &&
+ (ScreenOfDisplay(dpy, ScreenList[scrnum]->screen) ==
+ attr.screen))
+ return ScreenList[scrnum];
+ }
+ }
+
+ return NULL;
+}
+
+
+
+static void flush_expose (w)
+ Window w;
+{
+ XEvent dummy;
+
+ /* SUPPRESS 530 */
+ while (XCheckTypedWindowEvent (dpy, w, Expose, &dummy)) ;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * InstallWindowColormaps - install the colormaps for one twm window
+ *
+ * Inputs:
+ * type - type of event that caused the installation
+ * tmp - for a subset of event types, the address of the
+ * window structure, whose colormaps are to be installed.
+ *
+ ***********************************************************************
+ */
+
+InstallWindowColormaps (type, tmp)
+ int type;
+ TwmWindow *tmp;
+{
+ int i, j, n, number_cwins, state;
+ ColormapWindow **cwins, *cwin, **maxcwin = NULL;
+ TwmColormap *cmap;
+ char *row, *scoreboard;
+
+ switch (type) {
+ case EnterNotify:
+ case LeaveNotify:
+ case DestroyNotify:
+ default:
+ /* Save the colormap to be loaded for when force loading of
+ * root colormap(s) ends.
+ */
+ Scr->cmapInfo.pushed_window = tmp;
+ /* Don't load any new colormap if root colormap(s) has been
+ * force loaded.
+ */
+ if (Scr->cmapInfo.root_pushes)
+ return;
+ /* Don't reload the currend window colormap list.
+ */
+ if (Scr->cmapInfo.cmaps == &tmp->cmaps)
+ return;
+ if (Scr->cmapInfo.cmaps)
+ for (i = Scr->cmapInfo.cmaps->number_cwins,
+ cwins = Scr->cmapInfo.cmaps->cwins; i-- > 0; cwins++)
+ (*cwins)->colormap->state &= ~CM_INSTALLABLE;
+ Scr->cmapInfo.cmaps = &tmp->cmaps;
+ break;
+
+ case PropertyNotify:
+ case VisibilityNotify:
+ case ColormapNotify:
+ break;
+ }
+
+ number_cwins = Scr->cmapInfo.cmaps->number_cwins;
+ cwins = Scr->cmapInfo.cmaps->cwins;
+ scoreboard = Scr->cmapInfo.cmaps->scoreboard;
+
+ ColortableThrashing = FALSE; /* in case installation aborted */
+
+ state = CM_INSTALLED;
+
+ for (i = n = 0; i < number_cwins; i++) {
+ cwin = cwins[i];
+ cmap = cwin->colormap;
+ cmap->state |= CM_INSTALLABLE;
+ cmap->state &= ~CM_INSTALL;
+ cmap->w = cwin->w;
+ }
+ for (i = n = 0; i < number_cwins; i++) {
+ cwin = cwins[i];
+ cmap = cwin->colormap;
+ if (cwin->visibility != VisibilityFullyObscured &&
+ n < Scr->cmapInfo.maxCmaps) {
+ row = scoreboard + (i*(i-1)/2);
+ for (j = 0; j < i; j++)
+ if (row[j] && (cwins[j]->colormap->state & CM_INSTALL))
+ break;
+ if (j != i)
+ continue;
+ n++;
+ maxcwin = &cwins[i];
+ state &= (cmap->state & CM_INSTALLED);
+ cmap->state |= CM_INSTALL;
+ }
+ }
+
+ Scr->cmapInfo.first_req = NextRequest(dpy);
+
+ for ( ; n > 0 && maxcwin >= cwins; maxcwin--) {
+ cmap = (*maxcwin)->colormap;
+ if (cmap->state & CM_INSTALL) {
+ cmap->state &= ~CM_INSTALL;
+ if (!(state & CM_INSTALLED)) {
+ cmap->install_req = NextRequest(dpy);
+ XInstallColormap(dpy, cmap->c);
+ }
+ cmap->state |= CM_INSTALLED;
+ n--;
+ }
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedures:
+ * <Uni/I>nstallRootColormap - Force (un)loads root colormap(s)
+ *
+ * These matching routines provide a mechanism to insure that
+ * the root colormap(s) is installed during operations like
+ * rubber banding or menu display that require colors from
+ * that colormap. Calls may be nested arbitrarily deeply,
+ * as long as there is one UninstallRootColormap call per
+ * InstallRootColormap call.
+ *
+ * The final UninstallRootColormap will cause the colormap list
+ * which would otherwise have be loaded to be loaded, unless
+ * Enter or Leave Notify events are queued, indicating some
+ * other colormap list would potentially be loaded anyway.
+ ***********************************************************************
+ */
+
+InstallRootColormap()
+{
+ TwmWindow *tmp;
+ if (Scr->cmapInfo.root_pushes == 0) {
+ /*
+ * The saving and restoring of cmapInfo.pushed_window here
+ * is a slimy way to remember the actual pushed list and
+ * not that of the root window.
+ */
+ tmp = Scr->cmapInfo.pushed_window;
+ InstallWindowColormaps(0, &Scr->TwmRoot);
+ Scr->cmapInfo.pushed_window = tmp;
+ }
+ Scr->cmapInfo.root_pushes++;
+}
+
+
+
+/* ARGSUSED*/
+static Bool
+UninstallRootColormapQScanner(dpy, ev, args)
+ Display *dpy;
+ XEvent *ev;
+ char *args;
+{
+ if (!*args)
+ if (ev->type == EnterNotify) {
+ if (ev->xcrossing.mode != NotifyGrab)
+ *args = 1;
+ } else if (ev->type == LeaveNotify) {
+ if (ev->xcrossing.mode == NotifyNormal)
+ *args = 1;
+ }
+
+ return (False);
+}
+
+
+
+UninstallRootColormap()
+{
+ char args;
+ XEvent dummy;
+
+ if (Scr->cmapInfo.root_pushes)
+ Scr->cmapInfo.root_pushes--;
+
+ if (!Scr->cmapInfo.root_pushes) {
+ /*
+ * If we have subsequent Enter or Leave Notify events,
+ * we can skip the reload of pushed colormaps.
+ */
+ XSync (dpy, 0);
+ args = 0;
+ (void) XCheckIfEvent(dpy, &dummy, UninstallRootColormapQScanner, &args);
+
+ if (!args)
+ InstallWindowColormaps(0, Scr->cmapInfo.pushed_window);
+ }
+}
+
+#ifdef TRACE
+dumpevent (e)
+ XEvent *e;
+{
+ char *name = NULL;
+
+ switch (e->type) {
+ case KeyPress: name = "KeyPress"; break;
+ case KeyRelease: name = "KeyRelease"; break;
+ case ButtonPress: name = "ButtonPress"; break;
+ case ButtonRelease: name = "ButtonRelease"; break;
+ case MotionNotify: name = "MotionNotify"; break;
+ case EnterNotify: name = "EnterNotify"; break;
+ case LeaveNotify: name = "LeaveNotify"; break;
+ case FocusIn: name = "FocusIn"; break;
+ case FocusOut: name = "FocusOut"; break;
+ case KeymapNotify: name = "KeymapNotify"; break;
+ case Expose: name = "Expose"; break;
+ case GraphicsExpose: name = "GraphicsExpose"; break;
+ case NoExpose: name = "NoExpose"; break;
+ case VisibilityNotify: name = "VisibilityNotify"; break;
+ case CreateNotify: name = "CreateNotify"; break;
+ case DestroyNotify: name = "DestroyNotify"; break;
+ case UnmapNotify: name = "UnmapNotify"; break;
+ case MapNotify: name = "MapNotify"; break;
+ case MapRequest: name = "MapRequest"; break;
+ case ReparentNotify: name = "ReparentNotify"; break;
+ case ConfigureNotify: name = "ConfigureNotify"; break;
+ case ConfigureRequest: name = "ConfigureRequest"; break;
+ case GravityNotify: name = "GravityNotify"; break;
+ case ResizeRequest: name = "ResizeRequest"; break;
+ case CirculateNotify: name = "CirculateNotify"; break;
+ case CirculateRequest: name = "CirculateRequest"; break;
+ case PropertyNotify: name = "PropertyNotify"; break;
+ case SelectionClear: name = "SelectionClear"; break;
+ case SelectionRequest: name = "SelectionRequest"; break;
+ case SelectionNotify: name = "SelectionNotify"; break;
+ case ColormapNotify: name = "ColormapNotify"; break;
+ case ClientMessage: name = "ClientMessage"; break;
+ case MappingNotify: name = "MappingNotify"; break;
+ }
+
+ if (name) {
+ printf ("event: %s, %d remaining\n", name, QLength(dpy));
+ } else {
+ printf ("unknown event %d, %d remaining\n", e->type, QLength(dpy));
+ }
+}
+#endif /* TRACE */
+
diff --git a/src/events.h b/src/events.h
new file mode 100644
index 0000000..adb15b5
--- /dev/null
+++ b/src/events.h
@@ -0,0 +1,111 @@
+/*****************************************************************************/
+/*
+
+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: events.h,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * twm event handler include file
+ *
+ * 17-Nov-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#ifndef _EVENTS_
+#define _EVENTS_
+
+typedef void (*event_proc)();
+
+extern void InitEvents();
+extern Bool StashEventTime();
+extern Time lastTimestamp;
+extern void SimulateMapRequest();
+extern void AutoRaiseWindow();
+#define LastTimestamp() lastTimestamp
+extern Bool DispatchEvent();
+extern Bool DispatchEvent2();
+extern void HandleEvents();
+extern void HandleExpose();
+extern void HandleDestroyNotify();
+extern void HandleMapRequest();
+extern void HandleMapNotify();
+extern void HandleUnmapNotify();
+extern void HandleMotionNotify();
+extern void HandleButtonRelease();
+extern void HandleButtonPress();
+extern void HandleEnterNotify();
+extern void HandleLeaveNotify();
+extern void HandleConfigureRequest();
+extern void HandleClientMessage();
+extern void HandlePropertyNotify();
+extern void HandleKeyPress();
+extern void HandleColormapNotify();
+extern void HandleVisibilityNotify();
+extern void HandleUnknown();
+
+extern event_proc EventHandler[];
+extern Window DragWindow;
+extern int origDragX;
+extern int origDragY;
+extern int DragX;
+extern int DragY;
+extern int DragWidth;
+extern int DragHeight;
+extern int CurrentDragX;
+extern int CurrentDragY;
+
+extern int ButtonPressed;
+extern int Cancel;
+
+extern XEvent Event;
+
+#endif /* _EVENTS_ */
diff --git a/src/gc.c b/src/gc.c
new file mode 100644
index 0000000..2cdf838
--- /dev/null
+++ b/src/gc.c
@@ -0,0 +1,117 @@
+/*****************************************************************************/
+/*
+
+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: gc.c,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * Open the fonts and create the GCs
+ *
+ * 31-Mar-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include "util.h"
+#include "screen.h"
+
+/***********************************************************************
+ *
+ * Procedure:
+ * CreateGCs - open fonts and create all the needed GC's. I only
+ * want to do this once, hence the first_time flag.
+ *
+ ***********************************************************************
+ */
+
+void
+CreateGCs()
+{
+ static ScreenInfo *prevScr = NULL;
+ XGCValues gcv;
+ unsigned long gcm;
+
+ if (!Scr->FirstTime || prevScr == Scr)
+ return;
+
+ prevScr = Scr;
+
+ /* create GC's */
+
+ gcm = 0;
+ gcm |= GCFunction; gcv.function = GXxor;
+ gcm |= GCLineWidth; gcv.line_width = 0;
+ gcm |= GCForeground; gcv.foreground = Scr->XORvalue;
+ gcm |= GCSubwindowMode; gcv.subwindow_mode = IncludeInferiors;
+
+ Scr->DrawGC = XCreateGC(dpy, Scr->Root, gcm, &gcv);
+
+ gcm = 0;
+ gcm |= GCForeground; gcv.foreground = Scr->MenuC.fore;
+ gcm |= GCBackground; gcv.background = Scr->MenuC.back;
+ gcm |= GCFont; gcv.font = Scr->MenuFont.font->fid;
+
+ Scr->MenuGC = XCreateGC(dpy, Scr->Root, gcm, &gcv);
+
+ gcm = 0;
+ gcm |= GCPlaneMask; gcv.plane_mask = AllPlanes;
+ /*
+ * Prevent GraphicsExpose and NoExpose events. We'd only get NoExpose
+ * events anyway; they cause BadWindow errors from XGetWindowAttributes
+ * call in FindScreenInfo (events.c) (since drawable is a pixmap).
+ */
+ gcm |= GCGraphicsExposures; gcv.graphics_exposures = False;
+ gcm |= GCLineWidth; gcv.line_width = 0;
+
+ Scr->NormalGC = XCreateGC(dpy, Scr->Root, gcm, &gcv);
+}
diff --git a/src/gc.h b/src/gc.h
new file mode 100644
index 0000000..f8440ed
--- /dev/null
+++ b/src/gc.h
@@ -0,0 +1,68 @@
+/*****************************************************************************/
+/*
+
+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: gc.h,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * GC related externs
+ *
+ * 8-Apr-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#ifndef _GC_
+#define _GC_
+
+extern void CreateGCs();
+
+#endif /* _GC_ */
diff --git a/src/gram.y b/src/gram.y
new file mode 100644
index 0000000..8530b09
--- /dev/null
+++ b/src/gram.y
@@ -0,0 +1,883 @@
+/*****************************************************************************/
+/*
+
+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: gram.y,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * .twmrc command grammer
+ *
+ * 07-Jan-86 Thomas E. LaStrange File created
+ * 11-Nov-90 Dave Sternlicht Adding SaveColors
+ * 10-Oct-90 David M. Sternlicht Storing saved colors on root
+ *
+ ***********************************************************************/
+
+%{
+#include <stdio.h>
+#include <ctype.h>
+#include "twm.h"
+#include "menus.h"
+#include "list.h"
+#include "util.h"
+#include "screen.h"
+#include "parse.h"
+#include <X11/Xos.h>
+#include <X11/Xmu/CharSet.h>
+
+static char *Action = "";
+static char *Name = "";
+static MenuRoot *root, *pull = NULL;
+
+static MenuRoot *GetRoot();
+
+static Bool CheckWarpScreenArg(), CheckWarpRingArg();
+static Bool CheckColormapArg();
+static void GotButton(), GotKey(), GotTitleButton();
+static char *ptr;
+static name_list **list;
+static int cont = 0;
+static int color;
+int mods = 0;
+unsigned int mods_used = (ShiftMask | ControlMask | Mod1Mask);
+
+extern int do_single_keyword(), do_string_keyword(), do_number_keyword();
+extern name_list **do_colorlist_keyword();
+extern int do_color_keyword(), do_string_savecolor();
+extern int yylineno;
+%}
+
+%union
+{
+ int num;
+ char *ptr;
+};
+
+%token <num> LB RB LP RP MENUS MENU BUTTON DEFAULT_FUNCTION PLUS MINUS
+%token <num> ALL OR CURSORS PIXMAPS ICONS COLOR SAVECOLOR MONOCHROME FUNCTION
+%token <num> ICONMGR_SHOW ICONMGR WINDOW_FUNCTION ZOOM ICONMGRS
+%token <num> ICONMGR_GEOMETRY ICONMGR_NOSHOW MAKE_TITLE GRAYSCALE
+%token <num> ICONIFY_BY_UNMAPPING DONT_ICONIFY_BY_UNMAPPING
+%token <num> NO_TITLE AUTO_RAISE NO_HILITE ICON_REGION
+%token <num> META SHIFT LOCK CONTROL WINDOW TITLE ICON ROOT FRAME
+%token <num> COLON EQUALS SQUEEZE_TITLE DONT_SQUEEZE_TITLE
+%token <num> START_ICONIFIED NO_TITLE_HILITE TITLE_HILITE
+%token <num> MOVE RESIZE WAIT SELECT KILL LEFT_TITLEBUTTON RIGHT_TITLEBUTTON
+%token <num> NUMBER KEYWORD NKEYWORD CKEYWORD CLKEYWORD FKEYWORD FSKEYWORD
+%token <num> SKEYWORD DKEYWORD JKEYWORD WINDOW_RING WARP_CURSOR ERRORTOKEN
+%token <num> NO_STACKMODE
+%token <ptr> STRING
+
+%type <ptr> string
+%type <num> pixmap_list cursor_list color_list save_color_list stmt
+%type <num> win_color_list iconm_list win_list icon_list function menu
+%type <num> noarg sarg error narg squeeze
+%type <num> action button number signed_number full fullkey
+
+%start twmrc
+
+%%
+twmrc : stmts
+ ;
+
+stmts : /* Empty */
+ | stmts stmt
+ ;
+
+stmt : error
+ | noarg
+ | sarg
+ | narg
+ | squeeze
+ | ICON_REGION string DKEYWORD DKEYWORD number number
+ { AddIconRegion($2, $3, $4, $5, $6); }
+ | ICONMGR_GEOMETRY string number { if (Scr->FirstTime)
+ {
+ Scr->iconmgr.geometry=$2;
+ Scr->iconmgr.columns=$3;
+ }
+ }
+ | ICONMGR_GEOMETRY string { if (Scr->FirstTime)
+ Scr->iconmgr.geometry = $2;
+ }
+ | ZOOM number { if (Scr->FirstTime)
+ {
+ Scr->DoZoom = TRUE;
+ Scr->ZoomCount = $2;
+ }
+ }
+ | ZOOM { if (Scr->FirstTime)
+ Scr->DoZoom = TRUE; }
+ | PIXMAPS pixmap_list {}
+ | CURSORS cursor_list {}
+ | ICONIFY_BY_UNMAPPING { list = &Scr->IconifyByUn; }
+ win_list
+ | ICONIFY_BY_UNMAPPING { if (Scr->FirstTime)
+ Scr->IconifyByUnmapping = TRUE; }
+ | LEFT_TITLEBUTTON string EQUALS action {
+ GotTitleButton ($2, $4, False);
+ }
+ | RIGHT_TITLEBUTTON string EQUALS action {
+ GotTitleButton ($2, $4, True);
+ }
+ | button string { root = GetRoot($2, NULLSTR, NULLSTR);
+ Scr->Mouse[$1][C_ROOT][0].func = F_MENU;
+ Scr->Mouse[$1][C_ROOT][0].menu = root;
+ }
+ | button action { Scr->Mouse[$1][C_ROOT][0].func = $2;
+ if ($2 == F_MENU)
+ {
+ pull->prev = NULL;
+ Scr->Mouse[$1][C_ROOT][0].menu = pull;
+ }
+ else
+ {
+ root = GetRoot(TWM_ROOT,NULLSTR,NULLSTR);
+ Scr->Mouse[$1][C_ROOT][0].item =
+ AddToMenu(root,"x",Action,
+ NULLSTR,$2,NULLSTR,NULLSTR);
+ }
+ Action = "";
+ pull = NULL;
+ }
+ | string fullkey { GotKey($1, $2); }
+ | button full { GotButton($1, $2); }
+ | DONT_ICONIFY_BY_UNMAPPING { list = &Scr->DontIconify; }
+ win_list
+ | ICONMGR_NOSHOW { list = &Scr->IconMgrNoShow; }
+ win_list
+ | ICONMGR_NOSHOW { Scr->IconManagerDontShow = TRUE; }
+ | ICONMGRS { list = &Scr->IconMgrs; }
+ iconm_list
+ | ICONMGR_SHOW { list = &Scr->IconMgrShow; }
+ win_list
+ | NO_TITLE_HILITE { list = &Scr->NoTitleHighlight; }
+ win_list
+ | NO_TITLE_HILITE { if (Scr->FirstTime)
+ Scr->TitleHighlight = FALSE; }
+ | NO_HILITE { list = &Scr->NoHighlight; }
+ win_list
+ | NO_HILITE { if (Scr->FirstTime)
+ Scr->Highlight = FALSE; }
+ | NO_STACKMODE { list = &Scr->NoStackModeL; }
+ win_list
+ | NO_STACKMODE { if (Scr->FirstTime)
+ Scr->StackMode = FALSE; }
+ | NO_TITLE { list = &Scr->NoTitle; }
+ win_list
+ | NO_TITLE { if (Scr->FirstTime)
+ Scr->NoTitlebar = TRUE; }
+ | MAKE_TITLE { list = &Scr->MakeTitle; }
+ win_list
+ | START_ICONIFIED { list = &Scr->StartIconified; }
+ win_list
+ | AUTO_RAISE { list = &Scr->AutoRaise; }
+ win_list
+ | MENU string LP string COLON string RP {
+ root = GetRoot($2, $4, $6); }
+ menu { root->real_menu = TRUE;}
+ | MENU string { root = GetRoot($2, NULLSTR, NULLSTR); }
+ menu { root->real_menu = TRUE; }
+ | FUNCTION string { root = GetRoot($2, NULLSTR, NULLSTR); }
+ function
+ | ICONS { list = &Scr->IconNames; }
+ icon_list
+ | COLOR { color = COLOR; }
+ color_list
+ | GRAYSCALE { color = GRAYSCALE; }
+ color_list
+ | SAVECOLOR
+ save_color_list
+ | MONOCHROME { color = MONOCHROME; }
+ color_list
+ | DEFAULT_FUNCTION action { Scr->DefaultFunction.func = $2;
+ if ($2 == F_MENU)
+ {
+ pull->prev = NULL;
+ Scr->DefaultFunction.menu = pull;
+ }
+ else
+ {
+ root = GetRoot(TWM_ROOT,NULLSTR,NULLSTR);
+ Scr->DefaultFunction.item =
+ AddToMenu(root,"x",Action,
+ NULLSTR,$2, NULLSTR, NULLSTR);
+ }
+ Action = "";
+ pull = NULL;
+ }
+ | WINDOW_FUNCTION action { Scr->WindowFunction.func = $2;
+ root = GetRoot(TWM_ROOT,NULLSTR,NULLSTR);
+ Scr->WindowFunction.item =
+ AddToMenu(root,"x",Action,
+ NULLSTR,$2, NULLSTR, NULLSTR);
+ Action = "";
+ pull = NULL;
+ }
+ | WARP_CURSOR { list = &Scr->WarpCursorL; }
+ win_list
+ | WARP_CURSOR { if (Scr->FirstTime)
+ Scr->WarpCursor = TRUE; }
+ | WINDOW_RING { list = &Scr->WindowRingL; }
+ win_list
+ ;
+
+
+noarg : KEYWORD { if (!do_single_keyword ($1)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "unknown singleton keyword %d\n",
+ $1);
+ ParseError = 1;
+ }
+ }
+ ;
+
+sarg : SKEYWORD string { if (!do_string_keyword ($1, $2)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "unknown string keyword %d (value \"%s\")\n",
+ $1, $2);
+ ParseError = 1;
+ }
+ }
+ ;
+
+narg : NKEYWORD number { if (!do_number_keyword ($1, $2)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "unknown numeric keyword %d (value %d)\n",
+ $1, $2);
+ ParseError = 1;
+ }
+ }
+ ;
+
+
+
+full : EQUALS keys COLON contexts COLON action { $$ = $6; }
+ ;
+
+fullkey : EQUALS keys COLON contextkeys COLON action { $$ = $6; }
+ ;
+
+keys : /* Empty */
+ | keys key
+ ;
+
+key : META { mods |= Mod1Mask; }
+ | SHIFT { mods |= ShiftMask; }
+ | LOCK { mods |= LockMask; }
+ | CONTROL { mods |= ControlMask; }
+ | META number { if ($2 < 1 || $2 > 5) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "bad modifier number (%d), must be 1-5\n",
+ $2);
+ ParseError = 1;
+ } else {
+ mods |= (Mod1Mask << ($2 - 1));
+ }
+ }
+ | OR { }
+ ;
+
+contexts : /* Empty */
+ | contexts context
+ ;
+
+context : WINDOW { cont |= C_WINDOW_BIT; }
+ | TITLE { cont |= C_TITLE_BIT; }
+ | ICON { cont |= C_ICON_BIT; }
+ | ROOT { cont |= C_ROOT_BIT; }
+ | FRAME { cont |= C_FRAME_BIT; }
+ | ICONMGR { cont |= C_ICONMGR_BIT; }
+ | META { cont |= C_ICONMGR_BIT; }
+ | ALL { cont |= C_ALL_BITS; }
+ | OR { }
+ ;
+
+contextkeys : /* Empty */
+ | contextkeys contextkey
+ ;
+
+contextkey : WINDOW { cont |= C_WINDOW_BIT; }
+ | TITLE { cont |= C_TITLE_BIT; }
+ | ICON { cont |= C_ICON_BIT; }
+ | ROOT { cont |= C_ROOT_BIT; }
+ | FRAME { cont |= C_FRAME_BIT; }
+ | ICONMGR { cont |= C_ICONMGR_BIT; }
+ | META { cont |= C_ICONMGR_BIT; }
+ | ALL { cont |= C_ALL_BITS; }
+ | OR { }
+ | string { Name = $1; cont |= C_NAME_BIT; }
+ ;
+
+
+pixmap_list : LB pixmap_entries RB
+ ;
+
+pixmap_entries : /* Empty */
+ | pixmap_entries pixmap_entry
+ ;
+
+pixmap_entry : TITLE_HILITE string { SetHighlightPixmap ($2); }
+ ;
+
+
+cursor_list : LB cursor_entries RB
+ ;
+
+cursor_entries : /* Empty */
+ | cursor_entries cursor_entry
+ ;
+
+cursor_entry : FRAME string string {
+ NewBitmapCursor(&Scr->FrameCursor, $2, $3); }
+ | FRAME string {
+ NewFontCursor(&Scr->FrameCursor, $2); }
+ | TITLE string string {
+ NewBitmapCursor(&Scr->TitleCursor, $2, $3); }
+ | TITLE string {
+ NewFontCursor(&Scr->TitleCursor, $2); }
+ | ICON string string {
+ NewBitmapCursor(&Scr->IconCursor, $2, $3); }
+ | ICON string {
+ NewFontCursor(&Scr->IconCursor, $2); }
+ | ICONMGR string string {
+ NewBitmapCursor(&Scr->IconMgrCursor, $2, $3); }
+ | ICONMGR string {
+ NewFontCursor(&Scr->IconMgrCursor, $2); }
+ | BUTTON string string {
+ NewBitmapCursor(&Scr->ButtonCursor, $2, $3); }
+ | BUTTON string {
+ NewFontCursor(&Scr->ButtonCursor, $2); }
+ | MOVE string string {
+ NewBitmapCursor(&Scr->MoveCursor, $2, $3); }
+ | MOVE string {
+ NewFontCursor(&Scr->MoveCursor, $2); }
+ | RESIZE string string {
+ NewBitmapCursor(&Scr->ResizeCursor, $2, $3); }
+ | RESIZE string {
+ NewFontCursor(&Scr->ResizeCursor, $2); }
+ | WAIT string string {
+ NewBitmapCursor(&Scr->WaitCursor, $2, $3); }
+ | WAIT string {
+ NewFontCursor(&Scr->WaitCursor, $2); }
+ | MENU string string {
+ NewBitmapCursor(&Scr->MenuCursor, $2, $3); }
+ | MENU string {
+ NewFontCursor(&Scr->MenuCursor, $2); }
+ | SELECT string string {
+ NewBitmapCursor(&Scr->SelectCursor, $2, $3); }
+ | SELECT string {
+ NewFontCursor(&Scr->SelectCursor, $2); }
+ | KILL string string {
+ NewBitmapCursor(&Scr->DestroyCursor, $2, $3); }
+ | KILL string {
+ NewFontCursor(&Scr->DestroyCursor, $2); }
+ ;
+
+color_list : LB color_entries RB
+ ;
+
+
+color_entries : /* Empty */
+ | color_entries color_entry
+ ;
+
+color_entry : CLKEYWORD string { if (!do_colorlist_keyword ($1, color,
+ $2)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "unhandled list color keyword %d (string \"%s\")\n",
+ $1, $2);
+ ParseError = 1;
+ }
+ }
+ | CLKEYWORD string { list = do_colorlist_keyword($1,color,
+ $2);
+ if (!list) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "unhandled color list keyword %d (string \"%s\")\n",
+ $1, $2);
+ ParseError = 1;
+ }
+ }
+ win_color_list
+ | CKEYWORD string { if (!do_color_keyword ($1, color,
+ $2)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "unhandled color keyword %d (string \"%s\")\n",
+ $1, $2);
+ ParseError = 1;
+ }
+ }
+ ;
+
+save_color_list : LB s_color_entries RB
+ ;
+
+s_color_entries : /* Empty */
+ | s_color_entries s_color_entry
+ ;
+
+s_color_entry : string { do_string_savecolor(color, $1); }
+ | CLKEYWORD { do_var_savecolor($1); }
+ ;
+
+win_color_list : LB win_color_entries RB
+ ;
+
+win_color_entries : /* Empty */
+ | win_color_entries win_color_entry
+ ;
+
+win_color_entry : string string { if (Scr->FirstTime &&
+ color == Scr->Monochrome)
+ AddToList(list, $1, $2); }
+ ;
+
+squeeze : SQUEEZE_TITLE {
+ if (HasShape) Scr->SqueezeTitle = TRUE;
+ }
+ | SQUEEZE_TITLE { list = &Scr->SqueezeTitleL;
+ if (HasShape && Scr->SqueezeTitle == -1)
+ Scr->SqueezeTitle = TRUE;
+ }
+ LB win_sqz_entries RB
+ | DONT_SQUEEZE_TITLE { Scr->SqueezeTitle = FALSE; }
+ | DONT_SQUEEZE_TITLE { list = &Scr->DontSqueezeTitleL; }
+ win_list
+ ;
+
+win_sqz_entries : /* Empty */
+ | win_sqz_entries string JKEYWORD signed_number number {
+ if (Scr->FirstTime) {
+ do_squeeze_entry (list, $2, $3, $4, $5);
+ }
+ }
+ ;
+
+
+iconm_list : LB iconm_entries RB
+ ;
+
+iconm_entries : /* Empty */
+ | iconm_entries iconm_entry
+ ;
+
+iconm_entry : string string number { if (Scr->FirstTime)
+ AddToList(list, $1, (char *)
+ AllocateIconManager($1, NULLSTR,
+ $2,$3));
+ }
+ | string string string number
+ { if (Scr->FirstTime)
+ AddToList(list, $1, (char *)
+ AllocateIconManager($1,$2,
+ $3, $4));
+ }
+ ;
+
+win_list : LB win_entries RB
+ ;
+
+win_entries : /* Empty */
+ | win_entries win_entry
+ ;
+
+win_entry : string { if (Scr->FirstTime)
+ AddToList(list, $1, 0);
+ }
+ ;
+
+icon_list : LB icon_entries RB
+ ;
+
+icon_entries : /* Empty */
+ | icon_entries icon_entry
+ ;
+
+icon_entry : string string { if (Scr->FirstTime) AddToList(list, $1, $2); }
+ ;
+
+function : LB function_entries RB
+ ;
+
+function_entries: /* Empty */
+ | function_entries function_entry
+ ;
+
+function_entry : action { AddToMenu(root, "", Action, NULLSTR, $1,
+ NULLSTR, NULLSTR);
+ Action = "";
+ }
+ ;
+
+menu : LB menu_entries RB
+ ;
+
+menu_entries : /* Empty */
+ | menu_entries menu_entry
+ ;
+
+menu_entry : string action { AddToMenu(root, $1, Action, pull, $2,
+ NULLSTR, NULLSTR);
+ Action = "";
+ pull = NULL;
+ }
+ | string LP string COLON string RP action {
+ AddToMenu(root, $1, Action, pull, $7,
+ $3, $5);
+ Action = "";
+ pull = NULL;
+ }
+ ;
+
+action : FKEYWORD { $$ = $1; }
+ | FSKEYWORD string {
+ $$ = $1;
+ Action = $2;
+ switch ($1) {
+ case F_MENU:
+ pull = GetRoot ($2, NULLSTR,NULLSTR);
+ pull->prev = root;
+ break;
+ case F_WARPRING:
+ if (!CheckWarpRingArg (Action)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "ignoring invalid f.warptoring argument \"%s\"\n",
+ Action);
+ $$ = F_NOP;
+ }
+ case F_WARPTOSCREEN:
+ if (!CheckWarpScreenArg (Action)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "ignoring invalid f.warptoscreen argument \"%s\"\n",
+ Action);
+ $$ = F_NOP;
+ }
+ break;
+ case F_COLORMAP:
+ if (CheckColormapArg (Action)) {
+ $$ = F_COLORMAP;
+ } else {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "ignoring invalid f.colormap argument \"%s\"\n",
+ Action);
+ $$ = F_NOP;
+ }
+ break;
+ } /* end switch */
+ }
+ ;
+
+
+signed_number : number { $$ = $1; }
+ | PLUS number { $$ = $2; }
+ | MINUS number { $$ = -($2); }
+ ;
+
+button : BUTTON number { $$ = $2;
+ if ($2 == 0)
+ yyerror("bad button 0");
+
+ if ($2 > MAX_BUTTONS)
+ {
+ $$ = 0;
+ yyerror("button number too large");
+ }
+ }
+ ;
+
+string : STRING { ptr = (char *)malloc(strlen($1)+1);
+ strcpy(ptr, $1);
+ RemoveDQuote(ptr);
+ $$ = ptr;
+ }
+number : NUMBER { $$ = $1; }
+ ;
+
+%%
+yyerror(s) char *s;
+{
+ twmrc_error_prefix();
+ fprintf (stderr, "error in input file: %s\n", s ? s : "");
+ ParseError = 1;
+}
+RemoveDQuote(str)
+char *str;
+{
+ register char *i, *o;
+ register n;
+ register count;
+
+ for (i=str+1, o=str; *i && *i != '\"'; o++)
+ {
+ if (*i == '\\')
+ {
+ switch (*++i)
+ {
+ case 'n':
+ *o = '\n';
+ i++;
+ break;
+ case 'b':
+ *o = '\b';
+ i++;
+ break;
+ case 'r':
+ *o = '\r';
+ i++;
+ break;
+ case 't':
+ *o = '\t';
+ i++;
+ break;
+ case 'f':
+ *o = '\f';
+ i++;
+ break;
+ case '0':
+ if (*++i == 'x')
+ goto hex;
+ else
+ --i;
+ case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ n = 0;
+ count = 0;
+ while (*i >= '0' && *i <= '7' && count < 3)
+ {
+ n = (n<<3) + (*i++ - '0');
+ count++;
+ }
+ *o = n;
+ break;
+ hex:
+ case 'x':
+ n = 0;
+ count = 0;
+ while (i++, count++ < 2)
+ {
+ if (*i >= '0' && *i <= '9')
+ n = (n<<4) + (*i - '0');
+ else if (*i >= 'a' && *i <= 'f')
+ n = (n<<4) + (*i - 'a') + 10;
+ else if (*i >= 'A' && *i <= 'F')
+ n = (n<<4) + (*i - 'A') + 10;
+ else
+ break;
+ }
+ *o = n;
+ break;
+ case '\n':
+ i++; /* punt */
+ o--; /* to account for o++ at end of loop */
+ break;
+ case '\"':
+ case '\'':
+ case '\\':
+ default:
+ *o = *i++;
+ break;
+ }
+ }
+ else
+ *o = *i++;
+ }
+ *o = '\0';
+}
+
+static MenuRoot *GetRoot(name, fore, back)
+char *name;
+char *fore, *back;
+{
+ MenuRoot *tmp;
+
+ tmp = FindMenuRoot(name);
+ if (tmp == NULL)
+ tmp = NewMenuRoot(name);
+
+ if (fore)
+ {
+ int save;
+
+ save = Scr->FirstTime;
+ Scr->FirstTime = TRUE;
+ GetColor(COLOR, &tmp->hi_fore, fore);
+ GetColor(COLOR, &tmp->hi_back, back);
+ Scr->FirstTime = save;
+ }
+
+ return tmp;
+}
+
+static void GotButton(butt, func)
+int butt, func;
+{
+ int i;
+
+ for (i = 0; i < NUM_CONTEXTS; i++)
+ {
+ if ((cont & (1 << i)) == 0)
+ continue;
+
+ Scr->Mouse[butt][i][mods].func = func;
+ if (func == F_MENU)
+ {
+ pull->prev = NULL;
+ Scr->Mouse[butt][i][mods].menu = pull;
+ }
+ else
+ {
+ root = GetRoot(TWM_ROOT, NULLSTR, NULLSTR);
+ Scr->Mouse[butt][i][mods].item = AddToMenu(root,"x",Action,
+ NULLSTR, func, NULLSTR, NULLSTR);
+ }
+ }
+ Action = "";
+ pull = NULL;
+ cont = 0;
+ mods_used |= mods;
+ mods = 0;
+}
+
+static void GotKey(key, func)
+char *key;
+int func;
+{
+ int i;
+
+ for (i = 0; i < NUM_CONTEXTS; i++)
+ {
+ if ((cont & (1 << i)) == 0)
+ continue;
+ if (!AddFuncKey(key, i, mods, func, Name, Action))
+ break;
+ }
+
+ Action = "";
+ pull = NULL;
+ cont = 0;
+ mods_used |= mods;
+ mods = 0;
+}
+
+
+static void GotTitleButton (bitmapname, func, rightside)
+ char *bitmapname;
+ int func;
+ Bool rightside;
+{
+ if (!CreateTitleButton (bitmapname, func, Action, pull, rightside, True)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "unable to create %s titlebutton \"%s\"\n",
+ rightside ? "right" : "left", bitmapname);
+ }
+ Action = "";
+ pull = NULL;
+}
+
+static Bool CheckWarpScreenArg (s)
+ register char *s;
+{
+ XmuCopyISOLatin1Lowered (s, s);
+
+ if (strcmp (s, WARPSCREEN_NEXT) == 0 ||
+ strcmp (s, WARPSCREEN_PREV) == 0 ||
+ strcmp (s, WARPSCREEN_BACK) == 0)
+ return True;
+
+ for (; *s && isascii(*s) && isdigit(*s); s++) ; /* SUPPRESS 530 */
+ return (*s ? False : True);
+}
+
+
+static Bool CheckWarpRingArg (s)
+ register char *s;
+{
+ XmuCopyISOLatin1Lowered (s, s);
+
+ if (strcmp (s, WARPSCREEN_NEXT) == 0 ||
+ strcmp (s, WARPSCREEN_PREV) == 0)
+ return True;
+
+ return False;
+}
+
+
+static Bool CheckColormapArg (s)
+ register char *s;
+{
+ XmuCopyISOLatin1Lowered (s, s);
+
+ if (strcmp (s, COLORMAP_NEXT) == 0 ||
+ strcmp (s, COLORMAP_PREV) == 0 ||
+ strcmp (s, COLORMAP_DEFAULT) == 0)
+ return True;
+
+ return False;
+}
+
+
+twmrc_error_prefix ()
+{
+ fprintf (stderr, "%s: line %d: ", ProgramName, yylineno);
+}
diff --git a/src/iconmgr.c b/src/iconmgr.c
new file mode 100644
index 0000000..188495b
--- /dev/null
+++ b/src/iconmgr.c
@@ -0,0 +1,773 @@
+/*
+ *
+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.
+ * */
+
+/***********************************************************************
+ *
+ * $Xorg: iconmgr.c,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * Icon Manager routines
+ *
+ * 09-Mar-89 Tom LaStrange File Created
+ *
+ ***********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include "util.h"
+#include "parse.h"
+#include "screen.h"
+#include "resize.h"
+#include "add_window.h"
+#include "siconify.bm"
+#include <X11/Xos.h>
+#include <X11/Xmu/CharSet.h>
+#ifdef macII
+int strcmp(); /* missing from string.h in AUX 2.0 */
+#endif
+
+int iconmgr_textx = siconify_width+11;
+WList *Active = NULL;
+WList *DownIconManager = NULL;
+int iconifybox_width = siconify_width;
+int iconifybox_height = siconify_height;
+
+/***********************************************************************
+ *
+ * Procedure:
+ * CreateIconManagers - creat all the icon manager windows
+ * for this screen.
+ *
+ * Returned Value:
+ * none
+ *
+ * Inputs:
+ * none
+ *
+ ***********************************************************************
+ */
+
+void CreateIconManagers()
+{
+ IconMgr *p;
+ int mask;
+ char str[100];
+ char str1[100];
+ Pixel background;
+ char *icon_name;
+
+ if (Scr->NoIconManagers)
+ return;
+
+ if (Scr->siconifyPm == None)
+ {
+ Scr->siconifyPm = XCreatePixmapFromBitmapData(dpy, Scr->Root,
+ (char *)siconify_bits, siconify_width, siconify_height, 1, 0, 1);
+ }
+
+ for (p = &Scr->iconmgr; p != NULL; p = p->next)
+ {
+ mask = XParseGeometry(p->geometry, &JunkX, &JunkY,
+ (unsigned int *) &p->width, (unsigned int *)&p->height);
+
+ if (mask & XNegative)
+ JunkX = Scr->MyDisplayWidth - p->width -
+ (2 * Scr->BorderWidth) + JunkX;
+
+ if (mask & YNegative)
+ JunkY = Scr->MyDisplayHeight - p->height -
+ (2 * Scr->BorderWidth) + JunkY;
+
+ background = Scr->IconManagerC.back;
+ GetColorFromList(Scr->IconManagerBL, p->name, (XClassHint *)NULL,
+ &background);
+
+ p->w = XCreateSimpleWindow(dpy, Scr->Root,
+ JunkX, JunkY, p->width, p->height, 1,
+ Scr->Black, background);
+
+ sprintf(str, "%s Icon Manager", p->name);
+ sprintf(str1, "%s Icons", p->name);
+ if (p->icon_name)
+ icon_name = p->icon_name;
+ else
+ icon_name = str1;
+
+ XSetStandardProperties(dpy, p->w, str, icon_name, None, NULL, 0, NULL);
+
+ p->twm_win = AddWindow(p->w, TRUE, p);
+ SetMapStateProp (p->twm_win, WithdrawnState);
+ }
+ for (p = &Scr->iconmgr; p != NULL; p = p->next)
+ {
+ GrabButtons(p->twm_win);
+ GrabKeys(p->twm_win);
+ }
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AllocateIconManager - allocate a new icon manager
+ *
+ * Inputs:
+ * name - the name of this icon manager
+ * icon_name - the name of the associated icon
+ * geom - a geometry string to eventually parse
+ * columns - the number of columns this icon manager has
+ *
+ ***********************************************************************
+ */
+
+IconMgr *AllocateIconManager(name, icon_name, geom, columns)
+ char *name;
+ char *geom;
+ char *icon_name;
+ int columns;
+{
+ IconMgr *p;
+
+#ifdef DEBUG_ICONMGR
+ fprintf(stderr, "AllocateIconManager\n");
+ fprintf(stderr, " name=\"%s\" icon_name=\"%s\", geom=\"%s\", col=%d\n",
+ name, icon_name, geom, columns);
+#endif
+
+ if (Scr->NoIconManagers)
+ return NULL;
+
+ p = (IconMgr *)malloc(sizeof(IconMgr));
+ p->name = name;
+ p->icon_name = icon_name;
+ p->geometry = geom;
+ p->columns = columns;
+ p->first = NULL;
+ p->last = NULL;
+ p->active = NULL;
+ p->scr = Scr;
+ p->count = 0;
+ p->x = 0;
+ p->y = 0;
+ p->width = 150;
+ p->height = 10;
+
+ Scr->iconmgr.lasti->next = p;
+ p->prev = Scr->iconmgr.lasti;
+ Scr->iconmgr.lasti = p;
+ p->next = NULL;
+
+ return(p);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * MoveIconManager - move the pointer around in an icon manager
+ *
+ * Inputs:
+ * dir - one of the following:
+ * F_FORWICONMGR - forward in the window list
+ * F_BACKICONMGR - backward in the window list
+ * F_UPICONMGR - up one row
+ * F_DOWNICONMGR - down one row
+ * F_LEFTICONMGR - left one column
+ * F_RIGHTICONMGR - right one column
+ *
+ * Special Considerations:
+ * none
+ *
+ ***********************************************************************
+ */
+
+void MoveIconManager(dir)
+ int dir;
+{
+ IconMgr *ip;
+ WList *tmp = NULL;
+ int cur_row, cur_col, new_row, new_col;
+ int row_inc, col_inc;
+ int got_it;
+
+ if (!Active) return;
+
+ cur_row = Active->row;
+ cur_col = Active->col;
+ ip = Active->iconmgr;
+
+ row_inc = 0;
+ col_inc = 0;
+ got_it = FALSE;
+
+ switch (dir)
+ {
+ case F_FORWICONMGR:
+ if ((tmp = Active->next) == NULL)
+ tmp = ip->first;
+ got_it = TRUE;
+ break;
+
+ case F_BACKICONMGR:
+ if ((tmp = Active->prev) == NULL)
+ tmp = ip->last;
+ got_it = TRUE;
+ break;
+
+ case F_UPICONMGR:
+ row_inc = -1;
+ break;
+
+ case F_DOWNICONMGR:
+ row_inc = 1;
+ break;
+
+ case F_LEFTICONMGR:
+ col_inc = -1;
+ break;
+
+ case F_RIGHTICONMGR:
+ col_inc = 1;
+ break;
+ }
+
+ /* If got_it is FALSE ast this point then we got a left, right,
+ * up, or down, command. We will enter this loop until we find
+ * a window to warp to.
+ */
+ new_row = cur_row;
+ new_col = cur_col;
+
+ while (!got_it)
+ {
+ new_row += row_inc;
+ new_col += col_inc;
+ if (new_row < 0)
+ new_row = ip->cur_rows - 1;
+ if (new_col < 0)
+ new_col = ip->cur_columns - 1;
+ if (new_row >= ip->cur_rows)
+ new_row = 0;
+ if (new_col >= ip->cur_columns)
+ new_col = 0;
+
+ /* Now let's go through the list to see if there is an entry with this
+ * new position
+ */
+ for (tmp = ip->first; tmp != NULL; tmp = tmp->next)
+ {
+ if (tmp->row == new_row && tmp->col == new_col)
+ {
+ got_it = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!got_it)
+ {
+ fprintf (stderr,
+ "%s: unable to find window (%d, %d) in icon manager\n",
+ ProgramName, new_row, new_col);
+ return;
+ }
+
+ if (tmp == NULL)
+ return;
+
+ /* raise the frame so the icon manager is visible */
+ if (ip->twm_win->mapped) {
+ XRaiseWindow(dpy, ip->twm_win->frame);
+ XWarpPointer(dpy, None, tmp->icon, 0,0,0,0, 5, 5);
+ } else {
+ if (tmp->twm->title_height) {
+ int tbx = Scr->TBInfo.titlex;
+ int x = tmp->twm->highlightx;
+ XWarpPointer (dpy, None, tmp->twm->title_w, 0, 0, 0, 0,
+ tbx + (x - tbx) / 2,
+ Scr->TitleHeight / 4);
+ } else {
+ XWarpPointer (dpy, None, tmp->twm->w, 0, 0, 0, 0, 5, 5);
+ }
+ }
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * JumpIconManager - jump from one icon manager to another,
+ * possibly even on another screen
+ *
+ * Inputs:
+ * dir - one of the following:
+ * F_NEXTICONMGR - go to the next icon manager
+ * F_PREVICONMGR - go to the previous one
+ *
+ ***********************************************************************
+ */
+
+void JumpIconManager(dir)
+ register int dir;
+{
+ IconMgr *ip, *tmp_ip = NULL;
+ int got_it = FALSE;
+ ScreenInfo *sp;
+ int screen;
+
+ if (!Active) return;
+
+
+#define ITER(i) (dir == F_NEXTICONMGR ? (i)->next : (i)->prev)
+#define IPOFSP(sp) (dir == F_NEXTICONMGR ? &(sp->iconmgr) : sp->iconmgr.lasti)
+#define TEST(ip) if ((ip)->count != 0 && (ip)->twm_win->mapped) \
+ { got_it = TRUE; break; }
+
+ ip = Active->iconmgr;
+ for (tmp_ip = ITER(ip); tmp_ip; tmp_ip = ITER(tmp_ip)) {
+ TEST (tmp_ip);
+ }
+
+ if (!got_it) {
+ int origscreen = ip->scr->screen;
+ int inc = (dir == F_NEXTICONMGR ? 1 : -1);
+
+ for (screen = origscreen + inc; ; screen += inc) {
+ if (screen >= NumScreens)
+ screen = 0;
+ else if (screen < 0)
+ screen = NumScreens - 1;
+
+ sp = ScreenList[screen];
+ if (sp) {
+ for (tmp_ip = IPOFSP (sp); tmp_ip; tmp_ip = ITER(tmp_ip)) {
+ TEST (tmp_ip);
+ }
+ }
+ if (got_it || screen == origscreen) break;
+ }
+ }
+
+#undef ITER
+#undef IPOFSP
+#undef TEST
+
+ if (!got_it) {
+ Bell(XkbBI_MinorError,0,None);
+ return;
+ }
+
+ /* raise the frame so it is visible */
+ XRaiseWindow(dpy, tmp_ip->twm_win->frame);
+ if (tmp_ip->active)
+ XWarpPointer(dpy, None, tmp_ip->active->icon, 0,0,0,0, 5, 5);
+ else
+ XWarpPointer(dpy, None, tmp_ip->w, 0,0,0,0, 5, 5);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AddIconManager - add a window to an icon manager
+ *
+ * Inputs:
+ * tmp_win - the TwmWindow structure
+ *
+ ***********************************************************************
+ */
+
+WList *AddIconManager(tmp_win)
+ TwmWindow *tmp_win;
+{
+ WList *tmp;
+ int h;
+ unsigned long valuemask; /* mask for create windows */
+ XSetWindowAttributes attributes; /* attributes for create windows */
+ IconMgr *ip;
+
+ tmp_win->list = NULL;
+
+ if (tmp_win->iconmgr || tmp_win->transient || Scr->NoIconManagers)
+ return NULL;
+
+ if (LookInList(Scr->IconMgrNoShow, tmp_win->full_name, &tmp_win->class))
+ return NULL;
+ if (Scr->IconManagerDontShow &&
+ !LookInList(Scr->IconMgrShow, tmp_win->full_name, &tmp_win->class))
+ return NULL;
+ if ((ip = (IconMgr *)LookInList(Scr->IconMgrs, tmp_win->full_name,
+ &tmp_win->class)) == NULL)
+ ip = &Scr->iconmgr;
+
+ tmp = (WList *) malloc(sizeof(WList));
+ tmp->iconmgr = ip;
+ tmp->next = NULL;
+ tmp->active = FALSE;
+ tmp->down = FALSE;
+
+ InsertInIconManager(ip, tmp, tmp_win);
+
+ tmp->twm = tmp_win;
+
+ tmp->fore = Scr->IconManagerC.fore;
+ tmp->back = Scr->IconManagerC.back;
+ tmp->highlight = Scr->IconManagerHighlight;
+
+ GetColorFromList(Scr->IconManagerFL, tmp_win->full_name, &tmp_win->class,
+ &tmp->fore);
+ GetColorFromList(Scr->IconManagerBL, tmp_win->full_name, &tmp_win->class,
+ &tmp->back);
+ GetColorFromList(Scr->IconManagerHighlightL, tmp_win->full_name,
+ &tmp_win->class, &tmp->highlight);
+
+ h = Scr->IconManagerFont.height + 10;
+ if (h < (siconify_height + 4))
+ h = siconify_height + 4;
+
+ ip->height = h * ip->count;
+ tmp->me = ip->count;
+ tmp->x = -1;
+ tmp->y = -1;
+
+ valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
+ attributes.background_pixel = tmp->back;
+ attributes.border_pixel = tmp->back;
+ attributes.event_mask = (KeyPressMask | ButtonPressMask |
+ ButtonReleaseMask | ExposureMask |
+ EnterWindowMask | LeaveWindowMask);
+ attributes.cursor = Scr->IconMgrCursor;
+ tmp->w = XCreateWindow (dpy, ip->w, 0, 0, (unsigned int) 1,
+ (unsigned int) h, (unsigned int) 0,
+ CopyFromParent, (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent, valuemask, &attributes);
+
+
+ valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
+ attributes.background_pixel = tmp->back;
+ attributes.border_pixel = Scr->Black;
+ attributes.event_mask = (ButtonReleaseMask| ButtonPressMask |
+ ExposureMask);
+ attributes.cursor = Scr->ButtonCursor;
+ tmp->icon = XCreateWindow (dpy, tmp->w, 5, (int) (h - siconify_height)/2,
+ (unsigned int) siconify_width,
+ (unsigned int) siconify_height,
+ (unsigned int) 0, CopyFromParent,
+ (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent,
+ valuemask, &attributes);
+
+ ip->count += 1;
+ PackIconManager(ip);
+ XMapWindow(dpy, tmp->w);
+
+ XSaveContext(dpy, tmp->w, IconManagerContext, (caddr_t) tmp);
+ XSaveContext(dpy, tmp->w, TwmContext, (caddr_t) tmp_win);
+ XSaveContext(dpy, tmp->w, ScreenContext, (caddr_t) Scr);
+ XSaveContext(dpy, tmp->icon, TwmContext, (caddr_t) tmp_win);
+ XSaveContext(dpy, tmp->icon, ScreenContext, (caddr_t) Scr);
+ tmp_win->list = tmp;
+
+ if (!ip->twm_win->icon)
+ {
+ XMapWindow(dpy, ip->w);
+ XMapWindow(dpy, ip->twm_win->frame);
+ }
+
+ return (tmp);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * InsertInIconManager - put an allocated entry into an icon
+ * manager
+ *
+ * Inputs:
+ * ip - the icon manager pointer
+ * tmp - the entry to insert
+ *
+ ***********************************************************************
+ */
+
+void InsertInIconManager(ip, tmp, tmp_win)
+ IconMgr *ip;
+ WList *tmp;
+ TwmWindow *tmp_win;
+{
+ WList *tmp1;
+ int added;
+ int (*compar)() = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
+
+ added = FALSE;
+ if (ip->first == NULL)
+ {
+ ip->first = tmp;
+ tmp->prev = NULL;
+ ip->last = tmp;
+ added = TRUE;
+ }
+ else if (Scr->SortIconMgr)
+ {
+ for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next)
+ {
+ if ((*compar)(tmp_win->icon_name, tmp1->twm->icon_name) < 0)
+ {
+ tmp->next = tmp1;
+ tmp->prev = tmp1->prev;
+ tmp1->prev = tmp;
+ if (tmp->prev == NULL)
+ ip->first = tmp;
+ else
+ tmp->prev->next = tmp;
+ added = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!added)
+ {
+ ip->last->next = tmp;
+ tmp->prev = ip->last;
+ ip->last = tmp;
+ }
+}
+
+void RemoveFromIconManager(ip, tmp)
+ IconMgr *ip;
+ WList *tmp;
+{
+ if (tmp->prev == NULL)
+ ip->first = tmp->next;
+ else
+ tmp->prev->next = tmp->next;
+
+ if (tmp->next == NULL)
+ ip->last = tmp->prev;
+ else
+ tmp->next->prev = tmp->prev;
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * RemoveIconManager - remove a window from the icon manager
+ *
+ * Inputs:
+ * tmp_win - the TwmWindow structure
+ *
+ ***********************************************************************
+ */
+
+void RemoveIconManager(tmp_win)
+ TwmWindow *tmp_win;
+{
+ IconMgr *ip;
+ WList *tmp;
+
+ if (tmp_win->list == NULL)
+ return;
+
+ tmp = tmp_win->list;
+ tmp_win->list = NULL;
+ ip = tmp->iconmgr;
+
+ RemoveFromIconManager(ip, tmp);
+
+ XDeleteContext(dpy, tmp->icon, TwmContext);
+ XDeleteContext(dpy, tmp->icon, ScreenContext);
+ XDestroyWindow(dpy, tmp->icon);
+ XDeleteContext(dpy, tmp->w, IconManagerContext);
+ XDeleteContext(dpy, tmp->w, TwmContext);
+ XDeleteContext(dpy, tmp->w, ScreenContext);
+ XDestroyWindow(dpy, tmp->w);
+ ip->count -= 1;
+ free((char *) tmp);
+
+ PackIconManager(ip);
+
+ if (ip->count == 0)
+ {
+ XUnmapWindow(dpy, ip->twm_win->frame);
+ }
+
+}
+
+void ActiveIconManager(active)
+ WList *active;
+{
+ active->active = TRUE;
+ Active = active;
+ Active->iconmgr->active = active;
+ DrawIconManagerBorder(active);
+}
+
+void NotActiveIconManager(active)
+ WList *active;
+{
+ active->active = FALSE;
+ DrawIconManagerBorder(active);
+}
+
+void DrawIconManagerBorder(tmp)
+ WList *tmp;
+{
+ {
+ XSetForeground(dpy, Scr->NormalGC, tmp->fore);
+ XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 2, 2,
+ tmp->width-5, tmp->height-5);
+
+ if (tmp->active && Scr->Highlight)
+ XSetForeground(dpy, Scr->NormalGC, tmp->highlight);
+ else
+ XSetForeground(dpy, Scr->NormalGC, tmp->back);
+
+ XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 0, 0,
+ tmp->width-1, tmp->height-1);
+ XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 1, 1,
+ tmp->width-3, tmp->height-3);
+ }
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * SortIconManager - sort the dude
+ *
+ * Inputs:
+ * ip - a pointer to the icon manager struture
+ *
+ ***********************************************************************
+ */
+
+void SortIconManager(ip)
+ IconMgr *ip;
+{
+ WList *tmp1, *tmp2;
+ int done;
+ int (*compar)() = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
+
+ if (ip == NULL)
+ ip = Active->iconmgr;
+
+ done = FALSE;
+ do
+ {
+ for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next)
+ {
+ if ((tmp2 = tmp1->next) == NULL)
+ {
+ done = TRUE;
+ break;
+ }
+ if ((*compar)(tmp1->twm->icon_name, tmp2->twm->icon_name) > 0)
+ {
+ /* take it out and put it back in */
+ RemoveFromIconManager(ip, tmp2);
+ InsertInIconManager(ip, tmp2, tmp2->twm);
+ break;
+ }
+ }
+ }
+ while (!done);
+ PackIconManager(ip);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * PackIconManager - pack the icon manager windows following
+ * an addition or deletion
+ *
+ * Inputs:
+ * ip - a pointer to the icon manager struture
+ *
+ ***********************************************************************
+ */
+
+void PackIconManager(ip)
+ IconMgr *ip;
+{
+ int newwidth, i, row, col, maxcol, colinc, rowinc, wheight, wwidth;
+ int new_x, new_y;
+ int savewidth;
+ WList *tmp;
+
+ wheight = Scr->IconManagerFont.height + 10;
+ if (wheight < (siconify_height + 4))
+ wheight = siconify_height + 4;
+
+ wwidth = ip->width / ip->columns;
+
+ rowinc = wheight;
+ colinc = wwidth;
+
+ row = 0;
+ col = ip->columns;
+ maxcol = 0;
+ for (i = 0, tmp = ip->first; tmp != NULL; i++, tmp = tmp->next)
+ {
+ tmp->me = i;
+ if (++col >= ip->columns)
+ {
+ col = 0;
+ row += 1;
+ }
+ if (col > maxcol)
+ maxcol = col;
+
+ new_x = col * colinc;
+ new_y = (row-1) * rowinc;
+
+ /* if the position or size has not changed, don't touch it */
+ if (tmp->x != new_x || tmp->y != new_y ||
+ tmp->width != wwidth || tmp->height != wheight)
+ {
+ XMoveResizeWindow(dpy, tmp->w, new_x, new_y, wwidth, wheight);
+
+ tmp->row = row-1;
+ tmp->col = col;
+ tmp->x = new_x;
+ tmp->y = new_y;
+ tmp->width = wwidth;
+ tmp->height = wheight;
+ }
+ }
+ maxcol += 1;
+
+ ip->cur_rows = row;
+ ip->cur_columns = maxcol;
+ ip->height = row * rowinc;
+ if (ip->height == 0)
+ ip->height = rowinc;
+ newwidth = maxcol * colinc;
+ if (newwidth == 0)
+ newwidth = colinc;
+
+ XResizeWindow(dpy, ip->w, newwidth, ip->height);
+
+ savewidth = ip->width;
+ if (ip->twm_win)
+ SetupWindow (ip->twm_win,
+ ip->twm_win->frame_x, ip->twm_win->frame_y,
+ newwidth, ip->height + ip->twm_win->title_height, -1);
+ ip->width = savewidth;
+}
diff --git a/src/iconmgr.h b/src/iconmgr.h
new file mode 100644
index 0000000..90c7073
--- /dev/null
+++ b/src/iconmgr.h
@@ -0,0 +1,93 @@
+/*
+ *
+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.
+ * */
+
+/***********************************************************************
+ *
+ * $Xorg: iconmgr.h,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * Icon Manager includes
+ *
+ * 09-Mar-89 Tom LaStrange File Created
+ *
+ ***********************************************************************/
+
+#ifndef _ICONMGR_
+#define _ICONMGR_
+
+typedef struct WList
+{
+ struct WList *next;
+ struct WList *prev;
+ struct TwmWindow *twm;
+ struct IconMgr *iconmgr;
+ Window w;
+ Window icon;
+ int x, y, width, height;
+ int row, col;
+ int me;
+ Pixel fore, back, highlight;
+ unsigned top, bottom;
+ short active;
+ short down;
+} WList;
+
+typedef struct IconMgr
+{
+ struct IconMgr *next; /* pointer to the next icon manager */
+ struct IconMgr *prev; /* pointer to the previous icon mgr */
+ struct IconMgr *lasti; /* pointer to the last icon mgr */
+ struct WList *first; /* first window in the list */
+ struct WList *last; /* last window in the list */
+ struct WList *active; /* the active entry */
+ TwmWindow *twm_win; /* back pointer to the new parent */
+ struct ScreenInfo *scr; /* the screen this thing is on */
+ Window w; /* this icon manager window */
+ char *geometry; /* geometry string */
+ char *name;
+ char *icon_name;
+ int x, y, width, height;
+ int columns, cur_rows, cur_columns;
+ int count;
+} IconMgr;
+
+extern int iconmgr_textx;
+extern WList *DownIconManager;
+
+extern void CreateIconManagers();
+extern IconMgr *AllocateIconManager();
+extern void MoveIconManager();
+extern void JumpIconManager();
+extern WList *AddIconManager();
+extern void InsertInIconManager();
+extern void RemoveFromIconManager();
+extern void RemoveIconManager();
+extern void ActiveIconManager();
+extern void NotActiveIconManager();
+extern void DrawIconManagerBorder();
+extern void SortIconManager();
+extern void PackIconManager();
+
+
+#endif /* _ICONMGR_ */
diff --git a/src/icons.c b/src/icons.c
new file mode 100644
index 0000000..32f0ce8
--- /dev/null
+++ b/src/icons.c
@@ -0,0 +1,588 @@
+/*
+ *
+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.
+ * */
+
+/**********************************************************************
+ *
+ * $Xorg: icons.c,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * Icon releated routines
+ *
+ * 10-Apr-89 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include "screen.h"
+#include "icons.h"
+#include "gram.h"
+#include "parse.h"
+#include "util.h"
+
+#define iconWidth(w) (Scr->IconBorderWidth * 2 + w->icon_w_width)
+#define iconHeight(w) (Scr->IconBorderWidth * 2 + w->icon_w_height)
+
+static
+splitEntry (ie, grav1, grav2, w, h)
+ IconEntry *ie;
+ int grav1, grav2;
+ int w, h;
+{
+ IconEntry *new;
+
+ switch (grav1) {
+ case D_NORTH:
+ case D_SOUTH:
+ if (w != ie->w)
+ splitEntry (ie, grav2, grav1, w, ie->h);
+ if (h != ie->h) {
+ new = (IconEntry *)malloc (sizeof (IconEntry));
+ new->twm_win = 0;
+ new->used = 0;
+ new->next = ie->next;
+ ie->next = new;
+ new->x = ie->x;
+ new->h = (ie->h - h);
+ new->w = ie->w;
+ ie->h = h;
+ if (grav1 == D_SOUTH) {
+ new->y = ie->y;
+ ie->y = new->y + new->h;
+ } else
+ new->y = ie->y + ie->h;
+ }
+ break;
+ case D_EAST:
+ case D_WEST:
+ if (h != ie->h)
+ splitEntry (ie, grav2, grav1, ie->w, h);
+ if (w != ie->w) {
+ new = (IconEntry *)malloc (sizeof (IconEntry));
+ new->twm_win = 0;
+ new->used = 0;
+ new->next = ie->next;
+ ie->next = new;
+ new->y = ie->y;
+ new->w = (ie->w - w);
+ new->h = ie->h;
+ ie->w = w;
+ if (grav1 == D_EAST) {
+ new->x = ie->x;
+ ie->x = new->x + new->w;
+ } else
+ new->x = ie->x + ie->w;
+ }
+ break;
+ }
+}
+
+roundUp (v, multiple)
+{
+ return ((v + multiple - 1) / multiple) * multiple;
+}
+
+PlaceIcon(tmp_win, def_x, def_y, final_x, final_y)
+TwmWindow *tmp_win;
+int def_x, def_y;
+int *final_x, *final_y;
+{
+ IconRegion *ir;
+ IconEntry *ie;
+ int w = 0, h = 0;
+
+ ie = 0;
+ for (ir = Scr->FirstRegion; ir; ir = ir->next) {
+ w = roundUp (iconWidth (tmp_win), ir->stepx);
+ h = roundUp (iconHeight (tmp_win), ir->stepy);
+ for (ie = ir->entries; ie; ie=ie->next) {
+ if (ie->used)
+ continue;
+ if (ie->w >= w && ie->h >= h)
+ break;
+ }
+ if (ie)
+ break;
+ }
+ if (ie) {
+ splitEntry (ie, ir->grav1, ir->grav2, w, h);
+ ie->used = 1;
+ ie->twm_win = tmp_win;
+ *final_x = ie->x + (ie->w - iconWidth (tmp_win)) / 2;
+ *final_y = ie->y + (ie->h - iconHeight (tmp_win)) / 2;
+ } else {
+ *final_x = def_x;
+ *final_y = def_y;
+ }
+ return;
+}
+
+static IconEntry *
+FindIconEntry (tmp_win, irp)
+ TwmWindow *tmp_win;
+ IconRegion **irp;
+{
+ IconRegion *ir;
+ IconEntry *ie;
+
+ for (ir = Scr->FirstRegion; ir; ir = ir->next) {
+ for (ie = ir->entries; ie; ie=ie->next)
+ if (ie->twm_win == tmp_win) {
+ if (irp)
+ *irp = ir;
+ return ie;
+ }
+ }
+ return 0;
+}
+
+IconUp (tmp_win)
+ TwmWindow *tmp_win;
+{
+ int x, y;
+ int defx, defy;
+ struct IconRegion *ir;
+
+ /*
+ * If the client specified a particular location, let's use it (this might
+ * want to be an option at some point). Otherwise, try to fit within the
+ * icon region.
+ */
+ if (tmp_win->wmhints && (tmp_win->wmhints->flags & IconPositionHint))
+ return;
+
+ if (tmp_win->icon_moved) {
+ if (!XGetGeometry (dpy, tmp_win->icon_w, &JunkRoot, &defx, &defy,
+ &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth))
+ return;
+
+ x = defx + ((int) JunkWidth) / 2;
+ y = defy + ((int) JunkHeight) / 2;
+
+ for (ir = Scr->FirstRegion; ir; ir = ir->next) {
+ if (x >= ir->x && x < (ir->x + ir->w) &&
+ y >= ir->y && y < (ir->y + ir->h))
+ break;
+ }
+ if (!ir) return; /* outside icon regions, leave alone */
+ }
+
+ defx = -100;
+ defy = -100;
+ PlaceIcon(tmp_win, defx, defy, &x, &y);
+ if (x != defx || y != defy) {
+ XMoveWindow (dpy, tmp_win->icon_w, x, y);
+ tmp_win->icon_moved = FALSE; /* since we've restored it */
+ }
+}
+
+static IconEntry *
+prevIconEntry (ie, ir)
+ IconEntry *ie;
+ IconRegion *ir;
+{
+ IconEntry *ip;
+
+ if (ie == ir->entries)
+ return 0;
+ for (ip = ir->entries; ip->next != ie; ip=ip->next)
+ ;
+ return ip;
+}
+
+/* old is being freed; and is adjacent to ie. Merge
+ * regions together
+ */
+
+static
+mergeEntries (old, ie)
+ IconEntry *old, *ie;
+{
+ if (old->y == ie->y) {
+ ie->w = old->w + ie->w;
+ if (old->x < ie->x)
+ ie->x = old->x;
+ } else {
+ ie->h = old->h + ie->h;
+ if (old->y < ie->y)
+ ie->y = old->y;
+ }
+}
+
+IconDown (tmp_win)
+ TwmWindow *tmp_win;
+{
+ IconEntry *ie, *ip, *in;
+ IconRegion *ir;
+
+ ie = FindIconEntry (tmp_win, &ir);
+ if (ie) {
+ ie->twm_win = 0;
+ ie->used = 0;
+ ip = prevIconEntry (ie, ir);
+ in = ie->next;
+ for (;;) {
+ if (ip && ip->used == 0 &&
+ ((ip->x == ie->x && ip->w == ie->w) ||
+ (ip->y == ie->y && ip->h == ie->h)))
+ {
+ ip->next = ie->next;
+ mergeEntries (ie, ip);
+ free ((char *) ie);
+ ie = ip;
+ ip = prevIconEntry (ip, ir);
+ } else if (in && in->used == 0 &&
+ ((in->x == ie->x && in->w == ie->w) ||
+ (in->y == ie->y && in->h == ie->h)))
+ {
+ ie->next = in->next;
+ mergeEntries (in, ie);
+ free ((char *) in);
+ in = ie->next;
+ } else
+ break;
+ }
+ }
+}
+
+AddIconRegion(geom, grav1, grav2, stepx, stepy)
+char *geom;
+int grav1, grav2;
+{
+ IconRegion *ir;
+ int mask;
+
+ ir = (IconRegion *)malloc(sizeof(IconRegion));
+ ir->next = NULL;
+ if (Scr->LastRegion)
+ Scr->LastRegion->next = ir;
+ Scr->LastRegion = ir;
+ if (!Scr->FirstRegion)
+ Scr->FirstRegion = ir;
+
+ ir->entries = NULL;
+ ir->grav1 = grav1;
+ ir->grav2 = grav2;
+ if (stepx <= 0)
+ stepx = 1;
+ if (stepy <= 0)
+ stepy = 1;
+ ir->stepx = stepx;
+ ir->stepy = stepy;
+ ir->x = ir->y = ir->w = ir->h = 0;
+
+ mask = XParseGeometry(geom, &ir->x, &ir->y, (unsigned int *)&ir->w, (unsigned int *)&ir->h);
+
+ if (mask & XNegative)
+ ir->x += Scr->MyDisplayWidth - ir->w;
+
+ if (mask & YNegative)
+ ir->y += Scr->MyDisplayHeight - ir->h;
+ ir->entries = (IconEntry *)malloc(sizeof(IconEntry));
+ ir->entries->next = 0;
+ ir->entries->x = ir->x;
+ ir->entries->y = ir->y;
+ ir->entries->w = ir->w;
+ ir->entries->h = ir->h;
+ ir->entries->twm_win = 0;
+ ir->entries->used = 0;
+}
+
+#ifdef comment
+FreeIconEntries (ir)
+ IconRegion *ir;
+{
+ IconEntry *ie, *tmp;
+
+ for (ie = ir->entries; ie; ie=tmp)
+ {
+ tmp = ie->next;
+ free ((char *) ie);
+ }
+}
+FreeIconRegions()
+{
+ IconRegion *ir, *tmp;
+
+ for (ir = Scr->FirstRegion; ir != NULL;)
+ {
+ tmp = ir;
+ FreeIconEntries (ir);
+ ir = ir->next;
+ free((char *) tmp);
+ }
+ Scr->FirstRegion = NULL;
+ Scr->LastRegion = NULL;
+}
+#endif
+
+CreateIconWindow(tmp_win, def_x, def_y)
+TwmWindow *tmp_win;
+int def_x, def_y;
+{
+ unsigned long event_mask;
+ unsigned long valuemask; /* mask for create windows */
+ XSetWindowAttributes attributes; /* attributes for create windows */
+ Pixmap pm = None; /* tmp pixmap variable */
+ int final_x, final_y;
+ int x;
+
+
+ FB(tmp_win->iconc.fore, tmp_win->iconc.back);
+
+ tmp_win->forced = FALSE;
+ tmp_win->icon_not_ours = FALSE;
+
+ /* now go through the steps to get an icon window, if ForceIcon is
+ * set, then no matter what else is defined, the bitmap from the
+ * .twmrc file is used
+ */
+ if (Scr->ForceIcon)
+ {
+ char *icon_name;
+ Pixmap bm;
+
+ icon_name = LookInNameList(Scr->IconNames, tmp_win->full_name);
+ if (icon_name == NULL)
+ icon_name = LookInList(Scr->IconNames, tmp_win->full_name,
+ &tmp_win->class);
+
+ bm = None;
+ if (icon_name != NULL)
+ {
+ if ((bm = (Pixmap)LookInNameList(Scr->Icons, icon_name)) == None)
+ {
+ if ((bm = GetBitmap (icon_name)) != None)
+ AddToList(&Scr->Icons, icon_name, (char *)bm);
+ }
+ }
+
+ if (bm != None)
+ {
+ XGetGeometry(dpy, bm, &JunkRoot, &JunkX, &JunkY,
+ (unsigned int *) &tmp_win->icon_width, (unsigned int *)&tmp_win->icon_height,
+ &JunkBW, &JunkDepth);
+
+ pm = XCreatePixmap(dpy, Scr->Root, tmp_win->icon_width,
+ tmp_win->icon_height, Scr->d_depth);
+
+ /* the copy plane works on color ! */
+ XCopyPlane(dpy, bm, pm, Scr->NormalGC,
+ 0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
+
+ tmp_win->forced = TRUE;
+ }
+ }
+
+ /* if the pixmap is still NULL, we didn't get one from the above code,
+ * that could mean that ForceIcon was not set, or that the window
+ * was not in the Icons list, now check the WM hints for an icon
+ */
+ if (pm == None && tmp_win->wmhints &&
+ tmp_win->wmhints->flags & IconPixmapHint)
+ {
+
+ XGetGeometry(dpy, tmp_win->wmhints->icon_pixmap,
+ &JunkRoot, &JunkX, &JunkY,
+ (unsigned int *)&tmp_win->icon_width, (unsigned int *)&tmp_win->icon_height, &JunkBW, &JunkDepth);
+
+ pm = XCreatePixmap(dpy, Scr->Root,
+ tmp_win->icon_width, tmp_win->icon_height,
+ Scr->d_depth);
+
+ XCopyPlane(dpy, tmp_win->wmhints->icon_pixmap, pm, Scr->NormalGC,
+ 0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
+ }
+
+ /* if we still haven't got an icon, let's look in the Icon list
+ * if ForceIcon is not set
+ */
+ if (pm == None && !Scr->ForceIcon)
+ {
+ char *icon_name;
+ Pixmap bm;
+
+ icon_name = LookInNameList(Scr->IconNames, tmp_win->full_name);
+ if (icon_name == NULL)
+ icon_name = LookInList(Scr->IconNames, tmp_win->full_name,
+ &tmp_win->class);
+
+ bm = None;
+ if (icon_name != NULL)
+ {
+ if ((bm = (Pixmap)LookInNameList(Scr->Icons, icon_name)) == None)
+ {
+ if ((bm = GetBitmap (icon_name)) != None)
+ AddToList(&Scr->Icons, icon_name, (char *)bm);
+ }
+ }
+
+ if (bm != None)
+ {
+ XGetGeometry(dpy, bm, &JunkRoot, &JunkX, &JunkY,
+ (unsigned int *)&tmp_win->icon_width, (unsigned int *)&tmp_win->icon_height,
+ &JunkBW, &JunkDepth);
+
+ pm = XCreatePixmap(dpy, Scr->Root, tmp_win->icon_width,
+ tmp_win->icon_height, Scr->d_depth);
+
+ /* the copy plane works on color ! */
+ XCopyPlane(dpy, bm, pm, Scr->NormalGC,
+ 0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
+ }
+ }
+
+ /* if we still don't have an icon, assign the UnknownIcon */
+
+ if (pm == None && Scr->UnknownPm != None)
+ {
+ tmp_win->icon_width = Scr->UnknownWidth;
+ tmp_win->icon_height = Scr->UnknownHeight;
+
+ pm = XCreatePixmap(dpy, Scr->Root, tmp_win->icon_width,
+ tmp_win->icon_height, Scr->d_depth);
+
+ /* the copy plane works on color ! */
+ XCopyPlane(dpy, Scr->UnknownPm, pm, Scr->NormalGC,
+ 0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
+ }
+
+ if (pm == None)
+ {
+ tmp_win->icon_height = 0;
+ tmp_win->icon_width = 0;
+ valuemask = 0;
+ }
+ else
+ {
+ valuemask = CWBackPixmap;
+ attributes.background_pixmap = pm;
+ }
+
+ tmp_win->icon_w_width = XTextWidth(Scr->IconFont.font,
+ tmp_win->icon_name, strlen(tmp_win->icon_name));
+
+ tmp_win->icon_w_width += 6;
+ if (tmp_win->icon_w_width < tmp_win->icon_width)
+ {
+ tmp_win->icon_x = (tmp_win->icon_width - tmp_win->icon_w_width)/2;
+ tmp_win->icon_x += 3;
+ tmp_win->icon_w_width = tmp_win->icon_width;
+ }
+ else
+ {
+ tmp_win->icon_x = 3;
+ }
+ tmp_win->icon_y = tmp_win->icon_height + Scr->IconFont.height;
+ tmp_win->icon_w_height = tmp_win->icon_height + Scr->IconFont.height + 4;
+
+ event_mask = 0;
+ if (tmp_win->wmhints && tmp_win->wmhints->flags & IconWindowHint)
+ {
+ tmp_win->icon_w = tmp_win->wmhints->icon_window;
+ if (tmp_win->forced ||
+ XGetGeometry(dpy, tmp_win->icon_w, &JunkRoot, &JunkX, &JunkY,
+ (unsigned int *)&tmp_win->icon_w_width, (unsigned int *)&tmp_win->icon_w_height,
+ &JunkBW, &JunkDepth) == 0)
+ {
+ tmp_win->icon_w = None;
+ tmp_win->wmhints->flags &= ~IconWindowHint;
+ }
+ else
+ {
+ tmp_win->icon_not_ours = TRUE;
+ event_mask = EnterWindowMask | LeaveWindowMask;
+ }
+ }
+ else
+ {
+ tmp_win->icon_w = None;
+ }
+
+ if (tmp_win->icon_w == None)
+ {
+ tmp_win->icon_w = XCreateSimpleWindow(dpy, Scr->Root,
+ 0,0,
+ tmp_win->icon_w_width, tmp_win->icon_w_height,
+ Scr->IconBorderWidth, tmp_win->icon_border, tmp_win->iconc.back);
+ event_mask = ExposureMask;
+ }
+
+ XSelectInput (dpy, tmp_win->icon_w,
+ KeyPressMask | ButtonPressMask | ButtonReleaseMask |
+ event_mask);
+
+ tmp_win->icon_bm_w = None;
+ if (pm != None &&
+ (! (tmp_win->wmhints && tmp_win->wmhints->flags & IconWindowHint)))
+ {
+ int y;
+
+ y = 0;
+ if (tmp_win->icon_w_width == tmp_win->icon_width)
+ x = 0;
+ else
+ x = (tmp_win->icon_w_width - tmp_win->icon_width)/2;
+
+ tmp_win->icon_bm_w = XCreateWindow (dpy, tmp_win->icon_w, x, y,
+ (unsigned int)tmp_win->icon_width,
+ (unsigned int)tmp_win->icon_height,
+ (unsigned int) 0, Scr->d_depth,
+ (unsigned int) CopyFromParent,
+ Scr->d_visual, valuemask,
+ &attributes);
+ }
+
+ /* I need to figure out where to put the icon window now, because
+ * getting here means that I am going to make the icon visible
+ */
+ if (tmp_win->wmhints &&
+ tmp_win->wmhints->flags & IconPositionHint)
+ {
+ final_x = tmp_win->wmhints->icon_x;
+ final_y = tmp_win->wmhints->icon_y;
+ }
+ else
+ {
+ PlaceIcon(tmp_win, def_x, def_y, &final_x, &final_y);
+ }
+
+ if (final_x > Scr->MyDisplayWidth)
+ final_x = Scr->MyDisplayWidth - tmp_win->icon_w_width -
+ (2 * Scr->IconBorderWidth);
+
+ if (final_y > Scr->MyDisplayHeight)
+ final_y = Scr->MyDisplayHeight - tmp_win->icon_height -
+ Scr->IconFont.height - 4 - (2 * Scr->IconBorderWidth);
+
+ XMoveWindow(dpy, tmp_win->icon_w, final_x, final_y);
+ tmp_win->iconified = TRUE;
+
+ XMapSubwindows(dpy, tmp_win->icon_w);
+ XSaveContext(dpy, tmp_win->icon_w, TwmContext, (caddr_t)tmp_win);
+ XSaveContext(dpy, tmp_win->icon_w, ScreenContext, (caddr_t)Scr);
+ XDefineCursor(dpy, tmp_win->icon_w, Scr->IconCursor);
+ if (pm) XFreePixmap (dpy, pm);
+ return;
+}
diff --git a/src/icons.h b/src/icons.h
new file mode 100644
index 0000000..43cbab9
--- /dev/null
+++ b/src/icons.h
@@ -0,0 +1,56 @@
+/*
+ *
+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.
+ * */
+
+/**********************************************************************
+ *
+ * $Xorg: icons.h,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * Icon releated definitions
+ *
+ * 10-Apr-89 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#ifndef ICONS_H
+#define ICONS_H
+
+typedef struct IconRegion
+{
+ struct IconRegion *next;
+ int x, y, w, h;
+ int grav1, grav2;
+ int stepx, stepy; /* allocation granularity */
+ struct IconEntry *entries;
+} IconRegion;
+
+typedef struct IconEntry
+{
+ struct IconEntry *next;
+ int x, y, w, h;
+ TwmWindow *twm_win;
+ short used;
+}IconEntry;
+
+#endif /* ICONS_H */
diff --git a/src/lex.l b/src/lex.l
new file mode 100644
index 0000000..1886f4b
--- /dev/null
+++ b/src/lex.l
@@ -0,0 +1,145 @@
+%{
+/*****************************************************************************/
+/*
+
+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: lex.l,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * .twmrc lex file
+ *
+ * 12-Nov-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+/* #include <stdio.h> */ /* lex already includes stdio.h */
+#include "gram.h"
+#include "parse.h"
+extern char *ProgramName;
+
+extern int ParseError;
+#ifdef FLEX_SCANNER
+int yylineno;
+
+#undef YY_INPUT
+#define YY_INPUT(buf,result,size) ((result) = doinput((buf),(size)))
+doinput (buf, size)
+char *buf;
+{
+ int c;
+
+ if (size == 0)
+ return (0);
+
+ if ((c = (*twmInputFunc)()) <= 0)
+ return (0);
+
+ buf[0] = c;
+ return (1);
+}
+#endif
+
+%}
+
+string \"([^"]|\\.)*\"
+number [0-9]+
+%%
+"{" { return (LB); }
+"}" { return (RB); }
+"(" { return (LP); }
+")" { return (RP); }
+"=" { return (EQUALS); }
+":" { return (COLON); }
+"+" { return PLUS; }
+"-" { return MINUS; }
+"|" { return OR; }
+
+[a-zA-Z\.]+ { int token = parse_keyword (yytext,
+ &yylval.num);
+ if (token == ERRORTOKEN) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "ignoring unknown keyword: %s\n",
+ yytext);
+ ParseError = 1;
+ } else
+ return token;
+ }
+
+"!" { yylval.num = F_EXEC; return FSKEYWORD; }
+"^" { yylval.num = F_CUT; return FSKEYWORD; }
+
+{string} { yylval.ptr = (char *)yytext; return STRING; }
+{number} { (void)sscanf((char *)yytext, "%d", &yylval.num);
+ return (NUMBER);
+ }
+\#[^\n]*\n {;}
+[\n\t ] {;}
+. {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "ignoring character \"%s\"\n",
+ yytext);
+ ParseError = 1;
+ }
+%%
+#ifndef yywrap
+yywrap() { return(1);}
+#endif
+
+#undef unput
+#undef input
+#undef output
+#undef feof
+#define unput(c) twmUnput(c)
+#define input() (*twmInputFunc)()
+#define output(c) TwmOutput(c)
+#define feof() (1)
diff --git a/src/list.c b/src/list.c
new file mode 100644
index 0000000..e0f4774
--- /dev/null
+++ b/src/list.c
@@ -0,0 +1,258 @@
+/*****************************************************************************/
+/*
+
+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: list.c,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * TWM code to deal with the name lists for the NoTitle list and
+ * the AutoRaise list
+ *
+ * 11-Apr-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include "screen.h"
+#include "gram.h"
+
+struct name_list_struct
+{
+ name_list *next; /* pointer to the next name */
+ char *name; /* the name of the window */
+ char *ptr; /* list dependent data */
+};
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AddToList - add a window name to the appropriate list
+ *
+ * Inputs:
+ * list - the address of the pointer to the head of a list
+ * name - a pointer to the name of the window
+ * ptr - pointer to list dependent data
+ *
+ * Special Considerations
+ * If the list does not use the ptr value, a non-null value
+ * should be placed in it. LookInList returns this ptr value
+ * and procedures calling LookInList will check for a non-null
+ * return value as an indication of success.
+ *
+ ***********************************************************************
+ */
+
+void
+AddToList(list_head, name, ptr)
+name_list **list_head;
+char *name;
+char *ptr;
+{
+ name_list *nptr;
+
+ if (!list_head) return; /* ignore empty inserts */
+
+ nptr = (name_list *)malloc(sizeof(name_list));
+ if (nptr == NULL)
+ {
+ twmrc_error_prefix();
+ fprintf (stderr, "unable to allocate %d bytes for name_list\n",
+ sizeof(name_list));
+ Done();
+ }
+
+ nptr->next = *list_head;
+ nptr->name = name;
+ nptr->ptr = (ptr == NULL) ? (char *)TRUE : ptr;
+ *list_head = nptr;
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * LookInList - look through a list for a window name, or class
+ *
+ * Returned Value:
+ * the ptr field of the list structure or NULL if the name
+ * or class was not found in the list
+ *
+ * Inputs:
+ * list - a pointer to the head of a list
+ * name - a pointer to the name to look for
+ * class - a pointer to the class to look for
+ *
+ ***********************************************************************
+ */
+
+char *
+LookInList(list_head, name, class)
+name_list *list_head;
+char *name;
+XClassHint *class;
+{
+ name_list *nptr;
+
+ /* look for the name first */
+ for (nptr = list_head; nptr != NULL; nptr = nptr->next)
+ if (strcmp(name, nptr->name) == 0)
+ return (nptr->ptr);
+
+ if (class)
+ {
+ /* look for the res_name next */
+ for (nptr = list_head; nptr != NULL; nptr = nptr->next)
+ if (strcmp(class->res_name, nptr->name) == 0)
+ return (nptr->ptr);
+
+ /* finally look for the res_class */
+ for (nptr = list_head; nptr != NULL; nptr = nptr->next)
+ if (strcmp(class->res_class, nptr->name) == 0)
+ return (nptr->ptr);
+ }
+ return (NULL);
+}
+
+char *
+LookInNameList(list_head, name)
+name_list *list_head;
+char *name;
+{
+ return (LookInList(list_head, name, NULL));
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * GetColorFromList - look through a list for a window name, or class
+ *
+ * Returned Value:
+ * TRUE if the name was found
+ * FALSE if the name was not found
+ *
+ * Inputs:
+ * list - a pointer to the head of a list
+ * name - a pointer to the name to look for
+ * class - a pointer to the class to look for
+ *
+ * Outputs:
+ * ptr - fill in the list value if the name was found
+ *
+ ***********************************************************************
+ */
+
+int GetColorFromList(list_head, name, class, ptr)
+name_list *list_head;
+char *name;
+XClassHint *class;
+Pixel *ptr;
+{
+ int save;
+ name_list *nptr;
+
+ for (nptr = list_head; nptr != NULL; nptr = nptr->next)
+ if (strcmp(name, nptr->name) == 0)
+ {
+ save = Scr->FirstTime;
+ Scr->FirstTime = TRUE;
+ GetColor(Scr->Monochrome, ptr, nptr->ptr);
+ Scr->FirstTime = save;
+ return (TRUE);
+ }
+
+ if (class)
+ {
+ for (nptr = list_head; nptr != NULL; nptr = nptr->next)
+ if (strcmp(class->res_name, nptr->name) == 0)
+ {
+ save = Scr->FirstTime;
+ Scr->FirstTime = TRUE;
+ GetColor(Scr->Monochrome, ptr, nptr->ptr);
+ Scr->FirstTime = save;
+ return (TRUE);
+ }
+
+ for (nptr = list_head; nptr != NULL; nptr = nptr->next)
+ if (strcmp(class->res_class, nptr->name) == 0)
+ {
+ save = Scr->FirstTime;
+ Scr->FirstTime = TRUE;
+ GetColor(Scr->Monochrome, ptr, nptr->ptr);
+ Scr->FirstTime = save;
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * FreeList - free up a list
+ *
+ ***********************************************************************
+ */
+
+void FreeList(list)
+name_list **list;
+{
+ name_list *nptr;
+ name_list *tmp;
+
+ for (nptr = *list; nptr != NULL; )
+ {
+ tmp = nptr->next;
+ free((char *) nptr);
+ nptr = tmp;
+ }
+ *list = NULL;
+}
diff --git a/src/list.h b/src/list.h
new file mode 100644
index 0000000..8b4cce3
--- /dev/null
+++ b/src/list.h
@@ -0,0 +1,75 @@
+/*****************************************************************************/
+/*
+
+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: list.h,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * TWM list handling external definitions
+ *
+ * 11-Apr-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#ifndef _LIST_
+#define _LIST_
+
+typedef struct name_list_struct name_list;
+
+extern void AddToList();
+extern char* LookInList();
+extern char* LookInNameList();
+extern int GetColorFromList();
+extern void FreeList();
+
+#endif /* _LIST_ */
+
diff --git a/src/menus.c b/src/menus.c
new file mode 100644
index 0000000..83fe792
--- /dev/null
+++ b/src/menus.c
@@ -0,0 +1,3035 @@
+/*****************************************************************************/
+/*
+
+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: menus.c,v 1.6 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * twm menu code
+ *
+ * 17-Nov-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#include <stdio.h>
+#include <X11/Xos.h>
+#include "twm.h"
+#include "gc.h"
+#include "menus.h"
+#include "resize.h"
+#include "events.h"
+#include "util.h"
+#include "parse.h"
+#include "gram.h"
+#include "screen.h"
+#include <X11/Xmu/CharSet.h>
+#include <X11/bitmaps/menu12>
+#include "version.h"
+#include <X11/extensions/sync.h>
+#include <X11/SM/SMlib.h>
+
+extern XEvent Event;
+
+int RootFunction = 0;
+MenuRoot *ActiveMenu = NULL; /* the active menu */
+MenuItem *ActiveItem = NULL; /* the active menu item */
+int MoveFunction; /* either F_MOVE or F_FORCEMOVE */
+int WindowMoved = FALSE;
+int menuFromFrameOrWindowOrTitlebar = FALSE;
+
+int ConstMove = FALSE; /* constrained move variables */
+int ConstMoveDir;
+int ConstMoveX;
+int ConstMoveY;
+int ConstMoveXL;
+int ConstMoveXR;
+int ConstMoveYT;
+int ConstMoveYB;
+
+/* Globals used to keep track of whether the mouse has moved during
+ a resize function. */
+int ResizeOrigX;
+int ResizeOrigY;
+
+int MenuDepth = 0; /* number of menus up */
+static struct {
+ int x;
+ int y;
+} MenuOrigins[MAXMENUDEPTH];
+static Cursor LastCursor;
+
+void WarpAlongRing(), WarpToWindow();
+
+extern char *Action;
+extern int Context;
+extern TwmWindow *ButtonWindow, *Tmp_win;
+extern XEvent Event, ButtonEvent;
+extern char *InitFile;
+static void Identify();
+
+#define SHADOWWIDTH 5 /* in pixels */
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * InitMenus - initialize menu roots
+ *
+ ***********************************************************************
+ */
+
+void
+InitMenus()
+{
+ int i, j, k;
+ FuncKey *key, *tmp;
+
+ for (i = 0; i < MAX_BUTTONS+1; i++)
+ for (j = 0; j < NUM_CONTEXTS; j++)
+ for (k = 0; k < MOD_SIZE; k++)
+ {
+ Scr->Mouse[i][j][k].func = 0;
+ Scr->Mouse[i][j][k].item = NULL;
+ }
+
+ Scr->DefaultFunction.func = 0;
+ Scr->WindowFunction.func = 0;
+
+ if (FirstScreen)
+ {
+ for (key = Scr->FuncKeyRoot.next; key != NULL;)
+ {
+ free(key->name);
+ tmp = key;
+ key = key->next;
+ free((char *) tmp);
+ }
+ Scr->FuncKeyRoot.next = NULL;
+ }
+
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AddFuncKey - add a function key to the list
+ *
+ * Inputs:
+ * name - the name of the key
+ * cont - the context to look for the key press in
+ * mods - modifier keys that need to be pressed
+ * func - the function to perform
+ * win_name- the window name (if any)
+ * action - the action string associated with the function (if any)
+ *
+ ***********************************************************************
+ */
+
+Bool AddFuncKey (name, cont, mods, func, win_name, action)
+ char *name;
+ int cont, mods, func;
+ char *win_name;
+ char *action;
+{
+ FuncKey *tmp;
+ KeySym keysym;
+ KeyCode keycode;
+
+ /*
+ * Don't let a 0 keycode go through, since that means AnyKey to the
+ * XGrabKey call in GrabKeys().
+ */
+ if ((keysym = XStringToKeysym(name)) == NoSymbol ||
+ (keycode = XKeysymToKeycode(dpy, keysym)) == 0)
+ {
+ return False;
+ }
+
+ /* see if there already is a key defined for this context */
+ for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
+ {
+ if (tmp->keysym == keysym &&
+ tmp->cont == cont &&
+ tmp->mods == mods)
+ break;
+ }
+
+ if (tmp == NULL)
+ {
+ tmp = (FuncKey *) malloc(sizeof(FuncKey));
+ tmp->next = Scr->FuncKeyRoot.next;
+ Scr->FuncKeyRoot.next = tmp;
+ }
+
+ tmp->name = name;
+ tmp->keysym = keysym;
+ tmp->keycode = keycode;
+ tmp->cont = cont;
+ tmp->mods = mods;
+ tmp->func = func;
+ tmp->win_name = win_name;
+ tmp->action = action;
+
+ return True;
+}
+
+
+
+int CreateTitleButton (name, func, action, menuroot, rightside, append)
+ char *name;
+ int func;
+ char *action;
+ MenuRoot *menuroot;
+ Bool rightside;
+ Bool append;
+{
+ TitleButton *tb = (TitleButton *) malloc (sizeof(TitleButton));
+
+ if (!tb) {
+ fprintf (stderr,
+ "%s: unable to allocate %d bytes for title button\n",
+ ProgramName, sizeof(TitleButton));
+ return 0;
+ }
+
+ tb->next = NULL;
+ tb->name = name; /* note that we are not copying */
+ tb->bitmap = None; /* WARNING, values not set yet */
+ tb->width = 0; /* see InitTitlebarButtons */
+ tb->height = 0; /* ditto */
+ tb->func = func;
+ tb->action = action;
+ tb->menuroot = menuroot;
+ tb->rightside = rightside;
+ if (rightside) {
+ Scr->TBInfo.nright++;
+ } else {
+ Scr->TBInfo.nleft++;
+ }
+
+ /*
+ * Cases for list:
+ *
+ * 1. empty list, prepend left put at head of list
+ * 2. append left, prepend right put in between left and right
+ * 3. append right put at tail of list
+ *
+ * Do not refer to widths and heights yet since buttons not created
+ * (since fonts not loaded and heights not known).
+ */
+ if ((!Scr->TBInfo.head) || ((!append) && (!rightside))) { /* 1 */
+ tb->next = Scr->TBInfo.head;
+ Scr->TBInfo.head = tb;
+ } else if (append && rightside) { /* 3 */
+ register TitleButton *t;
+ for /* SUPPRESS 530 */
+ (t = Scr->TBInfo.head; t->next; t = t->next);
+ t->next = tb;
+ tb->next = NULL;
+ } else { /* 2 */
+ register TitleButton *t, *prev = NULL;
+ for (t = Scr->TBInfo.head; t && !t->rightside; t = t->next) {
+ prev = t;
+ }
+ if (prev) {
+ tb->next = prev->next;
+ prev->next = tb;
+ } else {
+ tb->next = Scr->TBInfo.head;
+ Scr->TBInfo.head = tb;
+ }
+ }
+
+ return 1;
+}
+
+
+
+/*
+ * InitTitlebarButtons - Do all the necessary stuff to load in a titlebar
+ * button. If we can't find the button, then put in a question; if we can't
+ * find the question mark, something is wrong and we are probably going to be
+ * in trouble later on.
+ */
+void InitTitlebarButtons ()
+{
+ TitleButton *tb;
+ int h;
+
+ /*
+ * initialize dimensions
+ */
+ Scr->TBInfo.width = (Scr->TitleHeight -
+ 2 * (Scr->FramePadding + Scr->ButtonIndent));
+ Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
+ ? ((Scr->TitlePadding + 1) / 2) : 1);
+ h = Scr->TBInfo.width - 2 * Scr->TBInfo.border;
+
+ /*
+ * add in some useful buttons and bindings so that novices can still
+ * use the system.
+ */
+ if (!Scr->NoDefaults) {
+ /* insert extra buttons */
+ if (!CreateTitleButton (TBPM_ICONIFY, F_ICONIFY, "", (MenuRoot *) NULL,
+ False, False)) {
+ fprintf (stderr, "%s: unable to add iconify button\n",
+ ProgramName);
+ }
+ if (!CreateTitleButton (TBPM_RESIZE, F_RESIZE, "", (MenuRoot *) NULL,
+ True, True)) {
+ fprintf (stderr, "%s: unable to add resize button\n",
+ ProgramName);
+ }
+ AddDefaultBindings ();
+ }
+ ComputeCommonTitleOffsets ();
+
+ /*
+ * load in images and do appropriate centering
+ */
+
+ for (tb = Scr->TBInfo.head; tb; tb = tb->next) {
+ tb->bitmap = FindBitmap (tb->name, &tb->width, &tb->height);
+ if (!tb->bitmap) {
+ tb->bitmap = FindBitmap (TBPM_QUESTION, &tb->width, &tb->height);
+ if (!tb->bitmap) { /* cannot happen (see util.c) */
+ fprintf (stderr,
+ "%s: unable to add titlebar button \"%s\"\n",
+ ProgramName, tb->name);
+ }
+ }
+
+ tb->dstx = (h - tb->width + 1) / 2;
+ if (tb->dstx < 0) { /* clip to minimize copying */
+ tb->srcx = -(tb->dstx);
+ tb->width = h;
+ tb->dstx = 0;
+ } else {
+ tb->srcx = 0;
+ }
+ tb->dsty = (h - tb->height + 1) / 2;
+ if (tb->dsty < 0) {
+ tb->srcy = -(tb->dsty);
+ tb->height = h;
+ tb->dsty = 0;
+ } else {
+ tb->srcy = 0;
+ }
+ }
+}
+
+
+
+PaintEntry(mr, mi, exposure)
+MenuRoot *mr;
+MenuItem *mi;
+int exposure;
+{
+ int y_offset;
+ int text_y;
+ GC gc;
+
+#ifdef DEBUG_MENUS
+ fprintf(stderr, "Paint entry\n");
+#endif
+ y_offset = mi->item_num * Scr->EntryHeight;
+ text_y = y_offset + Scr->MenuFont.y;
+
+ if (mi->func != F_TITLE)
+ {
+ int x, y;
+
+ if (mi->state)
+ {
+ XSetForeground(dpy, Scr->NormalGC, mi->hi_back);
+
+ XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
+ mr->width, Scr->EntryHeight);
+
+ FBF(mi->hi_fore, mi->hi_back, Scr->MenuFont.font->fid);
+
+ XDrawString(dpy, mr->w, Scr->NormalGC, mi->x,
+ text_y, mi->item, mi->strlen);
+
+ gc = Scr->NormalGC;
+ }
+ else
+ {
+ if (mi->user_colors || !exposure)
+ {
+ XSetForeground(dpy, Scr->NormalGC, mi->back);
+
+ XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
+ mr->width, Scr->EntryHeight);
+
+ FBF(mi->fore, mi->back, Scr->MenuFont.font->fid);
+ gc = Scr->NormalGC;
+ }
+ else
+ gc = Scr->MenuGC;
+
+ XDrawString(dpy, mr->w, gc, mi->x,
+ text_y, mi->item, mi->strlen);
+ }
+
+ if (mi->func == F_MENU)
+ {
+ /* create the pull right pixmap if needed */
+ if (Scr->pullPm == None)
+ {
+ Scr->pullPm = CreateMenuIcon (Scr->MenuFont.height,
+ &Scr->pullW, &Scr->pullH);
+ }
+ x = mr->width - Scr->pullW - 5;
+ y = y_offset + ((Scr->MenuFont.height - Scr->pullH) / 2);
+ XCopyPlane(dpy, Scr->pullPm, mr->w, gc, 0, 0,
+ Scr->pullW, Scr->pullH, x, y, 1);
+ }
+ }
+ else
+ {
+ int y;
+
+ XSetForeground(dpy, Scr->NormalGC, mi->back);
+
+ /* fill the rectangle with the title background color */
+ XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
+ mr->width, Scr->EntryHeight);
+
+ {
+ XSetForeground(dpy, Scr->NormalGC, mi->fore);
+ /* now draw the dividing lines */
+ if (y_offset)
+ XDrawLine (dpy, mr->w, Scr->NormalGC, 0, y_offset,
+ mr->width, y_offset);
+ y = ((mi->item_num+1) * Scr->EntryHeight)-1;
+ XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y, mr->width, y);
+ }
+
+ FBF(mi->fore, mi->back, Scr->MenuFont.font->fid);
+ /* finally render the title */
+ XDrawString(dpy, mr->w, Scr->NormalGC, mi->x,
+ text_y, mi->item, mi->strlen);
+ }
+}
+
+
+
+PaintMenu(mr, e)
+MenuRoot *mr;
+XEvent *e;
+{
+ MenuItem *mi;
+
+ for (mi = mr->first; mi != NULL; mi = mi->next)
+ {
+ int y_offset = mi->item_num * Scr->EntryHeight;
+
+ /* be smart about handling the expose, redraw only the entries
+ * that we need to
+ */
+ if (e->xexpose.y < (y_offset + Scr->EntryHeight) &&
+ (e->xexpose.y + e->xexpose.height) > y_offset)
+ {
+ PaintEntry(mr, mi, True);
+ }
+ }
+ XSync(dpy, 0);
+}
+
+
+
+static Bool fromMenu;
+
+UpdateMenu()
+{
+ MenuItem *mi;
+ int i, x, y, x_root, y_root, entry;
+ int done;
+ MenuItem *badItem = NULL;
+
+ fromMenu = TRUE;
+
+ while (TRUE)
+ {
+ /* block until there is an event */
+ if (!menuFromFrameOrWindowOrTitlebar) {
+ XMaskEvent(dpy,
+ ButtonPressMask | ButtonReleaseMask |
+ EnterWindowMask | ExposureMask |
+ VisibilityChangeMask | LeaveWindowMask |
+ 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 (!DispatchEvent ())
+ continue;
+
+ if (Event.type == ButtonRelease || Cancel) {
+ menuFromFrameOrWindowOrTitlebar = FALSE;
+ fromMenu = FALSE;
+ return;
+ }
+
+ if (Event.type != MotionNotify)
+ continue;
+
+ done = FALSE;
+ XQueryPointer( dpy, ActiveMenu->w, &JunkRoot, &JunkChild,
+ &x_root, &y_root, &x, &y, &JunkMask);
+
+ /* if we haven't recieved the enter notify yet, wait */
+ if (ActiveMenu && !ActiveMenu->entered)
+ continue;
+
+ XFindContext(dpy, ActiveMenu->w, ScreenContext, (caddr_t *)&Scr);
+
+ if (x < 0 || y < 0 ||
+ x >= ActiveMenu->width || y >= ActiveMenu->height)
+ {
+ if (ActiveItem && ActiveItem->func != F_TITLE)
+ {
+ ActiveItem->state = 0;
+ PaintEntry(ActiveMenu, ActiveItem, False);
+ }
+ ActiveItem = NULL;
+ continue;
+ }
+
+ /* look for the entry that the mouse is in */
+ entry = y / Scr->EntryHeight;
+ for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi=mi->next)
+ {
+ if (i == entry)
+ break;
+ }
+
+ /* if there is an active item, we might have to turn it off */
+ if (ActiveItem)
+ {
+ /* is the active item the one we are on ? */
+ if (ActiveItem->item_num == entry && ActiveItem->state)
+ done = TRUE;
+
+ /* if we weren't on the active entry, let's turn the old
+ * active one off
+ */
+ if (!done && ActiveItem->func != F_TITLE)
+ {
+ ActiveItem->state = 0;
+ PaintEntry(ActiveMenu, ActiveItem, False);
+ }
+ }
+
+ /* if we weren't on the active item, change the active item and turn
+ * it on
+ */
+ if (!done)
+ {
+ ActiveItem = mi;
+ if (ActiveItem->func != F_TITLE && !ActiveItem->state)
+ {
+ ActiveItem->state = 1;
+ PaintEntry(ActiveMenu, ActiveItem, False);
+ }
+ }
+
+ /* now check to see if we were over the arrow of a pull right entry */
+ if (ActiveItem->func == F_MENU &&
+ ((ActiveMenu->width - x) < (ActiveMenu->width >> 1)))
+ {
+ MenuRoot *save = ActiveMenu;
+ int savex = MenuOrigins[MenuDepth - 1].x;
+ int savey = MenuOrigins[MenuDepth - 1].y;
+
+ if (MenuDepth < MAXMENUDEPTH) {
+ PopUpMenu (ActiveItem->sub,
+ (savex + (ActiveMenu->width >> 1)),
+ (savey + ActiveItem->item_num * Scr->EntryHeight)
+ /*(savey + ActiveItem->item_num * Scr->EntryHeight +
+ (Scr->EntryHeight >> 1))*/, False);
+ } else if (!badItem) {
+ Bell(XkbBI_MinorError,0,None);
+ badItem = ActiveItem;
+ }
+
+ /* if the menu did get popped up, unhighlight the active item */
+ if (save != ActiveMenu && ActiveItem->state)
+ {
+ ActiveItem->state = 0;
+ PaintEntry(save, ActiveItem, False);
+ ActiveItem = NULL;
+ }
+ }
+ if (badItem != ActiveItem) badItem = NULL;
+ XFlush(dpy);
+ }
+
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * NewMenuRoot - create a new menu root
+ *
+ * Returned Value:
+ * (MenuRoot *)
+ *
+ * Inputs:
+ * name - the name of the menu root
+ *
+ ***********************************************************************
+ */
+
+MenuRoot *
+NewMenuRoot(name)
+ char *name;
+{
+ MenuRoot *tmp;
+
+#define UNUSED_PIXEL ((unsigned long) (~0)) /* more than 24 bits */
+
+ tmp = (MenuRoot *) malloc(sizeof(MenuRoot));
+ tmp->hi_fore = UNUSED_PIXEL;
+ tmp->hi_back = UNUSED_PIXEL;
+ tmp->name = name;
+ tmp->prev = NULL;
+ tmp->first = NULL;
+ tmp->last = NULL;
+ tmp->items = 0;
+ tmp->width = 0;
+ tmp->mapped = NEVER_MAPPED;
+ tmp->pull = FALSE;
+ tmp->w = None;
+ tmp->shadow = None;
+ tmp->real_menu = FALSE;
+
+ if (Scr->MenuList == NULL)
+ {
+ Scr->MenuList = tmp;
+ Scr->MenuList->next = NULL;
+ }
+
+ if (Scr->LastMenu == NULL)
+ {
+ Scr->LastMenu = tmp;
+ Scr->LastMenu->next = NULL;
+ }
+ else
+ {
+ Scr->LastMenu->next = tmp;
+ Scr->LastMenu = tmp;
+ Scr->LastMenu->next = NULL;
+ }
+
+ if (strcmp(name, TWM_WINDOWS) == 0)
+ Scr->Windows = tmp;
+
+ return (tmp);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AddToMenu - add an item to a root menu
+ *
+ * Returned Value:
+ * (MenuItem *)
+ *
+ * Inputs:
+ * menu - pointer to the root menu to add the item
+ * item - the text to appear in the menu
+ * action - the string to possibly execute
+ * sub - the menu root if it is a pull-right entry
+ * func - the numeric function
+ * fore - foreground color string
+ * back - background color string
+ *
+ ***********************************************************************
+ */
+
+MenuItem *
+AddToMenu(menu, item, action, sub, func, fore, back)
+ MenuRoot *menu;
+ char *item, *action;
+ MenuRoot *sub;
+ int func;
+ char *fore, *back;
+{
+ MenuItem *tmp;
+ int width;
+
+#ifdef DEBUG_MENUS
+ fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%d, f=%d\n",
+ item, action, sub, func);
+#endif
+
+ tmp = (MenuItem *) malloc(sizeof(MenuItem));
+ tmp->root = menu;
+
+ if (menu->first == NULL)
+ {
+ menu->first = tmp;
+ tmp->prev = NULL;
+ }
+ else
+ {
+ menu->last->next = tmp;
+ tmp->prev = menu->last;
+ }
+ menu->last = tmp;
+
+ tmp->item = item;
+ tmp->strlen = strlen(item);
+ tmp->action = action;
+ tmp->next = NULL;
+ tmp->sub = NULL;
+ tmp->state = 0;
+ tmp->func = func;
+
+ if (!Scr->HaveFonts) CreateFonts();
+ width = XTextWidth(Scr->MenuFont.font, item, tmp->strlen);
+ if (width <= 0)
+ width = 1;
+ if (width > menu->width)
+ menu->width = width;
+
+ tmp->user_colors = FALSE;
+ if (Scr->Monochrome == COLOR && fore != NULL)
+ {
+ int save;
+
+ save = Scr->FirstTime;
+ Scr->FirstTime = TRUE;
+ GetColor(COLOR, &tmp->fore, fore);
+ GetColor(COLOR, &tmp->back, back);
+ Scr->FirstTime = save;
+ tmp->user_colors = TRUE;
+ }
+ if (sub != NULL)
+ {
+ tmp->sub = sub;
+ menu->pull = TRUE;
+ }
+ tmp->item_num = menu->items++;
+
+ return (tmp);
+}
+
+
+
+MakeMenus()
+{
+ MenuRoot *mr;
+
+ for (mr = Scr->MenuList; mr != NULL; mr = mr->next)
+ {
+ if (mr->real_menu == FALSE)
+ continue;
+
+ MakeMenu(mr);
+ }
+}
+
+
+
+MakeMenu(mr)
+MenuRoot *mr;
+{
+ MenuItem *start, *end, *cur, *tmp;
+ XColor f1, f2, f3;
+ XColor b1, b2, b3;
+ XColor save_fore, save_back;
+ int num, i;
+ int fred, fgreen, fblue;
+ int bred, bgreen, bblue;
+ int width;
+ unsigned long valuemask;
+ XSetWindowAttributes attributes;
+ Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
+
+ Scr->EntryHeight = Scr->MenuFont.height + 4;
+
+ /* lets first size the window accordingly */
+ if (mr->mapped == NEVER_MAPPED)
+ {
+ if (mr->pull == TRUE)
+ {
+ mr->width += 16 + 10;
+ }
+
+ width = mr->width + 10;
+
+ for (cur = mr->first; cur != NULL; cur = cur->next)
+ {
+ if (cur->func != F_TITLE)
+ cur->x = 5;
+ else
+ {
+ cur->x = width - XTextWidth(Scr->MenuFont.font, cur->item,
+ cur->strlen);
+ cur->x /= 2;
+ }
+ }
+ mr->height = mr->items * Scr->EntryHeight;
+ mr->width += 10;
+
+ if (Scr->Shadow)
+ {
+ /*
+ * Make sure that you don't draw into the shadow window or else
+ * the background bits there will get saved
+ */
+ valuemask = (CWBackPixel | CWBorderPixel);
+ attributes.background_pixel = Scr->MenuShadowColor;
+ attributes.border_pixel = Scr->MenuShadowColor;
+ if (Scr->SaveUnder) {
+ valuemask |= CWSaveUnder;
+ attributes.save_under = True;
+ }
+ mr->shadow = XCreateWindow (dpy, Scr->Root, 0, 0,
+ (unsigned int) mr->width,
+ (unsigned int) mr->height,
+ (unsigned int)0,
+ CopyFromParent,
+ (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent,
+ valuemask, &attributes);
+ }
+
+ valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
+ attributes.background_pixel = Scr->MenuC.back;
+ attributes.border_pixel = Scr->MenuC.fore;
+ attributes.event_mask = (ExposureMask | EnterWindowMask);
+ if (Scr->SaveUnder) {
+ valuemask |= CWSaveUnder;
+ attributes.save_under = True;
+ }
+ if (Scr->BackingStore) {
+ valuemask |= CWBackingStore;
+ attributes.backing_store = Always;
+ }
+ mr->w = XCreateWindow (dpy, Scr->Root, 0, 0, (unsigned int) mr->width,
+ (unsigned int) mr->height, (unsigned int) 1,
+ CopyFromParent, (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent,
+ valuemask, &attributes);
+
+
+ XSaveContext(dpy, mr->w, MenuContext, (caddr_t)mr);
+ XSaveContext(dpy, mr->w, ScreenContext, (caddr_t)Scr);
+
+ mr->mapped = UNMAPPED;
+ }
+
+ /* get the default colors into the menus */
+ for (tmp = mr->first; tmp != NULL; tmp = tmp->next)
+ {
+ if (!tmp->user_colors) {
+ if (tmp->func != F_TITLE) {
+ tmp->fore = Scr->MenuC.fore;
+ tmp->back = Scr->MenuC.back;
+ } else {
+ tmp->fore = Scr->MenuTitleC.fore;
+ tmp->back = Scr->MenuTitleC.back;
+ }
+ }
+
+ if (mr->hi_fore != UNUSED_PIXEL)
+ {
+ tmp->hi_fore = mr->hi_fore;
+ tmp->hi_back = mr->hi_back;
+ }
+ else
+ {
+ tmp->hi_fore = tmp->back;
+ tmp->hi_back = tmp->fore;
+ }
+ }
+
+ if (Scr->Monochrome == MONOCHROME || !Scr->InterpolateMenuColors)
+ return;
+
+ start = mr->first;
+ while (TRUE)
+ {
+ for (; start != NULL; start = start->next)
+ {
+ if (start->user_colors)
+ break;
+ }
+ if (start == NULL)
+ break;
+
+ for (end = start->next; end != NULL; end = end->next)
+ {
+ if (end->user_colors)
+ break;
+ }
+ if (end == NULL)
+ break;
+
+ /* we have a start and end to interpolate between */
+ num = end->item_num - start->item_num;
+
+ f1.pixel = start->fore;
+ XQueryColor(dpy, cmap, &f1);
+ f2.pixel = end->fore;
+ XQueryColor(dpy, cmap, &f2);
+
+ b1.pixel = start->back;
+ XQueryColor(dpy, cmap, &b1);
+ b2.pixel = end->back;
+ XQueryColor(dpy, cmap, &b2);
+
+ fred = ((int)f2.red - (int)f1.red) / num;
+ fgreen = ((int)f2.green - (int)f1.green) / num;
+ fblue = ((int)f2.blue - (int)f1.blue) / num;
+
+ bred = ((int)b2.red - (int)b1.red) / num;
+ bgreen = ((int)b2.green - (int)b1.green) / num;
+ bblue = ((int)b2.blue - (int)b1.blue) / num;
+
+ f3 = f1;
+ f3.flags = DoRed | DoGreen | DoBlue;
+
+ b3 = b1;
+ b3.flags = DoRed | DoGreen | DoBlue;
+
+ num -= 1;
+ for (i = 0, cur = start->next; i < num; i++, cur = cur->next)
+ {
+ f3.red += fred;
+ f3.green += fgreen;
+ f3.blue += fblue;
+ save_fore = f3;
+
+ b3.red += bred;
+ b3.green += bgreen;
+ b3.blue += bblue;
+ save_back = b3;
+
+ XAllocColor(dpy, cmap, &f3);
+ XAllocColor(dpy, cmap, &b3);
+ cur->hi_back = cur->fore = f3.pixel;
+ cur->hi_fore = cur->back = b3.pixel;
+ cur->user_colors = True;
+
+ f3 = save_fore;
+ b3 = save_back;
+ }
+ start = end;
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * PopUpMenu - pop up a pull down menu
+ *
+ * Inputs:
+ * menu - the root pointer of the menu to pop up
+ * x, y - location of upper left of menu
+ * center - whether or not to center horizontally over position
+ *
+ ***********************************************************************
+ */
+
+Bool PopUpMenu (menu, x, y, center)
+ MenuRoot *menu;
+ int x, y;
+ Bool center;
+{
+ int WindowNameOffset, WindowNameCount;
+ TwmWindow **WindowNames;
+ TwmWindow *tmp_win2,*tmp_win3;
+ int i;
+ int (*compar)() =
+ (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
+
+ if (!menu) return False;
+
+ InstallRootColormap();
+
+ if (menu == Scr->Windows)
+ {
+ TwmWindow *tmp_win;
+
+ /* this is the twm windows menu, let's go ahead and build it */
+
+ DestroyMenu (menu);
+
+ menu->first = NULL;
+ menu->last = NULL;
+ menu->items = 0;
+ menu->width = 0;
+ menu->mapped = NEVER_MAPPED;
+ AddToMenu(menu, "TWM Windows", NULLSTR, NULL, F_TITLE,NULLSTR,NULLSTR);
+
+ WindowNameOffset=(char *)Scr->TwmRoot.next->name -
+ (char *)Scr->TwmRoot.next;
+ for(tmp_win = Scr->TwmRoot.next , WindowNameCount=0;
+ tmp_win != NULL;
+ tmp_win = tmp_win->next)
+ WindowNameCount++;
+ WindowNames =
+ (TwmWindow **)malloc(sizeof(TwmWindow *)*WindowNameCount);
+ WindowNames[0] = Scr->TwmRoot.next;
+ for(tmp_win = Scr->TwmRoot.next->next , WindowNameCount=1;
+ tmp_win != NULL;
+ tmp_win = tmp_win->next,WindowNameCount++)
+ {
+ tmp_win2 = tmp_win;
+ for (i=0;i<WindowNameCount;i++)
+ {
+ if ((*compar)(tmp_win2->name,WindowNames[i]->name) < 0)
+ {
+ tmp_win3 = tmp_win2;
+ tmp_win2 = WindowNames[i];
+ WindowNames[i] = tmp_win3;
+ }
+ }
+ WindowNames[WindowNameCount] = tmp_win2;
+ }
+ for (i=0; i<WindowNameCount; i++)
+ {
+ AddToMenu(menu, WindowNames[i]->name, (char *)WindowNames[i],
+ NULL, F_POPUP,NULL,NULL);
+ }
+ free(WindowNames);
+
+ MakeMenu(menu);
+ }
+
+ if (menu->w == None || menu->items == 0) return False;
+
+ /* Prevent recursively bringing up menus. */
+ if (menu->mapped == MAPPED) return False;
+
+ /*
+ * Dynamically set the parent; this allows pull-ups to also be main
+ * menus, or to be brought up from more than one place.
+ */
+ menu->prev = ActiveMenu;
+
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask | PointerMotionHintMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, Scr->MenuCursor, CurrentTime);
+
+ ActiveMenu = menu;
+ menu->mapped = MAPPED;
+ menu->entered = FALSE;
+
+ if (center) {
+ x -= (menu->width / 2);
+ y -= (Scr->EntryHeight / 2); /* sticky menus would be nice here */
+ }
+
+ /*
+ * clip to screen
+ */
+ if (x + menu->width > Scr->MyDisplayWidth) {
+ x = Scr->MyDisplayWidth - menu->width;
+ }
+ if (x < 0) x = 0;
+ if (y + menu->height > Scr->MyDisplayHeight) {
+ y = Scr->MyDisplayHeight - menu->height;
+ }
+ if (y < 0) y = 0;
+
+ MenuOrigins[MenuDepth].x = x;
+ MenuOrigins[MenuDepth].y = y;
+ MenuDepth++;
+
+ XMoveWindow(dpy, menu->w, x, y);
+ if (Scr->Shadow) {
+ XMoveWindow (dpy, menu->shadow, x + SHADOWWIDTH, y + SHADOWWIDTH);
+ }
+ if (Scr->Shadow) {
+ XRaiseWindow (dpy, menu->shadow);
+ }
+ XMapRaised(dpy, menu->w);
+ if (Scr->Shadow) {
+ XMapWindow (dpy, menu->shadow);
+ }
+ XSync(dpy, 0);
+ return True;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * PopDownMenu - unhighlight the current menu selection and
+ * take down the menus
+ *
+ ***********************************************************************
+ */
+
+PopDownMenu()
+{
+ MenuRoot *tmp;
+
+ if (ActiveMenu == NULL)
+ return;
+
+ if (ActiveItem)
+ {
+ ActiveItem->state = 0;
+ PaintEntry(ActiveMenu, ActiveItem, False);
+ }
+
+ for (tmp = ActiveMenu; tmp != NULL; tmp = tmp->prev)
+ {
+ if (Scr->Shadow) {
+ XUnmapWindow (dpy, tmp->shadow);
+ }
+ XUnmapWindow(dpy, tmp->w);
+ tmp->mapped = UNMAPPED;
+ UninstallRootColormap();
+ }
+
+ XFlush(dpy);
+ ActiveMenu = NULL;
+ ActiveItem = NULL;
+ MenuDepth = 0;
+ if (Context == C_WINDOW || Context == C_FRAME || Context == C_TITLE)
+ menuFromFrameOrWindowOrTitlebar = TRUE;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * FindMenuRoot - look for a menu root
+ *
+ * Returned Value:
+ * (MenuRoot *) - a pointer to the menu root structure
+ *
+ * Inputs:
+ * name - the name of the menu root
+ *
+ ***********************************************************************
+ */
+
+MenuRoot *
+FindMenuRoot(name)
+ char *name;
+{
+ MenuRoot *tmp;
+
+ for (tmp = Scr->MenuList; tmp != NULL; tmp = tmp->next)
+ {
+ if (strcmp(name, tmp->name) == 0)
+ return (tmp);
+ }
+ return NULL;
+}
+
+
+
+static Bool belongs_to_twm_window (t, w)
+ register TwmWindow *t;
+ register Window w;
+{
+ if (!t) return False;
+
+ if (w == t->frame || w == t->title_w || w == t->hilite_w ||
+ w == t->icon_w || w == t->icon_bm_w) return True;
+
+ if (t && t->titlebuttons) {
+ register TBWindow *tbw;
+ register int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
+ for (tbw = t->titlebuttons; nb > 0; tbw++, nb--) {
+ if (tbw->window == w) return True;
+ }
+ }
+ return False;
+}
+
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * resizeFromCenter -
+ *
+ ***********************************************************************
+ */
+
+
+extern int AddingX;
+extern int AddingY;
+extern int AddingW;
+extern int AddingH;
+
+void resizeFromCenter(w, tmp_win)
+ Window w;
+ TwmWindow *tmp_win;
+{
+ int lastx, lasty, width, height, bw2;
+ int namelen;
+ XEvent event;
+
+ namelen = strlen (tmp_win->name);
+ bw2 = tmp_win->frame_bw * 2;
+ AddingW = tmp_win->attr.width + bw2;
+ AddingH = tmp_win->attr.height + tmp_win->title_height + bw2;
+ width = (SIZE_HINDENT + XTextWidth (Scr->SizeFont.font,
+ tmp_win->name, namelen));
+ height = Scr->SizeFont.height + SIZE_VINDENT * 2;
+ XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
+ (unsigned int *)&DragWidth, (unsigned int *)&DragHeight,
+ &JunkBW, &JunkDepth);
+ XWarpPointer(dpy, None, w,
+ 0, 0, 0, 0, DragWidth/2, DragHeight/2);
+ XQueryPointer (dpy, Scr->Root, &JunkRoot,
+ &JunkChild, &JunkX, &JunkY,
+ &AddingX, &AddingY, &JunkMask);
+/*****
+ 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);
+*****/
+ lastx = -10000;
+ lasty = -10000;
+/*****
+ MoveOutline(Scr->Root,
+ origDragX - JunkBW, origDragY - JunkBW,
+ DragWidth * JunkBW, DragHeight * JunkBW,
+ tmp_win->frame_bw,
+ tmp_win->title_height);
+*****/
+ MenuStartResize(tmp_win, origDragX, origDragY, DragWidth, DragHeight);
+ 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)
+ {
+ MenuEndResize(tmp_win);
+ XMoveResizeWindow(dpy, w, AddingX, AddingY, AddingW, AddingH);
+ break;
+ }
+
+/* if (!DispatchEvent ()) continue; */
+
+ 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)
+ {
+ MenuDoResize(AddingX, AddingY, tmp_win);
+
+ lastx = AddingX;
+ lasty = AddingY;
+ }
+
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * ExecuteFunction - execute a twm root function
+ *
+ * Inputs:
+ * func - the function to execute
+ * action - the menu action to execute
+ * w - the window to execute this function on
+ * tmp_win - the twm window structure
+ * event - the event that caused the function
+ * context - the context in which the button was pressed
+ * pulldown- flag indicating execution from pull down menu
+ *
+ * Returns:
+ * TRUE if should continue with remaining actions else FALSE to abort
+ *
+ ***********************************************************************
+ */
+
+/* for F_WARPTO */
+#define true 1
+#define false 0
+int
+WarpThere(t)
+ TwmWindow* t;
+{
+ if (Scr->WarpUnmapped || t->mapped) {
+ if (!t->mapped) DeIconify (t);
+ if (!Scr->NoRaiseWarp) XRaiseWindow (dpy, t->frame);
+ WarpToWindow (t);
+ return true;
+ }
+ return false;
+}
+
+extern int MovedFromKeyPress;
+
+int
+ExecuteFunction(func, action, w, tmp_win, eventp, context, pulldown)
+ int func;
+ char *action;
+ Window w;
+ TwmWindow *tmp_win;
+ XEvent *eventp;
+ int context;
+ int pulldown;
+{
+ static Time last_time = 0;
+ char tmp[200];
+ char *ptr;
+ char buff[MAX_FILE_SIZE];
+ int count, fd;
+ Window rootw;
+ int origX, origY;
+ int do_next_action = TRUE;
+ int moving_icon = FALSE;
+ Bool fromtitlebar = False;
+ extern int ConstrainedMoveTime;
+
+ RootFunction = 0;
+ if (Cancel)
+ return TRUE; /* XXX should this be FALSE? */
+
+ switch (func)
+ {
+ case F_UPICONMGR:
+ case F_LEFTICONMGR:
+ case F_RIGHTICONMGR:
+ case F_DOWNICONMGR:
+ case F_FORWICONMGR:
+ case F_BACKICONMGR:
+ case F_NEXTICONMGR:
+ case F_PREVICONMGR:
+ case F_NOP:
+ case F_TITLE:
+ case F_DELTASTOP:
+ case F_RAISELOWER:
+ case F_WARPTOSCREEN:
+ case F_WARPTO:
+ case F_WARPRING:
+ case F_WARPTOICONMGR:
+ case F_COLORMAP:
+ break;
+ default:
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, Scr->WaitCursor, CurrentTime);
+ break;
+ }
+
+ switch (func)
+ {
+ case F_NOP:
+ case F_TITLE:
+ break;
+
+ case F_DELTASTOP:
+ if (WindowMoved) do_next_action = FALSE;
+ break;
+
+ case F_RESTART:
+ {
+ extern SmcConn smcConn;
+
+ XSync (dpy, 0);
+ Reborder (eventp->xbutton.time);
+ XSync (dpy, 0);
+ if (smcConn)
+ SmcCloseConnection (smcConn, 0, NULL);
+ execvp(*Argv, Argv);
+ fprintf (stderr, "%s: unable to restart: %s\n", ProgramName, *Argv);
+ break;
+ }
+
+ case F_UPICONMGR:
+ case F_DOWNICONMGR:
+ case F_LEFTICONMGR:
+ case F_RIGHTICONMGR:
+ case F_FORWICONMGR:
+ case F_BACKICONMGR:
+ MoveIconManager(func);
+ break;
+
+ case F_NEXTICONMGR:
+ case F_PREVICONMGR:
+ JumpIconManager(func);
+ break;
+
+ case F_SHOWLIST:
+ if (Scr->NoIconManagers)
+ break;
+ DeIconify(Scr->iconmgr.twm_win);
+ XRaiseWindow(dpy, Scr->iconmgr.twm_win->frame);
+ break;
+
+ case F_HIDELIST:
+ if (Scr->NoIconManagers)
+ break;
+ HideIconManager ();
+ break;
+
+ case F_SORTICONMGR:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ {
+ int save_sort;
+
+ save_sort = Scr->SortIconMgr;
+ Scr->SortIconMgr = TRUE;
+
+ if (context == C_ICONMGR)
+ SortIconManager((IconMgr *) NULL);
+ else if (tmp_win->iconmgr)
+ SortIconManager(tmp_win->iconmgrp);
+ else
+ Bell(XkbBI_Info,0,tmp_win->w);
+
+ Scr->SortIconMgr = save_sort;
+ }
+ break;
+
+ case F_IDENTIFY:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ Identify(tmp_win);
+ break;
+
+ case F_VERSION:
+ Identify ((TwmWindow *) NULL);
+ break;
+
+ case F_AUTORAISE:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ tmp_win->auto_raise = !tmp_win->auto_raise;
+ if (tmp_win->auto_raise) ++(Scr->NumAutoRaises);
+ else --(Scr->NumAutoRaises);
+ break;
+
+ case F_BEEP:
+ Bell(XkbBI_Info,0,None);
+ break;
+
+ case F_POPUP:
+ tmp_win = (TwmWindow *)action;
+ if (Scr->WindowFunction.func != 0)
+ {
+ ExecuteFunction(Scr->WindowFunction.func,
+ Scr->WindowFunction.item->action,
+ w, tmp_win, eventp, C_FRAME, FALSE);
+ }
+ else
+ {
+ DeIconify(tmp_win);
+ XRaiseWindow (dpy, tmp_win->frame);
+ }
+ break;
+
+ case F_RESIZE:
+ EventHandler[EnterNotify] = HandleUnknown;
+ EventHandler[LeaveNotify] = HandleUnknown;
+ if (DeferExecution(context, func, Scr->MoveCursor))
+ return TRUE;
+
+ PopDownMenu();
+
+ if (pulldown)
+ XWarpPointer(dpy, None, Scr->Root,
+ 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
+
+ if (w != tmp_win->icon_w) { /* can't resize icons */
+
+ if ((Context == C_FRAME || Context == C_WINDOW || Context == C_TITLE)
+ && fromMenu)
+ resizeFromCenter(w, tmp_win);
+ else {
+ /*
+ * see if this is being done from the titlebar
+ */
+ fromtitlebar =
+ belongs_to_twm_window (tmp_win, eventp->xbutton.window);
+
+ /* Save pointer position so we can tell if it was moved or
+ not during the resize. */
+ ResizeOrigX = eventp->xbutton.x_root;
+ ResizeOrigY = eventp->xbutton.y_root;
+
+ StartResize (eventp, tmp_win, fromtitlebar);
+
+ do {
+ XMaskEvent(dpy,
+ ButtonPressMask | ButtonReleaseMask |
+ EnterWindowMask | LeaveWindowMask |
+ ButtonMotionMask, &Event);
+
+ if (fromtitlebar && Event.type == ButtonPress) {
+ fromtitlebar = False;
+ continue;
+ }
+
+ if (Event.type == MotionNotify) {
+ /* discard any extra motion events before a release */
+ while
+ (XCheckMaskEvent
+ (dpy, ButtonMotionMask | ButtonReleaseMask, &Event))
+ if (Event.type == ButtonRelease)
+ break;
+ }
+
+ if (!DispatchEvent ()) continue;
+
+ } while (!(Event.type == ButtonRelease || Cancel));
+ return TRUE;
+ }
+ }
+ break;
+
+
+ case F_ZOOM:
+ case F_HORIZOOM:
+ case F_FULLZOOM:
+ case F_LEFTZOOM:
+ case F_RIGHTZOOM:
+ case F_TOPZOOM:
+ case F_BOTTOMZOOM:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+ fullzoom(tmp_win, func);
+ break;
+
+ case F_MOVE:
+ case F_FORCEMOVE:
+ if (DeferExecution(context, func, Scr->MoveCursor))
+ return TRUE;
+
+ PopDownMenu();
+ rootw = eventp->xbutton.root;
+ MoveFunction = func;
+
+ if (pulldown)
+ XWarpPointer(dpy, None, Scr->Root,
+ 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
+
+ EventHandler[EnterNotify] = HandleUnknown;
+ EventHandler[LeaveNotify] = HandleUnknown;
+
+ if (!Scr->NoGrabServer || !Scr->OpaqueMove) {
+ XGrabServer(dpy);
+ }
+ XGrabPointer(dpy, eventp->xbutton.root, True,
+ ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask | PointerMotionMask, /* PointerMotionHintMask */
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, Scr->MoveCursor, CurrentTime);
+
+ if (context == C_ICON && tmp_win->icon_w)
+ {
+ w = tmp_win->icon_w;
+ DragX = eventp->xbutton.x;
+ DragY = eventp->xbutton.y;
+ moving_icon = TRUE;
+ }
+
+ else if (w != tmp_win->icon_w)
+ {
+ XTranslateCoordinates(dpy, w, tmp_win->frame,
+ eventp->xbutton.x,
+ eventp->xbutton.y,
+ &DragX, &DragY, &JunkChild);
+
+ w = tmp_win->frame;
+ }
+
+ DragWindow = None;
+
+ XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
+ (unsigned int *)&DragWidth, (unsigned int *)&DragHeight, &JunkBW,
+ &JunkDepth);
+
+ origX = eventp->xbutton.x_root;
+ origY = eventp->xbutton.y_root;
+ CurrentDragX = origDragX;
+ CurrentDragY = origDragY;
+
+ /*
+ * only do the constrained move if timer is set; need to check it
+ * in case of stupid or wicked fast servers
+ */
+ if (ConstrainedMoveTime &&
+ (eventp->xbutton.time - last_time) < ConstrainedMoveTime)
+ {
+ int width, height;
+
+ ConstMove = TRUE;
+ ConstMoveDir = MOVE_NONE;
+ ConstMoveX = eventp->xbutton.x_root - DragX - JunkBW;
+ ConstMoveY = eventp->xbutton.y_root - DragY - JunkBW;
+ width = DragWidth + 2 * JunkBW;
+ height = DragHeight + 2 * JunkBW;
+ ConstMoveXL = ConstMoveX + width/3;
+ ConstMoveXR = ConstMoveX + 2*(width/3);
+ ConstMoveYT = ConstMoveY + height/3;
+ ConstMoveYB = ConstMoveY + 2*(height/3);
+
+ XWarpPointer(dpy, None, w,
+ 0, 0, 0, 0, DragWidth/2, DragHeight/2);
+
+ XQueryPointer(dpy, w, &JunkRoot, &JunkChild,
+ &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
+ }
+ last_time = eventp->xbutton.time;
+
+ if (!Scr->OpaqueMove)
+ {
+ InstallRootColormap();
+ if (!Scr->MoveDelta)
+ {
+ /*
+ * Draw initial outline. This was previously done the
+ * first time though the outer loop by dropping out of
+ * the XCheckMaskEvent inner loop down to one of the
+ * MoveOutline's below.
+ */
+ MoveOutline(rootw,
+ origDragX - JunkBW, origDragY - JunkBW,
+ DragWidth + 2 * JunkBW, DragHeight + 2 * JunkBW,
+ tmp_win->frame_bw,
+ moving_icon ? 0 : tmp_win->title_height);
+ /*
+ * This next line causes HandleReleaseNotify to call
+ * XRaiseWindow(). This is solely to preserve the
+ * previous behaviour that raises a window being moved
+ * on button release even if you never actually moved
+ * any distance (unless you move less than MoveDelta or
+ * NoRaiseMove is set or OpaqueMove is set).
+ */
+ DragWindow = w;
+ }
+ }
+
+ /*
+ * see if this is being done from the titlebar
+ */
+ fromtitlebar = belongs_to_twm_window (tmp_win, eventp->xbutton.window);
+
+ if (menuFromFrameOrWindowOrTitlebar) {
+ /* warp the pointer to the middle of the window */
+ XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
+ origDragX + DragWidth / 2,
+ origDragY + DragHeight / 2);
+ XFlush(dpy);
+ }
+
+ while (TRUE)
+ {
+ long releaseEvent = menuFromFrameOrWindowOrTitlebar ?
+ ButtonPress : ButtonRelease;
+ long movementMask = menuFromFrameOrWindowOrTitlebar ?
+ PointerMotionMask : ButtonMotionMask;
+
+ /* block until there is an interesting event */
+ XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
+ EnterWindowMask | LeaveWindowMask |
+ ExposureMask | movementMask |
+ VisibilityChangeMask, &Event);
+
+ /* throw away enter and leave events until release */
+ if (Event.xany.type == EnterNotify ||
+ Event.xany.type == LeaveNotify) continue;
+
+ if (Event.type == MotionNotify) {
+ /* discard any extra motion events before a logical release */
+ while(XCheckMaskEvent(dpy,
+ movementMask | releaseEvent, &Event))
+ if (Event.type == releaseEvent)
+ break;
+ }
+
+ /* test to see if we have a second button press to abort move */
+ if (!menuFromFrameOrWindowOrTitlebar && !MovedFromKeyPress) {
+ if (Event.type == ButtonPress && DragWindow != None) {
+ if (Scr->OpaqueMove)
+ XMoveWindow (dpy, DragWindow, origDragX, origDragY);
+ else
+ MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+ DragWindow = None;
+ }
+ }
+ if (fromtitlebar && Event.type == ButtonPress) {
+ fromtitlebar = False;
+ CurrentDragX = origX = Event.xbutton.x_root;
+ CurrentDragY = origY = Event.xbutton.y_root;
+ XTranslateCoordinates (dpy, rootw, tmp_win->frame,
+ origX, origY,
+ &DragX, &DragY, &JunkChild);
+ continue;
+ }
+
+ if (!DispatchEvent2 ()) continue;
+
+ if (Cancel)
+ {
+ WindowMoved = FALSE;
+ if (!Scr->OpaqueMove)
+ UninstallRootColormap();
+ return TRUE; /* XXX should this be FALSE? */
+ }
+ if (Event.type == releaseEvent)
+ {
+ MoveOutline(rootw, 0, 0, 0, 0, 0, 0);
+ if (moving_icon &&
+ ((CurrentDragX != origDragX ||
+ CurrentDragY != origDragY)))
+ tmp_win->icon_moved = TRUE;
+ if (!Scr->OpaqueMove && menuFromFrameOrWindowOrTitlebar)
+ XMoveWindow(dpy, DragWindow,
+ Event.xbutton.x_root - DragWidth / 2,
+ Event.xbutton.y_root - DragHeight / 2);
+ break;
+ }
+
+ /* something left to do only if the pointer moved */
+ if (Event.type != MotionNotify)
+ continue;
+
+ XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &JunkChild,
+ &(eventp->xmotion.x_root), &(eventp->xmotion.y_root),
+ &JunkX, &JunkY, &JunkMask);
+
+ if (DragWindow == None &&
+ abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta &&
+ abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta)
+ continue;
+
+ WindowMoved = TRUE;
+ DragWindow = w;
+
+ if (!Scr->NoRaiseMove && Scr->OpaqueMove) /* can't restore... */
+ XRaiseWindow(dpy, DragWindow);
+
+ if (ConstMove)
+ {
+ switch (ConstMoveDir)
+ {
+ case MOVE_NONE:
+ if (eventp->xmotion.x_root < ConstMoveXL ||
+ eventp->xmotion.x_root > ConstMoveXR)
+ ConstMoveDir = MOVE_HORIZ;
+
+ if (eventp->xmotion.y_root < ConstMoveYT ||
+ eventp->xmotion.y_root > ConstMoveYB)
+ ConstMoveDir = MOVE_VERT;
+
+ XQueryPointer(dpy, DragWindow, &JunkRoot, &JunkChild,
+ &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
+ break;
+
+ case MOVE_VERT:
+ ConstMoveY = eventp->xmotion.y_root - DragY - JunkBW;
+ break;
+
+ case MOVE_HORIZ:
+ ConstMoveX= eventp->xmotion.x_root - DragX - JunkBW;
+ break;
+ }
+
+ if (ConstMoveDir != MOVE_NONE)
+ {
+ int xl, yt, xr, yb, w, h;
+
+ xl = ConstMoveX;
+ yt = ConstMoveY;
+ w = DragWidth + 2 * JunkBW;
+ h = DragHeight + 2 * JunkBW;
+
+ if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
+ {
+ xr = xl + w;
+ yb = yt + h;
+
+ if (xl < 0)
+ xl = 0;
+ if (xr > Scr->MyDisplayWidth)
+ xl = Scr->MyDisplayWidth - w;
+
+ if (yt < 0)
+ yt = 0;
+ if (yb > Scr->MyDisplayHeight)
+ yt = Scr->MyDisplayHeight - h;
+ }
+ CurrentDragX = xl;
+ CurrentDragY = yt;
+ if (Scr->OpaqueMove)
+ XMoveWindow(dpy, DragWindow, xl, yt);
+ else
+ MoveOutline(eventp->xmotion.root, xl, yt, w, h,
+ tmp_win->frame_bw,
+ moving_icon ? 0 : tmp_win->title_height);
+ }
+ }
+ else if (DragWindow != None)
+ {
+ int xl, yt, xr, yb, w, h;
+ if (!menuFromFrameOrWindowOrTitlebar) {
+ xl = eventp->xmotion.x_root - DragX - JunkBW;
+ yt = eventp->xmotion.y_root - DragY - JunkBW;
+ }
+ else {
+ xl = eventp->xmotion.x_root - (DragWidth / 2);
+ yt = eventp->xmotion.y_root - (DragHeight / 2);
+ }
+ w = DragWidth + 2 * JunkBW;
+ h = DragHeight + 2 * JunkBW;
+
+ if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
+ {
+ xr = xl + w;
+ yb = yt + h;
+
+ if (xl < 0)
+ xl = 0;
+ if (xr > Scr->MyDisplayWidth)
+ xl = Scr->MyDisplayWidth - w;
+
+ if (yt < 0)
+ yt = 0;
+ if (yb > Scr->MyDisplayHeight)
+ yt = Scr->MyDisplayHeight - h;
+ }
+
+ CurrentDragX = xl;
+ CurrentDragY = yt;
+ if (Scr->OpaqueMove)
+ XMoveWindow(dpy, DragWindow, xl, yt);
+ else
+ MoveOutline(eventp->xmotion.root, xl, yt, w, h,
+ tmp_win->frame_bw,
+ moving_icon ? 0 : tmp_win->title_height);
+ }
+
+ }
+ MovedFromKeyPress = False;
+
+
+ if (!Scr->OpaqueMove && DragWindow == None)
+ UninstallRootColormap();
+
+ break;
+
+ case F_FUNCTION:
+ {
+ MenuRoot *mroot;
+ MenuItem *mitem;
+
+ if ((mroot = FindMenuRoot(action)) == NULL)
+ {
+ fprintf (stderr, "%s: couldn't find function \"%s\"\n",
+ ProgramName, action);
+ return TRUE;
+ }
+
+ if (NeedToDefer(mroot) && DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+ else
+ {
+ for (mitem = mroot->first; mitem != NULL; mitem = mitem->next)
+ {
+ if (!ExecuteFunction (mitem->func, mitem->action, w,
+ tmp_win, eventp, context, pulldown))
+ break;
+ }
+ }
+ }
+ break;
+
+ case F_DEICONIFY:
+ case F_ICONIFY:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ if (tmp_win->icon)
+ {
+ DeIconify(tmp_win);
+ }
+ else if (func == F_ICONIFY)
+ {
+ Iconify (tmp_win, eventp->xbutton.x_root - 5,
+ eventp->xbutton.y_root - 5);
+ }
+ break;
+
+ case F_RAISELOWER:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ if (!WindowMoved) {
+ XWindowChanges xwc;
+
+ xwc.stack_mode = Opposite;
+ if (w != tmp_win->icon_w)
+ w = tmp_win->frame;
+ XConfigureWindow (dpy, w, CWStackMode, &xwc);
+ }
+ break;
+
+ case F_RAISE:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ /* check to make sure raise is not from the WindowFunction */
+ if (w == tmp_win->icon_w && Context != C_ROOT)
+ XRaiseWindow(dpy, tmp_win->icon_w);
+ else
+ XRaiseWindow(dpy, tmp_win->frame);
+
+ break;
+
+ case F_LOWER:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ if (w == tmp_win->icon_w)
+ XLowerWindow(dpy, tmp_win->icon_w);
+ else
+ XLowerWindow(dpy, tmp_win->frame);
+
+ break;
+
+ case F_FOCUS:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ if (tmp_win->icon == FALSE)
+ {
+ if (!Scr->FocusRoot && Scr->Focus == tmp_win)
+ {
+ FocusOnRoot();
+ }
+ else
+ {
+ if (Scr->Focus != NULL) {
+ SetBorder (Scr->Focus, False);
+ if (Scr->Focus->hilite_w)
+ XUnmapWindow (dpy, Scr->Focus->hilite_w);
+ }
+
+ InstallWindowColormaps (0, tmp_win);
+ if (tmp_win->hilite_w) XMapWindow (dpy, tmp_win->hilite_w);
+ SetBorder (tmp_win, True);
+ SetFocus (tmp_win, eventp->xbutton.time);
+ Scr->FocusRoot = FALSE;
+ Scr->Focus = tmp_win;
+ }
+ }
+ break;
+
+ case F_DESTROY:
+ if (DeferExecution(context, func, Scr->DestroyCursor))
+ return TRUE;
+
+ if (tmp_win->iconmgr)
+ Bell(XkbBI_MinorError,0,tmp_win->w);
+ else
+ XKillClient(dpy, tmp_win->w);
+ break;
+
+ case F_DELETE:
+ if (DeferExecution(context, func, Scr->DestroyCursor))
+ return TRUE;
+
+ if (tmp_win->iconmgr) /* don't send ourself a message */
+ HideIconManager ();
+ else if (tmp_win->protocols & DoesWmDeleteWindow)
+ SendDeleteWindowMessage (tmp_win, LastTimestamp());
+ else
+ Bell(XkbBI_MinorError,0,tmp_win->w);
+ break;
+
+ case F_SAVEYOURSELF:
+ if (DeferExecution (context, func, Scr->SelectCursor))
+ return TRUE;
+
+ if (tmp_win->protocols & DoesWmSaveYourself)
+ SendSaveYourselfMessage (tmp_win, LastTimestamp());
+ else
+ Bell(XkbBI_MinorError,0,tmp_win->w);
+ break;
+
+ case F_CIRCLEUP:
+ XCirculateSubwindowsUp(dpy, Scr->Root);
+ break;
+
+ case F_CIRCLEDOWN:
+ XCirculateSubwindowsDown(dpy, Scr->Root);
+ break;
+
+ case F_EXEC:
+ PopDownMenu();
+ if (!Scr->NoGrabServer) {
+ XUngrabServer (dpy);
+ XSync (dpy, 0);
+ }
+ Execute(action);
+ break;
+
+ case F_UNFOCUS:
+ FocusOnRoot();
+ break;
+
+ case F_CUT:
+ strcpy(tmp, action);
+ strcat(tmp, "\n");
+ XStoreBytes(dpy, tmp, strlen(tmp));
+ break;
+
+ case F_CUTFILE:
+ ptr = XFetchBytes(dpy, &count);
+ if (ptr) {
+ if (sscanf (ptr, "%s", tmp) == 1) {
+ XFree (ptr);
+ ptr = ExpandFilename(tmp);
+ if (ptr) {
+ fd = open (ptr, 0);
+ if (fd >= 0) {
+ count = read (fd, buff, MAX_FILE_SIZE - 1);
+ if (count > 0) XStoreBytes (dpy, buff, count);
+ close(fd);
+ } else {
+ fprintf (stderr,
+ "%s: unable to open cut file \"%s\"\n",
+ ProgramName, tmp);
+ }
+ if (ptr != tmp) free (ptr);
+ }
+ } else {
+ XFree(ptr);
+ }
+ } else {
+ fprintf(stderr, "%s: cut buffer is empty\n", ProgramName);
+ }
+ break;
+
+ case F_WARPTOSCREEN:
+ {
+ if (strcmp (action, WARPSCREEN_NEXT) == 0) {
+ WarpToScreen (Scr->screen + 1, 1);
+ } else if (strcmp (action, WARPSCREEN_PREV) == 0) {
+ WarpToScreen (Scr->screen - 1, -1);
+ } else if (strcmp (action, WARPSCREEN_BACK) == 0) {
+ WarpToScreen (PreviousScreen, 0);
+ } else {
+ WarpToScreen (atoi (action), 0);
+ }
+ }
+ break;
+
+ case F_COLORMAP:
+ {
+ if (strcmp (action, COLORMAP_NEXT) == 0) {
+ BumpWindowColormap (tmp_win, 1);
+ } else if (strcmp (action, COLORMAP_PREV) == 0) {
+ BumpWindowColormap (tmp_win, -1);
+ } else {
+ BumpWindowColormap (tmp_win, 0);
+ }
+ }
+ break;
+
+ case F_WARPTO:
+ {
+ register TwmWindow *t;
+ int len;
+
+ len = strlen(action);
+
+ for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
+ if (!strncmp(action, t->name, len))
+ if (WarpThere(t)) break;
+ }
+ if (!t) {
+ for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
+ if (!strncmp(action, t->class.res_name, len))
+ if (WarpThere(t)) break;
+ }
+ if (!t) {
+ for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
+ if (!strncmp(action, t->class.res_class, len))
+ if (WarpThere(t)) break;
+ }
+ }
+ }
+
+ if (!t)
+ Bell(XkbBI_MinorError,0,None);
+ }
+ break;
+
+ case F_WARPTOICONMGR:
+ {
+ TwmWindow *t;
+ int len;
+ Window raisewin = None, iconwin = None;
+
+ len = strlen(action);
+ if (len == 0) {
+ if (tmp_win && tmp_win->list) {
+ raisewin = tmp_win->list->iconmgr->twm_win->frame;
+ iconwin = tmp_win->list->icon;
+ } else if (Scr->iconmgr.active) {
+ raisewin = Scr->iconmgr.twm_win->frame;
+ iconwin = Scr->iconmgr.active->w;
+ }
+ } else {
+ for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
+ if (strncmp (action, t->icon_name, len) == 0) {
+ if (t->list && t->list->iconmgr->twm_win->mapped) {
+ raisewin = t->list->iconmgr->twm_win->frame;
+ iconwin = t->list->icon;
+ break;
+ }
+ }
+ }
+ }
+
+ if (raisewin) {
+ XRaiseWindow (dpy, raisewin);
+ XWarpPointer (dpy, None, iconwin, 0,0,0,0, 5, 5);
+ } else {
+ Bell(XkbBI_MinorError,0,None);
+ }
+ }
+ break;
+
+ case F_WARPRING:
+ switch (action[0]) {
+ case 'n':
+ WarpAlongRing (&eventp->xbutton, True);
+ break;
+ case 'p':
+ WarpAlongRing (&eventp->xbutton, False);
+ break;
+ default:
+ Bell(XkbBI_MinorError,0,None);
+ break;
+ }
+ break;
+
+ case F_FILE:
+ action = ExpandFilename(action);
+ fd = open(action, 0);
+ if (fd >= 0)
+ {
+ count = read(fd, buff, MAX_FILE_SIZE - 1);
+ if (count > 0)
+ XStoreBytes(dpy, buff, count);
+
+ close(fd);
+ }
+ else
+ {
+ fprintf (stderr, "%s: unable to open file \"%s\"\n",
+ ProgramName, action);
+ }
+ break;
+
+ case F_REFRESH:
+ {
+ XSetWindowAttributes attributes;
+ unsigned long valuemask;
+
+ valuemask = (CWBackPixel | CWBackingStore | CWSaveUnder);
+ attributes.background_pixel = Scr->Black;
+ attributes.backing_store = NotUseful;
+ attributes.save_under = False;
+ w = XCreateWindow (dpy, Scr->Root, 0, 0,
+ (unsigned int) Scr->MyDisplayWidth,
+ (unsigned int) Scr->MyDisplayHeight,
+ (unsigned int) 0,
+ CopyFromParent, (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent, valuemask,
+ &attributes);
+ XMapWindow (dpy, w);
+ XDestroyWindow (dpy, w);
+ XFlush (dpy);
+ }
+ break;
+
+ case F_WINREFRESH:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ if (context == C_ICON && tmp_win->icon_w)
+ w = XCreateSimpleWindow(dpy, tmp_win->icon_w,
+ 0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
+ else
+ w = XCreateSimpleWindow(dpy, tmp_win->frame,
+ 0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
+
+ XMapWindow(dpy, w);
+ XDestroyWindow(dpy, w);
+ XFlush(dpy);
+ break;
+
+ case F_QUIT:
+ Done();
+ break;
+
+ case F_PRIORITY:
+ if (HasSync)
+ {
+ if (DeferExecution (context, func, Scr->SelectCursor))
+ return TRUE;
+ (void)XSyncSetPriority(dpy, tmp_win->w, atoi(action));
+ }
+ break;
+ }
+
+ if (ButtonPressed == -1) XUngrabPointer(dpy, CurrentTime);
+ return do_next_action;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * DeferExecution - defer the execution of a function to the
+ * next button press if the context is C_ROOT
+ *
+ * Inputs:
+ * context - the context in which the mouse button was pressed
+ * func - the function to defer
+ * cursor - the cursor to display while waiting
+ *
+ ***********************************************************************
+ */
+
+int
+DeferExecution(context, func, cursor)
+int context, func;
+Cursor cursor;
+{
+ if (context == C_ROOT)
+ {
+ LastCursor = cursor;
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, cursor, CurrentTime);
+
+ RootFunction = func;
+
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * ReGrab - regrab the pointer with the LastCursor;
+ *
+ ***********************************************************************
+ */
+
+ReGrab()
+{
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, LastCursor, CurrentTime);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * NeedToDefer - checks each function in the list to see if it
+ * is one that needs to be defered.
+ *
+ * Inputs:
+ * root - the menu root to check
+ *
+ ***********************************************************************
+ */
+
+NeedToDefer(root)
+MenuRoot *root;
+{
+ MenuItem *mitem;
+
+ for (mitem = root->first; mitem != NULL; mitem = mitem->next)
+ {
+ switch (mitem->func)
+ {
+ case F_IDENTIFY:
+ case F_RESIZE:
+ case F_MOVE:
+ case F_FORCEMOVE:
+ case F_DEICONIFY:
+ case F_ICONIFY:
+ case F_RAISELOWER:
+ case F_RAISE:
+ case F_LOWER:
+ case F_FOCUS:
+ case F_DESTROY:
+ case F_WINREFRESH:
+ case F_ZOOM:
+ case F_FULLZOOM:
+ case F_HORIZOOM:
+ case F_RIGHTZOOM:
+ case F_LEFTZOOM:
+ case F_TOPZOOM:
+ case F_BOTTOMZOOM:
+ case F_AUTORAISE:
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * Execute - execute the string by /bin/sh
+ *
+ * Inputs:
+ * s - the string containing the command
+ *
+ ***********************************************************************
+ */
+
+#if defined(sun) && defined(SVR4)
+static int System (s)
+ char *s;
+{
+ int pid, status;
+ if ((pid = fork ()) == 0) {
+ (void) setpgrp();
+ execl ("/bin/sh", "sh", "-c", s, 0);
+ } else
+ waitpid (pid, &status, 0);
+ return status;
+}
+#define system(s) System(s)
+#endif
+
+void
+Execute(s)
+ char *s;
+{
+ static char buf[256];
+ char *ds = DisplayString (dpy);
+ char *colon, *dot1;
+ char oldDisplay[256];
+ char *doisplay;
+ int restorevar = 0;
+
+ oldDisplay[0] = '\0';
+ doisplay=getenv("DISPLAY");
+ if (doisplay)
+ strcpy (oldDisplay, doisplay);
+
+ /*
+ * Build a display string using the current screen number, so that
+ * X programs which get fired up from a menu come up on the screen
+ * that they were invoked from, unless specifically overridden on
+ * their command line.
+ */
+ colon = strrchr (ds, ':');
+ if (colon) { /* if host[:]:dpy */
+ strcpy (buf, "DISPLAY=");
+ strcat (buf, ds);
+ colon = buf + 8 + (colon - ds); /* use version in buf */
+ dot1 = strchr (colon, '.'); /* first period after colon */
+ if (!dot1) dot1 = colon + strlen (colon); /* if not there, append */
+ (void) sprintf (dot1, ".%d", Scr->screen);
+ putenv (buf);
+ restorevar = 1;
+ }
+
+ (void) system (s);
+
+ if (restorevar) { /* why bother? */
+ (void) sprintf (buf, "DISPLAY=%s", oldDisplay);
+ putenv (buf);
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * FocusOnRoot - put input focus on the root window
+ *
+ ***********************************************************************
+ */
+
+void
+FocusOnRoot()
+{
+ SetFocus ((TwmWindow *) NULL, LastTimestamp());
+ if (Scr->Focus != NULL)
+ {
+ SetBorder (Scr->Focus, False);
+ if (Scr->Focus->hilite_w) XUnmapWindow (dpy, Scr->Focus->hilite_w);
+ }
+ InstallWindowColormaps(0, &Scr->TwmRoot);
+ Scr->Focus = NULL;
+ Scr->FocusRoot = TRUE;
+}
+
+DeIconify(tmp_win)
+TwmWindow *tmp_win;
+{
+ TwmWindow *t;
+
+ /* de-iconify the main window */
+ if (tmp_win->icon)
+ {
+ if (tmp_win->icon_on)
+ Zoom(tmp_win->icon_w, tmp_win->frame);
+ else if (tmp_win->group != (Window) 0)
+ {
+ for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
+ {
+ if (tmp_win->group == t->w && t->icon_on)
+ {
+ Zoom(t->icon_w, tmp_win->frame);
+ break;
+ }
+ }
+ }
+ }
+
+ XMapWindow(dpy, tmp_win->w);
+ tmp_win->mapped = TRUE;
+ if (Scr->NoRaiseDeicon)
+ XMapWindow(dpy, tmp_win->frame);
+ else
+ XMapRaised(dpy, tmp_win->frame);
+ SetMapStateProp(tmp_win, NormalState);
+
+ if (tmp_win->icon_w) {
+ XUnmapWindow(dpy, tmp_win->icon_w);
+ IconDown (tmp_win);
+ }
+ if (tmp_win->list)
+ XUnmapWindow(dpy, tmp_win->list->icon);
+ if ((Scr->WarpCursor ||
+ LookInList(Scr->WarpCursorL, tmp_win->full_name, &tmp_win->class)) &&
+ tmp_win->icon)
+ WarpToWindow (tmp_win);
+ tmp_win->icon = FALSE;
+ tmp_win->icon_on = FALSE;
+
+
+ /* now de-iconify transients */
+ for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
+ {
+ if (t->transient && t->transientfor == tmp_win->w)
+ {
+ if (t->icon_on)
+ Zoom(t->icon_w, t->frame);
+ else
+ Zoom(tmp_win->icon_w, t->frame);
+
+ XMapWindow(dpy, t->w);
+ t->mapped = TRUE;
+ if (Scr->NoRaiseDeicon)
+ XMapWindow(dpy, t->frame);
+ else
+ XMapRaised(dpy, t->frame);
+ SetMapStateProp(t, NormalState);
+
+ if (t->icon_w) {
+ XUnmapWindow(dpy, t->icon_w);
+ IconDown (t);
+ }
+ if (t->list) XUnmapWindow(dpy, t->list->icon);
+ t->icon = FALSE;
+ t->icon_on = FALSE;
+ }
+ }
+
+ XSync (dpy, 0);
+}
+
+
+
+Iconify(tmp_win, def_x, def_y)
+TwmWindow *tmp_win;
+int def_x, def_y;
+{
+ TwmWindow *t;
+ int iconify;
+ XWindowAttributes winattrs;
+ unsigned long eventMask;
+
+ iconify = ((!tmp_win->iconify_by_unmapping) || tmp_win->transient);
+ if (iconify)
+ {
+ if (tmp_win->icon_w == (Window) 0)
+ CreateIconWindow(tmp_win, def_x, def_y);
+ else
+ IconUp(tmp_win);
+ XMapRaised(dpy, tmp_win->icon_w);
+ }
+ if (tmp_win->list)
+ XMapWindow(dpy, tmp_win->list->icon);
+
+ XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
+ eventMask = winattrs.your_event_mask;
+
+ /* iconify transients first */
+ for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
+ {
+ if (t->transient && t->transientfor == tmp_win->w)
+ {
+ if (iconify)
+ {
+ if (t->icon_on)
+ Zoom(t->icon_w, tmp_win->icon_w);
+ else
+ Zoom(t->frame, tmp_win->icon_w);
+ }
+
+ /*
+ * Prevent the receipt of an UnmapNotify, since that would
+ * cause a transition to the Withdrawn state.
+ */
+ t->mapped = FALSE;
+ XSelectInput(dpy, t->w, eventMask & ~StructureNotifyMask);
+ XUnmapWindow(dpy, t->w);
+ XSelectInput(dpy, t->w, eventMask);
+ XUnmapWindow(dpy, t->frame);
+ if (t->icon_w)
+ XUnmapWindow(dpy, t->icon_w);
+ SetMapStateProp(t, IconicState);
+ SetBorder (t, False);
+ if (t == Scr->Focus)
+ {
+ SetFocus ((TwmWindow *) NULL, LastTimestamp());
+ Scr->Focus = NULL;
+ Scr->FocusRoot = TRUE;
+ }
+ if (t->list) XMapWindow(dpy, t->list->icon);
+ t->icon = TRUE;
+ t->icon_on = FALSE;
+ }
+ }
+
+ if (iconify)
+ Zoom(tmp_win->frame, tmp_win->icon_w);
+
+ /*
+ * Prevent the receipt of an UnmapNotify, since that would
+ * cause a transition to the Withdrawn state.
+ */
+ tmp_win->mapped = FALSE;
+ XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
+ XUnmapWindow(dpy, tmp_win->w);
+ XSelectInput(dpy, tmp_win->w, eventMask);
+ XUnmapWindow(dpy, tmp_win->frame);
+ SetMapStateProp(tmp_win, IconicState);
+
+ SetBorder (tmp_win, False);
+ if (tmp_win == Scr->Focus)
+ {
+ SetFocus ((TwmWindow *) NULL, LastTimestamp());
+ Scr->Focus = NULL;
+ Scr->FocusRoot = TRUE;
+ }
+ tmp_win->icon = TRUE;
+ if (iconify)
+ tmp_win->icon_on = TRUE;
+ else
+ tmp_win->icon_on = FALSE;
+ XSync (dpy, 0);
+}
+
+
+
+static void Identify (t)
+TwmWindow *t;
+{
+ int i, n, twidth, width, height;
+ int x, y;
+ unsigned int wwidth, wheight, bw, depth;
+ Window junk;
+ int px, py, dummy;
+ unsigned udummy;
+
+ n = 0;
+ (void) sprintf(Info[n++], "Twm version: %s", Version);
+ Info[n++][0] = '\0';
+
+ if (t) {
+ XGetGeometry (dpy, t->w, &JunkRoot, &JunkX, &JunkY,
+ &wwidth, &wheight, &bw, &depth);
+ (void) XTranslateCoordinates (dpy, t->w, Scr->Root, 0, 0,
+ &x, &y, &junk);
+ (void) sprintf(Info[n++], "Name = \"%s\"", t->full_name);
+ (void) sprintf(Info[n++], "Class.res_name = \"%s\"", t->class.res_name);
+ (void) sprintf(Info[n++], "Class.res_class = \"%s\"", t->class.res_class);
+ Info[n++][0] = '\0';
+ (void) sprintf(Info[n++], "Geometry/root = %dx%d+%d+%d", wwidth, wheight,
+ x, y);
+ (void) sprintf(Info[n++], "Border width = %d", bw);
+ (void) sprintf(Info[n++], "Depth = %d", depth);
+ if (HasSync)
+ {
+ int priority;
+ (void)XSyncGetPriority(dpy, t->w, &priority);
+ (void) sprintf(Info[n++], "Priority = %d", priority);
+ }
+ }
+
+ Info[n++][0] = '\0';
+ (void) sprintf(Info[n++], "Click to dismiss....");
+
+ /* figure out the width and height of the info window */
+ height = n * (Scr->DefaultFont.height+2);
+ width = 1;
+ for (i = 0; i < n; i++)
+ {
+ twidth = XTextWidth(Scr->DefaultFont.font, Info[i],
+ strlen(Info[i]));
+ if (twidth > width)
+ width = twidth;
+ }
+ if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);
+
+ width += 10; /* some padding */
+ if (XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild, &px, &py,
+ &dummy, &dummy, &udummy)) {
+ px -= (width / 2);
+ py -= (height / 3);
+ if (px + width + BW2 >= Scr->MyDisplayWidth)
+ px = Scr->MyDisplayWidth - width - BW2;
+ if (py + height + BW2 >= Scr->MyDisplayHeight)
+ py = Scr->MyDisplayHeight - height - BW2;
+ if (px < 0) px = 0;
+ if (py < 0) py = 0;
+ } else {
+ px = py = 0;
+ }
+ XMoveResizeWindow(dpy, Scr->InfoWindow, px, py, width, height);
+ XMapRaised(dpy, Scr->InfoWindow);
+ InfoLines = n;
+}
+
+
+
+SetMapStateProp(tmp_win, state)
+TwmWindow *tmp_win;
+int state;
+{
+ unsigned long data[2]; /* "suggested" by ICCCM version 1 */
+
+ data[0] = (unsigned long) state;
+ data[1] = (unsigned long) (tmp_win->iconify_by_unmapping ? None :
+ tmp_win->icon_w);
+
+ XChangeProperty (dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32,
+ PropModeReplace, (unsigned char *) data, 2);
+}
+
+
+
+Bool GetWMState (w, statep, iwp)
+ Window w;
+ int *statep;
+ Window *iwp;
+{
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems, bytesafter;
+ unsigned long *datap = NULL;
+ Bool retval = False;
+
+ if (XGetWindowProperty (dpy, w, _XA_WM_STATE, 0L, 2L, False, _XA_WM_STATE,
+ &actual_type, &actual_format, &nitems, &bytesafter,
+ (unsigned char **) &datap) != Success || !datap)
+ return False;
+
+ if (nitems <= 2) { /* "suggested" by ICCCM version 1 */
+ *statep = (int) datap[0];
+ *iwp = (Window) datap[1];
+ retval = True;
+ }
+
+ XFree ((char *) datap);
+ return retval;
+}
+
+
+
+WarpToScreen (n, inc)
+ int n, inc;
+{
+ Window dumwin;
+ int x, y, dumint;
+ unsigned int dummask;
+ ScreenInfo *newscr = NULL;
+
+ while (!newscr) {
+ /* wrap around */
+ if (n < 0)
+ n = NumScreens - 1;
+ else if (n >= NumScreens)
+ n = 0;
+
+ newscr = ScreenList[n];
+ if (!newscr) { /* make sure screen is managed */
+ if (inc) { /* walk around the list */
+ n += inc;
+ continue;
+ }
+ fprintf (stderr, "%s: unable to warp to unmanaged screen %d\n",
+ ProgramName, n);
+ Bell(XkbBI_MinorError,0,None);
+ return;
+ }
+ }
+
+ if (Scr->screen == n) return; /* already on that screen */
+
+ PreviousScreen = Scr->screen;
+ XQueryPointer (dpy, Scr->Root, &dumwin, &dumwin, &x, &y,
+ &dumint, &dumint, &dummask);
+
+ XWarpPointer (dpy, None, newscr->Root, 0, 0, 0, 0, x, y);
+ return;
+}
+
+
+
+
+/*
+ * BumpWindowColormap - rotate our internal copy of WM_COLORMAP_WINDOWS
+ */
+
+BumpWindowColormap (tmp, inc)
+ TwmWindow *tmp;
+ int inc;
+{
+ int i, j, previously_installed;
+ ColormapWindow **cwins;
+
+ if (!tmp) return;
+
+ if (inc && tmp->cmaps.number_cwins > 0) {
+ cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *)*
+ tmp->cmaps.number_cwins);
+ if (cwins) {
+ if ((previously_installed =
+ /* SUPPRESS 560 */(Scr->cmapInfo.cmaps == &tmp->cmaps &&
+ tmp->cmaps.number_cwins))) {
+ for (i = tmp->cmaps.number_cwins; i-- > 0; )
+ tmp->cmaps.cwins[i]->colormap->state = 0;
+ }
+
+ for (i = 0; i < tmp->cmaps.number_cwins; i++) {
+ j = i - inc;
+ if (j >= tmp->cmaps.number_cwins)
+ j -= tmp->cmaps.number_cwins;
+ else if (j < 0)
+ j += tmp->cmaps.number_cwins;
+ cwins[j] = tmp->cmaps.cwins[i];
+ }
+
+ free((char *) tmp->cmaps.cwins);
+
+ tmp->cmaps.cwins = cwins;
+
+ if (tmp->cmaps.number_cwins > 1)
+ bzero (tmp->cmaps.scoreboard,
+ ColormapsScoreboardLength(&tmp->cmaps));
+
+ if (previously_installed)
+ InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL);
+ }
+ } else
+ FetchWmColormapWindows (tmp);
+}
+
+
+
+HideIconManager ()
+{
+ SetMapStateProp (Scr->iconmgr.twm_win, WithdrawnState);
+ XUnmapWindow(dpy, Scr->iconmgr.twm_win->frame);
+ if (Scr->iconmgr.twm_win->icon_w)
+ XUnmapWindow (dpy, Scr->iconmgr.twm_win->icon_w);
+ Scr->iconmgr.twm_win->mapped = FALSE;
+ Scr->iconmgr.twm_win->icon = TRUE;
+}
+
+
+
+
+SetBorder (tmp, onoroff)
+ TwmWindow *tmp;
+ Bool onoroff;
+{
+ if (tmp->highlight) {
+ if (onoroff) {
+ XSetWindowBorder (dpy, tmp->frame, tmp->border);
+ if (tmp->title_w)
+ XSetWindowBorder (dpy, tmp->title_w, tmp->border);
+ } else {
+ XSetWindowBorderPixmap (dpy, tmp->frame, tmp->gray);
+ if (tmp->title_w)
+ XSetWindowBorderPixmap (dpy, tmp->title_w, tmp->gray);
+ }
+ }
+}
+
+
+
+DestroyMenu (menu)
+ MenuRoot *menu;
+{
+ MenuItem *item;
+
+ if (menu->w) {
+ XDeleteContext (dpy, menu->w, MenuContext);
+ XDeleteContext (dpy, menu->w, ScreenContext);
+ if (Scr->Shadow) XDestroyWindow (dpy, menu->shadow);
+ XDestroyWindow(dpy, menu->w);
+ }
+
+ for (item = menu->first; item; ) {
+ MenuItem *tmp = item;
+ item = item->next;
+ free ((char *) tmp);
+ }
+}
+
+
+
+/*
+ * warping routines
+ */
+void WarpAlongRing (ev, forward)
+ XButtonEvent *ev;
+ Bool forward;
+{
+ TwmWindow *r, *head;
+
+ if (Scr->RingLeader)
+ head = Scr->RingLeader;
+ else if (!(head = Scr->Ring))
+ return;
+
+ if (forward) {
+ for (r = head->ring.next; r != head; r = r->ring.next) {
+ if (!r || r->mapped) break;
+ }
+ } else {
+ for (r = head->ring.prev; r != head; r = r->ring.prev) {
+ if (!r || r->mapped) break;
+ }
+ }
+
+ if (r && r != head) {
+ TwmWindow *p = Scr->RingLeader, *t;
+
+ Scr->RingLeader = r;
+ WarpToWindow (r);
+
+ if (p && p->mapped &&
+ XFindContext (dpy, ev->window, TwmContext, (caddr_t *)&t) == XCSUCCESS &&
+ p == t) {
+ p->ring.cursor_valid = True;
+ p->ring.curs_x = ev->x_root - t->frame_x;
+ p->ring.curs_y = ev->y_root - t->frame_y;
+ if (p->ring.curs_x < -p->frame_bw ||
+ p->ring.curs_x >= p->frame_width + p->frame_bw ||
+ p->ring.curs_y < -p->frame_bw ||
+ p->ring.curs_y >= p->frame_height + p->frame_bw) {
+ /* somehow out of window */
+ p->ring.curs_x = p->frame_width / 2;
+ p->ring.curs_y = p->frame_height / 2;
+ }
+ }
+ }
+}
+
+
+
+void WarpToWindow (t)
+ TwmWindow *t;
+{
+ int x, y;
+
+ if (t->auto_raise || !Scr->NoRaiseWarp) AutoRaiseWindow (t);
+ if (t->ring.cursor_valid) {
+ x = t->ring.curs_x;
+ y = t->ring.curs_y;
+ } else {
+ x = t->frame_width / 2;
+ y = t->frame_height / 2;
+ }
+ XWarpPointer (dpy, None, t->frame, 0, 0, 0, 0, x, y);
+}
+
+
+
+
+/*
+ * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
+ * client messages will have the following form:
+ *
+ * event type ClientMessage
+ * message type _XA_WM_PROTOCOLS
+ * window tmp->w
+ * format 32
+ * data[0] message atom
+ * data[1] time stamp
+ */
+static void send_clientmessage (w, a, timestamp)
+ Window w;
+ Atom a;
+ Time timestamp;
+{
+ XClientMessageEvent ev;
+
+ ev.type = ClientMessage;
+ ev.window = w;
+ ev.message_type = _XA_WM_PROTOCOLS;
+ ev.format = 32;
+ ev.data.l[0] = a;
+ ev.data.l[1] = timestamp;
+ XSendEvent (dpy, w, False, 0L, (XEvent *) &ev);
+}
+
+SendDeleteWindowMessage (tmp, timestamp)
+ TwmWindow *tmp;
+ Time timestamp;
+{
+ send_clientmessage (tmp->w, _XA_WM_DELETE_WINDOW, timestamp);
+}
+
+SendSaveYourselfMessage (tmp, timestamp)
+ TwmWindow *tmp;
+ Time timestamp;
+{
+ send_clientmessage (tmp->w, _XA_WM_SAVE_YOURSELF, timestamp);
+}
+
+
+SendTakeFocusMessage (tmp, timestamp)
+ TwmWindow *tmp;
+ Time timestamp;
+{
+ send_clientmessage (tmp->w, _XA_WM_TAKE_FOCUS, timestamp);
+}
diff --git a/src/menus.h b/src/menus.h
new file mode 100644
index 0000000..f7729f9
--- /dev/null
+++ b/src/menus.h
@@ -0,0 +1,178 @@
+/*****************************************************************************/
+/*
+
+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: menus.h,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * twm menus include file
+ *
+ * 17-Nov-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#ifndef _MENUS_
+#define _MENUS_
+
+#define TWM_ROOT "bLoB_GoOp" /* my private root menu */
+#define TWM_WINDOWS "TwmWindows" /* for f.menu "TwmWindows" */
+
+#define MAX_FILE_SIZE 4096 /* max chars to read from file for cut */
+
+typedef struct MenuItem
+{
+ struct MenuItem *next; /* next menu item */
+ struct MenuItem *prev; /* prev menu item */
+ struct MenuRoot *sub; /* MenuRoot of a pull right menu */
+ struct MenuRoot *root; /* back pointer to my MenuRoot */
+ char *item; /* the character string displayed */
+ char *action; /* action to be performed */
+ Pixel fore; /* foreground color */
+ Pixel back; /* background color */
+ Pixel hi_fore; /* highlight foreground */
+ Pixel hi_back; /* highlight background */
+ short item_num; /* item number of this menu */
+ short x; /* x coordinate for text */
+ short func; /* twm built in function */
+ short state; /* video state, 0 = normal, 1 = reversed */
+ short strlen; /* strlen(item) */
+ short user_colors; /* colors were specified */
+} MenuItem;
+
+typedef struct MenuRoot
+{
+ struct MenuItem *first; /* first item in menu */
+ struct MenuItem *last; /* last item in menu */
+ struct MenuRoot *prev; /* previous root menu if pull right */
+ struct MenuRoot *next; /* next in list of root menus */
+ char *name; /* name of root */
+ Window w; /* the window of the menu */
+ Window shadow; /* the shadow window */
+ Pixel hi_fore; /* highlight foreground */
+ Pixel hi_back; /* highlight background */
+ short mapped; /* NEVER_MAPPED, UNMAPPED, or MAPPED */
+ short height; /* height of the menu */
+ short width; /* width of the menu */
+ short items; /* number of items in the menu */
+ short pull; /* is there a pull right entry ? */
+ short entered; /* EnterNotify following pop up */
+ short real_menu; /* this is a real menu */
+} MenuRoot;
+
+#define NEVER_MAPPED 0 /* constants for mapped field of MenuRoot */
+#define UNMAPPED 1
+#define MAPPED 2
+
+
+typedef struct MouseButton
+{
+ int func; /* the function number */
+ int mask; /* modifier mask */
+ MenuRoot *menu; /* menu if func is F_MENU */
+ MenuItem *item; /* action to perform if func != F_MENU */
+} MouseButton;
+
+typedef struct FuncKey
+{
+ struct FuncKey *next; /* next in the list of function keys */
+ char *name; /* key name */
+ KeySym keysym; /* X keysym */
+ KeyCode keycode; /* X keycode */
+ int cont; /* context */
+ int mods; /* modifiers */
+ int func; /* function to perform */
+ char *win_name; /* window name (if any) */
+ char *action; /* action string (if any) */
+} FuncKey;
+
+extern int RootFunction;
+extern MenuRoot *ActiveMenu;
+extern MenuItem *ActiveItem;
+extern int MoveFunction;
+extern int WindowMoved;
+extern int ConstMove;
+extern int ConstMoveDir;
+extern int ConstMoveX;
+extern int ConstMoveY;
+extern int ConstMoveXL;
+extern int ConstMoveXR;
+extern int ConstMoveYT;
+extern int ConstMoveYB;
+
+#define MAXMENUDEPTH 10 /* max number of nested menus */
+extern int MenuDepth;
+
+#define MOVE_NONE 0 /* modes of constrained move */
+#define MOVE_VERT 1
+#define MOVE_HORIZ 2
+
+#define WARPSCREEN_NEXT "next"
+#define WARPSCREEN_PREV "prev"
+#define WARPSCREEN_BACK "back"
+
+#define COLORMAP_NEXT "next"
+#define COLORMAP_PREV "prev"
+#define COLORMAP_DEFAULT "default"
+
+extern void InitTitlebarButtons();
+extern void InitMenus();
+extern MenuRoot *NewMenuRoot();
+extern MenuItem *AddToMenu();
+extern Bool PopUpMenu();
+extern MenuRoot *FindMenuRoot();
+extern Bool AddFuncKey();
+extern int ExecuteFunction();
+extern int DeferExecution();
+extern void Execute();
+extern void FocusOnRoot();
+
+#endif /* _MENUS_ */
diff --git a/src/parse.c b/src/parse.c
new file mode 100644
index 0000000..7281d0b
--- /dev/null
+++ b/src/parse.c
@@ -0,0 +1,1149 @@
+/*****************************************************************************/
+/*
+
+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: parse.c,v 1.5 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * parse the .twmrc file
+ *
+ * 17-Nov-87 Thomas E. LaStrange File created
+ * 10-Oct-90 David M. Sternlicht Storing saved colors on root
+ ***********************************************************************/
+
+#include <stdio.h>
+#include <X11/Xos.h>
+#include <X11/Xmu/CharSet.h>
+#include "twm.h"
+#include "screen.h"
+#include "menus.h"
+#include "util.h"
+#include "gram.h"
+#include "parse.h"
+#include <X11/Xatom.h>
+#include <X11/extensions/sync.h>
+
+#ifndef SYSTEM_INIT_FILE
+#define SYSTEM_INIT_FILE "/usr/lib/X11/twm/system.twmrc"
+#endif
+#define BUF_LEN 300
+
+static FILE *twmrc;
+static int ptr = 0;
+static int len = 0;
+static char buff[BUF_LEN+1];
+static char overflowbuff[20]; /* really only need one */
+static int overflowlen;
+static char **stringListSource, *currentString;
+static int ParseUsePPosition();
+
+extern int yylineno;
+extern int mods;
+
+int ConstrainedMoveTime = 400; /* milliseconds, event times */
+
+static int twmFileInput(), twmStringListInput();
+void twmUnput();
+int (*twmInputFunc)();
+
+extern char *defTwmrc[]; /* default bindings */
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * ParseTwmrc - parse the .twmrc file
+ *
+ * Inputs:
+ * filename - the filename to parse. A NULL indicates $HOME/.twmrc
+ *
+ ***********************************************************************
+ */
+
+static int doparse (ifunc, srctypename, srcname)
+ int (*ifunc)();
+ char *srctypename;
+ char *srcname;
+{
+ mods = 0;
+ ptr = 0;
+ len = 0;
+ yylineno = 1;
+ ParseError = FALSE;
+ twmInputFunc = ifunc;
+ overflowlen = 0;
+
+ yyparse();
+
+ if (Scr->PointerForeground.pixel != Scr->Black ||
+ Scr->PointerBackground.pixel != Scr->White)
+ {
+ XRecolorCursor(dpy, UpperLeftCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, RightButt,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, LeftButt,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, MiddleButt,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->FrameCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->TitleCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->IconCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->IconMgrCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->MoveCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->ResizeCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->MenuCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->ButtonCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->WaitCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->SelectCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->DestroyCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ }
+ if (ParseError) {
+ fprintf (stderr, "%s: errors found in twm %s",
+ ProgramName, srctypename);
+ if (srcname) fprintf (stderr, " \"%s\"", srcname);
+ fprintf (stderr, "\n");
+ }
+ return (ParseError ? 0 : 1);
+}
+
+
+int ParseTwmrc (filename)
+ char *filename;
+{
+ int i;
+ char *home = NULL;
+ int homelen = 0;
+ char *cp = NULL;
+ char tmpfilename[257];
+
+ /*
+ * If filename given, try it, else try ~/.twmrc.# then ~/.twmrc. Then
+ * try system.twmrc; finally using built-in defaults.
+ */
+ for (twmrc = NULL, i = 0; !twmrc && i < 4; i++) {
+ switch (i) {
+ case 0: /* -f filename */
+ cp = filename;
+ break;
+
+ case 1: /* ~/.twmrc.screennum */
+ if (!filename) {
+ home = getenv ("HOME");
+ if (home) {
+ homelen = strlen (home);
+ cp = tmpfilename;
+ (void) sprintf (tmpfilename, "%s/.twmrc.%d",
+ home, Scr->screen);
+ break;
+ }
+ }
+ continue;
+
+ case 2: /* ~/.twmrc */
+ if (home) {
+ tmpfilename[homelen + 7] = '\0';
+ }
+ break;
+
+ case 3: /* system.twmrc */
+ cp = SYSTEM_INIT_FILE;
+ break;
+ }
+
+ if (cp) twmrc = fopen (cp, "r");
+ }
+
+ if (twmrc) {
+ int status;
+
+ if (filename && cp != filename) {
+ fprintf (stderr,
+ "%s: unable to open twmrc file %s, using %s instead\n",
+ ProgramName, filename, cp);
+ }
+ status = doparse (twmFileInput, "file", cp);
+ fclose (twmrc);
+ return status;
+ } else {
+ if (filename) {
+ fprintf (stderr,
+ "%s: unable to open twmrc file %s, using built-in defaults instead\n",
+ ProgramName, filename);
+ }
+ return ParseStringList (defTwmrc);
+ }
+}
+
+int ParseStringList (sl)
+ char **sl;
+{
+ stringListSource = sl;
+ currentString = *sl;
+ return doparse (twmStringListInput, "string list", (char *)NULL);
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * twmFileInput - redefinition of the lex input routine for file input
+ *
+ * Returned Value:
+ * the next input character
+ *
+ ***********************************************************************
+ */
+
+static int twmFileInput()
+{
+ if (overflowlen) return (int) overflowbuff[--overflowlen];
+
+ while (ptr == len)
+ {
+ if (fgets(buff, BUF_LEN, twmrc) == NULL)
+ return 0;
+
+ yylineno++;
+
+ ptr = 0;
+ len = strlen(buff);
+ }
+ return ((int)buff[ptr++]);
+}
+
+static int twmStringListInput()
+{
+ if (overflowlen) return (int) overflowbuff[--overflowlen];
+
+ /*
+ * return the character currently pointed to
+ */
+ if (currentString) {
+ unsigned int c = (unsigned int) *currentString++;
+
+ if (c) return c; /* if non-nul char */
+ currentString = *++stringListSource; /* advance to next bol */
+ return '\n'; /* but say that we hit last eol */
+ }
+ return 0; /* eof */
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * twmUnput - redefinition of the lex unput routine
+ *
+ * Inputs:
+ * c - the character to push back onto the input stream
+ *
+ ***********************************************************************
+ */
+
+void twmUnput (c)
+ int c;
+{
+ if (overflowlen < sizeof overflowbuff) {
+ overflowbuff[overflowlen++] = (char) c;
+ } else {
+ twmrc_error_prefix ();
+ fprintf (stderr, "unable to unput character (%d)\n",
+ c);
+ }
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * TwmOutput - redefinition of the lex output routine
+ *
+ * Inputs:
+ * c - the character to print
+ *
+ ***********************************************************************
+ */
+
+void
+TwmOutput(c)
+{
+ putchar(c);
+}
+
+
+/**********************************************************************
+ *
+ * Parsing table and routines
+ *
+ ***********************************************************************/
+
+typedef struct _TwmKeyword {
+ char *name;
+ int value;
+ int subnum;
+} TwmKeyword;
+
+#define kw0_NoDefaults 1
+#define kw0_AutoRelativeResize 2
+#define kw0_ForceIcons 3
+#define kw0_NoIconManagers 4
+#define kw0_OpaqueMove 5
+#define kw0_InterpolateMenuColors 6
+#define kw0_NoVersion 7
+#define kw0_SortIconManager 8
+#define kw0_NoGrabServer 9
+#define kw0_NoMenuShadows 10
+#define kw0_NoRaiseOnMove 11
+#define kw0_NoRaiseOnResize 12
+#define kw0_NoRaiseOnDeiconify 13
+#define kw0_DontMoveOff 14
+#define kw0_NoBackingStore 15
+#define kw0_NoSaveUnders 16
+#define kw0_RestartPreviousState 17
+#define kw0_ClientBorderWidth 18
+#define kw0_NoTitleFocus 19
+#define kw0_RandomPlacement 20
+#define kw0_DecorateTransients 21
+#define kw0_ShowIconManager 22
+#define kw0_NoCaseSensitive 23
+#define kw0_NoRaiseOnWarp 24
+#define kw0_WarpUnmapped 25
+
+#define kws_UsePPosition 1
+#define kws_IconFont 2
+#define kws_ResizeFont 3
+#define kws_MenuFont 4
+#define kws_TitleFont 5
+#define kws_IconManagerFont 6
+#define kws_UnknownIcon 7
+#define kws_IconDirectory 8
+#define kws_MaxWindowSize 9
+
+#define kwn_ConstrainedMoveTime 1
+#define kwn_MoveDelta 2
+#define kwn_XorValue 3
+#define kwn_FramePadding 4
+#define kwn_TitlePadding 5
+#define kwn_ButtonIndent 6
+#define kwn_BorderWidth 7
+#define kwn_IconBorderWidth 8
+#define kwn_TitleButtonBorderWidth 9
+#define kwn_Priority 10
+
+#define kwcl_BorderColor 1
+#define kwcl_IconManagerHighlight 2
+#define kwcl_BorderTileForeground 3
+#define kwcl_BorderTileBackground 4
+#define kwcl_TitleForeground 5
+#define kwcl_TitleBackground 6
+#define kwcl_IconForeground 7
+#define kwcl_IconBackground 8
+#define kwcl_IconBorderColor 9
+#define kwcl_IconManagerForeground 10
+#define kwcl_IconManagerBackground 11
+
+#define kwc_DefaultForeground 1
+#define kwc_DefaultBackground 2
+#define kwc_MenuForeground 3
+#define kwc_MenuBackground 4
+#define kwc_MenuTitleForeground 5
+#define kwc_MenuTitleBackground 6
+#define kwc_MenuShadowColor 7
+#define kwc_PointerForeground 8
+#define kwc_PointerBackground 9
+
+
+/*
+ * The following is sorted alphabetically according to name (which must be
+ * in lowercase and only contain the letters a-z). It is fed to a binary
+ * search to parse keywords.
+ */
+static TwmKeyword keytable[] = {
+ { "all", ALL, 0 },
+ { "autoraise", AUTO_RAISE, 0 },
+ { "autorelativeresize", KEYWORD, kw0_AutoRelativeResize },
+ { "bordercolor", CLKEYWORD, kwcl_BorderColor },
+ { "bordertilebackground", CLKEYWORD, kwcl_BorderTileBackground },
+ { "bordertileforeground", CLKEYWORD, kwcl_BorderTileForeground },
+ { "borderwidth", NKEYWORD, kwn_BorderWidth },
+ { "button", BUTTON, 0 },
+ { "buttonindent", NKEYWORD, kwn_ButtonIndent },
+ { "c", CONTROL, 0 },
+ { "center", JKEYWORD, J_CENTER },
+ { "clientborderwidth", KEYWORD, kw0_ClientBorderWidth },
+ { "color", COLOR, 0 },
+ { "constrainedmovetime", NKEYWORD, kwn_ConstrainedMoveTime },
+ { "control", CONTROL, 0 },
+ { "cursors", CURSORS, 0 },
+ { "decoratetransients", KEYWORD, kw0_DecorateTransients },
+ { "defaultbackground", CKEYWORD, kwc_DefaultBackground },
+ { "defaultforeground", CKEYWORD, kwc_DefaultForeground },
+ { "defaultfunction", DEFAULT_FUNCTION, 0 },
+ { "destroy", KILL, 0 },
+ { "donticonifybyunmapping", DONT_ICONIFY_BY_UNMAPPING, 0 },
+ { "dontmoveoff", KEYWORD, kw0_DontMoveOff },
+ { "dontsqueezetitle", DONT_SQUEEZE_TITLE, 0 },
+ { "east", DKEYWORD, D_EAST },
+ { "f", FRAME, 0 },
+ { "f.autoraise", FKEYWORD, F_AUTORAISE },
+ { "f.backiconmgr", FKEYWORD, F_BACKICONMGR },
+ { "f.beep", FKEYWORD, F_BEEP },
+ { "f.bottomzoom", FKEYWORD, F_BOTTOMZOOM },
+ { "f.circledown", FKEYWORD, F_CIRCLEDOWN },
+ { "f.circleup", FKEYWORD, F_CIRCLEUP },
+ { "f.colormap", FSKEYWORD, F_COLORMAP },
+ { "f.cut", FSKEYWORD, F_CUT },
+ { "f.cutfile", FKEYWORD, F_CUTFILE },
+ { "f.deiconify", FKEYWORD, F_DEICONIFY },
+ { "f.delete", FKEYWORD, F_DELETE },
+ { "f.deltastop", FKEYWORD, F_DELTASTOP },
+ { "f.destroy", FKEYWORD, F_DESTROY },
+ { "f.downiconmgr", FKEYWORD, F_DOWNICONMGR },
+ { "f.exec", FSKEYWORD, F_EXEC },
+ { "f.file", FSKEYWORD, F_FILE },
+ { "f.focus", FKEYWORD, F_FOCUS },
+ { "f.forcemove", FKEYWORD, F_FORCEMOVE },
+ { "f.forwiconmgr", FKEYWORD, F_FORWICONMGR },
+ { "f.fullzoom", FKEYWORD, F_FULLZOOM },
+ { "f.function", FSKEYWORD, F_FUNCTION },
+ { "f.hbzoom", FKEYWORD, F_BOTTOMZOOM },
+ { "f.hideiconmgr", FKEYWORD, F_HIDELIST },
+ { "f.horizoom", FKEYWORD, F_HORIZOOM },
+ { "f.htzoom", FKEYWORD, F_TOPZOOM },
+ { "f.hzoom", FKEYWORD, F_HORIZOOM },
+ { "f.iconify", FKEYWORD, F_ICONIFY },
+ { "f.identify", FKEYWORD, F_IDENTIFY },
+ { "f.lefticonmgr", FKEYWORD, F_LEFTICONMGR },
+ { "f.leftzoom", FKEYWORD, F_LEFTZOOM },
+ { "f.lower", FKEYWORD, F_LOWER },
+ { "f.menu", FSKEYWORD, F_MENU },
+ { "f.move", FKEYWORD, F_MOVE },
+ { "f.nexticonmgr", FKEYWORD, F_NEXTICONMGR },
+ { "f.nop", FKEYWORD, F_NOP },
+ { "f.previconmgr", FKEYWORD, F_PREVICONMGR },
+ { "f.priority", FSKEYWORD, F_PRIORITY },
+ { "f.quit", FKEYWORD, F_QUIT },
+ { "f.raise", FKEYWORD, F_RAISE },
+ { "f.raiselower", FKEYWORD, F_RAISELOWER },
+ { "f.refresh", FKEYWORD, F_REFRESH },
+ { "f.resize", FKEYWORD, F_RESIZE },
+ { "f.restart", FKEYWORD, F_RESTART },
+ { "f.righticonmgr", FKEYWORD, F_RIGHTICONMGR },
+ { "f.rightzoom", FKEYWORD, F_RIGHTZOOM },
+ { "f.saveyourself", FKEYWORD, F_SAVEYOURSELF },
+ { "f.showiconmgr", FKEYWORD, F_SHOWLIST },
+ { "f.sorticonmgr", FKEYWORD, F_SORTICONMGR },
+ { "f.source", FSKEYWORD, F_BEEP }, /* XXX - don't work */
+ { "f.title", FKEYWORD, F_TITLE },
+ { "f.topzoom", FKEYWORD, F_TOPZOOM },
+ { "f.twmrc", FKEYWORD, F_RESTART },
+ { "f.unfocus", FKEYWORD, F_UNFOCUS },
+ { "f.upiconmgr", FKEYWORD, F_UPICONMGR },
+ { "f.version", FKEYWORD, F_VERSION },
+ { "f.vlzoom", FKEYWORD, F_LEFTZOOM },
+ { "f.vrzoom", FKEYWORD, F_RIGHTZOOM },
+ { "f.warpring", FSKEYWORD, F_WARPRING },
+ { "f.warpto", FSKEYWORD, F_WARPTO },
+ { "f.warptoiconmgr", FSKEYWORD, F_WARPTOICONMGR },
+ { "f.warptoscreen", FSKEYWORD, F_WARPTOSCREEN },
+ { "f.winrefresh", FKEYWORD, F_WINREFRESH },
+ { "f.zoom", FKEYWORD, F_ZOOM },
+ { "forceicons", KEYWORD, kw0_ForceIcons },
+ { "frame", FRAME, 0 },
+ { "framepadding", NKEYWORD, kwn_FramePadding },
+ { "function", FUNCTION, 0 },
+ { "grayscale", GRAYSCALE, 0 },
+ { "greyscale", GRAYSCALE, 0 },
+ { "i", ICON, 0 },
+ { "icon", ICON, 0 },
+ { "iconbackground", CLKEYWORD, kwcl_IconBackground },
+ { "iconbordercolor", CLKEYWORD, kwcl_IconBorderColor },
+ { "iconborderwidth", NKEYWORD, kwn_IconBorderWidth },
+ { "icondirectory", SKEYWORD, kws_IconDirectory },
+ { "iconfont", SKEYWORD, kws_IconFont },
+ { "iconforeground", CLKEYWORD, kwcl_IconForeground },
+ { "iconifybyunmapping", ICONIFY_BY_UNMAPPING, 0 },
+ { "iconmanagerbackground", CLKEYWORD, kwcl_IconManagerBackground },
+ { "iconmanagerdontshow", ICONMGR_NOSHOW, 0 },
+ { "iconmanagerfont", SKEYWORD, kws_IconManagerFont },
+ { "iconmanagerforeground", CLKEYWORD, kwcl_IconManagerForeground },
+ { "iconmanagergeometry", ICONMGR_GEOMETRY, 0 },
+ { "iconmanagerhighlight", CLKEYWORD, kwcl_IconManagerHighlight },
+ { "iconmanagers", ICONMGRS, 0 },
+ { "iconmanagershow", ICONMGR_SHOW, 0 },
+ { "iconmgr", ICONMGR, 0 },
+ { "iconregion", ICON_REGION, 0 },
+ { "icons", ICONS, 0 },
+ { "interpolatemenucolors", KEYWORD, kw0_InterpolateMenuColors },
+ { "l", LOCK, 0 },
+ { "left", JKEYWORD, J_LEFT },
+ { "lefttitlebutton", LEFT_TITLEBUTTON, 0 },
+ { "lock", LOCK, 0 },
+ { "m", META, 0 },
+ { "maketitle", MAKE_TITLE, 0 },
+ { "maxwindowsize", SKEYWORD, kws_MaxWindowSize },
+ { "menu", MENU, 0 },
+ { "menubackground", CKEYWORD, kwc_MenuBackground },
+ { "menufont", SKEYWORD, kws_MenuFont },
+ { "menuforeground", CKEYWORD, kwc_MenuForeground },
+ { "menushadowcolor", CKEYWORD, kwc_MenuShadowColor },
+ { "menutitlebackground", CKEYWORD, kwc_MenuTitleBackground },
+ { "menutitleforeground", CKEYWORD, kwc_MenuTitleForeground },
+ { "meta", META, 0 },
+ { "mod", META, 0 }, /* fake it */
+ { "monochrome", MONOCHROME, 0 },
+ { "move", MOVE, 0 },
+ { "movedelta", NKEYWORD, kwn_MoveDelta },
+ { "nobackingstore", KEYWORD, kw0_NoBackingStore },
+ { "nocasesensitive", KEYWORD, kw0_NoCaseSensitive },
+ { "nodefaults", KEYWORD, kw0_NoDefaults },
+ { "nograbserver", KEYWORD, kw0_NoGrabServer },
+ { "nohighlight", NO_HILITE, 0 },
+ { "noiconmanagers", KEYWORD, kw0_NoIconManagers },
+ { "nomenushadows", KEYWORD, kw0_NoMenuShadows },
+ { "noraiseondeiconify", KEYWORD, kw0_NoRaiseOnDeiconify },
+ { "noraiseonmove", KEYWORD, kw0_NoRaiseOnMove },
+ { "noraiseonresize", KEYWORD, kw0_NoRaiseOnResize },
+ { "noraiseonwarp", KEYWORD, kw0_NoRaiseOnWarp },
+ { "north", DKEYWORD, D_NORTH },
+ { "nosaveunders", KEYWORD, kw0_NoSaveUnders },
+ { "nostackmode", NO_STACKMODE, 0 },
+ { "notitle", NO_TITLE, 0 },
+ { "notitlefocus", KEYWORD, kw0_NoTitleFocus },
+ { "notitlehighlight", NO_TITLE_HILITE, 0 },
+ { "noversion", KEYWORD, kw0_NoVersion },
+ { "opaquemove", KEYWORD, kw0_OpaqueMove },
+ { "pixmaps", PIXMAPS, 0 },
+ { "pointerbackground", CKEYWORD, kwc_PointerBackground },
+ { "pointerforeground", CKEYWORD, kwc_PointerForeground },
+ { "priority", NKEYWORD, kwn_Priority },
+ { "r", ROOT, 0 },
+ { "randomplacement", KEYWORD, kw0_RandomPlacement },
+ { "resize", RESIZE, 0 },
+ { "resizefont", SKEYWORD, kws_ResizeFont },
+ { "restartpreviousstate", KEYWORD, kw0_RestartPreviousState },
+ { "right", JKEYWORD, J_RIGHT },
+ { "righttitlebutton", RIGHT_TITLEBUTTON, 0 },
+ { "root", ROOT, 0 },
+ { "s", SHIFT, 0 },
+ { "savecolor", SAVECOLOR, 0},
+ { "select", SELECT, 0 },
+ { "shift", SHIFT, 0 },
+ { "showiconmanager", KEYWORD, kw0_ShowIconManager },
+ { "sorticonmanager", KEYWORD, kw0_SortIconManager },
+ { "south", DKEYWORD, D_SOUTH },
+ { "squeezetitle", SQUEEZE_TITLE, 0 },
+ { "starticonified", START_ICONIFIED, 0 },
+ { "t", TITLE, 0 },
+ { "title", TITLE, 0 },
+ { "titlebackground", CLKEYWORD, kwcl_TitleBackground },
+ { "titlebuttonborderwidth", NKEYWORD, kwn_TitleButtonBorderWidth },
+ { "titlefont", SKEYWORD, kws_TitleFont },
+ { "titleforeground", CLKEYWORD, kwcl_TitleForeground },
+ { "titlehighlight", TITLE_HILITE, 0 },
+ { "titlepadding", NKEYWORD, kwn_TitlePadding },
+ { "unknownicon", SKEYWORD, kws_UnknownIcon },
+ { "usepposition", SKEYWORD, kws_UsePPosition },
+ { "w", WINDOW, 0 },
+ { "wait", WAIT, 0 },
+ { "warpcursor", WARP_CURSOR, 0 },
+ { "warpunmapped", KEYWORD, kw0_WarpUnmapped },
+ { "west", DKEYWORD, D_WEST },
+ { "window", WINDOW, 0 },
+ { "windowfunction", WINDOW_FUNCTION, 0 },
+ { "windowring", WINDOW_RING, 0 },
+ { "xorvalue", NKEYWORD, kwn_XorValue },
+ { "zoom", ZOOM, 0 },
+};
+
+static int numkeywords = (sizeof(keytable)/sizeof(keytable[0]));
+
+int parse_keyword (s, nump)
+ char *s;
+ int *nump;
+{
+ register int lower = 0, upper = numkeywords - 1;
+
+ XmuCopyISOLatin1Lowered (s, s);
+ while (lower <= upper) {
+ int middle = (lower + upper) / 2;
+ TwmKeyword *p = &keytable[middle];
+ int res = strcmp (p->name, s);
+
+ if (res < 0) {
+ lower = middle + 1;
+ } else if (res == 0) {
+ *nump = p->subnum;
+ return p->value;
+ } else {
+ upper = middle - 1;
+ }
+ }
+ return ERRORTOKEN;
+}
+
+
+
+/*
+ * action routines called by grammar
+ */
+
+int do_single_keyword (keyword)
+ int keyword;
+{
+ switch (keyword) {
+ case kw0_NoDefaults:
+ Scr->NoDefaults = TRUE;
+ return 1;
+
+ case kw0_AutoRelativeResize:
+ Scr->AutoRelativeResize = TRUE;
+ return 1;
+
+ case kw0_ForceIcons:
+ if (Scr->FirstTime) Scr->ForceIcon = TRUE;
+ return 1;
+
+ case kw0_NoIconManagers:
+ Scr->NoIconManagers = TRUE;
+ return 1;
+
+ case kw0_OpaqueMove:
+ Scr->OpaqueMove = TRUE;
+ return 1;
+
+ case kw0_InterpolateMenuColors:
+ if (Scr->FirstTime) Scr->InterpolateMenuColors = TRUE;
+ return 1;
+
+ case kw0_NoVersion:
+ /* obsolete */
+ return 1;
+
+ case kw0_SortIconManager:
+ if (Scr->FirstTime) Scr->SortIconMgr = TRUE;
+ return 1;
+
+ case kw0_NoGrabServer:
+ Scr->NoGrabServer = TRUE;
+ return 1;
+
+ case kw0_NoMenuShadows:
+ if (Scr->FirstTime) Scr->Shadow = FALSE;
+ return 1;
+
+ case kw0_NoRaiseOnMove:
+ if (Scr->FirstTime) Scr->NoRaiseMove = TRUE;
+ return 1;
+
+ case kw0_NoRaiseOnResize:
+ if (Scr->FirstTime) Scr->NoRaiseResize = TRUE;
+ return 1;
+
+ case kw0_NoRaiseOnDeiconify:
+ if (Scr->FirstTime) Scr->NoRaiseDeicon = TRUE;
+ return 1;
+
+ case kw0_DontMoveOff:
+ Scr->DontMoveOff = TRUE;
+ return 1;
+
+ case kw0_NoBackingStore:
+ Scr->BackingStore = FALSE;
+ return 1;
+
+ case kw0_NoSaveUnders:
+ Scr->SaveUnder = FALSE;
+ return 1;
+
+ case kw0_RestartPreviousState:
+ RestartPreviousState = True;
+ return 1;
+
+ case kw0_ClientBorderWidth:
+ if (Scr->FirstTime) Scr->ClientBorderWidth = TRUE;
+ return 1;
+
+ case kw0_NoTitleFocus:
+ Scr->TitleFocus = FALSE;
+ return 1;
+
+ case kw0_RandomPlacement:
+ Scr->RandomPlacement = TRUE;
+ return 1;
+
+ case kw0_DecorateTransients:
+ Scr->DecorateTransients = TRUE;
+ return 1;
+
+ case kw0_ShowIconManager:
+ Scr->ShowIconManager = TRUE;
+ return 1;
+
+ case kw0_NoCaseSensitive:
+ Scr->CaseSensitive = FALSE;
+ return 1;
+
+ case kw0_NoRaiseOnWarp:
+ Scr->NoRaiseWarp = TRUE;
+ return 1;
+
+ case kw0_WarpUnmapped:
+ Scr->WarpUnmapped = TRUE;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int do_string_keyword (keyword, s)
+ int keyword;
+ char *s;
+{
+ switch (keyword) {
+ case kws_UsePPosition:
+ {
+ int ppos = ParseUsePPosition (s);
+ if (ppos < 0) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "ignoring invalid UsePPosition argument \"%s\"\n", s);
+ } else {
+ Scr->UsePPosition = ppos;
+ }
+ return 1;
+ }
+
+ case kws_IconFont:
+ if (!Scr->HaveFonts) Scr->IconFont.name = s;
+ return 1;
+
+ case kws_ResizeFont:
+ if (!Scr->HaveFonts) Scr->SizeFont.name = s;
+ return 1;
+
+ case kws_MenuFont:
+ if (!Scr->HaveFonts) Scr->MenuFont.name = s;
+ return 1;
+
+ case kws_TitleFont:
+ if (!Scr->HaveFonts) Scr->TitleBarFont.name = s;
+ return 1;
+
+ case kws_IconManagerFont:
+ if (!Scr->HaveFonts) Scr->IconManagerFont.name = s;
+ return 1;
+
+ case kws_UnknownIcon:
+ if (Scr->FirstTime) GetUnknownIcon (s);
+ return 1;
+
+ case kws_IconDirectory:
+ if (Scr->FirstTime) Scr->IconDirectory = ExpandFilename (s);
+ return 1;
+
+ case kws_MaxWindowSize:
+ JunkMask = XParseGeometry (s, &JunkX, &JunkY, &JunkWidth, &JunkHeight);
+ if ((JunkMask & (WidthValue | HeightValue)) !=
+ (WidthValue | HeightValue)) {
+ twmrc_error_prefix();
+ fprintf (stderr, "bad MaxWindowSize \"%s\"\n", s);
+ return 0;
+ }
+ if (JunkWidth <= 0 || JunkHeight <= 0) {
+ twmrc_error_prefix();
+ fprintf (stderr, "MaxWindowSize \"%s\" must be positive\n", s);
+ return 0;
+ }
+ Scr->MaxWindowWidth = JunkWidth;
+ Scr->MaxWindowHeight = JunkHeight;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int do_number_keyword (keyword, num)
+ int keyword;
+ int num;
+{
+ switch (keyword) {
+ case kwn_ConstrainedMoveTime:
+ ConstrainedMoveTime = num;
+ return 1;
+
+ case kwn_MoveDelta:
+ Scr->MoveDelta = num;
+ return 1;
+
+ case kwn_XorValue:
+ if (Scr->FirstTime) Scr->XORvalue = num;
+ return 1;
+
+ case kwn_FramePadding:
+ if (Scr->FirstTime) Scr->FramePadding = num;
+ return 1;
+
+ case kwn_TitlePadding:
+ if (Scr->FirstTime) Scr->TitlePadding = num;
+ return 1;
+
+ case kwn_ButtonIndent:
+ if (Scr->FirstTime) Scr->ButtonIndent = num;
+ return 1;
+
+ case kwn_BorderWidth:
+ if (Scr->FirstTime) Scr->BorderWidth = num;
+ return 1;
+
+ case kwn_IconBorderWidth:
+ if (Scr->FirstTime) Scr->IconBorderWidth = num;
+ return 1;
+
+ case kwn_TitleButtonBorderWidth:
+ if (Scr->FirstTime) Scr->TBInfo.border = num;
+ return 1;
+
+ case kwn_Priority:
+ if (HasSync) XSyncSetPriority(dpy, /*self*/ None, num);
+ return 1;
+ }
+
+ return 0;
+}
+
+name_list **do_colorlist_keyword (keyword, colormode, s)
+ int keyword;
+ int colormode;
+ char *s;
+{
+ switch (keyword) {
+ case kwcl_BorderColor:
+ GetColor (colormode, &Scr->BorderColor, s);
+ return &Scr->BorderColorL;
+
+ case kwcl_IconManagerHighlight:
+ GetColor (colormode, &Scr->IconManagerHighlight, s);
+ return &Scr->IconManagerHighlightL;
+
+ case kwcl_BorderTileForeground:
+ GetColor (colormode, &Scr->BorderTileC.fore, s);
+ return &Scr->BorderTileForegroundL;
+
+ case kwcl_BorderTileBackground:
+ GetColor (colormode, &Scr->BorderTileC.back, s);
+ return &Scr->BorderTileBackgroundL;
+
+ case kwcl_TitleForeground:
+ GetColor (colormode, &Scr->TitleC.fore, s);
+ return &Scr->TitleForegroundL;
+
+ case kwcl_TitleBackground:
+ GetColor (colormode, &Scr->TitleC.back, s);
+ return &Scr->TitleBackgroundL;
+
+ case kwcl_IconForeground:
+ GetColor (colormode, &Scr->IconC.fore, s);
+ return &Scr->IconForegroundL;
+
+ case kwcl_IconBackground:
+ GetColor (colormode, &Scr->IconC.back, s);
+ return &Scr->IconBackgroundL;
+
+ case kwcl_IconBorderColor:
+ GetColor (colormode, &Scr->IconBorderColor, s);
+ return &Scr->IconBorderColorL;
+
+ case kwcl_IconManagerForeground:
+ GetColor (colormode, &Scr->IconManagerC.fore, s);
+ return &Scr->IconManagerFL;
+
+ case kwcl_IconManagerBackground:
+ GetColor (colormode, &Scr->IconManagerC.back, s);
+ return &Scr->IconManagerBL;
+ }
+ return NULL;
+}
+
+int do_color_keyword (keyword, colormode, s)
+ int keyword;
+ int colormode;
+ char *s;
+{
+ switch (keyword) {
+ case kwc_DefaultForeground:
+ GetColor (colormode, &Scr->DefaultC.fore, s);
+ return 1;
+
+ case kwc_DefaultBackground:
+ GetColor (colormode, &Scr->DefaultC.back, s);
+ return 1;
+
+ case kwc_MenuForeground:
+ GetColor (colormode, &Scr->MenuC.fore, s);
+ return 1;
+
+ case kwc_MenuBackground:
+ GetColor (colormode, &Scr->MenuC.back, s);
+ return 1;
+
+ case kwc_MenuTitleForeground:
+ GetColor (colormode, &Scr->MenuTitleC.fore, s);
+ return 1;
+
+ case kwc_MenuTitleBackground:
+ GetColor (colormode, &Scr->MenuTitleC.back, s);
+ return 1;
+
+ case kwc_MenuShadowColor:
+ GetColor (colormode, &Scr->MenuShadowColor, s);
+ return 1;
+
+ case kwc_PointerForeground:
+ GetColorValue (colormode, &Scr->PointerForeground, s);
+ return 1;
+
+ case kwc_PointerBackground:
+ GetColorValue (colormode, &Scr->PointerBackground, s);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * put_pixel_on_root() Save a pixel value in twm root window color property.
+ */
+put_pixel_on_root(pixel)
+ Pixel pixel;
+{
+ int i, addPixel = 1;
+ Atom pixelAtom, retAtom;
+ int retFormat;
+ unsigned long nPixels, retAfter;
+ Pixel *retProp;
+ pixelAtom = XInternAtom(dpy, "_MIT_PRIORITY_COLORS", True);
+ XGetWindowProperty(dpy, Scr->Root, pixelAtom, 0, 8192,
+ False, XA_CARDINAL, &retAtom,
+ &retFormat, &nPixels, &retAfter,
+ (unsigned char **)&retProp);
+
+ for (i=0; i< nPixels; i++)
+ if (pixel == retProp[i]) addPixel = 0;
+
+ if (addPixel)
+ XChangeProperty (dpy, Scr->Root, _XA_MIT_PRIORITY_COLORS,
+ XA_CARDINAL, 32, PropModeAppend,
+ (unsigned char *)&pixel, 1);
+}
+
+/*
+ * do_string_savecolor() save a color from a string in the twmrc file.
+ */
+do_string_savecolor(colormode, s)
+ int colormode;
+ char *s;
+{
+ Pixel p;
+ GetColor(colormode, &p, s);
+ put_pixel_on_root(p);
+}
+
+/*
+ * do_var_savecolor() save a color from a var in the twmrc file.
+ */
+typedef struct _cnode {int i; struct _cnode *next;} Cnode, *Cptr;
+Cptr chead = NULL;
+
+do_var_savecolor(key)
+int key;
+{
+ Cptr cptrav, cpnew;
+ if (!chead) {
+ chead = (Cptr)malloc(sizeof(Cnode));
+ chead->i = key; chead->next = NULL;
+ }
+ else {
+ cptrav = chead;
+ while (cptrav->next != NULL) { cptrav = cptrav->next; }
+ cpnew = (Cptr)malloc(sizeof(Cnode));
+ cpnew->i = key; cpnew->next = NULL; cptrav->next = cpnew;
+ }
+}
+
+/*
+ * assign_var_savecolor() traverse the var save color list placeing the pixels
+ * in the root window property.
+ */
+void assign_var_savecolor()
+{
+ Cptr cp = chead;
+ while (cp != NULL) {
+ switch (cp->i) {
+ case kwcl_BorderColor:
+ put_pixel_on_root(Scr->BorderColor);
+ break;
+ case kwcl_IconManagerHighlight:
+ put_pixel_on_root(Scr->IconManagerHighlight);
+ break;
+ case kwcl_BorderTileForeground:
+ put_pixel_on_root(Scr->BorderTileC.fore);
+ break;
+ case kwcl_BorderTileBackground:
+ put_pixel_on_root(Scr->BorderTileC.back);
+ break;
+ case kwcl_TitleForeground:
+ put_pixel_on_root(Scr->TitleC.fore);
+ break;
+ case kwcl_TitleBackground:
+ put_pixel_on_root(Scr->TitleC.back);
+ break;
+ case kwcl_IconForeground:
+ put_pixel_on_root(Scr->IconC.fore);
+ break;
+ case kwcl_IconBackground:
+ put_pixel_on_root(Scr->IconC.back);
+ break;
+ case kwcl_IconBorderColor:
+ put_pixel_on_root(Scr->IconBorderColor);
+ break;
+ case kwcl_IconManagerForeground:
+ put_pixel_on_root(Scr->IconManagerC.fore);
+ break;
+ case kwcl_IconManagerBackground:
+ put_pixel_on_root(Scr->IconManagerC.back);
+ break;
+ }
+ cp = cp->next;
+ }
+ if (chead) {
+ free(chead);
+ chead = NULL;
+ }
+}
+
+static int ParseUsePPosition (s)
+ register char *s;
+{
+ XmuCopyISOLatin1Lowered (s, s);
+
+ if (strcmp (s, "off") == 0) {
+ return PPOS_OFF;
+ } else if (strcmp (s, "on") == 0) {
+ return PPOS_ON;
+ } else if (strcmp (s, "non-zero") == 0 ||
+ strcmp (s, "nonzero") == 0) {
+ return PPOS_NON_ZERO;
+ }
+
+ return -1;
+}
+
+
+do_squeeze_entry (list, name, justify, num, denom)
+ name_list **list; /* squeeze or dont-squeeze list */
+ char *name; /* window name */
+ int justify; /* left, center, right */
+ int num; /* signed num */
+ int denom; /* 0 or indicates fraction denom */
+{
+ int absnum = (num < 0 ? -num : num);
+
+ if (denom < 0) {
+ twmrc_error_prefix();
+ fprintf (stderr, "negative SqueezeTitle denominator %d\n", denom);
+ return;
+ }
+ if (absnum > denom && denom != 0) {
+ twmrc_error_prefix();
+ fprintf (stderr, "SqueezeTitle fraction %d/%d outside window\n",
+ num, denom);
+ return;
+ }
+ if (denom == 1) {
+ twmrc_error_prefix();
+ fprintf (stderr, "useless SqueezeTitle faction %d/%d, assuming 0/0\n",
+ num, denom);
+ num = 0;
+ denom = 0;
+ }
+
+ if (HasShape) {
+ SqueezeInfo *sinfo;
+ sinfo = (SqueezeInfo *) malloc (sizeof(SqueezeInfo));
+
+ if (!sinfo) {
+ twmrc_error_prefix();
+ fprintf (stderr, "unable to allocate %d bytes for squeeze info\n",
+ sizeof(SqueezeInfo));
+ return;
+ }
+ sinfo->justify = justify;
+ sinfo->num = num;
+ sinfo->denom = denom;
+ AddToList (list, name, (char *) sinfo);
+ }
+}
diff --git a/src/parse.h b/src/parse.h
new file mode 100644
index 0000000..68443c4
--- /dev/null
+++ b/src/parse.h
@@ -0,0 +1,135 @@
+/*****************************************************************************/
+/*
+
+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: parse.h,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * .twmrc parsing externs
+ *
+ * 8-Apr-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#ifndef _PARSE_
+#define _PARSE_
+
+extern int ParseTwmrc(), ParseStringList();
+extern int (*twmInputFunc)();
+extern void twmUnput();
+extern void TwmOutput();
+
+#define F_NOP 0
+#define F_BEEP 1
+#define F_RESTART 2
+#define F_QUIT 3
+#define F_FOCUS 4
+#define F_REFRESH 5
+#define F_WINREFRESH 6
+#define F_DELTASTOP 7
+#define F_MOVE 8
+#define F_POPUP 9
+#define F_FORCEMOVE 10
+#define F_AUTORAISE 11
+#define F_IDENTIFY 12
+#define F_ICONIFY 13
+#define F_DEICONIFY 14
+#define F_UNFOCUS 15
+#define F_RESIZE 16
+#define F_ZOOM 17
+#define F_LEFTZOOM 18
+#define F_RIGHTZOOM 19
+#define F_TOPZOOM 20
+#define F_BOTTOMZOOM 21
+#define F_HORIZOOM 22
+#define F_FULLZOOM 23
+#define F_RAISE 24
+#define F_RAISELOWER 25
+#define F_LOWER 26
+#define F_DESTROY 27
+#define F_DELETE 28
+#define F_SAVEYOURSELF 29
+#define F_VERSION 30
+#define F_TITLE 31
+#define F_RIGHTICONMGR 32
+#define F_LEFTICONMGR 33
+#define F_UPICONMGR 34
+#define F_DOWNICONMGR 35
+#define F_FORWICONMGR 36
+#define F_BACKICONMGR 37
+#define F_NEXTICONMGR 38
+#define F_PREVICONMGR 39
+#define F_SORTICONMGR 40
+#define F_CIRCLEUP 41
+#define F_CIRCLEDOWN 42
+#define F_CUTFILE 43
+#define F_SHOWLIST 44
+#define F_HIDELIST 45
+
+#define F_MENU 101 /* string */
+#define F_WARPTO 102 /* string */
+#define F_WARPTOICONMGR 103 /* string */
+#define F_WARPRING 104 /* string */
+#define F_FILE 105 /* string */
+#define F_EXEC 106 /* string */
+#define F_CUT 107 /* string */
+#define F_FUNCTION 108 /* string */
+#define F_WARPTOSCREEN 109 /* string */
+#define F_COLORMAP 110 /* string */
+#define F_PRIORITY 111 /* string */
+
+#define D_NORTH 1
+#define D_SOUTH 2
+#define D_EAST 3
+#define D_WEST 4
+
+#endif /* _PARSE_ */
diff --git a/src/resize.c b/src/resize.c
new file mode 100644
index 0000000..5c07ce9
--- /dev/null
+++ b/src/resize.c
@@ -0,0 +1,1217 @@
+/*****************************************************************************/
+/*
+
+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: resize.c,v 1.5 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * window resizing borrowed from the "wm" window manager
+ *
+ * 11-Dec-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include "parse.h"
+#include "util.h"
+#include "resize.h"
+#include "add_window.h"
+#include "screen.h"
+
+#define MINHEIGHT 0 /* had been 32 */
+#define MINWIDTH 0 /* had been 60 */
+
+static int dragx; /* all these variables are used */
+static int dragy; /* in resize operations */
+static int dragWidth;
+static int dragHeight;
+
+static int origx;
+static int origy;
+static int origWidth;
+static int origHeight;
+
+static int clampTop;
+static int clampBottom;
+static int clampLeft;
+static int clampRight;
+static int clampDX;
+static int clampDY;
+
+static int last_width;
+static int last_height;
+
+
+static void do_auto_clamp (tmp_win, evp)
+ TwmWindow *tmp_win;
+ XEvent *evp;
+{
+ Window junkRoot;
+ int x, y, h, v, junkbw;
+ unsigned int junkMask;
+
+ switch (evp->type) {
+ case ButtonPress:
+ x = evp->xbutton.x_root;
+ y = evp->xbutton.y_root;
+ break;
+ case KeyPress:
+ x = evp->xkey.x_root;
+ y = evp->xkey.y_root;
+ break;
+ default:
+ if (!XQueryPointer (dpy, Scr->Root, &junkRoot, &junkRoot,
+ &x, &y, &junkbw, &junkbw, &junkMask))
+ return;
+ }
+
+ h = ((x - dragx) / (dragWidth < 3 ? 1 : (dragWidth / 3)));
+ v = ((y - dragy - tmp_win->title_height) /
+ (dragHeight < 3 ? 1 : (dragHeight / 3)));
+
+ if (h <= 0) {
+ clampLeft = 1;
+ clampDX = (x - dragx);
+ } else if (h >= 2) {
+ clampRight = 1;
+ clampDX = (x - dragx - dragWidth);
+ }
+
+ if (v <= 0) {
+ clampTop = 1;
+ clampDY = (y - dragy);
+ } else if (v >= 2) {
+ clampBottom = 1;
+ clampDY = (y - dragy - dragHeight);
+ }
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * StartResize - begin a window resize operation
+ *
+ * Inputs:
+ * ev - the event structure (button press)
+ * tmp_win - the TwmWindow pointer
+ * fromtitlebar - action invoked from titlebar button
+ *
+ ***********************************************************************
+ */
+
+void
+StartResize(evp, tmp_win, fromtitlebar)
+XEvent *evp;
+TwmWindow *tmp_win;
+Bool fromtitlebar;
+{
+ Window junkRoot;
+ unsigned int junkbw, junkDepth;
+
+ ResizeWindow = tmp_win->frame;
+ XGrabServer(dpy);
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask | PointerMotionHintMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, Scr->ResizeCursor, CurrentTime);
+
+ XGetGeometry(dpy, (Drawable) tmp_win->frame, &junkRoot,
+ &dragx, &dragy, (unsigned int *)&dragWidth, (unsigned int *)&dragHeight, &junkbw,
+ &junkDepth);
+ dragx += tmp_win->frame_bw;
+ dragy += tmp_win->frame_bw;
+ origx = dragx;
+ origy = dragy;
+ origWidth = dragWidth;
+ origHeight = dragHeight;
+ clampTop = clampBottom = clampLeft = clampRight = clampDX = clampDY = 0;
+
+ if (Scr->AutoRelativeResize && !fromtitlebar)
+ do_auto_clamp (tmp_win, evp);
+
+ Scr->SizeStringOffset = SIZE_HINDENT;
+ XResizeWindow (dpy, Scr->SizeWindow,
+ Scr->SizeStringWidth + SIZE_HINDENT * 2,
+ Scr->SizeFont.height + SIZE_VINDENT * 2);
+ XMapRaised(dpy, Scr->SizeWindow);
+ InstallRootColormap();
+ last_width = 0;
+ last_height = 0;
+ DisplaySize(tmp_win, origWidth, origHeight);
+ MoveOutline (Scr->Root, dragx - tmp_win->frame_bw,
+ dragy - tmp_win->frame_bw, dragWidth + 2 * tmp_win->frame_bw,
+ dragHeight + 2 * tmp_win->frame_bw,
+ tmp_win->frame_bw, tmp_win->title_height);
+}
+
+
+
+void
+MenuStartResize(tmp_win, x, y, w, h)
+TwmWindow *tmp_win;
+int x, y, w, h;
+{
+ XGrabServer(dpy);
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonPressMask | ButtonMotionMask | PointerMotionMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, Scr->ResizeCursor, CurrentTime);
+ dragx = x + tmp_win->frame_bw;
+ dragy = y + tmp_win->frame_bw;
+ origx = dragx;
+ origy = dragy;
+ dragWidth = origWidth = w; /* - 2 * tmp_win->frame_bw; */
+ dragHeight = origHeight = h; /* - 2 * tmp_win->frame_bw; */
+ clampTop = clampBottom = clampLeft = clampRight = clampDX = clampDY = 0;
+ last_width = 0;
+ last_height = 0;
+ Scr->SizeStringOffset = SIZE_HINDENT;
+ XResizeWindow (dpy, Scr->SizeWindow,
+ Scr->SizeStringWidth + SIZE_HINDENT * 2,
+ Scr->SizeFont.height + SIZE_VINDENT * 2);
+ XMapRaised(dpy, Scr->SizeWindow);
+ DisplaySize(tmp_win, origWidth, origHeight);
+ MoveOutline (Scr->Root, dragx - tmp_win->frame_bw,
+ dragy - tmp_win->frame_bw,
+ dragWidth + 2 * tmp_win->frame_bw,
+ dragHeight + 2 * tmp_win->frame_bw,
+ tmp_win->frame_bw, tmp_win->title_height);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AddStartResize - begin a windorew resize operation from AddWindow
+ *
+ * Inputs:
+ * tmp_win - the TwmWindow pointer
+ *
+ ***********************************************************************
+ */
+
+void
+AddStartResize(tmp_win, x, y, w, h)
+TwmWindow *tmp_win;
+int x, y, w, h;
+{
+ XGrabServer(dpy);
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonReleaseMask | ButtonMotionMask | PointerMotionHintMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, Scr->ResizeCursor, CurrentTime);
+
+ dragx = x + tmp_win->frame_bw;
+ dragy = y + tmp_win->frame_bw;
+ origx = dragx;
+ origy = dragy;
+ dragWidth = origWidth = w - 2 * tmp_win->frame_bw;
+ dragHeight = origHeight = h - 2 * tmp_win->frame_bw;
+ clampTop = clampBottom = clampLeft = clampRight = clampDX = clampDY = 0;
+/*****
+ if (Scr->AutoRelativeResize) {
+ clampRight = clampBottom = 1;
+ }
+*****/
+ last_width = 0;
+ last_height = 0;
+ DisplaySize(tmp_win, origWidth, origHeight);
+}
+
+
+
+void
+MenuDoResize(x_root, y_root, tmp_win)
+int x_root;
+int y_root;
+TwmWindow *tmp_win;
+{
+ int action;
+
+ action = 0;
+
+ x_root -= clampDX;
+ y_root -= clampDY;
+
+ if (clampTop) {
+ int delta = y_root - dragy;
+ if (dragHeight - delta < MINHEIGHT) {
+ delta = dragHeight - MINHEIGHT;
+ clampTop = 0;
+ }
+ dragy += delta;
+ dragHeight -= delta;
+ action = 1;
+ }
+ else if (y_root <= dragy/* ||
+ y_root == findRootInfo(root)->rooty*/) {
+ dragy = y_root;
+ dragHeight = origy + origHeight -
+ y_root;
+ clampBottom = 0;
+ clampTop = 1;
+ clampDY = 0;
+ action = 1;
+ }
+ if (clampLeft) {
+ int delta = x_root - dragx;
+ if (dragWidth - delta < MINWIDTH) {
+ delta = dragWidth - MINWIDTH;
+ clampLeft = 0;
+ }
+ dragx += delta;
+ dragWidth -= delta;
+ action = 1;
+ }
+ else if (x_root <= dragx/* ||
+ x_root == findRootInfo(root)->rootx*/) {
+ dragx = x_root;
+ dragWidth = origx + origWidth -
+ x_root;
+ clampRight = 0;
+ clampLeft = 1;
+ clampDX = 0;
+ action = 1;
+ }
+ if (clampBottom) {
+ int delta = y_root - dragy - dragHeight;
+ if (dragHeight + delta < MINHEIGHT) {
+ delta = MINHEIGHT - dragHeight;
+ clampBottom = 0;
+ }
+ dragHeight += delta;
+ action = 1;
+ }
+ else if (y_root >= dragy + dragHeight) {
+ dragy = origy;
+ dragHeight = 1 + y_root - dragy;
+ clampTop = 0;
+ clampBottom = 1;
+ clampDY = 0;
+ action = 1;
+ }
+ if (clampRight) {
+ int delta = x_root - dragx - dragWidth;
+ if (dragWidth + delta < MINWIDTH) {
+ delta = MINWIDTH - dragWidth;
+ clampRight = 0;
+ }
+ dragWidth += delta;
+ action = 1;
+ }
+ else if (x_root >= dragx + dragWidth) {
+ dragx = origx;
+ dragWidth = 1 + x_root - origx;
+ clampLeft = 0;
+ clampRight = 1;
+ clampDX = 0;
+ action = 1;
+ }
+
+ if (action) {
+ ConstrainSize (tmp_win, &dragWidth, &dragHeight);
+ if (clampLeft)
+ dragx = origx + origWidth - dragWidth;
+ if (clampTop)
+ dragy = origy + origHeight - dragHeight;
+ MoveOutline(Scr->Root,
+ dragx - tmp_win->frame_bw,
+ dragy - tmp_win->frame_bw,
+ dragWidth + 2 * tmp_win->frame_bw,
+ dragHeight + 2 * tmp_win->frame_bw,
+ tmp_win->frame_bw, tmp_win->title_height);
+ }
+
+ DisplaySize(tmp_win, dragWidth, dragHeight);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * DoResize - move the rubberband around. This is called for
+ * each motion event when we are resizing
+ *
+ * Inputs:
+ * x_root - the X corrdinate in the root window
+ * y_root - the Y corrdinate in the root window
+ * tmp_win - the current twm window
+ *
+ ***********************************************************************
+ */
+
+void
+DoResize(x_root, y_root, tmp_win)
+int x_root;
+int y_root;
+TwmWindow *tmp_win;
+{
+ int action;
+
+ action = 0;
+
+ x_root -= clampDX;
+ y_root -= clampDY;
+
+ if (clampTop) {
+ int delta = y_root - dragy;
+ if (dragHeight - delta < MINHEIGHT) {
+ delta = dragHeight - MINHEIGHT;
+ clampTop = 0;
+ }
+ dragy += delta;
+ dragHeight -= delta;
+ action = 1;
+ }
+ else if (y_root <= dragy/* ||
+ y_root == findRootInfo(root)->rooty*/) {
+ dragy = y_root;
+ dragHeight = origy + origHeight -
+ y_root;
+ clampBottom = 0;
+ clampTop = 1;
+ clampDY = 0;
+ action = 1;
+ }
+ if (clampLeft) {
+ int delta = x_root - dragx;
+ if (dragWidth - delta < MINWIDTH) {
+ delta = dragWidth - MINWIDTH;
+ clampLeft = 0;
+ }
+ dragx += delta;
+ dragWidth -= delta;
+ action = 1;
+ }
+ else if (x_root <= dragx/* ||
+ x_root == findRootInfo(root)->rootx*/) {
+ dragx = x_root;
+ dragWidth = origx + origWidth -
+ x_root;
+ clampRight = 0;
+ clampLeft = 1;
+ clampDX = 0;
+ action = 1;
+ }
+ if (clampBottom) {
+ int delta = y_root - dragy - dragHeight;
+ if (dragHeight + delta < MINHEIGHT) {
+ delta = MINHEIGHT - dragHeight;
+ clampBottom = 0;
+ }
+ dragHeight += delta;
+ action = 1;
+ }
+ else if (y_root >= dragy + dragHeight - 1/* ||
+ y_root == findRootInfo(root)->rooty
+ + findRootInfo(root)->rootheight - 1*/) {
+ dragy = origy;
+ dragHeight = 1 + y_root - dragy;
+ clampTop = 0;
+ clampBottom = 1;
+ clampDY = 0;
+ action = 1;
+ }
+ if (clampRight) {
+ int delta = x_root - dragx - dragWidth;
+ if (dragWidth + delta < MINWIDTH) {
+ delta = MINWIDTH - dragWidth;
+ clampRight = 0;
+ }
+ dragWidth += delta;
+ action = 1;
+ }
+ else if (x_root >= dragx + dragWidth - 1/* ||
+ x_root == findRootInfo(root)->rootx +
+ findRootInfo(root)->rootwidth - 1*/) {
+ dragx = origx;
+ dragWidth = 1 + x_root - origx;
+ clampLeft = 0;
+ clampRight = 1;
+ clampDX = 0;
+ action = 1;
+ }
+
+ if (action) {
+ ConstrainSize (tmp_win, &dragWidth, &dragHeight);
+ if (clampLeft)
+ dragx = origx + origWidth - dragWidth;
+ if (clampTop)
+ dragy = origy + origHeight - dragHeight;
+ MoveOutline(Scr->Root,
+ dragx - tmp_win->frame_bw,
+ dragy - tmp_win->frame_bw,
+ dragWidth + 2 * tmp_win->frame_bw,
+ dragHeight + 2 * tmp_win->frame_bw,
+ tmp_win->frame_bw, tmp_win->title_height);
+ }
+
+ DisplaySize(tmp_win, dragWidth, dragHeight);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * DisplaySize - display the size in the dimensions window
+ *
+ * Inputs:
+ * tmp_win - the current twm window
+ * width - the width of the rubber band
+ * height - the height of the rubber band
+ *
+ ***********************************************************************
+ */
+
+void
+DisplaySize(tmp_win, width, height)
+TwmWindow *tmp_win;
+int width;
+int height;
+{
+ char str[100];
+ int dwidth;
+ int dheight;
+
+ if (last_width == width && last_height == height)
+ return;
+
+ last_width = width;
+ last_height = height;
+
+ dheight = height - tmp_win->title_height;
+ dwidth = width;
+
+ /*
+ * ICCCM says that PMinSize is the default is no PBaseSize is given,
+ * and vice-versa.
+ */
+ if (tmp_win->hints.flags&(PMinSize|PBaseSize) && tmp_win->hints.flags & PResizeInc)
+ {
+ if (tmp_win->hints.flags & PBaseSize) {
+ dwidth -= tmp_win->hints.base_width;
+ dheight -= tmp_win->hints.base_height;
+ } else {
+ dwidth -= tmp_win->hints.min_width;
+ dheight -= tmp_win->hints.min_height;
+ }
+ }
+
+ if (tmp_win->hints.flags & PResizeInc)
+ {
+ dwidth /= tmp_win->hints.width_inc;
+ dheight /= tmp_win->hints.height_inc;
+ }
+
+ (void) sprintf (str, " %4d x %-4d ", dwidth, dheight);
+ XRaiseWindow(dpy, Scr->SizeWindow);
+ FBF(Scr->DefaultC.fore, Scr->DefaultC.back, Scr->SizeFont.font->fid);
+ XDrawImageString (dpy, Scr->SizeWindow, Scr->NormalGC,
+ Scr->SizeStringOffset,
+ Scr->SizeFont.font->ascent + SIZE_VINDENT,
+ str, 13);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * EndResize - finish the resize operation
+ *
+ ***********************************************************************
+ */
+
+void
+EndResize()
+{
+ TwmWindow *tmp_win;
+
+#ifdef DEBUG
+ fprintf(stderr, "EndResize\n");
+#endif
+
+ MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+ XUnmapWindow(dpy, Scr->SizeWindow);
+
+ XFindContext(dpy, ResizeWindow, TwmContext, (caddr_t *)&tmp_win);
+
+ ConstrainSize (tmp_win, &dragWidth, &dragHeight);
+
+ if (dragWidth != tmp_win->frame_width ||
+ dragHeight != tmp_win->frame_height)
+ tmp_win->zoomed = ZOOM_NONE;
+
+ SetupWindow (tmp_win, dragx - tmp_win->frame_bw, dragy - tmp_win->frame_bw,
+ dragWidth, dragHeight, -1);
+
+ if (tmp_win->iconmgr)
+ {
+ int ncols = tmp_win->iconmgrp->cur_columns;
+ if (ncols == 0) ncols = 1;
+
+ tmp_win->iconmgrp->width = (int) ((dragWidth *
+ (long) tmp_win->iconmgrp->columns)
+ / ncols);
+ PackIconManager(tmp_win->iconmgrp);
+ }
+
+ if (!Scr->NoRaiseResize)
+ XRaiseWindow(dpy, tmp_win->frame);
+
+ UninstallRootColormap();
+
+ ResizeWindow = None;
+}
+
+void
+MenuEndResize(tmp_win)
+TwmWindow *tmp_win;
+{
+ MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+ XUnmapWindow(dpy, Scr->SizeWindow);
+ ConstrainSize (tmp_win, &dragWidth, &dragHeight);
+ AddingX = dragx;
+ AddingY = dragy;
+ AddingW = dragWidth + (2 * tmp_win->frame_bw);
+ AddingH = dragHeight + (2 * tmp_win->frame_bw);
+ SetupWindow (tmp_win, AddingX, AddingY, AddingW, AddingH, -1);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AddEndResize - finish the resize operation for AddWindo<w
+ *
+ ***********************************************************************
+ */
+
+void
+AddEndResize(tmp_win)
+TwmWindow *tmp_win;
+{
+
+#ifdef DEBUG
+ fprintf(stderr, "AddEndResize\n");
+#endif
+
+ ConstrainSize (tmp_win, &dragWidth, &dragHeight);
+ AddingX = dragx;
+ AddingY = dragy;
+ AddingW = dragWidth + (2 * tmp_win->frame_bw);
+ AddingH = dragHeight + (2 * tmp_win->frame_bw);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * ConstrainSize - adjust the given width and height to account for the
+ * constraints imposed by size hints
+ *
+ * The general algorithm, especially the aspect ratio stuff, is
+ * borrowed from uwm's CheckConsistency routine.
+ *
+ ***********************************************************************/
+
+ConstrainSize (tmp_win, widthp, heightp)
+ TwmWindow *tmp_win;
+ int *widthp, *heightp;
+{
+#define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
+#define _min(a,b) (((a) < (b)) ? (a) : (b))
+
+ int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta;
+ int baseWidth, baseHeight;
+ int dwidth = *widthp, dheight = *heightp;
+
+
+ dheight -= tmp_win->title_height;
+
+ if (tmp_win->hints.flags & PMinSize) {
+ minWidth = tmp_win->hints.min_width;
+ minHeight = tmp_win->hints.min_height;
+ } else if (tmp_win->hints.flags & PBaseSize) {
+ minWidth = tmp_win->hints.base_width;
+ minHeight = tmp_win->hints.base_height;
+ } else
+ minWidth = minHeight = 1;
+
+ if (tmp_win->hints.flags & PBaseSize) {
+ baseWidth = tmp_win->hints.base_width;
+ baseHeight = tmp_win->hints.base_height;
+ } else if (tmp_win->hints.flags & PMinSize) {
+ baseWidth = tmp_win->hints.min_width;
+ baseHeight = tmp_win->hints.min_height;
+ } else
+ baseWidth = baseHeight = 0;
+
+
+ if (tmp_win->hints.flags & PMaxSize) {
+ maxWidth = _min (Scr->MaxWindowWidth, tmp_win->hints.max_width);
+ maxHeight = _min (Scr->MaxWindowHeight, tmp_win->hints.max_height);
+ } else {
+ maxWidth = Scr->MaxWindowWidth;
+ maxHeight = Scr->MaxWindowHeight;
+ }
+
+ if (tmp_win->hints.flags & PResizeInc) {
+ xinc = tmp_win->hints.width_inc;
+ yinc = tmp_win->hints.height_inc;
+ } else
+ xinc = yinc = 1;
+
+ /*
+ * First, clamp to min and max values
+ */
+ if (dwidth < minWidth) dwidth = minWidth;
+ if (dheight < minHeight) dheight = minHeight;
+
+ if (dwidth > maxWidth) dwidth = maxWidth;
+ if (dheight > maxHeight) dheight = maxHeight;
+
+
+ /*
+ * Second, fit to base + N * inc
+ */
+ dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth;
+ dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight;
+
+
+ /*
+ * Third, adjust for aspect ratio
+ */
+#define maxAspectX tmp_win->hints.max_aspect.x
+#define maxAspectY tmp_win->hints.max_aspect.y
+#define minAspectX tmp_win->hints.min_aspect.x
+#define minAspectY tmp_win->hints.min_aspect.y
+ /*
+ * The math looks like this:
+ *
+ * minAspectX dwidth maxAspectX
+ * ---------- <= ------- <= ----------
+ * minAspectY dheight maxAspectY
+ *
+ * If that is multiplied out, then the width and height are
+ * invalid in the following situations:
+ *
+ * minAspectX * dheight > minAspectY * dwidth
+ * maxAspectX * dheight < maxAspectY * dwidth
+ *
+ */
+
+ if (tmp_win->hints.flags & PAspect)
+ {
+ if (minAspectX * dheight > minAspectY * dwidth)
+ {
+ delta = makemult(minAspectX * dheight / minAspectY - dwidth,
+ xinc);
+ if (dwidth + delta <= maxWidth) dwidth += delta;
+ else
+ {
+ delta = makemult(dheight - dwidth*minAspectY/minAspectX,
+ yinc);
+ if (dheight - delta >= minHeight) dheight -= delta;
+ }
+ }
+
+ if (maxAspectX * dheight < maxAspectY * dwidth)
+ {
+ delta = makemult(dwidth * maxAspectY / maxAspectX - dheight,
+ yinc);
+ if (dheight + delta <= maxHeight) dheight += delta;
+ else
+ {
+ delta = makemult(dwidth - maxAspectX*dheight/maxAspectY,
+ xinc);
+ if (dwidth - delta >= minWidth) dwidth -= delta;
+ }
+ }
+ }
+
+
+ /*
+ * Fourth, account for border width and title height
+ */
+ *widthp = dwidth;
+ *heightp = dheight + tmp_win->title_height;
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * SetupWindow - set window sizes, this was called from either
+ * AddWindow, EndResize, or HandleConfigureNotify.
+ *
+ * Inputs:
+ * tmp_win - the TwmWindow pointer
+ * x - the x coordinate of the upper-left outer corner of the frame
+ * y - the y coordinate of the upper-left outer corner of the frame
+ * w - the width of the frame window w/o border
+ * h - the height of the frame window w/o border
+ * bw - the border width of the frame window or -1 not to change
+ *
+ * Special Considerations:
+ * This routine will check to make sure the window is not completely
+ * off the display, if it is, it'll bring some of it back on.
+ *
+ * The tmp_win->frame_XXX variables should NOT be updated with the
+ * values of x,y,w,h prior to calling this routine, since the new
+ * values are compared against the old to see whether a synthetic
+ * ConfigureNotify event should be sent. (It should be sent if the
+ * window was moved but not resized.)
+ *
+ ***********************************************************************
+ */
+
+void SetupWindow (tmp_win, x, y, w, h, bw)
+ TwmWindow *tmp_win;
+ int x, y, w, h, bw;
+{
+ SetupFrame (tmp_win, x, y, w, h, bw, False);
+}
+
+void SetupFrame (tmp_win, x, y, w, h, bw, sendEvent)
+ TwmWindow *tmp_win;
+ int x, y, w, h, bw;
+ Bool sendEvent; /* whether or not to force a send */
+{
+ XEvent client_event;
+ XWindowChanges frame_wc, xwc;
+ unsigned long frame_mask, xwcm;
+ int title_width, title_height;
+ int reShape;
+
+#ifdef DEBUG
+ fprintf (stderr, "SetupWindow: x=%d, y=%d, w=%d, h=%d, bw=%d\n",
+ x, y, w, h, bw);
+#endif
+
+ if (x >= Scr->MyDisplayWidth)
+ x = Scr->MyDisplayWidth - 16; /* one "average" cursor width */
+ if (y >= Scr->MyDisplayHeight)
+ y = Scr->MyDisplayHeight - 16; /* one "average" cursor width */
+ if (bw < 0)
+ bw = tmp_win->frame_bw; /* -1 means current frame width */
+
+ if (tmp_win->iconmgr) {
+ tmp_win->iconmgrp->width = w;
+ h = tmp_win->iconmgrp->height + tmp_win->title_height;
+ }
+
+ /*
+ * According to the July 27, 1988 ICCCM draft, we should send a
+ * "synthetic" ConfigureNotify event to the client if the window
+ * was moved but not resized.
+ */
+ if (((x != tmp_win->frame_x || y != tmp_win->frame_y) &&
+ (w == tmp_win->frame_width && h == tmp_win->frame_height)) ||
+ (bw != tmp_win->frame_bw))
+ sendEvent = TRUE;
+
+ xwcm = CWWidth;
+ title_width = xwc.width = w;
+ title_height = Scr->TitleHeight + bw;
+
+ ComputeWindowTitleOffsets (tmp_win, xwc.width, True);
+
+ reShape = (tmp_win->wShaped ? TRUE : FALSE);
+ if (tmp_win->squeeze_info) /* check for title shaping */
+ {
+ title_width = tmp_win->rightx + Scr->TBInfo.rightoff;
+ if (title_width < xwc.width)
+ {
+ xwc.width = title_width;
+ if (tmp_win->frame_height != h ||
+ tmp_win->frame_width != w ||
+ tmp_win->frame_bw != bw ||
+ title_width != tmp_win->title_width)
+ reShape = TRUE;
+ }
+ else
+ {
+ if (!tmp_win->wShaped) reShape = TRUE;
+ title_width = xwc.width;
+ }
+ }
+
+ tmp_win->title_width = title_width;
+ if (tmp_win->title_height) tmp_win->title_height = title_height;
+
+ if (tmp_win->title_w) {
+ if (bw != tmp_win->frame_bw) {
+ xwc.border_width = bw;
+ tmp_win->title_x = xwc.x = -bw;
+ tmp_win->title_y = xwc.y = -bw;
+ xwcm |= (CWX | CWY | CWBorderWidth);
+ }
+
+ XConfigureWindow(dpy, tmp_win->title_w, xwcm, &xwc);
+ }
+
+ if (tmp_win->attr.width != w)
+ tmp_win->widthEverChangedByUser = True;
+
+ if (tmp_win->attr.height != (h - tmp_win->title_height))
+ tmp_win->heightEverChangedByUser = True;
+
+ tmp_win->attr.width = w;
+ tmp_win->attr.height = h - tmp_win->title_height;
+
+ XMoveResizeWindow (dpy, tmp_win->w, 0, tmp_win->title_height,
+ w, h - tmp_win->title_height);
+
+ /*
+ * fix up frame and assign size/location values in tmp_win
+ */
+ frame_mask = 0;
+ if (bw != tmp_win->frame_bw) {
+ frame_wc.border_width = tmp_win->frame_bw = bw;
+ frame_mask |= CWBorderWidth;
+ }
+ frame_wc.x = tmp_win->frame_x = x;
+ frame_wc.y = tmp_win->frame_y = y;
+ frame_wc.width = tmp_win->frame_width = w;
+ frame_wc.height = tmp_win->frame_height = h;
+ frame_mask |= (CWX | CWY | CWWidth | CWHeight);
+ XConfigureWindow (dpy, tmp_win->frame, frame_mask, &frame_wc);
+
+ /*
+ * fix up highlight window
+ */
+ if (tmp_win->title_height && tmp_win->hilite_w)
+ {
+ xwc.width = (tmp_win->rightx - tmp_win->highlightx);
+ if (Scr->TBInfo.nright > 0) xwc.width -= Scr->TitlePadding;
+ if (xwc.width <= 0) {
+ xwc.x = Scr->MyDisplayWidth; /* move offscreen */
+ xwc.width = 1;
+ } else {
+ xwc.x = tmp_win->highlightx;
+ }
+
+ xwcm = CWX | CWWidth;
+ XConfigureWindow(dpy, tmp_win->hilite_w, xwcm, &xwc);
+ }
+
+ if (HasShape && reShape) {
+ SetFrameShape (tmp_win);
+ }
+
+ if (sendEvent)
+ {
+ client_event.type = ConfigureNotify;
+ client_event.xconfigure.display = dpy;
+ client_event.xconfigure.event = tmp_win->w;
+ client_event.xconfigure.window = tmp_win->w;
+ client_event.xconfigure.x = (x + tmp_win->frame_bw - tmp_win->old_bw);
+ client_event.xconfigure.y = (y + tmp_win->frame_bw +
+ tmp_win->title_height - tmp_win->old_bw);
+ client_event.xconfigure.width = tmp_win->frame_width;
+ client_event.xconfigure.height = tmp_win->frame_height -
+ tmp_win->title_height;
+ client_event.xconfigure.border_width = tmp_win->old_bw;
+ /* Real ConfigureNotify events say we're above title window, so ... */
+ /* what if we don't have a title ????? */
+ client_event.xconfigure.above = tmp_win->frame;
+ client_event.xconfigure.override_redirect = False;
+ XSendEvent(dpy, tmp_win->w, False, StructureNotifyMask, &client_event);
+ }
+}
+
+
+/**********************************************************************
+ * Rutgers mod #1 - rocky.
+ * Procedure:
+ * fullzoom - zooms window to full height of screen or
+ * to full height and width of screen. (Toggles
+ * so that it can undo the zoom - even when switching
+ * between fullzoom and vertical zoom.)
+ *
+ * Inputs:
+ * tmp_win - the TwmWindow pointer
+ *
+ *
+ **********************************************************************
+ */
+
+void
+fullzoom(tmp_win,flag)
+TwmWindow *tmp_win;
+int flag;
+{
+ Window junkRoot;
+ unsigned int junkbw, junkDepth;
+ int basex, basey;
+ int frame_bw_times_2;
+
+ XGetGeometry(dpy, (Drawable) tmp_win->frame, &junkRoot,
+ &dragx, &dragy, (unsigned int *)&dragWidth, (unsigned int *)&dragHeight, &junkbw,
+ &junkDepth);
+
+ basex = 0;
+ basey = 0;
+
+ if (tmp_win->zoomed == flag)
+ {
+ dragHeight = tmp_win->save_frame_height;
+ dragWidth = tmp_win->save_frame_width;
+ dragx = tmp_win->save_frame_x;
+ dragy = tmp_win->save_frame_y;
+ tmp_win->zoomed = ZOOM_NONE;
+ }
+ else
+ {
+ if (tmp_win->zoomed == ZOOM_NONE)
+ {
+ tmp_win->save_frame_x = dragx;
+ tmp_win->save_frame_y = dragy;
+ tmp_win->save_frame_width = dragWidth;
+ tmp_win->save_frame_height = dragHeight;
+ tmp_win->zoomed = flag;
+ }
+ else
+ tmp_win->zoomed = flag;
+
+
+ frame_bw_times_2 = 2*tmp_win->frame_bw;
+
+ switch (flag)
+ {
+ case ZOOM_NONE:
+ break;
+ case F_ZOOM:
+ dragHeight = Scr->MyDisplayHeight - frame_bw_times_2;
+ dragy=basey;
+ break;
+ case F_HORIZOOM:
+ dragx = basex;
+ dragWidth = Scr->MyDisplayWidth - frame_bw_times_2;
+ break;
+ case F_FULLZOOM:
+ dragx = basex;
+ dragy = basey;
+ dragHeight = Scr->MyDisplayHeight - frame_bw_times_2;
+ dragWidth = Scr->MyDisplayWidth - frame_bw_times_2;
+ break;
+ case F_LEFTZOOM:
+ dragx = basex;
+ dragy = basey;
+ dragHeight = Scr->MyDisplayHeight - frame_bw_times_2;
+ dragWidth = Scr->MyDisplayWidth/2 - frame_bw_times_2;
+ break;
+ case F_RIGHTZOOM:
+ dragx = basex + Scr->MyDisplayWidth/2;
+ dragy = basey;
+ dragHeight = Scr->MyDisplayHeight - frame_bw_times_2;
+ dragWidth = Scr->MyDisplayWidth/2 - frame_bw_times_2;
+ break;
+ case F_TOPZOOM:
+ dragx = basex;
+ dragy = basey;
+ dragHeight = Scr->MyDisplayHeight/2 - frame_bw_times_2;
+ dragWidth = Scr->MyDisplayWidth - frame_bw_times_2;
+ break;
+ case F_BOTTOMZOOM:
+ dragx = basex;
+ dragy = basey + Scr->MyDisplayHeight/2;
+ dragHeight = Scr->MyDisplayHeight/2 - frame_bw_times_2;
+ dragWidth = Scr->MyDisplayWidth - frame_bw_times_2;
+ break;
+ }
+ }
+
+ if (!Scr->NoRaiseResize)
+ XRaiseWindow(dpy, tmp_win->frame);
+
+ ConstrainSize(tmp_win, &dragWidth, &dragHeight);
+
+ SetupWindow (tmp_win, dragx , dragy , dragWidth, dragHeight, -1);
+ XUngrabPointer (dpy, CurrentTime);
+ XUngrabServer (dpy);
+}
+
+SetFrameShape (tmp)
+ TwmWindow *tmp;
+{
+ /*
+ * see if the titlebar needs to move
+ */
+ if (tmp->title_w) {
+ int oldx = tmp->title_x, oldy = tmp->title_y;
+ ComputeTitleLocation (tmp);
+ if (oldx != tmp->title_x || oldy != tmp->title_y)
+ XMoveWindow (dpy, tmp->title_w, tmp->title_x, tmp->title_y);
+ }
+
+ /*
+ * The frame consists of the shape of the contents window offset by
+ * title_height or'ed with the shape of title_w (which is always
+ * rectangular).
+ */
+ if (tmp->wShaped) {
+ /*
+ * need to do general case
+ */
+ XShapeCombineShape (dpy, tmp->frame, ShapeBounding,
+ 0, tmp->title_height, tmp->w,
+ ShapeBounding, ShapeSet);
+ if (tmp->title_w) {
+ XShapeCombineShape (dpy, tmp->frame, ShapeBounding,
+ tmp->title_x + tmp->frame_bw,
+ tmp->title_y + tmp->frame_bw,
+ tmp->title_w, ShapeBounding,
+ ShapeUnion);
+ }
+ } else {
+ /*
+ * can optimize rectangular contents window
+ */
+ if (tmp->squeeze_info) {
+ XRectangle newBounding[2];
+ XRectangle newClip[2];
+ int fbw2 = 2 * tmp->frame_bw;
+
+ /*
+ * Build the border clipping rectangles; one around title, one
+ * around window. The title_[xy] field already have had frame_bw
+ * subtracted off them so that they line up properly in the frame.
+ *
+ * The frame_width and frame_height do *not* include borders.
+ */
+ /* border */
+ newBounding[0].x = tmp->title_x;
+ newBounding[0].y = tmp->title_y;
+ newBounding[0].width = tmp->title_width + fbw2;
+ newBounding[0].height = tmp->title_height;
+ newBounding[1].x = -tmp->frame_bw;
+ newBounding[1].y = Scr->TitleHeight;
+ newBounding[1].width = tmp->attr.width + fbw2;
+ newBounding[1].height = tmp->attr.height + fbw2;
+ XShapeCombineRectangles (dpy, tmp->frame, ShapeBounding, 0, 0,
+ newBounding, 2, ShapeSet, YXBanded);
+ /* insides */
+ newClip[0].x = tmp->title_x + tmp->frame_bw;
+ newClip[0].y = 0;
+ newClip[0].width = tmp->title_width;
+ newClip[0].height = Scr->TitleHeight;
+ newClip[1].x = 0;
+ newClip[1].y = tmp->title_height;
+ newClip[1].width = tmp->attr.width;
+ newClip[1].height = tmp->attr.height;
+ XShapeCombineRectangles (dpy, tmp->frame, ShapeClip, 0, 0,
+ newClip, 2, ShapeSet, YXBanded);
+ } else {
+ (void) XShapeCombineMask (dpy, tmp->frame, ShapeBounding, 0, 0,
+ None, ShapeSet);
+ (void) XShapeCombineMask (dpy, tmp->frame, ShapeClip, 0, 0,
+ None, ShapeSet);
+ }
+ }
+}
+
+/*
+ * Squeezed Title:
+ *
+ * tmp->title_x
+ * 0 |
+ * tmp->title_y ........+--------------+......... -+,- tmp->frame_bw
+ * 0 : ......| +----------+ |....... : -++
+ * : : | | | | : : ||-Scr->TitleHeight
+ * : : | | | | : : ||
+ * +-------+ +----------+ +--------+ -+|-tmp->title_height
+ * | +---------------------------+ | --+
+ * | | | |
+ * | | | |
+ * | | | |
+ * | | | |
+ * | | | |
+ * | +---------------------------+ |
+ * +-------------------------------+
+ *
+ *
+ * Unsqueezed Title:
+ *
+ * tmp->title_x
+ * | 0
+ * tmp->title_y +-------------------------------+ -+,tmp->frame_bw
+ * 0 | +---------------------------+ | -+'
+ * | | | | |-Scr->TitleHeight
+ * | | | | |
+ * + +---------------------------+ + -+
+ * |-+---------------------------+-|
+ * | | | |
+ * | | | |
+ * | | | |
+ * | | | |
+ * | | | |
+ * | +---------------------------+ |
+ * +-------------------------------+
+ *
+ *
+ *
+ * Dimensions and Positions:
+ *
+ * frame orgin (0, 0)
+ * frame upper left border (-tmp->frame_bw, -tmp->frame_bw)
+ * frame size w/o border tmp->frame_width , tmp->frame_height
+ * frame/title border width tmp->frame_bw
+ * extra title height w/o bdr tmp->title_height = TitleHeight + frame_bw
+ * title window height Scr->TitleHeight
+ * title origin w/o border (tmp->title_x, tmp->title_y)
+ * client origin (0, Scr->TitleHeight + tmp->frame_bw)
+ * client size tmp->attr.width , tmp->attr.height
+ *
+ * When shaping, need to remember that the width and height of rectangles
+ * are really deltax and deltay to lower right handle corner, so they need
+ * to have -1 subtracted from would normally be the actual extents.
+ */
diff --git a/src/resize.h b/src/resize.h
new file mode 100644
index 0000000..742045e
--- /dev/null
+++ b/src/resize.h
@@ -0,0 +1,77 @@
+/*****************************************************************************/
+/*
+
+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: resize.h,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * resize function externs
+ *
+ * 8-Apr-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#ifndef _RESIZE_
+#define _RESIZE_
+
+extern void StartResize();
+extern void AddStartResize();
+extern void DoResize();
+extern void DisplaySize();
+extern void EndResize();
+extern void AddEndResize();
+extern void SetupWindow();
+extern void SetupFrame();
+
+#endif /* _RESIZE_ */
+
+extern void fullzoom();
diff --git a/src/screen.h b/src/screen.h
new file mode 100644
index 0000000..c47bc70
--- /dev/null
+++ b/src/screen.h
@@ -0,0 +1,267 @@
+/*
+ *
+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.
+ * */
+
+/***********************************************************************
+ *
+ * $Xorg: screen.h,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * twm per-screen data include file
+ *
+ * 11-3-88 Dave Payne, Apple Computer File created
+ *
+ ***********************************************************************/
+
+#ifndef _SCREEN_
+#define _SCREEN_
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include "list.h"
+#include "menus.h"
+#include "iconmgr.h"
+
+typedef struct _StdCmap {
+ struct _StdCmap *next; /* next link in chain */
+ Atom atom; /* property from which this came */
+ int nmaps; /* number of maps below */
+ XStandardColormap *maps; /* the actual maps */
+} StdCmap;
+
+#define SIZE_HINDENT 10
+#define SIZE_VINDENT 2
+
+typedef struct _TitlebarPixmaps {
+ Pixmap xlogo;
+ Pixmap resize;
+ Pixmap question;
+ Pixmap menu;
+ Pixmap delete;
+} TitlebarPixmaps;
+
+typedef struct ScreenInfo
+{
+ int screen; /* the default screen */
+ int d_depth; /* copy of DefaultDepth(dpy, screen) */
+ Visual *d_visual; /* copy of DefaultVisual(dpy, screen) */
+ int Monochrome; /* is the display monochrome ? */
+ int MyDisplayWidth; /* my copy of DisplayWidth(dpy, screen) */
+ int MyDisplayHeight; /* my copy of DisplayHeight(dpy, screen) */
+ int MaxWindowWidth; /* largest window to allow */
+ int MaxWindowHeight; /* ditto */
+
+ TwmWindow TwmRoot; /* the head of the twm window list */
+
+ Window Root; /* the root window */
+ Window SizeWindow; /* the resize dimensions window */
+ Window InfoWindow; /* the information window */
+
+ name_list *Icons; /* list of icon pixmaps */
+ TitlebarPixmaps tbpm; /* titlebar pixmaps */
+ Pixmap UnknownPm; /* the unknown icon pixmap */
+ Pixmap siconifyPm; /* the icon manager iconify pixmap */
+ Pixmap pullPm; /* pull right menu icon */
+ int pullW, pullH; /* size of pull right menu icon */
+ Pixmap hilitePm; /* focus highlight window background */
+ int hilite_pm_width, hilite_pm_height; /* cache the size */
+
+ MenuRoot *MenuList; /* head of the menu list */
+ MenuRoot *LastMenu; /* the last menu (mostly unused?) */
+ MenuRoot *Windows; /* the TwmWindows menu */
+
+ TwmWindow *Ring; /* one of the windows in window ring */
+ TwmWindow *RingLeader; /* current winodw in ring */
+
+ MouseButton Mouse[MAX_BUTTONS+1][NUM_CONTEXTS][MOD_SIZE];
+ MouseButton DefaultFunction;
+ MouseButton WindowFunction;
+
+ struct {
+ Colormaps *cmaps; /* current list of colormap windows */
+ int maxCmaps; /* maximum number of installed colormaps */
+ unsigned long first_req; /* seq # for first XInstallColormap() req in
+ pass thru loading a colortable list */
+ int root_pushes; /* current push level to install root
+ colormap windows */
+ TwmWindow *pushed_window; /* saved window to install when pushes drops
+ to zero */
+ } cmapInfo;
+
+ struct {
+ StdCmap *head, *tail; /* list of maps */
+ StdCmap *mru; /* most recently used in list */
+ int mruindex; /* index of mru in entry */
+ } StdCmapInfo;
+
+ struct {
+ int nleft, nright; /* numbers of buttons in list */
+ TitleButton *head; /* start of list */
+ int border; /* button border */
+ int pad; /* button-padding */
+ int width; /* width of single button & border */
+ int leftx; /* start of left buttons */
+ int titlex; /* start of title string */
+ int rightoff; /* offset back from right edge */
+ } TBInfo;
+ ColorPair BorderTileC; /* border tile colors */
+ ColorPair TitleC; /* titlebar colors */
+ ColorPair MenuC; /* menu colors */
+ ColorPair MenuTitleC; /* menu title colors */
+ ColorPair IconC; /* icon colors */
+ ColorPair IconManagerC; /* icon manager colors */
+ XColor PointerForeground; /* pointer foreground color */
+ XColor PointerBackground; /* pointer background color */
+ ColorPair DefaultC; /* default colors */
+ Pixel BorderColor; /* color of window borders */
+ Pixel MenuShadowColor; /* menu shadow color */
+ Pixel IconBorderColor; /* icon border color */
+ Pixel IconManagerHighlight; /* icon manager highlight */
+
+ Cursor TitleCursor; /* title bar cursor */
+ Cursor FrameCursor; /* frame cursor */
+ Cursor IconCursor; /* icon cursor */
+ Cursor IconMgrCursor; /* icon manager cursor */
+ Cursor ButtonCursor; /* title bar button cursor */
+ Cursor MoveCursor; /* move cursor */
+ Cursor ResizeCursor; /* resize cursor */
+ Cursor WaitCursor; /* wait a while cursor */
+ Cursor MenuCursor; /* menu cursor */
+ Cursor SelectCursor; /* dot cursor for f.move, etc. from menus */
+ Cursor DestroyCursor; /* skull and cross bones, f.destroy */
+
+ name_list *BorderColorL;
+ name_list *IconBorderColorL;
+ name_list *BorderTileForegroundL;
+ name_list *BorderTileBackgroundL;
+ name_list *TitleForegroundL;
+ name_list *TitleBackgroundL;
+ name_list *IconForegroundL;
+ name_list *IconBackgroundL;
+ name_list *IconManagerFL;
+ name_list *IconManagerBL;
+ name_list *IconMgrs;
+ name_list *NoTitle; /* list of window names with no title bar */
+ name_list *MakeTitle; /* list of window names with title bar */
+ name_list *AutoRaise; /* list of window names to auto-raise */
+ name_list *IconNames; /* list of window names and icon names */
+ name_list *NoHighlight; /* list of windows to not highlight */
+ name_list *NoStackModeL; /* windows to ignore stack mode requests */
+ name_list *NoTitleHighlight;/* list of windows to not highlight the TB*/
+ name_list *DontIconify; /* don't iconify by unmapping */
+ name_list *IconMgrNoShow; /* don't show in the icon manager */
+ name_list *IconMgrShow; /* show in the icon manager */
+ name_list *IconifyByUn; /* windows to iconify by unmapping */
+ name_list *StartIconified; /* windows to start iconic */
+ name_list *IconManagerHighlightL; /* icon manager highlight colors */
+ name_list *SqueezeTitleL; /* windows of which to squeeze title */
+ name_list *DontSqueezeTitleL; /* windows of which not to squeeze */
+ name_list *WindowRingL; /* windows in ring */
+ name_list *WarpCursorL; /* windows to warp cursor to on deiconify */
+
+ GC NormalGC; /* normal GC for everything */
+ GC MenuGC; /* gc for menus */
+ GC DrawGC; /* GC to draw lines for move and resize */
+
+ unsigned long Black;
+ unsigned long White;
+ unsigned long XORvalue; /* number to use when drawing xor'ed */
+ MyFont TitleBarFont; /* title bar font structure */
+ MyFont MenuFont; /* menu font structure */
+ MyFont IconFont; /* icon font structure */
+ MyFont SizeFont; /* resize font structure */
+ MyFont IconManagerFont; /* window list font structure */
+ MyFont DefaultFont;
+ IconMgr iconmgr; /* default icon manager */
+ struct IconRegion *FirstRegion; /* pointer to icon regions */
+ struct IconRegion *LastRegion; /* pointer to the last icon region */
+ char *IconDirectory; /* icon directory to search */
+ int SizeStringOffset; /* x offset in size window for drawing */
+ int SizeStringWidth; /* minimum width of size window */
+ int BorderWidth; /* border width of twm windows */
+ int IconBorderWidth; /* border width of icon windows */
+ int UnknownWidth; /* width of the unknown icon */
+ int UnknownHeight; /* height of the unknown icon */
+ int TitleHeight; /* height of the title bar window */
+ TwmWindow *Focus; /* the twm window that has focus */
+ int EntryHeight; /* menu entry height */
+ int FramePadding; /* distance between decorations and border */
+ int TitlePadding; /* distance between items in titlebar */
+ int ButtonIndent; /* amount to shrink buttons on each side */
+ int NumAutoRaises; /* number of autoraise windows on screen */
+ short NoDefaults; /* do not add in default UI stuff */
+ short UsePPosition; /* what do with PPosition, see values below */
+ short AutoRelativeResize; /* start resize relative to position in quad */
+ short FocusRoot; /* is the input focus on the root ? */
+ short WarpCursor; /* warp cursor on de-iconify ? */
+ short ForceIcon; /* force the icon to the user specified */
+ short NoGrabServer; /* don't do server grabs */
+ short NoRaiseMove; /* don't raise window following move */
+ short NoRaiseResize; /* don't raise window following resize */
+ short NoRaiseDeicon; /* don't raise window on deiconify */
+ short NoRaiseWarp; /* don't raise window on warp */
+ short DontMoveOff; /* don't allow windows to be moved off */
+ short DoZoom; /* zoom in and out of icons */
+ short TitleFocus; /* focus on window in title bar ? */
+ short NoTitlebar; /* put title bars on windows */
+ short DecorateTransients; /* put title bars on transients */
+ short IconifyByUnmapping; /* simply unmap windows when iconifying */
+ short ShowIconManager; /* display the window list */
+ short IconManagerDontShow; /* show nothing in the icon manager */
+ short BackingStore; /* use backing store for menus */
+ short SaveUnder; /* use save under's for menus */
+ short RandomPlacement; /* randomly place windows that no give hints */
+ short OpaqueMove; /* move the window rather than outline */
+ short Highlight; /* should we highlight the window borders */
+ short StackMode; /* should we honor stack mode requests */
+ short TitleHighlight; /* should we highlight the titlebar */
+ short MoveDelta; /* number of pixels before f.move starts */
+ short ZoomCount; /* zoom outline count */
+ short SortIconMgr; /* sort entries in the icon manager */
+ short Shadow; /* show the menu shadow */
+ short InterpolateMenuColors;/* make pretty menus */
+ short NoIconManagers; /* Don't create any icon managers */
+ short ClientBorderWidth; /* respect client window border width */
+ short SqueezeTitle; /* make title as small as possible */
+ short HaveFonts; /* set if fonts have been loaded */
+ short FirstTime; /* first time we've read .twmrc */
+ short CaseSensitive; /* be case-sensitive when sorting names */
+ short WarpUnmapped; /* allow warping to unmapped windows */
+
+ FuncKey FuncKeyRoot;
+} ScreenInfo;
+
+extern int MultiScreen;
+extern int NumScreens;
+extern ScreenInfo **ScreenList;
+extern ScreenInfo *Scr;
+extern int FirstScreen;
+
+#define PPOS_OFF 0
+#define PPOS_ON 1
+#define PPOS_NON_ZERO 2
+/* may eventually want an option for having the PPosition be the initial
+ location for the drag lines */
+
+#endif /* _SCREEN_ */
diff --git a/src/session.c b/src/session.c
new file mode 100644
index 0000000..992f8f2
--- /dev/null
+++ b/src/session.c
@@ -0,0 +1,1054 @@
+/* $Xorg: session.c,v 1.5 2001/02/09 02:05:37 xorgcvs Exp $ */
+/******************************************************************************
+
+Copyright 1994, 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.
+
+Author: Ralph Mor, X Consortium
+******************************************************************************/
+
+#include <X11/Xos.h>
+
+#ifndef X_NOT_POSIX
+#ifdef _POSIX_SOURCE
+#include <limits.h>
+#else
+#define _POSIX_SOURCE
+#include <limits.h>
+#undef _POSIX_SOURCE
+#endif
+#endif /* X_NOT_POSIX */
+#ifndef PATH_MAX
+#include <sys/param.h>
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN
+#else
+#define PATH_MAX 1024
+#endif
+#endif
+#endif /* PATH_MAX */
+
+#include <X11/Xlib.h>
+#include <X11/SM/SMlib.h>
+#include <X11/Xatom.h>
+#include <stdio.h>
+#include "twm.h"
+#include "screen.h"
+
+SmcConn smcConn = NULL;
+XtInputId iceInputId;
+char *twm_clientId;
+TWMWinConfigEntry *winConfigHead = NULL;
+Bool gotFirstSave = 0;
+Bool sent_save_done = 0;
+
+#define SAVEFILE_VERSION 2
+
+
+
+char *
+GetClientID (window)
+
+Window window;
+
+{
+ char *client_id = NULL;
+ Window client_leader;
+ XTextProperty tp;
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems;
+ unsigned long bytes_after;
+ unsigned char *prop = NULL;
+
+ if (XGetWindowProperty (dpy, window, _XA_WM_CLIENT_LEADER,
+ 0L, 1L, False, AnyPropertyType, &actual_type, &actual_format,
+ &nitems, &bytes_after, &prop) == Success)
+ {
+ if (actual_type == XA_WINDOW && actual_format == 32 &&
+ nitems == 1 && bytes_after == 0)
+ {
+ client_leader = *((Window *) prop);
+
+ if (XGetTextProperty (dpy, client_leader, &tp, _XA_SM_CLIENT_ID))
+ {
+ if (tp.encoding == XA_STRING &&
+ tp.format == 8 && tp.nitems != 0)
+ client_id = (char *) tp.value;
+ }
+ }
+
+ if (prop)
+ XFree (prop);
+ }
+
+ return client_id;
+}
+
+
+
+char *
+GetWindowRole (window)
+
+Window window;
+
+{
+ XTextProperty tp;
+
+ if (XGetTextProperty (dpy, window, &tp, _XA_WM_WINDOW_ROLE))
+ {
+ if (tp.encoding == XA_STRING && tp.format == 8 && tp.nitems != 0)
+ return ((char *) tp.value);
+ }
+
+ return NULL;
+}
+
+
+
+int
+write_byte (file, b)
+
+FILE *file;
+unsigned char b;
+
+{
+ if (fwrite ((char *) &b, 1, 1, file) != 1)
+ return 0;
+ return 1;
+}
+
+
+int
+write_ushort (file, s)
+
+FILE *file;
+unsigned short s;
+
+{
+ unsigned char file_short[2];
+
+ file_short[0] = (s & (unsigned)0xff00) >> 8;
+ file_short[1] = s & 0xff;
+ if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
+ return 0;
+ return 1;
+}
+
+
+int
+write_short (file, s)
+
+FILE *file;
+short s;
+
+{
+ unsigned char file_short[2];
+
+ file_short[0] = (s & (unsigned)0xff00) >> 8;
+ file_short[1] = s & 0xff;
+ if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
+ return 0;
+ return 1;
+}
+
+
+int
+write_counted_string (file, string)
+
+FILE *file;
+char *string;
+
+{
+ if (string)
+ {
+ unsigned char count = strlen (string);
+
+ if (write_byte (file, count) == 0)
+ return 0;
+ if (fwrite (string, (int) sizeof (char), (int) count, file) != count)
+ return 0;
+ }
+ else
+ {
+ if (write_byte (file, 0) == 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+
+int
+read_byte (file, bp)
+
+FILE *file;
+unsigned char *bp;
+
+{
+ if (fread ((char *) bp, 1, 1, file) != 1)
+ return 0;
+ return 1;
+}
+
+
+int
+read_ushort (file, shortp)
+
+FILE *file;
+unsigned short *shortp;
+
+{
+ unsigned char file_short[2];
+
+ if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
+ return 0;
+ *shortp = file_short[0] * 256 + file_short[1];
+ return 1;
+}
+
+
+int
+read_short (file, shortp)
+
+FILE *file;
+short *shortp;
+
+{
+ unsigned char file_short[2];
+
+ if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
+ return 0;
+ *shortp = file_short[0] * 256 + file_short[1];
+ return 1;
+}
+
+
+int
+read_counted_string (file, stringp)
+
+FILE *file;
+char **stringp;
+
+{
+ unsigned char len;
+ char *data;
+
+ if (read_byte (file, &len) == 0)
+ return 0;
+ if (len == 0) {
+ data = 0;
+ } else {
+ data = malloc ((unsigned) len + 1);
+ if (!data)
+ return 0;
+ if (fread (data, (int) sizeof (char), (int) len, file) != len) {
+ free (data);
+ return 0;
+ }
+ data[len] = '\0';
+ }
+ *stringp = data;
+ return 1;
+}
+
+
+
+/*
+ * An entry in the saved window config file looks like this:
+ *
+ * FIELD BYTES
+ * ----- ----
+ * SM_CLIENT_ID ID len 1 (may be 0)
+ * SM_CLIENT_ID LIST of bytes (may be NULL)
+ *
+ * WM_WINDOW_ROLE length 1 (may be 0)
+ * WM_WINDOW_ROLE LIST of bytes (may be NULL)
+ *
+ * if no WM_WINDOW_ROLE (length = 0)
+ *
+ * WM_CLASS "res name" length 1
+ * WM_CLASS "res name" LIST of bytes
+ * WM_CLASS "res class" length 1
+ * WM_CLASS "res class" LIST of bytes
+ * WM_NAME length 1 (0 if name changed)
+ * WM_NAME LIST of bytes
+ * WM_COMMAND arg count 1 (0 if no SM_CLIENT_ID)
+ * For each arg in WM_COMMAND
+ * arg length 1
+ * arg LIST of bytes
+ *
+ * Iconified bool 1
+ * Icon info present bool 1
+ *
+ * if icon info present
+ * icon x 2
+ * icon y 2
+ *
+ * Geom x 2
+ * Geom y 2
+ * Geom width 2
+ * Geom height 2
+ *
+ * Width ever changed by user 1
+ * Height ever changed by user 1
+ */
+
+int
+WriteWinConfigEntry (configFile, theWindow, clientId, windowRole)
+
+FILE *configFile;
+TwmWindow *theWindow;
+char *clientId;
+char *windowRole;
+
+{
+ char **wm_command;
+ int wm_command_count, i;
+
+ if (!write_counted_string (configFile, clientId))
+ return 0;
+
+ if (!write_counted_string (configFile, windowRole))
+ return 0;
+
+ if (!windowRole)
+ {
+ if (!write_counted_string (configFile, theWindow->class.res_name))
+ return 0;
+ if (!write_counted_string (configFile, theWindow->class.res_class))
+ return 0;
+ if (theWindow->nameChanged)
+ {
+ /*
+ * If WM_NAME changed on this window, we can't use it as
+ * a criteria for looking up window configurations. See the
+ * longer explanation in the GetWindowConfig() function below.
+ */
+
+ if (!write_counted_string (configFile, NULL))
+ return 0;
+ }
+ else
+ {
+ if (!write_counted_string (configFile, theWindow->name))
+ return 0;
+ }
+
+ wm_command = NULL;
+ wm_command_count = 0;
+ XGetCommand (dpy, theWindow->w, &wm_command, &wm_command_count);
+
+ if (clientId || !wm_command || wm_command_count == 0)
+ {
+ if (!write_byte (configFile, 0))
+ return 0;
+ }
+ else
+ {
+ if (!write_byte (configFile, (char) wm_command_count))
+ return 0;
+ for (i = 0; i < wm_command_count; i++)
+ if (!write_counted_string (configFile, wm_command[i]))
+ return 0;
+ XFreeStringList (wm_command);
+ }
+ }
+
+ if (!write_byte (configFile, theWindow->icon ? 1 : 0)) /* iconified */
+ return 0;
+
+ if (!write_byte (configFile, theWindow->icon_w ? 1 : 0)) /* icon exists */
+ return 0;
+
+ if (theWindow->icon_w)
+ {
+ int icon_x, icon_y;
+
+ XGetGeometry (dpy, theWindow->icon_w, &JunkRoot, &icon_x,
+ &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth);
+
+ if (!write_short (configFile, (short) icon_x))
+ return 0;
+ if (!write_short (configFile, (short) icon_y))
+ return 0;
+ }
+
+ if (!write_short (configFile, (short) theWindow->frame_x))
+ return 0;
+ if (!write_short (configFile, (short) theWindow->frame_y))
+ return 0;
+ if (!write_ushort (configFile, (unsigned short) theWindow->attr.width))
+ return 0;
+ if (!write_ushort (configFile, (unsigned short) theWindow->attr.height))
+ return 0;
+
+ if (!write_byte (configFile, theWindow->widthEverChangedByUser ? 1 : 0))
+ return 0;
+
+ if (!write_byte (configFile, theWindow->heightEverChangedByUser ? 1 : 0))
+ return 0;
+
+ return 1;
+}
+
+
+int
+ReadWinConfigEntry (configFile, version, pentry)
+
+FILE *configFile;
+unsigned short version;
+TWMWinConfigEntry **pentry;
+
+{
+ TWMWinConfigEntry *entry;
+ unsigned char byte;
+ int i;
+
+ *pentry = entry = (TWMWinConfigEntry *) malloc (
+ sizeof (TWMWinConfigEntry));
+ if (!*pentry)
+ return 0;
+
+ entry->tag = 0;
+ entry->client_id = NULL;
+ entry->window_role = NULL;
+ entry->class.res_name = NULL;
+ entry->class.res_class = NULL;
+ entry->wm_name = NULL;
+ entry->wm_command = NULL;
+ entry->wm_command_count = 0;
+
+ if (!read_counted_string (configFile, &entry->client_id))
+ goto give_up;
+
+ if (!read_counted_string (configFile, &entry->window_role))
+ goto give_up;
+
+ if (!entry->window_role)
+ {
+ if (!read_counted_string (configFile, &entry->class.res_name))
+ goto give_up;
+ if (!read_counted_string (configFile, &entry->class.res_class))
+ goto give_up;
+ if (!read_counted_string (configFile, &entry->wm_name))
+ goto give_up;
+
+ if (!read_byte (configFile, &byte))
+ goto give_up;
+ entry->wm_command_count = byte;
+
+ if (entry->wm_command_count == 0)
+ entry->wm_command = NULL;
+ else
+ {
+ entry->wm_command = (char **) malloc (entry->wm_command_count *
+ sizeof (char *));
+
+ if (!entry->wm_command)
+ goto give_up;
+
+ for (i = 0; i < entry->wm_command_count; i++)
+ if (!read_counted_string (configFile, &entry->wm_command[i]))
+ goto give_up;
+ }
+ }
+
+ if (!read_byte (configFile, &byte))
+ goto give_up;
+ entry->iconified = byte;
+
+ if (!read_byte (configFile, &byte))
+ goto give_up;
+ entry->icon_info_present = byte;
+
+ if (entry->icon_info_present)
+ {
+ if (!read_short (configFile, (short *) &entry->icon_x))
+ goto give_up;
+ if (!read_short (configFile, (short *) &entry->icon_y))
+ goto give_up;
+ }
+
+ if (!read_short (configFile, (short *) &entry->x))
+ goto give_up;
+ if (!read_short (configFile, (short *) &entry->y))
+ goto give_up;
+ if (!read_ushort (configFile, &entry->width))
+ goto give_up;
+ if (!read_ushort (configFile, &entry->height))
+ goto give_up;
+
+ if (version > 1)
+ {
+ if (!read_byte (configFile, &byte))
+ goto give_up;
+ entry->width_ever_changed_by_user = byte;
+
+ if (!read_byte (configFile, &byte))
+ goto give_up;
+ entry->height_ever_changed_by_user = byte;
+ }
+ else
+ {
+ entry->width_ever_changed_by_user = False;
+ entry->height_ever_changed_by_user = False;
+ }
+
+ return 1;
+
+give_up:
+
+ if (entry->client_id)
+ free (entry->client_id);
+ if (entry->window_role)
+ free (entry->window_role);
+ if (entry->class.res_name)
+ free (entry->class.res_name);
+ if (entry->class.res_class)
+ free (entry->class.res_class);
+ if (entry->wm_name)
+ free (entry->wm_name);
+ if (entry->wm_command_count)
+ {
+ for (i = 0; i < entry->wm_command_count; i++)
+ if (entry->wm_command[i])
+ free (entry->wm_command[i]);
+ }
+ if (entry->wm_command)
+ free ((char *) entry->wm_command);
+
+ free ((char *) entry);
+ *pentry = NULL;
+
+ return 0;
+}
+
+
+void
+ReadWinConfigFile (filename)
+
+char *filename;
+
+{
+ FILE *configFile;
+ TWMWinConfigEntry *entry;
+ int done = 0;
+ unsigned short version;
+
+ configFile = fopen (filename, "rb");
+ if (!configFile)
+ return;
+
+ if (!read_ushort (configFile, &version) ||
+ version > SAVEFILE_VERSION)
+ {
+ done = 1;
+ }
+
+ while (!done)
+ {
+ if (ReadWinConfigEntry (configFile, version, &entry))
+ {
+ entry->next = winConfigHead;
+ winConfigHead = entry;
+ }
+ else
+ done = 1;
+ }
+
+ fclose (configFile);
+}
+
+
+
+int
+GetWindowConfig (theWindow, x, y, width, height,
+ iconified, icon_info_present, icon_x, icon_y,
+ width_ever_changed_by_user, height_ever_changed_by_user)
+
+TwmWindow *theWindow;
+short *x, *y;
+unsigned short *width, *height;
+Bool *iconified;
+Bool *icon_info_present;
+short *icon_x, *icon_y;
+Bool *width_ever_changed_by_user;
+Bool *height_ever_changed_by_user;
+
+{
+ char *clientId, *windowRole;
+ TWMWinConfigEntry *ptr;
+ int found = 0;
+
+ ptr = winConfigHead;
+
+ if (!ptr)
+ return 0;
+
+ clientId = GetClientID (theWindow->w);
+ windowRole = GetWindowRole (theWindow->w);
+
+ while (ptr && !found)
+ {
+ int client_id_match = (!clientId && !ptr->client_id) ||
+ (clientId && ptr->client_id &&
+ strcmp (clientId, ptr->client_id) == 0);
+
+ if (!ptr->tag && client_id_match)
+ {
+ if (windowRole || ptr->window_role)
+ {
+ found = (windowRole && ptr->window_role &&
+ strcmp (windowRole, ptr->window_role) == 0);
+ }
+ else
+ {
+ /*
+ * Compare WM_CLASS + only compare WM_NAME if the
+ * WM_NAME in the saved file is non-NULL. If the
+ * WM_NAME in the saved file is NULL, this means that
+ * the client changed the value of WM_NAME during the
+ * session, and we can not use it as a criteria for
+ * our search. For example, with xmh, at save time
+ * the window name might be "xmh: folderY". However,
+ * if xmh does not properly restore state when it is
+ * restarted, the initial window name might be
+ * "xmh: folderX". This would cause the window manager
+ * to fail in finding the saved window configuration.
+ * The best we can do is ignore WM_NAME if its value
+ * changed in the previous session.
+ */
+
+ if (strcmp (theWindow->class.res_name,
+ ptr->class.res_name) == 0 &&
+ strcmp (theWindow->class.res_class,
+ ptr->class.res_class) == 0 &&
+ (ptr->wm_name == NULL ||
+ strcmp (theWindow->name, ptr->wm_name) == 0))
+ {
+ if (clientId)
+ {
+ /*
+ * If a client ID was present, we should not check
+ * WM_COMMAND because Xt will put a -xtsessionID arg
+ * on the command line.
+ */
+
+ found = 1;
+ }
+ else
+ {
+ /*
+ * For non-XSMP clients, also check WM_COMMAND.
+ */
+
+ char **wm_command = NULL;
+ int wm_command_count = 0, i;
+
+ XGetCommand (dpy, theWindow->w,
+ &wm_command, &wm_command_count);
+
+ if (wm_command_count == ptr->wm_command_count)
+ {
+ for (i = 0; i < wm_command_count; i++)
+ if (strcmp (wm_command[i],
+ ptr->wm_command[i]) != 0)
+ break;
+
+ if (i == wm_command_count)
+ found = 1;
+ }
+ }
+ }
+ }
+ }
+
+ if (!found)
+ ptr = ptr->next;
+ }
+
+ if (found)
+ {
+ *x = ptr->x;
+ *y = ptr->y;
+ *width = ptr->width;
+ *height = ptr->height;
+ *iconified = ptr->iconified;
+ *icon_info_present = ptr->icon_info_present;
+ *width_ever_changed_by_user = ptr->width_ever_changed_by_user;
+ *height_ever_changed_by_user = ptr->height_ever_changed_by_user;
+
+ if (*icon_info_present)
+ {
+ *icon_x = ptr->icon_x;
+ *icon_y = ptr->icon_y;
+ }
+ ptr->tag = 1;
+ }
+ else
+ *iconified = 0;
+
+ if (clientId)
+ XFree (clientId);
+
+ if (windowRole)
+ XFree (windowRole);
+
+ return found;
+}
+
+
+
+static char *
+unique_filename (path, prefix)
+
+char *path;
+char *prefix;
+
+{
+#ifndef X_NOT_POSIX
+ return ((char *) tempnam (path, prefix));
+#else
+ char tempFile[PATH_MAX];
+ char *tmp;
+
+ sprintf (tempFile, "%s/%sXXXXXX", path, prefix);
+ tmp = (char *) mktemp (tempFile);
+ if (tmp)
+ {
+ char *ptr = (char *) malloc (strlen (tmp) + 1);
+ strcpy (ptr, tmp);
+ return (ptr);
+ }
+ else
+ return (NULL);
+#endif
+}
+
+
+
+void
+SaveYourselfPhase2CB (smcConn, clientData)
+
+SmcConn smcConn;
+SmPointer clientData;
+
+{
+ int scrnum;
+ ScreenInfo *theScreen;
+ TwmWindow *theWindow;
+ char *clientId, *windowRole;
+ FILE *configFile = NULL;
+ char *path;
+ char *filename = NULL;
+ Bool success = False;
+ SmProp prop1, prop2, prop3, *props[3];
+ SmPropValue prop1val, prop2val, prop3val;
+ char discardCommand[80];
+ int numVals, i;
+ static int first_time = 1;
+
+ if (first_time)
+ {
+ char userId[20];
+ char hint = SmRestartIfRunning;
+
+ prop1.name = SmProgram;
+ prop1.type = SmARRAY8;
+ prop1.num_vals = 1;
+ prop1.vals = &prop1val;
+ prop1val.value = Argv[0];
+ prop1val.length = strlen (Argv[0]);
+
+ sprintf (userId, "%d", getuid());
+ prop2.name = SmUserID;
+ prop2.type = SmARRAY8;
+ prop2.num_vals = 1;
+ prop2.vals = &prop2val;
+ prop2val.value = (SmPointer) userId;
+ prop2val.length = strlen (userId);
+
+ prop3.name = SmRestartStyleHint;
+ prop3.type = SmCARD8;
+ prop3.num_vals = 1;
+ prop3.vals = &prop3val;
+ prop3val.value = (SmPointer) &hint;
+ prop3val.length = 1;
+
+ props[0] = &prop1;
+ props[1] = &prop2;
+ props[2] = &prop3;
+
+ SmcSetProperties (smcConn, 3, props);
+
+ first_time = 0;
+ }
+
+ path = getenv ("SM_SAVE_DIR");
+ if (!path)
+ {
+ path = getenv ("HOME");
+ if (!path)
+ path = ".";
+ }
+
+ if ((filename = unique_filename (path, ".twm")) == NULL)
+ goto bad;
+
+ if (!(configFile = fopen (filename, "wb")))
+ goto bad;
+
+ if (!write_ushort (configFile, SAVEFILE_VERSION))
+ goto bad;
+
+ success = True;
+
+ for (scrnum = 0; scrnum < NumScreens && success; scrnum++)
+ {
+ if (ScreenList[scrnum] != NULL)
+ {
+ theScreen = ScreenList[scrnum];
+ theWindow = theScreen->TwmRoot.next;
+
+ while (theWindow && success)
+ {
+ clientId = GetClientID (theWindow->w);
+ windowRole = GetWindowRole (theWindow->w);
+
+ if (!WriteWinConfigEntry (configFile, theWindow,
+ clientId, windowRole))
+ success = False;
+
+ if (clientId)
+ XFree (clientId);
+
+ if (windowRole)
+ XFree (windowRole);
+
+ theWindow = theWindow->next;
+ }
+ }
+ }
+
+ prop1.name = SmRestartCommand;
+ prop1.type = SmLISTofARRAY8;
+
+ prop1.vals = (SmPropValue *) malloc (
+ (Argc + 4) * sizeof (SmPropValue));
+
+ if (!prop1.vals)
+ {
+ success = False;
+ goto bad;
+ }
+
+ numVals = 0;
+
+ for (i = 0; i < Argc; i++)
+ {
+ if (strcmp (Argv[i], "-clientId") == 0 ||
+ strcmp (Argv[i], "-restore") == 0)
+ {
+ i++;
+ }
+ else
+ {
+ prop1.vals[numVals].value = (SmPointer) Argv[i];
+ prop1.vals[numVals++].length = strlen (Argv[i]);
+ }
+ }
+
+ prop1.vals[numVals].value = (SmPointer) "-clientId";
+ prop1.vals[numVals++].length = 9;
+
+ prop1.vals[numVals].value = (SmPointer) twm_clientId;
+ prop1.vals[numVals++].length = strlen (twm_clientId);
+
+ prop1.vals[numVals].value = (SmPointer) "-restore";
+ prop1.vals[numVals++].length = 8;
+
+ prop1.vals[numVals].value = (SmPointer) filename;
+ prop1.vals[numVals++].length = strlen (filename);
+
+ prop1.num_vals = numVals;
+
+ sprintf (discardCommand, "rm %s", filename);
+ prop2.name = SmDiscardCommand;
+ prop2.type = SmARRAY8;
+ prop2.num_vals = 1;
+ prop2.vals = &prop2val;
+ prop2val.value = (SmPointer) discardCommand;
+ prop2val.length = strlen (discardCommand);
+
+ props[0] = &prop1;
+ props[1] = &prop2;
+
+ SmcSetProperties (smcConn, 2, props);
+ free ((char *) prop1.vals);
+
+ bad:
+ SmcSaveYourselfDone (smcConn, success);
+ sent_save_done = 1;
+
+ if (configFile)
+ fclose (configFile);
+
+ if (filename)
+ free (filename);
+}
+
+
+
+void
+SaveYourselfCB (smcConn, clientData, saveType, shutdown, interactStyle, fast)
+
+SmcConn smcConn;
+SmPointer clientData;
+int saveType;
+Bool shutdown;
+int interactStyle;
+Bool fast;
+
+{
+ if (!SmcRequestSaveYourselfPhase2 (smcConn, SaveYourselfPhase2CB, NULL))
+ {
+ SmcSaveYourselfDone (smcConn, False);
+ sent_save_done = 1;
+ }
+ else
+ sent_save_done = 0;
+}
+
+
+
+void
+DieCB (smcConn, clientData)
+
+SmcConn smcConn;
+SmPointer clientData;
+
+{
+ SmcCloseConnection (smcConn, 0, NULL);
+ XtRemoveInput (iceInputId);
+ Done();
+}
+
+
+
+void
+SaveCompleteCB (smcConn, clientData)
+
+SmcConn smcConn;
+SmPointer clientData;
+
+{
+ ;
+}
+
+
+
+void
+ShutdownCancelledCB (smcConn, clientData)
+
+SmcConn smcConn;
+SmPointer clientData;
+
+{
+ if (!sent_save_done)
+ {
+ SmcSaveYourselfDone (smcConn, False);
+ sent_save_done = 1;
+ }
+}
+
+
+
+void
+ProcessIceMsgProc (client_data, source, id)
+
+XtPointer client_data;
+int *source;
+XtInputId *id;
+
+{
+ IceConn ice_conn = (IceConn) client_data;
+
+ IceProcessMessages (ice_conn, NULL, NULL);
+}
+
+
+
+void
+ConnectToSessionManager (previous_id)
+
+char *previous_id;
+
+{
+ char errorMsg[256];
+ unsigned long mask;
+ SmcCallbacks callbacks;
+ IceConn iceConn;
+
+ mask = SmcSaveYourselfProcMask | SmcDieProcMask |
+ SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
+
+ callbacks.save_yourself.callback = SaveYourselfCB;
+ callbacks.save_yourself.client_data = (SmPointer) NULL;
+
+ callbacks.die.callback = DieCB;
+ callbacks.die.client_data = (SmPointer) NULL;
+
+ callbacks.save_complete.callback = SaveCompleteCB;
+ callbacks.save_complete.client_data = (SmPointer) NULL;
+
+ callbacks.shutdown_cancelled.callback = ShutdownCancelledCB;
+ callbacks.shutdown_cancelled.client_data = (SmPointer) NULL;
+
+ smcConn = SmcOpenConnection (
+ NULL, /* use SESSION_MANAGER env */
+ (SmPointer) appContext,
+ SmProtoMajor,
+ SmProtoMinor,
+ mask,
+ &callbacks,
+ previous_id,
+ &twm_clientId,
+ 256, errorMsg);
+
+ if (smcConn == NULL)
+ return;
+
+ iceConn = SmcGetIceConnection (smcConn);
+
+ iceInputId = XtAppAddInput (
+ appContext,
+ IceConnectionNumber (iceConn),
+ (XtPointer) XtInputReadMask,
+ ProcessIceMsgProc,
+ (XtPointer) iceConn);
+}
+
+
+
diff --git a/src/siconify.bm b/src/siconify.bm
new file mode 100644
index 0000000..d6402b6
--- /dev/null
+++ b/src/siconify.bm
@@ -0,0 +1,5 @@
+#define siconify_width 11
+#define siconify_height 11
+static unsigned char siconify_bits[] = {
+ 0xff, 0x07, 0x01, 0x04, 0x0d, 0x05, 0x9d, 0x05, 0xb9, 0x04, 0x51, 0x04,
+ 0xe9, 0x04, 0xcd, 0x05, 0x85, 0x05, 0x01, 0x04, 0xff, 0x07};
diff --git a/src/system.twmrc b/src/system.twmrc
new file mode 100644
index 0000000..421f8d5
--- /dev/null
+++ b/src/system.twmrc
@@ -0,0 +1,89 @@
+#
+# $Xorg: system.twmrc,v 1.3 2000/08/17 19:54:08 cpqbld Exp $
+#
+# Default twm configuration file; needs to be kept small to conserve string
+# space in systems whose compilers don't handle medium-sized strings.
+#
+# Sites should tailor this file, providing any extra title buttons, menus, etc.
+# that may be appropriate for their environment. For example, if most of the
+# users were accustomed to uwm, the defaults could be set up not to decorate
+# any windows and to use meta-keys.
+#
+
+NoGrabServer
+RestartPreviousState
+DecorateTransients
+TitleFont "-adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*"
+ResizeFont "-adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*"
+MenuFont "-adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*"
+IconFont "-adobe-helvetica-bold-r-normal--*-100-*-*-*-*-*-*"
+IconManagerFont "-adobe-helvetica-bold-r-normal--*-100-*-*-*"
+#ClientBorderWidth
+
+Color
+{
+ BorderColor "slategrey"
+ DefaultBackground "rgb:2/a/9"
+ DefaultForeground "gray85"
+ TitleBackground "rgb:2/a/9"
+ TitleForeground "gray85"
+ MenuBackground "rgb:2/a/9"
+ MenuForeground "gray85"
+ MenuTitleBackground "gray70"
+ MenuTitleForeground "rgb:2/a/9"
+ IconBackground "rgb:2/a/9"
+ IconForeground "gray85"
+ IconBorderColor "gray85"
+ IconManagerBackground "rgb:2/a/9"
+ IconManagerForeground "gray85"
+}
+
+#
+# Define some useful functions for motion-based actions.
+#
+MoveDelta 3
+Function "move-or-lower" { f.move f.deltastop f.lower }
+Function "move-or-raise" { f.move f.deltastop f.raise }
+Function "move-or-iconify" { f.move f.deltastop f.iconify }
+
+#
+# Set some useful bindings. Sort of uwm-ish, sort of simple-button-ish
+#
+Button1 = : root : f.menu "defops"
+
+Button1 = m : window|icon : f.function "move-or-lower"
+Button2 = m : window|icon : f.iconify
+Button3 = m : window|icon : f.function "move-or-raise"
+
+Button1 = : title : f.function "move-or-raise"
+Button2 = : title : f.raiselower
+
+Button1 = : icon : f.function "move-or-iconify"
+Button2 = : icon : f.iconify
+
+Button1 = : iconmgr : f.iconify
+Button2 = : iconmgr : f.iconify
+
+#
+# And a menus with the usual things
+#
+menu "defops"
+{
+"Twm" f.title
+"Iconify" f.iconify
+"Resize" f.resize
+"Move" f.move
+"Raise" f.raise
+"Lower" f.lower
+"" f.nop
+"Focus" f.focus
+"Unfocus" f.unfocus
+"Show Iconmgr" f.showiconmgr
+"Hide Iconmgr" f.hideiconmgr
+"" f.nop
+"Kill" f.destroy
+"Delete" f.delete
+"" f.nop
+"Restart" f.restart
+"Exit" f.quit
+}
diff --git a/src/twm.c b/src/twm.c
new file mode 100644
index 0000000..900acc0
--- /dev/null
+++ b/src/twm.c
@@ -0,0 +1,898 @@
+/*****************************************************************************/
+/*
+
+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: twm.c,v 1.5 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * twm - "Tom's Window Manager"
+ *
+ * 27-Oct-87 Thomas E. LaStrange File created
+ * 10-Oct-90 David M. Sternlicht Storing saved colors on root
+ ***********************************************************************/
+
+#include <stdio.h>
+#include <signal.h>
+#include <fcntl.h>
+#include "twm.h"
+#include "add_window.h"
+#include "gc.h"
+#include "parse.h"
+#include "version.h"
+#include "menus.h"
+#include "events.h"
+#include "util.h"
+#include "gram.h"
+#include "screen.h"
+#include "iconmgr.h"
+#include <X11/Xproto.h>
+#include <X11/Xatom.h>
+#include <X11/SM/SMlib.h>
+
+XtAppContext appContext; /* Xt application context */
+
+Display *dpy; /* which display are we talking to */
+Window ResizeWindow; /* the window we are resizing */
+
+int MultiScreen = TRUE; /* try for more than one screen? */
+int NumScreens; /* number of screens in ScreenList */
+int HasShape; /* server supports shape extension? */
+int ShapeEventBase, ShapeErrorBase;
+int HasSync; /* server supports SYNC extension? */
+int SyncEventBase, SyncErrorBase;
+ScreenInfo **ScreenList; /* structures for each screen */
+ScreenInfo *Scr = NULL; /* the cur and prev screens */
+int PreviousScreen; /* last screen that we were on */
+int FirstScreen; /* TRUE ==> first screen of display */
+Bool PrintErrorMessages = False; /* controls error messages */
+static int RedirectError; /* TRUE ==> another window manager running */
+static int CatchRedirectError(); /* for settting RedirectError */
+static int TwmErrorHandler(); /* for everything else */
+char Info[INFO_LINES][INFO_SIZE]; /* info strings to print */
+int InfoLines;
+char *InitFile = NULL;
+
+Cursor UpperLeftCursor; /* upper Left corner cursor */
+Cursor RightButt;
+Cursor MiddleButt;
+Cursor LeftButt;
+
+XContext TwmContext; /* context for twm windows */
+XContext MenuContext; /* context for all menu windows */
+XContext IconManagerContext; /* context for all window list windows */
+XContext ScreenContext; /* context to get screen data */
+XContext ColormapContext; /* context for colormap operations */
+
+XClassHint NoClass; /* for applications with no class */
+
+XGCValues Gcv;
+
+char *Home; /* the HOME environment variable */
+int HomeLen; /* length of Home */
+int ParseError; /* error parsing the .twmrc file */
+
+int HandlingEvents = FALSE; /* are we handling events yet? */
+
+Window JunkRoot; /* junk window */
+Window JunkChild; /* junk window */
+int JunkX; /* junk variable */
+int JunkY; /* junk variable */
+unsigned int JunkWidth, JunkHeight, JunkBW, JunkDepth, JunkMask;
+
+char *ProgramName;
+int Argc;
+char **Argv;
+char **Environ;
+
+Bool RestartPreviousState = False; /* try to restart in previous state */
+
+unsigned long black, white;
+
+extern void assign_var_savecolor();
+
+Atom TwmAtoms[11];
+
+/* don't change the order of these strings */
+static char* atom_names[11] = {
+ "_MIT_PRIORITY_COLORS",
+ "WM_CHANGE_STATE",
+ "WM_STATE",
+ "WM_COLORMAP_WINDOWS",
+ "WM_PROTOCOLS",
+ "WM_TAKE_FOCUS",
+ "WM_SAVE_YOURSELF",
+ "WM_DELETE_WINDOW",
+ "SM_CLIENT_ID",
+ "WM_CLIENT_LEADER",
+ "WM_WINDOW_ROLE"
+};
+
+/***********************************************************************
+ *
+ * Procedure:
+ * main - start of twm
+ *
+ ***********************************************************************
+ */
+
+main(argc, argv, environ)
+ int argc;
+ char **argv;
+ char **environ;
+{
+ Window root, parent, *children;
+ unsigned int nchildren;
+ int i, j;
+ char *display_name = NULL;
+ unsigned long valuemask; /* mask for create windows */
+ XSetWindowAttributes attributes; /* attributes for create windows */
+ int numManaged, firstscrn, lastscrn, scrnum;
+ extern ColormapWindow *CreateColormapWindow();
+ int zero = 0;
+ char *restore_filename = NULL;
+ char *client_id = NULL;
+
+ ProgramName = argv[0];
+ Argc = argc;
+ Argv = argv;
+ Environ = environ;
+
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ switch (argv[i][1]) {
+ case 'd': /* -display dpy */
+ if (++i >= argc) goto usage;
+ display_name = argv[i];
+ continue;
+ case 's': /* -single */
+ MultiScreen = FALSE;
+ continue;
+ case 'f': /* -file twmrcfilename */
+ if (++i >= argc) goto usage;
+ InitFile = argv[i];
+ continue;
+ case 'v': /* -verbose */
+ PrintErrorMessages = True;
+ continue;
+ case 'c': /* -clientId */
+ if (++i >= argc) goto usage;
+ client_id = argv[i];
+ continue;
+ case 'r': /* -restore */
+ if (++i >= argc) goto usage;
+ restore_filename = argv[i];
+ continue;
+ case 'q': /* -quiet */
+ PrintErrorMessages = False;
+ continue;
+ }
+ }
+ usage:
+ fprintf (stderr,
+ "usage: %s [-display dpy] [-f file] [-s] [-q] [-v] [-clientId id] [-restore file]\n",
+ ProgramName);
+ exit (1);
+ }
+
+#define newhandler(sig) \
+ if (signal (sig, SIG_IGN) != SIG_IGN) (void) signal (sig, Done)
+
+ newhandler (SIGINT);
+ newhandler (SIGHUP);
+ newhandler (SIGQUIT);
+ newhandler (SIGTERM);
+
+#undef newhandler
+
+ Home = getenv("HOME");
+ if (Home != NULL) {
+ char *temp_p;
+
+ /*
+ * Make a copy of Home because the string returned by getenv() can be
+ * overwritten by some POSIX.1 and ANSI-C implementations of getenv()
+ * when further calls to getenv() are made
+ */
+
+ temp_p = strdup(Home);
+ Home = temp_p;
+ }
+
+ if (Home == NULL)
+ Home = "./";
+
+ HomeLen = strlen(Home);
+
+ NoClass.res_name = NoName;
+ NoClass.res_class = NoName;
+
+ XtToolkitInitialize ();
+ appContext = XtCreateApplicationContext ();
+
+ if (!(dpy = XtOpenDisplay (appContext, display_name, "twm", "twm",
+ NULL, 0, &zero, NULL))) {
+ fprintf (stderr, "%s: unable to open display \"%s\"\n",
+ ProgramName, XDisplayName(display_name));
+ exit (1);
+ }
+
+ if (fcntl(ConnectionNumber(dpy), F_SETFD, 1) == -1) {
+ fprintf (stderr,
+ "%s: unable to mark display connection as close-on-exec\n",
+ ProgramName);
+ exit (1);
+ }
+
+ if (restore_filename)
+ ReadWinConfigFile (restore_filename);
+
+ HasShape = XShapeQueryExtension (dpy, &ShapeEventBase, &ShapeErrorBase);
+ HasSync = XSyncQueryExtension(dpy, &SyncEventBase, &SyncErrorBase);
+ TwmContext = XUniqueContext();
+ MenuContext = XUniqueContext();
+ IconManagerContext = XUniqueContext();
+ ScreenContext = XUniqueContext();
+ ColormapContext = XUniqueContext();
+
+ (void) XInternAtoms(dpy, atom_names, sizeof TwmAtoms / sizeof TwmAtoms[0],
+ False, TwmAtoms);
+
+ /* Set up the per-screen global information. */
+
+ NumScreens = ScreenCount(dpy);
+
+ if (MultiScreen)
+ {
+ firstscrn = 0;
+ lastscrn = NumScreens - 1;
+ }
+ else
+ {
+ firstscrn = lastscrn = DefaultScreen(dpy);
+ }
+
+ InfoLines = 0;
+
+ /* for simplicity, always allocate NumScreens ScreenInfo struct pointers */
+ ScreenList = (ScreenInfo **) calloc (NumScreens, sizeof (ScreenInfo *));
+ if (ScreenList == NULL)
+ {
+ fprintf (stderr, "%s: Unable to allocate memory for screen list, exiting.\n",
+ ProgramName);
+ exit (1);
+ }
+ numManaged = 0;
+ PreviousScreen = DefaultScreen(dpy);
+ FirstScreen = TRUE;
+ for (scrnum = firstscrn ; scrnum <= lastscrn; scrnum++)
+ {
+ /* Make sure property priority colors is empty */
+ XChangeProperty (dpy, RootWindow(dpy, scrnum), _XA_MIT_PRIORITY_COLORS,
+ XA_CARDINAL, 32, PropModeReplace, NULL, 0);
+ RedirectError = FALSE;
+ XSetErrorHandler(CatchRedirectError);
+ XSelectInput(dpy, RootWindow (dpy, scrnum),
+ ColormapChangeMask | EnterWindowMask | PropertyChangeMask |
+ SubstructureRedirectMask | KeyPressMask |
+ ButtonPressMask | ButtonReleaseMask);
+ XSync(dpy, 0);
+ XSetErrorHandler(TwmErrorHandler);
+
+ if (RedirectError)
+ {
+ fprintf (stderr, "%s: another window manager is already running",
+ ProgramName);
+ if (MultiScreen && NumScreens > 0)
+ fprintf(stderr, " on screen %d?\n", scrnum);
+ else
+ fprintf(stderr, "?\n");
+ continue;
+ }
+
+ numManaged ++;
+
+ /* Note: ScreenInfo struct is calloc'ed to initialize to zero. */
+ Scr = ScreenList[scrnum] =
+ (ScreenInfo *) calloc(1, sizeof(ScreenInfo));
+ if (Scr == NULL)
+ {
+ fprintf (stderr, "%s: unable to allocate memory for ScreenInfo structure for screen %d.\n",
+ ProgramName, scrnum);
+ continue;
+ }
+
+ /* initialize list pointers, remember to put an initialization
+ * in InitVariables also
+ */
+ Scr->BorderColorL = NULL;
+ Scr->IconBorderColorL = NULL;
+ Scr->BorderTileForegroundL = NULL;
+ Scr->BorderTileBackgroundL = NULL;
+ Scr->TitleForegroundL = NULL;
+ Scr->TitleBackgroundL = NULL;
+ Scr->IconForegroundL = NULL;
+ Scr->IconBackgroundL = NULL;
+ Scr->NoTitle = NULL;
+ Scr->MakeTitle = NULL;
+ Scr->AutoRaise = NULL;
+ Scr->IconNames = NULL;
+ Scr->NoHighlight = NULL;
+ Scr->NoStackModeL = NULL;
+ Scr->NoTitleHighlight = NULL;
+ Scr->DontIconify = NULL;
+ Scr->IconMgrNoShow = NULL;
+ Scr->IconMgrShow = NULL;
+ Scr->IconifyByUn = NULL;
+ Scr->IconManagerFL = NULL;
+ Scr->IconManagerBL = NULL;
+ Scr->IconMgrs = NULL;
+ Scr->StartIconified = NULL;
+ Scr->SqueezeTitleL = NULL;
+ Scr->DontSqueezeTitleL = NULL;
+ Scr->WindowRingL = NULL;
+ Scr->WarpCursorL = NULL;
+ /* remember to put an initialization in InitVariables also
+ */
+
+ Scr->screen = scrnum;
+ Scr->d_depth = DefaultDepth(dpy, scrnum);
+ Scr->d_visual = DefaultVisual(dpy, scrnum);
+ Scr->Root = RootWindow(dpy, scrnum);
+ XSaveContext (dpy, Scr->Root, ScreenContext, (caddr_t) Scr);
+
+ Scr->TwmRoot.cmaps.number_cwins = 1;
+ Scr->TwmRoot.cmaps.cwins =
+ (ColormapWindow **) malloc(sizeof(ColormapWindow *));
+ Scr->TwmRoot.cmaps.cwins[0] =
+ CreateColormapWindow(Scr->Root, True, False);
+ Scr->TwmRoot.cmaps.cwins[0]->visibility = VisibilityPartiallyObscured;
+
+ Scr->cmapInfo.cmaps = NULL;
+ Scr->cmapInfo.maxCmaps =
+ MaxCmapsOfScreen(ScreenOfDisplay(dpy, Scr->screen));
+ Scr->cmapInfo.root_pushes = 0;
+ InstallWindowColormaps(0, &Scr->TwmRoot);
+
+ Scr->StdCmapInfo.head = Scr->StdCmapInfo.tail =
+ Scr->StdCmapInfo.mru = NULL;
+ Scr->StdCmapInfo.mruindex = 0;
+ LocateStandardColormaps();
+
+ Scr->TBInfo.nleft = Scr->TBInfo.nright = 0;
+ Scr->TBInfo.head = NULL;
+ Scr->TBInfo.border = 1;
+ Scr->TBInfo.width = 0;
+ Scr->TBInfo.leftx = 0;
+ Scr->TBInfo.titlex = 0;
+
+ Scr->MyDisplayWidth = DisplayWidth(dpy, scrnum);
+ Scr->MyDisplayHeight = DisplayHeight(dpy, scrnum);
+ Scr->MaxWindowWidth = 32767 - Scr->MyDisplayWidth;
+ Scr->MaxWindowHeight = 32767 - Scr->MyDisplayHeight;
+
+ Scr->XORvalue = (((unsigned long) 1) << Scr->d_depth) - 1;
+
+ if (DisplayCells(dpy, scrnum) < 3)
+ Scr->Monochrome = MONOCHROME;
+ else if (DefaultVisual(dpy, scrnum)->class == GrayScale)
+ Scr->Monochrome = GRAYSCALE;
+ else
+ Scr->Monochrome = COLOR;
+
+ /* setup default colors */
+ Scr->FirstTime = TRUE;
+ GetColor(Scr->Monochrome, &black, "black");
+ Scr->Black = black;
+ GetColor(Scr->Monochrome, &white, "white");
+ Scr->White = white;
+
+ if (FirstScreen)
+ {
+ SetFocus ((TwmWindow *)NULL, CurrentTime);
+
+ /* define cursors */
+
+ NewFontCursor(&UpperLeftCursor, "top_left_corner");
+ NewFontCursor(&RightButt, "rightbutton");
+ NewFontCursor(&LeftButt, "leftbutton");
+ NewFontCursor(&MiddleButt, "middlebutton");
+ }
+
+ Scr->iconmgr.x = 0;
+ Scr->iconmgr.y = 0;
+ Scr->iconmgr.width = 150;
+ Scr->iconmgr.height = 5;
+ Scr->iconmgr.next = NULL;
+ Scr->iconmgr.prev = NULL;
+ Scr->iconmgr.lasti = &(Scr->iconmgr);
+ Scr->iconmgr.first = NULL;
+ Scr->iconmgr.last = NULL;
+ Scr->iconmgr.active = NULL;
+ Scr->iconmgr.scr = Scr;
+ Scr->iconmgr.columns = 1;
+ Scr->iconmgr.count = 0;
+ Scr->iconmgr.name = "TWM";
+ Scr->iconmgr.icon_name = "Icons";
+
+ Scr->IconDirectory = NULL;
+
+ Scr->siconifyPm = None;
+ Scr->pullPm = None;
+ Scr->hilitePm = None;
+ Scr->tbpm.xlogo = None;
+ Scr->tbpm.resize = None;
+ Scr->tbpm.question = None;
+ Scr->tbpm.menu = None;
+ Scr->tbpm.delete = None;
+
+ InitVariables();
+ InitMenus();
+
+ /* Parse it once for each screen. */
+ ParseTwmrc(InitFile);
+ assign_var_savecolor(); /* storeing pixels for twmrc "entities" */
+ if (Scr->SqueezeTitle == -1) Scr->SqueezeTitle = FALSE;
+ if (!Scr->HaveFonts) CreateFonts();
+ CreateGCs();
+ MakeMenus();
+
+ Scr->TitleBarFont.y += Scr->FramePadding;
+ Scr->TitleHeight = Scr->TitleBarFont.height + Scr->FramePadding * 2;
+ /* make title height be odd so buttons look nice and centered */
+ if (!(Scr->TitleHeight & 1)) Scr->TitleHeight++;
+
+ InitTitlebarButtons (); /* menus are now loaded! */
+
+ XGrabServer(dpy);
+ XSync(dpy, 0);
+
+ JunkX = 0;
+ JunkY = 0;
+
+ XQueryTree(dpy, Scr->Root, &root, &parent, &children, &nchildren);
+ CreateIconManagers();
+ if (!Scr->NoIconManagers)
+ Scr->iconmgr.twm_win->icon = TRUE;
+
+ /*
+ * weed out icon windows
+ */
+ for (i = 0; i < nchildren; i++) {
+ if (children[i]) {
+ XWMHints *wmhintsp = XGetWMHints (dpy, children[i]);
+
+ if (wmhintsp) {
+ if (wmhintsp->flags & IconWindowHint) {
+ for (j = 0; j < nchildren; j++) {
+ if (children[j] == wmhintsp->icon_window) {
+ children[j] = None;
+ break;
+ }
+ }
+ }
+ XFree ((char *) wmhintsp);
+ }
+ }
+ }
+
+ /*
+ * map all of the non-override windows
+ */
+ for (i = 0; i < nchildren; i++)
+ {
+ if (children[i] && MappedNotOverride(children[i]))
+ {
+ XUnmapWindow(dpy, children[i]);
+ SimulateMapRequest(children[i]);
+ }
+ }
+
+ if (Scr->ShowIconManager && !Scr->NoIconManagers)
+ {
+ Scr->iconmgr.twm_win->icon = FALSE;
+ if (Scr->iconmgr.count)
+ {
+ SetMapStateProp (Scr->iconmgr.twm_win, NormalState);
+ XMapWindow(dpy, Scr->iconmgr.w);
+ XMapWindow(dpy, Scr->iconmgr.twm_win->frame);
+ }
+ }
+
+
+ attributes.border_pixel = Scr->DefaultC.fore;
+ attributes.background_pixel = Scr->DefaultC.back;
+ attributes.event_mask = (ExposureMask | ButtonPressMask |
+ KeyPressMask | ButtonReleaseMask);
+ attributes.backing_store = NotUseful;
+ attributes.cursor = XCreateFontCursor (dpy, XC_hand2);
+ valuemask = (CWBorderPixel | CWBackPixel | CWEventMask |
+ CWBackingStore | CWCursor);
+ Scr->InfoWindow = XCreateWindow (dpy, Scr->Root, 0, 0,
+ (unsigned int) 5, (unsigned int) 5,
+ (unsigned int) BW, 0,
+ (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent,
+ valuemask, &attributes);
+
+ Scr->SizeStringWidth = XTextWidth (Scr->SizeFont.font,
+ " 8888 x 8888 ", 13);
+ valuemask = (CWBorderPixel | CWBackPixel | CWBitGravity);
+ attributes.bit_gravity = NorthWestGravity;
+ Scr->SizeWindow = XCreateWindow (dpy, Scr->Root, 0, 0,
+ (unsigned int) Scr->SizeStringWidth,
+ (unsigned int) (Scr->SizeFont.height +
+ SIZE_VINDENT*2),
+ (unsigned int) BW, 0,
+ (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent,
+ valuemask, &attributes);
+
+ XUngrabServer(dpy);
+
+ FirstScreen = FALSE;
+ Scr->FirstTime = FALSE;
+ } /* for */
+
+ if (numManaged == 0) {
+ if (MultiScreen && NumScreens > 0)
+ fprintf (stderr, "%s: unable to find any unmanaged screens\n",
+ ProgramName);
+ exit (1);
+ }
+
+ (void) ConnectToSessionManager (client_id);
+
+ RestartPreviousState = False;
+ HandlingEvents = TRUE;
+ InitEvents();
+ HandleEvents();
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * InitVariables - initialize twm variables
+ *
+ ***********************************************************************
+ */
+
+InitVariables()
+{
+ FreeList(&Scr->BorderColorL);
+ FreeList(&Scr->IconBorderColorL);
+ FreeList(&Scr->BorderTileForegroundL);
+ FreeList(&Scr->BorderTileBackgroundL);
+ FreeList(&Scr->TitleForegroundL);
+ FreeList(&Scr->TitleBackgroundL);
+ FreeList(&Scr->IconForegroundL);
+ FreeList(&Scr->IconBackgroundL);
+ FreeList(&Scr->IconManagerFL);
+ FreeList(&Scr->IconManagerBL);
+ FreeList(&Scr->IconMgrs);
+ FreeList(&Scr->NoTitle);
+ FreeList(&Scr->MakeTitle);
+ FreeList(&Scr->AutoRaise);
+ FreeList(&Scr->IconNames);
+ FreeList(&Scr->NoHighlight);
+ FreeList(&Scr->NoStackModeL);
+ FreeList(&Scr->NoTitleHighlight);
+ FreeList(&Scr->DontIconify);
+ FreeList(&Scr->IconMgrNoShow);
+ FreeList(&Scr->IconMgrShow);
+ FreeList(&Scr->IconifyByUn);
+ FreeList(&Scr->StartIconified);
+ FreeList(&Scr->IconManagerHighlightL);
+ FreeList(&Scr->SqueezeTitleL);
+ FreeList(&Scr->DontSqueezeTitleL);
+ FreeList(&Scr->WindowRingL);
+ FreeList(&Scr->WarpCursorL);
+
+ NewFontCursor(&Scr->FrameCursor, "top_left_arrow");
+ NewFontCursor(&Scr->TitleCursor, "top_left_arrow");
+ NewFontCursor(&Scr->IconCursor, "top_left_arrow");
+ NewFontCursor(&Scr->IconMgrCursor, "top_left_arrow");
+ NewFontCursor(&Scr->MoveCursor, "fleur");
+ NewFontCursor(&Scr->ResizeCursor, "fleur");
+ NewFontCursor(&Scr->MenuCursor, "sb_left_arrow");
+ NewFontCursor(&Scr->ButtonCursor, "hand2");
+ NewFontCursor(&Scr->WaitCursor, "watch");
+ NewFontCursor(&Scr->SelectCursor, "dot");
+ NewFontCursor(&Scr->DestroyCursor, "pirate");
+
+ Scr->Ring = NULL;
+ Scr->RingLeader = NULL;
+
+ Scr->DefaultC.fore = black;
+ Scr->DefaultC.back = white;
+ Scr->BorderColor = black;
+ Scr->BorderTileC.fore = black;
+ Scr->BorderTileC.back = white;
+ Scr->TitleC.fore = black;
+ Scr->TitleC.back = white;
+ Scr->MenuC.fore = black;
+ Scr->MenuC.back = white;
+ Scr->MenuTitleC.fore = black;
+ Scr->MenuTitleC.back = white;
+ Scr->MenuShadowColor = black;
+ Scr->IconC.fore = black;
+ Scr->IconC.back = white;
+ Scr->IconBorderColor = black;
+ Scr->PointerForeground.pixel = black;
+ XQueryColor(dpy, Scr->TwmRoot.cmaps.cwins[0]->colormap->c,
+ &Scr->PointerForeground);
+ Scr->PointerBackground.pixel = white;
+ XQueryColor(dpy, Scr->TwmRoot.cmaps.cwins[0]->colormap->c,
+ &Scr->PointerBackground);
+ Scr->IconManagerC.fore = black;
+ Scr->IconManagerC.back = white;
+ Scr->IconManagerHighlight = black;
+
+ Scr->FramePadding = 2; /* values that look "nice" on */
+ Scr->TitlePadding = 8; /* 75 and 100dpi displays */
+ Scr->ButtonIndent = 1;
+ Scr->SizeStringOffset = 0;
+ Scr->BorderWidth = BW;
+ Scr->IconBorderWidth = BW;
+ Scr->UnknownWidth = 0;
+ Scr->UnknownHeight = 0;
+ Scr->NumAutoRaises = 0;
+ Scr->NoDefaults = FALSE;
+ Scr->UsePPosition = PPOS_OFF;
+ Scr->FocusRoot = TRUE;
+ Scr->Focus = NULL;
+ Scr->WarpCursor = FALSE;
+ Scr->ForceIcon = FALSE;
+ Scr->NoGrabServer = FALSE;
+ Scr->NoRaiseMove = FALSE;
+ Scr->NoRaiseResize = FALSE;
+ Scr->NoRaiseDeicon = FALSE;
+ Scr->NoRaiseWarp = FALSE;
+ Scr->DontMoveOff = FALSE;
+ Scr->DoZoom = FALSE;
+ Scr->TitleFocus = TRUE;
+ Scr->NoTitlebar = FALSE;
+ Scr->DecorateTransients = FALSE;
+ Scr->IconifyByUnmapping = FALSE;
+ Scr->ShowIconManager = FALSE;
+ Scr->IconManagerDontShow =FALSE;
+ Scr->BackingStore = TRUE;
+ Scr->SaveUnder = TRUE;
+ Scr->RandomPlacement = FALSE;
+ Scr->OpaqueMove = FALSE;
+ Scr->Highlight = TRUE;
+ Scr->StackMode = TRUE;
+ Scr->TitleHighlight = TRUE;
+ Scr->MoveDelta = 1; /* so that f.deltastop will work */
+ Scr->ZoomCount = 8;
+ Scr->SortIconMgr = FALSE;
+ Scr->Shadow = TRUE;
+ Scr->InterpolateMenuColors = FALSE;
+ Scr->NoIconManagers = FALSE;
+ Scr->ClientBorderWidth = FALSE;
+ Scr->SqueezeTitle = -1;
+ Scr->FirstRegion = NULL;
+ Scr->LastRegion = NULL;
+ Scr->FirstTime = TRUE;
+ Scr->HaveFonts = FALSE; /* i.e. not loaded yet */
+ Scr->CaseSensitive = TRUE;
+ Scr->WarpUnmapped = FALSE;
+
+ /* setup default fonts; overridden by defaults from system.twmrc */
+#define DEFAULT_NICE_FONT "variable"
+#define DEFAULT_FAST_FONT "fixed"
+
+ Scr->TitleBarFont.font = NULL;
+ Scr->TitleBarFont.name = DEFAULT_NICE_FONT;
+ Scr->MenuFont.font = NULL;
+ Scr->MenuFont.name = DEFAULT_NICE_FONT;
+ Scr->IconFont.font = NULL;
+ Scr->IconFont.name = DEFAULT_NICE_FONT;
+ Scr->SizeFont.font = NULL;
+ Scr->SizeFont.name = DEFAULT_FAST_FONT;
+ Scr->IconManagerFont.font = NULL;
+ Scr->IconManagerFont.name = DEFAULT_NICE_FONT;
+ Scr->DefaultFont.font = NULL;
+ Scr->DefaultFont.name = DEFAULT_FAST_FONT;
+
+}
+
+
+CreateFonts ()
+{
+ GetFont(&Scr->TitleBarFont);
+ GetFont(&Scr->MenuFont);
+ GetFont(&Scr->IconFont);
+ GetFont(&Scr->SizeFont);
+ GetFont(&Scr->IconManagerFont);
+ GetFont(&Scr->DefaultFont);
+ Scr->HaveFonts = TRUE;
+}
+
+
+RestoreWithdrawnLocation (tmp)
+ TwmWindow *tmp;
+{
+ int gravx, gravy;
+ unsigned int bw, mask;
+ XWindowChanges xwc;
+
+ if (XGetGeometry (dpy, tmp->w, &JunkRoot, &xwc.x, &xwc.y,
+ &JunkWidth, &JunkHeight, &bw, &JunkDepth)) {
+
+ GetGravityOffsets (tmp, &gravx, &gravy);
+ if (gravy < 0) xwc.y -= tmp->title_height;
+
+ if (bw != tmp->old_bw) {
+ int xoff, yoff;
+
+ if (!Scr->ClientBorderWidth) {
+ xoff = gravx;
+ yoff = gravy;
+ } else {
+ xoff = 0;
+ yoff = 0;
+ }
+
+ xwc.x -= (xoff + 1) * tmp->old_bw;
+ xwc.y -= (yoff + 1) * tmp->old_bw;
+ }
+ if (!Scr->ClientBorderWidth) {
+ xwc.x += gravx * tmp->frame_bw;
+ xwc.y += gravy * tmp->frame_bw;
+ }
+
+ mask = (CWX | CWY);
+ if (bw != tmp->old_bw) {
+ xwc.border_width = tmp->old_bw;
+ mask |= CWBorderWidth;
+ }
+
+ XConfigureWindow (dpy, tmp->w, mask, &xwc);
+
+ if (tmp->wmhints && (tmp->wmhints->flags & IconWindowHint)) {
+ XUnmapWindow (dpy, tmp->wmhints->icon_window);
+ }
+
+ }
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * Done - cleanup and exit twm
+ *
+ * Returned Value:
+ * none
+ *
+ * Inputs:
+ * none
+ *
+ * Outputs:
+ * none
+ *
+ * Special Considerations:
+ * none
+ *
+ ***********************************************************************
+ */
+
+void Reborder (time)
+Time time;
+{
+ TwmWindow *tmp; /* temp twm window structure */
+ int scrnum;
+
+ /* put a border back around all windows */
+
+ XGrabServer (dpy);
+ for (scrnum = 0; scrnum < NumScreens; scrnum++)
+ {
+ if ((Scr = ScreenList[scrnum]) == NULL)
+ continue;
+
+ InstallWindowColormaps (0, &Scr->TwmRoot); /* force reinstall */
+ for (tmp = Scr->TwmRoot.next; tmp != NULL; tmp = tmp->next)
+ {
+ RestoreWithdrawnLocation (tmp);
+ XMapWindow (dpy, tmp->w);
+ }
+ }
+
+ XUngrabServer (dpy);
+ SetFocus ((TwmWindow*)NULL, time);
+}
+
+SIGNAL_T Done()
+{
+ Reborder (CurrentTime);
+ XCloseDisplay(dpy);
+ exit(0);
+ SIGNAL_RETURN;
+}
+
+
+/*
+ * Error Handlers. If a client dies, we'll get a BadWindow error (except for
+ * GetGeometry which returns BadDrawable) for most operations that we do before
+ * manipulating the client's window.
+ */
+
+Bool ErrorOccurred = False;
+XErrorEvent LastErrorEvent;
+
+static int TwmErrorHandler(dpy, event)
+ Display *dpy;
+ XErrorEvent *event;
+{
+ LastErrorEvent = *event;
+ ErrorOccurred = True;
+
+ if (PrintErrorMessages && /* don't be too obnoxious */
+ event->error_code != BadWindow && /* watch for dead puppies */
+ (event->request_code != X_GetGeometry && /* of all styles */
+ event->error_code != BadDrawable))
+ XmuPrintDefaultErrorMessage (dpy, event, stderr);
+ return 0;
+}
+
+
+/* ARGSUSED*/
+static int CatchRedirectError(dpy, event)
+ Display *dpy;
+ XErrorEvent *event;
+{
+ RedirectError = TRUE;
+ LastErrorEvent = *event;
+ ErrorOccurred = True;
+ return 0;
+}
diff --git a/src/twm.h b/src/twm.h
new file mode 100644
index 0000000..7fe187e
--- /dev/null
+++ b/src/twm.h
@@ -0,0 +1,426 @@
+/*****************************************************************************/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** **/
+/** 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 not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND AND 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 DAMAGES **/
+/** 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. **/
+/*****************************************************************************/
+/*
+
+Portions 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.
+
+*/
+
+
+/***********************************************************************
+ *
+ * $Xorg: twm.h,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * twm include file
+ *
+ * 28-Oct-87 Thomas E. LaStrange File created
+ * 10-Oct-90 David M. Sternlicht Storeing saved colors on root
+ ***********************************************************************/
+
+#ifndef _TWM_
+#define _TWM_
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include <X11/extensions/shape.h>
+#include <X11/Xfuncs.h>
+#include <X11/StringDefs.h>
+#include <X11/Intrinsic.h>
+
+#ifndef WithdrawnState
+#define WithdrawnState 0
+#endif
+
+#define PIXEL_ALREADY_TYPEDEFED /* for Xmu/Drawing.h */
+
+#ifdef SIGNALRETURNSINT
+#define SIGNAL_T int
+#define SIGNAL_RETURN return 0
+#else
+#define SIGNAL_T void
+#define SIGNAL_RETURN return
+#endif
+
+typedef SIGNAL_T (*SigProc)(); /* type of function returned by signal() */
+
+#define BW 2 /* border width */
+#define BW2 4 /* border width * 2 */
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define NULLSTR ((char *) NULL)
+
+#define MAX_BUTTONS 5 /* max mouse buttons supported */
+
+/* info stings defines */
+#define INFO_LINES 30
+#define INFO_SIZE 200
+
+/* contexts for button presses */
+#define C_NO_CONTEXT -1
+#define C_WINDOW 0
+#define C_TITLE 1
+#define C_ICON 2
+#define C_ROOT 3
+#define C_FRAME 4
+#define C_ICONMGR 5
+#define C_NAME 6
+#define C_IDENTIFY 7
+#define NUM_CONTEXTS 8
+
+#define C_WINDOW_BIT (1 << C_WINDOW)
+#define C_TITLE_BIT (1 << C_TITLE)
+#define C_ICON_BIT (1 << C_ICON)
+#define C_ROOT_BIT (1 << C_ROOT)
+#define C_FRAME_BIT (1 << C_FRAME)
+#define C_ICONMGR_BIT (1 << C_ICONMGR)
+#define C_NAME_BIT (1 << C_NAME)
+
+#define C_ALL_BITS (C_WINDOW_BIT | C_TITLE_BIT | C_ICON_BIT |\
+ C_ROOT_BIT | C_FRAME_BIT | C_ICONMGR_BIT)
+
+/* modifiers for button presses */
+#define MOD_SIZE ((ShiftMask | ControlMask | Mod1Mask \
+ | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) + 1)
+
+#define TITLE_BAR_SPACE 1 /* 2 pixel space bordering chars */
+#define TITLE_BAR_FONT_HEIGHT 15 /* max of 15 pixel high chars */
+#define TITLE_BAR_HEIGHT (TITLE_BAR_FONT_HEIGHT+(2*TITLE_BAR_SPACE))
+
+/* defines for zooming/unzooming */
+#define ZOOM_NONE 0
+
+#define FBF(fix_fore, fix_back, fix_font)\
+ Gcv.foreground = fix_fore;\
+ Gcv.background = fix_back;\
+ Gcv.font = fix_font;\
+ XChangeGC(dpy, Scr->NormalGC, GCFont|GCForeground|GCBackground,&Gcv)
+
+#define FB(fix_fore, fix_back)\
+ Gcv.foreground = fix_fore;\
+ Gcv.background = fix_back;\
+ XChangeGC(dpy, Scr->NormalGC, GCForeground|GCBackground,&Gcv)
+
+typedef struct MyFont
+{
+ char *name; /* name of the font */
+ XFontStruct *font; /* font structure */
+ int height; /* height of the font */
+ int y; /* Y coordinate to draw characters */
+} MyFont;
+
+typedef struct ColorPair
+{
+ Pixel fore, back;
+} ColorPair;
+
+typedef struct _TitleButton {
+ struct _TitleButton *next; /* next link in chain */
+ char *name; /* bitmap name in case of deferal */
+ Pixmap bitmap; /* image to display in button */
+ int srcx, srcy; /* from where to start copying */
+ unsigned int width, height; /* size of pixmap */
+ int dstx, dsty; /* to where to start copying */
+ int func; /* function to execute */
+ char *action; /* optional action arg */
+ struct MenuRoot *menuroot; /* menu to pop on F_MENU */
+ Bool rightside; /* t: on right, f: on left */
+} TitleButton;
+
+typedef struct _TBWindow {
+ Window window; /* which window in this frame */
+ TitleButton *info; /* description of this window */
+} TBWindow;
+
+typedef struct _SqueezeInfo {
+ int justify; /* left, center, right */
+ int num; /* signed pixel count or numerator */
+ int denom; /* 0 for pix count or denominator */
+} SqueezeInfo;
+
+#define J_LEFT 1
+#define J_CENTER 2
+#define J_RIGHT 3
+
+/* Colormap window entry for each window in WM_COLORMAP_WINDOWS
+ * ICCCM property.
+ */
+typedef struct TwmColormap
+{
+ Colormap c; /* Colormap id */
+ int state; /* install(ability) state */
+ unsigned long install_req; /* request number which installed it */
+ Window w; /* window causing load of color table */
+ int refcnt;
+} TwmColormap;
+
+#define CM_INSTALLABLE 1
+#define CM_INSTALLED 2
+#define CM_INSTALL 4
+
+typedef struct ColormapWindow
+{
+ Window w; /* Window id */
+ TwmColormap *colormap; /* Colormap for this window */
+ int visibility; /* Visibility of this window */
+ int refcnt;
+} ColormapWindow;
+
+typedef struct Colormaps
+{
+ ColormapWindow **cwins; /* current list of colormap windows */
+ int number_cwins; /* number of elements in current list */
+ char *scoreboard; /* conflicts between installable colortables */
+} Colormaps;
+
+#define ColormapsScoreboardLength(cm) ((cm)->number_cwins * \
+ ((cm)->number_cwins - 1) / 2)
+
+/* for each window that is on the display, one of these structures
+ * is allocated and linked into a list
+ */
+typedef struct TwmWindow
+{
+ struct TwmWindow *next; /* next twm window */
+ struct TwmWindow *prev; /* previous twm window */
+ Window w; /* the child window */
+ int old_bw; /* border width before reparenting */
+ Window frame; /* the frame window */
+ Window title_w; /* the title bar window */
+ Window hilite_w; /* the hilite window */
+ Pixmap gray;
+ Window icon_w; /* the icon window */
+ Window icon_bm_w; /* the icon bitmap window */
+ int frame_x; /* x position of frame */
+ int frame_y; /* y position of frame */
+ int frame_width; /* width of frame */
+ int frame_height; /* height of frame */
+ int frame_bw; /* borderwidth of frame */
+ int title_x;
+ int title_y;
+ int icon_x; /* icon text x coordinate */
+ int icon_y; /* icon text y coordiante */
+ int icon_w_width; /* width of the icon window */
+ int icon_w_height; /* height of the icon window */
+ int icon_width; /* width of the icon bitmap */
+ int icon_height; /* height of the icon bitmap */
+ int title_height; /* height of the title bar */
+ int title_width; /* width of the title bar */
+ char *full_name; /* full name of the window */
+ char *name; /* name of the window */
+ char *icon_name; /* name of the icon */
+ int name_width; /* width of name text */
+ int highlightx; /* start of highlight window */
+ int rightx; /* start of right buttons */
+ XWindowAttributes attr; /* the child window attributes */
+ XSizeHints hints; /* normal hints */
+ XWMHints *wmhints; /* WM hints */
+ Window group; /* group ID */
+ XClassHint class;
+ struct WList *list;
+ /***********************************************************************
+ * color definitions per window
+ **********************************************************************/
+ Pixel border; /* border color */
+ Pixel icon_border; /* border color */
+ ColorPair border_tile;
+ ColorPair title;
+ ColorPair iconc;
+ short iconified; /* has the window ever been iconified? */
+ short icon; /* is the window an icon now ? */
+ short icon_on; /* is the icon visible */
+ short mapped; /* is the window mapped ? */
+ short auto_raise; /* should we auto-raise this window ? */
+ short forced; /* has had an icon forced upon it */
+ short icon_not_ours; /* icon pixmap or window supplied to us */
+ short icon_moved; /* user explicitly moved the icon */
+ short highlight; /* should highlight this window */
+ short stackmode; /* honor stackmode requests */
+ short iconify_by_unmapping; /* unmap window to iconify it */
+ short iconmgr; /* this is an icon manager window */
+ short transient; /* this is a transient window */
+ Window transientfor; /* window contained in XA_XM_TRANSIENT_FOR */
+ short titlehighlight; /* should I highlight the title bar */
+ struct IconMgr *iconmgrp; /* pointer to it if this is an icon manager */
+ int save_frame_x; /* x position of frame */
+ int save_frame_y; /* y position of frame */
+ int save_frame_width; /* width of frame */
+ int save_frame_height; /* height of frame */
+ short zoomed; /* is the window zoomed? */
+ short wShaped; /* this window has a bounding shape */
+ unsigned long protocols; /* which protocols this window handles */
+ Colormaps cmaps; /* colormaps for this application */
+ TBWindow *titlebuttons;
+ SqueezeInfo *squeeze_info; /* should the title be squeezed? */
+ struct {
+ struct TwmWindow *next, *prev;
+ Bool cursor_valid;
+ int curs_x, curs_y;
+ } ring;
+
+ Bool nameChanged; /* did WM_NAME ever change? */
+
+ /* did the user ever change the width/height? {yes, no, or unknown} */
+
+ Bool widthEverChangedByUser;
+ Bool heightEverChangedByUser;
+
+} TwmWindow;
+
+
+typedef struct TWMWinConfigEntry
+{
+ struct TWMWinConfigEntry *next;
+ int tag;
+ char *client_id;
+ char *window_role;
+ XClassHint class;
+ char *wm_name;
+ int wm_command_count;
+ char **wm_command;
+ short x, y;
+ unsigned short width, height;
+ short icon_x, icon_y;
+ Bool iconified;
+ Bool icon_info_present;
+ Bool width_ever_changed_by_user;
+ Bool height_ever_changed_by_user;
+} TWMWinConfigEntry;
+
+
+#define DoesWmTakeFocus (1L << 0)
+#define DoesWmSaveYourself (1L << 1)
+#define DoesWmDeleteWindow (1L << 2)
+
+#define TBPM_DOT ":dot" /* name of titlebar pixmap for dot */
+#define TBPM_ICONIFY ":iconify" /* same image as dot */
+#define TBPM_RESIZE ":resize" /* name of titlebar pixmap for resize button */
+#define TBPM_XLOGO ":xlogo" /* name of titlebar pixmap for xlogo */
+#define TBPM_DELETE ":delete" /* same image as xlogo */
+#define TBPM_MENU ":menu" /* name of titlebar pixmap for menus */
+#define TBPM_QUESTION ":question" /* name of unknown titlebar pixmap */
+
+#include <X11/Xosdefs.h>
+#ifndef X_NOT_STDC_ENV
+#include <stdlib.h>
+#else
+extern char *malloc(), *calloc(), *realloc(), *getenv();
+extern void free();
+#endif
+extern void Reborder();
+extern SIGNAL_T Done();
+void ComputeCommonTitleOffsets();
+void ComputeWindowTitleOffsets(), ComputeTitleLocation();
+extern char *ProgramName;
+extern Display *dpy;
+extern XtAppContext appContext;
+extern Window ResizeWindow; /* the window we are resizing */
+extern int HasShape; /* this server supports Shape extension */
+extern int HasSync; /* this server supports SYNC extension */
+
+extern int PreviousScreen;
+
+extern Cursor UpperLeftCursor;
+extern Cursor RightButt;
+extern Cursor MiddleButt;
+extern Cursor LeftButt;
+
+extern XClassHint NoClass;
+
+extern XContext TwmContext;
+extern XContext MenuContext;
+extern XContext IconManagerContext;
+extern XContext ScreenContext;
+extern XContext ColormapContext;
+
+extern char *Home;
+extern int HomeLen;
+extern int ParseError;
+
+extern int HandlingEvents;
+
+extern Window JunkRoot;
+extern Window JunkChild;
+extern int JunkX;
+extern int JunkY;
+extern unsigned int JunkWidth, JunkHeight, JunkBW, JunkDepth, JunkMask;
+extern XGCValues Gcv;
+extern int InfoLines;
+extern char Info[][INFO_SIZE];
+extern int Argc;
+extern char **Argv;
+extern char **Environ;
+extern void NewFontCursor();
+extern Pixmap CreateMenuIcon();
+
+extern Bool ErrorOccurred;
+extern XErrorEvent LastErrorEvent;
+
+#define ResetError() (ErrorOccurred = False)
+
+extern Bool RestartPreviousState;
+extern Bool GetWMState();
+
+extern Atom TwmAtoms[];
+
+#define _XA_MIT_PRIORITY_COLORS TwmAtoms[0]
+#define _XA_WM_CHANGE_STATE TwmAtoms[1]
+#define _XA_WM_STATE TwmAtoms[2]
+#define _XA_WM_COLORMAP_WINDOWS TwmAtoms[3]
+#define _XA_WM_PROTOCOLS TwmAtoms[4]
+#define _XA_WM_TAKE_FOCUS TwmAtoms[5]
+#define _XA_WM_SAVE_YOURSELF TwmAtoms[6]
+#define _XA_WM_DELETE_WINDOW TwmAtoms[7]
+#define _XA_SM_CLIENT_ID TwmAtoms[8]
+#define _XA_WM_CLIENT_LEADER TwmAtoms[9]
+#define _XA_WM_WINDOW_ROLE TwmAtoms[10]
+
+#endif /* _TWM_ */
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..0082a4d
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,959 @@
+/*****************************************************************************/
+/*
+
+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: util.c,v 1.5 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * utility routines for twm
+ *
+ * 28-Oct-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#include "twm.h"
+#include "util.h"
+#include "gram.h"
+#include "screen.h"
+#include <X11/Xos.h>
+#include <X11/Xatom.h>
+#include <stdio.h>
+#include <X11/Xmu/Drawing.h>
+#include <X11/Xmu/CharSet.h>
+
+static Pixmap CreateXLogoPixmap(), CreateResizePixmap();
+static Pixmap CreateQuestionPixmap(), CreateMenuPixmap();
+static Pixmap CreateDotPixmap();
+int HotX, HotY;
+
+/***********************************************************************
+ *
+ * Procedure:
+ * MoveOutline - move a window outline
+ *
+ * Inputs:
+ * root - the window we are outlining
+ * x - upper left x coordinate
+ * y - upper left y coordinate
+ * width - the width of the rectangle
+ * height - the height of the rectangle
+ * bw - the border width of the frame
+ * th - title height
+ *
+ ***********************************************************************
+ */
+
+/* ARGSUSED */
+void MoveOutline(root, x, y, width, height, bw, th)
+ Window root;
+ int x, y, width, height, bw, th;
+{
+ static int lastx = 0;
+ static int lasty = 0;
+ static int lastWidth = 0;
+ static int lastHeight = 0;
+ static int lastBW = 0;
+ static int lastTH = 0;
+ int xl, xr, yt, yb, xinnerl, xinnerr, yinnert, yinnerb;
+ int xthird, ythird;
+ XSegment outline[18];
+ register XSegment *r;
+
+ if (x == lastx && y == lasty && width == lastWidth && height == lastHeight
+ && lastBW == bw && th == lastTH)
+ return;
+
+ r = outline;
+
+#define DRAWIT() \
+ if (lastWidth || lastHeight) \
+ { \
+ xl = lastx; \
+ xr = lastx + lastWidth - 1; \
+ yt = lasty; \
+ yb = lasty + lastHeight - 1; \
+ xinnerl = xl + lastBW; \
+ xinnerr = xr - lastBW; \
+ yinnert = yt + lastTH + lastBW; \
+ yinnerb = yb - lastBW; \
+ xthird = (xinnerr - xinnerl) / 3; \
+ ythird = (yinnerb - yinnert) / 3; \
+ \
+ r->x1 = xl; \
+ r->y1 = yt; \
+ r->x2 = xr; \
+ r->y2 = yt; \
+ r++; \
+ \
+ r->x1 = xl; \
+ r->y1 = yb; \
+ r->x2 = xr; \
+ r->y2 = yb; \
+ r++; \
+ \
+ r->x1 = xl; \
+ r->y1 = yt; \
+ r->x2 = xl; \
+ r->y2 = yb; \
+ r++; \
+ \
+ r->x1 = xr; \
+ r->y1 = yt; \
+ r->x2 = xr; \
+ r->y2 = yb; \
+ r++; \
+ \
+ r->x1 = xinnerl + xthird; \
+ r->y1 = yinnert; \
+ r->x2 = r->x1; \
+ r->y2 = yinnerb; \
+ r++; \
+ \
+ r->x1 = xinnerl + (2 * xthird); \
+ r->y1 = yinnert; \
+ r->x2 = r->x1; \
+ r->y2 = yinnerb; \
+ r++; \
+ \
+ r->x1 = xinnerl; \
+ r->y1 = yinnert + ythird; \
+ r->x2 = xinnerr; \
+ r->y2 = r->y1; \
+ r++; \
+ \
+ r->x1 = xinnerl; \
+ r->y1 = yinnert + (2 * ythird); \
+ r->x2 = xinnerr; \
+ r->y2 = r->y1; \
+ r++; \
+ \
+ if (lastTH != 0) { \
+ r->x1 = xl; \
+ r->y1 = yt + lastTH; \
+ r->x2 = xr; \
+ r->y2 = r->y1; \
+ r++; \
+ } \
+ }
+
+ /* undraw the old one, if any */
+ DRAWIT ();
+
+ lastx = x;
+ lasty = y;
+ lastWidth = width;
+ lastHeight = height;
+ lastBW = bw;
+ lastTH = th;
+
+ /* draw the new one, if any */
+ DRAWIT ();
+
+#undef DRAWIT
+
+
+ if (r != outline)
+ {
+ XDrawSegments(dpy, root, Scr->DrawGC, outline, r - outline);
+ }
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * Zoom - zoom in or out of an icon
+ *
+ * Inputs:
+ * wf - window to zoom from
+ * wt - window to zoom to
+ *
+ ***********************************************************************
+ */
+
+void
+Zoom(wf, wt)
+ Window wf, wt;
+{
+ int fx, fy, tx, ty; /* from, to */
+ unsigned int fw, fh, tw, th; /* from, to */
+ long dx, dy, dw, dh;
+ long z;
+ int j;
+
+ if (!Scr->DoZoom || Scr->ZoomCount < 1) return;
+
+ if (wf == None || wt == None) return;
+
+ XGetGeometry (dpy, wf, &JunkRoot, &fx, &fy, &fw, &fh, &JunkBW, &JunkDepth);
+ XGetGeometry (dpy, wt, &JunkRoot, &tx, &ty, &tw, &th, &JunkBW, &JunkDepth);
+
+ dx = ((long) (tx - fx)); /* going from -> to */
+ dy = ((long) (ty - fy)); /* going from -> to */
+ dw = ((long) (tw - fw)); /* going from -> to */
+ dh = ((long) (th - fh)); /* going from -> to */
+ z = (long) (Scr->ZoomCount + 1);
+
+ for (j = 0; j < 2; j++) {
+ long i;
+
+ XDrawRectangle (dpy, Scr->Root, Scr->DrawGC, fx, fy, fw, fh);
+ for (i = 1; i < z; i++) {
+ int x = fx + (int) ((dx * i) / z);
+ int y = fy + (int) ((dy * i) / z);
+ unsigned width = (unsigned) (((long) fw) + (dw * i) / z);
+ unsigned height = (unsigned) (((long) fh) + (dh * i) / z);
+
+ XDrawRectangle (dpy, Scr->Root, Scr->DrawGC,
+ x, y, width, height);
+ }
+ XDrawRectangle (dpy, Scr->Root, Scr->DrawGC, tx, ty, tw, th);
+ }
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * ExpandFilename - expand the tilde character to HOME
+ * if it is the first character of the filename
+ *
+ * Returned Value:
+ * a pointer to the new name
+ *
+ * Inputs:
+ * name - the filename to expand
+ *
+ ***********************************************************************
+ */
+
+char *
+ExpandFilename(name)
+char *name;
+{
+ char *newname;
+
+ if (name[0] != '~') return name;
+
+ newname = (char *) malloc (HomeLen + strlen(name) + 2);
+ if (!newname) {
+ fprintf (stderr,
+ "%s: unable to allocate %d bytes to expand filename %s/%s\n",
+ ProgramName, HomeLen + strlen(name) + 2, Home, &name[1]);
+ } else {
+ (void) sprintf (newname, "%s/%s", Home, &name[1]);
+ }
+
+ return newname;
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * GetUnknownIcon - read in the bitmap file for the unknown icon
+ *
+ * Inputs:
+ * name - the filename to read
+ *
+ ***********************************************************************
+ */
+
+void
+GetUnknownIcon(name)
+char *name;
+{
+ if ((Scr->UnknownPm = GetBitmap(name)) != None)
+ {
+ XGetGeometry(dpy, Scr->UnknownPm, &JunkRoot, &JunkX, &JunkY,
+ (unsigned int *)&Scr->UnknownWidth, (unsigned int *)&Scr->UnknownHeight, &JunkBW, &JunkDepth);
+ }
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * FindBitmap - read in a bitmap file and return size
+ *
+ * Returned Value:
+ * the pixmap associated with the bitmap
+ * widthp - pointer to width of bitmap
+ * heightp - pointer to height of bitmap
+ *
+ * Inputs:
+ * name - the filename to read
+ *
+ ***********************************************************************
+ */
+
+Pixmap FindBitmap (name, widthp, heightp)
+ char *name;
+ unsigned int *widthp, *heightp;
+{
+ char *bigname;
+ Pixmap pm;
+
+ if (!name) return None;
+
+ /*
+ * Names of the form :name refer to hardcoded images that are scaled to
+ * look nice in title buttons. Eventually, it would be nice to put in a
+ * menu symbol as well....
+ */
+ if (name[0] == ':') {
+ int i;
+ static struct {
+ char *name;
+ Pixmap (*proc)();
+ } pmtab[] = {
+ { TBPM_DOT, CreateDotPixmap },
+ { TBPM_ICONIFY, CreateDotPixmap },
+ { TBPM_RESIZE, CreateResizePixmap },
+ { TBPM_XLOGO, CreateXLogoPixmap },
+ { TBPM_DELETE, CreateXLogoPixmap },
+ { TBPM_MENU, CreateMenuPixmap },
+ { TBPM_QUESTION, CreateQuestionPixmap },
+ };
+
+ for (i = 0; i < (sizeof pmtab)/(sizeof pmtab[0]); i++) {
+ if (XmuCompareISOLatin1 (pmtab[i].name, name) == 0)
+ return (*pmtab[i].proc) (widthp, heightp);
+ }
+ fprintf (stderr, "%s: no such built-in bitmap \"%s\"\n",
+ ProgramName, name);
+ return None;
+ }
+
+ /*
+ * Generate a full pathname if any special prefix characters (such as ~)
+ * are used. If the bigname is different from name, bigname will need to
+ * be freed.
+ */
+ bigname = ExpandFilename (name);
+ if (!bigname) return None;
+
+ /*
+ * look along bitmapFilePath resource same as toolkit clients
+ */
+ pm = XmuLocateBitmapFile (ScreenOfDisplay(dpy, Scr->screen), bigname, NULL,
+ 0, (int *)widthp, (int *)heightp, &HotX, &HotY);
+ if (pm == None && Scr->IconDirectory && bigname[0] != '/') {
+ if (bigname != name) free (bigname);
+ /*
+ * Attempt to find icon in old IconDirectory (now obsolete)
+ */
+ bigname = (char *) malloc (strlen(name) + strlen(Scr->IconDirectory) +
+ 2);
+ if (!bigname) {
+ fprintf (stderr,
+ "%s: unable to allocate memory for \"%s/%s\"\n",
+ ProgramName, Scr->IconDirectory, name);
+ return None;
+ }
+ (void) sprintf (bigname, "%s/%s", Scr->IconDirectory, name);
+ if (XReadBitmapFile (dpy, Scr->Root, bigname, widthp, heightp, &pm,
+ &HotX, &HotY) != BitmapSuccess) {
+ pm = None;
+ }
+ }
+ if (bigname != name) free (bigname);
+ if (pm == None) {
+ fprintf (stderr, "%s: unable to find bitmap \"%s\"\n",
+ ProgramName, name);
+ }
+
+ return pm;
+}
+
+Pixmap GetBitmap (name)
+ char *name;
+{
+ return FindBitmap (name, &JunkWidth, &JunkHeight);
+}
+
+
+InsertRGBColormap (a, maps, nmaps, replace)
+ Atom a;
+ XStandardColormap *maps;
+ int nmaps;
+ Bool replace;
+{
+ StdCmap *sc = NULL;
+
+ if (replace) { /* locate existing entry */
+ for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
+ if (sc->atom == a) break;
+ }
+ }
+
+ if (!sc) { /* no existing, allocate new */
+ sc = (StdCmap *) malloc (sizeof (StdCmap));
+ if (!sc) {
+ fprintf (stderr, "%s: unable to allocate %d bytes for StdCmap\n",
+ ProgramName, sizeof (StdCmap));
+ return;
+ }
+ }
+
+ if (replace) { /* just update contents */
+ if (sc->maps) XFree ((char *) maps);
+ if (sc == Scr->StdCmapInfo.mru) Scr->StdCmapInfo.mru = NULL;
+ } else { /* else appending */
+ sc->next = NULL;
+ sc->atom = a;
+ if (Scr->StdCmapInfo.tail) {
+ Scr->StdCmapInfo.tail->next = sc;
+ } else {
+ Scr->StdCmapInfo.head = sc;
+ }
+ Scr->StdCmapInfo.tail = sc;
+ }
+ sc->nmaps = nmaps;
+ sc->maps = maps;
+
+ return;
+}
+
+RemoveRGBColormap (a)
+ Atom a;
+{
+ StdCmap *sc, *prev;
+
+ prev = NULL;
+ for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
+ if (sc->atom == a) break;
+ prev = sc;
+ }
+ if (sc) { /* found one */
+ if (sc->maps) XFree ((char *) sc->maps);
+ if (prev) prev->next = sc->next;
+ if (Scr->StdCmapInfo.head == sc) Scr->StdCmapInfo.head = sc->next;
+ if (Scr->StdCmapInfo.tail == sc) Scr->StdCmapInfo.tail = prev;
+ if (Scr->StdCmapInfo.mru == sc) Scr->StdCmapInfo.mru = NULL;
+ }
+ return;
+}
+
+LocateStandardColormaps()
+{
+ Atom *atoms;
+ int natoms;
+ int i;
+
+ atoms = XListProperties (dpy, Scr->Root, &natoms);
+ for (i = 0; i < natoms; i++) {
+ XStandardColormap *maps = NULL;
+ int nmaps;
+
+ if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps, atoms[i])) {
+ /* if got one, then append to current list */
+ InsertRGBColormap (atoms[i], maps, nmaps, False);
+ }
+ }
+ if (atoms) XFree ((char *) atoms);
+ return;
+}
+
+GetColor(kind, what, name)
+int kind;
+Pixel *what;
+char *name;
+{
+ XColor color, junkcolor;
+ Status stat = 0;
+ Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
+
+#ifndef TOM
+ if (!Scr->FirstTime)
+ return;
+#endif
+
+ if (Scr->Monochrome != kind)
+ return;
+
+ if (!XAllocNamedColor (dpy, cmap, name, &color, &junkcolor))
+ {
+ /* if we could not allocate the color, let's see if this is a
+ * standard colormap
+ */
+ XStandardColormap *stdcmap = NULL;
+
+ /* parse the named color */
+ if (name[0] != '#')
+ stat = XParseColor (dpy, cmap, name, &color);
+ if (!stat)
+ {
+ fprintf (stderr, "%s: invalid color name \"%s\"\n",
+ ProgramName, name);
+ return;
+ }
+
+ /*
+ * look through the list of standard colormaps (check cache first)
+ */
+ if (Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps &&
+ (Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap ==
+ cmap)) {
+ stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]);
+ } else {
+ StdCmap *sc;
+
+ for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
+ int i;
+
+ for (i = 0; i < sc->nmaps; i++) {
+ if (sc->maps[i].colormap == cmap) {
+ Scr->StdCmapInfo.mru = sc;
+ Scr->StdCmapInfo.mruindex = i;
+ stdcmap = &(sc->maps[i]);
+ goto gotit;
+ }
+ }
+ }
+ }
+
+ gotit:
+ if (stdcmap) {
+ color.pixel = (stdcmap->base_pixel +
+ ((Pixel)(((float)color.red / 65535.0) *
+ stdcmap->red_max + 0.5) *
+ stdcmap->red_mult) +
+ ((Pixel)(((float)color.green /65535.0) *
+ stdcmap->green_max + 0.5) *
+ stdcmap->green_mult) +
+ ((Pixel)(((float)color.blue / 65535.0) *
+ stdcmap->blue_max + 0.5) *
+ stdcmap->blue_mult));
+ } else {
+ fprintf (stderr, "%s: unable to allocate color \"%s\"\n",
+ ProgramName, name);
+ return;
+ }
+ }
+
+ *what = color.pixel;
+}
+
+GetColorValue(kind, what, name)
+int kind;
+XColor *what;
+char *name;
+{
+ XColor junkcolor;
+ Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
+
+#ifndef TOM
+ if (!Scr->FirstTime)
+ return;
+#endif
+
+ if (Scr->Monochrome != kind)
+ return;
+
+ if (!XLookupColor (dpy, cmap, name, what, &junkcolor))
+ {
+ fprintf (stderr, "%s: invalid color name \"%s\"\n",
+ ProgramName, name);
+ }
+ else
+ {
+ what->pixel = AllPlanes;
+ }
+}
+
+GetFont(font)
+MyFont *font;
+{
+ char *deffontname = "fixed";
+
+ if (font->font != NULL)
+ XFreeFont(dpy, font->font);
+
+ if ((font->font = XLoadQueryFont(dpy, font->name)) == NULL)
+ {
+ if (Scr->DefaultFont.name) {
+ deffontname = Scr->DefaultFont.name;
+ }
+ if ((font->font = XLoadQueryFont(dpy, deffontname)) == NULL)
+ {
+ fprintf (stderr, "%s: unable to open fonts \"%s\" or \"%s\"\n",
+ ProgramName, font->name, deffontname);
+ exit(1);
+ }
+
+ }
+ font->height = font->font->ascent + font->font->descent;
+ font->y = font->font->ascent;
+}
+
+
+/*
+ * SetFocus - separate routine to set focus to make things more understandable
+ * and easier to debug
+ */
+SetFocus (tmp_win, time)
+ TwmWindow *tmp_win;
+ Time time;
+{
+ Window w = (tmp_win ? tmp_win->w : PointerRoot);
+
+#ifdef TRACE
+ if (tmp_win) {
+ printf ("Focusing on window \"%s\"\n", tmp_win->full_name);
+ } else {
+ printf ("Unfocusing; Scr->Focus was \"%s\"\n",
+ Scr->Focus ? Scr->Focus->full_name : "(nil)");
+ }
+#endif
+
+ XSetInputFocus (dpy, w, RevertToPointerRoot, time);
+}
+
+
+#ifdef NOPUTENV
+/*
+ * define our own putenv() if the system doesn't have one.
+ * putenv(s): place s (a string of the form "NAME=value") in
+ * the environment; replacing any existing NAME. s is placed in
+ * environment, so if you change s, the environment changes (like
+ * putenv on a sun). Binding removed if you putenv something else
+ * called NAME.
+ */
+int
+putenv(s)
+ char *s;
+{
+ char *v;
+ int varlen, idx;
+ extern char **environ;
+ char **newenv;
+ static int virgin = 1; /* true while "environ" is a virgin */
+
+ v = index(s, '=');
+ if(v == 0)
+ return 0; /* punt if it's not of the right form */
+ varlen = (v + 1) - s;
+
+ for (idx = 0; environ[idx] != 0; idx++) {
+ if (strncmp(environ[idx], s, varlen) == 0) {
+ if(v[1] != 0) { /* true if there's a value */
+ environ[idx] = s;
+ return 0;
+ } else {
+ do {
+ environ[idx] = environ[idx+1];
+ } while(environ[++idx] != 0);
+ return 0;
+ }
+ }
+ }
+
+ /* add to environment (unless no value; then just return) */
+ if(v[1] == 0)
+ return 0;
+ if(virgin) {
+ register i;
+
+ newenv = (char **) malloc((unsigned) ((idx + 2) * sizeof(char*)));
+ if(newenv == 0)
+ return -1;
+ for(i = idx-1; i >= 0; --i)
+ newenv[i] = environ[i];
+ virgin = 0; /* you're not a virgin anymore, sweety */
+ } else {
+ newenv = (char **) realloc((char *) environ,
+ (unsigned) ((idx + 2) * sizeof(char*)));
+ if (newenv == 0)
+ return -1;
+ }
+
+ environ = newenv;
+ environ[idx] = s;
+ environ[idx+1] = 0;
+
+ return 0;
+}
+#endif /* NOPUTENV */
+
+
+static Pixmap CreateXLogoPixmap (widthp, heightp)
+ unsigned int *widthp, *heightp;
+{
+ int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
+ if (h < 0) h = 0;
+
+ *widthp = *heightp = (unsigned int) h;
+ if (Scr->tbpm.xlogo == None) {
+ GC gc, gcBack;
+
+ Scr->tbpm.xlogo = XCreatePixmap (dpy, Scr->Root, h, h, 1);
+ gc = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
+ XSetForeground (dpy, gc, 0);
+ XFillRectangle (dpy, Scr->tbpm.xlogo, gc, 0, 0, h, h);
+ XSetForeground (dpy, gc, 1);
+ gcBack = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
+ XSetForeground (dpy, gcBack, 0);
+
+ /*
+ * draw the logo large so that it gets as dense as possible; then white
+ * out the edges so that they look crisp
+ */
+ XmuDrawLogo (dpy, Scr->tbpm.xlogo, gc, gcBack, -1, -1, h + 2, h + 2);
+ XDrawRectangle (dpy, Scr->tbpm.xlogo, gcBack, 0, 0, h - 1, h - 1);
+
+ /*
+ * done drawing
+ */
+ XFreeGC (dpy, gc);
+ XFreeGC (dpy, gcBack);
+ }
+ return Scr->tbpm.xlogo;
+}
+
+
+static Pixmap CreateResizePixmap (widthp, heightp)
+ unsigned int *widthp, *heightp;
+{
+ int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
+ if (h < 1) h = 1;
+
+ *widthp = *heightp = (unsigned int) h;
+ if (Scr->tbpm.resize == None) {
+ XPoint points[3];
+ GC gc;
+ int w;
+ int lw;
+
+ /*
+ * create the pixmap
+ */
+ Scr->tbpm.resize = XCreatePixmap (dpy, Scr->Root, h, h, 1);
+ gc = XCreateGC (dpy, Scr->tbpm.resize, 0L, NULL);
+ XSetForeground (dpy, gc, 0);
+ XFillRectangle (dpy, Scr->tbpm.resize, gc, 0, 0, h, h);
+ XSetForeground (dpy, gc, 1);
+ lw = h / 16;
+ if (lw == 1)
+ lw = 0;
+ XSetLineAttributes (dpy, gc, lw, LineSolid, CapButt, JoinMiter);
+
+ /*
+ * draw the resize button,
+ */
+ w = (h * 2) / 3;
+ points[0].x = w;
+ points[0].y = 0;
+ points[1].x = w;
+ points[1].y = w;
+ points[2].x = 0;
+ points[2].y = w;
+ XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
+ w = w / 2;
+ points[0].x = w;
+ points[0].y = 0;
+ points[1].x = w;
+ points[1].y = w;
+ points[2].x = 0;
+ points[2].y = w;
+ XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
+
+ /*
+ * done drawing
+ */
+ XFreeGC(dpy, gc);
+ }
+ return Scr->tbpm.resize;
+}
+
+
+static Pixmap CreateDotPixmap (widthp, heightp)
+ unsigned int *widthp, *heightp;
+{
+ int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
+
+ h = h * 3 / 4;
+ if (h < 1) h = 1;
+ if (!(h & 1))
+ h--;
+ *widthp = *heightp = (unsigned int) h;
+ if (Scr->tbpm.delete == None) {
+ GC gc;
+ Pixmap pix;
+
+ pix = Scr->tbpm.delete = XCreatePixmap (dpy, Scr->Root, h, h, 1);
+ gc = XCreateGC (dpy, pix, 0L, NULL);
+ XSetLineAttributes (dpy, gc, h, LineSolid, CapRound, JoinRound);
+ XSetForeground (dpy, gc, 0L);
+ XFillRectangle (dpy, pix, gc, 0, 0, h, h);
+ XSetForeground (dpy, gc, 1L);
+ XDrawLine (dpy, pix, gc, h/2, h/2, h/2, h/2);
+ XFreeGC (dpy, gc);
+ }
+ return Scr->tbpm.delete;
+}
+
+#define questionmark_width 8
+#define questionmark_height 8
+static char questionmark_bits[] = {
+ 0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18};
+
+static Pixmap CreateQuestionPixmap (widthp, heightp)
+ unsigned int *widthp, *heightp;
+{
+ *widthp = questionmark_width;
+ *heightp = questionmark_height;
+ if (Scr->tbpm.question == None) {
+ Scr->tbpm.question = XCreateBitmapFromData (dpy, Scr->Root,
+ questionmark_bits,
+ questionmark_width,
+ questionmark_height);
+ }
+ /*
+ * this must succeed or else we are in deep trouble elsewhere
+ */
+ return Scr->tbpm.question;
+}
+
+
+static Pixmap CreateMenuPixmap (widthp, heightp)
+ int *widthp, *heightp;
+{
+ return CreateMenuIcon (Scr->TBInfo.width - Scr->TBInfo.border * 2,
+ widthp,heightp);
+}
+
+Pixmap CreateMenuIcon (height, widthp, heightp)
+ int height;
+ int *widthp, *heightp;
+{
+ int h, w;
+ int ih, iw;
+ int ix, iy;
+ int mh, mw;
+ int tw, th;
+ int lw, lh;
+ int lx, ly;
+ int lines, dly;
+ int off;
+ int bw;
+
+ h = height;
+ w = h * 7 / 8;
+ if (h < 1)
+ h = 1;
+ if (w < 1)
+ w = 1;
+ *widthp = w;
+ *heightp = h;
+ if (Scr->tbpm.menu == None) {
+ Pixmap pix;
+ GC gc;
+
+ pix = Scr->tbpm.menu = XCreatePixmap (dpy, Scr->Root, w, h, 1);
+ gc = XCreateGC (dpy, pix, 0L, NULL);
+ XSetForeground (dpy, gc, 0L);
+ XFillRectangle (dpy, pix, gc, 0, 0, w, h);
+ XSetForeground (dpy, gc, 1L);
+ ix = 1;
+ iy = 1;
+ ih = h - iy * 2;
+ iw = w - ix * 2;
+ off = ih / 8;
+ mh = ih - off;
+ mw = iw - off;
+ bw = mh / 16;
+ if (bw == 0 && mw > 2)
+ bw = 1;
+ tw = mw - bw * 2;
+ th = mh - bw * 2;
+ XFillRectangle (dpy, pix, gc, ix, iy, mw, mh);
+ XFillRectangle (dpy, pix, gc, ix + iw - mw, iy + ih - mh, mw, mh);
+ XSetForeground (dpy, gc, 0L);
+ XFillRectangle (dpy, pix, gc, ix+bw, iy+bw, tw, th);
+ XSetForeground (dpy, gc, 1L);
+ lw = tw / 2;
+ if ((tw & 1) ^ (lw & 1))
+ lw++;
+ lx = ix + bw + (tw - lw) / 2;
+
+ lh = th / 2 - bw;
+ if ((lh & 1) ^ ((th - bw) & 1))
+ lh++;
+ ly = iy + bw + (th - bw - lh) / 2;
+
+ lines = 3;
+ if ((lh & 1) && lh < 6)
+ {
+ lines--;
+ }
+ dly = lh / (lines - 1);
+ while (lines--)
+ {
+ XFillRectangle (dpy, pix, gc, lx, ly, lw, bw);
+ ly += dly;
+ }
+ XFreeGC (dpy, gc);
+ }
+ return Scr->tbpm.menu;
+}
+
+void
+Bell(type,percent,win)
+ int type;
+ int percent;
+ Window win;
+{
+#ifdef XKB
+ XkbStdBell(dpy, win, percent, type);
+#else
+ XBell(dpy, percent);
+#endif
+ return;
+}
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..bfeab2f
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,95 @@
+/*****************************************************************************/
+/*
+
+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: util.h,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * utility routines header file
+ *
+ * 28-Oct-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#ifndef _UTIL_
+#define _UTIL_
+
+extern void Zoom();
+extern void MoveOutline();
+extern Pixmap GetBitmap(), FindBitmap();
+extern void GetUnknownIcon();
+extern char *ExpandFilename();
+extern int GetColor();
+
+extern int HotX, HotY;
+
+#define WM_BELL 0
+#define MINOR_ERROR_BELL 1
+#define MAJOR_ERROR_BELL 2
+#define INFO_BELL 3
+#define NUM_BELLS 4
+
+#define QUIET_BELL -100
+#define MODERATE_BELL 0
+#define LOUD_BELL 100
+
+#ifdef XKB
+#include <X11/extensions/XKBbells.h>
+#else
+#define XkbBI_Info 0
+#define XkbBI_MinorError 1
+#define XkbBI_MajorError 2
+#endif
+
+extern void Bell();
+
+#endif /* _UTIL_ */
diff --git a/src/version.c b/src/version.c
new file mode 100644
index 0000000..9e3e70c
--- /dev/null
+++ b/src/version.c
@@ -0,0 +1,54 @@
+/*****************************************************************************/
+/*
+
+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: version.c,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $ */
+char *Version = "The Open Group, R6.3";
+
diff --git a/src/version.h b/src/version.h
new file mode 100644
index 0000000..d232190
--- /dev/null
+++ b/src/version.h
@@ -0,0 +1,67 @@
+/*****************************************************************************/
+/*
+
+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: version.h,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * TWM version externs
+ *
+ * 8-Apr-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#ifndef _VERSION_
+#define _VERSION_
+
+extern char *Version;
+
+#endif /* _VERSION_ */