Exemple #1
0
void PopupMenu::show(const IntRect& r, FrameView* v, int index)
{
    ASSERT(client());
    
    calculatePositionAndSize(r, v);
    if (clientRect().isEmpty())
        return;

    OWBAL::ObserverServiceData::createObserverService()->notifyObserver("PopupMenuShow", "", this);
}
void WebPopupMenuProxyWin::showPopupMenu(const IntRect& rect, TextDirection, double, const Vector<WebPopupItem>& items, const PlatformPopupMenuData& data, int32_t selectedIndex)
{
    m_items = items;
    m_data = data;
    m_newSelectedIndex = selectedIndex;

    calculatePositionAndSize(rect);
    if (clientRect().isEmpty())
        return;

    HWND hostWindow = m_webView->window();

    if (!m_scrollbar && visibleItems() < m_items.size()) {
        m_scrollbar = Scrollbar::createNativeScrollbar(this, VerticalScrollbar, SmallScrollbar);
        m_scrollbar->styleChanged();
    }

    if (!m_popup) {
        registerWindowClass();

        DWORD exStyle = WS_EX_LTRREADING;

        m_popup = ::CreateWindowEx(exStyle, kWebKit2WebPopupMenuProxyWindowClassName, TEXT("PopupMenu"),
            WS_POPUP | WS_BORDER,
            m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(),
            hostWindow, 0, instanceHandle(), this);

        if (!m_popup)
            return;
    }

    BOOL shouldAnimate = FALSE;
    ::SystemParametersInfo(SPI_GETCOMBOBOXANIMATION, 0, &shouldAnimate, 0);

    if (shouldAnimate) {
        RECT viewRect = {0};
        ::GetWindowRect(hostWindow, &viewRect);

        if (!::IsRectEmpty(&viewRect)) {
            // Popups should slide into view away from the <select> box
            // NOTE: This may have to change for Vista
            DWORD slideDirection = (m_windowRect.y() < viewRect.top + rect.location().y()) ? AW_VER_NEGATIVE : AW_VER_POSITIVE;

            ::AnimateWindow(m_popup, defaultAnimationDuration, AW_SLIDE | slideDirection);
        }
    } else
        ::ShowWindow(m_popup, SW_SHOWNOACTIVATE);


    int index = selectedIndex;
    if (index >= 0)
        setFocusedIndex(index);

    m_showPopup = true;

    // Protect the popup menu in case its owner is destroyed while we're running the message pump.
    RefPtr<WebPopupMenuProxyWin> protect(this);

    ::SetCapture(hostWindow);

    MSG msg;
    HWND activeWindow;

    while (::GetMessage(&msg, 0, 0, 0)) {
        switch (msg.message) {
        case WM_HOST_WINDOW_MOUSEMOVE:
        case WM_HOST_WINDOW_CHAR: 
            if (msg.hwnd == m_popup) {
                // This message should be sent to the host window.
                msg.hwnd = hostWindow;
                msg.message -= WM_HOST_WINDOW_FIRST;
            }
            break;

        // Steal mouse messages.
        case WM_NCMOUSEMOVE:
        case WM_NCLBUTTONDOWN:
        case WM_NCLBUTTONUP:
        case WM_NCLBUTTONDBLCLK:
        case WM_NCRBUTTONDOWN:
        case WM_NCRBUTTONUP:
        case WM_NCRBUTTONDBLCLK:
        case WM_NCMBUTTONDOWN:
        case WM_NCMBUTTONUP:
        case WM_NCMBUTTONDBLCLK:
        case WM_MOUSEWHEEL:
            msg.hwnd = m_popup;
            break;

        // These mouse messages use client coordinates so we need to convert them.
        case WM_MOUSEMOVE:
        case WM_LBUTTONDOWN:
        case WM_LBUTTONUP:
        case WM_LBUTTONDBLCLK:
        case WM_RBUTTONDOWN:
        case WM_RBUTTONUP:
        case WM_RBUTTONDBLCLK:
        case WM_MBUTTONDOWN:
        case WM_MBUTTONUP:
        case WM_MBUTTONDBLCLK: {
            // Translate the coordinate.
            translatePoint(msg.lParam, msg.hwnd, m_popup);
            msg.hwnd = m_popup;
            break;
        }

        // Steal all keyboard messages.
        case WM_KEYDOWN:
        case WM_KEYUP:
        case WM_CHAR:
        case WM_DEADCHAR:
        case WM_SYSKEYUP:
        case WM_SYSCHAR:
        case WM_SYSDEADCHAR:
            msg.hwnd = m_popup;
            break;
        }

        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);

        if (!m_showPopup)
            break;
        activeWindow = ::GetActiveWindow();
        if (activeWindow != hostWindow && !::IsChild(activeWindow, hostWindow))
            break;
        if (::GetCapture() != hostWindow)
            break;
    }

    if (::GetCapture() == hostWindow)
        ::ReleaseCapture();

    m_showPopup = false;
    ::ShowWindow(m_popup, SW_HIDE);

    if (!m_client)
        return;

    m_client->valueChangedForPopupMenu(this, m_newSelectedIndex);

    // <https://bugs.webkit.org/show_bug.cgi?id=57904> In order to properly call the onClick()
    // handler on a <select> element, we need to fake a mouse up event in the main window.
    // The main window already received the mouse down, which showed this popup, but upon
    // selection of an item the mouse up gets eaten by the popup menu. So we take the mouse down
    // event, change the message type to a mouse up event, and post that in the message queue.
    // Thus, we are virtually clicking at the
    // same location where the mouse down event occurred. This allows the hit test to select
    // the correct element, and thereby call the onClick() JS handler.
    if (!m_client->currentlyProcessedMouseDownEvent())
        return;
        
    const MSG* initiatingWinEvent = m_client->currentlyProcessedMouseDownEvent()->nativeEvent();
    MSG fakeEvent = *initiatingWinEvent;
    fakeEvent.message = WM_LBUTTONUP;
    ::PostMessage(fakeEvent.hwnd, fakeEvent.message, fakeEvent.wParam, fakeEvent.lParam);
}