diff options
author | Elliot Lee <sopwith@src.gnome.org> | 1997-11-24 22:37:52 +0000 |
---|---|---|
committer | Elliot Lee <sopwith@src.gnome.org> | 1997-11-24 22:37:52 +0000 |
commit | 9508b76bd2401b6b9e289b5c8ec9fc0e08909283 (patch) | |
tree | 53c88a9e5ac09e1a027e56df33bdaa66d670901b /gdk/gdkinputcommon.h | |
download | gdk-pixbuf-9508b76bd2401b6b9e289b5c8ec9fc0e08909283.tar.gz |
Initial revision
Diffstat (limited to 'gdk/gdkinputcommon.h')
-rw-r--r-- | gdk/gdkinputcommon.h | 687 |
1 files changed, 687 insertions, 0 deletions
diff --git a/gdk/gdkinputcommon.h b/gdk/gdkinputcommon.h new file mode 100644 index 000000000..5e457e0aa --- /dev/null +++ b/gdk/gdkinputcommon.h @@ -0,0 +1,687 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if defined(XINPUT_GXI) || defined(XINPUT_XFREE) + +/* Forward declarations */ +static void gdk_input_get_root_relative_geometry (Display *dpy, Window w, + int *x_ret, int *y_ret, + int *width_ret, + int *height_ret); +static GdkDevicePrivate *gdk_input_device_new(XDeviceInfo *device, + gint include_core); +static void gdk_input_common_find_events(GdkWindow *window, + GdkDevicePrivate *gdkdev, + gint mask, + XEventClass *classes, + int *num_classes); +static void gdk_input_common_select_events(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static void gdk_input_translate_coordinates(GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, gdouble *y, + gdouble *pressure, + gdouble *xtilt, gdouble *ytilt); +static guint gdk_input_translate_state(guint state, guint device_state); +static gint gdk_input_common_init(gint include_core); +static gint gdk_input_common_other_event (GdkEvent *event, + XEvent *xevent, + GdkInputWindow *input_window, + GdkDevicePrivate *gdkdev); +static void gdk_input_common_set_axes (guint32 deviceid, GdkAxisUse *axes); +static GdkTimeCoord * gdk_input_common_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); +static void gdk_input_common_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +/* Global variables */ + +static gint gdk_input_root_width; +static gint gdk_input_root_height; + +static void +gdk_input_get_root_relative_geometry(Display *dpy, Window w, int *x_ret, int *y_ret, + int *width_ret, int *height_ret) +{ + Window root,parent; + Window *children; + int nchildren; + int x,y,width,height; + int xc,yc,widthc,heightc,border_widthc,depthc; + + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + XGetGeometry(dpy,w,&root,&x,&y,&width,&height,&border_widthc, + &depthc); + x += border_widthc; + y += border_widthc; + + while (root != parent) + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + XGetGeometry(dpy,w,&root,&xc,&yc,&widthc,&heightc, + &border_widthc,&depthc); + x += xc + border_widthc; + y += yc + border_widthc; + } + + if (x_ret) + *x_ret = x; + if (y_ret) + *y_ret = y; + if (width_ret) + *width_ret = width; + if (height_ret) + *height_ret = height; +} + +static GdkDevicePrivate * +gdk_input_device_new(XDeviceInfo *device, gint include_core) +{ + GdkDevicePrivate *gdkdev; + gchar *tmp_name, *p; + XAnyClassPtr class; + gint i,j; + + gdkdev = g_new(GdkDevicePrivate,1); + + gdkdev->info.deviceid = device->id; + if (device->name[0]) { + gdkdev->info.name = g_new(char, strlen(device->name)+1); + strcpy(gdkdev->info.name,device->name); + } else { + /* XFree86 3.2 gives an empty name to the default core devices, + (fixed in 3.2A) */ + gdkdev->info.name = g_strdup("pointer"); + strcpy(gdkdev->info.name,"pointer"); + gdkdev->info.source = GDK_SOURCE_MOUSE; + } + + gdkdev->info.mode = GDK_MODE_DISABLED; + + /* Try to figure out what kind of device this is by its name - + could invite a very, very, long list... Lowercase name + for comparison purposes */ + + tmp_name = g_strdup(gdkdev->info.name); + for (p = tmp_name; *p; p++) + { + if (*p >= 'A' && *p <= 'Z') + *p += 'a' - 'A'; + } + + if (!strcmp (tmp_name, "pointer")) + gdkdev->info.source = GDK_SOURCE_MOUSE; + else if (!strcmp (tmp_name, "wacom") || + !strcmp (tmp_name, "pen")) + gdkdev->info.source = GDK_SOURCE_PEN; + else if (!strcmp (tmp_name, "eraser")) + gdkdev->info.source = GDK_SOURCE_ERASER; + else if (!strcmp (tmp_name, "cursor")) + gdkdev->info.source = GDK_SOURCE_CURSOR; + else + gdkdev->info.source = GDK_SOURCE_PEN; + + g_free(tmp_name); + + gdkdev->xdevice = NULL; + + /* step through the classes */ + + gdkdev->info.num_axes = 0; + gdkdev->axes = 0; + gdkdev->info.has_cursor = 0; + gdkdev->needs_update = FALSE; + gdkdev->claimed = FALSE; + gdkdev->button_state = 0; + + class = device->inputclassinfo; + for (i=0;i<device->num_classes;i++) + { + switch (class->class) { + case ButtonClass: + { + break; + } + case ValuatorClass: + { + XValuatorInfo *xvi = (XValuatorInfo *)class; + gdkdev->info.num_axes = xvi->num_axes; + gdkdev->axes = g_new(GdkAxisInfo, xvi->num_axes); + gdkdev->info.axes = g_new(GdkAxisUse, xvi->num_axes); + for (j=0;j<xvi->num_axes;j++) + { + gdkdev->axes[j].resolution = + gdkdev->axes[j].xresolution = xvi->axes[j].resolution; + gdkdev->axes[j].min_value = + gdkdev->axes[j].xmin_value = xvi->axes[j].min_value; + gdkdev->axes[j].max_value = + gdkdev->axes[j].xmax_value = xvi->axes[j].max_value; + gdkdev->info.axes[j] = GDK_AXIS_IGNORE; + } + j=0; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_X; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_Y; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_PRESSURE; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_XTILT; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_YTILT; + + /* set up reverse lookup on axis use */ + for (j=GDK_AXIS_IGNORE;j<GDK_AXIS_LAST;j++) + gdkdev->axis_for_use[j] = -1; + + for (j=0;j<xvi->num_axes;j++) + if (gdkdev->info.axes[j] != GDK_AXIS_IGNORE) + gdkdev->axis_for_use[gdkdev->info.axes[j]] = j; + + break; + } + } + class = (XAnyClassPtr)(((char *)class) + class->length); + } + /* return NULL if no axes */ + if (!gdkdev->info.num_axes || !gdkdev->axes || + (!include_core && device->use == IsXPointer)) + { + g_free(gdkdev->info.name); + if (gdkdev->axes) + g_free(gdkdev->axes); + g_free(gdkdev); + return NULL; + } + + if (device->use != IsXPointer) + gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid); + + return gdkdev; +} + +static void +gdk_input_common_find_events(GdkWindow *window, + GdkDevicePrivate *gdkdev, + gint mask, + XEventClass *classes, + int *num_classes) +{ + gint i; + XEventClass class; + + i = 0; + /* We have to track press and release events in pairs to keep + track of button state correctly and implement grabbing */ + if (mask & GDK_BUTTON_PRESS_MASK || mask & GDK_BUTTON_RELEASE_MASK) + { + DeviceButtonPress (gdkdev->xdevice, gdkdev->buttonpress_type, + class); + if (class != 0) + classes[i++] = class; + DeviceButtonRelease (gdkdev->xdevice, gdkdev->buttonrelease_type, + class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_POINTER_MOTION_MASK) + { + DeviceMotionNotify (gdkdev->xdevice, gdkdev->motionnotify_type, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_POINTER_MOTION_HINT_MASK) + { + /* We'll get into trouble if the macros change, but at least we'll + know about it, and we avoid warnings now */ + DevicePointerMotionHint (gdkdev->xdevice, 0, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_PROXIMITY_IN_MASK) + { + ProximityIn (gdkdev->xdevice, gdkdev->proximityin_type, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_PROXIMITY_OUT_MASK) + { + ProximityOut (gdkdev->xdevice, gdkdev->proximityout_type, class); + if (class != 0) + classes[i++] = class; + } + + *num_classes = i; +} + +static void +gdk_input_common_select_events(GdkWindow *window, + GdkDevicePrivate *gdkdev) +{ + XEventClass classes[6]; + gint num_classes; + + if (gdkdev->info.mode == GDK_MODE_DISABLED) + gdk_input_common_find_events(window, gdkdev, 0, classes, &num_classes); + else + gdk_input_common_find_events(window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + classes, &num_classes); + + XSelectExtensionEvent (gdk_display, + GDK_WINDOW_XWINDOW(window), + classes, num_classes); +} + +gint +gdk_input_common_init(gint include_core) +{ + char **extensions; + XDeviceInfo *devices; + int num_devices; + int num_extensions, loop; + Display *display = gdk_display; + + /* Init global vars */ + gdk_window_get_geometry(NULL, /* use root window */ + NULL,NULL, + &gdk_input_root_width,&gdk_input_root_height, + NULL); + + /* Init XInput extension */ + + extensions = XListExtensions(display, &num_extensions); + for (loop = 0; loop < num_extensions && + (strcmp(extensions[loop], "XInputExtension") != 0); loop++); + XFreeExtensionList(extensions); + if (loop == num_extensions) /* XInput extension not found */ + return FALSE; + + gdk_input_devices = 0; + devices = XListInputDevices(display, &num_devices); + + for(loop=0; loop<num_devices; loop++) + { + GdkDevicePrivate *gdkdev = gdk_input_device_new(&devices[loop], + include_core); + if (gdkdev) + gdk_input_devices = g_list_append(gdk_input_devices, gdkdev); + } + XFreeDeviceList(devices); + + gdk_input_devices = g_list_append (gdk_input_devices, &gdk_input_core_info); + + return TRUE; +} + +static void +gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, gdouble *y, gdouble *pressure, + gdouble *xtilt, gdouble *ytilt) +{ + GdkWindowPrivate *win_priv; + + int x_axis, y_axis, pressure_axis, xtilt_axis, ytilt_axis; + + double device_width, device_height; + double x_offset, y_offset, x_scale, y_scale; + + win_priv = (GdkWindowPrivate *) 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 * win_priv->width >= win_priv->height) + { + /* device taller than window */ + x_scale = win_priv->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 - + win_priv->height)/2; + } + else + { + /* window taller than device */ + y_scale = win_priv->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 - win_priv->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; + } +} + +/* combine the state of the core device and the device state + into one - for now we do this in a simple-minded manner - + we just take the keyboard portion of the core device and + the button portion (all of?) the device state. + Any button remapping should go on here. */ +static guint +gdk_input_translate_state(guint state, guint device_state) +{ + return device_state | (state & 0xFF); +} + +static gint +gdk_input_common_other_event (GdkEvent *event, + XEvent *xevent, + GdkInputWindow *input_window, + GdkDevicePrivate *gdkdev) +{ + if ((xevent->type == gdkdev->buttonpress_type) || + (xevent->type == gdkdev->buttonrelease_type)) + { + XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *)(xevent); + + if (xdbe->type == gdkdev->buttonpress_type) + { + event->button.type = GDK_BUTTON_PRESS; + gdkdev->button_state |= 1 << xdbe->button; + } + else + { + event->button.type = GDK_BUTTON_RELEASE; + gdkdev->button_state &= ~(1 << xdbe->button); + } + event->button.window = input_window->window; + event->button.time = xdbe->time; + event->button.source = gdkdev->info.source; + event->button.deviceid = xdbe->deviceid; + + gdk_input_translate_coordinates (gdkdev,input_window, xdbe->axis_data, + &event->button.x,&event->button.y, + &event->button.pressure, + &event->button.xtilt, + &event->button.ytilt); + event->button.state = gdk_input_translate_state(xdbe->state,xdbe->device_state); + event->button.button = xdbe->button; + + return TRUE; + } + + if (xevent->type == gdkdev->motionnotify_type) + { + XDeviceMotionEvent *xdme = (XDeviceMotionEvent *)(xevent); + + gdk_input_translate_coordinates(gdkdev,input_window,xdme->axis_data, + &event->motion.x,&event->motion.y, + &event->motion.pressure, + &event->motion.xtilt, + &event->motion.ytilt); + + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = input_window->window; + event->motion.time = xdme->time; + event->motion.deviceid = xdme->deviceid; + event->motion.state = gdk_input_translate_state(xdme->state, + xdme->device_state); + event->motion.source = gdkdev->info.source; + event->motion.deviceid = xdme->deviceid; + + if (gdk_show_events) + g_print ("motion notify:\t\twindow: %ld device: %ld x,y: %f %f hint: %s\n", + xdme->window, + xdme->deviceid, + event->motion.x, event->motion.y, + (xevent->xmotion.is_hint) ? "true" : "false"); + + + return TRUE; + } + + if (xevent->type == gdkdev->proximityin_type || + xevent->type == gdkdev->proximityout_type) + { + XProximityNotifyEvent *xpne = (XProximityNotifyEvent *)(xevent); + + event->proximity.type = (xevent->type == gdkdev->proximityin_type)? + GDK_PROXIMITY_IN:GDK_PROXIMITY_OUT; + event->proximity.window = input_window->window; + event->proximity.time = xpne->time; + event->proximity.source = gdkdev->info.source; + event->proximity.deviceid = xpne->deviceid; + + return TRUE; + } + + return -1; /* wasn't one of our event types */ +} + +static void +gdk_input_common_set_axes (guint32 deviceid, GdkAxisUse *axes) +{ + int i; + GdkDevicePrivate *gdkdev = gdk_input_find_device(deviceid); + g_return_if_fail (gdkdev != NULL); + + 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 GdkTimeCoord * +gdk_input_common_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + GdkTimeCoord *coords; + XDeviceTimeCoord *device_coords; + GdkInputWindow *input_window; + GdkDevicePrivate *gdkdev; + + int mode_return; + int axis_count_return; + int i; + + gdkdev = gdk_input_find_device (deviceid); + input_window = gdk_input_window_find (window); + + g_return_val_if_fail (gdkdev != NULL, NULL); + g_return_val_if_fail (gdkdev->xdevice != NULL, NULL); + g_return_val_if_fail (input_window != NULL, NULL); + + device_coords = XGetDeviceMotionEvents (gdk_display, + gdkdev->xdevice, + start, stop, + nevents_return, &mode_return, + &axis_count_return); + + if (device_coords) + { + coords = g_new (GdkTimeCoord, *nevents_return); + + for (i=0; i<*nevents_return; i++) + { + gdk_input_translate_coordinates (gdkdev, input_window, + device_coords[i].data, + &coords[i].x, &coords[i].y, + &coords[i].pressure, + &coords[i].xtilt, &coords[i].ytilt); + } + XFreeDeviceMotionEvents (device_coords); + + return coords; + } + else + return NULL; +} + +static void +gdk_input_common_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + GdkDevicePrivate *gdkdev; + GdkInputWindow *input_window; + XDeviceState *state; + XInputClass *input_class; + gint x_int, y_int; + gint i; + + /* we probably need to get the mask in any case */ + + 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); + input_window = gdk_input_window_find (window); + + g_return_if_fail (gdkdev != NULL); + g_return_if_fail (gdkdev->xdevice != NULL); + g_return_if_fail (input_window != NULL); + + state = XQueryDeviceState (gdk_display, gdkdev->xdevice); + input_class = state->data; + for (i=0; i<state->num_classes; i++) + { + switch (input_class->class) + { + case ValuatorClass: + gdk_input_translate_coordinates(gdkdev, input_window, + ((XValuatorState *)input_class)->valuators, + x, y, pressure, + xtilt, ytilt); + + + break; + case ButtonClass: + if (mask) + { + *mask &= ~(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | + GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | + GDK_BUTTON5_MASK); + for (i=0; i < ((XButtonState *)input_class)->num_buttons; i++) + { + if (((XButtonState *)input_class)->buttons[i]) + *mask |= GDK_BUTTON1_MASK << i; + } + } + break; + } + input_class = (XInputClass *)(((char *)input_class)+input_class->length); + } + } +} + +#endif |