extern wxMenu *wxCurrentPopupMenu;
#endif
+#if wxUSE_UXTHEME
+// This is a hack used by the owner-drawn wxButton implementation to ensure
+// that the brush used for erasing its background is correctly aligned with the
+// control.
+extern wxWindowMSW *wxWindowBeingErased = NULL;
+#endif // wxUSE_UXTHEME
+
namespace
{
#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
+// If this variable is strictly positive, EVT_CHAR_HOOK is not generated for
+// Escape key presses as it can't be intercepted because it's needed by some
+// currently shown window, e.g. IME entry.
+//
+// This is currently global as we allow using UI from the main thread only
+// anyhow but could be replaced with a thread-specific value in the future if
+// needed.
+int gs_modalEntryWindowCount = 0;
+
} // anonymous namespace
// ---------------------------------------------------------------------------
WXLRESULT wxWindowMSW::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
{
+ WXLRESULT rc;
if ( m_oldWndProc )
- return ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
+ rc = ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
else
- return ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam);
+ rc = ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam);
+
+ // Special hack used by wxTextEntry auto-completion only: this event is
+ // sent after the normal keyboard processing so that its handler could use
+ // the updated contents of the text control, after taking the key that was
+ // pressed into account.
+ if ( nMsg == WM_CHAR )
+ {
+ wxKeyEvent event(CreateCharEvent(wxEVT_AFTER_CHAR, wParam, lParam));
+ HandleWindowEvent(event);
+ }
+
+ return rc;
}
bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
}
break;
+ case WM_IME_STARTCOMPOSITION:
+ // IME popup needs Escape as it should undo the changes in its
+ // entry window instead of e.g. closing the dialog for which the
+ // IME is used (and losing all the changes in the IME window).
+ gs_modalEntryWindowCount++;
+ break;
+
+ case WM_IME_ENDCOMPOSITION:
+ gs_modalEntryWindowCount--;
+ break;
+
#if wxUSE_HOTKEY
case WM_HOTKEY:
processed = HandleHotKey((WORD)wParam, lParam);
}
WXHBRUSH
-wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC),
- wxWindowMSW * WXUNUSED(child))
+wxWindowMSW::MSWGetBgBrushForChild(WXHDC hDC, wxWindowMSW *child)
{
+ // Test for the custom background brush first.
+ WXHBRUSH hbrush = MSWGetCustomBgBrush();
+ if ( hbrush )
+ {
+ // We assume that this is either a stipple or hatched brush and not a
+ // solid one as otherwise it would have been enough to set the
+ // background colour and such brushes need to be positioned correctly
+ // in order to align when different windows are painted, so do it here.
+ RECT rc;
+ ::GetWindowRect(GetHwndOf(child), &rc);
+
+ ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1);
+
+ if ( !::SetBrushOrgEx((HDC)hDC, -rc.left, -rc.top, NULL) )
+ {
+ wxLogLastError(wxT("SetBrushOrgEx(bg brush)"));
+ }
+
+ return hbrush;
+ }
+
+ // Otherwise see if we have a custom background colour.
if ( m_hasBgCol )
{
wxBrush *
WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC)
{
+ // Use the special wxWindowBeingErased variable if it is set as the child
+ // being erased.
+ wxWindowMSW * const child =
+#if wxUSE_UXTHEME
+ wxWindowBeingErased ? wxWindowBeingErased :
+#endif
+ this;
+
for ( wxWindowMSW *win = this; win; win = win->GetParent() )
{
- WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, this);
+ WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, child);
if ( hBrush )
return hBrush;
return event;
}
-// isASCII is true only when we're called from WM_CHAR handler and not from
-// WM_KEYDOWN one
-bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam)
+wxKeyEvent
+wxWindowMSW::CreateCharEvent(wxEventType evType,
+ WXWPARAM wParam,
+ WXLPARAM lParam) const
{
- wxKeyEvent event(wxEVT_CHAR);
+ wxKeyEvent event(evType);
InitAnyKeyEvent(event, wParam, lParam);
#if wxUSE_UNICODE
event.m_altDown = false;
}
+ return event;
+}
+
+// isASCII is true only when we're called from WM_CHAR handler and not from
+// WM_KEYDOWN one
+bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam)
+{
+ wxKeyEvent event(CreateCharEvent(wxEVT_CHAR, wParam, lParam));
return HandleWindowEvent(event);
}
{
wchar_t uc;
int id = wxMSWKeyboard::VKToWX(wParam, lParam, &uc);
- if ( id != WXK_NONE
+
+ // Don't intercept keyboard entry (notably Escape) if a modal window
+ // (not managed by wx, e.g. IME one) is currently opened as more often
+ // than not it needs all the keys for itself.
+ //
+ // Also don't catch it if a window currently captures the mouse as
+ // Escape is normally used to release the mouse capture and if you
+ // really need to catch all the keys in the window that has mouse
+ // capture it can be easily done in its own EVT_CHAR handler as it is
+ // certain to have focus while it has the capture.
+ if ( !gs_modalEntryWindowCount && !::GetCapture() )
+ {
+ if ( id != WXK_NONE
#if wxUSE_UNICODE
- || static_cast<int>(uc) != WXK_NONE
+ || static_cast<int>(uc) != WXK_NONE
#endif // wxUSE_UNICODE
- )
- {
- const wxWindow * const win = wxGetActiveWindow();
+ )
+ {
+ const wxWindow * const win = wxGetActiveWindow();
- wxKeyEvent event(wxEVT_CHAR_HOOK);
- MSWInitAnyKeyEvent(event, wParam, lParam, win);
+ wxKeyEvent event(wxEVT_CHAR_HOOK);
+ MSWInitAnyKeyEvent(event, wParam, lParam, win);
- event.m_keyCode = id;
+ event.m_keyCode = id;
#if wxUSE_UNICODE
- event.m_uniChar = uc;
+ event.m_uniChar = uc;
#endif // wxUSE_UNICODE
- wxEvtHandler * const handler = win ? win->GetEventHandler()
- : wxTheApp;
+ wxEvtHandler * const handler = win ? win->GetEventHandler()
+ : wxTheApp;
- if ( handler && handler->ProcessEvent(event) )
- {
- // processed
- return 1;
+ if ( handler && handler->ProcessEvent(event) )
+ {
+ // processed
+ return 1;
+ }
}
}
}