home *** CD-ROM | disk | FTP | other *** search
- /* X11menus - Low Level Menu Objects for X11 */
- /* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney */
- /* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz */
- /* You may give out copies of this software; for conditions see the */
- /* file COPYING included with this distribution. */
-
- /***********************************************************************/
- /** **/
- /** General Includes and Definitions **/
- /** **/
- /***********************************************************************/
-
- #include <X11/Xlib.h>
- #include <X11/Xutil.h>
- #include <X11/Xos.h>
- #include <X11/cursorfont.h>
-
- extern Display *StX11Display();
-
- #include "xlisp.h"
- #include "stmem.h"
-
- #define nil 0L
-
- extern LVAL slot_value();
- extern caddr_t get_menu_address();
-
- extern LVAL s_items, s_title, s_enabled, s_mark, sk_update;
-
- typedef struct {
- unsigned char *title;
- int len, enabled, checked;
- Window pane;
- } ItemEntry;
-
- typedef struct {
- unsigned long fore, back;
- } ColorPair;
-
- /***********************************************************************/
- /** **/
- /** Static Global Variables **/
- /** **/
- /***********************************************************************/
-
- /* gray stipple pattern bitmap data for disabled items */
- #define gray_width 16
- #define gray_height 16
- static char gray_bits[] = {
- 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
- 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
- 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa};
- static Pixmap GrayPM;
-
- /* check mark bitmap data */
- #define check_offset 2
- #define check_width 9
- #define check_height 8
- static char check_bits[] = {
- 0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x60, 0x00,
- 0x31, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04, 0x00
- };
- static Pixmap CheckPM;
-
- /* configuration parameters - should be set using the defaults database */
- static char *MenuFontName = "9x15";
- static XFontStruct *MenuFont;
- static unsigned long BorderColor;
- static ColorPair MenuC, MenuItemC, MenuTitleC;
- static unsigned int border_width, item_border_width;
- static int show_menu_title;
-
- /* graphics contexts used for menu items */
- static GC NormalGC, ReversedGC, TitleGC, GrayGC;
-
- /* current menu item's window pane - used in event handling */
- static Window current_item;
-
- static Cursor MenuCursor;
-
- /***********************************************************************/
- /** **/
- /** Menu System Initialization and Cleanup **/
- /** **/
- /***********************************************************************/
-
- StX11InitMenus()
- {
- Display *dpy = StX11Display();
- int screen = StX11Screen();
- char *option;
-
- border_width = 1;
- item_border_width = 0;
-
- option = (char *) XGetDefault(dpy, "xlisp", "menu.titles");
- if (option == NULL) option = "off";
- show_menu_title = is_option_on(option);
-
- MenuC.fore = BlackPixel(dpy, screen);
- MenuC.back = WhitePixel(dpy, screen);
- MenuItemC.fore = BlackPixel(dpy, screen);
- MenuItemC.back = WhitePixel(dpy, screen);
- MenuTitleC.fore = WhitePixel(dpy, screen);
- MenuTitleC.back = BlackPixel(dpy, screen);
- BorderColor = BlackPixel(dpy, screen);
-
- GrayPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
- gray_bits, gray_width, gray_height);
- CheckPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
- check_bits, check_width, check_height);
-
- LoadMenuFont();
- MakeMenuGC();
-
- MenuCursor = XCreateFontCursor(dpy, XC_sb_left_arrow);
- }
-
- static LoadMenuFont()
- {
- Display *dpy = StX11Display();
- char *font;
-
- font = (char *) XGetDefault(dpy, "xlisp", "menu.font");
- if (font == NULL) font = MenuFontName;
- if ((MenuFont = XLoadQueryFont(dpy, font)) == NULL) {
- fprintf(stderr, "xlisp: Can't open %s font\n", font);
- if ((MenuFont = XLoadQueryFont(dpy, MenuFontName)) == NULL) {
- fprintf(stderr, "xlisp: Can't open %s font\n", MenuFontName);
- exit(-1);
- }
- }
- }
-
- static MakeMenuGC()
- {
- unsigned long valuemask;
- XGCValues values;
- Display *dpy = StX11Display();
- int screen = StX11Screen();
-
- valuemask = 0; /* ignore XGCValues and use defaults */
- NormalGC = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
- XSetFont(dpy, NormalGC, MenuFont->fid);
- XSetForeground(dpy, NormalGC, MenuItemC.fore);
- XSetBackground(dpy, NormalGC, MenuItemC.back);
-
- valuemask = 0; /* ignore XGCValues and use defaults */
- ReversedGC = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
- XSetFont(dpy, ReversedGC, MenuFont->fid);
- XSetForeground(dpy, ReversedGC, MenuItemC.back);
- XSetBackground(dpy, ReversedGC, MenuItemC.fore);
-
- valuemask = GCStipple+GCFillStyle;
- values.stipple = GrayPM;
- values.fill_style = FillStippled;
- GrayGC = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
- XSetFont(dpy, GrayGC, MenuFont->fid);
- XSetForeground(dpy, GrayGC, MenuItemC.fore);
- XSetBackground(dpy, GrayGC, MenuItemC.back);
-
- valuemask = 0; /* ignore XGCValues and use defaults */
- TitleGC = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
- XSetFont(dpy, TitleGC, MenuFont->fid);
- XSetForeground(dpy, TitleGC, MenuTitleC.fore);
- XSetBackground(dpy, TitleGC, MenuTitleC.back);
- }
-
- StX11FinishMenus()
- {
- Display *dpy = StX11Display();
-
- XUnloadFont(dpy, MenuFont->fid);
- XFreeGC(dpy, NormalGC);
- XFreeGC(dpy, ReversedGC);
- XFreeGC(dpy, GrayGC);
- XFreeGC(dpy, TitleGC);
- XFreePixmap(dpy, GrayPM);
- XFreePixmap(dpy, CheckPM);
- XFreeCursor(dpy, MenuCursor);
- }
-
- /***********************************************************************/
- /** **/
- /** MENU-PROTO Definitions **/
- /** **/
- /***********************************************************************/
-
- StMObInstalled(m) LVAL m; { return(FALSE); }
-
- /***********************************************************************/
- /** **/
- /** MENU-PROTO Definitions **/
- /** **/
- /***********************************************************************/
-
- FORWARD char *get_item_string();
-
- /***********************************************************************/
- /** **/
- /** Support Function **/
- /** **/
- /***********************************************************************/
-
- caddr_t get_hardware_menu(menu)
- LVAL menu;
- {
- return((StMObAllocated(menu)) ? get_menu_address(menu) : NULL);
- }
-
- /***********************************************************************/
- /** **/
- /** Public Menu Functions **/
- /** **/
- /***********************************************************************/
-
- /* unused routines in popup system */
- StMObDisposeMach () {}
- StMObAllocateMach () {}
- StMObDeleteItem () {}
- StMObSetItemProp () {}
- StMObAppendItems () {}
- StMObRemove () {}
- StMObEnable () {}
- StMObInstall () {}
-
- StMObPopup (menu,x, y, window)
- LVAL menu, window;
- int x, y;
- {
- Window win, w;
- unsigned int width, height;
- XSetWindowAttributes setwinattr;
- unsigned long valuemask;
- XEvent report;
- int done = FALSE;
- LVAL items;
- int i, n, pane_height, left, top;
- ItemEntry *entries;
- int item_selected;
- Display *dpy = StX11Display();
- int screen = StX11Screen();
-
- /* adjust coordinates to the root window */
- if (window != NIL && (w = GETWINDOWADDRESS(window)) != nil) {
- StWGetLocation(w, &left, &top, FALSE);
- x += left;
- y += top;
- }
-
- /* have the menu update itself */
- send_message(menu, sk_update);
-
- /* get the item list and make sure there are some items to use */
- items = slot_value(menu, s_items);
- n = (consp(items)) ? llength(items) : 0;
- if (n == 0) return(0);
- if (show_menu_title) n++;
-
- /* set up the internal item entry array */
- entries = (ItemEntry *) StCalloc(n, sizeof(ItemEntry));
- get_menu_size(menu, items, entries, &width, &height);
-
- /* create opaque menu window */
- x = max(0, min(x, DisplayWidth(dpy, screen) - width));
- y = max(0, min(y, DisplayHeight(dpy, screen) - height));
- win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen),
- x, y, width, height, border_width,
- BorderColor, MenuC.back);
-
- /* set the override_redirect and save_under attributes for a menu */
- valuemask = CWOverrideRedirect | CWSaveUnder;
- setwinattr.override_redirect = TRUE;
- setwinattr.save_under = TRUE;
- XChangeWindowAttributes(dpy, win, valuemask, &setwinattr);
- XDefineCursor(dpy, win, MenuCursor);
-
- /* create the title and item windows */
- pane_height = height / n;
- for (i = 0; i < n; i++) {
- entries[i].pane = XCreateSimpleWindow(dpy, win, 0, pane_height * i,
- width, pane_height,
- item_border_width,
- BorderColor, MenuItemC.back);
- XSelectInput(dpy, entries[i].pane,
- ExposureMask | EnterWindowMask | LeaveWindowMask);
- }
-
- /* Display (map) the windows */
- XMapSubwindows(dpy, win);
- XMapWindow(dpy, win);
-
- /* grap the pointer */
- StX11ReleaseButton();
- XGrabPointer(dpy, win, TRUE,
- ButtonReleaseMask,
- GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
-
- /* Loop until button is released, examining each event */
- current_item = nil;
- while (! done) {
- XNextEvent(dpy, &report);
- switch (report.type) {
- case Expose:
- draw_pane(n, entries, report.xexpose.window);
- break;
- case ButtonPress:
- break;
- case ButtonRelease:
- done = TRUE;
- break;
- case EnterNotify:
- current_item = report.xcrossing.window;
- draw_pane(n, entries, current_item);
- break;
- case LeaveNotify:
- current_item = nil;
- draw_pane(n, entries, report.xcrossing.window);
- break;
- default:
- break;
- }
- }
-
- /* find the item selected */
- for (item_selected = 0, i = 0; i < n; i++) {
- if (current_item == entries[i].pane) {
- if (entries[i].enabled) item_selected = (show_menu_title) ? i : i + 1;
- break;
- }
- }
-
- /* clean up */
- XDestroyWindow(dpy, win);
- XFlush(dpy);
- StFree(entries);
- entries = nil;
-
- return(item_selected);
- }
-
- static get_menu_size(menu, items, entries, pwidth, pheight)
- LVAL menu, items;
- ItemEntry *entries;
- unsigned int *pwidth, *pheight;
- {
- int font_height, margin, text_width, len;
- LVAL title;
- unsigned char *str;
-
- font_height = MenuFont->max_bounds.ascent
- + MenuFont->max_bounds.descent;
- margin = MenuFont->max_bounds.descent / 2;
-
- if (show_menu_title) {
- title = slot_value(menu, s_title);
- if (! stringp(title)) xlerror("not a string", title);
- str = getstring(title);
- len = strlen(str);
- text_width = XTextWidth(MenuFont, str, len);
- entries->title = str;
- entries->len = len;
- entries->enabled = FALSE;
- entries->checked = FALSE;
- *pwidth = text_width;
- *pheight = font_height + 2 * margin;
- entries++;
- }
- else {
- *pwidth = 0;
- *pheight = 0;
- }
- for (; consp(items); items = cdr(items), entries++) {
- *pheight += font_height + 2 * margin;
- title = slot_value(car(items), s_title);
- if (! stringp(title)) xlerror("not a string", title);
- str = getstring(title);
- len = strlen(str);
- text_width = XTextWidth(MenuFont, str, len);
- if (*pwidth < text_width) *pwidth = text_width;
- entries->title = str;
- entries->len = len;
- entries->enabled = (slot_value(car(items), s_enabled) != NIL);
- entries->checked = (slot_value(car(items), s_mark) != NIL);
- }
- *pwidth += margin + check_width + 2 * check_offset;
- }
-
- draw_pane(n, entries, win)
- int n;
- ItemEntry *entries;
- Window win;
- {
- int margin, x, y, i;
- GC gc;
- Display *dpy = StX11Display();
-
- margin = MenuFont->max_bounds.descent / 2;
-
- x = check_width + 2 * check_offset;
- y = MenuFont->max_bounds.ascent + margin;
-
- for (i = 0; i < n; i++) {
- if (entries[i].pane == win) {
- if (show_menu_title && i == 0) {
- XSetWindowBackground(dpy, win, MenuTitleC.back);
- gc = TitleGC;
- }
- else if (win == current_item && entries[i].enabled) {
- XSetWindowBackground(dpy, win, MenuItemC.fore);
- gc = ReversedGC;
- }
- else {
- XSetWindowBackground(dpy, win, MenuItemC.back);
- gc = (entries[i].enabled) ? NormalGC : GrayGC;
- }
- XClearWindow(dpy, win);
- if (entries[i].checked)
- XCopyPlane(dpy, CheckPM, win, gc,
- 0, 0, check_width, check_height,
- check_offset, y - check_height, 1);
- XDrawString(dpy, win, gc, x, y, entries[i].title, entries[i].len);
- break;
- }
- }
- }
-
- #ifdef TODO
- special dividing lines
- use resource database to get defaults
- #endif TODO
-