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