v12i064: olvwm - Open Look Virtual Window Manager, Part08/16
Scott Oaks - Sun Consulting NYC
sdo at soliado.East.Sun.COM
Mon Apr 29 03:29:51 AEST 1991
Submitted-by: sdo at 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 at 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 at uunet.uu.net
argv at ora.com argv at zipcode.com
More information about the Comp.sources.x
mailing list