Merge branch 'issue1549' into 'gtk-3-24'

Handle Wintab cursors that are recognized after GDK app init

See merge request GNOME/gtk!2458
This commit is contained in:
Matthias Clasen
2021-03-05 18:53:42 +00:00

View File

@ -70,6 +70,10 @@ static gboolean default_display_opened = FALSE;
G_DEFINE_TYPE (GdkDeviceManagerWin32, gdk_device_manager_win32, GDK_TYPE_DEVICE_MANAGER)
static GdkDeviceWintab *gdk_device_manager_find_wintab_device (GdkDeviceManagerWin32 *, HCTX, UINT);
UINT _wintab_recognize_new_cursors (GdkDeviceManagerWin32 *, HCTX);
int _gdk_find_wintab_device_index (HCTX);
static GdkDevice *
create_pointer (GdkDeviceManager *device_manager,
GType g_type,
@ -355,18 +359,15 @@ wintab_init_check (GdkDeviceManagerWin32 *device_manager)
GdkDisplay *display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
GdkWindow *root = gdk_screen_get_root_window (gdk_display_get_default_screen (display));
static gboolean wintab_initialized = FALSE;
GdkDeviceWintab *device;
GdkWindowAttr wa;
WORD specversion;
HCTX *hctx;
UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware;
BOOL active;
DWORD physid;
AXIS axis_x, axis_y, axis_npressure, axis_or[3];
UINT devix, cursorix;
int i, num_axes = 0;
wchar_t devname[100], csrname[100];
gchar *devname_utf8, *csrname_utf8, *device_name;
UINT ndevices, ncursors;
UINT devix;
AXIS axis_x, axis_y;
int i;
wchar_t devname[100];
gchar *devname_utf8;
BOOL defcontext_done;
HMODULE wintab32;
char *wintab32_dll_path;
@ -465,13 +466,8 @@ wintab_init_check (GdkDeviceManagerWin32 *device_manager)
#ifdef DEBUG_WINTAB
GDK_NOTE (INPUT, (g_print("Device %u: %s\n", devix, devname_utf8)));
#endif
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_NCSRTYPES, &ncsrtypes);
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_FIRSTCSR, &firstcsr);
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_HARDWARE, &hardware);
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_X, &axis_x);
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_Y, &axis_y);
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_NPRESSURE, &axis_npressure);
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_ORIENTATION, axis_or);
defcontext_done = FALSE;
if (HIBYTE (specversion) > 1 || LOBYTE (specversion) >= 1)
@ -544,137 +540,183 @@ wintab_init_check (GdkDeviceManagerWin32 *device_manager)
}
if (!i)
GDK_NOTE (INPUT, g_print("Whoops, no queue size could be set\n"));
for (cursorix = firstcsr; cursorix < firstcsr + ncsrtypes; cursorix++)
{
/* Get the cursors that Wintab is currently aware of */
_wintab_recognize_new_cursors(device_manager, *hctx);
}
}
UINT
_wintab_recognize_new_cursors (GdkDeviceManagerWin32 *device_manager,
HCTX hctx)
{
GdkDisplay *display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
int devix;
wchar_t devname[100], csrname[100];
gchar *devname_utf8, *csrname_utf8, *device_name;
UINT ncsrtypes, firstcsr, cursorix;
BOOL active;
DWORD physid;
AXIS axis_x, axis_y, axis_npressure, axis_or[3];
GdkDeviceWintab *device;
LOGCONTEXT lc;
int num_axes;
UINT num_new_cursors = 0;
devix = _gdk_find_wintab_device_index(hctx);
if (devix == -1)
return num_new_cursors;
(*p_WTInfoW) (WTI_DEVICES + devix, DVC_NAME, devname);
devname_utf8 = g_utf16_to_utf8 (devname, -1, NULL, NULL, NULL);
#ifdef DEBUG_WINTAB
GDK_NOTE (INPUT, (g_print("Cursor %u:\n", cursorix), print_cursor (cursorix)));
#endif
active = FALSE;
(*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_ACTIVE, &active);
if (!active)
continue;
/* Wacom tablets seem to report cursors corresponding to
* nonexistent pens or pucks. At least my ArtPad II reports
* six cursors: a puck, pressure stylus and eraser stylus,
* and then the same three again. I only have a
* pressure-sensitive pen. The puck instances, and the
* second instances of the styluses report physid zero. So
* at least for Wacom, skip cursors with physid zero.
*/
(*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_PHYSID, &physid);
if (wcscmp (devname, L"WACOM Tablet") == 0 && physid == 0)
continue;
(*p_WTInfoW) (WTI_CURSORS + cursorix, CSR_NAME, csrname);
csrname_utf8 = g_utf16_to_utf8 (csrname, -1, NULL, NULL, NULL);
device_name = g_strconcat (devname_utf8, " ", csrname_utf8, NULL);
device = g_object_new (GDK_TYPE_DEVICE_WINTAB,
"name", device_name,
"type", GDK_DEVICE_TYPE_FLOATING,
"input-source", GDK_SOURCE_PEN,
"input-mode", GDK_MODE_SCREEN,
"has-cursor", lc.lcOptions & CXO_SYSTEM,
"display", display,
"device-manager", device_manager,
NULL);
device->sends_core = lc.lcOptions & CXO_SYSTEM;
if (device->sends_core)
{
_gdk_device_set_associated_device (device_manager->system_pointer, GDK_DEVICE (device));
_gdk_device_add_slave (device_manager->core_pointer, GDK_DEVICE (device));
}
g_free (csrname_utf8);
device->hctx = *hctx;
device->cursor = cursorix;
(*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_PKTDATA, &device->pktdata);
if (device->pktdata & PK_X)
{
_gdk_device_add_axis (GDK_DEVICE (device),
GDK_NONE,
GDK_AXIS_X,
axis_x.axMin,
axis_x.axMax,
axis_x.axResolution / 65535);
num_axes++;
}
if (device->pktdata & PK_Y)
{
_gdk_device_add_axis (GDK_DEVICE (device),
GDK_NONE,
GDK_AXIS_Y,
axis_y.axMin,
axis_y.axMax,
axis_y.axResolution / 65535);
num_axes++;
}
if (device->pktdata & PK_NORMAL_PRESSURE)
{
_gdk_device_add_axis (GDK_DEVICE (device),
GDK_NONE,
GDK_AXIS_PRESSURE,
axis_npressure.axMin,
axis_npressure.axMax,
axis_npressure.axResolution / 65535);
num_axes++;
}
if (device->pktdata & PK_ORIENTATION)
{
device->orientation_axes[0] = axis_or[0];
device->orientation_axes[1] = axis_or[1];
/* Wintab gives us azimuth and altitude, which
* we convert to x and y tilt in the -1000..1000 range
*/
_gdk_device_add_axis (GDK_DEVICE (device),
GDK_NONE,
GDK_AXIS_XTILT,
-1000,
1000,
1000);
_gdk_device_add_axis (GDK_DEVICE (device),
GDK_NONE,
GDK_AXIS_YTILT,
-1000,
1000,
1000);
num_axes += 2;
}
device->last_axis_data = g_new (gint, num_axes);
GDK_NOTE (INPUT, g_print ("device: (%u) %s axes: %d\n",
cursorix,
device_name,
num_axes));
#if 0
for (i = 0; i < gdkdev->info.num_axes; i++)
GDK_NOTE (INPUT, g_print ("... axis %d: %d--%d@%d\n",
i,
gdkdev->axes[i].min_value,
gdkdev->axes[i].max_value,
gdkdev->axes[i].resolution));
GDK_NOTE (INPUT, (g_print("Finding cursors for device %u: %s\n", devix, devname_utf8)));
#endif
device_manager->wintab_devices = g_list_append (device_manager->wintab_devices,
device);
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_FIRSTCSR, &firstcsr);
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_NCSRTYPES, &ncsrtypes);
for (cursorix = firstcsr; cursorix < firstcsr + ncsrtypes; cursorix++)
{
#ifdef DEBUG_WINTAB
GDK_NOTE (INPUT, (g_print("Cursor %u:\n", cursorix), print_cursor (cursorix)));
#endif
/* Skip cursors that are already known to us */
if (gdk_device_manager_find_wintab_device(device_manager, hctx, cursorix) != NULL)
continue;
active = FALSE;
(*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_ACTIVE, &active);
if (!active)
continue;
g_free (device_name);
/* Wacom tablets iterate through all possible cursors,
* even if the cursor's presence has not been recognized.
* Unrecognized cursors have a physid of zero and are ignored.
* Recognized cursors have a non-zero physid and we create a
* Wintab device object for each of them.
*/
(*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_PHYSID, &physid);
if (wcscmp (devname, L"WACOM Tablet") == 0 && physid == 0)
continue;
if (!(*p_WTGetA) (hctx, &lc))
{
g_warning ("wintab_recognize_new_cursors: Failed to retrieve device LOGCONTEXT");
continue;
}
g_free (devname_utf8);
/* Create a Wintab device for this cursor */
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_X, &axis_x);
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_Y, &axis_y);
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_NPRESSURE, &axis_npressure);
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_ORIENTATION, axis_or);
(*p_WTInfoW) (WTI_CURSORS + cursorix, CSR_NAME, csrname);
csrname_utf8 = g_utf16_to_utf8 (csrname, -1, NULL, NULL, NULL);
device_name = g_strconcat (devname_utf8, " ", csrname_utf8, NULL);
g_free (csrname_utf8);
device = g_object_new (GDK_TYPE_DEVICE_WINTAB,
"name", device_name,
"type", GDK_DEVICE_TYPE_FLOATING,
"input-source", GDK_SOURCE_PEN,
"input-mode", GDK_MODE_SCREEN,
"has-cursor", lc.lcOptions & CXO_SYSTEM,
"display", display,
"device-manager", device_manager,
NULL);
device->sends_core = lc.lcOptions & CXO_SYSTEM;
if (device->sends_core)
{
_gdk_device_set_associated_device (device_manager->system_pointer, GDK_DEVICE (device));
_gdk_device_add_slave (device_manager->core_pointer, GDK_DEVICE (device));
}
device->hctx = hctx;
device->cursor = cursorix;
(*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_PKTDATA, &device->pktdata);
num_axes = 0;
if (device->pktdata & PK_X)
{
_gdk_device_add_axis (GDK_DEVICE (device),
GDK_NONE,
GDK_AXIS_X,
axis_x.axMin,
axis_x.axMax,
axis_x.axResolution / 65535);
num_axes++;
}
if (device->pktdata & PK_Y)
{
_gdk_device_add_axis (GDK_DEVICE (device),
GDK_NONE,
GDK_AXIS_Y,
axis_y.axMin,
axis_y.axMax,
axis_y.axResolution / 65535);
num_axes++;
}
if (device->pktdata & PK_NORMAL_PRESSURE)
{
_gdk_device_add_axis (GDK_DEVICE (device),
GDK_NONE,
GDK_AXIS_PRESSURE,
axis_npressure.axMin,
axis_npressure.axMax,
axis_npressure.axResolution / 65535);
num_axes++;
}
if (device->pktdata & PK_ORIENTATION)
{
device->orientation_axes[0] = axis_or[0];
device->orientation_axes[1] = axis_or[1];
/* Wintab gives us azimuth and altitude, which
* we convert to x and y tilt in the -1000..1000 range
*/
_gdk_device_add_axis (GDK_DEVICE (device),
GDK_NONE,
GDK_AXIS_XTILT,
-1000,
1000,
1000);
_gdk_device_add_axis (GDK_DEVICE (device),
GDK_NONE,
GDK_AXIS_YTILT,
-1000,
1000,
1000);
num_axes += 2;
}
device->last_axis_data = g_new (gint, num_axes);
GDK_NOTE (INPUT, g_print ("device: (%u) %s axes: %d\n",
cursorix,
device_name,
num_axes));
#if 0
for (i = 0; i < gdkdev->info.num_axes; i++)
GDK_NOTE (INPUT, g_print ("... axis %d: %d--%d@%d\n",
i,
gdkdev->axes[i].min_value,
gdkdev->axes[i].max_value,
gdkdev->axes[i].resolution));
#endif
device_manager->wintab_devices = g_list_append (device_manager->wintab_devices,
device);
num_new_cursors++;
g_free (device_name);
}
g_free (devname_utf8);
return num_new_cursors;
}
/* Only initialize Wintab after the default display is set for
@ -918,6 +960,31 @@ get_modifier_key_state (void)
return state;
}
int
_gdk_find_wintab_device_index (HCTX hctx)
{
GList *tmp_list;
int devix;
/* Find the index of the Wintab driver's input device (probably zero) */
if (!wintab_contexts)
return -1; /* No tablet devices found or Wintab not initialized yet */
tmp_list = wintab_contexts;
devix = 0;
while (tmp_list)
{
if ((*(HCTX *) (tmp_list->data)) == hctx)
return devix;
else
{
devix++;
tmp_list = tmp_list->next;
}
}
return -1;
}
static GdkDeviceWintab *
gdk_device_manager_find_wintab_device (GdkDeviceManagerWin32 *device_manager,
HCTX hctx,
@ -1221,21 +1288,31 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
case WT_CSRCHANGE:
if (device_manager->dev_entered_proximity > 0)
device_manager->dev_entered_proximity -= 1;
device_manager->dev_entered_proximity -= 1;
if ((source_device = gdk_device_manager_find_wintab_device (device_manager,
(HCTX) msg->lParam,
packet.pkCursor)) == NULL)
return FALSE;
if ((source_device =
gdk_device_manager_find_wintab_device (device_manager,
(HCTX) msg->lParam,
packet.pkCursor)) == NULL)
{
/* Check for new cursors and try again */
if (_wintab_recognize_new_cursors(device_manager,
(HCTX) msg->lParam) == 0)
return FALSE;
if ((source_device =
gdk_device_manager_find_wintab_device (device_manager,
(HCTX) msg->lParam,
packet.pkCursor)) == NULL)
return FALSE;
}
if (source_device->sends_core &&
gdk_device_get_mode (GDK_DEVICE (source_device)) != GDK_MODE_DISABLED)
{
_gdk_device_virtual_set_active (device_manager->core_pointer,
GDK_DEVICE (source_device));
_gdk_input_ignore_core += 1;
}
gdk_device_get_mode (GDK_DEVICE (source_device)) != GDK_MODE_DISABLED)
{
_gdk_device_virtual_set_active (device_manager->core_pointer,
GDK_DEVICE (source_device));
_gdk_input_ignore_core += 1;
}
return FALSE;
case WT_PROXIMITY: