Compare commits

...

5 Commits

Author SHA1 Message Date
Carlos Garnacho
08f4e5f091 x11: Set GdkDeviceTool on motion/button events
The last known tool from the device is used here. If no tool is known,
the event will just have a NULL pointer there.
2015-01-06 15:43:32 +01:00
Carlos Garnacho
8999ce720a x11: Update GdkDevices on "Wacom Serial IDs" property changes
This takes care of the emission of GdkDevice::tool-changed, plus the
updating of the internal device accounting.
2015-01-06 15:43:32 +01:00
Carlos Garnacho
3666cd4cef events: Add gdk_event_[gs]et_device_tool()
This getter/setter will manage the tool pointer in GdkEventPrivate. The
setter should be most notably used by backends.
2015-01-06 15:43:32 +01:00
Carlos Garnacho
a34d9203ee gdkdevice: Add GdkDevice::tool-changed signal
On the devices and backends that support it, this signal will be emitted
on slave/floating devices whenever the tool they are interacting with
changes. These notifications may also work as a sort of proximity events,
as the tool will be unset when the pen moves too far.

For backends, gdk_device_update_tool() has been included, all that should
be done on their side is just calling this whenever any tool might have
changed.
2015-01-06 15:43:32 +01:00
Carlos Garnacho
6315284d6f gdkdevice: Add GdkDeviceTool to identify device tools
GdkDeviceTool is an opaque typedef that can be used to identify a given
tool (eg. pens on tablets) during the app/device lifetime. Tools are only
set on non-master devices, and are owned by these.

The accounting functions are made private, the only public call on
GdkDeviceTool so far is gdk_device_tool_get_serial(), useful to identify
the tool across runs.
2015-01-06 15:38:43 +01:00
8 changed files with 275 additions and 0 deletions

View File

@@ -747,6 +747,9 @@ gdk_device_list_axes
gdk_device_get_axis_value
gdk_device_get_last_event_window
<SUBSECTION>
gdk_device_tool_get_serial
<SUBSECTION Standard>
GDK_TYPE_AXIS_USE
GDK_TYPE_EXTENSION_MODE
@@ -846,6 +849,8 @@ gdk_event_get_device
gdk_event_set_device
gdk_event_get_source_device
gdk_event_set_source_device
gdk_event_get_device_tool
gdk_event_set_device_tool
<SUBSECTION>
gdk_setting_get

View File

@@ -43,6 +43,11 @@
typedef struct _GdkAxisInfo GdkAxisInfo;
struct _GdkDeviceTool
{
guint serial;
};
struct _GdkAxisInfo
{
GdkAtom label;
@@ -57,6 +62,7 @@ struct _GdkAxisInfo
enum {
CHANGED,
TOOL_CHANGED,
LAST_SIGNAL
};
@@ -256,6 +262,14 @@ gdk_device_class_init (GdkDeviceClass *klass)
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[TOOL_CHANGED] =
g_signal_new (g_intern_static_string ("tool-changed"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__BOXED,
G_TYPE_NONE, 1, GDK_TYPE_DEVICE_TOOL);
}
static void
@@ -287,6 +301,12 @@ gdk_device_dispose (GObject *object)
device->axes = NULL;
}
if (device->tools)
{
g_ptr_array_free (device->tools, TRUE);
device->tools = NULL;
}
g_free (device->name);
g_free (device->keys);
@@ -1757,3 +1777,101 @@ gdk_device_get_last_event_window (GdkDevice *device)
return info->window_under_pointer;
}
static GdkDeviceTool *
gdk_device_tool_copy (GdkDeviceTool *tool)
{
return tool;
}
static void
gdk_device_tool_free (GdkDeviceTool *tool)
{
/* Nothing to free here, memory is owned by GdkDevice */
}
G_DEFINE_BOXED_TYPE (GdkDeviceTool, gdk_device_tool,
gdk_device_tool_copy, gdk_device_tool_free);
GdkDeviceTool *
gdk_device_tool_new (guint serial)
{
GdkDeviceTool *tool;
tool = g_new0 (GdkDeviceTool, 1);
tool->serial = serial;
return tool;
}
void
gdk_device_add_tool (GdkDevice *device,
GdkDeviceTool *tool)
{
g_return_if_fail (GDK_IS_DEVICE (device));
g_return_if_fail (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER);
g_return_if_fail (tool != NULL);
if (!device->tools)
device->tools = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
g_ptr_array_add (device->tools, tool);
}
GdkDeviceTool *
gdk_device_lookup_tool (GdkDevice *device,
guint serial)
{
GdkDeviceTool *tool;
guint i;
g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
g_return_val_if_fail (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER, NULL);
if (!device->tools)
return NULL;
for (i = 0; i < device->tools->len; i++)
{
tool = g_ptr_array_index (device->tools, i);
if (tool->serial == serial)
return tool;
}
return NULL;
}
void
gdk_device_update_tool (GdkDevice *device,
GdkDeviceTool *tool)
{
g_return_if_fail (GDK_IS_DEVICE (device));
g_return_if_fail (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER);
g_return_if_fail (!tool || gdk_device_lookup_tool (device, gdk_device_tool_get_serial (tool)) != NULL);
if (device->last_tool == tool)
return;
device->last_tool = tool;
g_signal_emit (device, signals[TOOL_CHANGED], 0, tool);
}
/**
* gdk_device_tool_get_serial:
* @tool: a #GdkDeviceTool
*
* Gets the serial of this tool, this value can be used to identify a
* physical tool (eg. a tablet pen) across program executions.
*
* Returns: The serial ID for this tool
*
* Since: 3.16
**/
guint
gdk_device_tool_get_serial (GdkDeviceTool *tool)
{
g_return_val_if_fail (tool != NULL, 0);
return tool->serial;
}

View File

@@ -32,7 +32,10 @@ G_BEGIN_DECLS
#define GDK_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE, GdkDevice))
#define GDK_IS_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE))
#define GDK_TYPE_DEVICE_TOOL (gdk_device_tool_get_type ())
typedef struct _GdkTimeCoord GdkTimeCoord;
typedef struct _GdkDeviceTool GdkDeviceTool;
/**
* GdkInputSource:
@@ -274,6 +277,12 @@ gboolean gdk_device_grab_info_libgtk_only (GdkDisplay *display,
GDK_AVAILABLE_IN_3_12
GdkWindow *gdk_device_get_last_event_window (GdkDevice *device);
GDK_AVAILABLE_IN_3_16
GType gdk_device_tool_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_16
guint gdk_device_tool_get_serial (GdkDeviceTool *tool);
G_END_DECLS
#endif /* __GDK_DEVICE_H__ */

View File

@@ -56,6 +56,9 @@ struct _GdkDevice
GList *slaves;
GdkDeviceType type;
GArray *axes;
GPtrArray *tools;
GdkDeviceTool *last_tool;
};
struct _GdkDeviceClass
@@ -173,6 +176,15 @@ GdkWindow * _gdk_device_window_at_position (GdkDevice *device,
GdkModifierType *mask,
gboolean get_toplevel);
/* Device tools */
GdkDeviceTool *gdk_device_tool_new (guint serial);
GdkDeviceTool *gdk_device_lookup_tool (GdkDevice *device,
guint serial);
void gdk_device_add_tool (GdkDevice *device,
GdkDeviceTool *tool);
void gdk_device_update_tool (GdkDevice *device,
GdkDeviceTool *tool);
G_END_DECLS
#endif /* __GDK_DEVICE_PRIVATE_H__ */

View File

@@ -642,6 +642,7 @@ gdk_event_copy (const GdkEvent *event)
new_private->screen = private->screen;
new_private->device = private->device;
new_private->source_device = private->source_device;
new_private->tool = private->tool;
}
switch (event->any.type)
@@ -2262,3 +2263,54 @@ gdk_event_get_event_type (const GdkEvent *event)
return event->type;
}
/**
* gdk_event_get_device_tool:
* @event: a #GdkEvent
*
* If the event was generated by a device that supports
* different tools (eg. a tablet), this function will
* return a #GdkDeviceTool representing the tool that
* caused the event. Otherwise, %NULL will be returned.
*
* Note: the #GdkDeviceTool<!-- -->s will be constant during
* the application lifetime, if settings must be stored
* persistently across runs, see gdk_device_tool_get_serial()
*
* Returns: The current device tool, or %NULL
*
* Since: 3.16
**/
GdkDeviceTool *
gdk_event_get_device_tool (const GdkEvent *event)
{
GdkEventPrivate *private;
if (!gdk_event_is_allocated (event))
return NULL;
private = (GdkEventPrivate *) event;
return private->tool;
}
/**
* gdk_event_set_device_tool:
* @event: a #GdkEvent
* @tool: (nullable): tool to set on the event, or %NULL
*
* Sets the device tool for this event, should be rarely used.
*
* Since: 3.16
**/
void
gdk_event_set_device_tool (GdkEvent *event,
GdkDeviceTool *tool)
{
GdkEventPrivate *private;
if (!gdk_event_is_allocated (event))
return;
private = (GdkEventPrivate *) event;
private->tool = tool;
}

View File

@@ -1309,6 +1309,13 @@ GDK_AVAILABLE_IN_ALL
gboolean gdk_setting_get (const gchar *name,
GValue *value);
GDK_AVAILABLE_IN_3_16
GdkDeviceTool *gdk_event_get_device_tool (const GdkEvent *event);
GDK_AVAILABLE_IN_3_16
void gdk_event_set_device_tool (GdkEvent *event,
GdkDeviceTool *tool);
G_END_DECLS
#endif /* __GDK_EVENTS_H__ */

View File

@@ -184,6 +184,7 @@ struct _GdkEventPrivate
gpointer windowing_data;
GdkDevice *device;
GdkDevice *source_device;
GdkDeviceTool *tool;
};
typedef struct _GdkWindowPaint GdkWindowPaint;

View File

@@ -32,6 +32,7 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XInput2.h>
#include <X11/Xatom.h>
#include <string.h>
@@ -543,6 +544,7 @@ gdk_x11_device_manager_xi2_constructed (GObject *object)
screen = gdk_display_get_default_screen (display);
XISetMask (mask, XI_HierarchyChanged);
XISetMask (mask, XI_DeviceChanged);
XISetMask (mask, XI_PropertyEvent);
event_mask.deviceid = XIAllDevices;
event_mask.mask_len = sizeof (mask);
@@ -775,6 +777,68 @@ handle_device_changed (GdkX11DeviceManagerXI2 *device_manager,
_gdk_device_xi2_reset_scroll_valuators (GDK_X11_DEVICE_XI2 (source_device));
}
static guint
device_get_tool_serial (GdkDevice *device)
{
GdkDisplay *display;
gulong nitems, bytes_after;
guint serial_id = 0;
guint32 *data;
int rc, format;
Atom type;
display = gdk_device_get_display (device);
gdk_x11_display_error_trap_push (display);
rc = XIGetProperty (GDK_DISPLAY_XDISPLAY (display),
gdk_x11_device_get_id (device),
gdk_x11_get_xatom_by_name_for_display (display, "Wacom Serial IDs"),
0, 4, False, XA_INTEGER, &type, &format, &nitems, &bytes_after,
(guchar **) &data);
gdk_x11_display_error_trap_pop_ignored (display);
if (rc != Success)
return 0;
if (type == XA_INTEGER && format == 32 && nitems >= 4)
serial_id = data[3];
XFree (data);
return serial_id;
}
static void
handle_property_change (GdkX11DeviceManagerXI2 *device_manager,
XIPropertyEvent *ev)
{
GdkDevice *device;
device = g_hash_table_lookup (device_manager->id_table,
GUINT_TO_POINTER (ev->deviceid));
if (ev->property == gdk_x11_get_xatom_by_name ("Wacom Serial IDs"))
{
GdkDeviceTool *tool = NULL;
guint serial_id;
if (ev->what != XIPropertyDeleted)
{
serial_id = device_get_tool_serial (device);
tool = gdk_device_lookup_tool (device, serial_id);
if (!tool && serial_id > 0)
{
tool = gdk_device_tool_new (serial_id);
gdk_device_add_tool (device, tool);
}
}
gdk_device_update_tool (device, tool);
}
}
static GdkCrossingMode
translate_crossing_mode (gint mode)
{
@@ -1169,6 +1233,11 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
(XIDeviceChangedEvent *) ev);
return_val = FALSE;
break;
case XI_PropertyEvent:
handle_property_change (device_manager,
(XIPropertyEvent *) ev);
return_val = FALSE;
break;
case XI_KeyPress:
case XI_KeyRelease:
{
@@ -1308,6 +1377,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
source_device = g_hash_table_lookup (device_manager->id_table,
GUINT_TO_POINTER (xev->sourceid));
gdk_event_set_source_device (event, source_device);
gdk_event_set_device_tool (event, source_device->last_tool);
event->button.axes = translate_axes (event->button.device,
event->button.x,
@@ -1412,6 +1482,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
event->motion.device = device;
gdk_event_set_source_device (event, source_device);
gdk_event_set_device_tool (event, source_device->last_tool);
event->motion.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);