#include "wx/ownerdrw.h"
#endif
+#include "wx/hashmap.h"
#include "wx/evtloop.h"
#include "wx/power.h"
#include "wx/sysopt.h"
#endif
#endif
+#if wxUSE_UXTHEME
+ #include "wx/msw/uxtheme.h"
+ #define EP_EDITTEXT 1
+ #define ETS_NORMAL 1
+ #define ETS_HOT 2
+ #define ETS_SELECTED 3
+ #define ETS_DISABLED 4
+ #define ETS_FOCUSED 5
+ #define ETS_READONLY 6
+ #define ETS_ASSIST 7
+#endif
+
#if defined(TME_LEAVE) && defined(WM_MOUSELEAVE) && wxUSE_DYNLIB_CLASS
#define HAVE_TRACKMOUSEEVENT
#endif // everything needed for TrackMouseEvent()
#define wxUSE_MOUSEEVENT_HACK 1
#endif
+// not all compilers/platforms have X button related declarations (notably
+// Windows CE doesn't, and probably some old SDKs don't neither)
+#ifdef WM_XBUTTONDOWN
+ #define wxHAS_XBUTTON
+#endif
+
// ---------------------------------------------------------------------------
// global variables
// ---------------------------------------------------------------------------
} gs_lastMouseEvent;
#endif // wxUSE_MOUSEEVENT_HACK
+// hash containing the registered handlers for the custom messages
+WX_DECLARE_HASH_MAP(int, wxWindow::MSWMessageHandler,
+ wxIntegerHash, wxIntegerEqual,
+ MSWMessageHandlers);
+
+static MSWMessageHandlers gs_messageHandlers;
+
// ---------------------------------------------------------------------------
// private functions
// ---------------------------------------------------------------------------
m_mouseInWindow = false;
m_lastKeydownProcessed = false;
- m_childrenDisabled = NULL;
m_frozenness = 0;
m_hWnd = 0;
wxRemoveHandleAssociation(this);
}
- delete m_childrenDisabled;
-
}
// real construction (Init() must have been called before!)
return NULL;
}
-bool wxWindowMSW::Enable(bool enable)
+void wxWindowMSW::DoEnable( bool enable )
{
- // we shouldn't really enable the window if our parent is currently
- // disabled because under MSW this would indeed show the window in enabled
- // state but it still wouldn't respond to the input (as its parent is
- // disabled), so just update the internal m_childrenDisabled list in this
- // case and our state will be really changed when the parent is enabled
-
- // the logic above doesn't apply to top level windows, of course
- wxWindowMSW * const parent = IsTopLevel() ? NULL : GetParent();
- if ( parent && !parent->IsEnabled() && !IsEnabled() )
- {
- // it's a reference as we can create it below
- wxWindowList *& disabledSiblings = parent->m_childrenDisabled;
-
- bool rc = false;
- if ( enable )
- {
- // shouldn't be disabled when the parent is reenabled
- if ( disabledSiblings )
- {
- wxWindowList::compatibility_iterator
- i = disabledSiblings->Find(this);
- if ( i )
- {
- disabledSiblings->Erase(i);
- rc = true;
- }
- }
- //else: nothing to do
- }
- else // !enable
- {
- // should disable this window when the parent is enabled
- if ( !disabledSiblings )
- disabledSiblings = new wxWindowList;
-
- disabledSiblings->Append(this);
- }
-
- return rc;
- }
-
- if ( !wxWindowBase::Enable(enable) )
- return false;
-
HWND hWnd = GetHwnd();
if ( hWnd )
::EnableWindow(hWnd, (BOOL)enable);
-
- // the logic below doesn't apply to the top level windows -- otherwise
- // showing a modal dialog would result in total greying out (and ungreying
- // out later) of everything which would be really ugly
- if ( IsTopLevel() )
- return true;
-
- // when the parent is disabled, all of its children should be disabled as
- // well but when it is enabled back, only those of the children which
- // hadn't been already disabled in the beginning should be enabled again,
- // so we have to keep the list of those children
- for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
- node;
- node = node->GetNext() )
- {
- wxWindow *child = node->GetData();
- if ( child->IsTopLevel() )
- {
- // the logic below doesn't apply to top level children
- continue;
- }
-
- if ( enable )
- {
- // re-enable the child unless it had been disabled before us
- if ( !m_childrenDisabled || !m_childrenDisabled->Find(child) )
- child->Enable();
- }
- else // we're being disabled
- {
- if ( child->IsEnabled() )
- {
- // disable it as children shouldn't stay enabled while the
- // parent is not
- child->Disable();
- }
- else // child already disabled, remember it
- {
- // have we created the list of disabled children already?
- if ( !m_childrenDisabled )
- m_childrenDisabled = new wxWindowList;
-
- m_childrenDisabled->Append(child);
- }
- }
- }
-
- if ( enable && m_childrenDisabled )
- {
- // we don't need this list any more, don't keep unused memory
- delete m_childrenDisabled;
- m_childrenDisabled = NULL;
- }
-
- return true;
}
bool wxWindowMSW::Show(bool show)
return true;
}
+bool
+wxWindowMSW::MSWShowWithEffect(bool show,
+ wxShowEffect effect,
+ unsigned timeout,
+ wxDirection dir)
+{
+ typedef BOOL (WINAPI *AnimateWindow_t)(HWND, DWORD, DWORD);
+
+ static AnimateWindow_t s_pfnAnimateWindow = NULL;
+ static bool s_initDone = false;
+ if ( !s_initDone )
+ {
+ wxLogNull noLog;
+
+ wxDynamicLibrary dllUser32(_T("user32.dll"), wxDL_VERBATIM);
+ wxDL_INIT_FUNC(s_pfn, AnimateWindow, dllUser32);
+
+ s_initDone = true;
+
+ // notice that it's ok to unload user32.dll here as it won't be really
+ // unloaded, being still in use because we link to it statically too
+ }
+
+ if ( !s_pfnAnimateWindow )
+ return Show(show);
+
+ // prepare to use AnimateWindow()
+
+ if ( !timeout )
+ timeout = 200; // this is the default animation timeout, per MSDN
+
+ DWORD dwFlags = show ? 0 : AW_HIDE;
+ bool needsDir = false;
+ switch ( effect )
+ {
+ case wxSHOW_EFFECT_ROLL:
+ needsDir = true;
+ break;
+
+ case wxSHOW_EFFECT_SLIDE:
+ needsDir = true;
+ dwFlags |= AW_SLIDE;
+ break;
+
+ case wxSHOW_EFFECT_BLEND:
+ dwFlags |= AW_BLEND;
+ break;
+
+ case wxSHOW_EFFECT_EXPAND:
+ dwFlags |= AW_CENTER;
+ break;
+
+
+ case wxSHOW_EFFECT_MAX:
+ wxFAIL_MSG( _T("invalid window show effect") );
+ return false;
+
+ default:
+ wxFAIL_MSG( _T("unknown window show effect") );
+ return false;
+ }
+
+ if ( needsDir )
+ {
+ switch ( dir )
+ {
+ case wxTOP:
+ dwFlags |= AW_VER_NEGATIVE;
+ break;
+
+ case wxBOTTOM:
+ dwFlags |= AW_VER_POSITIVE;
+ break;
+
+ case wxLEFT:
+ dwFlags |= AW_HOR_NEGATIVE;
+ break;
+
+ case wxRIGHT:
+ dwFlags |= AW_HOR_POSITIVE;
+ break;
+
+ default:
+ wxFAIL_MSG( _T("unknown window effect direction") );
+ return false;
+ }
+ }
+ else // animation effect which doesn't need the direction
+ {
+ wxASSERT_MSG( dir == wxBOTTOM,
+ _T("non-default direction used unnecessarily") );
+ }
+
+
+ if ( !(*s_pfnAnimateWindow)(GetHwnd(), timeout, dwFlags) )
+ {
+ wxLogLastError(_T("AnimateWindow"));
+
+ return false;
+ }
+
+ return true;
+}
+
// Raise the window to the top of the Z order
void wxWindowMSW::Raise()
{
RECT *pr;
if ( prect )
{
- rect.left = prect->x;
- rect.top = prect->y;
- rect.right = prect->x + prect->width;
- rect.bottom = prect->y + prect->height;
+ wxCopyRectToRECT(*prect, rect);
pr = ▭
}
else
}
}
+wxBorder wxWindowMSW::GetDefaultBorderForControl() const
+{
+ return wxBORDER_THEME;
+}
+
+wxBorder wxWindowMSW::GetDefaultBorder() const
+{
+ return wxWindowBase::GetDefaultBorder();
+}
+
+// Translate wxBORDER_THEME (and other border styles if necessary to the value
+// that makes most sense for this Windows environment
+wxBorder wxWindowMSW::TranslateBorder(wxBorder border) const
+{
+#if defined(__POCKETPC__) || defined(__SMARTPHONE__)
+ if (border == wxBORDER_THEME || border == wxBORDER_SUNKEN || border == wxBORDER_SIMPLE)
+ return wxBORDER_SIMPLE;
+ else
+ return wxBORDER_NONE;
+#else
+#if wxUSE_UXTHEME
+ if (border == wxBORDER_THEME)
+ {
+ if (CanApplyThemeBorder())
+ {
+ wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
+ if (theme)
+ return wxBORDER_THEME;
+ }
+ }
+#endif
+ return border;
+#endif
+}
+
+
WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
{
// translate common wxWidgets styles to Windows ones
if ( flags & wxHSCROLL )
style |= WS_HSCROLL;
- const wxBorder border = GetBorder(flags);
+ const wxBorder border = TranslateBorder(GetBorder(flags));
+
+ // After translation, border is now optimized for the specific version of Windows
+ // and theme engine presence.
// WS_BORDER is only required for wxBORDER_SIMPLE
if ( border == wxBORDER_SIMPLE )
case wxBORDER_NONE:
case wxBORDER_SIMPLE:
+ case wxBORDER_THEME:
break;
case wxBORDER_STATIC:
style &= ~WS_BORDER;
break;
- case wxBORDER_DOUBLE:
- *exstyle |= WS_EX_DLGMODALFRAME;
- break;
+// case wxBORDER_DOUBLE:
+// *exstyle |= WS_EX_DLGMODALFRAME;
+// break;
}
// wxUniv doesn't use Windows dialog navigation functions at all
}
#endif // !HAVE_TRACKMOUSEEVENT
- if (wxUpdateUIEvent::CanUpdate(this))
+ if (wxUpdateUIEvent::CanUpdate(this) && IsShown())
UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
}
const RECT *pRect;
if ( rect )
{
- mswRect.left = rect->x;
- mswRect.top = rect->y;
- mswRect.right = rect->x + rect->width;
- mswRect.bottom = rect->y + rect->height;
-
+ wxCopyRectToRECT(*rect, mswRect);
pRect = &mswRect;
}
else
SIZE sizeRect;
TEXTMETRIC tm;
- ::GetTextExtentPoint32(hdc, string, string.length(), &sizeRect);
+ ::GetTextExtentPoint32(hdc, string.wx_str(), string.length(), &sizeRect);
GetTextMetrics(hdc, &tm);
if ( x )
::ClientToScreen(hWnd, &point);
wxCurrentPopupMenu = menu;
#if defined(__WXWINCE__)
- UINT flags = 0;
-#else
- UINT flags = TPM_RIGHTBUTTON | TPM_RECURSE;
-#endif
+ static const UINT flags = 0;
+#else // !__WXWINCE__
+ UINT flags = TPM_RIGHTBUTTON;
+ // NT4 doesn't support TPM_RECURSE and simply doesn't show the menu at all
+ // when it's use, I'm not sure about Win95/98 but prefer to err on the safe
+ // side and not to use it there neither -- modify the test if it does work
+ // on these systems
+ if ( wxGetWinVersion() >= wxWinVersion_5 )
+ {
+ // using TPM_RECURSE allows us to show a popup menu while another menu
+ // is opened which can be useful and is supported by the other
+ // platforms, so allow it under Windows too
+ flags |= TPM_RECURSE;
+ }
+#endif // __WXWINCE__/!__WXWINCE__
+
::TrackPopupMenu(hMenu, flags, point.x, point.y, 0, hWnd, NULL);
// we need to do it right now as otherwise the events are never going to be
case VK_RETURN:
{
- if ( (lDlgCode & DLGC_WANTMESSAGE) && !bCtrlDown )
- {
- // control wants to process Enter itself, don't
- // call IsDialogMessage() which would consume it
- return false;
- }
-
#if wxUSE_BUTTON
// currently active button should get enter press even
// if there is a default button elsewhere so check if
}
else // not a button itself, do we have default button?
{
- wxTopLevelWindow *
- tlw = wxDynamicCast(wxGetTopLevelParent(this),
- wxTopLevelWindow);
+ // check if this window or any of its ancestors
+ // wants the message for itself (we always reserve
+ // Ctrl-Enter for dialog navigation though)
+ wxWindow *win = this;
+ if ( !bCtrlDown )
+ {
+ // this will contain the dialog code of this
+ // window and all of its parent windows in turn
+ LONG lDlgCode2 = lDlgCode;
+
+ while ( win )
+ {
+ if ( lDlgCode2 & DLGC_WANTMESSAGE )
+ {
+ // as it wants to process Enter itself,
+ // don't call IsDialogMessage() which
+ // would consume it
+ return false;
+ }
+
+ // don't propagate keyboard messages beyond
+ // the first top level window parent
+ if ( win->IsTopLevel() )
+ break;
+
+ win = win->GetParent();
+
+ lDlgCode2 = ::SendMessage
+ (
+ GetHwndOf(win),
+ WM_GETDLGCODE,
+ 0,
+ 0
+ );
+ }
+ }
+ else // bCtrlDown
+ {
+ win = wxGetTopLevelParent(win);
+ }
+
+ wxTopLevelWindow * const
+ tlw = wxDynamicCast(win, wxTopLevelWindow);
if ( tlw )
{
btn = wxDynamicCast(tlw->GetDefaultItem(),
node = node->GetNext() )
{
wxWindow * const win = node->GetData();
- if ( win->AcceptsFocus() &&
+ if ( win->CanAcceptFocus() &&
!(::GetWindowLong(GetHwndOf(win), GWL_EXSTYLE) &
WS_EX_CONTROLPARENT) )
{
LRESULT rc;
- if ( wnd && wxEventLoop::AllowProcessing(wnd) )
+ if ( wnd && wxGUIEventLoop::AllowProcessing(wnd) )
rc = wnd->MSWWindowProc(message, wParam, lParam);
else
rc = ::DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
+#if 0
+ case WM_ENTERSIZEMOVE:
+ {
+ processed = HandleEnterSizeMove();
+ }
+ break;
+ case WM_EXITSIZEMOVE:
+ {
+ processed = HandleExitSizeMove();
+ }
+ break;
+#endif
case WM_SIZING:
{
LPRECT pRect = (LPRECT)lParam;
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_MBUTTONDBLCLK:
+#ifdef wxHAS_XBUTTON
+ case WM_XBUTTONDOWN:
+ case WM_XBUTTONUP:
+ case WM_XBUTTONDBLCLK:
+#endif // wxHAS_XBUTTON
{
#ifdef __WXMICROWIN__
// MicroWindows seems to ignore the fact that a window is
// problems, so don't do it for them (unnecessary anyhow)
if ( !win->IsOfStandardClass() )
{
- if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() )
+ if ( message == WM_LBUTTONDOWN && win->IsFocusable() )
win->SetFocus();
}
}
break;
#endif
+#if wxUSE_MENUS
case WM_MENUCHAR:
// we're only interested in our own menus, not MF_SYSMENU
if ( HIWORD(wParam) == MF_POPUP )
}
}
break;
+#endif // wxUSE_MENUS
#ifndef __WXWINCE__
case WM_POWERBROADCAST:
}
break;
#endif // __WXWINCE__
+
+#if wxUSE_UXTHEME
+ // If we want the default themed border then we need to draw it ourselves
+ case WM_NCCALCSIZE:
+ {
+ wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
+ const wxBorder border = TranslateBorder(GetBorder());
+ if (theme && border == wxBORDER_THEME)
+ {
+ // first ask the widget to calculate the border size
+ rc.result = MSWDefWindowProc(message, wParam, lParam);
+ processed = true;
+
+ // now alter the client size making room for drawing a themed border
+ NCCALCSIZE_PARAMS *csparam = NULL;
+ RECT rect;
+ if (wParam)
+ {
+ csparam = (NCCALCSIZE_PARAMS*)lParam;
+ rect = csparam->rgrc[0];
+ }
+ else
+ {
+ rect = *((RECT*)lParam);
+ }
+ wxUxThemeHandle hTheme((wxWindow *)this, L"EDIT");
+ RECT rcClient = { 0, 0, 0, 0 };
+ wxClientDC dc((wxWindow *)this);
+
+ if (theme->GetThemeBackgroundContentRect(
+ hTheme, GetHdcOf(dc), EP_EDITTEXT, ETS_NORMAL,
+ &rect, &rcClient) == S_OK)
+ {
+ InflateRect(&rcClient, -1, -1);
+ if (wParam)
+ csparam->rgrc[0] = rcClient;
+ else
+ *((RECT*)lParam) = rcClient;
+ rc.result = WVR_REDRAW;
+ }
+ }
+ }
+ break;
+
+ case WM_NCPAINT:
+ {
+ wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
+ const wxBorder border = TranslateBorder(GetBorder());
+ if (theme && border == wxBORDER_THEME)
+ {
+ // first ask the widget to paint its non-client area, such as scrollbars, etc.
+ rc.result = MSWDefWindowProc(message, wParam, lParam);
+ processed = true;
+
+ wxUxThemeHandle hTheme((wxWindow *)this, L"EDIT");
+ wxWindowDC dc((wxWindow *)this);
+
+ // Clip the DC so that you only draw on the non-client area
+ RECT rcBorder;
+ wxCopyRectToRECT(GetSize(), rcBorder);
+
+ RECT rcClient;
+ theme->GetThemeBackgroundContentRect(
+ hTheme, GetHdcOf(dc), EP_EDITTEXT, ETS_NORMAL, &rcBorder, &rcClient);
+ InflateRect(&rcClient, -1, -1);
+
+ ::ExcludeClipRect(GetHdcOf(dc), rcClient.left, rcClient.top,
+ rcClient.right, rcClient.bottom);
+
+ // Make sure the background is in a proper state
+ if (theme->IsThemeBackgroundPartiallyTransparent(hTheme, EP_EDITTEXT, ETS_NORMAL))
+ {
+ theme->DrawThemeParentBackground(GetHwnd(), GetHdcOf(dc), &rcBorder);
+ }
+
+ // Draw the border
+ int nState;
+ if ( !IsEnabled() )
+ nState = ETS_DISABLED;
+ // should we check this?
+ //else if ( ::GetWindowLong(GetHwnd(), GWL_STYLE) & ES_READONLY)
+ // nState = ETS_READONLY;
+ else
+ nState = ETS_NORMAL;
+ theme->DrawThemeBackground(hTheme, GetHdcOf(dc), EP_EDITTEXT, nState, &rcBorder, NULL);
+ }
+ }
+ break;
+
+#endif // wxUSE_UXTHEME
+
+ default:
+ // try a custom message handler
+ const MSWMessageHandlers::const_iterator
+ i = gs_messageHandlers.find(message);
+ if ( i != gs_messageHandlers.end() )
+ {
+ processed = (*i->second)(this, message, wParam, lParam);
+ }
}
if ( !processed )
m_hWnd = (WXHWND)::CreateWindowEx
(
extendedStyle,
- className,
- title ? title : m_windowName.c_str(),
+ className.wx_str(),
+ title ? title : m_windowName.wx_str(),
style,
x, y, w, h,
(HWND)MSWGetParent(),
(
CP_ACP,
0, // no flags
- ttip,
+ ttip.wx_str(),
tipLength,
buf,
WXSIZEOF(buf) - 1
{
#ifndef __WXMICROWIN__
// the logic is as follows:
- // -1. don't set cursor for non client area, including but not limited to
- // the title bar, scrollbars, &c
- // 0. allow the user to override default behaviour by using EVT_SET_CURSOR
- // 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
+ // 0. if we're busy, set the busy cursor (even for non client elements)
+ // 1. don't set custom cursor for non client area of enabled windows
+ // 2. ask user EVT_SET_CURSOR handler for the cursor
+ // 3. if still no cursor but we're in a TLW, set the global cursor
- if ( nHitTest != HTCLIENT )
+ HCURSOR hcursor = 0;
+ if ( wxIsBusy() )
{
- return false;
+ hcursor = wxGetCurrentBusyCursor();
}
+ else // not busy
+ {
+ if ( nHitTest != HTCLIENT )
+ return false;
- HCURSOR hcursor = 0;
-
- // first ask the user code - it may wish to set the cursor in some very
- // specific way (for example, depending on the current position)
- POINT pt;
+ // first ask the user code - it may wish to set the cursor in some very
+ // specific way (for example, depending on the current position)
+ POINT pt;
#ifdef __WXWINCE__
- if ( !::GetCursorPosWinCE(&pt))
+ if ( !::GetCursorPosWinCE(&pt))
#else
- if ( !::GetCursorPos(&pt) )
+ if ( !::GetCursorPos(&pt) )
#endif
- {
- wxLogLastError(wxT("GetCursorPos"));
- }
-
- int x = pt.x,
- y = pt.y;
- ScreenToClient(&x, &y);
- wxSetCursorEvent event(x, y);
-
- bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event);
- if ( processedEvtSetCursor && event.HasCursor() )
- {
- hcursor = GetHcursorOf(event.GetCursor());
- }
+ {
+ wxLogLastError(wxT("GetCursorPos"));
+ }
- if ( !hcursor )
- {
- bool isBusy = wxIsBusy();
+ int x = pt.x,
+ y = pt.y;
+ ScreenToClient(&x, &y);
+ wxSetCursorEvent event(x, y);
- // the test for processedEvtSetCursor is here to prevent using m_cursor
- // if the user code caught EVT_SET_CURSOR() and returned nothing from
- // it - this is a way to say that our cursor shouldn't be used for this
- // point
- if ( !processedEvtSetCursor && m_cursor.Ok() )
+ bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event);
+ if ( processedEvtSetCursor && event.HasCursor() )
{
- hcursor = GetHcursorOf(m_cursor);
+ hcursor = GetHcursorOf(event.GetCursor());
}
- if ( !GetParent() )
+ if ( !hcursor )
{
- if ( isBusy )
+ // the test for processedEvtSetCursor is here to prevent using
+ // m_cursor if the user code caught EVT_SET_CURSOR() and returned
+ // nothing from it - this is a way to say that our cursor shouldn't
+ // be used for this point
+ if ( !processedEvtSetCursor && m_cursor.Ok() )
{
- hcursor = wxGetCurrentBusyCursor();
+ hcursor = GetHcursorOf(m_cursor);
}
- else if ( !hcursor )
+
+ if ( !hcursor && !GetParent() )
{
const wxCursor *cursor = wxGetGlobalCursor();
if ( cursor && cursor->Ok() )
}
}
+
if ( hcursor )
{
-// wxLogDebug("HandleSetCursor: Setting cursor %ld", (long) hcursor);
-
::SetCursor(hcursor);
// cursor set, stop here
eventNc.SetEventObject(this);
GetEventHandler()->ProcessEvent(eventNc);
+ // don't keep an HRGN we don't need any longer (GetUpdateRegion() can only
+ // be called from inside the event handlers called above)
+ m_updateRegion.Clear();
+
return processed;
}
return rc;
}
+bool wxWindowMSW::HandleEnterSizeMove()
+{
+ wxMoveEvent event(wxPoint(0,0), m_windowId);
+ event.SetEventType(wxEVT_MOVE_START);
+ event.SetEventObject(this);
+
+ return GetEventHandler()->ProcessEvent(event);
+}
+
+bool wxWindowMSW::HandleExitSizeMove()
+{
+ wxMoveEvent event(wxPoint(0,0), m_windowId);
+ event.SetEventType(wxEVT_MOVE_END);
+ event.SetEventObject(this);
+
+ return GetEventHandler()->ProcessEvent(event);
+}
+
bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
{
#if USE_DEFERRED_SIZING
// command messages
// ---------------------------------------------------------------------------
-bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
+bool wxWindowMSW::HandleCommand(WXWORD id_, WXWORD cmd, WXHWND control)
{
+ // sign extend to int from short before comparing with the other int ids
+ int id = (signed short)id_;
+
#if wxUSE_MENUS_NATIVE
if ( !cmd && wxCurrentPopupMenu )
{
// try the id
if ( !win )
{
- // must cast to a signed type before comparing with other ids!
- win = FindItem((signed short)id);
+ win = FindItem(id);
}
if ( win )
event.m_leftDown = (flags & MK_LBUTTON) != 0;
event.m_middleDown = (flags & MK_MBUTTON) != 0;
event.m_rightDown = (flags & MK_RBUTTON) != 0;
- event.m_altDown = ::GetKeyState(VK_MENU) < 0;
+#ifdef wxHAS_XBUTTON
+ event.m_aux1Down = (flags & MK_XBUTTON1) != 0;
+ event.m_aux2Down = (flags & MK_XBUTTON2) != 0;
+#endif // wxHAS_XBUTTON
+ event.m_altDown = ::wxIsAltDown();
#ifndef __WXWINCE__
event.SetTimestamp(::GetMessageTime());
wxEVT_RIGHT_DCLICK,
wxEVT_MIDDLE_DOWN,
wxEVT_MIDDLE_UP,
- wxEVT_MIDDLE_DCLICK
+ wxEVT_MIDDLE_DCLICK,
+ 0, // this one is for wxEVT_MOTION which is not used here
+ wxEVT_AUX1_DOWN,
+ wxEVT_AUX1_UP,
+ wxEVT_AUX1_DCLICK,
+ wxEVT_AUX2_DOWN,
+ wxEVT_AUX2_UP,
+ wxEVT_AUX2_DCLICK
};
+#ifdef wxHAS_XBUTTON
+ // the same messages are used for both auxillary mouse buttons so we need
+ // to adjust the index manually
+ switch ( msg )
+ {
+ case WM_XBUTTONDOWN:
+ case WM_XBUTTONUP:
+ case WM_XBUTTONDBLCLK:
+ if ( flags & MK_XBUTTON2 )
+ msg += wxEVT_AUX2_DOWN - wxEVT_AUX1_DOWN;
+ }
+#endif // wxHAS_XBUTTON
+
wxMouseEvent event(eventsMouse[msg - WM_MOUSEMOVE]);
InitMouseEvent(event, x, y, flags);
return GetEventHandler()->ProcessEvent(event);
}
+#if wxUSE_MENUS
int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
WXLPARAM WXUNUSED_IN_WINCE(lParam))
{
// menu creation code
wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
- const wxChar *p = wxStrchr(item->GetText(), _T('&'));
+ const wxChar *p = wxStrchr(item->GetItemLabel().wx_str(), _T('&'));
while ( p++ )
{
if ( *p == _T('&') )
return GetEventHandler()->ProcessEvent(evt);
}
+#endif // wxUSE_MENUS
// ---------------------------------------------------------------------------
// joystick
return GetEventHandler()->ProcessEvent(event);
}
+// ----------------------------------------------------------------------------
+// custom message handlers
+// ----------------------------------------------------------------------------
+
+/* static */ bool
+wxWindowMSW::MSWRegisterMessageHandler(int msg, MSWMessageHandler handler)
+{
+ wxCHECK_MSG( gs_messageHandlers.find(msg) == gs_messageHandlers.end(),
+ false, _T("registering handler for the same message twice") );
+
+ gs_messageHandlers[msg] = handler;
+ return true;
+}
+
+/* static */ void
+wxWindowMSW::MSWUnregisterMessageHandler(int msg, MSWMessageHandler handler)
+{
+ const MSWMessageHandlers::iterator i = gs_messageHandlers.find(msg);
+ wxCHECK_RET( i != gs_messageHandlers.end() && i->second == handler,
+ _T("unregistering non-registered handler?") );
+
+ gs_messageHandlers.erase(i);
+}
+
// ===========================================================================
// global functions
// ===========================================================================
ms.SetLeftDown(wxIsKeyDown(VK_LBUTTON));
ms.SetMiddleDown(wxIsKeyDown(VK_MBUTTON));
ms.SetRightDown(wxIsKeyDown(VK_RBUTTON));
-
- ms.SetControlDown(wxIsKeyDown(VK_CONTROL));
- ms.SetShiftDown(wxIsKeyDown(VK_SHIFT));
- ms.SetAltDown(wxIsKeyDown(VK_MENU));
+#ifdef wxHAS_XBUTTON
+ ms.SetAux1Down(wxIsKeyDown(VK_XBUTTON1));
+ ms.SetAux2Down(wxIsKeyDown(VK_XBUTTON2));
+#endif // wxHAS_XBUTTON
+
+ ms.SetControlDown(wxIsCtrlDown ());
+ ms.SetShiftDown (wxIsShiftDown());
+ ms.SetAltDown (wxIsAltDown ());
// ms.SetMetaDown();
return ms;
case 0x00A7: return wxT("WM_NCMBUTTONDOWN");
case 0x00A8: return wxT("WM_NCMBUTTONUP");
case 0x00A9: return wxT("WM_NCMBUTTONDBLCLK");
+
+ case 0x00B0: return wxT("EM_GETSEL");
+ case 0x00B1: return wxT("EM_SETSEL");
+ case 0x00B2: return wxT("EM_GETRECT");
+ case 0x00B3: return wxT("EM_SETRECT");
+ case 0x00B4: return wxT("EM_SETRECTNP");
+ case 0x00B5: return wxT("EM_SCROLL");
+ case 0x00B6: return wxT("EM_LINESCROLL");
+ case 0x00B7: return wxT("EM_SCROLLCARET");
+ case 0x00B8: return wxT("EM_GETMODIFY");
+ case 0x00B9: return wxT("EM_SETMODIFY");
+ case 0x00BA: return wxT("EM_GETLINECOUNT");
+ case 0x00BB: return wxT("EM_LINEINDEX");
+ case 0x00BC: return wxT("EM_SETHANDLE");
+ case 0x00BD: return wxT("EM_GETHANDLE");
+ case 0x00BE: return wxT("EM_GETTHUMB");
+ case 0x00C1: return wxT("EM_LINELENGTH");
+ case 0x00C2: return wxT("EM_REPLACESEL");
+ case 0x00C4: return wxT("EM_GETLINE");
+ case 0x00C5: return wxT("EM_LIMITTEXT/EM_SETLIMITTEXT"); /* ;win40 Name change */
+ case 0x00C6: return wxT("EM_CANUNDO");
+ case 0x00C7: return wxT("EM_UNDO");
+ case 0x00C8: return wxT("EM_FMTLINES");
+ case 0x00C9: return wxT("EM_LINEFROMCHAR");
+ case 0x00CB: return wxT("EM_SETTABSTOPS");
+ case 0x00CC: return wxT("EM_SETPASSWORDCHAR");
+ case 0x00CD: return wxT("EM_EMPTYUNDOBUFFER");
+ case 0x00CE: return wxT("EM_GETFIRSTVISIBLELINE");
+ case 0x00CF: return wxT("EM_SETREADONLY");
+ case 0x00D0: return wxT("EM_SETWORDBREAKPROC");
+ case 0x00D1: return wxT("EM_GETWORDBREAKPROC");
+ case 0x00D2: return wxT("EM_GETPASSWORDCHAR");
+ case 0x00D3: return wxT("EM_SETMARGINS");
+ case 0x00D4: return wxT("EM_GETMARGINS");
+ case 0x00D5: return wxT("EM_GETLIMITTEXT");
+ case 0x00D6: return wxT("EM_POSFROMCHAR");
+ case 0x00D7: return wxT("EM_CHARFROMPOS");
+ case 0x00D8: return wxT("EM_SETIMESTATUS");
+ case 0x00D9: return wxT("EM_GETIMESTATUS");
+
case 0x0100: return wxT("WM_KEYDOWN");
case 0x0101: return wxT("WM_KEYUP");
case 0x0102: return wxT("WM_CHAR");
case 0x011F: return wxT("WM_MENUSELECT");
case 0x0120: return wxT("WM_MENUCHAR");
case 0x0121: return wxT("WM_ENTERIDLE");
+
+ case 0x0132: return wxT("WM_CTLCOLORMSGBOX");
+ case 0x0133: return wxT("WM_CTLCOLOREDIT");
+ case 0x0134: return wxT("WM_CTLCOLORLISTBOX");
+ case 0x0135: return wxT("WM_CTLCOLORBTN");
+ case 0x0136: return wxT("WM_CTLCOLORDLG");
+ case 0x0137: return wxT("WM_CTLCOLORSCROLLBAR");
+ case 0x0138: return wxT("WM_CTLCOLORSTATIC");
+ case 0x01E1: return wxT("MN_GETHMENU");
+
case 0x0200: return wxT("WM_MOUSEMOVE");
case 0x0201: return wxT("WM_LBUTTONDOWN");
case 0x0202: return wxT("WM_LBUTTONUP");
case 0x0208: return wxT("WM_MBUTTONUP");
case 0x0209: return wxT("WM_MBUTTONDBLCLK");
case 0x020A: return wxT("WM_MOUSEWHEEL");
+ case 0x020B: return wxT("WM_XBUTTONDOWN");
+ case 0x020C: return wxT("WM_XBUTTONUP");
+ case 0x020D: return wxT("WM_XBUTTONDBLCLK");
case 0x0210: return wxT("WM_PARENTNOTIFY");
case 0x0211: return wxT("WM_ENTERMENULOOP");
case 0x0212: return wxT("WM_EXITMENULOOP");
case 0x0290: return wxT("WM_IME_KEYDOWN");
case 0x0291: return wxT("WM_IME_KEYUP");
+ case 0x02A0: return wxT("WM_NCMOUSEHOVER");
+ case 0x02A1: return wxT("WM_MOUSEHOVER");
+ case 0x02A2: return wxT("WM_NCMOUSELEAVE");
+ case 0x02A3: return wxT("WM_MOUSELEAVE");
+
case 0x0300: return wxT("WM_CUT");
case 0x0301: return wxT("WM_COPY");
case 0x0302: return wxT("WM_PASTE");
case 0x030F: return wxT("WM_QUERYNEWPALETTE");
case 0x0310: return wxT("WM_PALETTEISCHANGING");
case 0x0311: return wxT("WM_PALETTECHANGED");
-#if wxUSE_HOTKEY
case 0x0312: return wxT("WM_HOTKEY");
-#endif
+
+ case 0x0317: return wxT("WM_PRINT");
+ case 0x0318: return wxT("WM_PRINTCLIENT");
// common controls messages - although they're not strictly speaking
// standard, it's nice to decode them nevertheless
}
return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam);
- };
+ }
private:
static HHOOK ms_hMsgHookProc;