X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/42e69d6b435a4dd5415caf3750db62cf45b6f373..43b2cccb4b6578afa43b25f4dd15d3d29d89bafd:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index de806ac65f..f0a7bba7b3 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -29,6 +29,10 @@ #endif #ifndef WX_PRECOMP + #include + #include "wx/msw/winundef.h" + #include "wx/window.h" + #include "wx/accel.h" #include "wx/setup.h" #include "wx/menu.h" #include "wx/dc.h" @@ -50,27 +54,32 @@ #include "wx/ownerdrw.h" #endif -#if wxUSE_DRAG_AND_DROP - #include "wx/msw/ole/droptgt.h" +#if wxUSE_DRAG_AND_DROP + #include "wx/dnd.h" #endif #include "wx/menuitem.h" #include "wx/log.h" +#include "wx/msw/private.h" + #if wxUSE_TOOLTIPS #include "wx/tooltip.h" #endif +#if wxUSE_CARET + #include "wx/caret.h" +#endif // wxUSE_CARET + #include "wx/intl.h" #include "wx/log.h" -#include "wx/msw/private.h" - #include "wx/textctrl.h" +#include "wx/notebook.h" #include -#ifndef __GNUWIN32__ +#ifndef __GNUWIN32_OLD__ #include #include #endif @@ -79,28 +88,16 @@ #include #endif -#if ( defined(__WIN95__) && !defined(__GNUWIN32__)) || defined(__TWIN32__ ) - #include -#endif - -#ifndef __TWIN32__ - #ifdef __GNUWIN32__ - #include +#if !defined(__GNUWIN32_OLD__) && !defined(__TWIN32__) + #ifdef __WIN95__ + #include + #endif +#else // broken compiler + #ifndef __TWIN32__ + #include "wx/msw/gnuwin32/extra.h" #endif #endif -#include "wx/msw/winundef.h" - -// --------------------------------------------------------------------------- -// macros -// --------------------------------------------------------------------------- - -// standard macros missing from some compilers headers -#ifndef GET_X_LPARAM - #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp)) - #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp)) -#endif // GET_X_LPARAM - // --------------------------------------------------------------------------- // global variables // --------------------------------------------------------------------------- @@ -110,14 +107,14 @@ extern MSG s_currentMsg; wxMenu *wxCurrentPopupMenu = NULL; extern wxList WXDLLEXPORT wxPendingDelete; -extern char wxCanvasClassName[]; +extern const wxChar *wxCanvasClassName; // --------------------------------------------------------------------------- // private functions // --------------------------------------------------------------------------- // the window proc for all our windows -LRESULT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, +LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #ifdef __WXDEBUG__ @@ -128,19 +125,26 @@ void wxRemoveHandleAssociation(wxWindow *win); void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win); wxWindow *wxFindWinFromHandle(WXHWND hWnd); +// this magical function is used to translate VK_APPS key presses to right +// mouse clicks +static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flags); + +// get the current state of SHIFT/CTRL keys +static inline bool IsShiftDown() { return (GetKeyState(VK_SHIFT) & 0x100) != 0; } +static inline bool IsCtrlDown() { return (GetKeyState(VK_CONTROL) & 0x100) != 0; } + // --------------------------------------------------------------------------- // event tables // --------------------------------------------------------------------------- -#if !USE_SHARED_LIBRARY - IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase) -#endif +IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase) BEGIN_EVENT_TABLE(wxWindow, wxWindowBase) EVT_ERASE_BACKGROUND(wxWindow::OnEraseBackground) EVT_SYS_COLOUR_CHANGED(wxWindow::OnSysColourChanged) EVT_INIT_DIALOG(wxWindow::OnInitDialog) EVT_IDLE(wxWindow::OnIdle) + EVT_SET_FOCUS(wxWindow::OnSetFocus) END_EVENT_TABLE() // =========================================================================== @@ -152,8 +156,19 @@ END_EVENT_TABLE() // --------------------------------------------------------------------------- // Find an item given the MS Windows id -wxWindow *wxWindow::FindItem(int id) const +wxWindow *wxWindow::FindItem(long id) const { + wxControl *item = wxDynamicCast(this, wxControl); + if ( item ) + { + // i it we or one of our "internal" children? + if ( item->GetId() == id || + (item->GetSubcontrols().Index(id) != wxNOT_FOUND) ) + { + return item; + } + } + wxWindowList::Node *current = GetChildren().GetFirst(); while (current) { @@ -163,19 +178,6 @@ wxWindow *wxWindow::FindItem(int id) const if ( wnd ) return wnd; - if ( childWin->IsKindOf(CLASSINFO(wxControl)) ) - { - wxControl *item = (wxControl *)childWin; - if ( item->GetId() == id ) - return item; - else - { - // In case it's a 'virtual' control (e.g. radiobox) - if ( item->GetSubcontrols().Member((wxObject *)id) ) - return item; - } - } - current = current->GetNext(); } @@ -231,12 +233,6 @@ void wxWindow::Init() m_doubleClickAllowed = 0; m_winCaptured = FALSE; - // caret stuff: initially there is no caret at all - m_caretWidth = - m_caretHeight = 0; - m_caretEnabled = - m_caretShown = FALSE; - m_isBeingDeleted = FALSE; m_oldWndProc = 0; m_useCtl3D = FALSE; @@ -245,6 +241,11 @@ void wxWindow::Init() // wxWnd m_hMenu = 0; + m_hWnd = 0; + + // pass WM_GETDLGCODE to DefWindowProc() + m_lDlgCode = 0; + m_xThumbSize = 0; m_yThumbSize = 0; m_backgroundTransparent = FALSE; @@ -273,13 +274,16 @@ wxWindow::~wxWindow() if ( m_hWnd ) { - if ( !::DestroyWindow(GetHwnd()) ) - wxLogLastError("DestroyWindow"); - } + // VZ: test temp removed to understand what really happens here + //if (::IsWindow(GetHwnd())) + { + if ( !::DestroyWindow(GetHwnd()) ) + wxLogLastError("DestroyWindow"); + } - // Restore old Window proc, if required and remove hWnd <-> wxWindow - // association - UnsubclassWin(); + // remove hWnd <-> wxWindow association + wxRemoveHandleAssociation(this); + } } // real construction (Init() must have been called before!) @@ -289,9 +293,10 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id, long style, const wxString& name) { - wxCHECK_MSG( parent, FALSE, "can't create wxWindow without parent" ); + wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") ); - CreateBase(parent, id, pos, size, style, name); + if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) + return FALSE; parent->AddChild(this); @@ -316,6 +321,14 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id, msflags |= WS_BORDER; } + // calculate the value to return from WM_GETDLGCODE handler + if ( GetWindowStyleFlag() & wxWANTS_CHARS ) + { + // want everything: i.e. all keys and WM_CHAR message + m_lDlgCode = DLGC_WANTARROWS | DLGC_WANTCHARS | + DLGC_WANTTAB | DLGC_WANTMESSAGE; + } + MSWCreate(m_windowId, parent, wxCanvasClassName, this, NULL, pos.x, pos.y, WidthDefault(size.x), HeightDefault(size.y), @@ -356,6 +369,15 @@ bool wxWindow::Enable(bool enable) if ( hWnd ) ::EnableWindow(hWnd, (BOOL)enable); + wxWindowList::Node *node = GetChildren().GetFirst(); + while ( node ) + { + wxWindow *child = node->GetData(); + child->Enable(enable); + + node = node->GetNext(); + } + return TRUE; } @@ -431,9 +453,9 @@ bool wxWindow::SetFont(const wxFont& font) { WXHANDLE hFont = m_font.GetResourceHandle(); - wxASSERT_MSG( hFont, _T("should have valid font") ); + wxASSERT_MSG( hFont, wxT("should have valid font") ); - ::SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, TRUE); + ::SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); } return TRUE; @@ -447,7 +469,7 @@ bool wxWindow::SetCursor(const wxCursor& cursor) } wxASSERT_MSG( m_cursor.Ok(), - _T("cursor must be valid after call to the base version")); + wxT("cursor must be valid after call to the base version")); HWND hWnd = GetHwnd(); @@ -459,7 +481,7 @@ bool wxWindow::SetCursor(const wxCursor& cursor) ::GetWindowRect(hWnd, &rect); if ( ::PtInRect(&rect, point) && !wxIsBusy() ) - ::SetCursor((HCURSOR)m_cursor.GetHCURSOR()); + ::SetCursor(GetHcursorOf(m_cursor)); return TRUE; } @@ -784,12 +806,15 @@ void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) void wxWindow::SubclassWin(WXHWND hWnd) { - wxASSERT_MSG( !m_oldWndProc, "subclassing window twice?" ); + wxASSERT_MSG( !m_oldWndProc, wxT("subclassing window twice?") ); - wxAssociateWinWithHandle((HWND)hWnd, this); + HWND hwnd = (HWND)hWnd; + wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in SubclassWin") ); - m_oldWndProc = (WXFARPROC) GetWindowLong((HWND) hWnd, GWL_WNDPROC); - SetWindowLong((HWND) hWnd, GWL_WNDPROC, (LONG) wxWndProc); + wxAssociateWinWithHandle(hwnd, this); + + m_oldWndProc = (WXFARPROC) GetWindowLong(hwnd, GWL_WNDPROC); + SetWindowLong(hwnd, GWL_WNDPROC, (LONG) wxWndProc); } void wxWindow::UnsubclassWin() @@ -797,16 +822,19 @@ void wxWindow::UnsubclassWin() wxRemoveHandleAssociation(this); // Restore old Window proc - if ( GetHwnd() ) + HWND hwnd = GetHwnd(); + if ( hwnd ) { - FARPROC farProc = (FARPROC) GetWindowLong(GetHwnd(), GWL_WNDPROC); + m_hWnd = 0; + + wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") ); + + FARPROC farProc = (FARPROC) GetWindowLong(hwnd, GWL_WNDPROC); if ( (m_oldWndProc != 0) && (farProc != (FARPROC) m_oldWndProc) ) { - SetWindowLong(GetHwnd(), GWL_WNDPROC, (LONG) m_oldWndProc); + SetWindowLong(hwnd, GWL_WNDPROC, (LONG) m_oldWndProc); m_oldWndProc = 0; } - - m_hWnd = 0; } } @@ -836,7 +864,8 @@ WXDWORD wxWindow::MakeExtendedStyle(long style, bool eliminateBorders) // Determines whether native 3D effects or CTL3D should be used, // applying a default border style if required, and returning an extended // style to pass to CreateWindowEx. -WXDWORD wxWindow::Determine3DEffects(WXDWORD defaultBorderStyle, bool *want3D) +WXDWORD wxWindow::Determine3DEffects(WXDWORD defaultBorderStyle, + bool *want3D) const { // If matches certain criteria, then assume no 3D effects // unless specifically requested (dealt with in MakeExtendedStyle) @@ -891,7 +920,7 @@ WXDWORD wxWindow::Determine3DEffects(WXDWORD defaultBorderStyle, bool *want3D) return exStyle; } -#if WXWIN_COMPATIBILITY_2 +#if WXWIN_COMPATIBILITY // If nothing defined for this, try the parent. // E.g. we may be a button loaded from a resource, with no callback function // defined. @@ -1006,7 +1035,7 @@ void wxWindow::Refresh(bool eraseBack, const wxRect *rect) // drag and drop // --------------------------------------------------------------------------- -#if wxUSE_DRAG_AND_DROP +#if wxUSE_DRAG_AND_DROP void wxWindow::SetDropTarget(wxDropTarget *pDropTarget) { @@ -1067,28 +1096,33 @@ void wxWindow::DoGetSize(int *x, int *y) const void wxWindow::DoGetPosition(int *x, int *y) const { HWND hWnd = GetHwnd(); - HWND hParentWnd = 0; - if ( GetParent() ) - hParentWnd = (HWND) GetParent()->GetHWND(); RECT rect; GetWindowRect(hWnd, &rect); - // Since we now have the absolute screen coords, if there's a parent we - // must subtract its top left corner POINT point; point.x = rect.left; point.y = rect.top; - if ( hParentWnd ) - { - ::ScreenToClient(hParentWnd, &point); - } - // We may be faking the client origin. So a window that's really at (0, - // 30) may appear (to wxWin apps) to be at (0, 0). - if ( GetParent() ) + // we do the adjustments with respect to the parent only for the "real" + // children, not for the dialogs/frames + if ( !IsTopLevel() ) { - wxPoint pt(GetParent()->GetClientAreaOrigin()); + HWND hParentWnd = 0; + wxWindow *parent = GetParent(); + if ( parent ) + hParentWnd = GetWinHwnd(parent); + + // Since we now have the absolute screen coords, if there's a parent we + // must subtract its top left corner + if ( hParentWnd ) + { + ::ScreenToClient(hParentWnd, &point); + } + + // We may be faking the client origin. So a window that's really at (0, + // 30) may appear (to wxWin apps) to be at (0, 0). + wxPoint pt(parent->GetClientAreaOrigin()); point.x -= pt.x; point.y -= pt.y; } @@ -1099,7 +1133,7 @@ void wxWindow::DoGetPosition(int *x, int *y) const *y = point.y; } -void wxWindow::ScreenToClient(int *x, int *y) const +void wxWindow::DoScreenToClient(int *x, int *y) const { POINT pt; if ( x ) @@ -1116,7 +1150,7 @@ void wxWindow::ScreenToClient(int *x, int *y) const *y = pt.y; } -void wxWindow::ClientToScreen(int *x, int *y) const +void wxWindow::DoClientToScreen(int *x, int *y) const { POINT pt; if ( x ) @@ -1145,35 +1179,79 @@ void wxWindow::DoGetClientSize(int *x, int *y) const *y = rect.bottom; } +void wxWindow::DoMoveWindow(int x, int y, int width, int height) +{ + if ( !::MoveWindow(GetHwnd(), x, y, width, height, TRUE) ) + { + wxLogLastError("MoveWindow"); + } +} + +// 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 wxWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags) { + // get the current size and position... int currentX, currentY; GetPosition(¤tX, ¤tY); int currentW,currentH; GetSize(¤tW, ¤tH); - if ( x == currentX && y == currentY && width == currentW && height == currentH ) + // ... and don't do anything (avoiding flicker) if it's already ok + if ( x == currentX && y == currentY && + width == currentW && height == currentH ) + { return; + } - int actualWidth = width; - int actualHeight = height; - int actualX = x; - int actualY = y; - if ( x == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) - actualX = currentX; - if ( y == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) - actualY = currentY; + if ( x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) + x = currentX; + if ( y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) + y = currentY; - AdjustForParentClientOrigin(actualX, actualY, sizeFlags); + AdjustForParentClientOrigin(x, y, sizeFlags); + wxSize size(-1, -1); if ( width == -1 ) - actualWidth = currentW; + { + if ( sizeFlags & wxSIZE_AUTO_WIDTH ) + { + size = DoGetBestSize(); + width = size.x; + } + else + { + // just take the current one + width = currentW; + } + } + if ( height == -1 ) - actualHeight = currentH; + { + if ( sizeFlags & wxSIZE_AUTO_HEIGHT ) + { + if ( size.x == -1 ) + { + size = DoGetBestSize(); + } + //else: already called DoGetBestSize() above - HWND hWnd = GetHwnd(); - if ( hWnd ) - MoveWindow(hWnd, actualX, actualY, actualWidth, actualHeight, (BOOL)TRUE); + height = size.y; + } + else + { + // just take the current one + height = currentH; + } + } + + DoMoveWindow(x, y, width, height); } void wxWindow::DoSetClientSize(int width, int height) @@ -1207,7 +1285,7 @@ void wxWindow::DoSetClientSize(int width, int height) ::ScreenToClient(hParentWnd, &point); } - MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)TRUE); + DoMoveWindow(point.x, point.y, actual_width, actual_height); wxSizeEvent event(wxSize(width, height), m_windowId); event.SetEventObject(this); @@ -1225,10 +1303,16 @@ wxPoint wxWindow::GetClientAreaOrigin() const // a toolbar that it manages itself). void wxWindow::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) { - if ( ((sizeFlags & wxSIZE_NO_ADJUSTMENTS) == 0) && GetParent() ) + // don't do it for the dialogs/frames - they float independently of their + // parent + if ( !IsTopLevel() ) { - wxPoint pt(GetParent()->GetClientAreaOrigin()); - x += pt.x; y += pt.y; + wxWindow *parent = GetParent(); + if ( !(sizeFlags & wxSIZE_NO_ADJUSTMENTS) && parent ) + { + wxPoint pt(parent->GetClientAreaOrigin()); + x += pt.x; y += pt.y; + } } } @@ -1260,7 +1344,8 @@ int wxWindow::GetCharWidth() const return lpTextMetric.tmAveCharWidth; } -void wxWindow::GetTextExtent(const wxString& string, int *x, int *y, +void wxWindow::GetTextExtent(const wxString& string, + int *x, int *y, int *descent, int *externalLeading, const wxFont *theFont) const { @@ -1282,7 +1367,7 @@ void wxWindow::GetTextExtent(const wxString& string, int *x, int *y, SIZE sizeRect; TEXTMETRIC tm; - GetTextExtentPoint(dc, (const char *)string, (int)string.Length(), &sizeRect); + GetTextExtentPoint(dc, string, (int)string.Length(), &sizeRect); GetTextMetrics(dc, &tm); if ( fontToUse && fnt && hfontOld ) @@ -1290,56 +1375,81 @@ void wxWindow::GetTextExtent(const wxString& string, int *x, int *y, ReleaseDC(hWnd, dc); - if ( x ) *x = sizeRect.cx; - if ( y ) *y = sizeRect.cy; - if ( descent ) *descent = tm.tmDescent; - if ( externalLeading ) *externalLeading = tm.tmExternalLeading; + if ( x ) + *x = sizeRect.cx; + if ( y ) + *y = sizeRect.cy; + if ( descent ) + *descent = tm.tmDescent; + if ( externalLeading ) + *externalLeading = tm.tmExternalLeading; } +#if wxUSE_CARET && WXWIN_COMPATIBILITY // --------------------------------------------------------------------------- // Caret manipulation // --------------------------------------------------------------------------- void wxWindow::CreateCaret(int w, int h) { - m_caretWidth = w; - m_caretHeight = h; - m_caretEnabled = TRUE; + SetCaret(new wxCaret(this, w, h)); } void wxWindow::CreateCaret(const wxBitmap *WXUNUSED(bitmap)) { - // Not implemented + wxFAIL_MSG("not implemented"); } void wxWindow::ShowCaret(bool show) { - if ( m_caretEnabled ) - { - if ( show ) - ::ShowCaret(GetHwnd()); - else - ::HideCaret(GetHwnd()); - m_caretShown = show; - } + wxCHECK_RET( m_caret, "no caret to show" ); + + m_caret->Show(show); } void wxWindow::DestroyCaret() { - m_caretEnabled = FALSE; + SetCaret(NULL); } void wxWindow::SetCaretPos(int x, int y) { - ::SetCaretPos(x, y); + wxCHECK_RET( m_caret, "no caret to move" ); + + m_caret->Move(x, y); } void wxWindow::GetCaretPos(int *x, int *y) const { + wxCHECK_RET( m_caret, "no caret to get position of" ); + + m_caret->GetPosition(x, y); +} +#endif // wxUSE_CARET + +// --------------------------------------------------------------------------- +// popup menu +// --------------------------------------------------------------------------- + +bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y) +{ + menu->SetInvokingWindow(this); + menu->UpdateUI(); + + HWND hWnd = GetHwnd(); + HMENU hMenu = GetHmenuOf(menu); POINT point; - ::GetCaretPos(&point); - *x = point.x; - *y = point.y; + point.x = x; + point.y = y; + ::ClientToScreen(hWnd, &point); + wxCurrentPopupMenu = menu; + ::TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL); + wxYield(); + wxCurrentPopupMenu = NULL; + + menu->SetInvokingWindow(NULL); + + return TRUE; } // =========================================================================== @@ -1360,6 +1470,10 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) { // intercept dialog navigation keys MSG *msg = (MSG *)pMsg; + + // here we try to do all the job which ::IsDialogMessage() usually does + // internally +#if 1 bool bProcess = TRUE; if ( msg->message != WM_KEYDOWN ) bProcess = FALSE; @@ -1369,7 +1483,8 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) if ( bProcess ) { - bool bCtrlDown = (::GetKeyState(VK_CONTROL) & 0x100) != 0; + bool bCtrlDown = IsCtrlDown(); + bool bShiftDown = IsShiftDown(); // WM_GETDLGCODE: ask the control if it wants the key for itself, // don't process it if it's the case (except for Ctrl-Tab/Enter @@ -1383,16 +1498,19 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) bool bForward = TRUE, bWindowChange = FALSE; - switch ( msg->wParam ) + switch ( msg->wParam ) { case VK_TAB: - if ( lDlgCode & DLGC_WANTTAB ) { + // assume that nobody wants Shift-TAB for himself - if we + // don't do it there is no easy way for a control to grab + // TABs but still let Shift-TAB work as navugation key + if ( (lDlgCode & DLGC_WANTTAB) && !bShiftDown ) { bProcess = FALSE; } else { // Ctrl-Tab cycles thru notebook pages bWindowChange = bCtrlDown; - bForward = !(::GetKeyState(VK_SHIFT) & 0x100); + bForward = !bShiftDown; } break; @@ -1412,27 +1530,40 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) case VK_RETURN: { - if ( lDlgCode & DLGC_WANTMESSAGE ) + if ( (lDlgCode & DLGC_WANTMESSAGE) && !bCtrlDown ) { // control wants to process Enter itself, don't // call IsDialogMessage() which would interpret // it return FALSE; } -#ifndef __WIN16__ - wxButton *btnDefault = GetDefaultItem(); - if ( btnDefault && !bCtrlDown ) + else if ( lDlgCode & DLGC_BUTTON ) { - // if there is a default button, Enter should - // press it - (void)::SendMessage((HWND)btnDefault->GetHWND(), - BM_CLICK, 0, 0); - return TRUE; + // buttons want process Enter themselevs + bProcess = FALSE; + } + else + { + wxPanel *panel = wxDynamicCast(this, wxPanel); + wxButton *btn = NULL; + if ( panel ) + { + // panel may have a default button which should + // be activated by Enter + btn = panel->GetDefaultItem(); + } + + if ( btn && btn->IsEnabled() ) + { + // if we do have a default button, do press it + btn->MSWCommand(BN_CLICKED, 0 /* unused */); + + return TRUE; + } + // 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. } - // else: but if there is 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. -#endif } break; @@ -1448,9 +1579,47 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) event.SetEventObject(this); if ( GetEventHandler()->ProcessEvent(event) ) + { + wxButton *btn = wxDynamicCast(FindFocus(), wxButton); + if ( btn ) + { + // the button which has focus should be default + btn->SetDefault(); + } + return TRUE; + } } } +#else + // let ::IsDialogMessage() do almost everything and handle just the + // things it doesn't here: Ctrl-TAB for switching notebook pages + if ( msg->message == WM_KEYDOWN ) + { + // don't process system keys here + if ( !(HIWORD(msg->lParam) & KF_ALTDOWN) ) + { + if ( (msg->wParam == VK_TAB) && IsCtrlDown() ) + { + // find the first notebook parent and change its page + wxWindow *win = this; + wxNotebook *nbook = NULL; + while ( win && !nbook ) + { + nbook = wxDynamicCast(win, wxNotebook); + win = win->GetParent(); + } + + if ( nbook ) + { + bool forward = !IsShiftDown(); + + nbook->AdvanceSelection(forward); + } + } + } + } +#endif // 0 if ( ::IsDialogMessage(GetHwnd(), msg) ) return TRUE; @@ -1471,10 +1640,7 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) bool wxWindow::MSWTranslateMessage(WXMSG* pMsg) { - return m_acceleratorTable.Ok() && - ::TranslateAccelerator(GetHwnd(), - GetTableHaccel(m_acceleratorTable), - (MSG *)pMsg); + return m_acceleratorTable.Translate(this, pMsg); } // --------------------------------------------------------------------------- @@ -1552,7 +1718,7 @@ void wxWindow::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam, void wxWindow::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam, WXWORD *nCtlColor, WXHDC *hdc, WXHWND *hwnd) { - *control = (WXHWND)LOWORD(lParam); + *hwnd = (WXHWND)LOWORD(lParam); *nCtlColor = (int)HIWORD(lParam); *hdc = (WXHDC)wParam; } @@ -1576,11 +1742,11 @@ void wxWindow::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, wxWindow *wxWndHook = NULL; // Main window proc -LRESULT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { // trace all messages - useful for the debugging #ifdef __WXDEBUG__ - wxLogTrace(wxTraceMessages, "Processing %s(wParam=%8lx, lParam=%8lx)", + wxLogTrace(wxTraceMessages, wxT("Processing %s(wParam=%8lx, lParam=%8lx)"), wxGetMessageName(message), wParam, lParam); #endif // __WXDEBUG__ @@ -1590,6 +1756,12 @@ LRESULT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARA // it with wxWindow stored in wxWndHook if ( !wnd && wxWndHook ) { +#if 0 // def __WXDEBUG__ + char buf[512]; + ::GetClassNameA((HWND) hWnd, buf, 512); + wxString className(buf); +#endif + wxAssociateWinWithHandle(hWnd, wxWndHook); wnd = wxWndHook; wxWndHook = NULL; @@ -1694,7 +1866,20 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) break; case WM_MOUSEMOVE: + { + short x = LOWORD(lParam); + short y = HIWORD(lParam); + + processed = HandleMouseMove(x, y, wParam); + } + break; + case WM_LBUTTONDOWN: + // set focus to this window + SetFocus(); + + // fall through + case WM_LBUTTONUP: case WM_LBUTTONDBLCLK: case WM_RBUTTONDOWN: @@ -1704,8 +1889,8 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) case WM_MBUTTONUP: case WM_MBUTTONDBLCLK: { - int x = LOWORD(lParam); - int y = HIWORD(lParam); + short x = LOWORD(lParam); + short y = HIWORD(lParam); processed = HandleMouseEvent(message, x, y, wParam); } @@ -1768,6 +1953,16 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) } break; + case WM_GETDLGCODE: + if ( m_lDlgCode ) + { + rc.result = m_lDlgCode; + processed = TRUE; + } + //else: get the dlg code from the DefWindowProc() + break; + + case WM_SYSKEYDOWN: case WM_KEYDOWN: // If this has been processed by an event handler, // return 0 now (we've handled it). @@ -1795,7 +1990,12 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) case VK_RETURN: case VK_BACK: case VK_TAB: - processed = TRUE; + case VK_ADD: + case VK_SUBTRACT: + // 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 + processed = FALSE; break; @@ -1804,20 +2004,11 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) // click because both usually pop up a context menu case VK_APPS: { - // construct the key mask - WPARAM fwKeys = MK_RBUTTON; - if ( (::GetKeyState(VK_CONTROL) & 0x100) != 0 ) - fwKeys |= MK_CONTROL; - if ( (::GetKeyState(VK_SHIFT) & 0x100) != 0 ) - fwKeys |= MK_SHIFT; - - // simulate right mouse button click - DWORD dwPos = ::GetMessagePos(); - int x = GET_X_LPARAM(dwPos), - y = GET_Y_LPARAM(dwPos); - - ScreenToClient(&x, &y); - processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, fwKeys); + WPARAM flags; + int x, y; + + TranslateKbdEventToMouse(this, &x, &y, &flags); + processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags); } break; #endif // VK_APPS @@ -1831,10 +2022,26 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) } break; + case WM_SYSKEYUP: case WM_KEYUP: - processed = HandleKeyUp((WORD) wParam, lParam); +#ifdef VK_APPS + // special case of VK_APPS: treat it the same as right mouse button + if ( wParam == VK_APPS ) + { + WPARAM flags; + int x, y; + + TranslateKbdEventToMouse(this, &x, &y, &flags); + processed = HandleMouseEvent(WM_RBUTTONUP, x, y, flags); + } + else +#endif // VK_APPS + { + processed = HandleKeyUp((WORD) wParam, lParam); + } break; + case WM_SYSCHAR: case WM_CHAR: // Always an ASCII character processed = HandleChar((WORD)wParam, lParam, TRUE); break; @@ -1926,7 +2133,7 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) break; case WM_GETMINMAXINFO: - processed = HandleGetMinMaxInfo((LPMINMAXINFO)lParam); + processed = HandleGetMinMaxInfo((MINMAXINFO*)lParam); break; case WM_SETCURSOR: @@ -1947,7 +2154,7 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) if ( !processed ) { #ifdef __WXDEBUG__ - wxLogTrace(wxTraceMessages, "Forwarding %s to DefWindowProc.", + wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."), wxGetMessageName(message)); #endif // __WXDEBUG__ rc.result = MSWDefWindowProc(message, wParam, lParam); @@ -1983,19 +2190,44 @@ wxWindow *wxFindWinFromHandle(WXHWND hWnd) return (wxWindow *)node->Data(); } +#if 0 // def __WXDEBUG__ +static int gs_AssociationCount = 0; +#endif + void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win) { // adding NULL hWnd is (first) surely a result of an error and // (secondly) breaks menu command processing wxCHECK_RET( hWnd != (HWND)NULL, - "attempt to add a NULL hWnd to window list ignored" ); + wxT("attempt to add a NULL hWnd to window list ignored") ); + + + wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd); + if ( oldWin && (oldWin != win) ) + { + wxString str(win->GetClassInfo()->GetClassName()); + wxLogError(wxT("Bug! Found existing HWND %X for new window of class %s"), (int) hWnd, (const wxChar*) str); + } + else if (!oldWin) + { +#if 0 // def __WXDEBUG__ + gs_AssociationCount ++; + wxLogDebug("+ Association %d", gs_AssociationCount); +#endif - if ( !wxWinHandleList->Find((long)hWnd) ) wxWinHandleList->Append((long)hWnd, win); + } } void wxRemoveHandleAssociation(wxWindow *win) { +#if 0 // def __WXDEBUG__ + if (wxWinHandleList->Member(win)) + { + wxLogDebug("- Association %d", gs_AssociationCount); + gs_AssociationCount --; + } +#endif wxWinHandleList->DeleteObject(win); } @@ -2015,16 +2247,16 @@ void wxWindow::MSWDetachWindowMenu() int i; for (i = 0; i < N; i++) { - char buf[100]; + wxChar buf[100]; int chars = GetMenuString(hMenu, i, buf, 100, MF_BYPOSITION); if ( !chars ) { - wxLogLastError("GetMenuString"); + wxLogLastError(wxT("GetMenuString")); continue; } - if ( strcmp(buf, "&Window") == 0 ) + if ( wxStrcmp(buf, wxT("&Window")) == 0 ) { RemoveMenu(hMenu, i, MF_BYPOSITION); @@ -2036,15 +2268,15 @@ void wxWindow::MSWDetachWindowMenu() bool wxWindow::MSWCreate(int id, wxWindow *parent, - const char *wclass, + const wxChar *wclass, wxWindow *wx_win, - const char *title, + const wxChar *title, int x, int y, int width, int height, WXDWORD style, - const char *dialog_template, + const wxChar *dialog_template, WXDWORD extendedStyle) { int x1 = CW_USEDEFAULT; @@ -2068,7 +2300,18 @@ bool wxWindow::MSWCreate(int id, if ( width > -1 ) width1 = width; if ( height > -1 ) height1 = height; - HWND hParent = NULL; + // Unfortunately this won't work in WIN16. Unless perhaps + // we define WS_EX_CONTROLPARENT ourselves? +#ifndef __WIN16__ + // if we have wxTAB_TRAVERSAL style, we want WS_EX_CONTROLPARENT or + // IsDialogMessage() won't work for us + if ( GetWindowStyleFlag() & wxTAB_TRAVERSAL ) + { + extendedStyle |= WS_EX_CONTROLPARENT; + } +#endif + + HWND hParent = (HWND)NULL; if ( parent ) hParent = (HWND) parent->GetHWND(); @@ -2089,7 +2332,22 @@ bool wxWindow::MSWCreate(int id, return FALSE; } - ::MoveWindow(GetHwnd(), x1, y1, width1, height1, FALSE); + // ::SetWindowLong(GWL_EXSTYLE) doesn't work for the dialogs, so try + // to take care of (at least some) extended style flags ourselves + if ( extendedStyle & WS_EX_TOPMOST ) + { + if ( !::SetWindowPos(GetHwnd(), HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE) ) + { + wxLogLastError(wxT("SetWindowPos")); + } + } + + // move the dialog to its initial position without forcing repainting + if ( !::MoveWindow(GetHwnd(), x1, y1, width1, height1, FALSE) ) + { + wxLogLastError(wxT("MoveWindow")); + } } else { @@ -2097,9 +2355,15 @@ bool wxWindow::MSWCreate(int id, if ( style & WS_CHILD ) controlId = id; + wxString className(wclass); + if ( GetWindowStyleFlag() & wxNO_FULL_REPAINT_ON_RESIZE ) + { + className += wxT("NR"); + } + m_hWnd = (WXHWND)CreateWindowEx(extendedStyle, - wclass, - title ? title : "", + className, + title ? title : wxT(""), style, x1, y1, width1, height1, @@ -2118,7 +2382,18 @@ bool wxWindow::MSWCreate(int id, } wxWndHook = NULL; - wxWinHandleList->Append((long)m_hWnd, this); +#ifdef __WXDEBUG__ + wxNode* node = wxWinHandleList->Member(this); + if (node) + { + HWND hWnd = (HWND) node->GetKeyInteger(); + if (hWnd != (HWND) m_hWnd) + { + wxLogError(wxT("A second HWND association is being added for the same window!")); + } + } +#endif + wxAssociateWinWithHandle((HWND) m_hWnd, this); return TRUE; } @@ -2170,10 +2445,10 @@ bool wxWindow::MSWOnNotify(int WXUNUSED(idCtrl), { #if wxUSE_TOOLTIPS NMHDR* hdr = (NMHDR *)lParam; - if ( hdr->code == TTN_NEEDTEXT && m_tooltip ) + if ( (int)hdr->code == TTN_NEEDTEXT && m_tooltip ) { TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam; - ttt->lpszText = (char *)m_tooltip->GetTip().c_str(); + ttt->lpszText = (wxChar *)m_tooltip->GetTip().c_str(); // processed return TRUE; @@ -2193,7 +2468,7 @@ bool wxWindow::HandleQueryEndSession(long logOff, bool *mayEnd) wxCloseEvent event(wxEVT_QUERY_END_SESSION, -1); event.SetEventObject(wxTheApp); event.SetCanVeto(TRUE); - event.SetLoggingOff(logOff == ENDSESSION_LOGOFF); + event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF); bool rc = wxTheApp->ProcessEvent(event); @@ -2216,7 +2491,7 @@ bool wxWindow::HandleEndSession(bool endSession, long logOff) wxCloseEvent event(wxEVT_END_SESSION, -1); event.SetEventObject(wxTheApp); event.SetCanVeto(FALSE); - event.SetLoggingOff( (logOff == ENDSESSION_LOGOFF) ); + event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) ); if ( (this == wxTheApp->GetTopWindow()) && // Only send once wxTheApp->ProcessEvent(event)) { @@ -2263,6 +2538,33 @@ bool wxWindow::HandleDestroy() // activation/focus // --------------------------------------------------------------------------- +void wxWindow::OnSetFocus(wxFocusEvent& event) +{ + // panel wants to track the window which was the last to have focus in it, + // so we want to set ourselves as the window which last had focus + // + // notice that it's also important to do it upwards the tree becaus + // otherwise when the top level panel gets focus, it won't set it back to + // us, but to some other sibling + wxWindow *win = this; + while ( win ) + { + wxWindow *parent = win->GetParent(); + wxPanel *panel = wxDynamicCast(parent, wxPanel); + if ( panel ) + { + panel->SetLastFocus(win); + } + + win = parent; + } + + wxLogTrace(_T("focus"), _T("%s (0x%08x) gets focus"), + GetClassInfo()->GetClassName(), GetHandle()); + + event.Skip(); +} + bool wxWindow::HandleActivate(int state, bool WXUNUSED(minimized), WXHWND WXUNUSED(activate)) @@ -2277,27 +2579,13 @@ bool wxWindow::HandleActivate(int state, bool wxWindow::HandleSetFocus(WXHWND WXUNUSED(hwnd)) { +#if wxUSE_CARET // Deal with caret - if ( m_caretEnabled && (m_caretWidth > 0) && (m_caretHeight > 0) ) - { - if ( ::CreateCaret(GetHwnd(), NULL, m_caretWidth, m_caretHeight) ) - { - if ( m_caretShown ) - { - if ( !::ShowCaret(GetHwnd()) ) - wxLogLastError("ShowCaret"); - } - } - else - wxLogLastError("CreateCaret"); - } - - // panel wants to track the window which was the last to have focus in it - wxWindow *parent = GetParent(); - if ( parent && parent->IsKindOf(CLASSINFO(wxPanel)) ) + if ( m_caret ) { - ((wxPanel *)parent)->SetLastFocus(GetId()); + m_caret->OnSetFocus(); } +#endif // wxUSE_CARET wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId); event.SetEventObject(this); @@ -2307,12 +2595,13 @@ bool wxWindow::HandleSetFocus(WXHWND WXUNUSED(hwnd)) bool wxWindow::HandleKillFocus(WXHWND WXUNUSED(hwnd)) { +#if wxUSE_CARET // Deal with caret - if ( m_caretEnabled ) + if ( m_caret ) { - if ( !::DestroyCaret() ) - wxLogLastError("DestroyCaret"); + m_caret->OnKillFocus(); } +#endif // wxUSE_CARET wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId); event.SetEventObject(this); @@ -2356,7 +2645,7 @@ bool wxWindow::HandleDropFiles(WXWPARAM wParam) int wIndex; for (wIndex=0; wIndex < (int)gwFilesDropped; wIndex++) { - DragQueryFile (hFilesInfo, wIndex, (LPSTR) wxBuffer, 1000); + DragQueryFile (hFilesInfo, wIndex, (LPTSTR) wxBuffer, 1000); files[wIndex] = wxBuffer; } DragFinish (hFilesInfo); @@ -2376,63 +2665,55 @@ bool wxWindow::HandleSetCursor(WXHWND hWnd, short nHitTest, int WXUNUSED(mouseMsg)) { - // don't set cursor for other windows, only for this one: this prevents - // children of this window from getting the same cursor as the parent has - // (don't forget that this message is propagated by default up the window - // parent-child hierarchy) - if ( GetHWND() == hWnd ) - { - // don't set cursor when the mouse is not in the client part - if ( nHitTest == HTCLIENT || nHitTest == HTERROR ) - { - HCURSOR hcursor = 0; - if ( wxIsBusy() ) - { - // from msw\utils.cpp - extern HCURSOR gs_wxBusyCursor; + // the logic is as follows: + // 1. if we have the cursor set it unless wxIsBusy() + // 2. if we're a top level window, set some cursor anyhow + // 3. if wxIsBusy(), set the busy cursor, otherwise the global one - hcursor = gs_wxBusyCursor; - } - else - { - wxCursor *cursor = NULL; - - if ( m_cursor.Ok() ) - { - cursor = &m_cursor; - } - else - { - // from msw\data.cpp - extern wxCursor *g_globalCursor; - - if ( g_globalCursor && g_globalCursor->Ok() ) - cursor = g_globalCursor; - } - - if ( cursor ) - hcursor = (HCURSOR)cursor->GetHCURSOR(); - } + HCURSOR hcursor = 0; + bool isBusy = wxIsBusy(); + if ( m_cursor.Ok() ) + { + hcursor = GetHcursorOf(m_cursor); + } - if ( hcursor ) + if ( !GetParent() ) + { + if ( isBusy ) + { + hcursor = wxGetCurrentBusyCursor(); + } + else if ( !hcursor ) + { + const wxCursor *cursor = wxGetGlobalCursor(); + if ( cursor && cursor->Ok() ) { - ::SetCursor(hcursor); - - return TRUE; + hcursor = GetHcursorOf(*cursor); } } } - return FALSE; + if ( hcursor ) + { + ::SetCursor(hcursor); + + // cursor set, stop here + return TRUE; + } + else + { + // pass up the window chain + return FALSE; + } } -#if wxUSE_OWNER_DRAWN // --------------------------------------------------------------------------- // owner drawn stuff // --------------------------------------------------------------------------- bool wxWindow::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct) { +#if wxUSE_OWNER_DRAWN // is it a menu item? if ( id == 0 ) { @@ -2461,12 +2742,14 @@ bool wxWindow::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct) { return ((wxControl *)item)->MSWOnDraw(itemStruct); } - else - return FALSE; +#endif // USE_OWNER_DRAWN + + return FALSE; } bool wxWindow::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct) { +#if wxUSE_OWNER_DRAWN // is it a menu item? if ( id == 0 ) { @@ -2484,10 +2767,9 @@ bool wxWindow::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct) { return ((wxControl *)item)->MSWOnMeasure(itemStruct); } - +#endif // owner-drawn menus return FALSE; } -#endif // owner-drawn menus // --------------------------------------------------------------------------- // colours and palettes @@ -2731,14 +3013,41 @@ bool wxWindow::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) return popupMenu->MSWCommand(cmd, id); } - wxWindow *win = FindItem(id); - if ( !win ) + wxWindow *win = (wxWindow*) NULL; + if ( cmd == 0 || cmd == 1 ) // menu or accel - use id + { + // must cast to a signed type before comparing with other ids! + win = FindItem((signed short)id); + } + + if (!win && control) { + // find it from HWND - this works even with the broken programs using + // the same ids for different controls win = wxFindWinFromHandle(control); } if ( win ) + { return win->MSWCommand(cmd, id); + } + + // the messages sent from the in-place edit control used by the treectrl + // for label editing have id == 0, but they should _not_ be treated as menu + // messages (they are EN_XXX ones, in fact) so don't translate anything + // coming from a control to wxEVT_COMMAND_MENU_SELECTED + if ( !control ) + { + // If no child window, it may be an accelerator, e.g. for a popup menu + // command + + wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED); + event.SetEventObject(this); + event.SetId(id); + event.SetInt(id); + + return GetEventHandler()->ProcessEvent(event); + } return FALSE; } @@ -2843,12 +3152,43 @@ bool wxWindow::HandleMouseMove(int x, int y, WXUINT flags) // keyboard handling // --------------------------------------------------------------------------- +// create the key event of the given type for the given key - used by +// HandleChar and HandleKeyDown/Up +wxKeyEvent wxWindow::CreateKeyEvent(wxEventType evType, + int id, + WXLPARAM lParam) const +{ + wxKeyEvent event(evType); + event.SetId(GetId()); + event.m_shiftDown = IsShiftDown(); + event.m_controlDown = IsCtrlDown(); + event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN; + + event.m_eventObject = (wxWindow *)this; // const_cast + event.m_keyCode = id; + event.SetTimestamp(s_currentMsg.time); + + // translate the position to client coords + POINT pt; + GetCursorPos(&pt); + RECT rect; + GetWindowRect(GetHwnd(),&rect); + pt.x -= rect.left; + pt.y -= rect.top; + + event.m_x = pt.x; + event.m_y = pt.y; + + return event; +} + // isASCII is TRUE only when we're called from WM_CHAR handler and not from // WM_KEYDOWN one bool wxWindow::HandleChar(WXWORD wParam, WXLPARAM lParam, bool isASCII) { + bool ctrlDown = FALSE; + int id; - bool tempControlDown = FALSE; if ( isASCII ) { // If 1 -> 26, translate to CTRL plus a letter. @@ -2857,142 +3197,86 @@ bool wxWindow::HandleChar(WXWORD wParam, WXLPARAM lParam, bool isASCII) { switch (id) { - case 13: - { + case 13: id = WXK_RETURN; break; - } - case 8: - { + + case 8: id = WXK_BACK; break; - } - case 9: - { + + case 9: id = WXK_TAB; break; - } - default: - { - tempControlDown = TRUE; + + default: + ctrlDown = TRUE; id = id + 96; - } } } } - else if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) { + else if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) + { // it's ASCII and will be processed here only when called from - // WM_CHAR (i.e. when isASCII = TRUE) + // WM_CHAR (i.e. when isASCII = TRUE), don't process it now id = -1; } if ( id != -1 ) { - wxKeyEvent event(wxEVT_CHAR); - event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE); - event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE); - if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN ) - event.m_altDown = TRUE; - - event.m_eventObject = this; - event.m_keyCode = id; - event.SetTimestamp(s_currentMsg.time); - - POINT pt; - GetCursorPos(&pt); - RECT rect; - GetWindowRect(GetHwnd(),&rect); - pt.x -= rect.left; - pt.y -= rect.top; - - event.m_x = pt.x; event.m_y = pt.y; + wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam)); + if ( ctrlDown ) + { + event.m_controlDown = TRUE; + } if ( GetEventHandler()->ProcessEvent(event) ) return TRUE; - else - return FALSE; } - else - return FALSE; + + return FALSE; } bool wxWindow::HandleKeyDown(WXWORD wParam, WXLPARAM lParam) { - int id; + int id = wxCharCodeMSWToWX(wParam); - if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) { + if ( !id ) + { + // normal ASCII char id = wParam; } - if ( id != -1 ) + if ( id != -1 ) // VZ: does this ever happen (FIXME)? { - wxKeyEvent event(wxEVT_KEY_DOWN); - event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE); - event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE); - if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN ) - event.m_altDown = TRUE; - - event.m_eventObject = this; - event.m_keyCode = id; - event.SetTimestamp(s_currentMsg.time); - - POINT pt; - GetCursorPos(&pt); - RECT rect; - GetWindowRect(GetHwnd(),&rect); - pt.x -= rect.left; - pt.y -= rect.top; - - event.m_x = pt.x; event.m_y = pt.y; - + wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam)); if ( GetEventHandler()->ProcessEvent(event) ) { return TRUE; } - else return FALSE; - } - else - { - return FALSE; } + + return FALSE; } bool wxWindow::HandleKeyUp(WXWORD wParam, WXLPARAM lParam) { - int id; + int id = wxCharCodeMSWToWX(wParam); - if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) { + if ( !id ) + { + // normal ASCII char id = wParam; } - if ( id != -1 ) + if ( id != -1 ) // VZ: does this ever happen (FIXME)? { - wxKeyEvent event(wxEVT_KEY_UP); - event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE); - event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE); - if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN ) - event.m_altDown = TRUE; - - event.m_eventObject = this; - event.m_keyCode = id; - event.SetTimestamp(s_currentMsg.time); - - POINT pt; - GetCursorPos(&pt); - RECT rect; - GetWindowRect(GetHwnd(),&rect); - pt.x -= rect.left; - pt.y -= rect.top; - - event.m_x = pt.x; event.m_y = pt.y; - + wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam)); if ( GetEventHandler()->ProcessEvent(event) ) return TRUE; - else - return FALSE; } - else - return FALSE; + + return FALSE; } // --------------------------------------------------------------------------- @@ -3067,7 +3351,7 @@ bool wxWindow::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags) break; default: - wxFAIL_MSG("no such joystick event"); + wxFAIL_MSG(wxT("no such joystick event")); return FALSE; } @@ -3093,7 +3377,7 @@ bool wxWindow::MSWOnScroll(int orientation, WXWORD wParam, return child->MSWOnScroll(orientation, wParam, pos, control); } - wxScrollEvent event; + wxScrollWinEvent event; event.SetPosition(pos); event.SetOrientation(orientation); event.m_eventObject = this; @@ -3101,32 +3385,35 @@ bool wxWindow::MSWOnScroll(int orientation, WXWORD wParam, switch ( wParam ) { case SB_TOP: - event.m_eventType = wxEVT_SCROLL_TOP; + event.m_eventType = wxEVT_SCROLLWIN_TOP; break; case SB_BOTTOM: - event.m_eventType = wxEVT_SCROLL_BOTTOM; + event.m_eventType = wxEVT_SCROLLWIN_BOTTOM; break; case SB_LINEUP: - event.m_eventType = wxEVT_SCROLL_LINEUP; + event.m_eventType = wxEVT_SCROLLWIN_LINEUP; break; case SB_LINEDOWN: - event.m_eventType = wxEVT_SCROLL_LINEDOWN; + event.m_eventType = wxEVT_SCROLLWIN_LINEDOWN; break; case SB_PAGEUP: - event.m_eventType = wxEVT_SCROLL_PAGEUP; + event.m_eventType = wxEVT_SCROLLWIN_PAGEUP; break; case SB_PAGEDOWN: - event.m_eventType = wxEVT_SCROLL_PAGEDOWN; + event.m_eventType = wxEVT_SCROLLWIN_PAGEDOWN; break; - case SB_THUMBTRACK: case SB_THUMBPOSITION: - event.m_eventType = wxEVT_SCROLL_THUMBTRACK; + event.m_eventType = wxEVT_SCROLLWIN_THUMBRELEASE; + break; + + case SB_THUMBTRACK: + event.m_eventType = wxEVT_SCROLLWIN_THUMBTRACK; break; default: @@ -3140,7 +3427,7 @@ bool wxWindow::MSWOnScroll(int orientation, WXWORD wParam, // global functions // =========================================================================== -void wxGetCharSize(WXHWND wnd, int *x, int *y,wxFont *the_font) +void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont *the_font) { TEXTMETRIC tm; HDC dc = ::GetDC((HWND) wnd); @@ -3150,7 +3437,7 @@ void wxGetCharSize(WXHWND wnd, int *x, int *y,wxFont *the_font) { // the_font->UseResource(); // the_font->RealizeResource(); - fnt = (HFONT)the_font->GetResourceHandle(); + fnt = (HFONT)((wxFont *)the_font)->GetResourceHandle(); // const_cast if ( fnt ) was = (HFONT) SelectObject(dc,fnt); } @@ -3160,8 +3447,11 @@ void wxGetCharSize(WXHWND wnd, int *x, int *y,wxFont *the_font) SelectObject(dc,was); } ReleaseDC((HWND)wnd, dc); - *x = tm.tmAveCharWidth; - *y = tm.tmHeight + tm.tmExternalLeading; + + if ( x ) + *x = tm.tmAveCharWidth; + if ( y ) + *y = tm.tmHeight + tm.tmExternalLeading; // if ( the_font ) // the_font->ReleaseResource(); @@ -3335,6 +3625,48 @@ wxWindow *wxGetActiveWindow() return NULL; } +extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) +{ + HWND hwnd = (HWND)hWnd; + + // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set + // by code in msw/radiobox.cpp), for all the others we just search up the + // window hierarchy + wxWindow *win = (wxWindow *)NULL; + if ( hwnd ) + { + win = wxFindWinFromHandle((WXHWND)hwnd); + if ( !win ) + { + // the radiobox pointer is stored in GWL_USERDATA only under Win32 +#ifdef __WIN32__ + // native radiobuttons return DLGC_RADIOBUTTON here and for any + // wxWindow class which overrides WM_GETDLGCODE processing to + // do it as well, win would be already non NULL + if ( ::SendMessage((HWND)hwnd, WM_GETDLGCODE, + 0, 0) & DLGC_RADIOBUTTON ) + { + win = (wxWindow *)::GetWindowLong(hwnd, GWL_USERDATA); + } + else +#endif // Win32 + { + // hwnd is not a wxWindow, try its parent next below + hwnd = ::GetParent(hwnd); + } + } + //else: it's a wxRadioButton, not a radiobutton from wxRadioBox + } + + while ( hwnd && !win ) + { + win = wxFindWinFromHandle((WXHWND)hwnd); + hwnd = ::GetParent(hwnd); + } + + return win; +} + // Windows keyboard hook. Allows interception of e.g. F1, ESCAPE // in active frames and dialogs, regardless of where the focus is. static HHOOK wxTheKeyboardHook = 0; @@ -3348,17 +3680,23 @@ void wxSetKeyboardHook(bool doIt) { wxTheKeyboardHookProc = MakeProcInstance((FARPROC) wxKeyboardHook, wxGetInstance()); wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(), + #if defined(__WIN32__) && !defined(__TWIN32__) - GetCurrentThreadId()); + GetCurrentThreadId() // (DWORD)GetCurrentProcess()); // This is another possibility. Which is right? #else - GetCurrentTask()); + GetCurrentTask() #endif + ); } else { UnhookWindowsHookEx(wxTheKeyboardHook); + // avoids mingw warning about statement with no effect (FreeProcInstance + // doesn't do anything under Win32) +#ifndef __GNUC__ FreeProcInstance(wxTheKeyboardHookProc); +#endif } } @@ -3368,8 +3706,8 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) DWORD hiWord = HIWORD(lParam); if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) ) { - int id; - if ( (id = wxCharCodeMSWToWX(wParam)) != 0 ) + int id = wxCharCodeMSWToWX(wParam); + if ( id != 0 ) { wxKeyEvent event(wxEVT_CHAR_HOOK); if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN ) @@ -3377,25 +3715,31 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) event.m_eventObject = NULL; event.m_keyCode = id; - /* begin Albert's fix for control and shift key 26.5 */ - event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE); - event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE); - /* end Albert's fix for control and shift key 26.5 */ + event.m_shiftDown = IsShiftDown(); + event.m_controlDown = IsCtrlDown(); event.SetTimestamp(s_currentMsg.time); wxWindow *win = wxGetActiveWindow(); + wxEvtHandler *handler; if ( win ) { - if ( win->GetEventHandler()->ProcessEvent(event) ) - return 1; + handler = win->GetEventHandler(); + event.SetId(win->GetId()); } else { - if ( wxTheApp && wxTheApp->ProcessEvent(event) ) - return 1; + handler = wxTheApp; + event.SetId(-1); + } + + if ( handler && handler->ProcessEvent(event) ) + { + // processed + return 1; } } } + return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam); } @@ -3817,3 +4161,22 @@ const char *wxGetMessageName(int message) } } #endif //__WXDEBUG__ + +static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flags) +{ + // construct the key mask + WPARAM& fwKeys = *flags; + + fwKeys = MK_RBUTTON; + if ( (::GetKeyState(VK_CONTROL) & 0x100) != 0 ) + fwKeys |= MK_CONTROL; + if ( (::GetKeyState(VK_SHIFT) & 0x100) != 0 ) + fwKeys |= MK_SHIFT; + + // simulate right mouse button click + DWORD dwPos = ::GetMessagePos(); + *x = GET_X_LPARAM(dwPos); + *y = GET_Y_LPARAM(dwPos); + + win->ScreenToClient(x, y); +}