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