+ HWND hWnd = GetHwnd();
+ SWP vSwp;
+
+ ::WinQueryWindowPos(hWnd, &vSwp);
+
+ if (pX)
+ *pX += vSwp.x;
+ if (pY)
+ *pY += vSwp.y;
+} // end of wxWindowOS2::DoClientToScreen
+
+//
+// Get size *available for subwindows* i.e. excluding menu bar etc.
+// Must be a frame type window
+//
+void wxWindowOS2::DoGetClientSize(
+ int* pWidth
+, int* pHeight
+) const
+{
+ HWND hWnd = GetHwnd();
+ RECTL vRect;
+
+ ::WinQueryWindowRect(hWnd, &vRect);
+ if (IsKindOf(CLASSINFO(wxDialog)))
+ {
+ RECTL vTitle;
+ HWND hWndTitle;
+ //
+ // For a Dialog we have to explicitly request the client portion.
+ // For a Frame the hWnd IS the client window
+ //
+ hWndTitle = ::WinWindowFromID(hWnd, FID_TITLEBAR);
+ if (::WinQueryWindowRect(hWndTitle, &vTitle))
+ {
+ if (vTitle.yTop - vTitle.yBottom == 0)
+ {
+ //
+ // Dialog has not been created yet, use a default
+ //
+ vTitle.yTop = 20;
+ }
+ vRect.yTop -= (vTitle.yTop - vTitle.yBottom);
+ }
+
+ ULONG uStyle = ::WinQueryWindowULong(hWnd, QWL_STYLE);
+
+ //
+ // Deal with borders
+ //
+ if (uStyle & FCF_DLGBORDER)
+ {
+ vRect.xLeft += 4;
+ vRect.xRight -= 4;
+ vRect.yTop -= 4;
+ vRect.yBottom += 4;
+ }
+ else if (uStyle & FCF_SIZEBORDER)
+ {
+ vRect.xLeft += 4;
+ vRect.xRight -= 4;
+ vRect.yTop -= 4;
+ vRect.yBottom += 4;
+ }
+ else if (uStyle & FCF_BORDER)
+ {
+ vRect.xLeft += 2;
+ vRect.xRight -= 2;
+ vRect.yTop -= 2;
+ vRect.yBottom += 2;
+ }
+ else // make some kind of adjustment or top sizers ram into the titlebar!
+ {
+ vRect.xLeft += 3;
+ vRect.xRight -= 3;
+ vRect.yTop -= 3;
+ vRect.yBottom += 3;
+ }
+ }
+ if (pWidth)
+ *pWidth = vRect.xRight - vRect.xLeft;
+ if (pHeight)
+ *pHeight = vRect.yTop - vRect.yBottom;
+} // end of wxWindowOS2::DoGetClientSize
+
+void wxWindowOS2::DoMoveWindow(
+ int nX
+, int nY
+, int nWidth
+, int nHeight
+)
+{
+ //
+ // Input parameters assume wxWidgets coordinate system
+ //
+ RECTL vRect;
+ wxWindow* pParent = GetParent();
+ HWND hWnd = GetHwnd();
+
+ if (pParent && !IsKindOf(CLASSINFO(wxDialog)))
+ {
+ int nOS2Height = GetOS2ParentHeight(pParent);
+
+ nY = nOS2Height - (nY + nHeight);
+ }
+ else
+ {
+ RECTL vRect;
+
+ ::WinQueryWindowRect(HWND_DESKTOP, &vRect);
+ nY = vRect.yTop - (nY + nHeight);
+ }
+
+ //
+ // In the case of a frame whose client is sized, the client cannot be
+ // large than its parent frame minus its borders! This usually happens
+ // when using an autosizer to size a frame to precisely hold client
+ // controls as in the notebook sample.
+ //
+ // In this case, we may need to resize both a frame and its client so we
+ // need a quick calc of the frame border size, then if the frame
+ // (less its borders) is smaller than the client, size the frame to
+ // encompass the client with the appropriate border size.
+ //
+ if (IsKindOf(CLASSINFO(wxFrame)))
+ {
+ RECTL vFRect;
+ int nWidthFrameDelta = 0;
+ int nHeightFrameDelta = 0;
+ wxFrame* pFrame;
+
+ pFrame = wxDynamicCast(this, wxFrame);
+ hWnd = pFrame->GetFrame();
+ ::WinQueryWindowRect(hWnd, &vRect);
+ ::WinMapWindowPoints(hWnd, HWND_DESKTOP, (PPOINTL)&vRect, 2);
+ vFRect = vRect;
+ ::WinCalcFrameRect(hWnd, &vRect, TRUE);
+ nWidthFrameDelta = ((vRect.xLeft - vFRect.xLeft) + (vFRect.xRight - vRect.xRight));
+ nHeightFrameDelta = ((vRect.yBottom - vFRect.yBottom) + (vFRect.yTop - vRect.yTop));
+ // Input values refer to the window position relative to its parent
+ // which may be the Desktop so we need to calculate
+ // the new frame values to keep the wxWidgets frame origin constant
+ nY -= nHeightFrameDelta;
+ nWidth += nWidthFrameDelta;
+ nHeight += nHeightFrameDelta;
+ }
+ ::WinSetWindowPos( hWnd
+ ,HWND_TOP
+ ,(LONG)nX
+ ,(LONG)nY
+ ,(LONG)nWidth
+ ,(LONG)nHeight
+ ,SWP_SIZE | SWP_MOVE
+ );
+ if (m_vWinSwp.cx == 0 && m_vWinSwp.cy == 0 && m_vWinSwp.fl == 0)
+ //
+ // Uninitialized
+ //
+ ::WinQueryWindowPos(hWnd, &m_vWinSwp);
+ else
+ {
+ //
+ // Handle resizing of scrolled windows. The target or window to
+ // be scrolled is the owner (gets the scroll notifications). The
+ // parent is usually the parent frame of the scrolled panel window.
+ // In order to show the scrollbars the target window will be shrunk
+ // by the size of the scroll bar widths and moved in the X and Y
+ // directon. That value will be computed as part of the diff for
+ // moving the children. Everytime the window is sized the
+ // toplevel OnSize is going to resize the panel to fit the client
+ // or the whole sizer and will need to me resized. This will send
+ // a WM_SIZE out which will be intercepted by the ScrollHelper
+ // which will cause the scrollbars to be displayed via the SetScrollbar
+ // call in CWindow.
+ //
+ if (IsKindOf(CLASSINFO(wxScrolledWindow)))
+ {
+ int nAdjustWidth = 0;
+ int nAdjustHeight = 0;
+ int nHSBHeight = wxSystemSettingsNative::GetMetric(wxSYS_HSCROLL_Y,
+ this);
+ int nVSBWidth = wxSystemSettingsNative::GetMetric(wxSYS_VSCROLL_X,
+ this);
+ SWP vSwpScroll;
+
+ if (GetScrollBarHorz() == NULLHANDLE ||
+ !WinIsWindowShowing(GetScrollBarHorz()))
+ nAdjustHeight = 0L;
+ else
+ nAdjustHeight = nHSBHeight;
+ if (GetScrollBarVert() == NULLHANDLE ||
+ !WinIsWindowShowing(GetScrollBarVert()))
+ nAdjustWidth = 0L;
+ else
+ nAdjustWidth = nVSBWidth;
+ ::WinQueryWindowPos(hWnd, &vSwpScroll);
+ ::WinSetWindowPos( hWnd
+ ,HWND_TOP
+ ,vSwpScroll.x
+ ,vSwpScroll.y + nAdjustHeight
+ ,vSwpScroll.cx - nAdjustWidth
+ ,vSwpScroll.cy - nAdjustHeight
+ ,SWP_MOVE | SWP_SIZE
+ );
+ }
+ ::WinQueryWindowPos(hWnd, &m_vWinSwp);
+ }
+} // end of wxWindowOS2::DoMoveWindow
+
+//
+// Set the size of the window: if the dimensions are positive, just use them,
+// but if any of them is equal to -1, it means that we must find the value for
+// it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
+// which case -1 is a valid value for x and y)
+//
+// If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
+// the width/height to best suit our contents, otherwise we reuse the current
+// width/height
+//
+void wxWindowOS2::DoSetSize( int nX,
+ int nY,
+ int nWidth,
+ int nHeight,
+ int nSizeFlags )
+{
+ //
+ // Input & output parameters assume wxWidgets coordinate system
+ //
+
+ //
+ // Get the current size and position...
+ //
+ int nCurrentX;
+ int nCurrentY;
+ int nCurrentWidth;
+ int nCurrentHeight;
+ wxSize vSize = wxDefaultSize;
+
+ GetPosition(&nCurrentX, &nCurrentY);
+ GetSize(&nCurrentWidth, &nCurrentHeight);
+
+ //
+ // ... and don't do anything (avoiding flicker) if it's already ok
+ //
+ if (nX == nCurrentX && nY == nCurrentY &&
+ nWidth == nCurrentWidth && nHeight == nCurrentHeight)
+ {
+ return;
+ }
+
+ if (nX == wxDefaultCoord && !(nSizeFlags & wxSIZE_ALLOW_MINUS_ONE))
+ nX = nCurrentX;
+ if (nY == wxDefaultCoord && !(nSizeFlags & wxSIZE_ALLOW_MINUS_ONE))
+ nY = nCurrentY;
+
+ AdjustForParentClientOrigin(nX, nY, nSizeFlags);
+
+ if (nWidth == wxDefaultCoord)
+ {
+ if (nSizeFlags & wxSIZE_AUTO_WIDTH)
+ {
+ vSize = DoGetBestSize();
+ nWidth = vSize.x;
+ }
+ else
+ {
+ //
+ // Just take the current one
+ //
+ nWidth = nCurrentWidth;
+ }
+ }
+
+ if (nHeight == wxDefaultCoord)
+ {
+ if (nSizeFlags & wxSIZE_AUTO_HEIGHT)
+ {
+ if (vSize.x == wxDefaultCoord)
+ {
+ vSize = DoGetBestSize();
+ }
+ nHeight = vSize.y;
+ }
+ else
+ {
+ // just take the current one
+ nHeight = nCurrentHeight;
+ }
+ }
+
+ DoMoveWindow( nX, nY, nWidth, nHeight );
+} // end of wxWindowOS2::DoSetSize
+
+void wxWindowOS2::DoSetClientSize( int nWidth,
+ int nHeight )
+{
+ //
+ // nX & nY assume wxWidgets coordinate system
+ //
+ int nX;
+ int nY;
+
+ GetPosition(&nX, &nY);
+
+ DoMoveWindow( nX, nY, nWidth, nHeight );
+
+ wxSize size( nWidth, nHeight );
+ wxSizeEvent vEvent( size, m_windowId );
+ vEvent.SetEventObject(this);
+ HandleWindowEvent(vEvent);
+} // end of wxWindowOS2::DoSetClientSize
+
+// ---------------------------------------------------------------------------
+// text metrics
+// ---------------------------------------------------------------------------
+
+int wxWindowOS2::GetCharHeight() const
+{
+ HPS hPs;
+ FONTMETRICS vFontMetrics;
+
+ hPs = ::WinGetPS(GetHwnd());
+
+ if(!GpiQueryFontMetrics(hPs, sizeof(FONTMETRICS), &vFontMetrics))
+ {
+ ::WinReleasePS(hPs);
+ return (0);
+ }
+ ::WinReleasePS(hPs);
+ return(vFontMetrics.lMaxAscender + vFontMetrics.lMaxDescender);
+} // end of wxWindowOS2::GetCharHeight
+
+int wxWindowOS2::GetCharWidth() const
+{
+ HPS hPs;
+ FONTMETRICS vFontMetrics;
+
+ hPs = ::WinGetPS(GetHwnd());
+
+ if(!GpiQueryFontMetrics(hPs, sizeof(FONTMETRICS), &vFontMetrics))
+ {
+ ::WinReleasePS(hPs);
+ return (0);
+ }
+ ::WinReleasePS(hPs);
+ return(vFontMetrics.lAveCharWidth);
+} // end of wxWindowOS2::GetCharWidth
+
+void wxWindowOS2::DoGetTextExtent( const wxString& rString,
+ int* pX,
+ int* pY,
+ int* pDescent,
+ int* pExternalLeading,
+ const wxFont* WXUNUSED(pTheFont) ) const
+{
+ POINTL avPoint[TXTBOX_COUNT];
+ POINTL vPtMin;
+ POINTL vPtMax;
+ int i;
+ int l;
+ FONTMETRICS vFM; // metrics structure
+ BOOL bRc = FALSE;
+ HPS hPS;
+
+ hPS = ::WinGetPS(GetHwnd());
+
+ l = rString.length();
+ if (l > 0L)
+ {
+ //
+ // In world coordinates.
+ //
+ bRc = ::GpiQueryTextBox( hPS,
+ l,
+ (char*) rString.wx_str(),
+ TXTBOX_COUNT,// return maximum information
+ avPoint // array of coordinates points
+ );
+ if (bRc)
+ {
+ vPtMin.x = avPoint[0].x;
+ vPtMax.x = avPoint[0].x;
+ vPtMin.y = avPoint[0].y;
+ vPtMax.y = avPoint[0].y;
+ for (i = 1; i < 4; i++)
+ {
+ if(vPtMin.x > avPoint[i].x) vPtMin.x = avPoint[i].x;
+ if(vPtMin.y > avPoint[i].y) vPtMin.y = avPoint[i].y;
+ if(vPtMax.x < avPoint[i].x) vPtMax.x = avPoint[i].x;
+ if(vPtMax.y < avPoint[i].y) vPtMax.y = avPoint[i].y;
+ }
+ bRc = ::GpiQueryFontMetrics( hPS
+ ,sizeof(FONTMETRICS)
+ ,&vFM
+ );
+ if (!bRc)
+ {
+ vPtMin.x = 0;
+ vPtMin.y = 0;
+ vPtMax.x = 0;
+ vPtMax.y = 0;
+ }
+ }
+ else
+ {
+ vPtMin.x = 0;
+ vPtMin.y = 0;
+ vPtMax.x = 0;
+ vPtMax.y = 0;
+ }
+ }
+ else
+ {
+ vPtMin.x = 0;
+ vPtMin.y = 0;
+ vPtMax.x = 0;
+ vPtMax.y = 0;
+ }
+ if (pX)
+ *pX = (vPtMax.x - vPtMin.x + 1);
+ if (pY)
+ *pY = (vPtMax.y - vPtMin.y + 1);
+ if (pDescent)
+ {
+ if (bRc)
+ *pDescent = vFM.lMaxDescender;
+ else
+ *pDescent = 0;
+ }
+ if (pExternalLeading)
+ {
+ if (bRc)
+ *pExternalLeading = vFM.lExternalLeading;
+ else
+ *pExternalLeading = 0;
+ }
+ ::WinReleasePS(hPS);
+} // end of wxWindow::DoGetTextExtent
+
+bool wxWindowOS2::IsMouseInWindow() const
+{
+ //
+ // Get the mouse position
+ POINTL vPt;
+
+ ::WinQueryPointerPos(HWND_DESKTOP, &vPt);
+
+ //
+ // Find the window which currently has the cursor and go up the window
+ // chain until we find this window - or exhaust it
+ //
+ HWND hWnd = ::WinWindowFromPoint(HWND_DESKTOP, &vPt, TRUE);
+
+ while (hWnd && (hWnd != GetHwnd()))
+ hWnd = ::WinQueryWindow(hWnd, QW_PARENT);
+
+ return hWnd != NULL;
+} // end of wxWindowOS2::IsMouseInWindow
+
+
+// ---------------------------------------------------------------------------
+// popup menu
+// ---------------------------------------------------------------------------
+//
+#if wxUSE_MENUS_NATIVE
+bool wxWindowOS2::DoPopupMenu( wxMenu* pMenu, int nX, int nY )
+{
+ HWND hWndOwner = GetHwnd();
+ HWND hWndParent = GetHwnd();
+ HWND hMenu = GetHmenuOf(pMenu);
+ bool bIsWaiting = true;
+ int nHeight;
+
+ pMenu->UpdateUI();
+
+ if ( nX == -1 && nY == -1 )
+ {
+ wxPoint mouse = wxGetMousePosition();
+ nX = mouse.x; nY = mouse.y;
+ }
+ else
+ {
+ DoClientToScreen( &nX
+ ,&nY
+ );
+ DoGetSize(0,&nHeight);
+ nY = nHeight - nY;
+ }
+
+ ::WinPopupMenu( hWndParent
+ ,hWndOwner
+ ,hMenu
+ ,nX
+ ,nY
+ ,0L
+ ,PU_HCONSTRAIN | PU_VCONSTRAIN | PU_MOUSEBUTTON1 | PU_KEYBOARD
+ );
+
+ while(bIsWaiting)
+ {
+ QMSG vMsg;
+
+ ::WinGetMsg(vHabmain,&vMsg, (HWND)0, 0, 0);
+ if (vMsg.msg == WM_COMMAND)
+ bIsWaiting = false;
+ ::WinDispatchMsg(vHabmain, (PQMSG)&vMsg);
+ }
+
+ return true;
+} // end of wxWindowOS2::DoPopupMenu
+#endif // wxUSE_MENUS_NATIVE
+
+// ===========================================================================
+// pre/post message processing
+// ===========================================================================
+
+MRESULT wxWindowOS2::OS2DefWindowProc( WXUINT uMsg,
+ WXWPARAM wParam,
+ WXLPARAM lParam )
+{
+ if (m_fnOldWndProc)
+ return (MRESULT)m_fnOldWndProc(GetHWND(), uMsg, (MPARAM)wParam, (MPARAM)lParam);
+ else
+ return ::WinDefWindowProc(GetHWND(), uMsg, (MPARAM)wParam, (MPARAM)lParam);
+} // end of wxWindowOS2::OS2DefWindowProc
+
+bool wxWindowOS2::OS2ProcessMessage( WXMSG* pMsg )
+{
+// wxUniversal implements tab traversal itself
+#ifndef __WXUNIVERSAL__
+ QMSG* pQMsg = (QMSG*)pMsg;
+
+ if (m_hWnd != 0 && (GetWindowStyleFlag() & wxTAB_TRAVERSAL))
+ {
+ //
+ // Intercept dialog navigation keys
+ //
+ bool bProcess = true;
+ USHORT uKeyFlags = SHORT1FROMMP(pQMsg->mp1);
+
+ if (uKeyFlags & KC_KEYUP)
+ bProcess = false;
+
+ if (uKeyFlags & KC_ALT)
+ bProcess = false;
+
+ if (!(uKeyFlags & KC_VIRTUALKEY))
+ bProcess = false;
+
+ if (bProcess)
+ {
+ bool bCtrlDown = IsCtrlDown();
+ bool bShiftDown = IsShiftDown();
+
+ //
+ // WM_QUERYDLGCODE: ask the control if it wants the key for itself,
+ // don't process it if it's the case (except for Ctrl-Tab/Enter
+ // combinations which are always processed)
+ //
+ ULONG ulDlgCode = 0;
+
+ if (!bCtrlDown)
+ {
+ ulDlgCode = (ULONG)::WinSendMsg(pQMsg->hwnd, WM_QUERYDLGCODE, pQMsg, 0);
+ }
+
+ bool bForward = true;
+ bool bWindowChange = false;
+
+ switch (SHORT2FROMMP(pQMsg->mp2))
+ {
+ //
+ // Going to make certain assumptions about specific types of controls
+ // here, so we may have to alter some things later if they prove invalid
+ //
+ case VK_TAB:
+ //
+ // Shift tabl will always be a nav-key but tabs may be wanted
+ //
+ if (!bShiftDown)
+ {
+ bProcess = false;
+ }
+ else
+ {
+ //
+ // Entry Fields want tabs for themselve usually
+ //
+ switch (ulDlgCode)
+ {
+ case DLGC_ENTRYFIELD:
+ case DLGC_MLE:
+ bProcess = true;
+ break;
+
+ default:
+ bProcess = false;
+ }
+
+ //
+ // Ctrl-Tab cycles thru notebook pages
+ //
+ bWindowChange = bCtrlDown;
+ bForward = !bShiftDown;
+ }
+ break;
+
+ case VK_UP:
+ case VK_LEFT:
+ if (bCtrlDown)
+ bProcess = false;
+ else
+ bForward = false;
+ break;
+
+ case VK_DOWN:
+ case VK_RIGHT:
+ if (bCtrlDown)
+ bProcess = false;
+ break;
+
+ case VK_ENTER:
+ {
+ if (bCtrlDown)
+ {
+ //
+ // ctrl-enter is not processed
+ //
+ return false;
+ }
+ else if (ulDlgCode & DLGC_BUTTON)
+ {
+ //
+ // buttons want process Enter themselevs
+ //
+ bProcess = false;
+ }
+ else
+ {
+ wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
+ wxButton* pBtn = NULL;
+
+ if (tlw)
+ {
+ pBtn = wxDynamicCast(tlw->GetDefaultItem(), wxButton);
+ }
+
+ if (pBtn && pBtn->IsEnabled())
+ {
+ //
+ // If we do have a default button, do press it
+ //
+ pBtn->OS2Command(BN_CLICKED, 0 /* unused */);
+ return true;
+ }
+ else if (!IsTopLevel())
+ {
+ //
+ // if not a top level window, let parent
+ // handle it
+ //
+ return false;
+ }
+ // else: but if it does not it makes sense to make
+ // it work like a TAB - and that's what we do.
+ // Note that Ctrl-Enter always works this way.
+ }
+ }
+ break;
+
+ default:
+ bProcess = false;
+ }
+
+ if (bProcess)
+ {
+ wxNavigationKeyEvent vEvent;
+
+ vEvent.SetDirection(bForward);
+ vEvent.SetWindowChange(bWindowChange);
+ vEvent.SetEventObject(this);
+
+ if (HandleWindowEvent(vEvent))
+ {
+ wxButton* pBtn = wxDynamicCast(FindFocus(), wxButton);
+
+ if (pBtn)
+ {
+ //
+ // The button which has focus should be default
+ //
+ pBtn->SetDefault();
+ }
+ return true;
+ }
+ }
+ }
+ //
+ // Let Dialogs process
+ //
+ if (::WinSendMsg(pQMsg->hwnd, WM_QUERYDLGCODE, pQMsg, 0));
+ return true;
+ }
+#else
+ pMsg = pMsg; // just shut up the compiler
+#endif // __WXUNIVERSAL__
+
+ return false;
+} // end of wxWindowOS2::OS2ProcessMessage
+
+bool wxWindowOS2::OS2TranslateMessage( WXMSG* pMsg )
+{
+#if wxUSE_ACCEL && !defined(__WXUNIVERSAL__)
+ return m_acceleratorTable.Translate(m_hWnd, pMsg);
+#else
+ pMsg = pMsg;
+ return false;
+#endif //wxUSE_ACCEL
+} // end of wxWindowOS2::OS2TranslateMessage
+
+bool wxWindowOS2::OS2ShouldPreProcessMessage( WXMSG* WXUNUSED(pMsg) )
+{
+ // preprocess all messages by default
+ return true;
+} // end of wxWindowOS2::OS2ShouldPreProcessMessage
+
+// ---------------------------------------------------------------------------
+// message params unpackers
+// ---------------------------------------------------------------------------
+
+void wxWindowOS2::UnpackCommand(
+ WXWPARAM wParam
+, WXLPARAM lParam
+, WORD* pId
+, WXHWND* phWnd
+, WORD* pCmd
+)
+{
+ *pId = LOWORD(wParam);
+ *phWnd = NULL; // or may be GetHWND() ?
+ *pCmd = LOWORD(lParam);
+} // end of wxWindowOS2::UnpackCommand
+
+void wxWindowOS2::UnpackActivate(
+ WXWPARAM wParam
+, WXLPARAM lParam
+, WXWORD* pState
+, WXHWND* phWnd
+)
+{
+ *pState = LOWORD(wParam);
+ *phWnd = (WXHWND)lParam;
+} // end of wxWindowOS2::UnpackActivate
+
+void wxWindowOS2::UnpackScroll(
+ WXWPARAM wParam
+, WXLPARAM lParam
+, WXWORD* pCode
+, WXWORD* pPos
+, WXHWND* phWnd
+)
+{
+ ULONG ulId;
+ HWND hWnd;
+
+ ulId = (ULONG)LONGFROMMP(wParam);
+ hWnd = ::WinWindowFromID(GetHwnd(), ulId);
+ if (hWnd == m_hWndScrollBarHorz || hWnd == m_hWndScrollBarVert)
+ *phWnd = NULLHANDLE;
+ else
+ *phWnd = hWnd;
+
+ *pPos = SHORT1FROMMP(lParam);
+ *pCode = SHORT2FROMMP(lParam);
+} // end of wxWindowOS2::UnpackScroll
+
+void wxWindowOS2::UnpackMenuSelect(
+ WXWPARAM wParam
+, WXLPARAM lParam
+, WXWORD* pItem
+, WXWORD* pFlags
+, WXHMENU* phMenu
+)
+{
+ *pItem = (WXWORD)LOWORD(wParam);
+ *pFlags = HIWORD(wParam);
+ *phMenu = (WXHMENU)lParam;
+} // end of wxWindowOS2::UnpackMenuSelect
+
+// ---------------------------------------------------------------------------
+// Main wxWidgets window proc and the window proc for wxWindow
+// ---------------------------------------------------------------------------
+
+//
+// Hook for new window just as it's being created, when the window isn't yet
+// associated with the handle
+//
+wxWindowOS2* wxWndHook = NULL;
+
+//
+// Main window proc
+//
+MRESULT EXPENTRY wxWndProc(
+ HWND hWnd
+, ULONG ulMsg
+, MPARAM wParam
+, MPARAM lParam
+)
+{
+ wxWindowOS2* pWnd = wxFindWinFromHandle((WXHWND)hWnd);
+
+ //
+ // When we get the first message for the HWND we just created, we associate
+ // it with wxWindow stored in wxWndHook
+ //
+ if (!pWnd && wxWndHook)
+ {
+ wxAssociateWinWithHandle(hWnd, wxWndHook);
+ pWnd = wxWndHook;
+ wxWndHook = NULL;
+ pWnd->SetHWND((WXHWND)hWnd);
+ }
+
+ MRESULT rc = (MRESULT)0;
+
+
+ //
+ // Stop right here if we don't have a valid handle in our wxWindow object.
+ //
+ if (pWnd && !pWnd->GetHWND())
+ {
+ pWnd->SetHWND((WXHWND) hWnd);
+ rc = pWnd->OS2DefWindowProc(ulMsg, wParam, lParam );
+ pWnd->SetHWND(0);
+ }
+ else
+ {
+ if (pWnd)
+ {
+ rc = pWnd->OS2WindowProc(ulMsg, wParam, lParam);
+ if ( (pWnd->GetScrollBarHorz() != NULLHANDLE ||
+ pWnd->GetScrollBarVert() != NULLHANDLE) &&
+ ulMsg == WM_PAINT)
+ {
+ if (pWnd->GetScrollBarHorz() != NULLHANDLE)
+ ::WinInvalidateRect(pWnd->GetScrollBarHorz(), NULL, TRUE);
+ if (pWnd->GetScrollBarVert() != NULLHANDLE)
+ ::WinInvalidateRect(pWnd->GetScrollBarVert(), NULL, TRUE);
+ }
+ }
+ else
+ rc = ::WinDefWindowProc(hWnd, ulMsg, wParam, lParam);
+ }
+
+ return rc;
+} // end of wxWndProc
+
+//
+// We will add (or delete) messages we need to handle at this default
+// level as we go
+//
+MRESULT wxWindowOS2::OS2WindowProc( WXUINT uMsg,
+ WXWPARAM wParam,
+ WXLPARAM lParam )
+{
+ //
+ // Did we process the uMsg?
+ //
+ bool bProcessed = false;
+ MRESULT mResult;
+
+ //
+ // For most messages we should return 0 when we do process the message
+ //
+ mResult = (MRESULT)0;
+
+ switch (uMsg)
+ {
+ case WM_CREATE:
+ {
+ bool bMayCreate;
+
+ bProcessed = HandleCreate( (WXLPCREATESTRUCT)lParam
+ ,&bMayCreate
+ );
+ if (bProcessed)
+ {
+ //
+ // Return 0 to bAllow window creation
+ //
+ mResult = (MRESULT)(bMayCreate ? 0 : -1);
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ HandleDestroy();
+ bProcessed = true;
+ break;
+
+ case WM_MOVE:
+ bProcessed = HandleMove( LOWORD(lParam)
+ ,HIWORD(lParam)
+ );
+ break;
+
+ case WM_SIZE:
+ bProcessed = HandleSize( LOWORD(lParam)
+ ,HIWORD(lParam)
+ ,(WXUINT)wParam
+ );
+ break;
+
+ case WM_WINDOWPOSCHANGED:
+
+ //
+ // Dialogs under OS/2 do not get WM_SIZE events at all.
+ // Instead they get this, which can function much like WM_SIZE
+ // PSWP contains the new sizes and positioning, PSWP+1 the old
+ // We use this because ADJUSTWINDOWPOS comes BEFORE the new
+ // position is added and our auto layout does a WinQueryWindowRect
+ // to get the CURRENT client size. That is the size used to position
+ // child controls, so we need to already be sized
+ // in order to get the child controls positoned properly.
+ //
+ if (IsKindOf(CLASSINFO(wxDialog)) || IsKindOf(CLASSINFO(wxFrame)))
+ {
+ PSWP pSwp = (PSWP)PVOIDFROMMP(wParam);
+ PSWP pSwp2 = pSwp++;
+
+ if (!(pSwp->cx == pSwp2->cx &&
+ pSwp->cy == pSwp2->cy))
+ bProcessed = HandleSize( pSwp->cx
+ ,pSwp->cy
+ ,(WXUINT)lParam
+ );
+ if (IsKindOf(CLASSINFO(wxFrame)))
+ {
+ wxFrame* pFrame = wxDynamicCast(this, wxFrame);
+
+ if (pFrame)
+ {
+ if (pFrame->GetStatusBar())
+ pFrame->PositionStatusBar();
+ if (pFrame->GetToolBar())
+ pFrame->PositionToolBar();
+ }
+ }
+ }
+ break;
+
+ case WM_ACTIVATE:
+ {
+ WXWORD wState;
+ WXHWND hWnd;
+
+ UnpackActivate( wParam
+ ,lParam
+ ,&wState
+ ,&hWnd
+ );
+
+ bProcessed = HandleActivate( wState
+ ,(WXHWND)hWnd
+ );
+ bProcessed = false;
+ }
+ break;
+
+ case WM_SETFOCUS:
+ if (SHORT1FROMMP((MPARAM)lParam) == TRUE)
+ bProcessed = HandleSetFocus((WXHWND)(HWND)wParam);
+ else
+ bProcessed = HandleKillFocus((WXHWND)(HWND)wParam);
+ break;
+
+ case WM_PAINT:
+ bProcessed = HandlePaint();
+ break;
+
+ case WM_CLOSE:
+ //
+ // Don't let the DefWindowProc() destroy our window - we'll do it
+ // ourselves in ~wxWindow
+ //
+ bProcessed = true;
+ mResult = (MRESULT)TRUE;
+ break;
+
+ case WM_SHOW:
+ bProcessed = HandleShow(wParam != 0, (int)lParam);
+ break;
+
+ //
+ // Under OS2 PM Joysticks are treated just like mouse events
+ // The "Motion" events will be prevelent in joysticks
+ //
+ case WM_MOUSEMOVE:
+ case WM_BUTTON1DOWN:
+ case WM_BUTTON1UP:
+ case WM_BUTTON1DBLCLK:
+ case WM_BUTTON1MOTIONEND:
+ case WM_BUTTON1MOTIONSTART:
+ case WM_BUTTON2DOWN:
+ case WM_BUTTON2UP:
+ case WM_BUTTON2DBLCLK:
+ case WM_BUTTON2MOTIONEND:
+ case WM_BUTTON2MOTIONSTART:
+ case WM_BUTTON3DOWN:
+ case WM_BUTTON3UP:
+ case WM_BUTTON3DBLCLK:
+ case WM_BUTTON3MOTIONEND:
+ case WM_BUTTON3MOTIONSTART:
+ {
+ short nX = LOWORD(wParam);
+ short nY = HIWORD(wParam);
+
+ //
+ // Redirect the event to a static control if necessary
+ //
+ if (this == GetCapture())
+ {
+ bProcessed = HandleMouseEvent( uMsg
+ ,nX
+ ,nY
+ ,(WXUINT)SHORT2FROMMP(lParam)
+ );
+ }
+ else
+ {
+ wxWindow* pWin = FindWindowForMouseEvent( this
+ ,&nX
+ ,&nY
+ );
+ if (!pWin->IsOfStandardClass())
+ {
+ if (uMsg == WM_BUTTON1DOWN && pWin->CanAcceptFocus() )
+ pWin->SetFocus();
+ }
+ bProcessed = pWin->HandleMouseEvent( uMsg
+ ,nX
+ ,nY
+ ,(WXUINT)SHORT2FROMMP(lParam)
+ );
+ }
+ }
+ break;
+
+ case WM_SYSCOMMAND:
+ bProcessed = HandleSysCommand(wParam, lParam);
+ break;
+
+ case WM_COMMAND:
+ {
+ WORD id, cmd;
+ WXHWND hwnd;
+ UnpackCommand(wParam, lParam, &id, &hwnd, &cmd);
+
+ bProcessed = HandleCommand(id, cmd, hwnd);
+ }
+ break;
+
+ //
+ // For these messages we must return TRUE if process the message
+ //
+ case WM_DRAWITEM:
+ case WM_MEASUREITEM:
+ {
+ int nIdCtrl = (UINT)wParam;
+
+ if ( uMsg == WM_DRAWITEM )
+ {
+ bProcessed = OS2OnDrawItem(nIdCtrl,
+ (WXDRAWITEMSTRUCT *)lParam);
+ }
+ else
+ {
+ return MRFROMLONG(OS2OnMeasureItem( nIdCtrl
+ ,(WXMEASUREITEMSTRUCT *)lParam
+ ));
+ }
+
+ if ( bProcessed )
+ mResult = (MRESULT)TRUE;
+ }
+ break;
+
+ case WM_QUERYDLGCODE:
+ if (!IsOfStandardClass())
+ {
+ if ( m_lDlgCode )
+ {
+ mResult = (MRESULT)m_lDlgCode;
+ bProcessed = true;
+ }
+ }
+ //
+ //else: get the dlg code from the DefWindowProc()
+ //
+ break;
+
+ //
+ // In OS/2 PM all keyboard events are of the WM_CHAR type. Virtual key and key-up
+ // and key-down events are obtained from the WM_CHAR params.
+ //
+ case WM_CHAR:
+ {
+ USHORT uKeyFlags = SHORT1FROMMP((MPARAM)wParam);
+
+ if (uKeyFlags & KC_KEYUP)
+ {
+ //TODO: check if the cast to WXWORD isn't causing trouble
+ bProcessed = HandleKeyUp(wParam, lParam);
+ break;
+ }
+ else // keydown event
+ {
+ m_bLastKeydownProcessed = false;
+ //
+ // If this has been processed by an event handler,
+ // return 0 now (we've handled it). DON't RETURN
+ // we still need to process further
+ //
+ m_bLastKeydownProcessed = HandleKeyDown(wParam, lParam);
+ if (uKeyFlags & KC_VIRTUALKEY)
+ {
+ USHORT uVk = SHORT2FROMMP((MPARAM)lParam);
+
+ //
+ // We consider these message "not interesting" to OnChar
+ //
+ switch(uVk)
+ {
+ case VK_SHIFT:
+ case VK_CTRL:
+ case VK_MENU:
+ case VK_CAPSLOCK:
+ case VK_NUMLOCK:
+ case VK_SCRLLOCK:
+ bProcessed = true;
+ break;
+
+ // Avoid duplicate messages to OnChar for these ASCII keys: they
+ // will be translated by TranslateMessage() and received in WM_CHAR
+ case VK_ESC:
+ case VK_ENTER:
+ case VK_BACKSPACE:
+ case VK_TAB:
+ // But set processed to false, not true to still pass them to
+ // the control's default window proc - otherwise built-in
+ // keyboard handling won't work
+ bProcessed = false;
+ break;
+
+ default:
+ bProcessed = HandleChar(wParam, lParam);
+ }
+ break;
+ }
+ else // WM_CHAR -- Always an ASCII character
+ {
+ if (m_bLastKeydownProcessed)
+ {
+ //
+ // The key was handled in the EVT_KEY_DOWN and handling
+ // a key in an EVT_KEY_DOWN handler is meant, by
+ // design, to prevent EVT_CHARs from happening
+ //
+ m_bLastKeydownProcessed = false;
+ bProcessed = true;
+ }
+ else // do generate a CHAR event
+ {
+ bProcessed = HandleChar(wParam, lParam, true);
+ break;
+ }
+ }
+ }
+ }
+
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ {
+ WXWORD wCode;
+ WXWORD wPos;
+ WXHWND hWnd;
+ UnpackScroll( wParam
+ ,lParam
+ ,&wCode
+ ,&wPos
+ ,&hWnd
+ );
+
+ bProcessed = OS2OnScroll( uMsg == WM_HSCROLL ? wxHORIZONTAL
+ : wxVERTICAL
+ ,wCode
+ ,wPos
+ ,hWnd
+ );
+ }
+ break;
+
+ case WM_CONTROL:
+ switch(SHORT2FROMMP(wParam))
+ {
+ case BN_PAINT:
+ {
+ HWND hWnd = ::WinWindowFromID((HWND)GetHwnd(), SHORT1FROMMP(wParam));
+ wxWindowOS2* pWin = wxFindWinFromHandle(hWnd);
+
+ if (!pWin)
+ {
+ bProcessed = false;
+ break;
+ }
+ if (pWin->IsKindOf(CLASSINFO(wxBitmapButton)))
+ {
+ wxBitmapButton* pBitmapButton = wxDynamicCast(pWin, wxBitmapButton);
+
+ pBitmapButton->OS2OnDraw((WXDRAWITEMSTRUCT *)lParam);
+ }
+ return 0;
+ }
+ // break;
+
+ case BKN_PAGESELECTEDPENDING:
+ {
+ PPAGESELECTNOTIFY pPage = (PPAGESELECTNOTIFY)lParam;
+
+ if ((pPage->ulPageIdNew != pPage->ulPageIdCur) &&
+ (pPage->ulPageIdNew > 0L && pPage->ulPageIdCur > 0L))
+ {
+ wxWindowOS2* pWin = wxFindWinFromHandle(pPage->hwndBook);
+ wxBookCtrlEvent vEvent( wxEVT_NOTEBOOK_PAGE_CHANGED
+ ,(int)SHORT1FROMMP(wParam)
+ ,(int)pPage->ulPageIdNew
+ ,(int)pPage->ulPageIdCur
+ );
+ if (!pWin)
+ {
+ bProcessed = false;
+ break;
+ }
+ if (pWin->IsKindOf(CLASSINFO(wxNotebook)))
+ {
+ wxNotebook* pNotebook = wxDynamicCast(pWin, wxNotebook);
+
+ vEvent.SetEventObject(pWin);
+ pNotebook->OnSelChange(vEvent);
+ bProcessed = true;
+ }
+ else
+ bProcessed = false;
+ }
+ else
+ bProcessed = false;
+ }
+ break;
+
+ case CBN_LBSELECT:
+ case BN_CLICKED: // Dups as LN_SELECT and CBN_LBSELECT
+ {
+ HWND hWnd = ::WinWindowFromID((HWND)GetHwnd(), SHORT1FROMMP(wParam));
+ wxWindowOS2* pWin = wxFindWinFromHandle(hWnd);
+
+ if (!pWin)
+ {
+ bProcessed = false;
+ break;
+ }
+ //
+ // Simulate a WM_COMMAND here, as wxWidgets expects all control
+ // button clicks to generate WM_COMMAND msgs, not WM_CONTROL
+ //
+ if (pWin->IsKindOf(CLASSINFO(wxRadioBox)))
+ {
+ wxRadioBox* pRadioBox = wxDynamicCast(pWin, wxRadioBox);
+
+ pRadioBox->OS2Command( (WXUINT)SHORT2FROMMP(wParam)
+ ,(WXWORD)SHORT1FROMMP(wParam)
+ );
+ }
+ if (pWin->IsKindOf(CLASSINFO(wxRadioButton)))
+ {
+ wxRadioButton* pRadioButton = wxDynamicCast(pWin, wxRadioButton);
+
+ pRadioButton->OS2Command( (WXUINT)SHORT2FROMMP(wParam)
+ ,(WXWORD)SHORT1FROMMP(wParam)
+ );
+ }
+ if (pWin->IsKindOf(CLASSINFO(wxCheckBox)))
+ {
+ wxCheckBox* pCheckBox = wxDynamicCast(pWin, wxCheckBox);
+
+ pCheckBox->OS2Command( (WXUINT)SHORT2FROMMP(wParam)
+ ,(WXWORD)SHORT1FROMMP(wParam)
+ );
+ }
+ if (pWin->IsKindOf(CLASSINFO(wxListBox)))
+ {
+ wxListBox* pListBox = wxDynamicCast(pWin, wxListBox);
+
+ pListBox->OS2Command( (WXUINT)SHORT2FROMMP(wParam)
+ ,(WXWORD)SHORT1FROMMP(wParam)
+ );
+ if (pListBox->GetWindowStyle() & wxLB_OWNERDRAW)
+ Refresh();
+ }
+ if (pWin->IsKindOf(CLASSINFO(wxComboBox)))
+ {
+ wxComboBox* pComboBox = wxDynamicCast(pWin, wxComboBox);
+
+ pComboBox->OS2Command( (WXUINT)SHORT2FROMMP(wParam)
+ ,(WXWORD)SHORT1FROMMP(wParam)
+ );
+ }
+ if (pWin->IsKindOf(CLASSINFO(wxChoice)))
+ {
+ wxChoice* pChoice = wxDynamicCast(pWin, wxChoice);
+
+ pChoice->OS2Command( (WXUINT)SHORT2FROMMP(wParam)
+ ,(WXWORD)SHORT1FROMMP(wParam)
+ );
+ }
+ return 0;
+ }
+ // break;
+
+ case LN_ENTER:
+ {
+ HWND hWnd = HWNDFROMMP(lParam);
+ wxWindowOS2* pWin = wxFindWinFromHandle(hWnd);
+
+ if (!pWin)
+ {
+ bProcessed = false;
+ break;
+ }
+ //
+ // Simulate a WM_COMMAND here, as wxWidgets expects all control
+ // button clicks to generate WM_COMMAND msgs, not WM_CONTROL
+ //
+ if (pWin->IsKindOf(CLASSINFO(wxListBox)))
+ {
+ wxListBox* pListBox = wxDynamicCast(pWin, wxListBox);
+
+ pListBox->OS2Command( (WXUINT)SHORT2FROMMP(wParam)
+ ,(WXWORD)SHORT1FROMMP(wParam)
+ );
+ if (pListBox->GetWindowStyle() & wxLB_OWNERDRAW)
+ Refresh();
+
+ }
+ if (pWin->IsKindOf(CLASSINFO(wxComboBox)))
+ {
+ wxComboBox* pComboBox = wxDynamicCast(pWin, wxComboBox);
+
+ pComboBox->OS2Command( (WXUINT)SHORT2FROMMP(wParam)
+ ,(WXWORD)SHORT1FROMMP(wParam)
+ );
+ }
+ return 0;
+ }
+ // break;
+
+ case SPBN_UPARROW:
+ case SPBN_DOWNARROW:
+ case SPBN_CHANGE:
+ {
+ char zVal[10];
+ long lVal;
+
+ ::WinSendMsg( HWNDFROMMP(lParam)
+ ,SPBM_QUERYVALUE
+ ,&zVal[0]
+ ,MPFROM2SHORT( (USHORT)10
+ ,(USHORT)SPBQ_UPDATEIFVALID
+ )
+ );
+ lVal = atol(zVal);
+ bProcessed = OS2OnScroll( wxVERTICAL
+ ,(WXWORD)SHORT2FROMMP(wParam)
+ ,(WXWORD)lVal
+ ,HWNDFROMMP(lParam)
+ );
+ }
+ break;
+
+ case SLN_SLIDERTRACK:
+ {
+ HWND hWnd = ::WinWindowFromID(GetHWND(), SHORT1FROMMP(wParam));
+ wxWindowOS2* pChild = wxFindWinFromHandle(hWnd);
+
+ if (!pChild)
+ {
+ bProcessed = false;
+ break;
+ }
+ if (pChild->IsKindOf(CLASSINFO(wxSlider)))
+ bProcessed = OS2OnScroll( wxVERTICAL
+ ,(WXWORD)SHORT2FROMMP(wParam)
+ ,(WXWORD)LONGFROMMP(lParam)
+ ,hWnd
+ );
+ }
+ break;
+ }
+ break;
+
+#if defined(__VISAGECPP__) && (__IBMCPP__ >= 400)
+ case WM_CTLCOLORCHANGE:
+ {
+ bProcessed = HandleCtlColor(&hBrush);
+ }
+ break;
+#endif
+ case WM_ERASEBACKGROUND:
+ //
+ // Returning TRUE to requestw PM to paint the window background
+ // in SYSCLR_WINDOW. We don't really want that
+ //
+ bProcessed = HandleEraseBkgnd((WXHDC)(HPS)wParam);
+ mResult = (MRESULT)(FALSE);
+ break;
+
+ // the return value for this message is ignored
+ case WM_SYSCOLORCHANGE:
+ bProcessed = HandleSysColorChange();
+ break;
+
+ case WM_REALIZEPALETTE:
+ bProcessed = HandlePaletteChanged();
+ break;
+
+ // move all drag and drops to wxDrg
+ case WM_ENDDRAG:
+ bProcessed = HandleEndDrag(wParam);
+ break;
+
+ case WM_INITDLG:
+ bProcessed = HandleInitDialog((WXHWND)(HWND)wParam);
+
+ if ( bProcessed )
+ {
+ // we never set focus from here
+ mResult = (MRESULT)FALSE;
+ }
+ break;
+
+ // wxFrame specific message
+ case WM_MINMAXFRAME:
+ bProcessed = HandleGetMinMaxInfo((PSWP)wParam);
+ break;
+
+ case WM_SYSVALUECHANGED:
+ // TODO: do something
+ mResult = (MRESULT)TRUE;
+ break;
+
+ //
+ // Comparable to WM_SETPOINTER for windows, only for just controls
+ //
+ case WM_CONTROLPOINTER:
+ bProcessed = HandleSetCursor( SHORT1FROMMP(wParam) // Control ID
+ ,(HWND)lParam // Cursor Handle
+ );
+ if (bProcessed )
+ {
+ //
+ // Returning TRUE stops the DefWindowProc() from further
+ // processing this message - exactly what we need because we've
+ // just set the cursor.
+ //
+ mResult = (MRESULT)TRUE;
+ }
+ break;
+
+#if wxUSE_MENUS_NATIVE
+ case WM_MENUEND:
+ if (wxCurrentPopupMenu)
+ {
+ if (GetHmenuOf(wxCurrentPopupMenu) == (HWND)lParam)
+ {
+ // Break out of msg loop in DoPopupMenu
+ ::WinPostMsg((HWND)lParam,WM_COMMAND,wParam,0);
+ }
+ }
+ break;
+#endif // wxUSE_MENUS_NATIVE
+
+ }
+ if (!bProcessed)
+ {
+#ifdef __WXDEBUG__
+ wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."),
+ wxGetMessageName(uMsg));
+#endif // __WXDEBUG__
+ if (IsKindOf(CLASSINFO(wxFrame)))
+ mResult = ::WinDefWindowProc(m_hWnd, uMsg, wParam, lParam);
+ else if (IsKindOf(CLASSINFO(wxDialog)))
+ mResult = ::WinDefDlgProc( m_hWnd, uMsg, wParam, lParam);
+ else
+ mResult = OS2DefWindowProc(uMsg, wParam, lParam);
+ }
+ return mResult;
+} // end of wxWindowOS2::OS2WindowProc
+
+// ----------------------------------------------------------------------------
+// wxWindow <-> HWND map
+// ----------------------------------------------------------------------------
+
+wxWinHashTable *wxWinHandleHash = NULL;
+
+wxWindow* wxFindWinFromHandle(
+ WXHWND hWnd
+)
+{
+ return (wxWindow *)wxWinHandleHash->Get((long)hWnd);
+} // end of wxFindWinFromHandle
+
+void wxAssociateWinWithHandle(
+ HWND hWnd
+, wxWindowOS2* pWin
+)
+{
+ //
+ // Adding NULL hWnd is (first) surely a result of an error and
+ // (secondly) breaks menu command processing
+ //
+ wxCHECK_RET( hWnd != (HWND)NULL,
+ wxT("attempt to add a NULL hWnd to window list ignored") );
+
+ wxWindow* pOldWin = wxFindWinFromHandle((WXHWND) hWnd);
+
+ if (pOldWin && (pOldWin != pWin))
+ {
+ wxString Newstr(pWin->GetClassInfo()->GetClassName());
+ wxString Oldstr(pOldWin->GetClassInfo()->GetClassName());
+ wxLogError( wxT("Bug! New window of class %s has same HWND %X as old window of class %s"),
+ Newstr.c_str(),
+ (int)hWnd,
+ Oldstr.c_str()
+ );
+ }
+ else if (!pOldWin)
+ {
+ wxWinHandleHash->Put( (long)hWnd
+ ,(wxWindow *)pWin
+ );
+ }
+} // end of wxAssociateWinWithHandle
+
+void wxRemoveHandleAssociation( wxWindowOS2* pWin )
+{
+ wxWinHandleHash->Delete((long)pWin->GetHWND());
+} // end of wxRemoveHandleAssociation
+
+//
+// Default destroyer - override if you destroy it in some other way
+// (e.g. with MDI child windows)
+//
+void wxWindowOS2::OS2DestroyWindow()
+{
+}
+
+bool wxWindowOS2::OS2GetCreateWindowCoords( const wxPoint& rPos,
+ const wxSize& rSize,
+ int& rnX,
+ int& rnY,
+ int& rnWidth,
+ int& rnHeight ) const
+{
+ bool bNonDefault = false;
+ static const int DEFAULT_Y = 200;
+ static const int DEFAULT_H = 250;
+
+ if (rPos.x == wxDefaultCoord)
+ {
+ rnX = rnY = CW_USEDEFAULT;
+ }
+ else
+ {
+ rnX = rPos.x;
+ rnY = rPos.y == wxDefaultCoord ? DEFAULT_Y : rPos.y;
+ bNonDefault = true;
+ }
+ if (rSize.x == wxDefaultCoord)
+ {
+ rnWidth = rnHeight = CW_USEDEFAULT;
+ }
+ else
+ {
+ rnWidth = rSize.x;
+ rnHeight = rSize.y == wxDefaultCoord ? DEFAULT_H : rSize.y;
+ bNonDefault = true;
+ }
+ return bNonDefault;
+} // end of wxWindowOS2::OS2GetCreateWindowCoords
+
+WXHWND wxWindowOS2::OS2GetParent() const
+{
+ return m_parent ? m_parent->GetHWND() : NULL;
+}
+
+bool wxWindowOS2::OS2Create( PSZ zClass,
+ const wxChar* zTitle,
+ WXDWORD dwStyle,
+ const wxPoint& rPos,
+ const wxSize& rSize,
+ void* pCtlData,
+ WXDWORD WXUNUSED(dwExStyle),
+ bool bIsChild )
+{
+ ERRORID vError;
+ wxString sError;
+ int nX = 0L;
+ int nY = 0L;
+ int nWidth = 0L;
+ int nHeight = 0L;
+ long lControlId = 0L;
+ wxWindowCreationHook vHook(this);
+ wxString sClassName((wxChar*)zClass);
+ wxString sTitle(zTitle ? zTitle : wxEmptyString);
+
+ OS2GetCreateWindowCoords( rPos
+ ,rSize
+ ,nX
+ ,nY
+ ,nWidth
+ ,nHeight
+ );
+
+ if (bIsChild)
+ {
+ lControlId = GetId();
+ if (GetWindowStyleFlag() & wxCLIP_SIBLINGS)
+ {
+ dwStyle |= WS_CLIPSIBLINGS;
+ }
+ }
+ //
+ // For each class "Foo" we have we also have "FooNR" ("no repaint") class
+ // which is the same but without CS_[HV]REDRAW class styles so using it
+ // ensures that the window is not fully repainted on each resize
+ //
+ if (!HasFlag(wxFULL_REPAINT_ON_RESIZE))
+ {
+ sClassName += wxT("NR");
+ }
+ m_hWnd = (WXHWND)::WinCreateWindow( (HWND)OS2GetParent()
+ ,sClassName.c_str()
+ ,sTitle.c_str()
+ ,(ULONG)dwStyle
+ ,(LONG)0L
+ ,(LONG)0L
+ ,(LONG)0L
+ ,(LONG)0L
+ ,NULLHANDLE
+ ,HWND_TOP
+ ,(ULONG)lControlId
+ ,pCtlData
+ ,NULL
+ );
+ if (!m_hWnd)
+ {
+ vError = ::WinGetLastError(wxGetInstance());
+ sError = wxPMErrorToStr(vError);
+ return false;
+ }
+ SubclassWin(m_hWnd);
+ SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
+
+ SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE));
+
+ LONG lColor = (LONG)m_backgroundColour.GetPixel();
+
+ if (!::WinSetPresParam( m_hWnd
+ ,PP_BACKGROUNDCOLOR
+ ,sizeof(LONG)
+ ,(PVOID)&lColor
+ ))
+ {
+ vError = ::WinGetLastError(vHabmain);
+ sError = wxPMErrorToStr(vError);
+ wxLogError(wxT("Error creating frame. Error: %s\n"), sError.c_str());
+ return false;
+ }
+ SetSize( nX
+ ,nY
+ ,nWidth
+ ,nHeight
+ );
+ return true;
+} // end of wxWindowOS2::OS2Create
+
+// ===========================================================================
+// OS2 PM message handlers
+// ===========================================================================
+
+// ---------------------------------------------------------------------------
+// window creation/destruction
+// ---------------------------------------------------------------------------
+
+bool wxWindowOS2::HandleCreate( WXLPCREATESTRUCT WXUNUSED(vCs),
+ bool* pbMayCreate )
+{
+ wxWindowCreateEvent vEvent((wxWindow*)this);
+
+ (void)HandleWindowEvent(vEvent);
+ *pbMayCreate = true;
+ return true;
+} // end of wxWindowOS2::HandleCreate
+
+bool wxWindowOS2::HandleDestroy()
+{
+ wxWindowDestroyEvent vEvent((wxWindow*)this);
+ vEvent.SetId(GetId());
+ (void)HandleWindowEvent(vEvent);
+
+ //
+ // Delete our drop target if we've got one
+ //
+#if wxUSE_DRAG_AND_DROP
+ wxDELETE(m_dropTarget);
+#endif // wxUSE_DRAG_AND_DROP
+
+ //
+ // WM_DESTROY handled
+ //
+ return true;
+} // end of wxWindowOS2::HandleDestroy
+
+// ---------------------------------------------------------------------------
+// activation/focus
+// ---------------------------------------------------------------------------
+void wxWindowOS2::OnSetFocus(
+ wxFocusEvent& rEvent
+)
+{
+ rEvent.Skip();
+} // end of wxWindowOS2::OnSetFocus
+
+bool wxWindowOS2::HandleActivate(
+ int nState
+, WXHWND WXUNUSED(hActivate)
+)
+{
+ wxActivateEvent vEvent( wxEVT_ACTIVATE
+ ,(bool)nState
+ ,m_windowId
+ );
+ vEvent.SetEventObject(this);
+ return HandleWindowEvent(vEvent);
+} // end of wxWindowOS2::HandleActivate
+
+bool wxWindowOS2::HandleSetFocus( WXHWND WXUNUSED(hWnd) )
+{
+ //
+ // Notify the parent keeping track of focus for the kbd navigation
+ // purposes that we got it
+ //
+ wxChildFocusEvent vEventFocus((wxWindow *)this);
+ (void)HandleWindowEvent(vEventFocus);
+
+#if wxUSE_CARET
+ //
+ // Deal with caret
+ //
+ if (m_caret)
+ {
+ m_caret->OnSetFocus();
+ }
+#endif // wxUSE_CARET
+
+#if wxUSE_TEXTCTRL
+ // If it's a wxTextCtrl don't send the event as it will be done
+ // after the control gets to process it from EN_FOCUS handler
+ if ( wxDynamicCastThis(wxTextCtrl) )
+ {
+ return false;
+ }
+#endif // wxUSE_TEXTCTRL
+
+ wxFocusEvent vEvent(wxEVT_SET_FOCUS, m_windowId);
+
+ vEvent.SetEventObject(this);
+ return HandleWindowEvent(vEvent);
+} // end of wxWindowOS2::HandleSetFocus
+
+bool wxWindowOS2::HandleKillFocus( WXHWND hWnd )
+{
+#if wxUSE_CARET
+ //
+ // Deal with caret
+ //
+ if (m_caret)
+ {
+ m_caret->OnKillFocus();
+ }
+#endif // wxUSE_CARET
+
+#if wxUSE_TEXTCTRL
+ //
+ // If it's a wxTextCtrl don't send the event as it will be done
+ // after the control gets to process it.
+ //
+ wxTextCtrl* pCtrl = wxDynamicCastThis(wxTextCtrl);
+
+ if (pCtrl)
+ {
+ return false;
+ }
+#endif
+
+ //
+ // Don't send the event when in the process of being deleted. This can
+ // only cause problems if the event handler tries to access the object.
+ //
+ if ( m_isBeingDeleted )
+ {
+ return false;
+ }
+
+ wxFocusEvent vEvent( wxEVT_KILL_FOCUS
+ ,m_windowId
+ );
+
+ vEvent.SetEventObject(this);
+
+ //
+ // wxFindWinFromHandle() may return NULL, it is ok
+ //
+ vEvent.SetWindow(wxFindWinFromHandle(hWnd));
+ return HandleWindowEvent(vEvent);
+} // end of wxWindowOS2::HandleKillFocus
+
+// ---------------------------------------------------------------------------
+// miscellaneous
+// ---------------------------------------------------------------------------
+
+bool wxWindowOS2::HandleShow(
+ bool bShow
+, int WXUNUSED(nStatus)
+)
+{
+ wxShowEvent vEvent(GetId(), bShow);
+
+ vEvent.SetEventObject(this);
+ return HandleWindowEvent(vEvent);
+} // end of wxWindowOS2::HandleShow
+
+bool wxWindowOS2::HandleInitDialog( WXHWND WXUNUSED(hWndFocus) )
+{
+ wxInitDialogEvent vEvent(GetId());
+
+ vEvent.SetEventObject(this);
+ return HandleWindowEvent(vEvent);
+} // end of wxWindowOS2::HandleInitDialog
+
+bool wxWindowOS2::HandleEndDrag(WXWPARAM WXUNUSED(wParam))
+{
+ // TODO: We'll handle drag and drop later
+ return false;
+}
+
+bool wxWindowOS2::HandleSetCursor( USHORT WXUNUSED(vId),
+ WXHWND hPointer )
+{
+ //
+ // Under OS/2 PM this allows the pointer to be changed
+ // as it passes over a control
+ //
+ ::WinSetPointer(HWND_DESKTOP, (HPOINTER)hPointer);
+ return true;
+} // end of wxWindowOS2::HandleSetCursor
+
+// ---------------------------------------------------------------------------
+// owner drawn stuff
+// ---------------------------------------------------------------------------
+bool wxWindowOS2::OS2OnDrawItem( int vId,
+ WXDRAWITEMSTRUCT* pItemStruct )
+{
+#if wxUSE_OWNER_DRAWN
+ wxClientDC vDc(this);
+
+#if wxUSE_MENUS_NATIVE
+ //
+ // Is it a menu item?
+ //
+ if (vId == 0)
+ {
+ ERRORID vError;
+ wxString sError;
+ POWNERITEM pMeasureStruct = (POWNERITEM)pItemStruct;
+ wxFrame* pFrame = (wxFrame*)this;
+ wxMenuItem* pMenuItem = pFrame->GetMenuBar()->FindItem(pMeasureStruct->idItem, pMeasureStruct->hItem);
+ HDC hDC = ::GpiQueryDevice(pMeasureStruct->hps);
+ wxRect vRect( pMeasureStruct->rclItem.xLeft
+ ,pMeasureStruct->rclItem.yBottom
+ ,pMeasureStruct->rclItem.xRight - pMeasureStruct->rclItem.xLeft
+ ,pMeasureStruct->rclItem.yTop - pMeasureStruct->rclItem.yBottom
+ );
+
+ wxPMDCImpl *impl = (wxPMDCImpl*) vDc.GetImpl();
+ impl->SetHDC( hDC, false );
+ impl->SetHPS( pMeasureStruct->hps );
+ //
+ // Load the wxWidgets Pallete and set to RGB mode
+ //
+ if (!::GpiCreateLogColorTable( pMeasureStruct->hps
+ ,0L
+ ,LCOLF_CONSECRGB
+ ,0L
+ ,(LONG)wxTheColourDatabase->m_nSize
+ ,(PLONG)wxTheColourDatabase->m_palTable
+ ))
+ {
+ vError = ::WinGetLastError(vHabmain);
+ sError = wxPMErrorToStr(vError);
+ wxLogError(wxT("Unable to set current color table (1). Error: %s\n"), sError.c_str());
+ }
+ //
+ // Set the color table to RGB mode
+ //
+ if (!::GpiCreateLogColorTable( pMeasureStruct->hps
+ ,0L
+ ,LCOLF_RGB
+ ,0L
+ ,0L
+ ,NULL
+ ))
+ {
+ vError = ::WinGetLastError(vHabmain);
+ sError = wxPMErrorToStr(vError);
+ wxLogError(wxT("Unable to set current color table (2). Error: %s\n"), sError.c_str());
+ }
+
+ wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE );
+
+ int eAction = 0;
+ int eStatus = 0;
+
+ if (pMeasureStruct->fsAttribute == pMeasureStruct->fsAttributeOld)
+ {
+ //
+ // Entire Item needs to be redrawn (either it has reappeared from
+ // behind another window or is being displayed for the first time
+ //
+ eAction = wxOwnerDrawn::wxODDrawAll;
+
+ if (pMeasureStruct->fsAttribute & MIA_HILITED)
+ {
+ //
+ // If it is currently selected we let the system handle it
+ //
+ eStatus |= wxOwnerDrawn::wxODSelected;
+ }
+ if (pMeasureStruct->fsAttribute & MIA_CHECKED)
+ {
+ //
+ // If it is currently checked we draw our own
+ //
+ eStatus |= wxOwnerDrawn::wxODChecked;
+ pMeasureStruct->fsAttributeOld = pMeasureStruct->fsAttribute &= ~MIA_CHECKED;
+ }
+ if (pMeasureStruct->fsAttribute & MIA_DISABLED)
+ {
+ //
+ // If it is currently disabled we let the system handle it
+ //
+ eStatus |= wxOwnerDrawn::wxODDisabled;
+ }
+ //
+ // Don't really care about framed (indicationg focus) or NoDismiss
+ //
+ }
+ else
+ {
+ if (pMeasureStruct->fsAttribute & MIA_HILITED)
+ {
+ eAction = wxOwnerDrawn::wxODDrawAll;
+ eStatus |= wxOwnerDrawn::wxODSelected;
+ //
+ // Keep the system from trying to highlight with its bogus colors
+ //
+ pMeasureStruct->fsAttributeOld = pMeasureStruct->fsAttribute &= ~MIA_HILITED;
+ }
+ else if (!(pMeasureStruct->fsAttribute & MIA_HILITED))
+ {
+ eAction = wxOwnerDrawn::wxODDrawAll;
+ eStatus = 0;
+ //
+ // Keep the system from trying to highlight with its bogus colors
+ //
+ pMeasureStruct->fsAttribute = pMeasureStruct->fsAttributeOld &= ~MIA_HILITED;
+ }
+ else
+ {
+ //
+ // For now we don't care about anything else
+ // just ignore the entire message!
+ //
+ return true;
+ }
+ }
+ //
+ // Now redraw the item
+ //
+ return(pMenuItem->OnDrawItem( vDc
+ ,vRect
+ ,(wxOwnerDrawn::wxODAction)eAction
+ ,(wxOwnerDrawn::wxODStatus)eStatus
+ ));
+ //
+ // leave the fsAttribute and fsOldAttribute unchanged. If different,
+ // the system will do the highlight or fraeming or disabling for us,
+ // otherwise, we'd have to do it ourselves.
+ //
+ }
+#endif // wxUSE_MENUS_NATIVE
+
+ wxWindow* pItem = FindItem(vId);
+
+ if (pItem && pItem->IsKindOf(CLASSINFO(wxControl)))
+ {
+ return ((wxControl *)pItem)->OS2OnDraw(pItemStruct);
+ }
+#else
+ vId = vId;
+ pItemStruct = pItemStruct;
+#endif
+ return false;
+} // end of wxWindowOS2::OS2OnDrawItem
+
+long wxWindowOS2::OS2OnMeasureItem( int lId,
+ WXMEASUREITEMSTRUCT* pItemStruct )
+{
+#if wxUSE_OWNER_DRAWN
+ //
+ // Is it a menu item?
+ //
+ if (lId == 65536) // I really don't like this...has to be a better indicator
+ {
+ if (IsKindOf(CLASSINFO(wxFrame))) // we'll assume if Frame then a menu
+ {
+ size_t nWidth;
+ size_t nHeight;
+ POWNERITEM pMeasureStruct = (POWNERITEM)pItemStruct;
+ wxFrame* pFrame = (wxFrame*)this;
+ wxMenuItem* pMenuItem = pFrame->GetMenuBar()->FindItem(pMeasureStruct->idItem, pMeasureStruct->hItem);
+
+ wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE );
+ nWidth = 0L;
+ nHeight = 0L;
+ if (pMenuItem->OnMeasureItem( &nWidth
+ ,&nHeight
+ ))
+ {
+ MRESULT mRc;
+
+ pMeasureStruct->rclItem.xRight = nWidth;
+ pMeasureStruct->rclItem.xLeft = 0L;
+ pMeasureStruct->rclItem.yTop = nHeight;
+ pMeasureStruct->rclItem.yBottom = 0L;
+ mRc = MRFROM2SHORT(nHeight, nWidth);
+ return LONGFROMMR(mRc);
+ }
+ return 0L;
+ }
+ }
+ wxWindow* pItem = FindItem(lId);
+
+ if (pItem && pItem->IsKindOf(CLASSINFO(wxControl)))