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/root_window_host_x11.h" 6 7 #include <strings.h> 8 #include <X11/cursorfont.h> 9 #include <X11/extensions/Xfixes.h> 10 #include <X11/extensions/XInput2.h> 11 #include <X11/extensions/Xrandr.h> 12 #include <X11/Xatom.h> 13 #include <X11/Xcursor/Xcursor.h> 14 #include <X11/Xlib.h> 15 16 #include <algorithm> 17 #include <limits> 18 #include <string> 19 20 #include "base/command_line.h" 21 #include "base/debug/trace_event.h" 22 #include "base/message_loop/message_loop.h" 23 #include "base/message_loop/message_pump_aurax11.h" 24 #include "base/stl_util.h" 25 #include "base/strings/string_number_conversions.h" 26 #include "base/strings/string_util.h" 27 #include "base/strings/stringprintf.h" 28 #include "third_party/skia/include/core/SkBitmap.h" 29 #include "third_party/skia/include/core/SkCanvas.h" 30 #include "third_party/skia/include/core/SkPostConfig.h" 31 #include "ui/aura/client/capture_client.h" 32 #include "ui/aura/client/cursor_client.h" 33 #include "ui/aura/client/screen_position_client.h" 34 #include "ui/aura/client/user_action_client.h" 35 #include "ui/aura/env.h" 36 #include "ui/aura/root_window.h" 37 #include "ui/base/cursor/cursor.h" 38 #include "ui/base/events/event.h" 39 #include "ui/base/events/event_utils.h" 40 #include "ui/base/keycodes/keyboard_codes.h" 41 #include "ui/base/touch/touch_factory_x11.h" 42 #include "ui/base/ui_base_switches.h" 43 #include "ui/base/view_prop.h" 44 #include "ui/base/x/device_list_cache_x.h" 45 #include "ui/base/x/x11_util.h" 46 #include "ui/compositor/dip_util.h" 47 #include "ui/compositor/layer.h" 48 #include "ui/gfx/codec/png_codec.h" 49 #include "ui/gfx/screen.h" 50 51 #if defined(OS_CHROMEOS) 52 #include "base/chromeos/chromeos_version.h" 53 #endif 54 55 using std::max; 56 using std::min; 57 58 namespace aura { 59 60 namespace { 61 62 // Standard Linux mouse buttons for going back and forward. 63 const int kBackMouseButton = 8; 64 const int kForwardMouseButton = 9; 65 66 const char* kAtomsToCache[] = { 67 "WM_DELETE_WINDOW", 68 "_NET_WM_PING", 69 "_NET_WM_PID", 70 "WM_S0", 71 #if defined(OS_CHROMEOS) 72 "Tap Paused", // Defined in the gestures library. 73 #endif 74 NULL 75 }; 76 77 ::Window FindEventTarget(const base::NativeEvent& xev) { 78 ::Window target = xev->xany.window; 79 if (xev->type == GenericEvent) 80 target = static_cast<XIDeviceEvent*>(xev->xcookie.data)->event; 81 return target; 82 } 83 84 #if defined(USE_XI2_MT) 85 bool IsSideBezelsEnabled() { 86 static bool side_bezels_enabled = 87 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 88 switches::kTouchSideBezels) == "1"; 89 return side_bezels_enabled; 90 } 91 #endif 92 93 void SelectEventsForRootWindow() { 94 Display* display = ui::GetXDisplay(); 95 ::Window root_window = ui::GetX11RootWindow(); 96 97 // Receive resize events for the root-window so |x_root_bounds_| can be 98 // updated. 99 XWindowAttributes attr; 100 XGetWindowAttributes(display, root_window, &attr); 101 if (!(attr.your_event_mask & StructureNotifyMask)) { 102 XSelectInput(display, root_window, 103 StructureNotifyMask | attr.your_event_mask); 104 } 105 106 if (!base::MessagePumpForUI::HasXInput2()) 107 return; 108 109 unsigned char mask[XIMaskLen(XI_LASTEVENT)] = {}; 110 memset(mask, 0, sizeof(mask)); 111 112 XISetMask(mask, XI_HierarchyChanged); 113 XISetMask(mask, XI_KeyPress); 114 XISetMask(mask, XI_KeyRelease); 115 116 XIEventMask evmask; 117 evmask.deviceid = XIAllDevices; 118 evmask.mask_len = sizeof(mask); 119 evmask.mask = mask; 120 XISelectEvents(display, root_window, &evmask, 1); 121 122 // Selecting for touch events seems to fail on some cases (e.g. when logging 123 // in incognito). So select for non-touch events first, and then select for 124 // touch-events (but keep the other events in the mask, i.e. do not memset 125 // |mask| back to 0). 126 // TODO(sad): Figure out why this happens. http://crbug.com/153976 127 #if defined(USE_XI2_MT) 128 XISetMask(mask, XI_TouchBegin); 129 XISetMask(mask, XI_TouchUpdate); 130 XISetMask(mask, XI_TouchEnd); 131 XISelectEvents(display, root_window, &evmask, 1); 132 #endif 133 } 134 135 // We emulate Windows' WM_KEYDOWN and WM_CHAR messages. WM_CHAR events are only 136 // generated for certain keys; see 137 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms646268.aspx. Per 138 // discussion on http://crbug.com/108480, char events should furthermore not be 139 // generated for Tab, Escape, and Backspace. 140 bool ShouldSendCharEventForKeyboardCode(ui::KeyboardCode keycode) { 141 if ((keycode >= ui::VKEY_0 && keycode <= ui::VKEY_9) || 142 (keycode >= ui::VKEY_A && keycode <= ui::VKEY_Z) || 143 (keycode >= ui::VKEY_NUMPAD0 && keycode <= ui::VKEY_NUMPAD9)) { 144 return true; 145 } 146 147 switch (keycode) { 148 case ui::VKEY_RETURN: 149 case ui::VKEY_SPACE: 150 // In addition to the keys listed at MSDN, we include other 151 // graphic-character and numpad keys. 152 case ui::VKEY_MULTIPLY: 153 case ui::VKEY_ADD: 154 case ui::VKEY_SUBTRACT: 155 case ui::VKEY_DECIMAL: 156 case ui::VKEY_DIVIDE: 157 case ui::VKEY_OEM_1: 158 case ui::VKEY_OEM_2: 159 case ui::VKEY_OEM_3: 160 case ui::VKEY_OEM_4: 161 case ui::VKEY_OEM_5: 162 case ui::VKEY_OEM_6: 163 case ui::VKEY_OEM_7: 164 case ui::VKEY_OEM_102: 165 case ui::VKEY_OEM_PLUS: 166 case ui::VKEY_OEM_COMMA: 167 case ui::VKEY_OEM_MINUS: 168 case ui::VKEY_OEM_PERIOD: 169 return true; 170 default: 171 return false; 172 } 173 } 174 175 bool default_override_redirect = false; 176 177 } // namespace 178 179 namespace internal { 180 181 // Accomplishes 2 tasks concerning touch event calibration: 182 // 1. Being a message-pump observer, 183 // routes all the touch events to the X root window, 184 // where they can be calibrated later. 185 // 2. Has the Calibrate method that does the actual bezel calibration, 186 // when invoked from X root window's event dispatcher. 187 class TouchEventCalibrate : public base::MessagePumpObserver { 188 public: 189 TouchEventCalibrate() 190 : left_(0), 191 right_(0), 192 top_(0), 193 bottom_(0) { 194 base::MessageLoopForUI::current()->AddObserver(this); 195 #if defined(USE_XI2_MT) 196 std::vector<std::string> parts; 197 if (Tokenize(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 198 switches::kTouchCalibration), ",", &parts) >= 4) { 199 if (!base::StringToInt(parts[0], &left_)) 200 DLOG(ERROR) << "Incorrect left border calibration value passed."; 201 if (!base::StringToInt(parts[1], &right_)) 202 DLOG(ERROR) << "Incorrect right border calibration value passed."; 203 if (!base::StringToInt(parts[2], &top_)) 204 DLOG(ERROR) << "Incorrect top border calibration value passed."; 205 if (!base::StringToInt(parts[3], &bottom_)) 206 DLOG(ERROR) << "Incorrect bottom border calibration value passed."; 207 } 208 #endif // defined(USE_XI2_MT) 209 } 210 211 virtual ~TouchEventCalibrate() { 212 base::MessageLoopForUI::current()->RemoveObserver(this); 213 } 214 215 #if defined(USE_XI2_MT) 216 bool IsEventOnSideBezels( 217 const base::NativeEvent& xev, 218 const gfx::Rect& bounds) { 219 if (!left_ && !right_) 220 return false; 221 222 gfx::Point location = ui::EventLocationFromNative(xev); 223 int x = location.x(); 224 return x < left_ || x > bounds.width() - right_; 225 } 226 #endif // defined(USE_XI2_MT) 227 228 // Modify the location of the |event|, 229 // expanding it from |bounds| to (|bounds| + bezels). 230 // Required when touchscreen is bigger than screen (i.e. has bezels), 231 // because we receive events in touchscreen coordinates, 232 // which need to be expanded when converting to screen coordinates, 233 // so that location on bezels will be outside of screen area. 234 void Calibrate(ui::TouchEvent* event, const gfx::Rect& bounds) { 235 #if defined(USE_XI2_MT) 236 int x = event->x(); 237 int y = event->y(); 238 239 if (!left_ && !right_ && !top_ && !bottom_) 240 return; 241 242 const int resolution_x = bounds.width(); 243 const int resolution_y = bounds.height(); 244 // The "grace area" (10% in this case) is to make it easier for the user to 245 // navigate to the corner. 246 const double kGraceAreaFraction = 0.1; 247 if (left_ || right_) { 248 // Offset the x position to the real 249 x -= left_; 250 // Check if we are in the grace area of the left side. 251 // Note: We might not want to do this when the gesture is locked? 252 if (x < 0 && x > -left_ * kGraceAreaFraction) 253 x = 0; 254 // Check if we are in the grace area of the right side. 255 // Note: We might not want to do this when the gesture is locked? 256 if (x > resolution_x - left_ && 257 x < resolution_x - left_ + right_ * kGraceAreaFraction) 258 x = resolution_x - left_; 259 // Scale the screen area back to the full resolution of the screen. 260 x = (x * resolution_x) / (resolution_x - (right_ + left_)); 261 } 262 if (top_ || bottom_) { 263 // When there is a top bezel we add our border, 264 y -= top_; 265 266 // Check if we are in the grace area of the top side. 267 // Note: We might not want to do this when the gesture is locked? 268 if (y < 0 && y > -top_ * kGraceAreaFraction) 269 y = 0; 270 271 // Check if we are in the grace area of the bottom side. 272 // Note: We might not want to do this when the gesture is locked? 273 if (y > resolution_y - top_ && 274 y < resolution_y - top_ + bottom_ * kGraceAreaFraction) 275 y = resolution_y - top_; 276 // Scale the screen area back to the full resolution of the screen. 277 y = (y * resolution_y) / (resolution_y - (bottom_ + top_)); 278 } 279 280 // Set the modified coordinate back to the event. 281 if (event->root_location() == event->location()) { 282 // Usually those will be equal, 283 // if not, I am not sure what the correct value should be. 284 event->set_root_location(gfx::Point(x, y)); 285 } 286 event->set_location(gfx::Point(x, y)); 287 #endif // defined(USE_XI2_MT) 288 } 289 290 private: 291 // Overridden from base::MessagePumpObserver: 292 virtual base::EventStatus WillProcessEvent( 293 const base::NativeEvent& event) OVERRIDE { 294 #if defined(USE_XI2_MT) 295 if (event->type == GenericEvent && 296 (event->xgeneric.evtype == XI_TouchBegin || 297 event->xgeneric.evtype == XI_TouchUpdate || 298 event->xgeneric.evtype == XI_TouchEnd)) { 299 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(event->xcookie.data); 300 xievent->event = xievent->root; 301 xievent->event_x = xievent->root_x; 302 xievent->event_y = xievent->root_y; 303 } 304 #endif // defined(USE_XI2_MT) 305 return base::EVENT_CONTINUE; 306 } 307 308 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE { 309 } 310 311 // The difference in screen's native resolution pixels between 312 // the border of the touchscreen and the border of the screen, 313 // aka bezel sizes. 314 int left_; 315 int right_; 316 int top_; 317 int bottom_; 318 319 DISALLOW_COPY_AND_ASSIGN(TouchEventCalibrate); 320 }; 321 322 } // namespace internal 323 324 //////////////////////////////////////////////////////////////////////////////// 325 // RootWindowHostX11::MouseMoveFilter filters out the move events that 326 // jump back and forth between two points. This happens when sub pixel mouse 327 // move is enabled and mouse move events could be jumping between two neighbor 328 // pixels, e.g. move(0,0), move(1,0), move(0,0), move(1,0) and on and on. 329 // The filtering is done by keeping track of the last two event locations and 330 // provides a Filter method to find out whether a mouse event is in a different 331 // location and should be processed. 332 333 class RootWindowHostX11::MouseMoveFilter { 334 public: 335 MouseMoveFilter() : insert_index_(0) { 336 for (size_t i = 0; i < kMaxEvents; ++i) { 337 const int int_max = std::numeric_limits<int>::max(); 338 recent_locations_[i] = gfx::Point(int_max, int_max); 339 } 340 } 341 ~MouseMoveFilter() {} 342 343 // Returns true if |event| is known and should be ignored. 344 bool Filter(const base::NativeEvent& event) { 345 const gfx::Point& location = ui::EventLocationFromNative(event); 346 for (size_t i = 0; i < kMaxEvents; ++i) { 347 if (location == recent_locations_[i]) 348 return true; 349 } 350 351 recent_locations_[insert_index_] = location; 352 insert_index_ = (insert_index_ + 1) % kMaxEvents; 353 return false; 354 } 355 356 private: 357 static const size_t kMaxEvents = 2; 358 359 gfx::Point recent_locations_[kMaxEvents]; 360 size_t insert_index_; 361 362 DISALLOW_COPY_AND_ASSIGN(MouseMoveFilter); 363 }; 364 365 //////////////////////////////////////////////////////////////////////////////// 366 // RootWindowHostX11 367 368 RootWindowHostX11::RootWindowHostX11(const gfx::Rect& bounds) 369 : delegate_(NULL), 370 xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()), 371 xwindow_(0), 372 x_root_window_(DefaultRootWindow(xdisplay_)), 373 current_cursor_(ui::kCursorNull), 374 window_mapped_(false), 375 bounds_(bounds), 376 is_internal_display_(false), 377 focus_when_shown_(false), 378 touch_calibrate_(new internal::TouchEventCalibrate), 379 mouse_move_filter_(new MouseMoveFilter), 380 atom_cache_(xdisplay_, kAtomsToCache) { 381 XSetWindowAttributes swa; 382 memset(&swa, 0, sizeof(swa)); 383 swa.background_pixmap = None; 384 swa.override_redirect = default_override_redirect; 385 xwindow_ = XCreateWindow( 386 xdisplay_, x_root_window_, 387 bounds.x(), bounds.y(), bounds.width(), bounds.height(), 388 0, // border width 389 CopyFromParent, // depth 390 InputOutput, 391 CopyFromParent, // visual 392 CWBackPixmap | CWOverrideRedirect, 393 &swa); 394 base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(this, xwindow_); 395 base::MessagePumpAuraX11::Current()->AddDispatcherForRootWindow(this); 396 397 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask | 398 KeyPressMask | KeyReleaseMask | 399 EnterWindowMask | LeaveWindowMask | 400 ExposureMask | VisibilityChangeMask | 401 StructureNotifyMask | PropertyChangeMask | 402 PointerMotionMask; 403 XSelectInput(xdisplay_, xwindow_, event_mask); 404 XFlush(xdisplay_); 405 406 if (base::MessagePumpForUI::HasXInput2()) 407 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_); 408 409 SelectEventsForRootWindow(); 410 411 // Get the initial size of the X root window. 412 XWindowAttributes attrs; 413 XGetWindowAttributes(xdisplay_, x_root_window_, &attrs); 414 x_root_bounds_.SetRect(attrs.x, attrs.y, attrs.width, attrs.height); 415 416 // TODO(erg): We currently only request window deletion events. We also 417 // should listen for activation events and anything else that GTK+ listens 418 // for, and do something useful. 419 ::Atom protocols[2]; 420 protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW"); 421 protocols[1] = atom_cache_.GetAtom("_NET_WM_PING"); 422 XSetWMProtocols(xdisplay_, xwindow_, protocols, 2); 423 424 // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with 425 // the desktop environment. 426 XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL); 427 428 // Likewise, the X server needs to know this window's pid so it knows which 429 // program to kill if the window hangs. 430 pid_t pid = getpid(); 431 XChangeProperty(xdisplay_, 432 xwindow_, 433 atom_cache_.GetAtom("_NET_WM_PID"), 434 XA_CARDINAL, 435 32, 436 PropModeReplace, 437 reinterpret_cast<unsigned char*>(&pid), 1); 438 439 XRRSelectInput(xdisplay_, x_root_window_, 440 RRScreenChangeNotifyMask | RROutputChangeNotifyMask); 441 Env::GetInstance()->AddObserver(this); 442 } 443 444 RootWindowHostX11::~RootWindowHostX11() { 445 Env::GetInstance()->RemoveObserver(this); 446 base::MessagePumpAuraX11::Current()->RemoveDispatcherForRootWindow(this); 447 base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(xwindow_); 448 449 UnConfineCursor(); 450 451 XDestroyWindow(xdisplay_, xwindow_); 452 } 453 454 bool RootWindowHostX11::Dispatch(const base::NativeEvent& event) { 455 XEvent* xev = event; 456 457 if (FindEventTarget(event) == x_root_window_) 458 return DispatchEventForRootWindow(event); 459 460 switch (xev->type) { 461 case EnterNotify: { 462 ui::MouseEvent mouse_event(xev); 463 // EnterNotify creates ET_MOUSE_MOVE. Mark as synthesized as this is not 464 // real mouse move event. 465 mouse_event.set_flags(mouse_event.flags() | ui::EF_IS_SYNTHESIZED); 466 TranslateAndDispatchMouseEvent(&mouse_event); 467 break; 468 } 469 case LeaveNotify: { 470 ui::MouseEvent mouse_event(xev); 471 TranslateAndDispatchMouseEvent(&mouse_event); 472 break; 473 } 474 case Expose: { 475 gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y, 476 xev->xexpose.width, xev->xexpose.height); 477 delegate_->AsRootWindow()->ScheduleRedrawRect(damage_rect); 478 break; 479 } 480 case KeyPress: { 481 ui::KeyEvent keydown_event(xev, false); 482 delegate_->OnHostKeyEvent(&keydown_event); 483 break; 484 } 485 case KeyRelease: { 486 ui::KeyEvent keyup_event(xev, false); 487 delegate_->OnHostKeyEvent(&keyup_event); 488 break; 489 } 490 case ButtonPress: { 491 if (static_cast<int>(xev->xbutton.button) == kBackMouseButton || 492 static_cast<int>(xev->xbutton.button) == kForwardMouseButton) { 493 client::UserActionClient* gesture_client = 494 client::GetUserActionClient(delegate_->AsRootWindow()); 495 if (gesture_client) { 496 gesture_client->OnUserAction( 497 static_cast<int>(xev->xbutton.button) == kBackMouseButton ? 498 client::UserActionClient::BACK : 499 client::UserActionClient::FORWARD); 500 } 501 break; 502 } 503 } // fallthrough 504 case ButtonRelease: { 505 ui::MouseEvent mouseev(xev); 506 TranslateAndDispatchMouseEvent(&mouseev); 507 break; 508 } 509 case FocusOut: 510 if (xev->xfocus.mode != NotifyGrab) 511 delegate_->OnHostLostWindowCapture(); 512 break; 513 case ConfigureNotify: { 514 DCHECK_EQ(xwindow_, xev->xconfigure.event); 515 DCHECK_EQ(xwindow_, xev->xconfigure.window); 516 // It's possible that the X window may be resized by some other means 517 // than from within aura (e.g. the X window manager can change the 518 // size). Make sure the root window size is maintained properly. 519 gfx::Rect bounds(xev->xconfigure.x, xev->xconfigure.y, 520 xev->xconfigure.width, xev->xconfigure.height); 521 bool size_changed = bounds_.size() != bounds.size(); 522 bool origin_changed = bounds_.origin() != bounds.origin(); 523 bounds_ = bounds; 524 UpdateIsInternalDisplay(); 525 // Always update barrier and mouse location because |bounds_| might 526 // have already been updated in |SetBounds|. 527 if (pointer_barriers_) { 528 UnConfineCursor(); 529 ConfineCursorToRootWindow(); 530 } 531 if (size_changed) 532 delegate_->OnHostResized(bounds.size()); 533 if (origin_changed) 534 delegate_->OnHostMoved(bounds_.origin()); 535 break; 536 } 537 case GenericEvent: 538 DispatchXI2Event(event); 539 break; 540 case MapNotify: { 541 // If there's no window manager running, we need to assign the X input 542 // focus to our host window. 543 if (!IsWindowManagerPresent() && focus_when_shown_) 544 XSetInputFocus(xdisplay_, xwindow_, RevertToNone, CurrentTime); 545 break; 546 } 547 case ClientMessage: { 548 Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]); 549 if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) { 550 // We have received a close message from the window manager. 551 delegate_->AsRootWindow()->OnRootWindowHostCloseRequested(); 552 } else if (message_type == atom_cache_.GetAtom("_NET_WM_PING")) { 553 XEvent reply_event = *xev; 554 reply_event.xclient.window = x_root_window_; 555 556 XSendEvent(xdisplay_, 557 reply_event.xclient.window, 558 False, 559 SubstructureRedirectMask | SubstructureNotifyMask, 560 &reply_event); 561 } 562 break; 563 } 564 case MappingNotify: { 565 switch (xev->xmapping.request) { 566 case MappingModifier: 567 case MappingKeyboard: 568 XRefreshKeyboardMapping(&xev->xmapping); 569 delegate_->AsRootWindow()->OnKeyboardMappingChanged(); 570 break; 571 case MappingPointer: 572 ui::UpdateButtonMap(); 573 break; 574 default: 575 NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request; 576 break; 577 } 578 break; 579 } 580 case MotionNotify: { 581 // Discard all but the most recent motion event that targets the same 582 // window with unchanged state. 583 XEvent last_event; 584 while (XPending(xev->xany.display)) { 585 XEvent next_event; 586 XPeekEvent(xev->xany.display, &next_event); 587 if (next_event.type == MotionNotify && 588 next_event.xmotion.window == xev->xmotion.window && 589 next_event.xmotion.subwindow == xev->xmotion.subwindow && 590 next_event.xmotion.state == xev->xmotion.state) { 591 XNextEvent(xev->xany.display, &last_event); 592 xev = &last_event; 593 } else { 594 break; 595 } 596 } 597 598 ui::MouseEvent mouseev(xev); 599 TranslateAndDispatchMouseEvent(&mouseev); 600 break; 601 } 602 } 603 return true; 604 } 605 606 void RootWindowHostX11::SetDelegate(RootWindowHostDelegate* delegate) { 607 delegate_ = delegate; 608 } 609 610 RootWindow* RootWindowHostX11::GetRootWindow() { 611 return delegate_->AsRootWindow(); 612 } 613 614 gfx::AcceleratedWidget RootWindowHostX11::GetAcceleratedWidget() { 615 return xwindow_; 616 } 617 618 void RootWindowHostX11::Show() { 619 if (!window_mapped_) { 620 // Before we map the window, set size hints. Otherwise, some window managers 621 // will ignore toplevel XMoveWindow commands. 622 XSizeHints size_hints; 623 size_hints.flags = PPosition | PWinGravity; 624 size_hints.x = bounds_.x(); 625 size_hints.y = bounds_.y(); 626 // Set StaticGravity so that the window position is not affected by the 627 // frame width when running with window manager. 628 size_hints.win_gravity = StaticGravity; 629 XSetWMNormalHints(xdisplay_, xwindow_, &size_hints); 630 631 XMapWindow(xdisplay_, xwindow_); 632 633 // We now block until our window is mapped. Some X11 APIs will crash and 634 // burn if passed |xwindow_| before the window is mapped, and XMapWindow is 635 // asynchronous. 636 base::MessagePumpAuraX11::Current()->BlockUntilWindowMapped(xwindow_); 637 window_mapped_ = true; 638 } 639 } 640 641 void RootWindowHostX11::Hide() { 642 if (window_mapped_) { 643 XWithdrawWindow(xdisplay_, xwindow_, 0); 644 window_mapped_ = false; 645 } 646 } 647 648 void RootWindowHostX11::ToggleFullScreen() { 649 NOTIMPLEMENTED(); 650 } 651 652 gfx::Rect RootWindowHostX11::GetBounds() const { 653 return bounds_; 654 } 655 656 void RootWindowHostX11::SetBounds(const gfx::Rect& bounds) { 657 // Even if the host window's size doesn't change, aura's root window 658 // size, which is in DIP, changes when the scale changes. 659 float current_scale = delegate_->GetDeviceScaleFactor(); 660 float new_scale = gfx::Screen::GetScreenFor(delegate_->AsRootWindow())-> 661 GetDisplayNearestWindow(delegate_->AsRootWindow()).device_scale_factor(); 662 bool origin_changed = bounds_.origin() != bounds.origin(); 663 bool size_changed = bounds_.size() != bounds.size(); 664 XWindowChanges changes = {0}; 665 unsigned value_mask = 0; 666 667 if (size_changed) { 668 changes.width = bounds.width(); 669 changes.height = bounds.height(); 670 value_mask = CWHeight | CWWidth; 671 } 672 673 if (origin_changed) { 674 changes.x = bounds.x(); 675 changes.y = bounds.y(); 676 value_mask |= CWX | CWY; 677 } 678 if (value_mask) 679 XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes); 680 681 // Assume that the resize will go through as requested, which should be the 682 // case if we're running without a window manager. If there's a window 683 // manager, it can modify or ignore the request, but (per ICCCM) we'll get a 684 // (possibly synthetic) ConfigureNotify about the actual size and correct 685 // |bounds_| later. 686 bounds_ = bounds; 687 UpdateIsInternalDisplay(); 688 if (origin_changed) 689 delegate_->OnHostMoved(bounds.origin()); 690 if (size_changed || current_scale != new_scale) { 691 delegate_->OnHostResized(bounds.size()); 692 } else { 693 delegate_->AsRootWindow()->SchedulePaintInRect( 694 delegate_->AsRootWindow()->bounds()); 695 } 696 } 697 698 gfx::Insets RootWindowHostX11::GetInsets() const { 699 return insets_; 700 } 701 702 void RootWindowHostX11::SetInsets(const gfx::Insets& insets) { 703 insets_ = insets; 704 if (pointer_barriers_) { 705 UnConfineCursor(); 706 ConfineCursorToRootWindow(); 707 } 708 } 709 710 gfx::Point RootWindowHostX11::GetLocationOnNativeScreen() const { 711 return bounds_.origin(); 712 } 713 714 void RootWindowHostX11::SetCapture() { 715 // TODO(oshima): Grab x input. 716 } 717 718 void RootWindowHostX11::ReleaseCapture() { 719 // TODO(oshima): Release x input. 720 } 721 722 void RootWindowHostX11::SetCursor(gfx::NativeCursor cursor) { 723 if (cursor == current_cursor_) 724 return; 725 current_cursor_ = cursor; 726 SetCursorInternal(cursor); 727 } 728 729 bool RootWindowHostX11::QueryMouseLocation(gfx::Point* location_return) { 730 client::CursorClient* cursor_client = 731 client::GetCursorClient(GetRootWindow()); 732 if (cursor_client && !cursor_client->IsMouseEventsEnabled()) { 733 *location_return = gfx::Point(0, 0); 734 return false; 735 } 736 737 ::Window root_return, child_return; 738 int root_x_return, root_y_return, win_x_return, win_y_return; 739 unsigned int mask_return; 740 XQueryPointer(xdisplay_, 741 xwindow_, 742 &root_return, 743 &child_return, 744 &root_x_return, &root_y_return, 745 &win_x_return, &win_y_return, 746 &mask_return); 747 *location_return = gfx::Point(max(0, min(bounds_.width(), win_x_return)), 748 max(0, min(bounds_.height(), win_y_return))); 749 return (win_x_return >= 0 && win_x_return < bounds_.width() && 750 win_y_return >= 0 && win_y_return < bounds_.height()); 751 } 752 753 bool RootWindowHostX11::ConfineCursorToRootWindow() { 754 #if XFIXES_MAJOR >= 5 755 DCHECK(!pointer_barriers_.get()); 756 if (pointer_barriers_) 757 return false; 758 pointer_barriers_.reset(new XID[4]); 759 gfx::Rect bounds(bounds_); 760 bounds.Inset(insets_); 761 // Horizontal, top barriers. 762 pointer_barriers_[0] = XFixesCreatePointerBarrier( 763 xdisplay_, x_root_window_, 764 bounds.x(), bounds.y(), bounds.right(), bounds.y(), 765 BarrierPositiveY, 766 0, XIAllDevices); 767 // Horizontal, bottom barriers. 768 pointer_barriers_[1] = XFixesCreatePointerBarrier( 769 xdisplay_, x_root_window_, 770 bounds.x(), bounds.bottom(), bounds.right(), bounds.bottom(), 771 BarrierNegativeY, 772 0, XIAllDevices); 773 // Vertical, left barriers. 774 pointer_barriers_[2] = XFixesCreatePointerBarrier( 775 xdisplay_, x_root_window_, 776 bounds.x(), bounds.y(), bounds.x(), bounds.bottom(), 777 BarrierPositiveX, 778 0, XIAllDevices); 779 // Vertical, right barriers. 780 pointer_barriers_[3] = XFixesCreatePointerBarrier( 781 xdisplay_, x_root_window_, 782 bounds.right(), bounds.y(), bounds.right(), bounds.bottom(), 783 BarrierNegativeX, 784 0, XIAllDevices); 785 #endif 786 return true; 787 } 788 789 void RootWindowHostX11::UnConfineCursor() { 790 #if XFIXES_MAJOR >= 5 791 if (pointer_barriers_) { 792 XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[0]); 793 XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[1]); 794 XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[2]); 795 XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[3]); 796 pointer_barriers_.reset(); 797 } 798 #endif 799 } 800 801 void RootWindowHostX11::OnCursorVisibilityChanged(bool show) { 802 SetCrOSTapPaused(!show); 803 } 804 805 void RootWindowHostX11::MoveCursorTo(const gfx::Point& location) { 806 XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0, 807 bounds_.x() + location.x(), 808 bounds_.y() + location.y()); 809 } 810 811 void RootWindowHostX11::SetFocusWhenShown(bool focus_when_shown) { 812 static const char* k_NET_WM_USER_TIME = "_NET_WM_USER_TIME"; 813 focus_when_shown_ = focus_when_shown; 814 if (IsWindowManagerPresent() && !focus_when_shown_) { 815 ui::SetIntProperty(xwindow_, 816 k_NET_WM_USER_TIME, 817 k_NET_WM_USER_TIME, 818 0); 819 } 820 } 821 822 bool RootWindowHostX11::CopyAreaToSkCanvas(const gfx::Rect& source_bounds, 823 const gfx::Point& dest_offset, 824 SkCanvas* canvas) { 825 ui::XScopedImage scoped_image( 826 XGetImage(xdisplay_, xwindow_, 827 source_bounds.x(), source_bounds.y(), 828 source_bounds.width(), source_bounds.height(), 829 AllPlanes, ZPixmap)); 830 XImage* image = scoped_image.get(); 831 if (!image) { 832 LOG(ERROR) << "XGetImage failed"; 833 return false; 834 } 835 836 if (image->bits_per_pixel == 32) { 837 if ((0xff << SK_R32_SHIFT) != image->red_mask || 838 (0xff << SK_G32_SHIFT) != image->green_mask || 839 (0xff << SK_B32_SHIFT) != image->blue_mask) { 840 LOG(WARNING) << "XImage and Skia byte orders differ"; 841 return false; 842 } 843 844 // Set the alpha channel before copying to the canvas. Otherwise, areas of 845 // the framebuffer that were cleared by ply-image rather than being obscured 846 // by an image during boot may end up transparent. 847 // TODO(derat|marcheu): Remove this if/when ply-image has been updated to 848 // set the framebuffer's alpha channel regardless of whether the device 849 // claims to support alpha or not. 850 for (int i = 0; i < image->width * image->height * 4; i += 4) 851 image->data[i + 3] = 0xff; 852 853 SkBitmap bitmap; 854 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 855 image->width, image->height, 856 image->bytes_per_line); 857 bitmap.setPixels(image->data); 858 canvas->drawBitmap(bitmap, SkIntToScalar(0), SkIntToScalar(0), NULL); 859 } else { 860 NOTIMPLEMENTED() << "Unsupported bits-per-pixel " << image->bits_per_pixel; 861 return false; 862 } 863 864 return true; 865 } 866 867 void RootWindowHostX11::PostNativeEvent( 868 const base::NativeEvent& native_event) { 869 DCHECK(xwindow_); 870 DCHECK(xdisplay_); 871 XEvent xevent = *native_event; 872 xevent.xany.display = xdisplay_; 873 xevent.xany.window = xwindow_; 874 875 switch (xevent.type) { 876 case EnterNotify: 877 case LeaveNotify: 878 case MotionNotify: 879 case KeyPress: 880 case KeyRelease: 881 case ButtonPress: 882 case ButtonRelease: { 883 // The fields used below are in the same place for all of events 884 // above. Using xmotion from XEvent's unions to avoid repeating 885 // the code. 886 xevent.xmotion.root = x_root_window_; 887 xevent.xmotion.time = CurrentTime; 888 889 gfx::Point point(xevent.xmotion.x, xevent.xmotion.y); 890 delegate_->AsRootWindow()->ConvertPointToNativeScreen(&point); 891 xevent.xmotion.x_root = point.x(); 892 xevent.xmotion.y_root = point.y(); 893 } 894 default: 895 break; 896 } 897 XSendEvent(xdisplay_, xwindow_, False, 0, &xevent); 898 } 899 900 void RootWindowHostX11::OnDeviceScaleFactorChanged( 901 float device_scale_factor) { 902 } 903 904 void RootWindowHostX11::PrepareForShutdown() { 905 base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(xwindow_); 906 } 907 908 void RootWindowHostX11::OnWindowInitialized(Window* window) { 909 } 910 911 void RootWindowHostX11::OnRootWindowInitialized(RootWindow* root_window) { 912 // UpdateIsInternalDisplay relies on: 913 // 1. delegate_ pointing to RootWindow - available after SetDelegate. 914 // 2. RootWindow's kDisplayIdKey property set - available by the time 915 // RootWindow::Init is called. 916 // (set in DisplayManager::CreateRootWindowForDisplay) 917 // Ready when NotifyRootWindowInitialized is called from RootWindow::Init. 918 if (!delegate_ || root_window != GetRootWindow()) 919 return; 920 UpdateIsInternalDisplay(); 921 922 // We have to enable Tap-to-click by default because the cursor is set to 923 // visible in Shell::InitRootWindowController. 924 SetCrOSTapPaused(false); 925 } 926 927 bool RootWindowHostX11::DispatchEventForRootWindow( 928 const base::NativeEvent& event) { 929 switch (event->type) { 930 case ConfigureNotify: 931 DCHECK_EQ(x_root_window_, event->xconfigure.event); 932 x_root_bounds_.SetRect(event->xconfigure.x, event->xconfigure.y, 933 event->xconfigure.width, event->xconfigure.height); 934 break; 935 936 case GenericEvent: 937 DispatchXI2Event(event); 938 break; 939 } 940 941 return true; 942 } 943 944 void RootWindowHostX11::DispatchXI2Event(const base::NativeEvent& event) { 945 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); 946 XEvent* xev = event; 947 if (!factory->ShouldProcessXI2Event(xev)) 948 return; 949 950 TRACE_EVENT1("input", "RootWindowHostX11::DispatchXI2Event", 951 "event_latency_us", 952 (ui::EventTimeForNow() - ui::EventTimeFromNative(event)). 953 InMicroseconds()); 954 955 ui::EventType type = ui::EventTypeFromNative(xev); 956 XEvent last_event; 957 int num_coalesced = 0; 958 959 switch (type) { 960 case ui::ET_TOUCH_MOVED: 961 case ui::ET_TOUCH_PRESSED: 962 case ui::ET_TOUCH_CANCELLED: 963 case ui::ET_TOUCH_RELEASED: { 964 #if defined(USE_XI2_MT) 965 // Ignore events from the bezel when the side bezel flag is not explicitly 966 // enabled. 967 if (!IsSideBezelsEnabled() && 968 touch_calibrate_->IsEventOnSideBezels(xev, bounds_)) { 969 break; 970 } 971 #endif // defined(USE_XI2_MT) 972 ui::TouchEvent touchev(xev); 973 #if defined(OS_CHROMEOS) 974 if (base::chromeos::IsRunningOnChromeOS()) { 975 if (!bounds_.Contains(touchev.location())) 976 break; 977 // X maps the touch-surface to the size of the X root-window. 978 // In multi-monitor setup, Coordinate Transformation Matrix 979 // repositions the touch-surface onto part of X root-window 980 // containing aura root-window corresponding to the touchscreen. 981 // However, if aura root-window has non-zero origin, 982 // we need to relocate the event into aura root-window coordinates. 983 touchev.Relocate(bounds_.origin()); 984 #if defined(USE_XI2_MT) 985 if (is_internal_display_) 986 touch_calibrate_->Calibrate(&touchev, bounds_); 987 #endif // defined(USE_XI2_MT) 988 } 989 #endif // defined(OS_CHROMEOS) 990 delegate_->OnHostTouchEvent(&touchev); 991 break; 992 } 993 case ui::ET_MOUSE_MOVED: 994 case ui::ET_MOUSE_DRAGGED: 995 case ui::ET_MOUSE_PRESSED: 996 case ui::ET_MOUSE_RELEASED: 997 case ui::ET_MOUSE_ENTERED: 998 case ui::ET_MOUSE_EXITED: { 999 if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) { 1000 // If this is a motion event, we want to coalesce all pending motion 1001 // events that are at the top of the queue. 1002 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event); 1003 if (num_coalesced > 0) 1004 xev = &last_event; 1005 1006 if (mouse_move_filter_ && mouse_move_filter_->Filter(xev)) 1007 break; 1008 } else if (type == ui::ET_MOUSE_PRESSED || 1009 type == ui::ET_MOUSE_RELEASED) { 1010 XIDeviceEvent* xievent = 1011 static_cast<XIDeviceEvent*>(xev->xcookie.data); 1012 int button = xievent->detail; 1013 if (button == kBackMouseButton || button == kForwardMouseButton) { 1014 if (type == ui::ET_MOUSE_RELEASED) 1015 break; 1016 client::UserActionClient* gesture_client = 1017 client::GetUserActionClient(delegate_->AsRootWindow()); 1018 if (gesture_client) { 1019 bool reverse_direction = 1020 ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled(); 1021 gesture_client->OnUserAction( 1022 (button == kBackMouseButton && !reverse_direction) || 1023 (button == kForwardMouseButton && reverse_direction) ? 1024 client::UserActionClient::BACK : 1025 client::UserActionClient::FORWARD); 1026 } 1027 break; 1028 } 1029 } 1030 ui::MouseEvent mouseev(xev); 1031 TranslateAndDispatchMouseEvent(&mouseev); 1032 break; 1033 } 1034 case ui::ET_MOUSEWHEEL: { 1035 ui::MouseWheelEvent mouseev(xev); 1036 TranslateAndDispatchMouseEvent(&mouseev); 1037 break; 1038 } 1039 case ui::ET_SCROLL_FLING_START: 1040 case ui::ET_SCROLL_FLING_CANCEL: 1041 case ui::ET_SCROLL: { 1042 ui::ScrollEvent scrollev(xev); 1043 delegate_->OnHostScrollEvent(&scrollev); 1044 break; 1045 } 1046 case ui::ET_UMA_DATA: 1047 break; 1048 case ui::ET_UNKNOWN: 1049 break; 1050 default: 1051 NOTREACHED(); 1052 } 1053 1054 // If we coalesced an event we need to free its cookie. 1055 if (num_coalesced > 0) 1056 XFreeEventData(xev->xgeneric.display, &last_event.xcookie); 1057 } 1058 1059 bool RootWindowHostX11::IsWindowManagerPresent() { 1060 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership 1061 // of WM_Sn selections (where n is a screen number). 1062 return XGetSelectionOwner( 1063 xdisplay_, atom_cache_.GetAtom("WM_S0")) != None; 1064 } 1065 1066 void RootWindowHostX11::SetCursorInternal(gfx::NativeCursor cursor) { 1067 XDefineCursor(xdisplay_, xwindow_, cursor.platform()); 1068 } 1069 1070 void RootWindowHostX11::TranslateAndDispatchMouseEvent( 1071 ui::MouseEvent* event) { 1072 RootWindow* root_window = GetRootWindow(); 1073 client::ScreenPositionClient* screen_position_client = 1074 GetScreenPositionClient(root_window); 1075 gfx::Rect local(bounds_.size()); 1076 1077 if (screen_position_client && !local.Contains(event->location())) { 1078 gfx::Point location(event->location()); 1079 // In order to get the correct point in screen coordinates 1080 // during passive grab, we first need to find on which host window 1081 // the mouse is on, and find out the screen coordinates on that 1082 // host window, then convert it back to this host window's coordinate. 1083 screen_position_client->ConvertHostPointToScreen(root_window, &location); 1084 screen_position_client->ConvertPointFromScreen(root_window, &location); 1085 root_window->ConvertPointToHost(&location); 1086 event->set_location(location); 1087 event->set_root_location(location); 1088 } 1089 delegate_->OnHostMouseEvent(event); 1090 } 1091 1092 void RootWindowHostX11::UpdateIsInternalDisplay() { 1093 RootWindow* root_window = GetRootWindow(); 1094 gfx::Screen* screen = gfx::Screen::GetScreenFor(root_window); 1095 gfx::Display display = screen->GetDisplayNearestWindow(root_window); 1096 is_internal_display_ = display.IsInternal(); 1097 } 1098 1099 void RootWindowHostX11::SetCrOSTapPaused(bool state) { 1100 #if defined(OS_CHROMEOS) 1101 // Temporarily pause tap-to-click when the cursor is hidden. 1102 Atom prop = atom_cache_.GetAtom("Tap Paused"); 1103 unsigned char value = state; 1104 XIDeviceList dev_list = 1105 ui::DeviceListCacheX::GetInstance()->GetXI2DeviceList(xdisplay_); 1106 1107 // Only slave pointer devices could possibly have tap-paused property. 1108 for (int i = 0; i < dev_list.count; i++) { 1109 if (dev_list[i].use == XISlavePointer) { 1110 Atom old_type; 1111 int old_format; 1112 unsigned long old_nvalues, bytes; 1113 unsigned char* data; 1114 int result = XIGetProperty(xdisplay_, dev_list[i].deviceid, prop, 0, 0, 1115 False, AnyPropertyType, &old_type, &old_format, 1116 &old_nvalues, &bytes, &data); 1117 if (result != Success) 1118 continue; 1119 XFree(data); 1120 XIChangeProperty(xdisplay_, dev_list[i].deviceid, prop, XA_INTEGER, 8, 1121 PropModeReplace, &value, 1); 1122 } 1123 } 1124 #endif 1125 } 1126 1127 // static 1128 RootWindowHost* RootWindowHost::Create(const gfx::Rect& bounds) { 1129 return new RootWindowHostX11(bounds); 1130 } 1131 1132 // static 1133 gfx::Size RootWindowHost::GetNativeScreenSize() { 1134 ::Display* xdisplay = base::MessagePumpAuraX11::GetDefaultXDisplay(); 1135 return gfx::Size(DisplayWidth(xdisplay, 0), DisplayHeight(xdisplay, 0)); 1136 } 1137 1138 namespace test { 1139 1140 void SetUseOverrideRedirectWindowByDefault(bool override_redirect) { 1141 default_override_redirect = override_redirect; 1142 } 1143 1144 } // namespace test 1145 } // namespace aura 1146