Commit b3dd7665 authored by erg@chromium.org's avatar erg@chromium.org

Aura/ash split: Don't use X11 window borders.

This disables window manager borders, and supports dragging of the
skyline, as well as resizing from the corners.

This patch also moves our ::Atom caching out of RootWindowHostLinux and into its own Singleton.

BUG=125106
TEST=none

Review URL: https://chromiumcodereview.appspot.com/10381063

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@137525 0039d316-1c4b-4281-b951-d872f2087c98
parent 9f56b2f4
......@@ -27,10 +27,12 @@
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/touch/touch_factory.h"
#include "ui/base/view_prop.h"
#include "ui/base/x/x11_atom_cache.h"
#include "ui/base/x/x11_util.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/image/image.h"
using ui::X11AtomCache;
using std::max;
using std::min;
......@@ -286,15 +288,6 @@ bool ShouldSendCharEventForKeyboardCode(ui::KeyboardCode keycode) {
}
}
// A list of atoms that we'll intern on host creation to save roundtrips to the
// X11 server. Must be kept in sync with RootWindowHostLinux::AtomList
const char* kAtomList[] = {
"WM_DELETE_WINDOW",
"_NET_WM_PING",
"_NET_WM_PID",
"WM_S0"
};
} // namespace
// A utility class that provides X Cursor for NativeCursors for which we have
......@@ -395,16 +388,13 @@ RootWindowHostLinux::RootWindowHostLinux(const gfx::Rect& bounds)
if (RootWindow::hide_host_cursor())
XDefineCursor(xdisplay_, x_root_window_, invisible_cursor_);
// Grab all the atoms we need now to minimize roundtrips to the X11 server.
XInternAtoms(xdisplay_, const_cast<char**>(kAtomList), ATOM_COUNT, False,
cached_atoms_);
// 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.
X11AtomCache* cache = X11AtomCache::GetInstance();
::Atom protocols[2];
protocols[0] = cached_atoms_[ATOM_WM_DELETE_WINDOW];
protocols[1] = cached_atoms_[ATOM__NET_WM_PING];
protocols[0] = cache->GetAtom(ui::ATOM_WM_DELETE_WINDOW);
protocols[1] = cache->GetAtom(ui::ATOM__NET_WM_PING);
XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
// We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
......@@ -416,7 +406,7 @@ RootWindowHostLinux::RootWindowHostLinux(const gfx::Rect& bounds)
pid_t pid = getpid();
XChangeProperty(xdisplay_,
xwindow_,
cached_atoms_[ATOM__NET_WM_PID],
cache->GetAtom(ui::ATOM__NET_WM_PID),
XA_CARDINAL,
32,
PropModeReplace,
......@@ -588,10 +578,11 @@ bool RootWindowHostLinux::Dispatch(const base::NativeEvent& event) {
}
case ClientMessage: {
Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]);
if (message_type == cached_atoms_[ATOM_WM_DELETE_WINDOW]) {
X11AtomCache* cache = X11AtomCache::GetInstance();
if (message_type == cache->GetAtom(ui::ATOM_WM_DELETE_WINDOW)) {
// We have received a close message from the window manager.
root_window_->OnRootWindowHostClosed();
} else if (message_type == cached_atoms_[ATOM__NET_WM_PING]) {
} else if (message_type == cache->GetAtom(ui::ATOM__NET_WM_PING)) {
XEvent reply_event = *xev;
reply_event.xclient.window = x_root_window_;
......@@ -840,7 +831,9 @@ void RootWindowHostLinux::PostNativeEvent(
bool RootWindowHostLinux::IsWindowManagerPresent() {
// Per ICCCM 2.8, "Manager Selections", window managers should take ownership
// of WM_Sn selections (where n is a screen number).
return XGetSelectionOwner(xdisplay_, cached_atoms_[ATOM_WM_S0]) != None;
return XGetSelectionOwner(
xdisplay_,
X11AtomCache::GetInstance()->GetAtom(ui::ATOM_WM_S0)) != None;
}
void RootWindowHostLinux::SetCursorInternal(gfx::NativeCursor cursor) {
......
......@@ -82,18 +82,6 @@ class RootWindowHostLinux : public RootWindowHost,
// The bounds of |xwindow_|.
gfx::Rect bounds_;
// Names of cached atoms that we fetch during the constructor to minimize
// round trips to the X11 server.
enum AtomList {
ATOM_WM_DELETE_WINDOW = 0,
ATOM__NET_WM_PING,
ATOM__NET_WM_PID,
ATOM_WM_S0,
ATOM_COUNT
};
::Atom cached_atoms_[ATOM_COUNT];
// True if the window should be focused when the window is shown.
bool focus_when_shown_;
......
// Copyright (c) 2012 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 "ui/base/x/x11_atom_cache.h"
#include <X11/Xatom.h>
#include "base/message_pump_x.h"
namespace ui {
namespace {
// A list of atoms that we'll intern on host creation to save roundtrips to the
// X11 server. Must be kept in sync with AtomCache::AtomName
struct AtomInfo {
ui::AtomName id;
const char* name;
} const kAtomList[] = {
{ ATOM_WM_DELETE_WINDOW, "WM_DELETE_WINDOW" },
{ ATOM__NET_WM_MOVERESIZE, "_NET_WM_MOVERESIZE" },
{ ATOM__NET_WM_PING, "_NET_WM_PING" },
{ ATOM__NET_WM_PID, "_NET_WM_PID" },
{ ATOM_WM_S0, "WM_S0" },
{ ATOM__MOTIF_WM_HINTS, "_MOTIF_WM_HINTS" }
};
// Our lists need to stay in sync here.
COMPILE_ASSERT(arraysize(kAtomList) == ui::ATOM_COUNT,
atom_lists_are_same_size);
} // namespace
X11AtomCache* X11AtomCache::GetInstance() {
return Singleton<X11AtomCache>::get();
}
::Atom X11AtomCache::GetAtom(AtomName name) const {
std::map<AtomName, ::Atom>::const_iterator it = cached_atoms_.find(name);
DCHECK(it != cached_atoms_.end());
return it->second;
}
X11AtomCache::X11AtomCache() {
const char* all_names[ATOM_COUNT];
::Atom cached_atoms[ATOM_COUNT];
for (int i = 0; i < ATOM_COUNT; ++i)
all_names[i] = kAtomList[i].name;
// Grab all the atoms we need now to minimize roundtrips to the X11 server.
XInternAtoms(base::MessagePumpX::GetDefaultXDisplay(),
const_cast<char**>(all_names), ATOM_COUNT, False,
cached_atoms);
for (int i = 0; i < ATOM_COUNT; ++i)
cached_atoms_.insert(std::make_pair(kAtomList[i].id, cached_atoms[i]));
}
X11AtomCache::~X11AtomCache() {}
} // namespace ui
// Copyright (c) 2012 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 UI_BASE_X_X11_ATOM_CACHE_H_
#define UI_BASE_X_X11_ATOM_CACHE_H_
#include "base/basictypes.h"
#include "base/memory/singleton.h"
#include "ui/base/ui_export.h"
#include <X11/Xlib.h>
#include <map>
// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
#undef RootWindow
namespace ui {
// Names of cached atoms that we fetch from X11AtomCache. Adding an entry here
// also requires adding an entry in the cc file.
enum AtomName {
ATOM_WM_DELETE_WINDOW = 0,
ATOM__NET_WM_MOVERESIZE,
ATOM__NET_WM_PING,
ATOM__NET_WM_PID,
ATOM_WM_S0,
ATOM__MOTIF_WM_HINTS,
ATOM_COUNT
};
// Pre-caches all Atoms on first use to minimize roundtrips to the X11
// server. Assumes that we only have a single X11 display,
// base::MessagePumpX::GetDefaultXDisplay().
class UI_EXPORT X11AtomCache {
public:
static X11AtomCache* GetInstance();
// Returns the pre-interned Atom by enum instead of string.
::Atom GetAtom(AtomName name) const;
private:
friend struct DefaultSingletonTraits<X11AtomCache>;
// Constructor performs all interning
X11AtomCache();
~X11AtomCache();
std::map<AtomName, ::Atom> cached_atoms_;
DISALLOW_COPY_AND_ASSIGN(X11AtomCache);
};
} // namespace ui
#endif // UI_BASE_X_ATOM_CACHE_H_
......@@ -295,6 +295,8 @@
'base/x/root_window_property_watcher_x.h',
'base/x/work_area_watcher_x.cc',
'base/x/work_area_watcher_x.h',
'base/x/x11_atom_cache.cc',
'base/x/x11_atom_cache.h',
'base/x/x11_util.cc',
'base/x/x11_util.h',
'base/x/x11_util_internal.h',
......
......@@ -348,6 +348,8 @@
'widget/widget_hwnd_utils.h',
'widget/widget_message_filter.cc',
'widget/widget_message_filter.h',
'widget/x11_window_event_filter.cc',
'widget/x11_window_event_filter.h',
'window/client_view.cc',
'window/client_view.h',
'window/custom_frame_view.cc',
......
......@@ -15,6 +15,8 @@
#if defined(OS_WIN)
#include "ui/base/win/hwnd_subclass.h"
#include "ui/views/widget/widget_message_filter.h"
#elif defined(USE_X11)
#include "ui/views/widget/x11_window_event_filter.h"
#endif
namespace views {
......@@ -27,8 +29,13 @@ DesktopNativeWidgetHelperAura::DesktopNativeWidgetHelperAura(
}
DesktopNativeWidgetHelperAura::~DesktopNativeWidgetHelperAura() {
if (root_window_event_filter_)
if (root_window_event_filter_) {
#if defined(USE_X11)
root_window_event_filter_->RemoveFilter(x11_window_event_filter_.get());
#endif
root_window_event_filter_->RemoveFilter(input_method_filter_.get());
}
}
void DesktopNativeWidgetHelperAura::PreInitialize(
......@@ -63,6 +70,12 @@ void DesktopNativeWidgetHelperAura::PreInitialize(
new aura::shared::InputMethodEventFilter(root_window_.get()));
root_window_event_filter_->AddFilter(input_method_filter_.get());
#if defined(USE_X11)
x11_window_event_filter_.reset(new X11WindowEventFilter(root_window_.get()));
x11_window_event_filter_->SetUseHostWindowBorders(false);
root_window_event_filter_->AddFilter(x11_window_event_filter_.get());
#endif
root_window_->AddRootWindowObserver(this);
aura::client::SetActivationClient(
......
......@@ -29,6 +29,9 @@ class HWNDSubclass;
namespace views {
class NativeWidgetAura;
class WidgetMessageFilter;
#if defined(USE_X11)
class X11WindowEventFilter;
#endif
// Implementation of non-Ash desktop integration code, allowing
// NativeWidgetAuras to work in a traditional desktop environment.
......@@ -73,6 +76,8 @@ class VIEWS_EXPORT DesktopNativeWidgetHelperAura
#if defined(OS_WIN)
scoped_ptr<ui::HWNDSubclass> subclass_;
#elif defined(USE_X11)
scoped_ptr<X11WindowEventFilter> x11_window_event_filter_;
#endif
DISALLOW_COPY_AND_ASSIGN(DesktopNativeWidgetHelperAura);
......
// Copyright (c) 2012 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 "ui/views/widget/x11_window_event_filter.h"
#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>
#include "base/message_pump_x.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window_delegate.h"
#include "ui/base/hit_test.h"
#include "ui/base/x/x11_atom_cache.h"
#include "ui/base/x/x11_atom_cache.h"
namespace {
// These constants are defined in the Extended Window Manager Hints
// standard...and aren't in any header that I can find.
const int k_NET_WM_MOVERESIZE_SIZE_TOPLEFT = 0;
const int k_NET_WM_MOVERESIZE_SIZE_TOP = 1;
const int k_NET_WM_MOVERESIZE_SIZE_TOPRIGHT = 2;
const int k_NET_WM_MOVERESIZE_SIZE_RIGHT = 3;
const int k_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT = 4;
const int k_NET_WM_MOVERESIZE_SIZE_BOTTOM = 5;
const int k_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT = 6;
const int k_NET_WM_MOVERESIZE_SIZE_LEFT = 7;
const int k_NET_WM_MOVERESIZE_MOVE = 8;
// This data structure represents additional hints that we send to the window
// manager and has a direct lineage back to Motif, which defined this de facto
// standard. This struct doesn't seem 64-bit safe though, but it's what GDK
// does.
typedef struct {
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long input_mode;
unsigned long status;
} MotifWmHints;
// The bitflag in |flags| in MotifWmHints that signals that the reader should
// pay attention to the value in |decorations|.
const unsigned long kHintsDecorations = (1L << 1);
} // namespace
namespace views {
X11WindowEventFilter::X11WindowEventFilter(aura::RootWindow* root_window)
: root_window_(root_window),
xdisplay_(base::MessagePumpX::GetDefaultXDisplay()),
xwindow_(root_window_->GetAcceleratedWidget()),
x_root_window_(DefaultRootWindow(xdisplay_)) {
}
X11WindowEventFilter::~X11WindowEventFilter() {}
void X11WindowEventFilter::SetUseHostWindowBorders(bool use_os_border) {
ui::X11AtomCache* cache = ui::X11AtomCache::GetInstance();
MotifWmHints motif_hints;
memset(&motif_hints, 0, sizeof(motif_hints));
motif_hints.flags = kHintsDecorations;
motif_hints.decorations = use_os_border ? 1 : 0;
::Atom hint_atom = cache->GetAtom(ui::ATOM__MOTIF_WM_HINTS);
XChangeProperty(base::MessagePumpX::GetDefaultXDisplay(),
xwindow_,
hint_atom,
hint_atom,
32,
PropModeReplace,
reinterpret_cast<unsigned char*>(&motif_hints),
sizeof(MotifWmHints)/sizeof(long));
}
bool X11WindowEventFilter::PreHandleKeyEvent(aura::Window* target,
aura::KeyEvent* event) {
return false;
}
bool X11WindowEventFilter::PreHandleMouseEvent(aura::Window* target,
aura::MouseEvent* event) {
if (event->type() != ui::ET_MOUSE_PRESSED)
return false;
int component =
target->delegate()->GetNonClientComponent(event->location());
if (component == HTCLIENT)
return false;
// Get the |x_root_window_| location out of the native event.
gfx::Point root_location;
const base::NativeEvent& native_event = event->native_event();
switch (native_event->type) {
case ButtonPress: {
root_location.SetPoint(native_event->xbutton.x_root,
native_event->xbutton.y_root);
break;
}
case GenericEvent: {
XIDeviceEvent* xievent =
static_cast<XIDeviceEvent*>(native_event->xcookie.data);
root_location.SetPoint(xievent->root_x, xievent->root_y);
break;
}
default: {
NOTREACHED();
return false;
}
}
return DispatchHostWindowDragMovement(component, root_location);
}
ui::TouchStatus X11WindowEventFilter::PreHandleTouchEvent(
aura::Window* target,
aura::TouchEvent* event) {
return ui::TOUCH_STATUS_UNKNOWN;
}
ui::GestureStatus X11WindowEventFilter::PreHandleGestureEvent(
aura::Window* target,
aura::GestureEvent* event) {
return ui::GESTURE_STATUS_UNKNOWN;
}
bool X11WindowEventFilter::DispatchHostWindowDragMovement(
int hittest,
const gfx::Point& screen_location) {
int direction = -1;
switch (hittest) {
case HTBOTTOM:
direction = k_NET_WM_MOVERESIZE_SIZE_BOTTOM;
break;
case HTBOTTOMLEFT:
direction = k_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
break;
case HTBOTTOMRIGHT:
direction = k_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
break;
case HTCAPTION:
direction = k_NET_WM_MOVERESIZE_MOVE;
break;
case HTLEFT:
direction = k_NET_WM_MOVERESIZE_SIZE_LEFT;
break;
case HTRIGHT:
direction = k_NET_WM_MOVERESIZE_SIZE_RIGHT;
break;
case HTTOP:
direction = k_NET_WM_MOVERESIZE_SIZE_TOP;
break;
case HTTOPLEFT:
direction = k_NET_WM_MOVERESIZE_SIZE_TOPLEFT;
break;
case HTTOPRIGHT:
direction = k_NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
break;
default:
return false;
}
// We most likely have an implicit grab right here. We need to dump it
// because what we're about to do is tell the window manager
// that it's now responsible for moving the window around; it immediately
// grabs when it receives the event below.
XUngrabPointer(xdisplay_, CurrentTime);
XEvent event;
memset(&event, 0, sizeof(event));
event.xclient.type = ClientMessage;
event.xclient.display = xdisplay_;
event.xclient.window = xwindow_;
event.xclient.message_type = ui::X11AtomCache::GetInstance()->GetAtom(
ui::ATOM__NET_WM_MOVERESIZE);
event.xclient.format = 32;
event.xclient.data.l[0] = screen_location.x();
event.xclient.data.l[1] = screen_location.y();
event.xclient.data.l[2] = direction;
event.xclient.data.l[3] = 0;
event.xclient.data.l[4] = 0;
XSendEvent(xdisplay_, x_root_window_, False,
SubstructureRedirectMask | SubstructureNotifyMask,
&event);
return true;
}
} // namespace views
// Copyright (c) 2012 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 UI_VIEWS_WIDGET_X11_WINDOW_EVENT_FILTER_H_
#define UI_VIEWS_WIDGET_X11_WINDOW_EVENT_FILTER_H_
#pragma once
#include <X11/Xlib.h>
// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
#undef RootWindow
#include "base/compiler_specific.h"
#include "ui/aura/event.h"
#include "ui/aura/event_filter.h"
#include "ui/views/views_export.h"
namespace aura {
class RootWindow;
}
namespace views {
// An EventFilter that sets properties on X11 windows.
class VIEWS_EXPORT X11WindowEventFilter : public aura::EventFilter {
public:
explicit X11WindowEventFilter(aura::RootWindow* root_window);
virtual ~X11WindowEventFilter();
// Changes whether borders are shown on this |root_window|.
void SetUseHostWindowBorders(bool use_os_border);
// Overridden from EventFilter:
virtual bool PreHandleKeyEvent(aura::Window* target,
aura::KeyEvent* event) OVERRIDE;
virtual bool PreHandleMouseEvent(aura::Window* target,
aura::MouseEvent* event) OVERRIDE;
virtual ui::TouchStatus PreHandleTouchEvent(aura::Window* target,
aura::TouchEvent* event) OVERRIDE;
virtual ui::GestureStatus PreHandleGestureEvent(
aura::Window* target,
aura::GestureEvent* event) OVERRIDE;
private:
// Dispatches a _NET_WM_MOVERESIZE message to the window manager to tell it
// to act as if a border or titlebar drag occurred.
bool DispatchHostWindowDragMovement(int hittest,
const gfx::Point& screen_location);
aura::RootWindow* root_window_;
// The display and the native X window hosting the root window.
Display* xdisplay_;
::Window xwindow_;
// The native root window.
::Window x_root_window_;
DISALLOW_COPY_AND_ASSIGN(X11WindowEventFilter);
};
} // namespace views
#endif // UI_VIEWS_WIDGET_X11_WINDOW_EVENT_FILTER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment