Home | History | Annotate | Download | only in 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/aura/window_tree_host_x11.h"
      6 
      7 #include <strings.h>
      8 #include <X11/cursorfont.h>
      9 #include <X11/extensions/XInput2.h>
     10 #include <X11/extensions/Xrandr.h>
     11 #include <X11/Xatom.h>
     12 #include <X11/Xcursor/Xcursor.h>
     13 #include <X11/Xlib.h>
     14 
     15 #include <algorithm>
     16 #include <limits>
     17 #include <string>
     18 
     19 #include "base/basictypes.h"
     20 #include "base/command_line.h"
     21 #include "base/debug/trace_event.h"
     22 #include "base/stl_util.h"
     23 #include "base/strings/string_number_conversions.h"
     24 #include "base/strings/string_util.h"
     25 #include "base/strings/stringprintf.h"
     26 #include "base/sys_info.h"
     27 #include "ui/aura/client/cursor_client.h"
     28 #include "ui/aura/env.h"
     29 #include "ui/aura/window.h"
     30 #include "ui/aura/window_event_dispatcher.h"
     31 #include "ui/base/cursor/cursor.h"
     32 #include "ui/base/ui_base_switches.h"
     33 #include "ui/base/view_prop.h"
     34 #include "ui/base/x/x11_util.h"
     35 #include "ui/compositor/compositor.h"
     36 #include "ui/compositor/dip_util.h"
     37 #include "ui/compositor/layer.h"
     38 #include "ui/events/event.h"
     39 #include "ui/events/event_switches.h"
     40 #include "ui/events/event_utils.h"
     41 #include "ui/events/keycodes/keyboard_codes.h"
     42 #include "ui/events/platform/platform_event_observer.h"
     43 #include "ui/events/platform/x11/x11_event_source.h"
     44 #include "ui/events/x/device_data_manager_x11.h"
     45 #include "ui/events/x/device_list_cache_x.h"
     46 #include "ui/events/x/touch_factory_x11.h"
     47 #include "ui/gfx/screen.h"
     48 
     49 using std::max;
     50 using std::min;
     51 
     52 namespace aura {
     53 
     54 namespace {
     55 
     56 const char* kAtomsToCache[] = {
     57   "WM_DELETE_WINDOW",
     58   "_NET_WM_PING",
     59   "_NET_WM_PID",
     60   NULL
     61 };
     62 
     63 ::Window FindEventTarget(const base::NativeEvent& xev) {
     64   ::Window target = xev->xany.window;
     65   if (xev->type == GenericEvent)
     66     target = static_cast<XIDeviceEvent*>(xev->xcookie.data)->event;
     67   return target;
     68 }
     69 
     70 void SelectXInput2EventsForRootWindow(XDisplay* display, ::Window root_window) {
     71   CHECK(ui::IsXInput2Available());
     72   unsigned char mask[XIMaskLen(XI_LASTEVENT)] = {};
     73   memset(mask, 0, sizeof(mask));
     74 
     75   XISetMask(mask, XI_HierarchyChanged);
     76 
     77   XIEventMask evmask;
     78   evmask.deviceid = XIAllDevices;
     79   evmask.mask_len = sizeof(mask);
     80   evmask.mask = mask;
     81   XISelectEvents(display, root_window, &evmask, 1);
     82 
     83 #if defined(OS_CHROMEOS)
     84   if (base::SysInfo::IsRunningOnChromeOS()) {
     85     // It is necessary to listen for touch events on the root window for proper
     86     // touch event calibration on Chrome OS, but this is not currently necessary
     87     // on the desktop. This seems to fail in some cases (e.g. when logging
     88     // in incognito). So select for non-touch events first, and then select for
     89     // touch-events (but keep the other events in the mask, i.e. do not memset
     90     // |mask| back to 0).
     91     // TODO(sad): Figure out why this happens. http://crbug.com/153976
     92     XISetMask(mask, XI_TouchBegin);
     93     XISetMask(mask, XI_TouchUpdate);
     94     XISetMask(mask, XI_TouchEnd);
     95     XISelectEvents(display, root_window, &evmask, 1);
     96   }
     97 #endif
     98 }
     99 
    100 bool default_override_redirect = false;
    101 
    102 }  // namespace
    103 
    104 namespace internal {
    105 
    106 // TODO(miletus) : Move this into DeviceDataManager.
    107 // Accomplishes 2 tasks concerning touch event calibration:
    108 // 1. Being a message-pump observer,
    109 //    routes all the touch events to the X root window,
    110 //    where they can be calibrated later.
    111 // 2. Has the Calibrate method that does the actual bezel calibration,
    112 //    when invoked from X root window's event dispatcher.
    113 class TouchEventCalibrate : public ui::PlatformEventObserver {
    114  public:
    115   TouchEventCalibrate() : left_(0), right_(0), top_(0), bottom_(0) {
    116     if (ui::PlatformEventSource::GetInstance())
    117       ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
    118 #if defined(USE_XI2_MT)
    119     std::vector<std::string> parts;
    120     if (Tokenize(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
    121                      switches::kTouchCalibration),
    122                  ",",
    123                  &parts) >= 4) {
    124       if (!base::StringToInt(parts[0], &left_))
    125         DLOG(ERROR) << "Incorrect left border calibration value passed.";
    126       if (!base::StringToInt(parts[1], &right_))
    127         DLOG(ERROR) << "Incorrect right border calibration value passed.";
    128       if (!base::StringToInt(parts[2], &top_))
    129         DLOG(ERROR) << "Incorrect top border calibration value passed.";
    130       if (!base::StringToInt(parts[3], &bottom_))
    131         DLOG(ERROR) << "Incorrect bottom border calibration value passed.";
    132     }
    133 #endif  // defined(USE_XI2_MT)
    134   }
    135 
    136   virtual ~TouchEventCalibrate() {
    137     if (ui::PlatformEventSource::GetInstance())
    138       ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this);
    139   }
    140 
    141   // Modify the location of the |event|,
    142   // expanding it from |bounds| to (|bounds| + bezels).
    143   // Required when touchscreen is bigger than screen (i.e. has bezels),
    144   // because we receive events in touchscreen coordinates,
    145   // which need to be expanded when converting to screen coordinates,
    146   // so that location on bezels will be outside of screen area.
    147   void Calibrate(ui::TouchEvent* event, const gfx::Rect& bounds) {
    148 #if defined(USE_XI2_MT)
    149     int x = event->x();
    150     int y = event->y();
    151 
    152     if (!left_ && !right_ && !top_ && !bottom_)
    153       return;
    154 
    155     const int resolution_x = bounds.width();
    156     const int resolution_y = bounds.height();
    157     // The "grace area" (10% in this case) is to make it easier for the user to
    158     // navigate to the corner.
    159     const double kGraceAreaFraction = 0.1;
    160     if (left_ || right_) {
    161       // Offset the x position to the real
    162       x -= left_;
    163       // Check if we are in the grace area of the left side.
    164       // Note: We might not want to do this when the gesture is locked?
    165       if (x < 0 && x > -left_ * kGraceAreaFraction)
    166         x = 0;
    167       // Check if we are in the grace area of the right side.
    168       // Note: We might not want to do this when the gesture is locked?
    169       if (x > resolution_x - left_ &&
    170           x < resolution_x - left_ + right_ * kGraceAreaFraction)
    171         x = resolution_x - left_;
    172       // Scale the screen area back to the full resolution of the screen.
    173       x = (x * resolution_x) / (resolution_x - (right_ + left_));
    174     }
    175     if (top_ || bottom_) {
    176       // When there is a top bezel we add our border,
    177       y -= top_;
    178 
    179       // Check if we are in the grace area of the top side.
    180       // Note: We might not want to do this when the gesture is locked?
    181       if (y < 0 && y > -top_ * kGraceAreaFraction)
    182         y = 0;
    183 
    184       // Check if we are in the grace area of the bottom side.
    185       // Note: We might not want to do this when the gesture is locked?
    186       if (y > resolution_y - top_ &&
    187           y < resolution_y - top_ + bottom_ * kGraceAreaFraction)
    188         y = resolution_y - top_;
    189       // Scale the screen area back to the full resolution of the screen.
    190       y = (y * resolution_y) / (resolution_y - (bottom_ + top_));
    191     }
    192 
    193     // Set the modified coordinate back to the event.
    194     if (event->root_location() == event->location()) {
    195       // Usually those will be equal,
    196       // if not, I am not sure what the correct value should be.
    197       event->set_root_location(gfx::Point(x, y));
    198     }
    199     event->set_location(gfx::Point(x, y));
    200 #endif  // defined(USE_XI2_MT)
    201   }
    202 
    203  private:
    204   // ui::PlatformEventObserver:
    205   virtual void WillProcessEvent(const ui::PlatformEvent& event) OVERRIDE {
    206 #if defined(USE_XI2_MT)
    207     if (event->type == GenericEvent &&
    208         (event->xgeneric.evtype == XI_TouchBegin ||
    209          event->xgeneric.evtype == XI_TouchUpdate ||
    210          event->xgeneric.evtype == XI_TouchEnd)) {
    211       XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(event->xcookie.data);
    212       xievent->event = xievent->root;
    213       xievent->event_x = xievent->root_x;
    214       xievent->event_y = xievent->root_y;
    215     }
    216 #endif  // defined(USE_XI2_MT)
    217   }
    218 
    219   virtual void DidProcessEvent(const ui::PlatformEvent& event) OVERRIDE {}
    220 
    221   // The difference in screen's native resolution pixels between
    222   // the border of the touchscreen and the border of the screen,
    223   // aka bezel sizes.
    224   int left_;
    225   int right_;
    226   int top_;
    227   int bottom_;
    228 
    229   DISALLOW_COPY_AND_ASSIGN(TouchEventCalibrate);
    230 };
    231 
    232 }  // namespace internal
    233 
    234 ////////////////////////////////////////////////////////////////////////////////
    235 // WindowTreeHostX11
    236 
    237 WindowTreeHostX11::WindowTreeHostX11(const gfx::Rect& bounds)
    238     : xdisplay_(gfx::GetXDisplay()),
    239       xwindow_(0),
    240       x_root_window_(DefaultRootWindow(xdisplay_)),
    241       current_cursor_(ui::kCursorNull),
    242       window_mapped_(false),
    243       bounds_(bounds),
    244       touch_calibrate_(new internal::TouchEventCalibrate),
    245       atom_cache_(xdisplay_, kAtomsToCache) {
    246   XSetWindowAttributes swa;
    247   memset(&swa, 0, sizeof(swa));
    248   swa.background_pixmap = None;
    249   swa.override_redirect = default_override_redirect;
    250   xwindow_ = XCreateWindow(
    251       xdisplay_, x_root_window_,
    252       bounds.x(), bounds.y(), bounds.width(), bounds.height(),
    253       0,               // border width
    254       CopyFromParent,  // depth
    255       InputOutput,
    256       CopyFromParent,  // visual
    257       CWBackPixmap | CWOverrideRedirect,
    258       &swa);
    259   if (ui::PlatformEventSource::GetInstance())
    260     ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
    261 
    262   long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
    263                     KeyPressMask | KeyReleaseMask |
    264                     EnterWindowMask | LeaveWindowMask |
    265                     ExposureMask | VisibilityChangeMask |
    266                     StructureNotifyMask | PropertyChangeMask |
    267                     PointerMotionMask;
    268   XSelectInput(xdisplay_, xwindow_, event_mask);
    269   XFlush(xdisplay_);
    270 
    271   if (ui::IsXInput2Available()) {
    272     ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
    273     SelectXInput2EventsForRootWindow(xdisplay_, x_root_window_);
    274   }
    275 
    276   // TODO(erg): We currently only request window deletion events. We also
    277   // should listen for activation events and anything else that GTK+ listens
    278   // for, and do something useful.
    279   ::Atom protocols[2];
    280   protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
    281   protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
    282   XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
    283 
    284   // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
    285   // the desktop environment.
    286   XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
    287 
    288   // Likewise, the X server needs to know this window's pid so it knows which
    289   // program to kill if the window hangs.
    290   // XChangeProperty() expects "pid" to be long.
    291   COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
    292   long pid = getpid();
    293   XChangeProperty(xdisplay_,
    294                   xwindow_,
    295                   atom_cache_.GetAtom("_NET_WM_PID"),
    296                   XA_CARDINAL,
    297                   32,
    298                   PropModeReplace,
    299                   reinterpret_cast<unsigned char*>(&pid), 1);
    300 
    301   // Allow subclasses to create and cache additional atoms.
    302   atom_cache_.allow_uncached_atoms();
    303 
    304   XRRSelectInput(xdisplay_, x_root_window_,
    305                  RRScreenChangeNotifyMask | RROutputChangeNotifyMask);
    306   CreateCompositor(GetAcceleratedWidget());
    307 }
    308 
    309 WindowTreeHostX11::~WindowTreeHostX11() {
    310   if (ui::PlatformEventSource::GetInstance())
    311     ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
    312 
    313   DestroyCompositor();
    314   DestroyDispatcher();
    315   XDestroyWindow(xdisplay_, xwindow_);
    316 }
    317 
    318 bool WindowTreeHostX11::CanDispatchEvent(const ui::PlatformEvent& event) {
    319   ::Window target = FindEventTarget(event);
    320   return target == xwindow_ || target == x_root_window_;
    321 }
    322 
    323 uint32_t WindowTreeHostX11::DispatchEvent(const ui::PlatformEvent& event) {
    324   XEvent* xev = event;
    325   if (FindEventTarget(xev) == x_root_window_) {
    326     if (xev->type == GenericEvent)
    327       DispatchXI2Event(xev);
    328     return ui::POST_DISPATCH_NONE;
    329   }
    330 
    331   if (xev->type == MotionNotify) {
    332     // Discard all but the most recent motion event that targets the same
    333     // window with unchanged state.
    334     XEvent last_event;
    335     while (XPending(xev->xany.display)) {
    336       XEvent next_event;
    337       XPeekEvent(xev->xany.display, &next_event);
    338       if (next_event.type == MotionNotify &&
    339           next_event.xmotion.window == xev->xmotion.window &&
    340           next_event.xmotion.subwindow == xev->xmotion.subwindow &&
    341           next_event.xmotion.state == xev->xmotion.state) {
    342         XNextEvent(xev->xany.display, &last_event);
    343         xev = &last_event;
    344       } else {
    345         break;
    346       }
    347     }
    348   }
    349 
    350   if ((xev->type == EnterNotify || xev->type == LeaveNotify) &&
    351       xev->xcrossing.detail == NotifyInferior) {
    352     // Ignore EventNotify and LeaveNotify  events from children of |xwindow_|.
    353     // NativeViewGLSurfaceGLX adds a child to |xwindow_|.
    354     // TODO(pkotwicz|tdanderson): Figure out whether the suppression is
    355     // necessary. crbug.com/385716
    356     return ui::POST_DISPATCH_STOP_PROPAGATION;
    357   }
    358 
    359   if (xev->type == EnterNotify ||
    360       xev->type == LeaveNotify ||
    361       xev->type == KeyPress ||
    362       xev->type == KeyRelease ||
    363       xev->type == ButtonPress ||
    364       xev->type == ButtonRelease ||
    365       xev->type == MotionNotify) {
    366     switch (ui::EventTypeFromNative(xev)) {
    367       case ui::ET_KEY_PRESSED:
    368       case ui::ET_KEY_RELEASED: {
    369         ui::KeyEvent keydown_event(xev);
    370         SendEventToProcessor(&keydown_event);
    371         break;
    372       }
    373       case ui::ET_MOUSE_MOVED:
    374       case ui::ET_MOUSE_DRAGGED:
    375       case ui::ET_MOUSE_ENTERED:
    376       case ui::ET_MOUSE_EXITED:
    377       case ui::ET_MOUSE_PRESSED:
    378       case ui::ET_MOUSE_RELEASED: {
    379         ui::MouseEvent mouse_event(xev);
    380         if (xev->type == EnterNotify) {
    381           aura::Window* root_window = window();
    382           client::CursorClient* cursor_client =
    383               client::GetCursorClient(root_window);
    384           if (cursor_client) {
    385             const gfx::Display display = gfx::Screen::GetScreenFor(
    386                 root_window)->GetDisplayNearestWindow(root_window);
    387             cursor_client->SetDisplay(display);
    388           }
    389           // EnterNotify creates ET_MOUSE_MOVE. Mark as synthesized as this is
    390           // not a real mouse move event.
    391           mouse_event.set_flags(mouse_event.flags() | ui::EF_IS_SYNTHESIZED);
    392         }
    393 
    394         TranslateAndDispatchLocatedEvent(&mouse_event);
    395         break;
    396       }
    397       case ui::ET_MOUSEWHEEL: {
    398         ui::MouseWheelEvent mouseev(xev);
    399         TranslateAndDispatchLocatedEvent(&mouseev);
    400         break;
    401       }
    402       case ui::ET_UNKNOWN:
    403         // No event is created for X11-release events for mouse-wheel buttons.
    404         break;
    405       default:
    406          NOTREACHED();
    407     }
    408     return ui::POST_DISPATCH_STOP_PROPAGATION;
    409   }
    410 
    411   switch (xev->type) {
    412     case Expose: {
    413       gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
    414                             xev->xexpose.width, xev->xexpose.height);
    415       compositor()->ScheduleRedrawRect(damage_rect);
    416       break;
    417     }
    418     case FocusOut:
    419       if (xev->xfocus.mode != NotifyGrab)
    420         OnHostLostWindowCapture();
    421       break;
    422     case ConfigureNotify: {
    423       DCHECK_EQ(xwindow_, xev->xconfigure.event);
    424       DCHECK_EQ(xwindow_, xev->xconfigure.window);
    425       // It's possible that the X window may be resized by some other means
    426       // than from within aura (e.g. the X window manager can change the
    427       // size). Make sure the root window size is maintained properly.
    428       gfx::Rect bounds(xev->xconfigure.x, xev->xconfigure.y,
    429           xev->xconfigure.width, xev->xconfigure.height);
    430       bool size_changed = bounds_.size() != bounds.size();
    431       bool origin_changed = bounds_.origin() != bounds.origin();
    432       bounds_ = bounds;
    433       OnConfigureNotify();
    434       if (size_changed)
    435         OnHostResized(bounds.size());
    436       if (origin_changed)
    437         OnHostMoved(bounds_.origin());
    438       break;
    439     }
    440     case GenericEvent:
    441       DispatchXI2Event(xev);
    442       break;
    443     case ClientMessage: {
    444       Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]);
    445       if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
    446         // We have received a close message from the window manager.
    447         OnHostCloseRequested();
    448       } else if (message_type == atom_cache_.GetAtom("_NET_WM_PING")) {
    449         XEvent reply_event = *xev;
    450         reply_event.xclient.window = x_root_window_;
    451 
    452         XSendEvent(xdisplay_,
    453                    reply_event.xclient.window,
    454                    False,
    455                    SubstructureRedirectMask | SubstructureNotifyMask,
    456                    &reply_event);
    457         XFlush(xdisplay_);
    458       }
    459       break;
    460     }
    461     case MappingNotify: {
    462       switch (xev->xmapping.request) {
    463         case MappingModifier:
    464         case MappingKeyboard:
    465           XRefreshKeyboardMapping(&xev->xmapping);
    466           break;
    467         case MappingPointer:
    468           ui::DeviceDataManagerX11::GetInstance()->UpdateButtonMap();
    469           break;
    470         default:
    471           NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
    472           break;
    473       }
    474       break;
    475     }
    476   }
    477   return ui::POST_DISPATCH_STOP_PROPAGATION;
    478 }
    479 
    480 ui::EventSource* WindowTreeHostX11::GetEventSource() {
    481   return this;
    482 }
    483 
    484 gfx::AcceleratedWidget WindowTreeHostX11::GetAcceleratedWidget() {
    485   return xwindow_;
    486 }
    487 
    488 void WindowTreeHostX11::Show() {
    489   if (!window_mapped_) {
    490     // Before we map the window, set size hints. Otherwise, some window managers
    491     // will ignore toplevel XMoveWindow commands.
    492     XSizeHints size_hints;
    493     size_hints.flags = PPosition | PWinGravity;
    494     size_hints.x = bounds_.x();
    495     size_hints.y = bounds_.y();
    496     // Set StaticGravity so that the window position is not affected by the
    497     // frame width when running with window manager.
    498     size_hints.win_gravity = StaticGravity;
    499     XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
    500 
    501     XMapWindow(xdisplay_, xwindow_);
    502 
    503     // We now block until our window is mapped. Some X11 APIs will crash and
    504     // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
    505     // asynchronous.
    506     if (ui::X11EventSource::GetInstance())
    507       ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_);
    508     window_mapped_ = true;
    509   }
    510 }
    511 
    512 void WindowTreeHostX11::Hide() {
    513   if (window_mapped_) {
    514     XWithdrawWindow(xdisplay_, xwindow_, 0);
    515     window_mapped_ = false;
    516   }
    517 }
    518 
    519 gfx::Rect WindowTreeHostX11::GetBounds() const {
    520   return bounds_;
    521 }
    522 
    523 void WindowTreeHostX11::SetBounds(const gfx::Rect& bounds) {
    524   // Even if the host window's size doesn't change, aura's root window
    525   // size, which is in DIP, changes when the scale changes.
    526   float current_scale = compositor()->device_scale_factor();
    527   float new_scale = gfx::Screen::GetScreenFor(window())->
    528       GetDisplayNearestWindow(window()).device_scale_factor();
    529   bool origin_changed = bounds_.origin() != bounds.origin();
    530   bool size_changed = bounds_.size() != bounds.size();
    531   XWindowChanges changes = {0};
    532   unsigned value_mask = 0;
    533 
    534   if (size_changed) {
    535     changes.width = bounds.width();
    536     changes.height = bounds.height();
    537     value_mask = CWHeight | CWWidth;
    538   }
    539 
    540   if (origin_changed) {
    541     changes.x = bounds.x();
    542     changes.y = bounds.y();
    543     value_mask |= CWX | CWY;
    544   }
    545   if (value_mask)
    546     XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
    547 
    548   // Assume that the resize will go through as requested, which should be the
    549   // case if we're running without a window manager.  If there's a window
    550   // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
    551   // (possibly synthetic) ConfigureNotify about the actual size and correct
    552   // |bounds_| later.
    553   bounds_ = bounds;
    554   if (origin_changed)
    555     OnHostMoved(bounds.origin());
    556   if (size_changed || current_scale != new_scale) {
    557     OnHostResized(bounds.size());
    558   } else {
    559     window()->SchedulePaintInRect(window()->bounds());
    560   }
    561 }
    562 
    563 gfx::Point WindowTreeHostX11::GetLocationOnNativeScreen() const {
    564   return bounds_.origin();
    565 }
    566 
    567 void WindowTreeHostX11::SetCapture() {
    568   // TODO(oshima): Grab x input.
    569 }
    570 
    571 void WindowTreeHostX11::ReleaseCapture() {
    572   // TODO(oshima): Release x input.
    573 }
    574 
    575 void WindowTreeHostX11::PostNativeEvent(
    576     const base::NativeEvent& native_event) {
    577   DCHECK(xwindow_);
    578   DCHECK(xdisplay_);
    579   XEvent xevent = *native_event;
    580   xevent.xany.display = xdisplay_;
    581   xevent.xany.window = xwindow_;
    582 
    583   switch (xevent.type) {
    584     case EnterNotify:
    585     case LeaveNotify:
    586     case MotionNotify:
    587     case KeyPress:
    588     case KeyRelease:
    589     case ButtonPress:
    590     case ButtonRelease: {
    591       // The fields used below are in the same place for all of events
    592       // above. Using xmotion from XEvent's unions to avoid repeating
    593       // the code.
    594       xevent.xmotion.root = x_root_window_;
    595       xevent.xmotion.time = CurrentTime;
    596 
    597       gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
    598       ConvertPointToNativeScreen(&point);
    599       xevent.xmotion.x_root = point.x();
    600       xevent.xmotion.y_root = point.y();
    601     }
    602     default:
    603       break;
    604   }
    605   XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
    606   XFlush(xdisplay_);
    607 }
    608 
    609 void WindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) {
    610   if (cursor == current_cursor_)
    611     return;
    612   current_cursor_ = cursor;
    613   SetCursorInternal(cursor);
    614 }
    615 
    616 void WindowTreeHostX11::MoveCursorToNative(const gfx::Point& location) {
    617   XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
    618                bounds_.x() + location.x(),
    619                bounds_.y() + location.y());
    620 }
    621 
    622 void WindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) {
    623 }
    624 
    625 ui::EventProcessor* WindowTreeHostX11::GetEventProcessor() {
    626   return dispatcher();
    627 }
    628 
    629 void WindowTreeHostX11::DispatchXI2Event(const base::NativeEvent& event) {
    630   ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
    631   XEvent* xev = event;
    632   XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data);
    633   if (!factory->ShouldProcessXI2Event(xev))
    634     return;
    635 
    636   TRACE_EVENT1("input", "WindowTreeHostX11::DispatchXI2Event",
    637                "event_latency_us",
    638                (ui::EventTimeForNow() - ui::EventTimeFromNative(event)).
    639                  InMicroseconds());
    640 
    641   int num_coalesced = 0;
    642   XEvent last_event;
    643   if (xev->xgeneric.evtype == XI_Motion) {
    644     // If this is a motion event, we want to coalesce all pending motion
    645     // events that are at the top of the queue. Note, we don't coalesce
    646     // touch update events here.
    647     num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
    648     if (num_coalesced > 0)
    649       xev = &last_event;
    650   }
    651   ui::EventType type = ui::EventTypeFromNative(xev);
    652 
    653   switch (type) {
    654     case ui::ET_TOUCH_MOVED:
    655     case ui::ET_TOUCH_PRESSED:
    656     case ui::ET_TOUCH_CANCELLED:
    657     case ui::ET_TOUCH_RELEASED: {
    658       ui::TouchEvent touchev(xev);
    659       if (ui::DeviceDataManagerX11::GetInstance()->TouchEventNeedsCalibrate(
    660               xiev->deviceid)) {
    661         touch_calibrate_->Calibrate(&touchev, bounds_);
    662       }
    663       TranslateAndDispatchLocatedEvent(&touchev);
    664       break;
    665     }
    666     case ui::ET_MOUSE_MOVED:
    667     case ui::ET_MOUSE_DRAGGED:
    668     case ui::ET_MOUSE_PRESSED:
    669     case ui::ET_MOUSE_RELEASED:
    670     case ui::ET_MOUSE_ENTERED:
    671     case ui::ET_MOUSE_EXITED: {
    672       ui::MouseEvent mouseev(xev);
    673       TranslateAndDispatchLocatedEvent(&mouseev);
    674       break;
    675     }
    676     case ui::ET_MOUSEWHEEL: {
    677       ui::MouseWheelEvent mouseev(xev);
    678       TranslateAndDispatchLocatedEvent(&mouseev);
    679       break;
    680     }
    681     case ui::ET_SCROLL_FLING_START:
    682     case ui::ET_SCROLL_FLING_CANCEL:
    683     case ui::ET_SCROLL: {
    684       ui::ScrollEvent scrollev(xev);
    685       SendEventToProcessor(&scrollev);
    686       break;
    687     }
    688     case ui::ET_KEY_PRESSED:
    689     case ui::ET_KEY_RELEASED: {
    690       ui::KeyEvent key_event(xev);
    691       SendEventToProcessor(&key_event);
    692       break;
    693     }
    694     case ui::ET_UMA_DATA:
    695       break;
    696     case ui::ET_UNKNOWN:
    697       break;
    698     default:
    699       NOTREACHED();
    700   }
    701 
    702   // If we coalesced an event we need to free its cookie.
    703   if (num_coalesced > 0)
    704     XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
    705 }
    706 
    707 void WindowTreeHostX11::SetCursorInternal(gfx::NativeCursor cursor) {
    708   XDefineCursor(xdisplay_, xwindow_, cursor.platform());
    709 }
    710 
    711 void WindowTreeHostX11::OnConfigureNotify() {}
    712 
    713 void WindowTreeHostX11::TranslateAndDispatchLocatedEvent(
    714     ui::LocatedEvent* event) {
    715   SendEventToProcessor(event);
    716 }
    717 
    718 // static
    719 WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) {
    720   return new WindowTreeHostX11(bounds);
    721 }
    722 
    723 // static
    724 gfx::Size WindowTreeHost::GetNativeScreenSize() {
    725   ::XDisplay* xdisplay = gfx::GetXDisplay();
    726   return gfx::Size(DisplayWidth(xdisplay, 0), DisplayHeight(xdisplay, 0));
    727 }
    728 
    729 namespace test {
    730 
    731 void SetUseOverrideRedirectWindowByDefault(bool override_redirect) {
    732   default_override_redirect = override_redirect;
    733 }
    734 
    735 }  // namespace test
    736 }  // namespace aura
    737