1 /*
2  * This file is part of gtkD.
3  *
4  * gtkD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 3
7  * of the License, or (at your option) any later version, with
8  * some exceptions, please read the COPYING file.
9  *
10  * gtkD is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with gtkD; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
18  */
19 
20 // generated automatically - do not change
21 // find conversion definition on APILookup.txt
22 // implement new conversion functionalities on the wrap.utils pakage
23 
24 
25 module gdk.DeviceManager;
26 
27 private import gdk.Device;
28 private import gdk.Display;
29 private import glib.ListG;
30 private import gobject.ObjectG;
31 private import gobject.Signals;
32 private import gtkc.gdk;
33 public  import gtkc.gdktypes;
34 private import std.algorithm;
35 
36 
37 /**
38  * In addition to a single pointer and keyboard for user interface input,
39  * GDK contains support for a variety of input devices, including graphics
40  * tablets, touchscreens and multiple pointers/keyboards interacting
41  * simultaneously with the user interface. Such input devices often have
42  * additional features, such as sub-pixel positioning information and
43  * additional device-dependent information.
44  * 
45  * In order to query the device hierarchy and be aware of changes in the
46  * device hierarchy (such as virtual devices being created or removed, or
47  * physical devices being plugged or unplugged), GDK provides
48  * #GdkDeviceManager.
49  * 
50  * By default, and if the platform supports it, GDK is aware of multiple
51  * keyboard/pointer pairs and multitouch devices. This behavior can be
52  * changed by calling gdk_disable_multidevice() before gdk_display_open().
53  * There should rarely be a need to do that though, since GDK defaults
54  * to a compatibility mode in which it will emit just one enter/leave
55  * event pair for all devices on a window. To enable per-device
56  * enter/leave events and other multi-pointer interaction features,
57  * gdk_window_set_support_multidevice() must be called on
58  * #GdkWindows (or gtk_widget_set_support_multidevice() on widgets).
59  * window. See the gdk_window_set_support_multidevice() documentation
60  * for more information.
61  * 
62  * On X11, multi-device support is implemented through XInput 2.
63  * Unless gdk_disable_multidevice() is called, the XInput 2
64  * #GdkDeviceManager implementation will be used as the input source.
65  * Otherwise either the core or XInput 1 implementations will be used.
66  * 
67  * For simple applications that don’t have any special interest in
68  * input devices, the so-called “client pointer”
69  * provides a reasonable approximation to a simple setup with a single
70  * pointer and keyboard. The device that has been set as the client
71  * pointer can be accessed via gdk_device_manager_get_client_pointer().
72  * 
73  * Conceptually, in multidevice mode there are 2 device types. Virtual
74  * devices (or master devices) are represented by the pointer cursors
75  * and keyboard foci that are seen on the screen. Physical devices (or
76  * slave devices) represent the hardware that is controlling the virtual
77  * devices, and thus have no visible cursor on the screen.
78  * 
79  * Virtual devices are always paired, so there is a keyboard device for every
80  * pointer device. Associations between devices may be inspected through
81  * gdk_device_get_associated_device().
82  * 
83  * There may be several virtual devices, and several physical devices could
84  * be controlling each of these virtual devices. Physical devices may also
85  * be “floating”, which means they are not attached to any virtual device.
86  * 
87  * # Master and slave devices
88  * 
89  * |[
90  * carlos@sacarino:~$ xinput list
91  * ⎡ Virtual core pointer                          id=2    [master pointer  (3)]
92  * ⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
93  * ⎜   ↳ Wacom ISDv4 E6 Pen stylus                 id=10   [slave  pointer  (2)]
94  * ⎜   ↳ Wacom ISDv4 E6 Finger touch               id=11   [slave  pointer  (2)]
95  * ⎜   ↳ SynPS/2 Synaptics TouchPad                id=13   [slave  pointer  (2)]
96  * ⎜   ↳ TPPS/2 IBM TrackPoint                     id=14   [slave  pointer  (2)]
97  * ⎜   ↳ Wacom ISDv4 E6 Pen eraser                 id=16   [slave  pointer  (2)]
98  * ⎣ Virtual core keyboard                         id=3    [master keyboard (2)]
99  * ↳ Virtual core XTEST keyboard               id=5    [slave  keyboard (3)]
100  * ↳ Power Button                              id=6    [slave  keyboard (3)]
101  * ↳ Video Bus                                 id=7    [slave  keyboard (3)]
102  * ↳ Sleep Button                              id=8    [slave  keyboard (3)]
103  * ↳ Integrated Camera                         id=9    [slave  keyboard (3)]
104  * ↳ AT Translated Set 2 keyboard              id=12   [slave  keyboard (3)]
105  * ↳ ThinkPad Extra Buttons                    id=15   [slave  keyboard (3)]
106  * ]|
107  * 
108  * By default, GDK will automatically listen for events coming from all
109  * master devices, setting the #GdkDevice for all events coming from input
110  * devices. Events containing device information are #GDK_MOTION_NOTIFY,
111  * #GDK_BUTTON_PRESS, #GDK_2BUTTON_PRESS, #GDK_3BUTTON_PRESS,
112  * #GDK_BUTTON_RELEASE, #GDK_SCROLL, #GDK_KEY_PRESS, #GDK_KEY_RELEASE,
113  * #GDK_ENTER_NOTIFY, #GDK_LEAVE_NOTIFY, #GDK_FOCUS_CHANGE,
114  * #GDK_PROXIMITY_IN, #GDK_PROXIMITY_OUT, #GDK_DRAG_ENTER, #GDK_DRAG_LEAVE,
115  * #GDK_DRAG_MOTION, #GDK_DRAG_STATUS, #GDK_DROP_START, #GDK_DROP_FINISHED
116  * and #GDK_GRAB_BROKEN. When dealing with an event on a master device,
117  * it is possible to get the source (slave) device that the event originated
118  * from via gdk_event_get_source_device().
119  * 
120  * On a standard session, all physical devices are connected by default to
121  * the "Virtual Core Pointer/Keyboard" master devices, hence routing all events
122  * through these. This behavior is only modified by device grabs, where the
123  * slave device is temporarily detached for as long as the grab is held, and
124  * more permanently by user modifications to the device hierarchy.
125  * 
126  * On certain application specific setups, it may make sense
127  * to detach a physical device from its master pointer, and mapping it to
128  * an specific window. This can be achieved by the combination of
129  * gdk_device_grab() and gdk_device_set_mode().
130  * 
131  * In order to listen for events coming from devices
132  * other than a virtual device, gdk_window_set_device_events() must be
133  * called. Generally, this function can be used to modify the event mask
134  * for any given device.
135  * 
136  * Input devices may also provide additional information besides X/Y.
137  * For example, graphics tablets may also provide pressure and X/Y tilt
138  * information. This information is device-dependent, and may be
139  * queried through gdk_device_get_axis(). In multidevice mode, virtual
140  * devices will change axes in order to always represent the physical
141  * device that is routing events through it. Whenever the physical device
142  * changes, the #GdkDevice:n-axes property will be notified, and
143  * gdk_device_list_axes() will return the new device axes.
144  * 
145  * Devices may also have associated “keys” or
146  * macro buttons. Such keys can be globally set to map into normal X
147  * keyboard events. The mapping is set using gdk_device_set_key().
148  * 
149  * In GTK+ 3.20, a new #GdkSeat object has been introduced that
150  * supersedes #GdkDeviceManager and should be preferred in newly
151  * written code.
152  */
153 public class DeviceManager : ObjectG
154 {
155 	/** the main Gtk struct */
156 	protected GdkDeviceManager* gdkDeviceManager;
157 
158 	/** Get the main Gtk struct */
159 	public GdkDeviceManager* getDeviceManagerStruct()
160 	{
161 		return gdkDeviceManager;
162 	}
163 
164 	/** the main Gtk struct as a void* */
165 	protected override void* getStruct()
166 	{
167 		return cast(void*)gdkDeviceManager;
168 	}
169 
170 	protected override void setStruct(GObject* obj)
171 	{
172 		gdkDeviceManager = cast(GdkDeviceManager*)obj;
173 		super.setStruct(obj);
174 	}
175 
176 	/**
177 	 * Sets our main struct and passes it to the parent class.
178 	 */
179 	public this (GdkDeviceManager* gdkDeviceManager, bool ownedRef = false)
180 	{
181 		this.gdkDeviceManager = gdkDeviceManager;
182 		super(cast(GObject*)gdkDeviceManager, ownedRef);
183 	}
184 
185 
186 	/** */
187 	public static GType getType()
188 	{
189 		return gdk_device_manager_get_type();
190 	}
191 
192 	/**
193 	 * Returns the client pointer, that is, the master pointer that acts as the core pointer
194 	 * for this application. In X11, window managers may change this depending on the interaction
195 	 * pattern under the presence of several pointers.
196 	 *
197 	 * You should use this function seldomly, only in code that isn’t triggered by a #GdkEvent
198 	 * and there aren’t other means to get a meaningful #GdkDevice to operate on.
199 	 *
200 	 * Deprecated: Use gdk_seat_get_pointer() instead.
201 	 *
202 	 * Return: The client pointer. This memory is
203 	 *     owned by GDK and must not be freed or unreferenced.
204 	 *
205 	 * Since: 3.0
206 	 */
207 	public Device getClientPointer()
208 	{
209 		auto p = gdk_device_manager_get_client_pointer(gdkDeviceManager);
210 		
211 		if(p is null)
212 		{
213 			return null;
214 		}
215 		
216 		return ObjectG.getDObject!(Device)(cast(GdkDevice*) p);
217 	}
218 
219 	/**
220 	 * Gets the #GdkDisplay associated to @device_manager.
221 	 *
222 	 * Return: the #GdkDisplay to which
223 	 *     @device_manager is associated to, or #NULL. This memory is
224 	 *     owned by GDK and must not be freed or unreferenced.
225 	 *
226 	 * Since: 3.0
227 	 */
228 	public Display getDisplay()
229 	{
230 		auto p = gdk_device_manager_get_display(gdkDeviceManager);
231 		
232 		if(p is null)
233 		{
234 			return null;
235 		}
236 		
237 		return ObjectG.getDObject!(Display)(cast(GdkDisplay*) p);
238 	}
239 
240 	/**
241 	 * Returns the list of devices of type @type currently attached to
242 	 * @device_manager.
243 	 *
244 	 * Deprecated: , use gdk_seat_get_pointer(), gdk_seat_get_keyboard()
245 	 * and gdk_seat_get_slaves() instead.
246 	 *
247 	 * Params:
248 	 *     type = device type to get.
249 	 *
250 	 * Return: a list of
251 	 *     #GdkDevices. The returned list must be
252 	 *     freed with g_list_free (). The list elements are owned by
253 	 *     GTK+ and must not be freed or unreffed.
254 	 *
255 	 * Since: 3.0
256 	 */
257 	public ListG listDevices(GdkDeviceType type)
258 	{
259 		auto p = gdk_device_manager_list_devices(gdkDeviceManager, type);
260 		
261 		if(p is null)
262 		{
263 			return null;
264 		}
265 		
266 		return new ListG(cast(GList*) p);
267 	}
268 
269 	protected class OnDeviceAddedDelegateWrapper
270 	{
271 		void delegate(Device, DeviceManager) dlg;
272 		gulong handlerId;
273 		ConnectFlags flags;
274 		this(void delegate(Device, DeviceManager) dlg, gulong handlerId, ConnectFlags flags)
275 		{
276 			this.dlg = dlg;
277 			this.handlerId = handlerId;
278 			this.flags = flags;
279 		}
280 	}
281 	protected OnDeviceAddedDelegateWrapper[] onDeviceAddedListeners;
282 
283 	/**
284 	 * The ::device-added signal is emitted either when a new master
285 	 * pointer is created, or when a slave (Hardware) input device
286 	 * is plugged in.
287 	 *
288 	 * Params:
289 	 *     device = the newly added #GdkDevice.
290 	 */
291 	gulong addOnDeviceAdded(void delegate(Device, DeviceManager) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
292 	{
293 		onDeviceAddedListeners ~= new OnDeviceAddedDelegateWrapper(dlg, 0, connectFlags);
294 		onDeviceAddedListeners[onDeviceAddedListeners.length - 1].handlerId = Signals.connectData(
295 			this,
296 			"device-added",
297 			cast(GCallback)&callBackDeviceAdded,
298 			cast(void*)onDeviceAddedListeners[onDeviceAddedListeners.length - 1],
299 			cast(GClosureNotify)&callBackDeviceAddedDestroy,
300 			connectFlags);
301 		return onDeviceAddedListeners[onDeviceAddedListeners.length - 1].handlerId;
302 	}
303 	
304 	extern(C) static void callBackDeviceAdded(GdkDeviceManager* devicemanagerStruct, GdkDevice* device,OnDeviceAddedDelegateWrapper wrapper)
305 	{
306 		wrapper.dlg(ObjectG.getDObject!(Device)(device), wrapper.outer);
307 	}
308 	
309 	extern(C) static void callBackDeviceAddedDestroy(OnDeviceAddedDelegateWrapper wrapper, GClosure* closure)
310 	{
311 		wrapper.outer.internalRemoveOnDeviceAdded(wrapper);
312 	}
313 
314 	protected void internalRemoveOnDeviceAdded(OnDeviceAddedDelegateWrapper source)
315 	{
316 		foreach(index, wrapper; onDeviceAddedListeners)
317 		{
318 			if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)
319 			{
320 				onDeviceAddedListeners[index] = null;
321 				onDeviceAddedListeners = std.algorithm.remove(onDeviceAddedListeners, index);
322 				break;
323 			}
324 		}
325 	}
326 	
327 
328 	protected class OnDeviceChangedDelegateWrapper
329 	{
330 		void delegate(Device, DeviceManager) dlg;
331 		gulong handlerId;
332 		ConnectFlags flags;
333 		this(void delegate(Device, DeviceManager) dlg, gulong handlerId, ConnectFlags flags)
334 		{
335 			this.dlg = dlg;
336 			this.handlerId = handlerId;
337 			this.flags = flags;
338 		}
339 	}
340 	protected OnDeviceChangedDelegateWrapper[] onDeviceChangedListeners;
341 
342 	/**
343 	 * The ::device-changed signal is emitted whenever a device
344 	 * has changed in the hierarchy, either slave devices being
345 	 * disconnected from their master device or connected to
346 	 * another one, or master devices being added or removed
347 	 * a slave device.
348 	 *
349 	 * If a slave device is detached from all master devices
350 	 * (gdk_device_get_associated_device() returns %NULL), its
351 	 * #GdkDeviceType will change to %GDK_DEVICE_TYPE_FLOATING,
352 	 * if it's attached, it will change to %GDK_DEVICE_TYPE_SLAVE.
353 	 *
354 	 * Params:
355 	 *     device = the #GdkDevice that changed.
356 	 */
357 	gulong addOnDeviceChanged(void delegate(Device, DeviceManager) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
358 	{
359 		onDeviceChangedListeners ~= new OnDeviceChangedDelegateWrapper(dlg, 0, connectFlags);
360 		onDeviceChangedListeners[onDeviceChangedListeners.length - 1].handlerId = Signals.connectData(
361 			this,
362 			"device-changed",
363 			cast(GCallback)&callBackDeviceChanged,
364 			cast(void*)onDeviceChangedListeners[onDeviceChangedListeners.length - 1],
365 			cast(GClosureNotify)&callBackDeviceChangedDestroy,
366 			connectFlags);
367 		return onDeviceChangedListeners[onDeviceChangedListeners.length - 1].handlerId;
368 	}
369 	
370 	extern(C) static void callBackDeviceChanged(GdkDeviceManager* devicemanagerStruct, GdkDevice* device,OnDeviceChangedDelegateWrapper wrapper)
371 	{
372 		wrapper.dlg(ObjectG.getDObject!(Device)(device), wrapper.outer);
373 	}
374 	
375 	extern(C) static void callBackDeviceChangedDestroy(OnDeviceChangedDelegateWrapper wrapper, GClosure* closure)
376 	{
377 		wrapper.outer.internalRemoveOnDeviceChanged(wrapper);
378 	}
379 
380 	protected void internalRemoveOnDeviceChanged(OnDeviceChangedDelegateWrapper source)
381 	{
382 		foreach(index, wrapper; onDeviceChangedListeners)
383 		{
384 			if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)
385 			{
386 				onDeviceChangedListeners[index] = null;
387 				onDeviceChangedListeners = std.algorithm.remove(onDeviceChangedListeners, index);
388 				break;
389 			}
390 		}
391 	}
392 	
393 
394 	protected class OnDeviceRemovedDelegateWrapper
395 	{
396 		void delegate(Device, DeviceManager) dlg;
397 		gulong handlerId;
398 		ConnectFlags flags;
399 		this(void delegate(Device, DeviceManager) dlg, gulong handlerId, ConnectFlags flags)
400 		{
401 			this.dlg = dlg;
402 			this.handlerId = handlerId;
403 			this.flags = flags;
404 		}
405 	}
406 	protected OnDeviceRemovedDelegateWrapper[] onDeviceRemovedListeners;
407 
408 	/**
409 	 * The ::device-removed signal is emitted either when a master
410 	 * pointer is removed, or when a slave (Hardware) input device
411 	 * is unplugged.
412 	 *
413 	 * Params:
414 	 *     device = the just removed #GdkDevice.
415 	 */
416 	gulong addOnDeviceRemoved(void delegate(Device, DeviceManager) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
417 	{
418 		onDeviceRemovedListeners ~= new OnDeviceRemovedDelegateWrapper(dlg, 0, connectFlags);
419 		onDeviceRemovedListeners[onDeviceRemovedListeners.length - 1].handlerId = Signals.connectData(
420 			this,
421 			"device-removed",
422 			cast(GCallback)&callBackDeviceRemoved,
423 			cast(void*)onDeviceRemovedListeners[onDeviceRemovedListeners.length - 1],
424 			cast(GClosureNotify)&callBackDeviceRemovedDestroy,
425 			connectFlags);
426 		return onDeviceRemovedListeners[onDeviceRemovedListeners.length - 1].handlerId;
427 	}
428 	
429 	extern(C) static void callBackDeviceRemoved(GdkDeviceManager* devicemanagerStruct, GdkDevice* device,OnDeviceRemovedDelegateWrapper wrapper)
430 	{
431 		wrapper.dlg(ObjectG.getDObject!(Device)(device), wrapper.outer);
432 	}
433 	
434 	extern(C) static void callBackDeviceRemovedDestroy(OnDeviceRemovedDelegateWrapper wrapper, GClosure* closure)
435 	{
436 		wrapper.outer.internalRemoveOnDeviceRemoved(wrapper);
437 	}
438 
439 	protected void internalRemoveOnDeviceRemoved(OnDeviceRemovedDelegateWrapper source)
440 	{
441 		foreach(index, wrapper; onDeviceRemovedListeners)
442 		{
443 			if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)
444 			{
445 				onDeviceRemovedListeners[index] = null;
446 				onDeviceRemovedListeners = std.algorithm.remove(onDeviceRemovedListeners, index);
447 				break;
448 			}
449 		}
450 	}
451 	
452 
453 	/**
454 	 * Disables multidevice support in GDK. This call must happen prior
455 	 * to gdk_display_open(), gtk_init(), gtk_init_with_args() or
456 	 * gtk_init_check() in order to take effect.
457 	 *
458 	 * Most common GTK+ applications won’t ever need to call this. Only
459 	 * applications that do mixed GDK/Xlib calls could want to disable
460 	 * multidevice support if such Xlib code deals with input devices in
461 	 * any way and doesn’t observe the presence of XInput 2.
462 	 *
463 	 * Since: 3.0
464 	 */
465 	public static void disableMultidevice()
466 	{
467 		gdk_disable_multidevice();
468 	}
469 }