#include "wx/menu.h"
#include "wx/dc.h"
#include "wx/dcclient.h"
+ #include "wx/dcmemory.h"
#include "wx/utils.h"
#include "wx/app.h"
- #include "wx/panel.h"
#include "wx/layout.h"
#include "wx/dialog.h"
#include "wx/frame.h"
#include "wx/button.h"
#include "wx/msgdlg.h"
#include "wx/settings.h"
-
- #include <stdio.h>
+ #include "wx/statbox.h"
#endif
#if wxUSE_OWNER_DRAWN
#endif
#endif
-
// ---------------------------------------------------------------------------
// global variables
// ---------------------------------------------------------------------------
-// the last Windows message we got (MT-UNSAFE)
+// the last Windows message we got (FIXME-MT)
extern MSG s_currentMsg;
#if wxUSE_MENUS_NATIVE
wxMenu *wxCurrentPopupMenu = NULL;
#endif // wxUSE_MENUS_NATIVE
-extern wxList WXDLLEXPORT wxPendingDelete;
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
// ---------------------------------------------------------------------------
// get the text metrics for the current font
static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win);
-// check if the mouse is in the window or its child
-//static bool IsMouseInWindow(HWND hwnd);
+// 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);
+
+ // 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
EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged)
EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog)
EVT_IDLE(wxWindowMSW::OnIdle)
- EVT_SET_FOCUS(wxWindowMSW::OnSetFocus)
END_EVENT_TABLE()
// ===========================================================================
wxWindow *wxWindowMSW::FindItem(long id) const
{
#if wxUSE_CONTROLS
- wxControl *item = wxDynamicThisCast(this, wxControl);
+ wxControl *item = wxDynamicCastThis(wxControl);
if ( item )
{
// is it we or one of our "internal" children?
m_hWnd = 0;
- // pass WM_GETDLGCODE to DefWindowProc()
- m_lDlgCode = 0;
-
m_xThumbSize = 0;
m_yThumbSize = 0;
m_backgroundTransparent = FALSE;
{
m_isBeingDeleted = TRUE;
- MSWDetachWindowMenu();
-
+#ifndef __WXUNIVERSAL__
// VS: make sure there's no wxFrame with last focus set to us:
- for (wxWindow *win = GetParent(); win; win = win->GetParent())
+ 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__
// 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
{
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);
- // all windows are created visible
- DWORD msflags = WS_CHILD | WS_VISIBLE;
+ // note that all windows are created visible by default
+ WXDWORD exstyle;
+ DWORD msflags = WS_VISIBLE | MSWGetCreateWindowFlags(&exstyle);
#ifdef __WXUNIVERSAL__
- // no 3d effects, we draw them ourselves
- WXDWORD exStyle = 0;
-#else // !wxUniversal
- if ( style & wxCLIP_CHILDREN )
- msflags |= WS_CLIPCHILDREN;
- if ( style & wxCLIP_SIBLINGS )
- msflags |= WS_CLIPSIBLINGS;
-
- bool want3D;
- WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D);
-
- // Even with extended styles, need to combine with WS_BORDER
- // for them to look right.
- if ( want3D ||
- (m_windowStyle & (wxBORDER |
- wxSIMPLE_BORDER |
- wxRAISED_BORDER |
- wxSUNKEN_BORDER |
- wxDOUBLE_BORDER)) )
- {
- msflags |= WS_BORDER;
- }
-
- // calculate the value to return from WM_GETDLGCODE handler
- if ( GetWindowStyleFlag() & wxWANTS_CHARS )
- {
- // want everything: i.e. all keys and WM_CHAR message
- m_lDlgCode = DLGC_WANTARROWS | DLGC_WANTCHARS |
- DLGC_WANTTAB | DLGC_WANTMESSAGE;
- }
-#endif // wxUniversal/!wxUniversal
+ // no borders, we draw them ourselves
+ exstyle = 0;
+ msflags &= ~WS_BORDER;
+#endif // wxUniversal
if ( style & wxPOPUP_WINDOW )
{
// a popup window floats on top of everything
- exStyle |= WS_EX_TOPMOST | WS_EX_TOOLWINDOW;
+ exstyle |= WS_EX_TOPMOST | WS_EX_TOOLWINDOW;
// it is also created hidden as other top level windows
msflags &= ~WS_VISIBLE;
m_isShown = FALSE;
}
- return MSWCreate(m_windowId, parent, wxCanvasClassName,
- (wxWindow *)this, NULL,
- pos.x, pos.y,
- WidthDefault(size.x), HeightDefault(size.y),
- msflags, NULL, exStyle);
+ return MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle);
}
// ---------------------------------------------------------------------------
#ifndef __WXMICROWIN__
::SetLastError(0);
#endif
-
+
if ( !::SetFocus(hWnd) )
{
+#if defined(__WXDEBUG__) && !defined(__WXMICROWIN__)
// was there really an error?
-#ifndef __WXMICROWIN__
DWORD dwRes = ::GetLastError();
-#else
-
- DWORD dwRes = 0;
-#endif
if ( dwRes )
{
- wxLogApiError(_T("SetFocus"), dwRes);
+ HWND hwndFocus = ::GetFocus();
+ if ( hwndFocus != hWnd )
+ {
+ wxLogApiError(_T("SetFocus"), dwRes);
+ }
}
-
- // VZ: just why does this happen sometimes?? any idea?
-#if 0
- HWND hwndFocus = ::GetFocus();
- wxASSERT_MSG( hwndFocus == hWnd, _T("SetFocus() didn't work?") );
-#endif // 0
+#endif // Debug
}
}
if ( show )
{
-#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);
-
- /* raise top level parent to top of z order*/
- ::SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0,
- SWP_NOMOVE|SWP_NOSIZE);
-#else
- BringWindowToTop(hWnd);
-#endif
+ wxBringWindowToTop(hWnd);
}
return TRUE;
// Raise the window to the top of the Z order
void wxWindowMSW::Raise()
{
-#ifdef __WIN16__
- ::BringWindowToTop(GetHwnd());
-#else // Win32
-#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(GetHwnd());
-
- /* raise top level parent to top of z order*/
- ::SetWindowPos(GetHwnd(), HWND_TOP, 0, 0, 0, 0,
- SWP_NOMOVE|SWP_NOSIZE);
-#else
- ::SetForegroundWindow(GetHwnd());
-#endif
-#endif
+ wxBringWindowToTop(GetHwnd());
}
// Lower the window to the bottom of the Z order
return wxGetWindowText(GetHWND());
}
-void wxWindowMSW::CaptureMouse()
+void wxWindowMSW::DoCaptureMouse()
{
HWND hWnd = GetHwnd();
if ( hWnd )
}
}
-void wxWindowMSW::ReleaseMouse()
+void wxWindowMSW::DoReleaseMouse()
{
if ( !::ReleaseCapture() )
{
POINT point;
::GetCursorPos(&point);
- RECT rect;
- ::GetWindowRect(hWnd, &rect);
+ RECT rect = wxGetWindowRect(hWnd);
if ( ::PtInRect(&rect, point) && !wxIsBusy() )
::SetCursor(GetHcursorOf(m_cursor));
#endif // WXWIN_COMPATIBILITY
+inline int GetScrollPosition(HWND hWnd, int wOrient)
+{
+#ifdef __WXMICROWIN__
+ return ::GetScrollPosWX(hWnd, wOrient);
+#else
+ return ::GetScrollPos(hWnd, wOrient);
+#endif
+}
+
int wxWindowMSW::GetScrollPos(int orient) const
{
int wOrient;
wOrient = SB_HORZ;
else
wOrient = SB_VERT;
+
HWND hWnd = GetHwnd();
- if ( hWnd )
- {
-#ifdef __WXMICROWIN__
- return ::GetScrollPosWX(hWnd, wOrient);
-#else
- return ::GetScrollPos(hWnd, wOrient);
-#endif
- }
- else
- return 0;
+ wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") );
+
+ return GetScrollPosition(hWnd, wOrient);
}
// This now returns the whole range, not just the number
void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh)
{
-#if defined(__WIN95__)
- SCROLLINFO info;
- int dir;
+ HWND hWnd = GetHwnd();
+ wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") );
- if ( orient == wxHORIZONTAL ) {
- dir = SB_HORZ;
- } else {
- dir = SB_VERT;
- }
+ int dir = orient == wxHORIZONTAL ? SB_HORZ : SB_VERT;
+#if defined(__WIN95__)
+ SCROLLINFO info;
info.cbSize = sizeof(SCROLLINFO);
info.nPage = 0;
info.nMin = 0;
info.nPos = pos;
info.fMask = 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 )
- ::SetScrollPos(hWnd, wOrient, pos, refresh);
-#endif
+ ::SetScrollInfo(hWnd, dir, &info, refresh);
+#else // !__WIN95__
+ ::SetScrollPos(hWnd, dir, pos, refresh);
+#endif // __WIN95__/!__WIN95__
}
// New function that will replace some of the above.
void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect)
{
RECT rect;
+ RECT *pr;
if ( prect )
{
rect.left = prect->x;
rect.top = prect->y;
rect.right = prect->x + prect->width;
rect.bottom = prect->y + prect->height;
+ pr = ▭
+ }
+ else
+ {
+ pr = NULL;
+ }
+
+ ::ScrollWindow(GetHwnd(), dx, dy, pr, pr);
+}
+
+static bool ScrollVertically(HWND hwnd, int kind, int count)
+{
+ int posStart = GetScrollPosition(hwnd, SB_VERT);
+
+ int pos = posStart;
+ for ( int n = 0; n < count; n++ )
+ {
+ ::SendMessage(hwnd, WM_VSCROLL, kind, 0);
+
+ int posNew = GetScrollPosition(hwnd, SB_VERT);
+ if ( posNew == pos )
+ {
+ // don't bother to continue, we're already at top/bottom
+ break;
+ }
+
+ pos = posNew;
}
- ::ScrollWindow(GetHwnd(), dx, dy, prect ? &rect : NULL, NULL);
+ return pos != posStart;
+}
+
+bool wxWindowMSW::ScrollLines(int lines)
+{
+ 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);
}
// ---------------------------------------------------------------------------
wxAssociateWinWithHandle(hwnd, this);
- m_oldWndProc = (WXFARPROC) GetWindowLong(hwnd, GWL_WNDPROC);
+ m_oldWndProc = (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC);
- wxASSERT( (WXFARPROC) m_oldWndProc != (WXFARPROC) wxWndProc );
-
- SetWindowLong(hwnd, GWL_WNDPROC, (LONG) wxWndProc);
+ // 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);
+ }
+ else
+ {
+ // don't bother restoring it neither
+ m_oldWndProc = NULL;
+ }
}
void wxWindowMSW::UnsubclassWin()
wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") );
- FARPROC farProc = (FARPROC) GetWindowLong(hwnd, GWL_WNDPROC);
- if ( (m_oldWndProc != 0) && (farProc != (FARPROC) m_oldWndProc) )
+ if ( m_oldWndProc )
+ {
+ if ( !wxCheckWindowWndProc((WXHWND)hwnd, m_oldWndProc) )
+ {
+ ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) 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() )
+ {
+ static wxChar buffer[512];
+ WNDCLASS cls;
+
+ ::GetClassName((HWND)hWnd, buffer, 512);
+ ::GetClassInfo(wxGetInstance(), buffer, &cls);
+ return wndProc == (WXFARPROC)cls.lpfnWndProc;
+ }
+ else
+#endif
+ {
+ return wndProc == (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC);
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Style handling
+// ----------------------------------------------------------------------------
+
+void wxWindowMSW::SetWindowStyleFlag(long flags)
+{
+ long flagsOld = GetWindowStyleFlag();
+ if ( flags == flagsOld )
+ return;
+
+ // update the internal variable
+ wxWindowBase::SetWindowStyleFlag(flags);
+
+ // 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) )
+ {
+ wxLogLastError(_T("SetWindowPos"));
+ }
+ }
+}
+
+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 )
{
- SetWindowLong(hwnd, GWL_WNDPROC, (LONG) m_oldWndProc);
- m_oldWndProc = 0;
+ 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;
}
}
+
+ return style;
}
// Make a Windows extended style from the given wxWindows window style
exStyle |= WS_EX_STATICEDGE;
#endif
}
+
return exStyle;
}
// applying a default border style if required, and returning an extended
// style to pass to CreateWindowEx.
WXDWORD wxWindowMSW::Determine3DEffects(WXDWORD defaultBorderStyle,
- bool *want3D) const
+ bool *want3D) const
{
// If matches certain criteria, then assume no 3D effects
// unless specifically requested (dealt with in MakeExtendedStyle)
|| (m_windowStyle & wxNO_BORDER) )
{
*want3D = FALSE;
- return MakeExtendedStyle(m_windowStyle, FALSE);
+ return MakeExtendedStyle(m_windowStyle);
}
// Determine whether we should be using 3D effects or not.
// 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() )
{
// Generate a LEAVE event
// we need to have client coordinates here for symmetry with
// wxEVT_ENTER_WINDOW
- RECT rect;
- if ( !::GetWindowRect(GetHwnd(), &rect) )
- {
- wxLogLastError(_T("GetWindowRect"));
- }
+ RECT rect = wxGetWindowRect(GetHwnd());
pt.x -= rect.left;
pt.y -= rect.top;
dc.Clear();
}
+static inline void SendSetRedraw(HWND hwnd, bool on)
+{
+#ifndef __WXMICROWIN__
+ ::SendMessage(hwnd, WM_SETREDRAW, (WPARAM)on, 0);
+#endif
+}
+
+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();
// Get total size
void wxWindowMSW::DoGetSize(int *x, int *y) const
{
- HWND hWnd = GetHwnd();
- RECT rect;
-#ifdef __WIN16__
- ::GetWindowRect(hWnd, &rect);
-#else
- if ( !::GetWindowRect(hWnd, &rect) )
- {
- wxLogLastError(_T("GetWindowRect"));
- }
-#endif
+ RECT rect = wxGetWindowRect(GetHwnd());
+
if ( x )
*x = rect.right - rect.left;
if ( y )
*y = rect.bottom - rect.top;
}
-void wxWindowMSW::DoGetPosition(int *x, int *y) const
+// Get size *available for subwindows* i.e. excluding menu bar etc.
+void wxWindowMSW::DoGetClientSize(int *x, int *y) const
{
- HWND hWnd = GetHwnd();
+ RECT rect = wxGetClientRect(GetHwnd());
- RECT rect;
- GetWindowRect(hWnd, &rect);
+ 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;
if ( y )
pt.y = *y;
- HWND hWnd = GetHwnd();
- ::ScreenToClient(hWnd, &pt);
+ ::ScreenToClient(GetHwnd(), &pt);
if ( x )
*x = pt.x;
if ( y )
pt.y = *y;
- HWND hWnd = GetHwnd();
- ::ClientToScreen(hWnd, &pt);
+ ::ClientToScreen(GetHwnd(), &pt);
if ( x )
*x = pt.x;
*y = pt.y;
}
-// Get size *available for subwindows* i.e. excluding menu bar etc.
-void wxWindowMSW::DoGetClientSize(int *x, int *y) const
-{
- HWND hWnd = GetHwnd();
- RECT rect;
- ::GetClientRect(hWnd, &rect);
- if ( x )
- *x = rect.right;
- if ( y )
- *y = rect.bottom;
-}
-
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"));
void wxWindowMSW::DoSetClientSize(int width, int height)
{
- wxWindow *parent = GetParent();
- HWND hWnd = GetHwnd();
- HWND hParentWnd = (HWND) 0;
- if ( parent )
- hParentWnd = (HWND) parent->GetHWND();
-
- RECT rect;
- ::GetClientRect(hWnd, &rect);
+ // 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) )
+ {
+ break;
+ }
- RECT rect2;
- GetWindowRect(hWnd, &rect2);
+ 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
- int actual_width = rect2.right - rect2.left - rect.right + width;
- int actual_height = rect2.bottom - rect2.top - rect.bottom + 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);
- // If there's a parent, must subtract the parent's top left corner
- // since MoveWindow moves relative to the parent
+ widthClient += rectWin.right - rectWin.left - rectClient.right;
+ heightClient += rectWin.bottom - rectWin.top - rectClient.bottom;
- POINT point;
- point.x = rect2.left;
- point.y = rect2.top;
- if ( parent )
- {
- ::ScreenToClient(hParentWnd, &point);
- }
+ POINT point;
+ point.x = rectWin.left;
+ point.y = rectWin.top;
- DoMoveWindow(point.x, point.y, actual_width, actual_height);
+ // MoveWindow positions the child windows relative to the parent, so
+ // adjust if necessary
+ if ( !IsTopLevel() )
+ {
+ wxWindow *parent = GetParent();
+ if ( parent )
+ {
+ ::ScreenToClient(GetHwndOf(parent), &point);
+ }
+ }
- wxSizeEvent event(wxSize(width, height), m_windowId);
- event.SetEventObject(this);
- GetEventHandler()->ProcessEvent(event);
+ DoMoveWindow(point.x, point.y, widthClient, heightClient);
+ }
}
// For implementation purposes - sometimes decorations make the client area
return wxPoint(0, 0);
}
-// Makes an adjustment to the window position (for example, a frame that has
-// a toolbar that it manages itself).
-void wxWindowMSW::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags)
-{
- // don't do it for the dialogs/frames - they float independently of their
- // parent
- if ( !IsTopLevel() )
- {
- wxWindow *parent = GetParent();
- if ( !(sizeFlags & wxSIZE_NO_ADJUSTMENTS) && parent )
- {
- wxPoint pt(parent->GetClientAreaOrigin());
- x += pt.x;
- y += pt.y;
- }
- }
-}
-
// ---------------------------------------------------------------------------
// text metrics
// ---------------------------------------------------------------------------
// 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
//
}
}
-#if wxUSE_MENUS_NATIVE
-
bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
{
menu->SetInvokingWindow(this);
bProcess = FALSE;
}
-#if wxUSE_BUTTON
+ // FIXME: this should be handled by
+ // wxNavigationKeyEvent handler and not here!!
else
{
- wxPanel *panel = wxDynamicThisCast(this, wxPanel);
- wxButton *btn = NULL;
- if ( panel )
- {
- // panel may have a default button which should
- // be activated by Enter
- btn = panel->GetDefaultItem();
- }
-
+#if wxUSE_BUTTON
+ wxButton *btn = wxDynamicCast(GetDefaultItem(),
+ wxButton);
if ( btn && btn->IsEnabled() )
{
// if we do have a default button, do press it
return TRUE;
}
- // else: but if it does not it makes sense to make
- // it work like a TAB - and that's what we do.
- // Note that Ctrl-Enter always works this way.
- }
+ 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;
if ( GetEventHandler()->ProcessEvent(event) )
{
-#if wxUSE_BUTTON
- wxButton *btn = wxDynamicCast(FindFocus(), wxButton);
- if ( btn )
- {
- // the button which has focus should be default
- btn->SetDefault();
- }
-#endif // wxUSE_BUTTON
-
return TRUE;
}
}
}
-#else
+#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 )
}
}
}
-#endif // 0
+#endif // 1/0
if ( ::IsDialogMessage(GetHwnd(), msg) )
{
#if wxUSE_ACCEL && !defined(__WXUNIVERSAL__)
return m_acceleratorTable.Translate(this, pMsg);
#else
+ (void) pMsg;
return FALSE;
#endif // wxUSE_ACCEL
}
+bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* WXUNUSED(pMsg))
+{
+ // preprocess all messages by default
+ return TRUE;
+}
+
// ---------------------------------------------------------------------------
// message params unpackers (different for Win16 and Win32)
// ---------------------------------------------------------------------------
// Hook for new window just as it's being created, when the window isn't yet
// associated with the handle
-wxWindowMSW *wxWndHook = NULL;
+static wxWindowMSW *gs_winBeingCreated = NULL;
+
+// implementation of wxWindowCreationHook class: it just sets gs_winBeingCreated to the
+// window being created and insures that it's always unset back later
+wxWindowCreationHook::wxWindowCreationHook(wxWindowMSW *winBeingCreated)
+{
+ gs_winBeingCreated = winBeingCreated;
+}
+
+wxWindowCreationHook::~wxWindowCreationHook()
+{
+ gs_winBeingCreated = NULL;
+}
// Main window proc
LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd);
// when we get the first message for the HWND we just created, we associate
- // it with wxWindow stored in wxWndHook
- if ( !wnd && wxWndHook )
+ // it with wxWindow stored in gs_winBeingCreated
+ if ( !wnd && gs_winBeingCreated )
{
-#if 0 // def __WXDEBUG__
- char buf[512];
- ::GetClassNameA((HWND) hWnd, buf, 512);
- wxString className(buf);
-#endif
-
- wxAssociateWinWithHandle(hWnd, wxWndHook);
- wnd = wxWndHook;
- wxWndHook = NULL;
+ wxAssociateWinWithHandle(hWnd, gs_winBeingCreated);
+ wnd = gs_winBeingCreated;
+ gs_winBeingCreated = NULL;
wnd->SetHWND((WXHWND)hWnd);
}
LRESULT rc;
- // Stop right here if we don't have a valid handle in our wxWindow object.
- if ( wnd && !wnd->GetHWND() )
- {
- // FIXME: why do we do this?
- wnd->SetHWND((WXHWND) hWnd);
- rc = wnd->MSWDefWindowProc(message, wParam, lParam );
- wnd->SetHWND(0);
- }
+ if ( wnd )
+ rc = wnd->MSWWindowProc(message, wParam, lParam);
else
- {
- if ( wnd )
- rc = wnd->MSWWindowProc(message, wParam, lParam);
- else
- rc = DefWindowProc( hWnd, message, wParam, lParam );
- }
+ rc = ::DefWindowProc(hWnd, message, wParam, lParam);
return rc;
}
break;
case WM_DESTROY:
- processed = HandleDestroy();
+ // 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:
#endif
case WM_LBUTTONDOWN:
- // set focus to this window
- if (AcceptsFocus())
- SetFocus();
-
- // fall through
-
case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_MBUTTONDBLCLK:
- processed = HandleMouseEvent(message,
+ {
+ 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;
+ 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
+ {
+ // 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 // __WXMICROWIN__
+#ifdef MM_JOY1MOVE
case MM_JOY1MOVE:
case MM_JOY2MOVE:
case MM_JOY1ZMOVE:
GET_Y_LPARAM(lParam),
wParam);
break;
-#endif
+#endif // __WXMICROWIN__
case WM_SYSCOMMAND:
processed = HandleSysCommand(wParam, lParam);
#endif // Win95
// for these messages we must return TRUE if process the message
-#ifdef WM_DRAWITEM // __WXMICROWIN__
+#ifdef WM_DRAWITEM
case WM_DRAWITEM:
case WM_MEASUREITEM:
{
rc.result = TRUE;
}
break;
-#endif
+#endif // defined(WM_DRAWITEM)
+
case WM_GETDLGCODE:
- if ( m_lDlgCode )
+ if ( GetWindowStyleFlag() & wxWANTS_CHARS )
{
- rc.result = m_lDlgCode;
+ // 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()
lParam);
}
break;
-#endif
+#endif // !__WXMICROWIN__
- // the return value for this message is ignored
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;
}
break;
#endif // __WIN32__
-
-#ifdef __WXUNIVERSAL__
- case WM_NCHITTEST:
- // we shouldn't allow the windows which don't want to get focus to
- // get it
- if ( !AcceptsFocus() )
- {
- rc.result = HTTRANSPARENT;
- processed = TRUE;
- }
- break;
-#endif // __WXUNIVERSAL__
}
if ( !processed )
return rc.result;
}
-// Dialog window proc
-LONG APIENTRY _EXPORT
-wxDlgProc(HWND WXUNUSED(hWnd), UINT message, WPARAM WXUNUSED(wParam), LPARAM WXUNUSED(lParam))
-{
- if ( message == WM_INITDIALOG )
- {
- // for this message, returning TRUE tells system to set focus to the
- // first control in the dialog box
- return TRUE;
- }
- else
- {
- // for all the other ones, FALSE means that we didn't process the
- // message
- return 0;
- }
-}
+// ----------------------------------------------------------------------------
+// wxWindow <-> HWND map
+// ----------------------------------------------------------------------------
+
+wxWinHashTable *wxWinHandleHash = NULL;
-wxList *wxWinHandleList = NULL;
wxWindow *wxFindWinFromHandle(WXHWND hWnd)
{
- wxNode *node = wxWinHandleList->Find((long)hWnd);
- if ( !node )
- return NULL;
- return (wxWindow *)node->Data();
+ return wxWinHandleHash->Get((long)hWnd);
}
-#if 0 // def __WXDEBUG__
-static int gs_AssociationCount = 0;
-#endif
-
void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win)
{
// adding NULL hWnd is (first) surely a result of an error and
wxCHECK_RET( hWnd != (HWND)NULL,
wxT("attempt to add a NULL hWnd to window list ignored") );
-
wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd);
+#ifdef __WXDEBUG__
if ( oldWin && (oldWin != win) )
{
- wxString str(win->GetClassInfo()->GetClassName());
- wxLogError(wxT("Bug! Found existing HWND %X for new window of class %s"), (int) hWnd, (const wxChar*) str);
+ wxLogDebug(wxT("HWND %X already associated with another window (%s)"),
+ hWnd, win->GetClassInfo()->GetClassName());
}
- else if (!oldWin)
+ else
+#endif // __WXDEBUG__
+ if (!oldWin)
{
-#if 0 // def __WXDEBUG__
- gs_AssociationCount ++;
- wxLogDebug("+ Association %d", gs_AssociationCount);
-#endif
-
- wxWinHandleList->Append((long)hWnd, win);
+ wxWinHandleHash->Put((long)hWnd, (wxWindow *)win);
}
}
void wxRemoveHandleAssociation(wxWindowMSW *win)
{
-#if 0 // def __WXDEBUG__
- if (wxWinHandleList->Member(win))
- {
- wxLogDebug("- Association %d", gs_AssociationCount);
- gs_AssociationCount --;
- }
-#endif
- wxWinHandleList->DeleteObject(win);
+ wxWinHandleHash->Delete((long)win->GetHWND());
}
+// ----------------------------------------------------------------------------
+// various MSW speciic class dependent functions
+// ----------------------------------------------------------------------------
+
// Default destroyer - override if you destroy it in some other way
// (e.g. with MDI child windows)
void wxWindowMSW::MSWDestroyWindow()
{
}
-void wxWindowMSW::MSWDetachWindowMenu()
+bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
+ const wxSize& size,
+ int& x, int& y,
+ int& w, int& h) const
{
-#ifndef __WXUNIVERSAL__
- if ( m_hMenu )
- {
- wxChar buf[1024];
- HMENU hMenu = (HMENU)m_hMenu;
-
- int N = ::GetMenuItemCount(hMenu);
- for ( int i = 0; i < N; i++ )
- {
- if ( !::GetMenuString(hMenu, i, buf, WXSIZEOF(buf), MF_BYPOSITION) )
- {
- wxLogLastError(wxT("GetMenuString"));
+ bool nonDefault = FALSE;
- continue;
- }
-
- if ( wxStrcmp(buf, _("&Window")) == 0 )
- {
- if ( !::RemoveMenu(hMenu, i, MF_BYPOSITION) )
- {
- wxLogLastError(wxT("RemoveMenu"));
- }
+ if ( pos.x == -1 )
+ {
+ // 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;
+ }
+ else
+ {
+ x = pos.x;
+ y = pos.y == -1 ? CW_USEDEFAULT : pos.y;
+
+ nonDefault = TRUE;
+ }
+
+ /*
+ 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;
- break;
- }
- }
+ nonDefault = TRUE;
}
-#endif
+
+ return nonDefault;
}
-bool wxWindowMSW::MSWCreate(int id,
- wxWindow *parent,
- const wxChar *wclass,
- wxWindow * WXUNUSED(wx_win),
+bool wxWindowMSW::MSWCreate(const wxChar *wclass,
const wxChar *title,
- int x,
- int y,
- int width,
- int height,
+ const wxPoint& pos,
+ const wxSize& size,
WXDWORD style,
- const wxChar *dialog_template,
WXDWORD extendedStyle)
{
- 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 rectParent;
- if ( parent )
- {
- ::GetClientRect(GetHwndOf(parent), &rectParent);
-
- width1 = rectParent.right - rectParent.left;
- height1 = rectParent.bottom - rectParent.top;
- }
-
- if ( x != -1 )
- x1 = x;
- if ( y != -1 )
- y1 = y;
- if ( width != -1 )
- width1 = width;
- if ( height != -1 )
- height1 = height;
-
- // unfortunately, setting WS_EX_CONTROLPARENT only for some windows in the
- // hierarchy with several embedded panels (and not all of them) causes the
- // program to hang during the next call to IsDialogMessage() due to the bug
- // in this function (at least in Windows NT 4.0, it seems to work ok in
- // Win2K)
-#if 0
- // if we have wxTAB_TRAVERSAL style, we want WS_EX_CONTROLPARENT or
- // IsDialogMessage() won't work for us
- if ( GetWindowStyleFlag() & wxTAB_TRAVERSAL )
- {
- extendedStyle |= WS_EX_CONTROLPARENT;
- }
-#endif // 0
+ // choose the position/size for the new window
+ 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 )
{
// be limited to the parents client area as child windows usually are
hParent = ::GetDesktopWindow();
}
- else if ( parent )
+ else // !popup
{
- hParent = GetHwndOf(parent);
- }
- else
- {
- // top level window
- hParent = NULL;
- }
-
- wxWndHook = this;
-
-#ifndef __WXMICROWIN__
- if ( dialog_template )
- {
- // for the dialogs without wxDIALOG_NO_PARENT style, use the top level
- // app window as parent - this avoids creating modal dialogs without
- // parent
- if ( !hParent && !(GetWindowStyleFlag() & wxDIALOG_NO_PARENT) )
- {
- wxWindow *winTop = wxTheApp->GetTopWindow();
- if ( winTop )
- hParent = GetHwndOf(winTop);
- }
-
- m_hWnd = (WXHWND)::CreateDialog(wxGetInstance(),
- dialog_template,
- hParent,
- (DLGPROC)wxDlgProc);
-
- if ( m_hWnd == 0 )
- {
- wxLogError(_("Can't find dialog template '%s'!\nCheck resource include path for finding wx.rc."),
- dialog_template);
-
- return FALSE;
- }
-
- if ( extendedStyle != 0 )
+ if ( (isChild || HasFlag(wxFRAME_TOOL_WINDOW)) && parent )
{
- ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, extendedStyle);
- ::SetWindowPos(GetHwnd(), NULL, 0, 0, 0, 0,
- SWP_NOSIZE |
- SWP_NOMOVE |
- SWP_NOZORDER |
- SWP_NOACTIVATE);
+ // this is either a normal child window or a top level window with
+ // wxFRAME_TOOL_WINDOW style (see below)
+ hParent = GetHwndOf(parent);
}
-
-#if defined(__WIN95__)
- // For some reason, the system menu is activated when we use the
- // WS_EX_CONTEXTHELP style, so let's set a reasonable icon
- if (extendedStyle & WS_EX_CONTEXTHELP)
+ else
{
- wxFrame *winTop = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame);
- if ( winTop )
- {
- wxIcon icon = winTop->GetIcon();
- if ( icon.Ok() )
- {
- ::SendMessage(GetHwnd(), WM_SETICON,
- (WPARAM)TRUE,
- (LPARAM)GetHiconOf(icon));
- }
- }
+ // 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;
}
-#endif // __WIN95__
-
- // JACS: is the following still necessary? The above seems to work.
+ }
- // ::SetWindowLong(GWL_EXSTYLE) doesn't work for the dialogs, so try
- // to take care of (at least some) extended style flags ourselves
- if ( extendedStyle & WS_EX_TOPMOST )
- {
- if ( !::SetWindowPos(GetHwnd(), HWND_TOPMOST, 0, 0, 0, 0,
- SWP_NOSIZE | SWP_NOMOVE) )
- {
- wxLogLastError(wxT("SetWindowPos"));
- }
- }
+ // 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();
- // move the dialog to its initial position without forcing repainting
- if ( !::MoveWindow(GetHwnd(), x1, y1, width1, height1, FALSE) )
+ if ( GetWindowStyleFlag() & wxCLIP_SIBLINGS )
{
- wxLogLastError(wxT("MoveWindow"));
+ style |= WS_CLIPSIBLINGS;
}
-
}
- else // creating a normal window, not a dialog
-#endif
- // __WXMICROWIN__
+ else // !child
{
- int controlId = 0;
- if ( style & WS_CHILD )
- {
- controlId = id;
-
- if ( GetWindowStyleFlag() & wxCLIP_SIBLINGS )
- {
- style |= WS_CLIPSIBLINGS;
- }
- }
-
- wxString className(wclass);
- if ( GetWindowStyleFlag() & wxNO_FULL_REPAINT_ON_RESIZE )
- {
- className += wxT("NR");
- }
-
- m_hWnd = (WXHWND)CreateWindowEx(extendedStyle,
- className,
- title ? title : wxT(""),
- style,
- x1, y1,
- width1, height1,
- hParent, (HMENU)controlId,
- wxGetInstance(),
- NULL);
-
- if ( !m_hWnd )
- {
- wxLogError(_("Can't create window of class %s!\nPossible Windows 3.x compatibility problem?"),
- wclass);
+ controlId = 0;
+ }
- return FALSE;
- }
+ // 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");
}
- wxWndHook = NULL;
+ // do create the window
+ wxWindowCreationHook hook(this);
-#ifdef __WXDEBUG__
- wxNode* node = wxWinHandleList->Member(this);
- if (node)
+ m_hWnd = (WXHWND)::CreateWindowEx
+ (
+ extendedStyle,
+ className,
+ title ? title : wxT(""),
+ style,
+ x, y, w, h,
+ hParent,
+ (HMENU)controlId,
+ wxGetInstance(),
+ NULL // no extra data
+ );
+
+ if ( !m_hWnd )
{
- HWND hWnd = (HWND) node->GetKeyInteger();
- if (hWnd != (HWND) m_hWnd)
- {
- wxLogError(wxT("A second HWND association is being added for the same window!"));
- }
+ wxLogSysError(_("Can't create window of class %s"), wclass);
+
+ return FALSE;
}
-#endif // Debug
- wxAssociateWinWithHandle((HWND) m_hWnd, this);
+ SubclassWin(m_hWnd);
- SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
+ SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
return TRUE;
}
// finally try this window too (catches toolbar case)
return MSWOnNotify(idCtrl, lParam, result);
-#else
+#else // __WXMICROWIN__
return FALSE;
#endif
}
if ( !endSession )
return FALSE;
+ // only send once
+ if ( (this != wxTheApp->GetTopWindow()) )
+ return FALSE;
+
wxCloseEvent event(wxEVT_END_SESSION, -1);
event.SetEventObject(wxTheApp);
event.SetCanVeto(FALSE);
event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) );
- if ( (this == wxTheApp->GetTopWindow()) && // Only send once
- wxTheApp->ProcessEvent(event))
- {
- }
- return TRUE;
+
+ return wxTheApp->ProcessEvent(event);
}
// ---------------------------------------------------------------------------
// activation/focus
// ---------------------------------------------------------------------------
-void wxWindowMSW::OnSetFocus(wxFocusEvent& event)
-{
- // panel wants to track the window which was the last to have focus in it,
- // so we want to set ourselves as the window which last had focus
- //
- // notice that it's also important to do it upwards the tree becaus
- // otherwise when the top level panel gets focus, it won't set it back to
- // us, but to some other sibling
- wxWindow *win = (wxWindow *)this;
- while ( win )
- {
- wxWindow *parent = win->GetParent();
- wxPanel *panel = wxDynamicCast(parent, wxPanel);
- if ( panel )
- {
- panel->SetLastFocus(win);
- }
-
- win = parent;
- }
-
- wxLogTrace(_T("focus"), _T("%s (0x%08x) gets focus"),
- GetClassInfo()->GetClassName(), GetHandle());
-
- event.Skip();
-}
-
bool wxWindowMSW::HandleActivate(int state,
bool WXUNUSED(minimized),
WXHWND WXUNUSED(activate))
bool wxWindowMSW::HandleSetFocus(WXHWND hwnd)
{
+ // notify the parent keeping track of focus for the kbd navigation
+ // purposes that we got it
+ wxChildFocusEvent eventFocus((wxWindow *)this);
+ (void)GetEventHandler()->ProcessEvent(eventFocus);
+
#if wxUSE_CARET
// Deal with caret
if ( m_caret )
}
#endif // wxUSE_CARET
+#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
+
wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId);
event.SetEventObject(this);
}
#endif // wxUSE_CARET
+#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
+
wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId);
event.SetEventObject(this);
{
#ifndef __WXMICROWIN__
HDROP hFilesInfo = (HDROP) wParam;
- POINT dropPoint;
- DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint);
// Get the total number of files dropped
- WORD gwFilesDropped = (WORD)::DragQueryFile
+ UINT gwFilesDropped = ::DragQueryFile
(
(HDROP)hFilesInfo,
(UINT)-1,
);
wxString *files = new wxString[gwFilesDropped];
- int wIndex;
- for (wIndex=0; wIndex < (int)gwFilesDropped; wIndex++)
+ for ( UINT wIndex = 0; wIndex < gwFilesDropped; wIndex++ )
{
- DragQueryFile (hFilesInfo, wIndex, (LPTSTR) wxBuffer, 1000);
- files[wIndex] = wxBuffer;
+ // first get the needed buffer length (+1 for terminating NUL)
+ size_t len = ::DragQueryFile(hFilesInfo, wIndex, NULL, 0) + 1;
+
+ // and now get the file name
+ ::DragQueryFile(hFilesInfo, wIndex,
+ files[wIndex].GetWriteBuf(len), len);
+
+ files[wIndex].UngetWriteBuf();
}
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;
-
- bool rc = GetEventHandler()->ProcessEvent(event);
- delete[] files;
+ POINT dropPoint;
+ DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint);
+ event.m_pos.x = dropPoint.x;
+ event.m_pos.y = dropPoint.y;
- return rc;
-#else
+ return GetEventHandler()->ProcessEvent(event);
+#else // __WXMICROWIN__
return FALSE;
#endif
}
// cursor set, stop here
return TRUE;
}
-#endif
+#endif // __WXMICROWIN__
+
// pass up the window chain
return FALSE;
}
#if wxUSE_MENUS_NATIVE
// is it a menu item?
- if ( id == 0 )
+ DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct;
+ if ( id == 0 && pDrawStruct->CtlType == ODT_MENU )
{
- DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct;
wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData);
wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE );
{
#if wxUSE_OWNER_DRAWN
// is it a menu item?
- if ( id == 0 )
+ MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct;
+ if ( id == 0 && pMeasureStruct->CtlType == ODT_MENU )
{
- MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct;
wxMenuItem *pMenuItem = (wxMenuItem *)(pMeasureStruct->itemData);
wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE );
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;
+}
+
+bool wxWindowMSW::HandleDisplayChange()
+{
+ wxDisplayChangedEvent event;
+ event.SetEventObject(this);
+
return GetEventHandler()->ProcessEvent(event);
}
*brush = hBrush;
return hBrush != 0;
-#else
+#else // __WXMICROWIN__
return FALSE;
#endif
}
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();
+ }
+
+ if ( win && win->HasCustomPalette() )
+ {
+ // realize the palette to see whether redrawing is needed
+ HDC hdc = ::GetDC((HWND) hWndPalChange);
+ win->m_palette.SetHPALETTE((WXHPALETTE)
+ ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
+
+ int result = ::RealizePalette(hdc);
+
+ // restore the palette (before releasing the DC)
+ win->m_palette.SetHPALETTE((WXHPALETTE)
+ ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
+ ::RealizePalette(hdc);
+ ::ReleaseDC((HWND) hWndPalChange, hdc);
+
+ // now check for the need to redraw
+ if (result > 0)
+ InvalidateRect((HWND) hWndPalChange, NULL, TRUE);
+ }
+
+ }
+#endif // wxUSE_PALETTE
+
wxPaletteChangedEvent event(GetId());
event.SetEventObject(this);
event.SetChangedWindow(wxFindWinFromHandle(hWndPalChange));
bool wxWindowMSW::HandleQueryNewPalette()
{
+
+#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) );
+
+ 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
+
wxQueryNewPaletteEvent event(GetId());
event.SetEventObject(this);
}
// Responds to colour changes: passes event on to children.
-void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& event)
+void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
{
- wxNode *node = GetChildren().First();
+ // 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
- wxWindow *win = (wxWindow *)node->Data();
- if ( win->GetParent() )
+ // 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() )
{
- wxSysColourChangedEvent event2;
- event.m_eventObject = win;
- win->GetEventHandler()->ProcessEvent(event2);
+ // we need to send the real WM_SYSCOLORCHANGE and not just trigger
+ // EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for
+ // the standard controls
+ ::SendMessage(GetHwndOf(win), WM_SYSCOLORCHANGE, 0, 0);
}
- node = node->Next();
+ node = node->GetNext();
+ }
+
+ // 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);
+ }
+
+ if ( !m_hasBgCol )
+ {
+ m_backgroundColour = wxSystemSettings::
+ GetSystemColour(wxSYS_COLOUR_BTNFACE);
+ }
+}
+
+extern wxCOLORMAP *wxGetStdColourMap()
+{
+ static COLORREF s_stdColours[wxSTD_COL_MAX];
+ static wxCOLORMAP s_cmap[wxSTD_COL_MAX];
+
+ if ( !gs_hasStdCmap )
+ {
+ static bool s_coloursInit = FALSE;
+
+ 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
+ }
+
+ s_coloursInit = TRUE;
+ }
+
+ gs_hasStdCmap = TRUE;
+
+ // 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)
+
+ INIT_CMAP_ENTRY(BTNTEXT);
+ INIT_CMAP_ENTRY(BTNSHADOW);
+ INIT_CMAP_ENTRY(BTNFACE);
+ INIT_CMAP_ENTRY(BTNHIGHLIGHT);
+
+#undef INIT_CMAP_ENTRY
}
+
+ return s_cmap;
}
// ---------------------------------------------------------------------------
bool rc = FALSE;
- if ( m_minWidth != -1 )
+ int minWidth = GetMinWidth(),
+ minHeight = GetMinHeight(),
+ maxWidth = GetMaxWidth(),
+ maxHeight = GetMaxHeight();
+
+ if ( minWidth != -1 )
{
- info->ptMinTrackSize.x = m_minWidth;
+ info->ptMinTrackSize.x = minWidth;
rc = TRUE;
}
- if ( m_minHeight != -1 )
+ if ( minHeight != -1 )
{
- info->ptMinTrackSize.y = m_minHeight;
+ info->ptMinTrackSize.y = minHeight;
rc = TRUE;
}
- if ( m_maxWidth != -1 )
+ if ( maxWidth != -1 )
{
- info->ptMaxTrackSize.x = m_maxWidth;
+ info->ptMaxTrackSize.x = maxWidth;
rc = TRUE;
}
- if ( m_maxHeight != -1 )
+ if ( maxHeight != -1 )
{
- info->ptMaxTrackSize.y = m_maxHeight;
+ info->ptMaxTrackSize.y = maxHeight;
rc = TRUE;
}
bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
{
#if wxUSE_MENUS_NATIVE
- if ( wxCurrentPopupMenu )
+ if ( !cmd && wxCurrentPopupMenu )
{
wxMenu *popupMenu = wxCurrentPopupMenu;
wxCurrentPopupMenu = NULL;
}
#endif // wxUSE_MENUS_NATIVE
- wxWindow *win = (wxWindow*) NULL;
- if ( cmd == 0 || cmd == 1 ) // menu or accel - use id
+ 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 )
{
- // must cast to a signed type before comparing with other ids!
- win = FindItem((signed short)id);
+ win = wxFindWinFromHandle(control);
}
- if (!win && control)
+ // try the id
+ if ( !win )
{
- // find it from HWND - this works even with the broken programs using
- // the same ids for different controls
- win = wxFindWinFromHandle(control);
+ // must cast to a signed type before comparing with other ids!
+ win = FindItem((signed short)id);
}
if ( win )
// 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
+ int id,
+ WXLPARAM lParam) const
{
wxKeyEvent event(evType);
event.SetId(GetId());
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 0xBB: // VK_OEM_PLUS
- case VK_ADD: id = WXK_ADD; break;
- case 0xBD: // VK_OEM_MINUS
- case VK_SUBTRACT: id = WXK_SUBTRACT; break;
- case 0xBE: // VK_OEM_PERIOD
- case VK_DECIMAL: id = WXK_DECIMAL; break;
- case VK_DIVIDE: id = WXK_DIVIDE; 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 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_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;
#endif // wxUSE_SPINCTRL
#endif // Win32
-
- if ( !win )
- {
- // hwnd is not a wxWindow, try its parent next below
- hwnd = ::GetParent(hwnd);
- }
}
}
while ( hwnd && !win )
{
- win = wxFindWinFromHandle((WXHWND)hwnd);
+ // 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);
}
return win;
return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam);
}
-#endif
+
+#endif // !__WXMICROWIN__
#ifdef __WXDEBUG__
const char *wxGetMessageName(int message)
{
POINT pt;
GetCursorPos( & pt );
+
return wxPoint(pt.x, pt.y);
}