]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/window.cpp
fixed calling Union() or Offset() on a previously Clear()ed region, also removed...
[wxWidgets.git] / src / msw / window.cpp
index 8808c8e64f291ce147224b2dbb6c4243d7c78ddf..ebd05bfd52bd386c847d68b3d697b0c41a336cd0 100644 (file)
@@ -178,6 +178,9 @@ static void TranslateKbdEventToMouse(wxWindowMSW *win,
 // get the text metrics for the current font
 static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win);
 
 // get the text metrics for the current font
 static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win);
 
+// find the window for the mouse event at the specified position
+static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y); //TW:REQ:Univ
+
 // wrapper around BringWindowToTop() API
 static inline void wxBringWindowToTop(HWND hwnd)
 {
 // wrapper around BringWindowToTop() API
 static inline void wxBringWindowToTop(HWND hwnd)
 {
@@ -405,25 +408,29 @@ bool wxWindowMSW::Create(wxWindow *parent,
 
     parent->AddChild(this);
 
 
     parent->AddChild(this);
 
-    // note that all windows are created visible by default
     WXDWORD exstyle;
     WXDWORD exstyle;
-    DWORD msflags = WS_VISIBLE | MSWGetCreateWindowFlags(&exstyle);
+    DWORD msflags = MSWGetCreateWindowFlags(&exstyle);
 
 #ifdef __WXUNIVERSAL__
     // no borders, we draw them ourselves
 
 #ifdef __WXUNIVERSAL__
     // no borders, we draw them ourselves
-    exstyle = 0;
+    exstyle &= ~(WS_EX_DLGMODALFRAME |
+                 WS_EX_STATICEDGE |
+                 WS_EX_CLIENTEDGE |
+                 WS_EX_WINDOWEDGE);
     msflags &= ~WS_BORDER;
 #endif // wxUniversal
 
     msflags &= ~WS_BORDER;
 #endif // wxUniversal
 
+    // all windows are created visible by default except popup ones (which are
+    // like the wxTopLevelWindows in this aspect)
     if ( style & wxPOPUP_WINDOW )
     {
     if ( style & wxPOPUP_WINDOW )
     {
-        // a popup window floats on top of everything
-        exstyle |= WS_EX_TOPMOST | WS_EX_TOOLWINDOW;
-
-        // it is also created hidden as other top level windows
         msflags &= ~WS_VISIBLE;
         m_isShown = FALSE;
     }
         msflags &= ~WS_VISIBLE;
         m_isShown = FALSE;
     }
+    else
+    {
+        msflags |= WS_VISIBLE;
+    }
 
     return MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle);
 }
 
     return MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle);
 }
@@ -458,6 +465,20 @@ void wxWindowMSW::SetFocus()
     }
 }
 
     }
 }
 
+void wxWindowMSW::SetFocusFromKbd()
+{
+    wxWindowBase::SetFocusFromKbd();
+
+    // when the focus is given to the control with DLGC_HASSETSEL style from
+    // keyboard its contents should be entirely selected: this is what
+    // ::IsDialogMessage() does and so we should do it as well to provide the
+    // same LNF as the native programs
+    if ( ::SendMessage(GetHwnd(), WM_GETDLGCODE, 0, 0) & DLGC_HASSETSEL )
+    {
+        ::SendMessage(GetHwnd(), EM_SETSEL, 0, -1);
+    }
+}
+
 // Get the window with the focus
 wxWindow *wxWindowBase::FindFocus()
 {
 // Get the window with the focus
 wxWindow *wxWindowBase::FindFocus()
 {
@@ -1978,12 +1999,21 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
                                 return TRUE;
                             }
                             else // no default button
                                 return TRUE;
                             }
                             else // no default button
-#endif // wxUSE_BUTTON
                             {
                             {
-                                // no special function for enter and don't even
-                                // let IsDialogMessage() have it: it seems to
-                                // do something really strange with it
-                                return FALSE;
+#endif // wxUSE_BUTTON
+                                // this is a quick and dirty test for a text
+                                // control
+                                if ( !(lDlgCode & DLGC_HASSETSEL) )
+                                {
+                                    // don't process Enter, the control might
+                                    // need it for itself and don't let
+                                    // ::IsDialogMessage() have it as it can
+                                    // eat the Enter events sometimes
+                                    return FALSE;
+                                }
+                                //else: treat Enter as TAB: pass to the next
+                                //      control as this is the best thing to do
+                                //      if the text doesn't handle Enter itself
                             }
                         }
                     }
                             }
                         }
                     }
@@ -2036,10 +2066,18 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
         }
 #endif // 1/0
 
         }
 #endif // 1/0
 
-        if ( ::IsDialogMessage(GetHwnd(), msg) )
+        // we handle VK_ESCAPE ourselves in wxDialog::OnCharHook() and we
+        // shouldn't let IsDialogMessage() get it as it _always_ eats the
+        // message even when there is no cancel button and when the message is
+        // needed by the control itself: in particular, it prevents the tree in
+        // place edit control from being closed with Escape in a dialog
+        if ( msg->message != WM_KEYDOWN || msg->wParam != VK_ESCAPE )
         {
         {
-            // IsDialogMessage() did something...
-            return TRUE;
+            if ( ::IsDialogMessage(GetHwnd(), msg) )
+            {
+                // IsDialogMessage() did something...
+                return TRUE;
+            }
         }
     }
 #endif // __WXUNIVERSAL__
         }
     }
 #endif // __WXUNIVERSAL__
@@ -2316,10 +2354,18 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
             break;
 
         case WM_CLOSE:
             break;
 
         case WM_CLOSE:
+#ifdef __WXUNIVERSAL__
+            // Universal uses its own wxFrame/wxDialog, so we don't receive
+            // close events unless we have this.
+            Close();
+            processed = TRUE;
+            rc.result = TRUE;
+#else
             // don't let the DefWindowProc() destroy our window - we'll do it
             // ourselves in ~wxWindow
             processed = TRUE;
             rc.result = TRUE;
             // don't let the DefWindowProc() destroy our window - we'll do it
             // ourselves in ~wxWindow
             processed = TRUE;
             rc.result = TRUE;
+#endif
             break;
 
         case WM_SHOWWINDOW:
             break;
 
         case WM_SHOWWINDOW:
@@ -2347,68 +2393,49 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
         case WM_MBUTTONDOWN:
         case WM_MBUTTONUP:
         case WM_MBUTTONDBLCLK:
         case WM_MBUTTONDOWN:
         case WM_MBUTTONUP:
         case WM_MBUTTONDBLCLK:
-         {
-                processed = FALSE;
+            {
 #ifdef __WXMICROWIN__
                 // MicroWindows seems to ignore the fact that a window is
                 // disabled. So catch mouse events and throw them away if
                 // necessary.
                 wxWindowMSW* win = this;
 #ifdef __WXMICROWIN__
                 // MicroWindows seems to ignore the fact that a window is
                 // disabled. So catch mouse events and throw them away if
                 // necessary.
                 wxWindowMSW* win = this;
-                while (win)
+                for ( ;; )
                 {
                     if (!win->IsEnabled())
                     {
                         processed = TRUE;
                         break;
                     }
                 {
                     if (!win->IsEnabled())
                     {
                         processed = TRUE;
                         break;
                     }
+
                     win = win->GetParent();
                     win = win->GetParent();
-                    if (win && win->IsTopLevel())
+                    if ( !win || win->IsTopLevel() )
                         break;
                 }
                         break;
                 }
-#endif // __WXMICROWIN__
+
                 if (!processed)
                 if (!processed)
+#endif // __WXMICROWIN__
                 {
                 {
-                    if (message == WM_LBUTTONDOWN && AcceptsFocus())
+                    // VZ: why do we need it here? DefWindowProc() is supposed
+                    //     to do this for us anyhow
+                    if ( message == WM_LBUTTONDOWN && AcceptsFocus() )
                         SetFocus();
                         SetFocus();
-                     processed = HandleMouseEvent(message,
-                                         GET_X_LPARAM(lParam),
-                                         GET_Y_LPARAM(lParam),
-                                                  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())
+                    int x = GET_X_LPARAM(lParam),
+                        y = GET_Y_LPARAM(lParam);
+
+                    // redirect the event to a static control if necessary
+                    if (this == GetCapture())
                     {
                     {
-                        processed = TRUE;
-                        break;
+                        processed = HandleMouseEvent(message, x, y, wParam);
+                    }
+                    else
+                    {
+                        wxWindowMSW *win = FindWindowForMouseEvent(this, &x, &y); //TW:REQ:Univ
+                        processed = win->HandleMouseEvent(message, x, y, wParam);
                     }
                     }
-                    win = win->GetParent();
-                    if (win && win->IsTopLevel())
-                        break;
                 }
                 }
-                break;
             }
             }
-#endif // __WXMICROWIN__
+            break;
 
 #ifdef MM_JOY1MOVE
         case MM_JOY1MOVE:
 
 #ifdef MM_JOY1MOVE
         case MM_JOY1MOVE:
@@ -2491,15 +2518,19 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
                 break;
             }
 
                 break;
             }
 
-            // we consider these message "not interesting" to OnChar
-            if ( wParam == VK_SHIFT || wParam == VK_CONTROL )
-            {
-                processed = TRUE;
-                break;
-            }
-
             switch ( wParam )
             {
             switch ( wParam )
             {
+                // we consider these message "not interesting" to OnChar, so
+                // just don't do anything more with them
+                case VK_SHIFT:
+                case VK_CONTROL:
+                case VK_MENU:
+                case VK_CAPITAL:
+                case VK_NUMLOCK:
+                case VK_SCROLL:
+                    processed = TRUE;
+                    break;
+
                 // avoid duplicate messages to OnChar for these ASCII keys:
                 // they will be translated by TranslateMessage() and received
                 // in WM_CHAR
                 // avoid duplicate messages to OnChar for these ASCII keys:
                 // they will be translated by TranslateMessage() and received
                 // in WM_CHAR
@@ -2544,23 +2575,9 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
                     break;
 #endif // VK_APPS
 
                     break;
 #endif // VK_APPS
 
-                case VK_LEFT:
-                case VK_RIGHT:
-                case VK_DOWN:
-                case VK_UP:
                 default:
                 default:
-                    if ( m_lastKeydownProcessed )
-                    {
-                        // The key was handled in the EVT_KEY_DOWN and handling
-                        // a key in an EVT_KEY_DOWN handler is meant, by
-                        // design, to prevent EVT_CHARs from happening
-                        m_lastKeydownProcessed = FALSE;
-                        processed = TRUE;
-                    }
-                    else // do generate a CHAR event
-                    {
-                        processed = HandleChar((WORD)wParam, lParam);
-                    }
+                    // do generate a CHAR event
+                    processed = HandleChar((WORD)wParam, lParam);
 
             }
             break;
 
             }
             break;
@@ -2586,7 +2603,18 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
 
         case WM_SYSCHAR:
         case WM_CHAR: // Always an ASCII character
 
         case WM_SYSCHAR:
         case WM_CHAR: // Always an ASCII character
-            processed = HandleChar((WORD)wParam, lParam, TRUE);
+            if ( m_lastKeydownProcessed )
+            {
+                // The key was handled in the EVT_KEY_DOWN and handling
+                // a key in an EVT_KEY_DOWN handler is meant, by
+                // design, to prevent EVT_CHARs from happening
+                m_lastKeydownProcessed = FALSE;
+                processed = TRUE;
+            }
+            else
+            {
+                processed = HandleChar((WORD)wParam, lParam, TRUE);
+            }
             break;
 
         case WM_HSCROLL:
             break;
 
         case WM_HSCROLL:
@@ -2646,6 +2674,10 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
             processed = HandlePaletteChanged((WXHWND) (HWND) wParam);
             break;
 
             processed = HandlePaletteChanged((WXHWND) (HWND) wParam);
             break;
 
+        case WM_CAPTURECHANGED:
+            processed = HandleCaptureChanged((WXHWND) (HWND) lParam);
+            break;
+
         case WM_QUERYNEWPALETTE:
             processed = HandleQueryNewPalette();
             break;
         case WM_QUERYNEWPALETTE:
             processed = HandleQueryNewPalette();
             break;
@@ -2814,6 +2846,9 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
                                            int& x, int& y,
                                            int& w, int& h) const
 {
                                            int& x, int& y,
                                            int& w, int& h) const
 {
+    static const int DEFAULT_Y = 200;
+    static const int DEFAULT_H = 250;
+
     bool nonDefault = FALSE;
 
     if ( pos.x == -1 )
     bool nonDefault = FALSE;
 
     if ( pos.x == -1 )
@@ -2825,8 +2860,11 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
     }
     else
     {
     }
     else
     {
+        // OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it
+        // neither because it is not handled as a special value by Windows then
+        // and so we have to choose some default value for it
         x = pos.x;
         x = pos.x;
-        y = pos.y == -1 ? CW_USEDEFAULT : pos.y;
+        y = pos.y == -1 ? DEFAULT_Y : pos.y;
 
         nonDefault = TRUE;
     }
 
         nonDefault = TRUE;
     }
@@ -2849,14 +2887,15 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
      */
     if ( size.x == -1 )
     {
      */
     if ( size.x == -1 )
     {
-        // as abobe, h is not used at all in this case anyhow
+        // as above, h is not used at all in this case anyhow
         w =
         h = CW_USEDEFAULT;
     }
     else
     {
         w =
         h = CW_USEDEFAULT;
     }
     else
     {
+        // and, again as above, we can't set the height to CW_USEDEFAULT here
         w = size.x;
         w = size.x;
-        h = size.y == -1 ? CW_USEDEFAULT : size.y;
+        h = size.y == -1 ? DEFAULT_H  : size.y;
 
         nonDefault = TRUE;
     }
 
         nonDefault = TRUE;
     }
@@ -2879,31 +2918,19 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
     wxWindow *parent = GetParent();
     bool isChild = (style & WS_CHILD) != 0;
     HWND hParent;
     wxWindow *parent = GetParent();
     bool isChild = (style & WS_CHILD) != 0;
     HWND hParent;
-    if ( GetWindowStyleFlag() & wxPOPUP_WINDOW )
+    if ( (isChild || HasFlag(wxPOPUP_WINDOW) || HasFlag(wxFRAME_TOOL_WINDOW)) )
     {
     {
-        // popup windows should have desktop as parent because they shouldn't
-        // be limited to the parents client area as child windows usually are
-        hParent = ::GetDesktopWindow();
+        // this is either a normal child window, a popup window or a top level
+        // window with wxFRAME_TOOL_WINDOW style (see below)
+        hParent = parent ? GetHwndOf(parent) : NULL;
     }
     }
-    else // !popup
+    else
     {
     {
-        if ( (isChild || HasFlag(wxFRAME_TOOL_WINDOW)) && parent )
-        {
-            // this is either a normal child window or a top level window with
-            // wxFRAME_TOOL_WINDOW style (see below)
-            hParent = GetHwndOf(parent);
-        }
-        else
-        {
-            // this is either a window for which no parent was specified (not
-            // much we can do then) or a frame without wxFRAME_TOOL_WINDOW
-            // style: we should use NULL parent HWND for it or it would be
-            // always on top of its parent which is not what we usually want
-            // (in fact, we only want it for frames with the special
-            // wxFRAME_TOOL_WINDOW as above)
-            hParent = NULL;
-        }
-
+        // this is a frame without wxFRAME_TOOL_WINDOW style: we should use
+        // NULL parent HWND for it or it would be always on top of its parent
+        // which is not what we usually want (in fact, we only want it for
+        // frames with the special wxFRAME_TOOL_WINDOW as above)
+        hParent = NULL;
     }
 
     // controlId is menu handle for the top level windows, so set it to 0
     }
 
     // controlId is menu handle for the top level windows, so set it to 0
@@ -3510,6 +3537,14 @@ bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange)
     return GetEventHandler()->ProcessEvent(event);
 }
 
     return GetEventHandler()->ProcessEvent(event);
 }
 
+bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture)
+{
+    wxMouseCaptureChangedEvent event(GetId(), wxFindWinFromHandle(hWndGainedCapture));
+    event.SetEventObject(this);
+
+    return GetEventHandler()->ProcessEvent(event);
+}
+
 bool wxWindowMSW::HandleQueryNewPalette()
 {
 
 bool wxWindowMSW::HandleQueryNewPalette()
 {
 
@@ -3775,9 +3810,13 @@ bool wxWindowMSW::HandleMove(int x, int y)
     return GetEventHandler()->ProcessEvent(event);
 }
 
     return GetEventHandler()->ProcessEvent(event);
 }
 
-bool wxWindowMSW::HandleSize(int w, int h, WXUINT WXUNUSED(flag))
+bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h),
+                             WXUINT WXUNUSED(flag))
 {
 {
-    wxSizeEvent event(wxSize(w, h), m_windowId);
+    // don't use w and h parameters as they specify the client size while
+    // according to the docs EVT_SIZE handler is supposed to receive the total
+    // size
+    wxSizeEvent event(GetSize(), m_windowId);
     event.SetEventObject(this);
 
     return GetEventHandler()->ProcessEvent(event);
     event.SetEventObject(this);
 
     return GetEventHandler()->ProcessEvent(event);
@@ -3934,6 +3973,64 @@ void wxWindowMSW::InitMouseEvent(wxMouseEvent& event,
 #endif // wxUSE_MOUSEEVENT_HACK
 }
 
 #endif // wxUSE_MOUSEEVENT_HACK
 }
 
+// Windows doesn't send the mouse events to the static controls (which are
+// transparent in the sense that their WM_NCHITTEST handler returns
+// HTTRANSPARENT) at all but we want all controls to receive the mouse events
+// and so we manually check if we don't have a child window under mouse and if
+// we do, send the event to it instead of the window Windows had sent WM_XXX
+// to.
+//
+// Notice that this is not done for the mouse move events because this could
+// (would?) be too slow, but only for clicks which means that the static texts
+// still don't get move, enter nor leave events.
+static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y) //TW:REQ:Univ
+{
+    wxCHECK_MSG( x && y, win, _T("NULL pointer in FindWindowForMouseEvent") );
+
+    // first try to find a non transparent child: this allows us to send events
+    // to a static text which is inside a static box, for example
+    POINT pt = { *x, *y };
+    HWND hwnd = GetHwndOf(win),
+         hwndUnderMouse;
+
+#ifdef __WIN32__
+    hwndUnderMouse = ::ChildWindowFromPointEx
+                       (
+                        hwnd,
+                        pt,
+                        CWP_SKIPINVISIBLE   |
+                        CWP_SKIPDISABLED    |
+                        CWP_SKIPTRANSPARENT
+                       );
+
+    if ( !hwndUnderMouse || hwndUnderMouse == hwnd )
+#endif // __WIN32__
+    {
+        // now try any child window at all
+        hwndUnderMouse = ::ChildWindowFromPoint(hwnd, pt);
+    }
+
+    // check that we have a child window which is susceptible to receive mouse
+    // events: for this it must be shown and enabled
+    if ( hwndUnderMouse &&
+            hwndUnderMouse != hwnd &&
+                ::IsWindowVisible(hwndUnderMouse) &&
+                    ::IsWindowEnabled(hwndUnderMouse) )
+    {
+        wxWindow *winUnderMouse = wxFindWinFromHandle((WXHWND)hwndUnderMouse);
+        if ( winUnderMouse )
+        {
+            // translate the mouse coords to the other window coords
+            win->ClientToScreen(x, y);
+            winUnderMouse->ScreenToClient(x, y);
+
+            win = winUnderMouse;
+        }
+    }
+
+    return win;
+}
+
 bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags)
 {
     // the mouse events take consecutive IDs from WM_MOUSEFIRST to
 bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags)
 {
     // the mouse events take consecutive IDs from WM_MOUSEFIRST to
@@ -4266,7 +4363,7 @@ bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags)
 // ---------------------------------------------------------------------------
 
 bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam,
 // ---------------------------------------------------------------------------
 
 bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam,
-                           WXWORD pos, WXHWND control)
+                              WXWORD pos, WXHWND control)
 {
     if ( control )
     {
 {
     if ( control )
     {