sdo@soliado.East.Sun.COM (Scott Oaks - Sun Consulting NYC) (04/29/91)
Submitted-by: sdo@soliado.East.Sun.COM (Scott Oaks - Sun Consulting NYC) Posting-number: Volume 12, Issue 61 Archive-name: olvwm/part05 #! /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 5 (of 16)." # Contents: Notice.c winmenu.c winroot.c # Wrapped by sdo@piccolo on Fri Apr 26 17:31:05 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Notice.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Notice.c'\" else echo shar: Extracting \"'Notice.c'\" \(14629 characters\) sed "s/^X//" >'Notice.c' <<'END_OF_FILE' X/* X * (c) Copyright 1989, 1990 Sun Microsystems, Inc. Sun design patents X * pending in the U.S. and foreign countries. See LEGAL_NOTICE X * file for terms of the license. X * X * Written for Sun Microsystems by Crucible, Santa Cruz, CA. X */ X static char sccsid[] = "@(#) Notice.c 25.6 90/05/22 Crucible"; X X#include <errno.h> X#include <stdio.h> X#include <X11/Xos.h> X#include <X11/Xlib.h> X#include <X11/Xutil.h> X#include <olgx/olgx.h> X X#include "olwm.h" X#include "notice.h" X#include "globals.h" X extern Graphics_info *olgx_gistext; extern Graphics_info *olgx_gisbutton; X extern int PointInRect(); X X#define NOTICE_EVENT_MASK ( ButtonPressMask | ButtonReleaseMask \ X | PointerMotionMask | KeyPressMask ) X#define NOTICE_ATTR_MASK ( CWBorderPixel | CWBackPixel | CWSaveUnder ) X X/* difference between inside beveled box and outside beveled box */ X#define BORDER_WIDTH 5 X#define MIN_BOX_SIDE ( 15 + BORDER_WIDTH ) /* betw side & text */ X#define MIN_BOX_TOP ( 15 + BORDER_WIDTH ) /* betw top & text */ X#define MIN_BOX_BOTTOM ( 15 + BORDER_WIDTH ) /* betw bot & text */ X#define MIN_BUTTON_SPACE 15 /* space between buttons */ X#define MIN_BUTTON_VSPACE 15 /* space above buttons */ X#define MIN_STRING_VSPACE 5 /* space above/below strings */ X typedef struct { X int x; X int y; X unsigned int width; /* space taken up by text */ X unsigned int fullWidth; /* width including endcaps */ X} noticeButtonDetails; X typedef struct { X Display *dpy; X Window window; X unsigned int buttonHeight; X unsigned int fontHeight; X unsigned int boxHeight; X unsigned int boxWidth; X int x; X int y; X int totalButtonWidth; X noticeButtonDetails *buttonInfo; X} noticeBoxDetails; X static void calculateBoxDimensions(); static void drawNoticeBox(); static int noticeEventLoop(); X X/* X * NoticeBox -- pop up a box which forces the user to answer X * a question using the buttons X * X * Arguments: X * dpy - pointer to current display X * screen - index to current screen X * noticeBox - pointer to NoticeBox structure: X * numButtons (number of buttons) X * defaultButton (index into buttonText for mouse warp) X * buttonText (array of strings for button text) X * numStrings (number of descriptive strings) X * stringText (array of strings for description) X * boxX (box origin (-1 =use default/centered)) X * boxY (box origin (-1 =use default/centered)) X * X * Default placement of the box is centered in the display X * Returns -1 on failure (0 for 0th button, 1 for 1st button, etc.) X */ int UseNoticeBox( dpy, screen, noticeBox ) Display *dpy; int screen; NoticeBox *noticeBox; X{ X XSetWindowAttributes attributes; X int buttonSelected; X noticeBoxDetails boxDetails; X int pointerX, pointerY; X int dummyInt; X Window dummyWin; X int ii; X int defaultButton; X X /* set up window attributes structure */ X attributes.border_pixel = GRV.Bg2Color; X attributes.background_pixel = GRV.Bg1Color; X attributes.save_under = True; X X /* set up initial elements of boxDetails structure */ X boxDetails.dpy = dpy; X boxDetails.buttonInfo = X (noticeButtonDetails *)MemAlloc( noticeBox->numButtons X * (unsigned int)sizeof(noticeButtonDetails) ); X X /* figure out size to make window and where to put it */ X calculateBoxDimensions( screen, noticeBox, &boxDetails ); X X /* create window */ X boxDetails.window = XCreateWindow( dpy, X RootWindow(dpy, X DefaultScreen(dpy)), X boxDetails.x, boxDetails.y, X boxDetails.boxWidth, X boxDetails.boxHeight, 0, X DefaultDepth(dpy, DefaultScreen(dpy)), X InputOutput, CopyFromParent, X NOTICE_ATTR_MASK, X &attributes ); X X /* grab server and map window so box can be drawn here */ X XGrabServer( dpy ); X XMapRaised( dpy, boxDetails.window ); X X /* only beep if beeps are selected */ X if (GRV.Beep != BeepNever) X XBell(dpy,100); X X drawNoticeBox( noticeBox, &boxDetails ); X X /* save current mouse position */ X XQueryPointer( dpy, RootWindow(dpy, DefaultScreen(dpy)), X &dummyWin, &dummyWin, X &pointerX, &pointerY, X &dummyInt, &dummyInt, &dummyInt ); X X /* warp pointer to default button */ X defaultButton = noticeBox->defaultButton; X if (GRV.PopupJumpCursor) X XWarpPointer( dpy, None, boxDetails.window, 0, 0, 0, 0, X boxDetails.buttonInfo[defaultButton].x X + boxDetails.buttonInfo[defaultButton].fullWidth/2, X boxDetails.buttonInfo[defaultButton].y X + boxDetails.buttonHeight/2 ); X X XSelectInput( dpy, boxDetails.window, NOTICE_EVENT_MASK ); X buttonSelected = noticeEventLoop( noticeBox, &boxDetails ); X X /* put the pointer back where we got it */ X /* REMIND we need to test to see if the pointer is still within the X * default button */ X if (GRV.PopupJumpCursor) X XWarpPointer( dpy, None, RootWindow(dpy, DefaultScreen(dpy)), X 0, 0, 0, 0, pointerX, pointerY ); X X /* free up the server as soon as we're done with it */ X XUngrabServer( dpy ); X X /* destroy window */ X XDestroyWindow( dpy, boxDetails.window ); X MemFree( boxDetails.buttonInfo ); X return( buttonSelected ); X} X X/* X * noticeEventLoop -- watch for events while in notice box X * X */ static int noticeEventLoop( noticeBox, details ) NoticeBox *noticeBox; noticeBoxDetails *details; X{ X XEvent event; X Bool done = False; X int buttonSelected = -1; X int buttonDown = -1; X Bool buttonDrawnDown = False; X int ii; X int buttonState; /* OLGX_NORMAL or OLGX_DEFAULT */ X int keyboardGrabbed = False; X X /* take control until we get an answer */ X /* REMIND: we're assuming the pointer can be grabbed, X * since we were successfully called from some menu X * REMIND: we may want to change the pointer during the grab X */ X XGrabPointer( details->dpy, details->window, False, X NOTICE_EVENT_MASK, X GrabModeAsync, GrabModeAsync, X None, None, CurrentTime ); X X /* REMIND: need to check return, in case someone else has X * grabbed the keyboard (what to do then? just XGrabKey(), X * or ignore keypress events?) X */ X keyboardGrabbed = ( GrabSuccess == XGrabKeyboard( X details->dpy, details->window, X False, GrabModeAsync, X GrabModeAsync, CurrentTime ) ); X X while ( !done ) X { X XNextEvent( details->dpy, &event ); X X /* X * Discard synthetic events X * X * This event loop is only interested in user events, so we X * don't even bother checking to see if this event is a mouse X * or keyboard event. X */ X if (event.xany.send_event) X continue; X X switch (event.type) X { X case ButtonPress: X /* first check to see if we're even in the notice box */ X if ( !PointInRect( event.xbutton.x, X event.xbutton.y, X 0, 0, X details->boxWidth, X details->boxHeight ) ) X break; X X /* if on one of the notice buttons, depress it */ X for ( ii = 0 ; ii < noticeBox->numButtons ; ii++ ) X { X if ( PointInRect( event.xbutton.x, X event.xbutton.y, X details->buttonInfo[ii].x, X details->buttonInfo[ii].y, X details->buttonInfo[ii].fullWidth, X details->buttonHeight ) ) X { X buttonDown = ii; X buttonDrawnDown = True; X olgx_draw_button( olgx_gisbutton, X details->window, X details->buttonInfo[ii].x, X details->buttonInfo[ii].y, X details->buttonInfo[ii].fullWidth, 0, X noticeBox->buttonText[ii], X OLGX_INVOKED ); X break; X } X } X break; X X case ButtonRelease: X /* only a depressed button can be selected */ X if ( PointInRect( event.xbutton.x, X event.xbutton.y, X details->buttonInfo[buttonDown].x, X details->buttonInfo[buttonDown].y, X details->buttonInfo[buttonDown].fullWidth, X details->buttonHeight ) ) X { X buttonSelected = buttonDown; X done = True; X } X X if (!done) X { X buttonDown = -1; X buttonDrawnDown = False; X } X X break; X X case MotionNotify: X /* check state of buttons */ X if ( buttonDown < 0 ) X break; X X if ( PointInRect( event.xbutton.x, X event.xbutton.y, X details->buttonInfo[buttonDown].x, X details->buttonInfo[buttonDown].y, X details->buttonInfo[buttonDown].fullWidth, X details->buttonHeight ) ) X { X /* Moved within button down at start of motion. X * If the button was is drawn undepressed, X * make it go down. X */ X if ( !buttonDrawnDown ) X { X olgx_draw_button( olgx_gisbutton, X details->window, X details->buttonInfo[buttonDown].x, X details->buttonInfo[buttonDown].y, X details->buttonInfo[buttonDown].fullWidth, 0, X noticeBox->buttonText[buttonDown], X OLGX_INVOKED ); X X buttonDrawnDown = True; X } X } X else X { X /* Moved out of button that was down at start. X * If the button was previously drawn down, X * draw it undepressed. X */ X if ( buttonDrawnDown ) X { X /* check if needs "default" indicator */ X if ( noticeBox->defaultButton == buttonDown ) X buttonState = OLGX_DEFAULT; X else X buttonState = OLGX_NORMAL; X X olgx_draw_button( olgx_gisbutton, X details->window, X details->buttonInfo[buttonDown].x, X details->buttonInfo[buttonDown].y, X details->buttonInfo[buttonDown].fullWidth, X 0, noticeBox->buttonText[buttonDown], X buttonState | OLGX_ERASE ); X X buttonDrawnDown = False; X } X } X X break; X X case KeyPress: X if (keyboardGrabbed && X event.xkey.keycode == GRV.ConfirmKey.keycode ) X { X buttonSelected = noticeBox->defaultButton; X done = True; X } X X break; X X default: X break; X } X } X X /* release control */ X XUngrabPointer( details->dpy, CurrentTime ); X if ( keyboardGrabbed ) X XUngrabKeyboard( details->dpy, CurrentTime ); X XFlush( details->dpy ); X X return( buttonSelected); X} X X/* X * calculateBoxDimensions -- determine size of box needed, etc. based on X * information passed in in noticeBox structure. Return X * values in boxDetails structure. X */ static void calculateBoxDimensions( screen, noticeBox, boxDetails ) int screen; NoticeBox *noticeBox; noticeBoxDetails *boxDetails; X{ X unsigned int displayWidth, displayHeight; X int longestStringLength = 0; X int totalButtonWidth = 0; X int ii; X X boxDetails->fontHeight = GRV.TextFontInfo->ascent + X GRV.TextFontInfo->descent; X X /* calculate the width of the text which appears inside the button */ X for ( ii = 0 ; ii < noticeBox->numButtons ; ii++ ) X { X boxDetails->buttonInfo[ii].width = X XTextWidth( GRV.ButtonFontInfo, X noticeBox->buttonText[ii], X strlen(noticeBox->buttonText[ii]) ); X boxDetails->buttonInfo[ii].fullWidth = X boxDetails->buttonInfo[ii].width X + 2 * ButtonEndcap_Width(olgx_gisbutton); X } X X /* add together widths of all the buttons */ X for ( ii = 0 ; ii < noticeBox->numButtons ; ii++ ) X totalButtonWidth += boxDetails->buttonInfo[ii].fullWidth; X boxDetails->totalButtonWidth = totalButtonWidth; X X /* figure out which descriptive string is longest */ X for ( ii = 0 ; ii < noticeBox->numStrings ; ii++ ) X longestStringLength = X MAX( longestStringLength, X XTextWidth( GRV.TextFontInfo, X noticeBox->stringText[ii], X strlen(noticeBox->stringText[ii]) ) ); X X /* X * REMIND: this calculation assumes all the buttons are X * on the same line X */ X boxDetails->boxWidth = 2 * MIN_BOX_SIDE X + MAX( longestStringLength, X totalButtonWidth + X /* amount of space between all the buttons */ X MIN_BUTTON_SPACE * (noticeBox->numButtons - 1) ); X X boxDetails->buttonHeight = Button_Height(olgx_gisbutton); X X boxDetails->boxHeight = MIN_BOX_TOP + MIN_BOX_BOTTOM X + ( noticeBox->numStrings * boxDetails->fontHeight ) X /* amount of space vertically between all the strings */ X + ( (noticeBox->numStrings - 1) * MIN_STRING_VSPACE ) X + MIN_BUTTON_VSPACE + boxDetails->buttonHeight; X X displayWidth = DisplayWidth( boxDetails->dpy, screen ); X displayHeight = DisplayHeight( boxDetails->dpy, screen ); X X /* if not set, create default "origin" for box: centered */ X boxDetails->x = ( noticeBox->boxX == -1 ) X ? (int)( displayWidth - boxDetails->boxWidth )/2 X : noticeBox->boxX ; X boxDetails->y = ( noticeBox->boxY == -1 ) X ? (int)( displayHeight - boxDetails->boxHeight )/2 X : noticeBox->boxY ; X X} X X/* X * drawNoticeBox -- draw box outline, strings, and buttons using information X * in noticeBox and boxDetails structures which are passed in. X * Location of buttons (x, y) are set in boxDetails structure X * for use later (mouse warping, determining pointer position). X */ static void drawNoticeBox( noticeBox, boxDetails ) NoticeBox *noticeBox; noticeBoxDetails *boxDetails; X{ X int ii; X int buttonX, buttonY; X int buttonState; /* OLGX_NORMAL or OLGX_DEFAULT */ X X /* draw beveled box */ X olgx_draw_box( olgx_gistext, boxDetails->window, 0, 0, X boxDetails->boxWidth, boxDetails->boxHeight, X OLGX_NORMAL, True ); X X olgx_draw_box( olgx_gistext, boxDetails->window, X BORDER_WIDTH, BORDER_WIDTH, X boxDetails->boxWidth - 2 * BORDER_WIDTH, X boxDetails->boxHeight - 2 * BORDER_WIDTH, X OLGX_NORMAL, True ); X X /* draw descriptive text X * REMIND: all strings are along the left edge (MIN_BOX_SIDE) X */ X for ( ii = 0 ; ii < noticeBox->numStrings ; ii++ ) X olgx_draw_text( olgx_gistext, boxDetails->window, X noticeBox->stringText[ii], MIN_BOX_SIDE, X /* need to move each line further down the screen */ X MIN_BOX_TOP + GRV.TextFontInfo->ascent * ( ii + 1 ) X + ( MIN_STRING_VSPACE * ii ), X 0, False, OLGX_NORMAL ); X X /* put buttons in - notice that it's a single row */ X /* row of buttons should be centered within available space, X * assuming MIN_BUTTON_SPACE between each of the them X */ X buttonX = ( boxDetails->boxWidth - (boxDetails->totalButtonWidth X + MIN_BUTTON_SPACE * (noticeBox->numButtons - 1)) )/2; X /* this calculates from the bottom of the box */ X buttonY = ( boxDetails->boxHeight - X ( MIN_BOX_BOTTOM + boxDetails->buttonHeight ) ); X for ( ii = 0 ; ii < noticeBox->numButtons ; ii++ ) X { X if ( noticeBox->defaultButton == ii ) X buttonState = OLGX_DEFAULT; X else X buttonState = OLGX_NORMAL; X X /* save button's x, y values for use later */ X boxDetails->buttonInfo[ii].x = buttonX; X boxDetails->buttonInfo[ii].y = buttonY; X X olgx_draw_button( olgx_gisbutton, boxDetails->window, X buttonX, buttonY, X boxDetails->buttonInfo[ii].fullWidth, 0, X noticeBox->buttonText[ii], X buttonState ); X X /* set up buttonX for next button */ X buttonX = buttonX + boxDetails->buttonInfo[ii].fullWidth X + MIN_BUTTON_SPACE; X } X} END_OF_FILE if test 14629 -ne `wc -c <'Notice.c'`; then echo shar: \"'Notice.c'\" unpacked with wrong size! fi # end of 'Notice.c' fi if test -f 'winmenu.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'winmenu.c'\" else echo shar: Extracting \"'winmenu.c'\" \(13410 characters\) sed "s/^X//" >'winmenu.c' <<'END_OF_FILE' X/* X * (c) Copyright 1989, 1990 Sun Microsystems, Inc. Sun design patents X * pending in the U.S. and foreign countries. See LEGAL_NOTICE X * file for terms of the license. X * X * Written for Sun Microsystems by Crucible, Santa Cruz, CA. X */ X static char sccsid[] = "@(#)winmenu.c 1.2 olvwm version 3/30/91"; X X/* X * Based on static char sccsid[] = "@(#) winmenu.c 25.4 90/05/18 Crucible"; X * X */ X X#include <errno.h> X#include <stdio.h> X#include <X11/Xos.h> X#include <X11/Xlib.h> X#include <X11/Xutil.h> X#include <X11/Xatom.h> X#include <olgx/olgx.h> X#include "mem.h" X#include "olwm.h" X#include "win.h" X#include "menu.h" X#include "globals.h" X X/*************************************************************************** X* global data X***************************************************************************/ X extern Atom AtomDecorAdd; extern Atom AtomDecorHeader; extern Atom AtomDecorPin; extern Atom AtomDeleteWindow; extern Atom AtomMenuLimited; extern Atom AtomProtocols; extern Atom AtomPushpinState; extern Atom AtomWinAttr; extern Atom AtomWTOther; X extern Window NoFocusWin; X X/*************************************************************************** X* private data X***************************************************************************/ X X/* function vector for menu windows */ static ClassMenu classMenu; X static int bindex_last; /* set to last menu button pressed; cleared X * when button released or a submenu is X * brought up */ X X/* X * after_info_t X * X * REMIND this is an abomination. This structure simply holds the arguments X * for the "afterProcessing" function, which should get called when a pop-up X * menu is finished tracking. Unfortunately, the architecture of this pinned X * menu system assumes that popping up a menu is synchronous, when in fact it X * just installs an event interposer and returns immediately. The solution is X * to pass along this information as a closure and have the information passed X * back by the menu "sync" function. X */ X typedef struct { X Display *dpy; X Menu *menu; X WinMenu *winInfo; X int bindex; X} after_info_t; X static after_info_t afterInfo; X X/*************************************************************************** X* private functions X***************************************************************************/ X static void afterProcessing(dpy, menu, winInfo, bindex) Display *dpy; Menu *menu; WinMenu *winInfo; int bindex; X{ X unsigned long nItems, remain; X long *pinState; X X /* unhighlight button */ X if ((bindex >= 0) && (bindex < menu->buttonCount)) X SetButton(dpy, menu, bindex, False); X X /* if our push-pin is out then we should go away */ X pinState = GetWindowProperty(dpy, winInfo->core.self, AtomPushpinState, X 0L, LONG_LENGTH(long), XA_INTEGER, 0, &nItems, &remain); X X if (pinState != NULL) X { X if (*pinState == PIN_OUT) /* pin is out */ X { X /* make our window die */ X ClientKill(winInfo->core.client,False); X } X XFree(pinState); X } X} X X static void afterProcWrapper( i ) X after_info_t *i; X{ X afterProcessing( i->dpy, i->menu, i->winInfo, i->bindex ); X} X X/* pressButton -- a user has moved the pointer in such a way that a X * button should be pressed (that is, highlighted, ready for X * activation. If any other button is pressed, unpress that button X * along the way. X */ static int pressButton(dpy, menu, winInfo, event, bindex, mbutton) Display *dpy; Menu *menu; WinMenu *winInfo; XXEvent *event; int bindex; int mbutton; X{ X if ((mbutton == MB_MENU) || (mbutton = MB_SELECT)) X { X SetButton(dpy, menu, bindex, True); X X if ((menu->buttons[bindex].stacked == True) && X (menu->buttons[bindex].action.submenu != NULL) && X (mbutton == MB_MENU)) X { X afterInfo.dpy = dpy; X afterInfo.menu = menu; X afterInfo.winInfo = winInfo; X afterInfo.bindex = bindex; X MenuShowSync(dpy, winInfo, X (Menu *)(menu->buttons[bindex].action.submenu), X event, afterProcWrapper, &afterInfo); X } X } X} X X X X/* findButton - find the button corresponding to an x,y position X * modifies the x,y position to the correct popup location X * for cascaded menus. X * returns: button index or -1 if button not found X */ static int findButton(menu, ex, ey, winInfo) Menu *menu; int *ex, *ey; WinMenu *winInfo; X{ X int bindex; X X /* figure out if the button press is in a button */ X for (bindex=0; bindex < menu->buttonCount; bindex++) X { X if (PointInRect(*ex, *ey, X menu->buttons[bindex].activeX, X menu->buttons[bindex].activeY, X menu->buttons[bindex].activeW, X menu->buttons[bindex].activeH)) X { X WinRootPos(winInfo, ex, ey); X *ex += menu->buttons[bindex].activeX + X menu->buttons[bindex].activeW; X *ey += menu->buttons[bindex].activeY; X return bindex; X } X } X return -1; X} X X X/*************************************************************************** X* private event functions X***************************************************************************/ X X/* X * eventButtonPress - a button has gone down. X */ static int eventButtonPress(dpy, event, winInfo) Display *dpy; XXEvent *event; WinMenu *winInfo; X{ X Menu *menu = (Menu *)(winInfo->menu); X int bindex; X int ex, ey; X X ex = event->xbutton.x; X ey = event->xbutton.y; X bindex = findButton(menu, &ex, &ey, winInfo); X bindex_last = bindex; X if (bindex != -1) X pressButton(dpy, menu, winInfo, event, bindex, MouseButton(dpy,event)); X} X X/* X * eventButtonRelease - a button has gone up X */ static int eventButtonRelease(dpy, event, winInfo) Display *dpy; XXEvent *event; WinMenu *winInfo; X{ X Menu *menu = (Menu *)(winInfo->menu); X int bindex; X int ex, ey; X X ex = event->xbutton.x; X ey = event->xbutton.y; X X if (MouseButton(dpy,event) == MB_ADJUST) X return; X X bindex = findButton(menu, &ex, &ey, winInfo); X X /* Make sure that the button under the ButtonRelease is the X * same one that the ButtonPress went down on. X */ X if ((bindex == bindex_last) && X (bindex_last >= 0) && X (bindex_last < menu->buttonCount)) X ExecButtonAction(dpy,winInfo,menu,bindex,True); X X afterProcessing(dpy,menu,winInfo,bindex_last); X} X X/* X * eventClientMessage - handle a DELETE_WINDOW message. X */ static int eventClientMessage(dpy, event, winInfo) Display *dpy; XXEvent *event; WinMenu *winInfo; X{ X if ((event->xclient.message_type == AtomProtocols) && X (event->xclient.data.l[0] == AtomDeleteWindow)) X { X DestroyClient(winInfo->core.client); X } X} X X/* X * eventPropertyNotify - the main window manager has changed a property on X * our pane; handle the property. X */ static int eventPropertyNotify(dpy, event, winInfo) Display *dpy; XXEvent *event; WinMenu *winInfo; X{ X ClientDistributeProperty(winInfo->core.client, event); X} X X X/* X * drawMenu -- draw the menu window X */ X/*ARGSUSED*/ /* dpy arg will be used when multiple Displays supported */ static int drawMenu(dpy, winInfo) Display *dpy; WinMenu *winInfo; X{ X DrawMenu(dpy, winInfo->menu); X} X X X/* X * DestroyMenu -- destroy the menu window resources and free any allocated X * data. X */ static int destroyMenu(dpy, winInfo) Display *dpy; WinMenu *winInfo; X{ X /* free our data and throw away window */ X ((Menu *)winInfo->menu)->originalMenu->currentlyDisplayed = False; X MemFree(winInfo->menu); X XUndefineCursor(dpy, winInfo->core.self); X XDestroyWindow(dpy, winInfo->core.self); X WIUninstallInfo(winInfo->core.self); X MemFree(winInfo); X} X X/* X * focusselectMenu - the focus or selection state has changed X */ static int focusselectMenu(dpy, winInfo, selected) Display *dpy; WinMenu *winInfo; Bool selected; X{ X (WinFunc(winInfo,core.drawfunc))(dpy, winInfo); X} X X/* X * newconfigMenu - recomputes the size of the menu window X * Note that menus don't change size, so this is a no-op. X */ static int newconfigMenu(win, pxcre) WinMenu *win; XXConfigureRequestEvent *pxcre; X{ X return win->core.dirtyconfig; X} X X/* menuSetParent -- callback during creation. Since menus are internally- X * created windows we must fix up certain fields that are only available X * after the window is mapped. X */ static int menuSetParent(w,cli,par) WinMenu *w; Client *cli; WinGenericFrame *par; X{ X w->core.client = cli; X WinAddChild(par,w); X XReparentWindow(cli->dpy, w->core.self, par->core.self, w->core.x, w->core.y); X par->fcore.panewin = (WinGenericPane *)w; X} X X X/*************************************************************************** X* global functions X***************************************************************************/ X X/* X * MakeMenu -- create the pinned menu's menu window (around which we'll put X * a frame). The window is mapped during the transition to normal X * state. X */ WinMenu * MakeMenu(dpy, junkwindow, menu, idx) Display *dpy; WinGeneric *junkwindow; Menu *menu; int idx; X{ X WinMenu *w; X Window win; X unsigned long valuemask; X XSetWindowAttributes attributes; X Menu *originalMenu; X Atom atomList[3]; X NewXSizeHints sizeHints; X XWMHints wmHints; X X /* save a pointer to the menu we're putting in the window. X * We will duplicate the structure later on and set the X * currentlyDisplayed flag in the original. X */ X originalMenu = menu; X X /* create the associated structure */ X w = MemNew(WinMenu); X w->class = &classMenu; X w->core.kind = WIN_MENU; X w->core.children = NULL; X w->core.x = menu->x; X w->core.y = menu->y; X w->core.width = menu->width; X w->core.height = menu->height - menu->titleHeight; X w->core.dirtyconfig = CWX|CWY|CWWidth|CWHeight; X w->core.exposures = NULL; X X /* create the actual window */ X attributes.event_mask = ButtonReleaseMask | ButtonPressMask | X ExposureMask | PropertyChangeMask; X attributes.background_pixel = GRV.Bg1Color; X attributes.cursor = GRV.MenuPointer; X valuemask = CWEventMask | CWBackPixel | CWCursor; X X win = XCreateWindow(dpy, RootWindow(dpy, DefaultScreen(dpy)), X w->core.x, w->core.y, X w->core.width, w->core.height, X 0, X DefaultDepth(dpy, DefaultScreen(dpy)), X InputOutput, X DefaultVisual(dpy, DefaultScreen(dpy)), X valuemask, X &attributes); X w->core.self = win; X X /* register the window */ X WIInstallInfo(w); X X /* first we set the properties defining what kind of OpenLook window it is */ X atomList[0] = AtomWTOther; X atomList[1] = AtomMenuLimited; X atomList[2] = (Atom) PIN_IN; X XChangeProperty(dpy, win, AtomWinAttr, AtomWinAttr, X 32, PropModeReplace, (unsigned char *)atomList, 3); X X /* add a push-pin */ X atomList[0] = AtomDecorPin; X atomList[1] = AtomDecorHeader; X XChangeProperty(dpy, win, AtomDecorAdd, XA_ATOM, X 32, PropModeReplace, (unsigned char *)atomList, 2); X X /* set protocols */ X atomList[0] = AtomDeleteWindow; X XChangeProperty(dpy, win, AtomProtocols, XA_ATOM, X 32, PropModeReplace, (unsigned char *)atomList, 1); X X /* now set the size hints */ X sizeHints.flags = USPosition | USSize; X XChangeProperty(dpy, win, XA_WM_NORMAL_HINTS, XA_WM_SIZE_HINTS, X 32, PropModeReplace, (unsigned char *)&sizeHints, X sizeof(NewXSizeHints)/sizeof(long)); X X /* and the wmHints */ X wmHints.flags = InputHint | StateHint | WindowGroupHint; X wmHints.initial_state = NormalState; X wmHints.input = False; X /* X * REMIND this is hack to make StateNew think we're a dependent X * follower, and thus not iconify us. X */ X wmHints.window_group = NoFocusWin; X X XChangeProperty(dpy, win, XA_WM_HINTS, XA_WM_HINTS, X 32, PropModeReplace, (unsigned char *)&wmHints, X sizeof(XWMHints)/sizeof(long)); X X XStoreName(dpy, win, menu->title); X X /* create a private, duplicate menu structure */ X w->menu = (void *)MemNew(Menu); X *(Menu *)(w->menu) = *menu; X menu = (Menu *)(w->menu); X menu->originalMenu = originalMenu; X originalMenu->currentlyDisplayed = True; X menu->title = NULL; X menu->x = menu->y = 0; X menu->titleHeight = menu->titleWidth = 0; X menu->height = w->core.height; X menu->window = win; X X StateNew(dpy, win, False, w); X X return w; X} X void MenuInit(dpy) Display *dpy; X{ X classMenu.core.kind = WIN_MENU; X classMenu.core.xevents[ButtonPress] = eventButtonPress; X classMenu.core.xevents[ButtonRelease] = eventButtonRelease; X classMenu.core.xevents[ClientMessage] = eventClientMessage; X classMenu.core.xevents[PropertyNotify] = eventPropertyNotify; X classMenu.core.xevents[Expose] = WinEventExpose; X classMenu.core.focusfunc = focusselectMenu; X classMenu.core.drawfunc = drawMenu; X classMenu.core.destroyfunc = destroyMenu; X classMenu.core.selectfunc = focusselectMenu; X classMenu.core.newconfigfunc = newconfigMenu; X classMenu.core.newposfunc = WinNewPosFunc; X classMenu.core.setconfigfunc = WinSetConfigFunc; X classMenu.core.createcallback = menuSetParent; X classMenu.core.heightfunc = NULL; X classMenu.core.widthfunc = NULL; X classMenu.pcore.setsizefunc = NULL; X X} END_OF_FILE if test 13410 -ne `wc -c <'winmenu.c'`; then echo shar: \"'winmenu.c'\" unpacked with wrong size! fi # end of 'winmenu.c' fi if test -f 'winroot.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'winroot.c'\" else echo shar: Extracting \"'winroot.c'\" \(14250 characters\) sed "s/^X//" >'winroot.c' <<'END_OF_FILE' X/* X * (c) Copyright 1989, 1990 Sun Microsystems, Inc. Sun design patents X * pending in the U.S. and foreign countries. See LEGAL_NOTICE X * file for terms of the license. X * X * Written for Sun Microsystems by Crucible, Santa Cruz, CA. X */ X static char sccsid[] = "@(#)winroot.c 1.2 olvwm version 3/30/91"; X X/* X * Based on static char sccsid[] = "@(#) winroot.c 25.8 90/05/22 Crucible"; X * X */ X X#include <errno.h> X#include <stdio.h> X#include <X11/Xos.h> X#include <X11/Xlib.h> X#include <X11/Xutil.h> X#include <X11/Xatom.h> X#include <X11/Xresource.h> X#include <olgx/olgx.h> X#include "mem.h" X#include "olwm.h" X#include "win.h" X#include "menu.h" X#include "globals.h" X#include "group.h" X X/*************************************************************************** X* global data X***************************************************************************/ X extern Menu *RootMenu; extern Window NoFocusWin; extern Time SelectionTime; X X/*************************************************************************** X* private data X***************************************************************************/ X static int lastButton; static XEvent buttonPressEvent; static ClassRoot classRoot; X X/*************************************************************************** X* private functions X***************************************************************************/ X static void redistributeKeystroke( dpy, e ) Display *dpy; XXEvent *e; X{ X XKeyEvent *ke = (XKeyEvent *) e; X Window childwin, dstwin, srcwin; X int srcx, srcy, dstx, dsty; X static Bool pressreceived = False; X static XKeyEvent pressevent; X X if ( ke->type == KeyPress ) { X if ( pressreceived == False ) { X srcwin = ke->window; X dstwin = ke->window; X srcx = ke->x; X srcy = ke->y; X while (1) { X XTranslateCoordinates( dpy, srcwin, dstwin, srcx, srcy, X &dstx, &dsty, &childwin ); X if ( childwin == None ) X break; X srcx = dstx; X srcy = dsty; X srcwin = dstwin; X dstwin = childwin; X } X pressevent = *ke; X pressevent.x = dstx; X pressevent.y = dsty; X pressevent.window = dstwin; X pressevent.subwindow = None; X pressreceived = True; X } X } else { X if ( pressreceived == True ) { X#ifdef notdef X XUngrabKeyboard( dpy, pressevent.time ); X#endif /* notdef */ X XSendEvent( dpy, pressevent.window, True, X KeyPressMask, &pressevent ); X XTranslateCoordinates( dpy, ke->window, pressevent.window, X ke->x, ke->y, &dstx, &dsty, &childwin ); X ke->x = dstx; X ke->y = dsty; X ke->window = pressevent.window; X ke->subwindow = None; X XSendEvent( dpy, pressevent.window, True, KeyPressMask, ke ); X } X pressreceived = False; X } X} X X static Bool matchKeystrokeToSpec(event,spec) X XEvent *event; X KeySpec *spec; X{ X return (spec->keycode == event->xkey.keycode && X (spec->modmask == AnyModifier || X spec->modmask == event->xkey.state)); X} X X static void rootKeystroke(dpy,pEvent) Display *dpy; XXEvent *pEvent; X{ X Window child; X WinGeneric *childInfo; X Client *childClient; X Bool samescreen; X int destX, destY; X X samescreen = XTranslateCoordinates(dpy, X DefaultRootWindow(dpy), DefaultRootWindow(dpy), X pEvent->xkey.x, pEvent->xkey.y, &destX, &destY, &child ); X X if (!samescreen) X return; X X if (pEvent->type == KeyPress && child != None && X matchKeystrokeToSpec(pEvent, &(GRV.FrontKey))) { X XWindowChanges xwc; X xwc.stack_mode = Opposite; X XConfigureWindow( dpy, child, CWStackMode, &xwc ); X childInfo = WIGetInfo(child); X childClient = childInfo->core.client; X if (childClient && childClient->virtualWindow) { X XConfigureWindow(dpy, childClient->virtualWindow, CWStackMode, &xwc); X } X } else if (matchKeystrokeToSpec(pEvent, &(GRV.HelpKey))) { X redistributeKeystroke( dpy, pEvent ); X } else if (pEvent->type == KeyPress && child != None && X matchKeystrokeToSpec(pEvent, &(GRV.OpenKey))) { X childInfo = WIGetInfo(child); X if ( childInfo ) { X childClient = childInfo->core.client; X if (childClient != NULL) X { X if ( childClient->wmState == IconicState ) { X StateIconNorm(childClient); X } else { X /* check for base vs. popup window */ X if (childClient->groupmask == GROUP_DEPENDENT) { X /* X * REMIND: passing (Menu *)NULL is bogus. X * Also, should pass DA_THIS instead of 0. X */ X DismissAction(dpy,childInfo,(Menu *)NULL,0,False); X } else { X StateNormIcon(childClient); X } X } X } X } X } else if (pEvent->type == KeyPress && X matchKeystrokeToSpec(pEvent, &(GRV.ColorLockKey))) { X InstallPointerColormap(dpy, pEvent->xkey.root, pEvent->xkey.x_root, X pEvent->xkey.y_root, True); X } else if (pEvent->type == KeyPress && X matchKeystrokeToSpec(pEvent, &(GRV.ColorUnlockKey))) { X UnlockColormap(dpy); X } X} X X static void rootProperty( dpy, pEvent ) Display *dpy; XXEvent *pEvent; X{ X unsigned long nitems, remain; X char *resourceString; X XrmDatabase serverDB; X X /* make sure that the property was the one we care about and X * changed (as opposed to deleted) X */ X if ( (pEvent->xproperty.atom != XA_RESOURCE_MANAGER) X || (pEvent->xproperty.state != PropertyNewValue) ) X return; X X resourceString = GetWindowProperty(dpy, RootWindow(dpy, DefaultScreen(dpy)), X XA_RESOURCE_MANAGER, 0L, 100000000L, X /* REMIND what should the length really be ? */ X XA_STRING, 0, &nitems, &remain); X if (resourceString != NULL) X { X serverDB = XrmGetStringDatabase( resourceString ); X UpdateDBValues( dpy, serverDB ); X XFree( resourceString ); X } X} X X X/* X * eventEnterNotify - the pointer has entered the root window X */ static int eventEnterNotify(dpy, pEvent, winInfo) Display *dpy; XXEvent *pEvent; WinRoot *winInfo; X{ X ColorWindowCrossing(dpy, pEvent, winInfo); X} X X/* X * eventConfigureRequest - a client wants to change configuration X */ static int eventConfigureRequest(dpy, pEvent, winInfo) Display *dpy; XXEvent *pEvent; WinRoot *winInfo; X{ X#define ConfEvent (pEvent->xconfigurerequest) X if ((winInfo = WIGetInfo(ConfEvent.window)) == NULL) X { X /* we don't know about this window, so let it go */ X ClientConfigure(NULL,NULL,pEvent); X } X else /* OBSOLETE: if (ConfEvent.value_mask & (CWX | CWY | CWWidth | CWHeight)) */ X { X /* configure the window and its frame */ X ClientConfigure(winInfo->core.client,winInfo,pEvent); X } X /* REMIND doesn't handle stacking or border width yet */ X} X X/* X * eventMapRequest - a new client is mapping X */ static int eventMapRequest(dpy, pEvent, winInfo) Display *dpy; XXEvent *pEvent; WinRoot *winInfo; X{ X#define MapEvent (pEvent->xmap) X StateNew(dpy, MapEvent.window, False, NULL); X} X X/* X * eventMotionNotify - the pointer is moving X */ static int eventMotionNotify(dpy, pEvent, winInfo) Display *dpy; XXEvent *pEvent; WinRoot *winInfo; X{ X short boxX, boxY, boxW, boxH; X clientInBoxClosure cibclosure; X Time timestamp; X X if (!pEvent->xmotion.same_screen) X return; X X /* If the user hasn't moved more than the threshold X * amount, break out of here. REMIND Also, if we get a X * MotionNotify event with no buttons down, we ignore it. X * Ideally this shouldn't happen, but some areas of the code X * still leave the pointer grabbed even after all the buttons X * have gone up. X */ X if ((ABS(pEvent->xmotion.x - buttonPressEvent.xbutton.x) < X GRV.MoveThreshold) && X (ABS(pEvent->xmotion.y - buttonPressEvent.xbutton.y) < X GRV.MoveThreshold)) X return; X if (pEvent->xmotion.state == 0) X return; X X switch(lastButton) X { X case MB_SELECT: X ClearSelections(dpy); X X /* need to trace a bounding box */ X if (TraceBoundingBox(dpy, &buttonPressEvent, X &boxX, &boxY, &boxW, &boxH, ×tamp)) X { X /* select all frames or icons in the box */ X cibclosure.dpy = dpy; X cibclosure.func = AddSelection; X cibclosure.bx = boxX; X cibclosure.by = boxY; X cibclosure.bw = boxW; X cibclosure.bh = boxH; X cibclosure.timestamp = timestamp; X ListApply(ActiveClientList, ClientInBox, &cibclosure); X } X break; X X case MB_ADJUST: X /* bounding box with toggles */ X if (TraceBoundingBox(dpy, &buttonPressEvent, X &boxX, &boxY, &boxW, &boxH, ×tamp)) X { X cibclosure.dpy = dpy; X cibclosure.func = ToggleSelection; X cibclosure.bx = boxX; X cibclosure.by = boxY; X cibclosure.bw = boxW; X cibclosure.bh = boxH; X cibclosure.timestamp = timestamp; X ListApply(ActiveClientList, ClientInBox, &cibclosure); X } X break; X } X} X X/* X * eventButtonRelease - handle a click X */ static int eventButtonRelease(dpy, pEvent, winInfo) Display *dpy; XXEvent *pEvent; WinRoot *winInfo; X{ X /* This only happens if we did NOT get a motion notify X * after the last button press. X */ X if (MouseButton(dpy, pEvent) == MB_SELECT) X { X /* Clear the selection list. */ X ClearSelections(dpy); X X /* Set the input focus to the root window. */ X XSetInputFocus(dpy, NoFocusWin, RevertToPointerRoot, X pEvent->xbutton.time); X X /* Tell the server that we are now the current X * selection owner. This might be necessary if X * the user had selected some text in an xterm X * and wants to unselect it. S/he does this by X * clicking in the root window. X */ X XSetSelectionOwner(dpy, XA_PRIMARY, X RootWindow(dpy, DefaultScreen(dpy)), X pEvent->xbutton.time); X SelectionTime = pEvent->xbutton.time; X } X} X X/* X * eventButtonPress - record a button press X */ static int eventButtonPress(dpy, pEvent, winInfo) Display *dpy; XXEvent *pEvent; WinRoot *winInfo; X{ X buttonPressEvent = *pEvent; X X /* set lastButton */ X if ((lastButton = MouseButton(dpy, pEvent)) == MB_MENU) X { X /* bring up menu for root */ X MenuShow(dpy, winInfo, RootMenu, pEvent); X } X} X X/* X * eventSelectionNotify - someone else has asked for the selection value X */ static int eventSelectionNotify(dpy, pEvent, winInfo) Display *dpy; XXEvent *pEvent; WinRoot *winInfo; X{ X /* We get this event from the owner of the selection X * if we had made a XConvertSelection call. At the X * moment we never make a XConvertSelction call X * so we don't have to worry about a SelectionNotify X * event. An XCovertSelection call is used to get X * the current selection. X */ X} X X/* X * eventSelectionRequest - someone else has asked for the selection value X */ static int eventSelectionRequest(dpy, pEvent, winInfo) Display *dpy; XXEvent *pEvent; WinRoot *winInfo; X{ X SelectionResponse((XSelectionRequestEvent *)pEvent); X} X X/* X * eventSelectionClear - someone else has asked to be the selection owner X */ static int eventSelectionClear(dpy, pEvent, winInfo) Display *dpy; XXEvent *pEvent; WinRoot *winInfo; X{ X /* X * Someone else has asked to be the selection owner. X * Clear our list of selected windows. X */ X ClearSelections(dpy); X} X X/* X * eventKeyPressRelease - a keystroke has happened in the root window X */ static int eventKeyPressRelease(dpy, pEvent, winInfo) Display *dpy; XXEvent *pEvent; WinRoot *winInfo; X{ X rootKeystroke( dpy, pEvent ); X} X X/* X * eventPropertyNotify - a root property has changed X */ static int eventPropertyNotify(dpy, pEvent, winInfo) Display *dpy; XXEvent *pEvent; WinRoot *winInfo; X{ X rootProperty( dpy, pEvent ); X} X X/* X * eventUnmapNotify - an unreparented pane is going away X */ static int eventUnmapNotify(dpy, pEvent, winInfo) Display *dpy; XXEvent *pEvent; WinRoot *winInfo; X{ X WinGeneric *wg; X X wg = WIGetInfo(pEvent->xunmap.window); X if (wg != NULL) X { X StateWithdrawn(wg->core.client); X } X} X X#ifdef NOTDEF X/* X * drawRoot -- draw the root window X */ X/*ARGSUSED*/ /* dpy arg will be used when multiple Displays supported */ static int drawRoot(dpy, winInfo) Display *dpy; WinGeneric *winInfo; X{ X} X X/* X * DestroyRoot -- destroy the root window resources and free any allocated X * data. X */ static int destroyRoot(dpy, winInfo) Display *dpy; WinGeneric *winInfo; X{ X /* free our data and throw away window */ X WIUninstallInfo(winInfo->core.self); X MemFree(winInfo); X} X#endif X X/*************************************************************************** X* global functions X***************************************************************************/ X X/* X * MakeRoot -- create the root window. Return a WinGeneric structure. X */ WinGeneric * MakeRoot(dpy, par) Display *dpy; WinGeneric *par; /* ignored */ X{ X XWindowAttributes attr; X WinRoot *w; X Window win; X X win = RootWindow(dpy, DefaultScreen(dpy)); X X if (XGetWindowAttributes(dpy, win, &attr) == 0) { X ErrorGeneral("could not get attributes of root window"); X /*NOTREACHED*/ X } X X /* create the associated structure */ X w = MemNew(WinRoot); X w->core.self = win; X w->class = &classRoot; X w->core.kind = WIN_ROOT; X w->core.parent = NULL; X w->core.children = NULL; X w->core.client = NULL; X w->core.x = 0; X w->core.y = 0; X w->core.width = attr.width; X w->core.height = attr.height; X w->core.dirtyconfig = False; X w->core.colormap = attr.colormap; X w->core.exposures = NULL; X X /* register the window */ X WIInstallInfo(w); X X return w; X} X void RootInit(dpy) Display *dpy; X{ X classRoot.core.kind = WIN_ROOT; X classRoot.core.xevents[ConfigureRequest] = eventConfigureRequest; X classRoot.core.xevents[EnterNotify] = eventEnterNotify; X classRoot.core.xevents[MapRequest] = eventMapRequest; X classRoot.core.xevents[MotionNotify] = eventMotionNotify; X classRoot.core.xevents[ButtonRelease] = eventButtonRelease; X classRoot.core.xevents[ButtonPress] = eventButtonPress; X classRoot.core.xevents[SelectionNotify] = eventSelectionNotify; X classRoot.core.xevents[SelectionRequest] = eventSelectionRequest; X classRoot.core.xevents[SelectionClear] = eventSelectionClear; X classRoot.core.xevents[KeyPress] = eventKeyPressRelease; X classRoot.core.xevents[KeyRelease] = eventKeyPressRelease; X classRoot.core.xevents[PropertyNotify] = eventPropertyNotify; X classRoot.core.xevents[UnmapNotify] = eventUnmapNotify; X classRoot.core.focusfunc = NULL; X classRoot.core.drawfunc = NULL; X classRoot.core.destroyfunc = NULL; X classRoot.core.selectfunc = NULL; X classRoot.core.newconfigfunc = NULL; X classRoot.core.newposfunc = NULL; X classRoot.core.setconfigfunc = NULL; X classRoot.core.createcallback = NULL; X classRoot.core.heightfunc = NULL; X classRoot.core.widthfunc = NULL; X} END_OF_FILE if test 14250 -ne `wc -c <'winroot.c'`; then echo shar: \"'winroot.c'\" unpacked with wrong size! fi # end of 'winroot.c' fi echo shar: End of archive 5 \(of 16\). cp /dev/null ark5isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 16 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 -- Dan Heller O'Reilly && Associates Z-Code Software Comp-sources-x: Senior Writer President comp-sources.x@uunet.uu.net argv@ora.com argv@zipcode.com