diff options
Diffstat (limited to 'WebCore/platform/win/PopupMenuWin.cpp')
-rw-r--r-- | WebCore/platform/win/PopupMenuWin.cpp | 1017 |
1 files changed, 0 insertions, 1017 deletions
diff --git a/WebCore/platform/win/PopupMenuWin.cpp b/WebCore/platform/win/PopupMenuWin.cpp deleted file mode 100644 index e86aef9..0000000 --- a/WebCore/platform/win/PopupMenuWin.cpp +++ /dev/null @@ -1,1017 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2007-2009 Torch Mobile Inc. - * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "PopupMenuWin.h" - -#include "BitmapInfo.h" -#include "Document.h" -#include "FloatRect.h" -#include "FontSelector.h" -#include "Frame.h" -#include "FrameView.h" -#include "GraphicsContext.h" -#include "HTMLNames.h" -#include "HostWindow.h" -#include "Page.h" -#include "PlatformMouseEvent.h" -#include "PlatformScreen.h" -#include "RenderTheme.h" -#include "RenderView.h" -#include "Scrollbar.h" -#include "ScrollbarTheme.h" -#include "SimpleFontData.h" -#include "WebCoreInstanceHandle.h" -#include <tchar.h> -#include <windows.h> -#include <windowsx.h> -#if OS(WINCE) -#include <ResDefCE.h> -#define MAKEPOINTS(l) (*((POINTS FAR *)&(l))) -#endif - -using std::min; - -namespace WebCore { - -using namespace HTMLNames; - -// Default Window animation duration in milliseconds -static const int defaultAnimationDuration = 200; -// Maximum height of a popup window -static const int maxPopupHeight = 320; - -const int optionSpacingMiddle = 1; -const int popupWindowBorderWidth = 1; - -static LPCTSTR kPopupWindowClassName = _T("PopupWindowClass"); - -// This is used from within our custom message pump when we want to send a -// message to the web view and not have our message stolen and sent to -// the popup window. -static const UINT WM_HOST_WINDOW_FIRST = WM_USER; -static const UINT WM_HOST_WINDOW_CHAR = WM_USER + WM_CHAR; -static const UINT WM_HOST_WINDOW_MOUSEMOVE = WM_USER + WM_MOUSEMOVE; - -// FIXME: Remove this as soon as practical. -static inline bool isASCIIPrintable(unsigned c) -{ - return c >= 0x20 && c <= 0x7E; -} - -static void translatePoint(LPARAM& lParam, HWND from, HWND to) -{ - POINT pt; - pt.x = (short)GET_X_LPARAM(lParam); - pt.y = (short)GET_Y_LPARAM(lParam); - ::MapWindowPoints(from, to, &pt, 1); - lParam = MAKELPARAM(pt.x, pt.y); -} - -PopupMenuWin::PopupMenuWin(PopupMenuClient* client) - : m_popupClient(client) - , m_scrollbar(0) - , m_popup(0) - , m_DC(0) - , m_bmp(0) - , m_wasClicked(false) - , m_itemHeight(0) - , m_scrollOffset(0) - , m_wheelDelta(0) - , m_focusedIndex(0) - , m_scrollbarCapturingMouse(false) - , m_showPopup(false) -{ -} - -PopupMenuWin::~PopupMenuWin() -{ - if (m_bmp) - ::DeleteObject(m_bmp); - if (m_DC) - ::DeleteDC(m_DC); - if (m_popup) - ::DestroyWindow(m_popup); - if (m_scrollbar) - m_scrollbar->setParent(0); -} - -void PopupMenuWin::disconnectClient() -{ - m_popupClient = 0; -} - -LPCTSTR PopupMenuWin::popupClassName() -{ - return kPopupWindowClassName; -} - -void PopupMenuWin::show(const IntRect& r, FrameView* view, int index) -{ - calculatePositionAndSize(r, view); - if (clientRect().isEmpty()) - return; - - HWND hostWindow = view->hostWindow()->platformPageClient(); - - if (!m_scrollbar && visibleItems() < client()->listSize()) { - // We need a scroll bar - m_scrollbar = client()->createScrollbar(this, VerticalScrollbar, SmallScrollbar); - m_scrollbar->styleChanged(); - } - - if (!m_popup) { - registerClass(); - - DWORD exStyle = WS_EX_LTRREADING; - - m_popup = ::CreateWindowEx(exStyle, kPopupWindowClassName, _T("PopupMenu"), - WS_POPUP | WS_BORDER, - m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), - hostWindow, 0, WebCore::instanceHandle(), this); - - if (!m_popup) - return; - } else { - // We need to reposition the popup window. - ::MoveWindow(m_popup, m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), false); - } - - // Determine whether we should animate our popups - // Note: Must use 'BOOL' and 'FALSE' instead of 'bool' and 'false' to avoid stack corruption with SystemParametersInfo - BOOL shouldAnimate = FALSE; -#if !OS(WINCE) - ::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 + view->contentsToWindow(r.location()).y()) ? AW_VER_NEGATIVE : AW_VER_POSITIVE; - - ::AnimateWindow(m_popup, defaultAnimationDuration, AW_SLIDE | slideDirection); - } - } else -#endif - ::ShowWindow(m_popup, SW_SHOWNOACTIVATE); - - if (client()) { - int index = client()->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<PopupMenu> 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. -#if !OS(WINCE) - 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: -#endif - 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_popupClient) - break; - - if (!m_showPopup) - break; - activeWindow = ::GetActiveWindow(); - if (activeWindow != hostWindow && !::IsChild(activeWindow, hostWindow)) - break; - if (::GetCapture() != hostWindow) - break; - } - - if (::GetCapture() == hostWindow) - ::ReleaseCapture(); - - // We're done, hide the popup if necessary. - hide(); -} - -void PopupMenuWin::hide() -{ - if (!m_showPopup) - return; - - m_showPopup = false; - - ::ShowWindow(m_popup, SW_HIDE); - - if (client()) - client()->popupDidHide(); - - // Post a WM_NULL message to wake up the message pump if necessary. - ::PostMessage(m_popup, WM_NULL, 0, 0); -} - -void PopupMenuWin::calculatePositionAndSize(const IntRect& r, FrameView* v) -{ - // r is in absolute document coordinates, but we want to be in screen coordinates - - // First, move to WebView coordinates - IntRect rScreenCoords(v->contentsToWindow(r.location()), r.size()); - - // Then, translate to screen coordinates - POINT location(rScreenCoords.location()); - if (!::ClientToScreen(v->hostWindow()->platformPageClient(), &location)) - return; - - rScreenCoords.setLocation(location); - - // First, determine the popup's height - int itemCount = client()->listSize(); - m_itemHeight = client()->menuStyle().font().height() + optionSpacingMiddle; - int naturalHeight = m_itemHeight * itemCount; - int popupHeight = min(maxPopupHeight, naturalHeight); - // The popup should show an integral number of items (i.e. no partial items should be visible) - popupHeight -= popupHeight % m_itemHeight; - - // Next determine its width - int popupWidth = 0; - for (int i = 0; i < itemCount; ++i) { - String text = client()->itemText(i); - if (text.isEmpty()) - continue; - - Font itemFont = client()->menuStyle().font(); - if (client()->itemIsLabel(i)) { - FontDescription d = itemFont.fontDescription(); - d.setWeight(d.bolderWeight()); - itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); - itemFont.update(m_popupClient->fontSelector()); - } - - popupWidth = max(popupWidth, itemFont.width(TextRun(text.characters(), text.length()))); - } - - if (naturalHeight > maxPopupHeight) - // We need room for a scrollbar - popupWidth += ScrollbarTheme::nativeTheme()->scrollbarThickness(SmallScrollbar); - - // Add padding to align the popup text with the <select> text - popupWidth += max(0, client()->clientPaddingRight() - client()->clientInsetRight()) + max(0, client()->clientPaddingLeft() - client()->clientInsetLeft()); - - // Leave room for the border - popupWidth += 2 * popupWindowBorderWidth; - popupHeight += 2 * popupWindowBorderWidth; - - // The popup should be at least as wide as the control on the page - popupWidth = max(rScreenCoords.width() - client()->clientInsetLeft() - client()->clientInsetRight(), popupWidth); - - // Always left-align items in the popup. This matches popup menus on the mac. - int popupX = rScreenCoords.x() + client()->clientInsetLeft(); - - IntRect popupRect(popupX, rScreenCoords.bottom(), popupWidth, popupHeight); - - // The popup needs to stay within the bounds of the screen and not overlap any toolbars - FloatRect screen = screenAvailableRect(v); - - // Check that we don't go off the screen vertically - if (popupRect.bottom() > screen.height()) { - // The popup will go off the screen, so try placing it above the client - if (rScreenCoords.y() - popupRect.height() < 0) { - // The popup won't fit above, either, so place it whereever's bigger and resize it to fit - if ((rScreenCoords.y() + rScreenCoords.height() / 2) < (screen.height() / 2)) { - // Below is bigger - popupRect.setHeight(screen.height() - popupRect.y()); - } else { - // Above is bigger - popupRect.setY(0); - popupRect.setHeight(rScreenCoords.y()); - } - } else { - // The popup fits above, so reposition it - popupRect.setY(rScreenCoords.y() - popupRect.height()); - } - } - - // Check that we don't go off the screen horizontally - if (popupRect.x() < screen.x()) { - popupRect.setWidth(popupRect.width() - (screen.x() - popupRect.x())); - popupRect.setX(screen.x()); - } - m_windowRect = popupRect; - return; -} - -bool PopupMenuWin::setFocusedIndex(int i, bool hotTracking) -{ - if (i < 0 || i >= client()->listSize() || i == focusedIndex()) - return false; - - if (!client()->itemIsEnabled(i)) - return false; - - invalidateItem(focusedIndex()); - invalidateItem(i); - - m_focusedIndex = i; - - if (!hotTracking) - client()->setTextFromItem(i); - - if (!scrollToRevealSelection()) - ::UpdateWindow(m_popup); - - return true; -} - -int PopupMenuWin::visibleItems() const -{ - return clientRect().height() / m_itemHeight; -} - -int PopupMenuWin::listIndexAtPoint(const IntPoint& point) const -{ - return m_scrollOffset + point.y() / m_itemHeight; -} - -int PopupMenuWin::focusedIndex() const -{ - return m_focusedIndex; -} - -void PopupMenuWin::focusFirst() -{ - if (!client()) - return; - - int size = client()->listSize(); - - for (int i = 0; i < size; ++i) - if (client()->itemIsEnabled(i)) { - setFocusedIndex(i); - break; - } -} - -void PopupMenuWin::focusLast() -{ - if (!client()) - return; - - int size = client()->listSize(); - - for (int i = size - 1; i > 0; --i) - if (client()->itemIsEnabled(i)) { - setFocusedIndex(i); - break; - } -} - -bool PopupMenuWin::down(unsigned lines) -{ - if (!client()) - return false; - - int size = client()->listSize(); - - int lastSelectableIndex, selectedListIndex; - lastSelectableIndex = selectedListIndex = focusedIndex(); - for (int i = selectedListIndex + 1; i >= 0 && i < size; ++i) - if (client()->itemIsEnabled(i)) { - lastSelectableIndex = i; - if (i >= selectedListIndex + (int)lines) - break; - } - - return setFocusedIndex(lastSelectableIndex); -} - -bool PopupMenuWin::up(unsigned lines) -{ - if (!client()) - return false; - - int size = client()->listSize(); - - int lastSelectableIndex, selectedListIndex; - lastSelectableIndex = selectedListIndex = focusedIndex(); - for (int i = selectedListIndex - 1; i >= 0 && i < size; --i) - if (client()->itemIsEnabled(i)) { - lastSelectableIndex = i; - if (i <= selectedListIndex - (int)lines) - break; - } - - return setFocusedIndex(lastSelectableIndex); -} - -void PopupMenuWin::invalidateItem(int index) -{ - if (!m_popup) - return; - - IntRect damageRect(clientRect()); - damageRect.setY(m_itemHeight * (index - m_scrollOffset)); - damageRect.setHeight(m_itemHeight); - if (m_scrollbar) - damageRect.setWidth(damageRect.width() - m_scrollbar->frameRect().width()); - - RECT r = damageRect; - ::InvalidateRect(m_popup, &r, TRUE); -} - -IntRect PopupMenuWin::clientRect() const -{ - IntRect clientRect = m_windowRect; - clientRect.inflate(-popupWindowBorderWidth); - clientRect.setLocation(IntPoint(0, 0)); - return clientRect; -} - -void PopupMenuWin::incrementWheelDelta(int delta) -{ - m_wheelDelta += delta; -} - -void PopupMenuWin::reduceWheelDelta(int delta) -{ - ASSERT(delta >= 0); - ASSERT(delta <= abs(m_wheelDelta)); - - if (m_wheelDelta > 0) - m_wheelDelta -= delta; - else if (m_wheelDelta < 0) - m_wheelDelta += delta; - else - return; -} - -bool PopupMenuWin::scrollToRevealSelection() -{ - if (!m_scrollbar) - return false; - - int index = focusedIndex(); - - if (index < m_scrollOffset) { - m_scrollbar->setValue(index, Scrollbar::NotFromScrollAnimator); - return true; - } - - if (index >= m_scrollOffset + visibleItems()) { - m_scrollbar->setValue(index - visibleItems() + 1, Scrollbar::NotFromScrollAnimator); - return true; - } - - return false; -} - -void PopupMenuWin::updateFromElement() -{ - if (!m_popup) - return; - - m_focusedIndex = client()->selectedIndex(); - - ::InvalidateRect(m_popup, 0, TRUE); - if (!scrollToRevealSelection()) - ::UpdateWindow(m_popup); -} - -const int separatorPadding = 4; -const int separatorHeight = 1; -void PopupMenuWin::paint(const IntRect& damageRect, HDC hdc) -{ - if (!m_popup) - return; - - if (!m_DC) { - m_DC = ::CreateCompatibleDC(::GetDC(m_popup)); - if (!m_DC) - return; - } - - if (m_bmp) { - bool keepBitmap = false; - BITMAP bitmap; - if (GetObject(m_bmp, sizeof(bitmap), &bitmap)) - keepBitmap = bitmap.bmWidth == clientRect().width() - && bitmap.bmHeight == clientRect().height(); - if (!keepBitmap) { - DeleteObject(m_bmp); - m_bmp = 0; - } - } - if (!m_bmp) { -#if OS(WINCE) - BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(clientRect().size(), BitmapInfo::BitCount16); -#else - BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(clientRect().size()); -#endif - void* pixels = 0; - m_bmp = ::CreateDIBSection(m_DC, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0); - if (!m_bmp) - return; - - ::SelectObject(m_DC, m_bmp); - } - - GraphicsContext context(m_DC); - - int itemCount = client()->listSize(); - - // listRect is the damageRect translated into the coordinates of the entire menu list (which is itemCount * m_itemHeight pixels tall) - IntRect listRect = damageRect; - listRect.move(IntSize(0, m_scrollOffset * m_itemHeight)); - - for (int y = listRect.y(); y < listRect.bottom(); y += m_itemHeight) { - int index = y / m_itemHeight; - - Color optionBackgroundColor, optionTextColor; - PopupMenuStyle itemStyle = client()->itemStyle(index); - if (index == focusedIndex()) { - optionBackgroundColor = RenderTheme::defaultTheme()->activeListBoxSelectionBackgroundColor(); - optionTextColor = RenderTheme::defaultTheme()->activeListBoxSelectionForegroundColor(); - } else { - optionBackgroundColor = itemStyle.backgroundColor(); - optionTextColor = itemStyle.foregroundColor(); - } - - // itemRect is in client coordinates - IntRect itemRect(0, (index - m_scrollOffset) * m_itemHeight, damageRect.width(), m_itemHeight); - - // Draw the background for this menu item - if (itemStyle.isVisible()) - context.fillRect(itemRect, optionBackgroundColor, ColorSpaceDeviceRGB); - - if (client()->itemIsSeparator(index)) { - IntRect separatorRect(itemRect.x() + separatorPadding, itemRect.y() + (itemRect.height() - separatorHeight) / 2, itemRect.width() - 2 * separatorPadding, separatorHeight); - context.fillRect(separatorRect, optionTextColor, ColorSpaceDeviceRGB); - continue; - } - - String itemText = client()->itemText(index); - - unsigned length = itemText.length(); - const UChar* string = itemText.characters(); - TextRun textRun(string, length, false, 0, 0, itemText.defaultWritingDirection() == WTF::Unicode::RightToLeft); - - context.setFillColor(optionTextColor, ColorSpaceDeviceRGB); - - Font itemFont = client()->menuStyle().font(); - if (client()->itemIsLabel(index)) { - FontDescription d = itemFont.fontDescription(); - d.setWeight(d.bolderWeight()); - itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); - itemFont.update(m_popupClient->fontSelector()); - } - - // Draw the item text - if (itemStyle.isVisible()) { - int textX = max(0, client()->clientPaddingLeft() - client()->clientInsetLeft()); - if (RenderTheme::defaultTheme()->popupOptionSupportsTextIndent() && itemStyle.textDirection() == LTR) - textX += itemStyle.textIndent().calcMinValue(itemRect.width()); - int textY = itemRect.y() + itemFont.ascent() + (itemRect.height() - itemFont.height()) / 2; - context.drawBidiText(itemFont, textRun, IntPoint(textX, textY)); - } - } - - if (m_scrollbar) - m_scrollbar->paint(&context, damageRect); - - HDC localDC = hdc ? hdc : ::GetDC(m_popup); - - ::BitBlt(localDC, damageRect.x(), damageRect.y(), damageRect.width(), damageRect.height(), m_DC, damageRect.x(), damageRect.y(), SRCCOPY); - - if (!hdc) - ::ReleaseDC(m_popup, localDC); -} - -int PopupMenuWin::scrollSize(ScrollbarOrientation orientation) const -{ - return ((orientation == VerticalScrollbar) && m_scrollbar) ? (m_scrollbar->totalSize() - m_scrollbar->visibleSize()) : 0; -} - -void PopupMenuWin::setScrollOffsetFromAnimation(const IntPoint& offset) -{ - if (m_scrollbar) - m_scrollbar->setValue(offset.y(), Scrollbar::FromScrollAnimator); -} - -void PopupMenuWin::valueChanged(Scrollbar* scrollBar) -{ - ASSERT(m_scrollbar); - - if (!m_popup) - return; - - int offset = scrollBar->value(); - - if (m_scrollOffset == offset) - return; - - int scrolledLines = m_scrollOffset - offset; - m_scrollOffset = offset; - - UINT flags = SW_INVALIDATE; - -#ifdef CAN_SET_SMOOTH_SCROLLING_DURATION - BOOL shouldSmoothScroll = FALSE; - ::SystemParametersInfo(SPI_GETLISTBOXSMOOTHSCROLLING, 0, &shouldSmoothScroll, 0); - if (shouldSmoothScroll) - flags |= MAKEWORD(SW_SMOOTHSCROLL, smoothScrollAnimationDuration); -#endif - - IntRect listRect = clientRect(); - if (m_scrollbar) - listRect.setWidth(listRect.width() - m_scrollbar->frameRect().width()); - RECT r = listRect; - ::ScrollWindowEx(m_popup, 0, scrolledLines * m_itemHeight, &r, 0, 0, 0, flags); - if (m_scrollbar) { - r = m_scrollbar->frameRect(); - ::InvalidateRect(m_popup, &r, TRUE); - } - ::UpdateWindow(m_popup); -} - -void PopupMenuWin::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) -{ - IntRect scrollRect = rect; - scrollRect.move(scrollbar->x(), scrollbar->y()); - RECT r = scrollRect; - ::InvalidateRect(m_popup, &r, false); -} - -void PopupMenuWin::registerClass() -{ - static bool haveRegisteredWindowClass = false; - - if (haveRegisteredWindowClass) - return; - -#if OS(WINCE) - WNDCLASS wcex; -#else - WNDCLASSEX wcex; - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.hIconSm = 0; - wcex.style = CS_DROPSHADOW; -#endif - - wcex.lpfnWndProc = PopupMenuWndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = sizeof(PopupMenu*); // For the PopupMenu pointer - wcex.hInstance = WebCore::instanceHandle(); - wcex.hIcon = 0; - wcex.hCursor = LoadCursor(0, IDC_ARROW); - wcex.hbrBackground = 0; - wcex.lpszMenuName = 0; - wcex.lpszClassName = kPopupWindowClassName; - - haveRegisteredWindowClass = true; - -#if OS(WINCE) - RegisterClass(&wcex); -#else - RegisterClassEx(&wcex); -#endif -} - - -LRESULT CALLBACK PopupMenuWin::PopupMenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ -#if OS(WINCE) - LONG longPtr = GetWindowLong(hWnd, 0); -#else - LONG_PTR longPtr = GetWindowLongPtr(hWnd, 0); -#endif - - if (PopupMenuWin* popup = reinterpret_cast<PopupMenuWin*>(longPtr)) - return popup->wndProc(hWnd, message, wParam, lParam); - - if (message == WM_CREATE) { - LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam); - - // Associate the PopupMenu with the window. -#if OS(WINCE) - ::SetWindowLong(hWnd, 0, (LONG)createStruct->lpCreateParams); -#else - ::SetWindowLongPtr(hWnd, 0, (LONG_PTR)createStruct->lpCreateParams); -#endif - return 0; - } - - return ::DefWindowProc(hWnd, message, wParam, lParam); -} - -const int smoothScrollAnimationDuration = 5000; - -LRESULT PopupMenuWin::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - LRESULT lResult = 0; - - switch (message) { -#if !OS(WINCE) - case WM_MOUSEACTIVATE: - return MA_NOACTIVATE; -#endif - case WM_SIZE: { - if (!scrollbar()) - break; - - IntSize size(LOWORD(lParam), HIWORD(lParam)); - scrollbar()->setFrameRect(IntRect(size.width() - scrollbar()->width(), 0, scrollbar()->width(), size.height())); - - int visibleItems = this->visibleItems(); - scrollbar()->setEnabled(visibleItems < client()->listSize()); - scrollbar()->setSteps(1, max(1, visibleItems - 1)); - scrollbar()->setProportion(visibleItems, client()->listSize()); - - break; - } - case WM_KEYDOWN: - if (!client()) - break; - - lResult = 0; - switch (LOWORD(wParam)) { - case VK_DOWN: - case VK_RIGHT: - down(); - break; - case VK_UP: - case VK_LEFT: - up(); - break; - case VK_HOME: - focusFirst(); - break; - case VK_END: - focusLast(); - break; - case VK_PRIOR: - if (focusedIndex() != scrollOffset()) { - // Set the selection to the first visible item - int firstVisibleItem = scrollOffset(); - up(focusedIndex() - firstVisibleItem); - } else { - // The first visible item is selected, so move the selection back one page - up(visibleItems()); - } - break; - case VK_NEXT: { - int lastVisibleItem = scrollOffset() + visibleItems() - 1; - if (focusedIndex() != lastVisibleItem) { - // Set the selection to the last visible item - down(lastVisibleItem - focusedIndex()); - } else { - // The last visible item is selected, so move the selection forward one page - down(visibleItems()); - } - break; - } - case VK_TAB: - ::SendMessage(client()->hostWindow()->platformPageClient(), message, wParam, lParam); - hide(); - break; - case VK_ESCAPE: - hide(); - break; - default: - if (isASCIIPrintable(wParam)) - // Send the keydown to the WebView so it can be used for type-to-select. - // Since we know that the virtual key is ASCII printable, it's OK to convert this to - // a WM_CHAR message. (We don't want to call TranslateMessage because that will post a - // WM_CHAR message that will be stolen and redirected to the popup HWND. - ::PostMessage(m_popup, WM_HOST_WINDOW_CHAR, wParam, lParam); - else - lResult = 1; - break; - } - break; - case WM_CHAR: { - if (!client()) - break; - - lResult = 0; - int index; - switch (wParam) { - case 0x0D: // Enter/Return - hide(); - index = focusedIndex(); - ASSERT(index >= 0); - client()->valueChanged(index); - break; - case 0x1B: // Escape - hide(); - break; - case 0x09: // TAB - case 0x08: // Backspace - case 0x0A: // Linefeed - default: // Character - lResult = 1; - break; - } - break; - } - case WM_MOUSEMOVE: { - IntPoint mousePoint(MAKEPOINTS(lParam)); - if (scrollbar()) { - IntRect scrollBarRect = scrollbar()->frameRect(); - if (scrollbarCapturingMouse() || scrollBarRect.contains(mousePoint)) { - // Put the point into coordinates relative to the scroll bar - mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y()); - PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(mousePoint.x(), mousePoint.y())); - scrollbar()->mouseMoved(event); - break; - } - } - - BOOL shouldHotTrack = FALSE; -#if !OS(WINCE) - ::SystemParametersInfo(SPI_GETHOTTRACKING, 0, &shouldHotTrack, 0); -#endif - - RECT bounds; - GetClientRect(popupHandle(), &bounds); - if (!::PtInRect(&bounds, mousePoint) && !(wParam & MK_LBUTTON) && client()) { - // When the mouse is not inside the popup menu and the left button isn't down, just - // repost the message to the web view. - - // Translate the coordinate. - translatePoint(lParam, m_popup, client()->hostWindow()->platformPageClient()); - - ::PostMessage(m_popup, WM_HOST_WINDOW_MOUSEMOVE, wParam, lParam); - break; - } - - if ((shouldHotTrack || wParam & MK_LBUTTON) && ::PtInRect(&bounds, mousePoint)) - setFocusedIndex(listIndexAtPoint(mousePoint), true); - - break; - } - case WM_LBUTTONDOWN: { - IntPoint mousePoint(MAKEPOINTS(lParam)); - if (scrollbar()) { - IntRect scrollBarRect = scrollbar()->frameRect(); - if (scrollBarRect.contains(mousePoint)) { - // Put the point into coordinates relative to the scroll bar - mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y()); - PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(mousePoint.x(), mousePoint.y())); - scrollbar()->mouseDown(event); - setScrollbarCapturingMouse(true); - break; - } - } - - // If the mouse is inside the window, update the focused index. Otherwise, - // hide the popup. - RECT bounds; - GetClientRect(m_popup, &bounds); - if (::PtInRect(&bounds, mousePoint)) - setFocusedIndex(listIndexAtPoint(mousePoint), true); - else - hide(); - break; - } - case WM_LBUTTONUP: { - IntPoint mousePoint(MAKEPOINTS(lParam)); - if (scrollbar()) { - IntRect scrollBarRect = scrollbar()->frameRect(); - if (scrollbarCapturingMouse() || scrollBarRect.contains(mousePoint)) { - setScrollbarCapturingMouse(false); - // Put the point into coordinates relative to the scroll bar - mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y()); - PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(mousePoint.x(), mousePoint.y())); - scrollbar()->mouseUp(); - // FIXME: This is a hack to work around Scrollbar not invalidating correctly when it doesn't have a parent widget - RECT r = scrollBarRect; - ::InvalidateRect(popupHandle(), &r, TRUE); - break; - } - } - // Only hide the popup if the mouse is inside the popup window. - RECT bounds; - GetClientRect(popupHandle(), &bounds); - if (client() && ::PtInRect(&bounds, mousePoint)) { - hide(); - int index = focusedIndex(); - if (index >= 0) - client()->valueChanged(index); - } - break; - } - - case WM_MOUSEWHEEL: { - if (!scrollbar()) - break; - - int i = 0; - for (incrementWheelDelta(GET_WHEEL_DELTA_WPARAM(wParam)); abs(wheelDelta()) >= WHEEL_DELTA; reduceWheelDelta(WHEEL_DELTA)) { - if (wheelDelta() > 0) - ++i; - else - --i; - } - scrollbar()->scroll(i > 0 ? ScrollUp : ScrollDown, ScrollByLine, abs(i)); - break; - } - - case WM_PAINT: { - PAINTSTRUCT paintInfo; - ::BeginPaint(popupHandle(), &paintInfo); - paint(paintInfo.rcPaint, paintInfo.hdc); - ::EndPaint(popupHandle(), &paintInfo); - lResult = 0; - break; - } -#if !OS(WINCE) - case WM_PRINTCLIENT: - paint(clientRect(), (HDC)wParam); - break; -#endif - default: - lResult = DefWindowProc(hWnd, message, wParam, lParam); - } - - return lResult; -} - -} |