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
This commit is contained in:
Marshall Greenblatt 2014-10-29 18:14:47 +00:00
parent 0cbadc6e07
commit 470518a52e
15 changed files with 181 additions and 29 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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.
// -----------------------------------------------------------------------------

View File

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

View File

@ -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 <sys/sysinfo.h>
#include <X11/cursorfont.h>
@ -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();
}

View File

@ -717,3 +717,6 @@ void CefBrowserHostImpl::PlatformTranslateMouseEvent(
// timestamp - Mac OSX specific
result.timeStampSeconds = currentEventTimestamp();
}
void CefBrowserHostImpl::PlatformNotifyMoveOrResizeStarted() {
}

View File

@ -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<views::DesktopWindowTreeHostWin*>(
aura::WindowTreeHost::GetForAcceleratedWidget(
HWNDForWidget(window_widget_)));
DCHECK(tree_host);
if (tree_host) {
// Cast to HWNDMessageHandlerDelegate so we can access HandleMove().
static_cast<views::HWNDMessageHandlerDelegate*>(tree_host)->HandleMove();
}
}

View File

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

View File

@ -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;

View File

@ -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 =

View File

@ -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;

View File

@ -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;

View File

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

View File

@ -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<CefBrowser> 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",

View File

@ -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 =