]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/window.cpp
1. wxShell fixes: now really uses shell (it wasn't different from wxExecute!)
[wxWidgets.git] / src / msw / window.cpp
index fea94bda8b0118f8c80e1e250bc670bc1171422c..3f8c4085f70dc197b4611404d513ec03b8b82f91 100644 (file)
@@ -79,7 +79,7 @@
 
 #include <string.h>
 
-#if !defined(__GNUWIN32__)|| defined(wxUSE_NORLANDER_HEADERS)
+#ifndef __GNUWIN32_OLD__
     #include <shellapi.h>
     #include <mmsystem.h>
 #endif
     #include <windowsx.h>
 #endif
 
-#if ( defined(__WIN95__) && !defined(__GNUWIN32__)) || defined(__TWIN32__ ) || defined(wxUSE_NORLANDER_HEADERS)
-    #include <commctrl.h>
-#endif
-
-#ifndef __TWIN32__
-    #ifdef __GNUWIN32__
-        #ifndef wxUSE_NORLANDER_HEADERS
-            #include "wx/msw/gnuwin32/extra.h"
-        #endif
+#if !defined(__GNUWIN32_OLD__) && !defined(__TWIN32__)
+    #ifdef __WIN95__
+        #include <commctrl.h>
+    #endif
+#else // broken compiler
+    #ifndef __TWIN32__
+        #include "wx/msw/gnuwin32/extra.h"
     #endif
 #endif
 
@@ -127,6 +125,10 @@ void wxRemoveHandleAssociation(wxWindow *win);
 void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win);
 wxWindow *wxFindWinFromHandle(WXHWND hWnd);
 
+// this magical function is used to translate VK_APPS key presses to right
+// mouse clicks
+static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flags);
+
 // ---------------------------------------------------------------------------
 // event tables
 // ---------------------------------------------------------------------------
@@ -268,8 +270,12 @@ wxWindow::~wxWindow()
 
     if ( m_hWnd )
     {
-        if ( !::DestroyWindow(GetHwnd()) )
-            wxLogLastError("DestroyWindow");
+        // VZ: test temp removed to understand what really happens here
+        //if (::IsWindow(GetHwnd()))
+        {
+            if ( !::DestroyWindow(GetHwnd()) )
+                wxLogLastError("DestroyWindow");
+        }
 
         // remove hWnd <-> wxWindow association
         wxRemoveHandleAssociation(this);
@@ -471,7 +477,7 @@ bool wxWindow::SetCursor(const wxCursor& cursor)
     ::GetWindowRect(hWnd, &rect);
 
     if ( ::PtInRect(&rect, point) && !wxIsBusy() )
-        ::SetCursor((HCURSOR)m_cursor.GetHCURSOR());
+        ::SetCursor(GetHcursorOf(m_cursor));
 
     return TRUE;
 }
@@ -964,9 +970,9 @@ void wxWindow::OnIdle(wxIdleEvent& event)
             // by the time the OnIdle function is called, so 'state' may be
             // meaningless.
             int state = 0;
-            if ( ::GetKeyState(VK_SHIFT) != 0 )
+            if ( wxIsShiftDown() )
                 state |= MK_SHIFT;
-            if ( ::GetKeyState(VK_CONTROL) != 0 )
+            if ( wxIsCtrlDown() )
                 state |= MK_CONTROL;
 
             wxMouseEvent event(wxEVT_LEAVE_WINDOW);
@@ -1473,8 +1479,8 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg)
 
         if ( bProcess )
         {
-            bool bCtrlDown = (::GetKeyState(VK_CONTROL) & 0x100) != 0;
-            bool bShiftDown = (::GetKeyState(VK_SHIFT) & 0x100) != 0;
+            bool bCtrlDown = wxIsCtrlDown();
+            bool bShiftDown = wxIsShiftDown();
 
             // WM_GETDLGCODE: ask the control if it wants the key for itself,
             // don't process it if it's the case (except for Ctrl-Tab/Enter
@@ -1589,8 +1595,7 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg)
             // don't process system keys here
             if ( !(HIWORD(msg->lParam) & KF_ALTDOWN) )
             {
-                if ( (msg->wParam == VK_TAB) &&
-                     (::GetKeyState(VK_CONTROL) & 0x100) != 0 )
+                if ( (msg->wParam == VK_TAB) && wxIsCtrlDown() )
                 {
                     // find the first notebook parent and change its page
                     wxWindow *win = this;
@@ -1603,7 +1608,7 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg)
 
                     if ( nbook )
                     {
-                        bool forward = !(::GetKeyState(VK_SHIFT) & 0x100);
+                        bool forward = !wxIsShiftDown();
 
                         nbook->AdvanceSelection(forward);
                     }
@@ -1953,6 +1958,7 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
             //else: get the dlg code from the DefWindowProc()
             break;
 
+        case WM_SYSKEYDOWN:
         case WM_KEYDOWN:
             // If this has been processed by an event handler,
             // return 0 now (we've handled it).
@@ -1994,20 +2000,11 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
                 // click because both usually pop up a context menu
                 case VK_APPS:
                     {
-                        // construct the key mask
-                        WPARAM fwKeys = MK_RBUTTON;
-                        if ( (::GetKeyState(VK_CONTROL) & 0x100) != 0 )
-                            fwKeys |= MK_CONTROL;
-                        if ( (::GetKeyState(VK_SHIFT) & 0x100) != 0 )
-                            fwKeys |= MK_SHIFT;
-
-                        // simulate right mouse button click
-                        DWORD dwPos = ::GetMessagePos();
-                        int x = GET_X_LPARAM(dwPos),
-                            y = GET_Y_LPARAM(dwPos);
-
-                        ScreenToClient(&x, &y);
-                        processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, fwKeys);
+                        WPARAM flags;
+                        int x, y;
+
+                        TranslateKbdEventToMouse(this, &x, &y, &flags);
+                        processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags);
                     }
                     break;
 #endif // VK_APPS
@@ -2021,10 +2018,26 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
             }
             break;
 
+        case WM_SYSKEYUP:
         case WM_KEYUP:
-            processed = HandleKeyUp((WORD) wParam, lParam);
+#ifdef VK_APPS
+            // special case of VK_APPS: treat it the same as right mouse button
+            if ( wParam == VK_APPS )
+            {
+                WPARAM flags;
+                int x, y;
+
+                TranslateKbdEventToMouse(this, &x, &y, &flags);
+                processed = HandleMouseEvent(WM_RBUTTONUP, x, y, flags);
+            }
+            else
+#endif // VK_APPS
+            {
+                processed = HandleKeyUp((WORD) wParam, lParam);
+            }
             break;
 
+        case WM_SYSCHAR:
         case WM_CHAR: // Always an ASCII character
             processed = HandleChar((WORD)wParam, lParam, TRUE);
             break;
@@ -2283,12 +2296,16 @@ bool wxWindow::MSWCreate(int id,
     if ( width > -1 ) width1 = width;
     if ( height > -1 ) height1 = height;
 
+    // Unfortunately this won't work in WIN16. Unless perhaps
+    // we define WS_EX_CONTROLPARENT ourselves?
+#ifndef __WIN16__
     // if we have wxTAB_TRAVERSAL style, we want WS_EX_CONTROLPARENT or
     // IsDialogMessage() won't work for us
     if ( GetWindowStyleFlag() & wxTAB_TRAVERSAL )
     {
         extendedStyle |= WS_EX_CONTROLPARENT;
     }
+#endif
 
     HWND hParent = (HWND)NULL;
     if ( parent )
@@ -2644,54 +2661,46 @@ bool wxWindow::HandleSetCursor(WXHWND hWnd,
                                short nHitTest,
                                int WXUNUSED(mouseMsg))
 {
-    // don't set cursor for other windows, only for this one: this prevents
-    // children of this window from getting the same cursor as the parent has
-    // (don't forget that this message is propagated by default up the window
-    // parent-child hierarchy)
-    if ( GetHWND() == hWnd )
-    {
-        // don't set cursor when the mouse is not in the client part
-        if ( nHitTest == HTCLIENT || nHitTest == HTERROR )
-        {
-            HCURSOR hcursor = 0;
-            if ( wxIsBusy() )
-            {
-                // from msw\utils.cpp
-                extern HCURSOR gs_wxBusyCursor;
-
-                hcursor = gs_wxBusyCursor;
-            }
-            else
-            {
-                wxCursor *cursor = NULL;
-
-                if ( m_cursor.Ok() )
-                {
-                    cursor = &m_cursor;
-                }
-                else
-                {
-                    // from msw\data.cpp
-                    extern wxCursor *g_globalCursor;
-
-                    if ( g_globalCursor && g_globalCursor->Ok() )
-                        cursor = g_globalCursor;
-                }
+    // the logic is as follows:
+    //  1. if we have the cursor set it unless wxIsBusy()
+    //  2. if we're a top level window, set some cursor anyhow
+    //  3. if wxIsBusy(), set the busy cursor, otherwise the global one
 
-                if ( cursor )
-                    hcursor = (HCURSOR)cursor->GetHCURSOR();
-            }
+    HCURSOR hcursor = 0;
+    bool isBusy = wxIsBusy();
+    if ( m_cursor.Ok() )
+    {
+        hcursor = GetHcursorOf(m_cursor);
+    }
 
-            if ( hcursor )
+    if ( !GetParent() )
+    {
+        if ( isBusy )
+        {
+            hcursor = wxGetCurrentBusyCursor();
+        }
+        else if ( !hcursor )
+        {
+            const wxCursor *cursor = wxGetGlobalCursor();
+            if ( cursor && cursor->Ok() )
             {
-                ::SetCursor(hcursor);
-
-                return TRUE;
+                hcursor = GetHcursorOf(*cursor);
             }
         }
     }
 
-    return FALSE;
+    if ( hcursor )
+    {
+        ::SetCursor(hcursor);
+
+        // cursor set, stop here
+        return TRUE;
+    }
+    else
+    {
+        // pass up the window chain
+        return FALSE;
+    }
 }
 
 // ---------------------------------------------------------------------------
@@ -3000,13 +3009,14 @@ bool wxWindow::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
         return popupMenu->MSWCommand(cmd, id);
     }
 
-    wxWindow *win;
+    wxWindow *win = (wxWindow*) NULL;
     if ( cmd == 0 || cmd == 1 ) // menu or accel - use id
     {
         // must cast to a signed type before comparing with other ids!
         win = FindItem((signed short)id);
     }
-    else
+
+    if (!win && control)
     {
         // find it from HWND - this works even with the broken programs using
         // the same ids for different controls
@@ -3014,17 +3024,25 @@ bool wxWindow::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
     }
 
     if ( win )
+    {
         return win->MSWCommand(cmd, id);
-    else
+    }
+
+    // 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
+    if ( !control )
     {
-        // If no child window, it may be an accelerator, e.g. for
-        // a popup menu command.
+        // If no child window, it may be an accelerator, e.g. for a popup menu
+        // command
 
         wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
         event.SetEventObject(this);
         event.SetId(id);
         event.SetInt(id);
-        return ProcessEvent(event);
+
+        return GetEventHandler()->ProcessEvent(event);
     }
 
     return FALSE;
@@ -3130,12 +3148,43 @@ bool wxWindow::HandleMouseMove(int x, int y, WXUINT flags)
 // keyboard handling
 // ---------------------------------------------------------------------------
 
+// create the key event of the given type for the given key - used by
+// HandleChar and HandleKeyDown/Up
+wxKeyEvent wxWindow::CreateKeyEvent(wxEventType evType,
+                                    int id,
+                                    WXLPARAM lParam) const
+{
+    wxKeyEvent event(evType);
+    event.SetId(GetId());
+    event.m_shiftDown = wxIsShiftDown();
+    event.m_controlDown = wxIsCtrlDown();
+    event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN;
+
+    event.m_eventObject = (wxWindow *)this; // const_cast
+    event.m_keyCode = id;
+    event.SetTimestamp(s_currentMsg.time);
+
+    // translate the position to client coords
+    POINT pt;
+    GetCursorPos(&pt);
+    RECT rect;
+    GetWindowRect(GetHwnd(),&rect);
+    pt.x -= rect.left;
+    pt.y -= rect.top;
+
+    event.m_x = pt.x;
+    event.m_y = pt.y;
+
+    return event;
+}
+
 // isASCII is TRUE only when we're called from WM_CHAR handler and not from
 // WM_KEYDOWN one
 bool wxWindow::HandleChar(WXWORD wParam, WXLPARAM lParam, bool isASCII)
 {
+    bool ctrlDown = FALSE;
+
     int id;
-    bool tempControlDown = FALSE;
     if ( isASCII )
     {
         // If 1 -> 26, translate to CTRL plus a letter.
@@ -3144,142 +3193,86 @@ bool wxWindow::HandleChar(WXWORD wParam, WXLPARAM lParam, bool isASCII)
         {
             switch (id)
             {
-            case 13:
-                {
+                case 13:
                     id = WXK_RETURN;
                     break;
-                }
-            case 8:
-                {
+
+                case 8:
                     id = WXK_BACK;
                     break;
-                }
-            case 9:
-                {
+
+                case 9:
                     id = WXK_TAB;
                     break;
-                }
-            default:
-                {
-                    tempControlDown = TRUE;
+
+                default:
+                    ctrlDown = TRUE;
                     id = id + 96;
-                }
             }
         }
     }
-    else if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) {
+    else if ( (id = wxCharCodeMSWToWX(wParam)) == 0 )
+    {
         // it's ASCII and will be processed here only when called from
-        // WM_CHAR (i.e. when isASCII = TRUE)
+        // WM_CHAR (i.e. when isASCII = TRUE), don't process it now
         id = -1;
     }
 
     if ( id != -1 )
     {
-        wxKeyEvent event(wxEVT_CHAR);
-        event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE);
-        event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE);
-        if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN )
-            event.m_altDown = TRUE;
-
-        event.m_eventObject = this;
-        event.m_keyCode = id;
-        event.SetTimestamp(s_currentMsg.time);
-
-        POINT pt;
-        GetCursorPos(&pt);
-        RECT rect;
-        GetWindowRect(GetHwnd(),&rect);
-        pt.x -= rect.left;
-        pt.y -= rect.top;
-
-        event.m_x = pt.x; event.m_y = pt.y;
+        wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam));
+        if ( ctrlDown )
+        {
+            event.m_controlDown = TRUE;
+        }
 
         if ( GetEventHandler()->ProcessEvent(event) )
             return TRUE;
-        else
-            return FALSE;
     }
-    else
-        return FALSE;
+
+    return FALSE;
 }
 
 bool wxWindow::HandleKeyDown(WXWORD wParam, WXLPARAM lParam)
 {
-    int id;
+    int id = wxCharCodeMSWToWX(wParam);
 
-    if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) {
+    if ( !id )
+    {
+        // normal ASCII char
         id = wParam;
     }
 
-    if ( id != -1 )
+    if ( id != -1 ) // VZ: does this ever happen (FIXME)?
     {
-        wxKeyEvent event(wxEVT_KEY_DOWN);
-        event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE);
-        event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE);
-        if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN )
-            event.m_altDown = TRUE;
-
-        event.m_eventObject = this;
-        event.m_keyCode = id;
-        event.SetTimestamp(s_currentMsg.time);
-
-        POINT pt;
-        GetCursorPos(&pt);
-        RECT rect;
-        GetWindowRect(GetHwnd(),&rect);
-        pt.x -= rect.left;
-        pt.y -= rect.top;
-
-        event.m_x = pt.x; event.m_y = pt.y;
-
+        wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam));
         if ( GetEventHandler()->ProcessEvent(event) )
         {
             return TRUE;
         }
-        else return FALSE;
-    }
-    else
-    {
-        return FALSE;
     }
+
+    return FALSE;
 }
 
 bool wxWindow::HandleKeyUp(WXWORD wParam, WXLPARAM lParam)
 {
-    int id;
+    int id = wxCharCodeMSWToWX(wParam);
 
-    if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) {
+    if ( !id )
+    {
+        // normal ASCII char
         id = wParam;
     }
 
-    if ( id != -1 )
+    if ( id != -1 ) // VZ: does this ever happen (FIXME)?
     {
-        wxKeyEvent event(wxEVT_KEY_UP);
-        event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE);
-        event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE);
-        if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN )
-            event.m_altDown = TRUE;
-
-        event.m_eventObject = this;
-        event.m_keyCode = id;
-        event.SetTimestamp(s_currentMsg.time);
-
-        POINT pt;
-        GetCursorPos(&pt);
-        RECT rect;
-        GetWindowRect(GetHwnd(),&rect);
-        pt.x -= rect.left;
-        pt.y -= rect.top;
-
-        event.m_x = pt.x; event.m_y = pt.y;
-
+        wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam));
         if ( GetEventHandler()->ProcessEvent(event) )
             return TRUE;
-        else
-            return FALSE;
     }
-    else
-        return FALSE;
+
+    return FALSE;
 }
 
 // ---------------------------------------------------------------------------
@@ -3412,8 +3405,8 @@ bool wxWindow::MSWOnScroll(int orientation, WXWORD wParam,
         break;
 
     case SB_THUMBPOSITION:
-        event.m_isScrolling = FALSE;
-        /* fall-through */
+        event.m_eventType = wxEVT_SCROLLWIN_THUMBRELEASE;
+        break;
 
     case SB_THUMBTRACK:
         event.m_eventType = wxEVT_SCROLLWIN_THUMBTRACK;
@@ -3641,6 +3634,8 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd)
         win = wxFindWinFromHandle((WXHWND)hwnd);
         if ( !win )
         {
+            // the radiobox pointer is stored in GWL_USERDATA only under Win32
+#ifdef __WIN32__
             // native radiobuttons return DLGC_RADIOBUTTON here and for any
             // wxWindow class which overrides WM_GETDLGCODE processing to
             // do it as well, win would be already non NULL
@@ -3650,6 +3645,7 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd)
                 win = (wxWindow *)::GetWindowLong(hwnd, GWL_USERDATA);
             }
             else
+#endif // Win32
             {
                 // hwnd is not a wxWindow, try its parent next below
                 hwnd = ::GetParent(hwnd);
@@ -3694,7 +3690,7 @@ void wxSetKeyboardHook(bool doIt)
         UnhookWindowsHookEx(wxTheKeyboardHook);
         // avoids mingw warning about statement with no effect (FreeProcInstance
         // doesn't do anything under Win32)
-#ifndef __GNUWIN32__
+#ifndef __GNUC__
         FreeProcInstance(wxTheKeyboardHookProc);
 #endif
     }
@@ -3706,8 +3702,8 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
     DWORD hiWord = HIWORD(lParam);
     if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) )
     {
-        int id;
-        if ( (id = wxCharCodeMSWToWX(wParam)) != 0 )
+        int id = wxCharCodeMSWToWX(wParam);
+        if ( id != 0 )
         {
             wxKeyEvent event(wxEVT_CHAR_HOOK);
             if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN )
@@ -3715,25 +3711,31 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
 
             event.m_eventObject = NULL;
             event.m_keyCode = id;
-            /* begin Albert's fix for control and shift key 26.5 */
-            event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE);
-            event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE);
-            /* end Albert's fix for control and shift key 26.5 */
+            event.m_shiftDown = wxIsShiftDown();
+            event.m_controlDown = wxIsCtrlDown();
             event.SetTimestamp(s_currentMsg.time);
 
             wxWindow *win = wxGetActiveWindow();
+            wxEvtHandler *handler;
             if ( win )
             {
-                if ( win->GetEventHandler()->ProcessEvent(event) )
-                    return 1;
+                handler = win->GetEventHandler();
+                event.SetId(win->GetId());
             }
             else
             {
-                if ( wxTheApp && wxTheApp->ProcessEvent(event) )
-                    return 1;
+                handler = wxTheApp;
+                event.SetId(-1);
+            }
+
+            if ( handler && handler->ProcessEvent(event) )
+            {
+                // processed
+                return 1;
             }
         }
     }
+
     return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam);
 }
 
@@ -4155,3 +4157,22 @@ const char *wxGetMessageName(int message)
     }
 }
 #endif //__WXDEBUG__
+
+static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flags)
+{
+    // construct the key mask
+    WPARAM& fwKeys = *flags;
+
+    fwKeys = MK_RBUTTON;
+    if ( wxIsCtrlDown() )
+        fwKeys |= MK_CONTROL;
+    if ( wxIsShiftDown() )
+        fwKeys |= MK_SHIFT;
+
+    // simulate right mouse button click
+    DWORD dwPos = ::GetMessagePos();
+    *x = GET_X_LPARAM(dwPos);
+    *y = GET_Y_LPARAM(dwPos);
+
+    win->ScreenToClient(x, y);
+}