mikew@wyse.wyse.com (Mike Wexler) (08/11/88)
Submitted-by: unido!pcsbsd!jkh (Jordan Hubbard) Posting-number: Volume 0, Issue 9 Archive-name: awm/part09 [NOTE: Jordan Hubbard has moved. The first postings listed his address as jkh@ardent. His current address is unido!pcsbst!jkh] #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 9 (of 13)." # Contents: awm/GetButton.c awm/menus/track_menu.c # Wrapped by mikew@wyse on Mon Aug 8 12:01:47 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f awm/GetButton.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"awm/GetButton.c\" else echo shar: Extracting \"awm/GetButton.c\" \(21347 characters\) sed "s/^X//" >awm/GetButton.c <<'END_OF_awm/GetButton.c' X#ident "%W% %G%" X X X X#ifndef lint Xstatic char *rcsid_GetButton_c = "$Header: GetButton.c,v 1.4 88/07/23 18:20:45 jkh Exp $"; X#endif lint X X#include "X11/copyright.h" X/* X * X * Copyright 1987, 1988 by Ardent Computer Corporation, Sunnyvale, Ca. X * X * Copyright 1987 by Jordan Hubbard. X * X * X * All Rights Reserved X * X * Permission to use, copy, modify, and distribute this software and its X * documentation for any purpose and without fee is hereby granted, X * provided that the above copyright notice appear in all copies and that X * both that copyright notice and this permission notice appear in X * supporting documentation, and that the name of Ardent Computer X * Corporation or Jordan Hubbard not be used in advertising or publicity X * pertaining to distribution of the software without specific, written X * prior permission. X * X */ X X/* X * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. X * X * All Rights Reserved X * X * Permission to use, copy, modify, and distribute this software and its X * documentation for any purpose and without fee is hereby granted, X * provided that the above copyright notice appear in all copies and that X * both that copyright notice and this permission notice appear in X * supporting documentation, and that the name of Digital Equipment X * Corporation not be used in advertising or publicity pertaining to X * distribution of the software without specific, written prior permission. X * X * X * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING X * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL X * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR X * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, X * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, X * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS X * SOFTWARE. X */ X X X X/* X * MODIFICATION HISTORY X * X * 000 -- M. Gancarz, DEC Ultrix Engineering Group X * 001 -- L. Guarino Reid, DEC Ultrix Engineering Group, Western Software Lab X * February 16, 1987 X * Add EnterWindow, LeaveWindow, and MouseMotion as recognized X * awm buttons for awm menus. Add bug fixes to prevent mem faults X * if icon_str is NULL. X * 002 -- L. Guarino Reid, DEC Ultrix Engineering Group X * April 16, 1987 X * Convert to X11 X * 003 -- J. Hubbard, U.C. Berkeley. Title/gadget box event handling. X * December 3, 1987. X * 004 -- J.Hubbard, Ardent Computer. More conformance with ICCCM. Merge of X * changes from R2 uwm. X */ X X#ifndef lint Xstatic char *sccsid = "@(#)GetButton.c 3.8 1/24/86"; X#endif X/* X * GetButton - This subroutine is used by the Ardent Window Manager (awm) X * to acquire button events. It waits for a button event to occur X * and handles all event traffic in the interim. X * X * File: GetButton.c X */ X X#include "awm.h" X#include "X11/Xutil.h" X Xextern XContext AwmContext; Xextern Window FocusWindow; X X#define ICONSTR (icon_str ? icon_str : "") X/* Amount of padding between text in a title bar and the edge of the bar */ X#define PAD 1 X Xstatic Icon_modified = FALSE; X XBoolean GetButton(b_ev) XXEvent *b_ev; /* Button event packet. */ X{ X#define STRLEN 50 X XKeyPressedEvent *kp_event; /* Key pressed event. */ X char *icon_str; /* Icon's name string. */ X register int icon_str_len; /* Icon name string lenght. */ X register int key_char; /* Key press character code. */ X register int icon_x; /* Icon window X coordinate. */ X register int icon_y; /* Icon window Y coordinate. */ X register int icon_w; /* Icon window width. */ X register int icon_h; /* Icon window height. */ X int status; /* Routine call return status. */ X Window icon; /* Icon window. */ X Window appl; /* Application window. */ X XWindowAttributes win_info; /* Icon window info structure. */ X char kbd_str[STRLEN]; /* Keyboard string. */ X int nbytes; /* Keyboard string length. */ X int i; /* Iteration counter. */ X Window win; /* scratch */ X AwmInfoPtr awi; X X Entry("GetButton") X X /* X * Get next event from input queue and store it in the event packet X * passed to GetButton. X */ X X XNextEvent(dpy, b_ev); X /* print_event_info("mainloop", b_ev); /* debugging for event handling */ X X /* X * The event occured on the root window, check for substructure X * changes. Otherwise, it must be a mouse button event. X */ X X if (b_ev->xany.window == RootWindow(dpy, scr)) { X switch (b_ev->xany.type) { X case CreateNotify: X case UnmapNotify: X case ReparentNotify: X case ConfigureNotify: X case GravityNotify: X case MapNotify: X case CirculateNotify: X Leave(FALSE) X X case MappingNotify: X XRefreshKeyboardMapping(b_ev); X Leave(FALSE) X X case MapRequest: X CheckMap(b_ev->xmap.window); X Leave(FALSE) X X case ConfigureRequest: X Configure((XConfigureEvent *)b_ev); X Leave(FALSE) X X case CirculateRequest: X Circulate((XCirculateEvent *)b_ev); X Leave(FALSE) X X case DestroyNotify: X RemoveIcon(b_ev->xdestroywindow.window); X Leave(FALSE) X X case FocusIn: X if (b_ev->xfocus.detail == NotifyPointerRoot) { X if (FocusSetByUser) { X XSetInputFocus(dpy, PointerRoot, None, X CurrentTime); X FocusSetByUser = FALSE; X FocusWindow = RootWindow(dpy, scr); X } X } X Leave(FALSE) X X case FocusOut: X if (b_ev->xfocus.detail == NotifyPointerRoot) { X if (FocusSetByUser == FALSE && !FocusSetByWM) { X XSetInputFocus(dpy, PointerRoot, None, X CurrentTime); X FocusWindow = RootWindow(dpy, scr); X } X } X Leave(FALSE) X X case ButtonPress: X case ButtonRelease: X Leave(TRUE) X X default: X Leave(FALSE) X } X } X X /* X * If the event type is EnterWindow, LeaveWindow, or MouseMoved, X * we are processing a menu. X * If the event type is ButtonPress or ButtonRelease, X * we have a button event. X * If it's an expose, then we may have exposed a title bar. X * If it's a Notify, we've probably frobbed a titled window. X */ X X switch (b_ev->type) { X XEvent e_fake; X X case MotionNotify: X case ButtonPress: X case ButtonRelease: X Leave(TRUE) X break; X X case FocusIn: X if (!FocusSetByWM) { X e_fake.xcrossing.type = FocusIn; X e_fake.xcrossing.focus = TRUE; X e_fake.xcrossing.window = b_ev->xcrossing.window; X HandleFocusIn(&e_fake); X } X Leave(FALSE) X break; X X case FocusOut: X if (!FocusSetByWM) { X e_fake.xcrossing.type = FocusOut; X e_fake.xcrossing.focus = TRUE; X e_fake.xcrossing.window = b_ev->xcrossing.window; X HandleFocusOut(&e_fake); X } X Leave(FALSE) X break; X X case EnterNotify: X HandleFocusIn(b_ev); X Leave(FALSE) X X case LeaveNotify: X HandleFocusOut(b_ev); X Leave(FALSE) X X case ConfigureRequest: X Configure((XConfigureEvent *)b_ev); X Leave(FALSE) X X case MapRequest: X CheckMap(b_ev->xmap.window); X Leave(FALSE); X X case MapNotify: X win = b_ev->xmap.window; X if (!(awi = GetAwmInfo(win))) X Leave(FALSE) X if (IsIcon(win, FALSE)) X Leave(FALSE) X XMapWindow(dpy, awi->frame); X XMapWindow(dpy, awi->client); X Leave(FALSE) X break; X X case UnmapNotify: X win = b_ev->xunmap.window; X if (!(awi = GetAwmInfo(win))) X Leave(FALSE) X X if (IsIcon(win, FALSE)) X Leave(FALSE) X XUnmapWindow(dpy, awi->frame); X Leave(FALSE) X break; X X case DestroyNotify: X win = b_ev->xdestroywindow.window; X if (!(awi = GetAwmInfo(win))) X Leave(FALSE) X if (win != awi->title) { X /* remove any icon associated with this window */ X RemoveIcon(win); X /* remove the frame/titlebar (if present) */ X NoDecorate(win, TRUE); X /* punt the rest of the per-window info */ X XDeleteContext(dpy, awi->client, AwmContext); X free(awi); X } X Leave(FALSE) X X case PropertyNotify: X win = b_ev->xproperty.window; X if (!(awi = GetAwmInfo(win))) X Leave(FALSE) X switch(b_ev->xproperty.atom) { X X case XA_WM_COMMAND: X case XA_WM_HINTS: X case XA_WM_CLIENT_MACHINE: X break; X X case XA_WM_ICON_NAME: X /* X * Icon was modified by type-in (I still think that's a X * gross feature, but some people like it... sigh), X * ignore this event. X */ X if (Icon_modified == TRUE) { X Icon_modified = FALSE; /* reset */ X Leave(FALSE) X } X if (awi->icon && awi->own && awi->iconPixmap == IBackPixmap) { X win = awi->icon; X status = XGetWindowAttributes(dpy, win, &win_info); X icon_str = GetIconName(awi->client); X icon_str_len = icon_str ? strlen(icon_str) : 0; X if (win_info.width != XTextWidth(IFontInfo, ICONSTR, X strlen(ICONSTR)) + X (HIconPad << 1)) { X XResizeWindow(dpy, win, X XTextWidth(IFontInfo, ICONSTR, X strlen(ICONSTR)) + X (HIconPad << 1), IFontInfo->ascent + X IFontInfo->descent + (VIconPad << 1)); X } X XClearWindow(dpy, win); X if (icon_str_len != 0) { X XDrawImageString(dpy, win, IconGC, HIconPad, X VIconPad+IFontInfo->ascent, icon_str, X icon_str_len); X free(icon_str); X } X } X break; X X case XA_WM_ICON_SIZE: X break; X X case XA_WM_NAME: X if (awi->title) { X if (awi->name) X free(awi->name); X awi->name = (char *)GetTitleName(win); X PaintTitle(win, (FocusWindow == awi->client)); X } X break; X X case XA_WM_NORMAL_HINTS: X case XA_WM_SIZE_HINTS: X case XA_WM_ZOOM_HINTS: X break; X X default: X fprintf(stderr, "awm: Got unknown property %d\n", X b_ev->xproperty.atom); X } X Leave(FALSE) X break; X X X case Expose: X win = b_ev->xexpose.window; X if (!(awi = GetAwmInfo(win))) /* probably a menu */ X Leave(FALSE) X if (awi->title == win) { X if (b_ev->xexpose.count == 0) { X XEvent evt; X X /* Eat up any previous exposes */ X while (XCheckTypedWindowEvent(dpy, awi->title, Expose, X &evt)); X PaintTitle(win, (FocusWindow == awi->client)); X if (awi->gadgets) X PaintGadgets(win); X } X Leave(FALSE) X } X break; X X default: X break; X } X X /* X * If we got this far, the event must be for an icon. X */ X win = b_ev->xany.window; X if (!(awi = GetAwmInfo(win))) X Leave(FALSE) X status = XGetWindowAttributes(dpy, win, &win_info); X if (status == FAILURE) X Leave(FALSE) X X if (b_ev->type == MapNotify || X b_ev->type == UnmapNotify || X b_ev->type == CreateNotify || X b_ev->type == ReparentNotify || X b_ev->type == GravityNotify || X b_ev->type == CirculateNotify || X b_ev->type == ConfigureNotify) X Leave(FALSE) X X /* X * Initialize the icon position variables. X */ X icon_x = win_info.x; X icon_y = win_info.y; X X /* X * Get the name of the window associated with the icon and X * determine its length. X */ X if (!awi->icon) X Leave(FALSE) X /* X * If we don't own it, or it's got a background pixmap, we don't have X * to repaint it. X */ X if (!awi->own || (awi->iconPixmap != IBackPixmap)) X Leave(FALSE) X icon = awi->icon; X icon_str = GetIconName(awi->client); X icon_str_len = icon_str ? strlen(icon_str) : 0; X X /* X * If the event is a window exposure event and the icon's name string X * is not of zero length, simply repaint the text in the icon window X * and return FALSE. X */ X if (b_ev->type == Expose && (!Freeze || Frozen == 0)) { X if (win_info.width != XTextWidth(IFontInfo, ICONSTR, X strlen(ICONSTR))+(HIconPad << 1)) { X XResizeWindow(dpy, icon, X XTextWidth(IFontInfo, ICONSTR, X strlen(ICONSTR)) + (HIconPad << 1), X IFontInfo->ascent + IFontInfo->descent + X (VIconPad << 1)); X } X XClearWindow(dpy, icon); X if (icon_str_len != 0) { X XDrawImageString(dpy, icon, X IconGC, HIconPad, VIconPad+IFontInfo->ascent, X icon_str, icon_str_len); X /* X * Remember to free the icon name string. X */ X free(icon_str); X } X Leave(FALSE) X } X X#ifndef NO_ICON_TYPIN X /* X * If we have gotten this far event can only be a key pressed event. X */ X kp_event = (XKeyPressedEvent *) b_ev; X X /* X * We convert the key pressed event to ascii. X */ X nbytes = XLookupString(kp_event, kbd_str, STRLEN, NULL); X X /* X * If kbd_str is a "non-string", then don't do anything. X */ X if (nbytes == 0) { X if (icon_str) X free(icon_str); X Leave(FALSE) X } X for (i = 0; i < nbytes; i++) { X key_char = kbd_str[i]; X /* X * If the key was <DELETE>, then delete a character from the end of X * the name, return FALSE. X * X * If the key was <CTRL-U>, then wipe out the entire window name X * and return FALSE. X * X * All other ctrl keys are squashed and we return FALSE. X * X * All printable characters are appended to the window's name, which X * may have to be grown to allow for the extra length. X */ X if (key_char == '\177') { X /* X * <DELETE> X */ X if (icon_str_len > 0) { X icon_str_len--; X icon_str[icon_str_len] = '\0'; X } X } X else if (key_char == '\025') { X /* X * <CTRL-U> X */ X if (icon_str_len > 0) { X icon_str_len = 0; X icon_str[0] = '\0'; X } X } X else if (key_char < IFontInfo->min_char_or_byte2 || X key_char > IFontInfo->max_char_or_byte2) { X /* X * Any other random (non-printable) key; ignore it. X */ X /* do nothing */ ; X } X else { X /* X * ASCII Alphanumerics. X */ X if (icon_str == NULL) X icon_str = (char *) malloc (icon_str_len + 2); X else X icon_str = (char *)realloc(icon_str, (icon_str_len + 2)); X if (icon_str == NULL) { X errno = ENOMEM; X Error("GetButton -> Realloc of window name string memory failed."); X } X icon_str[icon_str_len] = key_char; X icon_str[icon_str_len + 1] = '\0'; X icon_str_len += 1; X } X } X X /* X * Now that we have changed the size of the icon we have to reconfigure X * it so that everything looks good. Oh yes, don't forget to move the X * mouse so that it stays in the window! X */ X X /* X * Set the window name to the new string. Icon_modified is a kludge X * that tells us to avoid the next PropertyNotify, as it's a result of X * this call. X */ X XSetIconName(dpy, awi->client, ICONSTR); X Icon_modified = TRUE; X /* X * Determine the new icon window configuration. X */ X icon_h = IFontInfo->ascent + IFontInfo->descent + (VIconPad << 1); X icon_w = XTextWidth(IFontInfo, ICONSTR, strlen(ICONSTR)); X if (icon_w == 0) { X icon_w = icon_h; X } X else { X icon_w += (HIconPad << 1); X } X X if (icon_x < 0) icon_x = 0; X if (icon_y < 0) icon_y = 0; X if (icon_x - 1 + icon_w + (IBorderWidth << 1) > ScreenWidth) { X icon_x = ScreenWidth - icon_w - (IBorderWidth << 1) + 1; X } X if (icon_y - 1 + icon_h + (IBorderWidth << 1) > ScreenHeight) { X icon_y = ScreenHeight - icon_h - (IBorderWidth << 1) + 1; X } X X XMoveResizeWindow(dpy, icon, icon_x, icon_y, icon_w, icon_h); X XWarpPointer(dpy, None, icon, X 0, 0, 0, 0, (icon_w >> 1), (icon_h >> 1)); X X /* X * Free the local storage and return FALSE. X */ X if (icon_str) X free(icon_str); X#endif X Leave(FALSE) X} X XCheckMap(window) XWindow window; X{ X XWMHints *XGetWMHints(); X XWMHints *wmhints; X int x, y, w, h; X Window transient_for; X Window jW; X int border_width, j; X Binding *bptr; X AwmInfoPtr awi; X unsigned long event_mask; X X Entry("CheckMap") X X /* if it's a transient window, we won't rubber-band X * note that this call always sets transient_for. X */ X if (!XGetTransientForHint( dpy, window, &transient_for )) { X /* X * Handle any registered grabs for this window. We do this here X * because we may be about to make an icon out of this window X * and we want to register any potential grabs on it before this X * happens. X */ X awi = GetAwmInfo(window); X if (!awi) { X for (bptr = Blist; bptr; bptr = bptr->next) X if (bptr->context & WINDOW) X Grab(bptr->mask, window); X awi = RegisterWindow(window); X Decorate(awi->client); X event_mask = PropertyChangeMask | FocusChangeMask; X if (!FrameFocus) X event_mask |= (EnterWindowMask | LeaveWindowMask); X XSelectInput(dpy, window, event_mask); X SetBorderPixmaps(dpy, GrayPixmap); X } X if ((wmhints = XGetWMHints(dpy, window))) { X if ((wmhints->flags & StateHint) && (awi->state & ST_WINDOW) && X (wmhints->initial_state == IconicState)) { X /* window wants to be created as an icon. Leave size X /* and position alone, create as icon. */ X XFree(wmhints); X Iconify(window, 0, 0, 0, 0); X Leave_void X } X XFree(wmhints); X } X } X else if ((awi = GetAwmInfo(window)) == NULL) X awi = RegisterWindow(window); X if (awi->state & ST_WINDOW) { X if (!transient_for) X PlaceWindow(window); X XMapRaised(dpy, awi->frame); X XMapWindow(dpy, awi->client); X XSync(dpy, 0); X } X Leave_void X} X XConfigure(event) XXConfigureRequestEvent *event; X{ X XWindowChanges values; X AwmInfoPtr awi; X X Entry("Configure") X X values.x = event->x; X values.y = event->y; X values.width = event->width; X values.height = event->height; X values.border_width = event->border_width; X values.stack_mode = event->detail; X values.sibling = event->above; X X ConfigureWindow(event->window, event->value_mask, &values); X Leave_void X} X XCirculate(event) XXCirculateEvent *event; X{ X Entry("Circulate") X X if (event->place == PlaceOnTop) X XRaiseWindow(event->display, event->window); X else X XLowerWindow(event->display, event->window); X Leave_void X} X XPlaceWindow(window) XWindow window; X{ X XSizeHints wsh; X int x, y, w, h; X Boolean configureit = False; X XWindowChanges xwc; X AwmInfoPtr awi; X long flags; X X wsh.flags = 0; X flags = CWX | CWY | CWWidth | CWHeight; X awi = GetAwmInfo(window); X XGetSizeHints(dpy, window, &wsh, XA_WM_NORMAL_HINTS); X CheckConsistency(&wsh); X AskUser(dpy, scr, window, &x, &y, &w, &h, &wsh); X X wsh.flags |= (USPosition | USSize); X wsh.x = x; X wsh.y = y; X wsh.width = w; X wsh.height = h; X if (x < 0 || y < 0) { X Window jW; X int j, border_width; X X XGetGeometry(dpy, window, &jW, &j, &j, &j, &j, &border_width, &j); X X if (x < 0) X x += DisplayWidth(dpy, scr) - w - (border_width<<1); X if (y < 0) X y += DisplayHeight(dpy, scr) - h - (border_width<<1); X } X if (awi->frame) X XSetSizeHints(dpy, awi->frame, &wsh, XA_WM_NORMAL_HINTS); X XSetSizeHints(dpy, awi->client, &wsh, XA_WM_NORMAL_HINTS); X#ifdef titan /* 5x4 alignment */ X x += (x % 5); X y += (y % 4); X#endif X xwc.x = x; X xwc.y = y; X xwc.height = h; X xwc.width = w; X ConfigureWindow(window, flags, &xwc); X awi->state |= ST_PLACED; X} X XBoolean ConfigureWindow(w, mask, xwc) XWindow w; Xunsigned long mask; XXWindowChanges *xwc; X{ X XWindowAttributes xwa; X AwmInfoPtr awi; X int height, width, x, y; X int bch = 0, bcv = 0; X Entry("ConfigureWindow") X X awi = GetAwmInfo(w); X if (!awi) X Leave(FALSE) X X if (awi->attrs & AT_BORDER) { X bcv = BContext + 1; X bch = bcv * 2; X } X X height = xwc->height; X width = xwc->width; X x = y = 0; X /* width */ X xwc->width += bch; X if (awi->title) X XResizeWindow(dpy, awi->title, xwc->width, titleHeight); X /* height */ X if (awi->attrs & AT_TITLE) { X y = titleHeight + 2; X xwc->height += y; X } X if (awi->attrs & AT_BORDER) { X if (!(awi->attrs & AT_TITLE)) { X xwc->height += (bcv * 2); X y = bcv; X } X else X xwc->height += bcv; X xwc->x -= (BContext + (awi->border_width ? awi->border_width : 1)); X x = BContext; X } X if (PushDown == FALSE) { X if (awi->attrs & AT_TITLE) X xwc->y -= (titleHeight + 2); X else if (awi->attrs & AT_BORDER) X xwc->y -= (BContext + (awi->border_width ? X awi->border_width : 1)); X } X XConfigureWindow(dpy, awi->frame, mask, xwc); X if (awi->gadgets) X PutGadgets(w); X xwc->width = width; X xwc->height = height; X xwc->x = x; X xwc->y = y; X XConfigureWindow(dpy, awi->client, mask, xwc); X Leave(TRUE) X} X Xint XProcessRequests(box, num_vectors) XXSegment *box; Xint num_vectors; X{ X XEvent event; X X XPeekEvent(dpy, &event); X switch (event.type) { X X case MapRequest: X case ConfigureRequest: X case CirculateRequest: X X DrawBox(); X GetButton(&event); X DrawBox(); X return TRUE; X } X return FALSE; X} END_OF_awm/GetButton.c if test 21347 -ne `wc -c <awm/GetButton.c`; then echo shar: \"awm/GetButton.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f awm/menus/track_menu.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"awm/menus/track_menu.c\" else echo shar: Extracting \"awm/menus/track_menu.c\" \(26723 characters\) sed "s/^X//" >awm/menus/track_menu.c <<'END_OF_awm/menus/track_menu.c' X#ident "%W% %G%" X X#ifndef lint X static char sccs_id[] = "@(#)track_menu.c 2.1 12/16/87 Siemens Corporate Research and Support, Inc."; X#endif X X X#include "X11/copyright.h" X X/* X RTL Menu Package Version 1.0 X by Joe Camaratta and Mike Berman, Siemens RTL, Princeton NJ, 1987 X X track_menu.c: bring up menus and track the mouse X */ X X/* X * X * Copyright 1987, 1988 by Ardent Computer Corporation, Sunnyvale, Ca. X * X * Copyright 1987 by Jordan Hubbard. X * X * X * All Rights Reserved X * X * Permission to use, copy, modify, and distribute this software and its X * documentation for any purpose and without fee is hereby granted, X * provided that the above copyright notice appear in all copies and that X * both that copyright notice and this permission notice appear in X * supporting documentation, and that the name of Ardent Computer X * Corporation or Jordan Hubbard not be used in advertising or publicity X * pertaining to distribution of the software without specific, written X * prior permission. X * X */ X X X/* X X Copyright 1987 by X Siemens Corporate Research and Support, Inc., Princeton, New Jersey X X Permission to use, copy, modify, and distribute this software X and its documentation for any purpose and without fee is X hereby granted, provided that the above copyright notice X appear in all copies and that both that copyright notice and X this permission notice appear in supporting documentation, and X that the name of Siemens not be used in advertising or X publicity pertaining to distribution of the software without X specific, written prior permission. Siemens makes no X representations about the suitability of this software for any X purpose. It is provided "as is" without express or implied X warranty. X X */ X X/* X * The menu package will break if you don't define this, but X * it's there in case you want to see just how and where the X * "eventstack" stuff is used and, if necessary, replace it. X */ X#define SAVE_EVENTS X X X#include <stdio.h> X#include "X11/Xlib.h" X#include "X11/cursorfont.h" X#include "arrow_icon.h" X#include "null_icon.h" X#include "menu.h" X#include "menu.def.h" X#include "menu.ext.h" X#include "dbug.h" X#ifdef SAVE_EVENTS X#include "eventstack.h" X#endif X X#define MIN(x,y) (((x) <= (y))? x:y) X#define MAX(x,y) (((x) >= (y))? x:y) X X#define CLICK_TIME 290 /* in milliseconds */ X X#define CursorLockMask (ButtonReleaseMask | ExposureMask) X X/* Event macros */ X X#define EventGetXCoord(rep) ((rep).xmotion.x) X#define EventGetYCoord(rep) ((rep).xmotion.y) X#define EventType(rep) ((rep).type) X#define EventXWindow(rep) ((rep).xcrossing.window) X#define EventXTime(rep) ((rep).xcrossing.time) X#define EventXMode(rep) ((rep).xcrossing.mode) X#define EventXRootX(rep) ((rep).xcrossing.x_root) X#define EventXRootY(rep) ((rep).xcrossing.y_root) X#define EventXDetail(rep) ((rep).xcrossing.detail) X#define EventMWindow(rep) ((rep).xmotion.window) X#define EventMTime(rep) ((rep).xmotion.time) X#define EventButton(rep) ((rep).xbutton.button) X#define EventBWindow(rep) ((rep).xbutton.window) X#define EventBTime(rep) ((rep).xbutton.time) X#define EventEX(rep) ((rep).xexpose.x) X#define EventEY(rep) ((rep).xexpose.y) X#define EventEWidth(rep) ((rep).xexpose.width) X#define EventEHeight(rep) ((rep).xexpose.height) X#define PointerEvent(rep) \ X ((EventType(rep) == ButtonPress) || \ X (EventType(rep) == ButtonRelease) || \ X (EventType(rep) == MotionNotify) || \ X (EventType(rep) == EnterNotify) || \ X (EventType(rep) == LeaveNotify) || \ X (EventType(rep) == FocusIn) || \ X (EventType(rep) == FocusOut)) X#define KeyEvent(rep) \ X ((EventType(rep) == KeyPress) || (EventType(rep) == KeyRelease)) X/* Possible states for the state machine */ Xtypedef enum X{ X Initial, /* Inside a submenu, but not any item */ X CheckTrigger, /* Inside an item that has submenu, checking for pullright */ X Leaf, /* Inside an item with no submenu */ X Exit, /* Preparing to exit */ X LevelControl /* Not in any submenu, waiting to enter something */ X } State; X XState InitialState(), CheckTriggerState(), LeafState(), LevelControlState(), X GetItemState(); Xbool EventNotSignificant(), PushSubmenu(); X Xvoid OutputEvent(), GetNextSignificantEvent(), PopSubmenu(), X Highlight(), Unhighlight(), DisplayInitialMenus(), LockCursor(), X TossExtraMoves(), UnlockCursor(); X Xvoid ProcessExposeEvents(); X Xvoid SaveTest(); X XMenuItem *MenuGetItem(); XMenu *MenuGetMenu(); X X/* global state variables */ X Xstatic MenuItem *current_item; Xstatic Menu *current_menu; Xstatic Window root_window; Xextern Display *dpy; Xextern int scr; Xstatic int level; /* submenu level */ Xstatic Time button_time; /* time button press invoked */ Xstatic Cursor wait_cursor = None; /* empty cursor for lock state */ Xstatic bool click_allowed; Xstatic bool lock_event_mask, unlock_event_mask; X Xextern int Autoselect; Xextern int MDelta; X X#ifdef SAVE_EVENTS Xstatic struct Ev_q *ev_save = 0; X#endif X X XMenuItem *TrackMenu(root_menu, root_x, root_y, X init_button, root, buttime) XMenu *root_menu; /* Pointer to root menu requested to pop up */ Xint root_x, root_y; /* Position to start menu */ Xint init_button; /* The # of button used to pop up menu */ XWindow root; /* Window label for parent of menu */ XTime buttime; /* timestamp for button (or 0, if CLICK == 0) */ X{ X State CurrentState = LevelControl; X XEvent Event_Reply; X int open_x; X bool selected = FALSE; X MenuItem *selected_item; X X Entry("TrackMenu") X X /* Initialize globals */ X X button_time = buttime; X root_window = root; X level = 0; X current_menu = root_menu; X click_allowed = (TestOptionFlag(current_menu, clickokay))? TRUE : FALSE; X unlock_event_mask = (TestOptionFlag(current_menu, savebits))? X MenuEventMask : (MenuEventMask | ExposureMask); X lock_event_mask = (TestOptionFlag(current_menu, savebits))? X CursorLockMask : (CursorLockMask | ExposureMask); X X /* If not already done, set up the null cursor for lock state */ X if (wait_cursor == None) X { X Pixmap wc_pixmap; X XColor fg, bg; X X wc_pixmap = XCreateBitmapFromData (dpy, root_window, X null_icon_bits, X null_icon_width, null_icon_height); X wait_cursor = XCreatePixmapCursor (dpy, wc_pixmap, wc_pixmap, X &fg, &bg, 1, 1); X } X X X /* Block all other action by grabbing the server */ X /* XGrabServer (dpy); */ X /* Don't think we need to grab the server... so for now, we won't */ X X#ifdef SAVE_EVENTS X /* Get the present state, so it can be restored later */ X /* Any events on the queue when we start get saved now, restored later */ X SaveEvents (dpy, &ev_save, ~(unsigned long) ButtonReleaseMask); X#endif X X LockCursor(root_window); X if (!(current_item = X Display_Menu(current_menu, NULLMENU, root_x, root_y))) X { X CurrentState = Exit; X } X /* X * First item is a label and autoselect is on, so we want X * to push on to the first "real" item. X */ X if (ItemIsDeaf(current_item) && Autoselect) X current_item = current_item->nextItem; X LockCursor(ItemWindow(current_item)); X open_x = root_x; X X /* Push to appropriate previous item, if any */ X while (MenuHasInitialItem(current_menu) && (CurrentState != Exit)) X { X current_item = GetInitialItem(current_menu); X ClearInitialItem(current_menu); X X /* if the initial item can't be selected, take first in list */ X if (ItemIsNull(current_item) || ItemIsDisabled(current_item)) X { X current_item = MenuItems(current_menu); X break; X } X else if (ItemIsLeaf(current_item)) /* then we're done */ X break; X else X { X open_x += ItemGetArrowPosition(current_item); X if (!ItemIsDeaf(current_item)) X Highlight(current_item); X TossExtraMoves(ItemWindow(current_item)); X (void)PushSubmenu(open_x); X } X } X ProcessExposeEvents(); X if (CurrentState != Exit) X CurrentState = (ItemIsLeaf(current_item)) ? Leaf : CheckTrigger; X if (!ItemIsDeaf(current_item)) X Highlight(current_item); X XSync (dpy, 0); /* get release click, if it's in queue */ X#ifdef SAVE_EVENTS X DisposeEvents(dpy, (PointerMotionMask | EnterWindowMask | X LeaveWindowMask | ExposureMask)); X#endif X LockCursor(ItemWindow(current_item)); X PlacePointer(current_menu,current_item); X UnlockCursor(); X X /* State Machine */ X X while (CurrentState != Exit) X { X GetNextSignificantEvent(&Event_Reply, init_button); X switch (CurrentState) X { X case LevelControl: X CurrentState = LevelControlState(Event_Reply); X break; X case Initial: X CurrentState = InitialState(Event_Reply); X break; X case CheckTrigger: X CurrentState = CheckTriggerState(Event_Reply); X break; X case Leaf: X CurrentState = LeafState(Event_Reply, &selected); X break; X default: X Retch("(RTLmenu) YOW! Unknown State! (%d)\n", X CurrentState); X CurrentState = Exit; X break; X } X } X /* Clean up and exit */ X X selected_item = (selected)? current_item : NULLITEM; X while (level) X { X if (selected) X SetInitialItem(current_menu, current_item); X PopSubmenu(); X } X if (selected) X { X SetInitialItem(current_menu, current_item); X } X X Undisplay_Menu(current_menu); X UnlockCursor(); X XUngrabPointer(dpy, CurrentTime); X X /* Throw out any left over events from menu world */ X /* if (TestOptionFlag(current_menu, savebits)) { X XSync(dpy,1); X XUngrabServer(dpy, CurrentTime); add this if grab added! X } X else X XSync(dpy,0);*/ X X /* Push back any events that were lying around when menus started */ X X XFlush(dpy); X#ifdef SAVE_EVENTS X DisposeEvents(dpy, (PointerMotionMask | EnterWindowMask | X LeaveWindowMask | ExposureMask)); X RestoreEvents(dpy, &ev_save); X#endif X Leave(selected_item) X} X X/* Used for debugging */ X Xvoid OutputEvent(Event_Reply) XXEvent Event_Reply; X{ X Entry("OutputEvent") X X switch (EventType(Event_Reply)) X { X case ButtonPress: X case ButtonRelease: X DBUG_5("RTLmenu","Button Press/Release, button %d on window %d at time %d\n", X EventButton(Event_Reply), EventBWindow(Event_Reply), X EventBTime(Event_Reply)); X break; X case MotionNotify: X DBUG_5("RTLmenu","Motion Notify on window %d at time %d, x=%d\n", X EventMWindow(Event_Reply), EventMTime(Event_Reply), X EventGetXCoord(Event_Reply)); X break; X case EnterNotify: X DBUG_4("RTLmenu","Enter Notify on window %d at time %d\n", X EventXWindow(Event_Reply), EventXTime(Event_Reply)); X break; X case LeaveNotify: X DBUG_4("RTLmenu","Leave Notify on window %d at time %d\n", X EventXWindow(Event_Reply), EventXTime(Event_Reply)); X break; X default: X DBUG_3("RTLmenu","Unexpected event type %d\n", EventType(Event_Reply)); X break; X } X Leave_void X} X Xstatic bool locked = FALSE; X X/* Lock the cursor: make it disappear, and ignore events it generates. */ X/* Optionally, confine it to a single window. */ X/* (Using "None" for confine_window doesn't confine it. ) */ Xvoid LockCursor(confine_window) XWindow confine_window; X{ X int result; X X Entry("LockCursor") X X locked = TRUE; X result = XGrabPointer(dpy, X RootWindow(dpy, MenuScreen(current_menu)), X True, lock_event_mask, GrabModeSync, X GrabModeAsync, confine_window, X wait_cursor, CurrentTime); X DBUG_3("RTLmenu","Lock Cursor grab = %d\n",result); X Leave_void X} X X/* Unlock (and unconfine) the cursor. If cursor lock is not set, */ X/* this does nothing. */ X Xvoid UnlockCursor() X{ X int result; X X Entry("UnlockCursor") X X if (locked) X { X locked = FALSE; X result = XGrabPointer(dpy, X RootWindow(dpy, MenuScreen(current_menu)), X True, unlock_event_mask, X GrabModeAsync, GrabModeAsync, None, X MenuCursor(current_menu), CurrentTime); X DBUG_3("RTLmenu","Unlock Cursor grab = %d\n",result); X } X Leave_void X} X X/* Keep getting the X events, until finding one that may be interesting */ X/* to the operation of the state machine. */ X Xvoid GetNextSignificantEvent(Event_Reply,init_button) XXEvent *Event_Reply; Xint init_button; /* the button that initiated the menu */ X{ X XEvent Next_Event_Reply; X bool InsignificantEvent = True; X X Entry("GetNextSignificantEvent") X X /* Loop as long as any of a number of "insignificant" events */ X /* are found; when the event no longer matches one of the tests, */ X /* it is assumed to be "significant" and returned.*/ X do X { X XNextEvent(dpy, Event_Reply); X DBUG_EXECUTE("RTLmenu", OutputEvent(*Event_Reply)); X X /* If this event is an "enter", check whether there is a */ X /* "leave" for the same window already in the queue, */ X /* immediately following it; if so, throw them both out */ X /* and get the next event */ X /* NOTE: might try to look further ahead, but this is */ X /* tricky because other events might intervene. */ X X if ((EventType(*Event_Reply) == EnterNotify) && X (EventXMode(*Event_Reply) == NotifyNormal) && X (QLength(dpy) > 0) && X (MenuGetMenu(current_menu, EventXWindow(*Event_Reply)) X != current_menu)) X { X XPeekEvent(dpy, &Next_Event_Reply); X if ((EventType(Next_Event_Reply) == LeaveNotify) && X (EventXMode(Next_Event_Reply) == NotifyNormal) && X (EventXWindow(Next_Event_Reply) == EventXWindow(*Event_Reply))) X { X DBUG_2("RTLmenu","TOSS: Enter/leave pair.\n"); X XNextEvent(dpy, Event_Reply); X XNextEvent(dpy, Event_Reply); X } X } X#ifdef SAVE_EVENTS X if (EventNotSignificant(*Event_Reply, init_button)) X { X if (!(PointerEvent(*Event_Reply) || KeyEvent(*Event_Reply) X || EventType(*Event_Reply) == Expose)) X { X /* might be significant elsewhere -- save it for later */ X AddEventToStore(&ev_save, *Event_Reply); X } X } X else X#else X if (!EventNotSignificant(*Event_Reply, init_button)) X#endif X InsignificantEvent = FALSE; X } X while (InsignificantEvent); X X DBUG_2("RTLmenu","--->"); X Leave_void X} X X/* Check whether the event matches one of the events considered */ X/* "not significant".*/ Xbool EventNotSignificant(Event_Reply, init_button) XXEvent Event_Reply; Xint init_button; X{ X Entry("EventNotSignificant") X X /* Insignificant if not in following list */ X Leave(!((EventType(Event_Reply) == ButtonRelease) || X (EventType(Event_Reply) == ButtonPress) || X (EventType(Event_Reply) == MotionNotify) || X (EventType(Event_Reply) == EnterNotify) || X (EventType(Event_Reply) == Expose) || X (EventType(Event_Reply) == LeaveNotify)) X || X /* Insignificant if leave or enter is not "Normal" */ X (((EventType(Event_Reply) == LeaveNotify) || X (EventType(Event_Reply) == EnterNotify)) && X (EventXMode(Event_Reply) != NotifyNormal)) X || X /* Insignificant if hit button other than initial one */ X ((EventType(Event_Reply) == ButtonRelease) && X (EventButton(Event_Reply) != init_button)) X || X /* Insignificant if tail end of a click -- and clicks allowed */ X (click_allowed && X (EventType(Event_Reply) == ButtonRelease) && X (EventBTime(Event_Reply) - button_time < CLICK_TIME)) X ) X} X XState LevelControlState(rep) XXEvent rep; X{ X State next_state; X Menu *entered_menu; X MenuItem *entered_item; X X Entry("LevelControlState") X switch (EventType(rep)) X { X case MotionNotify: X case LeaveNotify: X next_state = LevelControl; /* loop back to this state */ X break; X case EnterNotify: X /* Decide whether we've entered a menu window or item window */ X entered_menu = MenuGetMenu(current_menu, EventXWindow(rep)); X entered_item = MenuGetItem(current_menu,EventXWindow(rep)); X X if ((MenuIsNull(entered_menu)) && (ItemIsNull(entered_item))) X /* Must be some other window; carry on */ X next_state = LevelControl; X else if (!ItemIsNull(entered_item) && X MenuIsDisplayed(ItemMenu(entered_item))) X { X /* we entered an item, but not a window. This should only happen */ X /* when we stayed in the parent of the current submenu. So, */ X /* Pop that submenu and get to the item. */ X if (level) X { X LockCursor(ItemWindow(entered_item)); X PopSubmenu(); X ProcessExposeEvents(); X UnlockCursor(); X current_item = entered_item; X Highlight(current_item); X next_state = GetItemState(rep); X } X else /* I must be very confused... */ X { X Retch("(RTLmenu) Tried to pop the root menu...\n"); X next_state = Exit; X } X } X X else if (!MenuIsNull(entered_menu)&& X MenuIsDisplayed(entered_menu)) X { X /* entered a menu that is displayed */ X while ((current_menu != entered_menu) && level) X /* drop down the menu that was entered */ X PopSubmenu(); X ProcessExposeEvents(); X UnlockCursor(); X if (current_menu == entered_menu) X next_state = Initial; X else X { X next_state = Exit; X Retch("(RTLmenu) Couldn't find the menu I entered!!\n"); X } X } X else X next_state = LevelControl; X break; X case ButtonRelease: X next_state = Exit; X break; X default: X Retch("RTLmenu","YOW! Unexpected event! (%d)\n", rep.type); X next_state = Exit; X break; X } X Leave(next_state) X} X X/* Figure out the status of the item we've just entered */ XState GetItemState(rep) XXEvent rep; X{ X int open_x; X State next_state; X X Entry("GetItemState") X if (ItemIsNull(current_item)) X { X Retch("(RTLmenu) null current item!"); X next_state = Exit; X } X else if (MenuIsNull(current_menu)) X { X Retch("(RTLmenu) null current menu!"); X next_state = Exit; X } X else if (ItemIsLeaf(current_item)) X { X if (MenuHasInitialItem(current_menu)) X ClearInitialItem(current_menu); X next_state = Leaf; X } X else if (EventGetXCoord(rep) >= (int)(ItemGetArrowPosition(current_item) - 4)) X { X /* entered item in "auto pop-up zone", i.e., over pull-right arrow. */ X LockCursor(ItemWindow(current_item)); X TossExtraMoves(ItemWindow(current_item)); X if (PushSubmenu(EventXRootX(rep))) X { X LockCursor(ItemWindow(current_item)); X PlacePointer(current_menu, current_item); X next_state = Initial; X ProcessExposeEvents(); X } X else X next_state = CheckTrigger; X UnlockCursor(); X } X else if (MenuHasInitialItem(current_menu)) X { X /* Entered menu has initial item -- move to it */ X DBUG_2("RTLmenu","Pushing for initial item."); X current_item = GetInitialItem(current_menu); X open_x = ItemGetArrowPosition(current_item) + X EventXRootX(rep); X ClearInitialItem(current_menu); X LockCursor(ItemWindow(current_item)); X if (PushSubmenu(open_x)) X { X ProcessExposeEvents(); X LockCursor(ItemWindow(current_item)); X PlacePointer(current_menu, current_item); X next_state = Initial; X } X UnlockCursor(); X } X else /* parent pull */ X next_state = CheckTrigger; X Leave(next_state) X} X XState InitialState( rep) XXEvent rep; X{ X State next_state; X X Entry("Initial") X switch (EventType(rep)) X { X case EnterNotify: X if (MenuIsNull(current_menu)) X { X Retch("(RTLmenu) null current menu!?!?"); X next_state = Exit; X } X else if (EventXDetail(rep) == NotifyInferior) X next_state = Initial; X else X { X current_item = MenuGetItem(current_menu, EventXWindow(rep)); X if (ItemIsNull(current_item)) X { X /* Retch("(RTLmenu) Window entered not an item!\n"); */ X next_state = Exit; X } X else X { X Highlight(current_item); X next_state = GetItemState(rep); X } X } X break; X case LeaveNotify: X /* Decide whether we're actually leaving */ X /* this menu for another submenu or the root, */ X /* or going into an item. */ X next_state = (EventXDetail(rep) == NotifyInferior)? X Initial : LevelControl; X break; X case ButtonRelease: X next_state = Exit; X break; X case MotionNotify: X next_state = Initial; X break; X default: X Retch("(RTLmenu) YOW! Unexpected event! (%d)\n", rep.type); X next_state = Exit; X break; X } X Leave(next_state) X} X X#define NotSet -1 X/* Look to see if pull-right is requested */ XState CheckTriggerState(rep) XXEvent rep; X{ X State next_state = CheckTrigger; X static int Trigger = NotSet; X static int OldX, NewX, childX, button; X X Entry("CheckTrigger") X if (MenuIsNull(current_menu) || ItemIsNull(current_item)) X { X Retch("(RTLmenu) Null menu or item..."); X next_state = Exit; X goto exit; X } X if (Trigger == NotSet) /* set it */ X { X Trigger = MIN(EventGetXCoord(rep) + MenuDelta(current_menu), X ItemGetArrowPosition(current_item)); X NewX = NotSet; X } X switch (EventType(rep)) X { X case LeaveNotify: X next_state = Initial; X Unhighlight(MenuGetItem(current_menu, EventXWindow(rep))); X Trigger = NotSet; X break; X case ButtonRelease: X next_state = Exit; X Trigger = NotSet; X break; X X case ButtonPress: X button = rep.xbutton.button; X while (TRUE) { X XNextEvent(dpy, &rep); X if (rep.type == ButtonRelease && X rep.xbutton.button == button) X break; X } X next_state = CheckTrigger; X childX = TestOptionFlag(current_menu, fixedchild) ? X (MenuX(current_menu) + ItemGetArrowPosition(current_item)) : X EventXRootX(rep); X Trigger = NotSet; X if (PushSubmenu(childX)) X { X next_state = LevelControl; X ProcessExposeEvents(); X LockCursor(ItemWindow(current_item)); X PlacePointer(current_menu, current_item); X } X UnlockCursor(); X break; X X case MotionNotify: X next_state = CheckTrigger; X OldX = NewX; X NewX = EventGetXCoord(rep); X if (NewX >= Trigger) X { X LockCursor(ItemWindow(current_item)); X childX = TestOptionFlag(current_menu, fixedchild)? X (MenuX(current_menu) + ItemGetArrowPosition(current_item)): X EventXRootX(rep); X Trigger = NotSet; X if (PushSubmenu(childX)) X { X next_state = LevelControl; X ProcessExposeEvents(); X LockCursor(ItemWindow(current_item)); X PlacePointer(current_menu, current_item); X } X UnlockCursor(); X } X else if (NewX < OldX) /* reverse motion */ X Trigger = MIN(Trigger, NewX + MenuDelta(current_menu)); X break; X X default: X Retch("(RTLmenu) YOW! Unexpected event!\n"); X next_state = Exit; X break; X } X exit: X Leave(next_state) X} X XState LeafState(rep,selected) XXEvent rep; Xbool *selected; X{ X State next_state; X X Entry("LeafState") X switch(EventType(rep)) X { X case LeaveNotify: X Unhighlight(MenuGetItem(current_menu, EventXWindow(rep))); X next_state = Initial; X break; X X case ButtonRelease: X *selected = TRUE; X next_state = Exit; X break; X X case ButtonPress: X case EnterNotify: X case MotionNotify: /* if events set right, this never happens */ X next_state = Leaf; X break; X X default: X Retch("(RTLMenu) YOW! Unexpected event! (%d)\n", X rep.type); X next_state = Exit; X break; X } X Leave(next_state) X} X Xbool PushSubmenu(x) Xint x; X{ X int y; X bool pushed; X MenuItem *new_current_item; X X Entry("PushSubmenu") X X if (ItemIsNull(current_item)) X { X Retch("(RTLMenu) Can't push from null item.\n"); X pushed = FALSE; X } X else if (MenuIsNull(ItemSubmenu(current_item))) X { X Retch("(RTLmenu) Null submenu.\n"); X pushed = FALSE; X } X else if (ItemIsNull(MenuItems(ItemSubmenu(current_item)))) X /* submenu has no items -- don't push, but not an error */ X pushed = FALSE; X else X { X y = ItemGetMiddleY(current_item); X ++level; X X if (new_current_item = X Display_Menu(ItemSubmenu(current_item), current_menu, x, y)) X { X XFlush(dpy); X current_menu = ItemSubmenu(current_item); X current_item = new_current_item; X if (ItemIsDeaf(current_item) && Autoselect) X current_item = current_item->nextItem; X pushed = TRUE; X } X else X { X Retch("(RTLmenu) Display_Menu failed!\n"); X pushed = FALSE; X } X } X Leave(pushed) X} X Xvoid PopSubmenu() X{ X Menu *parent; X MenuItem *item; X X Entry("PopSubmenu") X --level; X parent = current_menu->parentMenu; X Undisplay_Menu(current_menu); X current_menu = parent; X if (!MenuIsNull(current_menu)) X { X item = MenuItemHighlighted(current_menu); X if (!ItemIsNull(item)) X { X current_item = item; X } X } X X Leave_void X} X Xvoid Highlight(item) XMenuItem *item; X{ X MenuItem *old_highlight; X X Entry("Highlight") X X old_highlight = MenuItemHighlighted(current_menu); X if ((item != old_highlight) && /* else, already highlighted */ X (!ItemIsNull(item))) X { X if (!ItemIsNull(old_highlight) && !ItemIsDeaf(item)) X Unhighlight(old_highlight); X MenuInvert(ItemMenu(item), item); X SetHighlightItem(ItemMenu(item), item); X } X Leave_void X} X Xvoid Unhighlight(item) XMenuItem *item; X{ X Entry("Unhighlight") X if (!ItemIsNull(item)) X { X if (MenuItemHighlighted(current_menu) == item) X { X MenuInvert(ItemMenu(item), item); X ResetHighlightItem(ItemMenu(item)); X } X } X Leave_void X} X Xvoid TossExtraMoves(window) XWindow window; X{ X XEvent ev; X X Entry("TossExtraMoves") X /* XSync(dpy,0); /* make sure they're all on the queue */ X while (XCheckTypedWindowEvent(dpy, window, MotionNotify, &ev)) X DBUG_2("RTLmenu","Tossing extra motion.\n"); X Leave_void X} X X Xvoid ProcessExposeEvents() X{ X MenuItem *item; X XEvent ev; X X Entry("ProcessExposeEvents") X X XSync(dpy,0); X while (XCheckTypedEvent(dpy, Expose, &ev)) X { X item = MenuGetItem(current_menu, EventXWindow(ev)); X if (!ItemIsNull(item)) X Draw_Item(ItemMenu(item), item, EventEX(ev), EventEY(ev), X EventEWidth(ev), EventEHeight(ev)); X } X Leave_void X} END_OF_awm/menus/track_menu.c if test 26723 -ne `wc -c <awm/menus/track_menu.c`; then echo shar: \"awm/menus/track_menu.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of archive 9 \(of 13\). cp /dev/null ark9isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 13 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 Mike Wexler(wyse!mikew) Phone: (408)433-1000 x1330