home *** CD-ROM | disk | FTP | other *** search
/ Encyclopedia of Graphics File Formats Companion / GFF_CD.ISO / software / unix / saoimage / sao1_07.tar / btnlib / event.c < prev    next >
C/C++ Source or Header  |  1990-04-21  |  18KB  |  475 lines

  1. #ifndef lint
  2. static char SccsId[] = "%W%  %G%";
  3. #endif
  4.  
  5. /*
  6.  * Module:    event.c (Event Control)
  7.  * Project:    PROS -- ROSAT RSDC
  8.  * Purpose:    Field buttonbox events
  9.  * Subroutines:    ButtonEvent()            returns: int
  10.  * Subroutines:    static btn_Event()        returns: int
  11.  * Subroutines:    ButtonControl()            returns: int
  12.  * Subroutines:    static btn_Control()        returns: int
  13.  * Subroutine:    ButtonSelectMask        returns: int
  14.  * Xlib calls:    XNextEvent(), XPutBackEvent(), XPending()
  15.  * Xlib calls:    ConnectionNumber (macro)
  16.  * UNIX calls:    Select()
  17.  * Copyright:    1989 Smithsonian Astrophysical Observatory
  18.  *        You may do anything you like with this file except remove
  19.  *        this copyright.  The Smithsonian Astrophysical Observatory
  20.  *        makes no representations about the suitability of this
  21.  *        software for any purpose.  It is provided "as is" without
  22.  *        express or implied warranty.
  23.  * Modified:    {0} Michael VanHilst    initial version        21 March 1989
  24.  *        {1} Jay Travisano (STScI) VMS,IMTOOL changes    10 Nov   1989
  25.  *        {n} <who> -- <does what> -- <when>
  26.  */
  27.  
  28. #include <stdio.h>    /* define stderr, NULL */
  29. #include <X11/Xlib.h>
  30. #include "buttons.h"
  31.  
  32. #define MOUSESTATE (Button1Mask | Button2Mask | Button3Mask)
  33.  
  34. /* STATIC VARIABLES FOR USING UNIX SELECT TO DETECT NON-WINDOW EVENTS */
  35. static int select_flag,  x_mask[2], select_mask[2];
  36. static int select_size=0;
  37.  
  38.  
  39. /*
  40.  * Subroutine:    ButtonEvent
  41.  * Purpose:    Determine if the given event belongs to the button
  42.  *        box hierarchy
  43.  * Returns:    1 if yes this is a button event, 0 if no
  44.  * Called by:    Application program
  45.  * Uses:    btn_Event() below
  46.  * Xlib calls:    none
  47.  * Post-state:    takes no action
  48.  * Method:    Check the event's window to see if it is one of ours.  First
  49.  *        check this box and the branches of active submenus.
  50.  *        Then check on each of this boxes co-horts and do the same
  51.  *        with their active submenus.
  52.  * Note:    Must be called with a buttonbox at the base of the menu tree
  53.  */
  54. int ButtonEvent ( buttonbox, event )
  55.      ButtonBox buttonbox;    /* i: top handle for button menu group */
  56.      XEvent *event;        /* i: pointer to filled event record */
  57. {
  58.   int i;            /* l: loop counter */
  59.   static int btn_Event();
  60.  
  61.   /* is the event in the primary buttonbox (or its sub-menus) */
  62.   if( btn_Event(buttonbox, event) != 0 ) {
  63.     return( 1 );
  64.   } else {
  65.     /* is the event in a co-menu of the primary buttonbox  .. */
  66.     /*   .. (or one of their sub-menus) */
  67.     for( i = 0; i < buttonbox->co_menu_count; i++ ) {
  68.       if( btn_Event(buttonbox->co_menu[i], event) != 0 )
  69.     return( 1 );
  70.     }
  71.   }
  72.   /* none or the above */
  73.   return( 0 );
  74. }
  75.  
  76. /*
  77.  * Subroutine:    btn_Event
  78.  * Purpose:    Determine if the given event belongs to this button box
  79.  *        or a buttonbox in its branches of active submenus.
  80.  * Returns:    1 if yes this is a button event, 0 if no
  81.  * Called by:    ButtonEvent() above, ButtonControl(), btn_Control() below
  82.  * Xlib calls:    none
  83.  * Post-state:    takes no action
  84.  * Method:    Check this buttonbox, then recurse on each active submenu
  85.  *        and co-submenus.
  86.  */
  87. static int btn_Event ( buttonbox, event )
  88.      ButtonBox buttonbox;    /* i: top handle for button menu tree */
  89.      XEvent *event;        /* i: pointer to filled event record */
  90. {
  91.   int i;            /* l: loop counter */
  92.  
  93.   /* go through our window list to find a match */
  94.   for( i = 0; i < buttonbox->window_count; i++ )
  95.     if( event->xany.window == buttonbox->window_list[i] )
  96.       return( 1 );
  97.   /* no?, do we have any submenus?, if yes, try them by recursion */
  98.   if( buttonbox->submenu_count != 0 )
  99.     for( i = 0; i < buttonbox->submenu_count; i++ )
  100.       if( btn_Event(buttonbox->submenu[i], event) != 0 )
  101.     return( 1 );
  102.   /* no?, do we have any cosubmenus?, if yes, try them by recursion */
  103.   if( buttonbox->cosubmenu_count != 0 )
  104.     for( i = 0; i < buttonbox->cosubmenu_count; i++ )
  105.       if( btn_Event(buttonbox->cosubmenu[i], event) != 0 )
  106.     return( 1 );
  107.   return( 0 );
  108. }
  109.  
  110. /*
  111.  * Subroutine:    ButtonControl
  112.  * Purpose:    Check the event for belonging to the button menu or one of its
  113.  *        submenus, and handle button respons appropriately.  Return
  114.  *        code with a button selection event, or the first event which
  115.  *        belongs to the application.
  116.  * Returns:    1 if returns with button selection (response points at data),
  117.  *        0 if X event in "event" is not for this button group
  118.  *        -1 if a non-X event is indicated by UNIX select
  119.  * Called by:    Application program
  120.  * Uses:    btn_Event() above, btn_Control() below
  121.  * Xlib calls:    XPutBackEvent()
  122.  * Pre-state:    An event already in the passed event structure
  123.  * Post-state:    Pointer pointed at by response is set to point at the selected
  124.  *        button's data field on a button response event
  125.  * Post-state:    If status == 1, event will contain either a ButtonPressed or
  126.  *        ButtonReleased for one of the buttons.
  127.  *        If status == 0 event will be an event for the application
  128.  *        If status == -1, event will be of no interest to application
  129.  * Method:    Loop until we have an event which does not belong to any
  130.  *        buttonbox (must be for application) or a button selection is
  131.  *        made.  In each loop, use btn_Event for a quick check to
  132.  *        seek ownership of the event.  When claimed, call btn_Control
  133.  *        to actually field the event.  If btn_Control does not call for
  134.  *        returning, btn_Control will have returned with a new event
  135.  *        and the loop can continue.  If nobody claims the current
  136.  *        event, we must return.
  137.  *        Then check on each of this boxes co-horts and do the same
  138.  *        with their active submenus.
  139.  * Note:    Must be called with a buttonbox at the base of the menu tree
  140.  */
  141. int ButtonControl ( buttonbox, event, response )
  142.      ButtonBox buttonbox;    /* i: top handle for button menu group */
  143.      XEvent *event;        /* i: pointer to filled event record */
  144.      int **response;        /* o: ptr to button data ptr set on response */
  145. {
  146.   int status;        /* o: reason for return code (-1,0,1) */
  147.   int not_found;    /* l: event search status */
  148.   int i;        /* l: loop counter */
  149.   static int btn_Event();
  150.   static int btn_Control();
  151.  
  152.   status = 1;
  153.   *response = NULL;
  154.   while( 1 ) {
  155.     not_found = 1;
  156.     /* is the event in the primary buttonbox (or its sub-menus) */
  157.     if( btn_Event(buttonbox, event) != 0 ) {
  158.       status = btn_Control(buttonbox, event, response);
  159.       not_found = 0;
  160.     } else {
  161.       /* is the event in a co-menu (or one of their sub-menus) */
  162.       for( i = 0; i < buttonbox->co_menu_count; i++ ) {
  163.     if( btn_Event(buttonbox->co_menu[i], event) != 0 ) {
  164.       status = btn_Control(buttonbox->co_menu[i], event, response);
  165.       not_found = 0;
  166.       break;
  167.     }
  168.       }
  169.     }
  170.     /* if current event is nobody's or there is a response, return */
  171.     if( not_found || (status != 0) ) {
  172.       /* if it was fielded but the status is 0, it's a new unclaimed event */
  173. /* if new event is not to be fetched by ButtonControl, do this:
  174.       if( status == 0 )
  175.     XPutBackEvent (event->xany.display, event);
  176. */
  177.       return( status );
  178.     }
  179.   }
  180. }
  181.  
  182. /*
  183.  * Subroutine:    btn_Control
  184.  * Purpose:    Field events until one is not of this button box tree, or
  185.  *        a reportable button event occurs.
  186.  * Returns:    1 on button response (response points at data),
  187.  *        0 if X event not claimed,
  188.  *        -1 on non-X event indicated by UNIX select
  189.  * Called by:    ButtonControl() above
  190.  * Uses:    btn_Event() above, btn_Control() recurses
  191.  * Uses:    btn_PutImage(), btn_DrawButton() in DrawButton.c
  192.  * Uses:    btn_PushButton() in PushButton.c
  193.  * Xlib calls:    XNextEvent(), XPending()
  194.  * UNIX calls:    Select()
  195.  * Pre-state:    An event already in the passed event structure
  196.  * Post-state:    Pointer pointed at by response is set to point at the selected
  197.  *        button's data field on a button response event
  198.  * Post-state:    Possibly a different event in the passed event structure:
  199.  *        either a ButtonPressed or ButtonReleased for one of the
  200.  *        buttons, or an event which must be fielded by the application.
  201.  * Method:    Loop until we have an event which does not belong to any
  202.  *        buttonbox (must be for application) or a button selection is
  203.  *        made.  In each loop, check btn_Event to see if it belongs to
  204.  *        this button box, if not, recurse on submenus and cosubmenus
  205.  *        until one fields it.  If still not, return NULL, else (it
  206.  *        was fielded) get the next event and loop again.
  207.  */
  208. static int btn_Control ( buttonbox, event, response )
  209.      ButtonBox buttonbox;    /* i: top handle for button menu tree */
  210.      XEvent *event;        /* i: pointer to filled event record */
  211.      int **response;        /* o: ptr to button data ptr set on response */
  212. {
  213.   int status;        /* o: reason for return code (-1,0,1) */
  214.   int i;        /* l: loop counter */
  215.   int virgin;        /* l: flag that 1st event was never fielded */
  216.   int not_claimed;    /* l: flag that current event was not fielded */
  217.   int type;        /* l: temp for button response type */
  218.   int id;        /* l: temp for button id */
  219.   int mask[2];        /* l: temp store for select mask (select changes it) */
  220.   static int btn_Event();
  221.   int btn_PushButton();
  222.   void btn_PutImage(), btn_DrawButton(), btn_ReleaseButton();
  223.  
  224.   /* indicate that this is the passed event */
  225.   virgin = 1;
  226.   while( 1 ) {
  227.     not_claimed = 1;
  228.     status = 1;
  229.     /* see if this event belongs to this buttonbox */
  230.     for( i = 0; i <= buttonbox->btn_cnt; i++ ) {
  231.       if( event->xany.window == buttonbox->window_list[i] ) {
  232.     not_claimed = 0;
  233.     break;
  234.       }
  235.     }
  236.     /* if this was an event for an active button, field it */
  237.     if( i < buttonbox->btn_cnt ) {
  238.       switch( event->type ) {
  239.       case EnterNotify:
  240.     /* indicate occupation of this button */
  241.     buttonbox->buttons[i].occupied = 1;
  242.     /* display this button as occupied */
  243.     if( buttonbox->buttons[i].highlight == 0 )
  244.       btn_PutImage(&buttonbox->buttons[i], OFF_IN);
  245.     else
  246.       btn_PutImage(&buttonbox->buttons[i], ON_IN);
  247.     break;
  248.       case LeaveNotify:
  249.     /* if button is down, ignore, we will get another after release */
  250.     if( event->xcrossing.state & MOUSESTATE )
  251.       break;
  252.     /* unindicate occupation of this button */
  253.     buttonbox->buttons[i].occupied = 0;
  254.     /* display this button as unoccupied */
  255.     if( buttonbox->buttons[i].highlight == 0 )
  256.       btn_PutImage(&buttonbox->buttons[i], OFF_OUT);
  257.     else
  258.       btn_PutImage(&buttonbox->buttons[i], ON_OUT);
  259.     break;
  260.       case ButtonPress:
  261.     /* if mouse buttons are down, don't respond */
  262.     if( event->xbutton.state & MOUSESTATE )
  263.       break;
  264.     /* if missed a release (for unknown reason) too late now */
  265.     if( buttonbox->down_mouse_btn >=0 )
  266.       buttonbox->down_mouse_btn = -1;
  267.     /* call the routine to handle the buttonbox response */
  268.     if( btn_PushButton(buttonbox, i, event->xbutton.button,
  269.                event->xbutton.state, 1) ) {
  270.       /* report selection's data to calling routine (if not NO_OP) */
  271.       *response = buttonbox->buttons[i].feel->data;
  272.       return( 1 );
  273.     }
  274.     break;
  275.       case ButtonRelease:
  276.     /* we only care about the release of a known button */
  277.     if( event->xbutton.button != buttonbox->down_mouse_btn )
  278.       break;
  279.     id = buttonbox->down_btn;
  280.     type = buttonbox->buttons[id].feel->function[buttonbox->down_btn_func];
  281.     /* call the routine to handle most of the buttonbox response */
  282.     btn_ReleaseButton(buttonbox, type, id);
  283.     if( type == BTNCoWhile ) {
  284.       /* for a BTNCoWhile report release (already drawn correctly) */
  285.       *response = buttonbox->buttons[id].feel->data;
  286.       return( 1 );
  287.     } else if( (type == BTNWhile) || (type == BTNOneShot) ) {
  288.       /* for a BTNWhile or BTNOneShot draw button */
  289.       btn_DrawButton(&buttonbox->buttons[id]);
  290.       /* for a BTNWhile report release */
  291.       if( type == BTNWhile ) {
  292.         *response = buttonbox->buttons[id].feel->data;
  293.         return( 1 );
  294.       }
  295.     }
  296.     break;
  297.       case Expose:
  298.     /* on an expose window event, redraw the button */
  299.     btn_DrawButton(&buttonbox->buttons[i]);
  300.     break;
  301.       default:
  302.     /* server might send other events, but we are not interested */
  303.     break;
  304.       }
  305.     }
  306.     /* if event is not accounted for and there are submenus, try them */
  307.     if( not_claimed && (buttonbox->submenu_count != 0) ) {
  308.       /* is it one of their events */
  309.       for( i = 0; i < buttonbox->submenu_count; i++ ) {
  310.     /* chance of success small, so do a rapid search first */
  311.     if( btn_Event(buttonbox->submenu[i], event) != 0 ) {
  312.       /* if yes, pass the torch (recurse through submenu) */
  313.       if( (status = btn_Control(buttonbox->submenu[i], event, response))
  314.          != 0 )
  315.         /* got a selection, pass it on */
  316.         return( status );
  317.       not_claimed = 0;
  318.       break;
  319.     }
  320.       }
  321.     }
  322.     /* if event is not accounted for and there are submenus, try them */
  323.     if( not_claimed && (buttonbox->cosubmenu_count != 0) ) {
  324.       /* is it one of their events */
  325.       for( i = 0; i < buttonbox->cosubmenu_count; i++ ) {
  326.     /* chance of success small, so do a rapid search first */
  327.     if( btn_Event(buttonbox->cosubmenu[i], event) != 0 ) {
  328.       /* if yes, pass the torch (recurse through cosubmenu) */
  329.       if( (status = btn_Control(buttonbox->cosubmenu[i], event, response))
  330.           != 0 )
  331.         /* got a selection, pass it on */
  332.         return( status );
  333.       not_claimed = 0;
  334.       break;
  335.     }
  336.       }
  337.     }
  338.     /* if this event was not claimed, return status 0 */
  339.     if( not_claimed ) {
  340.       /* (Debug check) if we were called with someone else's event, shame! */
  341.       if( virgin != 0 ) {
  342.     (void)fprintf(stderr,
  343.               "WARNING: buttonbox called with unexpected event.\n");
  344.     (void)fprintf(stderr, "  event window= %x, event type = %x\n", 
  345.               event->xany.window, event->type);
  346.       }
  347.       return( 0 );
  348.     }
  349.     /* if no btn_Control call has fetched next event (event fielded here) */
  350.     if( status != 0 ) {
  351.       /* get next event */
  352.       if( select_flag ) {
  353.     /* if events may be non-X UNIX events, don't block on XNextEvent */
  354.     if( XPending(buttonbox->display) ) {
  355.       /* if an event is already pending, get it as X event */
  356.       XNextEvent(buttonbox->display, event);
  357.     } else {
  358. #ifndef VMS
  359.       /* block on UNIX select (returns on X or other events) */
  360.       /* set mask to screen events */
  361.       mask[0] = select_mask[0];
  362.       mask[1] = select_mask[1];
  363.  
  364.       if( select(select_size, mask,
  365.              (int *)0, (int *)0, (struct timeval *)0) <0 )
  366.         perror("select error");
  367.       /* both masks have only one bit, look for match */
  368.       if( (mask[0] & x_mask[0]) || (mask[1] & x_mask[1]) ) {
  369.         /* if event was X event, get it and loop */
  370.         XNextEvent(buttonbox->display, event);
  371.       } else {
  372.         /* if event was not X event, return special status code */
  373.         return( -1 );
  374.       }
  375. #else
  376.       return( -1 );
  377. #endif
  378.     }
  379.       } else {
  380.     /* if only X events are expected, block waiting for next then loop */
  381. #if VMS && IMTOOL
  382.     if( ! XPending (buttonbox->display) )
  383.       return( -1 );
  384. #endif
  385.     XNextEvent(buttonbox->display, event);
  386.       }
  387.     }
  388.     /* note that this is no longer the passed event */
  389.     virgin = 0;
  390.   } /* while( 1 ) loop */
  391. }
  392.  
  393. #ifndef VMS
  394.  
  395. /*
  396.  * Subroutine:    ButtonSelectMask
  397.  * Purpose:    Set a UNIX select mask for event detecting by ButtonControl.
  398.  * Returns:    1 if select flag was set, 0 if select flag could not be set
  399.  * Called by:    Application
  400.  * Xlib calls:    ConnectionNumber (macro)
  401.  * Pre-state:    Application has set mask that is passed
  402.  * Post-state:    Static variables accesible to ButtonControl are set
  403.  * Exception:    Display file descriptors are legal under newer UNIX's but not
  404.  *        accomodated here.
  405.  * Notes:    UNIX select blocks until an event (usually a pending message)
  406.  *        matching a select mask bit occurs.  XNextEvent() calls select
  407.  *        with only its display connection message bit.  It does not
  408.  *        return on other events.  By doing our own select and only
  409.  *        calling XNextEvent when we know that it has an event for
  410.  *        select, we avoid this problem.  When a non-X event is detected,
  411.  *        ButtonControl returns control to the application with a -1
  412.  *        status flag.  Select bits are cleared by reading from the
  413.  *        flagging file descriptor or closing it.
  414.  */
  415. int ButtonSelectMask ( display, setmask, size, set )
  416.      Display *display;    /* i: display connection for X events */
  417.      int *setmask;    /* i: array of mask ints set for other events */
  418.      int size;        /* i: number of bits used for select mask */
  419.      int set;        /* i: 1=set mask, else clear mask */
  420. {
  421.   int xchan;        /* l: file descriptor for X display (the bit offset) */
  422.  
  423.   /* if setting select mask for first time, install X server's mask */
  424.   if( select_size == 0 ) {
  425.     xchan = ConnectionNumber(display);
  426.     if( xchan < 32 ) {
  427.       x_mask[0] = (1 << xchan);
  428.       x_mask[1] = 0;
  429.       select_size = 32;
  430.     } else {
  431.       x_mask[0] = 0;
  432.       x_mask[1] = (1 << (xchan - 32));
  433.       /* set number of bits for file descriptors to that of system */
  434.       /* select_size = getdtablesize();
  435.        * hardwire it since SYSV systems lack a call to know */
  436.       select_size = 64;
  437.     }
  438.     select_mask[0] = x_mask[0];
  439.     select_mask[1] = x_mask[1];
  440.   }
  441.   if( set ) {
  442.     select_mask[0] |= setmask[0];
  443.     if( size > 32 ) {
  444.       select_mask[1] |= setmask[1];
  445.       if( select_size < size )
  446.     select_size = size;
  447.     }
  448.   } else {
  449.     if( (setmask[0] != 0) && (setmask[0] != x_mask[0]) )
  450.       select_mask[0] &= (~(setmask[0]));
  451.     if( (size > 32) && (setmask[1] != 0) && ((setmask[1] != x_mask[1])) )
  452.       select_mask[1] &= (~(setmask[1]));
  453.   }
  454.   if( (select_mask[0] != x_mask[0]) || (select_mask[1] != x_mask[1]) )
  455.     select_flag = 1;
  456.   else
  457.     select_flag = 0;
  458.   return( select_flag );
  459. }
  460.  
  461. #endif
  462.       
  463.                                                                
  464.                                                                
  465.                                                               
  466.  
  467.                                                                
  468.                                                                
  469.                                                                
  470.                                                                
  471.                                                                
  472.                                                                
  473.                                                                
  474.                                        
  475.