Get foreground tab on Android
[chromium-blink-merge.git] / ui / aura / root_window_host_x11.cc
blob08c8ca6f088d159ada39da33ad8fe13bc809780e
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.
5 #include "ui/aura/root_window_host_x11.h"
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>
16 #include <algorithm>
17 #include <limits>
18 #include <string>
20 #include "base/basictypes.h"
21 #include "base/command_line.h"
22 #include "base/debug/trace_event.h"
23 #include "base/message_loop/message_loop.h"
24 #include "base/message_loop/message_pump_x11.h"
25 #include "base/stl_util.h"
26 #include "base/strings/string_number_conversions.h"
27 #include "base/strings/string_util.h"
28 #include "base/strings/stringprintf.h"
29 #include "base/sys_info.h"
30 #include "ui/aura/client/cursor_client.h"
31 #include "ui/aura/client/screen_position_client.h"
32 #include "ui/aura/client/user_action_client.h"
33 #include "ui/aura/env.h"
34 #include "ui/aura/root_window.h"
35 #include "ui/base/cursor/cursor.h"
36 #include "ui/base/ui_base_switches.h"
37 #include "ui/base/view_prop.h"
38 #include "ui/base/x/x11_util.h"
39 #include "ui/compositor/dip_util.h"
40 #include "ui/compositor/layer.h"
41 #include "ui/events/event.h"
42 #include "ui/events/event_utils.h"
43 #include "ui/events/keycodes/keyboard_codes.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"
49 using std::max;
50 using std::min;
52 namespace aura {
54 namespace {
56 // Standard Linux mouse buttons for going back and forward.
57 const int kBackMouseButton = 8;
58 const int kForwardMouseButton = 9;
60 const char* kAtomsToCache[] = {
61 "WM_DELETE_WINDOW",
62 "_NET_WM_PING",
63 "_NET_WM_PID",
64 "WM_S0",
65 #if defined(OS_CHROMEOS)
66 "Tap Paused", // Defined in the gestures library.
67 #endif
68 NULL
71 ::Window FindEventTarget(const base::NativeEvent& xev) {
72 ::Window target = xev->xany.window;
73 if (xev->type == GenericEvent)
74 target = static_cast<XIDeviceEvent*>(xev->xcookie.data)->event;
75 return target;
78 #if defined(USE_XI2_MT)
79 bool IsSideBezelsEnabled() {
80 static bool side_bezels_enabled =
81 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
82 switches::kTouchSideBezels) != "0";
83 return side_bezels_enabled;
85 #endif
87 void SelectEventsForRootWindow() {
88 XDisplay* display = gfx::GetXDisplay();
89 ::Window root_window = ui::GetX11RootWindow();
91 // Receive resize events for the root-window so |x_root_bounds_| can be
92 // updated.
93 XWindowAttributes attr;
94 XGetWindowAttributes(display, root_window, &attr);
95 if (!(attr.your_event_mask & StructureNotifyMask)) {
96 XSelectInput(display, root_window,
97 StructureNotifyMask | attr.your_event_mask);
100 if (!ui::IsXInput2Available())
101 return;
103 unsigned char mask[XIMaskLen(XI_LASTEVENT)] = {};
104 memset(mask, 0, sizeof(mask));
106 XISetMask(mask, XI_HierarchyChanged);
107 XISetMask(mask, XI_KeyPress);
108 XISetMask(mask, XI_KeyRelease);
110 XIEventMask evmask;
111 evmask.deviceid = XIAllDevices;
112 evmask.mask_len = sizeof(mask);
113 evmask.mask = mask;
114 XISelectEvents(display, root_window, &evmask, 1);
116 // Selecting for touch events seems to fail on some cases (e.g. when logging
117 // in incognito). So select for non-touch events first, and then select for
118 // touch-events (but keep the other events in the mask, i.e. do not memset
119 // |mask| back to 0).
120 // TODO(sad): Figure out why this happens. http://crbug.com/153976
121 #if defined(USE_XI2_MT)
122 XISetMask(mask, XI_TouchBegin);
123 XISetMask(mask, XI_TouchUpdate);
124 XISetMask(mask, XI_TouchEnd);
125 XISelectEvents(display, root_window, &evmask, 1);
126 #endif
129 bool default_override_redirect = false;
131 } // namespace
133 namespace internal {
135 // Accomplishes 2 tasks concerning touch event calibration:
136 // 1. Being a message-pump observer,
137 // routes all the touch events to the X root window,
138 // where they can be calibrated later.
139 // 2. Has the Calibrate method that does the actual bezel calibration,
140 // when invoked from X root window's event dispatcher.
141 class TouchEventCalibrate : public base::MessagePumpObserver {
142 public:
143 TouchEventCalibrate()
144 : left_(0),
145 right_(0),
146 top_(0),
147 bottom_(0) {
148 base::MessageLoopForUI::current()->AddObserver(this);
149 #if defined(USE_XI2_MT)
150 std::vector<std::string> parts;
151 if (Tokenize(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
152 switches::kTouchCalibration), ",", &parts) >= 4) {
153 if (!base::StringToInt(parts[0], &left_))
154 DLOG(ERROR) << "Incorrect left border calibration value passed.";
155 if (!base::StringToInt(parts[1], &right_))
156 DLOG(ERROR) << "Incorrect right border calibration value passed.";
157 if (!base::StringToInt(parts[2], &top_))
158 DLOG(ERROR) << "Incorrect top border calibration value passed.";
159 if (!base::StringToInt(parts[3], &bottom_))
160 DLOG(ERROR) << "Incorrect bottom border calibration value passed.";
162 #endif // defined(USE_XI2_MT)
165 virtual ~TouchEventCalibrate() {
166 base::MessageLoopForUI::current()->RemoveObserver(this);
169 #if defined(USE_XI2_MT)
170 bool IsEventOnSideBezels(
171 const base::NativeEvent& xev,
172 const gfx::Rect& bounds) {
173 if (!left_ && !right_)
174 return false;
176 gfx::Point location = ui::EventLocationFromNative(xev);
177 int x = location.x();
178 return x < left_ || x > bounds.width() - right_;
180 #endif // defined(USE_XI2_MT)
182 // Modify the location of the |event|,
183 // expanding it from |bounds| to (|bounds| + bezels).
184 // Required when touchscreen is bigger than screen (i.e. has bezels),
185 // because we receive events in touchscreen coordinates,
186 // which need to be expanded when converting to screen coordinates,
187 // so that location on bezels will be outside of screen area.
188 void Calibrate(ui::TouchEvent* event, const gfx::Rect& bounds) {
189 #if defined(USE_XI2_MT)
190 int x = event->x();
191 int y = event->y();
193 if (!left_ && !right_ && !top_ && !bottom_)
194 return;
196 const int resolution_x = bounds.width();
197 const int resolution_y = bounds.height();
198 // The "grace area" (10% in this case) is to make it easier for the user to
199 // navigate to the corner.
200 const double kGraceAreaFraction = 0.1;
201 if (left_ || right_) {
202 // Offset the x position to the real
203 x -= left_;
204 // Check if we are in the grace area of the left side.
205 // Note: We might not want to do this when the gesture is locked?
206 if (x < 0 && x > -left_ * kGraceAreaFraction)
207 x = 0;
208 // Check if we are in the grace area of the right side.
209 // Note: We might not want to do this when the gesture is locked?
210 if (x > resolution_x - left_ &&
211 x < resolution_x - left_ + right_ * kGraceAreaFraction)
212 x = resolution_x - left_;
213 // Scale the screen area back to the full resolution of the screen.
214 x = (x * resolution_x) / (resolution_x - (right_ + left_));
216 if (top_ || bottom_) {
217 // When there is a top bezel we add our border,
218 y -= top_;
220 // Check if we are in the grace area of the top side.
221 // Note: We might not want to do this when the gesture is locked?
222 if (y < 0 && y > -top_ * kGraceAreaFraction)
223 y = 0;
225 // Check if we are in the grace area of the bottom side.
226 // Note: We might not want to do this when the gesture is locked?
227 if (y > resolution_y - top_ &&
228 y < resolution_y - top_ + bottom_ * kGraceAreaFraction)
229 y = resolution_y - top_;
230 // Scale the screen area back to the full resolution of the screen.
231 y = (y * resolution_y) / (resolution_y - (bottom_ + top_));
234 // Set the modified coordinate back to the event.
235 if (event->root_location() == event->location()) {
236 // Usually those will be equal,
237 // if not, I am not sure what the correct value should be.
238 event->set_root_location(gfx::Point(x, y));
240 event->set_location(gfx::Point(x, y));
241 #endif // defined(USE_XI2_MT)
244 private:
245 // Overridden from base::MessagePumpObserver:
246 virtual base::EventStatus WillProcessEvent(
247 const base::NativeEvent& event) OVERRIDE {
248 #if defined(USE_XI2_MT)
249 if (event->type == GenericEvent &&
250 (event->xgeneric.evtype == XI_TouchBegin ||
251 event->xgeneric.evtype == XI_TouchUpdate ||
252 event->xgeneric.evtype == XI_TouchEnd)) {
253 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(event->xcookie.data);
254 xievent->event = xievent->root;
255 xievent->event_x = xievent->root_x;
256 xievent->event_y = xievent->root_y;
258 #endif // defined(USE_XI2_MT)
259 return base::EVENT_CONTINUE;
262 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
265 // The difference in screen's native resolution pixels between
266 // the border of the touchscreen and the border of the screen,
267 // aka bezel sizes.
268 int left_;
269 int right_;
270 int top_;
271 int bottom_;
273 DISALLOW_COPY_AND_ASSIGN(TouchEventCalibrate);
276 } // namespace internal
278 ////////////////////////////////////////////////////////////////////////////////
279 // RootWindowHostX11::MouseMoveFilter filters out the move events that
280 // jump back and forth between two points. This happens when sub pixel mouse
281 // move is enabled and mouse move events could be jumping between two neighbor
282 // pixels, e.g. move(0,0), move(1,0), move(0,0), move(1,0) and on and on.
283 // The filtering is done by keeping track of the last two event locations and
284 // provides a Filter method to find out whether a mouse event is in a different
285 // location and should be processed.
287 class RootWindowHostX11::MouseMoveFilter {
288 public:
289 MouseMoveFilter() : insert_index_(0) {
290 for (size_t i = 0; i < kMaxEvents; ++i) {
291 const int int_max = std::numeric_limits<int>::max();
292 recent_locations_[i] = gfx::Point(int_max, int_max);
295 ~MouseMoveFilter() {}
297 // Returns true if |event| is known and should be ignored.
298 bool Filter(const base::NativeEvent& event) {
299 const gfx::Point& location = ui::EventLocationFromNative(event);
300 for (size_t i = 0; i < kMaxEvents; ++i) {
301 if (location == recent_locations_[i])
302 return true;
305 recent_locations_[insert_index_] = location;
306 insert_index_ = (insert_index_ + 1) % kMaxEvents;
307 return false;
310 private:
311 static const size_t kMaxEvents = 2;
313 gfx::Point recent_locations_[kMaxEvents];
314 size_t insert_index_;
316 DISALLOW_COPY_AND_ASSIGN(MouseMoveFilter);
319 ////////////////////////////////////////////////////////////////////////////////
320 // RootWindowHostX11
322 RootWindowHostX11::RootWindowHostX11(const gfx::Rect& bounds)
323 : xdisplay_(gfx::GetXDisplay()),
324 xwindow_(0),
325 x_root_window_(DefaultRootWindow(xdisplay_)),
326 current_cursor_(ui::kCursorNull),
327 window_mapped_(false),
328 bounds_(bounds),
329 is_internal_display_(false),
330 focus_when_shown_(false),
331 touch_calibrate_(new internal::TouchEventCalibrate),
332 mouse_move_filter_(new MouseMoveFilter),
333 atom_cache_(xdisplay_, kAtomsToCache),
334 bezel_tracking_ids_(0) {
335 XSetWindowAttributes swa;
336 memset(&swa, 0, sizeof(swa));
337 swa.background_pixmap = None;
338 swa.override_redirect = default_override_redirect;
339 xwindow_ = XCreateWindow(
340 xdisplay_, x_root_window_,
341 bounds.x(), bounds.y(), bounds.width(), bounds.height(),
342 0, // border width
343 CopyFromParent, // depth
344 InputOutput,
345 CopyFromParent, // visual
346 CWBackPixmap | CWOverrideRedirect,
347 &swa);
348 base::MessagePumpX11::Current()->AddDispatcherForWindow(this, xwindow_);
349 base::MessagePumpX11::Current()->AddDispatcherForRootWindow(this);
351 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
352 KeyPressMask | KeyReleaseMask |
353 EnterWindowMask | LeaveWindowMask |
354 ExposureMask | VisibilityChangeMask |
355 StructureNotifyMask | PropertyChangeMask |
356 PointerMotionMask;
357 XSelectInput(xdisplay_, xwindow_, event_mask);
358 XFlush(xdisplay_);
360 if (ui::IsXInput2Available())
361 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
363 SelectEventsForRootWindow();
365 // Get the initial size of the X root window.
366 XWindowAttributes attrs;
367 XGetWindowAttributes(xdisplay_, x_root_window_, &attrs);
368 x_root_bounds_.SetRect(attrs.x, attrs.y, attrs.width, attrs.height);
370 // TODO(erg): We currently only request window deletion events. We also
371 // should listen for activation events and anything else that GTK+ listens
372 // for, and do something useful.
373 ::Atom protocols[2];
374 protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
375 protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
376 XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
378 // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
379 // the desktop environment.
380 XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
382 // Likewise, the X server needs to know this window's pid so it knows which
383 // program to kill if the window hangs.
384 // XChangeProperty() expects "pid" to be long.
385 COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
386 long pid = getpid();
387 XChangeProperty(xdisplay_,
388 xwindow_,
389 atom_cache_.GetAtom("_NET_WM_PID"),
390 XA_CARDINAL,
392 PropModeReplace,
393 reinterpret_cast<unsigned char*>(&pid), 1);
395 XRRSelectInput(xdisplay_, x_root_window_,
396 RRScreenChangeNotifyMask | RROutputChangeNotifyMask);
397 Env::GetInstance()->AddObserver(this);
400 RootWindowHostX11::~RootWindowHostX11() {
401 Env::GetInstance()->RemoveObserver(this);
402 base::MessagePumpX11::Current()->RemoveDispatcherForRootWindow(this);
403 base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_);
405 UnConfineCursor();
407 XDestroyWindow(xdisplay_, xwindow_);
410 bool RootWindowHostX11::Dispatch(const base::NativeEvent& event) {
411 XEvent* xev = event;
413 if (FindEventTarget(event) == x_root_window_)
414 return DispatchEventForRootWindow(event);
416 switch (xev->type) {
417 case EnterNotify: {
418 aura::Window* root_window = GetRootWindow()->window();
419 client::CursorClient* cursor_client =
420 client::GetCursorClient(root_window);
421 if (cursor_client) {
422 const gfx::Display display = gfx::Screen::GetScreenFor(root_window)->
423 GetDisplayNearestWindow(root_window);
424 cursor_client->SetDisplay(display);
426 ui::MouseEvent mouse_event(xev);
427 // EnterNotify creates ET_MOUSE_MOVE. Mark as synthesized as this is not
428 // real mouse move event.
429 mouse_event.set_flags(mouse_event.flags() | ui::EF_IS_SYNTHESIZED);
430 TranslateAndDispatchMouseEvent(&mouse_event);
431 break;
433 case LeaveNotify: {
434 ui::MouseEvent mouse_event(xev);
435 TranslateAndDispatchMouseEvent(&mouse_event);
436 break;
438 case Expose: {
439 gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
440 xev->xexpose.width, xev->xexpose.height);
441 delegate_->AsRootWindow()->ScheduleRedrawRect(damage_rect);
442 break;
444 case KeyPress: {
445 ui::KeyEvent keydown_event(xev, false);
446 delegate_->OnHostKeyEvent(&keydown_event);
447 break;
449 case KeyRelease: {
450 ui::KeyEvent keyup_event(xev, false);
451 delegate_->OnHostKeyEvent(&keyup_event);
452 break;
454 case ButtonPress: {
455 if (static_cast<int>(xev->xbutton.button) == kBackMouseButton ||
456 static_cast<int>(xev->xbutton.button) == kForwardMouseButton) {
457 client::UserActionClient* gesture_client =
458 client::GetUserActionClient(delegate_->AsRootWindow()->window());
459 if (gesture_client) {
460 gesture_client->OnUserAction(
461 static_cast<int>(xev->xbutton.button) == kBackMouseButton ?
462 client::UserActionClient::BACK :
463 client::UserActionClient::FORWARD);
465 break;
467 } // fallthrough
468 case ButtonRelease: {
469 switch (ui::EventTypeFromNative(xev)) {
470 case ui::ET_MOUSEWHEEL: {
471 ui::MouseWheelEvent mouseev(xev);
472 TranslateAndDispatchMouseEvent(&mouseev);
473 break;
475 case ui::ET_MOUSE_PRESSED:
476 case ui::ET_MOUSE_RELEASED: {
477 ui::MouseEvent mouseev(xev);
478 TranslateAndDispatchMouseEvent(&mouseev);
479 break;
481 case ui::ET_UNKNOWN:
482 // No event is created for X11-release events for mouse-wheel buttons.
483 break;
484 default:
485 NOTREACHED();
487 break;
489 case FocusOut:
490 if (xev->xfocus.mode != NotifyGrab)
491 delegate_->OnHostLostWindowCapture();
492 break;
493 case ConfigureNotify: {
494 DCHECK_EQ(xwindow_, xev->xconfigure.event);
495 DCHECK_EQ(xwindow_, xev->xconfigure.window);
496 // It's possible that the X window may be resized by some other means
497 // than from within aura (e.g. the X window manager can change the
498 // size). Make sure the root window size is maintained properly.
499 gfx::Rect bounds(xev->xconfigure.x, xev->xconfigure.y,
500 xev->xconfigure.width, xev->xconfigure.height);
501 bool size_changed = bounds_.size() != bounds.size();
502 bool origin_changed = bounds_.origin() != bounds.origin();
503 bounds_ = bounds;
504 UpdateIsInternalDisplay();
505 // Always update barrier and mouse location because |bounds_| might
506 // have already been updated in |SetBounds|.
507 if (pointer_barriers_) {
508 UnConfineCursor();
509 ConfineCursorToRootWindow();
511 if (size_changed)
512 delegate_->OnHostResized(bounds.size());
513 if (origin_changed)
514 delegate_->OnHostMoved(bounds_.origin());
515 break;
517 case GenericEvent:
518 DispatchXI2Event(event);
519 break;
520 case MapNotify: {
521 // If there's no window manager running, we need to assign the X input
522 // focus to our host window.
523 if (!IsWindowManagerPresent() && focus_when_shown_)
524 XSetInputFocus(xdisplay_, xwindow_, RevertToNone, CurrentTime);
525 break;
527 case ClientMessage: {
528 Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]);
529 if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
530 // We have received a close message from the window manager.
531 delegate_->AsRootWindow()->OnRootWindowHostCloseRequested();
532 } else if (message_type == atom_cache_.GetAtom("_NET_WM_PING")) {
533 XEvent reply_event = *xev;
534 reply_event.xclient.window = x_root_window_;
536 XSendEvent(xdisplay_,
537 reply_event.xclient.window,
538 False,
539 SubstructureRedirectMask | SubstructureNotifyMask,
540 &reply_event);
542 break;
544 case MappingNotify: {
545 switch (xev->xmapping.request) {
546 case MappingModifier:
547 case MappingKeyboard:
548 XRefreshKeyboardMapping(&xev->xmapping);
549 delegate_->AsRootWindow()->OnKeyboardMappingChanged();
550 break;
551 case MappingPointer:
552 ui::DeviceDataManager::GetInstance()->UpdateButtonMap();
553 break;
554 default:
555 NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
556 break;
558 break;
560 case MotionNotify: {
561 // Discard all but the most recent motion event that targets the same
562 // window with unchanged state.
563 XEvent last_event;
564 while (XPending(xev->xany.display)) {
565 XEvent next_event;
566 XPeekEvent(xev->xany.display, &next_event);
567 if (next_event.type == MotionNotify &&
568 next_event.xmotion.window == xev->xmotion.window &&
569 next_event.xmotion.subwindow == xev->xmotion.subwindow &&
570 next_event.xmotion.state == xev->xmotion.state) {
571 XNextEvent(xev->xany.display, &last_event);
572 xev = &last_event;
573 } else {
574 break;
578 ui::MouseEvent mouseev(xev);
579 TranslateAndDispatchMouseEvent(&mouseev);
580 break;
583 return true;
586 RootWindow* RootWindowHostX11::GetRootWindow() {
587 return delegate_->AsRootWindow();
590 gfx::AcceleratedWidget RootWindowHostX11::GetAcceleratedWidget() {
591 return xwindow_;
594 void RootWindowHostX11::Show() {
595 if (!window_mapped_) {
596 // Before we map the window, set size hints. Otherwise, some window managers
597 // will ignore toplevel XMoveWindow commands.
598 XSizeHints size_hints;
599 size_hints.flags = PPosition | PWinGravity;
600 size_hints.x = bounds_.x();
601 size_hints.y = bounds_.y();
602 // Set StaticGravity so that the window position is not affected by the
603 // frame width when running with window manager.
604 size_hints.win_gravity = StaticGravity;
605 XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
607 XMapWindow(xdisplay_, xwindow_);
609 // We now block until our window is mapped. Some X11 APIs will crash and
610 // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
611 // asynchronous.
612 base::MessagePumpX11::Current()->BlockUntilWindowMapped(xwindow_);
613 window_mapped_ = true;
617 void RootWindowHostX11::Hide() {
618 if (window_mapped_) {
619 XWithdrawWindow(xdisplay_, xwindow_, 0);
620 window_mapped_ = false;
624 void RootWindowHostX11::ToggleFullScreen() {
625 NOTIMPLEMENTED();
628 gfx::Rect RootWindowHostX11::GetBounds() const {
629 return bounds_;
632 void RootWindowHostX11::SetBounds(const gfx::Rect& bounds) {
633 // Even if the host window's size doesn't change, aura's root window
634 // size, which is in DIP, changes when the scale changes.
635 float current_scale = delegate_->GetDeviceScaleFactor();
636 float new_scale = gfx::Screen::GetScreenFor(
637 delegate_->AsRootWindow()->window())->GetDisplayNearestWindow(
638 delegate_->AsRootWindow()->window()).device_scale_factor();
639 bool origin_changed = bounds_.origin() != bounds.origin();
640 bool size_changed = bounds_.size() != bounds.size();
641 XWindowChanges changes = {0};
642 unsigned value_mask = 0;
644 if (size_changed) {
645 changes.width = bounds.width();
646 changes.height = bounds.height();
647 value_mask = CWHeight | CWWidth;
650 if (origin_changed) {
651 changes.x = bounds.x();
652 changes.y = bounds.y();
653 value_mask |= CWX | CWY;
655 if (value_mask)
656 XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
658 // Assume that the resize will go through as requested, which should be the
659 // case if we're running without a window manager. If there's a window
660 // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
661 // (possibly synthetic) ConfigureNotify about the actual size and correct
662 // |bounds_| later.
663 bounds_ = bounds;
664 UpdateIsInternalDisplay();
665 if (origin_changed)
666 delegate_->OnHostMoved(bounds.origin());
667 if (size_changed || current_scale != new_scale) {
668 delegate_->OnHostResized(bounds.size());
669 } else {
670 delegate_->AsRootWindow()->window()->SchedulePaintInRect(
671 delegate_->AsRootWindow()->window()->bounds());
675 gfx::Insets RootWindowHostX11::GetInsets() const {
676 return insets_;
679 void RootWindowHostX11::SetInsets(const gfx::Insets& insets) {
680 insets_ = insets;
681 if (pointer_barriers_) {
682 UnConfineCursor();
683 ConfineCursorToRootWindow();
687 gfx::Point RootWindowHostX11::GetLocationOnNativeScreen() const {
688 return bounds_.origin();
691 void RootWindowHostX11::SetCapture() {
692 // TODO(oshima): Grab x input.
695 void RootWindowHostX11::ReleaseCapture() {
696 // TODO(oshima): Release x input.
699 void RootWindowHostX11::SetCursor(gfx::NativeCursor cursor) {
700 if (cursor == current_cursor_)
701 return;
702 current_cursor_ = cursor;
703 SetCursorInternal(cursor);
706 bool RootWindowHostX11::QueryMouseLocation(gfx::Point* location_return) {
707 client::CursorClient* cursor_client =
708 client::GetCursorClient(GetRootWindow()->window());
709 if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
710 *location_return = gfx::Point(0, 0);
711 return false;
714 ::Window root_return, child_return;
715 int root_x_return, root_y_return, win_x_return, win_y_return;
716 unsigned int mask_return;
717 XQueryPointer(xdisplay_,
718 xwindow_,
719 &root_return,
720 &child_return,
721 &root_x_return, &root_y_return,
722 &win_x_return, &win_y_return,
723 &mask_return);
724 *location_return = gfx::Point(max(0, min(bounds_.width(), win_x_return)),
725 max(0, min(bounds_.height(), win_y_return)));
726 return (win_x_return >= 0 && win_x_return < bounds_.width() &&
727 win_y_return >= 0 && win_y_return < bounds_.height());
730 bool RootWindowHostX11::ConfineCursorToRootWindow() {
731 #if XFIXES_MAJOR >= 5
732 DCHECK(!pointer_barriers_.get());
733 if (pointer_barriers_)
734 return false;
735 pointer_barriers_.reset(new XID[4]);
736 gfx::Rect bounds(bounds_);
737 bounds.Inset(insets_);
738 // Horizontal, top barriers.
739 pointer_barriers_[0] = XFixesCreatePointerBarrier(
740 xdisplay_, x_root_window_,
741 bounds.x(), bounds.y(), bounds.right(), bounds.y(),
742 BarrierPositiveY,
743 0, XIAllDevices);
744 // Horizontal, bottom barriers.
745 pointer_barriers_[1] = XFixesCreatePointerBarrier(
746 xdisplay_, x_root_window_,
747 bounds.x(), bounds.bottom(), bounds.right(), bounds.bottom(),
748 BarrierNegativeY,
749 0, XIAllDevices);
750 // Vertical, left barriers.
751 pointer_barriers_[2] = XFixesCreatePointerBarrier(
752 xdisplay_, x_root_window_,
753 bounds.x(), bounds.y(), bounds.x(), bounds.bottom(),
754 BarrierPositiveX,
755 0, XIAllDevices);
756 // Vertical, right barriers.
757 pointer_barriers_[3] = XFixesCreatePointerBarrier(
758 xdisplay_, x_root_window_,
759 bounds.right(), bounds.y(), bounds.right(), bounds.bottom(),
760 BarrierNegativeX,
761 0, XIAllDevices);
762 #endif
763 return true;
766 void RootWindowHostX11::UnConfineCursor() {
767 #if XFIXES_MAJOR >= 5
768 if (pointer_barriers_) {
769 XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[0]);
770 XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[1]);
771 XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[2]);
772 XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[3]);
773 pointer_barriers_.reset();
775 #endif
778 void RootWindowHostX11::OnCursorVisibilityChanged(bool show) {
779 SetCrOSTapPaused(!show);
782 void RootWindowHostX11::MoveCursorTo(const gfx::Point& location) {
783 XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
784 bounds_.x() + location.x(),
785 bounds_.y() + location.y());
788 void RootWindowHostX11::PostNativeEvent(
789 const base::NativeEvent& native_event) {
790 DCHECK(xwindow_);
791 DCHECK(xdisplay_);
792 XEvent xevent = *native_event;
793 xevent.xany.display = xdisplay_;
794 xevent.xany.window = xwindow_;
796 switch (xevent.type) {
797 case EnterNotify:
798 case LeaveNotify:
799 case MotionNotify:
800 case KeyPress:
801 case KeyRelease:
802 case ButtonPress:
803 case ButtonRelease: {
804 // The fields used below are in the same place for all of events
805 // above. Using xmotion from XEvent's unions to avoid repeating
806 // the code.
807 xevent.xmotion.root = x_root_window_;
808 xevent.xmotion.time = CurrentTime;
810 gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
811 delegate_->AsRootWindow()->host()->ConvertPointToNativeScreen(&point);
812 xevent.xmotion.x_root = point.x();
813 xevent.xmotion.y_root = point.y();
815 default:
816 break;
818 XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
821 void RootWindowHostX11::OnDeviceScaleFactorChanged(
822 float device_scale_factor) {
825 void RootWindowHostX11::PrepareForShutdown() {
826 base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_);
829 void RootWindowHostX11::OnWindowInitialized(Window* window) {
832 void RootWindowHostX11::OnRootWindowInitialized(RootWindow* root_window) {
833 // UpdateIsInternalDisplay relies on:
834 // 1. delegate_ pointing to RootWindow - available after SetDelegate.
835 // 2. RootWindow's kDisplayIdKey property set - available by the time
836 // RootWindow::Init is called.
837 // (set in DisplayManager::CreateRootWindowForDisplay)
838 // Ready when NotifyRootWindowInitialized is called from RootWindow::Init.
839 if (!delegate_ || root_window != GetRootWindow())
840 return;
841 UpdateIsInternalDisplay();
843 // We have to enable Tap-to-click by default because the cursor is set to
844 // visible in Shell::InitRootWindowController.
845 SetCrOSTapPaused(false);
848 bool RootWindowHostX11::DispatchEventForRootWindow(
849 const base::NativeEvent& event) {
850 switch (event->type) {
851 case ConfigureNotify:
852 DCHECK_EQ(x_root_window_, event->xconfigure.event);
853 x_root_bounds_.SetRect(event->xconfigure.x, event->xconfigure.y,
854 event->xconfigure.width, event->xconfigure.height);
855 break;
857 case GenericEvent:
858 DispatchXI2Event(event);
859 break;
862 return true;
865 void RootWindowHostX11::DispatchXI2Event(const base::NativeEvent& event) {
866 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
867 XEvent* xev = event;
868 if (!factory->ShouldProcessXI2Event(xev))
869 return;
871 TRACE_EVENT1("input", "RootWindowHostX11::DispatchXI2Event",
872 "event_latency_us",
873 (ui::EventTimeForNow() - ui::EventTimeFromNative(event)).
874 InMicroseconds());
876 ui::EventType type = ui::EventTypeFromNative(xev);
877 XEvent last_event;
878 int num_coalesced = 0;
880 switch (type) {
881 case ui::ET_TOUCH_MOVED:
882 case ui::ET_TOUCH_PRESSED:
883 case ui::ET_TOUCH_CANCELLED:
884 case ui::ET_TOUCH_RELEASED: {
885 #if defined(OS_CHROMEOS)
886 // Bail out early before generating a ui::TouchEvent if this event
887 // is not within the range of this RootWindow. Converting an xevent
888 // to ui::TouchEvent might change the state of the global touch tracking
889 // state, e.g. touch release event can remove the touch id from the
890 // record, and doing this multiple time when there are multiple
891 // RootWindow will cause problem. So only generate the ui::TouchEvent
892 // when we are sure it belongs to this RootWindow.
893 if (base::SysInfo::IsRunningOnChromeOS() &&
894 !bounds_.Contains(ui::EventLocationFromNative(xev)))
895 break;
896 #endif // defined(OS_CHROMEOS)
897 ui::TouchEvent touchev(xev);
898 #if defined(USE_XI2_MT)
899 // Ignore touch events with touch press happening on the side bezel.
900 if (!IsSideBezelsEnabled()) {
901 uint32 tracking_id = (1 << touchev.touch_id());
902 if (type == ui::ET_TOUCH_PRESSED &&
903 touch_calibrate_->IsEventOnSideBezels(xev, bounds_))
904 bezel_tracking_ids_ |= tracking_id;
905 if (bezel_tracking_ids_ & tracking_id) {
906 if (type == ui::ET_TOUCH_CANCELLED || type == ui::ET_TOUCH_RELEASED)
907 bezel_tracking_ids_ =
908 (bezel_tracking_ids_ | tracking_id) ^ tracking_id;
909 return;
912 #endif // defined(USE_XI2_MT)
913 #if defined(OS_CHROMEOS)
914 if (base::SysInfo::IsRunningOnChromeOS()) {
915 // X maps the touch-surface to the size of the X root-window.
916 // In multi-monitor setup, Coordinate Transformation Matrix
917 // repositions the touch-surface onto part of X root-window
918 // containing aura root-window corresponding to the touchscreen.
919 // However, if aura root-window has non-zero origin,
920 // we need to relocate the event into aura root-window coordinates.
921 touchev.Relocate(bounds_.origin());
922 #if defined(USE_XI2_MT)
923 if (is_internal_display_)
924 touch_calibrate_->Calibrate(&touchev, bounds_);
925 #endif // defined(USE_XI2_MT)
927 #endif // defined(OS_CHROMEOS)
928 delegate_->OnHostTouchEvent(&touchev);
929 break;
931 case ui::ET_MOUSE_MOVED:
932 case ui::ET_MOUSE_DRAGGED:
933 case ui::ET_MOUSE_PRESSED:
934 case ui::ET_MOUSE_RELEASED:
935 case ui::ET_MOUSE_ENTERED:
936 case ui::ET_MOUSE_EXITED: {
937 if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
938 // If this is a motion event, we want to coalesce all pending motion
939 // events that are at the top of the queue.
940 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
941 if (num_coalesced > 0)
942 xev = &last_event;
944 if (mouse_move_filter_ && mouse_move_filter_->Filter(xev))
945 break;
946 } else if (type == ui::ET_MOUSE_PRESSED ||
947 type == ui::ET_MOUSE_RELEASED) {
948 XIDeviceEvent* xievent =
949 static_cast<XIDeviceEvent*>(xev->xcookie.data);
950 int button = xievent->detail;
951 if (button == kBackMouseButton || button == kForwardMouseButton) {
952 if (type == ui::ET_MOUSE_RELEASED)
953 break;
954 client::UserActionClient* gesture_client =
955 client::GetUserActionClient(delegate_->AsRootWindow()->window());
956 if (gesture_client) {
957 bool reverse_direction =
958 ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled();
959 gesture_client->OnUserAction(
960 (button == kBackMouseButton && !reverse_direction) ||
961 (button == kForwardMouseButton && reverse_direction) ?
962 client::UserActionClient::BACK :
963 client::UserActionClient::FORWARD);
965 break;
968 ui::MouseEvent mouseev(xev);
969 TranslateAndDispatchMouseEvent(&mouseev);
970 break;
972 case ui::ET_MOUSEWHEEL: {
973 ui::MouseWheelEvent mouseev(xev);
974 TranslateAndDispatchMouseEvent(&mouseev);
975 break;
977 case ui::ET_SCROLL_FLING_START:
978 case ui::ET_SCROLL_FLING_CANCEL:
979 case ui::ET_SCROLL: {
980 ui::ScrollEvent scrollev(xev);
981 delegate_->OnHostScrollEvent(&scrollev);
982 break;
984 case ui::ET_UMA_DATA:
985 break;
986 case ui::ET_UNKNOWN:
987 break;
988 default:
989 NOTREACHED();
992 // If we coalesced an event we need to free its cookie.
993 if (num_coalesced > 0)
994 XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
997 bool RootWindowHostX11::IsWindowManagerPresent() {
998 // Per ICCCM 2.8, "Manager Selections", window managers should take ownership
999 // of WM_Sn selections (where n is a screen number).
1000 return XGetSelectionOwner(
1001 xdisplay_, atom_cache_.GetAtom("WM_S0")) != None;
1004 void RootWindowHostX11::SetCursorInternal(gfx::NativeCursor cursor) {
1005 XDefineCursor(xdisplay_, xwindow_, cursor.platform());
1008 void RootWindowHostX11::TranslateAndDispatchMouseEvent(
1009 ui::MouseEvent* event) {
1010 Window* root_window = GetRootWindow()->window();
1011 client::ScreenPositionClient* screen_position_client =
1012 client::GetScreenPositionClient(root_window);
1013 gfx::Rect local(bounds_.size());
1015 if (screen_position_client && !local.Contains(event->location())) {
1016 gfx::Point location(event->location());
1017 // In order to get the correct point in screen coordinates
1018 // during passive grab, we first need to find on which host window
1019 // the mouse is on, and find out the screen coordinates on that
1020 // host window, then convert it back to this host window's coordinate.
1021 screen_position_client->ConvertHostPointToScreen(root_window, &location);
1022 screen_position_client->ConvertPointFromScreen(root_window, &location);
1023 root_window->GetDispatcher()->ConvertPointToHost(&location);
1024 event->set_location(location);
1025 event->set_root_location(location);
1027 delegate_->OnHostMouseEvent(event);
1030 void RootWindowHostX11::UpdateIsInternalDisplay() {
1031 Window* root_window = GetRootWindow()->window();
1032 gfx::Screen* screen = gfx::Screen::GetScreenFor(root_window);
1033 gfx::Display display = screen->GetDisplayNearestWindow(root_window);
1034 is_internal_display_ = display.IsInternal();
1037 void RootWindowHostX11::SetCrOSTapPaused(bool state) {
1038 #if defined(OS_CHROMEOS)
1039 if (!ui::IsXInput2Available())
1040 return;
1041 // Temporarily pause tap-to-click when the cursor is hidden.
1042 Atom prop = atom_cache_.GetAtom("Tap Paused");
1043 unsigned char value = state;
1044 XIDeviceList dev_list =
1045 ui::DeviceListCacheX::GetInstance()->GetXI2DeviceList(xdisplay_);
1047 // Only slave pointer devices could possibly have tap-paused property.
1048 for (int i = 0; i < dev_list.count; i++) {
1049 if (dev_list[i].use == XISlavePointer) {
1050 Atom old_type;
1051 int old_format;
1052 unsigned long old_nvalues, bytes;
1053 unsigned char* data;
1054 int result = XIGetProperty(xdisplay_, dev_list[i].deviceid, prop, 0, 0,
1055 False, AnyPropertyType, &old_type, &old_format,
1056 &old_nvalues, &bytes, &data);
1057 if (result != Success)
1058 continue;
1059 XFree(data);
1060 XIChangeProperty(xdisplay_, dev_list[i].deviceid, prop, XA_INTEGER, 8,
1061 PropModeReplace, &value, 1);
1064 #endif
1067 // static
1068 RootWindowHost* RootWindowHost::Create(const gfx::Rect& bounds) {
1069 return new RootWindowHostX11(bounds);
1072 // static
1073 gfx::Size RootWindowHost::GetNativeScreenSize() {
1074 ::XDisplay* xdisplay = gfx::GetXDisplay();
1075 return gfx::Size(DisplayWidth(xdisplay, 0), DisplayHeight(xdisplay, 0));
1078 namespace test {
1080 void SetUseOverrideRedirectWindowByDefault(bool override_redirect) {
1081 default_override_redirect = override_redirect;
1084 } // namespace test
1085 } // namespace aura