File:  [Research Unix] / researchv9 / X11 / src / X.V11R1 / clients / uwm / Menu.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:22:00 2018 UTC (8 years, 1 month ago) by root
Branches: belllabs, MAIN
CVS tags: researchv9-SUN3_old, researchv9-SUN3, HEAD
researchv9-SUN3(old)

#ifndef lint
static char *rcsid_Menu_c = "$Header: /var/lib/cvsd/repos/research/researchv9/X11/src/X.V11R1/clients/uwm/Menu.c,v 1.1.1.1 2018/04/24 17:22:00 root Exp $";
#endif	lint

#include <X11/copyright.h>

/*
 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
 *
 *                         All Rights Reserved
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in
 * supporting documentation, and that the name of Digital Equipment
 * Corporation not be used in advertising or publicity pertaining to
 * distribution of the software without specific, written prior permission.
 *
 *
 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */



/*
 * MODIFICATION HISTORY
 *
 * 000 -- M. Gancarz, DEC Ultrix Engineering Group
 * 001 -- L. Guarino Reid, DEC Ultrix Engineering Group, Western Software Lab
 *	  February 16, 1987
 *	  Change menu implementation so that it uses EnterWindow, LeaveWindow,
 *	  and MouseMotion events to track the mouse, instead of polling.
 * 002 -- L. Guarino Reid, DEC Ultrix Engineering Group, Western Software Lab
 *	  April 30, 1987. Convert to X11.
 * 003 -- L. Guarino Reid, DEC Ultrix Engineering Group, Western Software Lab
 *	  June 18, 1987. Change call to system to handle signals move smoothly.
 */

#ifndef lint
static char *sccsid = "@(#)Menu.c	3.8	1/24/86";
#endif

#include <signal.h>
#include "uwm.h"

Bool alternateGC;		/* true if only 2 colors are used */

#define DisplayLine(w, pane, width, height, str, fg, bg, inv) \
         if (alternateGC) { \
	     if (inv) \
	         XFillRectangle(dpy, w, MenuInvGC, 0, pane, width, height); \
	     else \
                 XDrawString(dpy, w, MenuGC, HMenuPad, pane + VMenuPad + MFontInfo->ascent, str, strlen(str)); \
         } else { \
             XSetForeground(dpy, MenuGC, bg); \
	     XFillRectangle(dpy, w, MenuGC, 0, pane, width, height); \
             XSetForeground(dpy, MenuGC, fg); \
             XDrawString(dpy, w, MenuGC, HMenuPad, pane + VMenuPad + MFontInfo->ascent, str, strlen(str)); \
         }

/* the following procedure is a copy of the implementation of system, 
 * modified to reset the handling of SIGINT, SIGQUIT, and SIGHUP before
 * exec-ing
 */
execute(s)
char *s;
{
	int status, pid, w;
	register int (*istat)(), (*qstat)();

	if ((pid = vfork()) == 0) {
		signal(SIGINT, SIG_DFL);
		signal(SIGQUIT, SIG_DFL);
		signal(SIGHUP, SIG_DFL);
		execl("/bin/sh", "sh", "-c", s, 0);
		_exit(127);
	}
	istat = signal(SIGINT, SIG_IGN);
	qstat = signal(SIGQUIT, SIG_IGN);
	while ((w = wait(&status)) != pid && w != -1)
		;
	if (w == -1)
		status = -1;
	signal(SIGINT, istat);
	signal(SIGQUIT, qstat);
	return(status);
}

Bool Menu(window, mask, button, x, y, menu)
Window window;				/* Event window. */
int mask;				/* Button/key mask. */
int button;				/* Button event detail. */
int x, y;				/* Event mouse position. */
MenuInfo *menu;
{
    XEvent button_event;		/* Button event packet. */
    int event_x, event_y;		/* location of button event */
    Bool func_stat;			/* Function status return. */
    Window sub_window;			/* Current subwindow. */
    int cur_item = 0;			/* Current menu item. */
    int hi_lite = 0;			/* Current highlighted item. */
    int i;				/* Iteration counter. */
    int hlfg, hlbg;			/* Hi-liter pixels. */
    MenuLine *ml;			/* Menu lines pointer. */
    char *hlname;			/* Pointer to hi-liter name. */
    char *strbuf;			/* String buffer for IsTextNL. */
    char *malloc();

    /*
     * Change the cursor.
     */
    XChangeActivePointerGrab(dpy, EVENTMASK, MenuCursor, CurrentTime);

    /*
     * Map the menu.
     */
    MapMenu(menu, x, y);
    if (Autoselect) {
        event_x = (menu->width >> 2) * 3;
        event_y = (menu->iheight >> 1);
        XWarpPointer(dpy, None, menu->w, 0, 0, 0, 0, event_x, event_y);
	goto hilite;
    }
    else {
        XWarpPointer(dpy, None, menu->w, 0, 0, 0, 0, 
    		(menu->width >> 2) * 3, menu->iheight >> 1);
        XFlush(dpy);
    }

    /*
     * Main loop.
     */
    while (TRUE) {

        /*
         *  Get next event for menu.
         */
        if (!GetButton(&button_event)) continue;
	switch (button_event.type) {

            case LeaveNotify:
	        /*
	         * If the mouse has moved out of the menu sideways, abort
	         * the menu operation. Reset the cursor and unmap the menu.
	         */
	        event_x = ((XLeaveWindowEvent * )&button_event)->x;
	        event_y = ((XLeaveWindowEvent * )&button_event)->y;
		if (event_x < 0 || event_x > menu->width) {
            	   ResetCursor(button);
		   UnmapMenu(menu);
            	   return(FALSE);
        	}
		goto hilite;

            case EnterNotify:
	        event_x = ((XEnterWindowEvent * )&button_event)->x;
	        event_y = ((XEnterWindowEvent * )&button_event)->y;
		goto hilite;
            case MotionNotify:
		{
	        event_x = ((XPointerMovedEvent * )&button_event)->x;
	        event_y = ((XPointerMovedEvent * )&button_event)->y;
hilite:
        	/*
         	* If the mouse has moved below or above the menu, but is still
         	* within the same vertical plane, then simply adjust the values
         	* so the user doesn't fall off the edge.
         	*/
        	if (event_y >= menu->height) 
		  event_y = menu->height - 1;
        	else if (event_y < 0) 
		  event_y = 0;
		  
        	/*
         	* If the mouse has moved to another item in the menu,
         	* highlight the new item.
         	*/
        	cur_item = event_y / menu->iheight;
        	if (cur_item != hi_lite) {

            	/*
             	* Remove highlighting on old item.
             	*/
            	if (hi_lite) {
                	DisplayLine(menu->w, hi_lite * menu->iheight,
                            menu->width, menu->iheight, hlname,
                            hlfg, hlbg, 1);
			XFlush(dpy);
            	}

           	/*
             	* Highlight new item.
             	*/
            	hi_lite = cur_item;
            	if (cur_item) {
                	for(i = 1, ml = menu->line; ml; i++, ml = ml->next) {
                    		if (i == cur_item) break;
               	 	}
                	DisplayLine(menu->w, cur_item * menu->iheight,
                            menu->width, menu->iheight, ml->name,
                            menu->hlfg.pixel, menu->hlbg.pixel, 1);
/*                	XSetForeground(dpy, MenuGC, menu->hlfg.pixel );
			XDrawRectangle(dpy, menu->w, MenuGC, 1, 
				cur_item * menu->iheight + 1, 
				menu->width - 3, menu->iheight - 3);
*/
			XFlush(dpy);
             		hlfg = ml->fg.pixel;
            		hlbg = ml->bg.pixel;
            		hlname = ml->name;
            	}
		}
        	break;

            case ButtonRelease:
	        /* have we released the invoking button? */
	        if (((XButtonReleasedEvent *)&button_event)->button == button) {
		    /*
		     * If no item was selected, simply close the menu and return.
		     */
		    if (!cur_item) {
		         ResetCursor(button);
			 UnmapMenu(menu);
		         return(TRUE);
		     }

		     /*
		      * Get a pointer to the menu line selected.
		      */
		     --cur_item;
		     for(i = 0, ml = menu->line; ml; i++, ml = ml->next) {
		         if (i == cur_item) break;
		     }

		     /*
		      * Perform the selected menu line action.
		      */
		     switch (ml->type) {

		         case IsShellCommand:
		             UnmapMenu(menu);
		             execute(ml->text);
		             break;

		         case IsText:
		             UnmapMenu(menu);
		             XStoreBytes(dpy, ml->text, strlen(ml->text));
		             break;

		         case IsTextNL:
		             UnmapMenu(menu);
		             strbuf = (char *)malloc(strlen(ml->text) + 2);
		             strcpy(strbuf, ml->text);
		             strcat(strbuf, "\n");
		             XStoreBytes(dpy, strbuf, strlen(strbuf));
		             free(strbuf);
		             break;

		         case IsUwmFunction:
			     /* change cursor and grab next button event
			      * to select the target window */
			     if (XGrabPointer( dpy, RootWindow(dpy, scr),
					       TRUE, EVENTMASK, GrabModeAsync,
					       GrabModeAsync, None,
					       TargetCursor, CurrentTime )
				   != GrabSuccess )
			         Error( "Could not grab pointer" );
		             GetContext(
			       &sub_window, &event_x, &event_y);
		             UnmapMenu(menu);
		             if (sub_window != menu->w)
			       func_stat =
		                 (*ml->func) (
				   sub_window, mask, button, event_x, 
				   event_y);
			     else func_stat = FALSE;
			     if (!func_stat) {
			       /* eat the next ButtonRelease */
			       while (TRUE) {
				   if (GetButton(&button_event) &&
				       button_event.type == ButtonRelease)
				     break;
			       }
			     }
			     XUngrabPointer( dpy, CurrentTime );
		             break;

		         case IsImmFunction:
		             UnmapMenu(menu);
 		            (*ml->func) (
			      sub_window, mask, button, event_x, 
			      event_y);
		             break;
		 
		         case IsMenuFunction:
		             while (TRUE) {
		                if (!GetButton(&button_event)) continue;
		                if (button_event.type != ButtonPress) continue;
		                if ((((XButtonPressedEvent *)&button_event)->state != mask) 
				 || (((XButtonPressedEvent *)&button_event)->button != button)) 
				 {
		                     UnmapMenu(menu);
		                     return(TRUE);
		                 }
		                 break;
		             }
		             UnmapMenu(menu);
		             func_stat = 
			     	Menu(menu->w, mask, button, x, y, ml->menu);
		             return(func_stat);
		             break;

		         default:
 		            Error("Menu -> Internal type error.");
		     }
		     return(TRUE);
		  
                 } 
		 /* else a different button was released. Fall through: */
            default:
                    /*
                     * Some other button event occurred, so abort the menu
                     * operation.
                     */
		    ResetCursor(button);
                    UnmapMenu(menu);
                    return(TRUE);
		
	}
     }
  }
}


/*
 * Create the menu windows for later use.
 */
CreateMenus()
{
    MenuLink *ptr;

    /*
     * If MaxColors isn't set, then jam it to an impossibly high
     * number.
     */
    if (MaxColors == 0)
        MaxColors = 25000;

    for(ptr = Menus; ptr; ptr = ptr->next)
        InitMenu(ptr->menu);
}

/*
 * Initialize a menu.
 */
InitMenu(menu)
MenuInfo *menu;
{
    MenuLine *ml;		/* Menu lines pointer. */
    int width;			/* Width of an item name. */
    int maxwidth;		/* Maximum width of item names. */
    int len;			/* Length of an item name. */
    int count = 1;		/* Number of items + 1 for name. */

    /*
     * Determine the name of the longest menu item.
     */
    maxwidth = XTextWidth(MFontInfo, menu->name, strlen(menu->name));
    if (maxwidth == 0)
        Error("InitMenu -> Couldn't get length of menu name");

    for(ml = menu->line; ml; ml = ml->next) {
        if ((len = strlen(ml->name)) == 0)
            break;
        width = XTextWidth(MFontInfo, ml->name, strlen(ml->name));
        if (width == 0) 
	  Error("InitMenu -> Couldn't get length of menu item name");
        if (width > maxwidth) maxwidth = width;
        count++;
    }

    /*
     * Get the color cells for the menu items.
     */
    GetMenuColors(menu);

    /*
     * Stash the menu parameters in the menu info structure.
     */
    menu->iheight = MFontInfo->ascent + MFontInfo->descent + (VMenuPad << 1);
    menu->height = menu->iheight * count;
    menu->width = maxwidth + (HMenuPad << 1);
    menu->image = NULL;

    /*
     * Create the menu window.
     */
    menu->w = XCreateSimpleWindow(dpy, RootWindow(dpy, scr),
                            0, 0,
                            menu->width,
                            menu->height,
                            MBorderWidth,
                            MBorder, MBackground);
    if (menu->w == NULL) Error("InitMenu -> Couldn't create menu window");

    /*
     * Store the window name.
     */
    XStoreName(dpy, menu->w, menu->name);

    /*
     * Define a cursor for the window.
     */
    XDefineCursor(dpy, menu->w, MenuCursor);

    /*
     * We want enter, leave, and mouse motion events for menus.
     */
    XSelectInput(dpy, menu->w, 
    	(EnterWindowMask | LeaveWindowMask | PointerMotionMask));
}

/*
 * Map a menu.
 */
MapMenu(menu, x, y)
MenuInfo *menu;
int x, y;
{
    int item;
    Window w;
    MenuLine *ml;
    XWindowChanges values;

    w = menu->w;

    /*
     * Move the menu into place, normalizing the coordinates, if necessary;
     * then map it.
     */
    x -= (menu->width >> 1);
    if (x < 0) x = 0;
    else if (x + menu->width >= ScreenWidth)
        x = ScreenWidth - menu->width - (MBorderWidth << 1);
    if (y < 0) y = 0;
    else if (y + menu->height >= ScreenHeight)
        y = ScreenHeight - menu->height - (MBorderWidth << 1);
    values.x = x;
    values.y = y;
    values.stack_mode = Above;
    XConfigureWindow(dpy, w, CWX|CWY|CWStackMode, &values);

    /*
     * Map the window and draw the text items.
     */
    XMapWindow(dpy, w);
    DisplayLine(w, 0, menu->width, menu->iheight, menu->name,
                menu->bg.pixel, menu->fg.pixel, 0);

    if (alternateGC) {
        XFillRectangle(dpy, menu->w, MenuInvGC, 0, 0,
		       menu->width, menu->iheight);
        XDrawRectangle(dpy, menu->w, MenuInvGC, 1, 1,
		       menu->width - 3, menu->iheight - 3);
    } else {
        XSetForeground(dpy, MenuGC, menu->bg.pixel );
        XDrawRectangle(dpy, menu->w, MenuGC, 1, 1, menu->width - 3, 
		       menu->iheight - 3);
    }

    item = menu->iheight;
    for(ml = menu->line; ml; ml = ml->next) {
        DisplayLine(w, item, menu->width, menu->iheight, ml->name,
                    ml->fg.pixel, ml->bg.pixel, 0);
        item += menu->iheight;
    }

    /*
     * Position the mouse cursor in the menu header (or in the first item
     * if "autoselect" is set).
     */

    XFlush(dpy);
}

/*
 * Unmap a menu, restoring the contents of the screen underneath
 * if necessary. (Restore portion is a future.)
 */
UnmapMenu(menu)
MenuInfo *menu;
{
    /*
     * Unmap and flush.
     */
    XUnmapWindow(dpy, menu->w);
    XFlush(dpy);
}

/*
 * Get the context for invoking a window manager function.
 */
GetContext(w, x, y)
Window *w;
int *x, *y;
{
    XEvent button_event;  /* Button input event. */

    while (TRUE) {

        /*
         * Get the next mouse button event.  Spin our wheels until
         * a button event is returned (ie. GetButton == TRUE).
         * Note that mouse events within an icon window are handled
         * in the "GetButton" function or by the icon's owner if
         * it is not uwm.
         */
        if (!GetButton(&button_event)) continue;

        /*
         * If the button event received is not a ButtonPress event
         * then continue until we find one.
         */
        if (button_event.type != ButtonPress) continue;

        /*
         * Okay, determine the event window and mouse coordinates.
         */
        status = XTranslateCoordinates(dpy, 
				    RootWindow(dpy, scr), 
				    RootWindow(dpy, scr),
                                    ((XButtonPressedEvent *)&button_event)->x, 
                                    ((XButtonPressedEvent *)&button_event)->y, 
                                    x, y,
                                    w);

        if (status == FAILURE) continue;

        if (*w == 0)
            *w = RootWindow(dpy, scr);

        return;
    }
}

/*
 * Get the color cells for a menu.  This function is slightly brain-damaged
 * in that once MaxColors <= 1, then it refuses to even try to allocate any
 * more colors, even though the colors may have already been allocated.  It
 * probably ought to be done right someday.
 */
GetMenuColors(menu)
MenuInfo *menu;
{
    register MenuLine *ml;		/* Menu lines pointer. */

    /*
     * If we have more than 2 colors available, then attempt to get
     * the color map entries requested by the user.
     * Otherwise, default to standard black and white.
     */
    alternateGC = TRUE;			/* assume the best */
    if (DisplayCells(dpy, scr) > 2) {
        /*
         * Get the menu header colors first.
         */
        if (!(menu->foreground && menu->background && MaxColors > 1 &&
              XParseColor(dpy, DefaultColormap(dpy, scr), menu->foreground, &menu->fg) &&
              XAllocColor(dpy, DefaultColormap(dpy, scr), &menu->fg) &&
              XParseColor(dpy, DefaultColormap(dpy, scr), menu->background, &menu->bg) &&
              XAllocColor(dpy, DefaultColormap(dpy, scr), &menu->bg))) {
            menu->fg.pixel = MTextForground;
            menu->bg.pixel = MTextBackground;
        } else {
            AdjustMaxColors(menu->fg.pixel);
            AdjustMaxColors(menu->bg.pixel);
	    alternateGC = FALSE;
        }

        /*
         * Get the menu highlight colors.
         */
        if (!(menu->fghighlight && menu->bghighlight && MaxColors > 1 &&
              XParseColor(
	        dpy, DefaultColormap(dpy, scr), menu->fghighlight, &menu->hlfg) &&
              XAllocColor(dpy, DefaultColormap(dpy, scr), &menu->hlfg) &&
              XParseColor(
	        dpy, DefaultColormap(dpy, scr), menu->bghighlight, &menu->hlbg) &&
              XAllocColor(dpy, DefaultColormap(dpy, scr), &menu->hlbg))) {
            menu->hlfg.pixel = MTextBackground;
            menu->hlbg.pixel = MTextForground;
        } else {
            AdjustMaxColors(menu->hlfg.pixel);
            AdjustMaxColors(menu->hlbg.pixel);
	    alternateGC = FALSE;
        }

        /*
         * Get the menu item colors.
         */
        for(ml = menu->line; ml; ml = ml->next) {
            if (!(ml->foreground && ml->background && MaxColors > 1 &&
                  XParseColor(dpy, DefaultColormap(dpy, scr), ml->foreground, &ml->fg) &&
                  XAllocColor(dpy, DefaultColormap(dpy, scr), &ml->fg) &&
                  XParseColor(dpy, DefaultColormap(dpy, scr), ml->background, &ml->bg) &&
                  XAllocColor(dpy, DefaultColormap(dpy, scr), &ml->bg))) {
                ml->fg.pixel = MTextForground;
                ml->bg.pixel = MTextBackground;
            } else {
                AdjustMaxColors(ml->fg.pixel);
                AdjustMaxColors(ml->bg.pixel);
		alternateGC = FALSE;
            }
        }

    } else {

        /*
         * Only 2 colors available, so default to standard black and white.
         */
        menu->fg.pixel = MTextForground;
        menu->bg.pixel = MTextBackground;
        menu->hlfg.pixel = MTextBackground;
        menu->hlbg.pixel = MTextForground;
        for(ml = menu->line; ml; ml = ml->next) {
            ml->fg.pixel = MTextForground;
            ml->bg.pixel = MTextBackground;
        }
    }
}

/*
 * Decrement "MaxColors" if this pixel value has never been used in a
 * menu before.
 */
AdjustMaxColors(pixel)
int pixel;
{
    register MenuLink *mptr;
    register MenuLine *lptr;
    int count = 0;

    for(mptr = Menus; mptr; mptr = mptr->next) {
        if (mptr->menu->fg.pixel == pixel) ++count;
        if (mptr->menu->bg.pixel == pixel) ++count;
        if (mptr->menu->hlfg.pixel == pixel) ++count;
        if (mptr->menu->hlbg.pixel == pixel) ++count;
        for(lptr = mptr->menu->line; lptr; lptr = lptr->next) {
            if (lptr->fg.pixel == pixel) ++count;
            if (lptr->bg.pixel == pixel) ++count;
        }
        if (count > 1) return;
    }
    --MaxColors;
}


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.