Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(33)

Side by Side Diff: ash/host/ash_window_tree_host_x11.cc

Issue 201573015: Introdcue AshWindowTreeHost and move ash/chrome specific code in WTH to ash. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebased Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "ash/host/ash_window_tree_host_x11.h"
6
7 #include <X11/extensions/Xfixes.h>
8 #include <X11/extensions/XInput2.h>
9 #include <X11/Xatom.h>
10 #include <X11/Xlib.h>
11
12 #include <string>
13 #include <vector>
14
15 #include "ash/host/root_window_transformer.h"
16 #include "base/basictypes.h"
17 #include "base/command_line.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/message_loop/message_pump_x11.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_util.h"
22 #include "base/sys_info.h"
23 #include "ui/aura/client/screen_position_client.h"
24 #include "ui/aura/env.h"
25 #include "ui/aura/window.h"
26 #include "ui/base/x/x11_util.h"
27 #include "ui/events/event.h"
28 #include "ui/events/event_switches.h"
29 #include "ui/events/event_utils.h"
30 #include "ui/events/x/device_data_manager.h"
31 #include "ui/events/x/device_list_cache_x.h"
32 #include "ui/events/x/touch_factory_x11.h"
33 #include "ui/gfx/rect.h"
34 #include "ui/gfx/screen.h"
35
36 namespace ash {
37
38 // Accomplishes 2 tasks concerning touch event calibration:
39 // 1. Being a message-pump observer,
40 // routes all the touch events to the X root window,
41 // where they can be calibrated later.
42 // 2. Has the Calibrate method that does the actual bezel calibration,
43 // when invoked from X root window's event dispatcher.
44 class AshWindowTreeHostX11::TouchEventCalibrate
45 : public base::MessagePumpObserver {
46 public:
47 TouchEventCalibrate() : left_(0), right_(0), top_(0), bottom_(0) {
48 base::MessageLoopForUI::current()->AddObserver(this);
49 #if defined(USE_XI2_MT)
50 std::vector<std::string> parts;
51 if (Tokenize(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
52 switches::kTouchCalibration),
53 ",",
54 &parts) >= 4) {
55 if (!base::StringToInt(parts[0], &left_))
56 DLOG(ERROR) << "Incorrect left border calibration value passed.";
57 if (!base::StringToInt(parts[1], &right_))
58 DLOG(ERROR) << "Incorrect right border calibration value passed.";
59 if (!base::StringToInt(parts[2], &top_))
60 DLOG(ERROR) << "Incorrect top border calibration value passed.";
61 if (!base::StringToInt(parts[3], &bottom_))
62 DLOG(ERROR) << "Incorrect bottom border calibration value passed.";
63 }
64 #endif // defined(USE_XI2_MT)
65 }
66
67 virtual ~TouchEventCalibrate() {
68 base::MessageLoopForUI::current()->RemoveObserver(this);
69 }
70
71 // Modify the location of the |event|,
72 // expanding it from |bounds| to (|bounds| + bezels).
73 // Required when touchscreen is bigger than screen (i.e. has bezels),
74 // because we receive events in touchscreen coordinates,
75 // which need to be expanded when converting to screen coordinates,
76 // so that location on bezels will be outside of screen area.
77 void Calibrate(ui::TouchEvent* event, const gfx::Rect& bounds) {
78 #if defined(USE_XI2_MT)
79 int x = event->x();
80 int y = event->y();
81
82 if (!left_ && !right_ && !top_ && !bottom_)
83 return;
84
85 const int resolution_x = bounds.width();
86 const int resolution_y = bounds.height();
87 // The "grace area" (10% in this case) is to make it easier for the user to
88 // navigate to the corner.
89 const double kGraceAreaFraction = 0.1;
90 if (left_ || right_) {
91 // Offset the x position to the real
92 x -= left_;
93 // Check if we are in the grace area of the left side.
94 // Note: We might not want to do this when the gesture is locked?
95 if (x < 0 && x > -left_ * kGraceAreaFraction)
96 x = 0;
97 // Check if we are in the grace area of the right side.
98 // Note: We might not want to do this when the gesture is locked?
99 if (x > resolution_x - left_ &&
100 x < resolution_x - left_ + right_ * kGraceAreaFraction)
101 x = resolution_x - left_;
102 // Scale the screen area back to the full resolution of the screen.
103 x = (x * resolution_x) / (resolution_x - (right_ + left_));
104 }
105 if (top_ || bottom_) {
106 // When there is a top bezel we add our border,
107 y -= top_;
108
109 // Check if we are in the grace area of the top side.
110 // Note: We might not want to do this when the gesture is locked?
111 if (y < 0 && y > -top_ * kGraceAreaFraction)
112 y = 0;
113
114 // Check if we are in the grace area of the bottom side.
115 // Note: We might not want to do this when the gesture is locked?
116 if (y > resolution_y - top_ &&
117 y < resolution_y - top_ + bottom_ * kGraceAreaFraction)
118 y = resolution_y - top_;
119 // Scale the screen area back to the full resolution of the screen.
120 y = (y * resolution_y) / (resolution_y - (bottom_ + top_));
121 }
122
123 // Set the modified coordinate back to the event.
124 if (event->root_location() == event->location()) {
125 // Usually those will be equal,
126 // if not, I am not sure what the correct value should be.
127 event->set_root_location(gfx::Point(x, y));
128 }
129 event->set_location(gfx::Point(x, y));
130 #endif // defined(USE_XI2_MT)
131 }
132
133 private:
134 // Overridden from base::MessagePumpObserver:
135 virtual void WillProcessEvent(const base::NativeEvent& event) OVERRIDE {
136 #if defined(USE_XI2_MT)
137 if (event->type == GenericEvent &&
138 (event->xgeneric.evtype == XI_TouchBegin ||
139 event->xgeneric.evtype == XI_TouchUpdate ||
140 event->xgeneric.evtype == XI_TouchEnd)) {
141 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(event->xcookie.data);
142 xievent->event = xievent->root;
143 xievent->event_x = xievent->root_x;
144 xievent->event_y = xievent->root_y;
145 }
146 #endif // defined(USE_XI2_MT)
147 }
148
149 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {}
150
151 // The difference in screen's native resolution pixels between
152 // the border of the touchscreen and the border of the screen,
153 // aka bezel sizes.
154 int left_;
155 int right_;
156 int top_;
157 int bottom_;
158
159 DISALLOW_COPY_AND_ASSIGN(TouchEventCalibrate);
160 };
161
162 ////////////////////////////////////////////////////////////////////////////////
163 // AshWindowTreeHostX11
164
165 AshWindowTreeHostX11::AshWindowTreeHostX11(const gfx::Rect& initial_bounds)
166 : WindowTreeHostX11(initial_bounds),
167 is_internal_display_(false),
168 touch_calibrate_(new TouchEventCalibrate),
169 transformer_helper_(this) {
170 aura::Env::GetInstance()->AddObserver(this);
171 }
172
173 AshWindowTreeHostX11::~AshWindowTreeHostX11() {
174 aura::Env::GetInstance()->RemoveObserver(this);
175 UnConfineCursor();
176 }
177
178 void AshWindowTreeHostX11::ToggleFullScreen() { NOTIMPLEMENTED(); }
179
180 bool AshWindowTreeHostX11::ConfineCursorToRootWindow() {
181 #if XFIXES_MAJOR >= 5
182 DCHECK(!pointer_barriers_.get());
183 if (pointer_barriers_)
184 return false;
185 pointer_barriers_.reset(new XID[4]);
186 gfx::Rect barrier(bounds());
187 barrier.Inset(transformer_helper_.GetHostInsets());
188 // Horizontal, top barriers.
189 pointer_barriers_[0] = XFixesCreatePointerBarrier(xdisplay(),
190 x_root_window(),
191 barrier.x(),
192 barrier.y(),
193 barrier.right(),
194 barrier.y(),
195 BarrierPositiveY,
196 0,
197 XIAllDevices);
198 // Horizontal, bottom barriers.
199 pointer_barriers_[1] = XFixesCreatePointerBarrier(xdisplay(),
200 x_root_window(),
201 barrier.x(),
202 barrier.bottom(),
203 barrier.right(),
204 barrier.bottom(),
205 BarrierNegativeY,
206 0,
207 XIAllDevices);
208 // Vertical, left barriers.
209 pointer_barriers_[2] = XFixesCreatePointerBarrier(xdisplay(),
210 x_root_window(),
211 barrier.x(),
212 barrier.y(),
213 barrier.x(),
214 barrier.bottom(),
215 BarrierPositiveX,
216 0,
217 XIAllDevices);
218 // Vertical, right barriers.
219 pointer_barriers_[3] = XFixesCreatePointerBarrier(xdisplay(),
220 x_root_window(),
221 barrier.right(),
222 barrier.y(),
223 barrier.right(),
224 barrier.bottom(),
225 BarrierNegativeX,
226 0,
227 XIAllDevices);
228 #endif
229 return true;
230 }
231
232 void AshWindowTreeHostX11::UnConfineCursor() {
233 #if XFIXES_MAJOR >= 5
234 if (pointer_barriers_) {
235 XFixesDestroyPointerBarrier(xdisplay(), pointer_barriers_[0]);
236 XFixesDestroyPointerBarrier(xdisplay(), pointer_barriers_[1]);
237 XFixesDestroyPointerBarrier(xdisplay(), pointer_barriers_[2]);
238 XFixesDestroyPointerBarrier(xdisplay(), pointer_barriers_[3]);
239 pointer_barriers_.reset();
240 }
241 #endif
242 }
243
244 void AshWindowTreeHostX11::SetRootWindowTransformer(
245 scoped_ptr<RootWindowTransformer> transformer) {
246 transformer_helper_.SetRootWindowTransformer(transformer.Pass());
247 UpdateIsInternalDisplay();
248 if (pointer_barriers_) {
249 UnConfineCursor();
250 ConfineCursorToRootWindow();
251 }
252 }
253
254 aura::WindowTreeHost* AshWindowTreeHostX11::AsWindowTreeHost() { return this; }
255
256 void AshWindowTreeHostX11::SetBounds(const gfx::Rect& bounds) {
257 WindowTreeHostX11::SetBounds(bounds);
258 UpdateIsInternalDisplay();
259 if (pointer_barriers_) {
260 UnConfineCursor();
261 ConfineCursorToRootWindow();
262 }
263 }
264
265 gfx::Transform AshWindowTreeHostX11::GetRootTransform() const {
266 return transformer_helper_.GetTransform();
267 }
268
269 void AshWindowTreeHostX11::SetRootTransform(const gfx::Transform& transform) {
270 transformer_helper_.SetTransform(transform);
271 }
272
273 gfx::Transform AshWindowTreeHostX11::GetInverseRootTransform() const {
274 return transformer_helper_.GetInverseTransform();
275 }
276
277 void AshWindowTreeHostX11::UpdateRootWindowSize(const gfx::Size& host_size) {
278 transformer_helper_.UpdateWindowSize(host_size);
279 }
280
281 void AshWindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) {
282 SetCrOSTapPaused(!show);
283 }
284
285 void AshWindowTreeHostX11::OnWindowInitialized(aura::Window* window) {}
286
287 void AshWindowTreeHostX11::OnHostInitialized(aura::WindowTreeHost* host) {
288 // UpdateIsInternalDisplay relies on RootWindowSettings' display_id being set
289 // available by the time WED::Init is called. (set in
290 // DisplayManager::CreateRootWindowForDisplay)
291 // Ready when NotifyHostInitialized is called from WED::Init.
292 if (host != AsWindowTreeHost())
293 return;
294 UpdateIsInternalDisplay();
295
296 // We have to enable Tap-to-click by default because the cursor is set to
297 // visible in Shell::InitRootWindowController.
298 SetCrOSTapPaused(false);
299 }
300
301 void AshWindowTreeHostX11::OnConfigureNotify() {
302 UpdateIsInternalDisplay();
303
304 // Always update barrier and mouse location because |bounds_| might
305 // have already been updated in |SetBounds|.
306 if (pointer_barriers_) {
307 UnConfineCursor();
308 ConfineCursorToRootWindow();
309 }
310 }
311
312 void AshWindowTreeHostX11::TranslateAndDispatchLocatedEvent(
313 ui::LocatedEvent* event) {
314 switch (event->type()) {
315 case ui::ET_TOUCH_MOVED:
316 case ui::ET_TOUCH_PRESSED:
317 case ui::ET_TOUCH_CANCELLED:
318 case ui::ET_TOUCH_RELEASED: {
319 ui::TouchEvent* touchev = static_cast<ui::TouchEvent*>(event);
320 if (base::SysInfo::IsRunningOnChromeOS()) {
321 // X maps the touch-surface to the size of the X root-window.
322 // In multi-monitor setup, Coordinate Transformation Matrix
323 // repositions the touch-surface onto part of X root-window
324 // containing aura root-window corresponding to the touchscreen.
325 // However, if aura root-window has non-zero origin,
326 // we need to relocate the event into aura root-window coordinates.
327 touchev->Relocate(bounds().origin());
328 #if defined(USE_XI2_MT)
329 if (is_internal_display_)
330 touch_calibrate_->Calibrate(touchev, bounds());
331 #endif // defined(USE_XI2_MT)
332 }
333 break;
334 }
335 default: {
336 aura::Window* root_window = window();
337 aura::client::ScreenPositionClient* screen_position_client =
338 aura::client::GetScreenPositionClient(root_window);
339 gfx::Rect local(bounds().size());
340
341 if (screen_position_client && !local.Contains(event->location())) {
342 gfx::Point location(event->location());
343 // In order to get the correct point in screen coordinates
344 // during passive grab, we first need to find on which host window
345 // the mouse is on, and find out the screen coordinates on that
346 // host window, then convert it back to this host window's coordinate.
347 screen_position_client->ConvertHostPointToScreen(root_window,
348 &location);
349 screen_position_client->ConvertPointFromScreen(root_window, &location);
350 ConvertPointToHost(&location);
351 event->set_location(location);
352 event->set_root_location(location);
353 }
354 break;
355 }
356 }
357 SendEventToProcessor(event);
358 }
359
360 void AshWindowTreeHostX11::UpdateIsInternalDisplay() {
361 aura::Window* root_window = window();
362 gfx::Screen* screen = gfx::Screen::GetScreenFor(root_window);
363 gfx::Display display = screen->GetDisplayNearestWindow(root_window);
364 DCHECK(display.is_valid());
365 is_internal_display_ = display.IsInternal();
366 }
367
368 void AshWindowTreeHostX11::SetCrOSTapPaused(bool state) {
369 if (!ui::IsXInput2Available())
370 return;
371 // Temporarily pause tap-to-click when the cursor is hidden.
372 Atom prop = atom_cache()->GetAtom("Tap Paused");
373 unsigned char value = state;
374 XIDeviceList dev_list =
375 ui::DeviceListCacheX::GetInstance()->GetXI2DeviceList(xdisplay());
376
377 // Only slave pointer devices could possibly have tap-paused property.
378 for (int i = 0; i < dev_list.count; i++) {
379 if (dev_list[i].use == XISlavePointer) {
380 Atom old_type;
381 int old_format;
382 unsigned long old_nvalues, bytes;
383 unsigned char* data;
384 int result = XIGetProperty(xdisplay(),
385 dev_list[i].deviceid,
386 prop,
387 0,
388 0,
389 False,
390 AnyPropertyType,
391 &old_type,
392 &old_format,
393 &old_nvalues,
394 &bytes,
395 &data);
396 if (result != Success)
397 continue;
398 XFree(data);
399 XIChangeProperty(xdisplay(),
400 dev_list[i].deviceid,
401 prop,
402 XA_INTEGER,
403 8,
404 PropModeReplace,
405 &value,
406 1);
407 }
408 }
409 }
410
411 AshWindowTreeHost* AshWindowTreeHost::Create(const gfx::Rect& initial_bounds) {
412 return new AshWindowTreeHostX11(initial_bounds);
413 }
414
415 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698