Modified: trunk/Source/WebCore/ChangeLog (133091 => 133092)
--- trunk/Source/WebCore/ChangeLog 2012-10-31 22:50:45 UTC (rev 133091)
+++ trunk/Source/WebCore/ChangeLog 2012-10-31 23:09:37 UTC (rev 133092)
@@ -1,3 +1,29 @@
+2012-10-31 Roger Fong <[email protected]>
+
+ Change PopupMenu positioning on Windows such that behaviour on multiple monitors matches Windows standards.
+ https://bugs.webkit.org/show_bug.cgi?id=100317
+
+ Reviewed by Sam Weinig.
+
+ The existing code determines which screen the popup menu "belongs" to by determining which screen the owning application's hwnd belongs to,
+ where ownership is determined by how much of the hwnd is on which screen.
+ To match what most Windows applications do, the owning screen should be whichever screen the drop down button belongs to.
+ To determine which screen an element belongs to in Windows we need to pass in an hwnd for that element.
+ However, since the drop down button is something that WebKit renders there is no hwnd.
+
+ To remedy this issue, we can temporarily move the popup menu's hwnd to match the position and size of the button,
+ determine the correct screen, and then eventually move it back to the correct final position after the rest of
+ the calculations have been completed. This is all done in the same function call so no rendering of the popup menu occurs
+ between the temporary and final positionings.
+
+ There's not really a good way of testing popup menus except manually, they're separate hwnds created outside of the WebView.
+
+ * platform/win/PopupMenuWin.cpp:
+ (WebCore::monitorFromHwnd):
+ (WebCore):
+ (WebCore::PopupMenuWin::show):
+ (WebCore::PopupMenuWin::calculatePositionAndSize):
+
2012-10-31 Thiago Marcos P. Santos <[email protected]>
Added viewport at-rule to the CSS parser and tokenizer
Modified: trunk/Source/WebCore/platform/win/PopupMenuWin.cpp (133091 => 133092)
--- trunk/Source/WebCore/platform/win/PopupMenuWin.cpp 2012-10-31 22:50:45 UTC (rev 133091)
+++ trunk/Source/WebCore/platform/win/PopupMenuWin.cpp 2012-10-31 23:09:37 UTC (rev 133092)
@@ -37,6 +37,7 @@
#include "Page.h"
#include "PlatformMouseEvent.h"
#include "PlatformScreen.h"
+#include "RenderMenuList.h"
#include "RenderTheme.h"
#include "RenderView.h"
#include "Scrollbar.h"
@@ -93,6 +94,15 @@
lParam = MAKELPARAM(pt.x, pt.y);
}
+static FloatRect monitorFromHwnd(HWND hwnd)
+{
+ HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
+ MONITORINFOEX monitorInfo;
+ monitorInfo.cbSize = sizeof(MONITORINFOEX);
+ GetMonitorInfo(monitor, &monitorInfo);
+ return monitorInfo.rcWork;
+}
+
PopupMenuWin::PopupMenuWin(PopupMenuClient* client)
: m_popupClient(client)
, m_scrollbar(0)
@@ -145,23 +155,10 @@
m_scrollbar->styleChanged();
}
- if (!m_popup) {
- registerClass();
+ // We need to reposition the popup window to its final coordinates.
+ // Before calling this, the popup hwnd is currently the size of and at the location of the menu list client so it needs to be updated.
+ ::MoveWindow(m_popup, m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), false);
- DWORD exStyle = WS_EX_LTRREADING;
-
- m_popup = ::CreateWindowExW(exStyle, kPopupWindowClassName, L"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;
@@ -296,10 +293,40 @@
::PostMessage(m_popup, WM_NULL, 0, 0);
}
+// The screen that the popup is placed on should be whichever one the popup menu button lies on.
+// We fake an hwnd (here we use the popup's hwnd) on top of the button which we can then use to determine the screen.
+// We can then proceed with our final position/size calculations.
void PopupMenuWin::calculatePositionAndSize(const IntRect& r, FrameView* v)
{
- // r is in absolute document coordinates, but we want to be in screen coordinates
+ // First get the screen coordinates of the popup menu client.
+ HWND hostWindow = v->hostWindow()->platformPageClient();
+ IntRect absoluteBounds = ((RenderMenuList*)m_popupClient)->absoluteBoundingBoxRect();
+ IntRect absoluteScreenCoords(v->contentsToWindow(absoluteBounds.location()), absoluteBounds.size());
+ POINT absoluteLocation(absoluteScreenCoords.location());
+ if (!::ClientToScreen(v->hostWindow()->platformPageClient(), &absoluteLocation))
+ return;
+ absoluteScreenCoords.setLocation(absoluteLocation);
+ // Now set the popup menu's location temporarily to these coordinates so we can determine which screen the popup should lie on.
+ // We create or move m_popup as necessary.
+ if (!m_popup) {
+ registerClass();
+ DWORD exStyle = WS_EX_LTRREADING;
+ m_popup = ::CreateWindowExW(exStyle, kPopupWindowClassName, L"PopupMenu",
+ WS_POPUP | WS_BORDER,
+ absoluteScreenCoords.x(), absoluteScreenCoords.y(), absoluteScreenCoords.width(), absoluteScreenCoords.height(),
+ hostWindow, 0, WebCore::instanceHandle(), this);
+
+ if (!m_popup)
+ return;
+ } else
+ ::MoveWindow(m_popup, absoluteScreenCoords.x(), absoluteScreenCoords.y(), absoluteScreenCoords.width(), absoluteScreenCoords.height(), false);
+
+ FloatRect screen = monitorFromHwnd(m_popup);
+
+ // Now we determine the actual location and measurements of the popup itself.
+ // 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());
@@ -355,9 +382,6 @@
IntRect popupRect(popupX, rScreenCoords.maxY(), 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.maxY() > screen.height()) {
// The popup will go off the screen, so try placing it above the client