Linux: Use Aura to display context menus (issue #1258)

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1710 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2014-05-23 17:47:07 +00:00
parent aeb1aa7b52
commit 79bd4dd93c
11 changed files with 423 additions and 301 deletions

View File

@ -1093,6 +1093,8 @@
'libcef/browser/javascript_dialog_linux.cc',
'libcef/browser/menu_creator_runner_linux.cc',
'libcef/browser/menu_creator_runner_linux.h',
'libcef/browser/window_x11.cc',
'libcef/browser/window_x11.h',
#Include sources for printing.
'<(DEPTH)/chrome/renderer/printing/print_web_view_helper_linux.cc',
],

View File

@ -245,6 +245,14 @@ class CefBrowserHostImpl : public CefBrowserHost,
CefRefPtr<CefClient> client() const { return client_; }
int browser_id() const;
#if defined(USE_AURA)
views::Widget* window_widget() const { return window_widget_; }
#endif
#if defined(USE_X11)
CefWindowX11* window_x11() const { return window_x11_; }
#endif
// Returns the URL that is currently loading (or loaded) in the main frame.
GURL GetLoadingURL();

View File

@ -6,13 +6,10 @@
#include "libcef/browser/browser_host_impl.h"
#include <sys/sysinfo.h>
#include <X11/extensions/XInput2.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "libcef/browser/context.h"
#include "libcef/browser/window_delegate_view.h"
#include "libcef/browser/window_x11.h"
#include "libcef/browser/thread_util.h"
#include "base/bind.h"
@ -22,9 +19,6 @@
#include "content/public/common/renderer_preferences.h"
#include "third_party/WebKit/public/web/gtk/WebInputEventFactory.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/views/widget/widget.h"
namespace {
@ -37,296 +31,8 @@ long GetSystemUptime() {
return 0;
}
const char* kAtomsToCache[] = {
"WM_DELETE_WINDOW",
"WM_PROTOCOLS",
"_NET_WM_PING",
"_NET_WM_PID",
NULL
};
::Window FindEventTarget(const base::NativeEvent& xev) {
::Window target = xev->xany.window;
if (xev->type == GenericEvent)
target = static_cast<XIDeviceEvent*>(xev->xcookie.data)->event;
return target;
}
::Window FindChild(::Display* display, ::Window window) {
::Window root;
::Window parent;
::Window* children;
unsigned int nchildren;
if (XQueryTree(display, window, &root, &parent, &children, &nchildren)) {
DCHECK_EQ(1U, nchildren);
return children[0];
}
return None;
}
} // namespace
#if defined(USE_X11)
CEF_EXPORT XDisplay* cef_get_xdisplay() {
if (!CEF_CURRENTLY_ON(CEF_UIT))
return NULL;
return gfx::GetXDisplay();
}
#endif
// Object wrapper for an X11 Window.
// Based on WindowTreeHostX11 and DesktopWindowTreeHostX11.
class CefWindowX11 : public ui::PlatformEventDispatcher {
public:
CefWindowX11(CefRefPtr<CefBrowserHostImpl> browser,
::Window parent_xwindow,
const gfx::Rect& bounds)
: browser_(browser),
xdisplay_(gfx::GetXDisplay()),
parent_xwindow_(parent_xwindow),
xwindow_(0),
window_mapped_(false),
bounds_(bounds),
atom_cache_(xdisplay_, kAtomsToCache) {
if (parent_xwindow_ == None)
parent_xwindow_ = DefaultRootWindow(xdisplay_);
XSetWindowAttributes swa;
memset(&swa, 0, sizeof(swa));
swa.background_pixmap = None;
swa.override_redirect = false;
xwindow_ = XCreateWindow(
xdisplay_, parent_xwindow_,
bounds.x(), bounds.y(), bounds.width(), bounds.height(),
0, // border width
CopyFromParent, // depth
InputOutput,
CopyFromParent, // visual
CWBackPixmap | CWOverrideRedirect,
&swa);
if (ui::PlatformEventSource::GetInstance())
ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
long event_mask = FocusChangeMask | StructureNotifyMask | PropertyChangeMask;
XSelectInput(xdisplay_, xwindow_, event_mask);
XFlush(xdisplay_);
// TODO(erg): We currently only request window deletion events. We also
// should listen for activation events and anything else that GTK+ listens
// for, and do something useful.
::Atom protocols[2];
protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
// We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
// the desktop environment.
XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
// Likewise, the X server needs to know this window's pid so it knows which
// program to kill if the window hangs.
// XChangeProperty() expects "pid" to be long.
COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
long pid = getpid();
XChangeProperty(xdisplay_,
xwindow_,
atom_cache_.GetAtom("_NET_WM_PID"),
XA_CARDINAL,
32,
PropModeReplace,
reinterpret_cast<unsigned char*>(&pid), 1);
// Allow subclasses to create and cache additional atoms.
atom_cache_.allow_uncached_atoms();
}
virtual ~CefWindowX11() {
DCHECK(!xwindow_);
if (ui::PlatformEventSource::GetInstance())
ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
}
void Close() {
XEvent ev = {0};
ev.xclient.type = ClientMessage;
ev.xclient.window = xwindow_;
ev.xclient.message_type = atom_cache_.GetAtom("WM_PROTOCOLS");
ev.xclient.format = 32;
ev.xclient.data.l[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
ev.xclient.data.l[1] = CurrentTime;
XSendEvent(xdisplay_, xwindow_, False, NoEventMask, &ev);
}
void Show() {
if (xwindow_ == None)
return;
if (!window_mapped_) {
// Before we map the window, set size hints. Otherwise, some window managers
// will ignore toplevel XMoveWindow commands.
XSizeHints size_hints;
size_hints.flags = PPosition | PWinGravity;
size_hints.x = bounds_.x();
size_hints.y = bounds_.y();
// Set StaticGravity so that the window position is not affected by the
// frame width when running with window manager.
size_hints.win_gravity = StaticGravity;
XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
XMapWindow(xdisplay_, xwindow_);
// We now block until our window is mapped. Some X11 APIs will crash and
// burn if passed |xwindow_| before the window is mapped, and XMapWindow is
// asynchronous.
if (ui::X11EventSource::GetInstance())
ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_);
window_mapped_ = true;
}
}
void Hide() {
if (xwindow_ == None)
return;
if (window_mapped_) {
XWithdrawWindow(xdisplay_, xwindow_, 0);
window_mapped_ = false;
}
}
void SetBounds(const gfx::Rect& bounds) {
if (xwindow_ == None)
return;
bool origin_changed = bounds_.origin() != bounds.origin();
bool size_changed = bounds_.size() != bounds.size();
XWindowChanges changes = {0};
unsigned value_mask = 0;
if (size_changed) {
changes.width = bounds.width();
changes.height = bounds.height();
value_mask = CWHeight | CWWidth;
}
if (origin_changed) {
changes.x = bounds.x();
changes.y = bounds.y();
value_mask |= CWX | CWY;
}
if (value_mask)
XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
}
// ui::PlatformEventDispatcher methods:
virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE {
::Window target = FindEventTarget(event);
return target == xwindow_;
}
virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE {
XEvent* xev = event;
switch (xev->type) {
case ConfigureNotify: {
DCHECK_EQ(xwindow_, xev->xconfigure.event);
DCHECK_EQ(xwindow_, xev->xconfigure.window);
// It's possible that the X window may be resized by some other means
// than from within Aura (e.g. the X window manager can change the
// size). Make sure the root window size is maintained properly.
gfx::Rect bounds(xev->xconfigure.x, xev->xconfigure.y,
xev->xconfigure.width, xev->xconfigure.height);
bounds_ = bounds;
::Window child = FindChild(xdisplay_, xwindow_);
if (child) {
// Resize the child DesktopWindowTreeHostX11 to match this window.
XWindowChanges changes = {0};
changes.width = bounds.width();
changes.height = bounds.height();
XConfigureWindow(xdisplay_, child, CWHeight | CWWidth, &changes);
}
break;
}
case ClientMessage: {
Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]);
if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
// We have received a close message from the window manager.
if (browser_->destruction_state() <=
CefBrowserHostImpl::DESTRUCTION_STATE_PENDING) {
if (browser_->destruction_state() ==
CefBrowserHostImpl::DESTRUCTION_STATE_NONE) {
// Request that the browser close.
browser_->CloseBrowser(false);
}
// Cancel the close.
} else {
// Allow the close.
XDestroyWindow(xdisplay_, xwindow_);
}
} else if (message_type == atom_cache_.GetAtom("_NET_WM_PING")) {
XEvent reply_event = *xev;
reply_event.xclient.window = parent_xwindow_;
XSendEvent(xdisplay_,
reply_event.xclient.window,
False,
SubstructureRedirectMask | SubstructureNotifyMask,
&reply_event);
XFlush(xdisplay_);
}
break;
}
case DestroyNotify:
xwindow_ = None;
// Force the browser to be destroyed and release the reference added
// in PlatformCreateWindow().
browser_->WindowDestroyed();
delete this;
break;
case FocusIn:
// This message is recieved first followed by a "_NET_ACTIVE_WINDOW"
// message sent to the root window. When X11DesktopHandler handles the
// "_NET_ACTIVE_WINDOW" message it will erroneously mark the WebView
// (hosted in a DesktopWindowTreeHostX11) as unfocused. Use a delayed
// task here to restore the WebView's focus state.
CEF_POST_DELAYED_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::OnSetFocus, browser_,
FOCUS_SOURCE_SYSTEM),
100);
break;
}
return ui::POST_DISPATCH_STOP_PROPAGATION;
}
::Window xwindow() const { return xwindow_; }
gfx::Rect bounds() const { return bounds_; }
private:
CefRefPtr<CefBrowserHostImpl> browser_;
// The display and the native X window hosting the root window.
XDisplay* xdisplay_;
::Window parent_xwindow_;
::Window xwindow_;
// Is the window mapped to the screen?
bool window_mapped_;
// The bounds of |xwindow_|.
gfx::Rect bounds_;
ui::X11AtomCache atom_cache_;
DISALLOW_COPY_AND_ASSIGN(CefWindowX11);
};
bool CefBrowserHostImpl::PlatformCreateWindow() {
DCHECK(!window_x11_);
DCHECK(!window_widget_);

View File

@ -193,6 +193,10 @@ void CefMenuCreator::MenuClosed(CefRefPtr<CefMenuModelImpl> source) {
}
}
bool CefMenuCreator::FormatLabel(base::string16& label) {
return runner_->FormatLabel(label);
}
void CefMenuCreator::CreateDefaultModel() {
if (params_.is_editable) {
// Editable node.

View File

@ -24,6 +24,7 @@ class CefMenuCreator : public CefMenuModelImpl::Delegate {
public:
virtual ~Runner() {}
virtual bool RunContextMenu(CefMenuCreator* manager) =0;
virtual bool FormatLabel(base::string16& label) { return false; }
};
explicit CefMenuCreator(CefBrowserHostImpl* browser);
@ -49,6 +50,7 @@ class CefMenuCreator : public CefMenuModelImpl::Delegate {
cef_event_flags_t event_flags) OVERRIDE;
virtual void MenuWillShow(CefRefPtr<CefMenuModelImpl> source) OVERRIDE;
virtual void MenuClosed(CefRefPtr<CefMenuModelImpl> source) OVERRIDE;
virtual bool FormatLabel(base::string16& label) OVERRIDE;
// Create the default menu model.
void CreateDefaultModel();

View File

@ -1,8 +1,19 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.
// Copyright 2014 The Chromium Embedded Framework Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.
#include "libcef/browser/menu_creator_runner_linux.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/window_x11.h"
#include "base/strings/string_util.h"
#include "ui/aura/window.h"
#include "ui/gfx/point.h"
// Used to silence warnings about unused variables.
#if !defined(UNUSED)
#define UNUSED(x) ((void)(x))
#endif
CefMenuCreatorRunnerLinux::CefMenuCreatorRunnerLinux() {
}
@ -11,6 +22,30 @@ CefMenuCreatorRunnerLinux::~CefMenuCreatorRunnerLinux() {
}
bool CefMenuCreatorRunnerLinux::RunContextMenu(CefMenuCreator* manager) {
NOTIMPLEMENTED();
return false;
menu_.reset(new views::MenuRunner(manager->model()));
// We can't use aura::Window::GetBoundsInScreen on Linux because it will
// return bounds from DesktopWindowTreeHostX11 which in our case is relative
// to the parent window instead of the root window (screen).
const gfx::Rect& bounds_in_screen =
manager->browser()->window_x11()->GetBoundsInScreen();
gfx::Point screen_point =
gfx::Point(bounds_in_screen.x() + manager->params().x,
bounds_in_screen.y() + manager->params().y);
views::MenuRunner::RunResult result =
menu_->RunMenuAt(manager->browser()->window_widget(),
NULL, gfx::Rect(screen_point, gfx::Size()),
views::MenuItemView::TOPRIGHT, ui::MENU_SOURCE_NONE,
views::MenuRunner::CONTEXT_MENU);
UNUSED(result);
return true;
}
bool CefMenuCreatorRunnerLinux::FormatLabel(base::string16& label) {
// Remove the accelerator indicator (&) from label strings.
const char16 replace[] = {L'&', 0};
return base::ReplaceChars(label, replace, base::string16(), &label);
}

View File

@ -8,6 +8,9 @@
#include "libcef/browser/menu_creator.h"
#include "base/memory/scoped_ptr.h"
#include "ui/views/controls/menu/menu_runner.h"
class CefMenuCreatorRunnerLinux: public CefMenuCreator::Runner {
public:
CefMenuCreatorRunnerLinux();
@ -15,6 +18,10 @@ class CefMenuCreatorRunnerLinux: public CefMenuCreator::Runner {
// CefMemoryManager::Runner methods.
virtual bool RunContextMenu(CefMenuCreator* manager) OVERRIDE;
virtual bool FormatLabel(base::string16& label) OVERRIDE;
private:
scoped_ptr<views::MenuRunner> menu_;
};
#endif // CEF_LIBCEF_BROWSER_MENU_MANAGER_RUNNER_LINUX_H_

View File

@ -65,7 +65,7 @@ class CefSimpleMenuModel : public ui::MenuModel {
}
virtual base::string16 GetLabelAt(int index) const OVERRIDE {
return impl_->GetLabelAt(index).ToString16();
return impl_->GetFormattedLabelAt(index);
}
virtual bool IsItemDynamicAt(int index) const OVERRIDE {
@ -641,6 +641,12 @@ void CefMenuModelImpl::MenuClosed() {
base::Bind(&CefMenuModelImpl::OnMenuClosed, this));
}
base::string16 CefMenuModelImpl::GetFormattedLabelAt(int index) {
base::string16 label = GetLabelAt(index).ToString16();
delegate_->FormatLabel(label);
return label;
}
bool CefMenuModelImpl::VerifyRefCount() {
if (!VerifyContext())
return false;

View File

@ -31,6 +31,9 @@ class CefMenuModelImpl : public CefMenuModel {
// Notifies the delegate that the menu has closed.
virtual void MenuClosed(CefRefPtr<CefMenuModelImpl> source) =0;
// Allows the delegate to modify a menu item label before it's displayed.
virtual bool FormatLabel(base::string16& label) =0;
protected:
virtual ~Delegate() {}
};
@ -104,6 +107,7 @@ class CefMenuModelImpl : public CefMenuModel {
void ActivatedAt(int index, cef_event_flags_t event_flags);
void MenuWillShow();
void MenuClosed();
base::string16 GetFormattedLabelAt(int index);
// Verify that only a single reference exists to all CefMenuModelImpl objects.
bool VerifyRefCount();

View File

@ -0,0 +1,286 @@
// Copyright 2014 The Chromium Embedded Framework Authors.
// Portions copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libcef/browser/window_x11.h"
#include "libcef/browser/thread_util.h"
#include <X11/extensions/XInput2.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include "ui/events/platform/x11/x11_event_source.h"
namespace {
const char* kAtomsToCache[] = {
"WM_DELETE_WINDOW",
"WM_PROTOCOLS",
"_NET_WM_PING",
"_NET_WM_PID",
NULL
};
::Window FindEventTarget(const base::NativeEvent& xev) {
::Window target = xev->xany.window;
if (xev->type == GenericEvent)
target = static_cast<XIDeviceEvent*>(xev->xcookie.data)->event;
return target;
}
::Window FindChild(::Display* display, ::Window window) {
::Window root;
::Window parent;
::Window* children;
unsigned int nchildren;
if (XQueryTree(display, window, &root, &parent, &children, &nchildren)) {
DCHECK_EQ(1U, nchildren);
return children[0];
}
return None;
}
} // namespace
CEF_EXPORT XDisplay* cef_get_xdisplay() {
if (!CEF_CURRENTLY_ON(CEF_UIT))
return NULL;
return gfx::GetXDisplay();
}
CefWindowX11::CefWindowX11(CefRefPtr<CefBrowserHostImpl> browser,
::Window parent_xwindow,
const gfx::Rect& bounds)
: browser_(browser),
xdisplay_(gfx::GetXDisplay()),
parent_xwindow_(parent_xwindow),
xwindow_(0),
window_mapped_(false),
bounds_(bounds),
atom_cache_(xdisplay_, kAtomsToCache) {
if (parent_xwindow_ == None)
parent_xwindow_ = DefaultRootWindow(xdisplay_);
XSetWindowAttributes swa;
memset(&swa, 0, sizeof(swa));
swa.background_pixmap = None;
swa.override_redirect = false;
xwindow_ = XCreateWindow(
xdisplay_, parent_xwindow_,
bounds.x(), bounds.y(), bounds.width(), bounds.height(),
0, // border width
CopyFromParent, // depth
InputOutput,
CopyFromParent, // visual
CWBackPixmap | CWOverrideRedirect,
&swa);
if (ui::PlatformEventSource::GetInstance())
ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
long event_mask = FocusChangeMask | StructureNotifyMask | PropertyChangeMask;
XSelectInput(xdisplay_, xwindow_, event_mask);
XFlush(xdisplay_);
// TODO(erg): We currently only request window deletion events. We also
// should listen for activation events and anything else that GTK+ listens
// for, and do something useful.
::Atom protocols[2];
protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
// We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
// the desktop environment.
XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
// Likewise, the X server needs to know this window's pid so it knows which
// program to kill if the window hangs.
// XChangeProperty() expects "pid" to be long.
COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
long pid = getpid();
XChangeProperty(xdisplay_,
xwindow_,
atom_cache_.GetAtom("_NET_WM_PID"),
XA_CARDINAL,
32,
PropModeReplace,
reinterpret_cast<unsigned char*>(&pid), 1);
// Allow subclasses to create and cache additional atoms.
atom_cache_.allow_uncached_atoms();
}
CefWindowX11::~CefWindowX11() {
DCHECK(!xwindow_);
if (ui::PlatformEventSource::GetInstance())
ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
}
void CefWindowX11::Close() {
XEvent ev = {0};
ev.xclient.type = ClientMessage;
ev.xclient.window = xwindow_;
ev.xclient.message_type = atom_cache_.GetAtom("WM_PROTOCOLS");
ev.xclient.format = 32;
ev.xclient.data.l[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
ev.xclient.data.l[1] = CurrentTime;
XSendEvent(xdisplay_, xwindow_, False, NoEventMask, &ev);
}
void CefWindowX11::Show() {
if (xwindow_ == None)
return;
if (!window_mapped_) {
// Before we map the window, set size hints. Otherwise, some window managers
// will ignore toplevel XMoveWindow commands.
XSizeHints size_hints;
size_hints.flags = PPosition | PWinGravity;
size_hints.x = bounds_.x();
size_hints.y = bounds_.y();
// Set StaticGravity so that the window position is not affected by the
// frame width when running with window manager.
size_hints.win_gravity = StaticGravity;
XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
XMapWindow(xdisplay_, xwindow_);
// We now block until our window is mapped. Some X11 APIs will crash and
// burn if passed |xwindow_| before the window is mapped, and XMapWindow is
// asynchronous.
if (ui::X11EventSource::GetInstance())
ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_);
window_mapped_ = true;
}
}
void CefWindowX11::Hide() {
if (xwindow_ == None)
return;
if (window_mapped_) {
XWithdrawWindow(xdisplay_, xwindow_, 0);
window_mapped_ = false;
}
}
void CefWindowX11::SetBounds(const gfx::Rect& bounds) {
if (xwindow_ == None)
return;
bool origin_changed = bounds_.origin() != bounds.origin();
bool size_changed = bounds_.size() != bounds.size();
XWindowChanges changes = {0};
unsigned value_mask = 0;
if (size_changed) {
changes.width = bounds.width();
changes.height = bounds.height();
value_mask = CWHeight | CWWidth;
}
if (origin_changed) {
changes.x = bounds.x();
changes.y = bounds.y();
value_mask |= CWX | CWY;
}
if (value_mask)
XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
}
gfx::Rect CefWindowX11::GetBoundsInScreen() {
int x, y;
Window child;
if (XTranslateCoordinates(xdisplay_, xwindow_, DefaultRootWindow(xdisplay_),
0, 0, &x, &y, &child)) {
return gfx::Rect(gfx::Point(x, y), bounds_.size());
}
return gfx::Rect();
}
bool CefWindowX11::CanDispatchEvent(const ui::PlatformEvent& event) {
::Window target = FindEventTarget(event);
return target == xwindow_;
}
uint32_t CefWindowX11::DispatchEvent(const ui::PlatformEvent& event) {
XEvent* xev = event;
switch (xev->type) {
case ConfigureNotify: {
DCHECK_EQ(xwindow_, xev->xconfigure.event);
DCHECK_EQ(xwindow_, xev->xconfigure.window);
// It's possible that the X window may be resized by some other means
// than from within Aura (e.g. the X window manager can change the
// size). Make sure the root window size is maintained properly.
gfx::Rect bounds(xev->xconfigure.x, xev->xconfigure.y,
xev->xconfigure.width, xev->xconfigure.height);
bounds_ = bounds;
::Window child = FindChild(xdisplay_, xwindow_);
if (child) {
// Resize the child DesktopWindowTreeHostX11 to match this window.
XWindowChanges changes = {0};
changes.width = bounds.width();
changes.height = bounds.height();
XConfigureWindow(xdisplay_, child, CWHeight | CWWidth, &changes);
}
break;
}
case ClientMessage: {
Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]);
if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
// We have received a close message from the window manager.
if (browser_->destruction_state() <=
CefBrowserHostImpl::DESTRUCTION_STATE_PENDING) {
if (browser_->destruction_state() ==
CefBrowserHostImpl::DESTRUCTION_STATE_NONE) {
// Request that the browser close.
browser_->CloseBrowser(false);
}
// Cancel the close.
} else {
// Allow the close.
XDestroyWindow(xdisplay_, xwindow_);
}
} else if (message_type == atom_cache_.GetAtom("_NET_WM_PING")) {
XEvent reply_event = *xev;
reply_event.xclient.window = parent_xwindow_;
XSendEvent(xdisplay_,
reply_event.xclient.window,
False,
SubstructureRedirectMask | SubstructureNotifyMask,
&reply_event);
XFlush(xdisplay_);
}
break;
}
case DestroyNotify:
xwindow_ = None;
// Force the browser to be destroyed and release the reference added
// in PlatformCreateWindow().
browser_->WindowDestroyed();
delete this;
break;
case FocusIn:
// This message is recieved first followed by a "_NET_ACTIVE_WINDOW"
// message sent to the root window. When X11DesktopHandler handles the
// "_NET_ACTIVE_WINDOW" message it will erroneously mark the WebView
// (hosted in a DesktopWindowTreeHostX11) as unfocused. Use a delayed
// task here to restore the WebView's focus state.
CEF_POST_DELAYED_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::OnSetFocus, browser_,
FOCUS_SOURCE_SYSTEM),
100);
break;
}
return ui::POST_DISPATCH_STOP_PROPAGATION;
}

View File

@ -0,0 +1,62 @@
// Copyright 2014 The Chromium Embedded Framework Authors.
// Portions copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_WINDOW_X11_H_
#define CEF_LIBCEF_BROWSER_WINDOW_X11_H_
#pragma once
#include <X11/Xlib.h>
#include "libcef/browser/browser_host_impl.h"
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/x/x11_atom_cache.h"
// Object wrapper for an X11 Window.
// Based on WindowTreeHostX11 and DesktopWindowTreeHostX11.
class CefWindowX11 : public ui::PlatformEventDispatcher {
public:
CefWindowX11(CefRefPtr<CefBrowserHostImpl> browser,
::Window parent_xwindow,
const gfx::Rect& bounds);
virtual ~CefWindowX11();
void Close();
void Show();
void Hide();
void SetBounds(const gfx::Rect& bounds);
gfx::Rect GetBoundsInScreen();
// ui::PlatformEventDispatcher methods:
virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
::Window xwindow() const { return xwindow_; }
gfx::Rect bounds() const { return bounds_; }
private:
CefRefPtr<CefBrowserHostImpl> browser_;
// The display and the native X window hosting the root window.
::Display* xdisplay_;
::Window parent_xwindow_;
::Window xwindow_;
// Is the window mapped to the screen?
bool window_mapped_;
// The bounds of |xwindow_|.
gfx::Rect bounds_;
ui::X11AtomCache atom_cache_;
DISALLOW_COPY_AND_ASSIGN(CefWindowX11);
};
#endif // CEF_LIBCEF_BROWSER_WINDOW_X11_H_