#define PACKETMODE (PK_BUTTONS)
#include <pktdef.h>
-/* If USE_SYSCONTEXT is on, we open the Wintab device (hmm, what if
- * there are several?) as a system pointing device, i.e. it controls
- * the normal Windows cursor. This seems much more natural.
- */
-#define USE_SYSCONTEXT 1 /* The code for the other choice is not
- * good at all.
- */
-
#define DEBUG_WINTAB 1 /* Verbose debug messages enabled */
+#define PROXIMITY_OUT_DELAY 200 /* In milliseconds, see set_ignore_core */
+
#endif
#if defined(HAVE_WINTAB) || defined(HAVE_WHATEVER_OTHER)
/* Forward declarations */
-#if !USE_SYSCONTEXT
-static GdkInputWindow *gdk_input_window_find_within (GdkWindow *window);
-#endif
-
#ifdef HAVE_WINTAB
static GdkDevicePrivate *gdk_input_find_dev_from_ctx (HCTX hctx,
UINT id);
-static GList *wintab_contexts;
+static GList *wintab_contexts = NULL;
-static GdkWindow *wintab_window;
+static GdkWindow *wintab_window = NULL;
#endif /* HAVE_WINTAB */
#endif
-static void
-gdk_input_wintab_init (void)
+void
+_gdk_input_wintab_init_check (void)
{
+ static gboolean wintab_initialized = FALSE;
GdkDevicePrivate *gdkdev;
GdkWindowAttr wa;
WORD specversion;
- LOGCONTEXT defcontext;
HCTX *hctx;
UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware;
BOOL active;
int i, k;
int devix, cursorix;
char devname[100], csrname[100];
+ BOOL defcontext_done;
- _gdk_input_devices = NULL;
+ if (wintab_initialized)
+ return;
+
+ wintab_initialized = TRUE;
+
wintab_contexts = NULL;
if (!_gdk_input_ignore_wintab &&
WTInfo (WTI_INTERFACE, IFC_SPECVERSION, &specversion);
GDK_NOTE (INPUT, g_print ("Wintab interface version %d.%d\n",
HIBYTE (specversion), LOBYTE (specversion)));
-#if USE_SYSCONTEXT
- WTInfo (WTI_DEFSYSCTX, 0, &defcontext);
-#if DEBUG_WINTAB
- GDK_NOTE (INPUT, (g_print("DEFSYSCTX:\n"), print_lc(&defcontext)));
-#endif
-#else
- WTInfo (WTI_DEFCONTEXT, 0, &defcontext);
-#if DEBUG_WINTAB
- GDK_NOTE (INPUT, (g_print("DEFCONTEXT:\n"), print_lc(&defcontext)));
-#endif
-#endif
WTInfo (WTI_INTERFACE, IFC_NDEVICES, &ndevices);
WTInfo (WTI_INTERFACE, IFC_NCURSORS, &ncursors);
#if DEBUG_WINTAB
for (devix = 0; devix < ndevices; devix++)
{
LOGCONTEXT lc;
+
+ /* We open the Wintab device (hmm, what if there are several?) as a
+ * system pointing device, i.e. it controls the normal Windows
+ * cursor. This seems much more natural.
+ */
WTInfo (WTI_DEVICES + devix, DVC_NAME, devname);
WTInfo (WTI_DEVICES + devix, DVC_NPRESSURE, &axis_npressure);
WTInfo (WTI_DEVICES + devix, DVC_ORIENTATION, axis_or);
+ defcontext_done = FALSE;
if (HIBYTE (specversion) > 1 || LOBYTE (specversion) >= 1)
{
- WTInfo (WTI_DDCTXS + devix, CTX_NAME, lc.lcName);
- WTInfo (WTI_DDCTXS + devix, CTX_OPTIONS, &lc.lcOptions);
- lc.lcOptions |= CXO_MESSAGES;
-#if USE_SYSCONTEXT
- lc.lcOptions |= CXO_SYSTEM;
+ /* Try to get device-specific default context */
+ /* Some drivers, e.g. Aiptek, don't provide this info */
+ if (WTInfo (WTI_DSCTXS + devix, 0, &lc) > 0)
+ defcontext_done = TRUE;
+#if DEBUG_WINTAB
+ if (defcontext_done)
+ GDK_NOTE (INPUT, (g_print("Using device-specific default context\n")));
+ else
+ GDK_NOTE (INPUT, (g_print("Note: Driver did not provide device specific default context info despite claiming to support version 1.1\n")));
#endif
- lc.lcStatus = 0;
- WTInfo (WTI_DDCTXS + devix, CTX_LOCKS, &lc.lcLocks);
- lc.lcMsgBase = WT_DEFBASE;
- lc.lcDevice = devix;
- lc.lcPktRate = 50;
- lc.lcPktData = PACKETDATA;
- lc.lcPktMode = PK_BUTTONS; /* We want buttons in relative mode */
- lc.lcMoveMask = PACKETDATA;
- lc.lcBtnDnMask = lc.lcBtnUpMask = ~0;
- WTInfo (WTI_DDCTXS + devix, CTX_INORGX, &lc.lcInOrgX);
- WTInfo (WTI_DDCTXS + devix, CTX_INORGY, &lc.lcInOrgY);
- WTInfo (WTI_DDCTXS + devix, CTX_INORGZ, &lc.lcInOrgZ);
- WTInfo (WTI_DDCTXS + devix, CTX_INEXTX, &lc.lcInExtX);
- WTInfo (WTI_DDCTXS + devix, CTX_INEXTY, &lc.lcInExtY);
- WTInfo (WTI_DDCTXS + devix, CTX_INEXTZ, &lc.lcInExtZ);
- lc.lcOutOrgX = axis_x.axMin;
- lc.lcOutOrgY = axis_y.axMin;
- lc.lcOutExtX = axis_x.axMax - axis_x.axMin;
- lc.lcOutExtY = axis_y.axMax - axis_y.axMin;
- lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */
- WTInfo (WTI_DDCTXS + devix, CTX_SENSX, &lc.lcSensX);
- WTInfo (WTI_DDCTXS + devix, CTX_SENSY, &lc.lcSensY);
- WTInfo (WTI_DDCTXS + devix, CTX_SENSZ, &lc.lcSensZ);
- WTInfo (WTI_DDCTXS + devix, CTX_SYSMODE, &lc.lcSysMode);
- lc.lcSysOrgX = lc.lcSysOrgY = 0;
- WTInfo (WTI_DDCTXS + devix, CTX_SYSEXTX, &lc.lcSysExtX);
- WTInfo (WTI_DDCTXS + devix, CTX_SYSEXTY, &lc.lcSysExtY);
- WTInfo (WTI_DDCTXS + devix, CTX_SYSSENSX, &lc.lcSysSensX);
- WTInfo (WTI_DDCTXS + devix, CTX_SYSSENSY, &lc.lcSysSensY);
}
- else
- {
- lc = defcontext;
- lc.lcOptions |= CXO_MESSAGES;
- lc.lcMsgBase = WT_DEFBASE;
- lc.lcPktRate = 50;
- lc.lcPktData = PACKETDATA;
- lc.lcPktMode = PACKETMODE;
- lc.lcMoveMask = PACKETDATA;
- lc.lcBtnUpMask = lc.lcBtnDnMask = ~0;
-#if 0
- lc.lcOutExtY = -lc.lcOutExtY; /* Y grows downward */
-#else
- lc.lcOutOrgX = axis_x.axMin;
- lc.lcOutOrgY = axis_y.axMin;
- lc.lcOutExtX = axis_x.axMax - axis_x.axMin;
- lc.lcOutExtY = axis_y.axMax - axis_y.axMin;
- lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */
+
+ if (!defcontext_done)
+ WTInfo (WTI_DEFSYSCTX, 0, &lc);
+#if DEBUG_WINTAB
+ GDK_NOTE (INPUT, (g_print("Default context:\n"), print_lc(&lc)));
#endif
- }
+ lc.lcOptions |= CXO_MESSAGES;
+ lc.lcStatus = 0;
+ lc.lcMsgBase = WT_DEFBASE;
+ lc.lcPktRate = 50;
+ lc.lcPktData = PACKETDATA;
+ lc.lcPktMode = PACKETMODE;
+ lc.lcMoveMask = PACKETDATA;
+ lc.lcBtnUpMask = lc.lcBtnDnMask = ~0;
+ lc.lcOutOrgX = axis_x.axMin;
+ lc.lcOutOrgY = axis_y.axMin;
+ lc.lcOutExtX = axis_x.axMax - axis_x.axMin;
+ lc.lcOutExtY = axis_y.axMax - axis_y.axMin;
+ lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */
#if DEBUG_WINTAB
GDK_NOTE (INPUT, (g_print("context for device %d:\n", devix),
print_lc(&lc)));
gdkdev->info.name = g_strconcat (devname, " ", csrname, NULL);
gdkdev->info.source = GDK_SOURCE_PEN;
gdkdev->info.mode = GDK_MODE_SCREEN;
-#if USE_SYSCONTEXT
gdkdev->info.has_cursor = TRUE;
-#else
- gdkdev->info.has_cursor = FALSE;
-#endif
gdkdev->hctx = *hctx;
gdkdev->cursor = cursorix;
WTInfo (WTI_CURSORS + cursorix, CSR_PKTDATA, &gdkdev->pktdata);
gdkdev->info.num_axes));
for (i = 0; i < gdkdev->info.num_axes; i++)
GDK_NOTE (INPUT,
- g_print ("...axis %d: %d--%d@%d (%d--%d@%d)\n",
+ g_print ("... axis %d: %d--%d@%d (%d--%d@%d)\n",
i,
gdkdev->axes[i].xmin_value,
gdkdev->axes[i].xmax_value,
axis_data[1] = sin (az) * cos (el) * 1000;
}
-#if !USE_SYSCONTEXT
-
-static GdkInputWindow *
-gdk_input_window_find_within (GdkWindow *window)
-{
- GList *list;
- GdkWindow *tmpw;
- GdkInputWindow *candidate = NULL;
-
- for (list = _gdk_input_windows; list != NULL; list = list->next)
- {
- tmpw = ((GdkInputWindow *) (tmp_list->data))->window;
- if (tmpw == window
- || IsChild (GDK_WINDOW_HWND (window), GDK_WINDOW_HWND (tmpw)))
- {
- if (candidate)
- return NULL; /* Multiple hits */
- candidate = (GdkInputWindow *) (list->data);
- }
- }
-
- return candidate;
-}
-
-#endif /* USE_SYSCONTEXT */
-
#endif /* HAVE_WINTAB */
static void
gdouble *x_out,
gdouble *y_out)
{
- GdkWindowImplWin32 *impl;
+ GdkWindowImplWin32 *impl, *root_impl;
int i;
int x_axis = 0;
if (gdkdev->info.mode == GDK_MODE_SCREEN)
{
- x_scale = GetSystemMetrics (SM_CXSCREEN) / device_width;
- y_scale = GetSystemMetrics (SM_CYSCREEN) / device_height;
+ root_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (_gdk_root)->impl);
+ x_scale = root_impl->width / device_width;
+ y_scale = root_impl->height / device_height;
x_offset = - input_window->root_x;
y_offset = - input_window->root_y;
GetWindowRect (w, &rect);
if (x_ret)
- *x_ret = rect.left;
+ *x_ret = rect.left + _gdk_offset_x;
if (y_ret)
- *y_ret = rect.top;
+ *y_ret = rect.top + _gdk_offset_y;
}
void
input_window->root_y = root_y;
}
-/**
+/*
* Get the currently active keyboard modifiers (ignoring the mouse buttons)
* We could use gdk_window_get_pointer but that function does a lot of other
* expensive things besides getting the modifiers. This code is somewhat based
return state;
}
+#ifdef HAVE_WINTAB
+
+static guint ignore_core_timer = 0;
+
+static gboolean
+ignore_core_timefunc (gpointer data)
+{
+ /* The delay has passed */
+ _gdk_input_ignore_core = FALSE;
+ ignore_core_timer = 0;
+
+ return FALSE; /* remove timeout */
+}
+
+/*
+ * Set or unset the _gdk_input_ignore_core variable that tells GDK
+ * to ignore events for the core pointer when the tablet is in proximity
+ * The unsetting is delayed slightly so that if a tablet event arrives
+ * just after proximity out, it does not cause a core pointer event
+ * which e.g. causes GIMP to switch tools.
+ */
+static void
+set_ignore_core (gboolean ignore)
+{
+ if (ignore)
+ {
+ _gdk_input_ignore_core = TRUE;
+ /* Remove any pending clear */
+ if (ignore_core_timer)
+ {
+ g_source_remove (ignore_core_timer);
+ ignore_core_timer = 0;
+ }
+ }
+ else
+ if (!ignore_core_timer)
+ ignore_core_timer = g_timeout_add (PROXIMITY_OUT_DELAY,
+ ignore_core_timefunc, NULL);
+}
+#endif /* HAVE_WINTAB */
+
gboolean
_gdk_input_other_event (GdkEvent *event,
MSG *msg,
GdkWindow *window)
{
#ifdef HAVE_WINTAB
-#if !USE_SYSCONTEXT
- GdkWindow *current_window;
-#endif
GdkDisplay *display;
GdkWindowObject *obj, *grab_obj;
GdkInputWindow *input_window;
return FALSE;
}
-#if USE_SYSCONTEXT
window = gdk_window_at_pointer (&x, &y);
if (window == NULL)
- window = _gdk_parent_root;
+ window = _gdk_root;
g_object_ref (window);
display = gdk_drawable_get_display (window);
GDK_NOTE (EVENTS_OR_INPUT,
- g_print ("gdk_input_win32_other_event: window=%p (%d,%d)\n",
+ g_print ("gdk_input_win32_other_event: window=%p %+d%+d\n",
GDK_WINDOW_HWND (window), x, y));
-#else
- /* ??? This code is pretty bogus */
- current_window = gdk_win32_handle_table_lookup (GetActiveWindow ());
- if (current_window == NULL)
- return FALSE;
-
- input_window = gdk_input_window_find_within (current_window);
- if (input_window == NULL)
- return FALSE;
-#endif
-
if (msg->message == WT_PACKET)
{
if (!WTPacket ((HCTX) msg->lParam, msg->wParam, &packet))
switch (msg->message)
{
case WT_PACKET:
- if (window == _gdk_parent_root && x_grab_window == NULL)
+ /* Don't produce any button or motion events while a window is being
+ * moved or resized, see bug #151090. */
+ if (_sizemove_in_progress)
{
- GDK_NOTE (EVENTS_OR_INPUT, g_print ("...is root\n"));
+ GDK_NOTE (EVENTS_OR_INPUT, g_print ("... ignored when moving/sizing\n"));
+ return FALSE;
+ }
+ if (window == _gdk_root && x_grab_window == NULL)
+ {
+ GDK_NOTE (EVENTS_OR_INPUT, g_print ("... is root\n"));
return FALSE;
}
|| !(x_grab_mask && masktest))
{
GDK_NOTE (EVENTS_OR_INPUT,
- g_print ("...grabber doesn't want it\n"));
+ g_print ("... grabber doesn't want it\n"));
return FALSE;
}
- GDK_NOTE (EVENTS_OR_INPUT, g_print ("...to grabber\n"));
+ GDK_NOTE (EVENTS_OR_INPUT, g_print ("... to grabber\n"));
g_object_ref(x_grab_window);
g_object_unref(window);
if (!GDK_WINDOW_IMPL_WIN32 (obj->impl)->extension_events_selected
|| !(obj->extension_events & masktest))
{
- GDK_NOTE (EVENTS_OR_INPUT, g_print ("...not selected\n"));
+ GDK_NOTE (EVENTS_OR_INPUT, g_print ("... not selected\n"));
- if (obj->parent == GDK_WINDOW_OBJECT (_gdk_parent_root))
+ if (obj->parent == GDK_WINDOW_OBJECT (_gdk_root))
return FALSE;
/* It is not good to propagate the extended events up to the parent
if (obj->event_mask & masktest)
{
GDK_NOTE (EVENTS_OR_INPUT,
- g_print ("...wants ordinary event, ignoring this\n"));
+ g_print ("... wants ordinary event, ignoring this\n"));
return FALSE;
}
ScreenToClient (GDK_WINDOW_HWND (window), &pt);
x = pt.x;
y = pt.y;
- GDK_NOTE (EVENTS_OR_INPUT, g_print ("...propagating to %p (%d,%d)\n",
+ GDK_NOTE (EVENTS_OR_INPUT, g_print ("... propagating to %p %+d%+d\n",
GDK_WINDOW_HWND (window), x, y));
goto dijkstra;
}
event->button.time = _gdk_win32_get_next_tick (msg->time);
event->button.device = &gdkdev->info;
-#if 0
-#if USE_SYSCONTEXT
- /* Buttons 1 to 3 will come in as WM_[LMR]BUTTON{DOWN,UP} */
- if (event->button.button <= 3)
- return FALSE;
-#endif
-#endif
event->button.axes = g_new(gdouble, gdkdev->info.num_axes);
gdk_input_translate_coordinates (gdkdev, input_window,
&event->button.x,
&event->button.y);
+ /* Also calculate root coordinates. Note that input_window->root_x
+ is in GDK root coordinates. */
+ event->button.x_root = event->button.x + input_window->root_x;
+ event->button.y_root = event->button.y + input_window->root_y;
+
event->button.state = ((gdkdev->button_state << 8)
& (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
| GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
&event->motion.x,
&event->motion.y);
+ /* Also calculate root coordinates. Note that input_window->root_x
+ is in GDK root coordinates. */
+ event->motion.x_root = event->motion.x + input_window->root_x;
+ event->motion.y_root = event->motion.y + input_window->root_y;
+
event->motion.state = ((gdkdev->button_state << 8)
& (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
| GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
if (LOWORD (msg->lParam) == 0)
{
event->proximity.type = GDK_PROXIMITY_OUT;
- _gdk_input_ignore_core = FALSE;
+ set_ignore_core (FALSE);
}
else
{
event->proximity.type = GDK_PROXIMITY_IN;
- _gdk_input_ignore_core = TRUE;
+ set_ignore_core (TRUE);
}
event->proximity.time = _gdk_win32_get_next_tick (msg->time);
event->proximity.device = &gdkdev->info;
tmp_list = tmp_list->next;
}
}
-#endif
x_grab_window = NULL;
+#endif
}
gboolean
}
}
+#ifdef HAVE_WINTAB
+void
+_gdk_input_set_tablet_active (void)
+{
+ GList *tmp_list;
+ HCTX *hctx;
+
+ /* Bring the contexts to the top of the overlap order when one of the
+ * application's windows is activated */
+
+ if (!wintab_contexts)
+ return; /* No tablet devices found, or Wintab not initialized yet */
+
+ GDK_NOTE (INPUT, g_print ("_gdk_input_set_tablet_active: "
+ "Bringing Wintab contexts to the top of the overlap order\n"));
+
+ tmp_list = wintab_contexts;
+ while (tmp_list)
+ {
+ hctx = (HCTX *) (tmp_list->data);
+ WTOverlap (*hctx, TRUE);
+ tmp_list = tmp_list->next;
+ }
+}
+#endif /* HAVE_WINTAB */
+
void
_gdk_input_init (GdkDisplay *display)
{
_gdk_init_input_core (display);
#ifdef HAVE_WINTAB
- gdk_input_wintab_init ();
+#ifdef WINTAB_NO_LAZY_INIT
+ /* Normally, Wintab is only initialized when the application performs
+ * an action that requires it, such as enabling extended input events
+ * for a window or enumerating the devices.
+ */
+ _gdk_input_wintab_init_check ();
+#endif /* WINTAB_NO_LAZY_INIT */
#endif /* HAVE_WINTAB */
_gdk_input_devices = g_list_append (_gdk_input_devices, display->core_pointer);