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