diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/add_window.c | 1629 | ||||
-rw-r--r-- | src/add_window.h | 81 | ||||
-rw-r--r-- | src/cursor.c | 175 | ||||
-rw-r--r-- | src/events.c | 2817 | ||||
-rw-r--r-- | src/events.h | 111 | ||||
-rw-r--r-- | src/gc.c | 117 | ||||
-rw-r--r-- | src/gc.h | 68 | ||||
-rw-r--r-- | src/gram.y | 883 | ||||
-rw-r--r-- | src/iconmgr.c | 773 | ||||
-rw-r--r-- | src/iconmgr.h | 93 | ||||
-rw-r--r-- | src/icons.c | 588 | ||||
-rw-r--r-- | src/icons.h | 56 | ||||
-rw-r--r-- | src/lex.l | 145 | ||||
-rw-r--r-- | src/list.c | 258 | ||||
-rw-r--r-- | src/list.h | 75 | ||||
-rw-r--r-- | src/menus.c | 3035 | ||||
-rw-r--r-- | src/menus.h | 178 | ||||
-rw-r--r-- | src/parse.c | 1149 | ||||
-rw-r--r-- | src/parse.h | 135 | ||||
-rw-r--r-- | src/resize.c | 1217 | ||||
-rw-r--r-- | src/resize.h | 77 | ||||
-rw-r--r-- | src/screen.h | 267 | ||||
-rw-r--r-- | src/session.c | 1054 | ||||
-rw-r--r-- | src/siconify.bm | 5 | ||||
-rw-r--r-- | src/system.twmrc | 89 | ||||
-rw-r--r-- | src/twm.c | 898 | ||||
-rw-r--r-- | src/twm.h | 426 | ||||
-rw-r--r-- | src/util.c | 959 | ||||
-rw-r--r-- | src/util.h | 95 | ||||
-rw-r--r-- | src/version.c | 54 | ||||
-rw-r--r-- | src/version.h | 67 |
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_ */ |