home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / stdwin / Ports / x11 / llevent.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-28  |  8.7 KB  |  377 lines  |  [TEXT/????]

  1. /* X11 STDWIN -- Low-level event handling */
  2.  
  3. #include "x11.h"
  4. #include "llevent.h"
  5. #include <X11/keysym.h>
  6.  
  7. /* Double-click detection parameters */
  8.  
  9. #define DCLICKTIME    500
  10. #define DCLICKDIST    5
  11.  
  12. /* Events are handled in two phases.
  13.    There is low-level event handling which can be called at any time
  14.    and will only set various flags (global and in windows) indicating
  15.    changed circumstances.  This kind of event handling goes on even
  16.    while we are locked in a dialog box.
  17.    There is high-level event handling which passes the results of the
  18.    low-level handling to the application in request to a call to
  19.    'wgetevent'.
  20.    This file contains the low-level event handling. */
  21.  
  22.  
  23. /* Low-level event handler.
  24.    Data items set for use by higher-level event handler include:
  25.    
  26.    - the 'new active window' pointer
  27.    - the 'dirty' flags for all windows and subwindows
  28.    - the 'size changed' flags for all top-level windows
  29.    
  30.    These can be accumulated; the net effect of all such events is
  31.    correctly remembered.  The following data items are also set but need
  32.    to be checked after each call, since they are not queued:
  33.    
  34.    - the mouse button state
  35.    - the 'last-key-pressed' variable
  36.    
  37.    Mouse moves may be ignored, however.
  38.    The state change flags must be be reset by the higher-level event
  39.    handler after the changes have been noted. */
  40.  
  41. WINDOW *_w_new_active;        /* New active window */
  42. struct button_state _w_bs;    /* Mouse button state */
  43. KeySym _w_keysym;        /* Keysym of last non-modifier key pressed */
  44. int _w_state;            /* Modifiers in effect at key press */
  45.  
  46. bool _w_moved;            /* Set if button moved */
  47. bool _w_bs_changed;        /* Set if button up/down state changed */
  48. bool _w_dirty;            /* Set if any window needs a redraw */
  49. bool _w_resized;        /* Set if any window resized */
  50. bool _w_focused;        /* Set if between FocusIn and FocusOut */
  51. Time _w_lasttime = CurrentTime;    /* Last timestamp received in an event */
  52. WINDOW *_w_close_this;        /* Window to close (WM_DELETE_WINDOW) */
  53.  
  54. _w_ll_event(e)
  55.     XEvent *e;
  56. {
  57.     WINDOW *win;
  58.     
  59.     _wdebug(6, "_w_ll_event: event type %ld", e->type);
  60.     
  61.     win = _whichwin(e->xkey.window);
  62.     if (win == NULL) {
  63.         _wdebug(6, "_w_ll_event: event not for any window -- ignore");
  64.         return;
  65.     }
  66.     
  67.     switch (e->type) {
  68.     
  69.     /* Keyboard */
  70.     
  71.     case KeyPress:
  72.         _w_lasttime = e->xkey.time;
  73.         activate(win);
  74.         ll_key(&e->xkey, win);
  75.         break;
  76.     
  77.     case MappingNotify:
  78.         XRefreshKeyboardMapping(&e->xmapping);
  79.         break;
  80.     
  81.     /* Buttons */
  82.     
  83.     case MotionNotify:
  84. #ifndef DONT_COMPRESS_MOTION /* XXX should be a resource option instead */
  85.         /* Compress motion events */
  86.         while (XPending(_wd) > 0) {
  87.             XEvent e2;
  88.             XPeekEvent(_wd, &e2);
  89.             if (e2.type == MotionNotify &&
  90.                 e2.xmotion.window == e->xmotion.window &&
  91.                 e2.xmotion.subwindow == e->xmotion.subwindow) {
  92.                 /* replace current event with next one */
  93.                 XNextEvent(_wd, e);
  94.             }
  95.             else
  96.                 break;
  97.         }
  98. #endif
  99.         /* Fall through */
  100.     case ButtonPress:
  101.     case ButtonRelease:
  102.         _w_lasttime = e->xbutton.time;
  103.         ll_button(&e->xbutton, win);
  104.         break;
  105.     
  106.     /* Exposures */
  107.     
  108.     case GraphicsExpose:
  109.         _wdebug(3, "GraphicsExpose event:");
  110.     case Expose:
  111.         ll_expose(&e->xexpose, win);
  112.         break;
  113.     
  114.     /* Structure changes */
  115.     
  116.     case ConfigureNotify:
  117.         ll_configure(&e->xconfigure, win);
  118.         break;
  119.     
  120.     /* Input focus changes */
  121.     
  122.     case FocusIn:
  123.         _w_focused= TRUE;
  124.         activate(win);
  125.         break;
  126.     
  127.     case FocusOut:
  128.         _w_focused= FALSE;
  129.         deactivate(win);
  130.         break;
  131.     
  132.     case EnterNotify:
  133.         _w_lasttime = e->xcrossing.time;
  134.         if (!_w_focused && e->xcrossing.focus)
  135.             activate(win);
  136.         break;
  137.     
  138.     case LeaveNotify:
  139.         _w_lasttime = e->xcrossing.time;
  140.         if (!_w_focused && e->xcrossing.detail != NotifyInferior &&
  141.                 e->xcrossing.focus)
  142.             deactivate(win);
  143.         break;
  144.     
  145.     /* ICCCM */
  146.     
  147.     case ClientMessage:
  148.         _wdebug(2,
  149.             "ClientMessage, type=%ld, send_event=%ld, format=%ld",
  150.             e->xclient.message_type,
  151.             e->xclient.send_event,
  152.             e->xclient.format);
  153.         if (e->xclient.message_type == _wm_protocols) {
  154.             _wdebug(2, "It's a WM_PROTOCOLS ClientMessage (%ld)",
  155.                 e->xclient.data.l[0]);
  156.             _w_lasttime = e->xclient.data.l[1];
  157.         }
  158.         else {
  159.             _wdebug(1, "Unexpected ClientMessage ignored (%ld)",
  160.                 e->xclient.message_type);
  161.             break;
  162.         }
  163.         if (e->xclient.data.l[0] == _wm_delete_window) {
  164.             _wdebug(1, "WM_DELETE_WINDOW");
  165.             _w_close_this = win;
  166.         }
  167.         else {
  168.             _wdebug(1,
  169.                 "Unexpected WM_PROTOCOLS ClientMessage (%ld)",
  170.                 e->xclient.data.l[0]);
  171.         }
  172.         break;
  173.     
  174.     case SelectionRequest:
  175.         _w_selectionreply(
  176.             e->xselectionrequest.owner,
  177.             e->xselectionrequest.requestor,
  178.             e->xselectionrequest.selection,
  179.             e->xselectionrequest.target,
  180.             e->xselectionrequest.property,
  181.             e->xselectionrequest.time);
  182.         break;
  183.     
  184.     case SelectionClear:
  185.         _w_selectionclear(e->xselectionclear.selection);
  186.         break;
  187.     
  188.     case MapNotify:
  189.         /* Ignore this */
  190.         break;
  191.     
  192.     default:
  193.         _wdebug(1, "unexpected event type %d", e->type);
  194.     
  195.     }
  196. }
  197.  
  198. static
  199. activate(win)
  200.     WINDOW *win;
  201. {
  202.     if (_w_new_active != win) {
  203.         if (_w_new_active != NULL)
  204.             deactivate(_w_new_active);
  205.         _w_new_active= win;
  206.         if (win != NULL)
  207.             XSetWindowBorder(_wd, win->wo.wid, win->fgo);
  208.     }
  209. }
  210.  
  211. static
  212. deactivate(win)
  213.     WINDOW *win;
  214. {
  215.     if (win == _w_new_active) {
  216.         _w_new_active= NULL;
  217.         if (win != NULL)
  218.             _w_setgrayborder(win);
  219.     }
  220. }
  221.  
  222. static
  223. ll_key(e, win)
  224.     XKeyEvent *e;
  225.     WINDOW *win;
  226. {
  227.     char sbuf[1];
  228.     
  229.     _wdebug(6, "keycode %d, state 0x%x", e->keycode, e->state);
  230.     if (XLookupString(e, sbuf, 1, &_w_keysym, (XComposeStatus*)NULL) > 0)
  231.         _w_keysym= sbuf[0];
  232.     else if (IsModifierKey(_w_keysym))
  233.         _w_keysym= 0;
  234.     _w_state= e->state;
  235. }
  236.  
  237. /* Update button status, given a Button or Motion event.
  238.    THIS ASSUMES BUTTON AND MOTION EVENTS HAVE THE SAME LAY-OUT! */
  239.  
  240. static
  241. ll_button(e, win)
  242.     XButtonEvent *e;
  243.     WINDOW *win;
  244. {
  245.     Window w= e->window;
  246.     
  247.     /* This code is ugly.  I know. */
  248.     
  249.     if (!_w_bs.down) { /* New sequence */
  250.         if (e->type != ButtonPress) {
  251.             /* Button moved/release event while we've never
  252.                received a corresponding press event.
  253.                I suspect this is a server bug;
  254.                normally I never reach this code, but sometimes
  255.                it happens continually.  Why?... */
  256.             _wdebug(5,
  257.                 "ll_button: spurious button move/release %d",
  258.                 e->type);
  259.             return;
  260.         }
  261.         else {
  262.             bool isdclick= FALSE;
  263.             _w_bs.down= TRUE;
  264.             _w_bs_changed= TRUE;
  265.             if (_w_bs.button == e->button &&
  266.                     _w_bs.w == e->window) {
  267.                 /* Multiple-click detection; must be done
  268.                    before setting new values */
  269.                 if (e->time <= _w_bs.time + DCLICKTIME) {
  270.                     int dx= e->x - _w_bs.x;
  271.                     int dy= e->y - _w_bs.y;
  272.                     isdclick= (dx*dx + dy*dy <=
  273.                         DCLICKDIST*DCLICKDIST);
  274.                 }
  275.             }
  276.             if (!isdclick)
  277.                 _w_bs.clicks= 0;
  278.             ++_w_bs.clicks;
  279.             _w_bs.mask= e->state;
  280.             _w_bs.button= e->button;
  281.             _w_bs.time= e->time;
  282.             _w_bs.win= win;
  283.             _w_bs.w= w;
  284.             for (_w_bs.isub= NSUBS; --_w_bs.isub >= 0; ) {
  285.                 if (w == win->subw[_w_bs.isub].wid)
  286.                     break;
  287.             }
  288.             if (_w_bs.isub < 0) {
  289.                 _wdebug(0, "ll_button: can't find subwin");
  290.                 _w_bs.isub= 0;
  291.                 return;
  292.             }
  293.             _w_bs.x= _w_bs.xdown= e->x;
  294.             _w_bs.y= _w_bs.ydown= e->y;
  295.         }
  296.     }
  297.     else { /* Continue existing sequence */
  298.         if (win == _w_bs.win && w != _w_bs.w) {
  299.             /* Maybe changed between mbar and mwin? */
  300.             if (_w_bs.isub == MBAR && w == win->mwin.wid) {
  301.                 /* Change it -- because of XGrabPointer */
  302.                 _wdebug(3, "MBAR grabbed button");
  303.                 _w_bs.isub = MWIN;
  304.                 _w_bs.w = w;
  305.             }
  306.         }
  307.         if (win != _w_bs.win || w != _w_bs.w) {
  308.             /* XXX This still happens -- why? */
  309.             _wdebug(0, "ll_button: inconsistent _w_bs");
  310.             _w_bs.down= FALSE;
  311.             _w_bs.mask= 0;
  312.             _w_bs_changed= TRUE;
  313.         }
  314.         else {
  315.             _w_bs.mask= e->state;
  316.             _w_bs.x= e->x;
  317.             _w_bs.y= e->y;
  318.             _w_bs.time= e->time;
  319.             if (e->type == ButtonRelease &&
  320.                 e->button == _w_bs.button) {
  321.                 _w_bs.down= FALSE;
  322.                 _w_bs_changed= TRUE;
  323.             }
  324.             else
  325.                 _w_moved= TRUE;
  326.         }
  327.     }
  328.     _wdebug(5, "ll_button: xy=(%d, %d), down=%d, clicks=%d",
  329.         _w_bs.x, _w_bs.y, _w_bs.down, _w_bs.clicks);
  330. }
  331.  
  332. static
  333. ll_expose(e, win)
  334.     XExposeEvent *e;
  335.     WINDOW *win;
  336. {
  337.     Window w= e->window;
  338.     
  339.     _wdebug(3, "ll_expose called, count=%d, x=%d,y=%d,w=%d,h=%d",
  340.         e->count, e->x, e->y, e->width, e->height);
  341.     if (w == win->wa.wid)
  342.         wchange(win, e->x, e->y, e->x + e->width, e->y + e->height);
  343.     else if (w == win->mbar.wid)
  344.         win->mbar.dirty= TRUE;
  345.     else if (w == win->hbar.wid)
  346.         win->hbar.dirty= TRUE;
  347.     else if (w == win->vbar.wid)
  348.         win->vbar.dirty= TRUE;
  349.     else {
  350.         _wdebug(3, "ll_expose: uninteresting event");
  351.         return;
  352.     }
  353.     if (e->count == 0)
  354.         _w_dirty= TRUE;
  355. }
  356.  
  357. static
  358. ll_configure(e, win)
  359.     XConfigureEvent *e;
  360.     WINDOW *win;
  361. {
  362.     if (e->window != win->wo.wid) {
  363.         _wdebug(0, "ll_configure: not for wo.wid");
  364.         return;
  365.     }
  366.     win->wo.x= e->x + e->border_width;
  367.     win->wo.y= e->y + e->border_width;
  368.     win->wo.border= e->border_width;
  369.     if (win->wo.width != e->width || win->wo.height != e->height) {
  370.         /* Size changed */
  371.         win->wo.width= e->width;
  372.         win->wo.height= e->height;
  373.         _wmovesubwins(win);
  374.         win->resized= _w_resized= TRUE;
  375.     }
  376. }
  377.