]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/window.cpp
don't include winsock.h directly, this doesn't work (patch 565655)
[wxWidgets.git] / src / msw / window.cpp
index b1a3914509a9f4f981648c93339a29151a20bd77..e762e88e84693d3b6405a720b7aa54cc09b0b300 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);
 
+// 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)
 {
@@ -405,25 +408,29 @@ bool wxWindowMSW::Create(wxWindow *parent,
 
     parent->AddChild(this);
 
-    // note that all windows are created visible by default
     WXDWORD exstyle;
-    DWORD msflags = WS_VISIBLE | MSWGetCreateWindowFlags(&exstyle);
+    DWORD msflags = MSWGetCreateWindowFlags(&exstyle);
 
 #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
 
+    // all windows are created visible by default except popup ones (which are
+    // like the wxTopLevelWindows in this aspect)
     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;
     }
+    else
+    {
+        msflags |= WS_VISIBLE;
+    }
 
     return MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle);
 }
@@ -1156,6 +1163,17 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
                 *exstyle |= WS_EX_DLGMODALFRAME;
                 break;
         }
+
+        // to make the dialog navigation work with the nested panels we must
+        // use this style but, unfortunately, it hangs NT4 in some situations
+        // so we shouldn't use it -- even though it means that keyboard accels
+        // in, e.g. wxWizard, don't work
+#if 0
+        if ( flags & wxTAB_TRAVERSAL )
+        {
+            *exstyle |= WS_EX_CONTROLPARENT;
+        }
+#endif // 0
     }
 
     return style;
@@ -1992,12 +2010,21 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
                                 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
                             }
                         }
                     }
@@ -2338,10 +2365,18 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
             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;
+#endif
             break;
 
         case WM_SHOWWINDOW:
@@ -2369,68 +2404,49 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
         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;
-                while (win)
+                for ( ;; )
                 {
                     if (!win->IsEnabled())
                     {
                         processed = TRUE;
                         break;
                     }
+
                     win = win->GetParent();
-                    if (win && win->IsTopLevel())
+                    if ( !win || win->IsTopLevel() )
                         break;
                 }
-#endif // __WXMICROWIN__
+
                 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();
-                     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:
@@ -2841,6 +2857,9 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
                                            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 )
@@ -2852,8 +2871,11 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
     }
     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;
-        y = pos.y == -1 ? CW_USEDEFAULT : pos.y;
+        y = pos.y == -1 ? DEFAULT_Y : pos.y;
 
         nonDefault = TRUE;
     }
@@ -2876,14 +2898,15 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
      */
     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
     {
+        // and, again as above, we can't set the height to CW_USEDEFAULT here
         w = size.x;
-        h = size.y == -1 ? CW_USEDEFAULT : size.y;
+        h = size.y == -1 ? DEFAULT_H  : size.y;
 
         nonDefault = TRUE;
     }
@@ -2891,6 +2914,11 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
     return nonDefault;
 }
 
+WXHWND wxWindowMSW::MSWGetParent() const
+{
+    return m_parent ? m_parent->GetHWND() : NULL;
+}
+
 bool wxWindowMSW::MSWCreate(const wxChar *wclass,
                             const wxChar *title,
                             const wxPoint& pos,
@@ -2902,41 +2930,10 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
     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 )
-    {
-        // 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();
-    }
-    else // !popup
-    {
-        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;
-        }
-
-    }
-
     // 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 )
+    if ( style & WS_CHILD )
     {
         controlId = GetId();
 
@@ -2963,17 +2960,17 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
     wxWindowCreationHook hook(this);
 
     m_hWnd = (WXHWND)::CreateWindowEx
-             (
-                extendedStyle,
-                className,
-                title ? title : wxT(""),
-                style,
-                x, y, w, h,
-                hParent,
-                (HMENU)controlId,
-                wxGetInstance(),
-                NULL                        // no extra data
-             );
+                       (
+                            extendedStyle,
+                            className,
+                            title ? title : wxT(""),
+                            style,
+                            x, y, w, h,
+                            (HWND)MSWGetParent(),
+                            (HMENU)controlId,
+                            wxGetInstance(),
+                            NULL                        // no extra data
+                       );
 
     if ( !m_hWnd )
     {
@@ -3965,6 +3962,7 @@ void wxWindowMSW::InitMouseEvent(wxMouseEvent& event,
 
     event.SetTimestamp(s_currentMsg.time);
     event.m_eventObject = this;
+    event.SetId(GetId());
 
 #if wxUSE_MOUSEEVENT_HACK
     m_lastMouseX = x;
@@ -3973,6 +3971,64 @@ void wxWindowMSW::InitMouseEvent(wxMouseEvent& event,
 #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