]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/window.cpp
Don't use DDEExec registry key in wxMSW wxExecute() if it's empty.
[wxWidgets.git] / src / msw / window.cpp
index 6bb0616f0b5ea0016a4348202491f78865b67abc..d16f4990ff566e57bebf931d95ba69f10cbd9df6 100644 (file)
@@ -4,7 +4,6 @@
 // Author:      Julian Smart
 // Modified by: VZ on 13.05.99: no more Default(), MSWOnXXX() reorganisation
 // Created:     04/01/98
-// RCS-ID:      $Id$
 // Copyright:   (c) Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
@@ -81,6 +80,7 @@
 #include "wx/msw/private.h"
 #include "wx/msw/private/keyboard.h"
 #include "wx/msw/dcclient.h"
+#include "wx/private/textmeasure.h"
 
 #if wxUSE_TOOLTIPS
     #include "wx/tooltip.h"
@@ -1429,7 +1429,7 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
     // 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
+    // regions), so avoid it altogether
 
 
     if ( flags & wxVSCROLL )
@@ -2164,31 +2164,18 @@ void wxWindowMSW::DoGetTextExtent(const wxString& string,
                                   int *externalLeading,
                                   const wxFont *fontToUse) const
 {
-    wxASSERT_MSG( !fontToUse || fontToUse->IsOk(),
-                    wxT("invalid font in GetTextExtent()") );
-
-    HFONT hfontToUse;
-    if ( fontToUse )
-        hfontToUse = GetHfontOf(*fontToUse);
+    // ensure we work with a valid font
+    wxFont font;
+    if ( !fontToUse || !fontToUse->IsOk() )
+        font = GetFont();
     else
-        hfontToUse = GetHfontOf(GetFont());
-
-    WindowHDC hdc(GetHwnd());
-    SelectInHDC selectFont(hdc, hfontToUse);
+        font = *fontToUse;
 
-    SIZE sizeRect;
-    TEXTMETRIC tm;
-    ::GetTextExtentPoint32(hdc, string.t_str(), string.length(), &sizeRect);
-    GetTextMetrics(hdc, &tm);
+    wxCHECK_RET( font.IsOk(), wxT("invalid font in GetTextExtent()") );
 
-    if ( x )
-        *x = sizeRect.cx;
-    if ( y )
-        *y = sizeRect.cy;
-    if ( descent )
-        *descent = tm.tmDescent;
-    if ( externalLeading )
-        *externalLeading = tm.tmExternalLeading;
+    const wxWindow* win = static_cast<const wxWindow*>(this);
+    wxTextMeasure txm(win, &font);
+    txm.GetTextExtent(string, x, y, descent, externalLeading);
 }
 
 // ---------------------------------------------------------------------------
@@ -3445,26 +3432,31 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
 #if !defined(__WXWINCE__)
         case WM_CONTEXTMENU:
             {
-                // we don't convert from screen to client coordinates as
-                // the event may be handled by a parent window
-                wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
-
-                wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
-
-                // we could have got an event from our child, reflect it back
-                // to it if this is the case
-                wxWindowMSW *win = NULL;
+                // Ignore the events that are propagated from a child window by
+                // DefWindowProc(): as wxContextMenuEvent is already propagated
+                // upwards the window hierarchy by us, not doing this would
+                // result in duplicate events being sent.
                 WXHWND hWnd = (WXHWND)wParam;
                 if ( hWnd != m_hWnd )
                 {
-                    win = FindItemByHWND(hWnd);
+                    wxWindowMSW *win = FindItemByHWND(hWnd);
+                    if ( win && IsDescendant(win) )
+                    {
+                        // We had already generated wxContextMenuEvent when we
+                        // got WM_CONTEXTMENU for that window.
+                        processed = true;
+                        break;
+                    }
                 }
 
-                if ( !win )
-                    win = this;
+                // we don't convert from screen to client coordinates as
+                // the event may be handled by a parent window
+                wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
 
-                evtCtx.SetEventObject(win);
-                processed = win->HandleWindowEvent(evtCtx);
+                wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
+                evtCtx.SetEventObject(this);
+
+                processed = HandleWindowEvent(evtCtx);
             }
             break;
 #endif
@@ -4828,6 +4820,8 @@ bool wxWindowMSW::HandlePaint()
     // be called from inside the event handlers called above)
     m_updateRegion.Clear();
 
+    wxPaintDCImpl::EndPaint((wxWindow *)this);
+
     return processed;
 }
 
@@ -4969,7 +4963,11 @@ wxWindowMSW::MSWGetBgBrushForChild(WXHDC hDC, wxWindowMSW *child)
 
         ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1);
 
-        if ( !::SetBrushOrgEx((HDC)hDC, -rc.left, -rc.top, NULL) )
+        int x = rc.left,
+            y = rc.top;
+        MSWAdjustBrushOrg(&x, &y);
+
+        if ( !::SetBrushOrgEx((HDC)hDC, -x, -y, NULL) )
         {
             wxLogLastError(wxT("SetBrushOrgEx(bg brush)"));
         }
@@ -5109,11 +5107,9 @@ bool wxWindowMSW::HandleExitSizeMove()
     return HandleWindowEvent(event);
 }
 
-bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
+bool wxWindowMSW::BeginRepositioningChildren()
 {
 #if wxUSE_DEFERRED_SIZING
-    // when we resize this window, its children are probably going to be
-    // repositioned as well, prepare to use DeferWindowPos() for them
     int numChildren = 0;
     for ( HWND child = ::GetWindow(GetHwndOf(this), GW_CHILD);
           child;
@@ -5122,23 +5118,60 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
         numChildren ++;
     }
 
+    // Nothing is gained by deferring the repositioning of a single child.
+    if ( numChildren < 2 )
+        return false;
+
     // Protect against valid m_hDWP being overwritten
-    bool useDefer = false;
+    if ( m_hDWP )
+        return false;
 
-    if ( numChildren > 1 )
+    m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren);
+    if ( !m_hDWP )
     {
-        if (!m_hDWP)
-        {
-            m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren);
-            if ( !m_hDWP )
-            {
-                wxLogLastError(wxT("BeginDeferWindowPos"));
-            }
-            if (m_hDWP)
-                useDefer = true;
-        }
+        wxLogLastError(wxT("BeginDeferWindowPos"));
+        return false;
+    }
+
+    // Return true to indicate that EndDeferWindowPos() should be called.
+    return true;
+#endif // wxUSE_DEFERRED_SIZING
+}
+
+void wxWindowMSW::EndRepositioningChildren()
+{
+#if wxUSE_DEFERRED_SIZING
+    wxASSERT_MSG( m_hDWP, wxS("Shouldn't be called") );
+
+    // reset m_hDWP to NULL so that child windows don't try to use our
+    // m_hDWP after we call EndDeferWindowPos() on it (this shouldn't
+    // happen anyhow normally but who knows what weird flow of control we
+    // 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(wxT("EndDeferWindowPos"));
+    }
+
+    // Reset our children's pending pos/size values.
+    for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+          node;
+          node = node->GetNext() )
+    {
+        wxWindowMSW * const child = node->GetData();
+        child->MSWEndDeferWindowPos();
     }
 #endif // wxUSE_DEFERRED_SIZING
+}
+
+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
+    ChildrenRepositioningGuard repositionGuard(this);
 
     // update this window size
     bool processed = false;
@@ -5171,34 +5204,6 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
             processed = HandleWindowEvent(event);
     }
 
-#if wxUSE_DEFERRED_SIZING
-    // and finally change the positions of all child windows at once
-    if ( useDefer && m_hDWP )
-    {
-        // reset m_hDWP to NULL so that child windows don't try to use our
-        // m_hDWP after we call EndDeferWindowPos() on it (this shouldn't
-        // happen anyhow normally but who knows what weird flow of control we
-        // 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(wxT("EndDeferWindowPos"));
-        }
-
-        // Reset our children's pending pos/size values.
-        for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
-              node;
-              node = node->GetNext() )
-        {
-            wxWindowMSW * const child = node->GetData();
-            child->MSWEndDeferWindowPos();
-        }
-    }
-#endif // wxUSE_DEFERRED_SIZING
-
     return processed;
 }
 
@@ -5297,10 +5302,10 @@ bool wxWindowMSW::HandleCommand(WXWORD id_, WXWORD cmd, WXHWND control)
     // the messages sent from the in-place edit control used by the treectrl
     // for label editing have id == 0, but they should _not_ be treated as menu
     // messages (they are EN_XXX ones, in fact) so don't translate anything
-    // coming from a control to wxEVT_COMMAND_MENU_SELECTED
+    // coming from a control to wxEVT_MENU
     if ( !control )
     {
-        wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id);
+        wxCommandEvent event(wxEVT_MENU, id);
         event.SetEventObject(this);
         event.SetInt(id);
 
@@ -5461,7 +5466,7 @@ bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags)
     };
 
 #ifdef wxHAS_XBUTTON
-    // the same messages are used for both auxillary mouse buttons so we need
+    // the same messages are used for both auxiliary mouse buttons so we need
     // to adjust the index manually
     switch ( msg )
     {
@@ -5600,7 +5605,20 @@ wxWindowMSW::HandleMouseWheel(wxMouseWheelAxis axis,
         }
     }
 
+    static int s_columnsPerRotation = -1;
+    if ( s_columnsPerRotation == -1 )
+    {
+        if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
+                                     &s_columnsPerRotation, 0))
+        {
+            // this setting is not supported on Windows 2000/XP, so use the value of 1
+            // http://msdn.microsoft.com/en-us/library/ms997498.aspx
+            s_columnsPerRotation = 1;
+        }
+    }
+
     event.m_linesPerAction = s_linesPerRotation;
+    event.m_columnsPerAction = s_columnsPerRotation;
     return HandleWindowEvent(event);
 
 #else // !wxUSE_MOUSEWHEEL
@@ -5865,9 +5883,9 @@ int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
 
 bool wxWindowMSW::HandleClipboardEvent(WXUINT nMsg)
 {
-    const wxEventType type = nMsg == WM_CUT       ? wxEVT_COMMAND_TEXT_CUT
-                           : nMsg == WM_COPY      ? wxEVT_COMMAND_TEXT_COPY
-                           : /* nMsg == WM_PASTE */ wxEVT_COMMAND_TEXT_PASTE;
+    const wxEventType type = nMsg == WM_CUT       ? wxEVT_TEXT_CUT
+                           : nMsg == WM_COPY      ? wxEVT_TEXT_COPY
+                           : /* nMsg == WM_PASTE */ wxEVT_TEXT_PASTE;
     wxClipboardTextEvent evt(type, GetId());
 
     evt.SetEventObject(this);
@@ -6315,6 +6333,9 @@ int VKToWX(WXWORD vk, WXLPARAM lParam, wchar_t *uc)
 
         case VK_DELETE:
             wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DELETE, WXK_DELETE);
+
+            if ( uc )
+                *uc = WXK_DELETE;
             break;
 
         case VK_RETURN:
@@ -6609,7 +6630,7 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
     DWORD hiWord = HIWORD(lParam);
     if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) )
     {
-        wchar_t uc;
+        wchar_t uc = 0;
         int id = wxMSWKeyboard::VKToWX(wParam, lParam, &uc);
 
         // Don't intercept keyboard entry (notably Escape) if a modal window
@@ -7215,9 +7236,21 @@ wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
     {
         // WindowFromPoint() ignores the disabled children but we're supposed
         // to take them into account, so check if we have a child at this
-        // coordinate.
-        ::ScreenToClient(hWnd, &pt2);
-        hWnd = ::ChildWindowFromPointEx(hWnd, pt2, CWP_SKIPINVISIBLE);
+        // coordinate using ChildWindowFromPointEx().
+        for ( ;; )
+        {
+            pt2.x = pt.x;
+            pt2.y = pt.y;
+            ::ScreenToClient(hWnd, &pt2);
+            HWND child = ::ChildWindowFromPointEx(hWnd, pt2, CWP_SKIPINVISIBLE);
+            if ( child == hWnd || !child )
+                break;
+
+            // ChildWindowFromPointEx() only examines the immediate children
+            // but we want to get the deepest (top in Z-order) one, so continue
+            // iterating for as long as it finds anything.
+            hWnd = child;
+        }
     }
 
     return wxGetWindowFromHWND((WXHWND)hWnd);
@@ -7297,8 +7330,6 @@ bool wxWindowMSW::UnregisterHotKey(int hotkeyId)
     return true;
 }
 
-#if wxUSE_ACCEL
-
 bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam)
 {
     int win_modifiers = LOWORD(lParam);
@@ -7313,8 +7344,6 @@ bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam)
     return HandleWindowEvent(event);
 }
 
-#endif // wxUSE_ACCEL
-
 #endif // wxUSE_HOTKEY
 
 // Not tested under WinCE