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