Don't preload rarely seen large images
[chromium-blink-merge.git] / ash / host / ash_window_tree_host_x11.cc
blob979db19261d8f28c66f464acb82592d91796416a
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>
9 #include <X11/Xatom.h>
10 #include <X11/Xlib.h>
12 #include <string>
13 #include <vector>
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 "ash/ime/input_method_event_handler.h"
19 #include "base/basictypes.h"
20 #include "base/sys_info.h"
21 #include "ui/aura/env.h"
22 #include "ui/aura/window.h"
23 #include "ui/aura/window_event_dispatcher.h"
24 #include "ui/base/x/x11_util.h"
25 #include "ui/events/devices/device_data_manager.h"
26 #include "ui/events/devices/x11/device_list_cache_x11.h"
27 #include "ui/events/devices/x11/touch_factory_x11.h"
28 #include "ui/events/event.h"
29 #include "ui/events/event_utils.h"
30 #include "ui/events/null_event_targeter.h"
31 #include "ui/events/platform/platform_event_source.h"
32 #include "ui/gfx/geometry/rect.h"
33 #include "ui/gfx/screen.h"
35 namespace ash {
37 AshWindowTreeHostX11::AshWindowTreeHostX11(const gfx::Rect& initial_bounds)
38 : WindowTreeHostX11(initial_bounds), transformer_helper_(this) {
39 transformer_helper_.Init();
40 aura::Env::GetInstance()->AddObserver(this);
43 AshWindowTreeHostX11::~AshWindowTreeHostX11() {
44 aura::Env::GetInstance()->RemoveObserver(this);
45 UnConfineCursor();
48 void AshWindowTreeHostX11::ToggleFullScreen() { NOTIMPLEMENTED(); }
50 bool AshWindowTreeHostX11::ConfineCursorToRootWindow() {
51 #if XFIXES_MAJOR >= 5
52 DCHECK(!pointer_barriers_.get());
53 if (pointer_barriers_)
54 return false;
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(),
60 x_root_window(),
61 barrier.x(),
62 barrier.y(),
63 barrier.right(),
64 barrier.y(),
65 BarrierPositiveY,
67 XIAllDevices);
68 // Horizontal, bottom barriers.
69 pointer_barriers_[1] = XFixesCreatePointerBarrier(xdisplay(),
70 x_root_window(),
71 barrier.x(),
72 barrier.bottom(),
73 barrier.right(),
74 barrier.bottom(),
75 BarrierNegativeY,
77 XIAllDevices);
78 // Vertical, left barriers.
79 pointer_barriers_[2] = XFixesCreatePointerBarrier(xdisplay(),
80 x_root_window(),
81 barrier.x(),
82 barrier.y(),
83 barrier.x(),
84 barrier.bottom(),
85 BarrierPositiveX,
87 XIAllDevices);
88 // Vertical, right barriers.
89 pointer_barriers_[3] = XFixesCreatePointerBarrier(xdisplay(),
90 x_root_window(),
91 barrier.right(),
92 barrier.y(),
93 barrier.right(),
94 barrier.bottom(),
95 BarrierNegativeX,
97 XIAllDevices);
98 #endif
99 return true;
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();
111 #endif
114 void AshWindowTreeHostX11::SetRootWindowTransformer(
115 scoped_ptr<RootWindowTransformer> transformer) {
116 transformer_helper_.SetRootWindowTransformer(transformer.Pass());
117 if (pointer_barriers_) {
118 UnConfineCursor();
119 ConfineCursorToRootWindow();
123 gfx::Insets AshWindowTreeHostX11::GetHostInsets() const {
124 return transformer_helper_.GetHostInsets();
127 aura::WindowTreeHost* AshWindowTreeHostX11::AsWindowTreeHost() { return this; }
129 void AshWindowTreeHostX11::PrepareForShutdown() {
130 // Block the root window from dispatching events because it is weird for a
131 // ScreenPositionClient not to be attached to the root window and for
132 // ui::EventHandlers to be unable to convert the event's location to screen
133 // coordinates.
134 window()->SetEventTargeter(
135 scoped_ptr<ui::EventTargeter>(new ui::NullEventTargeter));
137 if (ui::PlatformEventSource::GetInstance()) {
138 // Block X events which are not turned into ui::Events from getting
139 // processed. (e.g. ConfigureNotify)
140 ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
144 void AshWindowTreeHostX11::SetBounds(const gfx::Rect& bounds) {
145 WindowTreeHostX11::SetBounds(bounds);
146 if (pointer_barriers_) {
147 UnConfineCursor();
148 ConfineCursorToRootWindow();
152 gfx::Transform AshWindowTreeHostX11::GetRootTransform() const {
153 return transformer_helper_.GetTransform();
156 void AshWindowTreeHostX11::SetRootTransform(const gfx::Transform& transform) {
157 transformer_helper_.SetTransform(transform);
160 gfx::Transform AshWindowTreeHostX11::GetInverseRootTransform() const {
161 return transformer_helper_.GetInverseTransform();
164 void AshWindowTreeHostX11::UpdateRootWindowSize(const gfx::Size& host_size) {
165 transformer_helper_.UpdateWindowSize(host_size);
168 void AshWindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) {
169 #if defined(OS_CHROMEOS)
170 SetCrOSTapPaused(!show);
171 #endif
174 void AshWindowTreeHostX11::OnWindowInitialized(aura::Window* window) {}
176 void AshWindowTreeHostX11::OnHostInitialized(aura::WindowTreeHost* host) {
177 if (host != AsWindowTreeHost())
178 return;
180 #if defined(OS_CHROMEOS)
181 // We have to enable Tap-to-click by default because the cursor is set to
182 // visible in Shell::InitRootWindowController.
183 SetCrOSTapPaused(false);
184 #endif
187 void AshWindowTreeHostX11::OnConfigureNotify() {
188 // Always update barrier and mouse location because |bounds_| might
189 // have already been updated in |SetBounds|.
190 if (pointer_barriers_) {
191 UnConfineCursor();
192 ConfineCursorToRootWindow();
196 bool AshWindowTreeHostX11::CanDispatchEvent(const ui::PlatformEvent& event) {
197 if(!WindowTreeHostX11::CanDispatchEvent(event))
198 return false;
199 XEvent* xev = event;
200 ui::EventType type = ui::EventTypeFromNative(xev);
201 // For touch event, check if the root window is residing on the according
202 // touch display.
203 switch (type) {
204 case ui::ET_TOUCH_MOVED:
205 case ui::ET_TOUCH_PRESSED:
206 case ui::ET_TOUCH_CANCELLED:
207 case ui::ET_TOUCH_RELEASED: {
208 #if defined(OS_CHROMEOS)
209 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data);
210 int64 touch_display_id =
211 ui::DeviceDataManager::GetInstance()->GetTargetDisplayForTouchDevice(
212 xiev->deviceid);
213 // If we don't have record of display id for this touch device, check
214 // that if the event is within the bound of the root window. Note
215 // that in multi-monitor case, the event position is in framebuffer
216 // space so the bounds check will not work so well.
217 if (touch_display_id == gfx::Display::kInvalidDisplayID) {
218 if (base::SysInfo::IsRunningOnChromeOS() &&
219 !bounds().Contains(ui::EventLocationFromNative(xev)))
220 return false;
221 } else {
222 gfx::Screen* screen = gfx::Screen::GetScreenFor(window());
223 gfx::Display display = screen->GetDisplayNearestWindow(window());
224 return touch_display_id == display.id();
226 #endif // defined(OS_CHROMEOS)
227 return true;
229 default:
230 return true;
233 void AshWindowTreeHostX11::TranslateAndDispatchLocatedEvent(
234 ui::LocatedEvent* event) {
235 TranslateLocatedEvent(event);
236 SendEventToProcessor(event);
239 bool AshWindowTreeHostX11::DispatchKeyEventPostIME(const ui::KeyEvent& event) {
240 ui::KeyEvent event_copy(event);
241 input_method_handler()->SetPostIME(true);
242 ui::EventSource::DeliverEventToProcessor(&event_copy);
243 input_method_handler()->SetPostIME(false);
244 return event_copy.handled();
247 ui::EventDispatchDetails AshWindowTreeHostX11::DeliverEventToProcessor(
248 ui::Event* event) {
249 return ui::EventSource::DeliverEventToProcessor(event);
252 #if defined(OS_CHROMEOS)
253 void AshWindowTreeHostX11::SetCrOSTapPaused(bool state) {
254 if (!ui::IsXInput2Available())
255 return;
256 // Temporarily pause tap-to-click when the cursor is hidden.
257 Atom prop = atom_cache()->GetAtom("Tap Paused");
258 unsigned char value = state;
259 const XIDeviceList& dev_list =
260 ui::DeviceListCacheX11::GetInstance()->GetXI2DeviceList(xdisplay());
262 // Only slave pointer devices could possibly have tap-paused property.
263 for (int i = 0; i < dev_list.count; i++) {
264 if (dev_list[i].use == XISlavePointer) {
265 Atom old_type;
266 int old_format;
267 unsigned long old_nvalues, bytes;
268 unsigned char* data;
269 int result = XIGetProperty(xdisplay(),
270 dev_list[i].deviceid,
271 prop,
274 False,
275 AnyPropertyType,
276 &old_type,
277 &old_format,
278 &old_nvalues,
279 &bytes,
280 &data);
281 if (result != Success)
282 continue;
283 XFree(data);
284 XIChangeProperty(xdisplay(),
285 dev_list[i].deviceid,
286 prop,
287 XA_INTEGER,
289 PropModeReplace,
290 &value,
295 #endif
297 AshWindowTreeHost* AshWindowTreeHost::Create(
298 const AshWindowTreeHostInitParams& init_params) {
299 if (init_params.offscreen)
300 return new AshWindowTreeHostUnified(init_params.initial_bounds);
301 return new AshWindowTreeHostX11(init_params.initial_bounds);
304 } // namespace ash