Index: ui/views/widget/x11_window_event_filter.cc |
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 0000000000000000000000000000000000000000..bb10c1bb632de029a383ea12bdba2a0fc9c53547 |
--- /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 |
+ |