+/**
+ * gdk_event_set_device:
+ * @event: a #GdkEvent
+ * @device: a #GdkDevice
+ *
+ * Sets the device for @event to @device. The event must
+ * have been allocated by GTK+, for instance, by
+ * gdk_event_copy().
+ *
+ * Since: 3.0
+ **/
+void
+gdk_event_set_device (GdkEvent *event,
+ GdkDevice *device)
+{
+ GdkEventPrivate *private;
+
+ g_return_if_fail (gdk_event_is_allocated (event));
+
+ private = (GdkEventPrivate *) event;
+
+ private->device = device;
+
+ switch (event->type)
+ {
+ case GDK_MOTION_NOTIFY:
+ event->motion.device = device;
+ break;
+ case GDK_BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ event->button.device = device;
+ break;
+ case GDK_SCROLL:
+ event->scroll.device = device;
+ break;
+ case GDK_PROXIMITY_IN:
+ case GDK_PROXIMITY_OUT:
+ event->proximity.device = device;
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * gdk_event_get_device:
+ * @event: a #GdkEvent.
+ *
+ * If the event contains a "device" field, this function will return
+ * it, else it will return %NULL.
+ *
+ * Returns: (transfer none): a #GdkDevice, or %NULL.
+ *
+ * Since: 3.0
+ **/
+GdkDevice *
+gdk_event_get_device (const GdkEvent *event)
+{
+ g_return_val_if_fail (event != NULL, NULL);
+
+ if (gdk_event_is_allocated (event))
+ {
+ GdkEventPrivate *private = (GdkEventPrivate *) event;
+
+ if (private->device)
+ return private->device;
+ }
+
+ switch (event->type)
+ {
+ case GDK_MOTION_NOTIFY:
+ return event->motion.device;
+ case GDK_BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ return event->button.device;
+ case GDK_SCROLL:
+ return event->scroll.device;
+ case GDK_PROXIMITY_IN:
+ case GDK_PROXIMITY_OUT:
+ return event->proximity.device;
+ default:
+ break;
+ }
+
+ /* Fallback if event has no device set */
+ switch (event->type)
+ {
+ case GDK_MOTION_NOTIFY:
+ case GDK_BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ case GDK_ENTER_NOTIFY:
+ case GDK_LEAVE_NOTIFY:
+ case GDK_FOCUS_CHANGE:
+ case GDK_PROXIMITY_IN:
+ case GDK_PROXIMITY_OUT:
+ case GDK_DRAG_ENTER:
+ case GDK_DRAG_LEAVE:
+ case GDK_DRAG_MOTION:
+ case GDK_DRAG_STATUS:
+ case GDK_DROP_START:
+ case GDK_DROP_FINISHED:
+ case GDK_SCROLL:
+ case GDK_GRAB_BROKEN:
+ case GDK_KEY_PRESS:
+ case GDK_KEY_RELEASE:
+ {
+ GdkDisplay *display;
+ GdkDeviceManager *device_manager;
+ GdkDevice *client_pointer;
+
+ g_warning ("Event with type %d not holding a GdkDevice. "
+ "It is most likely synthesized outside Gdk/GTK+\n",
+ event->type);
+
+ display = gdk_window_get_display (event->any.window);
+ device_manager = gdk_display_get_device_manager (display);
+ client_pointer = gdk_device_manager_get_client_pointer (device_manager);
+
+ if (event->type == GDK_KEY_PRESS ||
+ event->type == GDK_KEY_RELEASE)
+ return gdk_device_get_associated_device (client_pointer);
+ else
+ return client_pointer;
+ }
+ break;
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * gdk_event_set_source_device:
+ * @event: a #GdkEvent
+ * @device: a #GdkDevice
+ *
+ * Sets the slave device for @event to @device.
+ *
+ * The event must have been allocated by GTK+,
+ * for instance by gdk_event_copy().
+ *
+ * Since: 3.0
+ **/
+void
+gdk_event_set_source_device (GdkEvent *event,
+ GdkDevice *device)
+{
+ GdkEventPrivate *private;
+
+ g_return_if_fail (gdk_event_is_allocated (event));
+ g_return_if_fail (GDK_IS_DEVICE (device));
+
+ private = (GdkEventPrivate *) event;
+
+ private->source_device = device;
+}
+
+/**
+ * gdk_event_get_source_device:
+ * @event: a #GdkEvent
+ *
+ * This function returns the hardware (slave) #GdkDevice that has
+ * triggered the event, falling back to the virtual (master) device
+ * (as in gdk_event_get_device()) if the event wasn't caused by
+ * interaction with a hardware device. This may happen for example
+ * in synthesized crossing events after a #GdkWindow updates its
+ * geometry or a grab is acquired/released.
+ *
+ * If the event does not contain a device field, this function will
+ * return %NULL.
+ *
+ * Returns: (transfer none): a #GdkDevice, or %NULL.
+ *
+ * Since: 3.0
+ **/
+GdkDevice *
+gdk_event_get_source_device (const GdkEvent *event)
+{
+ GdkEventPrivate *private;
+
+ g_return_val_if_fail (event != NULL, NULL);
+
+ if (!gdk_event_is_allocated (event))
+ return NULL;
+
+ private = (GdkEventPrivate *) event;
+
+ if (private->source_device)
+ return private->source_device;
+
+ /* Fallback to event device */
+ return gdk_event_get_device (event);
+}
+