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

Side by Side Diff: ui/ozone/platform/x11/x11_event_factory.cc

Issue 1602173005: Add PlatformWindow/Event related code for Ozone X11. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Small fixes. Created 4 years, 11 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
OLDNEW
(Empty)
1 // Copyright 2016 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 "ui/ozone/platform/x11/x11_event_factory.h"
6
7 #include <X11/X.h>
8 #include <X11/XKBlib.h>
9 #include <X11/Xlib.h>
10 #include <X11/extensions/XInput2.h>
11
12 #include "base/logging.h"
13 #include "base/macros.h"
14 #include "ui/events/devices/x11/device_data_manager_x11.h"
15 #include "ui/events/event.h"
16 #include "ui/events/event_utils.h"
17 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
18 #include "ui/events/platform/platform_event_dispatcher.h"
19 #include "ui/events/x/events_x_utils.h"
20 #include "ui/gfx/x/x11_types.h"
21 #include "ui/ozone/platform/x11/x11_surface_factory.h"
22 #include "ui/ozone/platform/x11/x11_window_host.h"
23 #include "ui/ozone/public/ozone_platform.h"
24 #include "ui/ozone/public/surface_factory_ozone.h"
25
26 namespace ui {
27
28 namespace {
29
30 using TimeDelta = base::TimeDelta;
31
32 int g_xinput_opcode = -1;
33
34 bool InitializeXInput2(XDisplay* display) {
spang 2016/01/20 19:53:31 These look really easy to share with the X11 build
kylechar 2016/01/20 21:46:16 Good idea! I'll move that into a different CL.
35 if (!display)
36 return false;
37
38 int event, err;
39
40 int xiopcode;
41 if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) {
42 DVLOG(1) << "X Input extension not available.";
43 return false;
44 }
45 g_xinput_opcode = xiopcode;
46
47 int major = 2, minor = 2;
48 if (XIQueryVersion(display, &major, &minor) == BadRequest) {
49 DVLOG(1) << "XInput2 not supported in the server.";
50 return false;
51 }
52 if (major < 2 || (major == 2 && minor < 2)) {
53 DVLOG(1) << "XI version on server is " << major << "." << minor << ". "
54 << "But 2.2 is required.";
55 return false;
56 }
57
58 return true;
59 }
60
61 bool InitializeXkb(XDisplay* display) {
62 if (!display)
63 return false;
64
65 int opcode, event, error;
66 int major = XkbMajorVersion;
67 int minor = XkbMinorVersion;
68 if (!XkbQueryExtension(display, &opcode, &event, &error, &major, &minor)) {
69 DVLOG(1) << "Xkb extension not available.";
70 return false;
71 }
72
73 // Ask the server not to send KeyRelease event when the user holds down a key.
74 // crbug.com/138092
75 Bool supported_return;
76 if (!XkbSetDetectableAutoRepeat(display, True, &supported_return)) {
77 DVLOG(1) << "XKB not supported in the server.";
78 return false;
79 }
80
81 return true;
82 }
83
84 // Translates XI2 XEvent into a ui::Event.
85 ui::Event* TranslateXI2EventToEvent(const XEvent& xev) {
86 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev.xcookie.data);
87 EventType event_type = EventTypeFromXEvent(xev);
88 gfx::Point location = gfx::Point(xievent->event_x, xievent->event_y);
89 gfx::Point root_location = gfx::Point(xievent->root_x, xievent->root_y);
90 int flags = EventFlagsFromXEvent(xev);
91 switch (event_type) {
92 case ET_KEY_PRESSED:
93 case ET_KEY_RELEASED:
94 return new KeyEvent(event_type, KeyboardCodeFromXKeyEvent(&xev), flags);
95 case ET_MOUSE_PRESSED:
96 case ET_MOUSE_MOVED:
97 case ET_MOUSE_DRAGGED:
98 case ET_MOUSE_RELEASED:
99 return new MouseEvent(event_type, location, root_location, TimeDelta(),
100 flags, GetChangedMouseButtonFlagsFromXEvent(xev));
101 case ET_MOUSEWHEEL:
102 return new MouseWheelEvent(GetMouseWheelOffsetFromXEvent(xev), location,
103 root_location, TimeDelta(), flags,
104 GetChangedMouseButtonFlagsFromXEvent(xev));
105 case ET_SCROLL_FLING_START:
106 case ET_SCROLL_FLING_CANCEL: {
107 float x_offset, y_offset, x_offset_ordinal, y_offset_ordinal;
108 GetFlingDataFromXEvent(xev, &x_offset, &y_offset, &x_offset_ordinal,
109 &y_offset_ordinal, nullptr);
110 return new ScrollEvent(event_type, location, EventTimeFromXEvent(xev),
111 flags, x_offset, y_offset, x_offset_ordinal,
112 y_offset_ordinal, 0);
113 }
114 case ET_SCROLL: {
115 float x_offset, y_offset, x_offset_ordinal, y_offset_ordinal;
116 int finger_count;
117 GetScrollOffsetsFromXEvent(xev, &x_offset, &y_offset, &x_offset_ordinal,
118 &y_offset_ordinal, &finger_count);
119 return new ScrollEvent(event_type, location, EventTimeFromXEvent(xev),
120 flags, x_offset, y_offset, x_offset_ordinal,
121 y_offset_ordinal, finger_count);
122 }
123 case ET_TOUCH_MOVED:
124 case ET_TOUCH_PRESSED:
125 case ET_TOUCH_CANCELLED:
126 case ET_TOUCH_RELEASED:
127 return new TouchEvent(event_type, location, GetTouchIdFromXEvent(xev),
128 EventTimeFromXEvent(xev));
129 case ET_UNKNOWN:
130 return nullptr;
131 default:
132 break;
133 }
134 return nullptr;
135 }
136
137 // Translates a XEvent into a ui::Event.
138 ui::Event* TranslateXEventToEvent(const XEvent& xev) {
139 int flags = EventFlagsFromXEvent(xev);
140 switch (xev.type) {
141 case LeaveNotify:
142 case EnterNotify:
143 // EnterNotify creates ET_MOUSE_MOVED. Mark as synthesized as this is
144 // not real mouse move event.
145 // int flags = GetEventFlagsFromXState(xev.xcrossing.state);
146 if (xev.type == EnterNotify)
147 flags |= EF_IS_SYNTHESIZED;
148 return new MouseEvent(
149 ET_MOUSE_MOVED, gfx::Point(xev.xcrossing.x, xev.xcrossing.y),
150 gfx::Point(xev.xcrossing.x_root, xev.xcrossing.y_root), TimeDelta(),
151 flags, 0);
152
153 case KeyPress:
154 case KeyRelease:
155 return new KeyEvent(EventTypeFromXEvent(xev),
156 KeyboardCodeFromXKeyEvent(&xev), flags);
157
158 case ButtonPress:
159 case ButtonRelease: {
160 gfx::Point location = gfx::Point(xev.xbutton.x, xev.xbutton.y);
161 gfx::Point root_location =
162 gfx::Point(xev.xbutton.x_root, xev.xbutton.y_root);
163 switch (EventTypeFromXEvent(xev)) {
164 case ET_MOUSEWHEEL:
165 return new MouseWheelEvent(GetMouseWheelOffsetFromXEvent(xev),
166 location, root_location, TimeDelta(),
167 flags, 0);
168 case ET_MOUSE_PRESSED:
169 case ET_MOUSE_RELEASED:
170 return new MouseEvent(EventTypeFromXEvent(xev), location,
171 root_location, TimeDelta(), flags,
172 GetChangedMouseButtonFlagsFromXEvent(xev));
173 case ET_UNKNOWN:
174 // No event is created for X11-release events for mouse-wheel
175 // buttons.
176 break;
177 default:
178 NOTREACHED();
179 }
180 break;
181 }
182
183 case GenericEvent:
184 return TranslateXI2EventToEvent(xev);
185 }
186 return nullptr;
187 }
188
189 } // namespace
190
191 X11EventFactory::X11EventFactory(
192 XDisplay* display,
193 scoped_refptr<X11WindowHostManager> window_manager)
194 : display_(display), window_manager_(window_manager) {
195 CHECK(display_);
spang 2016/01/20 19:53:31 DCHECK for non-security assertions per chrome styl
kylechar 2016/01/20 21:46:16 Done.
196 DeviceDataManagerX11::CreateInstance();
197 InitializeXInput2(display_);
198 InitializeXkb(display_);
199 AddEventWatcher();
200 }
201
202 X11EventFactory::~X11EventFactory() {}
203
204 // static
205 X11EventFactory* X11EventFactory::GetInstance() {
206 return static_cast<X11EventFactory*>(PlatformEventSource::GetInstance());
207 }
208
209 ////////////////////////////////////////////////////////////////////////////////
210 // X11EventFactory, public
211
212 void X11EventFactory::DispatchXEvents() {
213 DCHECK(display_);
214 // Handle all pending events.
215 // It may be useful to eventually align this event dispatch with vsync, but
216 // not yet.
217 continue_stream_ = true;
218 while (XPending(display_) && continue_stream_) {
219 XEvent xevent;
220 XNextEvent(display_, &xevent);
221 ExtractCookieDataDispatchEvent(&xevent);
222 }
223 }
224
225 void X11EventFactory::BlockUntilWindowMapped(XID window) {
226 XEvent event;
227 do {
228 // Block until there's a message of |event_mask| type on |w|. Then remove
229 // it from the queue and stuff it in |event|.
230 XWindowEvent(display_, window, StructureNotifyMask, &event);
231 ExtractCookieDataDispatchEvent(&event);
232 } while (event.type != MapNotify);
233 }
234
235 ////////////////////////////////////////////////////////////////////////////////
236 // X11EventFactory, private
237
238 void X11EventFactory::AddEventWatcher() {
239 if (initialized_)
240 return;
241 if (!base::MessageLoop::current())
242 return;
243
244 int fd = ConnectionNumber(display_);
245 base::MessageLoopForUI::current()->WatchFileDescriptor(
246 fd, true, base::MessagePumpLibevent::WATCH_READ, &watcher_controller_,
247 this);
248 initialized_ = true;
249 }
250
251 uint32_t X11EventFactory::ExtractCookieDataDispatchEvent(XEvent* xevent) {
252 bool have_cookie = false;
253 if (xevent->type == GenericEvent &&
254 XGetEventData(xevent->xgeneric.display, &xevent->xcookie)) {
255 have_cookie = true;
256 }
257 uint32_t action = DispatchEvent(xevent);
258 if (have_cookie)
259 XFreeEventData(xevent->xgeneric.display, &xevent->xcookie);
260 return action;
261 }
262
263 uint32_t X11EventFactory::DispatchEvent(base::NativeEvent event) {
264 XEvent* xevent = static_cast<XEvent*>(event);
265 uint32_t action = POST_DISPATCH_STOP_PROPAGATION;
266 base::NativeEvent translated_event = TranslateXEventToEvent(*xevent);
267 if (translated_event) {
268 action = PlatformEventSource::DispatchEvent(translated_event);
269 } else {
270 DispatchXEventToXWindow(*xevent);
271 }
272 if (xevent->type == GenericEvent &&
273 xevent->xgeneric.evtype == XI_HierarchyChanged) {
274 // TODO(kylechar): UpdateDeviceList() isn't calling X11 functions.
275 ui::UpdateDeviceList();
276 }
277
278 if (xevent->type == EnterNotify &&
279 xevent->xcrossing.detail != NotifyInferior &&
280 xevent->xcrossing.mode != NotifyUngrab) {
281 // Clear stored scroll data
282 DeviceDataManagerX11::GetInstance()->InvalidateScrollClasses();
283 }
284 return action;
285 }
286
287 void X11EventFactory::StopCurrentEventStream() {
288 continue_stream_ = false;
289 }
290
291 void X11EventFactory::OnDispatcherListChanged() {
292 AddEventWatcher();
293 }
294
295 void X11EventFactory::OnFileCanReadWithoutBlocking(int fd) {
296 DispatchXEvents();
297 }
298
299 void X11EventFactory::OnFileCanWriteWithoutBlocking(int fd) {
300 NOTREACHED();
301 }
302
303 void X11EventFactory::DispatchXEventToXWindow(const XEvent& xev) {
304 switch (xev.type) {
305 case FocusOut:
306 case Expose:
307 case ConfigureNotify:
308 case ClientMessage: {
309 // This is a windowing message that needs to be passed to the platform
310 // window directly.
311 X11WindowHost* window = window_manager_->FindWindow(xev.xany.window);
312 if (window)
313 window->ProcessXEvent(xev);
314 }
315 }
316 }
317
318 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698