home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
yacl-012.zip
/
ui
/
os2evt.cxx
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-07
|
16KB
|
467 lines
/*
*
* Copyright (C) 1994, M. A. Sridhar
*
*
* This software is Copyright M. A. Sridhar, 1994. You are free
* to copy, modify or distribute this software as you see fit,
* and to use it for any purpose, provided this copyright
* notice and the following disclaimer are included with all
* copies.
*
* DISCLAIMER
*
* The author makes no warranties, either expressed or implied,
* with respect to this software, its quality, performance,
* merchantability, or fitness for any particular purpose. This
* software is distributed AS IS. The user of this software
* assumes all risks as to its quality and performance. In no
* event shall the author be liable for any direct, indirect or
* consequential damages, even if the author has been advised
* as to the possibility of such damages.
*
*/
#if defined(__GNUC__)
#pragma implementation
#endif
// Support for event handling under OS/2
#include "ui/cntroler.h"
#include "ui/timer.h"
#include "ui/menu.h"
#include <string.h>
static struct {
ulong message;
UI_EventType yaclEvent;
} TransTable [] = {
WM_BUTTON1DOWN, Event_LButtonPress,
WM_BUTTON2DOWN, Event_MButtonPress,
WM_BUTTON3DOWN, Event_RButtonPress,
WM_BUTTON1UP, Event_LButtonRelease,
WM_BUTTON2UP, Event_MButtonRelease,
WM_BUTTON3UP, Event_RButtonRelease,
WM_BUTTON1DBLCLK, Event_LButtonDblClk,
WM_BUTTON2DBLCLK, Event_MButtonDblClk,
WM_BUTTON3DBLCLK, Event_RButtonDblClk,
WM_CHAR, Event_KeyTyped,
WM_CLOSE, Event_CloseDown,
WM_DESTROY, Event_Quit,
WM_MENUEND, Event_LoseFocus,
WM_MENUSELECT, Event_GetFocus,
WM_MOVE, Event_Reconfigure,
WM_MOUSEMOVE, Event_MouseMove,
WM_PAINT, Event_Paint,
WM_SETFOCUS, Event_GetFocus,
WM_SIZE, Event_Reconfigure,
0, Event_Other
};
bool UI_Controller::_DoOneEvent (NativeEventStruct& qMsg)
{
UI_Event e (Event_None, NULL);
if (TranslateNativeEvent (qMsg, e) &&
e._origin->WindowClass() != NULL &&
// The window class is null for menu items. The menu item events
// are dispatched from the WindowProc.
e._origin->WindowClass() != _YACLWindowClassName &&
// ---------------------^^^^ ------------------
// Note that we compare pointers, not strings. We cannot
// compare strings, because OS/2's built-in window classes
// return invalid pointers as window classes. This check is
// needed because events targeted at a YACLWindow are dispatched
// from YACLWindowProc.
(e._type != Event_KeyTyped || e.key != '\011') &&
// Another hack, to prevent tabs from being dispatched. They
// should be dispatched from YACLWindowProc.
(!_eventFilter || _eventFilter->Execute (e, 0)))
DispatchNativeEvent (e);
if (_termination && _termination->Execute (e, 0))
return FALSE;
DispatchSoftEvents ();
return TRUE;
}
bool UI_Controller::ProcessNativeEvents ()
{
NativeEventStruct qMsg;
while (_root && WinGetMsg (_hab, &qMsg, NULLHANDLE, 0, 0)) {
WinDispatchMsg (_hab, &qMsg);
if (!_DoOneEvent (qMsg))
return FALSE;
}
return TRUE;
}
void UI_Controller::FlushEventQueue ()
{
NativeEventStruct qMsg;
while (_root && WinPeekMsg (_hab, &qMsg, NULLHANDLE, 0, 0, PM_REMOVE));
}
void UI_Controller::DispatchPendingEvents ()
{
DispatchSoftEvents ();
NativeEventStruct qMsg;
while (_root && WinPeekMsg (_hab, &qMsg, NULLHANDLE, 0, 0, PM_REMOVE)) {
WinDispatchMsg (_hab, &qMsg);
if (!_DoOneEvent (qMsg))
break;
}
}
bool UI_Controller::DispatchNativeEvent ( UI_Event& e )
{
if (!_root)
return TRUE;
switch (e.Type()) {
case Event_MouseMove:
if ( _current != e.Destination () ) {
// The mouse entered a different visual obj
if ( _current ) {
UI_Event leave (Event_ViewLeave, _current);
DispatchEvent (&leave);
}
_current = e.Destination ();
UI_Event enter (Event_ViewEnter, e.Destination ());
DispatchEvent (&enter);
}
break;
default:
break;
}
return DispatchEvent (&e);
}
bool UI_Controller::TranslateNativeEvent (NativeEventStruct& msg, UI_Event& e)
{
e._nativeEvent = new NativeEventStruct;
*(NativeEventStruct*)(e._nativeEvent) = msg;
e._shiftKey = WinGetKeyState (HWND_DESKTOP, VK_SHIFT) < 0 ? TRUE : FALSE;
e._ctrlKey = WinGetKeyState (HWND_DESKTOP, VK_CTRL ) < 0 ? TRUE : FALSE;
e._metaKey = WinGetKeyState (HWND_DESKTOP, VK_ALT ) < 0 ? TRUE : FALSE;
for (short i = 0; TransTable[i].message != 0; i++) {
if ( TransTable [i].message == msg.msg ) {
break;
}
}
e._type = TransTable [i].yaclEvent;
UI_VisualObject* view = (UI_VisualObject*) _visualObjMap[msg.hwnd];
switch (msg.msg) {
case WM_MENUEND: {
UI_MenuItem* itm = (UI_MenuItem*) _visualObjMap[(ulong) msg.mp2];
if (itm && itm->ViewID() != FID_MENU) {
// ----------------^^^^^
// This is really a hack. For some reason, it sends me a MENUEND
// message to a root item, and that seems to cause problems.
UI_Menu& menu = itm->Container();
UI_MenuItem* focusItem = menu.Focus();
if (focusItem) {
UI_Event evt (Event_LoseFocus, focusItem, focusItem);
DispatchEvent (&evt);
}
menu.MoveFocusTo (itm);
}
view = itm;
break;
}
case WM_MENUSELECT: {
UI_VObjCollection* parent = (UI_VObjCollection*)
_visualObjMap[msg.hwnd];
UI_ViewID id = SHORT1FROMMP (msg.mp1);
UI_MenuItem* itm = parent ? (UI_MenuItem*)(*parent)[id] : NULL;
if (itm) {
UI_Menu& menu = itm->Container();
UI_MenuItem* focusItem = menu.Focus();
if (focusItem) {
UI_Event evt (Event_LoseFocus, focusItem, focusItem);
DispatchEvent (&evt);
}
menu.MoveFocusTo (itm);
}
view = itm;
break;
}
case WM_CHAR:
e.key = SHORT1FROMMP(msg.mp2);
// PM gives me two WM_CHAR messages (See p. 452 of Petzold's book),
// so I ignore one of them:
if (((ulong) msg.mp1) & KC_KEYUP || e.key == 0)
e._type = Event_Other;
break;
case WM_BUTTON1DBLCLK:
case WM_BUTTON2DBLCLK:
case WM_BUTTON3DBLCLK:
case WM_BUTTON1DOWN:
case WM_BUTTON2DOWN:
case WM_BUTTON3DOWN:
case WM_BUTTON1UP:
case WM_BUTTON2UP:
case WM_BUTTON3UP: {
POINTL point = msg.ptl;
WinMapWindowPoints (HWND_DESKTOP, msg.hwnd, &point, 1);
RECTL rect;
WinQueryWindowRect (msg.hwnd, &rect);
e.curPos.Origin (UI_Point (point.x,
rect.yTop - rect.yBottom + 1 - point.y));
break;
}
case WM_TIMER: {
ulong id = SHORT1FROMMP (msg.mp1);
UI_Timer::DoAlarm (id);
break;
}
case WM_COMMAND: {
UI_ViewID id = SHORT1FROMMP(msg.mp1);
e._type = Event_Select;
UI_VObjCollection* parent = (UI_VObjCollection*)
_visualObjMap[msg.hwnd];
view = parent ? (*parent)[id] : NULL;
break;
}
case WM_CONTROL: {
UI_ViewID id = SHORT1FROMMP(msg.mp1);
e._type = Event_Select;
HWND h = WinWindowFromID (msg.hwnd, id);
view = (UI_VObjCollection*) _visualObjMap[h];
ushort code = SHORT2FROMMP(msg.mp1);
// if (code == CBN_EFCHANGE || CBN_LBSELECT)
// e._type = Event_Select;
// else
// e._type = (code == BN_CLICKED) ? Event_Select
// : Event_LButtonDblClk;
// The CBN_ messages seem to come before the WM_COMMAND (or is it
// WM_CONTROL), in fact, even before the selection actually changes.
// So we can't ask the listbox what its selection is, because it
// hasn't changed yet.
e._type = (code == BN_CLICKED) ? Event_Select
: Event_LButtonDblClk;
break;
}
case WM_MOUSEMOVE: {
short x = SHORT1FROMMP (msg.mp1);
short y = SHORT2FROMMP (msg.mp1);
if (view)
y = view->_shape.Height() - y; // Adjust for the fact that
// OS/2's origin reckoning is
// bottom left, not top left
e.curPos = UI_Rectangle (x, y, 0, 0);
e._type = Event_MouseMove;
break;
}
case WM_MOVE: {
if (!view)
break;
SWP swp;
WinQueryWindowPos (msg.hwnd, &swp);
POINTL newOrigin;
newOrigin.x = newOrigin.y = 0;
HWND handle;
if (_YACLWindowClassName == view->WindowClass()
// -----------------^^^^ ------------------
// Note that we compare pointers, not strings. We cannot
// compare strings, because OS/2's built-in window classes
// return invalid pointers as window classes.
&& view->_style & FCF_TITLEBAR) {
UI_CompositeVObject* v = (UI_CompositeVObject*) view;
HWND prnt = v->_parent ? v->_parent->_handle : HWND_DESKTOP;
WinMapWindowPoints (msg.hwnd, prnt, &newOrigin, 1);
handle = WinQueryWindow (v->_handle, QW_PARENT);
// Frame handle
}
else
handle = view->_parent ? view->_parent->_handle : HWND_DESKTOP;
HWND parentHandle = WinQueryWindow (handle, QW_PARENT);
UI_Point p (newOrigin.x, _YACLWindowHeight (parentHandle)
- newOrigin.y - swp.cy + 1);
e.curPos = view->_shape;
e.curPos.Origin (p);
e._type = Event_Reconfigure;
break;
}
case WM_SIZE: {
SWP swp;
WinQueryWindowPos (msg.hwnd, &swp);
// Doesn't seem like there is any good way to tell when a window is
// maximized, other than catching the WM_SYSCOMMAND. Even if I did
// that, I wouldn't get the correct co-ordinates -- seems like I
// always get (4, 28) as top left corner if I use (swp.x, swp.y).
if (view) {
e.curPos = UI_Rectangle (view->_shape.Origin(), swp.cx, swp.cy);
}
e._type = Event_Reconfigure;
break;
}
// case WM_WINDOWPOSCHANGED: {
// This is not needed, since WM_SIZE gives us the size change.
// PSWP pSwp = (PSWP) msg.mp1;
// if (view && pSwp) {
// HWND parentHandle = WinQueryWindow (msg.hwnd, QW_PARENT);
// long y = _YACLWindowHeight (parentHandle) - pSwp->y - pSwp->cy;
// e.curPos = UI_Rectangle (pSwp->x, y, pSwp->cx, pSwp->cy);
// }
// e._type = Event_Reconfigure;
// break;
// }
case WM_VSCROLL:
case WM_HSCROLL: {
HWND parent = WinWindowFromID (msg.hwnd, (ushort) msg.mp1);
view = (UI_VisualObject*) _visualObjMap [parent];
e.param = SHORT1FROMMP(msg.mp2);
switch (SHORT2FROMMP (msg.mp2)) {
case SB_LINEDOWN:
e._type = Event_ScrollForwardLine;
break;
case SB_PAGEDOWN:
e._type = Event_ScrollForwardPage;
break;
case SB_LINEUP:
e._type = Event_ScrollBackwardLine;
break;
case SB_PAGEUP:
e._type = Event_ScrollBackwardPage;
break;
case SB_ENDSCROLL:
e._type = Event_FinishScroll;
break;
case SB_SLIDERPOSITION:
e._type = Event_ScrollToPosition;
break;
case SB_SLIDERTRACK:
e._type = Event_Scroll;
break;
}
break;
}
default:
e.curPos.Origin (UI_Point (msg.ptl.x, msg.ptl.y));
break;
}
e._origin = e._dest = view;
return view != NULL;
}
void UI_Controller::_MakeOS2Interface (const UI_Event& e)
{
UI_VisualObject* origin = e.Origin ();
if (origin->MakeVisualElement ())
Register (origin);
origin->_PrivateInitialize ();
origin->Initialize ();
if (origin->WindowClass() == _YACLWindowClassName &&
origin->ViewHandle () > 0) {
// Force an initial paint event to be sent
UI_ViewHandle h = origin->ViewHandle();
RECTL rect;
WinQueryWindowRect (h, &rect);
WinInvalidateRect (h, &rect, TRUE);
}
}
MRESULT EXPENTRY YACLWindowProc (HWND hWnd, ULONG msg, MPARAM p1, MPARAM p2)
{
MRESULT result = 0;
// We need to call _DoErase for both ERASEBACKGROUND and PAINT messages,
// because sometimes PM seems to send me only a PAINT message with no
// ERASEBACKGROUND before it. However, the PAINT message erases and then
// does default processing, so it should be ok.
UI_Controller& ctrlr = _TheApplication->Controller();
switch (msg) {
case WM_ERASEBACKGROUND:
// Return TRUE to cause PM to paint the window background
// in SYSCLR_WINDOW
return (MRESULT) TRUE;
case WM_PAINT: {
RECTL rect;
HPS hps = WinBeginPaint (hWnd, 0, &rect);
WinFillRect (hps, &rect, CLR_WHITE);
WinEndPaint (hps);
break;
}
case WM_CLOSE:
break;
case WM_MOUSEMOVE: {
if (ctrlr._inWaitState)
ctrlr.SetCurrentCursor (ctrlr._defaultCursor);
else {
UI_VisualObject* v = ctrlr[hWnd];
if (v) {
UI_Cursor& cursor = v->Cursor();
if (cursor != UICursor_Default) {
ctrlr.SetCurrentCursor (v->Cursor());
break;
}
}
}
result = WinDefWindowProc (hWnd, msg, p1, p2);
break;
}
default:
result = WinDefWindowProc (hWnd, msg, p1, p2);
break;
}
QMSG qMsg;
WinQueryPointerPos (HWND_DESKTOP, &qMsg.ptl);
qMsg.hwnd = hWnd;
qMsg.msg = msg;
qMsg.mp1 = p1;
qMsg.mp2 = p2;
qMsg.time = 0;
UI_Event e (Event_None, 0);
// WM_COMMAND events arrive both in this WindowProc and in
// ProcessNativeEvent. Those from menu items are dispatched from
// here, and the rest are dispatched from ProcessNativeEvent.
if (ctrlr.TranslateNativeEvent (qMsg, e)) {
if ((qMsg.msg == WM_COMMAND && SHORT1FROMMP(p2) == CMDSRC_MENU)
|| (qMsg.msg != WM_COMMAND && qMsg.msg != WM_VSCROLL &&
qMsg.msg != WM_HSCROLL &&
(!ctrlr._eventFilter || ctrlr._eventFilter->Execute (e, 0))))
ctrlr.DispatchNativeEvent (e);
}
return result;
}