1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/views/widget/desktop_aura/x11_window_event_filter.h" 6 7 #include <X11/extensions/XInput.h> 8 #include <X11/extensions/XInput2.h> 9 #include <X11/Xatom.h> 10 #include <X11/Xlib.h> 11 12 #include "base/message_loop/message_pump_aurax11.h" 13 #include "ui/aura/root_window.h" 14 #include "ui/aura/window_delegate.h" 15 #include "ui/base/events/event.h" 16 #include "ui/base/events/event_utils.h" 17 #include "ui/base/hit_test.h" 18 #include "ui/views/widget/desktop_aura/desktop_activation_client.h" 19 #include "ui/views/widget/native_widget_aura.h" 20 21 namespace { 22 23 // These constants are defined in the Extended Window Manager Hints 24 // standard...and aren't in any header that I can find. 25 const int k_NET_WM_MOVERESIZE_SIZE_TOPLEFT = 0; 26 const int k_NET_WM_MOVERESIZE_SIZE_TOP = 1; 27 const int k_NET_WM_MOVERESIZE_SIZE_TOPRIGHT = 2; 28 const int k_NET_WM_MOVERESIZE_SIZE_RIGHT = 3; 29 const int k_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT = 4; 30 const int k_NET_WM_MOVERESIZE_SIZE_BOTTOM = 5; 31 const int k_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT = 6; 32 const int k_NET_WM_MOVERESIZE_SIZE_LEFT = 7; 33 const int k_NET_WM_MOVERESIZE_MOVE = 8; 34 35 // This data structure represents additional hints that we send to the window 36 // manager and has a direct lineage back to Motif, which defined this de facto 37 // standard. This struct doesn't seem 64-bit safe though, but it's what GDK 38 // does. 39 typedef struct { 40 unsigned long flags; 41 unsigned long functions; 42 unsigned long decorations; 43 long input_mode; 44 unsigned long status; 45 } MotifWmHints; 46 47 // The bitflag in |flags| in MotifWmHints that signals that the reader should 48 // pay attention to the value in |decorations|. 49 const unsigned long kHintsDecorations = (1L << 1); 50 51 const char* kAtomsToCache[] = { 52 "_MOTIF_WM_HINTS", 53 "_NET_WM_MOVERESIZE", 54 NULL 55 }; 56 57 } // namespace 58 59 namespace views { 60 61 X11WindowEventFilter::X11WindowEventFilter( 62 aura::RootWindow* root_window, 63 DesktopActivationClient* activation_client) 64 : activation_client_(activation_client), 65 xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()), 66 xwindow_(root_window->GetAcceleratedWidget()), 67 x_root_window_(DefaultRootWindow(xdisplay_)), 68 atom_cache_(xdisplay_, kAtomsToCache), 69 is_active_(false) { 70 } 71 72 X11WindowEventFilter::~X11WindowEventFilter() { 73 } 74 75 void X11WindowEventFilter::SetUseHostWindowBorders(bool use_os_border) { 76 MotifWmHints motif_hints; 77 memset(&motif_hints, 0, sizeof(motif_hints)); 78 motif_hints.flags = kHintsDecorations; 79 motif_hints.decorations = use_os_border ? 1 : 0; 80 81 ::Atom hint_atom = atom_cache_.GetAtom("_MOTIF_WM_HINTS"); 82 XChangeProperty(base::MessagePumpAuraX11::GetDefaultXDisplay(), 83 xwindow_, 84 hint_atom, 85 hint_atom, 86 32, 87 PropModeReplace, 88 reinterpret_cast<unsigned char*>(&motif_hints), 89 sizeof(MotifWmHints)/sizeof(long)); 90 } 91 92 void X11WindowEventFilter::OnMouseEvent(ui::MouseEvent* event) { 93 if (event->type() != ui::ET_MOUSE_PRESSED) 94 return; 95 96 if (!event->IsLeftMouseButton()) 97 return; 98 99 aura::Window* target = static_cast<aura::Window*>(event->target()); 100 int component = 101 target->delegate()->GetNonClientComponent(event->location()); 102 if (component == HTCLIENT) 103 return; 104 105 // Get the |x_root_window_| location out of the native event. 106 if (event->native_event()) { 107 const gfx::Point x_root_location = 108 ui::EventSystemLocationFromNative(event->native_event()); 109 if (DispatchHostWindowDragMovement(component, x_root_location)) 110 event->StopPropagation(); 111 } 112 } 113 114 bool X11WindowEventFilter::DispatchHostWindowDragMovement( 115 int hittest, 116 const gfx::Point& screen_location) { 117 int direction = -1; 118 switch (hittest) { 119 case HTBOTTOM: 120 direction = k_NET_WM_MOVERESIZE_SIZE_BOTTOM; 121 break; 122 case HTBOTTOMLEFT: 123 direction = k_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT; 124 break; 125 case HTBOTTOMRIGHT: 126 direction = k_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT; 127 break; 128 case HTCAPTION: 129 direction = k_NET_WM_MOVERESIZE_MOVE; 130 break; 131 case HTLEFT: 132 direction = k_NET_WM_MOVERESIZE_SIZE_LEFT; 133 break; 134 case HTRIGHT: 135 direction = k_NET_WM_MOVERESIZE_SIZE_RIGHT; 136 break; 137 case HTTOP: 138 direction = k_NET_WM_MOVERESIZE_SIZE_TOP; 139 break; 140 case HTTOPLEFT: 141 direction = k_NET_WM_MOVERESIZE_SIZE_TOPLEFT; 142 break; 143 case HTTOPRIGHT: 144 direction = k_NET_WM_MOVERESIZE_SIZE_TOPRIGHT; 145 break; 146 default: 147 return false; 148 } 149 150 // We most likely have an implicit grab right here. We need to dump it 151 // because what we're about to do is tell the window manager 152 // that it's now responsible for moving the window around; it immediately 153 // grabs when it receives the event below. 154 XUngrabPointer(xdisplay_, CurrentTime); 155 156 XEvent event; 157 memset(&event, 0, sizeof(event)); 158 event.xclient.type = ClientMessage; 159 event.xclient.display = xdisplay_; 160 event.xclient.window = xwindow_; 161 event.xclient.message_type = atom_cache_.GetAtom("_NET_WM_MOVERESIZE"); 162 event.xclient.format = 32; 163 event.xclient.data.l[0] = screen_location.x(); 164 event.xclient.data.l[1] = screen_location.y(); 165 event.xclient.data.l[2] = direction; 166 event.xclient.data.l[3] = 0; 167 event.xclient.data.l[4] = 0; 168 169 XSendEvent(xdisplay_, x_root_window_, False, 170 SubstructureRedirectMask | SubstructureNotifyMask, 171 &event); 172 173 return true; 174 } 175 176 } // namespace views 177