Changeset 48446 in webkit


Ignore:
Timestamp:
Sep 16, 2009 4:25:58 PM (15 years ago)
Author:
andersca@apple.com
Message:

<rdar://problem/7155710>
HTML selects on windows cause containing window to become inactive when opened

Reviewed by Adam Roben.

Redo the way we handle events when a popup menu is shown, based on
http://blogs.msdn.com/oldnewthing/archive/2004/08/20/217684.aspx

Since a non-active window can't capture the mouse, we use the owning window
(the WebView) as the capture window. We then run a recursive message pump that
forwards all mouse and keyboard events to the popup menu.

  • platform/PopupMenu.h:
  • platform/win/PopupMenuWin.cpp:

(WebCore::PopupMenu::PopupMenu):
(WebCore::PopupMenu::show):
(WebCore::PopupMenu::hide):
(WebCore::PopupMenu::wndProc):

Location:
trunk/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r48443 r48446  
     12009-09-16  Anders Carlsson  <andersca@apple.com>
     2
     3        Reviewed by Adam Roben.
     4
     5        <rdar://problem/7155710>
     6        HTML selects on windows cause containing window to become inactive when opened
     7       
     8        Redo the way we handle events when a popup menu is shown, based on
     9        http://blogs.msdn.com/oldnewthing/archive/2004/08/20/217684.aspx
     10       
     11        Since a non-active window can't capture the mouse, we use the owning window
     12        (the WebView) as the capture window. We then run a recursive message pump that
     13        forwards all mouse and keyboard events to the popup menu.
     14       
     15        * platform/PopupMenu.h:
     16        * platform/win/PopupMenuWin.cpp:
     17        (WebCore::PopupMenu::PopupMenu):
     18        (WebCore::PopupMenu::show):
     19        (WebCore::PopupMenu::hide):
     20        (WebCore::PopupMenu::wndProc):
     21
    1222009-09-16  Dan Bernstein  <mitz@apple.com>
    223
  • trunk/WebCore/platform/PopupMenu.h

    r48375 r48446  
    173173    int m_focusedIndex;
    174174    bool m_scrollbarCapturingMouse;
     175    bool m_showPopup;
    175176#elif PLATFORM(GTK)
    176177    IntPoint m_menuPosition;
  • trunk/WebCore/platform/win/PopupMenuWin.cpp

    r48396 r48446  
    6262static LPCTSTR kPopupWindowClassName = _T("PopupWindowClass");
    6363
     64// This is used from within our custom message pump when we want to send a
     65// WM_CHAR message to the web view and not have our message stolen and sent to
     66// the popup window.
     67static const UINT WM_HOST_WINDOW_CHAR = WM_USER;
     68
    6469// FIXME: Remove this as soon as practical.
    6570static inline bool isASCIIPrintable(unsigned c)
     
    8085    , m_focusedIndex(0)
    8186    , m_scrollbarCapturingMouse(false)
     87    , m_showPopup(false)
    8288{
    8389}
     
    126132        if (!m_popup)
    127133            return;
     134    } else {
     135        // We need to reposition the popup window.
     136        ::MoveWindow(m_popup, m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), false);
    128137    }
    129138
     
    143152            DWORD slideDirection = (m_windowRect.y() < viewRect.top + view->contentsToWindow(r.location()).y()) ? AW_VER_NEGATIVE : AW_VER_POSITIVE;
    144153
    145             ::AnimateWindow(m_popup, defaultAnimationDuration, AW_SLIDE | slideDirection | AW_ACTIVATE);
     154            ::AnimateWindow(m_popup, defaultAnimationDuration, AW_SLIDE | slideDirection);
    146155        }
    147156    } else
    148157#endif
    149         ::ShowWindow(m_popup, SW_SHOWNORMAL);
    150     ::SetCapture(m_popup);
     158        ::ShowWindow(m_popup, SW_SHOWNOACTIVATE);
    151159
    152160    if (client()) {
     
    155163            setFocusedIndex(index);
    156164    }
     165
     166    m_showPopup = true;
     167
     168    ::SetCapture(hostWindow);
     169
     170    MSG msg;
     171    HWND activeWindow;
     172
     173    while (::GetMessage(&msg, 0, 0, 0)) {
     174        switch (msg.message) {
     175            case WM_HOST_WINDOW_CHAR:
     176                if (msg.hwnd == m_popup) {
     177                    // This message should be sent to the host window as a WM_CHAR.
     178                    msg.hwnd = hostWindow;
     179                    msg.message = WM_CHAR;
     180                }
     181                break;
     182
     183            // Steal mouse messages.
     184            case WM_NCMOUSEMOVE:
     185            case WM_NCLBUTTONDOWN:
     186            case WM_NCLBUTTONUP:
     187            case WM_NCLBUTTONDBLCLK:
     188            case WM_NCRBUTTONDOWN:
     189            case WM_NCRBUTTONUP:
     190            case WM_NCRBUTTONDBLCLK:
     191            case WM_NCMBUTTONDOWN:
     192            case WM_NCMBUTTONUP:
     193            case WM_NCMBUTTONDBLCLK:
     194            case WM_MOUSEWHEEL:
     195                msg.hwnd = m_popup;
     196                break;
     197
     198            // These mouse messages use client coordinates so we need to convert them.
     199            case WM_MOUSEMOVE:
     200            case WM_LBUTTONDOWN:
     201            case WM_LBUTTONUP:
     202            case WM_LBUTTONDBLCLK:
     203            case WM_RBUTTONDOWN:
     204            case WM_RBUTTONUP:
     205            case WM_RBUTTONDBLCLK:
     206            case WM_MBUTTONDOWN:
     207            case WM_MBUTTONUP:
     208            case WM_MBUTTONDBLCLK: {
     209                POINT pt;
     210                pt.x = (short)LOWORD(msg.lParam);
     211                pt.y = (short)HIWORD(msg.lParam);
     212                ::MapWindowPoints(msg.hwnd, m_popup, &pt, 1);
     213                msg.lParam = MAKELPARAM(pt.x, pt.y);
     214                msg.hwnd = m_popup;
     215                break;
     216            }
     217
     218            // Steal all keyboard messages.
     219            case WM_KEYDOWN:
     220            case WM_KEYUP:
     221            case WM_CHAR:
     222            case WM_DEADCHAR:
     223            case WM_SYSKEYUP:
     224            case WM_SYSCHAR:
     225            case WM_SYSDEADCHAR:
     226                msg.hwnd = m_popup;
     227                break;
     228        }
     229
     230        ::TranslateMessage(&msg);
     231        ::DispatchMessage(&msg);
     232
     233        if (!m_showPopup)
     234            break;
     235        activeWindow = ::GetActiveWindow();
     236        if (activeWindow != hostWindow && !::IsChild(activeWindow, hostWindow))
     237            break;
     238        if (::GetCapture() != hostWindow)
     239            break;
     240    }
     241
     242    if (::GetCapture() == hostWindow)
     243        ::ReleaseCapture();
     244
     245    // We're done, hide the popup if necessary.
     246    hide();
    157247}
    158248
    159249void PopupMenu::hide()
    160250{
     251    if (!m_showPopup)
     252        return;
     253
     254    m_showPopup = false;
     255
    161256    ::ShowWindow(m_popup, SW_HIDE);
    162257
    163258    if (client())
    164259        client()->popupDidHide();
     260
     261    // Post a WM_NULL message to wake up the message pump if necessary.
     262    ::PostMessage(m_popup, WM_NULL, 0, 0);
    165263}
    166264
     
    661759
    662760    switch (message) {
     761        case WM_MOUSEACTIVATE:
     762            return MA_NOACTIVATE;
     763
    663764        case WM_SIZE: {
    664765            if (!scrollbar())
     
    675776            break;
    676777        }
    677         case WM_ACTIVATE:
    678             if (wParam == WA_INACTIVE)
    679                 hide();
    680             break;
    681         case WM_KILLFOCUS:
    682             if ((HWND)wParam != popupHandle())
    683                 // Focus is going elsewhere, so hide
    684                 hide();
    685             break;
    686778        case WM_KEYDOWN:
    687779            if (!client())
     
    735827                    if (isASCIIPrintable(wParam))
    736828                        // Send the keydown to the WebView so it can be used for type-to-select.
    737                         ::PostMessage(client()->hostWindow()->platformWindow(), message, wParam, lParam);
     829                        // Since we know that the virtual key is ASCII printable, it's OK to convert this to
     830                        // a WM_CHAR message. (We don't want to call TranslateMessage because that will post a
     831                        // WM_CHAR message that will be stolen and redirected to the popup HWND.
     832                        ::PostMessage(m_popup, WM_HOST_WINDOW_CHAR, wParam, lParam);
    738833                    else
    739834                        lResult = 1;
     
    789884                setFocusedIndex(listIndexAtPoint(mousePoint), true);
    790885
    791             // Release capture if the left button isn't down, and the mousePoint is outside the popup window.
    792             // This way, the WebView will get future mouse events in the rest of the window.
    793             if (!(wParam & MK_LBUTTON) && !::PtInRect(&bounds, mousePoint))
    794                 ::ReleaseCapture();
    795 
    796886            break;
    797887        }
    798888        case WM_LBUTTONDOWN: {
    799             ::SetCapture(popupHandle());
    800889            IntPoint mousePoint(MAKEPOINTS(lParam));
    801890            if (scrollbar()) {
     
    811900            }
    812901
    813             setFocusedIndex(listIndexAtPoint(mousePoint), true);
     902            // If the mouse is inside the window, update the focused index. Otherwise,
     903            // hide the popup.
     904            RECT bounds;
     905            GetClientRect(m_popup, &bounds);
     906            if (::PtInRect(&bounds, mousePoint))
     907                setFocusedIndex(listIndexAtPoint(mousePoint), true);
     908            else
     909                hide();
    814910            break;
    815911        }
     
    817913            IntPoint mousePoint(MAKEPOINTS(lParam));
    818914            if (scrollbar()) {
    819                 ::ReleaseCapture();
    820915                IntRect scrollBarRect = scrollbar()->frameRect();
    821916                if (scrollbarCapturingMouse() || scrollBarRect.contains(mousePoint)) {
     
    831926                }
    832927            }
    833             // Only release capture and hide the popup if the mouse is inside the popup window.
     928            // Only hide the popup if the mouse is inside the popup window.
    834929            RECT bounds;
    835930            GetClientRect(popupHandle(), &bounds);
    836931            if (client() && ::PtInRect(&bounds, mousePoint)) {
    837                 ::ReleaseCapture();
    838932                hide();
    839933                int index = focusedIndex();
     
    843937            break;
    844938        }
    845         case WM_MOUSEWHEEL:
    846             if (scrollbar()) {
    847                 int i = 0;
    848                 for (incrementWheelDelta(GET_WHEEL_DELTA_WPARAM(wParam)); abs(wheelDelta()) >= WHEEL_DELTA; reduceWheelDelta(WHEEL_DELTA)) {
    849                     if (wheelDelta() > 0)
    850                         ++i;
    851                     else
    852                         --i;
    853                 }
    854                 scrollbar()->scroll(i > 0 ? ScrollUp : ScrollDown, ScrollByLine, abs(i));
     939
     940        case WM_MOUSEWHEEL: {
     941            if (!scrollbar())
     942                break;
     943
     944            int i = 0;
     945            for (incrementWheelDelta(GET_WHEEL_DELTA_WPARAM(wParam)); abs(wheelDelta()) >= WHEEL_DELTA; reduceWheelDelta(WHEEL_DELTA)) {
     946                if (wheelDelta() > 0)
     947                    ++i;
     948                else
     949                    --i;
    855950            }
    856             break;
     951            scrollbar()->scroll(i > 0 ? ScrollUp : ScrollDown, ScrollByLine, abs(i));
     952            break;
     953        }
     954
    857955        case WM_PAINT: {
    858956            PAINTSTRUCT paintInfo;
Note: See TracChangeset for help on using the changeset viewer.