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