[comp.sources.wanted] color background for SunView

jaysun@cygnus.eng.clemson.edu (Jay) (02/21/89)

I have received about 8 responses so far about wanting color images
for a background for SunView.  But no one has done it and had it
work correctly.  The following response was the only one that gave
some advice on how to do it.  I know someone out there with some 
spare time on their hands can get this to work right.  Maybe someone
from SUN will be reading this and will give the people what they want.
COLOR.....  I am looking at this whenever I get a chance but I do not
claim to be the greatest C programmer in the world so if I do get this
going myself it will be awhile.

>  I sort of did it, but gave up.  The code is actually pretty simple
>  (and sun gives it out with every copy of SunOS).  All I had to do
>  was to change the root pixrect to be 8 bits instead of 1 and 
>  tell it not to do a monochromatic multiple rop (it tries to make
>  multiple copies so that smaller bitmaps/icons get replicated to fill
>  the screen).  I gave up because the images would get their palette
>  trashed right away.  The code to keep track of which window gets
>  which palette is a bit harder to hack.  With only 8 bits of color
>  My colorized icons, windows, etc (I colorized clock tool for instance)
>  grab the pallete from the background and make it look funny.
>  If you get any code that works better, please let me know.  Who
>  knows, maybe I will give it another go if enough people ask you
>  for it, and no one has yet done it.


Lets get it together,
                       Jay Williamson

pgraves@cvbnet2.UUCP (Peter Graves (x307)) (02/22/89)

From article <4498@hubcap.UUCP>, by jaysun@cygnus.eng.clemson.edu (Jay):
> 
> I have received about 8 responses so far about wanting color images
> for a background for SunView.  But no one has done it and had it
> work correctly.  The following response was the only one that gave
> some advice on how to do it.  I know someone out there with some 
> spare time on their hands can get this to work right.  Maybe someone
> from SUN will be reading this and will give the people what they want.
> COLOR.....  I am looking at this whenever I get a chance but I do not
> claim to be the greatest C programmer in the world so if I do get this
> going myself it will be awhile.
> 
> Lets get it together,
>                        Jay Williamson


   Here is a version of suntools that will let you have color images for a 
background.  We use it here all the time.  I haven't compiled it lately so 
I not sure it will, but you should be able to get it working easily.

Examples of using this version of suntools:

   To use a color image for the background:
      suntools -i -background <raster-file>

   Solid sky blue colored background:
      suntools -pattern sky -f 210 255 210

   Solid changing color background:
      suntools -int 10000000 -pattern grey -f 210 255 210;;


  Peter Graves
  Prime Computer, Inc

  Internet: pgraves@toolkit.prime.com
  UUCP:    {uunet!decvax, decwrl!sun, linus!raybed2}!cvbnet!toolkit!pgraves

 --------------------   CUT HERE  ---------------------------------------------

/* Changes made by Steve Yost. */
/* This source is made to use with a single color background - suntools receives   a SIGALRM signal every three seconds and changes the colormap for the
   background slightly . It also takes color image backgrounds, but does not
   account for this in the colormap shift.
*/
/* This source allows definition of several new arguments to the suntools which
   gets interrupts to change the color of the background:
	-int	interrupt interval in microseconds;
	-rl, -gl, -bl	red, green, and blue lower color value limits. ( > 0 ). 
	-ru, -gu, -bu	red, green, and blue upper color value limits. ( < 255 )
	-rint, -gint, -bint 	r,g,b value interval steps at each interrupt.
*/

#ifndef lint
static  char sccsid[] = "@(#)suntools.c 1.1 86/09/25 SMI";
#endif

/*
 * Sun Microsystems, Inc.
 */

/*
 * Root window: Provides the background window for a screen.
 *	Put up environment manager menu.
 */

#include <sys/types.h>
#include <pixrect/pixrect.h>
#include <sunwindow/rect.h>
#include <sunwindow/cms.h>
#include <string.h>
#include <suntool/tool_hs.h>
#include <sys/ioctl.h>
#include <sys/dir.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <pwd.h>
#include <ctype.h>
#include <sunwindow/defaults.h>
#include <suntool/menu.h>
#include <suntool/wmgr.h>
#include <suntool/selection.h>
#include <suntool/selection_svc.h>
#include <suntool/walkmenu.h>
#include <suntool/icon.h>
#include <suntool/icon_load.h>

#define Pkg_private

Pkg_private int walk_getrootmenu(), walk_handlerootmenuitem();
static int wmgr_getrootmenu(), wmgr_handlerootmenuitem();

#define GET_MENU (walk ? walk_getrootmenu : wmgr_getrootmenu)
#define MENU_ITEM (walk ? walk_handlerootmenuitem : wmgr_handlerootmenuitem)

#define KEY_PUT		KEY_LEFT(6)
#define KEY_CLOSE	KEY_LEFT(7)
#define KEY_GET		KEY_LEFT(8)
#define KEY_FIND	KEY_LEFT(9)
#define KEY_DELETE	KEY_LEFT(10)

#define MAXPATHLEN	1024

extern int            errno;

extern char          *malloc(),
		     *calloc(),
		     *getenv(),
		     *strcpy(),
		     *strncat(),
		     *strncpy(), 
		     *index();

extern struct pixrect *pr_load_image();

static void	      root_winmgr(),
		      root_colorchanger(),
		      root_colorchanger2(),
		      root_sigchldhandler(),
		      root_sigwinchhandler(),
		      root_sigchldcatcher(),
		      root_sigwinchcatcher(),
		      root_initialsetup(),
		      root_set_background(),
		      root_set_pattern(),
		      root_start_service();

Pkg_private char *wmgr_savestr();

static int            dummy_proc();
static struct selection empty_selection = {
	SELTYPE_NULL, 0, 0, 0, 0
};

static Seln_client    root_seln_handle;
static char	     *seln_svc_file;

static int            rootfd,
		      rootnumber,
		      root_SIGCHLD,
		      root_SIGWINCH;

static int walk;

static struct screen  screen;

static struct pixwin *pixwin;

#define	ROOTMENUITEMS	20
#define	ROOTMENUFILE	"/usr/lib/rootmenu"
#define ROOTMENUNAME	"Suntools"
#define ARG_CHARS       1024

static struct menuitem       root_items[ROOTMENUITEMS];

struct menuitemstrings {
	char         *mis_prog;    /* program to call */
	char         *mis_args;    /* args to program */
} root_itemstrings[ROOTMENUITEMS];

char                 *rootmenufile;

struct menu           wmgr_rootmenubody;
Pkg_private Menu      wmgr_rootmenu;

struct stat_rec {
    char             *name;	   /* Dynamically allocated menu file name */
    time_t            mftime;      /* Modified file time */
};

#define	MAX_FILES	40
Pkg_private struct stat_rec wmgr_stat_array[MAX_FILES];
Pkg_private int            wmgr_nextfile;

static	enum root_image_type {
	ROOT_IMAGE_PATTERN,
	ROOT_IMAGE_SOLID,
} root_image_type;
static struct pixrect *root_image_pixrect;
static root_color;
colormap_t root_colormap;
static int color_background = 0;
int interval = 1000000;	/* microseconds between color changes */
static int red_interval = 2;
static int green_interval = -1;
static int blue_interval = 3;
static int red_ulimit = 200;
static int green_ulimit = 150;
static int blue_ulimit = 200;
static int red_llimit = 0;
static int green_llimit = 0;
static int blue_llimit = 0;
#define	ROOT_CMS_SIZE 4
        	u_char root_red[ROOT_CMS_SIZE], root_green[ROOT_CMS_SIZE],
        	    root_blue[ROOT_CMS_SIZE];

#ifdef STANDALONE
main(argc, argv)
#else
suntools_main(argc, argv)
#endif
	int argc;
	char **argv;
{
	char	name[WIN_NAMESIZE], setupfile[MAXNAMLEN];
	int	placeholderfd;
	int	donosetup = 0, printname = 0;
	char   *root_background_file = 0;
	unsigned char red[256], green[256], blue[256];
	register struct	pixrect *fb_pixrect;
#define DONT_CARE_SHIFT         -1
        Firm_event fe_focus;
        int fe_focus_shift;
        Firm_event fe_restore_focus;
        int fe_restore_focus_shift;
        int set_focus = 0, set_restore_focus = 0, set_sync_tv = 0;
        struct timeval sync_tv;
	char *font_name;
	char    **args;
	struct singlecolor single_color;
	register int i;

	seln_svc_file = "selection_svc";
	root_image_type = ROOT_IMAGE_PATTERN;
	root_image_pixrect = tool_bkgrd;
	root_color = -1;
	root_set_pattern(defaults_get_string("/SunView/Root_Pattern",
	    "on", NULL), &single_color);
	if (defaults_get_boolean("/SunView/Click_to_Type", FALSE, NULL)) {
		/* 's'plit focus (See -S below if change) */
		fe_focus.id = MS_LEFT;
		fe_focus.value = 1;
		fe_focus_shift = DONT_CARE_SHIFT;
		set_focus = 1;
		fe_restore_focus.id = MS_MIDDLE;
		fe_restore_focus.value = 1;
		fe_restore_focus_shift = DONT_CARE_SHIFT;
		set_restore_focus = 1;
		sync_tv.tv_usec = 0;
		sync_tv.tv_sec = 10;
		set_sync_tv = 1;
	}
	
	font_name = defaults_get_string("/SunView/Font", "", NULL);
	if (*font_name != '\0') setenv("DEFAULT_FONT", font_name);
	
	/*
	 * Parse cmd line.
	 */
	setupfile[0] = NULL;
	win_initscreenfromargv(&screen, argv);
	if (argv) {
                for (args = ++argv;*args;args++) {
                        if ((strcmp(*args, "-s") == 0) && *(args+1)) {
				(void) strcpy(setupfile, *(args+1));
                                args++;
                        } else if (strcmp(*args, "-F") == 0) {
                                root_color = -1;
                                root_image_type = ROOT_IMAGE_SOLID;
                        } else if (strcmp(*args, "-B") == 0) {
                                root_color = 0;
                                root_image_type = ROOT_IMAGE_SOLID;
                        } else if (strcmp(*args, "-P") == 0)
				root_set_pattern("on", &single_color);
                        else if (strcmp(*args, "-n") == 0)
                                donosetup = 1;
                        else if (strcmp(*args, "-p") == 0)
                                printname = 1;
                        else if (strcmp(*args, "-int") == 0){
				if (args_remaining(args) < 2)
				    goto Arg_Count_Error;
				/* set up alarm to change root color */
				if (color_background == 1){
	    			    (void) signal(SIGALRM, root_colorchanger2);
				} else {
	    			    (void) signal(SIGALRM, root_colorchanger);
				}
				alarm(10);
                                interval = atoi(*++args);
                        }else if (strcmp(*args, "-rint") == 0){
				if (args_remaining(args) < 2)
					goto Arg_Count_Error;
                                red_interval = atoi(*++args);
                        }else if (strcmp(*args, "-gint") == 0){
				if (args_remaining(args) < 2)
					goto Arg_Count_Error;
                                green_interval = atoi(*++args);
                        }else if (strcmp(*args, "-bint") == 0){
				if (args_remaining(args) < 2)
					goto Arg_Count_Error;
                                blue_interval = atoi(*++args);
                        }else if (strcmp(*args, "-ru") == 0){
				if (args_remaining(args) < 2)
					goto Arg_Count_Error;
                                red_ulimit = atoi(*++args);
                        }else if (strcmp(*args, "-gu") == 0){
				if (args_remaining(args) < 2)
					goto Arg_Count_Error;
                                green_ulimit = atoi(*++args);
                        }else if (strcmp(*args, "-bu") == 0){
				if (args_remaining(args) < 2)
					goto Arg_Count_Error;
                                blue_ulimit = atoi(*++args);
                        }else if (strcmp(*args, "-rl") == 0){
				if (args_remaining(args) < 2)
					goto Arg_Count_Error;
                                red_llimit = atoi(*++args);
                        }else if (strcmp(*args, "-gl") == 0){
				if (args_remaining(args) < 2)
					goto Arg_Count_Error;
                                green_llimit = atoi(*++args);
                        }else if (strcmp(*args, "-bl") == 0){
				if (args_remaining(args) < 2)
					goto Arg_Count_Error;
                                blue_llimit = atoi(*++args);
                        } else if (strcmp(*args, "-color") == 0) {
				if (args_remaining(args) < 4)
					goto Arg_Count_Error;
				++args;
                                if (win_getsinglecolor(&args, &single_color))
                                	continue;
                                root_color = 1;
                        } else if (strcmp(*args, "-background") == 0) {
				if (args_remaining(args) < 2)
					goto Arg_Count_Error;
                                root_background_file = *++args;
                        } else if (strcmp(*args, "-pattern") == 0) {
				if (args_remaining(args) < 2)
					goto Arg_Count_Error;
				++args;
				root_set_pattern(*args, &single_color);
                        } else if (strcmp(*args, "-svc") == 0) {
				if (args_remaining(args) < 2)
					goto Arg_Count_Error;
                                seln_svc_file = *++args;
                                fprintf(stderr,
                                	"Starting selection service \"%s\"\n",
                                	seln_svc_file);
			} else if (strcmp(*args, "-S") == 0) {
				/*
				 * 's'plit focus (See Click_to_type above
				 * if change)
				 */
				fe_focus.id = MS_LEFT;
				fe_focus.value = 1;
				fe_focus_shift = DONT_CARE_SHIFT;
				set_focus = 1;
				fe_restore_focus.id = MS_MIDDLE;
				fe_restore_focus.value = 1;
				fe_restore_focus_shift = DONT_CARE_SHIFT;
				set_restore_focus = 1;
				sync_tv.tv_usec = 0;
				sync_tv.tv_sec = 10;
				set_sync_tv = 1;
			} else if (strcmp(*args, "-c") == 0) {
				/* set 'c'aret */
				get_focus_from_args(&args, &fe_focus.id,
				    &fe_focus.value, &fe_focus_shift);
				set_focus = 1;
			} else if (strcmp(*args, "-r") == 0) {
				/* 'r'estore caret */
				get_focus_from_args(&args, &fe_restore_focus.id,
				    &fe_restore_focus.value,
				    &fe_restore_focus_shift);
				set_restore_focus = 1;
			} else if (strcmp(*args, "-t") == 0) {
				/* set 't'imeout */
				if (args_remaining(args) < 2)
					goto Arg_Count_Error;
				args++;
				sync_tv.tv_usec = 0;
				sync_tv.tv_sec = atoi(*args);
				set_sync_tv = 1;
			} else if (argc == 2 && *args[0] != '-')
				/*
				 * If only arg and not a flag then treat as
				 * setupfile (backward compatibility with 1.0).
				 */
				(void) strcpy(setupfile, *args);
                }
        }

	/*
	 * Initialize root menu from menu file.
	 */
	rootmenufile = defaults_get_string("/SunView/Rootmenu_filename", "",
					   NULL);
	if (*rootmenufile == '\0'
	    && (rootmenufile = getenv("ROOTMENU")) == NULL)
	    rootmenufile = ROOTMENUFILE;
	if (defaults_get_boolean("/SunView/Walking_Menus", FALSE, NULL))
	    walk = 1;
	wmgr_rootmenu = walk ? NULL : (Menu)&wmgr_rootmenubody;
	if (GET_MENU(ROOTMENUNAME, wmgr_rootmenu, rootmenufile,
		     root_items, root_itemstrings, ROOTMENUITEMS) <= 0) {
	    fprintf(stderr, "suntools: invalid root menu\n");
	    exit(1);
	}
	/*
	 * Set up signal catchers.
	 */
	(void) signal(SIGCHLD, root_sigchldcatcher);
	(void) signal(SIGWINCH, root_sigwinchcatcher);
	/*
	 * Find out what colormap is so can restore later.
	 * Do now before call win_screennew which changes colormap.
	 */
	if (screen.scr_fbname[0] == NULL)
		strcpy(screen.scr_fbname, "/dev/fb");
	if ((fb_pixrect = pr_open(screen.scr_fbname)) == (struct pixrect *)0) {
		fprintf(stderr, "suntools: invalid frame buffer %s\n",
		    screen.scr_fbname);
		exit(1);
	}
	pr_getcolormap(fb_pixrect, 0, 256, red, green, blue);
	/*
	 * Create root window
	 */
	if ((rootfd = win_screennew(&screen)) == -1) {
		perror("suntools");
		exit(1);
	}
        if (root_background_file != (char *) NULL)
        	root_set_background(root_background_file);
	if (root_color != 1 && root_image_type == ROOT_IMAGE_SOLID) {
		Cursor	cursor = cursor_create(0);

		win_getcursor(rootfd, cursor);
		cursor_set(cursor, CURSOR_OP, PIX_SRC^PIX_DST, 0);
		win_setcursor(rootfd, cursor);
		cursor_destroy(cursor);
	}
	/* Set input parameters */
	if (set_focus)
		if (win_set_focus_event(rootfd, &fe_focus, fe_focus_shift)) {
			perror("win_set_focus_event");
			exit(1);
		}
	if (set_restore_focus)
		if (win_set_swallow_event(rootfd,
		    &fe_restore_focus, fe_restore_focus_shift)){
			perror("win_set_swallow_event");
			exit(1);
		}
	if (set_sync_tv)
		if (win_set_event_timeout(rootfd, &sync_tv)) {
			perror("win_set_event_timeout");
			exit(1);
		}
	win_screenget(rootfd, &screen);
	/*
	 * Open pixwin.
	 */
	if ((pixwin = pw_open(rootfd)) == 0) {
                fprintf(stderr, "%s not available for window system usage\n",
		    screen.scr_fbname);
                perror("suntools");
                exit(1);
        }
        /* Set up own color map if have own color */
        if (root_color == 1) {
        	char cmsname[CMS_NAMESIZE];
        	int color;
        	
        	root_red[0] = screen.scr_background.red;
        	root_green[0] = screen.scr_background.green;
        	root_blue[0] = screen.scr_background.blue;
		for (color = 1; color < ROOT_CMS_SIZE-1; color++) {
        		root_red[color] = single_color.red;
        		root_green[color] = single_color.green;
        		root_blue[color] = single_color.blue;
		}
        	root_red[ROOT_CMS_SIZE-1] = screen.scr_foreground.red;
        	root_green[ROOT_CMS_SIZE-1] = screen.scr_foreground.green;
        	root_blue[ROOT_CMS_SIZE-1] = screen.scr_foreground.blue;
        	sprintf(cmsname, "rootcolor%D", getpid());
        	pw_setcmsname(pixwin, cmsname);
		pw_putcolormap(pixwin, 0, ROOT_CMS_SIZE,
		    root_red, root_green, root_blue);
        }
	if ( color_background ){
        	char mycmsname[CMS_NAMESIZE];
		strcpy(mycmsname, "myroot");
               	pw_setcmsname(pixwin, mycmsname);
		pw_putcolormap(pixwin, 0, 
			root_colormap.length, 
			root_colormap.map[0],
			root_colormap.map[1],
			root_colormap.map[2]);
	}
       	/*
	 * Set up root''s name in environment
	 */
	win_fdtoname(rootfd, name);
	rootnumber = win_nametonumber(name);
	we_setparentwindow(name);
	if (printname)
		fprintf(stderr, "suntools window name is %s\n", name);
	/*
	 * Steal a window for the tool slot allocator
	 * & stash its name in the environment
	 */
	if ((placeholderfd = win_getnewwindow()) == -1)  {
		fprintf(stderr,
			"No window available for placing open windows\n");
		perror("suntools");
	} else {
		win_fdtoname(placeholderfd, name);
		setenv("WMGR_ENV_PLACEHOLDER", name);
	}
	/*
	 * Set up tool slot allocator
	 */
	wmgr_init_icon_position(rootfd);
	wmgr_init_tool_position(rootfd);
	/*
	 * Setup tty parameters for all terminal emulators that will start.
	 */
	{int tty_fd;
	tty_fd = open("/dev/tty", O_RDWR, 0);
	if (tty_fd < 0)
		ttysw_saveparms(2);	/* Try stderr */
	else {
		ttysw_saveparms(tty_fd);
		(void) close(tty_fd);
	}
	}
	/*	try to make sure there is a selection service
	 */
#define	SEL_SVC_SEC_WAIT	5
#define	SEL_CLIENT_NULL		(Seln_client) NULL
	if ((root_seln_handle = seln_create(dummy_proc, dummy_proc, dummy_proc,
	    &root_seln_handle)) == SEL_CLIENT_NULL) {
		root_start_service();
		for (i = 0;
		   i < SEL_SVC_SEC_WAIT && root_seln_handle == SEL_CLIENT_NULL;
		   i++) {
			sleep(1);
			root_seln_handle = seln_create(dummy_proc, dummy_proc,
			    dummy_proc, &root_seln_handle);
		}
		if (root_seln_handle == SEL_CLIENT_NULL)
			fprintf(stderr,
		        "Can't find old, or start new, selection service\n");
	}
	/*
	 * Draw background.
	 */
	root_sigwinchhandler();
	/*
	 * Do initial window setup.
	 */
	if (!donosetup)
		root_initialsetup(setupfile);
	/*
	 * Do window management loop.
	 */
	root_winmgr();
	/*
	 * Destroy screen sends SIGTERMs to all existing windows and
	 * wouldn''t let any windows install themselves in the window tree.
	 * Calling process of win_screedestroy is spared SIGTERM.
	 */
	win_screendestroy(rootfd);
	close(placeholderfd);
	/*
	 * Lock screen before clear so don''t clobber frame buffer while
	 * cursor moving.
	 */
	pw_lock(pixwin, &screen.scr_rect);
	/*
	 * Clear available plane groups
	 */
	for (i = 0; i < PIX_MAX_PLANE_GROUPS; i++) {
		if (pixwin->pw_clipdata->pwcd_plane_groups_available[i]) {
			/* Write to all plane groups */
			pr_set_planes(pixwin->pw_pixrect, i, PIX_ALL_PLANES);
			/* Clear screen */
			pr_rop(pixwin->pw_pixrect,
			    screen.scr_rect.r_left, screen.scr_rect.r_top,
			    screen.scr_rect.r_width, screen.scr_rect.r_height,
			    PIX_CLR, 0, 0, 0);
			/* Reset previous colormap */
			pr_putcolormap(pixwin->pw_pixrect, 0, 256,
			    red, green, blue);
		}
	}
	/*
	 * Unlock screen.
	 */
	pw_unlock(pixwin);
	exit(0);
Arg_Count_Error:
	fprintf(stderr, "%s arg count error\n", args);
	exit (-1);
}

static
args_remaining(args)
		char **args;
{
	register i;

	for (i = 0; *(args+i); i++) {}
	return (i);
}

static
get_focus_from_args(argv_ptr, event, value, shift)
	char ***argv_ptr;
	register short *event;
	register int *value;
	register int *shift;
{
#define	SHIFT_MASK(bit) (1 << (bit))
	char str[200];
	register char *arg;

	if (args_remaining(*argv_ptr) < 4) {
		fprintf(stderr, "%s arg count error\n", *argv_ptr);
		exit (-1);
	}
	(*argv_ptr)++;
	arg = **argv_ptr;
	if (strcmp(arg, "LOC_WINENTER") == 0)
		*event = LOC_WINENTER;
	else if (strcmp(arg, "MS_LEFT") == 0)
		*event = MS_LEFT;
	else if (strcmp(arg, "MS_MIDDLE") == 0)
		*event = MS_MIDDLE;
	else if (strcmp(arg, "MS_RIGHT") == 0)
		*event = MS_RIGHT;
	else if (sscanf(arg, "BUT%s", str) == 1)
		*event = atoi(str)+BUT_FIRST;
	else if (sscanf(arg, "KEY_LEFT%s", str) == 1)
		*event = atoi(str)+KEY_LEFTFIRST-1;
	else if (sscanf(arg, "KEY_RIGHT%s", str) == 1)
		*event = atoi(str)+KEY_RIGHTFIRST-1;
	else if (sscanf(arg, "KEY_TOP%s", str) == 1)
		*event = atoi(str)+KEY_TOPFIRST-1;
	else if (strcmp(arg, "KEY_BOTTOMLEFT") == 0)
		*event = KEY_BOTTOMLEFT;
	else if (strcmp(arg, "KEY_BOTTOMRIGHT") == 0)
		*event = KEY_BOTTOMRIGHT;
	else
		*event = atoi(arg);
	(*argv_ptr)++;
	arg = **argv_ptr;
	if (strcmp(arg, "DOWN") == 0 || strcmp(arg, "Down") == 0 ||
	    strcmp(arg, "down") == 0)
		*value = 1;
	else if (strcmp(arg, "ENTER") == 0 || strcmp(arg, "Enter") == 0 ||
	    strcmp(arg, "enter") == 0)
		*value = 1;
	else if (strcmp(arg, "UP") == 0 || strcmp(arg, "Up") == 0 ||
	    strcmp(arg, "up") == 0)
		*value = 0;
	else
		*value = atoi(arg);
	(*argv_ptr)++;
	arg = **argv_ptr;
	if (strcmp(arg, "SHIFT_LEFT") == 0)
		*shift = SHIFT_MASK(LEFTSHIFT);
	else if (strcmp(arg, "SHIFT_RIGHT") == 0)
		*shift = SHIFT_MASK(RIGHTSHIFT);
	else if (strcmp(arg, "SHIFT_LEFTCTRL") == 0)
		*shift = SHIFT_MASK(LEFTCTRL);
	else if (strcmp(arg, "SHIFT_RIGHTCTRL") == 0)
		*shift = SHIFT_MASK(RIGHTCTRL);
	else if (strcmp(arg, "SHIFT_DONT_CARE") == 0)
		*shift = DONT_CARE_SHIFT;
	else if (strcmp(arg, "SHIFT_ALL_UP") == 0)
		*shift = 0;
	else
		*shift = atoi(arg);

}

static void
root_winmgr()
{
    struct inputmask      im;
    struct inputevent     event;
    int                   keyexit = 0;

    /*
     * Set up input mask so can do menu stuff 
     */
    input_imnull(&im);
    im.im_flags |= IM_NEGEVENT;
    im.im_flags |= IM_ASCII;
    win_setinputcodebit(&im, SELECT_BUT);
    win_setinputcodebit(&im, MENU_BUT);
    win_setinputcodebit(&im, WIN_STOP);
    win_setinputcodebit(&im, KBD_REQUEST);
    win_setinputcodebit(&im, KEY_PUT);
    win_setinputcodebit(&im, KEY_GET);
    win_setinputcodebit(&im, KEY_FIND);
    win_setinputcodebit(&im, KEY_DELETE);
    win_setinputmask(rootfd, &im, (struct inputmask *) 0, WIN_NULLLINK);
    /*
     * Read and invoke menu items 
     */
    for (;;) {
	int                   ibits, nfds;

	/*
	 * Use select (to see if have input) so will return on SIGWINCH or
	 * SIGCHLD. 
	 */
	ibits = 1 << rootfd;
	do {
	    if (root_SIGCHLD)
		root_sigchldhandler();
	    if (root_SIGWINCH)
		root_sigwinchhandler();
	} while (root_SIGCHLD || root_SIGWINCH);
	nfds = select(8 * sizeof (ibits), &ibits, (int *) 0, (int *) 0,
		      (struct timeval *) 0);
	if (nfds == -1) {
	    if (errno == EINTR)
		/*
		 * Go around again so that signals can be handled.  ibits may
		 * be non-zero but should be ignored in this case and they will
		 * be selected again. 
		 */
		continue;
	    else {
		perror("suntools");
		break;
	    }
	}
	if (ibits & (1 << rootfd)) {
	    /*
	     * Read will not block. 
	     */
	    if (input_readevent(rootfd, &event) < 0) {
		if (errno != EWOULDBLOCK) {
		    perror("suntools");
		    break;
		}
	    }
	} else
	    continue;

	switch (event.ie_code) {
	  case CTRL(q):	       /* Escape for getting out	 */
	    if (keyexit) {	       /* when no mouse around	 */
		return;
	    }
	    continue;
	  case CTRL(d):
	    keyexit = 1;
	    continue;
	  case WIN_STOP:
	    if (root_seln_handle != (Seln_client) NULL) {
		seln_clear_functions();
	    }
	    break;
	  case KBD_REQUEST:	/* Always refuse keyboard focus request */
	    win_refuse_kbd_focus(rootfd);
	    break;
	  case KEY_PUT:
	  case KEY_GET:
	  case KEY_FIND:
	  case KEY_DELETE:
	    if (root_seln_handle != (Seln_client) NULL) {
		seln_report_event(root_seln_handle, &event);
	    }
	    break;
	  case KEY_CLOSE:
	    break;
	  case MS_LEFT:
	    if (win_inputposevent(&event)) {
		/*  the left button went down; clear the selection.  */
		selection_set(&empty_selection, dummy_proc, dummy_proc, rootfd);
		if (root_seln_handle != (Seln_client) NULL) {
		    Seln_rank             rank;

		    rank = seln_acquire(root_seln_handle, SELN_UNSPECIFIED);
		    seln_done(root_seln_handle, rank);
		}
	    }
	    break;
	  case MS_MIDDLE:
	    pw_rop( pixwin, 0,0, 1152, 900, PIX_NOT(PIX_SRC), pixwin->pw_pixrect, 0, 0 );
	  case MENU_BUT:
	    if (win_inputposevent(&event)) {
		if (!root_menu_mgr(&event)) {
		    return;
		}
	    }
	    break;
	  default:
	    break;
	}
	keyexit = 0;
    }
}

extern struct menuitem *menu_display();

static int
root_menu_mgr(event)
	struct inputevent    *event;
{
	Menu_item     mi; /* Old and new menu item */
	int	      exit;

	if (GET_MENU(ROOTMENUNAME, wmgr_rootmenu, rootmenufile,
		     root_items, root_itemstrings, ROOTMENUITEMS) <= 0) {
	    fprintf(stderr, "suntools: invalid root menu\n");
	    return 1;
	}
	for (;;) {
	    struct inputevent tevent;

	    exit = 0;
	    tevent = *event;
	    if (walk)
		mi = menu_show_using_fd(wmgr_rootmenu, rootfd, event);
	    else
		mi = (Menu_item)menu_display(&wmgr_rootmenu, event, rootfd);
	    if (mi)
		exit = MENU_ITEM(wmgr_rootmenu, mi, rootfd) == -1;
	    if (event->ie_code == MS_LEFT && !exit) {
		*event = tevent;
/*		win_setmouseposition(rootfd, event->ie_locx, event->ie_locy);*/
	    } else {
		break;
	    }
	}
	return (!exit);
}

static void
root_sigchldhandler()
{
	union	wait status;

	root_SIGCHLD = 0;
	while (wait3(&status, WNOHANG, (struct rusage *)0) > 0)
		{}
}

static void
root_sigwinchhandler()
{
	root_SIGWINCH = 0;
	pw_damaged(pixwin);
	switch (root_image_type) {
	case ROOT_IMAGE_PATTERN:
		pw_replrop(pixwin,
		    screen.scr_rect.r_left, screen.scr_rect.r_top,
		    screen.scr_rect.r_width, screen.scr_rect.r_height,
		    PIX_SRC | PIX_COLOR(root_color), root_image_pixrect, 0, 0);
		break;
	case ROOT_IMAGE_SOLID:
	default:
		pw_writebackground(pixwin,
		    screen.scr_rect.r_left, screen.scr_rect.r_top,
		    screen.scr_rect.r_width, screen.scr_rect.r_height,
		    PIX_SRC | PIX_COLOR(root_color));
	}
	pw_donedamaged(pixwin);
	return;
}

static void
root_colorchanger()
{
    int color;
    char colors[12];

	/* turn around when limit is reached */
	color = 1;
	if ( root_red[color] >= (red_ulimit-abs(red_interval)) ||
	     root_red[color] <= abs(red_interval) + red_llimit )
		red_interval = -red_interval;
	if ( root_green[color] >= (green_ulimit-abs(green_interval)) ||
	     root_green[color] <= abs(green_interval) + green_llimit )
		green_interval = -green_interval;
	if ( root_blue[color] >= (blue_ulimit-abs(blue_interval)) ||
	     root_blue[color] <= abs(blue_interval) + blue_llimit )
		blue_interval = -blue_interval;
		
    for (color = 1; color < ROOT_CMS_SIZE-1; color++) {
        root_red[color] += red_interval;
        root_green[color] += green_interval;
        root_blue[color] += blue_interval;
    }
    pw_putcolormap(pixwin, 0, ROOT_CMS_SIZE,
                    root_red, root_green, root_blue);
    /* write colormap numbers to screen */
    sprintf(colors, "%3d %3d %3d", root_red[1], root_green[1], root_blue[1] );
    pw_text(pixwin, 20, 30, PIX_SRC, 0, colors);
    /* set up for next time */
    ualarm(interval,0);

}

static void
root_colorchanger2()
{
	pw_shiftcolormap( pixwin, root_colormap.length, 1 );
	ualarm(interval,0);
}

static void
root_sigchldcatcher()
{
	root_SIGCHLD = 1;
}

static void
root_sigwinchcatcher()
{
	root_SIGWINCH = 1;
}

static char *
get_home_dir()
{
	extern	char *getlogin();
	extern	struct	passwd *getpwnam(), *getpwuid();
	struct	passwd *passwdent;
	char	*home_dir = getenv("HOME"), *loginname;

	if (home_dir != NULL)
		return(home_dir);
	loginname = getlogin();
	if (loginname == NULL) {
		passwdent = getpwuid(getuid());
	} else {
		passwdent = getpwnam(loginname);
	}
	if (passwdent == NULL) {
		fprintf(stderr,
		    "suntools: couldn't find user in password file.\n");
		return(NULL);
	}
	if (passwdent->pw_dir == NULL) {
		fprintf(stderr,
		    "suntools: no home directory in password file.\n");
		return(NULL);
	}
	return(passwdent->pw_dir);
}

#define	ROOT_ARGBUFSIZE		1000
#define	ROOT_SETUPFILE		"/.suntools"
#define	ROOT_MAXTOOLDELAY	10
#define	ROOT_DEFAULTSETUPFILE	"/usr/lib/.suntools"

static void
root_initialsetup(requestedfilename)
	char	*requestedfilename;
{
	register i;
	FILE	*file;
	char	filename[MAXNAMLEN], programname[MAXNAMLEN],
		otherargs[ROOT_ARGBUFSIZE];
	struct	rect rectnormal, recticonic;
	int	iconic, topchild, bottomchild, seconds, j;
	char	line[ARG_CHARS], full_programname[MAXPATHLEN];

	if (requestedfilename[0] == NULL) {
		char *home_dir = get_home_dir();
		if (home_dir == NULL)
			return;
		(void) strcpy(filename, home_dir);
		(void) strncat(filename, ROOT_SETUPFILE, sizeof(filename)-1-
				strlen(filename)-strlen(ROOT_SETUPFILE));
	} else
		(void) strncpy(filename, requestedfilename, sizeof(filename)-1);
	file = fopen(filename, "r");
	if (!file && !requestedfilename[0]) {
	/* If default file not found in HOME, look in public library */
		(void) strcpy(filename, ROOT_DEFAULTSETUPFILE);
		file = fopen(filename, "r");
	}
	if (!file) {
/*  We used to not give an error if looking for default .suntools.
    Now that we check the defaults lib dir, we give an error message.
		if (requestedfilename[0] == NULL)
			return;
*/
		fprintf(stderr, "suntools: couldn't open %s\n", filename);
		return;
	}
	while (fgets(line, sizeof (line), file)) {
		if (line[0] == '#')
			continue;
		otherargs[0] = '\0';
		programname[0] = '\0';
		i = sscanf(line, "%s%hd%hd%hd%hd%hd%hd%hd%hd%hD%[^\n]\n",
		    programname,
		    &rectnormal.r_left, &rectnormal.r_top,
		    &rectnormal.r_width, &rectnormal.r_height,
		    &recticonic.r_left, &recticonic.r_top,
		    &recticonic.r_width, &recticonic.r_height,
		    &iconic, otherargs);
		if (i == EOF)
			break;
		if (i < 10 || i > 11) {
		   /*
		    * Just get progname and args.
		    */
		    otherargs[0] = '\0';
		    programname[0] = '\0';
		    j = sscanf(line, "%s%[^\n]\n", programname, otherargs);
		    if (j > 0) {
			iconic = 0;
			rect_construct(&recticonic, WMGR_SETPOS, WMGR_SETPOS,
			    WMGR_SETPOS, WMGR_SETPOS);
			rect_construct(&rectnormal, WMGR_SETPOS, WMGR_SETPOS,
			    WMGR_SETPOS, WMGR_SETPOS);
		    } else {
		    fprintf(stderr,
		   "suntools: in file=%s fscanf gave %D, correct format is:\n",
			filename, i);
		    fprintf(stderr,
 "program open-left open-top open-width open-height close-left close-top close-width close-height iconicflag [args] <newline>\n OR\nprogram [args] <newline>\n");
		    continue;
		    }
		}
		/*
		 * Remember who top and bottom children windows are for use when
		 * trying to determine when tool is installed.
		 */
		topchild = win_getlink(rootfd, WL_TOPCHILD);
		bottomchild = win_getlink(rootfd, WL_BOTTOMCHILD);
		/*
		 * Fork tool.
		 */
		suntools_mark_close_on_exec();
		expand_path(programname, full_programname);
		(void) wmgr_forktool(full_programname, otherargs,
		    &rectnormal, &recticonic, iconic);
		/*
		 * Give tool chance to intall self in tree before starting next.
		 */
		for (seconds = 0; seconds < ROOT_MAXTOOLDELAY; seconds++) {
			sleep(1);
			if (topchild != win_getlink(rootfd, WL_TOPCHILD) ||
			    bottomchild != win_getlink(rootfd, WL_BOTTOMCHILD))
				break;
		}
	}
	(void) fclose(file);
}

Pkg_private
suntools_mark_close_on_exec()
{
	register i;
	int limit_fds = getdtablesize();

	/* Mark all fds (other than stds) as close on exec */
	for (i = 3; i < limit_fds; i++)
		(void) fcntl(i, F_SETFD, 1);
}

static void
root_set_pattern(token, ptr_single_color)
	char *token;
	struct singlecolor *ptr_single_color;
{
	char err[IL_ERRORMSG_SIZE];
	struct pixrect *mpr;

	if (strcmp(token, "on") == 0) {
		root_image_type = ROOT_IMAGE_PATTERN;
	} else if (strcmp(token, "off") == 0) {
		root_image_type = ROOT_IMAGE_SOLID;
	} else if (strcmp(token, "sky") == 0 ) {
		ptr_single_color->red = 110;
		ptr_single_color->green = 148;
		ptr_single_color->blue = 195;
		root_color = 1;
		root_image_type = ROOT_IMAGE_SOLID;
	} else if (strcmp(token, "green") == 0 ) {
		ptr_single_color->red = 33;
		ptr_single_color->green = 108;
		ptr_single_color->blue = 71;
		root_color = 1;
		root_image_type = ROOT_IMAGE_SOLID;
	} else if (strcmp(token, "beige") == 0 ) {
		ptr_single_color->red = 200; 
		ptr_single_color->green = 143;
		ptr_single_color->blue = 110;
		root_color = 1;
		root_image_type = ROOT_IMAGE_SOLID;
	} else if (strcmp(token, "royal") == 0 ) {
		ptr_single_color->red = 0; 
		ptr_single_color->green = 0;
		ptr_single_color->blue = 84;
		root_color = 1;
		root_image_type = ROOT_IMAGE_SOLID;
	} else if (strcmp(token, "grey") == 0 || strcmp(token, "gray") == 0) {
		ptr_single_color->red = ptr_single_color->green =
		    ptr_single_color->blue = 128;
		root_color = 1;
		root_image_type = ROOT_IMAGE_SOLID;
	} else if ((mpr = icon_load_mpr(token, err))== (struct pixrect *)0) {
		fprintf(stderr, "suntools: ");
		fprintf(stderr, err);
	} else {
		root_image_pixrect = mpr;
		root_image_type = ROOT_IMAGE_PATTERN;
	}
}

static void
root_set_background(filename)
	char	*filename;
{
	int		 x, y;
	FILE		*file;
	register struct pixrect	*tmp_pr, *root_pr;
	struct rasterfile rh;

	if ((file = fopen(filename, "r"))  == (FILE *) NULL)  {
		fprintf(stderr, "Couldn't open background file \"%s\":",
			filename);
		perror("");
		return;
	}
        pr_load_header(file, &rh);
	switch (root_colormap.type = rh.ras_maptype) {
                case RMT_NONE:
                        break;
                case RMT_EQUAL_RGB:
			color_background = 1;
                        root_colormap.length = rh.ras_maplength / 3;
                        root_colormap.map[0] = (unsigned char *)malloc((unsigned)root_colormap.length);
                        root_colormap.map[1] = (unsigned char *)malloc((unsigned)root_colormap.length);
                        root_colormap.map[2] = (unsigned char *)malloc((unsigned)root_colormap.length);
        		pr_load_colormap(file, &rh, &root_colormap) ;
			break;
		default:
			break;
	}
	if ((tmp_pr = pr_load_image(file, &rh, &root_colormap ))
	    == (struct pixrect *) NULL)  {
		fprintf(stderr, "Couldn't load background from %s\n",
			 filename);
		 fclose(file);
		 return;
	}
	fclose(file);
	root_pr =
	    mem_create(screen.scr_rect.r_width, screen.scr_rect.r_height, 
		rh.ras_depth);
	/* Center image */
	x = (screen.scr_rect.r_width - tmp_pr->pr_width) / 2;
	y = (screen.scr_rect.r_height - tmp_pr->pr_height) / 2;
	/* Initialize background */
	switch (root_image_type) {
	case ROOT_IMAGE_PATTERN:
		pr_replrop(root_pr, 0, 0,
		    screen.scr_rect.r_width, screen.scr_rect.r_height,
		    PIX_SRC | PIX_COLOR(root_color), root_image_pixrect, 			    0, 0);
		break;
	case ROOT_IMAGE_SOLID:
	default:
		pr_rop(root_pr, 0, 0,
		    screen.scr_rect.r_width, screen.scr_rect.r_height,
		    PIX_SRC | PIX_COLOR(root_color), 0, 0, 0);
	}
	/* Draw picture on image pixrect */
/*
	pr_rop(root_pr, x, y, tmp_pr->pr_width, tmp_pr->pr_height,
		PIX_SRC, tmp_pr, 0, 0);
*/
	pr_replrop(root_pr, 0, 0, screen.scr_rect.r_width, 
		screen.scr_rect.r_height,
                PIX_SRC, tmp_pr, 0, 0);

	pr_destroy(tmp_pr);
	root_image_pixrect = root_pr;
	/* PATTERN will cause image pixrect to be roped without replication */
	root_image_type = ROOT_IMAGE_PATTERN;
}

Pkg_private int
wmgr_menufile_changes()
{
	struct stat statb;
	int sa_count;

	if (wmgr_nextfile == 0) return 1;
	/* Whenever existing menu going up, stat menu files */
	for (sa_count = 0;sa_count < wmgr_nextfile;sa_count++) {
		if (stat(wmgr_stat_array[sa_count].name, &statb) < 0) {
			if (errno == ENOENT)
				return(1);
			fprintf(stderr, "suntools: ");
			perror(wmgr_stat_array[sa_count].name);
			return(-1);
		}
		if (statb.st_mtime > wmgr_stat_array[sa_count].mftime)
			return(1);
	}
	return 0;
}

Pkg_private
wmgr_free_changes_array()
{   
    int sa_count = 0;
    
    while (sa_count < wmgr_nextfile) {
	free(wmgr_stat_array[sa_count].name);      /* file name */
	wmgr_stat_array[sa_count].name = NULL;
	wmgr_stat_array[sa_count].mftime = 0;
	sa_count++;
    }
    wmgr_nextfile = 0;
}

static
wmgr_freerootmenus(menu)
	struct menu *menu;
{
	struct menu *next = menu->m_next, *nnext;

	while (next) {
		nnext = next->m_next;
		if (next->m_items) {
			free(next->m_items->mi_data); /* free string storage */
			free(next->m_items);	      /* item storage */
		}
		free(next);			      /* menu storage */
		next = nnext;
	}
	wmgr_free_changes_array();
}

static
wmgr_getrootmenu(mn, menu, mf, mi, mis, maxitems)
	char *mn, *mf;
	struct menu *menu;
	struct menuitem *mi;
	struct menuitemstrings *mis;
	int maxitems;
{
	FILE *f;
	int lineno;
	char line[ARG_CHARS], full_mf[MAXPATHLEN];
	char tag[32], prog[256], args[ARG_CHARS];
	struct stat statb;
	struct menu *menunext = (struct menu *)wmgr_rootmenu;
	int nitems = 0;
	static time_t mftime = 0;
	static char *nqformat = "%[^ \t\n]%*[ \t]%[^ \t\n]%*[ \t]%[^\n]\n";
	static char *qformat = "\"%[^\"]\"%*[ \t]%[^ \t\n]%*[ \t]%[^\n]\n";

	if (menu == (struct menu *)wmgr_rootmenu && wmgr_nextfile != 0) {
		if (wmgr_menufile_changes(wmgr_rootmenu) != 0)
			wmgr_freerootmenus(wmgr_rootmenu);
		else
			return menu->m_itemcount;
	}
	if (wmgr_nextfile >= MAX_FILES-1) {
		fprintf(stderr,
		    "suntools: max number of menus is %D\n", MAX_FILES);
		return -1;
	}
	expand_path(mf, full_mf);
	if ((f = fopen(full_mf, "r")) == NULL) {
		fprintf(stderr, "suntools: can't open menu file %s\n", full_mf);
		return -1;
	}
	if (stat(full_mf, &statb) < 0) {
	    fprintf(stderr, "suntools: ");
	    perror(full_mf);
	    fclose(f);
	    return -1;
	}
	wmgr_stat_array[wmgr_nextfile].mftime = statb.st_mtime;
	wmgr_stat_array[wmgr_nextfile].name = wmgr_savestr(full_mf);
	++wmgr_nextfile;
	menu->m_imagetype = MENU_IMAGESTRING;
	menu->m_imagedata = mn;
	menu->m_items = mi;
	for (nitems = 0, lineno = 1; nitems < maxitems &&
	    fgets(line, sizeof (line), f); lineno++) {
		if (line[0] == '#')
			continue;
		args[0] = '\0';
		if (sscanf(line, line[0] == '"' ? qformat : nqformat,
		    tag, prog, args) < 2) {
			fprintf(stderr,
			    "suntools: format error in %s: line %d\n",
			    full_mf, lineno);
			mftime = 0;	/* complain every time */
			continue;
		}
		if (strcmp(prog, "MENU") == 0) {
		    struct menu *m;
		    char *mi, *ms;
		    if (menu != (struct menu *)wmgr_rootmenu) {
			fprintf(stderr,
	"suntools: MENU command illegal in secondary menu file %s: line %d\n",
			    full_mf, lineno);
			continue;
		    }
		    if (wmgr_getrootmenu(
		        wmgr_savestr(tag),			   /* menu name */
		        m = (struct menu *)calloc(1, sizeof(struct menu)),
			args,				   /* file name */
		        mi = calloc(ROOTMENUITEMS, sizeof(struct menuitem)),
		        ms = calloc(ROOTMENUITEMS, sizeof(struct menuitemstrings)),
			ROOTMENUITEMS) <= 0) {
			    fprintf(stderr,
			        "suntools: invalid secondary menu %s\n", args);
			    free(m); free(mi), free(ms);
			    continue;
		    } else {
			menunext->m_next = m;
			menunext = m;
		    }
		} else {
		    if (mi->mi_imagedata)
		    	free((char *)mi->mi_imagedata);
		    mi->mi_imagetype = MENU_IMAGESTRING;
		    mi->mi_imagedata = (caddr_t)wmgr_savestr(tag);
		    mi->mi_data = (caddr_t)mis;
		    if (mis->mis_prog) free(mis->mis_prog);
		    if (mis->mis_args) free(mis->mis_args);
		    mis->mis_prog = wmgr_savestr(prog);
		    if (args[0] == '\0')
		    	mis->mis_args = (char *)NULL;
		    else
		    	mis->mis_args = wmgr_savestr(args);
		    mi++;
		    mis++;
		    nitems++;
		}
	}
	fclose(f);
	return menu->m_itemcount = nitems;
}

Pkg_private char *
wmgr_savestr(s)
	register char *s;
{
	register char *p;

	if ((p = malloc(strlen(s) + 1)) == NULL) {
		if (rootfd) win_screendestroy(rootfd);
		fprintf(stderr, "suntools: out of memory for menu strings\n");
		exit(1);
	}
	strcpy(p, s);
	return (p);
}

Pkg_private char *
wmgr_save2str(s, t)
	register char *s, *t;
{
	register char *p;

	if ((p = malloc(strlen(s) + strlen(t) + 1 + 1)) == NULL) {
		if (rootfd)
			win_screendestroy(rootfd);
		fprintf(stderr, "suntools: out of memory for menu strings\n");
		exit(1);
	}
	strcpy(p, s);
	strcpy(index(p, '\0') + 1, t);
	return (p);
}

static
wmgr_handlerootmenuitem(menu, mi, rootfd)
	struct	menu *menu;
	struct	menuitem *mi;
	int	rootfd;
{   
    int	returncode = 0;
    struct	rect recticon, rectnormal;
    struct	menuitemstrings *mis;
    char full_prog[MAXPATHLEN];

    /*
     * Get next default tool positions
    */
    rect_construct(&recticon,
		   WMGR_SETPOS, WMGR_SETPOS, WMGR_SETPOS, WMGR_SETPOS);
    rectnormal = recticon;
    mis = (struct menuitemstrings *)mi->mi_data;
    if (strcmp(mis->mis_prog, "EXIT") == 0) {
	returncode = wmgr_confirm(rootfd,
			"Press the left mouse button to confirm Exit.  \
To cancel, press the right mouse button now.");
    } else if (strcmp(mis->mis_prog, "REFRESH") == 0) {
	wmgr_refreshwindow(rootfd);
    } else {
	suntools_mark_close_on_exec();
	expand_path(mis->mis_prog, full_prog);
	(void) wmgr_forktool(full_prog, mis->mis_args,
			     &rectnormal, &recticon, 0/*!iconic*/);
    }
    return(returncode);
}


/* dummy proc for selection_set()
*/
static int
dummy_proc()
{
}


static void
root_start_service()
{
	register int	i, pid;
static char		*args[2] = {"selection_svc", 0 };
	if ((pid = vfork()) == 0)  {
		for (i = 30; i > 2; i--)  {
			close(i);
		}
		execvp(seln_svc_file, args, 0);
		perror("Couldn't fork selection service");
		sleep(7);
		exit(1);
	}
}

/* pw_shiftcmap.c - shift a colormap  to the left a specified distance */

pw_shiftcolormap(pw, size, distance)
        struct  pixwin *pw;
        int size;       /* size of colormap */
        int distance;   /* distance to shift */
{
        register u_char red[256], green[256], blue[256];
        register u_char r, g, b;
        register int    i;
        int     cycle, shift, planes;
        struct  colormapseg cms;

        pw_getcmsdata(pw, &cms, &planes);
        if (cms.cms_size < 2)
                return;
        pw_getcolormap(pw, 0, size, red, green, blue);
        for (shift = 0; shift < distance; ++shift) {
                r = red[0]; g = green[0]; b = blue[0];
                for (i = 0; i < size-1; ++i) {
                        red[i] = red[i+1];
                        green[i] = green[i+1];
                        blue[i] = blue[i+1];
                }
                red[i] = r; green[i] = g; blue[i] = b;
        }
        pw_putcolormap(pw, 0, size, red, green, blue);
}