/* GDK - The GIMP Drawing Kit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * Copyright (C) 1999 Tor Lillqvist * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ #include "config.h" #include #include #include #include "gdk.h" #include "gdkinput.h" #include "gdkprivate.h" #include "gdkx.h" #ifdef HAVE_WINTAB #include #define PACKETDATA (PK_CONTEXT | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION) #define PACKETMODE (PK_BUTTONS) #include #endif #include "gdkinputprivate.h" struct _GdkDevicePrivate { GdkDeviceInfo info; /* information about the axes */ GdkAxisInfo *axes; /* reverse lookup on axis use type */ gint axis_for_use[GDK_AXIS_LAST]; /* true if we need to select a different set of events, but * can't because this is the core pointer */ gint needs_update; /* State of buttons */ gint button_state; gint *last_axis_data; gint last_buttons; #ifdef HAVE_WINTAB /* WINTAB stuff: */ HCTX hctx; /* Cursor number */ UINT cursor; /* The cursor's CSR_PKTDATA */ WTPKT pktdata; /* CSR_NPBTNMARKS */ UINT npbtnmarks[2]; /* Azimuth and altitude axis */ AXIS orientation_axes[2]; #endif }; #ifndef M_PI #define M_PI 3.14159265358979323846 #endif /* 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. */ #ifdef HAVE_WINTAB #define DEBUG_WINTAB 1 #endif #define TWOPI (2.*M_PI) #define PING() g_print("%s: %d\n",__FILE__,__LINE__) /* Forward declarations */ static gint gdk_input_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev); static gint gdk_input_disable_window (GdkWindow *window, GdkDevicePrivate *gdkdev); static void gdk_input_none_get_pointer (GdkWindow *window, guint32 deviceid, gdouble *x, gdouble *y, gdouble *pressure, gdouble *xtilt, gdouble *ytilt, GdkModifierType *mask); static GdkDevicePrivate *gdk_input_find_device (guint32 deviceid); #ifdef HAVE_WINTAB static gint gdk_input_win32_set_mode (guint32 deviceid, GdkInputMode mode); static void gdk_input_win32_get_pointer (GdkWindow *window, guint32 deviceid, gdouble *x, gdouble *y, gdouble *pressure, gdouble *xtilt, gdouble *ytilt, GdkModifierType *mask); static gint gdk_input_win32_grab_pointer (GdkWindow * window, gint owner_events, GdkEventMask event_mask, GdkWindow *confine_to, guint32 time); static void gdk_input_win32_ungrab_pointer (guint32 time); static void gdk_input_win32_configure_event (GdkEventConfigure *event, GdkWindow *window); static void gdk_input_win32_enter_event (GdkEventCrossing *xevent, GdkWindow *window); static gint gdk_input_win32_other_event (GdkEvent *event, MSG *xevent); static gint gdk_input_win32_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev); static gint gdk_input_win32_disable_window (GdkWindow *window, GdkDevicePrivate *gdkdev); static GdkInputWindow *gdk_input_window_find (GdkWindow *window); #if !USE_SYSCONTEXT static GdkInputWindow *gdk_input_window_find_within (GdkWindow *window); #endif static GdkDevicePrivate *gdk_input_find_dev_from_ctx (HCTX hctx, UINT id); #endif /* HAVE_WINTAB */ /* Local variables */ static GList *gdk_input_devices; static GList *gdk_input_windows; static GList *wintab_contexts; static gint gdk_input_root_width; static gint gdk_input_root_height; static GdkWindow *wintab_window; static guint32 last_moved_cursor_id; static GdkAxisUse gdk_input_core_axes[] = { GDK_AXIS_X, GDK_AXIS_Y }; static GdkDeviceInfo gdk_input_core_info = { GDK_CORE_POINTER, "Core Pointer", GDK_SOURCE_MOUSE, GDK_MODE_SCREEN, TRUE, 2, gdk_input_core_axes }; /* Global variables */ GdkInputVTable gdk_input_vtable; gint gdk_input_ignore_core; gint gdk_input_ignore_wintab = FALSE; #if DEBUG_WINTAB static void print_lc(LOGCONTEXT *lc) { g_print ("lcName = %s\n", lc->lcName); g_print ("lcOptions ="); if (lc->lcOptions & CXO_SYSTEM) g_print (" CXO_SYSTEM"); if (lc->lcOptions & CXO_PEN) g_print (" CXO_PEN"); if (lc->lcOptions & CXO_MESSAGES) g_print (" CXO_MESSAGES"); if (lc->lcOptions & CXO_MARGIN) g_print (" CXO_MARGIN"); if (lc->lcOptions & CXO_MGNINSIDE) g_print (" CXO_MGNINSIDE"); if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES"); if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES"); g_print ("\n"); g_print ("lcStatus ="); if (lc->lcStatus & CXS_DISABLED) g_print (" CXS_DISABLED"); if (lc->lcStatus & CXS_OBSCURED) g_print (" CXS_OBSCURED"); if (lc->lcStatus & CXS_ONTOP) g_print (" CXS_ONTOP"); g_print ("\n"); g_print ("lcLocks ="); if (lc->lcLocks & CXL_INSIZE) g_print (" CXL_INSIZE"); if (lc->lcLocks & CXL_INASPECT) g_print (" CXL_INASPECT"); if (lc->lcLocks & CXL_SENSITIVITY) g_print (" CXL_SENSITIVITY"); if (lc->lcLocks & CXL_MARGIN) g_print (" CXL_MARGIN"); g_print ("\n"); g_print ("lcMsgBase = %#x, lcDevice = %#x, lcPktRate = %d\n", lc->lcMsgBase, lc->lcDevice, lc->lcPktRate); g_print ("lcPktData ="); if (lc->lcPktData & PK_CONTEXT) g_print (" PK_CONTEXT"); if (lc->lcPktData & PK_STATUS) g_print (" PK_STATUS"); if (lc->lcPktData & PK_TIME) g_print (" PK_TIME"); if (lc->lcPktData & PK_CHANGED) g_print (" PK_CHANGED"); if (lc->lcPktData & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER"); if (lc->lcPktData & PK_CURSOR) g_print (" PK_CURSOR"); if (lc->lcPktData & PK_BUTTONS) g_print (" PK_BUTTONS"); if (lc->lcPktData & PK_X) g_print (" PK_X"); if (lc->lcPktData & PK_Y) g_print (" PK_Y"); if (lc->lcPktData & PK_Z) g_print (" PK_Z"); if (lc->lcPktData & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE"); if (lc->lcPktData & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE"); if (lc->lcPktData & PK_ORIENTATION) g_print (" PK_ORIENTATION"); if (lc->lcPktData & PK_ROTATION) g_print (" PK_ROTATION"); g_print ("\n"); g_print ("lcPktMode ="); if (lc->lcPktMode & PK_CONTEXT) g_print (" PK_CONTEXT"); if (lc->lcPktMode & PK_STATUS) g_print (" PK_STATUS"); if (lc->lcPktMode & PK_TIME) g_print (" PK_TIME"); if (lc->lcPktMode & PK_CHANGED) g_print (" PK_CHANGED"); if (lc->lcPktMode & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER"); if (lc->lcPktMode & PK_CURSOR) g_print (" PK_CURSOR"); if (lc->lcPktMode & PK_BUTTONS) g_print (" PK_BUTTONS"); if (lc->lcPktMode & PK_X) g_print (" PK_X"); if (lc->lcPktMode & PK_Y) g_print (" PK_Y"); if (lc->lcPktMode & PK_Z) g_print (" PK_Z"); if (lc->lcPktMode & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE"); if (lc->lcPktMode & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE"); if (lc->lcPktMode & PK_ORIENTATION) g_print (" PK_ORIENTATION"); if (lc->lcPktMode & PK_ROTATION) g_print (" PK_ROTATION"); g_print ("\n"); g_print ("lcMoveMask ="); if (lc->lcMoveMask & PK_CONTEXT) g_print (" PK_CONTEXT"); if (lc->lcMoveMask & PK_STATUS) g_print (" PK_STATUS"); if (lc->lcMoveMask & PK_TIME) g_print (" PK_TIME"); if (lc->lcMoveMask & PK_CHANGED) g_print (" PK_CHANGED"); if (lc->lcMoveMask & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER"); if (lc->lcMoveMask & PK_CURSOR) g_print (" PK_CURSOR"); if (lc->lcMoveMask & PK_BUTTONS) g_print (" PK_BUTTONS"); if (lc->lcMoveMask & PK_X) g_print (" PK_X"); if (lc->lcMoveMask & PK_Y) g_print (" PK_Y"); if (lc->lcMoveMask & PK_Z) g_print (" PK_Z"); if (lc->lcMoveMask & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE"); if (lc->lcMoveMask & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE"); if (lc->lcMoveMask & PK_ORIENTATION) g_print (" PK_ORIENTATION"); if (lc->lcMoveMask & PK_ROTATION) g_print (" PK_ROTATION"); g_print ("\n"); g_print ("lcBtnDnMask = %#x, lcBtnUpMask = %#x\n", lc->lcBtnDnMask, lc->lcBtnUpMask); g_print ("lcInOrgX = %d, lcInOrgY = %d, lcInOrgZ = %d\n", lc->lcInOrgX, lc->lcInOrgY, lc->lcInOrgZ); g_print ("lcInExtX = %d, lcInExtY = %d, lcInExtZ = %d\n", lc->lcInExtX, lc->lcInExtY, lc->lcInExtZ); g_print ("lcOutOrgX = %d, lcOutOrgY = %d, lcOutOrgZ = %d\n", lc->lcOutOrgX, lc->lcOutOrgY, lc->lcOutOrgZ); g_print ("lcOutExtX = %d, lcOutExtY = %d, lcOutExtZ = %d\n", lc->lcOutExtX, lc->lcOutExtY, lc->lcOutExtZ); g_print ("lcSensX = %g, lcSensY = %g, lcSensZ = %g\n", lc->lcSensX / 65536., lc->lcSensY / 65536., lc->lcSensZ / 65536.); g_print ("lcSysMode = %d\n", lc->lcSysMode); g_print ("lcSysOrgX = %d, lcSysOrgY = %d\n", lc->lcSysOrgX, lc->lcSysOrgY); g_print ("lcSysExtX = %d, lcSysExtY = %d\n", lc->lcSysExtX, lc->lcSysExtY); g_print ("lcSysSensX = %g, lcSysSensY = %g\n", lc->lcSysSensX / 65536., lc->lcSysSensY / 65536.); } #endif void gdk_input_init (void) { guint32 deviceid_counter = 0; #ifdef HAVE_WINTAB GdkDevicePrivate *gdkdev; GdkDrawablePrivate *window_private; GdkWindowAttr wa; WORD specversion; LOGCONTEXT defcontext; HCTX *hctx; UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware; BOOL active; AXIS axis_x, axis_y, axis_npressure, axis_or[3]; int i, j, k; int devix, cursorix; char devname[100], csrname[100]; gdk_input_devices = NULL; wintab_contexts = NULL; if (!gdk_input_ignore_wintab && WTInfo (0, 0, NULL)) { WTInfo (WTI_INTERFACE, IFC_SPECVERSION, &specversion); GDK_NOTE (MISC, 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 (MISC, (g_print("DEFSYSCTX:\n"), print_lc(&defcontext))); #endif #else WTInfo (WTI_DEFCONTEXT, 0, &defcontext); #if DEBUG_WINTAB GDK_NOTE (MISC, (g_print("DEFCONTEXT:\n"), print_lc(&defcontext))); #endif #endif WTInfo (WTI_INTERFACE, IFC_NDEVICES, &ndevices); WTInfo (WTI_INTERFACE, IFC_NCURSORS, &ncursors); #if DEBUG_WINTAB GDK_NOTE (MISC, g_print ("NDEVICES: %d, NCURSORS: %d\n", ndevices, ncursors)); #endif /* Create a dummy window to receive wintab events */ wa.wclass = GDK_INPUT_OUTPUT; wa.event_mask = GDK_ALL_EVENTS_MASK; wa.width = 2; wa.height = 2; wa.x = -100; wa.y = -100; wa.window_type = GDK_WINDOW_TOPLEVEL; if ((wintab_window = gdk_window_new (NULL, &wa, GDK_WA_X|GDK_WA_Y)) == NULL) { g_warning ("gdk_input_init: gdk_window_new failed"); return; } gdk_window_ref (wintab_window); window_private = (GdkDrawablePrivate *) wintab_window; for (devix = 0; devix < ndevices; devix++) { LOGCONTEXT lc; WTInfo (WTI_DEVICES + devix, DVC_NAME, devname); WTInfo (WTI_DEVICES + devix, DVC_NCSRTYPES, &ncsrtypes); WTInfo (WTI_DEVICES + devix, DVC_FIRSTCSR, &firstcsr); WTInfo (WTI_DEVICES + devix, DVC_HARDWARE, &hardware); WTInfo (WTI_DEVICES + devix, DVC_X, &axis_x); WTInfo (WTI_DEVICES + devix, DVC_Y, &axis_y); WTInfo (WTI_DEVICES + devix, DVC_NPRESSURE, &axis_npressure); WTInfo (WTI_DEVICES + devix, DVC_ORIENTATION, axis_or); 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; #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 */ #endif } #if DEBUG_WINTAB GDK_NOTE (MISC, (g_print("context for device %d:\n", devix), print_lc(&lc))); #endif hctx = g_new (HCTX, 1); if ((*hctx = WTOpen (window_private->xwindow, &lc, TRUE)) == NULL) { g_warning ("gdk_input_init: WTOpen failed"); return; } GDK_NOTE (MISC, g_print ("opened Wintab device %d %#x\n", devix, *hctx)); wintab_contexts = g_list_append (wintab_contexts, hctx); #if 0 WTEnable (*hctx, TRUE); #endif WTOverlap (*hctx, TRUE); #if DEBUG_WINTAB GDK_NOTE (MISC, (g_print("context for device %d after WTOpen:\n", devix), print_lc(&lc))); #endif for (cursorix = firstcsr; cursorix < firstcsr + ncsrtypes; cursorix++) { active = FALSE; WTInfo (WTI_CURSORS + cursorix, CSR_ACTIVE, &active); if (!active) continue; gdkdev = g_new (GdkDevicePrivate, 1); WTInfo (WTI_CURSORS + cursorix, CSR_NAME, csrname); gdkdev->info.name = g_strconcat (devname, " ", csrname, NULL); gdkdev->info.deviceid = deviceid_counter++; 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 = 0; if (gdkdev->pktdata & PK_X) gdkdev->info.num_axes++; if (gdkdev->pktdata & PK_Y) gdkdev->info.num_axes++; if (gdkdev->pktdata & PK_NORMAL_PRESSURE) gdkdev->info.num_axes++; /* The wintab driver for the Wacom ArtPad II reports * PK_ORIENTATION in CSR_PKTDATA, but the tablet doesn't * actually sense tilt. Catch this by noticing that the * orientation axis's azimuth resolution is zero. */ if ((gdkdev->pktdata & PK_ORIENTATION) && axis_or[0].axResolution == 0) gdkdev->pktdata &= ~PK_ORIENTATION; if (gdkdev->pktdata & PK_ORIENTATION) gdkdev->info.num_axes += 2; /* x and y tilt */ WTInfo (WTI_CURSORS + cursorix, CSR_NPBTNMARKS, &gdkdev->npbtnmarks); gdkdev->axes = g_new (GdkAxisInfo, gdkdev->info.num_axes); gdkdev->info.axes = g_new (GdkAxisUse, gdkdev->info.num_axes); gdkdev->last_axis_data = g_new (gint, gdkdev->info.num_axes); for (k = 0; k < GDK_AXIS_LAST; k++) gdkdev->axis_for_use[k] = -1; k = 0; if (gdkdev->pktdata & PK_X) { gdkdev->axes[k].xresolution = gdkdev->axes[k].resolution = axis_x.axResolution / 65535.; gdkdev->axes[k].xmin_value = gdkdev->axes[k].min_value = axis_x.axMin; gdkdev->axes[k].xmax_value = gdkdev->axes[k].max_value = axis_x.axMax; gdkdev->info.axes[k] = GDK_AXIS_X; gdkdev->axis_for_use[GDK_AXIS_X] = k; k++; } if (gdkdev->pktdata & PK_Y) { gdkdev->axes[k].xresolution = gdkdev->axes[k].resolution = axis_y.axResolution / 65535.; gdkdev->axes[k].xmin_value = gdkdev->axes[k].min_value = axis_y.axMin; gdkdev->axes[k].xmax_value = gdkdev->axes[k].max_value = axis_y.axMax; gdkdev->info.axes[k] = GDK_AXIS_Y; gdkdev->axis_for_use[GDK_AXIS_Y] = k; k++; } if (gdkdev->pktdata & PK_NORMAL_PRESSURE) { gdkdev->axes[k].xresolution = gdkdev->axes[k].resolution = axis_npressure.axResolution / 65535.; gdkdev->axes[k].xmin_value = gdkdev->axes[k].min_value = axis_npressure.axMin; gdkdev->axes[k].xmax_value = gdkdev->axes[k].max_value = axis_npressure.axMax; gdkdev->info.axes[k] = GDK_AXIS_PRESSURE; gdkdev->axis_for_use[GDK_AXIS_PRESSURE] = k; k++; } if (gdkdev->pktdata & PK_ORIENTATION) { GdkAxisUse axis; gdkdev->orientation_axes[0] = axis_or[0]; gdkdev->orientation_axes[1] = axis_or[1]; for (axis = GDK_AXIS_XTILT; axis <= GDK_AXIS_YTILT; axis++) { /* Wintab gives us aximuth and altitude, which * we convert to x and y tilt in the -1000..1000 range */ gdkdev->axes[k].xresolution = gdkdev->axes[k].resolution = 1000; gdkdev->axes[k].xmin_value = gdkdev->axes[k].min_value = -1000; gdkdev->axes[k].xmax_value = gdkdev->axes[k].max_value = 1000; gdkdev->info.axes[k] = axis; gdkdev->axis_for_use[axis] = k; k++; } } gdkdev->info.num_keys = 0; gdkdev->info.keys = NULL; GDK_NOTE (EVENTS, (g_print ("device: %d (%d) %s axes: %d\n", gdkdev->info.deviceid, cursorix, gdkdev->info.name, gdkdev->info.num_axes), g_print ("axes: X:%d, Y:%d, PRESSURE:%d, " "XTILT:%d, YTILT:%d\n", gdkdev->axis_for_use[GDK_AXIS_X], gdkdev->axis_for_use[GDK_AXIS_Y], gdkdev->axis_for_use[GDK_AXIS_PRESSURE], gdkdev->axis_for_use[GDK_AXIS_XTILT], gdkdev->axis_for_use[GDK_AXIS_YTILT]))); for (i = 0; i < gdkdev->info.num_axes; i++) GDK_NOTE (EVENTS, g_print ("...axis %d: %d--%d@%d (%d--%d@%d)\n", i, gdkdev->axes[i].xmin_value, gdkdev->axes[i].xmax_value, gdkdev->axes[i].xresolution, gdkdev->axes[i].min_value, gdkdev->axes[i].max_value, gdkdev->axes[i].resolution)); gdk_input_devices = g_list_append (gdk_input_devices, gdkdev); } } } #endif /* HAVE_WINTAB */ if (deviceid_counter > 0) { #ifdef HAVE_WINTAB gdk_input_vtable.set_mode = gdk_input_win32_set_mode; gdk_input_vtable.set_axes = NULL; gdk_input_vtable.set_key = NULL; gdk_input_vtable.motion_events = NULL; gdk_input_vtable.get_pointer = gdk_input_win32_get_pointer; gdk_input_vtable.grab_pointer = gdk_input_win32_grab_pointer; gdk_input_vtable.ungrab_pointer = gdk_input_win32_ungrab_pointer; gdk_input_vtable.configure_event = gdk_input_win32_configure_event; gdk_input_vtable.enter_event = gdk_input_win32_enter_event; gdk_input_vtable.other_event = gdk_input_win32_other_event; gdk_input_vtable.enable_window = gdk_input_win32_enable_window; gdk_input_vtable.disable_window = gdk_input_win32_disable_window; gdk_input_root_width = gdk_screen_width (); gdk_input_root_height = gdk_screen_height (); gdk_input_ignore_core = FALSE; #else g_assert_not_reached (); #endif } else { gdk_input_vtable.set_mode = NULL; gdk_input_vtable.set_axes = NULL; gdk_input_vtable.set_key = NULL; gdk_input_vtable.motion_events = NULL; gdk_input_vtable.get_pointer = gdk_input_none_get_pointer; gdk_input_vtable.grab_pointer = NULL; gdk_input_vtable.ungrab_pointer = NULL; gdk_input_vtable.configure_event = NULL; gdk_input_vtable.enter_event = NULL; gdk_input_vtable.other_event = NULL; gdk_input_vtable.enable_window = NULL; gdk_input_vtable.disable_window = NULL; gdk_input_ignore_core = FALSE; } gdk_input_devices = g_list_append (gdk_input_devices, &gdk_input_core_info); } gint gdk_input_set_mode (guint32 deviceid, GdkInputMode mode) { if (deviceid == GDK_CORE_POINTER) return FALSE; if (gdk_input_vtable.set_mode) return gdk_input_vtable.set_mode (deviceid, mode); else return FALSE; } void gdk_input_set_axes (guint32 deviceid, GdkAxisUse *axes) { int i; GdkDevicePrivate *gdkdev = gdk_input_find_device (deviceid); g_return_if_fail (gdkdev != NULL); if (deviceid == GDK_CORE_POINTER) return; for (i = GDK_AXIS_IGNORE; i < GDK_AXIS_LAST; i++) { gdkdev->axis_for_use[i] = -1; } for (i = 0; i < gdkdev->info.num_axes; i++) { gdkdev->info.axes[i] = axes[i]; gdkdev->axis_for_use[axes[i]] = i; } } static void gdk_input_none_get_pointer (GdkWindow *window, guint32 deviceid, gdouble *x, gdouble *y, gdouble *pressure, gdouble *xtilt, gdouble *ytilt, GdkModifierType *mask) { gint x_int, y_int; gdk_window_get_pointer (window, &x_int, &y_int, mask); if (x) *x = x_int; if (y) *y = y_int; if (pressure) *pressure = 0.5; if (xtilt) *xtilt = 0; if (ytilt) *ytilt = 0; } #ifdef HAVE_WINTAB static void gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev, GdkInputWindow *input_window, gint *axis_data, gdouble *x, gdouble *y, gdouble *pressure, gdouble *xtilt, gdouble *ytilt) { GdkDrawablePrivate *window_private; gint x_axis, y_axis, pressure_axis, xtilt_axis, ytilt_axis; gdouble device_width, device_height; gdouble x_offset, y_offset, x_scale, y_scale; window_private = (GdkDrawablePrivate *) input_window->window; x_axis = gdkdev->axis_for_use[GDK_AXIS_X]; y_axis = gdkdev->axis_for_use[GDK_AXIS_Y]; pressure_axis = gdkdev->axis_for_use[GDK_AXIS_PRESSURE]; xtilt_axis = gdkdev->axis_for_use[GDK_AXIS_XTILT]; ytilt_axis = gdkdev->axis_for_use[GDK_AXIS_YTILT]; device_width = gdkdev->axes[x_axis].max_value - gdkdev->axes[x_axis].min_value; device_height = gdkdev->axes[y_axis].max_value - gdkdev->axes[y_axis].min_value; if (gdkdev->info.mode == GDK_MODE_SCREEN) { x_scale = gdk_input_root_width / device_width; y_scale = gdk_input_root_height / device_height; x_offset = -input_window->root_x; y_offset = -input_window->root_y; } else /* GDK_MODE_WINDOW */ { double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) / (device_width*gdkdev->axes[x_axis].resolution); if (device_aspect * window_private->width >= window_private->height) { /* device taller than window */ x_scale = window_private->width / device_width; y_scale = (x_scale * gdkdev->axes[x_axis].resolution) / gdkdev->axes[y_axis].resolution; x_offset = 0; y_offset = -(device_height * y_scale - window_private->height)/2; } else { /* window taller than device */ y_scale = window_private->height / device_height; x_scale = (y_scale * gdkdev->axes[y_axis].resolution) / gdkdev->axes[x_axis].resolution; y_offset = 0; x_offset = -(device_width * x_scale - window_private->width)/2; } } if (x) *x = x_offset + x_scale*axis_data[x_axis]; if (y) *y = y_offset + y_scale*axis_data[y_axis]; if (pressure) { if (pressure_axis != -1) *pressure = ((double)axis_data[pressure_axis] - gdkdev->axes[pressure_axis].min_value) / (gdkdev->axes[pressure_axis].max_value - gdkdev->axes[pressure_axis].min_value); else *pressure = 0.5; } if (xtilt) { if (xtilt_axis != -1) { *xtilt = 2. * (double)(axis_data[xtilt_axis] - (gdkdev->axes[xtilt_axis].min_value + gdkdev->axes[xtilt_axis].max_value)/2) / (gdkdev->axes[xtilt_axis].max_value - gdkdev->axes[xtilt_axis].min_value); } else *xtilt = 0; } if (ytilt) { if (ytilt_axis != -1) { *ytilt = 2. * (double)(axis_data[ytilt_axis] - (gdkdev->axes[ytilt_axis].min_value + gdkdev->axes[ytilt_axis].max_value)/2) / (gdkdev->axes[ytilt_axis].max_value - gdkdev->axes[ytilt_axis].min_value); } else *ytilt = 0; } } static void gdk_input_win32_get_pointer (GdkWindow *window, guint32 deviceid, gdouble *x, gdouble *y, gdouble *pressure, gdouble *xtilt, gdouble *ytilt, GdkModifierType *mask) { GdkDevicePrivate *gdkdev; GdkInputWindow *input_window; gint x_int, y_int; gint i; if (deviceid == GDK_CORE_POINTER) { gdk_window_get_pointer (window, &x_int, &y_int, mask); if (x) *x = x_int; if (y) *y = y_int; if (pressure) *pressure = 0.5; if (xtilt) *xtilt = 0; if (ytilt) *ytilt = 0; } else { if (mask) gdk_window_get_pointer (window, NULL, NULL, mask); gdkdev = gdk_input_find_device (deviceid); g_return_if_fail (gdkdev != NULL); input_window = gdk_input_window_find (window); g_return_if_fail (input_window != NULL); gdk_input_translate_coordinates (gdkdev, input_window, gdkdev->last_axis_data, x, y, pressure, xtilt, ytilt); if (mask) { *mask &= 0xFF; *mask |= ((gdkdev->last_buttons & 0x1F) << 8); } } } static void gdk_input_get_root_relative_geometry (HWND w, int *x_ret, int *y_ret) { RECT rect; GetWindowRect (w, &rect); if (x_ret) *x_ret = rect.left; if (y_ret) *y_ret = rect.top; } static gint gdk_input_win32_set_mode (guint32 deviceid, GdkInputMode mode) { GList *tmp_list; GdkDevicePrivate *gdkdev; GdkInputMode old_mode; GdkInputWindow *input_window; if (deviceid == GDK_CORE_POINTER) return FALSE; gdkdev = gdk_input_find_device (deviceid); g_return_val_if_fail (gdkdev != NULL, FALSE); old_mode = gdkdev->info.mode; if (old_mode == mode) return TRUE; gdkdev->info.mode = mode; if (mode == GDK_MODE_WINDOW) { gdkdev->info.has_cursor = FALSE; for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) { input_window = (GdkInputWindow *)tmp_list->data; if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) gdk_input_win32_enable_window (input_window->window, gdkdev); else if (old_mode != GDK_MODE_DISABLED) gdk_input_win32_disable_window (input_window->window, gdkdev); } } else if (mode == GDK_MODE_SCREEN) { gdkdev->info.has_cursor = TRUE; for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) gdk_input_win32_enable_window (((GdkInputWindow *)tmp_list->data)->window, gdkdev); } else /* mode == GDK_MODE_DISABLED */ { for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) { input_window = (GdkInputWindow *)tmp_list->data; if (old_mode != GDK_MODE_WINDOW || input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) gdk_input_win32_disable_window (input_window->window, gdkdev); } } return TRUE; } static void gdk_input_win32_configure_event (GdkEventConfigure *event, GdkWindow *window) { GdkInputWindow *input_window; gint root_x, root_y; input_window = gdk_input_window_find (window); g_return_if_fail (window != NULL); gdk_input_get_root_relative_geometry (GDK_DRAWABLE_XID (window), &root_x, &root_y); input_window->root_x = root_x; input_window->root_y = root_y; } static void gdk_input_win32_enter_event (GdkEventCrossing *event, GdkWindow *window) { GdkInputWindow *input_window; gint root_x, root_y; input_window = gdk_input_window_find (window); g_return_if_fail (window != NULL); gdk_input_get_root_relative_geometry (GDK_DRAWABLE_XID (window), &root_x, &root_y); input_window->root_x = root_x; input_window->root_y = root_y; } static void decode_tilt (gint *axis_data, AXIS *axes, PACKET *packet) { /* As I don't have a tilt-sensing tablet, * I cannot test this code. */ double az, el; az = TWOPI * packet->pkOrientation.orAzimuth / (axes[0].axResolution / 65536.); el = TWOPI * packet->pkOrientation.orAltitude / (axes[1].axResolution / 65536.); /* X tilt */ axis_data[0] = cos (az) * cos (el) * 1000; /* Y tilt */ axis_data[1] = sin (az) * cos (el) * 1000; } static GdkDevicePrivate * gdk_input_find_dev_from_ctx (HCTX hctx, UINT cursor) { GList *tmp_list = gdk_input_devices; GdkDevicePrivate *gdkdev; while (tmp_list) { gdkdev = (GdkDevicePrivate *) (tmp_list->data); if (gdkdev->hctx == hctx && gdkdev->cursor == cursor) return gdkdev; tmp_list = tmp_list->next; } return NULL; } static gint gdk_input_win32_other_event (GdkEvent *event, MSG *xevent) { GdkWindow *current_window; GdkInputWindow *input_window; GdkWindow *window; GdkWindowPrivate *window_private; GdkDevicePrivate *gdkdev; GdkEventMask masktest; POINT pt; PACKET packet; gint return_val; gint k; gint x, y; if (event->any.window != wintab_window) { g_warning ("gdk_input_win32_other_event: not wintab_window?"); return FALSE; } #if USE_SYSCONTEXT window = gdk_window_at_pointer (&x, &y); if (window == NULL) window = (GdkWindow *) gdk_root_parent; gdk_window_ref (window); window_private = (GdkWindowPrivate *) window; GDK_NOTE (EVENTS, g_print ("gdk_input_win32_other_event: window=%#x (%d,%d)\n", GDK_DRAWABLE_XID (window), x, y)); #else /* ??? This code is pretty bogus */ current_window = gdk_window_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 (xevent->message == WT_PACKET) { if (!WTPacket ((HCTX) xevent->lParam, xevent->wParam, &packet)) return FALSE; } switch (xevent->message) { case WT_PACKET: if (window_private == gdk_root_parent) { GDK_NOTE (EVENTS, g_print ("...is root\n")); return FALSE; } if ((gdkdev = gdk_input_find_dev_from_ctx ((HCTX) xevent->lParam, packet.pkCursor)) == NULL) return FALSE; if (gdkdev->info.mode == GDK_MODE_DISABLED) return FALSE; k = 0; if (gdkdev->pktdata & PK_X) gdkdev->last_axis_data[k++] = packet.pkX; if (gdkdev->pktdata & PK_Y) gdkdev->last_axis_data[k++] = packet.pkY; if (gdkdev->pktdata & PK_NORMAL_PRESSURE) gdkdev->last_axis_data[k++] = packet.pkNormalPressure; if (gdkdev->pktdata & PK_ORIENTATION) { decode_tilt (gdkdev->last_axis_data + k, gdkdev->orientation_axes, &packet); k += 2; } g_assert (k == gdkdev->info.num_axes); if (HIWORD (packet.pkButtons) != TBN_NONE) { /* Gdk buttons are numbered 1.. */ event->button.button = 1 + LOWORD (packet.pkButtons); if (HIWORD (packet.pkButtons) == TBN_UP) { event->any.type = GDK_BUTTON_RELEASE; masktest = GDK_BUTTON_RELEASE_MASK; gdkdev->button_state &= ~(1 << LOWORD (packet.pkButtons)); } else { event->any.type = GDK_BUTTON_PRESS; masktest = GDK_BUTTON_PRESS_MASK; gdkdev->button_state |= 1 << LOWORD (packet.pkButtons); } } else { event->any.type = GDK_MOTION_NOTIFY; masktest = GDK_POINTER_MOTION_MASK; if (gdkdev->button_state & (1 << 0)) masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK; if (gdkdev->button_state & (1 << 1)) masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON2_MOTION_MASK; if (gdkdev->button_state & (1 << 2)) masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK; } /* Now we can check if the window wants the event, and * propagate if necessary. */ dijkstra: if (!window_private->extension_events_selected || !(window_private->extension_events & masktest)) { GDK_NOTE (EVENTS, g_print ("...not selected\n")); if (window_private->parent == (GdkWindow *) gdk_root_parent) return FALSE; pt.x = x; pt.y = y; ClientToScreen (GDK_DRAWABLE_XID (window), &pt); gdk_window_unref (window); window = window_private->parent; gdk_window_ref (window); window_private = (GdkWindowPrivate *) window; ScreenToClient (GDK_DRAWABLE_XID (window), &pt); x = pt.x; y = pt.y; GDK_NOTE (EVENTS, g_print ("...propagating to %#x, (%d,%d)\n", GDK_DRAWABLE_XID (window), x, y)); goto dijkstra; } input_window = gdk_input_window_find (window); g_assert (input_window != NULL); if (gdkdev->info.mode == GDK_MODE_WINDOW && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR) return FALSE; event->any.window = window; if (event->any.type == GDK_BUTTON_PRESS || event->any.type == GDK_BUTTON_RELEASE) { event->button.time = xevent->time; event->button.source = gdkdev->info.source; last_moved_cursor_id = event->button.deviceid = gdkdev->info.deviceid; #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 gdk_input_translate_coordinates (gdkdev, input_window, gdkdev->last_axis_data, &event->button.x, &event->button.y, &event->button.pressure, &event->button.xtilt, &event->button.ytilt); event->button.state = ((gdkdev->button_state << 8) & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | GDK_BUTTON5_MASK)); GDK_NOTE (EVENTS, g_print ("WINTAB button %s: %d %d %g,%g %g %g,%g\n", (event->button.type == GDK_BUTTON_PRESS ? "press" : "release"), event->button.deviceid, event->button.button, event->button.x, event->button.y, event->button.pressure, event->button.xtilt, event->button.ytilt)); } else { event->motion.time = xevent->time; last_moved_cursor_id = event->motion.deviceid = gdkdev->info.deviceid; event->motion.is_hint = FALSE; event->motion.source = gdkdev->info.source; gdk_input_translate_coordinates (gdkdev, input_window, gdkdev->last_axis_data, &event->motion.x, &event->motion.y, &event->motion.pressure, &event->motion.xtilt, &event->motion.ytilt); event->motion.state = ((gdkdev->button_state << 8) & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | GDK_BUTTON5_MASK)); GDK_NOTE (EVENTS, g_print ("WINTAB motion: %d %g,%g %g %g,%g\n", event->motion.deviceid, event->motion.x, event->motion.y, event->motion.pressure, event->motion.xtilt, event->motion.ytilt)); /* Check for missing release or press events for the normal * pressure button. At least on my ArtPadII I sometimes miss a * release event? */ if ((gdkdev->pktdata & PK_NORMAL_PRESSURE && (event->motion.state & GDK_BUTTON1_MASK) && packet.pkNormalPressure <= MAX (0, gdkdev->npbtnmarks[0] - 2)) || (gdkdev->pktdata & PK_NORMAL_PRESSURE && !(event->motion.state & GDK_BUTTON1_MASK) && packet.pkNormalPressure > gdkdev->npbtnmarks[1] + 2)) { GdkEvent *event2 = gdk_event_copy (event); if (event->motion.state & GDK_BUTTON1_MASK) { event2->button.type = GDK_BUTTON_RELEASE; gdkdev->button_state &= ~1; } else { event2->button.type = GDK_BUTTON_PRESS; gdkdev->button_state |= 1; } event2->button.state = ((gdkdev->button_state << 8) & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | GDK_BUTTON5_MASK)); event2->button.button = 1; GDK_NOTE (EVENTS, g_print ("WINTAB synthesized button %s: %d %d %g,%g %g\n", (event2->button.type == GDK_BUTTON_PRESS ? "press" : "release"), event2->button.deviceid, event2->button.button, event2->button.x, event2->button.y, event2->button.pressure)); gdk_event_queue_append (event2); } } return TRUE; case WT_PROXIMITY: if (LOWORD (xevent->lParam) == 0) { event->proximity.type = GDK_PROXIMITY_OUT; gdk_input_ignore_core = FALSE; } else { event->proximity.type = GDK_PROXIMITY_IN; gdk_input_ignore_core = TRUE; } event->proximity.time = xevent->time; event->proximity.source = GDK_SOURCE_PEN; event->proximity.deviceid = last_moved_cursor_id; GDK_NOTE (EVENTS, g_print ("WINTAB proximity %s: %d\n", (event->proximity.type == GDK_PROXIMITY_IN ? "in" : "out"), event->proximity.deviceid)); return TRUE; } return FALSE; } static gint gdk_input_win32_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) { GdkWindowPrivate *window_private = (GdkWindowPrivate *) window; window_private->extension_events_selected = TRUE; return TRUE; } static gint gdk_input_win32_disable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) { GdkWindowPrivate *window_private = (GdkWindowPrivate *) window; window_private->extension_events_selected = FALSE; return TRUE; } static gint gdk_input_win32_grab_pointer (GdkWindow *window, gint owner_events, GdkEventMask event_mask, GdkWindow *confine_to, guint32 time) { GdkInputWindow *input_window, *new_window; gboolean need_ungrab; GdkDevicePrivate *gdkdev; GList *tmp_list; gint result; tmp_list = gdk_input_windows; new_window = NULL; need_ungrab = FALSE; GDK_NOTE (MISC, g_print ("gdk_input_win32_grab_pointer: %#x %d %#x\n", GDK_DRAWABLE_XID (window), owner_events, (confine_to ? GDK_DRAWABLE_XID (confine_to) : 0))); while (tmp_list) { input_window = (GdkInputWindow *)tmp_list->data; if (input_window->window == window) new_window = input_window; else if (input_window->grabbed) { input_window->grabbed = FALSE; need_ungrab = TRUE; } tmp_list = tmp_list->next; } if (new_window) { new_window->grabbed = TRUE; tmp_list = gdk_input_devices; while (tmp_list) { gdkdev = (GdkDevicePrivate *)tmp_list->data; if (gdkdev->info.deviceid != GDK_CORE_POINTER) { #if 0 /* XXX */ gdk_input_find_events (window, gdkdev, event_mask, event_classes, &num_classes); result = XGrabDevice (GDK_DISPLAY(), gdkdev->xdevice, GDK_WINDOW_XWINDOW (window), owner_events, num_classes, event_classes, GrabModeAsync, GrabModeAsync, time); /* FIXME: if failure occurs on something other than the first device, things will be badly inconsistent */ if (result != Success) return result; #endif } tmp_list = tmp_list->next; } } else { tmp_list = gdk_input_devices; while (tmp_list) { gdkdev = (GdkDevicePrivate *)tmp_list->data; if (gdkdev->info.deviceid != GDK_CORE_POINTER && ((gdkdev->button_state != 0) || need_ungrab)) { #if 0 /* XXX */ XUngrabDevice (gdk_display, gdkdev->xdevice, time); #endif gdkdev->button_state = 0; } tmp_list = tmp_list->next; } } return Success; } static void gdk_input_win32_ungrab_pointer (guint32 time) { GdkInputWindow *input_window; GdkDevicePrivate *gdkdev; GList *tmp_list; GDK_NOTE (MISC, g_print ("gdk_input_win32_ungrab_pointer\n")); tmp_list = gdk_input_windows; while (tmp_list) { input_window = (GdkInputWindow *)tmp_list->data; if (input_window->grabbed) break; tmp_list = tmp_list->next; } if (tmp_list) /* we found a grabbed window */ { input_window->grabbed = FALSE; tmp_list = gdk_input_devices; while (tmp_list) { gdkdev = (GdkDevicePrivate *)tmp_list->data; #if 0 /* XXX */ if (gdkdev->info.deviceid != GDK_CORE_POINTER && gdkdev->xdevice) XUngrabDevice (gdk_display, gdkdev->xdevice, time); #endif tmp_list = tmp_list->next; } } } #endif /* HAVE_WINTAB */ GList * gdk_input_list_devices (void) { return gdk_input_devices; } void gdk_input_set_source (guint32 deviceid, GdkInputSource source) { GdkDevicePrivate *gdkdev = gdk_input_find_device (deviceid); g_return_if_fail (gdkdev != NULL); gdkdev->info.source = source; } void gdk_input_set_key (guint32 deviceid, guint index, guint keyval, GdkModifierType modifiers) { if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_key) gdk_input_vtable.set_key (deviceid, index, keyval, modifiers); } GdkTimeCoord * gdk_input_motion_events (GdkWindow *window, guint32 deviceid, guint32 start, guint32 stop, gint *nevents_return) { g_return_val_if_fail (window != NULL, NULL); if (GDK_DRAWABLE_DESTROYED (window)) return NULL; *nevents_return = 0; return NULL; /* ??? */ } static gint gdk_input_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) { if (gdk_input_vtable.enable_window) return gdk_input_vtable.enable_window (window, gdkdev); else return TRUE; } static gint gdk_input_disable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) { if (gdk_input_vtable.disable_window) return gdk_input_vtable.disable_window(window,gdkdev); else return TRUE; } static GdkInputWindow * gdk_input_window_find (GdkWindow *window) { GList *tmp_list; for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next) if (((GdkInputWindow *)(tmp_list->data))->window == window) return (GdkInputWindow *)(tmp_list->data); return NULL; /* Not found */ } #if !USE_SYSCONTEXT static GdkInputWindow * gdk_input_window_find_within (GdkWindow *window) { GList *tmp_list; GdkWindowPrivate *window_private; GdkWindowPrivate *tmp_private; GdkInputWindow *candidate = NULL; window_private = (GdkWindowPrivate *) window; for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next) { (GdkWindowPrivate *) tmp_private = (GdkWindowPrivate *) (((GdkInputWindow *)(tmp_list->data))->window); if (tmp_private == window_private || IsChild (window_private->xwindow, tmp_private->xwindow)) { if (candidate) return NULL; /* Multiple hits */ candidate = (GdkInputWindow *)(tmp_list->data); } } return candidate; } #endif /* FIXME: this routine currently needs to be called between creation and the corresponding configure event (because it doesn't get the root_relative_geometry). This should work with gtk_window_set_extension_events, but will likely fail in other cases */ void gdk_input_set_extension_events (GdkWindow *window, gint mask, GdkExtensionMode mode) { GdkWindowPrivate *window_private; GList *tmp_list; GdkInputWindow *iw; g_return_if_fail (window != NULL); if (GDK_DRAWABLE_DESTROYED (window)) return; window_private = (GdkWindowPrivate *) window; if (mode == GDK_EXTENSION_EVENTS_NONE) mask = 0; if (mask != 0) { iw = g_new (GdkInputWindow,1); iw->window = window; iw->mode = mode; iw->grabbed = FALSE; gdk_input_windows = g_list_append (gdk_input_windows, iw); window_private->extension_events = mask; /* Add enter window events to the event mask */ gdk_window_set_events (window, gdk_window_get_events (window) | GDK_ENTER_NOTIFY_MASK); } else { iw = gdk_input_window_find (window); if (iw) { gdk_input_windows = g_list_remove (gdk_input_windows, iw); g_free (iw); } window_private->extension_events = 0; } for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) { GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data); if (gdkdev->info.deviceid != GDK_CORE_POINTER) { if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL)) gdk_input_enable_window (window, gdkdev); else gdk_input_disable_window (window, gdkdev); } } } void gdk_input_window_destroy (GdkWindow *window) { GdkInputWindow *input_window; input_window = gdk_input_window_find (window); g_return_if_fail (input_window != NULL); gdk_input_windows = g_list_remove (gdk_input_windows,input_window); g_free (input_window); } void gdk_input_exit (void) { #ifdef HAVE_WINTAB GList *tmp_list; GdkDevicePrivate *gdkdev; for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) { gdkdev = (GdkDevicePrivate *)(tmp_list->data); if (gdkdev->info.deviceid != GDK_CORE_POINTER) { gdk_input_win32_set_mode (gdkdev->info.deviceid, GDK_MODE_DISABLED); g_free (gdkdev->info.name); g_free (gdkdev->last_axis_data); g_free (gdkdev->info.axes); g_free (gdkdev->info.keys); g_free (gdkdev->axes); g_free (gdkdev); } } g_list_free (gdk_input_devices); for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) { g_free (tmp_list->data); } g_list_free (gdk_input_windows); gdk_input_windows = NULL; gdk_window_unref (wintab_window); wintab_window = NULL; #if 1 for (tmp_list = wintab_contexts; tmp_list; tmp_list = tmp_list->next) { HCTX *hctx = (HCTX *) tmp_list->data; BOOL result; #ifdef _MSC_VER /* For some reason WTEnable and/or WTClose tend to crash here. * Protect with __try/__except to avoid a message box. * When compiling with gcc, we cannot use __try/__except, so * don't call WTClose. I think this means that we'll * eventually run out of Wintab contexts, sigh. */ __try { #if 0 WTEnable (*hctx, FALSE); #endif result = WTClose (*hctx); } __except (/* GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? */ EXCEPTION_EXECUTE_HANDLER /*: EXCEPTION_CONTINUE_SEARCH */) { result = FALSE; } if (!result) g_warning ("gdk_input_exit: Closing Wintab context %#x failed", *hctx); #endif /* _MSC_VER */ g_free (hctx); } #endif g_list_free (wintab_contexts); wintab_contexts = NULL; #endif } static GdkDevicePrivate * gdk_input_find_device (guint32 id) { GList *tmp_list = gdk_input_devices; GdkDevicePrivate *gdkdev; while (tmp_list) { gdkdev = (GdkDevicePrivate *) (tmp_list->data); if (gdkdev->info.deviceid == id) return gdkdev; tmp_list = tmp_list->next; } return NULL; } void gdk_input_window_get_pointer (GdkWindow *window, guint32 deviceid, gdouble *x, gdouble *y, gdouble *pressure, gdouble *xtilt, gdouble *ytilt, GdkModifierType *mask) { if (gdk_input_vtable.get_pointer) gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure, xtilt, ytilt, mask); }