OLD | NEW |
---|---|
(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/Xlib.h> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/macros.h" | |
11 #include "ui/events/devices/x11/device_data_manager_x11.h" | |
12 #include "ui/events/event.h" | |
13 #include "ui/events/event_utils.h" | |
14 #include "ui/events/keycodes/keyboard_code_conversion_x.h" | |
15 #include "ui/events/platform/platform_event_dispatcher.h" | |
16 #include "ui/events/x/events_x_utils.h" | |
17 #include "ui/events/x/input_x.h" | |
18 #include "ui/gfx/x/x11_types.h" | |
19 #include "ui/ozone/platform/x11/x11_surface_factory.h" | |
20 #include "ui/ozone/platform/x11/x11_window_ozone.h" | |
21 #include "ui/ozone/public/ozone_platform.h" | |
22 #include "ui/ozone/public/surface_factory_ozone.h" | |
23 | |
24 namespace ui { | |
25 | |
26 namespace { | |
27 | |
28 using TimeDelta = base::TimeDelta; | |
29 | |
30 // Translates XI2 XEvent into a ui::Event. | |
31 ui::Event* TranslateXI2EventToEvent(const XEvent& xev) { | |
32 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev.xcookie.data); | |
33 EventType event_type = EventTypeFromXEvent(xev); | |
34 gfx::Point location = gfx::Point(xievent->event_x, xievent->event_y); | |
35 gfx::Point root_location = gfx::Point(xievent->root_x, xievent->root_y); | |
36 int flags = EventFlagsFromXEvent(xev); | |
37 switch (event_type) { | |
38 case ET_KEY_PRESSED: | |
39 case ET_KEY_RELEASED: | |
40 return new KeyEvent(event_type, KeyboardCodeFromXKeyEvent(&xev), flags); | |
41 case ET_MOUSE_PRESSED: | |
42 case ET_MOUSE_MOVED: | |
43 case ET_MOUSE_DRAGGED: | |
44 case ET_MOUSE_RELEASED: | |
45 return new MouseEvent(event_type, location, root_location, TimeDelta(), | |
46 flags, GetChangedMouseButtonFlagsFromXEvent(xev)); | |
47 case ET_MOUSEWHEEL: | |
48 return new MouseWheelEvent(GetMouseWheelOffsetFromXEvent(xev), location, | |
49 root_location, TimeDelta(), flags, | |
50 GetChangedMouseButtonFlagsFromXEvent(xev)); | |
51 case ET_SCROLL_FLING_START: | |
52 case ET_SCROLL_FLING_CANCEL: { | |
53 float x_offset, y_offset, x_offset_ordinal, y_offset_ordinal; | |
54 GetFlingDataFromXEvent(xev, &x_offset, &y_offset, &x_offset_ordinal, | |
55 &y_offset_ordinal, nullptr); | |
56 return new ScrollEvent(event_type, location, EventTimeFromXEvent(xev), | |
57 flags, x_offset, y_offset, x_offset_ordinal, | |
58 y_offset_ordinal, 0); | |
59 } | |
60 case ET_SCROLL: { | |
61 float x_offset, y_offset, x_offset_ordinal, y_offset_ordinal; | |
62 int finger_count; | |
63 GetScrollOffsetsFromXEvent(xev, &x_offset, &y_offset, &x_offset_ordinal, | |
64 &y_offset_ordinal, &finger_count); | |
65 return new ScrollEvent(event_type, location, EventTimeFromXEvent(xev), | |
66 flags, x_offset, y_offset, x_offset_ordinal, | |
67 y_offset_ordinal, finger_count); | |
68 } | |
69 case ET_TOUCH_MOVED: | |
70 case ET_TOUCH_PRESSED: | |
71 case ET_TOUCH_CANCELLED: | |
72 case ET_TOUCH_RELEASED: | |
73 return new TouchEvent(event_type, location, GetTouchIdFromXEvent(xev), | |
74 EventTimeFromXEvent(xev)); | |
75 case ET_UNKNOWN: | |
76 return nullptr; | |
77 default: | |
78 break; | |
79 } | |
80 return nullptr; | |
81 } | |
82 | |
83 // Translates a XEvent into a ui::Event. | |
84 ui::Event* TranslateXEventToEvent(const XEvent& xev) { | |
85 int flags = EventFlagsFromXEvent(xev); | |
86 switch (xev.type) { | |
87 case LeaveNotify: | |
88 case EnterNotify: | |
89 // EnterNotify creates ET_MOUSE_MOVED. Mark as synthesized as this is | |
90 // not real mouse move event. | |
91 // int flags = GetEventFlagsFromXState(xev.xcrossing.state); | |
92 if (xev.type == EnterNotify) | |
93 flags |= EF_IS_SYNTHESIZED; | |
94 return new MouseEvent( | |
95 ET_MOUSE_MOVED, gfx::Point(xev.xcrossing.x, xev.xcrossing.y), | |
96 gfx::Point(xev.xcrossing.x_root, xev.xcrossing.y_root), TimeDelta(), | |
97 flags, 0); | |
98 | |
99 case KeyPress: | |
100 case KeyRelease: | |
101 return new KeyEvent(EventTypeFromXEvent(xev), | |
102 KeyboardCodeFromXKeyEvent(&xev), flags); | |
103 | |
104 case ButtonPress: | |
105 case ButtonRelease: { | |
106 gfx::Point location = gfx::Point(xev.xbutton.x, xev.xbutton.y); | |
107 gfx::Point root_location = | |
108 gfx::Point(xev.xbutton.x_root, xev.xbutton.y_root); | |
109 switch (EventTypeFromXEvent(xev)) { | |
110 case ET_MOUSEWHEEL: | |
111 return new MouseWheelEvent(GetMouseWheelOffsetFromXEvent(xev), | |
112 location, root_location, TimeDelta(), | |
113 flags, 0); | |
114 case ET_MOUSE_PRESSED: | |
115 case ET_MOUSE_RELEASED: | |
116 return new MouseEvent(EventTypeFromXEvent(xev), location, | |
117 root_location, TimeDelta(), flags, | |
118 GetChangedMouseButtonFlagsFromXEvent(xev)); | |
119 case ET_UNKNOWN: | |
120 // No event is created for X11-release events for mouse-wheel | |
121 // buttons. | |
122 break; | |
123 default: | |
124 NOTREACHED(); | |
125 } | |
126 break; | |
127 } | |
128 | |
129 case GenericEvent: | |
130 return TranslateXI2EventToEvent(xev); | |
131 } | |
132 return nullptr; | |
133 } | |
134 | |
135 } // namespace | |
136 | |
137 X11EventFactory::X11EventFactory( | |
138 XDisplay* display, | |
139 scoped_refptr<X11WindowManagerOzone> window_manager) | |
140 : display_(display), window_manager_(window_manager) { | |
141 DCHECK(display_); | |
142 DeviceDataManagerX11::CreateInstance(); | |
143 InitializeXInput2(display_); | |
144 InitializeXkb(display_); | |
145 AddEventWatcher(); | |
spang
2016/01/20 22:32:53
Does it need to be called here since it's called i
kylechar
2016/01/21 14:14:52
I'm not sure. It seems like it shouldn't need to b
sadrul
2016/01/21 14:53:01
I think in some tests, the message-loop is created
| |
146 } | |
147 | |
148 X11EventFactory::~X11EventFactory() {} | |
149 | |
150 // static | |
151 X11EventFactory* X11EventFactory::GetInstance() { | |
152 return static_cast<X11EventFactory*>(PlatformEventSource::GetInstance()); | |
153 } | |
154 | |
155 //////////////////////////////////////////////////////////////////////////////// | |
156 // X11EventFactory, public | |
157 | |
158 void X11EventFactory::DispatchXEvents() { | |
159 DCHECK(display_); | |
160 // Handle all pending events. | |
161 // It may be useful to eventually align this event dispatch with vsync, but | |
162 // not yet. | |
163 continue_stream_ = true; | |
164 while (XPending(display_) && continue_stream_) { | |
165 XEvent xevent; | |
166 XNextEvent(display_, &xevent); | |
167 ExtractCookieDataDispatchEvent(&xevent); | |
168 } | |
169 } | |
170 | |
171 void X11EventFactory::BlockUntilWindowMapped(XID window) { | |
172 XEvent event; | |
173 do { | |
174 // Block until there's a message of |event_mask| type on |w|. Then remove | |
175 // it from the queue and stuff it in |event|. | |
176 XWindowEvent(display_, window, StructureNotifyMask, &event); | |
177 ExtractCookieDataDispatchEvent(&event); | |
178 } while (event.type != MapNotify); | |
179 } | |
180 | |
181 //////////////////////////////////////////////////////////////////////////////// | |
182 // X11EventFactory, private | |
183 | |
184 void X11EventFactory::AddEventWatcher() { | |
185 if (initialized_) | |
186 return; | |
187 if (!base::MessageLoop::current()) | |
188 return; | |
189 | |
190 int fd = ConnectionNumber(display_); | |
191 base::MessageLoopForUI::current()->WatchFileDescriptor( | |
192 fd, true, base::MessagePumpLibevent::WATCH_READ, &watcher_controller_, | |
193 this); | |
194 initialized_ = true; | |
195 } | |
196 | |
197 uint32_t X11EventFactory::ExtractCookieDataDispatchEvent(XEvent* xevent) { | |
198 bool have_cookie = false; | |
199 if (xevent->type == GenericEvent && | |
200 XGetEventData(xevent->xgeneric.display, &xevent->xcookie)) { | |
201 have_cookie = true; | |
202 } | |
203 uint32_t action = DispatchEvent(xevent); | |
204 if (have_cookie) | |
205 XFreeEventData(xevent->xgeneric.display, &xevent->xcookie); | |
206 return action; | |
207 } | |
208 | |
209 uint32_t X11EventFactory::DispatchEvent(base::NativeEvent event) { | |
210 XEvent* xevent = static_cast<XEvent*>(event); | |
211 uint32_t action = POST_DISPATCH_STOP_PROPAGATION; | |
212 base::NativeEvent translated_event = TranslateXEventToEvent(*xevent); | |
213 if (translated_event) { | |
214 action = PlatformEventSource::DispatchEvent(translated_event); | |
215 } else { | |
216 DispatchXEventToXWindow(*xevent); | |
spang
2016/01/20 22:32:53
Someday I hope we will be able to take this branch
| |
217 } | |
218 if (xevent->type == GenericEvent && | |
219 xevent->xgeneric.evtype == XI_HierarchyChanged) { | |
220 // TODO(kylechar): UpdateDeviceList() isn't calling X11 functions. | |
221 ui::UpdateDeviceList(); | |
222 } | |
223 | |
224 if (xevent->type == EnterNotify && | |
225 xevent->xcrossing.detail != NotifyInferior && | |
226 xevent->xcrossing.mode != NotifyUngrab) { | |
227 // Clear stored scroll data | |
228 DeviceDataManagerX11::GetInstance()->InvalidateScrollClasses(); | |
229 } | |
230 return action; | |
231 } | |
232 | |
233 void X11EventFactory::StopCurrentEventStream() { | |
234 continue_stream_ = false; | |
235 } | |
236 | |
237 void X11EventFactory::OnDispatcherListChanged() { | |
238 AddEventWatcher(); | |
239 } | |
240 | |
241 void X11EventFactory::OnFileCanReadWithoutBlocking(int fd) { | |
242 DispatchXEvents(); | |
243 } | |
244 | |
245 void X11EventFactory::OnFileCanWriteWithoutBlocking(int fd) { | |
246 NOTREACHED(); | |
247 } | |
248 | |
249 void X11EventFactory::DispatchXEventToXWindow(const XEvent& xev) { | |
250 switch (xev.type) { | |
251 case FocusOut: | |
252 case Expose: | |
253 case ConfigureNotify: | |
254 case ClientMessage: { | |
255 // This is a windowing message that needs to be passed to the platform | |
256 // window directly. | |
257 X11WindowOzone* window = window_manager_->FindWindow(xev.xany.window); | |
258 if (window) | |
259 window->ProcessXEvent(xev); | |
260 } | |
261 } | |
262 } | |
263 | |
264 } // namespace ui | |
OLD | NEW |