diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/aura/root_window_host_linux.cc | 31 | ||||
-rw-r--r-- | ui/aura/root_window_host_linux.h | 12 | ||||
-rw-r--r-- | ui/base/x/x11_atom_cache.cc | 65 | ||||
-rw-r--r-- | ui/base/x/x11_atom_cache.h | 58 | ||||
-rw-r--r-- | ui/ui.gyp | 2 | ||||
-rw-r--r-- | ui/views/views.gyp | 2 | ||||
-rw-r--r-- | ui/views/widget/desktop_native_widget_helper_aura.cc | 15 | ||||
-rw-r--r-- | ui/views/widget/desktop_native_widget_helper_aura.h | 5 | ||||
-rw-r--r-- | ui/views/widget/x11_window_event_filter.cc | 193 | ||||
-rw-r--r-- | ui/views/widget/x11_window_event_filter.h | 64 |
10 files changed, 415 insertions, 32 deletions
diff --git a/ui/aura/root_window_host_linux.cc b/ui/aura/root_window_host_linux.cc index 4f42775..af30780 100644 --- a/ui/aura/root_window_host_linux.cc +++ b/ui/aura/root_window_host_linux.cc @@ -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) { diff --git a/ui/aura/root_window_host_linux.h b/ui/aura/root_window_host_linux.h index 34484e4..7accce9 100644 --- a/ui/aura/root_window_host_linux.h +++ b/ui/aura/root_window_host_linux.h @@ -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_; diff --git a/ui/base/x/x11_atom_cache.cc b/ui/base/x/x11_atom_cache.cc new file mode 100644 index 0000000..9f16df8 --- /dev/null +++ b/ui/base/x/x11_atom_cache.cc @@ -0,0 +1,65 @@ +// 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 + + diff --git a/ui/base/x/x11_atom_cache.h b/ui/base/x/x11_atom_cache.h new file mode 100644 index 0000000..783da77b --- /dev/null +++ b/ui/base/x/x11_atom_cache.h @@ -0,0 +1,58 @@ +// 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', diff --git a/ui/views/views.gyp b/ui/views/views.gyp index a25a265..7acb492 100644 --- a/ui/views/views.gyp +++ b/ui/views/views.gyp @@ -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', diff --git a/ui/views/widget/desktop_native_widget_helper_aura.cc b/ui/views/widget/desktop_native_widget_helper_aura.cc index c109b9f..f971e5d 100644 --- a/ui/views/widget/desktop_native_widget_helper_aura.cc +++ b/ui/views/widget/desktop_native_widget_helper_aura.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( diff --git a/ui/views/widget/desktop_native_widget_helper_aura.h b/ui/views/widget/desktop_native_widget_helper_aura.h index 9011859..ee9b0d5 100644 --- a/ui/views/widget/desktop_native_widget_helper_aura.h +++ b/ui/views/widget/desktop_native_widget_helper_aura.h @@ -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); diff --git a/ui/views/widget/x11_window_event_filter.cc b/ui/views/widget/x11_window_event_filter.cc new file mode 100644 index 0000000..bb10c1b --- /dev/null +++ b/ui/views/widget/x11_window_event_filter.cc @@ -0,0 +1,193 @@ +// 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 + diff --git a/ui/views/widget/x11_window_event_filter.h b/ui/views/widget/x11_window_event_filter.h new file mode 100644 index 0000000..eaa6eca --- /dev/null +++ b/ui/views/widget/x11_window_event_filter.h @@ -0,0 +1,64 @@ +// 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_ |