X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/839b865d081f1410a8508b22f11a4f028d14daf9..f5766910b6731eb03e82371416e9778203396ce7:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 750f5c7c53..89faa57b7f 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -1,17 +1,21 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: windows.cpp -// Purpose: wxWindow +// Name: src/msw/window.cpp +// Purpose: wxWindowMSW // Author: Julian Smart -// Modified by: +// Modified by: VZ on 13.05.99: no more Default(), MSWOnXXX() reorganisation // Created: 04/01/98 // RCS-ID: $Id$ -// Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows license +// Copyright: (c) Julian Smart +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "window.h" -#endif +// =========================================================================== +// declarations +// =========================================================================== + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -20,48 +24,80 @@ #pragma hdrstop #endif +#include "wx/window.h" + #ifndef WX_PRECOMP - #include "wx/setup.h" + #include "wx/msw/wrapwin.h" + #include "wx/msw/wrapcctl.h" // include "properly" + #include "wx/msw/missing.h" + #include "wx/accel.h" #include "wx/menu.h" #include "wx/dc.h" #include "wx/dcclient.h" + #include "wx/dcmemory.h" #include "wx/utils.h" #include "wx/app.h" - #include "wx/panel.h" #include "wx/layout.h" #include "wx/dialog.h" #include "wx/frame.h" #include "wx/listbox.h" #include "wx/button.h" - #include "wx/settings.h" #include "wx/msgdlg.h" - - #include + #include "wx/settings.h" + #include "wx/statbox.h" + #include "wx/sizer.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/textctrl.h" + #include "wx/menuitem.h" + #include "wx/module.h" #endif -#if wxUSE_OWNER_DRAWN +#if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__) #include "wx/ownerdrw.h" #endif -#if wxUSE_DRAG_AND_DROP - #include "wx/msw/ole/droptgt.h" +#include "wx/evtloop.h" +#include "wx/power.h" +#include "wx/sysopt.h" + +#if wxUSE_DRAG_AND_DROP + #include "wx/dnd.h" +#endif + +#if wxUSE_ACCESSIBILITY + #include "wx/access.h" + #include + #include + #ifndef WM_GETOBJECT + #define WM_GETOBJECT 0x003D + #endif + #ifndef OBJID_CLIENT + #define OBJID_CLIENT 0xFFFFFFFC + #endif #endif -#include "wx/menuitem.h" -#include "wx/log.h" +#include "wx/msw/private.h" #if wxUSE_TOOLTIPS -#include "wx/tooltip.h" + #include "wx/tooltip.h" #endif -#include "wx/intl.h" -#include "wx/log.h" +#if wxUSE_CARET + #include "wx/caret.h" +#endif // wxUSE_CARET -#include "wx/msw/private.h" +#if wxUSE_SPINCTRL + #include "wx/spinctrl.h" +#endif // wxUSE_SPINCTRL + +#include "wx/notebook.h" +#include "wx/listctrl.h" +#include "wx/dynlib.h" #include -#ifndef __GNUWIN32__ +#if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__) /* && !defined(__WXWINCE__) */ ) || defined(__CYGWIN10__) #include #include #endif @@ -70,5028 +106,6497 @@ #include #endif -#if (defined(__WIN95__) && !defined(__GNUWIN32__)) || defined(__TWIN32__) -#include +#if !defined __WXWINCE__ && !defined NEED_PBT_H + #include #endif -#ifndef __TWIN32__ - #ifdef __GNUWIN32__ - #include - #endif +#if defined(__WXWINCE__) + #include "wx/msw/wince/missing.h" +#ifdef __POCKETPC__ + #include + #include + #include + #include #endif - -// all these are defined in -#ifdef GetCharWidth -#undef GetCharWidth #endif -#ifdef FindWindow -#undef FindWindow +#if defined(TME_LEAVE) && defined(WM_MOUSELEAVE) && wxUSE_DYNLIB_CLASS + #define HAVE_TRACKMOUSEEVENT +#endif // everything needed for TrackMouseEvent() + +// if this is set to 1, we use deferred window sizing to reduce flicker when +// resizing complicated window hierarchies, but this can in theory result in +// different behaviour than the old code so we keep the possibility to use it +// by setting this to 0 (in the future this should be removed completely) +#ifdef __WXWINCE__ +#define USE_DEFERRED_SIZING 0 +#else +#define USE_DEFERRED_SIZING 1 #endif -#ifdef GetClassName -#undef GetClassName +// set this to 1 to filter out duplicate mouse events, e.g. mouse move events +// when mouse position didnd't change +#ifdef __WXWINCE__ + #define wxUSE_MOUSEEVENT_HACK 0 +#else + #define wxUSE_MOUSEEVENT_HACK 1 #endif -#ifdef GetClassInfo -#undef GetClassInfo +// --------------------------------------------------------------------------- +// global variables +// --------------------------------------------------------------------------- + +#if wxUSE_MENUS_NATIVE +wxMenu *wxCurrentPopupMenu = NULL; +#endif // wxUSE_MENUS_NATIVE + +#ifdef __WXWINCE__ +extern wxChar *wxCanvasClassName; +#else +extern const wxChar *wxCanvasClassName; #endif -#ifdef __WXDEBUG__ - const char *wxGetMessageName(int message); -#endif //__WXDEBUG__ +// true if we had already created the std colour map, used by +// wxGetStdColourMap() and wxWindow::OnSysColourChanged() (FIXME-MT) +static bool gs_hasStdCmap = false; + +// last mouse event information we need to filter out the duplicates +#if wxUSE_MOUSEEVENT_HACK +static struct MouseEventInfoDummy +{ + // mouse position (in screen coordinates) + wxPoint pos; -#define WINDOW_MARGIN 3 // This defines sensitivity of Leave events + // last mouse event type + wxEventType type; +} gs_lastMouseEvent; +#endif // wxUSE_MOUSEEVENT_HACK + +// --------------------------------------------------------------------------- +// private functions +// --------------------------------------------------------------------------- + +// the window proc for all our windows +LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam); -wxMenu *wxCurrentPopupMenu = NULL; -extern wxList WXDLLEXPORT wxPendingDelete; -void wxRemoveHandleAssociation(wxWindow *win); -void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win); +#ifdef __WXDEBUG__ + const wxChar *wxGetMessageName(int message); +#endif //__WXDEBUG__ + +void wxRemoveHandleAssociation(wxWindowMSW *win); +extern void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win); wxWindow *wxFindWinFromHandle(WXHWND hWnd); -#if !USE_SHARED_LIBRARY - IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxEvtHandler) -#endif +// get the text metrics for the current font +static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win); -BEGIN_EVENT_TABLE(wxWindow, wxEvtHandler) - EVT_CHAR(wxWindow::OnChar) - EVT_ERASE_BACKGROUND(wxWindow::OnEraseBackground) - EVT_SYS_COLOUR_CHANGED(wxWindow::OnSysColourChanged) - EVT_INIT_DIALOG(wxWindow::OnInitDialog) - EVT_IDLE(wxWindow::OnIdle) -END_EVENT_TABLE() +#ifdef __WXWINCE__ +// find the window for the mouse event at the specified position +static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y); +#endif // __WXWINCE__ -// Find an item given the MS Windows id -wxWindow *wxWindow::FindItem(int id) const +// wrapper around BringWindowToTop() API +static inline void wxBringWindowToTop(HWND hwnd) { -// if (!GetChildren()) -// return NULL; - wxNode *current = GetChildren().First(); - while (current) - { - wxWindow *childWin = (wxWindow *)current->Data(); +#ifdef __WXMICROWIN__ + // It seems that MicroWindows brings the _parent_ of the window to the top, + // which can be the wrong one. - wxWindow *wnd = childWin->FindItem(id) ; - if (wnd) - return wnd ; + // activate (set focus to) specified window + ::SetFocus(hwnd); +#endif - 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->Next(); + // raise top level parent to top of z order + if (!::SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE)) + { + wxLogLastError(_T("SetWindowPos")); } - return NULL; } -// Find an item given the MS Windows handle -wxWindow *wxWindow::FindItemByHWND(WXHWND hWnd, bool controlOnly) const +#ifndef __WXWINCE__ + +// ensure that all our parent windows have WS_EX_CONTROLPARENT style +static void EnsureParentHasControlParentStyle(wxWindow *parent) { -// if (!GetChildren()) -// return NULL; - wxNode *current = GetChildren().First(); - while (current) + /* + If we have WS_EX_CONTROLPARENT flag we absolutely *must* set it for our + parent as well as otherwise several Win32 functions using + GetNextDlgTabItem() to iterate over all controls such as + IsDialogMessage() or DefDlgProc() would enter an infinite loop: indeed, + all of them iterate over all the controls starting from the currently + focused one and stop iterating when they get back to the focus but + unless all parents have WS_EX_CONTROLPARENT bit set, they would never + get back to the initial (focused) window: as we do have this style, + GetNextDlgTabItem() will leave this window and continue in its parent, + but if the parent doesn't have it, it wouldn't recurse inside it later + on and so wouldn't have a chance of getting back to this window either. + */ + while ( parent && !parent->IsTopLevel() ) { - wxObject *obj = (wxObject *)current->Data() ; - // Do a recursive search. - wxWindow *parent = (wxWindow *)obj ; - wxWindow *wnd = parent->FindItemByHWND(hWnd) ; - if (wnd) - return wnd ; - - if ((!controlOnly) || obj->IsKindOf(CLASSINFO(wxControl))) + LONG exStyle = ::GetWindowLong(GetHwndOf(parent), GWL_EXSTYLE); + if ( !(exStyle & WS_EX_CONTROLPARENT) ) { - wxWindow *item = (wxWindow *)current->Data(); - if ((HWND)(item->GetHWND()) == (HWND) hWnd) - return item; - else - { - if ( item->ContainsHWND(hWnd) ) - return item; - } + // force the parent to have this style + ::SetWindowLong(GetHwndOf(parent), GWL_EXSTYLE, + exStyle | WS_EX_CONTROLPARENT); } - current = current->Next(); + + parent = parent->GetParent(); } - return NULL; } -// Default command handler -bool wxWindow::MSWCommand(WXUINT WXUNUSED(param), WXWORD WXUNUSED(id)) -{ - return FALSE; -} +#endif // !__WXWINCE__ -bool wxWindow::MSWNotify(WXWPARAM WXUNUSED(wParam), - WXLPARAM lParam, - WXLPARAM* WXUNUSED(result)) +#ifdef __WXWINCE__ +// On Windows CE, GetCursorPos can return an error, so use this function +// instead +bool GetCursorPosWinCE(POINT* pt) { -#ifdef __WIN95__ -#if wxUSE_TOOLTIPS - NMHDR* hdr = (NMHDR *)lParam; - if ( hdr->code == TTN_NEEDTEXT && m_tooltip ) + if (!GetCursorPos(pt)) { - TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam; - ttt->lpszText = (char *)m_tooltip->GetTip().c_str(); - - // processed - return TRUE; + DWORD pos = GetMessagePos(); + pt->x = LOWORD(pos); + pt->y = HIWORD(pos); } -#endif + return true; +} #endif - return FALSE; -} +// --------------------------------------------------------------------------- +// event tables +// --------------------------------------------------------------------------- -void wxWindow::PreDelete(WXHDC WXUNUSED(dc)) -{ -} +// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu() +// method +#ifdef __WXUNIVERSAL__ + IMPLEMENT_ABSTRACT_CLASS(wxWindowMSW, wxWindowBase) +#else // __WXMSW__ +#if wxUSE_EXTENDED_RTTI -WXHWND wxWindow::GetHWND(void) const +// windows that are created from a parent window during its Create method, eg. spin controls in a calendar controls +// must never been streamed out separately otherwise chaos occurs. Right now easiest is to test for negative ids, as +// windows with negative ids never can be recreated anyway + +bool wxWindowStreamingCallback( const wxObject *object, wxWriter * , wxPersister * , wxxVariantArray & ) { - return (WXHWND) m_hWnd; + const wxWindow * win = dynamic_cast(object) ; + if ( win && win->GetId() < 0 ) + return false ; + return true ; } -void wxWindow::SetHWND(WXHWND hWnd) +IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxWindow, wxWindowBase,"wx/window.h", wxWindowStreamingCallback) + +// make wxWindowList known before the property is used + +wxCOLLECTION_TYPE_INFO( wxWindow* , wxWindowList ) ; + +template<> void wxCollectionToVariantArray( wxWindowList const &theList, wxxVariantArray &value) { - m_hWnd = hWnd; + wxListCollectionToVariantArray( theList , value ) ; } -// ---------------------------------------------------------------------------- -// constructors and such -// ---------------------------------------------------------------------------- +WX_DEFINE_FLAGS( wxWindowStyle ) -void wxWindow::Init() -{ - m_isWindow = TRUE; - - // Generic - m_windowId = 0; - m_isShown = TRUE; - m_windowStyle = 0; - m_windowParent = NULL; - m_windowEventHandler = this; - m_children = new wxList; - m_doubleClickAllowed = 0 ; - m_winCaptured = FALSE; - m_constraints = NULL; - m_constraintsInvolvedIn = NULL; - m_windowSizer = NULL; - m_sizerParent = NULL; - m_autoLayout = FALSE; - m_windowValidator = NULL; - - // MSW-specific - m_hWnd = 0; - m_winEnabled = TRUE; - m_caretWidth = m_caretHeight = 0; - m_caretEnabled = - m_caretShown = FALSE; - m_inOnSize = FALSE; - m_minSizeX = - m_minSizeY = - m_maxSizeX = - m_maxSizeY = -1; - - m_isBeingDeleted = FALSE; - m_oldWndProc = 0; -#ifndef __WIN32__ - m_globalHandle = 0; -#endif - m_useCtl3D = FALSE; - m_mouseInWindow = FALSE; +wxBEGIN_FLAGS( wxWindowStyle ) + // new style border flags, we put them first to + // use them for streaming out - m_windowParent = NULL; - m_defaultItem = NULL; + wxFLAGS_MEMBER(wxBORDER_SIMPLE) + wxFLAGS_MEMBER(wxBORDER_SUNKEN) + wxFLAGS_MEMBER(wxBORDER_DOUBLE) + wxFLAGS_MEMBER(wxBORDER_RAISED) + wxFLAGS_MEMBER(wxBORDER_STATIC) + wxFLAGS_MEMBER(wxBORDER_NONE) - wxSystemSettings settings; + // old style border flags + wxFLAGS_MEMBER(wxSIMPLE_BORDER) + wxFLAGS_MEMBER(wxSUNKEN_BORDER) + wxFLAGS_MEMBER(wxDOUBLE_BORDER) + wxFLAGS_MEMBER(wxRAISED_BORDER) + wxFLAGS_MEMBER(wxSTATIC_BORDER) + wxFLAGS_MEMBER(wxBORDER) - m_backgroundColour = settings.GetSystemColour(wxSYS_COLOUR_3DFACE) ; - m_foregroundColour = *wxBLACK; + // standard window styles + wxFLAGS_MEMBER(wxTAB_TRAVERSAL) + wxFLAGS_MEMBER(wxCLIP_CHILDREN) + wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) + wxFLAGS_MEMBER(wxWANTS_CHARS) + wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) + wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) + wxFLAGS_MEMBER(wxVSCROLL) + wxFLAGS_MEMBER(wxHSCROLL) - // wxWnd - m_lastMsg = 0; - m_lastWParam = 0; - m_lastLParam = 0; - m_hMenu = 0; +wxEND_FLAGS( wxWindowStyle ) - m_xThumbSize = 0; - m_yThumbSize = 0; - m_backgroundTransparent = FALSE; +wxBEGIN_PROPERTIES_TABLE(wxWindow) + wxEVENT_PROPERTY( Close , wxEVT_CLOSE_WINDOW , wxCloseEvent) + wxEVENT_PROPERTY( Create , wxEVT_CREATE , wxWindowCreateEvent ) + wxEVENT_PROPERTY( Destroy , wxEVT_DESTROY , wxWindowDestroyEvent ) + // Always constructor Properties first - m_lastXPos = (float)-1.0; - m_lastYPos = (float)-1.0; - m_lastEvent = -1; - m_returnCode = 0; + wxREADONLY_PROPERTY( Parent,wxWindow*, GetParent, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( Id,wxWindowID, SetId, GetId, -1 /*wxID_ANY*/ , 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) + wxPROPERTY( Position,wxPoint, SetPosition , GetPosition, wxDefaultPosition , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // pos + wxPROPERTY( Size,wxSize, SetSize, GetSize, wxDefaultSize , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // size + wxPROPERTY( WindowStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style -#if wxUSE_DRAG_AND_DROP - m_pDropTarget = NULL; -#endif + // Then all relations of the object graph -#if wxUSE_TOOLTIPS - m_tooltip = NULL; -#endif -} + wxREADONLY_PROPERTY_COLLECTION( Children , wxWindowList , wxWindowBase* , GetWindowChildren , wxPROP_OBJECT_GRAPH /*flags*/ , wxT("Helpstring") , wxT("group")) -wxWindow::wxWindow() -{ - Init(); -} + // and finally all other properties -// Destructor -wxWindow::~wxWindow() -{ - m_isBeingDeleted = TRUE; + wxPROPERTY( ExtraStyle , long , SetExtraStyle , GetExtraStyle , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // extstyle + wxPROPERTY( BackgroundColour , wxColour , SetBackgroundColour , GetBackgroundColour , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // bg + wxPROPERTY( ForegroundColour , wxColour , SetForegroundColour , GetForegroundColour , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // fg + wxPROPERTY( Enabled , bool , Enable , IsEnabled , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( Shown , bool , Show , IsShown , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) +#if 0 + // possible property candidates (not in xrc) or not valid in all subclasses + wxPROPERTY( Title,wxString, SetTitle, GetTitle, wxEmptyString ) + wxPROPERTY( Font , wxFont , SetFont , GetWindowFont , ) + wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxEmptyString ) + // MaxHeight, Width , MinHeight , Width + // TODO switch label to control and title to toplevels - // first of all, delete the things on which nothing else depends + wxPROPERTY( ThemeEnabled , bool , SetThemeEnabled , GetThemeEnabled , ) + //wxPROPERTY( Cursor , wxCursor , SetCursor , GetCursor , ) + // wxPROPERTY( ToolTip , wxString , SetToolTip , GetToolTipText , ) + wxPROPERTY( AutoLayout , bool , SetAutoLayout , GetAutoLayout , ) -#if wxUSE_TOOLTIPS - wxDELETE(m_tooltip); -#endif - // JACS - if behaviour is odd, restore this - // to the start of ~wxWindow. Vadim has changed - // it to nearer the end. Unsure of side-effects - // e.g. when deleting associated global data. - // Restore old Window proc, if required - // UnsubclassWin(); - // Have to delete constraints/sizer FIRST otherwise - // sizers may try to look at deleted windows as they - // delete themselves. -#if wxUSE_CONSTRAINTS - DeleteRelatedConstraints(); +#endif +wxEND_PROPERTIES_TABLE() - if (m_constraints) - { - // This removes any dangling pointers to this window - // in other windows' constraintsInvolvedIn lists. - UnsetConstraints(m_constraints); - delete m_constraints; - m_constraints = NULL; - } +wxBEGIN_HANDLERS_TABLE(wxWindow) +wxEND_HANDLERS_TABLE() - wxDELETE(m_windowSizer); +wxCONSTRUCTOR_DUMMY(wxWindow) - // If this is a child of a sizer, remove self from parent - if (m_sizerParent) - m_sizerParent->RemoveChild((wxWindow *)this); +#else + IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase) #endif +#endif // __WXUNIVERSAL__/__WXMSW__ - // wxWnd - MSWDetachWindowMenu(); - - if (m_windowParent) - m_windowParent->RemoveChild(this); +BEGIN_EVENT_TABLE(wxWindowMSW, wxWindowBase) + EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged) + EVT_ERASE_BACKGROUND(wxWindowMSW::OnEraseBackground) +#ifdef __WXWINCE__ + EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog) +#endif +END_EVENT_TABLE() - DestroyChildren(); +// =========================================================================== +// implementation +// =========================================================================== - if (m_hWnd) - ::DestroyWindow((HWND)m_hWnd); +// --------------------------------------------------------------------------- +// wxWindow utility functions +// --------------------------------------------------------------------------- - wxRemoveHandleAssociation(this); - m_hWnd = 0; -#ifndef __WIN32__ - if (m_globalHandle) +// Find an item given the MS Windows id +wxWindow *wxWindowMSW::FindItem(long id) const +{ +#if wxUSE_CONTROLS + wxControl *item = wxDynamicCastThis(wxControl); + if ( item ) { - GlobalFree((HGLOBAL) m_globalHandle); - m_globalHandle = 0; + // is it us or one of our "internal" children? + if ( item->GetId() == id +#ifndef __WXUNIVERSAL__ + || (item->GetSubcontrols().Index(id) != wxNOT_FOUND) +#endif // __WXUNIVERSAL__ + ) + { + return item; + } } -#endif +#endif // wxUSE_CONTROLS + + wxWindowList::compatibility_iterator current = GetChildren().GetFirst(); + while (current) + { + wxWindow *childWin = current->GetData(); - delete m_children; - m_children = NULL; + wxWindow *wnd = childWin->FindItem(id); + if ( wnd ) + return wnd; - // Just in case the window has been Closed, but - // we're then deleting immediately: don't leave - // dangling pointers. - wxPendingDelete.DeleteObject(this); + current = current->GetNext(); + } - // Just in case we've loaded a top-level window via - // wxWindow::LoadNativeDialog but we weren't a dialog - // class - wxTopLevelWindows.DeleteObject(this); + return NULL; +} - if ( m_windowValidator ) - delete m_windowValidator; +// Find an item given the MS Windows handle +wxWindow *wxWindowMSW::FindItemByHWND(WXHWND hWnd, bool controlOnly) const +{ + wxWindowList::compatibility_iterator current = GetChildren().GetFirst(); + while (current) + { + wxWindow *parent = current->GetData(); - // Restore old Window proc, if required - // and remove hWnd <-> wxWindow association - UnsubclassWin(); + // Do a recursive search. + wxWindow *wnd = parent->FindItemByHWND(hWnd); + if ( wnd ) + return wnd; + + if ( !controlOnly +#if wxUSE_CONTROLS + || parent->IsKindOf(CLASSINFO(wxControl)) +#endif // wxUSE_CONTROLS + ) + { + wxWindow *item = current->GetData(); + if ( item->GetHWND() == hWnd ) + return item; + else + { + if ( item->ContainsHWND(hWnd) ) + return item; + } + } + + current = current->GetNext(); + } + return NULL; } -// Destroy the window (delayed, if a managed window) -bool wxWindow::Destroy() +// Default command handler +bool wxWindowMSW::MSWCommand(WXUINT WXUNUSED(param), WXWORD WXUNUSED(id)) { - delete this; - return TRUE; + return false; } -extern char wxCanvasClassName[]; +// ---------------------------------------------------------------------------- +// constructors and such +// ---------------------------------------------------------------------------- -// real construction (Init() must have been called before!) -bool wxWindow::Create(wxWindow *parent, wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) +void wxWindowMSW::Init() { - wxCHECK_MSG( parent, FALSE, "can't create wxWindow without parent" ); + // MSW specific + m_isBeingDeleted = false; + m_oldWndProc = NULL; + m_mouseInWindow = false; + m_lastKeydownProcessed = false; - parent->AddChild(this); + m_childrenDisabled = NULL; + m_frozenness = 0; - SetName(name); + m_hWnd = 0; + m_hDWP = 0; - if ( id == -1 ) - m_windowId = (int)NewControlId(); - else - m_windowId = id; + m_xThumbSize = 0; + m_yThumbSize = 0; - int x = pos.x; - int y = pos.y; - int width = size.x; - int height = size.y; + m_pendingPosition = wxDefaultPosition; + m_pendingSize = wxDefaultSize; - // To be consistent with wxGTK - if (width == -1) - width = 20; - if (height == -1) - height = 20; +#ifdef __POCKETPC__ + m_contextMenuEnabled = false; +#endif +} - wxSystemSettings settings; +// Destructor +wxWindowMSW::~wxWindowMSW() +{ + m_isBeingDeleted = true; - m_windowStyle = style; +#ifndef __WXUNIVERSAL__ + // VS: make sure there's no wxFrame with last focus set to us: + for ( wxWindow *win = GetParent(); win; win = win->GetParent() ) + { + wxTopLevelWindow *frame = wxDynamicCast(win, wxTopLevelWindow); + if ( frame ) + { + if ( frame->GetLastFocus() == this ) + { + frame->SetLastFocus(NULL); + } - DWORD msflags = 0; - if (style & wxBORDER) - msflags |= WS_BORDER; - if (style & wxTHICK_FRAME) - msflags |= WS_THICKFRAME; + // apparently sometimes we can end up with our grand parent + // pointing to us as well: this is surely a bug in focus handling + // code but it's not clear where it happens so for now just try to + // fix it here by not breaking out of the loop + //break; + } + } +#endif // __WXUNIVERSAL__ - msflags |= WS_CHILD | WS_VISIBLE; - if (style & wxCLIP_CHILDREN) - msflags |= WS_CLIPCHILDREN; + // VS: destroy children first and _then_ detach *this from its parent. + // If we did it the other way around, children wouldn't be able + // find their parent frame (see above). + DestroyChildren(); - bool want3D; - WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D) ; + if ( m_hWnd ) + { + // VZ: test temp removed to understand what really happens here + //if (::IsWindow(GetHwnd())) + { + if ( !::DestroyWindow(GetHwnd()) ) + wxLogLastError(wxT("DestroyWindow")); + } - // Even with extended styles, need to combine with WS_BORDER - // for them to look right. - if (want3D || (m_windowStyle & wxSIMPLE_BORDER) || (m_windowStyle & wxRAISED_BORDER) || - (m_windowStyle & wxSUNKEN_BORDER) || (m_windowStyle & wxDOUBLE_BORDER)) - msflags |= WS_BORDER; + // remove hWnd <-> wxWindow association + wxRemoveHandleAssociation(this); + } - MSWCreate(m_windowId, parent, wxCanvasClassName, this, NULL, - x, y, width, height, msflags, NULL, exStyle); + delete m_childrenDisabled; - return TRUE; } -void wxWindow::SetFocus() +// real construction (Init() must have been called before!) +bool wxWindowMSW::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) { - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - ::SetFocus(hWnd); -} + wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") ); -void wxWindow::Enable(bool enable) -{ - m_winEnabled = enable; - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - ::EnableWindow(hWnd, (BOOL)enable); -} + if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) + return false; -void wxWindow::CaptureMouse() -{ - HWND hWnd = (HWND) GetHWND(); - if (hWnd && !m_winCaptured) - { - SetCapture(hWnd); - m_winCaptured = TRUE; - } -} + parent->AddChild(this); -void wxWindow::ReleaseMouse() -{ - if (m_winCaptured) + WXDWORD exstyle; + DWORD msflags = MSWGetCreateWindowFlags(&exstyle); + +#ifdef __WXUNIVERSAL__ + // no borders, we draw them ourselves + exstyle &= ~(WS_EX_DLGMODALFRAME | + WS_EX_STATICEDGE | + WS_EX_CLIENTEDGE | + WS_EX_WINDOWEDGE); + msflags &= ~WS_BORDER; +#endif // wxUniversal + + if ( IsShown() ) { - ReleaseCapture(); - m_winCaptured = FALSE; + msflags |= WS_VISIBLE; } -} -void wxWindow::SetAcceleratorTable(const wxAcceleratorTable& accel) -{ - m_acceleratorTable = accel; -} + if ( !MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle) ) + return false; + InheritAttributes(); -// Push/pop event handler (i.e. allow a chain of event handlers -// be searched) -void wxWindow::PushEventHandler(wxEvtHandler *handler) -{ - handler->SetNextHandler(GetEventHandler()); - SetEventHandler(handler); + return true; } -wxEvtHandler *wxWindow::PopEventHandler(bool deleteHandler) +// --------------------------------------------------------------------------- +// basic operations +// --------------------------------------------------------------------------- + +void wxWindowMSW::SetFocus() { - if ( GetEventHandler() ) + HWND hWnd = GetHwnd(); + wxCHECK_RET( hWnd, _T("can't set focus to invalid window") ); + +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) + ::SetLastError(0); +#endif + + if ( !::SetFocus(hWnd) ) { - wxEvtHandler *handlerA = GetEventHandler(); - wxEvtHandler *handlerB = handlerA->GetNextHandler(); - handlerA->SetNextHandler(NULL); - SetEventHandler(handlerB); - if ( deleteHandler ) +#if defined(__WXDEBUG__) && !defined(__WXMICROWIN__) + // was there really an error? + DWORD dwRes = ::GetLastError(); + if ( dwRes ) { - delete handlerA; - return NULL; + HWND hwndFocus = ::GetFocus(); + if ( hwndFocus != hWnd ) + { + wxLogApiError(_T("SetFocus"), dwRes); + } } - else - return handlerA; +#endif // Debug } - else - return NULL; } -#if wxUSE_DRAG_AND_DROP - -void wxWindow::SetDropTarget(wxDropTarget *pDropTarget) +void wxWindowMSW::SetFocusFromKbd() { - if ( m_pDropTarget != 0 ) { - m_pDropTarget->Revoke(m_hWnd); - delete m_pDropTarget; + // when the focus is given to the control with DLGC_HASSETSEL style from + // keyboard its contents should be entirely selected: this is what + // ::IsDialogMessage() does and so we should do it as well to provide the + // same LNF as the native programs + if ( ::SendMessage(GetHwnd(), WM_GETDLGCODE, 0, 0) & DLGC_HASSETSEL ) + { + ::SendMessage(GetHwnd(), EM_SETSEL, 0, -1); } - m_pDropTarget = pDropTarget; - if ( m_pDropTarget != 0 ) - m_pDropTarget->Register(m_hWnd); + // do this after (maybe) setting the selection as like this when + // wxEVT_SET_FOCUS handler is called, the selection would have been already + // set correctly -- this may be important + wxWindowBase::SetFocusFromKbd(); } -#endif // wxUSE_DRAG_AND_DROP - - -//old style file-manager drag&drop support -// I think we should retain the old-style -// DragAcceptFiles in parallel with SetDropTarget. -// JACS -void wxWindow::DragAcceptFiles(bool accept) +// Get the window with the focus +wxWindow *wxWindowBase::DoFindFocus() { - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - ::DragAcceptFiles(hWnd, (BOOL)accept); + HWND hWnd = ::GetFocus(); + if ( hWnd ) + { + return wxGetWindowFromHWND((WXHWND)hWnd); + } + + return NULL; } -// ---------------------------------------------------------------------------- -// tooltips -// ---------------------------------------------------------------------------- +bool wxWindowMSW::Enable(bool enable) +{ + if ( !wxWindowBase::Enable(enable) ) + return false; -#if wxUSE_TOOLTIPS + HWND hWnd = GetHwnd(); + if ( hWnd ) + ::EnableWindow(hWnd, (BOOL)enable); -void wxWindow::SetToolTip(const wxString &tip) -{ - SetToolTip(new wxToolTip(tip)); -} + // 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; + } -void wxWindow::SetToolTip(wxToolTip *tooltip) -{ - if ( m_tooltip ) - delete m_tooltip; + 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_tooltip = tooltip; - m_tooltip->SetWindow(this); -} + m_childrenDisabled->Append(child); + } + } + } -#endif // wxUSE_TOOLTIPS + if ( enable && m_childrenDisabled ) + { + // we don't need this list any more, don't keep unused memory + delete m_childrenDisabled; + m_childrenDisabled = NULL; + } -// Get total size -void wxWindow::GetSize(int *x, int *y) const -{ - HWND hWnd = (HWND) GetHWND(); - RECT rect; - GetWindowRect(hWnd, &rect); - *x = rect.right - rect.left; - *y = rect.bottom - rect.top; + return true; } -void wxWindow::GetPosition(int *x, int *y) const +bool wxWindowMSW::Show(bool show) { - HWND hWnd = (HWND) GetHWND(); - HWND hParentWnd = 0; - if (GetParent()) - hParentWnd = (HWND) GetParent()->GetHWND(); + if ( !wxWindowBase::Show(show) ) + return false; - RECT rect; - GetWindowRect(hWnd, &rect); + HWND hWnd = GetHwnd(); - // 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) + // we could be called before the underlying window is created (this is + // actually useful to prevent it from being initially shown), e.g. + // + // wxFoo *foo = new wxFoo; + // foo->Hide(); + // foo->Create(parent, ...); + // + // should work without errors + if ( hWnd ) { - ::ScreenToClient(hParentWnd, &point); + ::ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE); } - // 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()) - { - wxPoint pt(GetParent()->GetClientAreaOrigin()); - point.x -= pt.x; - point.y -= pt.y; - } - *x = point.x; - *y = point.y; + return true; } -void wxWindow::ScreenToClient(int *x, int *y) const +// Raise the window to the top of the Z order +void wxWindowMSW::Raise() { - HWND hWnd = (HWND) GetHWND(); - POINT pt; - pt.x = *x; - pt.y = *y; - - ::ScreenToClient(hWnd, &pt); + wxBringWindowToTop(GetHwnd()); +} - *x = pt.x; - *y = pt.y; +// Lower the window to the bottom of the Z order +void wxWindowMSW::Lower() +{ + ::SetWindowPos(GetHwnd(), HWND_BOTTOM, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); } -void wxWindow::ClientToScreen(int *x, int *y) const +void wxWindowMSW::DoCaptureMouse() { - HWND hWnd = (HWND) GetHWND(); - POINT pt; - pt.x = *x; - pt.y = *y; + HWND hWnd = GetHwnd(); + if ( hWnd ) + { + ::SetCapture(hWnd); + } +} - ::ClientToScreen(hWnd, &pt); +void wxWindowMSW::DoReleaseMouse() +{ + if ( !::ReleaseCapture() ) + { + wxLogLastError(_T("ReleaseCapture")); + } +} - *x = pt.x; - *y = pt.y; +/* static */ wxWindow *wxWindowBase::GetCapture() +{ + HWND hwnd = ::GetCapture(); + return hwnd ? wxFindWinFromHandle((WXHWND)hwnd) : (wxWindow *)NULL; } -void wxWindow::SetCursor(const wxCursor& cursor) +bool wxWindowMSW::SetFont(const wxFont& font) { - m_windowCursor = cursor; - if (m_windowCursor.Ok()) + if ( !wxWindowBase::SetFont(font) ) { - HWND hWnd = (HWND) GetHWND(); + // nothing to do + return false; + } - // Change the cursor NOW if we're within the correct window - POINT point; - ::GetCursorPos(&point); + HWND hWnd = GetHwnd(); + if ( hWnd != 0 ) + { + WXHANDLE hFont = m_font.GetResourceHandle(); - RECT rect; - ::GetWindowRect(hWnd, &rect); + wxASSERT_MSG( hFont, wxT("should have valid font") ); - if (::PtInRect(&rect, point) && !wxIsBusy()) - ::SetCursor((HCURSOR) m_windowCursor.GetHCURSOR()); + ::SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); } - // This will cause big reentrancy problems if wxFlushEvents is implemented. - // wxFlushEvents(); - // return old_cursor; + return true; } - - -// Get size *available for subwindows* i.e. excluding menu bar etc. -void wxWindow::GetClientSize(int *x, int *y) const +bool wxWindowMSW::SetCursor(const wxCursor& cursor) { - HWND hWnd = (HWND) GetHWND(); - RECT rect; - ::GetClientRect(hWnd, &rect); - *x = rect.right; - *y = rect.bottom; -} + if ( !wxWindowBase::SetCursor(cursor) ) + { + // no change + return false; + } -void wxWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags) -{ - int currentX, currentY; - GetPosition(¤tX, ¤tY); - int currentW,currentH; - GetSize(¤tW, ¤tH); + // don't "overwrite" busy cursor + if ( m_cursor.Ok() && !wxIsBusy() ) + { + ::SetCursor(GetHcursorOf(m_cursor)); + } - if (x == currentX && y == currentY && width == currentW && height == currentH) - return; + return true; +} - 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; +void wxWindowMSW::WarpPointer(int x, int y) +{ + ClientToScreen(&x, &y); - AdjustForParentClientOrigin(actualX, actualY, sizeFlags); + if ( !::SetCursorPos(x, y) ) + { + wxLogLastError(_T("SetCursorPos")); + } +} - if (width == -1) - actualWidth = currentW ; - if (height == -1) - actualHeight = currentH ; +void wxWindowMSW::MSWUpdateUIState(int action, int state) +{ + // WM_CHANGEUISTATE only appeared in Windows 2000 so it can do us no good + // to use it on older systems -- and could possibly do some harm + static int s_needToUpdate = -1; + if ( s_needToUpdate == -1 ) + { + int verMaj, verMin; + s_needToUpdate = wxGetOsVersion(&verMaj, &verMin) == wxOS_WINDOWS_NT && + verMaj >= 5; + } - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - MoveWindow(hWnd, actualX, actualY, actualWidth, actualHeight, (BOOL)TRUE); + if ( s_needToUpdate ) + { + // we send WM_CHANGEUISTATE so if nothing needs changing then the system + // won't send WM_UPDATEUISTATE + ::SendMessage(GetHwnd(), WM_CHANGEUISTATE, MAKEWPARAM(action, state), 0); + } } -void wxWindow::DoSetClientSize(int width, int height) +// --------------------------------------------------------------------------- +// scrolling stuff +// --------------------------------------------------------------------------- + +inline int GetScrollPosition(HWND hWnd, int wOrient) { - wxWindow *parent = GetParent(); - HWND hWnd = (HWND) GetHWND(); - HWND hParentWnd = (HWND) 0; - if (parent) - hParentWnd = (HWND) parent->GetHWND(); +#ifdef __WXMICROWIN__ + return ::GetScrollPosWX(hWnd, wOrient); +#else + WinStruct scrollInfo; + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_POS; + ::GetScrollInfo(hWnd, wOrient, &scrollInfo ); - RECT rect; - ::GetClientRect(hWnd, &rect); + return scrollInfo.nPos; - RECT rect2; - GetWindowRect(hWnd, &rect2); +#endif +} - // Find the difference between the entire window (title bar and all) - // and the client area; add this to the new client size to move the - // window - int actual_width = rect2.right - rect2.left - rect.right + width; - int actual_height = rect2.bottom - rect2.top - rect.bottom + height; +int wxWindowMSW::GetScrollPos(int orient) const +{ + HWND hWnd = GetHwnd(); + wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") ); - // If there's a parent, must subtract the parent's top left corner - // since MoveWindow moves relative to the parent + return GetScrollPosition(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT); +} - POINT point; - point.x = rect2.left; - point.y = rect2.top; - if (parent) +// This now returns the whole range, not just the number +// of positions that we can scroll. +int wxWindowMSW::GetScrollRange(int orient) const +{ + int maxPos; + HWND hWnd = GetHwnd(); + if ( !hWnd ) + return 0; +#if 0 + ::GetScrollRange(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT, + &minPos, &maxPos); +#endif + WinStruct scrollInfo; + scrollInfo.fMask = SIF_RANGE; + if ( !::GetScrollInfo(hWnd, + orient == wxHORIZONTAL ? SB_HORZ : SB_VERT, + &scrollInfo) ) { - ::ScreenToClient(hParentWnd, &point); + // Most of the time this is not really an error, since the return + // value can also be zero when there is no scrollbar yet. + // wxLogLastError(_T("GetScrollInfo")); } + maxPos = scrollInfo.nMax; - MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)TRUE); - - wxSizeEvent event(wxSize(width, height), m_windowId); - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); + // undo "range - 1" done in SetScrollbar() + return maxPos + 1; } -// For implementation purposes - sometimes decorations make the client area -// smaller -wxPoint wxWindow::GetClientAreaOrigin() const +int wxWindowMSW::GetScrollThumb(int orient) const { - return wxPoint(0, 0); + return orient == wxHORIZONTAL ? m_xThumbSize : m_yThumbSize; } -// Makes an adjustment to the window position (for example, a frame that has -// a toolbar that it manages itself). -void wxWindow::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) +void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh) { - if (((sizeFlags & wxSIZE_NO_ADJUSTMENTS) == 0) && GetParent()) + HWND hWnd = GetHwnd(); + wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") ); + + WinStruct info; + info.nPage = 0; + info.nMin = 0; + info.nPos = pos; + info.fMask = SIF_POS; + if ( HasFlag(wxALWAYS_SHOW_SB) ) { - wxPoint pt(GetParent()->GetClientAreaOrigin()); - x += pt.x; y += pt.y; + // disable scrollbar instead of removing it then + info.fMask |= SIF_DISABLENOSCROLL; } + + ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT, + &info, refresh); } -bool wxWindow::Show(bool show) -{ - m_isShown = show; - HWND hWnd = (HWND) GetHWND(); - int cshow; - if (show) - cshow = SW_SHOW; - else - cshow = SW_HIDE; - ShowWindow(hWnd, cshow); - if (show) +// New function that will replace some of the above. +void wxWindowMSW::SetScrollbar(int orient, + int pos, + int pageSize, + int range, + bool refresh) +{ + WinStruct info; + info.nPage = pageSize; + info.nMin = 0; // range is nMax - nMin + 1 + info.nMax = range - 1; // as both nMax and nMax are inclusive + info.nPos = pos; + info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; + if ( HasFlag(wxALWAYS_SHOW_SB) ) + { + // disable scrollbar instead of removing it then + info.fMask |= SIF_DISABLENOSCROLL; + } + + HWND hWnd = GetHwnd(); + if ( hWnd ) { - BringWindowToTop(hWnd); - // Next line causes a crash on NT, apparently. - // UpdateWindow(hWnd); // Should this be here or will it cause inefficiency? + // We have to set the variables here to make them valid in events + // triggered by ::SetScrollInfo() + *(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize; + + ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT, + &info, refresh); } - return TRUE; } -bool wxWindow::IsShown(void) const +void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect) { - // Can't rely on IsWindowVisible, since it will return FALSE - // if the parent is not visible. - return m_isShown; -// int ret = ::IsWindowVisible((HWND) GetHWND()) ; -// return (ret != 0); + RECT rect; + RECT *pr; + if ( prect ) + { + rect.left = prect->x; + rect.top = prect->y; + rect.right = prect->x + prect->width; + rect.bottom = prect->y + prect->height; + pr = ▭ + } + else + { + pr = NULL; + + } + +#ifdef __WXWINCE__ + // FIXME: is this the exact equivalent of the line below? + ::ScrollWindowEx(GetHwnd(), dx, dy, pr, pr, 0, 0, SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE); +#else + ::ScrollWindow(GetHwnd(), dx, dy, pr, pr); +#endif } -int wxWindow::GetCharHeight(void) const +static bool ScrollVertically(HWND hwnd, int kind, int count) { - TEXTMETRIC lpTextMetric; - HWND hWnd = (HWND) GetHWND(); - HDC dc = ::GetDC(hWnd); + int posStart = GetScrollPosition(hwnd, SB_VERT); + + int pos = posStart; + for ( int n = 0; n < count; n++ ) + { + ::SendMessage(hwnd, WM_VSCROLL, kind, 0); + + int posNew = GetScrollPosition(hwnd, SB_VERT); + if ( posNew == pos ) + { + // don't bother to continue, we're already at top/bottom + break; + } - GetTextMetrics(dc, &lpTextMetric); - ::ReleaseDC(hWnd, dc); + pos = posNew; + } - return lpTextMetric.tmHeight; + return pos != posStart; } -int wxWindow::GetCharWidth(void) const +bool wxWindowMSW::ScrollLines(int lines) { - TEXTMETRIC lpTextMetric; - HWND hWnd = (HWND) GetHWND(); - HDC dc = ::GetDC(hWnd); + bool down = lines > 0; - GetTextMetrics(dc, &lpTextMetric); - ::ReleaseDC(hWnd, dc); + return ScrollVertically(GetHwnd(), + down ? SB_LINEDOWN : SB_LINEUP, + down ? lines : -lines); +} + +bool wxWindowMSW::ScrollPages(int pages) +{ + bool down = pages > 0; - return lpTextMetric.tmAveCharWidth; + return ScrollVertically(GetHwnd(), + down ? SB_PAGEDOWN : SB_PAGEUP, + down ? pages : -pages); } -void wxWindow::GetTextExtent(const wxString& string, int *x, int *y, - int *descent, int *externalLeading, const wxFont *theFont, bool) const +// ---------------------------------------------------------------------------- +// RTL support +// ---------------------------------------------------------------------------- + +void wxWindowMSW::SetLayoutDirection(wxLayoutDirection dir) { - wxFont *fontToUse = (wxFont *)theFont; - if (!fontToUse) - fontToUse = (wxFont *) & m_windowFont; +#ifdef __WXWINCE__ + wxUnusedVar(dir); +#else + const HWND hwnd = GetHwnd(); + wxCHECK_RET( hwnd, _T("layout direction must be set after window creation") ); - HWND hWnd = (HWND) GetHWND(); - HDC dc = ::GetDC(hWnd); + LONG styleOld = ::GetWindowLong(hwnd, GWL_EXSTYLE); - HFONT fnt = 0; - HFONT was = 0; - if (fontToUse && fontToUse->Ok()) + LONG styleNew = styleOld; + switch ( dir ) + { + case wxLayout_LeftToRight: + styleNew &= ~WS_EX_LAYOUTRTL; + break; + + case wxLayout_RightToLeft: + styleNew |= WS_EX_LAYOUTRTL; + break; + + default: + wxFAIL_MSG(_T("unsupported layout direction")); + break; + } + + if ( styleNew != styleOld ) { - fnt = (HFONT)fontToUse->GetResourceHandle(); - if ( fnt ) - was = (HFONT) SelectObject(dc,fnt) ; + ::SetWindowLong(hwnd, GWL_EXSTYLE, styleNew); } +#endif +} - SIZE sizeRect; - TEXTMETRIC tm; - GetTextExtentPoint(dc, (const char *)string, (int)string.Length(), &sizeRect); - GetTextMetrics(dc, &tm); +wxLayoutDirection wxWindowMSW::GetLayoutDirection() const +{ +#ifdef __WXWINCE__ + return wxLayout_Default; +#else + const HWND hwnd = GetHwnd(); + wxCHECK_MSG( hwnd, wxLayout_Default, _T("invalid window") ); + + return ::GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL + ? wxLayout_RightToLeft + : wxLayout_LeftToRight; +#endif +} + +wxCoord +wxWindowMSW::AdjustForLayoutDirection(wxCoord x, + wxCoord WXUNUSED(width), + wxCoord WXUNUSED(widthTotal)) const +{ + // Win32 mirrors the coordinates of RTL windows automatically, so don't + // redo it ourselves + return x; +} + +// --------------------------------------------------------------------------- +// subclassing +// --------------------------------------------------------------------------- + +void wxWindowMSW::SubclassWin(WXHWND hWnd) +{ + wxASSERT_MSG( !m_oldWndProc, wxT("subclassing window twice?") ); + + HWND hwnd = (HWND)hWnd; + wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in SubclassWin") ); - if (fontToUse && fnt && was) - SelectObject(dc,was) ; + wxAssociateWinWithHandle(hwnd, this); - ReleaseDC(hWnd, dc); + m_oldWndProc = (WXFARPROC)wxGetWindowProc((HWND)hWnd); - *x = sizeRect.cx; - *y = sizeRect.cy; - if (descent) *descent = tm.tmDescent; - if (externalLeading) *externalLeading = tm.tmExternalLeading; + // we don't need to subclass the window of our own class (in the Windows + // sense of the word) + if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) ) + { + wxSetWindowProc(hwnd, wxWndProc); + } + else + { + // don't bother restoring it either: this also makes it easy to + // implement IsOfStandardClass() method which returns true for the + // standard controls and false for the wxWidgets own windows as it can + // simply check m_oldWndProc + m_oldWndProc = NULL; + } - // if (fontToUse) - // fontToUse->ReleaseResource(); + // we're officially created now, send the event + wxWindowCreateEvent event((wxWindow *)this); + (void)GetEventHandler()->ProcessEvent(event); } -void wxWindow::Refresh(bool eraseBack, const wxRect *rect) +void wxWindowMSW::UnsubclassWin() { - HWND hWnd = (HWND) GetHWND(); - if (hWnd) + wxRemoveHandleAssociation(this); + + // Restore old Window proc + HWND hwnd = GetHwnd(); + if ( hwnd ) { - if (rect) + SetHWND(0); + + wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") ); + + if ( m_oldWndProc ) { - RECT mswRect; - mswRect.left = rect->x; - mswRect.top = rect->y; - mswRect.right = rect->x + rect->width; - mswRect.bottom = rect->y + rect->height; + if ( !wxCheckWindowWndProc((WXHWND)hwnd, m_oldWndProc) ) + { + wxSetWindowProc(hwnd, (WNDPROC)m_oldWndProc); + } - ::InvalidateRect(hWnd, &mswRect, eraseBack); + m_oldWndProc = NULL; } - else - ::InvalidateRect(hWnd, NULL, eraseBack); } } -bool wxWindow::ProcessEvent(wxEvent& event) +void wxWindowMSW::AssociateHandle(WXWidget handle) { - // we save here the information about the last message because it might be - // overwritten if the event handler sends any messages to our window (case - // in point: wxNotebook::OnSize) - and then if we call Default() later - // (which is done quite often if the message is not processed) it will use - // incorrect values for m_lastXXX variables - WXUINT lastMsg = m_lastMsg; - WXWPARAM lastWParam = m_lastWParam; - WXLPARAM lastLParam = m_lastLParam; + if ( m_hWnd ) + { + if ( !::DestroyWindow(GetHwnd()) ) + wxLogLastError(wxT("DestroyWindow")); + } - // call the base version - bool bProcessed = wxEvtHandler::ProcessEvent(event); + WXHWND wxhwnd = (WXHWND)handle; - // restore - m_lastMsg = lastMsg; - m_lastWParam = lastWParam; - m_lastLParam = lastLParam; + SetHWND(wxhwnd); + SubclassWin(wxhwnd); +} - return bProcessed; +void wxWindowMSW::DissociateHandle() +{ + // this also calls SetHWND(0) for us + UnsubclassWin(); } -// Hook for new window just as it's being created, -// when the window isn't yet associated with the handle -wxWindow *wxWndHook = NULL; -// Main window proc -LRESULT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +bool wxCheckWindowWndProc(WXHWND hWnd, + WXFARPROC WXUNUSED(wndProc)) +{ +// TODO: This list of window class names should be factored out so they can be +// managed in one place and then accessed from here and other places, such as +// wxApp::RegisterWindowClasses() and wxApp::UnregisterWindowClasses() + +#ifdef __WXWINCE__ + extern wxChar *wxCanvasClassName; + extern wxChar *wxCanvasClassNameNR; +#else + extern const wxChar *wxCanvasClassName; + extern const wxChar *wxCanvasClassNameNR; +#endif + extern const wxChar *wxMDIFrameClassName; + extern const wxChar *wxMDIFrameClassNameNoRedraw; + extern const wxChar *wxMDIChildFrameClassName; + extern const wxChar *wxMDIChildFrameClassNameNoRedraw; + wxString str(wxGetWindowClass(hWnd)); + if (str == wxCanvasClassName || + str == wxCanvasClassNameNR || +#if wxUSE_GLCANVAS + str == _T("wxGLCanvasClass") || + str == _T("wxGLCanvasClassNR") || +#endif // wxUSE_GLCANVAS + str == wxMDIFrameClassName || + str == wxMDIFrameClassNameNoRedraw || + str == wxMDIChildFrameClassName || + str == wxMDIChildFrameClassNameNoRedraw || + str == _T("wxTLWHiddenParent")) + return true; // Effectively means don't subclass + else + return false; +} + +// ---------------------------------------------------------------------------- +// Style handling +// ---------------------------------------------------------------------------- + +void wxWindowMSW::SetWindowStyleFlag(long flags) +{ + long flagsOld = GetWindowStyleFlag(); + if ( flags == flagsOld ) + return; + + // update the internal variable + wxWindowBase::SetWindowStyleFlag(flags); + + // and the real window flags + MSWUpdateStyle(flagsOld, GetExtraStyle()); +} + +void wxWindowMSW::SetExtraStyle(long exflags) +{ + long exflagsOld = GetExtraStyle(); + if ( exflags == exflagsOld ) + return; + + // update the internal variable + wxWindowBase::SetExtraStyle(exflags); + + // and the real window flags + MSWUpdateStyle(GetWindowStyleFlag(), exflagsOld); +} + +void wxWindowMSW::MSWUpdateStyle(long flagsOld, long exflagsOld) { - wxWindow *wnd = wxFindWinFromHandle((WXHWND) hWnd); + // now update the Windows style as well if needed - and if the window had + // been already created + if ( !GetHwnd() ) + return; + + // we may need to call SetWindowPos() when we change some styles + bool callSWP = false; + + WXDWORD exstyle; + long style = MSWGetStyle(GetWindowStyleFlag(), &exstyle); + + // this is quite a horrible hack but we need it because MSWGetStyle() + // doesn't take exflags as parameter but uses GetExtraStyle() internally + // and so we have to modify the window exflags temporarily to get the + // correct exstyleOld + long exflagsNew = GetExtraStyle(); + wxWindowBase::SetExtraStyle(exflagsOld); + + WXDWORD exstyleOld; + long styleOld = MSWGetStyle(flagsOld, &exstyleOld); - if (!wnd && wxWndHook) + wxWindowBase::SetExtraStyle(exflagsNew); + + + if ( style != styleOld ) { - wxAssociateWinWithHandle(hWnd, wxWndHook); - wnd = wxWndHook; - wxWndHook = NULL; - wnd->m_hWnd = (WXHWND) hWnd; - } + // some flags (e.g. WS_VISIBLE or WS_DISABLED) should not be changed by + // this function so instead of simply setting the style to the new + // value we clear the bits which were set in styleOld but are set in + // the new one and set the ones which were not set before + long styleReal = ::GetWindowLong(GetHwnd(), GWL_STYLE); + styleReal &= ~styleOld; + styleReal |= style; + + ::SetWindowLong(GetHwnd(), GWL_STYLE, styleReal); + + // we need to call SetWindowPos() if any of the styles affecting the + // frame appearance have changed + callSWP = ((styleOld ^ style ) & (WS_BORDER | + WS_THICKFRAME | + WS_CAPTION | + WS_DLGFRAME | + WS_MAXIMIZEBOX | + WS_MINIMIZEBOX | + WS_SYSMENU) ) != 0; + } + + // and the extended style + long exstyleReal = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE); + + if ( exstyle != exstyleOld ) + { + exstyleReal &= ~exstyleOld; + exstyleReal |= exstyle; - // Stop right here if we don't have a valid handle in our wxWindow object. - if (wnd && !wnd->m_hWnd) { - wnd->m_hWnd = (WXHWND) hWnd; - long res = wnd->MSWDefWindowProc(message, wParam, lParam ); - wnd->m_hWnd = 0; - return res; + ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, exstyleReal); + + // ex style changes don't take effect without calling SetWindowPos + callSWP = true; } - if (wnd) { - wnd->m_lastMsg = message; - wnd->m_lastWParam = wParam; - wnd->m_lastLParam = lParam; + if ( callSWP ) + { + // we must call SetWindowPos() to flush the cached extended style and + // also to make the change to wxSTAY_ON_TOP style take effect: just + // setting the style simply doesn't work + if ( !::SetWindowPos(GetHwnd(), + exstyleReal & WS_EX_TOPMOST ? HWND_TOPMOST + : HWND_NOTOPMOST, + 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED) ) + { + wxLogLastError(_T("SetWindowPos")); + } } - if (wnd) - return wnd->MSWWindowProc(message, wParam, lParam); - else - return DefWindowProc( hWnd, message, wParam, lParam ); } -// Should probably have a test for 'genuine' NT -#if defined(__WIN32__) - #define DIMENSION_TYPE short -#else - #define DIMENSION_TYPE int -#endif - -// Main Windows 3 window proc -long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) +WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const { - wxASSERT( m_lastMsg == message && - m_lastWParam == wParam && m_lastLParam == lParam ); + // translate common wxWidgets styles to Windows ones -#ifdef __WXDEBUG__ - wxLogTrace(wxTraceMessages, "Processing %s(%lx, %lx)", - wxGetMessageName(message), wParam, lParam); -#endif // __WXDEBUG__ + // most of windows are child ones, those which are not (such as + // wxTopLevelWindow) should remove WS_CHILD in their MSWGetStyle() + WXDWORD style = WS_CHILD; + + // using this flag results in very significant reduction in flicker, + // especially with controls inside the static boxes (as the interior of the + // box is not redrawn twice), but sometimes results in redraw problems, so + // optionally allow the old code to continue to use it provided a special + // system option is turned on + if ( !wxSystemOptions::GetOptionInt(wxT("msw.window.no-clip-children")) + || (flags & wxCLIP_CHILDREN) ) + style |= WS_CLIPCHILDREN; + + // it doesn't seem useful to use WS_CLIPSIBLINGS here as we officially + // don't support overlapping windows and it only makes sense for them and, + // presumably, gives the system some extra work (to manage more clipping + // regions), so avoid it alltogether - HWND hWnd = (HWND)m_hWnd; - switch (message) + if ( flags & wxVSCROLL ) + style |= WS_VSCROLL; + + if ( flags & wxHSCROLL ) + style |= WS_HSCROLL; + + const wxBorder border = GetBorder(flags); + + // WS_BORDER is only required for wxBORDER_SIMPLE + if ( border == wxBORDER_SIMPLE ) + style |= WS_BORDER; + + // now deal with ext style if the caller wants it + if ( exstyle ) { - case WM_ACTIVATE: - { -#ifdef __WIN32__ - WORD state = LOWORD(wParam); - WORD minimized = HIWORD(wParam); - HWND hwnd = (HWND)lParam; -#else - WORD state = (WORD)wParam; - WORD minimized = LOWORD(lParam); - HWND hwnd = (HWND)HIWORD(lParam); + *exstyle = 0; + +#ifndef __WXWINCE__ + if ( flags & wxTRANSPARENT_WINDOW ) + *exstyle |= WS_EX_TRANSPARENT; #endif - MSWOnActivate(state, (minimized != 0), (WXHWND) hwnd); - return 0; - break; - } - case WM_SETFOCUS: + + switch ( border ) { - HWND hwnd = (HWND)wParam; - // return OnSetFocus(hwnd); + default: + case wxBORDER_DEFAULT: + wxFAIL_MSG( _T("unknown border style") ); + // fall through - if (MSWOnSetFocus((WXHWND) hwnd)) - return 0; - else return MSWDefWindowProc(message, wParam, lParam ); - break; + case wxBORDER_NONE: + case wxBORDER_SIMPLE: + break; + + case wxBORDER_STATIC: + *exstyle |= WS_EX_STATICEDGE; + break; + + case wxBORDER_RAISED: + *exstyle |= WS_EX_DLGMODALFRAME; + break; + + case wxBORDER_SUNKEN: + *exstyle |= WS_EX_CLIENTEDGE; + style &= ~WS_BORDER; + break; + + case wxBORDER_DOUBLE: + *exstyle |= WS_EX_DLGMODALFRAME; + break; } - case WM_KILLFOCUS: + + // wxUniv doesn't use Windows dialog navigation functions at all +#if !defined(__WXUNIVERSAL__) && !defined(__WXWINCE__) + // to make the dialog navigation work with the nested panels we must + // use this style (top level windows such as dialogs don't need it) + if ( (flags & wxTAB_TRAVERSAL) && !IsTopLevel() ) { - HWND hwnd = (HWND)lParam; - // return OnKillFocus(hwnd); - if (MSWOnKillFocus((WXHWND) hwnd)) - return 0; - else - return MSWDefWindowProc(message, wParam, lParam ); - break; + *exstyle |= WS_EX_CONTROLPARENT; } - case WM_CREATE: +#endif // __WXUNIVERSAL__ + } + + return style; +} + +// Setup background and foreground colours correctly +void wxWindowMSW::SetupColours() +{ + if ( GetParent() ) + SetBackgroundColour(GetParent()->GetBackgroundColour()); +} + +bool wxWindowMSW::IsMouseInWindow() const +{ + // get the mouse position + POINT pt; +#ifdef __WXWINCE__ + ::GetCursorPosWinCE(&pt); +#else + ::GetCursorPos(&pt); +#endif + + // find the window which currently has the cursor and go up the window + // chain until we find this window - or exhaust it + HWND hwnd = ::WindowFromPoint(pt); + while ( hwnd && (hwnd != GetHwnd()) ) + hwnd = ::GetParent(hwnd); + + return hwnd != NULL; +} + +void wxWindowMSW::OnInternalIdle() +{ +#ifndef HAVE_TRACKMOUSEEVENT + // Check if we need to send a LEAVE event + if ( m_mouseInWindow ) + { + // note that we should generate the leave event whether the window has + // or doesn't have mouse capture + if ( !IsMouseInWindow() ) { - MSWOnCreate((WXLPCREATESTRUCT) (LPCREATESTRUCT)lParam); - return 0; - break; + GenerateMouseLeave(); } - case WM_SHOWWINDOW: + } +#endif // !HAVE_TRACKMOUSEEVENT + + if (wxUpdateUIEvent::CanUpdate(this)) + UpdateWindowUI(wxUPDATE_UI_FROMIDLE); +} + +// Set this window to be the child of 'parent'. +bool wxWindowMSW::Reparent(wxWindowBase *parent) +{ + if ( !wxWindowBase::Reparent(parent) ) + return false; + + HWND hWndChild = GetHwnd(); + HWND hWndParent = GetParent() ? GetWinHwnd(GetParent()) : (HWND)0; + + ::SetParent(hWndChild, hWndParent); + +#ifndef __WXWINCE__ + if ( ::GetWindowLong(hWndChild, GWL_EXSTYLE) & WS_EX_CONTROLPARENT ) + { + EnsureParentHasControlParentStyle(GetParent()); + } +#endif // !__WXWINCE__ + + return true; +} + +static inline void SendSetRedraw(HWND hwnd, bool on) +{ +#ifndef __WXMICROWIN__ + ::SendMessage(hwnd, WM_SETREDRAW, (WPARAM)on, 0); +#endif +} + +void wxWindowMSW::Freeze() +{ + if ( !m_frozenness++ ) + { + if ( IsShown() ) + SendSetRedraw(GetHwnd(), false); + } +} + +void wxWindowMSW::Thaw() +{ + wxASSERT_MSG( m_frozenness > 0, _T("Thaw() without matching Freeze()") ); + + if ( --m_frozenness == 0 ) + { + if ( IsShown() ) { - MSWOnShow((wParam != 0), (int) lParam); - break; + SendSetRedraw(GetHwnd(), true); + + // we need to refresh everything or otherwise the invalidated area + // is not going to be repainted + Refresh(); } - case WM_PAINT: + } +} + +void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect) +{ + HWND hWnd = GetHwnd(); + if ( hWnd ) + { + RECT mswRect; + const RECT *pRect; + if ( rect ) { - if (MSWOnPaint()) - return 0; - else return MSWDefWindowProc(message, wParam, lParam ); - break; + mswRect.left = rect->x; + mswRect.top = rect->y; + mswRect.right = rect->x + rect->width; + mswRect.bottom = rect->y + rect->height; + + pRect = &mswRect; } - case WM_QUERYDRAGICON: + else { - HICON hIcon = (HICON)MSWOnQueryDragIcon(); - if ( hIcon ) - return (long)hIcon; - else - return MSWDefWindowProc(message, wParam, lParam ); - break; + pRect = NULL; } - case WM_SIZE: - { - int width = LOWORD(lParam); - int height = HIWORD(lParam); - MSWOnSize(width, height, wParam); - break; - } + // RedrawWindow not available on SmartPhone or eVC++ 3 +#if !defined(__SMARTPHONE__) && !(defined(_WIN32_WCE) && _WIN32_WCE < 400) + UINT flags = RDW_INVALIDATE | RDW_ALLCHILDREN; + if ( eraseBack ) + flags |= RDW_ERASE; - case WM_MOVE: - { - wxMoveEvent event(wxPoint(LOWORD(lParam), HIWORD(lParam)), - m_windowId); - event.SetEventObject(this); - if ( !GetEventHandler()->ProcessEvent(event) ) - Default(); - } - break; + ::RedrawWindow(hWnd, pRect, NULL, flags); +#else + ::InvalidateRect(hWnd, pRect, eraseBack); +#endif + } +} - case WM_WINDOWPOSCHANGING: - { - MSWOnWindowPosChanging((void *)lParam); - break; - } +void wxWindowMSW::Update() +{ + if ( !::UpdateWindow(GetHwnd()) ) + { + wxLogLastError(_T("UpdateWindow")); + } - case WM_RBUTTONDOWN: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnRButtonDown(x, y, wParam); - break; - } - case WM_RBUTTONUP: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnRButtonUp(x, y, wParam); - break; - } - case WM_RBUTTONDBLCLK: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnRButtonDClick(x, y, wParam); - break; - } - case WM_MBUTTONDOWN: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnMButtonDown(x, y, wParam); - break; - } - case WM_MBUTTONUP: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnMButtonUp(x, y, wParam); - break; - } - case WM_MBUTTONDBLCLK: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnMButtonDClick(x, y, wParam); - break; - } - case WM_LBUTTONDOWN: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnLButtonDown(x, y, wParam); - break; - } - case WM_LBUTTONUP: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnLButtonUp(x, y, wParam); - break; - } - case WM_LBUTTONDBLCLK: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnLButtonDClick(x, y, wParam); - break; - } - case WM_MOUSEMOVE: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnMouseMove(x, y, wParam); - break; - } - case MM_JOY1BUTTONDOWN: +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) + // just calling UpdateWindow() is not enough, what we did in our WM_PAINT + // handler needs to be really drawn right now + (void)::GdiFlush(); +#endif // __WIN32__ +} + +// --------------------------------------------------------------------------- +// 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 void AdjustStaticBoxZOrder(wxWindow *parent) +{ + // no sibling static boxes if we have no parent (ie TLW) + if ( !parent ) + return; + + for ( wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxStaticBox *statbox = wxDynamicCast(node->GetData(), wxStaticBox); + if ( statbox ) { - int x = LOWORD(lParam); - int y = HIWORD(lParam); - MSWOnJoyDown(wxJOYSTICK1, x, y, wParam); - break; + ::SetWindowPos(GetHwndOf(statbox), HWND_BOTTOM, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); } - case MM_JOY2BUTTONDOWN: + } +} + +#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 ( m_dropTarget != 0 ) { + m_dropTarget->Revoke(m_hWnd); + delete m_dropTarget; + } + + m_dropTarget = pDropTarget; + if ( m_dropTarget != 0 ) + { + AdjustStaticBoxZOrder(GetParent()); + m_dropTarget->Register(m_hWnd); + } +} +#endif // wxUSE_DRAG_AND_DROP + +// old-style file manager drag&drop support: we retain the old-style +// DragAcceptFiles in parallel with SetDropTarget. +void wxWindowMSW::DragAcceptFiles(bool WXUNUSED_IN_WINCE(accept)) +{ +#ifndef __WXWINCE__ + HWND hWnd = GetHwnd(); + if ( hWnd ) + { + AdjustStaticBoxZOrder(GetParent()); + ::DragAcceptFiles(hWnd, (BOOL)accept); + } +#endif +} + +// ---------------------------------------------------------------------------- +// tooltips +// ---------------------------------------------------------------------------- + +#if wxUSE_TOOLTIPS + +void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip) +{ + wxWindowBase::DoSetToolTip(tooltip); + + if ( m_tooltip ) + m_tooltip->SetWindow((wxWindow *)this); +} + +#endif // wxUSE_TOOLTIPS + +// --------------------------------------------------------------------------- +// moving and resizing +// --------------------------------------------------------------------------- + +bool wxWindowMSW::IsSizeDeferred() const +{ +#if USE_DEFERRED_SIZING + if ( m_pendingPosition != wxDefaultPosition || + m_pendingSize != wxDefaultSize ) + return true; +#endif // USE_DEFERRED_SIZING + + return false; +} + +// Get total size +void wxWindowMSW::DoGetSize(int *x, int *y) const +{ +#if USE_DEFERRED_SIZING + // if SetSize() had been called at wx level but not realized at Windows + // level yet (i.e. EndDeferWindowPos() not called), we still should return + // the new and not the old position to the other wx code + if ( m_pendingSize != wxDefaultSize ) + { + if ( x ) + *x = m_pendingSize.x; + if ( y ) + *y = m_pendingSize.y; + } + else // use current size +#endif // USE_DEFERRED_SIZING + { + RECT rect = wxGetWindowRect(GetHwnd()); + + if ( x ) + *x = rect.right - rect.left; + if ( y ) + *y = rect.bottom - rect.top; + } +} + +// Get size *available for subwindows* i.e. excluding menu bar etc. +void wxWindowMSW::DoGetClientSize(int *x, int *y) const +{ +#if USE_DEFERRED_SIZING + if ( m_pendingSize != wxDefaultSize ) + { + // we need to calculate the client size corresponding to pending size + RECT rect; + rect.left = m_pendingPosition.x; + rect.top = m_pendingPosition.y; + rect.right = rect.left + m_pendingSize.x; + rect.bottom = rect.top + m_pendingSize.y; + + ::SendMessage(GetHwnd(), WM_NCCALCSIZE, FALSE, (LPARAM)&rect); + + if ( x ) + *x = rect.right - rect.left; + if ( y ) + *y = rect.bottom - rect.top; + } + else +#endif // USE_DEFERRED_SIZING + { + RECT rect = wxGetClientRect(GetHwnd()); + + if ( x ) + *x = rect.right; + if ( y ) + *y = rect.bottom; + } +} + +void wxWindowMSW::DoGetPosition(int *x, int *y) const +{ + wxWindow * const parent = GetParent(); + + wxPoint pos; + if ( m_pendingPosition != wxDefaultPosition ) + { + pos = m_pendingPosition; + } + else // use current position + { + RECT rect = wxGetWindowRect(GetHwnd()); + + POINT point; + point.x = rect.left; + point.y = rect.top; + + // we do the adjustments with respect to the parent only for the "real" + // children, not for the dialogs/frames + if ( !IsTopLevel() ) { - int x = LOWORD(lParam); - int y = HIWORD(lParam); - MSWOnJoyDown(wxJOYSTICK2, x, y, wParam); - break; + if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ) + { + // In RTL mode, we want the logical left x-coordinate, + // which would be the physical right x-coordinate. + point.x = rect.right; + } + + // Since we now have the absolute screen coords, if there's a + // parent we must subtract its top left corner + if ( parent ) + { + ::ScreenToClient(GetHwndOf(parent), &point); + } } - case MM_JOY1BUTTONUP: + + pos.x = point.x; + pos.y = point.y; + } + + // we also must adjust by the client area offset: a control which is just + // under a toolbar could be at (0, 30) in Windows but at (0, 0) in wx + if ( parent && !IsTopLevel() ) + { + const wxPoint pt(parent->GetClientAreaOrigin()); + pos.x -= pt.x; + pos.y -= pt.y; + } + + if ( x ) + *x = pos.x; + if ( y ) + *y = pos.y; +} + +void wxWindowMSW::DoScreenToClient(int *x, int *y) const +{ + POINT pt; + if ( x ) + pt.x = *x; + if ( y ) + pt.y = *y; + + ::ScreenToClient(GetHwnd(), &pt); + + if ( x ) + *x = pt.x; + if ( y ) + *y = pt.y; +} + +void wxWindowMSW::DoClientToScreen(int *x, int *y) const +{ + POINT pt; + if ( x ) + pt.x = *x; + if ( y ) + pt.y = *y; + + ::ClientToScreen(GetHwnd(), &pt); + + if ( x ) + *x = pt.x; + if ( y ) + *y = pt.y; +} + +bool +wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height) +{ +#if USE_DEFERRED_SIZING + // if our parent had prepared a defer window handle for us, use it (unless + // we are a top level window) + wxWindowMSW * const parent = IsTopLevel() ? NULL : GetParent(); + + HDWP hdwp = parent ? (HDWP)parent->m_hDWP : NULL; + if ( hdwp ) + { + hdwp = ::DeferWindowPos(hdwp, (HWND)hwnd, NULL, x, y, width, height, + SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE); + if ( !hdwp ) { - int x = LOWORD(lParam); - int y = HIWORD(lParam); - MSWOnJoyUp(wxJOYSTICK1, x, y, wParam); - break; + wxLogLastError(_T("DeferWindowPos")); } - case MM_JOY2BUTTONUP: + } + + if ( parent ) + { + // hdwp must be updated as it may have been changed + parent->m_hDWP = (WXHANDLE)hdwp; + } + + if ( hdwp ) + { + // did deferred move, remember new coordinates of the window as they're + // different from what Windows would return for it + return true; + } + + // otherwise (or if deferring failed) move the window in place immediately +#endif // USE_DEFERRED_SIZING + if ( !::MoveWindow((HWND)hwnd, x, y, width, height, IsShown()) ) + { + wxLogLastError(wxT("MoveWindow")); + } + + // if USE_DEFERRED_SIZING, indicates that we didn't use deferred move, + // ignored otherwise + return false; +} + +void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height) +{ + // TODO: is this consistent with other platforms? + // Still, negative width or height shouldn't be allowed + if (width < 0) + width = 0; + if (height < 0) + height = 0; + + if ( DoMoveSibling(m_hWnd, x, y, width, height) ) + { +#if USE_DEFERRED_SIZING + m_pendingPosition = wxPoint(x, y); + m_pendingSize = wxSize(width, height); +#endif // USE_DEFERRED_SIZING + } +} + +// 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 wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) +{ + // get the current size and position... + int currentX, currentY; + int currentW, currentH; + + GetPosition(¤tX, ¤tY); + GetSize(¤tW, ¤tH); + + // ... and don't do anything (avoiding flicker) if it's already ok unless + // we're forced to resize the window + if ( x == currentX && y == currentY && + width == currentW && height == currentH && + !(sizeFlags & wxSIZE_FORCE) ) + { + return; + } + + if ( x == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) + x = currentX; + if ( y == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) + y = currentY; + + AdjustForParentClientOrigin(x, y, sizeFlags); + + wxSize size = wxDefaultSize; + if ( width == wxDefaultCoord ) + { + if ( sizeFlags & wxSIZE_AUTO_WIDTH ) { - int x = LOWORD(lParam); - int y = HIWORD(lParam); - MSWOnJoyUp(wxJOYSTICK2, x, y, wParam); - break; + size = DoGetBestSize(); + width = size.x; } - case MM_JOY1MOVE: + else { - int x = LOWORD(lParam); - int y = HIWORD(lParam); - MSWOnJoyMove(wxJOYSTICK1, x, y, wParam); - break; + // just take the current one + width = currentW; } - case MM_JOY2MOVE: + } + + if ( height == wxDefaultCoord ) + { + if ( sizeFlags & wxSIZE_AUTO_HEIGHT ) { - int x = LOWORD(lParam); - int y = HIWORD(lParam); - MSWOnJoyMove(wxJOYSTICK2, x, y, wParam); - break; + if ( size.x == wxDefaultCoord ) + { + size = DoGetBestSize(); + } + //else: already called DoGetBestSize() above + + height = size.y; } - case MM_JOY1ZMOVE: + else { - int z = LOWORD(lParam); - MSWOnJoyZMove(wxJOYSTICK1, z, wParam); - break; + // just take the current one + height = currentH; } - case MM_JOY2ZMOVE: + } + + DoMoveWindow(x, y, width, height); +} + +void wxWindowMSW::DoSetClientSize(int width, int height) +{ + // setting the client size is less obvious than it could have been + // because in the result of changing the total size the window scrollbar + // may [dis]appear and/or its menubar may [un]wrap (and AdjustWindowRect() + // doesn't take neither into account) and so the client size will not be + // correct as the difference between the total and client size changes -- + // so we keep changing it until we get it right + // + // normally this loop shouldn't take more than 3 iterations (usually 1 but + // if scrollbars [dis]appear as the result of the first call, then 2 and it + // may become 3 if the window had 0 size originally and so we didn't + // calculate the scrollbar correction correctly during the first iteration) + // but just to be on the safe side we check for it instead of making it an + // "infinite" loop (i.e. leaving break inside as the only way to get out) + for ( int i = 0; i < 4; i++ ) + { + RECT rectClient; + ::GetClientRect(GetHwnd(), &rectClient); + + // if the size is already ok, stop here (NB: rectClient.left = top = 0) + if ( (rectClient.right == width || width == wxDefaultCoord) && + (rectClient.bottom == height || height == wxDefaultCoord) ) { - int z = LOWORD(lParam); - MSWOnJoyZMove(wxJOYSTICK2, z, wParam); break; } - case WM_DESTROY: + + // Find the difference between the entire window (title bar and all) + // and the client area; add this to the new client size to move the + // window + RECT rectWin; + ::GetWindowRect(GetHwnd(), &rectWin); + + const int widthWin = rectWin.right - rectWin.left, + heightWin = rectWin.bottom - rectWin.top; + + // MoveWindow positions the child windows relative to the parent, so + // adjust if necessary + if ( !IsTopLevel() ) { - if (MSWOnDestroy()) - return 0; - else return MSWDefWindowProc(message, wParam, lParam ); - break; + wxWindow *parent = GetParent(); + if ( parent ) + { + ::ScreenToClient(GetHwndOf(parent), (POINT *)&rectWin); + } } - case WM_SYSCOMMAND: + + // don't call DoMoveWindow() because we want to move window immediately + // and not defer it here as otherwise the value returned by + // GetClient/WindowRect() wouldn't change as the window wouldn't be + // really resized + if ( !::MoveWindow(GetHwnd(), + rectWin.left, + rectWin.top, + width + widthWin - rectClient.right, + height + heightWin - rectClient.bottom, + TRUE) ) { - return MSWOnSysCommand(wParam, lParam); - break; + wxLogLastError(_T("MoveWindow")); } - case WM_COMMAND: - { -#ifdef __WIN32__ - WORD id = LOWORD(wParam); - HWND hwnd = (HWND)lParam; - WORD cmd = HIWORD(wParam); + } +} + +// --------------------------------------------------------------------------- +// text metrics +// --------------------------------------------------------------------------- + +int wxWindowMSW::GetCharHeight() const +{ + return wxGetTextMetrics(this).tmHeight; +} + +int wxWindowMSW::GetCharWidth() const +{ + // +1 is needed because Windows apparently adds it when calculating the + // dialog units size in pixels +#if wxDIALOG_UNIT_COMPATIBILITY + return wxGetTextMetrics(this).tmAveCharWidth; #else - WORD id = (WORD)wParam; - HWND hwnd = (HWND)LOWORD(lParam) ; - WORD cmd = HIWORD(lParam); + return wxGetTextMetrics(this).tmAveCharWidth + 1; #endif - if (!MSWOnCommand(id, cmd, (WXHWND) hwnd)) - return MSWDefWindowProc(message, wParam, lParam ); - break; - } -#if defined(__WIN95__) - case WM_NOTIFY: +} + +void wxWindowMSW::GetTextExtent(const wxString& string, + int *x, int *y, + int *descent, int *externalLeading, + const wxFont *theFont) const +{ + wxASSERT_MSG( !theFont || theFont->Ok(), + _T("invalid font in GetTextExtent()") ); + + wxFont fontToUse; + if (theFont) + fontToUse = *theFont; + else + fontToUse = GetFont(); + + WindowHDC hdc(GetHwnd()); + SelectInHDC selectFont(hdc, GetHfontOf(fontToUse)); + + SIZE sizeRect; + TEXTMETRIC tm; + ::GetTextExtentPoint32(hdc, string, string.length(), &sizeRect); + GetTextMetrics(hdc, &tm); + + if ( x ) + *x = sizeRect.cx; + if ( y ) + *y = sizeRect.cy; + if ( descent ) + *descent = tm.tmDescent; + if ( externalLeading ) + *externalLeading = tm.tmExternalLeading; +} + +// --------------------------------------------------------------------------- +// popup menu +// --------------------------------------------------------------------------- + +#if wxUSE_MENUS_NATIVE + +// yield for WM_COMMAND events only, i.e. process all WM_COMMANDs in the queue +// immediately, without waiting for the next event loop iteration +// +// NB: this function should probably be made public later as it can almost +// surely replace wxYield() elsewhere as well +static void wxYieldForCommandsOnly() +{ + // peek all WM_COMMANDs (it will always return WM_QUIT too but we don't + // want to process it here) + MSG msg; + while ( ::PeekMessage(&msg, (HWND)0, WM_COMMAND, WM_COMMAND, PM_REMOVE) ) + { + if ( msg.message == WM_QUIT ) { - // for some messages (TVN_ITEMEXPANDING for example), the return - // value of WM_NOTIFY handler is important, so don't just return 0 - // if we processed the message - return MSWOnNotify(wParam, lParam); + // if we retrieved a WM_QUIT, insert back into the message queue. + ::PostQuitMessage(0); + break; } -#endif - case WM_MENUSELECT: - { -#ifdef __WIN32__ - WORD flags = HIWORD(wParam); - HMENU sysmenu = (HMENU)lParam; + + // luckily (as we don't have access to wxEventLoopImpl method from here + // anyhow...) we don't need to pre process WM_COMMANDs so dispatch it + // immediately + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } +} + +bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y) +{ + menu->SetInvokingWindow(this); + menu->UpdateUI(); + + if ( x == wxDefaultCoord && y == wxDefaultCoord ) + { + wxPoint mouse = ScreenToClient(wxGetMousePosition()); + x = mouse.x; y = mouse.y; + } + + HWND hWnd = GetHwnd(); + HMENU hMenu = GetHmenuOf(menu); + POINT point; + point.x = x; + point.y = y; + ::ClientToScreen(hWnd, &point); + wxCurrentPopupMenu = menu; +#if defined(__WXWINCE__) + UINT flags = 0; #else - WORD flags = LOWORD(lParam); - HMENU sysmenu = (HMENU)HIWORD(lParam); + UINT flags = TPM_RIGHTBUTTON | TPM_RECURSE; #endif - MSWOnMenuHighlight((WORD)wParam, flags, (WXHMENU) sysmenu); - break; - } - case WM_INITMENUPOPUP: - { - MSWOnInitMenuPopup((WXHMENU) (HMENU)wParam, (int)LOWORD(lParam), (HIWORD(lParam) != 0)); - break; - } - case WM_DRAWITEM: - { - return MSWOnDrawItem((int)wParam, (WXDRAWITEMSTRUCT *)lParam); - break; - } - case WM_MEASUREITEM: + ::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 + // sent to wxCurrentPopupMenu from HandleCommand() + // + // note that even eliminating (ugly) wxCurrentPopupMenu global wouldn't + // help and we'd still need wxYieldForCommandsOnly() as the menu may be + // destroyed as soon as we return (it can be a local variable in the caller + // for example) and so we do need to process the event immediately + wxYieldForCommandsOnly(); + + wxCurrentPopupMenu = NULL; + + menu->SetInvokingWindow(NULL); + + return true; +} + +#endif // wxUSE_MENUS_NATIVE + +// =========================================================================== +// pre/post message processing +// =========================================================================== + +WXLRESULT wxWindowMSW::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +{ + if ( m_oldWndProc ) + return ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam); + else + return ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam); +} + +bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) +{ + // wxUniversal implements tab traversal itself +#ifndef __WXUNIVERSAL__ + if ( m_hWnd != 0 && (GetWindowStyleFlag() & wxTAB_TRAVERSAL) ) + { + // intercept dialog navigation keys + MSG *msg = (MSG *)pMsg; + + // here we try to do all the job which ::IsDialogMessage() usually does + // internally + if ( msg->message == WM_KEYDOWN ) { - return MSWOnMeasureItem((int)wParam, (WXMEASUREITEMSTRUCT *)lParam); - break; + bool bCtrlDown = wxIsCtrlDown(); + bool bShiftDown = wxIsShiftDown(); + + // 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 + // combinations which are always processed) + LONG lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0); + + // surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the + // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically, + // it, of course, implies them + if ( lDlgCode & DLGC_WANTALLKEYS ) + { + lDlgCode |= DLGC_WANTTAB | DLGC_WANTARROWS; + } + + bool bForward = true, + bWindowChange = false, + bFromTab = false; + + // should we process this message specially? + bool bProcess = true; + switch ( msg->wParam ) + { + case VK_TAB: + if ( lDlgCode & DLGC_WANTTAB ) { + bProcess = false; + } + else { + // Ctrl-Tab cycles thru notebook pages + bWindowChange = bCtrlDown; + bForward = !bShiftDown; + bFromTab = true; + } + break; + + case VK_UP: + case VK_LEFT: + if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown ) + bProcess = false; + else + bForward = false; + break; + + case VK_DOWN: + case VK_RIGHT: + if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown ) + bProcess = false; + break; + + case VK_PRIOR: + bForward = false; + // fall through + + case VK_NEXT: + // 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 ) + bProcess = false; + else + bWindowChange = true; + break; + + 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 + // this window is a button first + wxWindow *btn = NULL; + if ( lDlgCode & DLGC_DEFPUSHBUTTON ) + { + // let IsDialogMessage() handle this for all + // buttons except the owner-drawn ones which it + // just seems to ignore + long style = ::GetWindowLong(msg->hwnd, GWL_STYLE); + if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW ) + { + // emulate the button click + btn = wxFindWinFromHandle((WXHWND)msg->hwnd); + } + + bProcess = false; + } + else // not a button itself, do we have default button? + { + wxTopLevelWindow * + tlw = wxDynamicCast(wxGetTopLevelParent(this), + wxTopLevelWindow); + if ( tlw ) + { + btn = wxDynamicCast(tlw->GetDefaultItem(), + wxButton); + } + } + + if ( btn && btn->IsEnabled() ) + { + btn->MSWCommand(BN_CLICKED, 0 /* unused */); + return true; + } + +#endif // wxUSE_BUTTON + +#ifdef __WXWINCE__ + // map Enter presses into button presses on PDAs + wxJoystickEvent event(wxEVT_JOY_BUTTON_DOWN); + event.SetEventObject(this); + if ( GetEventHandler()->ProcessEvent(event) ) + return true; +#endif // __WXWINCE__ + } + break; + + default: + bProcess = false; + } + + if ( bProcess ) + { + wxNavigationKeyEvent event; + event.SetDirection(bForward); + event.SetWindowChange(bWindowChange); + event.SetFromTab(bFromTab); + event.SetEventObject(this); + + if ( GetEventHandler()->ProcessEvent(event) ) + { + // as we don't call IsDialogMessage(), which would take of + // this by default, we need to manually send this message + // so that controls can change their UI state if needed + MSWUpdateUIState(UIS_CLEAR, UISF_HIDEFOCUS); + + return true; + } + } } - case WM_KEYDOWN: - // If this has been processed by an event handler, - // return 0 now (we've handled it). - if (MSWOnKeyDown((WORD) wParam, lParam)) + if ( ::IsDialogMessage(GetHwnd(), msg) ) { - return 0; + // IsDialogMessage() did something... + return true; } + } +#endif // __WXUNIVERSAL__ + +#if wxUSE_TOOLTIPS + if ( m_tooltip ) + { + // relay mouse move events to the tooltip control + MSG *msg = (MSG *)pMsg; + if ( msg->message == WM_MOUSEMOVE ) + wxToolTip::RelayEvent(pMsg); + } +#endif // wxUSE_TOOLTIPS + + return false; +} - // we consider these message "not interesting" to OnChar - if ( wParam == VK_SHIFT || wParam == VK_CONTROL ) +bool wxWindowMSW::MSWTranslateMessage(WXMSG* pMsg) +{ +#if wxUSE_ACCEL && !defined(__WXUNIVERSAL__) + return m_acceleratorTable.Translate(this, pMsg); +#else + (void) pMsg; + return false; +#endif // wxUSE_ACCEL +} + +bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* msg) +{ + // all tests below have to deal with various bugs/misfeatures of + // IsDialogMessage(): we have to prevent it from being called from our + // MSWProcessMessage() in some situations + + // don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the + // message even when there is no cancel button and when the message is + // needed by the control itself: in particular, it prevents the tree in + // place edit control from being closed with Escape in a dialog + if ( msg->message == WM_KEYDOWN && msg->wParam == VK_ESCAPE ) + { + return false; + } + + // ::IsDialogMessage() is broken and may sometimes hang the application by + // going into an infinite loop when it tries to find the control to give + // focus to when Alt- is pressed, so we try to detect [some of] the + // situations when this may happen and not call it then + if ( msg->message != WM_SYSCHAR ) + return true; + + // assume we can call it by default + bool canSafelyCallIsDlgMsg = true; + + HWND hwndFocus = ::GetFocus(); + + // if the currently focused window itself has WS_EX_CONTROLPARENT style, + // ::IsDialogMessage() will also enter an infinite loop, because it will + // recursively check the child windows but not the window itself and so if + // none of the children accepts focus it loops forever (as it only stops + // when it gets back to the window it started from) + // + // while it is very unusual that a window with WS_EX_CONTROLPARENT + // style has the focus, it can happen. One such possibility is if + // all windows are either toplevel, wxDialog, wxPanel or static + // controls and no window can actually accept keyboard input. +#if !defined(__WXWINCE__) + if ( ::GetWindowLong(hwndFocus, GWL_EXSTYLE) & WS_EX_CONTROLPARENT ) + { + // pessimistic by default + canSafelyCallIsDlgMsg = false; + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) { - return Default(); + wxWindow * const win = node->GetData(); + if ( win->AcceptsFocus() && + !(::GetWindowLong(GetHwndOf(win), GWL_EXSTYLE) & + WS_EX_CONTROLPARENT) ) + { + // it shouldn't hang... + canSafelyCallIsDlgMsg = true; + + break; + } } + } +#endif // !__WXWINCE__ - // Avoid duplicate messages to OnChar for these special keys - switch ( wParam ) + if ( canSafelyCallIsDlgMsg ) + { + // ::IsDialogMessage() can enter in an infinite loop when the + // currently focused window is disabled or hidden and its + // parent has WS_EX_CONTROLPARENT style, so don't call it in + // this case + while ( hwndFocus ) { - case VK_ESCAPE: - case VK_SPACE: - case VK_RETURN: - case VK_BACK: - case VK_TAB: - case VK_LEFT: - case VK_RIGHT: - case VK_DOWN: - case VK_UP: - return Default(); + if ( !::IsWindowEnabled(hwndFocus) || + !::IsWindowVisible(hwndFocus) ) + { + // it would enter an infinite loop if we do this! + canSafelyCallIsDlgMsg = false; -#ifdef VK_APPS - // special case of VK_APPS: treat it the same as right mouse 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); - MSWOnRButtonDown(x, y, fwKeys); - } break; -#endif // VK_APPS + } - default: - if (!MSWOnChar((WORD)wParam, lParam)) - { - return Default(); - } + if ( !(::GetWindowLong(hwndFocus, GWL_STYLE) & WS_CHILD) ) + { + // it's a top level window, don't go further -- e.g. even + // if the parent of a dialog is disabled, this doesn't + // break navigation inside the dialog break; + } + + hwndFocus = ::GetParent(hwndFocus); } + } - break; + return canSafelyCallIsDlgMsg; +} + +// --------------------------------------------------------------------------- +// message params unpackers +// --------------------------------------------------------------------------- + +void wxWindowMSW::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam, + WORD *id, WXHWND *hwnd, WORD *cmd) +{ + *id = LOWORD(wParam); + *hwnd = (WXHWND)lParam; + *cmd = HIWORD(wParam); +} + +void wxWindowMSW::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam, + WXWORD *state, WXWORD *minimized, WXHWND *hwnd) +{ + *state = LOWORD(wParam); + *minimized = HIWORD(wParam); + *hwnd = (WXHWND)lParam; +} + +void wxWindowMSW::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam, + WXWORD *code, WXWORD *pos, WXHWND *hwnd) +{ + *code = LOWORD(wParam); + *pos = HIWORD(wParam); + *hwnd = (WXHWND)lParam; +} + +void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam, + WXHDC *hdc, WXHWND *hwnd) +{ + *hwnd = (WXHWND)lParam; + *hdc = (WXHDC)wParam; +} + +void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, + WXWORD *item, WXWORD *flags, WXHMENU *hmenu) +{ + *item = (WXWORD)wParam; + *flags = HIWORD(wParam); + *hmenu = (WXHMENU)lParam; +} + +// --------------------------------------------------------------------------- +// Main wxWidgets window proc and the window proc for wxWindow +// --------------------------------------------------------------------------- + +// Hook for new window just as it's being created, when the window isn't yet +// associated with the handle +static wxWindowMSW *gs_winBeingCreated = NULL; + +// implementation of wxWindowCreationHook class: it just sets gs_winBeingCreated to the +// window being created and insures that it's always unset back later +wxWindowCreationHook::wxWindowCreationHook(wxWindowMSW *winBeingCreated) +{ + gs_winBeingCreated = winBeingCreated; +} + +wxWindowCreationHook::~wxWindowCreationHook() +{ + gs_winBeingCreated = NULL; +} - case WM_KEYUP: +// Main window proc +LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + // trace all messages - useful for the debugging +#ifdef __WXDEBUG__ + wxLogTrace(wxTraceMessages, + wxT("Processing %s(hWnd=%08lx, wParam=%8lx, lParam=%8lx)"), + wxGetMessageName(message), (long)hWnd, (long)wParam, lParam); +#endif // __WXDEBUG__ + + wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd); + + // when we get the first message for the HWND we just created, we associate + // it with wxWindow stored in gs_winBeingCreated + if ( !wnd && gs_winBeingCreated ) { - if (!MSWOnKeyUp((WORD) wParam, lParam)) - return Default(); - break; + wxAssociateWinWithHandle(hWnd, gs_winBeingCreated); + wnd = gs_winBeingCreated; + gs_winBeingCreated = NULL; + wnd->SetHWND((WXHWND)hWnd); } - case WM_CHAR: // Always an ASCII character - { - if (!MSWOnChar((WORD)wParam, lParam, TRUE)) - return Default(); - break; - } - case WM_HSCROLL: - { -#ifdef __WIN32__ - WORD code = LOWORD(wParam); - WORD pos = HIWORD(wParam); - HWND control = (HWND)lParam; -#else - WORD code = (WORD)wParam; - WORD pos = LOWORD(lParam); - HWND control = (HWND)HIWORD(lParam); -#endif - MSWOnHScroll(code, pos, (WXHWND) control); - break; - } - case WM_VSCROLL: - { -#ifdef __WIN32__ - WORD code = LOWORD(wParam); - WORD pos = HIWORD(wParam); - HWND control = (HWND)lParam; -#else - WORD code = (WORD)wParam; - WORD pos = LOWORD(lParam); - HWND control = (HWND)HIWORD(lParam); -#endif - MSWOnVScroll(code, pos, (WXHWND) control); - break; - } -#ifdef __WIN32__ - case WM_CTLCOLORBTN: - { - int nCtlColor = CTLCOLOR_BTN; - HWND control = (HWND)lParam; - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam); + LRESULT rc; + + if ( wnd && wxEventLoop::AllowProcessing(wnd) ) + rc = wnd->MSWWindowProc(message, wParam, lParam); + else + rc = ::DefWindowProc(hWnd, message, wParam, lParam); + + return rc; +} + +WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) +{ + // did we process the message? + bool processed = false; + + // the return value + union + { + bool allow; + WXLRESULT result; + WXHBRUSH hBrush; + } rc; + + // for most messages we should return 0 when we do process the message + rc.result = 0; + + switch ( message ) + { + case WM_CREATE: + { + bool mayCreate; + processed = HandleCreate((WXLPCREATESTRUCT)lParam, &mayCreate); + if ( processed ) + { + // return 0 to allow window creation + rc.result = mayCreate ? 0 : -1; + } + } break; - } - case WM_CTLCOLORDLG: - { - int nCtlColor = CTLCOLOR_DLG; - HWND control = (HWND)lParam; - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam);\ - break; - } - case WM_CTLCOLORLISTBOX: - { - int nCtlColor = CTLCOLOR_LISTBOX; - HWND control = (HWND)lParam; - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam); + + case WM_DESTROY: + // never set processed to true and *always* pass WM_DESTROY to + // DefWindowProc() as Windows may do some internal cleanup when + // processing it and failing to pass the message along may cause + // memory and resource leaks! + (void)HandleDestroy(); break; - } - case WM_CTLCOLORMSGBOX: - { - int nCtlColor = CTLCOLOR_MSGBOX; - HWND control = (HWND)lParam; - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam); + + case WM_SIZE: + processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam); break; - } - case WM_CTLCOLORSCROLLBAR: - { - int nCtlColor = CTLCOLOR_SCROLLBAR; - HWND control = (HWND)lParam; - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam); + + case WM_MOVE: + processed = HandleMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break; - } - case WM_CTLCOLORSTATIC: - { - int nCtlColor = CTLCOLOR_STATIC; - HWND control = (HWND)lParam; - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam); + +#if !defined(__WXWINCE__) + case WM_MOVING: + { + LPRECT pRect = (LPRECT)lParam; + wxRect rc; + rc.SetLeft(pRect->left); + rc.SetTop(pRect->top); + rc.SetRight(pRect->right); + rc.SetBottom(pRect->bottom); + processed = HandleMoving(rc); + if (processed) { + pRect->left = rc.GetLeft(); + pRect->top = rc.GetTop(); + pRect->right = rc.GetRight(); + pRect->bottom = rc.GetBottom(); + } + } break; - } - case WM_CTLCOLOREDIT: - { - int nCtlColor = CTLCOLOR_EDIT; - HWND control = (HWND)lParam; - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam); + + case WM_SIZING: + { + LPRECT pRect = (LPRECT)lParam; + wxRect rc; + rc.SetLeft(pRect->left); + rc.SetTop(pRect->top); + rc.SetRight(pRect->right); + rc.SetBottom(pRect->bottom); + processed = HandleSizing(rc); + if (processed) { + pRect->left = rc.GetLeft(); + pRect->top = rc.GetTop(); + pRect->right = rc.GetRight(); + pRect->bottom = rc.GetBottom(); + } + } break; - } -#else - case WM_CTLCOLOR: - { - HWND control = (HWND)LOWORD(lParam); - int nCtlColor = (int)HIWORD(lParam); - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam); +#endif // !__WXWINCE__ + +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) + case WM_ACTIVATEAPP: + // This implicitly sends a wxEVT_ACTIVATE_APP event + wxTheApp->SetActive(wParam != 0, FindFocus()); break; - } #endif - case WM_SYSCOLORCHANGE: - { - // Return value of 0 means, we processed it. - if (MSWOnColorChange((WXHWND) hWnd, message, wParam, lParam) == 0) - return 0; - else - return MSWDefWindowProc(message, wParam, lParam ); - break; - } - case WM_PALETTECHANGED: - { - return MSWOnPaletteChanged((WXHWND) (HWND) wParam); + + case WM_ACTIVATE: + { + WXWORD state, minimized; + WXHWND hwnd; + UnpackActivate(wParam, lParam, &state, &minimized, &hwnd); + + processed = HandleActivate(state, minimized != 0, (WXHWND)hwnd); + } break; - } - case WM_QUERYNEWPALETTE: - { - return MSWOnQueryNewPalette(); + + case WM_SETFOCUS: + processed = HandleSetFocus((WXHWND)(HWND)wParam); break; - } - case WM_ERASEBKGND: - { - // Prevents flicker when dragging - if (IsIconic(hWnd)) return 1; - if (!MSWOnEraseBkgnd((WXHDC) (HDC)wParam)) - return 0; // Default(); MSWDefWindowProc(message, wParam, lParam ); - else return 1; + case WM_KILLFOCUS: + processed = HandleKillFocus((WXHWND)(HWND)wParam); break; - } - case WM_MDIACTIVATE: - { -#ifdef __WIN32__ - HWND hWndActivate = GET_WM_MDIACTIVATE_HWNDACTIVATE(wParam,lParam); - HWND hWndDeactivate = GET_WM_MDIACTIVATE_HWNDDEACT(wParam,lParam); - BOOL activate = GET_WM_MDIACTIVATE_FACTIVATE(hWnd,wParam,lParam); - return MSWOnMDIActivate((long) activate, (WXHWND) hWndActivate, (WXHWND) hWndDeactivate); -#else - return MSWOnMDIActivate((BOOL)wParam, (HWND)LOWORD(lParam), - (HWND)HIWORD(lParam)); -#endif - } - case WM_DROPFILES: - { - MSWOnDropFiles(wParam); + + case WM_PRINTCLIENT: + processed = HandlePrintClient((WXHDC)wParam); break; - } - case WM_INITDIALOG: - { - return 0; // MSWOnInitDialog((WXHWND)(HWND)wParam); + + case WM_PAINT: + if ( wParam ) + { + wxPaintDCEx dc((wxWindow *)this, (WXHDC)wParam); + + processed = HandlePaint(); + } + else // no DC given + { + processed = HandlePaint(); + } break; - } - case WM_QUERYENDSESSION: - { - // Same as WM_CLOSE, but inverted results. Thx Microsoft :-) - // return MSWOnClose(); - return MSWOnQueryEndSession(lParam); + case WM_CLOSE: +#ifdef __WXUNIVERSAL__ + // Universal uses its own wxFrame/wxDialog, so we don't receive + // close events unless we have this. + Close(); +#endif // __WXUNIVERSAL__ + + // don't let the DefWindowProc() destroy our window - we'll do it + // ourselves in ~wxWindow + processed = true; + rc.result = TRUE; break; - } - case WM_ENDSESSION: - { - // Same as WM_CLOSE, but inverted results. Thx Microsoft :-) - MSWOnEndSession((wParam != 0), lParam); - return 0L; + + case WM_SHOWWINDOW: + processed = HandleShow(wParam != 0, (int)lParam); break; - } - case WM_CLOSE: - { - if (MSWOnClose()) - return 0L; - else - return 1L; + + case WM_MOUSEMOVE: + processed = HandleMouseMove(GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam), + wParam); break; - } - case WM_GETMINMAXINFO: - { - MINMAXINFO *info = (MINMAXINFO *)lParam; - if (m_minSizeX != -1) - info->ptMinTrackSize.x = (int)m_minSizeX; - if (m_minSizeY != -1) - info->ptMinTrackSize.y = (int)m_minSizeY; - if (m_maxSizeX != -1) - info->ptMaxTrackSize.x = (int)m_maxSizeX; - if (m_maxSizeY != -1) - info->ptMaxTrackSize.y = (int)m_maxSizeY; - return MSWDefWindowProc(message, wParam, lParam ); +#ifdef HAVE_TRACKMOUSEEVENT + case WM_MOUSELEAVE: + // filter out excess WM_MOUSELEAVE events sent after PopupMenu() + // (on XP at least) + if ( m_mouseInWindow ) + { + GenerateMouseLeave(); + } + + // always pass processed back as false, this allows the window + // manager to process the message too. This is needed to + // ensure windows XP themes work properly as the mouse moves + // over widgets like buttons. So don't set processed to true here. break; - } +#endif // HAVE_TRACKMOUSEEVENT - case WM_GETDLGCODE: - return MSWGetDlgCode(); +#if wxUSE_MOUSEWHEEL + case WM_MOUSEWHEEL: + processed = HandleMouseWheel(wParam, lParam); + break; +#endif - case WM_SETCURSOR: - { - // don't set cursor when the mouse is not in the client part - short nHitTest = LOWORD(lParam); - if ( nHitTest == HTCLIENT || nHitTest == HTERROR ) + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MBUTTONDBLCLK: { - HCURSOR hcursor = 0; - if ( wxIsBusy() ) +#ifdef __WXMICROWIN__ + // MicroWindows seems to ignore the fact that a window is + // disabled. So catch mouse events and throw them away if + // necessary. + wxWindowMSW* win = this; + for ( ;; ) { - extern HCURSOR gs_wxBusyCursor; // from msw\utils.cpp + if (!win->IsEnabled()) + { + processed = true; + break; + } + + win = win->GetParent(); + if ( !win || win->IsTopLevel() ) + break; + } + + if ( processed ) + break; + +#endif // __WXMICROWIN__ + int x = GET_X_LPARAM(lParam), + y = GET_Y_LPARAM(lParam); - hcursor = gs_wxBusyCursor; +#ifdef __WXWINCE__ + // redirect the event to a static control if necessary by + // finding one under mouse because under CE the static controls + // don't generate mouse events (even with SS_NOTIFY) + wxWindowMSW *win; + if ( GetCapture() == this ) + { + // but don't do it if the mouse is captured by this window + // because then it should really get this event itself + win = this; } else { - wxCursor *cursor = NULL; + win = FindWindowForMouseEvent(this, &x, &y); + + // this should never happen + wxCHECK_MSG( win, 0, + _T("FindWindowForMouseEvent() returned NULL") ); + } +#ifdef __POCKETPC__ + if (IsContextMenuEnabled() && message == WM_LBUTTONDOWN) + { + SHRGINFO shrgi = {0}; - if ( m_windowCursor.Ok() ) + shrgi.cbSize = sizeof(SHRGINFO); + shrgi.hwndClient = (HWND) GetHWND(); + shrgi.ptDown.x = x; + shrgi.ptDown.y = y; + + shrgi.dwFlags = SHRG_RETURNCMD; + // shrgi.dwFlags = SHRG_NOTIFYPARENT; + + if (GN_CONTEXTMENU == ::SHRecognizeGesture(&shrgi)) { - cursor = &m_windowCursor; + wxPoint pt(x, y); + pt = ClientToScreen(pt); + + wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt); + + evtCtx.SetEventObject(this); + if (GetEventHandler()->ProcessEvent(evtCtx)) + { + processed = true; + return true; + } } - else - { - extern wxCursor *g_globalCursor; // from msw\data.cpp + } +#endif + +#else // !__WXWINCE__ + wxWindowMSW *win = this; +#endif // __WXWINCE__/!__WXWINCE__ + + processed = win->HandleMouseEvent(message, x, y, wParam); - if ( g_globalCursor && g_globalCursor->Ok() ) - cursor = g_globalCursor; + // if the app didn't eat the event, handle it in the default + // way, that is by giving this window the focus + if ( !processed ) + { + // for the standard classes their WndProc sets the focus to + // them anyhow and doing it from here results in some weird + // problems, so don't do it for them (unnecessary anyhow) + if ( !win->IsOfStandardClass() ) + { + if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() ) + win->SetFocus(); } + } + } + break; + +#ifdef MM_JOY1MOVE + case MM_JOY1MOVE: + case MM_JOY2MOVE: + case MM_JOY1ZMOVE: + case MM_JOY2ZMOVE: + case MM_JOY1BUTTONDOWN: + case MM_JOY2BUTTONDOWN: + case MM_JOY1BUTTONUP: + case MM_JOY2BUTTONUP: + processed = HandleJoystickEvent(message, + GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam), + wParam); + break; +#endif // __WXMICROWIN__ + + case WM_COMMAND: + { + WORD id, cmd; + WXHWND hwnd; + UnpackCommand(wParam, lParam, &id, &hwnd, &cmd); + + processed = HandleCommand(id, cmd, hwnd); + } + break; + + case WM_NOTIFY: + processed = HandleNotify((int)wParam, lParam, &rc.result); + break; + + // we only need to reply to WM_NOTIFYFORMAT manually when using MSLU, + // otherwise DefWindowProc() does it perfectly fine for us, but MSLU + // apparently doesn't always behave properly and needs some help +#if wxUSE_UNICODE_MSLU && defined(NF_QUERY) + case WM_NOTIFYFORMAT: + if ( lParam == NF_QUERY ) + { + processed = true; + rc.result = NFR_UNICODE; + } + break; +#endif // wxUSE_UNICODE_MSLU + + // for these messages we must return true if process the message +#ifdef WM_DRAWITEM + case WM_DRAWITEM: + case WM_MEASUREITEM: + { + int idCtrl = (UINT)wParam; + if ( message == WM_DRAWITEM ) + { + processed = MSWOnDrawItem(idCtrl, + (WXDRAWITEMSTRUCT *)lParam); + } + else + { + processed = MSWOnMeasureItem(idCtrl, + (WXMEASUREITEMSTRUCT *)lParam); + } + + if ( processed ) + rc.result = TRUE; + } + break; +#endif // defined(WM_DRAWITEM) - if ( cursor ) - hcursor = (HCURSOR)cursor->GetHCURSOR(); + case WM_GETDLGCODE: + if ( !IsOfStandardClass() ) + { + // we always want to get the char events + rc.result = DLGC_WANTCHARS; + + if ( GetWindowStyleFlag() & wxWANTS_CHARS ) + { + // in fact, we want everything + rc.result |= DLGC_WANTARROWS | + DLGC_WANTTAB | + DLGC_WANTALLKEYS; } - if ( hcursor ) + 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). + m_lastKeydownProcessed = HandleKeyDown((WORD) wParam, lParam); + if ( m_lastKeydownProcessed ) + { + processed = true; + } + + if ( !processed ) + { + switch ( wParam ) { - ::SetCursor(hcursor); + // we consider these messages "not interesting" to OnChar, so + // just don't do anything more with them + case VK_SHIFT: + case VK_CONTROL: + case VK_MENU: + case VK_CAPITAL: + case VK_NUMLOCK: + case VK_SCROLL: + processed = true; + break; + + // avoid duplicate messages to OnChar for these ASCII keys: + // they will be translated by TranslateMessage() and received + // in WM_CHAR + case VK_ESCAPE: + case VK_SPACE: + case VK_RETURN: + case VK_BACK: + case VK_TAB: + case VK_ADD: + case VK_SUBTRACT: + case VK_MULTIPLY: + case VK_DIVIDE: + case VK_NUMPAD0: + case VK_NUMPAD1: + case VK_NUMPAD2: + case VK_NUMPAD3: + case VK_NUMPAD4: + case VK_NUMPAD5: + case VK_NUMPAD6: + case VK_NUMPAD7: + case VK_NUMPAD8: + case VK_NUMPAD9: + case VK_OEM_1: + case VK_OEM_2: + case VK_OEM_3: + case VK_OEM_4: + case VK_OEM_5: + case VK_OEM_6: + case VK_OEM_7: + case VK_OEM_PLUS: + case VK_OEM_COMMA: + case VK_OEM_MINUS: + case VK_OEM_PERIOD: + // 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; + +#ifdef VK_APPS + // special case of VK_APPS: treat it the same as right mouse + // click because both usually pop up a context menu + case VK_APPS: + processed = HandleMouseEvent(WM_RBUTTONDOWN, -1, -1, 0); + break; +#endif // VK_APPS - // returning TRUE stops the DefWindowProc() from further - // processing this message - exactly what we need because we've - // just set the cursor. - return TRUE; + default: + // do generate a CHAR event + processed = HandleChar((WORD)wParam, lParam); } } - } + if (message == WM_SYSKEYDOWN) // Let Windows still handle the SYSKEYs + processed = false; + break; + + case WM_SYSKEYUP: + case WM_KEYUP: +#ifdef VK_APPS + // special case of VK_APPS: treat it the same as right mouse button + if ( wParam == VK_APPS ) + { + processed = HandleMouseEvent(WM_RBUTTONUP, -1, -1, 0); + } + else +#endif // VK_APPS + { + processed = HandleKeyUp((WORD) wParam, lParam); + } + break; - return MSWDefWindowProc(message, wParam, lParam ); + case WM_SYSCHAR: + case WM_CHAR: // Always an ASCII character + if ( m_lastKeydownProcessed ) + { + // The key was handled in the EVT_KEY_DOWN and handling + // a key in an EVT_KEY_DOWN handler is meant, by + // design, to prevent EVT_CHARs from happening + m_lastKeydownProcessed = false; + processed = true; + } + else + { + processed = HandleChar((WORD)wParam, lParam, true); + } + break; - default: - return MSWDefWindowProc(message, wParam, lParam ); - } +#if wxUSE_HOTKEY + case WM_HOTKEY: + processed = HandleHotKey((WORD)wParam, lParam); + break; +#endif // wxUSE_HOTKEY - return 0; // Success: we processed this command. -} + case WM_HSCROLL: + case WM_VSCROLL: + { + WXWORD code, pos; + WXHWND hwnd; + UnpackScroll(wParam, lParam, &code, &pos, &hwnd); -// Dialog window proc -LONG APIENTRY _EXPORT -wxDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - return 0; -} + processed = MSWOnScroll(message == WM_HSCROLL ? wxHORIZONTAL + : wxVERTICAL, + code, pos, hwnd); + } + break; -wxList *wxWinHandleList = NULL; -wxWindow *wxFindWinFromHandle(WXHWND hWnd) -{ - wxNode *node = wxWinHandleList->Find((long)hWnd); - if (!node) - return NULL; - return (wxWindow *)node->Data(); -} + // CTLCOLOR messages are sent by children to query the parent for their + // colors +#ifndef __WXMICROWIN__ + case WM_CTLCOLORMSGBOX: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLORSCROLLBAR: + case WM_CTLCOLORSTATIC: + { + WXHDC hdc; + WXHWND hwnd; + UnpackCtlColor(wParam, lParam, &hdc, &hwnd); -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" ); + processed = HandleCtlColor(&rc.hBrush, (WXHDC)hdc, (WXHWND)hwnd); + } + break; +#endif // !__WXMICROWIN__ - if ( !wxWinHandleList->Find((long)hWnd) ) - wxWinHandleList->Append((long)hWnd, win); -} + case WM_SYSCOLORCHANGE: + // the return value for this message is ignored + processed = HandleSysColorChange(); + break; -void wxRemoveHandleAssociation(wxWindow *win) -{ - wxWinHandleList->DeleteObject(win); -} +#if !defined(__WXWINCE__) + case WM_DISPLAYCHANGE: + processed = HandleDisplayChange(); + break; +#endif -// Default destroyer - override if you destroy it in some other way -// (e.g. with MDI child windows) -void wxWindow::MSWDestroyWindow() -{ -} + case WM_PALETTECHANGED: + processed = HandlePaletteChanged((WXHWND) (HWND) wParam); + break; -void wxWindow::MSWCreate(int id, wxWindow *parent, const char *wclass, wxWindow *wx_win, const char *title, - int x, int y, int width, int height, - WXDWORD style, const char *dialog_template, WXDWORD extendedStyle) -{ - bool is_dialog = (dialog_template != NULL); - int x1 = CW_USEDEFAULT; - int y1 = 0; - int width1 = CW_USEDEFAULT; - int height1 = 100; + case WM_CAPTURECHANGED: + processed = HandleCaptureChanged((WXHWND) (HWND) lParam); + break; - // Find parent's size, if it exists, to set up a possible default - // panel size the size of the parent window - RECT parent_rect; - if (parent) - { - // Was GetWindowRect: JACS 5/5/95 - ::GetClientRect((HWND) parent->GetHWND(), &parent_rect); + case WM_SETTINGCHANGE: + processed = HandleSettingChange(wParam, lParam); + break; - width1 = parent_rect.right - parent_rect.left; - height1 = parent_rect.bottom - parent_rect.top; - } + case WM_QUERYNEWPALETTE: + processed = HandleQueryNewPalette(); + break; + + case WM_ERASEBKGND: + processed = HandleEraseBkgnd((WXHDC)(HDC)wParam); + if ( processed ) + { + // we processed the message, i.e. erased the background + rc.result = TRUE; + } + break; - if (x > -1) x1 = x; - if (y > -1) y1 = y; - if (width > -1) width1 = width; - if (height > -1) height1 = height; +#if !defined(__WXWINCE__) + case WM_DROPFILES: + processed = HandleDropFiles(wParam); + break; +#endif - HWND hParent = NULL; - if (parent) - hParent = (HWND) parent->GetHWND(); + case WM_INITDIALOG: + processed = HandleInitDialog((WXHWND)(HWND)wParam); - wxWndHook = this; + if ( processed ) + { + // we never set focus from here + rc.result = FALSE; + } + break; - if (is_dialog) - { - // MakeProcInstance doesn't seem to be needed in C7. Is it needed for - // other compilers??? - // VZ: it's always needed for Win16 and never for Win32 -#ifdef __WIN32__ - m_hWnd = (WXHWND) ::CreateDialog(wxGetInstance(), dialog_template, hParent, - (DLGPROC)wxDlgProc); -#else - // N.B.: if we _don't_ use this form, - // then with VC++ 1.5, it crashes horribly. -#if 1 - m_hWnd = (WXHWND) ::CreateDialog(wxGetInstance(), dialog_template, hParent, - (DLGPROC)wxDlgProc); -#else - // Crashes when we use this. - DLGPROC dlgproc = (DLGPROC)MakeProcInstance((DLGPROC)wxWndProc, wxGetInstance()); +#if !defined(__WXWINCE__) + case WM_QUERYENDSESSION: + processed = HandleQueryEndSession(lParam, &rc.allow); + break; + + case WM_ENDSESSION: + processed = HandleEndSession(wParam != 0, lParam); + break; + + case WM_GETMINMAXINFO: + processed = HandleGetMinMaxInfo((MINMAXINFO*)lParam); + break; +#endif + + case WM_SETCURSOR: + processed = HandleSetCursor((WXHWND)(HWND)wParam, + LOWORD(lParam), // hit test + HIWORD(lParam)); // mouse msg + + if ( processed ) + { + // returning TRUE stops the DefWindowProc() from further + // processing this message - exactly what we need because we've + // just set the cursor. + rc.result = TRUE; + } + break; + +#if wxUSE_ACCESSIBILITY + case WM_GETOBJECT: + { + //WPARAM dwFlags = (WPARAM) (DWORD) wParam; + LPARAM dwObjId = (LPARAM) (DWORD) lParam; - m_hWnd = (WXHWND) ::CreateDialog(wxGetInstance(), dialog_template, hParent, - (DLGPROC)dlgproc); + if (dwObjId == (LPARAM)OBJID_CLIENT && GetOrCreateAccessible()) + { + return LresultFromObject(IID_IAccessible, wParam, (IUnknown*) GetAccessible()->GetIAccessible()); + } + break; + } #endif + +#if defined(WM_HELP) + case WM_HELP: + { + // by default, WM_HELP is propagated by DefWindowProc() upwards + // to the window parent but as we do it ourselves already + // (wxHelpEvent is derived from wxCommandEvent), we don't want + // to get the other events if we process this message at all + processed = true; + + // WM_HELP doesn't use lParam under CE +#ifndef __WXWINCE__ + HELPINFO* info = (HELPINFO*) lParam; + if ( info->iContextType == HELPINFO_WINDOW ) + { +#endif // !__WXWINCE__ + wxHelpEvent helpEvent + ( + wxEVT_HELP, + GetId(), +#ifdef __WXWINCE__ + wxGetMousePosition() // what else? +#else + wxPoint(info->MousePos.x, info->MousePos.y) #endif + ); - if (m_hWnd == 0) - MessageBox(NULL, "Can't find dummy dialog template!\nCheck resource include path for finding wx.rc.", - "wxWindows Error", MB_ICONEXCLAMATION | MB_OK); - else MoveWindow((HWND) m_hWnd, x1, y1, width1, height1, FALSE); - } - else - { - int controlId = 0; - if (style & WS_CHILD) - controlId = id; - if (!title) - title = ""; - - m_hWnd = (WXHWND)CreateWindowEx(extendedStyle, wclass, - title, - style, - x1, y1, - width1, height1, - hParent, (HMENU)controlId, wxGetInstance(), - NULL); - - if ( !m_hWnd ) { - wxLogError("Can't create window of class %s!\n" - "Possible Windows 3.x compatibility problem?", wclass); - } - } + helpEvent.SetEventObject(this); + GetEventHandler()->ProcessEvent(helpEvent); +#ifndef __WXWINCE__ + } + else if ( info->iContextType == HELPINFO_MENUITEM ) + { + wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId); + helpEvent.SetEventObject(this); + GetEventHandler()->ProcessEvent(helpEvent); - wxWndHook = NULL; - wxWinHandleList->Append((long)m_hWnd, this); -} + } + else // unknown help event? + { + processed = false; + } +#endif // !__WXWINCE__ + } + break; +#endif // WM_HELP -void wxWindow::MSWOnCreate(WXLPCREATESTRUCT WXUNUSED(cs)) -{ -} +#if !defined(__WXWINCE__) + case WM_CONTEXTMENU: + { + // we don't convert from screen to client coordinates as + // the event may be handled by a parent window + wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); -bool wxWindow::MSWOnClose() -{ - return FALSE; -} + wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt); + + // we could have got an event from our child, reflect it back + // to it if this is the case + wxWindowMSW *win = NULL; + if ( (WXHWND)wParam != m_hWnd ) + { + win = FindItemByHWND((WXHWND)wParam); + } + + if ( !win ) + win = this; -// Some compilers don't define this -#ifndef ENDSESSION_LOGOFF -#define ENDSESSION_LOGOFF 0x80000000 + evtCtx.SetEventObject(win); + processed = win->GetEventHandler()->ProcessEvent(evtCtx); + } + break; #endif -// Return TRUE to end session, FALSE to veto end session. -bool wxWindow::MSWOnQueryEndSession(long logOff) -{ - wxCloseEvent event(wxEVT_QUERY_END_SESSION, -1); - event.SetEventObject(wxTheApp); - event.SetCanVeto(TRUE); - event.SetLoggingOff( (logOff == ENDSESSION_LOGOFF) ); - if ((this == wxTheApp->GetTopWindow()) && // Only send once - wxTheApp->ProcessEvent(event) && event.GetVeto()) - { - return FALSE; // Veto! - } - else - { - return TRUE; // Don't veto - } -} + case WM_MENUCHAR: + // we're only interested in our own menus, not MF_SYSMENU + if ( HIWORD(wParam) == MF_POPUP ) + { + // handle menu chars for ownerdrawn menu items + int i = HandleMenuChar(toupper(LOWORD(wParam)), lParam); + if ( i != wxNOT_FOUND ) + { + rc.result = MAKELRESULT(i, MNC_EXECUTE); + processed = true; + } + } + break; -bool wxWindow::MSWOnEndSession(bool endSession, long logOff) -{ - wxCloseEvent event(wxEVT_END_SESSION, -1); - event.SetEventObject(wxTheApp); - event.SetCanVeto(FALSE); - event.SetLoggingOff( (logOff == ENDSESSION_LOGOFF) ); - if (endSession && // No need to send if the session isn't ending - (this == wxTheApp->GetTopWindow()) && // Only send once - wxTheApp->ProcessEvent(event)) - { +#ifndef __WXWINCE__ + case WM_POWERBROADCAST: + { + bool vetoed; + processed = HandlePower(wParam, lParam, &vetoed); + rc.result = processed && vetoed ? BROADCAST_QUERY_DENY : TRUE; + } + break; +#endif // __WXWINCE__ } - return TRUE; -} - -bool wxWindow::MSWOnDestroy() -{ - // delete our drop target if we've got one -#if wxUSE_DRAG_AND_DROP - if ( m_pDropTarget != NULL ) { - m_pDropTarget->Revoke(m_hWnd); - delete m_pDropTarget; - m_pDropTarget = NULL; + if ( !processed ) + { +#ifdef __WXDEBUG__ + wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."), + wxGetMessageName(message)); +#endif // __WXDEBUG__ + rc.result = MSWDefWindowProc(message, wParam, lParam); } -#endif - return TRUE; + return rc.result; } -// Deal with child commands from buttons etc. +// ---------------------------------------------------------------------------- +// wxWindow <-> HWND map +// ---------------------------------------------------------------------------- -long wxWindow::MSWOnNotify(WXWPARAM wParam, WXLPARAM lParam) -{ -#if defined(__WIN95__) - // Find a child window to send the notification to, e.g. a toolbar. - // There's a problem here. NMHDR::hwndFrom doesn't give us the - // handle of the toolbar; it's probably the handle of the tooltip - // window (anyway, it's parent is also the toolbar's parent). - // So, since we don't know which hWnd or wxWindow originated the - // WM_NOTIFY, we'll need to go through all the children of this window - // trying out MSWNotify. - // This won't work now, though, because any number of controls - // could respond to the same generic messages :-( +wxWinHashTable *wxWinHandleHash = NULL; - /* This doesn't work for toolbars, but try for other controls first. - */ - NMHDR *hdr = (NMHDR *)lParam; - HWND hWnd = (HWND)hdr->hwndFrom; - wxWindow *win = wxFindWinFromHandle((WXHWND) hWnd); +wxWindow *wxFindWinFromHandle(WXHWND hWnd) +{ + return (wxWindow*)wxWinHandleHash->Get((long)hWnd); +} - WXLPARAM result = 0; +void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win) +{ + // adding NULL hWnd is (first) surely a result of an error and + // (secondly) breaks menu command processing + wxCHECK_RET( hWnd != (HWND)NULL, + wxT("attempt to add a NULL hWnd to window list ignored") ); - if ( win ) + wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd); +#ifdef __WXDEBUG__ + if ( oldWin && (oldWin != win) ) { - if ( win->MSWNotify(wParam, lParam, &result) ) - return result; + wxLogDebug(wxT("HWND %X already associated with another window (%s)"), + (int) hWnd, win->GetClassInfo()->GetClassName()); } else +#endif // __WXDEBUG__ + if (!oldWin) { - // Rely on MSWNotify to check whether the message - // belongs to the window or not - wxNode *node = GetChildren().First(); - while (node) - { - wxWindow *child = (wxWindow *)node->Data(); - if ( child->MSWNotify(wParam, lParam, &result) ) - return result; - node = node->Next(); - } - - // finally try this window too (catches toolbar case) - if ( MSWNotify(wParam, lParam, &result) ) - return result; + wxWinHandleHash->Put((long)hWnd, (wxWindow *)win); } -#endif // Win95 - - // not processed - return Default(); } -void wxWindow::MSWOnMenuHighlight(WXWORD WXUNUSED(item), WXWORD WXUNUSED(flags), WXHMENU WXUNUSED(sysmenu)) +void wxRemoveHandleAssociation(wxWindowMSW *win) { + wxWinHandleHash->Delete((long)win->GetHWND()); } -void wxWindow::MSWOnInitMenuPopup(WXHMENU menu, int pos, bool isSystem) -{ -} +// ---------------------------------------------------------------------------- +// various MSW speciic class dependent functions +// ---------------------------------------------------------------------------- -bool wxWindow::MSWOnActivate(int state, bool WXUNUSED(minimized), WXHWND WXUNUSED(activate)) +// Default destroyer - override if you destroy it in some other way +// (e.g. with MDI child windows) +void wxWindowMSW::MSWDestroyWindow() { - wxActivateEvent event(wxEVT_ACTIVATE, ((state == WA_ACTIVE) || (state == WA_CLICKACTIVE)), - m_windowId); - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); - return 0; } -bool wxWindow::MSWOnSetFocus(WXHWND WXUNUSED(hwnd)) +bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos, + const wxSize& size, + int& x, int& y, + int& w, int& h) const { - // Deal with caret - if (m_caretEnabled && (m_caretWidth > 0) && (m_caretHeight > 0)) - { - ::CreateCaret((HWND) GetHWND(), NULL, m_caretWidth, m_caretHeight); - if (m_caretShown) - ::ShowCaret((HWND) GetHWND()); - } - - // panel wants to track the window which was the last to have focus in it - wxWindow *parent = GetParent(); - if ( parent && parent->IsKindOf(CLASSINFO(wxPanel)) ) - { - ((wxPanel *)parent)->SetLastFocus(GetId()); - } + // yes, those are just some arbitrary hardcoded numbers + static const int DEFAULT_Y = 200; - wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId); - event.SetEventObject(this); - if (!GetEventHandler()->ProcessEvent(event)) - Default(); - return TRUE; -} + bool nonDefault = false; -bool wxWindow::MSWOnKillFocus(WXHWND WXUNUSED(hwnd)) -{ - // Deal with caret - if (m_caretEnabled) + if ( pos.x == wxDefaultCoord ) { - ::DestroyCaret(); + // if x is set to CW_USEDEFAULT, y parameter is ignored anyhow so we + // can just as well set it to CW_USEDEFAULT as well + x = + y = CW_USEDEFAULT; } + else + { + // OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it + // neither because it is not handled as a special value by Windows then + // and so we have to choose some default value for it + x = pos.x; + y = pos.y == wxDefaultCoord ? DEFAULT_Y : pos.y; - wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId); - event.SetEventObject(this); - if (!GetEventHandler()->ProcessEvent(event)) - Default(); - return TRUE; -} - -void wxWindow::MSWOnDropFiles(WXWPARAM wParam) -{ - - HDROP hFilesInfo = (HDROP) wParam; - POINT dropPoint; - DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint); - - // Get the total number of files dropped - WORD gwFilesDropped = (WORD)DragQueryFile ((HDROP)hFilesInfo, - (UINT)-1, - (LPSTR)0, - (UINT)0); + nonDefault = true; + } - wxString *files = new wxString[gwFilesDropped]; - int wIndex; - for (wIndex=0; wIndex < (int)gwFilesDropped; wIndex++) + /* + NB: there used to be some code here which set the initial size of the + window to the client size of the parent if no explicit size was + specified. This was wrong because wxWidgets programs often assume + that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke + it. To see why, you should understand that Windows sends WM_SIZE from + inside ::CreateWindow() anyhow. However, ::CreateWindow() is called + from some base class ctor and so this WM_SIZE is not processed in the + real class' OnSize() (because it's not fully constructed yet and the + event goes to some base class OnSize() instead). So the WM_SIZE we + rely on is the one sent when the parent frame resizes its children + but here is the problem: if the child already has just the right + size, nothing will happen as both wxWidgets and Windows check for + this and ignore any attempts to change the window size to the size it + already has - so no WM_SIZE would be sent. + */ + + + // we don't use CW_USEDEFAULT here for several reasons: + // + // 1. it results in huge frames on modern screens (1000*800 is not + // uncommon on my 1280*1024 screen) which is way too big for a half + // empty frame of most of wxWidgets samples for example) + // + // 2. it is buggy for frames with wxFRAME_TOOL_WINDOW style for which + // the default is for whatever reason 8*8 which breaks client <-> + // window size calculations (it would be nice if it didn't, but it + // does and the simplest way to fix it seemed to change the broken + // default size anyhow) + // + // 3. there is just no advantage in doing it: with x and y it is + // possible that [future versions of] Windows position the new top + // level window in some smart way which we can't do, but we can + // guess a reasonably good size for a new window just as well + // ourselves + + // However, on PocketPC devices, we must use the default + // size if possible. +#ifdef _WIN32_WCE + if (size.x == wxDefaultCoord) + w = CW_USEDEFAULT; + else + w = size.x; + if (size.y == wxDefaultCoord) + h = CW_USEDEFAULT; + else + h = size.y; +#else + if ( size.x == wxDefaultCoord || size.y == wxDefaultCoord) { - DragQueryFile (hFilesInfo, wIndex, (LPSTR) wxBuffer, 1000); - files[wIndex] = wxBuffer; + nonDefault = true; } - DragFinish (hFilesInfo); - - wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files); - event.m_eventObject = this; - event.m_pos.x = dropPoint.x; event.m_pos.x = dropPoint.y; + w = WidthDefault(size.x); + h = HeightDefault(size.y); +#endif - if (!GetEventHandler()->ProcessEvent(event)) - Default(); + AdjustForParentClientOrigin(x, y); - delete[] files; + return nonDefault; } -bool wxWindow::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct) +WXHWND wxWindowMSW::MSWGetParent() const { -#if wxUSE_OWNER_DRAWN - if ( id == 0 ) { // is it a menu item? - DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct; - wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData); - wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE ); - - // prepare to call OnDrawItem() - wxDC dc; - dc.SetHDC((WXHDC)pDrawStruct->hDC, FALSE); - wxRect rect(pDrawStruct->rcItem.left, pDrawStruct->rcItem.top, - pDrawStruct->rcItem.right - pDrawStruct->rcItem.left, - pDrawStruct->rcItem.bottom - pDrawStruct->rcItem.top); - return pMenuItem->OnDrawItem( - dc, rect, - (wxOwnerDrawn::wxODAction)pDrawStruct->itemAction, - (wxOwnerDrawn::wxODStatus)pDrawStruct->itemState - ); - } -#endif // owner-drawn menus - - wxWindow *item = FindItem(id); -#if wxUSE_DYNAMIC_CLASSES - if (item && item->IsKindOf(CLASSINFO(wxControl))) - { - return ((wxControl *)item)->MSWOnDraw(itemStruct); - } - else -#endif - return FALSE; + return m_parent ? m_parent->GetHWND() : WXHWND(NULL); } -bool wxWindow::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct) +bool wxWindowMSW::MSWCreate(const wxChar *wclass, + const wxChar *title, + const wxPoint& pos, + const wxSize& size, + WXDWORD style, + WXDWORD extendedStyle) { -#if wxUSE_OWNER_DRAWN - if ( id == 0 ) { // is it a menu item? - MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct; - wxMenuItem *pMenuItem = (wxMenuItem *)(pMeasureStruct->itemData); - wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE ); + // choose the position/size for the new window + int x, y, w, h; + (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h); - return pMenuItem->OnMeasureItem(&pMeasureStruct->itemWidth, - &pMeasureStruct->itemHeight); - } -#endif // owner-drawn menus + // controlId is menu handle for the top level windows, so set it to 0 + // unless we're creating a child window + int controlId = style & WS_CHILD ? GetId() : 0; - wxWindow *item = FindItem(id); -#if wxUSE_DYNAMIC_CLASSES - if (item && item->IsKindOf(CLASSINFO(wxControl))) + // for each class "Foo" we have we also have "FooNR" ("no repaint") class + // which is the same but without CS_[HV]REDRAW class styles so using it + // ensures that the window is not fully repainted on each resize + wxString className(wclass); + if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) ) { - return ((wxControl *)item)->MSWOnMeasure(itemStruct); - } - else -#endif - return FALSE; -} - -WXHBRUSH wxWindow::MSWOnCtlColor(WXHDC pDC, WXHWND pWnd, WXUINT nCtlColor, - WXUINT message, WXWPARAM wParam, WXLPARAM lParam) -{ - if (nCtlColor == CTLCOLOR_DLG) + className += wxT("NR"); + } + + // do create the window + wxWindowCreationHook hook(this); + + m_hWnd = (WXHWND)::CreateWindowEx + ( + extendedStyle, + className, + title ? title : m_windowName.c_str(), + style, + x, y, w, h, + (HWND)MSWGetParent(), + (HMENU)controlId, + wxGetInstance(), + NULL // no extra data + ); + + if ( !m_hWnd ) { - return OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam); - } - - wxControl *item = (wxControl *)FindItemByHWND(pWnd, TRUE); + wxLogSysError(_("Can't create window of class %s"), className.c_str()); - WXHBRUSH hBrush = 0; - - if ( item ) - hBrush = item->OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam); - - // I think that even for dialogs, we may need to call DefWindowProc (?) - // Or maybe just rely on the usual default behaviour. - if ( !hBrush ) - hBrush = (WXHBRUSH) MSWDefWindowProc(message, wParam, lParam); + return false; + } - return hBrush ; -} + SubclassWin(m_hWnd); -// Define for each class of dialog and control -WXHBRUSH wxWindow::OnCtlColor(WXHDC pDC, WXHWND pWnd, WXUINT nCtlColor, - WXUINT message, WXWPARAM wParam, WXLPARAM lParam) -{ - return (WXHBRUSH) MSWDefWindowProc(message, wParam, lParam); + return true; } -bool wxWindow::MSWOnColorChange(WXHWND hWnd, WXUINT message, WXWPARAM wParam, WXLPARAM lParam) -{ - wxSysColourChangedEvent event; - event.SetEventObject(this); - - // Check if app handles this. - if (GetEventHandler()->ProcessEvent(event)) - return 0; +// =========================================================================== +// MSW message handlers +// =========================================================================== - // We didn't process it - return 1; -} +// --------------------------------------------------------------------------- +// WM_NOTIFY +// --------------------------------------------------------------------------- -long wxWindow::MSWOnPaletteChanged(WXHWND hWndPalChange) +bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) { - wxPaletteChangedEvent event(GetId()); - event.SetEventObject(this); - event.SetChangedWindow(wxFindWinFromHandle(hWndPalChange)); - GetEventHandler()->ProcessEvent(event); - return 0; -} +#ifndef __WXMICROWIN__ + LPNMHDR hdr = (LPNMHDR)lParam; + HWND hWnd = hdr->hwndFrom; + wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd); -long wxWindow::MSWOnQueryNewPalette() -{ - wxQueryNewPaletteEvent event(GetId()); - event.SetEventObject(this); - if (!GetEventHandler()->ProcessEvent(event) || !event.GetPaletteRealized()) + // if the control is one of our windows, let it handle the message itself + if ( win ) { - return (long) FALSE; - } - else - return (long) TRUE; -} - -// Responds to colour changes: passes event on to children. -void wxWindow::OnSysColourChanged(wxSysColourChangedEvent& event) -{ - wxNode *node = GetChildren().First(); + return win->MSWOnNotify(idCtrl, lParam, result); + } + + // VZ: why did we do it? normally this is unnecessary and, besides, it + // breaks the message processing for the toolbars because the tooltip + // notifications were being forwarded to the toolbar child controls + // (if it had any) before being passed to the toolbar itself, so in my + // example the tooltip for the combobox was always shown instead of the + // correct button tooltips +#if 0 + // try all our children + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); while ( node ) { - // Only propagate to non-top-level windows - wxWindow *win = (wxWindow *)node->Data(); - if ( win->GetParent() ) + wxWindow *child = node->GetData(); + if ( child->MSWOnNotify(idCtrl, lParam, result) ) { - wxSysColourChangedEvent event2; - event.m_eventObject = win; - win->GetEventHandler()->ProcessEvent(event2); + return true; } - node = node->Next(); + node = node->GetNext(); } -} +#endif // 0 -long wxWindow::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) -{ - if ( m_oldWndProc ) - return ::CallWindowProc(CASTWNDPROC m_oldWndProc, (HWND) GetHWND(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam); - else - return ::DefWindowProc((HWND) GetHWND(), nMsg, wParam, lParam); -} - -long wxWindow::Default() -{ - // Ignore 'fake' events (perhaps generated as a result of a separate real event) - if (m_lastMsg == 0) - return 0; - -#ifdef __WXDEBUG__ - wxLogTrace(wxTraceMessages, "Forwarding %s to DefWindowProc.", - wxGetMessageName(m_lastMsg)); -#endif // __WXDEBUG__ - - return this->MSWDefWindowProc(m_lastMsg, m_lastWParam, m_lastLParam); + // by default, handle it ourselves + return MSWOnNotify(idCtrl, lParam, result); +#else // __WXMICROWIN__ + return false; +#endif } -bool wxWindow::MSWProcessMessage(WXMSG* pMsg) -{ - if ( m_hWnd != 0 && (GetWindowStyleFlag() & wxTAB_TRAVERSAL) ) { - // intercept dialog navigation keys - MSG *msg = (MSG *)pMsg; - bool bProcess = TRUE; - if ( msg->message != WM_KEYDOWN ) - bProcess = FALSE; - - if ( bProcess && (HIWORD(msg->lParam) & KF_ALTDOWN) == KF_ALTDOWN ) - bProcess = FALSE; - - if ( bProcess ) - { - bool bCtrlDown = (::GetKeyState(VK_CONTROL) & 0x100) != 0; - - // 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 - // combinations which are always processed) - LONG lDlgCode = 0; - if ( !bCtrlDown ) - { - lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0); - } - - bool bForward = TRUE, - bWindowChange = FALSE; - - switch ( msg->wParam ) - { - case VK_TAB: - if ( lDlgCode & DLGC_WANTTAB ) { - bProcess = FALSE; - } - else { - // Ctrl-Tab cycles thru notebook pages - bWindowChange = bCtrlDown; - bForward = !(::GetKeyState(VK_SHIFT) & 0x100); - } - break; - - case VK_UP: - case VK_LEFT: - if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown ) - bProcess = FALSE; - else - bForward = FALSE; - break; - - case VK_DOWN: - case VK_RIGHT: - if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown ) - bProcess = FALSE; - break; +#if wxUSE_TOOLTIPS - case VK_RETURN: - { - if ( lDlgCode & DLGC_WANTMESSAGE ) - { - // control wants to process Enter itself, don't - // call IsDialogMessage() which would interpret - // it - return FALSE; - } -#ifndef __WIN16__ - wxButton *btnDefault = GetDefaultItem(); - if ( btnDefault && !bCtrlDown ) - { - // if there is a default button, Enter should - // press it - (void)::SendMessage((HWND)btnDefault->GetHWND(), - BM_CLICK, 0, 0); - return TRUE; - } - // 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. +bool wxWindowMSW::HandleTooltipNotify(WXUINT code, + WXLPARAM lParam, + const wxString& ttip) +{ + // I don't know why it happens, but the versions of comctl32.dll starting + // from 4.70 sometimes send TTN_NEEDTEXTW even to ANSI programs (normally, + // this message is supposed to be sent to Unicode programs only) -- hence + // we need to handle it as well, otherwise no tooltips will be shown in + // this case +#ifndef __WXWINCE__ + if ( !(code == (WXUINT) TTN_NEEDTEXTA || code == (WXUINT) TTN_NEEDTEXTW) + || ttip.empty() ) + { + // not a tooltip message or no tooltip to show anyhow + return false; + } #endif - } - break; - - default: - bProcess = FALSE; - } - - if ( bProcess ) - { - wxNavigationKeyEvent event; - event.SetDirection(bForward); - event.SetWindowChange(bWindowChange); - event.SetEventObject(this); - if ( GetEventHandler()->ProcessEvent(event) ) - return TRUE; - } + LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam; + + // We don't want to use the szText buffer because it has a limit of 80 + // bytes and this is not enough, especially for Unicode build where it + // limits the tooltip string length to only 40 characters + // + // The best would be, of course, to not impose any length limitations at + // all but then the buffer would have to be dynamic and someone would have + // to free it and we don't have the tooltip owner object here any more, so + // for now use our own static buffer with a higher fixed max length. + // + // Note that using a static buffer should not be a problem as only a single + // tooltip can be shown at the same time anyhow. +#if !wxUSE_UNICODE + if ( code == (WXUINT) TTN_NEEDTEXTW ) + { + // We need to convert tooltip from multi byte to Unicode on the fly. + static wchar_t buf[513]; + + // Truncate tooltip length if needed as otherwise we might not have + // enough space for it in the buffer and MultiByteToWideChar() would + // return an error + size_t tipLength = wxMin(ttip.length(), WXSIZEOF(buf) - 1); + + // Convert to WideChar without adding the NULL character. The NULL + // character is added afterwards (this is more efficient). + int len = ::MultiByteToWideChar + ( + CP_ACP, + 0, // no flags + ttip, + tipLength, + buf, + WXSIZEOF(buf) - 1 + ); + + if ( !len ) + { + wxLogLastError(_T("MultiByteToWideChar()")); } - if ( ::IsDialogMessage((HWND)GetHWND(), msg) ) - return TRUE; + buf[len] = L'\0'; + ttText->lpszText = (LPSTR) buf; } -#if wxUSE_TOOLTIPS - if ( m_tooltip ) + else // TTN_NEEDTEXTA +#endif // !wxUSE_UNICODE { - // relay mouse move events to the tooltip control - MSG *msg = (MSG *)pMsg; - if ( msg->message == WM_MOUSEMOVE ) - m_tooltip->RelayEvent(pMsg); + // we get here if we got TTN_NEEDTEXTA (only happens in ANSI build) or + // if we got TTN_NEEDTEXTW in Unicode build: in this case we just have + // to copy the string we have into the buffer + static wxChar buf[513]; + wxStrncpy(buf, ttip.c_str(), WXSIZEOF(buf) - 1); + buf[WXSIZEOF(buf) - 1] = _T('\0'); + ttText->lpszText = buf; } -#endif // wxUSE_TOOLTIPS - - return FALSE; -} -bool wxWindow::MSWTranslateMessage(WXMSG* pMsg) -{ - if (m_acceleratorTable.Ok() && - ::TranslateAccelerator((HWND) GetHWND(), (HACCEL) m_acceleratorTable.GetHACCEL(), (MSG *)pMsg)) - return TRUE; - else - return FALSE; + return true; } -long wxWindow::MSWOnMDIActivate(long WXUNUSED(flag), WXHWND WXUNUSED(activate), WXHWND WXUNUSED(deactivate)) -{ - return 1; -} +#endif // wxUSE_TOOLTIPS -void wxWindow::MSWDetachWindowMenu() +bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl), + WXLPARAM lParam, + WXLPARAM* WXUNUSED(result)) { - if (m_hMenu) +#if wxUSE_TOOLTIPS + if ( m_tooltip ) { - int N = GetMenuItemCount((HMENU) m_hMenu); - int i; - for (i = 0; i < N; i++) + NMHDR* hdr = (NMHDR *)lParam; + if ( HandleTooltipNotify(hdr->code, lParam, m_tooltip->GetTip())) { - char buf[100]; - int chars = GetMenuString((HMENU) m_hMenu, i, buf, 100, MF_BYPOSITION); - if ((chars > 0) && (strcmp(buf, "&Window") == 0)) - { - RemoveMenu((HMENU) m_hMenu, i, MF_BYPOSITION); - break; - } + // processed + return true; } } +#else + wxUnusedVar(lParam); +#endif // wxUSE_TOOLTIPS + + return false; } -bool wxWindow::MSWOnPaint() +// --------------------------------------------------------------------------- +// end session messages +// --------------------------------------------------------------------------- + +bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd) { -#ifdef __WIN32__ - HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle - ::GetUpdateRgn((HWND) GetHWND(), hRegion, FALSE); +#ifdef ENDSESSION_LOGOFF + wxCloseEvent event(wxEVT_QUERY_END_SESSION, wxID_ANY); + event.SetEventObject(wxTheApp); + event.SetCanVeto(true); + event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF); - m_updateRegion = wxRegion((WXHRGN) hRegion); -#else - RECT updateRect; - ::GetUpdateRect((HWND) GetHWND(), & updateRect, FALSE); + bool rc = wxTheApp->ProcessEvent(event); - m_updateRegion = wxRegion(updateRect.left, updateRect.top, - updateRect.right - updateRect.left, updateRect.bottom - updateRect.top); -#endif + if ( rc ) + { + // we may end only if the app didn't veto session closing (double + // negation...) + *mayEnd = !event.GetVeto(); + } - wxPaintEvent event(m_windowId); - event.SetEventObject(this); - if (!GetEventHandler()->ProcessEvent(event)) - Default(); - return TRUE; + return rc; +#else + wxUnusedVar(logOff); + wxUnusedVar(mayEnd); + return false; +#endif } -void wxWindow::MSWOnSize(int w, int h, WXUINT WXUNUSED(flag)) +bool wxWindowMSW::HandleEndSession(bool endSession, long logOff) { - if (m_inOnSize) - return; - - if (!m_hWnd) - return; +#ifdef ENDSESSION_LOGOFF + // do nothing if the session isn't ending + if ( !endSession ) + return false; - m_inOnSize = TRUE; + // only send once + if ( (this != wxTheApp->GetTopWindow()) ) + return false; - wxSizeEvent event(wxSize(w, h), m_windowId); - event.SetEventObject(this); - if (!GetEventHandler()->ProcessEvent(event)) - Default(); + wxCloseEvent event(wxEVT_END_SESSION, wxID_ANY); + event.SetEventObject(wxTheApp); + event.SetCanVeto(false); + event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) ); - m_inOnSize = FALSE; + return wxTheApp->ProcessEvent(event); +#else + wxUnusedVar(endSession); + wxUnusedVar(logOff); + return false; +#endif } -void wxWindow::MSWOnWindowPosChanging(void *WXUNUSED(lpPos)) -{ - Default(); -} +// --------------------------------------------------------------------------- +// window creation/destruction +// --------------------------------------------------------------------------- -// Deal with child commands from buttons etc. -bool wxWindow::MSWOnCommand(WXWORD id, WXWORD cmd, WXHWND control) +bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED_IN_WINCE(cs), + bool *mayCreate) { - if (wxCurrentPopupMenu) - { - wxMenu *popupMenu = wxCurrentPopupMenu; - wxCurrentPopupMenu = NULL; - bool succ = popupMenu->MSWCommand(cmd, id); - return succ; - } + // VZ: why is this commented out for WinCE? If it doesn't support + // WS_EX_CONTROLPARENT at all it should be somehow handled globally, + // not with multiple #ifdef's! +#ifndef __WXWINCE__ + if ( ((CREATESTRUCT *)cs)->dwExStyle & WS_EX_CONTROLPARENT ) + EnsureParentHasControlParentStyle(GetParent()); +#endif // !__WXWINCE__ - wxWindow *item = FindItem(id); - if (item) - { - bool value = item->MSWCommand(cmd, id); - return value; - } - else - { - wxWindow *win = wxFindWinFromHandle(control); - if (win) - return win->MSWCommand(cmd, id); - } - return FALSE; + *mayCreate = true; + + return true; } -long wxWindow::MSWOnSysCommand(WXWPARAM wParam, WXLPARAM lParam) +bool wxWindowMSW::HandleDestroy() { - switch (wParam & 0xFFFFFFF0) + SendDestroyEvent(); + + // delete our drop target if we've got one +#if wxUSE_DRAG_AND_DROP + if ( m_dropTarget != NULL ) { - case SC_MAXIMIZE: - { - wxMaximizeEvent event(m_windowId); - event.SetEventObject(this); - if (!GetEventHandler()->ProcessEvent(event)) - return Default(); - else - return 0; - break; - } - case SC_MINIMIZE: - { - wxIconizeEvent event(m_windowId); - event.SetEventObject(this); - if (!GetEventHandler()->ProcessEvent(event)) - return Default(); - else - return 0; - break; - } - default: - return Default(); + m_dropTarget->Revoke(m_hWnd); + + delete m_dropTarget; + m_dropTarget = NULL; } - return 0; -} +#endif // wxUSE_DRAG_AND_DROP -void wxWindow::MSWOnLButtonDown(int x, int y, WXUINT flags) -{ - wxMouseEvent event(wxEVT_LEFT_DOWN); + // WM_DESTROY handled + return true; +} - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); - event.m_eventObject = this; +// --------------------------------------------------------------------------- +// activation/focus +// --------------------------------------------------------------------------- - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVT_LEFT_DOWN; +bool wxWindowMSW::HandleActivate(int state, + bool WXUNUSED(minimized), + WXHWND WXUNUSED(activate)) +{ + wxActivateEvent event(wxEVT_ACTIVATE, + (state == WA_ACTIVE) || (state == WA_CLICKACTIVE), + m_windowId); + event.SetEventObject(this); - if (!GetEventHandler()->ProcessEvent(event)) - Default(); + return GetEventHandler()->ProcessEvent(event); } -void wxWindow::MSWOnLButtonUp(int x, int y, WXUINT flags) +bool wxWindowMSW::HandleSetFocus(WXHWND hwnd) { - wxMouseEvent event(wxEVT_LEFT_UP); - - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); - event.m_eventObject = this; + // Strangly enough, some controls get set focus events when they are being + // deleted, even if they already had focus before. + if ( m_isBeingDeleted ) + { + return false; + } - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVT_LEFT_UP; + // notify the parent keeping track of focus for the kbd navigation + // purposes that we got it + wxChildFocusEvent eventFocus((wxWindow *)this); + (void)GetEventHandler()->ProcessEvent(eventFocus); - if (!GetEventHandler()->ProcessEvent(event)) - Default(); -} +#if wxUSE_CARET + // Deal with caret + if ( m_caret ) + { + m_caret->OnSetFocus(); + } +#endif // wxUSE_CARET -void wxWindow::MSWOnLButtonDClick(int x, int y, WXUINT flags) -{ - wxMouseEvent event(wxEVT_LEFT_DCLICK); +#if wxUSE_TEXTCTRL + // If it's a wxTextCtrl don't send the event as it will be done + // after the control gets to process it from EN_FOCUS handler + if ( wxDynamicCastThis(wxTextCtrl) ) + { + return false; + } +#endif // wxUSE_TEXTCTRL - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); - event.m_eventObject = this; + wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId); + event.SetEventObject(this); - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVT_LEFT_DCLICK; + // wxFindWinFromHandle() may return NULL, it is ok + event.SetWindow(wxFindWinFromHandle(hwnd)); - if (!GetEventHandler()->ProcessEvent(event)) - Default(); + return GetEventHandler()->ProcessEvent(event); } -void wxWindow::MSWOnMButtonDown(int x, int y, WXUINT flags) +bool wxWindowMSW::HandleKillFocus(WXHWND hwnd) { - wxMouseEvent event(wxEVT_MIDDLE_DOWN); +#if wxUSE_CARET + // Deal with caret + if ( m_caret ) + { + m_caret->OnKillFocus(); + } +#endif // wxUSE_CARET - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); - event.m_eventObject = this; +#if wxUSE_TEXTCTRL + // If it's a wxTextCtrl don't send the event as it will be done + // after the control gets to process it. + wxTextCtrl *ctrl = wxDynamicCastThis(wxTextCtrl); + if ( ctrl ) + { + return false; + } +#endif - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVT_MIDDLE_DOWN; + // Don't send the event when in the process of being deleted. This can + // only cause problems if the event handler tries to access the object. + if ( m_isBeingDeleted ) + { + return false; + } - if (!GetEventHandler()->ProcessEvent(event)) - Default(); -} + wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId); + event.SetEventObject(this); -void wxWindow::MSWOnMButtonUp(int x, int y, WXUINT flags) -{ - wxMouseEvent event(wxEVT_MIDDLE_UP); + // wxFindWinFromHandle() may return NULL, it is ok + event.SetWindow(wxFindWinFromHandle(hwnd)); - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); - event.m_eventObject = this; + return GetEventHandler()->ProcessEvent(event); +} - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVT_MIDDLE_UP; +// --------------------------------------------------------------------------- +// labels +// --------------------------------------------------------------------------- - if (!GetEventHandler()->ProcessEvent(event)) - Default(); +void wxWindowMSW::SetLabel( const wxString& label) +{ + SetWindowText(GetHwnd(), label.c_str()); } -void wxWindow::MSWOnMButtonDClick(int x, int y, WXUINT flags) +wxString wxWindowMSW::GetLabel() const { - wxMouseEvent event(wxEVT_MIDDLE_DCLICK); + return wxGetWindowText(GetHWND()); +} - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); - event.m_eventObject = this; +// --------------------------------------------------------------------------- +// miscellaneous +// --------------------------------------------------------------------------- - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVT_MIDDLE_DCLICK; +bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status)) +{ + wxShowEvent event(GetId(), show); + event.SetEventObject(this); - if (!GetEventHandler()->ProcessEvent(event)) - Default(); + return GetEventHandler()->ProcessEvent(event); } -void wxWindow::MSWOnRButtonDown(int x, int y, WXUINT flags) +bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus)) { - wxMouseEvent event(wxEVT_RIGHT_DOWN); - - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); - event.m_eventObject = this; - - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVT_RIGHT_DOWN; + wxInitDialogEvent event(GetId()); + event.SetEventObject(this); - if (!GetEventHandler()->ProcessEvent(event)) - Default(); + return GetEventHandler()->ProcessEvent(event); } -void wxWindow::MSWOnRButtonUp(int x, int y, WXUINT flags) +bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam) { - wxMouseEvent event(wxEVT_RIGHT_UP); - - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.m_eventObject = this; - event.SetTimestamp(wxApp::sm_lastMessageTime); +#if defined (__WXMICROWIN__) || defined(__WXWINCE__) + wxUnusedVar(wParam); + return false; +#else // __WXMICROWIN__ + HDROP hFilesInfo = (HDROP) wParam; - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVT_RIGHT_UP; + // Get the total number of files dropped + UINT gwFilesDropped = ::DragQueryFile + ( + (HDROP)hFilesInfo, + (UINT)-1, + (LPTSTR)0, + (UINT)0 + ); - if (!GetEventHandler()->ProcessEvent(event)) - Default(); -} + wxString *files = new wxString[gwFilesDropped]; + for ( UINT wIndex = 0; wIndex < gwFilesDropped; wIndex++ ) + { + // first get the needed buffer length (+1 for terminating NUL) + size_t len = ::DragQueryFile(hFilesInfo, wIndex, NULL, 0) + 1; -void wxWindow::MSWOnRButtonDClick(int x, int y, WXUINT flags) -{ - wxMouseEvent event(wxEVT_RIGHT_DCLICK); + // and now get the file name + ::DragQueryFile(hFilesInfo, wIndex, + wxStringBuffer(files[wIndex], len), len); + } + DragFinish (hFilesInfo); - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); - event.m_eventObject = this; + wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files); + event.SetEventObject(this); - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVT_RIGHT_DCLICK; + POINT dropPoint; + DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint); + event.m_pos.x = dropPoint.x; + event.m_pos.y = dropPoint.y; - if (!GetEventHandler()->ProcessEvent(event)) - Default(); + return GetEventHandler()->ProcessEvent(event); +#endif } -void wxWindow::MSWOnMouseMove(int x, int y, WXUINT flags) + +bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd), + short nHitTest, + int WXUNUSED(mouseMsg)) { - // 'normal' move event... +#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 - if (!m_mouseInWindow) + if ( nHitTest != HTCLIENT ) { - // Generate an ENTER event - m_mouseInWindow = TRUE; - MSWOnMouseEnter(x, y, flags); + return false; } - wxMouseEvent event(wxEVT_MOTION); + HCURSOR hcursor = 0; - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); - event.m_eventObject = this; - - // Window gets a click down message followed by a mouse move - // message even if position isn't changed! We want to discard - // the trailing move event if x and y are the same. - if ((m_lastEvent == wxEVT_RIGHT_DOWN || m_lastEvent == wxEVT_LEFT_DOWN || - m_lastEvent == wxEVT_MIDDLE_DOWN) && - (m_lastXPos == event.m_x && m_lastYPos == event.m_y)) + // 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)) +#else + if ( !::GetCursorPos(&pt) ) +#endif { - m_lastXPos = event.m_x; m_lastYPos = event.m_y; - m_lastEvent = wxEVT_MOTION; - return; + wxLogLastError(wxT("GetCursorPos")); } - m_lastEvent = wxEVT_MOTION; - m_lastXPos = event.m_x; m_lastYPos = event.m_y; - - if (!GetEventHandler()->ProcessEvent(event)) - Default(); -} - -void wxWindow::MSWOnMouseEnter(int x, int y, WXUINT flags) -{ - wxMouseEvent event(wxEVT_ENTER_WINDOW); - - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); - event.m_eventObject = this; - - m_lastEvent = wxEVT_ENTER_WINDOW; - m_lastXPos = event.m_x; m_lastYPos = event.m_y; - // No message - ensure we don't try to call the default behaviour accidentally. - m_lastMsg = 0; - GetEventHandler()->ProcessEvent(event); -} + int x = pt.x, + y = pt.y; + ScreenToClient(&x, &y); + wxSetCursorEvent event(x, y); -void wxWindow::MSWOnMouseLeave(int x, int y, WXUINT flags) -{ - wxMouseEvent event(wxEVT_LEAVE_WINDOW); + bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event); + if ( processedEvtSetCursor && event.HasCursor() ) + { + hcursor = GetHcursorOf(event.GetCursor()); + } - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); - event.m_eventObject = this; + if ( !hcursor ) + { + bool isBusy = wxIsBusy(); - m_lastEvent = wxEVT_LEAVE_WINDOW; - m_lastXPos = event.m_x; m_lastYPos = event.m_y; - // No message - ensure we don't try to call the default behaviour accidentally. - m_lastMsg = 0; - GetEventHandler()->ProcessEvent(event); -} + // 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 = GetHcursorOf(m_cursor); + } -bool wxWindow::MSWOnChar(WXWORD wParam, WXLPARAM lParam, bool isASCII) -{ - int id; - bool tempControlDown = FALSE; - if (isASCII) - { - // If 1 -> 26, translate to CTRL plus a letter. - id = wParam; - if ((id > 0) && (id < 27)) + if ( !GetParent() ) { - switch (id) + if ( isBusy ) { - case 13: - { - id = WXK_RETURN; - break; - } - case 8: - { - id = WXK_BACK; - break; - } - case 9: - { - id = WXK_TAB; - break; - } - default: + hcursor = wxGetCurrentBusyCursor(); + } + else if ( !hcursor ) + { + const wxCursor *cursor = wxGetGlobalCursor(); + if ( cursor && cursor->Ok() ) { - tempControlDown = TRUE; - id = id + 96; + hcursor = GetHcursorOf(*cursor); } } } } - 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) - id = -1; + + if ( hcursor ) + { +// wxLogDebug("HandleSetCursor: Setting cursor %ld", (long) hcursor); + + ::SetCursor(hcursor); + + // cursor set, stop here + return true; } +#endif // __WXMICROWIN__ - if (id != -1) + // pass up the window chain + return false; +} + +bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam), + WXLPARAM WXUNUSED(lParam), + bool *WXUNUSED_IN_WINCE(vetoed)) +{ +#ifdef __WXWINCE__ + // FIXME + return false; +#else + wxEventType evtType; + switch ( wParam ) { - 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; + case PBT_APMQUERYSUSPEND: + evtType = wxEVT_POWER_SUSPENDING; + break; - event.m_eventObject = this; - event.m_keyCode = id; - event.SetTimestamp(wxApp::sm_lastMessageTime); + case PBT_APMQUERYSUSPENDFAILED: + evtType = wxEVT_POWER_SUSPEND_CANCEL; + break; - POINT pt ; - GetCursorPos(&pt) ; - RECT rect ; - GetWindowRect((HWND) GetHWND(),&rect) ; - pt.x -= rect.left ; - pt.y -= rect.top ; + case PBT_APMSUSPEND: + evtType = wxEVT_POWER_SUSPENDED; + break; - event.m_x = pt.x; event.m_y = pt.y; + case PBT_APMRESUMESUSPEND: +#ifdef PBT_APMRESUMEAUTOMATIC + case PBT_APMRESUMEAUTOMATIC: +#endif + evtType = wxEVT_POWER_RESUME; + break; - if (GetEventHandler()->ProcessEvent(event)) - return TRUE; - else - return FALSE; + default: + wxLogDebug(_T("Unknown WM_POWERBROADCAST(%d) event"), wParam); + // fall through + + // these messages are currently not mapped to wx events + case PBT_APMQUERYSTANDBY: + case PBT_APMQUERYSTANDBYFAILED: + case PBT_APMSTANDBY: + case PBT_APMRESUMESTANDBY: + case PBT_APMBATTERYLOW: + case PBT_APMPOWERSTATUSCHANGE: + case PBT_APMOEMEVENT: + case PBT_APMRESUMECRITICAL: + evtType = wxEVT_NULL; + break; } - else - return FALSE; + + // don't handle unknown messages + if ( evtType == wxEVT_NULL ) + return false; + + // TODO: notify about PBTF_APMRESUMEFROMFAILURE in case of resume events? + + wxPowerEvent event(evtType); + if ( !GetEventHandler()->ProcessEvent(event) ) + return false; + + *vetoed = event.IsVetoed(); + + return true; +#endif } -bool wxWindow::MSWOnKeyDown(WXWORD wParam, WXLPARAM lParam, bool isASCII) +bool wxWindowMSW::IsDoubleBuffered() const { - int id; - - if ((id = wxCharCodeMSWToWX(wParam)) == 0) { - id = wParam; + for ( const wxWindowMSW *wnd = this; + wnd && !wnd->IsTopLevel(); wnd = + wnd->GetParent() ) + { + if ( ::GetWindowLong(GetHwndOf(wnd), GWL_EXSTYLE) & WS_EX_COMPOSITED ) + return true; } - if (id != -1) + return false; +} + +// --------------------------------------------------------------------------- +// owner drawn stuff +// --------------------------------------------------------------------------- + +#if (wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE) || \ + (wxUSE_CONTROLS && !defined(__WXUNIVERSAL__)) + #define WXUNUSED_UNLESS_ODRAWN(param) param +#else + #define WXUNUSED_UNLESS_ODRAWN(param) +#endif + +bool +wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id), + WXDRAWITEMSTRUCT * WXUNUSED_UNLESS_ODRAWN(itemStruct)) +{ +#if wxUSE_OWNER_DRAWN + +#if wxUSE_MENUS_NATIVE + // is it a menu item? + DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct; + if ( id == 0 && pDrawStruct->CtlType == ODT_MENU ) { - 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; + wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData); - event.m_eventObject = this; - event.m_keyCode = id; - event.SetTimestamp(wxApp::sm_lastMessageTime); + // see comment before the same test in MSWOnMeasureItem() below + if ( !pMenuItem ) + return false; - POINT pt ; - GetCursorPos(&pt) ; - RECT rect ; - GetWindowRect((HWND) GetHWND(),&rect) ; - pt.x -= rect.left ; - pt.y -= rect.top ; + wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem), + false, _T("MSWOnDrawItem: bad wxMenuItem pointer") ); - event.m_x = pt.x; event.m_y = pt.y; + // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent + // the DC from being released + wxDCTemp dc((WXHDC)pDrawStruct->hDC); + wxRect rect(pDrawStruct->rcItem.left, pDrawStruct->rcItem.top, + pDrawStruct->rcItem.right - pDrawStruct->rcItem.left, + pDrawStruct->rcItem.bottom - pDrawStruct->rcItem.top); - if (GetEventHandler()->ProcessEvent(event)) - { - return TRUE; - } - else return FALSE; + return pMenuItem->OnDrawItem + ( + dc, + rect, + (wxOwnerDrawn::wxODAction)pDrawStruct->itemAction, + (wxOwnerDrawn::wxODStatus)pDrawStruct->itemState + ); } - else +#endif // wxUSE_MENUS_NATIVE + +#endif // USE_OWNER_DRAWN + +#if wxUSE_CONTROLS && !defined(__WXUNIVERSAL__) + +#if wxUSE_OWNER_DRAWN + wxControl *item = wxDynamicCast(FindItem(id), wxControl); +#else // !wxUSE_OWNER_DRAWN + // we may still have owner-drawn buttons internally because we have to make + // them owner-drawn to support colour change + wxControl *item = +# if wxUSE_BUTTON + wxDynamicCast(FindItem(id), wxButton) +# else + NULL +# endif + ; +#endif // USE_OWNER_DRAWN + + if ( item ) { - return FALSE; + return item->MSWOnDraw(itemStruct); } + +#endif // wxUSE_CONTROLS + + return false; } -bool wxWindow::MSWOnKeyUp(WXWORD wParam, WXLPARAM lParam, bool isASCII) +bool +wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct) { - int id; +#if wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE + // is it a menu item? + MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct; + if ( id == 0 && pMeasureStruct->CtlType == ODT_MENU ) + { + wxMenuItem *pMenuItem = (wxMenuItem *)(pMeasureStruct->itemData); - if ((id = wxCharCodeMSWToWX(wParam)) == 0) { - id = wParam; - } + // according to Carsten Fuchs the pointer may be NULL under XP if an + // MDI child frame is initially maximized, see this for more info: + // http://article.gmane.org/gmane.comp.lib.wxwidgets.general/27745 + // + // so silently ignore it instead of asserting + if ( !pMenuItem ) + return false; - if (id != -1) - { - 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; + wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem), + false, _T("MSWOnMeasureItem: bad wxMenuItem pointer") ); - event.m_eventObject = this; - event.m_keyCode = id; - event.SetTimestamp(wxApp::sm_lastMessageTime); + size_t w, h; + bool rc = pMenuItem->OnMeasureItem(&w, &h); - POINT pt ; - GetCursorPos(&pt) ; - RECT rect ; - GetWindowRect((HWND) GetHWND(),&rect) ; - pt.x -= rect.left ; - pt.y -= rect.top ; + pMeasureStruct->itemWidth = w; + pMeasureStruct->itemHeight = h; - event.m_x = pt.x; event.m_y = pt.y; + return rc; + } - if (GetEventHandler()->ProcessEvent(event)) - return TRUE; - else - return FALSE; + wxControl *item = wxDynamicCast(FindItem(id), wxControl); + if ( item ) + { + return item->MSWOnMeasure(itemStruct); } - else - return FALSE; +#else + wxUnusedVar(id); + wxUnusedVar(itemStruct); +#endif // wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE + + return false; } -void wxWindow::MSWOnJoyDown(int joystick, int x, int y, WXUINT flags) +// --------------------------------------------------------------------------- +// colours and palettes +// --------------------------------------------------------------------------- + +bool wxWindowMSW::HandleSysColorChange() { - int buttons = 0; - int change = 0; - if (flags & JOY_BUTTON1CHG) - change = wxJOY_BUTTON1; - if (flags & JOY_BUTTON2CHG) - change = wxJOY_BUTTON2; - if (flags & JOY_BUTTON3CHG) - change = wxJOY_BUTTON3; - if (flags & JOY_BUTTON4CHG) - change = wxJOY_BUTTON4; + wxSysColourChangedEvent event; + event.SetEventObject(this); - if (flags & JOY_BUTTON1) - buttons |= wxJOY_BUTTON1; - if (flags & JOY_BUTTON2) - buttons |= wxJOY_BUTTON2; - if (flags & JOY_BUTTON3) - buttons |= wxJOY_BUTTON3; - if (flags & JOY_BUTTON4) - buttons |= wxJOY_BUTTON4; + (void)GetEventHandler()->ProcessEvent(event); - wxJoystickEvent event(wxEVT_JOY_BUTTON_DOWN, buttons, joystick, change); - event.SetPosition(wxPoint(x, y)); + // always let the system carry on the default processing to allow the + // native controls to react to the colours update + return false; +} + +bool wxWindowMSW::HandleDisplayChange() +{ + wxDisplayChangedEvent event; event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); + return GetEventHandler()->ProcessEvent(event); } -void wxWindow::MSWOnJoyUp(int joystick, int x, int y, WXUINT flags) -{ - int buttons = 0; - int change = 0; - if (flags & JOY_BUTTON1CHG) - change = wxJOY_BUTTON1; - if (flags & JOY_BUTTON2CHG) - change = wxJOY_BUTTON2; - if (flags & JOY_BUTTON3CHG) - change = wxJOY_BUTTON3; - if (flags & JOY_BUTTON4CHG) - change = wxJOY_BUTTON4; +#ifndef __WXMICROWIN__ - if (flags & JOY_BUTTON1) - buttons |= wxJOY_BUTTON1; - if (flags & JOY_BUTTON2) - buttons |= wxJOY_BUTTON2; - if (flags & JOY_BUTTON3) - buttons |= wxJOY_BUTTON3; - if (flags & JOY_BUTTON4) - buttons |= wxJOY_BUTTON4; +bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush, WXHDC hDC, WXHWND hWnd) +{ +#if !wxUSE_CONTROLS || defined(__WXUNIVERSAL__) + wxUnusedVar(hDC); + wxUnusedVar(hWnd); +#else + wxControl *item = wxDynamicCast(FindItemByHWND(hWnd, true), wxControl); - wxJoystickEvent event(wxEVT_JOY_BUTTON_UP, buttons, joystick, change); - event.SetPosition(wxPoint(x, y)); - event.SetEventObject(this); + if ( item ) + *brush = item->MSWControlColor(hDC, hWnd); + else +#endif // wxUSE_CONTROLS + *brush = NULL; - GetEventHandler()->ProcessEvent(event); + return *brush != NULL; } -void wxWindow::MSWOnJoyMove(int joystick, int x, int y, WXUINT flags) +#endif // __WXMICROWIN__ + +bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange) { - int buttons = 0; - if (flags & JOY_BUTTON1) - buttons |= wxJOY_BUTTON1; - if (flags & JOY_BUTTON2) - buttons |= wxJOY_BUTTON2; - if (flags & JOY_BUTTON3) - buttons |= wxJOY_BUTTON3; - if (flags & JOY_BUTTON4) - buttons |= wxJOY_BUTTON4; +#if wxUSE_PALETTE + // same as below except we don't respond to our own messages + if ( hWndPalChange != GetHWND() ) + { + // check to see if we our our parents have a custom palette + wxWindowMSW *win = this; + while ( win && !win->HasCustomPalette() ) + { + win = win->GetParent(); + } - wxJoystickEvent event(wxEVT_JOY_MOVE, buttons, joystick, 0); - event.SetPosition(wxPoint(x, y)); + if ( win && win->HasCustomPalette() ) + { + // realize the palette to see whether redrawing is needed + HDC hdc = ::GetDC((HWND) hWndPalChange); + win->m_palette.SetHPALETTE((WXHPALETTE) + ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE)); + + int result = ::RealizePalette(hdc); + + // restore the palette (before releasing the DC) + win->m_palette.SetHPALETTE((WXHPALETTE) + ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE)); + ::RealizePalette(hdc); + ::ReleaseDC((HWND) hWndPalChange, hdc); + + // now check for the need to redraw + if (result > 0) + ::InvalidateRect((HWND) hWndPalChange, NULL, TRUE); + } + + } +#endif // wxUSE_PALETTE + + wxPaletteChangedEvent event(GetId()); event.SetEventObject(this); + event.SetChangedWindow(wxFindWinFromHandle(hWndPalChange)); - GetEventHandler()->ProcessEvent(event); + return GetEventHandler()->ProcessEvent(event); } -void wxWindow::MSWOnJoyZMove(int joystick, int z, WXUINT flags) +bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture) { - int buttons = 0; - if (flags & JOY_BUTTON1) - buttons |= wxJOY_BUTTON1; - if (flags & JOY_BUTTON2) - buttons |= wxJOY_BUTTON2; - if (flags & JOY_BUTTON3) - buttons |= wxJOY_BUTTON3; - if (flags & JOY_BUTTON4) - buttons |= wxJOY_BUTTON4; + // notify windows on the capture stack about lost capture + // (see http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863): + wxWindowBase::NotifyCaptureLost(); - wxJoystickEvent event(wxEVT_JOY_ZMOVE, buttons, joystick, 0); - event.SetZPosition(z); + wxWindow *win = wxFindWinFromHandle(hWndGainedCapture); + wxMouseCaptureChangedEvent event(GetId(), win); event.SetEventObject(this); - - GetEventHandler()->ProcessEvent(event); + return GetEventHandler()->ProcessEvent(event); } -void wxWindow::MSWOnVScroll(WXWORD wParam, WXWORD pos, WXHWND control) +bool wxWindowMSW::HandleSettingChange(WXWPARAM wParam, WXLPARAM lParam) { - if (control) - { - wxWindow *child = wxFindWinFromHandle(control); - if ( child ) - child->MSWOnVScroll(wParam, pos, control); - return; - } - - wxScrollEvent event; - event.SetPosition(pos); - event.SetOrientation(wxVERTICAL); - event.m_eventObject = this; + // despite MSDN saying "(This message cannot be sent directly to a window.)" + // we need to send this to child windows (it is only sent to top-level + // windows) so {list,tree}ctrls can adjust their font size if necessary + // this is exactly how explorer does it to enable the font size changes - switch ( wParam ) + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + while ( node ) { - case SB_TOP: - event.m_eventType = wxEVT_SCROLL_TOP; - break; - - case SB_BOTTOM: - event.m_eventType = wxEVT_SCROLL_BOTTOM; - break; + // top-level windows already get this message from the system + wxWindow *win = node->GetData(); + if ( !win->IsTopLevel() ) + { + ::SendMessage(GetHwndOf(win), WM_SETTINGCHANGE, wParam, lParam); + } - case SB_LINEUP: - event.m_eventType = wxEVT_SCROLL_LINEUP; - break; + node = node->GetNext(); + } - case SB_LINEDOWN: - event.m_eventType = wxEVT_SCROLL_LINEDOWN; - break; + // let the system handle it + return false; +} - case SB_PAGEUP: - event.m_eventType = wxEVT_SCROLL_PAGEUP; - break; +bool wxWindowMSW::HandleQueryNewPalette() +{ - case SB_PAGEDOWN: - event.m_eventType = wxEVT_SCROLL_PAGEDOWN; - break; +#if wxUSE_PALETTE + // check to see if we our our parents have a custom palette + wxWindowMSW *win = this; + while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent(); + if (win->HasCustomPalette()) { + /* realize the palette to see whether redrawing is needed */ + HDC hdc = ::GetDC((HWND) GetHWND()); + win->m_palette.SetHPALETTE( (WXHPALETTE) + ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), FALSE) ); - case SB_THUMBTRACK: - case SB_THUMBPOSITION: - event.m_eventType = wxEVT_SCROLL_THUMBTRACK; - break; + int result = ::RealizePalette(hdc); + /* restore the palette (before releasing the DC) */ + win->m_palette.SetHPALETTE( (WXHPALETTE) + ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), TRUE) ); + ::RealizePalette(hdc); + ::ReleaseDC((HWND) GetHWND(), hdc); + /* now check for the need to redraw */ + if (result > 0) + ::InvalidateRect((HWND) GetHWND(), NULL, TRUE); + } +#endif // wxUSE_PALETTE - default: - return; - break; - } + wxQueryNewPaletteEvent event(GetId()); + event.SetEventObject(this); - if (!GetEventHandler()->ProcessEvent(event)) - Default(); + return GetEventHandler()->ProcessEvent(event) && event.GetPaletteRealized(); } -void wxWindow::MSWOnHScroll( WXWORD wParam, WXWORD pos, WXHWND control) +// Responds to colour changes: passes event on to children. +void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event)) { - if (control) + // the top level window also reset the standard colour map as it might have + // changed (there is no need to do it for the non top level windows as we + // only have to do it once) + if ( IsTopLevel() ) { - wxWindow *child = wxFindWinFromHandle(control); - if ( child ) { - child->MSWOnHScroll(wParam, pos, control); + // FIXME-MT + gs_hasStdCmap = false; + } + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + while ( node ) + { + // Only propagate to non-top-level windows because Windows already + // sends this event to all top-level ones + wxWindow *win = node->GetData(); + if ( !win->IsTopLevel() ) + { + // we need to send the real WM_SYSCOLORCHANGE and not just trigger + // EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for + // the standard controls + ::SendMessage(GetHwndOf(win), WM_SYSCOLORCHANGE, 0, 0); + } + + node = node->GetNext(); + } +} + +extern wxCOLORMAP *wxGetStdColourMap() +{ + static COLORREF s_stdColours[wxSTD_COL_MAX]; + static wxCOLORMAP s_cmap[wxSTD_COL_MAX]; - return; - } - } - else { - wxScrollEvent event; - event.SetPosition(pos); - event.SetOrientation(wxHORIZONTAL); - event.m_eventObject = this; + if ( !gs_hasStdCmap ) + { + static bool s_coloursInit = false; - switch ( wParam ) + if ( !s_coloursInit ) { - case SB_TOP: - event.m_eventType = wxEVT_SCROLL_TOP; - break; - - case SB_BOTTOM: - event.m_eventType = wxEVT_SCROLL_BOTTOM; - break; + // When a bitmap is loaded, the RGB values can change (apparently + // because Windows adjusts them to care for the old programs always + // using 0xc0c0c0 while the transparent colour for the new Windows + // versions is different). But we do this adjustment ourselves so + // we want to avoid Windows' "help" and for this we need to have a + // reference bitmap which can tell us what the RGB values change + // to. + wxLogNull logNo; // suppress error if we couldn't load the bitmap + wxBitmap stdColourBitmap(_T("wxBITMAP_STD_COLOURS")); + if ( stdColourBitmap.Ok() ) + { + // the pixels in the bitmap must correspond to wxSTD_COL_XXX! + wxASSERT_MSG( stdColourBitmap.GetWidth() == wxSTD_COL_MAX, + _T("forgot to update wxBITMAP_STD_COLOURS!") ); - case SB_LINEUP: - event.m_eventType = wxEVT_SCROLL_LINEUP; - break; + wxMemoryDC memDC; + memDC.SelectObject(stdColourBitmap); - case SB_LINEDOWN: - event.m_eventType = wxEVT_SCROLL_LINEDOWN; - break; + wxColour colour; + for ( size_t i = 0; i < WXSIZEOF(s_stdColours); i++ ) + { + memDC.GetPixel(i, 0, &colour); + s_stdColours[i] = wxColourToRGB(colour); + } + } + else // wxBITMAP_STD_COLOURS couldn't be loaded + { + s_stdColours[0] = RGB(000,000,000); // black + s_stdColours[1] = RGB(128,128,128); // dark grey + s_stdColours[2] = RGB(192,192,192); // light grey + s_stdColours[3] = RGB(255,255,255); // white + //s_stdColours[4] = RGB(000,000,255); // blue + //s_stdColours[5] = RGB(255,000,255); // magenta + } - case SB_PAGEUP: - event.m_eventType = wxEVT_SCROLL_PAGEUP; - break; + s_coloursInit = true; + } - case SB_PAGEDOWN: - event.m_eventType = wxEVT_SCROLL_PAGEDOWN; - break; + gs_hasStdCmap = true; - case SB_THUMBTRACK: - case SB_THUMBPOSITION: - event.m_eventType = wxEVT_SCROLL_THUMBTRACK; - break; + // create the colour map +#define INIT_CMAP_ENTRY(col) \ + s_cmap[wxSTD_COL_##col].from = s_stdColours[wxSTD_COL_##col]; \ + s_cmap[wxSTD_COL_##col].to = ::GetSysColor(COLOR_##col) - default: - return; - } + INIT_CMAP_ENTRY(BTNTEXT); + INIT_CMAP_ENTRY(BTNSHADOW); + INIT_CMAP_ENTRY(BTNFACE); + INIT_CMAP_ENTRY(BTNHIGHLIGHT); - if ( GetEventHandler()->ProcessEvent(event) ) - return; +#undef INIT_CMAP_ENTRY } - // call the default WM_HSCROLL handler: it's non trivial in some common - // controls (up-down control for example) - Default(); + return s_cmap; } -void wxWindow::MSWOnShow(bool show, int status) -{ - wxShowEvent event(GetId(), show); - event.m_eventObject = this; - GetEventHandler()->ProcessEvent(event); -} +// --------------------------------------------------------------------------- +// painting +// --------------------------------------------------------------------------- -bool wxWindow::MSWOnInitDialog(WXHWND WXUNUSED(hWndFocus)) +bool wxWindowMSW::HandlePaint() { - wxInitDialogEvent event(GetId()); - event.m_eventObject = this; - GetEventHandler()->ProcessEvent(event); - return TRUE; + HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle + if ( !hRegion ) + wxLogLastError(wxT("CreateRectRgn")); + if ( ::GetUpdateRgn(GetHwnd(), hRegion, FALSE) == ERROR ) + wxLogLastError(wxT("GetUpdateRgn")); + + m_updateRegion = wxRegion((WXHRGN) hRegion); + + wxPaintEvent event(m_windowId); + event.SetEventObject(this); + + bool processed = GetEventHandler()->ProcessEvent(event); + + // note that we must generate NC event after the normal one as otherwise + // BeginPaint() will happily overwrite our decorations with the background + // colour + wxNcPaintEvent eventNc(m_windowId); + eventNc.SetEventObject(this); + GetEventHandler()->ProcessEvent(eventNc); + + return processed; } -void wxWindow::InitDialog() +// Can be called from an application's OnPaint handler +void wxWindowMSW::OnPaint(wxPaintEvent& event) { - wxInitDialogEvent event(GetId()); - event.SetEventObject( this ); - GetEventHandler()->ProcessEvent(event); +#ifdef __WXUNIVERSAL__ + event.Skip(); +#else + HDC hDC = (HDC) wxPaintDC::FindDCInCache((wxWindow*) event.GetEventObject()); + if (hDC != 0) + { + MSWDefWindowProc(WM_PAINT, (WPARAM) hDC, 0); + } +#endif } -// Default init dialog behaviour is to transfer data to window -void wxWindow::OnInitDialog(wxInitDialogEvent& event) +bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc) { - TransferDataToWindow(); + wxDCTemp dc(hdc, GetClientSize()); + + dc.SetHDC(hdc); + dc.SetWindow((wxWindow *)this); + + wxEraseEvent event(m_windowId, &dc); + event.SetEventObject(this); + bool rc = GetEventHandler()->ProcessEvent(event); + + // must be called manually as ~wxDC doesn't do anything for wxDCTemp + dc.SelectOldObjects(hdc); + + return rc; } -void wxGetCharSize(WXHWND wnd, int *x, int *y,wxFont *the_font) +void wxWindowMSW::OnEraseBackground(wxEraseEvent& event) { - TEXTMETRIC tm; - HDC dc = ::GetDC((HWND) wnd); - HFONT fnt =0; - HFONT was = 0; - if (the_font) + // standard non top level controls (i.e. except the dialogs) always erase + // their background themselves in HandleCtlColor() or have some control- + // specific ways to set the colours (common controls) + if ( IsOfStandardClass() && !IsTopLevel() ) { - // the_font->UseResource(); - // the_font->RealizeResource(); - fnt = (HFONT)the_font->GetResourceHandle(); - if ( fnt ) - was = (HFONT) SelectObject(dc,fnt) ; + event.Skip(); + return; } - GetTextMetrics(dc, &tm); - if (the_font && fnt && was) + + if ( GetBackgroundStyle() == wxBG_STYLE_CUSTOM ) { - SelectObject(dc,was) ; + // don't skip the event here, custom background means that the app + // is drawing it itself in its OnPaint(), so don't draw it at all + // now to avoid flicker + return; } - ReleaseDC((HWND)wnd, dc); - *x = tm.tmAveCharWidth; - *y = tm.tmHeight + tm.tmExternalLeading; - // if (the_font) - // the_font->ReleaseResource(); -} -// Returns 0 if was a normal ASCII value, not a special key. This indicates that -// the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead. -int wxCharCodeMSWToWX(int keySym) -{ - int id = 0; - switch (keySym) - { - case VK_CANCEL: id = WXK_CANCEL; break; - case VK_BACK: id = WXK_BACK; break; - case VK_TAB: id = WXK_TAB; break; - case VK_CLEAR: id = WXK_CLEAR; break; - case VK_RETURN: id = WXK_RETURN; break; - case VK_SHIFT: id = WXK_SHIFT; break; - case VK_CONTROL: id = WXK_CONTROL; break; - case VK_MENU : id = WXK_MENU; break; - case VK_PAUSE: id = WXK_PAUSE; break; - case VK_SPACE: id = WXK_SPACE; break; - case VK_ESCAPE: id = WXK_ESCAPE; break; - case VK_PRIOR: id = WXK_PRIOR; break; - case VK_NEXT : id = WXK_NEXT; break; - case VK_END: id = WXK_END; break; - case VK_HOME : id = WXK_HOME; break; - case VK_LEFT : id = WXK_LEFT; break; - case VK_UP: id = WXK_UP; break; - case VK_RIGHT: id = WXK_RIGHT; break; - case VK_DOWN : id = WXK_DOWN; break; - case VK_SELECT: id = WXK_SELECT; break; - case VK_PRINT: id = WXK_PRINT; break; - case VK_EXECUTE: id = WXK_EXECUTE; break; - case VK_INSERT: id = WXK_INSERT; break; - case VK_DELETE: id = WXK_DELETE; break; - case VK_HELP : id = WXK_HELP; break; - case VK_NUMPAD0: id = WXK_NUMPAD0; break; - case VK_NUMPAD1: id = WXK_NUMPAD1; break; - case VK_NUMPAD2: id = WXK_NUMPAD2; break; - case VK_NUMPAD3: id = WXK_NUMPAD3; break; - case VK_NUMPAD4: id = WXK_NUMPAD4; break; - case VK_NUMPAD5: id = WXK_NUMPAD5; break; - case VK_NUMPAD6: id = WXK_NUMPAD6; break; - case VK_NUMPAD7: id = WXK_NUMPAD7; break; - case VK_NUMPAD8: id = WXK_NUMPAD8; break; - case VK_NUMPAD9: id = WXK_NUMPAD9; break; - case VK_MULTIPLY: id = WXK_MULTIPLY; break; - case VK_ADD: id = WXK_ADD; break; - case VK_SUBTRACT: id = WXK_SUBTRACT; break; - case VK_DECIMAL: id = WXK_DECIMAL; break; - case VK_DIVIDE: id = WXK_DIVIDE; break; - case VK_F1: id = WXK_F1; break; - case VK_F2: id = WXK_F2; break; - case VK_F3: id = WXK_F3; break; - case VK_F4: id = WXK_F4; break; - case VK_F5: id = WXK_F5; break; - case VK_F6: id = WXK_F6; break; - case VK_F7: id = WXK_F7; break; - case VK_F8: id = WXK_F8; break; - case VK_F9: id = WXK_F9; break; - case VK_F10: id = WXK_F10; break; - case VK_F11: id = WXK_F11; break; - case VK_F12: id = WXK_F12; break; - case VK_F13: id = WXK_F13; break; - case VK_F14: id = WXK_F14; break; - case VK_F15: id = WXK_F15; break; - case VK_F16: id = WXK_F16; break; - case VK_F17: id = WXK_F17; break; - case VK_F18: id = WXK_F18; break; - case VK_F19: id = WXK_F19; break; - case VK_F20: id = WXK_F20; break; - case VK_F21: id = WXK_F21; break; - case VK_F22: id = WXK_F22; break; - case VK_F23: id = WXK_F23; break; - case VK_F24: id = WXK_F24; break; - case VK_NUMLOCK: id = WXK_NUMLOCK; break; - case VK_SCROLL: id = WXK_SCROLL; break; - default: - { - return 0; - } - } - return id; -} - -int wxCharCodeWXToMSW(int id, bool *isVirtual) -{ - *isVirtual = TRUE; - int keySym = 0; - switch (id) - { - case WXK_CANCEL: keySym = VK_CANCEL; break; - case WXK_CLEAR: keySym = VK_CLEAR; break; - case WXK_SHIFT: keySym = VK_SHIFT; break; - case WXK_CONTROL: keySym = VK_CONTROL; break; - case WXK_MENU : keySym = VK_MENU; break; - case WXK_PAUSE: keySym = VK_PAUSE; break; - case WXK_PRIOR: keySym = VK_PRIOR; break; - case WXK_NEXT : keySym = VK_NEXT; break; - case WXK_END: keySym = VK_END; break; - case WXK_HOME : keySym = VK_HOME; break; - case WXK_LEFT : keySym = VK_LEFT; break; - case WXK_UP: keySym = VK_UP; break; - case WXK_RIGHT: keySym = VK_RIGHT; break; - case WXK_DOWN : keySym = VK_DOWN; break; - case WXK_SELECT: keySym = VK_SELECT; break; - case WXK_PRINT: keySym = VK_PRINT; break; - case WXK_EXECUTE: keySym = VK_EXECUTE; break; - case WXK_INSERT: keySym = VK_INSERT; break; - case WXK_DELETE: keySym = VK_DELETE; break; - case WXK_HELP : keySym = VK_HELP; break; - case WXK_NUMPAD0: keySym = VK_NUMPAD0; break; - case WXK_NUMPAD1: keySym = VK_NUMPAD1; break; - case WXK_NUMPAD2: keySym = VK_NUMPAD2; break; - case WXK_NUMPAD3: keySym = VK_NUMPAD3; break; - case WXK_NUMPAD4: keySym = VK_NUMPAD4; break; - case WXK_NUMPAD5: keySym = VK_NUMPAD5; break; - case WXK_NUMPAD6: keySym = VK_NUMPAD6; break; - case WXK_NUMPAD7: keySym = VK_NUMPAD7; break; - case WXK_NUMPAD8: keySym = VK_NUMPAD8; break; - case WXK_NUMPAD9: keySym = VK_NUMPAD9; break; - case WXK_MULTIPLY: keySym = VK_MULTIPLY; break; - case WXK_ADD: keySym = VK_ADD; break; - case WXK_SUBTRACT: keySym = VK_SUBTRACT; break; - case WXK_DECIMAL: keySym = VK_DECIMAL; break; - case WXK_DIVIDE: keySym = VK_DIVIDE; break; - case WXK_F1: keySym = VK_F1; break; - case WXK_F2: keySym = VK_F2; break; - case WXK_F3: keySym = VK_F3; break; - case WXK_F4: keySym = VK_F4; break; - case WXK_F5: keySym = VK_F5; break; - case WXK_F6: keySym = VK_F6; break; - case WXK_F7: keySym = VK_F7; break; - case WXK_F8: keySym = VK_F8; break; - case WXK_F9: keySym = VK_F9; break; - case WXK_F10: keySym = VK_F10; break; - case WXK_F11: keySym = VK_F11; break; - case WXK_F12: keySym = VK_F12; break; - case WXK_F13: keySym = VK_F13; break; - case WXK_F14: keySym = VK_F14; break; - case WXK_F15: keySym = VK_F15; break; - case WXK_F16: keySym = VK_F16; break; - case WXK_F17: keySym = VK_F17; break; - case WXK_F18: keySym = VK_F18; break; - case WXK_F19: keySym = VK_F19; break; - case WXK_F20: keySym = VK_F20; break; - case WXK_F21: keySym = VK_F21; break; - case WXK_F22: keySym = VK_F22; break; - case WXK_F23: keySym = VK_F23; break; - case WXK_F24: keySym = VK_F24; break; - case WXK_NUMLOCK: keySym = VK_NUMLOCK; break; - case WXK_SCROLL: keySym = VK_SCROLL; break; - default: - { - *isVirtual = FALSE; - keySym = id; - break; - } + // do default background painting + if ( !DoEraseBackground(GetHdcOf(*event.GetDC())) ) + { + // let the system paint the background + event.Skip(); } - return keySym; } -// Caret manipulation -void wxWindow::CreateCaret(int w, int h) +bool wxWindowMSW::DoEraseBackground(WXHDC hDC) { - m_caretWidth = w; - m_caretHeight = h; - m_caretEnabled = TRUE; + HBRUSH hbr = (HBRUSH)MSWGetBgBrush(hDC); + if ( !hbr ) + return false; + + wxFillRect(GetHwnd(), (HDC)hDC, hbr); + + return true; } -void wxWindow::CreateCaret(const wxBitmap *WXUNUSED(bitmap)) +WXHBRUSH +wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC), WXHWND hWnd) { - // Not implemented + if ( m_hasBgCol ) + { + // our background colour applies to: + // 1. this window itself, always + // 2. all children unless the colour is "not inheritable" + // 3. even if it is not inheritable, our immediate transparent + // children should still inherit it -- but not any transparent + // children because it would look wrong if a child of non + // transparent child would show our bg colour when the child itself + // does not + wxWindow *win = wxFindWinFromHandle(hWnd); + if ( win == this || + m_inheritBgCol || + (win && win->HasTransparentBackground() && + win->GetParent() == this) ) + { + // draw children with the same colour as the parent + wxBrush * + brush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()); + + return (WXHBRUSH)GetHbrushOf(*brush); + } + } + + return 0; } -void wxWindow::ShowCaret(bool show) +WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC, WXHWND hWndToPaint) { - if (m_caretEnabled) + if ( !hWndToPaint ) + hWndToPaint = GetHWND(); + + for ( wxWindowMSW *win = this; win; win = win->GetParent() ) { - if (show) - ::ShowCaret((HWND) GetHWND()); - else - ::HideCaret((HWND) GetHWND()); - m_caretShown = show; + WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, hWndToPaint); + if ( hBrush ) + return hBrush; + + // background is not inherited beyond top level windows + if ( win->IsTopLevel() ) + break; } + + return 0; } -void wxWindow::DestroyCaret() +bool wxWindowMSW::HandlePrintClient(WXHDC hDC) { - m_caretEnabled = FALSE; + // we receive this message when DrawThemeParentBackground() is + // called from def window proc of several controls under XP and we + // must draw properly themed background here + // + // note that naively I'd expect filling the client rect with the + // brush returned by MSWGetBgBrush() work -- but for some reason it + // doesn't and we have to call parents MSWPrintChild() which is + // supposed to call DrawThemeBackground() with appropriate params + // + // also note that in this case lParam == PRF_CLIENT but we're + // clearly expected to paint the background and nothing else! + + if ( IsTopLevel() || InheritsBackgroundColour() ) + return false; + + // sometimes we don't want the parent to handle it at all, instead + // return whatever value this window wants + if ( !MSWShouldPropagatePrintChild() ) + return MSWPrintChild(hDC, (wxWindow *)this); + + for ( wxWindow *win = GetParent(); win; win = win->GetParent() ) + { + if ( win->MSWPrintChild(hDC, (wxWindow *)this) ) + return true; + + if ( win->IsTopLevel() || win->InheritsBackgroundColour() ) + break; + } + + return false; } -void wxWindow::SetCaretPos(int x, int y) +// --------------------------------------------------------------------------- +// moving and resizing +// --------------------------------------------------------------------------- + +bool wxWindowMSW::HandleMinimize() { - ::SetCaretPos(x, y); + wxIconizeEvent event(m_windowId); + event.SetEventObject(this); + + return GetEventHandler()->ProcessEvent(event); } -void wxWindow::GetCaretPos(int *x, int *y) const +bool wxWindowMSW::HandleMaximize() { - POINT point; - ::GetCaretPos(&point); - *x = point.x; - *y = point.y; + wxMaximizeEvent event(m_windowId); + event.SetEventObject(this); + + return GetEventHandler()->ProcessEvent(event); } -wxWindow *wxGetActiveWindow() +bool wxWindowMSW::HandleMove(int x, int y) { - HWND hWnd = GetActiveWindow(); - if (hWnd != 0) - { - return wxFindWinFromHandle((WXHWND) hWnd); - } - return NULL; -} + wxPoint point(x,y); + wxMoveEvent event(point, m_windowId); + event.SetEventObject(this); -// 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; -static FARPROC wxTheKeyboardHookProc = 0; -int APIENTRY _EXPORT -wxKeyboardHook(int nCode, WORD wParam, DWORD lParam); + return GetEventHandler()->ProcessEvent(event); +} -void wxSetKeyboardHook(bool doIt) +bool wxWindowMSW::HandleMoving(wxRect& rect) { - if (doIt) - { - wxTheKeyboardHookProc = MakeProcInstance((FARPROC) wxKeyboardHook, wxGetInstance()); - wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(), -#if defined(__WIN32__) && !defined(__TWIN32__) - GetCurrentThreadId()); - // (DWORD)GetCurrentProcess()); // This is another possibility. Which is right? -#else - GetCurrentTask()); -#endif - } - else - { - UnhookWindowsHookEx(wxTheKeyboardHook); - FreeProcInstance(wxTheKeyboardHookProc); - } + wxMoveEvent event(rect, m_windowId); + event.SetEventObject(this); + + bool rc = GetEventHandler()->ProcessEvent(event); + if (rc) + rect = event.GetRect(); + return rc; } -int APIENTRY _EXPORT -wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) +bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) { - DWORD hiWord = HIWORD(lParam); - if (nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0)) +#if USE_DEFERRED_SIZING + // when we resize this window, its children are probably going to be + // repositioned as well, prepare to use DeferWindowPos() for them + int numChildren = 0; + for ( HWND child = ::GetWindow(GetHwndOf(this), GW_CHILD); + child; + child = ::GetWindow(child, GW_HWNDNEXT) ) { - int id; - if ((id = wxCharCodeMSWToWX(wParam)) != 0) - { - wxKeyEvent event(wxEVT_CHAR_HOOK); - if ((HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN) - event.m_altDown = TRUE; + numChildren ++; + } - 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.SetTimestamp(wxApp::sm_lastMessageTime); + // Protect against valid m_hDWP being overwritten + bool useDefer = false; - wxWindow *win = wxGetActiveWindow(); - if (win) - { - if (win->GetEventHandler()->ProcessEvent(event)) - return 1; - } - else + if ( numChildren > 1 ) + { + if (!m_hDWP) + { + m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren); + if ( !m_hDWP ) { - if ( wxTheApp && wxTheApp->ProcessEvent(event) ) - return 1; + wxLogLastError(_T("BeginDeferWindowPos")); } + if (m_hDWP) + useDefer = true; } } - return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam); -} +#endif // USE_DEFERRED_SIZING -void wxWindow::SetSizeHints(int minW, int minH, int maxW, int maxH, int WXUNUSED(incW), int WXUNUSED(incH)) -{ - m_minSizeX = minW; - m_minSizeY = minH; - m_maxSizeX = maxW; - m_maxSizeY = maxH; -} + // update this window size + bool processed = false; + switch ( wParam ) + { + default: + wxFAIL_MSG( _T("unexpected WM_SIZE parameter") ); + // fall through nevertheless -void wxWindow::Centre(int direction) -{ - int x, y, width, height, panel_width, panel_height, new_x, new_y; + case SIZE_MAXHIDE: + case SIZE_MAXSHOW: + // we're not interested in these messages at all + break; - wxWindow *father = (wxWindow *)GetParent(); - if (!father) - return; + case SIZE_MINIMIZED: + processed = HandleMinimize(); + break; - father->GetClientSize(&panel_width, &panel_height); - GetSize(&width, &height); - GetPosition(&x, &y); + case SIZE_MAXIMIZED: + /* processed = */ HandleMaximize(); + // fall through to send a normal size event as well - new_x = -1; - new_y = -1; + case SIZE_RESTORED: + // don't use w and h parameters as they specify the client size + // while according to the docs EVT_SIZE handler is supposed to + // receive the total size + wxSizeEvent event(GetSize(), m_windowId); + event.SetEventObject(this); - if (direction & wxHORIZONTAL) - new_x = (int)((panel_width - width)/2); + processed = GetEventHandler()->ProcessEvent(event); + } - if (direction & wxVERTICAL) - new_y = (int)((panel_height - height)/2); +#if USE_DEFERRED_SIZING + // and finally change the positions of all child windows at once + if ( useDefer && m_hDWP ) + { + // reset m_hDWP to NULL so that child windows don't try to use our + // m_hDWP after we call EndDeferWindowPos() on it (this shouldn't + // happen anyhow normally but who knows what weird flow of control we + // may have depending on what the users EVT_SIZE handler does...) + HDWP hDWP = (HDWP)m_hDWP; + m_hDWP = NULL; + + // do put all child controls in place at once + if ( !::EndDeferWindowPos(hDWP) ) + { + wxLogLastError(_T("EndDeferWindowPos")); + } - SetSize(new_x, new_y, -1, -1); + // Reset our children's pending pos/size values. + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindowMSW *child = node->GetData(); + child->m_pendingPosition = wxDefaultPosition; + child->m_pendingSize = wxDefaultSize; + } + } +#endif // USE_DEFERRED_SIZING + return processed; } -void wxWindow::WarpPointer (int x_pos, int y_pos) +bool wxWindowMSW::HandleSizing(wxRect& rect) { - // Move the pointer to (x_pos,y_pos) coordinates. They are expressed in - // pixel coordinates, relatives to the canvas -- So, we first need to - // substract origin of the window, then convert to screen position - - int x = x_pos; int y = y_pos; - RECT rect; - GetWindowRect ((HWND) GetHWND(), &rect); - - x += rect.left; - y += rect.top; + wxSizeEvent event(rect, m_windowId); + event.SetEventObject(this); - SetCursorPos (x, y); + bool rc = GetEventHandler()->ProcessEvent(event); + if (rc) + rect = event.GetRect(); + return rc; } -void wxWindow::MSWDeviceToLogical (float *x, float *y) const +bool wxWindowMSW::HandleGetMinMaxInfo(void *WXUNUSED_IN_WINCE(mmInfo)) { -} +#ifdef __WXWINCE__ + return false; +#else + MINMAXINFO *info = (MINMAXINFO *)mmInfo; -bool wxWindow::MSWOnEraseBkgnd (WXHDC pDC) -{ - wxDC dc ; + bool rc = false; - dc.SetHDC(pDC); - dc.SetWindow(this); - dc.BeginDrawing(); + int minWidth = GetMinWidth(), + minHeight = GetMinHeight(), + maxWidth = GetMaxWidth(), + maxHeight = GetMaxHeight(); - wxEraseEvent event(m_windowId, &dc); - event.m_eventObject = this; - if (!GetEventHandler()->ProcessEvent(event)) + if ( minWidth != wxDefaultCoord ) { - dc.EndDrawing(); - dc.SelectOldObjects(pDC); - return FALSE; + info->ptMinTrackSize.x = minWidth; + rc = true; } - else + + if ( minHeight != wxDefaultCoord ) { - dc.EndDrawing(); - dc.SelectOldObjects(pDC); + info->ptMinTrackSize.y = minHeight; + rc = true; } - dc.SetHDC((WXHDC) NULL); - return TRUE; -} - -void wxWindow::OnEraseBackground(wxEraseEvent& event) -{ - if (!GetHWND()) - return; - - RECT rect; - ::GetClientRect((HWND) GetHWND(), &rect); - - COLORREF ref = PALETTERGB(m_backgroundColour.Red(), m_backgroundColour.Green(), m_backgroundColour.Blue()) ; - HBRUSH hBrush = ::CreateSolidBrush(ref); - int mode = ::SetMapMode((HDC) event.GetDC()->GetHDC(), MM_TEXT); + if ( maxWidth != wxDefaultCoord ) + { + info->ptMaxTrackSize.x = maxWidth; + rc = true; + } - // ::GetClipBox((HDC) event.GetDC()->GetHDC(), &rect); - ::FillRect ((HDC) event.GetDC()->GetHDC(), &rect, hBrush); - ::DeleteObject(hBrush); - ::SetMapMode((HDC) event.GetDC()->GetHDC(), mode); - /* - // Less efficient version (and doesn't account for scrolling) - int w, h; - GetClientSize(& w, & h); - wxBrush *brush = wxTheBrushList->FindOrCreateBrush(& GetBackgroundColour(), wxSOLID); - event.GetDC()->SetBrush(brush); - event.GetDC()->SetPen(wxTRANSPARENT_PEN); + if ( maxHeight != wxDefaultCoord ) + { + info->ptMaxTrackSize.y = maxHeight; + rc = true; + } - event.GetDC()->DrawRectangle(0, 0, w+1, h+1); - */ + return rc; +#endif } -#if WXWIN_COMPATIBILITY -void wxWindow::SetScrollRange(int orient, int range, bool refresh) +// --------------------------------------------------------------------------- +// command messages +// --------------------------------------------------------------------------- + +bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) { -#if defined(__WIN95__) +#if wxUSE_MENUS_NATIVE + if ( !cmd && wxCurrentPopupMenu ) + { + wxMenu *popupMenu = wxCurrentPopupMenu; + wxCurrentPopupMenu = NULL; + + return popupMenu->MSWCommand(cmd, id); + } +#endif // wxUSE_MENUS_NATIVE - int range1 = range; + wxWindow *win = NULL; - // Try to adjust the range to cope with page size > 1 - // - a Windows API quirk - int pageSize = GetScrollPage(orient); - if ( pageSize > 1 && range > 0) + // first try to find it from HWND - this works even with the broken + // programs using the same ids for different controls + if ( control ) { - range1 += (pageSize - 1); + win = wxFindWinFromHandle(control); } - SCROLLINFO info; - int dir; + // try the id + if ( !win ) + { + // must cast to a signed type before comparing with other ids! + win = FindItem((signed short)id); + } - if (orient == wxHORIZONTAL) { - dir = SB_HORZ; - } else { - dir = SB_VERT; + if ( win ) + { + return win->MSWCommand(cmd, id); } - info.cbSize = sizeof(SCROLLINFO); - info.nPage = pageSize; // Have to set this, or scrollbar goes awry - info.nMin = 0; - info.nMax = range1; - info.nPos = 0; - info.fMask = SIF_RANGE | SIF_PAGE; + // 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 - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - ::SetScrollInfo(hWnd, dir, &info, refresh); -#else - int wOrient ; - if (orient == wxHORIZONTAL) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; + wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED); + event.SetEventObject(this); + event.SetId(id); + event.SetInt(id); - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - ::SetScrollRange(hWnd, wOrient, 0, range, refresh); + return GetEventHandler()->ProcessEvent(event); + } + else + { +#if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__) + // the text ctrl which is logically part of wxSpinCtrl sends WM_COMMAND + // notifications to its parent which we want to reflect back to + // wxSpinCtrl + wxSpinCtrl *spin = wxSpinCtrl::GetSpinForTextCtrl(control); + if ( spin && spin->ProcessTextCommand(cmd, id) ) + return true; +#endif // wxUSE_SPINCTRL + +#if wxUSE_CHOICE && defined(__SMARTPHONE__) + // the listbox ctrl which is logically part of wxChoice sends WM_COMMAND + // notifications to its parent which we want to reflect back to + // wxChoice + wxChoice *choice = wxChoice::GetChoiceForListBox(control); + if ( choice && choice->MSWCommand(cmd, id) ) + return true; #endif + } + + return false; } -void wxWindow::SetScrollPage(int orient, int page, bool refresh) +// --------------------------------------------------------------------------- +// mouse events +// --------------------------------------------------------------------------- + +void wxWindowMSW::InitMouseEvent(wxMouseEvent& event, + int x, int y, + WXUINT flags) { -#if defined(__WIN95__) - SCROLLINFO info; - int dir; + // our client coords are not quite the same as Windows ones + wxPoint pt = GetClientAreaOrigin(); + event.m_x = x - pt.x; + event.m_y = y - pt.y; - if (orient == wxHORIZONTAL) { - dir = SB_HORZ; - m_xThumbSize = page; - } else { - dir = SB_VERT; - m_yThumbSize = page; - } + event.m_shiftDown = (flags & MK_SHIFT) != 0; + event.m_controlDown = (flags & MK_CONTROL) != 0; + 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; - info.cbSize = sizeof(SCROLLINFO); - info.nPage = page; - info.nMin = 0; - info.fMask = SIF_PAGE ; +#ifndef __WXWINCE__ + event.SetTimestamp(::GetMessageTime()); +#endif - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - ::SetScrollInfo(hWnd, dir, &info, refresh); + event.SetEventObject(this); + event.SetId(GetId()); + +#if wxUSE_MOUSEEVENT_HACK + gs_lastMouseEvent.pos = ClientToScreen(wxPoint(x, y)); + gs_lastMouseEvent.type = event.GetEventType(); +#endif // wxUSE_MOUSEEVENT_HACK +} + +#ifdef __WXWINCE__ +// Windows doesn't send the mouse events to the static controls (which are +// transparent in the sense that their WM_NCHITTEST handler returns +// HTTRANSPARENT) at all but we want all controls to receive the mouse events +// and so we manually check if we don't have a child window under mouse and if +// we do, send the event to it instead of the window Windows had sent WM_XXX +// to. +// +// Notice that this is not done for the mouse move events because this could +// (would?) be too slow, but only for clicks which means that the static texts +// still don't get move, enter nor leave events. +static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y) +{ + wxCHECK_MSG( x && y, win, _T("NULL pointer in FindWindowForMouseEvent") ); + + // first try to find a non transparent child: this allows us to send events + // to a static text which is inside a static box, for example + POINT pt = { *x, *y }; + HWND hwnd = GetHwndOf(win), + hwndUnderMouse; + +#ifdef __WXWINCE__ + hwndUnderMouse = ::ChildWindowFromPoint + ( + hwnd, + pt + ); #else - if (orient == wxHORIZONTAL) - m_xThumbSize = page; - else - m_yThumbSize = page; + hwndUnderMouse = ::ChildWindowFromPointEx + ( + hwnd, + pt, + CWP_SKIPINVISIBLE | + CWP_SKIPDISABLED | + CWP_SKIPTRANSPARENT + ); #endif -} -int wxWindow::OldGetScrollRange(int orient) const -{ - int wOrient ; - if (orient == wxHORIZONTAL) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; + if ( !hwndUnderMouse || hwndUnderMouse == hwnd ) + { + // now try any child window at all + hwndUnderMouse = ::ChildWindowFromPoint(hwnd, pt); + } -#if __WATCOMC__ && defined(__WINDOWS_386__) - short minPos, maxPos; -#else - int minPos, maxPos; -#endif - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - { - ::GetScrollRange(hWnd, wOrient, &minPos, &maxPos); -#if defined(__WIN95__) - // Try to adjust the range to cope with page size > 1 - // - a Windows API quirk - int pageSize = GetScrollPage(orient); - if ( pageSize > 1 ) + // check that we have a child window which is susceptible to receive mouse + // events: for this it must be shown and enabled + if ( hwndUnderMouse && + hwndUnderMouse != hwnd && + ::IsWindowVisible(hwndUnderMouse) && + ::IsWindowEnabled(hwndUnderMouse) ) + { + wxWindow *winUnderMouse = wxFindWinFromHandle((WXHWND)hwndUnderMouse); + if ( winUnderMouse ) { - maxPos -= (pageSize - 1); + // translate the mouse coords to the other window coords + win->ClientToScreen(x, y); + winUnderMouse->ScreenToClient(x, y); + + win = winUnderMouse; } -#endif - return maxPos; } - else - return 0; -} -int wxWindow::GetScrollPage(int orient) const -{ - if (orient == wxHORIZONTAL) - return m_xThumbSize; - else - return m_yThumbSize; + return win; } -#endif +#endif // __WXWINCE__ -int wxWindow::GetScrollPos(int orient) const +bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags) { - int wOrient ; - if (orient == wxHORIZONTAL) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; - HWND hWnd = (HWND) GetHWND(); - if (hWnd) + // the mouse events take consecutive IDs from WM_MOUSEFIRST to + // WM_MOUSELAST, so it's enough to subtract WM_MOUSEMOVE == WM_MOUSEFIRST + // from the message id and take the value in the table to get wxWin event + // id + static const wxEventType eventsMouse[] = { - return ::GetScrollPos(hWnd, wOrient); - } - else - return 0; + wxEVT_MOTION, + wxEVT_LEFT_DOWN, + wxEVT_LEFT_UP, + wxEVT_LEFT_DCLICK, + wxEVT_RIGHT_DOWN, + wxEVT_RIGHT_UP, + wxEVT_RIGHT_DCLICK, + wxEVT_MIDDLE_DOWN, + wxEVT_MIDDLE_UP, + wxEVT_MIDDLE_DCLICK + }; + + wxMouseEvent event(eventsMouse[msg - WM_MOUSEMOVE]); + InitMouseEvent(event, x, y, flags); + + return GetEventHandler()->ProcessEvent(event); } -// This now returns the whole range, not just the number -// of positions that we can scroll. -int wxWindow::GetScrollRange(int orient) const +bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags) { - int wOrient ; - if (orient == wxHORIZONTAL) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; + if ( !m_mouseInWindow ) + { + // it would be wrong to assume that just because we get a mouse move + // event that the mouse is inside the window: although this is usually + // true, it is not if we had captured the mouse, so we need to check + // the mouse coordinates here + if ( !HasCapture() || IsMouseInWindow() ) + { + // Generate an ENTER event + m_mouseInWindow = true; + +#ifdef HAVE_TRACKMOUSEEVENT + 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; -#if __WATCOMC__ && defined(__WINDOWS_386__) - short minPos, maxPos; -#else - int minPos, maxPos; -#endif - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - { - ::GetScrollRange(hWnd, wOrient, &minPos, &maxPos); -#if defined(__WIN95__) - // Try to adjust the range to cope with page size > 1 - // - a Windows API quirk - int pageSize = GetScrollThumb(orient); - if ( pageSize > 1 ) + wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM); + if ( dllComCtl32.IsLoaded() ) + { + s_pfn_TrackMouseEvent = (_TrackMouseEvent_t) + dllComCtl32.GetSymbol(_T("_TrackMouseEvent")); + } + + s_initDone = true; + + // 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 trackinfo; + + trackinfo.dwFlags = TME_LEAVE; + trackinfo.hwndTrack = GetHwnd(); + + (*s_pfn_TrackMouseEvent)(&trackinfo); + } +#endif // HAVE_TRACKMOUSEEVENT + + wxMouseEvent event(wxEVT_ENTER_WINDOW); + InitMouseEvent(event, x, y, flags); + + (void)GetEventHandler()->ProcessEvent(event); + } + } +#ifdef HAVE_TRACKMOUSEEVENT + 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 + // send it here if we are using native mouse leave tracking + if ( HasCapture() && !IsMouseInWindow() ) { - maxPos -= (pageSize - 1); + GenerateMouseLeave(); } - // October 10th: new range concept. - maxPos += pageSize; -#endif - - return maxPos; } - else - return 0; -} +#endif // HAVE_TRACKMOUSEEVENT + +#if wxUSE_MOUSEEVENT_HACK + // Windows often generates mouse events even if mouse position hasn't + // changed (http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/66576) + // + // Filter this out as it can result in unexpected behaviour compared to + // other platforms + if ( gs_lastMouseEvent.type == wxEVT_RIGHT_DOWN || + gs_lastMouseEvent.type == wxEVT_LEFT_DOWN || + gs_lastMouseEvent.type == wxEVT_MIDDLE_DOWN || + gs_lastMouseEvent.type == wxEVT_MOTION ) + { + if ( ClientToScreen(wxPoint(x, y)) == gs_lastMouseEvent.pos ) + { + gs_lastMouseEvent.type = wxEVT_MOTION; + + return false; + } + } +#endif // wxUSE_MOUSEEVENT_HACK -int wxWindow::GetScrollThumb(int orient) const -{ - if (orient == wxHORIZONTAL) - return m_xThumbSize; - else - return m_yThumbSize; + return HandleMouseEvent(WM_MOUSEMOVE, x, y, flags); } -void wxWindow::SetScrollPos(int orient, int pos, bool refresh) + +bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam) { -#if defined(__WIN95__) - SCROLLINFO info; - int dir; +#if wxUSE_MOUSEWHEEL + // notice that WM_MOUSEWHEEL position is in screen coords (as it's + // forwarded up to the parent by DefWindowProc()) and not in the client + // ones as all the other messages, translate them to the client coords for + // consistency + const wxPoint + pt = ScreenToClient(wxPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); + wxMouseEvent event(wxEVT_MOUSEWHEEL); + InitMouseEvent(event, pt.x, pt.y, LOWORD(wParam)); + event.m_wheelRotation = (short)HIWORD(wParam); + event.m_wheelDelta = WHEEL_DELTA; + + static int s_linesPerRotation = -1; + if ( s_linesPerRotation == -1 ) + { + if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, + &s_linesPerRotation, 0)) + { + // this is not supposed to happen + wxLogLastError(_T("SystemParametersInfo(GETWHEELSCROLLLINES)")); - if (orient == wxHORIZONTAL) { - dir = SB_HORZ; - } else { - dir = SB_VERT; + // the default is 3, so use it if SystemParametersInfo() failed + s_linesPerRotation = 3; + } } - info.cbSize = sizeof(SCROLLINFO); - info.nPage = 0; - info.nMin = 0; - info.nPos = pos; - info.fMask = SIF_POS ; + event.m_linesPerAction = s_linesPerRotation; + return GetEventHandler()->ProcessEvent(event); - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - ::SetScrollInfo(hWnd, dir, &info, refresh); -#else - int wOrient ; - if (orient == wxHORIZONTAL) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; +#else // !wxUSE_MOUSEWHEEL + wxUnusedVar(wParam); + wxUnusedVar(lParam); - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - ::SetScrollPos(hWnd, wOrient, pos, refresh); -#endif + return false; +#endif // wxUSE_MOUSEWHEEL/!wxUSE_MOUSEWHEEL } -// New function that will replace some of the above. -void wxWindow::SetScrollbar(int orient, int pos, int thumbVisible, - int range, bool refresh) +void wxWindowMSW::GenerateMouseLeave() { -/* -SetScrollPage(orient, thumbVisible, FALSE); + m_mouseInWindow = false; - int oldRange = range - thumbVisible ; - SetScrollRange(orient, oldRange, FALSE); + int state = 0; + if ( wxIsShiftDown() ) + state |= MK_SHIFT; + if ( wxIsCtrlDown() ) + state |= MK_CONTROL; - SetScrollPos(orient, pos, refresh); - */ -#if defined(__WIN95__) - int oldRange = range - thumbVisible ; + // Only the high-order bit should be tested + if ( GetKeyState( VK_LBUTTON ) & (1<<15) ) + state |= MK_LBUTTON; + if ( GetKeyState( VK_MBUTTON ) & (1<<15) ) + state |= MK_MBUTTON; + if ( GetKeyState( VK_RBUTTON ) & (1<<15) ) + state |= MK_RBUTTON; - int range1 = oldRange; - - // Try to adjust the range to cope with page size > 1 - // - a Windows API quirk - int pageSize = thumbVisible; - if ( pageSize > 1 && range > 0) + POINT pt; +#ifdef __WXWINCE__ + if ( !::GetCursorPosWinCE(&pt) ) +#else + if ( !::GetCursorPos(&pt) ) +#endif { - range1 += (pageSize - 1); + wxLogLastError(_T("GetCursorPos")); } - SCROLLINFO info; - int dir; + // we need to have client coordinates here for symmetry with + // wxEVT_ENTER_WINDOW + RECT rect = wxGetWindowRect(GetHwnd()); + pt.x -= rect.left; + pt.y -= rect.top; - if (orient == wxHORIZONTAL) { - dir = SB_HORZ; - } else { - dir = SB_VERT; - } + wxMouseEvent event(wxEVT_LEAVE_WINDOW); + InitMouseEvent(event, pt.x, pt.y, state); - info.cbSize = sizeof(SCROLLINFO); - info.nPage = pageSize; // Have to set this, or scrollbar goes awry - info.nMin = 0; - info.nMax = range1; - info.nPos = pos; - info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; + (void)GetEventHandler()->ProcessEvent(event); +} + +// --------------------------------------------------------------------------- +// keyboard handling +// --------------------------------------------------------------------------- + +// create the key event of the given type for the given key - used by +// HandleChar and HandleKeyDown/Up +wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType, + int id, + WXLPARAM lParam, + WXWPARAM wParam) const +{ + wxKeyEvent event(evType); + event.SetId(GetId()); + event.m_shiftDown = wxIsShiftDown(); + event.m_controlDown = wxIsCtrlDown(); + event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN; + + event.SetEventObject((wxWindow *)this); // const_cast + event.m_keyCode = id; +#if wxUSE_UNICODE + event.m_uniChar = (wxChar) wParam; +#endif + event.m_rawCode = (wxUint32) wParam; + event.m_rawFlags = (wxUint32) lParam; +#ifndef __WXWINCE__ + event.SetTimestamp(::GetMessageTime()); +#endif - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - ::SetScrollInfo(hWnd, dir, &info, refresh); + // translate the position to client coords + POINT pt; +#ifdef __WXWINCE__ + GetCursorPosWinCE(&pt); #else - int wOrient ; - if (orient == wxHORIZONTAL) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; + GetCursorPos(&pt); +#endif + RECT rect; + GetWindowRect(GetHwnd(),&rect); + pt.x -= rect.left; + pt.y -= rect.top; - HWND hWnd = (HWND) GetHWND(); - if (hWnd) + 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 wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII) +{ + int id; + if ( isASCII ) { - ::SetScrollRange(hWnd, wOrient, 0, range, FALSE); - ::SetScrollPos(hWnd, wOrient, pos, refresh); + id = wParam; } -#endif - if (orient == wxHORIZONTAL) { - m_xThumbSize = thumbVisible; - } else { - m_yThumbSize = thumbVisible; + else // we're called from WM_KEYDOWN + { + // don't pass lParam to wxCharCodeMSWToWX() here because we don't want + // to get numpad key codes: CHAR events should use the logical keys + // such as WXK_HOME instead of WXK_NUMPAD_HOME which is for KEY events + id = wxCharCodeMSWToWX(wParam); + if ( id == 0 ) + { + // it's ASCII and will be processed here only when called from + // WM_CHAR (i.e. when isASCII = true), don't process it now + return false; + } } -} -void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) -{ - RECT rect2; - if ( rect ) + wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam, wParam)); + + // the alphanumeric keys produced by pressing AltGr+something on European + // keyboards have both Ctrl and Alt modifiers which may confuse the user + // code as, normally, keys with Ctrl and/or Alt don't result in anything + // alphanumeric, so pretend that there are no modifiers at all (the + // KEY_DOWN event would still have the correct modifiers if they're really + // needed) + if ( event.m_controlDown && event.m_altDown && + (id >= 32 && id < 256) ) { - rect2.left = rect->x; - rect2.top = rect->y; - rect2.right = rect->x + rect->width; - rect2.bottom = rect->y + rect->height; + event.m_controlDown = + event.m_altDown = false; } - if ( rect ) - ::ScrollWindow((HWND) GetHWND(), dx, dy, &rect2, NULL); - else - ::ScrollWindow((HWND) GetHWND(), dx, dy, NULL, NULL); + return GetEventHandler()->ProcessEvent(event); } -void wxWindow::SetFont(const wxFont& font) +bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam) { - m_windowFont = font; - - if (!m_windowFont.Ok()) - return; + int id = wxCharCodeMSWToWX(wParam, lParam); - HWND hWnd = (HWND) GetHWND(); - if (hWnd != 0) + if ( !id ) { - if (m_windowFont.GetResourceHandle()) - SendMessage(hWnd, WM_SETFONT, - (WPARAM)m_windowFont.GetResourceHandle(),TRUE); + // normal ASCII char + id = wParam; } + + wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam, wParam)); + return GetEventHandler()->ProcessEvent(event); } -void wxWindow::SubclassWin(WXHWND hWnd) +bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam) { - wxASSERT_MSG( !m_oldWndProc, "subclassing window twice?" ); + int id = wxCharCodeMSWToWX(wParam, lParam); - wxAssociateWinWithHandle((HWND)hWnd, this); + if ( !id ) + { + // normal ASCII char + id = wParam; + } - m_oldWndProc = (WXFARPROC) GetWindowLong((HWND) hWnd, GWL_WNDPROC); - SetWindowLong((HWND) hWnd, GWL_WNDPROC, (LONG) wxWndProc); + wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam, wParam)); + return GetEventHandler()->ProcessEvent(event); } -void wxWindow::UnsubclassWin() +int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel), + WXLPARAM WXUNUSED_IN_WINCE(lParam)) { - wxRemoveHandleAssociation(this); + // FIXME: implement GetMenuItemCount for WinCE, possibly + // in terms of GetMenuItemInfo +#ifndef __WXWINCE__ + const HMENU hmenu = (HMENU)lParam; - // Restore old Window proc - if ((HWND) GetHWND()) + MENUITEMINFO mii; + wxZeroMemory(mii); + mii.cbSize = sizeof(MENUITEMINFO); + + // we could use MIIM_FTYPE here as we only need to know if the item is + // ownerdrawn or not and not dwTypeData which MIIM_TYPE also returns, but + // MIIM_FTYPE is not supported under Win95 + mii.fMask = MIIM_TYPE | MIIM_DATA; + + // find if we have this letter in any owner drawn item + const int count = ::GetMenuItemCount(hmenu); + for ( int i = 0; i < count; i++ ) { - FARPROC farProc = (FARPROC) GetWindowLong((HWND) GetHWND(), GWL_WNDPROC); - if ((m_oldWndProc != 0) && (farProc != (FARPROC) m_oldWndProc)) + // previous loop iteration could modify it, reset it back before + // calling GetMenuItemInfo() to prevent it from overflowing dwTypeData + mii.cch = 0; + + if ( ::GetMenuItemInfo(hmenu, i, TRUE, &mii) ) + { + if ( mii.fType == MFT_OWNERDRAW ) + { + // dwItemData member of the MENUITEMINFO is a + // pointer to the associated wxMenuItem -- see the + // menu creation code + wxMenuItem *item = (wxMenuItem*)mii.dwItemData; + + const wxChar *p = wxStrchr(item->GetText(), _T('&')); + while ( p++ ) + { + if ( *p == _T('&') ) + { + // this is not the accel char, find the real one + p = wxStrchr(p + 1, _T('&')); + } + else // got the accel char + { + // FIXME-UNICODE: this comparison doesn't risk to work + // for non ASCII accelerator characters I'm afraid, but + // what can we do? + if ( (wchar_t)wxToupper(*p) == (wchar_t)chAccel ) + { + return i; + } + else + { + // this one doesn't match + break; + } + } + } + } + } + else // failed to get the menu text? { - SetWindowLong((HWND) GetHWND(), GWL_WNDPROC, (LONG) m_oldWndProc); - m_oldWndProc = 0; + // it's not fatal, so don't show error, but still log it + wxLogLastError(_T("GetMenuItemInfo")); } } +#endif + return wxNOT_FOUND; } -// Make a Windows extended style from the given wxWindows window style -WXDWORD wxWindow::MakeExtendedStyle(long style, bool eliminateBorders) +bool wxWindowMSW::HandleClipboardEvent( WXUINT nMsg ) { - WXDWORD exStyle = 0; - if ( style & wxTRANSPARENT_WINDOW ) - exStyle |= WS_EX_TRANSPARENT ; + const wxEventType type = ( nMsg == WM_CUT ) ? wxEVT_COMMAND_TEXT_CUT : + ( nMsg == WM_COPY ) ? wxEVT_COMMAND_TEXT_COPY : + /*( nMsg == WM_PASTE ) ? */ wxEVT_COMMAND_TEXT_PASTE; + wxClipboardTextEvent evt(type, GetId()); - if ( !eliminateBorders ) - { - if ( style & wxSUNKEN_BORDER ) - exStyle |= WS_EX_CLIENTEDGE ; - if ( style & wxDOUBLE_BORDER ) - exStyle |= WS_EX_DLGMODALFRAME ; -#if defined(__WIN95__) - if ( style & wxRAISED_BORDER ) - exStyle |= WS_EX_WINDOWEDGE ; - if ( style & wxSTATIC_BORDER ) - exStyle |= WS_EX_STATICEDGE ; -#endif - } - return exStyle; + evt.SetEventObject(this); + + return GetEventHandler()->ProcessEvent(evt); } -// 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) +// --------------------------------------------------------------------------- +// joystick +// --------------------------------------------------------------------------- + +bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags) { - // If matches certain criteria, then assume no 3D effects - // unless specifically requested (dealt with in MakeExtendedStyle) - if ( !GetParent() || !IsKindOf(CLASSINFO(wxControl)) || (m_windowStyle & wxNO_BORDER) ) +#ifdef JOY_BUTTON1 + int change = 0; + if ( flags & JOY_BUTTON1CHG ) + change = wxJOY_BUTTON1; + if ( flags & JOY_BUTTON2CHG ) + change = wxJOY_BUTTON2; + if ( flags & JOY_BUTTON3CHG ) + change = wxJOY_BUTTON3; + if ( flags & JOY_BUTTON4CHG ) + change = wxJOY_BUTTON4; + + int buttons = 0; + if ( flags & JOY_BUTTON1 ) + buttons |= wxJOY_BUTTON1; + if ( flags & JOY_BUTTON2 ) + buttons |= wxJOY_BUTTON2; + if ( flags & JOY_BUTTON3 ) + buttons |= wxJOY_BUTTON3; + if ( flags & JOY_BUTTON4 ) + buttons |= wxJOY_BUTTON4; + + // the event ids aren't consecutive so we can't use table based lookup + int joystick; + wxEventType eventType; + switch ( msg ) { - *want3D = FALSE; - return MakeExtendedStyle(m_windowStyle, FALSE); - } + case MM_JOY1MOVE: + joystick = 1; + eventType = wxEVT_JOY_MOVE; + break; - // Determine whether we should be using 3D effects or not. - bool nativeBorder = FALSE; // by default, we don't want a Win95 effect + case MM_JOY2MOVE: + joystick = 2; + eventType = wxEVT_JOY_MOVE; + break; - // 1) App can specify global 3D effects - *want3D = wxTheApp->GetAuto3D(); + case MM_JOY1ZMOVE: + joystick = 1; + eventType = wxEVT_JOY_ZMOVE; + break; - // 2) If the parent is being drawn with user colours, or simple border specified, - // switch effects off. TODO: replace wxUSER_COLOURS with wxNO_3D - if (GetParent() && (GetParent()->GetWindowStyleFlag() & wxUSER_COLOURS) || (m_windowStyle & wxSIMPLE_BORDER)) - *want3D = FALSE; + case MM_JOY2ZMOVE: + joystick = 2; + eventType = wxEVT_JOY_ZMOVE; + break; - // 3) Control can override this global setting by defining - // a border style, e.g. wxSUNKEN_BORDER - if (m_windowStyle & wxSUNKEN_BORDER ) - *want3D = TRUE; + case MM_JOY1BUTTONDOWN: + joystick = 1; + eventType = wxEVT_JOY_BUTTON_DOWN; + break; - // 4) If it's a special border, CTL3D can't cope so we want a native border - if ( (m_windowStyle & wxDOUBLE_BORDER) || (m_windowStyle & wxRAISED_BORDER) || - (m_windowStyle & wxSTATIC_BORDER) ) - { - *want3D = TRUE; - nativeBorder = TRUE; - } + case MM_JOY2BUTTONDOWN: + joystick = 2; + eventType = wxEVT_JOY_BUTTON_DOWN; + break; - // 5) If this isn't a Win95 app, and we are using CTL3D, remove border - // effects from extended style -#if wxUSE_CTL3D - if ( *want3D ) - nativeBorder = FALSE; -#endif + case MM_JOY1BUTTONUP: + joystick = 1; + eventType = wxEVT_JOY_BUTTON_UP; + break; - DWORD exStyle = MakeExtendedStyle(m_windowStyle, !nativeBorder); + case MM_JOY2BUTTONUP: + joystick = 2; + eventType = wxEVT_JOY_BUTTON_UP; + break; - // If we want 3D, but haven't specified a border here, - // apply the default border style specified. - // TODO what about non-Win95 WIN32? Does it have borders? -#if defined(__WIN95__) && !wxUSE_CTL3D - if (defaultBorderStyle && (*want3D) && ! ((m_windowStyle & wxDOUBLE_BORDER) || (m_windowStyle & wxRAISED_BORDER) || - (m_windowStyle & wxSTATIC_BORDER) || (m_windowStyle & wxSIMPLE_BORDER) )) - exStyle |= defaultBorderStyle; // WS_EX_CLIENTEDGE ; -#endif + default: + wxFAIL_MSG(wxT("no such joystick event")); + + return false; + } + + wxJoystickEvent event(eventType, buttons, joystick, change); + event.SetPosition(wxPoint(x, y)); + event.SetEventObject(this); - return exStyle; + return GetEventHandler()->ProcessEvent(event); +#else + wxUnusedVar(msg); + wxUnusedVar(x); + wxUnusedVar(y); + wxUnusedVar(flags); + return false; +#endif } -void wxWindow::OnChar(wxKeyEvent& event) +// --------------------------------------------------------------------------- +// scrolling +// --------------------------------------------------------------------------- + +bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam, + WXWORD pos, WXHWND control) { - bool isVirtual; - int id = wxCharCodeWXToMSW((int)event.KeyCode(), &isVirtual); + if ( control && control != m_hWnd ) // Prevent infinite recursion + { + wxWindow *child = wxFindWinFromHandle(control); + if ( child ) + return child->MSWOnScroll(orientation, wParam, pos, control); + } - if ( id == -1 ) - id= m_lastWParam; + wxScrollWinEvent event; + event.SetPosition(pos); + event.SetOrientation(orientation); + event.SetEventObject(this); - if ( !event.ControlDown() ) // Why this test? - (void) MSWDefWindowProc(m_lastMsg, (WPARAM) id, m_lastLParam); -} + switch ( wParam ) + { + case SB_TOP: + event.SetEventType(wxEVT_SCROLLWIN_TOP); + break; -void wxWindow::OnKeyDown(wxKeyEvent& event) -{ - Default(); -} + case SB_BOTTOM: + event.SetEventType(wxEVT_SCROLLWIN_BOTTOM); + break; -void wxWindow::OnKeyUp(wxKeyEvent& event) -{ - Default(); -} + case SB_LINEUP: + event.SetEventType(wxEVT_SCROLLWIN_LINEUP); + break; -void wxWindow::OnPaint(wxPaintEvent& event) -{ - Default(); -} + case SB_LINEDOWN: + event.SetEventType(wxEVT_SCROLLWIN_LINEDOWN); + break; -bool wxWindow::IsEnabled(void) const -{ - return (::IsWindowEnabled((HWND) GetHWND()) != 0); -} + case SB_PAGEUP: + event.SetEventType(wxEVT_SCROLLWIN_PAGEUP); + break; -// Dialog support: override these and call -// base class members to add functionality -// that can't be done using validators. -// NOTE: these functions assume that controls -// are direct children of this window, not grandchildren -// or other levels of descendant. + case SB_PAGEDOWN: + event.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN); + break; -// Transfer values to controls. If returns FALSE, -// it's an application error (pops up a dialog) -bool wxWindow::TransferDataToWindow() -{ - wxNode *node = GetChildren().First(); - while ( node ) - { - wxWindow *child = (wxWindow *)node->Data(); - if ( child->GetValidator() && /* child->GetValidator()->Ok() && */ - !child->GetValidator()->TransferToWindow() ) + case SB_THUMBPOSITION: + case SB_THUMBTRACK: + // under Win32, the scrollbar range and position are 32 bit integers, + // but WM_[HV]SCROLL only carry the low 16 bits of them, so we must + // explicitly query the scrollbar for the correct position (this must + // be done only for these two SB_ events as they are the only one + // carrying the scrollbar position) { - wxLogError(_("Could not transfer data to window")); - return FALSE; - } + WinStruct scrollInfo; + scrollInfo.fMask = SIF_TRACKPOS; - node = node->Next(); - } - return TRUE; -} + if ( !::GetScrollInfo(GetHwnd(), + orientation == wxHORIZONTAL ? SB_HORZ + : SB_VERT, + &scrollInfo) ) + { + // Not necessarily an error, if there are no scrollbars yet. + // wxLogLastError(_T("GetScrollInfo")); + } -// Transfer values from controls. If returns FALSE, -// validation failed: don't quit -bool wxWindow::TransferDataFromWindow() -{ - wxNode *node = GetChildren().First(); - while ( node ) - { - wxWindow *child = (wxWindow *)node->Data(); - if ( child->GetValidator() && /* child->GetValidator()->Ok() && */ !child->GetValidator()->TransferFromWindow() ) - { - return FALSE; + event.SetPosition(scrollInfo.nTrackPos); } - node = node->Next(); + event.SetEventType( wParam == SB_THUMBPOSITION + ? wxEVT_SCROLLWIN_THUMBRELEASE + : wxEVT_SCROLLWIN_THUMBTRACK ); + break; + + default: + return false; } - return TRUE; + + return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::Validate() +// =========================================================================== +// global functions +// =========================================================================== + +void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont& the_font) { - wxNode *node = GetChildren().First(); - while ( node ) - { - wxWindow *child = (wxWindow *)node->Data(); - if ( child->GetValidator() && /* child->GetValidator()->Ok() && */ !child->GetValidator()->Validate(this) ) - { - return FALSE; - } + TEXTMETRIC tm; + HDC dc = ::GetDC((HWND) wnd); + HFONT was = 0; - node = node->Next(); - } - return TRUE; -} + // the_font.UseResource(); + // the_font.RealizeResource(); + HFONT fnt = (HFONT)the_font.GetResourceHandle(); // const_cast + if ( fnt ) + was = (HFONT) SelectObject(dc,fnt); -// Get the window with the focus -wxWindow *wxWindow::FindFocus() -{ - HWND hWnd = ::GetFocus(); - if ( hWnd ) + GetTextMetrics(dc, &tm); + if ( fnt && was ) { - return wxFindWinFromHandle((WXHWND) hWnd); + SelectObject(dc,was); } - return NULL; -} + ReleaseDC((HWND)wnd, dc); -void wxWindow::AddChild(wxWindow *child) -{ - GetChildren().Append(child); - child->m_windowParent = this; -} + if ( x ) + *x = tm.tmAveCharWidth; + if ( y ) + *y = tm.tmHeight + tm.tmExternalLeading; + + // the_font.ReleaseResource(); +} + +// use the "extended" bit (24) of lParam to distinguish extended keys +// from normal keys as the same key is sent +static inline +int ChooseNormalOrExtended(int lParam, int keyNormal, int keyExtended) +{ + // except that if lParam is 0, it means we don't have real lParam from + // WM_KEYDOWN but are just translating just a VK constant (e.g. done from + // msw/treectrl.cpp when processing TVN_KEYDOWN) -- then assume this is a + // non-numpad (hence extended) key as this is a more common case + return !lParam || (lParam & (1 << 24)) ? keyExtended : keyNormal; +} + +// this array contains the Windows virtual key codes which map one to one to +// WXK_xxx constants and is used in wxCharCodeMSWToWX/WXToMSW() below +// +// note that keys having a normal and numpad version (e.g. WXK_HOME and +// WXK_NUMPAD_HOME) are not included in this table as the mapping is not 1-to-1 +static const struct wxKeyMapping +{ + int vk; + wxKeyCode wxk; +} gs_specialKeys[] = +{ + { VK_CANCEL, WXK_CANCEL }, + { VK_BACK, WXK_BACK }, + { VK_TAB, WXK_TAB }, + { VK_CLEAR, WXK_CLEAR }, + { VK_SHIFT, WXK_SHIFT }, + { VK_CONTROL, WXK_CONTROL }, + { VK_MENU , WXK_ALT }, + { VK_PAUSE, WXK_PAUSE }, + { VK_CAPITAL, WXK_CAPITAL }, + { VK_SPACE, WXK_SPACE }, + { VK_ESCAPE, WXK_ESCAPE }, + { VK_SELECT, WXK_SELECT }, + { VK_PRINT, WXK_PRINT }, + { VK_EXECUTE, WXK_EXECUTE }, + { VK_SNAPSHOT, WXK_SNAPSHOT }, + { VK_HELP, WXK_HELP }, + + { VK_NUMPAD0, WXK_NUMPAD0 }, + { VK_NUMPAD1, WXK_NUMPAD1 }, + { VK_NUMPAD2, WXK_NUMPAD2 }, + { VK_NUMPAD3, WXK_NUMPAD3 }, + { VK_NUMPAD4, WXK_NUMPAD4 }, + { VK_NUMPAD5, WXK_NUMPAD5 }, + { VK_NUMPAD6, WXK_NUMPAD6 }, + { VK_NUMPAD7, WXK_NUMPAD7 }, + { VK_NUMPAD8, WXK_NUMPAD8 }, + { VK_NUMPAD9, WXK_NUMPAD9 }, + { VK_MULTIPLY, WXK_NUMPAD_MULTIPLY }, + { VK_ADD, WXK_NUMPAD_ADD }, + { VK_SUBTRACT, WXK_NUMPAD_SUBTRACT }, + { VK_DECIMAL, WXK_NUMPAD_DECIMAL }, + { VK_DIVIDE, WXK_NUMPAD_DIVIDE }, + + { VK_F1, WXK_F1 }, + { VK_F2, WXK_F2 }, + { VK_F3, WXK_F3 }, + { VK_F4, WXK_F4 }, + { VK_F5, WXK_F5 }, + { VK_F6, WXK_F6 }, + { VK_F7, WXK_F7 }, + { VK_F8, WXK_F8 }, + { VK_F9, WXK_F9 }, + { VK_F10, WXK_F10 }, + { VK_F11, WXK_F11 }, + { VK_F12, WXK_F12 }, + { VK_F13, WXK_F13 }, + { VK_F14, WXK_F14 }, + { VK_F15, WXK_F15 }, + { VK_F16, WXK_F16 }, + { VK_F17, WXK_F17 }, + { VK_F18, WXK_F18 }, + { VK_F19, WXK_F19 }, + { VK_F20, WXK_F20 }, + { VK_F21, WXK_F21 }, + { VK_F22, WXK_F22 }, + { VK_F23, WXK_F23 }, + { VK_F24, WXK_F24 }, + + { VK_NUMLOCK, WXK_NUMLOCK }, + { VK_SCROLL, WXK_SCROLL }, -void wxWindow::RemoveChild(wxWindow *child) -{ -// if (GetChildren()) - GetChildren().DeleteObject(child); - child->m_windowParent = NULL; -} +#ifdef VK_APPS + { VK_LWIN, WXK_WINDOWS_LEFT }, + { VK_RWIN, WXK_WINDOWS_RIGHT }, + { VK_APPS, WXK_WINDOWS_MENU }, +#endif // VK_APPS defined +}; -void wxWindow::DestroyChildren() +// Returns 0 if was a normal ASCII value, not a special key. This indicates that +// the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead. +int wxCharCodeMSWToWX(int vk, WXLPARAM lParam) { - wxNode *node; - while ((node = GetChildren().First()) != (wxNode *)NULL) { - wxWindow *child; - if ((child = (wxWindow *)node->Data()) != (wxWindow *)NULL) { - delete child; - if ( GetChildren().Member(child) ) - delete node; - } - } /* while */ -} + // check the table first + for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ ) + { + if ( gs_specialKeys[n].vk == vk ) + return gs_specialKeys[n].wxk; + } -void wxWindow::MakeModal(bool modal) -{ - // Disable all other windows - if (this->IsKindOf(CLASSINFO(wxDialog)) || this->IsKindOf(CLASSINFO(wxFrame))) + // keys requiring special handling + int wxk; + switch ( vk ) { - wxNode *node = wxTopLevelWindows.First(); - while (node) - { - wxWindow *win = (wxWindow *)node->Data(); - if (win != this) - win->Enable(!modal); + // the mapping for these keys may be incorrect on non-US keyboards so + // maybe we shouldn't map them to ASCII values at all + case VK_OEM_1: wxk = ';'; break; + case VK_OEM_PLUS: wxk = '+'; break; + case VK_OEM_COMMA: wxk = ','; break; + case VK_OEM_MINUS: wxk = '-'; break; + case VK_OEM_PERIOD: wxk = '.'; break; + case VK_OEM_2: wxk = '/'; break; + case VK_OEM_3: wxk = '~'; break; + case VK_OEM_4: wxk = '['; break; + case VK_OEM_5: wxk = '\\'; break; + case VK_OEM_6: wxk = ']'; break; + case VK_OEM_7: wxk = '\''; break; + + // handle extended keys + case VK_PRIOR: + wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEUP, WXK_PAGEUP); + break; - node = node->Next(); - } + case VK_NEXT: + wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEDOWN, WXK_PAGEDOWN); + break; + + case VK_END: + wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_END, WXK_END); + break; + + case VK_HOME: + wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_HOME, WXK_HOME); + break; + + case VK_LEFT: + wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_LEFT, WXK_LEFT); + break; + + case VK_UP: + wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_UP, WXK_UP); + break; + + case VK_RIGHT: + wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_RIGHT, WXK_RIGHT); + break; + + case VK_DOWN: + wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DOWN, WXK_DOWN); + break; + + case VK_INSERT: + wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_INSERT, WXK_INSERT); + break; + + case VK_DELETE: + wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DELETE, WXK_DELETE); + break; + + case VK_RETURN: + // don't use ChooseNormalOrExtended() here as the keys are reversed + // here: numpad enter is the extended one + wxk = lParam && (lParam & (1 << 24)) ? WXK_NUMPAD_ENTER : WXK_RETURN; + break; + + default: + wxk = 0; } -} -// If nothing defined for this, try the parent. -// E.g. we may be a button loaded from a resource, with no callback function -// defined. -void wxWindow::OnCommand(wxWindow& win, wxCommandEvent& event) -{ - if (GetEventHandler()->ProcessEvent(event) ) - return; - if (m_windowParent) - m_windowParent->GetEventHandler()->OnCommand(win, event); + return wxk; } -void wxWindow::SetConstraints(wxLayoutConstraints *c) +WXWORD wxCharCodeWXToMSW(int wxk, bool *isVirtual) { - if (m_constraints) - { - UnsetConstraints(m_constraints); - delete m_constraints; - } - m_constraints = c; - if (m_constraints) + if ( isVirtual ) + *isVirtual = true; + + // check the table first + for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ ) { - // Make sure other windows know they're part of a 'meaningful relationship' - if (m_constraints->left.GetOtherWindow() && (m_constraints->left.GetOtherWindow() != this)) - m_constraints->left.GetOtherWindow()->AddConstraintReference((wxWindow *)this); - if (m_constraints->top.GetOtherWindow() && (m_constraints->top.GetOtherWindow() != this)) - m_constraints->top.GetOtherWindow()->AddConstraintReference((wxWindow *)this); - if (m_constraints->right.GetOtherWindow() && (m_constraints->right.GetOtherWindow() != this)) - m_constraints->right.GetOtherWindow()->AddConstraintReference((wxWindow *)this); - if (m_constraints->bottom.GetOtherWindow() && (m_constraints->bottom.GetOtherWindow() != this)) - m_constraints->bottom.GetOtherWindow()->AddConstraintReference((wxWindow *)this); - if (m_constraints->width.GetOtherWindow() && (m_constraints->width.GetOtherWindow() != this)) - m_constraints->width.GetOtherWindow()->AddConstraintReference((wxWindow *)this); - if (m_constraints->height.GetOtherWindow() && (m_constraints->height.GetOtherWindow() != this)) - m_constraints->height.GetOtherWindow()->AddConstraintReference((wxWindow *)this); - if (m_constraints->centreX.GetOtherWindow() && (m_constraints->centreX.GetOtherWindow() != this)) - m_constraints->centreX.GetOtherWindow()->AddConstraintReference((wxWindow *)this); - if (m_constraints->centreY.GetOtherWindow() && (m_constraints->centreY.GetOtherWindow() != this)) - m_constraints->centreY.GetOtherWindow()->AddConstraintReference((wxWindow *)this); + if ( gs_specialKeys[n].wxk == wxk ) + return gs_specialKeys[n].vk; } -} -// This removes any dangling pointers to this window -// in other windows' constraintsInvolvedIn lists. -void wxWindow::UnsetConstraints(wxLayoutConstraints *c) -{ - if (c) + // and then check for special keys not included in the table + WXWORD vk; + switch ( wxk ) { - if (c->left.GetOtherWindow() && (c->top.GetOtherWindow() != this)) - c->left.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - if (c->top.GetOtherWindow() && (c->top.GetOtherWindow() != this)) - c->top.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - if (c->right.GetOtherWindow() && (c->right.GetOtherWindow() != this)) - c->right.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - if (c->bottom.GetOtherWindow() && (c->bottom.GetOtherWindow() != this)) - c->bottom.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - if (c->width.GetOtherWindow() && (c->width.GetOtherWindow() != this)) - c->width.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - if (c->height.GetOtherWindow() && (c->height.GetOtherWindow() != this)) - c->height.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - if (c->centreX.GetOtherWindow() && (c->centreX.GetOtherWindow() != this)) - c->centreX.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - if (c->centreY.GetOtherWindow() && (c->centreY.GetOtherWindow() != this)) - c->centreY.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - } -} + case WXK_PAGEUP: + case WXK_NUMPAD_PAGEUP: + vk = VK_PRIOR; + break; -// Back-pointer to other windows we're involved with, so if we delete -// this window, we must delete any constraints we're involved with. -void wxWindow::AddConstraintReference(wxWindow *otherWin) -{ - if (!m_constraintsInvolvedIn) - m_constraintsInvolvedIn = new wxList; - if (!m_constraintsInvolvedIn->Member(otherWin)) - m_constraintsInvolvedIn->Append(otherWin); -} + case WXK_PAGEDOWN: + case WXK_NUMPAD_PAGEDOWN: + vk = VK_NEXT; + break; -// REMOVE back-pointer to other windows we're involved with. -void wxWindow::RemoveConstraintReference(wxWindow *otherWin) -{ - if (m_constraintsInvolvedIn) - m_constraintsInvolvedIn->DeleteObject(otherWin); -} + case WXK_END: + case WXK_NUMPAD_END: + vk = VK_END; + break; -// Reset any constraints that mention this window -void wxWindow::DeleteRelatedConstraints() -{ - if (m_constraintsInvolvedIn) - { - wxNode *node = m_constraintsInvolvedIn->First(); - while (node) - { - wxWindow *win = (wxWindow *)node->Data(); - wxNode *next = node->Next(); - wxLayoutConstraints *constr = win->GetConstraints(); + case WXK_HOME: + case WXK_NUMPAD_HOME: + vk = VK_HOME; + break; - // Reset any constraints involving this window - if (constr) - { - constr->left.ResetIfWin((wxWindow *)this); - constr->top.ResetIfWin((wxWindow *)this); - constr->right.ResetIfWin((wxWindow *)this); - constr->bottom.ResetIfWin((wxWindow *)this); - constr->width.ResetIfWin((wxWindow *)this); - constr->height.ResetIfWin((wxWindow *)this); - constr->centreX.ResetIfWin((wxWindow *)this); - constr->centreY.ResetIfWin((wxWindow *)this); - } - delete node; - node = next; - } - delete m_constraintsInvolvedIn; - m_constraintsInvolvedIn = NULL; + case WXK_LEFT: + case WXK_NUMPAD_LEFT: + vk = VK_LEFT; + break; + + case WXK_UP: + case WXK_NUMPAD_UP: + vk = VK_UP; + break; + + case WXK_RIGHT: + case WXK_NUMPAD_RIGHT: + vk = VK_RIGHT; + break; + + case WXK_DOWN: + case WXK_NUMPAD_DOWN: + vk = VK_DOWN; + break; + + case WXK_INSERT: + case WXK_NUMPAD_INSERT: + vk = VK_INSERT; + break; + + case WXK_DELETE: + case WXK_NUMPAD_DELETE: + vk = VK_DELETE; + break; + + default: + if ( isVirtual ) + *isVirtual = false; + vk = (WXWORD)wxk; + break; } + + return vk; } -void wxWindow::SetSizer(wxSizer *sizer) +// small helper for wxGetKeyState() and wxGetMouseState() +static inline bool wxIsKeyDown(WXWORD vk) { - m_windowSizer = sizer; - if (sizer) - sizer->SetSizerParent((wxWindow *)this); + // 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; } -/* -* New version -*/ - -bool wxWindow::Layout() +bool wxGetKeyState(wxKeyCode key) { - if (GetConstraints()) - { - int w, h; - GetClientSize(&w, &h); - GetConstraints()->width.SetValue(w); - GetConstraints()->height.SetValue(h); - } + // although this does work under Windows, it is not supported under other + // platforms so don't allow it, you must use wxGetMouseState() instead + wxASSERT_MSG( key != VK_LBUTTON && + key != VK_RBUTTON && + key != VK_MBUTTON, + wxT("can't use wxGetKeyState() for mouse buttons") ); + + const WXWORD vk = wxCharCodeWXToMSW(key); - // If top level (one sizer), evaluate the sizer's constraints. - if (GetSizer()) + // if the requested key is a LED key, return true if the led is pressed + if ( key == WXK_NUMLOCK || key == WXK_CAPITAL || key == WXK_SCROLL ) { - int noChanges; - GetSizer()->ResetConstraints(); // Mark all constraints as unevaluated - GetSizer()->LayoutPhase1(&noChanges); - GetSizer()->LayoutPhase2(&noChanges); - GetSizer()->SetConstraintSizes(); // Recursively set the real window sizes - return TRUE; + // 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; + } - else + else // normal key { - // Otherwise, evaluate child constraints - ResetConstraints(); // Mark all constraints as unevaluated - DoPhase(1); // Just one phase need if no sizers involved - DoPhase(2); - SetConstraintSizes(); // Recursively set the real window sizes + return wxIsKeyDown(vk); } - return TRUE; } -// Do a phase of evaluating constraints: -// the default behaviour. wxSizers may do a similar -// thing, but also impose their own 'constraints' -// and order the evaluation differently. -bool wxWindow::LayoutPhase1(int *noChanges) +wxMouseState wxGetMouseState() { - wxLayoutConstraints *constr = GetConstraints(); - if (constr) - { - return constr->SatisfyConstraints((wxWindow *)this, noChanges); - } - else - return TRUE; -} + wxMouseState ms; + POINT pt; + GetCursorPos( &pt ); -bool wxWindow::LayoutPhase2(int *noChanges) -{ - *noChanges = 0; + ms.SetX(pt.x); + ms.SetY(pt.y); + ms.SetLeftDown(wxIsKeyDown(VK_LBUTTON)); + ms.SetMiddleDown(wxIsKeyDown(VK_MBUTTON)); + ms.SetRightDown(wxIsKeyDown(VK_RBUTTON)); - // Layout children - DoPhase(1); - DoPhase(2); - return TRUE; -} + ms.SetControlDown(wxIsKeyDown(VK_CONTROL)); + ms.SetShiftDown(wxIsKeyDown(VK_SHIFT)); + ms.SetAltDown(wxIsKeyDown(VK_MENU)); +// ms.SetMetaDown(); -// Do a phase of evaluating child constraints -bool wxWindow::DoPhase(int phase) -{ - int noIterations = 0; - int maxIterations = 500; - int noChanges = 1; - int noFailures = 0; - wxList succeeded; - while ((noChanges > 0) && (noIterations < maxIterations)) - { - noChanges = 0; - noFailures = 0; - wxNode *node = GetChildren().First(); - while (node) - { - wxWindow *child = (wxWindow *)node->Data(); - if (!child->IsKindOf(CLASSINFO(wxFrame)) && !child->IsKindOf(CLASSINFO(wxDialog))) - { - wxLayoutConstraints *constr = child->GetConstraints(); - if (constr) - { - if (succeeded.Member(child)) - { - } - else - { - int tempNoChanges = 0; - bool success = ( (phase == 1) ? child->LayoutPhase1(&tempNoChanges) : child->LayoutPhase2(&tempNoChanges) ) ; - noChanges += tempNoChanges; - if (success) - { - succeeded.Append(child); - } - } - } - } - node = node->Next(); - } - noIterations ++; - } - return TRUE; + return ms; } -void wxWindow::ResetConstraints() + +wxWindow *wxGetActiveWindow() { - wxLayoutConstraints *constr = GetConstraints(); - if (constr) - { - constr->left.SetDone(FALSE); - constr->top.SetDone(FALSE); - constr->right.SetDone(FALSE); - constr->bottom.SetDone(FALSE); - constr->width.SetDone(FALSE); - constr->height.SetDone(FALSE); - constr->centreX.SetDone(FALSE); - constr->centreY.SetDone(FALSE); - } - wxNode *node = GetChildren().First(); - while (node) + HWND hWnd = GetActiveWindow(); + if ( hWnd != 0 ) { - wxWindow *win = (wxWindow *)node->Data(); - if (!win->IsKindOf(CLASSINFO(wxFrame)) && !win->IsKindOf(CLASSINFO(wxDialog))) - win->ResetConstraints(); - node = node->Next(); + return wxFindWinFromHandle((WXHWND) hWnd); } + return NULL; } -// Need to distinguish between setting the 'fake' size for -// windows and sizers, and setting the real values. -void wxWindow::SetConstraintSizes(bool recurse) +extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) { - wxLayoutConstraints *constr = GetConstraints(); - if (constr && constr->left.GetDone() && constr->right.GetDone() && - constr->width.GetDone() && constr->height.GetDone()) - { - int x = constr->left.GetValue(); - int y = constr->top.GetValue(); - int w = constr->width.GetValue(); - int h = constr->height.GetValue(); + HWND hwnd = (HWND)hWnd; - // If we don't want to resize this window, just move it... - if ((constr->width.GetRelationship() != wxAsIs) || - (constr->height.GetRelationship() != wxAsIs)) - { - // Calls Layout() recursively. AAAGH. How can we stop that. - // Simply take Layout() out of non-top level OnSizes. - SizerSetSize(x, y, w, h); - } - else + // 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 ) { - SizerMove(x, y); +#if wxUSE_RADIOBOX + // 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, WM_GETDLGCODE, 0, 0) & DLGC_RADIOBUTTON ) + { + win = (wxWindow *)wxGetWindowUserData(hwnd); + } + //else: it's a wxRadioButton, not a radiobutton from wxRadioBox +#endif // wxUSE_RADIOBOX + + // spin control text buddy window should be mapped to spin ctrl + // itself so try it too +#if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__) + if ( !win ) + { + win = wxSpinCtrl::GetSpinForTextCtrl((WXHWND)hwnd); + } +#endif // wxUSE_SPINCTRL } } - else if (constr) - { - char *windowClass = this->GetClassInfo()->GetClassName(); - wxString winName; - if (GetName() == "") - winName = "unnamed"; - else - winName = GetName(); - wxLogDebug("Constraint(s) not satisfied for window of type %s, name %s:", - (const char *)windowClass, (const char *)winName); - if (!constr->left.GetDone()) - wxLogDebug(" unsatisfied 'left' constraint."); - if (!constr->right.GetDone()) - wxLogDebug(" unsatisfied 'right' constraint."); - if (!constr->width.GetDone()) - wxLogDebug(" unsatisfied 'width' constraint."); - if (!constr->height.GetDone()) - wxLogDebug(" unsatisfied 'height' constraint."); - wxLogDebug("Please check constraints: try adding AsIs() constraints.\n"); - } - - if (recurse) - { - wxNode *node = GetChildren().First(); - while (node) + while ( hwnd && !win ) + { + // this is a really ugly hack needed to avoid mistakenly returning the + // parent frame wxWindow for the find/replace modeless dialog HWND - + // this, in turn, is needed to call IsDialogMessage() from + // wxApp::ProcessMessage() as for this we must return NULL from here + // + // FIXME: this is clearly not the best way to do it but I think we'll + // need to change HWND <-> wxWindow code more heavily than I can + // do it now to fix it +#ifndef __WXMICROWIN__ + if ( ::GetWindow(hwnd, GW_OWNER) ) { - wxWindow *win = (wxWindow *)node->Data(); - if (!win->IsKindOf(CLASSINFO(wxFrame)) && !win->IsKindOf(CLASSINFO(wxDialog))) - win->SetConstraintSizes(); - node = node->Next(); + // it's a dialog box, don't go upwards + break; } - } -} +#endif -// This assumes that all sizers are 'on' the same -// window, i.e. the parent of this window. -void wxWindow::TransformSizerToActual(int *x, int *y) const -{ - if (!m_sizerParent || m_sizerParent->IsKindOf(CLASSINFO(wxDialog)) || - m_sizerParent->IsKindOf(CLASSINFO(wxFrame)) ) - return; + hwnd = ::GetParent(hwnd); + win = wxFindWinFromHandle((WXHWND)hwnd); + } - int xp, yp; - m_sizerParent->GetPosition(&xp, &yp); - m_sizerParent->TransformSizerToActual(&xp, &yp); - *x += xp; - *y += yp; + return win; } -void wxWindow::SizerSetSize(int x, int y, int w, int h) -{ - int xx = x; - int yy = y; - TransformSizerToActual(&xx, &yy); - SetSize(xx, yy, w, h); -} +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) -void wxWindow::SizerMove(int x, int y) -{ - int xx = x; - int yy = y; - TransformSizerToActual(&xx, &yy); - Move(xx, yy); -} +// 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; +static FARPROC wxTheKeyboardHookProc = 0; +int APIENTRY _EXPORT +wxKeyboardHook(int nCode, WORD wParam, DWORD lParam); -// Only set the size/position of the constraint (if any) -void wxWindow::SetSizeConstraint(int x, int y, int w, int h) +void wxSetKeyboardHook(bool doIt) { - wxLayoutConstraints *constr = GetConstraints(); - if (constr) + if ( doIt ) { - if (x != -1) - { - constr->left.SetValue(x); - constr->left.SetDone(TRUE); - } - if (y != -1) - { - constr->top.SetValue(y); - constr->top.SetDone(TRUE); - } - if (w != -1) - { - constr->width.SetValue(w); - constr->width.SetDone(TRUE); - } - if (h != -1) - { - constr->height.SetValue(h); - constr->height.SetDone(TRUE); - } + wxTheKeyboardHookProc = MakeProcInstance((FARPROC) wxKeyboardHook, wxGetInstance()); + wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(), + + GetCurrentThreadId() + // (DWORD)GetCurrentProcess()); // This is another possibility. Which is right? + ); + } + else + { + UnhookWindowsHookEx(wxTheKeyboardHook); } } -void wxWindow::MoveConstraint(int x, int y) +int APIENTRY _EXPORT +wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) { - wxLayoutConstraints *constr = GetConstraints(); - if (constr) + DWORD hiWord = HIWORD(lParam); + if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) ) { - if (x != -1) - { - constr->left.SetValue(x); - constr->left.SetDone(TRUE); - } - if (y != -1) + int id = wxCharCodeMSWToWX(wParam, lParam); + if ( id != 0 ) { - constr->top.SetValue(y); - constr->top.SetDone(TRUE); + wxKeyEvent event(wxEVT_CHAR_HOOK); + if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN ) + event.m_altDown = true; + + event.SetEventObject(NULL); + event.m_keyCode = id; + event.m_shiftDown = wxIsShiftDown(); + event.m_controlDown = wxIsCtrlDown(); +#ifndef __WXWINCE__ + event.SetTimestamp(::GetMessageTime()); +#endif + wxWindow *win = wxGetActiveWindow(); + wxEvtHandler *handler; + if ( win ) + { + handler = win->GetEventHandler(); + event.SetId(win->GetId()); + } + else + { + handler = wxTheApp; + event.SetId(wxID_ANY); + } + + if ( handler && handler->ProcessEvent(event) ) + { + // processed + return 1; + } } } -} -void wxWindow::GetSizeConstraint(int *w, int *h) const -{ - wxLayoutConstraints *constr = GetConstraints(); - if (constr) - { - *w = constr->width.GetValue(); - *h = constr->height.GetValue(); - } - else - GetSize(w, h); + return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam); } -void wxWindow::GetClientSizeConstraint(int *w, int *h) const +#endif // !__WXMICROWIN__ + +#ifdef __WXDEBUG__ +const wxChar *wxGetMessageName(int message) { - wxLayoutConstraints *constr = GetConstraints(); - if (constr) + switch ( message ) { - *w = constr->width.GetValue(); - *h = constr->height.GetValue(); + case 0x0000: return wxT("WM_NULL"); + case 0x0001: return wxT("WM_CREATE"); + case 0x0002: return wxT("WM_DESTROY"); + case 0x0003: return wxT("WM_MOVE"); + case 0x0005: return wxT("WM_SIZE"); + case 0x0006: return wxT("WM_ACTIVATE"); + case 0x0007: return wxT("WM_SETFOCUS"); + case 0x0008: return wxT("WM_KILLFOCUS"); + case 0x000A: return wxT("WM_ENABLE"); + case 0x000B: return wxT("WM_SETREDRAW"); + case 0x000C: return wxT("WM_SETTEXT"); + case 0x000D: return wxT("WM_GETTEXT"); + case 0x000E: return wxT("WM_GETTEXTLENGTH"); + case 0x000F: return wxT("WM_PAINT"); + case 0x0010: return wxT("WM_CLOSE"); + case 0x0011: return wxT("WM_QUERYENDSESSION"); + case 0x0012: return wxT("WM_QUIT"); + case 0x0013: return wxT("WM_QUERYOPEN"); + case 0x0014: return wxT("WM_ERASEBKGND"); + case 0x0015: return wxT("WM_SYSCOLORCHANGE"); + case 0x0016: return wxT("WM_ENDSESSION"); + case 0x0017: return wxT("WM_SYSTEMERROR"); + case 0x0018: return wxT("WM_SHOWWINDOW"); + case 0x0019: return wxT("WM_CTLCOLOR"); + case 0x001A: return wxT("WM_WININICHANGE"); + case 0x001B: return wxT("WM_DEVMODECHANGE"); + case 0x001C: return wxT("WM_ACTIVATEAPP"); + case 0x001D: return wxT("WM_FONTCHANGE"); + case 0x001E: return wxT("WM_TIMECHANGE"); + case 0x001F: return wxT("WM_CANCELMODE"); + case 0x0020: return wxT("WM_SETCURSOR"); + case 0x0021: return wxT("WM_MOUSEACTIVATE"); + case 0x0022: return wxT("WM_CHILDACTIVATE"); + case 0x0023: return wxT("WM_QUEUESYNC"); + case 0x0024: return wxT("WM_GETMINMAXINFO"); + case 0x0026: return wxT("WM_PAINTICON"); + case 0x0027: return wxT("WM_ICONERASEBKGND"); + case 0x0028: return wxT("WM_NEXTDLGCTL"); + case 0x002A: return wxT("WM_SPOOLERSTATUS"); + case 0x002B: return wxT("WM_DRAWITEM"); + case 0x002C: return wxT("WM_MEASUREITEM"); + case 0x002D: return wxT("WM_DELETEITEM"); + case 0x002E: return wxT("WM_VKEYTOITEM"); + case 0x002F: return wxT("WM_CHARTOITEM"); + case 0x0030: return wxT("WM_SETFONT"); + case 0x0031: return wxT("WM_GETFONT"); + case 0x0037: return wxT("WM_QUERYDRAGICON"); + case 0x0039: return wxT("WM_COMPAREITEM"); + case 0x0041: return wxT("WM_COMPACTING"); + case 0x0044: return wxT("WM_COMMNOTIFY"); + case 0x0046: return wxT("WM_WINDOWPOSCHANGING"); + case 0x0047: return wxT("WM_WINDOWPOSCHANGED"); + case 0x0048: return wxT("WM_POWER"); + + case 0x004A: return wxT("WM_COPYDATA"); + case 0x004B: return wxT("WM_CANCELJOURNAL"); + case 0x004E: return wxT("WM_NOTIFY"); + case 0x0050: return wxT("WM_INPUTLANGCHANGEREQUEST"); + case 0x0051: return wxT("WM_INPUTLANGCHANGE"); + case 0x0052: return wxT("WM_TCARD"); + case 0x0053: return wxT("WM_HELP"); + case 0x0054: return wxT("WM_USERCHANGED"); + case 0x0055: return wxT("WM_NOTIFYFORMAT"); + case 0x007B: return wxT("WM_CONTEXTMENU"); + case 0x007C: return wxT("WM_STYLECHANGING"); + case 0x007D: return wxT("WM_STYLECHANGED"); + case 0x007E: return wxT("WM_DISPLAYCHANGE"); + case 0x007F: return wxT("WM_GETICON"); + case 0x0080: return wxT("WM_SETICON"); + + case 0x0081: return wxT("WM_NCCREATE"); + case 0x0082: return wxT("WM_NCDESTROY"); + case 0x0083: return wxT("WM_NCCALCSIZE"); + case 0x0084: return wxT("WM_NCHITTEST"); + case 0x0085: return wxT("WM_NCPAINT"); + case 0x0086: return wxT("WM_NCACTIVATE"); + case 0x0087: return wxT("WM_GETDLGCODE"); + case 0x00A0: return wxT("WM_NCMOUSEMOVE"); + case 0x00A1: return wxT("WM_NCLBUTTONDOWN"); + case 0x00A2: return wxT("WM_NCLBUTTONUP"); + case 0x00A3: return wxT("WM_NCLBUTTONDBLCLK"); + case 0x00A4: return wxT("WM_NCRBUTTONDOWN"); + case 0x00A5: return wxT("WM_NCRBUTTONUP"); + case 0x00A6: return wxT("WM_NCRBUTTONDBLCLK"); + case 0x00A7: return wxT("WM_NCMBUTTONDOWN"); + case 0x00A8: return wxT("WM_NCMBUTTONUP"); + case 0x00A9: return wxT("WM_NCMBUTTONDBLCLK"); + case 0x0100: return wxT("WM_KEYDOWN"); + case 0x0101: return wxT("WM_KEYUP"); + case 0x0102: return wxT("WM_CHAR"); + case 0x0103: return wxT("WM_DEADCHAR"); + case 0x0104: return wxT("WM_SYSKEYDOWN"); + case 0x0105: return wxT("WM_SYSKEYUP"); + case 0x0106: return wxT("WM_SYSCHAR"); + case 0x0107: return wxT("WM_SYSDEADCHAR"); + case 0x0108: return wxT("WM_KEYLAST"); + + case 0x010D: return wxT("WM_IME_STARTCOMPOSITION"); + case 0x010E: return wxT("WM_IME_ENDCOMPOSITION"); + case 0x010F: return wxT("WM_IME_COMPOSITION"); + + case 0x0110: return wxT("WM_INITDIALOG"); + case 0x0111: return wxT("WM_COMMAND"); + case 0x0112: return wxT("WM_SYSCOMMAND"); + case 0x0113: return wxT("WM_TIMER"); + case 0x0114: return wxT("WM_HSCROLL"); + case 0x0115: return wxT("WM_VSCROLL"); + case 0x0116: return wxT("WM_INITMENU"); + case 0x0117: return wxT("WM_INITMENUPOPUP"); + case 0x011F: return wxT("WM_MENUSELECT"); + case 0x0120: return wxT("WM_MENUCHAR"); + case 0x0121: return wxT("WM_ENTERIDLE"); + case 0x0200: return wxT("WM_MOUSEMOVE"); + case 0x0201: return wxT("WM_LBUTTONDOWN"); + case 0x0202: return wxT("WM_LBUTTONUP"); + case 0x0203: return wxT("WM_LBUTTONDBLCLK"); + case 0x0204: return wxT("WM_RBUTTONDOWN"); + case 0x0205: return wxT("WM_RBUTTONUP"); + case 0x0206: return wxT("WM_RBUTTONDBLCLK"); + case 0x0207: return wxT("WM_MBUTTONDOWN"); + case 0x0208: return wxT("WM_MBUTTONUP"); + case 0x0209: return wxT("WM_MBUTTONDBLCLK"); + case 0x020A: return wxT("WM_MOUSEWHEEL"); + case 0x0210: return wxT("WM_PARENTNOTIFY"); + case 0x0211: return wxT("WM_ENTERMENULOOP"); + case 0x0212: return wxT("WM_EXITMENULOOP"); + + case 0x0213: return wxT("WM_NEXTMENU"); + case 0x0214: return wxT("WM_SIZING"); + case 0x0215: return wxT("WM_CAPTURECHANGED"); + case 0x0216: return wxT("WM_MOVING"); + case 0x0218: return wxT("WM_POWERBROADCAST"); + case 0x0219: return wxT("WM_DEVICECHANGE"); + + case 0x0220: return wxT("WM_MDICREATE"); + case 0x0221: return wxT("WM_MDIDESTROY"); + case 0x0222: return wxT("WM_MDIACTIVATE"); + case 0x0223: return wxT("WM_MDIRESTORE"); + case 0x0224: return wxT("WM_MDINEXT"); + case 0x0225: return wxT("WM_MDIMAXIMIZE"); + case 0x0226: return wxT("WM_MDITILE"); + case 0x0227: return wxT("WM_MDICASCADE"); + case 0x0228: return wxT("WM_MDIICONARRANGE"); + case 0x0229: return wxT("WM_MDIGETACTIVE"); + case 0x0230: return wxT("WM_MDISETMENU"); + case 0x0233: return wxT("WM_DROPFILES"); + + case 0x0281: return wxT("WM_IME_SETCONTEXT"); + case 0x0282: return wxT("WM_IME_NOTIFY"); + case 0x0283: return wxT("WM_IME_CONTROL"); + case 0x0284: return wxT("WM_IME_COMPOSITIONFULL"); + case 0x0285: return wxT("WM_IME_SELECT"); + case 0x0286: return wxT("WM_IME_CHAR"); + case 0x0290: return wxT("WM_IME_KEYDOWN"); + case 0x0291: return wxT("WM_IME_KEYUP"); + + case 0x0300: return wxT("WM_CUT"); + case 0x0301: return wxT("WM_COPY"); + case 0x0302: return wxT("WM_PASTE"); + case 0x0303: return wxT("WM_CLEAR"); + case 0x0304: return wxT("WM_UNDO"); + case 0x0305: return wxT("WM_RENDERFORMAT"); + case 0x0306: return wxT("WM_RENDERALLFORMATS"); + case 0x0307: return wxT("WM_DESTROYCLIPBOARD"); + case 0x0308: return wxT("WM_DRAWCLIPBOARD"); + case 0x0309: return wxT("WM_PAINTCLIPBOARD"); + case 0x030A: return wxT("WM_VSCROLLCLIPBOARD"); + case 0x030B: return wxT("WM_SIZECLIPBOARD"); + case 0x030C: return wxT("WM_ASKCBFORMATNAME"); + case 0x030D: return wxT("WM_CHANGECBCHAIN"); + case 0x030E: return wxT("WM_HSCROLLCLIPBOARD"); + 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 + + // common controls messages - although they're not strictly speaking + // standard, it's nice to decode them nevertheless + + // listview + case 0x1000 + 0: return wxT("LVM_GETBKCOLOR"); + case 0x1000 + 1: return wxT("LVM_SETBKCOLOR"); + case 0x1000 + 2: return wxT("LVM_GETIMAGELIST"); + case 0x1000 + 3: return wxT("LVM_SETIMAGELIST"); + case 0x1000 + 4: return wxT("LVM_GETITEMCOUNT"); + case 0x1000 + 5: return wxT("LVM_GETITEMA"); + case 0x1000 + 75: return wxT("LVM_GETITEMW"); + case 0x1000 + 6: return wxT("LVM_SETITEMA"); + case 0x1000 + 76: return wxT("LVM_SETITEMW"); + case 0x1000 + 7: return wxT("LVM_INSERTITEMA"); + case 0x1000 + 77: return wxT("LVM_INSERTITEMW"); + case 0x1000 + 8: return wxT("LVM_DELETEITEM"); + case 0x1000 + 9: return wxT("LVM_DELETEALLITEMS"); + case 0x1000 + 10: return wxT("LVM_GETCALLBACKMASK"); + case 0x1000 + 11: return wxT("LVM_SETCALLBACKMASK"); + case 0x1000 + 12: return wxT("LVM_GETNEXTITEM"); + case 0x1000 + 13: return wxT("LVM_FINDITEMA"); + case 0x1000 + 83: return wxT("LVM_FINDITEMW"); + case 0x1000 + 14: return wxT("LVM_GETITEMRECT"); + case 0x1000 + 15: return wxT("LVM_SETITEMPOSITION"); + case 0x1000 + 16: return wxT("LVM_GETITEMPOSITION"); + case 0x1000 + 17: return wxT("LVM_GETSTRINGWIDTHA"); + case 0x1000 + 87: return wxT("LVM_GETSTRINGWIDTHW"); + case 0x1000 + 18: return wxT("LVM_HITTEST"); + case 0x1000 + 19: return wxT("LVM_ENSUREVISIBLE"); + case 0x1000 + 20: return wxT("LVM_SCROLL"); + case 0x1000 + 21: return wxT("LVM_REDRAWITEMS"); + case 0x1000 + 22: return wxT("LVM_ARRANGE"); + case 0x1000 + 23: return wxT("LVM_EDITLABELA"); + case 0x1000 + 118: return wxT("LVM_EDITLABELW"); + case 0x1000 + 24: return wxT("LVM_GETEDITCONTROL"); + case 0x1000 + 25: return wxT("LVM_GETCOLUMNA"); + case 0x1000 + 95: return wxT("LVM_GETCOLUMNW"); + case 0x1000 + 26: return wxT("LVM_SETCOLUMNA"); + case 0x1000 + 96: return wxT("LVM_SETCOLUMNW"); + case 0x1000 + 27: return wxT("LVM_INSERTCOLUMNA"); + case 0x1000 + 97: return wxT("LVM_INSERTCOLUMNW"); + case 0x1000 + 28: return wxT("LVM_DELETECOLUMN"); + case 0x1000 + 29: return wxT("LVM_GETCOLUMNWIDTH"); + case 0x1000 + 30: return wxT("LVM_SETCOLUMNWIDTH"); + case 0x1000 + 31: return wxT("LVM_GETHEADER"); + case 0x1000 + 33: return wxT("LVM_CREATEDRAGIMAGE"); + case 0x1000 + 34: return wxT("LVM_GETVIEWRECT"); + case 0x1000 + 35: return wxT("LVM_GETTEXTCOLOR"); + case 0x1000 + 36: return wxT("LVM_SETTEXTCOLOR"); + case 0x1000 + 37: return wxT("LVM_GETTEXTBKCOLOR"); + case 0x1000 + 38: return wxT("LVM_SETTEXTBKCOLOR"); + case 0x1000 + 39: return wxT("LVM_GETTOPINDEX"); + case 0x1000 + 40: return wxT("LVM_GETCOUNTPERPAGE"); + case 0x1000 + 41: return wxT("LVM_GETORIGIN"); + case 0x1000 + 42: return wxT("LVM_UPDATE"); + case 0x1000 + 43: return wxT("LVM_SETITEMSTATE"); + case 0x1000 + 44: return wxT("LVM_GETITEMSTATE"); + case 0x1000 + 45: return wxT("LVM_GETITEMTEXTA"); + case 0x1000 + 115: return wxT("LVM_GETITEMTEXTW"); + case 0x1000 + 46: return wxT("LVM_SETITEMTEXTA"); + case 0x1000 + 116: return wxT("LVM_SETITEMTEXTW"); + case 0x1000 + 47: return wxT("LVM_SETITEMCOUNT"); + case 0x1000 + 48: return wxT("LVM_SORTITEMS"); + case 0x1000 + 49: return wxT("LVM_SETITEMPOSITION32"); + case 0x1000 + 50: return wxT("LVM_GETSELECTEDCOUNT"); + case 0x1000 + 51: return wxT("LVM_GETITEMSPACING"); + case 0x1000 + 52: return wxT("LVM_GETISEARCHSTRINGA"); + case 0x1000 + 117: return wxT("LVM_GETISEARCHSTRINGW"); + case 0x1000 + 53: return wxT("LVM_SETICONSPACING"); + case 0x1000 + 54: return wxT("LVM_SETEXTENDEDLISTVIEWSTYLE"); + case 0x1000 + 55: return wxT("LVM_GETEXTENDEDLISTVIEWSTYLE"); + case 0x1000 + 56: return wxT("LVM_GETSUBITEMRECT"); + case 0x1000 + 57: return wxT("LVM_SUBITEMHITTEST"); + case 0x1000 + 58: return wxT("LVM_SETCOLUMNORDERARRAY"); + case 0x1000 + 59: return wxT("LVM_GETCOLUMNORDERARRAY"); + case 0x1000 + 60: return wxT("LVM_SETHOTITEM"); + case 0x1000 + 61: return wxT("LVM_GETHOTITEM"); + case 0x1000 + 62: return wxT("LVM_SETHOTCURSOR"); + case 0x1000 + 63: return wxT("LVM_GETHOTCURSOR"); + case 0x1000 + 64: return wxT("LVM_APPROXIMATEVIEWRECT"); + case 0x1000 + 65: return wxT("LVM_SETWORKAREA"); + + // tree view + case 0x1100 + 0: return wxT("TVM_INSERTITEMA"); + case 0x1100 + 50: return wxT("TVM_INSERTITEMW"); + case 0x1100 + 1: return wxT("TVM_DELETEITEM"); + case 0x1100 + 2: return wxT("TVM_EXPAND"); + case 0x1100 + 4: return wxT("TVM_GETITEMRECT"); + case 0x1100 + 5: return wxT("TVM_GETCOUNT"); + case 0x1100 + 6: return wxT("TVM_GETINDENT"); + case 0x1100 + 7: return wxT("TVM_SETINDENT"); + case 0x1100 + 8: return wxT("TVM_GETIMAGELIST"); + case 0x1100 + 9: return wxT("TVM_SETIMAGELIST"); + case 0x1100 + 10: return wxT("TVM_GETNEXTITEM"); + case 0x1100 + 11: return wxT("TVM_SELECTITEM"); + case 0x1100 + 12: return wxT("TVM_GETITEMA"); + case 0x1100 + 62: return wxT("TVM_GETITEMW"); + case 0x1100 + 13: return wxT("TVM_SETITEMA"); + case 0x1100 + 63: return wxT("TVM_SETITEMW"); + case 0x1100 + 14: return wxT("TVM_EDITLABELA"); + case 0x1100 + 65: return wxT("TVM_EDITLABELW"); + case 0x1100 + 15: return wxT("TVM_GETEDITCONTROL"); + case 0x1100 + 16: return wxT("TVM_GETVISIBLECOUNT"); + case 0x1100 + 17: return wxT("TVM_HITTEST"); + case 0x1100 + 18: return wxT("TVM_CREATEDRAGIMAGE"); + case 0x1100 + 19: return wxT("TVM_SORTCHILDREN"); + case 0x1100 + 20: return wxT("TVM_ENSUREVISIBLE"); + case 0x1100 + 21: return wxT("TVM_SORTCHILDRENCB"); + case 0x1100 + 22: return wxT("TVM_ENDEDITLABELNOW"); + case 0x1100 + 23: return wxT("TVM_GETISEARCHSTRINGA"); + case 0x1100 + 64: return wxT("TVM_GETISEARCHSTRINGW"); + case 0x1100 + 24: return wxT("TVM_SETTOOLTIPS"); + case 0x1100 + 25: return wxT("TVM_GETTOOLTIPS"); + + // header + case 0x1200 + 0: return wxT("HDM_GETITEMCOUNT"); + case 0x1200 + 1: return wxT("HDM_INSERTITEMA"); + case 0x1200 + 10: return wxT("HDM_INSERTITEMW"); + case 0x1200 + 2: return wxT("HDM_DELETEITEM"); + case 0x1200 + 3: return wxT("HDM_GETITEMA"); + case 0x1200 + 11: return wxT("HDM_GETITEMW"); + case 0x1200 + 4: return wxT("HDM_SETITEMA"); + case 0x1200 + 12: return wxT("HDM_SETITEMW"); + case 0x1200 + 5: return wxT("HDM_LAYOUT"); + case 0x1200 + 6: return wxT("HDM_HITTEST"); + case 0x1200 + 7: return wxT("HDM_GETITEMRECT"); + case 0x1200 + 8: return wxT("HDM_SETIMAGELIST"); + case 0x1200 + 9: return wxT("HDM_GETIMAGELIST"); + case 0x1200 + 15: return wxT("HDM_ORDERTOINDEX"); + case 0x1200 + 16: return wxT("HDM_CREATEDRAGIMAGE"); + case 0x1200 + 17: return wxT("HDM_GETORDERARRAY"); + case 0x1200 + 18: return wxT("HDM_SETORDERARRAY"); + case 0x1200 + 19: return wxT("HDM_SETHOTDIVIDER"); + + // tab control + case 0x1300 + 2: return wxT("TCM_GETIMAGELIST"); + case 0x1300 + 3: return wxT("TCM_SETIMAGELIST"); + case 0x1300 + 4: return wxT("TCM_GETITEMCOUNT"); + case 0x1300 + 5: return wxT("TCM_GETITEMA"); + case 0x1300 + 60: return wxT("TCM_GETITEMW"); + case 0x1300 + 6: return wxT("TCM_SETITEMA"); + case 0x1300 + 61: return wxT("TCM_SETITEMW"); + case 0x1300 + 7: return wxT("TCM_INSERTITEMA"); + case 0x1300 + 62: return wxT("TCM_INSERTITEMW"); + case 0x1300 + 8: return wxT("TCM_DELETEITEM"); + case 0x1300 + 9: return wxT("TCM_DELETEALLITEMS"); + case 0x1300 + 10: return wxT("TCM_GETITEMRECT"); + case 0x1300 + 11: return wxT("TCM_GETCURSEL"); + case 0x1300 + 12: return wxT("TCM_SETCURSEL"); + case 0x1300 + 13: return wxT("TCM_HITTEST"); + case 0x1300 + 14: return wxT("TCM_SETITEMEXTRA"); + case 0x1300 + 40: return wxT("TCM_ADJUSTRECT"); + case 0x1300 + 41: return wxT("TCM_SETITEMSIZE"); + case 0x1300 + 42: return wxT("TCM_REMOVEIMAGE"); + case 0x1300 + 43: return wxT("TCM_SETPADDING"); + case 0x1300 + 44: return wxT("TCM_GETROWCOUNT"); + case 0x1300 + 45: return wxT("TCM_GETTOOLTIPS"); + case 0x1300 + 46: return wxT("TCM_SETTOOLTIPS"); + case 0x1300 + 47: return wxT("TCM_GETCURFOCUS"); + case 0x1300 + 48: return wxT("TCM_SETCURFOCUS"); + case 0x1300 + 49: return wxT("TCM_SETMINTABWIDTH"); + case 0x1300 + 50: return wxT("TCM_DESELECTALL"); + + // toolbar + case WM_USER+1: return wxT("TB_ENABLEBUTTON"); + case WM_USER+2: return wxT("TB_CHECKBUTTON"); + case WM_USER+3: return wxT("TB_PRESSBUTTON"); + case WM_USER+4: return wxT("TB_HIDEBUTTON"); + case WM_USER+5: return wxT("TB_INDETERMINATE"); + case WM_USER+9: return wxT("TB_ISBUTTONENABLED"); + case WM_USER+10: return wxT("TB_ISBUTTONCHECKED"); + case WM_USER+11: return wxT("TB_ISBUTTONPRESSED"); + case WM_USER+12: return wxT("TB_ISBUTTONHIDDEN"); + case WM_USER+13: return wxT("TB_ISBUTTONINDETERMINATE"); + case WM_USER+17: return wxT("TB_SETSTATE"); + case WM_USER+18: return wxT("TB_GETSTATE"); + case WM_USER+19: return wxT("TB_ADDBITMAP"); + case WM_USER+20: return wxT("TB_ADDBUTTONS"); + case WM_USER+21: return wxT("TB_INSERTBUTTON"); + case WM_USER+22: return wxT("TB_DELETEBUTTON"); + case WM_USER+23: return wxT("TB_GETBUTTON"); + case WM_USER+24: return wxT("TB_BUTTONCOUNT"); + case WM_USER+25: return wxT("TB_COMMANDTOINDEX"); + case WM_USER+26: return wxT("TB_SAVERESTOREA"); + case WM_USER+76: return wxT("TB_SAVERESTOREW"); + case WM_USER+27: return wxT("TB_CUSTOMIZE"); + case WM_USER+28: return wxT("TB_ADDSTRINGA"); + case WM_USER+77: return wxT("TB_ADDSTRINGW"); + case WM_USER+29: return wxT("TB_GETITEMRECT"); + case WM_USER+30: return wxT("TB_BUTTONSTRUCTSIZE"); + case WM_USER+31: return wxT("TB_SETBUTTONSIZE"); + case WM_USER+32: return wxT("TB_SETBITMAPSIZE"); + case WM_USER+33: return wxT("TB_AUTOSIZE"); + case WM_USER+35: return wxT("TB_GETTOOLTIPS"); + case WM_USER+36: return wxT("TB_SETTOOLTIPS"); + case WM_USER+37: return wxT("TB_SETPARENT"); + case WM_USER+39: return wxT("TB_SETROWS"); + case WM_USER+40: return wxT("TB_GETROWS"); + case WM_USER+42: return wxT("TB_SETCMDID"); + case WM_USER+43: return wxT("TB_CHANGEBITMAP"); + case WM_USER+44: return wxT("TB_GETBITMAP"); + case WM_USER+45: return wxT("TB_GETBUTTONTEXTA"); + case WM_USER+75: return wxT("TB_GETBUTTONTEXTW"); + case WM_USER+46: return wxT("TB_REPLACEBITMAP"); + case WM_USER+47: return wxT("TB_SETINDENT"); + case WM_USER+48: return wxT("TB_SETIMAGELIST"); + case WM_USER+49: return wxT("TB_GETIMAGELIST"); + case WM_USER+50: return wxT("TB_LOADIMAGES"); + case WM_USER+51: return wxT("TB_GETRECT"); + case WM_USER+52: return wxT("TB_SETHOTIMAGELIST"); + case WM_USER+53: return wxT("TB_GETHOTIMAGELIST"); + case WM_USER+54: return wxT("TB_SETDISABLEDIMAGELIST"); + case WM_USER+55: return wxT("TB_GETDISABLEDIMAGELIST"); + case WM_USER+56: return wxT("TB_SETSTYLE"); + case WM_USER+57: return wxT("TB_GETSTYLE"); + case WM_USER+58: return wxT("TB_GETBUTTONSIZE"); + case WM_USER+59: return wxT("TB_SETBUTTONWIDTH"); + case WM_USER+60: return wxT("TB_SETMAXTEXTROWS"); + case WM_USER+61: return wxT("TB_GETTEXTROWS"); + case WM_USER+41: return wxT("TB_GETBITMAPFLAGS"); + + default: + static wxString s_szBuf; + s_szBuf.Printf(wxT(""), message); + return s_szBuf.c_str(); } - else - GetClientSize(w, h); } +#endif //__WXDEBUG__ -void wxWindow::GetPositionConstraint(int *x, int *y) const +static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win) { - wxLayoutConstraints *constr = GetConstraints(); - if (constr) + // prepare the DC + TEXTMETRIC tm; + HWND hwnd = GetHwndOf(win); + HDC hdc = ::GetDC(hwnd); + +#if !wxDIALOG_UNIT_COMPATIBILITY + // and select the current font into it + HFONT hfont = GetHfontOf(win->GetFont()); + if ( hfont ) { - *x = constr->left.GetValue(); - *y = constr->top.GetValue(); + hfont = (HFONT)::SelectObject(hdc, hfont); } - else - GetPosition(x, y); -} - -bool wxWindow::Close(bool force) -{ - wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId); - event.SetEventObject(this); -#if WXWIN_COMPATIBILITY - event.SetForce(force); #endif - event.SetCanVeto(!force); - return (GetEventHandler()->ProcessEvent(event) && !event.GetVeto()); -} + // finally retrieve the text metrics from it + GetTextMetrics(hdc, &tm); -wxObject* wxWindow::GetChild(int number) const -{ - // Return a pointer to the Nth object in the Panel -// if (!GetChildren()) -// return(NULL) ; - wxNode *node = GetChildren().First(); - int n = number; - while (node && n--) - node = node->Next() ; - if (node) +#if !wxDIALOG_UNIT_COMPATIBILITY + // and clean up + if ( hfont ) { - wxObject *obj = (wxObject *)node->Data(); - return(obj) ; + (void)::SelectObject(hdc, hfont); } - else - return NULL ; -} - -void wxWindow::OnDefaultAction(wxControl *initiatingItem) -{ -/* This is obsolete now; if we wish to intercept listbox double-clicks, -* we explicitly intercept the wxEVT_COMMAND_LISTBOX_DOUBLECLICKED -* event. - - if (initiatingItem->IsKindOf(CLASSINFO(wxListBox))) - { - wxListBox *lbox = (wxListBox *)initiatingItem; - wxCommandEvent event(wxEVT_COMMAND_LEFT_DCLICK); - event.m_commandInt = -1; - if ((lbox->GetWindowStyleFlag() & wxLB_MULTIPLE) == 0) - { - event.m_commandString = copystring(lbox->GetStringSelection()); - event.m_commandInt = lbox->GetSelection(); - event.m_clientData = lbox->wxListBox::GetClientData(event.m_commandInt); - } - event.m_eventObject = lbox; - - lbox->ProcessCommand(event); +#endif - if (event.m_commandString) - delete[] event.m_commandString; - return; - } + ::ReleaseDC(hwnd, hdc); - wxButton *but = GetDefaultItem(); - if (but) - { - wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED); - event.SetEventObject(but); - but->Command(event); - } - */ + return tm; } -void wxWindow::Clear() +// Find the wxWindow at the current mouse position, returning the mouse +// position. +wxWindow* wxFindWindowAtPointer(wxPoint& pt) { - wxClientDC dc(this); - wxBrush brush(GetBackgroundColour(), wxSOLID); - dc.SetBackground(brush); - dc.Clear(); + pt = wxGetMousePosition(); + return wxFindWindowAtPoint(pt); } -// Fits the panel around the items -void wxWindow::Fit() +wxWindow* wxFindWindowAtPoint(const wxPoint& pt) { - int maxX = 0; - int maxY = 0; - wxNode *node = GetChildren().First(); - while ( node ) - { - wxWindow *win = (wxWindow *)node->Data(); - int wx, wy, ww, wh; - win->GetPosition(&wx, &wy); - win->GetSize(&ww, &wh); - if ( wx + ww > maxX ) - maxX = wx + ww; - if ( wy + wh > maxY ) - maxY = wy + wh; + POINT pt2; + pt2.x = pt.x; + pt2.y = pt.y; - node = node->Next(); - } - SetClientSize(maxX + 5, maxY + 5); + HWND hWnd = ::WindowFromPoint(pt2); + + return wxGetWindowFromHWND((WXHWND)hWnd); } -void wxWindow::SetValidator(const wxValidator& validator) +// Get the current mouse position. +wxPoint wxGetMousePosition() { - if ( m_windowValidator ) - delete m_windowValidator; - m_windowValidator = validator.Clone(); + POINT pt; +#ifdef __WXWINCE__ + GetCursorPosWinCE(&pt); +#else + GetCursorPos( & pt ); +#endif - if ( m_windowValidator ) - m_windowValidator->SetWindow(this) ; + return wxPoint(pt.x, pt.y); } -// Find a window by id or name -wxWindow *wxWindow::FindWindow(long id) +#if wxUSE_HOTKEY + +#if defined(__SMARTPHONE__) || defined(__POCKETPC__) +static void WinCEUnregisterHotKey(int modifiers, int id) { - if ( GetId() == id) - return this; + // Register hotkeys for the hardware buttons + HINSTANCE hCoreDll; + typedef BOOL (WINAPI *UnregisterFunc1Proc)(UINT, UINT); - wxNode *node = GetChildren().First(); - while ( node ) + UnregisterFunc1Proc procUnregisterFunc; + hCoreDll = LoadLibrary(_T("coredll.dll")); + if (hCoreDll) { - wxWindow *child = (wxWindow *)node->Data(); - wxWindow *found = child->FindWindow(id); - if ( found ) - return found; - node = node->Next(); + procUnregisterFunc = (UnregisterFunc1Proc)GetProcAddress(hCoreDll, _T("UnregisterFunc1")); + if (procUnregisterFunc) + procUnregisterFunc(modifiers, id); + FreeLibrary(hCoreDll); } - return NULL; } +#endif -wxWindow *wxWindow::FindWindow(const wxString& name) -{ - if ( GetName() == name) - return this; +bool wxWindowMSW::RegisterHotKey(int hotkeyId, int modifiers, int keycode) +{ + UINT win_modifiers=0; + if ( modifiers & wxMOD_ALT ) + win_modifiers |= MOD_ALT; + if ( modifiers & wxMOD_SHIFT ) + win_modifiers |= MOD_SHIFT; + if ( modifiers & wxMOD_CONTROL ) + win_modifiers |= MOD_CONTROL; + if ( modifiers & wxMOD_WIN ) + win_modifiers |= MOD_WIN; + +#if defined(__SMARTPHONE__) || defined(__POCKETPC__) + // Required for PPC and Smartphone hardware buttons + if (keycode >= WXK_SPECIAL1 && keycode <= WXK_SPECIAL20) + WinCEUnregisterHotKey(win_modifiers, hotkeyId); +#endif - wxNode *node = GetChildren().First(); - while ( node ) + if ( !::RegisterHotKey(GetHwnd(), hotkeyId, win_modifiers, keycode) ) { - wxWindow *child = (wxWindow *)node->Data(); - wxWindow *found = child->FindWindow(name); - if ( found ) - return found; - node = node->Next(); - } - return NULL; -} + wxLogLastError(_T("RegisterHotKey")); -/* TODO -// Default input behaviour for a scrolling canvas should be to scroll -// according to the cursor keys pressed -void wxWindow::OnChar(wxKeyEvent& event) -{ -int x_page = 0; -int y_page = 0; -int start_x = 0; -int start_y = 0; -// Bugfix Begin -int v_width = 0; -int v_height = 0; -int y_pages = 0; -// Bugfix End - - GetScrollUnitsPerPage(&x_page, &y_page); - // Bugfix Begin - GetVirtualSize(&v_width,&v_height); - // Bugfix End - ViewStart(&start_x, &start_y); - // Bugfix begin - if (vert_units) - y_pages = (int)(v_height/vert_units) - y_page; - - #ifdef __WXMSW__ - int y = 0; - #else - int y = y_page-1; - #endif - // Bugfix End - switch (event.keyCode) - { - case WXK_PRIOR: - { - // BugFix Begin - if (y_page > 0) - { - if (start_y - y_page > 0) - Scroll(start_x, start_y - y_page); - else - Scroll(start_x, 0); - } - // Bugfix End - break; - } - case WXK_NEXT: - { - // Bugfix Begin - if ((y_page > 0) && (start_y <= y_pages-y-1)) - { - if (y_pages + y < start_y + y_page) - Scroll(start_x, y_pages + y); - else - Scroll(start_x, start_y + y_page); - } - // Bugfix End - break; - } - case WXK_UP: - { - if ((y_page > 0) && (start_y >= 1)) - Scroll(start_x, start_y - 1); - break; - } - case WXK_DOWN: - { - // Bugfix Begin - if ((y_page > 0) && (start_y <= y_pages-y-1)) - // Bugfix End - { - Scroll(start_x, start_y + 1); - } - break; - } - case WXK_LEFT: - { - if ((x_page > 0) && (start_x >= 1)) - Scroll(start_x - 1, start_y); - break; - } - case WXK_RIGHT: - { - if (x_page > 0) - Scroll(start_x + 1, start_y); - break; - } - case WXK_HOME: - { - Scroll(0, 0); - break; - } - // This is new - case WXK_END: - { - Scroll(start_x, y_pages+y); - break; - } - // end - } + return false; } -*/ -// Setup background and foreground colours correctly -void wxWindow::SetupColours() -{ - if (GetParent()) - SetBackgroundColour(GetParent()->GetBackgroundColour()); + return true; } -void wxWindow::OnIdle(wxIdleEvent& event) +bool wxWindowMSW::UnregisterHotKey(int hotkeyId) { - // Check if we need to send a LEAVE event - if (m_mouseInWindow) - { - POINT pt; - ::GetCursorPos(&pt); - if (::WindowFromPoint(pt) != (HWND) GetHWND()) - { - // Generate a LEAVE event - m_mouseInWindow = FALSE; - - int state = 0; - if (::GetKeyState(VK_SHIFT) != 0) - state |= MK_SHIFT; - if (::GetKeyState(VK_CONTROL) != 0) - state |= MK_CONTROL; +#if defined(__SMARTPHONE__) || defined(__POCKETPC__) + WinCEUnregisterHotKey(MOD_WIN, hotkeyId); +#endif - // Unfortunately the mouse button and keyboard state may have changed - // by the time the OnIdle function is called, so 'state' may be - // meaningless. + if ( !::UnregisterHotKey(GetHwnd(), hotkeyId) ) + { + wxLogLastError(_T("UnregisterHotKey")); - MSWOnMouseLeave(pt.x, pt.y, state); - } + return false; } - UpdateWindowUI(); -} -// Raise the window to the top of the Z order -void wxWindow::Raise() -{ - ::BringWindowToTop((HWND) GetHWND()); + return true; } -// Lower the window to the bottom of the Z order -void wxWindow::Lower() -{ - ::SetWindowPos((HWND) GetHWND(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE); -} +#if wxUSE_ACCEL -long wxWindow::MSWGetDlgCode() +bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam) { - // default: just forward to def window proc (the msg has no parameters) - return MSWDefWindowProc(WM_GETDLGCODE, 0, 0); -} + int hotkeyId = wParam; + int virtualKey = HIWORD(lParam); + int win_modifiers = LOWORD(lParam); -bool wxWindow::AcceptsFocus() const -{ - // invisible and disabled controls don't need focus - return IsShown() && IsEnabled(); -} + wxKeyEvent event(CreateKeyEvent(wxEVT_HOTKEY, virtualKey, wParam, lParam)); + event.SetId(hotkeyId); + event.m_shiftDown = (win_modifiers & MOD_SHIFT) != 0; + event.m_controlDown = (win_modifiers & MOD_CONTROL) != 0; + event.m_altDown = (win_modifiers & MOD_ALT) != 0; + event.m_metaDown = (win_modifiers & MOD_WIN) != 0; -// Update region access -wxRegion wxWindow::GetUpdateRegion() const -{ - return m_updateRegion; + return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::IsExposed(int x, int y, int w, int h) const -{ - return (m_updateRegion.Contains(x, y, w, h) != wxOutRegion); -} +#endif // wxUSE_ACCEL -bool wxWindow::IsExposed(const wxPoint& pt) const -{ - return (m_updateRegion.Contains(pt) != wxOutRegion); -} +#endif // wxUSE_HOTKEY -bool wxWindow::IsExposed(const wxRect& rect) const -{ - return (m_updateRegion.Contains(rect) != wxOutRegion); -} +// Not tested under WinCE +#ifndef __WXWINCE__ -// Set this window to be the child of 'parent'. -bool wxWindow::Reparent(wxWindow *parent) +// this class installs a message hook which really wakes up our idle processing +// each time a WM_NULL is received (wxWakeUpIdle does this), even if we're +// sitting inside a local modal loop (e.g. a menu is opened or scrollbar is +// being dragged or even inside ::MessageBox()) and so don't control message +// dispatching otherwise +class wxIdleWakeUpModule : public wxModule { - if (parent == GetParent()) - return TRUE; - - // Unlink this window from the existing parent. - if (GetParent()) +public: + virtual bool OnInit() { - GetParent()->RemoveChild(this); + ms_hMsgHookProc = ::SetWindowsHookEx + ( + WH_GETMESSAGE, + &wxIdleWakeUpModule::MsgHookProc, + NULL, + GetCurrentThreadId() + ); + + if ( !ms_hMsgHookProc ) + { + wxLogLastError(_T("SetWindowsHookEx(WH_GETMESSAGE)")); + + return false; + } + + return true; } - else - wxTopLevelWindows.DeleteObject(this); - HWND hWndParent = 0; - HWND hWndChild = (HWND) GetHWND(); - if (parent != (wxWindow*) NULL) + virtual void OnExit() { - parent->AddChild(this); - hWndParent = (HWND) parent->GetHWND(); + ::UnhookWindowsHookEx(wxIdleWakeUpModule::ms_hMsgHookProc); } - else - wxTopLevelWindows.Append(this); - ::SetParent(hWndChild, hWndParent); + static LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam) + { + MSG *msg = (MSG*)lParam; - return TRUE; -} + // only process the message if it is actually going to be removed from + // the message queue, this prevents that the same event from being + // processed multiple times if now someone just called PeekMessage() + if ( msg->message == WM_NULL && wParam == PM_REMOVE ) + { + wxTheApp->ProcessPendingEvents(); + } -#ifdef __WXDEBUG__ -const char *wxGetMessageName(int message) -{ - switch ( message ) { - case 0x0000: return "WM_NULL"; - case 0x0001: return "WM_CREATE"; - case 0x0002: return "WM_DESTROY"; - case 0x0003: return "WM_MOVE"; - case 0x0005: return "WM_SIZE"; - case 0x0006: return "WM_ACTIVATE"; - case 0x0007: return "WM_SETFOCUS"; - case 0x0008: return "WM_KILLFOCUS"; - case 0x000A: return "WM_ENABLE"; - case 0x000B: return "WM_SETREDRAW"; - case 0x000C: return "WM_SETTEXT"; - case 0x000D: return "WM_GETTEXT"; - case 0x000E: return "WM_GETTEXTLENGTH"; - case 0x000F: return "WM_PAINT"; - case 0x0010: return "WM_CLOSE"; - case 0x0011: return "WM_QUERYENDSESSION"; - case 0x0012: return "WM_QUIT"; - case 0x0013: return "WM_QUERYOPEN"; - case 0x0014: return "WM_ERASEBKGND"; - case 0x0015: return "WM_SYSCOLORCHANGE"; - case 0x0016: return "WM_ENDSESSION"; - case 0x0017: return "WM_SYSTEMERROR"; - case 0x0018: return "WM_SHOWWINDOW"; - case 0x0019: return "WM_CTLCOLOR"; - case 0x001A: return "WM_WININICHANGE"; - case 0x001B: return "WM_DEVMODECHANGE"; - case 0x001C: return "WM_ACTIVATEAPP"; - case 0x001D: return "WM_FONTCHANGE"; - case 0x001E: return "WM_TIMECHANGE"; - case 0x001F: return "WM_CANCELMODE"; - case 0x0020: return "WM_SETCURSOR"; - case 0x0021: return "WM_MOUSEACTIVATE"; - case 0x0022: return "WM_CHILDACTIVATE"; - case 0x0023: return "WM_QUEUESYNC"; - case 0x0024: return "WM_GETMINMAXINFO"; - case 0x0026: return "WM_PAINTICON"; - case 0x0027: return "WM_ICONERASEBKGND"; - case 0x0028: return "WM_NEXTDLGCTL"; - case 0x002A: return "WM_SPOOLERSTATUS"; - case 0x002B: return "WM_DRAWITEM"; - case 0x002C: return "WM_MEASUREITEM"; - case 0x002D: return "WM_DELETEITEM"; - case 0x002E: return "WM_VKEYTOITEM"; - case 0x002F: return "WM_CHARTOITEM"; - case 0x0030: return "WM_SETFONT"; - case 0x0031: return "WM_GETFONT"; - case 0x0037: return "WM_QUERYDRAGICON"; - case 0x0039: return "WM_COMPAREITEM"; - case 0x0041: return "WM_COMPACTING"; - case 0x0044: return "WM_COMMNOTIFY"; - case 0x0046: return "WM_WINDOWPOSCHANGING"; - case 0x0047: return "WM_WINDOWPOSCHANGED"; - case 0x0048: return "WM_POWER"; - -#ifdef __WIN32__ - case 0x004A: return "WM_COPYDATA"; - case 0x004B: return "WM_CANCELJOURNAL"; - case 0x004E: return "WM_NOTIFY"; - case 0x0050: return "WM_INPUTLANGCHANGEREQUEST"; - case 0x0051: return "WM_INPUTLANGCHANGE"; - case 0x0052: return "WM_TCARD"; - case 0x0053: return "WM_HELP"; - case 0x0054: return "WM_USERCHANGED"; - case 0x0055: return "WM_NOTIFYFORMAT"; - case 0x007B: return "WM_CONTEXTMENU"; - case 0x007C: return "WM_STYLECHANGING"; - case 0x007D: return "WM_STYLECHANGED"; - case 0x007E: return "WM_DISPLAYCHANGE"; - case 0x007F: return "WM_GETICON"; - case 0x0080: return "WM_SETICON"; -#endif //WIN32 - - case 0x0081: return "WM_NCCREATE"; - case 0x0082: return "WM_NCDESTROY"; - case 0x0083: return "WM_NCCALCSIZE"; - case 0x0084: return "WM_NCHITTEST"; - case 0x0085: return "WM_NCPAINT"; - case 0x0086: return "WM_NCACTIVATE"; - case 0x0087: return "WM_GETDLGCODE"; - case 0x00A0: return "WM_NCMOUSEMOVE"; - case 0x00A1: return "WM_NCLBUTTONDOWN"; - case 0x00A2: return "WM_NCLBUTTONUP"; - case 0x00A3: return "WM_NCLBUTTONDBLCLK"; - case 0x00A4: return "WM_NCRBUTTONDOWN"; - case 0x00A5: return "WM_NCRBUTTONUP"; - case 0x00A6: return "WM_NCRBUTTONDBLCLK"; - case 0x00A7: return "WM_NCMBUTTONDOWN"; - case 0x00A8: return "WM_NCMBUTTONUP"; - case 0x00A9: return "WM_NCMBUTTONDBLCLK"; - case 0x0100: return "WM_KEYDOWN"; - case 0x0101: return "WM_KEYUP"; - case 0x0102: return "WM_CHAR"; - case 0x0103: return "WM_DEADCHAR"; - case 0x0104: return "WM_SYSKEYDOWN"; - case 0x0105: return "WM_SYSKEYUP"; - case 0x0106: return "WM_SYSCHAR"; - case 0x0107: return "WM_SYSDEADCHAR"; - case 0x0108: return "WM_KEYLAST"; - -#ifdef __WIN32__ - case 0x010D: return "WM_IME_STARTCOMPOSITION"; - case 0x010E: return "WM_IME_ENDCOMPOSITION"; - case 0x010F: return "WM_IME_COMPOSITION"; -#endif //WIN32 - - case 0x0110: return "WM_INITDIALOG"; - case 0x0111: return "WM_COMMAND"; - case 0x0112: return "WM_SYSCOMMAND"; - case 0x0113: return "WM_TIMER"; - case 0x0114: return "WM_HSCROLL"; - case 0x0115: return "WM_VSCROLL"; - case 0x0116: return "WM_INITMENU"; - case 0x0117: return "WM_INITMENUPOPUP"; - case 0x011F: return "WM_MENUSELECT"; - case 0x0120: return "WM_MENUCHAR"; - case 0x0121: return "WM_ENTERIDLE"; - case 0x0200: return "WM_MOUSEMOVE"; - case 0x0201: return "WM_LBUTTONDOWN"; - case 0x0202: return "WM_LBUTTONUP"; - case 0x0203: return "WM_LBUTTONDBLCLK"; - case 0x0204: return "WM_RBUTTONDOWN"; - case 0x0205: return "WM_RBUTTONUP"; - case 0x0206: return "WM_RBUTTONDBLCLK"; - case 0x0207: return "WM_MBUTTONDOWN"; - case 0x0208: return "WM_MBUTTONUP"; - case 0x0209: return "WM_MBUTTONDBLCLK"; - case 0x0210: return "WM_PARENTNOTIFY"; - case 0x0211: return "WM_ENTERMENULOOP"; - case 0x0212: return "WM_EXITMENULOOP"; - -#ifdef __WIN32__ - case 0x0213: return "WM_NEXTMENU"; - case 0x0214: return "WM_SIZING"; - case 0x0215: return "WM_CAPTURECHANGED"; - case 0x0216: return "WM_MOVING"; - case 0x0218: return "WM_POWERBROADCAST"; - case 0x0219: return "WM_DEVICECHANGE"; -#endif //WIN32 - - case 0x0220: return "WM_MDICREATE"; - case 0x0221: return "WM_MDIDESTROY"; - case 0x0222: return "WM_MDIACTIVATE"; - case 0x0223: return "WM_MDIRESTORE"; - case 0x0224: return "WM_MDINEXT"; - case 0x0225: return "WM_MDIMAXIMIZE"; - case 0x0226: return "WM_MDITILE"; - case 0x0227: return "WM_MDICASCADE"; - case 0x0228: return "WM_MDIICONARRANGE"; - case 0x0229: return "WM_MDIGETACTIVE"; - case 0x0230: return "WM_MDISETMENU"; - case 0x0233: return "WM_DROPFILES"; - -#ifdef __WIN32__ - case 0x0281: return "WM_IME_SETCONTEXT"; - case 0x0282: return "WM_IME_NOTIFY"; - case 0x0283: return "WM_IME_CONTROL"; - case 0x0284: return "WM_IME_COMPOSITIONFULL"; - case 0x0285: return "WM_IME_SELECT"; - case 0x0286: return "WM_IME_CHAR"; - case 0x0290: return "WM_IME_KEYDOWN"; - case 0x0291: return "WM_IME_KEYUP"; -#endif //WIN32 - - case 0x0300: return "WM_CUT"; - case 0x0301: return "WM_COPY"; - case 0x0302: return "WM_PASTE"; - case 0x0303: return "WM_CLEAR"; - case 0x0304: return "WM_UNDO"; - case 0x0305: return "WM_RENDERFORMAT"; - case 0x0306: return "WM_RENDERALLFORMATS"; - case 0x0307: return "WM_DESTROYCLIPBOARD"; - case 0x0308: return "WM_DRAWCLIPBOARD"; - case 0x0309: return "WM_PAINTCLIPBOARD"; - case 0x030A: return "WM_VSCROLLCLIPBOARD"; - case 0x030B: return "WM_SIZECLIPBOARD"; - case 0x030C: return "WM_ASKCBFORMATNAME"; - case 0x030D: return "WM_CHANGECBCHAIN"; - case 0x030E: return "WM_HSCROLLCLIPBOARD"; - case 0x030F: return "WM_QUERYNEWPALETTE"; - case 0x0310: return "WM_PALETTEISCHANGING"; - case 0x0311: return "WM_PALETTECHANGED"; + return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam); + }; -#ifdef __WIN32__ - // common controls messages - although they're not strictly speaking - // standard, it's nice to decode them nevertheless +private: + static HHOOK ms_hMsgHookProc; - // listview - case 0x1000 + 0: return "LVM_GETBKCOLOR"; - case 0x1000 + 1: return "LVM_SETBKCOLOR"; - case 0x1000 + 2: return "LVM_GETIMAGELIST"; - case 0x1000 + 3: return "LVM_SETIMAGELIST"; - case 0x1000 + 4: return "LVM_GETITEMCOUNT"; - case 0x1000 + 5: return "LVM_GETITEMA"; - case 0x1000 + 75: return "LVM_GETITEMW"; - case 0x1000 + 6: return "LVM_SETITEMA"; - case 0x1000 + 76: return "LVM_SETITEMW"; - case 0x1000 + 7: return "LVM_INSERTITEMA"; - case 0x1000 + 77: return "LVM_INSERTITEMW"; - case 0x1000 + 8: return "LVM_DELETEITEM"; - case 0x1000 + 9: return "LVM_DELETEALLITEMS"; - case 0x1000 + 10: return "LVM_GETCALLBACKMASK"; - case 0x1000 + 11: return "LVM_SETCALLBACKMASK"; - case 0x1000 + 12: return "LVM_GETNEXTITEM"; - case 0x1000 + 13: return "LVM_FINDITEMA"; - case 0x1000 + 83: return "LVM_FINDITEMW"; - case 0x1000 + 14: return "LVM_GETITEMRECT"; - case 0x1000 + 15: return "LVM_SETITEMPOSITION"; - case 0x1000 + 16: return "LVM_GETITEMPOSITION"; - case 0x1000 + 17: return "LVM_GETSTRINGWIDTHA"; - case 0x1000 + 87: return "LVM_GETSTRINGWIDTHW"; - case 0x1000 + 18: return "LVM_HITTEST"; - case 0x1000 + 19: return "LVM_ENSUREVISIBLE"; - case 0x1000 + 20: return "LVM_SCROLL"; - case 0x1000 + 21: return "LVM_REDRAWITEMS"; - case 0x1000 + 22: return "LVM_ARRANGE"; - case 0x1000 + 23: return "LVM_EDITLABELA"; - case 0x1000 + 118: return "LVM_EDITLABELW"; - case 0x1000 + 24: return "LVM_GETEDITCONTROL"; - case 0x1000 + 25: return "LVM_GETCOLUMNA"; - case 0x1000 + 95: return "LVM_GETCOLUMNW"; - case 0x1000 + 26: return "LVM_SETCOLUMNA"; - case 0x1000 + 96: return "LVM_SETCOLUMNW"; - case 0x1000 + 27: return "LVM_INSERTCOLUMNA"; - case 0x1000 + 97: return "LVM_INSERTCOLUMNW"; - case 0x1000 + 28: return "LVM_DELETECOLUMN"; - case 0x1000 + 29: return "LVM_GETCOLUMNWIDTH"; - case 0x1000 + 30: return "LVM_SETCOLUMNWIDTH"; - case 0x1000 + 31: return "LVM_GETHEADER"; - case 0x1000 + 33: return "LVM_CREATEDRAGIMAGE"; - case 0x1000 + 34: return "LVM_GETVIEWRECT"; - case 0x1000 + 35: return "LVM_GETTEXTCOLOR"; - case 0x1000 + 36: return "LVM_SETTEXTCOLOR"; - case 0x1000 + 37: return "LVM_GETTEXTBKCOLOR"; - case 0x1000 + 38: return "LVM_SETTEXTBKCOLOR"; - case 0x1000 + 39: return "LVM_GETTOPINDEX"; - case 0x1000 + 40: return "LVM_GETCOUNTPERPAGE"; - case 0x1000 + 41: return "LVM_GETORIGIN"; - case 0x1000 + 42: return "LVM_UPDATE"; - case 0x1000 + 43: return "LVM_SETITEMSTATE"; - case 0x1000 + 44: return "LVM_GETITEMSTATE"; - case 0x1000 + 45: return "LVM_GETITEMTEXTA"; - case 0x1000 + 115: return "LVM_GETITEMTEXTW"; - case 0x1000 + 46: return "LVM_SETITEMTEXTA"; - case 0x1000 + 116: return "LVM_SETITEMTEXTW"; - case 0x1000 + 47: return "LVM_SETITEMCOUNT"; - case 0x1000 + 48: return "LVM_SORTITEMS"; - case 0x1000 + 49: return "LVM_SETITEMPOSITION32"; - case 0x1000 + 50: return "LVM_GETSELECTEDCOUNT"; - case 0x1000 + 51: return "LVM_GETITEMSPACING"; - case 0x1000 + 52: return "LVM_GETISEARCHSTRINGA"; - case 0x1000 + 117: return "LVM_GETISEARCHSTRINGW"; - case 0x1000 + 53: return "LVM_SETICONSPACING"; - case 0x1000 + 54: return "LVM_SETEXTENDEDLISTVIEWSTYLE"; - case 0x1000 + 55: return "LVM_GETEXTENDEDLISTVIEWSTYLE"; - case 0x1000 + 56: return "LVM_GETSUBITEMRECT"; - case 0x1000 + 57: return "LVM_SUBITEMHITTEST"; - case 0x1000 + 58: return "LVM_SETCOLUMNORDERARRAY"; - case 0x1000 + 59: return "LVM_GETCOLUMNORDERARRAY"; - case 0x1000 + 60: return "LVM_SETHOTITEM"; - case 0x1000 + 61: return "LVM_GETHOTITEM"; - case 0x1000 + 62: return "LVM_SETHOTCURSOR"; - case 0x1000 + 63: return "LVM_GETHOTCURSOR"; - case 0x1000 + 64: return "LVM_APPROXIMATEVIEWRECT"; - case 0x1000 + 65: return "LVM_SETWORKAREA"; + DECLARE_DYNAMIC_CLASS(wxIdleWakeUpModule) +}; - // tree view - case 0x1100 + 0: return "TVM_INSERTITEMA"; - case 0x1100 + 50: return "TVM_INSERTITEMW"; - case 0x1100 + 1: return "TVM_DELETEITEM"; - case 0x1100 + 2: return "TVM_EXPAND"; - case 0x1100 + 4: return "TVM_GETITEMRECT"; - case 0x1100 + 5: return "TVM_GETCOUNT"; - case 0x1100 + 6: return "TVM_GETINDENT"; - case 0x1100 + 7: return "TVM_SETINDENT"; - case 0x1100 + 8: return "TVM_GETIMAGELIST"; - case 0x1100 + 9: return "TVM_SETIMAGELIST"; - case 0x1100 + 10: return "TVM_GETNEXTITEM"; - case 0x1100 + 11: return "TVM_SELECTITEM"; - case 0x1100 + 12: return "TVM_GETITEMA"; - case 0x1100 + 62: return "TVM_GETITEMW"; - case 0x1100 + 13: return "TVM_SETITEMA"; - case 0x1100 + 63: return "TVM_SETITEMW"; - case 0x1100 + 14: return "TVM_EDITLABELA"; - case 0x1100 + 65: return "TVM_EDITLABELW"; - case 0x1100 + 15: return "TVM_GETEDITCONTROL"; - case 0x1100 + 16: return "TVM_GETVISIBLECOUNT"; - case 0x1100 + 17: return "TVM_HITTEST"; - case 0x1100 + 18: return "TVM_CREATEDRAGIMAGE"; - case 0x1100 + 19: return "TVM_SORTCHILDREN"; - case 0x1100 + 20: return "TVM_ENSUREVISIBLE"; - case 0x1100 + 21: return "TVM_SORTCHILDRENCB"; - case 0x1100 + 22: return "TVM_ENDEDITLABELNOW"; - case 0x1100 + 23: return "TVM_GETISEARCHSTRINGA"; - case 0x1100 + 64: return "TVM_GETISEARCHSTRINGW"; - case 0x1100 + 24: return "TVM_SETTOOLTIPS"; - case 0x1100 + 25: return "TVM_GETTOOLTIPS"; +HHOOK wxIdleWakeUpModule::ms_hMsgHookProc = 0; - // header - case 0x1200 + 0: return "HDM_GETITEMCOUNT"; - case 0x1200 + 1: return "HDM_INSERTITEMA"; - case 0x1200 + 10: return "HDM_INSERTITEMW"; - case 0x1200 + 2: return "HDM_DELETEITEM"; - case 0x1200 + 3: return "HDM_GETITEMA"; - case 0x1200 + 11: return "HDM_GETITEMW"; - case 0x1200 + 4: return "HDM_SETITEMA"; - case 0x1200 + 12: return "HDM_SETITEMW"; - case 0x1200 + 5: return "HDM_LAYOUT"; - case 0x1200 + 6: return "HDM_HITTEST"; - case 0x1200 + 7: return "HDM_GETITEMRECT"; - case 0x1200 + 8: return "HDM_SETIMAGELIST"; - case 0x1200 + 9: return "HDM_GETIMAGELIST"; - case 0x1200 + 15: return "HDM_ORDERTOINDEX"; - case 0x1200 + 16: return "HDM_CREATEDRAGIMAGE"; - case 0x1200 + 17: return "HDM_GETORDERARRAY"; - case 0x1200 + 18: return "HDM_SETORDERARRAY"; - case 0x1200 + 19: return "HDM_SETHOTDIVIDER"; +IMPLEMENT_DYNAMIC_CLASS(wxIdleWakeUpModule, wxModule) - // tab control - case 0x1300 + 2: return "TCM_GETIMAGELIST"; - case 0x1300 + 3: return "TCM_SETIMAGELIST"; - case 0x1300 + 4: return "TCM_GETITEMCOUNT"; - case 0x1300 + 5: return "TCM_GETITEMA"; - case 0x1300 + 60: return "TCM_GETITEMW"; - case 0x1300 + 6: return "TCM_SETITEMA"; - case 0x1300 + 61: return "TCM_SETITEMW"; - case 0x1300 + 7: return "TCM_INSERTITEMA"; - case 0x1300 + 62: return "TCM_INSERTITEMW"; - case 0x1300 + 8: return "TCM_DELETEITEM"; - case 0x1300 + 9: return "TCM_DELETEALLITEMS"; - case 0x1300 + 10: return "TCM_GETITEMRECT"; - case 0x1300 + 11: return "TCM_GETCURSEL"; - case 0x1300 + 12: return "TCM_SETCURSEL"; - case 0x1300 + 13: return "TCM_HITTEST"; - case 0x1300 + 14: return "TCM_SETITEMEXTRA"; - case 0x1300 + 40: return "TCM_ADJUSTRECT"; - case 0x1300 + 41: return "TCM_SETITEMSIZE"; - case 0x1300 + 42: return "TCM_REMOVEIMAGE"; - case 0x1300 + 43: return "TCM_SETPADDING"; - case 0x1300 + 44: return "TCM_GETROWCOUNT"; - case 0x1300 + 45: return "TCM_GETTOOLTIPS"; - case 0x1300 + 46: return "TCM_SETTOOLTIPS"; - case 0x1300 + 47: return "TCM_GETCURFOCUS"; - case 0x1300 + 48: return "TCM_SETCURFOCUS"; - case 0x1300 + 49: return "TCM_SETMINTABWIDTH"; - case 0x1300 + 50: return "TCM_DESELECTALL"; +#endif // __WXWINCE__ - // toolbar - case WM_USER+1: return "TB_ENABLEBUTTON"; - case WM_USER+2: return "TB_CHECKBUTTON"; - case WM_USER+3: return "TB_PRESSBUTTON"; - case WM_USER+4: return "TB_HIDEBUTTON"; - case WM_USER+5: return "TB_INDETERMINATE"; - case WM_USER+9: return "TB_ISBUTTONENABLED"; - case WM_USER+10: return "TB_ISBUTTONCHECKED"; - case WM_USER+11: return "TB_ISBUTTONPRESSED"; - case WM_USER+12: return "TB_ISBUTTONHIDDEN"; - case WM_USER+13: return "TB_ISBUTTONINDETERMINATE"; - case WM_USER+17: return "TB_SETSTATE"; - case WM_USER+18: return "TB_GETSTATE"; - case WM_USER+19: return "TB_ADDBITMAP"; - case WM_USER+20: return "TB_ADDBUTTONS"; - case WM_USER+21: return "TB_INSERTBUTTON"; - case WM_USER+22: return "TB_DELETEBUTTON"; - case WM_USER+23: return "TB_GETBUTTON"; - case WM_USER+24: return "TB_BUTTONCOUNT"; - case WM_USER+25: return "TB_COMMANDTOINDEX"; - case WM_USER+26: return "TB_SAVERESTOREA"; - case WM_USER+76: return "TB_SAVERESTOREW"; - case WM_USER+27: return "TB_CUSTOMIZE"; - case WM_USER+28: return "TB_ADDSTRINGA"; - case WM_USER+77: return "TB_ADDSTRINGW"; - case WM_USER+29: return "TB_GETITEMRECT"; - case WM_USER+30: return "TB_BUTTONSTRUCTSIZE"; - case WM_USER+31: return "TB_SETBUTTONSIZE"; - case WM_USER+32: return "TB_SETBITMAPSIZE"; - case WM_USER+33: return "TB_AUTOSIZE"; - case WM_USER+35: return "TB_GETTOOLTIPS"; - case WM_USER+36: return "TB_SETTOOLTIPS"; - case WM_USER+37: return "TB_SETPARENT"; - case WM_USER+39: return "TB_SETROWS"; - case WM_USER+40: return "TB_GETROWS"; - case WM_USER+42: return "TB_SETCMDID"; - case WM_USER+43: return "TB_CHANGEBITMAP"; - case WM_USER+44: return "TB_GETBITMAP"; - case WM_USER+45: return "TB_GETBUTTONTEXTA"; - case WM_USER+75: return "TB_GETBUTTONTEXTW"; - case WM_USER+46: return "TB_REPLACEBITMAP"; - case WM_USER+47: return "TB_SETINDENT"; - case WM_USER+48: return "TB_SETIMAGELIST"; - case WM_USER+49: return "TB_GETIMAGELIST"; - case WM_USER+50: return "TB_LOADIMAGES"; - case WM_USER+51: return "TB_GETRECT"; - case WM_USER+52: return "TB_SETHOTIMAGELIST"; - case WM_USER+53: return "TB_GETHOTIMAGELIST"; - case WM_USER+54: return "TB_SETDISABLEDIMAGELIST"; - case WM_USER+55: return "TB_GETDISABLEDIMAGELIST"; - case WM_USER+56: return "TB_SETSTYLE"; - case WM_USER+57: return "TB_GETSTYLE"; - case WM_USER+58: return "TB_GETBUTTONSIZE"; - case WM_USER+59: return "TB_SETBUTTONWIDTH"; - case WM_USER+60: return "TB_SETMAXTEXTROWS"; - case WM_USER+61: return "TB_GETTEXTROWS"; - case WM_USER+41: return "TB_GETBITMAPFLAGS"; - -#endif //WIN32 +#ifdef __WXWINCE__ - default: - static char s_szBuf[128]; - sprintf(s_szBuf, "", message); - return s_szBuf; - } +#if wxUSE_STATBOX +static void wxAdjustZOrder(wxWindow* parent) +{ + if (parent->IsKindOf(CLASSINFO(wxStaticBox))) + { + // Set the z-order correctly + SetWindowPos((HWND) parent->GetHWND(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); + } + + wxWindowList::compatibility_iterator current = parent->GetChildren().GetFirst(); + while (current) + { + wxWindow *childWin = current->GetData(); + wxAdjustZOrder(childWin); + current = current->GetNext(); + } } -#endif //__WXDEBUG__ +#endif + +// We need to adjust the z-order of static boxes in WinCE, to +// make 'contained' controls visible +void wxWindowMSW::OnInitDialog( wxInitDialogEvent& event ) +{ +#if wxUSE_STATBOX + wxAdjustZOrder(this); +#endif + + event.Skip(); +} +#endif