From 470518a52e20e923f0b1ac17c61bb29f29c2dd79 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Wed, 29 Oct 2014 18:14:47 +0000 Subject: [PATCH] Windows/Linux: Fix positioning of select popups and dismissal on window move/resize by calling new CefBrowserHost::NotifyMoveOrResizeStarted() method from client applications (issue #1208). git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1901 5089003a-bbd8-11dd-ad1f-f1f9622dbc98 --- include/capi/cef_browser_capi.h | 7 +++++ include/cef_browser.h | 7 +++++ libcef/browser/browser_host_impl.cc | 18 ++++++++++++ libcef/browser/browser_host_impl.h | 3 ++ libcef/browser/browser_host_impl_linux.cc | 30 +++++++++++++++++++ libcef/browser/browser_host_impl_mac.mm | 3 ++ libcef/browser/browser_host_impl_win.cc | 30 +++++++++++++++++++ libcef/browser/window_x11.cc | 36 +++++++---------------- libcef/browser/window_x11.h | 6 ++++ libcef_dll/cpptoc/browser_host_cpptoc.cc | 14 +++++++++ libcef_dll/ctocpp/browser_host_ctocpp.cc | 10 +++++++ libcef_dll/ctocpp/browser_host_ctocpp.h | 1 + patch/patches/views_widget_180.patch | 17 ++++++++--- tests/cefclient/cefclient_gtk.cpp | 20 +++++++++++++ tests/cefclient/cefclient_win.cpp | 8 +++++ 15 files changed, 181 insertions(+), 29 deletions(-) diff --git a/include/capi/cef_browser_capi.h b/include/capi/cef_browser_capi.h index 1606c9bea..0c53818d6 100644 --- a/include/capi/cef_browser_capi.h +++ b/include/capi/cef_browser_capi.h @@ -456,6 +456,13 @@ typedef struct _cef_browser_host_t { void (CEF_CALLBACK *send_capture_lost_event)( struct _cef_browser_host_t* self); + /// + // Notify the browser that the window hosting it is about to be moved or + // resized. This function is only used on Windows and Linux. + /// + void (CEF_CALLBACK *notify_move_or_resize_started)( + struct _cef_browser_host_t* self); + /// // Get the NSTextInputContext implementation for enabling IME on Mac when // window rendering is disabled. diff --git a/include/cef_browser.h b/include/cef_browser.h index 4174f4760..d8147e47b 100644 --- a/include/cef_browser.h +++ b/include/cef_browser.h @@ -507,6 +507,13 @@ class CefBrowserHost : public virtual CefBase { /*--cef()--*/ virtual void SendCaptureLostEvent() =0; + /// + // Notify the browser that the window hosting it is about to be moved or + // resized. This method is only used on Windows and Linux. + /// + /*--cef()--*/ + virtual void NotifyMoveOrResizeStarted() =0; + /// // Get the NSTextInputContext implementation for enabling IME on Mac when // window rendering is disabled. diff --git a/libcef/browser/browser_host_impl.cc b/libcef/browser/browser_host_impl.cc index a76bd0255..34a6fca1d 100644 --- a/libcef/browser/browser_host_impl.cc +++ b/libcef/browser/browser_host_impl.cc @@ -1164,6 +1164,24 @@ void CefBrowserHostImpl::SendCaptureLostEvent() { widget->LostCapture(); } +void CefBrowserHostImpl::NotifyMoveOrResizeStarted() { + if (!CEF_CURRENTLY_ON_UIT()) { + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefBrowserHostImpl::NotifyMoveOrResizeStarted, this)); + return; + } + + if (!web_contents()) + return; + + // Dismiss any existing popups. + content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); + if (rvh) + rvh->NotifyMoveOrResizeStarted(); + + PlatformNotifyMoveOrResizeStarted(); +} + // CefBrowser methods. // ----------------------------------------------------------------------------- diff --git a/libcef/browser/browser_host_impl.h b/libcef/browser/browser_host_impl.h index 1e6f2a9aa..7ec5a96ee 100644 --- a/libcef/browser/browser_host_impl.h +++ b/libcef/browser/browser_host_impl.h @@ -175,6 +175,7 @@ class CefBrowserHostImpl : public CefBrowserHost, int deltaX, int deltaY) OVERRIDE; virtual void SendFocusEvent(bool setFocus) OVERRIDE; virtual void SendCaptureLostEvent() OVERRIDE; + virtual void NotifyMoveOrResizeStarted() OVERRIDE; virtual CefTextInputContext GetNSTextInputContext() OVERRIDE; virtual void HandleKeyEventBeforeTextInputClient(CefEventHandle keyEvent) OVERRIDE; @@ -540,6 +541,8 @@ class CefBrowserHostImpl : public CefBrowserHost, void PlatformTranslateMouseEvent(blink::WebMouseEvent& web_event, const CefMouseEvent& mouse_event); + void PlatformNotifyMoveOrResizeStarted(); + int TranslateModifiers(uint32 cefKeyStates); void SendMouseEvent(const blink::WebMouseEvent& web_event); diff --git a/libcef/browser/browser_host_impl_linux.cc b/libcef/browser/browser_host_impl_linux.cc index ab4d140dc..54009239d 100644 --- a/libcef/browser/browser_host_impl_linux.cc +++ b/libcef/browser/browser_host_impl_linux.cc @@ -5,6 +5,10 @@ #include "libcef/browser/browser_host_impl.h" +// Include this first to avoid type conflict errors. +#include "base/tracked_objects.h" +#undef Status + #include #include @@ -14,10 +18,13 @@ #include "libcef/browser/thread_util.h" #include "base/bind.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/public/browser/native_web_keyboard_event.h" +#include "content/public/browser/render_view_host.h" #include "content/public/common/file_chooser_params.h" #include "content/public/common/renderer_preferences.h" #include "third_party/WebKit/public/web/WebInputEvent.h" +#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h" #include "ui/views/widget/widget.h" namespace { @@ -429,3 +436,26 @@ void CefBrowserHostImpl::PlatformTranslateMouseEvent( // timestamp result.timeStampSeconds = GetSystemUptime(); } + +void CefBrowserHostImpl::PlatformNotifyMoveOrResizeStarted() { + if (IsWindowless()) + return; + + if (!window_x11_) + return; + + views::DesktopWindowTreeHostX11* tree_host = window_x11_->GetHost(); + if (!tree_host) + return; + + // Explicitly set the screen bounds so that WindowTreeHost::*Screen() + // methods return the correct results. + const gfx::Rect& bounds = window_x11_->GetBoundsInScreen(); + tree_host->set_screen_bounds(bounds); + + // Send updated screen rectangle information to the renderer process so that + // popups are displayed in the correct location. + content::RenderWidgetHostImpl::From(web_contents()->GetRenderViewHost())-> + SendScreenRects(); +} + diff --git a/libcef/browser/browser_host_impl_mac.mm b/libcef/browser/browser_host_impl_mac.mm index abcc639eb..3f8d59b90 100644 --- a/libcef/browser/browser_host_impl_mac.mm +++ b/libcef/browser/browser_host_impl_mac.mm @@ -717,3 +717,6 @@ void CefBrowserHostImpl::PlatformTranslateMouseEvent( // timestamp - Mac OSX specific result.timeStampSeconds = currentEventTimestamp(); } + +void CefBrowserHostImpl::PlatformNotifyMoveOrResizeStarted() { +} diff --git a/libcef/browser/browser_host_impl_win.cc b/libcef/browser/browser_host_impl_win.cc index 7f46d11a9..a9d6ab085 100644 --- a/libcef/browser/browser_host_impl_win.cc +++ b/libcef/browser/browser_host_impl_win.cc @@ -31,10 +31,13 @@ #include "grit/ui_unscaled_resources.h" #include "net/base/mime_util.h" #include "third_party/WebKit/public/web/WebInputEvent.h" +#include "ui/aura/window_tree_host.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/win/shell.h" #include "ui/gfx/win/hwnd_util.h" +#include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h" #include "ui/views/widget/widget.h" +#include "ui/views/win/hwnd_message_handler_delegate.h" #include "ui/views/win/hwnd_util.h" #pragma comment(lib, "dwmapi.lib") @@ -601,6 +604,12 @@ LRESULT CALLBACK CefBrowserHostImpl::WndProc(HWND hwnd, UINT message, } return 0; + case WM_MOVING: + case WM_MOVE: + if (browser) + browser->NotifyMoveOrResizeStarted(); + return 0; + case WM_SETFOCUS: if (browser) browser->SetFocus(true); @@ -942,3 +951,24 @@ void CefBrowserHostImpl::PlatformTranslateMouseEvent( // timestamp result.timeStampSeconds = GetMessageTime() / 1000.0; } + +void CefBrowserHostImpl::PlatformNotifyMoveOrResizeStarted() { + if (IsWindowless()) + return; + + if (!window_widget_) + return; + + // Notify DesktopWindowTreeHostWin of move events so that screen rectangle + // information is communicated to the renderer process and popups are + // displayed in the correct location. + views::DesktopWindowTreeHostWin* tree_host = + static_cast( + aura::WindowTreeHost::GetForAcceleratedWidget( + HWNDForWidget(window_widget_))); + DCHECK(tree_host); + if (tree_host) { + // Cast to HWNDMessageHandlerDelegate so we can access HandleMove(). + static_cast(tree_host)->HandleMove(); + } +} diff --git a/libcef/browser/window_x11.cc b/libcef/browser/window_x11.cc index 931b35ca4..ef8438ecc 100644 --- a/libcef/browser/window_x11.cc +++ b/libcef/browser/window_x11.cc @@ -290,6 +290,15 @@ gfx::Rect CefWindowX11::GetBoundsInScreen() { return gfx::Rect(); } +views::DesktopWindowTreeHostX11* CefWindowX11::GetHost() { + if (browser_.get()) { + ::Window child = FindChild(xdisplay_, xwindow_); + if (child) + return views::DesktopWindowTreeHostX11::GetHostForXID(child); + } + return NULL; +} + bool CefWindowX11::CanDispatchEvent(const ui::PlatformEvent& event) { ::Window target = FindEventTarget(event); return target == xwindow_; @@ -317,14 +326,7 @@ uint32_t CefWindowX11::DispatchEvent(const ui::PlatformEvent& event) { changes.height = bounds.height(); XConfigureWindow(xdisplay_, child, CWHeight | CWWidth, &changes); - // Explicitly set the screen bounds so that WindowTreeHost::*Screen() - // methods return the correct results. - views::DesktopWindowTreeHostX11* window_tree_host = - views::DesktopWindowTreeHostX11::GetHostForXID(child); - if (window_tree_host) { - window_tree_host->set_screen_bounds( - CefWindowX11::GetBoundsInScreen()); - } + browser_->NotifyMoveOrResizeStarted(); } } break; @@ -385,23 +387,6 @@ uint32_t CefWindowX11::DispatchEvent(const ui::PlatformEvent& event) { base::Bind(&CefWindowX11::ContinueFocus, weak_ptr_factory_.GetWeakPtr()), 100); - - // Explicitly set the screen bounds so that WindowTreeHost::*Screen() - // methods return the correct results. This is done here to update the - // bounds for the case of a simple window move which will not result in - // a ConfigureEvent in the case that this window is hosted in a parent, - // i.e. the CefClient use case. - if (browser_.get()) { - ::Window child = FindChild(xdisplay_, xwindow_); - if (child) { - views::DesktopWindowTreeHostX11* window_tree_host = - views::DesktopWindowTreeHostX11::GetHostForXID(child); - if (window_tree_host) { - window_tree_host->set_screen_bounds( - CefWindowX11::GetBoundsInScreen()); - } - } - } } break; case FocusOut: @@ -454,3 +439,4 @@ void CefWindowX11::ContinueFocus() { browser_->SetFocus(true); focus_pending_ = false; } + diff --git a/libcef/browser/window_x11.h b/libcef/browser/window_x11.h index 7475e93fe..01e926566 100644 --- a/libcef/browser/window_x11.h +++ b/libcef/browser/window_x11.h @@ -16,6 +16,10 @@ #include "ui/gfx/rect.h" #include "ui/gfx/x/x11_atom_cache.h" +namespace views { +class DesktopWindowTreeHostX11; +} + // Object wrapper for an X11 Window. // Based on WindowTreeHostX11 and DesktopWindowTreeHostX11. class CefWindowX11 : public ui::PlatformEventDispatcher { @@ -36,6 +40,8 @@ class CefWindowX11 : public ui::PlatformEventDispatcher { gfx::Rect GetBoundsInScreen(); + views::DesktopWindowTreeHostX11* GetHost(); + // ui::PlatformEventDispatcher methods: virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE; virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE; diff --git a/libcef_dll/cpptoc/browser_host_cpptoc.cc b/libcef_dll/cpptoc/browser_host_cpptoc.cc index 5c90f7902..61a53c93c 100644 --- a/libcef_dll/cpptoc/browser_host_cpptoc.cc +++ b/libcef_dll/cpptoc/browser_host_cpptoc.cc @@ -637,6 +637,18 @@ void CEF_CALLBACK browser_host_send_capture_lost_event( CefBrowserHostCppToC::Get(self)->SendCaptureLostEvent(); } +void CEF_CALLBACK browser_host_notify_move_or_resize_started( + struct _cef_browser_host_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefBrowserHostCppToC::Get(self)->NotifyMoveOrResizeStarted(); +} + cef_text_input_context_t CEF_CALLBACK browser_host_get_nstext_input_context( struct _cef_browser_host_t* self) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -838,6 +850,8 @@ CefBrowserHostCppToC::CefBrowserHostCppToC(CefBrowserHost* cls) struct_.struct_.send_focus_event = browser_host_send_focus_event; struct_.struct_.send_capture_lost_event = browser_host_send_capture_lost_event; + struct_.struct_.notify_move_or_resize_started = + browser_host_notify_move_or_resize_started; struct_.struct_.get_nstext_input_context = browser_host_get_nstext_input_context; struct_.struct_.handle_key_event_before_text_input_client = diff --git a/libcef_dll/ctocpp/browser_host_ctocpp.cc b/libcef_dll/ctocpp/browser_host_ctocpp.cc index dd5b09fc0..dd5636527 100644 --- a/libcef_dll/ctocpp/browser_host_ctocpp.cc +++ b/libcef_dll/ctocpp/browser_host_ctocpp.cc @@ -495,6 +495,16 @@ void CefBrowserHostCToCpp::SendCaptureLostEvent() { struct_->send_capture_lost_event(struct_); } +void CefBrowserHostCToCpp::NotifyMoveOrResizeStarted() { + if (CEF_MEMBER_MISSING(struct_, notify_move_or_resize_started)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->notify_move_or_resize_started(struct_); +} + CefTextInputContext CefBrowserHostCToCpp::GetNSTextInputContext() { if (CEF_MEMBER_MISSING(struct_, get_nstext_input_context)) return NULL; diff --git a/libcef_dll/ctocpp/browser_host_ctocpp.h b/libcef_dll/ctocpp/browser_host_ctocpp.h index 8cb5a624c..4e6e2493c 100644 --- a/libcef_dll/ctocpp/browser_host_ctocpp.h +++ b/libcef_dll/ctocpp/browser_host_ctocpp.h @@ -78,6 +78,7 @@ class CefBrowserHostCToCpp int deltaY) OVERRIDE; virtual void SendFocusEvent(bool setFocus) OVERRIDE; virtual void SendCaptureLostEvent() OVERRIDE; + virtual void NotifyMoveOrResizeStarted() OVERRIDE; virtual CefTextInputContext GetNSTextInputContext() OVERRIDE; virtual void HandleKeyEventBeforeTextInputClient( CefEventHandle keyEvent) OVERRIDE; diff --git a/patch/patches/views_widget_180.patch b/patch/patches/views_widget_180.patch index f561c3efe..c7f99a23a 100644 --- a/patch/patches/views_widget_180.patch +++ b/patch/patches/views_widget_180.patch @@ -57,7 +57,7 @@ index d184ae4..92ffd42 100644 if (input_method) input_method->OnBlur(); diff --git desktop_aura/desktop_window_tree_host_x11.cc desktop_aura/desktop_window_tree_host_x11.cc -index 9831992..081a56a0 100644 +index 9831992..23a00a9 100644 --- desktop_aura/desktop_window_tree_host_x11.cc +++ desktop_aura/desktop_window_tree_host_x11.cc @@ -147,7 +147,8 @@ DesktopWindowTreeHostX11::DesktopWindowTreeHostX11( @@ -98,7 +98,16 @@ index 9831992..081a56a0 100644 return bounds_; } -@@ -933,6 +939,8 @@ void DesktopWindowTreeHostX11::SetBounds(const gfx::Rect& requested_bounds) { +@@ -879,6 +885,8 @@ void DesktopWindowTreeHostX11::Hide() { + } + + gfx::Rect DesktopWindowTreeHostX11::GetBounds() const { ++ if (!screen_bounds_.IsEmpty()) ++ return screen_bounds_; + return bounds_; + } + +@@ -933,6 +941,8 @@ void DesktopWindowTreeHostX11::SetBounds(const gfx::Rect& requested_bounds) { } gfx::Point DesktopWindowTreeHostX11::GetLocationOnNativeScreen() const { @@ -107,7 +116,7 @@ index 9831992..081a56a0 100644 return bounds_.origin(); } -@@ -1085,10 +1093,14 @@ void DesktopWindowTreeHostX11::InitX11Window( +@@ -1085,10 +1095,14 @@ void DesktopWindowTreeHostX11::InitX11Window( } } @@ -123,7 +132,7 @@ index 9831992..081a56a0 100644 bounds_.x(), bounds_.y(), bounds_.width(), bounds_.height(), 0, // border width -@@ -1706,6 +1718,10 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent( +@@ -1706,6 +1720,10 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent( } break; } diff --git a/tests/cefclient/cefclient_gtk.cpp b/tests/cefclient/cefclient_gtk.cpp index 45e3deed4..6047e1c83 100644 --- a/tests/cefclient/cefclient_gtk.cpp +++ b/tests/cefclient/cefclient_gtk.cpp @@ -205,6 +205,24 @@ gboolean WindowState(GtkWidget* widget, return TRUE; } +gboolean WindowConfigure(GtkWindow* window, + GdkEvent* event, + gpointer data) { + // Called when size, position or stack order changes. + if (g_handler) { + CefRefPtr browser = g_handler->GetBrowser(); + if (browser) { + // Notify the browser of move/resize events so that: + // - Popup windows are displayed in the correct location and dismissed + // when the window moves. + // - Drag&drop areas are updated accordingly. + browser->GetHost()->NotifyMoveOrResizeStarted(); + } + } + + return FALSE; // Don't stop this message. +} + // Callback for Tests > Get Source... menu item. gboolean GetSourceActivated(GtkWidget* widget) { if (g_handler.get() && g_handler->GetBrowserId()) @@ -454,6 +472,8 @@ int main(int argc, char* argv[]) { G_CALLBACK(WindowFocusIn), NULL); g_signal_connect(window, "window-state-event", G_CALLBACK(WindowState), NULL); + g_signal_connect(G_OBJECT(window), "configure-event", + G_CALLBACK(WindowConfigure), NULL); GtkWidget* vbox = gtk_vbox_new(FALSE, 0); g_signal_connect(vbox, "size-allocate", diff --git a/tests/cefclient/cefclient_win.cpp b/tests/cefclient/cefclient_win.cpp index 7e0237310..7b57b44e6 100644 --- a/tests/cefclient/cefclient_win.cpp +++ b/tests/cefclient/cefclient_win.cpp @@ -645,6 +645,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, } } break; + case WM_MOVING: + case WM_MOVE: + // Notify the browser of move events so that popup windows are displayed + // in the correct location and dismissed when the window moves. + if (g_handler.get() && g_handler->GetBrowser()) + g_handler->GetBrowser()->GetHost()->NotifyMoveOrResizeStarted(); + return 0; + case WM_ERASEBKGND: if (g_handler.get() && g_handler->GetBrowser()) { CefWindowHandle hwnd =