m_childrenDisabled = NULL;
m_frozenness = 0;
- // wxWnd
- m_hMenu = 0;
-
m_hWnd = 0;
+ m_hDWP = 0;
m_xThumbSize = 0;
m_yThumbSize = 0;
// wxTopLevelWindow) should remove WS_CHILD in their MSWGetStyle()
WXDWORD style = WS_CHILD;
- if ( flags & wxCLIP_CHILDREN )
- style |= WS_CLIPCHILDREN;
+ // using this flag results in very significant reduction in flicker,
+ // especially with controls inside the static boxes (as the interior of the
+ // box is not redrawn twice)
+ style |= WS_CLIPCHILDREN;
+
+ // it doesn't seem useful to use WS_CLIPSIBLINGS here as we officially
+ // don't support overlapping windows and it only makes sense for them and,
+ // presumably, gives the system some extra work (to manage more clipping
+ // regions), so avoid it alltogether
- if ( flags & wxCLIP_SIBLINGS )
- style |= WS_CLIPSIBLINGS;
if ( flags & wxVSCROLL )
style |= WS_VSCROLL;
state |= MK_SHIFT;
if ( wxIsCtrlDown() )
state |= MK_CONTROL;
- if ( GetKeyState( VK_LBUTTON ) )
+
+ // Only the high-order bit should be tested
+ if ( GetKeyState( VK_LBUTTON ) & (1<<15) )
state |= MK_LBUTTON;
- if ( GetKeyState( VK_MBUTTON ) )
+ if ( GetKeyState( VK_MBUTTON ) & (1<<15) )
state |= MK_MBUTTON;
- if ( GetKeyState( VK_RBUTTON ) )
+ if ( GetKeyState( VK_RBUTTON ) & (1<<15) )
state |= MK_RBUTTON;
POINT pt;
width = 0;
if (height < 0)
height = 0;
- if ( !::MoveWindow(GetHwnd(), x, y, width, height, IsShown() /*Repaint?*/) )
+
+ // if our parent had prepared a defer window handle for us, use it
+ wxWindowMSW *parent = GetParent();
+ HDWP hdwp = parent ? (HDWP)parent->m_hDWP : NULL;
+ if ( hdwp )
+ {
+ hdwp = ::DeferWindowPos(hdwp, GetHwnd(), NULL,
+ x, y, width, height,
+ SWP_NOZORDER);
+ if ( !hdwp )
+ {
+ wxLogLastError(_T("DeferWindowPos"));
+ }
+
+ // 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 )
{
- wxLogLastError(wxT("MoveWindow"));
+ if ( !::MoveWindow(GetHwnd(), x, y, width, height, TRUE) )
+ {
+ wxLogLastError(wxT("MoveWindow"));
+ }
}
}
// here we try to do all the job which ::IsDialogMessage() usually does
// internally
-#if 1
if ( msg->message == WM_KEYDOWN )
{
bool bCtrlDown = wxIsCtrlDown();
case VK_ESCAPE:
{
#if wxUSE_BUTTON
- wxButton *btn = wxDynamicCast(FindWindow(wxID_CANCEL),
- wxButton);
+ 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
bProcess = false;
}
// FIXME: this should be handled by
- // wxNavigationKeyEvent handler and not here!!
+ // wxNavigationKeyEvent handler and not here!
else
{
#if wxUSE_BUTTON
}
}
}
-#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 )
- {
- // don't process system keys here
- if ( !(HIWORD(msg->lParam) & KF_ALTDOWN) )
- {
- if ( (msg->wParam == VK_TAB) && wxIsCtrlDown() )
- {
- // find the first notebook parent and change its page
- wxWindow *win = this;
- wxNotebook *nbook = NULL;
- while ( win && !nbook )
- {
- nbook = wxDynamicCast(win, wxNotebook);
- win = win->GetParent();
- }
-
- if ( nbook )
- {
- bool forward = !wxIsShiftDown();
-
- nbook->AdvanceSelection(forward);
- }
- }
- }
- }
-#endif // 1/0
// don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the
// message even when there is no cancel button and when the message is
}
void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam,
- WXWORD *nCtlColor, WXHDC *hdc, WXHWND *hwnd)
+ WXHDC *hdc, WXHWND *hwnd)
{
-#ifndef __WXMICROWIN__
- *nCtlColor = CTLCOLOR_BTN;
*hwnd = (WXHWND)lParam;
*hdc = (WXHDC)wParam;
-#endif
}
void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam,
(void)HandleDestroy();
break;
+#ifndef __SMARTPHONE__ // or wxWinCE in general ?
+ case WM_WINDOWPOSCHANGING:
+ {
+ WINDOWPOS *wp = wx_reinterpret_cast(WINDOWPOS *, lParam);
+
+ if ( wp->flags & SWP_NOSIZE )
+ break;
+
+ // when we resize this window, its children are probably going
+ // to be repositioned as well, prepare to use DeferWindowPos()
+ // for them
+ const int numChildren = GetChildren().GetCount();
+ if ( numChildren > 1 )
+ {
+ m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren);
+ if ( !m_hDWP )
+ {
+ wxLogLastError(_T("BeginDeferWindowPos"));
+ }
+ }
+ }
+ break;
+
+ case WM_WINDOWPOSCHANGED:
+ // first let DefWindowProc() handle the message: it will generate
+ // WM_MOVE and WM_SIZE as needed
+ processed = MSWDefWindowProc(message, wParam, lParam) == 0;
+
+ // then change the positions of all child windows at once
+ if ( m_hDWP )
+ {
+ HDWP hDWP = (HDWP)m_hDWP;
+ m_hDWP = NULL;
+
+ // put all child controls in place at once now
+ if ( !::EndDeferWindowPos(hDWP) )
+ {
+ wxLogLastError(_T("EndDeferWindowPos"));
+ }
+ }
+ break;
+#endif // __SMARTPHONE__
+
+ case WM_SIZE:
+ processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam);
+ break;
+
case WM_MOVE:
processed = HandleMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
break;
#if !defined(__WXWINCE__)
+ // TODO: move those in WM_WINDOWPOSCHANGING case above
case WM_MOVING:
{
LPRECT pRect = (LPRECT)lParam;
}
}
break;
-#endif
- case WM_SIZE:
- processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam);
- break;
-
-#if !defined(__WXWINCE__)
case WM_SIZING:
{
LPRECT pRect = (LPRECT)lParam;
}
}
break;
-#endif
+#endif // !__WXWINCE__
#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
case WM_ACTIVATEAPP:
break;
// CTLCOLOR messages are sent by children to query the parent for their
- // colors#ifndef __WXMICROWIN__
+ // colors
#ifndef __WXMICROWIN__
case WM_CTLCOLORMSGBOX:
case WM_CTLCOLOREDIT:
case WM_CTLCOLORSCROLLBAR:
case WM_CTLCOLORSTATIC:
{
- WXWORD nCtlColor;
WXHDC hdc;
WXHWND hwnd;
- UnpackCtlColor(wParam, lParam, &nCtlColor, &hdc, &hwnd);
-
- processed = HandleCtlColor(&rc.hBrush,
- (WXHDC)hdc,
- (WXHWND)hwnd,
- nCtlColor,
- message,
- wParam,
- lParam);
+ UnpackCtlColor(wParam, lParam, &hdc, &hwnd);
+
+ processed = HandleCtlColor(&rc.hBrush, (WXHDC)hdc, (WXHWND)hwnd);
}
break;
#endif // !__WXMICROWIN__
return GetEventHandler()->ProcessEvent(event);
}
-bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush,
- WXHDC pDC,
- WXHWND pWnd,
- WXUINT nCtlColor,
- WXUINT message,
- WXWPARAM wParam,
- WXLPARAM lParam)
-{
#ifndef __WXMICROWIN__
- WXHBRUSH hBrush = 0;
-#ifdef __WXWINCE__
- if (false)
-#else
- if ( nCtlColor == CTLCOLOR_DLG )
-#endif
- {
- hBrush = OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam);
- }
+bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush, WXHDC pDC, WXHWND pWnd)
+{
#if wxUSE_CONTROLS
+ wxWindow *item = FindItemByHWND(pWnd, true);
+ if ( item )
+ *brush = item->MSWControlColor(pDC);
else
- {
- wxControl *item = (wxControl *)FindItemByHWND(pWnd, true);
- if ( item )
- hBrush = item->OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam);
- }
#endif // wxUSE_CONTROLS
+ *brush = NULL;
- if ( hBrush )
- *brush = hBrush;
-
- return hBrush != 0;
-#else // __WXMICROWIN__
- return false;
-#endif
+ return *brush != NULL;
}
-// Define for each class of dialog and control
-WXHBRUSH wxWindowMSW::OnCtlColor(WXHDC WXUNUSED(hDC),
- WXHWND WXUNUSED(hWnd),
- WXUINT WXUNUSED(nCtlColor),
- WXUINT WXUNUSED(message),
- WXWPARAM WXUNUSED(wParam),
- WXLPARAM WXUNUSED(lParam))
+#endif // __WXMICROWIN__
+
+WXHBRUSH wxWindowMSW::MSWControlColor(WXHDC WXUNUSED(hDC))
{
return (WXHBRUSH)0;
}
bool wxWindowMSW::HandlePaint()
{
-// if (GetExtraStyle() & wxWS_EX_THEMED_BACKGROUND)
-// return false;
-
HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle
if ( !hRegion )
wxLogLastError(wxT("CreateRectRgn"));
bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
{
- // Prevents flicker when dragging
- if ( ::IsIconic(GetHwnd()) )
- return true;
-
wxDCTemp dc(hdc);
dc.SetHDC(hdc);
void wxWindowMSW::OnEraseBackground(wxEraseEvent& event)
{
- if ( !m_hasBgCol )
+ // standard non top level controls (i.e. except the dialogs) always erase
+ // their background themselves in HandleCtlColor() or have some control-
+ // specific ways to set the colours (common controls)
+ if ( IsOfStandardClass() && !IsTopLevel() )
{
event.Skip();
return;
}
- // we have a fixed solid background colour, do use it
- RECT rect;
- ::GetClientRect(GetHwnd(), &rect);
+ if ( GetBackgroundStyle() == wxBG_STYLE_CUSTOM )
+ {
+ // don't skip the event here, custom background means that the app
+ // is drawing it itself in its OnPaint(), so don't draw it at all
+ // now to avoid flicker
+ return;
+ }
+
- wxColour backgroundColour(GetBackgroundColour());
- COLORREF ref = PALETTERGB(backgroundColour.Red(),
- backgroundColour.Green(),
- backgroundColour.Blue());
- HBRUSH hBrush = ::CreateSolidBrush(ref);
+ // do default background painting
+ if ( !DoEraseBackground(*event.GetDC()) )
+ {
+ // let the system paint the background
+ event.Skip();
+ }
+}
+
+bool wxWindowMSW::DoEraseBackground(wxDC& dc)
+{
+ HBRUSH hBrush = (HBRUSH)MSWGetBgBrush(dc.GetHDC());
if ( !hBrush )
- wxLogLastError(wxT("CreateSolidBrush"));
+ return false;
- HDC hdc = (HDC)event.GetDC()->GetHDC();
+ RECT rc;
+ ::GetClientRect(GetHwnd(), &rc);
+ ::FillRect(GetHdcOf(dc), &rc, hBrush);
-#ifndef __WXWINCE__
- int mode = ::SetMapMode(hdc, MM_TEXT);
-#endif
+ return true;
+}
+
+WXHBRUSH wxWindowMSW::MSWGetSolidBgBrushForChild(wxWindow *child)
+{
+ wxColour col = MSWGetBgColourForChild(child);
+ if ( col.Ok() )
+ {
+ // draw children with the same colour as the parent
+ wxBrush *brush = wxTheBrushList->FindOrCreateBrush(col, wxSOLID);
- ::FillRect(hdc, &rect, hBrush);
- ::DeleteObject(hBrush);
+ return (WXHBRUSH)brush->GetResourceHandle();
+ }
-#ifndef __WXWINCE__
- ::SetMapMode(hdc, mode);
-#endif
+ return 0;
+}
+
+wxColour wxWindowMSW::MSWGetBgColourForChild(wxWindow *child)
+{
+ if ( m_hasBgCol )
+ {
+ // our background colour applies to:
+ // 1. this window itself, always
+ // 2. all children unless the colour is "not inheritable"
+ // 3. immediate transparent children which should show the same
+ // background as we do, but not for transparent grandchildren
+ // which use the background of their immediate parent instead
+ if ( m_inheritBgCol ||
+ child == this ||
+ (child->HasTransparentBackground() &&
+ child->GetParent() == this) )
+ {
+ return GetBackgroundColour();
+ }
+ }
+
+ return wxNullColour;
+}
+
+WXHBRUSH wxWindowMSW::MSWGetBgBrushForSelf(wxWindow *parent, WXHDC hDC)
+{
+ return parent->MSWGetBgBrushForChild(hDC, (wxWindow *)this);
+}
+
+WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC)
+{
+ for ( wxWindow *win = (wxWindow *)this; win; win = win->GetParent() )
+ {
+ WXHBRUSH hBrush = MSWGetBgBrushForSelf(win, hDC);
+ if ( hBrush )
+ return hBrush;
+
+ // background is not inherited beyond the windows which have their own
+ // fixed background such as top level windows and notebooks and for
+ // windows for which a custom colour had been explicitly set with
+ // SetOwnBackgroundColour() and so shouldn't affect its children
+ if ( win->ProvidesBackground() ||
+ (win->m_hasBgCol && !win->m_inheritBgCol) )
+ break;
+ }
+
+ return 0;
}
// ---------------------------------------------------------------------------
case VK_NUMLOCK: id = WXK_NUMLOCK; break;
case VK_SCROLL: id = WXK_SCROLL; break;
+ // the mapping for these keys may be incorrect on non-US keyboards so
+ // maybe we shouldn't map them to ASCII values at all
case VK_OEM_1: id = ';'; break;
case VK_OEM_PLUS: id = '+'; break;
case VK_OEM_COMMA: id = ','; break;
bool bVirtual;
//High order with GetAsyncKeyState only available on WIN32
-#ifdef __WIN32__
+#ifdef __WIN32__
//If the requested key is a LED key, return
//true if the led is pressed
if (key == WXK_NUMLOCK ||
key == WXK_SCROLL)
{
#endif
- //low order bit means LED is highlighted,
+ //low order bit means LED is highlighted,
//high order means key is down
//Here, for compat with other ports we want both
return GetKeyState( wxCharCodeWXToMSW(key, &bVirtual) ) != 0;
-#ifdef __WIN32__
+#ifdef __WIN32__
}
else
{
static LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
MSG *msg = (MSG*)lParam;
- if ( msg->message == WM_NULL )
+
+ // only process the message if it is actually going to be removed from
+ // the message queue, this prevents that the same event from being
+ // processed multiple times if now someone just called PeekMessage()
+ if ( msg->message == WM_NULL && wParam == PM_REMOVE )
{
wxTheApp->ProcessPendingEvents();
}