home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / oldXMenu / Internal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-02-25  |  25.7 KB  |  987 lines

  1. #include <X11/copyright.h>
  2.  
  3. /* $Header: Internal.c,v 1.12 87/12/20 12:05:22 rws Exp $ */
  4. /* Copyright    Massachusetts Institute of Technology    1985    */
  5.  
  6. /*
  7.  * XMenu:    MIT Project Athena, X Window system menu package
  8.  *
  9.  *     XMenuInternal.c - XMenu internal (not user visable) routines.
  10.  *
  11.  *    Author:        Tony Della Fera, DEC
  12.  *            November, 1985
  13.  *
  14.  */
  15.  
  16. #include "XMenuInt.h"
  17.  
  18. /*
  19.  * Toggle color macro.
  20.  */
  21. #define toggle_color(x) \
  22.     ((x) == menu->bkgnd_color ? menu->s_frg_color : menu->bkgnd_color)
  23.  
  24. /*
  25.  * Internal Window creation queue sizes.
  26.  */
  27. #define S_QUE_SIZE    300
  28. #define P_QUE_SIZE    20
  29. #define BUFFER_SIZE    (S_QUE_SIZE >= P_QUE_SIZE ? S_QUE_SIZE : P_QUE_SIZE)
  30.  
  31.  
  32. /*
  33.  * XMWinQue - Internal window creation queue datatype.
  34.  */
  35. typedef struct _xmwinquedef {
  36.     int sq_size;
  37.     XMSelect *sq[S_QUE_SIZE];
  38.     XMSelect **sq_ptr;
  39.     int pq_size;
  40.     XMPane *pq[P_QUE_SIZE];
  41.     XMPane **pq_ptr;
  42. } XMWinQue;
  43.  
  44. /*
  45.  * _XMWinQue - Internal static window creation queue.
  46.  */
  47. static Bool _XMWinQueIsInit = False;
  48. static XMWinQue _XMWinQue;
  49.  
  50. /*
  51.  * _XMErrorCode - Global XMenu error code.
  52.  */
  53. int _XMErrorCode = XME_NO_ERROR; 
  54. /*
  55.  * _XMErrorList - Global XMenu error code discription strings.
  56.  */
  57. char *
  58. _XMErrorList[XME_CODE_COUNT] = {
  59.     "No error",                /* XME_NO_ERROR */
  60.     "Menu not initialized",        /* XME_NOT_INIT */
  61.     "Argument out of bounds",        /* XME_ARG_BOUNDS */
  62.     "Pane not found",            /* XME_P_NOT_FOUND */
  63.     "Selection not found",        /* XME_S_NOT_FOUND */
  64.     "Invalid menu style parameter",    /* XME_STYLE_PARAM */
  65.     "Unable to grab mouse",        /* XME_GRAB_MOUSE */
  66.     "Unable to interpret locator",    /* XME_INTERP_LOC */
  67.     "Unable to calloc memory",        /* XME_CALLOC */
  68.     "Unable to create XAssocTable",    /* XME_CREATE_ASSOC */
  69.     "Unable to store bitmap",        /* XME_STORE_BITMAP */
  70.     "Unable to make tile pixmaps",    /* XME_MAKE_TILES */
  71.     "Unable to make pixmap",        /* XME_MAKE_PIXMAP */
  72.     "Unable to create cursor",        /* XME_CREATE_CURSOR */
  73.     "Unable to open font",        /* XME_OPEN_FONT */
  74.     "Unable to create windows",        /* XME_CREATE_WINDOW */
  75.     "Unable to create transparencies",    /* XME_CREATE_TRANSP */
  76. };
  77.  
  78. /*
  79.  * _XMEventHandler - Internal event handler variable.
  80.  */
  81. int (*_XMEventHandler)() = NULL;
  82.  
  83.  
  84.  
  85. /*
  86.  * _XMWinQueInit - Internal routine to initialize the window
  87.  *           queue.
  88.  */
  89. _XMWinQueInit()
  90. {
  91.     /*
  92.      * If the queue is not initialized initialize it.
  93.      */
  94.     if (!_XMWinQueIsInit) {
  95.     /*
  96.      * Blank the queue structure.
  97.      */
  98.     bzero(&_XMWinQue, sizeof(XMWinQue));
  99.  
  100.     /*
  101.      * Initialize the next free location pointers.
  102.      */
  103.     _XMWinQue.sq_ptr = _XMWinQue.sq;
  104.     _XMWinQue.pq_ptr = _XMWinQue.pq;
  105.     }
  106. }
  107.  
  108.  
  109.  
  110. /*
  111.  * _XMWinQueAddPane - Internal routine to add a pane to the pane
  112.  *              window queue.
  113.  */
  114. int
  115. _XMWinQueAddPane(display, menu, p_ptr)
  116.     register XMenu *menu;    /* Menu being manipulated. */
  117.     register XMPane *p_ptr;    /* XMPane being queued. */
  118. {
  119.     /*
  120.      * If the queue is currently full then flush it.
  121.      */
  122.     if (_XMWinQue.pq_size == P_QUE_SIZE) {
  123.     if (_XMWinQueFlush(display, menu, 0, 0) == _FAILURE) return(_FAILURE);
  124.     }
  125.  
  126.     /*
  127.      * Insert the new XMPane pointer and increment the queue pointer
  128.      * and the queue size.
  129.      */
  130.     *_XMWinQue.pq_ptr = p_ptr;
  131.     _XMWinQue.pq_ptr++;
  132.     _XMWinQue.pq_size++;
  133.  
  134.     /*
  135.      * All went well, return successfully.
  136.      */
  137.     _XMErrorCode = XME_NO_ERROR;
  138.     return(_SUCCESS);
  139. }
  140.  
  141.  
  142.  
  143. /*
  144.  * _XMWinQueAddSelection - Internal routine to add a selection to
  145.  *               the selection window queue.
  146.  */
  147. int
  148. _XMWinQueAddSelection(display, menu, s_ptr)
  149.     register XMenu *menu;    /* Menu being manipulated. */
  150.     register XMSelect *s_ptr;    /* XMSelection being queued. */
  151. {
  152.     /*
  153.      * If this entry will overflow the queue then flush it.
  154.      */
  155.     if (_XMWinQue.sq_size == S_QUE_SIZE) {
  156.     if (_XMWinQueFlush(display, menu, 0, 0) == _FAILURE) return(_FAILURE);
  157.     }
  158.  
  159.     /*
  160.      * Insert the new XMSelect pointer and increment the queue pointer
  161.      * and the queue size.
  162.      */
  163.     *_XMWinQue.sq_ptr = s_ptr;
  164.     _XMWinQue.sq_ptr++;
  165.     _XMWinQue.sq_size++;
  166.  
  167.     /*
  168.      * All went well, return successfully.
  169.      */
  170.     _XMErrorCode = XME_NO_ERROR;
  171.     return(_SUCCESS);
  172. }
  173.  
  174.  
  175.  
  176. /*
  177.  * _XMWinQueFlush - Internal routine to flush the pane and
  178.  *            selection window queues.
  179.  */
  180. int
  181. _XMWinQueFlush(display, menu, pane, select)
  182.     register Display *display;
  183.     register XMenu *menu;        /* Menu being manipulated. */
  184.     register XMPane *pane;        /* Current pane. */
  185. {
  186.     register int pq_index;        /* Pane queue index. */
  187.     register int sq_index;        /* Selection queue index. */
  188.     register XMPane *p_ptr;        /* XMPane pointer. */
  189.     register XMSelect *s_ptr;       /* XMSelect pointer. */
  190.     unsigned long valuemask;        /* Which attributes to set. */
  191.     XSetWindowAttributes *attributes;     /* Attributes to be set. */
  192.  
  193.     /*
  194.      * If the pane window queue is not empty...
  195.      */
  196.     
  197.     if (_XMWinQue.pq_size > 0) {
  198.     /*
  199.      * set up attributes for pane window to be created.
  200.      */
  201.     valuemask = (CWBackPixmap | CWBorderPixel | CWOverrideRedirect);
  202.     attributes = (XSetWindowAttributes *)malloc(sizeof(XSetWindowAttributes));
  203.     attributes->border_pixel = menu->p_bdr_color;
  204.     attributes->background_pixmap = menu->inact_pixmap;
  205.     attributes->override_redirect = True;
  206.     
  207.     /*
  208.      * Create all the pending panes in order, so that the
  209.      * current pane will be on top, with the others
  210.      * stacked appropriately under it.
  211.      */
  212.     for (pq_index = _XMWinQue.pq_size - 1;
  213.          pq_index >= 0;
  214.          pq_index--) 
  215.       {
  216.           p_ptr = _XMWinQue.pq[pq_index];  /* Retrieve next pane. */
  217.           if (p_ptr == pane) break;
  218.           p_ptr->window = XCreateWindow(display,
  219.                         menu->parent,
  220.                         p_ptr->window_x,
  221.                         p_ptr->window_y,
  222.                         p_ptr->window_w,
  223.                         p_ptr->window_h,
  224.                         menu->p_bdr_width,
  225.                         CopyFromParent,
  226.                         InputOutput,
  227.                         CopyFromParent,
  228.                         valuemask,
  229.                         attributes);
  230.           XMakeAssoc(display, menu->assoc_tab, p_ptr->window, p_ptr);
  231.           XSelectInput(display, p_ptr->window, menu->p_events);
  232.       }
  233.     for (pq_index = 0;
  234.          pq_index < _XMWinQue.pq_size;
  235.          pq_index++) 
  236.       {
  237.           p_ptr = _XMWinQue.pq[pq_index];    /* Retrieve next pane. */
  238.           p_ptr->window = XCreateWindow(display,
  239.                         menu->parent,
  240.                         p_ptr->window_x,
  241.                         p_ptr->window_y,
  242.                         p_ptr->window_w,
  243.                         p_ptr->window_h,
  244.                         menu->p_bdr_width,
  245.                         CopyFromParent,
  246.                         InputOutput,
  247.                         CopyFromParent,
  248.                         valuemask,
  249.                         attributes);
  250.           XMakeAssoc(display, menu->assoc_tab, p_ptr->window, p_ptr);
  251.           XSelectInput(display, p_ptr->window, menu->p_events);
  252.           if (p_ptr == pane) break;
  253.     }
  254.  
  255.     /*
  256.      * Reset the pane queue pointer and size.
  257.      */
  258.     _XMWinQue.pq_size = 0;
  259.     _XMWinQue.pq_ptr = _XMWinQue.pq;
  260.     }
  261.  
  262.     /*
  263.      * If the selection window queue is not empty...
  264.      */
  265.     
  266.     if (_XMWinQue.sq_size > 0) {
  267.  
  268.     for (sq_index = 0; sq_index < _XMWinQue.sq_size; sq_index++) {
  269.         /*
  270.          * Retrieve the XMSelect pointer.
  271.          */
  272.         s_ptr = _XMWinQue.sq[sq_index];
  273.         s_ptr->window = XCreateWindow(display,
  274.                    s_ptr->parent_p->window,
  275.                    s_ptr->window_x,
  276.                    s_ptr->window_y,
  277.                    s_ptr->window_w,
  278.                    s_ptr->window_h,
  279.                    0,                /* border width*/
  280.                    CopyFromParent,
  281.                    InputOnly,
  282.                    CopyFromParent,
  283.                    0,
  284.                    attributes);
  285.         
  286.         /*
  287.          * Insert the new window id and its
  288.          * associated XMSelect structure into the 
  289.          * assoction table.
  290.          */
  291.         XMakeAssoc(display, menu->assoc_tab, s_ptr->window, s_ptr);
  292.         XSelectInput(display, s_ptr->window, menu->s_events);
  293.     }
  294.  
  295.     /*
  296.      * Reset the selection queue pointer and size.
  297.      */
  298.     _XMWinQue.sq_size = 0;
  299.     _XMWinQue.sq_ptr = _XMWinQue.sq;
  300.     }
  301.  
  302.     /*
  303.      * Flush X's internal queues.
  304.      */
  305.     XFlush(display);
  306.  
  307.     /*
  308.      * All went well, return successfully.
  309.      */
  310.     _XMErrorCode = XME_NO_ERROR;
  311.     return(_SUCCESS);
  312. }
  313.  
  314.  
  315.  
  316. /*
  317.  * _XMGetPanePtr -     Given a menu pointer and a pane index number, return
  318.  *            a pane pointer that points to the indexed pane.
  319.  */
  320. XMPane *
  321. _XMGetPanePtr(menu, p_num)
  322.     register XMenu *menu;    /* Menu to find the pane in. */
  323.     register int p_num;        /* Index number of pane to find. */
  324. {
  325.     register XMPane *p_ptr;    /* Pane pointer to be returned. */
  326.     register int i;        /* Loop counter. */
  327.  
  328.     /*
  329.      * Is the pane number out of range?
  330.      */
  331.     if ((p_num < 0) || (p_num > (menu->p_count - 1))) {
  332.     _XMErrorCode = XME_P_NOT_FOUND;
  333.     return(NULL);
  334.     }
  335.  
  336.     /*
  337.      * Find the right pane.
  338.      */
  339.     p_ptr = menu->p_list->next;
  340.     for (i = 0; i < p_num; i++) p_ptr = p_ptr->next;
  341.  
  342.     /*
  343.      * Return successfully.
  344.      */
  345.     _XMErrorCode = XME_NO_ERROR;
  346.     return(p_ptr);
  347. }
  348.  
  349.  
  350.  
  351. /*
  352.  * _XMGetSelectionPtr -    Given pane pointer and a selection index number,
  353.  *            return a selection pointer that points to the
  354.  *            indexed selection.
  355.  */
  356. XMSelect *
  357. _XMGetSelectionPtr(p_ptr, s_num)
  358.     register XMPane *p_ptr;    /* Pane to find the selection in. */
  359.     register int s_num;        /* Index number of the selection to find. */
  360. {
  361.     register XMSelect *s_ptr;    /* Selection pointer to be returned. */
  362.     register int i;        /* Loop counter. *./
  363.     
  364.     /*
  365.      * Is the selection number out of range?
  366.      */
  367.     if ((s_num < 0) || (s_num > (p_ptr->s_count - 1))) {
  368.     _XMErrorCode = XME_S_NOT_FOUND;
  369.     return(NULL);
  370.     }
  371.  
  372.     /*
  373.      * Find the right selection.
  374.      */
  375.     s_ptr = p_ptr->s_list->next;
  376.     for (i = 0; i < s_num; i++) s_ptr = s_ptr->next;
  377.  
  378.     /*
  379.      * Return successfully.
  380.      */
  381.     _XMErrorCode = XME_NO_ERROR;
  382.     return(s_ptr);
  383. }
  384.  
  385.  
  386.  
  387. /*
  388.  * _XMRecomputeGlobals - Internal subroutine to recompute menu wide
  389.  *             global values.
  390.  */
  391. _XMRecomputeGlobals(display, menu)
  392.     register Display *display; /*X11 display variable. */    
  393.     register XMenu *menu;    /* Menu object to compute from. */
  394. {
  395.     register XMPane *p_ptr;    /* Pane pointer. */
  396.     register XMSelect *s_ptr;    /* Selection pointer. */
  397.  
  398.     register int max_p_label = 0;    /* Maximum pane label width. */
  399.     register int max_s_label = 0;    /* Maximum selection label width. */
  400.     register int s_count = 0;        /* Maximum selection count. */
  401.  
  402.     int p_s_pad;        /* Pane <-> selection padding. */
  403.     int p_s_diff;        /* Pane <-> selection seperation. */
  404.  
  405.     int p_height;        /* Pane window height. */
  406.     int p_width;        /* Pane window width. */
  407.     int s_width;        /* Selection window width. */
  408.  
  409.     int screen;            /* DefaultScreen holder. */
  410.     
  411.     /*
  412.      * For each pane...
  413.      */
  414.     for (
  415.     p_ptr = menu->p_list->next;
  416.     p_ptr != menu->p_list;
  417.     p_ptr = p_ptr->next
  418.     ){
  419.     
  420.     /*
  421.      * Recompute maximum pane label width.
  422.      */
  423.     max_p_label = max(max_p_label, p_ptr->label_width);
  424.  
  425.     /*
  426.      * Recompute maximum selection count. 
  427.      */
  428.     s_count = max(s_count, p_ptr->s_count);
  429.  
  430.     /*
  431.      * For each selection in the current pane...
  432.      */
  433.     for (
  434.         s_ptr = p_ptr->s_list->next;
  435.         s_ptr != p_ptr->s_list;
  436.         s_ptr = s_ptr->next
  437.     ){
  438.  
  439.         /*
  440.          * Recompute maximum selection label width.
  441.          */
  442.         max_s_label = max(max_s_label, s_ptr->label_width);
  443.     }
  444.     }
  445.  
  446.     /*
  447.      * Recompute pane height.
  448.      */
  449.     p_height = (menu->flag_height << 1) + (menu->s_y_off * s_count);
  450.  
  451.     /*
  452.      * Recompute horizontal padding between the pane window and the
  453.      * selection windows.
  454.      */
  455.     p_s_pad = menu->p_x_off << 1;
  456.  
  457.     /*
  458.      * Recompute pane and selection window widths.
  459.      * This is done by first computing the window sizes from the maximum
  460.      * label widths.  If the spacing between the selection window and the
  461.      * containing pane window is less than the pane selection padding value
  462.      * (twice the pane X offset) then change the size of the pane to be
  463.      * the size of the selection window plus the padding.  If, however the
  464.      * spacing between the selection window and the containing pane window
  465.      * is more than the pane selection padding value increase the size of
  466.      * the selection to its maximum possible value (the pane width minus
  467.      * the pane selection padding value).
  468.      */
  469.     p_width = max_p_label + p_s_pad;
  470.     s_width = max_s_label + (menu->s_fnt_pad << 1) + (menu->s_bdr_width << 1);
  471.     p_s_diff = p_width - s_width;
  472.     if (p_s_diff < p_s_pad) {
  473.     p_width = s_width + p_s_pad;
  474.     }
  475.     else if (p_s_diff > p_s_pad) {
  476.     s_width = p_width - p_s_pad;
  477.     }
  478.  
  479.     /*
  480.      * Reset menu wide global values.
  481.      */
  482.     menu->s_count = s_count;
  483.     menu->p_height = p_height;
  484.     menu->p_width = p_width;
  485.     menu->s_width = s_width;
  486.  
  487.     /* 
  488.      * Ensure that the origin of the menu is placed so that
  489.      * None of the panes ore selections are off the screen.
  490.      */
  491.     screen = DefaultScreen(display);
  492.     if (menu->x_pos + menu->width > DisplayWidth(display, screen))
  493.         menu->x_pos = DisplayWidth(display, screen) - menu->width;
  494.     else if (menu->x_pos < 0) menu->x_pos = 0;
  495.     if(menu->y_pos + menu->height > DisplayHeight(display, screen))
  496.         menu->y_pos = DisplayHeight(display, screen) - menu->height;
  497.     else if (menu->y_pos < 0) menu->y_pos = 0;
  498. }
  499.  
  500.  
  501. /*
  502.  * _XMRecomputePane - Internal subroutine to recompute pane
  503.  *              window dependencies.
  504.  */
  505. int
  506. _XMRecomputePane(display, menu, p_ptr, p_num)
  507.     register Display *display;    /* Standard X display variable. */
  508.     register XMenu *menu;    /* Menu object being recomputed. */
  509.     register XMPane *p_ptr;    /* Pane pointer. */
  510.     register int p_num;        /* Pane sequence number. */
  511. {
  512.     register int window_x;    /* Recomputed window X coordinate. */
  513.     register int window_y;    /* Recomputed window Y coordinate. */
  514.     
  515.     unsigned long change_mask;    /* Value mask to reconfigure window. */
  516.     XWindowChanges *changes;    /* Values to use in configure window. */
  517.     
  518.     register Bool config_p = False;    /* Reconfigure pane window? */
  519.  
  520.     /*
  521.      * Update the pane serial number.
  522.      */
  523.     p_ptr->serial = p_num;
  524.  
  525.     /*
  526.      * Recompute window X and Y coordinates.
  527.      */
  528.     switch (menu->menu_style) {
  529.     case LEFT:
  530.         window_x = menu->p_x_off * ((menu->p_count - 1) - p_num);
  531.         window_y = menu->p_y_off * ((menu->p_count - 1) - p_num);
  532.         break;
  533.     case RIGHT:
  534.         window_x = menu->p_x_off * p_num;
  535.         window_y = menu->p_y_off * ((menu->p_count - 1) - p_num);
  536.         break;
  537.     case CENTER:
  538.         window_x = 0;
  539.         window_y = menu->p_y_off * ((menu->p_count - 1) - p_num);
  540.         break;
  541.     default:
  542.         /* Error! Invalid style parameter. */
  543.         _XMErrorCode = XME_STYLE_PARAM;
  544.         return(_FAILURE);
  545.     }
  546.     window_x += menu->x_pos;
  547.     window_y += menu->y_pos;
  548.  
  549.     /*
  550.      * If the newly compute pane coordinates differ from the 
  551.      * current coordinates, reset the current coordinates and
  552.      * reconfigure the pane.
  553.      */
  554.     if (
  555.     (window_x != p_ptr->window_x) ||
  556.     (window_y != p_ptr->window_y)
  557.     ){
  558.     /*
  559.      * Reset the coordinates and schedule
  560.      * the pane for reconfiguration.
  561.      */
  562.     p_ptr->window_x = window_x;
  563.     p_ptr->window_y = window_y;
  564.     config_p = True;
  565.     }
  566.  
  567.     /*
  568.      * If the local pane width and height differs from the
  569.      * menu pane width and height, reset the local values.
  570.      */
  571.     if (
  572.     (p_ptr->window_w != menu->p_width) ||
  573.     (p_ptr->window_h != menu->p_height)
  574.     ){
  575.     /*
  576.      * Reset window width and height and schedule
  577.      * the pane for reconfiguration.
  578.      */
  579.     p_ptr->window_w = menu->p_width;
  580.     p_ptr->window_h = menu->p_height;
  581.     config_p = True;
  582.     }
  583.  
  584.     /*
  585.      * If we need to reconfigure the pane window do it now.
  586.      */
  587.     if (config_p == True) {
  588.     /*
  589.      * If the pane window has already been created then
  590.      * reconfigure the existing window, otherwise queue
  591.      * it for creation with the new configuration.
  592.      */
  593.     if (p_ptr->window) {
  594.         change_mask = (CWX | CWY | CWWidth | CWHeight);
  595.         changes = (XWindowChanges *)malloc(sizeof(XWindowChanges));
  596.         changes->x = p_ptr->window_x;
  597.         changes->y = p_ptr->window_y;
  598.         changes->width = p_ptr->window_w;
  599.         changes->height = p_ptr->window_h;
  600.         
  601.         XConfigureWindow(
  602.                  display,
  603.                  p_ptr->window,
  604.                  change_mask,
  605.                  changes
  606.                  );
  607.         free(changes);
  608.         
  609.     }
  610.     else {
  611.         if (_XMWinQueAddPane(display, menu, p_ptr) == _FAILURE) {
  612.         return(_FAILURE);
  613.         }
  614.     }
  615.     }
  616.  
  617.     /*
  618.      * Recompute label X position.
  619.      */
  620.     switch (menu->p_style) {
  621.     case LEFT:
  622.         p_ptr->label_x = menu->p_x_off + menu->p_fnt_pad;
  623.         break;
  624.     case RIGHT:
  625.         p_ptr->label_x = menu->p_width -
  626.         (p_ptr->label_width + menu->p_x_off + menu->p_fnt_pad);
  627.         break;
  628.     case CENTER:
  629.         p_ptr->label_x = (menu->p_width - p_ptr->label_width) >> 1;
  630.         break;
  631.     default:
  632.         /* Error! Invalid style parameter. */
  633.         _XMErrorCode = XME_STYLE_PARAM;
  634.         return(_FAILURE);
  635.     }
  636.     /*
  637.      * Recompute label Y positions.
  638.      */
  639.     p_ptr->label_uy = menu->p_fnt_pad + menu->p_fnt_info->max_bounds.ascent;
  640.     p_ptr->label_ly = (menu->p_height - menu->p_fnt_pad - menu->p_fnt_info->max_bounds.descent);
  641.  
  642.     /*
  643.      * All went well, return successfully.
  644.      */
  645.     _XMErrorCode = XME_NO_ERROR;
  646.     return(_SUCCESS);
  647. }
  648.  
  649.  
  650.  
  651. /*
  652.  * _XMRecomputeSelection - Internal subroutine to recompute
  653.  *               selection window dependencies.
  654.  */
  655. int
  656. _XMRecomputeSelection(display, menu, s_ptr, s_num)
  657.     register Display *display;
  658.     register XMenu *menu;    /* Menu object being recomputed. */
  659.     register XMSelect *s_ptr;    /* Selection pointer. */
  660.     register int s_num;        /* Selection sequence number. */
  661. {
  662.     register Bool config_s = False;    /* Reconfigure selection window? */
  663.     XWindowChanges *changes;        /* Values to change in configure. */
  664.     unsigned long change_mask;        /* Value mask for XConfigureWindow. */
  665.     
  666.     /*
  667.      * If the selection serial numbers are out of order, begin
  668.      * resequencing selections.  Recompute selection window coordinates
  669.      * and serial number.
  670.      *
  671.      * When selections are created they are given a serial number of
  672.      * -1, this causes this routine to give a new selection
  673.      * its initial coordinates and serial number.
  674.      */
  675.     if (s_ptr->serial != s_num) {
  676.     /*
  677.      * Fix the sequence number.
  678.      */
  679.     s_ptr->serial = s_num;
  680.     /*
  681.      * Recompute window X and Y coordinates.
  682.      */
  683.     s_ptr->window_x = menu->s_x_off;
  684.     s_ptr->window_y = menu->flag_height + (menu->s_y_off * s_num);
  685.     /*
  686.      * We must reconfigure the window.
  687.      */
  688.     config_s = True;
  689.     }
  690.  
  691.     /*
  692.      * If the local selection width and height differs from the
  693.      * menu selection width and height, reset the local values.
  694.      */
  695.     if (
  696.     (s_ptr->window_w != menu->s_width) ||
  697.     (s_ptr->window_h != menu->s_height)
  698.     ){
  699.     /*
  700.      * We must reconfigure the window.
  701.      */
  702.     config_s = True;
  703.     /*
  704.      * Reset window width and height.
  705.      */
  706.     s_ptr->window_w = menu->s_width;
  707.     s_ptr->window_h = menu->s_height;
  708.     }
  709.  
  710.     /*
  711.      * If we need to reconfigure the selection window do it now.
  712.      */
  713.     if (config_s == True) {
  714.     /*
  715.      * If the selection window has already been created then
  716.      * reconfigure the existing window, otherwise queue it
  717.      * for creation with the new configuration.
  718.      */
  719.     if (s_ptr->window) {
  720.         changes = (XWindowChanges *)malloc(sizeof(XWindowChanges));
  721.         change_mask = (CWX | CWY | CWWidth | CWHeight);
  722.         changes = (XWindowChanges *)malloc(sizeof(XWindowChanges));
  723.         changes->x = s_ptr->window_x;
  724.         changes->y = s_ptr->window_y;
  725.         changes->width = s_ptr->window_w;
  726.         changes->height = s_ptr->window_h;
  727.         
  728.         XConfigureWindow(
  729.                  display,
  730.                  s_ptr->window,
  731.                  change_mask,
  732.                  changes
  733.                  );
  734.         free(changes);
  735.         
  736.     }
  737.     else {
  738.         if (_XMWinQueAddSelection(display, menu, s_ptr) == _FAILURE) {
  739.         return(_FAILURE);
  740.         }
  741.     }
  742.     }
  743.  
  744.     /*
  745.      * Recompute label X position.
  746.      */
  747.     switch (menu->s_style) {
  748.     case LEFT:
  749.         s_ptr->label_x = menu->s_bdr_width + menu->s_fnt_pad + s_ptr->window_x;
  750.         break;
  751.     case RIGHT:
  752.         s_ptr->label_x = s_ptr->window_x + menu->s_width -
  753.         (s_ptr->label_width + menu->s_bdr_width + menu->s_fnt_pad);
  754.         break;
  755.     case CENTER:
  756.         s_ptr->label_x = s_ptr->window_x + ((menu->s_width - s_ptr->label_width) >> 1);
  757.         break;
  758.     default:
  759.         /* Error! Invaild style parameter. */
  760.         _XMErrorCode = XME_STYLE_PARAM;
  761.         return(_FAILURE);
  762.     }
  763.     /*
  764.      * Recompute label Y position.
  765.      */
  766.     s_ptr->label_y = s_ptr->window_y + menu->s_fnt_info->max_bounds.ascent + menu->s_fnt_pad + menu->s_bdr_width;
  767.     
  768.     /*
  769.      * All went well, return successfully.
  770.      */
  771.     _XMErrorCode = XME_NO_ERROR;
  772.     return(_SUCCESS);
  773. }
  774.  
  775.  
  776.  
  777. /*
  778.  * _XMTransToOrigin - Internal subroutine to translate the point at
  779.  *              the center of the current pane and selection to the 
  780.  *              the menu origin.
  781.  *
  782.  *    WARNING! ******    Be certain that all menu depencies have been
  783.  *            recomputed before calling this routine or
  784.  *            unpredictable results will follow.
  785.  */
  786. _XMTransToOrigin(display, menu, p_ptr, s_ptr, x_pos, y_pos, orig_x, orig_y)
  787.     Display *display;        /* Not used. Included for consistency. */
  788.     register XMenu *menu;    /* Menu being computed against. */
  789.     register XMPane *p_ptr;    /* Current pane pointer. */
  790.     register XMSelect *s_ptr;    /* Current selection pointer. */
  791.     int x_pos;            /* X coordinate of point to translate. */
  792.     int y_pos;            /* Y coordinate of point to translate. */
  793.     int *orig_x;        /* Return value X coord. of the menu origin. */
  794.     int *orig_y;        /* Return value Y coord. of the menu origin. */
  795. {
  796.     register int l_orig_x;    /* Local X coordinate of the menu origin. */
  797.     register int l_orig_y;    /* Local Y coordinate of the menu origin. */
  798.     
  799.     /*
  800.      * Translate the menu origin such that the cursor hot point will be in the
  801.      * center of the desired current selection and pane.
  802.      * If the current selection pointer is NULL then assume that the hot point
  803.      * will be in the center of the current pane flag.
  804.      */
  805.  
  806.     if (s_ptr == NULL) {
  807.     /*
  808.      * Translate from the center of the pane flag to the upper left
  809.      * of the current pane window.
  810.      */
  811.     l_orig_x = x_pos - (menu->p_width >> 1) - menu->p_bdr_width;
  812.     l_orig_y = y_pos - (menu->flag_height >> 1) - menu->p_bdr_width;
  813.     }
  814.     else {
  815.     /*
  816.      * First translate from the center of the current selection
  817.      * to the upper left of the current selection window.
  818.      */
  819.     l_orig_x = x_pos - (menu->s_width >> 1);
  820.     l_orig_y = y_pos - (menu->s_height >> 1);
  821.  
  822.     /*
  823.      * Then translate to the upper left of the current pane window.
  824.      */
  825.     l_orig_x -= (s_ptr->window_x + menu->p_bdr_width);
  826.     l_orig_y -= (s_ptr->window_y + menu->p_bdr_width);
  827.     }
  828.  
  829.     /*
  830.      * Finally translate to the upper left of the menu.
  831.      */
  832.     l_orig_x -= (p_ptr->window_x - menu->x_pos);
  833.     l_orig_y -= (p_ptr->window_y - menu->y_pos);
  834.  
  835.     /*
  836.      * Set the return values.
  837.      */
  838.     *orig_x = l_orig_x;
  839.     *orig_y = l_orig_y;
  840. }
  841.  
  842. /*
  843.  * _XMRefreshPane - Internal subroutine to completely refresh
  844.  *            the contents of a pane.
  845.  */
  846. _XMRefreshPane(display, menu, pane)
  847.     register Display *display;
  848.     register XMenu *menu;
  849.     register XMPane *pane;
  850. {
  851.     register XMSelect *s_list = pane->s_list;
  852.     register XMSelect *s_ptr;
  853.  
  854.     /*
  855.      * First clear the pane. 
  856.      */
  857.     XClearWindow(display, pane->window);
  858.     if (!pane->activated) {
  859.     XFillRectangle(display,
  860.                pane->window,
  861.                menu->inverse_select_GC,
  862.                pane->label_x - menu->p_fnt_pad,
  863.                pane->label_uy - menu->p_fnt_info->max_bounds.ascent - menu->p_fnt_pad,
  864.                pane->label_width + (menu->p_fnt_pad << 1),
  865.                menu->flag_height);
  866.  
  867.     XFillRectangle(display,
  868.                pane->window,
  869.                menu->inverse_select_GC,
  870.                pane->label_x - menu->p_fnt_pad,
  871.                pane->label_ly - menu->p_fnt_info->max_bounds.ascent - menu->p_fnt_pad,
  872.                pane->label_width + (menu->p_fnt_pad << 1),
  873.                menu->flag_height);
  874.     }
  875.     if (!pane->active) {
  876.     XDrawString(display,
  877.             pane->window,
  878.             menu->inact_GC,
  879.             pane->label_x, pane->label_uy,
  880.             pane->label, pane->label_length);
  881.     XDrawString(display,
  882.             pane->window,
  883.             menu->inact_GC,
  884.             pane->label_x, pane->label_ly,
  885.             pane->label, pane->label_length);
  886.     }
  887.     else {
  888.     XDrawString(display,
  889.              pane->window,
  890.              menu->pane_GC,
  891.              pane->label_x, pane->label_uy,
  892.              pane->label, pane->label_length);
  893.     XDrawString(display,
  894.              pane->window,
  895.              menu->pane_GC,
  896.              pane->label_x, pane->label_ly,
  897.              pane->label, pane->label_length);
  898.  
  899.     /*
  900.      * Finally refresh each selection if the pane is activated.
  901.      */
  902.     if (pane->activated) {
  903.         for (s_ptr = s_list->next; s_ptr != s_list; s_ptr = s_ptr->next)
  904.         _XMRefreshSelection(display, menu, s_ptr);
  905.     }
  906.     }
  907. }
  908.     
  909.     
  910.  
  911.  
  912. /*
  913.  * _XMRefreshSelection - Internal subroutine that refreshes 
  914.  *             a single selection window.
  915.  */
  916. _XMRefreshSelection(display, menu, select)
  917.     register Display *display;
  918.     register XMenu *menu;
  919.     register XMSelect *select;
  920. {
  921.     register int width = select->window_w;
  922.     register int height = select->window_h;
  923.     register int bdr_width = menu->s_bdr_width;
  924.     
  925.     if (select->activated) {
  926.     if (menu->menu_mode == INVERT) {
  927.         XFillRectangle(display, 
  928.                select->parent_p->window,
  929.                menu->normal_select_GC,
  930.                select->window_x, select->window_y,
  931.                width, height); 
  932.         XDrawString(display,
  933.             select->parent_p->window,
  934.             menu->inverse_select_GC,
  935.             select->label_x,
  936.             select->label_y,
  937.             select->label, select->label_length);
  938.     }
  939.         else {
  940.             /*
  941.          * Using BOX mode.
  942.              * Since most drawing routines with arbitrary width lines
  943.          * are slow compared to raster-ops lets use a raster-op to
  944.          * draw the boxes.
  945.              */
  946.         
  947.         XDrawRectangle(display,
  948.                select->parent_p->window,
  949.                menu->normal_select_GC,
  950.                select->window_x + (bdr_width >> 1),
  951.                select->window_y + (bdr_width >> 1 ),
  952.                width - bdr_width,
  953.                height - bdr_width);
  954.         XDrawString(display,
  955.             select->parent_p->window,
  956.             menu->normal_select_GC,
  957.             select->label_x,
  958.             select->label_y,
  959.             select->label, select->label_length);
  960.         }
  961.     }
  962.     else {
  963.     XClearArea(display, 
  964.            select->parent_p->window,
  965.            select->window_x, select->window_y,
  966.            width, height,
  967.            False);
  968.     if (select->active) {
  969.         XDrawString(display,
  970.             select->parent_p->window,
  971.             menu->normal_select_GC,
  972.             select->label_x,
  973.             select->label_y,
  974.             select->label, select->label_length);
  975.     }
  976.     else {
  977.         XDrawString(display,
  978.             select->parent_p->window,
  979.             menu->inact_GC,
  980.             select->label_x,
  981.             select->label_y,
  982.             select->label, select->label_length);
  983.     }
  984.     }
  985. }
  986.  
  987.