X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/195896c7921c70eeaf588a89cabb02fcb8eb08c6..546bfbea8180aeee5a16f4abb34e721445277305:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 4f8b2a6558..4ee8e7b1f3 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -1,4967 +1,5155 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: windows.cpp +// Name: src/msw/windows.cpp // Purpose: wxWindow // Author: Julian Smart -// Modified by: +// Modified by: VZ on 13.05.99: no more Default(), MSWOnXXX() reorganisation // Created: 04/01/98 // RCS-ID: $Id$ // Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows license +// Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// +// =========================================================================== +// declarations +// =========================================================================== + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + #ifdef __GNUG__ -#pragma implementation "window.h" + #pragma implementation "window.h" #endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop + #pragma hdrstop #endif #ifndef WX_PRECOMP -#include -#include "wx/setup.h" -#include "wx/menu.h" -#include "wx/dc.h" -#include "wx/dcclient.h" -#include "wx/utils.h" -#include "wx/app.h" -#include "wx/panel.h" -#include "wx/layout.h" -#include "wx/dialog.h" -#include "wx/listbox.h" -#include "wx/button.h" -#include "wx/settings.h" -#include "wx/msgdlg.h" + #include + #include "wx/msw/winundef.h" + #include "wx/window.h" + #include "wx/accel.h" + #include "wx/setup.h" + #include "wx/menu.h" + #include "wx/dc.h" + #include "wx/dcclient.h" + #include "wx/dcmemory.h" + #include "wx/utils.h" + #include "wx/app.h" + #include "wx/layout.h" + #include "wx/dialog.h" + #include "wx/frame.h" + #include "wx/listbox.h" + #include "wx/button.h" + #include "wx/msgdlg.h" + #include "wx/settings.h" + #include "wx/statbox.h" #endif -#if USE_OWNER_DRAWN -#include "wx/ownerdrw.h" +#if wxUSE_OWNER_DRAWN + #include "wx/ownerdrw.h" #endif -#if USE_DRAG_AND_DROP -#include "wx/msw/ole/droptgt.h" +#if wxUSE_DRAG_AND_DROP + #include "wx/dnd.h" #endif #include "wx/menuitem.h" +#include "wx/log.h" + #include "wx/msw/private.h" +#if wxUSE_TOOLTIPS + #include "wx/tooltip.h" +#endif + +#if wxUSE_CARET + #include "wx/caret.h" +#endif // wxUSE_CARET + +#if wxUSE_SPINCTRL + #include "wx/spinctrl.h" +#endif // wxUSE_SPINCTRL + +#include "wx/intl.h" +#include "wx/log.h" + +#include "wx/textctrl.h" +#include "wx/notebook.h" + #include -#ifndef __GNUWIN32__ -#include -#include +#if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__)) || defined(__CYGWIN10__) + #include + #include #endif #ifdef __WIN32__ -#include -#endif - -#ifdef __GNUWIN32__ -#include + #include #endif -#ifdef GetCharWidth -#undef GetCharWidth +#if (!defined(__GNUWIN32_OLD__) && !defined(__TWIN32__) && !defined(__WXMICROWIN__)) || defined(__CYGWIN10__) + #ifdef __WIN95__ + #include + #endif +#elif !defined(__WXMICROWIN__) // broken compiler + #ifndef __TWIN32__ + #include "wx/msw/gnuwin32/extra.h" + #endif #endif -#ifdef FindWindow -#undef FindWindow +// This didn't appear in mingw until 2.95.2 +#ifndef SIF_TRACKPOS +#define SIF_TRACKPOS 16 #endif -#ifdef GetClassName -#undef GetClassName +#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 -#ifdef GetClassInfo -#undef GetClassInfo -#endif +// --------------------------------------------------------------------------- +// global variables +// --------------------------------------------------------------------------- -#define WINDOW_MARGIN 3 // This defines sensitivity of Leave events +// the last Windows message we got (FIXME-MT) +extern MSG s_currentMsg; +#if wxUSE_MENUS_NATIVE wxMenu *wxCurrentPopupMenu = NULL; -extern wxList wxPendingDelete; +#endif // wxUSE_MENUS_NATIVE + +extern const wxChar *wxCanvasClassName; + +// true if we had already created the std colour map, used by +// wxGetStdColourMap() and wxWindow::OnSysColourChanged() (FIXME-MT) +static bool gs_hasStdCmap = FALSE; + +// --------------------------------------------------------------------------- +// private functions +// --------------------------------------------------------------------------- + +// the window proc for all our windows +LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam); -void wxRemoveHandleAssociation(wxWindow *win); -void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win); +#ifdef __WXDEBUG__ + const char *wxGetMessageName(int message); +#endif //__WXDEBUG__ + +void wxRemoveHandleAssociation(wxWindowMSW *win); +void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win); wxWindow *wxFindWinFromHandle(WXHWND hWnd); -#if !USE_SHARED_LIBRARY -IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxEvtHandler) +// this magical function is used to translate VK_APPS key presses to right +// mouse clicks +static void TranslateKbdEventToMouse(wxWindowMSW *win, + int *x, int *y, WPARAM *flags); + +// get the text metrics for the current font +static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win); + +// wrapper around BringWindowToTop() API +static inline void wxBringWindowToTop(HWND hwnd) +{ +#ifdef __WXMICROWIN__ + // It seems that MicroWindows brings the _parent_ of the window to the top, + // which can be the wrong one. + + // activate (set focus to) specified window + ::SetFocus(hwnd); -BEGIN_EVENT_TABLE(wxWindow, wxEvtHandler) - EVT_CHAR(wxWindow::OnChar) - EVT_SIZE(wxWindow::OnSize) - EVT_ERASE_BACKGROUND(wxWindow::OnEraseBackground) - EVT_SYS_COLOUR_CHANGED(wxWindow::OnSysColourChanged) - EVT_INIT_DIALOG(wxWindow::OnInitDialog) - EVT_IDLE(wxWindow::OnIdle) + // 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) ) + { + wxLogLastError(_T("BringWindowToTop")); + } +#endif // __WXMICROWIN__/!__WXMICROWIN__ +} + +// --------------------------------------------------------------------------- +// event tables +// --------------------------------------------------------------------------- + +// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu() +// method +#ifdef __WXUNIVERSAL__ + IMPLEMENT_ABSTRACT_CLASS(wxWindowMSW, wxWindowBase) +#else // __WXMSW__ + IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase) +#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() -#endif +// =========================================================================== +// implementation +// =========================================================================== + +// --------------------------------------------------------------------------- +// wxWindow utility functions +// --------------------------------------------------------------------------- // Find an item given the MS Windows id -wxWindow *wxWindow::FindItem(const int id) const +wxWindow *wxWindowMSW::FindItem(long id) const { - if (!GetChildren()) - return NULL; - wxNode *current = GetChildren()->First(); - while (current) - { - wxWindow *childWin = (wxWindow *)current->Data(); - - wxWindow *wnd = childWin->FindItem(id) ; - if (wnd) - return wnd ; +#if wxUSE_CONTROLS + wxControl *item = wxDynamicCastThis(wxControl); + if ( item ) + { + // is it we or one of our "internal" children? + if ( item->GetId() == id +#ifndef __WXUNIVERSAL__ + || (item->GetSubcontrols().Index(id) != wxNOT_FOUND) +#endif // __WXUNIVERSAL__ + ) + { + return item; + } + } +#endif // wxUSE_CONTROLS - if (childWin->IsKindOf(CLASSINFO(wxControl))) + wxWindowList::Node *current = GetChildren().GetFirst(); + while (current) { - wxControl *item = (wxControl *)childWin; - if (item->m_windowId == id) - return item; - else - { - // In case it's a 'virtual' control (e.g. radiobox) - if (item->GetSubcontrols().Member((wxObject *)id)) - return item; - } + wxWindow *childWin = current->GetData(); + + wxWindow *wnd = childWin->FindItem(id); + if ( wnd ) + return wnd; + + current = current->GetNext(); } - current = current->Next(); - } - return NULL; -} -// Find an item given the MS Windows handle -wxWindow *wxWindow::FindItemByHWND(const WXHWND hWnd, bool controlOnly) const -{ - if (!GetChildren()) return NULL; - wxNode *current = GetChildren()->First(); - while (current) - { - wxObject *obj = (wxObject *)current->Data() ; - // Do a recursive search. - wxWindow *parent = (wxWindow *)obj ; - wxWindow *wnd = parent->FindItemByHWND(hWnd) ; - if (wnd) - return wnd ; - - if ((!controlOnly) || obj->IsKindOf(CLASSINFO(wxControl))) - { - wxWindow *item = (wxWindow *)current->Data(); - if ((HWND)(item->GetHWND()) == (HWND) hWnd) - return item; - else - { - if ( item->ContainsHWND(hWnd) ) - return item; - } - } - current = current->Next(); - } - return NULL; -} - -// Default command handler -bool wxWindow::MSWCommand(const WXUINT WXUNUSED(param), const WXWORD WXUNUSED(id)) -{ - return FALSE; } -bool wxWindow::MSWNotify(const WXWPARAM WXUNUSED(wParam), const WXLPARAM WXUNUSED(lParam)) +// Find an item given the MS Windows handle +wxWindow *wxWindowMSW::FindItemByHWND(WXHWND hWnd, bool controlOnly) const { - return FALSE; -} + wxWindowList::Node *current = GetChildren().GetFirst(); + while (current) + { + wxWindow *parent = current->GetData(); + + // Do a recursive search. + wxWindow *wnd = parent->FindItemByHWND(hWnd); + if ( wnd ) + return wnd; + + if ( !controlOnly +#if wxUSE_CONTROLS + || parent->IsKindOf(CLASSINFO(wxControl)) +#endif // wxUSE_CONTROLS + ) + { + wxWindow *item = current->GetData(); + if ( item->GetHWND() == hWnd ) + return item; + else + { + if ( item->ContainsHWND(hWnd) ) + return item; + } + } -void wxWindow::PreDelete(const WXHDC WXUNUSED(dc)) -{ + current = current->GetNext(); + } + return NULL; } -WXHWND wxWindow::GetHWND(void) const +// Default command handler +bool wxWindowMSW::MSWCommand(WXUINT WXUNUSED(param), WXWORD WXUNUSED(id)) { - return (WXHWND) m_hWnd; + return FALSE; } -void wxWindow::SetHWND(WXHWND hWnd) -{ - m_hWnd = hWnd; -} +// ---------------------------------------------------------------------------- +// constructors and such +// ---------------------------------------------------------------------------- -// Constructor -wxWindow::wxWindow(void) +void wxWindowMSW::Init() { - // Generic - m_windowId = 0; - m_isShown = TRUE; - m_windowStyle = 0; - m_windowParent = NULL; - m_windowEventHandler = this; - m_windowName = ""; - m_windowCursor = *wxSTANDARD_CURSOR; - m_children = new wxList; - m_doubleClickAllowed = 0 ; - m_winCaptured = FALSE; - m_constraints = NULL; - m_constraintsInvolvedIn = NULL; - m_windowSizer = NULL; - m_sizerParent = NULL; - m_autoLayout = FALSE; - m_windowValidator = NULL; - - // MSW-specific - m_hWnd = 0; - m_winEnabled = TRUE; - m_caretWidth = 0; m_caretHeight = 0; - m_caretEnabled = FALSE; - m_caretShown = FALSE; - m_inOnSize = FALSE; - m_minSizeX = -1; - m_minSizeY = -1; - m_maxSizeX = -1; - m_maxSizeY = -1; -// m_paintHDC = 0; -// m_tempHDC = 0; - m_isBeingDeleted = FALSE; - m_oldWndProc = 0; -#ifndef __WIN32__ - m_globalHandle = 0; -#endif - m_useCtl3D = FALSE; - - m_defaultItem = NULL; + // generic + InitBase(); - wxSystemSettings settings; + // MSW specific + m_doubleClickAllowed = 0; - m_backgroundColour = settings.GetSystemColour(wxSYS_COLOUR_WINDOW) ; ; - m_foregroundColour = *wxBLACK; - m_defaultForegroundColour = *wxBLACK ; - m_defaultBackgroundColour = settings.GetSystemColour(wxSYS_COLOUR_3DFACE) ; + m_isBeingDeleted = FALSE; + m_oldWndProc = 0; + m_useCtl3D = FALSE; + m_mouseInWindow = FALSE; -/* - wxColour(GetRValue(GetSysColor(COLOR_WINDOW)), - GetGValue(GetSysColor(COLOR_BTNFACE)), GetBValue(GetSysColor(COLOR_BTNFACE))); -*/ + // wxWnd + m_hMenu = 0; - // wxWnd - m_lastMsg = 0; - m_lastWParam = 0; - m_lastLParam = 0; - m_acceleratorTable = 0; - m_hMenu = 0; + m_hWnd = 0; - m_xThumbSize = 0; - m_yThumbSize = 0; - m_backgroundTransparent = FALSE; + m_xThumbSize = 0; + m_yThumbSize = 0; + m_backgroundTransparent = FALSE; - m_lastXPos = (float)-1.0; - m_lastYPos = (float)-1.0; - m_lastEvent = -1; - m_returnCode = 0; + // as all windows are created with WS_VISIBLE style... + m_isShown = TRUE; -#if USE_DRAG_AND_DROP - m_pDropTarget = NULL; -#endif +#if wxUSE_MOUSEEVENT_HACK + m_lastMouseX = + m_lastMouseY = -1; + m_lastMouseEvent = -1; +#endif // wxUSE_MOUSEEVENT_HACK } // Destructor -wxWindow::~wxWindow(void) -{ - m_isBeingDeleted = TRUE; - - // JACS - if behaviour is odd, restore this - // to the start of ~wxWindow. Vadim has changed - // it to nearer the end. Unsure of side-effects - // e.g. when deleting associated global data. - // Restore old Window proc, if required -// UnsubclassWin(); - - // Have to delete constraints/sizer FIRST otherwise - // sizers may try to look at deleted windows as they - // delete themselves. -#if USE_CONSTRAINTS - DeleteRelatedConstraints(); - if (m_constraints) - { - // This removes any dangling pointers to this window - // in other windows' constraintsInvolvedIn lists. - UnsetConstraints(m_constraints); - delete m_constraints; - m_constraints = NULL; - } - if (m_windowSizer) - { - delete m_windowSizer; - m_windowSizer = NULL; - } - // If this is a child of a sizer, remove self from parent - if (m_sizerParent) - m_sizerParent->RemoveChild((wxWindow *)this); -#endif +wxWindowMSW::~wxWindowMSW() +{ + m_isBeingDeleted = TRUE; - // wxWnd - MSWDetachWindowMenu(); +#ifndef __WXUNIVERSAL__ + // 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); + if ( frame ) + { + if ( frame->GetLastFocus() == this ) + { + frame->SetLastFocus((wxWindow*)NULL); + } + break; + } + } +#endif // __WXUNIVERSAL__ - // TODO for backward compatibility -#if 0 - // WX_CANVAS - if (m_windowDC) - { - HWND hWnd = (HWND) GetHWND(); - HDC dc = ::GetDC(hWnd); - m_windowDC->SelectOldObjects (dc); - ReleaseDC(hWnd, dc); - delete m_windowDC; - } -#endif + // VS: destroy children first and _then_ detach *this from its parent. + // If we'd do it the other way around, children wouldn't be able + // find their parent frame (see above). + DestroyChildren(); - if (m_windowParent) - m_windowParent->RemoveChild(this); + if ( m_parent ) + m_parent->RemoveChild(this); - DestroyChildren(); + if ( m_hWnd ) + { + // VZ: test temp removed to understand what really happens here + //if (::IsWindow(GetHwnd())) + { + if ( !::DestroyWindow(GetHwnd()) ) + wxLogLastError(wxT("DestroyWindow")); + } - if (m_hWnd) - ::DestroyWindow((HWND)m_hWnd); + // remove hWnd <-> wxWindow association + wxRemoveHandleAssociation(this); + } +} - wxRemoveHandleAssociation(this); - m_hWnd = 0; -#ifndef __WIN32__ - if (m_globalHandle) - { - GlobalFree((HGLOBAL) m_globalHandle); - m_globalHandle = 0; - } -#endif +// real construction (Init() must have been called before!) +bool wxWindowMSW::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + 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; - delete m_children; - m_children = NULL; + parent->AddChild(this); - // Just in case the window has been Closed, but - // we're then deleting immediately: don't leave - // dangling pointers. - wxPendingDelete.DeleteObject(this); + // note that all windows are created visible by default + WXDWORD exstyle; + DWORD msflags = WS_VISIBLE | MSWGetCreateWindowFlags(&exstyle); - // Just in case we've loaded a top-level window via - // wxWindow::LoadNativeDialog but we weren't a dialog - // class - wxTopLevelWindows.DeleteObject(this); +#ifdef __WXUNIVERSAL__ + // no borders, we draw them ourselves + exstyle = 0; + msflags &= ~WS_BORDER; +#endif // wxUniversal -// if (GetFont() && GetFont()->Ok()) -// GetFont()->ReleaseResource(); + if ( style & wxPOPUP_WINDOW ) + { + // a popup window floats on top of everything + exstyle |= WS_EX_TOPMOST | WS_EX_TOOLWINDOW; - if ( m_windowValidator ) - delete m_windowValidator; + // it is also created hidden as other top level windows + msflags &= ~WS_VISIBLE; + m_isShown = FALSE; + } - // Restore old Window proc, if required - // and remove hWnd <-> wxWindow association - UnsubclassWin(); + return MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle); } -// Destroy the window (delayed, if a managed window) -bool wxWindow::Destroy(void) -{ - delete this; - return TRUE; -} +// --------------------------------------------------------------------------- +// basic operations +// --------------------------------------------------------------------------- -extern char wxCanvasClassName[]; - -// Constructor -bool wxWindow::Create(wxWindow *parent, const wxWindowID id, - const wxPoint& pos, - const wxSize& size, - const long style, - const wxString& name) -{ - // Generic - m_isBeingDeleted = FALSE; - m_windowId = 0; - m_isShown = TRUE; - m_windowStyle = 0; - m_windowParent = NULL; - m_windowEventHandler = this; -// m_windowFont = NULL; - // We don't wish internal (potentially transient) fonts to be found - // by FindOrCreate -// wxTheFontList->RemoveFont(& m_windowFont); - m_windowName = ""; - m_windowCursor = *wxSTANDARD_CURSOR; - m_doubleClickAllowed = 0 ; - m_winCaptured = FALSE; - m_constraints = NULL; - m_constraintsInvolvedIn = NULL; - m_windowSizer = NULL; - m_sizerParent = NULL; - m_autoLayout = FALSE; - m_windowValidator = NULL; -#if USE_DRAG_AND_DROP - m_pDropTarget = NULL; -#endif +void wxWindowMSW::SetFocus() +{ + HWND hWnd = GetHwnd(); + wxCHECK_RET( hWnd, _T("can't set focus to invalid window") ); - // MSW-specific - m_hWnd = 0; - m_winEnabled = TRUE; - m_caretWidth = 0; m_caretHeight = 0; - m_caretEnabled = FALSE; - m_caretShown = FALSE; - m_inOnSize = FALSE; - m_minSizeX = -1; - m_minSizeY = -1; - m_maxSizeX = -1; - m_maxSizeY = -1; -// m_paintHDC = 0; -// m_tempHDC = 0; - m_oldWndProc = 0; -#ifndef __WIN32__ - m_globalHandle = 0; +#ifndef __WXMICROWIN__ + ::SetLastError(0); #endif - m_useCtl3D = FALSE; - m_defaultItem = NULL; - m_windowParent = NULL; -// m_windowDC = NULL; - m_mouseInWindow = FALSE; - if (!parent) - return FALSE; - - if (parent) parent->AddChild(this); - - // wxWnd - m_lastMsg = 0; - m_lastWParam = 0; - m_lastLParam = 0; - m_acceleratorTable = 0; - m_hMenu = 0; - m_xThumbSize = 0; - m_yThumbSize = 0; - m_backgroundTransparent = FALSE; - - m_lastXPos = (float)-1.0; - m_lastYPos = (float)-1.0; - m_lastEvent = -1; - m_returnCode = 0; - - SetName(name); - - if ( id == -1 ) - m_windowId = (int)NewControlId(); - else - m_windowId = id; + if ( !::SetFocus(hWnd) ) + { +#if defined(__WXDEBUG__) && !defined(__WXMICROWIN__) + // was there really an error? + DWORD dwRes = ::GetLastError(); + if ( dwRes ) + { + HWND hwndFocus = ::GetFocus(); + if ( hwndFocus != hWnd ) + { + wxLogApiError(_T("SetFocus"), dwRes); + } + } +#endif // Debug + } +} - int x = pos.x; - int y = pos.y; - int width = size.x; - int height = size.y; +// Get the window with the focus +wxWindow *wxWindowBase::FindFocus() +{ + HWND hWnd = ::GetFocus(); + if ( hWnd ) + { + return wxGetWindowFromHWND((WXHWND)hWnd); + } - wxSystemSettings settings; + return NULL; +} - m_backgroundColour = settings.GetSystemColour(wxSYS_COLOUR_WINDOW) ; ; - m_foregroundColour = *wxBLACK; - m_defaultForegroundColour = *wxBLACK ; - m_defaultBackgroundColour = settings.GetSystemColour(wxSYS_COLOUR_3DFACE) ; -/* - m_defaultBackgroundColour = wxColour(GetRValue(GetSysColor(COLOR_BTNFACE)), - GetGValue(GetSysColor(COLOR_BTNFACE)), GetBValue(GetSysColor(COLOR_BTNFACE))); -*/ +bool wxWindowMSW::Enable(bool enable) +{ + if ( !wxWindowBase::Enable(enable) ) + return FALSE; - m_windowStyle = style; + HWND hWnd = GetHwnd(); + if ( hWnd ) + ::EnableWindow(hWnd, (BOOL)enable); - DWORD msflags = 0; - if (style & wxBORDER) - msflags |= WS_BORDER; - if (style & wxTHICK_FRAME) - msflags |= WS_THICKFRAME; - // TODO: probably make WS_CLIPCHILDREN this a setting in wx/setup.h, - // to reduce flicker with the trade-off that groupboxes must paint in a solid - // colour (so your control order must be correct, and you can't easily draw a - // transparent group). - msflags |= WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN; + // 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 ) + { + wxWindow *child = node->GetData(); + child->Enable(enable); - bool want3D; - WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D) ; + node = node->GetNext(); + } +#endif // 0 - // Even with extended styles, need to combine with WS_BORDER - // for them to look right. - if (want3D || (m_windowStyle & wxSIMPLE_BORDER) || (m_windowStyle & wxRAISED_BORDER) || - (m_windowStyle & wxSUNKEN_BORDER) || (m_windowStyle & wxDOUBLE_BORDER)) - msflags |= WS_BORDER; + return TRUE; +} - m_mouseInWindow = FALSE ; +bool wxWindowMSW::Show(bool show) +{ + if ( !wxWindowBase::Show(show) ) + return FALSE; - if ( id == -1 ) - m_windowId = (int)NewControlId(); - else - m_windowId = id; + HWND hWnd = GetHwnd(); + int cshow = show ? SW_SHOW : SW_HIDE; + ::ShowWindow(hWnd, cshow); - MSWCreate(m_windowId, (wxWindow *)parent, wxCanvasClassName, this, NULL, x, y, width, height, msflags, - NULL, exStyle); + if ( show ) + { + wxBringWindowToTop(hWnd); + } - return TRUE; + return TRUE; } -void wxWindow::SetFocus(void) +// Raise the window to the top of the Z order +void wxWindowMSW::Raise() { - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - ::SetFocus(hWnd); + wxBringWindowToTop(GetHwnd()); } -void wxWindow::Enable(const bool enable) +// Lower the window to the bottom of the Z order +void wxWindowMSW::Lower() { - m_winEnabled = enable; - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - ::EnableWindow(hWnd, (BOOL)enable); + ::SetWindowPos(GetHwnd(), HWND_BOTTOM, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); } -void wxWindow::CaptureMouse(void) +void wxWindowMSW::SetTitle( const wxString& title) { - HWND hWnd = (HWND) GetHWND(); - if (hWnd && !m_winCaptured) - { - SetCapture(hWnd); - m_winCaptured = TRUE; - } + SetWindowText(GetHwnd(), title.c_str()); } -void wxWindow::ReleaseMouse(void) +wxString wxWindowMSW::GetTitle() const { - if (m_winCaptured) - { - ReleaseCapture(); - m_winCaptured = FALSE; - } + return wxGetWindowText(GetHWND()); } -// Push/pop event handler (i.e. allow a chain of event handlers -// be searched) -void wxWindow::PushEventHandler(wxEvtHandler *handler) +void wxWindowMSW::DoCaptureMouse() { - handler->SetNextHandler(GetEventHandler()); - SetEventHandler(handler); + HWND hWnd = GetHwnd(); + if ( hWnd ) + { + ::SetCapture(hWnd); + } } -wxEvtHandler *wxWindow::PopEventHandler(bool deleteHandler) +void wxWindowMSW::DoReleaseMouse() { - if ( GetEventHandler() ) - { - wxEvtHandler *handlerA = GetEventHandler(); - wxEvtHandler *handlerB = handlerA->GetNextHandler(); - handlerA->SetNextHandler(NULL); - SetEventHandler(handlerB); - if ( deleteHandler ) - { - delete handlerA; - return NULL; - } - else - return handlerA; - } - else - return NULL; + if ( !::ReleaseCapture() ) + { + wxLogLastError(_T("ReleaseCapture")); + } } -#if USE_DRAG_AND_DROP +/* static */ wxWindow *wxWindowBase::GetCapture() +{ + HWND hwnd = ::GetCapture(); + return hwnd ? wxFindWinFromHandle((WXHWND)hwnd) : (wxWindow *)NULL; +} -void wxWindow::SetDropTarget(wxDropTarget *pDropTarget) +bool wxWindowMSW::SetFont(const wxFont& font) { - if ( m_pDropTarget != 0 ) { - m_pDropTarget->Revoke(m_hWnd); - delete m_pDropTarget; - } + if ( !wxWindowBase::SetFont(font) ) + { + // nothing to do + return FALSE; + } - m_pDropTarget = pDropTarget; - if ( m_pDropTarget != 0 ) - m_pDropTarget->Register(m_hWnd); -} + HWND hWnd = GetHwnd(); + if ( hWnd != 0 ) + { + WXHANDLE hFont = m_font.GetResourceHandle(); -#endif + wxASSERT_MSG( hFont, wxT("should have valid font") ); -//old style file-manager drag&drop support -// I think we should retain the old-style -// DragAcceptFiles in parallel with SetDropTarget. -// JACS -void wxWindow::DragAcceptFiles(const bool accept) -{ - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - ::DragAcceptFiles(hWnd, (BOOL)accept); -} + ::SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); + } -// Get total size -void wxWindow::GetSize(int *x, int *y) const -{ - HWND hWnd = (HWND) GetHWND(); - RECT rect; - GetWindowRect(hWnd, &rect); - *x = rect.right - rect.left; - *y = rect.bottom - rect.top; + return TRUE; } - -void wxWindow::GetPosition(int *x, int *y) const +bool wxWindowMSW::SetCursor(const wxCursor& cursor) { - HWND hWnd = (HWND) GetHWND(); - HWND hParentWnd = 0; - if (GetParent()) - hParentWnd = (HWND) GetParent()->GetHWND(); - - RECT rect; - GetWindowRect(hWnd, &rect); + if ( !wxWindowBase::SetCursor(cursor) ) + { + // no change + return FALSE; + } + + if ( m_cursor.Ok() ) + { + HWND hWnd = GetHwnd(); - // Since we now have the absolute screen coords, - // if there's a parent we must subtract its top left corner - POINT point; - point.x = rect.left; - point.y = rect.top; - if (hParentWnd) - { - ::ScreenToClient(hParentWnd, &point); - } - *x = point.x; - *y = point.y; + // Change the cursor NOW if we're within the correct window + POINT point; + ::GetCursorPos(&point); + + RECT rect = wxGetWindowRect(hWnd); + + if ( ::PtInRect(&rect, point) && !wxIsBusy() ) + ::SetCursor(GetHcursorOf(m_cursor)); + } + + return TRUE; } -void wxWindow::ScreenToClient(int *x, int *y) const +void wxWindowMSW::WarpPointer (int x, int y) { - HWND hWnd = (HWND) GetHWND(); - POINT pt; - pt.x = *x; - pt.y = *y; - ::ScreenToClient(hWnd, &pt); + ClientToScreen(&x, &y); - *x = pt.x; - *y = pt.y; + if ( !::SetCursorPos(x, y) ) + { + wxLogLastError(_T("SetCursorPos")); + } } -void wxWindow::ClientToScreen(int *x, int *y) const +#if WXWIN_COMPATIBILITY +void wxWindowMSW::MSWDeviceToLogical (float *x, float *y) const { - HWND hWnd = (HWND) GetHWND(); - POINT pt; - pt.x = *x; - pt.y = *y; - ::ClientToScreen(hWnd, &pt); - - *x = pt.x; - *y = pt.y; } +#endif // WXWIN_COMPATIBILITY + +// --------------------------------------------------------------------------- +// scrolling stuff +// --------------------------------------------------------------------------- -void wxWindow::SetCursor(const wxCursor& cursor) +#if WXWIN_COMPATIBILITY +void wxWindowMSW::SetScrollRange(int orient, int range, bool refresh) { - m_windowCursor = cursor; - if (m_windowCursor.Ok()) - { - HWND hWnd = (HWND) GetHWND(); +#if defined(__WIN95__) - // Change the cursor NOW if we're within the correct window - POINT point; - ::GetCursorPos(&point); + int range1 = range; - RECT rect; - ::GetWindowRect(hWnd, &rect); + // 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); + } - if (::PtInRect(&rect, point) && !wxIsBusy()) - ::SetCursor((HCURSOR) m_windowCursor.GetHCURSOR()); - } + SCROLLINFO info; + int dir; - // This will cause big reentrancy problems if wxFlushEvents is implemented. -// wxFlushEvents(); -// return old_cursor; -} + 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; -// Get size *available for subwindows* i.e. excluding menu bar etc. -// For XView, this is the same as GetSize -void wxWindow::GetClientSize(int *x, int *y) const -{ - HWND hWnd = (HWND) GetHWND(); - RECT rect; - GetClientRect(hWnd, &rect); - *x = rect.right; - *y = rect.bottom; -} - -void wxWindow::SetSize(const int x, const int y, const int width, const int height, const int sizeFlags) -{ - int currentX, currentY; - GetPosition(¤tX, ¤tY); - int actualWidth = width; - int actualHeight = height; - int actualX = x; - int actualY = y; - if (x == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) - actualX = currentX; - if (y == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) - actualY = currentY; - - int currentW,currentH; - GetSize(¤tW, ¤tH); - if (width == -1) - actualWidth = currentW ; - if (height == -1) - actualHeight = currentH ; - - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - MoveWindow(hWnd, actualX, actualY, actualWidth, actualHeight, (BOOL)TRUE); - -/* Not needed? should be called anyway via MoveWindow - if (!(width == -1) && (height == -1)) - { -#if WXWIN_COMPATIBILITY - GetEventHandler()->OldOnSize(width, height); + HWND hWnd = GetHwnd(); + if ( hWnd ) + ::SetScrollInfo(hWnd, dir, &info, refresh); #else - wxSizeEvent event(wxSize(width, height), m_windowId); - event.eventObject = this; - GetEventHandler()->ProcessEvent(event); + 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 wxWindow::SetClientSize(const int width, const int height) +void wxWindowMSW::SetScrollPage(int orient, int page, bool refresh) { - wxWindow *parent = GetParent(); - HWND hWnd = (HWND) GetHWND(); - HWND hParentWnd = (HWND) (HWND) parent->GetHWND(); - - RECT rect; - GetClientRect(hWnd, &rect); - - RECT rect2; - GetWindowRect(hWnd, &rect2); +#if defined(__WIN95__) + SCROLLINFO info; + int dir; + + if ( orient == wxHORIZONTAL ) { + dir = SB_HORZ; + m_xThumbSize = page; + } else { + dir = SB_VERT; + m_yThumbSize = page; + } - // Find the difference between the entire window (title bar and all) - // and the client area; add this to the new client size to move the - // window - int actual_width = rect2.right - rect2.left - rect.right + width; - int actual_height = rect2.bottom - rect2.top - rect.bottom + height; + info.cbSize = sizeof(SCROLLINFO); + info.nPage = page; + info.nMin = 0; + info.fMask = SIF_PAGE; - // If there's a parent, must subtract the parent's top left corner - // since MoveWindow moves relative to the parent + HWND hWnd = GetHwnd(); + if ( hWnd ) + ::SetScrollInfo(hWnd, dir, &info, refresh); +#else + if ( orient == wxHORIZONTAL ) + m_xThumbSize = page; + else + m_yThumbSize = page; +#endif +} - POINT point; - point.x = rect2.left; - point.y = rect2.top; - if (parent) - { - ::ScreenToClient(hParentWnd, &point); - } +int wxWindowMSW::OldGetScrollRange(int orient) const +{ + int wOrient; + if ( orient == wxHORIZONTAL ) + wOrient = SB_HORZ; + else + wOrient = SB_VERT; - MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)TRUE); -#if WXWIN_COMPATIBILITY - GetEventHandler()->OldOnSize(width, height); +#if __WATCOMC__ && defined(__WINDOWS_386__) + short minPos, maxPos; #else - wxSizeEvent event(wxSize(width, height), m_windowId); - event.m_eventObject = this; - GetEventHandler()->ProcessEvent(event); + 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; } -bool wxWindow::Show(const bool show) +int wxWindowMSW::GetScrollPage(int orient) const { - HWND hWnd = (HWND) GetHWND(); - int cshow; - if (show) - cshow = SW_SHOW; - else - cshow = SW_HIDE; - ShowWindow(hWnd, (BOOL)cshow); - if (show) - { - BringWindowToTop(hWnd); - // Next line causes a crash on NT, apparently. -// UpdateWindow(hWnd); // Should this be here or will it cause inefficiency? - } - return TRUE; + if ( orient == wxHORIZONTAL ) + return m_xThumbSize; + else + return m_yThumbSize; } -bool wxWindow::IsShown(void) const +#endif // WXWIN_COMPATIBILITY + +inline int GetScrollPosition(HWND hWnd, int wOrient) { - return (::IsWindowVisible((HWND) GetHWND()) != 0); +#ifdef __WXMICROWIN__ + return ::GetScrollPosWX(hWnd, wOrient); +#else + return ::GetScrollPos(hWnd, wOrient); +#endif } -int wxWindow::GetCharHeight(void) const +int wxWindowMSW::GetScrollPos(int orient) const { - TEXTMETRIC lpTextMetric; - HWND hWnd = (HWND) GetHWND(); - HDC dc = ::GetDC(hWnd); + int wOrient; + if ( orient == wxHORIZONTAL ) + wOrient = SB_HORZ; + else + wOrient = SB_VERT; - GetTextMetrics(dc, &lpTextMetric); - ::ReleaseDC(hWnd, dc); + HWND hWnd = GetHwnd(); + wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") ); - return lpTextMetric.tmHeight; + return GetScrollPosition(hWnd, wOrient); } -int wxWindow::GetCharWidth(void) const +// This now returns the whole range, not just the number +// of positions that we can scroll. +int wxWindowMSW::GetScrollRange(int orient) const { - TEXTMETRIC lpTextMetric; - HWND hWnd = (HWND) GetHWND(); - HDC dc = ::GetDC(hWnd); + 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 = GetScrollThumb(orient); + if ( pageSize > 1 ) + { + maxPos -= (pageSize - 1); + } + // October 10th: new range concept. + maxPos += pageSize; +#endif - GetTextMetrics(dc, &lpTextMetric); - ::ReleaseDC(hWnd, dc); + return maxPos; + } + else + return 0; +} - return lpTextMetric.tmAveCharWidth; +int wxWindowMSW::GetScrollThumb(int orient) const +{ + if ( orient == wxHORIZONTAL ) + return m_xThumbSize; + else + return m_yThumbSize; } -void wxWindow::GetTextExtent(const wxString& string, int *x, int *y, - int *descent, int *externalLeading, const wxFont *theFont, const bool) const +void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh) { - wxFont *fontToUse = (wxFont *)theFont; - if (!fontToUse) - fontToUse = (wxFont *) & m_windowFont; + HWND hWnd = GetHwnd(); + wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") ); - HWND hWnd = (HWND) GetHWND(); - HDC dc = ::GetDC(hWnd); + int dir = orient == wxHORIZONTAL ? SB_HORZ : SB_VERT; - HFONT fnt = 0; - HFONT was = 0; - if (fontToUse && fontToUse->Ok()) - { -// fontToUse->UseResource(); - -// fontToUse->RealizeResource(); - if ((fnt=(HFONT) fontToUse->GetResourceHandle())) - was = SelectObject(dc,fnt) ; - } +#if defined(__WIN95__) + SCROLLINFO info; + info.cbSize = sizeof(SCROLLINFO); + 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__ +} - SIZE sizeRect; - TEXTMETRIC tm; - GetTextExtentPoint(dc, (const char *)string, (int)string.Length(), &sizeRect); - GetTextMetrics(dc, &tm); +// 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; - if (fontToUse && fnt && was) - SelectObject(dc,was) ; + int range1 = oldRange; - ReleaseDC(hWnd, dc); + // Try to adjust the range to cope with page size > 1 + // - a Windows API quirk + int pageSize = thumbVisible; + if ( pageSize > 1 && range > 0) + { + range1 += (pageSize - 1); + } - *x = sizeRect.cx; - *y = sizeRect.cy; - if (descent) *descent = tm.tmDescent; - if (externalLeading) *externalLeading = tm.tmExternalLeading; + SCROLLINFO info; + int dir; -// if (fontToUse) -// fontToUse->ReleaseResource(); -} + if ( orient == wxHORIZONTAL ) { + dir = SB_HORZ; + } else { + dir = SB_VERT; + } -#if WXWIN_COMPATIBILITY -void wxWindow::GetTextExtent(const wxString& string, float *x, float *y, - float *descent, - float *externalLeading, - const wxFont *theFont, const bool use16) const - { - int x1, y1, descent1, externalLeading1; - GetTextExtent(string, &x1, &y1, &descent1, &externalLeading1, theFont, use16); - *x = x1; *y = y1; - if ( descent ) - *descent = descent1; - if ( externalLeading ) - *externalLeading = externalLeading1; - } + info.cbSize = sizeof(SCROLLINFO); + info.nPage = pageSize; // Have to set this, or scrollbar goes awry + info.nMin = 0; + info.nMax = range1; + info.nPos = pos; + info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; + + 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, FALSE); + ::SetScrollPos(hWnd, wOrient, pos, refresh); + } #endif + if ( orient == wxHORIZONTAL ) { + m_xThumbSize = thumbVisible; + } else { + m_yThumbSize = thumbVisible; + } +} -void wxWindow::Refresh(const bool eraseBack, const wxRectangle *rect) +void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect) { - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - { - if (rect) + RECT rect; + RECT *pr; + if ( prect ) { - RECT mswRect; - mswRect.left = rect->x; - mswRect.top = rect->y; - mswRect.right = rect->x + rect->width; - mswRect.bottom = rect->y + rect->height; - - ::InvalidateRect(hWnd, &mswRect, eraseBack); + rect.left = prect->x; + rect.top = prect->y; + rect.right = prect->x + prect->width; + rect.bottom = prect->y + prect->height; + pr = ▭ } else - ::InvalidateRect(hWnd, NULL, eraseBack); - } -} + { + pr = NULL; + } -// TODO: Are these really necessary now? -/* -WXHDC wxWindow::GetHDC(void) const -{ - wxWindow *nonConst = (wxWindow *)this; - if (m_paintHDC) - return(m_paintHDC) ; - nonConst->m_tempHDC = (WXHDC) ::GetDC((HWND) GetHWND()) ; - return(m_tempHDC) ; + ::ScrollWindow(GetHwnd(), dx, dy, pr, pr); } -void wxWindow::ReleaseHDC(void) +static bool ScrollVertically(HWND hwnd, int kind, int count) { - // We're within an OnPaint: it'll be released. - if (m_paintHDC) - return ; + int posStart = GetScrollPosition(hwnd, SB_VERT); - ::ReleaseDC((HWND) GetHWND(),(HDC) m_tempHDC) ; -} -*/ + int pos = posStart; + for ( int n = 0; n < count; n++ ) + { + ::SendMessage(hwnd, WM_VSCROLL, kind, 0); -// Hook for new window just as it's being created, -// when the window isn't yet associated with the handle -wxWindow *wxWndHook = NULL; + int posNew = GetScrollPosition(hwnd, SB_VERT); + if ( posNew == pos ) + { + // don't bother to continue, we're already at top/bottom + break; + } -/* -#if HAVE_SOCKET -// DDE Interface Handler -extern "C" { - long ddeWindowProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam); - void __ddeUnblock(HWND hWnd, WPARAM wParam); -}; -#endif -*/ - -// Main Windows 3 window proc -LRESULT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - wxWindow *wnd = wxFindWinFromHandle((WXHWND) hWnd); - - if (!wnd && wxWndHook) - { - wxAssociateWinWithHandle(hWnd, wxWndHook); - wnd = wxWndHook; - wxWndHook = NULL; - wnd->m_hWnd = (WXHWND) hWnd; - } -#if (DEBUG > 1) - wxDebugMsg("hWnd = %d, m_hWnd = %d, msg = %d\n", hWnd, m_hWnd, message); -#endif - // Stop right here if we don't have a valid handle - // in our wxWnd object. - if (wnd && !wnd->m_hWnd) { -// wxDebugMsg("Warning: could not find a valid handle, wx_win.cc/wxWndProc.\n"); - wnd->m_hWnd = (WXHWND) hWnd; - long res = wnd->MSWDefWindowProc(message, wParam, lParam ); - wnd->m_hWnd = 0; - return res; - } - - if (wnd) { - wnd->m_lastMsg = message; - wnd->m_lastWParam = wParam; - wnd->m_lastLParam = lParam; -/* Don't know why this was here - if (message == WM_SETFONT) - return 0; - else if (message == WM_INITDIALOG) - return TRUE; -*/ - } - if (wnd) - return wnd->MSWWindowProc(message, wParam, lParam); - else - return DefWindowProc( hWnd, message, wParam, lParam ); -} - -// Should probably have a test for 'genuine' NT -#if defined(__WIN32__) -#define DIMENSION_TYPE short -#else -#define DIMENSION_TYPE int -#endif + pos = posNew; + } -// Main Windows 3 window proc -long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) + return pos != posStart; +} + +bool wxWindowMSW::ScrollLines(int lines) { -#if 0 - switch (message) - { - case WM_INITDIALOG: - case WM_ACTIVATE: - case WM_SETFOCUS: - case WM_KILLFOCUS: - case WM_CREATE: - case WM_PAINT: - case WM_QUERYDRAGICON: - case WM_SIZE: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_RBUTTONDBLCLK: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - case WM_MBUTTONDBLCLK: - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_LBUTTONDBLCLK: - case WM_MOUSEMOVE: -// case WM_DESTROY: - case WM_COMMAND: - case WM_NOTIFY: - case WM_MENUSELECT: - case WM_INITMENUPOPUP: - case WM_DRAWITEM: - case WM_MEASUREITEM: - case WM_KEYDOWN: - case WM_KEYUP: - case WM_CHAR: // Always an ASCII character - case WM_HSCROLL: - case WM_VSCROLL: - case WM_CTLCOLORBTN: - case WM_CTLCOLORDLG: - case WM_CTLCOLORLISTBOX: - case WM_CTLCOLORMSGBOX: - case WM_CTLCOLORSCROLLBAR: - case WM_CTLCOLORSTATIC: - case WM_CTLCOLOREDIT: - case WM_SYSCOLORCHANGE: - case WM_ERASEBKGND: - case WM_MDIACTIVATE: - case WM_DROPFILES: - case WM_QUERYENDSESSION: -// case WM_CLOSE: - case WM_GETMINMAXINFO: - return MSWDefWindowProc(message, wParam, lParam ); + bool down = lines > 0; + + return ScrollVertically(GetHwnd(), + down ? SB_LINEDOWN : SB_LINEUP, + down ? lines : -lines); +} + +bool wxWindowMSW::ScrollPages(int pages) +{ + bool down = pages > 0; + + return ScrollVertically(GetHwnd(), + down ? SB_PAGEDOWN : SB_PAGEUP, + down ? pages : -pages); +} + +// --------------------------------------------------------------------------- +// subclassing +// --------------------------------------------------------------------------- + +void wxWindowMSW::SubclassWin(WXHWND hWnd) +{ + wxASSERT_MSG( !m_oldWndProc, wxT("subclassing window twice?") ); + + HWND hwnd = (HWND)hWnd; + wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in SubclassWin") ); + + wxAssociateWinWithHandle(hwnd, this); + + m_oldWndProc = (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC); + + // we don't need to subclass the window of our own class (in the Windows + // sense of the word) + if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) ) + { + ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) wxWndProc); } -#endif + else + { + // don't bother restoring it neither + m_oldWndProc = NULL; + } +} + +void wxWindowMSW::UnsubclassWin() +{ + wxRemoveHandleAssociation(this); + // Restore old Window proc + HWND hwnd = GetHwnd(); + if ( hwnd ) + { + m_hWnd = 0; - HWND hWnd = (HWND)m_hWnd; + wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") ); - switch (message) - { -/* - case WM_SETFONT: + if ( m_oldWndProc ) { - return 0; + if ( !wxCheckWindowWndProc((WXHWND)hwnd, m_oldWndProc) ) + { + ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) m_oldWndProc); + } + + m_oldWndProc = NULL; } -*/ - case WM_ACTIVATE: - { -#ifdef __WIN32__ - WORD state = LOWORD(wParam); - WORD minimized = HIWORD(wParam); - HWND hwnd = (HWND)lParam; -#else - WORD state = (WORD)wParam; - WORD minimized = LOWORD(lParam); - HWND hwnd = (HWND)HIWORD(lParam); + } +} + +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() ) + { + static wxChar buffer[512]; + WNDCLASS cls; + + ::GetClassName((HWND)hWnd, buffer, 512); + ::GetClassInfo(wxGetInstance(), buffer, &cls); + return wndProc == (WXFARPROC)cls.lpfnWndProc; + } + else #endif - MSWOnActivate(state, (minimized != 0), (WXHWND) hwnd); - return 0; - break; - } - case WM_SETFOCUS: - { - HWND hwnd = (HWND)wParam; -// return OnSetFocus(hwnd); + { + return wndProc == (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC); + } +} - if (MSWOnSetFocus((WXHWND) hwnd)) - return 0; - else return MSWDefWindowProc(message, wParam, lParam ); - break; - } - case WM_KILLFOCUS: - { - HWND hwnd = (HWND)lParam; -// return OnKillFocus(hwnd); - if (MSWOnKillFocus((WXHWND) hwnd)) - return 0; - else - return MSWDefWindowProc(message, wParam, lParam ); - break; - } - case WM_CREATE: - { - MSWOnCreate((WXLPCREATESTRUCT) (LPCREATESTRUCT)lParam); - return 0; - break; - } - case WM_SHOWWINDOW: - { - MSWOnShow((wParam != 0), (int) lParam); - break; - } - case WM_PAINT: - { - if (MSWOnPaint()) - return 0; - else return MSWDefWindowProc(message, wParam, lParam ); - break; - } - case WM_QUERYDRAGICON: - { - HICON hIcon = 0; - if ((hIcon = (HICON) MSWOnQueryDragIcon())) - return (long)hIcon; - else return MSWDefWindowProc(message, wParam, lParam ); - break; - } +// ---------------------------------------------------------------------------- +// Style handling +// ---------------------------------------------------------------------------- - case WM_SIZE: - { - int width = LOWORD(lParam); - int height = HIWORD(lParam); - MSWOnSize(width, height, wParam); - break; - } +void wxWindowMSW::SetWindowStyleFlag(long flags) +{ + long flagsOld = GetWindowStyleFlag(); + if ( flags == flagsOld ) + return; - case WM_WINDOWPOSCHANGING: - { - WINDOWPOS *pos = (WINDOWPOS *)lParam; - MSWOnWindowPosChanging((void *)pos); - break; - } + // update the internal variable + wxWindowBase::SetWindowStyleFlag(flags); - case WM_RBUTTONDOWN: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnRButtonDown(x, y, wParam); - break; - } - case WM_RBUTTONUP: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnRButtonUp(x, y, wParam); - break; - } - case WM_RBUTTONDBLCLK: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnRButtonDClick(x, y, wParam); - break; - } - case WM_MBUTTONDOWN: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnMButtonDown(x, y, wParam); - break; - } - case WM_MBUTTONUP: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnMButtonUp(x, y, wParam); - break; - } - case WM_MBUTTONDBLCLK: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnMButtonDClick(x, y, wParam); - break; - } - case WM_LBUTTONDOWN: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnLButtonDown(x, y, wParam); - break; - } - case WM_LBUTTONUP: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnLButtonUp(x, y, wParam); - break; - } - case WM_LBUTTONDBLCLK: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnLButtonDClick(x, y, wParam); - break; - } - case WM_MOUSEMOVE: - { - int x = (DIMENSION_TYPE) LOWORD(lParam); - int y = (DIMENSION_TYPE) HIWORD(lParam); - MSWOnMouseMove(x, y, wParam); - break; - } - case MM_JOY1BUTTONDOWN: - { - int x = LOWORD(lParam); - int y = HIWORD(lParam); - MSWOnJoyDown(wxJOYSTICK1, x, y, wParam); - break; - } - case MM_JOY2BUTTONDOWN: - { - int x = LOWORD(lParam); - int y = HIWORD(lParam); - MSWOnJoyDown(wxJOYSTICK2, x, y, wParam); - break; - } - case MM_JOY1BUTTONUP: - { - int x = LOWORD(lParam); - int y = HIWORD(lParam); - MSWOnJoyUp(wxJOYSTICK1, x, y, wParam); - break; - } - case MM_JOY2BUTTONUP: - { - int x = LOWORD(lParam); - int y = HIWORD(lParam); - MSWOnJoyUp(wxJOYSTICK2, x, y, wParam); - break; - } - case MM_JOY1MOVE: - { - int x = LOWORD(lParam); - int y = HIWORD(lParam); - MSWOnJoyMove(wxJOYSTICK1, x, y, wParam); - break; - } - case MM_JOY2MOVE: - { - int x = LOWORD(lParam); - int y = HIWORD(lParam); - MSWOnJoyMove(wxJOYSTICK2, x, y, wParam); - break; - } - case MM_JOY1ZMOVE: - { - int z = LOWORD(lParam); - MSWOnJoyZMove(wxJOYSTICK1, z, wParam); - break; - } - case MM_JOY2ZMOVE: - { - int z = LOWORD(lParam); - MSWOnJoyZMove(wxJOYSTICK2, z, wParam); - break; - } - case WM_DESTROY: + // now update the Windows style as well if needed - and if the window had + // been already created + if ( !GetHwnd() ) + return; + + WXDWORD exstyle, exstyleOld; + long style = MSWGetStyle(flags, &exstyle), + styleOld = MSWGetStyle(flagsOld, &exstyleOld); + + if ( style != styleOld ) + { + // some flags (e.g. WS_VISIBLE or WS_DISABLED) should not be changed by + // this function so instead of simply setting the style to the new + // value we clear the bits which were set in styleOld but are set in + // the new one and set the ones which were not set before + long styleReal = ::GetWindowLong(GetHwnd(), GWL_STYLE); + styleReal &= ~styleOld; + styleReal |= style; + + ::SetWindowLong(GetHwnd(), GWL_STYLE, styleReal); + } + + // and the extended style + if ( exstyle != exstyleOld ) + { + long exstyleReal = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE); + exstyleReal &= ~exstyleOld; + exstyleReal |= exstyle; + + ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, exstyleReal); + + // we must call SetWindowPos() to flash the cached extended style and + // also to make the change to wxSTAY_ON_TOP style take effect: just + // setting the style simply doesn't work + if ( !::SetWindowPos(GetHwnd(), + exstyleReal & WS_EX_TOPMOST ? HWND_TOPMOST + : HWND_NOTOPMOST, + 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE) ) { - if (MSWOnDestroy()) - return 0; - else return MSWDefWindowProc(message, wParam, lParam ); - break; + wxLogLastError(_T("SetWindowPos")); } - case WM_SYSCOMMAND: + } +} + +WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const +{ + // translate the style + WXDWORD style = WS_CHILD; + + if ( flags & wxCLIP_CHILDREN ) + style |= WS_CLIPCHILDREN; + + if ( flags & wxCLIP_SIBLINGS ) + style |= WS_CLIPSIBLINGS; + + wxBorder border = (wxBorder)(flags & wxBORDER_MASK); + if ( border != wxBORDER_NONE && border != wxBORDER_DEFAULT ) + style |= WS_BORDER; + + // now deal with ext style if the caller wants it + if ( exstyle ) + { + *exstyle = 0; + + if ( flags & wxTRANSPARENT_WINDOW ) + *exstyle |= WS_EX_TRANSPARENT; + + switch ( flags & wxBORDER_MASK ) { - return MSWOnSysCommand(wParam, lParam); - break; + default: + wxFAIL_MSG( _T("unknown border style") ); + // fall through + + case wxBORDER_NONE: + case wxBORDER_SIMPLE: + case wxBORDER_DEFAULT: + break; + + case wxBORDER_STATIC: + *exstyle |= WS_EX_STATICEDGE; + break; + + case wxBORDER_RAISED: + *exstyle |= WS_EX_WINDOWEDGE; + break; + + case wxBORDER_SUNKEN: + *exstyle |= WS_EX_CLIENTEDGE; + break; + + case wxBORDER_DOUBLE: + *exstyle |= WS_EX_DLGMODALFRAME; + break; } - case WM_COMMAND: - { -#ifdef __WIN32__ - WORD id = LOWORD(wParam); - HWND hwnd = (HWND)lParam; - WORD cmd = HIWORD(wParam); -#else - WORD id = (WORD)wParam; - HWND hwnd = (HWND)LOWORD(lParam) ; - WORD cmd = HIWORD(lParam); -#endif - if (!MSWOnCommand(id, cmd, (WXHWND) hwnd)) - return MSWDefWindowProc(message, wParam, lParam ); - break; - } + } + + 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__) - case WM_NOTIFY: - { - if (!MSWOnNotify(wParam, lParam)) - return MSWDefWindowProc(message, wParam, lParam ); - break; - } + 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 - case WM_MENUSELECT: + } + + 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() +{ + if ( GetParent() ) + SetBackgroundColour(GetParent()->GetBackgroundColour()); +} + +bool wxWindowMSW::IsMouseInWindow() const +{ + // get the mouse position + POINT pt; + ::GetCursorPos(&pt); + + // find the window which currently has the cursor and go up the window + // chain until we find this window - or exhaust it + HWND hwnd = ::WindowFromPoint(pt); + while ( hwnd && (hwnd != GetHwnd()) ) + hwnd = ::GetParent(hwnd); + + return hwnd != NULL; +} + +void wxWindowMSW::OnIdle(wxIdleEvent& WXUNUSED(event)) +{ + // Check if we need to send a LEAVE event + if ( m_mouseInWindow ) + { + // note that we should generate the leave event whether the window has + // or doesn't have mouse capture + if ( !IsMouseInWindow() ) { -#ifdef __WIN32__ - WORD flags = HIWORD(wParam); - HMENU sysmenu = (HMENU)lParam; -#else - WORD flags = LOWORD(lParam); - HMENU sysmenu = (HMENU)HIWORD(lParam); + // Generate a LEAVE event + m_mouseInWindow = FALSE; + + // Unfortunately the mouse button and keyboard state may have + // changed by the time the OnIdle function is called, so 'state' + // may be meaningless. + 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); + } + } + + UpdateWindowUI(); +} + +// Set this window to be the child of 'parent'. +bool wxWindowMSW::Reparent(wxWindowBase *parent) +{ + if ( !wxWindowBase::Reparent(parent) ) + return FALSE; + + HWND hWndChild = GetHwnd(); + HWND hWndParent = GetParent() ? GetWinHwnd(GetParent()) : (HWND)0; + + ::SetParent(hWndChild, hWndParent); + + return TRUE; +} + +void wxWindowMSW::Clear() +{ + wxClientDC dc((wxWindow *)this); + wxBrush brush(GetBackgroundColour(), wxSOLID); + dc.SetBackground(brush); + dc.Clear(); +} + +static inline void SendSetRedraw(HWND hwnd, bool on) +{ +#ifndef __WXMICROWIN__ + ::SendMessage(hwnd, WM_SETREDRAW, (WPARAM)on, 0); #endif - MSWOnMenuHighlight((WORD)wParam, flags, (WXHMENU) sysmenu); - break; - } - case WM_INITMENUPOPUP: +} + +void wxWindowMSW::Freeze() +{ + SendSetRedraw(GetHwnd(), FALSE); +} + +void wxWindowMSW::Thaw() +{ + SendSetRedraw(GetHwnd(), TRUE); + + // we need to refresh everything or otherwise he invalidated area is not + // repainted + Refresh(); +} + +void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect) +{ + HWND hWnd = GetHwnd(); + if ( hWnd ) + { + if ( rect ) { - MSWOnInitMenuPopup((WXHMENU) (HMENU)wParam, (int)LOWORD(lParam), (HIWORD(lParam) != 0)); - break; + RECT mswRect; + mswRect.left = rect->x; + mswRect.top = rect->y; + mswRect.right = rect->x + rect->width; + mswRect.bottom = rect->y + rect->height; + + ::InvalidateRect(hWnd, &mswRect, eraseBack); } - case WM_DRAWITEM: + else + ::InvalidateRect(hWnd, NULL, eraseBack); + } +} + +void wxWindowMSW::Update() +{ + if ( !::UpdateWindow(GetHwnd()) ) + { + wxLogLastError(_T("UpdateWindow")); + } + +#if defined(__WIN32__) && !defined(__WXMICROWIN__) + // just calling UpdateWindow() is not enough, what we did in our WM_PAINT + // handler needs to be really drawn right now + (void)::GdiFlush(); +#endif // __WIN32__ +} + +// --------------------------------------------------------------------------- +// drag and drop +// --------------------------------------------------------------------------- + +#if wxUSE_DRAG_AND_DROP + +void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget) +{ + if ( m_dropTarget != 0 ) { + m_dropTarget->Revoke(m_hWnd); + delete m_dropTarget; + } + + m_dropTarget = 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) +{ + HWND hWnd = GetHwnd(); + if ( hWnd ) + ::DragAcceptFiles(hWnd, (BOOL)accept); +} + +// ---------------------------------------------------------------------------- +// tooltips +// ---------------------------------------------------------------------------- + +#if wxUSE_TOOLTIPS + +void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip) +{ + wxWindowBase::DoSetToolTip(tooltip); + + if ( m_tooltip ) + m_tooltip->SetWindow(this); +} + +#endif // wxUSE_TOOLTIPS + +// --------------------------------------------------------------------------- +// moving and resizing +// --------------------------------------------------------------------------- + +// Get total size +void wxWindowMSW::DoGetSize(int *x, int *y) const +{ + RECT rect = wxGetWindowRect(GetHwnd()); + + if ( x ) + *x = rect.right - rect.left; + if ( y ) + *y = rect.bottom - rect.top; +} + +// Get size *available for subwindows* i.e. excluding menu bar etc. +void wxWindowMSW::DoGetClientSize(int *x, int *y) const +{ + RECT rect = wxGetClientRect(GetHwnd()); + + if ( x ) + *x = rect.right; + if ( y ) + *y = rect.bottom; +} + +void wxWindowMSW::DoGetPosition(int *x, int *y) const +{ + RECT rect = wxGetWindowRect(GetHwnd()); + + POINT point; + point.x = rect.left; + point.y = rect.top; + + // we do the adjustments with respect to the parent only for the "real" + // children, not for the dialogs/frames + if ( !IsTopLevel() ) + { + HWND hParentWnd = 0; + wxWindow *parent = GetParent(); + if ( parent ) + hParentWnd = GetWinHwnd(parent); + + // Since we now have the absolute screen coords, if there's a parent we + // must subtract its top left corner + if ( hParentWnd ) { - return MSWOnDrawItem((int)wParam, (WXDRAWITEMSTRUCT *)lParam); - break; + ::ScreenToClient(hParentWnd, &point); } - case WM_MEASUREITEM: + + if ( parent ) { - return MSWOnMeasureItem((int)wParam, (WXMEASUREITEMSTRUCT *)lParam); - break; + // We may be faking the client origin. So a window that's really at (0, + // 30) may appear (to wxWin apps) to be at (0, 0). + wxPoint pt(parent->GetClientAreaOrigin()); + point.x -= pt.x; + point.y -= pt.y; } - case WM_KEYDOWN: + } + + if ( x ) + *x = point.x; + if ( y ) + *y = point.y; +} + +void wxWindowMSW::DoScreenToClient(int *x, int *y) const +{ + POINT pt; + if ( x ) + pt.x = *x; + if ( y ) + pt.y = *y; + + ::ScreenToClient(GetHwnd(), &pt); + + if ( x ) + *x = pt.x; + if ( y ) + *y = pt.y; +} + +void wxWindowMSW::DoClientToScreen(int *x, int *y) const +{ + POINT pt; + if ( x ) + pt.x = *x; + if ( y ) + pt.y = *y; + + ::ClientToScreen(GetHwnd(), &pt); + + if ( x ) + *x = pt.x; + if ( y ) + *y = pt.y; +} + +void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height) +{ + // TODO: is this consistent with other platforms? + // Still, negative width or height shouldn't be allowed + if (width < 0) + width = 0; + if (height < 0) + height = 0; + if ( !::MoveWindow(GetHwnd(), x, y, width, height, TRUE) ) + { + wxLogLastError(wxT("MoveWindow")); + } +} + +// set the size of the window: if the dimensions are positive, just use them, +// but if any of them is equal to -1, it means that we must find the value for +// it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in +// which case -1 is a valid value for x and y) +// +// If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate +// the width/height to best suit our contents, otherwise we reuse the current +// width/height +void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) +{ + // get the current size and position... + int currentX, currentY; + GetPosition(¤tX, ¤tY); + int currentW,currentH; + GetSize(¤tW, ¤tH); + + // ... and don't do anything (avoiding flicker) if it's already ok + if ( x == currentX && y == currentY && + width == currentW && height == currentH ) + { + return; + } + + if ( x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) + x = currentX; + if ( y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) + y = currentY; + + AdjustForParentClientOrigin(x, y, sizeFlags); + + wxSize size(-1, -1); + if ( width == -1 ) + { + if ( sizeFlags & wxSIZE_AUTO_WIDTH ) { -// return Default(); - - if (wParam == VK_SHIFT) - return Default(); - - else if (wParam == VK_CONTROL) - return Default(); - - // Avoid duplicate messages to OnChar - else if ((wParam != VK_ESCAPE) && (wParam != VK_SPACE) && (wParam != VK_RETURN) && (wParam != VK_BACK) && (wParam != VK_TAB)) - { - MSWOnChar((WORD)wParam, lParam); - if (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE) - return Default(); - } - else - return Default(); - break; + size = DoGetBestSize(); + width = size.x; } - case WM_KEYUP: + else { -/* - if (wParam == VK_SHIFT) - wxShiftDown = FALSE; - else if (wParam == VK_CONTROL) - wxControlDown = FALSE; -*/ - break; + // just take the current one + width = currentW; } - case WM_CHAR: // Always an ASCII character + } + + if ( height == -1 ) + { + if ( sizeFlags & wxSIZE_AUTO_HEIGHT ) { - MSWOnChar((WORD)wParam, lParam, TRUE); - break; + if ( size.x == -1 ) + { + size = DoGetBestSize(); + } + //else: already called DoGetBestSize() above + + height = size.y; } - case WM_HSCROLL: + else { -#ifdef __WIN32__ - WORD code = LOWORD(wParam); - WORD pos = HIWORD(wParam); - HWND control = (HWND)lParam; -#else - WORD code = (WORD)wParam; - WORD pos = LOWORD(lParam); - HWND control = (HWND)HIWORD(lParam); -#endif - MSWOnHScroll(code, pos, (WXHWND) control); - break; + // just take the current one + height = currentH; } - case WM_VSCROLL: + } + + DoMoveWindow(x, y, width, height); +} + +void wxWindowMSW::DoSetClientSize(int width, int height) +{ + // setting the client size is less obvious than it it could have been + // because in the result of changing the total size the window scrollbar + // may [dis]appear and/or its menubar may [un]wrap and so the client size + // will not be correct as the difference between the total and client size + // changes - so we keep changing it until we get it right + // + // normally this loop shouldn't take more than 3 iterations (usually 1 but + // if scrollbars [dis]appear as the result of the first call, then 2 and it + // may become 3 if the window had 0 size originally and so we didn't + // calculate the scrollbar correction correctly during the first iteration) + // but just to be on the safe side we check for it instead of making it an + // "infinite" loop (i.e. leaving break inside as the only way to get out) + for ( int i = 0; i < 4; i++ ) + { + RECT rectClient; + ::GetClientRect(GetHwnd(), &rectClient); + + // if the size is already ok, stop here (rectClient.left = top = 0) + if ( (rectClient.right == width || width == -1) && + (rectClient.bottom == height || height == -1) ) { -#ifdef __WIN32__ - WORD code = LOWORD(wParam); - WORD pos = HIWORD(wParam); - HWND control = (HWND)lParam; -#else - WORD code = (WORD)wParam; - WORD pos = LOWORD(lParam); - HWND control = (HWND)HIWORD(lParam); -#endif - MSWOnVScroll(code, pos, (WXHWND) control); break; } -#ifdef __WIN32__ - case WM_CTLCOLORBTN: - { - int nCtlColor = CTLCOLOR_BTN; - HWND control = (HWND)lParam; - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam); - break; - } - case WM_CTLCOLORDLG: - { - int nCtlColor = CTLCOLOR_DLG; - HWND control = (HWND)lParam; - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam);\ - break; - } - case WM_CTLCOLORLISTBOX: - { - int nCtlColor = CTLCOLOR_LISTBOX; - HWND control = (HWND)lParam; - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam); - break; - } - case WM_CTLCOLORMSGBOX: - { - int nCtlColor = CTLCOLOR_MSGBOX; - HWND control = (HWND)lParam; - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam); - break; - } - case WM_CTLCOLORSCROLLBAR: - { - int nCtlColor = CTLCOLOR_SCROLLBAR; - HWND control = (HWND)lParam; - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam); - break; - } - case WM_CTLCOLORSTATIC: - { - int nCtlColor = CTLCOLOR_STATIC; - HWND control = (HWND)lParam; - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam); - break; - } - case WM_CTLCOLOREDIT: - { - int nCtlColor = CTLCOLOR_EDIT; - HWND control = (HWND)lParam; - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam); - break; - } -#else - case WM_CTLCOLOR: - { - HWND control = (HWND)LOWORD(lParam); - int nCtlColor = (int)HIWORD(lParam); - HDC pDC = (HDC)wParam; - return (DWORD)MSWOnCtlColor((WXHDC) pDC, (WXHWND) control, nCtlColor, - message, wParam, lParam); - break; - } -#endif - case WM_SYSCOLORCHANGE: - { - // Return value of 0 means, we processed it. - if (MSWOnColorChange((WXHWND) hWnd, message, wParam, lParam) == 0) - return 0; - else - return MSWDefWindowProc(message, wParam, lParam ); - break; - } - case WM_ERASEBKGND: + + int widthClient = width, + heightClient = height; + + // Find the difference between the entire window (title bar and all) + // and the client area; add this to the new client size to move the + // window + RECT rectWin; + ::GetWindowRect(GetHwnd(), &rectWin); + + widthClient += rectWin.right - rectWin.left - rectClient.right; + heightClient += rectWin.bottom - rectWin.top - rectClient.bottom; + + POINT point; + point.x = rectWin.left; + point.y = rectWin.top; + + // MoveWindow positions the child windows relative to the parent, so + // adjust if necessary + if ( !IsTopLevel() ) { - // Prevents flicker when dragging - if (IsIconic(hWnd)) return 1; - - // EXPERIMENTAL -// return 1; - if (!MSWOnEraseBkgnd((WXHDC) (HDC)wParam)) - return 0; // Default(); MSWDefWindowProc(message, wParam, lParam ); - else return 1; - break; + wxWindow *parent = GetParent(); + if ( parent ) + { + ::ScreenToClient(GetHwndOf(parent), &point); + } } - case WM_MDIACTIVATE: - { -#ifdef __WIN32__ - HWND hWndActivate = GET_WM_MDIACTIVATE_HWNDACTIVATE(wParam,lParam); - HWND hWndDeactivate = GET_WM_MDIACTIVATE_HWNDDEACT(wParam,lParam); - BOOL activate = GET_WM_MDIACTIVATE_FACTIVATE(hWnd,wParam,lParam); - return MSWOnMDIActivate((long) activate, (WXHWND) hWndActivate, (WXHWND) hWndDeactivate); + + DoMoveWindow(point.x, point.y, widthClient, heightClient); + } +} + +// For implementation purposes - sometimes decorations make the client area +// smaller +wxPoint wxWindowMSW::GetClientAreaOrigin() const +{ + return wxPoint(0, 0); +} + +// --------------------------------------------------------------------------- +// text metrics +// --------------------------------------------------------------------------- + +int wxWindowMSW::GetCharHeight() const +{ + return wxGetTextMetrics(this).tmHeight; +} + +int wxWindowMSW::GetCharWidth() const +{ + // +1 is needed because Windows apparently adds it when calculating the + // dialog units size in pixels +#if wxDIALOG_UNIT_COMPATIBILITY + return wxGetTextMetrics(this).tmAveCharWidth; #else - return MSWOnMDIActivate((BOOL)wParam, (HWND)LOWORD(lParam), - (HWND)HIWORD(lParam)); + return wxGetTextMetrics(this).tmAveCharWidth + 1; #endif - } - case WM_DROPFILES: - { - MSWOnDropFiles(wParam); - break; - } - case WM_INITDIALOG: - { - return 0; // MSWOnInitDialog((WXHWND)(HWND)wParam); - break; - } - case WM_QUERYENDSESSION: +} + +void wxWindowMSW::GetTextExtent(const wxString& string, + int *x, int *y, + int *descent, int *externalLeading, + const wxFont *theFont) const +{ + const wxFont *fontToUse = theFont; + if ( !fontToUse ) + fontToUse = &m_font; + + HWND hWnd = GetHwnd(); + HDC dc = ::GetDC(hWnd); + + HFONT fnt = 0; + HFONT hfontOld = 0; + if ( fontToUse && fontToUse->Ok() ) + { + fnt = (HFONT)((wxFont *)fontToUse)->GetResourceHandle(); // const_cast + if ( fnt ) + hfontOld = (HFONT)SelectObject(dc,fnt); + } + + SIZE sizeRect; + TEXTMETRIC tm; + GetTextExtentPoint(dc, string, (int)string.Length(), &sizeRect); + GetTextMetrics(dc, &tm); + + if ( fontToUse && fnt && hfontOld ) + SelectObject(dc, hfontOld); + + ReleaseDC(hWnd, dc); + + if ( x ) + *x = sizeRect.cx; + if ( y ) + *y = sizeRect.cy; + if ( descent ) + *descent = tm.tmDescent; + if ( externalLeading ) + *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 +// --------------------------------------------------------------------------- + +#if wxUSE_MENUS_NATIVE + +// yield for WM_COMMAND events only, i.e. process all WM_COMMANDs in the queue +// immediately, without waiting for the next event loop iteration +// +// NB: this function should probably be made public later as it can almost +// surely replace wxYield() elsewhere as well +static void wxYieldForCommandsOnly() +{ + // peek all WM_COMMANDs (it will always return WM_QUIT too but we don't + // want to process it here) + MSG msg; + while ( ::PeekMessage(&msg, (HWND)0, WM_COMMAND, WM_COMMAND, PM_REMOVE) + && msg.message != WM_QUIT ) + { + wxTheApp->DoMessage((WXMSG *)&msg); + } +} + +bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y) +{ + menu->SetInvokingWindow(this); + menu->UpdateUI(); + + HWND hWnd = GetHwnd(); + HMENU hMenu = GetHmenuOf(menu); + POINT point; + point.x = x; + point.y = y; + ::ClientToScreen(hWnd, &point); + wxCurrentPopupMenu = menu; + ::TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, 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() + // + // note that even eliminating (ugly) wxCurrentPopupMenu global wouldn't + // help and we'd still need wxYieldForCommandsOnly() as the menu may be + // destroyed as soon as we return (it can be a local variable in the caller + // for example) and so we do need to process the event immediately + wxYieldForCommandsOnly(); + + wxCurrentPopupMenu = NULL; + + menu->SetInvokingWindow(NULL); + + return TRUE; +} + +#endif // wxUSE_MENUS_NATIVE + +// =========================================================================== +// pre/post message processing +// =========================================================================== + +long wxWindowMSW::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +{ + if ( m_oldWndProc ) + return ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam); + else + return ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam); +} + +bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) +{ + // wxUniversal implements tab traversal itself +#ifndef __WXUNIVERSAL__ + if ( m_hWnd != 0 && (GetWindowStyleFlag() & wxTAB_TRAVERSAL) ) + { + // intercept dialog navigation keys + MSG *msg = (MSG *)pMsg; + + // here we try to do all the job which ::IsDialogMessage() usually does + // internally +#if 1 + bool bProcess = TRUE; + if ( msg->message != WM_KEYDOWN ) + bProcess = FALSE; + + if ( bProcess && (HIWORD(msg->lParam) & KF_ALTDOWN) == KF_ALTDOWN ) + bProcess = FALSE; + + if ( bProcess ) { - // Same as WM_CLOSE, but inverted results. Thx Microsoft :-) - return MSWOnClose(); - break; + bool bCtrlDown = wxIsCtrlDown(); + bool bShiftDown = wxIsShiftDown(); + + // WM_GETDLGCODE: ask the control if it wants the key for itself, + // don't process it if it's the case (except for Ctrl-Tab/Enter + // combinations which are always processed) + LONG lDlgCode = 0; + if ( !bCtrlDown ) + { + lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0); + } + + bool bForward = TRUE, + bWindowChange = FALSE; + + switch ( msg->wParam ) + { + case VK_TAB: + // assume that nobody wants Shift-TAB for himself - if we + // don't do it there is no easy way for a control to grab + // TABs but still let Shift-TAB work as navugation key + if ( (lDlgCode & DLGC_WANTTAB) && !bShiftDown ) { + bProcess = FALSE; + } + else { + // Ctrl-Tab cycles thru notebook pages + bWindowChange = bCtrlDown; + bForward = !bShiftDown; + } + break; + + case VK_UP: + case VK_LEFT: + if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown ) + bProcess = FALSE; + else + bForward = FALSE; + break; + + case VK_DOWN: + case VK_RIGHT: + if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown ) + bProcess = FALSE; + break; + + case VK_RETURN: + { + if ( (lDlgCode & DLGC_WANTMESSAGE) && !bCtrlDown ) + { + // control wants to process Enter itself, don't + // call IsDialogMessage() which would interpret + // it + return FALSE; + } + else if ( lDlgCode & DLGC_BUTTON ) + { + // let IsDialogMessage() handle this for all + // buttons except the owner-drawn ones which it + // just seems to ignore + long style = ::GetWindowLong(msg->hwnd, GWL_STYLE); + if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW ) + { + // emulate the button click + wxWindow *btn = wxFindWinFromHandle((WXHWND)msg->hwnd); + if ( btn ) + btn->MSWCommand(BN_CLICKED, 0 /* unused */); + } + + bProcess = FALSE; + } + // FIXME: this should be handled by + // wxNavigationKeyEvent handler and not here!! + else + { +#if wxUSE_BUTTON + wxButton *btn = wxDynamicCast(GetDefaultItem(), + wxButton); + if ( btn && btn->IsEnabled() ) + { + // if we do have a default button, do press it + btn->MSWCommand(BN_CLICKED, 0 /* unused */); + + return TRUE; + } + else // no default button +#endif // wxUSE_BUTTON + { + // no special function for enter and don't even + // let IsDialogMessage() have it: it seems to + // do something really strange with it + return FALSE; + } + } + } + break; + + default: + bProcess = FALSE; + } + + if ( bProcess ) + { + wxNavigationKeyEvent event; + event.SetDirection(bForward); + event.SetWindowChange(bWindowChange); + event.SetEventObject(this); + + if ( GetEventHandler()->ProcessEvent(event) ) + { + return TRUE; + } + } } - case WM_CLOSE: +#else // 0 + // let ::IsDialogMessage() do almost everything and handle just the + // things it doesn't here: Ctrl-TAB for switching notebook pages + if ( msg->message == WM_KEYDOWN ) { - if (MSWOnClose()) - return 0L; - else - return 1L; - break; + // don't process system keys here + if ( !(HIWORD(msg->lParam) & KF_ALTDOWN) ) + { + if ( (msg->wParam == VK_TAB) && wxIsCtrlDown() ) + { + // find the first notebook parent and change its page + wxWindow *win = this; + wxNotebook *nbook = NULL; + while ( win && !nbook ) + { + nbook = wxDynamicCast(win, wxNotebook); + win = win->GetParent(); + } + + if ( nbook ) + { + bool forward = !wxIsShiftDown(); + + nbook->AdvanceSelection(forward); + } + } + } } +#endif // 1/0 - case WM_GETMINMAXINFO: + if ( ::IsDialogMessage(GetHwnd(), msg) ) { - MINMAXINFO *info = (MINMAXINFO *)lParam; - if (m_minSizeX != -1) - info->ptMinTrackSize.x = (int)m_minSizeX; - if (m_minSizeY != -1) - info->ptMinTrackSize.y = (int)m_minSizeY; - if (m_maxSizeX != -1) - info->ptMaxTrackSize.x = (int)m_maxSizeX; - if (m_maxSizeY != -1) - info->ptMaxTrackSize.y = (int)m_maxSizeY; - return MSWDefWindowProc(message, wParam, lParam ); - break; + // IsDialogMessage() did something... + return TRUE; } + } +#endif // __WXUNIVERSAL__ -/* -#if HAVE_SOCKET - case WM_TIMER: - { - __ddeUnblock(hWnd, wParam); - break; - } - - case ASYNC_SELECT_MESSAGE: - return ddeWindowProc(hWnd,message,wParam,lParam); -#endif -*/ - - default: - return MSWDefWindowProc(message, wParam, lParam ); +#if wxUSE_TOOLTIPS + if ( m_tooltip ) + { + // relay mouse move events to the tooltip control + MSG *msg = (MSG *)pMsg; + if ( msg->message == WM_MOUSEMOVE ) + m_tooltip->RelayEvent(pMsg); } - return 0; // Success: we processed this command. +#endif // wxUSE_TOOLTIPS + + return FALSE; } -// Dialog window proc -LONG APIENTRY _EXPORT - wxDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +bool wxWindowMSW::MSWTranslateMessage(WXMSG* pMsg) { - return 0; +#if wxUSE_ACCEL && !defined(__WXUNIVERSAL__) + return m_acceleratorTable.Translate(this, pMsg); +#else + (void) pMsg; + return FALSE; +#endif // wxUSE_ACCEL } -wxList *wxWinHandleList = NULL; -wxWindow *wxFindWinFromHandle(WXHWND hWnd) +bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* WXUNUSED(pMsg)) { - wxNode *node = wxWinHandleList->Find((long)hWnd); - if (!node) - return NULL; - return (wxWindow *)node->Data(); + // preprocess all messages by default + return TRUE; } -void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win) -{ - // adding NULL hWnd is (first) surely a result of an error and - // (secondly) breaks menu command processing - wxCHECK( hWnd != NULL ); +// --------------------------------------------------------------------------- +// message params unpackers (different for Win16 and Win32) +// --------------------------------------------------------------------------- - if ( !wxWinHandleList->Find((long)hWnd) ) - wxWinHandleList->Append((long)hWnd, win); +#ifdef __WIN32__ + +void wxWindowMSW::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam, + WORD *id, WXHWND *hwnd, WORD *cmd) +{ + *id = LOWORD(wParam); + *hwnd = (WXHWND)lParam; + *cmd = HIWORD(wParam); } -void wxRemoveHandleAssociation(wxWindow *win) +void wxWindowMSW::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam, + WXWORD *state, WXWORD *minimized, WXHWND *hwnd) { - wxWinHandleList->DeleteObject(win); + *state = LOWORD(wParam); + *minimized = HIWORD(wParam); + *hwnd = (WXHWND)lParam; } -// Default destroyer - override if you destroy it in some other way -// (e.g. with MDI child windows) -void wxWindow::MSWDestroyWindow(void) +void wxWindowMSW::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam, + WXWORD *code, WXWORD *pos, WXHWND *hwnd) { -#if 0 + *code = LOWORD(wParam); + *pos = HIWORD(wParam); + *hwnd = (WXHWND)lParam; +} -#if DEBUG > 1 - wxDebugMsg("wxWindow::MSWDestroyWindow %d\n", handle); -#endif - MSWDetachWindowMenu(); -// SetWindowLong(handle, 0, (long)0); - HWND oldHandle = handle; - handle = NULL; - - ::DestroyWindow(oldHandle); - - // Menu is destroyed explicitly by wxMDIChild::DestroyWindow, - // or when Windows HWND is deleted if MDI parent or - // SDI frame. -/* - if (m_hMenu) - { - ::DestroyMenu(m_hMenu); - m_hMenu = 0; - } - */ +void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam, + WXWORD *nCtlColor, WXHDC *hdc, WXHWND *hwnd) +{ +#ifndef __WXMICROWIN__ + *nCtlColor = CTLCOLOR_BTN; + *hwnd = (WXHWND)lParam; + *hdc = (WXHDC)wParam; #endif } -void wxWindow::MSWCreate(const int id, wxWindow *parent, const char *wclass, wxWindow *wx_win, const char *title, - const int x, const int y, const int width, const int height, - const WXDWORD style, const char *dialog_template, const WXDWORD extendedStyle) -{ - bool is_dialog = (dialog_template != NULL); - int x1 = CW_USEDEFAULT; - int y1 = 0; - int width1 = CW_USEDEFAULT; - int height1 = 100; - - // Find parent's size, if it exists, to set up a possible default - // panel size the size of the parent window - RECT parent_rect; - if (parent) - { - // Was GetWindowRect: JACS 5/5/95 - ::GetClientRect((HWND) parent->GetHWND(), &parent_rect); - - width1 = parent_rect.right - parent_rect.left; - height1 = parent_rect.bottom - parent_rect.top; - } - - if (x > -1) x1 = x; - if (y > -1) y1 = y; - if (width > -1) width1 = width; - if (height > -1) height1 = height; - - HWND hParent = NULL; - if (parent) - hParent = (HWND) parent->GetHWND(); - - wxWndHook = this; - - if (is_dialog) - { - // MakeProcInstance doesn't seem to be needed in C7. Is it needed for - // other compilers??? - // VZ: it's always needed for Win16 and never for Win32 -#ifdef __WIN32__ - m_hWnd = (WXHWND) ::CreateDialog(wxGetInstance(), dialog_template, hParent, - (DLGPROC)wxDlgProc); -#else - DLGPROC dlgproc = (DLGPROC)MakeProcInstance((DLGPROC)wxWndProc, wxGetInstance()); +void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, + WXWORD *item, WXWORD *flags, WXHMENU *hmenu) +{ + *item = (WXWORD)wParam; + *flags = HIWORD(wParam); + *hmenu = (WXHMENU)lParam; +} - m_hWnd = (WXHWND) ::CreateDialog(wxGetInstance(), dialog_template, hParent, - (DLGPROC)dlgproc); -#endif +#else // Win16 - if (m_hWnd == 0) - MessageBox(NULL, "Can't find dummy dialog template!\nCheck resource include path for finding wx.rc.", - "wxWindows Error", MB_ICONEXCLAMATION | MB_OK); - else MoveWindow((HWND) m_hWnd, x1, y1, width1, height1, FALSE); - } - else - { - int controlId = 0; - if (style & WS_CHILD) - controlId = id; - if (!title) - title = ""; - - m_hWnd = (WXHWND) CreateWindowEx(extendedStyle, wclass, - title, - style, - x1, y1, - width1, height1, -// hParent, NULL, wxGetInstance(), - hParent, (HMENU)controlId, wxGetInstance(), - NULL); - - if (m_hWnd == 0) - { - char buf[300]; - sprintf(buf, "Can't create window of class %s! Weird.\nPossible Windows 3.x compatibility problem?", - wclass); - wxFatalError(buf, - "Fatal wxWindows Error"); - } - } - wxWndHook = NULL; - wxWinHandleList->Append((long)m_hWnd, this); - -#if DEBUG > 1 - wxDebugMsg("wxWindow::MSWCreate %d\n", m_hWnd); -#endif +void wxWindowMSW::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam, + WXWORD *id, WXHWND *hwnd, WXWORD *cmd) +{ + *id = (WXWORD)wParam; + *hwnd = (WXHWND)LOWORD(lParam); + *cmd = HIWORD(lParam); } -void wxWindow::MSWOnCreate(WXLPCREATESTRUCT WXUNUSED(cs)) +void wxWindowMSW::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam, + WXWORD *state, WXWORD *minimized, WXHWND *hwnd) { + *state = (WXWORD)wParam; + *minimized = LOWORD(lParam); + *hwnd = (WXHWND)HIWORD(lParam); } -bool wxWindow::MSWOnClose(void) +void wxWindowMSW::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam, + WXWORD *code, WXWORD *pos, WXHWND *hwnd) { -#if DEBUG > 1 - wxDebugMsg("wxWindow::MSWOnClose %d\n", handle); -#endif - return FALSE; + *code = (WXWORD)wParam; + *pos = LOWORD(lParam); + *hwnd = (WXHWND)HIWORD(lParam); } -bool wxWindow::MSWOnDestroy(void) +void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam, + WXWORD *nCtlColor, WXHDC *hdc, WXHWND *hwnd) { -#if DEBUG > 1 - wxDebugMsg("wxWindow::MSWOnDestroy %d\n", handle); -#endif - // delete our drop target if we've got one - #if USE_DRAG_AND_DROP - if ( m_pDropTarget != NULL ) { - m_pDropTarget->Revoke(m_hWnd); - - delete m_pDropTarget; - m_pDropTarget = NULL; - } - #endif - - return TRUE; + *hwnd = (WXHWND)LOWORD(lParam); + *nCtlColor = (int)HIWORD(lParam); + *hdc = (WXHDC)wParam; } -// Deal with child commands from buttons etc. - -bool wxWindow::MSWOnNotify(const WXWPARAM wParam, const WXLPARAM lParam) +void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, + WXWORD *item, WXWORD *flags, WXHMENU *hmenu) { -#if defined(__WIN95__) - // Find a child window to send the notification to, e.g. a toolbar. - // There's a problem here. NMHDR::hwndFrom doesn't give us the - // handle of the toolbar; it's probably the handle of the tooltip - // window (anyway, it's parent is also the toolbar's parent). - // So, since we don't know which hWnd or wxWindow originated the - // WM_NOTIFY, we'll need to go through all the children of this window - // trying out MSWNotify. - // This won't work now, though, because any number of controls - // could respond to the same generic messages :-( - -/* This doesn't work for toolbars, but try for other controls first. - */ - NMHDR *hdr = (NMHDR *)lParam; - HWND hWnd = (HWND)hdr->hwndFrom; - wxWindow *win = wxFindWinFromHandle((WXHWND) hWnd); - - if ( win ) - return win->MSWNotify(wParam, lParam); - else - { - // Rely on MSWNotify to check whether the message - // belongs to the window or not - wxNode *node = GetChildren()->First(); - while (node) - { - wxWindow *child = (wxWindow *)node->Data(); - if ( child->MSWNotify(wParam, lParam) ) - return TRUE; - node = node->Next(); - } - } + *item = (WXWORD)wParam; + *flags = LOWORD(lParam); + *hmenu = (WXHMENU)HIWORD(lParam); +} - return FALSE; +#endif // Win32/16 -#endif - return FALSE; -} +// --------------------------------------------------------------------------- +// Main wxWindows window proc and the window proc for wxWindow +// --------------------------------------------------------------------------- + +// Hook for new window just as it's being created, when the window isn't yet +// associated with the handle +static wxWindowMSW *gs_winBeingCreated = NULL; -void wxWindow::MSWOnMenuHighlight(const WXWORD WXUNUSED(item), const WXWORD WXUNUSED(flags), const WXHMENU WXUNUSED(sysmenu)) +// implementation of wxWindowCreationHook class: it just sets gs_winBeingCreated to the +// window being created and insures that it's always unset back later +wxWindowCreationHook::wxWindowCreationHook(wxWindowMSW *winBeingCreated) { -#if DEBUG > 1 - wxDebugMsg("wxWindow::MSWOnMenuHighlight %d\n", handle); -#endif + gs_winBeingCreated = winBeingCreated; } -void wxWindow::MSWOnInitMenuPopup(const WXHMENU menu, const int pos, const bool isSystem) +wxWindowCreationHook::~wxWindowCreationHook() { - if (!isSystem) - OldOnInitMenuPopup(pos); + gs_winBeingCreated = NULL; } -bool wxWindow::MSWOnActivate(const int state, const bool WXUNUSED(minimized), const WXHWND WXUNUSED(activate)) +// Main window proc +LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { -#if DEBUG > 1 - wxDebugMsg("wxWindow::MSWOnActivate %d\n", handle); -#endif + // trace all messages - useful for the debugging +#ifdef __WXDEBUG__ + wxLogTrace(wxTraceMessages, wxT("Processing %s(wParam=%8lx, lParam=%8lx)"), + wxGetMessageName(message), wParam, lParam); +#endif // __WXDEBUG__ -#if WXWIN_COMPATIBILITY - GetEventHandler()->OldOnActivate(((state == WA_ACTIVE) || (state == WA_CLICKACTIVE))); -#else - wxActivateEvent event(wxEVT_ACTIVATE, ((state == WA_ACTIVE) || (state == WA_CLICKACTIVE)), - m_windowId); - event.m_eventObject = this; - GetEventHandler()->ProcessEvent(event); -#endif - return 0; -} + wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd); -bool wxWindow::MSWOnSetFocus(const WXHWND WXUNUSED(hwnd)) -{ -#if DEBUG > 1 - wxDebugMsg("wxWindow::MSWOnSetFocus %d\n", m_hWnd); -#endif - // Deal with caret - if (m_caretEnabled && (m_caretWidth > 0) && (m_caretHeight > 0)) + // when we get the first message for the HWND we just created, we associate + // it with wxWindow stored in gs_winBeingCreated + if ( !wnd && gs_winBeingCreated ) { - ::CreateCaret((HWND) GetHWND(), NULL, m_caretWidth, m_caretHeight); - if (m_caretShown) - ::ShowCaret((HWND) GetHWND()); + wxAssociateWinWithHandle(hWnd, gs_winBeingCreated); + wnd = gs_winBeingCreated; + gs_winBeingCreated = NULL; + wnd->SetHWND((WXHWND)hWnd); } -#if WXWIN_COMPATIBILITY - GetEventHandler()->OldOnSetFocus(); -#else - wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId); - event.m_eventObject = this; - GetEventHandler()->ProcessEvent(event); -#endif - return TRUE; + LRESULT rc; + + if ( wnd ) + rc = wnd->MSWWindowProc(message, wParam, lParam); + else + rc = ::DefWindowProc(hWnd, message, wParam, lParam); + + return rc; } -bool wxWindow::MSWOnKillFocus(const WXHWND WXUNUSED(hwnd)) +long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) { -#if DEBUG > 1 - wxDebugMsg("wxWindow::MSWOnKillFocus %d\n", m_hWnd); -#endif - // Deal with caret - if (m_caretEnabled) + // did we process the message? + bool processed = FALSE; + + // the return value + union { - ::DestroyCaret(); - } + bool allow; + long result; + WXHICON hIcon; + WXHBRUSH hBrush; + } rc; -#if WXWIN_COMPATIBILITY - GetEventHandler()->OldOnKillFocus(); -#else - wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId); - event.m_eventObject = this; - GetEventHandler()->ProcessEvent(event); -#endif - return TRUE; -} + // for most messages we should return 0 when we do process the message + rc.result = 0; -void wxWindow::MSWOnDropFiles(const WXWPARAM wParam) -{ -#if DEBUG > 1 - wxDebugMsg("wxWindow::MSWOnDropFiles %d\n", m_hWnd); -#endif + switch ( message ) + { + case WM_CREATE: + { + bool mayCreate; + processed = HandleCreate((WXLPCREATESTRUCT)lParam, &mayCreate); + if ( processed ) + { + // return 0 to allow window creation + rc.result = mayCreate ? 0 : -1; + } + } + break; - HANDLE hFilesInfo = (HANDLE)wParam; - POINT dropPoint; - DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint); - - // Get the total number of files dropped - WORD gwFilesDropped = (WORD)DragQueryFile ((HDROP)hFilesInfo, - (UINT)-1, - (LPSTR)0, - (UINT)0); - - wxString *files = new wxString[gwFilesDropped]; - int wIndex; - for (wIndex=0; wIndex < (int)gwFilesDropped; wIndex++) - { - DragQueryFile (hFilesInfo, wIndex, (LPSTR) wxBuffer, 1000); - files[wIndex] = wxBuffer; - } - DragFinish (hFilesInfo); - - wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files); - event.m_eventObject = this; - event.m_pos.x = dropPoint.x; event.m_pos.x = dropPoint.y; - - GetEventHandler()->ProcessEvent(event); - - delete[] files; -} - -bool wxWindow::MSWOnDrawItem(const int id, WXDRAWITEMSTRUCT *itemStruct) -{ -#if USE_OWNER_DRAWN - if ( id == 0 ) { // is it a menu item? - DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct; - wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData); - wxCHECK_RET( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE ); - - // prepare to call OnDrawItem() - wxDC dc; - dc.SetHDC((WXHDC)pDrawStruct->hDC, FALSE); - wxRect rect(pDrawStruct->rcItem.left, pDrawStruct->rcItem.top, - pDrawStruct->rcItem.right - pDrawStruct->rcItem.left, - pDrawStruct->rcItem.bottom - pDrawStruct->rcItem.top); - return pMenuItem->OnDrawItem( - dc, rect, - (wxOwnerDrawn::wxODAction)pDrawStruct->itemAction, - (wxOwnerDrawn::wxODStatus)pDrawStruct->itemState - ); - } -#endif // owner-drawn menus + case WM_DESTROY: + // never set processed to TRUE and *always* pass WM_DESTROY to + // DefWindowProc() as Windows may do some internal cleanup when + // processing it and failing to pass the message along may cause + // memory and resource leaks! + (void)HandleDestroy(); + break; + + case WM_MOVE: + processed = HandleMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + break; + + case WM_SIZE: + switch ( wParam ) + { + case SIZE_MAXHIDE: + case SIZE_MAXSHOW: + // we're not interested in these messages at all + break; + + case SIZE_MINIMIZED: + // we shouldn't send sizev events for these messages as the + // client size may be negative which breaks existing code + // + // OTOH we might send another (wxMinimizedEvent?) one or + // add an additional parameter to wxSizeEvent if this is + // useful to anybody + break; + + default: + wxFAIL_MSG( _T("unexpected WM_SIZE parameter") ); + // fall through nevertheless + + case SIZE_MAXIMIZED: + case SIZE_RESTORED: + processed = HandleSize(LOWORD(lParam), HIWORD(lParam), + wParam); + } + break; - wxWindow *item = FindItem(id); -#if USE_DYNAMIC_CLASSES - if (item && item->IsKindOf(CLASSINFO(wxControl))) - { - return ((wxControl *)item)->MSWOnDraw(itemStruct); - } - else +#ifndef __WXMICROWIN__ + case WM_ACTIVATEAPP: + wxTheApp->SetActive(wParam != 0, FindFocus()); + break; #endif - return FALSE; -} -bool wxWindow::MSWOnMeasureItem(const int id, WXMEASUREITEMSTRUCT *itemStruct) -{ -#if USE_OWNER_DRAWN - if ( id == 0 ) { // is it a menu item? - MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct; - wxMenuItem *pMenuItem = (wxMenuItem *)(pMeasureStruct->itemData); - wxCHECK_RET( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE ); + case WM_ACTIVATE: + { + WXWORD state, minimized; + WXHWND hwnd; + UnpackActivate(wParam, lParam, &state, &minimized, &hwnd); - return pMenuItem->OnMeasureItem(&pMeasureStruct->itemWidth, - &pMeasureStruct->itemHeight); - } -#endif // owner-drawn menus + processed = HandleActivate(state, minimized != 0, (WXHWND)hwnd); + } + break; + + case WM_SETFOCUS: + processed = HandleSetFocus((WXHWND)(HWND)wParam); + break; + + case WM_KILLFOCUS: + processed = HandleKillFocus((WXHWND)(HWND)wParam); + break; + + case WM_PAINT: + processed = HandlePaint(); + break; + + case WM_CLOSE: + // don't let the DefWindowProc() destroy our window - we'll do it + // ourselves in ~wxWindow + processed = TRUE; + rc.result = TRUE; + break; + + case WM_SHOWWINDOW: + processed = HandleShow(wParam != 0, (int)lParam); + break; + + case WM_MOUSEMOVE: + processed = HandleMouseMove(GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam), + wParam); + break; - wxWindow *item = FindItem(id); -#if USE_DYNAMIC_CLASSES - if (item && item->IsKindOf(CLASSINFO(wxControl))) - { - return ((wxControl *)item)->MSWOnMeasure(itemStruct); - } - else +#if wxUSE_MOUSEWHEEL + case WM_MOUSEWHEEL: + processed = HandleMouseWheel(wParam, lParam); + break; #endif - return FALSE; -} -WXHBRUSH wxWindow::MSWOnCtlColor(const WXHDC pDC, const WXHWND pWnd, const WXUINT nCtlColor, - const WXUINT message, const WXWPARAM wParam, const WXLPARAM lParam) -{ -#if DEBUG > 1 - wxDebugMsg("wxWindow::MSWOnCtlColour %d\n", m_hWnd); + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MBUTTONDBLCLK: + { + processed = FALSE; +#ifdef __WXMICROWIN__ + // MicroWindows seems to ignore the fact that a window is + // disabled. So catch mouse events and throw them away if + // necessary. + wxWindowMSW* win = this; + while (win) + { + if (!win->IsEnabled()) + { + processed = TRUE; + break; + } + win = win->GetParent(); + if (win && win->IsTopLevel()) + break; + } +#endif // __WXMICROWIN__ + if (!processed) + { + if (message == WM_LBUTTONDOWN && AcceptsFocus()) + SetFocus(); + processed = HandleMouseEvent(message, + GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam), + wParam); + } + break; + } + +#ifdef __WXMICROWIN__ + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONUP: + case WM_NCLBUTTONDBLCLK: + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONUP: + case WM_NCRBUTTONDBLCLK: +#if 0 + case WM_NCMBUTTONDOWN: + case WM_NCMBUTTONUP: + case WM_NCMBUTTONDBLCLK: #endif - if (nCtlColor == CTLCOLOR_DLG) - { - return OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam); - } + { + // MicroWindows seems to ignore the fact that a window + // is disabled. So catch mouse events and throw them away if necessary. + processed = FALSE; + wxWindowMSW* win = this; + while (win) + { + if (!win->IsEnabled()) + { + processed = TRUE; + break; + } + win = win->GetParent(); + if (win && win->IsTopLevel()) + break; + } + break; + } +#endif // __WXMICROWIN__ + +#ifdef MM_JOY1MOVE + case MM_JOY1MOVE: + case MM_JOY2MOVE: + case MM_JOY1ZMOVE: + case MM_JOY2ZMOVE: + case MM_JOY1BUTTONDOWN: + case MM_JOY2BUTTONDOWN: + case MM_JOY1BUTTONUP: + case MM_JOY2BUTTONUP: + processed = HandleJoystickEvent(message, + GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam), + wParam); + break; +#endif // __WXMICROWIN__ - wxControl *item = (wxControl *)FindItemByHWND(pWnd, TRUE); + case WM_SYSCOMMAND: + processed = HandleSysCommand(wParam, lParam); + break; + + case WM_COMMAND: + { + WORD id, cmd; + WXHWND hwnd; + UnpackCommand(wParam, lParam, &id, &hwnd, &cmd); - WXHBRUSH hBrush = 0; + processed = HandleCommand(id, cmd, hwnd); + } + break; - if ( item ) - hBrush = item->OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam); +#ifdef __WIN95__ + case WM_NOTIFY: + processed = HandleNotify((int)wParam, lParam, &rc.result); + break; +#endif // Win95 - // I think that even for dialogs, we may need to call DefWindowProc (?) - // Or maybe just rely on the usual default behaviour. - if ( !hBrush ) - hBrush = (WXHBRUSH) MSWDefWindowProc(message, wParam, lParam); + // for these messages we must return TRUE if process the message +#ifdef WM_DRAWITEM + case WM_DRAWITEM: + case WM_MEASUREITEM: + { + int idCtrl = (UINT)wParam; + if ( message == WM_DRAWITEM ) + { + processed = MSWOnDrawItem(idCtrl, + (WXDRAWITEMSTRUCT *)lParam); + } + else + { + processed = MSWOnMeasureItem(idCtrl, + (WXMEASUREITEMSTRUCT *)lParam); + } + + if ( processed ) + rc.result = TRUE; + } + break; +#endif // defined(WM_DRAWITEM) - return hBrush ; -} + case WM_GETDLGCODE: + if ( GetWindowStyleFlag() & wxWANTS_CHARS ) + { + // want everything: i.e. all keys and WM_CHAR message + rc.result = DLGC_WANTARROWS | DLGC_WANTCHARS | + DLGC_WANTTAB | DLGC_WANTMESSAGE; + processed = TRUE; + } + //else: get the dlg code from the DefWindowProc() + break; + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + // If this has been processed by an event handler, + // return 0 now (we've handled it). + if ( HandleKeyDown((WORD) wParam, lParam) ) + { + processed = TRUE; + + break; + } + + // we consider these message "not interesting" to OnChar + if ( wParam == VK_SHIFT || wParam == VK_CONTROL ) + { + processed = TRUE; + + break; + } + + switch ( wParam ) + { + // 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: + // 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; + + TranslateKbdEventToMouse(this, &x, &y, &flags); + processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags); + } + break; +#endif // VK_APPS + + case VK_LEFT: + case VK_RIGHT: + case VK_DOWN: + case VK_UP: + default: + processed = HandleChar((WORD)wParam, lParam); + } + break; + + case WM_SYSKEYUP: + case WM_KEYUP: +#ifdef VK_APPS + // special case of VK_APPS: treat it the same as right mouse button + if ( wParam == VK_APPS ) + { + WPARAM flags; + int x, y; + + TranslateKbdEventToMouse(this, &x, &y, &flags); + processed = HandleMouseEvent(WM_RBUTTONUP, x, y, flags); + } + else +#endif // VK_APPS + { + processed = HandleKeyUp((WORD) wParam, lParam); + } + break; + + case WM_SYSCHAR: + case WM_CHAR: // Always an ASCII character + processed = HandleChar((WORD)wParam, lParam, TRUE); + break; + + case WM_HSCROLL: + case WM_VSCROLL: + { + WXWORD code, pos; + WXHWND hwnd; + UnpackScroll(wParam, lParam, &code, &pos, &hwnd); + + processed = MSWOnScroll(message == WM_HSCROLL ? wxHORIZONTAL + : wxVERTICAL, + code, pos, hwnd); + } + break; + + // 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: + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLORSCROLLBAR: + case WM_CTLCOLORSTATIC: +#else // Win16 + case WM_CTLCOLOR: +#endif // Win32/16 + { + WXWORD nCtlColor; + WXHDC hdc; + WXHWND hwnd; + UnpackCtlColor(wParam, lParam, &nCtlColor, &hdc, &hwnd); + + processed = HandleCtlColor(&rc.hBrush, + (WXHDC)hdc, + (WXHWND)hwnd, + nCtlColor, + message, + wParam, + lParam); + } + break; +#endif // !__WXMICROWIN__ + + case WM_SYSCOLORCHANGE: + // the return value for this message is ignored + processed = HandleSysColorChange(); + break; + + case WM_DISPLAYCHANGE: + processed = HandleDisplayChange(); + break; + + case WM_PALETTECHANGED: + processed = HandlePaletteChanged((WXHWND) (HWND) wParam); + break; + + case WM_QUERYNEWPALETTE: + processed = HandleQueryNewPalette(); + break; + + case WM_ERASEBKGND: + processed = HandleEraseBkgnd((WXHDC)(HDC)wParam); + if ( processed ) + { + // we processed the message, i.e. erased the background + rc.result = TRUE; + } + break; + + case WM_DROPFILES: + processed = HandleDropFiles(wParam); + break; + + case WM_INITDIALOG: + processed = HandleInitDialog((WXHWND)(HWND)wParam); + + if ( processed ) + { + // we never set focus from here + rc.result = FALSE; + } + break; + + case WM_QUERYENDSESSION: + processed = HandleQueryEndSession(lParam, &rc.allow); + break; + + case WM_ENDSESSION: + processed = HandleEndSession(wParam != 0, lParam); + break; + + case WM_GETMINMAXINFO: + processed = HandleGetMinMaxInfo((MINMAXINFO*)lParam); + break; + + case WM_SETCURSOR: + processed = HandleSetCursor((WXHWND)(HWND)wParam, + LOWORD(lParam), // hit test + HIWORD(lParam)); // mouse msg + + if ( processed ) + { + // returning TRUE stops the DefWindowProc() from further + // processing this message - exactly what we need because we've + // just set the cursor. + rc.result = TRUE; + } + break; + +#if defined(__WIN32__) && defined(WM_HELP) + case WM_HELP: + { + HELPINFO* info = (HELPINFO*) lParam; + // Don't yet process menu help events, just windows + if (info->iContextType == HELPINFO_WINDOW) + { + wxWindowMSW* subjectOfHelp = this; + bool eventProcessed = FALSE; + while (subjectOfHelp && !eventProcessed) + { + wxHelpEvent helpEvent(wxEVT_HELP, + subjectOfHelp->GetId(), + wxPoint(info->MousePos.x, + info->MousePos.y) ); + helpEvent.SetEventObject(this); + eventProcessed = + GetEventHandler()->ProcessEvent(helpEvent); + + // Go up the window hierarchy until the event is + // handled (or not) + subjectOfHelp = subjectOfHelp->GetParent(); + } + + processed = eventProcessed; + } + else if (info->iContextType == HELPINFO_MENUITEM) + { + wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId); + helpEvent.SetEventObject(this); + processed = GetEventHandler()->ProcessEvent(helpEvent); + + } + //else: processed is already FALSE + } + break; + + case WM_CONTEXTMENU: + { + // we don't convert from screen to client coordinates as + // the event may be handled by a parent window + wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + + wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt); + processed = GetEventHandler()->ProcessEvent(evtCtx); + } + break; +#endif // __WIN32__ + } + + if ( !processed ) + { +#ifdef __WXDEBUG__ + wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."), + wxGetMessageName(message)); +#endif // __WXDEBUG__ + rc.result = MSWDefWindowProc(message, wParam, lParam); + } -// Define for each class of dialog and control -WXHBRUSH wxWindow::OnCtlColor(const WXHDC pDC, const WXHWND pWnd, const WXUINT nCtlColor, - WXUINT message, WXWPARAM wParam, WXLPARAM lParam) -{ - return (WXHBRUSH) MSWDefWindowProc(message, wParam, lParam); + return rc.result; } -bool wxWindow::MSWOnColorChange(const WXHWND hWnd, const WXUINT message, const WXWPARAM wParam, const WXLPARAM lParam) -{ - wxSysColourChangedEvent event; - event.m_eventObject = this; - - // Check if app handles this. - if (GetEventHandler()->ProcessEvent(event)) - return 0; +// ---------------------------------------------------------------------------- +// wxWindow <-> HWND map +// ---------------------------------------------------------------------------- -#if WXWIN_COMPATIBILITY - if (GetEventHandler()->OldOnSysColourChange()) - return 0; -#endif +wxWinHashTable *wxWinHandleHash = NULL; - // We didn't process it - return 1; +wxWindow *wxFindWinFromHandle(WXHWND hWnd) +{ + return wxWinHandleHash->Get((long)hWnd); } -// Responds to colour changes: passes event on to children. -void wxWindow::OnSysColourChanged(wxSysColourChangedEvent& event) +void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win) { - wxNode *node = GetChildren()->First(); - while ( node ) - { - // Only propagate to non-top-level windows - wxWindow *win = (wxWindow *)node->Data(); - if ( win->GetParent() ) - { - wxSysColourChangedEvent event2; - event.m_eventObject = win; - win->GetEventHandler()->ProcessEvent(event2); - } + // adding NULL hWnd is (first) surely a result of an error and + // (secondly) breaks menu command processing + wxCHECK_RET( hWnd != (HWND)NULL, + wxT("attempt to add a NULL hWnd to window list ignored") ); - node = node->Next(); + wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd); +#ifdef __WXDEBUG__ + if ( oldWin && (oldWin != win) ) + { + wxLogDebug(wxT("HWND %X already associated with another window (%s)"), + hWnd, win->GetClassInfo()->GetClassName()); + } + else +#endif // __WXDEBUG__ + if (!oldWin) + { + wxWinHandleHash->Put((long)hWnd, (wxWindow *)win); } } -long wxWindow::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +void wxRemoveHandleAssociation(wxWindowMSW *win) { - if ( m_oldWndProc ) - return ::CallWindowProc(CASTWNDPROC (FARPROC) m_oldWndProc, (HWND) GetHWND(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam); - else - return ::DefWindowProc((HWND) GetHWND(), nMsg, wParam, lParam); + wxWinHandleHash->Delete((long)win->GetHWND()); } -long wxWindow::Default() -{ - return this->MSWDefWindowProc(m_lastMsg, m_lastWParam, m_lastLParam); -} +// ---------------------------------------------------------------------------- +// various MSW speciic class dependent functions +// ---------------------------------------------------------------------------- -bool wxWindow::MSWProcessMessage(WXMSG* pMsg) +// Default destroyer - override if you destroy it in some other way +// (e.g. with MDI child windows) +void wxWindowMSW::MSWDestroyWindow() { - if (!m_hWnd) - return FALSE; - else - { - // Suggestion by Andrew Davison to allow - // a panel to accept character input in user edit mode - - // OK, what we probably want to do here for wxWin 2.0 - // is have a window style to indicate whether the window - // should process dialog-style input, since we can't - // otherwise tell whether it's supposed to do tab traversal - // or not. - if (GetWindowStyleFlag() & wxTAB_TRAVERSAL) - return (::IsDialogMessage((HWND) m_hWnd, (MSG *)pMsg) != 0); - else - return FALSE; - } } -long wxWindow::MSWOnMDIActivate(const long WXUNUSED(flag), const WXHWND WXUNUSED(activate), const WXHWND WXUNUSED(deactivate)) +bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos, + const wxSize& size, + int& x, int& y, + int& w, int& h) const { -#if DEBUG > 1 - wxDebugMsg("wxWindow::MSWOnMDIActivate %d\n", m_hWnd); -#endif - return 1; -} + bool nonDefault = FALSE; -void wxWindow::MSWDetachWindowMenu(void) -{ - if (m_hMenu) - { - int N = GetMenuItemCount((HMENU) m_hMenu); - int i; - for (i = 0; i < N; i++) + if ( pos.x == -1 ) { - char buf[100]; - int chars = GetMenuString((HMENU) m_hMenu, i, buf, 100, MF_BYPOSITION); - if ((chars > 0) && (strcmp(buf, "&Window") == 0)) - { - RemoveMenu((HMENU) m_hMenu, i, MF_BYPOSITION); - break; - } + // if set x to CW_USEDEFAULT, y parameter is ignored anyhow so we can + // just as well set it to CW_USEDEFAULT as well + x = + y = CW_USEDEFAULT; } - } -} - -bool wxWindow::MSWOnPaint(void) -{ -#if WXWIN_COMPATIBILITY - GetEventHandler()->OldOnPaint(); -#else - wxPaintEvent event(m_windowId); - event.m_eventObject = this; - GetEventHandler()->ProcessEvent(event); -#endif - return TRUE; - -#if 0 - -#if DEBUG > 1 - wxDebugMsg("wxWindow::MSWOnPaint %d\n", m_hWnd); -#endif -#ifdef __WIN32__ - HRGN tRgn=CreateRectRgn(0,0,0,0); //Dummy call to get a handle! - if (GetUpdateRgn(m_hWnd, tRgn, FALSE)) -#else - RECT tRect; - if (GetUpdateRect((HWND) m_hWnd, &tRect, FALSE)) -#endif - { - PAINTSTRUCT ps; - // Hold a pointer to the dc so long as the OnPaint() message - // is being processed - HDC dc = BeginPaint(m_hWnd, &ps); - bool isPanel = IsKindOf(CLASSINFO(wxWindow)); - m_paintHDC = (WXHDC) dc; - RECT updateRect1 = ps.rcPaint; - m_updateRect.x = updateRect1.left; - m_updateRect.y = updateRect1.top; - m_updateRect.width = updateRect1.right - updateRect1.left; - m_updateRect.height = updateRect1.bottom - updateRect1.top; - - GetEventHandler()->OldOnPaint(); - - m_paintHDC = 0; - EndPaint((HWND) m_hWnd, &ps); -#ifdef __WIN32__ - DeleteObject(tRgn); -#endif - - if (isPanel) - // Do default processing - return FALSE; else - return TRUE; - } -#ifdef __WIN32__ - DeleteObject(tRgn); -#endif - return FALSE; -#endif -} - -void wxWindow::MSWOnSize(const int w, const int h, const WXUINT WXUNUSED(flag)) -{ - if (m_inOnSize) - return; - -#if DEBUG > 1 - wxDebugMsg("wxWindow::MSWOnSize %d\n", m_hWnd); -#endif - if (!m_hWnd) - return; + { + x = pos.x; + y = pos.y == -1 ? CW_USEDEFAULT : pos.y; - m_inOnSize = TRUE; + nonDefault = TRUE; + } -#if WXWIN_COMPATIBILITY - GetEventHandler()->OldOnSize(w, h); -#else - wxSizeEvent event(wxSize(w, h), m_windowId); - event.m_eventObject = this; - GetEventHandler()->ProcessEvent(event); -#endif + /* + NB: there used to be some code here which set the initial size of the + window to the client size of the parent if no explicit size was + specified. This was wrong because wxWindows programs often assume + that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke + it. To see why, you should understand that Windows sends WM_SIZE from + inside ::CreateWindow() anyhow. However, ::CreateWindow() is called + from some base class ctor and so this WM_SIZE is not processed in the + real class' OnSize() (because it's not fully constructed yet and the + event goes to some base class OnSize() instead). So the WM_SIZE we + rely on is the one sent when the parent frame resizes its children + but here is the problem: if the child already has just the right + size, nothing will happen as both wxWindows and Windows check for + this and ignore any attempts to change the window size to the size it + already has - so no WM_SIZE would be sent. + */ + if ( size.x == -1 ) + { + // as abobe, h is not used at all in this case anyhow + w = + h = CW_USEDEFAULT; + } + else + { + w = size.x; + h = size.y == -1 ? CW_USEDEFAULT : size.y; - m_inOnSize = FALSE; -} + nonDefault = TRUE; + } -void wxWindow::MSWOnWindowPosChanging(void *WXUNUSED(lpPos)) -{ - Default(); + return nonDefault; } -// Deal with child commands from buttons etc. -bool wxWindow::MSWOnCommand(const WXWORD id, const WXWORD cmd, const WXHWND WXUNUSED(control)) +bool wxWindowMSW::MSWCreate(const wxChar *wclass, + const wxChar *title, + const wxPoint& pos, + const wxSize& size, + WXDWORD style, + WXDWORD extendedStyle) { -#if DEBUG > 1 - wxDebugMsg("wxWindow::MSWOnCommand\n"); -#endif - if (wxCurrentPopupMenu) - { - wxMenu *popupMenu = wxCurrentPopupMenu; - wxCurrentPopupMenu = NULL; - bool succ = popupMenu->MSWCommand(cmd, id); - return succ; - } -#if DEBUG > 1 - char buf[80]; - sprintf(buf, "Looking for item %d...\n", id); - wxDebugMsg(buf); -#endif + // choose the position/size for the new window + int x, y, w, h; + (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h); - wxWindow *item = FindItem(id); - if (item) - { - bool value = item->MSWCommand(cmd, id); -#if DEBUG > 1 - if (value) - wxDebugMsg("MSWCommand succeeded\n"); - else - wxDebugMsg("MSWCommand failed\n"); -#endif - return value; - } - else - { -#if DEBUG > 1 - wxDebugMsg("Could not find item!\n"); - char buf[100]; - wxDebugMsg("Item ids for this panel:\n"); - - wxNode *current = GetChildren()->First(); - while (current) + // find the correct parent HWND + wxWindow *parent = GetParent(); + bool isChild = (style & WS_CHILD) != 0; + HWND hParent; + if ( GetWindowStyleFlag() & wxPOPUP_WINDOW ) { - wxObject *obj = (wxObject *)current->Data() ; - if (obj->IsKindOf(CLASSINFO(wxControl))) - { - wxControl *item = (wxControl *)current->Data(); - sprintf(buf, " %d\n", (int)item->m_windowId); - wxDebugMsg(buf); - } - current = current->Next(); + // popup windows should have desktop as parent because they shouldn't + // be limited to the parents client area as child windows usually are + hParent = ::GetDesktopWindow(); } - wxYield(); -#endif - return FALSE; - } -} - -long wxWindow::MSWOnSysCommand(WXWPARAM wParam, WXLPARAM lParam) -{ - switch (wParam) + else // !popup { - case SC_MAXIMIZE: + if ( (isChild || HasFlag(wxFRAME_TOOL_WINDOW)) && parent ) { - wxMaximizeEvent event(m_windowId); - event.SetEventObject(this); - if (!GetEventHandler()->ProcessEvent(event)) - return Default(); - else - return 0; - break; + // this is either a normal child window or a top level window with + // wxFRAME_TOOL_WINDOW style (see below) + hParent = GetHwndOf(parent); } - case SC_MINIMIZE: + else { - wxIconizeEvent event(m_windowId); - event.SetEventObject(this); - if (!GetEventHandler()->ProcessEvent(event)) - return Default(); - else - return 0; - break; + // this is either a window for which no parent was specified (not + // much we can do then) or a frame without wxFRAME_TOOL_WINDOW + // style: we should use NULL parent HWND for it or it would be + // always on top of its parent which is not what we usually want + // (in fact, we only want it for frames with the special + // wxFRAME_TOOL_WINDOW as above) + hParent = NULL; } - default: - return Default(); - } - return 0; -} -void wxWindow::MSWOnLButtonDown(const int x, const int y, const WXUINT flags) -{ -#if 0 // defined(__WIN32__) && !defined(WIN95) - // DClick not clean supported on Win3.1, except if someone know - // how to emulate Sleep()... - // This means that your app will receive Down-Up-Dclick sequences - // rather than Dclick - if (m_doubleClickAllowed) - { - UINT time = GetDoubleClickTime() ; - Sleep(time) ; - MSG dummy ; - if (PeekMessage(&dummy,m_hWnd, - WM_LBUTTONDBLCLK,WM_LBUTTONDBLCLK, - PM_NOREMOVE) - ) - { - PeekMessage(&dummy,m_hWnd,WM_LBUTTONUP,WM_LBUTTONUP,PM_REMOVE); - return; } - } -#endif - -//wxDebugMsg("LButtonDown\n") ; - wxMouseEvent event(wxEVENT_TYPE_LEFT_DOWN); - -/* - float px = (float)x; - float py = (float)y; - - MSWDeviceToLogical(&px, &py); - CalcUnscrolledPosition((int)px, (int)py, &event.m_x, &event.m_y); -*/ + // controlId is menu handle for the top level windows, so set it to 0 + // unless we're creating a child window + int controlId; + if ( isChild ) + { + controlId = GetId(); - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); /* MATTHEW: timeStamp */ - event.m_eventObject = this; + if ( GetWindowStyleFlag() & wxCLIP_SIBLINGS ) + { + style |= WS_CLIPSIBLINGS; + } + } + else // !child + { + controlId = 0; + } - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVENT_TYPE_LEFT_DOWN; - GetEventHandler()->OldOnMouseEvent(event); -} + // 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 ) + { + className += wxT("NR"); + } -void wxWindow::MSWOnLButtonUp(const int x, const int y, const WXUINT flags) -{ -//wxDebugMsg("LButtonUp\n") ; - wxMouseEvent event(wxEVENT_TYPE_LEFT_UP); + // do create the window + wxWindowCreationHook hook(this); -/* - float px = (float)x; - float py = (float)y; + m_hWnd = (WXHWND)::CreateWindowEx + ( + extendedStyle, + className, + title ? title : wxT(""), + style, + x, y, w, h, + hParent, + (HMENU)controlId, + wxGetInstance(), + NULL // no extra data + ); - MSWDeviceToLogical(&px, &py); + if ( !m_hWnd ) + { + wxLogSysError(_("Can't create window of class %s"), wclass); - CalcUnscrolledPosition((int)px, (int)py, &event.m_x, &event.m_y); -*/ + return FALSE; + } - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); /* MATTHEW: timeStamp */ - event.m_eventObject = this; + SubclassWin(m_hWnd); - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVENT_TYPE_LEFT_UP; + SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - GetEventHandler()->OldOnMouseEvent(event); + return TRUE; } -void wxWindow::MSWOnLButtonDClick(const int x, const int y, const WXUINT flags) -{ -//wxDebugMsg("LButtonDClick\n") ; - /* MATTHEW: If dclick not allowed, generate another single-click */ - wxMouseEvent event(m_doubleClickAllowed ? - wxEVENT_TYPE_LEFT_DCLICK : wxEVENT_TYPE_LEFT_DOWN); +// =========================================================================== +// MSW message handlers +// =========================================================================== -/* - float px = (float)x; - float py = (float)y; +// --------------------------------------------------------------------------- +// WM_NOTIFY +// --------------------------------------------------------------------------- - MSWDeviceToLogical(&px, &py); +#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__ + LPNMHDR hdr = (LPNMHDR)lParam; + HWND hWnd = hdr->hwndFrom; + wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd); - CalcUnscrolledPosition((int)px, (int)py, &event.m_x, &event.m_y); -*/ + // is this one of our windows? + if ( win ) + { + return win->MSWOnNotify(idCtrl, lParam, result); + } - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON != 0)); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); /* MATTHEW: timeStamp */ - event.m_eventObject = this; + // try all our children + wxWindowList::Node *node = GetChildren().GetFirst(); + while ( node ) + { + wxWindow *child = node->GetData(); + if ( child->MSWOnNotify(idCtrl, lParam, result) ) + { + return TRUE; + } - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVENT_TYPE_LEFT_DCLICK; + node = node->GetNext(); + } -// if (m_doubleClickAllowed) - GetEventHandler()->OldOnMouseEvent(event); + // finally try this window too (catches toolbar case) + return MSWOnNotify(idCtrl, lParam, result); +#else // __WXMICROWIN__ + return FALSE; +#endif } -void wxWindow::MSWOnMButtonDown(const int x, const int y, const WXUINT flags) +bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl), + WXLPARAM lParam, + WXLPARAM* WXUNUSED(result)) { -#if 0 // defined(__WIN32__) && !defined(__WIN95__) - // DClick not clean supported on Win3.1, except if someone know - // how to emulate Sleep()... - // This means that your app will receive Down-Up-Dclick sequences - // rather than Dclick - if (m_doubleClickAllowed) - { - UINT time = GetDoubleClickTime() ; - Sleep(time) ; - MSG dummy ; - if (PeekMessage(&dummy,m_hWnd, - WM_MBUTTONDBLCLK,WM_MBUTTONDBLCLK, - PM_NOREMOVE) - ) +#if wxUSE_TOOLTIPS + NMHDR* hdr = (NMHDR *)lParam; + if ( (int)hdr->code == TTN_NEEDTEXT && m_tooltip ) { - PeekMessage(&dummy,m_hWnd,WM_MBUTTONUP,WM_MBUTTONUP,PM_REMOVE); - return; + TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam; + ttt->lpszText = (wxChar *)m_tooltip->GetTip().c_str(); + + // processed + return TRUE; } - } -#endif +#endif // wxUSE_TOOLTIPS -//wxDebugMsg("MButtonDown\n") ; - wxMouseEvent event(wxEVENT_TYPE_MIDDLE_DOWN); + return FALSE; +} +#endif // __WIN95__ -/* - float px = (float)x; - float py = (float)y; +// --------------------------------------------------------------------------- +// end session messages +// --------------------------------------------------------------------------- - MSWDeviceToLogical(&px, &py); +bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd) +{ + wxCloseEvent event(wxEVT_QUERY_END_SESSION, -1); + event.SetEventObject(wxTheApp); + event.SetCanVeto(TRUE); + event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF); - CalcUnscrolledPosition((int)px, (int)py, &event.m_x, &event.m_y); -*/ + bool rc = wxTheApp->ProcessEvent(event); - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); /* MATTHEW: timeStamp */ - event.m_eventObject = this; + if ( rc ) + { + // we may end only if the app didn't veto session closing (double + // negation...) + *mayEnd = !event.GetVeto(); + } - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVENT_TYPE_LEFT_DOWN; - GetEventHandler()->OldOnMouseEvent(event); + return rc; } -void wxWindow::MSWOnMButtonUp(const int x, const int y, const WXUINT flags) +bool wxWindowMSW::HandleEndSession(bool endSession, long logOff) { -//wxDebugMsg("MButtonUp\n") ; - wxMouseEvent event(wxEVENT_TYPE_MIDDLE_UP); - -/* - float px = (float)x; - float py = (float)y; - - MSWDeviceToLogical(&px, &py); + // do nothing if the session isn't ending + if ( !endSession ) + return FALSE; - CalcUnscrolledPosition((int)px, (int)py, &event.m_x, &event.m_y); -*/ + // only send once + if ( (this != wxTheApp->GetTopWindow()) ) + return FALSE; - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); /* MATTHEW: timeStamp */ - event.m_eventObject = this; + wxCloseEvent event(wxEVT_END_SESSION, -1); + event.SetEventObject(wxTheApp); + event.SetCanVeto(FALSE); + event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) ); - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVENT_TYPE_LEFT_UP; - GetEventHandler()->OldOnMouseEvent(event); + return wxTheApp->ProcessEvent(event); } -void wxWindow::MSWOnMButtonDClick(const int x, const int y, const WXUINT flags) -{ -//wxDebugMsg("MButtonDClick\n") ; - /* MATTHEW: If dclick not allowed, generate another single-click */ - wxMouseEvent event((m_doubleClickAllowed) ? - wxEVENT_TYPE_MIDDLE_DCLICK : wxEVENT_TYPE_MIDDLE_DOWN); - -/* - float px = (float)x; - float py = (float)y; +// --------------------------------------------------------------------------- +// window creation/destruction +// --------------------------------------------------------------------------- - MSWDeviceToLogical(&px, &py); - - CalcUnscrolledPosition((int)px, (int)py, &event.m_x, &event.m_y); -*/ +bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED(cs), bool *mayCreate) +{ + // TODO: should generate this event from WM_NCCREATE + wxWindowCreateEvent event((wxWindow *)this); + (void)GetEventHandler()->ProcessEvent(event); - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); /* MATTHEW: timeStamp */ - event.m_eventObject = this; + *mayCreate = TRUE; - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVENT_TYPE_LEFT_DCLICK; -// if (m_doubleClickAllowed) - GetEventHandler()->OldOnMouseEvent(event); + return TRUE; } -void wxWindow::MSWOnRButtonDown(const int x, const int y, const WXUINT flags) +bool wxWindowMSW::HandleDestroy() { -#if 0 // defined(__WIN32__) && !defined(__WIN95__) - // DClick not clean supported on Win3.1, except if someone know - // how to emulate Sleep()... - // This means that your app will receive Down-Up-Dclick sequences - // rather than Dclick - if (m_doubleClickAllowed) - { - UINT time = GetDoubleClickTime() ; - Sleep(time) ; - MSG dummy ; - if (PeekMessage(&dummy,m_hWnd, - WM_RBUTTONDBLCLK,WM_RBUTTONDBLCLK, - PM_NOREMOVE) - ) - { - PeekMessage(&dummy,m_hWnd,WM_RBUTTONUP,WM_RBUTTONUP,PM_REMOVE); - return; - } - } -#endif - -//wxDebugMsg("RButtonDown\n") ; - wxMouseEvent event(wxEVENT_TYPE_RIGHT_DOWN); - -/* - float px = (float)x; - float py = (float)y; + wxWindowDestroyEvent event((wxWindow *)this); + (void)GetEventHandler()->ProcessEvent(event); - MSWDeviceToLogical(&px, &py); - - CalcUnscrolledPosition((int)px, (int)py, &event.m_x, &event.m_y); -*/ + // delete our drop target if we've got one +#if wxUSE_DRAG_AND_DROP + if ( m_dropTarget != NULL ) + { + m_dropTarget->Revoke(m_hWnd); - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); /* MATTHEW: timeStamp */ - event.m_eventObject = this; + delete m_dropTarget; + m_dropTarget = NULL; + } +#endif // wxUSE_DRAG_AND_DROP - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVENT_TYPE_RIGHT_DOWN; - GetEventHandler()->OldOnMouseEvent(event); + // WM_DESTROY handled + return TRUE; } -void wxWindow::MSWOnRButtonUp(const int x, const int y, const WXUINT flags) -{ -//wxDebugMsg("RButtonUp\n") ; - wxMouseEvent event(wxEVENT_TYPE_RIGHT_UP); - -/* - float px = (float)x; - float py = (float)y; - - MSWDeviceToLogical(&px, &py); - - CalcUnscrolledPosition((int)px, (int)py, &event.m_x, &event.m_y); -*/ +// --------------------------------------------------------------------------- +// activation/focus +// --------------------------------------------------------------------------- - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.m_eventObject = this; - event.SetTimestamp(wxApp::sm_lastMessageTime); /* MATTHEW: timeStamp */ +bool wxWindowMSW::HandleActivate(int state, + bool WXUNUSED(minimized), + WXHWND WXUNUSED(activate)) +{ + wxActivateEvent event(wxEVT_ACTIVATE, + (state == WA_ACTIVE) || (state == WA_CLICKACTIVE), + m_windowId); + event.SetEventObject(this); - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVENT_TYPE_RIGHT_UP; - GetEventHandler()->OldOnMouseEvent(event); + return GetEventHandler()->ProcessEvent(event); } -void wxWindow::MSWOnRButtonDClick(const int x, const int y, const WXUINT flags) +bool wxWindowMSW::HandleSetFocus(WXHWND hwnd) { -//wxDebugMsg("RButtonDClick\n") ; - /* MATTHEW: If dclick not allowed, generate another single-click */ - wxMouseEvent event((m_doubleClickAllowed) ? - wxEVENT_TYPE_RIGHT_DCLICK : wxEVENT_TYPE_RIGHT_DOWN); + // notify the parent keeping track of focus for the kbd navigation + // purposes that we got it + wxChildFocusEvent eventFocus((wxWindow *)this); + (void)GetEventHandler()->ProcessEvent(eventFocus); -/* - float px = (float)x; - float py = (float)y; +#if wxUSE_CARET + // Deal with caret + if ( m_caret ) + { + m_caret->OnSetFocus(); + } +#endif // wxUSE_CARET - MSWDeviceToLogical(&px, &py); +#if wxUSE_TEXTCTRL + // If it's a wxTextCtrl don't send the event as it will be done + // after the control gets to process it from EN_FOCUS handler + if ( wxDynamicCastThis(wxTextCtrl) ) + { + return FALSE; + } +#endif // wxUSE_TEXTCTRL - CalcUnscrolledPosition((int)px, (int)py, &event.m_x, &event.m_y); -*/ + wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId); + event.SetEventObject(this); - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); /* MATTHEW: timeStamp */ - event.m_eventObject = this; + // wxFindWinFromHandle() may return NULL, it is ok + event.SetWindow(wxFindWinFromHandle(hwnd)); - m_lastXPos = event.m_x; m_lastYPos = event.m_y; m_lastEvent = wxEVENT_TYPE_RIGHT_DCLICK; -// if (m_doubleClickAllowed) - GetEventHandler()->OldOnMouseEvent(event); + return GetEventHandler()->ProcessEvent(event); } -void wxWindow::MSWOnMouseMove(const int x, const int y, const WXUINT flags) +bool wxWindowMSW::HandleKillFocus(WXHWND hwnd) { - // 'normal' move event... - // Set cursor, but only if we're not in 'busy' mode - - // Trouble with this is that it sets the cursor for controls too :-( - if (m_windowCursor.Ok() && !wxIsBusy()) - ::SetCursor((HCURSOR) m_windowCursor.GetHCURSOR()); +#if wxUSE_CARET + // Deal with caret + if ( m_caret ) + { + m_caret->OnKillFocus(); + } +#endif // wxUSE_CARET - wxMouseEvent event(wxEVENT_TYPE_MOTION); +#if wxUSE_TEXTCTRL + // If it's a wxTextCtrl don't send the event as it will be done + // after the control gets to process it. + wxTextCtrl *ctrl = wxDynamicCastThis(wxTextCtrl); + if ( ctrl ) + { + return FALSE; + } +#endif -/* - float px = (float)x; - float py = (float)y; + wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId); + event.SetEventObject(this); - MSWDeviceToLogical(&px, &py); + // wxFindWinFromHandle() may return NULL, it is ok + event.SetWindow(wxFindWinFromHandle(hwnd)); - CalcUnscrolledPosition((int)px, (int)py, &event.m_x, &event.m_y); -*/ + return GetEventHandler()->ProcessEvent(event); +} - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); /* MATTHEW: timeStamp */ - event.m_eventObject = this; +// --------------------------------------------------------------------------- +// miscellaneous +// --------------------------------------------------------------------------- - // Window gets a click down message followed by a mouse move - // message even if position isn't changed! We want to discard - // the trailing move event if x and y are the same. - if ((m_lastEvent == wxEVENT_TYPE_RIGHT_DOWN || m_lastEvent == wxEVENT_TYPE_LEFT_DOWN || - m_lastEvent == wxEVENT_TYPE_MIDDLE_DOWN) && - (m_lastXPos == event.m_x && m_lastYPos == event.m_y)) - { - m_lastXPos = event.m_x; m_lastYPos = event.m_y; - m_lastEvent = wxEVENT_TYPE_MOTION; - return; - } +bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status)) +{ + wxShowEvent event(GetId(), show); + event.m_eventObject = this; - m_lastEvent = wxEVENT_TYPE_MOTION; - m_lastXPos = event.m_x; m_lastYPos = event.m_y; - GetEventHandler()->OldOnMouseEvent(event); + return GetEventHandler()->ProcessEvent(event); } -/* TODO put back leave/enter code if required - */ -#if 0 -void wxWindow::MSWOnMouseMove(int x, int y, WXUINT flags) -{ -//wxDebugMsg("Client 0x%08x Move Msg %d,%d\n",this,x,y) ; - -// #if MOUSE_EXIT_FIX //Should work now!! - - // Don't do the Leave/Enter fix if we've captured the window, - // or SetCapture won't work properly. - if (!m_winCaptured) - { - HWND hunder ; - POINT pt ; - // See if we Leave/Enter the window. - GetCursorPos(&pt) ; - hunder = WindowFromPoint(pt) ; - if (hunder==m_hWnd) - { - // I'm in the Window, but perhaps in NC area. - RECT wind ; - RECT nc ; - GetClientRect(m_hWnd,&wind) ; - GetWindowRect(m_hWnd,&nc) ; - pt.x -= nc.left ; - pt.y -= nc.top ; - wind.left += WINDOW_MARGIN ; // to be able to 'see' leave - wind.top += WINDOW_MARGIN ; // to be able to 'see' leave - wind.right -= WINDOW_MARGIN ; // to be able to 'see' leave - wind.bottom -= WINDOW_MARGIN ; // to be able to 'see' leave - - if (!PtInRect(&wind,pt)) - hunder = NULL ; // So, I can simulate a Leave event... - } - - if (hunder!=m_hWnd) - { - if (m_mouseInWindow) - { - m_mouseInWindow = FALSE ; - // Capture/Release is no more needed... - //ReleaseCapture() ; - MSWOnMouseLeave(x,y,flags) ; - return ; - } - // We never want to see Enter or Motion in this part of the Window... - return ; - } - else - { - // Event was triggered while I'm really into my client area. - // Do an Enter if not done. - if (!m_mouseInWindow) - { - m_mouseInWindow = TRUE ; - // Capture/Release is no more needed... - //SetCapture(m_hWnd) ; - // Set cursor, but only if we're not in 'busy' mode - if (m_windowCursor.Ok() && !wxIsBusy()) - ::SetCursor(m_windowCursor.ms_cursor); - MSWOnMouseEnter(x,y,flags) ; - return ; - } - } - } -// #endif //MOUSE_EXIT_FIX - - // 'normal' move event... - // Set cursor, but only if we're not in 'busy' mode - if (m_windowCursor.Ok() && !wxIsBusy()) - ::SetCursor(m_windowCursor.ms_cursor); - - wxMouseEvent event(wxEVENT_TYPE_MOTION); - -/* - float px = (float)x; - float py = (float)y; - - MSWDeviceToLogical(&px, &py); - - CalcUnscrolledPosition((int)px, (int)py, &event.m_x, &event.m_y); -*/ - - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); /* MATTHEW: timeStamp */ - event.m_eventObject = this; - - // Window gets a click down message followed by a mouse move - // message even if position isn't changed! We want to discard - // the trailing move event if x and y are the same. - if ((m_lastEvent == wxEVENT_TYPE_RIGHT_DOWN || m_lastEvent == wxEVENT_TYPE_LEFT_DOWN || - m_lastEvent == wxEVENT_TYPE_MIDDLE_DOWN) && - (m_lastXPos == event.m_x && m_lastYPos == event.m_y)) - { - m_lastXPos = event.m_x; m_lastYPos = event.m_y; - m_lastEvent = wxEVENT_TYPE_MOTION; - return; - } - - m_lastEvent = wxEVENT_TYPE_MOTION; - m_lastXPos = event.m_x; m_lastYPos = event.m_y; - GetEventHandler()->OldOnMouseEvent(event); +bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus)) +{ + wxInitDialogEvent event(GetId()); + event.m_eventObject = this; + + return GetEventHandler()->ProcessEvent(event); } -#endif -void wxWindow::MSWOnMouseEnter(const int x, const int y, const WXUINT flags) +bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam) { -//wxDebugMsg("Client 0x%08x Enter %d,%d\n",this,x,y) ; +#ifndef __WXMICROWIN__ + HDROP hFilesInfo = (HDROP) wParam; - // Set cursor, but only if we're not in 'busy' mode - if (m_windowCursor.Ok() && !wxIsBusy()) - ::SetCursor((HCURSOR) m_windowCursor.GetHCURSOR()); + // Get the total number of files dropped + UINT gwFilesDropped = ::DragQueryFile + ( + (HDROP)hFilesInfo, + (UINT)-1, + (LPTSTR)0, + (UINT)0 + ); - wxMouseEvent event(wxEVENT_TYPE_ENTER_WINDOW); + wxString *files = new wxString[gwFilesDropped]; + for ( UINT wIndex = 0; wIndex < gwFilesDropped; wIndex++ ) + { + // first get the needed buffer length (+1 for terminating NUL) + size_t len = ::DragQueryFile(hFilesInfo, wIndex, NULL, 0) + 1; -/* - float px = (float)x; - float py = (float)y; + // and now get the file name + ::DragQueryFile(hFilesInfo, wIndex, + files[wIndex].GetWriteBuf(len), len); - MSWDeviceToLogical(&px, &py); + files[wIndex].UngetWriteBuf(); + } + DragFinish (hFilesInfo); - CalcUnscrolledPosition((int)px, (int)py, &event.m_x, &event.m_y); -*/ + wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files); + event.m_eventObject = this; - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); /* MATTHEW: timeStamp */ - event.m_eventObject = this; + POINT dropPoint; + DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint); + event.m_pos.x = dropPoint.x; + event.m_pos.y = dropPoint.y; - m_lastEvent = wxEVENT_TYPE_ENTER_WINDOW; - m_lastXPos = event.m_x; m_lastYPos = event.m_y; - GetEventHandler()->OldOnMouseEvent(event); + return GetEventHandler()->ProcessEvent(event); +#else // __WXMICROWIN__ + return FALSE; +#endif } -void wxWindow::MSWOnMouseLeave(const int x, const int y, const WXUINT flags) +bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd), + short nHitTest, + int WXUNUSED(mouseMsg)) { -//wxDebugMsg("Client 0x%08x Leave %d,%d\n",this,x,y) ; - - // Set cursor, but only if we're not in 'busy' mode - if (m_windowCursor.Ok() && !wxIsBusy()) - ::SetCursor((HCURSOR) m_windowCursor.GetHCURSOR()); +#ifndef __WXMICROWIN__ + // the logic is as follows: + // -1. don't set cursor for non client area, including but not limited to + // the title bar, scrollbars, &c + // 0. allow the user to override default behaviour by using EVT_SET_CURSOR + // 1. if we have the cursor set it unless wxIsBusy() + // 2. if we're a top level window, set some cursor anyhow + // 3. if wxIsBusy(), set the busy cursor, otherwise the global one - wxMouseEvent event(wxEVENT_TYPE_LEAVE_WINDOW); - -/* - float px = (float)x; - float py = (float)y; + if ( nHitTest != HTCLIENT ) + { + return FALSE; + } - MSWDeviceToLogical(&px, &py); + HCURSOR hcursor = 0; - CalcUnscrolledPosition((int)px, (int)py, &event.m_x, &event.m_y); -*/ + // first ask the user code - it may wish to set the cursor in some very + // specific way (for example, depending on the current position) + POINT pt; +#ifdef __WIN32__ + if ( !::GetCursorPos(&pt) ) + { + wxLogLastError(wxT("GetCursorPos")); + } +#else + // In WIN16 it doesn't return a value. + ::GetCursorPos(&pt); +#endif - event.m_x = x; event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); - event.SetTimestamp(wxApp::sm_lastMessageTime); /* MATTHEW: timeStamp */ - event.m_eventObject = this; + int x = pt.x, + y = pt.y; + ScreenToClient(&x, &y); + wxSetCursorEvent event(x, y); - m_lastEvent = wxEVENT_TYPE_LEAVE_WINDOW; - m_lastXPos = event.m_x; m_lastYPos = event.m_y; - GetEventHandler()->OldOnMouseEvent(event); -} + bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event); + if ( processedEvtSetCursor && event.HasCursor() ) + { + hcursor = GetHcursorOf(event.GetCursor()); + } -void wxWindow::MSWOnChar(const WXWORD wParam, const WXLPARAM lParam, const bool isASCII) -{ - int id; - bool tempControlDown = FALSE; - if (isASCII) - { - // If 1 -> 26, translate to CTRL plus a letter. - id = wParam; - if ((id > 0) && (id < 27)) + if ( !hcursor ) { - switch (id) - { - case 13: - { - id = WXK_RETURN; - break; - } - case 8: - { - id = WXK_BACK; - break; - } - case 9: + bool isBusy = wxIsBusy(); + + // the test for processedEvtSetCursor is here to prevent using m_cursor + // if the user code caught EVT_SET_CURSOR() and returned nothing from + // it - this is a way to say that our cursor shouldn't be used for this + // point + if ( !processedEvtSetCursor && m_cursor.Ok() ) { - id = WXK_TAB; - break; + hcursor = GetHcursorOf(m_cursor); } - default: + + if ( !GetParent() ) { - tempControlDown = TRUE; - id = id + 96; + if ( isBusy ) + { + hcursor = wxGetCurrentBusyCursor(); + } + else if ( !hcursor ) + { + const wxCursor *cursor = wxGetGlobalCursor(); + if ( cursor && cursor->Ok() ) + { + hcursor = GetHcursorOf(*cursor); + } + } } - } } - } - else - if ((id = wxCharCodeMSWToWX(wParam)) == 0) - id = -1; - if (id > -1) - { - wxKeyEvent event(wxEVT_CHAR); - event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE); - event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE); - if ((HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN) - event.m_altDown = TRUE; + if ( hcursor ) + { + ::SetCursor(hcursor); - event.m_eventObject = this; - event.m_keyCode = id; - event.SetTimestamp(wxApp::sm_lastMessageTime); /* MATTHEW: timeStamp */ - - POINT pt ; - GetCursorPos(&pt) ; - RECT rect ; - GetWindowRect((HWND) GetHWND(),&rect) ; - pt.x -= rect.left ; - pt.y -= rect.top ; - -/* - float fx,fy ; - fx = (float)pt.x ; - fy = (float)pt.y ; - MSWDeviceToLogical(&fx,&fy) ; - CalcUnscrolledPosition((int)fx,(int)fy,&event.m_x,&event.m_y) ; -*/ - event.m_x = pt.x; event.m_y = pt.y; + // cursor set, stop here + return TRUE; + } +#endif // __WXMICROWIN__ -#if WXWIN_COMPATIBILITY - GetEventHandler()->OldOnChar(event); -#else - if (!GetEventHandler()->ProcessEvent(event)) - Default(); -#endif - } + // pass up the window chain + return FALSE; } -void wxWindow::MSWOnJoyDown(const int joystick, const int x, const int y, const WXUINT flags) +// --------------------------------------------------------------------------- +// owner drawn stuff +// --------------------------------------------------------------------------- + +bool wxWindowMSW::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct) { - int buttons = 0; - int change = 0; - if (flags & JOY_BUTTON1CHG) - change = wxJOY_BUTTON1; - if (flags & JOY_BUTTON2CHG) - change = wxJOY_BUTTON2; - if (flags & JOY_BUTTON3CHG) - change = wxJOY_BUTTON3; - if (flags & JOY_BUTTON4CHG) - change = wxJOY_BUTTON4; +#if wxUSE_OWNER_DRAWN - if (flags & JOY_BUTTON1) - buttons |= wxJOY_BUTTON1; - if (flags & JOY_BUTTON2) - buttons |= wxJOY_BUTTON2; - if (flags & JOY_BUTTON3) - buttons |= wxJOY_BUTTON3; - if (flags & JOY_BUTTON4) - buttons |= wxJOY_BUTTON4; +#if wxUSE_MENUS_NATIVE + // is it a menu item? + DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct; + if ( id == 0 && pDrawStruct->CtlType == ODT_MENU ) + { + wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData); + + wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE ); + + // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent + // the DC from being released + wxDCTemp dc((WXHDC)pDrawStruct->hDC); + wxRect rect(pDrawStruct->rcItem.left, pDrawStruct->rcItem.top, + pDrawStruct->rcItem.right - pDrawStruct->rcItem.left, + pDrawStruct->rcItem.bottom - pDrawStruct->rcItem.top); + + return pMenuItem->OnDrawItem + ( + dc, + rect, + (wxOwnerDrawn::wxODAction)pDrawStruct->itemAction, + (wxOwnerDrawn::wxODStatus)pDrawStruct->itemState + ); + } +#endif // wxUSE_MENUS_NATIVE - wxJoystickEvent event(wxEVT_JOY_BUTTON_DOWN, buttons, joystick, change); - event.SetPosition(wxPoint(x, y)); - event.SetEventObject(this); +#if wxUSE_CONTROLS + wxWindow *item = FindItem(id); + if ( item && item->IsKindOf(CLASSINFO(wxControl)) ) + { + return ((wxControl *)item)->MSWOnDraw(itemStruct); + } +#endif // wxUSE_CONTROLS + +#endif // USE_OWNER_DRAWN - GetEventHandler()->ProcessEvent(event); + return FALSE; } -void wxWindow::MSWOnJoyUp(const int joystick, const int x, const int y, const WXUINT flags) +bool wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct) { - int buttons = 0; - int change = 0; - if (flags & JOY_BUTTON1CHG) - change = wxJOY_BUTTON1; - if (flags & JOY_BUTTON2CHG) - change = wxJOY_BUTTON2; - if (flags & JOY_BUTTON3CHG) - change = wxJOY_BUTTON3; - if (flags & JOY_BUTTON4CHG) - change = wxJOY_BUTTON4; +#if wxUSE_OWNER_DRAWN + // is it a menu item? + MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct; + if ( id == 0 && pMeasureStruct->CtlType == ODT_MENU ) + { + wxMenuItem *pMenuItem = (wxMenuItem *)(pMeasureStruct->itemData); - if (flags & JOY_BUTTON1) - buttons |= wxJOY_BUTTON1; - if (flags & JOY_BUTTON2) - buttons |= wxJOY_BUTTON2; - if (flags & JOY_BUTTON3) - buttons |= wxJOY_BUTTON3; - if (flags & JOY_BUTTON4) - buttons |= wxJOY_BUTTON4; + wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE ); - wxJoystickEvent event(wxEVT_JOY_BUTTON_UP, buttons, joystick, change); - event.SetPosition(wxPoint(x, y)); - event.SetEventObject(this); + return pMenuItem->OnMeasureItem(&pMeasureStruct->itemWidth, + &pMeasureStruct->itemHeight); + } - GetEventHandler()->ProcessEvent(event); + wxWindow *item = FindItem(id); + if ( item && item->IsKindOf(CLASSINFO(wxControl)) ) + { + return ((wxControl *)item)->MSWOnMeasure(itemStruct); + } +#endif // owner-drawn menus + return FALSE; } -void wxWindow::MSWOnJoyMove(const int joystick, const int x, const int y, const WXUINT flags) +// --------------------------------------------------------------------------- +// colours and palettes +// --------------------------------------------------------------------------- + +bool wxWindowMSW::HandleSysColorChange() { - int buttons = 0; - if (flags & JOY_BUTTON1) - buttons |= wxJOY_BUTTON1; - if (flags & JOY_BUTTON2) - buttons |= wxJOY_BUTTON2; - if (flags & JOY_BUTTON3) - buttons |= wxJOY_BUTTON3; - if (flags & JOY_BUTTON4) - buttons |= wxJOY_BUTTON4; + wxSysColourChangedEvent event; + event.SetEventObject(this); + + (void)GetEventHandler()->ProcessEvent(event); + + // always let the system carry on the default processing to allow the + // native controls to react to the colours update + return FALSE; +} - wxJoystickEvent event(wxEVT_JOY_MOVE, buttons, joystick, 0); - event.SetPosition(wxPoint(x, y)); +bool wxWindowMSW::HandleDisplayChange() +{ + wxDisplayChangedEvent event; event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); + return GetEventHandler()->ProcessEvent(event); } -void wxWindow::MSWOnJoyZMove(const int joystick, const int z, const WXUINT flags) +bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush, + WXHDC pDC, + WXHWND pWnd, + WXUINT nCtlColor, + WXUINT message, + WXWPARAM wParam, + WXLPARAM lParam) { - int buttons = 0; - if (flags & JOY_BUTTON1) - buttons |= wxJOY_BUTTON1; - if (flags & JOY_BUTTON2) - buttons |= wxJOY_BUTTON2; - if (flags & JOY_BUTTON3) - buttons |= wxJOY_BUTTON3; - if (flags & JOY_BUTTON4) - buttons |= wxJOY_BUTTON4; +#ifndef __WXMICROWIN__ + WXHBRUSH hBrush = 0; - wxJoystickEvent event(wxEVT_JOY_ZMOVE, buttons, joystick, 0); - event.SetZPosition(z); - event.SetEventObject(this); + if ( nCtlColor == CTLCOLOR_DLG ) + { + hBrush = OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam); + } +#if wxUSE_CONTROLS + else + { + wxControl *item = (wxControl *)FindItemByHWND(pWnd, TRUE); + if ( item ) + hBrush = item->OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam); + } +#endif // wxUSE_CONTROLS + + if ( hBrush ) + *brush = hBrush; - GetEventHandler()->ProcessEvent(event); + return hBrush != 0; +#else // __WXMICROWIN__ + return FALSE; +#endif } -void wxWindow::MSWOnVScroll(const WXWORD wParam, const WXWORD pos, const WXHWND control) +// Define for each class of dialog and control +WXHBRUSH wxWindowMSW::OnCtlColor(WXHDC WXUNUSED(hDC), + WXHWND WXUNUSED(hWnd), + WXUINT WXUNUSED(nCtlColor), + WXUINT WXUNUSED(message), + WXWPARAM WXUNUSED(wParam), + WXLPARAM WXUNUSED(lParam)) { - if (control) - { - wxWindow *child = wxFindWinFromHandle(control); - if ( child ) - child->MSWOnVScroll(wParam, pos, control); - return; - } + return (WXHBRUSH)0; +} - wxScrollEvent event; - event.SetPosition(pos); - event.SetOrientation(wxVERTICAL); - event.m_eventObject = this; +bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange) +{ +#if wxUSE_PALETTE + // same as below except we don't respond to our own messages + if ( hWndPalChange != GetHWND() ) + { + // check to see if we our our parents have a custom palette + wxWindow *win = this; + while ( win && !win->HasCustomPalette() ) + { + win = win->GetParent(); + } - switch ( wParam ) - { - case SB_TOP: - event.m_eventType = wxEVENT_TYPE_SCROLL_TOP; - break; + if ( win && win->HasCustomPalette() ) + { + // realize the palette to see whether redrawing is needed + HDC hdc = ::GetDC((HWND) hWndPalChange); + win->m_palette.SetHPALETTE((WXHPALETTE) + ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE)); + + int result = ::RealizePalette(hdc); + + // restore the palette (before releasing the DC) + win->m_palette.SetHPALETTE((WXHPALETTE) + ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE)); + ::RealizePalette(hdc); + ::ReleaseDC((HWND) hWndPalChange, hdc); + + // now check for the need to redraw + if (result > 0) + InvalidateRect((HWND) hWndPalChange, NULL, TRUE); + } - case SB_BOTTOM: - event.m_eventType = wxEVENT_TYPE_SCROLL_BOTTOM; - break; + } +#endif // wxUSE_PALETTE - case SB_LINEUP: - event.m_eventType = wxEVENT_TYPE_SCROLL_LINEUP; - break; + wxPaletteChangedEvent event(GetId()); + event.SetEventObject(this); + event.SetChangedWindow(wxFindWinFromHandle(hWndPalChange)); - case SB_LINEDOWN: - event.m_eventType = wxEVENT_TYPE_SCROLL_LINEDOWN; - break; + return GetEventHandler()->ProcessEvent(event); +} - case SB_PAGEUP: - event.m_eventType = wxEVENT_TYPE_SCROLL_PAGEUP; - break; +bool wxWindowMSW::HandleQueryNewPalette() +{ - case SB_PAGEDOWN: - event.m_eventType = wxEVENT_TYPE_SCROLL_PAGEDOWN; - break; +#if wxUSE_PALETTE + // check to see if we our our parents have a custom palette + wxWindow *win = this; + while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent(); + if (win->HasCustomPalette()) { + /* realize the palette to see whether redrawing is needed */ + HDC hdc = GetDC((HWND) GetHWND()); + win->m_palette.SetHPALETTE( (WXHPALETTE) + ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), FALSE) ); - case SB_THUMBTRACK: - case SB_THUMBPOSITION: - event.m_eventType = wxEVENT_TYPE_SCROLL_THUMBTRACK; - break; + int result = ::RealizePalette(hdc); + /* restore the palette (before releasing the DC) */ + win->m_palette.SetHPALETTE( (WXHPALETTE) + ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), TRUE) ); + ::RealizePalette(hdc); + ::ReleaseDC((HWND) GetHWND(), hdc); + /* now check for the need to redraw */ + if (result > 0) + ::InvalidateRect((HWND) GetHWND(), NULL, TRUE); + } +#endif // wxUSE_PALETTE - default: - return; - break; - } + wxQueryNewPaletteEvent event(GetId()); + event.SetEventObject(this); - if (!GetEventHandler()->ProcessEvent(event)) -#if WXWIN_COMPATIBILITY - GetEventHandler()->OldOnScroll(event); -#else - Default(); -#endif + return GetEventHandler()->ProcessEvent(event) && event.GetPaletteRealized(); } -void wxWindow::MSWOnHScroll( const WXWORD wParam, const WXWORD pos, const WXHWND control) +// Responds to colour changes: passes event on to children. +void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event)) { - if (control) - { - wxWindow *child = wxFindWinFromHandle(control); - if ( child ) - child->MSWOnHScroll(wParam, pos, control); - return; - } + // the top level window also reset the standard colour map as it might have + // changed (there is no need to do it for the non top level windows as we + // only have to do it once) + if ( IsTopLevel() ) + { + // FIXME-MT + gs_hasStdCmap = FALSE; + } + wxWindowList::Node *node = GetChildren().GetFirst(); + while ( node ) + { + // Only propagate to non-top-level windows because Windows already + // sends this event to all top-level ones + wxWindow *win = node->GetData(); + if ( !win->IsTopLevel() ) + { + // we need to send the real WM_SYSCOLORCHANGE and not just trigger + // EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for + // the standard controls + ::SendMessage(GetHwndOf(win), WM_SYSCOLORCHANGE, 0, 0); + } - wxScrollEvent event; - event.SetPosition(pos); - event.SetOrientation(wxHORIZONTAL); - event.m_eventObject = this; + node = node->GetNext(); + } - switch ( wParam ) - { - case SB_TOP: - event.m_eventType = wxEVENT_TYPE_SCROLL_TOP; - break; + // update the colours we use if they were not set explicitly by the user: + // this must be done or OnCtlColor() would continue to use the old colours + if ( !m_hasFgCol ) + { + m_foregroundColour = wxSystemSettings:: + GetSystemColour(wxSYS_COLOUR_WINDOWTEXT); + } - case SB_BOTTOM: - event.m_eventType = wxEVENT_TYPE_SCROLL_BOTTOM; - break; + if ( !m_hasBgCol ) + { + m_backgroundColour = wxSystemSettings:: + GetSystemColour(wxSYS_COLOUR_BTNFACE); + } +} - case SB_LINEUP: - event.m_eventType = wxEVENT_TYPE_SCROLL_LINEUP; - break; +extern wxCOLORMAP *wxGetStdColourMap() +{ + static COLORREF s_stdColours[wxSTD_COL_MAX]; + static wxCOLORMAP s_cmap[wxSTD_COL_MAX]; - case SB_LINEDOWN: - event.m_eventType = wxEVENT_TYPE_SCROLL_LINEDOWN; - break; + if ( !gs_hasStdCmap ) + { + static bool s_coloursInit = FALSE; - case SB_PAGEUP: - event.m_eventType = wxEVENT_TYPE_SCROLL_PAGEUP; - break; + if ( !s_coloursInit ) + { + // When a bitmap is loaded, the RGB values can change (apparently + // because Windows adjusts them to care for the old programs always + // using 0xc0c0c0 while the transparent colour for the new Windows + // versions is different). But we do this adjustment ourselves so + // we want to avoid Windows' "help" and for this we need to have a + // reference bitmap which can tell us what the RGB values change + // to. + wxBitmap stdColourBitmap(_T("wxBITMAP_STD_COLOURS")); + if ( stdColourBitmap.Ok() ) + { + // the pixels in the bitmap must correspond to wxSTD_COL_XXX! + wxASSERT_MSG( stdColourBitmap.GetWidth() == wxSTD_COL_MAX, + _T("forgot to update wxBITMAP_STD_COLOURS!") ); + + wxMemoryDC memDC; + memDC.SelectObject(stdColourBitmap); + + wxColour colour; + for ( size_t i = 0; i < WXSIZEOF(s_stdColours); i++ ) + { + memDC.GetPixel(i, 0, &colour); + s_stdColours[i] = wxColourToRGB(colour); + } + } + else // wxBITMAP_STD_COLOURS couldn't be loaded + { + s_stdColours[0] = RGB(000,000,000); // black + s_stdColours[1] = RGB(128,128,128); // dark grey + s_stdColours[2] = RGB(192,192,192); // light grey + s_stdColours[3] = RGB(255,255,255); // white + //s_stdColours[4] = RGB(000,000,255); // blue + //s_stdColours[5] = RGB(255,000,255); // magenta + } - case SB_PAGEDOWN: - event.m_eventType = wxEVENT_TYPE_SCROLL_PAGEDOWN; - break; + s_coloursInit = TRUE; + } - case SB_THUMBTRACK: - case SB_THUMBPOSITION: - event.m_eventType = wxEVENT_TYPE_SCROLL_THUMBTRACK; - break; + gs_hasStdCmap = TRUE; - default: - return; - break; - } - if (!GetEventHandler()->ProcessEvent(event)) -#if WXWIN_COMPATIBILITY - GetEventHandler()->OldOnScroll(event); -#else - Default(); -#endif -} + // create the colour map +#define INIT_CMAP_ENTRY(col) \ + s_cmap[wxSTD_COL_##col].from = s_stdColours[wxSTD_COL_##col]; \ + s_cmap[wxSTD_COL_##col].to = ::GetSysColor(COLOR_##col) -void wxWindow::MSWOnShow(bool show, int status) -{ - wxShowEvent event(GetId(), show); - event.m_eventObject = this; - GetEventHandler()->ProcessEvent(event); -} + INIT_CMAP_ENTRY(BTNTEXT); + INIT_CMAP_ENTRY(BTNSHADOW); + INIT_CMAP_ENTRY(BTNFACE); + INIT_CMAP_ENTRY(BTNHIGHLIGHT); -bool wxWindow::MSWOnInitDialog(WXHWND WXUNUSED(hWndFocus)) -{ - wxInitDialogEvent event(GetId()); - event.m_eventObject = this; - GetEventHandler()->ProcessEvent(event); - return TRUE; -} +#undef INIT_CMAP_ENTRY + } -void wxWindow::InitDialog(void) -{ - wxInitDialogEvent event(GetId()); - event.SetEventObject( this ); - GetEventHandler()->ProcessEvent(event); + return s_cmap; } -// Default init dialog behaviour is to transfer data to window -void wxWindow::OnInitDialog(wxInitDialogEvent& event) -{ - TransferDataToWindow(); -} +// --------------------------------------------------------------------------- +// painting +// --------------------------------------------------------------------------- -void wxGetCharSize(WXHWND wnd, int *x, int *y,wxFont *the_font) +bool wxWindowMSW::HandlePaint() { - TEXTMETRIC tm; - HDC dc = ::GetDC((HWND) wnd); - HFONT fnt =0; - HFONT was = 0; - if (the_font) - { -#if DEBUG > 1 - wxDebugMsg("wxGetCharSize: Selecting HFONT %X\n", fnt); -#endif -// the_font->UseResource(); -// the_font->RealizeResource(); - if ((fnt=(HFONT) the_font->GetResourceHandle())) - was = SelectObject(dc,fnt) ; - } - GetTextMetrics(dc, &tm); - if (the_font && fnt && was) - { -#if DEBUG > 1 - wxDebugMsg("wxGetCharSize: Selecting old HFONT %X\n", was); -#endif - SelectObject(dc,was) ; - } - ReleaseDC((HWND)wnd, dc); - *x = tm.tmAveCharWidth; - *y = tm.tmHeight + tm.tmExternalLeading; +#ifdef __WIN32__ + HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle + if ( !hRegion ) + wxLogLastError(wxT("CreateRectRgn")); + if ( ::GetUpdateRgn(GetHwnd(), hRegion, FALSE) == ERROR ) + wxLogLastError(wxT("GetUpdateRgn")); + + m_updateRegion = wxRegion((WXHRGN) hRegion); +#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); -// if (the_font) -// the_font->ReleaseResource(); -} + bool processed = GetEventHandler()->ProcessEvent(event); -// Returns 0 if was a normal ASCII value, not a special key. This indicates that -// the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead. -int wxCharCodeMSWToWX(int keySym) -{ - int id = 0; - switch (keySym) - { - case VK_CANCEL: id = WXK_CANCEL; break; - case VK_BACK: id = WXK_BACK; break; - case VK_TAB: id = WXK_TAB; break; - case VK_CLEAR: id = WXK_CLEAR; break; - case VK_RETURN: id = WXK_RETURN; break; - case VK_SHIFT: id = WXK_SHIFT; break; - case VK_CONTROL: id = WXK_CONTROL; break; - case VK_MENU : id = WXK_MENU; break; - case VK_PAUSE: id = WXK_PAUSE; break; - case VK_SPACE: id = WXK_SPACE; break; - case VK_ESCAPE: id = WXK_ESCAPE; break; - case VK_PRIOR: id = WXK_PRIOR; break; - case VK_NEXT : id = WXK_NEXT; break; - case VK_END: id = WXK_END; break; - case VK_HOME : id = WXK_HOME; break; - case VK_LEFT : id = WXK_LEFT; break; - case VK_UP: id = WXK_UP; break; - case VK_RIGHT: id = WXK_RIGHT; break; - case VK_DOWN : id = WXK_DOWN; break; - case VK_SELECT: id = WXK_SELECT; break; - case VK_PRINT: id = WXK_PRINT; break; - case VK_EXECUTE: id = WXK_EXECUTE; break; - case VK_INSERT: id = WXK_INSERT; break; - case VK_DELETE: id = WXK_DELETE; break; - case VK_HELP : id = WXK_HELP; break; - case VK_NUMPAD0: id = WXK_NUMPAD0; break; - case VK_NUMPAD1: id = WXK_NUMPAD1; break; - case VK_NUMPAD2: id = WXK_NUMPAD2; break; - case VK_NUMPAD3: id = WXK_NUMPAD3; break; - case VK_NUMPAD4: id = WXK_NUMPAD4; break; - case VK_NUMPAD5: id = WXK_NUMPAD5; break; - case VK_NUMPAD6: id = WXK_NUMPAD6; break; - case VK_NUMPAD7: id = WXK_NUMPAD7; break; - case VK_NUMPAD8: id = WXK_NUMPAD8; break; - case VK_NUMPAD9: id = WXK_NUMPAD9; break; - case VK_MULTIPLY: id = WXK_MULTIPLY; break; - case VK_ADD: id = WXK_ADD; break; - case VK_SUBTRACT: id = WXK_SUBTRACT; break; - case VK_DECIMAL: id = WXK_DECIMAL; break; - case VK_DIVIDE: id = WXK_DIVIDE; break; - case VK_F1: id = WXK_F1; break; - case VK_F2: id = WXK_F2; break; - case VK_F3: id = WXK_F3; break; - case VK_F4: id = WXK_F4; break; - case VK_F5: id = WXK_F5; break; - case VK_F6: id = WXK_F6; break; - case VK_F7: id = WXK_F7; break; - case VK_F8: id = WXK_F8; break; - case VK_F9: id = WXK_F9; break; - case VK_F10: id = WXK_F10; break; - case VK_F11: id = WXK_F11; break; - case VK_F12: id = WXK_F12; break; - case VK_F13: id = WXK_F13; break; - case VK_F14: id = WXK_F14; break; - case VK_F15: id = WXK_F15; break; - case VK_F16: id = WXK_F16; break; - case VK_F17: id = WXK_F17; break; - case VK_F18: id = WXK_F18; break; - case VK_F19: id = WXK_F19; break; - case VK_F20: id = WXK_F20; break; - case VK_F21: id = WXK_F21; break; - case VK_F22: id = WXK_F22; break; - case VK_F23: id = WXK_F23; break; - case VK_F24: id = WXK_F24; break; - case VK_NUMLOCK: id = WXK_NUMLOCK; break; - case VK_SCROLL: id = WXK_SCROLL; break; - default: - { - return 0; - } - } - return id; + // note that we must generate NC event after the normal one as otherwise + // BeginPaint() will happily overwrite our decorations with the background + // colour + wxNcPaintEvent eventNc(m_windowId); + eventNc.SetEventObject(this); + GetEventHandler()->ProcessEvent(eventNc); + + return processed; } -int wxCharCodeWXToMSW(int id, bool *isVirtual) +// Can be called from an application's OnPaint handler +void wxWindowMSW::OnPaint(wxPaintEvent& event) { - *isVirtual = TRUE; - int keySym = 0; - switch (id) - { - case WXK_CANCEL: keySym = VK_CANCEL; break; - case WXK_CLEAR: keySym = VK_CLEAR; break; - case WXK_SHIFT: keySym = VK_SHIFT; break; - case WXK_CONTROL: keySym = VK_CONTROL; break; - case WXK_MENU : keySym = VK_MENU; break; - case WXK_PAUSE: keySym = VK_PAUSE; break; - case WXK_PRIOR: keySym = VK_PRIOR; break; - case WXK_NEXT : keySym = VK_NEXT; break; - case WXK_END: keySym = VK_END; break; - case WXK_HOME : keySym = VK_HOME; break; - case WXK_LEFT : keySym = VK_LEFT; break; - case WXK_UP: keySym = VK_UP; break; - case WXK_RIGHT: keySym = VK_RIGHT; break; - case WXK_DOWN : keySym = VK_DOWN; break; - case WXK_SELECT: keySym = VK_SELECT; break; - case WXK_PRINT: keySym = VK_PRINT; break; - case WXK_EXECUTE: keySym = VK_EXECUTE; break; - case WXK_INSERT: keySym = VK_INSERT; break; - case WXK_DELETE: keySym = VK_DELETE; break; - case WXK_HELP : keySym = VK_HELP; break; - case WXK_NUMPAD0: keySym = VK_NUMPAD0; break; - case WXK_NUMPAD1: keySym = VK_NUMPAD1; break; - case WXK_NUMPAD2: keySym = VK_NUMPAD2; break; - case WXK_NUMPAD3: keySym = VK_NUMPAD3; break; - case WXK_NUMPAD4: keySym = VK_NUMPAD4; break; - case WXK_NUMPAD5: keySym = VK_NUMPAD5; break; - case WXK_NUMPAD6: keySym = VK_NUMPAD6; break; - case WXK_NUMPAD7: keySym = VK_NUMPAD7; break; - case WXK_NUMPAD8: keySym = VK_NUMPAD8; break; - case WXK_NUMPAD9: keySym = VK_NUMPAD9; break; - case WXK_MULTIPLY: keySym = VK_MULTIPLY; break; - case WXK_ADD: keySym = VK_ADD; break; - case WXK_SUBTRACT: keySym = VK_SUBTRACT; break; - case WXK_DECIMAL: keySym = VK_DECIMAL; break; - case WXK_DIVIDE: keySym = VK_DIVIDE; break; - case WXK_F1: keySym = VK_F1; break; - case WXK_F2: keySym = VK_F2; break; - case WXK_F3: keySym = VK_F3; break; - case WXK_F4: keySym = VK_F4; break; - case WXK_F5: keySym = VK_F5; break; - case WXK_F6: keySym = VK_F6; break; - case WXK_F7: keySym = VK_F7; break; - case WXK_F8: keySym = VK_F8; break; - case WXK_F9: keySym = VK_F9; break; - case WXK_F10: keySym = VK_F10; break; - case WXK_F11: keySym = VK_F11; break; - case WXK_F12: keySym = VK_F12; break; - case WXK_F13: keySym = VK_F13; break; - case WXK_F14: keySym = VK_F14; break; - case WXK_F15: keySym = VK_F15; break; - case WXK_F16: keySym = VK_F16; break; - case WXK_F17: keySym = VK_F17; break; - case WXK_F18: keySym = VK_F18; break; - case WXK_F19: keySym = VK_F19; break; - case WXK_F20: keySym = VK_F20; break; - case WXK_F21: keySym = VK_F21; break; - case WXK_F22: keySym = VK_F22; break; - case WXK_F23: keySym = VK_F23; break; - case WXK_F24: keySym = VK_F24; break; - case WXK_NUMLOCK: keySym = VK_NUMLOCK; break; - case WXK_SCROLL: keySym = VK_SCROLL; break; - default: +#ifdef __WXUNIVERSAL__ + event.Skip(); +#else + HDC hDC = (HDC) wxPaintDC::FindDCInCache((wxWindow*) event.GetEventObject()); + if (hDC != 0) { - *isVirtual = FALSE; - keySym = id; - break; + MSWDefWindowProc(WM_PAINT, (WPARAM) hDC, 0); } - } - return keySym; +#endif } -// Caret manipulation -void wxWindow::CreateCaret(const int w, const int h) +bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc) { - m_caretWidth = w; - m_caretHeight = h; - m_caretEnabled = TRUE; -} + // Prevents flicker when dragging + if ( ::IsIconic(GetHwnd()) ) + return TRUE; -void wxWindow::CreateCaret(const wxBitmap *WXUNUSED(bitmap)) -{ - // Not implemented -} + wxDCTemp dc(hdc); -void wxWindow::ShowCaret(const bool show) -{ - if (m_caretEnabled) - { - if (show) - ::ShowCaret((HWND) GetHWND()); - else - ::HideCaret((HWND) GetHWND()); - m_caretShown = show; - } -} + dc.SetHDC(hdc); + dc.SetWindow((wxWindow *)this); + dc.BeginDrawing(); -void wxWindow::DestroyCaret(void) -{ - m_caretEnabled = FALSE; -} + wxEraseEvent event(m_windowId, &dc); + event.SetEventObject(this); + bool rc = GetEventHandler()->ProcessEvent(event); -void wxWindow::SetCaretPos(const int x, const int y) -{ - ::SetCaretPos(x, y); + dc.EndDrawing(); + + // must be called manually as ~wxDC doesn't do anything for wxDCTemp + dc.SelectOldObjects(hdc); + + return rc; } -void wxWindow::GetCaretPos(int *x, int *y) const +void wxWindowMSW::OnEraseBackground(wxEraseEvent& event) { - POINT point; - ::GetCaretPos(&point); - *x = point.x; - *y = point.y; -} + RECT rect; + ::GetClientRect(GetHwnd(), &rect); -/* - * Update iterator. Use from within OnPaint. - */ + COLORREF ref = PALETTERGB(m_backgroundColour.Red(), + m_backgroundColour.Green(), + m_backgroundColour.Blue()); + HBRUSH hBrush = ::CreateSolidBrush(ref); + if ( !hBrush ) + wxLogLastError(wxT("CreateSolidBrush")); -static RECT gs_UpdateRect; + HDC hdc = (HDC)event.GetDC()->GetHDC(); -wxUpdateIterator::wxUpdateIterator(wxWindow* wnd) -{ - current = 0; //start somewhere... -#if defined(__WIN32__) && !defined(__win32s__) - rlist = NULL; //make sure I don't free randomly - int len = GetRegionData((HRGN) wnd->m_updateRgn,0,NULL); //Get buffer size - if (len) - { - rlist = (WXRGNDATA *) (RGNDATA *)new char[len]; - GetRegionData((HRGN) wnd->m_updateRgn,len, (RGNDATA *)rlist); - rp = (void *)(RECT*) ((RGNDATA *)rlist)->Buffer; - rects = ((RGNDATA *)rlist)->rdh.nCount; - } - else -#endif - { - gs_UpdateRect.left = wnd->m_updateRect.x; - gs_UpdateRect.top = wnd->m_updateRect.y; - gs_UpdateRect.right = wnd->m_updateRect.x + wnd->m_updateRect.width; - gs_UpdateRect.bottom = wnd->m_updateRect.y + wnd->m_updateRect.height; - rects = 1; - rp = (void *)&gs_UpdateRect; //Only one available in Win16,32s - } -} + int mode = ::SetMapMode(hdc, MM_TEXT); -wxUpdateIterator::~wxUpdateIterator(void) -{ -#ifdef __WIN32__ -#ifndef __win32s__ - if (rlist) delete (RGNDATA *) rlist; -#endif -#endif + ::FillRect(hdc, &rect, hBrush); + ::DeleteObject(hBrush); + ::SetMapMode(hdc, mode); } -wxUpdateIterator::operator int (void) -{ - if (current < rects) - { - return TRUE; - } - else - { - return FALSE; - } -} +// --------------------------------------------------------------------------- +// moving and resizing +// --------------------------------------------------------------------------- -wxUpdateIterator* wxUpdateIterator::operator ++(int) +bool wxWindowMSW::HandleMinimize() { - current++; - return this; -} + wxIconizeEvent event(m_windowId); + event.SetEventObject(this); -void wxUpdateIterator::GetRect(wxRect *rect) -{ - RECT *mswRect = ((RECT *)rp)+current; //ought to error check this... - rect->x = mswRect->left; - rect->y = mswRect->top; - rect->width = mswRect->right - mswRect->left; - rect->height = mswRect->bottom - mswRect->top; + return GetEventHandler()->ProcessEvent(event); } -int wxUpdateIterator::GetX() +bool wxWindowMSW::HandleMaximize() { - return ((RECT*)rp)[current].left; -} + wxMaximizeEvent event(m_windowId); + event.SetEventObject(this); -int wxUpdateIterator::GetY() -{ - return ((RECT *)rp)[current].top; + return GetEventHandler()->ProcessEvent(event); } -int wxUpdateIterator::GetW() +bool wxWindowMSW::HandleMove(int x, int y) { - return ((RECT *)rp)[current].right-GetX(); + wxMoveEvent event(wxPoint(x, y), m_windowId); + event.SetEventObject(this); + + return GetEventHandler()->ProcessEvent(event); } -int wxUpdateIterator::GetH() +bool wxWindowMSW::HandleSize(int w, int h, WXUINT WXUNUSED(flag)) { - return ((RECT *)rp)[current].bottom-GetY(); + wxSizeEvent event(wxSize(w, h), m_windowId); + event.SetEventObject(this); + + return GetEventHandler()->ProcessEvent(event); } -wxWindow *wxGetActiveWindow(void) +bool wxWindowMSW::HandleGetMinMaxInfo(void *mmInfo) { - HWND hWnd = GetActiveWindow(); - if (hWnd != 0) - { - return wxFindWinFromHandle((WXHWND) hWnd); - } - return NULL; -} + MINMAXINFO *info = (MINMAXINFO *)mmInfo; -// Windows keyboard hook. Allows interception of e.g. F1, ESCAPE -// in active frames and dialogs, regardless of where the focus is. -static HHOOK wxTheKeyboardHook = 0; -static FARPROC wxTheKeyboardHookProc = 0; -int APIENTRY _EXPORT - wxKeyboardHook(int nCode, WORD wParam, DWORD lParam); + bool rc = FALSE; -void wxSetKeyboardHook(bool doIt) -{ - if (doIt) - { - wxTheKeyboardHookProc = MakeProcInstance((FARPROC) wxKeyboardHook, wxGetInstance()); - wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(), -#ifdef __WIN32__ - GetCurrentThreadId()); -// (DWORD)GetCurrentProcess()); // This is another possibility. Which is right? -#else - GetCurrentTask()); -#endif - } - else - { - UnhookWindowsHookEx(wxTheKeyboardHook); - FreeProcInstance(wxTheKeyboardHookProc); - } -} + int minWidth = GetMinWidth(), + minHeight = GetMinHeight(), + maxWidth = GetMaxWidth(), + maxHeight = GetMaxHeight(); -int APIENTRY _EXPORT - wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) -{ - DWORD hiWord = HIWORD(lParam); - if (nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0)) - { - int id; - if ((id = wxCharCodeMSWToWX(wParam)) != 0) + if ( minWidth != -1 ) + { + info->ptMinTrackSize.x = minWidth; + rc = TRUE; + } + + if ( minHeight != -1 ) { - wxKeyEvent event(wxEVT_CHAR_HOOK); - if ((HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN) - event.m_altDown = TRUE; + info->ptMinTrackSize.y = minHeight; + rc = TRUE; + } - event.m_eventObject = NULL; - event.m_keyCode = id; -/* begin Albert's fix for control and shift key 26.5 */ - event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE); - event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE); -/* end Albert's fix for control and shift key 26.5 */ - event.SetTimestamp(wxApp::sm_lastMessageTime); /* MATTHEW: timeStamp */ + if ( maxWidth != -1 ) + { + info->ptMaxTrackSize.x = maxWidth; + rc = TRUE; + } -#if WXWIN_COMPATIBILITY - if ( wxTheApp && wxTheApp->OldOnCharHook(event) ) - return 1; -#endif - wxWindow *win = wxGetActiveWindow(); - if (win) - { - if (win->GetEventHandler()->ProcessEvent(event)) - return 1; - } - else - { - if ( wxTheApp && wxTheApp->ProcessEvent(event) ) - return 1; - } + if ( maxHeight != -1 ) + { + info->ptMaxTrackSize.y = maxHeight; + rc = TRUE; } - } - return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam); -} -void wxWindow::SetSizeHints(const int minW, const int minH, const int maxW, const int maxH, const int WXUNUSED(incW), const int WXUNUSED(incH)) -{ - m_minSizeX = minW; - m_minSizeY = minH; - m_maxSizeX = maxW; - m_maxSizeY = maxH; + return rc; } -void wxWindow::Centre(const int direction) +// --------------------------------------------------------------------------- +// command messages +// --------------------------------------------------------------------------- + +bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) { - int x, y, width, height, panel_width, panel_height, new_x, new_y; +#if wxUSE_MENUS_NATIVE + if ( !cmd && wxCurrentPopupMenu ) + { + wxMenu *popupMenu = wxCurrentPopupMenu; + wxCurrentPopupMenu = NULL; - wxWindow *father = (wxWindow *)GetParent(); - if (!father) - return; + return popupMenu->MSWCommand(cmd, id); + } +#endif // wxUSE_MENUS_NATIVE + + wxWindow *win = NULL; + + // first try to find it from HWND - this works even with the broken + // programs using the same ids for different controls + if ( control ) + { + win = wxFindWinFromHandle(control); + } - father->GetClientSize(&panel_width, &panel_height); - GetSize(&width, &height); - GetPosition(&x, &y); + // try the id + if ( !win ) + { + // must cast to a signed type before comparing with other ids! + win = FindItem((signed short)id); + } - new_x = -1; - new_y = -1; + if ( win ) + { + return win->MSWCommand(cmd, id); + } - if (direction & wxHORIZONTAL) - new_x = (int)((panel_width - width)/2); + // the messages sent from the in-place edit control used by the treectrl + // for label editing have id == 0, but they should _not_ be treated as menu + // messages (they are EN_XXX ones, in fact) so don't translate anything + // coming from a control to wxEVT_COMMAND_MENU_SELECTED + if ( !control ) + { + // If no child window, it may be an accelerator, e.g. for a popup menu + // command - if (direction & wxVERTICAL) - new_y = (int)((panel_height - height)/2); + wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED); + event.SetEventObject(this); + event.SetId(id); + event.SetInt(id); - SetSize(new_x, new_y, -1, -1); + return GetEventHandler()->ProcessEvent(event); + } +#if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__) + else + { + // the text ctrl which is logically part of wxSpinCtrl sends WM_COMMAND + // notifications to its parent which we want to reflect back to + // wxSpinCtrl + wxSpinCtrl *spin = wxSpinCtrl::GetSpinForTextCtrl(control); + if ( spin && spin->ProcessTextCommand(cmd, id) ) + return TRUE; + } +#endif // wxUSE_SPINCTRL + return FALSE; } -/* TODO (maybe) -void wxWindow::OnPaint(void) +bool wxWindowMSW::HandleSysCommand(WXWPARAM wParam, WXLPARAM WXUNUSED(lParam)) { - PaintSelectionHandles(); + // 4 bits are reserved + switch ( wParam & 0xFFFFFFF0 ) + { + case SC_MAXIMIZE: + return HandleMaximize(); + + case SC_MINIMIZE: + return HandleMinimize(); + } + + return FALSE; } -*/ -void wxWindow::WarpPointer (const int x_pos, const int y_pos) +// --------------------------------------------------------------------------- +// mouse events +// --------------------------------------------------------------------------- + +void wxWindowMSW::InitMouseEvent(wxMouseEvent& event, + int x, int y, + WXUINT flags) { - // Move the pointer to (x_pos,y_pos) coordinates. They are expressed in - // pixel coordinates, relatives to the canvas -- So, we first need to - // substract origin of the window, then convert to screen position + // our client coords are not quite the same as Windows ones + wxPoint pt = GetClientAreaOrigin(); + event.m_x = x - pt.x; + event.m_y = y - pt.y; - int x = x_pos; int y = y_pos; -/* Leave this to the app to decide (and/or wxScrolledWindow) - x -= m_xScrollPosition * m_xScrollPixelsPerLine; - y -= m_yScrollPosition * m_yScrollPixelsPerLine; -*/ - RECT rect; - GetWindowRect ((HWND) GetHWND(), &rect); + event.m_shiftDown = (flags & MK_SHIFT) != 0; + event.m_controlDown = (flags & MK_CONTROL) != 0; + event.m_leftDown = (flags & MK_LBUTTON) != 0; + event.m_middleDown = (flags & MK_MBUTTON) != 0; + event.m_rightDown = (flags & MK_RBUTTON) != 0; + event.m_altDown = (::GetKeyState(VK_MENU) & 0x80000000) != 0; - x += rect.left; - y += rect.top; + event.SetTimestamp(s_currentMsg.time); + event.m_eventObject = this; - SetCursorPos (x, y); +#if wxUSE_MOUSEEVENT_HACK + m_lastMouseX = x; + m_lastMouseY = y; + m_lastMouseEvent = event.GetEventType(); +#endif // wxUSE_MOUSEEVENT_HACK } -void wxWindow::MSWDeviceToLogical (float *x, float *y) const +bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags) { - // TODO - // Do we have a SetUserScale in wxWindow too, so we can - // get mouse events scaled? -/* - if (m_windowDC) - { - *x = m_windowDC->DeviceToLogicalX ((int) *x); - *y = m_windowDC->DeviceToLogicalY ((int) *y); - } -*/ + // the mouse events take consecutive IDs from WM_MOUSEFIRST to + // WM_MOUSELAST, so it's enough to substract WM_MOUSEMOVE == WM_MOUSEFIRST + // from the message id and take the value in the table to get wxWin event + // id + static const wxEventType eventsMouse[] = + { + wxEVT_MOTION, + wxEVT_LEFT_DOWN, + wxEVT_LEFT_UP, + wxEVT_LEFT_DCLICK, + wxEVT_RIGHT_DOWN, + wxEVT_RIGHT_UP, + wxEVT_RIGHT_DCLICK, + wxEVT_MIDDLE_DOWN, + wxEVT_MIDDLE_UP, + wxEVT_MIDDLE_DCLICK + }; + + wxMouseEvent event(eventsMouse[msg - WM_MOUSEMOVE]); + InitMouseEvent(event, x, y, flags); + + return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::MSWOnEraseBkgnd (const WXHDC pDC) +bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags) { - wxDC dc ; + if ( !m_mouseInWindow ) + { + // it would be wrong to assume that just because we get a mouse move + // event that the mouse is inside the window: although this is usually + // true, it is not if we had captured the mouse, so we need to check + // the mouse coordinates here + if ( !HasCapture() || IsMouseInWindow() ) + { + // Generate an ENTER event + m_mouseInWindow = TRUE; - dc.SetHDC(pDC); - dc.SetWindow(this); - dc.BeginDrawing(); + wxMouseEvent event(wxEVT_ENTER_WINDOW); + InitMouseEvent(event, x, y, flags); - wxEraseEvent event(m_windowId, &dc); - event.m_eventObject = this; - if (!GetEventHandler()->ProcessEvent(event)) - { - dc.EndDrawing(); - dc.SelectOldObjects(pDC); - return FALSE; + (void)GetEventHandler()->ProcessEvent(event); + } } - else + +#if wxUSE_MOUSEEVENT_HACK + // Window gets a click down message followed by a mouse move message even + // if position isn't changed! We want to discard the trailing move event + // if x and y are the same. + if ( (m_lastMouseEvent == wxEVT_RIGHT_DOWN || + m_lastMouseEvent == wxEVT_LEFT_DOWN || + m_lastMouseEvent == wxEVT_MIDDLE_DOWN) && + (m_lastMouseX == x && m_lastMouseY == y) ) { - dc.EndDrawing(); - dc.SelectOldObjects(pDC); + m_lastMouseEvent = wxEVT_MOTION; + + return FALSE; } +#endif // wxUSE_MOUSEEVENT_HACK - dc.SetHDC((WXHDC) NULL); - return TRUE; + return HandleMouseEvent(WM_MOUSEMOVE, x, y, flags); } -void wxWindow::OnEraseBackground(wxEraseEvent& event) -{ - RECT rect; - ::GetClientRect((HWND) GetHWND(), &rect); - HBRUSH hBrush = ::CreateSolidBrush(PALETTERGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue())); - int mode = ::SetMapMode((HDC) event.GetDC()->GetHDC(), MM_TEXT); +bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam) +{ +#if wxUSE_MOUSEWHEEL + wxMouseEvent event(wxEVT_MOUSEWHEEL); + InitMouseEvent(event, + GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam), + LOWORD(wParam)); + event.m_wheelRotation = (short)HIWORD(wParam); + event.m_wheelDelta = WHEEL_DELTA; -// ::GetClipBox((HDC) event.GetDC()->GetHDC(), &rect); - ::FillRect ((HDC) event.GetDC()->GetHDC(), &rect, hBrush); - ::DeleteObject(hBrush); - ::SetMapMode((HDC) event.GetDC()->GetHDC(), mode); -/* - // Less efficient version (and doesn't account for scrolling) - int w, h; - GetClientSize(& w, & h); - wxBrush *brush = wxTheBrushList->FindOrCreateBrush(& GetBackgroundColour(), wxSOLID); - event.GetDC()->SetBrush(brush); - event.GetDC()->SetPen(wxTRANSPARENT_PEN); +#ifdef __WIN32__ + static int s_linesPerRotation = -1; + if ( s_linesPerRotation == -1 ) + { + if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, + &s_linesPerRotation, 0)) + { + // this is not supposed to happen + wxLogLastError(_T("SystemParametersInfo(GETWHEELSCROLLLINES)")); - event.GetDC()->DrawRectangle(0, 0, w+1, h+1); -*/ -} + // the default is 3, so use it if SystemParametersInfo() failed + s_linesPerRotation = 3; + } + } +#else // Win16 + // no SystemParametersInfo() under Win16 + static const int s_linesPerRotation = 3; +#endif -#if WXWIN_COMPATIBILITY -void wxWindow::SetScrollRange(const int orient, const int range, const bool refresh) -{ -#if defined(__WIN95__) + event.m_linesPerAction = s_linesPerRotation; + return GetEventHandler()->ProcessEvent(event); - 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 = (HWND) GetHWND(); - if (hWnd) - ::SetScrollInfo(hWnd, dir, &info, refresh); #else - int wOrient ; - if (orient == wxHORIZONTAL) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; - - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - ::SetScrollRange(hWnd, wOrient, 0, range, refresh); + (void) wParam; + (void) lParam; + + return FALSE; #endif } -void wxWindow::SetScrollPage(const int orient, const int page, const bool refresh) + +// --------------------------------------------------------------------------- +// keyboard handling +// --------------------------------------------------------------------------- + +// create the key event of the given type for the given key - used by +// HandleChar and HandleKeyDown/Up +wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType, + int id, + WXLPARAM lParam) const { -#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 = (HWND) GetHWND(); - if (hWnd) - ::SetScrollInfo(hWnd, dir, &info, refresh); -#else - if (orient == wxHORIZONTAL) - m_xThumbSize = page; - else - m_yThumbSize = page; -#endif + wxKeyEvent event(evType); + event.SetId(GetId()); + event.m_shiftDown = wxIsShiftDown(); + event.m_controlDown = wxIsCtrlDown(); + event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN; + + event.m_eventObject = (wxWindow *)this; // const_cast + event.m_keyCode = id; + event.SetTimestamp(s_currentMsg.time); + + // translate the position to client coords + POINT pt; + GetCursorPos(&pt); + RECT rect; + GetWindowRect(GetHwnd(),&rect); + pt.x -= rect.left; + pt.y -= rect.top; + + event.m_x = pt.x; + event.m_y = pt.y; + + return event; } -int wxWindow::OldGetScrollRange(const int orient) const +// isASCII is TRUE only when we're called from WM_CHAR handler and not from +// WM_KEYDOWN one +bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII) { - int wOrient ; - if (orient == wxHORIZONTAL) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; + bool ctrlDown = FALSE; -#if __WATCOMC__ && defined(__WINDOWS_386__) - short minPos, maxPos; -#else - int minPos, maxPos; -#endif - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - { - ::GetScrollRange(hWnd, wOrient, &minPos, &maxPos); -#if defined(__WIN95__) - // Try to adjust the range to cope with page size > 1 - // - a Windows API quirk - int pageSize = GetScrollPage(orient); - if ( pageSize > 1 ) + int id; + if ( isASCII ) { - maxPos -= (pageSize - 1); - } -#endif - return maxPos; - } - else - return 0; -} + // If 1 -> 26, translate to CTRL plus a letter. + id = wParam; + if ( (id > 0) && (id < 27) ) + { + switch (id) + { + case 13: + id = WXK_RETURN; + break; -int wxWindow::GetScrollPage(const int orient) const -{ - if (orient == wxHORIZONTAL) - return m_xThumbSize; - else - return m_yThumbSize; -} -#endif + case 8: + id = WXK_BACK; + break; -int wxWindow::GetScrollPos(const int orient) const -{ - int wOrient ; - if (orient == wxHORIZONTAL) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - { - return ::GetScrollPos(hWnd, wOrient); - } - else - return 0; -} + case 9: + id = WXK_TAB; + break; -// This now returns the whole range, not just the number -// of positions that we can scroll. -int wxWindow::GetScrollRange(const int orient) const -{ - int wOrient ; - if (orient == wxHORIZONTAL) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; + default: + ctrlDown = TRUE; + id = id + 96; + } + } + } + else if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) + { + // it's ASCII and will be processed here only when called from + // WM_CHAR (i.e. when isASCII = TRUE), don't process it now + id = -1; + } -#if __WATCOMC__ && defined(__WINDOWS_386__) - short minPos, maxPos; -#else - int minPos, maxPos; -#endif - HWND hWnd = (HWND) GetHWND(); - if (hWnd) - { - ::GetScrollRange(hWnd, wOrient, &minPos, &maxPos); -#if defined(__WIN95__) - // Try to adjust the range to cope with page size > 1 - // - a Windows API quirk - int pageSize = GetScrollPage(orient); - if ( pageSize > 1 ) + if ( id != -1 ) { - maxPos -= (pageSize - 1); - } - // October 10th: new range concept. - maxPos += pageSize; -#endif + wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam)); + if ( ctrlDown ) + { + event.m_controlDown = TRUE; + } - return maxPos; - } - else - return 0; -} + if ( GetEventHandler()->ProcessEvent(event) ) + return TRUE; + } -int wxWindow::GetScrollThumb(const int orient) const -{ - if (orient == wxHORIZONTAL) - return m_xThumbSize; - else - return m_yThumbSize; + return FALSE; } -void wxWindow::SetScrollPos(const int orient, const int pos, const bool refresh) +bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam) { -#if defined(__WIN95__) - SCROLLINFO info; - int dir; - - if (orient == wxHORIZONTAL) { - dir = SB_HORZ; - } else { - dir = SB_VERT; - } - - info.cbSize = sizeof(SCROLLINFO); - info.nPage = 0; - info.nMin = 0; - info.nPos = pos; - info.fMask = SIF_POS ; - - HWND 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 = (HWND) GetHWND(); - if (hWnd) - ::SetScrollPos(hWnd, wOrient, pos, refresh); -#endif -} + int id = wxCharCodeMSWToWX(wParam); -// New function that will replace some of the above. -void wxWindow::SetScrollbar(const int orient, const int pos, const int thumbVisible, - const int range, const bool refresh) -{ -/* - SetScrollPage(orient, thumbVisible, FALSE); + if ( !id ) + { + // normal ASCII char + id = wParam; + } - int oldRange = range - thumbVisible ; - SetScrollRange(orient, oldRange, FALSE); + if ( id != -1 ) // VZ: does this ever happen (FIXME)? + { + wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam)); + if ( GetEventHandler()->ProcessEvent(event) ) + { + return TRUE; + } + } - SetScrollPos(orient, pos, 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) - { - 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 = pos; - info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; - - HWND 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 = (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; - } + return FALSE; } -void wxWindow::ScrollWindow(const int dx, const int dy, const wxRectangle *rect) +bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam) { - RECT rect2; - if ( rect ) - { - rect2.left = rect->x; - rect2.top = rect->y; - rect2.right = rect->x + rect->width; - rect2.bottom = rect->y + rect->height; - } + int id = wxCharCodeMSWToWX(wParam); - if ( rect ) - ::ScrollWindow((HWND) GetHWND(), dx, dy, &rect2, NULL); - else - ::ScrollWindow((HWND) GetHWND(), dx, dy, NULL, NULL); -} + if ( !id ) + { + // normal ASCII char + id = wParam; + } -void wxWindow::OnSize(wxSizeEvent& event) -{ - Default(); -#if USE_CONSTRAINTS - if (GetAutoLayout()) - Layout(); -#endif -} + if ( id != -1 ) // VZ: does this ever happen (FIXME)? + { + wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam)); + if ( GetEventHandler()->ProcessEvent(event) ) + return TRUE; + } -/* -void wxWindow::CalcScrolledPosition(const int x, const int y, int *xx, int *yy) const -{ - *xx = x; - *yy = y; + return FALSE; } -void wxWindow::CalcUnscrolledPosition(const int x, const int y, float *xx, float *yy) const -{ - *xx = x; - *yy = y; -} -*/ +// --------------------------------------------------------------------------- +// joystick +// --------------------------------------------------------------------------- -void wxWindow::SetFont(const wxFont& font) +bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags) { - // Decrement the usage count of the old label font - // (we may be able to free it up) -// if (GetFont()->Ok()) -// GetFont()->ReleaseResource(); - - m_windowFont = font; +#ifdef JOY_BUTTON1 + int change = 0; + if ( flags & JOY_BUTTON1CHG ) + change = wxJOY_BUTTON1; + if ( flags & JOY_BUTTON2CHG ) + change = wxJOY_BUTTON2; + if ( flags & JOY_BUTTON3CHG ) + change = wxJOY_BUTTON3; + if ( flags & JOY_BUTTON4CHG ) + change = wxJOY_BUTTON4; - if (!m_windowFont.Ok()) - return; + int buttons = 0; + if ( flags & JOY_BUTTON1 ) + buttons |= wxJOY_BUTTON1; + if ( flags & JOY_BUTTON2 ) + buttons |= wxJOY_BUTTON2; + if ( flags & JOY_BUTTON3 ) + buttons |= wxJOY_BUTTON3; + if ( flags & JOY_BUTTON4 ) + buttons |= wxJOY_BUTTON4; -// m_windowFont.UseResource(); + // the event ids aren't consecutive so we can't use table based lookup + int joystick; + wxEventType eventType; + switch ( msg ) + { + case MM_JOY1MOVE: + joystick = 1; + eventType = wxEVT_JOY_MOVE; + break; - HWND hWnd = (HWND) GetHWND(); - if (hWnd != 0) - { -// m_windowFont.RealizeResource(); + case MM_JOY2MOVE: + joystick = 2; + eventType = wxEVT_JOY_MOVE; + break; - if (m_windowFont.GetResourceHandle()) - SendMessage(hWnd, WM_SETFONT, - (WPARAM)m_windowFont.GetResourceHandle(),TRUE); - } -} + case MM_JOY1ZMOVE: + joystick = 1; + eventType = wxEVT_JOY_ZMOVE; + break; -void wxWindow::SubclassWin(WXHWND hWnd) -{ - wxAssociateWinWithHandle((HWND)hWnd, this); + case MM_JOY2ZMOVE: + joystick = 2; + eventType = wxEVT_JOY_ZMOVE; + break; - m_oldWndProc = (WXFARPROC) GetWindowLong((HWND) hWnd, GWL_WNDPROC); - SetWindowLong((HWND) hWnd, GWL_WNDPROC, (LONG) wxWndProc); -} + case MM_JOY1BUTTONDOWN: + joystick = 1; + eventType = wxEVT_JOY_BUTTON_DOWN; + break; -void wxWindow::UnsubclassWin(void) -{ - wxRemoveHandleAssociation(this); + case MM_JOY2BUTTONDOWN: + joystick = 2; + eventType = wxEVT_JOY_BUTTON_DOWN; + break; - // Restore old Window proc - if ((HWND) GetHWND()) - { - FARPROC farProc = (FARPROC) GetWindowLong((HWND) GetHWND(), GWL_WNDPROC); - if ((m_oldWndProc != 0) && (farProc != (FARPROC) m_oldWndProc)) - { - SetWindowLong((HWND) GetHWND(), GWL_WNDPROC, (LONG) m_oldWndProc); - m_oldWndProc = 0; - } - } -} + case MM_JOY1BUTTONUP: + joystick = 1; + eventType = wxEVT_JOY_BUTTON_UP; + break; -// Make a Windows extended style from the given wxWindows window style -WXDWORD wxWindow::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 ) - exStyle |= WS_EX_WINDOWEDGE ; - if ( style & wxSTATIC_BORDER ) - exStyle |= WS_EX_STATICEDGE ; -#endif - } - return exStyle; -} + case MM_JOY2BUTTONUP: + joystick = 2; + eventType = wxEVT_JOY_BUTTON_UP; + break; -// Determines whether native 3D effects or CTL3D should be used, -// applying a default border style if required, and returning an extended -// style to pass to CreateWindowEx. -WXDWORD wxWindow::Determine3DEffects(WXDWORD defaultBorderStyle, bool *want3D) -{ - // If matches certain criteria, then assume no 3D effects - // unless specifically requested (dealt with in MakeExtendedStyle) - if ( !GetParent() || !IsKindOf(CLASSINFO(wxControl)) || (m_windowStyle & wxNO_BORDER) ) - { - *want3D = FALSE; - return MakeExtendedStyle(m_windowStyle, FALSE); - } - - // 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 CTL3D - if ( *want3D ) - nativeBorder = FALSE; -#endif + default: + wxFAIL_MSG(wxT("no such joystick event")); + + return FALSE; + } - DWORD exStyle = MakeExtendedStyle(m_windowStyle, !nativeBorder); + wxJoystickEvent event(eventType, buttons, joystick, change); + event.SetPosition(wxPoint(x, y)); + event.SetEventObject(this); - // 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__) && !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 ; + return GetEventHandler()->ProcessEvent(event); +#else + return FALSE; #endif - - return exStyle; } -#if WXWIN_COMPATIBILITY -void wxWindow::OldOnPaint(void) -{ - wxPaintEvent event(m_windowId); - event.m_eventObject = this; - if (!GetEventHandler()->ProcessEvent(event)) - Default(); -}; +// --------------------------------------------------------------------------- +// scrolling +// --------------------------------------------------------------------------- -void wxWindow::OldOnSize(int w, int h) +bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam, + WXWORD pos, WXHWND control) { - wxSizeEvent event(wxSize(w, h), m_windowId); - event.m_eventObject = this; - if (!GetEventHandler()->ProcessEvent(event)) - Default(); -}; + if ( control ) + { + wxWindow *child = wxFindWinFromHandle(control); + if ( child ) + return child->MSWOnScroll(orientation, wParam, pos, control); + } -void wxWindow::OldOnMouseEvent(wxMouseEvent& event) -{ - if (!GetEventHandler()->ProcessEvent(event)) - Default(); -}; + wxScrollWinEvent event; + event.SetPosition(pos); + event.SetOrientation(orientation); + event.m_eventObject = this; -void wxWindow::OldOnChar(wxKeyEvent& event) -{ - if (!GetEventHandler()->ProcessEvent(event)) - Default(); -}; + switch ( wParam ) + { + case SB_TOP: + event.m_eventType = wxEVT_SCROLLWIN_TOP; + break; -void wxWindow::OldOnSetFocus(void) -{ - wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId); - event.m_eventObject = this; - if (!GetEventHandler()->ProcessEvent(event)) - Default(); -}; + case SB_BOTTOM: + event.m_eventType = wxEVT_SCROLLWIN_BOTTOM; + break; -void wxWindow::OldOnKillFocus(void) -{ - wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId); - event.m_eventObject = this; - if (!GetEventHandler()->ProcessEvent(event)) - Default(); -}; -#endif + case SB_LINEUP: + event.m_eventType = wxEVT_SCROLLWIN_LINEUP; + break; -void wxWindow::OnChar(wxKeyEvent& event) -{ - bool isVirtual; - int id = wxCharCodeWXToMSW((int)event.KeyCode(), &isVirtual); + case SB_LINEDOWN: + event.m_eventType = wxEVT_SCROLLWIN_LINEDOWN; + break; - if ( id == -1 ) - id= m_lastWParam; + case SB_PAGEUP: + event.m_eventType = wxEVT_SCROLLWIN_PAGEUP; + break; - if ( !event.ControlDown() ) - (void) MSWDefWindowProc(m_lastMsg, (WPARAM) id, m_lastLParam); -} + case SB_PAGEDOWN: + event.m_eventType = wxEVT_SCROLLWIN_PAGEDOWN; + break; -void wxWindow::OnPaint(wxPaintEvent& event) -{ - Default(); -} + 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); + scrollInfo.fMask = SIF_TRACKPOS; + + if ( !::GetScrollInfo(GetHwnd(), + orientation == wxHORIZONTAL ? SB_HORZ + : SB_VERT, + &scrollInfo) ) + { + wxLogLastError(_T("GetScrollInfo")); + } -bool wxWindow::IsEnabled(void) const -{ - return (::IsWindowEnabled((HWND) GetHWND()) != 0); -} + event.SetPosition(scrollInfo.nTrackPos); + } +#endif // Win32 -// Dialog support: override these and call -// base class members to add functionality -// that can't be done using validators. -// NOTE: these functions assume that controls -// are direct children of this window, not grandchildren -// or other levels of descendant. + event.m_eventType = wParam == SB_THUMBPOSITION + ? wxEVT_SCROLLWIN_THUMBRELEASE + : wxEVT_SCROLLWIN_THUMBTRACK; + break; -// Transfer values to controls. If returns FALSE, -// it's an application error (pops up a dialog) -bool wxWindow::TransferDataToWindow(void) -{ - wxNode *node = GetChildren()->First(); - while ( node ) - { - wxWindow *child = (wxWindow *)node->Data(); - if ( child->GetValidator() && /* child->GetValidator()->Ok() && */ - !child->GetValidator()->TransferToWindow() ) - { - wxMessageBox("Application Error", "Could not transfer data to window", wxOK|wxICON_EXCLAMATION); - return FALSE; - } + default: + return FALSE; + } - node = node->Next(); - } - return TRUE; + return GetEventHandler()->ProcessEvent(event); } -// Transfer values from controls. If returns FALSE, -// validation failed: don't quit -bool wxWindow::TransferDataFromWindow(void) -{ - wxNode *node = GetChildren()->First(); - while ( node ) - { - wxWindow *child = (wxWindow *)node->Data(); - if ( child->GetValidator() && /* child->GetValidator()->Ok() && */ !child->GetValidator()->TransferFromWindow() ) - { - return FALSE; - } - - node = node->Next(); - } - return TRUE; -} +// =========================================================================== +// global functions +// =========================================================================== -bool wxWindow::Validate(void) +void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont *the_font) { - wxNode *node = GetChildren()->First(); - while ( node ) - { - wxWindow *child = (wxWindow *)node->Data(); - if ( child->GetValidator() && /* child->GetValidator()->Ok() && */ !child->GetValidator()->Validate(this) ) - { - return FALSE; - } + TEXTMETRIC tm; + HDC dc = ::GetDC((HWND) wnd); + HFONT fnt =0; + HFONT was = 0; + if ( the_font ) + { + // the_font->UseResource(); + // the_font->RealizeResource(); + fnt = (HFONT)((wxFont *)the_font)->GetResourceHandle(); // const_cast + if ( fnt ) + was = (HFONT) SelectObject(dc,fnt); + } + GetTextMetrics(dc, &tm); + if ( the_font && fnt && was ) + { + SelectObject(dc,was); + } + ReleaseDC((HWND)wnd, dc); - node = node->Next(); - } - return TRUE; + if ( x ) + *x = tm.tmAveCharWidth; + if ( y ) + *y = tm.tmHeight + tm.tmExternalLeading; + + // if ( the_font ) + // the_font->ReleaseResource(); } -// Get the window with the focus -wxWindow *wxWindow::FindFocus(void) +// Returns 0 if was a normal ASCII value, not a special key. This indicates that +// the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead. +int wxCharCodeMSWToWX(int keySym) { - HWND hWnd = ::GetFocus(); - if ( hWnd ) + int id; + switch (keySym) { - return wxFindWinFromHandle((WXHWND) hWnd); + case VK_CANCEL: id = WXK_CANCEL; break; + case VK_BACK: id = WXK_BACK; break; + case VK_TAB: id = WXK_TAB; break; + case VK_CLEAR: id = WXK_CLEAR; break; + case VK_RETURN: id = WXK_RETURN; break; + case VK_SHIFT: id = WXK_SHIFT; break; + case VK_CONTROL: id = WXK_CONTROL; break; + case VK_MENU : id = WXK_MENU; break; + case VK_PAUSE: id = WXK_PAUSE; break; + case VK_SPACE: id = WXK_SPACE; break; + case VK_ESCAPE: id = WXK_ESCAPE; break; + case VK_PRIOR: id = WXK_PRIOR; break; + case VK_NEXT : id = WXK_NEXT; break; + case VK_END: id = WXK_END; break; + case VK_HOME : id = WXK_HOME; break; + case VK_LEFT : id = WXK_LEFT; break; + case VK_UP: id = WXK_UP; break; + case VK_RIGHT: id = WXK_RIGHT; break; + case VK_DOWN : id = WXK_DOWN; break; + case VK_SELECT: id = WXK_SELECT; break; + case VK_PRINT: id = WXK_PRINT; break; + case VK_EXECUTE: id = WXK_EXECUTE; break; + case VK_INSERT: id = WXK_INSERT; break; + case VK_DELETE: id = WXK_DELETE; break; + case VK_HELP : id = WXK_HELP; break; + case VK_NUMPAD0: id = WXK_NUMPAD0; break; + case VK_NUMPAD1: id = WXK_NUMPAD1; break; + case VK_NUMPAD2: id = WXK_NUMPAD2; break; + case VK_NUMPAD3: id = WXK_NUMPAD3; break; + case VK_NUMPAD4: id = WXK_NUMPAD4; break; + case VK_NUMPAD5: id = WXK_NUMPAD5; break; + case VK_NUMPAD6: id = WXK_NUMPAD6; break; + case VK_NUMPAD7: id = WXK_NUMPAD7; break; + case VK_NUMPAD8: id = WXK_NUMPAD8; break; + case VK_NUMPAD9: id = WXK_NUMPAD9; break; + case VK_MULTIPLY: id = WXK_NUMPAD_MULTIPLY; break; + case VK_ADD: id = WXK_NUMPAD_ADD; break; + case VK_SUBTRACT: id = WXK_NUMPAD_SUBTRACT; break; + case VK_DECIMAL: id = WXK_NUMPAD_DECIMAL; break; + case VK_DIVIDE: id = WXK_NUMPAD_DIVIDE; break; + case VK_F1: id = WXK_F1; break; + case VK_F2: id = WXK_F2; break; + case VK_F3: id = WXK_F3; break; + case VK_F4: id = WXK_F4; break; + case VK_F5: id = WXK_F5; break; + case VK_F6: id = WXK_F6; break; + case VK_F7: id = WXK_F7; break; + case VK_F8: id = WXK_F8; break; + case VK_F9: id = WXK_F9; break; + case VK_F10: id = WXK_F10; break; + case VK_F11: id = WXK_F11; break; + case VK_F12: id = WXK_F12; break; + case VK_F13: id = WXK_F13; break; + case VK_F14: id = WXK_F14; break; + case VK_F15: id = WXK_F15; break; + case VK_F16: id = WXK_F16; break; + case VK_F17: id = WXK_F17; break; + case VK_F18: id = WXK_F18; break; + case VK_F19: id = WXK_F19; break; + case VK_F20: id = WXK_F20; break; + case VK_F21: id = WXK_F21; break; + case VK_F22: id = WXK_F22; break; + case VK_F23: id = WXK_F23; break; + case VK_F24: id = WXK_F24; break; + case VK_NUMLOCK: id = WXK_NUMLOCK; break; + case VK_SCROLL: id = WXK_SCROLL; break; + default: + id = 0; } - return NULL; -} -void wxWindow::AddChild(wxWindow *child) -{ - GetChildren()->Append(child); - child->m_windowParent = this; -} - -void wxWindow::RemoveChild(wxWindow *child) -{ - if (GetChildren()) - GetChildren()->DeleteObject(child); - child->m_windowParent = NULL; + return id; } -void wxWindow::DestroyChildren(void) +int wxCharCodeWXToMSW(int id, bool *isVirtual) { - if (GetChildren()) { - wxNode *node; - while ((node = GetChildren()->First()) != (wxNode *)NULL) { - wxWindow *child; - if ((child = (wxWindow *)node->Data()) != (wxWindow *)NULL) { - delete child; - if ( GetChildren()->Member(child) ) - delete node; - } - } /* while */ - } + *isVirtual = TRUE; + int keySym = 0; + switch (id) + { + case WXK_CANCEL: keySym = VK_CANCEL; break; + case WXK_CLEAR: keySym = VK_CLEAR; break; + case WXK_SHIFT: keySym = VK_SHIFT; break; + case WXK_CONTROL: keySym = VK_CONTROL; break; + case WXK_MENU : keySym = VK_MENU; break; + case WXK_PAUSE: keySym = VK_PAUSE; break; + case WXK_PRIOR: keySym = VK_PRIOR; break; + case WXK_NEXT : keySym = VK_NEXT; break; + case WXK_END: keySym = VK_END; break; + case WXK_HOME : keySym = VK_HOME; break; + case WXK_LEFT : keySym = VK_LEFT; break; + case WXK_UP: keySym = VK_UP; break; + case WXK_RIGHT: keySym = VK_RIGHT; break; + case WXK_DOWN : keySym = VK_DOWN; break; + case WXK_SELECT: keySym = VK_SELECT; break; + case WXK_PRINT: keySym = VK_PRINT; break; + case WXK_EXECUTE: keySym = VK_EXECUTE; break; + case WXK_INSERT: keySym = VK_INSERT; break; + case WXK_DELETE: keySym = VK_DELETE; break; + case WXK_HELP : keySym = VK_HELP; break; + case WXK_NUMPAD0: keySym = VK_NUMPAD0; break; + case WXK_NUMPAD1: keySym = VK_NUMPAD1; break; + case WXK_NUMPAD2: keySym = VK_NUMPAD2; break; + case WXK_NUMPAD3: keySym = VK_NUMPAD3; break; + case WXK_NUMPAD4: keySym = VK_NUMPAD4; break; + case WXK_NUMPAD5: keySym = VK_NUMPAD5; break; + case WXK_NUMPAD6: keySym = VK_NUMPAD6; break; + case WXK_NUMPAD7: keySym = VK_NUMPAD7; break; + case WXK_NUMPAD8: keySym = VK_NUMPAD8; break; + case WXK_NUMPAD9: keySym = VK_NUMPAD9; break; + case WXK_NUMPAD_MULTIPLY: keySym = VK_MULTIPLY; break; + case WXK_NUMPAD_ADD: keySym = VK_ADD; break; + case WXK_NUMPAD_SUBTRACT: keySym = VK_SUBTRACT; break; + case WXK_NUMPAD_DECIMAL: keySym = VK_DECIMAL; break; + case WXK_NUMPAD_DIVIDE: keySym = VK_DIVIDE; break; + case WXK_F1: keySym = VK_F1; break; + case WXK_F2: keySym = VK_F2; break; + case WXK_F3: keySym = VK_F3; break; + case WXK_F4: keySym = VK_F4; break; + case WXK_F5: keySym = VK_F5; break; + case WXK_F6: keySym = VK_F6; break; + case WXK_F7: keySym = VK_F7; break; + case WXK_F8: keySym = VK_F8; break; + case WXK_F9: keySym = VK_F9; break; + case WXK_F10: keySym = VK_F10; break; + case WXK_F11: keySym = VK_F11; break; + case WXK_F12: keySym = VK_F12; break; + case WXK_F13: keySym = VK_F13; break; + case WXK_F14: keySym = VK_F14; break; + case WXK_F15: keySym = VK_F15; break; + case WXK_F16: keySym = VK_F16; break; + case WXK_F17: keySym = VK_F17; break; + case WXK_F18: keySym = VK_F18; break; + case WXK_F19: keySym = VK_F19; break; + case WXK_F20: keySym = VK_F20; break; + case WXK_F21: keySym = VK_F21; break; + case WXK_F22: keySym = VK_F22; break; + case WXK_F23: keySym = VK_F23; break; + case WXK_F24: keySym = VK_F24; break; + case WXK_NUMLOCK: keySym = VK_NUMLOCK; break; + case WXK_SCROLL: keySym = VK_SCROLL; break; + default: + { + *isVirtual = FALSE; + keySym = id; + break; + } + } + return keySym; } -void wxWindow::MakeModal(const bool modal) +wxWindow *wxGetActiveWindow() { - // Disable all other windows - if (this->IsKindOf(CLASSINFO(wxDialog)) || this->IsKindOf(CLASSINFO(wxFrame))) - { - wxNode *node = wxTopLevelWindows.First(); - while (node) + HWND hWnd = GetActiveWindow(); + if ( hWnd != 0 ) { - wxWindow *win = (wxWindow *)node->Data(); - if (win != this) - win->Enable(!modal); - - node = node->Next(); + return wxFindWinFromHandle((WXHWND) hWnd); } - } + return NULL; } -// If nothing defined for this, try the parent. -// E.g. we may be a button loaded from a resource, with no callback function -// defined. -void wxWindow::OnCommand(wxWindow& win, wxCommandEvent& event) -{ - if (GetEventHandler()->ProcessEvent(event) ) - return; - if (m_windowParent) - m_windowParent->GetEventHandler()->OnCommand(win, event); -} - -void wxWindow::SetConstraints(wxLayoutConstraints *c) -{ - if (m_constraints) - { - UnsetConstraints(m_constraints); - delete m_constraints; - } - m_constraints = c; - if (m_constraints) - { - // Make sure other windows know they're part of a 'meaningful relationship' - if (m_constraints->left.GetOtherWindow() && (m_constraints->left.GetOtherWindow() != this)) - m_constraints->left.GetOtherWindow()->AddConstraintReference((wxWindow *)this); - if (m_constraints->top.GetOtherWindow() && (m_constraints->top.GetOtherWindow() != this)) - m_constraints->top.GetOtherWindow()->AddConstraintReference((wxWindow *)this); - if (m_constraints->right.GetOtherWindow() && (m_constraints->right.GetOtherWindow() != this)) - m_constraints->right.GetOtherWindow()->AddConstraintReference((wxWindow *)this); - if (m_constraints->bottom.GetOtherWindow() && (m_constraints->bottom.GetOtherWindow() != this)) - m_constraints->bottom.GetOtherWindow()->AddConstraintReference((wxWindow *)this); - if (m_constraints->width.GetOtherWindow() && (m_constraints->width.GetOtherWindow() != this)) - m_constraints->width.GetOtherWindow()->AddConstraintReference((wxWindow *)this); - if (m_constraints->height.GetOtherWindow() && (m_constraints->height.GetOtherWindow() != this)) - m_constraints->height.GetOtherWindow()->AddConstraintReference((wxWindow *)this); - if (m_constraints->centreX.GetOtherWindow() && (m_constraints->centreX.GetOtherWindow() != this)) - m_constraints->centreX.GetOtherWindow()->AddConstraintReference((wxWindow *)this); - if (m_constraints->centreY.GetOtherWindow() && (m_constraints->centreY.GetOtherWindow() != this)) - m_constraints->centreY.GetOtherWindow()->AddConstraintReference((wxWindow *)this); - } -} - -// This removes any dangling pointers to this window -// in other windows' constraintsInvolvedIn lists. -void wxWindow::UnsetConstraints(wxLayoutConstraints *c) -{ - if (c) - { - if (c->left.GetOtherWindow() && (c->top.GetOtherWindow() != this)) - c->left.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - if (c->top.GetOtherWindow() && (c->top.GetOtherWindow() != this)) - c->top.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - if (c->right.GetOtherWindow() && (c->right.GetOtherWindow() != this)) - c->right.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - if (c->bottom.GetOtherWindow() && (c->bottom.GetOtherWindow() != this)) - c->bottom.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - if (c->width.GetOtherWindow() && (c->width.GetOtherWindow() != this)) - c->width.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - if (c->height.GetOtherWindow() && (c->height.GetOtherWindow() != this)) - c->height.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - if (c->centreX.GetOtherWindow() && (c->centreX.GetOtherWindow() != this)) - c->centreX.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - if (c->centreY.GetOtherWindow() && (c->centreY.GetOtherWindow() != this)) - c->centreY.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this); - } -} - -// Back-pointer to other windows we're involved with, so if we delete -// this window, we must delete any constraints we're involved with. -void wxWindow::AddConstraintReference(wxWindow *otherWin) -{ - if (!m_constraintsInvolvedIn) - m_constraintsInvolvedIn = new wxList; - if (!m_constraintsInvolvedIn->Member(otherWin)) - m_constraintsInvolvedIn->Append(otherWin); -} - -// REMOVE back-pointer to other windows we're involved with. -void wxWindow::RemoveConstraintReference(wxWindow *otherWin) -{ - if (m_constraintsInvolvedIn) - m_constraintsInvolvedIn->DeleteObject(otherWin); -} - -// Reset any constraints that mention this window -void wxWindow::DeleteRelatedConstraints(void) -{ - if (m_constraintsInvolvedIn) - { - wxNode *node = m_constraintsInvolvedIn->First(); - while (node) - { - wxWindow *win = (wxWindow *)node->Data(); - wxNode *next = node->Next(); - wxLayoutConstraints *constr = win->GetConstraints(); - - // Reset any constraints involving this window - if (constr) - { - constr->left.ResetIfWin((wxWindow *)this); - constr->top.ResetIfWin((wxWindow *)this); - constr->right.ResetIfWin((wxWindow *)this); - constr->bottom.ResetIfWin((wxWindow *)this); - constr->width.ResetIfWin((wxWindow *)this); - constr->height.ResetIfWin((wxWindow *)this); - constr->centreX.ResetIfWin((wxWindow *)this); - constr->centreY.ResetIfWin((wxWindow *)this); - } - delete node; - node = next; - } - delete m_constraintsInvolvedIn; - m_constraintsInvolvedIn = NULL; - } -} - -void wxWindow::SetSizer(wxSizer *sizer) -{ - m_windowSizer = sizer; - if (sizer) - sizer->SetSizerParent((wxWindow *)this); -} - -/* - * New version - */ - -bool wxWindow::Layout(void) -{ - if (GetConstraints()) - { - int w, h; - GetClientSize(&w, &h); - GetConstraints()->width.SetValue(w); - GetConstraints()->height.SetValue(h); - } - - // If top level (one sizer), evaluate the sizer's constraints. - if (GetSizer()) - { - int noChanges; - GetSizer()->ResetConstraints(); // Mark all constraints as unevaluated - GetSizer()->LayoutPhase1(&noChanges); - GetSizer()->LayoutPhase2(&noChanges); - GetSizer()->SetConstraintSizes(); // Recursively set the real window sizes - return TRUE; - } - else - { - // Otherwise, evaluate child constraints - ResetConstraints(); // Mark all constraints as unevaluated - DoPhase(1); // Just one phase need if no sizers involved - DoPhase(2); - SetConstraintSizes(); // Recursively set the real window sizes - } - return TRUE; -} - - -// Do a phase of evaluating constraints: -// the default behaviour. wxSizers may do a similar -// thing, but also impose their own 'constraints' -// and order the evaluation differently. -bool wxWindow::LayoutPhase1(int *noChanges) -{ - wxLayoutConstraints *constr = GetConstraints(); - if (constr) - { - return constr->SatisfyConstraints((wxWindow *)this, noChanges); - } - else - return TRUE; -} +extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) +{ + HWND hwnd = (HWND)hWnd; -bool wxWindow::LayoutPhase2(int *noChanges) -{ - *noChanges = 0; - - // Layout children - DoPhase(1); - DoPhase(2); - return TRUE; -} - -// Do a phase of evaluating child constraints -bool wxWindow::DoPhase(const int phase) -{ - int noIterations = 0; - int maxIterations = 500; - int noChanges = 1; - int noFailures = 0; - wxList succeeded; - while ((noChanges > 0) && (noIterations < maxIterations)) - { - noChanges = 0; - noFailures = 0; - wxNode *node = GetChildren()->First(); - while (node) - { - wxWindow *child = (wxWindow *)node->Data(); - if (!child->IsKindOf(CLASSINFO(wxFrame)) && !child->IsKindOf(CLASSINFO(wxDialog))) - { - wxLayoutConstraints *constr = child->GetConstraints(); - if (constr) + // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set + // by code in msw/radiobox.cpp), for all the others we just search up the + // window hierarchy + wxWindow *win = (wxWindow *)NULL; + if ( hwnd ) + { + win = wxFindWinFromHandle((WXHWND)hwnd); + if ( !win ) { - if (succeeded.Member(child)) - { - } - else - { - int tempNoChanges = 0; - bool success = ( (phase == 1) ? child->LayoutPhase1(&tempNoChanges) : child->LayoutPhase2(&tempNoChanges) ) ; - noChanges += tempNoChanges; - if (success) + // 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 + // do it as well, win would be already non NULL + if ( ::SendMessage(hwnd, WM_GETDLGCODE, 0, 0) & DLGC_RADIOBUTTON ) { - succeeded.Append(child); + win = (wxWindow *)::GetWindowLong(hwnd, GWL_USERDATA); } - } + //else: it's a wxRadioButton, not a radiobutton from wxRadioBox +#endif // wxUSE_RADIOBOX + + // spin control text buddy window should be mapped to spin ctrl + // itself so try it too +#if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__) + if ( !win ) + { + win = wxSpinCtrl::GetSpinForTextCtrl((WXHWND)hwnd); + } +#endif // wxUSE_SPINCTRL + +#endif // Win32 } - } - node = node->Next(); - } - noIterations ++; - } - return TRUE; -} - -void wxWindow::ResetConstraints(void) -{ - wxLayoutConstraints *constr = GetConstraints(); - if (constr) - { - constr->left.SetDone(FALSE); - constr->top.SetDone(FALSE); - constr->right.SetDone(FALSE); - constr->bottom.SetDone(FALSE); - constr->width.SetDone(FALSE); - constr->height.SetDone(FALSE); - constr->centreX.SetDone(FALSE); - constr->centreY.SetDone(FALSE); - } - wxNode *node = GetChildren()->First(); - while (node) - { - wxWindow *win = (wxWindow *)node->Data(); - if (!win->IsKindOf(CLASSINFO(wxFrame)) && !win->IsKindOf(CLASSINFO(wxDialog))) - win->ResetConstraints(); - node = node->Next(); - } -} - -// Need to distinguish between setting the 'fake' size for -// windows and sizers, and setting the real values. -void wxWindow::SetConstraintSizes(const bool recurse) -{ - wxLayoutConstraints *constr = GetConstraints(); - if (constr && constr->left.GetDone() && constr->right.GetDone() && - constr->width.GetDone() && constr->height.GetDone()) - { - int x = constr->left.GetValue(); - int y = constr->top.GetValue(); - int w = constr->width.GetValue(); - int h = constr->height.GetValue(); - - // If we don't want to resize this window, just move it... - if ((constr->width.GetRelationship() != wxAsIs) || - (constr->height.GetRelationship() != wxAsIs)) - { - // Calls Layout() recursively. AAAGH. How can we stop that. - // Simply take Layout() out of non-top level OnSizes. - SizerSetSize(x, y, w, h); } - else - { - SizerMove(x, y); - } - } - else if (constr) - { - char *windowClass = this->GetClassInfo()->GetClassName(); - - wxString winName; - if (GetName() == "") - winName = "unnamed"; - else - winName = GetName(); - wxDebugMsg("Constraint(s) not satisfied for window of type %s, name %s:\n", (const char *)windowClass, (const char *)winName); - if (!constr->left.GetDone()) - wxDebugMsg(" unsatisfied 'left' constraint.\n"); - if (!constr->right.GetDone()) - wxDebugMsg(" unsatisfied 'right' constraint.\n"); - if (!constr->width.GetDone()) - wxDebugMsg(" unsatisfied 'width' constraint.\n"); - if (!constr->height.GetDone()) - wxDebugMsg(" unsatisfied 'height' constraint.\n"); - wxDebugMsg("Please check constraints: try adding AsIs() constraints.\n"); - } - if (recurse) - { - wxNode *node = GetChildren()->First(); - while (node) + while ( hwnd && !win ) { - wxWindow *win = (wxWindow *)node->Data(); - if (!win->IsKindOf(CLASSINFO(wxFrame)) && !win->IsKindOf(CLASSINFO(wxDialog))) - win->SetConstraintSizes(); - node = node->Next(); + // this is a really ugly hack needed to avoid mistakenly returning the + // parent frame wxWindow for the find/replace modeless dialog HWND - + // this, in turn, is needed to call IsDialogMessage() from + // wxApp::ProcessMessage() as for this we must return NULL from here + // + // FIXME: this is clearly not the best way to do it but I think we'll + // need to change HWND <-> wxWindow code more heavily than I can + // do it now to fix it +#ifndef __WXMICROWIN__ + if ( ::GetWindow(hwnd, GW_OWNER) ) + { + // it's a dialog box, don't go upwards + break; + } +#endif + + hwnd = ::GetParent(hwnd); + win = wxFindWinFromHandle((WXHWND)hwnd); } - } -} -// This assumes that all sizers are 'on' the same -// window, i.e. the parent of this window. -void wxWindow::TransformSizerToActual(int *x, int *y) const -{ - if (!m_sizerParent || m_sizerParent->IsKindOf(CLASSINFO(wxDialog)) || - m_sizerParent->IsKindOf(CLASSINFO(wxFrame)) ) - return; - - int xp, yp; - m_sizerParent->GetPosition(&xp, &yp); - m_sizerParent->TransformSizerToActual(&xp, &yp); - *x += xp; - *y += yp; + return win; } -void wxWindow::SizerSetSize(const int x, const int y, const int w, const int h) -{ - int xx = x; - int yy = y; - TransformSizerToActual(&xx, &yy); - SetSize(xx, yy, w, h); -} +#ifndef __WXMICROWIN__ -void wxWindow::SizerMove(const int x, const int y) -{ - int xx = x; - int yy = y; - TransformSizerToActual(&xx, &yy); - Move(xx, yy); -} +// Windows keyboard hook. Allows interception of e.g. F1, ESCAPE +// in active frames and dialogs, regardless of where the focus is. +static HHOOK wxTheKeyboardHook = 0; +static FARPROC wxTheKeyboardHookProc = 0; +int APIENTRY _EXPORT +wxKeyboardHook(int nCode, WORD wParam, DWORD lParam); -// Only set the size/position of the constraint (if any) -void wxWindow::SetSizeConstraint(const int x, const int y, const int w, const int h) +void wxSetKeyboardHook(bool doIt) { - wxLayoutConstraints *constr = GetConstraints(); - if (constr) - { - if (x != -1) - { - constr->left.SetValue(x); - constr->left.SetDone(TRUE); - } - if (y != -1) - { - constr->top.SetValue(y); - constr->top.SetDone(TRUE); - } - if (w != -1) + if ( doIt ) { - constr->width.SetValue(w); - constr->width.SetDone(TRUE); + 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 + ); } - if (h != -1) + else { - constr->height.SetValue(h); - constr->height.SetDone(TRUE); + 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 } - } } -void wxWindow::MoveConstraint(const int x, const int y) +int APIENTRY _EXPORT +wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) { - wxLayoutConstraints *constr = GetConstraints(); - if (constr) - { - if (x != -1) + DWORD hiWord = HIWORD(lParam); + if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) ) { - constr->left.SetValue(x); - constr->left.SetDone(TRUE); - } - if (y != -1) - { - constr->top.SetValue(y); - constr->top.SetDone(TRUE); - } - } -} + int id = wxCharCodeMSWToWX(wParam); + if ( id != 0 ) + { + wxKeyEvent event(wxEVT_CHAR_HOOK); + if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN ) + event.m_altDown = TRUE; + + event.m_eventObject = NULL; + event.m_keyCode = id; + event.m_shiftDown = wxIsShiftDown(); + event.m_controlDown = wxIsCtrlDown(); + event.SetTimestamp(s_currentMsg.time); + + wxWindow *win = wxGetActiveWindow(); + wxEvtHandler *handler; + if ( win ) + { + handler = win->GetEventHandler(); + event.SetId(win->GetId()); + } + else + { + handler = wxTheApp; + event.SetId(-1); + } -void wxWindow::GetSizeConstraint(int *w, int *h) const -{ - wxLayoutConstraints *constr = GetConstraints(); - if (constr) - { - *w = constr->width.GetValue(); - *h = constr->height.GetValue(); - } - else - GetSize(w, h); -} + if ( handler && handler->ProcessEvent(event) ) + { + // processed + return 1; + } + } + } -void wxWindow::GetClientSizeConstraint(int *w, int *h) const -{ - wxLayoutConstraints *constr = GetConstraints(); - if (constr) - { - *w = constr->width.GetValue(); - *h = constr->height.GetValue(); - } - else - GetClientSize(w, h); + return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam); } -void wxWindow::GetPositionConstraint(int *x, int *y) const -{ - wxLayoutConstraints *constr = GetConstraints(); - if (constr) - { - *x = constr->left.GetValue(); - *y = constr->top.GetValue(); - } - else - GetPosition(x, y); -} +#endif // !__WXMICROWIN__ -bool wxWindow::Close(const bool force) +#ifdef __WXDEBUG__ +const char *wxGetMessageName(int message) { - // Let's generalise it to work the same for any window. -/* - if (!IsKindOf(CLASSINFO(wxDialog)) && !IsKindOf(CLASSINFO(wxFrame))) - { - this->Destroy(); - return TRUE; - } -*/ + switch ( message ) + { + case 0x0000: return "WM_NULL"; + case 0x0001: return "WM_CREATE"; + case 0x0002: return "WM_DESTROY"; + case 0x0003: return "WM_MOVE"; + case 0x0005: return "WM_SIZE"; + case 0x0006: return "WM_ACTIVATE"; + case 0x0007: return "WM_SETFOCUS"; + case 0x0008: return "WM_KILLFOCUS"; + case 0x000A: return "WM_ENABLE"; + case 0x000B: return "WM_SETREDRAW"; + case 0x000C: return "WM_SETTEXT"; + case 0x000D: return "WM_GETTEXT"; + case 0x000E: return "WM_GETTEXTLENGTH"; + case 0x000F: return "WM_PAINT"; + case 0x0010: return "WM_CLOSE"; + case 0x0011: return "WM_QUERYENDSESSION"; + case 0x0012: return "WM_QUIT"; + case 0x0013: return "WM_QUERYOPEN"; + case 0x0014: return "WM_ERASEBKGND"; + case 0x0015: return "WM_SYSCOLORCHANGE"; + case 0x0016: return "WM_ENDSESSION"; + case 0x0017: return "WM_SYSTEMERROR"; + case 0x0018: return "WM_SHOWWINDOW"; + case 0x0019: return "WM_CTLCOLOR"; + case 0x001A: return "WM_WININICHANGE"; + case 0x001B: return "WM_DEVMODECHANGE"; + case 0x001C: return "WM_ACTIVATEAPP"; + case 0x001D: return "WM_FONTCHANGE"; + case 0x001E: return "WM_TIMECHANGE"; + case 0x001F: return "WM_CANCELMODE"; + case 0x0020: return "WM_SETCURSOR"; + case 0x0021: return "WM_MOUSEACTIVATE"; + case 0x0022: return "WM_CHILDACTIVATE"; + case 0x0023: return "WM_QUEUESYNC"; + case 0x0024: return "WM_GETMINMAXINFO"; + case 0x0026: return "WM_PAINTICON"; + case 0x0027: return "WM_ICONERASEBKGND"; + case 0x0028: return "WM_NEXTDLGCTL"; + case 0x002A: return "WM_SPOOLERSTATUS"; + case 0x002B: return "WM_DRAWITEM"; + case 0x002C: return "WM_MEASUREITEM"; + case 0x002D: return "WM_DELETEITEM"; + case 0x002E: return "WM_VKEYTOITEM"; + case 0x002F: return "WM_CHARTOITEM"; + case 0x0030: return "WM_SETFONT"; + case 0x0031: return "WM_GETFONT"; + case 0x0037: return "WM_QUERYDRAGICON"; + case 0x0039: return "WM_COMPAREITEM"; + case 0x0041: return "WM_COMPACTING"; + case 0x0044: return "WM_COMMNOTIFY"; + case 0x0046: return "WM_WINDOWPOSCHANGING"; + case 0x0047: return "WM_WINDOWPOSCHANGED"; + case 0x0048: return "WM_POWER"; + +#ifdef __WIN32__ + case 0x004A: return "WM_COPYDATA"; + case 0x004B: return "WM_CANCELJOURNAL"; + case 0x004E: return "WM_NOTIFY"; + case 0x0050: return "WM_INPUTLANGCHANGEREQUEST"; + case 0x0051: return "WM_INPUTLANGCHANGE"; + case 0x0052: return "WM_TCARD"; + case 0x0053: return "WM_HELP"; + case 0x0054: return "WM_USERCHANGED"; + case 0x0055: return "WM_NOTIFYFORMAT"; + case 0x007B: return "WM_CONTEXTMENU"; + case 0x007C: return "WM_STYLECHANGING"; + case 0x007D: return "WM_STYLECHANGED"; + case 0x007E: return "WM_DISPLAYCHANGE"; + case 0x007F: return "WM_GETICON"; + case 0x0080: return "WM_SETICON"; +#endif //WIN32 + + case 0x0081: return "WM_NCCREATE"; + case 0x0082: return "WM_NCDESTROY"; + case 0x0083: return "WM_NCCALCSIZE"; + case 0x0084: return "WM_NCHITTEST"; + case 0x0085: return "WM_NCPAINT"; + case 0x0086: return "WM_NCACTIVATE"; + case 0x0087: return "WM_GETDLGCODE"; + case 0x00A0: return "WM_NCMOUSEMOVE"; + case 0x00A1: return "WM_NCLBUTTONDOWN"; + case 0x00A2: return "WM_NCLBUTTONUP"; + case 0x00A3: return "WM_NCLBUTTONDBLCLK"; + case 0x00A4: return "WM_NCRBUTTONDOWN"; + case 0x00A5: return "WM_NCRBUTTONUP"; + case 0x00A6: return "WM_NCRBUTTONDBLCLK"; + case 0x00A7: return "WM_NCMBUTTONDOWN"; + case 0x00A8: return "WM_NCMBUTTONUP"; + case 0x00A9: return "WM_NCMBUTTONDBLCLK"; + case 0x0100: return "WM_KEYDOWN"; + case 0x0101: return "WM_KEYUP"; + case 0x0102: return "WM_CHAR"; + case 0x0103: return "WM_DEADCHAR"; + case 0x0104: return "WM_SYSKEYDOWN"; + case 0x0105: return "WM_SYSKEYUP"; + case 0x0106: return "WM_SYSCHAR"; + case 0x0107: return "WM_SYSDEADCHAR"; + case 0x0108: return "WM_KEYLAST"; + +#ifdef __WIN32__ + case 0x010D: return "WM_IME_STARTCOMPOSITION"; + case 0x010E: return "WM_IME_ENDCOMPOSITION"; + case 0x010F: return "WM_IME_COMPOSITION"; +#endif //WIN32 + + case 0x0110: return "WM_INITDIALOG"; + case 0x0111: return "WM_COMMAND"; + case 0x0112: return "WM_SYSCOMMAND"; + case 0x0113: return "WM_TIMER"; + case 0x0114: return "WM_HSCROLL"; + case 0x0115: return "WM_VSCROLL"; + case 0x0116: return "WM_INITMENU"; + case 0x0117: return "WM_INITMENUPOPUP"; + case 0x011F: return "WM_MENUSELECT"; + case 0x0120: return "WM_MENUCHAR"; + case 0x0121: return "WM_ENTERIDLE"; + case 0x0200: return "WM_MOUSEMOVE"; + case 0x0201: return "WM_LBUTTONDOWN"; + case 0x0202: return "WM_LBUTTONUP"; + case 0x0203: return "WM_LBUTTONDBLCLK"; + case 0x0204: return "WM_RBUTTONDOWN"; + case 0x0205: return "WM_RBUTTONUP"; + case 0x0206: return "WM_RBUTTONDBLCLK"; + case 0x0207: return "WM_MBUTTONDOWN"; + case 0x0208: return "WM_MBUTTONUP"; + case 0x0209: return "WM_MBUTTONDBLCLK"; + case 0x020A: return "WM_MOUSEWHEEL"; + case 0x0210: return "WM_PARENTNOTIFY"; + case 0x0211: return "WM_ENTERMENULOOP"; + case 0x0212: return "WM_EXITMENULOOP"; + +#ifdef __WIN32__ + case 0x0213: return "WM_NEXTMENU"; + case 0x0214: return "WM_SIZING"; + case 0x0215: return "WM_CAPTURECHANGED"; + case 0x0216: return "WM_MOVING"; + case 0x0218: return "WM_POWERBROADCAST"; + case 0x0219: return "WM_DEVICECHANGE"; +#endif //WIN32 + + case 0x0220: return "WM_MDICREATE"; + case 0x0221: return "WM_MDIDESTROY"; + case 0x0222: return "WM_MDIACTIVATE"; + case 0x0223: return "WM_MDIRESTORE"; + case 0x0224: return "WM_MDINEXT"; + case 0x0225: return "WM_MDIMAXIMIZE"; + case 0x0226: return "WM_MDITILE"; + case 0x0227: return "WM_MDICASCADE"; + case 0x0228: return "WM_MDIICONARRANGE"; + case 0x0229: return "WM_MDIGETACTIVE"; + case 0x0230: return "WM_MDISETMENU"; + case 0x0233: return "WM_DROPFILES"; + +#ifdef __WIN32__ + case 0x0281: return "WM_IME_SETCONTEXT"; + case 0x0282: return "WM_IME_NOTIFY"; + case 0x0283: return "WM_IME_CONTROL"; + case 0x0284: return "WM_IME_COMPOSITIONFULL"; + case 0x0285: return "WM_IME_SELECT"; + case 0x0286: return "WM_IME_CHAR"; + case 0x0290: return "WM_IME_KEYDOWN"; + case 0x0291: return "WM_IME_KEYUP"; +#endif //WIN32 + + case 0x0300: return "WM_CUT"; + case 0x0301: return "WM_COPY"; + case 0x0302: return "WM_PASTE"; + case 0x0303: return "WM_CLEAR"; + case 0x0304: return "WM_UNDO"; + case 0x0305: return "WM_RENDERFORMAT"; + case 0x0306: return "WM_RENDERALLFORMATS"; + case 0x0307: return "WM_DESTROYCLIPBOARD"; + case 0x0308: return "WM_DRAWCLIPBOARD"; + case 0x0309: return "WM_PAINTCLIPBOARD"; + case 0x030A: return "WM_VSCROLLCLIPBOARD"; + case 0x030B: return "WM_SIZECLIPBOARD"; + case 0x030C: return "WM_ASKCBFORMATNAME"; + case 0x030D: return "WM_CHANGECBCHAIN"; + case 0x030E: return "WM_HSCROLLCLIPBOARD"; + case 0x030F: return "WM_QUERYNEWPALETTE"; + case 0x0310: return "WM_PALETTEISCHANGING"; + case 0x0311: return "WM_PALETTECHANGED"; - wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId); - event.SetEventObject(this); - event.SetForce(force); +#ifdef __WIN32__ + // common controls messages - although they're not strictly speaking + // standard, it's nice to decode them nevertheless + + // listview + case 0x1000 + 0: return "LVM_GETBKCOLOR"; + case 0x1000 + 1: return "LVM_SETBKCOLOR"; + case 0x1000 + 2: return "LVM_GETIMAGELIST"; + case 0x1000 + 3: return "LVM_SETIMAGELIST"; + case 0x1000 + 4: return "LVM_GETITEMCOUNT"; + case 0x1000 + 5: return "LVM_GETITEMA"; + case 0x1000 + 75: return "LVM_GETITEMW"; + case 0x1000 + 6: return "LVM_SETITEMA"; + case 0x1000 + 76: return "LVM_SETITEMW"; + case 0x1000 + 7: return "LVM_INSERTITEMA"; + case 0x1000 + 77: return "LVM_INSERTITEMW"; + case 0x1000 + 8: return "LVM_DELETEITEM"; + case 0x1000 + 9: return "LVM_DELETEALLITEMS"; + case 0x1000 + 10: return "LVM_GETCALLBACKMASK"; + case 0x1000 + 11: return "LVM_SETCALLBACKMASK"; + case 0x1000 + 12: return "LVM_GETNEXTITEM"; + case 0x1000 + 13: return "LVM_FINDITEMA"; + case 0x1000 + 83: return "LVM_FINDITEMW"; + case 0x1000 + 14: return "LVM_GETITEMRECT"; + case 0x1000 + 15: return "LVM_SETITEMPOSITION"; + case 0x1000 + 16: return "LVM_GETITEMPOSITION"; + case 0x1000 + 17: return "LVM_GETSTRINGWIDTHA"; + case 0x1000 + 87: return "LVM_GETSTRINGWIDTHW"; + case 0x1000 + 18: return "LVM_HITTEST"; + case 0x1000 + 19: return "LVM_ENSUREVISIBLE"; + case 0x1000 + 20: return "LVM_SCROLL"; + case 0x1000 + 21: return "LVM_REDRAWITEMS"; + case 0x1000 + 22: return "LVM_ARRANGE"; + case 0x1000 + 23: return "LVM_EDITLABELA"; + case 0x1000 + 118: return "LVM_EDITLABELW"; + case 0x1000 + 24: return "LVM_GETEDITCONTROL"; + case 0x1000 + 25: return "LVM_GETCOLUMNA"; + case 0x1000 + 95: return "LVM_GETCOLUMNW"; + case 0x1000 + 26: return "LVM_SETCOLUMNA"; + case 0x1000 + 96: return "LVM_SETCOLUMNW"; + case 0x1000 + 27: return "LVM_INSERTCOLUMNA"; + case 0x1000 + 97: return "LVM_INSERTCOLUMNW"; + case 0x1000 + 28: return "LVM_DELETECOLUMN"; + case 0x1000 + 29: return "LVM_GETCOLUMNWIDTH"; + case 0x1000 + 30: return "LVM_SETCOLUMNWIDTH"; + case 0x1000 + 31: return "LVM_GETHEADER"; + case 0x1000 + 33: return "LVM_CREATEDRAGIMAGE"; + case 0x1000 + 34: return "LVM_GETVIEWRECT"; + case 0x1000 + 35: return "LVM_GETTEXTCOLOR"; + case 0x1000 + 36: return "LVM_SETTEXTCOLOR"; + case 0x1000 + 37: return "LVM_GETTEXTBKCOLOR"; + case 0x1000 + 38: return "LVM_SETTEXTBKCOLOR"; + case 0x1000 + 39: return "LVM_GETTOPINDEX"; + case 0x1000 + 40: return "LVM_GETCOUNTPERPAGE"; + case 0x1000 + 41: return "LVM_GETORIGIN"; + case 0x1000 + 42: return "LVM_UPDATE"; + case 0x1000 + 43: return "LVM_SETITEMSTATE"; + case 0x1000 + 44: return "LVM_GETITEMSTATE"; + case 0x1000 + 45: return "LVM_GETITEMTEXTA"; + case 0x1000 + 115: return "LVM_GETITEMTEXTW"; + case 0x1000 + 46: return "LVM_SETITEMTEXTA"; + case 0x1000 + 116: return "LVM_SETITEMTEXTW"; + case 0x1000 + 47: return "LVM_SETITEMCOUNT"; + case 0x1000 + 48: return "LVM_SORTITEMS"; + case 0x1000 + 49: return "LVM_SETITEMPOSITION32"; + case 0x1000 + 50: return "LVM_GETSELECTEDCOUNT"; + case 0x1000 + 51: return "LVM_GETITEMSPACING"; + case 0x1000 + 52: return "LVM_GETISEARCHSTRINGA"; + case 0x1000 + 117: return "LVM_GETISEARCHSTRINGW"; + case 0x1000 + 53: return "LVM_SETICONSPACING"; + case 0x1000 + 54: return "LVM_SETEXTENDEDLISTVIEWSTYLE"; + case 0x1000 + 55: return "LVM_GETEXTENDEDLISTVIEWSTYLE"; + case 0x1000 + 56: return "LVM_GETSUBITEMRECT"; + case 0x1000 + 57: return "LVM_SUBITEMHITTEST"; + case 0x1000 + 58: return "LVM_SETCOLUMNORDERARRAY"; + case 0x1000 + 59: return "LVM_GETCOLUMNORDERARRAY"; + case 0x1000 + 60: return "LVM_SETHOTITEM"; + case 0x1000 + 61: return "LVM_GETHOTITEM"; + case 0x1000 + 62: return "LVM_SETHOTCURSOR"; + case 0x1000 + 63: return "LVM_GETHOTCURSOR"; + case 0x1000 + 64: return "LVM_APPROXIMATEVIEWRECT"; + case 0x1000 + 65: return "LVM_SETWORKAREA"; + + // tree view + case 0x1100 + 0: return "TVM_INSERTITEMA"; + case 0x1100 + 50: return "TVM_INSERTITEMW"; + case 0x1100 + 1: return "TVM_DELETEITEM"; + case 0x1100 + 2: return "TVM_EXPAND"; + case 0x1100 + 4: return "TVM_GETITEMRECT"; + case 0x1100 + 5: return "TVM_GETCOUNT"; + case 0x1100 + 6: return "TVM_GETINDENT"; + case 0x1100 + 7: return "TVM_SETINDENT"; + case 0x1100 + 8: return "TVM_GETIMAGELIST"; + case 0x1100 + 9: return "TVM_SETIMAGELIST"; + case 0x1100 + 10: return "TVM_GETNEXTITEM"; + case 0x1100 + 11: return "TVM_SELECTITEM"; + case 0x1100 + 12: return "TVM_GETITEMA"; + case 0x1100 + 62: return "TVM_GETITEMW"; + case 0x1100 + 13: return "TVM_SETITEMA"; + case 0x1100 + 63: return "TVM_SETITEMW"; + case 0x1100 + 14: return "TVM_EDITLABELA"; + case 0x1100 + 65: return "TVM_EDITLABELW"; + case 0x1100 + 15: return "TVM_GETEDITCONTROL"; + case 0x1100 + 16: return "TVM_GETVISIBLECOUNT"; + case 0x1100 + 17: return "TVM_HITTEST"; + case 0x1100 + 18: return "TVM_CREATEDRAGIMAGE"; + case 0x1100 + 19: return "TVM_SORTCHILDREN"; + case 0x1100 + 20: return "TVM_ENSUREVISIBLE"; + case 0x1100 + 21: return "TVM_SORTCHILDRENCB"; + case 0x1100 + 22: return "TVM_ENDEDITLABELNOW"; + case 0x1100 + 23: return "TVM_GETISEARCHSTRINGA"; + case 0x1100 + 64: return "TVM_GETISEARCHSTRINGW"; + case 0x1100 + 24: return "TVM_SETTOOLTIPS"; + case 0x1100 + 25: return "TVM_GETTOOLTIPS"; + + // header + case 0x1200 + 0: return "HDM_GETITEMCOUNT"; + case 0x1200 + 1: return "HDM_INSERTITEMA"; + case 0x1200 + 10: return "HDM_INSERTITEMW"; + case 0x1200 + 2: return "HDM_DELETEITEM"; + case 0x1200 + 3: return "HDM_GETITEMA"; + case 0x1200 + 11: return "HDM_GETITEMW"; + case 0x1200 + 4: return "HDM_SETITEMA"; + case 0x1200 + 12: return "HDM_SETITEMW"; + case 0x1200 + 5: return "HDM_LAYOUT"; + case 0x1200 + 6: return "HDM_HITTEST"; + case 0x1200 + 7: return "HDM_GETITEMRECT"; + case 0x1200 + 8: return "HDM_SETIMAGELIST"; + case 0x1200 + 9: return "HDM_GETIMAGELIST"; + case 0x1200 + 15: return "HDM_ORDERTOINDEX"; + case 0x1200 + 16: return "HDM_CREATEDRAGIMAGE"; + case 0x1200 + 17: return "HDM_GETORDERARRAY"; + case 0x1200 + 18: return "HDM_SETORDERARRAY"; + case 0x1200 + 19: return "HDM_SETHOTDIVIDER"; + + // tab control + case 0x1300 + 2: return "TCM_GETIMAGELIST"; + case 0x1300 + 3: return "TCM_SETIMAGELIST"; + case 0x1300 + 4: return "TCM_GETITEMCOUNT"; + case 0x1300 + 5: return "TCM_GETITEMA"; + case 0x1300 + 60: return "TCM_GETITEMW"; + case 0x1300 + 6: return "TCM_SETITEMA"; + case 0x1300 + 61: return "TCM_SETITEMW"; + case 0x1300 + 7: return "TCM_INSERTITEMA"; + case 0x1300 + 62: return "TCM_INSERTITEMW"; + case 0x1300 + 8: return "TCM_DELETEITEM"; + case 0x1300 + 9: return "TCM_DELETEALLITEMS"; + case 0x1300 + 10: return "TCM_GETITEMRECT"; + case 0x1300 + 11: return "TCM_GETCURSEL"; + case 0x1300 + 12: return "TCM_SETCURSEL"; + case 0x1300 + 13: return "TCM_HITTEST"; + case 0x1300 + 14: return "TCM_SETITEMEXTRA"; + case 0x1300 + 40: return "TCM_ADJUSTRECT"; + case 0x1300 + 41: return "TCM_SETITEMSIZE"; + case 0x1300 + 42: return "TCM_REMOVEIMAGE"; + case 0x1300 + 43: return "TCM_SETPADDING"; + case 0x1300 + 44: return "TCM_GETROWCOUNT"; + case 0x1300 + 45: return "TCM_GETTOOLTIPS"; + case 0x1300 + 46: return "TCM_SETTOOLTIPS"; + case 0x1300 + 47: return "TCM_GETCURFOCUS"; + case 0x1300 + 48: return "TCM_SETCURFOCUS"; + case 0x1300 + 49: return "TCM_SETMINTABWIDTH"; + case 0x1300 + 50: return "TCM_DESELECTALL"; + + // toolbar + case WM_USER+1: return "TB_ENABLEBUTTON"; + case WM_USER+2: return "TB_CHECKBUTTON"; + case WM_USER+3: return "TB_PRESSBUTTON"; + case WM_USER+4: return "TB_HIDEBUTTON"; + case WM_USER+5: return "TB_INDETERMINATE"; + case WM_USER+9: return "TB_ISBUTTONENABLED"; + case WM_USER+10: return "TB_ISBUTTONCHECKED"; + case WM_USER+11: return "TB_ISBUTTONPRESSED"; + case WM_USER+12: return "TB_ISBUTTONHIDDEN"; + case WM_USER+13: return "TB_ISBUTTONINDETERMINATE"; + case WM_USER+17: return "TB_SETSTATE"; + case WM_USER+18: return "TB_GETSTATE"; + case WM_USER+19: return "TB_ADDBITMAP"; + case WM_USER+20: return "TB_ADDBUTTONS"; + case WM_USER+21: return "TB_INSERTBUTTON"; + case WM_USER+22: return "TB_DELETEBUTTON"; + case WM_USER+23: return "TB_GETBUTTON"; + case WM_USER+24: return "TB_BUTTONCOUNT"; + case WM_USER+25: return "TB_COMMANDTOINDEX"; + case WM_USER+26: return "TB_SAVERESTOREA"; + case WM_USER+76: return "TB_SAVERESTOREW"; + case WM_USER+27: return "TB_CUSTOMIZE"; + case WM_USER+28: return "TB_ADDSTRINGA"; + case WM_USER+77: return "TB_ADDSTRINGW"; + case WM_USER+29: return "TB_GETITEMRECT"; + case WM_USER+30: return "TB_BUTTONSTRUCTSIZE"; + case WM_USER+31: return "TB_SETBUTTONSIZE"; + case WM_USER+32: return "TB_SETBITMAPSIZE"; + case WM_USER+33: return "TB_AUTOSIZE"; + case WM_USER+35: return "TB_GETTOOLTIPS"; + case WM_USER+36: return "TB_SETTOOLTIPS"; + case WM_USER+37: return "TB_SETPARENT"; + case WM_USER+39: return "TB_SETROWS"; + case WM_USER+40: return "TB_GETROWS"; + case WM_USER+42: return "TB_SETCMDID"; + case WM_USER+43: return "TB_CHANGEBITMAP"; + case WM_USER+44: return "TB_GETBITMAP"; + case WM_USER+45: return "TB_GETBUTTONTEXTA"; + case WM_USER+75: return "TB_GETBUTTONTEXTW"; + case WM_USER+46: return "TB_REPLACEBITMAP"; + case WM_USER+47: return "TB_SETINDENT"; + case WM_USER+48: return "TB_SETIMAGELIST"; + case WM_USER+49: return "TB_GETIMAGELIST"; + case WM_USER+50: return "TB_LOADIMAGES"; + case WM_USER+51: return "TB_GETRECT"; + case WM_USER+52: return "TB_SETHOTIMAGELIST"; + case WM_USER+53: return "TB_GETHOTIMAGELIST"; + case WM_USER+54: return "TB_SETDISABLEDIMAGELIST"; + case WM_USER+55: return "TB_GETDISABLEDIMAGELIST"; + case WM_USER+56: return "TB_SETSTYLE"; + case WM_USER+57: return "TB_GETSTYLE"; + case WM_USER+58: return "TB_GETBUTTONSIZE"; + case WM_USER+59: return "TB_SETBUTTONWIDTH"; + case WM_USER+60: return "TB_SETMAXTEXTROWS"; + case WM_USER+61: return "TB_GETTEXTROWS"; + case WM_USER+41: return "TB_GETBITMAPFLAGS"; + +#endif //WIN32 - return GetEventHandler()->ProcessEvent(event); + default: + static char s_szBuf[128]; + sprintf(s_szBuf, "", message); + return s_szBuf; + } +} +#endif //__WXDEBUG__ -/* - if ( !force && event.GetVeto() ) - return FALSE; +static void TranslateKbdEventToMouse(wxWindowMSW *win, + int *x, int *y, WPARAM *flags) +{ + // construct the key mask + WPARAM& fwKeys = *flags; - Show(FALSE); + fwKeys = MK_RBUTTON; + if ( wxIsCtrlDown() ) + fwKeys |= MK_CONTROL; + if ( wxIsShiftDown() ) + fwKeys |= MK_SHIFT; - if (!wxPendingDelete.Member(this)) - wxPendingDelete.Append(this); + // simulate right mouse button click + DWORD dwPos = ::GetMessagePos(); + *x = GET_X_LPARAM(dwPos); + *y = GET_Y_LPARAM(dwPos); - return TRUE; -*/ + win->ScreenToClient(x, y); } -wxObject* wxWindow::GetChild(const int number) const +static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win) { - // Return a pointer to the Nth object in the Panel - if (!GetChildren()) - return(NULL) ; - wxNode *node = GetChildren()->First(); - int n = number; - while (node && n--) - node = node->Next() ; - if (node) - { - wxObject *obj = (wxObject *)node->Data(); - return(obj) ; - } - else - return NULL ; -} + // prepare the DC + TEXTMETRIC tm; + HWND hwnd = GetHwndOf(win); + HDC hdc = ::GetDC(hwnd); -void wxWindow::OnDefaultAction(wxControl *initiatingItem) -{ - if (initiatingItem->IsKindOf(CLASSINFO(wxListBox)) && initiatingItem->GetCallback()) - { - wxListBox *lbox = (wxListBox *)initiatingItem; - wxCommandEvent event(wxEVENT_TYPE_LISTBOX_DCLICK_COMMAND); - event.m_commandInt = -1; - if ((lbox->GetWindowStyleFlag() & wxLB_MULTIPLE) == 0) +#if !wxDIALOG_UNIT_COMPATIBILITY + // and select the current font into it + HFONT hfont = GetHfontOf(win->GetFont()); + if ( hfont ) { - event.m_commandString = copystring(lbox->GetStringSelection()); - event.m_commandInt = lbox->GetSelection(); - event.m_clientData = lbox->wxListBox::GetClientData(event.m_commandInt); + hfont = (HFONT)::SelectObject(hdc, hfont); } - event.m_eventObject = lbox; +#endif - lbox->ProcessCommand(event); + // finally retrieve the text metrics from it + GetTextMetrics(hdc, &tm); - if (event.m_commandString) - delete[] event.m_commandString; - return; - } - - wxButton *but = GetDefaultItem(); - if (but) - { - wxCommandEvent event(wxEVENT_TYPE_BUTTON_COMMAND); - but->Command(event); - } -} +#if !wxDIALOG_UNIT_COMPATIBILITY + // and clean up + if ( hfont ) + { + (void)::SelectObject(hdc, hfont); + } +#endif -void wxWindow::Clear(void) -{ - wxClientDC dc(this); - wxBrush brush(GetBackgroundColour(), wxSOLID); - dc.SetBackground(brush); - dc.Clear(); -} + ::ReleaseDC(hwnd, hdc); -// Fits the panel around the items -void wxWindow::Fit(void) -{ - int maxX = 0; - int maxY = 0; - wxNode *node = GetChildren()->First(); - while ( node ) - { - wxWindow *win = (wxWindow *)node->Data(); - int wx, wy, ww, wh; - win->GetPosition(&wx, &wy); - win->GetSize(&ww, &wh); - if ( wx + ww > maxX ) - maxX = wx + ww; - if ( wy + wh > maxY ) - maxY = wy + wh; - - node = node->Next(); - } - SetClientSize(maxX + 5, maxY + 5); -} - -void wxWindow::SetValidator(const wxValidator& validator) -{ - if ( m_windowValidator ) - delete m_windowValidator; - m_windowValidator = validator.Clone(); - - if ( m_windowValidator ) - m_windowValidator->SetWindow(this) ; -} - -// Find a window by id or name -wxWindow *wxWindow::FindWindow(const long id) -{ - if ( GetId() == id) - return this; - - wxNode *node = GetChildren()->First(); - while ( node ) - { - wxWindow *child = (wxWindow *)node->Data(); - wxWindow *found = child->FindWindow(id); - if ( found ) - return found; - node = node->Next(); - } - return NULL; -} - -wxWindow *wxWindow::FindWindow(const wxString& name) -{ - if ( GetName() == name) - return this; - - wxNode *node = GetChildren()->First(); - while ( node ) - { - wxWindow *child = (wxWindow *)node->Data(); - wxWindow *found = child->FindWindow(name); - if ( found ) - return found; - node = node->Next(); - } - return NULL; -} - -/* TODO -// Default input behaviour for a scrolling canvas should be to scroll -// according to the cursor keys pressed -void wxWindow::OnChar(wxKeyEvent& event) -{ - int x_page = 0; - int y_page = 0; - int start_x = 0; - int start_y = 0; - // Bugfix Begin - int v_width = 0; - int v_height = 0; - int y_pages = 0; - // Bugfix End - - GetScrollUnitsPerPage(&x_page, &y_page); - // Bugfix Begin - GetVirtualSize(&v_width,&v_height); - // Bugfix End - ViewStart(&start_x, &start_y); - // Bugfix begin - if (vert_units) - y_pages = (int)(v_height/vert_units) - y_page; - -#ifdef __WINDOWS__ - int y = 0; -#else - int y = y_page-1; -#endif - // Bugfix End - switch (event.keyCode) - { - case WXK_PRIOR: - { - // BugFix Begin - if (y_page > 0) - { - if (start_y - y_page > 0) - Scroll(start_x, start_y - y_page); - else - Scroll(start_x, 0); - } - // Bugfix End - break; - } - case WXK_NEXT: - { - // Bugfix Begin - if ((y_page > 0) && (start_y <= y_pages-y-1)) - { - if (y_pages + y < start_y + y_page) - Scroll(start_x, y_pages + y); - else - Scroll(start_x, start_y + y_page); - } - // Bugfix End - break; - } - case WXK_UP: - { - if ((y_page > 0) && (start_y >= 1)) - Scroll(start_x, start_y - 1); - break; - } - case WXK_DOWN: - { - // Bugfix Begin - if ((y_page > 0) && (start_y <= y_pages-y-1)) - // Bugfix End - { - Scroll(start_x, start_y + 1); - } - break; - } - case WXK_LEFT: - { - if ((x_page > 0) && (start_x >= 1)) - Scroll(start_x - 1, start_y); - break; - } - case WXK_RIGHT: - { - if (x_page > 0) - Scroll(start_x + 1, start_y); - break; - } - case WXK_HOME: - { - Scroll(0, 0); - break; - } - // This is new - case WXK_END: - { - Scroll(start_x, y_pages+y); - break; - } - // end - } -} -*/ + return tm; +} -// Setup background and foreground colours correctly -void wxWindow::SetupColours(void) +// Find the wxWindow at the current mouse position, returning the mouse +// position. +wxWindow* wxFindWindowAtPointer(wxPoint& WXUNUSED(pt)) { - if (GetParent()) - SetBackgroundColour(GetParent()->GetBackgroundColour()); + return wxFindWindowAtPoint(wxGetMousePosition()); } -// Do Update UI processing for child controls - -// TODO: should this be implemented for the child window rather -// than the parent? Then you can override it e.g. for wxCheckBox -// to do the Right Thing rather than having to assume a fixed number -// of control classes. - -void wxWindow::UpdateWindowUI(void) +wxWindow* wxFindWindowAtPoint(const wxPoint& pt) { - wxWindowID id = GetId(); - if (id > 0) - { - wxUpdateUIEvent event(id); - event.m_eventObject = this; - - if (this->GetEventHandler()->ProcessEvent(event)) - { - if (event.GetSetEnabled()) - this->Enable(event.GetEnabled()); - - if (event.GetSetText() && this->IsKindOf(CLASSINFO(wxControl))) - ((wxControl*)this)->SetLabel(event.GetText()); - - if (this->IsKindOf(CLASSINFO(wxCheckBox))) - { - if (event.GetSetChecked()) - ((wxCheckBox *) this)->SetValue(event.GetChecked()); - } - else if (this->IsKindOf(CLASSINFO(wxRadioButton))) - { - if (event.GetSetChecked()) - ((wxRadioButton *) this)->SetValue(event.GetChecked()); - } - } - } + POINT pt2; + pt2.x = pt.x; + pt2.y = pt.y; + HWND hWndHit = ::WindowFromPoint(pt2); -} + wxWindow* win = wxFindWinFromHandle((WXHWND) hWndHit) ; + HWND hWnd = hWndHit; -void wxWindow::OnIdle(wxIdleEvent& event) -{ - UpdateWindowUI(); + // Try to find a window with a wxWindow associated with it + while (!win && (hWnd != 0)) + { + hWnd = ::GetParent(hWnd); + win = wxFindWinFromHandle((WXHWND) hWnd) ; + } + return win; } -// Raise the window to the top of the Z order -void wxWindow::Raise(void) +// Get the current mouse position. +wxPoint wxGetMousePosition() { - ::BringWindowToTop((HWND) GetHWND()); -} + POINT pt; + GetCursorPos( & pt ); -// Lower the window to the bottom of the Z order -void wxWindow::Lower(void) -{ - ::SetWindowPos((HWND) GetHWND(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE); + return wxPoint(pt.x, pt.y); }