X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/d515c32dc3b653c20661dcb2841fc7e6f3e323ee..98840d95db7ab85159dc63d523864b2523d48cae:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 001ff1f48b..bbca2e056f 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -5,8 +5,8 @@ // 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 ///////////////////////////////////////////////////////////////////////////// // =========================================================================== @@ -17,7 +17,7 @@ // headers // --------------------------------------------------------------------------- -#ifdef __GNUG__ +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "window.h" #endif @@ -29,8 +29,7 @@ #endif #ifndef WX_PRECOMP - #include - #include "wx/msw/winundef.h" + #include "wx/msw/wrapwin.h" #include "wx/window.h" #include "wx/accel.h" #include "wx/setup.h" @@ -50,14 +49,28 @@ #include "wx/statbox.h" #endif -#if wxUSE_OWNER_DRAWN +#if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__) #include "wx/ownerdrw.h" #endif +#include "wx/module.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" @@ -80,10 +93,11 @@ #include "wx/textctrl.h" #include "wx/notebook.h" +#include "wx/listctrl.h" #include -#if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__)) || defined(__CYGWIN10__) +#if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)) || defined(__CYGWIN10__) #include #include #endif @@ -92,58 +106,24 @@ #include #endif -#if (!defined(__GNUWIN32_OLD__) && !defined(__TWIN32__) && !defined(__WXMICROWIN__)) || defined(__CYGWIN10__) +#if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)) || defined(__CYGWIN10__) #ifdef __WIN95__ #include #endif -#elif !defined(__WXMICROWIN__) // broken compiler - #ifndef __TWIN32__ - #include "wx/msw/gnuwin32/extra.h" - #endif +#elif !defined(__WXMICROWIN__) && !defined(__WXWINCE__) // broken compiler + #include "wx/msw/gnuwin32/extra.h" #endif -// ---------------------------------------------------------------------------- -// standard constants not available with all compilers/headers -// ---------------------------------------------------------------------------- +#include "wx/msw/missing.h" -// This didn't appear in mingw until 2.95.2 -#ifndef SIF_TRACKPOS -#define SIF_TRACKPOS 16 -#endif - -#if wxUSE_MOUSEWHEEL - #ifndef WM_MOUSEWHEEL - #define WM_MOUSEWHEEL 0x020A - #endif - #ifndef WHEEL_DELTA - #define WHEEL_DELTA 120 - #endif - #ifndef SPI_GETWHEELSCROLLLINES - #define SPI_GETWHEELSCROLLLINES 104 - #endif -#endif // wxUSE_MOUSEWHEEL - -#ifndef VK_OEM_1 - #define VK_OEM_1 0xBA - #define VK_OEM_PLUS 0xBB - #define VK_OEM_COMMA 0xBC - #define VK_OEM_MINUS 0xBD - #define VK_OEM_PERIOD 0xBE - #define VK_OEM_2 0xBF - #define VK_OEM_3 0xC0 - #define VK_OEM_4 0xDB - #define VK_OEM_5 0xDC - #define VK_OEM_6 0xDD - #define VK_OEM_7 0xDE +#if defined(__WXWINCE__) +#include "wx/msw/wince/missing.h" #endif // --------------------------------------------------------------------------- // global variables // --------------------------------------------------------------------------- -// the last Windows message we got (FIXME-MT) -extern MSG s_currentMsg; - #if wxUSE_MENUS_NATIVE wxMenu *wxCurrentPopupMenu = NULL; #endif // wxUSE_MENUS_NATIVE @@ -162,12 +142,13 @@ static bool gs_hasStdCmap = FALSE; LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + #ifdef __WXDEBUG__ const char *wxGetMessageName(int message); #endif //__WXDEBUG__ void wxRemoveHandleAssociation(wxWindowMSW *win); -void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win); +extern void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win); wxWindow *wxFindWinFromHandle(WXHWND hWnd); // this magical function is used to translate VK_APPS key presses to right @@ -190,15 +171,45 @@ static inline void wxBringWindowToTop(HWND hwnd) // activate (set focus to) specified window ::SetFocus(hwnd); +#endif // raise top level parent to top of z order - ::SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); -#else // !__WXMICROWIN__ - if ( !::BringWindowToTop(hwnd) ) + if (!::SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE)) { - wxLogLastError(_T("BringWindowToTop")); + wxLogLastError(_T("SetWindowPos")); } -#endif // __WXMICROWIN__/!__WXMICROWIN__ +} + +// ensure that all our parent windows have WS_EX_CONTROLPARENT style +static void EnsureParentHasControlParentStyle(wxWindow *parent) +{ + /* + 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 neither. + */ +#ifndef __WXWINCE__ + while ( parent && !parent->IsTopLevel() ) + { + LONG exStyle = ::GetWindowLong(GetHwndOf(parent), GWL_EXSTYLE); + if ( !(exStyle & WS_EX_CONTROLPARENT) ) + { + // force the parent to have this style + ::SetWindowLong(GetHwndOf(parent), GWL_EXSTYLE, + exStyle | WS_EX_CONTROLPARENT); + } + + parent = parent->GetParent(); + } +#endif // !__WXWINCE__ } // --------------------------------------------------------------------------- @@ -210,14 +221,119 @@ static inline void wxBringWindowToTop(HWND hwnd) #ifdef __WXUNIVERSAL__ IMPLEMENT_ABSTRACT_CLASS(wxWindowMSW, wxWindowBase) #else // __WXMSW__ +#if wxUSE_EXTENDED_RTTI + +// 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 & ) +{ + const wxWindow * win = dynamic_cast(object) ; + if ( win && win->GetId() < 0 ) + return false ; + return true ; +} + +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) +{ + wxListCollectionToVariantArray( theList , value ) ; +} + +WX_DEFINE_FLAGS( wxWindowStyle ) + +wxBEGIN_FLAGS( wxWindowStyle ) + // new style border flags, we put them first to + // use them for streaming out + + wxFLAGS_MEMBER(wxBORDER_SIMPLE) + wxFLAGS_MEMBER(wxBORDER_SUNKEN) + wxFLAGS_MEMBER(wxBORDER_DOUBLE) + wxFLAGS_MEMBER(wxBORDER_RAISED) + wxFLAGS_MEMBER(wxBORDER_STATIC) + wxFLAGS_MEMBER(wxBORDER_NONE) + + // 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) + + // 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) + +wxEND_FLAGS( wxWindowStyle ) + +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 + + wxREADONLY_PROPERTY( Parent,wxWindow*, GetParent, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( Id,wxWindowID, SetId, GetId, -1, 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) + wxPROPERTY( Position,wxPoint, SetPosition , GetPosition, wxPoint(-1,-1) , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // pos + wxPROPERTY( Size,wxSize, SetSize, GetSize, wxSize(-1,-1) , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // size + wxPROPERTY( WindowStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style + + // Then all relations of the object graph + + wxREADONLY_PROPERTY_COLLECTION( Children , wxWindowList , wxWindowBase* , GetWindowChildren , wxPROP_OBJECT_GRAPH /*flags*/ , wxT("Helpstring") , wxT("group")) + + // and finally all other properties + + wxPROPERTY( ExtraStyle , long , SetExtraStyle , GetExtraStyle , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // extstyle + wxPROPERTY( BackgroundColour , wxColour , SetBackgroundColour , GetBackgroundColour , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // bg + wxPROPERTY( ForegroundColour , wxColour , SetForegroundColour , GetForegroundColour , , 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, wxT("") ) + wxPROPERTY( Font , wxFont , SetFont , GetWindowFont , ) + wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxT("") ) + // MaxHeight, Width , MinHeight , Width + // TODO switch label to control and title to toplevels + + wxPROPERTY( ThemeEnabled , bool , SetThemeEnabled , GetThemeEnabled , ) + //wxPROPERTY( Cursor , wxCursor , SetCursor , GetCursor , ) + // wxPROPERTY( ToolTip , wxString , SetToolTip , GetToolTipText , ) + wxPROPERTY( AutoLayout , bool , SetAutoLayout , GetAutoLayout , ) + + + +#endif +wxEND_PROPERTIES_TABLE() + +wxBEGIN_HANDLERS_TABLE(wxWindow) +wxEND_HANDLERS_TABLE() + +wxCONSTRUCTOR_DUMMY(wxWindow) + +#else IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase) +#endif #endif // __WXUNIVERSAL__/__WXMSW__ BEGIN_EVENT_TABLE(wxWindowMSW, wxWindowBase) EVT_ERASE_BACKGROUND(wxWindowMSW::OnEraseBackground) EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged) EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog) - EVT_IDLE(wxWindowMSW::OnIdle) END_EVENT_TABLE() // =========================================================================== @@ -247,7 +363,7 @@ wxWindow *wxWindowMSW::FindItem(long id) const } #endif // wxUSE_CONTROLS - wxWindowList::Node *current = GetChildren().GetFirst(); + wxWindowList::compatibility_iterator current = GetChildren().GetFirst(); while (current) { wxWindow *childWin = current->GetData(); @@ -265,7 +381,7 @@ wxWindow *wxWindowMSW::FindItem(long id) const // Find an item given the MS Windows handle wxWindow *wxWindowMSW::FindItemByHWND(WXHWND hWnd, bool controlOnly) const { - wxWindowList::Node *current = GetChildren().GetFirst(); + wxWindowList::compatibility_iterator current = GetChildren().GetFirst(); while (current) { wxWindow *parent = current->GetData(); @@ -308,18 +424,14 @@ bool wxWindowMSW::MSWCommand(WXUINT WXUNUSED(param), WXWORD WXUNUSED(id)) void wxWindowMSW::Init() { - // generic - InitBase(); - // MSW specific - m_doubleClickAllowed = 0; - m_isBeingDeleted = FALSE; - m_oldWndProc = 0; - m_useCtl3D = FALSE; + m_oldWndProc = NULL; m_mouseInWindow = FALSE; m_lastKeydownProcessed = FALSE; + m_childrenDisabled = NULL; + // wxWnd m_hMenu = 0; @@ -327,7 +439,6 @@ void wxWindowMSW::Init() m_xThumbSize = 0; m_yThumbSize = 0; - m_backgroundTransparent = FALSE; // as all windows are created with WS_VISIBLE style... m_isShown = TRUE; @@ -348,12 +459,12 @@ wxWindowMSW::~wxWindowMSW() // VS: make sure there's no wxFrame with last focus set to us: for ( wxWindow *win = GetParent(); win; win = win->GetParent() ) { - wxFrame *frame = wxDynamicCast(win, wxFrame); + wxTopLevelWindow *frame = wxDynamicCast(win, wxTopLevelWindow); if ( frame ) { if ( frame->GetLastFocus() == this ) { - frame->SetLastFocus((wxWindow*)NULL); + frame->SetLastFocus(NULL); } break; } @@ -365,9 +476,6 @@ wxWindowMSW::~wxWindowMSW() // find their parent frame (see above). DestroyChildren(); - if ( m_parent ) - m_parent->RemoveChild(this); - if ( m_hWnd ) { // VZ: test temp removed to understand what really happens here @@ -380,6 +488,8 @@ wxWindowMSW::~wxWindowMSW() // remove hWnd <-> wxWindow association wxRemoveHandleAssociation(this); } + + delete m_childrenDisabled; } // real construction (Init() must have been called before!) @@ -392,17 +502,6 @@ bool wxWindowMSW::Create(wxWindow *parent, { wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") ); -#if wxUSE_STATBOX - // wxGTK doesn't allow to create controls with static box as the parent so - // this will result in a crash when the program is ported to wxGTK - warn - // about it - // - // the correct solution is to create the controls as siblings of the - // static box - wxASSERT_MSG( !wxDynamicCast(parent, wxStaticBox), - _T("wxStaticBox can't be used as a window parent!") ); -#endif // wxUSE_STATBOX - if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) return FALSE; @@ -444,7 +543,7 @@ void wxWindowMSW::SetFocus() HWND hWnd = GetHwnd(); wxCHECK_RET( hWnd, _T("can't set focus to invalid window") ); -#ifndef __WXMICROWIN__ +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) ::SetLastError(0); #endif @@ -467,8 +566,6 @@ void wxWindowMSW::SetFocus() void wxWindowMSW::SetFocusFromKbd() { - wxWindowBase::SetFocusFromKbd(); - // 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 @@ -477,6 +574,11 @@ void wxWindowMSW::SetFocusFromKbd() { ::SendMessage(GetHwnd(), EM_SETSEL, 0, -1); } + + // 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(); } // Get the window with the focus @@ -500,19 +602,58 @@ bool wxWindowMSW::Enable(bool enable) if ( hWnd ) ::EnableWindow(hWnd, (BOOL)enable); - // VZ: no, this is a bad idea: imagine that you have a dialog with some - // disabled controls and disable it - you really wouldn't like the - // disabled controls be reenabled too when you reenable the dialog! -#if 0 - wxWindowList::Node *node = GetChildren().GetFirst(); - while ( node ) + // 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(); - child->Enable(enable); + if ( child->IsTopLevel() ) + { + // the logic below doesn't apply to top level children + continue; + } - node = node->GetNext(); + if ( enable ) + { + // enable the child back unless it had been disabled before us + if ( !m_childrenDisabled || !m_childrenDisabled->Find(child) ) + child->Enable(); + } + else // we're being disabled + { + if ( child->IsEnabled() ) + { + // disable it as children shouldn't stay enabled while the + // parent is not + child->Disable(); + } + else // child already disabled, remember it + { + // have we created the list of disabled children already? + if ( !m_childrenDisabled ) + m_childrenDisabled = new wxWindowList; + + m_childrenDisabled->Append(child); + } + } + } + + if ( enable && m_childrenDisabled ) + { + // we don't need this list any more, don't keep unused memory + delete m_childrenDisabled; + m_childrenDisabled = NULL; } -#endif // 0 return TRUE; } @@ -526,7 +667,7 @@ bool wxWindowMSW::Show(bool show) int cshow = show ? SW_SHOW : SW_HIDE; ::ShowWindow(hWnd, cshow); - if ( show ) + if ( show && IsTopLevel() ) { wxBringWindowToTop(hWnd); } @@ -635,201 +776,75 @@ void wxWindowMSW::WarpPointer (int x, int y) } } -#if WXWIN_COMPATIBILITY -void wxWindowMSW::MSWDeviceToLogical (float *x, float *y) const -{ -} -#endif // WXWIN_COMPATIBILITY - // --------------------------------------------------------------------------- // scrolling stuff // --------------------------------------------------------------------------- -#if WXWIN_COMPATIBILITY -void wxWindowMSW::SetScrollRange(int orient, int range, bool refresh) -{ -#if defined(__WIN95__) - - int range1 = range; - - // Try to adjust the range to cope with page size > 1 - // - a Windows API quirk - int pageSize = GetScrollPage(orient); - if ( pageSize > 1 && range > 0) - { - range1 += (pageSize - 1); - } - - SCROLLINFO info; - int dir; - - if ( orient == wxHORIZONTAL ) { - dir = SB_HORZ; - } else { - dir = SB_VERT; - } - - 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; - - HWND hWnd = GetHwnd(); - if ( hWnd ) - ::SetScrollInfo(hWnd, dir, &info, refresh); -#else - int wOrient; - if ( orient == wxHORIZONTAL ) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; - - HWND hWnd = GetHwnd(); - if ( hWnd ) - ::SetScrollRange(hWnd, wOrient, 0, range, refresh); -#endif -} - -void wxWindowMSW::SetScrollPage(int orient, int page, bool refresh) +// convert wxHORIZONTAL/wxVERTICAL to SB_HORZ/SB_VERT +static inline int wxDirToWinStyle(int orient) { -#if defined(__WIN95__) - SCROLLINFO info; - int dir; - - if ( orient == wxHORIZONTAL ) { - dir = SB_HORZ; - m_xThumbSize = page; - } else { - dir = SB_VERT; - m_yThumbSize = page; - } - - info.cbSize = sizeof(SCROLLINFO); - info.nPage = page; - info.nMin = 0; - info.fMask = SIF_PAGE; - - HWND hWnd = GetHwnd(); - if ( hWnd ) - ::SetScrollInfo(hWnd, dir, &info, refresh); -#else - if ( orient == wxHORIZONTAL ) - m_xThumbSize = page; - else - m_yThumbSize = page; -#endif + return orient == wxHORIZONTAL ? SB_HORZ : SB_VERT; } -int wxWindowMSW::OldGetScrollRange(int orient) const -{ - int wOrient; - if ( orient == wxHORIZONTAL ) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; - -#if __WATCOMC__ && defined(__WINDOWS_386__) - short minPos, maxPos; -#else - int minPos, maxPos; -#endif - 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 ) - { - maxPos -= (pageSize - 1); - } -#endif - return maxPos; - } - else - return 0; -} - -int wxWindowMSW::GetScrollPage(int orient) const -{ - if ( orient == wxHORIZONTAL ) - return m_xThumbSize; - else - return m_yThumbSize; -} - -#endif // WXWIN_COMPATIBILITY - inline int GetScrollPosition(HWND hWnd, int wOrient) { #ifdef __WXMICROWIN__ return ::GetScrollPosWX(hWnd, wOrient); #else - return ::GetScrollPos(hWnd, wOrient); + WinStruct scrollInfo; + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_POS; + if ( !::GetScrollInfo(hWnd, + wOrient, + &scrollInfo) ) + { + // Not neccessarily an error, if there are no scrollbars yet. + // wxLogLastError(_T("GetScrollInfo")); + } + return scrollInfo.nPos; +// return ::GetScrollPos(hWnd, wOrient); #endif } int wxWindowMSW::GetScrollPos(int orient) const { - int wOrient; - if ( orient == wxHORIZONTAL ) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; - HWND hWnd = GetHwnd(); wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") ); - return GetScrollPosition(hWnd, wOrient); + return GetScrollPosition(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT); } // This now returns the whole range, not just the number // of positions that we can scroll. int wxWindowMSW::GetScrollRange(int orient) const { - int wOrient; - if ( orient == wxHORIZONTAL ) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; - -#if __WATCOMC__ && defined(__WINDOWS_386__) - short minPos, maxPos; -#else - int minPos, maxPos; -#endif + int maxPos; 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 ) - { - maxPos -= (pageSize - 1); - } - // October 10th: new range concept. - maxPos += pageSize; + if ( !hWnd ) + return 0; +#if 0 + ::GetScrollRange(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT, + &minPos, &maxPos); #endif - - return maxPos; + WinStruct scrollInfo; + scrollInfo.fMask = SIF_RANGE; + if ( !::GetScrollInfo(hWnd, + orient == wxHORIZONTAL ? SB_HORZ : SB_VERT, + &scrollInfo) ) + { + // 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")); } - else - return 0; + maxPos = scrollInfo.nMax; + + // undo "range - 1" done in SetScrollbar() + return maxPos + 1; } int wxWindowMSW::GetScrollThumb(int orient) const { - if ( orient == wxHORIZONTAL ) - return m_xThumbSize; - else - return m_yThumbSize; + return orient == wxHORIZONTAL ? m_xThumbSize : m_yThumbSize; } void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh) @@ -837,77 +852,48 @@ void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh) HWND hWnd = GetHwnd(); wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") ); - int dir = orient == wxHORIZONTAL ? SB_HORZ : SB_VERT; - -#if defined(__WIN95__) - SCROLLINFO info; - info.cbSize = sizeof(SCROLLINFO); + WinStruct info; info.nPage = 0; info.nMin = 0; info.nPos = pos; info.fMask = SIF_POS; - - ::SetScrollInfo(hWnd, dir, &info, refresh); -#else // !__WIN95__ - ::SetScrollPos(hWnd, dir, pos, refresh); -#endif // __WIN95__/!__WIN95__ -} - -// New function that will replace some of the above. -void wxWindowMSW::SetScrollbar(int orient, int pos, int thumbVisible, - int range, bool refresh) -{ -#if defined(__WIN95__) - int oldRange = range - thumbVisible; - - 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) + if ( HasFlag(wxALWAYS_SHOW_SB) ) { - range1 += (pageSize - 1); + // disable scrollbar instead of removing it then + info.fMask |= SIF_DISABLENOSCROLL; } - SCROLLINFO info; - int dir; - - if ( orient == wxHORIZONTAL ) { - dir = SB_HORZ; - } else { - dir = SB_VERT; - } + ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT, + &info, refresh); +} - info.cbSize = sizeof(SCROLLINFO); - info.nPage = pageSize; // Have to set this, or scrollbar goes awry - info.nMin = 0; - info.nMax = range1; +// 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; - - HWND hWnd = GetHwnd(); - if ( hWnd ) - ::SetScrollInfo(hWnd, dir, &info, refresh); -#else - int wOrient; - if ( orient == wxHORIZONTAL ) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; + if ( HasFlag(wxALWAYS_SHOW_SB) ) + { + // disable scrollbar instead of removing it then + info.fMask |= SIF_DISABLENOSCROLL; + } HWND hWnd = GetHwnd(); if ( hWnd ) { - ::SetScrollRange(hWnd, wOrient, 0, range, FALSE); - ::SetScrollPos(hWnd, wOrient, pos, refresh); - } -#endif - if ( orient == wxHORIZONTAL ) { - m_xThumbSize = thumbVisible; - } else { - m_yThumbSize = thumbVisible; + ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT, + &info, refresh); } + + *(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize; } void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect) @@ -927,7 +913,12 @@ void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect) pr = NULL; } +#ifdef __WXWINCE__ + // FIXME: is this the exact equivalent of the line below? + ::ScrollWindowEx(GetHwnd(), dx, dy, pr, pr, 0, 0, SW_ERASE|SW_INVALIDATE); +#else ::ScrollWindow(GetHwnd(), dx, dy, pr, pr); +#endif } static bool ScrollVertically(HWND hwnd, int kind, int count) @@ -987,13 +978,16 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd) // we don't need to subclass the window of our own class (in the Windows // sense of the word) - if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) ) + if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) ) { ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) wxWndProc); } else { - // don't bother restoring it neither + // don't bother restoring it neither: this also makes it easy to + // implement IsOfStandardClass() method which returns TRUE for the + // standard controls and FALSE for the wxWindows own windows as it can + // simply check m_oldWndProc m_oldWndProc = NULL; } } @@ -1024,35 +1018,44 @@ void wxWindowMSW::UnsubclassWin() bool wxCheckWindowWndProc(WXHWND hWnd, WXFARPROC wndProc) { -#if wxUSE_UNICODE_MSLU - // VS: We can't use GetWindowLong(hwnd, GWL_WNDPROC) together with unicows.dll - // because it doesn't return pointer to the real wnd proc but rather a handle - // of a fake proc that does Unicode<->ANSI translation. - // - // The hack bellow works, because WNDCLASS contains original window handler - // rather that the unicows fake one. This may not be on purpose, though; if - // it stops working with future versions of unicows.dll, we can override - // unicows hooks by setting Unicows_{Set,Get}WindowLong and - // Unicows_RegisterClass to our own versions that keep track of - // fake<->real wnd proc mapping. - // - // FIXME: Doesn't handle wnd procs set by SetWindowLong, only these set - // with RegisterClass!! - - if ( wxUsingUnicowsDll() ) + // Unicows note: the code below works, but only because WNDCLASS contains + // original window handler rather that the unicows fake one. This may not + // be on purpose, though; if it stops working with future versions of + // unicows.dll, we can override unicows hooks by setting + // Unicows_{Set,Get}WindowLong and Unicows_RegisterClass to our own + // versions that keep track of fake<->real wnd proc mapping. + + // On WinCE (at least), the wndproc comparison doesn't work, + // so have to use something like this. +#ifdef __WXWINCE__ + extern const wxChar *wxCanvasClassName; + extern const wxChar *wxCanvasClassNameNR; + 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 || + str == wxMDIFrameClassName || + str == wxMDIFrameClassNameNoRedraw || + str == wxMDIChildFrameClassName || + str == wxMDIChildFrameClassNameNoRedraw || + str == _T("wxTLWHiddenParent")) + return TRUE; // Effectively means don't subclass + else + return FALSE; +#else + WNDCLASS cls; + if ( !::GetClassInfo(wxGetInstance(), wxGetWindowClass(hWnd), &cls) ) { - static wxChar buffer[512]; - WNDCLASS cls; + wxLogLastError(_T("GetClassInfo")); - ::GetClassName((HWND)hWnd, buffer, 512); - ::GetClassInfo(wxGetInstance(), buffer, &cls); - return wndProc == (WXFARPROC)cls.lpfnWndProc; + return FALSE; } - else + + return wndProc == (WXFARPROC)cls.lpfnWndProc; #endif - { - return wndProc == (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC); - } } // ---------------------------------------------------------------------------- @@ -1116,7 +1119,7 @@ void wxWindowMSW::SetWindowStyleFlag(long flags) WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const { // translate the style - WXDWORD style = WS_CHILD; + WXDWORD style = WS_CHILD | WS_VISIBLE; if ( flags & wxCLIP_CHILDREN ) style |= WS_CLIPCHILDREN; @@ -1124,8 +1127,16 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const if ( flags & wxCLIP_SIBLINGS ) style |= WS_CLIPSIBLINGS; - wxBorder border = (wxBorder)(flags & wxBORDER_MASK); - if ( border != wxBORDER_NONE && border != wxBORDER_DEFAULT ) + 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 @@ -1133,18 +1144,20 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const { *exstyle = 0; +#ifndef __WXWINCE__ if ( flags & wxTRANSPARENT_WINDOW ) *exstyle |= WS_EX_TRANSPARENT; +#endif - switch ( flags & wxBORDER_MASK ) + switch ( border ) { default: + case wxBORDER_DEFAULT: wxFAIL_MSG( _T("unknown border style") ); // fall through case wxBORDER_NONE: case wxBORDER_SIMPLE: - case wxBORDER_DEFAULT: break; case wxBORDER_STATIC: @@ -1152,11 +1165,12 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const break; case wxBORDER_RAISED: - *exstyle |= WS_EX_WINDOWEDGE; + *exstyle |= WS_EX_DLGMODALFRAME; break; case wxBORDER_SUNKEN: *exstyle |= WS_EX_CLIENTEDGE; + style &= ~WS_BORDER; break; case wxBORDER_DOUBLE: @@ -1164,134 +1178,20 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const break; } - if ( flags & wxTAB_TRAVERSAL ) + // 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() ) { *exstyle |= WS_EX_CONTROLPARENT; } +#endif // __WXUNIVERSAL__ } return style; } -// Make a Windows extended style from the given wxWindows window style -WXDWORD wxWindowMSW::MakeExtendedStyle(long style, bool eliminateBorders) -{ - WXDWORD exStyle = 0; - if ( style & wxTRANSPARENT_WINDOW ) - exStyle |= WS_EX_TRANSPARENT; - - 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 ) - // It seems that WS_EX_WINDOWEDGE doesn't work, but WS_EX_DLGMODALFRAME does - exStyle |= WS_EX_DLGMODALFRAME; /* WS_EX_WINDOWEDGE */; - if ( style & wxSTATIC_BORDER ) - exStyle |= WS_EX_STATICEDGE; -#endif - } - - return exStyle; -} - -// 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 wxWindowMSW::Determine3DEffects(WXDWORD defaultBorderStyle, - bool *want3D) const -{ - // If matches certain criteria, then assume no 3D effects - // unless specifically requested (dealt with in MakeExtendedStyle) - if ( !GetParent() -#if wxUSE_CONTROLS - || !IsKindOf(CLASSINFO(wxControl)) -#endif // wxUSE_CONTROLS - || (m_windowStyle & wxNO_BORDER) ) - { - *want3D = FALSE; - return MakeExtendedStyle(m_windowStyle); - } - - // Determine whether we should be using 3D effects or not. - bool nativeBorder = FALSE; // by default, we don't want a Win95 effect - - // 1) App can specify global 3D effects - *want3D = wxTheApp->GetAuto3D(); - - // 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; - - // 3) Control can override this global setting by defining - // a border style, e.g. wxSUNKEN_BORDER - if ( m_windowStyle & wxSUNKEN_BORDER ) - *want3D = TRUE; - - // 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; - } - - // 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 - - DWORD exStyle = MakeExtendedStyle(m_windowStyle, !nativeBorder); - - // 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 - - return exStyle; -} - -#if WXWIN_COMPATIBILITY -// If nothing defined for this, try the parent. -// E.g. we may be a button loaded from a resource, with no callback function -// defined. -void wxWindowMSW::OnCommand(wxWindow& win, wxCommandEvent& event) -{ - if ( GetEventHandler()->ProcessEvent(event) ) - return; - if ( m_parent ) - m_parent->GetEventHandler()->OnCommand(win, event); -} -#endif // WXWIN_COMPATIBILITY_2 - -#if WXWIN_COMPATIBILITY -wxObject* wxWindowMSW::GetChild(int number) const -{ - // Return a pointer to the Nth object in the Panel - wxNode *node = GetChildren().First(); - int n = number; - while (node && n--) - node = node->Next(); - if ( node ) - { - wxObject *obj = (wxObject *)node->Data(); - return(obj); - } - else - return NULL; -} -#endif // WXWIN_COMPATIBILITY - // Setup background and foreground colours correctly void wxWindowMSW::SetupColours() { @@ -1314,7 +1214,7 @@ bool wxWindowMSW::IsMouseInWindow() const return hwnd != NULL; } -void wxWindowMSW::OnIdle(wxIdleEvent& WXUNUSED(event)) +void wxWindowMSW::OnInternalIdle() { // Check if we need to send a LEAVE event if ( m_mouseInWindow ) @@ -1327,7 +1227,7 @@ void wxWindowMSW::OnIdle(wxIdleEvent& WXUNUSED(event)) m_mouseInWindow = FALSE; // Unfortunately the mouse button and keyboard state may have - // changed by the time the OnIdle function is called, so 'state' + // changed by the time the OnInternalIdle function is called, so 'state' // may be meaningless. int state = 0; if ( wxIsShiftDown() ) @@ -1360,7 +1260,8 @@ void wxWindowMSW::OnIdle(wxIdleEvent& WXUNUSED(event)) } } - UpdateWindowUI(); + if (wxUpdateUIEvent::CanUpdate(this)) + UpdateWindowUI(wxUPDATE_UI_FROMIDLE); } // Set this window to be the child of 'parent'. @@ -1374,15 +1275,14 @@ bool wxWindowMSW::Reparent(wxWindowBase *parent) ::SetParent(hWndChild, hWndParent); - return TRUE; -} +#ifndef __WXWINCE__ + if ( ::GetWindowLong(hWndChild, GWL_EXSTYLE) & WS_EX_CONTROLPARENT ) + { + EnsureParentHasControlParentStyle(GetParent()); + } +#endif // !__WXWINCE__ -void wxWindowMSW::Clear() -{ - wxClientDC dc((wxWindow *)this); - wxBrush brush(GetBackgroundColour(), wxSOLID); - dc.SetBackground(brush); - dc.Clear(); + return TRUE; } static inline void SendSetRedraw(HWND hwnd, bool on) @@ -1433,7 +1333,7 @@ void wxWindowMSW::Update() wxLogLastError(_T("UpdateWindow")); } -#if defined(__WIN32__) && !defined(__WXMICROWIN__) +#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(); @@ -1444,8 +1344,8 @@ void wxWindowMSW::Update() // drag and drop // --------------------------------------------------------------------------- -#if wxUSE_DRAG_AND_DROP +#if wxUSE_DRAG_AND_DROP void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget) { if ( m_dropTarget != 0 ) { @@ -1457,16 +1357,17 @@ void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget) if ( m_dropTarget != 0 ) 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 accept) { +#if !defined(__WXWINCE__) HWND hWnd = GetHwnd(); if ( hWnd ) ::DragAcceptFiles(hWnd, (BOOL)accept); +#endif } // ---------------------------------------------------------------------------- @@ -1480,7 +1381,7 @@ void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip) wxWindowBase::DoSetToolTip(tooltip); if ( m_tooltip ) - m_tooltip->SetWindow(this); + m_tooltip->SetWindow((wxWindow *)this); } #endif // wxUSE_TOOLTIPS @@ -1789,48 +1690,6 @@ void wxWindowMSW::GetTextExtent(const wxString& string, *externalLeading = tm.tmExternalLeading; } -#if wxUSE_CARET && WXWIN_COMPATIBILITY -// --------------------------------------------------------------------------- -// Caret manipulation -// --------------------------------------------------------------------------- - -void wxWindowMSW::CreateCaret(int w, int h) -{ - SetCaret(new wxCaret(this, w, h)); -} - -void wxWindowMSW::CreateCaret(const wxBitmap *WXUNUSED(bitmap)) -{ - wxFAIL_MSG("not implemented"); -} - -void wxWindowMSW::ShowCaret(bool show) -{ - wxCHECK_RET( m_caret, "no caret to show" ); - - m_caret->Show(show); -} - -void wxWindowMSW::DestroyCaret() -{ - SetCaret(NULL); -} - -void wxWindowMSW::SetCaretPos(int x, int y) -{ - wxCHECK_RET( m_caret, "no caret to move" ); - - m_caret->Move(x, y); -} - -void wxWindowMSW::GetCaretPos(int *x, int *y) const -{ - wxCHECK_RET( m_caret, "no caret to get position of" ); - - m_caret->GetPosition(x, y); -} -#endif // wxUSE_CARET - // --------------------------------------------------------------------------- // popup menu // --------------------------------------------------------------------------- @@ -1847,10 +1706,20 @@ 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) - && msg.message != WM_QUIT ) + while ( ::PeekMessage(&msg, (HWND)0, WM_COMMAND, WM_COMMAND, PM_REMOVE) ) { - wxTheApp->DoMessage((WXMSG *)&msg); + if ( msg.message == WM_QUIT ) + { + // if we retrieved a WM_QUIT, insert back into the message queue. + ::PostQuitMessage(0); + break; + } + + // 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); } } @@ -1866,7 +1735,11 @@ bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y) point.y = y; ::ClientToScreen(hWnd, &point); wxCurrentPopupMenu = menu; - ::TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL); + UINT flags = 0; +#if !defined(__WXWINCE__) + flags = TPM_RIGHTBUTTON; +#endif + ::TrackPopupMenu(hMenu, flags, point.x, point.y, 0, hWnd, NULL); // we need to do it righ now as otherwise the events are never going to be // sent to wxCurrentPopupMenu from HandleCommand() @@ -1910,14 +1783,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) // here we try to do all the job which ::IsDialogMessage() usually does // internally #if 1 - bool bProcess = TRUE; - if ( msg->message != WM_KEYDOWN ) - bProcess = FALSE; - - if ( bProcess && (HIWORD(msg->lParam) & KF_ALTDOWN) == KF_ALTDOWN ) - bProcess = FALSE; - - if ( bProcess ) + if ( msg->message == WM_KEYDOWN ) { bool bCtrlDown = wxIsCtrlDown(); bool bShiftDown = wxIsShiftDown(); @@ -1929,11 +1795,21 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) if ( !bCtrlDown ) { 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; + // should we process this message specially? + bool bProcess = TRUE; switch ( msg->wParam ) { case VK_TAB: @@ -2016,6 +1892,12 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) // eat the Enter events sometimes return FALSE; } + else if (!IsTopLevel()) + { + // if not a top level window, let parent + // handle it + return FALSE; + } //else: treat Enter as TAB: pass to the next // control as this is the best thing to do // if the text doesn't handle Enter itself @@ -2078,7 +1960,80 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) // place edit control from being closed with Escape in a dialog if ( msg->message != WM_KEYDOWN || msg->wParam != VK_ESCAPE ) { - if ( ::IsDialogMessage(GetHwnd(), msg) ) + // ::IsDialogMessage() is broken and may sometimes hang the + // application by going into an infinite loop, so we try to detect + // [some of] the situatations when this may happen and not call it + // then + + // 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 ) + { + // passimistic by default + canSafelyCallIsDlgMsg = FALSE; + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + 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__ + + 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 ) + { + if ( !::IsWindowEnabled(hwndFocus) || + !::IsWindowVisible(hwndFocus) ) + { + // it would enter an infinite loop if we do this! + canSafelyCallIsDlgMsg = FALSE; + + break; + } + + 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); + } + } + + // let IsDialogMessage() have the message if it's safe to call it + if ( canSafelyCallIsDlgMsg && ::IsDialogMessage(GetHwnd(), msg) ) { // IsDialogMessage() did something... return TRUE; @@ -2117,11 +2072,9 @@ bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* WXUNUSED(pMsg)) } // --------------------------------------------------------------------------- -// message params unpackers (different for Win16 and Win32) +// message params unpackers // --------------------------------------------------------------------------- -#ifdef __WIN32__ - void wxWindowMSW::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam, WORD *id, WXHWND *hwnd, WORD *cmd) { @@ -2164,50 +2117,6 @@ void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, *hmenu = (WXHMENU)lParam; } -#else // Win16 - -void wxWindowMSW::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam, - WXWORD *id, WXHWND *hwnd, WXWORD *cmd) -{ - *id = (WXWORD)wParam; - *hwnd = (WXHWND)LOWORD(lParam); - *cmd = HIWORD(lParam); -} - -void wxWindowMSW::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam, - WXWORD *state, WXWORD *minimized, WXHWND *hwnd) -{ - *state = (WXWORD)wParam; - *minimized = LOWORD(lParam); - *hwnd = (WXHWND)HIWORD(lParam); -} - -void wxWindowMSW::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam, - WXWORD *code, WXWORD *pos, WXHWND *hwnd) -{ - *code = (WXWORD)wParam; - *pos = LOWORD(lParam); - *hwnd = (WXHWND)HIWORD(lParam); -} - -void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam, - WXWORD *nCtlColor, WXHDC *hdc, WXHWND *hwnd) -{ - *hwnd = (WXHWND)LOWORD(lParam); - *nCtlColor = (int)HIWORD(lParam); - *hdc = (WXHDC)wParam; -} - -void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, - WXWORD *item, WXWORD *flags, WXHMENU *hmenu) -{ - *item = (WXWORD)wParam; - *flags = LOWORD(lParam); - *hmenu = (WXHMENU)HIWORD(lParam); -} - -#endif // Win32/16 - // --------------------------------------------------------------------------- // Main wxWindows window proc and the window proc for wxWindow // --------------------------------------------------------------------------- @@ -2233,8 +2142,9 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM w { // trace all messages - useful for the debugging #ifdef __WXDEBUG__ - wxLogTrace(wxTraceMessages, wxT("Processing %s(wParam=%8lx, lParam=%8lx)"), - wxGetMessageName(message), wParam, lParam); + 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); @@ -2302,6 +2212,26 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam processed = HandleMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break; +#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; +#endif + case WM_SIZE: switch ( wParam ) { @@ -2330,7 +2260,27 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam } break; -#ifndef __WXMICROWIN__ +#if !defined(__WXWINCE__) + 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; +#endif + +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) case WM_ACTIVATEAPP: wxTheApp->SetActive(wParam != 0, FindFocus()); break; @@ -2355,8 +2305,35 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam break; case WM_PAINT: - processed = HandlePaint(); + { + if ( wParam ) + { + // cast to wxWindow is needed for wxUniv + wxPaintDCEx dc((wxWindow *)this, (WXHDC)wParam); + processed = HandlePaint(); + } + else + { + processed = HandlePaint(); + } + break; + } + +#ifndef __WXWINCE__ + case WM_PRINT: + { + // Don't call the wx handlers in this case + if ( wxIsKindOf(this, wxListCtrl) ) + break; + + if ( lParam & PRF_ERASEBKGND ) + HandleEraseBkgnd((WXHDC)(HDC)wParam); + + wxPaintDCEx dc((wxWindow *)this, (WXHDC)wParam); + processed = HandlePaint(); + } break; +#endif case WM_CLOSE: #ifdef __WXUNIVERSAL__ @@ -2383,6 +2360,62 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam wParam); break; + // Seems to be broken currently +#if 0 // ndef __WXWINCE__ + case WM_MOUSELEAVE: + { + wxASSERT_MSG( !m_mouseInWindow, wxT("the mouse should be in a window to generate this event!") ); + + // only process this message if the mouse is not in the window, + // This can also check for children in composite windows. + // however, this may mean the the wxEVT_LEAVE_WINDOW is never sent + // if the mouse does not enter the window from it's child before + // leaving the scope of the window. ( perhaps this can be picked + // up in the OnIdle code as before, for this special case ) + if ( /*IsComposite() && */ !IsMouseInWindow() ) + { + m_mouseInWindow = FALSE; + + // Unfortunately no mouse state is passed with a WM_MOUSE_LEAVE + int state = 0; + if ( wxIsShiftDown() ) + state |= MK_SHIFT; + if ( wxIsCtrlDown() ) + state |= MK_CONTROL; + if ( GetKeyState( VK_LBUTTON ) ) + state |= MK_LBUTTON; + if ( GetKeyState( VK_MBUTTON ) ) + state |= MK_MBUTTON; + if ( GetKeyState( VK_RBUTTON ) ) + state |= MK_RBUTTON; + + POINT pt; + if ( !::GetCursorPos(&pt) ) + { + wxLogLastError(_T("GetCursorPos")); + } + + // 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; + + wxMouseEvent event2(wxEVT_LEAVE_WINDOW); + InitMouseEvent(event2, pt.x, pt.y, state); + + (void)GetEventHandler()->ProcessEvent(event2); + } + // 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. + processed = false; + } + break; +#endif + // __WXWINCE__ + #if wxUSE_MOUSEWHEEL case WM_MOUSEWHEEL: processed = HandleMouseWheel(wParam, lParam); @@ -2417,28 +2450,42 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam break; } - if (!processed) + if ( processed ) + break; + #endif // __WXMICROWIN__ + int x = GET_X_LPARAM(lParam), + y = GET_Y_LPARAM(lParam); + + // redirect the event to a static control if necessary by + // finding one under mouse + wxWindowMSW *win; + if ( GetCapture() == this ) { - // VZ: why do we need it here? DefWindowProc() is supposed - // to do this for us anyhow - if ( message == WM_LBUTTONDOWN && AcceptsFocus() ) - SetFocus(); + // 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 + { + win = FindWindowForMouseEvent(this, &x, &y); - int x = GET_X_LPARAM(lParam), - y = GET_Y_LPARAM(lParam); + // this should never happen + wxCHECK_MSG( win, 0, + _T("FindWindowForMouseEvent() returned NULL") ); - // redirect the event to a static control if necessary - if (this == GetCapture()) - { - processed = HandleMouseEvent(message, x, y, wParam); - } - else + // for the standard classes their WndProc sets the focus to + // them anyhow and doing it from here results in some weird + // problems, but for our windows we want them to acquire + // focus when clicked + if ( !win->IsOfStandardClass() ) { - wxWindowMSW *win = FindWindowForMouseEvent(this, &x, &y); //TW:REQ:Univ - processed = win->HandleMouseEvent(message, x, y, wParam); + if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() ) + win->SetFocus(); } } + + processed = win->HandleMouseEvent(message, x, y, wParam); } break; @@ -2472,11 +2519,9 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam } break; -#ifdef __WIN95__ case WM_NOTIFY: processed = HandleNotify((int)wParam, lParam, &rc.result); break; -#endif // Win95 // for these messages we must return TRUE if process the message #ifdef WM_DRAWITEM @@ -2502,11 +2547,19 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam #endif // defined(WM_DRAWITEM) case WM_GETDLGCODE: - if ( GetWindowStyleFlag() & wxWANTS_CHARS ) + if ( !IsOfStandardClass() ) { - // want everything: i.e. all keys and WM_CHAR message - rc.result = DLGC_WANTARROWS | DLGC_WANTCHARS | - DLGC_WANTTAB | DLGC_WANTMESSAGE; + // 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; + } + processed = TRUE; } //else: get the dlg code from the DefWindowProc() @@ -2520,71 +2573,73 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam if ( m_lastKeydownProcessed ) { processed = TRUE; - break; } - switch ( wParam ) + if ( !processed ) { - // we consider these message "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_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; + switch ( wParam ) + { + // we consider these message "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; - 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_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: - { - WPARAM flags; - int x, y; + // special case of VK_APPS: treat it the same as right mouse + // click because both usually pop up a context menu + case VK_APPS: + { + WPARAM flags; + int x, y; - TranslateKbdEventToMouse(this, &x, &y, &flags); - processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags); - } - break; + TranslateKbdEventToMouse(this, &x, &y, &flags); + processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags); + } + break; #endif // VK_APPS - default: - // do generate a CHAR event - processed = HandleChar((WORD)wParam, lParam); - + 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: @@ -2622,6 +2677,12 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam } break; +#if wxUSE_HOTKEY + case WM_HOTKEY: + processed = HandleHotKey((WORD)wParam, lParam); + break; +#endif // wxUSE_HOTKEY + case WM_HSCROLL: case WM_VSCROLL: { @@ -2638,7 +2699,6 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam // CTLCOLOR messages are sent by children to query the parent for their // colors#ifndef __WXMICROWIN__ #ifndef __WXMICROWIN__ -#ifdef __WIN32__ case WM_CTLCOLORMSGBOX: case WM_CTLCOLOREDIT: case WM_CTLCOLORLISTBOX: @@ -2646,9 +2706,6 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam case WM_CTLCOLORDLG: case WM_CTLCOLORSCROLLBAR: case WM_CTLCOLORSTATIC: -#else // Win16 - case WM_CTLCOLOR: -#endif // Win32/16 { WXWORD nCtlColor; WXHDC hdc; @@ -2671,9 +2728,11 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam processed = HandleSysColorChange(); break; +#if !defined(__WXWINCE__) case WM_DISPLAYCHANGE: processed = HandleDisplayChange(); break; +#endif case WM_PALETTECHANGED: processed = HandlePaletteChanged((WXHWND) (HWND) wParam); @@ -2696,9 +2755,11 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam } break; +#if !defined(__WXWINCE__) case WM_DROPFILES: processed = HandleDropFiles(wParam); break; +#endif case WM_INITDIALOG: processed = HandleInitDialog((WXHWND)(HWND)wParam); @@ -2710,6 +2771,7 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam } break; +#if !defined(__WXWINCE__) case WM_QUERYENDSESSION: processed = HandleQueryEndSession(lParam, &rc.allow); break; @@ -2721,6 +2783,7 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam case WM_GETMINMAXINFO: processed = HandleGetMinMaxInfo((MINMAXINFO*)lParam); break; +#endif case WM_SETCURSOR: processed = HandleSetCursor((WXHWND)(HWND)wParam, @@ -2736,21 +2799,43 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam } break; -#if defined(__WIN32__) && defined(WM_HELP) +#if wxUSE_ACCESSIBILITY + case WM_GETOBJECT: + { + //WPARAM dwFlags = (WPARAM) (DWORD) wParam; + LPARAM dwObjId = (LPARAM) (DWORD) lParam; + + if (dwObjId == (LPARAM)OBJID_CLIENT && GetOrCreateAccessible()) + { + return LresultFromObject(IID_IAccessible, wParam, (IUnknown*) GetAccessible()->GetIAccessible()); + } + break; + } +#endif + +#if defined(WM_HELP) case WM_HELP: { + // HELPINFO doesn't seem to be supported on WinCE. +#ifndef __WXWINCE__ HELPINFO* info = (HELPINFO*) lParam; // Don't yet process menu help events, just windows if (info->iContextType == HELPINFO_WINDOW) { +#endif wxWindowMSW* subjectOfHelp = this; bool eventProcessed = FALSE; while (subjectOfHelp && !eventProcessed) { wxHelpEvent helpEvent(wxEVT_HELP, subjectOfHelp->GetId(), - wxPoint(info->MousePos.x, - info->MousePos.y) ); +#ifdef __WXWINCE__ + wxPoint(0, 0) +#else + wxPoint(info->MousePos.x, info->MousePos.y) +#endif + ); + helpEvent.SetEventObject(this); eventProcessed = GetEventHandler()->ProcessEvent(helpEvent); @@ -2761,6 +2846,7 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam } processed = eventProcessed; +#ifndef __WXWINCE__ } else if (info->iContextType == HELPINFO_MENUITEM) { @@ -2770,9 +2856,12 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam } //else: processed is already FALSE +#endif } break; +#endif +#if !defined(__WXWINCE__) case WM_CONTEXTMENU: { // we don't convert from screen to client coordinates as @@ -2780,10 +2869,25 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt); + evtCtx.SetEventObject(this); processed = GetEventHandler()->ProcessEvent(evtCtx); } break; -#endif // __WIN32__ +#endif + + 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; } if ( !processed ) @@ -2821,7 +2925,7 @@ void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win) if ( oldWin && (oldWin != win) ) { wxLogDebug(wxT("HWND %X already associated with another window (%s)"), - hWnd, win->GetClassInfo()->GetClassName()); + (int) hWnd, win->GetClassInfo()->GetClassName()); } else #endif // __WXDEBUG__ @@ -2905,12 +3009,14 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos, nonDefault = TRUE; } + AdjustForParentClientOrigin(x, y); + return nonDefault; } WXHWND wxWindowMSW::MSWGetParent() const { - return m_parent ? m_parent->GetHWND() : NULL; + return m_parent ? m_parent->GetHWND() : WXHWND(NULL); } bool wxWindowMSW::MSWCreate(const wxChar *wclass, @@ -2926,26 +3032,13 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass, // controlId is menu handle for the top level windows, so set it to 0 // unless we're creating a child window - int controlId; - if ( style & WS_CHILD ) - { - controlId = GetId(); - - if ( GetWindowStyleFlag() & wxCLIP_SIBLINGS ) - { - style |= WS_CLIPSIBLINGS; - } - } - else // !child - { - controlId = 0; - } + int controlId = style & WS_CHILD ? GetId() : 0; // 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 ( GetWindowStyleFlag() & wxNO_FULL_REPAINT_ON_RESIZE ) + if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) ) { className += wxT("NR"); } @@ -2953,18 +3046,37 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass, // do create the window wxWindowCreationHook hook(this); - m_hWnd = (WXHWND)::CreateWindowEx - ( - extendedStyle, - className, - title ? title : wxT(""), - style, - x, y, w, h, - (HWND)MSWGetParent(), - (HMENU)controlId, - wxGetInstance(), - NULL // no extra data - ); +#ifdef __WXWINCE__ + if (extendedStyle == 0) + { + m_hWnd = (WXHWND)::CreateWindow + ( + className, + title ? title : wxEmptyString, + style, + x, y, w, h, + (HWND)MSWGetParent(), + (HMENU)controlId, + wxGetInstance(), + NULL // no extra data + ); + } + else +#endif + { + m_hWnd = (WXHWND)::CreateWindowEx + ( + extendedStyle, + className, + title ? title : wxEmptyString, + style, + x, y, w, h, + (HWND)MSWGetParent(), + (HMENU)controlId, + wxGetInstance(), + NULL // no extra data + ); + } if ( !m_hWnd ) { @@ -2989,7 +3101,7 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass, // --------------------------------------------------------------------------- #ifdef __WIN95__ -// FIXME: VZ: I'm not sure at all that the order of processing is correct + bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) { #ifndef __WXMICROWIN__ @@ -2997,14 +3109,21 @@ bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) HWND hWnd = hdr->hwndFrom; wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd); - // is this one of our windows? + // if the control is one of our windows, let it handle the message itself if ( win ) { 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::Node *node = GetChildren().GetFirst(); + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); while ( node ) { wxWindow *child = node->GetData(); @@ -3015,32 +3134,103 @@ bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) node = node->GetNext(); } +#endif // 0 - // finally try this window too (catches toolbar case) + // by default, handle it ourselves return MSWOnNotify(idCtrl, lParam, result); #else // __WXMICROWIN__ return FALSE; #endif } +#if wxUSE_TOOLTIPS + +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 + + LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam; + +#if !wxUSE_UNICODE + if ( code == (WXUINT) TTN_NEEDTEXTA ) + { + // we pass just the pointer as we store the string internally anyhow + ttText->lpszText = (char *)ttip.c_str(); + } + else // TTN_NEEDTEXTW +#endif // !Unicode + { +#if wxUSE_UNICODE + // in Unicode mode this is just what we need + ttText->lpszText = (wxChar *)ttip.c_str(); +#else // !Unicode +/* + MultiByteToWideChar(CP_ACP, 0, ttip, ttip.length()+1, + (wchar_t *)ttText->szText, + sizeof(ttText->szText) / sizeof(wchar_t)); +*/ + // Fix by dimitrishortcut: see patch 771772 + + // FIXME: szText has a max of 80 bytes, so limit the tooltip string + // length accordingly. Ideally lpszText should be used, but who + // would be responsible for freeing the buffer? + + // Maximum length of a tip is 39 characters. 39 is 80/2 minus 1 byte + // needed for NULL character. + size_t tipLength = wxMin(ttip.Len(), 39); + + // Convert to WideChar without adding the NULL character. The NULL + // character is added afterwards (Could have used ttip.Left(tipLength) + // and a cchMultiByte parameter of tipLength+1, but this is more + //efficient. + ::MultiByteToWideChar(CP_ACP, 0, ttip, tipLength, + (wchar_t *)ttText->szText, + sizeof(ttText->szText) / sizeof(wchar_t)); + + // Add the NULL character. + ttText->szText[tipLength*2+0] = '\0'; + ttText->szText[tipLength*2+1] = '\0'; + +#endif // Unicode/!Unicode + } + + return TRUE; +} + +#endif // wxUSE_TOOLTIPS + bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl), - WXLPARAM lParam, - WXLPARAM* WXUNUSED(result)) + WXLPARAM lParam, + WXLPARAM* WXUNUSED(result)) { #if wxUSE_TOOLTIPS - NMHDR* hdr = (NMHDR *)lParam; - if ( (int)hdr->code == TTN_NEEDTEXT && m_tooltip ) + if ( m_tooltip ) { - TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam; - ttt->lpszText = (wxChar *)m_tooltip->GetTip().c_str(); - - // processed - return TRUE; + NMHDR* hdr = (NMHDR *)lParam; + if ( HandleTooltipNotify(hdr->code, lParam, m_tooltip->GetTip())) + { + // processed + return TRUE; + } } #endif // wxUSE_TOOLTIPS return FALSE; } + #endif // __WIN95__ // --------------------------------------------------------------------------- @@ -3049,6 +3239,7 @@ bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl), bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd) { +#ifndef __WXWINCE__ wxCloseEvent event(wxEVT_QUERY_END_SESSION, -1); event.SetEventObject(wxTheApp); event.SetCanVeto(TRUE); @@ -3064,10 +3255,14 @@ bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd) } return rc; +#else + return FALSE; +#endif } bool wxWindowMSW::HandleEndSession(bool endSession, long logOff) { +#ifndef __WXWINCE__ // do nothing if the session isn't ending if ( !endSession ) return FALSE; @@ -3082,14 +3277,25 @@ bool wxWindowMSW::HandleEndSession(bool endSession, long logOff) event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) ); return wxTheApp->ProcessEvent(event); +#else + return FALSE; +#endif } // --------------------------------------------------------------------------- // window creation/destruction // --------------------------------------------------------------------------- -bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED(cs), bool *mayCreate) +bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT cs, bool *mayCreate) { + // 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__ + // TODO: should generate this event from WM_NCCREATE wxWindowCreateEvent event((wxWindow *)this); (void)GetEventHandler()->ProcessEvent(event); @@ -3101,8 +3307,7 @@ bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED(cs), bool *mayCreate) bool wxWindowMSW::HandleDestroy() { - wxWindowDestroyEvent event((wxWindow *)this); - (void)GetEventHandler()->ProcessEvent(event); + SendDestroyEvent(); // delete our drop target if we've got one #if wxUSE_DRAG_AND_DROP @@ -3188,6 +3393,13 @@ bool wxWindowMSW::HandleKillFocus(WXHWND hwnd) } #endif + // 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; + } + wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId); event.SetEventObject(this); @@ -3219,7 +3431,9 @@ bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus)) bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam) { -#ifndef __WXMICROWIN__ +#if defined (__WXMICROWIN__) || defined(__WXWINCE__) + return FALSE; +#else // __WXMICROWIN__ HDROP hFilesInfo = (HDROP) wParam; // Get the total number of files dropped @@ -3239,9 +3453,7 @@ bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam) // and now get the file name ::DragQueryFile(hFilesInfo, wIndex, - files[wIndex].GetWriteBuf(len), len); - - files[wIndex].UngetWriteBuf(); + wxStringBuffer(files[wIndex], len), len); } DragFinish (hFilesInfo); @@ -3254,11 +3466,10 @@ bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam) event.m_pos.y = dropPoint.y; return GetEventHandler()->ProcessEvent(event); -#else // __WXMICROWIN__ - return FALSE; #endif } + bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd), short nHitTest, int WXUNUSED(mouseMsg)) @@ -3282,15 +3493,10 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd), // 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 __WIN32__ if ( !::GetCursorPos(&pt) ) { wxLogLastError(wxT("GetCursorPos")); } -#else - // In WIN16 it doesn't return a value. - ::GetCursorPos(&pt); -#endif int x = pt.x, y = pt.y; @@ -3335,6 +3541,8 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd), if ( hcursor ) { +// wxLogDebug("HandleSetCursor: Setting cursor %ld", (long) hcursor); + ::SetCursor(hcursor); // cursor set, stop here @@ -3350,7 +3558,16 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd), // owner drawn stuff // --------------------------------------------------------------------------- -bool wxWindowMSW::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct) +#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 @@ -3380,22 +3597,34 @@ bool wxWindowMSW::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct) } #endif // wxUSE_MENUS_NATIVE -#if wxUSE_CONTROLS - wxWindow *item = FindItem(id); - if ( item && item->IsKindOf(CLASSINFO(wxControl)) ) +#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 = wxDynamicCast(FindItem(id), wxButton); +#endif // USE_OWNER_DRAWN + + if ( item ) { - return ((wxControl *)item)->MSWOnDraw(itemStruct); + return item->MSWOnDraw(itemStruct); } -#endif // wxUSE_CONTROLS -#endif // USE_OWNER_DRAWN +#endif // wxUSE_CONTROLS return FALSE; } -bool wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct) +bool +wxWindowMSW::MSWOnMeasureItem(int WXUNUSED_UNLESS_ODRAWN(id), + WXMEASUREITEMSTRUCT * + WXUNUSED_UNLESS_ODRAWN(itemStruct)) { -#if wxUSE_OWNER_DRAWN +#if wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE // is it a menu item? MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct; if ( id == 0 && pMeasureStruct->CtlType == ODT_MENU ) @@ -3408,12 +3637,13 @@ bool wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct) &pMeasureStruct->itemHeight); } - wxWindow *item = FindItem(id); - if ( item && item->IsKindOf(CLASSINFO(wxControl)) ) + wxControl *item = wxDynamicCast(FindItem(id), wxControl); + if ( item ) { - return ((wxControl *)item)->MSWOnMeasure(itemStruct); + return item->MSWOnMeasure(itemStruct); } -#endif // owner-drawn menus +#endif // wxUSE_OWNER_DRAWN + return FALSE; } @@ -3452,7 +3682,11 @@ bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush, #ifndef __WXMICROWIN__ WXHBRUSH hBrush = 0; +#ifdef __WXWINCE__ + if (FALSE) +#else if ( nCtlColor == CTLCOLOR_DLG ) +#endif { hBrush = OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam); } @@ -3492,7 +3726,7 @@ bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange) if ( hWndPalChange != GetHWND() ) { // check to see if we our our parents have a custom palette - wxWindow *win = this; + wxWindowMSW *win = this; while ( win && !win->HasCustomPalette() ) { win = win->GetParent(); @@ -3541,7 +3775,7 @@ bool wxWindowMSW::HandleQueryNewPalette() #if wxUSE_PALETTE // check to see if we our our parents have a custom palette - wxWindow *win = this; + wxWindowMSW *win = this; while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent(); if (win->HasCustomPalette()) { /* realize the palette to see whether redrawing is needed */ @@ -3578,7 +3812,7 @@ void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event)) // FIXME-MT gs_hasStdCmap = FALSE; } - wxWindowList::Node *node = GetChildren().GetFirst(); + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); while ( node ) { // Only propagate to non-top-level windows because Windows already @@ -3682,7 +3916,9 @@ extern wxCOLORMAP *wxGetStdColourMap() bool wxWindowMSW::HandlePaint() { -#ifdef __WIN32__ +// if (GetExtraStyle() & wxWS_EX_THEMED_BACKGROUND) +// return FALSE; + HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle if ( !hRegion ) wxLogLastError(wxT("CreateRectRgn")); @@ -3690,14 +3926,6 @@ bool wxWindowMSW::HandlePaint() wxLogLastError(wxT("GetUpdateRgn")); m_updateRegion = wxRegion((WXHRGN) hRegion); -#else // Win16 - RECT updateRect; - ::GetUpdateRect(GetHwnd(), &updateRect, FALSE); - - m_updateRegion = wxRegion(updateRect.left, updateRect.top, - updateRect.right - updateRect.left, - updateRect.bottom - updateRect.top); -#endif // Win32/16 wxPaintEvent event(m_windowId); event.SetEventObject(this); @@ -3734,6 +3962,29 @@ bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc) if ( ::IsIconic(GetHwnd()) ) return TRUE; +#if 0 + if (GetParent() && GetParent()->GetExtraStyle() & wxWS_EX_THEMED_BACKGROUND) + { + return FALSE; + } + + if (GetExtraStyle() & wxWS_EX_THEMED_BACKGROUND) + { + if (wxUxThemeEngine::Get()) + { + WXHTHEME hTheme = wxUxThemeEngine::Get()->m_pfnOpenThemeData(GetHWND(), L"TAB"); + if (hTheme) + { + WXURECT rect; + ::GetClientRect((HWND) GetHWND(), (RECT*) & rect); + wxUxThemeEngine::Get()->m_pfnDrawThemeBackground(hTheme, hdc, 10 /* TABP_BODY */, 0, &rect, &rect); + wxUxThemeEngine::Get()->m_pfnCloseThemeData(hTheme); + return TRUE; + } + } + } +#endif + wxDCTemp dc(hdc); dc.SetHDC(hdc); @@ -3766,11 +4017,16 @@ void wxWindowMSW::OnEraseBackground(wxEraseEvent& event) HDC hdc = (HDC)event.GetDC()->GetHDC(); +#ifndef __WXWINCE__ int mode = ::SetMapMode(hdc, MM_TEXT); +#endif ::FillRect(hdc, &rect, hBrush); ::DeleteObject(hBrush); + +#ifndef __WXWINCE__ ::SetMapMode(hdc, mode); +#endif } // --------------------------------------------------------------------------- @@ -3801,6 +4057,17 @@ bool wxWindowMSW::HandleMove(int x, int y) return GetEventHandler()->ProcessEvent(event); } +bool wxWindowMSW::HandleMoving(wxRect& rect) +{ + wxMoveEvent event(rect, m_windowId); + event.SetEventObject(this); + + bool rc = GetEventHandler()->ProcessEvent(event); + if (rc) + rect = event.GetRect(); + return rc; +} + bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT WXUNUSED(flag)) { @@ -3813,8 +4080,22 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), return GetEventHandler()->ProcessEvent(event); } +bool wxWindowMSW::HandleSizing(wxRect& rect) +{ + wxSizeEvent event(rect, m_windowId); + event.SetEventObject(this); + + bool rc = GetEventHandler()->ProcessEvent(event); + if (rc) + rect = event.GetRect(); + return rc; +} + bool wxWindowMSW::HandleGetMinMaxInfo(void *mmInfo) { +#ifdef __WXWINCE__ + return FALSE; +#else MINMAXINFO *info = (MINMAXINFO *)mmInfo; bool rc = FALSE; @@ -3849,6 +4130,7 @@ bool wxWindowMSW::HandleGetMinMaxInfo(void *mmInfo) } return rc; +#endif } // --------------------------------------------------------------------------- @@ -3921,6 +4203,7 @@ bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) bool wxWindowMSW::HandleSysCommand(WXWPARAM wParam, WXLPARAM WXUNUSED(lParam)) { +#ifndef __WXWINCE__ // 4 bits are reserved switch ( wParam & 0xFFFFFFF0 ) { @@ -3930,6 +4213,7 @@ bool wxWindowMSW::HandleSysCommand(WXWPARAM wParam, WXLPARAM WXUNUSED(lParam)) case SC_MINIMIZE: return HandleMinimize(); } +#endif return FALSE; } @@ -3952,9 +4236,15 @@ void wxWindowMSW::InitMouseEvent(wxMouseEvent& event, 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) & 0x80000000) != 0; + // event.m_altDown = (::GetKeyState(VK_MENU) & 0x80000000) != 0; + // Returns different negative values on WinME and WinNT, + // so simply test for negative value. + event.m_altDown = ::GetKeyState(VK_MENU) < 0; + +#ifndef __WXWINCE__ + event.SetTimestamp(::GetMessageTime()); +#endif - event.SetTimestamp(s_currentMsg.time); event.m_eventObject = this; event.SetId(GetId()); @@ -3985,7 +4275,13 @@ static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y) // HWND hwnd = GetHwndOf(win), hwndUnderMouse; -#ifdef __WIN32__ +#ifdef __WXWINCE__ + hwndUnderMouse = ::ChildWindowFromPoint + ( + hwnd, + pt + ); +#else hwndUnderMouse = ::ChildWindowFromPointEx ( hwnd, @@ -3994,9 +4290,9 @@ static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y) // CWP_SKIPDISABLED | CWP_SKIPTRANSPARENT ); +#endif if ( !hwndUnderMouse || hwndUnderMouse == hwnd ) -#endif // __WIN32__ { // now try any child window at all hwndUnderMouse = ::ChildWindowFromPoint(hwnd, pt); @@ -4061,7 +4357,19 @@ bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags) { // Generate an ENTER event m_mouseInWindow = TRUE; - +#if _WIN32_WINNT >= 0x0400 +#ifndef __WXWINCE__ + TRACKMOUSEEVENT trackinfo; + + trackinfo.cbSize = sizeof(trackinfo); + trackinfo.dwFlags = TME_LEAVE; + trackinfo.hwndTrack = GetHwnd(); + //Use the commctrl.h _TrackMouseEvent, which will call the + // appropriate TrackMouseEvent or emulate it ( win95 ) + // else we need _WIN32_WINNT >= 0x0400 + _TrackMouseEvent(&trackinfo); +#endif +#endif wxMouseEvent event(wxEVT_ENTER_WINDOW); InitMouseEvent(event, x, y, flags); @@ -4099,7 +4407,6 @@ bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam) event.m_wheelRotation = (short)HIWORD(wParam); event.m_wheelDelta = WHEEL_DELTA; -#ifdef __WIN32__ static int s_linesPerRotation = -1; if ( s_linesPerRotation == -1 ) { @@ -4113,10 +4420,6 @@ bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam) s_linesPerRotation = 3; } } -#else // Win16 - // no SystemParametersInfo() under Win16 - static const int s_linesPerRotation = 3; -#endif event.m_linesPerAction = s_linesPerRotation; return GetEventHandler()->ProcessEvent(event); @@ -4151,7 +4454,9 @@ wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType, event.m_keyCode = id; event.m_rawCode = (wxUint32) wParam; event.m_rawFlags = (wxUint32) lParam; - event.SetTimestamp(s_currentMsg.time); +#ifndef __WXWINCE__ + event.SetTimestamp(::GetMessageTime()); +#endif // translate the position to client coords POINT pt; @@ -4171,12 +4476,12 @@ wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType, // WM_KEYDOWN one bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII) { - bool ctrlDown = FALSE; - int id; if ( isASCII ) { - // If 1 -> 26, translate to CTRL plus a letter. + // If 1 -> 26, translate to either special keycode or just set + // ctrlDown. IOW, Ctrl-C should result in keycode == 3 and + // ControlDown() == TRUE. id = wParam; if ( (id > 0) && (id < 27) ) { @@ -4195,8 +4500,8 @@ bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII) break; default: - ctrlDown = TRUE; - id = id + 'a' - 1; + //ctrlDown = TRUE; + break; } } } @@ -4212,9 +4517,18 @@ bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII) } wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam, wParam)); - if ( ctrlDown ) + + // 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) ) { - event.m_controlDown = TRUE; + event.m_controlDown = + event.m_altDown = FALSE; } return GetEventHandler()->ProcessEvent(event); @@ -4262,6 +4576,68 @@ bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam) return FALSE; } +int wxWindowMSW::HandleMenuChar(int chAccel, WXLPARAM lParam) +{ + // FIXME: implement GetMenuItemCount for WinCE, possibly + // in terms of GetMenuItemInfo +#ifndef __WXWINCE__ + const HMENU hmenu = (HMENU)lParam; + + MENUITEMINFO mii; + wxZeroMemory(mii); + mii.cbSize = sizeof(MENUITEMINFO); + 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++ ) + { + 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 ( wxToupper(*p) == chAccel ) + { + return i; + } + else + { + // this one doesn't match + break; + } + } + } + } + } + else // failed to get the menu text? + { + // it's not fatal, so don't show error, but still log + // it + wxLogLastError(_T("GetMenuItemInfo")); + } + } +#endif + return wxNOT_FOUND; +} + // --------------------------------------------------------------------------- // joystick // --------------------------------------------------------------------------- @@ -4397,16 +4773,13 @@ bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam, case SB_THUMBPOSITION: case SB_THUMBTRACK: -#ifdef __WIN32__ // 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) { - SCROLLINFO scrollInfo; - wxZeroMemory(scrollInfo); - scrollInfo.cbSize = sizeof(SCROLLINFO); + WinStruct scrollInfo; scrollInfo.fMask = SIF_TRACKPOS; if ( !::GetScrollInfo(GetHwnd(), @@ -4414,12 +4787,12 @@ bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam, : SB_VERT, &scrollInfo) ) { - wxLogLastError(_T("GetScrollInfo")); + // Not neccessarily an error, if there are no scrollbars yet. + // wxLogLastError(_T("GetScrollInfo")); } event.SetPosition(scrollInfo.nTrackPos); } -#endif // Win32 event.m_eventType = wParam == SB_THUMBPOSITION ? wxEVT_SCROLLWIN_THUMBRELEASE @@ -4554,6 +4927,12 @@ int wxCharCodeMSWToWX(int keySym) case VK_OEM_6: id = ']'; break; case VK_OEM_7: id = '\''; break; +#ifdef VK_APPS + case VK_LWIN: id = WXK_WINDOWS_LEFT; break; + case VK_RWIN: id = WXK_WINDOWS_RIGHT; break; + case VK_APPS: id = WXK_WINDOWS_MENU; break; +#endif // VK_APPS defined + default: id = 0; } @@ -4564,7 +4943,7 @@ int wxCharCodeMSWToWX(int keySym) int wxCharCodeWXToMSW(int id, bool *isVirtual) { *isVirtual = TRUE; - int keySym = 0; + int keySym; switch (id) { case WXK_CANCEL: keySym = VK_CANCEL; break; @@ -4638,6 +5017,18 @@ int wxCharCodeWXToMSW(int id, bool *isVirtual) return keySym; } +bool wxGetKeyState(wxKeyCode key) +{ + bool bVirtual; + int vkey = wxCharCodeWXToMSW(key, &bVirtual); + + //there aren't WXK_ macros for non-virtual key codes + if (bVirtual == false) + return false; + + return GetKeyState(vkey) < 0; +} + wxWindow *wxGetActiveWindow() { HWND hWnd = GetActiveWindow(); @@ -4661,9 +5052,6 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) win = wxFindWinFromHandle((WXHWND)hwnd); if ( !win ) { - // all these hacks only work under Win32 anyhow -#ifdef __WIN32__ - #if wxUSE_RADIOBOX // native radiobuttons return DLGC_RADIOBUTTON here and for any // wxWindow class which overrides WM_GETDLGCODE processing to @@ -4683,8 +5071,6 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) win = wxSpinCtrl::GetSpinForTextCtrl((WXHWND)hwnd); } #endif // wxUSE_SPINCTRL - -#endif // Win32 } } @@ -4713,7 +5099,7 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) return win; } -#ifndef __WXMICROWIN__ +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) // Windows keyboard hook. Allows interception of e.g. F1, ESCAPE // in active frames and dialogs, regardless of where the focus is. @@ -4729,23 +5115,13 @@ void wxSetKeyboardHook(bool 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); - - // avoids warning about statement with no effect (FreeProcInstance - // doesn't do anything under Win32) -#if !defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) && !defined(__NT__) && !defined(__GNUWIN32__) - FreeProcInstance(wxTheKeyboardHookProc); -#endif } } @@ -4766,8 +5142,9 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) event.m_keyCode = id; event.m_shiftDown = wxIsShiftDown(); event.m_controlDown = wxIsCtrlDown(); - event.SetTimestamp(s_currentMsg.time); - +#ifndef __WXWINCE__ + event.SetTimestamp(::GetMessageTime()); +#endif wxWindow *win = wxGetActiveWindow(); wxEvtHandler *handler; if ( win ) @@ -4853,7 +5230,6 @@ const char *wxGetMessageName(int message) 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"; @@ -4869,7 +5245,6 @@ const char *wxGetMessageName(int message) 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"; @@ -4898,11 +5273,9 @@ const char *wxGetMessageName(int message) 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"; @@ -4930,14 +5303,12 @@ const char *wxGetMessageName(int message) 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"; @@ -4952,7 +5323,6 @@ const char *wxGetMessageName(int message) 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"; @@ -4961,7 +5331,6 @@ const char *wxGetMessageName(int message) 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"; @@ -4981,8 +5350,10 @@ const char *wxGetMessageName(int message) case 0x030F: return "WM_QUERYNEWPALETTE"; case 0x0310: return "WM_PALETTEISCHANGING"; case 0x0311: return "WM_PALETTECHANGED"; +#if wxUSE_HOTKEY + case 0x0312: return "WM_HOTKEY"; +#endif -#ifdef __WIN32__ // common controls messages - although they're not strictly speaking // standard, it's nice to decode them nevertheless @@ -5204,8 +5575,6 @@ const char *wxGetMessageName(int message) case WM_USER+61: return "TB_GETTEXTROWS"; case WM_USER+41: return "TB_GETBITMAPFLAGS"; -#endif //WIN32 - default: static char s_szBuf[128]; sprintf(s_szBuf, "", message); @@ -5268,9 +5637,10 @@ static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win) // Find the wxWindow at the current mouse position, returning the mouse // position. -wxWindow* wxFindWindowAtPointer(wxPoint& WXUNUSED(pt)) +wxWindow* wxFindWindowAtPointer(wxPoint& pt) { - return wxFindWindowAtPoint(wxGetMousePosition()); + pt = wxGetMousePosition(); + return wxFindWindowAtPoint(pt); } wxWindow* wxFindWindowAtPoint(const wxPoint& pt) @@ -5301,3 +5671,108 @@ wxPoint wxGetMousePosition() return wxPoint(pt.x, pt.y); } +#if wxUSE_HOTKEY + +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 ( !::RegisterHotKey(GetHwnd(), hotkeyId, win_modifiers, keycode) ) + { + wxLogLastError(_T("RegisterHotKey")); + + return FALSE; + } + + return TRUE; +} + +bool wxWindowMSW::UnregisterHotKey(int hotkeyId) +{ + if ( !::UnregisterHotKey(GetHwnd(), hotkeyId) ) + { + wxLogLastError(_T("UnregisterHotKey")); + + return FALSE; + } + + return TRUE; +} + +bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam) +{ + int hotkeyId = wParam; + int virtualKey = HIWORD(lParam); + int win_modifiers = LOWORD(lParam); + + 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; + + return GetEventHandler()->ProcessEvent(event); +} + +#endif // wxUSE_HOTKEY + +// Not verified for WinCE +#ifndef __WXWINCE__ +/* + * wxEventFixModule (needs a better name) allows message handling to continute while a menu + * is being shown - ie, to continue processing messages from a worker thread. + * + * Code originally by Jason W. from wx-dev, reworked into a wxModule by Chris Mellon + */ + +class wxEventFixModule : public wxModule { +public: + //base class virtuals + virtual bool OnInit() { + wxEventFixModule::s_hMsgHookProc = SetWindowsHookEx( + WH_GETMESSAGE, + &wxEventFixModule::MsgHookProc, + NULL, + GetCurrentThreadId()); + wxLogDebug(_T("Loaded event fix module")); + return true; + }; + virtual void OnExit() { + UnhookWindowsHookEx(wxEventFixModule::s_hMsgHookProc); + + }; + static LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam) { + MSG *msg = (MSG*)lParam; + switch (msg->message) + { + case WM_NULL: + static bool bInHookProc = false; + if (!bInHookProc) + { + bInHookProc = true; + wxTheApp->ProcessPendingEvents(); + bInHookProc = false; + } + break; + } + return CallNextHookEx(wxEventFixModule::s_hMsgHookProc, nCode, wParam, lParam); + }; +private: + static HHOOK s_hMsgHookProc; +DECLARE_DYNAMIC_CLASS(wxEventFixModule) +}; +HHOOK wxEventFixModule::s_hMsgHookProc = 0; + +IMPLEMENT_DYNAMIC_CLASS(wxEventFixModule, wxModule) +#endif + // __WXWINCE__ +