// Modified by: VZ on 13.05.99: no more Default(), MSWOnXXX() reorganisation
// Created: 04/01/98
// RCS-ID: $Id$
-// Copyright: (c) Julian Smart and Markus Holzem
-// Licence: wxWindows license
+// Copyright: (c) Julian Smart
+// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ===========================================================================
#include "wx/dnd.h"
#endif
+#if wxUSE_ACCESSIBILITY
+ #include "wx/access.h"
+ #include <oleacc.h>
+ #ifndef WM_GETOBJECT
+ #define WM_GETOBJECT 0x003D
+ #endif
+ #ifndef OBJID_CLIENT
+ #define OBJID_CLIENT 0xFFFFFFFC
+ #endif
+#endif
+
#include "wx/menuitem.h"
#include "wx/log.h"
#ifndef VK_OEM_1
#define VK_OEM_1 0xBA
- #define VK_OEM_PLUS 0xBB
- #define VK_OEM_COMMA 0xBC
- #define VK_OEM_MINUS 0xBD
- #define VK_OEM_PERIOD 0xBE
#define VK_OEM_2 0xBF
#define VK_OEM_3 0xC0
#define VK_OEM_4 0xDB
#define VK_OEM_7 0xDE
#endif
+#ifndef VK_OEM_COMMA
+ #define VK_OEM_PLUS 0xBB
+ #define VK_OEM_COMMA 0xBC
+ #define VK_OEM_MINUS 0xBD
+ #define VK_OEM_PERIOD 0xBE
+#endif
+
// ---------------------------------------------------------------------------
// global variables
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// the window proc for all our windows
+#ifdef __DIGITALMARS__
+extern "C" LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
+ WPARAM wParam, LPARAM lParam);
+#else
LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam);
+#endif
+
#ifdef __WXDEBUG__
const char *wxGetMessageName(int message);
#endif //__WXDEBUG__
void wxRemoveHandleAssociation(wxWindowMSW *win);
-void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win);
+#ifdef __DIGITALMARS__
+extern "C" void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win);
+#else
+extern void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win);
+#endif
wxWindow *wxFindWinFromHandle(WXHWND hWnd);
// this magical function is used to translate VK_APPS key presses to right
// get the text metrics for the current font
static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win);
+// find the window for the mouse event at the specified position
+static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y); //TW:REQ:Univ
+
// wrapper around BringWindowToTop() API
static inline void wxBringWindowToTop(HWND hwnd)
{
InitBase();
// MSW specific
- m_doubleClickAllowed = 0;
-
m_isBeingDeleted = FALSE;
- m_oldWndProc = 0;
+ m_oldWndProc = NULL;
m_useCtl3D = FALSE;
m_mouseInWindow = FALSE;
m_lastKeydownProcessed = FALSE;
+ m_childrenDisabled = NULL;
+
// wxWnd
m_hMenu = 0;
// VS: make sure there's no wxFrame with last focus set to us:
for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
{
- wxFrame *frame = wxDynamicCast(win, wxFrame);
+ wxTopLevelWindow *frame = wxDynamicCast(win, wxTopLevelWindow);
if ( frame )
{
if ( frame->GetLastFocus() == this )
{
- frame->SetLastFocus((wxWindow*)NULL);
+ frame->SetLastFocus(NULL);
}
break;
}
// remove hWnd <-> wxWindow association
wxRemoveHandleAssociation(this);
}
+
+ delete m_childrenDisabled;
}
// real construction (Init() must have been called before!)
{
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;
parent->AddChild(this);
- // note that all windows are created visible by default
WXDWORD exstyle;
- DWORD msflags = WS_VISIBLE | MSWGetCreateWindowFlags(&exstyle);
+ DWORD msflags = MSWGetCreateWindowFlags(&exstyle);
#ifdef __WXUNIVERSAL__
// no borders, we draw them ourselves
- exstyle = 0;
+ exstyle &= ~(WS_EX_DLGMODALFRAME |
+ WS_EX_STATICEDGE |
+ WS_EX_CLIENTEDGE |
+ WS_EX_WINDOWEDGE);
msflags &= ~WS_BORDER;
#endif // wxUniversal
+ // all windows are created visible by default except popup ones (which are
+ // like the wxTopLevelWindows in this aspect)
if ( style & wxPOPUP_WINDOW )
{
- // a popup window floats on top of everything
- exstyle |= WS_EX_TOPMOST | WS_EX_TOOLWINDOW;
-
- // it is also created hidden as other top level windows
msflags &= ~WS_VISIBLE;
m_isShown = FALSE;
}
+ else
+ {
+ msflags |= WS_VISIBLE;
+ }
return MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle);
}
}
}
+void wxWindowMSW::SetFocusFromKbd()
+{
+ wxWindowBase::SetFocusFromKbd();
+
+ // when the focus is given to the control with DLGC_HASSETSEL style from
+ // keyboard its contents should be entirely selected: this is what
+ // ::IsDialogMessage() does and so we should do it as well to provide the
+ // same LNF as the native programs
+ if ( ::SendMessage(GetHwnd(), WM_GETDLGCODE, 0, 0) & DLGC_HASSETSEL )
+ {
+ ::SendMessage(GetHwnd(), EM_SETSEL, 0, -1);
+ }
+}
+
// Get the window with the focus
wxWindow *wxWindowBase::FindFocus()
{
if ( hWnd )
::EnableWindow(hWnd, (BOOL)enable);
- // VZ: no, this is a bad idea: imagine that you have a dialog with some
- // disabled controls and disable it - you really wouldn't like the
- // disabled controls be reenabled too when you reenable the dialog!
-#if 0
- wxWindowList::Node *node = GetChildren().GetFirst();
- while ( node )
+ // the logic below doesn't apply to the top level windows -- otherwise
+ // showing a modal dialog would result in total greying out (and ungreying
+ // out later) of everything which would be really ugly
+ if ( IsTopLevel() )
+ return TRUE;
+
+ // when the parent is disabled, all of its children should be disabled as
+ // well but when it is enabled back, only those of the children which
+ // hadn't been already disabled in the beginning should be enabled again,
+ // so we have to keep the list of those children
+ for ( wxWindowList::Node *node = GetChildren().GetFirst();
+ node;
+ node = node->GetNext() )
{
wxWindow *child = node->GetData();
- child->Enable(enable);
+ if ( child->IsTopLevel() )
+ {
+ // the logic below doesn't apply to top level children
+ continue;
+ }
- node = node->GetNext();
+ if ( enable )
+ {
+ // enable the child back unless it had been disabled before us
+ if ( !m_childrenDisabled || !m_childrenDisabled->Find(child) )
+ child->Enable();
+ }
+ else // we're being disabled
+ {
+ if ( child->IsEnabled() )
+ {
+ // disable it as children shouldn't stay enabled while the
+ // parent is not
+ child->Disable();
+ }
+ else // child already disabled, remember it
+ {
+ // have we created the list of disabled children already?
+ if ( !m_childrenDisabled )
+ m_childrenDisabled = new wxWindowList;
+
+ m_childrenDisabled->Append(child);
+ }
+ }
+ }
+
+ if ( enable && m_childrenDisabled )
+ {
+ // we don't need this list any more, don't keep unused memory
+ delete m_childrenDisabled;
+ m_childrenDisabled = NULL;
}
-#endif // 0
return TRUE;
}
// scrolling stuff
// ---------------------------------------------------------------------------
+// convert wxHORIZONTAL/wxVERTICAL to SB_HORZ/SB_VERT
+static inline int wxDirToWinStyle(int orient)
+{
+ return orient == wxHORIZONTAL ? SB_HORZ : SB_VERT;
+}
+
#if WXWIN_COMPATIBILITY
void wxWindowMSW::SetScrollRange(int orient, int range, bool refresh)
{
-#if defined(__WIN95__)
-
int range1 = range;
// Try to adjust the range to cope with page size > 1
range1 += (pageSize - 1);
}
- SCROLLINFO info;
- int dir;
-
- if ( orient == wxHORIZONTAL ) {
- dir = SB_HORZ;
- } else {
- dir = SB_VERT;
- }
-
- info.cbSize = sizeof(SCROLLINFO);
+ WinStruct<SCROLLINFO> info;
info.nPage = pageSize; // Have to set this, or scrollbar goes awry
info.nMin = 0;
info.nMax = range1;
- info.nPos = 0;
info.fMask = SIF_RANGE | SIF_PAGE;
HWND hWnd = GetHwnd();
if ( hWnd )
- ::SetScrollInfo(hWnd, dir, &info, refresh);
-#else
- int wOrient;
- if ( orient == wxHORIZONTAL )
- wOrient = SB_HORZ;
- else
- wOrient = SB_VERT;
-
- HWND hWnd = GetHwnd();
- if ( hWnd )
- ::SetScrollRange(hWnd, wOrient, 0, range, refresh);
-#endif
+ ::SetScrollInfo(hWnd, wxDirToWinStyle(orient), &info, refresh);
}
void wxWindowMSW::SetScrollPage(int orient, int page, bool refresh)
{
-#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);
+ WinStruct<SCROLLINFO> info;
info.nPage = page;
- info.nMin = 0;
info.fMask = SIF_PAGE;
HWND hWnd = GetHwnd();
if ( hWnd )
- ::SetScrollInfo(hWnd, dir, &info, refresh);
-#else
- if ( orient == wxHORIZONTAL )
- m_xThumbSize = page;
- else
- m_yThumbSize = page;
-#endif
-}
-
-int wxWindowMSW::OldGetScrollRange(int orient) const
-{
- int wOrient;
- if ( orient == wxHORIZONTAL )
- wOrient = SB_HORZ;
- else
- wOrient = SB_VERT;
-
-#if __WATCOMC__ && defined(__WINDOWS_386__)
- short minPos, maxPos;
-#else
- int minPos, maxPos;
-#endif
- HWND hWnd = GetHwnd();
- if ( hWnd )
- {
- ::GetScrollRange(hWnd, wOrient, &minPos, &maxPos);
-#if defined(__WIN95__)
- // Try to adjust the range to cope with page size > 1
- // - a Windows API quirk
- int pageSize = GetScrollPage(orient);
- if ( pageSize > 1 )
- {
- maxPos -= (pageSize - 1);
- }
-#endif
- return maxPos;
- }
- else
- return 0;
+ ::SetScrollInfo(hWnd, wxDirToWinStyle(orient), &info, refresh);
}
int wxWindowMSW::GetScrollPage(int orient) const
{
- if ( orient == wxHORIZONTAL )
- return m_xThumbSize;
- else
- return m_yThumbSize;
+ return orient == wxHORIZONTAL ? m_xThumbSize : m_yThumbSize;
}
#endif // WXWIN_COMPATIBILITY
int wxWindowMSW::GetScrollPos(int orient) const
{
- int wOrient;
- if ( orient == wxHORIZONTAL )
- wOrient = SB_HORZ;
- else
- wOrient = SB_VERT;
-
HWND hWnd = GetHwnd();
wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") );
- return GetScrollPosition(hWnd, wOrient);
+ return GetScrollPosition(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT);
}
// This now returns the whole range, not just the number
// of positions that we can scroll.
int wxWindowMSW::GetScrollRange(int orient) const
{
- int wOrient;
- if ( orient == wxHORIZONTAL )
- wOrient = SB_HORZ;
- else
- wOrient = SB_VERT;
-
-#if __WATCOMC__ && defined(__WINDOWS_386__)
- short minPos, maxPos;
-#else
int minPos, maxPos;
-#endif
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
-
- return maxPos;
- }
- else
+ if ( !hWnd )
return 0;
+
+ ::GetScrollRange(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
+ &minPos, &maxPos);
+
+ // undo "range - 1" done in SetScrollbar()
+ return maxPos + 1;
}
int wxWindowMSW::GetScrollThumb(int orient) const
{
- if ( orient == wxHORIZONTAL )
- return m_xThumbSize;
- else
- return m_yThumbSize;
+ return orient == wxHORIZONTAL ? m_xThumbSize : m_yThumbSize;
}
void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh)
HWND hWnd = GetHwnd();
wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") );
- int dir = orient == wxHORIZONTAL ? SB_HORZ : SB_VERT;
-
-#if defined(__WIN95__)
- SCROLLINFO info;
- info.cbSize = sizeof(SCROLLINFO);
+ WinStruct<SCROLLINFO> info;
info.nPage = 0;
info.nMin = 0;
info.nPos = pos;
info.fMask = SIF_POS;
- ::SetScrollInfo(hWnd, dir, &info, refresh);
-#else // !__WIN95__
- ::SetScrollPos(hWnd, dir, pos, refresh);
-#endif // __WIN95__/!__WIN95__
+ ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
+ &info, refresh);
}
// New function that will replace some of the above.
-void wxWindowMSW::SetScrollbar(int orient, int pos, int thumbVisible,
- int range, bool refresh)
-{
-#if defined(__WIN95__)
- int oldRange = range - thumbVisible;
-
- int range1 = oldRange;
-
- // Try to adjust the range to cope with page size > 1
- // - a Windows API quirk
- int pageSize = thumbVisible;
- if ( pageSize > 1 && range > 0)
- {
- 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;
+void wxWindowMSW::SetScrollbar(int orient,
+ int pos,
+ int pageSize,
+ int range,
+ bool refresh)
+{
+ WinStruct<SCROLLINFO> info;
+ info.nPage = pageSize;
+ info.nMin = 0; // range is nMax - nMin + 1
+ info.nMax = range - 1; // as both nMax and nMax are inclusive
info.nPos = pos;
info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
- HWND hWnd = GetHwnd();
- if ( hWnd )
- ::SetScrollInfo(hWnd, dir, &info, refresh);
-#else
- int wOrient;
- if ( orient == wxHORIZONTAL )
- wOrient = SB_HORZ;
- else
- wOrient = SB_VERT;
-
HWND hWnd = GetHwnd();
if ( hWnd )
{
- ::SetScrollRange(hWnd, wOrient, 0, range, FALSE);
- ::SetScrollPos(hWnd, wOrient, pos, refresh);
- }
-#endif
- if ( orient == wxHORIZONTAL ) {
- m_xThumbSize = thumbVisible;
- } else {
- m_yThumbSize = thumbVisible;
+ ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
+ &info, refresh);
}
+
+ *(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize;
}
void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect)
}
else
{
- // don't bother restoring it neither
+ // don't bother restoring it neither: this also makes it easy to
+ // implement IsOfStandardClass() method which returns TRUE for the
+ // standard controls and FALSE for the wxWindows own windows as it can
+ // simply check m_oldWndProc
m_oldWndProc = NULL;
}
}
bool wxCheckWindowWndProc(WXHWND hWnd, WXFARPROC wndProc)
{
-#if wxUSE_UNICODE_MSLU
- // VS: We can't use GetWindowLong(hwnd, GWL_WNDPROC) together with unicows.dll
- // because it doesn't return pointer to the real wnd proc but rather a handle
- // of a fake proc that does Unicode<->ANSI translation.
- //
- // The hack bellow works, because WNDCLASS contains original window handler
- // rather that the unicows fake one. This may not be on purpose, though; if
- // it stops working with future versions of unicows.dll, we can override
- // unicows hooks by setting Unicows_{Set,Get}WindowLong and
- // Unicows_RegisterClass to our own versions that keep track of
- // fake<->real wnd proc mapping.
- //
- // FIXME: Doesn't handle wnd procs set by SetWindowLong, only these set
- // with RegisterClass!!
-
- if ( wxUsingUnicowsDll() )
+ // Unicows note: the code below works, but only because WNDCLASS contains
+ // original window handler rather that the unicows fake one. This may not
+ // be on purpose, though; if it stops working with future versions of
+ // unicows.dll, we can override unicows hooks by setting
+ // Unicows_{Set,Get}WindowLong and Unicows_RegisterClass to our own
+ // versions that keep track of fake<->real wnd proc mapping.
+ WNDCLASS cls;
+ if ( !::GetClassInfo(wxGetInstance(), wxGetWindowClass(hWnd), &cls) )
{
- static wxChar buffer[512];
- WNDCLASS cls;
+ wxLogLastError(_T("GetClassInfo"));
- ::GetClassName((HWND)hWnd, buffer, 512);
- ::GetClassInfo(wxGetInstance(), buffer, &cls);
- return wndProc == (WXFARPROC)cls.lpfnWndProc;
- }
- else
-#endif
- {
- return wndProc == (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC);
+ return FALSE;
}
+
+ return wndProc == (WXFARPROC)cls.lpfnWndProc;
}
// ----------------------------------------------------------------------------
WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
{
// translate the style
- WXDWORD style = WS_CHILD;
+ WXDWORD style = WS_CHILD | WS_VISIBLE;
if ( flags & wxCLIP_CHILDREN )
style |= WS_CLIPCHILDREN;
style |= WS_CLIPSIBLINGS;
wxBorder border = (wxBorder)(flags & wxBORDER_MASK);
- if ( border != wxBORDER_NONE && border != wxBORDER_DEFAULT )
+
+ // Check if we want to automatically give it a sunken style.
+ // Note than because 'sunken' actually maps to WS_EX_CLIENTEDGE, which
+ // is a more neutral term, we don't necessarily get a sunken effect in
+ // Windows XP. Instead we get the appropriate style for the theme.
+
+ if (border == wxBORDER_DEFAULT && wxTheApp->GetAuto3D() &&
+ GetParent() && (GetParent()->IsKindOf(CLASSINFO(wxPanel)) ||
+ GetParent()->IsKindOf(CLASSINFO(wxDialog))) &&
+ ((GetParent()->GetWindowStyleFlag() & wxUSER_COLOURS) != wxUSER_COLOURS))
+ {
+ border = (wxBorder)((flags & wxBORDER_MASK) | wxBORDER_SUNKEN);
+ }
+
+ // Only give it WS_BORDER for wxBORDER_SIMPLE
+ if (border & wxBORDER_SIMPLE)
style |= WS_BORDER;
-
+
// now deal with ext style if the caller wants it
if ( exstyle )
{
if ( flags & wxTRANSPARENT_WINDOW )
*exstyle |= WS_EX_TRANSPARENT;
- switch ( flags & wxBORDER_MASK )
+ switch ( border )
{
default:
wxFAIL_MSG( _T("unknown border style") );
break;
case wxBORDER_RAISED:
- *exstyle |= WS_EX_WINDOWEDGE;
+ *exstyle |= WS_EX_DLGMODALFRAME;
break;
case wxBORDER_SUNKEN:
*exstyle |= WS_EX_CLIENTEDGE;
+ style &= ~WS_BORDER;
break;
case wxBORDER_DOUBLE:
*exstyle |= WS_EX_DLGMODALFRAME;
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__)
- if ( style & wxRAISED_BORDER )
- // It seems that WS_EX_WINDOWEDGE doesn't work, but WS_EX_DLGMODALFRAME does
- exStyle |= WS_EX_DLGMODALFRAME; /* WS_EX_WINDOWEDGE */;
- if ( style & wxSTATIC_BORDER )
- exStyle |= WS_EX_STATICEDGE;
-#endif
- }
- return exStyle;
-}
-
-// Determines whether native 3D effects or CTL3D should be used,
-// applying a default border style if required, and returning an extended
-// style to pass to CreateWindowEx.
-WXDWORD wxWindowMSW::Determine3DEffects(WXDWORD defaultBorderStyle,
- bool *want3D) const
-{
- // If matches certain criteria, then assume no 3D effects
- // unless specifically requested (dealt with in MakeExtendedStyle)
- if ( !GetParent()
-#if wxUSE_CONTROLS
- || !IsKindOf(CLASSINFO(wxControl))
-#endif // wxUSE_CONTROLS
- || (m_windowStyle & wxNO_BORDER) )
- {
- *want3D = FALSE;
- return MakeExtendedStyle(m_windowStyle);
- }
-
- // Determine whether we should be using 3D effects or not.
- bool nativeBorder = FALSE; // by default, we don't want a Win95 effect
-
- // 1) App can specify global 3D effects
- *want3D = wxTheApp->GetAuto3D();
-
- // 2) If the parent is being drawn with user colours, or simple border specified,
- // switch effects off. TODO: replace wxUSER_COLOURS with wxNO_3D
- if ( GetParent() && (GetParent()->GetWindowStyleFlag() & wxUSER_COLOURS) || (m_windowStyle & wxSIMPLE_BORDER) )
- *want3D = FALSE;
-
- // 3) Control can override this global setting by defining
- // a border style, e.g. wxSUNKEN_BORDER
- if ( m_windowStyle & wxSUNKEN_BORDER )
- *want3D = TRUE;
-
- // 4) If it's a special border, CTL3D can't cope so we want a native border
- if ( (m_windowStyle & wxDOUBLE_BORDER) || (m_windowStyle & wxRAISED_BORDER) ||
- (m_windowStyle & wxSTATIC_BORDER) )
- {
- *want3D = TRUE;
- nativeBorder = TRUE;
+ // wxUniv doesn't use Windows dialog navigation functions at all
+#ifndef __WXUNIVERSAL__
+ // to make the dialog navigation work with the nested panels we must
+ // use this style (top level windows such as dialogs don't need it)
+ if ( (flags & wxTAB_TRAVERSAL) && !IsTopLevel() )
+ {
+ *exstyle |= WS_EX_CONTROLPARENT;
+ }
+#endif // __WXUNIVERSAL__
}
- // 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;
+ return style;
}
#if WXWIN_COMPATIBILITY
// drag and drop
// ---------------------------------------------------------------------------
-#if wxUSE_DRAG_AND_DROP
+#if wxUSE_DRAG_AND_DROP
void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget)
{
if ( m_dropTarget != 0 ) {
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
wxWindowBase::DoSetToolTip(tooltip);
if ( m_tooltip )
- m_tooltip->SetWindow(this);
+ m_tooltip->SetWindow((wxWindow *)this);
}
#endif // wxUSE_TOOLTIPS
{
wxTheApp->DoMessage((WXMSG *)&msg);
}
+
+ // If we retrieved a WM_QUIT, insert back into the message queue.
+ if (msg.message == WM_QUIT)
+ ::PostQuitMessage(0);
}
bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
long wxWindowMSW::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
{
if ( m_oldWndProc )
+#ifdef __DIGITALMARS__
+ return ::CallWindowProc( (FARPROC) m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
+#else
return ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
+#endif
else
return ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam);
}
// here we try to do all the job which ::IsDialogMessage() usually does
// internally
#if 1
- bool bProcess = TRUE;
- if ( msg->message != WM_KEYDOWN )
- bProcess = FALSE;
-
- if ( bProcess && (HIWORD(msg->lParam) & KF_ALTDOWN) == KF_ALTDOWN )
- bProcess = FALSE;
-
- if ( bProcess )
+ if ( msg->message == WM_KEYDOWN )
{
bool bCtrlDown = wxIsCtrlDown();
bool bShiftDown = wxIsShiftDown();
if ( !bCtrlDown )
{
lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
+
+ // surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the
+ // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
+ // it, of course, implies them
+ if ( lDlgCode & DLGC_WANTALLKEYS )
+ {
+ lDlgCode |= DLGC_WANTTAB | DLGC_WANTARROWS;
+ }
}
bool bForward = TRUE,
bWindowChange = FALSE;
+ // should we process this message specially?
+ bool bProcess = TRUE;
switch ( msg->wParam )
{
case VK_TAB:
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;
+#endif // wxUSE_BUTTON
+ // this is a quick and dirty test for a text
+ // control
+ if ( !(lDlgCode & DLGC_HASSETSEL) )
+ {
+ // don't process Enter, the control might
+ // need it for itself and don't let
+ // ::IsDialogMessage() have it as it can
+ // eat the Enter events sometimes
+ return FALSE;
+ }
+ else if (!IsTopLevel())
+ {
+ // if not a top level window, let parent
+ // handle it
+ return FALSE;
+ }
+ //else: treat Enter as TAB: pass to the next
+ // control as this is the best thing to do
+ // if the text doesn't handle Enter itself
}
}
}
}
#endif // 1/0
- if ( ::IsDialogMessage(GetHwnd(), msg) )
+ // we handle VK_ESCAPE ourselves in wxDialog::OnCharHook() and we
+ // shouldn't let IsDialogMessage() get it as it _always_ eats the
+ // message even when there is no cancel button and when the message is
+ // needed by the control itself: in particular, it prevents the tree in
+ // place edit control from being closed with Escape in a dialog
+ if ( msg->message != WM_KEYDOWN || msg->wParam != VK_ESCAPE )
{
- // IsDialogMessage() did something...
- return TRUE;
+ // ::IsDialogMessage() can enter in an infinite loop when the
+ // currently focused window is disabled or hidden and its parent
+ // has WS_EX_CONTROLPARENT style, so don't call it in this case
+ bool canSafelyCallIsDlgMsg = TRUE;
+
+ HWND hwndFocus = ::GetFocus();
+ while ( hwndFocus )
+ {
+ if ( !::IsWindowEnabled(hwndFocus) ||
+ !::IsWindowVisible(hwndFocus) )
+ {
+ // it would enter an infinite loop if we do this!
+ canSafelyCallIsDlgMsg = FALSE;
+
+ break;
+ }
+
+ if ( !(::GetWindowLong(hwndFocus, GWL_STYLE) & WS_CHILD) )
+ {
+ // it's a top level window, don't go further -- e.g. even
+ // if the parent of a dialog is disabled, this doesn't
+ // break navigation inside the dialog
+ break;
+ }
+
+ hwndFocus = ::GetParent(hwndFocus);
+ }
+
+ if ( canSafelyCallIsDlgMsg && ::IsDialogMessage(GetHwnd(), msg) )
+ {
+ // IsDialogMessage() did something...
+ return TRUE;
+ }
}
}
#endif // __WXUNIVERSAL__
{
// trace all messages - useful for the debugging
#ifdef __WXDEBUG__
+#if wxUSE_LOG
wxLogTrace(wxTraceMessages, wxT("Processing %s(wParam=%8lx, lParam=%8lx)"),
- wxGetMessageName(message), wParam, lParam);
+ wxGetMessageName(message), (long) wParam, lParam);
+#endif // wxUSE_LOG
#endif // __WXDEBUG__
wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd);
break;
case WM_CLOSE:
+#ifdef __WXUNIVERSAL__
+ // Universal uses its own wxFrame/wxDialog, so we don't receive
+ // close events unless we have this.
+ Close();
+ processed = TRUE;
+ rc.result = TRUE;
+#else
// don't let the DefWindowProc() destroy our window - we'll do it
// ourselves in ~wxWindow
processed = TRUE;
rc.result = TRUE;
+#endif
break;
case WM_SHOWWINDOW:
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)
+ for ( ;; )
{
if (!win->IsEnabled())
{
processed = TRUE;
break;
}
+
win = win->GetParent();
- if (win && win->IsTopLevel())
+ if ( !win || win->IsTopLevel() )
break;
}
+
+ if ( processed )
+ break;
+
#endif // __WXMICROWIN__
- if (!processed)
+ int x = GET_X_LPARAM(lParam),
+ y = GET_Y_LPARAM(lParam);
+
+ // redirect the event to a static control if necessary by
+ // finding one under mouse
+ wxWindowMSW *win;
+ if ( GetCapture() == this )
{
- if (message == WM_LBUTTONDOWN && AcceptsFocus())
- SetFocus();
- processed = HandleMouseEvent(message,
- GET_X_LPARAM(lParam),
- GET_Y_LPARAM(lParam),
- wParam);
+ // but don't do it if the mouse is captured by this window
+ // because then it should really get this event itself
+ win = this;
}
- 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
- {
- // 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)
+ else
{
- if (!win->IsEnabled())
+ win = FindWindowForMouseEvent(this, &x, &y);
+
+ // this should never happen
+ wxCHECK_MSG( win, 0,
+ _T("FindWindowForMouseEvent() returned NULL") );
+
+ // for the standard classes their WndProc sets the focus to
+ // them anyhow and doing it from here results in some weird
+ // problems, but for our windows we want them to acquire
+ // focus when clicked
+ if ( !win->IsOfStandardClass() )
{
- processed = TRUE;
- break;
+ if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() )
+ win->SetFocus();
}
- win = win->GetParent();
- if (win && win->IsTopLevel())
- break;
}
- break;
+
+ processed = win->HandleMouseEvent(message, x, y, wParam);
}
-#endif // __WXMICROWIN__
+ break;
#ifdef MM_JOY1MOVE
case MM_JOY1MOVE:
#endif // defined(WM_DRAWITEM)
case WM_GETDLGCODE:
- if ( GetWindowStyleFlag() & wxWANTS_CHARS )
+ if ( !IsOfStandardClass() )
{
- // want everything: i.e. all keys and WM_CHAR message
- rc.result = DLGC_WANTARROWS | DLGC_WANTCHARS |
- DLGC_WANTTAB | DLGC_WANTMESSAGE;
+ // we always want to get the char events
+ rc.result = DLGC_WANTCHARS;
+
+ if ( GetWindowStyleFlag() & wxWANTS_CHARS )
+ {
+ // in fact, we want everything
+ rc.result |= DLGC_WANTARROWS |
+ DLGC_WANTTAB |
+ DLGC_WANTALLKEYS;
+ }
+
processed = TRUE;
}
//else: get the dlg code from the DefWindowProc()
if ( m_lastKeydownProcessed )
{
processed = TRUE;
- break;
}
- switch ( wParam )
+ if ( !processed )
{
- // we consider these message "not interesting" to OnChar, so
- // just don't do anything more with them
- case VK_SHIFT:
- case VK_CONTROL:
- case VK_MENU:
- case VK_CAPITAL:
- case VK_NUMLOCK:
- case VK_SCROLL:
- processed = TRUE;
- break;
-
- // avoid duplicate messages to OnChar for these ASCII keys:
- // they will be translated by TranslateMessage() and received
- // in WM_CHAR
- case VK_ESCAPE:
- case VK_SPACE:
- case VK_RETURN:
- case VK_BACK:
- case VK_TAB:
- case VK_ADD:
- case VK_SUBTRACT:
- case VK_MULTIPLY:
- case VK_DIVIDE:
- case VK_OEM_1:
- case VK_OEM_2:
- case VK_OEM_3:
- case VK_OEM_4:
- case VK_OEM_5:
- case VK_OEM_6:
- case VK_OEM_7:
- case VK_OEM_PLUS:
- case VK_OEM_COMMA:
- case VK_OEM_MINUS:
- case VK_OEM_PERIOD:
- // but set processed to FALSE, not TRUE to still pass them
- // to the control's default window proc - otherwise
- // built-in keyboard handling won't work
- processed = FALSE;
+ switch ( wParam )
+ {
+ // we consider these message "not interesting" to OnChar, so
+ // just don't do anything more with them
+ case VK_SHIFT:
+ case VK_CONTROL:
+ case VK_MENU:
+ case VK_CAPITAL:
+ case VK_NUMLOCK:
+ case VK_SCROLL:
+ processed = TRUE;
+ break;
- break;
+ // avoid duplicate messages to OnChar for these ASCII keys:
+ // they will be translated by TranslateMessage() and received
+ // in WM_CHAR
+ case VK_ESCAPE:
+ case VK_SPACE:
+ case VK_RETURN:
+ case VK_BACK:
+ case VK_TAB:
+ case VK_ADD:
+ case VK_SUBTRACT:
+ case VK_MULTIPLY:
+ case VK_DIVIDE:
+ case VK_OEM_1:
+ case VK_OEM_2:
+ case VK_OEM_3:
+ case VK_OEM_4:
+ case VK_OEM_5:
+ case VK_OEM_6:
+ case VK_OEM_7:
+ case VK_OEM_PLUS:
+ case VK_OEM_COMMA:
+ case VK_OEM_MINUS:
+ case VK_OEM_PERIOD:
+ // but set processed to FALSE, not TRUE to still pass them
+ // to the control's default window proc - otherwise
+ // built-in keyboard handling won't work
+ processed = FALSE;
+ break;
#ifdef VK_APPS
- // special case of VK_APPS: treat it the same as right mouse
- // click because both usually pop up a context menu
- case VK_APPS:
- {
- WPARAM flags;
- int x, y;
+ // special case of VK_APPS: treat it the same as right mouse
+ // click because both usually pop up a context menu
+ case VK_APPS:
+ {
+ WPARAM flags;
+ int x, y;
- TranslateKbdEventToMouse(this, &x, &y, &flags);
- processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags);
- }
- break;
+ TranslateKbdEventToMouse(this, &x, &y, &flags);
+ processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags);
+ }
+ break;
#endif // VK_APPS
- default:
- // do generate a CHAR event
- processed = HandleChar((WORD)wParam, lParam);
-
+ default:
+ // do generate a CHAR event
+ processed = HandleChar((WORD)wParam, lParam);
+ }
}
+ if (message == WM_SYSKEYDOWN) // Let Windows still handle the SYSKEYs
+ processed = FALSE;
break;
case WM_SYSKEYUP:
processed = HandlePaletteChanged((WXHWND) (HWND) wParam);
break;
+ case WM_CAPTURECHANGED:
+ processed = HandleCaptureChanged((WXHWND) (HWND) lParam);
+ break;
+
case WM_QUERYNEWPALETTE:
processed = HandleQueryNewPalette();
break;
}
break;
+#if wxUSE_ACCESSIBILITY
+ case WM_GETOBJECT:
+ {
+ //WPARAM dwFlags = (WPARAM) (DWORD) wParam;
+ LPARAM dwObjId = (LPARAM) (DWORD) lParam;
+
+ if (dwObjId == OBJID_CLIENT && GetOrCreateAccessible())
+ {
+ return LresultFromObject(IID_IAccessible, wParam, (IUnknown*) GetAccessible()->GetIAccessible());
+ }
+ break;
+ }
+#endif
+
#if defined(__WIN32__) && defined(WM_HELP)
case WM_HELP:
{
processed = GetEventHandler()->ProcessEvent(evtCtx);
}
break;
+
+ case WM_MENUCHAR:
+ // we're only interested in our own menus, not MF_SYSMENU
+ if ( HIWORD(wParam) == MF_POPUP )
+ {
+ // handle menu chars for ownerdrawn menu items
+ int i = HandleMenuChar(toupper(LOWORD(wParam)), lParam);
+ if ( i != wxNOT_FOUND )
+ {
+ rc.result = MAKELRESULT(i, MNC_EXECUTE);
+ processed = TRUE;
+ }
+ }
+ break;
#endif // __WIN32__
}
if ( !processed )
{
#ifdef __WXDEBUG__
+#if wxUSE_LOG
wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."),
wxGetMessageName(message));
+#endif // wxUSE_LOG
#endif // __WXDEBUG__
rc.result = MSWDefWindowProc(message, wParam, lParam);
}
if ( oldWin && (oldWin != win) )
{
wxLogDebug(wxT("HWND %X already associated with another window (%s)"),
- hWnd, win->GetClassInfo()->GetClassName());
+ (int) hWnd, win->GetClassInfo()->GetClassName());
}
else
#endif // __WXDEBUG__
int& x, int& y,
int& w, int& h) const
{
+ static const int DEFAULT_Y = 200;
+ static const int DEFAULT_H = 250;
+
bool nonDefault = FALSE;
if ( pos.x == -1 )
}
else
{
+ // OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it
+ // neither because it is not handled as a special value by Windows then
+ // and so we have to choose some default value for it
x = pos.x;
- y = pos.y == -1 ? CW_USEDEFAULT : pos.y;
+ y = pos.y == -1 ? DEFAULT_Y : pos.y;
nonDefault = TRUE;
}
*/
if ( size.x == -1 )
{
- // as abobe, h is not used at all in this case anyhow
+ // as above, h is not used at all in this case anyhow
w =
h = CW_USEDEFAULT;
}
else
{
+ // and, again as above, we can't set the height to CW_USEDEFAULT here
w = size.x;
- h = size.y == -1 ? CW_USEDEFAULT : size.y;
+ h = size.y == -1 ? DEFAULT_H : size.y;
nonDefault = TRUE;
}
return nonDefault;
}
+WXHWND wxWindowMSW::MSWGetParent() const
+{
+ return m_parent ? m_parent->GetHWND() : WXHWND(NULL);
+}
+
bool wxWindowMSW::MSWCreate(const wxChar *wclass,
const wxChar *title,
const wxPoint& pos,
int x, y, w, h;
(void)MSWGetCreateWindowCoords(pos, size, x, y, w, h);
- // find the correct parent HWND
- wxWindow *parent = GetParent();
- bool isChild = (style & WS_CHILD) != 0;
- HWND hParent;
- if ( GetWindowStyleFlag() & wxPOPUP_WINDOW )
- {
- // 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();
- }
- else // !popup
- {
- if ( (isChild || HasFlag(wxFRAME_TOOL_WINDOW)) && parent )
- {
- // this is either a normal child window or a top level window with
- // wxFRAME_TOOL_WINDOW style (see below)
- hParent = GetHwndOf(parent);
- }
- else
- {
- // 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;
- }
-
- }
-
// 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();
-
- if ( GetWindowStyleFlag() & wxCLIP_SIBLINGS )
- {
- style |= WS_CLIPSIBLINGS;
- }
- }
- else // !child
- {
- controlId = 0;
- }
+ int controlId = style & WS_CHILD ? GetId() : 0;
// for each class "Foo" we have we also have "FooNR" ("no repaint") class
// which is the same but without CS_[HV]REDRAW class styles so using it
wxWindowCreationHook hook(this);
m_hWnd = (WXHWND)::CreateWindowEx
- (
- extendedStyle,
- className,
- title ? title : wxT(""),
- style,
- x, y, w, h,
- hParent,
- (HMENU)controlId,
- wxGetInstance(),
- NULL // no extra data
- );
+ (
+ extendedStyle,
+ className,
+ title ? title : wxT(""),
+ style,
+ x, y, w, h,
+ (HWND)MSWGetParent(),
+ (HMENU)controlId,
+ wxGetInstance(),
+ NULL // no extra data
+ );
if ( !m_hWnd )
{
// ---------------------------------------------------------------------------
#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__
HWND hWnd = hdr->hwndFrom;
wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd);
- // is this one of our windows?
+ // if the control is one of our windows, let it handle the message itself
if ( win )
{
return win->MSWOnNotify(idCtrl, lParam, result);
}
+ // VZ: why did we do it? normally this is unnecessary and, besides, it
+ // breaks the message processing for the toolbars because the tooltip
+ // notifications were being forwarded to the toolbar child controls
+ // (if it had any) before being passed to the toolbar itself, so in my
+ // example the tooltip for the combobox was always shown instead of the
+ // correct button tooltips
+#if 0
// try all our children
wxWindowList::Node *node = GetChildren().GetFirst();
while ( node )
node = node->GetNext();
}
+#endif // 0
- // finally try this window too (catches toolbar case)
+ // by default, handle it ourselves
return MSWOnNotify(idCtrl, lParam, result);
#else // __WXMICROWIN__
return FALSE;
#endif
}
+#if wxUSE_TOOLTIPS
+
+bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
+ WXLPARAM lParam,
+ const wxString& ttip)
+{
+ // I don't know why it happens, but the versions of comctl32.dll starting
+ // from 4.70 sometimes send TTN_NEEDTEXTW even to ANSI programs (normally,
+ // this message is supposed to be sent to Unicode programs only) -- hence
+ // we need to handle it as well, otherwise no tooltips will be shown in
+ // this case
+
+ if ( !(code == (WXUINT) TTN_NEEDTEXTA || code == (WXUINT) TTN_NEEDTEXTW) || ttip.empty() )
+ {
+ // not a tooltip message or no tooltip to show anyhow
+ return FALSE;
+ }
+
+ LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
+
+#if !wxUSE_UNICODE
+ if ( code == (WXUINT) TTN_NEEDTEXTA )
+ {
+ // we pass just the pointer as we store the string internally anyhow
+ ttText->lpszText = (char *)ttip.c_str();
+ }
+ else // TTN_NEEDTEXTW
+#endif // !Unicode
+ {
+#if wxUSE_UNICODE
+ // in Unicode mode this is just what we need
+ ttText->lpszText = (wxChar *)ttip.c_str();
+#else // !Unicode
+ MultiByteToWideChar(CP_ACP, 0, ttip, ttip.length()+1,
+ (wchar_t *)ttText->szText,
+ sizeof(ttText->szText) / sizeof(wchar_t));
+#endif // Unicode/!Unicode
+ }
+
+ return TRUE;
+}
+
+#endif // wxUSE_TOOLTIPS
+
bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl),
- WXLPARAM lParam,
- WXLPARAM* WXUNUSED(result))
+ WXLPARAM lParam,
+ WXLPARAM* WXUNUSED(result))
{
#if wxUSE_TOOLTIPS
- NMHDR* hdr = (NMHDR *)lParam;
- if ( (int)hdr->code == TTN_NEEDTEXT && m_tooltip )
+ if ( m_tooltip )
{
- TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam;
- ttt->lpszText = (wxChar *)m_tooltip->GetTip().c_str();
-
- // processed
- return TRUE;
+ NMHDR* hdr = (NMHDR *)lParam;
+ if ( HandleTooltipNotify(hdr->code, lParam, m_tooltip->GetTip()))
+ {
+ // processed
+ return TRUE;
+ }
}
#endif // wxUSE_TOOLTIPS
return FALSE;
}
+
#endif // __WIN95__
// ---------------------------------------------------------------------------
// window creation/destruction
// ---------------------------------------------------------------------------
-bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED(cs), bool *mayCreate)
+bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT cs, bool *mayCreate)
{
+ // if we have WS_EX_CONTROLPARENT flag we absolutely *must* set it for our
+ // parent as well as otherwise several Win32 functions using
+ // GetNextDlgTabItem() to iterate over all controls such as
+ // IsDialogMessage() or DefDlgProc() would enter an infinite loop: indeed,
+ // all of them iterate over all the controls starting from the focus and
+ // stop iterating when they get back to the focus but unless all parents
+ // have WS_EX_CONTROLPARENT bit set, they would never get back to focus
+ if ( ((CREATESTRUCT *)cs)->dwExStyle & WS_EX_CONTROLPARENT )
+ {
+ // there is no need to do anything for the top level windows
+ const wxWindow *parent = GetParent();
+ while ( parent && !parent->IsTopLevel() )
+ {
+ LONG exStyle = ::GetWindowLong(GetHwndOf(parent), GWL_EXSTYLE);
+ if ( !(exStyle & WS_EX_CONTROLPARENT) )
+ {
+ // force the parent to have this style
+ ::SetWindowLong(GetHwndOf(parent), GWL_EXSTYLE,
+ exStyle | WS_EX_CONTROLPARENT);
+ }
+
+ parent = parent->GetParent();
+ }
+ }
+
// TODO: should generate this event from WM_NCCREATE
wxWindowCreateEvent event((wxWindow *)this);
(void)GetEventHandler()->ProcessEvent(event);
bool wxWindowMSW::HandleDestroy()
{
- wxWindowDestroyEvent event((wxWindow *)this);
- (void)GetEventHandler()->ProcessEvent(event);
+ SendDestroyEvent();
// delete our drop target if we've got one
#if wxUSE_DRAG_AND_DROP
}
#endif
+ // Don't send the event when in the process of being deleted. This can
+ // only cause problems if the event handler tries to access the object.
+ if ( m_isBeingDeleted )
+ {
+ return FALSE;
+ }
+
wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId);
event.SetEventObject(this);
bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam)
{
-#ifndef __WXMICROWIN__
+#if defined (__WXMICROWIN__)
+ return FALSE;
+#else // __WXMICROWIN__
HDROP hFilesInfo = (HDROP) wParam;
// Get the total number of files dropped
event.m_pos.y = dropPoint.y;
return GetEventHandler()->ProcessEvent(event);
-#else // __WXMICROWIN__
- return FALSE;
#endif
}
+#ifdef __DIGITALMARS__
+extern "C" HCURSOR wxGetCurrentBusyCursor();
+#endif
+
bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
short nHitTest,
int WXUNUSED(mouseMsg))
if ( hcursor )
{
+// wxLogDebug("HandleSetCursor: Setting cursor %ld", (long) hcursor);
+
::SetCursor(hcursor);
// cursor set, stop here
if ( hWndPalChange != GetHWND() )
{
// check to see if we our our parents have a custom palette
- wxWindow *win = this;
+ wxWindowMSW *win = this;
while ( win && !win->HasCustomPalette() )
{
win = win->GetParent();
return GetEventHandler()->ProcessEvent(event);
}
+bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture)
+{
+ wxMouseCaptureChangedEvent event(GetId(), wxFindWinFromHandle(hWndGainedCapture));
+ event.SetEventObject(this);
+
+ return GetEventHandler()->ProcessEvent(event);
+}
+
bool wxWindowMSW::HandleQueryNewPalette()
{
#if wxUSE_PALETTE
// check to see if we our our parents have a custom palette
- wxWindow *win = this;
+ wxWindowMSW *win = this;
while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent();
if (win->HasCustomPalette()) {
/* realize the palette to see whether redrawing is needed */
event.SetTimestamp(s_currentMsg.time);
event.m_eventObject = this;
+ event.SetId(GetId());
#if wxUSE_MOUSEEVENT_HACK
m_lastMouseX = x;
#endif // wxUSE_MOUSEEVENT_HACK
}
+// Windows doesn't send the mouse events to the static controls (which are
+// transparent in the sense that their WM_NCHITTEST handler returns
+// HTTRANSPARENT) at all but we want all controls to receive the mouse events
+// and so we manually check if we don't have a child window under mouse and if
+// we do, send the event to it instead of the window Windows had sent WM_XXX
+// to.
+//
+// Notice that this is not done for the mouse move events because this could
+// (would?) be too slow, but only for clicks which means that the static texts
+// still don't get move, enter nor leave events.
+static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y) //TW:REQ:Univ
+{
+ wxCHECK_MSG( x && y, win, _T("NULL pointer in FindWindowForMouseEvent") );
+
+ // first try to find a non transparent child: this allows us to send events
+ // to a static text which is inside a static box, for example
+ POINT pt = { *x, *y };
+ HWND hwnd = GetHwndOf(win),
+ hwndUnderMouse;
+
+#ifdef __WIN32__
+ hwndUnderMouse = ::ChildWindowFromPointEx
+ (
+ hwnd,
+ pt,
+ CWP_SKIPINVISIBLE |
+ CWP_SKIPDISABLED |
+ CWP_SKIPTRANSPARENT
+ );
+
+ if ( !hwndUnderMouse || hwndUnderMouse == hwnd )
+#endif // __WIN32__
+ {
+ // now try any child window at all
+ hwndUnderMouse = ::ChildWindowFromPoint(hwnd, pt);
+ }
+
+ // check that we have a child window which is susceptible to receive mouse
+ // events: for this it must be shown and enabled
+ if ( hwndUnderMouse &&
+ hwndUnderMouse != hwnd &&
+ ::IsWindowVisible(hwndUnderMouse) &&
+ ::IsWindowEnabled(hwndUnderMouse) )
+ {
+ wxWindow *winUnderMouse = wxFindWinFromHandle((WXHWND)hwndUnderMouse);
+ if ( winUnderMouse )
+ {
+ // translate the mouse coords to the other window coords
+ win->ClientToScreen(x, y);
+ winUnderMouse->ScreenToClient(x, y);
+
+ win = winUnderMouse;
+ }
+ }
+
+ return win;
+}
+
bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags)
{
// the mouse events take consecutive IDs from WM_MOUSEFIRST to
int id;
if ( isASCII )
{
- // If 1 -> 26, translate to CTRL plus a letter.
+ // If 1 -> 26, translate to either special keycode or just set
+ // ctrlDown. IOW, Ctrl-C should result in keycode == 3 and
+ // ControlDown() == TRUE.
id = wParam;
if ( (id > 0) && (id < 27) )
{
default:
ctrlDown = TRUE;
- id = id + 'a' - 1;
+ break;
}
}
}
}
wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam, wParam));
- if ( ctrlDown )
+
+ // the alphanumeric keys produced by pressing AltGr+something on European
+ // keyboards have both Ctrl and Alt modifiers which may confuse the user
+ // code as, normally, keys with Ctrl and/or Alt don't result in anything
+ // alphanumeric, so pretend that there are no modifiers at all (the
+ // KEY_DOWN event would still have the correct modifiers if they're really
+ // needed)
+ if ( event.m_controlDown && event.m_altDown &&
+ (id >= 32 && id < 256) )
{
- event.m_controlDown = TRUE;
+ event.m_controlDown =
+ event.m_altDown = FALSE;
}
return GetEventHandler()->ProcessEvent(event);
return FALSE;
}
+#ifdef __WIN32__
+
+int wxWindowMSW::HandleMenuChar(int chAccel, WXLPARAM lParam)
+{
+ const HMENU hmenu = (HMENU)lParam;
+
+ MENUITEMINFO mii;
+ wxZeroMemory(mii);
+ mii.cbSize = sizeof(MENUITEMINFO);
+ mii.fMask = MIIM_TYPE | MIIM_DATA;
+
+ // find if we have this letter in any owner drawn item
+ const int count = ::GetMenuItemCount(hmenu);
+ for ( int i = 0; i < count; i++ )
+ {
+ if ( ::GetMenuItemInfo(hmenu, i, TRUE, &mii) )
+ {
+ if ( mii.fType == MFT_OWNERDRAW )
+ {
+ // dwItemData member of the MENUITEMINFO is a
+ // pointer to the associated wxMenuItem -- see the
+ // menu creation code
+ wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
+
+ const wxChar *p = wxStrchr(item->GetText(), _T('&'));
+ while ( p++ )
+ {
+ if ( *p == _T('&') )
+ {
+ // this is not the accel char, find the real one
+ p = wxStrchr(p + 1, _T('&'));
+ }
+ else // got the accel char
+ {
+ // FIXME-UNICODE: this comparison doesn't risk to work
+ // for non ASCII accelerator characters I'm afraid, but
+ // what can we do?
+ if ( wxToupper(*p) == chAccel )
+ {
+ return i;
+ }
+ else
+ {
+ // this one doesn't match
+ break;
+ }
+ }
+ }
+ }
+ }
+ else // failed ot get the menu text?
+ {
+ // it's not fatal, so don't show error, but still log
+ // it
+ wxLogLastError(_T("GetMenuItemInfo"));
+ }
+ }
+
+ return wxNOT_FOUND;
+}
+
+#endif // __WIN32__
+
// ---------------------------------------------------------------------------
// joystick
// ---------------------------------------------------------------------------
// be done only for these two SB_ events as they are the only one
// carrying the scrollbar position)
{
- SCROLLINFO scrollInfo;
- wxZeroMemory(scrollInfo);
- scrollInfo.cbSize = sizeof(SCROLLINFO);
+ WinStruct<SCROLLINFO> scrollInfo;
scrollInfo.fMask = SIF_TRACKPOS;
if ( !::GetScrollInfo(GetHwnd(),
case VK_OEM_6: id = ']'; break;
case VK_OEM_7: id = '\''; break;
+#ifdef VK_APPS
+ case VK_LWIN: id = WXK_WINDOWS_LEFT; break;
+ case VK_RWIN: id = WXK_WINDOWS_RIGHT; break;
+ case VK_APPS: id = WXK_WINDOWS_MENU; break;
+#endif // VK_APPS defined
+
default:
id = 0;
}
// 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__)
+#if !defined(__WIN32__) && !defined(__NT__)
FreeProcInstance(wxTheKeyboardHookProc);
#endif
}
// Find the wxWindow at the current mouse position, returning the mouse
// position.
-wxWindow* wxFindWindowAtPointer(wxPoint& WXUNUSED(pt))
+wxWindow* wxFindWindowAtPointer(wxPoint& pt)
{
- return wxFindWindowAtPoint(wxGetMousePosition());
+ pt = wxGetMousePosition();
+ return wxFindWindowAtPoint(pt);
}
wxWindow* wxFindWindowAtPoint(const wxPoint& pt)