Linux: Add drag&drop support (issue #1258).

- Requires proper handling of the "XdndProxy" property on the top-level window. This currently works in cefsimple but not cefclient (perhaps due to https://bugzilla.gnome.org/show_bug.cgi?id=653264).

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1759 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2014-07-08 22:37:06 +00:00
parent 81f8883b4a
commit 824f8f4009
5 changed files with 154 additions and 37 deletions

View File

@ -417,8 +417,10 @@ void CefBrowserHostImpl::PlatformTranslateMouseEvent(
GetBrowser(), GetBrowser(),
result.x, result.y, result.x, result.y,
result.globalX, result.globalY); result.globalX, result.globalY);
} else { } else if (window_x11_) {
// TODO(linux): Convert global{X,Y} to screen coordinates. const gfx::Point& origin = window_x11_->bounds().origin();
result.globalX += origin.x();
result.globalY += origin.y();
} }
// modifiers // modifiers

View File

@ -12,14 +12,23 @@
#include "ui/base/x/x11_util.h" #include "ui/base/x/x11_util.h"
#include "ui/events/platform/x11/x11_event_source.h" #include "ui/events/platform/x11/x11_event_source.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
#include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
namespace { namespace {
const char kWMDeleteWindow[] = "WM_DELETE_WINDOW";
const char kWMProtocols[] = "WM_PROTOCOLS";
const char kNetWMPing[] = "_NET_WM_PING";
const char kNetWMPid[] = "_NET_WM_PID";
const char kXdndProxy[] = "XdndProxy";
const char* kAtomsToCache[] = { const char* kAtomsToCache[] = {
"WM_DELETE_WINDOW", kWMDeleteWindow,
"WM_PROTOCOLS", kWMProtocols,
"_NET_WM_PING", kNetWMPing,
"_NET_WM_PID", kNetWMPid,
kXdndProxy,
NULL NULL
}; };
@ -90,8 +99,8 @@ CefWindowX11::CefWindowX11(CefRefPtr<CefBrowserHostImpl> browser,
// should listen for activation events and anything else that GTK+ listens // should listen for activation events and anything else that GTK+ listens
// for, and do something useful. // for, and do something useful.
::Atom protocols[2]; ::Atom protocols[2];
protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW"); protocols[0] = atom_cache_.GetAtom(kWMDeleteWindow);
protocols[1] = atom_cache_.GetAtom("_NET_WM_PING"); protocols[1] = atom_cache_.GetAtom(kNetWMPing);
XSetWMProtocols(xdisplay_, xwindow_, protocols, 2); XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
// We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
@ -105,7 +114,7 @@ CefWindowX11::CefWindowX11(CefRefPtr<CefBrowserHostImpl> browser,
long pid = getpid(); long pid = getpid();
XChangeProperty(xdisplay_, XChangeProperty(xdisplay_,
xwindow_, xwindow_,
atom_cache_.GetAtom("_NET_WM_PID"), atom_cache_.GetAtom(kNetWMPid),
XA_CARDINAL, XA_CARDINAL,
32, 32,
PropModeReplace, PropModeReplace,
@ -125,9 +134,9 @@ void CefWindowX11::Close() {
XEvent ev = {0}; XEvent ev = {0};
ev.xclient.type = ClientMessage; ev.xclient.type = ClientMessage;
ev.xclient.window = xwindow_; ev.xclient.window = xwindow_;
ev.xclient.message_type = atom_cache_.GetAtom("WM_PROTOCOLS"); ev.xclient.message_type = atom_cache_.GetAtom(kWMProtocols);
ev.xclient.format = 32; ev.xclient.format = 32;
ev.xclient.data.l[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW"); ev.xclient.data.l[0] = atom_cache_.GetAtom(kWMDeleteWindow);
ev.xclient.data.l[1] = CurrentTime; ev.xclient.data.l[1] = CurrentTime;
XSendEvent(xdisplay_, xwindow_, False, NoEventMask, &ev); XSendEvent(xdisplay_, xwindow_, False, NoEventMask, &ev);
} }
@ -245,37 +254,77 @@ uint32_t CefWindowX11::DispatchEvent(const ui::PlatformEvent& event) {
changes.width = bounds.width(); changes.width = bounds.width();
changes.height = bounds.height(); changes.height = bounds.height();
XConfigureWindow(xdisplay_, child, CWHeight | CWWidth, &changes); 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(bounds);
// Find the top-most window containing the browser window.
views::X11TopmostWindowFinder finder;
::Window topmost_window = finder.FindWindowAt(bounds.origin());
DCHECK(topmost_window);
// Configure the drag&drop proxy property for the top-most window so
// that all drag&drop-related messages will be sent to the child
// DesktopWindowTreeHostX11. The proxy property is referenced by
// DesktopDragDropClientAuraX11::FindWindowFor.
::Window proxy_target = gfx::kNullAcceleratedWidget;
ui::GetXIDProperty(topmost_window, kXdndProxy, &proxy_target);
if (proxy_target != child) {
// Set the proxy target for the top-most window.
XChangeProperty(xdisplay_,
topmost_window,
atom_cache_.GetAtom(kXdndProxy),
XA_WINDOW,
32,
PropModeReplace,
reinterpret_cast<unsigned char*>(&child), 1);
// Do the same for the proxy target per the spec.
XChangeProperty(xdisplay_,
child,
atom_cache_.GetAtom(kXdndProxy),
XA_WINDOW,
32,
PropModeReplace,
reinterpret_cast<unsigned char*>(&child), 1);
}
} }
} }
break; break;
} }
case ClientMessage: { case ClientMessage: {
Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]); Atom message_type = xev->xclient.message_type;
if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) { if (message_type == atom_cache_.GetAtom(kWMProtocols)) {
// We have received a close message from the window manager. Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
if (browser_ && browser_->destruction_state() <= if (protocol == atom_cache_.GetAtom(kWMDeleteWindow)) {
CefBrowserHostImpl::DESTRUCTION_STATE_PENDING) { // We have received a close message from the window manager.
if (browser_->destruction_state() == if (browser_ && browser_->destruction_state() <=
CefBrowserHostImpl::DESTRUCTION_STATE_NONE) { CefBrowserHostImpl::DESTRUCTION_STATE_PENDING) {
// Request that the browser close. if (browser_->destruction_state() ==
browser_->CloseBrowser(false); CefBrowserHostImpl::DESTRUCTION_STATE_NONE) {
// Request that the browser close.
browser_->CloseBrowser(false);
}
// Cancel the close.
} else {
// Allow the close.
XDestroyWindow(xdisplay_, xwindow_);
} }
} else if (protocol == atom_cache_.GetAtom(kNetWMPing)) {
XEvent reply_event = *xev;
reply_event.xclient.window = parent_xwindow_;
// Cancel the close. XSendEvent(xdisplay_,
} else { reply_event.xclient.window,
// Allow the close. False,
XDestroyWindow(xdisplay_, xwindow_); SubstructureRedirectMask | SubstructureNotifyMask,
&reply_event);
XFlush(xdisplay_);
} }
} 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; break;
} }

View File

@ -112,6 +112,12 @@ patches = [
'name': 'webkit_platform_mac_328814', 'name': 'webkit_platform_mac_328814',
'path': '../third_party/WebKit/Source/platform/mac/', 'path': '../third_party/WebKit/Source/platform/mac/',
}, },
{
# Fix drag&drop of combined text and URL data on Linux/Aura.
# https://codereview.chromium.org/208313009
'name': 'ui_dragdrop_355390',
'path': '../ui/base/dragdrop/',
},
{ {
# Disable scollbar bounce and overlay on OS X. # Disable scollbar bounce and overlay on OS X.
# http://code.google.com/p/chromiumembedded/issues/detail?id=364 # http://code.google.com/p/chromiumembedded/issues/detail?id=364

View File

@ -0,0 +1,14 @@
Index: os_exchange_data_provider_aurax11.cc
===================================================================
--- os_exchange_data_provider_aurax11.cc (revision 280796)
+++ os_exchange_data_provider_aurax11.cc (working copy)
@@ -155,7 +155,8 @@
format_map_.Insert(atom_cache_.GetAtom(kMimeTypeMozillaURL), mem);
// Set a string fallback as well.
- SetString(spec);
+ if (!HasString())
+ SetString(spec);
// Return early if this drag already contains file contents (this implies
// that file contents must be populated before URLs). Nautilus (and possibly

View File

@ -80,7 +80,34 @@ Index: desktop_aura/desktop_window_tree_host_x11.cc
xwindow_ = None; xwindow_ = None;
desktop_native_widget_aura_->OnHostClosed(); desktop_native_widget_aura_->OnHostClosed();
@@ -1042,9 +1044,13 @@ @@ -443,6 +445,8 @@
}
gfx::Rect DesktopWindowTreeHostX11::GetWindowBoundsInScreen() const {
+ if (!screen_bounds_.IsEmpty())
+ return screen_bounds_;
return bounds_;
}
@@ -455,6 +459,8 @@
// Attempts to calculate the rect by asking the NonClientFrameView what it
// thought its GetBoundsForClientView() were broke combobox drop down
// placement.
+ if (!screen_bounds_.IsEmpty())
+ return screen_bounds_;
return bounds_;
}
@@ -899,6 +905,8 @@
}
gfx::Point DesktopWindowTreeHostX11::GetLocationOnNativeScreen() const {
+ if (!screen_bounds_.IsEmpty())
+ return screen_bounds_.origin();
return bounds_.origin();
}
@@ -1042,9 +1050,13 @@
} }
} }
@ -95,7 +122,7 @@ Index: desktop_aura/desktop_window_tree_host_x11.cc
bounds_.x(), bounds_.y(), bounds_.x(), bounds_.y(),
bounds_.width(), bounds_.height(), bounds_.width(), bounds_.height(),
0, // border width 0, // border width
@@ -1600,6 +1606,10 @@ @@ -1600,6 +1612,10 @@
} }
break; break;
} }
@ -110,7 +137,26 @@ Index: desktop_aura/desktop_window_tree_host_x11.h
=================================================================== ===================================================================
--- desktop_aura/desktop_window_tree_host_x11.h (revision 280796) --- desktop_aura/desktop_window_tree_host_x11.h (revision 280796)
+++ desktop_aura/desktop_window_tree_host_x11.h (working copy) +++ desktop_aura/desktop_window_tree_host_x11.h (working copy)
@@ -331,6 +331,9 @@ @@ -84,6 +84,8 @@
// Deallocates the internal list of open windows.
static void CleanUpWindowList();
+ void set_screen_bounds(const gfx::Rect& bounds) { screen_bounds_ = bounds; }
+
protected:
// Overridden from DesktopWindowTreeHost:
virtual void Init(aura::Window* content_window,
@@ -250,6 +252,9 @@
// The bounds of |xwindow_|.
gfx::Rect bounds_;
+ // Override the screen bounds when the host is a child window.
+ gfx::Rect screen_bounds_;
+
// Whenever the bounds are set, we keep the previous set of bounds around so
// we can have a better chance of getting the real |restored_bounds_|. Window
// managers tend to send a Configure message with the maximized bounds, and
@@ -331,6 +336,9 @@
// the frame when |xwindow_| gains focus or handles a mouse button event. // the frame when |xwindow_| gains focus or handles a mouse button event.
bool urgency_hint_set_; bool urgency_hint_set_;