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/ash_window_tree_host_unified.h"
17 #include "ash/host/root_window_transformer.h"
18 #include "base/basictypes.h"
19 #include "base/sys_info.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/devices/device_data_manager.h"
25 #include "ui/events/devices/x11/device_list_cache_x11.h"
26 #include "ui/events/devices/x11/touch_factory_x11.h"
27 #include "ui/events/event.h"
28 #include "ui/events/event_utils.h"
29 #include "ui/events/null_event_targeter.h"
30 #include "ui/events/platform/platform_event_source.h"
31 #include "ui/gfx/geometry/rect.h"
32 #include "ui/gfx/screen.h"
36 AshWindowTreeHostX11::AshWindowTreeHostX11(const gfx::Rect
& initial_bounds
)
37 : WindowTreeHostX11(initial_bounds
), transformer_helper_(this) {
38 transformer_helper_
.Init();
39 aura::Env::GetInstance()->AddObserver(this);
42 AshWindowTreeHostX11::~AshWindowTreeHostX11() {
43 aura::Env::GetInstance()->RemoveObserver(this);
47 void AshWindowTreeHostX11::ToggleFullScreen() { NOTIMPLEMENTED(); }
49 bool AshWindowTreeHostX11::ConfineCursorToRootWindow() {
51 DCHECK(!pointer_barriers_
.get());
52 if (pointer_barriers_
)
54 pointer_barriers_
.reset(new XID
[4]);
55 gfx::Rect
barrier(bounds());
56 barrier
.Inset(transformer_helper_
.GetHostInsets());
57 // Horizontal, top barriers.
58 pointer_barriers_
[0] = XFixesCreatePointerBarrier(xdisplay(),
67 // Horizontal, bottom barriers.
68 pointer_barriers_
[1] = XFixesCreatePointerBarrier(xdisplay(),
77 // Vertical, left barriers.
78 pointer_barriers_
[2] = XFixesCreatePointerBarrier(xdisplay(),
87 // Vertical, right barriers.
88 pointer_barriers_
[3] = XFixesCreatePointerBarrier(xdisplay(),
101 void AshWindowTreeHostX11::UnConfineCursor() {
102 #if XFIXES_MAJOR >= 5
103 if (pointer_barriers_
) {
104 XFixesDestroyPointerBarrier(xdisplay(), pointer_barriers_
[0]);
105 XFixesDestroyPointerBarrier(xdisplay(), pointer_barriers_
[1]);
106 XFixesDestroyPointerBarrier(xdisplay(), pointer_barriers_
[2]);
107 XFixesDestroyPointerBarrier(xdisplay(), pointer_barriers_
[3]);
108 pointer_barriers_
.reset();
113 void AshWindowTreeHostX11::SetRootWindowTransformer(
114 scoped_ptr
<RootWindowTransformer
> transformer
) {
115 transformer_helper_
.SetRootWindowTransformer(transformer
.Pass());
116 if (pointer_barriers_
) {
118 ConfineCursorToRootWindow();
122 gfx::Insets
AshWindowTreeHostX11::GetHostInsets() const {
123 return transformer_helper_
.GetHostInsets();
126 aura::WindowTreeHost
* AshWindowTreeHostX11::AsWindowTreeHost() { return this; }
128 void AshWindowTreeHostX11::PrepareForShutdown() {
129 // Block the root window from dispatching events because it is weird for a
130 // ScreenPositionClient not to be attached to the root window and for
131 // ui::EventHandlers to be unable to convert the event's location to screen
133 window()->SetEventTargeter(
134 scoped_ptr
<ui::EventTargeter
>(new ui::NullEventTargeter
));
136 if (ui::PlatformEventSource::GetInstance()) {
137 // Block X events which are not turned into ui::Events from getting
138 // processed. (e.g. ConfigureNotify)
139 ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
143 void AshWindowTreeHostX11::SetBounds(const gfx::Rect
& bounds
) {
144 WindowTreeHostX11::SetBounds(bounds
);
145 if (pointer_barriers_
) {
147 ConfineCursorToRootWindow();
151 gfx::Transform
AshWindowTreeHostX11::GetRootTransform() const {
152 return transformer_helper_
.GetTransform();
155 void AshWindowTreeHostX11::SetRootTransform(const gfx::Transform
& transform
) {
156 transformer_helper_
.SetTransform(transform
);
159 gfx::Transform
AshWindowTreeHostX11::GetInverseRootTransform() const {
160 return transformer_helper_
.GetInverseTransform();
163 void AshWindowTreeHostX11::UpdateRootWindowSize(const gfx::Size
& host_size
) {
164 transformer_helper_
.UpdateWindowSize(host_size
);
167 void AshWindowTreeHostX11::OnCursorVisibilityChangedNative(bool show
) {
168 #if defined(OS_CHROMEOS)
169 SetCrOSTapPaused(!show
);
173 void AshWindowTreeHostX11::OnWindowInitialized(aura::Window
* window
) {}
175 void AshWindowTreeHostX11::OnHostInitialized(aura::WindowTreeHost
* host
) {
176 if (host
!= AsWindowTreeHost())
179 #if defined(OS_CHROMEOS)
180 // We have to enable Tap-to-click by default because the cursor is set to
181 // visible in Shell::InitRootWindowController.
182 SetCrOSTapPaused(false);
186 void AshWindowTreeHostX11::OnConfigureNotify() {
187 // Always update barrier and mouse location because |bounds_| might
188 // have already been updated in |SetBounds|.
189 if (pointer_barriers_
) {
191 ConfineCursorToRootWindow();
195 bool AshWindowTreeHostX11::CanDispatchEvent(const ui::PlatformEvent
& event
) {
196 if(!WindowTreeHostX11::CanDispatchEvent(event
))
199 ui::EventType type
= ui::EventTypeFromNative(xev
);
200 // For touch event, check if the root window is residing on the according
203 case ui::ET_TOUCH_MOVED
:
204 case ui::ET_TOUCH_PRESSED
:
205 case ui::ET_TOUCH_CANCELLED
:
206 case ui::ET_TOUCH_RELEASED
: {
207 #if defined(OS_CHROMEOS)
208 XIDeviceEvent
* xiev
= static_cast<XIDeviceEvent
*>(xev
->xcookie
.data
);
209 int64 touch_display_id
=
210 ui::DeviceDataManager::GetInstance()->GetTargetDisplayForTouchDevice(
212 // If we don't have record of display id for this touch device, check
213 // that if the event is within the bound of the root window. Note
214 // that in multi-monitor case, the event position is in framebuffer
215 // space so the bounds check will not work so well.
216 if (touch_display_id
== gfx::Display::kInvalidDisplayID
) {
217 if (base::SysInfo::IsRunningOnChromeOS() &&
218 !bounds().Contains(ui::EventLocationFromNative(xev
)))
221 gfx::Screen
* screen
= gfx::Screen::GetScreenFor(window());
222 gfx::Display display
= screen
->GetDisplayNearestWindow(window());
223 return touch_display_id
== display
.id();
225 #endif // defined(OS_CHROMEOS)
232 void AshWindowTreeHostX11::TranslateAndDispatchLocatedEvent(
233 ui::LocatedEvent
* event
) {
234 TranslateLocatedEvent(event
);
235 SendEventToProcessor(event
);
238 #if defined(OS_CHROMEOS)
239 void AshWindowTreeHostX11::SetCrOSTapPaused(bool state
) {
240 if (!ui::IsXInput2Available())
242 // Temporarily pause tap-to-click when the cursor is hidden.
243 Atom prop
= atom_cache()->GetAtom("Tap Paused");
244 unsigned char value
= state
;
245 const XIDeviceList
& dev_list
=
246 ui::DeviceListCacheX11::GetInstance()->GetXI2DeviceList(xdisplay());
248 // Only slave pointer devices could possibly have tap-paused property.
249 for (int i
= 0; i
< dev_list
.count
; i
++) {
250 if (dev_list
[i
].use
== XISlavePointer
) {
253 unsigned long old_nvalues
, bytes
;
255 int result
= XIGetProperty(xdisplay(),
256 dev_list
[i
].deviceid
,
267 if (result
!= Success
)
270 XIChangeProperty(xdisplay(),
271 dev_list
[i
].deviceid
,
283 AshWindowTreeHost
* AshWindowTreeHost::Create(
284 const AshWindowTreeHostInitParams
& init_params
) {
285 if (init_params
.offscreen
)
286 return new AshWindowTreeHostUnified(init_params
.initial_bounds
);
287 return new AshWindowTreeHostX11(init_params
.initial_bounds
);