#include "wx/msgdlg.h"
#include "wx/settings.h"
#include "wx/statbox.h"
+ #include "wx/sizer.h"
#endif
#if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__)
#include "wx/ownerdrw.h"
#endif
+#include "wx/evtloop.h"
#include "wx/module.h"
#include "wx/sysopt.h"
#define HAVE_TRACKMOUSEEVENT
#endif // everything needed for TrackMouseEvent()
+// if this is set to 1, we use deferred window sizing to reduce flicker when
+// resizing complicated window hierarchies, but this can in theory result in
+// different behaviour than the old code so we keep the possibility to use it
+// by setting this to 0 (in the future this should be removed completely)
#define USE_DEFERRED_SIZING 1
// ---------------------------------------------------------------------------
m_lastMouseY = -1;
m_lastMouseEvent = -1;
#endif // wxUSE_MOUSEEVENT_HACK
+
+ m_pendingPosition = wxDefaultPosition;
+ m_pendingSize = wxDefaultSize;
}
// Destructor
{
m_isBeingDeleted = true;
- if (m_windowReserved)
- {
- delete (wxExtraWindowData*) m_windowReserved;
- m_windowReserved = NULL;
- }
-
#ifndef __WXUNIVERSAL__
// VS: make sure there's no wxFrame with last focus set to us:
for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
}
delete m_childrenDisabled;
+
}
// real construction (Init() must have been called before!)
wOrient,
&scrollInfo) )
{
- // Not neccessarily an error, if there are no scrollbars yet.
+ // Not necessarily an error, if there are no scrollbars yet.
// wxLogLastError(_T("GetScrollInfo"));
}
return scrollInfo.nPos;
}
-bool wxCheckWindowWndProc(WXHWND hWnd, WXFARPROC wndProc)
+bool wxCheckWindowWndProc(WXHWND hWnd,
+ WXFARPROC WXUNUSED_IN_WINCE(wndProc))
{
// Unicows note: the code below works, but only because WNDCLASS contains
// original window handler rather that the unicows fake one. This may not
// On WinCE (at least), the wndproc comparison doesn't work,
// so have to use something like this.
#ifdef __WXWINCE__
- wxUnusedVar(wndProc);
-
extern wxChar *wxCanvasClassName;
extern wxChar *wxCanvasClassNameNR;
extern const wxChar *wxMDIFrameClassName;
pRect = NULL;
}
-#ifndef __SMARTPHONE__
+ // RedrawWindow not available on SmartPhone or eVC++ 3
+#if !defined(__SMARTPHONE__) && !(defined(_WIN32_WCE) && _WIN32_WCE < 400)
UINT flags = RDW_INVALIDATE | RDW_ALLCHILDREN;
if ( eraseBack )
flags |= RDW_ERASE;
// old style file-manager drag&drop support: we retain the old-style
// DragAcceptFiles in parallel with SetDropTarget.
-void wxWindowMSW::DragAcceptFiles(bool accept)
+void wxWindowMSW::DragAcceptFiles(bool WXUNUSED_IN_WINCE(accept))
{
-#if !defined(__WXWINCE__)
+#ifndef __WXWINCE__
HWND hWnd = GetHwnd();
if ( hWnd )
::DragAcceptFiles(hWnd, (BOOL)accept);
-#else
- wxUnusedVar(accept);
#endif
}
// Get total size
void wxWindowMSW::DoGetSize(int *x, int *y) const
{
- wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
- if (extraData && extraData->m_deferring && GetParent() && GetParent()->m_hDWP)
+ // if SetSize() had been called at wx level but not realized at Windows
+ // level yet (i.e. EndDeferWindowPos() not called), we still should return
+ // the new and not the old position to the other wx code
+ if ( m_pendingSize != wxDefaultSize )
{
- *x = extraData->m_size.x;
- *y = extraData->m_size.y;
- return;
+ if ( x )
+ *x = m_pendingSize.x;
+ if ( y )
+ *y = m_pendingSize.y;
}
+ else // use current size
+ {
+ RECT rect = wxGetWindowRect(GetHwnd());
- RECT rect = wxGetWindowRect(GetHwnd());
-
- if ( x )
- *x = rect.right - rect.left;
- if ( y )
- *y = rect.bottom - rect.top;
+ if ( x )
+ *x = rect.right - rect.left;
+ if ( y )
+ *y = rect.bottom - rect.top;
+ }
}
// Get size *available for subwindows* i.e. excluding menu bar etc.
void wxWindowMSW::DoGetClientSize(int *x, int *y) const
{
+ // this is only for top level windows whose resizing is never deferred, so
+ // we can safely use the current size here
RECT rect = wxGetClientRect(GetHwnd());
if ( x )
void wxWindowMSW::DoGetPosition(int *x, int *y) const
{
- wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
- if (extraData && extraData->m_deferring && GetParent() && GetParent()->m_hDWP)
+ wxWindow * const parent = GetParent();
+
+ wxPoint pos;
+ if ( m_pendingPosition != wxDefaultPosition )
{
- *x = extraData->m_pos.x;
- *y = extraData->m_pos.y;
- return;
+ pos = m_pendingPosition;
}
-
- RECT rect = wxGetWindowRect(GetHwnd());
-
- POINT point;
- point.x = rect.left;
- point.y = rect.top;
-
- // we do the adjustments with respect to the parent only for the "real"
- // children, not for the dialogs/frames
- if ( !IsTopLevel() )
+ else // use current position
{
- HWND hParentWnd = 0;
- wxWindow *parent = GetParent();
- if ( parent )
- hParentWnd = GetWinHwnd(parent);
+ RECT rect = wxGetWindowRect(GetHwnd());
- // Since we now have the absolute screen coords, if there's a parent we
- // must subtract its top left corner
- if ( hParentWnd )
- {
- ::ScreenToClient(hParentWnd, &point);
- }
+ POINT point;
+ point.x = rect.left;
+ point.y = rect.top;
- if ( parent )
+ // we do the adjustments with respect to the parent only for the "real"
+ // children, not for the dialogs/frames
+ if ( !IsTopLevel() )
{
- // We may be faking the client origin. So a window that's really at (0,
- // 30) may appear (to wxWin apps) to be at (0, 0).
- wxPoint pt(parent->GetClientAreaOrigin());
- point.x -= pt.x;
- point.y -= pt.y;
+ // Since we now have the absolute screen coords, if there's a
+ // parent we must subtract its top left corner
+ if ( parent )
+ {
+ ::ScreenToClient(GetHwndOf(parent), &point);
+ }
}
+
+ pos.x = point.x;
+ pos.y = point.y;
+ }
+
+ // we also must adjust by the client area offset: a control which is just
+ // under a toolbar could be at (0, 30) in Windows but at (0, 0) in wx
+ if ( parent && !IsTopLevel() )
+ {
+ const wxPoint pt(parent->GetClientAreaOrigin());
+ pos.x -= pt.x;
+ pos.y -= pt.y;
}
if ( x )
- *x = point.x;
+ *x = pos.x;
if ( y )
- *y = point.y;
+ *y = pos.y;
}
void wxWindowMSW::DoScreenToClient(int *x, int *y) const
*y = pt.y;
}
-void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height)
+void
+wxWindowMSW::DoMoveSibling(WXHWND hwnd, 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 USE_DEFERRED_SIZING
// if our parent had prepared a defer window handle for us, use it (unless
// we are a top level window)
- wxWindowMSW *parent = GetParent();
-
-#if USE_DEFERRED_SIZING
- HDWP hdwp = parent && !IsTopLevel() ? (HDWP)parent->m_hDWP : NULL;
-#else
- HDWP hdwp = 0;
-#endif
-
- wxMoveWindowDeferred(hdwp, this, GetHwnd(), x, y, width, height);
+ wxWindowMSW * const parent = IsTopLevel() ? NULL : GetParent();
+ HDWP hdwp = parent ? (HDWP)parent->m_hDWP : NULL;
if ( hdwp )
{
- // Store the size so we can report it accurately
- wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
- if (!extraData)
+ hdwp = ::DeferWindowPos(hdwp, (HWND)hwnd, NULL, x, y, width, height,
+ SWP_NOZORDER);
+ if ( !hdwp )
{
- extraData = new wxExtraWindowData;
- m_windowReserved = (void*) extraData;
+ wxLogLastError(_T("DeferWindowPos"));
}
- extraData->m_pos = wxPoint(x, y);
- extraData->m_size = wxSize(width, height);
- extraData->m_deferring = true;
+ }
+ if ( parent )
+ {
// hdwp must be updated as it may have been changed
parent->m_hDWP = (WXHANDLE)hdwp;
}
+
+ // otherwise (or if deferring failed) move the window in place immediately
+ if ( !hdwp )
+#endif // USE_DEFERRED_SIZING
+ {
+ if ( !::MoveWindow((HWND)hwnd, x, y, width, height, IsShown()) )
+ {
+ wxLogLastError(wxT("MoveWindow"));
+ }
+ }
+}
+
+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;
+
+ DoMoveSibling(m_hWnd, x, y, width, height);
}
// set the size of the window: if the dimensions are positive, just use them,
{
// get the current size and position...
int currentX, currentY;
+ int currentW, currentH;
+
GetPosition(¤tX, ¤tY);
- int currentW,currentH;
GetSize(¤tW, ¤tH);
// ... and don't do anything (avoiding flicker) if it's already ok
}
}
+ m_pendingPosition = wxPoint(x, y);
+ m_pendingSize = wxSize(width, height);
DoMoveWindow(x, y, width, height);
}
RECT rectClient;
::GetClientRect(GetHwnd(), &rectClient);
- // if the size is already ok, stop here (rectClient.left = top = 0)
+ // if the size is already ok, stop here (NB: rectClient.left = top = 0)
if ( (rectClient.right == width || width == wxDefaultCoord) &&
(rectClient.bottom == height || height == wxDefaultCoord) )
{
break;
}
- int widthClient = width,
- heightClient = height;
-
// Find the difference between the entire window (title bar and all)
// and the client area; add this to the new client size to move the
// window
RECT rectWin;
::GetWindowRect(GetHwnd(), &rectWin);
- widthClient += rectWin.right - rectWin.left - rectClient.right;
- heightClient += rectWin.bottom - rectWin.top - rectClient.bottom;
-
- POINT point;
- point.x = rectWin.left;
- point.y = rectWin.top;
+ const int widthWin = rectWin.right - rectWin.left,
+ heightWin = rectWin.bottom - rectWin.top;
// MoveWindow positions the child windows relative to the parent, so
// adjust if necessary
wxWindow *parent = GetParent();
if ( parent )
{
- ::ScreenToClient(GetHwndOf(parent), &point);
+ ::ScreenToClient(GetHwndOf(parent), (POINT *)&rectWin);
}
}
- DoMoveWindow(point.x, point.y, widthClient, heightClient);
+ // don't call DoMoveWindow() because we want to move window immediately
+ // and not defer it here
+ if ( !::MoveWindow(GetHwnd(),
+ rectWin.left,
+ rectWin.top,
+ width + widthWin - rectClient.right,
+ height + heightWin - rectClient.bottom,
+ TRUE) )
+ {
+ wxLogLastError(_T("MoveWindow"));
+ }
}
}
SIZE sizeRect;
TEXTMETRIC tm;
- GetTextExtentPoint(hdc, string, string.length(), &sizeRect);
+ ::GetTextExtentPoint32(hdc, string, string.length(), &sizeRect);
GetTextMetrics(hdc, &tm);
if ( x )
bProcess = false;
break;
- case VK_ESCAPE:
- {
-#if wxUSE_BUTTON
- wxButton *btn = wxDynamicCast(FindWindow(wxID_CANCEL),wxButton);
-
- // our own wxLogDialog should react to Esc
- // without Cancel button but this is a private class
- // so let's try recognize it by content
- #if wxUSE_LOG_DIALOG
- if ( !btn &&
- wxDynamicCast(this,wxDialog) &&
- FindWindow(wxID_MORE) &&
- FindWindow(wxID_OK) &&
- !FindWindow(wxID_CANCEL) &&
- GetTitle().MakeLower().StartsWith(wxTheApp->GetAppName().c_str())
- )
- btn = wxDynamicCast(FindWindow(wxID_OK),wxButton);
- #endif // wxUSE_LOG_DIALOG
- if ( btn && btn->IsEnabled() )
- {
- // if we do have a cancel button, do press it
- btn->MSWCommand(BN_CLICKED, 0 /* unused */);
-
- // we consumed the message
- return true;
- }
-#endif // wxUSE_BUTTON
-
- bProcess = false;
- }
- break;
-
case VK_RETURN:
{
if ( (lDlgCode & DLGC_WANTMESSAGE) && !bCtrlDown )
LRESULT rc;
- if ( wnd )
+ if ( wnd && wxEventLoop::AllowProcessing(wnd) )
rc = wnd->MSWWindowProc(message, wParam, lParam);
else
rc = ::DefWindowProc(hWnd, message, wParam, lParam);
break;
#endif // !__WXWINCE__
+#if !(defined(_WIN32_WCE) && _WIN32_WCE < 400)
+ case WM_WINDOWPOSCHANGED:
+ {
+ WINDOWPOS *lpPos = (WINDOWPOS *)lParam;
+
+ if ( !(lpPos->flags & SWP_NOSIZE) )
+ {
+ RECT rc;
+ ::GetClientRect(GetHwnd(), &rc);
+
+ AutoHRGN hrgnClient(::CreateRectRgnIndirect(&rc));
+ AutoHRGN hrgnNew(::CreateRectRgn(lpPos->x, lpPos->y,
+ lpPos->cx, lpPos->cy));
+
+ // we need to invalidate any new exposed areas here
+ // to force them to repaint
+ if ( ::CombineRgn(hrgnNew, hrgnNew, hrgnClient, RGN_DIFF) != NULLREGION )
+ ::InvalidateRgn(GetHwnd(), hrgnNew, TRUE);
+ }
+ }
+ break;
+#endif
#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
case WM_ACTIVATEAPP:
// This implicitly sends a wxEVT_ACTIVATE_APP event
// window creation/destruction
// ---------------------------------------------------------------------------
-bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT cs, bool *mayCreate)
+bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED_IN_WINCE(cs),
+ bool *mayCreate)
{
// VZ: why is this commented out for WinCE? If it doesn't support
// WS_EX_CONTROLPARENT at all it should be somehow handled globally,
#ifndef __WXWINCE__
if ( ((CREATESTRUCT *)cs)->dwExStyle & WS_EX_CONTROLPARENT )
EnsureParentHasControlParentStyle(GetParent());
-#else
- wxUnusedVar(cs);
#endif // !__WXWINCE__
// TODO: should generate this event from WM_NCCREATE
if ( !::GetCursorPosWinCE(&pt))
#else
if ( !::GetCursorPos(&pt) )
-#endif
+#endif
{
wxLogLastError(wxT("GetCursorPos"));
}
// we want to avoid Windows' "help" and for this we need to have a
// reference bitmap which can tell us what the RGB values change
// to.
+ wxLogNull logNo; // suppress error if we couldn't load the bitmap
wxBitmap stdColourBitmap(_T("wxBITMAP_STD_COLOURS"));
if ( stdColourBitmap.Ok() )
{
//
// also note that in this case lParam == PRF_CLIENT but we're
// clearly expected to paint the background and nothing else!
+
+ if ( IsTopLevel() || InheritsBackgroundColour() )
+ return false;
+
+ // sometimes we don't want the parent to handle it at all, instead
+ // return whatever value this window wants
+ if ( !MSWShouldPropagatePrintChild() )
+ return MSWPrintChild(hDC, (wxWindow *)this);
+
for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
{
if ( win->MSWPrintChild(hDC, (wxWindow *)this) )
bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
{
- // when we resize this window, its children are probably going to be
- // repositioned as well, prepare to use DeferWindowPos() for them
#if USE_DEFERRED_SIZING
// when we resize this window, its children are probably going to be
// repositioned as well, prepare to use DeferWindowPos() for them
numChildren ++;
}
- // Protect against valid m_hDWP being overwritten
+ // Protect against valid m_hDWP being overwritten
bool useDefer = false;
if ( numChildren > 1 )
{
if (!m_hDWP)
- {
+ {
m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren);
if ( !m_hDWP )
{
// may have depending on what the users EVT_SIZE handler does...)
HDWP hDWP = (HDWP)m_hDWP;
m_hDWP = NULL;
-
+
// do put all child controls in place at once
if ( !::EndDeferWindowPos(hDWP) )
{
wxLogLastError(_T("EndDeferWindowPos"));
}
- // Seems to be a bug in DeferWindowPos such that going from (a) to (b) to (a)
- // doesn't work (omits last position/size). So check if there's a disparity,
- // and correct.
+ // Reset our children's pending pos/size values.
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
node;
node = node->GetNext() )
{
- wxWindow *child = node->GetData();
- wxExtraWindowData* extraData = (wxExtraWindowData*) child->m_windowReserved;
- if (extraData && extraData->m_deferring)
- {
- wxPoint pos = child->GetPosition();
-
- if (extraData->m_pos != pos)
- child->Move(extraData->m_pos);
-
- extraData->m_deferring = false;
- }
+ wxWindowMSW *child = node->GetData();
+ child->m_pendingPosition = wxDefaultPosition;
+ child->m_pendingSize = wxDefaultSize;
}
}
-#endif
+#endif // USE_DEFERRED_SIZING
return processed;
}
return rc;
}
-bool wxWindowMSW::HandleGetMinMaxInfo(void *mmInfo)
+bool wxWindowMSW::HandleGetMinMaxInfo(void *WXUNUSED_IN_WINCE(mmInfo))
{
#ifdef __WXWINCE__
- wxUnusedVar(mmInfo);
return false;
#else
MINMAXINFO *info = (MINMAXINFO *)mmInfo;
bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam)
{
#if wxUSE_MOUSEWHEEL
+ // notice that WM_MOUSEWHEEL position is in screen coords (as it's
+ // forwarded up to the parent by DefWindowProc()) and not in the client
+ // ones as all the other messages, translate them to the client coords for
+ // consistency
+ const wxPoint
+ pt = ScreenToClient(wxPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
wxMouseEvent event(wxEVT_MOUSEWHEEL);
- InitMouseEvent(event,
- GET_X_LPARAM(lParam),
- GET_Y_LPARAM(lParam),
- LOWORD(wParam));
+ InitMouseEvent(event, pt.x, pt.y, LOWORD(wParam));
event.m_wheelRotation = (short)HIWORD(wParam);
event.m_wheelDelta = WHEEL_DELTA;
return false;
}
-int wxWindowMSW::HandleMenuChar(int chAccel, WXLPARAM lParam)
+int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
+ WXLPARAM WXUNUSED_IN_WINCE(lParam))
{
// FIXME: implement GetMenuItemCount for WinCE, possibly
// in terms of GetMenuItemInfo
wxLogLastError(_T("GetMenuItemInfo"));
}
}
-#else
- wxUnusedVar(chAccel);
- wxUnusedVar(lParam);
#endif
return wxNOT_FOUND;
}
: SB_VERT,
&scrollInfo) )
{
- // Not neccessarily an error, if there are no scrollbars yet.
+ // Not necessarily an error, if there are no scrollbars yet.
// wxLogLastError(_T("GetScrollInfo"));
}
#endif // wxUSE_HOTKEY
-// Moves a window by deferred method or normal method
-bool wxMoveWindowDeferred(HDWP& hdwp, wxWindow* win, HWND hWnd, int x, int y, int width, int height)
-{
- if ( hdwp )
- {
- hdwp = ::DeferWindowPos(hdwp, hWnd, NULL,
- x, y, width, height,
- SWP_NOZORDER);
- if ( !hdwp )
- {
- wxLogLastError(_T("DeferWindowPos"));
- }
- }
-
- // otherwise (or if deferring failed) move the window in place immediately
- if ( !hdwp )
- {
- if ( !::MoveWindow(hWnd, x, y, width, height, win->IsShown()) )
- {
- wxLogLastError(wxT("MoveWindow"));
- }
- }
- return hdwp != NULL;
-}
-
// Not tested under WinCE
#ifndef __WXWINCE__