home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / yacl-012.zip / ui / os2evt.cxx < prev    next >
C/C++ Source or Header  |  1995-04-07  |  16KB  |  467 lines

  1.  
  2.  
  3.  
  4.  
  5. /*
  6.  *
  7.  *          Copyright (C) 1994, M. A. Sridhar
  8.  *  
  9.  *
  10.  *     This software is Copyright M. A. Sridhar, 1994. You are free
  11.  *     to copy, modify or distribute this software  as you see fit,
  12.  *     and to use  it  for  any  purpose, provided   this copyright
  13.  *     notice and the following   disclaimer are included  with all
  14.  *     copies.
  15.  *
  16.  *                        DISCLAIMER
  17.  *
  18.  *     The author makes no warranties, either expressed or implied,
  19.  *     with respect  to  this  software, its  quality, performance,
  20.  *     merchantability, or fitness for any particular purpose. This
  21.  *     software is distributed  AS IS.  The  user of this  software
  22.  *     assumes all risks  as to its quality  and performance. In no
  23.  *     event shall the author be liable for any direct, indirect or
  24.  *     consequential damages, even if the  author has been  advised
  25.  *     as to the possibility of such damages.
  26.  *
  27.  */
  28.  
  29. #if defined(__GNUC__)
  30. #pragma implementation
  31. #endif
  32.  
  33. // Support for event handling under OS/2
  34. #include "ui/cntroler.h"
  35. #include "ui/timer.h"
  36. #include "ui/menu.h"
  37.  
  38. #include <string.h>
  39.  
  40. static struct {
  41.     ulong         message;
  42.     UI_EventType  yaclEvent;
  43. } TransTable [] = {
  44.     WM_BUTTON1DOWN,         Event_LButtonPress,
  45.     WM_BUTTON2DOWN,         Event_MButtonPress,
  46.     WM_BUTTON3DOWN,         Event_RButtonPress,
  47.     WM_BUTTON1UP,           Event_LButtonRelease,
  48.     WM_BUTTON2UP,           Event_MButtonRelease,
  49.     WM_BUTTON3UP,           Event_RButtonRelease,
  50.     WM_BUTTON1DBLCLK,       Event_LButtonDblClk,
  51.     WM_BUTTON2DBLCLK,       Event_MButtonDblClk,
  52.     WM_BUTTON3DBLCLK,       Event_RButtonDblClk,
  53.     WM_CHAR,                Event_KeyTyped,
  54.     WM_CLOSE,               Event_CloseDown,
  55.     WM_DESTROY,             Event_Quit,
  56.     WM_MENUEND,             Event_LoseFocus,
  57.     WM_MENUSELECT,          Event_GetFocus,
  58.     WM_MOVE,                Event_Reconfigure,
  59.     WM_MOUSEMOVE,           Event_MouseMove,
  60.     WM_PAINT,               Event_Paint,
  61.     WM_SETFOCUS,            Event_GetFocus,
  62.     WM_SIZE,                Event_Reconfigure,
  63.     0,                      Event_Other
  64. };
  65.  
  66.  
  67.  
  68. bool UI_Controller::_DoOneEvent (NativeEventStruct& qMsg)
  69. {
  70.     UI_Event e (Event_None, NULL);
  71.     if (TranslateNativeEvent (qMsg, e) &&
  72.         e._origin->WindowClass() != NULL &&
  73.         // The window class is null for menu items. The menu item events
  74.         // are dispatched from the WindowProc.
  75.         e._origin->WindowClass() != _YACLWindowClassName &&
  76.         // ---------------------^^^^ ------------------
  77.         // Note that we compare pointers, not strings. We cannot
  78.         // compare strings, because OS/2's built-in window classes
  79.         // return invalid pointers as window classes. This check is
  80.         // needed because events targeted at a YACLWindow are dispatched
  81.         // from YACLWindowProc.
  82.         (e._type != Event_KeyTyped || e.key != '\011') &&
  83.         // Another hack, to prevent tabs from being dispatched. They
  84.         // should be dispatched from YACLWindowProc.
  85.         (!_eventFilter || _eventFilter->Execute (e, 0)))
  86.         DispatchNativeEvent (e);
  87.     if (_termination && _termination->Execute (e, 0))
  88.         return FALSE;
  89.     DispatchSoftEvents ();
  90.     return TRUE;
  91. }
  92.  
  93.  
  94. bool UI_Controller::ProcessNativeEvents ()
  95. {
  96.     NativeEventStruct qMsg;
  97.     while (_root && WinGetMsg (_hab, &qMsg, NULLHANDLE, 0, 0)) {
  98.         WinDispatchMsg (_hab, &qMsg);
  99.         if (!_DoOneEvent (qMsg))
  100.             return FALSE;
  101.     }
  102.     return TRUE;
  103. }
  104.  
  105. void UI_Controller::FlushEventQueue ()
  106. {
  107.     NativeEventStruct qMsg;
  108.     while (_root && WinPeekMsg (_hab, &qMsg, NULLHANDLE, 0, 0, PM_REMOVE));
  109. }
  110.  
  111.  
  112.  
  113. void UI_Controller::DispatchPendingEvents ()
  114. {
  115.     DispatchSoftEvents ();
  116.     NativeEventStruct qMsg;
  117.     while (_root && WinPeekMsg (_hab, &qMsg, NULLHANDLE, 0, 0, PM_REMOVE)) {
  118.         WinDispatchMsg (_hab, &qMsg);
  119.         if (!_DoOneEvent (qMsg))
  120.             break;
  121.     }
  122. }
  123.  
  124.  
  125.  
  126. bool UI_Controller::DispatchNativeEvent ( UI_Event& e )
  127. {
  128.     if (!_root)
  129.         return TRUE;
  130.     switch (e.Type()) {
  131.     case Event_MouseMove:
  132.         if ( _current != e.Destination () ) {
  133.             // The mouse entered a different visual obj
  134.             if ( _current ) {
  135.                 UI_Event leave (Event_ViewLeave, _current);
  136.                 DispatchEvent (&leave);
  137.             }
  138.             _current = e.Destination ();
  139.             UI_Event enter (Event_ViewEnter, e.Destination ());
  140.             DispatchEvent (&enter);
  141.         }
  142.         break;
  143.  
  144.     default:
  145.         break;
  146.     }
  147.     return DispatchEvent (&e);
  148. }
  149.  
  150.  
  151.  
  152. bool UI_Controller::TranslateNativeEvent (NativeEventStruct& msg, UI_Event& e)
  153. {
  154.     e._nativeEvent = new NativeEventStruct;
  155.     *(NativeEventStruct*)(e._nativeEvent) = msg;
  156.     e._shiftKey = WinGetKeyState (HWND_DESKTOP, VK_SHIFT) < 0 ? TRUE : FALSE;
  157.     e._ctrlKey  = WinGetKeyState (HWND_DESKTOP, VK_CTRL ) < 0 ? TRUE : FALSE;
  158.     e._metaKey  = WinGetKeyState (HWND_DESKTOP, VK_ALT  ) < 0 ? TRUE : FALSE;
  159.  
  160.     for (short i = 0; TransTable[i].message != 0; i++) {
  161.         if ( TransTable [i].message == msg.msg ) {
  162.             break;
  163.         }
  164.     }
  165.     e._type  = TransTable [i].yaclEvent;
  166.     UI_VisualObject* view = (UI_VisualObject*) _visualObjMap[msg.hwnd];
  167.     switch (msg.msg) {
  168.     case WM_MENUEND: {
  169.         UI_MenuItem* itm = (UI_MenuItem*) _visualObjMap[(ulong) msg.mp2];
  170.         if (itm && itm->ViewID() != FID_MENU) {
  171.             // ----------------^^^^^
  172.             // This is really a hack. For some reason, it sends me a MENUEND
  173.             // message to a root item, and that seems to cause problems.
  174.             UI_Menu& menu = itm->Container();
  175.             UI_MenuItem* focusItem = menu.Focus();
  176.             if (focusItem) {
  177.                 UI_Event evt (Event_LoseFocus, focusItem, focusItem);
  178.                 DispatchEvent (&evt);
  179.             }
  180.             menu.MoveFocusTo (itm);
  181.         }
  182.         view = itm;
  183.         break;
  184.     }
  185.         
  186.     case WM_MENUSELECT: {
  187.         UI_VObjCollection* parent = (UI_VObjCollection*)
  188.             _visualObjMap[msg.hwnd];
  189.         UI_ViewID id = SHORT1FROMMP (msg.mp1);
  190.         UI_MenuItem* itm = parent ? (UI_MenuItem*)(*parent)[id] : NULL;
  191.         if (itm) {
  192.             UI_Menu& menu = itm->Container();
  193.             UI_MenuItem* focusItem = menu.Focus();
  194.             if (focusItem) {
  195.                 UI_Event evt (Event_LoseFocus, focusItem, focusItem);
  196.                 DispatchEvent (&evt);
  197.             }
  198.             menu.MoveFocusTo (itm);
  199.         }
  200.         view = itm;
  201.         break;
  202.     }
  203.         
  204.     case WM_CHAR:
  205.         e.key = SHORT1FROMMP(msg.mp2);
  206.         // PM gives me two WM_CHAR messages (See p. 452 of Petzold's book),
  207.         // so I ignore one of them:
  208.         if (((ulong) msg.mp1) & KC_KEYUP || e.key == 0)
  209.             e._type = Event_Other;
  210.         break;
  211.         
  212.     case WM_BUTTON1DBLCLK:
  213.     case WM_BUTTON2DBLCLK:
  214.     case WM_BUTTON3DBLCLK:
  215.     case WM_BUTTON1DOWN:
  216.     case WM_BUTTON2DOWN:
  217.     case WM_BUTTON3DOWN:
  218.     case WM_BUTTON1UP:
  219.     case WM_BUTTON2UP:
  220.     case WM_BUTTON3UP: {
  221.         POINTL point = msg.ptl;
  222.         WinMapWindowPoints (HWND_DESKTOP, msg.hwnd, &point, 1);
  223.         RECTL rect;
  224.         WinQueryWindowRect (msg.hwnd, &rect);
  225.         e.curPos.Origin (UI_Point (point.x,
  226.                                    rect.yTop - rect.yBottom + 1 - point.y));
  227.         break;
  228.     }
  229.         
  230.     case WM_TIMER: {
  231.         ulong id = SHORT1FROMMP (msg.mp1);
  232.         UI_Timer::DoAlarm (id);
  233.         break;
  234.     }
  235.         
  236.     case WM_COMMAND: {
  237.         UI_ViewID id = SHORT1FROMMP(msg.mp1);
  238.         e._type = Event_Select;
  239.         UI_VObjCollection* parent = (UI_VObjCollection*)
  240.             _visualObjMap[msg.hwnd];
  241.         view = parent ? (*parent)[id] : NULL;
  242.         break;
  243.     }
  244.  
  245.     case WM_CONTROL: {
  246.         UI_ViewID id = SHORT1FROMMP(msg.mp1);
  247.         e._type = Event_Select;
  248.         HWND h = WinWindowFromID (msg.hwnd, id);
  249.         view = (UI_VObjCollection*) _visualObjMap[h];
  250.         ushort code = SHORT2FROMMP(msg.mp1);
  251.         //  if (code == CBN_EFCHANGE || CBN_LBSELECT)
  252.         //      e._type = Event_Select;
  253.         //  else
  254.         //      e._type = (code == BN_CLICKED) ? Event_Select
  255.         //          : Event_LButtonDblClk;
  256.         // The CBN_ messages seem to come before the WM_COMMAND (or is it
  257.         // WM_CONTROL), in fact, even before the selection actually changes.
  258.         // So we can't ask the listbox what its selection is, because it
  259.         // hasn't changed yet.
  260.         e._type = (code == BN_CLICKED) ? Event_Select
  261.             : Event_LButtonDblClk;
  262.         break;
  263.     }
  264.         
  265.     case WM_MOUSEMOVE: {
  266.         short x = SHORT1FROMMP (msg.mp1);
  267.         short y = SHORT2FROMMP (msg.mp1);
  268.         if (view)
  269.             y = view->_shape.Height() - y; // Adjust for the fact that
  270.                                            // OS/2's origin reckoning is
  271.                                            // bottom left, not top left
  272.         e.curPos = UI_Rectangle (x, y, 0, 0);
  273.         e._type = Event_MouseMove;
  274.         break;
  275.     }
  276.  
  277.     case WM_MOVE: {
  278.         if (!view)
  279.             break;
  280.         SWP swp;
  281.         WinQueryWindowPos (msg.hwnd, &swp);
  282.         POINTL newOrigin;
  283.         newOrigin.x = newOrigin.y = 0;
  284.         HWND handle;
  285.         if (_YACLWindowClassName == view->WindowClass()
  286.             // -----------------^^^^ ------------------
  287.             // Note that we compare pointers, not strings. We cannot
  288.             // compare strings, because OS/2's built-in window classes
  289.             // return invalid pointers as window classes.
  290.             && view->_style & FCF_TITLEBAR) {
  291.             UI_CompositeVObject* v = (UI_CompositeVObject*) view;
  292.             HWND prnt = v->_parent ? v->_parent->_handle : HWND_DESKTOP;
  293.             WinMapWindowPoints (msg.hwnd, prnt, &newOrigin, 1);
  294.             handle = WinQueryWindow (v->_handle, QW_PARENT);
  295.                 // Frame handle
  296.         }
  297.         else
  298.             handle = view->_parent ? view->_parent->_handle : HWND_DESKTOP;
  299.         HWND parentHandle  = WinQueryWindow (handle, QW_PARENT);
  300.         UI_Point p (newOrigin.x, _YACLWindowHeight (parentHandle)
  301.                     - newOrigin.y - swp.cy + 1);
  302.         e.curPos = view->_shape;
  303.         e.curPos.Origin (p);
  304.         e._type = Event_Reconfigure;
  305.         break;
  306.     }
  307.         
  308.     case WM_SIZE: {
  309.         SWP swp;
  310.         WinQueryWindowPos (msg.hwnd, &swp);
  311.         // Doesn't seem like there is any good way to tell when a window is
  312.         // maximized, other than catching the WM_SYSCOMMAND. Even if I did
  313.         // that, I wouldn't get the correct co-ordinates -- seems like I
  314.         // always get (4, 28) as top left corner if I use (swp.x, swp.y).
  315.         if (view) {
  316.             e.curPos = UI_Rectangle (view->_shape.Origin(), swp.cx, swp.cy);
  317.         }
  318.         e._type = Event_Reconfigure;
  319.         break;
  320.     }
  321.  
  322. //     case WM_WINDOWPOSCHANGED: {
  323.         // This is not needed, since WM_SIZE gives us the size change.
  324. //         PSWP pSwp = (PSWP) msg.mp1;
  325. //         if (view && pSwp) {
  326. //             HWND parentHandle  = WinQueryWindow (msg.hwnd, QW_PARENT);
  327. //             long y = _YACLWindowHeight (parentHandle) - pSwp->y - pSwp->cy;
  328. //             e.curPos = UI_Rectangle (pSwp->x, y, pSwp->cx, pSwp->cy);
  329. //         }
  330. //         e._type = Event_Reconfigure;
  331. //         break;
  332. //     }
  333.  
  334.         
  335.         
  336.     case WM_VSCROLL:
  337.     case WM_HSCROLL: {
  338.         HWND parent = WinWindowFromID (msg.hwnd, (ushort) msg.mp1);
  339.         view = (UI_VisualObject*) _visualObjMap [parent];
  340.         e.param = SHORT1FROMMP(msg.mp2);
  341.         switch (SHORT2FROMMP (msg.mp2)) {
  342.         case SB_LINEDOWN:
  343.             e._type = Event_ScrollForwardLine;
  344.             break;
  345.  
  346.         case SB_PAGEDOWN:
  347.             e._type = Event_ScrollForwardPage;
  348.             break;
  349.  
  350.         case SB_LINEUP:
  351.             e._type = Event_ScrollBackwardLine;
  352.             break;
  353.  
  354.         case SB_PAGEUP:
  355.             e._type = Event_ScrollBackwardPage;
  356.             break;
  357.  
  358.         case SB_ENDSCROLL:
  359.             e._type = Event_FinishScroll;
  360.             break;
  361.  
  362.         case SB_SLIDERPOSITION:
  363.             e._type = Event_ScrollToPosition;
  364.             break;
  365.  
  366.         case SB_SLIDERTRACK:
  367.             e._type = Event_Scroll;
  368.             break;
  369.         }
  370.         break;
  371.     }
  372.         
  373.     default:
  374.         e.curPos.Origin (UI_Point (msg.ptl.x, msg.ptl.y));
  375.         break;
  376.     }
  377.     e._origin = e._dest = view;
  378.     return view != NULL;
  379. }
  380.  
  381.  
  382. void UI_Controller::_MakeOS2Interface (const UI_Event& e)
  383. {
  384.     UI_VisualObject* origin = e.Origin ();
  385.     if (origin->MakeVisualElement ())
  386.         Register (origin);
  387.     origin->_PrivateInitialize ();
  388.     origin->Initialize ();
  389.     if (origin->WindowClass() == _YACLWindowClassName &&
  390.         origin->ViewHandle () > 0) {
  391.         // Force an initial paint event to be sent
  392.         UI_ViewHandle h = origin->ViewHandle();
  393.         RECTL rect;
  394.         WinQueryWindowRect (h, &rect);
  395.         WinInvalidateRect  (h, &rect, TRUE);
  396.     }
  397. }
  398.  
  399.  
  400. MRESULT EXPENTRY YACLWindowProc (HWND hWnd, ULONG msg, MPARAM p1, MPARAM p2)
  401. {
  402.     MRESULT result = 0;
  403.     // We need to call _DoErase for both ERASEBACKGROUND and PAINT messages,
  404.     // because sometimes PM seems to send me only a PAINT message with no
  405.     // ERASEBACKGROUND before it. However, the PAINT message erases and then
  406.     // does default processing, so it should be ok.
  407.     UI_Controller& ctrlr = _TheApplication->Controller();
  408.     switch (msg) {
  409.     case WM_ERASEBACKGROUND:
  410.         // Return TRUE to cause PM to paint the window background
  411.         // in SYSCLR_WINDOW
  412.         return (MRESULT) TRUE;
  413.  
  414.     case WM_PAINT: {
  415.         RECTL rect;
  416.         HPS hps = WinBeginPaint (hWnd, 0, &rect);
  417.         WinFillRect (hps, &rect, CLR_WHITE);
  418.         WinEndPaint (hps);
  419.         break;
  420.     }
  421.     case WM_CLOSE:
  422.         break;
  423.  
  424.     case WM_MOUSEMOVE: {
  425.         if (ctrlr._inWaitState)
  426.             ctrlr.SetCurrentCursor (ctrlr._defaultCursor);
  427.         else {
  428.             UI_VisualObject* v = ctrlr[hWnd];
  429.             if (v) {
  430.                 UI_Cursor& cursor = v->Cursor();
  431.                 if (cursor != UICursor_Default) {
  432.                     ctrlr.SetCurrentCursor (v->Cursor());
  433.                     break;
  434.                 }
  435.             }
  436.         }
  437.         result = WinDefWindowProc (hWnd, msg, p1, p2);
  438.         break;
  439.     }
  440.         
  441.     default:
  442.         result = WinDefWindowProc (hWnd, msg, p1, p2);
  443.         break;
  444.     }
  445.     QMSG qMsg;
  446.     WinQueryPointerPos (HWND_DESKTOP, &qMsg.ptl);
  447.     qMsg.hwnd = hWnd;
  448.     qMsg.msg  = msg;
  449.     qMsg.mp1  = p1;
  450.     qMsg.mp2  = p2;
  451.     qMsg.time = 0;
  452.     UI_Event e (Event_None, 0);
  453.         // WM_COMMAND events arrive both in this WindowProc and in
  454.         // ProcessNativeEvent. Those from menu items are dispatched from
  455.         // here, and the rest are dispatched from ProcessNativeEvent.
  456.     if (ctrlr.TranslateNativeEvent (qMsg, e)) {
  457.         if ((qMsg.msg == WM_COMMAND && SHORT1FROMMP(p2) == CMDSRC_MENU)
  458.             || (qMsg.msg != WM_COMMAND && qMsg.msg != WM_VSCROLL &&
  459.                 qMsg.msg != WM_HSCROLL &&
  460.             (!ctrlr._eventFilter || ctrlr._eventFilter->Execute (e, 0))))
  461.             ctrlr.DispatchNativeEvent (e);
  462.     }
  463.     return result;
  464. }
  465.  
  466.  
  467.