• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
FindEventTarget(const base::NativeEvent & xev)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 
SelectXInput2EventsForRootWindow(XDisplay * display,::Window root_window)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:
TouchEventCalibrate()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 
~TouchEventCalibrate()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.
Calibrate(ui::TouchEvent * event,const gfx::Rect & bounds)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:
WillProcessEvent(const ui::PlatformEvent & event)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 
DidProcessEvent(const ui::PlatformEvent & event)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 
WindowTreeHostX11(const gfx::Rect & bounds)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 
~WindowTreeHostX11()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 
CanDispatchEvent(const ui::PlatformEvent & event)318 bool WindowTreeHostX11::CanDispatchEvent(const ui::PlatformEvent& event) {
319   ::Window target = FindEventTarget(event);
320   return target == xwindow_ || target == x_root_window_;
321 }
322 
DispatchEvent(const ui::PlatformEvent & event)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 
GetEventSource()480 ui::EventSource* WindowTreeHostX11::GetEventSource() {
481   return this;
482 }
483 
GetAcceleratedWidget()484 gfx::AcceleratedWidget WindowTreeHostX11::GetAcceleratedWidget() {
485   return xwindow_;
486 }
487 
Show()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 
Hide()512 void WindowTreeHostX11::Hide() {
513   if (window_mapped_) {
514     XWithdrawWindow(xdisplay_, xwindow_, 0);
515     window_mapped_ = false;
516   }
517 }
518 
GetBounds() const519 gfx::Rect WindowTreeHostX11::GetBounds() const {
520   return bounds_;
521 }
522 
SetBounds(const gfx::Rect & bounds)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 
GetLocationOnNativeScreen() const563 gfx::Point WindowTreeHostX11::GetLocationOnNativeScreen() const {
564   return bounds_.origin();
565 }
566 
SetCapture()567 void WindowTreeHostX11::SetCapture() {
568   // TODO(oshima): Grab x input.
569 }
570 
ReleaseCapture()571 void WindowTreeHostX11::ReleaseCapture() {
572   // TODO(oshima): Release x input.
573 }
574 
PostNativeEvent(const base::NativeEvent & native_event)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 
SetCursorNative(gfx::NativeCursor cursor)609 void WindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) {
610   if (cursor == current_cursor_)
611     return;
612   current_cursor_ = cursor;
613   SetCursorInternal(cursor);
614 }
615 
MoveCursorToNative(const gfx::Point & location)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 
OnCursorVisibilityChangedNative(bool show)622 void WindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) {
623 }
624 
GetEventProcessor()625 ui::EventProcessor* WindowTreeHostX11::GetEventProcessor() {
626   return dispatcher();
627 }
628 
DispatchXI2Event(const base::NativeEvent & event)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 
SetCursorInternal(gfx::NativeCursor cursor)707 void WindowTreeHostX11::SetCursorInternal(gfx::NativeCursor cursor) {
708   XDefineCursor(xdisplay_, xwindow_, cursor.platform());
709 }
710 
OnConfigureNotify()711 void WindowTreeHostX11::OnConfigureNotify() {}
712 
TranslateAndDispatchLocatedEvent(ui::LocatedEvent * event)713 void WindowTreeHostX11::TranslateAndDispatchLocatedEvent(
714     ui::LocatedEvent* event) {
715   SendEventToProcessor(event);
716 }
717 
718 // static
Create(const gfx::Rect & bounds)719 WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) {
720   return new WindowTreeHostX11(bounds);
721 }
722 
723 // static
GetNativeScreenSize()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 
SetUseOverrideRedirectWindowByDefault(bool override_redirect)731 void SetUseOverrideRedirectWindowByDefault(bool override_redirect) {
732   default_override_redirect = override_redirect;
733 }
734 
735 }  // namespace test
736 }  // namespace aura
737