Title: [133092] trunk/Source/WebCore
Revision
133092
Author
[email protected]
Date
2012-10-31 16:09:37 -0700 (Wed, 31 Oct 2012)

Log Message

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):

Modified Paths

Diff

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
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to