1 // Copyright 2014 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 "ash/host/ash_window_tree_host_x11.h"
7 #include <X11/extensions/Xfixes.h>
8 #include <X11/extensions/XInput2.h>
15 #include "ash/host/ash_window_tree_host_init_params.h"
16 #include "ash/host/root_window_transformer.h"
17 #include "base/basictypes.h"
18 #include "base/sys_info.h"
19 #include "ui/aura/client/screen_position_client.h"
20 #include "ui/aura/env.h"
21 #include "ui/aura/window.h"
22 #include "ui/aura/window_event_dispatcher.h"
23 #include "ui/base/x/x11_util.h"
24 #include "ui/events/device_data_manager.h"
25 #include "ui/events/event.h"
26 #include "ui/events/event_utils.h"
27 #include "ui/events/platform/platform_event_source.h"
28 #include "ui/events/x/device_list_cache_x.h"
29 #include "ui/events/x/touch_factory_x11.h"
30 #include "ui/gfx/rect.h"
31 #include "ui/gfx/screen.h"
35 AshWindowTreeHostX11::AshWindowTreeHostX11(const gfx::Rect
& initial_bounds
)
36 : WindowTreeHostX11(initial_bounds
),
37 transformer_helper_(this),
38 display_ids_(std::make_pair(gfx::Display::kInvalidDisplayID
,
39 gfx::Display::kInvalidDisplayID
)) {
40 aura::Env::GetInstance()->AddObserver(this);
43 AshWindowTreeHostX11::~AshWindowTreeHostX11() {
44 aura::Env::GetInstance()->RemoveObserver(this);
48 void AshWindowTreeHostX11::ToggleFullScreen() { NOTIMPLEMENTED(); }
50 bool AshWindowTreeHostX11::ConfineCursorToRootWindow() {
52 DCHECK(!pointer_barriers_
.get());
53 if (pointer_barriers_
)
55 pointer_barriers_
.reset(new XID
[4]);
56 gfx::Rect
barrier(bounds());
57 barrier
.Inset(transformer_helper_
.GetHostInsets());
58 // Horizontal, top barriers.
59 pointer_barriers_
[0] = XFixesCreatePointerBarrier(xdisplay(),
68 // Horizontal, bottom barriers.
69 pointer_barriers_
[1] = XFixesCreatePointerBarrier(xdisplay(),
78 // Vertical, left barriers.
79 pointer_barriers_
[2] = XFixesCreatePointerBarrier(xdisplay(),
88 // Vertical, right barriers.
89 pointer_barriers_
[3] = XFixesCreatePointerBarrier(xdisplay(),
102 void AshWindowTreeHostX11::UnConfineCursor() {
103 #if XFIXES_MAJOR >= 5
104 if (pointer_barriers_
) {
105 XFixesDestroyPointerBarrier(xdisplay(), pointer_barriers_
[0]);
106 XFixesDestroyPointerBarrier(xdisplay(), pointer_barriers_
[1]);
107 XFixesDestroyPointerBarrier(xdisplay(), pointer_barriers_
[2]);
108 XFixesDestroyPointerBarrier(xdisplay(), pointer_barriers_
[3]);
109 pointer_barriers_
.reset();
114 void AshWindowTreeHostX11::SetRootWindowTransformer(
115 scoped_ptr
<RootWindowTransformer
> transformer
) {
116 transformer_helper_
.SetRootWindowTransformer(transformer
.Pass());
117 if (pointer_barriers_
) {
119 ConfineCursorToRootWindow();
123 gfx::Insets
AshWindowTreeHostX11::GetHostInsets() const {
124 return transformer_helper_
.GetHostInsets();
127 aura::WindowTreeHost
* AshWindowTreeHostX11::AsWindowTreeHost() { return this; }
129 void AshWindowTreeHostX11::UpdateDisplayID(int64 id1
, int64 id2
) {
130 display_ids_
.first
= id1
;
131 display_ids_
.second
= id2
;
134 void AshWindowTreeHostX11::PrepareForShutdown() {
135 if (ui::PlatformEventSource::GetInstance())
136 ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
139 void AshWindowTreeHostX11::SetBounds(const gfx::Rect
& bounds
) {
140 WindowTreeHostX11::SetBounds(bounds
);
141 if (pointer_barriers_
) {
143 ConfineCursorToRootWindow();
147 gfx::Transform
AshWindowTreeHostX11::GetRootTransform() const {
148 return transformer_helper_
.GetTransform();
151 void AshWindowTreeHostX11::SetRootTransform(const gfx::Transform
& transform
) {
152 transformer_helper_
.SetTransform(transform
);
155 gfx::Transform
AshWindowTreeHostX11::GetInverseRootTransform() const {
156 return transformer_helper_
.GetInverseTransform();
159 void AshWindowTreeHostX11::UpdateRootWindowSize(const gfx::Size
& host_size
) {
160 transformer_helper_
.UpdateWindowSize(host_size
);
163 void AshWindowTreeHostX11::OnCursorVisibilityChangedNative(bool show
) {
164 #if defined(OS_CHROMEOS)
165 SetCrOSTapPaused(!show
);
169 void AshWindowTreeHostX11::OnWindowInitialized(aura::Window
* window
) {}
171 void AshWindowTreeHostX11::OnHostInitialized(aura::WindowTreeHost
* host
) {
172 if (host
!= AsWindowTreeHost())
175 #if defined(OS_CHROMEOS)
176 // We have to enable Tap-to-click by default because the cursor is set to
177 // visible in Shell::InitRootWindowController.
178 SetCrOSTapPaused(false);
182 void AshWindowTreeHostX11::OnConfigureNotify() {
183 // Always update barrier and mouse location because |bounds_| might
184 // have already been updated in |SetBounds|.
185 if (pointer_barriers_
) {
187 ConfineCursorToRootWindow();
191 bool AshWindowTreeHostX11::CanDispatchEvent(const ui::PlatformEvent
& event
) {
192 if(!WindowTreeHostX11::CanDispatchEvent(event
))
195 ui::EventType type
= ui::EventTypeFromNative(xev
);
196 // For touch event, check if the root window is residing on the according
199 case ui::ET_TOUCH_MOVED
:
200 case ui::ET_TOUCH_PRESSED
:
201 case ui::ET_TOUCH_CANCELLED
:
202 case ui::ET_TOUCH_RELEASED
: {
203 #if defined(OS_CHROMEOS)
204 XIDeviceEvent
* xiev
= static_cast<XIDeviceEvent
*>(xev
->xcookie
.data
);
205 int64 touch_display_id
=
206 ui::DeviceDataManager::GetInstance()->GetDisplayForTouchDevice(
208 // If we don't have record of display id for this touch device, check
209 // that if the event is within the bound of the root window. Note
210 // that in multi-monitor case, the event position is in framebuffer
211 // space so the bounds check will not work so well.
212 if (touch_display_id
== gfx::Display::kInvalidDisplayID
) {
213 if (base::SysInfo::IsRunningOnChromeOS() &&
214 !bounds().Contains(ui::EventLocationFromNative(xev
)))
216 } else if (touch_display_id
!= display_ids_
.first
&&
217 touch_display_id
!= display_ids_
.second
) {
220 #endif // defined(OS_CHROMEOS)
227 void AshWindowTreeHostX11::TranslateAndDispatchLocatedEvent(
228 ui::LocatedEvent
* event
) {
229 if (!event
->IsTouchEvent()) {
230 aura::Window
* root_window
= window();
231 aura::client::ScreenPositionClient
* screen_position_client
=
232 aura::client::GetScreenPositionClient(root_window
);
233 gfx::Rect
local(bounds().size());
234 local
.Inset(transformer_helper_
.GetHostInsets());
236 if (screen_position_client
&& !local
.Contains(event
->location())) {
237 gfx::Point
location(event
->location());
238 // In order to get the correct point in screen coordinates
239 // during passive grab, we first need to find on which host window
240 // the mouse is on, and find out the screen coordinates on that
241 // host window, then convert it back to this host window's coordinate.
242 screen_position_client
->ConvertHostPointToScreen(root_window
,
244 screen_position_client
->ConvertPointFromScreen(root_window
, &location
);
245 ConvertPointToHost(&location
);
246 event
->set_location(location
);
247 event
->set_root_location(location
);
250 SendEventToProcessor(event
);
253 #if defined(OS_CHROMEOS)
254 void AshWindowTreeHostX11::SetCrOSTapPaused(bool state
) {
255 if (!ui::IsXInput2Available())
257 // Temporarily pause tap-to-click when the cursor is hidden.
258 Atom prop
= atom_cache()->GetAtom("Tap Paused");
259 unsigned char value
= state
;
260 XIDeviceList dev_list
=
261 ui::DeviceListCacheX::GetInstance()->GetXI2DeviceList(xdisplay());
263 // Only slave pointer devices could possibly have tap-paused property.
264 for (int i
= 0; i
< dev_list
.count
; i
++) {
265 if (dev_list
[i
].use
== XISlavePointer
) {
268 unsigned long old_nvalues
, bytes
;
270 int result
= XIGetProperty(xdisplay(),
271 dev_list
[i
].deviceid
,
282 if (result
!= Success
)
285 XIChangeProperty(xdisplay(),
286 dev_list
[i
].deviceid
,
298 AshWindowTreeHost
* AshWindowTreeHost::Create(
299 const AshWindowTreeHostInitParams
& init_params
) {
300 return new AshWindowTreeHostX11(init_params
.initial_bounds
);