Merge lp:~3v1n0/unity/xi2-input-monitor into lp:unity
- xi2-input-monitor
- Merge into trunk
Proposed by
Marco Trevisan (Treviño)
Status: | Merged |
---|---|
Approved by: | Andrea Azzarone |
Approved revision: | no longer in the source branch. |
Merged at revision: | 4182 |
Proposed branch: | lp:~3v1n0/unity/xi2-input-monitor |
Merge into: | lp:unity |
Diff against target: |
610 lines (+494/-2) 11 files modified
launcher/EdgeBarrierController.cpp (+1/-1) launcher/EdgeBarrierControllerPrivate.h (+1/-1) plugins/unityshell/src/unityshell.h (+2/-0) unity-shared/CMakeLists.txt (+1/-0) unity-shared/InputMonitor.cpp (+386/-0) unity-shared/InputMonitor.h (+91/-0) unity-shared/StandaloneWindowManager.cpp (+3/-0) unity-shared/StandaloneWindowManager.h (+1/-0) unity-shared/WindowManager.h (+1/-0) unity-shared/XWindowManager.cpp (+6/-0) unity-shared/XWindowManager.h (+1/-0) |
To merge this branch: | bzr merge lp:~3v1n0/unity/xi2-input-monitor |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andrea Azzarone (community) | Approve | ||
Review via email: mp+303122@code.launchpad.net |
Commit message
InputMonitor: add an unity class that monitors XInput2 events and converts them to XEvent
Clients of this class can register event handlers, and when an interested event will hit
our event filter function (that is set only if we have handlers), then we notify them
with a standard XEvent struct, converted from the XIDeviceEvent cookie.
The nice thing of this monitor is that it always reports events, despite the X grabs.
Description of the change
To post a comment you must log in.
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote : | # |
Done thanks...
I think I added that thinking of future abstractions, but this won't be the case.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'launcher/EdgeBarrierController.cpp' |
2 | --- launcher/EdgeBarrierController.cpp 2015-12-23 09:29:24 +0000 |
3 | +++ launcher/EdgeBarrierController.cpp 2016-08-22 10:28:22 +0000 |
4 | @@ -295,7 +295,7 @@ |
5 | nux::GetGraphicsDisplay()->AddEventFilter(event_filter); |
6 | } |
7 | |
8 | -bool EdgeBarrierController::Impl::HandleEvent(XEvent xevent) |
9 | +bool EdgeBarrierController::Impl::HandleEvent(XEvent& xevent) |
10 | { |
11 | Display *dpy = nux::GetGraphicsDisplay()->GetX11Display(); |
12 | XGenericEventCookie *cookie = &xevent.xcookie; |
13 | |
14 | === modified file 'launcher/EdgeBarrierControllerPrivate.h' |
15 | --- launcher/EdgeBarrierControllerPrivate.h 2015-12-23 09:29:24 +0000 |
16 | +++ launcher/EdgeBarrierControllerPrivate.h 2016-08-22 10:28:22 +0000 |
17 | @@ -58,7 +58,7 @@ |
18 | PointerBarrierWrapper::Ptr FindBarrierEventOwner(XIBarrierEvent* barrier_event); |
19 | |
20 | static bool HandleEventCB(XEvent event, void* data); |
21 | - bool HandleEvent(XEvent event); |
22 | + bool HandleEvent(XEvent& event); |
23 | |
24 | std::vector<PointerBarrierWrapper::Ptr> vertical_barriers_; |
25 | std::vector<PointerBarrierWrapper::Ptr> horizontal_barriers_; |
26 | |
27 | === modified file 'plugins/unityshell/src/unityshell.h' |
28 | --- plugins/unityshell/src/unityshell.h 2016-08-12 11:21:48 +0000 |
29 | +++ plugins/unityshell/src/unityshell.h 2016-08-22 10:28:22 +0000 |
30 | @@ -56,6 +56,7 @@ |
31 | #include "DashStyle.h" |
32 | #include "EdgeBarrierController.h" |
33 | #include "FavoriteStoreGSettings.h" |
34 | +#include "InputMonitor.h" |
35 | #include "ShortcutController.h" |
36 | #include "LauncherController.h" |
37 | #include "LockScreenController.h" |
38 | @@ -317,6 +318,7 @@ |
39 | internal::FavoriteStoreGSettings favorite_store_; |
40 | ThumbnailGenerator thumbnail_generator_; |
41 | lockscreen::Settings lockscreen_settings_; |
42 | + input::Monitor input_monitor_; |
43 | |
44 | /* The window thread should be the last thing removed, as c++ does it in reverse order */ |
45 | std::unique_ptr<nux::WindowThread> wt; |
46 | |
47 | === modified file 'unity-shared/CMakeLists.txt' |
48 | --- unity-shared/CMakeLists.txt 2016-08-12 11:21:48 +0000 |
49 | +++ unity-shared/CMakeLists.txt 2016-08-22 10:28:22 +0000 |
50 | @@ -82,6 +82,7 @@ |
51 | set (UNITY_SHARED_SOURCES |
52 | XKeyboardUtil.cpp |
53 | XWindowManager.cpp |
54 | + InputMonitor.cpp |
55 | ${UNITY_SHARED_SOURCES} |
56 | ) |
57 | else() |
58 | |
59 | === added file 'unity-shared/InputMonitor.cpp' |
60 | --- unity-shared/InputMonitor.cpp 1970-01-01 00:00:00 +0000 |
61 | +++ unity-shared/InputMonitor.cpp 2016-08-22 10:28:22 +0000 |
62 | @@ -0,0 +1,386 @@ |
63 | +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- |
64 | +/* |
65 | + * Copyright (C) 2014 Canonical Ltd |
66 | + * |
67 | + * This program is free software: you can redistribute it and/or modify |
68 | + * it under the terms of the GNU General Public License version 3 as |
69 | + * published by the Free Software Foundation. |
70 | + * |
71 | + * This program is distributed in the hope that it will be useful, |
72 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
73 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
74 | + * GNU General Public License for more details. |
75 | + * |
76 | + * You should have received a copy of the GNU General Public License |
77 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
78 | + * |
79 | + * Authored by: Marco Trevisan <marco.trevisan@canonical.com> |
80 | + */ |
81 | + |
82 | +#include "InputMonitor.h" |
83 | + |
84 | +#include <Nux/Nux.h> |
85 | +#include <NuxCore/Logger.h> |
86 | +#include <X11/extensions/XInput2.h> |
87 | +#include <UnityCore/GLibSource.h> |
88 | +#include <unordered_set> |
89 | +#include <gdk/gdkx.h> |
90 | +#include <glib.h> |
91 | + |
92 | +namespace unity |
93 | +{ |
94 | +namespace input |
95 | +{ |
96 | +namespace |
97 | +{ |
98 | +DECLARE_LOGGER(logger, "unity.input.monitor"); |
99 | + |
100 | +Monitor* instance_ = nullptr; |
101 | + |
102 | +const unsigned XINPUT_MAJOR_VERSION = 2; |
103 | +const unsigned XINPUT_MINOR_VERSION = 3; |
104 | + |
105 | +bool operator&(Events l, Events r) |
106 | +{ |
107 | + typedef std::underlying_type<Events>::type ut; |
108 | + return static_cast<ut>(static_cast<ut>(l) & static_cast<ut>(r)); |
109 | +} |
110 | + |
111 | +template <typename EVENT> |
112 | +void initialize_event_common(EVENT* ev, XIDeviceEvent* xiev) |
113 | +{ |
114 | + ev->serial = xiev->serial; |
115 | + ev->send_event = xiev->send_event; |
116 | + ev->display = xiev->display; |
117 | + ev->window = xiev->event; |
118 | + ev->root = xiev->root; |
119 | + ev->subwindow = xiev->child; |
120 | + ev->time = xiev->time; |
121 | + ev->x = std::round(xiev->event_x); |
122 | + ev->y = std::round(xiev->event_y); |
123 | + ev->x_root = std::round(xiev->root_x); |
124 | + ev->y_root = std::round(xiev->root_y); |
125 | + ev->state = xiev->mods.effective; |
126 | + ev->same_screen = True; |
127 | +} |
128 | + |
129 | +template <typename EVENT_TYPE, typename NATIVE_TYPE> |
130 | +void initialize_event(XEvent* ev, NATIVE_TYPE* xiev); |
131 | + |
132 | +template <> |
133 | +void initialize_event<XButtonEvent>(XEvent* ev, XIDeviceEvent* xiev) |
134 | +{ |
135 | + XButtonEvent* bev = &ev->xbutton; |
136 | + ev->type = (xiev->evtype == XI_ButtonPress) ? ButtonPress : ButtonRelease; |
137 | + initialize_event_common(bev, xiev); |
138 | + bev->button = xiev->detail; |
139 | +} |
140 | + |
141 | +template <> |
142 | +void initialize_event<XKeyEvent>(XEvent* ev, XIDeviceEvent* xiev) |
143 | +{ |
144 | + XKeyEvent* kev = &ev->xkey; |
145 | + ev->type = (xiev->evtype == XI_KeyPress) ? KeyPress : KeyRelease; |
146 | + initialize_event_common(kev, xiev); |
147 | + kev->keycode = xiev->detail; |
148 | +} |
149 | + |
150 | +template <> |
151 | +void initialize_event<XMotionEvent>(XEvent* ev, XIDeviceEvent* xiev) |
152 | +{ |
153 | + XMotionEvent* mev = &ev->xmotion; |
154 | + ev->type = MotionNotify; |
155 | + initialize_event_common(mev, xiev); |
156 | + mev->is_hint = NotifyNormal; |
157 | + |
158 | + for (int i = 0; i < xiev->buttons.mask_len * 8; ++i) |
159 | + { |
160 | + if (XIMaskIsSet(xiev->buttons.mask, i)) |
161 | + { |
162 | + mev->is_hint = NotifyHint; |
163 | + break; |
164 | + } |
165 | + } |
166 | +} |
167 | + |
168 | +template <> |
169 | +void initialize_event<XGenericEventCookie>(XEvent* ev, XIBarrierEvent* xiev) |
170 | +{ |
171 | + XGenericEventCookie* cev = &ev->xcookie; |
172 | + cev->type = GenericEvent; |
173 | + cev->serial = xiev->serial; |
174 | + cev->send_event = xiev->send_event; |
175 | + cev->display = xiev->display; |
176 | + cev->evtype = xiev->evtype; |
177 | + cev->data = xiev; |
178 | +} |
179 | +} |
180 | + |
181 | +struct Monitor::Impl |
182 | +{ |
183 | + Impl() |
184 | + : xi_opcode_(0) |
185 | + , event_filter_set_(false) |
186 | + , invoking_callbacks_(false) |
187 | + { |
188 | + Display *dpy = gdk_x11_get_default_xdisplay(); |
189 | + int event_base, error_base; |
190 | + |
191 | + if (XQueryExtension(dpy, "XInputExtension", &xi_opcode_, &event_base, &error_base)) |
192 | + { |
193 | + int maj = XINPUT_MAJOR_VERSION; |
194 | + int min = XINPUT_MINOR_VERSION; |
195 | + |
196 | + if (XIQueryVersion(dpy, &maj, &min) == BadRequest) |
197 | + { |
198 | + LOG_ERROR(logger) << "Need XInput version "<< maj << "." << min << ", " |
199 | + << "impossible, to setup an InputMonitor"; |
200 | + } |
201 | + } |
202 | + else |
203 | + { |
204 | + LOG_ERROR(logger) << "Missing XInput, impossible to setup an InputMonitor"; |
205 | + } |
206 | + } |
207 | + |
208 | + ~Impl() |
209 | + { |
210 | + if (event_filter_set_) |
211 | + { |
212 | + pointer_callbacks_.clear(); |
213 | + key_callbacks_.clear(); |
214 | + barrier_callbacks_.clear(); |
215 | + UpdateEventMonitor(); |
216 | + } |
217 | + } |
218 | + |
219 | + bool RegisterClient(Events type, EventCallback const& cb) |
220 | + { |
221 | + bool added = false; |
222 | + |
223 | + if (type & Events::POINTER) |
224 | + added = pointer_callbacks_.insert(cb).second || added; |
225 | + |
226 | + if (type & Events::KEYS) |
227 | + added = key_callbacks_.insert(cb).second || added; |
228 | + |
229 | + if (type & Events::BARRIER) |
230 | + added = barrier_callbacks_.insert(cb).second || added; |
231 | + |
232 | + if (added) |
233 | + UpdateEventMonitor(); |
234 | + |
235 | + return added; |
236 | + } |
237 | + |
238 | + bool UnregisterClient(EventCallback const& cb) |
239 | + { |
240 | + if (invoking_callbacks_) |
241 | + { |
242 | + // Delay the event removal if we're currently invoking a callback |
243 | + // not to break the callbacks loop |
244 | + removal_queue_.insert(cb); |
245 | + return false; |
246 | + } |
247 | + |
248 | + bool removed = false; |
249 | + removed = pointer_callbacks_.erase(cb) > 0 || removed; |
250 | + removed = key_callbacks_.erase(cb) > 0 || removed; |
251 | + removed = barrier_callbacks_.erase(cb) > 0 || removed; |
252 | + |
253 | + if (removed) |
254 | + UpdateEventMonitor(); |
255 | + |
256 | + return removed; |
257 | + } |
258 | + |
259 | + void UpdateEventMonitor() |
260 | + { |
261 | + auto* dpy = nux::GetGraphicsDisplay()->GetX11Display(); |
262 | + Window root = DefaultRootWindow(dpy); |
263 | + |
264 | + unsigned char master_dev_bits[XIMaskLen(XI_LASTEVENT)] = { 0 }; |
265 | + XIEventMask master_dev = { XIAllMasterDevices, sizeof(master_dev_bits), master_dev_bits }; |
266 | + |
267 | + if (!barrier_callbacks_.empty()) |
268 | + { |
269 | + XISetMask(master_dev.mask, XI_BarrierHit); |
270 | + XISetMask(master_dev.mask, XI_BarrierLeave); |
271 | + } |
272 | + |
273 | + unsigned char all_devs_bits[XIMaskLen(XI_LASTEVENT)] = { 0 }; |
274 | + XIEventMask all_devs = { XIAllDevices, sizeof(all_devs_bits), all_devs_bits }; |
275 | + |
276 | + if (!pointer_callbacks_.empty()) |
277 | + { |
278 | + XISetMask(all_devs.mask, XI_Motion); |
279 | + XISetMask(all_devs.mask, XI_ButtonPress); |
280 | + XISetMask(all_devs.mask, XI_ButtonRelease); |
281 | + } |
282 | + |
283 | + if (!key_callbacks_.empty()) |
284 | + { |
285 | + XISetMask(all_devs.mask, XI_KeyPress); |
286 | + XISetMask(all_devs.mask, XI_KeyRelease); |
287 | + } |
288 | + |
289 | + XIEventMask selected[] = {master_dev, all_devs}; |
290 | + XISelectEvents(dpy, root, selected, G_N_ELEMENTS(selected)); |
291 | + XSync(dpy, False); |
292 | + |
293 | + LOG_DEBUG(logger) << "Pointer clients: " << pointer_callbacks_.size() << ", " |
294 | + << "Key clients: " << key_callbacks_.size() << ", " |
295 | + << "Barrier clients: " << barrier_callbacks_.size(); |
296 | + |
297 | + if (!pointer_callbacks_.empty() || !key_callbacks_.empty() || !barrier_callbacks_.empty()) |
298 | + { |
299 | + if (!event_filter_set_) |
300 | + { |
301 | + nux::GetGraphicsDisplay()->AddEventFilter({[] (XEvent event, void* data) { |
302 | + return static_cast<Impl*>(data)->HandleEvent(event); |
303 | + }, this}); |
304 | + |
305 | + event_filter_set_ = true; |
306 | + LOG_DEBUG(logger) << "Event filter enabled"; |
307 | + } |
308 | + } |
309 | + else if (event_filter_set_) |
310 | + { |
311 | + nux::GetGraphicsDisplay()->RemoveEventFilter(this); |
312 | + event_filter_set_ = false; |
313 | + LOG_DEBUG(logger) << "Event filter disabled"; |
314 | + } |
315 | + } |
316 | + |
317 | + bool HandleEvent(XEvent& event) |
318 | + { |
319 | + bool handled = false; |
320 | + |
321 | + if (event.type != GenericEvent || event.xcookie.extension != xi_opcode_) |
322 | + return handled; |
323 | + |
324 | + switch (event.xcookie.evtype) |
325 | + { |
326 | + case XI_ButtonPress: |
327 | + case XI_ButtonRelease: |
328 | + handled = InvokeCallbacks<XButtonEvent>(pointer_callbacks_, event); |
329 | + break; |
330 | + case XI_Motion: |
331 | + handled = InvokeCallbacks<XMotionEvent>(pointer_callbacks_, event); |
332 | + break; |
333 | + case XI_KeyPress: |
334 | + case XI_KeyRelease: |
335 | + handled = InvokeCallbacks<XKeyEvent>(key_callbacks_, event); |
336 | + break; |
337 | + case XI_BarrierHit: |
338 | + case XI_BarrierLeave: |
339 | + handled = InvokeCallbacks<XGenericEventCookie, XIBarrierEvent>(barrier_callbacks_, event); |
340 | + break; |
341 | + } |
342 | + |
343 | + return handled; |
344 | + } |
345 | + |
346 | + template <typename EVENT_TYPE, typename NATIVE_TYPE = XIDeviceEvent> |
347 | + bool InvokeCallbacks(std::unordered_set<EventCallback>& callbacks, XEvent& xiev) |
348 | + { |
349 | + XGenericEventCookie *cookie = &xiev.xcookie; |
350 | + |
351 | + if (!XGetEventData(xiev.xany.display, cookie)) |
352 | + return false; |
353 | + |
354 | + XEvent event; |
355 | + initialize_event<EVENT_TYPE>(&event, reinterpret_cast<NATIVE_TYPE*>(cookie->data)); |
356 | + invoking_callbacks_ = true; |
357 | + |
358 | + for (auto it = callbacks.begin(); it != callbacks.end();) |
359 | + { |
360 | + if (it->empty()) |
361 | + { |
362 | + it = callbacks.erase(it); |
363 | + continue; |
364 | + } |
365 | + |
366 | + (*it)(event); |
367 | + ++it; |
368 | + } |
369 | + |
370 | + XFreeEventData(xiev.xany.display, cookie); |
371 | + invoking_callbacks_ = false; |
372 | + |
373 | + // A callback might unregister itself on the event callback, causing the |
374 | + // above callbacks loop to crash, so in this case we save the event in the |
375 | + // removal queue and eventually we unregistered these callbacks. |
376 | + bool update_event_monitor = false; |
377 | + for (auto it = removal_queue_.begin(); it != removal_queue_.end(); it = removal_queue_.erase(it)) |
378 | + { |
379 | + auto const& cb = *it; |
380 | + pointer_callbacks_.erase(cb); |
381 | + key_callbacks_.erase(cb); |
382 | + barrier_callbacks_.erase(cb); |
383 | + update_event_monitor = true; |
384 | + } |
385 | + |
386 | + if (callbacks.empty() || update_event_monitor) |
387 | + { |
388 | + idle_removal_.reset(new glib::Idle([this] { |
389 | + UpdateEventMonitor(); |
390 | + return false; |
391 | + })); |
392 | + |
393 | + return false; |
394 | + } |
395 | + |
396 | + return true; |
397 | + } |
398 | + |
399 | + int xi_opcode_; |
400 | + bool event_filter_set_; |
401 | + bool invoking_callbacks_; |
402 | + glib::Source::UniquePtr idle_removal_; |
403 | + std::unordered_set<EventCallback> pointer_callbacks_; |
404 | + std::unordered_set<EventCallback> key_callbacks_; |
405 | + std::unordered_set<EventCallback> barrier_callbacks_; |
406 | + std::unordered_set<EventCallback> removal_queue_; |
407 | +}; |
408 | + |
409 | +Monitor::Monitor() |
410 | +{ |
411 | + if (instance_) |
412 | + { |
413 | + LOG_WARN(logger) << "More than one input::Monitor created."; |
414 | + return; |
415 | + } |
416 | + |
417 | + instance_ = this; |
418 | + impl_.reset(new Impl()); |
419 | +} |
420 | + |
421 | +Monitor::~Monitor() |
422 | +{ |
423 | + if (this == instance_) |
424 | + instance_ = nullptr; |
425 | +} |
426 | + |
427 | +Monitor& Monitor::Get() |
428 | +{ |
429 | + if (!instance_) |
430 | + { |
431 | + LOG_ERROR(logger) << "No input::Monitor created yet."; |
432 | + } |
433 | + |
434 | + return *instance_; |
435 | +} |
436 | + |
437 | +bool Monitor::RegisterClient(Events events, EventCallback const& cb) |
438 | +{ |
439 | + return impl_->RegisterClient(events, cb); |
440 | +} |
441 | + |
442 | +bool Monitor::UnregisterClient(EventCallback const& cb) |
443 | +{ |
444 | + return impl_->UnregisterClient(cb); |
445 | +} |
446 | + |
447 | +} // input namespace |
448 | +} // unity namespace |
449 | |
450 | === added file 'unity-shared/InputMonitor.h' |
451 | --- unity-shared/InputMonitor.h 1970-01-01 00:00:00 +0000 |
452 | +++ unity-shared/InputMonitor.h 2016-08-22 10:28:22 +0000 |
453 | @@ -0,0 +1,91 @@ |
454 | +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- |
455 | +/* |
456 | + * Copyright (C) 2014 Canonical Ltd |
457 | + * |
458 | + * This program is free software: you can redistribute it and/or modify |
459 | + * it under the terms of the GNU General Public License version 3 as |
460 | + * published by the Free Software Foundation. |
461 | + * |
462 | + * This program is distributed in the hope that it will be useful, |
463 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
464 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
465 | + * GNU General Public License for more details. |
466 | + * |
467 | + * You should have received a copy of the GNU General Public License |
468 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
469 | + * |
470 | + * Authored by: Marco Trevisan <marco.trevisan@canonical.com> |
471 | + */ |
472 | + |
473 | +#ifndef __UNITY_INPUT_MONITOR__ |
474 | +#define __UNITY_INPUT_MONITOR__ |
475 | + |
476 | +#include <X11/Xlib.h> |
477 | +#include <sigc++/slot.h> |
478 | +#include <memory> |
479 | + |
480 | +namespace unity |
481 | +{ |
482 | +namespace input |
483 | +{ |
484 | +enum class Events : unsigned |
485 | +{ |
486 | + POINTER = (1 << 0), |
487 | + KEYS = (1 << 1), |
488 | + BARRIER = (1 << 2), |
489 | + INPUT = POINTER | KEYS, |
490 | + ALL = POINTER | KEYS | BARRIER |
491 | +}; |
492 | + |
493 | +class Monitor : public sigc::trackable |
494 | +{ |
495 | +public: |
496 | + typedef sigc::slot<void, XEvent const&> EventCallback; |
497 | + |
498 | + static Monitor& Get(); |
499 | + |
500 | + Monitor(); |
501 | + ~Monitor(); |
502 | + |
503 | + bool RegisterClient(Events, EventCallback const&); |
504 | + bool UnregisterClient(EventCallback const&); |
505 | + |
506 | +private: |
507 | + Monitor(Monitor const&) = delete; |
508 | + Monitor& operator=(Monitor const&) = delete; |
509 | + |
510 | + struct Impl; |
511 | + std::unique_ptr<Impl> impl_; |
512 | +}; |
513 | + |
514 | +} // input namespace |
515 | +} // unity namespace |
516 | + |
517 | +namespace std |
518 | +{ |
519 | +template<> |
520 | +struct hash<unity::input::Monitor::EventCallback> |
521 | +{ |
522 | + size_t operator()(unity::input::Monitor::EventCallback const& cb) const |
523 | + { |
524 | + if (cb.rep_) |
525 | + return std::hash<size_t>()(reinterpret_cast<size_t>(cb.rep_->call_)); |
526 | + |
527 | + return std::hash<size_t>()(reinterpret_cast<size_t>(cb.rep_)); |
528 | + } |
529 | +}; |
530 | + |
531 | +template<> |
532 | +struct equal_to<unity::input::Monitor::EventCallback> |
533 | +{ |
534 | + bool operator()(unity::input::Monitor::EventCallback const& lhs, unity::input::Monitor::EventCallback const& rhs) const |
535 | + { |
536 | + if (!lhs.rep_ || !rhs.rep_) |
537 | + return (lhs.rep_ == rhs.rep_); |
538 | + |
539 | + return (lhs.rep_->call_ == rhs.rep_->call_); |
540 | + } |
541 | +}; |
542 | +} // std namespace |
543 | + |
544 | +#endif // __UNITY_INPUT_MONITOR__ |
545 | |
546 | === modified file 'unity-shared/StandaloneWindowManager.cpp' |
547 | --- unity-shared/StandaloneWindowManager.cpp 2015-11-20 11:33:38 +0000 |
548 | +++ unity-shared/StandaloneWindowManager.cpp 2016-08-22 10:28:22 +0000 |
549 | @@ -624,6 +624,9 @@ |
550 | return std::string(); |
551 | } |
552 | |
553 | +void StandaloneWindowManager::SetCardinalProperty(Window, Atom, std::vector<long> const&) |
554 | +{} |
555 | + |
556 | std::vector<long> StandaloneWindowManager::GetCardinalProperty(Window, Atom) const |
557 | { |
558 | return std::vector<long>(); |
559 | |
560 | === modified file 'unity-shared/StandaloneWindowManager.h' |
561 | --- unity-shared/StandaloneWindowManager.h 2016-03-18 18:58:26 +0000 |
562 | +++ unity-shared/StandaloneWindowManager.h 2016-08-22 10:28:22 +0000 |
563 | @@ -165,6 +165,7 @@ |
564 | virtual std::string GetWindowName(Window window_id) const; |
565 | virtual bool IsOnscreenKeyboard(Window window_id) const; |
566 | virtual std::string GetStringProperty(Window window_id, Atom) const; |
567 | + virtual void SetCardinalProperty(Window window_id, Atom, std::vector<long> const&); |
568 | virtual std::vector<long> GetCardinalProperty(Window window_id, Atom) const; |
569 | |
570 | // Mock functions |
571 | |
572 | === modified file 'unity-shared/WindowManager.h' |
573 | --- unity-shared/WindowManager.h 2016-03-18 18:58:26 +0000 |
574 | +++ unity-shared/WindowManager.h 2016-08-22 10:28:22 +0000 |
575 | @@ -170,6 +170,7 @@ |
576 | virtual bool IsOnscreenKeyboard(Window window_id) const = 0; |
577 | |
578 | virtual std::string GetStringProperty(Window, Atom) const = 0; |
579 | + virtual void SetCardinalProperty(Window, Atom, std::vector<long> const&) = 0; |
580 | virtual std::vector<long> GetCardinalProperty(Window, Atom) const = 0; |
581 | |
582 | virtual Cursor GetCachedCursor(unsigned int cursor_name) const = 0; |
583 | |
584 | === modified file 'unity-shared/XWindowManager.cpp' |
585 | --- unity-shared/XWindowManager.cpp 2015-01-21 15:28:59 +0000 |
586 | +++ unity-shared/XWindowManager.cpp 2016-08-22 10:28:22 +0000 |
587 | @@ -123,6 +123,12 @@ |
588 | return std::string(val, n_items); |
589 | } |
590 | |
591 | +void XWindowManager::SetCardinalProperty(Window window_id, Atom atom, std::vector<long> const& values) |
592 | +{ |
593 | + XChangeProperty(screen->dpy(), window_id, atom, XA_CARDINAL, 32, PropModeReplace, |
594 | + (unsigned char *) values.data(), values.size()); |
595 | +} |
596 | + |
597 | std::vector<long> XWindowManager::GetCardinalProperty(Window window_id, Atom atom) const |
598 | { |
599 | Atom type; |
600 | |
601 | === modified file 'unity-shared/XWindowManager.h' |
602 | --- unity-shared/XWindowManager.h 2015-01-21 15:28:59 +0000 |
603 | +++ unity-shared/XWindowManager.h 2016-08-22 10:28:22 +0000 |
604 | @@ -36,6 +36,7 @@ |
605 | std::string GetWindowName(Window window_id) const; |
606 | bool IsOnscreenKeyboard(Window window_id) const; |
607 | std::string GetStringProperty(Window window_id, Atom atom) const; |
608 | + void SetCardinalProperty(Window, Atom, std::vector<long> const&); |
609 | std::vector<long> GetCardinalProperty(Window, Atom) const; |
610 | }; |
611 |
Nice! I think the class Monitor has no need to have a virtual dtor. So please make it non-virtual.