home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d3xx / d386 / xlispstat.lha / XLispStat / src3.lzh / UNIX / X11menus.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-30  |  13.2 KB  |  432 lines

  1. /* X11menus - Low Level Menu Objects for X11                           */
  2. /* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney                  */
  3. /* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz    */
  4. /* You may give out copies of this software; for conditions see the    */
  5. /* file COPYING included with this distribution.                       */
  6.  
  7. /***********************************************************************/
  8. /**                                                                   **/
  9. /**                    General Includes and Definitions               **/
  10. /**                                                                   **/
  11. /***********************************************************************/
  12.  
  13. #include <X11/Xlib.h>
  14. #include <X11/Xutil.h>
  15. #include <X11/Xos.h>
  16. #include <X11/cursorfont.h>
  17.  
  18. extern Display *StX11Display();
  19.  
  20. #include "xlisp.h"
  21. #include "stmem.h"
  22.  
  23. #define nil 0L
  24.  
  25. extern LVAL slot_value();
  26. extern caddr_t get_menu_address();
  27.  
  28. extern LVAL s_items, s_title, s_enabled, s_mark, sk_update;
  29.  
  30. typedef struct {
  31.   unsigned char *title;
  32.   int len, enabled, checked;
  33.   Window pane;
  34. } ItemEntry;
  35.  
  36. typedef struct {
  37.   unsigned long fore, back;
  38. } ColorPair;
  39.  
  40. /***********************************************************************/
  41. /**                                                                   **/
  42. /**                      Static Global Variables                      **/
  43. /**                                                                   **/
  44. /***********************************************************************/
  45.  
  46. /* gray stipple pattern bitmap data for disabled items */
  47. #define gray_width 16
  48. #define gray_height 16
  49. static char gray_bits[] = {
  50.    0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
  51.    0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
  52.    0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa};
  53. static Pixmap GrayPM;
  54.  
  55. /* check mark bitmap data */
  56. #define check_offset 2
  57. #define check_width 9
  58. #define check_height 8
  59. static char check_bits[] = {
  60.   0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x60, 0x00,
  61.   0x31, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04, 0x00
  62. };
  63. static Pixmap CheckPM;
  64.  
  65. /* configuration parameters - should be set using the defaults database */
  66. static char *MenuFontName = "9x15";
  67. static XFontStruct *MenuFont;
  68. static unsigned long BorderColor;
  69. static ColorPair MenuC, MenuItemC, MenuTitleC;
  70. static unsigned int border_width, item_border_width;
  71. static int show_menu_title;
  72.  
  73. /* graphics contexts used for menu items */
  74. static GC NormalGC, ReversedGC, TitleGC, GrayGC;
  75.  
  76. /* current menu item's window pane - used in event handling */
  77. static Window current_item;
  78.  
  79. static Cursor MenuCursor;
  80.  
  81. /***********************************************************************/
  82. /**                                                                   **/
  83. /**               Menu System Initialization and Cleanup              **/
  84. /**                                                                   **/
  85. /***********************************************************************/
  86.  
  87. StX11InitMenus()
  88. {
  89.   Display *dpy = StX11Display();
  90.   int screen = StX11Screen();
  91.   char *option;
  92.  
  93.   border_width = 1;
  94.   item_border_width = 0;
  95.  
  96.   option = (char *) XGetDefault(dpy, "xlisp", "menu.titles");
  97.   if (option == NULL) option = "off";
  98.   show_menu_title = is_option_on(option);
  99.  
  100.   MenuC.fore = BlackPixel(dpy, screen);
  101.   MenuC.back = WhitePixel(dpy, screen);
  102.   MenuItemC.fore = BlackPixel(dpy, screen);
  103.   MenuItemC.back = WhitePixel(dpy, screen);
  104.   MenuTitleC.fore = WhitePixel(dpy, screen);
  105.   MenuTitleC.back = BlackPixel(dpy, screen);
  106.   BorderColor = BlackPixel(dpy, screen);
  107.   
  108.   GrayPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen), 
  109.                  gray_bits, gray_width, gray_height);
  110.   CheckPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen), 
  111.                   check_bits, check_width, check_height);
  112.  
  113.   LoadMenuFont();
  114.   MakeMenuGC();
  115.  
  116.   MenuCursor = XCreateFontCursor(dpy, XC_sb_left_arrow);
  117. }
  118.  
  119. static LoadMenuFont()
  120. {
  121.   Display *dpy = StX11Display();
  122.   char *font;
  123.  
  124.   font = (char *) XGetDefault(dpy, "xlisp", "menu.font");
  125.   if (font == NULL) font = MenuFontName;
  126.   if ((MenuFont = XLoadQueryFont(dpy, font)) == NULL) {
  127.     fprintf(stderr, "xlisp: Can't open %s font\n", font);
  128.     if ((MenuFont = XLoadQueryFont(dpy, MenuFontName)) == NULL) {
  129.       fprintf(stderr, "xlisp: Can't open %s font\n", MenuFontName);
  130.       exit(-1);
  131.     }
  132.   }
  133. }
  134.  
  135. static MakeMenuGC()
  136. {
  137.   unsigned long valuemask;
  138.   XGCValues values;
  139.   Display *dpy = StX11Display();
  140.   int screen = StX11Screen();
  141.  
  142.   valuemask = 0; /* ignore XGCValues and use defaults */
  143.   NormalGC = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
  144.   XSetFont(dpy, NormalGC, MenuFont->fid);
  145.   XSetForeground(dpy, NormalGC, MenuItemC.fore);
  146.   XSetBackground(dpy, NormalGC, MenuItemC.back);
  147.  
  148.   valuemask = 0; /* ignore XGCValues and use defaults */
  149.   ReversedGC = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
  150.   XSetFont(dpy, ReversedGC, MenuFont->fid);
  151.   XSetForeground(dpy, ReversedGC, MenuItemC.back);
  152.   XSetBackground(dpy, ReversedGC, MenuItemC.fore);
  153.  
  154.   valuemask = GCStipple+GCFillStyle;
  155.   values.stipple = GrayPM;
  156.   values.fill_style = FillStippled;
  157.   GrayGC = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
  158.   XSetFont(dpy, GrayGC, MenuFont->fid);
  159.   XSetForeground(dpy, GrayGC, MenuItemC.fore);
  160.   XSetBackground(dpy, GrayGC, MenuItemC.back);
  161.  
  162.   valuemask = 0; /* ignore XGCValues and use defaults */
  163.   TitleGC = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
  164.   XSetFont(dpy, TitleGC, MenuFont->fid);
  165.   XSetForeground(dpy, TitleGC, MenuTitleC.fore);
  166.   XSetBackground(dpy, TitleGC, MenuTitleC.back);
  167. }
  168.  
  169. StX11FinishMenus()
  170. {
  171.   Display *dpy = StX11Display();
  172.  
  173.   XUnloadFont(dpy, MenuFont->fid);
  174.   XFreeGC(dpy, NormalGC);
  175.   XFreeGC(dpy, ReversedGC);
  176.   XFreeGC(dpy, GrayGC);
  177.   XFreeGC(dpy, TitleGC);
  178.   XFreePixmap(dpy, GrayPM);
  179.   XFreePixmap(dpy, CheckPM);
  180.   XFreeCursor(dpy, MenuCursor);
  181. }
  182.  
  183. /***********************************************************************/
  184. /**                                                                   **/
  185. /**                       MENU-PROTO Definitions                      **/
  186. /**                                                                   **/
  187. /***********************************************************************/
  188.  
  189. StMObInstalled(m) LVAL m; { return(FALSE); }
  190.  
  191. /***********************************************************************/
  192. /**                                                                   **/
  193. /**                       MENU-PROTO Definitions                      **/
  194. /**                                                                   **/
  195. /***********************************************************************/
  196.  
  197. FORWARD char *get_item_string();
  198.  
  199. /***********************************************************************/
  200. /**                                                                   **/
  201. /**                        Support Function                           **/
  202. /**                                                                   **/
  203. /***********************************************************************/
  204.  
  205. caddr_t get_hardware_menu(menu)
  206.     LVAL menu;
  207. {
  208.   return((StMObAllocated(menu)) ? get_menu_address(menu) : NULL);
  209. }
  210.  
  211. /***********************************************************************/
  212. /**                                                                   **/
  213. /**                      Public Menu Functions                        **/
  214. /**                                                                   **/
  215. /***********************************************************************/
  216.  
  217. /* unused routines in popup system */
  218. StMObDisposeMach () {}
  219. StMObAllocateMach () {}
  220. StMObDeleteItem () {}
  221. StMObSetItemProp () {}
  222. StMObAppendItems () {}
  223. StMObRemove () {}
  224. StMObEnable () {}
  225. StMObInstall () {}
  226.  
  227. StMObPopup (menu,x, y, window)
  228.      LVAL menu, window;
  229.      int x, y;
  230. {
  231.   Window win, w;
  232.   unsigned int width, height;
  233.   XSetWindowAttributes setwinattr;
  234.   unsigned long valuemask;
  235.   XEvent report;
  236.   int done = FALSE;
  237.   LVAL items;
  238.   int i, n, pane_height, left, top;
  239.   ItemEntry *entries;
  240.   int item_selected;
  241.   Display *dpy = StX11Display();
  242.   int screen = StX11Screen();
  243.  
  244.   /* adjust coordinates to the root window */
  245.   if (window != NIL && (w = GETWINDOWADDRESS(window)) != nil) {
  246.     StWGetLocation(w, &left, &top, FALSE);
  247.     x += left;
  248.     y += top;
  249.   }
  250.  
  251.   /* have the menu update itself */
  252.   send_message(menu, sk_update);
  253.  
  254.   /* get the item list and make sure there are some items to use */
  255.   items = slot_value(menu, s_items);
  256.   n = (consp(items)) ? llength(items) : 0;
  257.   if (n == 0) return(0);
  258.   if (show_menu_title) n++;
  259.  
  260.   /* set up the internal item entry array */
  261.   entries = (ItemEntry *) StCalloc(n, sizeof(ItemEntry));
  262.   get_menu_size(menu, items, entries, &width, &height);
  263.  
  264.   /* create opaque menu window */
  265.   x = max(0, min(x, DisplayWidth(dpy, screen) - width));
  266.   y = max(0, min(y, DisplayHeight(dpy, screen) - height));
  267.   win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen),
  268.                 x, y, width, height, border_width,
  269.                 BorderColor, MenuC.back);
  270.  
  271.   /* set the override_redirect and save_under attributes for a menu */
  272.   valuemask = CWOverrideRedirect | CWSaveUnder;
  273.   setwinattr.override_redirect = TRUE;
  274.   setwinattr.save_under = TRUE;
  275.   XChangeWindowAttributes(dpy, win, valuemask, &setwinattr);
  276.   XDefineCursor(dpy, win, MenuCursor);
  277.   
  278.   /* create the title and item windows */
  279.   pane_height = height / n;
  280.   for (i = 0; i < n; i++) {
  281.     entries[i].pane = XCreateSimpleWindow(dpy, win, 0, pane_height * i, 
  282.                       width, pane_height,
  283.                       item_border_width, 
  284.                       BorderColor, MenuItemC.back);
  285.     XSelectInput(dpy, entries[i].pane, 
  286.          ExposureMask | EnterWindowMask | LeaveWindowMask);
  287.   }
  288.                       
  289.   /* Display (map) the windows */
  290.   XMapSubwindows(dpy, win);
  291.   XMapWindow(dpy, win);
  292.  
  293.   /* grap the pointer */
  294.   StX11ReleaseButton();
  295.   XGrabPointer(dpy, win, TRUE, 
  296.            ButtonReleaseMask,
  297.            GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
  298.  
  299.   /* Loop until button is released, examining each event */
  300.   current_item = nil;
  301.   while (! done) {
  302.     XNextEvent(dpy, &report);
  303.     switch (report.type) {
  304.     case Expose:
  305.       draw_pane(n, entries, report.xexpose.window);
  306.       break;
  307.     case ButtonPress:
  308.       break;
  309.     case ButtonRelease:
  310.       done = TRUE;
  311.       break;
  312.     case EnterNotify:
  313.       current_item = report.xcrossing.window;
  314.       draw_pane(n, entries, current_item);
  315.       break;
  316.     case LeaveNotify:
  317.       current_item = nil;
  318.       draw_pane(n, entries, report.xcrossing.window);
  319.       break;
  320.     default:
  321.       break;
  322.     }
  323.   }
  324.  
  325.   /* find the item selected */
  326.   for (item_selected = 0, i = 0; i < n; i++) {
  327.     if (current_item == entries[i].pane) {
  328.       if (entries[i].enabled) item_selected =  (show_menu_title) ? i : i + 1;
  329.       break;
  330.     }
  331.   }
  332.  
  333.   /* clean up */
  334.   XDestroyWindow(dpy, win);
  335.   XFlush(dpy);
  336.   StFree(entries);
  337.   entries = nil;
  338.  
  339.   return(item_selected);
  340. }
  341.  
  342. static get_menu_size(menu, items, entries, pwidth, pheight)
  343.      LVAL menu, items;
  344.      ItemEntry *entries;
  345.      unsigned int *pwidth, *pheight;
  346. {
  347.   int font_height, margin, text_width, len;
  348.   LVAL title;
  349.   unsigned char *str;
  350.  
  351.   font_height = MenuFont->max_bounds.ascent
  352.               + MenuFont->max_bounds.descent;
  353.   margin = MenuFont->max_bounds.descent / 2;
  354.   
  355.   if (show_menu_title) {
  356.     title = slot_value(menu, s_title);
  357.     if (! stringp(title)) xlerror("not a string", title);
  358.     str = getstring(title);
  359.     len = strlen(str);
  360.     text_width = XTextWidth(MenuFont, str, len);
  361.     entries->title = str;
  362.     entries->len = len;
  363.     entries->enabled = FALSE;
  364.     entries->checked = FALSE;
  365.     *pwidth = text_width;
  366.     *pheight = font_height + 2 * margin;
  367.     entries++;
  368.   }
  369.   else {
  370.     *pwidth = 0;
  371.     *pheight = 0;
  372.   }
  373.   for (; consp(items); items = cdr(items), entries++) {
  374.     *pheight += font_height + 2 * margin;
  375.     title = slot_value(car(items), s_title);
  376.     if (! stringp(title)) xlerror("not a string", title);
  377.     str = getstring(title);
  378.     len = strlen(str);
  379.     text_width = XTextWidth(MenuFont, str, len);
  380.     if (*pwidth < text_width) *pwidth = text_width;
  381.     entries->title = str;
  382.     entries->len = len;
  383.     entries->enabled = (slot_value(car(items), s_enabled) != NIL);
  384.     entries->checked = (slot_value(car(items), s_mark) != NIL);
  385.   }
  386.   *pwidth += margin + check_width + 2 * check_offset;
  387. }
  388.  
  389. draw_pane(n, entries, win)
  390.      int n;
  391.      ItemEntry *entries;
  392.      Window win;
  393. {
  394.   int margin, x, y, i;
  395.   GC gc;
  396.   Display *dpy = StX11Display();
  397.  
  398.   margin = MenuFont->max_bounds.descent / 2;
  399.  
  400.   x = check_width + 2 * check_offset;
  401.   y = MenuFont->max_bounds.ascent + margin; 
  402.   
  403.   for (i = 0; i < n; i++) {
  404.     if (entries[i].pane == win) {
  405.       if (show_menu_title && i == 0) {
  406.     XSetWindowBackground(dpy, win, MenuTitleC.back);
  407.     gc = TitleGC;
  408.       }
  409.       else if (win == current_item && entries[i].enabled) {
  410.     XSetWindowBackground(dpy, win, MenuItemC.fore);
  411.     gc = ReversedGC;
  412.       }
  413.       else {
  414.     XSetWindowBackground(dpy, win, MenuItemC.back);
  415.     gc = (entries[i].enabled) ? NormalGC : GrayGC;
  416.       }
  417.       XClearWindow(dpy, win);
  418.       if (entries[i].checked)
  419.     XCopyPlane(dpy, CheckPM, win, gc, 
  420.            0, 0, check_width, check_height,
  421.            check_offset, y - check_height, 1);
  422.       XDrawString(dpy, win, gc, x, y, entries[i].title, entries[i].len);    
  423.       break;
  424.     }
  425.   }
  426. }
  427.  
  428. #ifdef TODO
  429.   special dividing lines
  430.   use resource database to get defaults
  431. #endif TODO
  432.