Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/aura/root_window_host_linux.h" | 5 #include "ui/aura/root_window_host_linux.h" |
| 6 | 6 |
| 7 #include <X11/cursorfont.h> | 7 #include <X11/cursorfont.h> |
| 8 #include <X11/extensions/Xfixes.h> | 8 #include <X11/extensions/Xfixes.h> |
| 9 #include <X11/extensions/XInput2.h> | 9 #include <X11/extensions/XInput2.h> |
| 10 #include <X11/extensions/Xrandr.h> | 10 #include <X11/extensions/Xrandr.h> |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 44 namespace aura { | 44 namespace aura { |
| 45 | 45 |
| 46 namespace { | 46 namespace { |
| 47 | 47 |
| 48 // Standard Linux mouse buttons for going back and forward. | 48 // Standard Linux mouse buttons for going back and forward. |
| 49 const int kBackMouseButton = 8; | 49 const int kBackMouseButton = 8; |
| 50 const int kForwardMouseButton = 9; | 50 const int kForwardMouseButton = 9; |
| 51 | 51 |
| 52 const int kAnimatedCursorFrameDelayMs = 25; | 52 const int kAnimatedCursorFrameDelayMs = 25; |
| 53 | 53 |
| 54 const int kXRootWindowPaddingLeft = 40; | |
|
Daniel Erat
2012/09/10 17:27:31
nit: add a comment documenting what these are, and
sadrul
2012/09/10 18:19:32
Done (to make sure this gets fixed properly, I hav
| |
| 55 const int kXRootWindowPaddingRight = 40; | |
| 56 const int kXRootWindowPaddingBottom = 30; | |
| 57 const int kXRootWindowPaddingTop = 0; | |
| 58 | |
| 54 const char kRootWindowHostLinuxKey[] = "__AURA_ROOT_WINDOW_HOST_LINUX__"; | 59 const char kRootWindowHostLinuxKey[] = "__AURA_ROOT_WINDOW_HOST_LINUX__"; |
| 55 | 60 |
| 56 const char* kAtomsToCache[] = { | 61 const char* kAtomsToCache[] = { |
| 57 "WM_DELETE_WINDOW", | 62 "WM_DELETE_WINDOW", |
| 58 "_NET_WM_PING", | 63 "_NET_WM_PING", |
| 59 "_NET_WM_PID", | 64 "_NET_WM_PID", |
| 60 "WM_S0", | 65 "WM_S0", |
| 61 NULL | 66 NULL |
| 62 }; | 67 }; |
| 63 | 68 |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 261 } else { | 266 } else { |
| 262 // This isn't an event we want so free its cookie data. | 267 // This isn't an event we want so free its cookie data. |
| 263 XFreeEventData(display, &next_event.xcookie); | 268 XFreeEventData(display, &next_event.xcookie); |
| 264 } | 269 } |
| 265 } | 270 } |
| 266 break; | 271 break; |
| 267 } | 272 } |
| 268 return num_coalesed; | 273 return num_coalesed; |
| 269 } | 274 } |
| 270 | 275 |
| 276 void SelectEventsForRootWindow() { | |
| 277 XIEventMask evmask; | |
| 278 unsigned char mask[XIMaskLen(XI_LASTEVENT)] = {}; | |
| 279 memset(mask, 0, sizeof(mask)); | |
| 280 | |
| 281 XISetMask(mask, XI_HierarchyChanged); | |
| 282 | |
| 283 XISetMask(mask, XI_KeyPress); | |
| 284 XISetMask(mask, XI_KeyRelease); | |
| 285 | |
| 286 #if defined(USE_XI2_MT) | |
| 287 XISetMask(mask, XI_TouchBegin); | |
| 288 XISetMask(mask, XI_TouchUpdate); | |
| 289 XISetMask(mask, XI_TouchEnd); | |
| 290 #endif | |
| 291 XISetMask(mask, XI_ButtonPress); | |
| 292 XISetMask(mask, XI_ButtonRelease); | |
| 293 XISetMask(mask, XI_Motion); | |
| 294 | |
| 295 evmask.deviceid = XIAllDevices; | |
| 296 evmask.mask_len = sizeof(mask); | |
| 297 evmask.mask = mask; | |
| 298 | |
| 299 Display* display = ui::GetXDisplay(); | |
| 300 XISelectEvents(display, ui::GetX11RootWindow(), &evmask, 1); | |
| 301 } | |
| 302 | |
| 271 // We emulate Windows' WM_KEYDOWN and WM_CHAR messages. WM_CHAR events are only | 303 // We emulate Windows' WM_KEYDOWN and WM_CHAR messages. WM_CHAR events are only |
| 272 // generated for certain keys; see | 304 // generated for certain keys; see |
| 273 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms646268.aspx. Per | 305 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms646268.aspx. Per |
| 274 // discussion on http://crbug.com/108480, char events should furthermore not be | 306 // discussion on http://crbug.com/108480, char events should furthermore not be |
| 275 // generated for Tab, Escape, and Backspace. | 307 // generated for Tab, Escape, and Backspace. |
| 276 bool ShouldSendCharEventForKeyboardCode(ui::KeyboardCode keycode) { | 308 bool ShouldSendCharEventForKeyboardCode(ui::KeyboardCode keycode) { |
| 277 if ((keycode >= ui::VKEY_0 && keycode <= ui::VKEY_9) || | 309 if ((keycode >= ui::VKEY_0 && keycode <= ui::VKEY_9) || |
| 278 (keycode >= ui::VKEY_A && keycode <= ui::VKEY_Z) || | 310 (keycode >= ui::VKEY_A && keycode <= ui::VKEY_Z) || |
| 279 (keycode >= ui::VKEY_NUMPAD0 && keycode <= ui::VKEY_NUMPAD9)) { | 311 (keycode >= ui::VKEY_NUMPAD0 && keycode <= ui::VKEY_NUMPAD9)) { |
| 280 return true; | 312 return true; |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 524 xwindow_ = XCreateWindow( | 556 xwindow_ = XCreateWindow( |
| 525 xdisplay_, x_root_window_, | 557 xdisplay_, x_root_window_, |
| 526 bounds.x(), bounds.y(), bounds.width(), bounds.height(), | 558 bounds.x(), bounds.y(), bounds.width(), bounds.height(), |
| 527 0, // border width | 559 0, // border width |
| 528 CopyFromParent, // depth | 560 CopyFromParent, // depth |
| 529 InputOutput, | 561 InputOutput, |
| 530 CopyFromParent, // visual | 562 CopyFromParent, // visual |
| 531 CWBackPixmap, | 563 CWBackPixmap, |
| 532 &swa); | 564 &swa); |
| 533 base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(this, xwindow_); | 565 base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(this, xwindow_); |
| 566 base::MessagePumpAuraX11::Current()->AddDispatcherForRootWindow(this); | |
| 567 | |
| 568 // Get the initial size of the X root window. | |
| 569 XWindowAttributes attrs; | |
| 570 XGetWindowAttributes(xdisplay_, x_root_window_, &attrs); | |
|
Daniel Erat
2012/09/10 17:27:31
i was going to suggest XGetGeometry() instead, but
sadrul
2012/09/10 18:19:32
If XGetGeometry is less expensive than XGetWindowA
| |
| 571 root_bounds_.SetRect(attrs.x, attrs.y, attrs.width, attrs.height); | |
| 534 | 572 |
| 535 prop_.reset(new ui::ViewProp(xwindow_, kRootWindowHostLinuxKey, this)); | 573 prop_.reset(new ui::ViewProp(xwindow_, kRootWindowHostLinuxKey, this)); |
| 536 | 574 |
| 537 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask | | 575 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask | |
| 538 KeyPressMask | KeyReleaseMask | | 576 KeyPressMask | KeyReleaseMask | |
| 539 EnterWindowMask | LeaveWindowMask | | 577 EnterWindowMask | LeaveWindowMask | |
| 540 ExposureMask | VisibilityChangeMask | | 578 ExposureMask | VisibilityChangeMask | |
| 541 StructureNotifyMask | PropertyChangeMask | | 579 StructureNotifyMask | PropertyChangeMask | |
| 542 PointerMotionMask; | 580 PointerMotionMask; |
| 543 XSelectInput(xdisplay_, xwindow_, event_mask); | 581 XSelectInput(xdisplay_, xwindow_, event_mask); |
| 544 XFlush(xdisplay_); | 582 XFlush(xdisplay_); |
| 545 | 583 |
| 584 // Receive resize events for the root-window so |root_bounds_| can be updated. | |
| 585 XSelectInput(xdisplay_, x_root_window_, StructureNotifyMask); | |
|
Daniel Erat
2012/09/10 17:27:31
do this before you query the bounds; otherwise the
sadrul
2012/09/10 18:19:32
Done.
| |
| 586 | |
| 546 if (base::MessagePumpForUI::HasXInput2()) | 587 if (base::MessagePumpForUI::HasXInput2()) |
| 547 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_); | 588 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_); |
| 548 | 589 |
| 590 SelectEventsForRootWindow(); | |
| 591 | |
| 549 // Initialize invisible cursor. | 592 // Initialize invisible cursor. |
| 550 char nodata[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 593 char nodata[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
| 551 XColor black; | 594 XColor black; |
| 552 black.red = black.green = black.blue = 0; | 595 black.red = black.green = black.blue = 0; |
| 553 Pixmap blank = XCreateBitmapFromData(xdisplay_, xwindow_, | 596 Pixmap blank = XCreateBitmapFromData(xdisplay_, xwindow_, |
| 554 nodata, 8, 8); | 597 nodata, 8, 8); |
| 555 invisible_cursor_ = XCreatePixmapCursor(xdisplay_, blank, blank, | 598 invisible_cursor_ = XCreatePixmapCursor(xdisplay_, blank, blank, |
| 556 &black, &black, 0, 0); | 599 &black, &black, 0, 0); |
| 557 XFreePixmap(xdisplay_, blank); | 600 XFreePixmap(xdisplay_, blank); |
| 558 | 601 |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 586 // window to broadcast. | 629 // window to broadcast. |
| 587 // TODO(jhorwich) Remove this once Chrome supports window-based broadcasting. | 630 // TODO(jhorwich) Remove this once Chrome supports window-based broadcasting. |
| 588 static int root_window_number = 0; | 631 static int root_window_number = 0; |
| 589 std::string name = StringPrintf("aura_root_%d", root_window_number++); | 632 std::string name = StringPrintf("aura_root_%d", root_window_number++); |
| 590 XStoreName(xdisplay_, xwindow_, name.c_str()); | 633 XStoreName(xdisplay_, xwindow_, name.c_str()); |
| 591 XRRSelectInput(xdisplay_, x_root_window_, | 634 XRRSelectInput(xdisplay_, x_root_window_, |
| 592 RRScreenChangeNotifyMask | RROutputChangeNotifyMask); | 635 RRScreenChangeNotifyMask | RROutputChangeNotifyMask); |
| 593 } | 636 } |
| 594 | 637 |
| 595 RootWindowHostLinux::~RootWindowHostLinux() { | 638 RootWindowHostLinux::~RootWindowHostLinux() { |
| 639 base::MessagePumpAuraX11::Current()->RemoveDispatcherForRootWindow(this); | |
| 596 base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(xwindow_); | 640 base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(xwindow_); |
| 597 | 641 |
| 598 UnConfineCursor(); | 642 UnConfineCursor(); |
| 599 | 643 |
| 600 XDestroyWindow(xdisplay_, xwindow_); | 644 XDestroyWindow(xdisplay_, xwindow_); |
| 601 | 645 |
| 602 // Clears XCursorCache. | 646 // Clears XCursorCache. |
| 603 ui::GetXCursor(ui::kCursorClearXCursorCache); | 647 ui::GetXCursor(ui::kCursorClearXCursorCache); |
| 604 | 648 |
| 605 XFreeCursor(xdisplay_, invisible_cursor_); | 649 XFreeCursor(xdisplay_, invisible_cursor_); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 641 case ButtonRelease: { | 685 case ButtonRelease: { |
| 642 ui::MouseEvent mouseev(xev); | 686 ui::MouseEvent mouseev(xev); |
| 643 delegate_->OnHostMouseEvent(&mouseev); | 687 delegate_->OnHostMouseEvent(&mouseev); |
| 644 break; | 688 break; |
| 645 } | 689 } |
| 646 case FocusOut: | 690 case FocusOut: |
| 647 if (xev->xfocus.mode != NotifyGrab) | 691 if (xev->xfocus.mode != NotifyGrab) |
| 648 delegate_->OnHostLostCapture(); | 692 delegate_->OnHostLostCapture(); |
| 649 break; | 693 break; |
| 650 case ConfigureNotify: { | 694 case ConfigureNotify: { |
| 651 DCHECK_EQ(xwindow_, xev->xconfigure.window); | 695 if (xev->xconfigure.window == xwindow_) { |
| 652 DCHECK_EQ(xwindow_, xev->xconfigure.event); | 696 DCHECK_EQ(xwindow_, xev->xconfigure.event); |
| 653 // It's possible that the X window may be resized by some other means than | 697 // It's possible that the X window may be resized by some other means |
| 654 // from within aura (e.g. the X window manager can change the size). Make | 698 // than from within aura (e.g. the X window manager can change the |
| 655 // sure the root window size is maintained properly. | 699 // size). Make sure the root window size is maintained properly. |
| 656 gfx::Rect bounds(xev->xconfigure.x, xev->xconfigure.y, | 700 gfx::Rect bounds(xev->xconfigure.x, xev->xconfigure.y, |
| 657 xev->xconfigure.width, xev->xconfigure.height); | 701 xev->xconfigure.width, xev->xconfigure.height); |
| 658 bool size_changed = bounds_.size() != bounds.size(); | 702 bool size_changed = bounds_.size() != bounds.size(); |
| 659 bool origin_changed = bounds_.origin() != bounds.origin(); | 703 bool origin_changed = bounds_.origin() != bounds.origin(); |
| 660 bounds_ = bounds; | 704 bounds_ = bounds; |
| 661 // Update barrier and mouse location when the root window has | 705 // Update barrier and mouse location when the root window has |
| 662 // moved/resized. | 706 // moved/resized. |
| 663 if (pointer_barriers_.get() && (size_changed || origin_changed)) { | 707 if (pointer_barriers_.get() && (size_changed || origin_changed)) { |
| 664 UnConfineCursor(); | 708 UnConfineCursor(); |
| 665 RootWindow* root = delegate_->AsRootWindow(); | 709 RootWindow* root = delegate_->AsRootWindow(); |
| 666 client::ScreenPositionClient* client = | 710 client::ScreenPositionClient* client = |
| 667 client::GetScreenPositionClient(root); | 711 client::GetScreenPositionClient(root); |
| 668 if (client) { | 712 if (client) { |
| 669 gfx::Point p = gfx::Screen::GetCursorScreenPoint(); | 713 gfx::Point p = gfx::Screen::GetCursorScreenPoint(); |
| 670 client->ConvertPointFromScreen(root, &p); | 714 client->ConvertPointFromScreen(root, &p); |
| 671 if (root->ContainsPoint(p)) { | 715 if (root->ContainsPoint(p)) { |
| 672 root->ConvertPointToNativeScreen(&p); | 716 root->ConvertPointToNativeScreen(&p); |
| 673 XWarpPointer( | 717 XWarpPointer( |
| 674 xdisplay_, None, x_root_window_, 0, 0, 0, 0, p.x(), p.y()); | 718 xdisplay_, None, x_root_window_, 0, 0, 0, 0, p.x(), p.y()); |
| 719 } | |
| 675 } | 720 } |
| 721 ConfineCursorToRootWindow(); | |
| 676 } | 722 } |
| 677 ConfineCursorToRootWindow(); | 723 if (size_changed) |
| 724 delegate_->OnHostResized(bounds.size()); | |
| 725 if (origin_changed) | |
| 726 delegate_->OnHostMoved(bounds_.origin()); | |
| 727 } else { | |
| 728 DCHECK_EQ(x_root_window_, xev->xconfigure.event); | |
| 729 DCHECK_EQ(x_root_window_, xev->xconfigure.window); | |
| 730 root_bounds_.SetRect(xev->xconfigure.x, xev->xconfigure.y, | |
| 731 xev->xconfigure.width, xev->xconfigure.height); | |
| 678 } | 732 } |
| 679 if (size_changed) | |
| 680 delegate_->OnHostResized(bounds.size()); | |
| 681 if (origin_changed) | |
| 682 delegate_->OnHostMoved(bounds_.origin()); | |
| 683 break; | 733 break; |
| 684 } | 734 } |
| 685 case GenericEvent: { | 735 case GenericEvent: { |
| 686 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); | 736 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); |
| 687 if (!factory->ShouldProcessXI2Event(xev)) | 737 if (!factory->ShouldProcessXI2Event(xev)) |
| 688 break; | 738 break; |
| 689 | 739 |
| 690 ui::EventType type = ui::EventTypeFromNative(xev); | 740 ui::EventType type = ui::EventTypeFromNative(xev); |
| 691 XEvent last_event; | 741 XEvent last_event; |
| 692 int num_coalesced = 0; | 742 int num_coalesced = 0; |
| 693 | 743 |
| 694 switch (type) { | 744 switch (type) { |
| 695 case ui::ET_TOUCH_MOVED: | 745 case ui::ET_TOUCH_MOVED: |
| 696 num_coalesced = CoalescePendingMotionEvents(xev, &last_event); | 746 num_coalesced = CoalescePendingMotionEvents(xev, &last_event); |
| 697 if (num_coalesced > 0) | 747 if (num_coalesced > 0) |
| 698 xev = &last_event; | 748 xev = &last_event; |
| 699 // fallthrough | 749 // fallthrough |
| 700 case ui::ET_TOUCH_PRESSED: | 750 case ui::ET_TOUCH_PRESSED: |
| 701 case ui::ET_TOUCH_RELEASED: { | 751 case ui::ET_TOUCH_RELEASED: { |
| 702 ui::TouchEvent touchev(xev); | 752 ui::TouchEvent touchev(xev); |
| 753 // X maps the touch-surface to the size of the X root-window. In | |
| 754 // multi-monitor setup, the X root-window size is a combination of | |
| 755 // both the monitor sizes. So it is necessary to remap the location of | |
| 756 // the event from the X root-window to the X host-window for the aura | |
| 757 // root-window. | |
| 758 touchev.CalibrateLocation(root_bounds_.size(), bounds_.size()); | |
| 759 if (!bounds_.Contains(touchev.location())) { | |
| 760 // This might still be in the bezel region. | |
| 761 gfx::Rect expanded(bounds_); | |
| 762 expanded.Inset(-kXRootWindowPaddingLeft, | |
| 763 -kXRootWindowPaddingTop, | |
| 764 -kXRootWindowPaddingRight, | |
| 765 -kXRootWindowPaddingBottom); | |
| 766 if (!expanded.Contains(touchev.location())) | |
| 767 break; | |
| 768 } | |
| 703 delegate_->OnHostTouchEvent(&touchev); | 769 delegate_->OnHostTouchEvent(&touchev); |
| 704 break; | 770 break; |
| 705 } | 771 } |
| 706 case ui::ET_MOUSE_MOVED: | 772 case ui::ET_MOUSE_MOVED: |
| 707 case ui::ET_MOUSE_DRAGGED: | 773 case ui::ET_MOUSE_DRAGGED: |
| 708 case ui::ET_MOUSE_PRESSED: | 774 case ui::ET_MOUSE_PRESSED: |
| 709 case ui::ET_MOUSE_RELEASED: | 775 case ui::ET_MOUSE_RELEASED: |
| 710 case ui::ET_MOUSE_ENTERED: | 776 case ui::ET_MOUSE_ENTERED: |
| 711 case ui::ET_MOUSE_EXITED: { | 777 case ui::ET_MOUSE_EXITED: { |
| 712 if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) { | 778 if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) { |
| (...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1136 ui::ViewProp::GetValue(accelerated_widget, kRootWindowHostLinuxKey)); | 1202 ui::ViewProp::GetValue(accelerated_widget, kRootWindowHostLinuxKey)); |
| 1137 } | 1203 } |
| 1138 | 1204 |
| 1139 // static | 1205 // static |
| 1140 gfx::Size RootWindowHost::GetNativeScreenSize() { | 1206 gfx::Size RootWindowHost::GetNativeScreenSize() { |
| 1141 ::Display* xdisplay = base::MessagePumpAuraX11::GetDefaultXDisplay(); | 1207 ::Display* xdisplay = base::MessagePumpAuraX11::GetDefaultXDisplay(); |
| 1142 return gfx::Size(DisplayWidth(xdisplay, 0), DisplayHeight(xdisplay, 0)); | 1208 return gfx::Size(DisplayWidth(xdisplay, 0), DisplayHeight(xdisplay, 0)); |
| 1143 } | 1209 } |
| 1144 | 1210 |
| 1145 } // namespace aura | 1211 } // namespace aura |
| OLD | NEW |