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); }