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 64 Archive-name: olvwm/part08 #! /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 8 (of 16)." # Contents: resources1.c usermenu.c # Wrapped by sdo@piccolo on Fri Apr 26 17:31:06 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'resources1.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'resources1.c'\" else echo shar: Extracting \"'resources1.c'\" \(19186 characters\) sed "s/^X//" >'resources1.c' <<'END_OF_FILE' X/* X * (c) Copyright 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[] = "@(#)resources1.c 1.2 olvwm version 4/26/91"; X X/* X * Based on static char sccsid[] = "@(#) resources.c 25.34 90/06/05 Crucible"; X * X */ X X#include <ctype.h> X#include <errno.h> X#include <stdio.h> X#include <string.h> X#include <sys/file.h> X#include <X11/Xos.h> X#include <X11/Xlib.h> X#include <X11/Xutil.h> X#include <X11/Xresource.h> X#include <X11/keysym.h> X#include <X11/cursorfont.h> X X#include <olgx/olgx.h> X X#include "mem.h" X#include "olwm.h" X#include "win.h" X#include "defaults.h" X#include "globals.h" X#include "resources.h" X#include "olcursor.h" X extern char *AppName; extern Bool ColorDisplay; extern List *ActiveClientList; X extern Graphics_info *olgx_gisbutton; extern Graphics_info *olgx_gistext; extern Graphics_info *olgx_gisnormal; extern Graphics_info *olgx_gisreverse; extern Graphics_info *olgx_gisrevpin; X extern GC DrawNormalGC, DrawReverseGC; extern GC DrawLinesGC, DrawRevLinesGC; extern GC DrawBackgroundGC, DrawSelectedGC; extern GC DrawBusyGC; extern GC IconUnselectedGC, IconBorderGC; extern GC IconNormalGC, IconSelectedGC; X extern Pixmap Gray50; extern int Gray50width; extern int Gray50height; X extern XrmDatabase OlwmDB; extern GlobalResourceVariables GRV; X extern Bool WorkspaceColorUsed; extern unsigned long WorkspaceColorPixel; X X X/* X * Global routines X */ X X/* X * The Resource Update Functions X */ X X/* X * setWorkspaceColor -- set the root window background. X * If isUpdate is true, then the background has already been set once X * (on startup), so XSetWindowBackground not done if default case. X * X * REMIND: this routine doesn't work properly for GrayScale visuals. X * X */ static void setWorkspaceColor( dpy, colorname, isUpdate ) Display *dpy; char *colorname; Bool isUpdate; X{ X XColor color; X GC gc; X XGCValues gcv; X Pixmap bitmap = 0; X Pixmap pixmap; X unsigned int width, height; X Bool valid = False; X Bool docolor = False; X X if ( colorname != NULL ) X { X /* Null string disables root setting */ X if (*colorname == '\0') X return; X X if ( *colorname == '/' ) X { X unsigned int x, y; X X if ( BitmapSuccess == XReadBitmapFile( dpy, X DefaultRootWindow(dpy), X colorname, X &width, &height, X &bitmap, &x, &y ) ) X valid = True; X } X else if ( (*colorname == '#') && ColorDisplay ) X { X XParseColor( dpy, X DefaultColormap(dpy,DefaultScreen(dpy)), X colorname, &color ); X X if ( XAllocColor( dpy, X DefaultColormap(dpy,DefaultScreen(dpy)), X &color ) ) X valid = docolor = True; X } X else if ( ColorDisplay ) X { X /* It is a color name */ X /* X * NOTE: this could possibly fail on a full X * dynamic colormap. If it does, tough -- X * we''ll just set it to whatever junk X * comes back for now. X * Presumably this won''t happen since X * 'props' was able to display the color. X */ X if ( XAllocNamedColor(dpy, X DefaultColormap(dpy,DefaultScreen(dpy)), X colorname, &color, &color) ) X valid = docolor = True; X } X } X X /* the new color isn't usable, and we've set the background before */ X if ( !valid && isUpdate ) X return; X X if ( !valid && ColorDisplay ) X { X XParseColor( dpy, DefaultColormap(dpy,DefaultScreen(dpy)), X DEFAULTCOLOR, &color ); X if ( XAllocColor( dpy, DefaultColormap(dpy,DefaultScreen(dpy)), X &color ) ) X valid = docolor = True; X } X X if ( !valid ) X { X bitmap = Gray50; X width = Gray50width; X height = Gray50height; X } X X if ( docolor ) X { X WorkspaceColorUsed = True; X WorkspaceColorPixel = color.pixel; X XSetWindowBackground(dpy, DefaultRootWindow(dpy), color.pixel); X /*if (VirtualDesktop) { X XSetWindowBackground(dpy, VirtualDesktop, color.pixel); X XClearWindow(dpy, VirtualDesktop); X }*/ X } X else X { X WorkspaceColorUsed = False; X gcv.foreground = BlackPixel(dpy,DefaultScreen(dpy)); X gcv.background = WhitePixel(dpy,DefaultScreen(dpy)); X gc = XCreateGC( dpy, DefaultRootWindow(dpy), X GCForeground|GCBackground, &gcv ); X pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), X width, height, X (unsigned int)DefaultDepth(dpy, X DefaultScreen(dpy))); X XCopyPlane( dpy, bitmap, pixmap, gc, 0, 0, width, height, X 0, 0, (unsigned long)1 ); X XSetWindowBackgroundPixmap(dpy, DefaultRootWindow(dpy), pixmap); X XFreeGC( dpy, gc ); X XFreePixmap( dpy, bitmap ); X XFreePixmap( dpy, pixmap ); X } X XClearWindow( dpy, DefaultRootWindow(dpy) ); X} X X X/* X * UpdWorkspace - Update workspace color X * X */ X/*ARGSUSED*/ /* rmIndex not needed here */ Bool UpdWorkspace( dpy, rmIndex, isUpdate ) Display *dpy; int rmIndex; Bool isUpdate; X{ X XGCValues xgcv; X X if (isUpdate && WorkspaceColorUsed) { X /* X * REMIND: this code helps prevent us from freeing the same cell X * twice. We should be able to do this according to the protocol, X * but some servers have bugs where allocating a cell twice and X * then freeing it once will actually free the cell. X */ X if (WorkspaceColorPixel != GRV.Bg0Color && X WorkspaceColorPixel != GRV.Bg1Color && X WorkspaceColorPixel != GRV.Bg2Color && X WorkspaceColorPixel != GRV.Bg3Color) X { X XFreeColors(dpy, CMAP, &WorkspaceColorPixel, 1, 0); X } X WorkspaceColorUsed = False; X } X X setWorkspaceColor( dpy, GRV.WorkspaceColor, isUpdate ); X X if (isUpdate) X { X xgcv.foreground = WorkspaceColorPixel; X xgcv.background = WorkspaceColorPixel; X if (WorkspaceColorUsed) X { X XChangeGC(dpy, IconNormalGC, GCBackground, &xgcv); X XChangeGC(dpy, IconSelectedGC, GCBackground, &xgcv); X XChangeGC(dpy, IconUnselectedGC, GCForeground, &xgcv); X } X WinRedrawAllWindows(); X } X return( True ); X} X X/* X * UpdSync - Update whether synchronization is being done, or not. X * X */ X/*ARGSUSED*/ /* rmIndex not needed here */ Bool UpdSync( dpy, rmIndex, isUpdate ) Display *dpy; int rmIndex; Bool isUpdate; X{ X (void) XSynchronize( dpy, GRV.Synchronize ); X return( True ); X} X X X/* X * UpdTitleFont - Update title font being used X * X */ X/*ARGSUSED*/ /* std arg rmIndex not used here */ Bool UpdTitleFont( dpy, rmIndex, isUpdate ) Display *dpy; int rmIndex; Bool isUpdate; X{ X XGCValues values; X X values.font = GRV.TitleFontInfo->fid; X XChangeGC( dpy, DrawNormalGC, GCFont, &values ); X XChangeGC( dpy, DrawReverseGC, GCFont, &values ); X#ifdef REMIND_STILL_NEEDED? X XChangeGC( dpy, DrawLinesGC, GCFont, &values ); X XChangeGC( dpy, DrawRevLinesGC, GCFont, &values ); X#endif /* REMIND_STILL_NEEDED? */ X X olgx_set_text_font(olgx_gisnormal, GRV.TitleFontInfo, X OLGX_NORMAL); X olgx_set_text_font(olgx_gisreverse, GRV.TitleFontInfo, X OLGX_NORMAL); X olgx_set_text_font(olgx_gisrevpin, GRV.TitleFontInfo, X OLGX_NORMAL); X return( True ); X} X X/* X * UpdTextFont - Update text font being used (e.g., notice box text) X * X */ X/*ARGSUSED*/ /* std args dpy, rmIndex not used here */ Bool UpdTextFont( dpy, rmIndex, isUpdate ) Display *dpy; int rmIndex; Bool isUpdate; X{ X olgx_set_text_font(olgx_gistext, GRV.TextFontInfo, X OLGX_NORMAL); X return( True ); X} X X/* X * UpdButtonFont - Update button font being used X * X */ X/*ARGSUSED*/ /* std args dpy, rmIndex not used here */ Bool UpdButtonFont( dpy, rmIndex, isUpdate ) Display *dpy; int rmIndex; Bool isUpdate; X{ X olgx_set_text_font(olgx_gisbutton, GRV.ButtonFontInfo, X OLGX_NORMAL); X X return( True ); X} X X X/* X * UpdIconFont - Update icon font being used X * X */ X/*ARGSUSED*/ /* std arg rmIndex not used here */ Bool UpdIconFont( dpy, rmIndex, isUpdate ) Display *dpy; int rmIndex; Bool isUpdate; X{ X XGCValues values; X X values.font = GRV.IconFontInfo->fid; X XChangeGC( dpy, IconNormalGC, GCFont, &values ); X XChangeGC( dpy, IconSelectedGC, GCFont, &values ); X X return( True ); X} X X X/* X * UpdGlyphFont - Update glyph font being used X * X * REMIND - this code should be used by InitGraphics.c X * instead of being duplicated. X */ X/*ARGSUSED*/ /* std args dpy, rmIndex not used here */ Bool UpdGlyphFont( dpy, rmIndex, isUpdate ) Display *dpy; int rmIndex; Bool isUpdate; X{ X olgx_set_glyph_font(olgx_gisnormal, GRV.GlyphFontInfo, X OLGX_NORMAL); X olgx_set_glyph_font(olgx_gisreverse, GRV.GlyphFontInfo, X OLGX_NORMAL); X olgx_set_glyph_font(olgx_gisrevpin, GRV.GlyphFontInfo, X OLGX_NORMAL); X olgx_set_glyph_font(olgx_gisbutton, GRV.GlyphFontInfo, X OLGX_NORMAL); X X /* X * REMIND Even though it might not make sense, what about olgx_gistext? X */ X X /* REMIND HACK - if the following routine is modified to X * use olgx macros, may only need to be from InitGraphics(), X * or perhaps entire call should be moved here! X */ X setResizeSizes(); X X return( True ); X} X X X/* X * UpdFg1Color - Update Fg1Color used X * X */ X/*ARGSUSED*/ /* std arg rmIndex not used here */ Bool UpdFg1Color( dpy, rmIndex, isUpdate ) Display *dpy; int rmIndex; Bool isUpdate; X{ X XGCValues xgcv; X X if (isUpdate) X { X olgx_set_single_color(olgx_gisrevpin,OLGX_WHITE,GRV.Fg1Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisreverse,OLGX_BG1,GRV.Fg1Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisreverse,OLGX_BG3,GRV.Fg1Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisnormal,OLGX_BLACK,GRV.Fg1Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisbutton,OLGX_BLACK,GRV.Fg1Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gistext,OLGX_BLACK,GRV.Fg1Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisreverse,OLGX_BLACK,GRV.Fg1Color,OLGX_SPECIAL); X X xgcv.foreground = GRV.Fg1Color; X xgcv.background = GRV.Fg1Color; X XChangeGC(dpy, DrawNormalGC, GCBackground, &xgcv); X XChangeGC(dpy, DrawReverseGC, GCForeground, &xgcv); X XChangeGC(dpy, DrawBusyGC, GCForeground, &xgcv); X XChangeGC(dpy, IconNormalGC, GCBackground, &xgcv); X XChangeGC(dpy, IconSelectedGC, GCForeground, &xgcv); X#ifdef COLOR2D X XChangeGC(dpy, IconBorderGC, GCBackground, &xgcv); X#endif X WinRedrawAllWindows(); X } X} X X X/* X * UpdBg1Color - Update Bg1Color used X * X */ X/*ARGSUSED*/ /* std arg rmIndex not used here */ Bool UpdBg1Color( dpy, rmIndex, isUpdate ) Display *dpy; int rmIndex; Bool isUpdate; X{ X XGCValues xgcv; X X if (isUpdate) X { X olgx_set_single_color(olgx_gisnormal,OLGX_BG1,GRV.Bg1Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisrevpin,OLGX_BG1,GRV.Bg1Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisbutton,OLGX_BG1,GRV.Bg1Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gistext,OLGX_BG1,GRV.Bg1Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisreverse,OLGX_BLACK,GRV.Bg1Color,OLGX_SPECIAL); X X xgcv.foreground = GRV.Bg1Color; X xgcv.background = GRV.Bg1Color; X XChangeGC(dpy, DrawBackgroundGC, GCForeground|GCBackground, &xgcv); X XChangeGC(dpy, DrawNormalGC, GCBackground, &xgcv); X XChangeGC(dpy, DrawReverseGC, GCForeground, &xgcv); X if (!WorkspaceColorUsed) X { X XChangeGC(dpy, IconNormalGC, GCBackground, &xgcv); X XChangeGC(dpy, IconSelectedGC, GCBackground, &xgcv); X XChangeGC(dpy, IconUnselectedGC, GCForeground, &xgcv); X } X XChangeGC(dpy, IconBorderGC, GCBackground, &xgcv); X } X X UpdBg2Color(dpy,rmIndex,isUpdate); X UpdBg3Color(dpy,rmIndex,isUpdate); X UpdBg0Color(dpy,rmIndex,isUpdate); X if (isUpdate) X { X WinRedrawAllWindows(); X } X} X X X/* X * UpdBg2Color - Update Bg2Color used X * X */ X/*ARGSUSED*/ /* std arg rmIndex not used here */ Bool UpdBg2Color( dpy, rmIndex, isUpdate ) Display *dpy; int rmIndex; Bool isUpdate; X{ X XGCValues xgcv; X X if (isUpdate) X { X olgx_set_single_color(olgx_gisreverse,OLGX_WHITE,GRV.Bg2Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisnormal,OLGX_BG2,GRV.Bg2Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisrevpin,OLGX_BG2,GRV.Bg2Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisbutton,OLGX_BG2,GRV.Bg2Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gistext,OLGX_BG2,GRV.Bg2Color,OLGX_SPECIAL); X X xgcv.foreground = GRV.Bg2Color; X xgcv.background = GRV.Bg2Color; X#ifdef COLOR2D X XChangeGC(dpy, DrawSelectedGC, GCForeground, &xgcv); X#else X if (GRV.F3dUsed) X { X XChangeGC(dpy, DrawSelectedGC, GCForeground, &xgcv); X } X#endif X } X} X X X/* X * UpdBg3Color - Update Bg3Color used X * X */ X/*ARGSUSED*/ /* std arg rmIndex not used here */ Bool UpdBg3Color( dpy, rmIndex, isUpdate ) Display *dpy; int rmIndex; Bool isUpdate; X{ X if (isUpdate) X { X olgx_set_single_color(olgx_gisnormal,OLGX_BG3,GRV.Bg3Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisrevpin,OLGX_BG3,GRV.Bg3Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisbutton,OLGX_BG3,GRV.Bg3Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gistext,OLGX_BG3,GRV.Bg3Color,OLGX_SPECIAL); X } X} X X X/* X * UpdBg0Color - Update Bg0Color used for 3d color shading X * X */ X/*ARGSUSED*/ /* std arg rmIndex not used here */ Bool UpdBg0Color( dpy, rmIndex, isUpdate ) Display *dpy; int rmIndex; Bool isUpdate; X{ X if (isUpdate) X { X olgx_set_single_color(olgx_gisrevpin,OLGX_BLACK,GRV.Bg0Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisreverse,OLGX_BG2,GRV.Bg0Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gistext,OLGX_WHITE,GRV.Bg0Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisbutton,OLGX_WHITE,GRV.Bg0Color,OLGX_SPECIAL); X olgx_set_single_color(olgx_gisnormal,OLGX_WHITE,GRV.Bg0Color,OLGX_SPECIAL); X } X} X X/* X * updBorderColor - handle changes in the border colour X */ Bool updBorderColor( dpy, rmIndex, isUpdate) Display *dpy; int rmIndex; Bool isUpdate; X{ X#ifndef COLOR2D X XGCValues xgcv; X X if (isUpdate) X { X xgcv.foreground = GRV.BorderColor; X xgcv.background = GRV.BorderColor; X XChangeGC(dpy, IconBorderGC, GCForeground, &xgcv); X if (!GRV.F3dUsed) X XChangeGC(dpy, DrawSelectedGC, GCForeground, &xgcv); X WinRedrawAllWindows(); X } X#endif X} X X X/* X * UpdCursorColor - Update CursorColor used X * X * REMIND - this doesn't work; a new XDefineCursor is probably needed. X */ X/*ARGSUSED*/ /* std arg rmIndex not used here */ Bool UpdCursorColor( dpy, rmIndex, isUpdate ) Display *dpy; int rmIndex; Bool isUpdate; X{ X int ii; X XColor foreColor, backColor; X X /* set up new cursor rgb values in color structure */ X foreColor.pixel = GRV.CursorColor; X XQueryColor( dpy, CMAP, &foreColor ); X /* REMIND - should backColor be background (GRV.Bg1Color)? X * Is backColor even used when making these cursors?? X */ X backColor.pixel = WhitePixel( dpy, DefaultScreen(dpy) ); X XQueryColor( dpy, CMAP, &backColor ); X X /* loop through and update all six pointers */ X for ( ii = 0 ; ii < NUM_CURSORS ; ii++ ) X { X Cursor *tmpVariable; X X switch( ii ) X { X case BASICPTR: tmpVariable = &GRV.BasicPointer; X break; X case MOVEPTR: tmpVariable = &GRV.MovePointer; X break; X case BUSYPTR: tmpVariable = &GRV.BusyPointer; X break; X case ICONPTR: tmpVariable = &GRV.IconPointer; X break; X case RESIZEPTR: tmpVariable = &GRV.ResizePointer; X break; X case MENUPTR: tmpVariable = &GRV.MenuPointer; X break; X case QUESTIONPTR: tmpVariable = &GRV.QuestionPointer; X break; X case TARGETPTR: tmpVariable = &GRV.TargetPointer; X break; X case PANPTR: tmpVariable = &GRV.PanPointer; X break; X } X X#ifdef LATER X XRecolorCursor( dpy, *tmpVariable, &foreColor, &backColor ); X#endif X } X X} X X X/* X * UpdIconLocation -- the icon placement policy has changed; rearrange the X * icons accordingly. X */ Bool updIconLocation( dpy, rmIndex ) Display *dpy; int rmIndex; X{ X SlotSetLocations(dpy); X} X X X/* X * unconfigureFocus X * X * Tell a client to remove any grabs it may have set up according to the focus X * mode. If this client is the focus, tell it to draw in its unfocused state. X */ static void * unconfigureFocus(cli) X Client *cli; X{ X FrameSetupGrabs(cli, cli->framewin->core.self, False); X if (cli->isFocus) { X cli->isFocus = False; X WinCallDraw(cli->framewin); X cli->isFocus = True; X } X return NULL; X} X X X/* X * reconfigureFocus X * X * Tell a client to restore any grabs it may need for the new focus mode. If X * this client is the focus, tell it to draw using the proper highlighting for X * the new focus mode. X */ static void * reconfigureFocus(cli) X Client *cli; X{ X FrameSetupGrabs(cli, cli->framewin->core.self, True); X if (cli->isFocus) { X WinCallDraw(cli->framewin); X } X return NULL; X} X X X/* X * UpdInputFocusStyle -- change the focus style on the fly X * X * This is a trifle odd. GRV.FocusFollowsMouse has already been updated with X * its new value. Momentarily reset it back to its old value, and then call X * unconfigureFocus on every client. This will clear grabs and highlighting X * and such as if the old focus mode were still in effect. Reset GRV. X * GRV.FocusFollowsMouse to the new value, and then call reconfigureFocus on X * every client to set up stuff for the new focus mode. X */ Bool UpdInputFocusStyle(dpy, rmIndex, isUpdate) X Display *dpy; X int rmIndex; X Bool isUpdate; X{ X if (isUpdate) { X GRV.FocusFollowsMouse = !GRV.FocusFollowsMouse; X ListApply(ActiveClientList, unconfigureFocus, 0); X GRV.FocusFollowsMouse = !GRV.FocusFollowsMouse; X ListApply(ActiveClientList, reconfigureFocus, 0); X } X} X X X/* X * The Resource Manipulation Functions X */ X X X/* X * UpdateDBValues - check all our dynamically configurable current X * resources against the ones in this new db. If any of them X * differ, then set the new global variable, update the value in X * the global db, and call the appropriate update routine. X * X * NOTICE that this assumes that all global variables have been X * set to something by this point (since they will be used by X * the setFunc()s). X * X * The setFunc() does the actual comparison between the new db X * resource and the value previously set (using the appropriate X * global variable), since it "knows" how to convert the string X * representation of the resource into the appropriate type. X */ void UpdateDBValues( dpy, newDB ) Display *dpy; XXrmDatabase newDB; X{ X char name[MAX_NAME]; X char class[MAX_CLASS]; X XrmRepresentation newRepType; X XrmValue newValue; X int ii; X X for ( ii = 0 ; ii < RM_ENTRYEND ; ii++ ) X { X /* first, ignore all the non-dynamically settable resources */ X switch ( ii ) X { X case RM_DISPLAY: X case RM_PREFIX: X case RM_USE3D: X case RM_CURSORFONT: X continue; X } X X /* check to see if this resource is set in the new db */ X MakeRMName( name, ii ); X MakeRMClass( class, ii ); X if ( !XrmGetResource( newDB, name, class, &newRepType, X &newValue ) ) X continue; X X /* let the setFunc convert the newValue, compare it against X * the old, and then set the global variable to that new X * value X */ X if ( RMTable[ii].setFunc( dpy, ii, newValue.addr, True ) ) X { X /* if we really updated to using the new value, X * store it in the global db for future reference X */ X XrmPutStringResource( &OlwmDB, name, newValue.addr ); X if ( RMTable[ii].updFunc != (BFuncPtr)0 ) X RMTable[ii].updFunc( dpy, ii, True ); X } X } X} X END_OF_FILE if test 19186 -ne `wc -c <'resources1.c'`; then echo shar: \"'resources1.c'\" unpacked with wrong size! fi # end of 'resources1.c' fi if test -f 'usermenu.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'usermenu.c'\" else echo shar: Extracting \"'usermenu.c'\" \(20286 characters\) sed "s/^X//" >'usermenu.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[] = "@(#)usermenu.c 1.2 olvwm version 3/30/91"; X X/* X * Based on static char sccsid[] = "@(#) usermenu.c 25.4 90/05/23 Crucible"; X * X */ X X/* X * This file contains all of the functions for manipulating the user menu X * X * Global Functions: X * InitUserMenu -- load the user menu and initialise X * X * Global data: X * RootMenu -- workspace menu X */ X X/* X * Syntax of the user menu file should be identical to that used by X * buildmenu (SunView style rootmenu files). X * X * NOTICE that SunView compatibility has resulted in old-style X * olwm menus no longer being supported. X * X * There are two new reserved keywords: X * X * DEFAULT tags a default button X * TITLE tags a title string for a menu (for titlebar) X * X * One syntax in sunview menus is not supported: X * <icon_file> can not be used as a menu item X * X * Here are the common reserved keywords: X * MENU and END are used to delimit a submenu X * PIN (appearing after END) indicates the menu is pinnable X * EXIT (built-in - olwm service) X * REFRESH (built-in - olwm service) X * POSTSCRIPT will invoke psh on the named command X * X * The file is line-oriented, however commands to be executed can X * extend to the next line if the newline is escaped (\). X * X * Each line consists of up to three fields: a label (a string X * corresponding to either the menu label or menu option label), X * up to two tags (keywords), and a command to be executed X * (or a file from which to read a submenu). Two tags are allowed X * if one of them is "DEFAULT" or "END". X * X * The tag is used to indicate the start and end of menu definitions, X * pinnability, built-in functions, and default options. X * The label indicates the text which appears on the user's menu, X * and the command describes what should be done when each item X * is selected. X * X * Labels must be enclosed in double quotes if they contain X * whitespace. Commands may be enclosed in double quotes (but X * do not have to be). X * X * Comments can be embedded in a file by starting a line with a X * pound sign (#). Comments may not be preserved as the file is X * used. X * X * There are several functions which aren't invoked as programs; X * rather, they are built in to window manager. These built-in X * services are each denoted by a single keyword. The keywords are X * listed in the svctokenlookup[] array initialization. X * X * example (will always have label: "Workspace Menu"): X * X * "Workspace Menu" TITLE X * Programs MENU X * "Helpful Programs" TITLE X * "Command Tool" cmdtool X * "Blue Xterm" DEFAULT xterm -fg white \ X * -bg blue X * Programs END PIN X * Utilities MENU X * "Refresh Screen" DEFAULT REFRESH X * "Clipboard" CLIPBOARD X * Utilities END X */ X X#include <errno.h> X#include <stdio.h> X#include <ctype.h> X#include <strings.h> X#include <sys/file.h> X#include <sys/param.h> X#include <X11/Xos.h> X#include <X11/Xlib.h> X#include <X11/Xutil.h> X#include <X11/Xatom.h> X extern char *strtok(); /* not defined in strings.h */ X X#include "olwm.h" X#include "mem.h" X#include "menu.h" X X#define MENUFILE "openwin-menu" X#define TOKLEN 300 X X/* parseMenu return values */ X#define MENU_FATAL -1 X#define MENU_NOTFOUND 0 X#define MENU_OK 1 X#define MENU_PINNABLE 2 X typedef enum { UsrToken, MenuToken, EndToken, DefaultToken, PinToken, X TitleToken, ServiceToken, PshToken } TokenType; X X/* locally useful macro */ X#define APPEND_STRING(buf, str) ( strncat( buf, str, \ X ( sizeof(buf) - strlen(buf) - 1 ) ) ) X X/* Externals */ extern int RefreshFunc(); extern int ClipboardFunc(); extern int PrintScreenFunc(); extern int ExitFunc(); extern int PropertiesFunc(); extern int SaveWorkspaceFunc(); extern int FlipDragFunc(); extern int AppMenuFunc(); extern int PshFunc(); extern int NopFunc(); extern int WindowCtlFunc(); extern int RestartOLWM(); extern int FlipFocusFunc(); X X/* global data */ Menu *RootMenu; X X/* local forward declarations */ static Bool checkFile(); static int menuFromFile(); static int parseMenu(); static void fillMenuStruct(); static TokenType lookupToken(); static Menu *buildFromSpec(); static void initMenu(); static void initButton(); static void freeButtonData(); static void freeMenuData(); X X/* local data */ typedef struct _buttondata { X struct _buttondata *next; X char *name; X Bool isDefault; X Bool isLast; X FuncPtr func; X char *exec; /* string to be executed, like "xterm" */ X void *submenu; X } buttondata; X X typedef struct { X char *title; X char *label; X int idefault; /* index of default button */ X int nbuttons; X Bool pinnable; X buttondata *bfirst; X} menudata; X menudata userroot = { "Workspace Menu", NULL, -1, 0, True, NULL }; X X/* default Root menu should be quite minimal */ Button RootButtons[] = { X { "Xterm", False, Enabled, {AppMenuFunc, (void *)"xterm"} }, X { "Refresh", False, Enabled, {RefreshFunc, NULL} }, X { "Exit WM", False, Enabled, {ExitOLWM, NULL} }, X { "Exit", False, Enabled, {ExitFunc, NULL} }, X }; Menu DefaultRootMenu = { "Workspace", RootButtons, 4, -1, True, (FuncPtr)MakeMenu}; X X X/* X * Global routines X */ X X/* X * InitUserMenu -- load the user menu from a file using menuFromFile() X * and then create the actual RootMenu using buildFromSpec(). X * X * The file to be read is either in the directory specified by X * OLWMPATH or HOME, or OPENWINHOME/lib, and should be called X * MENUFILE. If none of those three files exist, X * use the default menu. X * X */ void InitUserMenu(dpy) Display *dpy; X{ X char *getenv(); X char temp[MAXPATHLEN]; X char *path; X X RootMenu = (Menu *) 0; X X /* X * SLEAZE X * This isn't a loop. It's a construct that makes "break" mean "jump to X * the statement just outside the brace." X */ X while (1) { X /* try reading $OLWMMENU */ X path = getenv("OLWMMENU"); X if (path != NULL && menuFromFile(path, &userroot, False) >= MENU_OK) X break; X X /* try reading $HOME/.openwin-menu */ X path = getenv("HOME"); X strcpy(temp, path ? path : ""); X strcat(temp, "/."); X strcat(temp, MENUFILE); X if (menuFromFile(temp, &userroot, False) >= MENU_OK) X break; X X /* try reading $OPENWINHOME/lib/openwin-menu */ X path = getenv("OPENWINHOME"); X strcpy(temp, path ? path : ""); X strcat(temp, "/lib/"); X strcat(temp, MENUFILE); X if (menuFromFile(temp, &userroot, False) >= MENU_OK) X break; X X /* use default root menu */ X MenuCreate(dpy, &DefaultRootMenu); X RootMenu = &DefaultRootMenu; X return; X } X X /* we read a menu from a file; now build it */ X RootMenu = buildFromSpec( dpy, &userroot, userroot.title ); X} X X X/* X * Local routines X */ X X#ifdef NOTDEF X/* X * checkFile - check to see that a file (composed of named file and dir) X * is readable X */ static Bool checkFile( location, file, path ) char *location, *file, *path; X{ X char *getenv(); X char *dir; X X if ( (dir = getenv( location )) == NULL ) X return False; X strcpy( path, dir ); X strcat( path, file ); X return ( access( path, R_OK ) == 0 ); X} X#endif X X/* X * menuFromFile - read a menu description from a file X * X * Return values: same as parseMenu, with the addition of X * MENU_NOTFOUND = couldn't read submenu file X */ static int menuFromFile(file, menu, messages) char *file; menudata *menu; Bool messages; X{ X FILE *stream; X int lineno = 1; /* Needed for recursion */ X int rval; X X stream = fopen(file, "r"); X if (stream == NULL) { X if (messages) X fprintf(stderr, "olvwm: can't open menu file %s\n", file); X return(MENU_NOTFOUND); X } X X rval = parseMenu(file, stream, menu, &lineno); X fclose(stream); X if (rval >= MENU_OK) X fillMenuStruct(menu); X else X freeMenuData(menu); X X return(rval); X} X X X/* X * parseMenu -- read the user menu from the given stream and X * parse the stream into the menu structures defined locally. X * These structures (which are local to this module) are later X * used to build real menu structures. X * X * Note that fillMenuStruct() needs to be called after parseMenu() X * is called (to finish filling out the menudata structure). X * If parseMenu() returns < 0, then freeMenuData() needs to be X * called instead, to free up unused memory. X * X * Return values: X * MENU_OK = an unpinnable menu was read successfully X * MENU_PINNABLE = a pinnable menu was read successfully X * MENU_FATAL = a fatal error was encountered X * X * This is based heavily on buildmenu's getmenu() parsing routine. X * X */ static int parseMenu(filename, stream, rootmenu, lineno) char *filename; XFILE *stream; menudata *rootmenu; int *lineno; X{ X menudata *currentMenu, *saveMenu; X buttondata *currentButton; X char line[TOKLEN]; X char label[TOKLEN]; X char prog[TOKLEN]; X char args[TOKLEN]; static char localBuf[1024]; X char *nqformat = X "%[^ \t\n]%*[ \t]%[^ \t\n]%*[ \t]%[^\n]\n"; X char *qformat = X "\"%[^\"]\"%*[ \t]%[^ \t\n]%*[ \t]%[^\n]\n"; X char *format; X register char *p; X int continuation; X Bool done; X X currentMenu = rootmenu; X initButton( (buttondata **)&(currentMenu->bfirst) ); X currentButton = currentMenu->bfirst; X continuation = 0; X X for ( ; fgets(line, sizeof(line), stream) ; (*lineno)++ ) X { X if (line[0] == '#') X continue; X X for ( p = line ; isspace(*p) ; p++ ) X ; X X if ( *p == '\0' ) X continue; X X /* X * if we're already on a continuation line (the previous X * line ended in '\') then just copy the input through X * to the output until we get a line that doesn't end in X * '\' (nuke the vi backslash). X */ X if (continuation) X { X /* fgets includes the newline in the string read */ X while ( line[strlen(line) - 2] == '\\' ) X { X /* get rid of backslash */ X line[strlen(line) - 2] = '\0'; X APPEND_STRING( localBuf, " " ); X APPEND_STRING(localBuf, p); X if ( !fgets(line, sizeof(line), stream) ) X break; X (*lineno)++; X for ( p = line ; isspace(*p) ; p++ ) X ; X } X /* last line of continuation - replace \n with \0 */ X line[strlen(line) - 1] = '\0'; X APPEND_STRING( localBuf, " " ); X APPEND_STRING(localBuf, p); X /* save it permanently in the buttondata structure */ X currentButton->exec = MemNewString( localBuf ); X localBuf[0] = '\0'; X continuation = 0; X initButton( (buttondata **)&(currentButton->next) ); X currentButton = currentButton->next; X continue; X } X X /* if the line ends in '\' remember that continuation X * has started. X */ X if ( line[strlen(line) - 2] == '\\' ) X { X continuation = 1; X line[strlen(line) - 2] = '\0'; X } X X args[0] = '\0'; X format = ( *p == '"' ) ? qformat : nqformat; X X if ( sscanf( p, format, label, prog, args ) < 2 ) X { X fprintf(stderr, X "olvwm: syntax error in menu file %s, line %d\n", X filename, *lineno); X return(MENU_FATAL); X } X X if ( strcmp(prog, "END") == 0 ) X { X /* currently allocated button is last for this menu */ X currentButton->isLast = True; X if (currentMenu->label != NULL && X strcmp(label, currentMenu->label) != 0) { X fprintf(stderr, X "olvwm: menu label mismatch in file %s, line %d\n", X filename, *lineno); X return(MENU_FATAL); X } X if ( strcmp(args, "PIN") == 0 ) X return(MENU_PINNABLE); X else X return(MENU_OK); X } X X if ( strcmp(prog, "TITLE") == 0 ) X { X currentMenu->title = MemNewString( label ); X /* we don't need to set up the next button, since X * the TITLE line didn't use up a button X */ X continue; X } X X currentButton->name = MemNewString( label ); X X if ( strcmp(prog, "DEFAULT") == 0) { X char *t; X char *u; X X currentButton->isDefault = True; X X /* X * Pull the first token from args into prog. X */ X t = strtok(args, " \t"); X if ( t == NULL ) { X fprintf(stderr, X "olvwm: error in menu file %s, line %d\n", X filename, *lineno); X fputs("missing item after DEFAULT keyword.\n", stderr); X return(MENU_FATAL); X } X strcpy(prog, t); X t = strtok(NULL, ""); /* get remainder of args */ X if (t == NULL) X args[0] = '\0'; X else { X u = args; X /* can't use strcpy because they overlap */ X while ( *u++ = *t++ ) X ; X } X } X X if ( strcmp(prog, "MENU") == 0 ) X { X int rval; X X initMenu( (menudata **)&(currentButton->submenu) ); X saveMenu = currentMenu; X currentMenu = (menudata *)currentButton->submenu; X currentMenu->label = MemNewString(label); X X if (args[0] == '\0') X { X /* we haven't incremented lineno for this X * read loop yet, so we need to do it now. X * when END is read, parseMenu returns without X * incrementing lineno, so the count will be X * ok when this loop increments it before X * reading the next line of the file. X */ X (*lineno)++; X if ( (rval = parseMenu(filename, stream, X currentMenu, lineno)) < 0 ) X { X freeMenuData( currentMenu ); X return(MENU_FATAL); X } X else X fillMenuStruct( currentMenu ); X } X else { X rval = menuFromFile(args, currentMenu, True); X if (rval <= MENU_NOTFOUND) X return(MENU_FATAL); X } X if ( rval == MENU_PINNABLE ) X currentMenu->pinnable = True; X X currentMenu = saveMenu; X /* if submenu not found, reuse button */ X if ( rval != MENU_NOTFOUND ) X { X initButton( (buttondata **)&(currentButton->next) ); X currentButton = currentButton->next; X } X continue; X } X X done = False; X while ( !done ) X { X switch ( lookupToken( prog, &(currentButton->func) ) ) X { X case UsrToken: X /* if UsrToken, that means that "prog" was just X * the first word of the command to be executed, X */ X strcpy( localBuf, prog ); X APPEND_STRING( localBuf, " " ); X APPEND_STRING( localBuf, args ); X /* copy current contents of localBuf back into X * args array so that PshToken code can be used X */ X strcpy( args, localBuf ); X localBuf[0] = '\0'; X /* fall through */ X case PshToken: X if (continuation) X strcpy( localBuf, args ); X else X currentButton->exec = MemNewString( args ); X done = True; X break; X case PinToken: X fprintf( stderr, X "olvwm: format error in menu file %s, line %d\n", X filename, *lineno ); X fputs("menu title and END required before PIN keyword.\n", X stderr); X return(MENU_FATAL); X break; X default: X /* some other valid token found and returned */ X done = True; X break; X } X } X X if ( !continuation ) X { X initButton( (buttondata **)&(currentButton->next) ); X currentButton = currentButton->next; X } X } X /* never used the last button created */ X currentButton->isLast = True; X X return(MENU_OK); X} X X X/* X * fillMenuStruct - Once the menu structures have been filled out using X * information in the menu description file (via parseMenu()), the X * nbuttons and idefault elements need to be set. X */ static void fillMenuStruct( mptr ) menudata *mptr; X{ X buttondata *bptr; X int buttonIndex = 0; X X bptr = mptr->bfirst; X if ( bptr->isLast == True ) X { X MemFree( bptr ); X bptr = mptr->bfirst = NULL; X } X for ( ; bptr != NULL && bptr->isLast == False ; bptr = bptr->next ) X { X if ( bptr->isDefault == True ) X mptr->idefault = buttonIndex; X X if ( (bptr->next)->isLast == True ) X { X MemFree( bptr->next); X bptr->next = NULL; X } X X buttonIndex++; X } X /* buttonIndex is one past end, but started at 0, so = number buttons */ X mptr->nbuttons = buttonIndex; X} X X X/* X * Allowed menu keywords ("Token") X */ X struct _svctoken { X char *token; X FuncPtr func; X TokenType toktype; X} svctokenlookup[] = { X { "REFRESH", RefreshFunc, ServiceToken }, X { "CLIPBOARD", ClipboardFunc, ServiceToken }, X { "PRINT_SCREEN", PrintScreenFunc, ServiceToken }, X { "EXIT", ExitFunc, ServiceToken }, X { "WMEXIT", ExitOLWM, ServiceToken }, X { "PROPERTIES", PropertiesFunc, ServiceToken }, X { "NOP", NopFunc, ServiceToken }, X { "DEFAULT", NULL, DefaultToken }, X { "MENU", NULL, MenuToken }, X { "END", NULL, EndToken }, X { "PIN", NULL, PinToken }, X { "TITLE", NULL, TitleToken }, X { "WINDOW_CONTROLS", WindowCtlFunc, ServiceToken }, X { "FLIPDRAG", FlipDragFunc, ServiceToken }, X { "SAVE_WORKSPACE", SaveWorkspaceFunc, ServiceToken }, X { "POSTSCRIPT", PshFunc, PshToken }, X { "RESTART", RestartOLWM, ServiceToken }, X { "FLIPFOCUS", FlipFocusFunc, ServiceToken }, X}; X X#define NSERVICES (sizeof(svctokenlookup)/sizeof(struct _svctoken)) X X/* lookupToken -- look up a token in the list of tokens X * given a supposed keyword or service name. If the name doesn't X * match any existing token, return the user-defined token. X */ static TokenType lookupToken(nm,ppf) char *nm; XFuncPtr *ppf; X{ X int ii; X X for (ii=0; ii<NSERVICES; ii++) X { X if (!strcmp(nm,svctokenlookup[ii].token)) X { X if (ppf != (FuncPtr *)0) X *ppf = svctokenlookup[ii].func; X return svctokenlookup[ii].toktype; X } X } X if (ppf != (FuncPtr *)0) X *ppf = AppMenuFunc; X return UsrToken; X} X X X/* buildFromSpec -- build the real menu structures, and create the X * associated menus, from the specifications parsed from X * the menu layout. Free up the specifications as we go X * along. X */ static Menu * buildFromSpec(dpy,menu,deftitle) Display *dpy; menudata *menu; char *deftitle; X{ X Menu *m; X Button *b; X int ii; X buttondata *bdata, *bsave; X X m = MemNew(Menu); X if (menu->pinnable) X { X m->hasPushPin = True; X m->pinAction = (FuncPtr)MakeMenu; X if (menu->title == NULL) X m->title = deftitle; X else X m->title = menu->title; X } X else X { X m->hasPushPin = False; X m->pinAction = NULL; X /* non-pinnable menus only get titles if they ask for them */ X /* m->title must be NULL if menu->title is NULL */ X m->title = menu->title; X } X X m->buttonCount = menu->nbuttons; X m->buttonDefault = menu->idefault; X X b = (Button *)MemAlloc((unsigned)(menu->nbuttons * sizeof(Button))); X m->buttons = b; X for ( ii=0, bdata=menu->bfirst ; ii<menu->nbuttons ; ii++ ) X { X b[ii].label = bdata->name; X b[ii].stacked = bdata->submenu != NULL; X b[ii].state = Enabled; X b[ii].action.callback = bdata->func; X if ( b[ii].stacked ) X b[ii].action.submenu = X (void *)buildFromSpec(dpy, X (menudata *)(bdata->submenu), X bdata->name); X else X b[ii].action.submenu = (void *)bdata->exec; X X bsave = bdata; X bdata = bdata->next; X MemFree(bsave); X X } X X MenuCreate(dpy,m); X MemFree(menu); X return(m); X} X X X/* X * initMenu - X */ static void initMenu( newmenu ) menudata **newmenu; X{ X *newmenu = MemNew(menudata); X (*newmenu)->title = NULL; X (*newmenu)->label = NULL; X (*newmenu)->idefault = -1; X (*newmenu)->nbuttons = 0; X (*newmenu)->pinnable = False; X (*newmenu)->bfirst = (buttondata *)0; X} X X/* X * initButton - X */ static void initButton( newButton ) buttondata **newButton; X{ X *newButton = MemNew(buttondata); X (*newButton)->next = NULL; X (*newButton)->name = NULL; X (*newButton)->isDefault = False; X (*newButton)->isLast = False; X (*newButton)->func = (FuncPtr)0; X (*newButton)->exec = NULL; X (*newButton)->submenu = NULL; X} X X/* X * freeMenuData - free any possibly allocated memory for this menudata X * structure (and its buttons), since it's not going to be used X */ static void freeMenuData( unusedMenu ) menudata *unusedMenu; X{ X buttondata *unusedButton; X X /* isLast probably isn't set, since this menu had an error */ X if ( ( unusedButton = unusedMenu->bfirst ) != (buttondata *)0 ) X freeButtonData( unusedButton ); X X MemFree( unusedMenu->title ); X MemFree( unusedMenu->label ); X MemFree( unusedMenu ); X unusedMenu = NULL; X} X X/* X * freeButtonData - free any possibly allocated memory for this buttondata X * structure, since it's not going to be used X */ static void freeButtonData( unusedButton ) buttondata *unusedButton; X{ X X if ( unusedButton->next != NULL ) X freeButtonData( unusedButton->next ); X X MemFree( unusedButton->name ); X MemFree( unusedButton->exec ); X if ( unusedButton->submenu != NULL ) X freeMenuData( unusedButton->submenu ); X MemFree( unusedButton ); X unusedButton = NULL; X} END_OF_FILE if test 20286 -ne `wc -c <'usermenu.c'`; then echo shar: \"'usermenu.c'\" unpacked with wrong size! fi # end of 'usermenu.c' fi echo shar: End of archive 8 \(of 16\). cp /dev/null ark8isdone 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