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
49using std::max;
50using std::min;
51
52namespace aura {
53
54namespace {
55
56const 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
70void 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
100bool default_override_redirect = false;
101
102}  // namespace
103
104namespace 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.
113class 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
237WindowTreeHostX11::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
309WindowTreeHostX11::~WindowTreeHostX11() {
310  if (ui::PlatformEventSource::GetInstance())
311    ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
312
313  DestroyCompositor();
314  DestroyDispatcher();
315  XDestroyWindow(xdisplay_, xwindow_);
316}
317
318bool WindowTreeHostX11::CanDispatchEvent(const ui::PlatformEvent& event) {
319  ::Window target = FindEventTarget(event);
320  return target == xwindow_ || target == x_root_window_;
321}
322
323uint32_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
480ui::EventSource* WindowTreeHostX11::GetEventSource() {
481  return this;
482}
483
484gfx::AcceleratedWidget WindowTreeHostX11::GetAcceleratedWidget() {
485  return xwindow_;
486}
487
488void 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
512void WindowTreeHostX11::Hide() {
513  if (window_mapped_) {
514    XWithdrawWindow(xdisplay_, xwindow_, 0);
515    window_mapped_ = false;
516  }
517}
518
519gfx::Rect WindowTreeHostX11::GetBounds() const {
520  return bounds_;
521}
522
523void 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
563gfx::Point WindowTreeHostX11::GetLocationOnNativeScreen() const {
564  return bounds_.origin();
565}
566
567void WindowTreeHostX11::SetCapture() {
568  // TODO(oshima): Grab x input.
569}
570
571void WindowTreeHostX11::ReleaseCapture() {
572  // TODO(oshima): Release x input.
573}
574
575void 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
609void WindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) {
610  if (cursor == current_cursor_)
611    return;
612  current_cursor_ = cursor;
613  SetCursorInternal(cursor);
614}
615
616void 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
622void WindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) {
623}
624
625ui::EventProcessor* WindowTreeHostX11::GetEventProcessor() {
626  return dispatcher();
627}
628
629void 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
707void WindowTreeHostX11::SetCursorInternal(gfx::NativeCursor cursor) {
708  XDefineCursor(xdisplay_, xwindow_, cursor.platform());
709}
710
711void WindowTreeHostX11::OnConfigureNotify() {}
712
713void WindowTreeHostX11::TranslateAndDispatchLocatedEvent(
714    ui::LocatedEvent* event) {
715  SendEventToProcessor(event);
716}
717
718// static
719WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) {
720  return new WindowTreeHostX11(bounds);
721}
722
723// static
724gfx::Size WindowTreeHost::GetNativeScreenSize() {
725  ::XDisplay* xdisplay = gfx::GetXDisplay();
726  return gfx::Size(DisplayWidth(xdisplay, 0), DisplayHeight(xdisplay, 0));
727}
728
729namespace test {
730
731void SetUseOverrideRedirectWindowByDefault(bool override_redirect) {
732  default_override_redirect = override_redirect;
733}
734
735}  // namespace test
736}  // namespace aura
737