#include "wx/ownerdrw.h"
#endif
+#include "wx/hashmap.h"
#include "wx/evtloop.h"
#include "wx/power.h"
#include "wx/sysopt.h"
#include "wx/notebook.h"
#include "wx/listctrl.h"
+#include "wx/dynlib.h"
#include <string.h>
#endif
#endif
-#if defined(TME_LEAVE) && defined(WM_MOUSELEAVE)
+#if defined(TME_LEAVE) && defined(WM_MOUSELEAVE) && wxUSE_DYNLIB_CLASS
#define HAVE_TRACKMOUSEEVENT
#endif // everything needed for TrackMouseEvent()
} 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 )
{
- 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)
// don't "overwrite" busy cursor
if ( m_cursor.Ok() && !wxIsBusy() )
{
- ::SetCursor(GetHcursorOf(m_cursor));
+ // normally we should change the cursor only if it's over this window
+ // but we should do it always if we capture the mouse currently
+ bool set = HasCapture();
+ if ( !set )
+ {
+ HWND hWnd = GetHwnd();
+
+ POINT point;
+#ifdef __WXWINCE__
+ ::GetCursorPosWinCE(&point);
+#else
+ ::GetCursorPos(&point);
+#endif
+
+ RECT rect = wxGetWindowRect(hWnd);
+
+ set = ::PtInRect(&rect, point) != 0;
+ }
+
+ if ( set )
+ {
+ ::SetCursor(GetHcursorOf(m_cursor));
+ }
+ //else: will be set later when the mouse enters this window
}
return true;
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
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
// drag and drop
// ---------------------------------------------------------------------------
+#if wxUSE_DRAG_AND_DROP || !defined(__WXWINCE__)
+
+#if wxUSE_STATBOX
+
// we need to lower the sibling static boxes so controls contained within can be
// a drop target
-static inline void AdjustStaticBoxZOrder(wxWindow *parent)
+static void AdjustStaticBoxZOrder(wxWindow *parent)
{
// no sibling static boxes if we have no parent (ie TLW)
if ( !parent )
}
}
+#else // !wxUSE_STATBOX
+
+static inline void AdjustStaticBoxZOrder(wxWindow * WXUNUSED(parent))
+{
+}
+
+#endif // wxUSE_STATBOX/!wxUSE_STATBOX
+
+#endif // drag and drop is used
+
#if wxUSE_DRAG_AND_DROP
void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget)
{
{
if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft )
{
- // In RTL mode, we want the logical left x-coordinate,
+ // In RTL mode, we want the logical left x-coordinate,
// which would be the physical right x-coordinate.
point.x = rect.right;
}
::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
switch ( msg->wParam )
{
case VK_TAB:
- if ( lDlgCode & DLGC_WANTTAB ) {
+ if ( (lDlgCode & DLGC_WANTTAB) && !bCtrlDown )
+ {
+ // let the control have the TAB
bProcess = false;
}
- else {
+ else // use it for navigation
+ {
// Ctrl-Tab cycles thru notebook pages
bWindowChange = bCtrlDown;
bForward = !bShiftDown;
// we treat PageUp/Dn as arrows because chances are that
// a control which needs arrows also needs them for
// navigation (e.g. wxTextCtrl, wxListCtrl, ...)
- if ( (lDlgCode & DLGC_WANTARROWS) || !bCtrlDown )
+ if ( (lDlgCode & DLGC_WANTARROWS) && !bCtrlDown )
bProcess = false;
- else
+ else // OTOH Ctrl-PageUp/Dn works as [Shift-]Ctrl-Tab
bWindowChange = true;
break;
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);
#ifdef HAVE_TRACKMOUSEEVENT
case WM_MOUSELEAVE:
- // filter out excess WM_MOUSELEAVE events sent after PopupMenu() (on XP at least)
+ // filter out excess WM_MOUSELEAVE events sent after PopupMenu()
+ // (on XP at least)
if ( m_mouseInWindow )
{
GenerateMouseLeave();
// problems, so don't do it for them (unnecessary anyhow)
if ( !win->IsOfStandardClass() )
{
- if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() )
+ if ( message == WM_LBUTTONDOWN && win->CanAcceptFocus() )
win->SetFocus();
}
}
#endif // defined(WM_DRAWITEM)
case WM_GETDLGCODE:
- if ( !IsOfStandardClass() )
+ if ( !IsOfStandardClass() || HasFlag(wxWANTS_CHARS) )
{
// we always want to get the char events
rc.result = DLGC_WANTCHARS;
- if ( GetWindowStyleFlag() & wxWANTS_CHARS )
+ if ( HasFlag(wxWANTS_CHARS) )
{
// in fact, we want everything
rc.result |= DLGC_WANTARROWS |
}
break;
#endif // __WXWINCE__
+
+ 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 )
(
extendedStyle,
className,
- title ? title : m_windowName.c_str(),
+ title ? title : (const wxChar*)m_windowName.c_str(),
style,
x, y, w, h,
(HWND)MSWGetParent(),
bool wxWindowMSW::IsDoubleBuffered() const
{
- const wxWindow* wnd = this;
-
- while ( wnd )
+ for ( const wxWindowMSW *wnd = this;
+ wnd && !wnd->IsTopLevel(); wnd =
+ wnd->GetParent() )
{
- if ( ::GetWindowLong((HWND)wnd->GetHWND(), GWL_EXSTYLE) & WS_EX_COMPOSITED )
+ if ( ::GetWindowLong(GetHwndOf(wnd), GWL_EXSTYLE) & WS_EX_COMPOSITED )
return true;
- wnd = wnd->GetParent();
}
return false;
m_mouseInWindow = true;
#ifdef HAVE_TRACKMOUSEEVENT
- WinStruct<TRACKMOUSEEVENT> trackinfo;
+ typedef BOOL (WINAPI *_TrackMouseEvent_t)(LPTRACKMOUSEEVENT);
+#ifdef __WXWINCE__
+ static const _TrackMouseEvent_t
+ s_pfn_TrackMouseEvent = _TrackMouseEvent;
+#else // !__WXWINCE__
+ static _TrackMouseEvent_t s_pfn_TrackMouseEvent;
+ static bool s_initDone = false;
+ if ( !s_initDone )
+ {
+ wxLogNull noLog;
+
+ wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
+ if ( dllComCtl32.IsLoaded() )
+ {
+ s_pfn_TrackMouseEvent = (_TrackMouseEvent_t)
+ dllComCtl32.GetSymbol(_T("_TrackMouseEvent"));
+ }
- trackinfo.dwFlags = TME_LEAVE;
- trackinfo.hwndTrack = GetHwnd();
+ s_initDone = true;
- // Use the commctrl.h _TrackMouseEvent(), which will call the real
- // TrackMouseEvent() if available or emulate it
- _TrackMouseEvent(&trackinfo);
+ // notice that it's ok to unload comctl32.dll here as it won't
+ // be really unloaded, being still in use because we link to it
+ // statically too
+ }
+
+ if ( s_pfn_TrackMouseEvent )
+#endif // __WXWINCE__/!__WXWINCE__
+ {
+ WinStruct<TRACKMOUSEEVENT> trackinfo;
+
+ trackinfo.dwFlags = TME_LEAVE;
+ trackinfo.hwndTrack = GetHwnd();
+
+ (*s_pfn_TrackMouseEvent)(&trackinfo);
+ }
#endif // HAVE_TRACKMOUSEEVENT
wxMouseEvent event(wxEVT_ENTER_WINDOW);
}
}
#ifdef HAVE_TRACKMOUSEEVENT
- else
+ else // mouse not in window
{
// Check if we need to send a LEAVE event
// Windows doesn't send WM_MOUSELEAVE if the mouse has been captured so
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
// ===========================================================================
return vk;
}
+#ifndef SM_SWAPBUTTON
+ #define SM_SWAPBUTTON 23
+#endif
+
// small helper for wxGetKeyState() and wxGetMouseState()
static inline bool wxIsKeyDown(WXWORD vk)
{
+ switch (vk)
+ {
+ case VK_LBUTTON:
+ if (GetSystemMetrics(SM_SWAPBUTTON)) vk = VK_RBUTTON;
+ break;
+ case VK_RBUTTON:
+ if (GetSystemMetrics(SM_SWAPBUTTON)) vk = VK_LBUTTON;
+ break;
+ }
// the low order bit indicates whether the key was pressed since the last
// call and the high order one indicates whether it is down right now and
// we only want that one
- return (::GetAsyncKeyState(vk) & (1<<15)) != 0;
+ return (GetAsyncKeyState(vk) & (1<<15)) != 0;
}
bool wxGetKeyState(wxKeyCode key)
// low order bit means LED is highlighted and high order one means the
// key is down; for compatibility with the other ports return true if
// either one is set
- return ::GetKeyState(vk) != 0;
+ return GetKeyState(vk) != 0;
}
else // normal key
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 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;