home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume15 / twm / part02 / menus.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-06-12  |  13.6 KB  |  606 lines

  1. /*****************************************************************************/
  2. /**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
  3. /**                          Salt Lake City, Utah                           **/
  4. /**                                                                         **/
  5. /**                           All Rights Reserved                           **/
  6. /**                                                                         **/
  7. /**    Permission to use, copy, modify, and distribute this software and    **/
  8. /**    its documentation  for  any  purpose  and  without  fee is hereby    **/
  9. /**    granted, provided that the above copyright notice appear  in  all    **/
  10. /**    copies and that both  that  copyright  notice  and  this  permis-    **/
  11. /**    sion  notice appear in supporting  documentation,  and  that  the    **/
  12. /**    name  of Evans & Sutherland  not be used in advertising or publi-    **/
  13. /**    city pertaining to distribution  of the software without  specif-    **/
  14. /**    ic, written prior permission.                                        **/
  15. /**                                                                         **/
  16. /**    EVANS  & SUTHERLAND  DISCLAIMS  ALL  WARRANTIES  WITH  REGARD  TO    **/
  17. /**    THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILI-    **/
  18. /**    TY AND FITNESS, IN NO EVENT SHALL EVANS &  SUTHERLAND  BE  LIABLE    **/
  19. /**    FOR  ANY  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY  DAM-    **/
  20. /**    AGES  WHATSOEVER RESULTING FROM  LOSS OF USE,  DATA  OR  PROFITS,    **/
  21. /**    WHETHER   IN  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS    **/
  22. /**    ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE  OR PER-    **/
  23. /**    FORMANCE OF THIS SOFTWARE.                                           **/
  24. /*****************************************************************************/
  25.  
  26. /***********************************************************************
  27.  *
  28.  * $Header: menus.c,v 1.20 88/04/15 07:09:54 tlastran Exp $
  29.  *
  30.  * twm menu code
  31.  *
  32.  * 17-Nov-87 Thomas E. LaStrange        File created
  33.  *
  34.  ***********************************************************************/
  35.  
  36. #ifndef lint
  37. static char RCSinfo[] =
  38. "$Header: menus.c,v 1.20 88/04/15 07:09:54 tlastran Exp $";
  39. #endif
  40.  
  41. #include <stdio.h>
  42. #include <signal.h>
  43. #include "twm.h"
  44. #include "gc.h"
  45. #include "menus.h"
  46. #include "events.h"
  47. #include "util.h"
  48. #include "gram.h"
  49.  
  50. #include "pull.bm"
  51.  
  52. MenuRoot *Menu[MAX_BUTTONS + 1];    /* one root per button */
  53. MenuItem *Item[MAX_BUTTONS + 1];    /* one action per button */
  54. MenuRoot *MenuList = NULL;        /* head of the menu list */
  55. MenuRoot *LastMenu = NULL;        /* the last menu */
  56. MenuRoot *ActiveMenu = NULL;        /* the active menu */
  57. MenuItem *ActiveItem = NULL;        /* the active menu item */
  58.  
  59. /***********************************************************************
  60.  *
  61.  *  Procedure:
  62.  *    InitMenus - initialize menu roots
  63.  *
  64.  ***********************************************************************
  65.  */
  66.  
  67. void
  68. InitMenus()
  69. {
  70.     int i;
  71.  
  72.     for (i = 0; i < (MAX_BUTTONS + 1); i++)
  73.     {
  74.     Menu[i] = NULL;
  75.     Item[i] = NULL;
  76.     }
  77. }
  78.  
  79. /***********************************************************************
  80.  *
  81.  *  Procedure:
  82.  *    NewMenuRoot - create a new menu root
  83.  *
  84.  *  Returned Value:
  85.  *    (MenuRoot *)
  86.  *
  87.  *  Inputs:
  88.  *    name    - the name of the menu root
  89.  *
  90.  ***********************************************************************
  91.  */
  92.  
  93. MenuRoot *
  94. NewMenuRoot(name)
  95.     char *name;
  96. {
  97.     MenuRoot *tmp;
  98.  
  99.     CreateGCs();
  100.  
  101.     tmp = (MenuRoot *) malloc(sizeof(MenuRoot));
  102.     tmp->name = name;
  103.     tmp->prev = NULL;
  104.     tmp->first = NULL;
  105.     tmp->last = NULL;
  106.     tmp->items = 0;
  107.     tmp->width = 0;
  108.     tmp->mapped = FALSE;
  109.     tmp->pull = FALSE;
  110.     tmp->active = TRUE;
  111.     tmp->shadow = XCreateSimpleWindow(dpy, Root,
  112.     0, 0, 10, 10, 1, Foreground, Foreground);
  113.     tmp->w = XCreateSimpleWindow(dpy, Root,
  114.     0, 0, 10, 10, 1, Foreground, Background);
  115.     XSelectInput(dpy, tmp->w, LeaveWindowMask);
  116.  
  117.     if (MenuList == NULL)
  118.     {
  119.     MenuList = tmp;
  120.     MenuList->next = NULL;
  121.     }
  122.  
  123.     if (LastMenu == NULL)
  124.     {
  125.     LastMenu = tmp;
  126.     LastMenu->next = NULL;
  127.     }
  128.     else
  129.     {
  130.     LastMenu->next = tmp;
  131.     LastMenu = tmp;
  132.     LastMenu->next = NULL;
  133.     }
  134.  
  135.     return (tmp);
  136. }
  137.  
  138. /***********************************************************************
  139.  *
  140.  *  Procedure:
  141.  *    AddToMenu - add an item to a root menu
  142.  *
  143.  *  Returned Value:
  144.  *    (MenuItem *)
  145.  *
  146.  *  Inputs:
  147.  *    menu    - pointer to the root menu to add the item
  148.  *    item    - the text to appear in the menu
  149.  *    action    - the string to possibly execute
  150.  *    sub    - the menu root if it is a pull-right entry
  151.  *    func    - the numeric function
  152.  *
  153.  ***********************************************************************
  154.  */
  155.  
  156. MenuItem *
  157. AddToMenu(menu, item, action, sub, func)
  158.     MenuRoot *menu;
  159.     char *item, *action;
  160.     MenuRoot *sub;
  161.     int func;
  162. {
  163.     unsigned long valuemask;
  164.     XSetWindowAttributes attributes;
  165.     MenuItem *tmp;
  166.     int width;
  167.  
  168. #ifdef DEBUG
  169.     fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%d, f=%d\n",
  170.     item, action, sub, func);
  171. #endif
  172.  
  173.     tmp = (MenuItem *) malloc(sizeof(MenuItem));
  174.     tmp->root = menu;
  175.  
  176.     if (menu->first == NULL)
  177.     {
  178.     menu->first = tmp;
  179.     tmp->prev = NULL;
  180.     }
  181.     else
  182.     {
  183.     menu->last->next = tmp;
  184.     tmp->prev = menu->last;
  185.     }
  186.     menu->last = tmp;
  187.  
  188.     tmp->item = item;
  189.     tmp->action = action;
  190.     tmp->next = NULL;
  191.     tmp->sub = NULL;
  192.     tmp->pull = NULL;
  193.     tmp->state = 0;
  194.     tmp->func = func;
  195.  
  196.     width = XTextWidth(MenuFont, item, strlen(item));
  197.     if (width > menu->width)
  198.     menu->width = width;
  199.  
  200.     if (tmp->func != F_TITLE)
  201.     {
  202.     tmp->w = XCreateSimpleWindow(dpy, menu->w,
  203.         0, menu->items * (MenuFontHeight + 4),
  204.         width, MenuFontHeight + 4,
  205.         0,
  206.         Foreground, Background);
  207.     XSelectInput(dpy, tmp->w, EnterWindowMask
  208.         | LeaveWindowMask | ExposureMask);
  209.     }
  210.     else
  211.     {
  212.     tmp->w = XCreateSimpleWindow(dpy, menu->w,
  213.         -1, menu->items * (MenuFontHeight + 4),
  214.         width, MenuFontHeight + 2,
  215.         1,
  216.         Foreground, Background);
  217.     XSelectInput(dpy, tmp->w, ExposureMask);
  218.     }
  219.  
  220.     if (sub != NULL)
  221.     {
  222.     Pixmap pm;
  223.  
  224.     tmp->sub = sub;
  225.     pm = MakePixmap(tmp->w, MenuNormalGC,
  226.         pull_bits, pull_width, pull_height);
  227.  
  228.     valuemask = CWEventMask | CWBackPixmap;
  229.     attributes.background_pixmap = pm;
  230.     attributes.event_mask = EnterWindowMask | LeaveWindowMask;
  231.  
  232.     tmp->pull = XCreateWindow(dpy, tmp->w,
  233.         0, 0,
  234.         pull_width, pull_height,
  235.         0, DefaultDepth(dpy, 0), CopyFromParent, DefaultVisual(dpy, 0),
  236.         valuemask, &attributes);
  237.  
  238.     XMapWindow(dpy, tmp->pull);
  239.  
  240.     menu->pull = TRUE;
  241.     XSaveContext(dpy, tmp->pull, MenuContext, tmp);
  242.     }
  243.     menu->items += 1;
  244.  
  245.     XSaveContext(dpy, tmp->w, MenuContext, tmp);
  246.  
  247.     if (menu->items == 1)
  248.     XSaveContext(dpy, tmp->root->w, MenuContext, tmp);
  249.  
  250.     return (tmp);
  251. }
  252.  
  253. /***********************************************************************
  254.  *
  255.  *  Procedure:
  256.  *    PopUpMenu - pop up a pull down menu
  257.  *
  258.  *  Inputs:
  259.  *    menu    - the root pointer of the menu to pop up
  260.  *    x    - the x location of the mouse
  261.  *    y    - the y location of the mouse
  262.  *
  263.  ***********************************************************************
  264.  */
  265.  
  266. void
  267. PopUpMenu(menu, x, y)
  268.     MenuRoot *menu;
  269.     int x, y;
  270. {
  271.     int d_width, d_height, m_height;
  272.     XWindowChanges xwc, pwc;
  273.     unsigned int xwcm, pwcm;
  274.     MenuItem *tmp;
  275.  
  276.     if (ActiveMenu != NULL)
  277.     ActiveMenu->active = FALSE;
  278.  
  279.     menu->active = TRUE;
  280.     ActiveMenu = menu;
  281.     if (menu->mapped != TRUE)
  282.     {
  283.     if (menu->pull == TRUE)
  284.     {
  285.         menu->width += pull_width + 10;
  286.     }
  287.  
  288.     xwcm = 0;
  289.     xwcm |= CWWidth;
  290.     xwc.width = menu->width + 10;
  291.  
  292.     pwcm = 0;
  293.     pwcm |= CWX;
  294.     pwc.x = xwc.width - pull_width;
  295.  
  296.     for (tmp = menu->first; tmp != NULL; tmp = tmp->next)
  297.     {
  298.         XConfigureWindow(dpy, tmp->w, xwcm, &xwc);
  299.         if (tmp->pull != NULL)
  300.         {
  301.         XConfigureWindow(dpy, tmp->pull, pwcm, &pwc);
  302.         }
  303.         if (tmp->func != F_TITLE)
  304.         tmp->y = 5;
  305.         else
  306.         {
  307.         tmp->y = xwc.width - XTextWidth(MenuFont, tmp->item,
  308.             strlen(tmp->item));
  309.         tmp->y /= 2;
  310.         }
  311.     }
  312.     }
  313.     menu->mapped = TRUE;
  314.  
  315.     d_width = DisplayWidth(dpy, DefaultScreen(dpy));
  316.     d_height = DisplayHeight(dpy, DefaultScreen(dpy));
  317.     m_height = menu->items * (MenuFontHeight + 4);
  318.  
  319.     if ((x + menu->width + 10) > d_width)
  320.     x = (d_width - menu->width - 20);
  321.  
  322.     if ((y + m_height + 10) > d_height)
  323.     y = (d_height - m_height - 20);
  324.  
  325.     xwcm = 0;
  326.     xwcm |= CWX;
  327.     xwc.x = x - 1;
  328.     xwcm |= CWY;
  329.     xwc.y = y - ((MenuFontHeight + 4) / 2);
  330.     xwcm |= CWWidth;
  331.     xwc.width = menu->width + 10;
  332.     xwcm |= CWHeight;
  333.     xwc.height = m_height;
  334.  
  335.     XConfigureWindow(dpy, menu->w, xwcm, &xwc);
  336.  
  337.     xwc.x = xwc.x + 5;
  338.     xwc.y = xwc.y + 5;
  339.     /* xwc.width -= 20; xwc.height -= 20; */
  340.  
  341.     XConfigureWindow(dpy, menu->shadow, xwcm, &xwc);
  342.     XWarpPointer(dpy, None, menu->w, 0, 0, 0, 0, 1, (MenuFontHeight + 4) / 2);
  343.     XMapSubwindows(dpy, menu->w);
  344.     XRaiseWindow(dpy, menu->shadow);
  345.     XMapRaised(dpy, menu->w);
  346.     XMapWindow(dpy, menu->shadow);
  347. }
  348.  
  349. /***********************************************************************
  350.  *
  351.  *  Procedure:
  352.  *    FindMenuRoot - look for a menu root
  353.  *
  354.  *  Returned Value:
  355.  *    (MenuRoot *)  - a pointer to the menu root structure 
  356.  *
  357.  *  Inputs:
  358.  *    name    - the name of the menu root 
  359.  *
  360.  ***********************************************************************
  361.  */
  362.  
  363. MenuRoot *
  364. FindMenuRoot(name)
  365.     char *name;
  366. {
  367.     MenuRoot *tmp;
  368.  
  369.     for (tmp = MenuList; tmp != NULL; tmp = tmp->next)
  370.     {
  371.     if (strcmp(name, tmp->name) == 0)
  372.         return (tmp);
  373.     }
  374.     return NULL;
  375. }
  376.  
  377. /***********************************************************************
  378.  *
  379.  *  Procedure:
  380.  *    ExecuteFunction - execute a twm root function
  381.  *
  382.  *  Inputs:
  383.  *    menu - the menu item to execute 
  384.  *
  385.  ***********************************************************************
  386.  */
  387.  
  388. void
  389. ExecuteFunction(menu)
  390.     MenuItem *menu;
  391. {
  392.     Window w;
  393.     unsigned long black;
  394.     char tmp[200];
  395.     char *ptr;
  396.     int len;
  397.     char buff[MAX_FILE_SIZE];
  398.     int count, fd;
  399.     MenuRoot *root, *tmp_root;
  400.     MenuItem *item, *tmp_item;
  401.  
  402.     XGrabPointer(dpy, Root, True,
  403.     ButtonReleaseMask | ButtonMotionMask,
  404.     GrabModeAsync, GrabModeSync,
  405.     Root, ClockCursor, CurrentTime);
  406.  
  407.     switch (menu->func)
  408.     {
  409.     case F_NOP:
  410.     case F_TITLE:
  411.     break;
  412.  
  413.     case F_CIRCLEUP:
  414.     XCirculateSubwindowsUp(dpy, Root);
  415.     break;
  416.  
  417.     case F_CIRCLEDOWN:
  418.     XCirculateSubwindowsDown(dpy, Root);
  419.     break;
  420.  
  421.     case F_VERSION:
  422.     XMapRaised(dpy, VersionWindow);
  423.     break;
  424.  
  425.     case F_EXEC:
  426.     Execute(menu->action);
  427.     break;
  428.  
  429.     case F_FOCUS:
  430.     FocusOnRoot();
  431.     break;
  432.  
  433.     case F_CUT:
  434.     strcpy(tmp, menu->action);
  435.     strcat(tmp, "\n");
  436.     XStoreBytes(dpy, tmp, strlen(tmp));
  437.     break;
  438.  
  439.     case F_CUTFILE:
  440.     ptr = XFetchBytes(dpy, &count);
  441.     if (count != 0)
  442.     {
  443.         if (sscanf(ptr, "%s", tmp) == 1)
  444.         {
  445.         fd = open(tmp, 0);
  446.         if (fd >= 0)
  447.         {
  448.             count = read(fd, buff, MAX_FILE_SIZE - 1);
  449.             if (count > 0)
  450.             XStoreBytes(dpy, buff, strlen(buff));
  451.  
  452.             close(fd);
  453.         }
  454.         else
  455.         {
  456.             fprintf(stderr, "twm: couldn't open \"%s\"\n", tmp);
  457.         }
  458.         }
  459.         XFree(ptr);
  460.     }
  461.     else
  462.     {
  463.         fprintf(stderr, "twm: nothing in the cut buffer\n");
  464.     }
  465.     break;
  466.  
  467.     case F_FILE:
  468.     fd = open(menu->action, 0);
  469.     if (fd >= 0)
  470.     {
  471.         count = read(fd, buff, MAX_FILE_SIZE - 1);
  472.         if (count > 0)
  473.         XStoreBytes(dpy, buff, strlen(buff));
  474.  
  475.         close(fd);
  476.     }
  477.     else
  478.     {
  479.         fprintf(stderr, "twm: couldn't open \"%s\"\n", menu->action);
  480.     }
  481.     break;
  482.  
  483.     case F_TWMRC:
  484.     len = strlen(menu->action);
  485.     if (len == 0)
  486.         ptr = NULL;
  487.     else
  488.     {
  489.         ptr = (char *)malloc(len+1);
  490.         if (ptr == NULL)
  491.         {
  492.         fprintf(stderr, "twm: out of memory\n");
  493.         exit(1);
  494.         }
  495.         strcpy(ptr, menu->action);
  496.     }
  497.  
  498.     /* first get rid of the existing menu structure and destroy all
  499.      * windows */
  500.     for (root = MenuList; root != NULL;)
  501.     {
  502.         for (item = root->last; item != NULL;)
  503.         {
  504.         if (item->pull != NULL)
  505.         {
  506.             XDeleteContext(dpy, item->pull, MenuContext);
  507.             XDestroyWindow(dpy, item->pull);
  508.         }
  509.         XDeleteContext(dpy, item->w, MenuContext);
  510.         XDestroyWindow(dpy, item->w);
  511.  
  512.         free(item->item);
  513.         free(item->action);
  514.  
  515.         tmp_item = item;
  516.         item = item->prev;
  517.         free(tmp_item);
  518.         }
  519.  
  520.         XDeleteContext(dpy, root->w, MenuContext);
  521.         XDestroyWindow(dpy, root->shadow);
  522.         XDestroyWindow(dpy, root->w);
  523.         free(root->name);
  524.  
  525.         tmp_root = root;
  526.         root = root->next;
  527.         free(tmp_root);
  528.     }
  529.     MenuList = NULL;
  530.     LastMenu = NULL;
  531.     ActiveMenu = NULL;
  532.     ActiveItem = NULL;
  533.  
  534.     ParseTwmrc(ptr);
  535.     break;
  536.  
  537.     case F_REFRESH:
  538.     black = BlackPixel(dpy, DefaultScreen(dpy));
  539.     w = XCreateSimpleWindow(dpy, Root,
  540.         0, 0, 9999, 9999, 0, black, black);
  541.     XMapWindow(dpy, w);
  542.     XDestroyWindow(dpy, w);
  543.     XFlush(dpy);
  544.     break;
  545.  
  546.     case F_QUIT:
  547.     Done();
  548.     break;
  549.     }
  550. }
  551.  
  552. /***********************************************************************
  553.  *
  554.  *  Procedure:
  555.  *    Execute - execute the string by /bin/sh
  556.  *
  557.  *  Inputs:
  558.  *    s    - the string containing the command
  559.  *
  560.  ***********************************************************************
  561.  */
  562.  
  563. void
  564. Execute(s)
  565.     char *s;
  566. {
  567.     int status, pid, w;
  568.     register int (*istat) (), (*qstat) ();
  569.  
  570.     if ((pid = vfork()) == 0)
  571.     {
  572.     signal(SIGINT, SIG_DFL);
  573.     signal(SIGQUIT, SIG_DFL);
  574.     signal(SIGHUP, SIG_DFL);
  575.     execl("/bin/sh", "sh", "-c", s, 0);
  576.     _exit(127);
  577.     }
  578.     istat = signal(SIGINT, SIG_IGN);
  579.     qstat = signal(SIGQUIT, SIG_IGN);
  580.     while ((w = wait(&status)) != pid && w != -1);
  581.     if (w == -1)
  582.     status = -1;
  583.     signal(SIGINT, istat);
  584.     signal(SIGQUIT, qstat);
  585. }
  586.  
  587. /***********************************************************************
  588.  *
  589.  *  Procedure:
  590.  *    FocusOnRoot - put input focus on the root window
  591.  *
  592.  ***********************************************************************
  593.  */
  594.  
  595. void
  596. FocusOnRoot()
  597. {
  598.     XSetInputFocus(dpy, Root, RevertToPointerRoot, CurrentTime);
  599.     if (Focus != NULL)
  600.     {
  601.     XUnmapWindow(dpy, Focus->hilite_w);
  602.     }
  603.     Focus = NULL;
  604.     FocusRoot = TRUE;
  605. }
  606.