Home | History | Annotate | Download | only in desktop_aura
      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