summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac17
-rw-r--r--docs/reference/gdk/gdk-docs.sgml2
-rw-r--r--docs/reference/gdk/gdk3-sections.txt68
-rw-r--r--docs/reference/gdk/gdk3.types2
-rw-r--r--docs/reference/gdk/tmpl/input_devices.sgml309
-rw-r--r--docs/reference/gtk/compiling.sgml7
-rw-r--r--docs/reference/gtk/gtk-docs.sgml1
-rw-r--r--docs/reference/gtk/gtk3-sections.txt28
-rw-r--r--gdk/Makefile.am5
-rw-r--r--gdk/gdk.c23
-rw-r--r--gdk/gdk.h15
-rw-r--r--gdk/gdk.symbols210
-rw-r--r--gdk/gdkdevice.c1399
-rw-r--r--gdk/gdkdevice.h292
-rw-r--r--gdk/gdkdevicemanager.c302
-rw-r--r--gdk/gdkdevicemanager.h76
-rw-r--r--gdk/gdkdeviceprivate.h135
-rw-r--r--gdk/gdkdisplay.c1099
-rw-r--r--gdk/gdkdisplay.h108
-rw-r--r--gdk/gdkdnd.h5
-rw-r--r--gdk/gdkevents.c317
-rw-r--r--gdk/gdkevents.h46
-rw-r--r--gdk/gdkglobals.c1
-rw-r--r--gdk/gdkinput.h148
-rw-r--r--gdk/gdkinternals.h106
-rw-r--r--gdk/gdkoffscreenwindow.c35
-rw-r--r--gdk/gdktypes.h44
-rw-r--r--gdk/gdkwindow.c1116
-rw-r--r--gdk/gdkwindow.h32
-rw-r--r--gdk/gdkwindowimpl.h14
-rw-r--r--gdk/quartz/Makefile.am2
-rw-r--r--gdk/quartz/gdkdevice-core.c356
-rw-r--r--gdk/quartz/gdkdevice-core.h51
-rw-r--r--gdk/quartz/gdkdevicemanager-core.c130
-rw-r--r--gdk/quartz/gdkdevicemanager-core.h54
-rw-r--r--gdk/quartz/gdkdisplay-quartz.c11
-rw-r--r--gdk/quartz/gdkevents-quartz.c460
-rw-r--r--gdk/quartz/gdkinput.c367
-rw-r--r--gdk/quartz/gdkinputprivate.h5
-rw-r--r--gdk/quartz/gdkprivate-quartz.h3
-rw-r--r--gdk/quartz/gdkwindow-quartz.c132
-rw-r--r--gdk/win32/Makefile.am8
-rw-r--r--gdk/win32/gdkdevice-win32.c396
-rw-r--r--gdk/win32/gdkdevice-win32.h51
-rw-r--r--gdk/win32/gdkdevice-wintab.c386
-rw-r--r--gdk/win32/gdkdevice-wintab.h79
-rw-r--r--gdk/win32/gdkdevicemanager-win32.c1089
-rw-r--r--gdk/win32/gdkdevicemanager-win32.h59
-rw-r--r--gdk/win32/gdkdnd-win32.c222
-rw-r--r--gdk/win32/gdkevents-win32.c266
-rw-r--r--gdk/win32/gdkinput-win32.c1392
-rw-r--r--gdk/win32/gdkinput-win32.h147
-rw-r--r--gdk/win32/gdkinput.c441
-rw-r--r--gdk/win32/gdkmain-win32.c3
-rw-r--r--gdk/win32/gdkwindow-win32.c246
-rw-r--r--gdk/x11/Makefile.am18
-rw-r--r--gdk/x11/gdkdevice-core.c501
-rw-r--r--gdk/x11/gdkdevice-core.h52
-rw-r--r--gdk/x11/gdkdevice-xi.c624
-rw-r--r--gdk/x11/gdkdevice-xi.h88
-rw-r--r--gdk/x11/gdkdevice-xi2.c621
-rw-r--r--gdk/x11/gdkdevice-xi2.h64
-rw-r--r--gdk/x11/gdkdevicemanager-core.c904
-rw-r--r--gdk/x11/gdkdevicemanager-core.h54
-rw-r--r--gdk/x11/gdkdevicemanager-x11.c76
-rw-r--r--gdk/x11/gdkdevicemanager-xi.c650
-rw-r--r--gdk/x11/gdkdevicemanager-xi.h58
-rw-r--r--gdk/x11/gdkdevicemanager-xi2.c1146
-rw-r--r--gdk/x11/gdkdevicemanager-xi2.h61
-rw-r--r--gdk/x11/gdkdisplay-x11.c1303
-rw-r--r--gdk/x11/gdkdnd-x11.c127
-rw-r--r--gdk/x11/gdkevents-x11.c3088
-rw-r--r--gdk/x11/gdkeventsource.c427
-rw-r--r--gdk/x11/gdkeventsource.h46
-rw-r--r--gdk/x11/gdkeventtranslator.c100
-rw-r--r--gdk/x11/gdkeventtranslator.h65
-rw-r--r--gdk/x11/gdkinput-none.c126
-rw-r--r--gdk/x11/gdkinput-x11.c937
-rw-r--r--gdk/x11/gdkinput-xfree.c422
-rw-r--r--gdk/x11/gdkinput.c547
-rw-r--r--gdk/x11/gdkinputprivate.h189
-rw-r--r--gdk/x11/gdkmain-x11.c266
-rw-r--r--gdk/x11/gdkprivate-x11.h7
-rw-r--r--gdk/x11/gdkscreen-x11.c656
-rw-r--r--gdk/x11/gdkwindow-x11.c426
-rw-r--r--gdk/x11/gdkwindow-x11.h2
-rw-r--r--gtk/gtk.symbols12
-rw-r--r--gtk/gtkaboutdialog.c42
-rw-r--r--gtk/gtkbutton.c34
-rw-r--r--gtk/gtkcellrendereraccel.c89
-rw-r--r--gtk/gtkcolorsel.c98
-rw-r--r--gtk/gtkcombobox.c122
-rw-r--r--gtk/gtkcombobox.h2
-rw-r--r--gtk/gtkdnd.c155
-rw-r--r--gtk/gtkentry.c15
-rw-r--r--gtk/gtkentrycompletion.c34
-rw-r--r--gtk/gtkentryprivate.h5
-rw-r--r--gtk/gtkhandlebox.c38
-rw-r--r--gtk/gtkiconview.c21
-rw-r--r--gtk/gtklabel.c9
-rw-r--r--gtk/gtkmain.c258
-rw-r--r--gtk/gtkmain.h7
-rw-r--r--gtk/gtkmarshalers.list1
-rw-r--r--gtk/gtkmenu.c246
-rw-r--r--gtk/gtkmenu.h9
-rw-r--r--gtk/gtkmenushell.c51
-rw-r--r--gtk/gtkmenushell.h8
-rw-r--r--gtk/gtknotebook.c13
-rw-r--r--gtk/gtkpaned.c31
-rw-r--r--gtk/gtkplug-x11.c72
-rw-r--r--gtk/gtkprivate.h1
-rw-r--r--gtk/gtkrange.c77
-rw-r--r--gtk/gtkscalebutton.c144
-rw-r--r--gtk/gtksocket.c2
-rw-r--r--gtk/gtkspinbutton.c6
-rw-r--r--gtk/gtktextview.c56
-rw-r--r--gtk/gtktooltip.c14
-rw-r--r--gtk/gtktreeprivate.h3
-rw-r--r--gtk/gtktreeview.c86
-rw-r--r--gtk/gtktreeviewcolumn.c3
-rw-r--r--gtk/gtkwidget.c516
-rw-r--r--gtk/gtkwidget.h30
-rw-r--r--gtk/gtkwindow.c232
-rw-r--r--gtk/gtkwindow.h14
124 files changed, 18197 insertions, 10328 deletions
diff --git a/configure.ac b/configure.ac
index a99e7d2e34..e4fa2428f1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1560,22 +1560,22 @@ if test "x$gdktarget" = "xx11"; then
fi
# set up things for XInput
-
- if test "x$with_xinput" = "xxfree" || test "x$with_xinput" = "xyes"; then
+ if test "x$with_xinput" != "xno" && $PKG_CONFIG --exists "xi" ; then
AC_DEFINE(XINPUT_XFREE, 1,
[Define to 1 if XFree XInput should be used])
- if $PKG_CONFIG --exists xi ; then
- X_PACKAGES="$X_PACKAGES xi"
- else
- GTK_ADD_LIB(x_extra_libs, Xi)
- fi
+ X_PACKAGES="$X_PACKAGES xi"
+
+ AC_CHECK_HEADER(X11/extensions/XInput2.h,
+ have_xinput2=yes; AC_DEFINE(XINPUT_2, 1, [Define to 1 if XInput 2.0 is available]))
else
AC_DEFINE(XINPUT_NONE, 1,
[Define to 1 if no XInput should be used])
fi
- AM_CONDITIONAL(XINPUT_XFREE, test x$with_xinput = xxfree || test x$with_xinput = xyes)
+ AM_CONDITIONAL(XINPUT_NONE, test "x$with_xinput" = "xno")
+ AM_CONDITIONAL(XINPUT_XFREE, test "x$with_xinput" != "xno")
+ AM_CONDITIONAL(XINPUT_2, test "x$have_xinput2" = "xyes")
# Check for the RANDR extension
if $PKG_CONFIG --exists "xrandr >= 1.2.99" ; then
@@ -1633,6 +1633,7 @@ else
XPACKAGES=
AM_CONDITIONAL(XINPUT_XFREE, false)
+ AM_CONDITIONAL(XINPUT_2, false)
AM_CONDITIONAL(USE_X11, false)
AM_CONDITIONAL(HAVE_X11R6, false)
fi
diff --git a/docs/reference/gdk/gdk-docs.sgml b/docs/reference/gdk/gdk-docs.sgml
index 81fd772b7b..a0a295d105 100644
--- a/docs/reference/gdk/gdk-docs.sgml
+++ b/docs/reference/gdk/gdk-docs.sgml
@@ -53,7 +53,7 @@
<xi:include href="xml/threads.xml" />
<xi:include href="xml/input.xml" />
- <xi:include href="xml/input_devices.xml" />
+ <xi:include href="xml/gdkdevicemanager.xml" />
<xi:include href="xml/pango_interaction.xml" />
<xi:include href="xml/cairo_interaction.xml" />
diff --git a/docs/reference/gdk/gdk3-sections.txt b/docs/reference/gdk/gdk3-sections.txt
index e9be5c5f52..903e9b8f64 100644
--- a/docs/reference/gdk/gdk3-sections.txt
+++ b/docs/reference/gdk/gdk3-sections.txt
@@ -81,6 +81,7 @@ gdk_filter_return_get_type
gdk_font_type_get_type
gdk_function_get_type
gdk_gc_values_mask_get_type
+gdk_grab_ownership_get_type
gdk_grab_status_get_type
gdk_gravity_get_type
gdk_image_type_get_type
@@ -110,8 +111,7 @@ gdk_window_type_get_type
gdk_window_type_hint_get_type
gdk_wm_decoration_get_type
gdk_wm_function_get_type
-gdk_pointer_grab_info_libgtk_only
-gdk_keyboard_grab_info_libgtk_only
+gdk_device_grab_info_libgtk_only
gdk_add_option_entries_libgtk_only
gdk_pre_parse_libgtk_only
</SECTION>
@@ -126,9 +126,11 @@ gdk_display_get_name
gdk_display_get_n_screens
gdk_display_get_screen
gdk_display_get_default_screen
+gdk_display_get_device_manager
gdk_display_pointer_ungrab
gdk_display_keyboard_ungrab
gdk_display_pointer_is_grabbed
+gdk_display_device_is_grabbed
gdk_display_beep
gdk_display_sync
gdk_display_flush
@@ -141,10 +143,15 @@ gdk_display_add_client_message_filter
gdk_display_set_double_click_time
gdk_display_set_double_click_distance
gdk_display_get_pointer
+gdk_display_get_device_state
gdk_display_get_window_at_pointer
+gdk_display_get_window_at_device_position
GdkDisplayPointerHooks
gdk_display_set_pointer_hooks
+GdkDisplayDeviceHooks
+gdk_display_set_device_hooks
gdk_display_warp_pointer
+gdk_display_warp_device
gdk_display_supports_cursor_color
gdk_display_supports_cursor_alpha
gdk_display_get_default_cursor_size
@@ -741,6 +748,7 @@ gdk_window_get_origin
gdk_window_get_deskrelative_origin
gdk_window_get_root_coords
gdk_window_get_pointer
+gdk_window_get_device_position
GdkModifierType
gdk_window_get_parent
gdk_window_get_toplevel
@@ -763,6 +771,14 @@ GdkWMFunction
gdk_get_default_root_window
<SUBSECTION>
+gdk_window_get_support_multidevice
+gdk_window_set_support_multidevice
+gdk_window_get_device_cursor
+gdk_window_set_device_cursor
+gdk_window_get_device_events
+gdk_window_set_device_events
+
+<SUBSECTION>
GdkPointerHooks
gdk_set_pointer_hooks
@@ -1027,14 +1043,22 @@ gdk_keymap_get_type
</SECTION>
<SECTION>
-<TITLE>Input Devices</TITLE>
-<FILE>input_devices</FILE>
+<TITLE>GdkDeviceManager</TITLE>
+<FILE>gdkdevicemanager</FILE>
+GdkDeviceManager
GdkDevice
+GdkDeviceType
GdkInputSource
GdkInputMode
GdkDeviceKey
GdkDeviceAxis
GdkAxisUse
+GdkGrabOwnership
+gdk_enable_multidevice
+gdk_device_manager_get_display
+gdk_device_manager_list_devices
+
+<SUBSECTION>
gdk_devices_list
gdk_device_get_name
gdk_device_set_source
@@ -1045,8 +1069,16 @@ gdk_device_set_key
gdk_device_get_key
gdk_device_set_axis_use
gdk_device_get_axis_use
-gdk_device_get_core_pointer
+gdk_device_get_associated_device
+gdk_device_get_device_type
+gdk_device_get_display
gdk_device_get_has_cursor
+gdk_device_get_n_axes
+gdk_device_get_core_pointer
+
+<SUBSECTION>
+gdk_device_grab
+gdk_device_ungrab
<SUBSECTION>
gdk_device_get_state
@@ -1054,16 +1086,30 @@ gdk_device_get_history
gdk_device_free_history
GdkTimeCoord
gdk_device_get_axis
+gdk_device_list_axes
+gdk_device_get_axis_value
<SUBSECTION>
gdk_input_set_extension_events
GdkExtensionMode
+<SUBSECTION>
+gdk_devices_list
+gdk_device_get_core_pointer
+
<SUBSECTION Standard>
GDK_TYPE_AXIS_USE
GDK_TYPE_EXTENSION_MODE
GDK_TYPE_INPUT_MODE
GDK_TYPE_INPUT_SOURCE
+GDK_TYPE_DEVICE_TYPE
+GDK_TYPE_GRAB_OWNERSHIP
+GDK_DEVICE_MANAGER
+GDK_DEVICE_MANAGER_CLASS
+GDK_DEVICE_MANAGER_GET_CLASS
+GDK_IS_DEVICE_MANAGER
+GDK_IS_DEVICE_MANAGER_CLASS
+GDK_TYPE_DEVICE_MANAGER
GDK_DEVICE
GDK_DEVICE_CLASS
GDK_DEVICE_GET_CLASS
@@ -1073,7 +1119,12 @@ GDK_TYPE_DEVICE
<SUBSECTION Private>
GdkDeviceClass
+GdkDevicePrivate
+GdkDeviceManagerClass
+GdkDeviceManagerPrivate
gdk_device_get_type
+gdk_device_manager_get_type
+gdk_device_type_get_type
GDK_MAX_TIMECOORD_AXES
</SECTION>
@@ -1101,6 +1152,9 @@ gdk_event_get_axis
gdk_event_get_coords
gdk_event_get_root_coords
gdk_event_request_motions
+gdk_events_get_angle
+gdk_events_get_center
+gdk_events_get_distance
<SUBSECTION>
gdk_event_handler_set
@@ -1117,6 +1171,8 @@ gdk_get_show_events
gdk_set_show_events
gdk_event_set_screen
gdk_event_get_screen
+gdk_event_get_device
+gdk_event_set_device
<SUBSECTION>
gdk_setting_get
@@ -1240,6 +1296,8 @@ gdk_drag_context_get_action
gdk_drag_context_get_actions
gdk_drag_context_get_suggested_action
gdk_drag_context_list_targets
+gdk_drag_context_get_device
+gdk_drag_context_set_device
<SUBSECTION Standard>
GDK_DRAG_CONTEXT
diff --git a/docs/reference/gdk/gdk3.types b/docs/reference/gdk/gdk3.types
index 12b0f8d356..8b200f566b 100644
--- a/docs/reference/gdk/gdk3.types
+++ b/docs/reference/gdk/gdk3.types
@@ -9,3 +9,5 @@ gdk_pango_renderer_get_type
gdk_pixmap_get_type
gdk_gc_get_type
gdk_keymap_get_type
+gdk_device_get_type
+gdk_device_manager_get_type
diff --git a/docs/reference/gdk/tmpl/input_devices.sgml b/docs/reference/gdk/tmpl/input_devices.sgml
deleted file mode 100644
index e31cd9e1c3..0000000000
--- a/docs/reference/gdk/tmpl/input_devices.sgml
+++ /dev/null
@@ -1,309 +0,0 @@
-<!-- ##### SECTION Title ##### -->
-Input Devices
-
-<!-- ##### SECTION Short_Description ##### -->
-Functions for handling extended input devices
-
-<!-- ##### SECTION Long_Description ##### -->
-<para>
-In addition to the normal keyboard and mouse input devices, GTK+ also
-contains support for <firstterm>extended input devices</firstterm>. In
-particular, this support is targeted at graphics tablets. Graphics
-tablets typically return sub-pixel positioning information and possibly
-information about the pressure and tilt of the stylus. Under
-X, the support for extended devices is done through the
-<firstterm>XInput</firstterm> extension.
-</para>
-<para>
-Because handling extended input devices may involve considerable
-overhead, they need to be turned on for each #GdkWindow
-individually using gdk_input_set_extension_events().
-(Or, more typically, for GtkWidgets, using gtk_widget_set_extension_events()).
-As an additional complication, depending on the support from
-the windowing system, its possible that a normal mouse
-cursor will not be displayed for a particular extension
-device. If an application does not want to deal with displaying
-a cursor itself, it can ask only to get extension events
-from devices that will display a cursor, by passing the
-%GDK_EXTENSION_EVENTS_CURSOR value to
-gdk_input_set_extension_events(). Otherwise, the application
-must retrieve the device information using gdk_devices_list(),
-check the <structfield>has_cursor</structfield> field, and,
-if it is %FALSE, draw a cursor itself when it receives
-motion events.
-</para>
-<para>
-Each pointing device is assigned a unique integer ID; events from a
-particular device can be identified by the
-<structfield>deviceid</structfield> field in the event structure. The
-events generated by pointer devices have also been extended to contain
-<structfield>pressure</structfield>, <structfield>xtilt</structfield>
-and <structfield>ytilt</structfield> fields which contain the extended
-information reported as additional <firstterm>valuators</firstterm>
-from the device. The <structfield>pressure</structfield> field is a
-a double value ranging from 0.0 to 1.0, while the tilt fields are
-double values ranging from -1.0 to 1.0. (With -1.0 representing the
-maximum tilt to the left or up, and 1.0 representing the maximum
-tilt to the right or down.)
-</para>
-<para>
-One additional field in each event is the
-<structfield>source</structfield> field, which contains an
-enumeration value describing the type of device; this currently
-can be one of %GDK_SOURCE_MOUSE, %GDK_SOURCE_PEN, %GDK_SOURCE_ERASER,
-or %GDK_SOURCE_CURSOR. This field is present to allow simple
-applications to (for instance) delete when they detect eraser
-devices without having to keep track of complicated per-device
-settings.
-</para>
-<para>
-Various aspects of each device may be configured.
-The configuration of devices is queried using gdk_devices_list().
-Each device must be activated using gdk_device_set_mode(), which
-also controls whether the device's range is mapped to the
-entire screen or to a single window. The mapping of the valuators of
-the device onto the predefined valuator types is set using
-gdk_device_set_axis_use(). And the source type for each device
-can be set with gdk_device_set_source().
-</para>
-<para>
-Devices may also have associated <firstterm>keys</firstterm>
-or macro buttons. Such keys can be globally set to map
-into normal X keyboard events. The mapping is set using
-gdk_device_set_key().
-</para>
-<para>
-The interfaces in this section will most likely be considerably
-modified in the future to accomodate devices that may have different
-sets of additional valuators than the pressure <structfield>xtilt</structfield>
-and <structfield>ytilt</structfield>.
-</para>
-
-<!-- ##### SECTION See_Also ##### -->
-<para>
-
-</para>
-
-<!-- ##### SECTION Stability_Level ##### -->
-
-
-<!-- ##### SECTION Image ##### -->
-
-
-<!-- ##### STRUCT GdkDevice ##### -->
-<para>
-A <structname>GdkDevice</structname> structure contains
-a detailed description of an extended input device. All
-fields are read-only; but you can use gdk_device_set_source(),
-gdk_device_set_mode(), gdk_device_set_key() and gdk_device_set_axis_use()
-to configure various aspects of the device.
-</para>
-
-@parent_instance: the parent instance
-@name: the name of this device.
-@source: the type of this device.
-@mode: the mode of this device
-@has_cursor: %TRUE if the pointer follows device motion.
-@num_axes: the length of the @axes array.
-@axes: an array of #GdkDeviceAxis, describing the axes of this device.
-@num_keys: the length of the @keys array.
-@keys: an array of #GdkDeviceKey, describing the mapped macro buttons
- of this device.
-
-<!-- ##### ENUM GdkInputSource ##### -->
-<para>
-An enumeration describing the type of an input device
-in general terms.
-</para>
-
-@GDK_SOURCE_MOUSE: the device is a mouse. (This will be reported for the core
- pointer, even if it is something else, such as a trackball.)
-@GDK_SOURCE_PEN: the device is a stylus of a graphics tablet or similar device.
-@GDK_SOURCE_ERASER: the device is an eraser. Typically, this would be the other end
- of a stylus on a graphics tablet.
-@GDK_SOURCE_CURSOR: the device is a graphics tablet "puck" or similar device.
-
-<!-- ##### ENUM GdkInputMode ##### -->
-<para>
-An enumeration that describes the mode of an input device.
-</para>
-
-@GDK_MODE_DISABLED: the device is disabled and will not report any events.
-@GDK_MODE_SCREEN: the device is enabled. The device's coordinate space
- maps to the entire screen.
-@GDK_MODE_WINDOW: the device is enabled. The device's coordinate space
- is mapped to a single window. The manner in which this window
- is chosen is undefined, but it will typically be the same
- way in which the focus window for key events is determined.
-
-<!-- ##### STRUCT GdkDeviceKey ##### -->
-<para>
-The <structname>GdkDeviceKey</structname> structure contains information
-about the mapping of one device macro button onto a normal X key event.
-It has the following fields:
-</para>
-
-@keyval: the keyval to generate when the macro button is pressed.
- If this is 0, no keypress will be generated.
-@modifiers: the modifiers set for the generated key event.
-
-<!-- ##### STRUCT GdkDeviceAxis ##### -->
-<para>
-The <structname>GdkDeviceAxis</structname> structure contains information
-about the range and mapping of a device axis.
-</para>
-
-@use: specifies how the axis is used.
-@min: the minimal value that will be reported by this axis.
-@max: the maximal value that will be reported by this axis.
-
-<!-- ##### ENUM GdkAxisUse ##### -->
-<para>
-An enumeration describing the way in which a device
-axis (valuator) maps onto the predefined valuator
-types that GTK+ understands.
-</para>
-
-@GDK_AXIS_IGNORE: the axis is ignored.
-@GDK_AXIS_X: the axis is used as the x axis.
-@GDK_AXIS_Y: the axis is used as the y axis.
-@GDK_AXIS_PRESSURE: the axis is used for pressure information.
-@GDK_AXIS_XTILT: the axis is used for x tilt information.
-@GDK_AXIS_YTILT: the axis is used for x tilt information.
-@GDK_AXIS_WHEEL: the axis is used for wheel information.
-@GDK_AXIS_LAST: a constant equal to the numerically highest axis value.
-
-<!-- ##### FUNCTION gdk_devices_list ##### -->
-<para>
-</para>
-
-@void:
-@Returns:
-
-
-<!-- ##### FUNCTION gdk_device_set_source ##### -->
-<para>
-Sets the source type for an input device.
-</para>
-
-@device: a #GdkDevice.
-@source: the source type.
-
-
-<!-- ##### FUNCTION gdk_device_set_mode ##### -->
-<para>
-Sets a the mode of an input device. The mode controls if the
-device is active and whether the device's range is mapped to the
-entire screen or to a single window.
-</para>
-
-@device: a #GdkDevice.
-@mode: the input mode.
-@Returns: %TRUE if the mode was successfully changed.
-
-
-<!-- ##### FUNCTION gdk_device_set_key ##### -->
-<para>
-Specifies the X key event to generate when a macro button of a device
-is pressed.
-</para>
-
-@device: a #GdkDevice.
-@index_: the index of the macro button to set.
-@keyval: the keyval to generate.
-@modifiers: the modifiers to set.
-
-
-<!-- ##### FUNCTION gdk_device_set_axis_use ##### -->
-<para>
-Specifies how an axis of a device is used.
-</para>
-
-@device: a #GdkDevice.
-@index_: the index of the axis.
-@use: specifies how the axis is used.
-
-
-<!-- ##### FUNCTION gdk_device_get_core_pointer ##### -->
-<para>
-</para>
-
-@void:
-@Returns:
-
-
-<!-- ##### FUNCTION gdk_device_get_state ##### -->
-
-
-@device:
-@window:
-@axes:
-@mask:
-
-
-<!-- ##### FUNCTION gdk_device_get_history ##### -->
-<para>
-
-</para>
-
-@device:
-@window:
-@start:
-@stop:
-@events:
-@n_events:
-@Returns:
-
-
-<!-- ##### FUNCTION gdk_device_free_history ##### -->
-<para>
-Frees an array of #GdkTimeCoord that was returned by gdk_device_get_history().
-</para>
-
-@events: an array of #GdkTimeCoord.
-@n_events: the length of the array.
-
-
-<!-- ##### STRUCT GdkTimeCoord ##### -->
-<para>
-The #GdkTimeCoord structure stores a single event in a
-motion history. It contains the following fields:
-</para>
-
-@time: The timestamp for this event.
-@axes: the values of the device's axes.
-
-<!-- ##### FUNCTION gdk_device_get_axis ##### -->
-<para>
-
-</para>
-
-@device:
-@axes:
-@use:
-@value:
-@Returns:
-
-
-<!-- ##### FUNCTION gdk_input_set_extension_events ##### -->
-<para>
-Turns extension events on or off for a particular window,
-and specifies the event mask for extension events.
-</para>
-
-@window: a #GdkWindow.
-@mask: the event mask
-@mode: the type of extension events that are desired.
-
-
-<!-- ##### ENUM GdkExtensionMode ##### -->
-<para>
-An enumeration used to specify which extension events
-are desired for a particular widget.
-</para>
-
-@GDK_EXTENSION_EVENTS_NONE: no extension events are desired.
-@GDK_EXTENSION_EVENTS_ALL: all extension events are desired.
-@GDK_EXTENSION_EVENTS_CURSOR: extension events are desired only if a cursor
- will be displayed for the device.
-
diff --git a/docs/reference/gtk/compiling.sgml b/docs/reference/gtk/compiling.sgml
index c5e58b79c5..d126bd491f 100644
--- a/docs/reference/gtk/compiling.sgml
+++ b/docs/reference/gtk/compiling.sgml
@@ -63,6 +63,13 @@ symbol GDK_MULTIHEAD_SAFE by using the command line option
</para>
<para>
+Similarly, if you want to make sure that your program doesn't use any
+functions which may be problematic in a multidevice setting, you can
+define the preprocessor symbol GDK_MULTIDEVICE_SAFE by using the command
+line option <literal>-DGTK_MULTIDEVICE_SAFE=1</literal>.
+</para>
+
+<para>
The recommended way of using GTK+ has always been to only include the
toplevel headers <filename>gtk.h</filename>, <filename>gdk.h</filename>,
<filename>gdk-pixbuf.h</filename>.
diff --git a/docs/reference/gtk/gtk-docs.sgml b/docs/reference/gtk/gtk-docs.sgml
index 468587eeb5..9f35339532 100644
--- a/docs/reference/gtk/gtk-docs.sgml
+++ b/docs/reference/gtk/gtk-docs.sgml
@@ -336,6 +336,7 @@ that is, GUI components such as #GtkButton or #GtkTextView.
<xi:include href="xml/gtktooltip.xml" />
<xi:include href="xml/gtkviewport.xml" />
<xi:include href="xml/gtkaccessible.xml" />
+ <xi:include href="xml/gtkdevicegroup.xml" />
</chapter>
<chapter id="AbstractObjects">
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index f1545fc8b9..40c8e39246 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -79,11 +79,6 @@ gtk_accelerator_get_label
gtk_accelerator_set_default_mod_mask
gtk_accelerator_get_default_mod_mask
-<SUBSECTION Private>
-GtkAccelGroupEntry
-GtkAccelGroupPrivate
-gtk_accel_group_get_type
-
<SUBSECTION Standard>
GtkAccelGroupClass
GTK_TYPE_ACCEL_GROUP
@@ -92,6 +87,11 @@ GTK_IS_ACCEL_GROUP
GTK_ACCEL_GROUP_CLASS
GTK_IS_ACCEL_GROUP_CLASS
GTK_ACCEL_GROUP_GET_CLASS
+
+<SUBSECTION Private>
+GtkAccelGroupPrivate
+GtkAccelGroupEntry
+gtk_accel_group_get_type
</SECTION>
<SECTION>
@@ -263,10 +263,10 @@ gtk_action_group_add_action_with_accel
gtk_action_group_remove_action
GtkActionEntry
gtk_action_group_add_actions
-gtk_action_group_add_actions_full
+gtk_action_group_add_actions_full
GtkToggleActionEntry
gtk_action_group_add_toggle_actions
-gtk_action_group_add_toggle_actions_full
+gtk_action_group_add_toggle_actions_full
GtkRadioActionEntry
gtk_action_group_add_radio_actions
gtk_action_group_add_radio_actions_full
@@ -782,6 +782,7 @@ gtk_combo_box_insert_text
gtk_combo_box_prepend_text
gtk_combo_box_remove_text
gtk_combo_box_get_active_text
+gtk_combo_box_popup_for_device
gtk_combo_box_popup
gtk_combo_box_popdown
gtk_combo_box_get_popup_accessible
@@ -1961,6 +1962,7 @@ gtk_menu_new
gtk_menu_set_screen
gtk_menu_reorder_child
gtk_menu_attach
+gtk_menu_popup_for_device
gtk_menu_popup
gtk_menu_set_accel_group
gtk_menu_get_accel_group
@@ -4812,15 +4814,18 @@ gtk_widget_set_parent
gtk_widget_set_parent_window
gtk_widget_get_parent_window
gtk_widget_set_events
+gtk_widget_get_events
gtk_widget_add_events
gtk_widget_set_extension_events
gtk_widget_get_extension_events
+gtk_widget_set_device_events
+gtk_widget_get_device_events
+gtk_widget_add_device_events
gtk_widget_get_toplevel
gtk_widget_get_ancestor
gtk_widget_get_colormap
gtk_widget_set_colormap
gtk_widget_get_visual
-gtk_widget_get_events
gtk_widget_get_pointer
gtk_widget_is_ancestor
gtk_widget_translate_coordinates
@@ -4938,11 +4943,14 @@ gtk_widget_is_toplevel
gtk_widget_set_window
gtk_widget_set_receives_default
gtk_widget_get_receives_default
+gtk_widget_set_support_multidevice
+gtk_widget_get_support_multidevice
gtk_widget_set_realized
gtk_widget_get_realized
gtk_widget_set_mapped
gtk_widget_get_mapped
gtk_widget_get_requisition
+gtk_widget_device_is_shadowed
<SUBSECTION>
gtk_requisition_copy
@@ -5091,6 +5099,7 @@ gtk_window_group_new
gtk_window_group_add_window
gtk_window_group_remove_window
gtk_window_group_list_windows
+gtk_window_group_get_current_device_grab
<SUBSECTION Standard>
GTK_IS_WINDOW_GROUP
GTK_IS_WINDOW_GROUP_CLASS
@@ -5132,6 +5141,8 @@ gtk_false
gtk_grab_add
gtk_grab_get_current
gtk_grab_remove
+gtk_device_grab_add
+gtk_device_grab_remove
<SUBSECTION>
gtk_init_add
@@ -5153,6 +5164,7 @@ gtk_key_snooper_remove
gtk_get_current_event
gtk_get_current_event_time
gtk_get_current_event_state
+gtk_get_current_event_device
gtk_get_event_widget
gtk_propagate_event
diff --git a/gdk/Makefile.am b/gdk/Makefile.am
index ec244a811e..21b296c654 100644
--- a/gdk/Makefile.am
+++ b/gdk/Makefile.am
@@ -77,6 +77,9 @@ gdk_public_h_sources = \
gdkcairo.h \
gdkcolor.h \
gdkcursor.h \
+ gdkdevice.h \
+ gdkdevicemanager.h \
+ gdkdeviceprivate.h \
gdkdisplay.h \
gdkdisplaymanager.h \
gdkdnd.h \
@@ -122,6 +125,8 @@ gdk_c_sources = \
gdkcairo.c \
gdkcolor.c \
gdkcursor.c \
+ gdkdevice.c \
+ gdkdevicemanager.c \
gdkdisplay.c \
gdkdisplaymanager.c \
gdkdnd.c \
diff --git a/gdk/gdk.c b/gdk/gdk.c
index 8fe3c450d3..89a4e2f8e8 100644
--- a/gdk/gdk.c
+++ b/gdk/gdk.c
@@ -787,5 +787,28 @@ gdk_set_program_class (const char *program_class)
gdk_progclass = g_strdup (program_class);
}
+/**
+ * gdk_enable_multidevice:
+ *
+ * Enables multidevice support in GDK. This call must happen prior
+ * to gdk_display_open(), gtk_init(), gtk_init_with_args() or
+ * gtk_init_check() in order to take effect.
+ *
+ * Note that individual #GdkWindow<!-- -->s still need to explicitly
+ * enable multidevice awareness through gdk_window_set_support_multidevice().
+ *
+ * This function must be called before initializing GDK.
+ *
+ * Since: 3.0
+ **/
+void
+gdk_enable_multidevice (void)
+{
+ if (gdk_initialized)
+ return;
+
+ _gdk_enable_multidevice = TRUE;
+}
+
#define __GDK_C__
#include "gdkaliasdef.c"
diff --git a/gdk/gdk.h b/gdk/gdk.h
index 219298e2ce..e910a8b23c 100644
--- a/gdk/gdk.h
+++ b/gdk/gdk.h
@@ -33,6 +33,8 @@
#include <gdk/gdkcairo.h>
#include <gdk/gdkcolor.h>
#include <gdk/gdkcursor.h>
+#include <gdk/gdkdevice.h>
+#include <gdk/gdkdevicemanager.h>
#include <gdk/gdkdisplay.h>
#include <gdk/gdkdisplaymanager.h>
#include <gdk/gdkdnd.h>
@@ -66,6 +68,7 @@ G_BEGIN_DECLS
/* Initialization, exit and events
*/
#define GDK_PRIORITY_EVENTS (G_PRIORITY_DEFAULT)
+void gdk_enable_multidevice (void);
void gdk_parse_args (gint *argc,
gchar ***argv);
void gdk_init (gint *argc,
@@ -109,6 +112,7 @@ gint gdk_input_add (gint source,
void gdk_input_remove (gint tag);
#endif /* GDK_DISABLE_DEPRECATED */
+#ifndef GDK_MULTIDEVICE_SAFE
GdkGrabStatus gdk_pointer_grab (GdkWindow *window,
gboolean owner_events,
GdkEventMask event_mask,
@@ -118,18 +122,15 @@ GdkGrabStatus gdk_pointer_grab (GdkWindow *window,
GdkGrabStatus gdk_keyboard_grab (GdkWindow *window,
gboolean owner_events,
guint32 time_);
-
-gboolean gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
- GdkWindow **grab_window,
- gboolean *owner_events);
-gboolean gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
- GdkWindow **grab_window,
- gboolean *owner_events);
+#endif /* GDK_MULTIDEVICE_SAFE */
#ifndef GDK_MULTIHEAD_SAFE
+
+#ifndef GDK_MULTIDEVICE_SAFE
void gdk_pointer_ungrab (guint32 time_);
void gdk_keyboard_ungrab (guint32 time_);
gboolean gdk_pointer_is_grabbed (void);
+#endif /* GDK_MULTIDEVICE_SAFE */
gint gdk_screen_width (void) G_GNUC_CONST;
gint gdk_screen_height (void) G_GNUC_CONST;
diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols
index 36b111fdec..9ee4082d8f 100644
--- a/gdk/gdk.symbols
+++ b/gdk/gdk.symbols
@@ -19,13 +19,6 @@
#define IN_HEADER(x) 1
#endif
-#if IN_HEADER(__GDK_EVENTS_H__)
-#if IN_FILE(__GDK_EVENTS_X11_C__)
-gdk_add_client_message_filter
-gdk_events_pending
-#endif
-#endif
-
#if IN_HEADER(__GDK_TEST_UTILS_H__)
#if IN_FILE(__GDK_TEST_UTILS_X11_C__)
gdk_test_simulate_button
@@ -41,6 +34,7 @@ gdk_event_free
gdk_event_get
gdk_event_get_axis
gdk_event_get_coords
+gdk_event_get_device
gdk_event_get_root_coords
gdk_event_get_screen
gdk_event_get_state
@@ -51,13 +45,56 @@ gdk_event_new
gdk_event_peek
gdk_event_put
gdk_event_request_motions
+gdk_event_set_device
gdk_event_set_screen
+gdk_events_get_distance
+gdk_events_get_angle
+gdk_events_get_center
gdk_get_show_events
gdk_set_show_events
gdk_setting_get
#endif
#endif
+#if IN_HEADER(__GDK_EVENTS_H__)
+#if IN_FILE(__GDK_DISPLAY_X11_C__)
+gdk_add_client_message_filter
+#endif
+#endif
+
+#if IN_HEADER(__GDK_EVENTS_H__)
+#if IN_FILE(__GDK_EVENT_SOURCE_C__)
+gdk_events_pending
+#endif
+#endif
+
+#if IN_HEADER(__GDK_EVENT_TRANSLATOR_H__)
+#if IN_FILE(__GDK_EVENT_TRANSLATOR_C__)
+#ifdef GDK_WINDOWING_X11
+gdk_event_translator_get_type G_GNUC_CONST
+gdk_event_translator_translate
+gdk_event_translator_get_handled_events
+gdk_event_translator_select_window_events
+#endif
+#endif
+#endif
+
+#if IN_HEADER(__GDK_DEVICE_MANAGER_CORE_H__)
+#if IN_FILE(__GDK_DEVICE_MANAGER_CORE_C__)
+#ifdef GDK_WINDOWING_X11
+gdk_device_manager_core_get_type
+#endif
+#endif
+#endif
+
+#if IN_HEADER(__GDK_DEVICE_MANAGER_XI2_H__)
+#if IN_FILE(__GDK_DEVICE_MANAGER_XI2_C__)
+#ifdef GDK_WINDOWING_X11
+gdk_device_manager_xi2_get_type
+#endif
+#endif
+#endif
+
#if IN_HEADER(__GDK_H__)
#if IN_FILE(__GDK_MAIN_X11_C__)
gdk_error_trap_pop
@@ -67,7 +104,6 @@ gdk_get_display
gdk_get_use_xshm
gdk_set_use_xshm
#endif
-gdk_keyboard_grab
#endif
#endif
@@ -75,17 +111,24 @@ gdk_keyboard_grab
#if IN_HEADER(__GDK_H__)
#if IN_FILE(__GDK_DISPLAY_C__)
gdk_beep
+#ifndef GDK_MULTIDEVICE_SAFE
+#ifndef GDK_DISABLE_DEPRECATED
+#ifndef GDK_MULTIHEAD_SAFE
+gdk_device_get_core_pointer
gdk_set_pointer_hooks
+#endif
+#endif
gdk_keyboard_ungrab
gdk_pointer_is_grabbed
gdk_pointer_ungrab
+#endif
gdk_event_send_client_message
gdk_event_send_clientmessage_toall
-gdk_keyboard_grab_info_libgtk_only
-gdk_pointer_grab_info_libgtk_only
+#ifndef GDK_MULTIDEVICE_SAFE
gdk_display_pointer_is_grabbed
#endif
#endif
+#endif
#if IN_HEADER(__GDK_H__)
#if IN_FILE(__GDK_IM_X11_C__)
@@ -98,14 +141,12 @@ gdk_set_locale
#endif
#if IN_HEADER(__GDK_H__)
-#if IN_FILE(__GDK_EVENTS_X11_C__)
+#if IN_FILE(__GDK_DISPLAY_X11_C__)
+#ifndef GDK_DISABLE_DEPRECATED
+gdk_display_list_devices
+#endif
gdk_event_send_client_message_for_display
gdk_flush
-#endif
-#endif
-
-#if IN_HEADER(__GDK_H__)
-#if IN_FILE(__GDK_DISPLAY_X11_C__)
gdk_notify_startup_complete
gdk_notify_startup_complete_with_id
#endif
@@ -132,6 +173,7 @@ gdk_get_display_arg_name
gdk_get_program_class
gdk_init
gdk_init_check
+gdk_enable_multidevice
gdk_pre_parse_libgtk_only
gdk_parse_args
gdk_set_program_class
@@ -167,6 +209,14 @@ gdk_screen_height_mm G_GNUC_CONST
#endif
#endif
+#if IN_HEADER(__GDK_H__)
+#if IN_FILE(__GDK_WINDOW_C__)
+#ifndef GDK_MULTIDEVICE_SAFE
+gdk_keyboard_grab
+#endif
+#endif
+#endif
+
#if IN_HEADER(__GDK_PROPERTY_H__)
#if IN_FILE(__GDK_SELECTION_C__)
gdk_string_to_compound_text
@@ -210,6 +260,7 @@ gdk_axis_use_get_type G_GNUC_CONST
gdk_byte_order_get_type G_GNUC_CONST
gdk_cap_style_get_type G_GNUC_CONST
gdk_crossing_mode_get_type G_GNUC_CONST
+gdk_device_type_get_type G_GNUC_CONST
gdk_extension_mode_get_type G_GNUC_CONST
gdk_event_mask_get_type G_GNUC_CONST
gdk_event_type_get_type G_GNUC_CONST
@@ -217,6 +268,7 @@ gdk_fill_get_type G_GNUC_CONST
gdk_fill_rule_get_type G_GNUC_CONST
gdk_filter_return_get_type G_GNUC_CONST
gdk_function_get_type G_GNUC_CONST
+gdk_grab_ownership_get_type G_GNUC_CONST
gdk_grab_status_get_type G_GNUC_CONST
gdk_gravity_get_type G_GNUC_CONST
gdk_join_style_get_type G_GNUC_CONST
@@ -367,76 +419,99 @@ gdk_cursor_get_image
#endif
#endif
-#if IN_HEADER(__GDK_INPUT_H__)
-#if IN_FILE(__GDK_INPUT_C__)
+#if IN_HEADER(__GDK_DEVICE_MANAGER_H__)
+#if IN_FILE(__GDK_DEVICE_MANAGER_C__)
+gdk_device_manager_get_display
+gdk_device_manager_get_type G_GNUC_CONST
+gdk_device_manager_list_devices
+#endif
+#endif
+
+#if IN_HEADER(__GDK_DEVICE_H__)
+#if IN_FILE(__GDK_DEVICE_C__)
gdk_device_free_history
+gdk_device_get_associated_device
gdk_device_get_axis
gdk_device_get_axis_use
+gdk_device_get_axis_value
+gdk_device_get_device_type
+gdk_device_get_display
gdk_device_get_has_cursor
gdk_device_get_history
gdk_device_get_key
gdk_device_get_mode
+gdk_device_get_n_axes
gdk_device_get_name
gdk_device_get_source
gdk_device_get_type G_GNUC_CONST
+gdk_device_get_state
+gdk_device_list_axes
gdk_device_set_axis_use
gdk_device_set_key
+gdk_device_set_mode
gdk_device_set_source
-gdk_devices_list
-gdk_input_set_extension_events
+gdk_device_grab
#endif
#endif
-#if IN_HEADER(__GDK_INPUT_H__)
-#if IN_FILE(__GDK_DISPLAY_C__)
-gdk_device_get_core_pointer
+#if IN_HEADER(__GDK_DEVICE_H__)
+#if IN_FILE(__GDK_DISPLAY_X11_C__)
+gdk_device_ungrab
#endif
#endif
-#if IN_HEADER(__GDK_INPUT_H__)
-#if IN_FILE(__GDK_INPUT_X11_C__)
-gdk_device_get_state
+#if IN_HEADER(__GDK_DEVICE_H__)
+#if IN_FILE(__GDK_DISPLAY_C__)
+gdk_device_grab_info_libgtk_only
#endif
#endif
#if IN_HEADER(__GDK_INPUT_H__)
-#if IN_FILE(__GDK_INPUT_XFREE_C__)
-gdk_device_set_mode
-#endif
+#if IN_FILE(__GDK_INPUT_C__)
+#ifndef GDK_DISABLE_DEPRECATED
+#ifndef GDK_MULTIDEVICE_SAFE
+#ifndef GDK_MULTIHEAD_SAFE
+gdk_devices_list
#endif
-
-#if IN_HEADER(__GDK_INPUT_H__)
-#if IN_FILE(__GDK_INPUT_NONE_C__)
-gdk_device_get_state
-gdk_device_set_mode
+gdk_input_set_extension_events
#endif
#endif
-
-#if IN_HEADER(__GDK_DISPLAY_H__)
-#if IN_FILE(__GDK_EVENTS_X11_C__)
-gdk_display_add_client_message_filter
#endif
#endif
#if IN_HEADER(__GDK_DISPLAY_H__)
#if IN_FILE(__GDK_DISPLAY_C__)
gdk_display_close
-gdk_display_get_core_pointer
gdk_display_get_event
-gdk_display_get_pointer
+gdk_display_get_device_manager
+gdk_display_get_device_state
gdk_display_get_type G_GNUC_CONST
-gdk_display_get_window_at_pointer
+gdk_display_get_window_at_device_position
gdk_display_peek_event
gdk_display_put_event
+#ifndef GDK_MULTIDEVICE_SAFE
+gdk_display_get_pointer
+gdk_display_get_window_at_pointer
+gdk_display_keyboard_ungrab
+gdk_display_pointer_ungrab
gdk_display_set_pointer_hooks
+gdk_display_set_device_hooks
+gdk_display_device_is_grabbed
+#ifndef GDK_DISABLE_DEPRECATED
+gdk_display_get_core_pointer
+#endif
+#endif
#endif
#endif
#if IN_HEADER(__GDK_DISPLAY_H__)
#if IN_FILE(__GDK_WINDOW_X11_C__)
+gdk_display_warp_device
+#ifndef GDK_MULTIDEVICE_SAFE
gdk_display_warp_pointer
#endif
#endif
+#endif
#if IN_HEADER(__GDK_DISPLAY_H__)
#if IN_FILE(__GDK_DISPLAY_MANAGER_C__)
@@ -455,6 +530,7 @@ gdk_display_supports_cursor_color
#if IN_HEADER(__GDK_DISPLAY_H__)
#if IN_FILE(__GDK_DISPLAY_X11_C__)
+gdk_display_add_client_message_filter
gdk_display_beep
gdk_display_sync
gdk_display_flush
@@ -463,8 +539,6 @@ gdk_display_get_default_screen
gdk_display_get_name
gdk_display_get_n_screens
gdk_display_get_screen
-gdk_display_pointer_ungrab
-gdk_display_keyboard_ungrab
gdk_display_open
gdk_display_request_selection_notification
gdk_display_store_clipboard
@@ -477,12 +551,6 @@ gdk_display_supports_composite
#endif
#if IN_HEADER(__GDK_DISPLAY_H__)
-#if IN_FILE(__GDK_INPUT_C__)
-gdk_display_list_devices
-#endif
-#endif
-
-#if IN_HEADER(__GDK_DISPLAY_H__)
#if IN_FILE(__GDK_C__)
gdk_display_open_default_libgtk_only
#endif
@@ -511,6 +579,8 @@ gdk_drag_abort
gdk_drag_begin
gdk_drag_context_get_type G_GNUC_CONST
gdk_drag_context_new
+gdk_drag_context_get_device
+gdk_drag_context_set_device
gdk_drag_drop
gdk_drag_drop_succeeded
gdk_drag_find_window_for_screen
@@ -659,12 +729,14 @@ gdk_window_get_back_pixmap
gdk_window_get_background
gdk_window_get_composited
gdk_window_get_cursor
-gdk_window_get_deskrelative_origin
gdk_window_get_focus_on_map
gdk_window_get_geometry
gdk_window_get_modal_hint
gdk_window_get_origin
gdk_window_get_root_coords
+gdk_window_get_deskrelative_origin
+gdk_window_set_support_multidevice
+gdk_window_get_support_multidevice
gdk_window_set_background
gdk_window_set_back_pixmap
gdk_window_set_cursor
@@ -679,7 +751,9 @@ gdk_window_merge_child_input_shapes
gdk_window_set_static_gravities
gdk_window_reparent
gdk_window_add_filter
+#ifndef GDK_MULTIDEVICE_SAFE
gdk_window_at_pointer
+#endif
gdk_window_begin_paint_rect
gdk_window_begin_paint_region
gdk_window_clear
@@ -698,7 +772,9 @@ gdk_window_get_children
gdk_window_get_internal_paint_info
gdk_window_get_parent
gdk_window_get_effective_parent
+#ifndef GDK_MULTIDEVICE_SAFE
gdk_window_get_pointer
+#endif
gdk_window_get_position
gdk_window_get_state
gdk_window_get_toplevel
@@ -726,10 +802,17 @@ gdk_window_set_user_data
gdk_window_thaw_toplevel_updates_libgtk_only
gdk_window_thaw_updates
gdk_window_set_composited
+#ifndef GDK_MULTIDEVICE_SAFE
gdk_pointer_grab
+#endif
gdk_window_beep
gdk_window_geometry_changed
gdk_window_ensure_native
+gdk_window_set_device_events
+gdk_window_get_device_events
+gdk_window_set_device_cursor
+gdk_window_get_device_cursor
+gdk_window_get_device_position
#endif
#endif
@@ -908,12 +991,6 @@ gdk_visual_get_type G_GNUC_CONST
#endif
#endif
-#if IN_HEADER(__GDK_X_H__)
-#if IN_FILE(__GDK_EVENTS_X11_C__)
-gdk_net_wm_supports
-#endif
-#endif
-
#if IN_HEADER(__GDK_PANGO_H__)
#if IN_FILE(__GDK_PANGO_C__)
gdk_pango_attr_emboss_color_new
@@ -1048,13 +1125,6 @@ gdk_screen_get_rgb_visual
#endif
#if IN_HEADER(__GDK_SCREEN_H__)
-#if IN_FILE(__GDK_EVENTS_X11_C__)
-gdk_screen_get_setting
-gdk_screen_broadcast_client_message
-#endif
-#endif
-
-#if IN_HEADER(__GDK_SCREEN_H__)
#if IN_FILE(__GDK_VISUAL_X11_C__)
gdk_screen_get_system_visual
gdk_screen_list_visuals
@@ -1069,6 +1139,7 @@ gdk_screen_get_toplevel_windows
#if IN_HEADER(__GDK_SCREEN_H__)
#if IN_FILE(__GDK_SCREEN_X11_C__)
+gdk_screen_broadcast_client_message
gdk_screen_get_display
gdk_screen_get_width
gdk_screen_get_width_mm
@@ -1077,6 +1148,7 @@ gdk_screen_get_height_mm
gdk_screen_get_number
gdk_screen_get_primary_monitor
gdk_screen_get_root_window
+gdk_screen_get_setting
gdk_screen_get_default_colormap
gdk_screen_set_default_colormap
gdk_screen_get_n_monitors
@@ -1219,6 +1291,7 @@ gdk_x11_display_ungrab
gdk_x11_lookup_xdisplay
gdk_x11_display_broadcast_startup_message
gdk_x11_display_get_startup_notification_id
+gdk_x11_register_standard_event_type
#endif
#if IN_FILE(__GDK_DRAWABLE_X11_C__)
@@ -1249,22 +1322,18 @@ gdk_x11_grab_server
gdk_x11_ungrab_server
#endif
-#if IN_FILE(__GDK_EVENTS_X11_C__)
-gdk_x11_get_server_time
-gdk_x11_register_standard_event_type
-gdk_x11_screen_get_window_manager_name
-gdk_x11_screen_supports_net_wm_hint
-#endif
-
#if IN_FILE(__GDK_IMAGE_X11_C__)
gdk_x11_image_get_xdisplay
gdk_x11_image_get_ximage
#endif
#if IN_FILE(__GDK_SCREEN_X11_C__)
+gdk_net_wm_supports
gdk_x11_screen_get_screen_number
+gdk_x11_screen_get_window_manager_name
gdk_x11_screen_get_xscreen
gdk_x11_screen_get_monitor_output
+gdk_x11_screen_supports_net_wm_hint
#endif
#if IN_FILE(__GDK_VISUAL_X11_C__)
@@ -1274,6 +1343,7 @@ gdkx_visual_get
#endif
#if IN_FILE(__GDK_WINDOW_X11_C__)
+gdk_x11_get_server_time
gdk_x11_window_set_user_time
gdk_x11_window_move_to_current_desktop
#endif
diff --git a/gdk/gdkdevice.c b/gdk/gdkdevice.c
new file mode 100644
index 0000000000..6ee68eb310
--- /dev/null
+++ b/gdk/gdkdevice.c
@@ -0,0 +1,1399 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+#include "gdkdevice.h"
+#include "gdkdeviceprivate.h"
+#include "gdkintl.h"
+#include "gdkinternals.h"
+#include "gdkalias.h"
+
+typedef struct _GdkAxisInfo GdkAxisInfo;
+
+struct _GdkAxisInfo
+{
+ GdkAtom label;
+ GdkAxisUse use;
+
+ gdouble min_axis;
+ gdouble max_axis;
+
+ gdouble min_value;
+ gdouble max_value;
+ gdouble resolution;
+};
+
+struct _GdkDevicePrivate
+{
+ GdkDeviceManager *device_manager;
+ GdkDisplay *display;
+ GdkDevice *associated;
+ GdkDeviceType type;
+ GArray *axes;
+};
+
+static void gdk_device_dispose (GObject *object);
+static void gdk_device_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gdk_device_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+
+G_DEFINE_ABSTRACT_TYPE (GdkDevice, gdk_device, G_TYPE_OBJECT)
+
+enum {
+ PROP_0,
+ PROP_DISPLAY,
+ PROP_DEVICE_MANAGER,
+ PROP_NAME,
+ PROP_ASSOCIATED_DEVICE,
+ PROP_TYPE,
+ PROP_INPUT_SOURCE,
+ PROP_INPUT_MODE,
+ PROP_HAS_CURSOR,
+ PROP_N_AXES
+};
+
+
+static void
+gdk_device_class_init (GdkDeviceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gdk_device_dispose;
+ object_class->set_property = gdk_device_set_property;
+ object_class->get_property = gdk_device_get_property;
+
+ /**
+ * GdkDevice:display:
+ *
+ * The #GdkDisplay the #GdkDevice pertains to.
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY,
+ g_param_spec_object ("display",
+ P_("Device Display"),
+ P_("Display to which the device belongs to"),
+ GDK_TYPE_DISPLAY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+ /**
+ * GdkDevice:device-manager:
+ *
+ * The #GdkDeviceManager the #GdkDevice pertains to.
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (object_class,
+ PROP_DEVICE_MANAGER,
+ g_param_spec_object ("device-manager",
+ P_("Device manager"),
+ P_("Device manager to which the device belongs to"),
+ GDK_TYPE_DEVICE_MANAGER,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+ /**
+ * GdkDevice:name:
+ *
+ * The device name.
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (object_class,
+ PROP_NAME,
+ g_param_spec_string ("name",
+ P_("Device name"),
+ P_("Device name"),
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+ /**
+ * GdkDevice:type:
+ *
+ * Device role in the device manager.
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (object_class,
+ PROP_TYPE,
+ g_param_spec_enum ("type",
+ P_("Device type"),
+ P_("Device role in the device manager"),
+ GDK_TYPE_DEVICE_TYPE,
+ GDK_DEVICE_TYPE_MASTER,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+ /**
+ * GdkDevice:associated-device:
+ *
+ * Associated pointer or keyboard to this device, if any. Devices of type #GDK_DEVICE_TYPE_MASTER
+ * always come in keyboard/pointer pairs. Other device types will have a %NULL associated device.
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (object_class,
+ PROP_ASSOCIATED_DEVICE,
+ g_param_spec_object ("associated-device",
+ P_("Associated device"),
+ P_("Associated pointer or keyboard to this device"),
+ GDK_TYPE_DEVICE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GdkDevice:input-source:
+ *
+ * Source type for the device.
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (object_class,
+ PROP_INPUT_SOURCE,
+ g_param_spec_enum ("input-source",
+ P_("Input source"),
+ P_("Source type for the device"),
+ GDK_TYPE_INPUT_SOURCE,
+ GDK_SOURCE_MOUSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+ /**
+ * GdkDevice:input-mode:
+ *
+ * Input mode for the device.
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (object_class,
+ PROP_INPUT_MODE,
+ g_param_spec_enum ("input-mode",
+ P_("Input mode for the device"),
+ P_("Input mode for the device"),
+ GDK_TYPE_INPUT_MODE,
+ GDK_MODE_DISABLED,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GdkDevice:has-cursor:
+ *
+ * Whether the device is represented by a cursor on the screen. Devices of type
+ * %GDK_DEVICE_TYPE_MASTER will have %TRUE here.
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (object_class,
+ PROP_HAS_CURSOR,
+ g_param_spec_boolean ("has-cursor",
+ P_("Whether the device has cursor"),
+ P_("Whether there is a visible cursor following device motion"),
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+ /**
+ * GdkDevice:n-axes:
+ *
+ * Number of axes in the device.
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (object_class,
+ PROP_N_AXES,
+ g_param_spec_uint ("n-axes",
+ P_("Number of axes in the device"),
+ P_("Number of axes in the device"),
+ 0, G_MAXUINT, 0,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ g_type_class_add_private (object_class, sizeof (GdkDevicePrivate));
+}
+
+static void
+gdk_device_init (GdkDevice *device)
+{
+ GdkDevicePrivate *priv;
+
+ device->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
+ GDK_TYPE_DEVICE,
+ GdkDevicePrivate);
+
+ priv->axes = g_array_new (FALSE, TRUE, sizeof (GdkAxisInfo));
+}
+
+static void
+gdk_device_dispose (GObject *object)
+{
+ GdkDevicePrivate *priv;
+ GdkDevice *device;
+
+ device = GDK_DEVICE (object);
+ priv = device->priv;
+
+ if (priv->associated)
+ {
+ _gdk_device_set_associated_device (priv->associated, NULL);
+ g_object_unref (priv->associated);
+ priv->associated = NULL;
+ }
+
+ if (priv->axes)
+ {
+ g_array_free (priv->axes, TRUE);
+ priv->axes = NULL;
+ }
+
+ g_free (device->name);
+ g_free (device->keys);
+ g_free (device->axes);
+
+ device->name = NULL;
+ device->keys = NULL;
+ device->axes = NULL;
+
+ G_OBJECT_CLASS (gdk_device_parent_class)->dispose (object);
+}
+
+static void
+gdk_device_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdkDevice *device = GDK_DEVICE (object);
+ GdkDevicePrivate *priv = device->priv;
+
+ switch (prop_id)
+ {
+ case PROP_DISPLAY:
+ priv->display = g_value_get_object (value);
+ break;
+ case PROP_DEVICE_MANAGER:
+ priv->device_manager = g_value_get_object (value);
+ break;
+ case PROP_NAME:
+ if (device->name)
+ g_free (device->name);
+
+ device->name = g_value_dup_string (value);
+ break;
+ case PROP_TYPE:
+ priv->type = g_value_get_enum (value);
+ break;
+ case PROP_INPUT_SOURCE:
+ device->source = g_value_get_enum (value);
+ break;
+ case PROP_INPUT_MODE:
+ gdk_device_set_mode (device, g_value_get_enum (value));
+ break;
+ case PROP_HAS_CURSOR:
+ device->has_cursor = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdk_device_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdkDevice *device = GDK_DEVICE (object);
+ GdkDevicePrivate *priv = device->priv;
+
+ switch (prop_id)
+ {
+ case PROP_DISPLAY:
+ g_value_set_object (value, priv->display);
+ break;
+ case PROP_DEVICE_MANAGER:
+ g_value_set_object (value, priv->device_manager);
+ break;
+ case PROP_ASSOCIATED_DEVICE:
+ g_value_set_object (value, priv->associated);
+ break;
+ case PROP_NAME:
+ g_value_set_string (value,
+ device->name);
+ break;
+ case PROP_TYPE:
+ g_value_set_enum (value, priv->type);
+ break;
+ case PROP_INPUT_SOURCE:
+ g_value_set_enum (value, device->source);
+ break;
+ case PROP_INPUT_MODE:
+ g_value_set_enum (value, device->mode);
+ break;
+ case PROP_HAS_CURSOR:
+ g_value_set_boolean (value,
+ device->has_cursor);
+ break;
+ case PROP_N_AXES:
+ g_value_set_uint (value, priv->axes->len);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/**
+ * gdk_device_get_state:
+ * @device: a #GdkDevice.
+ * @window: a #GdkWindow.
+ * @axes: an array of doubles to store the values of the axes of @device in,
+ * or %NULL.
+ * @mask: location to store the modifiers, or %NULL.
+ *
+ * Gets the current state of a device relative to @window.
+ */
+void
+gdk_device_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask)
+{
+ g_return_if_fail (GDK_IS_DEVICE (device));
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ if (GDK_DEVICE_GET_CLASS (device)->get_state)
+ GDK_DEVICE_GET_CLASS (device)->get_state (device, window, axes, mask);
+}
+
+/**
+ * gdk_device_get_history:
+ * @device: a #GdkDevice
+ * @window: the window with respect to which which the event coordinates will be reported
+ * @start: starting timestamp for range of events to return
+ * @stop: ending timestamp for the range of events to return
+ * @events: (array length=n_events) (out) (transfer none): location to store a newly-allocated array of #GdkTimeCoord, or %NULL
+ * @n_events: location to store the length of @events, or %NULL
+ *
+ * Obtains the motion history for a device; given a starting and
+ * ending timestamp, return all events in the motion history for
+ * the device in the given range of time. Some windowing systems
+ * do not support motion history, in which case, %FALSE will
+ * be returned. (This is not distinguishable from the case where
+ * motion history is supported and no events were found.)
+ *
+ * Return value: %TRUE if the windowing system supports motion history and
+ * at least one event was found.
+ **/
+gboolean
+gdk_device_get_history (GdkDevice *device,
+ GdkWindow *window,
+ guint32 start,
+ guint32 stop,
+ GdkTimeCoord ***events,
+ guint *n_events)
+{
+ g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
+ g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
+
+ if (n_events)
+ *n_events = 0;
+
+ if (events)
+ *events = NULL;
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return FALSE;
+
+ if (!GDK_DEVICE_GET_CLASS (device)->get_history)
+ return FALSE;
+
+ return GDK_DEVICE_GET_CLASS (device)->get_history (device, window,
+ start, stop,
+ events, n_events);
+}
+
+GdkTimeCoord **
+_gdk_device_allocate_history (GdkDevice *device,
+ guint n_events)
+{
+ GdkTimeCoord **result = g_new (GdkTimeCoord *, n_events);
+ gint i;
+
+ for (i = 0; i < n_events; i++)
+ result[i] = g_malloc (sizeof (GdkTimeCoord) -
+ sizeof (double) * (GDK_MAX_TIMECOORD_AXES - device->num_axes));
+ return result;
+}
+
+/**
+ * gdk_device_free_history:
+ * @events: (inout) (transfer none): an array of #GdkTimeCoord.
+ * @n_events: the length of the array.
+ *
+ * Frees an array of #GdkTimeCoord that was returned by gdk_device_get_history().
+ */
+void
+gdk_device_free_history (GdkTimeCoord **events,
+ gint n_events)
+{
+ gint i;
+
+ for (i = 0; i < n_events; i++)
+ g_free (events[i]);
+
+ g_free (events);
+}
+
+/**
+ * gdk_device_get_name:
+ * @device: a #GdkDevice
+ *
+ * Determines the name of the device.
+ *
+ * Return value: a name
+ *
+ * Since: 2.20
+ **/
+const gchar *
+gdk_device_get_name (GdkDevice *device)
+{
+ g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
+
+ return device->name;
+}
+
+/**
+ * gdk_device_get_has_cursor:
+ * @device: a #GdkDevice
+ *
+ * Determines whether the pointer follows device motion.
+ *
+ * Return value: %TRUE if the pointer follows device motion
+ *
+ * Since: 2.20
+ **/
+gboolean
+gdk_device_get_has_cursor (GdkDevice *device)
+{
+ g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
+
+ return device->has_cursor;
+}
+
+/**
+ * gdk_device_get_source:
+ * @device: a #GdkDevice
+ *
+ * Determines the type of the device.
+ *
+ * Return value: a #GdkInputSource
+ *
+ * Since: 2.20
+ **/
+GdkInputSource
+gdk_device_get_source (GdkDevice *device)
+{
+ g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
+
+ return device->source;
+}
+
+/**
+ * gdk_device_set_source:
+ * @device: a #GdkDevice.
+ * @source: the source type.
+ *
+ * Sets the source type for an input device.
+ **/
+void
+gdk_device_set_source (GdkDevice *device,
+ GdkInputSource source)
+{
+ g_return_if_fail (GDK_IS_DEVICE (device));
+
+ device->source = source;
+}
+
+/**
+ * gdk_device_get_mode:
+ * @device: a #GdkDevice
+ *
+ * Determines the mode of the device.
+ *
+ * Return value: a #GdkInputSource
+ *
+ * Since: 2.20
+ **/
+GdkInputMode
+gdk_device_get_mode (GdkDevice *device)
+{
+ g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
+
+ return device->mode;
+}
+
+/**
+ * gdk_device_set_mode:
+ * @device: a #GdkDevice.
+ * @mode: the input mode.
+ *
+ * Sets a the mode of an input device. The mode controls if the
+ * device is active and whether the device's range is mapped to the
+ * entire screen or to a single window.
+ *
+ * Returns: %TRUE if the mode was successfully changed.
+ **/
+gboolean
+gdk_device_set_mode (GdkDevice *device,
+ GdkInputMode mode)
+{
+ g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
+
+ if (device->mode == mode)
+ return TRUE;
+
+ if (mode == GDK_MODE_DISABLED &&
+ gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER)
+ return FALSE;
+
+ /* FIXME: setting has_cursor when mode is window? */
+
+ device->mode = mode;
+ g_object_notify (G_OBJECT (device), "input-mode");
+
+ if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER)
+ _gdk_input_check_extension_events (device);
+
+ return TRUE;
+}
+
+/**
+ * gdk_device_get_key:
+ * @device: a #GdkDevice.
+ * @index_: the index of the macro button to get.
+ * @keyval: return value for the keyval.
+ * @modifiers: return value for modifiers.
+ *
+ * If @index_ has a valid keyval, this function will return %TRUE
+ * and fill in @keyval and @modifiers with the keyval settings.
+ *
+ * Returns: %TRUE if keyval is set for @index.
+ *
+ * Since: 2.20
+ **/
+gboolean
+gdk_device_get_key (GdkDevice *device,
+ guint index_,
+ guint *keyval,
+ GdkModifierType *modifiers)
+{
+ g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
+ g_return_val_if_fail (index_ < device->num_keys, FALSE);
+
+ if (!device->keys[index_].keyval &&
+ !device->keys[index_].modifiers)
+ return FALSE;
+
+ if (keyval)
+ *keyval = device->keys[index_].keyval;
+
+ if (modifiers)
+ *modifiers = device->keys[index_].modifiers;
+
+ return TRUE;
+}
+
+/**
+ * gdk_device_set_key:
+ * @device: a #GdkDevice
+ * @index_: the index of the macro button to set
+ * @keyval: the keyval to generate
+ * @modifiers: the modifiers to set
+ *
+ * Specifies the X key event to generate when a macro button of a device
+ * is pressed.
+ **/
+void
+gdk_device_set_key (GdkDevice *device,
+ guint index_,
+ guint keyval,
+ GdkModifierType modifiers)
+{
+ g_return_if_fail (GDK_IS_DEVICE (device));
+ g_return_if_fail (index_ < device->num_keys);
+
+ device->keys[index_].keyval = keyval;
+ device->keys[index_].modifiers = modifiers;
+}
+
+/**
+ * gdk_device_get_axis_use:
+ * @device: a #GdkDevice.
+ * @index_: the index of the axis.
+ *
+ * Returns the axis use for @index_.
+ *
+ * Returns: a #GdkAxisUse specifying how the axis is used.
+ *
+ * Since: 2.20
+ **/
+GdkAxisUse
+gdk_device_get_axis_use (GdkDevice *device,
+ guint index_)
+{
+ g_return_val_if_fail (GDK_IS_DEVICE (device), GDK_AXIS_IGNORE);
+ g_return_val_if_fail (index_ < device->num_axes, GDK_AXIS_IGNORE);
+
+ return device->axes[index_].use;
+}
+
+/**
+ * gdk_device_set_axis_use:
+ * @device: a #GdkDevice
+ * @index_: the index of the axis
+ * @use: specifies how the axis is used
+ *
+ * Specifies how an axis of a device is used.
+ **/
+void
+gdk_device_set_axis_use (GdkDevice *device,
+ guint index_,
+ GdkAxisUse use)
+{
+ GdkDevicePrivate *priv;
+ GdkAxisInfo *info;
+
+ g_return_if_fail (GDK_IS_DEVICE (device));
+ g_return_if_fail (index_ < device->num_axes);
+
+ priv = device->priv;
+ info = &g_array_index (priv->axes, GdkAxisInfo, index_);
+ info->use = use;
+
+ device->axes[index_].use = use;
+
+ switch (use)
+ {
+ case GDK_AXIS_X:
+ case GDK_AXIS_Y:
+ device->axes[index_].min = info->min_axis = 0;
+ device->axes[index_].max = info->max_axis = 0;
+ break;
+ case GDK_AXIS_XTILT:
+ case GDK_AXIS_YTILT:
+ device->axes[index_].min = info->min_axis = -1;
+ device->axes[index_].max = info->max_axis = 1;
+ break;
+ default:
+ device->axes[index_].min = info->min_axis = 0;
+ device->axes[index_].max = info->max_axis = 1;
+ break;
+ }
+}
+
+/**
+ * gdk_device_get_display:
+ * @device: a #GdkDevice
+ *
+ * Returns the #GdkDisplay to which @device pertains.
+ *
+ * Returns: a #GdkDisplay. This memory is owned by GTK+,
+ * and must not be freed or unreffed.
+ *
+ * Since: 3.0
+ **/
+GdkDisplay *
+gdk_device_get_display (GdkDevice *device)
+{
+ GdkDevicePrivate *priv;
+
+ g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
+
+ priv = device->priv;
+
+ return priv->display;
+}
+
+/**
+ * gdk_device_get_associated_device:
+ * @device: a #GdkDevice
+ *
+ * Returns the associated device to @device, if @device is of type
+ * %GDK_DEVICE_TYPE_MASTER, it will return the paired pointer or
+ * keyboard.
+ *
+ * If @device is of type %GDK_DEVICE_TYPE_SLAVE, it will return
+ * the master device to which @device is attached to.
+ *
+ * If @device is of type %GDK_DEVICE_TYPE_FLOATING, %NULL will be
+ * returned, as there is no associated device.
+ *
+ * Returns: The associated device, or %NULL
+ *
+ * Since: 3.0
+ **/
+GdkDevice *
+gdk_device_get_associated_device (GdkDevice *device)
+{
+ GdkDevicePrivate *priv;
+
+ g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
+
+ priv = device->priv;
+
+ return priv->associated;
+}
+
+void
+_gdk_device_set_associated_device (GdkDevice *device,
+ GdkDevice *associated)
+{
+ GdkDevicePrivate *priv;
+
+ g_return_if_fail (GDK_IS_DEVICE (device));
+ g_return_if_fail (GDK_IS_DEVICE (associated));
+
+ priv = device->priv;
+
+ if (priv->associated == associated)
+ return;
+
+ if (priv->associated)
+ {
+ g_object_unref (priv->associated);
+ priv->associated = NULL;
+ }
+
+ if (associated)
+ priv->associated = g_object_ref (associated);
+}
+
+/**
+ * gdk_device_get_device_type:
+ * @device: a #GdkDevice
+ *
+ * Returns the device type for @device.
+ *
+ * Returns: the #GdkDeviceType for @device.
+ *
+ * Since: 3.0
+ **/
+GdkDeviceType
+gdk_device_get_device_type (GdkDevice *device)
+{
+ GdkDevicePrivate *priv;
+
+ g_return_val_if_fail (GDK_IS_DEVICE (device), GDK_DEVICE_TYPE_MASTER);
+
+ priv = device->priv;
+
+ return priv->type;
+}
+
+/**
+ * gdk_device_get_n_axes:
+ * @device: a #GdkDevice
+ *
+ * Returns the number of axes the device currently has.
+ *
+ * Returns: the number of axes.
+ *
+ * Since: 3.0
+ **/
+guint
+gdk_device_get_n_axes (GdkDevice *device)
+{
+ g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
+
+ return device->num_axes;
+}
+
+/**
+ * gdk_device_list_axes:
+ * @device: a #GdkDevice
+ *
+ * Returns a #GList of #GdkAtom<!-- -->s, containing the labels for
+ * the axes that @device currently has.
+ *
+ * Returns: A #GList of #GdkAtom<!-- -->s, free with g_list_free().
+ *
+ * Since: 3.0
+ **/
+GList *
+gdk_device_list_axes (GdkDevice *device)
+{
+ GdkDevicePrivate *priv;
+ GList *axes = NULL;
+ gint i;
+
+ priv = device->priv;
+
+ for (i = 0; i < priv->axes->len; i++)
+ {
+ GdkAxisInfo axis_info;
+
+ axis_info = g_array_index (priv->axes, GdkAxisInfo, i);
+ axes = g_list_prepend (axes, GDK_ATOM_TO_POINTER (axis_info.label));
+ }
+
+ return g_list_reverse (axes);
+}
+
+/**
+ * gdk_device_get_axis_value:
+ * @device: a #GdkDevice.
+ * @axes: pointer to an array of axes
+ * @axis_label: #GdkAtom with the axis label.
+ * @value: location to store the found value.
+ *
+ * Interprets an array of double as axis values for a given device,
+ * and locates the value in the array for a given axis label, as returned
+ * by gdk_device_list_axes()
+ *
+ * Returns: %TRUE if the given axis use was found, otherwise %FALSE.
+ *
+ * Since: 3.0
+ **/
+gboolean
+gdk_device_get_axis_value (GdkDevice *device,
+ gdouble *axes,
+ GdkAtom axis_label,
+ gdouble *value)
+{
+ GdkDevicePrivate *priv;
+ gint i;
+
+ g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
+
+ if (axes == NULL)
+ return FALSE;
+
+ priv = device->priv;
+
+ for (i = 0; i < priv->axes->len; i++)
+ {
+ GdkAxisInfo axis_info;
+
+ axis_info = g_array_index (priv->axes, GdkAxisInfo, i);
+
+ if (axis_info.label != axis_label)
+ continue;
+
+ if (value)
+ *value = axes[i];
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * gdk_device_get_axis:
+ * @device: a #GdkDevice
+ * @axes: pointer to an array of axes
+ * @use: the use to look for
+ * @value: location to store the found value.
+ *
+ * Interprets an array of double as axis values for a given device,
+ * and locates the value in the array for a given axis use.
+ *
+ * Return value: %TRUE if the given axis use was found, otherwise %FALSE
+ **/
+gboolean
+gdk_device_get_axis (GdkDevice *device,
+ gdouble *axes,
+ GdkAxisUse use,
+ gdouble *value)
+{
+ GdkDevicePrivate *priv;
+ gint i;
+
+ g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
+
+ if (axes == NULL)
+ return FALSE;
+
+ priv = device->priv;
+
+ g_return_val_if_fail (priv->axes != NULL, FALSE);
+
+ for (i = 0; i < priv->axes->len; i++)
+ {
+ GdkAxisInfo axis_info;
+
+ axis_info = g_array_index (priv->axes, GdkAxisInfo, i);
+
+ if (axis_info.use != use)
+ continue;
+
+ if (value)
+ *value = axes[i];
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static GdkEventMask
+get_native_grab_event_mask (GdkEventMask grab_mask)
+{
+ /* Similar to the above but for pointer events only */
+ return
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
+ GDK_SCROLL_MASK |
+ (grab_mask &
+ ~(GDK_POINTER_MOTION_HINT_MASK |
+ GDK_BUTTON_MOTION_MASK |
+ GDK_BUTTON1_MOTION_MASK |
+ GDK_BUTTON2_MOTION_MASK |
+ GDK_BUTTON3_MOTION_MASK));
+}
+
+/**
+ * gdk_device_grab:
+ * @device: a #GdkDevice
+ * @window: the #GdkWindow which will own the grab (the grab window)
+ * @grab_ownership: specifies the grab ownership.
+ * @owner_events: if %FALSE then all device events are reported with respect to
+ * @window and are only reported if selected by @event_mask. If
+ * %TRUE then pointer events for this application are reported
+ * as normal, but pointer events outside this application are
+ * reported with respect to @window and only if selected by
+ * @event_mask. In either mode, unreported events are discarded.
+ * @event_mask: specifies the event mask, which is used in accordance with
+ * @owner_events.
+ * @cursor: the cursor to display while the grab is active if the device is
+ * a pointer. If this is %NULL then the normal cursors are used for
+ * @window and its descendants, and the cursor for @window is used
+ * elsewhere.
+ * @time_: the timestamp of the event which led to this pointer grab. This
+ * usually comes from the #GdkEvent struct, though %GDK_CURRENT_TIME
+ * can be used if the time isn't known.
+ *
+ * Grabs the device so that all events coming from this device are passed to
+ * this application until the device is ungrabbed with gdk_device_ungrab(),
+ * or the window becomes unviewable. This overrides any previous grab on the device
+ * by this client.
+ *
+ * Device grabs are used for operations which need complete control over the
+ * given device events (either pointer or keyboard). For example in GTK+ this
+ * is used for Drag and Drop operations, popup menus and such.
+ *
+ * Note that if the event mask of an X window has selected both button press
+ * and button release events, then a button press event will cause an automatic
+ * pointer grab until the button is released. X does this automatically since
+ * most applications expect to receive button press and release events in pairs.
+ * It is equivalent to a pointer grab on the window with @owner_events set to
+ * %TRUE.
+ *
+ * If you set up anything at the time you take the grab that needs to be
+ * cleaned up when the grab ends, you should handle the #GdkEventGrabBroken
+ * events that are emitted when the grab ends unvoluntarily.
+ *
+ * Returns: %GDK_GRAB_SUCCESS if the grab was successful.
+ *
+ * Since: 3.0
+ **/
+GdkGrabStatus
+gdk_device_grab (GdkDevice *device,
+ GdkWindow *window,
+ GdkGrabOwnership grab_ownership,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkCursor *cursor,
+ guint32 time_)
+{
+ GdkGrabStatus res;
+ GdkWindow *native;
+
+ g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
+ g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+
+ if (_gdk_native_windows)
+ native = window;
+ else
+ native = gdk_window_get_toplevel (window);
+
+ while (((GdkWindowObject *) native)->window_type == GDK_WINDOW_OFFSCREEN)
+ {
+ native = gdk_offscreen_window_get_embedder (native);
+
+ if (native == NULL ||
+ (!_gdk_window_has_impl (native) &&
+ !gdk_window_is_viewable (native)))
+ return GDK_GRAB_NOT_VIEWABLE;
+
+ native = gdk_window_get_toplevel (native);
+ }
+
+ res = _gdk_windowing_device_grab (device,
+ window,
+ native,
+ owner_events,
+ get_native_grab_event_mask (event_mask),
+ NULL,
+ cursor,
+ time_);
+
+ if (res == GDK_GRAB_SUCCESS)
+ {
+ GdkDisplay *display;
+ gulong serial;
+
+ display = gdk_drawable_get_display (window);
+ serial = _gdk_windowing_window_get_next_serial (display);
+
+ _gdk_display_add_device_grab (display,
+ device,
+ window,
+ native,
+ grab_ownership,
+ owner_events,
+ event_mask,
+ serial,
+ time_,
+ FALSE);
+ }
+
+ return res;
+}
+
+/* Private API */
+void
+_gdk_device_reset_axes (GdkDevice *device)
+{
+ GdkDevicePrivate *priv;
+ gint i;
+
+ priv = device->priv;
+
+ for (i = priv->axes->len - 1; i >= 0; i--)
+ g_array_remove_index (priv->axes, i);
+
+ g_object_notify (G_OBJECT (device), "n-axes");
+
+ /* This is done for backwards compatibility */
+ g_free (device->axes);
+ device->axes = NULL;
+}
+
+guint
+_gdk_device_add_axis (GdkDevice *device,
+ GdkAtom label_atom,
+ GdkAxisUse use,
+ gdouble min_value,
+ gdouble max_value,
+ gdouble resolution)
+{
+ GdkDevicePrivate *priv;
+ GdkAxisInfo axis_info;
+ guint pos;
+
+ priv = device->priv;
+
+ axis_info.use = use;
+ axis_info.label = label_atom;
+ axis_info.min_value = min_value;
+ axis_info.max_value = max_value;
+ axis_info.resolution = resolution;
+
+ switch (use)
+ {
+ case GDK_AXIS_X:
+ case GDK_AXIS_Y:
+ axis_info.min_axis = 0;
+ axis_info.max_axis = 0;
+ break;
+ case GDK_AXIS_XTILT:
+ case GDK_AXIS_YTILT:
+ axis_info.min_axis = -1;
+ axis_info.max_axis = 1;
+ break;
+ default:
+ axis_info.min_axis = 0;
+ axis_info.max_axis = 1;
+ break;
+ }
+
+ priv->axes = g_array_append_val (priv->axes, axis_info);
+ device->num_axes = priv->axes->len;
+ pos = device->num_axes - 1;
+
+ /* This is done for backwards compatibility, since the public
+ * struct doesn't actually store the device data.
+ */
+ device->axes = g_realloc (device->axes, sizeof (GdkDeviceAxis) * priv->axes->len);
+ device->axes[pos].use = axis_info.use;
+ device->axes[pos].min = axis_info.min_axis;
+ device->axes[pos].max = axis_info.max_axis;
+
+ g_object_notify (G_OBJECT (device), "n-axes");
+
+ return pos;
+}
+
+void
+_gdk_device_set_keys (GdkDevice *device,
+ guint num_keys)
+{
+ if (device->keys)
+ g_free (device->keys);
+
+ device->num_keys = num_keys;
+ device->keys = g_new0 (GdkDeviceKey, num_keys);
+}
+
+static GdkAxisInfo *
+find_axis_info (GArray *array,
+ GdkAxisUse use)
+{
+ GdkAxisInfo *info;
+ gint i;
+
+ for (i = 0; i < GDK_AXIS_LAST; i++)
+ {
+ info = &g_array_index (array, GdkAxisInfo, i);
+
+ if (info->use == use)
+ return info;
+ }
+
+ return NULL;
+}
+
+GdkAxisUse
+_gdk_device_get_axis_use (GdkDevice *device,
+ guint index_)
+{
+ GdkDevicePrivate *priv;
+ GdkAxisInfo info;
+
+ priv = device->priv;
+
+ info = g_array_index (priv->axes, GdkAxisInfo, index_);
+ return info.use;
+}
+
+gboolean
+_gdk_device_translate_window_coord (GdkDevice *device,
+ GdkWindow *window,
+ guint index_,
+ gdouble value,
+ gdouble *axis_value)
+{
+ GdkDevicePrivate *priv;
+ GdkAxisInfo axis_info;
+ GdkAxisInfo *axis_info_x, *axis_info_y;
+ gdouble device_width, device_height;
+ gdouble x_offset, y_offset;
+ gdouble x_scale, y_scale;
+ gdouble x_min, y_min;
+ gdouble x_resolution, y_resolution;
+ gdouble device_aspect;
+ gint window_width, window_height;
+ GdkWindowObject *window_private;
+
+ priv = device->priv;
+
+ if (index_ >= priv->axes->len)
+ return FALSE;
+
+ axis_info = g_array_index (priv->axes, GdkAxisInfo, index_);
+
+ if (axis_info.use != GDK_AXIS_X &&
+ axis_info.use != GDK_AXIS_Y)
+ return FALSE;
+
+ if (axis_info.use == GDK_AXIS_X)
+ {
+ axis_info_x = &axis_info;
+ axis_info_y = find_axis_info (priv->axes, GDK_AXIS_Y);
+ }
+ else
+ {
+ axis_info_x = find_axis_info (priv->axes, GDK_AXIS_X);
+ axis_info_y = &axis_info;
+ }
+
+ device_width = axis_info_x->max_value - axis_info_x->min_value;
+ device_height = axis_info_y->max_value - axis_info_y->min_value;
+
+ if (device_width > 0)
+ x_min = axis_info_x->min_value;
+ else
+ {
+ device_width = gdk_screen_get_width (gdk_drawable_get_screen (window));
+ x_min = 0;
+ }
+
+ if (device_height > 0)
+ y_min = axis_info_y->min_value;
+ else
+ {
+ device_height = gdk_screen_get_height (gdk_drawable_get_screen (window));
+ y_min = 0;
+ }
+
+ window_private = (GdkWindowObject *) window;
+ gdk_drawable_get_size (window, &window_width, &window_height);
+
+ x_resolution = axis_info_x->resolution;
+ y_resolution = axis_info_y->resolution;
+
+ /*
+ * Some drivers incorrectly report the resolution of the device
+ * as zero (in partiular linuxwacom < 0.5.3 with usb tablets).
+ * This causes the device_aspect to become NaN and totally
+ * breaks windowed mode. If this is the case, the best we can
+ * do is to assume the resolution is non-zero is equal in both
+ * directions (which is true for many devices). The absolute
+ * value of the resolution doesn't matter since we only use the
+ * ratio.
+ */
+ if (x_resolution == 0 || y_resolution == 0)
+ {
+ x_resolution = 1;
+ y_resolution = 1;
+ }
+
+ device_aspect = (device_height * y_resolution) /
+ (device_width * x_resolution);
+
+ if (device_aspect * window_width >= window_height)
+ {
+ /* device taller than window */
+ x_scale = window_width / device_width;
+ y_scale = (x_scale * x_resolution) / y_resolution;
+
+ x_offset = 0;
+ y_offset = - (device_height * y_scale - window_height) / 2;
+ }
+ else
+ {
+ /* window taller than device */
+ y_scale = window_height / device_height;
+ x_scale = (y_scale * y_resolution) / x_resolution;
+
+ y_offset = 0;
+ x_offset = - (device_width * x_scale - window_width) / 2;
+ }
+
+ if (axis_value)
+ {
+ if (axis_info.use == GDK_AXIS_X)
+ *axis_value = x_offset + x_scale * (value - x_min);
+ else
+ *axis_value = y_offset + y_scale * (value - y_min);
+ }
+
+ return TRUE;
+}
+
+gboolean
+_gdk_device_translate_screen_coord (GdkDevice *device,
+ GdkWindow *window,
+ gint window_root_x,
+ gint window_root_y,
+ guint index_,
+ gdouble value,
+ gdouble *axis_value)
+{
+ GdkDevicePrivate *priv;
+ GdkAxisInfo axis_info;
+ gdouble axis_width, scale, offset;
+ GdkWindowObject *window_private;
+
+ if (device->mode != GDK_MODE_SCREEN)
+ return FALSE;
+
+ priv = device->priv;
+
+ if (index_ >= priv->axes->len)
+ return FALSE;
+
+ axis_info = g_array_index (priv->axes, GdkAxisInfo, index_);
+
+ if (axis_info.use != GDK_AXIS_X &&
+ axis_info.use != GDK_AXIS_Y)
+ return FALSE;
+
+ axis_width = axis_info.max_value - axis_info.min_value;
+ window_private = (GdkWindowObject *) window;
+
+ if (axis_info.use == GDK_AXIS_X)
+ {
+ if (axis_width > 0)
+ scale = gdk_screen_get_width (gdk_drawable_get_screen (window)) / axis_width;
+ else
+ scale = 1;
+
+ offset = - window_root_x - window_private->abs_x;
+ }
+ else
+ {
+ if (axis_width > 0)
+ scale = gdk_screen_get_height (gdk_drawable_get_screen (window)) / axis_width;
+ else
+ scale = 1;
+
+ offset = - window_root_y - window_private->abs_y;
+ }
+
+ if (axis_value)
+ *axis_value = offset + scale * (value - axis_info.min_value);
+
+ return TRUE;
+}
+
+gboolean
+_gdk_device_translate_axis (GdkDevice *device,
+ guint index_,
+ gdouble value,
+ gdouble *axis_value)
+{
+ GdkDevicePrivate *priv;
+ GdkAxisInfo axis_info;
+ gdouble axis_width, out;
+
+ priv = device->priv;
+
+ if (index_ >= priv->axes->len)
+ return FALSE;
+
+ axis_info = g_array_index (priv->axes, GdkAxisInfo, index_);
+
+ if (axis_info.use == GDK_AXIS_X ||
+ axis_info.use == GDK_AXIS_Y)
+ return FALSE;
+
+ axis_width = axis_info.max_value - axis_info.min_value;
+ out = (axis_info.max_axis * (value - axis_info.min_value) +
+ axis_info.min_axis * (axis_info.max_value - value)) / axis_width;
+
+ if (axis_value)
+ *axis_value = out;
+
+ return TRUE;
+}
+
+#define __GDK_DEVICE_C__
+#include "gdkaliasdef.c"
diff --git a/gdk/gdkdevice.h b/gdk/gdkdevice.h
new file mode 100644
index 0000000000..dfbf48aef3
--- /dev/null
+++ b/gdk/gdkdevice.h
@@ -0,0 +1,292 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdk.h> can be included directly."
+#endif
+
+#ifndef __GDK_DEVICE_H__
+#define __GDK_DEVICE_H__
+
+#include <gdk/gdktypes.h>
+
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE (gdk_device_get_type ())
+#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))
+
+typedef struct _GdkDevice GdkDevice;
+typedef struct _GdkDevicePrivate GdkDevicePrivate;
+
+typedef struct _GdkDeviceKey GdkDeviceKey;
+typedef struct _GdkDeviceAxis GdkDeviceAxis;
+typedef struct _GdkTimeCoord GdkTimeCoord;
+
+/**
+ * GdkExtensionMode:
+ * @GDK_EXTENSION_EVENTS_NONE: no extension events are desired.
+ * @GDK_EXTENSION_EVENTS_ALL: all extension events are desired.
+ * @GDK_EXTENSION_EVENTS_CURSOR: extension events are desired only if a cursor
+ * will be displayed for the device.
+ *
+ * An enumeration used to specify which extension events
+ * are desired for a particular widget.
+ */
+typedef enum
+{
+ GDK_EXTENSION_EVENTS_NONE,
+ GDK_EXTENSION_EVENTS_ALL,
+ GDK_EXTENSION_EVENTS_CURSOR
+} GdkExtensionMode;
+
+/**
+ * GdkInputSource:
+ * @GDK_SOURCE_MOUSE: the device is a mouse. (This will be reported for the core
+ * pointer, even if it is something else, such as a trackball.)
+ * @GDK_SOURCE_PEN: the device is a stylus of a graphics tablet or similar device.
+ * @GDK_SOURCE_ERASER: the device is an eraser. Typically, this would be the other end
+ * of a stylus on a graphics tablet.
+ * @GDK_SOURCE_CURSOR: the device is a graphics tablet "puck" or similar device.
+ * @GDK_SOURCE_KEYBOARD: the device is a keyboard.
+ *
+ * An enumeration describing the type of an input device in general terms.
+ */
+typedef enum
+{
+ GDK_SOURCE_MOUSE,
+ GDK_SOURCE_PEN,
+ GDK_SOURCE_ERASER,
+ GDK_SOURCE_CURSOR,
+ GDK_SOURCE_KEYBOARD
+} GdkInputSource;
+
+/**
+ * GdkInputMode:
+ * @GDK_MODE_DISABLED: the device is disabled and will not report any events.
+ * @GDK_MODE_SCREEN: the device is enabled. The device's coordinate space
+ * maps to the entire screen.
+ * @GDK_MODE_WINDOW: the device is enabled. The device's coordinate space
+ * is mapped to a single window. The manner in which this window
+ * is chosen is undefined, but it will typically be the same
+ * way in which the focus window for key events is determined.
+ *
+ * An enumeration that describes the mode of an input device.
+ */
+typedef enum
+{
+ GDK_MODE_DISABLED,
+ GDK_MODE_SCREEN,
+ GDK_MODE_WINDOW
+} GdkInputMode;
+
+/**
+ * GdkAxisUse:
+ * @GDK_AXIS_IGNORE: the axis is ignored.
+ * @GDK_AXIS_X: the axis is used as the x axis.
+ * @GDK_AXIS_Y: the axis is used as the y axis.
+ * @GDK_AXIS_PRESSURE: the axis is used for pressure information.
+ * @GDK_AXIS_XTILT: the axis is used for x tilt information.
+ * @GDK_AXIS_YTILT: the axis is used for x tilt information.
+ * @GDK_AXIS_WHEEL: the axis is used for wheel information.
+ * @GDK_AXIS_LAST: a constant equal to the numerically highest axis value.
+ *
+ * An enumeration describing the way in which a device
+ * axis (valuator) maps onto the predefined valuator
+ * types that GTK+ understands.
+ */
+typedef enum
+{
+ GDK_AXIS_IGNORE,
+ GDK_AXIS_X,
+ GDK_AXIS_Y,
+ GDK_AXIS_PRESSURE,
+ GDK_AXIS_XTILT,
+ GDK_AXIS_YTILT,
+ GDK_AXIS_WHEEL,
+ GDK_AXIS_LAST
+} GdkAxisUse;
+
+/**
+ * GdkDeviceType:
+ * @GDK_DEVICE_TYPE_MASTER: Device is a master (or virtual) device. There will
+ * be an associated focus indicator on the screen.
+ * @GDK_DEVICE_TYPE_SLAVE: Device is a slave (or physical) device.
+ * @GDK_DEVICE_TYPE_FLOATING: Device is a physical device, currently not attached to
+ * any virtual device.
+ *
+ * Indicates the device type. See <link linkend="GdkDeviceManager.description">above</link>
+ * for more information about the meaning of these device types.
+ */
+typedef enum {
+ GDK_DEVICE_TYPE_MASTER,
+ GDK_DEVICE_TYPE_SLAVE,
+ GDK_DEVICE_TYPE_FLOATING
+} GdkDeviceType;
+
+/**
+ * GdkDeviceKey:
+ * @keyval: the keyval to generate when the macro button is pressed.
+ * If this is 0, no keypress will be generated.
+ * @modifiers: the modifiers set for the generated key event.
+ *
+ * The <structname>GdkDeviceKey</structname> structure contains information
+ * about the mapping of one device macro button onto a normal X key event.
+ */
+struct _GdkDeviceKey
+{
+ guint keyval;
+ GdkModifierType modifiers;
+};
+
+/**
+ * GdkDeviceAxis:
+ * @use: specifies how the axis is used.
+ * @min: the minimal value that will be reported by this axis.
+ * @max: the maximal value that will be reported by this axis.
+ *
+ * The <structname>GdkDeviceAxis</structname> structure contains information
+ * about the range and mapping of a device axis.
+ */
+struct _GdkDeviceAxis
+{
+ GdkAxisUse use;
+ gdouble min;
+ gdouble max;
+};
+
+/* We don't allocate each coordinate this big, but we use it to
+ * be ANSI compliant and avoid accessing past the defined limits.
+ */
+#define GDK_MAX_TIMECOORD_AXES 128
+
+/**
+ * GdkTimeCoord:
+ * @time: The timestamp for this event.
+ * @axes: the values of the device's axes.
+ *
+ * The #GdkTimeCoord structure stores a single event in a motion history.
+ */
+struct _GdkTimeCoord
+{
+ guint32 time;
+ gdouble axes[GDK_MAX_TIMECOORD_AXES];
+};
+
+struct _GdkDevice
+{
+ GObject parent_instance;
+
+ /* All fields are read-only */
+ gchar *GSEAL (name);
+ GdkInputSource GSEAL (source);
+ GdkInputMode GSEAL (mode);
+ gboolean GSEAL (has_cursor); /* TRUE if a X pointer follows device motion */
+
+ gint GSEAL (num_axes);
+ GdkDeviceAxis *GSEAL (axes);
+
+ gint GSEAL (num_keys);
+ GdkDeviceKey *GSEAL (keys);
+
+ /*< private >*/
+ GdkDevicePrivate *priv;
+};
+
+GType gdk_device_get_type (void) G_GNUC_CONST;
+
+G_CONST_RETURN gchar *gdk_device_get_name (GdkDevice *device);
+gboolean gdk_device_get_has_cursor (GdkDevice *device);
+
+/* Functions to configure a device */
+GdkInputSource gdk_device_get_source (GdkDevice *device);
+void gdk_device_set_source (GdkDevice *device,
+ GdkInputSource source);
+
+GdkInputMode gdk_device_get_mode (GdkDevice *device);
+gboolean gdk_device_set_mode (GdkDevice *device,
+ GdkInputMode mode);
+
+gboolean gdk_device_get_key (GdkDevice *device,
+ guint index_,
+ guint *keyval,
+ GdkModifierType *modifiers);
+void gdk_device_set_key (GdkDevice *device,
+ guint index_,
+ guint keyval,
+ GdkModifierType modifiers);
+
+GdkAxisUse gdk_device_get_axis_use (GdkDevice *device,
+ guint index_);
+void gdk_device_set_axis_use (GdkDevice *device,
+ guint index_,
+ GdkAxisUse use);
+
+
+void gdk_device_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask);
+gboolean gdk_device_get_history (GdkDevice *device,
+ GdkWindow *window,
+ guint32 start,
+ guint32 stop,
+ GdkTimeCoord ***events,
+ guint *n_events);
+void gdk_device_free_history (GdkTimeCoord **events,
+ gint n_events);
+
+guint gdk_device_get_n_axes (GdkDevice *device);
+GList * gdk_device_list_axes (GdkDevice *device);
+gboolean gdk_device_get_axis_value (GdkDevice *device,
+ gdouble *axes,
+ GdkAtom axis_label,
+ gdouble *value);
+
+gboolean gdk_device_get_axis (GdkDevice *device,
+ gdouble *axes,
+ GdkAxisUse use,
+ gdouble *value);
+GdkDisplay * gdk_device_get_display (GdkDevice *device);
+
+GdkDevice * gdk_device_get_associated_device (GdkDevice *device);
+
+GdkDeviceType gdk_device_get_device_type (GdkDevice *device);
+
+GdkGrabStatus gdk_device_grab (GdkDevice *device,
+ GdkWindow *window,
+ GdkGrabOwnership grab_ownership,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkCursor *cursor,
+ guint32 time_);
+
+void gdk_device_ungrab (GdkDevice *device,
+ guint32 time_);
+
+gboolean gdk_device_grab_info_libgtk_only (GdkDisplay *display,
+ GdkDevice *device,
+ GdkWindow **grab_window,
+ gboolean *owner_events);
+
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_H__ */
diff --git a/gdk/gdkdevicemanager.c b/gdk/gdkdevicemanager.c
new file mode 100644
index 0000000000..5bce0fcf91
--- /dev/null
+++ b/gdk/gdkdevicemanager.c
@@ -0,0 +1,302 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+#include "gdkdevicemanager.h"
+#include "gdkintl.h"
+#include "gdkinternals.h"
+#include "gdkalias.h"
+
+/**
+ * SECTION:gdkdevicemanager
+ * @Short_description: Functions for handling input devices
+ * @Long_description: In addition to a single pointer and keyboard for user interface input, GDK
+ * contains support for a variety of input devices, including graphics tablets,
+ * touchscreens and multiple pointers/keyboards interacting simultaneously with
+ * the user interface. Under X, the support for multiple input devices is done
+ * through the <firstterm>XInput 2</firstterm> extension, which also supports
+ * additional features such as sub-pixel positioning information and additional
+ * device-dependent information.
+ * @Title: GdkDeviceManager
+ * @See_also: #GdkDevice, #GdkEvent, gdk_enable_multidevice()
+ *
+ * By default, GDK supports the traditional single keyboard/pointer input scheme (Plus additional
+ * special input devices such as tablets. In short, backwards compatible with 2.X). Since version 3.0,
+ * if gdk_enable_multidevice() is called before gdk_display_open() and the platform supports it, GDK
+ * will be aware of multiple keyboard/pointer pairs interacting simultaneously with the user interface.
+ *
+ * Conceptually, in multidevice mode there are 2 device types, virtual devices (or master devices)
+ * are represented by the pointer cursors and keyboard foci that are seen on the screen. physical
+ * devices (or slave devices) represent the hardware that is controlling the virtual devices, and
+ * thus has no visible cursor on the screen.
+ *
+ * Virtual devices are always paired, there is a keyboard device for every pointer device,
+ * associations between devices may be inspected through gdk_device_get_associated_device().
+ *
+ * There may be several virtual devices, and several physical devices could be controlling each of
+ * these virtual devices. Physical devices may also be "floating", which means they are not attached
+ * to any virtual device.
+ *
+ * By default, GDK will automatically listen for events coming from all master devices, setting the
+ * #GdkDevice for all events coming from input devices
+ * <footnote>
+ * Events containing device information are #GDK_MOTION_NOTIFY, #GDK_BUTTON_PRESS, #GDK_2BUTTON_PRESS,
+ * #GDK_3BUTTON_PRESS, #GDK_BUTTON_RELEASE, #GDK_SCROLL, #GDK_KEY_PRESS, #GDK_KEY_RELEASE,
+ * #GDK_ENTER_NOTIFY, #GDK_LEAVE_NOTIFY, #GDK_FOCUS_CHANGE, #GDK_PROXIMITY_IN, #GDK_PROXIMITY_OUT,
+ * #GDK_DRAG_ENTER, #GDK_DRAG_LEAVE, #GDK_DRAG_MOTION, #GDK_DRAG_STATUS, #GDK_DROP_START,
+ * #GDK_DROP_FINISHED and #GDK_GRAB_BROKEN.
+ * </footnote>
+ * , although gdk_window_set_support_multidevice() has to be called on #GdkWindow<!-- --> in order to
+ * support additional features of multiple pointer interaction, such as multiple, per-device enter/leave
+ * events. The default setting will emit just one enter/leave event pair for all devices on the window.
+ * See gdk_window_set_support_multidevice() documentation for more information.
+ *
+ * In order to listen for events coming from other than a virtual device, gdk_window_set_device_events()
+ * must be called. Generally, this function can be used to modify the event mask for any given device.
+ *
+ * Input devices may also provide additional information besides X/Y. For example, graphics tablets may
+ * also provide pressure and X/Y tilt information. This information is device-dependent, and may be
+ * queried through gdk_device_get_axis(). In multidevice mode, virtual devices will change axes in order
+ * to always represent the physical device that is routing events through it. Whenever the physical device
+ * changes, the #GdkDevice:n-axes property will be notified, and gdk_device_list_axes() will return the
+ * new device axes.
+ *
+ * Devices may also have associated <firstterm>keys</firstterm> or macro buttons. Such keys can be
+ * globally set to map into normal X keyboard events. The mapping is set using gdk_device_set_key().
+ *
+ * In order to query the device hierarchy and be aware of changes in the device hierarchy (such as
+ * virtual devices being created or removed, or physical devices being plugged or unplugged), GDK
+ * provides #GdkDeviceManager. On X11, multidevice support is implemented through XInput 2. If
+ * gdk_enable_multidevice() is called, the XInput 2.x #GdkDeviceManager implementation will be used
+ * as input source, else either the core or XInput 1.x implementations will be used.
+ */
+
+static void gdk_device_manager_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gdk_device_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+
+G_DEFINE_ABSTRACT_TYPE (GdkDeviceManager, gdk_device_manager, G_TYPE_OBJECT)
+
+enum {
+ PROP_0,
+ PROP_DISPLAY
+};
+
+enum {
+ DEVICE_ADDED,
+ DEVICE_REMOVED,
+ DEVICE_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0 };
+
+
+struct _GdkDeviceManagerPrivate
+{
+ GdkDisplay *display;
+};
+
+
+static void
+gdk_device_manager_class_init (GdkDeviceManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = gdk_device_manager_set_property;
+ object_class->get_property = gdk_device_manager_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY,
+ g_param_spec_object ("display",
+ P_("Display"),
+ P_("Display for the device manager"),
+ GDK_TYPE_DISPLAY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GdkDeviceManager::device-added:
+ * @device_manager: the object on which the signal is emitted
+ * @device: the newly added #GdkDevice.
+ *
+ * The ::device-added signal is emitted either when a new master
+ * pointer is created, or when a slave (Hardware) input device
+ * is plugged in.
+ */
+ signals [DEVICE_ADDED] =
+ g_signal_new (g_intern_static_string ("device-added"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdkDeviceManagerClass, device_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ GDK_TYPE_DEVICE);
+
+ /**
+ * GdkDeviceManager::device-removed:
+ * @device_manager: the object on which the signal is emitted
+ * @device: the just removed #GdkDevice.
+ *
+ * The ::device-removed signal is emitted either when a master
+ * pointer is removed, or when a slave (Hardware) input device
+ * is unplugged.
+ */
+ signals [DEVICE_REMOVED] =
+ g_signal_new (g_intern_static_string ("device-removed"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdkDeviceManagerClass, device_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ GDK_TYPE_DEVICE);
+
+ /**
+ * GdkDeviceManager::device-changed:
+ * @device_manager: the object on which the signal is emitted
+ * @device: the #GdkDevice that changed.
+ *
+ * The ::device-changed signal is emitted either when some
+ * #GdkDevice has changed the number of either axes or keys.
+ * For example In X this will normally happen when the slave
+ * device routing events through the master device changes,
+ * in that case the master device will change to reflect the
+ * new slave device axes and keys.
+ */
+ signals [DEVICE_CHANGED] =
+ g_signal_new (g_intern_static_string ("device-changed"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdkDeviceManagerClass, device_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ GDK_TYPE_DEVICE);
+
+ g_type_class_add_private (object_class, sizeof (GdkDeviceManagerPrivate));
+}
+
+static void
+gdk_device_manager_init (GdkDeviceManager *device_manager)
+{
+ GdkDeviceManagerPrivate *priv;
+
+ device_manager->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (device_manager,
+ GDK_TYPE_DEVICE_MANAGER,
+ GdkDeviceManagerPrivate);
+}
+
+static void
+gdk_device_manager_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdkDeviceManagerPrivate *priv;
+
+ priv = GDK_DEVICE_MANAGER (object)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_DISPLAY:
+ priv->display = g_value_get_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdk_device_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdkDeviceManagerPrivate *priv;
+
+ priv = GDK_DEVICE_MANAGER (object)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_DISPLAY:
+ g_value_set_object (value, priv->display);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/**
+ * gdk_device_manager_get_display:
+ * @device_manager: a #GdkDeviceManager
+ *
+ * Gets the #GdkDisplay associated to @device_manager.
+ *
+ * Returns: the #GdkDisplay to which @device_manager is
+ * associated to, or #NULL.
+ *
+ * Since: 3.0
+ **/
+GdkDisplay *
+gdk_device_manager_get_display (GdkDeviceManager *device_manager)
+{
+ GdkDeviceManagerPrivate *priv;
+
+ g_return_val_if_fail (GDK_IS_DEVICE_MANAGER (device_manager), NULL);
+
+ priv = device_manager->priv;
+
+ return priv->display;
+}
+
+/**
+ * gdk_device_manager_list_devices:
+ * @device_manager: a #GdkDeviceManager
+ * @type: device type to get.
+ *
+ * Returns the list of devices of type @type currently attached to
+ * @device_manager.
+ *
+ * Returns: a list of #GdkDevice<!-- -->s. The returned list must be
+ * freed with g_list_free (). The list elements are owned by
+ * GTK+ and must not be freed or unreffed.
+ *
+ * Since: 3.0
+ **/
+GList *
+gdk_device_manager_list_devices (GdkDeviceManager *device_manager,
+ GdkDeviceType type)
+{
+ g_return_val_if_fail (GDK_IS_DEVICE_MANAGER (device_manager), NULL);
+
+ return GDK_DEVICE_MANAGER_GET_CLASS (device_manager)->list_devices (device_manager, type);
+}
+
+#define __GDK_DEVICE_MANAGER_C__
+#include "gdkaliasdef.c"
diff --git a/gdk/gdkdevicemanager.h b/gdk/gdkdevicemanager.h
new file mode 100644
index 0000000000..32ac376884
--- /dev/null
+++ b/gdk/gdkdevicemanager.h
@@ -0,0 +1,76 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdk.h> can be included directly."
+#endif
+
+#ifndef __GDK_DEVICE_MANAGER_H__
+#define __GDK_DEVICE_MANAGER_H__
+
+#include <gdk/gdktypes.h>
+#include <gdk/gdkdevice.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_MANAGER (gdk_device_manager_get_type ())
+#define GDK_DEVICE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_MANAGER, GdkDeviceManager))
+#define GDK_DEVICE_MANAGER_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_MANAGER, GdkDeviceManagerClass))
+#define GDK_IS_DEVICE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_MANAGER))
+#define GDK_IS_DEVICE_MANAGER_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_MANAGER))
+#define GDK_DEVICE_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_MANAGER, GdkDeviceManagerClass))
+
+typedef struct _GdkDeviceManager GdkDeviceManager;
+typedef struct _GdkDeviceManagerPrivate GdkDeviceManagerPrivate;
+typedef struct _GdkDeviceManagerClass GdkDeviceManagerClass;
+
+struct _GdkDeviceManager
+{
+ GObject parent_instance;
+
+ /*< private >*/
+ GdkDeviceManagerPrivate *priv;
+};
+
+struct _GdkDeviceManagerClass
+{
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (* device_added) (GdkDeviceManager *device_manager,
+ GdkDevice *device);
+ void (* device_removed) (GdkDeviceManager *device_manager,
+ GdkDevice *device);
+ void (* device_changed) (GdkDeviceManager *device_manager,
+ GdkDevice *device);
+
+ /* VMethods */
+ GList * (* list_devices) (GdkDeviceManager *device_manager,
+ GdkDeviceType type);
+};
+
+GType gdk_device_manager_get_type (void) G_GNUC_CONST;
+
+GdkDisplay * gdk_device_manager_get_display (GdkDeviceManager *device_manager);
+GList * gdk_device_manager_list_devices (GdkDeviceManager *device_manager,
+ GdkDeviceType type);
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_MANAGER_H__ */
diff --git a/gdk/gdkdeviceprivate.h b/gdk/gdkdeviceprivate.h
new file mode 100644
index 0000000000..15f0546954
--- /dev/null
+++ b/gdk/gdkdeviceprivate.h
@@ -0,0 +1,135 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdk.h> can be included directly."
+#endif
+
+#ifndef __GDK_DEVICE_PRIVATE_H__
+#define __GDK_DEVICE_PRIVATE_H__
+
+#include <gdk/gdkdevice.h>
+#include <gdk/gdkevents.h>
+
+G_BEGIN_DECLS
+
+#define GDK_DEVICE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE, GdkDeviceClass))
+#define GDK_IS_DEVICE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE))
+#define GDK_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE, GdkDeviceClass))
+
+typedef struct _GdkDeviceClass GdkDeviceClass;
+
+struct _GdkDeviceClass
+{
+ GObjectClass parent_class;
+
+ gboolean (* get_history) (GdkDevice *device,
+ GdkWindow *window,
+ guint32 start,
+ guint32 stop,
+ GdkTimeCoord ***events,
+ guint *n_events);
+
+ void (* get_state) (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask);
+
+ void (* set_window_cursor) (GdkDevice *device,
+ GdkWindow *window,
+ GdkCursor *cursor);
+
+ void (* warp) (GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y);
+ gboolean (* query_state) (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow **root_window,
+ GdkWindow **child_window,
+ gint *root_x,
+ gint *root_y,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask);
+ GdkGrabStatus (* grab) (GdkDevice *device,
+ GdkWindow *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time_);
+ void (*ungrab) (GdkDevice *device,
+ guint32 time_);
+
+ GdkWindow * (* window_at_position) (GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel);
+ void (* select_window_events) (GdkDevice *device,
+ GdkWindow *window,
+ GdkEventMask event_mask);
+};
+
+void _gdk_device_set_associated_device (GdkDevice *device,
+ GdkDevice *relative);
+
+void _gdk_device_reset_axes (GdkDevice *device);
+guint _gdk_device_add_axis (GdkDevice *device,
+ GdkAtom label_atom,
+ GdkAxisUse use,
+ gdouble min_value,
+ gdouble max_value,
+ gdouble resolution);
+
+void _gdk_device_set_keys (GdkDevice *device,
+ guint num_keys);
+
+GdkAxisUse _gdk_device_get_axis_use (GdkDevice *device,
+ guint index);
+
+gboolean _gdk_device_translate_window_coord (GdkDevice *device,
+ GdkWindow *window,
+ guint index,
+ gdouble value,
+ gdouble *axis_value);
+
+gboolean _gdk_device_translate_screen_coord (GdkDevice *device,
+ GdkWindow *window,
+ gint window_root_x,
+ gint window_root_y,
+ guint index,
+ gdouble value,
+ gdouble *axis_value);
+
+gboolean _gdk_device_translate_axis (GdkDevice *device,
+ guint index,
+ gdouble value,
+ gdouble *axis_value);
+
+GdkTimeCoord ** _gdk_device_allocate_history (GdkDevice *device,
+ guint n_events);
+
+void _gdk_input_check_extension_events (GdkDevice *device);
+
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_PRIVATE_H__ */
diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c
index ac49a5bf49..d64329458f 100644
--- a/gdk/gdkdisplay.c
+++ b/gdk/gdkdisplay.c
@@ -33,12 +33,44 @@
#include "gdkalias.h"
enum {
+ OPENED,
CLOSED,
LAST_SIGNAL
};
-static void gdk_display_dispose (GObject *object);
-static void gdk_display_finalize (GObject *object);
+static void gdk_display_dispose (GObject *object);
+static void gdk_display_finalize (GObject *object);
+
+static void multihead_get_device_state (GdkDisplay *display,
+ GdkDevice *device,
+ GdkScreen **screen,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask);
+static GdkWindow * multihead_window_get_device_position (GdkDisplay *display,
+ GdkDevice *device,
+ GdkWindow *window,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask);
+static GdkWindow * multihead_window_at_device_position (GdkDisplay *display,
+ GdkDevice *device,
+ gint *win_x,
+ gint *win_y);
+
+static void multihead_default_get_pointer (GdkDisplay *display,
+ GdkScreen **screen,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask);
+static GdkWindow * multihead_default_window_get_pointer (GdkDisplay *display,
+ GdkWindow *window,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask);
+static GdkWindow * multihead_default_window_at_pointer (GdkDisplay *display,
+ gint *win_x,
+ gint *win_y);
static void singlehead_get_pointer (GdkDisplay *display,
@@ -62,23 +94,37 @@ static GdkWindow* singlehead_default_window_get_pointer (GdkWindow *window
static GdkWindow* singlehead_default_window_at_pointer (GdkScreen *screen,
gint *win_x,
gint *win_y);
-static GdkWindow *gdk_window_real_window_get_pointer (GdkDisplay *display,
- GdkWindow *window,
- gint *x,
- gint *y,
- GdkModifierType *mask);
-static GdkWindow *gdk_display_real_get_window_at_pointer (GdkDisplay *display,
- gint *win_x,
- gint *win_y);
+static GdkWindow *gdk_window_real_window_get_device_position (GdkDisplay *display,
+ GdkDevice *device,
+ GdkWindow *window,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask);
+static GdkWindow *gdk_display_real_get_window_at_device_position (GdkDisplay *display,
+ GdkDevice *device,
+ gint *win_x,
+ gint *win_y);
static guint signals[LAST_SIGNAL] = { 0 };
static char *gdk_sm_client_id;
-static const GdkDisplayPointerHooks default_pointer_hooks = {
- _gdk_windowing_get_pointer,
- gdk_window_real_window_get_pointer,
- gdk_display_real_get_window_at_pointer
+static const GdkDisplayDeviceHooks default_device_hooks = {
+ _gdk_windowing_get_device_state,
+ gdk_window_real_window_get_device_position,
+ gdk_display_real_get_window_at_device_position
+};
+
+static const GdkDisplayDeviceHooks multihead_pointer_hooks = {
+ multihead_get_device_state,
+ multihead_window_get_device_position,
+ multihead_window_at_device_position
+};
+
+static const GdkDisplayPointerHooks multihead_default_pointer_hooks = {
+ multihead_default_get_pointer,
+ multihead_default_window_get_pointer,
+ multihead_default_window_at_pointer
};
static const GdkDisplayPointerHooks singlehead_pointer_hooks = {
@@ -93,6 +139,7 @@ static const GdkPointerHooks singlehead_default_pointer_hooks = {
};
static const GdkPointerHooks *singlehead_current_pointer_hooks = &singlehead_default_pointer_hooks;
+static const GdkDisplayPointerHooks *multihead_current_pointer_hooks = &multihead_default_pointer_hooks;
G_DEFINE_TYPE (GdkDisplay, gdk_display, G_TYPE_OBJECT)
@@ -100,11 +147,24 @@ static void
gdk_display_class_init (GdkDisplayClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
-
+
object_class->finalize = gdk_display_finalize;
object_class->dispose = gdk_display_dispose;
/**
+ * GdkDisplay::opened.
+ * @display: the object on which the signal is emitted
+ *
+ */
+ signals[OPENED] =
+ g_signal_new (g_intern_static_string ("opened"),
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ /**
* GdkDisplay::closed:
* @display: the object on which the signal is emitted
* @is_error: %TRUE if the display was closed due to an error
@@ -127,26 +187,87 @@ gdk_display_class_init (GdkDisplayClass *class)
}
static void
+free_pointer_info (GdkPointerWindowInfo *info)
+{
+ g_object_unref (info->toplevel_under_pointer);
+ g_slice_free (GdkPointerWindowInfo, info);
+}
+
+static void
+free_device_grab (GdkDeviceGrabInfo *info)
+{
+ g_object_unref (info->window);
+ g_object_unref (info->native_window);
+ g_free (info);
+}
+
+static gboolean
+free_device_grabs_foreach (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ GList *list = value;
+
+ g_list_foreach (list, (GFunc) free_device_grab, NULL);
+ g_list_free (list);
+
+ return TRUE;
+}
+
+static void
+device_removed_cb (GdkDeviceManager *device_manager,
+ GdkDevice *device,
+ GdkDisplay *display)
+{
+ g_hash_table_remove (display->multiple_click_info, device);
+ g_hash_table_remove (display->device_grabs, device);
+ g_hash_table_remove (display->pointers_info, device);
+
+ /* FIXME: change core pointer and remove from device list */
+}
+
+static void
+gdk_display_opened (GdkDisplay *display)
+{
+ GdkDeviceManager *device_manager;
+
+ device_manager = gdk_display_get_device_manager (display);
+
+ g_signal_connect (device_manager, "device-removed",
+ G_CALLBACK (device_removed_cb), display);
+}
+
+static void
gdk_display_init (GdkDisplay *display)
{
_gdk_displays = g_slist_prepend (_gdk_displays, display);
- display->button_click_time[0] = display->button_click_time[1] = 0;
- display->button_window[0] = display->button_window[1] = NULL;
- display->button_number[0] = display->button_number[1] = -1;
- display->button_x[0] = display->button_x[1] = 0;
- display->button_y[0] = display->button_y[1] = 0;
-
display->double_click_time = 250;
display->double_click_distance = 5;
- display->pointer_hooks = &default_pointer_hooks;
+ display->device_hooks = &default_device_hooks;
+
+ display->device_grabs = g_hash_table_new (NULL, NULL);
+ display->motion_hint_info = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) g_free);
+
+ display->pointers_info = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) free_pointer_info);
+
+ display->multiple_click_info = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) g_free);
+
+ g_signal_connect (display, "opened",
+ G_CALLBACK (gdk_display_opened), NULL);
}
static void
gdk_display_dispose (GObject *object)
{
GdkDisplay *display = GDK_DISPLAY_OBJECT (object);
+ GdkDeviceManager *device_manager;
+
+ device_manager = gdk_display_get_device_manager (GDK_DISPLAY_OBJECT (object));
g_list_foreach (display->queued_events, (GFunc)gdk_event_free, NULL);
g_list_free (display->queued_events);
@@ -165,12 +286,28 @@ gdk_display_dispose (GObject *object)
NULL);
}
+ if (device_manager)
+ g_signal_handlers_disconnect_by_func (device_manager, device_removed_cb, object);
+
G_OBJECT_CLASS (gdk_display_parent_class)->dispose (object);
}
static void
gdk_display_finalize (GObject *object)
{
+ GdkDisplay *display = GDK_DISPLAY_OBJECT (object);
+
+ g_hash_table_foreach_remove (display->device_grabs,
+ free_device_grabs_foreach,
+ NULL);
+ g_hash_table_destroy (display->device_grabs);
+
+ g_hash_table_destroy (display->pointers_info);
+ g_hash_table_destroy (display->multiple_click_info);
+
+ if (display->device_manager)
+ g_object_unref (display->device_manager);
+
G_OBJECT_CLASS (gdk_display_parent_class)->finalize (object);
}
@@ -273,12 +410,55 @@ gdk_display_put_event (GdkDisplay *display,
}
/**
+ * gdk_display_pointer_ungrab:
+ * @display: a #GdkDisplay.
+ * @time_: a timestap (e.g. %GDK_CURRENT_TIME).
+ *
+ * Release any pointer grab.
+ *
+ * Since: 2.2
+ *
+ * Deprecated: 3.0. Use gdk_device_ungrab(), together with gdk_device_grab()
+ * instead.
+ */
+void
+gdk_display_pointer_ungrab (GdkDisplay *display,
+ guint32 time_)
+{
+ GdkDeviceManager *device_manager;
+ GList *devices, *dev;
+ GdkDevice *device;
+
+ g_return_if_fail (GDK_IS_DISPLAY (display));
+
+ device_manager = gdk_display_get_device_manager (display);
+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+
+ /* FIXME: Should this be generic to all backends? */
+ /* FIXME: What happens with extended devices? */
+ for (dev = devices; dev; dev = dev->next)
+ {
+ device = dev->data;
+
+ if (device->source != GDK_SOURCE_MOUSE)
+ continue;
+
+ gdk_device_ungrab (device, time_);
+ }
+
+ g_list_free (devices);
+}
+
+/**
* gdk_pointer_ungrab:
* @time_: a timestamp from a #GdkEvent, or %GDK_CURRENT_TIME if no
* timestamp is available.
*
* Ungrabs the pointer on the default display, if it is grabbed by this
* application.
+ *
+ * Deprecated: 3.0. Use gdk_device_ungrab(), together with gdk_device_grab()
+ * instead.
**/
void
gdk_pointer_ungrab (guint32 time)
@@ -294,8 +474,10 @@ gdk_pointer_ungrab (guint32 time)
*
* Note that this does not take the inmplicit pointer grab on button
* presses into account.
-
- * Return value: %TRUE if the pointer is currently grabbed by this application.*
+ *
+ * Return value: %TRUE if the pointer is currently grabbed by this application.
+ *
+ * Deprecated: 3.0. Use gdk_display_device_is_grabbed() instead.
**/
gboolean
gdk_pointer_is_grabbed (void)
@@ -304,12 +486,55 @@ gdk_pointer_is_grabbed (void)
}
/**
+ * gdk_display_keyboard_ungrab:
+ * @display: a #GdkDisplay.
+ * @time_: a timestap (e.g #GDK_CURRENT_TIME).
+ *
+ * Release any keyboard grab
+ *
+ * Since: 2.2
+ *
+ * Deprecated: 3.0. Use gdk_device_ungrab(), together with gdk_device_grab()
+ * instead.
+ */
+void
+gdk_display_keyboard_ungrab (GdkDisplay *display,
+ guint32 time)
+{
+ GdkDeviceManager *device_manager;
+ GList *devices, *dev;
+ GdkDevice *device;
+
+ g_return_if_fail (GDK_IS_DISPLAY (display));
+
+ device_manager = gdk_display_get_device_manager (display);
+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+
+ /* FIXME: Should this be generic to all backends? */
+ /* FIXME: What happens with extended devices? */
+ for (dev = devices; dev; dev = dev->next)
+ {
+ device = dev->data;
+
+ if (device->source != GDK_SOURCE_KEYBOARD)
+ continue;
+
+ gdk_device_ungrab (device, time);
+ }
+
+ g_list_free (devices);
+}
+
+/**
* gdk_keyboard_ungrab:
* @time_: a timestamp from a #GdkEvent, or %GDK_CURRENT_TIME if no
* timestamp is available.
*
* Ungrabs the keyboard on the default display, if it is grabbed by this
* application.
+ *
+ * Deprecated: 3.0. Use gdk_device_ungrab(), together with gdk_device_grab()
+ * instead.
**/
void
gdk_keyboard_ungrab (guint32 time)
@@ -377,6 +602,10 @@ gdk_event_send_clientmessage_toall (GdkEvent *event)
*
* Return value: the core pointer device; this is owned by the
* display and should not be freed.
+ *
+ * Deprecated: 3.0. Use gdk_display_get_device_manager() instead, or
+ * gdk_event_get_device() if a #GdkEvent with pointer device
+ * information is available.
**/
GdkDevice *
gdk_device_get_core_pointer (void)
@@ -394,6 +623,10 @@ gdk_device_get_core_pointer (void)
* display and should not be freed.
*
* Since: 2.2
+ *
+ * Deprecated: 3.0. Use gdk_display_get_device_manager() instead, or
+ * gdk_event_get_device() if a #GdkEvent with device
+ * information is available.
**/
GdkDevice *
gdk_display_get_core_pointer (GdkDisplay *display)
@@ -445,11 +678,21 @@ _gdk_get_sm_client_id (void)
}
void
-_gdk_display_enable_motion_hints (GdkDisplay *display)
+_gdk_display_enable_motion_hints (GdkDisplay *display,
+ GdkDevice *device)
{
- gulong serial;
-
- if (display->pointer_info.motion_hint_serial != 0)
+ gulong *device_serial, serial;
+
+ device_serial = g_hash_table_lookup (display->motion_hint_info, device);
+
+ if (!device_serial)
+ {
+ device_serial = g_new0 (gulong, 1);
+ *device_serial = G_MAXULONG;
+ g_hash_table_insert (display->motion_hint_info, device, device_serial);
+ }
+
+ if (*device_serial != 0)
{
serial = _gdk_windowing_window_get_next_serial (display);
/* We might not actually generate the next request, so
@@ -458,12 +701,119 @@ _gdk_display_enable_motion_hints (GdkDisplay *display)
anyway. */
if (serial > 0)
serial--;
- if (serial < display->pointer_info.motion_hint_serial)
- display->pointer_info.motion_hint_serial = serial;
+ if (serial < *device_serial)
+ *device_serial = serial;
}
}
/**
+ * gdk_display_get_device_state:
+ * @display: a #GdkDisplay.
+ * @device: device to query status to.
+ * @screen: location to store the #GdkScreen the @device is on, or %NULL.
+ * @x: location to store root window X coordinate of @device, or %NULL.
+ * @y: location to store root window Y coordinate of @device, or %NULL.
+ * @mask: location to store current modifier mask for @device, or %NULL.
+ *
+ * Gets the current location and state of @device for a given display.
+ *
+ * Since: 3.0
+ **/
+void
+gdk_display_get_device_state (GdkDisplay *display,
+ GdkDevice *device,
+ GdkScreen **screen,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
+{
+ GdkScreen *tmp_screen;
+ gint tmp_x, tmp_y;
+ GdkModifierType tmp_mask;
+
+ g_return_if_fail (GDK_IS_DISPLAY (display));
+ g_return_if_fail (GDK_IS_DEVICE (device));
+
+ display->device_hooks->get_device_state (display, device, &tmp_screen, &tmp_x, &tmp_y, &tmp_mask);
+
+ if (screen)
+ *screen = tmp_screen;
+ if (x)
+ *x = tmp_x;
+ if (y)
+ *y = tmp_y;
+ if (mask)
+ *mask = tmp_mask;
+}
+
+/**
+ * gdk_display_get_window_at_device_position:
+ * @display: a #GdkDisplay.
+ * @device: #GdkDevice to query info to.
+ * @win_x: return location for the X coordinate of the device location, relative to the window origin, or %NULL.
+ * @win_y: return location for the Y coordinate of the device location, relative to the window origin, or %NULL.
+ *
+ * Obtains the window underneath @device, returning the location of the device in @win_x and @win_y. Returns
+ * %NULL if the window tree under @device is not known to GDK (for example, belongs to another application).
+ *
+ * Returns: the #GdkWindow under the device position, or %NULL.
+ *
+ * Since: 3.0
+ **/
+GdkWindow *
+gdk_display_get_window_at_device_position (GdkDisplay *display,
+ GdkDevice *device,
+ gint *win_x,
+ gint *win_y)
+{
+ gint tmp_x, tmp_y;
+ GdkWindow *window;
+
+ g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+ g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
+
+ window = display->device_hooks->window_at_device_position (display, device, &tmp_x, &tmp_y);
+
+ if (win_x)
+ *win_x = tmp_x;
+ if (win_y)
+ *win_y = tmp_y;
+
+ return window;
+}
+
+/**
+ * gdk_display_set_device_hooks:
+ * @display: a #GdkDisplay.
+ * @new_hooks: a table of pointers to functions for getting quantities related to all
+ * devices position, or %NULL to restore the default table.
+ *
+ * This function allows for hooking into the operation of getting the current location of any
+ * #GdkDevice on a particular #GdkDisplay. This is only useful for such low-level tools as
+ * an event recorder. Applications should never have any reason to use this facility.
+ *
+ * Returns: The previous device hook table.
+ *
+ * Since: 3.0
+ **/
+GdkDisplayDeviceHooks *
+gdk_display_set_device_hooks (GdkDisplay *display,
+ const GdkDisplayDeviceHooks *new_hooks)
+{
+ const GdkDisplayDeviceHooks *result;
+
+ g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+ result = display->device_hooks;
+
+ if (new_hooks)
+ display->device_hooks = new_hooks;
+ else
+ display->device_hooks = &default_device_hooks;
+
+ return (GdkDisplayDeviceHooks *) result;
+}
+
+/**
* gdk_display_get_pointer:
* @display: a #GdkDisplay
* @screen: (allow-none): location to store the screen that the
@@ -476,6 +826,8 @@ _gdk_display_enable_motion_hints (GdkDisplay *display)
* mask for a given display.
*
* Since: 2.2
+ *
+ * Deprecated: 3.0. Use gdk_display_get_device_state() instead.
**/
void
gdk_display_get_pointer (GdkDisplay *display,
@@ -484,33 +836,21 @@ gdk_display_get_pointer (GdkDisplay *display,
gint *y,
GdkModifierType *mask)
{
- GdkScreen *tmp_screen;
- gint tmp_x, tmp_y;
- GdkModifierType tmp_mask;
-
g_return_if_fail (GDK_IS_DISPLAY (display));
- display->pointer_hooks->get_pointer (display, &tmp_screen, &tmp_x, &tmp_y, &tmp_mask);
-
- if (screen)
- *screen = tmp_screen;
- if (x)
- *x = tmp_x;
- if (y)
- *y = tmp_y;
- if (mask)
- *mask = tmp_mask;
+ gdk_display_get_device_state (display, display->core_pointer, screen, x, y, mask);
}
static GdkWindow *
-gdk_display_real_get_window_at_pointer (GdkDisplay *display,
- gint *win_x,
- gint *win_y)
+gdk_display_real_get_window_at_device_position (GdkDisplay *display,
+ GdkDevice *device,
+ gint *win_x,
+ gint *win_y)
{
GdkWindow *window;
gint x, y;
- window = _gdk_windowing_window_at_pointer (display, &x, &y, NULL, FALSE);
+ window = _gdk_windowing_window_at_device_position (display, device, &x, &y, NULL, FALSE);
/* This might need corrections, as the native window returned
may contain client side children */
@@ -532,11 +872,12 @@ gdk_display_real_get_window_at_pointer (GdkDisplay *display,
}
static GdkWindow *
-gdk_window_real_window_get_pointer (GdkDisplay *display,
- GdkWindow *window,
- gint *x,
- gint *y,
- GdkModifierType *mask)
+gdk_window_real_window_get_device_position (GdkDisplay *display,
+ GdkDevice *device,
+ GdkWindow *window,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
{
GdkWindowObject *private;
gint tmpx, tmpy;
@@ -545,9 +886,10 @@ gdk_window_real_window_get_pointer (GdkDisplay *display,
private = (GdkWindowObject *) window;
- normal_child = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_pointer (window,
- &tmpx, &tmpy,
- &tmp_mask);
+ normal_child = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_device_state (window,
+ device,
+ &tmpx, &tmpy,
+ &tmp_mask);
/* We got the coords on the impl, convert to the window */
tmpx -= private->abs_x;
tmpy -= private->abs_y;
@@ -580,25 +922,82 @@ gdk_window_real_window_get_pointer (GdkDisplay *display,
* Returns: (transfer none): the window under the mouse pointer, or %NULL
*
* Since: 2.2
+ *
+ * Deprecated: 3.0. Use gdk_display_get_window_at_device_position() instead.
**/
GdkWindow *
gdk_display_get_window_at_pointer (GdkDisplay *display,
gint *win_x,
gint *win_y)
{
- gint tmp_x, tmp_y;
- GdkWindow *window;
-
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
- window = display->pointer_hooks->window_at_pointer (display, &tmp_x, &tmp_y);
+ return gdk_display_get_window_at_device_position (display, display->core_pointer, win_x, win_y);
+}
- if (win_x)
- *win_x = tmp_x;
- if (win_y)
- *win_y = tmp_y;
+static void
+multihead_get_device_state (GdkDisplay *display,
+ GdkDevice *device,
+ GdkScreen **screen,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
+{
+ multihead_current_pointer_hooks->get_pointer (display, screen, x, y, mask);
+}
- return window;
+static GdkWindow *
+multihead_window_get_device_position (GdkDisplay *display,
+ GdkDevice *device,
+ GdkWindow *window,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
+{
+ return multihead_current_pointer_hooks->window_get_pointer (display, window, x, y, mask);
+}
+
+static GdkWindow *
+multihead_window_at_device_position (GdkDisplay *display,
+ GdkDevice *device,
+ gint *win_x,
+ gint *win_y)
+{
+ return multihead_current_pointer_hooks->window_at_pointer (display, win_x, win_y);
+}
+
+static void
+multihead_default_get_pointer (GdkDisplay *display,
+ GdkScreen **screen,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
+{
+ return _gdk_windowing_get_device_state (display,
+ display->core_pointer,
+ screen, x, y, mask);
+}
+
+static GdkWindow *
+multihead_default_window_get_pointer (GdkDisplay *display,
+ GdkWindow *window,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
+{
+ return gdk_window_real_window_get_device_position (display,
+ display->core_pointer,
+ window, x, y, mask);
+}
+
+static GdkWindow *
+multihead_default_window_at_pointer (GdkDisplay *display,
+ gint *win_x,
+ gint *win_y)
+{
+ return gdk_display_real_get_window_at_device_position (display,
+ display->core_pointer,
+ win_x, win_y);
}
/**
@@ -617,20 +1016,23 @@ gdk_display_get_window_at_pointer (GdkDisplay *display,
* Return value: the previous pointer hook table
*
* Since: 2.2
+ *
+ * Deprecated: 3.0. Use gdk_display_set_device_hooks() instead.
**/
GdkDisplayPointerHooks *
gdk_display_set_pointer_hooks (GdkDisplay *display,
const GdkDisplayPointerHooks *new_hooks)
{
- const GdkDisplayPointerHooks *result;
+ const GdkDisplayPointerHooks *result = multihead_current_pointer_hooks;
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
- result = display->pointer_hooks;
if (new_hooks)
- display->pointer_hooks = new_hooks;
+ multihead_current_pointer_hooks = new_hooks;
else
- display->pointer_hooks = &default_pointer_hooks;
+ multihead_current_pointer_hooks = &multihead_default_pointer_hooks;
+
+ gdk_display_set_device_hooks (display, &multihead_pointer_hooks);
return (GdkDisplayPointerHooks *)result;
}
@@ -677,8 +1079,13 @@ singlehead_default_window_get_pointer (GdkWindow *window,
gint *y,
GdkModifierType *mask)
{
- return gdk_window_real_window_get_pointer (gdk_drawable_get_display (window),
- window, x, y, mask);
+ GdkDisplay *display;
+
+ display = gdk_drawable_get_display (window);
+
+ return gdk_window_real_window_get_device_position (display,
+ display->core_pointer,
+ window, x, y, mask);
}
static GdkWindow*
@@ -686,8 +1093,13 @@ singlehead_default_window_at_pointer (GdkScreen *screen,
gint *win_x,
gint *win_y)
{
- return gdk_display_real_get_window_at_pointer (gdk_screen_get_display (screen),
- win_x, win_y);
+ GdkDisplay *display;
+
+ display = gdk_screen_get_display (screen);
+
+ return gdk_display_real_get_window_at_device_position (display,
+ display->core_pointer,
+ win_x, win_y);
}
/**
@@ -706,6 +1118,8 @@ singlehead_default_window_at_pointer (GdkScreen *screen,
* see gdk_display_set_pointer_hooks().
*
* Return value: the previous pointer hook table
+ *
+ * Deprecated: 3.0. Use gdk_display_set_device_hooks() instead.
**/
GdkPointerHooks *
gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks)
@@ -725,7 +1139,7 @@ gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks)
static void
generate_grab_broken_event (GdkWindow *window,
- gboolean keyboard,
+ GdkDevice *device,
gboolean implicit,
GdkWindow *grab_window)
{
@@ -733,45 +1147,54 @@ generate_grab_broken_event (GdkWindow *window,
if (!GDK_WINDOW_DESTROYED (window))
{
- GdkEvent event;
- event.type = GDK_GRAB_BROKEN;
- event.grab_broken.window = window;
- event.grab_broken.send_event = 0;
- event.grab_broken.keyboard = keyboard;
- event.grab_broken.implicit = implicit;
- event.grab_broken.grab_window = grab_window;
- gdk_event_put (&event);
+ GdkEvent *event;
+
+ event = gdk_event_new (GDK_GRAB_BROKEN);
+ event->grab_broken.window = g_object_ref (window);
+ event->grab_broken.send_event = FALSE;
+ event->grab_broken.implicit = implicit;
+ event->grab_broken.grab_window = grab_window;
+ gdk_event_set_device (event, device);
+ event->grab_broken.keyboard = (device->source == GDK_SOURCE_KEYBOARD) ? TRUE : FALSE;
+
+ gdk_event_put (event);
+ gdk_event_free (event);
}
}
-GdkPointerGrabInfo *
-_gdk_display_get_last_pointer_grab (GdkDisplay *display)
+GdkDeviceGrabInfo *
+_gdk_display_get_last_device_grab (GdkDisplay *display,
+ GdkDevice *device)
{
GList *l;
- l = g_list_last (display->pointer_grabs);
+ l = g_hash_table_lookup (display->device_grabs, device);
- if (l == NULL)
- return NULL;
- else
- return (GdkPointerGrabInfo *)l->data;
-}
+ if (l)
+ {
+ l = g_list_last (l);
+ return l->data;
+ }
+ return NULL;
+}
-GdkPointerGrabInfo *
-_gdk_display_add_pointer_grab (GdkDisplay *display,
- GdkWindow *window,
- GdkWindow *native_window,
- gboolean owner_events,
- GdkEventMask event_mask,
- unsigned long serial_start,
- guint32 time,
- gboolean implicit)
+GdkDeviceGrabInfo *
+_gdk_display_add_device_grab (GdkDisplay *display,
+ GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow *native_window,
+ GdkGrabOwnership grab_ownership,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ unsigned long serial_start,
+ guint32 time,
+ gboolean implicit)
{
- GdkPointerGrabInfo *info, *other_info;
- GList *l;
+ GdkDeviceGrabInfo *info, *other_info;
+ GList *grabs, *l;
- info = g_new0 (GdkPointerGrabInfo, 1);
+ info = g_new0 (GdkDeviceGrabInfo, 1);
info->window = g_object_ref (window);
info->native_window = g_object_ref (native_window);
@@ -781,19 +1204,22 @@ _gdk_display_add_pointer_grab (GdkDisplay *display,
info->event_mask = event_mask;
info->time = time;
info->implicit = implicit;
+ info->ownership = grab_ownership;
+
+ grabs = g_hash_table_lookup (display->device_grabs, device);
/* Find the first grab that has a larger start time (if any) and insert
* before that. I.E we insert after already existing grabs with same
* start time */
- for (l = display->pointer_grabs; l != NULL; l = l->next)
+ for (l = grabs; l != NULL; l = l->next)
{
other_info = l->data;
-
+
if (info->serial_start < other_info->serial_start)
break;
}
- display->pointer_grabs =
- g_list_insert_before (display->pointer_grabs, l, info);
+
+ grabs = g_list_insert_before (grabs, l, info);
/* Make sure the new grab end before next grab */
if (l)
@@ -801,9 +1227,9 @@ _gdk_display_add_pointer_grab (GdkDisplay *display,
other_info = l->data;
info->serial_end = other_info->serial_start;
}
-
+
/* Find any previous grab and update its end time */
- l = g_list_find (display->pointer_grabs, info);
+ l = g_list_find (grabs, info);
l = l->prev;
if (l)
{
@@ -811,27 +1237,22 @@ _gdk_display_add_pointer_grab (GdkDisplay *display,
other_info->serial_end = serial_start;
}
- return info;
-}
+ g_hash_table_insert (display->device_grabs, device, grabs);
-static void
-free_pointer_grab (GdkPointerGrabInfo *info)
-{
- g_object_unref (info->window);
- g_object_unref (info->native_window);
- g_free (info);
+ return info;
}
/* _gdk_synthesize_crossing_events only works inside one toplevel.
This function splits things into two calls if needed, converting the
coordinates to the right toplevel */
static void
-synthesize_crossing_events (GdkDisplay *display,
- GdkWindow *src_window,
- GdkWindow *dest_window,
- GdkCrossingMode crossing_mode,
- guint32 time,
- gulong serial)
+synthesize_crossing_events (GdkDisplay *display,
+ GdkDevice *device,
+ GdkWindow *src_window,
+ GdkWindow *dest_window,
+ GdkCrossingMode crossing_mode,
+ guint32 time,
+ gulong serial)
{
GdkWindow *src_toplevel, *dest_toplevel;
GdkModifierType state;
@@ -862,6 +1283,7 @@ synthesize_crossing_events (GdkDisplay *display,
_gdk_synthesize_crossing_events (display,
src_window,
dest_window,
+ device,
crossing_mode,
x, y, state,
time,
@@ -873,13 +1295,14 @@ synthesize_crossing_events (GdkDisplay *display,
gdk_window_get_pointer (src_toplevel,
&x, &y, &state);
_gdk_synthesize_crossing_events (display,
- src_window,
- NULL,
- crossing_mode,
- x, y, state,
- time,
- NULL,
- serial, FALSE);
+ src_window,
+ NULL,
+ device,
+ crossing_mode,
+ x, y, state,
+ time,
+ NULL,
+ serial, FALSE);
}
else
{
@@ -889,6 +1312,7 @@ synthesize_crossing_events (GdkDisplay *display,
_gdk_synthesize_crossing_events (display,
src_window,
NULL,
+ device,
crossing_mode,
x, y, state,
time,
@@ -899,6 +1323,7 @@ synthesize_crossing_events (GdkDisplay *display,
_gdk_synthesize_crossing_events (display,
NULL,
dest_window,
+ device,
crossing_mode,
x, y, state,
time,
@@ -908,15 +1333,18 @@ synthesize_crossing_events (GdkDisplay *display,
}
static GdkWindow *
-get_current_toplevel (GdkDisplay *display,
- int *x_out, int *y_out,
+get_current_toplevel (GdkDisplay *display,
+ GdkDevice *device,
+ int *x_out,
+ int *y_out,
GdkModifierType *state_out)
{
GdkWindow *pointer_window;
int x, y;
GdkModifierType state;
- pointer_window = _gdk_windowing_window_at_pointer (display, &x, &y, &state, TRUE);
+ pointer_window = _gdk_windowing_window_at_device_position (display, device, &x, &y, &state, TRUE);
+
if (pointer_window != NULL &&
(GDK_WINDOW_DESTROYED (pointer_window) ||
GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT ||
@@ -930,29 +1358,32 @@ get_current_toplevel (GdkDisplay *display,
}
static void
-switch_to_pointer_grab (GdkDisplay *display,
- GdkPointerGrabInfo *grab,
- GdkPointerGrabInfo *last_grab,
- guint32 time,
- gulong serial)
+switch_to_pointer_grab (GdkDisplay *display,
+ GdkDevice *device,
+ GdkDeviceGrabInfo *grab,
+ GdkDeviceGrabInfo *last_grab,
+ guint32 time,
+ gulong serial)
{
GdkWindow *src_window, *pointer_window, *new_toplevel;
+ GdkPointerWindowInfo *info;
GList *old_grabs;
GdkModifierType state;
int x, y;
/* Temporarily unset pointer to make sure we send the crossing events below */
- old_grabs = display->pointer_grabs;
- display->pointer_grabs = NULL;
-
+ old_grabs = g_hash_table_lookup (display->device_grabs, device);
+ g_hash_table_steal (display->device_grabs, device);
+ info = _gdk_display_get_pointer_info (display, device);
+
if (grab)
{
/* New grab is in effect */
-
+
/* We need to generate crossing events for the grab.
* However, there are never any crossing events for implicit grabs
* TODO: ... Actually, this could happen if the pointer window
- * doesn't have button mask so a parent gets the event...
+ * doesn't have button mask so a parent gets the event...
*/
if (!grab->implicit)
{
@@ -961,19 +1392,17 @@ switch_to_pointer_grab (GdkDisplay *display,
if (last_grab)
src_window = last_grab->window;
else
- src_window = display->pointer_info.window_under_pointer;
-
+ src_window = info->window_under_pointer;
+
if (src_window != grab->window)
- {
- synthesize_crossing_events (display,
- src_window, grab->window,
- GDK_CROSSING_GRAB, time, serial);
- }
+ synthesize_crossing_events (display, device,
+ src_window, grab->window,
+ GDK_CROSSING_GRAB, time, serial);
/* !owner_event Grabbing a window that we're not inside, current status is
now NULL (i.e. outside grabbed window) */
- if (!grab->owner_events && display->pointer_info.window_under_pointer != grab->window)
- _gdk_display_set_window_under_pointer (display, NULL);
+ if (!grab->owner_events && info->window_under_pointer != grab->window)
+ _gdk_display_set_window_under_pointer (display, device, NULL);
}
grab->activated = TRUE;
@@ -989,18 +1418,18 @@ switch_to_pointer_grab (GdkDisplay *display,
/* We force check what window we're in, and update the toplevel_under_pointer info,
* as that won't get told of this change with toplevel enter events.
*/
- if (display->pointer_info.toplevel_under_pointer)
- g_object_unref (display->pointer_info.toplevel_under_pointer);
- display->pointer_info.toplevel_under_pointer = NULL;
+ if (info->toplevel_under_pointer)
+ g_object_unref (info->toplevel_under_pointer);
+ info->toplevel_under_pointer = NULL;
- new_toplevel = get_current_toplevel (display, &x, &y, &state);
+ new_toplevel = get_current_toplevel (display, device, &x, &y, &state);
if (new_toplevel)
{
/* w is now toplevel and x,y in toplevel coords */
- display->pointer_info.toplevel_under_pointer = g_object_ref (new_toplevel);
- display->pointer_info.toplevel_x = x;
- display->pointer_info.toplevel_y = y;
- display->pointer_info.state = state;
+ info->toplevel_under_pointer = g_object_ref (new_toplevel);
+ info->toplevel_x = x;
+ info->toplevel_y = y;
+ info->state = state;
}
}
@@ -1015,55 +1444,59 @@ switch_to_pointer_grab (GdkDisplay *display,
x, y,
NULL, NULL);
}
-
+
if (pointer_window != last_grab->window)
- synthesize_crossing_events (display,
- last_grab->window, pointer_window,
- GDK_CROSSING_UNGRAB, time, serial);
-
+ synthesize_crossing_events (display, device,
+ last_grab->window, pointer_window,
+ GDK_CROSSING_UNGRAB, time, serial);
+
/* We're now ungrabbed, update the window_under_pointer */
- _gdk_display_set_window_under_pointer (display, pointer_window);
+ _gdk_display_set_window_under_pointer (display, device, pointer_window);
}
}
-
- display->pointer_grabs = old_grabs;
+ g_hash_table_insert (display->device_grabs, device, old_grabs);
}
void
-_gdk_display_pointer_grab_update (GdkDisplay *display,
- gulong current_serial)
+_gdk_display_device_grab_update (GdkDisplay *display,
+ GdkDevice *device,
+ gulong current_serial)
{
- GdkPointerGrabInfo *current_grab, *next_grab;
+ GdkDeviceGrabInfo *current_grab, *next_grab;
+ GList *grabs;
guint32 time;
-
+
time = display->last_event_time;
+ grabs = g_hash_table_lookup (display->device_grabs, device);
- while (display->pointer_grabs != NULL)
+ while (grabs != NULL)
{
- current_grab = display->pointer_grabs->data;
+ current_grab = grabs->data;
if (current_grab->serial_start > current_serial)
return; /* Hasn't started yet */
-
+
if (current_grab->serial_end > current_serial)
{
/* This one hasn't ended yet.
its the currently active one or scheduled to be active */
if (!current_grab->activated)
- switch_to_pointer_grab (display, current_grab, NULL, time, current_serial);
-
+ {
+ if (device->source != GDK_SOURCE_KEYBOARD)
+ switch_to_pointer_grab (display, device, current_grab, NULL, time, current_serial);
+ }
+
break;
}
-
next_grab = NULL;
- if (display->pointer_grabs->next)
+ if (grabs->next)
{
/* This is the next active grab */
- next_grab = display->pointer_grabs->next->data;
-
+ next_grab = grabs->next->data;
+
if (next_grab->serial_start > current_serial)
next_grab = NULL; /* Actually its not yet active */
}
@@ -1071,52 +1504,64 @@ _gdk_display_pointer_grab_update (GdkDisplay *display,
if ((next_grab == NULL && current_grab->implicit_ungrab) ||
(next_grab != NULL && current_grab->window != next_grab->window))
generate_grab_broken_event (GDK_WINDOW (current_grab->window),
- FALSE, current_grab->implicit,
+ device,
+ current_grab->implicit,
next_grab? next_grab->window : NULL);
/* Remove old grab */
- display->pointer_grabs =
- g_list_delete_link (display->pointer_grabs,
- display->pointer_grabs);
-
- switch_to_pointer_grab (display,
- next_grab, current_grab,
- time, current_serial);
-
- free_pointer_grab (current_grab);
+ grabs = g_list_delete_link (grabs, grabs);
+ g_hash_table_insert (display->device_grabs, device, grabs);
+
+ if (device->source != GDK_SOURCE_KEYBOARD)
+ switch_to_pointer_grab (display, device,
+ next_grab, current_grab,
+ time, current_serial);
+
+ free_device_grab (current_grab);
}
}
static GList *
-find_pointer_grab (GdkDisplay *display,
- gulong serial)
+grab_list_find (GList *grabs,
+ gulong serial)
{
- GdkPointerGrabInfo *grab;
- GList *l;
+ GdkDeviceGrabInfo *grab;
- for (l = display->pointer_grabs; l != NULL; l = l->next)
+ while (grabs)
{
- grab = l->data;
+ grab = grabs->data;
if (serial >= grab->serial_start && serial < grab->serial_end)
- return l;
+ return grabs;
+
+ grabs = grabs->next;
}
-
+
return NULL;
}
+static GList *
+find_device_grab (GdkDisplay *display,
+ GdkDevice *device,
+ gulong serial)
+{
+ GList *l;
+ l = g_hash_table_lookup (display->device_grabs, device);
+ return grab_list_find (l, serial);
+}
-GdkPointerGrabInfo *
-_gdk_display_has_pointer_grab (GdkDisplay *display,
- gulong serial)
+GdkDeviceGrabInfo *
+_gdk_display_has_device_grab (GdkDisplay *display,
+ GdkDevice *device,
+ gulong serial)
{
GList *l;
- l = find_pointer_grab (display, serial);
+ l = find_device_grab (display, device, serial);
if (l)
return l->data;
-
+
return NULL;
}
@@ -1124,16 +1569,17 @@ _gdk_display_has_pointer_grab (GdkDisplay *display,
* If if_child is non-NULL, end the grab only if the grabbed
* window is the same as if_child or a descendant of it */
gboolean
-_gdk_display_end_pointer_grab (GdkDisplay *display,
- gulong serial,
- GdkWindow *if_child,
- gboolean implicit)
+_gdk_display_end_device_grab (GdkDisplay *display,
+ GdkDevice *device,
+ gulong serial,
+ GdkWindow *if_child,
+ gboolean implicit)
{
- GdkPointerGrabInfo *grab;
+ GdkDeviceGrabInfo *grab;
GList *l;
- l = find_pointer_grab (display, serial);
-
+ l = find_device_grab (display, device, serial);
+
if (l == NULL)
return FALSE;
@@ -1150,96 +1596,128 @@ _gdk_display_end_pointer_grab (GdkDisplay *display,
return FALSE;
}
-void
-_gdk_display_set_has_keyboard_grab (GdkDisplay *display,
- GdkWindow *window,
- GdkWindow *native_window,
- gboolean owner_events,
- unsigned long serial,
- guint32 time)
-{
- if (display->keyboard_grab.window != NULL &&
- display->keyboard_grab.window != window)
- generate_grab_broken_event (display->keyboard_grab.window,
- TRUE, FALSE, window);
-
- display->keyboard_grab.window = window;
- display->keyboard_grab.native_window = native_window;
- display->keyboard_grab.owner_events = owner_events;
- display->keyboard_grab.serial = serial;
- display->keyboard_grab.time = time;
+/* Returns TRUE if device events are not blocked by any grab */
+gboolean
+_gdk_display_check_grab_ownership (GdkDisplay *display,
+ GdkDevice *device,
+ gulong serial)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+ GdkGrabOwnership higher_ownership, device_ownership;
+ gboolean device_is_keyboard;
+
+ g_hash_table_iter_init (&iter, display->device_grabs);
+ higher_ownership = device_ownership = GDK_OWNERSHIP_NONE;
+ device_is_keyboard = (device->source == GDK_SOURCE_KEYBOARD);
+
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ GdkDeviceGrabInfo *grab;
+ GdkDevice *dev;
+ GList *grabs;
+
+ dev = key;
+ grabs = value;
+ grabs = grab_list_find (grabs, serial);
+
+ if (!grabs)
+ continue;
+
+ /* Discard device if it's not of the same type */
+ if ((device_is_keyboard && dev->source != GDK_SOURCE_KEYBOARD) ||
+ (!device_is_keyboard && dev->source == GDK_SOURCE_KEYBOARD))
+ continue;
+
+ grab = grabs->data;
+
+ if (dev == device)
+ device_ownership = grab->ownership;
+ else
+ {
+ if (grab->ownership > higher_ownership)
+ higher_ownership = grab->ownership;
+ }
+ }
+
+ if (higher_ownership > device_ownership)
+ {
+ /* There's a higher priority ownership
+ * going on for other device(s)
+ */
+ return FALSE;
+ }
+
+ return TRUE;
}
-void
-_gdk_display_unset_has_keyboard_grab (GdkDisplay *display,
- gboolean implicit)
+GdkPointerWindowInfo *
+_gdk_display_get_pointer_info (GdkDisplay *display,
+ GdkDevice *device)
{
- if (implicit)
- generate_grab_broken_event (display->keyboard_grab.window,
- TRUE, FALSE, NULL);
- display->keyboard_grab.window = NULL;
+ GdkPointerWindowInfo *info;
+
+ if (G_UNLIKELY (!device))
+ return NULL;
+
+ info = g_hash_table_lookup (display->pointers_info, device);
+
+ if (G_UNLIKELY (!info))
+ {
+ info = g_slice_new0 (GdkPointerWindowInfo);
+ g_hash_table_insert (display->pointers_info, device, info);
+ }
+
+ return info;
}
-/**
- * gdk_keyboard_grab_info_libgtk_only:
- * @display: the display for which to get the grab information
- * @grab_window: location to store current grab window
- * @owner_events: location to store boolean indicating whether
- * the @owner_events flag to gdk_keyboard_grab() was %TRUE.
- *
- * Determines information about the current keyboard grab.
- * This is not public API and must not be used by applications.
- *
- * Return value: %TRUE if this application currently has the
- * keyboard grabbed.
- **/
-gboolean
-gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
- GdkWindow **grab_window,
- gboolean *owner_events)
+void
+_gdk_display_pointer_info_foreach (GdkDisplay *display,
+ GdkDisplayPointerInfoForeach func,
+ gpointer user_data)
{
- g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+ GHashTableIter iter;
+ gpointer key, value;
- if (display->keyboard_grab.window)
+ g_hash_table_iter_init (&iter, display->pointers_info);
+
+ while (g_hash_table_iter_next (&iter, &key, &value))
{
- if (grab_window)
- *grab_window = display->keyboard_grab.window;
- if (owner_events)
- *owner_events = display->keyboard_grab.owner_events;
+ GdkPointerWindowInfo *info = value;
+ GdkDevice *device = key;
- return TRUE;
+ (func) (display, device, info, user_data);
}
- else
- return FALSE;
}
/**
- * gdk_pointer_grab_info_libgtk_only:
- * @display: the #GdkDisplay for which to get the grab information
+ * gdk_device_grab_info_libgtk_only:
+ * @display: the display for which to get the grab information
+ * @device: device to get the grab information from
* @grab_window: location to store current grab window
* @owner_events: location to store boolean indicating whether
- * the @owner_events flag to gdk_pointer_grab() was %TRUE.
- *
- * Determines information about the current pointer grab.
+ * the @owner_events flag to gdk_keyboard_grab() or
+ * gdk_pointer_grab() was %TRUE.
+ *
+ * Determines information about the current keyboard grab.
* This is not public API and must not be used by applications.
- *
+ *
* Return value: %TRUE if this application currently has the
- * pointer grabbed.
+ * keyboard grabbed.
**/
gboolean
-gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
- GdkWindow **grab_window,
- gboolean *owner_events)
+gdk_device_grab_info_libgtk_only (GdkDisplay *display,
+ GdkDevice *device,
+ GdkWindow **grab_window,
+ gboolean *owner_events)
{
- GdkPointerGrabInfo *info;
-
+ GdkDeviceGrabInfo *info;
+
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+ g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
+
+ info = _gdk_display_get_last_device_grab (display, device);
- /* What we're interested in is the steady state (ie last grab),
- because we're interested e.g. if we grabbed so that we
- can ungrab, even if our grab is not active just yet. */
- info = _gdk_display_get_last_pointer_grab (display);
-
if (info)
{
if (grab_window)
@@ -1253,7 +1731,6 @@ gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
return FALSE;
}
-
/**
* gdk_display_pointer_is_grabbed:
* @display: a #GdkDisplay
@@ -1263,21 +1740,77 @@ gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
* Returns: %TRUE if an active X pointer grab is in effect
*
* Since: 2.2
+ *
+ * Deprecated: 3.0. Use gdk_display_device_is_grabbed() instead.
*/
gboolean
gdk_display_pointer_is_grabbed (GdkDisplay *display)
{
- GdkPointerGrabInfo *info;
-
+ GdkDeviceManager *device_manager;
+ GList *devices, *dev;
+ GdkDevice *device;
+
+ g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
+
+ device_manager = gdk_display_get_device_manager (display);
+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+
+ for (dev = devices; dev; dev = dev->next)
+ {
+ device = dev->data;
+
+ if (device->source == GDK_SOURCE_MOUSE &&
+ gdk_display_device_is_grabbed (display, device))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * gdk_display_device_is_grabbed:
+ * @display: a #GdkDisplay
+ * @device: a #GdkDevice
+ *
+ * Returns %TRUE if there is an ongoing grab on @device for @display.
+ *
+ * Returns: %TRUE if there is a grab in effect for @device.
+ **/
+gboolean
+gdk_display_device_is_grabbed (GdkDisplay *display,
+ GdkDevice *device)
+{
+ GdkDeviceGrabInfo *info;
+
g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
+ g_return_val_if_fail (GDK_IS_DEVICE (device), TRUE);
/* What we're interested in is the steady state (ie last grab),
because we're interested e.g. if we grabbed so that we
can ungrab, even if our grab is not active just yet. */
- info = _gdk_display_get_last_pointer_grab (display);
-
+ info = _gdk_display_get_last_device_grab (display, device);
+
return (info && !info->implicit);
}
+/**
+ * gdk_display_get_device_manager:
+ * @display: a #GdkDisplay.
+ *
+ * Returns the #GdkDeviceManager associated to @display.
+ *
+ * Returns: A #GdkDeviceManager, or %NULL. This memory is
+ * owned by GDK and must not be freed or unreferenced.
+ *
+ * Since: 3.0
+ **/
+GdkDeviceManager *
+gdk_display_get_device_manager (GdkDisplay *display)
+{
+ g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+ return display->device_manager;
+}
+
#define __GDK_DISPLAY_C__
#include "gdkaliasdef.c"
diff --git a/gdk/gdkdisplay.h b/gdk/gdkdisplay.h
index 5de93efc28..55fcf3825d 100644
--- a/gdk/gdkdisplay.h
+++ b/gdk/gdkdisplay.h
@@ -30,11 +30,13 @@
#include <gdk/gdktypes.h>
#include <gdk/gdkevents.h>
+#include <gdk/gdkdevicemanager.h>
G_BEGIN_DECLS
typedef struct _GdkDisplayClass GdkDisplayClass;
typedef struct _GdkDisplayPointerHooks GdkDisplayPointerHooks;
+typedef struct _GdkDisplayDeviceHooks GdkDisplayDeviceHooks;
#define GDK_TYPE_DISPLAY (gdk_display_get_type ())
#define GDK_DISPLAY_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_DISPLAY, GdkDisplay))
@@ -67,9 +69,17 @@ typedef struct
gdouble toplevel_x, toplevel_y;
guint32 state;
guint32 button;
- gulong motion_hint_serial; /* 0 == didn't deliver hinted motion event */
} GdkPointerWindowInfo;
+typedef struct
+{
+ guint32 button_click_time[2]; /* The last 2 button click times. */
+ GdkWindow *button_window[2]; /* The last 2 windows to receive button presses. */
+ gint button_number[2]; /* The last 2 buttons to be pressed. */
+ gint button_x[2]; /* The last 2 button click positions. */
+ gint button_y[2];
+} GdkMultipleClickInfo;
+
struct _GdkDisplay
{
GObject parent_instance;
@@ -81,28 +91,29 @@ struct _GdkDisplay
/* Information for determining if the latest button click
* is part of a double-click or triple-click
*/
- guint32 GSEAL (button_click_time[2]); /* The last 2 button click times. */
- GdkWindow *GSEAL (button_window[2]); /* The last 2 windows to receive button presses. */
- gint GSEAL (button_number[2]); /* The last 2 buttons to be pressed. */
+ GHashTable *GSEAL (multiple_click_info);
guint GSEAL (double_click_time); /* Maximum time between clicks in msecs */
GdkDevice *GSEAL (core_pointer); /* Core pointer device */
- const GdkDisplayPointerHooks *GSEAL (pointer_hooks); /* Current hooks for querying pointer */
+ const GdkDisplayDeviceHooks *GSEAL (device_hooks); /* Current hooks for querying pointer */
guint GSEAL (closed) : 1; /* Whether this display has been closed */
guint GSEAL (ignore_core_events) : 1; /* Don't send core motion and button event */
guint GSEAL (double_click_distance); /* Maximum distance between clicks in pixels */
- gint GSEAL (button_x[2]); /* The last 2 button click positions. */
- gint GSEAL (button_y[2]);
- GList *GSEAL (pointer_grabs);
- GdkKeyboardGrabInfo GSEAL (keyboard_grab);
- GdkPointerWindowInfo GSEAL (pointer_info);
+ GHashTable *GSEAL (device_grabs);
+ GHashTable *GSEAL (motion_hint_info);
+
+ /* Hashtable containing a GdkPointerWindowInfo for each device */
+ GHashTable *GSEAL (pointers_info);
/* Last reported event time from server */
guint32 GSEAL (last_event_time);
+
+ /* Device manager associated to the display */
+ GdkDeviceManager *GSEAL (device_manager);
};
struct _GdkDisplayClass
@@ -138,6 +149,44 @@ struct _GdkDisplayPointerHooks
gint *win_y);
};
+/**
+ * GdkDisplayDeviceHooks:
+ * @get_device_state: Obtains the current position and modifier state for
+ * @device. The position is given in coordinates relative to the window
+ * containing the pointer, which is returned in @window.
+ * @window_get_device_position: Obtains the window underneath the device
+ * position. Current device position and modifier state are returned in
+ * @x, @y and @mask. The position is given in coordinates relative to
+ * @window.
+ * @window_at_device_position: Obtains the window underneath the device
+ * position, returning the location of that window in @win_x, @win_y.
+ * Returns %NULL if the window under the mouse pointer is not known to
+ * GDK (for example, belongs to another application).
+ *
+ * A table of pointers to functions for getting quantities related to
+ * the current device position. Each #GdkDisplay has a table of this type,
+ * which can be set using gdk_display_set_device_hooks().
+ */
+struct _GdkDisplayDeviceHooks
+{
+ void (* get_device_state) (GdkDisplay *display,
+ GdkDevice *device,
+ GdkScreen **screen,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask);
+ GdkWindow * (* window_get_device_position) (GdkDisplay *display,
+ GdkDevice *device,
+ GdkWindow *window,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask);
+ GdkWindow * (* window_at_device_position) (GdkDisplay *display,
+ GdkDevice *device,
+ gint *win_x,
+ gint *win_y);
+};
+
GType gdk_display_get_type (void) G_GNUC_CONST;
GdkDisplay *gdk_display_open (const gchar *display_name);
@@ -147,18 +196,26 @@ gint gdk_display_get_n_screens (GdkDisplay *display);
GdkScreen * gdk_display_get_screen (GdkDisplay *display,
gint screen_num);
GdkScreen * gdk_display_get_default_screen (GdkDisplay *display);
+
+#ifndef GDK_MULTIDEVICE_SAFE
void gdk_display_pointer_ungrab (GdkDisplay *display,
guint32 time_);
void gdk_display_keyboard_ungrab (GdkDisplay *display,
guint32 time_);
gboolean gdk_display_pointer_is_grabbed (GdkDisplay *display);
+#endif /* GDK_MULTIDEVICE_SAFE */
+
+gboolean gdk_display_device_is_grabbed (GdkDisplay *display,
+ GdkDevice *device);
void gdk_display_beep (GdkDisplay *display);
void gdk_display_sync (GdkDisplay *display);
void gdk_display_flush (GdkDisplay *display);
void gdk_display_close (GdkDisplay *display);
+#ifndef GDK_DISABLE_DEPRECATED
GList * gdk_display_list_devices (GdkDisplay *display);
+#endif /* GDK_DISABLE_DEPRECATED */
GdkEvent* gdk_display_get_event (GdkDisplay *display);
GdkEvent* gdk_display_peek_event (GdkDisplay *display);
@@ -177,7 +234,11 @@ void gdk_display_set_double_click_distance (GdkDisplay *display,
GdkDisplay *gdk_display_get_default (void);
+#ifndef GDK_MULTIDEVICE_SAFE
+
+#ifndef GDK_DISABLE_DEPRECATED
GdkDevice *gdk_display_get_core_pointer (GdkDisplay *display);
+#endif /* GDK_DISABLE_DEPRECATED */
void gdk_display_get_pointer (GdkDisplay *display,
GdkScreen **screen,
@@ -191,9 +252,31 @@ void gdk_display_warp_pointer (GdkDisplay *disp
GdkScreen *screen,
gint x,
gint y);
-
+#endif /* GDK_MULTIDEVICE_SAFE */
+
+void gdk_display_get_device_state (GdkDisplay *display,
+ GdkDevice *device,
+ GdkScreen **screen,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask);
+GdkWindow * gdk_display_get_window_at_device_position (GdkDisplay *display,
+ GdkDevice *device,
+ gint *win_x,
+ gint *win_y);
+void gdk_display_warp_device (GdkDisplay *display,
+ GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y);
+
+#ifndef GDK_MULTIDEVICE_SAFE
GdkDisplayPointerHooks *gdk_display_set_pointer_hooks (GdkDisplay *display,
const GdkDisplayPointerHooks *new_hooks);
+#endif /* GDK_MULTIDEVICE_SAFE */
+
+GdkDisplayDeviceHooks *gdk_display_set_device_hooks (GdkDisplay *display,
+ const GdkDisplayDeviceHooks *new_hooks);
GdkDisplay *gdk_display_open_default_libgtk_only (void);
@@ -221,6 +304,9 @@ gboolean gdk_display_supports_shapes (GdkDisplay *display);
gboolean gdk_display_supports_input_shapes (GdkDisplay *display);
gboolean gdk_display_supports_composite (GdkDisplay *display);
+GdkDeviceManager * gdk_display_get_device_manager (GdkDisplay *display);
+
+
G_END_DECLS
#endif /* __GDK_DISPLAY_H__ */
diff --git a/gdk/gdkdnd.h b/gdk/gdkdnd.h
index 7fa98a5e88..2b6ceb0406 100644
--- a/gdk/gdkdnd.h
+++ b/gdk/gdkdnd.h
@@ -32,6 +32,7 @@
#define __GDK_DND_H__
#include <gdk/gdktypes.h>
+#include <gdk/gdkdevice.h>
G_BEGIN_DECLS
@@ -106,6 +107,10 @@ struct _GdkDragContextClass {
GType gdk_drag_context_get_type (void) G_GNUC_CONST;
GdkDragContext * gdk_drag_context_new (void);
+void gdk_drag_context_set_device (GdkDragContext *context,
+ GdkDevice *device);
+GdkDevice * gdk_drag_context_get_device (GdkDragContext *context);
+
GList *gdk_drag_context_list_targets (GdkDragContext *context);
GdkDragAction gdk_drag_context_get_actions (GdkDragContext *context);
GdkDragAction gdk_drag_context_get_suggested_action (GdkDragContext *context);
diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c
index 6152202f00..151ce86245 100644
--- a/gdk/gdkevents.c
+++ b/gdk/gdkevents.c
@@ -26,6 +26,7 @@
#include "config.h"
#include <string.h> /* For memset() */
+#include <math.h>
#include "gdk.h"
#include "gdkinternals.h"
@@ -446,6 +447,7 @@ gdk_event_copy (const GdkEvent *event)
GdkEventPrivate *private = (GdkEventPrivate *)event;
new_private->screen = private->screen;
+ new_private->device = private->device;
}
switch (event->any.type)
@@ -920,6 +922,95 @@ gdk_event_get_axis (const GdkEvent *event,
}
/**
+ * gdk_event_set_device:
+ * @event: a #GdkEvent
+ * @device: a #GdkDevice
+ *
+ * Sets the device for @event to @device. The event must
+ * have been allocated by GTK+, for instance, by
+ * gdk_event_copy().
+ *
+ * Since: 3.0
+ **/
+void
+gdk_event_set_device (GdkEvent *event,
+ GdkDevice *device)
+{
+ GdkEventPrivate *private;
+
+ g_return_if_fail (gdk_event_is_allocated (event));
+
+ private = (GdkEventPrivate *) event;
+
+ private->device = device;
+
+ switch (event->type)
+ {
+ case GDK_MOTION_NOTIFY:
+ event->motion.device = device;
+ break;
+ case GDK_BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ event->button.device = device;
+ break;
+ case GDK_SCROLL:
+ event->scroll.device = device;
+ break;
+ case GDK_PROXIMITY_IN:
+ case GDK_PROXIMITY_OUT:
+ event->proximity.device = device;
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * gdk_event_get_device:
+ * @event: a #GdkEvent.
+ *
+ * If the event contains a "device" field, this function will return
+ * it, else it will return %NULL.
+ *
+ * Returns: a #GdkDevice, or %NULL.
+ *
+ * Since: 3.0
+ **/
+GdkDevice *
+gdk_event_get_device (const GdkEvent *event)
+{
+ g_return_val_if_fail (event != NULL, NULL);
+
+ if (gdk_event_is_allocated (event))
+ {
+ GdkEventPrivate *private = (GdkEventPrivate *) event;
+
+ if (private->device)
+ return private->device;
+ }
+
+ switch (event->type)
+ {
+ case GDK_MOTION_NOTIFY:
+ return event->motion.device;
+ case GDK_BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ return event->button.device;
+ case GDK_SCROLL:
+ return event->scroll.device;
+ case GDK_PROXIMITY_IN:
+ case GDK_PROXIMITY_OUT:
+ return event->proximity.device;
+ default:
+ return NULL;
+ }
+}
+
+/**
* gdk_event_request_motions:
* @event: a valid #GdkEvent
*
@@ -954,8 +1045,139 @@ gdk_event_request_motions (const GdkEventMotion *event)
gdk_device_get_state (event->device, event->window, NULL, NULL);
display = gdk_drawable_get_display (event->window);
- _gdk_display_enable_motion_hints (display);
+ _gdk_display_enable_motion_hints (display, event->device);
+ }
+}
+
+static gboolean
+gdk_events_get_axis_distances (GdkEvent *event1,
+ GdkEvent *event2,
+ gdouble *x_distance,
+ gdouble *y_distance,
+ gdouble *distance)
+{
+ gdouble x1, x2, y1, y2;
+ gdouble xd, yd;
+
+ if (!gdk_event_get_coords (event1, &x1, &y1) ||
+ !gdk_event_get_coords (event2, &x2, &y2))
+ return FALSE;
+
+ xd = x2 - x1;
+ yd = y2 - y1;
+
+ if (x_distance)
+ *x_distance = xd;
+
+ if (y_distance)
+ *y_distance = yd;
+
+ if (distance)
+ *distance = sqrt ((xd * xd) + (yd * yd));
+
+ return TRUE;
+}
+
+/**
+ * gdk_events_get_distance:
+ * @event1: first #GdkEvent
+ * @event2: second #GdkEvent
+ * @distance: return location for the distance
+ *
+ * If both events have X/Y information, the distance between both coordinates
+ * (as in a straight line going from @event1 to @event2) will be returned.
+ *
+ * Returns: %TRUE if the distance could be calculated.
+ *
+ * Since: 3.0
+ **/
+gboolean
+gdk_events_get_distance (GdkEvent *event1,
+ GdkEvent *event2,
+ gdouble *distance)
+{
+ return gdk_events_get_axis_distances (event1, event2,
+ NULL, NULL,
+ distance);
+}
+
+/**
+ * gdk_events_get_angle:
+ * @event1: first #GdkEvent
+ * @event2: second #GdkEvent
+ * @angle: return location for the relative angle between both events
+ *
+ * If both events contain X/Y information, this function will return %TRUE
+ * and return in @angle the relative angle from @event1 to @event2. The rotation
+ * direction for positive angles is from the positive X axis towards the positive
+ * Y axis.
+ *
+ * Returns: %TRUE if the angle could be calculated.
+ *
+ * Since: 3.0
+ **/
+gboolean
+gdk_events_get_angle (GdkEvent *event1,
+ GdkEvent *event2,
+ gdouble *angle)
+{
+ gdouble x_distance, y_distance, distance;
+
+ if (!gdk_events_get_axis_distances (event1, event2,
+ &x_distance, &y_distance,
+ &distance))
+ return FALSE;
+
+ if (angle)
+ {
+ *angle = atan2 (x_distance, y_distance);
+
+ /* Invert angle */
+ *angle = (2 * G_PI) - *angle;
+
+ /* Shift it 90° */
+ *angle += G_PI / 2;
+
+ /* And constraint it to 0°-360° */
+ *angle = fmod (*angle, 2 * G_PI);
}
+
+ return TRUE;
+}
+
+/**
+ * gdk_events_get_center:
+ * @event1: first #GdkEvent
+ * @event2: second #GdkEvent
+ * @x: return location for the X coordinate of the center
+ * @y: return location for the Y coordinate of the center
+ *
+ * If both events contain X/Y information, the center of both coordinates
+ * will be returned in @x and @y.
+ *
+ * Returns: %TRUE if the center could be calculated.
+ *
+ * Since: 3.0
+ **/
+gboolean
+gdk_events_get_center (GdkEvent *event1,
+ GdkEvent *event2,
+ gdouble *x,
+ gdouble *y)
+{
+ gdouble x1, x2, y1, y2;
+
+ if (!gdk_event_get_coords (event1, &x1, &y1) ||
+ !gdk_event_get_coords (event2, &x2, &y2))
+ return FALSE;
+
+ if (x)
+ *x = (x2 + x1) / 2;
+
+ if (y)
+ *y = (y2 + y1) / 2;
+
+ return TRUE;
}
/**
@@ -1186,54 +1408,67 @@ void
_gdk_event_button_generate (GdkDisplay *display,
GdkEvent *event)
{
- if ((event->button.time < (display->button_click_time[1] + 2*display->double_click_time)) &&
- (event->button.window == display->button_window[1]) &&
- (event->button.button == display->button_number[1]) &&
- (ABS (event->button.x - display->button_x[1]) <= display->double_click_distance) &&
- (ABS (event->button.y - display->button_y[1]) <= display->double_click_distance))
-{
+ GdkMultipleClickInfo *info;
+
+ info = g_hash_table_lookup (display->multiple_click_info, event->button.device);
+
+ if (G_UNLIKELY (!info))
+ {
+ info = g_new0 (GdkMultipleClickInfo, 1);
+ info->button_number[0] = info->button_number[1] = -1;
+
+ g_hash_table_insert (display->multiple_click_info,
+ event->button.device, info);
+ }
+
+ if ((event->button.time < (info->button_click_time[1] + 2 * display->double_click_time)) &&
+ (event->button.window == info->button_window[1]) &&
+ (event->button.button == info->button_number[1]) &&
+ (ABS (event->button.x - info->button_x[1]) <= display->double_click_distance) &&
+ (ABS (event->button.y - info->button_y[1]) <= display->double_click_distance))
+ {
gdk_synthesize_click (display, event, 3);
-
- display->button_click_time[1] = 0;
- display->button_click_time[0] = 0;
- display->button_window[1] = NULL;
- display->button_window[0] = NULL;
- display->button_number[1] = -1;
- display->button_number[0] = -1;
- display->button_x[0] = display->button_x[1] = 0;
- display->button_y[0] = display->button_y[1] = 0;
+
+ info->button_click_time[1] = 0;
+ info->button_click_time[0] = 0;
+ info->button_window[1] = NULL;
+ info->button_window[0] = NULL;
+ info->button_number[1] = -1;
+ info->button_number[0] = -1;
+ info->button_x[0] = info->button_x[1] = 0;
+ info->button_y[0] = info->button_y[1] = 0;
}
- else if ((event->button.time < (display->button_click_time[0] + display->double_click_time)) &&
- (event->button.window == display->button_window[0]) &&
- (event->button.button == display->button_number[0]) &&
- (ABS (event->button.x - display->button_x[0]) <= display->double_click_distance) &&
- (ABS (event->button.y - display->button_y[0]) <= display->double_click_distance))
+ else if ((event->button.time < (info->button_click_time[0] + display->double_click_time)) &&
+ (event->button.window == info->button_window[0]) &&
+ (event->button.button == info->button_number[0]) &&
+ (ABS (event->button.x - info->button_x[0]) <= display->double_click_distance) &&
+ (ABS (event->button.y - info->button_y[0]) <= display->double_click_distance))
{
gdk_synthesize_click (display, event, 2);
- display->button_click_time[1] = display->button_click_time[0];
- display->button_click_time[0] = event->button.time;
- display->button_window[1] = display->button_window[0];
- display->button_window[0] = event->button.window;
- display->button_number[1] = display->button_number[0];
- display->button_number[0] = event->button.button;
- display->button_x[1] = display->button_x[0];
- display->button_x[0] = event->button.x;
- display->button_y[1] = display->button_y[0];
- display->button_y[0] = event->button.y;
+ info->button_click_time[1] = info->button_click_time[0];
+ info->button_click_time[0] = event->button.time;
+ info->button_window[1] = info->button_window[0];
+ info->button_window[0] = event->button.window;
+ info->button_number[1] = info->button_number[0];
+ info->button_number[0] = event->button.button;
+ info->button_x[1] = info->button_x[0];
+ info->button_x[0] = event->button.x;
+ info->button_y[1] = info->button_y[0];
+ info->button_y[0] = event->button.y;
}
else
{
- display->button_click_time[1] = 0;
- display->button_click_time[0] = event->button.time;
- display->button_window[1] = NULL;
- display->button_window[0] = event->button.window;
- display->button_number[1] = -1;
- display->button_number[0] = event->button.button;
- display->button_x[1] = 0;
- display->button_x[0] = event->button.x;
- display->button_y[1] = 0;
- display->button_y[0] = event->button.y;
+ info->button_click_time[1] = 0;
+ info->button_click_time[0] = event->button.time;
+ info->button_window[1] = NULL;
+ info->button_window[0] = event->button.window;
+ info->button_number[1] = -1;
+ info->button_number[0] = event->button.button;
+ info->button_x[1] = 0;
+ info->button_x[0] = event->button.x;
+ info->button_y[1] = 0;
+ info->button_y[0] = event->button.y;
}
}
diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h
index 2f7a09b8d5..f8f6d1a61a 100644
--- a/gdk/gdkevents.h
+++ b/gdk/gdkevents.h
@@ -34,7 +34,7 @@
#include <gdk/gdkcolor.h>
#include <gdk/gdktypes.h>
#include <gdk/gdkdnd.h>
-#include <gdk/gdkinput.h>
+#include <gdk/gdkdevice.h>
G_BEGIN_DECLS
@@ -187,35 +187,6 @@ typedef enum
GDK_EVENT_LAST /* helper variable for decls */
} GdkEventType;
-/* Event masks. (Used to select what types of events a window
- * will receive).
- */
-typedef enum
-{
- GDK_EXPOSURE_MASK = 1 << 1,
- GDK_POINTER_MOTION_MASK = 1 << 2,
- GDK_POINTER_MOTION_HINT_MASK = 1 << 3,
- GDK_BUTTON_MOTION_MASK = 1 << 4,
- GDK_BUTTON1_MOTION_MASK = 1 << 5,
- GDK_BUTTON2_MOTION_MASK = 1 << 6,
- GDK_BUTTON3_MOTION_MASK = 1 << 7,
- GDK_BUTTON_PRESS_MASK = 1 << 8,
- GDK_BUTTON_RELEASE_MASK = 1 << 9,
- GDK_KEY_PRESS_MASK = 1 << 10,
- GDK_KEY_RELEASE_MASK = 1 << 11,
- GDK_ENTER_NOTIFY_MASK = 1 << 12,
- GDK_LEAVE_NOTIFY_MASK = 1 << 13,
- GDK_FOCUS_CHANGE_MASK = 1 << 14,
- GDK_STRUCTURE_MASK = 1 << 15,
- GDK_PROPERTY_CHANGE_MASK = 1 << 16,
- GDK_VISIBILITY_NOTIFY_MASK = 1 << 17,
- GDK_PROXIMITY_IN_MASK = 1 << 18,
- GDK_PROXIMITY_OUT_MASK = 1 << 19,
- GDK_SUBSTRUCTURE_MASK = 1 << 20,
- GDK_SCROLL_MASK = 1 << 21,
- GDK_ALL_EVENTS_MASK = 0x3FFFFE
-} GdkEventMask;
-
typedef enum
{
GDK_VISIBILITY_UNOBSCURED,
@@ -569,7 +540,22 @@ gboolean gdk_event_get_root_coords (const GdkEvent *event,
gboolean gdk_event_get_axis (const GdkEvent *event,
GdkAxisUse axis_use,
gdouble *value);
+void gdk_event_set_device (GdkEvent *event,
+ GdkDevice *device);
+GdkDevice* gdk_event_get_device (const GdkEvent *event);
void gdk_event_request_motions (const GdkEventMotion *event);
+
+gboolean gdk_events_get_distance (GdkEvent *event1,
+ GdkEvent *event2,
+ gdouble *distance);
+gboolean gdk_events_get_angle (GdkEvent *event1,
+ GdkEvent *event2,
+ gdouble *angle);
+gboolean gdk_events_get_center (GdkEvent *event1,
+ GdkEvent *event2,
+ gdouble *x,
+ gdouble *y);
+
void gdk_event_handler_set (GdkEventFunc func,
gpointer data,
GDestroyNotify notify);
diff --git a/gdk/gdkglobals.c b/gdk/gdkglobals.c
index 4c3ad80956..a805bcc5bf 100644
--- a/gdk/gdkglobals.c
+++ b/gdk/gdkglobals.c
@@ -40,6 +40,7 @@ gchar *_gdk_display_name = NULL;
gint _gdk_screen_number = -1;
gchar *_gdk_display_arg_name = NULL;
gboolean _gdk_native_windows = FALSE;
+gboolean _gdk_enable_multidevice = FALSE;
GSList *_gdk_displays = NULL;
diff --git a/gdk/gdkinput.h b/gdk/gdkinput.h
index ad843954a1..bc30cd2ef4 100644
--- a/gdk/gdkinput.h
+++ b/gdk/gdkinput.h
@@ -32,159 +32,27 @@
#define __GDK_INPUT_H__
#include <gdk/gdktypes.h>
+#include <gdk/gdkdevice.h>
G_BEGIN_DECLS
-#define GDK_TYPE_DEVICE (gdk_device_get_type ())
-#define GDK_DEVICE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_DEVICE, GdkDevice))
-#define GDK_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_DEVICE, GdkDeviceClass))
-#define GDK_IS_DEVICE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_DEVICE))
-#define GDK_IS_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_DEVICE))
-#define GDK_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_DEVICE, GdkDeviceClass))
-
-typedef struct _GdkDeviceKey GdkDeviceKey;
-typedef struct _GdkDeviceAxis GdkDeviceAxis;
-typedef struct _GdkDevice GdkDevice;
-typedef struct _GdkDeviceClass GdkDeviceClass;
-typedef struct _GdkTimeCoord GdkTimeCoord;
-
-typedef enum
-{
- GDK_EXTENSION_EVENTS_NONE,
- GDK_EXTENSION_EVENTS_ALL,
- GDK_EXTENSION_EVENTS_CURSOR
-} GdkExtensionMode;
-
-typedef enum
-{
- GDK_SOURCE_MOUSE,
- GDK_SOURCE_PEN,
- GDK_SOURCE_ERASER,
- GDK_SOURCE_CURSOR
-} GdkInputSource;
-
-typedef enum
-{
- GDK_MODE_DISABLED,
- GDK_MODE_SCREEN,
- GDK_MODE_WINDOW
-} GdkInputMode;
-
-typedef enum
-{
- GDK_AXIS_IGNORE,
- GDK_AXIS_X,
- GDK_AXIS_Y,
- GDK_AXIS_PRESSURE,
- GDK_AXIS_XTILT,
- GDK_AXIS_YTILT,
- GDK_AXIS_WHEEL,
- GDK_AXIS_LAST
-} GdkAxisUse;
-
-struct _GdkDeviceKey
-{
- guint keyval;
- GdkModifierType modifiers;
-};
-
-struct _GdkDeviceAxis
-{
- GdkAxisUse use;
- gdouble min;
- gdouble max;
-};
-
-struct _GdkDevice
-{
- GObject parent_instance;
- /* All fields are read-only */
-
- gchar *GSEAL (name);
- GdkInputSource GSEAL (source);
- GdkInputMode GSEAL (mode);
- gboolean GSEAL (has_cursor); /* TRUE if the X pointer follows device motion */
-
- gint GSEAL (num_axes);
- GdkDeviceAxis *GSEAL (axes);
-
- gint GSEAL (num_keys);
- GdkDeviceKey *GSEAL (keys);
-};
-
-/* We don't allocate each coordinate this big, but we use it to
- * be ANSI compliant and avoid accessing past the defined limits.
- */
-#define GDK_MAX_TIMECOORD_AXES 128
-
-struct _GdkTimeCoord
-{
- guint32 time;
- gdouble axes[GDK_MAX_TIMECOORD_AXES];
-};
-
-GType gdk_device_get_type (void) G_GNUC_CONST;
+#if !defined (GDK_MULTIDEVICE_SAFE) && !defined (GDK_DISABLE_DEPRECATED)
#ifndef GDK_MULTIHEAD_SAFE
-/* Returns a list of GdkDevice * */
-GList * gdk_devices_list (void);
-#endif /* GDK_MULTIHEAD_SAFE */
-
-G_CONST_RETURN gchar *gdk_device_get_name (GdkDevice *device);
-GdkInputSource gdk_device_get_source (GdkDevice *device);
-GdkInputMode gdk_device_get_mode (GdkDevice *device);
-gboolean gdk_device_get_has_cursor (GdkDevice *device);
-
-void gdk_device_get_key (GdkDevice *device,
- guint index,
- guint *keyval,
- GdkModifierType *modifiers);
-GdkAxisUse gdk_device_get_axis_use (GdkDevice *device,
- guint index);
-
-/* Functions to configure a device */
-void gdk_device_set_source (GdkDevice *device,
- GdkInputSource source);
-
-gboolean gdk_device_set_mode (GdkDevice *device,
- GdkInputMode mode);
-
-void gdk_device_set_key (GdkDevice *device,
- guint index_,
- guint keyval,
- GdkModifierType modifiers);
-
-void gdk_device_set_axis_use (GdkDevice *device,
- guint index_,
- GdkAxisUse use);
-void gdk_device_get_state (GdkDevice *device,
- GdkWindow *window,
- gdouble *axes,
- GdkModifierType *mask);
+/* Returns a list of GdkDevice * */
+GList * gdk_devices_list (void);
-gboolean gdk_device_get_history (GdkDevice *device,
- GdkWindow *window,
- guint32 start,
- guint32 stop,
- GdkTimeCoord ***events,
- gint *n_events);
+GdkDevice *gdk_device_get_core_pointer (void);
-void gdk_device_free_history (GdkTimeCoord **events,
- gint n_events);
-gboolean gdk_device_get_axis (GdkDevice *device,
- gdouble *axes,
- GdkAxisUse use,
- gdouble *value);
+#endif /* GDK_MULTIHEAD_SAFE */
void gdk_input_set_extension_events (GdkWindow *window,
gint mask,
GdkExtensionMode mode);
-#ifndef GDK_MULTIHEAD_SAFE
-GdkDevice *gdk_device_get_core_pointer (void);
-#endif
-
+#endif /* !GDK_MULTIDEVICE_SAFE && GDK_DISABLE_DEPRECATED */
+
G_END_DECLS
#endif /* __GDK_INPUT_H__ */
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index 822335fcd4..b154c57240 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -169,6 +169,7 @@ struct _GdkEventPrivate
guint flags;
GdkScreen *screen;
gpointer windowing_data;
+ GdkDevice *device;
};
/* Tracks information about the pointer grab on this display */
@@ -182,13 +183,19 @@ typedef struct
guint event_mask;
gboolean implicit;
guint32 time;
+ GdkGrabOwnership ownership;
- gboolean activated;
- gboolean implicit_ungrab;
-} GdkPointerGrabInfo;
+ guint activated : 1;
+ guint implicit_ungrab : 1;
+} GdkDeviceGrabInfo;
typedef struct _GdkInputWindow GdkInputWindow;
+typedef void (* GdkDisplayPointerInfoForeach) (GdkDisplay *display,
+ GdkDevice *device,
+ GdkPointerWindowInfo *device_info,
+ gpointer user_data);
+
/* Private version of GdkWindowObject. The initial part of this strucuture
is public for historical reasons. Don't change that part */
typedef struct _GdkWindowPaint GdkWindowPaint;
@@ -236,6 +243,7 @@ struct _GdkWindowObject
guint accept_focus : 1;
guint focus_on_map : 1;
guint shaped : 1;
+ guint support_multidevice : 1;
GdkEventMask event_mask;
@@ -255,6 +263,7 @@ struct _GdkWindowObject
GdkRegion *clip_region; /* Clip region (wrt toplevel) in window coords */
GdkRegion *clip_region_with_children; /* Clip region in window coords */
GdkCursor *cursor;
+ GHashTable *device_cursor;
gint8 toplevel_window_type;
guint synthesize_crossing_event_queued : 1;
guint effective_visibility : 2;
@@ -274,6 +283,9 @@ struct _GdkWindowObject
cairo_surface_t *cairo_surface;
guint outstanding_surfaces; /* only set on impl window */
+
+ GList *devices_inside;
+ GHashTable *device_events;
};
#define GDK_WINDOW_TYPE(d) (((GdkWindowObject*)(GDK_WINDOW (d)))->window_type)
@@ -287,6 +299,7 @@ extern GSList *_gdk_displays;
extern gchar *_gdk_display_name;
extern gint _gdk_screen_number;
extern gchar *_gdk_display_arg_name;
+extern gboolean _gdk_enable_multidevice;
void _gdk_events_queue (GdkDisplay *display);
GdkEvent* _gdk_event_unqueue (GdkDisplay *display);
@@ -315,6 +328,9 @@ void gdk_synthesize_window_state (GdkWindow *window,
GdkWindowState unset_flags,
GdkWindowState set_flags);
+GdkDeviceManager * _gdk_device_manager_new (GdkDisplay *display);
+
+
#define GDK_SCRATCH_IMAGE_WIDTH 256
#define GDK_SCRATCH_IMAGE_HEIGHT 64
@@ -453,17 +469,20 @@ GdkRegion *_gdk_windowing_get_shape_for_mask (GdkBitmap *mask);
void _gdk_windowing_window_beep (GdkWindow *window);
-void _gdk_windowing_get_pointer (GdkDisplay *display,
+void _gdk_windowing_get_device_state (GdkDisplay *display,
+ GdkDevice *device,
GdkScreen **screen,
gint *x,
gint *y,
GdkModifierType *mask);
-GdkWindow* _gdk_windowing_window_at_pointer (GdkDisplay *display,
- gint *win_x,
- gint *win_y,
- GdkModifierType *mask,
- gboolean get_toplevel);
-GdkGrabStatus _gdk_windowing_pointer_grab (GdkWindow *window,
+GdkWindow* _gdk_windowing_window_at_device_position (GdkDisplay *display,
+ GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel);
+GdkGrabStatus _gdk_windowing_device_grab (GdkDevice *device,
+ GdkWindow *window,
GdkWindow *native,
gboolean owner_events,
GdkEventMask event_mask,
@@ -580,34 +599,41 @@ char *_gdk_windowing_get_startup_notify_id (GAppLaunchContext *context,
void _gdk_windowing_launch_failed (GAppLaunchContext *context,
const char *startup_notify_id);
-GdkPointerGrabInfo *_gdk_display_get_active_pointer_grab (GdkDisplay *display);
-void _gdk_display_pointer_grab_update (GdkDisplay *display,
- gulong current_serial);
-GdkPointerGrabInfo *_gdk_display_get_last_pointer_grab (GdkDisplay *display);
-GdkPointerGrabInfo *_gdk_display_add_pointer_grab (GdkDisplay *display,
- GdkWindow *window,
- GdkWindow *native_window,
- gboolean owner_events,
- GdkEventMask event_mask,
- unsigned long serial_start,
- guint32 time,
- gboolean implicit);
-GdkPointerGrabInfo * _gdk_display_has_pointer_grab (GdkDisplay *display,
- gulong serial);
-gboolean _gdk_display_end_pointer_grab (GdkDisplay *display,
- gulong serial,
- GdkWindow *if_child,
- gboolean implicit);
-void _gdk_display_set_has_keyboard_grab (GdkDisplay *display,
- GdkWindow *window,
- GdkWindow *native_window,
- gboolean owner_events,
- unsigned long serial,
- guint32 time);
-void _gdk_display_unset_has_keyboard_grab (GdkDisplay *display,
- gboolean implicit);
-void _gdk_display_enable_motion_hints (GdkDisplay *display);
-
+void _gdk_display_device_grab_update (GdkDisplay *display,
+ GdkDevice *device,
+ gulong current_serial);
+GdkDeviceGrabInfo *_gdk_display_get_last_device_grab (GdkDisplay *display,
+ GdkDevice *device);
+GdkDeviceGrabInfo *_gdk_display_add_device_grab (GdkDisplay *display,
+ GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow *native_window,
+ GdkGrabOwnership grab_ownership,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ unsigned long serial_start,
+ guint32 time,
+ gboolean implicit);
+GdkDeviceGrabInfo * _gdk_display_has_device_grab (GdkDisplay *display,
+ GdkDevice *device,
+ gulong serial);
+gboolean _gdk_display_end_device_grab (GdkDisplay *display,
+ GdkDevice *device,
+ gulong serial,
+ GdkWindow *if_child,
+ gboolean implicit);
+gboolean _gdk_display_check_grab_ownership (GdkDisplay *display,
+ GdkDevice *device,
+ gulong serial);
+void _gdk_display_enable_motion_hints (GdkDisplay *display,
+ GdkDevice *device);
+
+GdkPointerWindowInfo * _gdk_display_get_pointer_info (GdkDisplay *display,
+ GdkDevice *device);
+
+void _gdk_display_pointer_info_foreach (GdkDisplay *display,
+ GdkDisplayPointerInfoForeach func,
+ gpointer user_data);
void _gdk_window_invalidate_for_expose (GdkWindow *window,
GdkRegion *region);
@@ -639,6 +665,7 @@ gboolean _gdk_window_event_parent_of (GdkWindow *parent,
void _gdk_synthesize_crossing_events (GdkDisplay *display,
GdkWindow *src,
GdkWindow *dest,
+ GdkDevice *device,
GdkCrossingMode mode,
gint toplevel_x,
gint toplevel_y,
@@ -648,7 +675,8 @@ void _gdk_synthesize_crossing_events (GdkDisplay *display,
gulong serial,
gboolean non_linear);
void _gdk_display_set_window_under_pointer (GdkDisplay *display,
- GdkWindow *window);
+ GdkDevice *device,
+ GdkWindow *window);
void _gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_window);
diff --git a/gdk/gdkoffscreenwindow.c b/gdk/gdkoffscreenwindow.c
index 23d92affd2..2c4113b0fa 100644
--- a/gdk/gdkoffscreenwindow.c
+++ b/gdk/gdkoffscreenwindow.c
@@ -811,10 +811,11 @@ gdk_offscreen_window_get_deskrelative_origin (GdkWindow *window,
}
static gboolean
-gdk_offscreen_window_get_pointer (GdkWindow *window,
- gint *x,
- gint *y,
- GdkModifierType *mask)
+gdk_offscreen_window_get_device_state (GdkWindow *window,
+ GdkDevice *device,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
{
GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
GdkOffscreenWindow *offscreen;
@@ -829,7 +830,7 @@ gdk_offscreen_window_get_pointer (GdkWindow *window,
offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
if (offscreen->embedder != NULL)
{
- gdk_window_get_pointer (offscreen->embedder, &tmpx, &tmpy, &tmpmask);
+ gdk_window_get_device_position (offscreen->embedder, device, &tmpx, &tmpy, &tmpmask);
from_embedder (window,
tmpx, tmpy,
&dtmpx, &dtmpy);
@@ -1110,27 +1111,6 @@ gdk_offscreen_window_set_static_gravities (GdkWindow *window,
}
static void
-gdk_offscreen_window_set_cursor (GdkWindow *window,
- GdkCursor *cursor)
-{
- GdkWindowObject *private = (GdkWindowObject *)window;
- GdkOffscreenWindow *offscreen;
-
- offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
-
- if (offscreen->cursor)
- {
- gdk_cursor_unref (offscreen->cursor);
- offscreen->cursor = NULL;
- }
-
- if (cursor)
- offscreen->cursor = gdk_cursor_ref (cursor);
-
- /* TODO: The cursor is never actually used... */
-}
-
-static void
gdk_offscreen_window_get_geometry (GdkWindow *window,
gint *x,
gint *y,
@@ -1289,7 +1269,6 @@ gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface)
iface->get_events = gdk_offscreen_window_get_events;
iface->set_events = gdk_offscreen_window_set_events;
iface->reparent = gdk_offscreen_window_reparent;
- iface->set_cursor = gdk_offscreen_window_set_cursor;
iface->get_geometry = gdk_offscreen_window_get_geometry;
iface->shape_combine_region = gdk_offscreen_window_shape_combine_region;
iface->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
@@ -1298,7 +1277,7 @@ gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface)
iface->queue_translation = gdk_offscreen_window_queue_translation;
iface->get_root_coords = gdk_offscreen_window_get_root_coords;
iface->get_deskrelative_origin = gdk_offscreen_window_get_deskrelative_origin;
- iface->get_pointer = gdk_offscreen_window_get_pointer;
+ iface->get_device_state = gdk_offscreen_window_get_device_state;
iface->destroy = gdk_offscreen_window_destroy;
}
diff --git a/gdk/gdktypes.h b/gdk/gdktypes.h
index 78748dc3d3..f2a1ff4015 100644
--- a/gdk/gdktypes.h
+++ b/gdk/gdktypes.h
@@ -236,6 +236,50 @@ typedef enum
GDK_GRAB_FROZEN = 4
} GdkGrabStatus;
+/**
+ * GdkGrabOwnership:
+ * @GDK_OWNERSHIP_NONE: All other devices' events are allowed.
+ * @GDK_OWNERSHIP_WINDOW: Other devices' events are blocked for the grab window.
+ * @GDK_OWNERSHIP_APPLICATION: Other devices' events are blocked for the whole application.
+ *
+ * Defines how device grabs interact with other devices.
+ */
+typedef enum
+{
+ GDK_OWNERSHIP_NONE,
+ GDK_OWNERSHIP_WINDOW,
+ GDK_OWNERSHIP_APPLICATION
+} GdkGrabOwnership;
+
+/* Event masks. (Used to select what types of events a window
+ * * will receive).
+ * */
+typedef enum
+{
+ GDK_EXPOSURE_MASK = 1 << 1,
+ GDK_POINTER_MOTION_MASK = 1 << 2,
+ GDK_POINTER_MOTION_HINT_MASK = 1 << 3,
+ GDK_BUTTON_MOTION_MASK = 1 << 4,
+ GDK_BUTTON1_MOTION_MASK = 1 << 5,
+ GDK_BUTTON2_MOTION_MASK = 1 << 6,
+ GDK_BUTTON3_MOTION_MASK = 1 << 7,
+ GDK_BUTTON_PRESS_MASK = 1 << 8,
+ GDK_BUTTON_RELEASE_MASK = 1 << 9,
+ GDK_KEY_PRESS_MASK = 1 << 10,
+ GDK_KEY_RELEASE_MASK = 1 << 11,
+ GDK_ENTER_NOTIFY_MASK = 1 << 12,
+ GDK_LEAVE_NOTIFY_MASK = 1 << 13,
+ GDK_FOCUS_CHANGE_MASK = 1 << 14,
+ GDK_STRUCTURE_MASK = 1 << 15,
+ GDK_PROPERTY_CHANGE_MASK = 1 << 16,
+ GDK_VISIBILITY_NOTIFY_MASK = 1 << 17,
+ GDK_PROXIMITY_IN_MASK = 1 << 18,
+ GDK_PROXIMITY_OUT_MASK = 1 << 19,
+ GDK_SUBSTRUCTURE_MASK = 1 << 20,
+ GDK_SCROLL_MASK = 1 << 21,
+ GDK_ALL_EVENTS_MASK = 0x3FFFFE
+} GdkEventMask;
+
typedef void (*GdkInputFunction) (gpointer data,
gint source,
GdkInputCondition condition);
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 10b27d3037..17d6e20a3c 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -37,6 +37,8 @@
#include "gdk.h" /* For gdk_rectangle_union() */
#include "gdkinternals.h"
#include "gdkintl.h"
+#include "gdkscreen.h"
+#include "gdkdeviceprivate.h"
#include "gdkdrawable.h"
#include "gdkmarshalers.h"
#include "gdkpixmap.h"
@@ -224,7 +226,6 @@ typedef struct {
int dx, dy; /* The amount that the source was moved to reach dest_region */
} GdkWindowRegionMove;
-
/* Global info */
static GdkGC *gdk_window_create_gc (GdkDrawable *drawable,
@@ -402,7 +403,8 @@ static void do_move_region_bits_on_impl (GdkWindowObject *private,
int dx, int dy);
static void gdk_window_invalidate_in_parent (GdkWindowObject *private);
static void move_native_children (GdkWindowObject *private);
-static void update_cursor (GdkDisplay *display);
+static void update_cursor (GdkDisplay *display,
+ GdkDevice *device);
static void impl_window_add_update_area (GdkWindowObject *impl_window,
GdkRegion *region);
static void gdk_window_region_move_free (GdkWindowRegionMove *move);
@@ -650,10 +652,30 @@ gdk_window_class_init (GdkWindowObjectClass *klass)
}
static void
+device_removed_cb (GdkDeviceManager *device_manager,
+ GdkDevice *device,
+ GdkWindow *window)
+{
+ GdkWindowObject *private;
+
+ private = (GdkWindowObject *) window;
+
+ private->devices_inside = g_list_remove (private->devices_inside, device);
+ g_hash_table_remove (private->device_cursor, device);
+
+ if (private->device_events)
+ g_hash_table_remove (private->device_events, device);
+}
+
+static void
gdk_window_finalize (GObject *object)
{
GdkWindow *window = GDK_WINDOW (object);
GdkWindowObject *obj = (GdkWindowObject *) object;
+ GdkDeviceManager *device_manager;
+
+ device_manager = gdk_display_get_device_manager (gdk_drawable_get_display (GDK_DRAWABLE (window)));
+ g_signal_handlers_disconnect_by_func (device_manager, device_removed_cb, window);
if (!GDK_WINDOW_DESTROYED (window))
{
@@ -690,6 +712,15 @@ gdk_window_finalize (GObject *object)
if (obj->cursor)
gdk_cursor_unref (obj->cursor);
+ if (obj->device_cursor)
+ g_hash_table_destroy (obj->device_cursor);
+
+ if (obj->device_events)
+ g_hash_table_destroy (obj->device_events);
+
+ if (obj->devices_inside)
+ g_list_free (obj->devices_inside);
+
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -1246,12 +1277,20 @@ find_native_sibling_above (GdkWindowObject *parent,
}
static GdkEventMask
-get_native_event_mask (GdkWindowObject *private)
+get_native_device_event_mask (GdkWindowObject *private,
+ GdkDevice *device)
{
+ GdkEventMask event_mask;
+
+ if (device)
+ event_mask = GPOINTER_TO_INT (g_hash_table_lookup (private->device_events, device));
+ else
+ event_mask = private->event_mask;
+
if (_gdk_native_windows ||
private->window_type == GDK_WINDOW_ROOT ||
private->window_type == GDK_WINDOW_FOREIGN)
- return private->event_mask;
+ return event_mask;
else
{
GdkEventMask mask;
@@ -1313,6 +1352,12 @@ get_native_grab_event_mask (GdkEventMask grab_mask)
~GDK_POINTER_MOTION_HINT_MASK);
}
+static GdkEventMask
+get_native_event_mask (GdkWindowObject *private)
+{
+ return get_native_device_event_mask (private, NULL);
+}
+
/* Puts the native window in the right order wrt the other native windows
* in the hierarchy, given the position it has in the client side data.
* This is useful if some operation changed the stacking order.
@@ -1365,6 +1410,7 @@ gdk_window_new (GdkWindow *parent,
gboolean native;
GdkEventMask event_mask;
GdkWindow *real_parent;
+ GdkDeviceManager *device_manager;
g_return_val_if_fail (attributes != NULL, NULL);
@@ -1541,6 +1587,13 @@ gdk_window_new (GdkWindow *parent,
(attributes->cursor) :
NULL));
+ private->device_cursor = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) gdk_cursor_unref);
+
+ device_manager = gdk_display_get_device_manager (gdk_drawable_get_display (GDK_DRAWABLE (parent)));
+ g_signal_connect (device_manager, "device-removed",
+ G_CALLBACK (device_removed_cb), window);
+
return window;
}
@@ -2003,6 +2056,30 @@ window_remove_filters (GdkWindow *window)
}
}
+static void
+update_pointer_info_foreach (GdkDisplay *display,
+ GdkDevice *device,
+ GdkPointerWindowInfo *pointer_info,
+ gpointer user_data)
+{
+ GdkWindow *window = user_data;
+
+ if (pointer_info->toplevel_under_pointer == window)
+ {
+ g_object_unref (pointer_info->toplevel_under_pointer);
+ pointer_info->toplevel_under_pointer = NULL;
+ }
+}
+
+static void
+window_remove_from_pointer_info (GdkWindow *window,
+ GdkDisplay *display)
+{
+ _gdk_display_pointer_info_foreach (display,
+ update_pointer_info_foreach,
+ window);
+}
+
/**
* _gdk_window_destroy_hierarchy:
* @window: a #GdkWindow
@@ -2139,9 +2216,6 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
impl_iface = GDK_WINDOW_IMPL_GET_IFACE (private->impl);
- if (private->extension_events)
- impl_iface->input_window_destroy (window);
-
if (gdk_window_has_impl (private))
impl_iface->destroy (window, recursing_native,
foreign_destroy);
@@ -2165,11 +2239,7 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
private->redirect = NULL;
- if (display->pointer_info.toplevel_under_pointer == window)
- {
- g_object_unref (display->pointer_info.toplevel_under_pointer);
- display->pointer_info.toplevel_under_pointer = NULL;
- }
+ window_remove_from_pointer_info (window, display);
if (private->clip_region)
{
@@ -6377,6 +6447,8 @@ gdk_window_constrain_size (GdkGeometry *geometry,
* Return value: (transfer none): the window containing the pointer (as with
* gdk_window_at_pointer()), or %NULL if the window containing the
* pointer isn't known to GDK
+ *
+ * Deprecated: 3.0. Use gdk_window_get_device_position() instead.
**/
GdkWindow*
gdk_window_get_pointer (GdkWindow *window,
@@ -6385,29 +6457,50 @@ gdk_window_get_pointer (GdkWindow *window,
GdkModifierType *mask)
{
GdkDisplay *display;
- gint tmp_x, tmp_y;
- GdkModifierType tmp_mask;
- GdkWindow *child;
- g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
+ g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
- if (window)
- {
- display = gdk_drawable_get_display (window);
- }
- else
- {
- GdkScreen *screen = gdk_screen_get_default ();
+ display = gdk_drawable_get_display (window);
- display = gdk_screen_get_display (screen);
- window = gdk_screen_get_root_window (screen);
+ return gdk_window_get_device_position (window, display->core_pointer, x, y, mask);
+}
- GDK_NOTE (MULTIHEAD,
- g_message ("Passing NULL for window to gdk_window_get_pointer()\n"
- "is not multihead safe"));
- }
+/**
+ * gdk_window_get_device_position:
+ * @window: a #GdkWindow.
+ * @device: #GdkDevice to query to.
+ * @x: return location for the X coordinate of @device, or %NULL.
+ * @y: return location for the Y coordinate of @device, or %NULL.
+ * @mask: return location for the modifier mask, or %NULL.
+ *
+ * Obtains the current device position and modifier state.
+ * The position is given in coordinates relative to the upper left
+ * corner of @window.
+ *
+ * Returns: The window underneath @device (as with
+ * gdk_display_get_window_at_device_position()), or %NULL if the
+ * window is not known to GDK.
+ *
+ * Since: 3.0
+ **/
+GdkWindow *
+gdk_window_get_device_position (GdkWindow *window,
+ GdkDevice *device,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
+{
+ GdkDisplay *display;
+ gint tmp_x, tmp_y;
+ GdkModifierType tmp_mask;
+ GdkWindow *child;
- child = display->pointer_hooks->window_get_pointer (display, window, &tmp_x, &tmp_y, &tmp_mask);
+ g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
+ g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
+
+ display = gdk_drawable_get_display (window);
+ child = display->device_hooks->window_get_device_position (display, device, window,
+ &tmp_x, &tmp_y, &tmp_mask);
if (x)
*x = tmp_x;
@@ -6416,7 +6509,7 @@ gdk_window_get_pointer (GdkWindow *window,
if (mask)
*mask = tmp_mask;
- _gdk_display_enable_motion_hints (display);
+ _gdk_display_enable_motion_hints (display, device);
return child;
}
@@ -6436,6 +6529,8 @@ gdk_window_get_pointer (GdkWindow *window,
* gdk_display_get_window_at_pointer() instead.
*
* Return value: (transfer none): window under the mouse pointer
+ *
+ * Deprecated: 3.0. Use gdk_display_get_window_at_device_position() instead.
**/
GdkWindow*
gdk_window_at_pointer (gint *win_x,
@@ -7086,30 +7181,31 @@ gdk_window_hide (GdkWindow *window)
else if (was_mapped)
{
GdkDisplay *display;
+ GdkDeviceManager *device_manager;
+ GList *devices, *d;
/* May need to break grabs on children */
display = gdk_drawable_get_display (window);
+ device_manager = gdk_display_get_device_manager (display);
- if (_gdk_display_end_pointer_grab (display,
- _gdk_windowing_window_get_next_serial (display),
- window,
- TRUE))
- gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
+ /* Get all devices */
+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+ devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
+ devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
- if (display->keyboard_grab.window != NULL)
- {
- if (is_parent_of (window, display->keyboard_grab.window))
- {
- /* Call this ourselves, even though gdk_display_keyboard_ungrab
- does so too, since we want to pass implicit == TRUE so the
- broken grab event is generated */
- _gdk_display_unset_has_keyboard_grab (display,
- TRUE);
- gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
- }
- }
+ for (d = devices; d; d = d->next)
+ {
+ GdkDevice *device = d->data;
+
+ if (_gdk_display_end_device_grab (display, device,
+ _gdk_windowing_window_get_next_serial (display),
+ window,
+ TRUE))
+ gdk_device_ungrab (device, GDK_CURRENT_TIME);
+ }
private->state = GDK_WINDOW_STATE_WITHDRAWN;
+ g_list_free (devices);
}
did_hide = _gdk_window_update_viewable (window);
@@ -7191,9 +7287,10 @@ gdk_window_withdraw (GdkWindow *window)
* @event_mask: event mask for @window
*
* The event mask for a window determines which events will be reported
- * for that window. For example, an event mask including #GDK_BUTTON_PRESS_MASK
- * means the window should report button press events. The event mask
- * is the bitwise OR of values from the #GdkEventMask enumeration.
+ * for that window from all master input devices. For example, an event mask
+ * including #GDK_BUTTON_PRESS_MASK means the window should report button
+ * press events. The event mask is the bitwise OR of values from the
+ * #GdkEventMask enumeration.
**/
void
gdk_window_set_events (GdkWindow *window,
@@ -7213,7 +7310,15 @@ gdk_window_set_events (GdkWindow *window,
display = gdk_drawable_get_display (window);
if ((private->event_mask & GDK_POINTER_MOTION_HINT_MASK) &&
!(event_mask & GDK_POINTER_MOTION_HINT_MASK))
- _gdk_display_enable_motion_hints (display);
+ {
+ GList *devices = private->devices_inside;
+
+ while (devices)
+ {
+ _gdk_display_enable_motion_hints (display, (GdkDevice *) devices->data);
+ devices = devices->next;
+ }
+ }
private->event_mask = event_mask;
@@ -7230,7 +7335,8 @@ gdk_window_set_events (GdkWindow *window,
* gdk_window_get_events:
* @window: a #GdkWindow
*
- * Gets the event mask for @window. See gdk_window_set_events().
+ * Gets the event mask for @window for all master input devices. See
+ * gdk_window_set_events().
*
* Return value: event mask for @window
**/
@@ -7248,6 +7354,115 @@ gdk_window_get_events (GdkWindow *window)
return private->event_mask;
}
+/**
+ * gdk_window_set_device_events:
+ * @window: a #GdkWindow
+ * @device: #GdkDevice to enable events for.
+ * @event_mask: event mask for @window
+ *
+ * Sets the event mask for a given device (Normally a floating device, not
+ * attached to any visible pointer) to @window. For example, an event mask
+ * including #GDK_BUTTON_PRESS_MASK means the window should report button
+ * press events. The event mask is the bitwise OR of values from the
+ * #GdkEventMask enumeration.
+ *
+ * Since: 3.0
+ **/
+void
+gdk_window_set_device_events (GdkWindow *window,
+ GdkDevice *device,
+ GdkEventMask event_mask)
+{
+ GdkEventMask device_mask;
+ GdkWindowObject *private;
+ GdkDisplay *display;
+ GdkWindow *native;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+ g_return_if_fail (GDK_IS_DEVICE (device));
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return;
+
+ private = (GdkWindowObject *) window;
+
+ /* If motion hint is disabled, enable motion events again */
+ display = gdk_drawable_get_display (window);
+ if ((private->event_mask & GDK_POINTER_MOTION_HINT_MASK) &&
+ !(event_mask & GDK_POINTER_MOTION_HINT_MASK))
+ _gdk_display_enable_motion_hints (display, device);
+
+ if (G_UNLIKELY (!private->device_events))
+ private->device_events = g_hash_table_new (NULL, NULL);
+
+ if (event_mask == 0)
+ {
+ /* FIXME: unsetting events on a master device
+ * would restore private->event_mask
+ */
+ g_hash_table_remove (private->device_events, device);
+ }
+ else
+ g_hash_table_insert (private->device_events, device,
+ GINT_TO_POINTER (event_mask));
+
+ if (_gdk_native_windows)
+ native = window;
+ else
+ native = gdk_window_get_toplevel (window);
+
+ while (gdk_window_is_offscreen ((GdkWindowObject *)native))
+ {
+ native = gdk_offscreen_window_get_embedder (native);
+
+ if (native == NULL ||
+ (!_gdk_window_has_impl (native) &&
+ !gdk_window_is_viewable (native)))
+ return;
+
+ native = gdk_window_get_toplevel (native);
+ }
+
+ device_mask = get_native_device_event_mask (private, device);
+ GDK_DEVICE_GET_CLASS (device)->select_window_events (device, native, device_mask);
+}
+
+/**
+ * gdk_window_get_device_events:
+ * @window: a #GdkWindow.
+ * @device: a #GdkDevice.
+ *
+ * Returns the event mask for @window corresponding to an specific device.
+ *
+ * Returns: device event mask for @window
+ *
+ * Since: 3.0
+ **/
+GdkEventMask
+gdk_window_get_device_events (GdkWindow *window,
+ GdkDevice *device)
+{
+ GdkWindowObject *private;
+ GdkEventMask mask;
+
+ g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+ g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return 0;
+
+ private = (GdkWindowObject *) window;
+
+ if (!private->device_events)
+ return 0;
+
+ mask = GPOINTER_TO_INT (g_hash_table_lookup (private->device_events, device));
+
+ /* FIXME: device could be controlled by private->event_mask */
+
+ return mask;
+}
+
static void
gdk_window_move_resize_toplevel (GdkWindow *window,
gboolean with_move,
@@ -8023,6 +8238,23 @@ gdk_window_set_back_pixmap (GdkWindow *window,
}
}
+static void
+update_cursor_foreach (GdkDisplay *display,
+ GdkDevice *device,
+ GdkPointerWindowInfo *pointer_info,
+ gpointer user_data)
+{
+ GdkWindow *window = user_data;
+ GdkWindowObject *private = (GdkWindowObject *) window;
+
+ if (_gdk_native_windows ||
+ private->window_type == GDK_WINDOW_ROOT ||
+ private->window_type == GDK_WINDOW_FOREIGN)
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_device_cursor (window, device, private->cursor);
+ else if (_gdk_window_event_parent_of (window, pointer_info->window_under_pointer))
+ update_cursor (display, device);
+}
+
/**
* gdk_window_get_cursor:
* @window: a #GdkWindow
@@ -8055,7 +8287,7 @@ gdk_window_get_cursor (GdkWindow *window)
* @window: a #GdkWindow
* @cursor: a cursor
*
- * Sets the mouse pointer for a #GdkWindow. Use gdk_cursor_new_for_display()
+ * Sets the default mouse pointer for a #GdkWindow. Use gdk_cursor_new_for_display()
* or gdk_cursor_new_from_pixmap() to create the cursor. To make the cursor
* invisible, use %GDK_BLANK_CURSOR. Passing %NULL for the @cursor argument
* to gdk_window_set_cursor() means that @window will use the cursor of its
@@ -8066,7 +8298,6 @@ gdk_window_set_cursor (GdkWindow *window,
GdkCursor *cursor)
{
GdkWindowObject *private;
- GdkWindowImplIface *impl_iface;
GdkDisplay *display;
g_return_if_fail (GDK_IS_WINDOW (window));
@@ -8085,21 +8316,90 @@ gdk_window_set_cursor (GdkWindow *window,
if (cursor)
private->cursor = gdk_cursor_ref (cursor);
- if (_gdk_native_windows ||
- private->window_type == GDK_WINDOW_ROOT ||
- private->window_type == GDK_WINDOW_FOREIGN)
- {
- impl_iface = GDK_WINDOW_IMPL_GET_IFACE (private->impl);
- impl_iface->set_cursor (window, cursor);
- }
- else if (_gdk_window_event_parent_of (window, display->pointer_info.window_under_pointer))
- update_cursor (display);
+ _gdk_display_pointer_info_foreach (display,
+ update_cursor_foreach,
+ window);
g_object_notify (G_OBJECT (window), "cursor");
}
}
/**
+ * gdk_window_get_device_cursor:
+ * @window: a #GdkWindow.
+ * @device: a #GdkDevice.
+ *
+ * Retrieves a #GdkCursor pointer for the @device currently set on the
+ * specified #GdkWindow, or %NULL. If the return value is %NULL then
+ * there is no custom cursor set on the specified window, and it is
+ * using the cursor for its parent window.
+ *
+ * Returns: a #GdkCursor, or %NULL. The returned object is owned
+ * by the #GdkWindow and should not be unreferenced directly. Use
+ * gdk_window_set_cursor() to unset the cursor of the window
+ *
+ * Since: 3.0
+ **/
+GdkCursor *
+gdk_window_get_device_cursor (GdkWindow *window,
+ GdkDevice *device)
+{
+ GdkWindowObject *private;
+
+ g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
+ g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
+
+ private = (GdkWindowObject *) window;
+
+ return g_hash_table_lookup (private->device_cursor, device);
+}
+
+/**
+ * gdk_window_set_device_cursor:
+ * @window: a #Gdkwindow
+ * @device: a #GdkDevice
+ * @cursor: a #GdkCursor
+ *
+ * Sets a specific #GdkCursor for a given device when it gets inside @window.
+ * Use gdk_cursor_new_for_display() or gdk_cursor_new_from_pixmap() to create
+ * the cursor. To make the cursor invisible, use %GDK_BLANK_CURSOR. Passing
+ * %NULL for the @cursor argument to gdk_window_set_cursor() means that
+ * @window will use the cursor of its parent window. Most windows should
+ * use this default.
+ *
+ * Since: 3.0
+ **/
+void
+gdk_window_set_device_cursor (GdkWindow *window,
+ GdkDevice *device,
+ GdkCursor *cursor)
+{
+ GdkWindowObject *private;
+ GdkDisplay *display;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+ g_return_if_fail (GDK_IS_DEVICE (window));
+
+ private = (GdkWindowObject *) window;
+ display = gdk_drawable_get_display (window);
+
+ if (!cursor)
+ g_hash_table_remove (private->device_cursor, device);
+ else
+ g_hash_table_replace (private->device_cursor, device, cursor);
+
+ if (!GDK_WINDOW_DESTROYED (window))
+ {
+ GdkPointerWindowInfo *pointer_info;
+
+ pointer_info = _gdk_display_get_pointer_info (display, device);
+
+ if (_gdk_window_event_parent_of (window, pointer_info->window_under_pointer))
+ update_cursor (display, device);
+ }
+}
+
+/**
* gdk_window_get_geometry:
* @window: a #GdkWindow
* @x: return location for X coordinate of window (relative to its parent)
@@ -9394,27 +9694,34 @@ _gdk_window_event_parent_of (GdkWindow *parent,
}
static void
-update_cursor (GdkDisplay *display)
+update_cursor (GdkDisplay *display,
+ GdkDevice *device)
{
GdkWindowObject *cursor_window, *parent, *toplevel;
GdkWindow *pointer_window;
GdkWindowImplIface *impl_iface;
- GdkPointerGrabInfo *grab;
+ GdkPointerWindowInfo *pointer_info;
+ GdkDeviceGrabInfo *grab;
- pointer_window = display->pointer_info.window_under_pointer;
+ pointer_info = _gdk_display_get_pointer_info (display, device);
+ pointer_window = pointer_info->window_under_pointer;
/* We ignore the serials here and just pick the last grab
we've sent, as that would shortly be used anyway. */
- grab = _gdk_display_get_last_pointer_grab (display);
+ grab = _gdk_display_get_last_device_grab (display, device);
if (/* have grab */
grab != NULL &&
/* the pointer is not in a descendant of the grab window */
!_gdk_window_event_parent_of (grab->window, pointer_window))
- /* use the cursor from the grab window */
- cursor_window = (GdkWindowObject *)grab->window;
+ {
+ /* use the cursor from the grab window */
+ cursor_window = (GdkWindowObject *) grab->window;
+ }
else
- /* otherwise use the cursor from the pointer window */
- cursor_window = (GdkWindowObject *)pointer_window;
+ {
+ /* otherwise use the cursor from the pointer window */
+ cursor_window = (GdkWindowObject *) pointer_window;
+ }
/* Find the first window with the cursor actually set, as
the cursor is inherited from the parent */
@@ -9425,9 +9732,10 @@ update_cursor (GdkDisplay *display)
/* Set all cursors on toplevel, otherwise its tricky to keep track of
* which native window has what cursor set. */
- toplevel = (GdkWindowObject *)get_event_toplevel (pointer_window);
+ toplevel = (GdkWindowObject *) get_event_toplevel (pointer_window);
impl_iface = GDK_WINDOW_IMPL_GET_IFACE (toplevel->impl);
- impl_iface->set_cursor ((GdkWindow *)toplevel, cursor_window->cursor);
+ impl_iface->set_device_cursor ((GdkWindow *) toplevel, device,
+ cursor_window->cursor);
}
static gboolean
@@ -9659,6 +9967,61 @@ gdk_window_beep (GdkWindow *window)
gdk_display_beep (display);
}
+/**
+ * gdk_window_set_support_multidevice:
+ * @window: a #GdkWindow.
+ * @support_multidevice: %TRUE to enable multidevice support in @window.
+ *
+ * This function will enable multidevice features in @window.
+ *
+ * Multidevice aware windows will need to handle properly multiple,
+ * per device enter/leave events, device grabs and grab ownerships.
+ *
+ * Since: 3.0
+ **/
+void
+gdk_window_set_support_multidevice (GdkWindow *window,
+ gboolean support_multidevice)
+{
+ GdkWindowObject *private = (GdkWindowObject *) window;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return;
+
+ if (private->support_multidevice == support_multidevice)
+ return;
+
+ private->support_multidevice = support_multidevice;
+
+ /* FIXME: What to do if called when some pointers are inside the window ? */
+}
+
+/**
+ * gdk_window_get_support_multidevice:
+ * @window: a #GdkWindow.
+ *
+ * Returns %TRUE if the window is aware of the existence of multiple
+ * devices.
+ *
+ * Returns: %TRUE if the window handles multidevice features.
+ *
+ * Since: 3.0
+ **/
+gboolean
+gdk_window_get_support_multidevice (GdkWindow *window)
+{
+ GdkWindowObject *private = (GdkWindowObject *) window;
+
+ g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return FALSE;
+
+ return private->support_multidevice;
+}
+
static const guint type_masks[] = {
GDK_SUBSTRUCTURE_MASK, /* GDK_DELETE = 0 */
GDK_STRUCTURE_MASK, /* GDK_DESTROY = 1 */
@@ -9888,6 +10251,7 @@ send_crossing_event (GdkDisplay *display,
GdkCrossingMode mode,
GdkNotifyType notify_type,
GdkWindow *subwindow,
+ GdkDevice *device,
gint toplevel_x,
gint toplevel_y,
GdkModifierType mask,
@@ -9897,10 +10261,10 @@ send_crossing_event (GdkDisplay *display,
{
GdkEvent *event;
guint32 window_event_mask, type_event_mask;
- GdkPointerGrabInfo *grab;
- GdkWindowImplIface *impl_iface;
+ GdkDeviceGrabInfo *grab;
+ gboolean block_event = FALSE;
- grab = _gdk_display_has_pointer_grab (display, serial);
+ grab = _gdk_display_has_device_grab (display, device, serial);
if (grab != NULL &&
!grab->owner_events)
@@ -9914,20 +10278,39 @@ send_crossing_event (GdkDisplay *display,
window_event_mask = window->event_mask;
if (type == GDK_LEAVE_NOTIFY)
- type_event_mask = GDK_LEAVE_NOTIFY_MASK;
- else
- type_event_mask = GDK_ENTER_NOTIFY_MASK;
+ {
+ type_event_mask = GDK_LEAVE_NOTIFY_MASK;
+ window->devices_inside = g_list_remove (window->devices_inside, device);
- if (window->extension_events != 0)
+ if (!window->support_multidevice && window->devices_inside)
+ {
+ /* Block leave events unless it's the last pointer */
+ block_event = TRUE;
+ }
+ }
+ else
{
- impl_iface = GDK_WINDOW_IMPL_GET_IFACE (window->impl);
- impl_iface->input_window_crossing ((GdkWindow *)window,
- type == GDK_ENTER_NOTIFY);
+ type_event_mask = GDK_ENTER_NOTIFY_MASK;
+
+ if (!window->support_multidevice && window->devices_inside)
+ {
+ /* Only emit enter events for the first device */
+ block_event = TRUE;
+ }
+
+ if (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER &&
+ device->mode != GDK_MODE_DISABLED &&
+ !g_list_find (window->devices_inside, device))
+ window->devices_inside = g_list_prepend (window->devices_inside, device);
}
+ if (block_event)
+ return;
+
if (window_event_mask & type_event_mask)
{
event = _gdk_make_event ((GdkWindow *)window, type, event_in_queue, TRUE);
+ gdk_event_set_device (event, device);
event->crossing.time = time_;
event->crossing.subwindow = subwindow;
if (subwindow)
@@ -9954,6 +10337,7 @@ void
_gdk_synthesize_crossing_events (GdkDisplay *display,
GdkWindow *src,
GdkWindow *dest,
+ GdkDevice *device,
GdkCrossingMode mode,
gint toplevel_x,
gint toplevel_y,
@@ -9978,6 +10362,18 @@ _gdk_synthesize_crossing_events (GdkDisplay *display,
if (a == b)
return; /* No crossings generated between src and dest */
+ if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER)
+ {
+ if (a && gdk_window_get_device_events (src, device) == 0)
+ a = NULL;
+
+ if (b && gdk_window_get_device_events (dest, device) == 0)
+ b = NULL;
+ }
+
+ if (!a && !b)
+ return;
+
c = find_common_ancestor (a, b);
non_linear |= (c != a) && (c != b);
@@ -9997,7 +10393,7 @@ _gdk_synthesize_crossing_events (GdkDisplay *display,
a, GDK_LEAVE_NOTIFY,
mode,
notify_type,
- NULL,
+ NULL, device,
toplevel_x, toplevel_y,
mask, time_,
event_in_queue,
@@ -10019,6 +10415,7 @@ _gdk_synthesize_crossing_events (GdkDisplay *display,
mode,
notify_type,
(GdkWindow *)last,
+ device,
toplevel_x, toplevel_y,
mask, time_,
event_in_queue,
@@ -10065,6 +10462,7 @@ _gdk_synthesize_crossing_events (GdkDisplay *display,
mode,
notify_type,
(GdkWindow *)next,
+ device,
toplevel_x, toplevel_y,
mask, time_,
event_in_queue,
@@ -10086,6 +10484,7 @@ _gdk_synthesize_crossing_events (GdkDisplay *display,
mode,
notify_type,
NULL,
+ device,
toplevel_x, toplevel_y,
mask, time_,
event_in_queue,
@@ -10100,14 +10499,18 @@ _gdk_synthesize_crossing_events (GdkDisplay *display,
static GdkWindow *
get_pointer_window (GdkDisplay *display,
GdkWindow *event_window,
+ GdkDevice *device,
gdouble toplevel_x,
gdouble toplevel_y,
gulong serial)
{
GdkWindow *pointer_window;
- GdkPointerGrabInfo *grab;
+ GdkDeviceGrabInfo *grab;
+ GdkPointerWindowInfo *pointer_info;
+
+ pointer_info = _gdk_display_get_pointer_info (display, device);
- if (event_window == display->pointer_info.toplevel_under_pointer)
+ if (event_window == pointer_info->toplevel_under_pointer)
pointer_window =
_gdk_window_find_descendant_at (event_window,
toplevel_x, toplevel_y,
@@ -10115,7 +10518,7 @@ get_pointer_window (GdkDisplay *display,
else
pointer_window = NULL;
- grab = _gdk_display_has_pointer_grab (display, serial);
+ grab = _gdk_display_has_device_grab (display, device, serial);
if (grab != NULL &&
!grab->owner_events &&
pointer_window != grab->window)
@@ -10126,47 +10529,80 @@ get_pointer_window (GdkDisplay *display,
void
_gdk_display_set_window_under_pointer (GdkDisplay *display,
- GdkWindow *window)
+ GdkDevice *device,
+ GdkWindow *window)
{
+ GdkPointerWindowInfo *device_info;
+
/* We don't track this if all native, and it can cause issues
with the update_cursor call below */
if (_gdk_native_windows)
return;
- if (display->pointer_info.window_under_pointer)
- g_object_unref (display->pointer_info.window_under_pointer);
- display->pointer_info.window_under_pointer = window;
- if (window)
- g_object_ref (window);
+ device_info = _gdk_display_get_pointer_info (display, device);
+
+ if (device_info->window_under_pointer)
+ g_object_unref (device_info->window_under_pointer);
+ device_info->window_under_pointer = window;
if (window)
- update_cursor (display);
+ {
+ g_object_ref (window);
+ update_cursor (display, device);
+ }
- _gdk_display_enable_motion_hints (display);
+ _gdk_display_enable_motion_hints (display, device);
}
-/*
- *--------------------------------------------------------------
- * gdk_pointer_grab
- *
- * Grabs the pointer to a specific window
- *
- * Arguments:
- * "window" is the window which will receive the grab
- * "owner_events" specifies whether events will be reported as is,
- * or relative to "window"
- * "event_mask" masks only interesting events
- * "confine_to" limits the cursor movement to the specified window
- * "cursor" changes the cursor for the duration of the grab
- * "time" specifies the time
- *
- * Results:
- *
- * Side effects:
- * requires a corresponding call to gdk_pointer_ungrab
- *
- *--------------------------------------------------------------
- */
+/**
+ * gdk_pointer_grab:
+ * @window: the #GdkWindow which will own the grab (the grab window).
+ * @owner_events: if %FALSE then all pointer events are reported with respect to
+ * @window and are only reported if selected by @event_mask. If %TRUE then pointer
+ * events for this application are reported as normal, but pointer events outside
+ * this application are reported with respect to @window and only if selected by
+ * @event_mask. In either mode, unreported events are discarded.
+ * @event_mask: specifies the event mask, which is used in accordance with
+ * @owner_events. Note that only pointer events (i.e. button and motion events)
+ * may be selected.
+ * @confine_to: If non-%NULL, the pointer will be confined to this
+ * window during the grab. If the pointer is outside @confine_to, it will
+ * automatically be moved to the closest edge of @confine_to and enter
+ * and leave events will be generated as necessary.
+ * @cursor: the cursor to display while the grab is active. If this is %NULL then
+ * the normal cursors are used for @window and its descendants, and the cursor
+ * for @window is used for all other windows.
+ * @time_: the timestamp of the event which led to this pointer grab. This usually
+ * comes from a #GdkEventButton struct, though %GDK_CURRENT_TIME can be used if
+ * the time isn't known.
+ *
+ * Grabs the pointer (usually a mouse) so that all events are passed to this
+ * application until the pointer is ungrabbed with gdk_pointer_ungrab(), or
+ * the grab window becomes unviewable.
+ * This overrides any previous pointer grab by this client.
+ *
+ * Pointer grabs are used for operations which need complete control over mouse
+ * events, even if the mouse leaves the application.
+ * For example in GTK+ it is used for Drag and Drop, for dragging the handle in
+ * the #GtkHPaned and #GtkVPaned widgets, and for resizing columns in #GtkCList
+ * widgets.
+ *
+ * Note that if the event mask of an X window has selected both button press and
+ * button release events, then a button press event will cause an automatic
+ * pointer grab until the button is released.
+ * X does this automatically since most applications expect to receive button
+ * press and release events in pairs.
+ * It is equivalent to a pointer grab on the window with @owner_events set to
+ * %TRUE.
+ *
+ * If you set up anything at the time you take the grab that needs to be cleaned
+ * up when the grab ends, you should handle the #GdkEventGrabBroken events that
+ * are emitted when the grab ends unvoluntarily.
+ *
+ * Returns: %GDK_GRAB_SUCCESS if the grab was successful.
+ *
+ * Deprecated: 3.0. Use gdk_device_grab() instead.
+ **/
GdkGrabStatus
gdk_pointer_grab (GdkWindow * window,
gboolean owner_events,
@@ -10177,8 +10613,11 @@ gdk_pointer_grab (GdkWindow * window,
{
GdkWindow *native;
GdkDisplay *display;
- GdkGrabStatus res;
+ GdkDeviceManager *device_manager;
+ GdkDevice *device;
+ GdkGrabStatus res = 0;
gulong serial;
+ GList *devices, *dev;
g_return_val_if_fail (window != NULL, 0);
g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
@@ -10218,24 +10657,147 @@ gdk_pointer_grab (GdkWindow * window,
display = gdk_drawable_get_display (window);
serial = _gdk_windowing_window_get_next_serial (display);
+ device_manager = gdk_display_get_device_manager (display);
+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+
+ /* FIXME: Should this be generic to all backends? */
+ /* FIXME: What happens with extended devices? */
+ for (dev = devices; dev; dev = dev->next)
+ {
+ device = dev->data;
+
+ if (device->source != GDK_SOURCE_MOUSE)
+ continue;
+
+ res = _gdk_windowing_device_grab (device,
+ window,
+ native,
+ owner_events,
+ get_native_grab_event_mask (event_mask),
+ confine_to,
+ cursor,
+ time);
+
+ if (res == GDK_GRAB_SUCCESS)
+ _gdk_display_add_device_grab (display,
+ device,
+ window,
+ native,
+ GDK_OWNERSHIP_NONE,
+ owner_events,
+ event_mask,
+ serial,
+ time,
+ FALSE);
+ }
+
+ /* FIXME: handle errors when grabbing */
+
+ g_list_free (devices);
+
+ return res;
+}
+
+/**
+ * gdk_keyboard_grab:
+ * @window: the #GdkWindow which will own the grab (the grab window).
+ * @owner_events: if %FALSE then all keyboard events are reported with respect to
+ * @window. If %TRUE then keyboard events for this application are
+ * reported as normal, but keyboard events outside this application
+ * are reported with respect to @window. Both key press and key
+ * release events are always reported, independant of the event mask
+ * set by the application.
+ * @time: a timestamp from a #GdkEvent, or %GDK_CURRENT_TIME if no timestamp is
+available.
+ *
+ * Grabs the keyboard so that all events are passed to this
+ * application until the keyboard is ungrabbed with gdk_keyboard_ungrab().
+ * This overrides any previous keyboard grab by this client.
+ *
+ * If you set up anything at the time you take the grab that needs to be cleaned
+ * up when the grab ends, you should handle the #GdkEventGrabBroken events that
+ * are emitted when the grab ends unvoluntarily.
+ *
+ * Returns: %GDK_GRAB_SUCCESS if the grab was successful.
+ *
+ * Deprecated: 3.0. Use gdk_device_grab() instead.
+ **/
+GdkGrabStatus
+gdk_keyboard_grab (GdkWindow *window,
+ gboolean owner_events,
+ guint32 time)
+{
+ GdkWindow *native;
+ GdkDisplay *display;
+ GdkDeviceManager *device_manager;
+ GdkDevice *device;
+ GdkGrabStatus res = 0;
+ gulong serial;
+ GList *devices, *dev;
+
+ g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+
+ /* Non-viewable client side window => fail */
+ if (!_gdk_window_has_impl (window) &&
+ !gdk_window_is_viewable (window))
+ return GDK_GRAB_NOT_VIEWABLE;
+
+ if (_gdk_native_windows)
+ native = window;
+ else
+ native = gdk_window_get_toplevel (window);
+
+ while (gdk_window_is_offscreen ((GdkWindowObject *)native))
+ {
+ native = gdk_offscreen_window_get_embedder (native);
+
+ if (native == NULL ||
+ (!_gdk_window_has_impl (native) &&
+ !gdk_window_is_viewable (native)))
+ return GDK_GRAB_NOT_VIEWABLE;
+
+ native = gdk_window_get_toplevel (native);
+ }
+
+ display = gdk_drawable_get_display (window);
+
+ serial = _gdk_windowing_window_get_next_serial (display);
+ device_manager = gdk_display_get_device_manager (display);
+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+
+ /* FIXME: Should this be generic to all backends? */
+ /* FIXME: What happens with extended devices? */
+ for (dev = devices; dev; dev = dev->next)
+ {
+ device = dev->data;
+
+ if (device->source != GDK_SOURCE_KEYBOARD)
+ continue;
- res = _gdk_windowing_pointer_grab (window,
- native,
- owner_events,
- get_native_grab_event_mask (event_mask),
- confine_to,
- cursor,
- time);
-
- if (res == GDK_GRAB_SUCCESS)
- _gdk_display_add_pointer_grab (display,
- window,
- native,
- owner_events,
- event_mask,
- serial,
- time,
- FALSE);
+ res = _gdk_windowing_device_grab (device,
+ window,
+ native,
+ owner_events,
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
+ NULL,
+ NULL,
+ time);
+
+ if (res == GDK_GRAB_SUCCESS)
+ _gdk_display_add_device_grab (display,
+ device,
+ window,
+ native,
+ GDK_OWNERSHIP_NONE,
+ owner_events, 0,
+ serial,
+ time,
+ FALSE);
+ }
+
+ /* FIXME: handle errors when grabbing */
+
+ g_list_free (devices);
return res;
}
@@ -10262,7 +10824,8 @@ do_synthesize_crossing_event (gpointer data)
GdkDisplay *display;
GdkWindow *changed_toplevel;
GdkWindowObject *changed_toplevel_priv;
- GdkWindow *new_window_under_pointer;
+ GHashTableIter iter;
+ gpointer key, value;
gulong serial;
changed_toplevel = data;
@@ -10275,30 +10838,39 @@ do_synthesize_crossing_event (gpointer data)
display = gdk_drawable_get_display (changed_toplevel);
serial = _gdk_windowing_window_get_next_serial (display);
+ g_hash_table_iter_init (&iter, display->pointers_info);
- if (changed_toplevel == display->pointer_info.toplevel_under_pointer)
+ while (g_hash_table_iter_next (&iter, &key, &value))
{
- new_window_under_pointer =
- get_pointer_window (display, changed_toplevel,
- display->pointer_info.toplevel_x,
- display->pointer_info.toplevel_y,
- serial);
- if (new_window_under_pointer !=
- display->pointer_info.window_under_pointer)
- {
- _gdk_synthesize_crossing_events (display,
- display->pointer_info.window_under_pointer,
- new_window_under_pointer,
- GDK_CROSSING_NORMAL,
- display->pointer_info.toplevel_x,
- display->pointer_info.toplevel_y,
- display->pointer_info.state,
- GDK_CURRENT_TIME,
- NULL,
- serial,
- FALSE);
- _gdk_display_set_window_under_pointer (display, new_window_under_pointer);
- }
+ GdkWindow *new_window_under_pointer;
+ GdkPointerWindowInfo *pointer_info = value;
+ GdkDevice *device = key;
+
+ if (changed_toplevel == pointer_info->toplevel_under_pointer)
+ {
+ new_window_under_pointer =
+ get_pointer_window (display, changed_toplevel,
+ device,
+ pointer_info->toplevel_x,
+ pointer_info->toplevel_y,
+ serial);
+ if (new_window_under_pointer != pointer_info->window_under_pointer)
+ {
+ _gdk_synthesize_crossing_events (display,
+ pointer_info->window_under_pointer,
+ new_window_under_pointer,
+ device,
+ GDK_CROSSING_NORMAL,
+ pointer_info->toplevel_x,
+ pointer_info->toplevel_y,
+ pointer_info->state,
+ GDK_CURRENT_TIME,
+ NULL,
+ serial,
+ FALSE);
+ _gdk_display_set_window_under_pointer (display, device, new_window_under_pointer);
+ }
+ }
}
return FALSE;
@@ -10317,12 +10889,12 @@ _gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
display = gdk_drawable_get_display (changed_window);
toplevel = get_event_toplevel (changed_window);
- toplevel_priv = (GdkWindowObject *)toplevel;
+ toplevel_priv = (GdkWindowObject *) toplevel;
- if (toplevel == display->pointer_info.toplevel_under_pointer &&
- !toplevel_priv->synthesize_crossing_event_queued)
+ if (!toplevel_priv->synthesize_crossing_event_queued)
{
toplevel_priv->synthesize_crossing_event_queued = TRUE;
+
g_idle_add_full (GDK_PRIORITY_EVENTS - 1,
do_synthesize_crossing_event,
g_object_ref (toplevel),
@@ -10333,6 +10905,7 @@ _gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
/* Don't use for crossing events */
static GdkWindow *
get_event_window (GdkDisplay *display,
+ GdkDevice *device,
GdkWindow *pointer_window,
GdkEventType type,
GdkModifierType mask,
@@ -10342,9 +10915,9 @@ get_event_window (GdkDisplay *display,
guint evmask;
GdkWindow *grab_window;
GdkWindowObject *w;
- GdkPointerGrabInfo *grab;
+ GdkDeviceGrabInfo *grab;
- grab = _gdk_display_has_pointer_grab (display, serial);
+ grab = _gdk_display_has_device_grab (display, device, serial);
if (grab != NULL && !grab->owner_events)
{
@@ -10405,6 +10978,8 @@ proxy_pointer_event (GdkDisplay *display,
{
GdkWindow *toplevel_window, *event_window;
GdkWindow *pointer_window;
+ GdkPointerWindowInfo *pointer_info;
+ GdkDevice *device;
GdkEvent *event;
guint state;
gdouble toplevel_x, toplevel_y;
@@ -10415,6 +10990,8 @@ proxy_pointer_event (GdkDisplay *display,
gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
gdk_event_get_state (source_event, &state);
time_ = gdk_event_get_time (source_event);
+ device = gdk_event_get_device (source_event);
+ pointer_info = _gdk_display_get_pointer_info (display, device);
toplevel_window = convert_native_coords_to_toplevel (event_window,
toplevel_x, toplevel_y,
&toplevel_x, &toplevel_y);
@@ -10445,8 +11022,9 @@ proxy_pointer_event (GdkDisplay *display,
/* Send leave events from window under pointer to event window
that will get the subwindow == NULL window */
_gdk_synthesize_crossing_events (display,
- display->pointer_info.window_under_pointer,
+ pointer_info->window_under_pointer,
event_window,
+ device,
source_event->crossing.mode,
toplevel_x, toplevel_y,
state, time_,
@@ -10462,16 +11040,17 @@ proxy_pointer_event (GdkDisplay *display,
source_event->crossing.mode,
source_event->crossing.detail,
NULL,
- toplevel_x, toplevel_y,
+ device,
+ toplevel_x, toplevel_y,
state, time_,
source_event,
serial);
- _gdk_display_set_window_under_pointer (display, NULL);
+ _gdk_display_set_window_under_pointer (display, device, NULL);
return TRUE;
}
- pointer_window = get_pointer_window (display, toplevel_window,
+ pointer_window = get_pointer_window (display, toplevel_window, device,
toplevel_x, toplevel_y, serial);
if (((source_event->type == GDK_ENTER_NOTIFY &&
@@ -10491,7 +11070,8 @@ proxy_pointer_event (GdkDisplay *display,
source_event->crossing.mode,
source_event->crossing.detail,
NULL,
- toplevel_x, toplevel_y,
+ device,
+ toplevel_x, toplevel_y,
state, time_,
source_event,
serial);
@@ -10500,30 +11080,32 @@ proxy_pointer_event (GdkDisplay *display,
_gdk_synthesize_crossing_events (display,
event_window,
pointer_window,
+ device,
source_event->crossing.mode,
toplevel_x, toplevel_y,
state, time_,
source_event,
serial, non_linear);
- _gdk_display_set_window_under_pointer (display, pointer_window);
+ _gdk_display_set_window_under_pointer (display, device, pointer_window);
return TRUE;
}
- if (display->pointer_info.window_under_pointer != pointer_window)
+ if (pointer_info->window_under_pointer != pointer_window)
{
/* Either a toplevel crossing notify that ended up inside a child window,
or a motion notify that got into another child window */
/* Different than last time, send crossing events */
_gdk_synthesize_crossing_events (display,
- display->pointer_info.window_under_pointer,
+ pointer_info->window_under_pointer,
pointer_window,
+ device,
GDK_CROSSING_NORMAL,
toplevel_x, toplevel_y,
state, time_,
source_event,
serial, non_linear);
- _gdk_display_set_window_under_pointer (display, pointer_window);
+ _gdk_display_set_window_under_pointer (display, device, pointer_window);
}
else if (source_event->type == GDK_MOTION_NOTIFY)
{
@@ -10532,24 +11114,35 @@ proxy_pointer_event (GdkDisplay *display,
gboolean is_hint;
event_win = get_event_window (display,
- pointer_window,
- source_event->type,
- state,
- &evmask,
- serial);
+ device,
+ pointer_window,
+ source_event->type,
+ state,
+ &evmask,
+ serial);
+
+ if (event_win &&
+ gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER &&
+ gdk_window_get_device_events (event_win, device) == 0)
+ return TRUE;
is_hint = FALSE;
if (event_win &&
(evmask & GDK_POINTER_MOTION_HINT_MASK))
{
- if (display->pointer_info.motion_hint_serial != 0 &&
- serial < display->pointer_info.motion_hint_serial)
+ gulong *device_serial;
+
+ device_serial = g_hash_table_lookup (display->motion_hint_info, device);
+
+ if (!device_serial ||
+ (*device_serial != 0 &&
+ serial < *device_serial))
event_win = NULL; /* Ignore event */
else
{
is_hint = TRUE;
- display->pointer_info.motion_hint_serial = G_MAXULONG;
+ *device_serial = G_MAXULONG;
}
}
@@ -10561,11 +11154,12 @@ proxy_pointer_event (GdkDisplay *display,
toplevel_x, toplevel_y,
&event->motion.x, &event->motion.y);
event->motion.x_root = source_event->motion.x_root;
- event->motion.y_root = source_event->motion.y_root;;
+ event->motion.y_root = source_event->motion.y_root;
event->motion.state = state;
event->motion.is_hint = is_hint;
- event->motion.device = NULL;
event->motion.device = source_event->motion.device;
+ event->motion.axes = g_memdup (source_event->motion.axes,
+ sizeof (gdouble) * source_event->motion.device->num_axes);
}
}
@@ -10595,12 +11189,14 @@ proxy_button_event (GdkEvent *source_event,
gdouble toplevel_x, toplevel_y;
GdkDisplay *display;
GdkWindowObject *w;
+ GdkDevice *device;
type = source_event->any.type;
event_window = source_event->any.window;
gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
gdk_event_get_state (source_event, &state);
time_ = gdk_event_get_time (source_event);
+ device = gdk_event_get_device (source_event);
display = gdk_drawable_get_display (source_event->any.window);
toplevel_window = convert_native_coords_to_toplevel (event_window,
toplevel_x, toplevel_y,
@@ -10608,7 +11204,7 @@ proxy_button_event (GdkEvent *source_event,
if (type == GDK_BUTTON_PRESS &&
!source_event->any.send_event &&
- _gdk_display_has_pointer_grab (display, serial) == NULL)
+ _gdk_display_has_device_grab (display, device, serial) == NULL)
{
pointer_window =
_gdk_window_find_descendant_at (toplevel_window,
@@ -10627,22 +11223,25 @@ proxy_button_event (GdkEvent *source_event,
}
pointer_window = (GdkWindow *)w;
- _gdk_display_add_pointer_grab (display,
- pointer_window,
- toplevel_window,
- FALSE,
- gdk_window_get_events (pointer_window),
- serial,
+ _gdk_display_add_device_grab (display,
+ device,
+ pointer_window,
+ toplevel_window,
+ GDK_OWNERSHIP_NONE,
+ FALSE,
+ gdk_window_get_events (pointer_window),
+ serial,
time_,
- TRUE);
- _gdk_display_pointer_grab_update (display, serial);
+ TRUE);
+ _gdk_display_device_grab_update (display, device, serial);
}
- pointer_window = get_pointer_window (display, toplevel_window,
+ pointer_window = get_pointer_window (display, toplevel_window, device,
toplevel_x, toplevel_y,
serial);
event_win = get_event_window (display,
+ device,
pointer_window,
type, state,
NULL, serial);
@@ -10650,6 +11249,10 @@ proxy_button_event (GdkEvent *source_event,
if (event_win == NULL || display->ignore_core_events)
return TRUE;
+ if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER &&
+ gdk_window_get_device_events (event_win, device) == 0)
+ return TRUE;
+
event = _gdk_make_event (event_win, type, source_event, FALSE);
switch (type)
@@ -10664,6 +11267,8 @@ proxy_button_event (GdkEvent *source_event,
event->button.y_root = source_event->button.y_root;
event->button.state = state;
event->button.device = source_event->button.device;
+ event->button.axes = g_memdup (source_event->button.axes,
+ sizeof (gdouble) * source_event->button.device->num_axes);
if (type == GDK_BUTTON_PRESS)
_gdk_event_button_generate (display, event);
@@ -10762,22 +11367,6 @@ gdk_window_print_tree (GdkWindow *window,
#endif /* DEBUG_WINDOW_PRINTING */
-static gboolean
-is_input_event (GdkDisplay *display,
- GdkEvent *event)
-{
- GdkDevice *core_pointer;
-
- core_pointer = gdk_display_get_core_pointer (display);
- if ((event->type == GDK_MOTION_NOTIFY &&
- event->motion.device != core_pointer) ||
- ((event->type == GDK_BUTTON_PRESS ||
- event->type == GDK_BUTTON_RELEASE) &&
- event->button.device != core_pointer))
- return TRUE;
- return FALSE;
-}
-
void
_gdk_windowing_got_event (GdkDisplay *display,
GList *event_link,
@@ -10789,19 +11378,39 @@ _gdk_windowing_got_event (GdkDisplay *display,
gdouble x, y;
gboolean unlink_event;
guint old_state, old_button;
- GdkPointerGrabInfo *button_release_grab;
+ GdkDeviceGrabInfo *button_release_grab;
+ GdkPointerWindowInfo *pointer_info;
+ GdkDevice *device;
gboolean is_toplevel;
if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
display->last_event_time = gdk_event_get_time (event);
- _gdk_display_pointer_grab_update (display,
- serial);
+ device = gdk_event_get_device (event);
+
+ if (device)
+ {
+ GdkInputMode mode;
+
+ g_object_get (device, "input-mode", &mode, NULL);
+ _gdk_display_device_grab_update (display, device, serial);
+
+ if (mode == GDK_MODE_DISABLED ||
+ !_gdk_display_check_grab_ownership (display, device, serial))
+ {
+ /* Device events are blocked by another
+ * device grab, or the device is disabled
+ */
+ unlink_event = TRUE;
+ goto out;
+ }
+ }
event_window = event->any.window;
if (!event_window)
return;
+ pointer_info = _gdk_display_get_pointer_info (display, device);
event_private = GDK_WINDOW_OBJECT (event_window);
#ifdef DEBUG_WINDOW_PRINTING
@@ -10818,31 +11427,32 @@ _gdk_windowing_got_event (GdkDisplay *display,
{
if (event->type == GDK_BUTTON_PRESS &&
!event->any.send_event &&
- _gdk_display_has_pointer_grab (display, serial) == NULL)
+ _gdk_display_has_device_grab (display, device, serial) == NULL)
{
- _gdk_display_add_pointer_grab (display,
- event_window,
- event_window,
- FALSE,
- gdk_window_get_events (event_window),
- serial,
- gdk_event_get_time (event),
- TRUE);
- _gdk_display_pointer_grab_update (display,
- serial);
+ _gdk_display_add_device_grab (display,
+ device,
+ event_window,
+ event_window,
+ GDK_OWNERSHIP_NONE,
+ FALSE,
+ gdk_window_get_events (event_window),
+ serial,
+ gdk_event_get_time (event),
+ TRUE);
+ _gdk_display_device_grab_update (display, device, serial);
}
if (event->type == GDK_BUTTON_RELEASE &&
!event->any.send_event)
{
button_release_grab =
- _gdk_display_has_pointer_grab (display, serial);
+ _gdk_display_has_device_grab (display, device, serial);
if (button_release_grab &&
button_release_grab->implicit &&
(event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
{
button_release_grab->serial_end = serial;
button_release_grab->implicit_ungrab = FALSE;
- _gdk_display_pointer_grab_update (display, serial);
+ _gdk_display_device_grab_update (display, device, serial);
}
}
@@ -10860,9 +11470,6 @@ _gdk_windowing_got_event (GdkDisplay *display,
return;
}
- if (is_input_event (display, event))
- return;
-
if (!(is_button_type (event->type) ||
is_motion_type (event->type)) ||
event_private->window_type == GDK_WINDOW_ROOT)
@@ -10874,7 +11481,7 @@ _gdk_windowing_got_event (GdkDisplay *display,
event->type == GDK_LEAVE_NOTIFY) &&
(event->crossing.mode == GDK_CROSSING_GRAB ||
event->crossing.mode == GDK_CROSSING_UNGRAB) &&
- (_gdk_display_has_pointer_grab (display, serial) ||
+ (_gdk_display_has_device_grab (display, device, serial) ||
event->crossing.detail == GDK_NOTIFY_INFERIOR))
{
/* We synthesize all crossing events due to grabs ourselves,
@@ -10900,9 +11507,9 @@ _gdk_windowing_got_event (GdkDisplay *display,
event->type == GDK_ENTER_NOTIFY &&
event->crossing.mode == GDK_CROSSING_UNGRAB)
{
- if (display->pointer_info.toplevel_under_pointer)
- g_object_unref (display->pointer_info.toplevel_under_pointer);
- display->pointer_info.toplevel_under_pointer = g_object_ref (event_window);
+ if (pointer_info->toplevel_under_pointer)
+ g_object_unref (pointer_info->toplevel_under_pointer);
+ pointer_info->toplevel_under_pointer = g_object_ref (event_window);
}
unlink_event = TRUE;
@@ -10915,36 +11522,37 @@ _gdk_windowing_got_event (GdkDisplay *display,
if (event->type == GDK_ENTER_NOTIFY &&
event->crossing.detail != GDK_NOTIFY_INFERIOR)
{
- if (display->pointer_info.toplevel_under_pointer)
- g_object_unref (display->pointer_info.toplevel_under_pointer);
- display->pointer_info.toplevel_under_pointer = g_object_ref (event_window);
+ if (pointer_info->toplevel_under_pointer)
+ g_object_unref (pointer_info->toplevel_under_pointer);
+ pointer_info->toplevel_under_pointer = g_object_ref (event_window);
}
else if (event->type == GDK_LEAVE_NOTIFY &&
event->crossing.detail != GDK_NOTIFY_INFERIOR &&
- display->pointer_info.toplevel_under_pointer == event_window)
+ pointer_info->toplevel_under_pointer == event_window)
{
- if (display->pointer_info.toplevel_under_pointer)
- g_object_unref (display->pointer_info.toplevel_under_pointer);
- display->pointer_info.toplevel_under_pointer = NULL;
+ if (pointer_info->toplevel_under_pointer)
+ g_object_unref (pointer_info->toplevel_under_pointer);
+ pointer_info->toplevel_under_pointer = NULL;
}
}
/* Store last pointer window and position/state */
- old_state = display->pointer_info.state;
- old_button = display->pointer_info.button;
+ old_state = pointer_info->state;
+ old_button = pointer_info->button;
gdk_event_get_coords (event, &x, &y);
convert_native_coords_to_toplevel (event_window, x, y, &x, &y);
- display->pointer_info.toplevel_x = x;
- display->pointer_info.toplevel_y = y;
- gdk_event_get_state (event, &display->pointer_info.state);
+ pointer_info->toplevel_x = x;
+ pointer_info->toplevel_y = y;
+ gdk_event_get_state (event, &pointer_info->state);
if (event->type == GDK_BUTTON_PRESS ||
event->type == GDK_BUTTON_RELEASE)
- display->pointer_info.button = event->button.button;
+ pointer_info->button = event->button.button;
- if (display->pointer_info.state != old_state ||
- display->pointer_info.button != old_button)
- _gdk_display_enable_motion_hints (display);
+ if (device &&
+ (pointer_info->state != old_state ||
+ pointer_info->button != old_button))
+ _gdk_display_enable_motion_hints (display, device);
unlink_event = FALSE;
if (is_motion_type (event->type))
@@ -10959,14 +11567,14 @@ _gdk_windowing_got_event (GdkDisplay *display,
!event->any.send_event)
{
button_release_grab =
- _gdk_display_has_pointer_grab (display, serial);
+ _gdk_display_has_device_grab (display, device, serial);
if (button_release_grab &&
button_release_grab->implicit &&
(event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
{
button_release_grab->serial_end = serial;
button_release_grab->implicit_ungrab = FALSE;
- _gdk_display_pointer_grab_update (display, serial);
+ _gdk_display_device_grab_update (display, device, serial);
}
}
@@ -10989,9 +11597,10 @@ get_extension_event_window (GdkDisplay *display,
guint evmask;
GdkWindow *grab_window;
GdkWindowObject *w;
- GdkPointerGrabInfo *grab;
+ GdkDeviceGrabInfo *grab;
- grab = _gdk_display_has_pointer_grab (display, serial);
+ /* FIXME: which device? */
+ grab = _gdk_display_has_device_grab (display, display->core_pointer, serial);
if (grab != NULL && !grab->owner_events)
{
@@ -11050,7 +11659,8 @@ _gdk_window_get_input_window_for_event (GdkWindow *native_window,
toplevel_window = convert_native_coords_to_toplevel (native_window,
toplevel_x, toplevel_y,
&toplevel_x, &toplevel_y);
- pointer_window = get_pointer_window (display, toplevel_window,
+ /* FIXME: which device? */
+ pointer_window = get_pointer_window (display, toplevel_window, NULL,
toplevel_x, toplevel_y, serial);
event_win = get_extension_event_window (display,
pointer_window,
diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h
index 0bd254a207..640f6af3f4 100644
--- a/gdk/gdkwindow.h
+++ b/gdk/gdkwindow.h
@@ -543,6 +543,7 @@ struct _GdkWindowObject
guint GSEAL (accept_focus) : 1;
guint GSEAL (focus_on_map) : 1;
guint GSEAL (shaped) : 1;
+ guint GSEAL (support_multidevice) : 1;
GdkEventMask GSEAL (event_mask);
@@ -567,8 +568,11 @@ GdkWindow* gdk_window_new (GdkWindow *parent,
void gdk_window_destroy (GdkWindow *window);
GdkWindowType gdk_window_get_window_type (GdkWindow *window);
gboolean gdk_window_is_destroyed (GdkWindow *window);
+
+#ifndef GDK_MULTIDEVICE_SAFE
GdkWindow* gdk_window_at_pointer (gint *win_x,
gint *win_y);
+#endif /* GDK_MULTIDEVICE_SAFE */
void gdk_window_show (GdkWindow *window);
void gdk_window_hide (GdkWindow *window);
void gdk_window_withdraw (GdkWindow *window);
@@ -760,6 +764,11 @@ void gdk_window_set_back_pixmap (GdkWindow *window,
void gdk_window_set_cursor (GdkWindow *window,
GdkCursor *cursor);
GdkCursor *gdk_window_get_cursor (GdkWindow *window);
+void gdk_window_set_device_cursor (GdkWindow *window,
+ GdkDevice *device,
+ GdkCursor *cursor);
+GdkCursor *gdk_window_get_device_cursor (GdkWindow *window,
+ GdkDevice *device);
void gdk_window_get_user_data (GdkWindow *window,
gpointer *data);
void gdk_window_get_geometry (GdkWindow *window,
@@ -802,10 +811,18 @@ void gdk_window_get_root_origin (GdkWindow *window,
gint *y);
void gdk_window_get_frame_extents (GdkWindow *window,
GdkRectangle *rect);
+
+#ifndef GDK_MULTIDEVICE_SAFE
GdkWindow* gdk_window_get_pointer (GdkWindow *window,
gint *x,
gint *y,
GdkModifierType *mask);
+#endif /* GDK_MULTIDEVICE_SAFE */
+GdkWindow * gdk_window_get_device_position (GdkWindow *window,
+ GdkDevice *device,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask);
GdkWindow * gdk_window_get_parent (GdkWindow *window);
GdkWindow * gdk_window_get_toplevel (GdkWindow *window);
@@ -817,6 +834,11 @@ GList * gdk_window_peek_children (GdkWindow *window);
GdkEventMask gdk_window_get_events (GdkWindow *window);
void gdk_window_set_events (GdkWindow *window,
GdkEventMask event_mask);
+void gdk_window_set_device_events (GdkWindow *window,
+ GdkDevice *device,
+ GdkEventMask event_mask);
+GdkEventMask gdk_window_get_device_events (GdkWindow *window,
+ GdkDevice *device);
void gdk_window_set_icon_list (GdkWindow *window,
GList *pixbufs);
@@ -906,9 +928,9 @@ void gdk_window_get_internal_paint_info (GdkWindow *window,
void gdk_window_enable_synchronized_configure (GdkWindow *window);
void gdk_window_configure_finished (GdkWindow *window);
-#ifndef GDK_MULTIHEAD_SAFE
-GdkPointerHooks *gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks);
-#endif /* GDK_MULTIHEAD_SAFE */
+#if !defined (GDK_MULTIHEAD_SAFE) && !defined (GDK_MULTIDEVICE_SAFE)
+GdkPointerHooks *gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks);
+#endif /* !GDK_MULTIHEAD_SAFE && !GDK_MULTIDEVICE_SAFE */
GdkWindow *gdk_get_default_root_window (void);
@@ -929,6 +951,10 @@ void gdk_window_redirect_to_drawable (GdkWindow *window,
gint height);
void gdk_window_remove_redirection (GdkWindow *window);
+/* Multidevice support */
+void gdk_window_set_support_multidevice (GdkWindow *window,
+ gboolean support_multidevice);
+gboolean gdk_window_get_support_multidevice (GdkWindow *window);
G_END_DECLS
diff --git a/gdk/gdkwindowimpl.h b/gdk/gdkwindowimpl.h
index 3a5029b016..dc0ca75e93 100644
--- a/gdk/gdkwindowimpl.h
+++ b/gdk/gdkwindowimpl.h
@@ -77,8 +77,9 @@ struct _GdkWindowImplIface
void (* clear_region) (GdkWindow *window,
GdkRegion *region,
gboolean send_expose);
-
- void (* set_cursor) (GdkWindow *window,
+
+ void (* set_device_cursor) (GdkWindow *window,
+ GdkDevice *device,
GdkCursor *cursor);
void (* get_geometry) (GdkWindow *window,
@@ -95,10 +96,11 @@ struct _GdkWindowImplIface
gint (* get_deskrelative_origin) (GdkWindow *window,
gint *x,
gint *y);
- gboolean (* get_pointer) (GdkWindow *window,
+ gboolean (* get_device_state) (GdkWindow *window,
+ GdkDevice *device,
gint *x,
gint *y,
- GdkModifierType *mask);
+ GdkModifierType *mask);
void (* shape_combine_region) (GdkWindow *window,
const GdkRegion *shape_region,
@@ -142,10 +144,6 @@ struct _GdkWindowImplIface
void (* destroy) (GdkWindow *window,
gboolean recursing,
gboolean foreign_destroy);
-
- void (* input_window_destroy) (GdkWindow *window);
- void (* input_window_crossing)(GdkWindow *window,
- gboolean enter);
gboolean supports_native_bg;
};
diff --git a/gdk/quartz/Makefile.am b/gdk/quartz/Makefile.am
index a5721b1c3e..ac6c2c743b 100644
--- a/gdk/quartz/Makefile.am
+++ b/gdk/quartz/Makefile.am
@@ -24,6 +24,8 @@ libgdk_quartz_la_SOURCES = \
gdkapplaunchcontext-quartz.c \
gdkcolor-quartz.c \
gdkcursor-quartz.c \
+ gdkdevice-core.c \
+ gdkdevicemanager-core.c \
gdkdisplay-quartz.c \
gdkdnd-quartz.c \
gdkdrawable-quartz.c \
diff --git a/gdk/quartz/gdkdevice-core.c b/gdk/quartz/gdkdevice-core.c
new file mode 100644
index 0000000000..81cd6a3447
--- /dev/null
+++ b/gdk/quartz/gdkdevice-core.c
@@ -0,0 +1,356 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ * Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+
+#import "GdkQuartzView.h"
+#include "gdkwindow-quartz.h"
+#include "gdkprivate-quartz.h"
+#include "gdkdevice-core.h"
+
+static gboolean gdk_device_core_get_history (GdkDevice *device,
+ GdkWindow *window,
+ guint32 start,
+ guint32 stop,
+ GdkTimeCoord ***events,
+ guint *n_events);
+static void gdk_device_core_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask);
+static void gdk_device_core_set_window_cursor (GdkDevice *device,
+ GdkWindow *window,
+ GdkCursor *cursor);
+static void gdk_device_core_warp (GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y);
+static gboolean gdk_device_core_query_state (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow **root_window,
+ GdkWindow **child_window,
+ gint *root_x,
+ gint *root_y,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask);
+static GdkGrabStatus gdk_device_core_grab (GdkDevice *device,
+ GdkWindow *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time_);
+static void gdk_device_core_ungrab (GdkDevice *device,
+ guint32 time_);
+static GdkWindow * gdk_device_core_window_at_position (GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel);
+static void gdk_device_core_select_window_events (GdkDevice *device,
+ GdkWindow *window,
+ GdkEventMask event_mask);
+
+
+G_DEFINE_TYPE (GdkDeviceCore, gdk_device_core, GDK_TYPE_DEVICE)
+
+static void
+gdk_device_core_class_init (GdkDeviceCoreClass *klass)
+{
+ GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
+
+ device_class->get_history = gdk_device_core_get_history;
+ device_class->get_state = gdk_device_core_get_state;
+ device_class->set_window_cursor = gdk_device_core_set_window_cursor;
+ device_class->warp = gdk_device_core_warp;
+ device_class->query_state = gdk_device_core_query_state;
+ device_class->grab = gdk_device_core_grab;
+ device_class->ungrab = gdk_device_core_ungrab;
+ device_class->window_at_position = gdk_device_core_window_at_position;
+ device_class->select_window_events = gdk_device_core_select_window_events;
+}
+
+static void
+gdk_device_core_init (GdkDeviceCore *device_core)
+{
+ GdkDevice *device;
+
+ device = GDK_DEVICE (device_core);
+
+ _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_X, 0, 0, 1);
+ _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_Y, 0, 0, 1);
+}
+
+static gboolean
+gdk_device_core_get_history (GdkDevice *device,
+ GdkWindow *window,
+ guint32 start,
+ guint32 stop,
+ GdkTimeCoord ***events,
+ guint *n_events)
+{
+ return FALSE;
+}
+
+static void
+gdk_device_core_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask)
+{
+ gint x_int, y_int;
+
+ gdk_window_get_pointer (window, &x_int, &y_int, mask);
+
+ if (axes)
+ {
+ axes[0] = x_int;
+ axes[1] = y_int;
+ }
+}
+
+static void
+translate_coords_to_child_coords (GdkWindow *parent,
+ GdkWindow *child,
+ gint *x,
+ gint *y)
+{
+ GdkWindow *current = child;
+
+ if (child == parent)
+ return;
+
+ while (current != parent)
+ {
+ gint tmp_x, tmp_y;
+
+ gdk_window_get_origin (current, &tmp_x, &tmp_y);
+
+ *x -= tmp_x;
+ *y -= tmp_y;
+
+ current = gdk_window_get_parent (current);
+ }
+}
+
+static void
+gdk_device_core_set_window_cursor (GdkDevice *device,
+ GdkWindow *window,
+ GdkCursor *cursor)
+{
+ GdkCursorPrivate *cursor_private;
+ NSCursor *nscursor;
+
+ cursor_private = (GdkCursorPrivate*) cursor;
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return;
+
+ if (!cursor)
+ nscursor = [NSCursor arrowCursor];
+ else
+ nscursor = cursor_private->nscursor;
+
+ [nscursor set];
+}
+
+static void
+gdk_device_core_warp (GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y)
+{
+ CGDisplayMoveCursorToPoint (CGMainDisplayID (), CGPointMake (x, y));
+}
+
+static GdkWindow *
+gdk_device_core_query_state_helper (GdkWindow *window,
+ GdkDevice *device,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
+{
+ GdkWindowObject *toplevel;
+ GdkWindowObject *private;
+ NSPoint point;
+ gint x_tmp, y_tmp;
+ GdkWindow *found_window;
+
+ g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
+
+ if (GDK_WINDOW_DESTROYED (window))
+ {
+ *x = 0;
+ *y = 0;
+ *mask = 0;
+ return NULL;
+ }
+
+ toplevel = GDK_WINDOW_OBJECT (gdk_window_get_toplevel (window));
+
+ *mask = _gdk_quartz_events_get_current_event_mask ();
+
+ /* Get the y coordinate, needs to be flipped. */
+ if (window == _gdk_root)
+ {
+ point = [NSEvent mouseLocation];
+ _gdk_quartz_window_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
+ }
+ else
+ {
+ GdkWindowImplQuartz *impl;
+ NSWindow *nswindow;
+
+ impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
+ private = GDK_WINDOW_OBJECT (toplevel);
+ nswindow = impl->toplevel;
+
+ point = [nswindow mouseLocationOutsideOfEventStream];
+
+ x_tmp = point.x;
+ y_tmp = private->height - point.y;
+
+ window = (GdkWindow *)toplevel;
+ }
+
+ found_window = _gdk_quartz_window_find_child (window, x_tmp, y_tmp,
+ FALSE);
+
+ if (found_window == _gdk_root)
+ found_window = NULL;
+ else if (found_window)
+ translate_coords_to_child_coords (window, found_window,
+ &x_tmp, &y_tmp);
+
+ *x = x_tmp;
+ *y = y_tmp;
+
+ return found_window;
+}
+
+static gboolean
+gdk_device_core_query_state (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow **root_window,
+ GdkWindow **child_window,
+ gint *root_x,
+ gint *root_y,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask)
+{
+ GdkDisplay *display;
+ GdkWindow *found_window;
+ NSPoint point;
+ gint x_tmp, y_tmp;
+
+ found_window = gdk_device_core_query_state_helper (window, device,
+ win_x, win_y,
+ mask);
+ if (!found_window)
+ return FALSE;
+
+ display = gdk_drawable_get_display (window);
+
+ if (root_window)
+ *root_window = _gdk_root;
+
+ if (child_window)
+ *child_window = found_window;
+
+ point = [NSEvent mouseLocation];
+ _gdk_quartz_window_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
+
+ if (root_x)
+ *root_x = x_tmp;
+
+ if (root_y)
+ *root_y = y_tmp;
+
+ return TRUE;
+}
+
+static GdkGrabStatus
+gdk_device_core_grab (GdkDevice *device,
+ GdkWindow *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time_)
+{
+ /* Should remain empty */
+ return GDK_GRAB_SUCCESS;
+}
+
+static void
+gdk_device_core_ungrab (GdkDevice *device,
+ guint32 time_)
+{
+ /* Should remain empty */
+}
+
+static GdkWindow *
+gdk_device_core_window_at_position (GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel)
+{
+ GdkDisplay *display;
+ GdkScreen *screen;
+ GdkWindow *found_window;
+ NSPoint point;
+ gint x_tmp, y_tmp;
+
+ display = gdk_device_get_display (device);
+ screen = gdk_display_get_default_screen (display);
+
+ /* Get mouse coordinates, find window under the mouse pointer */
+ point = [NSEvent mouseLocation];
+ _gdk_quartz_window_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
+
+ found_window = _gdk_quartz_window_find_child (_gdk_root, x_tmp, y_tmp,
+ get_toplevel);
+
+ if (found_window)
+ translate_coords_to_child_coords (_gdk_root, found_window,
+ &x_tmp, &y_tmp);
+
+ if (win_x)
+ *win_x = found_window ? x_tmp : -1;
+
+ if (win_y)
+ *win_y = found_window ? y_tmp : -1;
+
+ if (mask)
+ *mask = _gdk_quartz_events_get_current_event_mask ();
+
+ return found_window;
+}
+
+static void
+gdk_device_core_select_window_events (GdkDevice *device,
+ GdkWindow *window,
+ GdkEventMask event_mask)
+{
+ /* The mask is set in the common code. */
+}
diff --git a/gdk/quartz/gdkdevice-core.h b/gdk/quartz/gdkdevice-core.h
new file mode 100644
index 0000000000..8f53d6fad8
--- /dev/null
+++ b/gdk/quartz/gdkdevice-core.h
@@ -0,0 +1,51 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GDK_DEVICE_CORE_H__
+#define __GDK_DEVICE_CORE_H__
+
+#include <gdk/gdkdeviceprivate.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_CORE (gdk_device_core_get_type ())
+#define GDK_DEVICE_CORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_CORE, GdkDeviceCore))
+#define GDK_DEVICE_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_CORE, GdkDeviceCoreClass))
+#define GDK_IS_DEVICE_CORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_CORE))
+#define GDK_IS_DEVICE_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_CORE))
+#define GDK_DEVICE_CORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_CORE, GdkDeviceCoreClass))
+
+typedef struct _GdkDeviceCore GdkDeviceCore;
+typedef struct _GdkDeviceCoreClass GdkDeviceCoreClass;
+
+struct _GdkDeviceCore
+{
+ GdkDevice parent_instance;
+};
+
+struct _GdkDeviceCoreClass
+{
+ GdkDeviceClass parent_class;
+};
+
+GType gdk_device_core_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_CORE_H__ */
diff --git a/gdk/quartz/gdkdevicemanager-core.c b/gdk/quartz/gdkdevicemanager-core.c
new file mode 100644
index 0000000000..d4765c1335
--- /dev/null
+++ b/gdk/quartz/gdkdevicemanager-core.c
@@ -0,0 +1,130 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+
+#include <gdk/gdktypes.h>
+#include <gdk/gdkdevicemanager.h>
+#include "gdkdevicemanager-core.h"
+#include "gdkdevice-core.h"
+#include "gdkkeysyms.h"
+
+
+#define HAS_FOCUS(toplevel) \
+ ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
+
+static void gdk_device_manager_core_finalize (GObject *object);
+static void gdk_device_manager_core_constructed (GObject *object);
+
+static GList * gdk_device_manager_core_list_devices (GdkDeviceManager *device_manager,
+ GdkDeviceType type);
+
+
+G_DEFINE_TYPE (GdkDeviceManagerCore, gdk_device_manager_core, GDK_TYPE_DEVICE_MANAGER)
+
+static void
+gdk_device_manager_core_class_init (GdkDeviceManagerCoreClass *klass)
+{
+ GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gdk_device_manager_core_finalize;
+ object_class->constructed = gdk_device_manager_core_constructed;
+ device_manager_class->list_devices = gdk_device_manager_core_list_devices;
+}
+
+static GdkDevice *
+create_core_pointer (GdkDeviceManager *device_manager,
+ GdkDisplay *display)
+{
+ return g_object_new (GDK_TYPE_DEVICE_CORE,
+ "name", "Core Pointer",
+ "type", GDK_DEVICE_TYPE_MASTER,
+ "input-source", GDK_SOURCE_MOUSE,
+ "input-mode", GDK_MODE_SCREEN,
+ "has-cursor", TRUE,
+ "display", display,
+ "device-manager", device_manager,
+ NULL);
+}
+
+static GdkDevice *
+create_core_keyboard (GdkDeviceManager *device_manager,
+ GdkDisplay *display)
+{
+ return g_object_new (GDK_TYPE_DEVICE_CORE,
+ "name", "Core Keyboard",
+ "type", GDK_DEVICE_TYPE_MASTER,
+ "input-source", GDK_SOURCE_KEYBOARD,
+ "input-mode", GDK_MODE_SCREEN,
+ "has-cursor", FALSE,
+ "display", display,
+ "device-manager", device_manager,
+ NULL);
+}
+
+static void
+gdk_device_manager_core_init (GdkDeviceManagerCore *device_manager)
+{
+}
+
+static void
+gdk_device_manager_core_finalize (GObject *object)
+{
+ GdkDeviceManagerCore *device_manager_core;
+
+ device_manager_core = GDK_DEVICE_MANAGER_CORE (object);
+
+ g_object_unref (device_manager_core->core_pointer);
+ g_object_unref (device_manager_core->core_keyboard);
+
+ G_OBJECT_CLASS (gdk_device_manager_core_parent_class)->finalize (object);
+}
+
+static void
+gdk_device_manager_core_constructed (GObject *object)
+{
+ GdkDeviceManagerCore *device_manager;
+ GdkDisplay *display;
+
+ device_manager = GDK_DEVICE_MANAGER_CORE (object);
+ display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
+ device_manager->core_pointer = create_core_pointer (GDK_DEVICE_MANAGER (device_manager), display);
+ device_manager->core_keyboard = create_core_keyboard (GDK_DEVICE_MANAGER (device_manager), display);
+
+ _gdk_device_set_associated_device (device_manager->core_pointer, device_manager->core_keyboard);
+ _gdk_device_set_associated_device (device_manager->core_keyboard, device_manager->core_pointer);
+}
+
+static GList *
+gdk_device_manager_core_list_devices (GdkDeviceManager *device_manager,
+ GdkDeviceType type)
+{
+ GdkDeviceManagerCore *device_manager_core;
+ GList *devices = NULL;
+
+ if (type == GDK_DEVICE_TYPE_MASTER)
+ {
+ device_manager_core = (GdkDeviceManagerCore *) device_manager;
+ devices = g_list_prepend (devices, device_manager_core->core_keyboard);
+ devices = g_list_prepend (devices, device_manager_core->core_pointer);
+ }
+
+ return devices;
+}
diff --git a/gdk/quartz/gdkdevicemanager-core.h b/gdk/quartz/gdkdevicemanager-core.h
new file mode 100644
index 0000000000..0a337fcd00
--- /dev/null
+++ b/gdk/quartz/gdkdevicemanager-core.h
@@ -0,0 +1,54 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GDK_DEVICE_MANAGER_CORE_H__
+#define __GDK_DEVICE_MANAGER_CORE_H__
+
+#include <gdk/gdkdevicemanager.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_MANAGER_CORE (gdk_device_manager_core_get_type ())
+#define GDK_DEVICE_MANAGER_CORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_MANAGER_CORE, GdkDeviceManagerCore))
+#define GDK_DEVICE_MANAGER_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_MANAGER_CORE, GdkDeviceManagerCoreClass))
+#define GDK_IS_DEVICE_MANAGER_CORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_MANAGER_CORE))
+#define GDK_IS_DEVICE_MANAGER_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_MANAGER_CORE))
+#define GDK_DEVICE_MANAGER_CORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_MANAGER_CORE, GdkDeviceManagerCoreClass))
+
+typedef struct _GdkDeviceManagerCore GdkDeviceManagerCore;
+typedef struct _GdkDeviceManagerCoreClass GdkDeviceManagerCoreClass;
+
+struct _GdkDeviceManagerCore
+{
+ GdkDeviceManager parent_object;
+ GdkDevice *core_pointer;
+ GdkDevice *core_keyboard;
+};
+
+struct _GdkDeviceManagerCoreClass
+{
+ GdkDeviceManagerClass parent_class;
+};
+
+GType gdk_device_manager_core_get_type (void) G_GNUC_CONST;
+
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_MANAGER_CORE_H__ */
diff --git a/gdk/quartz/gdkdisplay-quartz.c b/gdk/quartz/gdkdisplay-quartz.c
index 5de6519207..556f84eee5 100644
--- a/gdk/quartz/gdkdisplay-quartz.c
+++ b/gdk/quartz/gdkdisplay-quartz.c
@@ -23,6 +23,7 @@
#include "gdk.h"
#include "gdkprivate-quartz.h"
#include "gdkscreen-quartz.h"
+#include "gdkdevicemanager-core.h"
GdkWindow *
gdk_display_get_default_group (GdkDisplay *display)
@@ -40,6 +41,14 @@ _gdk_windowing_set_default_display (GdkDisplay *display)
g_assert (display == NULL || _gdk_display == display);
}
+GdkDeviceManager *
+_gdk_device_manager_new (GdkDisplay *display)
+{
+ return g_object_new (GDK_TYPE_DEVICE_MANAGER_CORE,
+ "display", display,
+ NULL);
+}
+
GdkDisplay *
gdk_display_open (const gchar *display_name)
{
@@ -50,6 +59,7 @@ gdk_display_open (const gchar *display_name)
[NSApplication sharedApplication];
_gdk_display = g_object_new (GDK_TYPE_DISPLAY, NULL);
+ _gdk_display->device_manager = _gdk_device_manager_new (_gdk_display);
_gdk_visual_init ();
@@ -58,6 +68,7 @@ gdk_display_open (const gchar *display_name)
_gdk_windowing_window_init ();
_gdk_events_init ();
+
_gdk_input_init ();
#if 0
diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
index 24b9dd578e..5a7180d3ed 100644
--- a/gdk/quartz/gdkevents-quartz.c
+++ b/gdk/quartz/gdkevents-quartz.c
@@ -32,6 +32,7 @@
#include "gdkscreen.h"
#include "gdkkeysyms.h"
#include "gdkprivate-quartz.h"
+#include "gdkdevicemanager-core.h"
#define GRIP_WIDTH 15
#define GRIP_HEIGHT 15
@@ -68,70 +69,52 @@ gdk_events_pending (void)
(_gdk_quartz_event_loop_check_pending ()));
}
-GdkGrabStatus
-gdk_keyboard_grab (GdkWindow *window,
- gint owner_events,
- guint32 time)
+GdkEvent*
+gdk_event_get_graphics_expose (GdkWindow *window)
{
- GdkDisplay *display;
- GdkWindow *toplevel;
-
- g_return_val_if_fail (window != NULL, 0);
- g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
-
- display = gdk_drawable_get_display (window);
- toplevel = gdk_window_get_toplevel (window);
-
- _gdk_display_set_has_keyboard_grab (display,
- window,
- toplevel,
- owner_events,
- 0,
- time);
-
- return GDK_GRAB_SUCCESS;
-}
-
-void
-gdk_display_keyboard_ungrab (GdkDisplay *display,
- guint32 time)
-{
- _gdk_display_unset_has_keyboard_grab (display, FALSE);
+ /* FIXME: Implement */
+ return NULL;
}
void
-gdk_display_pointer_ungrab (GdkDisplay *display,
- guint32 time)
+gdk_device_ungrab (GdkDevice *device,
+ guint32 time_)
{
- GdkPointerGrabInfo *grab;
+ GdkDeviceGrabInfo *grab;
- grab = _gdk_display_get_last_pointer_grab (display);
+ grab = _gdk_display_get_last_device_grab (_gdk_display, device);
if (grab)
grab->serial_end = 0;
- _gdk_display_pointer_grab_update (display, 0);
+ _gdk_display_device_grab_update (_gdk_display, device, 0);
}
GdkGrabStatus
-_gdk_windowing_pointer_grab (GdkWindow *window,
- GdkWindow *native,
- gboolean owner_events,
- GdkEventMask event_mask,
- GdkWindow *confine_to,
- GdkCursor *cursor,
- guint32 time)
+_gdk_windowing_device_grab (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow *native,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time)
{
g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
- _gdk_display_add_pointer_grab (_gdk_display,
- window,
- native,
- owner_events,
- event_mask,
- 0,
- time,
- FALSE);
+ if (!window || GDK_WINDOW_DESTROYED (window))
+ return GDK_GRAB_NOT_VIEWABLE;
+
+ _gdk_display_add_device_grab (_gdk_display,
+ device,
+ window,
+ native,
+ GDK_OWNERSHIP_NONE,
+ owner_events,
+ event_mask,
+ 0,
+ time,
+ FALSE);
return GDK_GRAB_SUCCESS;
}
@@ -139,19 +122,27 @@ _gdk_windowing_pointer_grab (GdkWindow *window,
static void
break_all_grabs (guint32 time)
{
- GdkPointerGrabInfo *grab;
+ GList *list, *l;
+ GdkDeviceManager *device_manager;
- if (_gdk_display->keyboard_grab.window)
- _gdk_display_unset_has_keyboard_grab (_gdk_display, FALSE);
-
- grab = _gdk_display_get_last_pointer_grab (_gdk_display);
- if (grab)
+ device_manager = gdk_display_get_device_manager (_gdk_display);
+ list = gdk_device_manager_list_devices (device_manager,
+ GDK_DEVICE_TYPE_MASTER);
+ for (l = list; l; l = l->next)
{
- grab->serial_end = 0;
- grab->implicit_ungrab = TRUE;
+ GdkDeviceGrabInfo *grab;
+
+ grab = _gdk_display_get_last_device_grab (_gdk_display, l->data);
+ if (grab)
+ {
+ grab->serial_end = 0;
+ grab->implicit_ungrab = TRUE;
+ }
+
+ _gdk_display_device_grab_update (_gdk_display, l->data, 0);
}
- _gdk_display_pointer_grab_update (_gdk_display, 0);
+ g_list_free (list);
}
static void
@@ -344,11 +335,15 @@ create_focus_event (GdkWindow *window,
gboolean in)
{
GdkEvent *event;
+ GdkDeviceManagerCore *device_manager;
event = gdk_event_new (GDK_FOCUS_CHANGE);
event->focus_change.window = window;
event->focus_change.in = in;
+ device_manager = GDK_DEVICE_MANAGER_CORE (_gdk_display->device_manager);
+ gdk_event_set_device (event, device_manager->core_keyboard);
+
return event;
}
@@ -481,6 +476,8 @@ _gdk_quartz_events_send_enter_notify_event (GdkWindow *window)
event->crossing.detail = GDK_NOTIFY_ANCESTOR;
event->crossing.state = 0;
+ gdk_event_set_device (event, _gdk_display->core_pointer);
+
append_event (event, TRUE);
}
@@ -511,8 +508,10 @@ find_toplevel_under_pointer (GdkDisplay *display,
gint *y)
{
GdkWindow *toplevel;
+ GdkPointerWindowInfo *info;
- toplevel = display->pointer_info.toplevel_under_pointer;
+ info = _gdk_display_get_pointer_info (display, display->core_pointer);
+ toplevel = info->toplevel_under_pointer;
if (toplevel)
{
GdkWindowObject *private;
@@ -531,6 +530,197 @@ find_toplevel_under_pointer (GdkDisplay *display,
return toplevel;
}
+static GdkWindow *
+find_toplevel_for_keyboard_event (NSEvent *nsevent)
+{
+ GList *list, *l;
+ GdkWindow *window;
+ GdkDisplay *display;
+ GdkQuartzView *view;
+ GdkDeviceManager *device_manager;
+
+ view = (GdkQuartzView *)[[nsevent window] contentView];
+ window = [view gdkWindow];
+
+ display = gdk_drawable_get_display (GDK_DRAWABLE (window));
+
+ device_manager = gdk_display_get_device_manager (display);
+ list = gdk_device_manager_list_devices (device_manager,
+ GDK_DEVICE_TYPE_MASTER);
+ for (l = list; l; l = l->next)
+ {
+ GdkDeviceGrabInfo *grab;
+ GdkDevice *device = l->data;
+
+ if (device->source != GDK_SOURCE_KEYBOARD)
+ continue;
+
+ grab = _gdk_display_get_last_device_grab (display, device);
+ if (grab && grab->window && !grab->owner_events)
+ {
+ window = gdk_window_get_toplevel (grab->window);
+ break;
+ }
+ }
+
+ g_list_free (list);
+
+ return window;
+}
+
+static GdkWindow *
+find_toplevel_for_mouse_event (NSEvent *nsevent,
+ gint *x,
+ gint *y)
+{
+ NSPoint point;
+ NSPoint screen_point;
+ NSEventType event_type;
+ GdkWindow *toplevel;
+ GdkQuartzView *view;
+ GdkDisplay *display;
+ GdkDeviceGrabInfo *grab;
+ GdkWindowObject *private;
+
+ view = (GdkQuartzView *)[[nsevent window] contentView];
+ toplevel = [view gdkWindow];
+
+ display = gdk_drawable_get_display (toplevel);
+ private = GDK_WINDOW_OBJECT (toplevel);
+
+ event_type = [nsevent type];
+ point = [nsevent locationInWindow];
+ screen_point = [[nsevent window] convertBaseToScreen:point];
+
+ /* From the docs for XGrabPointer:
+ *
+ * If owner_events is True and if a generated pointer event
+ * would normally be reported to this client, it is reported
+ * as usual. Otherwise, the event is reported with respect to
+ * the grab_window and is reported only if selected by
+ * event_mask. For either value of owner_events, unreported
+ * events are discarded.
+ */
+ grab = _gdk_display_get_last_device_grab (display,
+ display->core_pointer);
+ if (grab)
+ {
+ /* Implicit grabs do not go through XGrabPointer and thus the
+ * event mask should not be checked.
+ */
+ if (!grab->implicit
+ && (grab->event_mask & get_event_mask_from_ns_event (nsevent)) == 0)
+ return NULL;
+
+ if (grab->owner_events)
+ {
+ /* For owner events, we need to use the toplevel under the
+ * pointer, not the window from the NSEvent, since that is
+ * reported with respect to the key window, which could be
+ * wrong.
+ */
+ GdkWindow *toplevel_under_pointer;
+ gint x_tmp, y_tmp;
+
+ toplevel_under_pointer = find_toplevel_under_pointer (display,
+ screen_point,
+ &x_tmp, &y_tmp);
+ if (toplevel_under_pointer)
+ {
+ toplevel = toplevel_under_pointer;
+ *x = x_tmp;
+ *y = y_tmp;
+ }
+
+ return toplevel;
+ }
+ else
+ {
+ /* Finally check the grab window. */
+ GdkWindow *grab_toplevel;
+ GdkWindowObject *grab_private;
+ NSWindow *grab_nswindow;
+
+ grab_toplevel = gdk_window_get_toplevel (grab->window);
+ grab_private = (GdkWindowObject *)grab_toplevel;
+
+ grab_nswindow = ((GdkWindowImplQuartz *)grab_private->impl)->toplevel;
+ point = [grab_nswindow convertScreenToBase:screen_point];
+
+ /* Note: x_root and y_root are already right. */
+ *x = point.x;
+ *y = grab_private->height - point.y;
+
+ return grab_toplevel;
+ }
+
+ return NULL;
+ }
+ else
+ {
+ /* The non-grabbed case. */
+ GdkWindow *toplevel_under_pointer;
+ gint x_tmp, y_tmp;
+
+ /* Ignore all events but mouse moved that might be on the title
+ * bar (above the content view). The reason is that otherwise
+ * gdk gets confused about getting e.g. button presses with no
+ * window (the title bar is not known to it).
+ */
+ if (event_type != NSMouseMoved)
+ if (*y < 0)
+ return NULL;
+
+ /* As for owner events, we need to use the toplevel under the
+ * pointer, not the window from the NSEvent.
+ */
+ toplevel_under_pointer = find_toplevel_under_pointer (display,
+ screen_point,
+ &x_tmp, &y_tmp);
+ if (toplevel_under_pointer)
+ {
+ GdkWindowObject *toplevel_private;
+ GdkWindowImplQuartz *toplevel_impl;
+
+ toplevel = toplevel_under_pointer;
+
+ toplevel_private = (GdkWindowObject *)toplevel;
+ toplevel_impl = (GdkWindowImplQuartz *)toplevel_private->impl;
+
+ if ([toplevel_impl->toplevel showsResizeIndicator])
+ {
+ NSRect frame;
+
+ /* If the resize indicator is visible and the event
+ * is in the lower right 15x15 corner, we leave these
+ * events to Cocoa as to be handled as resize events.
+ * Applications may have widgets in this area. These
+ * will most likely be larger than 15x15 and for
+ * scroll bars there are also other means to move
+ * the scroll bar. Since the resize indicator is
+ * the only way of resizing windows on Mac OS, it
+ * is too important to not make functional.
+ */
+ frame = [toplevel_impl->view bounds];
+ if (x_tmp > frame.size.width - GRIP_WIDTH
+ && x_tmp < frame.size.width
+ && y_tmp > frame.size.height - GRIP_HEIGHT
+ && y_tmp < frame.size.height)
+ {
+ return NULL;
+ }
+ }
+
+ *x = x_tmp;
+ *y = y_tmp;
+ }
+
+ return toplevel;
+ }
+
+ return NULL;
+}
+
/* This function finds the correct window to send an event to, taking
* into account grabs, event propagation, and event masks.
*/
@@ -542,14 +732,13 @@ find_window_for_ns_event (NSEvent *nsevent,
gint *y_root)
{
GdkQuartzView *view;
- GdkWindow *toplevel;
- GdkWindowObject *private;
NSPoint point;
NSPoint screen_point;
NSEventType event_type;
+ GdkWindow *toplevel;
+ GdkWindowObject *private;
view = (GdkQuartzView *)[[nsevent window] contentView];
-
toplevel = [view gdkWindow];
private = GDK_WINDOW_OBJECT (toplevel);
@@ -576,138 +765,7 @@ find_window_for_ns_event (NSEvent *nsevent,
case NSLeftMouseDragged:
case NSRightMouseDragged:
case NSOtherMouseDragged:
- {
- GdkDisplay *display;
- GdkPointerGrabInfo *grab;
-
- display = gdk_drawable_get_display (toplevel);
-
- /* From the docs for XGrabPointer:
- *
- * If owner_events is True and if a generated pointer event
- * would normally be reported to this client, it is reported
- * as usual. Otherwise, the event is reported with respect to
- * the grab_window and is reported only if selected by
- * event_mask. For either value of owner_events, unreported
- * events are discarded.
- */
- grab = _gdk_display_get_last_pointer_grab (display);
- if (grab)
- {
- /* Implicit grabs do not go through XGrabPointer and thus the
- * event mask should not be checked.
- */
- if (!grab->implicit
- && (grab->event_mask & get_event_mask_from_ns_event (nsevent)) == 0)
- return NULL;
-
- if (grab->owner_events)
- {
- /* For owner events, we need to use the toplevel under the
- * pointer, not the window from the NSEvent, since that is
- * reported with respect to the key window, which could be
- * wrong.
- */
- GdkWindow *toplevel_under_pointer;
- gint x_tmp, y_tmp;
-
- toplevel_under_pointer = find_toplevel_under_pointer (display,
- screen_point,
- &x_tmp, &y_tmp);
- if (toplevel_under_pointer)
- {
- toplevel = toplevel_under_pointer;
- *x = x_tmp;
- *y = y_tmp;
- }
-
- return toplevel;
- }
- else
- {
- /* Finally check the grab window. */
- GdkWindow *grab_toplevel;
- GdkWindowObject *grab_private;
- NSWindow *grab_nswindow;
-
- grab_toplevel = gdk_window_get_toplevel (grab->window);
- grab_private = (GdkWindowObject *)grab_toplevel;
-
- grab_nswindow = ((GdkWindowImplQuartz *)grab_private->impl)->toplevel;
- point = [grab_nswindow convertScreenToBase:screen_point];
-
- /* Note: x_root and y_root are already right. */
- *x = point.x;
- *y = grab_private->height - point.y;
-
- return grab_toplevel;
- }
-
- return NULL;
- }
- else
- {
- /* The non-grabbed case. */
- GdkWindow *toplevel_under_pointer;
- gint x_tmp, y_tmp;
-
- /* Ignore all events but mouse moved that might be on the title
- * bar (above the content view). The reason is that otherwise
- * gdk gets confused about getting e.g. button presses with no
- * window (the title bar is not known to it).
- */
- if (event_type != NSMouseMoved)
- if (*y < 0)
- return NULL;
-
- /* As for owner events, we need to use the toplevel under the
- * pointer, not the window from the NSEvent.
- */
- toplevel_under_pointer = find_toplevel_under_pointer (display,
- screen_point,
- &x_tmp, &y_tmp);
- if (toplevel_under_pointer)
- {
- GdkWindowObject *toplevel_private;
- GdkWindowImplQuartz *toplevel_impl;
-
- toplevel = toplevel_under_pointer;
-
- toplevel_private = (GdkWindowObject *)toplevel;
- toplevel_impl = (GdkWindowImplQuartz *)toplevel_private->impl;
-
- if ([toplevel_impl->toplevel showsResizeIndicator])
- {
- NSRect frame;
-
- /* If the resize indicator is visible and the event
- * is in the lower right 15x15 corner, we leave these
- * events to Cocoa as to be handled as resize events.
- * Applications may have widgets in this area. These
- * will most likely be larger than 15x15 and for
- * scroll bars there are also other means to move
- * the scroll bar. Since the resize indicator is
- * the only way of resizing windows on Mac OS, it
- * is too important to not make functional.
- */
- frame = [toplevel_impl->view bounds];
- if (x_tmp > frame.size.width - GRIP_WIDTH
- && x_tmp < frame.size.width
- && y_tmp > frame.size.height - GRIP_HEIGHT
- && y_tmp < frame.size.height)
- {
- return NULL;
- }
- }
-
- *x = x_tmp;
- *y = y_tmp;
- }
-
- return toplevel;
- }
- }
- break;
+ return find_toplevel_for_mouse_event (nsevent, x, y);
case NSMouseEntered:
case NSMouseExited:
@@ -722,10 +780,7 @@ find_window_for_ns_event (NSEvent *nsevent,
case NSKeyDown:
case NSKeyUp:
case NSFlagsChanged:
- if (_gdk_display->keyboard_grab.window && !_gdk_display->keyboard_grab.owner_events)
- return gdk_window_get_toplevel (_gdk_display->keyboard_grab.window);
-
- return toplevel;
+ return find_toplevel_for_keyboard_event (nsevent);
default:
/* Ignore everything else. */
@@ -759,6 +814,8 @@ fill_crossing_event (GdkWindow *toplevel,
event->crossing.detail = detail;
event->crossing.state = get_keyboard_modifiers_from_ns_event (nsevent);
+ gdk_event_set_device (event, _gdk_display->core_pointer);
+
/* FIXME: Focus and button state? */
}
@@ -883,6 +940,7 @@ fill_key_event (GdkWindow *window,
GdkEventType type)
{
GdkEventPrivate *priv;
+ GdkDeviceManagerCore *device_manager;
gchar buf[7];
gunichar c = 0;
@@ -896,6 +954,9 @@ fill_key_event (GdkWindow *window,
event->key.hardware_keycode = [nsevent keyCode];
event->key.group = ([nsevent modifierFlags] & NSAlternateKeyMask) ? 1 : 0;
event->key.keyval = GDK_VoidSymbol;
+
+ device_manager = GDK_DEVICE_MANAGER_CORE (_gdk_display->device_manager);
+ gdk_event_set_device (event, device_manager->core_keyboard);
gdk_keymap_translate_keyboard_state (NULL,
event->key.hardware_keycode,
@@ -1177,9 +1238,10 @@ gdk_event_translate (GdkEvent *event,
}
else if (![impl->toplevel isKeyWindow])
{
- GdkPointerGrabInfo *grab;
+ GdkDeviceGrabInfo *grab;
- grab = _gdk_display_get_last_pointer_grab (_gdk_display);
+ grab = _gdk_display_get_last_device_grab (_gdk_display,
+ _gdk_display->core_pointer);
if (!grab)
[impl->toplevel makeKeyWindow];
}
diff --git a/gdk/quartz/gdkinput.c b/gdk/quartz/gdkinput.c
index 9407b08c0a..c431fc47af 100644
--- a/gdk/quartz/gdkinput.c
+++ b/gdk/quartz/gdkinput.c
@@ -31,11 +31,11 @@
#include "gdkinput.h"
#include "gdkprivate.h"
#include "gdkinputprivate.h"
+#include <gdkdevice.h>
+#include <gdkdeviceprivate.h>
-static GdkDeviceAxis gdk_input_core_axes[] = {
- { GDK_AXIS_X, 0, 0 },
- { GDK_AXIS_Y, 0, 0 }
-};
+/* Addition used for extension_events mask */
+#define GDK_ALL_DEVICES_MASK (1<<30)
GdkDevice *_gdk_core_pointer = NULL;
@@ -47,62 +47,6 @@ gint _gdk_input_ignore_core;
GList *_gdk_input_windows;
GList *_gdk_input_devices;
-void
-_gdk_init_input_core (void)
-{
- _gdk_core_pointer = g_object_new (GDK_TYPE_DEVICE, NULL);
-
- _gdk_core_pointer->name = "Core Pointer";
- _gdk_core_pointer->source = GDK_SOURCE_MOUSE;
- _gdk_core_pointer->mode = GDK_MODE_SCREEN;
- _gdk_core_pointer->has_cursor = TRUE;
- _gdk_core_pointer->num_axes = 2;
- _gdk_core_pointer->axes = gdk_input_core_axes;
- _gdk_core_pointer->num_keys = 0;
- _gdk_core_pointer->keys = NULL;
-
- _gdk_display->core_pointer = _gdk_core_pointer;
-}
-
-static void
-gdk_device_finalize (GObject *object)
-{
- g_error ("A GdkDevice object was finalized. This should not happen");
-}
-
-static void
-gdk_device_class_init (GObjectClass *class)
-{
- class->finalize = gdk_device_finalize;
-}
-
-GType
-gdk_device_get_type (void)
-{
- static GType object_type = 0;
-
- if (!object_type)
- {
- const GTypeInfo object_info =
- {
- sizeof (GdkDeviceClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gdk_device_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GdkDevicePrivate),
- 0, /* n_preallocs */
- (GInstanceInitFunc) NULL,
- };
-
- object_type = g_type_register_static (G_TYPE_OBJECT,
- "GdkDevice",
- &object_info, 0);
- }
-
- return object_type;
-}
GList *
gdk_devices_list (void)
@@ -116,173 +60,50 @@ gdk_display_list_devices (GdkDisplay *dpy)
return _gdk_input_devices;
}
-G_CONST_RETURN gchar *
-gdk_device_get_name (GdkDevice *device)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
-
- return device->name;
-}
-
-GdkInputSource
-gdk_device_get_source (GdkDevice *device)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
-
- return device->source;
-}
-
-GdkInputMode
-gdk_device_get_mode (GdkDevice *device)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
-
- return device->mode;
-}
-
-gboolean
-gdk_device_get_has_cursor (GdkDevice *device)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
-
- return device->has_cursor;
-}
-
-void
-gdk_device_set_source (GdkDevice *device,
- GdkInputSource source)
-{
- device->source = source;
-}
-
-void
-gdk_device_get_key (GdkDevice *device,
- guint index,
- guint *keyval,
- GdkModifierType *modifiers)
+static void
+_gdk_input_select_device_events (GdkWindow *impl_window,
+ GdkDevice *device)
{
- g_return_if_fail (GDK_IS_DEVICE (device));
- g_return_if_fail (index < device->num_keys);
-
- if (!device->keys[index].keyval &&
- !device->keys[index].modifiers)
+ guint event_mask;
+ GdkWindowObject *w;
+ GdkInputWindow *iw;
+ GdkInputMode mode;
+ gboolean has_cursor;
+ GdkDeviceType type;
+ GList *l;
+
+ event_mask = 0;
+ iw = ((GdkWindowObject *)impl_window)->input_window;
+
+ g_object_get (device,
+ "type", &type,
+ "input-mode", &mode,
+ "has-cursor", &has_cursor,
+ NULL);
+
+ if (iw == NULL ||
+ mode == GDK_MODE_DISABLED ||
+ type == GDK_DEVICE_TYPE_MASTER)
return;
- if (keyval)
- *keyval = device->keys[index].keyval;
-
- if (modifiers)
- *modifiers = device->keys[index].modifiers;
-}
-
-void
-gdk_device_set_key (GdkDevice *device,
- guint index,
- guint keyval,
- GdkModifierType modifiers)
-{
- g_return_if_fail (device != NULL);
- g_return_if_fail (index < device->num_keys);
-
- device->keys[index].keyval = keyval;
- device->keys[index].modifiers = modifiers;
-}
-
-GdkAxisUse
-gdk_device_get_axis_use (GdkDevice *device,
- guint index)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), GDK_AXIS_IGNORE);
- g_return_val_if_fail (index < device->num_axes, GDK_AXIS_IGNORE);
-
- return device->axes[index].use;
-}
-
-void
-gdk_device_set_axis_use (GdkDevice *device,
- guint index,
- GdkAxisUse use)
-{
- g_return_if_fail (device != NULL);
- g_return_if_fail (index < device->num_axes);
-
- device->axes[index].use = use;
-
- switch (use)
+ for (l = _gdk_input_windows; l != NULL; l = l->next)
{
- case GDK_AXIS_X:
- case GDK_AXIS_Y:
- device->axes[index].min = 0.;
- device->axes[index].max = 0.;
- break;
- case GDK_AXIS_XTILT:
- case GDK_AXIS_YTILT:
- device->axes[index].min = -1.;
- device->axes[index].max = 1;
- break;
- default:
- device->axes[index].min = 0.;
- device->axes[index].max = 1;
- break;
- }
-}
+ w = l->data;
-void
-gdk_device_get_state (GdkDevice *device,
- GdkWindow *window,
- gdouble *axes,
- GdkModifierType *mask)
-{
- gint x_int, y_int;
+ if (has_cursor || (w->extension_events & GDK_ALL_DEVICES_MASK))
+ {
+ event_mask = w->extension_events;
- g_assert (device == _gdk_core_pointer);
-
- gdk_window_get_pointer (window, &x_int, &y_int, mask);
+ if (event_mask)
+ event_mask |= GDK_PROXIMITY_OUT_MASK
+ | GDK_BUTTON_PRESS_MASK
+ | GDK_BUTTON_RELEASE_MASK;
- if (axes)
- {
- axes[0] = x_int;
- axes[1] = y_int;
+ gdk_window_set_device_events ((GdkWindow *) w, device, event_mask);
+ }
}
}
-void
-gdk_device_free_history (GdkTimeCoord **events,
- gint n_events)
-{
- gint i;
-
- for (i = 0; i < n_events; i++)
- g_free (events[i]);
-
- g_free (events);
-}
-
-gboolean
-gdk_device_get_history (GdkDevice *device,
- GdkWindow *window,
- guint32 start,
- guint32 stop,
- GdkTimeCoord ***events,
- gint *n_events)
-{
- g_return_val_if_fail (window != NULL, FALSE);
- g_return_val_if_fail (GDK_WINDOW_IS_QUARTZ (window), FALSE);
- g_return_val_if_fail (events != NULL, FALSE);
- g_return_val_if_fail (n_events != NULL, FALSE);
-
- *n_events = 0;
- *events = NULL;
- return FALSE;
-}
-
-gboolean
-gdk_device_set_mode (GdkDevice *device,
- GdkInputMode mode)
-{
- return FALSE;
-}
-
gint
_gdk_input_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev)
{
@@ -315,10 +136,12 @@ _gdk_input_window_find(GdkWindow *window)
cases */
void
-gdk_input_set_extension_events (GdkWindow *window, gint mask,
- GdkExtensionMode mode)
+gdk_input_set_extension_events (GdkWindow *window,
+ gint mask,
+ GdkExtensionMode mode)
{
GdkWindowObject *window_private;
+ GdkWindowObject *impl_window;
GList *tmp_list;
GdkInputWindow *iw;
@@ -326,13 +149,14 @@ gdk_input_set_extension_events (GdkWindow *window, gint mask,
g_return_if_fail (GDK_WINDOW_IS_QUARTZ (window));
window_private = (GdkWindowObject*) window;
+ impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
if (mode == GDK_EXTENSION_EVENTS_NONE)
mask = 0;
if (mask != 0)
{
- iw = g_new(GdkInputWindow,1);
+ iw = g_new (GdkInputWindow, 1);
iw->window = window;
iw->mode = mode;
@@ -341,39 +165,32 @@ gdk_input_set_extension_events (GdkWindow *window, gint mask,
iw->num_obscuring = 0;
iw->grabbed = FALSE;
- _gdk_input_windows = g_list_append (_gdk_input_windows,iw);
+ _gdk_input_windows = g_list_append (_gdk_input_windows, iw);
window_private->extension_events = mask;
/* Add enter window events to the event mask */
/* FIXME, this is not needed for XINPUT_NONE */
gdk_window_set_events (window,
- gdk_window_get_events (window) |
- GDK_ENTER_NOTIFY_MASK);
+ 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);
- }
+ {
+ _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);
+ GdkDevice *dev = tmp_list->data;
- if (gdkdev != (GdkDevicePrivate *)_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);
- }
+ _gdk_input_select_device_events (GDK_WINDOW (impl_window), dev);
}
}
@@ -390,10 +207,57 @@ _gdk_input_window_destroy (GdkWindow *window)
}
void
+_gdk_input_check_extension_events (GdkDevice *device)
+{
+}
+
+void
_gdk_input_init (void)
{
- _gdk_init_input_core ();
- _gdk_input_devices = g_list_append (NULL, _gdk_core_pointer);
+ GdkDeviceManager *device_manager;
+ GList *list, *l;
+
+ device_manager = gdk_display_get_device_manager (_gdk_display);
+
+ /* For backward compatibility, just add floating devices that are
+ * not keyboards.
+ */
+ list = gdk_device_manager_list_devices (device_manager,
+ GDK_DEVICE_TYPE_FLOATING);
+ for (l = list; l; l = l->next)
+ {
+ GdkDevice *device = l->data;
+
+ if (device->source == GDK_SOURCE_KEYBOARD)
+ continue;
+
+ _gdk_input_devices = g_list_prepend (_gdk_input_devices, l->data);
+ }
+
+ g_list_free (list);
+
+ /* Now set "core" pointer to the first master device that is a pointer.
+ */
+ list = gdk_device_manager_list_devices (device_manager,
+ GDK_DEVICE_TYPE_MASTER);
+
+ for (l = list; l; l = l->next)
+ {
+ GdkDevice *device = list->data;
+
+ if (device->source != GDK_SOURCE_MOUSE)
+ continue;
+
+ _gdk_display->core_pointer = device;
+ break;
+ }
+
+ g_list_free (list);
+
+ /* Add the core pointer to the devices list */
+ _gdk_input_devices = g_list_prepend (_gdk_input_devices,
+ _gdk_display->core_pointer);
+
_gdk_input_ignore_core = FALSE;
}
@@ -425,30 +289,3 @@ _gdk_input_exit (void)
}
g_list_free (_gdk_input_windows);
}
-
-gboolean
-gdk_device_get_axis (GdkDevice *device, gdouble *axes, GdkAxisUse use, gdouble *value)
-{
- gint i;
-
- g_return_val_if_fail (device != NULL, FALSE);
-
- if (axes == NULL)
- return FALSE;
-
- for (i = 0; i < device->num_axes; i++)
- if (device->axes[i].use == use)
- {
- if (value)
- *value = axes[i];
- return TRUE;
- }
-
- return FALSE;
-}
-
-void
-_gdk_input_window_crossing (GdkWindow *window,
- gboolean enter)
-{
-}
diff --git a/gdk/quartz/gdkinputprivate.h b/gdk/quartz/gdkinputprivate.h
index b8f13ac38a..0868f33a08 100644
--- a/gdk/quartz/gdkinputprivate.h
+++ b/gdk/quartz/gdkinputprivate.h
@@ -97,11 +97,6 @@ struct _GdkDevicePrivate {
GdkDevice info;
};
-struct _GdkDeviceClass
-{
- GObjectClass parent_class;
-};
-
struct _GdkInputWindow
{
/* gdk window */
diff --git a/gdk/quartz/gdkprivate-quartz.h b/gdk/quartz/gdkprivate-quartz.h
index 49aafb416f..0809dcf82b 100644
--- a/gdk/quartz/gdkprivate-quartz.h
+++ b/gdk/quartz/gdkprivate-quartz.h
@@ -152,7 +152,8 @@ void _gdk_quartz_window_nspoint_to_gdk_xy (NSPoint point,
gint *y);
GdkWindow *_gdk_quartz_window_find_child (GdkWindow *window,
gint x,
- gint y);
+ gint y,
+ gboolean get_toplevel);
void _gdk_quartz_window_attach_to_parent (GdkWindow *window);
void _gdk_quartz_window_detach_from_parent (GdkWindow *window);
void _gdk_quartz_window_did_become_main (GdkWindow *window);
diff --git a/gdk/quartz/gdkwindow-quartz.c b/gdk/quartz/gdkwindow-quartz.c
index 93b68c29ca..efc0672e7c 100644
--- a/gdk/quartz/gdkwindow-quartz.c
+++ b/gdk/quartz/gdkwindow-quartz.c
@@ -23,6 +23,7 @@
#include <Carbon/Carbon.h>
#include "gdk.h"
+#include "gdkdeviceprivate.h"
#include "gdkwindowimpl.h"
#include "gdkprivate-quartz.h"
#include "gdkscreen-quartz.h"
@@ -143,41 +144,47 @@ gdk_window_impl_quartz_get_context (GdkDrawable *drawable,
static void
check_grab_unmap (GdkWindow *window)
{
+ GList *list, *l;
GdkDisplay *display = gdk_drawable_get_display (window);
+ GdkDeviceManager *device_manager;
- _gdk_display_end_pointer_grab (display, 0, window, TRUE);
-
- if (display->keyboard_grab.window)
+ device_manager = gdk_display_get_device_manager (display);
+ list = gdk_device_manager_list_devices (device_manager,
+ GDK_DEVICE_TYPE_FLOATING);
+ for (l = list; l; l = l->next)
{
- GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
- GdkWindowObject *tmp = GDK_WINDOW_OBJECT (display->keyboard_grab.window);
-
- while (tmp && tmp != private)
- tmp = tmp->parent;
-
- if (tmp)
- _gdk_display_unset_has_keyboard_grab (display, TRUE);
+ _gdk_display_end_device_grab (display, l->data, 0, window, TRUE);
}
+
+ g_list_free (list);
}
static void
check_grab_destroy (GdkWindow *window)
{
+ GList *list, *l;
GdkDisplay *display = gdk_drawable_get_display (window);
- GdkPointerGrabInfo *grab;
+ GdkDeviceManager *device_manager;
/* Make sure there is no lasting grab in this native window */
- grab = _gdk_display_get_last_pointer_grab (display);
- if (grab && grab->native_window == window)
+ device_manager = gdk_display_get_device_manager (display);
+ list = gdk_device_manager_list_devices (device_manager,
+ GDK_DEVICE_TYPE_MASTER);
+
+ for (l = list; l; l = l->next)
{
- /* Serials are always 0 in quartz, but for clarity: */
- grab->serial_end = grab->serial_start;
- grab->implicit_ungrab = TRUE;
+ GdkDeviceGrabInfo *grab;
+
+ grab = _gdk_display_get_last_device_grab (display, l->data);
+ if (grab && grab->native_window == window)
+ {
+ /* Serials are always 0 in quartz, but for clarity: */
+ grab->serial_end = grab->serial_start;
+ grab->implicit_ungrab = TRUE;
+ }
}
- if (window == display->keyboard_grab.native_window &&
- display->keyboard_grab.window != NULL)
- _gdk_display_unset_has_keyboard_grab (display, TRUE);
+ g_list_free (list);
}
static void
@@ -698,7 +705,8 @@ find_child_window_helper (GdkWindow *window,
gint x,
gint y,
gint x_offset,
- gint y_offset)
+ gint y_offset,
+ gboolean get_toplevel)
{
GdkWindowImplQuartz *impl;
GList *l;
@@ -751,13 +759,15 @@ find_child_window_helper (GdkWindow *window,
}
}
- if (x >= temp_x && y >= temp_y &&
+ if ((!get_toplevel || (get_toplevel && window == _gdk_root)) &&
+ x >= temp_x && y >= temp_y &&
x < temp_x + child_private->width && y < temp_y + child_private->height)
{
/* Look for child windows. */
return find_child_window_helper (l->data,
x, y,
- temp_x, temp_y);
+ temp_x, temp_y,
+ get_toplevel);
}
}
@@ -771,12 +781,13 @@ find_child_window_helper (GdkWindow *window,
GdkWindow *
_gdk_quartz_window_find_child (GdkWindow *window,
gint x,
- gint y)
+ gint y,
+ gboolean get_toplevel)
{
GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
if (x >= 0 && y >= 0 && x < private->width && y < private->height)
- return find_child_window_helper (window, x, y, 0, 0);
+ return find_child_window_helper (window, x, y, 0, 0, get_toplevel);
return NULL;
}
@@ -1701,8 +1712,9 @@ gdk_window_quartz_set_back_pixmap (GdkWindow *window,
}
static void
-gdk_window_quartz_set_cursor (GdkWindow *window,
- GdkCursor *cursor)
+gdk_window_quartz_set_device_cursor (GdkWindow *window,
+ GdkDevice *device,
+ GdkCursor *cursor)
{
GdkCursorPrivate *cursor_private;
NSCursor *nscursor;
@@ -1893,10 +1905,11 @@ gdk_window_get_root_origin (GdkWindow *window,
/* Returns coordinates relative to the passed in window. */
static GdkWindow *
-gdk_window_quartz_get_pointer_helper (GdkWindow *window,
- gint *x,
- gint *y,
- GdkModifierType *mask)
+gdk_window_quartz_get_device_state_helper (GdkWindow *window,
+ GdkDevice *device,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
{
GdkWindowObject *toplevel;
GdkWindowObject *private;
@@ -1941,7 +1954,8 @@ gdk_window_quartz_get_pointer_helper (GdkWindow *window,
window = (GdkWindow *)toplevel;
}
- found_window = _gdk_quartz_window_find_child (window, x_tmp, y_tmp);
+ found_window = _gdk_quartz_window_find_child (window, x_tmp, y_tmp,
+ FALSE);
/* We never return the root window. */
if (found_window == _gdk_root)
@@ -1954,26 +1968,30 @@ gdk_window_quartz_get_pointer_helper (GdkWindow *window,
}
static gboolean
-gdk_window_quartz_get_pointer (GdkWindow *window,
- gint *x,
- gint *y,
- GdkModifierType *mask)
+gdk_window_quartz_get_device_state (GdkWindow *window,
+ GdkDevice *device,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
{
- return gdk_window_quartz_get_pointer_helper (window, x, y, mask) != NULL;
+ return gdk_window_quartz_get_device_state_helper (window,
+ device,
+ x, y, mask) != NULL;
}
/* Returns coordinates relative to the root. */
void
-_gdk_windowing_get_pointer (GdkDisplay *display,
- GdkScreen **screen,
- gint *x,
- gint *y,
- GdkModifierType *mask)
+_gdk_windowing_get_device_state (GdkDisplay *display,
+ GdkDevice *device,
+ GdkScreen **screen,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
{
g_return_if_fail (display == _gdk_display);
*screen = _gdk_screen;
- gdk_window_quartz_get_pointer_helper (_gdk_root, x, y, mask);
+ gdk_window_quartz_get_device_state_helper (_gdk_root, device, x, y, mask);
}
void
@@ -1997,9 +2015,10 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display,
gint x, y;
GdkModifierType tmp_mask = 0;
- found_window = gdk_window_quartz_get_pointer_helper (_gdk_root,
- &x, &y,
- &tmp_mask);
+ found_window = gdk_window_quartz_get_device_state_helper (_gdk_root,
+ display->core_pointer,
+ &x, &y,
+ &tmp_mask);
if (found_window)
{
GdkWindowObject *private;
@@ -2052,6 +2071,21 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display,
return found_window;
}
+GdkWindow*
+_gdk_windowing_window_at_device_position (GdkDisplay *display,
+ GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel)
+{
+ return GDK_DEVICE_GET_CLASS (device)->window_at_position (device,
+ win_x, win_y,
+ mask,
+ get_toplevel);
+}
+
+
static GdkEventMask
gdk_window_quartz_get_events (GdkWindow *window)
{
@@ -3065,10 +3099,10 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface)
iface->set_background = gdk_window_quartz_set_background;
iface->set_back_pixmap = gdk_window_quartz_set_back_pixmap;
iface->reparent = gdk_window_quartz_reparent;
- iface->set_cursor = gdk_window_quartz_set_cursor;
+ iface->set_device_cursor = gdk_window_quartz_set_device_cursor;
iface->get_geometry = gdk_window_quartz_get_geometry;
iface->get_root_coords = gdk_window_quartz_get_root_coords;
- iface->get_pointer = gdk_window_quartz_get_pointer;
+ iface->get_device_state = gdk_window_quartz_get_device_state;
iface->get_deskrelative_origin = gdk_window_quartz_get_deskrelative_origin;
iface->shape_combine_region = gdk_window_quartz_shape_combine_region;
iface->input_shape_combine_region = gdk_window_quartz_input_shape_combine_region;
@@ -3076,6 +3110,4 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface)
iface->queue_antiexpose = _gdk_quartz_window_queue_antiexpose;
iface->queue_translation = _gdk_quartz_window_queue_translation;
iface->destroy = _gdk_quartz_window_destroy;
- iface->input_window_destroy = _gdk_input_window_destroy;
- iface->input_window_crossing = _gdk_input_window_crossing;
}
diff --git a/gdk/win32/Makefile.am b/gdk/win32/Makefile.am
index 17d048edde..e6c5b2deb4 100644
--- a/gdk/win32/Makefile.am
+++ b/gdk/win32/Makefile.am
@@ -29,6 +29,12 @@ libgdk_win32_la_SOURCES = \
gdkapplaunchcontext-win32.c \
gdkcolor-win32.c \
gdkcursor-win32.c \
+ gdkdevicemanager-win32.c \
+ gdkdevicemanager-win32.h \
+ gdkdevice-win32.c \
+ gdkdevice-win32.h \
+ gdkdevice-wintab.c \
+ gdkdevice-wintab.h \
gdkdisplay-win32.c \
gdkdnd-win32.c \
gdkdrawable-win32.c \
@@ -41,8 +47,6 @@ libgdk_win32_la_SOURCES = \
gdkim-win32.c \
gdkimage-win32.c \
gdkinput.c \
- gdkinput-win32.c \
- gdkinput-win32.h \
gdkkeys-win32.c \
gdkmain-win32.c \
gdkpixmap-win32.c \
diff --git a/gdk/win32/gdkdevice-win32.c b/gdk/win32/gdkdevice-win32.c
new file mode 100644
index 0000000000..9e4eb81644
--- /dev/null
+++ b/gdk/win32/gdkdevice-win32.c
@@ -0,0 +1,396 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+
+#include <gdk/gdkwindow.h>
+
+#include <windowsx.h>
+#include <objbase.h>
+
+#include "gdkdevice-win32.h"
+#include "gdkwin32.h"
+
+static gboolean gdk_device_win32_get_history (GdkDevice *device,
+ GdkWindow *window,
+ guint32 start,
+ guint32 stop,
+ GdkTimeCoord ***events,
+ guint *n_events);
+static void gdk_device_win32_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask);
+static void gdk_device_win32_set_window_cursor (GdkDevice *device,
+ GdkWindow *window,
+ GdkCursor *cursor);
+static void gdk_device_win32_warp (GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y);
+static gboolean gdk_device_win32_query_state (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow **root_window,
+ GdkWindow **child_window,
+ gint *root_x,
+ gint *root_y,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask);
+static GdkGrabStatus gdk_device_win32_grab (GdkDevice *device,
+ GdkWindow *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time_);
+static void gdk_device_win32_ungrab (GdkDevice *device,
+ guint32 time_);
+static GdkWindow * gdk_device_win32_window_at_position (GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel);
+static void gdk_device_win32_select_window_events (GdkDevice *device,
+ GdkWindow *window,
+ GdkEventMask event_mask);
+
+
+G_DEFINE_TYPE (GdkDeviceWin32, gdk_device_win32, GDK_TYPE_DEVICE)
+
+static void
+gdk_device_win32_class_init (GdkDeviceWin32Class *klass)
+{
+ GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
+
+ device_class->get_history = gdk_device_win32_get_history;
+ device_class->get_state = gdk_device_win32_get_state;
+ device_class->set_window_cursor = gdk_device_win32_set_window_cursor;
+ device_class->warp = gdk_device_win32_warp;
+ device_class->query_state = gdk_device_win32_query_state;
+ device_class->grab = gdk_device_win32_grab;
+ device_class->ungrab = gdk_device_win32_ungrab;
+ device_class->window_at_position = gdk_device_win32_window_at_position;
+ device_class->select_window_events = gdk_device_win32_select_window_events;
+}
+
+static void
+gdk_device_win32_init (GdkDeviceWin32 *device_win32)
+{
+ GdkDevice *device;
+
+ device = GDK_DEVICE (device_win32);
+
+ _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_X, 0, 0, 1);
+ _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_Y, 0, 0, 1);
+}
+
+static gboolean
+gdk_device_win32_get_history (GdkDevice *device,
+ GdkWindow *window,
+ guint32 start,
+ guint32 stop,
+ GdkTimeCoord ***events,
+ guint *n_events)
+{
+ return FALSE;
+}
+
+static void
+gdk_device_win32_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask)
+{
+ gint x_int, y_int;
+
+ gdk_window_get_pointer (window, &x_int, &y_int, mask);
+
+ if (axes)
+ {
+ axes[0] = x_int;
+ axes[1] = y_int;
+ }
+}
+
+static void
+gdk_device_win32_set_window_cursor (GdkDevice *device,
+ GdkWindow *window,
+ GdkCursor *cursor)
+{
+ GdkCursorPrivate *cursor_private;
+ GdkWindowObject *parent_window;
+ GdkWindowImplWin32 *impl;
+ HCURSOR hcursor;
+ HCURSOR hprevcursor;
+
+ impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
+ cursor_private = (GdkCursorPrivate*) cursor;
+
+ hprevcursor = impl->hcursor;
+
+ if (!cursor)
+ hcursor = NULL;
+ else
+ hcursor = cursor_private->hcursor;
+
+ if (hcursor != NULL)
+ {
+ /* If the pointer is over our window, set new cursor */
+ GdkWindow *curr_window = gdk_window_get_pointer (window, NULL, NULL, NULL);
+
+ if (curr_window == window ||
+ (curr_window && window == gdk_window_get_toplevel (curr_window)))
+ SetCursor (hcursor);
+ else
+ {
+ /* Climb up the tree and find whether our window is the
+ * first ancestor that has cursor defined, and if so, set
+ * new cursor.
+ */
+ GdkWindowObject *curr_window_obj = GDK_WINDOW_OBJECT (curr_window);
+
+ while (curr_window_obj &&
+ !GDK_WINDOW_IMPL_WIN32 (curr_window_obj->impl)->hcursor)
+ {
+ curr_window_obj = curr_window_obj->parent;
+ if (curr_window_obj == GDK_WINDOW_OBJECT (window))
+ {
+ SetCursor (hcursor);
+ break;
+ }
+ }
+ }
+ }
+
+ /* Unset the previous cursor: Need to make sure it's no longer in
+ * use before we destroy it, in case we're not over our window but
+ * the cursor is still set to our old one.
+ */
+ if (hprevcursor != NULL &&
+ GetCursor () == hprevcursor)
+ {
+ /* Look for a suitable cursor to use instead */
+ hcursor = NULL;
+ parent_window = GDK_WINDOW_OBJECT (window)->parent;
+
+ while (hcursor == NULL)
+ {
+ if (parent_window)
+ {
+ impl = GDK_WINDOW_IMPL_WIN32 (parent_window->impl);
+ hcursor = impl->hcursor;
+ parent_window = parent_window->parent;
+ }
+ else
+ hcursor = LoadCursor (NULL, IDC_ARROW);
+ }
+
+ SetCursor (hcursor);
+ }
+}
+
+static void
+gdk_device_win32_warp (GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y)
+{
+ SetCursorPos (x - _gdk_offset_x, y - _gdk_offset_y);
+}
+
+static GdkModifierType
+get_current_mask (void)
+{
+ GdkModifierType mask;
+ BYTE kbd[256];
+
+ GetKeyboardState (kbd);
+ mask = 0;
+ if (kbd[VK_SHIFT] & 0x80)
+ mask |= GDK_SHIFT_MASK;
+ if (kbd[VK_CAPITAL] & 0x80)
+ mask |= GDK_LOCK_MASK;
+ if (kbd[VK_CONTROL] & 0x80)
+ mask |= GDK_CONTROL_MASK;
+ if (kbd[VK_MENU] & 0x80)
+ mask |= GDK_MOD1_MASK;
+ if (kbd[VK_LBUTTON] & 0x80)
+ mask |= GDK_BUTTON1_MASK;
+ if (kbd[VK_MBUTTON] & 0x80)
+ mask |= GDK_BUTTON2_MASK;
+ if (kbd[VK_RBUTTON] & 0x80)
+ mask |= GDK_BUTTON3_MASK;
+
+ return mask;
+}
+
+static gboolean
+gdk_device_win32_query_state (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow **root_window,
+ GdkWindow **child_window,
+ gint *root_x,
+ gint *root_y,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask)
+{
+ gboolean return_val;
+ POINT point;
+ HWND hwnd, hwndc;
+
+ g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), FALSE);
+
+ return_val = TRUE;
+
+ hwnd = GDK_WINDOW_HWND (window);
+ GetCursorPos (&point);
+
+ if (root_x)
+ *root_x = point.x;
+
+ if (root_y)
+ *root_y = point.y;
+
+ ScreenToClient (hwnd, &point);
+
+ if (win_x)
+ *win_x = point.x;
+
+ if (win_y)
+ *win_y = point.y;
+
+ if (window == _gdk_root)
+ {
+ if (win_x)
+ *win_x += _gdk_offset_x;
+
+ if (win_y)
+ *win_y += _gdk_offset_y;
+ }
+
+ if (child_window)
+ {
+ hwndc = ChildWindowFromPoint (hwnd, point);
+
+ if (hwndc && hwndc != hwnd)
+ *child_window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwndc);
+ else
+ *child_window = NULL; /* Direct child unknown to gdk */
+ }
+
+ if (root_window)
+ {
+ GdkScreen *screen;
+
+ screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
+ *root_window = gdk_screen_get_root_window (screen);
+ }
+
+ if (mask)
+ *mask = get_current_mask ();
+
+ return TRUE;
+}
+
+static GdkGrabStatus
+gdk_device_win32_grab (GdkDevice *device,
+ GdkWindow *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time_)
+{
+ if (device->source != GDK_SOURCE_KEYBOARD)
+ SetCapture (GDK_WINDOW_HWND (window));
+
+ return GDK_GRAB_SUCCESS;
+}
+
+static void
+gdk_device_win32_ungrab (GdkDevice *device,
+ guint32 time_)
+{
+ GdkDisplay *display;
+
+ display = gdk_device_get_display (device);
+
+ if (device->source != GDK_SOURCE_KEYBOARD)
+ ReleaseCapture ();
+}
+
+static GdkWindow *
+gdk_device_win32_window_at_position (GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel)
+{
+ GdkWindow *window;
+ POINT point, pointc;
+ HWND hwnd, hwndc;
+ RECT rect;
+
+ GetCursorPos (&pointc);
+ point = pointc;
+ hwnd = WindowFromPoint (point);
+
+ if (hwnd == NULL)
+ {
+ window = _gdk_root;
+ *win_x = pointc.x + _gdk_offset_x;
+ *win_y = pointc.y + _gdk_offset_y;
+ return window;
+ }
+
+ ScreenToClient (hwnd, &point);
+
+ do
+ {
+ if (get_toplevel &&
+ (window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd)) != NULL &&
+ GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
+ break;
+
+ hwndc = ChildWindowFromPoint (hwnd, point);
+ ClientToScreen (hwnd, &point);
+ ScreenToClient (hwndc, &point);
+ }
+ while (hwndc != hwnd && (hwnd = hwndc, 1));
+
+ window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd);
+
+ if (window && (win_x || win_y))
+ {
+ GetClientRect (hwnd, &rect);
+ *win_x = point.x - rect.left;
+ *win_y = point.y - rect.top;
+ }
+
+ return window;
+}
+
+static void
+gdk_device_win32_select_window_events (GdkDevice *device,
+ GdkWindow *window,
+ GdkEventMask event_mask)
+{
+}
diff --git a/gdk/win32/gdkdevice-win32.h b/gdk/win32/gdkdevice-win32.h
new file mode 100644
index 0000000000..ef9c322b3d
--- /dev/null
+++ b/gdk/win32/gdkdevice-win32.h
@@ -0,0 +1,51 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GDK_DEVICE_WIN32_H__
+#define __GDK_DEVICE_WIN32_H__
+
+#include <gdk/gdkdeviceprivate.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_WIN32 (gdk_device_win32_get_type ())
+#define GDK_DEVICE_WIN32(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_WIN32, GdkDeviceWin32))
+#define GDK_DEVICE_WIN32_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_WIN32, GdkDeviceWin32Class))
+#define GDK_IS_DEVICE_WIN32(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_WIN32))
+#define GDK_IS_DEVICE_WIN32_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_WIN32))
+#define GDK_DEVICE_WIN32_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_WIN32, GdkDeviceWin32Class))
+
+typedef struct _GdkDeviceWin32 GdkDeviceWin32;
+typedef struct _GdkDeviceWin32Class GdkDeviceWin32Class;
+
+struct _GdkDeviceWin32
+{
+ GdkDevice parent_instance;
+};
+
+struct _GdkDeviceWin32Class
+{
+ GdkDeviceClass parent_class;
+};
+
+GType gdk_device_win32_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_WIN32_H__ */
diff --git a/gdk/win32/gdkdevice-wintab.c b/gdk/win32/gdkdevice-wintab.c
new file mode 100644
index 0000000000..392e10b2e4
--- /dev/null
+++ b/gdk/win32/gdkdevice-wintab.c
@@ -0,0 +1,386 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+
+#include <gdk/gdkwindow.h>
+
+#include <windowsx.h>
+#include <objbase.h>
+
+#include "gdkwin32.h"
+#include "gdkdevice-wintab.h"
+
+static GQuark quark_window_input_info = 0;
+static GSList *input_windows = NULL;
+
+typedef struct
+{
+ gdouble root_x;
+ gdouble root_y;
+ GHashTable *device_events;
+} GdkWindowInputInfo;
+
+static gboolean gdk_device_wintab_get_history (GdkDevice *device,
+ GdkWindow *window,
+ guint32 start,
+ guint32 stop,
+ GdkTimeCoord ***events,
+ guint *n_events);
+static void gdk_device_wintab_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask);
+static void gdk_device_wintab_set_window_cursor (GdkDevice *device,
+ GdkWindow *window,
+ GdkCursor *cursor);
+static void gdk_device_wintab_warp (GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y);
+static gboolean gdk_device_wintab_query_state (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow **root_window,
+ GdkWindow **child_window,
+ gint *root_x,
+ gint *root_y,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask);
+static GdkGrabStatus gdk_device_wintab_grab (GdkDevice *device,
+ GdkWindow *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time_);
+static void gdk_device_wintab_ungrab (GdkDevice *device,
+ guint32 time_);
+static GdkWindow * gdk_device_wintab_window_at_position (GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel);
+static void gdk_device_wintab_select_window_events (GdkDevice *device,
+ GdkWindow *window,
+ GdkEventMask event_mask);
+
+
+G_DEFINE_TYPE (GdkDeviceWintab, gdk_device_wintab, GDK_TYPE_DEVICE)
+
+static void
+gdk_device_wintab_class_init (GdkDeviceWintabClass *klass)
+{
+ GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
+
+ device_class->get_history = gdk_device_wintab_get_history;
+ device_class->get_state = gdk_device_wintab_get_state;
+ device_class->set_window_cursor = gdk_device_wintab_set_window_cursor;
+ device_class->warp = gdk_device_wintab_warp;
+ device_class->query_state = gdk_device_wintab_query_state;
+ device_class->grab = gdk_device_wintab_grab;
+ device_class->ungrab = gdk_device_wintab_ungrab;
+ device_class->window_at_position = gdk_device_wintab_window_at_position;
+ device_class->select_window_events = gdk_device_wintab_select_window_events;
+
+ quark_window_input_info = g_quark_from_static_string ("gdk-window-input-info");
+}
+
+static void
+gdk_device_wintab_init (GdkDeviceWintab *device_wintab)
+{
+ GdkDevice *device;
+
+ device = GDK_DEVICE (device_wintab);
+}
+
+static gboolean
+gdk_device_wintab_get_history (GdkDevice *device,
+ GdkWindow *window,
+ guint32 start,
+ guint32 stop,
+ GdkTimeCoord ***events,
+ guint *n_events)
+{
+ return FALSE;
+}
+
+static void
+gdk_device_wintab_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask)
+{
+ GdkDeviceWintab *device_wintab;
+
+ device_wintab = GDK_DEVICE_WINTAB (device);
+
+ /* For now just use the last known button and axis state of the device.
+ * Since graphical tablets send an insane amount of motion events each
+ * second, the info should be fairly up to date */
+ if (mask)
+ {
+ gdk_window_get_pointer (window, NULL, NULL, mask);
+ *mask &= 0xFF; /* Mask away core pointer buttons */
+ *mask |= ((device_wintab->button_state << 8)
+ & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
+ | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
+ | GDK_BUTTON5_MASK));
+ }
+
+ if (device_wintab->last_axis_data)
+ _gdk_device_wintab_translate_axes (device, window, axes, NULL, NULL);
+}
+
+static void
+gdk_device_wintab_set_window_cursor (GdkDevice *device,
+ GdkWindow *window,
+ GdkCursor *cursor)
+{
+}
+
+static void
+gdk_device_wintab_warp (GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y)
+{
+}
+
+static gboolean
+gdk_device_wintab_query_state (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow **root_window,
+ GdkWindow **child_window,
+ gint *root_x,
+ gint *root_y,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask)
+{
+ return FALSE;
+}
+
+static GdkGrabStatus
+gdk_device_wintab_grab (GdkDevice *device,
+ GdkWindow *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time_)
+{
+ return GDK_GRAB_SUCCESS;
+}
+
+static void
+gdk_device_wintab_ungrab (GdkDevice *device,
+ guint32 time_)
+{
+}
+
+static GdkWindow *
+gdk_device_wintab_window_at_position (GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel)
+{
+ return NULL;
+}
+
+static void
+input_info_free (GdkWindowInputInfo *info)
+{
+ g_hash_table_destroy (info->device_events);
+ g_free (info);
+}
+
+static void
+gdk_device_wintab_select_window_events (GdkDevice *device,
+ GdkWindow *window,
+ GdkEventMask event_mask)
+{
+ GdkWindowInputInfo *info;
+
+ info = g_object_get_qdata (G_OBJECT (window),
+ quark_window_input_info);
+ if (event_mask)
+ {
+ if (!info)
+ {
+ info = g_new0 (GdkWindowInputInfo, 1);
+ info->device_events = g_hash_table_new (NULL, NULL);
+
+ g_object_set_qdata_full (G_OBJECT (window),
+ quark_window_input_info,
+ info,
+ (GDestroyNotify) input_info_free);
+ input_windows = g_slist_prepend (input_windows, window);
+ }
+
+ g_hash_table_insert (info->device_events, device,
+ GUINT_TO_POINTER (event_mask));
+ }
+ else if (info)
+ {
+ g_hash_table_remove (info->device_events, device);
+
+ if (g_hash_table_size (info->device_events) == 0)
+ {
+ g_object_set_qdata (G_OBJECT (window),
+ quark_window_input_info,
+ NULL);
+ input_windows = g_slist_remove (input_windows, window);
+ }
+ }
+}
+
+GdkEventMask
+_gdk_device_wintab_get_events (GdkDeviceWintab *device,
+ GdkWindow *window)
+{
+ GdkWindowInputInfo *info;
+
+ info = g_object_get_qdata (G_OBJECT (window),
+ quark_window_input_info);
+
+ if (!info)
+ return 0;
+
+ return GPOINTER_TO_UINT (g_hash_table_lookup (info->device_events, device));
+}
+
+gboolean
+_gdk_device_wintab_get_window_coords (GdkWindow *window,
+ gdouble *root_x,
+ gdouble *root_y)
+{
+ GdkWindowInputInfo *info;
+
+ info = g_object_get_qdata (G_OBJECT (window),
+ quark_window_input_info);
+
+ if (!info)
+ return FALSE;
+
+ *root_x = info->root_x;
+ *root_y = info->root_y;
+
+ return TRUE;
+}
+
+void
+_gdk_device_wintab_update_window_coords (GdkWindow *window)
+{
+ GdkWindowInputInfo *info;
+ gint root_x, root_y;
+
+ info = g_object_get_qdata (G_OBJECT (window),
+ quark_window_input_info);
+
+ g_return_if_fail (info != NULL);
+
+ gdk_window_get_origin (window, &root_x, &root_y);
+ info->root_x = (gdouble) root_x;
+ info->root_y = (gdouble) root_y;
+}
+
+void
+_gdk_device_wintab_translate_axes (GdkDeviceWintab *device_wintab,
+ GdkWindow *window,
+ gdouble *axes,
+ gdouble *x,
+ gdouble *y)
+{
+ GdkDevice *device;
+ GdkWindow *impl_window;
+ gdouble root_x, root_y;
+ gdouble temp_x, temp_y;
+ gint i;
+
+ device = GDK_DEVICE (device_wintab);
+ impl_window = _gdk_window_get_impl_window (window);
+ temp_x = temp_y = 0;
+
+ if (!_gdk_device_wintab_get_window_coords (impl_window, &root_x, &root_y))
+ return;
+
+ for (i = 0; i < device->num_axes; i++)
+ {
+ GdkAxisUse use;
+
+ use = _gdk_device_get_axis_use (device, i);
+
+ switch (use)
+ {
+ case GDK_AXIS_X:
+ case GDK_AXIS_Y:
+ if (gdk_device_get_mode (device) == GDK_MODE_WINDOW)
+ _gdk_device_translate_window_coord (device, window, i,
+ device_wintab->last_axis_data[i],
+ &axes[i]);
+ else
+ _gdk_device_translate_screen_coord (device, window,
+ root_x, root_y, i,
+ device_wintab->last_axis_data[i],
+ &axes[i]);
+ if (use == GDK_AXIS_X)
+ temp_x = axes[i];
+ else if (use == GDK_AXIS_Y)
+ temp_y = axes[i];
+
+ break;
+ default:
+ _gdk_device_translate_axis (device, i,
+ device_wintab->last_axis_data[i],
+ &axes[i]);
+ break;
+ }
+ }
+
+ if (x)
+ *x = temp_x;
+
+ if (y)
+ *y = temp_y;
+}
+
+void
+_gdk_input_check_extension_events (GdkDevice *device)
+{
+ GSList *l;
+
+ if (!GDK_IS_DEVICE_WINTAB (device))
+ return;
+
+ for (l = input_windows; l; l = l->next)
+ {
+ GdkWindowObject *window_private;
+ GdkEventMask event_mask = 0;
+
+ window_private = l->data;
+
+ if (gdk_device_get_mode (device) != GDK_MODE_DISABLED)
+ event_mask = window_private->extension_events;
+
+ gdk_window_set_device_events (GDK_WINDOW (window_private),
+ device, event_mask);
+ }
+}
diff --git a/gdk/win32/gdkdevice-wintab.h b/gdk/win32/gdkdevice-wintab.h
new file mode 100644
index 0000000000..79fae8a8e2
--- /dev/null
+++ b/gdk/win32/gdkdevice-wintab.h
@@ -0,0 +1,79 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GDK_DEVICE_WINTAB_H__
+#define __GDK_DEVICE_WINTAB_H__
+
+#include <gdk/gdkdeviceprivate.h>
+
+#include <windows.h>
+#include <wintab.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_WINTAB (gdk_device_wintab_get_type ())
+#define GDK_DEVICE_WINTAB(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_WINTAB, GdkDeviceWintab))
+#define GDK_DEVICE_WINTAB_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_WINTAB, GdkDeviceWintabClass))
+#define GDK_IS_DEVICE_WINTAB(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_WINTAB))
+#define GDK_IS_DEVICE_WINTAB_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_WINTAB))
+#define GDK_DEVICE_WINTAB_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_WINTAB, GdkDeviceWintabClass))
+
+typedef struct _GdkDeviceWintab GdkDeviceWintab;
+typedef struct _GdkDeviceWintabClass GdkDeviceWintabClass;
+
+struct _GdkDeviceWintab
+{
+ GdkDevice parent_instance;
+
+ gint *last_axis_data;
+ gint button_state;
+
+ /* WINTAB stuff: */
+ HCTX hctx;
+ /* Cursor number */
+ UINT cursor;
+ /* The cursor's CSR_PKTDATA */
+ WTPKT pktdata;
+ /* Azimuth and altitude axis */
+ AXIS orientation_axes[2];
+};
+
+struct _GdkDeviceWintabClass
+{
+ GdkDeviceClass parent_class;
+};
+
+GType gdk_device_wintab_get_type (void) G_GNUC_CONST;
+
+GdkEventMask _gdk_device_wintab_get_events (GdkDeviceWintab *device,
+ GdkWindow *window);
+gboolean _gdk_device_wintab_get_window_coords (GdkWindow *window,
+ gdouble *root_x,
+ gdouble *root_y);
+void _gdk_device_wintab_update_window_coords (GdkWindow *window);
+
+void _gdk_device_wintab_translate_axes (GdkDeviceWintab *device,
+ GdkWindow *window,
+ gdouble *axes,
+ gdouble *x,
+ gdouble *y);
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_WINTAB_H__ */
diff --git a/gdk/win32/gdkdevicemanager-win32.c b/gdk/win32/gdkdevicemanager-win32.c
new file mode 100644
index 0000000000..eea814296b
--- /dev/null
+++ b/gdk/win32/gdkdevicemanager-win32.c
@@ -0,0 +1,1089 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include <gdk/gdk.h>
+#include "gdkprivate-win32.h"
+#include "gdkdevicemanager-win32.h"
+#include "gdkdeviceprivate.h"
+#include "gdkdevice-win32.h"
+#include "gdkdevice-wintab.h"
+
+#include <windows.h>
+#include <wintab.h>
+
+#define PACKETDATA (PK_CONTEXT | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION)
+/* We want everything in absolute mode */
+#define PACKETMODE (0)
+#include <pktdef.h>
+
+#define DEBUG_WINTAB 1 /* Verbose debug messages enabled */
+#define PROXIMITY_OUT_DELAY 200 /* In milliseconds, see set_ignore_core */
+#define TWOPI (2 * G_PI)
+
+static GList *wintab_contexts = NULL;
+static GdkWindow *wintab_window = NULL;
+static guint ignore_core_timer = 0;
+extern gint _gdk_input_ignore_core;
+
+typedef UINT (WINAPI *t_WTInfoA) (UINT a, UINT b, LPVOID c);
+typedef UINT (WINAPI *t_WTInfoW) (UINT a, UINT b, LPVOID c);
+typedef BOOL (WINAPI *t_WTEnable) (HCTX a, BOOL b);
+typedef HCTX (WINAPI *t_WTOpenA) (HWND a, LPLOGCONTEXTA b, BOOL c);
+typedef BOOL (WINAPI *t_WTOverlap) (HCTX a, BOOL b);
+typedef BOOL (WINAPI *t_WTPacket) (HCTX a, UINT b, LPVOID c);
+typedef int (WINAPI *t_WTQueueSizeSet) (HCTX a, int b);
+
+static t_WTInfoA p_WTInfoA;
+static t_WTInfoW p_WTInfoW;
+static t_WTEnable p_WTEnable;
+static t_WTOpenA p_WTOpenA;
+static t_WTOverlap p_WTOverlap;
+static t_WTPacket p_WTPacket;
+static t_WTQueueSizeSet p_WTQueueSizeSet;
+
+
+static void gdk_device_manager_win32_finalize (GObject *object);
+static void gdk_device_manager_win32_constructed (GObject *object);
+
+static GList * gdk_device_manager_win32_list_devices (GdkDeviceManager *device_manager,
+ GdkDeviceType type);
+
+
+G_DEFINE_TYPE (GdkDeviceManagerWin32, gdk_device_manager_win32, GDK_TYPE_DEVICE_MANAGER)
+
+static void
+gdk_device_manager_win32_class_init (GdkDeviceManagerWin32Class *klass)
+{
+ GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gdk_device_manager_win32_finalize;
+ object_class->constructed = gdk_device_manager_win32_constructed;
+ device_manager_class->list_devices = gdk_device_manager_win32_list_devices;
+}
+
+static GdkDevice *
+create_core_pointer (GdkDeviceManager *device_manager)
+{
+ return g_object_new (GDK_TYPE_DEVICE_WIN32,
+ "name", "Core Pointer",
+ "type", GDK_DEVICE_TYPE_MASTER,
+ "input-source", GDK_SOURCE_MOUSE,
+ "input-mode", GDK_MODE_SCREEN,
+ "has-cursor", TRUE,
+ "display", _gdk_display,
+ "device-manager", device_manager,
+ NULL);
+}
+
+static GdkDevice *
+create_core_keyboard (GdkDeviceManager *device_manager)
+{
+ return g_object_new (GDK_TYPE_DEVICE_WIN32,
+ "name", "Core Keyboard",
+ "type", GDK_DEVICE_TYPE_MASTER,
+ "input-source", GDK_SOURCE_KEYBOARD,
+ "input-mode", GDK_MODE_SCREEN,
+ "has-cursor", FALSE,
+ "display", _gdk_display,
+ "device-manager", device_manager,
+ NULL);
+}
+
+static void
+gdk_device_manager_win32_init (GdkDeviceManagerWin32 *device_manager_win32)
+{
+}
+
+static void
+gdk_device_manager_win32_finalize (GObject *object)
+{
+ GdkDeviceManagerWin32 *device_manager_win32;
+
+ device_manager_win32 = GDK_DEVICE_MANAGER_WIN32 (object);
+
+ g_object_unref (device_manager_win32->core_pointer);
+ g_object_unref (device_manager_win32->core_keyboard);
+
+ G_OBJECT_CLASS (gdk_device_manager_win32_parent_class)->finalize (object);
+}
+
+#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");
+ 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",
+ (guint) lc->lcBtnDnMask, (guint) lc->lcBtnUpMask);
+ g_print ("lcInOrgX = %ld, lcInOrgY = %ld, lcInOrgZ = %ld\n",
+ lc->lcInOrgX, lc->lcInOrgY, lc->lcInOrgZ);
+ g_print ("lcInExtX = %ld, lcInExtY = %ld, lcInExtZ = %ld\n",
+ lc->lcInExtX, lc->lcInExtY, lc->lcInExtZ);
+ g_print ("lcOutOrgX = %ld, lcOutOrgY = %ld, lcOutOrgZ = %ld\n",
+ lc->lcOutOrgX, lc->lcOutOrgY, lc->lcOutOrgZ);
+ g_print ("lcOutExtX = %ld, lcOutExtY = %ld, lcOutExtZ = %ld\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.);
+}
+
+static void
+print_cursor (int index)
+{
+ int size;
+ int i;
+ char *name;
+ BOOL active;
+ WTPKT wtpkt;
+ BYTE buttons;
+ BYTE buttonbits;
+ char *btnnames;
+ char *p;
+ BYTE buttonmap[32];
+ BYTE sysbtnmap[32];
+ BYTE npbutton;
+ UINT npbtnmarks[2];
+ UINT *npresponse;
+ BYTE tpbutton;
+ UINT tpbtnmarks[2];
+ UINT *tpresponse;
+ DWORD physid;
+ UINT mode;
+ UINT minpktdata;
+ UINT minbuttons;
+ UINT capabilities;
+
+ size = (*p_WTInfoA) (WTI_CURSORS + index, CSR_NAME, NULL);
+ name = g_malloc (size + 1);
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_NAME, name);
+ g_print ("NAME: %s\n", name);
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_ACTIVE, &active);
+ g_print ("ACTIVE: %s\n", active ? "YES" : "NO");
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_PKTDATA, &wtpkt);
+ g_print ("PKTDATA: %#x:", (guint) wtpkt);
+#define BIT(x) if (wtpkt & PK_##x) g_print (" " #x)
+ BIT (CONTEXT);
+ BIT (STATUS);
+ BIT (TIME);
+ BIT (CHANGED);
+ BIT (SERIAL_NUMBER);
+ BIT (BUTTONS);
+ BIT (X);
+ BIT (Y);
+ BIT (Z);
+ BIT (NORMAL_PRESSURE);
+ BIT (TANGENT_PRESSURE);
+ BIT (ORIENTATION);
+ BIT (ROTATION);
+#undef BIT
+ g_print ("\n");
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_BUTTONS, &buttons);
+ g_print ("BUTTONS: %d\n", buttons);
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_BUTTONBITS, &buttonbits);
+ g_print ("BUTTONBITS: %d\n", buttonbits);
+ size = (*p_WTInfoA) (WTI_CURSORS + index, CSR_BTNNAMES, NULL);
+ g_print ("BTNNAMES:");
+ if (size > 0)
+ {
+ btnnames = g_malloc (size + 1);
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_BTNNAMES, btnnames);
+ p = btnnames;
+ while (*p)
+ {
+ g_print (" %s", p);
+ p += strlen (p) + 1;
+ }
+ }
+ g_print ("\n");
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_BUTTONMAP, buttonmap);
+ g_print ("BUTTONMAP:");
+ for (i = 0; i < buttons; i++)
+ g_print (" %d", buttonmap[i]);
+ g_print ("\n");
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_SYSBTNMAP, sysbtnmap);
+ g_print ("SYSBTNMAP:");
+ for (i = 0; i < buttons; i++)
+ g_print (" %d", sysbtnmap[i]);
+ g_print ("\n");
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_NPBUTTON, &npbutton);
+ g_print ("NPBUTTON: %d\n", npbutton);
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_NPBTNMARKS, npbtnmarks);
+ g_print ("NPBTNMARKS: %d %d\n", npbtnmarks[0], npbtnmarks[1]);
+ size = (*p_WTInfoA) (WTI_CURSORS + index, CSR_NPRESPONSE, NULL);
+ g_print ("NPRESPONSE:");
+ if (size > 0)
+ {
+ npresponse = g_malloc (size);
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_NPRESPONSE, npresponse);
+ for (i = 0; i < size / sizeof (UINT); i++)
+ g_print (" %d", npresponse[i]);
+ }
+ g_print ("\n");
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_TPBUTTON, &tpbutton);
+ g_print ("TPBUTTON: %d\n", tpbutton);
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_TPBTNMARKS, tpbtnmarks);
+ g_print ("TPBTNMARKS: %d %d\n", tpbtnmarks[0], tpbtnmarks[1]);
+ size = (*p_WTInfoA) (WTI_CURSORS + index, CSR_TPRESPONSE, NULL);
+ g_print ("TPRESPONSE:");
+ if (size > 0)
+ {
+ tpresponse = g_malloc (size);
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_TPRESPONSE, tpresponse);
+ for (i = 0; i < size / sizeof (UINT); i++)
+ g_print (" %d", tpresponse[i]);
+ }
+ g_print ("\n");
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_PHYSID, &physid);
+ g_print ("PHYSID: %#x\n", (guint) physid);
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_CAPABILITIES, &capabilities);
+ g_print ("CAPABILITIES: %#x:", capabilities);
+#define BIT(x) if (capabilities & CRC_##x) g_print (" " #x)
+ BIT (MULTIMODE);
+ BIT (AGGREGATE);
+ BIT (INVERT);
+#undef BIT
+ g_print ("\n");
+ if (capabilities & CRC_MULTIMODE)
+ {
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_MODE, &mode);
+ g_print ("MODE: %d\n", mode);
+ }
+ if (capabilities & CRC_AGGREGATE)
+ {
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_MINPKTDATA, &minpktdata);
+ g_print ("MINPKTDATA: %d\n", minpktdata);
+ (*p_WTInfoA) (WTI_CURSORS + index, CSR_MINBUTTONS, &minbuttons);
+ g_print ("MINBUTTONS: %d\n", minbuttons);
+ }
+}
+#endif
+
+static void
+_gdk_input_wintab_init_check (GdkDeviceManagerWin32 *device_manager)
+{
+ 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];
+ int i, devix, cursorix, num_axes = 0;
+ wchar_t devname[100], csrname[100];
+ gchar *devname_utf8, *csrname_utf8, *device_name;
+ BOOL defcontext_done;
+ HMODULE wintab32;
+
+ if (wintab_initialized)
+ return;
+
+ wintab_initialized = TRUE;
+
+ wintab_contexts = NULL;
+
+ if (_gdk_input_ignore_wintab)
+ return;
+
+ if ((wintab32 = LoadLibrary ("wintab32.dll")) == NULL)
+ return;
+
+ if ((p_WTInfoA = (t_WTInfoA) GetProcAddress (wintab32, "WTInfoA")) == NULL)
+ return;
+ if ((p_WTInfoW = (t_WTInfoW) GetProcAddress (wintab32, "WTInfoW")) == NULL)
+ return;
+ if ((p_WTEnable = (t_WTEnable) GetProcAddress (wintab32, "WTEnable")) == NULL)
+ return;
+ if ((p_WTOpenA = (t_WTOpenA) GetProcAddress (wintab32, "WTOpenA")) == NULL)
+ return;
+ if ((p_WTOverlap = (t_WTOverlap) GetProcAddress (wintab32, "WTOverlap")) == NULL)
+ return;
+ if ((p_WTPacket = (t_WTPacket) GetProcAddress (wintab32, "WTPacket")) == NULL)
+ return;
+ if ((p_WTQueueSizeSet = (t_WTQueueSizeSet) GetProcAddress (wintab32, "WTQueueSizeSet")) == NULL)
+ return;
+
+ if (!(*p_WTInfoA) (0, 0, NULL))
+ return;
+
+ (*p_WTInfoA) (WTI_INTERFACE, IFC_SPECVERSION, &specversion);
+ GDK_NOTE (INPUT, g_print ("Wintab interface version %d.%d\n",
+ HIBYTE (specversion), LOBYTE (specversion)));
+ (*p_WTInfoA) (WTI_INTERFACE, IFC_NDEVICES, &ndevices);
+ (*p_WTInfoA) (WTI_INTERFACE, IFC_NCURSORS, &ncursors);
+#if DEBUG_WINTAB
+ GDK_NOTE (INPUT, 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_wintab_init: gdk_window_new failed");
+ return;
+ }
+ g_object_ref (wintab_window);
+
+ for (devix = 0; devix < ndevices; devix++)
+ {
+ LOGCONTEXT lc;
+
+ /* We open the Wintab device (hmm, what if there are several, or
+ * can there even be several, probably not?) as a system
+ * pointing device, i.e. it controls the normal Windows
+ * cursor. This seems much more natural.
+ */
+
+ (*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("Device %d: %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)
+ {
+ /* Try to get device-specific default context */
+ /* Some drivers, e.g. Aiptek, don't provide this info */
+ if ((*p_WTInfoA) (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
+ }
+
+ if (!defcontext_done)
+ (*p_WTInfoA) (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 = 0;
+ 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)));
+#endif
+ hctx = g_new (HCTX, 1);
+ if ((*hctx = (*p_WTOpenA) (GDK_WINDOW_HWND (wintab_window), &lc, TRUE)) == NULL)
+ {
+ g_warning ("gdk_input_wintab_init: WTOpen failed");
+ return;
+ }
+ GDK_NOTE (INPUT, g_print ("opened Wintab device %d %p\n",
+ devix, *hctx));
+
+ wintab_contexts = g_list_append (wintab_contexts, hctx);
+#if 0
+ (*p_WTEnable) (*hctx, TRUE);
+#endif
+ (*p_WTOverlap) (*hctx, TRUE);
+
+#if DEBUG_WINTAB
+ GDK_NOTE (INPUT, (g_print("context for device %d after WTOpen:\n", devix),
+ print_lc(&lc)));
+#endif
+ /* Increase packet queue size to reduce the risk of lost packets.
+ * According to the specs, if the function fails we must try again
+ * with a smaller queue size.
+ */
+ GDK_NOTE (INPUT, g_print("Attempting to increase queue size\n"));
+ for (i = 32; i >= 1; i >>= 1)
+ {
+ if ((*p_WTQueueSizeSet) (*hctx, i))
+ {
+ GDK_NOTE (INPUT, g_print("Queue size set to %d\n", i));
+ break;
+ }
+ }
+ if (!i)
+ GDK_NOTE (INPUT, g_print("Whoops, no queue size could be set\n"));
+ for (cursorix = firstcsr; cursorix < firstcsr + ncsrtypes; cursorix++)
+ {
+#ifdef DEBUG_WINTAB
+ GDK_NOTE (INPUT, (g_print("Cursor %d:\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_SLAVE,
+ "source", GDK_SOURCE_PEN,
+ "mode", GDK_MODE_SCREEN,
+ "has-cursor", FALSE,
+ "display", _gdk_display,
+ "device-manager", device_manager,
+ NULL);
+
+ 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++;
+ }
+
+ /* 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 ((device->pktdata & PK_ORIENTATION) && axis_or[0].axResolution == 0)
+ {
+ device->orientation_axes[0] = axis_or[0];
+ device->orientation_axes[1] = axis_or[1];
+
+ /* Wintab gives us aximuth 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: (%d) %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);
+
+ g_free (device_name);
+ }
+
+ g_free (devname_utf8);
+ }
+}
+
+static void
+gdk_device_manager_win32_constructed (GObject *object)
+{
+ GdkDeviceManagerWin32 *device_manager;
+
+ device_manager = GDK_DEVICE_MANAGER_WIN32 (object);
+ device_manager->core_pointer = create_core_pointer (GDK_DEVICE_MANAGER (device_manager));
+ device_manager->core_keyboard = create_core_keyboard (GDK_DEVICE_MANAGER (device_manager));
+
+ _gdk_device_set_associated_device (device_manager->core_pointer, device_manager->core_keyboard);
+ _gdk_device_set_associated_device (device_manager->core_keyboard, device_manager->core_pointer);
+
+ _gdk_input_wintab_init_check (device_manager);
+}
+
+static GList *
+gdk_device_manager_win32_list_devices (GdkDeviceManager *device_manager,
+ GdkDeviceType type)
+{
+ GdkDeviceManagerWin32 *device_manager_win32;
+ GList *devices = NULL;
+
+ device_manager_win32 = (GdkDeviceManagerWin32 *) device_manager;
+
+ if (type == GDK_DEVICE_TYPE_MASTER)
+ {
+ devices = g_list_prepend (devices, device_manager_win32->core_keyboard);
+ devices = g_list_prepend (devices, device_manager_win32->core_pointer);
+ }
+ else if (type == GDK_DEVICE_TYPE_FLOATING)
+ devices = g_list_copy (device_manager_win32->wintab_devices);
+
+ return devices;
+}
+
+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);
+ (*p_WTOverlap) (*hctx, TRUE);
+ tmp_list = tmp_list->next;
+ }
+}
+
+static void
+decode_tilt (gint *axis_data,
+ AXIS *axes,
+ PACKET *packet)
+{
+ double az, el;
+
+ /* As I don't have a tilt-sensing tablet,
+ * I cannot test this code.
+ */
+ 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;
+}
+
+/*
+ * 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
+ * on build_pointer_event_state from gdkevents-win32.c
+ */
+static guint
+get_modifier_key_state (void)
+{
+ guint state;
+
+ state = 0;
+ /* High-order bit is up/down, low order bit is toggled/untoggled */
+ if (GetKeyState (VK_CONTROL) < 0)
+ state |= GDK_CONTROL_MASK;
+ if (GetKeyState (VK_SHIFT) < 0)
+ state |= GDK_SHIFT_MASK;
+ if (GetKeyState (VK_MENU) < 0)
+ state |= GDK_MOD1_MASK;
+ if (GetKeyState (VK_CAPITAL) & 0x1)
+ state |= GDK_LOCK_MASK;
+
+ return state;
+}
+
+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 = gdk_threads_add_timeout (PROXIMITY_OUT_DELAY,
+ ignore_core_timefunc, NULL);
+}
+
+static GdkDeviceWintab *
+_gdk_device_manager_find_wintab_device (HCTX hctx,
+ UINT cursor)
+{
+ GdkDeviceManagerWin32 *device_manager;
+ GdkDeviceWintab *device;
+ GList *tmp_list;
+
+ device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (_gdk_display));
+ tmp_list = device_manager->wintab_devices;
+
+ while (tmp_list)
+ {
+ device = tmp_list->data;
+ tmp_list = tmp_list->next;
+
+ if (device->hctx == hctx &&
+ device->cursor == cursor)
+ return device;
+ }
+
+ return NULL;
+}
+
+gboolean
+_gdk_input_other_event (GdkEvent *event,
+ MSG *msg,
+ GdkWindow *window)
+{
+ GdkDisplay *display;
+ GdkWindowObject *obj;
+ GdkDeviceWintab *device = NULL;
+ GdkDeviceGrabInfo *last_grab;
+ GdkEventMask masktest;
+ guint key_state;
+ POINT pt;
+
+ PACKET packet;
+ gdouble root_x, root_y;
+ gint num_axes;
+ gint x, y;
+ guint translated_buttons, button_diff, button_mask;
+ /* Translation from tablet button state to GDK button state for
+ * buttons 1-3 - swap button 2 and 3.
+ */
+ static guint button_map[8] = {0, 1, 4, 5, 2, 3, 6, 7};
+
+ if (event->any.window != wintab_window)
+ {
+ g_warning ("_gdk_input_other_event: not wintab_window?");
+ return FALSE;
+ }
+
+ window = gdk_window_at_pointer (&x, &y);
+ if (window == NULL)
+ window = _gdk_root;
+
+ g_object_ref (window);
+ display = gdk_drawable_get_display (window);
+
+ GDK_NOTE (EVENTS_OR_INPUT,
+ g_print ("_gdk_input_other_event: window=%p %+d%+d\n",
+ GDK_WINDOW_HWND (window), x, y));
+
+ if (msg->message == WT_PACKET)
+ {
+ if (!(*p_WTPacket) ((HCTX) msg->lParam, msg->wParam, &packet))
+ return FALSE;
+ }
+
+ obj = GDK_WINDOW_OBJECT (window);
+
+ switch (msg->message)
+ {
+ case WT_PACKET:
+ /* Don't produce any button or motion events while a window is being
+ * moved or resized, see bug #151090.
+ */
+ if (_modal_operation_in_progress)
+ {
+ GDK_NOTE (EVENTS_OR_INPUT, g_print ("... ignored when moving/sizing\n"));
+ return FALSE;
+ }
+
+ if ((device = _gdk_device_manager_find_wintab_device ((HCTX) msg->lParam,
+ packet.pkCursor)) == NULL)
+ return FALSE;
+
+ if (gdk_device_get_mode (GDK_DEVICE (device)) == GDK_MODE_DISABLED)
+ return FALSE;
+
+ last_grab = _gdk_display_get_last_device_grab (_gdk_display, GDK_DEVICE (device));
+
+ if (last_grab && last_grab->window)
+ {
+ g_object_unref (window);
+
+ window = g_object_ref (last_grab->window);
+ obj = GDK_WINDOW_OBJECT (window);
+ }
+
+ if (window == _gdk_root)
+ {
+ GDK_NOTE (EVENTS_OR_INPUT, g_print ("... is root\n"));
+ return FALSE;
+ }
+
+ num_axes = 0;
+ if (device->pktdata & PK_X)
+ device->last_axis_data[num_axes++] = packet.pkX;
+ if (device->pktdata & PK_Y)
+ device->last_axis_data[num_axes++] = packet.pkY;
+ if (device->pktdata & PK_NORMAL_PRESSURE)
+ device->last_axis_data[num_axes++] = packet.pkNormalPressure;
+ if (device->pktdata & PK_ORIENTATION)
+ {
+ decode_tilt (device->last_axis_data + num_axes,
+ device->orientation_axes, &packet);
+ num_axes += 2;
+ }
+
+ translated_buttons = button_map[packet.pkButtons & 0x07] | (packet.pkButtons & ~0x07);
+
+ if (translated_buttons != device->button_state)
+ {
+ /* At least one button has changed state so produce a button event
+ * If more than one button has changed state (unlikely),
+ * just care about the first and act on the next the next time
+ * we get a packet
+ */
+ button_diff = translated_buttons ^ device->button_state;
+
+ /* Gdk buttons are numbered 1.. */
+ event->button.button = 1;
+
+ for (button_mask = 1; button_mask != 0x80000000;
+ button_mask <<= 1, event->button.button++)
+ {
+ if (button_diff & button_mask)
+ {
+ /* Found a button that has changed state */
+ break;
+ }
+ }
+
+ if (!(translated_buttons & button_mask))
+ {
+ event->any.type = GDK_BUTTON_RELEASE;
+ masktest = GDK_BUTTON_RELEASE_MASK;
+ }
+ else
+ {
+ event->any.type = GDK_BUTTON_PRESS;
+ masktest = GDK_BUTTON_PRESS_MASK;
+ }
+ device->button_state ^= button_mask;
+ }
+ else
+ {
+ event->any.type = GDK_MOTION_NOTIFY;
+ masktest = GDK_POINTER_MOTION_MASK;
+ if (device->button_state & (1 << 0))
+ masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK;
+ if (device->button_state & (1 << 1))
+ masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON2_MOTION_MASK;
+ if (device->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.
+ */
+ while (gdk_window_get_device_events (window, GDK_DEVICE (device)) == 0)
+ {
+ GDK_NOTE (EVENTS_OR_INPUT, g_print ("... not selected\n"));
+
+ if (obj->parent == GDK_WINDOW_OBJECT (_gdk_root))
+ return FALSE;
+
+ /* It is not good to propagate the extended events up to the parent
+ * if this window wants normal (not extended) motion/button events */
+ if (obj->event_mask & masktest)
+ {
+ GDK_NOTE (EVENTS_OR_INPUT,
+ g_print ("... wants ordinary event, ignoring this\n"));
+ return FALSE;
+ }
+
+ pt.x = x;
+ pt.y = y;
+ ClientToScreen (GDK_WINDOW_HWND (window), &pt);
+ g_object_unref (window);
+ window = (GdkWindow *) obj->parent;
+ obj = GDK_WINDOW_OBJECT (window);
+ g_object_ref (window);
+ 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_WINDOW_HWND (window), x, y));
+ }
+
+ if (gdk_window_get_device_events (window, GDK_DEVICE (device)) == 0)
+ return FALSE;
+
+ event->any.window = window;
+ key_state = get_modifier_key_state ();
+ if (event->any.type == GDK_BUTTON_PRESS ||
+ event->any.type == GDK_BUTTON_RELEASE)
+ {
+ event->button.time = _gdk_win32_get_next_tick (msg->time);
+ gdk_event_set_device (event, GDK_DEVICE (device));
+
+ event->button.axes = g_new (gdouble, num_axes);
+ _gdk_device_wintab_get_window_coords (window, &root_x, &root_y);
+
+ _gdk_device_wintab_translate_axes (device,
+ window,
+ event->button.axes,
+ &event->button.x,
+ &event->button.y);
+
+ event->button.x_root = event->button.x + root_x;
+ event->button.y_root = event->button.y + root_y;
+
+ event->button.state =
+ key_state | ((device->button_state << 8)
+ & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
+ | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
+ | GDK_BUTTON5_MASK));
+
+ GDK_NOTE (EVENTS_OR_INPUT,
+ g_print ("WINTAB button %s:%d %g,%g\n",
+ (event->button.type == GDK_BUTTON_PRESS ?
+ "press" : "release"),
+ event->button.button,
+ event->button.x, event->button.y));
+ }
+ else
+ {
+ event->motion.time = _gdk_win32_get_next_tick (msg->time);
+ event->motion.is_hint = FALSE;
+ gdk_event_set_device (event, GDK_DEVICE (device));
+
+ event->motion.axes = g_new (gdouble, num_axes);
+ _gdk_device_wintab_get_window_coords (window, &root_x, &root_y);
+
+ _gdk_device_wintab_translate_axes (device,
+ window,
+ event->motion.axes,
+ &event->motion.x,
+ &event->motion.y);
+
+ event->motion.x_root = event->motion.x + root_x;
+ event->motion.y_root = event->motion.y + root_y;
+
+ event->motion.state =
+ key_state | ((device->button_state << 8)
+ & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
+ | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
+ | GDK_BUTTON5_MASK));
+
+ GDK_NOTE (EVENTS_OR_INPUT,
+ g_print ("WINTAB motion: %g,%g\n",
+ event->motion.x, event->motion.y));
+ }
+ return TRUE;
+
+ case WT_PROXIMITY:
+ if (LOWORD (msg->lParam) == 0)
+ {
+ event->proximity.type = GDK_PROXIMITY_OUT;
+ set_ignore_core (FALSE);
+ }
+ else
+ {
+ event->proximity.type = GDK_PROXIMITY_IN;
+ set_ignore_core (TRUE);
+ }
+ event->proximity.time = _gdk_win32_get_next_tick (msg->time);
+ gdk_event_set_device (event, GDK_DEVICE (device));
+
+ GDK_NOTE (EVENTS_OR_INPUT,
+ g_print ("WINTAB proximity %s\n",
+ (event->proximity.type == GDK_PROXIMITY_IN ?
+ "in" : "out")));
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/gdk/win32/gdkdevicemanager-win32.h b/gdk/win32/gdkdevicemanager-win32.h
new file mode 100644
index 0000000000..69d26b7561
--- /dev/null
+++ b/gdk/win32/gdkdevicemanager-win32.h
@@ -0,0 +1,59 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GDK_DEVICE_MANAGER_WIN32_H__
+#define __GDK_DEVICE_MANAGER_WIN32_H__
+
+#include <gdk/gdkdevicemanager.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_MANAGER_WIN32 (gdk_device_manager_win32_get_type ())
+#define GDK_DEVICE_MANAGER_WIN32(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_MANAGER_WIN32, GdkDeviceManagerWin32))
+#define GDK_DEVICE_MANAGER_WIN32_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_MANAGER_WIN32, GdkDeviceManagerWin32Class))
+#define GDK_IS_DEVICE_MANAGER_WIN32(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_MANAGER_WIN32))
+#define GDK_IS_DEVICE_MANAGER_WIN32_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_MANAGER_WIN32))
+#define GDK_DEVICE_MANAGER_WIN32_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_MANAGER_WIN32, GdkDeviceManagerWin32Class))
+
+typedef struct _GdkDeviceManagerWin32 GdkDeviceManagerWin32;
+typedef struct _GdkDeviceManagerWin32Class GdkDeviceManagerWin32Class;
+
+struct _GdkDeviceManagerWin32
+{
+ GdkDeviceManager parent_object;
+ GdkDevice *core_pointer;
+ GdkDevice *core_keyboard;
+ GList *wintab_devices;
+};
+
+struct _GdkDeviceManagerWin32Class
+{
+ GdkDeviceManagerClass parent_class;
+};
+
+GType gdk_device_manager_win32_get_type (void) G_GNUC_CONST;
+
+void _gdk_input_set_tablet_active (void);
+gboolean _gdk_input_other_event (GdkEvent *event,
+ MSG *msg,
+ GdkWindow *window);
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_MANAGER_WIN32_H__ */
diff --git a/gdk/win32/gdkdnd-win32.c b/gdk/win32/gdkdnd-win32.c
index f0b57a9b68..6436fb7817 100644
--- a/gdk/win32/gdkdnd-win32.c
+++ b/gdk/win32/gdkdnd-win32.c
@@ -98,6 +98,7 @@ typedef enum {
* this is used on both source and destination sides.
*/
struct _GdkDragContextPrivateWin32 {
+ GdkDevice *device;
gboolean being_finalized;
gint ref_count;
IUnknown *iface;
@@ -203,6 +204,39 @@ gdk_drag_context_new (void)
return g_object_new (GDK_TYPE_DRAG_CONTEXT, NULL);
}
+GdkDevice *
+gdk_drag_context_get_device (GdkDragContext *context)
+{
+ GdkDragContextPrivateWin32 *private;
+
+ g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), NULL);
+
+ private = PRIVATE_DATA (context);
+
+ return private->device;
+}
+
+void
+gdk_drag_context_set_device (GdkDragContext *context,
+ GdkDevice *device)
+{
+ GdkDragContextPrivateWin32 *private;
+
+ g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+ g_return_if_fail (GDK_IS_DEVICE (device));
+
+ private = PRIVATE_DATA (context);
+
+ if (private->device)
+ {
+ g_object_unref (private->device);
+ private->device = NULL;
+ }
+
+ if (device)
+ private->device = g_object_ref (device);
+}
+
static GdkDragContext *
gdk_drag_context_find (gboolean is_source,
GdkWindow *source,
@@ -425,24 +459,28 @@ dnd_event_put (GdkEventType type,
const POINTL pt,
gboolean to_dest_window)
{
- GdkEvent e;
- e.type = type;
+ GdkEvent *e;
+
+ e = gdk_event_new (type);
+
if (to_dest_window)
- e.dnd.window = context->dest_window;
+ e->dnd.window = context->dest_window;
else
- e.dnd.window = context->source_window;
- e.dnd.send_event = FALSE;
- e.dnd.context = context;
- e.dnd.time = GDK_CURRENT_TIME;
- e.dnd.x_root = pt.x + _gdk_offset_x;
- e.dnd.y_root = pt.x + _gdk_offset_y;
+ e->dnd.window = context->source_window;
+ e->dnd.send_event = FALSE;
+ e->dnd.context = g_object_ref (context);
+ e->dnd.time = GDK_CURRENT_TIME;
+ e->dnd.x_root = pt.x + _gdk_offset_x;
+ e->dnd.y_root = pt.x + _gdk_offset_y;
- g_object_ref (e.dnd.context);
- if (e.dnd.window != NULL)
- g_object_ref (e.dnd.window);
+ if (e->dnd.window != NULL)
+ g_object_ref (e->dnd.window);
- GDK_NOTE (EVENTS, _gdk_win32_print_event (&e));
- gdk_event_put (&e);
+ gdk_event_set_device (e, gdk_drag_context_get_device (context));
+
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (e));
+ gdk_event_put (e);
+ gdk_event_free (e);
}
static HRESULT STDMETHODCALLTYPE
@@ -1173,6 +1211,7 @@ target_context_new (GdkWindow *window)
{
target_drag_context *result;
GdkDragContextPrivateWin32 *private;
+ GdkDevice *device;
result = g_new0 (target_drag_context, 1);
@@ -1182,6 +1221,9 @@ target_context_new (GdkWindow *window)
result->context->protocol = GDK_DRAG_PROTO_OLE2;
result->context->is_source = FALSE;
+ device = gdk_display_get_core_pointer (_gdk_display);
+ gdk_drag_context_set_device (result->context, device);
+
result->context->source_window = NULL;
result->context->dest_window = window;
@@ -1208,6 +1250,7 @@ source_context_new (GdkWindow *window,
{
source_drag_context *result;
GdkDragContextPrivateWin32 *private;
+ GdkDevice *device;
result = g_new0 (source_drag_context, 1);
@@ -1217,6 +1260,9 @@ source_context_new (GdkWindow *window,
result->context->protocol = GDK_DRAG_PROTO_OLE2;
result->context->is_source = TRUE;
+ device = gdk_display_get_core_pointer (_gdk_display);
+ gdk_drag_context_set_device (result->context, device);
+
result->context->source_window = window;
g_object_ref (window);
@@ -1428,6 +1474,7 @@ gdk_dropfiles_filter (GdkXEvent *xev,
POINT pt;
gint nfiles, i;
gchar *fileName, *linkedFile;
+ GdkDevice *device;
if (msg->message == WM_DROPFILES)
{
@@ -1437,6 +1484,9 @@ gdk_dropfiles_filter (GdkXEvent *xev,
context->protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
context->is_source = FALSE;
+ device = gdk_display_get_core_pointer (_gdk_display);
+ gdk_drag_context_set_device (context, device);
+
context->source_window = _gdk_root;
g_object_ref (context->source_window);
@@ -1452,6 +1502,7 @@ gdk_dropfiles_filter (GdkXEvent *xev,
event->dnd.type = GDK_DROP_START;
event->dnd.context = current_dest_drag;
+ gdk_event_set_device (event, gdk_drag_context_get_device (current_dest_drag));
hdrop = (HANDLE) msg->wParam;
DragQueryPoint (hdrop, &pt);
@@ -1615,7 +1666,7 @@ static void
local_send_leave (GdkDragContext *context,
guint32 time)
{
- GdkEvent tmp_event;
+ GdkEvent *tmp_event;
GDK_NOTE (DND, g_print ("local_send_leave: context=%p current_dest_drag=%p\n",
context,
@@ -1625,17 +1676,20 @@ local_send_leave (GdkDragContext *context,
(current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
(current_dest_drag->source_window == context->source_window))
{
- tmp_event.dnd.type = GDK_DRAG_LEAVE;
- tmp_event.dnd.window = context->dest_window;
+ tmp_event = gdk_event_new (GDK_DRAG_LEAVE);
+
+ tmp_event->dnd.window = g_object_ref (context->dest_window);
/* Pass ownership of context to the event */
- tmp_event.dnd.send_event = FALSE;
- tmp_event.dnd.context = current_dest_drag;
- tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+ tmp_event->dnd.send_event = FALSE;
+ tmp_event->dnd.context = g_object_ref (current_dest_drag);
+ tmp_event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+ gdk_event_set_device (tmp_event, gdk_drag_context_get_device (context));
current_dest_drag = NULL;
- GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
- gdk_event_put (&tmp_event);
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event));
+ gdk_event_put (tmp_event);
+ gdk_event_free (tmp_event);
}
}
@@ -1643,9 +1697,10 @@ static void
local_send_enter (GdkDragContext *context,
guint32 time)
{
- GdkEvent tmp_event;
+ GdkEvent *tmp_event;
GdkDragContextPrivateWin32 *private;
GdkDragContext *new_context;
+ GdkDevice *device;
GDK_NOTE (DND, g_print ("local_send_enter: context=%p current_dest_drag=%p\n",
context,
@@ -1663,6 +1718,9 @@ local_send_enter (GdkDragContext *context,
new_context->protocol = GDK_DRAG_PROTO_LOCAL;
new_context->is_source = FALSE;
+ device = gdk_display_get_core_pointer (_gdk_display);
+ gdk_drag_context_set_device (new_context, device);
+
new_context->source_window = context->source_window;
g_object_ref (new_context->source_window);
@@ -1676,16 +1734,18 @@ local_send_enter (GdkDragContext *context,
GDK_PROPERTY_CHANGE_MASK);
new_context->actions = context->actions;
- tmp_event.type = GDK_DRAG_ENTER;
- tmp_event.dnd.window = context->dest_window;
- tmp_event.dnd.send_event = FALSE;
- tmp_event.dnd.context = new_context;
- tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+ tmp_event = gdk_event_new (GDK_DRAG_ENTER);
+ tmp_event->dnd.window = g_object_ref (context->dest_window);
+ tmp_event->dnd.send_event = FALSE;
+ tmp_event->dnd.context = g_object_ref (new_context);
+ tmp_event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+ gdk_event_set_device (tmp_event, gdk_drag_context_get_device (context));
current_dest_drag = new_context;
- GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
- gdk_event_put (&tmp_event);
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event));
+ gdk_event_put (tmp_event);
+ gdk_event_free (tmp_event);
}
static void
@@ -1695,7 +1755,7 @@ local_send_motion (GdkDragContext *context,
GdkDragAction action,
guint32 time)
{
- GdkEvent tmp_event;
+ GdkEvent *tmp_event;
GDK_NOTE (DND, g_print ("local_send_motion: context=%p (%d,%d) current_dest_drag=%p\n",
context, x_root, y_root,
@@ -1705,24 +1765,26 @@ local_send_motion (GdkDragContext *context,
(current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
(current_dest_drag->source_window == context->source_window))
{
- tmp_event.type = GDK_DRAG_MOTION;
- tmp_event.dnd.window = current_dest_drag->dest_window;
- tmp_event.dnd.send_event = FALSE;
- tmp_event.dnd.context = current_dest_drag;
- tmp_event.dnd.time = time;
+ tmp_event = gdk_event_new (GDK_DRAG_MOTION);
+ tmp_event->dnd.window = g_object_ref (current_dest_drag->dest_window);
+ tmp_event->dnd.send_event = FALSE;
+ tmp_event->dnd.context = g_object_ref (current_dest_drag);
+ tmp_event->dnd.time = time;
+ gdk_event_set_device (tmp_event, gdk_drag_context_get_device (current_dest_drag));
current_dest_drag->suggested_action = action;
- tmp_event.dnd.x_root = x_root;
- tmp_event.dnd.y_root = y_root;
+ tmp_event->dnd.x_root = x_root;
+ tmp_event->dnd.y_root = y_root;
PRIVATE_DATA (current_dest_drag)->last_pt.x = x_root - _gdk_offset_x;
PRIVATE_DATA (current_dest_drag)->last_pt.y = y_root - _gdk_offset_y;
PRIVATE_DATA (context)->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
- GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
- gdk_event_put (&tmp_event);
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event));
+ gdk_event_put (tmp_event);
+ gdk_event_free (tmp_event);
}
}
@@ -1730,7 +1792,7 @@ static void
local_send_drop (GdkDragContext *context,
guint32 time)
{
- GdkEvent tmp_event;
+ GdkEvent *tmp_event;
GDK_NOTE (DND, g_print ("local_send_drop: context=%p current_dest_drag=%p\n",
context,
@@ -1744,19 +1806,21 @@ local_send_drop (GdkDragContext *context,
private = PRIVATE_DATA (current_dest_drag);
/* Pass ownership of context to the event */
- tmp_event.type = GDK_DROP_START;
- tmp_event.dnd.window = current_dest_drag->dest_window;
- tmp_event.dnd.send_event = FALSE;
- tmp_event.dnd.context = current_dest_drag;
- tmp_event.dnd.time = GDK_CURRENT_TIME;
+ tmp_event = gdk_event_new (GDK_DROP_START);
+ tmp_event->dnd.window = g_object_ref (current_dest_drag->dest_window);
+ tmp_event->dnd.send_event = FALSE;
+ tmp_event->dnd.context = g_object_ref (current_dest_drag);
+ tmp_event->dnd.time = GDK_CURRENT_TIME;
+ gdk_event_set_device (tmp_event, gdk_drag_context_get_device (current_dest_drag));
- tmp_event.dnd.x_root = private->last_pt.x + _gdk_offset_x;
- tmp_event.dnd.y_root = private->last_pt.y + _gdk_offset_y;
+ tmp_event->dnd.x_root = private->last_pt.x + _gdk_offset_x;
+ tmp_event->dnd.y_root = private->last_pt.y + _gdk_offset_y;
current_dest_drag = NULL;
- GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
- gdk_event_put (&tmp_event);
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event));
+ gdk_event_put (tmp_event);
+ gdk_event_free (tmp_event);
}
}
@@ -1787,11 +1851,15 @@ gdk_drag_begin (GdkWindow *window,
if (!use_ole2_dnd)
{
GdkDragContext *new_context;
+ GdkDevice *device;
g_return_val_if_fail (window != NULL, NULL);
new_context = gdk_drag_context_new ();
+ device = gdk_display_get_core_pointer (_gdk_display);
+ gdk_drag_context_set_device (new_context, device);
+
new_context->is_source = TRUE;
new_context->source_window = window;
@@ -2043,7 +2111,7 @@ gdk_drag_motion (GdkDragContext *context,
}
else
{
- GdkEvent tmp_event;
+ GdkEvent *tmp_event;
/* Send a leave to the last destination */
gdk_drag_do_leave (context, time);
@@ -2076,18 +2144,20 @@ gdk_drag_motion (GdkDragContext *context,
/* Push a status event, to let the client know that
* the drag changed
*/
- tmp_event.type = GDK_DRAG_STATUS;
- tmp_event.dnd.window = context->source_window;
+ tmp_event = gdk_event_new (GDK_DRAG_STATUS);
+ tmp_event->dnd.window = g_object_ref (context->source_window);
/* We use this to signal a synthetic status. Perhaps
* we should use an extra field...
*/
- tmp_event.dnd.send_event = TRUE;
+ tmp_event->dnd.send_event = TRUE;
- tmp_event.dnd.context = context;
- tmp_event.dnd.time = time;
+ tmp_event->dnd.context = g_object_ref (context);
+ tmp_event->dnd.time = time;
+ gdk_event_set_device (tmp_event, gdk_drag_context_get_device (context));
- GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
- gdk_event_put (&tmp_event);
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event));
+ gdk_event_put (tmp_event);
+ gdk_event_free (tmp_event);
}
/* Send a drag-motion event */
@@ -2176,7 +2246,7 @@ gdk_drag_status (GdkDragContext *context,
{
GdkDragContextPrivateWin32 *private;
GdkDragContext *src_context;
- GdkEvent tmp_event;
+ GdkEvent *tmp_event;
g_return_if_fail (context != NULL);
@@ -2205,19 +2275,21 @@ gdk_drag_status (GdkDragContext *context,
if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
private->drag_status = GDK_DRAG_STATUS_DRAG;
- tmp_event.type = GDK_DRAG_STATUS;
- tmp_event.dnd.window = context->source_window;
- tmp_event.dnd.send_event = FALSE;
- tmp_event.dnd.context = src_context;
- tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+ tmp_event = gdk_event_new (GDK_DRAG_STATUS);
+ tmp_event->dnd.window = g_object_ref (context->source_window);
+ tmp_event->dnd.send_event = FALSE;
+ tmp_event->dnd.context = g_object_ref (src_context);
+ tmp_event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+ gdk_event_set_device (tmp_event, gdk_drag_context_get_device (src_context));
if (action == GDK_ACTION_DEFAULT)
action = 0;
src_context->action = action;
- GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
- gdk_event_put (&tmp_event);
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event));
+ gdk_event_put (tmp_event);
+ gdk_event_free (tmp_event);
}
}
}
@@ -2246,7 +2318,7 @@ gdk_drop_finish (GdkDragContext *context,
{
GdkDragContextPrivateWin32 *private;
GdkDragContext *src_context;
- GdkEvent tmp_event;
+ GdkEvent *tmp_event;
g_return_if_fail (context != NULL);
@@ -2261,13 +2333,15 @@ gdk_drop_finish (GdkDragContext *context,
context->dest_window);
if (src_context)
{
- tmp_event.type = GDK_DROP_FINISHED;
- tmp_event.dnd.window = src_context->source_window;
- tmp_event.dnd.send_event = FALSE;
- tmp_event.dnd.context = src_context;
-
- GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
- gdk_event_put (&tmp_event);
+ tmp_event = gdk_event_new (GDK_DROP_FINISHED);
+ tmp_event->dnd.window = g_object_ref (src_context->source_window);
+ tmp_event->dnd.send_event = FALSE;
+ tmp_event->dnd.context = g_object_ref (src_context);
+ gdk_event_set_device (tmp_event, gdk_drag_context_get_device (src_context));
+
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event));
+ gdk_event_put (tmp_event);
+ gdk_event_free (tmp_event);
}
}
else
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index 219da60b03..b5c6174473 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -47,8 +47,10 @@
#include "gdk.h"
#include "gdkprivate-win32.h"
-#include "gdkinput-win32.h"
#include "gdkkeysyms.h"
+#include "gdkdevicemanager-win32.h"
+#include "gdkdeviceprivate.h"
+#include "gdkdevice-wintab.h"
#include <windowsx.h>
@@ -101,6 +103,7 @@ static gboolean is_modally_blocked (GdkWindow *window);
*/
static GList *client_filters; /* Filters for client messages */
+extern gint _gdk_input_ignore_core;
static HCURSOR p_grab_cursor;
@@ -199,31 +202,44 @@ _gdk_win32_get_next_tick (gulong suggested_tick)
}
static void
-generate_focus_event (GdkWindow *window,
- gboolean in)
+generate_focus_event (GdkDeviceManager *device_manager,
+ GdkWindow *window,
+ gboolean in)
{
+ GdkDevice *device;
GdkEvent *event;
+ device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard;
+
event = gdk_event_new (GDK_FOCUS_CHANGE);
event->focus_change.window = window;
event->focus_change.in = in;
+ gdk_event_set_device (event, device);
append_event (event);
}
static void
-generate_grab_broken_event (GdkWindow *window,
- gboolean keyboard,
- GdkWindow *grab_window)
+generate_grab_broken_event (GdkDeviceManager *device_manager,
+ GdkWindow *window,
+ gboolean keyboard,
+ GdkWindow *grab_window)
{
GdkEvent *event = gdk_event_new (GDK_GRAB_BROKEN);
+ GdkDevice *device;
+
+ if (keyboard)
+ device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard;
+ else
+ device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_pointer;
event->grab_broken.window = window;
event->grab_broken.send_event = 0;
event->grab_broken.keyboard = keyboard;
event->grab_broken.implicit = FALSE;
event->grab_broken.grab_window = grab_window;
-
+ gdk_event_set_device (event, device);
+
append_event (event);
}
@@ -443,17 +459,19 @@ event_mask_string (GdkEventMask mask)
#endif
GdkGrabStatus
-_gdk_windowing_pointer_grab (GdkWindow *window,
- GdkWindow *native_window,
- gboolean owner_events,
- GdkEventMask event_mask,
- GdkWindow *confine_to,
- GdkCursor *cursor,
- guint32 time)
+_gdk_windowing_device_grab (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow *native_window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time)
{
HCURSOR hcursor;
GdkCursorPrivate *cursor_private;
gint return_val;
+ GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) native_window)->impl);
g_return_val_if_fail (window != NULL, 0);
g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
@@ -466,54 +484,53 @@ _gdk_windowing_pointer_grab (GdkWindow *window,
else if ((hcursor = CopyCursor (cursor_private->hcursor)) == NULL)
WIN32_API_FAILED ("CopyCursor");
- return_val = _gdk_input_grab_pointer (native_window,
- owner_events,
- event_mask,
- confine_to,
- time);
+ return_val = GDK_DEVICE_GET_CLASS (device)->grab (device,
+ native_window,
+ owner_events,
+ event_mask,
+ confine_to,
+ cursor,
+ time);
- if (return_val == GDK_GRAB_SUCCESS)
+ /* TODO_CSW: grab brokens, confine window, input_grab */
+ if (p_grab_cursor != NULL)
{
- GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) native_window)->impl);
-
- SetCapture (GDK_WINDOW_HWND (native_window));
- /* TODO_CSW: grab brokens, confine window, input_grab */
- if (p_grab_cursor != NULL)
- {
- if (GetCursor () == p_grab_cursor)
- SetCursor (NULL);
- DestroyCursor (p_grab_cursor);
- }
-
- p_grab_cursor = hcursor;
+ if (GetCursor () == p_grab_cursor)
+ SetCursor (NULL);
+ DestroyCursor (p_grab_cursor);
+ }
- if (p_grab_cursor != NULL)
- SetCursor (p_grab_cursor);
- else if (impl->hcursor != NULL)
- SetCursor (impl->hcursor);
- else
- SetCursor (LoadCursor (NULL, IDC_ARROW));
+ p_grab_cursor = hcursor;
- }
+ if (p_grab_cursor != NULL)
+ SetCursor (p_grab_cursor);
+ else if (impl->hcursor != NULL)
+ SetCursor (impl->hcursor);
+ else
+ SetCursor (LoadCursor (NULL, IDC_ARROW));
return return_val;
}
void
-gdk_display_pointer_ungrab (GdkDisplay *display,
- guint32 time)
+gdk_device_ungrab (GdkDevice *device,
+ guint32 time)
{
- GdkPointerGrabInfo *info;
+ GdkDeviceGrabInfo *info;
+ GdkDisplay *display;
+
+ g_return_if_fail (GDK_IS_DEVICE (device));
+
+ display = gdk_device_get_display (device);
+ info = _gdk_display_get_last_device_grab (display, device);
- info = _gdk_display_get_last_pointer_grab (display);
if (info)
{
info->serial_end = 0;
- ReleaseCapture ();
+ GDK_DEVICE_GET_CLASS (device)->ungrab (device, time);
}
- /* TODO_CSW: cursor, confines, etc */
- _gdk_display_pointer_grab_update (display, 0);
+ _gdk_display_device_grab_update (display, device, 0);
}
@@ -525,8 +542,11 @@ find_window_for_mouse_event (GdkWindow* reported_window,
POINTS points;
POINT pt;
GdkWindow* other_window = NULL;
+ GdkDeviceManagerWin32 *device_manager;
+
+ device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (_gdk_display));
- if (!_gdk_display_get_last_pointer_grab (_gdk_display))
+ if (!_gdk_display_get_last_device_grab (_gdk_display, device_manager->core_pointer))
return reported_window;
points = MAKEPOINTS (msg->lParam);
@@ -562,41 +582,6 @@ find_window_for_mouse_event (GdkWindow* reported_window,
return other_window;
}
-GdkGrabStatus
-gdk_keyboard_grab (GdkWindow *window,
- gboolean owner_events,
- guint32 time)
-{
- GdkDisplay *display;
- GdkWindow *toplevel;
-
- g_return_val_if_fail (window != NULL, 0);
- g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
-
- GDK_NOTE (EVENTS, g_print ("gdk_keyboard_grab %p%s\n",
- GDK_WINDOW_HWND (window), owner_events ? " OWNER_EVENTS" : ""));
-
- display = gdk_drawable_get_display (window);
- toplevel = gdk_window_get_toplevel (window);
-
- _gdk_display_set_has_keyboard_grab (display,
- window,
- toplevel,
- owner_events,
- 0,
- time);
-
- return GDK_GRAB_SUCCESS;
-}
-
-void
-gdk_display_keyboard_ungrab (GdkDisplay *display,
- guint32 time)
-{
- GDK_NOTE (EVENTS, g_print ("gdk_display_keyboard_ungrab\n"));
- _gdk_display_unset_has_keyboard_grab (display, FALSE);
-}
-
void
gdk_display_add_client_message_filter (GdkDisplay *display,
GdkAtom message_type,
@@ -1195,11 +1180,11 @@ do_show_window (GdkWindow *window, gboolean hide_window)
}
static void
-synthesize_enter_or_leave_event (GdkWindow *window,
- MSG *msg,
- GdkEventType type,
- GdkCrossingMode mode,
- GdkNotifyType detail)
+synthesize_enter_or_leave_event (GdkWindow *window,
+ MSG *msg,
+ GdkEventType type,
+ GdkCrossingMode mode,
+ GdkNotifyType detail)
{
GdkEvent *event;
POINT pt;
@@ -1219,12 +1204,13 @@ synthesize_enter_or_leave_event (GdkWindow *window,
event->crossing.detail = detail;
event->crossing.focus = TRUE; /* FIXME: Set correctly */
event->crossing.state = 0; /* FIXME: Set correctly */
+ gdk_event_set_device (event, _gdk_display->core_pointer);
append_event (event);
if (type == GDK_ENTER_NOTIFY &&
((GdkWindowObject *) window)->extension_events != 0)
- _gdk_input_enter_event (window);
+ _gdk_device_wintab_update_window_coords (window);
}
static void
@@ -1684,10 +1670,10 @@ handle_display_change (void)
}
static void
-generate_button_event (GdkEventType type,
- gint button,
- GdkWindow *window,
- MSG *msg)
+generate_button_event (GdkEventType type,
+ gint button,
+ GdkWindow *window,
+ MSG *msg)
{
GdkEvent *event = gdk_event_new (type);
@@ -1700,7 +1686,7 @@ generate_button_event (GdkEventType type,
event->button.axes = NULL;
event->button.state = build_pointer_event_state (msg);
event->button.button = button;
- event->button.device = _gdk_display->core_pointer;
+ gdk_event_set_device (event, _gdk_display->core_pointer);
append_event (event);
}
@@ -1868,7 +1854,10 @@ gdk_event_translate (MSG *msg,
GdkWindow *orig_window, *new_window, *toplevel;
- GdkPointerGrabInfo *grab = NULL;
+ GdkDeviceManager *device_manager;
+
+ GdkDeviceGrabInfo *keyboard_grab = NULL;
+ GdkDeviceGrabInfo *pointer_grab = NULL;
GdkWindow *grab_window = NULL;
static gint update_colors_counter = 0;
@@ -1929,7 +1918,14 @@ gdk_event_translate (MSG *msg,
}
return FALSE;
}
-
+
+ device_manager = gdk_display_get_device_manager (_gdk_display);
+
+ keyboard_grab = _gdk_display_get_last_device_grab (_gdk_display,
+ GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard);
+ pointer_grab = _gdk_display_get_last_device_grab (_gdk_display,
+ GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_pointer);
+
g_object_ref (window);
/* window's refcount has now been increased, so code below should
@@ -2047,7 +2043,7 @@ gdk_event_translate (MSG *msg,
/* Let the system handle Alt-Tab, Alt-Space and Alt-F4 unless
* the keyboard is grabbed.
*/
- if (_gdk_display->keyboard_grab.window == NULL &&
+ if (!keyboard_grab &&
(msg->wParam == VK_TAB ||
msg->wParam == VK_SPACE ||
msg->wParam == VK_F4))
@@ -2071,9 +2067,10 @@ gdk_event_translate (MSG *msg,
in_ime_composition)
break;
- if (!propagate (&window, msg,
- _gdk_display->keyboard_grab.window,
- _gdk_display->keyboard_grab.owner_events,
+ if (keyboard_grab &&
+ !propagate (&window, msg,
+ keyboard_grab->window,
+ keyboard_grab->owner_events,
GDK_ALL_EVENTS_MASK,
doesnt_want_key, FALSE))
break;
@@ -2090,6 +2087,7 @@ gdk_event_translate (MSG *msg,
event->key.string = NULL;
event->key.length = 0;
event->key.hardware_keycode = msg->wParam;
+ gdk_event_set_device (event, GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard);
if (HIWORD (msg->lParam) & KF_EXTENDED)
{
switch (msg->wParam)
@@ -2175,9 +2173,10 @@ gdk_event_translate (MSG *msg,
if (!(msg->lParam & GCS_RESULTSTR))
break;
- if (!propagate (&window, msg,
- _gdk_display->keyboard_grab.window,
- _gdk_display->keyboard_grab.owner_events,
+ if (keyboard_grab &&
+ !propagate (&window, msg,
+ keyboard_grab->window,
+ keyboard_grab->owner_events,
GDK_ALL_EVENTS_MASK,
doesnt_want_char, FALSE))
break;
@@ -2201,6 +2200,7 @@ gdk_event_translate (MSG *msg,
/* Build a key press event */
event = gdk_event_new (GDK_KEY_PRESS);
event->key.window = window;
+ gdk_event_set_device (event, GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard);
build_wm_ime_composition_event (event, msg, wbuf[i], key_state);
append_event (event);
@@ -2211,6 +2211,7 @@ gdk_event_translate (MSG *msg,
/* Build a key release event. */
event = gdk_event_new (GDK_KEY_RELEASE);
event->key.window = window;
+ gdk_event_set_device (event, GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard);
build_wm_ime_composition_event (event, msg, wbuf[i], key_state);
append_event (event);
@@ -2307,10 +2308,10 @@ gdk_event_translate (MSG *msg,
current_toplevel ? GDK_WINDOW_HWND (current_toplevel) : NULL,
toplevel ? GDK_WINDOW_HWND (toplevel) : NULL));
if (current_toplevel)
- synthesize_enter_or_leave_event (current_toplevel, msg,
- GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
- synthesize_enter_or_leave_event (toplevel, msg,
- GDK_ENTER_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
+ synthesize_enter_or_leave_event (current_toplevel, msg,
+ GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
+ synthesize_enter_or_leave_event (toplevel, msg,
+ GDK_ENTER_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
assign_object (&current_toplevel, toplevel);
track_mouse_event (TME_LEAVE, GDK_WINDOW_HWND (toplevel));
}
@@ -2336,7 +2337,7 @@ gdk_event_translate (MSG *msg,
event->motion.axes = NULL;
event->motion.state = build_pointer_event_state (msg);
event->motion.is_hint = FALSE;
- event->motion.device = _gdk_display->core_pointer;
+ gdk_event_set_device (event, _gdk_display->core_pointer);
append_event (event);
@@ -2365,8 +2366,8 @@ gdk_event_translate (MSG *msg,
{
/* we are only interested if we don't know the new window */
if (current_toplevel)
- synthesize_enter_or_leave_event (current_toplevel, msg,
- GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
+ synthesize_enter_or_leave_event (current_toplevel, msg,
+ GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
assign_object (&current_toplevel, NULL);
}
else
@@ -2412,7 +2413,7 @@ gdk_event_translate (MSG *msg,
event->scroll.x_root = (gint16) GET_X_LPARAM (msg->lParam) + _gdk_offset_x;
event->scroll.y_root = (gint16) GET_Y_LPARAM (msg->lParam) + _gdk_offset_y;
event->scroll.state = build_pointer_event_state (msg);
- event->scroll.device = _gdk_display->core_pointer;
+ gdk_event_set_device (event, _gdk_display->core_pointer);
append_event (event);
@@ -2512,16 +2513,16 @@ gdk_event_translate (MSG *msg,
break;
case WM_KILLFOCUS:
- if (_gdk_display->keyboard_grab.window != NULL &&
- !GDK_WINDOW_DESTROYED (_gdk_display->keyboard_grab.window))
+ if (keyboard_grab != NULL &&
+ !GDK_WINDOW_DESTROYED (keyboard_grab->window))
{
- generate_grab_broken_event (_gdk_display->keyboard_grab.window, FALSE, NULL);
+ generate_grab_broken_event (device_manager, keyboard_grab->window, FALSE, NULL);
}
/* fallthrough */
case WM_SETFOCUS:
- if (_gdk_display->keyboard_grab.window != NULL &&
- !_gdk_display->keyboard_grab.owner_events)
+ if (keyboard_grab != NULL &&
+ !keyboard_grab->owner_events)
break;
if (!(((GdkWindowObject *) window)->event_mask & GDK_FOCUS_CHANGE_MASK))
@@ -2530,7 +2531,7 @@ gdk_event_translate (MSG *msg,
if (GDK_WINDOW_DESTROYED (window))
break;
- generate_focus_event (window, (msg->message == WM_SETFOCUS));
+ generate_focus_event (device_manager, window, (msg->message == WM_SETFOCUS));
return_val = TRUE;
break;
@@ -2558,11 +2559,8 @@ gdk_event_translate (MSG *msg,
GDK_NOTE (EVENTS, g_print (" %#x %#x",
LOWORD (msg->lParam), HIWORD (msg->lParam)));
- grab = _gdk_display_get_last_pointer_grab (_gdk_display);
- if (grab != NULL)
- {
- grab_window = grab->window;
- }
+ if (pointer_grab != NULL)
+ grab_window = pointer_grab->window;
if (grab_window == NULL && LOWORD (msg->lParam) != HTCLIENT)
break;
@@ -2617,14 +2615,14 @@ gdk_event_translate (MSG *msg,
SetForegroundWindow (GDK_WINDOW_HWND (impl->transient_owner));
}
- grab = _gdk_display_get_last_pointer_grab (_gdk_display);
- if (grab != NULL)
+ if (pointer_grab != NULL)
{
- if (grab->window == window)
+ if (pointer_grab->window == window)
gdk_pointer_ungrab (msg->time);
}
- if (_gdk_display->keyboard_grab.window == window)
+ if (keyboard_grab &&
+ keyboard_grab->window == window)
gdk_keyboard_ungrab (msg->time);
}
@@ -2655,13 +2653,13 @@ gdk_event_translate (MSG *msg,
if (msg->wParam == SIZE_MINIMIZED)
{
/* Don't generate any GDK event. This is *not* an UNMAP. */
- grab = _gdk_display_get_last_pointer_grab (_gdk_display);
- if (grab != NULL)
+ if (pointer_grab != NULL)
{
- if (grab->window == window)
+ if (pointer_grab->window == window)
gdk_pointer_ungrab (msg->time);
}
- if (_gdk_display->keyboard_grab.window == window)
+ if (keyboard_grab &&
+ keyboard_grab->window == window)
gdk_keyboard_ungrab (msg->time);
gdk_synthesize_window_state (window,
@@ -2707,7 +2705,7 @@ gdk_event_translate (MSG *msg,
((GdkWindowObject *) window)->resize_count -= 1;
if (((GdkWindowObject *) window)->extension_events != 0)
- _gdk_input_configure_event (window);
+ _gdk_device_wintab_update_window_coords (window);
return_val = TRUE;
}
@@ -3089,14 +3087,14 @@ gdk_event_translate (MSG *msg,
break;
case WM_DESTROY:
- grab = _gdk_display_get_last_pointer_grab (_gdk_display);
- if (grab != NULL)
+ if (pointer_grab != NULL)
{
- if (grab->window == window)
+ if (pointer_grab->window == window)
gdk_pointer_ungrab (msg->time);
}
- if (_gdk_display->keyboard_grab.window == window)
+ if (keyboard_grab &&
+ keyboard_grab->window == window)
gdk_keyboard_ungrab (msg->time);
if ((window != NULL) && (msg->hwnd != GetDesktopWindow ()))
diff --git a/gdk/win32/gdkinput-win32.c b/gdk/win32/gdkinput-win32.c
deleted file mode 100644
index d02952dc1e..0000000000
--- a/gdk/win32/gdkinput-win32.c
+++ /dev/null
@@ -1,1392 +0,0 @@
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- * Copyright (C) 1998-2007 Tor Lillqvist
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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-2000. 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 <stdlib.h>
-#include <stdio.h>
-#include <math.h>
-
-#include "gdk.h"
-#include "gdkinput.h"
-#include "gdkinternals.h"
-#include "gdkprivate-win32.h"
-#include "gdkinput-win32.h"
-
-#define PACKETDATA (PK_CONTEXT | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION)
-/* We want everything in absolute mode */
-#define PACKETMODE (0)
-#include <pktdef.h>
-
-#define DEBUG_WINTAB 1 /* Verbose debug messages enabled */
-
-#define PROXIMITY_OUT_DELAY 200 /* In milliseconds, see set_ignore_core */
-
-#define TWOPI (2.*G_PI)
-
-/* Forward declarations */
-
-static GdkDevicePrivate *gdk_input_find_dev_from_ctx (HCTX hctx,
- UINT id);
-static GList *wintab_contexts = NULL;
-
-static GdkWindow *wintab_window = NULL;
-
-static GdkWindow *x_grab_window = NULL; /* Window that currently holds
- * the extended inputs grab
- */
-static GdkEventMask x_grab_mask;
-static gboolean x_grab_owner_events;
-
-typedef UINT (WINAPI *t_WTInfoA) (UINT a, UINT b, LPVOID c);
-typedef UINT (WINAPI *t_WTInfoW) (UINT a, UINT b, LPVOID c);
-typedef BOOL (WINAPI *t_WTEnable) (HCTX a, BOOL b);
-typedef HCTX (WINAPI *t_WTOpenA) (HWND a, LPLOGCONTEXTA b, BOOL c);
-typedef BOOL (WINAPI *t_WTOverlap) (HCTX a, BOOL b);
-typedef BOOL (WINAPI *t_WTPacket) (HCTX a, UINT b, LPVOID c);
-typedef int (WINAPI *t_WTQueueSizeSet) (HCTX a, int b);
-
-static t_WTInfoA p_WTInfoA;
-static t_WTInfoW p_WTInfoW;
-static t_WTEnable p_WTEnable;
-static t_WTOpenA p_WTOpenA;
-static t_WTOverlap p_WTOverlap;
-static t_WTPacket p_WTPacket;
-static t_WTQueueSizeSet p_WTQueueSizeSet;
-
-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;
-}
-
-#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");
- 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",
- (guint) lc->lcBtnDnMask, (guint) lc->lcBtnUpMask);
- g_print ("lcInOrgX = %ld, lcInOrgY = %ld, lcInOrgZ = %ld\n",
- lc->lcInOrgX, lc->lcInOrgY, lc->lcInOrgZ);
- g_print ("lcInExtX = %ld, lcInExtY = %ld, lcInExtZ = %ld\n",
- lc->lcInExtX, lc->lcInExtY, lc->lcInExtZ);
- g_print ("lcOutOrgX = %ld, lcOutOrgY = %ld, lcOutOrgZ = %ld\n",
- lc->lcOutOrgX, lc->lcOutOrgY, lc->lcOutOrgZ);
- g_print ("lcOutExtX = %ld, lcOutExtY = %ld, lcOutExtZ = %ld\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.);
-}
-
-static void
-print_cursor (int index)
-{
- int size;
- int i;
- char *name;
- BOOL active;
- WTPKT wtpkt;
- BYTE buttons;
- BYTE buttonbits;
- char *btnnames;
- char *p;
- BYTE buttonmap[32];
- BYTE sysbtnmap[32];
- BYTE npbutton;
- UINT npbtnmarks[2];
- UINT *npresponse;
- BYTE tpbutton;
- UINT tpbtnmarks[2];
- UINT *tpresponse;
- DWORD physid;
- UINT mode;
- UINT minpktdata;
- UINT minbuttons;
- UINT capabilities;
-
- size = (*p_WTInfoA) (WTI_CURSORS + index, CSR_NAME, NULL);
- name = g_malloc (size + 1);
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_NAME, name);
- g_print ("NAME: %s\n", name);
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_ACTIVE, &active);
- g_print ("ACTIVE: %s\n", active ? "YES" : "NO");
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_PKTDATA, &wtpkt);
- g_print ("PKTDATA: %#x:", (guint) wtpkt);
-#define BIT(x) if (wtpkt & PK_##x) g_print (" " #x)
- BIT (CONTEXT);
- BIT (STATUS);
- BIT (TIME);
- BIT (CHANGED);
- BIT (SERIAL_NUMBER);
- BIT (BUTTONS);
- BIT (X);
- BIT (Y);
- BIT (Z);
- BIT (NORMAL_PRESSURE);
- BIT (TANGENT_PRESSURE);
- BIT (ORIENTATION);
- BIT (ROTATION);
-#undef BIT
- g_print ("\n");
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_BUTTONS, &buttons);
- g_print ("BUTTONS: %d\n", buttons);
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_BUTTONBITS, &buttonbits);
- g_print ("BUTTONBITS: %d\n", buttonbits);
- size = (*p_WTInfoA) (WTI_CURSORS + index, CSR_BTNNAMES, NULL);
- g_print ("BTNNAMES:");
- if (size > 0)
- {
- btnnames = g_malloc (size + 1);
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_BTNNAMES, btnnames);
- p = btnnames;
- while (*p)
- {
- g_print (" %s", p);
- p += strlen (p) + 1;
- }
- }
- g_print ("\n");
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_BUTTONMAP, buttonmap);
- g_print ("BUTTONMAP:");
- for (i = 0; i < buttons; i++)
- g_print (" %d", buttonmap[i]);
- g_print ("\n");
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_SYSBTNMAP, sysbtnmap);
- g_print ("SYSBTNMAP:");
- for (i = 0; i < buttons; i++)
- g_print (" %d", sysbtnmap[i]);
- g_print ("\n");
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_NPBUTTON, &npbutton);
- g_print ("NPBUTTON: %d\n", npbutton);
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_NPBTNMARKS, npbtnmarks);
- g_print ("NPBTNMARKS: %d %d\n", npbtnmarks[0], npbtnmarks[1]);
- size = (*p_WTInfoA) (WTI_CURSORS + index, CSR_NPRESPONSE, NULL);
- g_print ("NPRESPONSE:");
- if (size > 0)
- {
- npresponse = g_malloc (size);
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_NPRESPONSE, npresponse);
- for (i = 0; i < size / sizeof (UINT); i++)
- g_print (" %d", npresponse[i]);
- }
- g_print ("\n");
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_TPBUTTON, &tpbutton);
- g_print ("TPBUTTON: %d\n", tpbutton);
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_TPBTNMARKS, tpbtnmarks);
- g_print ("TPBTNMARKS: %d %d\n", tpbtnmarks[0], tpbtnmarks[1]);
- size = (*p_WTInfoA) (WTI_CURSORS + index, CSR_TPRESPONSE, NULL);
- g_print ("TPRESPONSE:");
- if (size > 0)
- {
- tpresponse = g_malloc (size);
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_TPRESPONSE, tpresponse);
- for (i = 0; i < size / sizeof (UINT); i++)
- g_print (" %d", tpresponse[i]);
- }
- g_print ("\n");
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_PHYSID, &physid);
- g_print ("PHYSID: %#x\n", (guint) physid);
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_CAPABILITIES, &capabilities);
- g_print ("CAPABILITIES: %#x:", capabilities);
-#define BIT(x) if (capabilities & CRC_##x) g_print (" " #x)
- BIT (MULTIMODE);
- BIT (AGGREGATE);
- BIT (INVERT);
-#undef BIT
- g_print ("\n");
- if (capabilities & CRC_MULTIMODE)
- {
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_MODE, &mode);
- g_print ("MODE: %d\n", mode);
- }
- if (capabilities & CRC_AGGREGATE)
- {
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_MINPKTDATA, &minpktdata);
- g_print ("MINPKTDATA: %d\n", minpktdata);
- (*p_WTInfoA) (WTI_CURSORS + index, CSR_MINBUTTONS, &minbuttons);
- g_print ("MINBUTTONS: %d\n", minbuttons);
- }
-}
-#endif
-
-void
-_gdk_input_wintab_init_check (void)
-{
- static gboolean wintab_initialized = FALSE;
- GdkDevicePrivate *gdkdev;
- 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];
- int i, k;
- int devix, cursorix;
- wchar_t devname[100], csrname[100];
- gchar *devname_utf8, *csrname_utf8;
- BOOL defcontext_done;
- HMODULE wintab32;
-
- if (wintab_initialized)
- return;
-
- wintab_initialized = TRUE;
-
- wintab_contexts = NULL;
-
- if (_gdk_input_ignore_wintab)
- return;
-
- if ((wintab32 = LoadLibrary ("wintab32.dll")) == NULL)
- return;
-
- if ((p_WTInfoA = (t_WTInfoA) GetProcAddress (wintab32, "WTInfoA")) == NULL)
- return;
- if ((p_WTInfoW = (t_WTInfoW) GetProcAddress (wintab32, "WTInfoW")) == NULL)
- return;
- if ((p_WTEnable = (t_WTEnable) GetProcAddress (wintab32, "WTEnable")) == NULL)
- return;
- if ((p_WTOpenA = (t_WTOpenA) GetProcAddress (wintab32, "WTOpenA")) == NULL)
- return;
- if ((p_WTOverlap = (t_WTOverlap) GetProcAddress (wintab32, "WTOverlap")) == NULL)
- return;
- if ((p_WTPacket = (t_WTPacket) GetProcAddress (wintab32, "WTPacket")) == NULL)
- return;
- if ((p_WTQueueSizeSet = (t_WTQueueSizeSet) GetProcAddress (wintab32, "WTQueueSizeSet")) == NULL)
- return;
-
- if (!(*p_WTInfoA) (0, 0, NULL))
- return;
-
- (*p_WTInfoA) (WTI_INTERFACE, IFC_SPECVERSION, &specversion);
- GDK_NOTE (INPUT, g_print ("Wintab interface version %d.%d\n",
- HIBYTE (specversion), LOBYTE (specversion)));
- (*p_WTInfoA) (WTI_INTERFACE, IFC_NDEVICES, &ndevices);
- (*p_WTInfoA) (WTI_INTERFACE, IFC_NCURSORS, &ncursors);
-#if DEBUG_WINTAB
- GDK_NOTE (INPUT, 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_wintab_init: gdk_window_new failed");
- return;
- }
- g_object_ref (wintab_window);
-
- for (devix = 0; devix < ndevices; devix++)
- {
- LOGCONTEXT lc;
-
- /* We open the Wintab device (hmm, what if there are several, or
- * can there even be several, probably not?) as a system
- * pointing device, i.e. it controls the normal Windows
- * cursor. This seems much more natural.
- */
-
- (*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("Device %d: %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)
- {
- /* Try to get device-specific default context */
- /* Some drivers, e.g. Aiptek, don't provide this info */
- if ((*p_WTInfoA) (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
- }
-
- if (!defcontext_done)
- (*p_WTInfoA) (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 = 0;
- 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)));
-#endif
- hctx = g_new (HCTX, 1);
- if ((*hctx = (*p_WTOpenA) (GDK_WINDOW_HWND (wintab_window), &lc, TRUE)) == NULL)
- {
- g_warning ("gdk_input_wintab_init: WTOpen failed");
- return;
- }
- GDK_NOTE (INPUT, g_print ("opened Wintab device %d %p\n",
- devix, *hctx));
-
- wintab_contexts = g_list_append (wintab_contexts, hctx);
-#if 0
- (*p_WTEnable) (*hctx, TRUE);
-#endif
- (*p_WTOverlap) (*hctx, TRUE);
-
-#if DEBUG_WINTAB
- GDK_NOTE (INPUT, (g_print("context for device %d after WTOpen:\n", devix),
- print_lc(&lc)));
-#endif
- /* Increase packet queue size to reduce the risk of lost packets.
- * According to the specs, if the function fails we must try again
- * with a smaller queue size.
- */
- GDK_NOTE (INPUT, g_print("Attempting to increase queue size\n"));
- for (i = 32; i >= 1; i >>= 1)
- {
- if ((*p_WTQueueSizeSet) (*hctx, i))
- {
- GDK_NOTE (INPUT, g_print("Queue size set to %d\n", i));
- break;
- }
- }
- if (!i)
- GDK_NOTE (INPUT, g_print("Whoops, no queue size could be set\n"));
- for (cursorix = firstcsr; cursorix < firstcsr + ncsrtypes; cursorix++)
- {
-#ifdef DEBUG_WINTAB
- GDK_NOTE (INPUT, (g_print("Cursor %d:\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;
-
- gdkdev = g_object_new (GDK_TYPE_DEVICE, NULL);
- (*p_WTInfoW) (WTI_CURSORS + cursorix, CSR_NAME, csrname);
- csrname_utf8 = g_utf16_to_utf8 (csrname, -1, NULL, NULL, NULL);
- gdkdev->info.name = g_strconcat (devname_utf8, " ", csrname_utf8, NULL);
- g_free (csrname_utf8);
- gdkdev->info.source = GDK_SOURCE_PEN;
- gdkdev->info.mode = GDK_MODE_SCREEN;
- gdkdev->info.has_cursor = TRUE;
- gdkdev->hctx = *hctx;
- gdkdev->cursor = cursorix;
- (*p_WTInfoA) (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 */
-
- gdkdev->info.axes = g_new (GdkDeviceAxis, gdkdev->info.num_axes);
- gdkdev->axes = g_new (GdkAxisInfo, gdkdev->info.num_axes);
- gdkdev->last_axis_data = g_new (gint, gdkdev->info.num_axes);
-
- k = 0;
- if (gdkdev->pktdata & PK_X)
- {
- gdkdev->axes[k].resolution = axis_x.axResolution / 65535.;
- gdkdev->axes[k].min_value = axis_x.axMin;
- gdkdev->axes[k].max_value = axis_x.axMax;
- gdkdev->info.axes[k].use = GDK_AXIS_X;
- gdkdev->info.axes[k].min = axis_x.axMin;
- gdkdev->info.axes[k].max = axis_x.axMax;
- k++;
- }
- if (gdkdev->pktdata & PK_Y)
- {
- gdkdev->axes[k].resolution = axis_y.axResolution / 65535.;
- gdkdev->axes[k].min_value = axis_y.axMin;
- gdkdev->axes[k].max_value = axis_y.axMax;
- gdkdev->info.axes[k].use = GDK_AXIS_Y;
- gdkdev->info.axes[k].min = axis_y.axMin;
- gdkdev->info.axes[k].max = axis_y.axMax;
- k++;
- }
- if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
- {
- gdkdev->axes[k].resolution = axis_npressure.axResolution / 65535.;
- gdkdev->axes[k].min_value = axis_npressure.axMin;
- gdkdev->axes[k].max_value = axis_npressure.axMax;
- gdkdev->info.axes[k].use = GDK_AXIS_PRESSURE;
- /* GIMP seems to expect values in the range 0-1 */
- gdkdev->info.axes[k].min = 0.0; /*axis_npressure.axMin;*/
- gdkdev->info.axes[k].max = 1.0; /*axis_npressure.axMax;*/
- 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].resolution = 1000;
- gdkdev->axes[k].min_value = -1000;
- gdkdev->axes[k].max_value = 1000;
- gdkdev->info.axes[k].use = axis;
- gdkdev->info.axes[k].min = -1000;
- gdkdev->info.axes[k].max = 1000;
- k++;
- }
- }
- gdkdev->info.num_keys = 0;
- gdkdev->info.keys = NULL;
- GDK_NOTE (INPUT, g_print ("device: (%d) %s axes: %d\n",
- cursorix,
- gdkdev->info.name,
- gdkdev->info.num_axes));
- 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_input_devices = g_list_append (_gdk_input_devices,
- gdkdev);
- }
- g_free (devname_utf8);
- }
-}
-
-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 void
-gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
- GdkInputWindow *input_window,
- gint *axis_data,
- gdouble *axis_out,
- gdouble *x_out,
- gdouble *y_out)
-{
- GdkWindowImplWin32 *root_impl;
- GdkWindowObject *window_object;
-
- int i;
- int x_axis = 0;
- int y_axis = 0;
-
- double device_width, device_height;
- double x_offset, y_offset, x_scale, y_scale;
-
- window_object = GDK_WINDOW_OBJECT (input_window);
-
- for (i=0; i<gdkdev->info.num_axes; i++)
- {
- switch (gdkdev->info.axes[i].use)
- {
- case GDK_AXIS_X:
- x_axis = i;
- break;
- case GDK_AXIS_Y:
- y_axis = i;
- break;
- default:
- break;
- }
- }
-
- 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)
- {
- root_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (_gdk_root)->impl);
- x_scale = GDK_WINDOW_OBJECT (_gdk_root)->width / device_width;
- y_scale = GDK_WINDOW_OBJECT (_gdk_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_object->width >= window_object->height)
- {
- /* device taller than window */
- x_scale = window_object->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_object->height) / 2;
- }
- else
- {
- /* window taller than device */
- y_scale = window_object->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_object->width) / 2;
- }
- }
-
- for (i = 0; i < gdkdev->info.num_axes; i++)
- {
- switch (gdkdev->info.axes[i].use)
- {
- case GDK_AXIS_X:
- axis_out[i] = x_offset + x_scale * axis_data[x_axis];
- if (x_out)
- *x_out = axis_out[i];
- break;
- case GDK_AXIS_Y:
- axis_out[i] = y_offset + y_scale * axis_data[y_axis];
- if (y_out)
- *y_out = axis_out[i];
- break;
- default:
- axis_out[i] =
- (gdkdev->info.axes[i].max * (axis_data[i] - gdkdev->axes[i].min_value) +
- gdkdev->info.axes[i].min * (gdkdev->axes[i].max_value - axis_data[i])) /
- (gdkdev->axes[i].max_value - gdkdev->axes[i].min_value);
- break;
- }
- }
-}
-
-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 + _gdk_offset_x;
- if (y_ret)
- *y_ret = rect.top + _gdk_offset_y;
-}
-
-void
-_gdk_input_configure_event (GdkWindow *window)
-{
- GdkInputWindow *input_window;
- int root_x, root_y;
-
- input_window = _gdk_input_window_find (window);
- g_return_if_fail (window != NULL);
-
- gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window),
- &root_x, &root_y);
-
- input_window->root_x = root_x;
- input_window->root_y = root_y;
-}
-
-void
-_gdk_input_enter_event (GdkWindow *window)
-{
- GdkInputWindow *input_window;
- int root_x, root_y;
-
- input_window = _gdk_input_window_find (window);
- g_return_if_fail (window != NULL);
-
- gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window), &root_x, &root_y);
-
- input_window->root_x = root_x;
- 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
- * on build_pointer_event_state from gdkevents-win32.c
- */
-static guint
-get_modifier_key_state (void)
-{
- guint state;
-
- state = 0;
- /* High-order bit is up/down, low order bit is toggled/untoggled */
- if (GetKeyState (VK_CONTROL) < 0)
- state |= GDK_CONTROL_MASK;
- if (GetKeyState (VK_SHIFT) < 0)
- state |= GDK_SHIFT_MASK;
- if (GetKeyState (VK_MENU) < 0)
- state |= GDK_MOD1_MASK;
- if (GetKeyState (VK_CAPITAL) & 0x1)
- state |= GDK_LOCK_MASK;
-
- return state;
-}
-
-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 = gdk_threads_add_timeout (PROXIMITY_OUT_DELAY,
- ignore_core_timefunc, NULL);
-}
-
-gboolean
-_gdk_input_other_event (GdkEvent *event,
- MSG *msg,
- GdkWindow *window)
-{
- GdkDisplay *display;
- GdkWindowObject *obj, *grab_obj;
- GdkInputWindow *input_window;
- GdkDevicePrivate *gdkdev = NULL;
- GdkEventMask masktest;
- guint key_state;
- POINT pt;
-
- PACKET packet;
- gint k;
- gint x, y;
- guint translated_buttons, button_diff, button_mask;
- /* Translation from tablet button state to GDK button state for
- * buttons 1-3 - swap button 2 and 3.
- */
- static guint button_map[8] = {0, 1, 4, 5, 2, 3, 6, 7};
-
- if (event->any.window != wintab_window)
- {
- g_warning ("_gdk_input_other_event: not wintab_window?");
- return FALSE;
- }
-
- window = gdk_window_at_pointer (&x, &y);
- if (window == NULL)
- window = _gdk_root;
-
- g_object_ref (window);
- display = gdk_drawable_get_display (window);
-
- GDK_NOTE (EVENTS_OR_INPUT,
- g_print ("_gdk_input_other_event: window=%p %+d%+d\n",
- GDK_WINDOW_HWND (window), x, y));
-
- if (msg->message == WT_PACKET)
- {
- if (!(*p_WTPacket) ((HCTX) msg->lParam, msg->wParam, &packet))
- return FALSE;
- }
-
- obj = GDK_WINDOW_OBJECT (window);
-
- switch (msg->message)
- {
- case WT_PACKET:
- /* Don't produce any button or motion events while a window is being
- * moved or resized, see bug #151090.
- */
- if (_modal_operation_in_progress)
- {
- 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;
- }
-
- if ((gdkdev = gdk_input_find_dev_from_ctx ((HCTX) msg->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);
-
- translated_buttons = button_map[packet.pkButtons & 0x07] | (packet.pkButtons & ~0x07);
-
- if (translated_buttons != gdkdev->button_state)
- {
- /* At least one button has changed state so produce a button event
- * If more than one button has changed state (unlikely),
- * just care about the first and act on the next the next time
- * we get a packet
- */
- button_diff = translated_buttons ^ gdkdev->button_state;
-
- /* Gdk buttons are numbered 1.. */
- event->button.button = 1;
-
- for (button_mask = 1; button_mask != 0x80000000;
- button_mask <<= 1, event->button.button++)
- {
- if (button_diff & button_mask)
- {
- /* Found a button that has changed state */
- break;
- }
- }
-
- if (!(translated_buttons & button_mask))
- {
- event->any.type = GDK_BUTTON_RELEASE;
- masktest = GDK_BUTTON_RELEASE_MASK;
- }
- else
- {
- event->any.type = GDK_BUTTON_PRESS;
- masktest = GDK_BUTTON_PRESS_MASK;
- }
- gdkdev->button_state ^= button_mask;
- }
- 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;
- }
-
- /* See if input is grabbed */
- /* FIXME: x_grab_owner_events should probably be handled somehow */
- if (x_grab_window != NULL)
- {
- grab_obj = GDK_WINDOW_OBJECT (x_grab_window);
- if (!GDK_WINDOW_IMPL_WIN32 (grab_obj->impl)->extension_events_selected
- || !(grab_obj->extension_events & masktest)
- || !(x_grab_mask && masktest))
- {
- GDK_NOTE (EVENTS_OR_INPUT,
- g_print ("... grabber doesn't want it\n"));
- return FALSE;
- }
- GDK_NOTE (EVENTS_OR_INPUT, g_print ("... to grabber\n"));
-
- g_object_ref(x_grab_window);
- g_object_unref(window);
- window = x_grab_window;
- obj = grab_obj;
- }
- /* Now we can check if the window wants the event, and
- * propagate if necessary.
- */
- loop:
- if (!GDK_WINDOW_IMPL_WIN32 (obj->impl)->extension_events_selected
- || !(obj->extension_events & masktest))
- {
- GDK_NOTE (EVENTS_OR_INPUT, g_print ("... not selected\n"));
-
- if (obj->parent == GDK_WINDOW_OBJECT (_gdk_root))
- return FALSE;
-
- /* It is not good to propagate the extended events up to the parent
- * if this window wants normal (not extended) motion/button events */
- if (obj->event_mask & masktest)
- {
- GDK_NOTE (EVENTS_OR_INPUT,
- g_print ("... wants ordinary event, ignoring this\n"));
- return FALSE;
- }
-
- pt.x = x;
- pt.y = y;
- ClientToScreen (GDK_WINDOW_HWND (window), &pt);
- g_object_unref (window);
- window = (GdkWindow *) obj->parent;
- obj = GDK_WINDOW_OBJECT (window);
- g_object_ref (window);
- 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_WINDOW_HWND (window), x, y));
- goto loop;
- }
-
- 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;
- key_state = get_modifier_key_state ();
- if (event->any.type == GDK_BUTTON_PRESS
- || event->any.type == GDK_BUTTON_RELEASE)
- {
- event->button.time = _gdk_win32_get_next_tick (msg->time);
- event->button.device = &gdkdev->info;
-
- event->button.axes = g_new(gdouble, gdkdev->info.num_axes);
-
- gdk_input_translate_coordinates (gdkdev, input_window,
- gdkdev->last_axis_data,
- event->button.axes,
- &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
- | GDK_BUTTON5_MASK))
- | key_state;
- GDK_NOTE (EVENTS_OR_INPUT,
- g_print ("WINTAB button %s:%d %g,%g\n",
- (event->button.type == GDK_BUTTON_PRESS ?
- "press" : "release"),
- event->button.button,
- event->button.x, event->button.y));
- }
- else
- {
- event->motion.time = _gdk_win32_get_next_tick (msg->time);
- event->motion.is_hint = FALSE;
- event->motion.device = &gdkdev->info;
-
- event->motion.axes = g_new(gdouble, gdkdev->info.num_axes);
-
- gdk_input_translate_coordinates (gdkdev, input_window,
- gdkdev->last_axis_data,
- event->motion.axes,
- &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
- | GDK_BUTTON5_MASK))
- | key_state;
-
- GDK_NOTE (EVENTS_OR_INPUT,
- g_print ("WINTAB motion: %g,%g\n",
- event->motion.x, event->motion.y));
- }
- return TRUE;
-
- case WT_PROXIMITY:
- if (LOWORD (msg->lParam) == 0)
- {
- event->proximity.type = GDK_PROXIMITY_OUT;
- set_ignore_core (FALSE);
- }
- else
- {
- event->proximity.type = GDK_PROXIMITY_IN;
- set_ignore_core (TRUE);
- }
- event->proximity.time = _gdk_win32_get_next_tick (msg->time);
- event->proximity.device = &gdkdev->info;
-
- GDK_NOTE (EVENTS_OR_INPUT,
- g_print ("WINTAB proximity %s\n",
- (event->proximity.type == GDK_PROXIMITY_IN ?
- "in" : "out")));
- return TRUE;
- }
- return FALSE;
-}
-
-gboolean
-_gdk_input_enable_window (GdkWindow *window,
- GdkDevicePrivate *gdkdev)
-{
- GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
-
- impl->extension_events_selected = TRUE;
-
- return TRUE;
-}
-
-gboolean
-_gdk_input_disable_window (GdkWindow *window,
- GdkDevicePrivate *gdkdev)
-{
- GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
-
- impl->extension_events_selected = FALSE;
-
- return TRUE;
-}
-
-gint
-_gdk_input_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;
-
- tmp_list = _gdk_input_windows;
- new_window = NULL;
- need_ungrab = FALSE;
-
- GDK_NOTE (INPUT, g_print ("_gdk_input_grab_pointer: %p %d %p\n",
- GDK_WINDOW_HWND (window),
- owner_events,
- (confine_to ? GDK_WINDOW_HWND (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;
- x_grab_window = window;
- x_grab_mask = event_mask;
- x_grab_owner_events = owner_events;
-
- /* FIXME: Do we need to handle confine_to and time? */
-
- tmp_list = _gdk_input_devices;
- while (tmp_list)
- {
- gdkdev = (GdkDevicePrivate *)tmp_list->data;
- if (!GDK_IS_CORE (gdkdev) && gdkdev->hctx)
- {
-#if 0
- /* XXX */
- gdk_input_common_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
- {
- x_grab_window = NULL;
-#if 0
- tmp_list = _gdk_input_devices;
- while (tmp_list)
- {
- gdkdev = (GdkDevicePrivate *)tmp_list->data;
- if (!GDK_IS_CORE (gdkdev) && gdkdev->hctx &&
- ((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;
- }
-#endif
- }
-
- return GDK_GRAB_SUCCESS;
-}
-
-void
-_gdk_input_ungrab_pointer (guint32 time)
-{
- GdkInputWindow *input_window;
- GdkDevicePrivate *gdkdev;
- GList *tmp_list;
-
- GDK_NOTE (INPUT, g_print ("_gdk_input_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 (!GDK_IS_CORE (gdkdev) && gdkdev->xdevice)
- XUngrabDevice (gdk_display, gdkdev->xdevice, time);
-#endif
- tmp_list = tmp_list->next;
- }
- }
- x_grab_window = NULL;
-}
-
-gboolean
-_gdk_device_get_history (GdkDevice *device,
- GdkWindow *window,
- guint32 start,
- guint32 stop,
- GdkTimeCoord ***events,
- gint *n_events)
-{
- return FALSE;
-}
-
-void
-gdk_device_get_state (GdkDevice *device,
- GdkWindow *window,
- gdouble *axes,
- GdkModifierType *mask)
-{
- g_return_if_fail (device != NULL);
- g_return_if_fail (GDK_IS_WINDOW (window));
-
- if (GDK_IS_CORE (device))
- {
- gint x_int, y_int;
-
- gdk_window_get_pointer (window, &x_int, &y_int, mask);
-
- if (axes)
- {
- axes[0] = x_int;
- axes[1] = y_int;
- }
- }
- else
- {
- GdkDevicePrivate *gdkdev;
- GdkInputWindow *input_window;
-
- gdkdev = (GdkDevicePrivate *)device;
- /* For now just use the last known button and axis state of the device.
- * Since graphical tablets send an insane amount of motion events each
- * second, the info should be fairly up to date */
- if (mask)
- {
- gdk_window_get_pointer (window, NULL, NULL, mask);
- *mask &= 0xFF; /* Mask away core pointer buttons */
- *mask |= ((gdkdev->button_state << 8)
- & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
- | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
- | GDK_BUTTON5_MASK));
- }
- input_window = _gdk_input_window_find (window);
- g_return_if_fail (input_window != NULL);
- /* For some reason, input_window is sometimes NULL when I use The GIMP 2
- * (bug #141543?). Avoid crashing if debugging is disabled. */
- if (axes && gdkdev->last_axis_data && input_window)
- gdk_input_translate_coordinates (gdkdev, input_window,
- gdkdev->last_axis_data,
- axes, NULL, NULL);
- }
-}
-
-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);
- (*p_WTOverlap) (*hctx, TRUE);
- tmp_list = tmp_list->next;
- }
-}
-
-void
-_gdk_input_init (GdkDisplay *display)
-{
- _gdk_input_ignore_core = FALSE;
- _gdk_input_devices = NULL;
-
- _gdk_init_input_core (display);
-#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 */
-
- _gdk_input_devices = g_list_append (_gdk_input_devices, display->core_pointer);
-}
-
diff --git a/gdk/win32/gdkinput-win32.h b/gdk/win32/gdkinput-win32.h
deleted file mode 100644
index 608d8f99d6..0000000000
--- a/gdk/win32/gdkinput-win32.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* 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., 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/.
- */
-
-#ifndef __GDK_INPUT_WIN32_H__
-#define __GDK_INPUT_WIN32_H__
-
-#include <windows.h>
-#include <wintab.h>
-
-typedef struct _GdkAxisInfo GdkAxisInfo;
-typedef struct _GdkDevicePrivate GdkDevicePrivate;
-
-/* information about a device axis */
-struct _GdkAxisInfo
-{
- /* calibrated resolution (for aspect ratio) - only relative values
- between axes used */
- gint resolution;
-
- /* calibrated minimum/maximum values */
- gint min_value, max_value;
-};
-
-struct _GdkDeviceClass
-{
- GObjectClass parent_class;
-};
-
-struct _GdkDevicePrivate
-{
- GdkDevice info;
-
- /* information about the axes */
- GdkAxisInfo *axes;
-
- gint button_state;
-
- gint *last_axis_data;
-
- /* WINTAB stuff: */
- HCTX hctx;
- /* Cursor number */
- UINT cursor;
- /* The cursor's CSR_PKTDATA */
- WTPKT pktdata;
- /* Azimuth and altitude axis */
- AXIS orientation_axes[2];
-};
-
-struct _GdkInputWindow
-{
- /* gdk window */
- GdkWindow *window;
-
- /* Extension mode (GDK_EXTENSION_EVENTS_ALL/CURSOR) */
- GdkExtensionMode mode;
-
- /* position relative to root window */
- gint root_x;
- gint root_y;
-
- /* rectangles relative to window of windows obscuring this one */
- GdkRectangle *obscuring;
- gint num_obscuring;
-
- /* Is there a pointer grab for this window ? */
- gint grabbed;
-};
-
-/* Global data */
-
-#define GDK_IS_CORE(d) (((GdkDevice *)(d)) == gdk_display_get_default ()->core_pointer)
-
-extern GList *_gdk_input_devices;
-extern GList *_gdk_input_windows;
-
-extern gint _gdk_input_ignore_core;
-
-/* Function declarations */
-void _gdk_init_input_core (GdkDisplay *display);
-
-GdkTimeCoord ** _gdk_device_allocate_history (GdkDevice *device,
- gint n_events);
-
-/* The following functions are provided by each implementation
- * (just wintab for now)
- */
-void _gdk_input_configure_event (GdkWindow *window);
-void _gdk_input_enter_event (GdkWindow *window);
-gboolean _gdk_input_other_event (GdkEvent *event,
- MSG *msg,
- GdkWindow *window);
-
-void _gdk_input_crossing_event (GdkWindow *window,
- gboolean enter);
-
-
-/* These should be in gdkinternals.h */
-
-GdkInputWindow *_gdk_input_window_find (GdkWindow *window);
-
-void _gdk_input_window_destroy (GdkWindow *window);
-
-gint _gdk_input_enable_window (GdkWindow *window,
- GdkDevicePrivate *gdkdev);
-gint _gdk_input_disable_window (GdkWindow *window,
- GdkDevicePrivate *gdkdev);
-gint _gdk_input_grab_pointer (GdkWindow *window,
- gint owner_events,
- GdkEventMask event_mask,
- GdkWindow *confine_to,
- guint32 time);
-void _gdk_input_ungrab_pointer (guint32 time);
-gboolean _gdk_device_get_history (GdkDevice *device,
- GdkWindow *window,
- guint32 start,
- guint32 stop,
- GdkTimeCoord ***events,
- gint *n_events);
-
-void _gdk_input_wintab_init_check (void);
-void _gdk_input_set_tablet_active (void);
-
-#endif /* __GDK_INPUT_WIN32_H__ */
diff --git a/gdk/win32/gdkinput.c b/gdk/win32/gdkinput.c
index e5ab44b720..32de7fc28d 100644
--- a/gdk/win32/gdkinput.c
+++ b/gdk/win32/gdkinput.c
@@ -37,63 +37,13 @@
#include "gdkinput.h"
#include "gdkprivate-win32.h"
-#include "gdkinput-win32.h"
-
-static GdkDeviceAxis gdk_input_core_axes[] = {
- { GDK_AXIS_X, 0, 0 },
- { GDK_AXIS_Y, 0, 0 }
-};
-
-/* Global variables */
+#include "gdkdevicemanager-win32.h"
gint _gdk_input_ignore_core;
GList *_gdk_input_devices;
GList *_gdk_input_windows;
-void
-_gdk_init_input_core (GdkDisplay *display)
-{
- display->core_pointer = g_object_new (GDK_TYPE_DEVICE, NULL);
-
- display->core_pointer->name = "Core Pointer";
- display->core_pointer->source = GDK_SOURCE_MOUSE;
- display->core_pointer->mode = GDK_MODE_SCREEN;
- display->core_pointer->has_cursor = TRUE;
- display->core_pointer->num_axes = 2;
- display->core_pointer->axes = gdk_input_core_axes;
- display->core_pointer->num_keys = 0;
- display->core_pointer->keys = NULL;
-}
-
-GType
-gdk_device_get_type (void)
-{
- static GType object_type = 0;
-
- if (!object_type)
- {
- const GTypeInfo object_info =
- {
- sizeof (GdkDeviceClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) NULL,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GdkDevicePrivate),
- 0, /* n_preallocs */
- (GInstanceInitFunc) NULL,
- };
-
- object_type = g_type_register_static (G_TYPE_OBJECT,
- g_intern_static_string ("GdkDevice"),
- &object_info, 0);
- }
-
- return object_type;
-}
-
GList *
gdk_devices_list (void)
{
@@ -105,188 +55,9 @@ gdk_display_list_devices (GdkDisplay *dpy)
{
g_return_val_if_fail (dpy == _gdk_display, NULL);
- _gdk_input_wintab_init_check ();
return _gdk_input_devices;
}
-G_CONST_RETURN gchar *
-gdk_device_get_name (GdkDevice *device)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
-
- return device->name;
-}
-
-GdkInputSource
-gdk_device_get_source (GdkDevice *device)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
-
- return device->source;
-}
-
-GdkInputMode
-gdk_device_get_mode (GdkDevice *device)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
-
- return device->mode;
-}
-
-gboolean
-gdk_device_get_has_cursor (GdkDevice *device)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
-
- return device->has_cursor;
-}
-
-void
-gdk_device_set_source (GdkDevice *device,
- GdkInputSource source)
-{
- g_return_if_fail (device != NULL);
-
- device->source = source;
-}
-
-void
-gdk_device_get_key (GdkDevice *device,
- guint index,
- guint *keyval,
- GdkModifierType *modifiers)
-{
- g_return__if_fail (GDK_IS_DEVICE (device));
- g_return_if_fail (index < device->num_keys);
-
- if (!device->keys[index].keyval &&
- !device->keys[index].modifiers)
- return;
-
- if (keyval)
- *keyval = device->keys[index].keyval;
-
- if (modifiers)
- *modifiers = device->keys[index].modifiers;
-}
-
-void
-gdk_device_set_key (GdkDevice *device,
- guint index,
- guint keyval,
- GdkModifierType modifiers)
-{
- g_return_if_fail (device != NULL);
- g_return_if_fail (index < device->num_keys);
-
- device->keys[index].keyval = keyval;
- device->keys[index].modifiers = modifiers;
-}
-
-GdkAxisUse
-gdk_device_get_axis_use (GdkDevice *device,
- guint index)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), GDK_AXIS_IGNORE);
- g_return_val_if_fail (index < device->num_axes, GDK_AXIS_IGNORE);
-
- return device->axes[index].use;
-}
-
-void
-gdk_device_set_axis_use (GdkDevice *device,
- guint index,
- GdkAxisUse use)
-{
- g_return_if_fail (device != NULL);
- g_return_if_fail (index < device->num_axes);
-
- device->axes[index].use = use;
-
- switch (use)
- {
- case GDK_AXIS_X:
- case GDK_AXIS_Y:
- device->axes[index].min = 0.;
- device->axes[index].max = 0.;
- break;
- case GDK_AXIS_XTILT:
- case GDK_AXIS_YTILT:
- device->axes[index].min = -1.;
- device->axes[index].max = 1;
- break;
- default:
- device->axes[index].min = 0.;
- device->axes[index].max = 1;
- break;
- }
-}
-
-gboolean
-gdk_device_get_history (GdkDevice *device,
- GdkWindow *window,
- guint32 start,
- guint32 stop,
- GdkTimeCoord ***events,
- gint *n_events)
-{
- g_return_val_if_fail (window != NULL, FALSE);
- g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
- g_return_val_if_fail (events != NULL, FALSE);
- g_return_val_if_fail (n_events != NULL, FALSE);
-
- if (n_events)
- *n_events = 0;
- if (events)
- *events = NULL;
-
- if (GDK_WINDOW_DESTROYED (window))
- return FALSE;
-
- if (GDK_IS_CORE (device))
- return FALSE;
- else
- return _gdk_device_get_history (device, window, start, stop, events, n_events);
-}
-
-GdkTimeCoord **
-_gdk_device_allocate_history (GdkDevice *device,
- gint n_events)
-{
- GdkTimeCoord **result = g_new (GdkTimeCoord *, n_events);
- gint i;
-
- for (i=0; i<n_events; i++)
- result[i] = g_malloc (sizeof (GdkTimeCoord) -
- sizeof (double) * (GDK_MAX_TIMECOORD_AXES - device->num_axes));
-
- return result;
-}
-
-void
-gdk_device_free_history (GdkTimeCoord **events,
- gint n_events)
-{
- gint i;
-
- for (i=0; i<n_events; i++)
- g_free (events[i]);
-
- g_free (events);
-}
-
-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 */
-}
-
/* 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
@@ -295,212 +66,60 @@ _gdk_input_window_find(GdkWindow *window)
void
gdk_input_set_extension_events (GdkWindow *window, gint mask,
- GdkExtensionMode mode)
+ GdkExtensionMode mode)
{
+ GdkDeviceManager *device_manager;
GdkWindowObject *window_private;
- GList *tmp_list;
- GdkInputWindow *iw;
+ GList *devices, *d;
- g_return_if_fail (window != NULL);
g_return_if_fail (GDK_IS_WINDOW (window));
- window_private = (GdkWindowObject*) window;
if (GDK_WINDOW_DESTROYED (window))
return;
if (mode == GDK_EXTENSION_EVENTS_NONE)
mask = 0;
- if (mask != 0)
- {
- _gdk_input_wintab_init_check ();
-
- iw = g_new(GdkInputWindow,1);
-
- iw->window = window;
- iw->mode = mode;
-
- iw->obscuring = NULL;
- iw->num_obscuring = 0;
- iw->grabbed = FALSE;
+ window_private = (GdkWindowObject *) window;
+ window_private->extension_events = mask;
- _gdk_input_windows = g_list_append(_gdk_input_windows,iw);
- window_private->extension_events = mask;
+ device_manager = gdk_display_get_device_manager (_gdk_display);
+ devices = gdk_device_manager_list_devices (device_manager,
+ GDK_DEVICE_TYPE_FLOATING);
- /* Add enter window events to the event mask */
- if (g_list_length (_gdk_input_devices) > 1)
- gdk_window_set_events (window,
- gdk_window_get_events (window) |
- GDK_ENTER_NOTIFY_MASK);
- }
- else
+ for (d = devices; d; d = d->next)
{
- iw = _gdk_input_window_find (window);
- if (iw)
- {
- _gdk_input_windows = g_list_remove(_gdk_input_windows,iw);
- g_free(iw);
- }
+ GdkDevice *dev;
+ gint dev_mask;
- window_private->extension_events = 0;
- }
+ dev = d->data;
+ dev_mask = mask;
- for (tmp_list = _gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
- {
- GdkDevicePrivate *gdkdev = tmp_list->data;
+ if (gdk_device_get_mode (dev) == GDK_MODE_DISABLED ||
+ (!gdk_device_get_has_cursor (dev) && mode == GDK_EXTENSION_EVENTS_CURSOR))
+ dev_mask = 0;
- if (!GDK_IS_CORE (gdkdev))
- {
- 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);
- }
+ gdk_window_set_device_events (window, dev, mask);
}
-}
-
-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_crossing_event (GdkWindow *window,
- gboolean enter)
-{
- if (enter)
- {
-#if 0 /* No idea what to do... */
- GdkWindowObject *priv = (GdkWindowObject *)window;
- GdkInputWindow *input_window;
- gint root_x, root_y;
-#if 0
- gdk_input_check_proximity(display);
-#endif
- input_window = priv->input_window;
- if (input_window != NULL)
- {
- _gdk_input_get_root_relative_geometry (window, &root_x, &root_y);
- input_window->root_x = root_x;
- input_window->root_y = root_y;
- }
-#endif
- }
- else
- _gdk_input_ignore_core = FALSE;
+ g_list_free (devices);
}
void
-_gdk_input_exit (void)
+_gdk_input_init (GdkDisplay *display)
{
- GList *tmp_list;
- GdkDevicePrivate *gdkdev;
+ GdkDeviceManagerWin32 *device_manager;
- for (tmp_list = _gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
- {
- gdkdev = (GdkDevicePrivate *)(tmp_list->data);
- if (!GDK_IS_CORE (gdkdev))
- {
- gdk_device_set_mode (&gdkdev->info, GDK_MODE_DISABLED);
+ _gdk_input_ignore_core = FALSE;
- g_free(gdkdev->info.name);
- g_free(gdkdev->axes);
- g_free(gdkdev->info.axes);
- g_free(gdkdev->info.keys);
- 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);
-}
-
-gboolean
-gdk_device_get_axis (GdkDevice *device,
- gdouble *axes,
- GdkAxisUse use,
- gdouble *value)
-{
- gint i;
-
- g_return_val_if_fail (device != NULL, FALSE);
+ device_manager = g_object_new (GDK_TYPE_DEVICE_MANAGER_WIN32,
+ "display", display,
+ NULL);
+ display->device_manager = GDK_DEVICE_MANAGER (device_manager);
- if (axes == NULL)
- return FALSE;
-
- for (i=0; i<device->num_axes; i++)
- if (device->axes[i].use == use)
- {
- if (value)
- *value = axes[i];
- return TRUE;
- }
-
- return FALSE;
-}
-
-gboolean
-gdk_device_set_mode (GdkDevice *device,
- GdkInputMode mode)
-{
- GList *tmp_list;
- GdkDevicePrivate *gdkdev;
- GdkInputMode old_mode;
- GdkInputWindow *input_window;
-
- if (GDK_IS_CORE (device))
- return FALSE;
-
- gdkdev = (GdkDevicePrivate *)device;
-
- if (device->mode == mode)
- return TRUE;
-
- old_mode = device->mode;
- device->mode = mode;
-
- if (mode == GDK_MODE_WINDOW)
- {
- device->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_enable_window (input_window->window, gdkdev);
- else
- if (old_mode != GDK_MODE_DISABLED)
- _gdk_input_disable_window (input_window->window, gdkdev);
- }
- }
- else if (mode == GDK_MODE_SCREEN)
- {
- device->has_cursor = TRUE;
- for (tmp_list = _gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
- _gdk_input_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_disable_window (input_window->window, gdkdev);
- }
- }
+ display->core_pointer = device_manager->core_pointer;
- return TRUE;
+ _gdk_input_devices = g_list_append (NULL, display->core_pointer);
+ _gdk_input_devices = g_list_concat (_gdk_input_devices,
+ g_list_copy (device_manager->wintab_devices));
}
diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c
index 94b7ac793c..4ea4c8fbe2 100644
--- a/gdk/win32/gdkmain-win32.c
+++ b/gdk/win32/gdkmain-win32.c
@@ -39,10 +39,11 @@
#include "gdkinternals.h"
#include "gdkintl.h"
#include "gdkprivate-win32.h"
-#include "gdkinput-win32.h"
#include <objbase.h>
+#include <windows.h>
+#include <wintab.h>
#include <imm.h>
static gboolean gdk_synchronize = FALSE;
diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c
index 55ca651efe..d44d8f464e 100644
--- a/gdk/win32/gdkwindow-win32.c
+++ b/gdk/win32/gdkwindow-win32.c
@@ -33,7 +33,8 @@
#include "gdk.h"
#include "gdkwindowimpl.h"
#include "gdkprivate-win32.h"
-#include "gdkinput-win32.h"
+#include "gdkdeviceprivate.h"
+#include "gdkdevicemanager-win32.h"
#include "gdkenumtypes.h"
static GdkColormap* gdk_window_impl_win32_get_colormap (GdkDrawable *drawable);
@@ -787,9 +788,6 @@ _gdk_win32_window_destroy (GdkWindow *window,
GDK_NOTE (MISC, g_print ("_gdk_win32_window_destroy: %p\n",
GDK_WINDOW_HWND (window)));
- if (private->extension_events != 0)
- _gdk_input_window_destroy (window);
-
/* Remove ourself from the modal stack */
_gdk_remove_modal_window (window);
@@ -1829,12 +1827,12 @@ gdk_win32_window_set_back_pixmap (GdkWindow *window,
}
static void
-gdk_win32_window_set_cursor (GdkWindow *window,
- GdkCursor *cursor)
+gdk_win32_window_set_device_cursor (GdkWindow *window,
+ GdkDevice *device,
+ GdkCursor *cursor)
{
GdkWindowImplWin32 *impl;
GdkCursorPrivate *cursor_private;
- GdkWindowObject *parent_window;
HCURSOR hcursor;
HCURSOR hprevcursor;
@@ -1859,6 +1857,8 @@ gdk_win32_window_set_cursor (GdkWindow *window,
*/
hprevcursor = impl->hcursor;
+ GDK_DEVICE_GET_CLASS (device)->set_window_cursor (device, window, cursor);
+
if (hcursor == NULL)
impl->hcursor = NULL;
else
@@ -1875,62 +1875,10 @@ gdk_win32_window_set_cursor (GdkWindow *window,
hcursor, impl->hcursor));
}
- if (impl->hcursor != NULL)
- {
- /* If the pointer is over our window, set new cursor */
- GdkWindow *curr_window = gdk_window_get_pointer (window, NULL, NULL, NULL);
- if (curr_window == window ||
- (curr_window && window == gdk_window_get_toplevel (curr_window)))
- SetCursor (impl->hcursor);
- else
- {
- /* Climb up the tree and find whether our window is the
- * first ancestor that has cursor defined, and if so, set
- * new cursor.
- */
- GdkWindowObject *curr_window_obj = GDK_WINDOW_OBJECT (curr_window);
- while (curr_window_obj &&
- !GDK_WINDOW_IMPL_WIN32 (curr_window_obj->impl)->hcursor)
- {
- curr_window_obj = curr_window_obj->parent;
- if (curr_window_obj == GDK_WINDOW_OBJECT (window))
- {
- SetCursor (impl->hcursor);
- break;
- }
- }
- }
- }
-
- /* Destroy the previous cursor: Need to make sure it's no longer in
- * use before we destroy it, in case we're not over our window but
- * the cursor is still set to our old one.
- */
+ /* Destroy the previous cursor */
if (hprevcursor != NULL)
{
- if (GetCursor () == hprevcursor)
- {
- /* Look for a suitable cursor to use instead */
- hcursor = NULL;
- parent_window = GDK_WINDOW_OBJECT (window)->parent;
- while (hcursor == NULL)
- {
- if (parent_window)
- {
- impl = GDK_WINDOW_IMPL_WIN32 (parent_window->impl);
- hcursor = impl->hcursor;
- parent_window = parent_window->parent;
- }
- else
- {
- hcursor = LoadCursor (NULL, IDC_ARROW);
- }
- }
- SetCursor (hcursor);
- }
-
GDK_NOTE (MISC, g_print ("... DestroyCursor (%p)\n", hprevcursor));
-
API_CALL (DestroyCursor, (hprevcursor));
}
}
@@ -2113,87 +2061,43 @@ gdk_window_get_frame_extents (GdkWindow *window,
r.left, r.top));
}
-
-static GdkModifierType
-get_current_mask (void)
-{
- GdkModifierType mask;
- BYTE kbd[256];
-
- GetKeyboardState (kbd);
- mask = 0;
- if (kbd[VK_SHIFT] & 0x80)
- mask |= GDK_SHIFT_MASK;
- if (kbd[VK_CAPITAL] & 0x80)
- mask |= GDK_LOCK_MASK;
- if (kbd[VK_CONTROL] & 0x80)
- mask |= GDK_CONTROL_MASK;
- if (kbd[VK_MENU] & 0x80)
- mask |= GDK_MOD1_MASK;
- if (kbd[VK_LBUTTON] & 0x80)
- mask |= GDK_BUTTON1_MASK;
- if (kbd[VK_MBUTTON] & 0x80)
- mask |= GDK_BUTTON2_MASK;
- if (kbd[VK_RBUTTON] & 0x80)
- mask |= GDK_BUTTON3_MASK;
-
- return mask;
-}
-
static gboolean
-gdk_window_win32_get_pointer (GdkWindow *window,
- gint *x,
- gint *y,
- GdkModifierType *mask)
+gdk_window_win32_get_device_state (GdkWindow *window,
+ GdkDevice *device,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
{
- gboolean return_val;
- POINT point;
- HWND hwnd, hwndc;
+ GdkWindow *child;
g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), FALSE);
-
- return_val = TRUE;
-
- hwnd = GDK_WINDOW_HWND (window);
- GetCursorPos (&point);
- ScreenToClient (hwnd, &point);
- *x = point.x;
- *y = point.y;
-
- if (window == _gdk_root)
- {
- *x += _gdk_offset_x;
- *y += _gdk_offset_y;
- }
-
- hwndc = ChildWindowFromPoint (hwnd, point);
- if (hwndc != NULL && hwndc != hwnd &&
- !gdk_win32_handle_table_lookup ((GdkNativeWindow) hwndc))
- return_val = FALSE; /* Direct child unknown to gdk */
-
- *mask = get_current_mask ();
-
- return return_val;
+ GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
+ NULL, &child,
+ NULL, NULL,
+ x, y, mask);
+ return (child != NULL);
}
void
-_gdk_windowing_get_pointer (GdkDisplay *display,
- GdkScreen **screen,
- gint *x,
- gint *y,
- GdkModifierType *mask)
+_gdk_windowing_get_device_state (GdkDisplay *display,
+ GdkDevice *device,
+ GdkScreen **screen,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
{
- POINT point;
-
g_return_if_fail (display == _gdk_display);
-
- *screen = _gdk_screen;
- GetCursorPos (&point);
- *x = point.x + _gdk_offset_x;
- *y = point.y + _gdk_offset_y;
- *mask = get_current_mask ();
+ if (screen)
+ *screen = _gdk_screen;
+
+ GDK_DEVICE_GET_CLASS (device)->query_state (device,
+ gdk_screen_get_root_window (_gdk_screen),
+ NULL, NULL,
+ x, y,
+ NULL, NULL,
+ mask);
}
void
@@ -2202,64 +2106,40 @@ gdk_display_warp_pointer (GdkDisplay *display,
gint x,
gint y)
{
+ GdkDeviceManagerWin32 *device_manager;
+
g_return_if_fail (display == _gdk_display);
g_return_if_fail (screen == _gdk_screen);
- SetCursorPos (x - _gdk_offset_x, y - _gdk_offset_y);
+ device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (display));
+ GDK_DEVICE_GET_CLASS (device_manager->core_pointer)->warp (device_manager->core_pointer,
+ screen, x, y);
}
-GdkWindow*
-_gdk_windowing_window_at_pointer (GdkDisplay *display,
- gint *win_x,
- gint *win_y,
- GdkModifierType *mask,
- gboolean get_toplevel)
+void
+gdk_display_warp_device (GdkDisplay *display,
+ GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y)
{
- GdkWindow *window;
- POINT point, pointc;
- HWND hwnd, hwndc;
- RECT rect;
-
- GetCursorPos (&pointc);
- point = pointc;
- hwnd = WindowFromPoint (point);
-
- if (hwnd == NULL)
- {
- window = _gdk_root;
- *win_x = pointc.x + _gdk_offset_x;
- *win_y = pointc.y + _gdk_offset_y;
- return window;
- }
-
- ScreenToClient (hwnd, &point);
-
- do {
- if (get_toplevel &&
- (window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd)) != NULL &&
- GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
- break;
-
- hwndc = ChildWindowFromPoint (hwnd, point);
- ClientToScreen (hwnd, &point);
- ScreenToClient (hwndc, &point);
- } while (hwndc != hwnd && (hwnd = hwndc, 1));
-
- window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd);
-
- if (window && (win_x || win_y))
- {
- GetClientRect (hwnd, &rect);
- *win_x = point.x - rect.left;
- *win_y = point.y - rect.top;
- }
+ g_return_if_fail (display == _gdk_display);
+ g_return_if_fail (screen == _gdk_screen);
+ g_return_if_fail (GDK_IS_DEVICE (device));
+ g_return_if_fail (display == gdk_device_get_display (device));
- GDK_NOTE (MISC, g_print ("_gdk_windowing_window_at_pointer: %+d%+d %p%s\n",
- *win_x, *win_y,
- hwnd,
- (window == NULL ? " NULL" : "")));
+ GDK_DEVICE_GET_CLASS (device)->warp (device, screen, x, y);
+}
- return window;
+GdkWindow*
+_gdk_windowing_window_at_device_position (GdkDisplay *display,
+ GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel)
+{
+ return GDK_DEVICE_GET_CLASS (device)->window_at_position (device, win_x, win_y, mask, get_toplevel);
}
static GdkEventMask
@@ -3485,9 +3365,9 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface)
iface->set_background = gdk_win32_window_set_background;
iface->set_back_pixmap = gdk_win32_window_set_back_pixmap;
iface->reparent = gdk_win32_window_reparent;
- iface->set_cursor = gdk_win32_window_set_cursor;
+ iface->set_device_cursor = gdk_win32_window_set_device_cursor;
iface->get_geometry = gdk_win32_window_get_geometry;
- iface->get_pointer = gdk_window_win32_get_pointer;
+ iface->get_device_state = gdk_window_win32_get_device_state;
iface->get_root_coords = gdk_win32_window_get_root_coords;
iface->shape_combine_region = gdk_win32_window_shape_combine_region;
iface->input_shape_combine_region = gdk_win32_input_shape_combine_region;
@@ -3496,6 +3376,4 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface)
iface->queue_antiexpose = _gdk_win32_window_queue_antiexpose;
iface->queue_translation = _gdk_win32_window_queue_translation;
iface->destroy = _gdk_win32_window_destroy;
- iface->input_window_destroy = _gdk_input_window_destroy;
- iface->input_window_crossing = _gdk_input_crossing_event;
}
diff --git a/gdk/x11/Makefile.am b/gdk/x11/Makefile.am
index fd4067c787..8f7abfe09f 100644
--- a/gdk/x11/Makefile.am
+++ b/gdk/x11/Makefile.am
@@ -23,19 +23,25 @@ libgdk_x11_la_SOURCES = \
gdkasync.h \
gdkcolor-x11.c \
gdkcursor-x11.c \
+ gdkdevice-core.c \
+ gdkdevicemanager-core.c \
+ gdkdevicemanager-x11.c \
gdkdisplay-x11.c \
gdkdisplay-x11.h \
gdkdnd-x11.c \
gdkdrawable-x11.c \
gdkdrawable-x11.h \
- gdkevents-x11.c \
+ gdkeventsource.c \
+ gdkeventsource.h \
+ gdkeventtranslator.c \
+ gdkeventtranslator.h \
gdkfont-x11.c \
gdkgc-x11.c \
gdkgeometry-x11.c \
gdkglobals-x11.c \
gdkim-x11.c \
gdkimage-x11.c \
- gdkinput.c \
+ gdkinput.c \
gdkkeys-x11.c \
gdkmain-x11.c \
gdkpixmap-x11.c \
@@ -53,16 +59,16 @@ libgdk_x11_la_SOURCES = \
gdkxid.c \
gdkx.h \
gdkprivate-x11.h \
- gdkinputprivate.h \
xsettings-client.h \
xsettings-client.c \
xsettings-common.h \
xsettings-common.c
if XINPUT_XFREE
-libgdk_x11_la_SOURCES += gdkinput-x11.c gdkinput-xfree.c
-else
-libgdk_x11_la_SOURCES += gdkinput-none.c
+libgdk_x11_la_SOURCES += gdkdevicemanager-xi.c gdkdevice-xi.c
+if XINPUT_2
+libgdk_x11_la_SOURCES += gdkdevicemanager-xi2.c gdkdevice-xi2.c
+endif
endif
diff --git a/gdk/x11/gdkdevice-core.c b/gdk/x11/gdkdevice-core.c
new file mode 100644
index 0000000000..7ff8c4d8a4
--- /dev/null
+++ b/gdk/x11/gdkdevice-core.c
@@ -0,0 +1,501 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+
+#include <gdk/gdkwindow.h>
+#include "gdkdevice-core.h"
+#include "gdkprivate-x11.h"
+#include "gdkx.h"
+
+static gboolean gdk_device_core_get_history (GdkDevice *device,
+ GdkWindow *window,
+ guint32 start,
+ guint32 stop,
+ GdkTimeCoord ***events,
+ guint *n_events);
+static void gdk_device_core_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask);
+static void gdk_device_core_set_window_cursor (GdkDevice *device,
+ GdkWindow *window,
+ GdkCursor *cursor);
+static void gdk_device_core_warp (GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y);
+static gboolean gdk_device_core_query_state (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow **root_window,
+ GdkWindow **child_window,
+ gint *root_x,
+ gint *root_y,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask);
+static GdkGrabStatus gdk_device_core_grab (GdkDevice *device,
+ GdkWindow *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time_);
+static void gdk_device_core_ungrab (GdkDevice *device,
+ guint32 time_);
+static GdkWindow * gdk_device_core_window_at_position (GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel);
+static void gdk_device_core_select_window_events (GdkDevice *device,
+ GdkWindow *window,
+ GdkEventMask event_mask);
+
+
+G_DEFINE_TYPE (GdkDeviceCore, gdk_device_core, GDK_TYPE_DEVICE)
+
+static void
+gdk_device_core_class_init (GdkDeviceCoreClass *klass)
+{
+ GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
+
+ device_class->get_history = gdk_device_core_get_history;
+ device_class->get_state = gdk_device_core_get_state;
+ device_class->set_window_cursor = gdk_device_core_set_window_cursor;
+ device_class->warp = gdk_device_core_warp;
+ device_class->query_state = gdk_device_core_query_state;
+ device_class->grab = gdk_device_core_grab;
+ device_class->ungrab = gdk_device_core_ungrab;
+ device_class->window_at_position = gdk_device_core_window_at_position;
+ device_class->select_window_events = gdk_device_core_select_window_events;
+}
+
+static void
+gdk_device_core_init (GdkDeviceCore *device_core)
+{
+ GdkDevice *device;
+
+ device = GDK_DEVICE (device_core);
+
+ _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_X, 0, 0, 1);
+ _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_Y, 0, 0, 1);
+}
+
+static gboolean
+impl_coord_in_window (GdkWindow *window,
+ int impl_x,
+ int impl_y)
+{
+ GdkWindowObject *priv = (GdkWindowObject *) window;
+
+ if (impl_x < priv->abs_x ||
+ impl_x > priv->abs_x + priv->width)
+ return FALSE;
+
+ if (impl_y < priv->abs_y ||
+ impl_y > priv->abs_y + priv->height)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+gdk_device_core_get_history (GdkDevice *device,
+ GdkWindow *window,
+ guint32 start,
+ guint32 stop,
+ GdkTimeCoord ***events,
+ guint *n_events)
+{
+ GdkWindowObject *priv;
+ XTimeCoord *xcoords;
+ GdkTimeCoord **coords;
+ GdkWindow *impl_window;
+ int tmp_n_events;
+ int i, j;
+
+ impl_window = _gdk_window_get_impl_window (window);
+ xcoords = XGetMotionEvents (GDK_DRAWABLE_XDISPLAY (window),
+ GDK_DRAWABLE_XID (impl_window),
+ start, stop, &tmp_n_events);
+ if (!xcoords)
+ return FALSE;
+
+ priv = (GdkWindowObject *) window;
+ coords = _gdk_device_allocate_history (device, tmp_n_events);
+
+ for (i = 0, j = 0; i < tmp_n_events; i++)
+ {
+ if (impl_coord_in_window (window, xcoords[i].x, xcoords[i].y))
+ {
+ coords[j]->time = xcoords[i].time;
+ coords[j]->axes[0] = xcoords[i].x - priv->abs_x;
+ coords[j]->axes[1] = xcoords[i].y - priv->abs_y;
+ j++;
+ }
+ }
+
+ XFree (xcoords);
+
+ /* free the events we allocated too much */
+ for (i = j; i < tmp_n_events; i++)
+ {
+ g_free (coords[i]);
+ coords[i] = NULL;
+ }
+
+ tmp_n_events = j;
+
+ if (tmp_n_events == 0)
+ {
+ gdk_device_free_history (coords, tmp_n_events);
+ return FALSE;
+ }
+
+ if (n_events)
+ *n_events = tmp_n_events;
+
+ if (events)
+ *events = coords;
+ else if (coords)
+ gdk_device_free_history (coords, tmp_n_events);
+
+ return TRUE;
+}
+
+static void
+gdk_device_core_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask)
+{
+ gint x_int, y_int;
+
+ gdk_window_get_pointer (window, &x_int, &y_int, mask);
+
+ if (axes)
+ {
+ axes[0] = x_int;
+ axes[1] = y_int;
+ }
+}
+
+static void
+gdk_device_core_set_window_cursor (GdkDevice *device,
+ GdkWindow *window,
+ GdkCursor *cursor)
+{
+ GdkCursorPrivate *cursor_private;
+ Cursor xcursor;
+
+ cursor_private = (GdkCursorPrivate*) cursor;
+
+ if (!cursor)
+ xcursor = None;
+ else
+ xcursor = cursor_private->xcursor;
+
+ XDefineCursor (GDK_WINDOW_XDISPLAY (window),
+ GDK_WINDOW_XID (window),
+ xcursor);
+}
+
+static void
+gdk_device_core_warp (GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y)
+{
+ Display *xdisplay;
+ Window dest;
+
+ xdisplay = GDK_DISPLAY_XDISPLAY (gdk_device_get_display (device));
+ dest = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
+
+ XWarpPointer (xdisplay, None, dest, 0, 0, 0, 0, x, y);
+}
+
+static gboolean
+gdk_device_core_query_state (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow **root_window,
+ GdkWindow **child_window,
+ gint *root_x,
+ gint *root_y,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask)
+{
+ GdkDisplay *display;
+ Window xroot_window, xchild_window;
+ int xroot_x, xroot_y, xwin_x, xwin_y;
+ unsigned int xmask;
+
+ display = gdk_drawable_get_display (window);
+
+ if (!XQueryPointer (GDK_WINDOW_XDISPLAY (window),
+ GDK_WINDOW_XID (window),
+ &xroot_window,
+ &xchild_window,
+ &xroot_x,
+ &xroot_y,
+ &xwin_x,
+ &xwin_y,
+ &xmask))
+ {
+ return FALSE;
+ }
+
+ if (root_window)
+ *root_window = gdk_window_lookup_for_display (display, xroot_window);
+
+ if (child_window)
+ *child_window = gdk_window_lookup_for_display (display, xchild_window);
+
+ if (root_x)
+ *root_x = xroot_x;
+
+ if (root_y)
+ *root_y = xroot_y;
+
+ if (win_x)
+ *win_x = xwin_x;
+
+ if (win_y)
+ *win_y = xwin_y;
+
+ if (mask)
+ *mask = xmask;
+
+ return TRUE;
+}
+
+static GdkGrabStatus
+gdk_device_core_grab (GdkDevice *device,
+ GdkWindow *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time_)
+{
+ GdkDisplay *display;
+ Window xwindow, xconfine_to;
+ int status;
+
+ display = gdk_device_get_display (device);
+
+ xwindow = GDK_WINDOW_XID (window);
+
+ if (confine_to)
+ confine_to = _gdk_window_get_impl_window (confine_to);
+
+ if (!confine_to || GDK_WINDOW_DESTROYED (confine_to))
+ xconfine_to = None;
+ else
+ xconfine_to = GDK_WINDOW_XID (confine_to);
+
+ if (device->source == GDK_SOURCE_KEYBOARD)
+ {
+ /* Device is a keyboard */
+ status = XGrabKeyboard (GDK_DISPLAY_XDISPLAY (display),
+ xwindow,
+ owner_events,
+ GrabModeAsync, GrabModeAsync,
+ time_);
+ }
+ else
+ {
+ Cursor xcursor;
+ guint xevent_mask;
+ gint i;
+
+ /* Device is a pointer */
+ if (!cursor)
+ xcursor = None;
+ else
+ {
+ _gdk_x11_cursor_update_theme (cursor);
+ xcursor = ((GdkCursorPrivate *) cursor)->xcursor;
+ }
+
+ xevent_mask = 0;
+
+ for (i = 0; i < _gdk_nenvent_masks; i++)
+ {
+ if (event_mask & (1 << (i + 1)))
+ xevent_mask |= _gdk_event_mask_table[i];
+ }
+
+ /* We don't want to set a native motion hint mask, as we're emulating motion
+ * hints. If we set a native one we just wouldn't get any events.
+ */
+ xevent_mask &= ~PointerMotionHintMask;
+
+ status = XGrabPointer (GDK_DISPLAY_XDISPLAY (display),
+ xwindow,
+ owner_events,
+ xevent_mask,
+ GrabModeAsync, GrabModeAsync,
+ xconfine_to,
+ xcursor,
+ time_);
+ }
+
+ return _gdk_x11_convert_grab_status (status);
+}
+
+static void
+gdk_device_core_ungrab (GdkDevice *device,
+ guint32 time_)
+{
+ GdkDisplay *display;
+
+ display = gdk_device_get_display (device);
+
+ if (device->source == GDK_SOURCE_KEYBOARD)
+ XUngrabKeyboard (GDK_DISPLAY_XDISPLAY (display), time_);
+ else
+ XUngrabPointer (GDK_DISPLAY_XDISPLAY (display), time_);
+}
+
+static GdkWindow *
+gdk_device_core_window_at_position (GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel)
+{
+ GdkDisplay *display;
+ GdkScreen *screen;
+ Display *xdisplay;
+ GdkWindow *window;
+ Window xwindow, root, child, last;
+ int xroot_x, xroot_y, xwin_x, xwin_y;
+ unsigned int xmask;
+
+ last = None;
+ display = gdk_device_get_display (device);
+ screen = gdk_display_get_default_screen (display);
+
+ /* This function really only works if the mouse pointer is held still
+ * during its operation. If it moves from one leaf window to another
+ * than we'll end up with inaccurate values for win_x, win_y
+ * and the result.
+ */
+ gdk_x11_display_grab (display);
+
+ xdisplay = GDK_SCREEN_XDISPLAY (screen);
+ xwindow = GDK_SCREEN_XROOTWIN (screen);
+
+ XQueryPointer (xdisplay, xwindow,
+ &root, &child,
+ &xroot_x, &xroot_y,
+ &xwin_x, &xwin_y,
+ &xmask);
+
+ if (root == xwindow)
+ xwindow = child;
+ else
+ xwindow = root;
+
+ while (xwindow)
+ {
+ last = xwindow;
+ XQueryPointer (xdisplay, xwindow,
+ &root, &xwindow,
+ &xroot_x, &xroot_y,
+ &xwin_x, &xwin_y,
+ &xmask);
+
+ if (get_toplevel && last != root &&
+ (window = gdk_window_lookup_for_display (display, last)) != NULL &&
+ GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
+ {
+ xwindow = last;
+ break;
+ }
+ }
+
+ gdk_x11_display_ungrab (display);
+
+ window = gdk_window_lookup_for_display (display, last);
+
+ if (win_x)
+ *win_x = (window) ? xwin_x : -1;
+
+ if (win_y)
+ *win_y = (window) ? xwin_y : -1;
+
+ if (mask)
+ *mask = xmask;
+
+ return window;
+}
+
+static void
+gdk_device_core_select_window_events (GdkDevice *device,
+ GdkWindow *window,
+ GdkEventMask event_mask)
+{
+ GdkEventMask filter_mask, window_mask;
+ guint xmask = 0;
+ gint i;
+
+ window_mask = gdk_window_get_events (window);
+ filter_mask = (GDK_POINTER_MOTION_MASK &
+ GDK_POINTER_MOTION_HINT_MASK &
+ GDK_BUTTON_MOTION_MASK &
+ GDK_BUTTON1_MOTION_MASK &
+ GDK_BUTTON2_MOTION_MASK &
+ GDK_BUTTON3_MOTION_MASK &
+ GDK_BUTTON_PRESS_MASK &
+ GDK_BUTTON_RELEASE_MASK &
+ GDK_KEY_PRESS_MASK &
+ GDK_KEY_RELEASE_MASK &
+ GDK_ENTER_NOTIFY_MASK &
+ GDK_LEAVE_NOTIFY_MASK &
+ GDK_FOCUS_CHANGE_MASK &
+ GDK_PROXIMITY_IN_MASK &
+ GDK_PROXIMITY_OUT_MASK &
+ GDK_SCROLL_MASK);
+
+ /* Filter out non-device events */
+ event_mask &= filter_mask;
+
+ /* Unset device events on window mask */
+ window_mask &= ~(filter_mask);
+
+ /* Combine masks */
+ event_mask |= window_mask;
+
+ for (i = 0; i < _gdk_nenvent_masks; i++)
+ {
+ if (event_mask & (1 << (i + 1)))
+ xmask |= _gdk_event_mask_table[i];
+ }
+
+ if (GDK_WINDOW_XID (window) != GDK_WINDOW_XROOTWIN (window))
+ xmask |= StructureNotifyMask | PropertyChangeMask;
+
+ XSelectInput (GDK_WINDOW_XDISPLAY (window),
+ GDK_WINDOW_XWINDOW (window),
+ xmask);
+}
diff --git a/gdk/x11/gdkdevice-core.h b/gdk/x11/gdkdevice-core.h
new file mode 100644
index 0000000000..04424b5883
--- /dev/null
+++ b/gdk/x11/gdkdevice-core.h
@@ -0,0 +1,52 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GDK_DEVICE_CORE_H__
+#define __GDK_DEVICE_CORE_H__
+
+#include <gdk/gdkdeviceprivate.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_CORE (gdk_device_core_get_type ())
+#define GDK_DEVICE_CORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_CORE, GdkDeviceCore))
+#define GDK_DEVICE_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_CORE, GdkDeviceCoreClass))
+#define GDK_IS_DEVICE_CORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_CORE))
+#define GDK_IS_DEVICE_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_CORE))
+#define GDK_DEVICE_CORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_CORE, GdkDeviceCoreClass))
+
+typedef struct _GdkDeviceCore GdkDeviceCore;
+typedef struct _GdkDeviceCoreClass GdkDeviceCoreClass;
+
+struct _GdkDeviceCore
+{
+ GdkDevice parent_instance;
+};
+
+struct _GdkDeviceCoreClass
+{
+ GdkDeviceClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType gdk_device_core_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_CORE_H__ */
diff --git a/gdk/x11/gdkdevice-xi.c b/gdk/x11/gdkdevice-xi.c
new file mode 100644
index 0000000000..b82ff18002
--- /dev/null
+++ b/gdk/x11/gdkdevice-xi.c
@@ -0,0 +1,624 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+
+#include <gdk/gdkwindow.h>
+#include "gdkdeviceprivate.h"
+#include "gdkdevice-xi.h"
+#include "gdkprivate-x11.h"
+#include "gdkintl.h"
+#include "gdkx.h"
+
+#define MAX_DEVICE_CLASSES 13
+
+static GQuark quark_window_input_info = 0;
+
+typedef struct
+{
+ gdouble root_x;
+ gdouble root_y;
+} GdkWindowInputInfo;
+
+static void gdk_device_xi_constructed (GObject *object);
+static void gdk_device_xi_dispose (GObject *object);
+
+static void gdk_device_xi_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gdk_device_xi_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static gboolean gdk_device_xi_get_history (GdkDevice *device,
+ GdkWindow *window,
+ guint32 start,
+ guint32 stop,
+ GdkTimeCoord ***events,
+ guint *n_events);
+
+static void gdk_device_xi_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask);
+static void gdk_device_xi_set_window_cursor (GdkDevice *device,
+ GdkWindow *window,
+ GdkCursor *cursor);
+static void gdk_device_xi_warp (GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y);
+static gboolean gdk_device_xi_query_state (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow **root_window,
+ GdkWindow **child_window,
+ gint *root_x,
+ gint *root_y,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask);
+static GdkGrabStatus gdk_device_xi_grab (GdkDevice *device,
+ GdkWindow *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time_);
+static void gdk_device_xi_ungrab (GdkDevice *device,
+ guint32 time_);
+
+static GdkWindow* gdk_device_xi_window_at_position (GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel);
+
+static void gdk_device_xi_select_window_events (GdkDevice *device,
+ GdkWindow *window,
+ GdkEventMask mask);
+
+
+G_DEFINE_TYPE (GdkDeviceXI, gdk_device_xi, GDK_TYPE_DEVICE)
+
+enum {
+ PROP_0,
+ PROP_DEVICE_ID
+};
+
+static void
+gdk_device_xi_class_init (GdkDeviceXIClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
+
+ quark_window_input_info = g_quark_from_static_string ("gdk-window-input-info");
+
+ object_class->constructed = gdk_device_xi_constructed;
+ object_class->set_property = gdk_device_xi_set_property;
+ object_class->get_property = gdk_device_xi_get_property;
+ object_class->dispose = gdk_device_xi_dispose;
+
+ device_class->get_history = gdk_device_xi_get_history;
+ device_class->get_state = gdk_device_xi_get_state;
+ device_class->set_window_cursor = gdk_device_xi_set_window_cursor;
+ device_class->warp = gdk_device_xi_warp;
+ device_class->query_state = gdk_device_xi_query_state;
+ device_class->grab = gdk_device_xi_grab;
+ device_class->ungrab = gdk_device_xi_ungrab;
+ device_class->window_at_position = gdk_device_xi_window_at_position;
+ device_class->select_window_events = gdk_device_xi_select_window_events;
+
+ g_object_class_install_property (object_class,
+ PROP_DEVICE_ID,
+ g_param_spec_int ("device-id",
+ P_("Device ID"),
+ P_("Device ID"),
+ 0, G_MAXINT, 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gdk_device_xi_init (GdkDeviceXI *device)
+{
+}
+
+static void
+gdk_device_xi_constructed (GObject *object)
+{
+ GdkDeviceXI *device;
+ GdkDisplay *display;
+
+ device = GDK_DEVICE_XI (object);
+ display = gdk_device_get_display (GDK_DEVICE (object));
+
+ gdk_error_trap_push ();
+ device->xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (display),
+ device->device_id);
+
+ if (gdk_error_trap_pop ())
+ g_warning ("Device %s can't be opened", GDK_DEVICE (device)->name);
+
+ if (G_OBJECT_CLASS (gdk_device_xi_parent_class)->constructed)
+ G_OBJECT_CLASS (gdk_device_xi_parent_class)->constructed (object);
+}
+
+static void
+gdk_device_xi_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdkDeviceXI *device = GDK_DEVICE_XI (object);
+
+ switch (prop_id)
+ {
+ case PROP_DEVICE_ID:
+ device->device_id = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdk_device_xi_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdkDeviceXI *device = GDK_DEVICE_XI (object);
+
+ switch (prop_id)
+ {
+ case PROP_DEVICE_ID:
+ g_value_set_int (value, device->device_id);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdk_device_xi_dispose (GObject *object)
+{
+ GdkDeviceXI *device_xi;
+ GdkDisplay *display;
+
+ device_xi = GDK_DEVICE_XI (object);
+ display = gdk_device_get_display (GDK_DEVICE (device_xi));
+
+ if (device_xi->xdevice)
+ {
+ XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device_xi->xdevice);
+ device_xi->xdevice = NULL;
+ }
+
+ if (device_xi->axis_data)
+ {
+ g_free (device_xi->axis_data);
+ device_xi->axis_data = NULL;
+ }
+
+ G_OBJECT_CLASS (gdk_device_xi_parent_class)->dispose (object);
+}
+
+static gboolean
+gdk_device_xi_get_history (GdkDevice *device,
+ GdkWindow *window,
+ guint32 start,
+ guint32 stop,
+ GdkTimeCoord ***events,
+ guint *n_events)
+{
+ GdkTimeCoord **coords;
+ XDeviceTimeCoord *device_coords;
+ GdkWindow *impl_window;
+ GdkDeviceXI *device_xi;
+ gint n_events_return;
+ gint mode_return;
+ gint axis_count_return;
+ gint i;
+
+ device_xi = GDK_DEVICE_XI (device);
+ impl_window = _gdk_window_get_impl_window (window);
+
+ device_coords = XGetDeviceMotionEvents (GDK_WINDOW_XDISPLAY (impl_window),
+ device_xi->xdevice,
+ start, stop,
+ &n_events_return,
+ &mode_return,
+ &axis_count_return);
+
+ if (!device_coords)
+ return FALSE;
+
+ *n_events = (guint) n_events_return;
+ coords = _gdk_device_allocate_history (device, *n_events);
+
+ for (i = 0; i < *n_events; i++)
+ {
+ coords[i]->time = device_coords[i].time;
+ gdk_device_xi_translate_axes (device, window,
+ device_coords[i].data,
+ coords[i]->axes,
+ NULL, NULL);
+ }
+
+ XFreeDeviceMotionEvents (device_coords);
+
+ *events = coords;
+
+ return TRUE;
+}
+
+static void
+gdk_device_xi_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask)
+{
+ GdkDeviceXI *device_xi;
+ XDeviceState *state;
+ XInputClass *input_class;
+ gint i;
+
+ if (mask)
+ gdk_window_get_pointer (window, NULL, NULL, mask);
+
+ device_xi = GDK_DEVICE_XI (device);
+ state = XQueryDeviceState (GDK_WINDOW_XDISPLAY (window),
+ device_xi->xdevice);
+ input_class = state->data;
+
+ for (i = 0; i < state->num_classes; i++)
+ {
+ switch (input_class->class)
+ {
+ case ValuatorClass:
+ if (axes)
+ gdk_device_xi_translate_axes (device, window,
+ ((XValuatorState *) input_class)->valuators,
+ axes, NULL, NULL);
+ break;
+
+ case ButtonClass:
+ if (mask)
+ {
+ *mask &= 0xFF;
+ if (((XButtonState *)input_class)->num_buttons > 0)
+ *mask |= ((XButtonState *)input_class)->buttons[0] << 7;
+ /* GDK_BUTTON1_MASK = 1 << 8, and button n is stored
+ * in bit 1<<(n%8) in byte n/8. n = 1,2,... */
+ }
+ break;
+ }
+
+ input_class = (XInputClass *)(((char *)input_class)+input_class->length);
+ }
+
+ XFreeDeviceState (state);
+}
+
+static void
+gdk_device_xi_set_window_cursor (GdkDevice *device,
+ GdkWindow *window,
+ GdkCursor *cursor)
+{
+}
+
+static void
+gdk_device_xi_warp (GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y)
+{
+}
+
+static void
+find_events (GdkDevice *device,
+ GdkEventMask mask,
+ XEventClass *classes,
+ int *num_classes)
+{
+ GdkDeviceXI *device_xi;
+ XEventClass class;
+ gint i;
+
+ device_xi = GDK_DEVICE_XI (device);
+ i = 0;
+
+ if (mask & GDK_BUTTON_PRESS_MASK)
+ {
+ DeviceButtonPress (device_xi->xdevice, device_xi->button_press_type, class);
+ if (class != 0)
+ classes[i++] = class;
+
+ DeviceButtonPressGrab (device_xi->xdevice, 0, class);
+ if (class != 0)
+ classes[i++] = class;
+ }
+
+ if (mask & GDK_BUTTON_RELEASE_MASK)
+ {
+ DeviceButtonRelease (device_xi->xdevice, device_xi->button_release_type, class);
+ if (class != 0)
+ classes[i++] = class;
+ }
+
+ if (mask & (GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK |
+ GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_MOTION_MASK))
+ {
+ /* Make sure device->motionnotify_type is set */
+ DeviceMotionNotify (device_xi->xdevice, device_xi->motion_notify_type, class);
+ if (class != 0)
+ classes[i++] = class;
+ DeviceStateNotify (device_xi->xdevice, device_xi->state_notify_type, class);
+ if (class != 0)
+ classes[i++] = class;
+ }
+
+ if (mask & GDK_KEY_PRESS_MASK)
+ {
+ DeviceKeyPress (device_xi->xdevice, device_xi->key_press_type, class);
+ if (class != 0)
+ classes[i++] = class;
+ }
+
+ if (mask & GDK_KEY_RELEASE_MASK)
+ {
+ DeviceKeyRelease (device_xi->xdevice, device_xi->key_release_type, class);
+ if (class != 0)
+ classes[i++] = class;
+ }
+
+ if (mask & GDK_PROXIMITY_IN_MASK)
+ {
+ ProximityIn (device_xi->xdevice, device_xi->proximity_in_type, class);
+ if (class != 0)
+ classes[i++] = class;
+ }
+
+ if (mask & GDK_PROXIMITY_OUT_MASK)
+ {
+ ProximityOut (device_xi->xdevice, device_xi->proximity_out_type, class);
+ if (class != 0)
+ classes[i++] = class;
+ }
+
+ *num_classes = i;
+}
+
+static gboolean
+gdk_device_xi_query_state (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow **root_window,
+ GdkWindow **child_window,
+ gint *root_x,
+ gint *root_y,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask)
+{
+ return FALSE;
+}
+
+static GdkGrabStatus
+gdk_device_xi_grab (GdkDevice *device,
+ GdkWindow *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time_)
+{
+ XEventClass event_classes[MAX_DEVICE_CLASSES];
+ gint status, num_classes;
+ GdkDeviceXI *device_xi;
+
+ device_xi = GDK_DEVICE_XI (device);
+ find_events (device, event_mask, event_classes, &num_classes);
+
+ status = XGrabDevice (GDK_WINDOW_XDISPLAY (window),
+ device_xi->xdevice,
+ GDK_WINDOW_XWINDOW (window),
+ owner_events,
+ num_classes, event_classes,
+ GrabModeAsync, GrabModeAsync,
+ time_);
+
+ return _gdk_x11_convert_grab_status (status);
+}
+
+static void
+gdk_device_xi_ungrab (GdkDevice *device,
+ guint32 time_)
+{
+ GdkDisplay *display;
+ GdkDeviceXI *device_xi;
+
+ device_xi = GDK_DEVICE_XI (device);
+ display = gdk_device_get_display (device);
+
+ XUngrabDevice (GDK_DISPLAY_XDISPLAY (device),
+ device_xi->xdevice,
+ time_);
+}
+
+static GdkWindow*
+gdk_device_xi_window_at_position (GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel)
+{
+ return NULL;
+}
+static void
+gdk_device_xi_select_window_events (GdkDevice *device,
+ GdkWindow *window,
+ GdkEventMask event_mask)
+{
+ XEventClass event_classes[MAX_DEVICE_CLASSES];
+ GdkDeviceXI *device_xi;
+ gint num_classes;
+
+ event_mask |= (GDK_PROXIMITY_IN_MASK |
+ GDK_PROXIMITY_OUT_MASK);
+
+ device_xi = GDK_DEVICE_XI (device);
+ find_events (device, event_mask, event_classes, &num_classes);
+
+ XSelectExtensionEvent (GDK_WINDOW_XDISPLAY (window),
+ GDK_WINDOW_XWINDOW (window),
+ event_classes, num_classes);
+
+ if (event_mask)
+ {
+ GdkWindowInputInfo *info;
+
+ info = g_new0 (GdkWindowInputInfo, 1);
+ g_object_set_qdata_full (G_OBJECT (window),
+ quark_window_input_info,
+ info,
+ (GDestroyNotify) g_free);
+ }
+ else
+ g_object_set_qdata (G_OBJECT (window),
+ quark_window_input_info,
+ NULL);
+}
+
+void
+gdk_device_xi_update_window_info (GdkWindow *window)
+{
+ GdkWindowInputInfo *info;
+ gint root_x, root_y;
+
+ info = g_object_get_qdata (G_OBJECT (window),
+ quark_window_input_info);
+
+ if (!info)
+ return;
+
+ gdk_window_get_origin (window, &root_x, &root_y);
+ info->root_x = (gdouble) root_x;
+ info->root_y = (gdouble) root_y;
+}
+
+static gboolean
+gdk_device_xi_get_window_info (GdkWindow *window,
+ gdouble *root_x,
+ gdouble *root_y)
+{
+ GdkWindowInputInfo *info;
+
+ info = g_object_get_qdata (G_OBJECT (window),
+ quark_window_input_info);
+
+ if (!info)
+ return FALSE;
+
+ *root_x = info->root_x;
+ *root_y = info->root_y;
+
+ return TRUE;
+}
+
+void
+gdk_device_xi_update_axes (GdkDevice *device,
+ gint axes_count,
+ gint first_axis,
+ gint *axis_data)
+{
+ GdkDeviceXI *device_xi;
+ int i;
+
+ device_xi = GDK_DEVICE_XI (device);
+ g_return_if_fail (first_axis >= 0 && first_axis + axes_count <= device->num_axes);
+
+ if (!device_xi->axis_data)
+ device_xi->axis_data = g_new0 (gint, device->num_axes);
+
+ for (i = 0; i < axes_count; i++)
+ device_xi->axis_data[first_axis + i] = axis_data[i];
+}
+
+void
+gdk_device_xi_translate_axes (GdkDevice *device,
+ GdkWindow *window,
+ gint *axis_data,
+ gdouble *axes,
+ gdouble *x,
+ gdouble *y)
+{
+ GdkDeviceXI *device_xi;
+ GdkWindow *impl_window;
+ gdouble root_x, root_y;
+ gdouble temp_x, temp_y;
+ gint i;
+
+ device_xi = GDK_DEVICE_XI (device);
+ impl_window = _gdk_window_get_impl_window (window);
+ temp_x = temp_y = 0;
+
+ if (!gdk_device_xi_get_window_info (impl_window, &root_x, &root_y))
+ return;
+
+ for (i = 0; i < device->num_axes; i++)
+ {
+ GdkAxisUse use;
+
+ use = _gdk_device_get_axis_use (device, i);
+
+ switch (use)
+ {
+ case GDK_AXIS_X:
+ case GDK_AXIS_Y:
+ if (device->mode == GDK_MODE_WINDOW)
+ _gdk_device_translate_window_coord (device, window,
+ i, axis_data[i],
+ &axes[i]);
+ else
+ _gdk_device_translate_screen_coord (device, window,
+ root_x, root_y,
+ i, axis_data[i],
+ &axes[i]);
+ if (use == GDK_AXIS_X)
+ temp_x = axes[i];
+ else if (use == GDK_AXIS_Y)
+ temp_y = axes[i];
+
+ break;
+ default:
+ _gdk_device_translate_axis (device, i, axis_data[i], &axes[i]);
+ break;
+ }
+ }
+
+ if (x)
+ *x = temp_x;
+
+ if (y)
+ *y = temp_y;
+}
diff --git a/gdk/x11/gdkdevice-xi.h b/gdk/x11/gdkdevice-xi.h
new file mode 100644
index 0000000000..55f33d30a2
--- /dev/null
+++ b/gdk/x11/gdkdevice-xi.h
@@ -0,0 +1,88 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GDK_DEVICE_XI_H__
+#define __GDK_DEVICE_XI_H__
+
+#include <gdk/gdkdeviceprivate.h>
+#include <X11/extensions/XInput.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_XI (gdk_device_xi_get_type ())
+#define GDK_DEVICE_XI(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_XI, GdkDeviceXI))
+#define GDK_DEVICE_XI_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_XI, GdkDeviceXIClass))
+#define GDK_IS_DEVICE_XI(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_XI))
+#define GDK_IS_DEVICE_XI_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_XI))
+#define GDK_DEVICE_XI_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_XI, GdkDeviceXIClass))
+
+typedef struct _GdkDeviceXI GdkDeviceXI;
+typedef struct _GdkDeviceXIClass GdkDeviceXIClass;
+
+struct _GdkDeviceXI
+{
+ GdkDevice parent_instance;
+
+ guint32 device_id;
+ XDevice *xdevice;
+
+ gint button_press_type;
+ gint button_release_type;
+ gint key_press_type;
+ gint key_release_type;
+ gint motion_notify_type;
+ gint proximity_in_type;
+ gint proximity_out_type;
+ gint state_notify_type;
+
+ /* minimum key code for device */
+ gint min_keycode;
+
+ gint *axis_data;
+
+ guint in_proximity : 1;
+};
+
+struct _GdkDeviceXIClass
+{
+ GdkDeviceClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType gdk_device_xi_get_type (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+void gdk_device_xi_update_window_info (GdkWindow *window);
+
+G_GNUC_INTERNAL
+void gdk_device_xi_update_axes (GdkDevice *device,
+ gint axes_count,
+ gint first_axis,
+ gint *axis_data);
+G_GNUC_INTERNAL
+void gdk_device_xi_translate_axes (GdkDevice *device,
+ GdkWindow *window,
+ gint *axis_data,
+ gdouble *axes,
+ gdouble *x,
+ gdouble *y);
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_XI_H__ */
diff --git a/gdk/x11/gdkdevice-xi2.c b/gdk/x11/gdkdevice-xi2.c
new file mode 100644
index 0000000000..d7bc64e66e
--- /dev/null
+++ b/gdk/x11/gdkdevice-xi2.c
@@ -0,0 +1,621 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+
+#include <X11/extensions/XInput2.h>
+#include "gdkdevice-xi2.h"
+#include "gdkintl.h"
+#include "gdkx.h"
+
+
+struct _GdkDeviceXI2Private
+{
+ int device_id;
+};
+
+static void gdk_device_xi2_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gdk_device_xi2_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void gdk_device_xi2_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask);
+static void gdk_device_xi2_set_window_cursor (GdkDevice *device,
+ GdkWindow *window,
+ GdkCursor *cursor);
+static void gdk_device_xi2_warp (GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y);
+static gboolean gdk_device_xi2_query_state (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow **root_window,
+ GdkWindow **child_window,
+ gint *root_x,
+ gint *root_y,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask);
+
+static GdkGrabStatus gdk_device_xi2_grab (GdkDevice *device,
+ GdkWindow *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time_);
+static void gdk_device_xi2_ungrab (GdkDevice *device,
+ guint32 time_);
+
+static GdkWindow * gdk_device_xi2_window_at_position (GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel);
+static void gdk_device_xi2_select_window_events (GdkDevice *device,
+ GdkWindow *window,
+ GdkEventMask event_mask);
+
+
+G_DEFINE_TYPE (GdkDeviceXI2, gdk_device_xi2, GDK_TYPE_DEVICE)
+
+enum {
+ PROP_0,
+ PROP_DEVICE_ID
+};
+
+static void
+gdk_device_xi2_class_init (GdkDeviceXI2Class *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
+
+ object_class->get_property = gdk_device_xi2_get_property;
+ object_class->set_property = gdk_device_xi2_set_property;
+
+ device_class->get_state = gdk_device_xi2_get_state;
+ device_class->set_window_cursor = gdk_device_xi2_set_window_cursor;
+ device_class->warp = gdk_device_xi2_warp;
+ device_class->query_state = gdk_device_xi2_query_state;
+ device_class->grab = gdk_device_xi2_grab;
+ device_class->ungrab = gdk_device_xi2_ungrab;
+ device_class->window_at_position = gdk_device_xi2_window_at_position;
+ device_class->select_window_events = gdk_device_xi2_select_window_events;
+
+ g_object_class_install_property (object_class,
+ PROP_DEVICE_ID,
+ g_param_spec_int ("device-id",
+ P_("Device ID"),
+ P_("Device identifier"),
+ 0, G_MAXINT, 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_type_class_add_private (object_class, sizeof (GdkDeviceXI2Private));
+}
+
+static void
+gdk_device_xi2_init (GdkDeviceXI2 *device)
+{
+ GdkDeviceXI2Private *priv;
+
+ device->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
+ GDK_TYPE_DEVICE_XI2,
+ GdkDeviceXI2Private);
+}
+
+static void
+gdk_device_xi2_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdkDeviceXI2Private *priv;
+
+ priv = GDK_DEVICE_XI2 (object)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_DEVICE_ID:
+ g_value_set_int (value, priv->device_id);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdk_device_xi2_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdkDeviceXI2Private *priv;
+
+ priv = GDK_DEVICE_XI2 (object)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_DEVICE_ID:
+ priv->device_id = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdk_device_xi2_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask)
+{
+ GdkDeviceXI2Private *priv;
+ GdkDisplay *display;
+ XIDeviceInfo *info;
+ gint i, j, ndevices;
+
+ priv = GDK_DEVICE_XI2 (device)->priv;
+ display = gdk_device_get_display (device);
+
+ if (axes)
+ {
+ info = XIQueryDevice(GDK_DISPLAY_XDISPLAY (display),
+ priv->device_id, &ndevices);
+
+ for (i = 0, j = 0; i < info->num_classes; i++)
+ {
+ XIAnyClassInfo *class_info = info->classes[i];
+ GdkAxisUse use;
+ gdouble value;
+
+ if (class_info->type != XIValuatorClass)
+ continue;
+
+ value = ((XIValuatorClassInfo *) class_info)->value;
+ use = _gdk_device_get_axis_use (device, j);
+
+ switch (use)
+ {
+ case GDK_AXIS_X:
+ case GDK_AXIS_Y:
+ case GDK_AXIS_IGNORE:
+ if (device->mode == GDK_MODE_WINDOW)
+ _gdk_device_translate_window_coord (device, window, j, value, &axes[j]);
+ else
+ {
+ gint root_x, root_y;
+
+ /* FIXME: Maybe root coords chaching should happen here */
+ gdk_window_get_origin (window, &root_x, &root_y);
+ _gdk_device_translate_screen_coord (device, window,
+ root_x, root_y,
+ j, value,
+ &axes[j]);
+ }
+ break;
+ default:
+ _gdk_device_translate_axis (device, j, value, &axes[j]);
+ break;
+ }
+
+ j++;
+ }
+
+ XIFreeDeviceInfo (info);
+ }
+
+ if (mask)
+ gdk_device_xi2_query_state (device, window,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ mask);
+}
+
+static void
+gdk_device_xi2_set_window_cursor (GdkDevice *device,
+ GdkWindow *window,
+ GdkCursor *cursor)
+{
+ GdkDeviceXI2Private *priv;
+ GdkCursorPrivate *cursor_private;
+
+ priv = GDK_DEVICE_XI2 (device)->priv;
+
+ /* Non-master devices don't have a cursor */
+ if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER)
+ return;
+
+ if (cursor)
+ {
+ cursor_private = (GdkCursorPrivate*) cursor;
+
+ XIDefineCursor (GDK_WINDOW_XDISPLAY (window),
+ priv->device_id,
+ GDK_WINDOW_XWINDOW (window),
+ cursor_private->xcursor);
+ }
+ else
+ XIUndefineCursor (GDK_WINDOW_XDISPLAY (window),
+ priv->device_id,
+ GDK_WINDOW_XWINDOW (window));
+}
+
+static void
+gdk_device_xi2_warp (GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y)
+{
+ GdkDeviceXI2Private *priv;
+ Window dest;
+
+ priv = GDK_DEVICE_XI2 (device)->priv;
+ dest = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
+
+ XIWarpPointer (GDK_SCREEN_XDISPLAY (screen),
+ priv->device_id,
+ None, dest,
+ 0, 0, 0, 0, x, y);
+}
+
+static gboolean
+gdk_device_xi2_query_state (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow **root_window,
+ GdkWindow **child_window,
+ gint *root_x,
+ gint *root_y,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask)
+{
+ GdkDisplay *display;
+ GdkDeviceXI2Private *priv;
+ Window xroot_window, xchild_window;
+ gdouble xroot_x, xroot_y, xwin_x, xwin_y;
+ XIButtonState button_state;
+ XIModifierState mod_state;
+ XIGroupState group_state;
+
+ if (!window || GDK_WINDOW_DESTROYED (window))
+ return FALSE;
+
+ priv = GDK_DEVICE_XI2 (device)->priv;
+ display = gdk_drawable_get_display (window);
+
+ if (!XIQueryPointer (GDK_WINDOW_XDISPLAY (window),
+ priv->device_id,
+ GDK_WINDOW_XID (window),
+ &xroot_window,
+ &xchild_window,
+ &xroot_x,
+ &xroot_y,
+ &xwin_x,
+ &xwin_y,
+ &button_state,
+ &mod_state,
+ &group_state))
+ {
+ return FALSE;
+ }
+
+ if (root_window)
+ *root_window = gdk_window_lookup_for_display (display, xroot_window);
+
+ if (child_window)
+ *child_window = gdk_window_lookup_for_display (display, xchild_window);
+
+ if (root_x)
+ *root_x = (gint) xroot_x;
+
+ if (root_y)
+ *root_y = (gint) xroot_y;
+
+ if (win_x)
+ *win_x = (gint) xwin_x;
+
+ if (win_y)
+ *win_y = (gint) xwin_y;
+
+ if (mask)
+ *mask = gdk_device_xi2_translate_state (&mod_state, &button_state);
+
+ return TRUE;
+}
+
+static GdkGrabStatus
+gdk_device_xi2_grab (GdkDevice *device,
+ GdkWindow *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time_)
+{
+ GdkDeviceXI2Private *priv;
+ GdkDisplay *display;
+ XIEventMask mask;
+ Window xwindow;
+ Cursor xcursor;
+ int status;
+
+ priv = GDK_DEVICE_XI2 (device)->priv;
+ display = gdk_device_get_display (device);
+
+ /* FIXME: confine_to is actually unused */
+
+ xwindow = GDK_WINDOW_XID (window);
+
+ if (!cursor)
+ xcursor = None;
+ else
+ {
+ _gdk_x11_cursor_update_theme (cursor);
+ xcursor = ((GdkCursorPrivate *) cursor)->xcursor;
+ }
+
+ mask.deviceid = priv->device_id;
+ mask.mask = gdk_device_xi2_translate_event_mask (event_mask, &mask.mask_len);
+
+ status = XIGrabDevice (GDK_DISPLAY_XDISPLAY (display),
+ priv->device_id,
+ xwindow,
+ time_,
+ xcursor,
+ GrabModeAsync, GrabModeAsync,
+ owner_events,
+ &mask);
+
+ g_free (mask.mask);
+
+ return _gdk_x11_convert_grab_status (status);
+}
+
+static void
+gdk_device_xi2_ungrab (GdkDevice *device,
+ guint32 time_)
+{
+ GdkDeviceXI2Private *priv;
+ GdkDisplay *display;
+
+ priv = GDK_DEVICE_XI2 (device)->priv;
+ display = gdk_device_get_display (device);
+
+ XIUngrabDevice (GDK_DISPLAY_XDISPLAY (display),
+ priv->device_id,
+ time_);
+}
+
+static GdkWindow *
+gdk_device_xi2_window_at_position (GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel)
+{
+ GdkDeviceXI2Private *priv;
+ GdkDisplay *display;
+ GdkScreen *screen;
+ Display *xdisplay;
+ GdkWindow *window;
+ Window xwindow, root, child, last = None;
+ gdouble xroot_x, xroot_y, xwin_x, xwin_y;
+ XIButtonState button_state;
+ XIModifierState mod_state;
+ XIGroupState group_state;
+
+ priv = GDK_DEVICE_XI2 (device)->priv;
+ display = gdk_device_get_display (device);
+ screen = gdk_display_get_default_screen (display);
+
+ /* This function really only works if the mouse pointer is held still
+ * during its operation. If it moves from one leaf window to another
+ * than we'll end up with inaccurate values for win_x, win_y
+ * and the result.
+ */
+ gdk_x11_display_grab (display);
+
+ xdisplay = GDK_SCREEN_XDISPLAY (screen);
+ xwindow = GDK_SCREEN_XROOTWIN (screen);
+
+ XIQueryPointer (xdisplay,
+ priv->device_id,
+ xwindow,
+ &root, &child,
+ &xroot_x, &xroot_y,
+ &xwin_x, &xwin_y,
+ &button_state,
+ &mod_state,
+ &group_state);
+
+ if (root == xwindow)
+ xwindow = child;
+ else
+ xwindow = root;
+
+ while (xwindow)
+ {
+ last = xwindow;
+ XIQueryPointer (xdisplay,
+ priv->device_id,
+ xwindow,
+ &root, &xwindow,
+ &xroot_x, &xroot_y,
+ &xwin_x, &xwin_y,
+ &button_state,
+ &mod_state,
+ &group_state);
+
+ if (get_toplevel && last != root &&
+ (window = gdk_window_lookup_for_display (display, last)) != NULL &&
+ GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
+ {
+ xwindow = last;
+ break;
+ }
+ }
+
+ gdk_x11_display_ungrab (display);
+
+ window = gdk_window_lookup_for_display (display, last);
+
+ if (win_x)
+ *win_x = (window) ? (gint) xwin_x : -1;
+
+ if (win_y)
+ *win_y = (window) ? (gint) xwin_y : -1;
+
+ if (mask)
+ *mask = gdk_device_xi2_translate_state (&mod_state, &button_state);
+
+ return window;
+}
+
+static void
+gdk_device_xi2_select_window_events (GdkDevice *device,
+ GdkWindow *window,
+ GdkEventMask event_mask)
+{
+ GdkDeviceXI2Private *priv;
+ XIEventMask evmask;
+
+ priv = GDK_DEVICE_XI2 (device)->priv;
+
+ evmask.deviceid = priv->device_id;
+ evmask.mask = gdk_device_xi2_translate_event_mask (event_mask, &evmask.mask_len);
+
+ XISelectEvents (GDK_WINDOW_XDISPLAY (window),
+ GDK_WINDOW_XWINDOW (window),
+ &evmask, 1);
+
+ g_free (evmask.mask);
+}
+
+guchar *
+gdk_device_xi2_translate_event_mask (GdkEventMask event_mask,
+ int *len)
+{
+ guchar *mask;
+
+ *len = XIMaskLen (XI_LASTEVENT);
+ mask = g_new0 (guchar, *len);
+
+ if (event_mask & GDK_POINTER_MOTION_MASK ||
+ event_mask & GDK_POINTER_MOTION_HINT_MASK)
+ XISetMask (mask, XI_Motion);
+
+ if (event_mask & GDK_BUTTON_MOTION_MASK ||
+ event_mask & GDK_BUTTON1_MOTION_MASK ||
+ event_mask & GDK_BUTTON2_MOTION_MASK ||
+ event_mask & GDK_BUTTON3_MOTION_MASK)
+ {
+ XISetMask (mask, XI_ButtonPress);
+ XISetMask (mask, XI_ButtonRelease);
+ XISetMask (mask, XI_Motion);
+ }
+
+ if (event_mask & GDK_SCROLL_MASK)
+ {
+ XISetMask (mask, XI_ButtonPress);
+ XISetMask (mask, XI_ButtonRelease);
+ }
+
+ if (event_mask & GDK_BUTTON_PRESS_MASK)
+ XISetMask (mask, XI_ButtonPress);
+
+ if (event_mask & GDK_BUTTON_RELEASE_MASK)
+ XISetMask (mask, XI_ButtonRelease);
+
+ if (event_mask & GDK_KEY_PRESS_MASK)
+ XISetMask (mask, XI_KeyPress);
+
+ if (event_mask & GDK_KEY_RELEASE_MASK)
+ XISetMask (mask, XI_KeyRelease);
+
+ if (event_mask & GDK_ENTER_NOTIFY_MASK)
+ XISetMask (mask, XI_Enter);
+
+ if (event_mask & GDK_LEAVE_NOTIFY_MASK)
+ XISetMask (mask, XI_Leave);
+
+ if (event_mask & GDK_FOCUS_CHANGE_MASK)
+ {
+ XISetMask (mask, XI_FocusIn);
+ XISetMask (mask, XI_FocusOut);
+ }
+
+ return mask;
+}
+
+guint
+gdk_device_xi2_translate_state (XIModifierState *mods_state,
+ XIButtonState *buttons_state)
+{
+ guint state = 0;
+
+ if (mods_state)
+ state = (guint) mods_state->effective;
+
+ if (buttons_state)
+ {
+ gint len, i;
+
+ /* We're only interested in the first 5 buttons */
+ len = MIN (5, buttons_state->mask_len * 8);
+
+ for (i = 0; i < len; i++)
+ {
+ if (!XIMaskIsSet (buttons_state->mask, i))
+ continue;
+
+ switch (i)
+ {
+ case 1:
+ state |= GDK_BUTTON1_MASK;
+ break;
+ case 2:
+ state |= GDK_BUTTON2_MASK;
+ break;
+ case 3:
+ state |= GDK_BUTTON3_MASK;
+ break;
+ case 4:
+ state |= GDK_BUTTON4_MASK;
+ break;
+ case 5:
+ state |= GDK_BUTTON5_MASK;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return state;
+}
diff --git a/gdk/x11/gdkdevice-xi2.h b/gdk/x11/gdkdevice-xi2.h
new file mode 100644
index 0000000000..67e4dc940a
--- /dev/null
+++ b/gdk/x11/gdkdevice-xi2.h
@@ -0,0 +1,64 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GDK_DEVICE_XI2_H__
+#define __GDK_DEVICE_XI2_H__
+
+#include <gdk/gdkdeviceprivate.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_XI2 (gdk_device_xi2_get_type ())
+#define GDK_DEVICE_XI2(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_XI2, GdkDeviceXI2))
+#define GDK_DEVICE_XI2_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_XI2, GdkDeviceXI2Class))
+#define GDK_IS_DEVICE_XI2(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_XI2))
+#define GDK_IS_DEVICE_XI2_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_XI2))
+#define GDK_DEVICE_XI2_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_XI2, GdkDeviceXI2Class))
+
+typedef struct _GdkDeviceXI2 GdkDeviceXI2;
+typedef struct _GdkDeviceXI2Private GdkDeviceXI2Private;
+typedef struct _GdkDeviceXI2Class GdkDeviceXI2Class;
+
+struct _GdkDeviceXI2
+{
+ GdkDevice parent_instance;
+
+ /*< private >*/
+ GdkDeviceXI2Private *priv;
+};
+
+struct _GdkDeviceXI2Class
+{
+ GdkDeviceClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType gdk_device_xi2_get_type (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+guchar * gdk_device_xi2_translate_event_mask (GdkEventMask event_mask,
+ int *len);
+G_GNUC_INTERNAL
+guint gdk_device_xi2_translate_state (XIModifierState *mods_state,
+ XIButtonState *buttons_state);
+
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_XI2_H__ */
diff --git a/gdk/x11/gdkdevicemanager-core.c b/gdk/x11/gdkdevicemanager-core.c
new file mode 100644
index 0000000000..0e7b8c33d2
--- /dev/null
+++ b/gdk/x11/gdkdevicemanager-core.c
@@ -0,0 +1,904 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+
+#include <gdk/gdktypes.h>
+#include <gdk/gdkdevicemanager.h>
+#include "gdkdevicemanager-core.h"
+#include "gdkeventtranslator.h"
+#include "gdkdevice-core.h"
+#include "gdkkeysyms.h"
+#include "gdkprivate-x11.h"
+#include "gdkx.h"
+#include "gdkalias.h"
+
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
+
+#define HAS_FOCUS(toplevel) \
+ ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
+
+static void gdk_device_manager_core_finalize (GObject *object);
+static void gdk_device_manager_core_constructed (GObject *object);
+
+static GList * gdk_device_manager_core_list_devices (GdkDeviceManager *device_manager,
+ GdkDeviceType type);
+
+static void gdk_device_manager_event_translator_init (GdkEventTranslatorIface *iface);
+
+static gboolean gdk_device_manager_core_translate_event (GdkEventTranslator *translator,
+ GdkDisplay *display,
+ GdkEvent *event,
+ XEvent *xevent);
+
+
+G_DEFINE_TYPE_WITH_CODE (GdkDeviceManagerCore, gdk_device_manager_core, GDK_TYPE_DEVICE_MANAGER,
+ G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
+ gdk_device_manager_event_translator_init))
+
+static void
+gdk_device_manager_core_class_init (GdkDeviceManagerCoreClass *klass)
+{
+ GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gdk_device_manager_core_finalize;
+ object_class->constructed = gdk_device_manager_core_constructed;
+ device_manager_class->list_devices = gdk_device_manager_core_list_devices;
+}
+
+static void
+gdk_device_manager_event_translator_init (GdkEventTranslatorIface *iface)
+{
+ iface->translate_event = gdk_device_manager_core_translate_event;
+}
+
+static GdkDevice *
+create_core_pointer (GdkDeviceManager *device_manager,
+ GdkDisplay *display)
+{
+ return g_object_new (GDK_TYPE_DEVICE_CORE,
+ "name", "Core Pointer",
+ "type", GDK_DEVICE_TYPE_MASTER,
+ "input-source", GDK_SOURCE_MOUSE,
+ "input-mode", GDK_MODE_SCREEN,
+ "has-cursor", TRUE,
+ "display", display,
+ "device-manager", device_manager,
+ NULL);
+}
+
+static GdkDevice *
+create_core_keyboard (GdkDeviceManager *device_manager,
+ GdkDisplay *display)
+{
+ return g_object_new (GDK_TYPE_DEVICE_CORE,
+ "name", "Core Keyboard",
+ "type", GDK_DEVICE_TYPE_MASTER,
+ "input-source", GDK_SOURCE_KEYBOARD,
+ "input-mode", GDK_MODE_SCREEN,
+ "has-cursor", FALSE,
+ "display", display,
+ "device-manager", device_manager,
+ NULL);
+}
+
+static void
+gdk_device_manager_core_init (GdkDeviceManagerCore *device_manager)
+{
+}
+
+static void
+gdk_device_manager_core_finalize (GObject *object)
+{
+ GdkDeviceManagerCore *device_manager_core;
+
+ device_manager_core = GDK_DEVICE_MANAGER_CORE (object);
+
+ g_object_unref (device_manager_core->core_pointer);
+ g_object_unref (device_manager_core->core_keyboard);
+
+ G_OBJECT_CLASS (gdk_device_manager_core_parent_class)->finalize (object);
+}
+
+static void
+gdk_device_manager_core_constructed (GObject *object)
+{
+ GdkDeviceManagerCore *device_manager;
+ GdkDisplay *display;
+
+ device_manager = GDK_DEVICE_MANAGER_CORE (object);
+ display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
+ device_manager->core_pointer = create_core_pointer (GDK_DEVICE_MANAGER (device_manager), display);
+ device_manager->core_keyboard = create_core_keyboard (GDK_DEVICE_MANAGER (device_manager), display);
+
+ _gdk_device_set_associated_device (device_manager->core_pointer, device_manager->core_keyboard);
+ _gdk_device_set_associated_device (device_manager->core_keyboard, device_manager->core_pointer);
+}
+
+static void
+translate_key_event (GdkDisplay *display,
+ GdkDeviceManagerCore *device_manager,
+ GdkEvent *event,
+ XEvent *xevent)
+{
+ GdkKeymap *keymap = gdk_keymap_get_for_display (display);
+ GdkModifierType consumed, state;
+ gunichar c = 0;
+ gchar buf[7];
+
+ event->key.type = xevent->xany.type == KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
+ event->key.time = xevent->xkey.time;
+ gdk_event_set_device (event, device_manager->core_keyboard);
+
+ event->key.state = (GdkModifierType) xevent->xkey.state;
+ event->key.group = _gdk_x11_get_group_for_state (display, xevent->xkey.state);
+ event->key.hardware_keycode = xevent->xkey.keycode;
+
+ event->key.keyval = GDK_VoidSymbol;
+
+ gdk_keymap_translate_keyboard_state (keymap,
+ event->key.hardware_keycode,
+ event->key.state,
+ event->key.group,
+ &event->key.keyval,
+ NULL, NULL, &consumed);
+
+ state = event->key.state & ~consumed;
+ _gdk_keymap_add_virtual_modifiers_compat (keymap, &state);
+ event->key.state |= state;
+
+ event->key.is_modifier = _gdk_keymap_key_is_modifier (keymap, event->key.hardware_keycode);
+
+ /* Fill in event->string crudely, since various programs
+ * depend on it.
+ */
+ event->key.string = NULL;
+
+ if (event->key.keyval != GDK_VoidSymbol)
+ c = gdk_keyval_to_unicode (event->key.keyval);
+
+ if (c)
+ {
+ gsize bytes_written;
+ gint len;
+
+ /* Apply the control key - Taken from Xlib
+ */
+ if (event->key.state & GDK_CONTROL_MASK)
+ {
+ if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
+ else if (c == '2')
+ {
+ event->key.string = g_memdup ("\0\0", 2);
+ event->key.length = 1;
+ buf[0] = '\0';
+ goto out;
+ }
+ else if (c >= '3' && c <= '7') c -= ('3' - '\033');
+ else if (c == '8') c = '\177';
+ else if (c == '/') c = '_' & 0x1F;
+ }
+
+ len = g_unichar_to_utf8 (c, buf);
+ buf[len] = '\0';
+
+ event->key.string = g_locale_from_utf8 (buf, len,
+ NULL, &bytes_written,
+ NULL);
+ if (event->key.string)
+ event->key.length = bytes_written;
+ }
+ else if (event->key.keyval == GDK_Escape)
+ {
+ event->key.length = 1;
+ event->key.string = g_strdup ("\033");
+ }
+ else if (event->key.keyval == GDK_Return ||
+ event->key.keyval == GDK_KP_Enter)
+ {
+ event->key.length = 1;
+ event->key.string = g_strdup ("\r");
+ }
+
+ if (!event->key.string)
+ {
+ event->key.length = 0;
+ event->key.string = g_strdup ("");
+ }
+
+ out:
+#ifdef G_ENABLE_DEBUG
+ if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
+ {
+ g_message ("%s:\t\twindow: %ld key: %12s %d",
+ event->type == GDK_KEY_PRESS ? "key press " : "key release",
+ xevent->xkey.window,
+ event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
+ event->key.keyval);
+
+ if (event->key.length > 0)
+ g_message ("\t\tlength: %4d string: \"%s\"",
+ event->key.length, buf);
+ }
+#endif /* G_ENABLE_DEBUG */
+ return;
+}
+
+#ifdef G_ENABLE_DEBUG
+static const char notify_modes[][19] = {
+ "NotifyNormal",
+ "NotifyGrab",
+ "NotifyUngrab",
+ "NotifyWhileGrabbed"
+};
+
+static const char notify_details[][23] = {
+ "NotifyAncestor",
+ "NotifyVirtual",
+ "NotifyInferior",
+ "NotifyNonlinear",
+ "NotifyNonlinearVirtual",
+ "NotifyPointer",
+ "NotifyPointerRoot",
+ "NotifyDetailNone"
+};
+#endif
+
+static void
+set_user_time (GdkWindow *window,
+ GdkEvent *event)
+{
+ g_return_if_fail (event != NULL);
+
+ window = gdk_window_get_toplevel (event->client.window);
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ /* If an event doesn't have a valid timestamp, we shouldn't use it
+ * to update the latest user interaction time.
+ */
+ if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
+ gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
+ gdk_event_get_time (event));
+}
+
+static void
+generate_focus_event (GdkDeviceManagerCore *device_manager,
+ GdkWindow *window,
+ gboolean in)
+{
+ GdkEvent *event;
+
+ event = gdk_event_new (GDK_FOCUS_CHANGE);
+ event->focus_change.window = g_object_ref (window);
+ event->focus_change.send_event = FALSE;
+ event->focus_change.in = in;
+ gdk_event_set_device (event, device_manager->core_keyboard);
+
+ gdk_event_put (event);
+ gdk_event_free (event);
+}
+
+static gboolean
+set_screen_from_root (GdkDisplay *display,
+ GdkEvent *event,
+ Window xrootwin)
+{
+ GdkScreen *screen;
+
+ screen = _gdk_x11_display_screen_for_xrootwin (display, xrootwin);
+
+ if (screen)
+ {
+ gdk_event_set_screen (event, screen);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static GdkCrossingMode
+translate_crossing_mode (int mode)
+{
+ switch (mode)
+ {
+ case NotifyNormal:
+ return GDK_CROSSING_NORMAL;
+ case NotifyGrab:
+ return GDK_CROSSING_GRAB;
+ case NotifyUngrab:
+ return GDK_CROSSING_UNGRAB;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static GdkNotifyType
+translate_notify_type (int detail)
+{
+ switch (detail)
+ {
+ case NotifyInferior:
+ return GDK_NOTIFY_INFERIOR;
+ case NotifyAncestor:
+ return GDK_NOTIFY_ANCESTOR;
+ case NotifyVirtual:
+ return GDK_NOTIFY_VIRTUAL;
+ case NotifyNonlinear:
+ return GDK_NOTIFY_NONLINEAR;
+ case NotifyNonlinearVirtual:
+ return GDK_NOTIFY_NONLINEAR_VIRTUAL;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static gboolean
+is_parent_of (GdkWindow *parent,
+ GdkWindow *child)
+{
+ GdkWindow *w;
+
+ w = child;
+ while (w != NULL)
+ {
+ if (w == parent)
+ return TRUE;
+
+ w = gdk_window_get_parent (w);
+ }
+
+ return FALSE;
+}
+
+static GdkWindow *
+get_event_window (GdkEventTranslator *translator,
+ XEvent *xevent)
+{
+ GdkDeviceManager *device_manager;
+ GdkDisplay *display;
+ GdkWindow *window;
+
+ device_manager = GDK_DEVICE_MANAGER (translator);
+ display = gdk_device_manager_get_display (device_manager);
+ window = gdk_window_lookup_for_display (display, xevent->xany.window);
+
+ /* Apply keyboard grabs to non-native windows */
+ if (xevent->type == KeyPress || xevent->type == KeyRelease)
+ {
+ GdkDeviceGrabInfo *info;
+ gulong serial;
+
+ serial = _gdk_windowing_window_get_next_serial (display);
+ info = _gdk_display_has_device_grab (display,
+ GDK_DEVICE_MANAGER_CORE (device_manager)->core_keyboard,
+ serial);
+ if (info &&
+ (!is_parent_of (info->window, window) ||
+ !info->owner_events))
+ {
+ /* Report key event against grab window */
+ window = info->window;
+ }
+ }
+
+ return window;
+}
+
+static gboolean
+gdk_device_manager_core_translate_event (GdkEventTranslator *translator,
+ GdkDisplay *display,
+ GdkEvent *event,
+ XEvent *xevent)
+{
+ GdkDeviceManagerCore *device_manager;
+ GdkWindow *window;
+ GdkWindowObject *window_private;
+ GdkWindowImplX11 *window_impl = NULL;
+ gboolean return_val;
+ GdkToplevelX11 *toplevel = NULL;
+ GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+ device_manager = GDK_DEVICE_MANAGER_CORE (translator);
+ return_val = FALSE;
+
+ window = get_event_window (translator, xevent);
+ window_private = (GdkWindowObject *) window;
+
+ if (window && GDK_WINDOW_DESTROYED (window))
+ return FALSE;
+
+ if (window)
+ {
+ toplevel = _gdk_x11_window_get_toplevel (window);
+ window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
+ g_object_ref (window);
+ }
+
+ event->any.window = window;
+ event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
+
+ if (window_private && GDK_WINDOW_DESTROYED (window))
+ {
+ if (xevent->type != DestroyNotify)
+ {
+ return_val = FALSE;
+ goto done;
+ }
+ }
+
+ if (window &&
+ (xevent->type == MotionNotify ||
+ xevent->type == ButtonRelease))
+ {
+ if (_gdk_moveresize_handle_event (xevent))
+ {
+ return_val = FALSE;
+ goto done;
+ }
+ }
+
+ /* We do a "manual" conversion of the XEvent to a
+ * GdkEvent. The structures are mostly the same so
+ * the conversion is fairly straightforward. We also
+ * optionally print debugging info regarding events
+ * received.
+ */
+
+ return_val = TRUE;
+
+ switch (xevent->type)
+ {
+ case KeyPress:
+ if (window_private == NULL)
+ {
+ return_val = FALSE;
+ break;
+ }
+ translate_key_event (display, device_manager, event, xevent);
+ set_user_time (window, event);
+ break;
+
+ case KeyRelease:
+ if (window_private == NULL)
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ /* Emulate detectable auto-repeat by checking to see
+ * if the next event is a key press with the same
+ * keycode and timestamp, and if so, ignoring the event.
+ */
+
+ if (!display_x11->have_xkb_autorepeat && XPending (xevent->xkey.display))
+ {
+ XEvent next_event;
+
+ XPeekEvent (xevent->xkey.display, &next_event);
+
+ if (next_event.type == KeyPress &&
+ next_event.xkey.keycode == xevent->xkey.keycode &&
+ next_event.xkey.time == xevent->xkey.time)
+ {
+ return_val = FALSE;
+ break;
+ }
+ }
+
+ translate_key_event (display, device_manager, event, xevent);
+ break;
+
+ case ButtonPress:
+ GDK_NOTE (EVENTS,
+ g_message ("button press:\t\twindow: %ld x,y: %d %d button: %d",
+ xevent->xbutton.window,
+ xevent->xbutton.x, xevent->xbutton.y,
+ xevent->xbutton.button));
+
+ if (window_private == NULL)
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ /* If we get a ButtonPress event where the button is 4 or 5,
+ it's a Scroll event */
+ switch (xevent->xbutton.button)
+ {
+ case 4: /* up */
+ case 5: /* down */
+ case 6: /* left */
+ case 7: /* right */
+ event->scroll.type = GDK_SCROLL;
+
+ if (xevent->xbutton.button == 4)
+ event->scroll.direction = GDK_SCROLL_UP;
+ else if (xevent->xbutton.button == 5)
+ event->scroll.direction = GDK_SCROLL_DOWN;
+ else if (xevent->xbutton.button == 6)
+ event->scroll.direction = GDK_SCROLL_LEFT;
+ else
+ event->scroll.direction = GDK_SCROLL_RIGHT;
+
+ event->scroll.window = window;
+ event->scroll.time = xevent->xbutton.time;
+ event->scroll.x = (gdouble) xevent->xbutton.x;
+ event->scroll.y = (gdouble) xevent->xbutton.y;
+ event->scroll.x_root = (gdouble) xevent->xbutton.x_root;
+ event->scroll.y_root = (gdouble) xevent->xbutton.y_root;
+ event->scroll.state = (GdkModifierType) xevent->xbutton.state;
+ event->scroll.device = device_manager->core_pointer;
+
+ if (!set_screen_from_root (display, event, xevent->xbutton.root))
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ break;
+
+ default:
+ event->button.type = GDK_BUTTON_PRESS;
+ event->button.window = window;
+ event->button.time = xevent->xbutton.time;
+ event->button.x = (gdouble) xevent->xbutton.x;
+ event->button.y = (gdouble) xevent->xbutton.y;
+ event->button.x_root = (gdouble) xevent->xbutton.x_root;
+ event->button.y_root = (gdouble) xevent->xbutton.y_root;
+ event->button.axes = NULL;
+ event->button.state = (GdkModifierType) xevent->xbutton.state;
+ event->button.button = xevent->xbutton.button;
+ event->button.device = device_manager->core_pointer;
+
+ if (!set_screen_from_root (display, event, xevent->xbutton.root))
+ return_val = FALSE;
+
+ break;
+ }
+
+ set_user_time (window, event);
+
+ break;
+
+ case ButtonRelease:
+ GDK_NOTE (EVENTS,
+ g_message ("button release:\twindow: %ld x,y: %d %d button: %d",
+ xevent->xbutton.window,
+ xevent->xbutton.x, xevent->xbutton.y,
+ xevent->xbutton.button));
+
+ if (window_private == NULL)
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ /* We treat button presses as scroll wheel events, so ignore the release */
+ if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 ||
+ xevent->xbutton.button == 6 || xevent->xbutton.button == 7)
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ event->button.type = GDK_BUTTON_RELEASE;
+ event->button.window = window;
+ event->button.time = xevent->xbutton.time;
+ event->button.x = (gdouble) xevent->xbutton.x;
+ event->button.y = (gdouble) xevent->xbutton.y;
+ event->button.x_root = (gdouble) xevent->xbutton.x_root;
+ event->button.y_root = (gdouble) xevent->xbutton.y_root;
+ event->button.axes = NULL;
+ event->button.state = (GdkModifierType) xevent->xbutton.state;
+ event->button.button = xevent->xbutton.button;
+ event->button.device = device_manager->core_pointer;
+
+ if (!set_screen_from_root (display, event, xevent->xbutton.root))
+ return_val = FALSE;
+
+ break;
+
+ case MotionNotify:
+ GDK_NOTE (EVENTS,
+ g_message ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s",
+ xevent->xmotion.window,
+ xevent->xmotion.x, xevent->xmotion.y,
+ (xevent->xmotion.is_hint) ? "true" : "false"));
+
+ if (window_private == NULL)
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ event->motion.type = GDK_MOTION_NOTIFY;
+ event->motion.window = window;
+ event->motion.time = xevent->xmotion.time;
+ event->motion.x = (gdouble) xevent->xmotion.x;
+ event->motion.y = (gdouble) xevent->xmotion.y;
+ event->motion.x_root = (gdouble) xevent->xmotion.x_root;
+ event->motion.y_root = (gdouble) xevent->xmotion.y_root;
+ event->motion.axes = NULL;
+ event->motion.state = (GdkModifierType) xevent->xmotion.state;
+ event->motion.is_hint = xevent->xmotion.is_hint;
+ event->motion.device = device_manager->core_pointer;
+
+ if (!set_screen_from_root (display, event, xevent->xbutton.root))
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ break;
+
+ case EnterNotify:
+ GDK_NOTE (EVENTS,
+ g_message ("enter notify:\t\twindow: %ld detail: %d subwin: %ld",
+ xevent->xcrossing.window,
+ xevent->xcrossing.detail,
+ xevent->xcrossing.subwindow));
+
+ if (window_private == NULL)
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ if (!set_screen_from_root (display, event, xevent->xbutton.root))
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ event->crossing.type = GDK_ENTER_NOTIFY;
+ event->crossing.window = window;
+ gdk_event_set_device (event, device_manager->core_pointer);
+
+ /* If the subwindow field of the XEvent is non-NULL, then
+ * lookup the corresponding GdkWindow.
+ */
+ if (xevent->xcrossing.subwindow != None)
+ event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow);
+ else
+ event->crossing.subwindow = NULL;
+
+ event->crossing.time = xevent->xcrossing.time;
+ event->crossing.x = (gdouble) xevent->xcrossing.x;
+ event->crossing.y = (gdouble) xevent->xcrossing.y;
+ event->crossing.x_root = (gdouble) xevent->xcrossing.x_root;
+ event->crossing.y_root = (gdouble) xevent->xcrossing.y_root;
+
+ event->crossing.mode = translate_crossing_mode (xevent->xcrossing.mode);
+ event->crossing.detail = translate_notify_type (xevent->xcrossing.detail);
+
+ event->crossing.focus = xevent->xcrossing.focus;
+ event->crossing.state = xevent->xcrossing.state;
+
+ break;
+
+ case LeaveNotify:
+ GDK_NOTE (EVENTS,
+ g_message ("leave notify:\t\twindow: %ld detail: %d subwin: %ld",
+ xevent->xcrossing.window,
+ xevent->xcrossing.detail, xevent->xcrossing.subwindow));
+
+ if (window_private == NULL)
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ if (!set_screen_from_root (display, event, xevent->xbutton.root))
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ event->crossing.type = GDK_LEAVE_NOTIFY;
+ event->crossing.window = window;
+ gdk_event_set_device (event, device_manager->core_pointer);
+
+ /* If the subwindow field of the XEvent is non-NULL, then
+ * lookup the corresponding GdkWindow.
+ */
+ if (xevent->xcrossing.subwindow != None)
+ event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow);
+ else
+ event->crossing.subwindow = NULL;
+
+ event->crossing.time = xevent->xcrossing.time;
+ event->crossing.x = (gdouble) xevent->xcrossing.x;
+ event->crossing.y = (gdouble) xevent->xcrossing.y;
+ event->crossing.x_root = (gdouble) xevent->xcrossing.x_root;
+ event->crossing.y_root = (gdouble) xevent->xcrossing.y_root;
+
+ event->crossing.mode = translate_crossing_mode (xevent->xcrossing.mode);
+ event->crossing.detail = translate_notify_type (xevent->xcrossing.detail);
+
+ event->crossing.focus = xevent->xcrossing.focus;
+ event->crossing.state = xevent->xcrossing.state;
+
+ break;
+
+ /* We only care about focus events that indicate that _this_
+ * window (not a ancestor or child) got or lost the focus
+ */
+ case FocusIn:
+ GDK_NOTE (EVENTS,
+ g_message ("focus in:\t\twindow: %ld, detail: %s, mode: %s",
+ xevent->xfocus.window,
+ notify_details[xevent->xfocus.detail],
+ notify_modes[xevent->xfocus.mode]));
+
+ if (toplevel)
+ {
+ gboolean had_focus = HAS_FOCUS (toplevel);
+
+ switch (xevent->xfocus.detail)
+ {
+ case NotifyAncestor:
+ case NotifyVirtual:
+ /* When the focus moves from an ancestor of the window to
+ * the window or a descendent of the window, *and* the
+ * pointer is inside the window, then we were previously
+ * receiving keystroke events in the has_pointer_focus
+ * case and are now receiving them in the
+ * has_focus_window case.
+ */
+ if (toplevel->has_pointer &&
+ xevent->xfocus.mode != NotifyGrab &&
+ xevent->xfocus.mode != NotifyUngrab)
+ toplevel->has_pointer_focus = FALSE;
+
+ /* fall through */
+ case NotifyNonlinear:
+ case NotifyNonlinearVirtual:
+ if (xevent->xfocus.mode != NotifyGrab &&
+ xevent->xfocus.mode != NotifyUngrab)
+ toplevel->has_focus_window = TRUE;
+ /* We pretend that the focus moves to the grab
+ * window, so we pay attention to NotifyGrab
+ * NotifyUngrab, and ignore NotifyWhileGrabbed
+ */
+ if (xevent->xfocus.mode != NotifyWhileGrabbed)
+ toplevel->has_focus = TRUE;
+ break;
+ case NotifyPointer:
+ /* The X server sends NotifyPointer/NotifyGrab,
+ * but the pointer focus is ignored while a
+ * grab is in effect
+ */
+ if (xevent->xfocus.mode != NotifyGrab &&
+ xevent->xfocus.mode != NotifyUngrab)
+ toplevel->has_pointer_focus = TRUE;
+ break;
+ case NotifyInferior:
+ case NotifyPointerRoot:
+ case NotifyDetailNone:
+ break;
+ }
+
+ if (HAS_FOCUS (toplevel) != had_focus)
+ generate_focus_event (device_manager, window, TRUE);
+ }
+ break;
+ case FocusOut:
+ GDK_NOTE (EVENTS,
+ g_message ("focus out:\t\twindow: %ld, detail: %s, mode: %s",
+ xevent->xfocus.window,
+ notify_details[xevent->xfocus.detail],
+ notify_modes[xevent->xfocus.mode]));
+
+ if (toplevel)
+ {
+ gboolean had_focus = HAS_FOCUS (toplevel);
+
+ switch (xevent->xfocus.detail)
+ {
+ case NotifyAncestor:
+ case NotifyVirtual:
+ /* When the focus moves from the window or a descendent
+ * of the window to an ancestor of the window, *and* the
+ * pointer is inside the window, then we were previously
+ * receiving keystroke events in the has_focus_window
+ * case and are now receiving them in the
+ * has_pointer_focus case.
+ */
+ if (toplevel->has_pointer &&
+ xevent->xfocus.mode != NotifyGrab &&
+ xevent->xfocus.mode != NotifyUngrab)
+ toplevel->has_pointer_focus = TRUE;
+
+ /* fall through */
+ case NotifyNonlinear:
+ case NotifyNonlinearVirtual:
+ if (xevent->xfocus.mode != NotifyGrab &&
+ xevent->xfocus.mode != NotifyUngrab)
+ toplevel->has_focus_window = FALSE;
+ if (xevent->xfocus.mode != NotifyWhileGrabbed)
+ toplevel->has_focus = FALSE;
+ break;
+ case NotifyPointer:
+ if (xevent->xfocus.mode != NotifyGrab &&
+ xevent->xfocus.mode != NotifyUngrab)
+ toplevel->has_pointer_focus = FALSE;
+ break;
+ case NotifyInferior:
+ case NotifyPointerRoot:
+ case NotifyDetailNone:
+ break;
+ }
+
+ if (HAS_FOCUS (toplevel) != had_focus)
+ generate_focus_event (device_manager, window, FALSE);
+ }
+ break;
+
+ default:
+ return_val = FALSE;
+ }
+
+ done:
+ if (return_val)
+ {
+ if (event->any.window)
+ g_object_ref (event->any.window);
+
+ if (((event->any.type == GDK_ENTER_NOTIFY) ||
+ (event->any.type == GDK_LEAVE_NOTIFY)) &&
+ (event->crossing.subwindow != NULL))
+ g_object_ref (event->crossing.subwindow);
+ }
+ else
+ {
+ /* Mark this event as having no resources to be freed */
+ event->any.window = NULL;
+ event->any.type = GDK_NOTHING;
+ }
+
+ if (window)
+ g_object_unref (window);
+
+ return return_val;
+}
+
+static GList *
+gdk_device_manager_core_list_devices (GdkDeviceManager *device_manager,
+ GdkDeviceType type)
+{
+ GdkDeviceManagerCore *device_manager_core;
+ GList *devices = NULL;
+
+ if (type == GDK_DEVICE_TYPE_MASTER)
+ {
+ device_manager_core = (GdkDeviceManagerCore *) device_manager;
+ devices = g_list_prepend (devices, device_manager_core->core_keyboard);
+ devices = g_list_prepend (devices, device_manager_core->core_pointer);
+ }
+
+ return devices;
+}
+
+#define __GDK_DEVICE_MANAGER_CORE_C__
+#include "gdkaliasdef.c"
diff --git a/gdk/x11/gdkdevicemanager-core.h b/gdk/x11/gdkdevicemanager-core.h
new file mode 100644
index 0000000000..0a337fcd00
--- /dev/null
+++ b/gdk/x11/gdkdevicemanager-core.h
@@ -0,0 +1,54 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GDK_DEVICE_MANAGER_CORE_H__
+#define __GDK_DEVICE_MANAGER_CORE_H__
+
+#include <gdk/gdkdevicemanager.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_MANAGER_CORE (gdk_device_manager_core_get_type ())
+#define GDK_DEVICE_MANAGER_CORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_MANAGER_CORE, GdkDeviceManagerCore))
+#define GDK_DEVICE_MANAGER_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_MANAGER_CORE, GdkDeviceManagerCoreClass))
+#define GDK_IS_DEVICE_MANAGER_CORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_MANAGER_CORE))
+#define GDK_IS_DEVICE_MANAGER_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_MANAGER_CORE))
+#define GDK_DEVICE_MANAGER_CORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_MANAGER_CORE, GdkDeviceManagerCoreClass))
+
+typedef struct _GdkDeviceManagerCore GdkDeviceManagerCore;
+typedef struct _GdkDeviceManagerCoreClass GdkDeviceManagerCoreClass;
+
+struct _GdkDeviceManagerCore
+{
+ GdkDeviceManager parent_object;
+ GdkDevice *core_pointer;
+ GdkDevice *core_keyboard;
+};
+
+struct _GdkDeviceManagerCoreClass
+{
+ GdkDeviceManagerClass parent_class;
+};
+
+GType gdk_device_manager_core_get_type (void) G_GNUC_CONST;
+
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_MANAGER_CORE_H__ */
diff --git a/gdk/x11/gdkdevicemanager-x11.c b/gdk/x11/gdkdevicemanager-x11.c
new file mode 100644
index 0000000000..335764b7f0
--- /dev/null
+++ b/gdk/x11/gdkdevicemanager-x11.c
@@ -0,0 +1,76 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+#include "gdkx.h"
+#include "gdkdevicemanager-core.h"
+
+#ifdef XINPUT_XFREE
+#include "gdkdevicemanager-xi.h"
+#ifdef XINPUT_2
+#include "gdkdevicemanager-xi2.h"
+#endif
+#endif
+
+GdkDeviceManager *
+_gdk_device_manager_new (GdkDisplay *display)
+{
+ if (!g_getenv ("GDK_CORE_DEVICE_EVENTS"))
+ {
+#if defined (XINPUT_2) || defined (XINPUT_XFREE)
+ int opcode, firstevent, firsterror;
+ Display *xdisplay;
+
+ xdisplay = GDK_DISPLAY_XDISPLAY (display);
+
+ if (XQueryExtension (xdisplay, "XInputExtension",
+ &opcode, &firstevent, &firsterror))
+ {
+#ifdef XINPUT_2
+ int major, minor;
+
+ major = 2;
+ minor = 0;
+
+ if (_gdk_enable_multidevice &&
+ XIQueryVersion (xdisplay, &major, &minor) != BadRequest)
+ {
+ GdkDeviceManagerXI2 *device_manager_xi2;
+
+ device_manager_xi2 = g_object_new (GDK_TYPE_DEVICE_MANAGER_XI2,
+ "display", display,
+ NULL);
+ device_manager_xi2->opcode = opcode;
+
+ return GDK_DEVICE_MANAGER (device_manager_xi2);
+ }
+ else
+#endif /* XINPUT_2 */
+ return g_object_new (GDK_TYPE_DEVICE_MANAGER_XI,
+ "display", display,
+ "event-base", firstevent,
+ NULL);
+ }
+#endif /* XINPUT_2 || XINPUT_XFREE */
+ }
+
+ return g_object_new (GDK_TYPE_DEVICE_MANAGER_CORE,
+ "display", display,
+ NULL);
+}
diff --git a/gdk/x11/gdkdevicemanager-xi.c b/gdk/x11/gdkdevicemanager-xi.c
new file mode 100644
index 0000000000..c1c3390525
--- /dev/null
+++ b/gdk/x11/gdkdevicemanager-xi.c
@@ -0,0 +1,650 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+
+#include "gdkdevicemanager-xi.h"
+#include "gdkeventtranslator.h"
+#include "gdkdevice-xi.h"
+#include "gdkintl.h"
+#include "gdkx.h"
+
+#include <X11/extensions/XInput.h>
+
+
+struct _GdkDeviceManagerXIPrivate
+{
+ GHashTable *id_table;
+ gint event_base;
+ GList *devices;
+ gboolean ignore_core_events;
+};
+
+static void gdk_device_manager_xi_constructed (GObject *object);
+static void gdk_device_manager_xi_finalize (GObject *object);
+static void gdk_device_manager_xi_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gdk_device_manager_xi_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gdk_device_manager_xi_event_translator_init (GdkEventTranslatorIface *iface);
+static gboolean gdk_device_manager_xi_translate_event (GdkEventTranslator *translator,
+ GdkDisplay *display,
+ GdkEvent *event,
+ XEvent *xevent);
+static GList * gdk_device_manager_xi_list_devices (GdkDeviceManager *device_manager,
+ GdkDeviceType type);
+
+
+G_DEFINE_TYPE_WITH_CODE (GdkDeviceManagerXI, gdk_device_manager_xi, GDK_TYPE_DEVICE_MANAGER_CORE,
+ G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
+ gdk_device_manager_xi_event_translator_init))
+
+enum {
+ PROP_0,
+ PROP_EVENT_BASE
+};
+
+static void
+gdk_device_manager_xi_class_init (GdkDeviceManagerXIClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
+
+ object_class->constructed = gdk_device_manager_xi_constructed;
+ object_class->finalize = gdk_device_manager_xi_finalize;
+ object_class->set_property = gdk_device_manager_xi_set_property;
+ object_class->get_property = gdk_device_manager_xi_get_property;
+
+ device_manager_class->list_devices = gdk_device_manager_xi_list_devices;
+
+ g_object_class_install_property (object_class,
+ PROP_EVENT_BASE,
+ g_param_spec_int ("event-base",
+ P_("Event base"),
+ P_("Event base for XInput events"),
+ 0, G_MAXINT, 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_type_class_add_private (object_class, sizeof (GdkDeviceManagerXIPrivate));
+}
+
+static GdkFilterReturn
+window_input_info_filter (GdkXEvent *xevent,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ GdkDeviceManager *device_manager;
+ GdkDisplay *display;
+ GdkWindow *window;
+ XEvent *xev;
+
+ device_manager = user_data;
+ xev = (XEvent *) xevent;
+
+ display = gdk_device_manager_get_display (device_manager);
+ window = gdk_window_lookup_for_display (display, xev->xany.window);
+
+ if (window && xev->type == ConfigureNotify)
+ gdk_device_xi_update_window_info (window);
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+gdk_device_manager_xi_init (GdkDeviceManagerXI *device_manager)
+{
+ GdkDeviceManagerXIPrivate *priv;
+
+ device_manager->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (device_manager,
+ GDK_TYPE_DEVICE_MANAGER_XI,
+ GdkDeviceManagerXIPrivate);
+
+ priv->id_table = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) g_object_unref);
+
+ gdk_window_add_filter (NULL, window_input_info_filter, device_manager);
+}
+
+static void
+translate_class_info (GdkDevice *device,
+ XDeviceInfo *info)
+{
+ GdkDeviceXI *device_xi;
+ XAnyClassPtr class;
+ gint i, j;
+
+ device_xi = GDK_DEVICE_XI (device);
+ class = info->inputclassinfo;
+
+ for (i = 0; i < info->num_classes; i++)
+ {
+ switch (class->class) {
+ case ButtonClass:
+ break;
+ case KeyClass:
+ {
+ XKeyInfo *xki = (XKeyInfo *)class;
+ guint num_keys;
+
+ num_keys = xki->max_keycode - xki->min_keycode + 1;
+ _gdk_device_set_keys (device, num_keys);
+
+ device_xi->min_keycode = xki->min_keycode;
+
+ break;
+ }
+ case ValuatorClass:
+ {
+ XValuatorInfo *xvi = (XValuatorInfo *)class;
+
+ for (j = 0; j < xvi->num_axes; j++)
+ {
+ GdkAxisUse use;
+
+ switch (j)
+ {
+ case 0:
+ use = GDK_AXIS_X;
+ break;
+ case 1:
+ use = GDK_AXIS_Y;
+ break;
+ case 2:
+ use = GDK_AXIS_PRESSURE;
+ break;
+ case 3:
+ use = GDK_AXIS_XTILT;
+ break;
+ case 4:
+ use = GDK_AXIS_YTILT;
+ break;
+ case 5:
+ use = GDK_AXIS_WHEEL;
+ break;
+ default:
+ use = GDK_AXIS_IGNORE;
+ }
+
+ _gdk_device_add_axis (device,
+ GDK_NONE,
+ use,
+ xvi->axes[j].min_value,
+ xvi->axes[j].max_value,
+ xvi->axes[j].resolution);
+ }
+
+ break;
+ }
+ }
+
+ class = (XAnyClassPtr) (((char *) class) + class->length);
+ }
+}
+
+static GdkDevice *
+create_device (GdkDeviceManager *device_manager,
+ GdkDisplay *display,
+ XDeviceInfo *info)
+{
+ GdkInputSource input_source;
+ GdkDevice *device;
+
+ if (info->use != IsXExtensionPointer &&
+ info->use != IsXExtensionKeyboard)
+ return NULL;
+
+ if (info->use == IsXExtensionKeyboard)
+ input_source = GDK_SOURCE_KEYBOARD;
+ else
+ {
+ gchar *tmp_name;
+
+ tmp_name = g_ascii_strdown (info->name, -1);
+
+ if (strstr (tmp_name, "eraser"))
+ input_source = GDK_SOURCE_ERASER;
+ else if (strstr (tmp_name, "cursor"))
+ input_source = GDK_SOURCE_CURSOR;
+ else if (strstr (tmp_name, "wacom") ||
+ strstr (tmp_name, "pen"))
+ input_source = GDK_SOURCE_PEN;
+ else
+ input_source = GDK_SOURCE_MOUSE;
+
+ g_free (tmp_name);
+ }
+
+ device = g_object_new (GDK_TYPE_DEVICE_XI,
+ "name", info->name,
+ "type", GDK_DEVICE_TYPE_FLOATING,
+ "input-source", input_source,
+ "input-mode", GDK_MODE_DISABLED,
+ "has-cursor", FALSE,
+ "display", display,
+ "device-manager", device_manager,
+ "device-id", info->id,
+ NULL);
+ translate_class_info (device, info);
+
+ return device;
+}
+
+static void
+gdk_device_manager_xi_constructed (GObject *object)
+{
+ GdkDeviceManagerXIPrivate *priv;
+ XDeviceInfo *devices;
+ gint i, num_devices;
+ GdkDisplay *display;
+
+ priv = GDK_DEVICE_MANAGER_XI (object)->priv;
+ display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
+ devices = XListInputDevices(GDK_DISPLAY_XDISPLAY (display), &num_devices);
+
+ for(i = 0; i < num_devices; i++)
+ {
+ GdkDevice *device;
+
+ device = create_device (GDK_DEVICE_MANAGER (object),
+ display, &devices[i]);
+ if (device)
+ {
+ priv->devices = g_list_prepend (priv->devices, device);
+ g_hash_table_insert (priv->id_table,
+ GINT_TO_POINTER (devices[i].id),
+ device);
+ }
+ }
+
+ XFreeDeviceList(devices);
+
+ gdk_x11_register_standard_event_type (display,
+ priv->event_base,
+ 15 /* Number of events */);
+
+ if (G_OBJECT_CLASS (gdk_device_manager_xi_parent_class)->constructed)
+ G_OBJECT_CLASS (gdk_device_manager_xi_parent_class)->constructed (object);
+}
+
+static void
+gdk_device_manager_xi_finalize (GObject *object)
+{
+ GdkDeviceManagerXIPrivate *priv;
+
+ priv = GDK_DEVICE_MANAGER_XI (object)->priv;
+
+ g_list_foreach (priv->devices, (GFunc) g_object_unref, NULL);
+ g_list_free (priv->devices);
+
+ g_hash_table_destroy (priv->id_table);
+
+ gdk_window_remove_filter (NULL, window_input_info_filter, object);
+
+ G_OBJECT_CLASS (gdk_device_manager_xi_parent_class)->finalize (object);
+}
+
+static void
+gdk_device_manager_xi_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdkDeviceManagerXIPrivate *priv;
+
+ priv = GDK_DEVICE_MANAGER_XI (object)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_EVENT_BASE:
+ priv->event_base = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdk_device_manager_xi_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdkDeviceManagerXIPrivate *priv;
+
+ priv = GDK_DEVICE_MANAGER_XI (object)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_EVENT_BASE:
+ g_value_set_int (value, priv->event_base);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdk_device_manager_xi_event_translator_init (GdkEventTranslatorIface *iface)
+{
+ iface->translate_event = gdk_device_manager_xi_translate_event;
+}
+
+/* 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
+translate_state (guint state, guint device_state)
+{
+ return device_state | (state & 0xFF);
+}
+
+static GdkDevice *
+lookup_device (GdkDeviceManagerXI *device_manager,
+ XEvent *xevent)
+{
+ GdkDeviceManagerXIPrivate *priv;
+ guint32 device_id;
+
+ priv = GDK_DEVICE_MANAGER_XI (device_manager)->priv;
+
+ /* This is a sort of a hack, as there isn't any XDeviceAnyEvent -
+ but it's potentially faster than scanning through the types of
+ every device. If we were deceived, then it won't match any of
+ the types for the device anyways */
+ device_id = ((XDeviceButtonEvent *)xevent)->deviceid;
+
+ return g_hash_table_lookup (priv->id_table, GINT_TO_POINTER (device_id));
+}
+
+static gboolean
+gdk_device_manager_xi_translate_event (GdkEventTranslator *translator,
+ GdkDisplay *display,
+ GdkEvent *event,
+ XEvent *xevent)
+{
+ GdkDeviceManagerXIPrivate *priv;
+ GdkDeviceManagerXI *device_manager;
+ GdkEventTranslatorIface *parent_iface;
+ GdkDeviceXI *device_xi;
+ GdkDevice *device;
+ GdkWindow *window;
+
+ parent_iface = g_type_interface_peek_parent (GDK_EVENT_TRANSLATOR_GET_IFACE (translator));
+ device_manager = GDK_DEVICE_MANAGER_XI (translator);
+ priv = device_manager->priv;
+
+ if (!priv->ignore_core_events &&
+ parent_iface->translate_event (translator, display, event, xevent))
+ return TRUE;
+
+ device = lookup_device (device_manager, xevent);
+ device_xi = GDK_DEVICE_XI (device);
+
+ if (!device)
+ return FALSE;
+
+ window = gdk_window_lookup_for_display (display, xevent->xany.window);
+
+ if (!window)
+ return FALSE;
+
+ if ((xevent->type == device_xi->button_press_type) ||
+ (xevent->type == device_xi->button_release_type))
+ {
+ XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *) xevent;
+
+ event->button.type = (xdbe->type == device_xi->button_press_type) ?
+ GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
+
+ event->button.device = device;
+ event->button.window = g_object_ref (window);
+ event->button.time = xdbe->time;
+
+ event->button.x_root = (gdouble) xdbe->x_root;
+ event->button.y_root = (gdouble) xdbe->y_root;
+
+ event->button.axes = g_new0 (gdouble, device->num_axes);
+ gdk_device_xi_update_axes (device, xdbe->axes_count,
+ xdbe->first_axis, xdbe->axis_data);
+ gdk_device_xi_translate_axes (device, window,
+ device_xi->axis_data,
+ event->button.axes,
+ &event->button.x,
+ &event->button.y);
+
+ event->button.state = translate_state (xdbe->state, xdbe->device_state);
+ event->button.button = xdbe->button;
+
+ if (event->button.type == GDK_BUTTON_PRESS)
+ _gdk_event_button_generate (gdk_drawable_get_display (event->button.window),
+ event);
+
+ GDK_NOTE (EVENTS,
+ g_print ("button %s:\t\twindow: %ld device: %ld x,y: %f %f button: %d\n",
+ (event->button.type == GDK_BUTTON_PRESS) ? "press" : "release",
+ xdbe->window,
+ xdbe->deviceid,
+ event->button.x, event->button.y,
+ xdbe->button));
+
+ /* Update the timestamp of the latest user interaction, if the event has
+ * a valid timestamp.
+ */
+ if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
+ gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
+ gdk_event_get_time (event));
+ return TRUE;
+ }
+
+ if ((xevent->type == device_xi->key_press_type) ||
+ (xevent->type == device_xi->key_release_type))
+ {
+ XDeviceKeyEvent *xdke = (XDeviceKeyEvent *) xevent;
+
+ GDK_NOTE (EVENTS,
+ g_print ("device key %s:\twindow: %ld device: %ld keycode: %d\n",
+ (event->key.type == GDK_KEY_PRESS) ? "press" : "release",
+ xdke->window,
+ xdke->deviceid,
+ xdke->keycode));
+
+ if (xdke->keycode < device_xi->min_keycode ||
+ xdke->keycode >= device_xi->min_keycode + device->num_keys)
+ {
+ g_warning ("Invalid device key code received");
+ return FALSE;
+ }
+
+ event->key.keyval = device->keys[xdke->keycode - device_xi->min_keycode].keyval;
+
+ if (event->key.keyval == 0)
+ {
+ GDK_NOTE (EVENTS,
+ g_print ("\t\ttranslation - NONE\n"));
+
+ return FALSE;
+ }
+
+ event->key.type = (xdke->type == device_xi->key_press_type) ?
+ GDK_KEY_PRESS : GDK_KEY_RELEASE;
+
+ event->key.window = g_object_ref (window);
+ event->key.time = xdke->time;
+
+ event->key.state = translate_state (xdke->state, xdke->device_state)
+ | device->keys[xdke->keycode - device_xi->min_keycode].modifiers;
+
+ /* Add a string translation for the key event */
+ if ((event->key.keyval >= 0x20) && (event->key.keyval <= 0xFF))
+ {
+ event->key.length = 1;
+ event->key.string = g_new (gchar, 2);
+ event->key.string[0] = (gchar) event->key.keyval;
+ event->key.string[1] = 0;
+ }
+ else
+ {
+ event->key.length = 0;
+ event->key.string = g_new0 (gchar, 1);
+ }
+
+ GDK_NOTE (EVENTS,
+ g_print ("\t\ttranslation - keyval: %d modifiers: %#x\n",
+ event->key.keyval,
+ event->key.state));
+
+ /* Update the timestamp of the latest user interaction, if the event has
+ * a valid timestamp.
+ */
+ if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
+ gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
+ gdk_event_get_time (event));
+ return TRUE;
+ }
+
+ if (xevent->type == device_xi->motion_notify_type)
+ {
+ XDeviceMotionEvent *xdme = (XDeviceMotionEvent *) xevent;
+
+ event->motion.device = device;
+
+ if (device_xi->in_proximity)
+ priv->ignore_core_events = TRUE;
+
+ event->motion.x_root = (gdouble) xdme->x_root;
+ event->motion.y_root = (gdouble) xdme->y_root;
+
+ event->motion.axes = g_new0 (gdouble, device->num_axes);
+ gdk_device_xi_update_axes (device, xdme->axes_count,
+ xdme->first_axis, xdme->axis_data);
+ gdk_device_xi_translate_axes (device, window,
+ device_xi->axis_data,
+ event->motion.axes,
+ &event->motion.x,
+ &event->motion.y);
+
+ event->motion.type = GDK_MOTION_NOTIFY;
+ event->motion.window = g_object_ref (window);
+ event->motion.time = xdme->time;
+ event->motion.state = translate_state (xdme->state,
+ xdme->device_state);
+ event->motion.is_hint = xdme->is_hint;
+
+ GDK_NOTE (EVENTS,
+ g_print ("motion notify:\t\twindow: %ld device: %ld x,y: %f %f state %#4x hint: %s\n",
+ xdme->window,
+ xdme->deviceid,
+ event->motion.x, event->motion.y,
+ event->motion.state,
+ (xdme->is_hint) ? "true" : "false"));
+
+
+ /* Update the timestamp of the latest user interaction, if the event has
+ * a valid timestamp.
+ */
+ if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
+ gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
+ gdk_event_get_time (event));
+ return TRUE;
+ }
+
+ if (xevent->type == device_xi->proximity_in_type ||
+ xevent->type == device_xi->proximity_out_type)
+ {
+ XProximityNotifyEvent *xpne = (XProximityNotifyEvent *) xevent;
+
+ if (xevent->type == device_xi->proximity_in_type)
+ {
+ event->proximity.type = GDK_PROXIMITY_IN;
+ device_xi->in_proximity = TRUE;
+ priv->ignore_core_events = TRUE;
+ }
+ else
+ {
+ event->proximity.type = GDK_PROXIMITY_OUT;
+ device_xi->in_proximity = FALSE;
+ priv->ignore_core_events = FALSE;
+ }
+
+ event->proximity.device = device;
+ event->proximity.window = g_object_ref (window);
+ event->proximity.time = xpne->time;
+
+ /* Update the timestamp of the latest user interaction, if the event has
+ * a valid timestamp.
+ */
+ if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
+ gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
+ gdk_event_get_time (event));
+ return TRUE;
+ }
+
+ if (xevent->type == device_xi->state_notify_type)
+ {
+ XDeviceStateNotifyEvent *xdse = (XDeviceStateNotifyEvent *) xevent;
+ XInputClass *input_class = (XInputClass *) xdse->data;
+ int i;
+
+ for (i = 0; i < xdse->num_classes; i++)
+ {
+ if (input_class->class == ValuatorClass)
+ gdk_device_xi_update_axes (device, device->num_axes, 0,
+ ((XValuatorState *)input_class)->valuators);
+
+ input_class = (XInputClass *)(((char *)input_class)+input_class->length);
+ }
+
+ GDK_NOTE (EVENTS,
+ g_print ("device state notify:\t\twindow: %ld device: %ld\n",
+ xdse->window,
+ xdse->deviceid));
+
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+static GList *
+gdk_device_manager_xi_list_devices (GdkDeviceManager *device_manager,
+ GdkDeviceType type)
+{
+ GdkDeviceManagerXIPrivate *priv;
+
+ priv = GDK_DEVICE_MANAGER_XI (device_manager)->priv;
+
+ if (type == GDK_DEVICE_TYPE_MASTER)
+ return GDK_DEVICE_MANAGER_CLASS (gdk_device_manager_xi_parent_class)->list_devices (device_manager, type);
+ else if (type == GDK_DEVICE_TYPE_FLOATING)
+ {
+ return g_list_copy (priv->devices);
+ }
+ else
+ return NULL;
+}
diff --git a/gdk/x11/gdkdevicemanager-xi.h b/gdk/x11/gdkdevicemanager-xi.h
new file mode 100644
index 0000000000..6fd7d6dc73
--- /dev/null
+++ b/gdk/x11/gdkdevicemanager-xi.h
@@ -0,0 +1,58 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GDK_DEVICE_MANAGER_XI_H__
+#define __GDK_DEVICE_MANAGER_XI_H__
+
+#include "gdkdevicemanager-core.h"
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_MANAGER_XI (gdk_device_manager_xi_get_type ())
+#define GDK_DEVICE_MANAGER_XI(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_MANAGER_XI, GdkDeviceManagerXI))
+#define GDK_DEVICE_MANAGER_XI_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_MANAGER_XI, GdkDeviceManagerXIClass))
+#define GDK_IS_DEVICE_MANAGER_XI(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_MANAGER_XI))
+#define GDK_IS_DEVICE_MANAGER_XI_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_MANAGER_XI))
+#define GDK_DEVICE_MANAGER_XI_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_MANAGER_XI, GdkDeviceManagerXIClass))
+
+typedef struct _GdkDeviceManagerXI GdkDeviceManagerXI;
+typedef struct _GdkDeviceManagerXIPrivate GdkDeviceManagerXIPrivate;
+typedef struct _GdkDeviceManagerXIClass GdkDeviceManagerXIClass;
+
+struct _GdkDeviceManagerXI
+{
+ GdkDeviceManagerCore parent_object;
+ GdkDevice *core_pointer;
+ GdkDevice *core_keyboard;
+
+ /*< private >*/
+ GdkDeviceManagerXIPrivate *priv;
+};
+
+struct _GdkDeviceManagerXIClass
+{
+ GdkDeviceManagerCoreClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType gdk_device_manager_xi_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_MANAGER_XI_H__ */
diff --git a/gdk/x11/gdkdevicemanager-xi2.c b/gdk/x11/gdkdevicemanager-xi2.c
new file mode 100644
index 0000000000..9915a3a697
--- /dev/null
+++ b/gdk/x11/gdkdevicemanager-xi2.c
@@ -0,0 +1,1146 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <gdk/gdkdeviceprivate.h>
+
+#include "gdkdevicemanager-xi2.h"
+#include "gdkeventtranslator.h"
+#include "gdkdevice-xi2.h"
+#include "gdkkeysyms.h"
+#include "gdkprivate-x11.h"
+#include "gdkx.h"
+#include "gdkalias.h"
+
+#define HAS_FOCUS(toplevel) ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
+
+
+static void gdk_device_manager_xi2_constructed (GObject *object);
+static void gdk_device_manager_xi2_finalize (GObject *object);
+
+static GList * gdk_device_manager_xi2_list_devices (GdkDeviceManager *device_manager,
+ GdkDeviceType type);
+
+static void gdk_device_manager_xi2_event_translator_init (GdkEventTranslatorIface *iface);
+
+static gboolean gdk_device_manager_xi2_translate_event (GdkEventTranslator *translator,
+ GdkDisplay *display,
+ GdkEvent *event,
+ XEvent *xevent);
+static GdkEventMask gdk_device_manager_xi2_get_handled_events (GdkEventTranslator *translator);
+static void gdk_device_manager_xi2_select_window_events (GdkEventTranslator *translator,
+ Window window,
+ GdkEventMask event_mask);
+
+
+G_DEFINE_TYPE_WITH_CODE (GdkDeviceManagerXI2, gdk_device_manager_xi2, GDK_TYPE_DEVICE_MANAGER,
+ G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
+ gdk_device_manager_xi2_event_translator_init))
+
+
+static void
+gdk_device_manager_xi2_class_init (GdkDeviceManagerXI2Class *klass)
+{
+ GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructed = gdk_device_manager_xi2_constructed;
+ object_class->finalize = gdk_device_manager_xi2_finalize;
+
+ device_manager_class->list_devices = gdk_device_manager_xi2_list_devices;
+}
+
+static void
+gdk_device_manager_xi2_init (GdkDeviceManagerXI2 *device_manager)
+{
+ device_manager->id_table = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ (GDestroyNotify) g_object_unref);
+}
+
+static void
+_gdk_device_manager_xi2_select_events (GdkDeviceManager *device_manager,
+ Window xwindow,
+ XIEventMask *event_mask)
+{
+ GdkDisplay *display;
+ Display *xdisplay;
+
+ display = gdk_device_manager_get_display (device_manager);
+ xdisplay = GDK_DISPLAY_XDISPLAY (display);
+
+ XISelectEvents (xdisplay, xwindow, event_mask, 1);
+}
+
+static void
+translate_valuator_class (GdkDisplay *display,
+ GdkDevice *device,
+ XIValuatorClassInfo *info,
+ gint n_valuator)
+{
+ static gboolean initialized = FALSE;
+ static Atom label_atoms [GDK_AXIS_LAST] = { 0 };
+ GdkAxisUse use = GDK_AXIS_IGNORE;
+ GdkAtom label;
+ gint i;
+
+ if (!initialized)
+ {
+ label_atoms [GDK_AXIS_X] = gdk_x11_get_xatom_by_name_for_display (display, "Abs X");
+ label_atoms [GDK_AXIS_Y] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Y");
+ label_atoms [GDK_AXIS_PRESSURE] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Pressure");
+ label_atoms [GDK_AXIS_XTILT] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Tilt X");
+ label_atoms [GDK_AXIS_YTILT] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Tilt Y");
+ label_atoms [GDK_AXIS_WHEEL] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Wheel");
+ initialized = TRUE;
+ }
+
+ for (i = GDK_AXIS_IGNORE; i <= GDK_AXIS_LAST; i++)
+ {
+ if (label_atoms[i] == info->label)
+ {
+ use = i;
+ break;
+ }
+ }
+
+ if (info->label != None)
+ label = gdk_x11_xatom_to_atom_for_display (display, info->label);
+ else
+ label = GDK_NONE;
+
+ _gdk_device_add_axis (device,
+ label,
+ use,
+ info->min,
+ info->max,
+ info->resolution);
+}
+
+static void
+translate_device_classes (GdkDisplay *display,
+ GdkDevice *device,
+ XIAnyClassInfo **classes,
+ guint n_classes)
+{
+ gint i, n_valuator = 0;
+
+ g_object_freeze_notify (G_OBJECT (device));
+
+ for (i = 0; i < n_classes; i++)
+ {
+ XIAnyClassInfo *class_info = classes[i];
+
+ switch (class_info->type)
+ {
+ case XIKeyClass:
+ {
+ XIKeyClassInfo *key_info = (XIKeyClassInfo *) class_info;
+ gint i;
+
+ _gdk_device_set_keys (device, key_info->num_keycodes);
+
+ for (i = 0; i < key_info->num_keycodes; i++)
+ gdk_device_set_key (device, i, key_info->keycodes[i], 0);
+ }
+ break;
+ case XIValuatorClass:
+ translate_valuator_class (display, device,
+ (XIValuatorClassInfo *) class_info,
+ n_valuator);
+ n_valuator++;
+ break;
+ default:
+ /* Ignore */
+ break;
+ }
+ }
+
+ g_object_thaw_notify (G_OBJECT (device));
+}
+
+static GdkDevice *
+create_device (GdkDeviceManager *device_manager,
+ GdkDisplay *display,
+ XIDeviceInfo *dev)
+{
+ GdkInputSource input_source;
+ GdkDeviceType type;
+ GdkDevice *device;
+ GdkInputMode mode;
+
+ if (dev->use == XIMasterKeyboard || dev->use == XISlaveKeyboard)
+ input_source = GDK_SOURCE_KEYBOARD;
+ else
+ {
+ gchar *tmp_name;
+
+ tmp_name = g_ascii_strdown (dev->name, -1);
+
+ if (strstr (tmp_name, "eraser"))
+ input_source = GDK_SOURCE_ERASER;
+ else if (strstr (tmp_name, "cursor"))
+ input_source = GDK_SOURCE_CURSOR;
+ else if (strstr (tmp_name, "wacom") ||
+ strstr (tmp_name, "pen"))
+ input_source = GDK_SOURCE_PEN;
+ else
+ input_source = GDK_SOURCE_MOUSE;
+
+ g_free (tmp_name);
+ }
+
+ switch (dev->use)
+ {
+ case XIMasterKeyboard:
+ case XIMasterPointer:
+ type = GDK_DEVICE_TYPE_MASTER;
+ mode = GDK_MODE_SCREEN;
+ break;
+ case XISlaveKeyboard:
+ case XISlavePointer:
+ type = GDK_DEVICE_TYPE_SLAVE;
+ mode = GDK_MODE_DISABLED;
+ break;
+ case XIFloatingSlave:
+ default:
+ type = GDK_DEVICE_TYPE_FLOATING;
+ mode = GDK_MODE_DISABLED;
+ break;
+ }
+
+ device = g_object_new (GDK_TYPE_DEVICE_XI2,
+ "name", dev->name,
+ "type", type,
+ "input-source", input_source,
+ "input-mode", mode,
+ "has-cursor", (dev->use == XIMasterPointer),
+ "display", display,
+ "device-manager", device_manager,
+ "device-id", dev->deviceid,
+ NULL);
+
+ translate_device_classes (display, device, dev->classes, dev->num_classes);
+
+ return device;
+}
+
+static GdkDevice *
+add_device (GdkDeviceManagerXI2 *device_manager,
+ XIDeviceInfo *dev,
+ gboolean emit_signal)
+{
+ GdkDisplay *display;
+ GdkDevice *device;
+
+ display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
+ device = create_device (GDK_DEVICE_MANAGER (device_manager), display, dev);
+
+ g_hash_table_replace (device_manager->id_table,
+ GINT_TO_POINTER (dev->deviceid),
+ device);
+
+ if (dev->use == XIMasterPointer || dev->use == XIMasterKeyboard)
+ device_manager->master_devices = g_list_append (device_manager->master_devices, device);
+ else if (dev->use == XISlavePointer || dev->use == XISlaveKeyboard)
+ device_manager->slave_devices = g_list_append (device_manager->slave_devices, device);
+ else if (dev->use == XIFloatingSlave)
+ device_manager->floating_devices = g_list_append (device_manager->floating_devices, device);
+ else
+ g_warning ("Unhandled device: %s\n", device->name);
+
+ if (emit_signal)
+ g_signal_emit_by_name (device_manager, "device-added", device);
+
+ return device;
+}
+
+static void
+remove_device (GdkDeviceManagerXI2 *device_manager,
+ int device_id)
+{
+ GdkDevice *device;
+
+ device = g_hash_table_lookup (device_manager->id_table,
+ GINT_TO_POINTER (device_id));
+
+ if (device)
+ {
+ device_manager->master_devices = g_list_remove (device_manager->master_devices, device);
+ device_manager->slave_devices = g_list_remove (device_manager->slave_devices, device);
+ device_manager->floating_devices = g_list_remove (device_manager->floating_devices, device);
+
+ g_signal_emit_by_name (device_manager, "device-removed", device);
+
+ g_object_run_dispose (G_OBJECT (device));
+
+ g_hash_table_remove (device_manager->id_table,
+ GINT_TO_POINTER (device_id));
+ }
+}
+
+static void
+relate_devices (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ GdkDeviceManagerXI2 *device_manager;
+ GdkDevice *device, *relative;
+
+ device_manager = user_data;
+ device = g_hash_table_lookup (device_manager->id_table, key);
+ relative = g_hash_table_lookup (device_manager->id_table, value);
+
+ _gdk_device_set_associated_device (device, relative);
+ _gdk_device_set_associated_device (relative, device);
+}
+
+static void
+gdk_device_manager_xi2_constructed (GObject *object)
+{
+ GdkDeviceManagerXI2 *device_manager_xi2;
+ GdkDisplay *display;
+ GdkScreen *screen;
+ GHashTable *relations;
+ Display *xdisplay;
+ XIDeviceInfo *info, *dev;
+ int ndevices, i;
+ XIEventMask event_mask;
+ unsigned char mask[2] = { 0 };
+
+ device_manager_xi2 = GDK_DEVICE_MANAGER_XI2 (object);
+ display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
+ xdisplay = GDK_DISPLAY_XDISPLAY (display);
+ relations = g_hash_table_new (NULL, NULL);
+
+ info = XIQueryDevice(xdisplay, XIAllDevices, &ndevices);
+
+ /* Initialize devices list */
+ for (i = 0; i < ndevices; i++)
+ {
+ GdkDevice *device;
+
+ dev = &info[i];
+ device = add_device (device_manager_xi2, dev, FALSE);
+
+ if (dev->use == XIMasterPointer ||
+ dev->use == XIMasterKeyboard)
+ {
+ g_hash_table_insert (relations,
+ GINT_TO_POINTER (dev->deviceid),
+ GINT_TO_POINTER (dev->attachment));
+ }
+ }
+
+ XIFreeDeviceInfo(info);
+
+ /* Stablish relationships between devices */
+ g_hash_table_foreach (relations, relate_devices, object);
+ g_hash_table_destroy (relations);
+
+ /* Connect to hierarchy change events */
+ screen = gdk_display_get_default_screen (display);
+ XISetMask (mask, XI_HierarchyChanged);
+ XISetMask (mask, XI_DeviceChanged);
+
+ event_mask.deviceid = XIAllDevices;
+ event_mask.mask_len = sizeof (mask);
+ event_mask.mask = mask;
+
+ _gdk_device_manager_xi2_select_events (GDK_DEVICE_MANAGER (object),
+ GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen)),
+ &event_mask);
+}
+
+static void
+gdk_device_manager_xi2_finalize (GObject *object)
+{
+ GdkDeviceManagerXI2 *device_manager_xi2;
+
+ device_manager_xi2 = GDK_DEVICE_MANAGER_XI2 (object);
+
+ g_list_foreach (device_manager_xi2->master_devices, (GFunc) g_object_unref, NULL);
+ g_list_free (device_manager_xi2->master_devices);
+
+ g_list_foreach (device_manager_xi2->slave_devices, (GFunc) g_object_unref, NULL);
+ g_list_free (device_manager_xi2->slave_devices);
+
+ g_list_foreach (device_manager_xi2->floating_devices, (GFunc) g_object_unref, NULL);
+ g_list_free (device_manager_xi2->floating_devices);
+
+ g_hash_table_destroy (device_manager_xi2->id_table);
+
+ G_OBJECT_CLASS (gdk_device_manager_xi2_parent_class)->finalize (object);
+}
+
+static GList *
+gdk_device_manager_xi2_list_devices (GdkDeviceManager *device_manager,
+ GdkDeviceType type)
+{
+ GdkDeviceManagerXI2 *device_manager_xi2;
+ GList *list = NULL;
+
+ device_manager_xi2 = GDK_DEVICE_MANAGER_XI2 (device_manager);
+
+ switch (type)
+ {
+ case GDK_DEVICE_TYPE_MASTER:
+ list = device_manager_xi2->master_devices;
+ break;
+ case GDK_DEVICE_TYPE_SLAVE:
+ list = device_manager_xi2->slave_devices;
+ break;
+ case GDK_DEVICE_TYPE_FLOATING:
+ list = device_manager_xi2->floating_devices;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ return g_list_copy (list);
+}
+
+static void
+gdk_device_manager_xi2_event_translator_init (GdkEventTranslatorIface *iface)
+{
+ iface->translate_event = gdk_device_manager_xi2_translate_event;
+ iface->get_handled_events = gdk_device_manager_xi2_get_handled_events;
+ iface->select_window_events = gdk_device_manager_xi2_select_window_events;
+}
+
+static void
+handle_hierarchy_changed (GdkDeviceManagerXI2 *device_manager,
+ XIHierarchyEvent *ev)
+{
+ GdkDevice *device;
+ gint i;
+
+ /* We only care about enabled devices */
+ if (!(ev->flags & XIDeviceEnabled) &&
+ !(ev->flags & XIDeviceDisabled))
+ return;
+
+ for (i = 0; i < ev->num_info; i++)
+ {
+ if (ev->info[i].flags & XIDeviceEnabled)
+ {
+ GdkDisplay *display;
+ Display *xdisplay;
+ XIDeviceInfo *info;
+ int ndevices;
+
+ display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
+ xdisplay = GDK_DISPLAY_XDISPLAY (display);
+
+ info = XIQueryDevice(xdisplay, ev->info[i].deviceid, &ndevices);
+ device = add_device (device_manager, &info[0], TRUE);
+ XIFreeDeviceInfo(info);
+ }
+ else if (ev->info[i].flags & XIDeviceDisabled)
+ remove_device (device_manager, ev->info[i].deviceid);
+ }
+}
+
+static void
+handle_device_changed (GdkDeviceManagerXI2 *device_manager,
+ XIDeviceChangedEvent *ev)
+{
+ GdkDisplay *display;
+ GdkDevice *device;
+
+ display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
+ device = g_hash_table_lookup (device_manager->id_table,
+ GUINT_TO_POINTER (ev->deviceid));
+
+ _gdk_device_reset_axes (device);
+ translate_device_classes (display, device, ev->classes, ev->num_classes);
+}
+
+static GdkCrossingMode
+translate_crossing_mode (int mode)
+{
+ switch (mode)
+ {
+ case NotifyNormal:
+ return GDK_CROSSING_NORMAL;
+ case NotifyGrab:
+ return GDK_CROSSING_GRAB;
+ case NotifyUngrab:
+ return GDK_CROSSING_UNGRAB;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static GdkNotifyType
+translate_notify_type (int detail)
+{
+ switch (detail)
+ {
+ case NotifyInferior:
+ return GDK_NOTIFY_INFERIOR;
+ case NotifyAncestor:
+ return GDK_NOTIFY_ANCESTOR;
+ case NotifyVirtual:
+ return GDK_NOTIFY_VIRTUAL;
+ case NotifyNonlinear:
+ return GDK_NOTIFY_NONLINEAR;
+ case NotifyNonlinearVirtual:
+ return GDK_NOTIFY_NONLINEAR_VIRTUAL;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static gboolean
+set_screen_from_root (GdkDisplay *display,
+ GdkEvent *event,
+ Window xrootwin)
+{
+ GdkScreen *screen;
+
+ screen = _gdk_x11_display_screen_for_xrootwin (display, xrootwin);
+
+ if (screen)
+ {
+ gdk_event_set_screen (event, screen);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+set_user_time (GdkEvent *event)
+{
+ GdkWindow *window;
+ guint32 time;
+
+ window = gdk_window_get_toplevel (event->any.window);
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ time = gdk_event_get_time (event);
+
+ /* If an event doesn't have a valid timestamp, we shouldn't use it
+ * to update the latest user interaction time.
+ */
+ if (time != GDK_CURRENT_TIME)
+ gdk_x11_window_set_user_time (window, time);
+}
+
+static void
+translate_keyboard_string (GdkEventKey *event)
+{
+ gunichar c = 0;
+ gchar buf[7];
+
+ /* Fill in event->string crudely, since various programs
+ * depend on it.
+ */
+ event->string = NULL;
+
+ if (event->keyval != GDK_VoidSymbol)
+ c = gdk_keyval_to_unicode (event->keyval);
+
+ if (c)
+ {
+ gsize bytes_written;
+ gint len;
+
+ /* Apply the control key - Taken from Xlib
+ */
+ if (event->state & GDK_CONTROL_MASK)
+ {
+ if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
+ else if (c == '2')
+ {
+ event->string = g_memdup ("\0\0", 2);
+ event->length = 1;
+ buf[0] = '\0';
+ return;
+ }
+ else if (c >= '3' && c <= '7') c -= ('3' - '\033');
+ else if (c == '8') c = '\177';
+ else if (c == '/') c = '_' & 0x1F;
+ }
+
+ len = g_unichar_to_utf8 (c, buf);
+ buf[len] = '\0';
+
+ event->string = g_locale_from_utf8 (buf, len,
+ NULL, &bytes_written,
+ NULL);
+ if (event->string)
+ event->length = bytes_written;
+ }
+ else if (event->keyval == GDK_Escape)
+ {
+ event->length = 1;
+ event->string = g_strdup ("\033");
+ }
+ else if (event->keyval == GDK_Return ||
+ event->keyval == GDK_KP_Enter)
+ {
+ event->length = 1;
+ event->string = g_strdup ("\r");
+ }
+
+ if (!event->string)
+ {
+ event->length = 0;
+ event->string = g_strdup ("");
+ }
+}
+
+static void
+generate_focus_event (GdkWindow *window,
+ gboolean in)
+{
+ GdkEvent event;
+
+ event.type = GDK_FOCUS_CHANGE;
+ event.focus_change.window = window;
+ event.focus_change.send_event = FALSE;
+ event.focus_change.in = in;
+
+ gdk_event_put (&event);
+}
+
+static void
+handle_focus_change (GdkWindow *window,
+ gint detail,
+ gint mode,
+ gboolean in)
+{
+ GdkToplevelX11 *toplevel;
+ gboolean had_focus;
+
+ toplevel = _gdk_x11_window_get_toplevel (window);
+
+ if (!toplevel)
+ return;
+
+ had_focus = HAS_FOCUS (toplevel);
+
+ switch (detail)
+ {
+ case NotifyAncestor:
+ case NotifyVirtual:
+ /* When the focus moves from an ancestor of the window to
+ * the window or a descendent of the window, *and* the
+ * pointer is inside the window, then we were previously
+ * receiving keystroke events in the has_pointer_focus
+ * case and are now receiving them in the
+ * has_focus_window case.
+ */
+ if (toplevel->has_pointer &&
+ mode != NotifyGrab &&
+ mode != NotifyUngrab)
+ toplevel->has_pointer_focus = (in) ? FALSE : TRUE;
+
+ /* fall through */
+ case NotifyNonlinear:
+ case NotifyNonlinearVirtual:
+ if (mode != NotifyGrab &&
+ mode != NotifyUngrab)
+ toplevel->has_focus_window = (in) ? TRUE : FALSE;
+ /* We pretend that the focus moves to the grab
+ * window, so we pay attention to NotifyGrab
+ * NotifyUngrab, and ignore NotifyWhileGrabbed
+ */
+ if (mode != NotifyWhileGrabbed)
+ toplevel->has_focus = (in) ? TRUE : FALSE;
+ break;
+ case NotifyPointer:
+ /* The X server sends NotifyPointer/NotifyGrab,
+ * but the pointer focus is ignored while a
+ * grab is in effect
+ */
+ if (mode != NotifyGrab &&
+ mode != NotifyUngrab)
+ toplevel->has_pointer_focus = (in) ? TRUE :FALSE;
+ break;
+ case NotifyInferior:
+ case NotifyPointerRoot:
+ case NotifyDetailNone:
+ break;
+ }
+
+ if (HAS_FOCUS (toplevel) != had_focus)
+ generate_focus_event (window, (in) ? TRUE : FALSE);
+}
+
+static gdouble *
+translate_axes (GdkDevice *device,
+ gdouble x,
+ gdouble y,
+ GdkWindow *window,
+ XIValuatorState *valuators)
+{
+ guint n_axes, i;
+ gint width, height;
+ gdouble *axes;
+ double *vals;
+
+ g_object_get (device, "n-axes", &n_axes, NULL);
+
+ axes = g_new0 (gdouble, n_axes);
+ vals = valuators->values;
+
+ gdk_drawable_get_size (GDK_DRAWABLE (window), &width, &height);
+
+ for (i = 0; i < valuators->mask_len * 8; i++)
+ {
+ GdkAxisUse use;
+ gdouble val;
+
+ if (!XIMaskIsSet (valuators->mask, i))
+ continue;
+
+ use = _gdk_device_get_axis_use (device, i);
+ val = *vals++;
+
+ switch (use)
+ {
+ case GDK_AXIS_X:
+ case GDK_AXIS_Y:
+ if (device->mode == GDK_MODE_WINDOW)
+ _gdk_device_translate_window_coord (device, window, i, val, &axes[i]);
+ else
+ {
+ if (use == GDK_AXIS_X)
+ axes[i] = x;
+ else
+ axes[i] = y;
+ }
+ break;
+ default:
+ _gdk_device_translate_axis (device, i, val, &axes[i]);
+ break;
+ }
+ }
+
+ return axes;
+}
+
+static gboolean
+is_parent_of (GdkWindow *parent,
+ GdkWindow *child)
+{
+ GdkWindow *w;
+
+ w = child;
+ while (w != NULL)
+ {
+ if (w == parent)
+ return TRUE;
+
+ w = gdk_window_get_parent (w);
+ }
+
+ return FALSE;
+}
+
+static GdkWindow *
+get_event_window (GdkEventTranslator *translator,
+ XIEvent *ev)
+{
+ GdkDisplay *display;
+ GdkWindow *window = NULL;
+
+ display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (translator));
+
+ switch (ev->evtype)
+ {
+ case XI_KeyPress:
+ case XI_KeyRelease:
+ case XI_ButtonPress:
+ case XI_ButtonRelease:
+ case XI_Motion:
+ {
+ XIDeviceEvent *xev = (XIDeviceEvent *) ev;
+
+ window = gdk_window_lookup_for_display (display, xev->event);
+
+ /* Apply keyboard grabs to non-native windows */
+ if (ev->evtype == XI_KeyPress || ev->evtype == XI_KeyRelease)
+ {
+ GdkDeviceGrabInfo *info;
+ GdkDevice *device;
+ gulong serial;
+
+ device = g_hash_table_lookup (GDK_DEVICE_MANAGER_XI2 (translator)->id_table,
+ GUINT_TO_POINTER (((XIDeviceEvent *) ev)->deviceid));
+
+ serial = _gdk_windowing_window_get_next_serial (display);
+ info = _gdk_display_has_device_grab (display, device, serial);
+
+ if (info &&
+ (!is_parent_of (info->window, window) ||
+ !info->owner_events))
+ {
+ /* Report key event against grab window */
+ window = info->window;
+ }
+ }
+ }
+ break;
+ case XI_Enter:
+ case XI_Leave:
+ case XI_FocusIn:
+ case XI_FocusOut:
+ {
+ XIEnterEvent *xev = (XIEnterEvent *) ev;
+
+ window = gdk_window_lookup_for_display (display, xev->event);
+ }
+ break;
+ }
+
+ return window;
+}
+
+static gboolean
+gdk_device_manager_xi2_translate_event (GdkEventTranslator *translator,
+ GdkDisplay *display,
+ GdkEvent *event,
+ XEvent *xevent)
+{
+ GdkDeviceManagerXI2 *device_manager;
+ XGenericEventCookie *cookie;
+ gboolean return_val = TRUE;
+ GdkWindow *window;
+ XIEvent *ev;
+ Display *dpy;
+
+ dpy = GDK_DISPLAY_XDISPLAY (display);
+ device_manager = (GdkDeviceManagerXI2 *) translator;
+ cookie = &xevent->xcookie;
+
+ if (!XGetEventData (dpy, cookie))
+ return FALSE;
+
+ if (cookie->type != GenericEvent ||
+ cookie->extension != device_manager->opcode)
+ {
+ XFreeEventData (dpy, cookie);
+ return FALSE;
+ }
+
+ ev = (XIEvent *) cookie->data;
+
+ window = get_event_window (translator, ev);
+
+ if (window && GDK_WINDOW_DESTROYED (window))
+ {
+ XFreeEventData (dpy, cookie);
+ return FALSE;
+ }
+
+ if (ev->evtype == XI_Motion ||
+ ev->evtype == XI_ButtonRelease)
+ {
+ if (_gdk_moveresize_handle_event (xevent))
+ {
+ XFreeEventData (dpy, cookie);
+ return FALSE;
+ }
+ }
+
+ switch (ev->evtype)
+ {
+ case XI_HierarchyChanged:
+ handle_hierarchy_changed (device_manager,
+ (XIHierarchyEvent *) ev);
+ return_val = FALSE;
+ break;
+ case XI_DeviceChanged:
+ handle_device_changed (device_manager,
+ (XIDeviceChangedEvent *) ev);
+ return_val = FALSE;
+ break;
+ case XI_KeyPress:
+ case XI_KeyRelease:
+ {
+ XIDeviceEvent *xev = (XIDeviceEvent *) ev;
+ GdkKeymap *keymap = gdk_keymap_get_for_display (display);
+ GdkModifierType consumed, state;
+ GdkDevice *device;
+
+ event->key.type = xev->evtype == XI_KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
+
+ event->key.window = window;
+
+ event->key.time = xev->time;
+ event->key.state = gdk_device_xi2_translate_state (&xev->mods, &xev->buttons);
+ event->key.group = _gdk_x11_get_group_for_state (display, event->key.state);
+
+ event->key.hardware_keycode = xev->detail;
+ event->key.is_modifier = _gdk_keymap_key_is_modifier (keymap, event->key.hardware_keycode);
+
+ device = g_hash_table_lookup (device_manager->id_table,
+ GUINT_TO_POINTER (xev->deviceid));
+ gdk_event_set_device (event, device);
+
+ event->key.keyval = GDK_VoidSymbol;
+
+ gdk_keymap_translate_keyboard_state (keymap,
+ event->key.hardware_keycode,
+ event->key.state,
+ event->key.group,
+ &event->key.keyval,
+ NULL, NULL, &consumed);
+
+ state = event->key.state & ~consumed;
+ _gdk_keymap_add_virtual_modifiers_compat (keymap, &state);
+ event->key.state |= state;
+
+ translate_keyboard_string ((GdkEventKey *) event);
+
+ if (ev->evtype == XI_KeyPress)
+ set_user_time (event);
+
+ /* FIXME: emulate autorepeat on key
+ * release? XI2 seems attached to Xkb.
+ */
+ }
+
+ break;
+ case XI_ButtonPress:
+ case XI_ButtonRelease:
+ {
+ XIDeviceEvent *xev = (XIDeviceEvent *) ev;
+
+ switch (xev->detail)
+ {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ event->scroll.type = GDK_SCROLL;
+
+ if (xev->detail == 4)
+ event->scroll.direction = GDK_SCROLL_UP;
+ else if (xev->detail == 5)
+ event->scroll.direction = GDK_SCROLL_DOWN;
+ else if (xev->detail == 6)
+ event->scroll.direction = GDK_SCROLL_LEFT;
+ else
+ event->scroll.direction = GDK_SCROLL_RIGHT;
+
+ event->scroll.window = window;
+ event->scroll.time = xev->time;
+ event->scroll.x = (gdouble) xev->event_x;
+ event->scroll.y = (gdouble) xev->event_y;
+ event->scroll.x_root = (gdouble) xev->root_x;
+ event->scroll.y_root = (gdouble) xev->root_y;
+
+ event->scroll.device = g_hash_table_lookup (device_manager->id_table,
+ GUINT_TO_POINTER (xev->deviceid));
+
+ event->scroll.state = gdk_device_xi2_translate_state (&xev->mods, &xev->buttons);
+ break;
+ default:
+ event->button.type = (ev->evtype == XI_ButtonPress) ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
+
+ event->button.window = window;
+ event->button.time = xev->time;
+ event->button.x = (gdouble) xev->event_x;
+ event->button.y = (gdouble) xev->event_y;
+ event->button.x_root = (gdouble) xev->root_x;
+ event->button.y_root = (gdouble) xev->root_y;
+
+ event->button.device = g_hash_table_lookup (device_manager->id_table,
+ GUINT_TO_POINTER (xev->deviceid));
+
+ event->button.axes = translate_axes (event->button.device,
+ event->button.x,
+ event->button.y,
+ event->button.window,
+ &xev->valuators);
+
+ if (event->button.device->mode == GDK_MODE_WINDOW)
+ {
+ GdkDevice *device = event->button.device;
+
+ /* Update event coordinates from axes */
+ gdk_device_get_axis (device, event->button.axes, GDK_AXIS_X, &event->button.x);
+ gdk_device_get_axis (device, event->button.axes, GDK_AXIS_Y, &event->button.y);
+ }
+
+ event->button.state = gdk_device_xi2_translate_state (&xev->mods, &xev->buttons);
+ event->button.button = xev->detail;
+ }
+
+ if (!set_screen_from_root (display, event, xev->root))
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ set_user_time (event);
+
+ break;
+ }
+ case XI_Motion:
+ {
+ XIDeviceEvent *xev = (XIDeviceEvent *) ev;
+
+ event->motion.type = GDK_MOTION_NOTIFY;
+
+ event->motion.window = window;
+
+ event->motion.time = xev->time;
+ event->motion.x = (gdouble) xev->event_x;
+ event->motion.y = (gdouble) xev->event_y;
+ event->motion.x_root = (gdouble) xev->root_x;
+ event->motion.y_root = (gdouble) xev->root_y;
+
+ event->motion.device = g_hash_table_lookup (device_manager->id_table,
+ GINT_TO_POINTER (xev->deviceid));
+
+ event->motion.state = gdk_device_xi2_translate_state (&xev->mods, &xev->buttons);
+
+ /* There doesn't seem to be motion hints in XI */
+ event->motion.is_hint = FALSE;
+
+ event->motion.axes = translate_axes (event->motion.device,
+ event->motion.x,
+ event->motion.y,
+ event->motion.window,
+ &xev->valuators);
+
+ if (event->motion.device->mode == GDK_MODE_WINDOW)
+ {
+ GdkDevice *device = event->motion.device;
+
+ /* Update event coordinates from axes */
+ gdk_device_get_axis (device, event->motion.axes, GDK_AXIS_X, &event->motion.x);
+ gdk_device_get_axis (device, event->motion.axes, GDK_AXIS_Y, &event->motion.y);
+ }
+ }
+ break;
+ case XI_Enter:
+ case XI_Leave:
+ {
+ XIEnterEvent *xev = (XIEnterEvent *) ev;
+ GdkDevice *device;
+
+ event->crossing.type = (ev->evtype == XI_Enter) ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY;
+
+ event->crossing.x = (gdouble) xev->event_x;
+ event->crossing.y = (gdouble) xev->event_y;
+ event->crossing.x_root = (gdouble) xev->root_x;
+ event->crossing.y_root = (gdouble) xev->root_y;
+ event->crossing.time = xev->time;
+ event->crossing.focus = xev->focus;
+
+ event->crossing.window = window;
+ event->crossing.subwindow = gdk_window_lookup_for_display (display, xev->child);
+
+ device = g_hash_table_lookup (device_manager->id_table,
+ GINT_TO_POINTER (xev->deviceid));
+ gdk_event_set_device (event, device);
+
+ event->crossing.mode = translate_crossing_mode (xev->mode);
+ event->crossing.detail = translate_notify_type (xev->detail);
+ event->crossing.state = gdk_device_xi2_translate_state (&xev->mods, &xev->buttons);
+ }
+ break;
+ case XI_FocusIn:
+ case XI_FocusOut:
+ {
+ XIEnterEvent *xev = (XIEnterEvent *) ev;
+
+ handle_focus_change (window, xev->detail, xev->mode,
+ (ev->evtype == XI_FocusIn) ? TRUE : FALSE);
+
+ return_val = FALSE;
+ }
+ default:
+ return_val = FALSE;
+ break;
+ }
+
+ event->any.send_event = cookie->send_event;
+
+ if (return_val)
+ {
+ if (event->any.window)
+ g_object_ref (event->any.window);
+
+ if (((event->any.type == GDK_ENTER_NOTIFY) ||
+ (event->any.type == GDK_LEAVE_NOTIFY)) &&
+ (event->crossing.subwindow != NULL))
+ g_object_ref (event->crossing.subwindow);
+ }
+ else
+ {
+ /* Mark this event as having no resources to be freed */
+ event->any.window = NULL;
+ event->any.type = GDK_NOTHING;
+ }
+
+ XFreeEventData (dpy, cookie);
+
+ return return_val;
+}
+
+static GdkEventMask
+gdk_device_manager_xi2_get_handled_events (GdkEventTranslator *translator)
+{
+ return (GDK_KEY_PRESS_MASK |
+ GDK_KEY_RELEASE_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_SCROLL_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_POINTER_MOTION_HINT_MASK |
+ GDK_BUTTON1_MOTION_MASK |
+ GDK_BUTTON2_MOTION_MASK |
+ GDK_BUTTON3_MOTION_MASK |
+ GDK_BUTTON_MOTION_MASK |
+ GDK_FOCUS_CHANGE_MASK);
+}
+
+static void
+gdk_device_manager_xi2_select_window_events (GdkEventTranslator *translator,
+ Window window,
+ GdkEventMask evmask)
+{
+ GdkDeviceManager *device_manager;
+ XIEventMask event_mask;
+
+ device_manager = GDK_DEVICE_MANAGER (translator);
+
+ event_mask.deviceid = XIAllMasterDevices;
+ event_mask.mask = gdk_device_xi2_translate_event_mask (evmask, &event_mask.mask_len);
+
+ _gdk_device_manager_xi2_select_events (device_manager, window, &event_mask);
+ g_free (event_mask.mask);
+}
+
+#define __GDK_DEVICE_MANAGER_XI2_C__
+#include "gdkaliasdef.c"
diff --git a/gdk/x11/gdkdevicemanager-xi2.h b/gdk/x11/gdkdevicemanager-xi2.h
new file mode 100644
index 0000000000..d47bcdb16a
--- /dev/null
+++ b/gdk/x11/gdkdevicemanager-xi2.h
@@ -0,0 +1,61 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GDK_DEVICE_MANAGER_XI2_H__
+#define __GDK_DEVICE_MANAGER_XI2_H__
+
+#include <gdk/gdkdevicemanager.h>
+#include <X11/extensions/XInput2.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_MANAGER_XI2 (gdk_device_manager_xi2_get_type ())
+#define GDK_DEVICE_MANAGER_XI2(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_MANAGER_XI2, GdkDeviceManagerXI2))
+#define GDK_DEVICE_MANAGER_XI2_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_MANAGER_XI2, GdkDeviceManagerXI2Class))
+#define GDK_IS_DEVICE_MANAGER_XI2(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_MANAGER_XI2))
+#define GDK_IS_DEVICE_MANAGER_XI2_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_MANAGER_XI2))
+#define GDK_DEVICE_MANAGER_XI2_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_MANAGER_XI2, GdkDeviceManagerXI2Class))
+
+typedef struct _GdkDeviceManagerXI2 GdkDeviceManagerXI2;
+typedef struct _GdkDeviceManagerXI2Class GdkDeviceManagerXI2Class;
+
+struct _GdkDeviceManagerXI2
+{
+ GdkDeviceManager parent_object;
+
+ GHashTable *id_table;
+
+ GList *master_devices;
+ GList *slave_devices;
+ GList *floating_devices;
+
+ int opcode;
+};
+
+struct _GdkDeviceManagerXI2Class
+{
+ GdkDeviceManagerClass parent_class;
+};
+
+GType gdk_device_manager_xi2_get_type (void) G_GNUC_CONST;
+
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_MANAGER_CORE_H__ */
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 6cded79e4b..a8c714d9d8 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -34,10 +34,13 @@
#include "gdkasync.h"
#include "gdkdisplay.h"
#include "gdkdisplay-x11.h"
+#include "gdkeventsource.h"
+#include "gdkeventtranslator.h"
#include "gdkscreen.h"
#include "gdkscreen-x11.h"
#include "gdkinternals.h"
-#include "gdkinputprivate.h"
+#include "gdkdeviceprivate.h"
+#include "gdkdevicemanager.h"
#include "xsettings-client.h"
#include "gdkalias.h"
@@ -69,6 +72,13 @@
static void gdk_display_x11_dispose (GObject *object);
static void gdk_display_x11_finalize (GObject *object);
+static void gdk_display_x11_event_translator_init (GdkEventTranslatorIface *iface);
+
+static gboolean gdk_display_x11_translate_event (GdkEventTranslator *translator,
+ GdkDisplay *display,
+ GdkEvent *event,
+ XEvent *xevent);
+
#ifdef HAVE_X11R6
static void gdk_internal_connection_watch (Display *display,
XPointer arg,
@@ -77,6 +87,14 @@ static void gdk_internal_connection_watch (Display *display,
XPointer *watch_data);
#endif /* HAVE_X11R6 */
+typedef struct _GdkEventTypeX11 GdkEventTypeX11;
+
+struct _GdkEventTypeX11
+{
+ gint base;
+ gint n_events;
+};
+
/* Note that we never *directly* use WM_LOCALE_NAME, WM_PROTOCOLS,
* but including them here has the side-effect of getting them
* into the internal Xlib cache
@@ -120,7 +138,10 @@ static const char *const precache_atoms[] = {
"_NET_VIRTUAL_ROOTS"
};
-G_DEFINE_TYPE (GdkDisplayX11, _gdk_display_x11, GDK_TYPE_DISPLAY)
+G_DEFINE_TYPE_WITH_CODE (GdkDisplayX11, _gdk_display_x11, GDK_TYPE_DISPLAY,
+ G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
+ gdk_display_x11_event_translator_init))
+
static void
_gdk_display_x11_class_init (GdkDisplayX11Class * class)
@@ -136,6 +157,1013 @@ _gdk_display_x11_init (GdkDisplayX11 *display)
{
}
+static void
+gdk_display_x11_event_translator_init (GdkEventTranslatorIface *iface)
+{
+ iface->translate_event = gdk_display_x11_translate_event;
+}
+
+static void
+do_net_wm_state_changes (GdkWindow *window)
+{
+ GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+ GdkWindowState old_state;
+
+ if (GDK_WINDOW_DESTROYED (window) ||
+ gdk_window_get_window_type (window) != GDK_WINDOW_TOPLEVEL)
+ return;
+
+ old_state = gdk_window_get_state (window);
+
+ /* For found_sticky to remain TRUE, we have to also be on desktop
+ * 0xFFFFFFFF
+ */
+ if (old_state & GDK_WINDOW_STATE_STICKY)
+ {
+ if (!(toplevel->have_sticky && toplevel->on_all_desktops))
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_STICKY,
+ 0);
+ }
+ else
+ {
+ if (toplevel->have_sticky || toplevel->on_all_desktops)
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_STICKY);
+ }
+
+ if (old_state & GDK_WINDOW_STATE_FULLSCREEN)
+ {
+ if (!toplevel->have_fullscreen)
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_FULLSCREEN,
+ 0);
+ }
+ else
+ {
+ if (toplevel->have_fullscreen)
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_FULLSCREEN);
+ }
+
+ /* Our "maximized" means both vertical and horizontal; if only one,
+ * we don't expose that via GDK
+ */
+ if (old_state & GDK_WINDOW_STATE_MAXIMIZED)
+ {
+ if (!(toplevel->have_maxvert && toplevel->have_maxhorz))
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_MAXIMIZED,
+ 0);
+ }
+ else
+ {
+ if (toplevel->have_maxvert && toplevel->have_maxhorz)
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_MAXIMIZED);
+ }
+}
+
+static void
+gdk_check_wm_desktop_changed (GdkWindow *window)
+{
+ GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+ GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ guchar *data;
+ gulong *desktop;
+
+ type = None;
+ gdk_error_trap_push ();
+ XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
+ GDK_WINDOW_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"),
+ 0, G_MAXLONG, False, XA_CARDINAL, &type,
+ &format, &nitems,
+ &bytes_after, &data);
+ gdk_error_trap_pop ();
+
+ if (type != None)
+ {
+ desktop = (gulong *)data;
+ toplevel->on_all_desktops = (*desktop == 0xFFFFFFFF);
+ XFree (desktop);
+ }
+ else
+ toplevel->on_all_desktops = FALSE;
+
+ do_net_wm_state_changes (window);
+}
+
+static void
+gdk_check_wm_state_changed (GdkWindow *window)
+{
+ GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+ GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ guchar *data;
+ Atom *atoms = NULL;
+ gulong i;
+
+ gboolean had_sticky = toplevel->have_sticky;
+
+ toplevel->have_sticky = FALSE;
+ toplevel->have_maxvert = FALSE;
+ toplevel->have_maxhorz = FALSE;
+ toplevel->have_fullscreen = FALSE;
+
+ type = None;
+ gdk_error_trap_push ();
+ XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
+ 0, G_MAXLONG, False, XA_ATOM, &type, &format, &nitems,
+ &bytes_after, &data);
+ gdk_error_trap_pop ();
+
+ if (type != None)
+ {
+ Atom sticky_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_STICKY");
+ Atom maxvert_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT");
+ Atom maxhorz_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ");
+ Atom fullscreen_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_FULLSCREEN");
+
+ atoms = (Atom *)data;
+
+ i = 0;
+ while (i < nitems)
+ {
+ if (atoms[i] == sticky_atom)
+ toplevel->have_sticky = TRUE;
+ else if (atoms[i] == maxvert_atom)
+ toplevel->have_maxvert = TRUE;
+ else if (atoms[i] == maxhorz_atom)
+ toplevel->have_maxhorz = TRUE;
+ else if (atoms[i] == fullscreen_atom)
+ toplevel->have_fullscreen = TRUE;
+
+ ++i;
+ }
+
+ XFree (atoms);
+ }
+
+ /* When have_sticky is turned on, we have to check the DESKTOP property
+ * as well.
+ */
+ if (toplevel->have_sticky && !had_sticky)
+ gdk_check_wm_desktop_changed (window);
+ else
+ do_net_wm_state_changes (window);
+}
+
+static GdkWindow *
+get_event_window (GdkEventTranslator *translator,
+ XEvent *xevent)
+{
+ GdkDisplay *display;
+ Window xwindow;
+
+ display = (GdkDisplay *) translator;
+
+ switch (xevent->type)
+ {
+ case DestroyNotify:
+ xwindow = xevent->xdestroywindow.window;
+ break;
+ case UnmapNotify:
+ xwindow = xevent->xunmap.window;
+ break;
+ case MapNotify:
+ xwindow = xevent->xmap.window;
+ break;
+ case ConfigureNotify:
+ xwindow = xevent->xconfigure.window;
+ break;
+ default:
+ xwindow = xevent->xany.window;
+ }
+
+ return gdk_window_lookup_for_display (display, xwindow);
+}
+
+static gboolean
+gdk_display_x11_translate_event (GdkEventTranslator *translator,
+ GdkDisplay *display,
+ GdkEvent *event,
+ XEvent *xevent)
+{
+ GdkWindow *window;
+ GdkWindowObject *window_private;
+ GdkWindowImplX11 *window_impl = NULL;
+ GdkScreen *screen = NULL;
+ GdkScreenX11 *screen_x11 = NULL;
+ GdkToplevelX11 *toplevel = NULL;
+ GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+ gboolean return_val;
+ Window xwindow = None;
+
+ /* Find the GdkWindow that this event relates to.
+ * Basically this means substructure events
+ * are reported same as structure events
+ */
+ window = get_event_window (translator, xevent);
+ window_private = (GdkWindowObject *) window;
+
+ if (window)
+ {
+ /* We may receive events such as NoExpose/GraphicsExpose
+ * and ShmCompletion for pixmaps
+ */
+ if (!GDK_IS_WINDOW (window))
+ return FALSE;
+
+ screen = GDK_WINDOW_SCREEN (window);
+ screen_x11 = GDK_SCREEN_X11 (screen);
+ toplevel = _gdk_x11_window_get_toplevel (window);
+ window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
+ xwindow = GDK_WINDOW_XID (window);
+
+ g_object_ref (window);
+ }
+
+ event->any.window = window;
+ event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
+
+ if (window_private && GDK_WINDOW_DESTROYED (window))
+ {
+ if (xevent->type != DestroyNotify)
+ {
+ return_val = FALSE;
+ goto done;
+ }
+ }
+
+ if (xevent->type == DestroyNotify)
+ {
+ int i, n;
+
+ n = gdk_display_get_n_screens (display);
+ for (i = 0; i < n; i++)
+ {
+ screen = gdk_display_get_screen (display, i);
+ screen_x11 = GDK_SCREEN_X11 (screen);
+
+ if (screen_x11->wmspec_check_window == xwindow)
+ {
+ screen_x11->wmspec_check_window = None;
+ screen_x11->last_wmspec_check_time = 0;
+ g_free (screen_x11->window_manager_name);
+ screen_x11->window_manager_name = g_strdup ("unknown");
+
+ /* careful, reentrancy */
+ _gdk_x11_screen_window_manager_changed (screen);
+
+ return_val = FALSE;
+ goto done;
+ }
+ }
+ }
+
+ /* We do a "manual" conversion of the XEvent to a
+ * GdkEvent. The structures are mostly the same so
+ * the conversion is fairly straightforward. We also
+ * optionally print debugging info regarding events
+ * received.
+ */
+
+ return_val = TRUE;
+
+ switch (xevent->type)
+ {
+ case KeymapNotify:
+ GDK_NOTE (EVENTS,
+ g_message ("keymap notify"));
+
+ /* Not currently handled */
+ return_val = FALSE;
+ break;
+
+ case Expose:
+ GDK_NOTE (EVENTS,
+ g_message ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d%s",
+ xevent->xexpose.window, xevent->xexpose.count,
+ xevent->xexpose.x, xevent->xexpose.y,
+ xevent->xexpose.width, xevent->xexpose.height,
+ event->any.send_event ? " (send)" : ""));
+
+ if (window_private == NULL)
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ {
+ GdkRectangle expose_rect;
+
+ expose_rect.x = xevent->xexpose.x;
+ expose_rect.y = xevent->xexpose.y;
+ expose_rect.width = xevent->xexpose.width;
+ expose_rect.height = xevent->xexpose.height;
+
+ _gdk_window_process_expose (window, xevent->xexpose.serial, &expose_rect);
+ return_val = FALSE;
+ }
+
+ break;
+
+ case GraphicsExpose:
+ {
+ GdkRectangle expose_rect;
+
+ GDK_NOTE (EVENTS,
+ g_message ("graphics expose:\tdrawable: %ld",
+ xevent->xgraphicsexpose.drawable));
+
+ if (window_private == NULL)
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ expose_rect.x = xevent->xgraphicsexpose.x;
+ expose_rect.y = xevent->xgraphicsexpose.y;
+ expose_rect.width = xevent->xgraphicsexpose.width;
+ expose_rect.height = xevent->xgraphicsexpose.height;
+
+ _gdk_window_process_expose (window, xevent->xgraphicsexpose.serial, &expose_rect);
+ return_val = FALSE;
+ }
+ break;
+
+ case NoExpose:
+ GDK_NOTE (EVENTS,
+ g_message ("no expose:\t\tdrawable: %ld",
+ xevent->xnoexpose.drawable));
+
+ event->no_expose.type = GDK_NO_EXPOSE;
+ event->no_expose.window = window;
+
+ break;
+
+ case VisibilityNotify:
+#ifdef G_ENABLE_DEBUG
+ if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
+ switch (xevent->xvisibility.state)
+ {
+ case VisibilityFullyObscured:
+ g_message ("visibility notify:\twindow: %ld none",
+ xevent->xvisibility.window);
+ break;
+ case VisibilityPartiallyObscured:
+ g_message ("visibility notify:\twindow: %ld partial",
+ xevent->xvisibility.window);
+ break;
+ case VisibilityUnobscured:
+ g_message ("visibility notify:\twindow: %ld full",
+ xevent->xvisibility.window);
+ break;
+ }
+#endif /* G_ENABLE_DEBUG */
+
+ if (window_private == NULL)
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ event->visibility.type = GDK_VISIBILITY_NOTIFY;
+ event->visibility.window = window;
+
+ switch (xevent->xvisibility.state)
+ {
+ case VisibilityFullyObscured:
+ event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
+ break;
+
+ case VisibilityPartiallyObscured:
+ event->visibility.state = GDK_VISIBILITY_PARTIAL;
+ break;
+
+ case VisibilityUnobscured:
+ event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
+ break;
+ }
+
+ break;
+
+ case CreateNotify:
+ GDK_NOTE (EVENTS,
+ g_message ("create notify:\twindow: %ld x,y: %d %d w,h: %d %d b-w: %d parent: %ld ovr: %d",
+ xevent->xcreatewindow.window,
+ xevent->xcreatewindow.x,
+ xevent->xcreatewindow.y,
+ xevent->xcreatewindow.width,
+ xevent->xcreatewindow.height,
+ xevent->xcreatewindow.border_width,
+ xevent->xcreatewindow.parent,
+ xevent->xcreatewindow.override_redirect));
+ /* not really handled */
+ break;
+
+ case DestroyNotify:
+ GDK_NOTE (EVENTS,
+ g_message ("destroy notify:\twindow: %ld",
+ xevent->xdestroywindow.window));
+
+ /* Ignore DestroyNotify from SubstructureNotifyMask */
+ if (xevent->xdestroywindow.window == xevent->xdestroywindow.event)
+ {
+ event->any.type = GDK_DESTROY;
+ event->any.window = window;
+
+ return_val = window_private && !GDK_WINDOW_DESTROYED (window);
+
+ if (window && GDK_WINDOW_XID (window) != screen_x11->xroot_window)
+ gdk_window_destroy_notify (window);
+ }
+ else
+ return_val = FALSE;
+
+ break;
+
+ case UnmapNotify:
+ GDK_NOTE (EVENTS,
+ g_message ("unmap notify:\t\twindow: %ld",
+ xevent->xmap.window));
+
+ event->any.type = GDK_UNMAP;
+ event->any.window = window;
+
+ /* If we are shown (not withdrawn) and get an unmap, it means we
+ * were iconified in the X sense. If we are withdrawn, and get
+ * an unmap, it means we hid the window ourselves, so we
+ * will have already flipped the iconified bit off.
+ */
+ if (window)
+ {
+ if (GDK_WINDOW_IS_MAPPED (window))
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_ICONIFIED);
+
+ _gdk_xgrab_check_unmap (window, xevent->xany.serial);
+ }
+
+ break;
+
+ case MapNotify:
+ GDK_NOTE (EVENTS,
+ g_message ("map notify:\t\twindow: %ld",
+ xevent->xmap.window));
+
+ event->any.type = GDK_MAP;
+ event->any.window = window;
+
+ /* Unset iconified if it was set */
+ if (window && (((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_ICONIFIED))
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_ICONIFIED,
+ 0);
+
+ break;
+
+ case ReparentNotify:
+ GDK_NOTE (EVENTS,
+ g_message ("reparent notify:\twindow: %ld x,y: %d %d parent: %ld ovr: %d",
+ xevent->xreparent.window,
+ xevent->xreparent.x,
+ xevent->xreparent.y,
+ xevent->xreparent.parent,
+ xevent->xreparent.override_redirect));
+
+ /* Not currently handled */
+ return_val = FALSE;
+ break;
+
+ case ConfigureNotify:
+ GDK_NOTE (EVENTS,
+ g_message ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d b-w: %d above: %ld ovr: %d%s",
+ xevent->xconfigure.window,
+ xevent->xconfigure.x,
+ xevent->xconfigure.y,
+ xevent->xconfigure.width,
+ xevent->xconfigure.height,
+ xevent->xconfigure.border_width,
+ xevent->xconfigure.above,
+ xevent->xconfigure.override_redirect,
+ !window
+ ? " (discarding)"
+ : GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD
+ ? " (discarding child)"
+ : xevent->xconfigure.event != xevent->xconfigure.window
+ ? " (discarding substructure)"
+ : ""));
+ if (window && GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
+ {
+ window_private->width = xevent->xconfigure.width;
+ window_private->height = xevent->xconfigure.height;
+
+ _gdk_window_update_size (window);
+ _gdk_x11_drawable_update_size (window_private->impl);
+ _gdk_x11_screen_size_changed (screen, xevent);
+ }
+
+#ifdef HAVE_XSYNC
+ if (toplevel && display_x11->use_sync && !XSyncValueIsZero (toplevel->pending_counter_value))
+ {
+ toplevel->current_counter_value = toplevel->pending_counter_value;
+ XSyncIntToValue (&toplevel->pending_counter_value, 0);
+ }
+#endif
+
+ if (!window ||
+ xevent->xconfigure.event != xevent->xconfigure.window ||
+ GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD ||
+ GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
+ return_val = FALSE;
+ else
+ {
+ event->configure.type = GDK_CONFIGURE;
+ event->configure.window = window;
+ event->configure.width = xevent->xconfigure.width;
+ event->configure.height = xevent->xconfigure.height;
+
+ if (!xevent->xconfigure.send_event &&
+ !xevent->xconfigure.override_redirect &&
+ !GDK_WINDOW_DESTROYED (window))
+ {
+ gint tx = 0;
+ gint ty = 0;
+ Window child_window = 0;
+
+ gdk_error_trap_push ();
+ if (XTranslateCoordinates (GDK_DRAWABLE_XDISPLAY (window),
+ GDK_DRAWABLE_XID (window),
+ screen_x11->xroot_window,
+ 0, 0,
+ &tx, &ty,
+ &child_window))
+ {
+ event->configure.x = tx;
+ event->configure.y = ty;
+ }
+ gdk_error_trap_pop ();
+ }
+ else
+ {
+ event->configure.x = xevent->xconfigure.x;
+ event->configure.y = xevent->xconfigure.y;
+ }
+ window_private->x = event->configure.x;
+ window_private->y = event->configure.y;
+ window_private->width = xevent->xconfigure.width;
+ window_private->height = xevent->xconfigure.height;
+
+ _gdk_window_update_size (window);
+ _gdk_x11_drawable_update_size (window_private->impl);
+
+ if (window_private->resize_count >= 1)
+ {
+ window_private->resize_count -= 1;
+
+ if (window_private->resize_count == 0)
+ _gdk_moveresize_configure_done (display, window);
+ }
+ }
+ break;
+
+ case PropertyNotify:
+ GDK_NOTE (EVENTS,
+ g_message ("property notify:\twindow: %ld, atom(%ld): %s%s%s",
+ xevent->xproperty.window,
+ xevent->xproperty.atom,
+ "\"",
+ gdk_x11_get_xatom_name_for_display (display, xevent->xproperty.atom),
+ "\""));
+
+ if (window_private == NULL)
+ {
+ return_val = FALSE;
+ break;
+ }
+
+ /* We compare with the serial of the last time we mapped the
+ * window to avoid refetching properties that we set ourselves
+ */
+ if (toplevel &&
+ xevent->xproperty.serial >= toplevel->map_serial)
+ {
+ if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"))
+ gdk_check_wm_state_changed (window);
+
+ if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"))
+ gdk_check_wm_desktop_changed (window);
+ }
+
+ if (window_private->event_mask & GDK_PROPERTY_CHANGE_MASK)
+ {
+ event->property.type = GDK_PROPERTY_NOTIFY;
+ event->property.window = window;
+ event->property.atom = gdk_x11_xatom_to_atom_for_display (display, xevent->xproperty.atom);
+ event->property.time = xevent->xproperty.time;
+ event->property.state = xevent->xproperty.state;
+ }
+ else
+ return_val = FALSE;
+
+ break;
+
+ case SelectionClear:
+ GDK_NOTE (EVENTS,
+ g_message ("selection clear:\twindow: %ld",
+ xevent->xproperty.window));
+
+ if (_gdk_selection_filter_clear_event (&xevent->xselectionclear))
+ {
+ event->selection.type = GDK_SELECTION_CLEAR;
+ event->selection.window = window;
+ event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionclear.selection);
+ event->selection.time = xevent->xselectionclear.time;
+ }
+ else
+ return_val = FALSE;
+
+ break;
+
+ case SelectionRequest:
+ GDK_NOTE (EVENTS,
+ g_message ("selection request:\twindow: %ld",
+ xevent->xproperty.window));
+
+ event->selection.type = GDK_SELECTION_REQUEST;
+ event->selection.window = window;
+ event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.selection);
+ event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.target);
+ event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.property);
+ event->selection.requestor = xevent->xselectionrequest.requestor;
+ event->selection.time = xevent->xselectionrequest.time;
+
+ break;
+
+ case SelectionNotify:
+ GDK_NOTE (EVENTS,
+ g_message ("selection notify:\twindow: %ld",
+ xevent->xproperty.window));
+
+ event->selection.type = GDK_SELECTION_NOTIFY;
+ event->selection.window = window;
+ event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.selection);
+ event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.target);
+ if (xevent->xselection.property == None)
+ event->selection.property = GDK_NONE;
+ else
+ event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.property);
+ event->selection.time = xevent->xselection.time;
+
+ break;
+
+ case ColormapNotify:
+ GDK_NOTE (EVENTS,
+ g_message ("colormap notify:\twindow: %ld",
+ xevent->xcolormap.window));
+
+ /* Not currently handled */
+ return_val = FALSE;
+ break;
+
+ case ClientMessage:
+ {
+ GList *tmp_list;
+ GdkFilterReturn result = GDK_FILTER_CONTINUE;
+ GdkAtom message_type = gdk_x11_xatom_to_atom_for_display (display, xevent->xclient.message_type);
+
+ GDK_NOTE (EVENTS,
+ g_message ("client message:\twindow: %ld",
+ xevent->xclient.window));
+
+ tmp_list = display_x11->client_filters;
+ while (tmp_list)
+ {
+ GdkClientFilter *filter = tmp_list->data;
+ tmp_list = tmp_list->next;
+
+ if (filter->type == message_type)
+ {
+ result = (*filter->function) (xevent, event, filter->data);
+ if (result != GDK_FILTER_CONTINUE)
+ break;
+ }
+ }
+
+ switch (result)
+ {
+ case GDK_FILTER_REMOVE:
+ return_val = FALSE;
+ break;
+ case GDK_FILTER_TRANSLATE:
+ return_val = TRUE;
+ break;
+ case GDK_FILTER_CONTINUE:
+ /* Send unknown ClientMessage's on to Gtk for it to use */
+ if (window_private == NULL)
+ {
+ return_val = FALSE;
+ }
+ else
+ {
+ event->client.type = GDK_CLIENT_EVENT;
+ event->client.window = window;
+ event->client.message_type = message_type;
+ event->client.data_format = xevent->xclient.format;
+ memcpy(&event->client.data, &xevent->xclient.data,
+ sizeof(event->client.data));
+ }
+ break;
+ }
+ }
+
+ break;
+
+ case MappingNotify:
+ GDK_NOTE (EVENTS,
+ g_message ("mapping notify"));
+
+ /* Let XLib know that there is a new keyboard mapping.
+ */
+ XRefreshKeyboardMapping (&xevent->xmapping);
+ _gdk_keymap_keys_changed (display);
+ return_val = FALSE;
+ break;
+
+ default:
+#ifdef HAVE_XFIXES
+ if (xevent->type - display_x11->xfixes_event_base == XFixesSelectionNotify)
+ {
+ XFixesSelectionNotifyEvent *selection_notify = (XFixesSelectionNotifyEvent *)xevent;
+
+ _gdk_x11_screen_process_owner_change (screen, xevent);
+
+ event->owner_change.type = GDK_OWNER_CHANGE;
+ event->owner_change.window = window;
+ event->owner_change.owner = selection_notify->owner;
+ event->owner_change.reason = selection_notify->subtype;
+ event->owner_change.selection =
+ gdk_x11_xatom_to_atom_for_display (display,
+ selection_notify->selection);
+ event->owner_change.time = selection_notify->timestamp;
+ event->owner_change.selection_time = selection_notify->selection_timestamp;
+
+ return_val = TRUE;
+ }
+ else
+#endif
+#ifdef HAVE_RANDR
+ if (xevent->type - display_x11->xrandr_event_base == RRScreenChangeNotify ||
+ xevent->type - display_x11->xrandr_event_base == RRNotify)
+ {
+ if (screen)
+ _gdk_x11_screen_size_changed (screen, xevent);
+ }
+ else
+#endif
+#if defined(HAVE_XCOMPOSITE) && defined (HAVE_XDAMAGE) && defined (HAVE_XFIXES)
+ if (display_x11->have_xdamage && window_private && window_private->composited &&
+ xevent->type == display_x11->xdamage_event_base + XDamageNotify &&
+ ((XDamageNotifyEvent *) xevent)->damage == window_impl->damage)
+ {
+ XDamageNotifyEvent *damage_event = (XDamageNotifyEvent *) xevent;
+ XserverRegion repair;
+ GdkRectangle rect;
+
+ rect.x = window_private->x + damage_event->area.x;
+ rect.y = window_private->y + damage_event->area.y;
+ rect.width = damage_event->area.width;
+ rect.height = damage_event->area.height;
+
+ repair = XFixesCreateRegion (display_x11->xdisplay,
+ &damage_event->area, 1);
+ XDamageSubtract (display_x11->xdisplay,
+ window_impl->damage,
+ repair, None);
+ XFixesDestroyRegion (display_x11->xdisplay, repair);
+
+ if (window_private->parent != NULL)
+ _gdk_window_process_expose (GDK_WINDOW (window_private->parent),
+ damage_event->serial, &rect);
+
+ return_val = TRUE;
+ }
+ else
+#endif
+#ifdef HAVE_XKB
+ if (xevent->type == display_x11->xkb_event_type)
+ {
+ XkbEvent *xkb_event = (XkbEvent *) xevent;
+
+ switch (xkb_event->any.xkb_type)
+ {
+ case XkbNewKeyboardNotify:
+ case XkbMapNotify:
+ _gdk_keymap_keys_changed (display);
+
+ return_val = FALSE;
+ break;
+
+ case XkbStateNotify:
+ _gdk_keymap_state_changed (display, xevent);
+ break;
+ }
+ }
+ else
+#endif
+ return_val = FALSE;
+ }
+
+ done:
+ if (return_val)
+ {
+ if (event->any.window)
+ g_object_ref (event->any.window);
+ }
+ else
+ {
+ /* Mark this event as having no resources to be freed */
+ event->any.window = NULL;
+ event->any.type = GDK_NOTHING;
+ }
+
+ if (window)
+ g_object_unref (window);
+
+ return return_val;
+}
+
+static GdkFilterReturn
+gdk_wm_protocols_filter (GdkXEvent *xev,
+ GdkEvent *event,
+ gpointer data)
+{
+ XEvent *xevent = (XEvent *)xev;
+ GdkWindow *win = event->any.window;
+ GdkDisplay *display;
+ Atom atom;
+
+ if (!win)
+ return GDK_FILTER_REMOVE;
+
+ display = GDK_WINDOW_DISPLAY (win);
+ atom = (Atom)xevent->xclient.data.l[0];
+
+ if (atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW"))
+ {
+ /* The delete window request specifies a window
+ * to delete. We don't actually destroy the
+ * window because "it is only a request". (The
+ * window might contain vital data that the
+ * program does not want destroyed). Instead
+ * the event is passed along to the program,
+ * which should then destroy the window.
+ */
+ GDK_NOTE (EVENTS,
+ g_message ("delete window:\t\twindow: %ld",
+ xevent->xclient.window));
+
+ event->any.type = GDK_DELETE;
+
+ gdk_x11_window_set_user_time (win, xevent->xclient.data.l[1]);
+
+ return GDK_FILTER_TRANSLATE;
+ }
+ else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS"))
+ {
+ GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (event->any.window);
+ GdkWindowObject *private = (GdkWindowObject *)win;
+
+ /* There is no way of knowing reliably whether we are viewable;
+ * _gdk_x11_set_input_focus_safe() traps errors asynchronously.
+ */
+ if (toplevel && private->accept_focus)
+ _gdk_x11_set_input_focus_safe (display, toplevel->focus_window,
+ RevertToParent,
+ xevent->xclient.data.l[1]);
+
+ return GDK_FILTER_REMOVE;
+ }
+ else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING") &&
+ !_gdk_x11_display_is_root_window (display,
+ xevent->xclient.window))
+ {
+ XClientMessageEvent xclient = xevent->xclient;
+
+ xclient.window = GDK_WINDOW_XROOTWIN (win);
+ XSendEvent (GDK_WINDOW_XDISPLAY (win),
+ xclient.window,
+ False,
+ SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient);
+
+ return GDK_FILTER_REMOVE;
+ }
+ else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_SYNC_REQUEST") &&
+ GDK_DISPLAY_X11 (display)->use_sync)
+ {
+ GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (event->any.window);
+ if (toplevel)
+ {
+#ifdef HAVE_XSYNC
+ XSyncIntsToValue (&toplevel->pending_counter_value,
+ xevent->xclient.data.l[2],
+ xevent->xclient.data.l[3]);
+#endif
+ }
+ return GDK_FILTER_REMOVE;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+_gdk_event_init (GdkDisplay *display)
+{
+ GdkDisplayX11 *display_x11;
+ GdkDeviceManager *device_manager;
+
+ display_x11 = GDK_DISPLAY_X11 (display);
+ display_x11->event_source = gdk_event_source_new (display);
+
+ gdk_event_source_add_translator ((GdkEventSource *) display_x11->event_source,
+ GDK_EVENT_TRANSLATOR (display));
+
+ device_manager = gdk_display_get_device_manager (display);
+ gdk_event_source_add_translator ((GdkEventSource *) display_x11->event_source,
+ GDK_EVENT_TRANSLATOR (device_manager));
+
+ gdk_display_add_client_message_filter (display,
+ gdk_atom_intern_static_string ("WM_PROTOCOLS"),
+ gdk_wm_protocols_filter,
+ NULL);
+}
+
+static void
+_gdk_input_init (GdkDisplay *display)
+{
+ GdkDisplayX11 *display_x11;
+ GdkDeviceManager *device_manager;
+ GdkDevice *device;
+ GList *list, *l;
+
+ display_x11 = GDK_DISPLAY_X11 (display);
+ device_manager = gdk_display_get_device_manager (display);
+
+ /* For backwards compatibility, just add
+ * floating devices that are not keyboards.
+ */
+ list = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING);
+
+ for (l = list; l; l = l->next)
+ {
+ device = l->data;
+
+ if (device->source == GDK_SOURCE_KEYBOARD)
+ continue;
+
+ display_x11->input_devices = g_list_prepend (display_x11->input_devices, l->data);
+ }
+
+ g_list_free (list);
+
+ /* Now set "core" pointer to the first
+ * master device that is a pointer.
+ */
+ list = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+
+ for (l = list; l; l = l->next)
+ {
+ device = list->data;
+
+ if (device->source != GDK_SOURCE_MOUSE)
+ continue;
+
+ display->core_pointer = device;
+ break;
+ }
+
+ /* Add the core pointer to the devices list */
+ display_x11->input_devices = g_list_prepend (display_x11->input_devices, display->core_pointer);
+
+ g_list_free (list);
+}
+
/**
* gdk_display_open:
* @display_name: the name of the display to open
@@ -206,11 +1234,15 @@ gdk_display_open (const gchar *display_name)
* structures in places
*/
for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
- _gdk_x11_events_init_screen (display_x11->screens[i]);
-
+ _gdk_screen_x11_events_init (display_x11->screens[i]);
+
/*set the default screen */
display_x11->default_screen = display_x11->screens[DefaultScreen (display_x11->xdisplay)];
+ display->device_manager = _gdk_device_manager_new (display);
+
+ _gdk_event_init (display);
+
attr.window_type = GDK_WINDOW_TOPLEVEL;
attr.wclass = GDK_INPUT_OUTPUT;
attr.x = 10;
@@ -395,15 +1427,15 @@ gdk_display_open (const gchar *display_name)
display_x11->use_sync = TRUE;
}
#endif
-
+
_gdk_windowing_image_init (display);
- _gdk_events_init (display);
_gdk_input_init (display);
_gdk_dnd_init (display);
for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
_gdk_x11_screen_setup (display_x11->screens[i]);
+ g_signal_emit_by_name (display, "opened");
g_signal_emit_by_name (gdk_display_manager_get(),
"display_opened", display);
@@ -592,11 +1624,13 @@ struct XPointerUngrabInfo {
};
static void
-pointer_ungrab_callback (GdkDisplay *display,
- gpointer data,
- gulong serial)
+device_ungrab_callback (GdkDisplay *display,
+ gpointer data,
+ gulong serial)
{
- _gdk_display_pointer_grab_update (display, serial);
+ GdkDevice *device = data;
+
+ _gdk_display_device_grab_update (display, device, serial);
}
@@ -606,78 +1640,47 @@ pointer_ungrab_callback (GdkDisplay *display,
)
/**
- * gdk_display_pointer_ungrab:
- * @display: a #GdkDisplay.
+ * gdk_device_ungrab:
+ * @device: a #GdkDevice
* @time_: a timestap (e.g. %GDK_CURRENT_TIME).
*
- * Release any pointer grab.
+ * Release any grab on @device.
*
- * Since: 2.2
+ * Since: 3.0
*/
void
-gdk_display_pointer_ungrab (GdkDisplay *display,
- guint32 time_)
+gdk_device_ungrab (GdkDevice *device,
+ guint32 time_)
{
+ GdkDisplay *display;
Display *xdisplay;
- GdkDisplayX11 *display_x11;
- GdkPointerGrabInfo *grab;
+ GdkDeviceGrabInfo *grab;
unsigned long serial;
- g_return_if_fail (GDK_IS_DISPLAY (display));
+ g_return_if_fail (GDK_IS_DEVICE (device));
- display_x11 = GDK_DISPLAY_X11 (display);
+ display = gdk_device_get_display (device);
xdisplay = GDK_DISPLAY_XDISPLAY (display);
serial = NextRequest (xdisplay);
-
- _gdk_input_ungrab_pointer (display, time_);
- XUngrabPointer (xdisplay, time_);
+
+ GDK_DEVICE_GET_CLASS (device)->ungrab (device, time_);
XFlush (xdisplay);
- grab = _gdk_display_get_last_pointer_grab (display);
+ grab = _gdk_display_get_last_device_grab (display, device);
if (grab &&
(time_ == GDK_CURRENT_TIME ||
grab->time == GDK_CURRENT_TIME ||
!XSERVER_TIME_IS_LATER (grab->time, time_)))
{
grab->serial_end = serial;
- _gdk_x11_roundtrip_async (display,
- pointer_ungrab_callback,
- NULL);
+ _gdk_x11_roundtrip_async (display,
+ device_ungrab_callback,
+ device);
}
}
/**
- * gdk_display_keyboard_ungrab:
- * @display: a #GdkDisplay.
- * @time_: a timestap (e.g #GDK_CURRENT_TIME).
- *
- * Release any keyboard grab
- *
- * Since: 2.2
- */
-void
-gdk_display_keyboard_ungrab (GdkDisplay *display,
- guint32 time)
-{
- Display *xdisplay;
- GdkDisplayX11 *display_x11;
-
- g_return_if_fail (GDK_IS_DISPLAY (display));
-
- display_x11 = GDK_DISPLAY_X11 (display);
- xdisplay = GDK_DISPLAY_XDISPLAY (display);
-
- XUngrabKeyboard (xdisplay, time);
- XFlush (xdisplay);
-
- if (time == GDK_CURRENT_TIME ||
- display->keyboard_grab.time == GDK_CURRENT_TIME ||
- !XSERVER_TIME_IS_LATER (display->keyboard_grab.time, time))
- _gdk_display_unset_has_keyboard_grab (display, FALSE);
-}
-
-/**
* gdk_display_beep:
* @display: a #GdkDisplay
*
@@ -829,7 +1832,12 @@ gdk_display_x11_dispose (GObject *object)
for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
_gdk_screen_close (display_x11->screens[i]);
- _gdk_events_uninit (GDK_DISPLAY_OBJECT (object));
+ if (display_x11->event_source)
+ {
+ g_source_destroy (display_x11->event_source);
+ g_source_unref (display_x11->event_source);
+ display_x11->event_source = NULL;
+ }
G_OBJECT_CLASS (_gdk_display_x11_parent_class)->dispose (object);
}
@@ -1479,6 +2487,185 @@ gdk_display_supports_composite (GdkDisplay *display)
x11_display->have_xfixes;
}
+/**
+ * gdk_display_list_devices:
+ * @display: a #GdkDisplay
+ *
+ * Returns the list of available input devices attached to @display.
+ * The list is statically allocated and should not be freed.
+ *
+ * Return value: a list of #GdkDevice
+ *
+ * Since: 2.2
+ *
+ * Deprecated: 3.0. Use gdk_device_manager_list_devices() instead.
+ **/
+GList *
+gdk_display_list_devices (GdkDisplay *display)
+{
+ g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+ return GDK_DISPLAY_X11 (display)->input_devices;
+}
+
+/**
+ * gdk_event_send_client_message_for_display:
+ * @display: the #GdkDisplay for the window where the message is to be sent.
+ * @event: the #GdkEvent to send, which should be a #GdkEventClient.
+ * @winid: the window to send the client message to.
+ *
+ * On X11, sends an X ClientMessage event to a given window. On
+ * Windows, sends a message registered with the name
+ * GDK_WIN32_CLIENT_MESSAGE.
+ *
+ * This could be used for communicating between different
+ * applications, though the amount of data is limited to 20 bytes on
+ * X11, and to just four bytes on Windows.
+ *
+ * Returns: non-zero on success.
+ *
+ * Since: 2.2
+ */
+gboolean
+gdk_event_send_client_message_for_display (GdkDisplay *display,
+ GdkEvent *event,
+ GdkNativeWindow winid)
+{
+ XEvent sev;
+
+ g_return_val_if_fail(event != NULL, FALSE);
+
+ /* Set up our event to send, with the exception of its target window */
+ sev.xclient.type = ClientMessage;
+ sev.xclient.display = GDK_DISPLAY_XDISPLAY (display);
+ sev.xclient.format = event->client.data_format;
+ sev.xclient.window = winid;
+ memcpy(&sev.xclient.data, &event->client.data, sizeof (sev.xclient.data));
+ sev.xclient.message_type = gdk_x11_atom_to_xatom_for_display (display, event->client.message_type);
+
+ return _gdk_send_xevent (display, winid, False, NoEventMask, &sev);
+}
+
+/**
+ * gdk_display_add_client_message_filter:
+ * @display: a #GdkDisplay for which this message filter applies
+ * @message_type: the type of ClientMessage events to receive.
+ * This will be checked against the @message_type field
+ * of the XClientMessage event struct.
+ * @func: the function to call to process the event.
+ * @data: user data to pass to @func.
+ *
+ * Adds a filter to be called when X ClientMessage events are received.
+ * See gdk_window_add_filter() if you are interested in filtering other
+ * types of events.
+ *
+ * Since: 2.2
+ **/
+void
+gdk_display_add_client_message_filter (GdkDisplay *display,
+ GdkAtom message_type,
+ GdkFilterFunc func,
+ gpointer data)
+{
+ GdkClientFilter *filter;
+ g_return_if_fail (GDK_IS_DISPLAY (display));
+ filter = g_new (GdkClientFilter, 1);
+
+ filter->type = message_type;
+ filter->function = func;
+ filter->data = data;
+
+ GDK_DISPLAY_X11(display)->client_filters =
+ g_list_append (GDK_DISPLAY_X11 (display)->client_filters,
+ filter);
+}
+
+/**
+ * gdk_add_client_message_filter:
+ * @message_type: the type of ClientMessage events to receive. This will be
+ * checked against the <structfield>message_type</structfield> field of the
+ * XClientMessage event struct.
+ * @func: the function to call to process the event.
+ * @data: user data to pass to @func.
+ *
+ * Adds a filter to the default display to be called when X ClientMessage events
+ * are received. See gdk_display_add_client_message_filter().
+ **/
+void
+gdk_add_client_message_filter (GdkAtom message_type,
+ GdkFilterFunc func,
+ gpointer data)
+{
+ gdk_display_add_client_message_filter (gdk_display_get_default (),
+ message_type, func, data);
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_flush
+ *
+ * Flushes the Xlib output buffer and then waits
+ * until all requests have been received and processed
+ * by the X server. The only real use for this function
+ * is in dealing with XShm.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+void
+gdk_flush (void)
+{
+ GSList *tmp_list = _gdk_displays;
+
+ while (tmp_list)
+ {
+ XSync (GDK_DISPLAY_XDISPLAY (tmp_list->data), False);
+ tmp_list = tmp_list->next;
+ }
+}
+
+/**
+ * gdk_x11_register_standard_event_type:
+ * @display: a #GdkDisplay
+ * @event_base: first event type code to register
+ * @n_events: number of event type codes to register
+ *
+ * Registers interest in receiving extension events with type codes
+ * between @event_base and <literal>event_base + n_events - 1</literal>.
+ * The registered events must have the window field in the same place
+ * as core X events (this is not the case for e.g. XKB extension events).
+ *
+ * If an event type is registered, events of this type will go through
+ * global and window-specific filters (see gdk_window_add_filter()).
+ * Unregistered events will only go through global filters.
+ * GDK may register the events of some X extensions on its own.
+ *
+ * This function should only be needed in unusual circumstances, e.g.
+ * when filtering XInput extension events on the root window.
+ *
+ * Since: 2.4
+ **/
+void
+gdk_x11_register_standard_event_type (GdkDisplay *display,
+ gint event_base,
+ gint n_events)
+{
+ GdkEventTypeX11 *event_type;
+ GdkDisplayX11 *display_x11;
+
+ display_x11 = GDK_DISPLAY_X11 (display);
+ event_type = g_new (GdkEventTypeX11, 1);
+
+ event_type->base = event_base;
+ event_type->n_events = n_events;
+
+ display_x11->event_types = g_slist_prepend (display_x11->event_types, event_type);
+}
#define __GDK_DISPLAY_X11_C__
#include "gdkaliasdef.c"
diff --git a/gdk/x11/gdkdnd-x11.c b/gdk/x11/gdkdnd-x11.c
index 8f6730078d..acce83bb84 100644
--- a/gdk/x11/gdkdnd-x11.c
+++ b/gdk/x11/gdkdnd-x11.c
@@ -96,6 +96,7 @@ struct _GdkDragContextPrivateX11 {
guint version; /* Xdnd protocol version */
GSList *window_caches;
+ GdkDevice *device;
};
#define PRIVATE_DATA(context) ((GdkDragContextPrivateX11 *) GDK_DRAG_CONTEXT (context)->windowing_data)
@@ -220,6 +221,55 @@ gdk_drag_context_new (void)
return g_object_new (GDK_TYPE_DRAG_CONTEXT, NULL);
}
+/**
+ * gdk_drag_context_set_device:
+ * @context: a #GdkDragContext
+ * @device: a #GdkDevice
+ *
+ * Associates a #GdkDevice to @context, so all Drag and Drop events
+ * for @context are emitted as if they came from this device.
+ **/
+void
+gdk_drag_context_set_device (GdkDragContext *context,
+ GdkDevice *device)
+{
+ GdkDragContextPrivateX11 *private;
+
+ g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+ g_return_if_fail (GDK_IS_DEVICE (device));
+
+ private = PRIVATE_DATA (context);
+
+ if (private->device)
+ {
+ g_object_unref (private->device);
+ private->device = NULL;
+ }
+
+ if (device)
+ private->device = g_object_ref (device);
+}
+
+/**
+ * gdk_drag_context_get_device:
+ * @context: a #GdkDragContext
+ *
+ * Returns the #GdkDevice associated to the drag context.
+ *
+ * Returns: The #GdkDevice associated to @context.
+ **/
+GdkDevice *
+gdk_drag_context_get_device (GdkDragContext *context)
+{
+ GdkDragContextPrivateX11 *private;
+
+ g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), NULL);
+
+ private = PRIVATE_DATA (context);
+
+ return private->device;
+}
+
static GdkDragContext *
gdk_drag_context_find (GdkDisplay *display,
gboolean is_source,
@@ -2083,6 +2133,7 @@ xdnd_status_filter (GdkXEvent *xev,
event->dnd.send_event = FALSE;
event->dnd.type = GDK_DRAG_STATUS;
event->dnd.context = context;
+ gdk_event_set_device (event, gdk_drag_context_get_device (context));
g_object_ref (context);
event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
@@ -2130,6 +2181,7 @@ xdnd_finished_filter (GdkXEvent *xev,
event->dnd.type = GDK_DROP_FINISHED;
event->dnd.context = context;
+ gdk_event_set_device (event, gdk_drag_context_get_device (context));
g_object_ref (context);
event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
@@ -2237,7 +2289,7 @@ send_client_message_async_cb (Window window,
context->dest_window &&
window == GDK_WINDOW_XID (context->dest_window))
{
- GdkEvent temp_event;
+ GdkEvent *temp_event;
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
g_object_unref (context->dest_window);
@@ -2246,13 +2298,16 @@ send_client_message_async_cb (Window window,
private->drag_status = GDK_DRAG_STATUS_DRAG;
- temp_event.dnd.type = GDK_DRAG_STATUS;
- temp_event.dnd.window = context->source_window;
- temp_event.dnd.send_event = TRUE;
- temp_event.dnd.context = context;
- temp_event.dnd.time = GDK_CURRENT_TIME;
+ temp_event = gdk_event_new (GDK_DRAG_STATUS);
+ temp_event->dnd.window = g_object_ref (context->source_window);
+ temp_event->dnd.send_event = TRUE;
+ temp_event->dnd.context = g_object_ref (context);
+ temp_event->dnd.time = GDK_CURRENT_TIME;
+ gdk_event_set_device (temp_event, gdk_drag_context_get_device (context));
- gdk_event_put (&temp_event);
+ gdk_event_put (temp_event);
+
+ gdk_event_free (temp_event);
}
g_object_unref (context);
@@ -2309,13 +2364,15 @@ xdnd_send_xevent (GdkDragContext *context,
if (gdk_x11_get_xatom_by_name_for_display (display, xdnd_filters[i].atom_name) ==
event_send->xclient.message_type)
{
- GdkEvent temp_event;
- temp_event.any.window = window;
+ GdkEvent *temp_event;
+
+ temp_event = gdk_event_new (GDK_NOTHING);
+ temp_event->any.window = g_object_ref (window);
- if ((*xdnd_filters[i].func) (event_send, &temp_event, NULL) == GDK_FILTER_TRANSLATE)
+ if ((*xdnd_filters[i].func) (event_send, temp_event, NULL) == GDK_FILTER_TRANSLATE)
{
- gdk_event_put (&temp_event);
- g_object_unref (temp_event.dnd.context);
+ gdk_event_put (temp_event);
+ gdk_event_free (temp_event);
}
return TRUE;
@@ -2806,6 +2863,9 @@ xdnd_enter_filter (GdkXEvent *xev,
new_context->protocol = GDK_DRAG_PROTO_XDND;
PRIVATE_DATA(new_context)->version = version;
+ /* FIXME: Should extend DnD protocol to have device info */
+ gdk_drag_context_set_device (new_context, gdk_display_get_core_pointer (display));
+
new_context->source_window = gdk_window_lookup_for_display (display, source_window);
if (new_context->source_window)
g_object_ref (new_context->source_window);
@@ -2872,6 +2932,7 @@ xdnd_enter_filter (GdkXEvent *xev,
event->dnd.type = GDK_DRAG_ENTER;
event->dnd.context = new_context;
+ gdk_event_set_device (event, gdk_drag_context_get_device (new_context));
g_object_ref (new_context);
display_x11->current_dest_drag = new_context;
@@ -2909,6 +2970,7 @@ xdnd_leave_filter (GdkXEvent *xev,
event->dnd.type = GDK_DRAG_LEAVE;
/* Pass ownership of context to the event */
event->dnd.context = display_x11->current_dest_drag;
+ gdk_event_set_device (event, gdk_drag_context_get_device (event->dnd.context));
display_x11->current_dest_drag = NULL;
@@ -2952,6 +3014,7 @@ xdnd_position_filter (GdkXEvent *xev,
{
event->dnd.type = GDK_DRAG_MOTION;
event->dnd.context = display_x11->current_dest_drag;
+ gdk_event_set_device (event, gdk_drag_context_get_device (event->dnd.context));
g_object_ref (display_x11->current_dest_drag);
event->dnd.time = time;
@@ -3007,6 +3070,7 @@ xdnd_drop_filter (GdkXEvent *xev,
event->dnd.type = GDK_DROP_START;
event->dnd.context = display_x11->current_dest_drag;
+ gdk_event_set_device (event, gdk_drag_context_get_device (event->dnd.context));
g_object_ref (display_x11->current_dest_drag);
event->dnd.time = time;
@@ -3086,6 +3150,8 @@ gdk_drag_begin (GdkWindow *window,
GList *targets)
{
GdkDragContext *new_context;
+ GdkDisplay *display;
+ GdkDevice *device;
g_return_val_if_fail (window != NULL, NULL);
g_return_val_if_fail (GDK_WINDOW_IS_X11 (window), NULL);
@@ -3100,6 +3166,10 @@ gdk_drag_begin (GdkWindow *window,
new_context->actions = 0;
+ display = gdk_drawable_get_display (GDK_DRAWABLE (window));
+ device = gdk_display_get_core_pointer (display);
+ gdk_drag_context_set_device (new_context, device);
+
return new_context;
}
@@ -3421,7 +3491,7 @@ gdk_drag_motion (GdkDragContext *context,
if (context->dest_window != dest_window)
{
- GdkEvent temp_event;
+ GdkEvent *temp_event;
/* Send a leave to the last destination */
gdk_drag_do_leave (context, time);
@@ -3465,18 +3535,19 @@ gdk_drag_motion (GdkDragContext *context,
/* Push a status event, to let the client know that
* the drag changed
*/
-
- temp_event.dnd.type = GDK_DRAG_STATUS;
- temp_event.dnd.window = context->source_window;
+ temp_event = gdk_event_new (GDK_DRAG_STATUS);
+ temp_event->dnd.window = g_object_ref (context->source_window);
/* We use this to signal a synthetic status. Perhaps
* we should use an extra field...
*/
- temp_event.dnd.send_event = TRUE;
+ temp_event->dnd.send_event = TRUE;
- temp_event.dnd.context = context;
- temp_event.dnd.time = time;
+ temp_event->dnd.context = g_object_ref (context);
+ temp_event->dnd.time = time;
+ gdk_event_set_device (temp_event, gdk_drag_context_get_device (context));
- gdk_event_put (&temp_event);
+ gdk_event_put (temp_event);
+ gdk_event_free (temp_event);
}
else
{
@@ -3505,7 +3576,7 @@ gdk_drag_motion (GdkDragContext *context,
case GDK_DRAG_PROTO_ROOTWIN:
{
- GdkEvent temp_event;
+ GdkEvent *temp_event;
/* GTK+ traditionally has used application/x-rootwin-drop,
* but the XDND spec specifies x-rootwindow-drop.
*/
@@ -3520,13 +3591,15 @@ gdk_drag_motion (GdkDragContext *context,
else
context->action = 0;
- temp_event.dnd.type = GDK_DRAG_STATUS;
- temp_event.dnd.window = context->source_window;
- temp_event.dnd.send_event = FALSE;
- temp_event.dnd.context = context;
- temp_event.dnd.time = time;
+ temp_event = gdk_event_new (GDK_DRAG_STATUS);
+ temp_event->dnd.window = g_object_ref (context->source_window);
+ temp_event->dnd.send_event = FALSE;
+ temp_event->dnd.context = g_object_ref (context);
+ temp_event->dnd.time = time;
+ gdk_event_set_device (temp_event, gdk_drag_context_get_device (context));
- gdk_event_put (&temp_event);
+ gdk_event_put (temp_event);
+ gdk_event_free (temp_event);
}
break;
case GDK_DRAG_PROTO_NONE:
diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c
deleted file mode 100644
index c50c82ae8e..0000000000
--- a/gdk/x11/gdkevents-x11.c
+++ /dev/null
@@ -1,3088 +0,0 @@
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
- * Josh MacDonald, Ryan Lortie
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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-2007. 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 "gdk.h"
-#include "gdkprivate-x11.h"
-#include "gdkinternals.h"
-#include "gdkx.h"
-#include "gdkscreen-x11.h"
-#include "gdkdisplay-x11.h"
-#include "gdkasync.h"
-
-#include "gdkkeysyms.h"
-
-#include "xsettings-client.h"
-
-#include <string.h>
-
-#include "gdkinputprivate.h"
-#include "gdksettings.c"
-#include "gdkalias.h"
-
-
-#ifdef HAVE_XKB
-#include <X11/XKBlib.h>
-#endif
-
-#ifdef HAVE_XSYNC
-#include <X11/extensions/sync.h>
-#endif
-
-#ifdef HAVE_XFIXES
-#include <X11/extensions/Xfixes.h>
-#endif
-
-#ifdef HAVE_RANDR
-#include <X11/extensions/Xrandr.h>
-#endif
-
-#include <X11/Xatom.h>
-
-typedef struct _GdkIOClosure GdkIOClosure;
-typedef struct _GdkDisplaySource GdkDisplaySource;
-typedef struct _GdkEventTypeX11 GdkEventTypeX11;
-
-typedef union _GdkNotifyEvent GdkNotifyEvent;
-
-struct _GdkIOClosure
-{
- GdkInputFunction function;
- GdkInputCondition condition;
- GDestroyNotify notify;
- gpointer data;
-};
-
-struct _GdkDisplaySource
-{
- GSource source;
-
- GdkDisplay *display;
- GPollFD event_poll_fd;
-};
-
-struct _GdkEventTypeX11
-{
- gint base;
- gint n_events;
-};
-
-union _GdkNotifyEvent
-{
- XEvent xevent;
- XFixesSelectionNotifyEvent selection_notify;
- XDamageNotifyEvent damage_event;
-};
-
-/*
- * Private function declarations
- */
-
-static gint gdk_event_apply_filters (XEvent *xevent,
- GdkEvent *event,
- GList *filters);
-static gboolean gdk_event_translate (GdkDisplay *display,
- GdkEvent *event,
- XEvent *xevent,
- gboolean return_exposes);
-
-static gboolean gdk_event_prepare (GSource *source,
- gint *timeout);
-static gboolean gdk_event_check (GSource *source);
-static gboolean gdk_event_dispatch (GSource *source,
- GSourceFunc callback,
- gpointer user_data);
-
-static GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
- GdkEvent *event,
- gpointer data);
-
-static GSource *gdk_display_source_new (GdkDisplay *display);
-static gboolean gdk_check_xpending (GdkDisplay *display);
-
-static Bool gdk_xsettings_watch_cb (Window window,
- Bool is_start,
- long mask,
- void *cb_data);
-static void gdk_xsettings_notify_cb (const char *name,
- XSettingsAction action,
- XSettingsSetting *setting,
- void *data);
-
-/* Private variable declarations
- */
-
-static GList *display_sources;
-
-static GSourceFuncs event_funcs = {
- gdk_event_prepare,
- gdk_event_check,
- gdk_event_dispatch,
- NULL
-};
-
-static GSource *
-gdk_display_source_new (GdkDisplay *display)
-{
- GSource *source = g_source_new (&event_funcs, sizeof (GdkDisplaySource));
- GdkDisplaySource *display_source = (GdkDisplaySource *)source;
-
- display_source->display = display;
-
- return source;
-}
-
-static gboolean
-gdk_check_xpending (GdkDisplay *display)
-{
- return XPending (GDK_DISPLAY_XDISPLAY (display));
-}
-
-/*********************************************
- * Functions for maintaining the event queue *
- *********************************************/
-
-static void
-refcounted_grab_server (Display *xdisplay)
-{
- GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
-
- gdk_x11_display_grab (display);
-}
-
-static void
-refcounted_ungrab_server (Display *xdisplay)
-{
- GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
-
- gdk_x11_display_ungrab (display);
-}
-
-void
-_gdk_x11_events_init_screen (GdkScreen *screen)
-{
- GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
-
- /* Keep a flag to avoid extra notifies that we don't need
- */
- screen_x11->xsettings_in_init = TRUE;
- screen_x11->xsettings_client = xsettings_client_new_with_grab_funcs (screen_x11->xdisplay,
- screen_x11->screen_num,
- gdk_xsettings_notify_cb,
- gdk_xsettings_watch_cb,
- screen,
- refcounted_grab_server,
- refcounted_ungrab_server);
- screen_x11->xsettings_in_init = FALSE;
-}
-
-void
-_gdk_x11_events_uninit_screen (GdkScreen *screen)
-{
- GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
-
- if (screen_x11->xsettings_client)
- {
- xsettings_client_destroy (screen_x11->xsettings_client);
- screen_x11->xsettings_client = NULL;
- }
-}
-
-void
-_gdk_events_init (GdkDisplay *display)
-{
- GSource *source;
- GdkDisplaySource *display_source;
- GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
-
- int connection_number = ConnectionNumber (display_x11->xdisplay);
- GDK_NOTE (MISC, g_message ("connection number: %d", connection_number));
-
-
- source = display_x11->event_source = gdk_display_source_new (display);
- display_source = (GdkDisplaySource*) source;
- g_source_set_priority (source, GDK_PRIORITY_EVENTS);
-
- display_source->event_poll_fd.fd = connection_number;
- display_source->event_poll_fd.events = G_IO_IN;
-
- g_source_add_poll (source, &display_source->event_poll_fd);
- g_source_set_can_recurse (source, TRUE);
- g_source_attach (source, NULL);
-
- display_sources = g_list_prepend (display_sources,display_source);
-
- gdk_display_add_client_message_filter (display,
- gdk_atom_intern_static_string ("WM_PROTOCOLS"),
- gdk_wm_protocols_filter,
- NULL);
-}
-
-void
-_gdk_events_uninit (GdkDisplay *display)
-{
- GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
-
- if (display_x11->event_source)
- {
- display_sources = g_list_remove (display_sources,
- display_x11->event_source);
- g_source_destroy (display_x11->event_source);
- g_source_unref (display_x11->event_source);
- display_x11->event_source = NULL;
- }
-}
-
-/**
- * gdk_events_pending:
- *
- * Checks if any events are ready to be processed for any display.
- *
- * Return value: %TRUE if any events are pending.
- **/
-gboolean
-gdk_events_pending (void)
-{
- GList *tmp_list;
-
- for (tmp_list = display_sources; tmp_list; tmp_list = tmp_list->next)
- {
- GdkDisplaySource *tmp_source = tmp_list->data;
- GdkDisplay *display = tmp_source->display;
-
- if (_gdk_event_queue_find_first (display))
- return TRUE;
- }
-
- for (tmp_list = display_sources; tmp_list; tmp_list = tmp_list->next)
- {
- GdkDisplaySource *tmp_source = tmp_list->data;
- GdkDisplay *display = tmp_source->display;
-
- if (gdk_check_xpending (display))
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gint
-gdk_event_apply_filters (XEvent *xevent,
- GdkEvent *event,
- GList *filters)
-{
- GList *tmp_list;
- GdkFilterReturn result;
-
- tmp_list = filters;
-
- while (tmp_list)
- {
- GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
-
- tmp_list = tmp_list->next;
- result = filter->function (xevent, event, filter->data);
- if (result != GDK_FILTER_CONTINUE)
- return result;
- }
-
- return GDK_FILTER_CONTINUE;
-}
-
-/**
- * gdk_display_add_client_message_filter:
- * @display: a #GdkDisplay for which this message filter applies
- * @message_type: the type of ClientMessage events to receive.
- * This will be checked against the @message_type field
- * of the XClientMessage event struct.
- * @func: the function to call to process the event.
- * @data: user data to pass to @func.
- *
- * Adds a filter to be called when X ClientMessage events are received.
- * See gdk_window_add_filter() if you are interested in filtering other
- * types of events.
- *
- * Since: 2.2
- **/
-void
-gdk_display_add_client_message_filter (GdkDisplay *display,
- GdkAtom message_type,
- GdkFilterFunc func,
- gpointer data)
-{
- GdkClientFilter *filter;
- g_return_if_fail (GDK_IS_DISPLAY (display));
- filter = g_new (GdkClientFilter, 1);
-
- filter->type = message_type;
- filter->function = func;
- filter->data = data;
-
- GDK_DISPLAY_X11(display)->client_filters =
- g_list_append (GDK_DISPLAY_X11 (display)->client_filters,
- filter);
-}
-
-/**
- * gdk_add_client_message_filter:
- * @message_type: the type of ClientMessage events to receive. This will be
- * checked against the <structfield>message_type</structfield> field of the
- * XClientMessage event struct.
- * @func: the function to call to process the event.
- * @data: user data to pass to @func.
- *
- * Adds a filter to the default display to be called when X ClientMessage events
- * are received. See gdk_display_add_client_message_filter().
- **/
-void
-gdk_add_client_message_filter (GdkAtom message_type,
- GdkFilterFunc func,
- gpointer data)
-{
- gdk_display_add_client_message_filter (gdk_display_get_default (),
- message_type, func, data);
-}
-
-static void
-do_net_wm_state_changes (GdkWindow *window)
-{
- GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
- GdkWindowState old_state;
-
- if (GDK_WINDOW_DESTROYED (window) ||
- gdk_window_get_window_type (window) != GDK_WINDOW_TOPLEVEL)
- return;
-
- old_state = gdk_window_get_state (window);
-
- /* For found_sticky to remain TRUE, we have to also be on desktop
- * 0xFFFFFFFF
- */
- if (old_state & GDK_WINDOW_STATE_STICKY)
- {
- if (!(toplevel->have_sticky && toplevel->on_all_desktops))
- gdk_synthesize_window_state (window,
- GDK_WINDOW_STATE_STICKY,
- 0);
- }
- else
- {
- if (toplevel->have_sticky || toplevel->on_all_desktops)
- gdk_synthesize_window_state (window,
- 0,
- GDK_WINDOW_STATE_STICKY);
- }
-
- if (old_state & GDK_WINDOW_STATE_FULLSCREEN)
- {
- if (!toplevel->have_fullscreen)
- gdk_synthesize_window_state (window,
- GDK_WINDOW_STATE_FULLSCREEN,
- 0);
- }
- else
- {
- if (toplevel->have_fullscreen)
- gdk_synthesize_window_state (window,
- 0,
- GDK_WINDOW_STATE_FULLSCREEN);
- }
-
- /* Our "maximized" means both vertical and horizontal; if only one,
- * we don't expose that via GDK
- */
- if (old_state & GDK_WINDOW_STATE_MAXIMIZED)
- {
- if (!(toplevel->have_maxvert && toplevel->have_maxhorz))
- gdk_synthesize_window_state (window,
- GDK_WINDOW_STATE_MAXIMIZED,
- 0);
- }
- else
- {
- if (toplevel->have_maxvert && toplevel->have_maxhorz)
- gdk_synthesize_window_state (window,
- 0,
- GDK_WINDOW_STATE_MAXIMIZED);
- }
-}
-
-static void
-gdk_check_wm_desktop_changed (GdkWindow *window)
-{
- GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
- GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
-
- Atom type;
- gint format;
- gulong nitems;
- gulong bytes_after;
- guchar *data;
- gulong *desktop;
-
- type = None;
- gdk_error_trap_push ();
- XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
- GDK_WINDOW_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"),
- 0, G_MAXLONG, False, XA_CARDINAL, &type,
- &format, &nitems,
- &bytes_after, &data);
- gdk_error_trap_pop ();
-
- if (type != None)
- {
- desktop = (gulong *)data;
- toplevel->on_all_desktops = (*desktop == 0xFFFFFFFF);
- XFree (desktop);
- }
- else
- toplevel->on_all_desktops = FALSE;
-
- do_net_wm_state_changes (window);
-}
-
-static void
-gdk_check_wm_state_changed (GdkWindow *window)
-{
- GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
- GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
-
- Atom type;
- gint format;
- gulong nitems;
- gulong bytes_after;
- guchar *data;
- Atom *atoms = NULL;
- gulong i;
-
- gboolean had_sticky = toplevel->have_sticky;
-
- toplevel->have_sticky = FALSE;
- toplevel->have_maxvert = FALSE;
- toplevel->have_maxhorz = FALSE;
- toplevel->have_fullscreen = FALSE;
-
- type = None;
- gdk_error_trap_push ();
- XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
- 0, G_MAXLONG, False, XA_ATOM, &type, &format, &nitems,
- &bytes_after, &data);
- gdk_error_trap_pop ();
-
- if (type != None)
- {
- Atom sticky_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_STICKY");
- Atom maxvert_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT");
- Atom maxhorz_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ");
- Atom fullscreen_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_FULLSCREEN");
-
- atoms = (Atom *)data;
-
- i = 0;
- while (i < nitems)
- {
- if (atoms[i] == sticky_atom)
- toplevel->have_sticky = TRUE;
- else if (atoms[i] == maxvert_atom)
- toplevel->have_maxvert = TRUE;
- else if (atoms[i] == maxhorz_atom)
- toplevel->have_maxhorz = TRUE;
- else if (atoms[i] == fullscreen_atom)
- toplevel->have_fullscreen = TRUE;
-
- ++i;
- }
-
- XFree (atoms);
- }
-
- /* When have_sticky is turned on, we have to check the DESKTOP property
- * as well.
- */
- if (toplevel->have_sticky && !had_sticky)
- gdk_check_wm_desktop_changed (window);
- else
- do_net_wm_state_changes (window);
-}
-
-#define HAS_FOCUS(toplevel) \
- ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
-
-static void
-generate_focus_event (GdkWindow *window,
- gboolean in)
-{
- GdkEvent event;
-
- event.type = GDK_FOCUS_CHANGE;
- event.focus_change.window = window;
- event.focus_change.send_event = FALSE;
- event.focus_change.in = in;
-
- gdk_event_put (&event);
-}
-
-static gboolean
-set_screen_from_root (GdkDisplay *display,
- GdkEvent *event,
- Window xrootwin)
-{
- GdkScreen *screen;
-
- screen = _gdk_x11_display_screen_for_xrootwin (display, xrootwin);
-
- if (screen)
- {
- gdk_event_set_screen (event, screen);
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-translate_key_event (GdkDisplay *display,
- GdkEvent *event,
- XEvent *xevent)
-{
- GdkKeymap *keymap = gdk_keymap_get_for_display (display);
- gunichar c = 0;
- gchar buf[7];
- GdkModifierType consumed, state;
-
- event->key.type = xevent->xany.type == KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
- event->key.time = xevent->xkey.time;
-
- event->key.state = (GdkModifierType) xevent->xkey.state;
- event->key.group = _gdk_x11_get_group_for_state (display, xevent->xkey.state);
- event->key.hardware_keycode = xevent->xkey.keycode;
-
- event->key.keyval = GDK_VoidSymbol;
-
- gdk_keymap_translate_keyboard_state (keymap,
- event->key.hardware_keycode,
- event->key.state,
- event->key.group,
- &event->key.keyval,
- NULL, NULL, &consumed);
- state = event->key.state & ~consumed;
- _gdk_keymap_add_virtual_modifiers_compat (keymap, &state);
- event->key.state |= state;
-
- event->key.is_modifier = _gdk_keymap_key_is_modifier (keymap, event->key.hardware_keycode);
-
- /* Fill in event->string crudely, since various programs
- * depend on it.
- */
- event->key.string = NULL;
-
- if (event->key.keyval != GDK_VoidSymbol)
- c = gdk_keyval_to_unicode (event->key.keyval);
-
- if (c)
- {
- gsize bytes_written;
- gint len;
-
- /* Apply the control key - Taken from Xlib
- */
- if (event->key.state & GDK_CONTROL_MASK)
- {
- if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
- else if (c == '2')
- {
- event->key.string = g_memdup ("\0\0", 2);
- event->key.length = 1;
- buf[0] = '\0';
- goto out;
- }
- else if (c >= '3' && c <= '7') c -= ('3' - '\033');
- else if (c == '8') c = '\177';
- else if (c == '/') c = '_' & 0x1F;
- }
-
- len = g_unichar_to_utf8 (c, buf);
- buf[len] = '\0';
-
- event->key.string = g_locale_from_utf8 (buf, len,
- NULL, &bytes_written,
- NULL);
- if (event->key.string)
- event->key.length = bytes_written;
- }
- else if (event->key.keyval == GDK_Escape)
- {
- event->key.length = 1;
- event->key.string = g_strdup ("\033");
- }
- else if (event->key.keyval == GDK_Return ||
- event->key.keyval == GDK_KP_Enter)
- {
- event->key.length = 1;
- event->key.string = g_strdup ("\r");
- }
-
- if (!event->key.string)
- {
- event->key.length = 0;
- event->key.string = g_strdup ("");
- }
-
- out:
-#ifdef G_ENABLE_DEBUG
- if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
- {
- g_message ("%s:\t\twindow: %ld key: %12s %d",
- event->type == GDK_KEY_PRESS ? "key press " : "key release",
- xevent->xkey.window,
- event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
- event->key.keyval);
-
- if (event->key.length > 0)
- g_message ("\t\tlength: %4d string: \"%s\"",
- event->key.length, buf);
- }
-#endif /* G_ENABLE_DEBUG */
- return;
-}
-
-/**
- * gdk_x11_register_standard_event_type:
- * @display: a #GdkDisplay
- * @event_base: first event type code to register
- * @n_events: number of event type codes to register
- *
- * Registers interest in receiving extension events with type codes
- * between @event_base and <literal>event_base + n_events - 1</literal>.
- * The registered events must have the window field in the same place
- * as core X events (this is not the case for e.g. XKB extension events).
- *
- * If an event type is registered, events of this type will go through
- * global and window-specific filters (see gdk_window_add_filter()).
- * Unregistered events will only go through global filters.
- * GDK may register the events of some X extensions on its own.
- *
- * This function should only be needed in unusual circumstances, e.g.
- * when filtering XInput extension events on the root window.
- *
- * Since: 2.4
- **/
-void
-gdk_x11_register_standard_event_type (GdkDisplay *display,
- gint event_base,
- gint n_events)
-{
- GdkEventTypeX11 *event_type;
- GdkDisplayX11 *display_x11;
-
- display_x11 = GDK_DISPLAY_X11 (display);
- event_type = g_new (GdkEventTypeX11, 1);
-
- event_type->base = event_base;
- event_type->n_events = n_events;
-
- display_x11->event_types = g_slist_prepend (display_x11->event_types, event_type);
-}
-
-/* Return the window this has to do with, if any, rather
- * than the frame or root window that was selecting
- * for substructure
- */
-static void
-get_real_window (GdkDisplay *display,
- XEvent *event,
- Window *event_window,
- Window *filter_window)
-{
- /* Core events all have an event->xany.window field, but that's
- * not true for extension events
- */
- if (event->type >= KeyPress &&
- event->type <= MappingNotify)
- {
- *filter_window = event->xany.window;
- switch (event->type)
- {
- case CreateNotify:
- *event_window = event->xcreatewindow.window;
- break;
- case DestroyNotify:
- *event_window = event->xdestroywindow.window;
- break;
- case UnmapNotify:
- *event_window = event->xunmap.window;
- break;
- case MapNotify:
- *event_window = event->xmap.window;
- break;
- case MapRequest:
- *event_window = event->xmaprequest.window;
- break;
- case ReparentNotify:
- *event_window = event->xreparent.window;
- break;
- case ConfigureNotify:
- *event_window = event->xconfigure.window;
- break;
- case ConfigureRequest:
- *event_window = event->xconfigurerequest.window;
- break;
- case GravityNotify:
- *event_window = event->xgravity.window;
- break;
- case CirculateNotify:
- *event_window = event->xcirculate.window;
- break;
- case CirculateRequest:
- *event_window = event->xcirculaterequest.window;
- break;
- default:
- *event_window = event->xany.window;
- }
- }
- else
- {
- GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
- GSList *tmp_list;
-
- for (tmp_list = display_x11->event_types;
- tmp_list;
- tmp_list = tmp_list->next)
- {
- GdkEventTypeX11 *event_type = tmp_list->data;
-
- if (event->type >= event_type->base &&
- event->type < event_type->base + event_type->n_events)
- {
- *event_window = event->xany.window;
- *filter_window = event->xany.window;
- return;
- }
- }
-
- *event_window = None;
- *filter_window = None;
- }
-}
-
-#ifdef G_ENABLE_DEBUG
-static const char notify_modes[][19] = {
- "NotifyNormal",
- "NotifyGrab",
- "NotifyUngrab",
- "NotifyWhileGrabbed"
-};
-
-static const char notify_details[][23] = {
- "NotifyAncestor",
- "NotifyVirtual",
- "NotifyInferior",
- "NotifyNonlinear",
- "NotifyNonlinearVirtual",
- "NotifyPointer",
- "NotifyPointerRoot",
- "NotifyDetailNone"
-};
-#endif
-
-static void
-set_user_time (GdkWindow *window,
- GdkEvent *event)
-{
- g_return_if_fail (event != NULL);
-
- window = gdk_window_get_toplevel (event->client.window);
- g_return_if_fail (GDK_IS_WINDOW (window));
-
- /* If an event doesn't have a valid timestamp, we shouldn't use it
- * to update the latest user interaction time.
- */
- if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
- gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
- gdk_event_get_time (event));
-}
-
-static gboolean
-is_parent_of (GdkWindow *parent,
- GdkWindow *child)
-{
- GdkWindow *w;
-
- w = child;
- while (w != NULL)
- {
- if (w == parent)
- return TRUE;
-
- w = gdk_window_get_parent (w);
- }
-
- return FALSE;
-}
-
-static gboolean
-gdk_event_translate (GdkDisplay *display,
- GdkEvent *event,
- XEvent *xevent,
- gboolean return_exposes)
-{
- GdkNotifyEvent *notify_event;
- GdkWindow *window;
- GdkWindowObject *window_private;
- GdkWindow *filter_window;
- GdkWindowImplX11 *window_impl = NULL;
- gboolean return_val;
- GdkScreen *screen = NULL;
- GdkScreenX11 *screen_x11 = NULL;
- GdkToplevelX11 *toplevel = NULL;
- GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
- Window xwindow, filter_xwindow;
-
- return_val = FALSE;
-
- /* init these, since the done: block uses them */
- window = NULL;
- window_private = NULL;
- event->any.window = NULL;
-
- if (_gdk_default_filters)
- {
- /* Apply global filters */
- GdkFilterReturn result;
- result = gdk_event_apply_filters (xevent, event,
- _gdk_default_filters);
-
- if (result != GDK_FILTER_CONTINUE)
- {
- return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
- goto done;
- }
- }
-
- /* Find the GdkWindow that this event relates to.
- * Basically this means substructure events
- * are reported same as structure events
- */
- get_real_window (display, xevent, &xwindow, &filter_xwindow);
-
- window = gdk_window_lookup_for_display (display, xwindow);
- /* We may receive events such as NoExpose/GraphicsExpose
- * and ShmCompletion for pixmaps
- */
- if (window && !GDK_IS_WINDOW (window))
- window = NULL;
- window_private = (GdkWindowObject *) window;
-
- /* We always run the filters for the window where the event
- * is delivered, not the window that it relates to
- */
- if (filter_xwindow == xwindow)
- filter_window = window;
- else
- {
- filter_window = gdk_window_lookup_for_display (display, filter_xwindow);
- if (filter_window && !GDK_IS_WINDOW (filter_window))
- filter_window = NULL;
- }
-
- if (window)
- {
- screen = GDK_WINDOW_SCREEN (window);
- screen_x11 = GDK_SCREEN_X11 (screen);
- toplevel = _gdk_x11_window_get_toplevel (window);
- }
-
- if (window != NULL)
- {
- /* Apply keyboard grabs to non-native windows */
- if (/* Is key event */
- (xevent->type == KeyPress || xevent->type == KeyRelease) &&
- /* And we have a grab */
- display->keyboard_grab.window != NULL &&
- (
- /* The window is not a descendant of the grabbed window */
- !is_parent_of ((GdkWindow *)display->keyboard_grab.window, window) ||
- /* Or owner event is false */
- !display->keyboard_grab.owner_events
- )
- )
- {
- /* Report key event against grab window */
- window = display->keyboard_grab.window;;
- window_private = (GdkWindowObject *) window;
- }
-
- window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
-
- /* Move key events on focus window to the real toplevel, and
- * filter out all other events on focus window
- */
- if (toplevel && xwindow == toplevel->focus_window)
- {
- switch (xevent->type)
- {
- case KeyPress:
- case KeyRelease:
- xwindow = GDK_WINDOW_XID (window);
- xevent->xany.window = xwindow;
- break;
- default:
- return FALSE;
- }
- }
-
- g_object_ref (window);
- }
-
- event->any.window = window;
- event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
-
- if (window_private && GDK_WINDOW_DESTROYED (window))
- {
- if (xevent->type != DestroyNotify)
- {
- return_val = FALSE;
- goto done;
- }
- }
- else if (filter_window)
- {
- /* Apply per-window filters */
- GdkWindowObject *filter_private = (GdkWindowObject *) filter_window;
- GdkFilterReturn result;
-
- if (filter_private->filters)
- {
- g_object_ref (filter_window);
-
- result = gdk_event_apply_filters (xevent, event,
- filter_private->filters);
-
- g_object_unref (filter_window);
-
- if (result != GDK_FILTER_CONTINUE)
- {
- return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
- goto done;
- }
- }
- }
-
- if (xevent->type == DestroyNotify)
- {
- int i, n;
-
- n = gdk_display_get_n_screens (display);
- for (i = 0; i < n; i++)
- {
- screen = gdk_display_get_screen (display, i);
- screen_x11 = GDK_SCREEN_X11 (screen);
-
- if (screen_x11->wmspec_check_window == xwindow)
- {
- screen_x11->wmspec_check_window = None;
- screen_x11->last_wmspec_check_time = 0;
- g_free (screen_x11->window_manager_name);
- screen_x11->window_manager_name = g_strdup ("unknown");
-
- /* careful, reentrancy */
- _gdk_x11_screen_window_manager_changed (screen);
-
- return_val = FALSE;
- goto done;
- }
- }
- }
-
- if (window &&
- (xevent->xany.type == MotionNotify ||
- xevent->xany.type == ButtonRelease))
- {
- if (_gdk_moveresize_handle_event (xevent))
- {
- return_val = FALSE;
- goto done;
- }
- }
-
- /* We do a "manual" conversion of the XEvent to a
- * GdkEvent. The structures are mostly the same so
- * the conversion is fairly straightforward. We also
- * optionally print debugging info regarding events
- * received.
- */
-
- return_val = TRUE;
-
- switch (xevent->type)
- {
- case KeyPress:
- if (window_private == NULL)
- {
- return_val = FALSE;
- break;
- }
- translate_key_event (display, event, xevent);
- set_user_time (window, event);
- break;
-
- case KeyRelease:
- if (window_private == NULL)
- {
- return_val = FALSE;
- break;
- }
-
- /* Emulate detectable auto-repeat by checking to see
- * if the next event is a key press with the same
- * keycode and timestamp, and if so, ignoring the event.
- */
-
- if (!display_x11->have_xkb_autorepeat && XPending (xevent->xkey.display))
- {
- XEvent next_event;
-
- XPeekEvent (xevent->xkey.display, &next_event);
-
- if (next_event.type == KeyPress &&
- next_event.xkey.keycode == xevent->xkey.keycode &&
- next_event.xkey.time == xevent->xkey.time)
- {
- return_val = FALSE;
- break;
- }
- }
-
- translate_key_event (display, event, xevent);
- break;
-
- case ButtonPress:
- GDK_NOTE (EVENTS,
- g_message ("button press:\t\twindow: %ld x,y: %d %d button: %d",
- xevent->xbutton.window,
- xevent->xbutton.x, xevent->xbutton.y,
- xevent->xbutton.button));
-
- if (window_private == NULL)
- {
- return_val = FALSE;
- break;
- }
-
- /* If we get a ButtonPress event where the button is 4 or 5,
- it's a Scroll event */
- switch (xevent->xbutton.button)
- {
- case 4: /* up */
- case 5: /* down */
- case 6: /* left */
- case 7: /* right */
- event->scroll.type = GDK_SCROLL;
-
- if (xevent->xbutton.button == 4)
- event->scroll.direction = GDK_SCROLL_UP;
- else if (xevent->xbutton.button == 5)
- event->scroll.direction = GDK_SCROLL_DOWN;
- else if (xevent->xbutton.button == 6)
- event->scroll.direction = GDK_SCROLL_LEFT;
- else
- event->scroll.direction = GDK_SCROLL_RIGHT;
-
- event->scroll.window = window;
- event->scroll.time = xevent->xbutton.time;
- event->scroll.x = xevent->xbutton.x;
- event->scroll.y = xevent->xbutton.y;
- event->scroll.x_root = (gfloat)xevent->xbutton.x_root;
- event->scroll.y_root = (gfloat)xevent->xbutton.y_root;
- event->scroll.state = (GdkModifierType) xevent->xbutton.state;
- event->scroll.device = display->core_pointer;
-
- if (!set_screen_from_root (display, event, xevent->xbutton.root))
- {
- return_val = FALSE;
- break;
- }
-
- break;
-
- default:
- event->button.type = GDK_BUTTON_PRESS;
- event->button.window = window;
- event->button.time = xevent->xbutton.time;
- event->button.x = xevent->xbutton.x;
- event->button.y = xevent->xbutton.y;
- event->button.x_root = (gfloat)xevent->xbutton.x_root;
- event->button.y_root = (gfloat)xevent->xbutton.y_root;
- event->button.axes = NULL;
- event->button.state = (GdkModifierType) xevent->xbutton.state;
- event->button.button = xevent->xbutton.button;
- event->button.device = display->core_pointer;
-
- if (!set_screen_from_root (display, event, xevent->xbutton.root))
- {
- return_val = FALSE;
- break;
- }
- break;
- }
-
- set_user_time (window, event);
-
- break;
-
- case ButtonRelease:
- GDK_NOTE (EVENTS,
- g_message ("button release:\twindow: %ld x,y: %d %d button: %d",
- xevent->xbutton.window,
- xevent->xbutton.x, xevent->xbutton.y,
- xevent->xbutton.button));
-
- if (window_private == NULL)
- {
- return_val = FALSE;
- break;
- }
-
- /* We treat button presses as scroll wheel events, so ignore the release */
- if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 ||
- xevent->xbutton.button == 6 || xevent->xbutton.button ==7)
- {
- return_val = FALSE;
- break;
- }
-
- event->button.type = GDK_BUTTON_RELEASE;
- event->button.window = window;
- event->button.time = xevent->xbutton.time;
- event->button.x = xevent->xbutton.x;
- event->button.y = xevent->xbutton.y;
- event->button.x_root = (gfloat)xevent->xbutton.x_root;
- event->button.y_root = (gfloat)xevent->xbutton.y_root;
- event->button.axes = NULL;
- event->button.state = (GdkModifierType) xevent->xbutton.state;
- event->button.button = xevent->xbutton.button;
- event->button.device = display->core_pointer;
-
- if (!set_screen_from_root (display, event, xevent->xbutton.root))
- return_val = FALSE;
-
- break;
-
- case MotionNotify:
- GDK_NOTE (EVENTS,
- g_message ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s",
- xevent->xmotion.window,
- xevent->xmotion.x, xevent->xmotion.y,
- (xevent->xmotion.is_hint) ? "true" : "false"));
-
- if (window_private == NULL)
- {
- return_val = FALSE;
- break;
- }
-
- event->motion.type = GDK_MOTION_NOTIFY;
- event->motion.window = window;
- event->motion.time = xevent->xmotion.time;
- event->motion.x = xevent->xmotion.x;
- event->motion.y = xevent->xmotion.y;
- event->motion.x_root = (gfloat)xevent->xmotion.x_root;
- event->motion.y_root = (gfloat)xevent->xmotion.y_root;
- event->motion.axes = NULL;
- event->motion.state = (GdkModifierType) xevent->xmotion.state;
- event->motion.is_hint = xevent->xmotion.is_hint;
- event->motion.device = display->core_pointer;
-
- if (!set_screen_from_root (display, event, xevent->xbutton.root))
- {
- return_val = FALSE;
- break;
- }
-
- break;
-
- case EnterNotify:
- GDK_NOTE (EVENTS,
- g_message ("enter notify:\t\twindow: %ld detail: %d subwin: %ld mode: %d",
- xevent->xcrossing.window,
- xevent->xcrossing.detail,
- xevent->xcrossing.subwindow,
- xevent->xcrossing.mode));
-
- if (window_private == NULL)
- {
- return_val = FALSE;
- break;
- }
-
- if (!set_screen_from_root (display, event, xevent->xbutton.root))
- {
- return_val = FALSE;
- break;
- }
-
- /* Handle focusing (in the case where no window manager is running */
- if (toplevel && xevent->xcrossing.detail != NotifyInferior)
- {
- toplevel->has_pointer = TRUE;
-
- if (xevent->xcrossing.focus && !toplevel->has_focus_window)
- {
- gboolean had_focus = HAS_FOCUS (toplevel);
-
- toplevel->has_pointer_focus = TRUE;
-
- if (HAS_FOCUS (toplevel) != had_focus)
- generate_focus_event (window, TRUE);
- }
- }
-
- event->crossing.type = GDK_ENTER_NOTIFY;
- event->crossing.window = window;
-
- /* If the subwindow field of the XEvent is non-NULL, then
- * lookup the corresponding GdkWindow.
- */
- if (xevent->xcrossing.subwindow != None)
- event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow);
- else
- event->crossing.subwindow = NULL;
-
- event->crossing.time = xevent->xcrossing.time;
- event->crossing.x = xevent->xcrossing.x;
- event->crossing.y = xevent->xcrossing.y;
- event->crossing.x_root = xevent->xcrossing.x_root;
- event->crossing.y_root = xevent->xcrossing.y_root;
-
- /* Translate the crossing mode into Gdk terms.
- */
- switch (xevent->xcrossing.mode)
- {
- case NotifyNormal:
- event->crossing.mode = GDK_CROSSING_NORMAL;
- break;
- case NotifyGrab:
- event->crossing.mode = GDK_CROSSING_GRAB;
- break;
- case NotifyUngrab:
- event->crossing.mode = GDK_CROSSING_UNGRAB;
- break;
- };
-
- /* Translate the crossing detail into Gdk terms.
- */
- switch (xevent->xcrossing.detail)
- {
- case NotifyInferior:
- event->crossing.detail = GDK_NOTIFY_INFERIOR;
- break;
- case NotifyAncestor:
- event->crossing.detail = GDK_NOTIFY_ANCESTOR;
- break;
- case NotifyVirtual:
- event->crossing.detail = GDK_NOTIFY_VIRTUAL;
- break;
- case NotifyNonlinear:
- event->crossing.detail = GDK_NOTIFY_NONLINEAR;
- break;
- case NotifyNonlinearVirtual:
- event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
- break;
- default:
- event->crossing.detail = GDK_NOTIFY_UNKNOWN;
- break;
- }
-
- event->crossing.focus = xevent->xcrossing.focus;
- event->crossing.state = xevent->xcrossing.state;
-
- break;
-
- case LeaveNotify:
- GDK_NOTE (EVENTS,
- g_message ("leave notify:\t\twindow: %ld detail: %d subwin: %ld mode: %d",
- xevent->xcrossing.window,
- xevent->xcrossing.detail,
- xevent->xcrossing.subwindow,
- xevent->xcrossing.mode));
-
- if (window_private == NULL)
- {
- return_val = FALSE;
- break;
- }
-
- if (!set_screen_from_root (display, event, xevent->xbutton.root))
- {
- return_val = FALSE;
- break;
- }
-
- /* Handle focusing (in the case where no window manager is running */
- if (toplevel && xevent->xcrossing.detail != NotifyInferior)
- {
- toplevel->has_pointer = FALSE;
-
- if (xevent->xcrossing.focus && !toplevel->has_focus_window)
- {
- gboolean had_focus = HAS_FOCUS (toplevel);
-
- toplevel->has_pointer_focus = FALSE;
-
- if (HAS_FOCUS (toplevel) != had_focus)
- generate_focus_event (window, FALSE);
- }
- }
-
- event->crossing.type = GDK_LEAVE_NOTIFY;
- event->crossing.window = window;
-
- /* If the subwindow field of the XEvent is non-NULL, then
- * lookup the corresponding GdkWindow.
- */
- if (xevent->xcrossing.subwindow != None)
- event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow);
- else
- event->crossing.subwindow = NULL;
-
- event->crossing.time = xevent->xcrossing.time;
- event->crossing.x = xevent->xcrossing.x;
- event->crossing.y = xevent->xcrossing.y;
- event->crossing.x_root = xevent->xcrossing.x_root;
- event->crossing.y_root = xevent->xcrossing.y_root;
-
- /* Translate the crossing mode into Gdk terms.
- */
- switch (xevent->xcrossing.mode)
- {
- case NotifyNormal:
- event->crossing.mode = GDK_CROSSING_NORMAL;
- break;
- case NotifyGrab:
- event->crossing.mode = GDK_CROSSING_GRAB;
- break;
- case NotifyUngrab:
- event->crossing.mode = GDK_CROSSING_UNGRAB;
- break;
- };
-
- /* Translate the crossing detail into Gdk terms.
- */
- switch (xevent->xcrossing.detail)
- {
- case NotifyInferior:
- event->crossing.detail = GDK_NOTIFY_INFERIOR;
- break;
- case NotifyAncestor:
- event->crossing.detail = GDK_NOTIFY_ANCESTOR;
- break;
- case NotifyVirtual:
- event->crossing.detail = GDK_NOTIFY_VIRTUAL;
- break;
- case NotifyNonlinear:
- event->crossing.detail = GDK_NOTIFY_NONLINEAR;
- break;
- case NotifyNonlinearVirtual:
- event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
- break;
- default:
- event->crossing.detail = GDK_NOTIFY_UNKNOWN;
- break;
- }
-
- event->crossing.focus = xevent->xcrossing.focus;
- event->crossing.state = xevent->xcrossing.state;
-
- break;
-
- /* We only care about focus events that indicate that _this_
- * window (not a ancestor or child) got or lost the focus
- */
- case FocusIn:
- GDK_NOTE (EVENTS,
- g_message ("focus in:\t\twindow: %ld, detail: %s, mode: %s",
- xevent->xfocus.window,
- notify_details[xevent->xfocus.detail],
- notify_modes[xevent->xfocus.mode]));
-
- if (toplevel)
- {
- gboolean had_focus = HAS_FOCUS (toplevel);
-
- switch (xevent->xfocus.detail)
- {
- case NotifyAncestor:
- case NotifyVirtual:
- /* When the focus moves from an ancestor of the window to
- * the window or a descendent of the window, *and* the
- * pointer is inside the window, then we were previously
- * receiving keystroke events in the has_pointer_focus
- * case and are now receiving them in the
- * has_focus_window case.
- */
- if (toplevel->has_pointer &&
- xevent->xfocus.mode != NotifyGrab &&
- xevent->xfocus.mode != NotifyUngrab)
- toplevel->has_pointer_focus = FALSE;
-
- /* fall through */
- case NotifyNonlinear:
- case NotifyNonlinearVirtual:
- if (xevent->xfocus.mode != NotifyGrab &&
- xevent->xfocus.mode != NotifyUngrab)
- toplevel->has_focus_window = TRUE;
- /* We pretend that the focus moves to the grab
- * window, so we pay attention to NotifyGrab
- * NotifyUngrab, and ignore NotifyWhileGrabbed
- */
- if (xevent->xfocus.mode != NotifyWhileGrabbed)
- toplevel->has_focus = TRUE;
- break;
- case NotifyPointer:
- /* The X server sends NotifyPointer/NotifyGrab,
- * but the pointer focus is ignored while a
- * grab is in effect
- */
- if (xevent->xfocus.mode != NotifyGrab &&
- xevent->xfocus.mode != NotifyUngrab)
- toplevel->has_pointer_focus = TRUE;
- break;
- case NotifyInferior:
- case NotifyPointerRoot:
- case NotifyDetailNone:
- break;
- }
-
- if (HAS_FOCUS (toplevel) != had_focus)
- generate_focus_event (window, TRUE);
- }
- break;
- case FocusOut:
- GDK_NOTE (EVENTS,
- g_message ("focus out:\t\twindow: %ld, detail: %s, mode: %s",
- xevent->xfocus.window,
- notify_details[xevent->xfocus.detail],
- notify_modes[xevent->xfocus.mode]));
-
- if (toplevel)
- {
- gboolean had_focus = HAS_FOCUS (toplevel);
-
- switch (xevent->xfocus.detail)
- {
- case NotifyAncestor:
- case NotifyVirtual:
- /* When the focus moves from the window or a descendent
- * of the window to an ancestor of the window, *and* the
- * pointer is inside the window, then we were previously
- * receiving keystroke events in the has_focus_window
- * case and are now receiving them in the
- * has_pointer_focus case.
- */
- if (toplevel->has_pointer &&
- xevent->xfocus.mode != NotifyGrab &&
- xevent->xfocus.mode != NotifyUngrab)
- toplevel->has_pointer_focus = TRUE;
-
- /* fall through */
- case NotifyNonlinear:
- case NotifyNonlinearVirtual:
- if (xevent->xfocus.mode != NotifyGrab &&
- xevent->xfocus.mode != NotifyUngrab)
- toplevel->has_focus_window = FALSE;
- if (xevent->xfocus.mode != NotifyWhileGrabbed)
- toplevel->has_focus = FALSE;
- break;
- case NotifyPointer:
- if (xevent->xfocus.mode != NotifyGrab &&
- xevent->xfocus.mode != NotifyUngrab)
- toplevel->has_pointer_focus = FALSE;
- break;
- case NotifyInferior:
- case NotifyPointerRoot:
- case NotifyDetailNone:
- break;
- }
-
- if (HAS_FOCUS (toplevel) != had_focus)
- generate_focus_event (window, FALSE);
- }
- break;
-
-#if 0
- /* gdk_keyboard_grab() causes following events. These events confuse
- * the XIM focus, so ignore them.
- */
- if (xevent->xfocus.mode == NotifyGrab ||
- xevent->xfocus.mode == NotifyUngrab)
- break;
-#endif
-
- case KeymapNotify:
- GDK_NOTE (EVENTS,
- g_message ("keymap notify"));
-
- /* Not currently handled */
- return_val = FALSE;
- break;
-
- case Expose:
- GDK_NOTE (EVENTS,
- g_message ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d%s",
- xevent->xexpose.window, xevent->xexpose.count,
- xevent->xexpose.x, xevent->xexpose.y,
- xevent->xexpose.width, xevent->xexpose.height,
- event->any.send_event ? " (send)" : ""));
-
- if (window_private == NULL)
- {
- return_val = FALSE;
- break;
- }
-
- {
- GdkRectangle expose_rect;
-
- expose_rect.x = xevent->xexpose.x;
- expose_rect.y = xevent->xexpose.y;
- expose_rect.width = xevent->xexpose.width;
- expose_rect.height = xevent->xexpose.height;
-
- _gdk_window_process_expose (window, xevent->xexpose.serial, &expose_rect);
- return_val = FALSE;
- }
-
- break;
-
- case GraphicsExpose:
- {
- GdkRectangle expose_rect;
-
- GDK_NOTE (EVENTS,
- g_message ("graphics expose:\tdrawable: %ld",
- xevent->xgraphicsexpose.drawable));
-
- if (window_private == NULL)
- {
- return_val = FALSE;
- break;
- }
-
- expose_rect.x = xevent->xgraphicsexpose.x;
- expose_rect.y = xevent->xgraphicsexpose.y;
- expose_rect.width = xevent->xgraphicsexpose.width;
- expose_rect.height = xevent->xgraphicsexpose.height;
-
- if (return_exposes)
- {
- event->expose.type = GDK_EXPOSE;
- event->expose.area = expose_rect;
- event->expose.region = gdk_region_rectangle (&expose_rect);
- event->expose.window = window;
- event->expose.count = xevent->xgraphicsexpose.count;
-
- return_val = TRUE;
- }
- else
- {
- _gdk_window_process_expose (window, xevent->xgraphicsexpose.serial, &expose_rect);
-
- return_val = FALSE;
- }
-
- }
- break;
-
- case NoExpose:
- GDK_NOTE (EVENTS,
- g_message ("no expose:\t\tdrawable: %ld",
- xevent->xnoexpose.drawable));
-
- event->no_expose.type = GDK_NO_EXPOSE;
- event->no_expose.window = window;
-
- break;
-
- case VisibilityNotify:
-#ifdef G_ENABLE_DEBUG
- if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
- switch (xevent->xvisibility.state)
- {
- case VisibilityFullyObscured:
- g_message ("visibility notify:\twindow: %ld none",
- xevent->xvisibility.window);
- break;
- case VisibilityPartiallyObscured:
- g_message ("visibility notify:\twindow: %ld partial",
- xevent->xvisibility.window);
- break;
- case VisibilityUnobscured:
- g_message ("visibility notify:\twindow: %ld full",
- xevent->xvisibility.window);
- break;
- }
-#endif /* G_ENABLE_DEBUG */
-
- if (window_private == NULL)
- {
- return_val = FALSE;
- break;
- }
-
- event->visibility.type = GDK_VISIBILITY_NOTIFY;
- event->visibility.window = window;
-
- switch (xevent->xvisibility.state)
- {
- case VisibilityFullyObscured:
- event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
- break;
-
- case VisibilityPartiallyObscured:
- event->visibility.state = GDK_VISIBILITY_PARTIAL;
- break;
-
- case VisibilityUnobscured:
- event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
- break;
- }
-
- break;
-
- case CreateNotify:
- GDK_NOTE (EVENTS,
- g_message ("create notify:\twindow: %ld x,y: %d %d w,h: %d %d b-w: %d parent: %ld ovr: %d",
- xevent->xcreatewindow.window,
- xevent->xcreatewindow.x,
- xevent->xcreatewindow.y,
- xevent->xcreatewindow.width,
- xevent->xcreatewindow.height,
- xevent->xcreatewindow.border_width,
- xevent->xcreatewindow.parent,
- xevent->xcreatewindow.override_redirect));
- /* not really handled */
- break;
-
- case DestroyNotify:
- GDK_NOTE (EVENTS,
- g_message ("destroy notify:\twindow: %ld",
- xevent->xdestroywindow.window));
-
- /* Ignore DestroyNotify from SubstructureNotifyMask */
- if (xevent->xdestroywindow.window == xevent->xdestroywindow.event)
- {
- event->any.type = GDK_DESTROY;
- event->any.window = window;
-
- return_val = window_private && !GDK_WINDOW_DESTROYED (window);
-
- if (window && GDK_WINDOW_XID (window) != screen_x11->xroot_window)
- gdk_window_destroy_notify (window);
- }
- else
- return_val = FALSE;
-
- break;
-
- case UnmapNotify:
- GDK_NOTE (EVENTS,
- g_message ("unmap notify:\t\twindow: %ld",
- xevent->xmap.window));
-
- event->any.type = GDK_UNMAP;
- event->any.window = window;
-
- /* If we are shown (not withdrawn) and get an unmap, it means we
- * were iconified in the X sense. If we are withdrawn, and get
- * an unmap, it means we hid the window ourselves, so we
- * will have already flipped the iconified bit off.
- */
- if (window)
- {
- if (GDK_WINDOW_IS_MAPPED (window))
- gdk_synthesize_window_state (window,
- 0,
- GDK_WINDOW_STATE_ICONIFIED);
-
- _gdk_xgrab_check_unmap (window, xevent->xany.serial);
- }
-
- break;
-
- case MapNotify:
- GDK_NOTE (EVENTS,
- g_message ("map notify:\t\twindow: %ld",
- xevent->xmap.window));
-
- event->any.type = GDK_MAP;
- event->any.window = window;
-
- /* Unset iconified if it was set */
- if (window && (((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_ICONIFIED))
- gdk_synthesize_window_state (window,
- GDK_WINDOW_STATE_ICONIFIED,
- 0);
-
- break;
-
- case ReparentNotify:
- GDK_NOTE (EVENTS,
- g_message ("reparent notify:\twindow: %ld x,y: %d %d parent: %ld ovr: %d",
- xevent->xreparent.window,
- xevent->xreparent.x,
- xevent->xreparent.y,
- xevent->xreparent.parent,
- xevent->xreparent.override_redirect));
-
- /* Not currently handled */
- return_val = FALSE;
- break;
-
- case ConfigureNotify:
- GDK_NOTE (EVENTS,
- g_message ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d b-w: %d above: %ld ovr: %d%s",
- xevent->xconfigure.window,
- xevent->xconfigure.x,
- xevent->xconfigure.y,
- xevent->xconfigure.width,
- xevent->xconfigure.height,
- xevent->xconfigure.border_width,
- xevent->xconfigure.above,
- xevent->xconfigure.override_redirect,
- !window
- ? " (discarding)"
- : GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD
- ? " (discarding child)"
- : xevent->xconfigure.event != xevent->xconfigure.window
- ? " (discarding substructure)"
- : ""));
- if (window && GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
- {
- window_private->width = xevent->xconfigure.width;
- window_private->height = xevent->xconfigure.height;
-
- _gdk_window_update_size (window);
- _gdk_x11_drawable_update_size (window_private->impl);
- _gdk_x11_screen_size_changed (screen, xevent);
- }
-
- if (window &&
- xevent->xconfigure.event == xevent->xconfigure.window &&
- !GDK_WINDOW_DESTROYED (window) &&
- window_private->input_window != NULL)
- _gdk_input_configure_event (&xevent->xconfigure, window);
-
-#ifdef HAVE_XSYNC
- if (toplevel && display_x11->use_sync && !XSyncValueIsZero (toplevel->pending_counter_value))
- {
- toplevel->current_counter_value = toplevel->pending_counter_value;
- XSyncIntToValue (&toplevel->pending_counter_value, 0);
- }
-#endif
-
- if (!window ||
- xevent->xconfigure.event != xevent->xconfigure.window ||
- GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD ||
- GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
- return_val = FALSE;
- else
- {
- event->configure.type = GDK_CONFIGURE;
- event->configure.window = window;
- event->configure.width = xevent->xconfigure.width;
- event->configure.height = xevent->xconfigure.height;
-
- if (!xevent->xconfigure.send_event &&
- !xevent->xconfigure.override_redirect &&
- !GDK_WINDOW_DESTROYED (window))
- {
- gint tx = 0;
- gint ty = 0;
- Window child_window = 0;
-
- gdk_error_trap_push ();
- if (XTranslateCoordinates (GDK_DRAWABLE_XDISPLAY (window),
- GDK_DRAWABLE_XID (window),
- screen_x11->xroot_window,
- 0, 0,
- &tx, &ty,
- &child_window))
- {
- event->configure.x = tx;
- event->configure.y = ty;
- }
- gdk_error_trap_pop ();
- }
- else
- {
- event->configure.x = xevent->xconfigure.x;
- event->configure.y = xevent->xconfigure.y;
- }
- window_private->x = event->configure.x;
- window_private->y = event->configure.y;
- window_private->width = xevent->xconfigure.width;
- window_private->height = xevent->xconfigure.height;
-
- _gdk_window_update_size (window);
- _gdk_x11_drawable_update_size (window_private->impl);
-
- if (window_private->resize_count >= 1)
- {
- window_private->resize_count -= 1;
-
- if (window_private->resize_count == 0)
- _gdk_moveresize_configure_done (display, window);
- }
- }
- break;
-
- case PropertyNotify:
- GDK_NOTE (EVENTS,
- g_message ("property notify:\twindow: %ld, atom(%ld): %s%s%s",
- xevent->xproperty.window,
- xevent->xproperty.atom,
- "\"",
- gdk_x11_get_xatom_name_for_display (display, xevent->xproperty.atom),
- "\""));
-
- if (window_private == NULL)
- {
- return_val = FALSE;
- break;
- }
-
- /* We compare with the serial of the last time we mapped the
- * window to avoid refetching properties that we set ourselves
- */
- if (toplevel &&
- xevent->xproperty.serial >= toplevel->map_serial)
- {
- if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"))
- gdk_check_wm_state_changed (window);
-
- if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"))
- gdk_check_wm_desktop_changed (window);
- }
-
- if (window_private->event_mask & GDK_PROPERTY_CHANGE_MASK)
- {
- event->property.type = GDK_PROPERTY_NOTIFY;
- event->property.window = window;
- event->property.atom = gdk_x11_xatom_to_atom_for_display (display, xevent->xproperty.atom);
- event->property.time = xevent->xproperty.time;
- event->property.state = xevent->xproperty.state;
- }
- else
- return_val = FALSE;
-
- break;
-
- case SelectionClear:
- GDK_NOTE (EVENTS,
- g_message ("selection clear:\twindow: %ld",
- xevent->xproperty.window));
-
- if (_gdk_selection_filter_clear_event (&xevent->xselectionclear))
- {
- event->selection.type = GDK_SELECTION_CLEAR;
- event->selection.window = window;
- event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionclear.selection);
- event->selection.time = xevent->xselectionclear.time;
- }
- else
- return_val = FALSE;
-
- break;
-
- case SelectionRequest:
- GDK_NOTE (EVENTS,
- g_message ("selection request:\twindow: %ld",
- xevent->xproperty.window));
-
- event->selection.type = GDK_SELECTION_REQUEST;
- event->selection.window = window;
- event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.selection);
- event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.target);
- event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.property);
- event->selection.requestor = xevent->xselectionrequest.requestor;
- event->selection.time = xevent->xselectionrequest.time;
-
- break;
-
- case SelectionNotify:
- GDK_NOTE (EVENTS,
- g_message ("selection notify:\twindow: %ld",
- xevent->xproperty.window));
-
-
- event->selection.type = GDK_SELECTION_NOTIFY;
- event->selection.window = window;
- event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.selection);
- event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.target);
- if (xevent->xselection.property == None)
- event->selection.property = GDK_NONE;
- else
- event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.property);
- event->selection.time = xevent->xselection.time;
-
- break;
-
- case ColormapNotify:
- GDK_NOTE (EVENTS,
- g_message ("colormap notify:\twindow: %ld",
- xevent->xcolormap.window));
-
- /* Not currently handled */
- return_val = FALSE;
- break;
-
- case ClientMessage:
- {
- GList *tmp_list;
- GdkFilterReturn result = GDK_FILTER_CONTINUE;
- GdkAtom message_type = gdk_x11_xatom_to_atom_for_display (display, xevent->xclient.message_type);
-
- GDK_NOTE (EVENTS,
- g_message ("client message:\twindow: %ld",
- xevent->xclient.window));
-
- tmp_list = display_x11->client_filters;
- while (tmp_list)
- {
- GdkClientFilter *filter = tmp_list->data;
- tmp_list = tmp_list->next;
-
- if (filter->type == message_type)
- {
- result = (*filter->function) (xevent, event, filter->data);
- if (result != GDK_FILTER_CONTINUE)
- break;
- }
- }
-
- switch (result)
- {
- case GDK_FILTER_REMOVE:
- return_val = FALSE;
- break;
- case GDK_FILTER_TRANSLATE:
- return_val = TRUE;
- break;
- case GDK_FILTER_CONTINUE:
- /* Send unknown ClientMessage's on to Gtk for it to use */
- if (window_private == NULL)
- {
- return_val = FALSE;
- }
- else
- {
- event->client.type = GDK_CLIENT_EVENT;
- event->client.window = window;
- event->client.message_type = message_type;
- event->client.data_format = xevent->xclient.format;
- memcpy(&event->client.data, &xevent->xclient.data,
- sizeof(event->client.data));
- }
- break;
- }
- }
-
- break;
-
- case MappingNotify:
- GDK_NOTE (EVENTS,
- g_message ("mapping notify"));
-
- /* Let XLib know that there is a new keyboard mapping.
- */
- XRefreshKeyboardMapping (&xevent->xmapping);
- _gdk_keymap_keys_changed (display);
- return_val = FALSE;
- break;
-
- default:
- notify_event = (GdkNotifyEvent *) xevent;
-#ifdef HAVE_XFIXES
- XFixesSelectionNotifyEvent *selection_notify = &(notify_event->selection_notify);
-#endif
-#ifdef HAVE_XDAMAGE
- XDamageNotifyEvent *damage_event = &(notify_event->damage_event);
-#endif
-#ifdef HAVE_XKB
- if (xevent->type == display_x11->xkb_event_type)
- {
- XkbEvent *xkb_event = (XkbEvent *)xevent;
-
- switch (xkb_event->any.xkb_type)
- {
- case XkbNewKeyboardNotify:
- case XkbMapNotify:
- _gdk_keymap_keys_changed (display);
-
- return_val = FALSE;
- break;
-
- case XkbStateNotify:
- _gdk_keymap_state_changed (display, xevent);
- break;
- }
- }
- else
-#endif
-#ifdef HAVE_XFIXES
- if (xevent->type - display_x11->xfixes_event_base == XFixesSelectionNotify)
- {
- _gdk_x11_screen_process_owner_change (screen, xevent);
-
- event->owner_change.type = GDK_OWNER_CHANGE;
- event->owner_change.window = window;
- event->owner_change.owner = selection_notify->owner;
- event->owner_change.reason = selection_notify->subtype;
- event->owner_change.selection =
- gdk_x11_xatom_to_atom_for_display (display,
- selection_notify->selection);
- event->owner_change.time = selection_notify->timestamp;
- event->owner_change.selection_time = selection_notify->selection_timestamp;
-
- return_val = TRUE;
- }
- else
-#endif
-#ifdef HAVE_RANDR
- if (xevent->type - display_x11->xrandr_event_base == RRScreenChangeNotify ||
- xevent->type - display_x11->xrandr_event_base == RRNotify)
- {
- if (screen)
- _gdk_x11_screen_size_changed (screen, xevent);
- }
- else
-#endif
-#if defined(HAVE_XCOMPOSITE) && defined (HAVE_XDAMAGE) && defined (HAVE_XFIXES)
- if (display_x11->have_xdamage && window_private && window_private->composited &&
- xevent->type == display_x11->xdamage_event_base + XDamageNotify &&
- damage_event->damage == window_impl->damage)
- {
- XserverRegion repair;
- GdkRectangle rect;
-
- rect.x = window_private->x + damage_event->area.x;
- rect.y = window_private->y + damage_event->area.y;
- rect.width = damage_event->area.width;
- rect.height = damage_event->area.height;
-
- repair = XFixesCreateRegion (display_x11->xdisplay,
- &damage_event->area, 1);
- XDamageSubtract (display_x11->xdisplay,
- window_impl->damage,
- repair, None);
- XFixesDestroyRegion (display_x11->xdisplay, repair);
-
- if (window_private->parent != NULL)
- _gdk_window_process_expose (GDK_WINDOW (window_private->parent),
- damage_event->serial, &rect);
-
- return_val = TRUE;
- }
- else
-#endif
- {
- /* something else - (e.g., a Xinput event) */
-
- if (window_private &&
- !GDK_WINDOW_DESTROYED (window_private) &&
- window_private->input_window)
- return_val = _gdk_input_other_event (event, xevent, window);
- else
- return_val = FALSE;
-
- break;
- }
- }
-
- done:
- if (return_val)
- {
- if (event->any.window)
- g_object_ref (event->any.window);
- if (((event->any.type == GDK_ENTER_NOTIFY) ||
- (event->any.type == GDK_LEAVE_NOTIFY)) &&
- (event->crossing.subwindow != NULL))
- g_object_ref (event->crossing.subwindow);
- }
- else
- {
- /* Mark this event as having no resources to be freed */
- event->any.window = NULL;
- event->any.type = GDK_NOTHING;
- }
-
- if (window)
- g_object_unref (window);
-
- return return_val;
-}
-
-static GdkFilterReturn
-gdk_wm_protocols_filter (GdkXEvent *xev,
- GdkEvent *event,
- gpointer data)
-{
- XEvent *xevent = (XEvent *)xev;
- GdkWindow *win = event->any.window;
- GdkDisplay *display;
- Atom atom;
-
- if (!win)
- return GDK_FILTER_REMOVE;
-
- display = GDK_WINDOW_DISPLAY (win);
- atom = (Atom)xevent->xclient.data.l[0];
-
- if (atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW"))
- {
- /* The delete window request specifies a window
- * to delete. We don't actually destroy the
- * window because "it is only a request". (The
- * window might contain vital data that the
- * program does not want destroyed). Instead
- * the event is passed along to the program,
- * which should then destroy the window.
- */
- GDK_NOTE (EVENTS,
- g_message ("delete window:\t\twindow: %ld",
- xevent->xclient.window));
-
- event->any.type = GDK_DELETE;
-
- gdk_x11_window_set_user_time (win, xevent->xclient.data.l[1]);
-
- return GDK_FILTER_TRANSLATE;
- }
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS"))
- {
- GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (event->any.window);
- GdkWindowObject *private = (GdkWindowObject *)win;
-
- /* There is no way of knowing reliably whether we are viewable;
- * _gdk_x11_set_input_focus_safe() traps errors asynchronously.
- */
- if (toplevel && private->accept_focus)
- _gdk_x11_set_input_focus_safe (display, toplevel->focus_window,
- RevertToParent,
- xevent->xclient.data.l[1]);
-
- return GDK_FILTER_REMOVE;
- }
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING") &&
- !_gdk_x11_display_is_root_window (display,
- xevent->xclient.window))
- {
- XClientMessageEvent xclient = xevent->xclient;
-
- xclient.window = GDK_WINDOW_XROOTWIN (win);
- XSendEvent (GDK_WINDOW_XDISPLAY (win),
- xclient.window,
- False,
- SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient);
-
- return GDK_FILTER_REMOVE;
- }
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_SYNC_REQUEST") &&
- GDK_DISPLAY_X11 (display)->use_sync)
- {
- GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (event->any.window);
- if (toplevel)
- {
-#ifdef HAVE_XSYNC
- XSyncIntsToValue (&toplevel->pending_counter_value,
- xevent->xclient.data.l[2],
- xevent->xclient.data.l[3]);
-#endif
- }
- return GDK_FILTER_REMOVE;
- }
-
- return GDK_FILTER_CONTINUE;
-}
-
-void
-_gdk_events_queue (GdkDisplay *display)
-{
- GList *node;
- GdkEvent *event;
- XEvent xevent;
- Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
-
- while (!_gdk_event_queue_find_first(display) && XPending (xdisplay))
- {
- XNextEvent (xdisplay, &xevent);
-
- switch (xevent.type)
- {
- case KeyPress:
- case KeyRelease:
- break;
- default:
- if (XFilterEvent (&xevent, None))
- continue;
- }
-
- event = gdk_event_new (GDK_NOTHING);
-
- event->any.window = NULL;
- event->any.send_event = xevent.xany.send_event ? TRUE : FALSE;
-
- ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
-
- node = _gdk_event_queue_append (display, event);
-
- if (gdk_event_translate (display, event, &xevent, FALSE))
- {
- ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
- _gdk_windowing_got_event (display, node, event, xevent.xany.serial);
- }
- else
- {
- _gdk_event_queue_remove_link (display, node);
- g_list_free_1 (node);
- gdk_event_free (event);
- }
- }
-}
-
-static gboolean
-gdk_event_prepare (GSource *source,
- gint *timeout)
-{
- GdkDisplay *display = ((GdkDisplaySource*)source)->display;
- gboolean retval;
-
- GDK_THREADS_ENTER ();
-
- *timeout = -1;
- retval = (_gdk_event_queue_find_first (display) != NULL ||
- gdk_check_xpending (display));
-
- GDK_THREADS_LEAVE ();
-
- return retval;
-}
-
-static gboolean
-gdk_event_check (GSource *source)
-{
- GdkDisplaySource *display_source = (GdkDisplaySource*)source;
- gboolean retval;
-
- GDK_THREADS_ENTER ();
-
- if (display_source->event_poll_fd.revents & G_IO_IN)
- retval = (_gdk_event_queue_find_first (display_source->display) != NULL ||
- gdk_check_xpending (display_source->display));
- else
- retval = FALSE;
-
- GDK_THREADS_LEAVE ();
-
- return retval;
-}
-
-static gboolean
-gdk_event_dispatch (GSource *source,
- GSourceFunc callback,
- gpointer user_data)
-{
- GdkDisplay *display = ((GdkDisplaySource*)source)->display;
- GdkEvent *event;
-
- GDK_THREADS_ENTER ();
-
- _gdk_events_queue (display);
- event = _gdk_event_unqueue (display);
-
- if (event)
- {
- if (_gdk_event_func)
- (*_gdk_event_func) (event, _gdk_event_data);
-
- gdk_event_free (event);
- }
-
- GDK_THREADS_LEAVE ();
-
- return TRUE;
-}
-
-/**
- * gdk_event_send_client_message_for_display:
- * @display: the #GdkDisplay for the window where the message is to be sent.
- * @event: the #GdkEvent to send, which should be a #GdkEventClient.
- * @winid: the window to send the client message to.
- *
- * On X11, sends an X ClientMessage event to a given window. On
- * Windows, sends a message registered with the name
- * GDK_WIN32_CLIENT_MESSAGE.
- *
- * This could be used for communicating between different
- * applications, though the amount of data is limited to 20 bytes on
- * X11, and to just four bytes on Windows.
- *
- * Returns: non-zero on success.
- *
- * Since: 2.2
- */
-gboolean
-gdk_event_send_client_message_for_display (GdkDisplay *display,
- GdkEvent *event,
- GdkNativeWindow winid)
-{
- XEvent sev;
-
- g_return_val_if_fail(event != NULL, FALSE);
-
- /* Set up our event to send, with the exception of its target window */
- sev.xclient.type = ClientMessage;
- sev.xclient.display = GDK_DISPLAY_XDISPLAY (display);
- sev.xclient.format = event->client.data_format;
- sev.xclient.window = winid;
- memcpy(&sev.xclient.data, &event->client.data, sizeof (sev.xclient.data));
- sev.xclient.message_type = gdk_x11_atom_to_xatom_for_display (display, event->client.message_type);
-
- return _gdk_send_xevent (display, winid, False, NoEventMask, &sev);
-}
-
-
-
-/* Sends a ClientMessage to all toplevel client windows */
-static gboolean
-gdk_event_send_client_message_to_all_recurse (GdkDisplay *display,
- XEvent *xev,
- guint32 xid,
- guint level)
-{
- Atom type = None;
- int format;
- unsigned long nitems, after;
- unsigned char *data;
- Window *ret_children, ret_root, ret_parent;
- unsigned int ret_nchildren;
- gboolean send = FALSE;
- gboolean found = FALSE;
- gboolean result = FALSE;
- int i;
-
- gdk_error_trap_push ();
-
- if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xid,
- gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE"),
- 0, 0, False, AnyPropertyType,
- &type, &format, &nitems, &after, &data) != Success)
- goto out;
-
- if (type)
- {
- send = TRUE;
- XFree (data);
- }
- else
- {
- /* OK, we're all set, now let's find some windows to send this to */
- if (!XQueryTree (GDK_DISPLAY_XDISPLAY (display), xid,
- &ret_root, &ret_parent,
- &ret_children, &ret_nchildren))
- goto out;
-
- for(i = 0; i < ret_nchildren; i++)
- if (gdk_event_send_client_message_to_all_recurse (display, xev, ret_children[i], level + 1))
- found = TRUE;
-
- XFree (ret_children);
- }
-
- if (send || (!found && (level == 1)))
- {
- xev->xclient.window = xid;
- _gdk_send_xevent (display, xid, False, NoEventMask, xev);
- }
-
- result = send || found;
-
- out:
- gdk_error_trap_pop ();
-
- return result;
-}
-
-/**
- * gdk_screen_broadcast_client_message:
- * @screen: the #GdkScreen where the event will be broadcasted.
- * @event: the #GdkEvent.
- *
- * On X11, sends an X ClientMessage event to all toplevel windows on
- * @screen.
- *
- * Toplevel windows are determined by checking for the WM_STATE property,
- * as described in the Inter-Client Communication Conventions Manual (ICCCM).
- * If no windows are found with the WM_STATE property set, the message is
- * sent to all children of the root window.
- *
- * On Windows, broadcasts a message registered with the name
- * GDK_WIN32_CLIENT_MESSAGE to all top-level windows. The amount of
- * data is limited to one long, i.e. four bytes.
- *
- * Since: 2.2
- */
-
-void
-gdk_screen_broadcast_client_message (GdkScreen *screen,
- GdkEvent *event)
-{
- XEvent sev;
- GdkWindow *root_window;
-
- g_return_if_fail (event != NULL);
-
- root_window = gdk_screen_get_root_window (screen);
-
- /* Set up our event to send, with the exception of its target window */
- sev.xclient.type = ClientMessage;
- sev.xclient.display = GDK_WINDOW_XDISPLAY (root_window);
- sev.xclient.format = event->client.data_format;
- memcpy(&sev.xclient.data, &event->client.data, sizeof (sev.xclient.data));
- sev.xclient.message_type =
- gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (root_window),
- event->client.message_type);
-
- gdk_event_send_client_message_to_all_recurse (gdk_screen_get_display (screen),
- &sev,
- GDK_WINDOW_XID (root_window),
- 0);
-}
-
-/*
- *--------------------------------------------------------------
- * gdk_flush
- *
- * Flushes the Xlib output buffer and then waits
- * until all requests have been received and processed
- * by the X server. The only real use for this function
- * is in dealing with XShm.
- *
- * Arguments:
- *
- * Results:
- *
- * Side effects:
- *
- *--------------------------------------------------------------
- */
-
-void
-gdk_flush (void)
-{
- GSList *tmp_list = _gdk_displays;
-
- while (tmp_list)
- {
- XSync (GDK_DISPLAY_XDISPLAY (tmp_list->data), False);
- tmp_list = tmp_list->next;
- }
-}
-
-static Bool
-timestamp_predicate (Display *display,
- XEvent *xevent,
- XPointer arg)
-{
- Window xwindow = GPOINTER_TO_UINT (arg);
- GdkDisplay *gdk_display = gdk_x11_lookup_xdisplay (display);
-
- if (xevent->type == PropertyNotify &&
- xevent->xproperty.window == xwindow &&
- xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (gdk_display,
- "GDK_TIMESTAMP_PROP"))
- return True;
-
- return False;
-}
-
-/**
- * gdk_x11_get_server_time:
- * @window: a #GdkWindow, used for communication with the server.
- * The window must have GDK_PROPERTY_CHANGE_MASK in its
- * events mask or a hang will result.
- *
- * Routine to get the current X server time stamp.
- *
- * Return value: the time stamp.
- **/
-guint32
-gdk_x11_get_server_time (GdkWindow *window)
-{
- Display *xdisplay;
- Window xwindow;
- guchar c = 'a';
- XEvent xevent;
- Atom timestamp_prop_atom;
-
- g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
- g_return_val_if_fail (!GDK_WINDOW_DESTROYED (window), 0);
-
- xdisplay = GDK_WINDOW_XDISPLAY (window);
- xwindow = GDK_WINDOW_XWINDOW (window);
- timestamp_prop_atom =
- gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
- "GDK_TIMESTAMP_PROP");
-
- XChangeProperty (xdisplay, xwindow, timestamp_prop_atom,
- timestamp_prop_atom,
- 8, PropModeReplace, &c, 1);
-
- XIfEvent (xdisplay, &xevent,
- timestamp_predicate, GUINT_TO_POINTER(xwindow));
-
- return xevent.xproperty.time;
-}
-
-static void
-fetch_net_wm_check_window (GdkScreen *screen)
-{
- GdkScreenX11 *screen_x11;
- GdkDisplay *display;
- Atom type;
- gint format;
- gulong n_items;
- gulong bytes_after;
- guchar *data;
- Window *xwindow;
- GTimeVal tv;
- gint error;
-
- screen_x11 = GDK_SCREEN_X11 (screen);
- display = screen_x11->display;
-
- g_return_if_fail (GDK_DISPLAY_X11 (display)->trusted_client);
-
- g_get_current_time (&tv);
-
- if (ABS (tv.tv_sec - screen_x11->last_wmspec_check_time) < 15)
- return; /* we've checked recently */
-
- screen_x11->last_wmspec_check_time = tv.tv_sec;
-
- data = NULL;
- XGetWindowProperty (screen_x11->xdisplay, screen_x11->xroot_window,
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTING_WM_CHECK"),
- 0, G_MAXLONG, False, XA_WINDOW, &type, &format,
- &n_items, &bytes_after, &data);
-
- if (type != XA_WINDOW)
- {
- if (data)
- XFree (data);
- return;
- }
-
- xwindow = (Window *)data;
-
- if (screen_x11->wmspec_check_window == *xwindow)
- {
- XFree (xwindow);
- return;
- }
-
- gdk_error_trap_push ();
-
- /* Find out if this WM goes away, so we can reset everything. */
- XSelectInput (screen_x11->xdisplay, *xwindow, StructureNotifyMask);
- gdk_display_sync (display);
-
- error = gdk_error_trap_pop ();
- if (!error)
- {
- screen_x11->wmspec_check_window = *xwindow;
- screen_x11->need_refetch_net_supported = TRUE;
- screen_x11->need_refetch_wm_name = TRUE;
-
- /* Careful, reentrancy */
- _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11));
- }
- else if (error == BadWindow)
- {
- /* Leftover property, try again immediately, new wm may be starting up */
- screen_x11->last_wmspec_check_time = 0;
- }
-
- XFree (xwindow);
-}
-
-/**
- * gdk_x11_screen_get_window_manager_name:
- * @screen: a #GdkScreen
- *
- * Returns the name of the window manager for @screen.
- *
- * Return value: the name of the window manager screen @screen, or
- * "unknown" if the window manager is unknown. The string is owned by GDK
- * and should not be freed.
- *
- * Since: 2.2
- **/
-const char*
-gdk_x11_screen_get_window_manager_name (GdkScreen *screen)
-{
- GdkScreenX11 *screen_x11;
-
- screen_x11 = GDK_SCREEN_X11 (screen);
-
- if (!G_LIKELY (GDK_DISPLAY_X11 (screen_x11->display)->trusted_client))
- return screen_x11->window_manager_name;
-
- fetch_net_wm_check_window (screen);
-
- if (screen_x11->need_refetch_wm_name)
- {
- /* Get the name of the window manager */
- screen_x11->need_refetch_wm_name = FALSE;
-
- g_free (screen_x11->window_manager_name);
- screen_x11->window_manager_name = g_strdup ("unknown");
-
- if (screen_x11->wmspec_check_window != None)
- {
- Atom type;
- gint format;
- gulong n_items;
- gulong bytes_after;
- gchar *name;
-
- name = NULL;
-
- gdk_error_trap_push ();
-
- XGetWindowProperty (GDK_DISPLAY_XDISPLAY (screen_x11->display),
- screen_x11->wmspec_check_window,
- gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
- "_NET_WM_NAME"),
- 0, G_MAXLONG, False,
- gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
- "UTF8_STRING"),
- &type, &format,
- &n_items, &bytes_after,
- (guchar **)&name);
-
- gdk_display_sync (screen_x11->display);
-
- gdk_error_trap_pop ();
-
- if (name != NULL)
- {
- g_free (screen_x11->window_manager_name);
- screen_x11->window_manager_name = g_strdup (name);
- XFree (name);
- }
- }
- }
-
- return GDK_SCREEN_X11 (screen)->window_manager_name;
-}
-
-typedef struct _NetWmSupportedAtoms NetWmSupportedAtoms;
-
-struct _NetWmSupportedAtoms
-{
- Atom *atoms;
- gulong n_atoms;
-};
-
-static void
-cleanup_atoms(gpointer data)
-{
- NetWmSupportedAtoms *supported_atoms = data;
- if (supported_atoms->atoms)
- XFree (supported_atoms->atoms);
- g_free (supported_atoms);
-}
-
-/**
- * gdk_x11_screen_supports_net_wm_hint:
- * @screen: the relevant #GdkScreen.
- * @property: a property atom.
- *
- * This function is specific to the X11 backend of GDK, and indicates
- * whether the window manager supports a certain hint from the
- * Extended Window Manager Hints Specification. You can find this
- * specification on
- * <ulink url="http://www.freedesktop.org">http://www.freedesktop.org</ulink>.
- *
- * When using this function, keep in mind that the window manager
- * can change over time; so you shouldn't use this function in
- * a way that impacts persistent application state. A common bug
- * is that your application can start up before the window manager
- * does when the user logs in, and before the window manager starts
- * gdk_x11_screen_supports_net_wm_hint() will return %FALSE for every property.
- * You can monitor the window_manager_changed signal on #GdkScreen to detect
- * a window manager change.
- *
- * Return value: %TRUE if the window manager supports @property
- *
- * Since: 2.2
- **/
-gboolean
-gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
- GdkAtom property)
-{
- gulong i;
- GdkScreenX11 *screen_x11;
- NetWmSupportedAtoms *supported_atoms;
- GdkDisplay *display;
-
- g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
-
- screen_x11 = GDK_SCREEN_X11 (screen);
- display = screen_x11->display;
-
- if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
- return FALSE;
-
- supported_atoms = g_object_get_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms");
- if (!supported_atoms)
- {
- supported_atoms = g_new0 (NetWmSupportedAtoms, 1);
- g_object_set_data_full (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms, cleanup_atoms);
- }
-
- fetch_net_wm_check_window (screen);
-
- if (screen_x11->wmspec_check_window == None)
- return FALSE;
-
- if (screen_x11->need_refetch_net_supported)
- {
- /* WM has changed since we last got the supported list,
- * refetch it.
- */
- Atom type;
- gint format;
- gulong bytes_after;
-
- screen_x11->need_refetch_net_supported = FALSE;
-
- if (supported_atoms->atoms)
- XFree (supported_atoms->atoms);
-
- supported_atoms->atoms = NULL;
- supported_atoms->n_atoms = 0;
-
- XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_x11->xroot_window,
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTED"),
- 0, G_MAXLONG, False, XA_ATOM, &type, &format,
- &supported_atoms->n_atoms, &bytes_after,
- (guchar **)&supported_atoms->atoms);
-
- if (type != XA_ATOM)
- return FALSE;
- }
-
- if (supported_atoms->atoms == NULL)
- return FALSE;
-
- i = 0;
- while (i < supported_atoms->n_atoms)
- {
- if (supported_atoms->atoms[i] == gdk_x11_atom_to_xatom_for_display (display, property))
- return TRUE;
-
- ++i;
- }
-
- return FALSE;
-}
-
-/**
- * gdk_net_wm_supports:
- * @property: a property atom.
- *
- * This function is specific to the X11 backend of GDK, and indicates
- * whether the window manager for the default screen supports a certain
- * hint from the Extended Window Manager Hints Specification. See
- * gdk_x11_screen_supports_net_wm_hint() for complete details.
- *
- * Return value: %TRUE if the window manager supports @property
- **/
-gboolean
-gdk_net_wm_supports (GdkAtom property)
-{
- return gdk_x11_screen_supports_net_wm_hint (gdk_screen_get_default (), property);
-}
-
-
-static void
-gdk_xsettings_notify_cb (const char *name,
- XSettingsAction action,
- XSettingsSetting *setting,
- void *data)
-{
- GdkEvent new_event;
- GdkScreen *screen = data;
- GdkScreenX11 *screen_x11 = data;
- int i;
-
- if (screen_x11->xsettings_in_init)
- return;
-
- new_event.type = GDK_SETTING;
- new_event.setting.window = gdk_screen_get_root_window (screen);
- new_event.setting.send_event = FALSE;
- new_event.setting.name = NULL;
-
- for (i = 0; i < GDK_SETTINGS_N_ELEMENTS() ; i++)
- if (strcmp (GDK_SETTINGS_X_NAME (i), name) == 0)
- {
- new_event.setting.name = (char*) GDK_SETTINGS_GDK_NAME (i);
- break;
- }
-
- if (!new_event.setting.name)
- return;
-
- switch (action)
- {
- case XSETTINGS_ACTION_NEW:
- new_event.setting.action = GDK_SETTING_ACTION_NEW;
- break;
- case XSETTINGS_ACTION_CHANGED:
- new_event.setting.action = GDK_SETTING_ACTION_CHANGED;
- break;
- case XSETTINGS_ACTION_DELETED:
- new_event.setting.action = GDK_SETTING_ACTION_DELETED;
- break;
- }
-
- gdk_event_put (&new_event);
-}
-
-static gboolean
-check_transform (const gchar *xsettings_name,
- GType src_type,
- GType dest_type)
-{
- if (!g_value_type_transformable (src_type, dest_type))
- {
- g_warning ("Cannot transform xsetting %s of type %s to type %s\n",
- xsettings_name,
- g_type_name (src_type),
- g_type_name (dest_type));
- return FALSE;
- }
- else
- return TRUE;
-}
-
-/**
- * gdk_screen_get_setting:
- * @screen: the #GdkScreen where the setting is located
- * @name: the name of the setting
- * @value: location to store the value of the setting
- *
- * Retrieves a desktop-wide setting such as double-click time
- * for the #GdkScreen @screen.
- *
- * FIXME needs a list of valid settings here, or a link to
- * more information.
- *
- * Returns: %TRUE if the setting existed and a value was stored
- * in @value, %FALSE otherwise.
- *
- * Since: 2.2
- **/
-gboolean
-gdk_screen_get_setting (GdkScreen *screen,
- const gchar *name,
- GValue *value)
-{
-
- const char *xsettings_name = NULL;
- XSettingsResult result;
- XSettingsSetting *setting = NULL;
- GdkScreenX11 *screen_x11;
- gboolean success = FALSE;
- gint i;
- GValue tmp_val = { 0, };
-
- g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
-
- screen_x11 = GDK_SCREEN_X11 (screen);
-
- for (i = 0; i < GDK_SETTINGS_N_ELEMENTS(); i++)
- if (strcmp (GDK_SETTINGS_GDK_NAME (i), name) == 0)
- {
- xsettings_name = GDK_SETTINGS_X_NAME (i);
- break;
- }
-
- if (!xsettings_name)
- goto out;
-
- result = xsettings_client_get_setting (screen_x11->xsettings_client,
- xsettings_name, &setting);
- if (result != XSETTINGS_SUCCESS)
- goto out;
-
- switch (setting->type)
- {
- case XSETTINGS_TYPE_INT:
- if (check_transform (xsettings_name, G_TYPE_INT, G_VALUE_TYPE (value)))
- {
- g_value_init (&tmp_val, G_TYPE_INT);
- g_value_set_int (&tmp_val, setting->data.v_int);
- g_value_transform (&tmp_val, value);
-
- success = TRUE;
- }
- break;
- case XSETTINGS_TYPE_STRING:
- if (check_transform (xsettings_name, G_TYPE_STRING, G_VALUE_TYPE (value)))
- {
- g_value_init (&tmp_val, G_TYPE_STRING);
- g_value_set_string (&tmp_val, setting->data.v_string);
- g_value_transform (&tmp_val, value);
-
- success = TRUE;
- }
- break;
- case XSETTINGS_TYPE_COLOR:
- if (!check_transform (xsettings_name, GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
- {
- GdkColor color;
-
- g_value_init (&tmp_val, GDK_TYPE_COLOR);
-
- color.pixel = 0;
- color.red = setting->data.v_color.red;
- color.green = setting->data.v_color.green;
- color.blue = setting->data.v_color.blue;
-
- g_value_set_boxed (&tmp_val, &color);
-
- g_value_transform (&tmp_val, value);
-
- success = TRUE;
- }
- break;
- }
-
- g_value_unset (&tmp_val);
-
- out:
- if (setting)
- xsettings_setting_free (setting);
-
- if (success)
- return TRUE;
- else
- return _gdk_x11_get_xft_setting (screen, name, value);
-}
-
-static GdkFilterReturn
-gdk_xsettings_client_event_filter (GdkXEvent *xevent,
- GdkEvent *event,
- gpointer data)
-{
- GdkScreenX11 *screen = data;
-
- if (xsettings_client_process_event (screen->xsettings_client, (XEvent *)xevent))
- return GDK_FILTER_REMOVE;
- else
- return GDK_FILTER_CONTINUE;
-}
-
-static Bool
-gdk_xsettings_watch_cb (Window window,
- Bool is_start,
- long mask,
- void *cb_data)
-{
- GdkWindow *gdkwin;
- GdkScreen *screen = cb_data;
-
- gdkwin = gdk_window_lookup_for_display (gdk_screen_get_display (screen), window);
-
- if (is_start)
- {
- if (gdkwin)
- g_object_ref (gdkwin);
- else
- {
- gdkwin = gdk_window_foreign_new_for_display (gdk_screen_get_display (screen), window);
-
- /* gdk_window_foreign_new_for_display() can fail and return NULL if the
- * window has already been destroyed.
- */
- if (!gdkwin)
- return False;
- }
-
- gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
- }
- else
- {
- if (!gdkwin)
- {
- /* gdkwin should not be NULL here, since if starting the watch succeeded
- * we have a reference on the window. It might mean that the caller didn't
- * remove the watch when it got a DestroyNotify event. Or maybe the
- * caller ignored the return value when starting the watch failed.
- */
- g_warning ("gdk_xsettings_watch_cb(): Couldn't find window to unwatch");
- return False;
- }
-
- gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
- g_object_unref (gdkwin);
- }
-
- return True;
-}
-
-void
-_gdk_windowing_event_data_copy (const GdkEvent *src,
- GdkEvent *dst)
-{
-}
-
-void
-_gdk_windowing_event_data_free (GdkEvent *event)
-{
-}
-
-#define __GDK_EVENTS_X11_C__
-#include "gdkaliasdef.c"
diff --git a/gdk/x11/gdkeventsource.c b/gdk/x11/gdkeventsource.c
new file mode 100644
index 0000000000..e0ab3bee28
--- /dev/null
+++ b/gdk/x11/gdkeventsource.c
@@ -0,0 +1,427 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+
+#include "gdkeventsource.h"
+#include "gdkinternals.h"
+#include "gdkx.h"
+#include "gdkalias.h"
+
+static gboolean gdk_event_source_prepare (GSource *source,
+ gint *timeout);
+static gboolean gdk_event_source_check (GSource *source);
+static gboolean gdk_event_source_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data);
+static void gdk_event_source_finalize (GSource *source);
+
+#define HAS_FOCUS(toplevel) \
+ ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
+
+struct _GdkEventSource
+{
+ GSource source;
+
+ GdkDisplay *display;
+ GPollFD event_poll_fd;
+ GList *translators;
+};
+
+static GSourceFuncs event_funcs = {
+ gdk_event_source_prepare,
+ gdk_event_source_check,
+ gdk_event_source_dispatch,
+ gdk_event_source_finalize
+};
+
+static GList *event_sources = NULL;
+
+static gint
+gdk_event_apply_filters (XEvent *xevent,
+ GdkEvent *event,
+ GList *filters)
+{
+ GList *tmp_list;
+ GdkFilterReturn result;
+
+ tmp_list = filters;
+
+ while (tmp_list)
+ {
+ GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
+
+ tmp_list = tmp_list->next;
+ result = filter->function (xevent, event, filter->data);
+
+ if (result != GDK_FILTER_CONTINUE)
+ return result;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static GdkWindow *
+gdk_event_source_get_filter_window (GdkEventSource *event_source,
+ XEvent *xevent)
+{
+ GdkWindow *window;
+
+ window = gdk_window_lookup_for_display (event_source->display,
+ xevent->xany.window);
+
+ if (window && !GDK_IS_WINDOW (window))
+ window = NULL;
+
+ return window;
+}
+
+static void
+handle_focus_change (GdkEventCrossing *event)
+{
+ GdkToplevelX11 *toplevel;
+ gboolean focus_in, had_focus;
+
+ toplevel = _gdk_x11_window_get_toplevel (event->window);
+ focus_in = (event->type == GDK_ENTER_NOTIFY);
+
+ if (!toplevel || event->detail == GDK_NOTIFY_INFERIOR)
+ return;
+
+ toplevel->has_pointer = focus_in;
+
+ if (!event->focus || toplevel->has_focus_window)
+ return;
+
+ had_focus = HAS_FOCUS (toplevel);
+ toplevel->has_pointer_focus = focus_in;
+
+ if (HAS_FOCUS (toplevel) != had_focus)
+ {
+ GdkEvent *focus_event;
+
+ focus_event = gdk_event_new (GDK_FOCUS_CHANGE);
+ focus_event->focus_change.window = g_object_ref (event->window);
+ focus_event->focus_change.send_event = FALSE;
+ focus_event->focus_change.in = focus_in;
+ gdk_event_set_device (focus_event, gdk_event_get_device ((GdkEvent *) event));
+
+ gdk_event_put (focus_event);
+ gdk_event_free (focus_event);
+ }
+}
+
+static GdkEvent *
+gdk_event_source_translate_event (GdkEventSource *event_source,
+ XEvent *xevent)
+{
+ GdkEvent *event = gdk_event_new (GDK_NOTHING);
+ GList *list = event_source->translators;
+ GdkFilterReturn result;
+ GdkWindow *filter_window;
+
+ /* Run default filters */
+ if (_gdk_default_filters)
+ {
+ /* Apply global filters */
+
+ result = gdk_event_apply_filters (xevent, event,
+ _gdk_default_filters);
+
+ if (result == GDK_FILTER_REMOVE)
+ {
+ gdk_event_free (event);
+ return NULL;
+ }
+ else if (result == GDK_FILTER_TRANSLATE)
+ return event;
+ }
+
+ filter_window = gdk_event_source_get_filter_window (event_source, xevent);
+
+ if (filter_window)
+ {
+ /* Apply per-window filters */
+ GdkWindowObject *filter_private = (GdkWindowObject *) filter_window;
+ GdkFilterReturn result;
+
+ event->any.window = g_object_ref (filter_window);
+
+ if (filter_private->filters)
+ {
+ result = gdk_event_apply_filters (xevent, event,
+ filter_private->filters);
+
+ if (result == GDK_FILTER_REMOVE)
+ {
+ gdk_event_free (event);
+ return NULL;
+ }
+ else if (result == GDK_FILTER_TRANSLATE)
+ return event;
+ }
+ }
+
+ gdk_event_free (event);
+ event = NULL;
+
+ while (list && !event)
+ {
+ GdkEventTranslator *translator = list->data;
+
+ list = list->next;
+ event = gdk_event_translator_translate (translator,
+ event_source->display,
+ xevent);
+ }
+
+ if (event &&
+ (event->type == GDK_ENTER_NOTIFY ||
+ event->type == GDK_LEAVE_NOTIFY) &&
+ event->crossing.window != NULL)
+ {
+ /* Handle focusing (in the case where no window manager is running */
+ handle_focus_change (&event->crossing);
+ }
+
+ return event;
+}
+
+static gboolean
+gdk_check_xpending (GdkDisplay *display)
+{
+ return XPending (GDK_DISPLAY_XDISPLAY (display));
+}
+
+static gboolean
+gdk_event_source_prepare (GSource *source,
+ gint *timeout)
+{
+ GdkDisplay *display = ((GdkEventSource*) source)->display;
+ gboolean retval;
+
+ GDK_THREADS_ENTER ();
+
+ *timeout = -1;
+ retval = (_gdk_event_queue_find_first (display) != NULL ||
+ gdk_check_xpending (display));
+
+ GDK_THREADS_LEAVE ();
+
+ return retval;
+}
+
+static gboolean
+gdk_event_source_check (GSource *source)
+{
+ GdkEventSource *event_source = (GdkEventSource*) source;
+ gboolean retval;
+
+ GDK_THREADS_ENTER ();
+
+ if (event_source->event_poll_fd.revents & G_IO_IN)
+ retval = (_gdk_event_queue_find_first (event_source->display) != NULL ||
+ gdk_check_xpending (event_source->display));
+ else
+ retval = FALSE;
+
+ GDK_THREADS_LEAVE ();
+
+ return retval;
+}
+
+void
+_gdk_events_queue (GdkDisplay *display)
+{
+ GdkEvent *event;
+ XEvent xevent;
+ Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
+ GdkEventSource *event_source;
+ GdkDisplayX11 *display_x11;
+
+ display_x11 = GDK_DISPLAY_X11 (display);
+ event_source = (GdkEventSource *) display_x11->event_source;
+
+ while (!_gdk_event_queue_find_first (display) && XPending (xdisplay))
+ {
+ XNextEvent (xdisplay, &xevent);
+
+ switch (xevent.type)
+ {
+ case KeyPress:
+ case KeyRelease:
+ break;
+ default:
+ if (XFilterEvent (&xevent, None))
+ continue;
+ }
+
+ event = gdk_event_source_translate_event (event_source, &xevent);
+
+ if (event)
+ {
+ GList *node;
+
+ node = _gdk_event_queue_append (display, event);
+ _gdk_windowing_got_event (display, node, event, xevent.xany.serial);
+ }
+ }
+}
+
+static gboolean
+gdk_event_source_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ GdkDisplay *display = ((GdkEventSource*) source)->display;
+ GdkEvent *event;
+
+ GDK_THREADS_ENTER ();
+
+ event = gdk_display_get_event (display);
+
+ if (event)
+ {
+ if (_gdk_event_func)
+ (*_gdk_event_func) (event, _gdk_event_data);
+
+ gdk_event_free (event);
+ }
+
+ GDK_THREADS_LEAVE ();
+
+ return TRUE;
+}
+
+static void
+gdk_event_source_finalize (GSource *source)
+{
+ event_sources = g_list_remove (event_sources, source);
+}
+
+GSource *
+gdk_event_source_new (GdkDisplay *display)
+{
+ GSource *source;
+ GdkEventSource *event_source;
+ GdkDisplayX11 *display_x11;
+ int connection_number;
+
+ source = g_source_new (&event_funcs, sizeof (GdkEventSource));
+ event_source = (GdkEventSource *) source;
+ event_source->display = display;
+
+ display_x11 = GDK_DISPLAY_X11 (display);
+ connection_number = ConnectionNumber (display_x11->xdisplay);
+
+ event_source->event_poll_fd.fd = connection_number;
+ event_source->event_poll_fd.events = G_IO_IN;
+ g_source_add_poll (source, &event_source->event_poll_fd);
+
+ g_source_set_priority (source, GDK_PRIORITY_EVENTS);
+ g_source_set_can_recurse (source, TRUE);
+ g_source_attach (source, NULL);
+
+ event_sources = g_list_prepend (event_sources, source);
+
+ return source;
+}
+
+void
+gdk_event_source_add_translator (GdkEventSource *source,
+ GdkEventTranslator *translator)
+{
+ g_return_if_fail (GDK_IS_EVENT_TRANSLATOR (translator));
+
+ source->translators = g_list_append (source->translators, translator);
+}
+
+void
+gdk_event_source_select_events (GdkEventSource *source,
+ Window window,
+ GdkEventMask event_mask,
+ unsigned int extra_x_mask)
+{
+ unsigned int xmask = extra_x_mask;
+ GList *list;
+ gint i;
+
+ list = source->translators;
+
+ while (list)
+ {
+ GdkEventTranslator *translator = list->data;
+ GdkEventMask translator_mask, mask;
+
+ translator_mask = gdk_event_translator_get_handled_events (translator);
+ mask = event_mask & translator_mask;
+
+ if (mask != 0)
+ {
+ gdk_event_translator_select_window_events (translator, window, mask);
+ event_mask &= ~mask;
+ }
+
+ list = list->next;
+ }
+
+ for (i = 0; i < _gdk_nenvent_masks; i++)
+ {
+ if (event_mask & (1 << (i + 1)))
+ xmask |= _gdk_event_mask_table[i];
+ }
+
+ XSelectInput (GDK_DISPLAY_XDISPLAY (source->display), window, xmask);
+}
+
+/**
+ * gdk_events_pending:
+ *
+ * Checks if any events are ready to be processed for any display.
+ *
+ * Return value: %TRUE if any events are pending.
+ **/
+gboolean
+gdk_events_pending (void)
+{
+ GList *tmp_list;
+
+ for (tmp_list = event_sources; tmp_list; tmp_list = tmp_list->next)
+ {
+ GdkEventSource *tmp_source = tmp_list->data;
+ GdkDisplay *display = tmp_source->display;
+
+ if (_gdk_event_queue_find_first (display))
+ return TRUE;
+ }
+
+ for (tmp_list = event_sources; tmp_list; tmp_list = tmp_list->next)
+ {
+ GdkEventSource *tmp_source = tmp_list->data;
+ GdkDisplay *display = tmp_source->display;
+
+ if (gdk_check_xpending (display))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+#define __GDK_EVENT_SOURCE_C__
+#include "gdkaliasdef.c"
diff --git a/gdk/x11/gdkeventsource.h b/gdk/x11/gdkeventsource.h
new file mode 100644
index 0000000000..4fc0dbe7b4
--- /dev/null
+++ b/gdk/x11/gdkeventsource.h
@@ -0,0 +1,46 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GDK_EVENT_SOURCE_H__
+#define __GDK_EVENT_SOURCE_H__
+
+#include "gdkeventtranslator.h"
+#include "gdkprivate-x11.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GdkEventSource GdkEventSource;
+
+G_GNUC_INTERNAL
+GSource * gdk_event_source_new (GdkDisplay *display);
+
+G_GNUC_INTERNAL
+void gdk_event_source_add_translator (GdkEventSource *source,
+ GdkEventTranslator *translator);
+
+G_GNUC_INTERNAL
+void gdk_event_source_select_events (GdkEventSource *source,
+ Window window,
+ GdkEventMask event_mask,
+ unsigned int extra_x_mask);
+
+
+G_END_DECLS
+
+#endif /* __GDK_EVENT_SOURCE_H__ */
diff --git a/gdk/x11/gdkeventtranslator.c b/gdk/x11/gdkeventtranslator.c
new file mode 100644
index 0000000000..753dfc890a
--- /dev/null
+++ b/gdk/x11/gdkeventtranslator.c
@@ -0,0 +1,100 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "config.h"
+
+#include "gdkeventtranslator.h"
+#include "gdkalias.h"
+
+GType
+gdk_event_translator_get_type (void)
+{
+ static GType translator_type = 0;
+
+ if (G_UNLIKELY (!translator_type))
+ {
+ translator_type = g_type_register_static_simple (G_TYPE_INTERFACE,
+ g_intern_static_string ("GdkEventTranslator"),
+ sizeof (GdkEventTranslatorIface),
+ NULL, 0, NULL, 0);
+
+ g_type_interface_add_prerequisite (translator_type, G_TYPE_OBJECT);
+ }
+
+ return translator_type;
+}
+
+GdkEvent *
+gdk_event_translator_translate (GdkEventTranslator *translator,
+ GdkDisplay *display,
+ XEvent *xevent)
+{
+ GdkEventTranslatorIface *iface;
+ GdkEvent *event;
+
+ g_return_val_if_fail (GDK_IS_EVENT_TRANSLATOR (translator), NULL);
+ g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+ iface = GDK_EVENT_TRANSLATOR_GET_IFACE (translator);
+
+ if (!iface->translate_event)
+ return NULL;
+
+ event = gdk_event_new (GDK_NOTHING);
+
+ if ((iface->translate_event) (translator, display, event, xevent))
+ return event;
+
+ gdk_event_free (event);
+
+ return NULL;
+}
+
+GdkEventMask
+gdk_event_translator_get_handled_events (GdkEventTranslator *translator)
+{
+ GdkEventTranslatorIface *iface;
+
+ g_return_val_if_fail (GDK_IS_EVENT_TRANSLATOR (translator), 0);
+
+ iface = GDK_EVENT_TRANSLATOR_GET_IFACE (translator);
+
+ if (iface->get_handled_events)
+ return iface->get_handled_events (translator);
+
+ return 0;
+}
+
+void
+gdk_event_translator_select_window_events (GdkEventTranslator *translator,
+ Window window,
+ GdkEventMask event_mask)
+{
+ GdkEventTranslatorIface *iface;
+
+ g_return_if_fail (GDK_IS_EVENT_TRANSLATOR (translator));
+
+ iface = GDK_EVENT_TRANSLATOR_GET_IFACE (translator);
+
+ if (iface->select_window_events)
+ iface->select_window_events (translator, window, event_mask);
+}
+
+#define __GDK_EVENT_TRANSLATOR_C__
+#include "gdkaliasdef.c"
diff --git a/gdk/x11/gdkeventtranslator.h b/gdk/x11/gdkeventtranslator.h
new file mode 100644
index 0000000000..62c99e3f5d
--- /dev/null
+++ b/gdk/x11/gdkeventtranslator.h
@@ -0,0 +1,65 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GDK_EVENT_TRANSLATOR_H__
+#define __GDK_EVENT_TRANSLATOR_H__
+
+#include <gdk/gdktypes.h>
+#include <gdk/gdkdisplay.h>
+#include "gdkprivate-x11.h"
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_EVENT_TRANSLATOR (gdk_event_translator_get_type ())
+#define GDK_EVENT_TRANSLATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_EVENT_TRANSLATOR, GdkEventTranslator))
+#define GDK_IS_EVENT_TRANSLATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_EVENT_TRANSLATOR))
+#define GDK_EVENT_TRANSLATOR_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), GDK_TYPE_EVENT_TRANSLATOR, GdkEventTranslatorIface))
+
+typedef struct _GdkEventTranslatorIface GdkEventTranslatorIface;
+typedef struct _GdkEventTranslator GdkEventTranslator; /* Dummy typedef */
+
+struct _GdkEventTranslatorIface
+{
+ GTypeInterface iface;
+
+ /* VMethods */
+ gboolean (* translate_event) (GdkEventTranslator *translator,
+ GdkDisplay *display,
+ GdkEvent *event,
+ XEvent *xevent);
+
+ GdkEventMask (* get_handled_events) (GdkEventTranslator *translator);
+ void (* select_window_events) (GdkEventTranslator *translator,
+ Window window,
+ GdkEventMask event_mask);
+};
+
+GType gdk_event_translator_get_type (void) G_GNUC_CONST;
+
+GdkEvent * gdk_event_translator_translate (GdkEventTranslator *translator,
+ GdkDisplay *display,
+ XEvent *xevent);
+GdkEventMask gdk_event_translator_get_handled_events (GdkEventTranslator *translator);
+void gdk_event_translator_select_window_events (GdkEventTranslator *translator,
+ Window window,
+ GdkEventMask event_mask);
+
+G_END_DECLS
+
+#endif /* __GDK_EVENT_TRANSLATOR_H__ */
diff --git a/gdk/x11/gdkinput-none.c b/gdk/x11/gdkinput-none.c
deleted file mode 100644
index 4d21beff34..0000000000
--- a/gdk/x11/gdkinput-none.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/* 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 Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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.
- */
-
-#include "config.h"
-#include "gdkinputprivate.h"
-#include "gdkdisplay-x11.h"
-#include "gdkalias.h"
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. 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/.
- */
-
-void
-_gdk_input_init (GdkDisplay *display)
-{
- GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
-
- _gdk_init_input_core (display);
-
- display_x11->input_devices = g_list_append (NULL, display->core_pointer);
- display->ignore_core_events = FALSE;
-}
-
-void
-gdk_device_get_state (GdkDevice *device,
- GdkWindow *window,
- gdouble *axes,
- GdkModifierType *mask)
-{
- gint x_int, y_int;
-
- g_return_if_fail (device != NULL);
- g_return_if_fail (GDK_IS_WINDOW (window));
-
- gdk_window_get_pointer (window, &x_int, &y_int, mask);
-
- if (axes)
- {
- axes[0] = x_int;
- axes[1] = y_int;
- }
-}
-
-gboolean
-_gdk_device_get_history (GdkDevice *device,
- GdkWindow *window,
- guint32 start,
- guint32 stop,
- GdkTimeCoord ***events,
- gint *n_events)
-{
- g_warning ("gdk_device_get_history() called for invalid device");
- return FALSE;
-}
-
-void
-_gdk_input_select_events (GdkWindow *impl_window,
- GdkDevicePrivate *gdkdev)
-{
-}
-
-gboolean
-_gdk_input_other_event (GdkEvent *event,
- XEvent *xevent,
- GdkWindow *window)
-{
- return FALSE;
-}
-
-void
-_gdk_input_configure_event (XConfigureEvent *xevent,
- GdkWindow *window)
-{
-}
-
-void
-_gdk_input_crossing_event (GdkWindow *window,
- gboolean enter)
-{
-}
-
-gint
-_gdk_input_grab_pointer (GdkWindow * window,
- GdkWindow *native_window,
- gint owner_events,
- GdkEventMask event_mask,
- GdkWindow * confine_to,
- guint32 time)
-{
- return Success;
-}
-
-void
-_gdk_input_ungrab_pointer (GdkDisplay *display,
- guint32 time)
-{
-}
-
-gboolean
-gdk_device_set_mode (GdkDevice *device,
- GdkInputMode mode)
-{
- return FALSE;
-}
-
-#define __GDK_INPUT_NONE_C__
-#include "gdkaliasdef.c"
diff --git a/gdk/x11/gdkinput-x11.c b/gdk/x11/gdkinput-x11.c
deleted file mode 100644
index 767b0702c4..0000000000
--- a/gdk/x11/gdkinput-x11.c
+++ /dev/null
@@ -1,937 +0,0 @@
-/* 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 Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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-2000. 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 "gdkinputprivate.h"
-#include "gdkinternals.h"
-#include "gdkx.h"
-#include "gdk.h" /* For gdk_error_trap_push()/pop() */
-#include "gdkdisplay-x11.h"
-#include "gdkalias.h"
-
-#include <string.h>
-
-/* Forward declarations */
-static GdkDevicePrivate *gdk_input_device_new (GdkDisplay *display,
- XDeviceInfo *device,
- gint include_core);
-static void gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
- GdkWindow *window,
- gint *axis_data,
- gdouble *axis_out,
- gdouble *x_out,
- gdouble *y_out);
-static void gdk_input_update_axes (GdkDevicePrivate *gdkdev,
- gint axes_count,
- gint first_axis,
- gint *axis_data);
-static guint gdk_input_translate_state (guint state,
- guint device_state);
-
-GdkDevicePrivate *
-_gdk_input_find_device (GdkDisplay *display,
- guint32 id)
-{
- GList *tmp_list = GDK_DISPLAY_X11 (display)->input_devices;
- GdkDevicePrivate *gdkdev;
- while (tmp_list)
- {
- gdkdev = (GdkDevicePrivate *)(tmp_list->data);
- if (gdkdev->deviceid == id)
- return gdkdev;
- tmp_list = tmp_list->next;
- }
- return NULL;
-}
-
-void
-_gdk_input_get_root_relative_geometry (GdkWindow *window,
- int *x_ret, int *y_ret)
-{
- Window child;
- gint x,y;
-
- XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
- GDK_WINDOW_XWINDOW (window),
- GDK_WINDOW_XROOTWIN (window),
- 0, 0, &x, &y, &child);
-
- if (x_ret)
- *x_ret = x;
- if (y_ret)
- *y_ret = y;
-}
-
-static GdkDevicePrivate *
-gdk_input_device_new (GdkDisplay *display,
- XDeviceInfo *device,
- gint include_core)
-{
- GdkDevicePrivate *gdkdev;
- gchar *tmp_name;
- XAnyClassPtr class;
- gint i,j;
-
- gdkdev = g_object_new (GDK_TYPE_DEVICE, NULL);
-
- gdkdev->deviceid = device->id;
- gdkdev->display = display;
-
- if (device->name[0])
- gdkdev->info.name = g_strdup (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");
-
- 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_ascii_strdown (gdkdev->info.name, -1);
-
- if (strstr (tmp_name, "eraser"))
- gdkdev->info.source = GDK_SOURCE_ERASER;
- else if (strstr (tmp_name, "cursor"))
- gdkdev->info.source = GDK_SOURCE_CURSOR;
- else if (strstr (tmp_name, "wacom") ||
- strstr (tmp_name, "pen"))
- gdkdev->info.source = GDK_SOURCE_PEN;
- else
- gdkdev->info.source = GDK_SOURCE_MOUSE;
-
- g_free(tmp_name);
-
- gdkdev->xdevice = NULL;
-
- /* step through the classes */
-
- gdkdev->info.num_axes = 0;
- gdkdev->info.num_keys = 0;
- gdkdev->info.axes = NULL;
- gdkdev->info.keys = NULL;
- gdkdev->axes = 0;
- gdkdev->info.has_cursor = 0;
- gdkdev->needs_update = FALSE;
- gdkdev->claimed = FALSE;
- memset(gdkdev->button_state, 0, sizeof (gdkdev->button_state));
- gdkdev->button_count = 0;
-
- class = device->inputclassinfo;
- for (i=0;i<device->num_classes;i++)
- {
- switch (class->class) {
- case ButtonClass:
- break;
- case KeyClass:
- {
- XKeyInfo *xki = (XKeyInfo *)class;
- /* Hack to catch XFree86 3.3.1 bug. Other devices better
- * not have exactly 25 keys...
- */
- if ((xki->min_keycode == 8) && (xki->max_keycode == 32))
- {
- gdkdev->info.num_keys = 32;
- gdkdev->min_keycode = 1;
- }
- else
- {
- gdkdev->info.num_keys = xki->max_keycode - xki->min_keycode + 1;
- gdkdev->min_keycode = xki->min_keycode;
- }
- gdkdev->info.keys = g_new (GdkDeviceKey, gdkdev->info.num_keys);
-
- for (j=0; j<gdkdev->info.num_keys; j++)
- {
- gdkdev->info.keys[j].keyval = 0;
- gdkdev->info.keys[j].modifiers = 0;
- }
-
- break;
- }
- case ValuatorClass:
- {
- XValuatorInfo *xvi = (XValuatorInfo *)class;
- gdkdev->info.num_axes = xvi->num_axes;
- gdkdev->axes = g_new (GdkAxisInfo, xvi->num_axes);
- gdkdev->axis_data = g_new0 (gint, xvi->num_axes);
- gdkdev->info.axes = g_new0 (GdkDeviceAxis, 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].use = GDK_AXIS_IGNORE;
- }
- j=0;
- if (j<xvi->num_axes)
- gdk_device_set_axis_use (&gdkdev->info, j++, GDK_AXIS_X);
- if (j<xvi->num_axes)
- gdk_device_set_axis_use (&gdkdev->info, j++, GDK_AXIS_Y);
- if (j<xvi->num_axes)
- gdk_device_set_axis_use (&gdkdev->info, j++, GDK_AXIS_PRESSURE);
- if (j<xvi->num_axes)
- gdk_device_set_axis_use (&gdkdev->info, j++, GDK_AXIS_XTILT);
- if (j<xvi->num_axes)
- gdk_device_set_axis_use (&gdkdev->info, j++, GDK_AXIS_YTILT);
- if (j<xvi->num_axes)
- gdk_device_set_axis_use (&gdkdev->info, j++, GDK_AXIS_WHEEL);
-
- break;
- }
- }
- class = (XAnyClassPtr)(((char *)class) + class->length);
- }
- /* return NULL if no axes */
- if (!gdkdev->info.num_axes || !gdkdev->axes ||
- (!include_core && device->use == IsXPointer))
- goto error;
-
- if (device->use != IsXPointer)
- {
- gdk_error_trap_push ();
- gdkdev->xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (display),
- gdkdev->deviceid);
-
- /* return NULL if device is not ready */
- if (gdk_error_trap_pop ())
- goto error;
- }
-
- gdkdev->buttonpress_type = 0;
- gdkdev->buttonrelease_type = 0;
- gdkdev->keypress_type = 0;
- gdkdev->keyrelease_type = 0;
- gdkdev->motionnotify_type = 0;
- gdkdev->proximityin_type = 0;
- gdkdev->proximityout_type = 0;
- gdkdev->changenotify_type = 0;
-
- return gdkdev;
-
- error:
-
- g_object_unref (gdkdev);
-
- return NULL;
-}
-
-void
-_gdk_input_common_find_events (GdkDevicePrivate *gdkdev,
- gint mask,
- XEventClass *classes,
- int *num_classes)
-{
- gint i;
- XEventClass class;
-
- i = 0;
- if (mask & GDK_BUTTON_PRESS_MASK)
- {
- DeviceButtonPress (gdkdev->xdevice, gdkdev->buttonpress_type,
- class);
- if (class != 0)
- classes[i++] = class;
- DeviceButtonPressGrab (gdkdev->xdevice, 0, class);
- if (class != 0)
- classes[i++] = class;
- }
- if (mask & GDK_BUTTON_RELEASE_MASK)
- {
- DeviceButtonRelease (gdkdev->xdevice, gdkdev->buttonrelease_type,
- class);
- if (class != 0)
- classes[i++] = class;
- }
- if (mask & (GDK_POINTER_MOTION_MASK |
- GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK |
- GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_MOTION_MASK))
- {
- DeviceMotionNotify (gdkdev->xdevice, gdkdev->motionnotify_type, class);
- if (class != 0)
- classes[i++] = class;
- DeviceStateNotify (gdkdev->xdevice, gdkdev->devicestatenotify_type, class);
- if (class != 0)
- classes[i++] = class;
- }
- if (mask & GDK_KEY_PRESS_MASK)
- {
- DeviceKeyPress (gdkdev->xdevice, gdkdev->keypress_type, class);
- if (class != 0)
- classes[i++] = class;
- }
- if (mask & GDK_KEY_RELEASE_MASK)
- {
- DeviceKeyRelease (gdkdev->xdevice, gdkdev->keyrelease_type, 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;
-}
-
-void
-_gdk_input_select_events (GdkWindow *impl_window,
- GdkDevicePrivate *gdkdev)
-{
- XEventClass classes[GDK_MAX_DEVICE_CLASSES];
- gint num_classes;
- guint event_mask;
- GdkWindowObject *w;
- GdkInputWindow *iw;
- GList *l;
-
- event_mask = 0;
- iw = ((GdkWindowObject *)impl_window)->input_window;
-
- if (gdkdev->info.mode != GDK_MODE_DISABLED &&
- iw != NULL)
- {
- for (l = iw->windows; l != NULL; l = l->next)
- {
- w = l->data;
- if (gdkdev->info.has_cursor || (w->extension_events & GDK_ALL_DEVICES_MASK))
- event_mask |= w->extension_events;
- }
- }
- event_mask &= ~GDK_ALL_DEVICES_MASK;
-
- if (event_mask)
- event_mask |= GDK_PROXIMITY_OUT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK;
-
- _gdk_input_common_find_events (gdkdev, event_mask,
- classes, &num_classes);
- XSelectExtensionEvent (GDK_WINDOW_XDISPLAY (impl_window),
- GDK_WINDOW_XWINDOW (impl_window),
- classes, num_classes);
-}
-
-gint
-_gdk_input_common_init (GdkDisplay *display,
- gint include_core)
-{
- XDeviceInfo *devices;
- int num_devices, loop;
- int ignore, event_base;
- GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
-
- /* Init XInput extension */
-
- display_x11->input_devices = NULL;
- if (XQueryExtension (display_x11->xdisplay, "XInputExtension",
- &ignore, &event_base, &ignore))
- {
- gdk_x11_register_standard_event_type (display,
- event_base, 15 /* Number of events */);
-
- devices = XListInputDevices(display_x11->xdisplay, &num_devices);
-
- for(loop=0; loop<num_devices; loop++)
- {
- GdkDevicePrivate *gdkdev = gdk_input_device_new(display,
- &devices[loop],
- include_core);
- if (gdkdev)
- display_x11->input_devices = g_list_append(display_x11->input_devices, gdkdev);
- }
- XFreeDeviceList(devices);
- }
-
- display_x11->input_devices = g_list_append (display_x11->input_devices, display->core_pointer);
-
- return TRUE;
-}
-
-static void
-gdk_input_update_axes (GdkDevicePrivate *gdkdev,
- gint axes_count,
- gint first_axis,
- gint *axis_data)
-{
- int i;
- g_return_if_fail (first_axis >= 0 && first_axis + axes_count <= gdkdev->info.num_axes);
-
- for (i = 0; i < axes_count; i++)
- gdkdev->axis_data[first_axis + i] = axis_data[i];
-}
-
-static void
-gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
- GdkWindow *window,
- gint *axis_data,
- gdouble *axis_out,
- gdouble *x_out,
- gdouble *y_out)
-{
- GdkWindowObject *priv, *impl_window;
-
- int i;
- int x_axis = 0;
- int y_axis = 0;
-
- double device_width, device_height, x_min, y_min;
- double x_offset, y_offset, x_scale, y_scale;
-
- priv = (GdkWindowObject *) window;
- impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
-
- for (i=0; i<gdkdev->info.num_axes; i++)
- {
- switch (gdkdev->info.axes[i].use)
- {
- case GDK_AXIS_X:
- x_axis = i;
- break;
- case GDK_AXIS_Y:
- y_axis = i;
- break;
- default:
- break;
- }
- }
-
- device_width = gdkdev->axes[x_axis].max_value - gdkdev->axes[x_axis].min_value;
- if (device_width > 0)
- {
- x_min = gdkdev->axes[x_axis].min_value;
- }
- else
- {
- device_width = gdk_screen_get_width (gdk_drawable_get_screen (window));
- x_min = 0;
- }
-
- device_height = gdkdev->axes[y_axis].max_value - gdkdev->axes[y_axis].min_value;
- if (device_height > 0)
- {
- y_min = gdkdev->axes[y_axis].min_value;
- }
- else
- {
- device_height = gdk_screen_get_height (gdk_drawable_get_screen (window));
- y_min = 0;
- }
-
- if (gdkdev->info.mode == GDK_MODE_SCREEN)
- {
- x_scale = gdk_screen_get_width (gdk_drawable_get_screen (window)) / device_width;
- y_scale = gdk_screen_get_height (gdk_drawable_get_screen (window)) / device_height;
-
- x_offset = - impl_window->input_window->root_x - priv->abs_x;
- y_offset = - impl_window->input_window->root_y - priv->abs_y;
- }
- else /* GDK_MODE_WINDOW */
- {
- double x_resolution = gdkdev->axes[x_axis].resolution;
- double y_resolution = gdkdev->axes[y_axis].resolution;
- double device_aspect;
- /*
- * Some drivers incorrectly report the resolution of the device
- * as zero (in partiular linuxwacom < 0.5.3 with usb tablets).
- * This causes the device_aspect to become NaN and totally
- * breaks windowed mode. If this is the case, the best we can
- * do is to assume the resolution is non-zero is equal in both
- * directions (which is true for many devices). The absolute
- * value of the resolution doesn't matter since we only use the
- * ratio.
- */
- if ((x_resolution == 0) || (y_resolution == 0))
- {
- x_resolution = 1;
- y_resolution = 1;
- }
- device_aspect = (device_height*y_resolution) /
- (device_width*x_resolution);
- if (device_aspect * priv->width >= priv->height)
- {
- /* device taller than window */
- x_scale = priv->width / device_width;
- y_scale = (x_scale * x_resolution) / y_resolution;
-
- x_offset = 0;
- y_offset = -(device_height * y_scale - priv->height)/2;
- }
- else
- {
- /* window taller than device */
- y_scale = priv->height / device_height;
- x_scale = (y_scale * y_resolution) / x_resolution;
-
- y_offset = 0;
- x_offset = - (device_width * x_scale - priv->width)/2;
- }
- }
-
- for (i=0; i<gdkdev->info.num_axes; i++)
- {
- switch (gdkdev->info.axes[i].use)
- {
- case GDK_AXIS_X:
- axis_out[i] = x_offset + x_scale * (axis_data[x_axis] - x_min);
- if (x_out)
- *x_out = axis_out[i];
- break;
- case GDK_AXIS_Y:
- axis_out[i] = y_offset + y_scale * (axis_data[y_axis] - y_min);
- if (y_out)
- *y_out = axis_out[i];
- break;
- default:
- axis_out[i] =
- (gdkdev->info.axes[i].max * (axis_data[i] - gdkdev->axes[i].min_value) +
- gdkdev->info.axes[i].min * (gdkdev->axes[i].max_value - axis_data[i])) /
- (gdkdev->axes[i].max_value - gdkdev->axes[i].min_value);
- break;
- }
- }
-}
-
-/* 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);
-}
-
-
-gboolean
-_gdk_input_common_other_event (GdkEvent *event,
- XEvent *xevent,
- GdkWindow *window,
- GdkDevicePrivate *gdkdev)
-{
- GdkWindowObject *priv, *impl_window;
- GdkInputWindow *input_window;
-
- priv = (GdkWindowObject *) window;
- impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
- input_window = impl_window->input_window;
-
- if ((xevent->type == gdkdev->buttonpress_type) ||
- (xevent->type == gdkdev->buttonrelease_type))
- {
- XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *)(xevent);
-
- g_return_val_if_fail (xdbe->button < 256, FALSE);
- if (xdbe->type == gdkdev->buttonpress_type)
- {
- event->button.type = GDK_BUTTON_PRESS;
- if (!(gdkdev->button_state[xdbe->button/8] & 1 << (xdbe->button%8)))
- {
- gdkdev->button_state[xdbe->button/8] |= 1 << (xdbe->button%8);
- gdkdev->button_count++;
- }
- }
- else
- {
- event->button.type = GDK_BUTTON_RELEASE;
- if (gdkdev->button_state[xdbe->button/8] & 1 << (xdbe->button%8))
- {
- gdkdev->button_state[xdbe->button/8] &= ~(1 << (xdbe->button%8));
- gdkdev->button_count--;
- }
- }
- event->button.device = &gdkdev->info;
- event->button.window = window;
- event->button.time = xdbe->time;
-
- event->button.axes = g_new (gdouble, gdkdev->info.num_axes);
- gdk_input_update_axes (gdkdev, xdbe->axes_count, xdbe->first_axis,
- xdbe->axis_data);
- gdk_input_translate_coordinates (gdkdev, window, gdkdev->axis_data,
- event->button.axes,
- &event->button.x, &event->button.y);
- event->button.x_root = event->button.x + priv->abs_x + input_window->root_x;
- event->button.y_root = event->button.y + priv->abs_y + input_window->root_y;
- event->button.state = gdk_input_translate_state (xdbe->state,xdbe->device_state);
- event->button.button = xdbe->button;
-
- if (event->button.type == GDK_BUTTON_PRESS)
- _gdk_event_button_generate (gdk_drawable_get_display (event->button.window),
- event);
-
- GDK_NOTE (EVENTS,
- g_print ("button %s:\t\twindow: %ld device: %ld x,y: %f %f button: %d\n",
- (event->button.type == GDK_BUTTON_PRESS) ? "press" : "release",
- xdbe->window,
- xdbe->deviceid,
- event->button.x, event->button.y,
- xdbe->button));
-
- /* Update the timestamp of the latest user interaction, if the event has
- * a valid timestamp.
- */
- if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
- gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
- gdk_event_get_time (event));
- return TRUE;
- }
-
- if ((xevent->type == gdkdev->keypress_type) ||
- (xevent->type == gdkdev->keyrelease_type))
- {
- XDeviceKeyEvent *xdke = (XDeviceKeyEvent *)(xevent);
-
- GDK_NOTE (EVENTS,
- g_print ("device key %s:\twindow: %ld device: %ld keycode: %d\n",
- (event->key.type == GDK_KEY_PRESS) ? "press" : "release",
- xdke->window,
- xdke->deviceid,
- xdke->keycode));
-
- if (xdke->keycode < gdkdev->min_keycode ||
- xdke->keycode >= gdkdev->min_keycode + gdkdev->info.num_keys)
- {
- g_warning ("Invalid device key code received");
- return FALSE;
- }
-
- event->key.keyval = gdkdev->info.keys[xdke->keycode - gdkdev->min_keycode].keyval;
-
- if (event->key.keyval == 0)
- {
- GDK_NOTE (EVENTS,
- g_print ("\t\ttranslation - NONE\n"));
-
- return FALSE;
- }
-
- event->key.type = (xdke->type == gdkdev->keypress_type) ?
- GDK_KEY_PRESS : GDK_KEY_RELEASE;
-
- event->key.window = window;
- event->key.time = xdke->time;
-
- event->key.state = gdk_input_translate_state(xdke->state, xdke->device_state)
- | gdkdev->info.keys[xdke->keycode - gdkdev->min_keycode].modifiers;
-
- /* Add a string translation for the key event */
- if ((event->key.keyval >= 0x20) && (event->key.keyval <= 0xFF))
- {
- event->key.length = 1;
- event->key.string = g_new (gchar, 2);
- event->key.string[0] = (gchar)event->key.keyval;
- event->key.string[1] = 0;
- }
- else
- {
- event->key.length = 0;
- event->key.string = g_new0 (gchar, 1);
- }
-
- GDK_NOTE (EVENTS,
- g_print ("\t\ttranslation - keyval: %d modifiers: %#x\n",
- event->key.keyval,
- event->key.state));
-
- /* Update the timestamp of the latest user interaction, if the event has
- * a valid timestamp.
- */
- if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
- gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
- gdk_event_get_time (event));
- return TRUE;
- }
-
- if (xevent->type == gdkdev->motionnotify_type)
- {
- XDeviceMotionEvent *xdme = (XDeviceMotionEvent *)(xevent);
-
- event->motion.device = &gdkdev->info;
-
- event->motion.axes = g_new (gdouble, gdkdev->info.num_axes);
- gdk_input_update_axes (gdkdev, xdme->axes_count, xdme->first_axis, xdme->axis_data);
- gdk_input_translate_coordinates(gdkdev, window, gdkdev->axis_data,
- event->motion.axes,
- &event->motion.x,&event->motion.y);
- event->motion.x_root = event->motion.x + priv->abs_x + input_window->root_x;
- event->motion.y_root = event->motion.y + priv->abs_y + input_window->root_y;
-
- event->motion.type = GDK_MOTION_NOTIFY;
- event->motion.window = window;
- event->motion.time = xdme->time;
- event->motion.state = gdk_input_translate_state(xdme->state,
- xdme->device_state);
- event->motion.is_hint = xdme->is_hint;
-
- GDK_NOTE (EVENTS,
- g_print ("motion notify:\t\twindow: %ld device: %ld x,y: %f %f state %#4x hint: %s\n",
- xdme->window,
- xdme->deviceid,
- event->motion.x, event->motion.y,
- event->motion.state,
- (xdme->is_hint) ? "true" : "false"));
-
-
- /* Update the timestamp of the latest user interaction, if the event has
- * a valid timestamp.
- */
- if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
- gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
- gdk_event_get_time (event));
- return TRUE;
- }
-
- if (xevent->type == gdkdev->devicestatenotify_type)
- {
- int i;
- XDeviceStateNotifyEvent *xdse = (XDeviceStateNotifyEvent *)(xevent);
- XInputClass *input_class = (XInputClass *)xdse->data;
- for (i=0; i<xdse->num_classes; i++)
- {
- if (input_class->class == ValuatorClass)
- gdk_input_update_axes (gdkdev, gdkdev->info.num_axes, 0,
- ((XValuatorState *)input_class)->valuators);
- input_class = (XInputClass *)(((char *)input_class)+input_class->length);
- }
-
- GDK_NOTE (EVENTS,
- g_print ("device state notify:\t\twindow: %ld device: %ld\n",
- xdse->window,
- xdse->deviceid));
-
- return FALSE;
- }
- if (xevent->type == gdkdev->proximityin_type ||
- xevent->type == gdkdev->proximityout_type)
- {
- XProximityNotifyEvent *xpne = (XProximityNotifyEvent *)(xevent);
-
- event->proximity.device = &gdkdev->info;
- event->proximity.type = (xevent->type == gdkdev->proximityin_type)?
- GDK_PROXIMITY_IN:GDK_PROXIMITY_OUT;
- event->proximity.window = window;
- event->proximity.time = xpne->time;
-
- /* Update the timestamp of the latest user interaction, if the event has
- * a valid timestamp.
- */
- if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
- gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
- gdk_event_get_time (event));
- return TRUE;
- }
-
- return FALSE; /* wasn't one of our event types */
-}
-
-gboolean
-_gdk_input_common_event_selected (GdkEvent *event,
- GdkWindow *window,
- GdkDevicePrivate *gdkdev)
-{
- GdkWindowObject *priv = (GdkWindowObject *) window;
-
- switch (event->type) {
- case GDK_BUTTON_PRESS:
- return priv->extension_events & GDK_BUTTON_PRESS_MASK;
-
- case GDK_BUTTON_RELEASE:
- return priv->extension_events & GDK_BUTTON_RELEASE_MASK;
-
- case GDK_KEY_PRESS:
- return priv->extension_events & GDK_KEY_PRESS_MASK;
-
- case GDK_KEY_RELEASE:
- return priv->extension_events & GDK_KEY_RELEASE_MASK;
-
- case GDK_MOTION_NOTIFY:
- if (priv->extension_events & GDK_POINTER_MOTION_MASK)
- return TRUE;
- if (gdkdev->button_count && (priv->extension_events & GDK_BUTTON_MOTION_MASK))
- return TRUE;
-
- if ((gdkdev->button_state[0] & 1 << 1) && (priv->extension_events & GDK_BUTTON1_MOTION_MASK))
- return TRUE;
- if ((gdkdev->button_state[0] & 1 << 2) && (priv->extension_events & GDK_BUTTON2_MOTION_MASK))
- return TRUE;
- if ((gdkdev->button_state[0] & 1 << 3) && (priv->extension_events & GDK_BUTTON3_MOTION_MASK))
- return TRUE;
-
- return FALSE;
-
- case GDK_PROXIMITY_IN:
- return priv->extension_events & GDK_PROXIMITY_IN_MASK;
-
- case GDK_PROXIMITY_OUT:
- return priv->extension_events & GDK_PROXIMITY_OUT_MASK;
-
- default:
- return FALSE;
- }
-
-
-}
-
-
-gboolean
-_gdk_device_get_history (GdkDevice *device,
- GdkWindow *window,
- guint32 start,
- guint32 stop,
- GdkTimeCoord ***events,
- gint *n_events)
-{
- GdkTimeCoord **coords;
- XDeviceTimeCoord *device_coords;
- GdkWindow *impl_window;
- GdkDevicePrivate *gdkdev;
- gint mode_return;
- gint axis_count_return;
- gint i;
-
- gdkdev = (GdkDevicePrivate *)device;
-
- impl_window = _gdk_window_get_impl_window (window);
-
- device_coords = XGetDeviceMotionEvents (GDK_WINDOW_XDISPLAY (impl_window),
- gdkdev->xdevice,
- start, stop,
- n_events, &mode_return,
- &axis_count_return);
-
- if (device_coords)
- {
- coords = _gdk_device_allocate_history (device, *n_events);
-
- for (i = 0; i < *n_events; i++)
- {
- coords[i]->time = device_coords[i].time;
-
- gdk_input_translate_coordinates (gdkdev, window,
- device_coords[i].data,
- coords[i]->axes, NULL, NULL);
- }
-
- XFreeDeviceMotionEvents (device_coords);
-
- *events = coords;
-
- return TRUE;
- }
- else
- return FALSE;
-}
-
-/**
- * gdk_device_get_state:
- * @device: a #GdkDevice.
- * @window: a #GdkWindow.
- * @axes: an array of doubles to store the values of the axes of @device in,
- * or %NULL.
- * @mask: location to store the modifiers, or %NULL.
- *
- * Gets the current state of a device.
- */
-void
-gdk_device_get_state (GdkDevice *device,
- GdkWindow *window,
- gdouble *axes,
- GdkModifierType *mask)
-{
- gint i;
-
- g_return_if_fail (device != NULL);
- g_return_if_fail (GDK_IS_WINDOW (window));
-
- if (GDK_IS_CORE (device))
- {
- gint x_int, y_int;
-
- gdk_window_get_pointer (window, &x_int, &y_int, mask);
-
- if (axes)
- {
- axes[0] = x_int;
- axes[1] = y_int;
- }
- }
- else
- {
- GdkDevicePrivate *gdkdev;
- XDeviceState *state;
- XInputClass *input_class;
-
- if (mask)
- gdk_window_get_pointer (window, NULL, NULL, mask);
-
- gdkdev = (GdkDevicePrivate *)device;
-
- state = XQueryDeviceState (GDK_WINDOW_XDISPLAY (window),
- gdkdev->xdevice);
- input_class = state->data;
- for (i=0; i<state->num_classes; i++)
- {
- switch (input_class->class)
- {
- case ValuatorClass:
- if (axes)
- gdk_input_translate_coordinates (gdkdev, window,
- ((XValuatorState *)input_class)->valuators,
- axes, NULL, NULL);
- break;
-
- case ButtonClass:
- if (mask)
- {
- *mask &= 0xFF;
- if (((XButtonState *)input_class)->num_buttons > 0)
- *mask |= ((XButtonState *)input_class)->buttons[0] << 7;
- /* GDK_BUTTON1_MASK = 1 << 8, and button n is stored
- * in bit 1<<(n%8) in byte n/8. n = 1,2,... */
- }
- break;
- }
- input_class = (XInputClass *)(((char *)input_class)+input_class->length);
- }
- XFreeDeviceState (state);
- }
-}
-
-#define __GDK_INPUT_X11_C__
-#include "gdkaliasdef.c"
diff --git a/gdk/x11/gdkinput-xfree.c b/gdk/x11/gdkinput-xfree.c
deleted file mode 100644
index bf63959f31..0000000000
--- a/gdk/x11/gdkinput-xfree.c
+++ /dev/null
@@ -1,422 +0,0 @@
-/* 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 Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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.
- */
-
-#include "config.h"
-#include <string.h>
-#include "gdkinputprivate.h"
-#include "gdkdisplay-x11.h"
-#include "gdkalias.h"
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. 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/.
- */
-
-/* forward declarations */
-
-static void gdk_input_check_proximity (GdkDisplay *display);
-
-void
-_gdk_input_init(GdkDisplay *display)
-{
- _gdk_init_input_core (display);
- display->ignore_core_events = FALSE;
- _gdk_input_common_init (display, FALSE);
-}
-
-gboolean
-gdk_device_set_mode (GdkDevice *device,
- GdkInputMode mode)
-{
- GList *tmp_list;
- GdkDevicePrivate *gdkdev;
- GdkInputWindow *input_window;
- GdkDisplayX11 *display_impl;
-
- if (GDK_IS_CORE (device))
- return FALSE;
-
- gdkdev = (GdkDevicePrivate *)device;
-
- if (device->mode == mode)
- return TRUE;
-
- device->mode = mode;
-
- if (mode == GDK_MODE_WINDOW)
- device->has_cursor = FALSE;
- else if (mode == GDK_MODE_SCREEN)
- device->has_cursor = TRUE;
-
- display_impl = GDK_DISPLAY_X11 (gdkdev->display);
- for (tmp_list = display_impl->input_windows; tmp_list; tmp_list = tmp_list->next)
- {
- input_window = (GdkInputWindow *)tmp_list->data;
- _gdk_input_select_events (input_window->impl_window, gdkdev);
- }
-
- return TRUE;
-}
-
-static void
-gdk_input_check_proximity (GdkDisplay *display)
-{
- GdkDisplayX11 *display_impl = GDK_DISPLAY_X11 (display);
- GList *tmp_list = display_impl->input_devices;
- gint new_proximity = 0;
-
- while (tmp_list && !new_proximity)
- {
- GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data);
-
- if (gdkdev->info.mode != GDK_MODE_DISABLED
- && !GDK_IS_CORE (gdkdev)
- && gdkdev->xdevice)
- {
- XDeviceState *state = XQueryDeviceState(display_impl->xdisplay,
- gdkdev->xdevice);
- XInputClass *xic;
- int i;
-
- xic = state->data;
- for (i=0; i<state->num_classes; i++)
- {
- if (xic->class == ValuatorClass)
- {
- XValuatorState *xvs = (XValuatorState *)xic;
- if ((xvs->mode & ProximityState) == InProximity)
- {
- new_proximity = TRUE;
- }
- break;
- }
- xic = (XInputClass *)((char *)xic + xic->length);
- }
-
- XFreeDeviceState (state);
- }
- tmp_list = tmp_list->next;
- }
-
- display->ignore_core_events = new_proximity;
-}
-
-void
-_gdk_input_configure_event (XConfigureEvent *xevent,
- GdkWindow *window)
-{
- GdkWindowObject *priv = (GdkWindowObject *)window;
- GdkInputWindow *input_window;
- gint root_x, root_y;
-
- input_window = priv->input_window;
- if (input_window != NULL)
- {
- _gdk_input_get_root_relative_geometry (window, &root_x, &root_y);
- input_window->root_x = root_x;
- input_window->root_y = root_y;
- }
-}
-
-void
-_gdk_input_crossing_event (GdkWindow *window,
- gboolean enter)
-{
- GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
- GdkDisplayX11 *display_impl = GDK_DISPLAY_X11 (display);
- GdkWindowObject *priv = (GdkWindowObject *)window;
- GdkInputWindow *input_window;
- gint root_x, root_y;
-
- if (enter)
- {
- gdk_input_check_proximity(display);
-
- input_window = priv->input_window;
- if (input_window != NULL)
- {
- _gdk_input_get_root_relative_geometry (window, &root_x, &root_y);
- input_window->root_x = root_x;
- input_window->root_y = root_y;
- }
- }
- else
- display->ignore_core_events = FALSE;
-}
-
-static GdkEventType
-get_input_event_type (GdkDevicePrivate *gdkdev,
- XEvent *xevent,
- int *core_x, int *core_y)
-{
- if (xevent->type == gdkdev->buttonpress_type)
- {
- XDeviceButtonEvent *xie = (XDeviceButtonEvent *)(xevent);
- *core_x = xie->x;
- *core_y = xie->y;
- return GDK_BUTTON_PRESS;
- }
-
- if (xevent->type == gdkdev->buttonrelease_type)
- {
- XDeviceButtonEvent *xie = (XDeviceButtonEvent *)(xevent);
- *core_x = xie->x;
- *core_y = xie->y;
- return GDK_BUTTON_RELEASE;
- }
-
- if (xevent->type == gdkdev->keypress_type)
- {
- XDeviceKeyEvent *xie = (XDeviceKeyEvent *)(xevent);
- *core_x = xie->x;
- *core_y = xie->y;
- return GDK_KEY_PRESS;
- }
-
- if (xevent->type == gdkdev->keyrelease_type)
- {
- XDeviceKeyEvent *xie = (XDeviceKeyEvent *)(xevent);
- *core_x = xie->x;
- *core_y = xie->y;
- return GDK_KEY_RELEASE;
- }
-
- if (xevent->type == gdkdev->motionnotify_type)
- {
- XDeviceMotionEvent *xie = (XDeviceMotionEvent *)(xevent);
- *core_x = xie->x;
- *core_y = xie->y;
- return GDK_MOTION_NOTIFY;
- }
-
- if (xevent->type == gdkdev->proximityin_type)
- {
- XProximityNotifyEvent *xie = (XProximityNotifyEvent *)(xevent);
- *core_x = xie->x;
- *core_y = xie->y;
- return GDK_PROXIMITY_IN;
- }
-
- if (xevent->type == gdkdev->proximityout_type)
- {
- XProximityNotifyEvent *xie = (XProximityNotifyEvent *)(xevent);
- *core_x = xie->x;
- *core_y = xie->y;
- return GDK_PROXIMITY_OUT;
- }
-
- *core_x = 0;
- *core_y = 0;
- return GDK_NOTHING;
-}
-
-
-gboolean
-_gdk_input_other_event (GdkEvent *event,
- XEvent *xevent,
- GdkWindow *event_window)
-{
- GdkWindow *window;
- GdkWindowObject *priv;
- GdkInputWindow *iw;
- GdkDevicePrivate *gdkdev;
- GdkEventType event_type;
- int x, y;
- GdkDisplay *display = GDK_WINDOW_DISPLAY (event_window);
- GdkDisplayX11 *display_impl = GDK_DISPLAY_X11 (display);
-
- /* This is a sort of a hack, as there isn't any XDeviceAnyEvent -
- but it's potentially faster than scanning through the types of
- every device. If we were deceived, then it won't match any of
- the types for the device anyways */
- gdkdev = _gdk_input_find_device (display,
- ((XDeviceButtonEvent *)xevent)->deviceid);
- if (!gdkdev)
- return FALSE; /* we don't handle it - not an XInput event */
-
- event_type = get_input_event_type (gdkdev, xevent, &x, &y);
- if (event_type == GDK_NOTHING)
- return FALSE;
-
- /* If we're not getting any event window its likely because we're outside the
- window and there is no grab. We should still report according to the
- implicit grab though. */
- iw = ((GdkWindowObject *)event_window)->input_window;
-
- if (iw->button_down_window)
- window = iw->button_down_window;
- else
- window = _gdk_window_get_input_window_for_event (event_window,
- event_type,
- x, y,
- xevent->xany.serial);
- priv = (GdkWindowObject *)window;
- if (window == NULL)
- return FALSE;
-
- if (gdkdev->info.mode == GDK_MODE_DISABLED ||
- priv->extension_events == 0 ||
- !(gdkdev->info.has_cursor || (priv->extension_events & GDK_ALL_DEVICES_MASK)))
- return FALSE;
-
- if (!display->ignore_core_events && priv->extension_events != 0)
- gdk_input_check_proximity (GDK_WINDOW_DISPLAY (window));
-
- if (!_gdk_input_common_other_event (event, xevent, window, gdkdev))
- return FALSE;
-
- if (event->type == GDK_BUTTON_PRESS)
- iw->button_down_window = window;
- if (event->type == GDK_BUTTON_RELEASE && !gdkdev->button_count)
- iw->button_down_window = NULL;
-
- if (event->type == GDK_PROXIMITY_OUT &&
- display->ignore_core_events)
- gdk_input_check_proximity (GDK_WINDOW_DISPLAY (window));
-
- return _gdk_input_common_event_selected(event, window, gdkdev);
-}
-
-gint
-_gdk_input_grab_pointer (GdkWindow *window,
- GdkWindow *native_window, /* This is the toplevel */
- gint owner_events,
- GdkEventMask event_mask,
- GdkWindow * confine_to,
- guint32 time)
-{
- GdkInputWindow *input_window;
- GdkWindowObject *priv, *impl_window;
- gboolean need_ungrab;
- GdkDevicePrivate *gdkdev;
- GList *tmp_list;
- XEventClass event_classes[GDK_MAX_DEVICE_CLASSES];
- gint num_classes;
- gint result;
- GdkDisplayX11 *display_impl = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
-
- tmp_list = display_impl->input_windows;
- need_ungrab = FALSE;
-
- while (tmp_list)
- {
- input_window = (GdkInputWindow *)tmp_list->data;
-
- if (input_window->grabbed)
- {
- input_window->grabbed = FALSE;
- need_ungrab = TRUE;
- break;
- }
- tmp_list = tmp_list->next;
- }
-
- priv = (GdkWindowObject *)window;
- impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
- input_window = impl_window->input_window;
- if (priv->extension_events)
- {
- g_assert (input_window != NULL);
- input_window->grabbed = TRUE;
-
- tmp_list = display_impl->input_devices;
- while (tmp_list)
- {
- gdkdev = (GdkDevicePrivate *)tmp_list->data;
- if (!GDK_IS_CORE (gdkdev) && gdkdev->xdevice)
- {
- _gdk_input_common_find_events (gdkdev, event_mask,
- event_classes, &num_classes);
-#ifdef G_ENABLE_DEBUG
- if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
- result = GrabSuccess;
- else
-#endif
- result = XGrabDevice (display_impl->xdisplay, gdkdev->xdevice,
- GDK_WINDOW_XWINDOW (native_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;
- }
- tmp_list = tmp_list->next;
- }
- }
- else
- {
- tmp_list = display_impl->input_devices;
- while (tmp_list)
- {
- gdkdev = (GdkDevicePrivate *)tmp_list->data;
- if (!GDK_IS_CORE (gdkdev) && gdkdev->xdevice &&
- ((gdkdev->button_count != 0) || need_ungrab))
- {
- XUngrabDevice (display_impl->xdisplay, gdkdev->xdevice, time);
- memset (gdkdev->button_state, 0, sizeof (gdkdev->button_state));
- gdkdev->button_count = 0;
- }
-
- tmp_list = tmp_list->next;
- }
- }
-
- return Success;
-}
-
-void
-_gdk_input_ungrab_pointer (GdkDisplay *display,
- guint32 time)
-{
- GdkInputWindow *input_window = NULL; /* Quiet GCC */
- GdkDevicePrivate *gdkdev;
- GList *tmp_list;
- GdkDisplayX11 *display_impl = GDK_DISPLAY_X11 (display);
-
- tmp_list = display_impl->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 = display_impl->input_devices;
- while (tmp_list)
- {
- gdkdev = (GdkDevicePrivate *)tmp_list->data;
- if (!GDK_IS_CORE (gdkdev) && gdkdev->xdevice)
- XUngrabDevice( display_impl->xdisplay, gdkdev->xdevice, time);
-
- tmp_list = tmp_list->next;
- }
- }
-}
-
-#define __GDK_INPUT_XFREE_C__
-#include "gdkaliasdef.c"
diff --git a/gdk/x11/gdkinput.c b/gdk/x11/gdkinput.c
index fb2f810cea..208d2c3856 100644
--- a/gdk/x11/gdkinput.c
+++ b/gdk/x11/gdkinput.c
@@ -27,115 +27,23 @@
#include "config.h"
#include <stdlib.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include "gdkx.h"
-#include "gdkinput.h"
-#include "gdkprivate.h"
-#include "gdkinputprivate.h"
#include "gdkscreen-x11.h"
#include "gdkdisplay-x11.h"
+#include "gdkwindow.h"
#include "gdkalias.h"
-static GdkDeviceAxis gdk_input_core_axes[] = {
- { GDK_AXIS_X, 0, 0 },
- { GDK_AXIS_Y, 0, 0 }
-};
-
-void
-_gdk_init_input_core (GdkDisplay *display)
-{
- GdkDevicePrivate *private;
-
- display->core_pointer = g_object_new (GDK_TYPE_DEVICE, NULL);
- private = (GdkDevicePrivate *)display->core_pointer;
-
- display->core_pointer->name = "Core Pointer";
- display->core_pointer->source = GDK_SOURCE_MOUSE;
- display->core_pointer->mode = GDK_MODE_SCREEN;
- display->core_pointer->has_cursor = TRUE;
- display->core_pointer->num_axes = 2;
- display->core_pointer->axes = gdk_input_core_axes;
- display->core_pointer->num_keys = 0;
- display->core_pointer->keys = NULL;
-
- private->display = display;
-}
-
-static void gdk_device_class_init (GdkDeviceClass *klass);
-static void gdk_device_dispose (GObject *object);
-
-static gpointer gdk_device_parent_class = NULL;
-
-GType
-gdk_device_get_type (void)
-{
- static GType object_type = 0;
-
- if (!object_type)
- {
- const GTypeInfo object_info =
- {
- sizeof (GdkDeviceClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gdk_device_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GdkDevicePrivate),
- 0, /* n_preallocs */
- (GInstanceInitFunc) NULL,
- };
-
- object_type = g_type_register_static (G_TYPE_OBJECT,
- g_intern_static_string ("GdkDevice"),
- &object_info, 0);
- }
+/* Addition used for extension_events mask */
+#define GDK_ALL_DEVICES_MASK (1<<30)
- return object_type;
-}
-
-static void
-gdk_device_class_init (GdkDeviceClass *klass)
+struct _GdkInputWindow
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- gdk_device_parent_class = g_type_class_peek_parent (klass);
-
- object_class->dispose = gdk_device_dispose;
-}
+ GList *windows; /* GdkWindow:s with extension_events set */
-static void
-gdk_device_dispose (GObject *object)
-{
- GdkDevicePrivate *gdkdev = (GdkDevicePrivate *) object;
-
- if (gdkdev->display && !GDK_IS_CORE (gdkdev))
- {
-#ifndef XINPUT_NONE
- if (gdkdev->xdevice)
- {
- XCloseDevice (GDK_DISPLAY_XDISPLAY (gdkdev->display), gdkdev->xdevice);
- gdkdev->xdevice = NULL;
- }
- g_free (gdkdev->axes);
- g_free (gdkdev->axis_data);
- gdkdev->axes = NULL;
- gdkdev->axis_data = NULL;
-#endif /* !XINPUT_NONE */
-
- g_free (gdkdev->info.name);
- g_free (gdkdev->info.keys);
- g_free (gdkdev->info.axes);
-
- gdkdev->info.name = NULL;
- gdkdev->info.keys = NULL;
- gdkdev->info.axes = NULL;
- }
+ /* gdk window */
+ GdkWindow *impl_window; /* an impl window */
+};
- G_OBJECT_CLASS (gdk_device_parent_class)->dispose (object);
-}
/**
* gdk_devices_list:
@@ -144,6 +52,8 @@ gdk_device_dispose (GObject *object)
* The list is statically allocated and should not be freed.
*
* Return value: a list of #GdkDevice
+ *
+ * Deprecated: 3.0. Use gdk_device_manager_list_devices() instead.
**/
GList *
gdk_devices_list (void)
@@ -151,348 +61,46 @@ gdk_devices_list (void)
return gdk_display_list_devices (gdk_display_get_default ());
}
-/**
- * gdk_display_list_devices:
- * @display: a #GdkDisplay
- *
- * Returns the list of available input devices attached to @display.
- * The list is statically allocated and should not be freed.
- *
- * Return value: a list of #GdkDevice
- *
- * Since: 2.2
- **/
-GList *
-gdk_display_list_devices (GdkDisplay *display)
-{
- g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
-
- return GDK_DISPLAY_X11 (display)->input_devices;
-}
-
-/**
- * gdk_device_get_name:
- * @device: a #GdkDevice
- *
- * Determines the name of the device.
- *
- * Return value: a name
- *
- * Since: 2.22
- **/
-const gchar *
-gdk_device_get_name (GdkDevice *device)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
-
- return device->name;
-}
-
-/**
- * gdk_device_get_source:
- * @device: a #GdkDevice
- *
- * Determines the type of the device.
- *
- * Return value: a #GdkInputSource
- *
- * Since: 2.22
- **/
-GdkInputSource
-gdk_device_get_source (GdkDevice *device)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
-
- return device->source;
-}
-
-/**
- * gdk_device_get_mode:
- * @device: a #GdkDevice
- *
- * Determines the mode of the device.
- *
- * Return value: a #GdkInputSource
- *
- * Since: 2.22
- **/
-GdkInputMode
-gdk_device_get_mode (GdkDevice *device)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
-
- return device->mode;
-}
-
-/**
- * gdk_device_get_has_cursor:
- * @device: a #GdkDevice
- *
- * Determines whether the pointer follows device motion.
- *
- * Return value: %TRUE if the pointer follows device motion
- *
- * Since: 2.22
- **/
-gboolean
-gdk_device_get_has_cursor (GdkDevice *device)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
-
- return device->has_cursor;
-}
-
-void
-gdk_device_set_source (GdkDevice *device,
- GdkInputSource source)
-{
- g_return_if_fail (device != NULL);
-
- device->source = source;
-}
-
-/**
- * gdk_device_get_key:
- * @device: a #GdkDevice.
- * @index: the index of the macro button to get.
- * @keyval: return value for the keyval.
- * @modifiers: return value for modifiers.
- *
- * If @index has a valid keyval, this function will
- * fill in @keyval and @modifiers with the keyval settings.
- *
- * Since: 2.22
- **/
-void
-gdk_device_get_key (GdkDevice *device,
- guint index,
- guint *keyval,
- GdkModifierType *modifiers)
+static void
+_gdk_input_select_device_events (GdkWindow *impl_window,
+ GdkDevice *device)
{
- g_return_if_fail (GDK_IS_DEVICE (device));
- g_return_if_fail (index < device->num_keys);
-
- if (!device->keys[index].keyval &&
- !device->keys[index].modifiers)
+ guint event_mask;
+ GdkWindowObject *w;
+ GdkInputWindow *iw;
+ GdkInputMode mode;
+ gboolean has_cursor;
+ GdkDeviceType type;
+ GList *l;
+
+ event_mask = 0;
+ iw = ((GdkWindowObject *)impl_window)->input_window;
+
+ g_object_get (device,
+ "type", &type,
+ "input-mode", &mode,
+ "has-cursor", &has_cursor,
+ NULL);
+
+ if (iw == NULL ||
+ mode == GDK_MODE_DISABLED ||
+ type == GDK_DEVICE_TYPE_MASTER)
return;
- if (keyval)
- *keyval = device->keys[index].keyval;
-
- if (modifiers)
- *modifiers = device->keys[index].modifiers;
-}
-
-void
-gdk_device_set_key (GdkDevice *device,
- guint index,
- guint keyval,
- GdkModifierType modifiers)
-{
- g_return_if_fail (device != NULL);
- g_return_if_fail (index < device->num_keys);
-
- device->keys[index].keyval = keyval;
- device->keys[index].modifiers = modifiers;
-}
-
-/**
- * gdk_device_get_axis_use:
- * @device: a #GdkDevice.
- * @index: the index of the axis.
- *
- * Returns the axis use for @index.
- *
- * Returns: a #GdkAxisUse specifying how the axis is used.
- *
- * Since: 2.22
- **/
-GdkAxisUse
-gdk_device_get_axis_use (GdkDevice *device,
- guint index)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), GDK_AXIS_IGNORE);
- g_return_val_if_fail (index < device->num_axes, GDK_AXIS_IGNORE);
-
- return device->axes[index].use;
-}
-
-void
-gdk_device_set_axis_use (GdkDevice *device,
- guint index,
- GdkAxisUse use)
-{
- g_return_if_fail (device != NULL);
- g_return_if_fail (index < device->num_axes);
-
- device->axes[index].use = use;
-
- switch (use)
+ for (l = iw->windows; l != NULL; l = l->next)
{
- case GDK_AXIS_X:
- case GDK_AXIS_Y:
- device->axes[index].min = 0.;
- device->axes[index].max = 0.;
- break;
- case GDK_AXIS_XTILT:
- case GDK_AXIS_YTILT:
- device->axes[index].min = -1.;
- device->axes[index].max = 1;
- break;
- default:
- device->axes[index].min = 0.;
- device->axes[index].max = 1;
- break;
- }
-}
-
-static gboolean
-impl_coord_in_window (GdkWindow *window,
- int impl_x,
- int impl_y)
-{
- GdkWindowObject *priv = (GdkWindowObject *)window;
-
- if (impl_x < priv->abs_x ||
- impl_x > priv->abs_x + priv->width)
- return FALSE;
- if (impl_y < priv->abs_y ||
- impl_y > priv->abs_y + priv->height)
- return FALSE;
- return TRUE;
-}
+ w = l->data;
-/**
- * gdk_device_get_history:
- * @device: a #GdkDevice
- * @window: the window with respect to which which the event coordinates will be reported
- * @start: starting timestamp for range of events to return
- * @stop: ending timestamp for the range of events to return
- * @events: (array length=n_events) (out) (transfer none): location to store a newly-allocated array of #GdkTimeCoord, or %NULL
- * @n_events: location to store the length of @events, or %NULL
- *
- * Obtains the motion history for a device; given a starting and
- * ending timestamp, return all events in the motion history for
- * the device in the given range of time. Some windowing systems
- * do not support motion history, in which case, %FALSE will
- * be returned. (This is not distinguishable from the case where
- * motion history is supported and no events were found.)
- *
- * Return value: %TRUE if the windowing system supports motion history and
- * at least one event was found.
- **/
-gboolean
-gdk_device_get_history (GdkDevice *device,
- GdkWindow *window,
- guint32 start,
- guint32 stop,
- GdkTimeCoord ***events,
- gint *n_events)
-{
- GdkTimeCoord **coords = NULL;
- GdkWindow *impl_window;
- gboolean result = FALSE;
- int tmp_n_events = 0;
+ if (has_cursor || (w->extension_events & GDK_ALL_DEVICES_MASK))
+ {
+ event_mask = w->extension_events;
- g_return_val_if_fail (GDK_WINDOW_IS_X11 (window), FALSE);
+ if (event_mask)
+ event_mask |= GDK_PROXIMITY_OUT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK;
- impl_window = _gdk_window_get_impl_window (window);
-
- if (GDK_WINDOW_DESTROYED (window))
- /* Nothing */ ;
- else if (GDK_IS_CORE (device))
- {
- XTimeCoord *xcoords;
-
- xcoords = XGetMotionEvents (GDK_DRAWABLE_XDISPLAY (window),
- GDK_DRAWABLE_XID (impl_window),
- start, stop, &tmp_n_events);
- if (xcoords)
- {
- GdkWindowObject *priv = (GdkWindowObject *)window;
- int i, j;
-
- coords = _gdk_device_allocate_history (device, tmp_n_events);
- j = 0;
-
- for (i = 0; i < tmp_n_events; i++)
- {
- if (impl_coord_in_window (window, xcoords[i].x, xcoords[i].y))
- {
- coords[j]->time = xcoords[i].time;
- coords[j]->axes[0] = xcoords[i].x - priv->abs_x;
- coords[j]->axes[1] = xcoords[i].y - priv->abs_y;
- j++;
- }
- }
-
- XFree (xcoords);
-
- /* free the events we allocated too much */
- for (i = j; i < tmp_n_events; i++)
- {
- g_free (coords[i]);
- coords[i] = NULL;
- }
-
- tmp_n_events = j;
-
- if (tmp_n_events > 0)
- {
- result = TRUE;
- }
- else
- {
- gdk_device_free_history (coords, tmp_n_events);
- coords = NULL;
- }
- }
+ gdk_window_set_device_events ((GdkWindow *) w, device, event_mask);
+ }
}
- else
- result = _gdk_device_get_history (device, window, start, stop, &coords, &tmp_n_events);
-
- if (n_events)
- *n_events = tmp_n_events;
-
- if (events)
- *events = coords;
- else if (coords)
- gdk_device_free_history (coords, tmp_n_events);
-
- return result;
-}
-
-GdkTimeCoord **
-_gdk_device_allocate_history (GdkDevice *device,
- gint n_events)
-{
- GdkTimeCoord **result = g_new (GdkTimeCoord *, n_events);
- gint i;
-
- for (i=0; i<n_events; i++)
- result[i] = g_malloc (sizeof (GdkTimeCoord) -
- sizeof (double) * (GDK_MAX_TIMECOORD_AXES - device->num_axes));
-
- return result;
-}
-
-/**
- * gdk_device_free_history:
- * @events: (inout) (transfer none): an array of #GdkTimeCoord.
- * @n_events: the length of the array.
- *
- * Frees an array of #GdkTimeCoord that was returned by gdk_device_get_history().
- */
-void
-gdk_device_free_history (GdkTimeCoord **events,
- gint n_events)
-{
- gint i;
-
- for (i=0; i<n_events; i++)
- g_free (events[i]);
-
- g_free (events);
}
static void
@@ -526,9 +134,21 @@ unset_extension_events (GdkWindow *window)
window_private->extension_events = 0;
}
+/**
+ * gdk_input_set_extension_events:
+ * @window: a #GdkWindow.
+ * @mask: the event mask
+ * @mode: the type of extension events that are desired.
+ *
+ * Turns extension events on or off for a particular window,
+ * and specifies the event mask for extension events.
+ *
+ * Deprecated: 3.0. Use gdk_window_set_device_events() instead.
+ **/
void
-gdk_input_set_extension_events (GdkWindow *window, gint mask,
- GdkExtensionMode mode)
+gdk_input_set_extension_events (GdkWindow *window,
+ gint mask,
+ GdkExtensionMode mode)
{
GdkWindowObject *window_private;
GdkWindowObject *impl_window;
@@ -565,15 +185,8 @@ gdk_input_set_extension_events (GdkWindow *window, gint mask,
iw->impl_window = (GdkWindow *)impl_window;
iw->windows = NULL;
- iw->grabbed = FALSE;
display_x11->input_windows = g_list_append (display_x11->input_windows, iw);
-
-#ifndef XINPUT_NONE
- /* we might not receive ConfigureNotify so get the root_relative_geometry
- * now, just in case */
- _gdk_input_get_root_relative_geometry (window, &iw->root_x, &iw->root_y);
-#endif /* !XINPUT_NONE */
impl_window->input_window = iw;
}
@@ -589,10 +202,8 @@ gdk_input_set_extension_events (GdkWindow *window, gint mask,
#ifndef XINPUT_NONE
for (tmp_list = display_x11->input_devices; tmp_list; tmp_list = tmp_list->next)
{
- GdkDevicePrivate *gdkdev = tmp_list->data;
-
- if (!GDK_IS_CORE (gdkdev))
- _gdk_input_select_events ((GdkWindow *)impl_window, gdkdev);
+ GdkDevice *dev = tmp_list->data;
+ _gdk_input_select_device_events (GDK_WINDOW (impl_window), dev);
}
#endif /* !XINPUT_NONE */
}
@@ -603,40 +214,20 @@ _gdk_input_window_destroy (GdkWindow *window)
unset_extension_events (window);
}
-/**
- * gdk_device_get_axis:
- * @device: a #GdkDevice
- * @axes: pointer to an array of axes
- * @use: the use to look for
- * @value: location to store the found value.
- *
- * Interprets an array of double as axis values for a given device,
- * and locates the value in the array for a given axis use.
- *
- * Return value: %TRUE if the given axis use was found, otherwise %FALSE
- **/
-gboolean
-gdk_device_get_axis (GdkDevice *device,
- gdouble *axes,
- GdkAxisUse use,
- gdouble *value)
+void
+_gdk_input_check_extension_events (GdkDevice *device)
{
- gint i;
-
- g_return_val_if_fail (device != NULL, FALSE);
-
- if (axes == NULL)
- return FALSE;
+ GdkDisplayX11 *display_impl;
+ GdkInputWindow *input_window;
+ GList *tmp_list;
- for (i=0; i<device->num_axes; i++)
- if (device->axes[i].use == use)
- {
- if (value)
- *value = axes[i];
- return TRUE;
- }
+ display_impl = GDK_DISPLAY_X11 (gdk_device_get_display (device));
- return FALSE;
+ for (tmp_list = display_impl->input_windows; tmp_list; tmp_list = tmp_list->next)
+ {
+ input_window = tmp_list->data;
+ _gdk_input_select_device_events (input_window->impl_window, device);
+ }
}
#define __GDK_INPUT_C__
diff --git a/gdk/x11/gdkinputprivate.h b/gdk/x11/gdkinputprivate.h
deleted file mode 100644
index 1b89230fcf..0000000000
--- a/gdk/x11/gdkinputprivate.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/* 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 Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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-2000. 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/.
- */
-
-#ifndef __GDK_INPUTPRIVATE_H__
-#define __GDK_INPUTPRIVATE_H__
-
-#include "config.h"
-#include "gdkinput.h"
-#include "gdkevents.h"
-#include "gdkx.h"
-
-#include <X11/Xlib.h>
-
-#ifndef XINPUT_NONE
-#include <X11/extensions/XInput.h>
-#endif
-
-
-typedef struct _GdkAxisInfo GdkAxisInfo;
-typedef struct _GdkDevicePrivate GdkDevicePrivate;
-
-/* information about a device axis */
-struct _GdkAxisInfo
-{
- /* reported x resolution */
- gint xresolution;
-
- /* reported x minimum/maximum values */
- gint xmin_value, xmax_value;
-
- /* calibrated resolution (for aspect ration) - only relative values
- between axes used */
- gint resolution;
-
- /* calibrated minimum/maximum values */
- gint min_value, max_value;
-};
-
-#define GDK_INPUT_NUM_EVENTC 6
-
-struct _GdkDevicePrivate
-{
- GdkDevice info;
-
- guint32 deviceid;
-
- GdkDisplay *display;
-
-
-#ifndef XINPUT_NONE
- /* information about the axes */
- GdkAxisInfo *axes;
- gint *axis_data;
-
- /* Information about XInput device */
- XDevice *xdevice;
-
- /* minimum key code for device */
- gint min_keycode;
-
- int buttonpress_type, buttonrelease_type, keypress_type,
- keyrelease_type, motionnotify_type, proximityin_type,
- proximityout_type, changenotify_type, devicestatenotify_type;
-
- /* true if we need to select a different set of events, but
- can't because this is the core pointer */
- gint needs_update;
-
- /* Mask of buttons (used for button grabs) */
- char button_state[32];
- gint button_count;
-
- /* true if we've claimed the device as active. (used only for XINPUT_GXI) */
- gint claimed;
-#endif /* !XINPUT_NONE */
-};
-
-struct _GdkDeviceClass
-{
- GObjectClass parent_class;
-};
-
-/* Addition used for extension_events mask */
-#define GDK_ALL_DEVICES_MASK (1<<30)
-
-struct _GdkInputWindow
-{
- GList *windows; /* GdkWindow:s with extension_events set */
-
- /* gdk window */
- GdkWindow *impl_window; /* an impl window */
- GdkWindow *button_down_window;
-
- /* position relative to root window */
- gint root_x;
- gint root_y;
-
- /* Is there a pointer grab for this window ? */
- gint grabbed;
-};
-
-/* Global data */
-
-#define GDK_IS_CORE(d) (((GdkDevice *)(d)) == ((GdkDevicePrivate *)(d))->display->core_pointer)
-
-/* Function declarations */
-
-GdkInputWindow *_gdk_input_window_find (GdkWindow *window);
-void _gdk_input_window_destroy (GdkWindow *window);
-GdkTimeCoord ** _gdk_device_allocate_history (GdkDevice *device,
- gint n_events);
-void _gdk_init_input_core (GdkDisplay *display);
-
-/* The following functions are provided by each implementation
- * (xfree, gxi, and none)
- */
-void _gdk_input_configure_event (XConfigureEvent *xevent,
- GdkWindow *window);
-void _gdk_input_crossing_event (GdkWindow *window,
- gboolean enter);
-gboolean _gdk_input_other_event (GdkEvent *event,
- XEvent *xevent,
- GdkWindow *window);
-gint _gdk_input_grab_pointer (GdkWindow *window,
- GdkWindow *native_window,
- gint owner_events,
- GdkEventMask event_mask,
- GdkWindow *confine_to,
- guint32 time);
-void _gdk_input_ungrab_pointer (GdkDisplay *display,
- guint32 time);
-gboolean _gdk_device_get_history (GdkDevice *device,
- GdkWindow *window,
- guint32 start,
- guint32 stop,
- GdkTimeCoord ***events,
- gint *n_events);
-
-#ifndef XINPUT_NONE
-
-#define GDK_MAX_DEVICE_CLASSES 13
-
-gint _gdk_input_common_init (GdkDisplay *display,
- gint include_core);
-GdkDevicePrivate * _gdk_input_find_device (GdkDisplay *display,
- guint32 id);
-void _gdk_input_get_root_relative_geometry(GdkWindow *window,
- int *x_ret,
- int *y_ret);
-void _gdk_input_common_find_events (GdkDevicePrivate *gdkdev,
- gint mask,
- XEventClass *classes,
- int *num_classes);
-void _gdk_input_select_events (GdkWindow *impl_window,
- GdkDevicePrivate *gdkdev);
-gint _gdk_input_common_other_event (GdkEvent *event,
- XEvent *xevent,
- GdkWindow *window,
- GdkDevicePrivate *gdkdev);
-gboolean _gdk_input_common_event_selected (GdkEvent *event,
- GdkWindow *window,
- GdkDevicePrivate *gdkdev);
-
-#endif /* !XINPUT_NONE */
-
-#endif /* __GDK_INPUTPRIVATE_H__ */
diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c
index f12c7094b8..bf53d6552c 100644
--- a/gdk/x11/gdkmain-x11.c
+++ b/gdk/x11/gdkmain-x11.c
@@ -47,11 +47,13 @@
#include "gdkasync.h"
#include "gdkdisplay-x11.h"
#include "gdkinternals.h"
+#include "gdkprivate-x11.h"
#include "gdkintl.h"
#include "gdkregion-generic.h"
-#include "gdkinputprivate.h"
#include "gdkalias.h"
+#include <gdk/gdkdeviceprivate.h>
+
typedef struct _GdkPredicate GdkPredicate;
typedef struct _GdkErrorTrap GdkErrorTrap;
@@ -116,8 +118,8 @@ gdk_get_use_xshm (void)
return GDK_DISPLAY_X11 (gdk_display_get_default ())->use_xshm;
}
-static GdkGrabStatus
-gdk_x11_convert_grab_status (gint status)
+GdkGrabStatus
+_gdk_x11_convert_grab_status (gint status)
{
switch (status)
{
@@ -143,171 +145,46 @@ has_pointer_grab_callback (GdkDisplay *display,
gpointer data,
gulong serial)
{
- _gdk_display_pointer_grab_update (display, serial);
-}
-
-GdkGrabStatus
-_gdk_windowing_pointer_grab (GdkWindow *window,
- GdkWindow *native,
- gboolean owner_events,
- GdkEventMask event_mask,
- GdkWindow *confine_to,
- GdkCursor *cursor,
- guint32 time)
-{
- gint return_val;
- GdkCursorPrivate *cursor_private;
- GdkDisplayX11 *display_x11;
- guint xevent_mask;
- Window xwindow;
- Window xconfine_to;
- Cursor xcursor;
- int i;
-
- if (confine_to)
- confine_to = _gdk_window_get_impl_window (confine_to);
-
- display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (native));
-
- cursor_private = (GdkCursorPrivate*) cursor;
-
- xwindow = GDK_WINDOW_XID (native);
-
- if (!confine_to || GDK_WINDOW_DESTROYED (confine_to))
- xconfine_to = None;
- else
- xconfine_to = GDK_WINDOW_XID (confine_to);
-
- if (!cursor)
- xcursor = None;
- else
- {
- _gdk_x11_cursor_update_theme (cursor);
- xcursor = cursor_private->xcursor;
- }
-
- xevent_mask = 0;
- for (i = 0; i < _gdk_nenvent_masks; i++)
- {
- if (event_mask & (1 << (i + 1)))
- xevent_mask |= _gdk_event_mask_table[i];
- }
-
- /* We don't want to set a native motion hint mask, as we're emulating motion
- * hints. If we set a native one we just wouldn't get any events.
- */
- xevent_mask &= ~PointerMotionHintMask;
-
- return_val = _gdk_input_grab_pointer (window,
- native,
- owner_events,
- event_mask,
- confine_to,
- time);
+ GdkDevice *device = data;
- if (return_val == GrabSuccess ||
- G_UNLIKELY (!display_x11->trusted_client && return_val == AlreadyGrabbed))
- {
- if (!GDK_WINDOW_DESTROYED (native))
- {
-#ifdef G_ENABLE_DEBUG
- if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
- return_val = GrabSuccess;
- else
-#endif
- return_val = XGrabPointer (GDK_WINDOW_XDISPLAY (native),
- xwindow,
- owner_events,
- xevent_mask,
- GrabModeAsync, GrabModeAsync,
- xconfine_to,
- xcursor,
- time);
- }
- else
- return_val = AlreadyGrabbed;
- }
-
- if (return_val == GrabSuccess)
- _gdk_x11_roundtrip_async (GDK_DISPLAY_OBJECT (display_x11),
- has_pointer_grab_callback,
- NULL);
-
- return gdk_x11_convert_grab_status (return_val);
+ _gdk_display_device_grab_update (display, device, serial);
}
-/*
- *--------------------------------------------------------------
- * gdk_keyboard_grab
- *
- * Grabs the keyboard to a specific window
- *
- * Arguments:
- * "window" is the window which will receive the grab
- * "owner_events" specifies whether events will be reported as is,
- * or relative to "window"
- * "time" specifies the time
- *
- * Results:
- *
- * Side effects:
- * requires a corresponding call to gdk_keyboard_ungrab
- *
- *--------------------------------------------------------------
- */
-
GdkGrabStatus
-gdk_keyboard_grab (GdkWindow * window,
- gboolean owner_events,
- guint32 time)
+_gdk_windowing_device_grab (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow *native,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time)
{
- gint return_val;
- unsigned long serial;
GdkDisplay *display;
- GdkDisplayX11 *display_x11;
- GdkWindow *native;
-
- g_return_val_if_fail (window != NULL, 0);
- g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
-
- native = gdk_window_get_toplevel (window);
-
- /* TODO: What do we do for offscreens and children? We need to proxy the grab somehow */
- if (!GDK_IS_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (native)->impl))
- return GDK_GRAB_SUCCESS;
+ GdkGrabStatus status = GDK_GRAB_SUCCESS;
- display = GDK_WINDOW_DISPLAY (native);
- display_x11 = GDK_DISPLAY_X11 (display);
+ if (!window || GDK_WINDOW_DESTROYED (window))
+ return GDK_GRAB_NOT_VIEWABLE;
- serial = NextRequest (GDK_WINDOW_XDISPLAY (native));
+ display = gdk_device_get_display (device);
- if (!GDK_WINDOW_DESTROYED (native))
- {
#ifdef G_ENABLE_DEBUG
- if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
- return_val = GrabSuccess;
- else
-#endif
- return_val = XGrabKeyboard (GDK_WINDOW_XDISPLAY (native),
- GDK_WINDOW_XID (native),
- owner_events,
- GrabModeAsync, GrabModeAsync,
- time);
- if (G_UNLIKELY (!display_x11->trusted_client &&
- return_val == AlreadyGrabbed))
- /* we can't grab the keyboard, but we can do a GTK-local grab */
- return_val = GrabSuccess;
- }
+ if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
+ status = GrabSuccess;
else
- return_val = AlreadyGrabbed;
-
- if (return_val == GrabSuccess)
- _gdk_display_set_has_keyboard_grab (display,
- window, native,
- owner_events,
- serial, time);
-
- return gdk_x11_convert_grab_status (return_val);
+#endif
+ status = GDK_DEVICE_GET_CLASS (device)->grab (device,
+ native,
+ owner_events,
+ event_mask,
+ confine_to,
+ cursor,
+ time);
+ if (status == GDK_GRAB_SUCCESS)
+ _gdk_x11_roundtrip_async (display,
+ has_pointer_grab_callback,
+ device);
+ return status;
}
/**
@@ -325,21 +202,21 @@ _gdk_xgrab_check_unmap (GdkWindow *window,
gulong serial)
{
GdkDisplay *display = gdk_drawable_get_display (window);
+ GdkDeviceManager *device_manager;
+ GList *devices, *d;
- _gdk_display_end_pointer_grab (display, serial, window, TRUE);
+ device_manager = gdk_display_get_device_manager (display);
- if (display->keyboard_grab.window &&
- serial >= display->keyboard_grab.serial)
- {
- GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
- GdkWindowObject *tmp = GDK_WINDOW_OBJECT (display->keyboard_grab.window);
+ /* Get all devices */
+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+ devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
+ devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
- while (tmp && tmp != private)
- tmp = tmp->parent;
+ /* End all grabs on the newly hidden window */
+ for (d = devices; d; d = d->next)
+ _gdk_display_end_device_grab (display, d->data, serial, window, TRUE);
- if (tmp)
- _gdk_display_unset_has_keyboard_grab (display, TRUE);
- }
+ g_list_free (devices);
}
/**
@@ -353,25 +230,35 @@ void
_gdk_xgrab_check_destroy (GdkWindow *window)
{
GdkDisplay *display = gdk_drawable_get_display (window);
- GdkPointerGrabInfo *grab;
+ GdkDeviceManager *device_manager;
+ GdkDeviceGrabInfo *grab;
+ GList *devices, *d;
- /* Make sure there is no lasting grab in this native
- window */
- grab = _gdk_display_get_last_pointer_grab (display);
- if (grab && grab->native_window == window)
+ device_manager = gdk_display_get_device_manager (display);
+
+ /* Get all devices */
+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+ devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
+ devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
+
+ for (d = devices; d; d = d->next)
{
- /* We don't know the actual serial to end, but it
- doesn't really matter as this only happens
- after we get told of the destroy from the
- server so we know its ended in the server,
- just make sure its ended. */
- grab->serial_end = grab->serial_start;
- grab->implicit_ungrab = TRUE;
+ /* Make sure there is no lasting grab in this native window */
+ grab = _gdk_display_get_last_device_grab (display, d->data);
+
+ if (grab && grab->native_window == window)
+ {
+ /* We don't know the actual serial to end, but it
+ doesn't really matter as this only happens
+ after we get told of the destroy from the
+ server so we know its ended in the server,
+ just make sure its ended. */
+ grab->serial_end = grab->serial_start;
+ grab->implicit_ungrab = TRUE;
+ }
}
-
- if (window == display->keyboard_grab.native_window &&
- display->keyboard_grab.window != NULL)
- _gdk_display_unset_has_keyboard_grab (display, TRUE);
+
+ g_list_free (devices);
}
void
@@ -734,5 +621,16 @@ gdk_x11_get_default_xdisplay (void)
return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
}
+void
+_gdk_windowing_event_data_copy (const GdkEvent *src,
+ GdkEvent *dst)
+{
+}
+
+void
+_gdk_windowing_event_data_free (GdkEvent *event)
+{
+}
+
#define __GDK_MAIN_X11_C__
#include "gdkaliasdef.c"
diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h
index 05c033ac76..00cde1b6e2 100644
--- a/gdk/x11/gdkprivate-x11.h
+++ b/gdk/x11/gdkprivate-x11.h
@@ -177,8 +177,7 @@ void _gdk_x11_precache_atoms (GdkDisplay *display,
const gchar * const *atom_names,
gint n_atoms);
-void _gdk_x11_events_init_screen (GdkScreen *screen);
-void _gdk_x11_events_uninit_screen (GdkScreen *screen);
+void _gdk_screen_x11_events_init (GdkScreen *screen);
void _gdk_events_init (GdkDisplay *display);
void _gdk_events_uninit (GdkDisplay *display);
@@ -186,7 +185,6 @@ void _gdk_windowing_window_init (GdkScreen *screen);
void _gdk_visual_init (GdkScreen *screen);
void _gdk_dnd_init (GdkDisplay *display);
void _gdk_windowing_image_init (GdkDisplay *display);
-void _gdk_input_init (GdkDisplay *display);
PangoRenderer *_gdk_x11_renderer_get (GdkDrawable *drawable,
GdkGC *gc);
@@ -198,6 +196,9 @@ gboolean _gdk_x11_get_xft_setting (GdkScreen *screen,
const gchar *name,
GValue *value);
+GdkGrabStatus _gdk_x11_convert_grab_status (gint status);
+
+
extern GdkDrawableClass _gdk_x11_drawable_class;
extern gboolean _gdk_use_xshm;
extern const int _gdk_nenvent_masks;
diff --git a/gdk/x11/gdkscreen-x11.c b/gdk/x11/gdkscreen-x11.c
index 335016227e..60df9b1696 100644
--- a/gdk/x11/gdkscreen-x11.c
+++ b/gdk/x11/gdkscreen-x11.c
@@ -51,6 +51,8 @@
#include <X11/extensions/Xfixes.h>
#endif
+#include "gdksettings.c"
+
static void gdk_screen_x11_dispose (GObject *object);
static void gdk_screen_x11_finalize (GObject *object);
static void init_randr_support (GdkScreen *screen);
@@ -66,6 +68,14 @@ static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE (GdkScreenX11, _gdk_screen_x11, GDK_TYPE_SCREEN)
+typedef struct _NetWmSupportedAtoms NetWmSupportedAtoms;
+
+struct _NetWmSupportedAtoms
+{
+ Atom *atoms;
+ gulong n_atoms;
+};
+
struct _GdkX11Monitor
{
GdkRectangle geometry;
@@ -273,11 +283,23 @@ gdk_screen_set_default_colormap (GdkScreen *screen,
}
static void
+_gdk_screen_x11_events_uninit (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+ if (screen_x11->xsettings_client)
+ {
+ xsettings_client_destroy (screen_x11->xsettings_client);
+ screen_x11->xsettings_client = NULL;
+ }
+}
+
+static void
gdk_screen_x11_dispose (GObject *object)
{
GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
- _gdk_x11_events_uninit_screen (GDK_SCREEN (object));
+ _gdk_screen_x11_events_uninit (GDK_SCREEN (object));
if (screen_x11->default_colormap)
{
@@ -1434,5 +1456,637 @@ gdk_screen_get_window_stack (GdkScreen *screen)
return ret;
}
+/* Sends a ClientMessage to all toplevel client windows */
+static gboolean
+gdk_event_send_client_message_to_all_recurse (GdkDisplay *display,
+ XEvent *xev,
+ guint32 xid,
+ guint level)
+{
+ Atom type = None;
+ int format;
+ unsigned long nitems, after;
+ unsigned char *data;
+ Window *ret_children, ret_root, ret_parent;
+ unsigned int ret_nchildren;
+ gboolean send = FALSE;
+ gboolean found = FALSE;
+ gboolean result = FALSE;
+ int i;
+
+ gdk_error_trap_push ();
+
+ if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xid,
+ gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE"),
+ 0, 0, False, AnyPropertyType,
+ &type, &format, &nitems, &after, &data) != Success)
+ goto out;
+
+ if (type)
+ {
+ send = TRUE;
+ XFree (data);
+ }
+ else
+ {
+ /* OK, we're all set, now let's find some windows to send this to */
+ if (!XQueryTree (GDK_DISPLAY_XDISPLAY (display), xid,
+ &ret_root, &ret_parent,
+ &ret_children, &ret_nchildren))
+ goto out;
+
+ for(i = 0; i < ret_nchildren; i++)
+ if (gdk_event_send_client_message_to_all_recurse (display, xev, ret_children[i], level + 1))
+ found = TRUE;
+
+ XFree (ret_children);
+ }
+
+ if (send || (!found && (level == 1)))
+ {
+ xev->xclient.window = xid;
+ _gdk_send_xevent (display, xid, False, NoEventMask, xev);
+ }
+
+ result = send || found;
+
+ out:
+ gdk_error_trap_pop ();
+
+ return result;
+}
+
+/**
+ * gdk_screen_broadcast_client_message:
+ * @screen: the #GdkScreen where the event will be broadcasted.
+ * @event: the #GdkEvent.
+ *
+ * On X11, sends an X ClientMessage event to all toplevel windows on
+ * @screen.
+ *
+ * Toplevel windows are determined by checking for the WM_STATE property,
+ * as described in the Inter-Client Communication Conventions Manual (ICCCM).
+ * If no windows are found with the WM_STATE property set, the message is
+ * sent to all children of the root window.
+ *
+ * On Windows, broadcasts a message registered with the name
+ * GDK_WIN32_CLIENT_MESSAGE to all top-level windows. The amount of
+ * data is limited to one long, i.e. four bytes.
+ *
+ * Since: 2.2
+ */
+
+void
+gdk_screen_broadcast_client_message (GdkScreen *screen,
+ GdkEvent *event)
+{
+ XEvent sev;
+ GdkWindow *root_window;
+
+ g_return_if_fail (event != NULL);
+
+ root_window = gdk_screen_get_root_window (screen);
+
+ /* Set up our event to send, with the exception of its target window */
+ sev.xclient.type = ClientMessage;
+ sev.xclient.display = GDK_WINDOW_XDISPLAY (root_window);
+ sev.xclient.format = event->client.data_format;
+ memcpy(&sev.xclient.data, &event->client.data, sizeof (sev.xclient.data));
+ sev.xclient.message_type =
+ gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (root_window),
+ event->client.message_type);
+
+ gdk_event_send_client_message_to_all_recurse (gdk_screen_get_display (screen),
+ &sev,
+ GDK_WINDOW_XID (root_window),
+ 0);
+}
+
+static gboolean
+check_transform (const gchar *xsettings_name,
+ GType src_type,
+ GType dest_type)
+{
+ if (!g_value_type_transformable (src_type, dest_type))
+ {
+ g_warning ("Cannot transform xsetting %s of type %s to type %s\n",
+ xsettings_name,
+ g_type_name (src_type),
+ g_type_name (dest_type));
+ return FALSE;
+ }
+ else
+ return TRUE;
+}
+
+/**
+ * gdk_screen_get_setting:
+ * @screen: the #GdkScreen where the setting is located
+ * @name: the name of the setting
+ * @value: location to store the value of the setting
+ *
+ * Retrieves a desktop-wide setting such as double-click time
+ * for the #GdkScreen @screen.
+ *
+ * FIXME needs a list of valid settings here, or a link to
+ * more information.
+ *
+ * Returns: %TRUE if the setting existed and a value was stored
+ * in @value, %FALSE otherwise.
+ *
+ * Since: 2.2
+ **/
+gboolean
+gdk_screen_get_setting (GdkScreen *screen,
+ const gchar *name,
+ GValue *value)
+{
+
+ const char *xsettings_name = NULL;
+ XSettingsResult result;
+ XSettingsSetting *setting = NULL;
+ GdkScreenX11 *screen_x11;
+ gboolean success = FALSE;
+ gint i;
+ GValue tmp_val = { 0, };
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
+
+ screen_x11 = GDK_SCREEN_X11 (screen);
+
+ for (i = 0; i < GDK_SETTINGS_N_ELEMENTS(); i++)
+ if (strcmp (GDK_SETTINGS_GDK_NAME (i), name) == 0)
+ {
+ xsettings_name = GDK_SETTINGS_X_NAME (i);
+ break;
+ }
+
+ if (!xsettings_name)
+ goto out;
+
+ result = xsettings_client_get_setting (screen_x11->xsettings_client,
+ xsettings_name, &setting);
+ if (result != XSETTINGS_SUCCESS)
+ goto out;
+
+ switch (setting->type)
+ {
+ case XSETTINGS_TYPE_INT:
+ if (check_transform (xsettings_name, G_TYPE_INT, G_VALUE_TYPE (value)))
+ {
+ g_value_init (&tmp_val, G_TYPE_INT);
+ g_value_set_int (&tmp_val, setting->data.v_int);
+ g_value_transform (&tmp_val, value);
+
+ success = TRUE;
+ }
+ break;
+ case XSETTINGS_TYPE_STRING:
+ if (check_transform (xsettings_name, G_TYPE_STRING, G_VALUE_TYPE (value)))
+ {
+ g_value_init (&tmp_val, G_TYPE_STRING);
+ g_value_set_string (&tmp_val, setting->data.v_string);
+ g_value_transform (&tmp_val, value);
+
+ success = TRUE;
+ }
+ break;
+ case XSETTINGS_TYPE_COLOR:
+ if (!check_transform (xsettings_name, GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
+ {
+ GdkColor color;
+
+ g_value_init (&tmp_val, GDK_TYPE_COLOR);
+
+ color.pixel = 0;
+ color.red = setting->data.v_color.red;
+ color.green = setting->data.v_color.green;
+ color.blue = setting->data.v_color.blue;
+
+ g_value_set_boxed (&tmp_val, &color);
+
+ g_value_transform (&tmp_val, value);
+
+ success = TRUE;
+ }
+ break;
+ }
+
+ g_value_unset (&tmp_val);
+
+ out:
+ if (setting)
+ xsettings_setting_free (setting);
+
+ if (success)
+ return TRUE;
+ else
+ return _gdk_x11_get_xft_setting (screen, name, value);
+}
+
+static void
+cleanup_atoms(gpointer data)
+{
+ NetWmSupportedAtoms *supported_atoms = data;
+ if (supported_atoms->atoms)
+ XFree (supported_atoms->atoms);
+ g_free (supported_atoms);
+}
+
+static void
+fetch_net_wm_check_window (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11;
+ GdkDisplay *display;
+ Atom type;
+ gint format;
+ gulong n_items;
+ gulong bytes_after;
+ guchar *data;
+ Window *xwindow;
+ GTimeVal tv;
+ gint error;
+
+ screen_x11 = GDK_SCREEN_X11 (screen);
+ display = screen_x11->display;
+
+ g_return_if_fail (GDK_DISPLAY_X11 (display)->trusted_client);
+
+ g_get_current_time (&tv);
+
+ if (ABS (tv.tv_sec - screen_x11->last_wmspec_check_time) < 15)
+ return; /* we've checked recently */
+
+ screen_x11->last_wmspec_check_time = tv.tv_sec;
+
+ data = NULL;
+ XGetWindowProperty (screen_x11->xdisplay, screen_x11->xroot_window,
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTING_WM_CHECK"),
+ 0, G_MAXLONG, False, XA_WINDOW, &type, &format,
+ &n_items, &bytes_after, &data);
+
+ if (type != XA_WINDOW)
+ {
+ if (data)
+ XFree (data);
+ return;
+ }
+
+ xwindow = (Window *)data;
+
+ if (screen_x11->wmspec_check_window == *xwindow)
+ {
+ XFree (xwindow);
+ return;
+ }
+
+ gdk_error_trap_push ();
+
+ /* Find out if this WM goes away, so we can reset everything. */
+ XSelectInput (screen_x11->xdisplay, *xwindow, StructureNotifyMask);
+ gdk_display_sync (display);
+
+ error = gdk_error_trap_pop ();
+ if (!error)
+ {
+ screen_x11->wmspec_check_window = *xwindow;
+ screen_x11->need_refetch_net_supported = TRUE;
+ screen_x11->need_refetch_wm_name = TRUE;
+
+ /* Careful, reentrancy */
+ _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11));
+ }
+ else if (error == BadWindow)
+ {
+ /* Leftover property, try again immediately, new wm may be starting up */
+ screen_x11->last_wmspec_check_time = 0;
+ }
+
+ XFree (xwindow);
+}
+
+/**
+ * gdk_x11_screen_supports_net_wm_hint:
+ * @screen: the relevant #GdkScreen.
+ * @property: a property atom.
+ *
+ * This function is specific to the X11 backend of GDK, and indicates
+ * whether the window manager supports a certain hint from the
+ * Extended Window Manager Hints Specification. You can find this
+ * specification on
+ * <ulink url="http://www.freedesktop.org">http://www.freedesktop.org</ulink>.
+ *
+ * When using this function, keep in mind that the window manager
+ * can change over time; so you shouldn't use this function in
+ * a way that impacts persistent application state. A common bug
+ * is that your application can start up before the window manager
+ * does when the user logs in, and before the window manager starts
+ * gdk_x11_screen_supports_net_wm_hint() will return %FALSE for every property.
+ * You can monitor the window_manager_changed signal on #GdkScreen to detect
+ * a window manager change.
+ *
+ * Return value: %TRUE if the window manager supports @property
+ *
+ * Since: 2.2
+ **/
+gboolean
+gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
+ GdkAtom property)
+{
+ gulong i;
+ GdkScreenX11 *screen_x11;
+ NetWmSupportedAtoms *supported_atoms;
+ GdkDisplay *display;
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
+
+ screen_x11 = GDK_SCREEN_X11 (screen);
+ display = screen_x11->display;
+
+ if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
+ return FALSE;
+
+ supported_atoms = g_object_get_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms");
+ if (!supported_atoms)
+ {
+ supported_atoms = g_new0 (NetWmSupportedAtoms, 1);
+ g_object_set_data_full (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms, cleanup_atoms);
+ }
+
+ fetch_net_wm_check_window (screen);
+
+ if (screen_x11->wmspec_check_window == None)
+ return FALSE;
+
+ if (screen_x11->need_refetch_net_supported)
+ {
+ /* WM has changed since we last got the supported list,
+ * refetch it.
+ */
+ Atom type;
+ gint format;
+ gulong bytes_after;
+
+ screen_x11->need_refetch_net_supported = FALSE;
+
+ if (supported_atoms->atoms)
+ XFree (supported_atoms->atoms);
+
+ supported_atoms->atoms = NULL;
+ supported_atoms->n_atoms = 0;
+
+ XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_x11->xroot_window,
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTED"),
+ 0, G_MAXLONG, False, XA_ATOM, &type, &format,
+ &supported_atoms->n_atoms, &bytes_after,
+ (guchar **)&supported_atoms->atoms);
+
+ if (type != XA_ATOM)
+ return FALSE;
+ }
+
+ if (supported_atoms->atoms == NULL)
+ return FALSE;
+
+ i = 0;
+ while (i < supported_atoms->n_atoms)
+ {
+ if (supported_atoms->atoms[i] == gdk_x11_atom_to_xatom_for_display (display, property))
+ return TRUE;
+
+ ++i;
+ }
+
+ return FALSE;
+}
+
+/**
+ * gdk_net_wm_supports:
+ * @property: a property atom.
+ *
+ * This function is specific to the X11 backend of GDK, and indicates
+ * whether the window manager for the default screen supports a certain
+ * hint from the Extended Window Manager Hints Specification. See
+ * gdk_x11_screen_supports_net_wm_hint() for complete details.
+ *
+ * Return value: %TRUE if the window manager supports @property
+ **/
+gboolean
+gdk_net_wm_supports (GdkAtom property)
+{
+ return gdk_x11_screen_supports_net_wm_hint (gdk_screen_get_default (), property);
+}
+
+static void
+refcounted_grab_server (Display *xdisplay)
+{
+ GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
+
+ gdk_x11_display_grab (display);
+}
+
+static void
+refcounted_ungrab_server (Display *xdisplay)
+{
+ GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
+
+ gdk_x11_display_ungrab (display);
+}
+
+static GdkFilterReturn
+gdk_xsettings_client_event_filter (GdkXEvent *xevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ GdkScreenX11 *screen = data;
+
+ if (xsettings_client_process_event (screen->xsettings_client, (XEvent *)xevent))
+ return GDK_FILTER_REMOVE;
+ else
+ return GDK_FILTER_CONTINUE;
+}
+
+static Bool
+gdk_xsettings_watch_cb (Window window,
+ Bool is_start,
+ long mask,
+ void *cb_data)
+{
+ GdkWindow *gdkwin;
+ GdkScreen *screen = cb_data;
+
+ gdkwin = gdk_window_lookup_for_display (gdk_screen_get_display (screen), window);
+
+ if (is_start)
+ {
+ if (gdkwin)
+ g_object_ref (gdkwin);
+ else
+ {
+ gdkwin = gdk_window_foreign_new_for_display (gdk_screen_get_display (screen), window);
+
+ /* gdk_window_foreign_new_for_display() can fail and return NULL if the
+ * window has already been destroyed.
+ */
+ if (!gdkwin)
+ return False;
+ }
+
+ gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
+ }
+ else
+ {
+ if (!gdkwin)
+ {
+ /* gdkwin should not be NULL here, since if starting the watch succeeded
+ * we have a reference on the window. It might mean that the caller didn't
+ * remove the watch when it got a DestroyNotify event. Or maybe the
+ * caller ignored the return value when starting the watch failed.
+ */
+ g_warning ("gdk_xsettings_watch_cb(): Couldn't find window to unwatch");
+ return False;
+ }
+
+ gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
+ g_object_unref (gdkwin);
+ }
+
+ return True;
+}
+
+static void
+gdk_xsettings_notify_cb (const char *name,
+ XSettingsAction action,
+ XSettingsSetting *setting,
+ void *data)
+{
+ GdkEvent new_event;
+ GdkScreen *screen = data;
+ GdkScreenX11 *screen_x11 = data;
+ int i;
+
+ if (screen_x11->xsettings_in_init)
+ return;
+
+ new_event.type = GDK_SETTING;
+ new_event.setting.window = gdk_screen_get_root_window (screen);
+ new_event.setting.send_event = FALSE;
+ new_event.setting.name = NULL;
+
+ for (i = 0; i < GDK_SETTINGS_N_ELEMENTS() ; i++)
+ if (strcmp (GDK_SETTINGS_X_NAME (i), name) == 0)
+ {
+ new_event.setting.name = (char*) GDK_SETTINGS_GDK_NAME (i);
+ break;
+ }
+
+ if (!new_event.setting.name)
+ return;
+
+ switch (action)
+ {
+ case XSETTINGS_ACTION_NEW:
+ new_event.setting.action = GDK_SETTING_ACTION_NEW;
+ break;
+ case XSETTINGS_ACTION_CHANGED:
+ new_event.setting.action = GDK_SETTING_ACTION_CHANGED;
+ break;
+ case XSETTINGS_ACTION_DELETED:
+ new_event.setting.action = GDK_SETTING_ACTION_DELETED;
+ break;
+ }
+
+ gdk_event_put (&new_event);
+}
+
+void
+_gdk_screen_x11_events_init (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+ /* Keep a flag to avoid extra notifies that we don't need
+ */
+ screen_x11->xsettings_in_init = TRUE;
+ screen_x11->xsettings_client = xsettings_client_new_with_grab_funcs (screen_x11->xdisplay,
+ screen_x11->screen_num,
+ gdk_xsettings_notify_cb,
+ gdk_xsettings_watch_cb,
+ screen,
+ refcounted_grab_server,
+ refcounted_ungrab_server);
+ screen_x11->xsettings_in_init = FALSE;
+}
+
+/**
+ * gdk_x11_screen_get_window_manager_name:
+ * @screen: a #GdkScreen
+ *
+ * Returns the name of the window manager for @screen.
+ *
+ * Return value: the name of the window manager screen @screen, or
+ * "unknown" if the window manager is unknown. The string is owned by GDK
+ * and should not be freed.
+ *
+ * Since: 2.2
+ **/
+const char*
+gdk_x11_screen_get_window_manager_name (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11;
+
+ screen_x11 = GDK_SCREEN_X11 (screen);
+
+ if (!G_LIKELY (GDK_DISPLAY_X11 (screen_x11->display)->trusted_client))
+ return screen_x11->window_manager_name;
+
+ fetch_net_wm_check_window (screen);
+
+ if (screen_x11->need_refetch_wm_name)
+ {
+ /* Get the name of the window manager */
+ screen_x11->need_refetch_wm_name = FALSE;
+
+ g_free (screen_x11->window_manager_name);
+ screen_x11->window_manager_name = g_strdup ("unknown");
+
+ if (screen_x11->wmspec_check_window != None)
+ {
+ Atom type;
+ gint format;
+ gulong n_items;
+ gulong bytes_after;
+ gchar *name;
+
+ name = NULL;
+
+ gdk_error_trap_push ();
+
+ XGetWindowProperty (GDK_DISPLAY_XDISPLAY (screen_x11->display),
+ screen_x11->wmspec_check_window,
+ gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
+ "_NET_WM_NAME"),
+ 0, G_MAXLONG, False,
+ gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
+ "UTF8_STRING"),
+ &type, &format,
+ &n_items, &bytes_after,
+ (guchar **)&name);
+
+ gdk_display_sync (screen_x11->display);
+
+ gdk_error_trap_pop ();
+
+ if (name != NULL)
+ {
+ g_free (screen_x11->window_manager_name);
+ screen_x11->window_manager_name = g_strdup (name);
+ XFree (name);
+ }
+ }
+ }
+
+ return GDK_SCREEN_X11 (screen)->window_manager_name;
+}
+
#define __GDK_SCREEN_X11_C__
#include "gdkaliasdef.c"
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index 92a64fb47b..1eedd43940 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -39,17 +39,19 @@
#include <unistd.h>
#include "gdk.h"
+#include "gdkx.h"
#include "gdkwindow.h"
#include "gdkwindowimpl.h"
#include "gdkasync.h"
-#include "gdkinputprivate.h"
#include "gdkdisplay-x11.h"
#include "gdkprivate-x11.h"
#include "gdkregion.h"
#include "gdkinternals.h"
#include "MwmUtil.h"
#include "gdkwindow-x11.h"
+#include "gdkdeviceprivate.h"
+#include "gdkeventsource.h"
#include "gdkalias.h"
#include <stdlib.h>
@@ -146,6 +148,8 @@ static void
gdk_window_impl_x11_init (GdkWindowImplX11 *impl)
{
impl->toplevel_window_type = -1;
+ impl->device_cursor = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) gdk_cursor_unref);
}
GdkToplevelX11 *
@@ -210,6 +214,8 @@ gdk_window_impl_x11_finalize (GObject *object)
if (window_impl->cursor)
gdk_cursor_unref (window_impl->cursor);
+ g_hash_table_destroy (window_impl->device_cursor);
+
G_OBJECT_CLASS (gdk_window_impl_x11_parent_class)->finalize (object);
}
@@ -513,18 +519,31 @@ check_leader_window_title (GdkDisplay *display)
}
static Window
-create_focus_window (Display *xdisplay,
- XID parent)
+create_focus_window (GdkDisplay *display,
+ XID parent)
{
- Window focus_window = XCreateSimpleWindow (xdisplay, parent,
- -1, -1, 1, 1, 0,
- 0, 0);
-
+ GdkDisplayX11 *display_x11;
+ GdkEventMask event_mask;
+ Display *xdisplay;
+ Window focus_window;
+
+ xdisplay = GDK_DISPLAY_XDISPLAY (display);
+ display_x11 = GDK_DISPLAY_X11 (display);
+
+ focus_window = XCreateSimpleWindow (xdisplay, parent,
+ -1, -1, 1, 1, 0,
+ 0, 0);
+
/* FIXME: probably better to actually track the requested event mask for the toplevel
*/
- XSelectInput (xdisplay, focus_window,
- KeyPressMask | KeyReleaseMask | FocusChangeMask);
-
+ event_mask = (GDK_KEY_PRESS_MASK |
+ GDK_KEY_RELEASE_MASK |
+ GDK_FOCUS_CHANGE_MASK);
+
+ gdk_event_source_select_events ((GdkEventSource *) display_x11->event_source,
+ focus_window,
+ event_mask, 0);
+
XMapWindow (xdisplay, focus_window);
return focus_window;
@@ -573,6 +592,7 @@ setup_toplevel_window (GdkWindow *window,
{
GdkWindowObject *obj = (GdkWindowObject *)window;
GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+ GdkDisplay *display = gdk_drawable_get_display (window);
Display *xdisplay = GDK_WINDOW_XDISPLAY (window);
XID xid = GDK_WINDOW_XID (window);
XID xparent = GDK_WINDOW_XID (parent);
@@ -591,7 +611,7 @@ setup_toplevel_window (GdkWindow *window,
/* The focus window is off the visible area, and serves to receive key
* press events so they don't get sent to child windows.
*/
- toplevel->focus_window = create_focus_window (xdisplay, xid);
+ toplevel->focus_window = create_focus_window (display, xid);
_gdk_xid_table_insert (screen_x11->display, &toplevel->focus_window, window);
}
@@ -652,6 +672,7 @@ _gdk_window_impl_new (GdkWindow *window,
GdkWindowImplX11 *impl;
GdkDrawableImplX11 *draw_impl;
GdkScreenX11 *screen_x11;
+ GdkDisplayX11 *display_x11;
Window xparent;
Visual *xvisual;
@@ -664,12 +685,12 @@ _gdk_window_impl_new (GdkWindow *window,
unsigned int class;
const char *title;
- int i;
private = (GdkWindowObject *) window;
screen_x11 = GDK_SCREEN_X11 (screen);
xparent = GDK_WINDOW_XID (real_parent);
+ display_x11 = GDK_DISPLAY_X11 (GDK_SCREEN_DISPLAY (screen));
impl = g_object_new (_gdk_window_impl_get_type (), NULL);
private->impl = (GdkDrawable *)impl;
@@ -683,15 +704,6 @@ _gdk_window_impl_new (GdkWindow *window,
xvisual = ((GdkVisualPrivate*) visual)->xvisual;
- xattributes.event_mask = StructureNotifyMask | PropertyChangeMask;
- for (i = 0; i < _gdk_nenvent_masks; i++)
- {
- if (event_mask & (1 << (i + 1)))
- xattributes.event_mask |= _gdk_event_mask_table[i];
- }
- if (xattributes.event_mask)
- xattributes_mask |= CWEventMask;
-
if (attributes_mask & GDK_WA_NOREDIR)
{
xattributes.override_redirect =
@@ -837,6 +849,10 @@ _gdk_window_impl_new (GdkWindow *window,
if (attributes_mask & GDK_WA_TYPE_HINT)
gdk_window_set_type_hint (window, attributes->type_hint);
+
+ gdk_event_source_select_events ((GdkEventSource *) display_x11->event_source,
+ GDK_WINDOW_XWINDOW (window), event_mask,
+ StructureNotifyMask | PropertyChangeMask);
}
static GdkEventMask
@@ -2647,41 +2663,30 @@ gdk_window_x11_set_back_pixmap (GdkWindow *window,
}
static void
-gdk_window_x11_set_cursor (GdkWindow *window,
- GdkCursor *cursor)
+gdk_window_x11_set_device_cursor (GdkWindow *window,
+ GdkDevice *device,
+ GdkCursor *cursor)
{
GdkWindowObject *private;
GdkWindowImplX11 *impl;
- GdkCursorPrivate *cursor_private;
- Cursor xcursor;
-
- private = (GdkWindowObject *)window;
- impl = GDK_WINDOW_IMPL_X11 (private->impl);
- cursor_private = (GdkCursorPrivate*) cursor;
- if (impl->cursor)
- {
- gdk_cursor_unref (impl->cursor);
- impl->cursor = NULL;
- }
+ g_return_if_fail (GDK_IS_WINDOW (window));
+ g_return_if_fail (GDK_IS_DEVICE (device));
+
+ private = (GdkWindowObject *) window;
+ impl = GDK_WINDOW_IMPL_X11 (private->impl);
if (!cursor)
- xcursor = None;
+ g_hash_table_remove (impl->device_cursor, device);
else
{
_gdk_x11_cursor_update_theme (cursor);
- xcursor = cursor_private->xcursor;
+ g_hash_table_replace (impl->device_cursor,
+ device, gdk_cursor_ref (cursor));
}
-
+
if (!GDK_WINDOW_DESTROYED (window))
- {
- XDefineCursor (GDK_WINDOW_XDISPLAY (window),
- GDK_WINDOW_XID (window),
- xcursor);
-
- if (cursor)
- impl->cursor = gdk_cursor_ref (cursor);
- }
+ GDK_DEVICE_GET_CLASS (device)->set_window_cursor (device, window, cursor);
}
GdkCursor *
@@ -3008,106 +3013,112 @@ gdk_window_get_frame_extents (GdkWindow *window,
}
void
-_gdk_windowing_get_pointer (GdkDisplay *display,
- GdkScreen **screen,
- gint *x,
- gint *y,
- GdkModifierType *mask)
+_gdk_windowing_get_device_state (GdkDisplay *display,
+ GdkDevice *device,
+ GdkScreen **screen,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
{
GdkScreen *default_screen;
- Display *xdisplay;
- Window xwindow;
- Window root = None;
- Window child;
- int rootx, rooty;
- int winx;
- int winy;
- unsigned int xmask;
if (display->closed)
return;
default_screen = gdk_display_get_default_screen (display);
- xdisplay = GDK_SCREEN_XDISPLAY (default_screen);
- xwindow = GDK_SCREEN_XROOTWIN (default_screen);
-
- if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
+
+ if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
{
- XQueryPointer (xdisplay, xwindow,
- &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
- }
- else
+ GdkWindow *root;
+
+ GDK_DEVICE_GET_CLASS (device)->query_state (device,
+ gdk_screen_get_root_window (default_screen),
+ &root, NULL,
+ x, y,
+ NULL, NULL,
+ mask);
+ *screen = gdk_drawable_get_screen (root);
+ }
+ else
{
XSetWindowAttributes attributes;
- Window w;
-
- w = XCreateWindow (xdisplay, xwindow, 0, 0, 1, 1, 0,
- CopyFromParent, InputOnly, CopyFromParent,
+ Display *xdisplay;
+ Window xwindow, w, root, child;
+ int rootx, rooty, winx, winy;
+ unsigned int xmask;
+
+ /* FIXME: untrusted clients not multidevice-safe */
+
+ xdisplay = GDK_SCREEN_XDISPLAY (default_screen);
+ xwindow = GDK_SCREEN_XROOTWIN (default_screen);
+
+ w = XCreateWindow (xdisplay, xwindow, 0, 0, 1, 1, 0,
+ CopyFromParent, InputOnly, CopyFromParent,
0, &attributes);
- XQueryPointer (xdisplay, w,
+ XQueryPointer (xdisplay, w,
&root, &child, &rootx, &rooty, &winx, &winy, &xmask);
XDestroyWindow (xdisplay, w);
+
+ if (root != None)
+ {
+ GdkWindow *gdk_root = gdk_window_lookup_for_display (display, root);
+ *screen = gdk_drawable_get_screen (gdk_root);
+ }
+
+ *x = rootx;
+ *y = rooty;
+ *mask = xmask;
}
-
- if (root != None)
- {
- GdkWindow *gdk_root = gdk_window_lookup_for_display (display, root);
- *screen = gdk_drawable_get_screen (gdk_root);
- }
-
- *x = rootx;
- *y = rooty;
- *mask = xmask;
}
static gboolean
-gdk_window_x11_get_pointer (GdkWindow *window,
- gint *x,
- gint *y,
- GdkModifierType *mask)
+gdk_window_x11_get_device_state (GdkWindow *window,
+ GdkDevice *device,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
{
GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
gboolean return_val;
- Window root;
- Window child;
- int rootx, rooty;
- int winx = 0;
- int winy = 0;
- unsigned int xmask = 0;
g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), FALSE);
-
return_val = TRUE;
+
if (!GDK_WINDOW_DESTROYED (window))
{
if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
{
- if (XQueryPointer (GDK_WINDOW_XDISPLAY (window),
- GDK_WINDOW_XID (window),
- &root, &child, &rootx, &rooty, &winx, &winy, &xmask))
- {
- if (child)
- return_val = gdk_window_lookup_for_display (GDK_WINDOW_DISPLAY (window), child) != NULL;
- }
+ GdkWindow *child;
+
+ GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
+ NULL, &child,
+ NULL, NULL,
+ x, y, mask);
+ return_val = (child != NULL);
}
else
{
GdkScreen *screen;
int originx, originy;
- _gdk_windowing_get_pointer (gdk_drawable_get_display (window), &screen,
- &rootx, &rooty, &xmask);
+ int rootx, rooty;
+ int winx = 0;
+ int winy = 0;
+ unsigned int xmask = 0;
+
+ _gdk_windowing_get_device_state (gdk_drawable_get_display (window), device,
+ &screen, &rootx, &rooty, &xmask);
gdk_window_get_origin (window, &originx, &originy);
winx = rootx - originx;
winy = rooty - originy;
+
+ *x = winx;
+ *y = winy;
+ *mask = xmask;
}
}
- *x = winx;
- *y = winy;
- *mask = xmask;
-
return return_val;
}
@@ -3131,6 +3142,8 @@ gdk_window_x11_get_pointer (GdkWindow *window,
* for the color picker in the #GtkColorSelectionDialog.
*
* Since: 2.8
+ *
+ * Deprecated: 3.0. Use gdk_display_warp_device() instead.
*/
void
gdk_display_warp_pointer (GdkDisplay *display,
@@ -3138,37 +3151,64 @@ gdk_display_warp_pointer (GdkDisplay *display,
gint x,
gint y)
{
- Display *xdisplay;
- Window dest;
+ GdkDevice *device;
- xdisplay = GDK_DISPLAY_XDISPLAY (display);
- dest = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
+ g_return_if_fail (GDK_IS_DISPLAY (display));
+ g_return_if_fail (GDK_IS_SCREEN (screen));
- XWarpPointer (xdisplay, None, dest, 0, 0, 0, 0, x, y);
+ device = display->core_pointer;
+ GDK_DEVICE_GET_CLASS (device)->warp (device, screen, x, y);
+}
+
+/**
+ * gdk_display_warp_device:
+ * @display: a #GdkDisplay.
+ * @device: a #GdkDevice.
+ * @screen: the screen of @display to warp @device to.
+ * @x: the X coordinate of the destination.
+ * @y: the Y coordinate of the destination.
+ *
+ * Warps @device in @display to the point @x,@y on
+ * the screen @screen, unless the device is confined
+ * to a window by a grab, in which case it will be moved
+ * as far as allowed by the grab. Warping the pointer
+ * creates events as if the user had moved the mouse
+ * instantaneously to the destination.
+ *
+ * Note that the pointer should normally be under the
+ * control of the user. This function was added to cover
+ * some rare use cases like keyboard navigation support
+ * for the color picker in the #GtkColorSelectionDialog.
+ *
+ * Since: 3.0
+ **/
+void
+gdk_display_warp_device (GdkDisplay *display,
+ GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y)
+{
+ g_return_if_fail (GDK_IS_DISPLAY (display));
+ g_return_if_fail (GDK_IS_DEVICE (device));
+ g_return_if_fail (GDK_IS_SCREEN (screen));
+ g_return_if_fail (display == gdk_device_get_display (device));
+
+ GDK_DEVICE_GET_CLASS (device)->warp (device, screen, x, y);
}
GdkWindow*
-_gdk_windowing_window_at_pointer (GdkDisplay *display,
- gint *win_x,
- gint *win_y,
- GdkModifierType *mask,
- gboolean get_toplevel)
+_gdk_windowing_window_at_device_position (GdkDisplay *display,
+ GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel)
{
GdkWindow *window;
GdkScreen *screen;
- Window root;
- Window xwindow;
- Window child;
- Window xwindow_last = 0;
- Display *xdisplay;
- int rootx = -1, rooty = -1;
- int winx, winy;
- unsigned int xmask;
screen = gdk_display_get_default_screen (display);
-
- xwindow = GDK_SCREEN_XROOTWIN (screen);
- xdisplay = GDK_SCREEN_XDISPLAY (screen);
/* This function really only works if the mouse pointer is held still
* during its operation. If it moves from one leaf window to another
@@ -3176,35 +3216,24 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display,
* and the result.
*/
gdk_x11_display_grab (display);
- if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
- {
- XQueryPointer (xdisplay, xwindow,
- &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
- if (root == xwindow)
- xwindow = child;
- else
- xwindow = root;
-
- while (xwindow)
- {
- xwindow_last = xwindow;
- XQueryPointer (xdisplay, xwindow,
- &root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask);
- if (get_toplevel && xwindow_last != root &&
- (window = gdk_window_lookup_for_display (display, xwindow_last)) != NULL &&
- GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
- {
- xwindow = xwindow_last;
- break;
- }
- }
- }
- else
+ if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
+ window = GDK_DEVICE_GET_CLASS (device)->window_at_position (device, win_x, win_y, mask, get_toplevel);
+ else
{
gint i, screens, width, height;
GList *toplevels, *list;
- Window pointer_window;
-
+ Window pointer_window, root, xwindow, child;
+ Window xwindow_last = 0;
+ Display *xdisplay;
+ int rootx = -1, rooty = -1;
+ int winx, winy;
+ unsigned int xmask;
+
+ /* FIXME: untrusted clients case not multidevice-safe */
+
+ xwindow = GDK_SCREEN_XROOTWIN (screen);
+ xdisplay = GDK_SCREEN_XDISPLAY (screen);
+
pointer_window = None;
screens = gdk_display_get_n_screens (display);
for (i = 0; i < screens; ++i) {
@@ -3265,16 +3294,17 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display,
GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
break;
}
+
+ window = gdk_window_lookup_for_display (display, xwindow_last);
+
+ *win_x = window ? winx : -1;
+ *win_y = window ? winy : -1;
+ if (mask)
+ *mask = xmask;
}
-
+
gdk_x11_display_ungrab (display);
- window = gdk_window_lookup_for_display (display, xwindow_last);
- *win_x = window ? winx : -1;
- *win_y = window ? winy : -1;
- if (mask)
- *mask = xmask;
-
return window;
}
@@ -3305,21 +3335,18 @@ gdk_window_x11_set_events (GdkWindow *window,
GdkEventMask event_mask)
{
long xevent_mask = 0;
- int i;
if (!GDK_WINDOW_DESTROYED (window))
{
+ GdkDisplayX11 *display_x11;
+
if (GDK_WINDOW_XID (window) != GDK_WINDOW_XROOTWIN (window))
xevent_mask = StructureNotifyMask | PropertyChangeMask;
- for (i = 0; i < _gdk_nenvent_masks; i++)
- {
- if (event_mask & (1 << (i + 1)))
- xevent_mask |= _gdk_event_mask_table[i];
- }
-
- XSelectInput (GDK_WINDOW_XDISPLAY (window),
- GDK_WINDOW_XID (window),
- xevent_mask);
+
+ display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window));
+ gdk_event_source_select_events ((GdkEventSource *) display_x11->event_source,
+ GDK_WINDOW_XWINDOW (window), event_mask,
+ xevent_mask);
}
}
@@ -5529,10 +5556,10 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface)
iface->set_back_pixmap = gdk_window_x11_set_back_pixmap;
iface->reparent = gdk_window_x11_reparent;
iface->clear_region = gdk_window_x11_clear_region;
- iface->set_cursor = gdk_window_x11_set_cursor;
+ iface->set_device_cursor = gdk_window_x11_set_device_cursor;
iface->get_geometry = gdk_window_x11_get_geometry;
iface->get_root_coords = gdk_window_x11_get_root_coords;
- iface->get_pointer = gdk_window_x11_get_pointer;
+ iface->get_device_state = gdk_window_x11_get_device_state;
iface->get_deskrelative_origin = gdk_window_x11_get_deskrelative_origin;
iface->shape_combine_region = gdk_window_x11_shape_combine_region;
iface->input_shape_combine_region = gdk_window_x11_input_shape_combine_region;
@@ -5540,10 +5567,63 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface)
iface->queue_antiexpose = _gdk_x11_window_queue_antiexpose;
iface->queue_translation = _gdk_x11_window_queue_translation;
iface->destroy = _gdk_x11_window_destroy;
- iface->input_window_destroy = _gdk_input_window_destroy;
- iface->input_window_crossing = _gdk_input_crossing_event;
iface->supports_native_bg = TRUE;
}
+static Bool
+timestamp_predicate (Display *display,
+ XEvent *xevent,
+ XPointer arg)
+{
+ Window xwindow = GPOINTER_TO_UINT (arg);
+ GdkDisplay *gdk_display = gdk_x11_lookup_xdisplay (display);
+
+ if (xevent->type == PropertyNotify &&
+ xevent->xproperty.window == xwindow &&
+ xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (gdk_display,
+ "GDK_TIMESTAMP_PROP"))
+ return True;
+
+ return False;
+}
+
+/**
+ * gdk_x11_get_server_time:
+ * @window: a #GdkWindow, used for communication with the server.
+ * The window must have GDK_PROPERTY_CHANGE_MASK in its
+ * events mask or a hang will result.
+ *
+ * Routine to get the current X server time stamp.
+ *
+ * Return value: the time stamp.
+ **/
+guint32
+gdk_x11_get_server_time (GdkWindow *window)
+{
+ Display *xdisplay;
+ Window xwindow;
+ guchar c = 'a';
+ XEvent xevent;
+ Atom timestamp_prop_atom;
+
+ g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+ g_return_val_if_fail (!GDK_WINDOW_DESTROYED (window), 0);
+
+ xdisplay = GDK_WINDOW_XDISPLAY (window);
+ xwindow = GDK_WINDOW_XWINDOW (window);
+ timestamp_prop_atom =
+ gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
+ "GDK_TIMESTAMP_PROP");
+
+ XChangeProperty (xdisplay, xwindow, timestamp_prop_atom,
+ timestamp_prop_atom,
+ 8, PropModeReplace, &c, 1);
+
+ XIfEvent (xdisplay, &xevent,
+ timestamp_predicate, GUINT_TO_POINTER(xwindow));
+
+ return xevent.xproperty.time;
+}
+
#define __GDK_WINDOW_X11_C__
#include "gdkaliasdef.c"
diff --git a/gdk/x11/gdkwindow-x11.h b/gdk/x11/gdkwindow-x11.h
index 9a7f2aed35..762f1044a2 100644
--- a/gdk/x11/gdkwindow-x11.h
+++ b/gdk/x11/gdkwindow-x11.h
@@ -60,6 +60,8 @@ struct _GdkWindowImplX11
GdkToplevelX11 *toplevel; /* Toplevel-specific information */
GdkCursor *cursor;
+ GHashTable *device_cursor;
+
gint8 toplevel_window_type;
guint no_bg : 1; /* Set when the window background is temporarily
* unset during resizing and scaling */
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 7a9644dca4..8f3340277f 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -804,6 +804,7 @@ gtk_combo_box_new_text
gtk_combo_box_new_with_model
gtk_combo_box_popdown
gtk_combo_box_popup
+gtk_combo_box_popup_for_device
gtk_combo_box_prepend_text
gtk_combo_box_remove_text
gtk_combo_box_set_active
@@ -1950,6 +1951,7 @@ gtk_list_store_swap
#if IN_FILE(__GTK_MAIN_C__)
gtk_get_option_group
gtk_get_current_event
+gtk_get_current_event_device
gtk_get_current_event_state
gtk_get_current_event_time
gtk_false G_GNUC_CONST
@@ -1963,6 +1965,8 @@ gtk_get_event_widget
gtk_grab_add
gtk_grab_get_current
gtk_grab_remove
+gtk_device_grab_add
+gtk_device_grab_remove
gtk_propagate_event
gtk_quit_add
gtk_quit_add_destroy
@@ -2020,6 +2024,7 @@ gtk_menu_get_type G_GNUC_CONST
gtk_menu_new
gtk_menu_popdown
gtk_menu_popup
+gtk_menu_popup_for_device
gtk_menu_reorder_child
gtk_menu_reposition
gtk_menu_set_accel_group
@@ -4304,6 +4309,7 @@ gtk_widget_activate
gtk_widget_is_composited
gtk_widget_add_accelerator
gtk_widget_add_events
+gtk_widget_add_device_events
gtk_widget_add_mnemonic_label
gtk_widget_can_activate_accel
gtk_widget_child_focus
@@ -4338,6 +4344,7 @@ gtk_widget_get_direction
gtk_widget_get_display
gtk_widget_get_double_buffered
gtk_widget_get_events
+gtk_widget_get_device_events
gtk_widget_get_extension_events
gtk_widget_get_has_tooltip
gtk_widget_get_modifier_style
@@ -4424,6 +4431,7 @@ gtk_widget_set_default_direction
gtk_widget_set_direction
gtk_widget_set_double_buffered
gtk_widget_set_events
+gtk_widget_set_device_events
gtk_widget_set_extension_events
gtk_widget_set_has_tooltip
gtk_widget_set_name
@@ -4470,6 +4478,9 @@ gtk_widget_set_realized
gtk_widget_get_realized
gtk_widget_set_mapped
gtk_widget_get_mapped
+gtk_widget_get_support_multidevice
+gtk_widget_set_support_multidevice
+gtk_widget_device_is_shadowed
#endif
#endif
@@ -4523,6 +4534,7 @@ gtk_window_group_get_type G_GNUC_CONST
gtk_window_group_new
gtk_window_group_remove_window
gtk_window_group_list_windows
+gtk_window_group_get_current_device_grab
gtk_window_has_toplevel_focus
gtk_window_iconify
gtk_window_is_active
diff --git a/gtk/gtkaboutdialog.c b/gtk/gtkaboutdialog.c
index 54e70d603c..6b17f1c2ec 100644
--- a/gtk/gtkaboutdialog.c
+++ b/gtk/gtkaboutdialog.c
@@ -194,9 +194,10 @@ static void follow_if_link (GtkAboutDialog
GtkTextView *text_view,
GtkTextIter *iter);
static void set_cursor_if_appropriate (GtkAboutDialog *about,
- GtkTextView *text_view,
- gint x,
- gint y);
+ GtkTextView *text_view,
+ GdkDevice *device,
+ gint x,
+ gint y);
static void display_credits_dialog (GtkWidget *button,
gpointer data);
static void display_license_dialog (GtkWidget *button,
@@ -1866,9 +1867,10 @@ text_view_event_after (GtkWidget *text_view,
static void
set_cursor_if_appropriate (GtkAboutDialog *about,
- GtkTextView *text_view,
- gint x,
- gint y)
+ GtkTextView *text_view,
+ GdkDevice *device,
+ gint x,
+ gint y)
{
GtkAboutDialogPrivate *priv = about->priv;
GSList *tags = NULL, *tagp = NULL;
@@ -1896,9 +1898,9 @@ set_cursor_if_appropriate (GtkAboutDialog *about,
priv->hovering_over_link = hovering_over_link;
if (hovering_over_link)
- gdk_window_set_cursor (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT), priv->hand_cursor);
+ gdk_window_set_device_cursor (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT), device, priv->hand_cursor);
else
- gdk_window_set_cursor (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT), priv->regular_cursor);
+ gdk_window_set_device_cursor (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT), device, priv->regular_cursor);
}
if (tags)
@@ -1916,7 +1918,7 @@ text_view_motion_notify_event (GtkWidget *text_view,
GTK_TEXT_WINDOW_WIDGET,
event->x, event->y, &x, &y);
- set_cursor_if_appropriate (about, GTK_TEXT_VIEW (text_view), x, y);
+ set_cursor_if_appropriate (about, GTK_TEXT_VIEW (text_view), event->device, x, y);
gdk_event_request_motions (event);
@@ -1929,15 +1931,27 @@ text_view_visibility_notify_event (GtkWidget *text_view,
GdkEventVisibility *event,
GtkAboutDialog *about)
{
+ GdkDeviceManager *device_manager;
+ GdkDisplay *display;
+ GList *devices, *d;
gint wx, wy, bx, by;
- gdk_window_get_pointer (gtk_widget_get_window (text_view), &wx, &wy, NULL);
+ display = gdk_drawable_get_display (event->window);
+ device_manager = gdk_display_get_device_manager (display);
+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
- gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
- GTK_TEXT_WINDOW_WIDGET,
- wx, wy, &bx, &by);
+ for (d = devices; d; d = d->next)
+ {
+ GdkDevice *dev = d->data;
- set_cursor_if_appropriate (about, GTK_TEXT_VIEW (text_view), bx, by);
+ gdk_window_get_device_position (text_view->window, dev, &wx, &wy, NULL);
+
+ gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
+ GTK_TEXT_WINDOW_WIDGET,
+ wx, wy, &bx, &by);
+
+ set_cursor_if_appropriate (about, GTK_TEXT_VIEW (text_view), dev, bx, by);
+ }
return FALSE;
}
diff --git a/gtk/gtkbutton.c b/gtk/gtkbutton.c
index 37367b3fb3..4ebe9a0ba8 100644
--- a/gtk/gtkbutton.c
+++ b/gtk/gtkbutton.c
@@ -88,9 +88,9 @@ struct _GtkButtonPrivate
GtkWidget *image;
guint align_set : 1;
guint image_is_stock : 1;
- guint has_grab : 1;
guint use_action_appearance : 1;
guint32 grab_time;
+ GdkDevice *grab_keyboard;
GtkPositionType image_position;
GtkAction *action;
};
@@ -1715,22 +1715,28 @@ gtk_real_button_activate (GtkButton *button)
{
GtkWidget *widget = GTK_WIDGET (button);
GtkButtonPrivate *priv;
+ GdkDevice *device;
guint32 time;
priv = GTK_BUTTON_GET_PRIVATE (button);
+ device = gtk_get_current_event_device ();
+
+ g_return_if_fail (device && device->source == GDK_SOURCE_KEYBOARD);
if (gtk_widget_get_realized (widget) && !button->activate_timeout)
{
time = gtk_get_current_event_time ();
- if (gdk_keyboard_grab (button->event_window, TRUE, time) ==
- GDK_GRAB_SUCCESS)
- {
- priv->has_grab = TRUE;
+
+ if (gdk_device_grab (device, button->event_window,
+ GDK_OWNERSHIP_WINDOW, TRUE,
+ GDK_KEY_PRESS | GDK_KEY_RELEASE,
+ NULL, time) == GDK_GRAB_SUCCESS)
+ {
+ gtk_device_grab_add (widget, device, TRUE);
+ priv->grab_keyboard = device;
priv->grab_time = time;
}
- gtk_grab_add (widget);
-
button->activate_timeout = gdk_threads_add_timeout (ACTIVATE_TIMEOUT,
button_activate_timeout,
button);
@@ -1752,12 +1758,12 @@ gtk_button_finish_activate (GtkButton *button,
g_source_remove (button->activate_timeout);
button->activate_timeout = 0;
- if (priv->has_grab)
+ if (priv->grab_keyboard)
{
- gdk_display_keyboard_ungrab (gtk_widget_get_display (widget),
- priv->grab_time);
+ gdk_device_ungrab (priv->grab_keyboard, priv->grab_time);
+ gtk_device_grab_remove (widget, priv->grab_keyboard);
+ priv->grab_keyboard = NULL;
}
- gtk_grab_remove (widget);
button->button_down = FALSE;
@@ -2247,8 +2253,14 @@ gtk_button_grab_notify (GtkWidget *widget,
gboolean was_grabbed)
{
GtkButton *button = GTK_BUTTON (widget);
+ GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
gboolean save_in;
+ if (button->activate_timeout &&
+ priv->grab_keyboard &&
+ gtk_widget_device_is_shadowed (widget, priv->grab_keyboard))
+ gtk_button_finish_activate (button, FALSE);
+
if (!was_grabbed)
{
save_in = button->in_button;
diff --git a/gtk/gtkcellrendereraccel.c b/gtk/gtkcellrendereraccel.c
index dedbfdae64..9dfd2c2a8a 100644
--- a/gtk/gtkcellrendereraccel.c
+++ b/gtk/gtkcellrendereraccel.c
@@ -30,6 +30,8 @@
#include "gtkalias.h"
+#define GTK_CELL_RENDERER_ACCEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_CELL_RENDERER_ACCEL, GtkCellRendererAccelPrivate))
+
static void gtk_cell_renderer_accel_get_property (GObject *object,
guint param_id,
GValue *value,
@@ -72,6 +74,14 @@ enum {
PROP_ACCEL_MODE
};
+typedef struct GtkCellRendererAccelPrivate GtkCellRendererAccelPrivate;
+
+struct GtkCellRendererAccelPrivate
+{
+ GdkDevice *grab_keyboard;
+ GdkDevice *grab_pointer;
+};
+
static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE (GtkCellRendererAccel, gtk_cell_renderer_accel, GTK_TYPE_CELL_RENDERER_TEXT)
@@ -213,6 +223,8 @@ gtk_cell_renderer_accel_class_init (GtkCellRendererAccelClass *cell_accel_class)
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1,
G_TYPE_STRING);
+
+ g_type_class_add_private (object_class, sizeof (GtkCellRendererAccelPrivate));
}
@@ -405,6 +417,7 @@ grab_key_callback (GtkWidget *widget,
GdkEventKey *event,
GtkCellRendererAccel *accel)
{
+ GtkCellRendererAccelPrivate *priv;
GdkModifierType accel_mods = 0;
guint accel_key;
gchar *path;
@@ -413,6 +426,7 @@ grab_key_callback (GtkWidget *widget,
GdkModifierType consumed_modifiers;
GdkDisplay *display;
+ priv = GTK_CELL_RENDERER_ACCEL_GET_PRIVATE (accel);
display = gtk_widget_get_display (widget);
if (event->is_modifier)
@@ -471,9 +485,9 @@ grab_key_callback (GtkWidget *widget,
edited = TRUE;
out:
- gtk_grab_remove (accel->grab_widget);
- gdk_display_keyboard_ungrab (display, event->time);
- gdk_display_pointer_ungrab (display, event->time);
+ gtk_device_grab_remove (accel->grab_widget, priv->grab_pointer);
+ gdk_device_ungrab (priv->grab_keyboard, event->time);
+ gdk_device_ungrab (priv->grab_pointer, event->time);
path = g_strdup (g_object_get_data (G_OBJECT (accel->edit_widget), "gtk-cell-renderer-text"));
@@ -481,7 +495,9 @@ grab_key_callback (GtkWidget *widget,
gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (accel->edit_widget));
accel->edit_widget = NULL;
accel->grab_widget = NULL;
-
+ priv->grab_keyboard = NULL;
+ priv->grab_pointer = NULL;
+
if (edited)
g_signal_emit (accel, signals[ACCEL_EDITED], 0, path,
accel_key, accel_mods, event->hardware_keycode);
@@ -497,11 +513,16 @@ static void
ungrab_stuff (GtkWidget *widget,
GtkCellRendererAccel *accel)
{
- GdkDisplay *display = gtk_widget_get_display (widget);
+ GtkCellRendererAccelPrivate *priv;
+
+ priv = GTK_CELL_RENDERER_ACCEL_GET_PRIVATE (accel);
+
+ gtk_device_grab_remove (accel->grab_widget, priv->grab_pointer);
+ gdk_device_ungrab (priv->grab_keyboard, GDK_CURRENT_TIME);
+ gdk_device_ungrab (priv->grab_pointer, GDK_CURRENT_TIME);
- gtk_grab_remove (accel->grab_widget);
- gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
- gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
+ priv->grab_keyboard = NULL;
+ priv->grab_pointer = NULL;
g_signal_handlers_disconnect_by_func (G_OBJECT (accel->grab_widget),
G_CALLBACK (grab_key_callback),
@@ -548,34 +569,62 @@ gtk_cell_renderer_accel_start_editing (GtkCellRenderer *cell,
GdkRectangle *cell_area,
GtkCellRendererState flags)
{
+ GtkCellRendererAccelPrivate *priv;
GtkCellRendererText *celltext;
GtkCellRendererAccel *accel;
GtkWidget *label;
GtkWidget *eventbox;
-
+ GdkDevice *device, *keyb, *pointer;
+ guint32 time;
+
celltext = GTK_CELL_RENDERER_TEXT (cell);
accel = GTK_CELL_RENDERER_ACCEL (cell);
+ priv = GTK_CELL_RENDERER_ACCEL_GET_PRIVATE (cell);
/* If the cell isn't editable we return NULL. */
if (celltext->editable == FALSE)
return NULL;
g_return_val_if_fail (widget->window != NULL, NULL);
-
- if (gdk_keyboard_grab (widget->window, FALSE,
- gdk_event_get_time (event)) != GDK_GRAB_SUCCESS)
+
+ if (event)
+ device = gdk_event_get_device (event);
+ else
+ device = gtk_get_current_event_device ();
+
+ if (!device)
+ return NULL;
+
+ if (device->source == GDK_SOURCE_KEYBOARD)
+ {
+ keyb = device;
+ pointer = gdk_device_get_associated_device (device);
+ }
+ else
+ {
+ pointer = device;
+ keyb = gdk_device_get_associated_device (device);
+ }
+
+ time = gdk_event_get_time (event);
+
+ if (gdk_device_grab (keyb, widget->window,
+ GDK_OWNERSHIP_WINDOW, FALSE,
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
+ NULL, time) != GDK_GRAB_SUCCESS)
return NULL;
- if (gdk_pointer_grab (widget->window, FALSE,
- GDK_BUTTON_PRESS_MASK,
- NULL, NULL,
- gdk_event_get_time (event)) != GDK_GRAB_SUCCESS)
+ if (gdk_device_grab (pointer, widget->window,
+ GDK_OWNERSHIP_WINDOW, FALSE,
+ GDK_BUTTON_PRESS_MASK,
+ NULL, time) != GDK_GRAB_SUCCESS)
{
- gdk_display_keyboard_ungrab (gtk_widget_get_display (widget),
- gdk_event_get_time (event));
+ gdk_device_ungrab (keyb, time);
return NULL;
}
-
+
+ priv->grab_keyboard = keyb;
+ priv->grab_pointer = pointer;
accel->grab_widget = widget;
g_signal_connect (G_OBJECT (widget), "key-press-event",
@@ -609,7 +658,7 @@ gtk_cell_renderer_accel_start_editing (GtkCellRenderer *cell,
gtk_widget_show_all (accel->edit_widget);
- gtk_grab_add (accel->grab_widget);
+ gtk_device_grab_add (accel->grab_widget, pointer, TRUE);
g_signal_connect (G_OBJECT (accel->edit_widget), "unrealize",
G_CALLBACK (ungrab_stuff), accel);
diff --git a/gtk/gtkcolorsel.c b/gtk/gtkcolorsel.c
index 34d2d4a7d9..10ec2724f7 100644
--- a/gtk/gtkcolorsel.c
+++ b/gtk/gtkcolorsel.c
@@ -149,6 +149,8 @@ struct _ColorSelectionPrivate
/* Window for grabbing on */
GtkWidget *dropper_grab_widget;
guint32 grab_time;
+ GdkDevice *keyboard_device;
+ GdkDevice *pointer_device;
/* Connection to settings */
gulong settings_connection;
@@ -1631,10 +1633,11 @@ make_picker_cursor (GdkScreen *screen)
}
static void
-grab_color_at_mouse (GdkScreen *screen,
- gint x_root,
- gint y_root,
- gpointer data)
+grab_color_at_pointer (GdkScreen *screen,
+ GdkDevice *device,
+ gint x_root,
+ gint y_root,
+ gpointer data)
{
GdkImage *image;
guint32 pixel;
@@ -1651,7 +1654,7 @@ grab_color_at_mouse (GdkScreen *screen,
{
gint x, y;
GdkDisplay *display = gdk_screen_get_display (screen);
- GdkWindow *window = gdk_display_get_window_at_pointer (display, &x, &y);
+ GdkWindow *window = gdk_display_get_window_at_device_position (display, device, &x, &y);
if (!window)
return;
image = gdk_drawable_get_image (window, x, y, 1, 1);
@@ -1682,18 +1685,19 @@ shutdown_eyedropper (GtkWidget *widget)
{
GtkColorSelection *colorsel;
ColorSelectionPrivate *priv;
- GdkDisplay *display = gtk_widget_get_display (widget);
colorsel = GTK_COLOR_SELECTION (widget);
- priv = colorsel->private_data;
+ priv = colorsel->private_data;
if (priv->has_grab)
{
- gdk_display_keyboard_ungrab (display, priv->grab_time);
- gdk_display_pointer_ungrab (display, priv->grab_time);
- gtk_grab_remove (priv->dropper_grab_widget);
+ gdk_device_ungrab (priv->keyboard_device, priv->grab_time);
+ gdk_device_ungrab (priv->pointer_device, priv->grab_time);
+ gtk_device_grab_remove (priv->dropper_grab_widget, priv->pointer_device);
priv->has_grab = FALSE;
+ priv->keyboard_device = NULL;
+ priv->pointer_device = NULL;
}
}
@@ -1702,8 +1706,9 @@ mouse_motion (GtkWidget *invisible,
GdkEventMotion *event,
gpointer data)
{
- grab_color_at_mouse (gdk_event_get_screen ((GdkEvent *)event),
- event->x_root, event->y_root, data);
+ grab_color_at_pointer (gdk_event_get_screen ((GdkEvent *) event),
+ gdk_event_get_device ((GdkEvent *) event),
+ event->x_root, event->y_root, data);
}
static gboolean
@@ -1716,8 +1721,9 @@ mouse_release (GtkWidget *invisible,
if (event->button != 1)
return FALSE;
- grab_color_at_mouse (gdk_event_get_screen ((GdkEvent *)event),
- event->x_root, event->y_root, data);
+ grab_color_at_pointer (gdk_event_get_screen ((GdkEvent *) event),
+ gdk_event_get_device ((GdkEvent *) event),
+ event->x_root, event->y_root, data);
shutdown_eyedropper (GTK_WIDGET (data));
@@ -1739,12 +1745,15 @@ key_press (GtkWidget *invisible,
gpointer data)
{
GdkDisplay *display = gtk_widget_get_display (invisible);
- GdkScreen *screen = gdk_event_get_screen ((GdkEvent *)event);
+ GdkScreen *screen = gdk_event_get_screen ((GdkEvent *) event);
+ GdkDevice *device, *pointer_device;
guint state = event->state & gtk_accelerator_get_default_mod_mask ();
gint x, y;
gint dx, dy;
- gdk_display_get_pointer (display, NULL, &x, &y, NULL);
+ device = gdk_event_get_device ((GdkEvent * ) event);
+ pointer_device = gdk_device_get_associated_device (device);
+ gdk_display_get_device_state (display, pointer_device, NULL, &x, &y, NULL);
dx = 0;
dy = 0;
@@ -1756,7 +1765,7 @@ key_press (GtkWidget *invisible,
case GDK_ISO_Enter:
case GDK_KP_Enter:
case GDK_KP_Space:
- grab_color_at_mouse (screen, x, y, data);
+ grab_color_at_pointer (screen, pointer_device, x, y, data);
/* fall through */
case GDK_Escape:
@@ -1797,8 +1806,8 @@ key_press (GtkWidget *invisible,
return FALSE;
}
- gdk_display_warp_pointer (display, screen, x + dx, y + dy);
-
+ gdk_display_warp_device (display, pointer_device, screen, x + dx, y + dy);
+
return TRUE;
}
@@ -1838,12 +1847,26 @@ get_screen_color (GtkWidget *button)
GtkColorSelection *colorsel = g_object_get_data (G_OBJECT (button), "COLORSEL");
ColorSelectionPrivate *priv = colorsel->private_data;
GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (button));
+ GdkDevice *device, *keyb_device, *pointer_device;
GdkCursor *picker_cursor;
GdkGrabStatus grab_status;
GtkWidget *grab_widget, *toplevel;
guint32 time = gtk_get_current_event_time ();
-
+
+ device = gtk_get_current_event_device ();
+
+ if (device->source == GDK_SOURCE_KEYBOARD)
+ {
+ keyb_device = device;
+ pointer_device = gdk_device_get_associated_device (device);
+ }
+ else
+ {
+ pointer_device = device;
+ keyb_device = gdk_device_get_associated_device (device);
+ }
+
if (priv->dropper_grab_widget == NULL)
{
grab_widget = gtk_window_new (GTK_WINDOW_POPUP);
@@ -1867,29 +1890,38 @@ get_screen_color (GtkWidget *button)
priv->dropper_grab_widget = grab_widget;
}
- if (gdk_keyboard_grab (priv->dropper_grab_widget->window,
- FALSE, time) != GDK_GRAB_SUCCESS)
+ if (gdk_device_grab (keyb_device,
+ priv->dropper_grab_widget->window,
+ GDK_OWNERSHIP_APPLICATION, FALSE,
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
+ NULL, time) != GDK_GRAB_SUCCESS)
return;
-
+
picker_cursor = make_picker_cursor (screen);
- grab_status = gdk_pointer_grab (priv->dropper_grab_widget->window,
- FALSE,
- GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK,
- NULL,
- picker_cursor,
- time);
+ grab_status = gdk_device_grab (pointer_device,
+ priv->dropper_grab_widget->window,
+ GDK_OWNERSHIP_APPLICATION,
+ FALSE,
+ GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK,
+ picker_cursor,
+ time);
gdk_cursor_unref (picker_cursor);
-
+
if (grab_status != GDK_GRAB_SUCCESS)
{
- gdk_display_keyboard_ungrab (gtk_widget_get_display (button), time);
+ gdk_device_ungrab (keyb_device, time);
return;
}
- gtk_grab_add (priv->dropper_grab_widget);
+ gtk_device_grab_add (priv->dropper_grab_widget,
+ pointer_device,
+ TRUE);
+
priv->grab_time = time;
priv->has_grab = TRUE;
-
+ priv->keyboard_device = keyb_device;
+ priv->pointer_device = pointer_device;
+
g_signal_connect (priv->dropper_grab_widget, "button-press-event",
G_CALLBACK (mouse_press), colorsel);
g_signal_connect (priv->dropper_grab_widget, "key-press-event",
diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c
index 23b159b88b..64c8e05658 100644
--- a/gtk/gtkcombobox.c
+++ b/gtk/gtkcombobox.c
@@ -127,6 +127,9 @@ struct _GtkComboBoxPrivate
gpointer row_separator_data;
GDestroyNotify row_separator_destroy;
+ GdkDevice *grab_pointer;
+ GdkDevice *grab_keyboard;
+
gchar *tearoff_title;
};
@@ -1861,27 +1864,31 @@ gtk_combo_box_menu_popup (GtkComboBox *combo_box,
static gboolean
popup_grab_on_window (GdkWindow *window,
- guint32 activate_time,
- gboolean grab_keyboard)
-{
- if ((gdk_pointer_grab (window, TRUE,
- GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- GDK_POINTER_MOTION_MASK,
- NULL, NULL, activate_time) == 0))
+ GdkDevice *keyboard,
+ GdkDevice *pointer,
+ guint32 activate_time)
+{
+ if (keyboard &&
+ gdk_device_grab (keyboard, window,
+ GDK_OWNERSHIP_WINDOW, TRUE,
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
+ NULL, activate_time) != GDK_GRAB_SUCCESS)
+ return FALSE;
+
+ if (pointer &&
+ gdk_device_grab (pointer, window,
+ GDK_OWNERSHIP_WINDOW, TRUE,
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK,
+ NULL, activate_time) != GDK_GRAB_SUCCESS)
{
- if (!grab_keyboard ||
- gdk_keyboard_grab (window, TRUE,
- activate_time) == 0)
- return TRUE;
- else
- {
- gdk_display_pointer_ungrab (gdk_drawable_get_display (window),
- activate_time);
- return FALSE;
- }
+ if (keyboard)
+ gdk_device_ungrab (keyboard, activate_time);
+
+ return FALSE;
}
- return FALSE;
+ return TRUE;
}
/**
@@ -1903,13 +1910,30 @@ gtk_combo_box_popup (GtkComboBox *combo_box)
g_signal_emit (combo_box, combo_box_signals[POPUP], 0);
}
-static void
-gtk_combo_box_real_popup (GtkComboBox *combo_box)
+/**
+ * gtk_combo_box_popup_for_device:
+ * @combo_box: a #GtkComboBox
+ * @device: a #GdkDevice
+ *
+ * Pops up the menu or dropdown list of @combo_box, the popup window
+ * will be grabbed so only @device and its associated pointer/keyboard
+ * are the only #GdkDevice<!-- -->s able to send events to it.
+ *
+ * Since: 3.0
+ **/
+void
+gtk_combo_box_popup_for_device (GtkComboBox *combo_box,
+ GdkDevice *device)
{
GtkComboBoxPrivate *priv = combo_box->priv;
gint x, y, width, height;
GtkTreePath *path = NULL, *ppath;
GtkWidget *toplevel;
+ GdkDevice *keyboard, *pointer;
+ guint32 time;
+
+ g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
+ g_return_if_fail (GDK_IS_DEVICE (device));
if (!gtk_widget_get_realized (GTK_WIDGET (combo_box)))
return;
@@ -1917,6 +1941,22 @@ gtk_combo_box_real_popup (GtkComboBox *combo_box)
if (gtk_widget_get_mapped (priv->popup_widget))
return;
+ if (priv->grab_pointer && priv->grab_keyboard)
+ return;
+
+ time = gtk_get_current_event_time ();
+
+ if (device->source == GDK_SOURCE_KEYBOARD)
+ {
+ keyboard = device;
+ pointer = gdk_device_get_associated_device (device);
+ }
+ else
+ {
+ pointer = device;
+ keyboard = gdk_device_get_associated_device (device);
+ }
+
if (GTK_IS_MENU (priv->popup_widget))
{
gtk_combo_box_menu_popup (combo_box,
@@ -1966,13 +2006,40 @@ gtk_combo_box_real_popup (GtkComboBox *combo_box)
gtk_widget_grab_focus (priv->tree_view);
if (!popup_grab_on_window (priv->popup_window->window,
- GDK_CURRENT_TIME, TRUE))
+ keyboard, pointer, time))
{
gtk_widget_hide (priv->popup_window);
return;
}
- gtk_grab_add (priv->popup_window);
+ gtk_device_grab_add (priv->popup_window, pointer, TRUE);
+ priv->grab_pointer = pointer;
+ priv->grab_keyboard = keyboard;
+}
+
+static void
+gtk_combo_box_real_popup (GtkComboBox *combo_box)
+{
+ GdkDevice *device;
+
+ device = gtk_get_current_event_device ();
+
+ if (!device)
+ {
+ GdkDeviceManager *device_manager;
+ GdkDisplay *display;
+ GList *devices;
+
+ display = gtk_widget_get_display (GTK_WIDGET (combo_box));
+ device_manager = gdk_display_get_device_manager (display);
+
+ /* No device was set, pick the first master device */
+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+ device = devices->data;
+ g_list_free (devices);
+ }
+
+ gtk_combo_box_popup_for_device (combo_box, device);
}
static gboolean
@@ -2014,10 +2081,13 @@ gtk_combo_box_popdown (GtkComboBox *combo_box)
if (!gtk_widget_get_realized (GTK_WIDGET (combo_box)))
return;
- gtk_grab_remove (priv->popup_window);
+ gtk_device_grab_remove (priv->popup_window, priv->grab_pointer);
gtk_widget_hide_all (priv->popup_window);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button),
FALSE);
+
+ priv->grab_pointer = NULL;
+ priv->grab_keyboard = NULL;
}
static gint
@@ -3896,7 +3966,7 @@ gtk_combo_box_list_button_pressed (GtkWidget *widget,
!gtk_widget_has_focus (priv->button))
gtk_widget_grab_focus (priv->button);
- gtk_combo_box_popup (combo_box);
+ gtk_combo_box_popup_for_device (combo_box, event->device);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), TRUE);
@@ -4092,7 +4162,9 @@ gtk_combo_box_list_scroll_timeout (GtkComboBox *combo_box)
if (priv->auto_scroll)
{
- gdk_window_get_pointer (priv->tree_view->window, &x, &y, NULL);
+ gdk_window_get_device_position (priv->tree_view->window,
+ priv->grab_pointer,
+ &x, &y, NULL);
gtk_combo_box_list_auto_scroll (combo_box, x, y);
}
diff --git a/gtk/gtkcombobox.h b/gtk/gtkcombobox.h
index cbe40f9ca5..f5141a7ded 100644
--- a/gtk/gtkcombobox.h
+++ b/gtk/gtkcombobox.h
@@ -133,6 +133,8 @@ gchar *gtk_combo_box_get_active_text (GtkComboBox *combo_box);
/* programmatic control */
void gtk_combo_box_popup (GtkComboBox *combo_box);
+void gtk_combo_box_popup_for_device (GtkComboBox *combo_box,
+ GdkDevice *device);
void gtk_combo_box_popdown (GtkComboBox *combo_box);
AtkObject* gtk_combo_box_get_popup_accessible (GtkComboBox *combo_box);
diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c
index 0c73e18e45..03f04363d5 100644
--- a/gtk/gtkdnd.c
+++ b/gtk/gtkdnd.c
@@ -398,8 +398,12 @@ gtk_drag_get_ipc_widget (GtkWidget *widget)
return result;
}
-
-#ifdef GDK_WINDOWING_X11
+/* FIXME: modifying the XEvent window as in root_key_filter() isn't
+ * going to work with XGE/XI2, since the actual event to handle would
+ * be allocated/freed before GDK gets to translate the event.
+ * Active grabs on the keyboard are used instead at the moment...
+ */
+#if defined (GDK_WINDOWING_X11) && !defined (XINPUT_2)
/*
* We want to handle a handful of keys during DND, e.g. Escape to abort.
@@ -418,7 +422,7 @@ root_key_filter (GdkXEvent *xevent,
GdkEvent *event,
gpointer data)
{
- XEvent *ev = (XEvent *)xevent;
+ XEvent *ev = (XEvent *) xevent;
if ((ev->type == KeyPress || ev->type == KeyRelease) &&
ev->xkey.root == ev->xkey.window)
@@ -458,6 +462,7 @@ static GrabKey grab_keys[] = {
static void
grab_dnd_keys (GtkWidget *widget,
+ GdkDevice *device,
guint32 time)
{
guint i;
@@ -488,6 +493,7 @@ grab_dnd_keys (GtkWidget *widget,
static void
ungrab_dnd_keys (GtkWidget *widget,
+ GdkDevice *device,
guint32 time)
{
guint i;
@@ -513,23 +519,28 @@ ungrab_dnd_keys (GtkWidget *widget,
gdk_error_trap_pop ();
}
-#else
+#else /* GDK_WINDOWING_X11 && !XINPUT_2 */
static void
grab_dnd_keys (GtkWidget *widget,
+ GdkDevice *device,
guint32 time)
{
- gdk_keyboard_grab (widget->window, FALSE, time);
+ gdk_device_grab (device, widget->window,
+ GDK_OWNERSHIP_APPLICATION, FALSE,
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
+ NULL, time);
}
static void
ungrab_dnd_keys (GtkWidget *widget,
+ GdkDevice *device,
guint32 time)
{
- gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), time);
+ gdk_device_ungrab (device, time);
}
-#endif
+#endif /* GDK_WINDOWING_X11 */
/***************************************************************
@@ -545,9 +556,20 @@ gtk_drag_release_ipc_widget (GtkWidget *widget)
{
GtkWindow *window = GTK_WINDOW (widget);
GdkScreen *screen = gtk_widget_get_screen (widget);
+ GdkDragContext *context = g_object_get_data (G_OBJECT (widget), "drag-context");
GSList *drag_widgets = g_object_get_data (G_OBJECT (screen),
"gtk-dnd-ipc-widgets");
- ungrab_dnd_keys (widget, GDK_CURRENT_TIME);
+ GdkDevice *pointer, *keyboard;
+
+ if (context)
+ {
+ pointer = gdk_drag_context_get_device (context);
+ keyboard = gdk_device_get_associated_device (pointer);
+
+ if (keyboard)
+ ungrab_dnd_keys (widget, keyboard, GDK_CURRENT_TIME);
+ }
+
if (window->group)
gtk_window_group_remove_window (window->group, window);
drag_widgets = g_slist_prepend (drag_widgets, widget);
@@ -940,11 +962,13 @@ gtk_drag_update_cursor (GtkDragSourceInfo *info)
if (cursor != info->cursor)
{
- gdk_pointer_grab (info->ipc_widget->window, FALSE,
- GDK_POINTER_MOTION_MASK |
- GDK_BUTTON_RELEASE_MASK,
- NULL,
- cursor, info->grab_time);
+ GdkDevice *pointer;
+
+ pointer = gdk_drag_context_get_device (info->context);
+ gdk_device_grab (pointer, info->ipc_widget->window,
+ GDK_OWNERSHIP_APPLICATION, FALSE,
+ GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
+ cursor, info->grab_time);
info->cursor = cursor;
}
}
@@ -2379,7 +2403,9 @@ gtk_drag_begin_internal (GtkWidget *widget,
GdkDragContext *context;
GtkWidget *ipc_widget;
GdkCursor *cursor;
-
+ GdkDevice *pointer, *keyboard;
+
+ pointer = keyboard = NULL;
ipc_widget = gtk_drag_get_ipc_widget (widget);
gtk_drag_get_event_actions (event, button, actions,
@@ -2390,24 +2416,45 @@ gtk_drag_begin_internal (GtkWidget *widget,
NULL);
if (event)
- time = gdk_event_get_time (event);
+ {
+ time = gdk_event_get_time (event);
+ pointer = gdk_event_get_device (event);
+
+ if (pointer->source == GDK_SOURCE_KEYBOARD)
+ {
+ keyboard = pointer;
+ pointer = gdk_device_get_associated_device (keyboard);
+ }
+ else
+ keyboard = gdk_device_get_associated_device (pointer);
+ }
+ else
+ {
+ pointer = gdk_display_get_core_pointer (gtk_widget_get_display (widget));
+ keyboard = gdk_device_get_associated_device (pointer);
+ }
- if (gdk_pointer_grab (ipc_widget->window, FALSE,
- GDK_POINTER_MOTION_MASK |
- GDK_BUTTON_RELEASE_MASK, NULL,
- cursor, time) != GDK_GRAB_SUCCESS)
+ if (!pointer)
+ return NULL;
+
+ if (gdk_device_grab (pointer, ipc_widget->window,
+ GDK_OWNERSHIP_APPLICATION, FALSE,
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_RELEASE_MASK,
+ cursor, time) != GDK_GRAB_SUCCESS)
{
gtk_drag_release_ipc_widget (ipc_widget);
return NULL;
}
- grab_dnd_keys (ipc_widget, time);
+ if (keyboard)
+ grab_dnd_keys (ipc_widget, keyboard, time);
/* We use a GTK grab here to override any grabs that the widget
* we are dragging from might have held
*/
- gtk_grab_add (ipc_widget);
-
+ gtk_device_grab_add (ipc_widget, pointer, FALSE);
+
tmp_list = g_list_last (target_list->list);
while (tmp_list)
{
@@ -2420,6 +2467,7 @@ gtk_drag_begin_internal (GtkWidget *widget,
source_widgets = g_slist_prepend (source_widgets, ipc_widget);
context = gdk_drag_begin (ipc_widget->window, targets);
+ gdk_drag_context_set_device (context, pointer);
g_list_free (targets);
info = gtk_drag_get_source_info (context, TRUE);
@@ -2451,10 +2499,10 @@ gtk_drag_begin_internal (GtkWidget *widget,
info->cur_x = event->motion.x_root;
info->cur_y = event->motion.y_root;
}
- else
+ else
{
- gdk_display_get_pointer (gtk_widget_get_display (widget),
- &info->cur_screen, &info->cur_x, &info->cur_y, NULL);
+ gdk_display_get_device_state (gtk_widget_get_display (widget), pointer,
+ &info->cur_screen, &info->cur_x, &info->cur_y, NULL);
}
g_signal_emit_by_name (widget, "drag-begin", info->context);
@@ -2510,11 +2558,11 @@ gtk_drag_begin_internal (GtkWidget *widget,
if (cursor != info->cursor)
{
- gdk_pointer_grab (widget->window, FALSE,
- GDK_POINTER_MOTION_MASK |
- GDK_BUTTON_RELEASE_MASK,
- NULL,
- cursor, time);
+ gdk_device_grab (pointer, widget->window,
+ GDK_OWNERSHIP_APPLICATION, FALSE,
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_RELEASE_MASK,
+ cursor, time);
info->cursor = cursor;
}
}
@@ -3468,11 +3516,13 @@ _gtk_drag_source_handle_event (GtkWidget *widget,
info);
if (info->cursor != cursor)
{
- gdk_pointer_grab (widget->window, FALSE,
- GDK_POINTER_MOTION_MASK |
- GDK_BUTTON_RELEASE_MASK,
- NULL,
- cursor, info->grab_time);
+ GdkDevice *pointer;
+
+ pointer = gdk_drag_context_get_device (context);
+ gdk_device_grab (pointer, widget->window,
+ GDK_OWNERSHIP_APPLICATION, FALSE,
+ GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
+ cursor, info->grab_time);
info->cursor = cursor;
}
@@ -4062,7 +4112,10 @@ gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
{
GdkEvent *send_event;
GtkWidget *source_widget = info->widget;
- GdkDisplay *display = gtk_widget_get_display (source_widget);
+ GdkDevice *pointer, *keyboard;
+
+ pointer = gdk_drag_context_get_device (info->context);
+ keyboard = gdk_device_get_associated_device (pointer);
if (info->update_idle)
{
@@ -4094,9 +4147,9 @@ gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
gtk_drag_key_cb,
info);
- gdk_display_pointer_ungrab (display, time);
- ungrab_dnd_keys (info->ipc_widget, time);
- gtk_grab_remove (info->ipc_widget);
+ gdk_device_ungrab (pointer, time);
+ ungrab_dnd_keys (info->ipc_widget, keyboard, time);
+ gtk_device_grab_remove (info->ipc_widget, pointer);
/* Send on a release pair to the original
* widget to convince it to release its grab. We need to
@@ -4114,7 +4167,7 @@ gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
send_event->button.axes = NULL;
send_event->button.state = 0;
send_event->button.button = info->button;
- send_event->button.device = gdk_display_get_core_pointer (display);
+ send_event->button.device = pointer;
send_event->button.x_root = 0;
send_event->button.y_root = 0;
@@ -4160,15 +4213,16 @@ gtk_drag_motion_cb (GtkWidget *widget,
if (event->is_hint)
{
GdkDisplay *display = gtk_widget_get_display (widget);
-
- gdk_display_get_pointer (display, &screen, &x_root, &y_root, NULL);
+
+ gdk_display_get_device_state (display, event->device,
+ &screen, &x_root, &y_root, NULL);
event->x_root = x_root;
event->y_root = y_root;
}
else
screen = gdk_event_get_screen ((GdkEvent *)event);
- gtk_drag_update (info, screen, event->x_root, event->y_root, (GdkEvent *)event);
+ gtk_drag_update (info, screen, event->x_root, event->y_root, (GdkEvent *) event);
return TRUE;
}
@@ -4192,10 +4246,12 @@ gtk_drag_key_cb (GtkWidget *widget,
GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
GdkModifierType state;
GdkWindow *root_window;
+ GdkDevice *pointer;
gint dx, dy;
dx = dy = 0;
state = event->state & gtk_accelerator_get_default_mod_mask ();
+ pointer = gdk_device_get_associated_device (gdk_event_get_device ((GdkEvent *) event));
if (event->type == GDK_KEY_PRESS)
{
@@ -4244,16 +4300,16 @@ gtk_drag_key_cb (GtkWidget *widget,
* that would be overkill.
*/
root_window = gtk_widget_get_root_window (widget);
- gdk_window_get_pointer (root_window, NULL, NULL, &state);
+ gdk_window_get_device_position (root_window, pointer, NULL, NULL, &state);
event->state = state;
if (dx != 0 || dy != 0)
{
info->cur_x += dx;
info->cur_y += dy;
- gdk_display_warp_pointer (gtk_widget_get_display (widget),
- gtk_widget_get_screen (widget),
- info->cur_x, info->cur_y);
+ gdk_display_warp_device (gtk_widget_get_display (widget), pointer,
+ gtk_widget_get_screen (widget),
+ info->cur_x, info->cur_y);
}
gtk_drag_update (info, info->cur_screen, info->cur_x, info->cur_y, (GdkEvent *)event);
@@ -4287,8 +4343,11 @@ gtk_drag_grab_notify_cb (GtkWidget *widget,
gpointer data)
{
GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
+ GdkDevice *pointer;
+
+ pointer = gdk_drag_context_get_device (info->context);
- if (!was_grabbed)
+ if (gtk_widget_device_is_shadowed (widget, pointer))
{
/* We have to block callbacks to avoid recursion here, because
gtk_drag_cancel calls gtk_grab_remove (via gtk_drag_end) */
diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
index 963cf33f53..3c7aa25f94 100644
--- a/gtk/gtkentry.c
+++ b/gtk/gtkentry.c
@@ -139,6 +139,8 @@ struct _GtkEntryPrivate
gint start_y;
gchar *im_module;
+
+ GdkDevice *completion_device;
};
typedef struct _GtkEntryPasswordHint GtkEntryPasswordHint;
@@ -9157,6 +9159,7 @@ static gint
gtk_entry_completion_timeout (gpointer data)
{
GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
+ GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (completion->priv->entry);
completion->priv->completion_timeout = 0;
@@ -9186,7 +9189,7 @@ gtk_entry_completion_timeout (gpointer data)
if (gtk_widget_get_visible (completion->priv->popup_window))
_gtk_entry_completion_resize_popup (completion);
else
- _gtk_entry_completion_popup (completion);
+ _gtk_entry_completion_popup (completion, priv->completion_device);
}
else
_gtk_entry_completion_popdown (completion);
@@ -9491,7 +9494,9 @@ static void
gtk_entry_completion_changed (GtkWidget *entry,
gpointer user_data)
{
+ GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
+ GdkDevice *device;
/* (re)install completion timeout */
if (completion->priv->completion_timeout)
@@ -9509,6 +9514,14 @@ gtk_entry_completion_changed (GtkWidget *entry,
return;
}
+ device = gtk_get_current_event_device ();
+
+ if (device && device->source == GDK_SOURCE_KEYBOARD)
+ device = gdk_device_get_associated_device (device);
+
+ if (device)
+ priv->completion_device = device;
+
completion->priv->completion_timeout =
gdk_threads_add_timeout (COMPLETION_TIMEOUT,
gtk_entry_completion_timeout,
diff --git a/gtk/gtkentrycompletion.c b/gtk/gtkentrycompletion.c
index 8237387391..6225b41dda 100644
--- a/gtk/gtkentrycompletion.c
+++ b/gtk/gtkentrycompletion.c
@@ -1473,7 +1473,8 @@ _gtk_entry_completion_resize_popup (GtkEntryCompletion *completion)
}
void
-_gtk_entry_completion_popup (GtkEntryCompletion *completion)
+_gtk_entry_completion_popup (GtkEntryCompletion *completion,
+ GdkDevice *device)
{
GtkTreeViewColumn *column;
GList *renderers;
@@ -1488,6 +1489,9 @@ _gtk_entry_completion_popup (GtkEntryCompletion *completion)
if (!gtk_widget_has_focus (completion->priv->entry))
return;
+ if (completion->priv->grab_device)
+ return;
+
completion->priv->ignore_enter = TRUE;
column = gtk_tree_view_get_column (GTK_TREE_VIEW (completion->priv->action_view), 0);
@@ -1520,13 +1524,16 @@ _gtk_entry_completion_popup (GtkEntryCompletion *completion)
gtk_widget_get_screen (completion->priv->entry));
gtk_widget_show (completion->priv->popup_window);
-
- gtk_grab_add (completion->priv->popup_window);
- gdk_pointer_grab (completion->priv->popup_window->window, TRUE,
- GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK |
- GDK_POINTER_MOTION_MASK,
- NULL, NULL, GDK_CURRENT_TIME);
+
+ gtk_device_grab_add (completion->priv->popup_window, device, TRUE);
+ gdk_device_grab (device, completion->priv->popup_window->window,
+ GDK_OWNERSHIP_WINDOW, TRUE,
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK,
+ NULL, GDK_CURRENT_TIME);
+
+ completion->priv->grab_device = device;
}
void
@@ -1536,9 +1543,14 @@ _gtk_entry_completion_popdown (GtkEntryCompletion *completion)
return;
completion->priv->ignore_enter = FALSE;
-
- gdk_pointer_ungrab (GDK_CURRENT_TIME);
- gtk_grab_remove (completion->priv->popup_window);
+
+ if (completion->priv->grab_device)
+ {
+ gdk_device_ungrab (completion->priv->grab_device, GDK_CURRENT_TIME);
+ gtk_device_grab_remove (completion->priv->popup_window,
+ completion->priv->grab_device);
+ completion->priv->grab_device = NULL;
+ }
gtk_widget_hide (completion->priv->popup_window);
}
diff --git a/gtk/gtkentryprivate.h b/gtk/gtkentryprivate.h
index a7678002b8..baf0b9fe1f 100644
--- a/gtk/gtkentryprivate.h
+++ b/gtk/gtkentryprivate.h
@@ -69,10 +69,13 @@ struct _GtkEntryCompletionPrivate
gchar *completion_prefix;
GSource *check_completion_idle;
+
+ GdkDevice *grab_device;
};
gboolean _gtk_entry_completion_resize_popup (GtkEntryCompletion *completion);
-void _gtk_entry_completion_popup (GtkEntryCompletion *completion);
+void _gtk_entry_completion_popup (GtkEntryCompletion *completion,
+ GdkDevice *device);
void _gtk_entry_completion_popdown (GtkEntryCompletion *completion);
void _gtk_entry_get_borders (GtkEntry *entry,
diff --git a/gtk/gtkhandlebox.c b/gtk/gtkhandlebox.c
index 5ff6050a9f..119ba107ed 100644
--- a/gtk/gtkhandlebox.c
+++ b/gtk/gtkhandlebox.c
@@ -42,6 +42,7 @@ struct _GtkHandleBoxPrivate
{
gint orig_x;
gint orig_y;
+ GdkDevice *grab_device;
};
enum {
@@ -1114,22 +1115,25 @@ gtk_handle_box_button_press (GtkWidget *widget,
hb->attach_allocation.height = 0;
}
hb->in_drag = TRUE;
+ private->grab_device = event->device;
fleur = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
GDK_FLEUR);
- if (gdk_pointer_grab (invisible->window,
- FALSE,
- (GDK_BUTTON1_MOTION_MASK |
- GDK_POINTER_MOTION_HINT_MASK |
- GDK_BUTTON_RELEASE_MASK),
- NULL,
- fleur,
- event->time) != 0)
+ if (gdk_device_grab (event->device,
+ invisible->window,
+ GDK_OWNERSHIP_WINDOW,
+ FALSE,
+ (GDK_BUTTON1_MOTION_MASK |
+ GDK_POINTER_MOTION_HINT_MASK |
+ GDK_BUTTON_RELEASE_MASK),
+ fleur,
+ event->time) != GDK_GRAB_SUCCESS)
{
hb->in_drag = FALSE;
+ private->grab_device = NULL;
}
else
{
- gtk_grab_add (invisible);
+ gtk_device_grab_add (invisible, private->grab_device, TRUE);
g_signal_connect (invisible, "event",
G_CALLBACK (gtk_handle_box_grab_event), hb);
}
@@ -1169,9 +1173,10 @@ gtk_handle_box_motion (GtkWidget *widget,
new_x = 0;
new_y = 0;
screen = gtk_widget_get_screen (widget);
- gdk_display_get_pointer (gdk_screen_get_display (screen),
- &pointer_screen,
- &new_x, &new_y, NULL);
+ gdk_display_get_device_state (gdk_screen_get_display (screen),
+ event->device,
+ &pointer_screen,
+ &new_x, &new_y, NULL);
if (pointer_screen != screen)
{
GtkHandleBoxPrivate *private = gtk_handle_box_get_private (hb);
@@ -1418,15 +1423,18 @@ static void
gtk_handle_box_end_drag (GtkHandleBox *hb,
guint32 time)
{
+ GtkHandleBoxPrivate *private = gtk_handle_box_get_private (hb);
GtkWidget *invisible = gtk_handle_box_get_invisible ();
-
+
hb->in_drag = FALSE;
- gtk_grab_remove (invisible);
- gdk_pointer_ungrab (time);
+ gtk_device_grab_remove (invisible, private->grab_device);
+ gdk_device_ungrab (private->grab_device, time);
g_signal_handlers_disconnect_by_func (invisible,
G_CALLBACK (gtk_handle_box_grab_event),
hb);
+
+ private->grab_device = NULL;
}
#define __GTK_HANDLE_BOX_C__
diff --git a/gtk/gtkiconview.c b/gtk/gtkiconview.c
index 4f07208930..0942ef5593 100644
--- a/gtk/gtkiconview.c
+++ b/gtk/gtkiconview.c
@@ -124,6 +124,7 @@ struct _GtkIconViewPrivate
gboolean doing_rubberband;
gint rubberband_x1, rubberband_y1;
gint rubberband_x2, rubberband_y2;
+ GdkDevice *rubberband_device;
guint scroll_timeout_id;
gint scroll_value_diff;
@@ -308,6 +309,7 @@ static void gtk_icon_view_set_cursor_item (GtkIco
GtkIconViewItem *item,
gint cursor_cell);
static void gtk_icon_view_start_rubberbanding (GtkIconView *icon_view,
+ GdkDevice *device,
gint x,
gint y);
static void gtk_icon_view_stop_rubberbanding (GtkIconView *icon_view);
@@ -2217,7 +2219,7 @@ gtk_icon_view_button_press (GtkWidget *widget,
}
if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
- gtk_icon_view_start_rubberbanding (icon_view, event->x, event->y);
+ gtk_icon_view_start_rubberbanding (icon_view, event->device, event->x, event->y);
}
/* don't draw keyboard focus around an clicked-on item */
@@ -2309,7 +2311,9 @@ gtk_icon_view_update_rubberband (gpointer data)
icon_view = GTK_ICON_VIEW (data);
- gdk_window_get_pointer (icon_view->priv->bin_window, &x, &y, NULL);
+ gdk_window_get_device_position (icon_view->priv->bin_window,
+ icon_view->priv->rubberband_device,
+ &x, &y, NULL);
x = MAX (x, 0);
y = MAX (y, 0);
@@ -2360,12 +2364,14 @@ gtk_icon_view_update_rubberband (gpointer data)
static void
gtk_icon_view_start_rubberbanding (GtkIconView *icon_view,
+ GdkDevice *device,
gint x,
gint y)
{
GList *items;
- g_assert (!icon_view->priv->doing_rubberband);
+ if (icon_view->priv->rubberband_device)
+ return;
for (items = icon_view->priv->items; items; items = items->next)
{
@@ -2380,8 +2386,9 @@ gtk_icon_view_start_rubberbanding (GtkIconView *icon_view,
icon_view->priv->rubberband_y2 = y;
icon_view->priv->doing_rubberband = TRUE;
+ icon_view->priv->rubberband_device = device;
- gtk_grab_add (GTK_WIDGET (icon_view));
+ gtk_device_grab_add (GTK_WIDGET (icon_view), device, TRUE);
}
static void
@@ -2390,10 +2397,12 @@ gtk_icon_view_stop_rubberbanding (GtkIconView *icon_view)
if (!icon_view->priv->doing_rubberband)
return;
+ gtk_device_grab_remove (GTK_WIDGET (icon_view),
+ icon_view->priv->rubberband_device);
+
icon_view->priv->doing_rubberband = FALSE;
+ icon_view->priv->rubberband_device = NULL;
- gtk_grab_remove (GTK_WIDGET (icon_view));
-
gtk_widget_queue_draw (GTK_WIDGET (icon_view));
}
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index 611cebbf80..a027f857e9 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -4786,7 +4786,6 @@ gtk_label_motion (GtkWidget *widget,
GtkLabel *label = GTK_LABEL (widget);
GtkLabelSelectionInfo *info = label->select_info;
gint index;
- gint x, y;
if (info == NULL)
return FALSE;
@@ -4799,8 +4798,7 @@ gtk_label_motion (GtkWidget *widget,
if (info->selection_anchor == info->selection_end)
{
- gdk_window_get_pointer (event->window, &x, &y, NULL);
- if (get_layout_index (label, x, y, &index))
+ if (get_layout_index (label, event->x, event->y, &index))
{
for (l = info->links; l != NULL; l = l->next)
{
@@ -4842,8 +4840,6 @@ gtk_label_motion (GtkWidget *widget,
if ((event->state & GDK_BUTTON1_MASK) == 0)
return FALSE;
- gdk_window_get_pointer (info->window, &x, &y, NULL);
-
if (info->in_drag)
{
if (gtk_drag_check_threshold (widget,
@@ -4868,6 +4864,9 @@ gtk_label_motion (GtkWidget *widget,
}
else
{
+ gint x, y;
+
+ gdk_window_get_device_position (info->window, event->device, &x, &y, NULL);
get_layout_index (label, x, y, &index);
if (info->select_words)
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index ed88d3898d..ea54a4b4e1 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1316,12 +1316,10 @@ gtk_main_iteration_do (gboolean blocking)
/* private libgtk to libgdk interfaces
*/
-gboolean gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
- GdkWindow **grab_window,
- gboolean *owner_events);
-gboolean gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
- GdkWindow **grab_window,
- gboolean *owner_events);
+gboolean gdk_device_grab_info_libgtk_only (GdkDisplay *display,
+ GdkDevice *device,
+ GdkWindow **grab_window,
+ gboolean *owner_events);
static void
rewrite_events_translate (GdkWindow *old_window,
@@ -1396,6 +1394,7 @@ rewrite_event_for_grabs (GdkEvent *event)
gpointer grab_widget_ptr;
gboolean owner_events;
GdkDisplay *display;
+ GdkDevice *device;
switch (event->type)
{
@@ -1407,20 +1406,15 @@ rewrite_event_for_grabs (GdkEvent *event)
case GDK_MOTION_NOTIFY:
case GDK_PROXIMITY_IN:
case GDK_PROXIMITY_OUT:
- display = gdk_drawable_get_display (event->proximity.window);
- if (!gdk_pointer_grab_info_libgtk_only (display, &grab_window, &owner_events) ||
- !owner_events)
- return NULL;
- break;
-
case GDK_KEY_PRESS:
case GDK_KEY_RELEASE:
- display = gdk_drawable_get_display (event->key.window);
- if (!gdk_keyboard_grab_info_libgtk_only (display, &grab_window, &owner_events) ||
+ display = gdk_drawable_get_display (event->any.window);
+ device = gdk_event_get_device (event);
+
+ if (!gdk_device_grab_info_libgtk_only (display, device, &grab_window, &owner_events) ||
!owner_events)
- return NULL;
+ return NULL;
break;
-
default:
return NULL;
}
@@ -1440,9 +1434,10 @@ void
gtk_main_do_event (GdkEvent *event)
{
GtkWidget *event_widget;
- GtkWidget *grab_widget;
+ GtkWidget *grab_widget = NULL;
GtkWindowGroup *window_group;
GdkEvent *rewritten_event = NULL;
+ GdkDevice *device;
GList *tmp_list;
if (event->type == GDK_SETTING)
@@ -1489,13 +1484,9 @@ gtk_main_do_event (GdkEvent *event)
event = rewritten_event;
event_widget = gtk_get_event_widget (event);
}
-
- window_group = gtk_main_get_window_group (event_widget);
- /* Push the event onto a stack of current events for
- * gtk_current_event_get().
- */
- current_events = g_list_prepend (current_events, event);
+ window_group = gtk_main_get_window_group (event_widget);
+ device = gdk_event_get_device (event);
/* If there is a grab in effect...
*/
@@ -1511,11 +1502,34 @@ gtk_main_do_event (GdkEvent *event)
gtk_widget_is_ancestor (event_widget, grab_widget))
grab_widget = event_widget;
}
- else
+ else if (device)
{
- grab_widget = event_widget;
+ grab_widget = gtk_window_group_get_current_device_grab (window_group, device);
+
+ if (grab_widget &&
+ gtk_widget_get_sensitive (event_widget) &&
+ gtk_widget_is_ancestor (event_widget, grab_widget))
+ grab_widget = event_widget;
+ }
+
+ if (!grab_widget)
+ grab_widget = event_widget;
+
+ /* If the widget receiving events is actually blocked by another device GTK+ grab */
+ if (device &&
+ _gtk_window_group_widget_is_blocked_for_device (window_group, grab_widget, device))
+ {
+ if (rewritten_event)
+ gdk_event_free (rewritten_event);
+
+ return;
}
+ /* Push the event onto a stack of current events for
+ * gtk_current_event_get().
+ */
+ current_events = g_list_prepend (current_events, event);
+
/* Not all events get sent to the grabbing widget.
* The delete, destroy, expose, focus change and resize
* events still get sent to the event widget because
@@ -1636,14 +1650,17 @@ gtk_main_do_event (GdkEvent *event)
break;
case GDK_ENTER_NOTIFY:
- GTK_PRIVATE_SET_FLAG (event_widget, GTK_HAS_POINTER);
- _gtk_widget_set_pointer_window (event_widget, event->any.window);
+ _gtk_widget_set_device_window (event_widget,
+ gdk_event_get_device (event),
+ event->any.window);
if (gtk_widget_is_sensitive (grab_widget))
gtk_widget_event (grab_widget, event);
break;
case GDK_LEAVE_NOTIFY:
- GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_HAS_POINTER);
+ _gtk_widget_set_device_window (event_widget,
+ gdk_event_get_device (event),
+ NULL);
if (gtk_widget_is_sensitive (grab_widget))
gtk_widget_event (grab_widget, event);
break;
@@ -1718,16 +1735,73 @@ typedef struct
gboolean was_grabbed;
gboolean is_grabbed;
gboolean from_grab;
+ GList *notified_windows;
+ GdkDevice *device;
} GrabNotifyInfo;
static void
+synth_crossing_for_grab_notify (GtkWidget *from,
+ GtkWidget *to,
+ GrabNotifyInfo *info,
+ GList *devices,
+ GdkCrossingMode mode)
+{
+ while (devices)
+ {
+ GdkDevice *device = devices->data;
+ GdkWindow *from_window, *to_window;
+
+ /* Do not propagate events more than once to
+ * the same windows if non-multidevice aware.
+ */
+ if (!from)
+ from_window = NULL;
+ else
+ {
+ from_window = _gtk_widget_get_device_window (from, device);
+
+ if (from_window &&
+ !gdk_window_get_support_multidevice (from_window) &&
+ g_list_find (info->notified_windows, from_window))
+ from_window = NULL;
+ }
+
+ if (!to)
+ to_window = NULL;
+ else
+ {
+ to_window = _gtk_widget_get_device_window (to, device);
+
+ if (to_window &&
+ !gdk_window_get_support_multidevice (to_window) &&
+ g_list_find (info->notified_windows, to_window))
+ to_window = NULL;
+ }
+
+ if (from_window || to_window)
+ {
+ _gtk_widget_synthesize_crossing ((from_window) ? from : NULL,
+ (to_window) ? to : NULL,
+ device, mode);
+
+ if (from_window)
+ info->notified_windows = g_list_prepend (info->notified_windows, from_window);
+
+ if (to_window)
+ info->notified_windows = g_list_prepend (info->notified_windows, to_window);
+ }
+
+ devices = devices->next;
+ }
+}
+
+static void
gtk_grab_notify_foreach (GtkWidget *child,
gpointer data)
-
{
GrabNotifyInfo *info = data;
-
gboolean was_grabbed, is_grabbed, was_shadowed, is_shadowed;
+ GList *devices;
was_grabbed = info->was_grabbed;
is_grabbed = info->is_grabbed;
@@ -1742,42 +1816,55 @@ gtk_grab_notify_foreach (GtkWidget *child,
if ((was_shadowed || is_shadowed) && GTK_IS_CONTAINER (child))
gtk_container_forall (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
-
+
+ if (info->device &&
+ _gtk_widget_get_device_window (child, info->device))
+ {
+ /* Device specified and is on widget */
+ devices = g_list_prepend (NULL, info->device);
+ }
+ else
+ devices = _gtk_widget_list_devices (child);
+
if (is_shadowed)
{
GTK_PRIVATE_SET_FLAG (child, GTK_SHADOWED);
- if (!was_shadowed && GTK_WIDGET_HAS_POINTER (child)
- && gtk_widget_is_sensitive (child))
- _gtk_widget_synthesize_crossing (child, info->new_grab_widget,
- GDK_CROSSING_GTK_GRAB);
+ if (!was_shadowed && devices &&
+ gtk_widget_is_sensitive (child))
+ synth_crossing_for_grab_notify (child, info->new_grab_widget,
+ info, devices,
+ GDK_CROSSING_GTK_GRAB);
}
else
{
GTK_PRIVATE_UNSET_FLAG (child, GTK_SHADOWED);
- if (was_shadowed && GTK_WIDGET_HAS_POINTER (child)
- && gtk_widget_is_sensitive (child))
- _gtk_widget_synthesize_crossing (info->old_grab_widget, child,
- info->from_grab ? GDK_CROSSING_GTK_GRAB
- : GDK_CROSSING_GTK_UNGRAB);
+ if (was_shadowed && devices &&
+ gtk_widget_is_sensitive (child))
+ synth_crossing_for_grab_notify (info->old_grab_widget, child,
+ info, devices,
+ info->from_grab ? GDK_CROSSING_GTK_GRAB :
+ GDK_CROSSING_GTK_UNGRAB);
}
if (was_shadowed != is_shadowed)
_gtk_widget_grab_notify (child, was_shadowed);
-
+
g_object_unref (child);
-
+ g_list_free (devices);
+
info->was_grabbed = was_grabbed;
info->is_grabbed = is_grabbed;
}
static void
gtk_grab_notify (GtkWindowGroup *group,
+ GdkDevice *device,
GtkWidget *old_grab_widget,
GtkWidget *new_grab_widget,
gboolean from_grab)
{
GList *toplevels;
- GrabNotifyInfo info;
+ GrabNotifyInfo info = { 0 };
if (old_grab_widget == new_grab_widget)
return;
@@ -1785,12 +1872,13 @@ gtk_grab_notify (GtkWindowGroup *group,
info.old_grab_widget = old_grab_widget;
info.new_grab_widget = new_grab_widget;
info.from_grab = from_grab;
+ info.device = device;
g_object_ref (group);
toplevels = gtk_window_list_toplevels ();
g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
-
+
while (toplevels)
{
GtkWindow *toplevel = toplevels->data;
@@ -1804,6 +1892,7 @@ gtk_grab_notify (GtkWindowGroup *group,
g_object_unref (toplevel);
}
+ g_list_free (info.notified_windows);
g_object_unref (group);
}
@@ -1829,7 +1918,7 @@ gtk_grab_add (GtkWidget *widget)
g_object_ref (widget);
group->grabs = g_slist_prepend (group->grabs, widget);
- gtk_grab_notify (group, old_grab_widget, widget, TRUE);
+ gtk_grab_notify (group, NULL, old_grab_widget, widget, TRUE);
}
}
@@ -1865,12 +1954,72 @@ gtk_grab_remove (GtkWidget *widget)
else
new_grab_widget = NULL;
- gtk_grab_notify (group, widget, new_grab_widget, FALSE);
+ gtk_grab_notify (group, NULL, widget, new_grab_widget, FALSE);
g_object_unref (widget);
}
}
+/**
+ * gtk_device_grab_add:
+ * @widget: a #GtkWidget
+ * @device: a #GtkDevice to grab on.
+ * @block_others: %TRUE to prevent other devices to interact with @widget.
+ *
+ * Adds a GTK+ grab on @device, so all the events on @device and its
+ * associated pointer or keyboard (if any) are delivered to @widget.
+ * If the @block_others parameter is %TRUE, any other devices will be
+ * unable to interact with @widget during the grab.
+ *
+ * Since: 3.0
+ **/
+void
+gtk_device_grab_add (GtkWidget *widget,
+ GdkDevice *device,
+ gboolean block_others)
+{
+ GtkWindowGroup *group;
+ GtkWidget *old_grab_widget;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (GDK_IS_DEVICE (device));
+
+ group = gtk_main_get_window_group (widget);
+ old_grab_widget = gtk_window_group_get_current_device_grab (group, device);
+
+ if (old_grab_widget != widget)
+ _gtk_window_group_add_device_grab (group, widget, device, block_others);
+
+ gtk_grab_notify (group, device, old_grab_widget, widget, TRUE);
+}
+
+/**
+ * gtk_device_grab_remove:
+ * @widget: a #GtkWidget
+ * @device: a #GdkDevice
+ *
+ * Removes a device grab from the given widget. You have to pair calls
+ * to gtk_device_grab_add() and gtk_device_grab_remove().
+ *
+ * Since: 3.0
+ **/
+void
+gtk_device_grab_remove (GtkWidget *widget,
+ GdkDevice *device)
+{
+ GtkWindowGroup *group;
+ GtkWidget *new_grab_widget;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (GDK_IS_DEVICE (device));
+
+ group = gtk_main_get_window_group (widget);
+ _gtk_window_group_remove_device_grab (group, widget, device);
+ new_grab_widget = gtk_window_group_get_current_device_grab (group, device);
+
+ gtk_grab_notify (group, device, widget, new_grab_widget, FALSE);
+}
+
void
gtk_init_add (GtkFunction function,
gpointer data)
@@ -2125,6 +2274,23 @@ gtk_get_current_event_state (GdkModifierType *state)
}
/**
+ * gtk_get_current_event_device:
+ *
+ * If there is a current event and it has a device, return that
+ * device, otherwise return %NULL.
+ *
+ * Returns: a #GdkDevice, or %NULL
+ **/
+GdkDevice *
+gtk_get_current_event_device (void)
+{
+ if (current_events)
+ return gdk_event_get_device (current_events->data);
+ else
+ return NULL;
+}
+
+/**
* gtk_get_event_widget:
* @event: a #GdkEvent
*
diff --git a/gtk/gtkmain.h b/gtk/gtkmain.h
index 13f0fcb44a..9b4c686469 100644
--- a/gtk/gtkmain.h
+++ b/gtk/gtkmain.h
@@ -138,6 +138,12 @@ void gtk_grab_add (GtkWidget *widget);
GtkWidget* gtk_grab_get_current (void);
void gtk_grab_remove (GtkWidget *widget);
+void gtk_device_grab_add (GtkWidget *widget,
+ GdkDevice *device,
+ gboolean block_others);
+void gtk_device_grab_remove (GtkWidget *widget,
+ GdkDevice *device);
+
void gtk_init_add (GtkFunction function,
gpointer data);
void gtk_quit_add_destroy (guint main_level,
@@ -160,6 +166,7 @@ void gtk_key_snooper_remove (guint snooper_handler_id);
GdkEvent* gtk_get_current_event (void);
guint32 gtk_get_current_event_time (void);
gboolean gtk_get_current_event_state (GdkModifierType *state);
+GdkDevice * gtk_get_current_event_device (void);
GtkWidget* gtk_get_event_widget (GdkEvent *event);
diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list
index 77873cb022..22af46d610 100644
--- a/gtk/gtkmarshalers.list
+++ b/gtk/gtkmarshalers.list
@@ -83,6 +83,7 @@ VOID:OBJECT,INT,OBJECT
VOID:OBJECT,INT,INT
VOID:OBJECT,INT,INT,BOXED,UINT,UINT
VOID:OBJECT,OBJECT
+VOID:OBJECT,POINTER
VOID:OBJECT,STRING
VOID:OBJECT,STRING,STRING
VOID:OBJECT,UINT
diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c
index 0bbfae42ac..e9999946d1 100644
--- a/gtk/gtkmenu.c
+++ b/gtk/gtkmenu.c
@@ -64,6 +64,7 @@
typedef struct _GtkMenuAttachData GtkMenuAttachData;
typedef struct _GtkMenuPrivate GtkMenuPrivate;
+typedef struct _GtkMenuPopdownData GtkMenuPopdownData;
struct _GtkMenuAttachData
{
@@ -100,6 +101,12 @@ struct _GtkMenuPrivate
guint no_toggle_size : 1;
};
+struct _GtkMenuPopdownData
+{
+ GtkMenu *menu;
+ GdkDevice *device;
+};
+
typedef struct
{
gint left_attach;
@@ -1370,33 +1377,38 @@ gtk_menu_tearoff_bg_copy (GtkMenu *menu)
static gboolean
popup_grab_on_window (GdkWindow *window,
- guint32 activate_time,
- gboolean grab_keyboard)
+ GdkDevice *keyboard,
+ GdkDevice *pointer,
+ guint32 activate_time)
{
- if ((gdk_pointer_grab (window, TRUE,
- GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
- GDK_POINTER_MOTION_MASK,
- NULL, NULL, activate_time) == 0))
+ if (keyboard &&
+ gdk_device_grab (keyboard, window,
+ GDK_OWNERSHIP_WINDOW, TRUE,
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
+ NULL, activate_time) != GDK_GRAB_SUCCESS)
+ return FALSE;
+
+ if (pointer &&
+ gdk_device_grab (pointer, window,
+ GDK_OWNERSHIP_WINDOW, TRUE,
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
+ GDK_POINTER_MOTION_MASK,
+ NULL, activate_time) != GDK_GRAB_SUCCESS)
{
- if (!grab_keyboard ||
- gdk_keyboard_grab (window, TRUE,
- activate_time) == 0)
- return TRUE;
- else
- {
- gdk_display_pointer_ungrab (gdk_drawable_get_display (window),
- activate_time);
- return FALSE;
- }
+ if (keyboard)
+ gdk_device_ungrab (keyboard, activate_time);
+
+ return FALSE;
}
- return FALSE;
+ return TRUE;
}
/**
- * gtk_menu_popup:
+ * gtk_menu_popup_for_device:
* @menu: a #GtkMenu.
+ * @device: (allow-none): a #GdkDevice
* @parent_menu_shell: (allow-none): the menu shell containing the triggering menu item, or %NULL
* @parent_menu_item: (allow-none): the menu item whose activation triggered the popup, or %NULL
* @func: (allow-none): a user supplied function used to position the menu, or %NULL
@@ -1406,9 +1418,9 @@ popup_grab_on_window (GdkWindow *window,
*
* Displays a menu and makes it available for selection. Applications can use
* this function to display context-sensitive menus, and will typically supply
- * %NULL for the @parent_menu_shell, @parent_menu_item, @func and @data
+ * %NULL for the @parent_menu_shell, @parent_menu_item, @func and @data
* parameters. The default menu positioning function will position the menu
- * at the current mouse cursor position.
+ * at the current position of @device (or its corresponding pointer).
*
* The @button parameter should be the mouse button pressed to initiate
* the menu popup. If the menu popup was initiated by something other than
@@ -1421,15 +1433,18 @@ popup_grab_on_window (GdkWindow *window,
* a mouse click or key press) that caused the initiation of the popup.
* Only if no such event is available, gtk_get_current_event_time() can
* be used instead.
+ *
+ * Since: 3.0
*/
void
-gtk_menu_popup (GtkMenu *menu,
- GtkWidget *parent_menu_shell,
- GtkWidget *parent_menu_item,
- GtkMenuPositionFunc func,
- gpointer data,
- guint button,
- guint32 activate_time)
+gtk_menu_popup_for_device (GtkMenu *menu,
+ GdkDevice *device,
+ GtkWidget *parent_menu_shell,
+ GtkWidget *parent_menu_item,
+ GtkMenuPositionFunc func,
+ gpointer data,
+ guint button,
+ guint32 activate_time)
{
GtkWidget *widget;
GtkWidget *xgrab_shell;
@@ -1439,13 +1454,26 @@ gtk_menu_popup (GtkMenu *menu,
gboolean grab_keyboard;
GtkMenuPrivate *priv;
GtkWidget *parent_toplevel;
+ GdkDevice *keyboard, *pointer;
g_return_if_fail (GTK_IS_MENU (menu));
+ g_return_if_fail (GDK_IS_DEVICE (device));
widget = GTK_WIDGET (menu);
menu_shell = GTK_MENU_SHELL (menu);
priv = gtk_menu_get_private (menu);
+ if (device->source == GDK_SOURCE_KEYBOARD)
+ {
+ keyboard = device;
+ pointer = gdk_device_get_associated_device (device);
+ }
+ else
+ {
+ pointer = device;
+ keyboard = gdk_device_get_associated_device (device);
+ }
+
menu_shell->parent_menu_shell = parent_menu_shell;
priv->seen_item_enter = FALSE;
@@ -1493,10 +1521,16 @@ gtk_menu_popup (GtkMenu *menu,
grab_keyboard = gtk_menu_shell_get_take_focus (menu_shell);
gtk_window_set_accept_focus (GTK_WINDOW (menu->toplevel), grab_keyboard);
+ if (!grab_keyboard)
+ keyboard = NULL;
+
if (xgrab_shell && xgrab_shell != widget)
{
- if (popup_grab_on_window (xgrab_shell->window, activate_time, grab_keyboard))
- GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
+ if (popup_grab_on_window (xgrab_shell->window, keyboard, pointer, activate_time))
+ {
+ _gtk_menu_shell_set_grab_devices (GTK_MENU_SHELL (xgrab_shell), keyboard, pointer);
+ GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
+ }
}
else
{
@@ -1504,8 +1538,11 @@ gtk_menu_popup (GtkMenu *menu,
xgrab_shell = widget;
transfer_window = menu_grab_transfer_window_get (menu);
- if (popup_grab_on_window (transfer_window, activate_time, grab_keyboard))
- GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
+ if (popup_grab_on_window (transfer_window, keyboard, pointer, activate_time))
+ {
+ _gtk_menu_shell_set_grab_devices (GTK_MENU_SHELL (xgrab_shell), keyboard, pointer);
+ GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
+ }
}
if (!GTK_MENU_SHELL (xgrab_shell)->have_xgrab)
@@ -1519,6 +1556,7 @@ gtk_menu_popup (GtkMenu *menu,
return;
}
+ _gtk_menu_shell_set_grab_devices (GTK_MENU_SHELL (menu), keyboard, pointer);
menu_shell->active = TRUE;
menu_shell->button = button;
@@ -1614,8 +1652,9 @@ gtk_menu_popup (GtkMenu *menu,
gtk_widget_show (menu->toplevel);
if (xgrab_shell == widget)
- popup_grab_on_window (widget->window, activate_time, grab_keyboard); /* Should always succeed */
- gtk_grab_add (GTK_WIDGET (menu));
+ popup_grab_on_window (widget->window, keyboard, pointer, activate_time); /* Should always succeed */
+
+ gtk_device_grab_add (GTK_WIDGET (menu), pointer, TRUE);
if (parent_menu_shell)
{
@@ -1630,11 +1669,77 @@ gtk_menu_popup (GtkMenu *menu,
_gtk_menu_shell_update_mnemonics (menu_shell);
}
+/**
+ * gtk_menu_popup:
+ * @menu: a #GtkMenu.
+ * @parent_menu_shell: (allow-none): the menu shell containing the triggering menu item, or %NULL
+ * @parent_menu_item: (allow-none): the menu item whose activation triggered the popup, or %NULL
+ * @func: (allow-none): a user supplied function used to position the menu, or %NULL
+ * @data: (allow-none): user supplied data to be passed to @func.
+ * @button: the mouse button which was pressed to initiate the event.
+ * @activate_time: the time at which the activation event occurred.
+ *
+ * Displays a menu and makes it available for selection. Applications can use
+ * this function to display context-sensitive menus, and will typically supply
+ * %NULL for the @parent_menu_shell, @parent_menu_item, @func and @data
+ * parameters. The default menu positioning function will position the menu
+ * at the current mouse cursor position.
+ *
+ * The @button parameter should be the mouse button pressed to initiate
+ * the menu popup. If the menu popup was initiated by something other than
+ * a mouse button press, such as a mouse button release or a keypress,
+ * @button should be 0.
+ *
+ * The @activate_time parameter is used to conflict-resolve initiation of
+ * concurrent requests for mouse/keyboard grab requests. To function
+ * properly, this needs to be the time stamp of the user event (such as
+ * a mouse click or key press) that caused the initiation of the popup.
+ * Only if no such event is available, gtk_get_current_event_time() can
+ * be used instead.
+ */
+void
+gtk_menu_popup (GtkMenu *menu,
+ GtkWidget *parent_menu_shell,
+ GtkWidget *parent_menu_item,
+ GtkMenuPositionFunc func,
+ gpointer data,
+ guint button,
+ guint32 activate_time)
+{
+ GdkDevice *device;
+
+ g_return_if_fail (GTK_IS_MENU (menu));
+
+ device = gtk_get_current_event_device ();
+
+ if (!device)
+ {
+ GdkDisplay *display;
+ GdkDeviceManager *device_manager;
+ GList *devices;
+
+ display = gtk_widget_get_display (GTK_WIDGET (menu));
+ device_manager = gdk_display_get_device_manager (display);
+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+
+ device = devices->data;
+
+ g_list_free (devices);
+ }
+
+ gtk_menu_popup_for_device (menu, device,
+ parent_menu_shell,
+ parent_menu_item,
+ func, data,
+ button, activate_time);
+}
+
void
gtk_menu_popdown (GtkMenu *menu)
{
GtkMenuPrivate *private;
GtkMenuShell *menu_shell;
+ GdkDevice *pointer;
g_return_if_fail (GTK_IS_MENU (menu));
@@ -1676,15 +1781,16 @@ gtk_menu_popdown (GtkMenu *menu)
}
else
{
- /* We popped up the menu from the tearoff, so we need to
+ GdkDevice *keyboard, *pointer;
+
+ /* We popped up the menu from the tearoff, so we need to
* release the grab - we aren't actually hiding the menu.
*/
- if (menu_shell->have_xgrab)
+ if (menu_shell->have_xgrab &&
+ _gtk_menu_shell_get_grab_devices (menu_shell, &keyboard, &pointer))
{
- GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (menu));
-
- gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
- gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
+ gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
+ gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
}
}
@@ -1700,7 +1806,13 @@ gtk_menu_popdown (GtkMenu *menu)
gtk_widget_hide (GTK_WIDGET (menu));
menu_shell->have_xgrab = FALSE;
- gtk_grab_remove (GTK_WIDGET (menu));
+
+ _gtk_menu_shell_get_grab_devices (menu_shell, NULL, &pointer);
+
+ if (pointer)
+ gtk_device_grab_remove (GTK_WIDGET (menu), pointer);
+
+ _gtk_menu_shell_set_grab_devices (menu_shell, NULL, NULL);
menu_grab_transfer_window_destroy (menu);
}
@@ -3293,6 +3405,7 @@ gtk_menu_motion_notify (GtkWidget *widget,
send_event->crossing.x = event->x;
send_event->crossing.y = event->y;
send_event->crossing.state = event->state;
+ gdk_event_set_device (send_event, gdk_event_get_device ((GdkEvent *) event));
/* We send the event to 'widget', the currently active menu,
* instead of 'menu', the menu that the pointer is in. This
@@ -3967,14 +4080,17 @@ gtk_menu_stop_navigating_submenu (GtkMenu *menu)
static gboolean
gtk_menu_stop_navigating_submenu_cb (gpointer user_data)
{
- GtkMenu *menu = user_data;
+ GtkMenuPopdownData *popdown_data = user_data;
+ GtkMenu *menu = popdown_data->menu;
GdkWindow *child_window;
gtk_menu_stop_navigating_submenu (menu);
if (gtk_widget_get_realized (GTK_WIDGET (menu)))
{
- child_window = gdk_window_get_pointer (menu->bin_window, NULL, NULL, NULL);
+ child_window = gdk_window_get_device_position (menu->bin_window,
+ popdown_data->device,
+ NULL, NULL, NULL);
if (child_window)
{
@@ -3983,6 +4099,7 @@ gtk_menu_stop_navigating_submenu_cb (gpointer user_data)
send_event->crossing.window = g_object_ref (child_window);
send_event->crossing.time = GDK_CURRENT_TIME; /* Bogus */
send_event->crossing.send_event = TRUE;
+ gdk_event_set_device (send_event, popdown_data->device);
GTK_WIDGET_CLASS (gtk_menu_parent_class)->enter_notify_event (GTK_WIDGET (menu), (GdkEventCrossing *)send_event);
@@ -4089,6 +4206,7 @@ gtk_menu_set_submenu_navigation_region (GtkMenu *menu,
gint height = 0;
GdkPoint point[3];
GtkWidget *event_widget;
+ GtkMenuPopdownData *popdown_data;
g_return_if_fail (menu_item->submenu != NULL);
g_return_if_fail (event != NULL);
@@ -4163,9 +4281,15 @@ gtk_menu_set_submenu_navigation_region (GtkMenu *menu,
"gtk-menu-popdown-delay", &popdown_delay,
NULL);
- menu->navigation_timeout = gdk_threads_add_timeout (popdown_delay,
- gtk_menu_stop_navigating_submenu_cb,
- menu);
+ popdown_data = g_new (GtkMenuPopdownData, 1);
+ popdown_data->menu = menu;
+ popdown_data->device = gdk_event_get_device ((GdkEvent *) event);
+
+ menu->navigation_timeout = gdk_threads_add_timeout_full (G_PRIORITY_DEFAULT,
+ popdown_delay,
+ gtk_menu_stop_navigating_submenu_cb,
+ popdown_data,
+ (GDestroyNotify) g_free);
#ifdef DRAW_STAY_UP_TRIANGLE
draw_stay_up_triangle (gdk_get_default_root_window(),
@@ -4202,15 +4326,17 @@ gtk_menu_position (GtkMenu *menu)
GdkScreen *screen;
GdkScreen *pointer_screen;
GdkRectangle monitor;
-
+ GdkDevice *pointer;
+
g_return_if_fail (GTK_IS_MENU (menu));
widget = GTK_WIDGET (menu);
screen = gtk_widget_get_screen (widget);
- gdk_display_get_pointer (gdk_screen_get_display (screen),
- &pointer_screen, &x, &y, NULL);
-
+ _gtk_menu_shell_get_grab_devices (GTK_MENU_SHELL (menu), NULL, &pointer);
+ gdk_display_get_device_state (gdk_screen_get_display (screen),
+ pointer, &pointer_screen, &x, &y, NULL);
+
/* We need the requisition to figure out the right place to
* popup the menu. In fact, we always need to ask here, since
* if a size_request was queued while we weren't popped up,
@@ -5324,16 +5450,24 @@ gtk_menu_grab_notify (GtkWidget *widget,
GtkWidget *toplevel;
GtkWindowGroup *group;
GtkWidget *grab;
+ GdkDevice *pointer;
+
+ _gtk_menu_shell_get_grab_devices (GTK_MENU_SHELL (widget), NULL, &pointer);
+
+ if (!pointer ||
+ !gtk_widget_device_is_shadowed (widget, pointer))
+ return;
toplevel = gtk_widget_get_toplevel (widget);
+
+ if (!GTK_IS_WINDOW (toplevel))
+ return;
+
group = gtk_window_get_group (GTK_WINDOW (toplevel));
- grab = _gtk_window_group_get_current_grab (group);
+ grab = gtk_window_group_get_current_device_grab (group, pointer);
- if (!was_grabbed)
- {
- if (GTK_MENU_SHELL (widget)->active && !GTK_IS_MENU_SHELL (grab))
- gtk_menu_shell_cancel (GTK_MENU_SHELL (widget));
- }
+ if (GTK_MENU_SHELL (widget)->active && !GTK_IS_MENU_SHELL (grab))
+ gtk_menu_shell_cancel (GTK_MENU_SHELL (widget));
}
/**
diff --git a/gtk/gtkmenu.h b/gtk/gtkmenu.h
index 6a944c0584..0929472af7 100644
--- a/gtk/gtkmenu.h
+++ b/gtk/gtkmenu.h
@@ -133,6 +133,15 @@ void gtk_menu_popup (GtkMenu *menu,
gpointer data,
guint button,
guint32 activate_time);
+void gtk_menu_popup_for_device (GtkMenu *menu,
+ GdkDevice *device,
+ GtkWidget *parent_menu_shell,
+ GtkWidget *parent_menu_item,
+ GtkMenuPositionFunc func,
+ gpointer data,
+ guint button,
+ guint32 activate_time);
+
/* Position the menu according to its position function. Called
* from gtkmenuitem.c when a menu-item changes its allocation
diff --git a/gtk/gtkmenushell.c b/gtk/gtkmenushell.c
index c3e107fa1c..615f9a45c5 100644
--- a/gtk/gtkmenushell.c
+++ b/gtk/gtkmenushell.c
@@ -135,6 +135,9 @@ struct _GtkMenuShellPrivate
GtkMnemonicHash *mnemonic_hash;
GtkKeyHash *key_hash;
+ GdkDevice *grab_keyboard;
+ GdkDevice *grab_pointer;
+
guint take_focus : 1;
guint activated_submenu : 1;
/* This flag is a crutch to keep mnemonics in the same menu
@@ -548,7 +551,9 @@ _gtk_menu_shell_activate (GtkMenuShell *menu_shell)
{
if (!menu_shell->active)
{
- gtk_grab_add (GTK_WIDGET (menu_shell));
+ gtk_device_grab_add (GTK_WIDGET (menu_shell),
+ gtk_get_current_event_device (),
+ TRUE);
menu_shell->have_grab = TRUE;
menu_shell->active = TRUE;
}
@@ -1073,6 +1078,8 @@ gtk_real_menu_shell_deactivate (GtkMenuShell *menu_shell)
{
if (menu_shell->active)
{
+ GtkMenuShellPrivate *priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell);
+
menu_shell->button = 0;
menu_shell->active = FALSE;
menu_shell->activate_time = 0;
@@ -1086,15 +1093,16 @@ gtk_real_menu_shell_deactivate (GtkMenuShell *menu_shell)
if (menu_shell->have_grab)
{
menu_shell->have_grab = FALSE;
- gtk_grab_remove (GTK_WIDGET (menu_shell));
+ gtk_device_grab_remove (GTK_WIDGET (menu_shell), priv->grab_pointer);
}
if (menu_shell->have_xgrab)
{
- GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (menu_shell));
+ gdk_device_ungrab (priv->grab_pointer, GDK_CURRENT_TIME);
+ gdk_device_ungrab (priv->grab_keyboard, GDK_CURRENT_TIME);
menu_shell->have_xgrab = FALSE;
- gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
- gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
+ priv->grab_pointer = NULL;
+ priv->grab_keyboard = NULL;
}
menu_shell->keyboard_mode = FALSE;
@@ -1743,6 +1751,39 @@ _gtk_menu_shell_remove_mnemonic (GtkMenuShell *menu_shell,
gtk_menu_shell_reset_key_hash (menu_shell);
}
+void
+_gtk_menu_shell_set_grab_devices (GtkMenuShell *menu_shell,
+ GdkDevice *keyboard,
+ GdkDevice *pointer)
+{
+ GtkMenuShellPrivate *priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell);
+
+ g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
+ g_return_if_fail (!keyboard || GDK_IS_DEVICE (keyboard));
+ g_return_if_fail (!pointer || GDK_IS_DEVICE (pointer));
+
+ priv->grab_keyboard = keyboard;
+ priv->grab_pointer = pointer;
+}
+
+gboolean
+_gtk_menu_shell_get_grab_devices (GtkMenuShell *menu_shell,
+ GdkDevice **keyboard,
+ GdkDevice **pointer)
+{
+ GtkMenuShellPrivate *priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell);
+
+ g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), FALSE);
+
+ if (keyboard)
+ *keyboard = priv->grab_keyboard;
+
+ if (pointer)
+ *pointer = priv->grab_pointer;
+
+ return TRUE;
+}
+
/**
* gtk_menu_shell_get_take_focus:
* @menu_shell: a #GtkMenuShell
diff --git a/gtk/gtkmenushell.h b/gtk/gtkmenushell.h
index e0d042bf17..f8c5a32c54 100644
--- a/gtk/gtkmenushell.h
+++ b/gtk/gtkmenushell.h
@@ -118,6 +118,14 @@ void _gtk_menu_shell_select_last (GtkMenuShell *menu_shell,
gboolean search_sensitive);
void _gtk_menu_shell_activate (GtkMenuShell *menu_shell);
gint _gtk_menu_shell_get_popup_delay (GtkMenuShell *menu_shell);
+
+void _gtk_menu_shell_set_grab_devices (GtkMenuShell *menu_shell,
+ GdkDevice *keyboard,
+ GdkDevice *pointer);
+gboolean _gtk_menu_shell_get_grab_devices (GtkMenuShell *menu_shell,
+ GdkDevice **keyboard,
+ GdkDevice **pointer);
+
void gtk_menu_shell_cancel (GtkMenuShell *menu_shell);
void _gtk_menu_shell_add_mnemonic (GtkMenuShell *menu_shell,
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index 62008bafd3..bb528fdf07 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -2751,7 +2751,8 @@ get_drop_position (GtkNotebook *notebook,
static void
show_drag_window (GtkNotebook *notebook,
GtkNotebookPrivate *priv,
- GtkNotebookPage *page)
+ GtkNotebookPage *page,
+ GdkDevice *device)
{
GtkWidget *widget = GTK_WIDGET (notebook);
@@ -2786,10 +2787,10 @@ show_drag_window (GtkNotebook *notebook,
gdk_window_show (priv->drag_window);
/* the grab will dissapear when the window is hidden */
- gdk_pointer_grab (priv->drag_window,
- FALSE,
- GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
- NULL, NULL, GDK_CURRENT_TIME);
+ gdk_device_grab (device, priv->drag_window,
+ GDK_OWNERSHIP_WINDOW, FALSE,
+ GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
+ NULL, GDK_CURRENT_TIME);
}
/* This function undoes the reparenting that happens both when drag_window
@@ -3129,7 +3130,7 @@ gtk_notebook_motion_notify (GtkWidget *widget,
if (priv->operation != DRAG_OPERATION_REORDER)
{
priv->operation = DRAG_OPERATION_REORDER;
- show_drag_window (notebook, priv, page);
+ show_drag_window (notebook, priv, page, event->device);
}
gtk_notebook_pages_allocate (notebook);
diff --git a/gtk/gtkpaned.c b/gtk/gtkpaned.c
index d9c9177770..69e766d8a3 100644
--- a/gtk/gtkpaned.c
+++ b/gtk/gtkpaned.c
@@ -150,6 +150,7 @@ struct _GtkPanedPrivate
GtkWidget *saved_focus;
GtkPaned *first_paned;
guint32 grab_time;
+ GdkDevice *grab_device;
};
@@ -1215,18 +1216,20 @@ gtk_paned_button_press (GtkWidget *widget,
{
/* We need a server grab here, not gtk_grab_add(), since
* we don't want to pass events on to the widget's children */
- if (gdk_pointer_grab (paned->handle, FALSE,
- GDK_POINTER_MOTION_HINT_MASK
- | GDK_BUTTON1_MOTION_MASK
- | GDK_BUTTON_RELEASE_MASK
- | GDK_ENTER_NOTIFY_MASK
- | GDK_LEAVE_NOTIFY_MASK,
- NULL, NULL,
- event->time) != GDK_GRAB_SUCCESS)
+ if (gdk_device_grab (event->device,
+ paned->handle,
+ GDK_OWNERSHIP_WINDOW, FALSE,
+ GDK_POINTER_MOTION_HINT_MASK
+ | GDK_BUTTON1_MOTION_MASK
+ | GDK_BUTTON_RELEASE_MASK
+ | GDK_ENTER_NOTIFY_MASK
+ | GDK_LEAVE_NOTIFY_MASK,
+ NULL, event->time) != GDK_GRAB_SUCCESS)
return FALSE;
paned->in_drag = TRUE;
paned->priv->grab_time = event->time;
+ paned->priv->grab_device = event->device;
if (paned->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
paned->drag_pos = event->x;
@@ -1258,8 +1261,10 @@ stop_drag (GtkPaned *paned)
paned->in_drag = FALSE;
paned->drag_pos = -1;
paned->position_set = TRUE;
- gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (paned)),
- paned->priv->grab_time);
+
+ gdk_device_ungrab (paned->priv->grab_device,
+ paned->priv->grab_time);
+ paned->priv->grab_device = NULL;
}
static void
@@ -1267,8 +1272,12 @@ gtk_paned_grab_notify (GtkWidget *widget,
gboolean was_grabbed)
{
GtkPaned *paned = GTK_PANED (widget);
+ GdkDevice *grab_device;
+
+ grab_device = paned->priv->grab_device;
- if (!was_grabbed && paned->in_drag)
+ if (paned->in_drag && grab_device &&
+ gtk_widget_device_is_shadowed (widget, grab_device))
stop_drag (paned);
}
diff --git a/gtk/gtkplug-x11.c b/gtk/gtkplug-x11.c
index 95dcf1ab6f..d0df6f54c5 100644
--- a/gtk/gtkplug-x11.c
+++ b/gtk/gtkplug-x11.c
@@ -25,6 +25,21 @@
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
+#include "config.h"
+
+#ifdef XINPUT_2
+
+/* Hack to have keyboard events interpreted
+ * regardless of the default device manager
+ */
+#define GDK_COMPILATION
+#include "x11/gdkdevicemanager-core.h"
+#include "x11/gdkdevicemanager-xi2.h"
+#include "x11/gdkeventtranslator.h"
+#undef GDK_COMPILATION
+
+#endif /* XINPUT_2 */
+
#include "gtkmain.h"
#include "gtkmarshalers.h"
#include "gtkplug.h"
@@ -208,7 +223,7 @@ _gtk_plug_windowing_filter_func (GdkXEvent *gdk_xevent,
XEvent *xevent = (XEvent *)gdk_xevent;
GdkFilterReturn return_val;
-
+
return_val = GDK_FILTER_CONTINUE;
switch (xevent->type)
@@ -326,6 +341,61 @@ _gtk_plug_windowing_filter_func (GdkXEvent *gdk_xevent,
break;
}
+
+#ifdef XINPUT_2
+ case KeyPress:
+ case KeyRelease:
+ {
+ static GdkDeviceManager *core_device_manager = NULL;
+ GdkDeviceManager *device_manager;
+ GdkEvent *translated_event;
+ GList *devices, *d;
+ GdkDevice *keyboard = NULL;
+
+ device_manager = gdk_display_get_device_manager (display);
+
+ /* bail out if the device manager already
+ * interprets core keyboard events.
+ */
+ if (!GDK_IS_DEVICE_MANAGER_XI2 (device_manager))
+ return GDK_FILTER_CONTINUE;
+
+ /* Find out the first keyboard device, the
+ * generated event will be assigned to it.
+ */
+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+
+ for (d = devices; d; d = d->next)
+ {
+ GdkDevice *device = d->data;
+
+ if (device->source == GDK_SOURCE_KEYBOARD)
+ keyboard = device;
+ }
+
+ g_list_free (devices);
+
+ if (!keyboard)
+ return GDK_FILTER_CONTINUE;
+
+ /* This is a crude hack so key events
+ * are interpreted as if there was a
+ * GdkDeviceManagerCore available.
+ */
+ if (G_UNLIKELY (!core_device_manager))
+ core_device_manager = g_object_new (GDK_TYPE_DEVICE_MANAGER_CORE,
+ "display", display,
+ NULL);
+
+ translated_event = gdk_event_translator_translate (GDK_EVENT_TRANSLATOR (core_device_manager), display, xevent);
+ gdk_event_set_device (translated_event, keyboard);
+
+ gtk_main_do_event (translated_event);
+ gdk_event_free (translated_event);
+
+ return_val = GDK_FILTER_REMOVE;
+ }
+#endif
}
return return_val;
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index 4c5efb374b..8db5c48518 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -50,7 +50,6 @@ typedef enum
PRIVATE_GTK_REQUEST_NEEDED = 1 << 13, /* Whether we need to call gtk_widget_size_request */
PRIVATE_GTK_WIDTH_REQUEST_NEEDED = 1 << 14, /* Whether we need to call gtk_extended_layout_get_desired_width */
PRIVATE_GTK_HEIGHT_REQUEST_NEEDED = 1 << 15 /* Whether we need to call gtk_extended_layout_get_desired_height */
-
} GtkPrivateFlags;
/* Macros for extracting a widgets private_flags from GtkWidget.
diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c
index 744871d065..fa92d25651 100644
--- a/gtk/gtkrange.c
+++ b/gtk/gtkrange.c
@@ -139,6 +139,8 @@ struct _GtkRangeLayout
gint *mark_pos;
gint n_marks;
gboolean recalc_marks;
+
+ GdkDevice *grab_device;
};
@@ -2032,16 +2034,28 @@ gtk_range_expose (GtkWidget *widget,
static void
range_grab_add (GtkRange *range,
+ GdkDevice *device,
MouseLocation location,
gint button)
{
- /* we don't actually gtk_grab, since a button is down */
+ GtkRangeLayout *layout = range->layout;
+
+ if (device == layout->grab_device)
+ return;
+
+ if (layout->grab_device != NULL)
+ {
+ g_warning ("GtkRange already had a grab device, releasing device grab");
+ gtk_device_grab_remove (GTK_WIDGET (range), layout->grab_device);
+ }
+
+ /* we don't actually gdk_grab, since a button is down */
+ gtk_device_grab_add (GTK_WIDGET (range), device, TRUE);
- gtk_grab_add (GTK_WIDGET (range));
-
range->layout->grab_location = location;
range->layout->grab_button = button;
-
+ range->layout->grab_device = device;
+
if (gtk_range_update_mouse_location (range))
gtk_widget_queue_draw (GTK_WIDGET (range));
}
@@ -2049,10 +2063,16 @@ range_grab_add (GtkRange *range,
static void
range_grab_remove (GtkRange *range)
{
+ GtkRangeLayout *layout = range->layout;
MouseLocation location;
- gtk_grab_remove (GTK_WIDGET (range));
-
+ if (layout->grab_device)
+ {
+ gtk_device_grab_remove (GTK_WIDGET (range),
+ layout->grab_device);
+ layout->grab_device = NULL;
+ }
+
location = range->layout->grab_location;
range->layout->grab_location = MOUSE_OUTSIDE;
range->layout->grab_button = 0;
@@ -2177,9 +2197,15 @@ static gboolean
gtk_range_key_press (GtkWidget *widget,
GdkEventKey *event)
{
+ GdkDevice *device;
GtkRange *range = GTK_RANGE (widget);
+ GtkRangeLayout *layout = range->layout;
+
+ device = gdk_event_get_device ((GdkEvent *) event);
+ device = gdk_device_get_associated_device (device);
- if (event->keyval == GDK_Escape &&
+ if (device == layout->grab_device &&
+ event->keyval == GDK_Escape &&
range->layout->grab_location != MOUSE_OUTSIDE)
{
stop_scrolling (range);
@@ -2199,6 +2225,7 @@ gtk_range_button_press (GtkWidget *widget,
GdkEventButton *event)
{
GtkRange *range = GTK_RANGE (widget);
+ GdkDevice *device;
if (!gtk_widget_has_focus (widget))
gtk_widget_grab_focus (widget);
@@ -2207,8 +2234,10 @@ gtk_range_button_press (GtkWidget *widget,
if (range->layout->grab_location != MOUSE_OUTSIDE)
return FALSE;
+ device = gdk_event_get_device ((GdkEvent *) event);
range->layout->mouse_x = event->x;
range->layout->mouse_y = event->y;
+
if (gtk_range_update_mouse_location (range))
gtk_widget_queue_draw (widget);
@@ -2225,7 +2254,7 @@ gtk_range_button_press (GtkWidget *widget,
event->y : event->x);
range->trough_click_forward = click_value > range->adjustment->value;
- range_grab_add (range, MOUSE_TROUGH, event->button);
+ range_grab_add (range, device, MOUSE_TROUGH, event->button);
scroll = range_get_scroll_for_grab (range);
@@ -2242,7 +2271,7 @@ gtk_range_button_press (GtkWidget *widget,
GdkRectangle *stepper_area;
GtkScrollType scroll;
- range_grab_add (range, range->layout->mouse_location, event->button);
+ range_grab_add (range, device, range->layout->mouse_location, event->button);
stepper_area = get_area (range, range->layout->mouse_location);
gtk_widget_queue_draw_area (widget,
@@ -2309,7 +2338,7 @@ gtk_range_button_press (GtkWidget *widget,
range->slide_initial_coordinate = event->x;
}
- range_grab_add (range, MOUSE_SLIDER, event->button);
+ range_grab_add (range, device, MOUSE_SLIDER, event->button);
gtk_widget_style_get (widget, "activate-slider", &activate_slider, NULL);
@@ -2386,8 +2415,12 @@ gtk_range_grab_broken (GtkWidget *widget,
GdkEventGrabBroken *event)
{
GtkRange *range = GTK_RANGE (widget);
+ GdkDevice *device;
- if (range->layout->grab_location != MOUSE_OUTSIDE)
+ device = gdk_event_get_device ((GdkEvent *) event);
+
+ if (device == range->layout->grab_device &&
+ range->layout->grab_location != MOUSE_OUTSIDE)
{
if (range->layout->grab_location == MOUSE_SLIDER)
update_slider_position (range, range->layout->mouse_x, range->layout->mouse_y);
@@ -2405,6 +2438,7 @@ gtk_range_button_release (GtkWidget *widget,
GdkEventButton *event)
{
GtkRange *range = GTK_RANGE (widget);
+ GdkDevice *device;
if (event->window == range->event_window)
{
@@ -2413,13 +2447,17 @@ gtk_range_button_release (GtkWidget *widget,
}
else
{
- gdk_window_get_pointer (range->event_window,
- &range->layout->mouse_x,
- &range->layout->mouse_y,
- NULL);
+ gdk_window_get_device_position (range->event_window,
+ event->device,
+ &range->layout->mouse_x,
+ &range->layout->mouse_y,
+ NULL);
}
-
- if (range->layout->grab_button == event->button)
+
+ device = gdk_event_get_device ((GdkEvent *) event);
+
+ if (range->layout->grab_device == device &&
+ range->layout->grab_button == event->button)
{
if (range->layout->grab_location == MOUSE_SLIDER)
update_slider_position (range, range->layout->mouse_x, range->layout->mouse_y);
@@ -2551,7 +2589,10 @@ static void
gtk_range_grab_notify (GtkWidget *widget,
gboolean was_grabbed)
{
- if (!was_grabbed)
+ GtkRangeLayout *layout = GTK_RANGE (widget)->layout;
+
+ if (layout->grab_device &&
+ gtk_widget_device_is_shadowed (widget, layout->grab_device))
stop_scrolling (GTK_RANGE (widget));
}
diff --git a/gtk/gtkscalebutton.c b/gtk/gtkscalebutton.c
index f994d6e92f..dce3937a25 100644
--- a/gtk/gtkscalebutton.c
+++ b/gtk/gtkscalebutton.c
@@ -116,6 +116,9 @@ struct _GtkScaleButtonPrivate
gchar **icon_list;
+ GdkDevice *grab_pointer;
+ GdkDevice *grab_keyboard;
+
GtkAdjustment *adjustment; /* needed because it must be settable in init() */
};
@@ -901,6 +904,7 @@ gtk_scale_popup (GtkWidget *widget,
GdkDisplay *display;
GdkScreen *screen;
gboolean is_moved;
+ GdkDevice *device, *keyboard, *pointer;
is_moved = FALSE;
button = GTK_SCALE_BUTTON (widget);
@@ -982,21 +986,27 @@ gtk_scale_popup (GtkWidget *widget,
/* Move the dock, but set is_moved so we
* don't forward the first click later on,
* as it could make the scale go to the bottom */
- if (y < rect.y) {
- y = rect.y;
- is_moved = TRUE;
- } else if (y + d->allocation.height > rect.height + rect.y) {
- y = rect.y + rect.height - d->allocation.height;
- is_moved = TRUE;
- }
+ if (y < rect.y)
+ {
+ y = rect.y;
+ is_moved = TRUE;
+ }
+ else if (y + d->allocation.height > rect.height + rect.y)
+ {
+ y = rect.y + rect.height - d->allocation.height;
+ is_moved = TRUE;
+ }
- if (x < rect.x) {
- x = rect.x;
- is_moved = TRUE;
- } else if (x + d->allocation.width > rect.width + rect.x) {
- x = rect.x + rect.width - d->allocation.width;
- is_moved = TRUE;
- }
+ if (x < rect.x)
+ {
+ x = rect.x;
+ is_moved = TRUE;
+ }
+ else if (x + d->allocation.width > rect.width + rect.x)
+ {
+ x = rect.x + rect.width - d->allocation.width;
+ is_moved = TRUE;
+ }
}
gtk_window_move (GTK_WINDOW (priv->dock), x, y);
@@ -1004,28 +1014,46 @@ gtk_scale_popup (GtkWidget *widget,
if (event->type == GDK_BUTTON_PRESS)
GTK_WIDGET_CLASS (gtk_scale_button_parent_class)->button_press_event (widget, (GdkEventButton *) event);
+ device = gdk_event_get_device (event);
+
+ if (device->source == GDK_SOURCE_KEYBOARD)
+ {
+ keyboard = device;
+ pointer = gdk_device_get_associated_device (device);
+ }
+ else
+ {
+ pointer = device;
+ keyboard = gdk_device_get_associated_device (device);
+ }
+
/* grab focus */
- gtk_grab_add (priv->dock);
+ gtk_device_grab_add (priv->dock, pointer, TRUE);
- if (gdk_pointer_grab (priv->dock->window, TRUE,
- GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- GDK_POINTER_MOTION_MASK, NULL, NULL, time)
- != GDK_GRAB_SUCCESS)
+ if (gdk_device_grab (pointer, priv->dock->window,
+ GDK_OWNERSHIP_WINDOW, TRUE,
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK, NULL, time) != GDK_GRAB_SUCCESS)
{
- gtk_grab_remove (priv->dock);
+ gtk_device_grab_remove (priv->dock, pointer);
gtk_widget_hide (priv->dock);
return FALSE;
}
- if (gdk_keyboard_grab (priv->dock->window, TRUE, time) != GDK_GRAB_SUCCESS)
+ if (gdk_device_grab (keyboard, priv->dock->window,
+ GDK_OWNERSHIP_WINDOW, TRUE,
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
+ NULL, time) != GDK_GRAB_SUCCESS)
{
- gdk_display_pointer_ungrab (display, time);
- gtk_grab_remove (priv->dock);
+ gdk_device_ungrab (pointer, time);
+ gtk_device_grab_remove (priv->dock, pointer);
gtk_widget_hide (priv->dock);
return FALSE;
}
gtk_widget_grab_focus (priv->dock);
+ priv->grab_keyboard = keyboard;
+ priv->grab_pointer = pointer;
if (event->type == GDK_BUTTON_PRESS && !is_moved)
{
@@ -1080,8 +1108,21 @@ gtk_scale_button_popup (GtkWidget *widget)
{
GdkEvent *ev;
- ev = gdk_event_new (GDK_KEY_RELEASE);
- gtk_scale_popup (widget, ev, GDK_CURRENT_TIME);
+ /* This is a callback for a keybinding signal,
+ * current event should be the key event that
+ * triggered it.
+ */
+ ev = gtk_get_current_event ();
+
+ if (ev->type != GDK_KEY_PRESS &&
+ ev->type != GDK_KEY_RELEASE)
+ {
+ gdk_event_free (ev);
+ ev = gdk_event_new (GDK_KEY_RELEASE);
+ ev->key.time = GDK_CURRENT_TIME;
+ }
+
+ gtk_scale_popup (widget, ev, ev->key.time);
gdk_event_free (ev);
}
@@ -1100,22 +1141,35 @@ gtk_scale_button_grab_notify (GtkScaleButton *button,
{
GdkDisplay *display;
GtkScaleButtonPrivate *priv;
-
- if (was_grabbed != FALSE)
- return;
+ GtkWidget *toplevel, *grab_widget;
+ GtkWindowGroup *group;
priv = button->priv;
- if (!gtk_widget_has_grab (priv->dock))
+ if (!priv->grab_pointer ||
+ !gtk_widget_device_is_shadowed (GTK_WIDGET (button), priv->grab_pointer))
return;
- if (gtk_widget_is_ancestor (gtk_grab_get_current (), priv->dock))
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
+
+ if (GTK_IS_WINDOW (toplevel))
+ group = gtk_window_get_group (GTK_WINDOW (toplevel));
+ else
+ group = gtk_window_get_group (NULL);
+
+ grab_widget = gtk_window_group_get_current_device_grab (group, priv->grab_pointer);
+
+ if (grab_widget &&
+ gtk_widget_is_ancestor (grab_widget, priv->dock))
return;
display = gtk_widget_get_display (priv->dock);
- gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
- gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
- gtk_grab_remove (priv->dock);
+ gdk_device_ungrab (priv->grab_keyboard, GDK_CURRENT_TIME);
+ gdk_device_ungrab (priv->grab_pointer, GDK_CURRENT_TIME);
+ gtk_device_grab_remove (priv->dock, priv->grab_pointer);
+
+ priv->grab_keyboard = NULL;
+ priv->grab_pointer = NULL;
/* hide again */
gtk_widget_hide (priv->dock);
@@ -1227,7 +1281,7 @@ cb_dock_grab_notify (GtkWidget *widget,
static gboolean
cb_dock_grab_broken_event (GtkWidget *widget,
- gboolean was_grabbed,
+ gboolean was_grabbed,
gpointer user_data)
{
GtkScaleButton *button = (GtkScaleButton *) user_data;
@@ -1253,9 +1307,12 @@ gtk_scale_button_release_grab (GtkScaleButton *button,
/* ungrab focus */
display = gtk_widget_get_display (GTK_WIDGET (button));
- gdk_display_keyboard_ungrab (display, event->time);
- gdk_display_pointer_ungrab (display, event->time);
- gtk_grab_remove (priv->dock);
+ gdk_device_ungrab (priv->grab_keyboard, event->time);
+ gdk_device_ungrab (priv->grab_pointer, event->time);
+ gtk_device_grab_remove (priv->dock, priv->grab_pointer);
+
+ priv->grab_keyboard = NULL;
+ priv->grab_pointer = NULL;
/* hide again */
gtk_widget_hide (priv->dock);
@@ -1297,9 +1354,12 @@ gtk_scale_button_popdown (GtkWidget *widget)
/* ungrab focus */
display = gtk_widget_get_display (widget);
- gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
- gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
- gtk_grab_remove (priv->dock);
+ gdk_device_ungrab (priv->grab_keyboard, GDK_CURRENT_TIME);
+ gdk_device_ungrab (priv->grab_pointer, GDK_CURRENT_TIME);
+ gtk_device_grab_remove (priv->dock, priv->grab_pointer);
+
+ priv->grab_keyboard = NULL;
+ priv->grab_pointer = NULL;
/* hide again */
gtk_widget_hide (priv->dock);
@@ -1418,7 +1478,7 @@ gtk_scale_button_scale_press (GtkWidget *widget,
/* the scale will grab input; if we have input grabbed, all goes
* horribly wrong, so let's not do that.
*/
- gtk_grab_remove (priv->dock);
+ gtk_device_grab_remove (priv->dock, event->device);
return GTK_WIDGET_CLASS (_gtk_scale_button_scale_parent_class)->button_press_event (widget, event);
}
@@ -1453,7 +1513,7 @@ gtk_scale_button_scale_release (GtkWidget *widget,
* find that, so we do this complex 'first-call-parent-then-do-actual-
* action' thingy...
*/
- gtk_grab_add (button->priv->dock);
+ gtk_device_grab_add (button->priv->dock, event->device, TRUE);
return res;
}
diff --git a/gtk/gtksocket.c b/gtk/gtksocket.c
index dfb20f001d..5e6a1fb8ec 100644
--- a/gtk/gtksocket.c
+++ b/gtk/gtksocket.c
@@ -558,7 +558,7 @@ activate_key (GtkAccelGroup *accel_group,
if (gdk_event && gdk_event->type == GDK_KEY_PRESS && socket->plug_window)
{
- _gtk_socket_windowing_send_key_event (socket, gdk_event, TRUE);
+ _gtk_socket_windowing_send_key_event (socket, gdk_event, FALSE);
retval = TRUE;
}
diff --git a/gtk/gtkspinbutton.c b/gtk/gtkspinbutton.c
index 32934bcf89..71d7934bf0 100644
--- a/gtk/gtkspinbutton.c
+++ b/gtk/gtkspinbutton.c
@@ -903,10 +903,12 @@ gtk_spin_button_enter_notify (GtkWidget *widget,
if (event->window == spin->panel)
{
+ GdkDevice *device;
gint x;
gint y;
- gdk_window_get_pointer (spin->panel, &x, &y, NULL);
+ device = gdk_event_get_device ((GdkEvent *) event);
+ gdk_window_get_device_position (spin->panel, device, &x, &y, NULL);
if (y <= widget->requisition.height / 2)
spin->in_child = GTK_ARROW_UP;
@@ -915,7 +917,7 @@ gtk_spin_button_enter_notify (GtkWidget *widget,
gtk_widget_queue_draw (GTK_WIDGET (spin));
}
-
+
if (GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->enter_notify_event)
return GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->enter_notify_event (widget, event);
diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
index 2819c793c0..2c629f07b7 100644
--- a/gtk/gtktextview.c
+++ b/gtk/gtktextview.c
@@ -109,6 +109,7 @@ struct _GtkTextViewPrivate
guint blink_time; /* time in msec the cursor has blinked since last user event */
guint im_spot_idle;
gchar *im_module;
+ GdkDevice *grab_device;
guint scroll_after_paste : 1;
};
@@ -4084,7 +4085,12 @@ static void
gtk_text_view_grab_notify (GtkWidget *widget,
gboolean was_grabbed)
{
- if (!was_grabbed)
+ GtkTextViewPrivate *priv;
+
+ priv = GTK_TEXT_VIEW_GET_PRIVATE (widget);
+
+ if (priv->grab_device &&
+ gtk_widget_device_is_shadowed (widget, priv->grab_device))
{
gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget));
gtk_text_view_unobscure_mouse_cursor (GTK_TEXT_VIEW (widget));
@@ -5992,6 +5998,7 @@ gtk_text_view_unselect (GtkTextView *text_view)
static void
get_iter_at_pointer (GtkTextView *text_view,
+ GdkDevice *device,
GtkTextIter *iter,
gint *x,
gint *y)
@@ -5999,9 +6006,9 @@ get_iter_at_pointer (GtkTextView *text_view,
gint xcoord, ycoord;
GdkModifierType state;
- gdk_window_get_pointer (text_view->text_window->bin_window,
- &xcoord, &ycoord, &state);
-
+ gdk_window_get_device_position (text_view->text_window->bin_window,
+ device, &xcoord, &ycoord, &state);
+
gtk_text_layout_get_iter_at_pixel (text_view->layout,
iter,
xcoord + text_view->xoffset,
@@ -6015,12 +6022,13 @@ get_iter_at_pointer (GtkTextView *text_view,
static void
move_mark_to_pointer_and_scroll (GtkTextView *text_view,
- const gchar *mark_name)
+ const gchar *mark_name,
+ GdkDevice *device)
{
GtkTextIter newplace;
GtkTextMark *mark;
- get_iter_at_pointer (text_view, &newplace, NULL, NULL);
+ get_iter_at_pointer (text_view, device, &newplace, NULL, NULL);
mark = gtk_text_buffer_get_mark (get_buffer (text_view), mark_name);
@@ -6045,7 +6053,6 @@ selection_scan_timeout (gpointer data)
text_view = GTK_TEXT_VIEW (data);
- DV(g_print (G_STRLOC": calling move_mark_to_pointer_and_scroll\n"));
gtk_text_view_scroll_mark_onscreen (text_view,
gtk_text_buffer_get_insert (get_buffer (text_view)));
@@ -6074,10 +6081,12 @@ drag_scan_timeout (gpointer data)
GtkTextIter newplace;
gint x, y, width, height;
gdouble pointer_xoffset, pointer_yoffset;
+ GdkDevice *device;
text_view = GTK_TEXT_VIEW (data);
+ device = gdk_display_get_core_pointer (gtk_widget_get_display (GTK_WIDGET (data)));
- get_iter_at_pointer (text_view, &newplace, &x, &y);
+ get_iter_at_pointer (text_view, device, &newplace, &x, &y);
gdk_drawable_get_size (text_view->text_window->bin_window, &width, &height);
gtk_text_buffer_move_mark (get_buffer (text_view),
@@ -6214,11 +6223,17 @@ selection_motion_event_handler (GtkTextView *text_view,
GdkEventMotion *event,
SelectionData *data)
{
+ GtkTextViewPrivate *priv;
+
+ priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
gdk_event_request_motions (event);
+ if (priv->grab_device != event->device)
+ return FALSE;
+
if (data->granularity == SELECT_CHARACTERS)
{
- move_mark_to_pointer_and_scroll (text_view, "insert");
+ move_mark_to_pointer_and_scroll (text_view, "insert", event->device);
}
else
{
@@ -6231,7 +6246,7 @@ selection_motion_event_handler (GtkTextView *text_view,
gtk_text_buffer_get_iter_at_mark (buffer, &orig_start, data->orig_start);
gtk_text_buffer_get_iter_at_mark (buffer, &orig_end, data->orig_end);
- get_iter_at_pointer (text_view, &cursor, NULL, NULL);
+ get_iter_at_pointer (text_view, event->device, &cursor, NULL, NULL);
start = cursor;
extend_selection (text_view, data->granularity, &start, &end);
@@ -6265,6 +6280,7 @@ gtk_text_view_start_selection_drag (GtkTextView *text_view,
const GtkTextIter *iter,
GdkEventButton *button)
{
+ GtkTextViewPrivate *priv;
GtkTextIter cursor, ins, bound;
GtkTextIter orig_start, orig_end;
GtkTextBuffer *buffer;
@@ -6272,7 +6288,8 @@ gtk_text_view_start_selection_drag (GtkTextView *text_view,
if (text_view->selection_drag_handler != 0)
return;
-
+
+ priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
data = g_new0 (SelectionData, 1);
if (button->type == GDK_2BUTTON_PRESS)
@@ -6282,7 +6299,10 @@ gtk_text_view_start_selection_drag (GtkTextView *text_view,
else
data->granularity = SELECT_CHARACTERS;
- gtk_grab_add (GTK_WIDGET (text_view));
+ priv->grab_device = button->device;
+ gtk_device_grab_add (GTK_WIDGET (text_view),
+ priv->grab_device,
+ TRUE);
buffer = get_buffer (text_view);
@@ -6332,7 +6352,6 @@ gtk_text_view_start_selection_drag (GtkTextView *text_view,
&orig_start, TRUE);
data->orig_end = gtk_text_buffer_create_mark (buffer, NULL,
&orig_end, TRUE);
-
gtk_text_view_check_cursor_blink (text_view);
text_view->selection_drag_handler = g_signal_connect_data (text_view,
@@ -6346,6 +6365,13 @@ gtk_text_view_start_selection_drag (GtkTextView *text_view,
static gboolean
gtk_text_view_end_selection_drag (GtkTextView *text_view)
{
+ GtkTextViewPrivate *priv;
+
+ priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
+
+ if (!priv->grab_device)
+ return FALSE;
+
if (text_view->selection_drag_handler == 0)
return FALSE;
@@ -6358,7 +6384,9 @@ gtk_text_view_end_selection_drag (GtkTextView *text_view)
text_view->scroll_timeout = 0;
}
- gtk_grab_remove (GTK_WIDGET (text_view));
+ gtk_device_grab_remove (GTK_WIDGET (text_view),
+ priv->grab_device);
+ priv->grab_device = NULL;
return TRUE;
}
diff --git a/gtk/gtktooltip.c b/gtk/gtktooltip.c
index 204a2b6bba..d5a301be4e 100644
--- a/gtk/gtktooltip.c
+++ b/gtk/gtktooltip.c
@@ -1246,6 +1246,7 @@ _gtk_tooltip_focus_in (GtkWidget *widget)
gboolean return_value = FALSE;
GdkDisplay *display;
GtkTooltip *tooltip;
+ GdkDevice *device;
/* Get current tooltip for this display */
display = gtk_widget_get_display (widget);
@@ -1256,12 +1257,23 @@ _gtk_tooltip_focus_in (GtkWidget *widget)
if (!tooltip || !tooltip->keyboard_mode_enabled)
return;
+ device = gtk_get_current_event_device ();
+
+ if (device && device->source == GDK_SOURCE_KEYBOARD)
+ device = gdk_device_get_associated_device (device);
+
+ /* This function should be called by either a focus in event,
+ * or a key binding. In either case there should be a device.
+ */
+ if (!device)
+ return;
+
if (tooltip->keyboard_widget)
g_object_unref (tooltip->keyboard_widget);
tooltip->keyboard_widget = g_object_ref (widget);
- gdk_window_get_pointer (widget->window, &x, &y, NULL);
+ gdk_window_get_device_position (widget->window, device, &x, &y, NULL);
return_value = gtk_tooltip_run_requery (&widget, tooltip, &x, &y);
if (!return_value)
diff --git a/gtk/gtktreeprivate.h b/gtk/gtktreeprivate.h
index c44d61813d..e8887e0b17 100644
--- a/gtk/gtktreeprivate.h
+++ b/gtk/gtktreeprivate.h
@@ -406,7 +406,8 @@ void _gtk_tree_view_column_unset_tree_view (GtkTreeViewColumn *column);
void _gtk_tree_view_column_set_width (GtkTreeViewColumn *column,
gint width);
void _gtk_tree_view_column_start_drag (GtkTreeView *tree_view,
- GtkTreeViewColumn *column);
+ GtkTreeViewColumn *column,
+ GdkDevice *device);
gboolean _gtk_tree_view_column_cell_event (GtkTreeViewColumn *tree_column,
GtkCellEditable **editable_widget,
GdkEvent *event,
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index 533bb17e84..b75c75d218 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -396,8 +396,9 @@ static void update_prelight (GtkTreeView
/* interactive search */
static void gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
-static void gtk_tree_view_search_dialog_hide (GtkWidget *search_dialog,
- GtkTreeView *tree_view);
+static void gtk_tree_view_search_dialog_hide (GtkWidget *search_dialog,
+ GtkTreeView *tree_view,
+ GdkDevice *device);
static void gtk_tree_view_search_position_func (GtkTreeView *tree_view,
GtkWidget *search_dialog,
gpointer user_data);
@@ -457,6 +458,7 @@ static void gtk_tree_view_real_start_editing (GtkTreeView *tree_view,
static void gtk_tree_view_stop_editing (GtkTreeView *tree_view,
gboolean cancel_editing);
static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
+ GdkDevice *device,
gboolean keybinding);
static gboolean gtk_tree_view_start_interactive_search (GtkTreeView *tree_view);
static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView *tree_view,
@@ -5493,7 +5495,9 @@ gtk_tree_view_key_press (GtkWidget *widget,
if (tree_view->priv->imcontext_changed || /* we're in a preedit */
(retval && text_modified)) /* ...or the text was modified */
{
- if (gtk_tree_view_real_start_interactive_search (tree_view, FALSE))
+ if (gtk_tree_view_real_start_interactive_search (tree_view,
+ gdk_event_get_device ((GdkEvent *) event),
+ FALSE))
{
gtk_widget_grab_focus (GTK_WIDGET (tree_view));
return TRUE;
@@ -5602,7 +5606,8 @@ gtk_tree_view_focus_out (GtkWidget *widget,
/* destroy interactive search dialog */
if (tree_view->priv->search_window)
- gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
+ gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
+ gdk_event_get_device ((GdkEvent *) event));
return FALSE;
}
@@ -9265,7 +9270,8 @@ gtk_tree_view_set_column_drag_info (GtkTreeView *tree_view,
void
_gtk_tree_view_column_start_drag (GtkTreeView *tree_view,
- GtkTreeViewColumn *column)
+ GtkTreeViewColumn *column,
+ GdkDevice *device)
{
GdkEvent *send_event;
GtkAllocation allocation;
@@ -9314,6 +9320,7 @@ _gtk_tree_view_column_start_drag (GtkTreeView *tree_view,
send_event->crossing.subwindow = NULL;
send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
send_event->crossing.time = GDK_CURRENT_TIME;
+ gdk_event_set_device (send_event, device);
gtk_propagate_event (column->button, send_event);
gdk_event_free (send_event);
@@ -9327,9 +9334,9 @@ _gtk_tree_view_column_start_drag (GtkTreeView *tree_view,
send_event->button.axes = NULL;
send_event->button.state = 0;
send_event->button.button = 1;
- send_event->button.device = gdk_display_get_core_pointer (display);
send_event->button.x_root = 0;
send_event->button.y_root = 0;
+ gdk_event_set_device (send_event, device);
gtk_propagate_event (column->button, send_event);
gdk_event_free (send_event);
@@ -10249,7 +10256,7 @@ gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
static gboolean
gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
{
- gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
+ gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
tree_view->priv->typeselect_flush_timeout = 0;
return FALSE;
@@ -10258,17 +10265,43 @@ gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
/* Cut and paste from gtkwindow.c */
static void
send_focus_change (GtkWidget *widget,
+ GdkDevice *device,
gboolean in)
{
- GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
+ GdkDeviceManager *device_manager;
+ GList *devices, *d;
+
+ device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+ devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
+ devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
+
+ for (d = devices; d; d = d->next)
+ {
+ GdkDevice *dev = d->data;
+ GdkEvent *fevent;
+
+ if (dev->source != GDK_SOURCE_KEYBOARD)
+ continue;
+
+ /* Skip non-master keyboards that haven't
+ * selected for events from this window
+ */
+ if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
+ !gdk_window_get_device_events (widget->window, dev))
+ continue;
- fevent->focus_change.type = GDK_FOCUS_CHANGE;
- fevent->focus_change.window = g_object_ref (gtk_widget_get_window (widget));
- fevent->focus_change.in = in;
+ fevent = gdk_event_new (GDK_FOCUS_CHANGE);
- gtk_widget_send_focus_change (widget, fevent);
+ fevent->focus_change.type = GDK_FOCUS_CHANGE;
+ fevent->focus_change.window = g_object_ref (widget->window);
+ fevent->focus_change.in = in;
+ gdk_event_set_device (fevent, device);
- gdk_event_free (fevent);
+ gtk_widget_send_focus_change (widget, fevent);
+
+ gdk_event_free (fevent);
+ }
}
static void
@@ -10352,6 +10385,7 @@ gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
*/
static gboolean
gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
+ GdkDevice *device,
gboolean keybinding)
{
/* We only start interactive search if we have focus or the columns
@@ -10424,7 +10458,7 @@ gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
(entry_parent_class->grab_focus) (tree_view->priv->search_entry);
/* send focus-in event */
- send_focus_change (tree_view->priv->search_entry, TRUE);
+ send_focus_change (tree_view->priv->search_entry, device, TRUE);
/* search first matching iter */
gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
@@ -10435,7 +10469,9 @@ gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
static gboolean
gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
{
- return gtk_tree_view_real_start_interactive_search (tree_view, TRUE);
+ return gtk_tree_view_real_start_interactive_search (tree_view,
+ gtk_get_current_event_device (),
+ TRUE);
}
/* this function returns the new width of the column being resized given
@@ -14075,7 +14111,8 @@ gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
static void
gtk_tree_view_search_dialog_hide (GtkWidget *search_dialog,
- GtkTreeView *tree_view)
+ GtkTreeView *tree_view,
+ GdkDevice *device)
{
if (tree_view->priv->disable_popdown)
return;
@@ -14095,10 +14132,10 @@ gtk_tree_view_search_dialog_hide (GtkWidget *search_dialog,
if (gtk_widget_get_visible (search_dialog))
{
/* send focus-in event */
- send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
+ send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
gtk_widget_hide (search_dialog);
gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
- send_focus_change (GTK_WIDGET (tree_view), TRUE);
+ send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
}
}
@@ -14184,7 +14221,8 @@ gtk_tree_view_search_activate (GtkEntry *entry,
GtkRBTree *tree;
gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
- tree_view);
+ tree_view,
+ gtk_get_current_event_device ());
/* If we have a row selected and it's the cursor row, we activate
* the row XXX */
@@ -14225,7 +14263,7 @@ gtk_tree_view_search_delete_event (GtkWidget *widget,
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
- gtk_tree_view_search_dialog_hide (widget, tree_view);
+ gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
return TRUE;
}
@@ -14235,9 +14273,12 @@ gtk_tree_view_search_button_press_event (GtkWidget *widget,
GdkEventButton *event,
GtkTreeView *tree_view)
{
+ GdkDevice *keyb_device;
+
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
- gtk_tree_view_search_dialog_hide (widget, tree_view);
+ keyb_device = gdk_device_get_associated_device (event->device);
+ gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
if (event->window == tree_view->priv->bin_window)
gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
@@ -14294,7 +14335,8 @@ gtk_tree_view_search_key_press_event (GtkWidget *widget,
event->keyval == GDK_KP_Tab ||
event->keyval == GDK_ISO_Left_Tab))
{
- gtk_tree_view_search_dialog_hide (widget, tree_view);
+ gtk_tree_view_search_dialog_hide (widget, tree_view,
+ gdk_event_get_device ((GdkEvent *) event));
return TRUE;
}
diff --git a/gtk/gtktreeviewcolumn.c b/gtk/gtktreeviewcolumn.c
index 5c36375321..0d953de7af 100644
--- a/gtk/gtktreeviewcolumn.c
+++ b/gtk/gtktreeviewcolumn.c
@@ -1097,7 +1097,8 @@ gtk_tree_view_column_button_event (GtkWidget *widget,
(gint) ((GdkEventMotion *)event)->y)))
{
column->maybe_reordered = FALSE;
- _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (column->tree_view), column);
+ _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (column->tree_view), column,
+ event->motion.device);
return TRUE;
}
if (column->clickable == FALSE)
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 6cd6ba6250..b70cb2b693 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -376,6 +376,7 @@ static GQuark quark_aux_info = 0;
static GQuark quark_accel_path = 0;
static GQuark quark_accel_closures = 0;
static GQuark quark_event_mask = 0;
+static GQuark quark_device_event_mask = 0;
static GQuark quark_extension_event_mode = 0;
static GQuark quark_parent_window = 0;
static GQuark quark_pointer_window = 0;
@@ -472,6 +473,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
quark_accel_path = g_quark_from_static_string ("gtk-accel-path");
quark_accel_closures = g_quark_from_static_string ("gtk-accel-closures");
quark_event_mask = g_quark_from_static_string ("gtk-event-mask");
+ quark_device_event_mask = g_quark_from_static_string ("gtk-device-event-mask");
quark_extension_event_mode = g_quark_from_static_string ("gtk-extension-event-mode");
quark_parent_window = g_quark_from_static_string ("gtk-parent-window");
quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window");
@@ -3521,6 +3523,9 @@ gtk_widget_realize (GtkWidget *widget)
mode = gtk_widget_get_extension_events (widget);
if (mode != GDK_EXTENSION_EVENTS_NONE)
gtk_widget_set_extension_events_internal (widget, mode, NULL);
+
+ if ((GTK_WIDGET_FLAGS (widget) & GTK_MULTIDEVICE) != 0)
+ gdk_window_set_support_multidevice (widget->window, TRUE);
}
}
@@ -5655,6 +5660,62 @@ _gtk_widget_set_has_grab (GtkWidget *widget,
}
/**
+ * gtk_widget_device_is_shadowed:
+ * @widget: a #GtkWidget
+ * @device: a #GdkDevice
+ *
+ * Returns %TRUE if @device has been shadowed by a GTK+
+ * device grab on another widget, so it would stop sending
+ * events to @widget. This may be used in the
+ * #GtkWidget::grab-notify signal to check for specific
+ * devices. See gtk_device_grab_add().
+ *
+ * Returns: %TRUE if there is an ongoing grab on @device
+ * by another #GtkWidget than @widget.
+ *
+ * Since: 3.0
+ **/
+gboolean
+gtk_widget_device_is_shadowed (GtkWidget *widget,
+ GdkDevice *device)
+{
+ GtkWindowGroup *group;
+ GtkWidget *grab_widget, *toplevel;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+ g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
+
+ if (!gtk_widget_get_realized (widget))
+ return TRUE;
+
+ toplevel = gtk_widget_get_toplevel (widget);
+
+ if (GTK_IS_WINDOW (toplevel))
+ group = gtk_window_get_group (GTK_WINDOW (toplevel));
+ else
+ group = gtk_window_get_group (NULL);
+
+ grab_widget = gtk_window_group_get_current_device_grab (group, device);
+
+ /* Widget not inside the hierarchy of grab_widget */
+ if (grab_widget &&
+ widget != grab_widget &&
+ !gtk_widget_is_ancestor (widget, grab_widget))
+ return TRUE;
+
+ if (group->grabs)
+ {
+ grab_widget = group->grabs->data;
+
+ if (widget != grab_widget &&
+ !gtk_widget_is_ancestor (widget, grab_widget))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
* gtk_widget_set_name:
* @widget: a #GtkWidget
* @name: name for the widget
@@ -7890,10 +7951,53 @@ gtk_widget_set_events (GtkWidget *widget,
g_object_notify (G_OBJECT (widget), "events");
}
+/**
+ * gtk_widget_set_device_events:
+ * @widget: a #GtkWidget
+ * #device: a #GdkDevice
+ * @events: event mask
+ *
+ * Sets the device event mask (see #GdkEventMask) for a widget. The event
+ * mask determines which events a widget will receive from @device. Keep
+ * in mind that different widgets have different default event masks, and by
+ * changing the event mask you may disrupt a widget's functionality,
+ * so be careful. This function must be called while a widget is
+ * unrealized. Consider gtk_widget_add_device_events() for widgets that are
+ * already realized, or if you want to preserve the existing event
+ * mask. This function can't be used with #GTK_NO_WINDOW widgets;
+ * to get events on those widgets, place them inside a #GtkEventBox
+ * and receive events on the event box.
+ *
+ * Since: 3.0
+ **/
+void
+gtk_widget_set_device_events (GtkWidget *widget,
+ GdkDevice *device,
+ GdkEventMask events)
+{
+ GHashTable *device_events;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (GDK_IS_DEVICE (device));
+ g_return_if_fail (!gtk_widget_get_realized (widget));
+
+ device_events = g_object_get_qdata (G_OBJECT (widget), quark_device_event_mask);
+
+ if (G_UNLIKELY (!device_events))
+ {
+ device_events = g_hash_table_new (NULL, NULL);
+ g_object_set_qdata_full (G_OBJECT (widget), quark_device_event_mask, device_events,
+ (GDestroyNotify) g_hash_table_unref);
+ }
+
+ g_hash_table_insert (device_events, device, GUINT_TO_POINTER (events));
+}
+
static void
gtk_widget_add_events_internal (GtkWidget *widget,
- gint events,
- GList *window_list)
+ GdkDevice *device,
+ gint events,
+ GList *window_list)
{
GList *l;
@@ -7904,15 +8008,18 @@ gtk_widget_add_events_internal (GtkWidget *widget,
gdk_window_get_user_data (window, &user_data);
if (user_data == widget)
- {
- GList *children;
+ {
+ GList *children;
- gdk_window_set_events (window, gdk_window_get_events (window) | events);
+ if (device)
+ gdk_window_set_device_events (window, device, gdk_window_get_events (window) | events);
+ else
+ gdk_window_set_events (window, gdk_window_get_events (window) | events);
- children = gdk_window_get_children (window);
- gtk_widget_add_events_internal (widget, events, children);
- g_list_free (children);
- }
+ children = gdk_window_get_children (window);
+ gtk_widget_add_events_internal (widget, device, events, children);
+ g_list_free (children);
+ }
}
}
@@ -7945,7 +8052,60 @@ gtk_widget_add_events (GtkWidget *widget,
else
window_list = g_list_prepend (NULL, widget->window);
- gtk_widget_add_events_internal (widget, events, window_list);
+ gtk_widget_add_events_internal (widget, NULL, events, window_list);
+
+ g_list_free (window_list);
+ }
+
+ g_object_notify (G_OBJECT (widget), "events");
+}
+
+/**
+ * gtk_widget_add_device_events:
+ * @widget: a #GtkWidget
+ * @device: a #GdkDevice
+ * @events: an event mask, see #GdkEventMask
+ *
+ * Adds the device events in the bitfield @events to the event mask for
+ * @widget. See gtk_widget_set_device_events() for details.
+ *
+ * Since: 3.0
+ **/
+void
+gtk_widget_add_device_events (GtkWidget *widget,
+ GdkDevice *device,
+ GdkEventMask events)
+{
+ GdkEventMask old_events;
+ GHashTable *device_events;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (GDK_IS_DEVICE (device));
+
+ old_events = gtk_widget_get_device_events (widget, device);
+
+ device_events = g_object_get_qdata (G_OBJECT (widget), quark_device_event_mask);
+
+ if (G_UNLIKELY (!device_events))
+ {
+ device_events = g_hash_table_new (NULL, NULL);
+ g_object_set_qdata_full (G_OBJECT (widget), quark_device_event_mask, device_events,
+ (GDestroyNotify) g_hash_table_unref);
+ }
+
+ g_hash_table_insert (device_events, device,
+ GUINT_TO_POINTER (old_events | events));
+
+ if (gtk_widget_get_realized (widget))
+ {
+ GList *window_list;
+
+ if (!gtk_widget_get_has_window (widget))
+ window_list = gdk_window_get_children (widget->window);
+ else
+ window_list = g_list_prepend (NULL, widget->window);
+
+ gtk_widget_add_events_internal (widget, device, events, window_list);
g_list_free (window_list);
}
@@ -8170,6 +8330,35 @@ gtk_widget_get_events (GtkWidget *widget)
}
/**
+ * gtk_widget_get_device_events:
+ * @widget: a #GtkWidget
+ * @device: a #GdkDevice
+ *
+ * Returns the events mask for the widget corresponding to an specific device. These
+ * are the events that the widget will receive when @device operates on it.
+ *
+ * Returns: device event mask for @widget
+ *
+ * Since: 3.0
+ **/
+GdkEventMask
+gtk_widget_get_device_events (GtkWidget *widget,
+ GdkDevice *device)
+{
+ GHashTable *device_events;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
+ g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
+
+ device_events = g_object_get_qdata (G_OBJECT (widget), quark_device_event_mask);
+
+ if (!device_events)
+ return 0;
+
+ return GPOINTER_TO_UINT (g_hash_table_lookup (device_events, device));
+}
+
+/**
* gtk_widget_get_extension_events:
* @widget: a #GtkWidget
*
@@ -8755,59 +8944,147 @@ _gtk_widget_peek_colormap (void)
}
/*
- * _gtk_widget_set_pointer_window:
+ * _gtk_widget_set_device_window:
* @widget: a #GtkWidget.
- * @pointer_window: the new pointer window.
+ * @device: a #GdkDevice.
+ * @window: the new device window.
*
- * Sets pointer window for @widget. Does not ref @pointer_window.
+ * Sets pointer window for @widget and @device. Does not ref @window.
* Actually stores it on the #GdkScreen, but you don't need to know that.
*/
void
-_gtk_widget_set_pointer_window (GtkWidget *widget,
- GdkWindow *pointer_window)
+_gtk_widget_set_device_window (GtkWidget *widget,
+ GdkDevice *device,
+ GdkWindow *window)
{
+ GdkScreen *screen;
+ GHashTable *device_window;
+
g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (GDK_IS_DEVICE (device));
+ g_return_if_fail (!window || GDK_IS_WINDOW (window));
- if (gtk_widget_get_realized (widget))
- {
- GdkScreen *screen = gdk_drawable_get_screen (widget->window);
+ if (!gtk_widget_get_realized (widget))
+ return;
+
+ screen = gdk_drawable_get_screen (widget->window);
+ device_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
- g_object_set_qdata (G_OBJECT (screen), quark_pointer_window,
- pointer_window);
+ if (G_UNLIKELY (!device_window))
+ {
+ device_window = g_hash_table_new (NULL, NULL);
+ g_object_set_qdata_full (G_OBJECT (screen),
+ quark_pointer_window,
+ device_window,
+ (GDestroyNotify) g_hash_table_destroy);
}
+
+ if (window)
+ g_hash_table_insert (device_window, device, window);
+ else
+ g_hash_table_remove (device_window, device);
}
/*
- * _gtk_widget_get_pointer_window:
+ * _gtk_widget_get_device_window:
* @widget: a #GtkWidget.
+ * @device: a #GdkDevice.
*
- * Return value: the pointer window set on the #GdkScreen @widget is attached
+ * Return value: the device window set on the #GdkScreen @widget is attached
* to, or %NULL.
*/
GdkWindow *
-_gtk_widget_get_pointer_window (GtkWidget *widget)
+_gtk_widget_get_device_window (GtkWidget *widget,
+ GdkDevice *device)
{
+ GdkScreen *screen;
+ GHashTable *device_window;
+ GdkWindow *window;
+ GtkWidget *w;
+
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+ g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
- if (gtk_widget_get_realized (widget))
+ if (!gtk_widget_get_realized (widget))
+ return NULL;
+
+ screen = gdk_drawable_get_screen (widget->window);
+ device_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
+
+ if (G_UNLIKELY (!device_window))
+ return NULL;
+
+ window = g_hash_table_lookup (device_window, device);
+
+ if (!window)
+ return NULL;
+
+ gdk_window_get_user_data (window, (gpointer *) &w);
+
+ if (widget != w)
+ return NULL;
+
+ return window;
+}
+
+/*
+ * _gtk_widget_list_devices:
+ * @widget: a #GtkWidget.
+ *
+ * Returns the list of #GdkDevices that is currently on top of any widget #GdkWindow.
+ * Free the list with g_list_free(), the elements are owned by GTK+ and must not
+ * be freed.
+ */
+GList *
+_gtk_widget_list_devices (GtkWidget *widget)
+{
+ GdkScreen *screen;
+ GHashTableIter iter;
+ GHashTable *device_window;
+ GList *devices = NULL;
+ gpointer key, value;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+
+ if (!gtk_widget_get_realized (widget))
+ return NULL;
+
+ screen = gdk_drawable_get_screen (widget->window);
+ device_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
+
+ if (G_UNLIKELY (!device_window))
+ return NULL;
+
+ g_hash_table_iter_init (&iter, device_window);
+
+ while (g_hash_table_iter_next (&iter, &key, &value))
{
- GdkScreen *screen = gdk_drawable_get_screen (widget->window);
+ GdkDevice *device = key;
+ GdkWindow *window = value;
+ GtkWidget *w;
- return g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
+ if (window)
+ {
+ gdk_window_get_user_data (window, (gpointer *) &w);
+
+ if (widget == w)
+ devices = g_list_prepend (devices, device);
+ }
}
- return NULL;
+ return devices;
}
static void
-synth_crossing (GtkWidget *widget,
- GdkEventType type,
- GdkWindow *window,
- GdkCrossingMode mode,
- GdkNotifyType detail)
+synth_crossing (GtkWidget *widget,
+ GdkEventType type,
+ GdkWindow *window,
+ GdkDevice *device,
+ GdkCrossingMode mode,
+ GdkNotifyType detail)
{
GdkEvent *event;
-
+
event = gdk_event_new (type);
event->crossing.window = g_object_ref (window);
@@ -8820,6 +9097,7 @@ synth_crossing (GtkWidget *widget,
event->crossing.detail = detail;
event->crossing.focus = FALSE;
event->crossing.state = 0;
+ gdk_event_set_device (event, device);
if (!widget)
widget = gtk_get_event_widget (event);
@@ -8831,32 +9109,6 @@ synth_crossing (GtkWidget *widget,
}
/*
- * _gtk_widget_is_pointer_widget:
- * @widget: a #GtkWidget
- *
- * Returns %TRUE if the pointer window belongs to @widget.
- */
-gboolean
-_gtk_widget_is_pointer_widget (GtkWidget *widget)
-{
- if (GTK_WIDGET_HAS_POINTER (widget))
- {
- GdkWindow *win;
- GtkWidget *wid;
-
- win = _gtk_widget_get_pointer_window (widget);
- if (win)
- {
- gdk_window_get_user_data (win, (gpointer *)&wid);
- if (wid == widget)
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/*
* _gtk_widget_synthesize_crossing:
* @from: the #GtkWidget the virtual pointer is leaving.
* @to: the #GtkWidget the virtual pointer is moving to.
@@ -8888,20 +9140,30 @@ _gtk_widget_is_pointer_widget (GtkWidget *widget)
* - enter notify on real pointer window, detail Ancestor
*/
void
-_gtk_widget_synthesize_crossing (GtkWidget *from,
- GtkWidget *to,
- GdkCrossingMode mode)
+_gtk_widget_synthesize_crossing (GtkWidget *from,
+ GtkWidget *to,
+ GdkDevice *device,
+ GdkCrossingMode mode)
{
GdkWindow *from_window = NULL, *to_window = NULL;
g_return_if_fail (from != NULL || to != NULL);
if (from != NULL)
- from_window = GTK_WIDGET_HAS_POINTER (from)
- ? _gtk_widget_get_pointer_window (from) : from->window;
+ {
+ from_window = _gtk_widget_get_device_window (from, device);
+
+ if (!from_window)
+ from_window = from->window;
+ }
+
if (to != NULL)
- to_window = GTK_WIDGET_HAS_POINTER (to)
- ? _gtk_widget_get_pointer_window (to) : to->window;
+ {
+ to_window = _gtk_widget_get_device_window (to, device);
+
+ if (!to_window)
+ to_window = to->window;
+ }
if (from_window == NULL && to_window == NULL)
;
@@ -8919,11 +9181,11 @@ _gtk_widget_synthesize_crossing (GtkWidget *from,
}
synth_crossing (from, GDK_LEAVE_NOTIFY, from_window,
- mode, GDK_NOTIFY_ANCESTOR);
+ device, mode, GDK_NOTIFY_ANCESTOR);
for (list = g_list_last (from_ancestors); list; list = list->prev)
{
synth_crossing (NULL, GDK_LEAVE_NOTIFY, (GdkWindow *) list->data,
- mode, GDK_NOTIFY_VIRTUAL);
+ device, mode, GDK_NOTIFY_VIRTUAL);
}
/* XXX: enter/inferior on root window? */
@@ -8948,10 +9210,10 @@ _gtk_widget_synthesize_crossing (GtkWidget *from,
for (list = to_ancestors; list; list = list->next)
{
synth_crossing (NULL, GDK_ENTER_NOTIFY, (GdkWindow *) list->data,
- mode, GDK_NOTIFY_VIRTUAL);
+ device, mode, GDK_NOTIFY_VIRTUAL);
}
synth_crossing (to, GDK_ENTER_NOTIFY, to_window,
- mode, GDK_NOTIFY_ANCESTOR);
+ device, mode, GDK_NOTIFY_ANCESTOR);
g_list_free (to_ancestors);
}
@@ -8985,25 +9247,25 @@ _gtk_widget_synthesize_crossing (GtkWidget *from,
{
if (mode != GDK_CROSSING_GTK_UNGRAB)
synth_crossing (from, GDK_LEAVE_NOTIFY, from_window,
- mode, GDK_NOTIFY_INFERIOR);
+ device, mode, GDK_NOTIFY_INFERIOR);
for (list = to_ancestors; list; list = list->next)
synth_crossing (NULL, GDK_ENTER_NOTIFY, (GdkWindow *) list->data,
- mode, GDK_NOTIFY_VIRTUAL);
+ device, mode, GDK_NOTIFY_VIRTUAL);
synth_crossing (to, GDK_ENTER_NOTIFY, to_window,
- mode, GDK_NOTIFY_ANCESTOR);
+ device, mode, GDK_NOTIFY_ANCESTOR);
}
else if (from_ancestor == to_window)
{
synth_crossing (from, GDK_LEAVE_NOTIFY, from_window,
- mode, GDK_NOTIFY_ANCESTOR);
+ device, mode, GDK_NOTIFY_ANCESTOR);
for (list = g_list_last (from_ancestors); list; list = list->prev)
{
synth_crossing (NULL, GDK_LEAVE_NOTIFY, (GdkWindow *) list->data,
- mode, GDK_NOTIFY_VIRTUAL);
+ device, mode, GDK_NOTIFY_VIRTUAL);
}
if (mode != GDK_CROSSING_GTK_GRAB)
synth_crossing (to, GDK_ENTER_NOTIFY, to_window,
- mode, GDK_NOTIFY_INFERIOR);
+ device, mode, GDK_NOTIFY_INFERIOR);
}
else
{
@@ -9016,20 +9278,20 @@ _gtk_widget_synthesize_crossing (GtkWidget *from,
}
synth_crossing (from, GDK_LEAVE_NOTIFY, from_window,
- mode, GDK_NOTIFY_NONLINEAR);
+ device, mode, GDK_NOTIFY_NONLINEAR);
for (list = g_list_last (from_ancestors); list; list = list->prev)
{
synth_crossing (NULL, GDK_LEAVE_NOTIFY, (GdkWindow *) list->data,
- mode, GDK_NOTIFY_NONLINEAR_VIRTUAL);
+ device, mode, GDK_NOTIFY_NONLINEAR_VIRTUAL);
}
for (list = to_ancestors; list; list = list->next)
{
synth_crossing (NULL, GDK_ENTER_NOTIFY, (GdkWindow *) list->data,
- mode, GDK_NOTIFY_NONLINEAR_VIRTUAL);
+ device, mode, GDK_NOTIFY_NONLINEAR_VIRTUAL);
}
synth_crossing (to, GDK_ENTER_NOTIFY, to_window,
- mode, GDK_NOTIFY_NONLINEAR);
+ device, mode, GDK_NOTIFY_NONLINEAR);
}
g_list_free (from_ancestors);
g_list_free (to_ancestors);
@@ -9091,15 +9353,41 @@ gtk_widget_propagate_state (GtkWidget *widget,
g_signal_emit (widget, widget_signals[STATE_CHANGED], 0, old_state);
- if (GTK_WIDGET_HAS_POINTER (widget) && !GTK_WIDGET_SHADOWED (widget))
- {
- if (!gtk_widget_is_sensitive (widget))
- _gtk_widget_synthesize_crossing (widget, NULL,
- GDK_CROSSING_STATE_CHANGED);
- else if (old_state == GTK_STATE_INSENSITIVE)
- _gtk_widget_synthesize_crossing (NULL, widget,
- GDK_CROSSING_STATE_CHANGED);
- }
+ if (!GTK_WIDGET_SHADOWED (widget))
+ {
+ GList *event_windows = NULL;
+ GList *devices, *d;
+
+ devices = _gtk_widget_list_devices (widget);
+
+ for (d = devices; d; d = d->next)
+ {
+ GdkWindow *window;
+ GdkDevice *device;
+
+ device = d->data;
+ window = _gtk_widget_get_device_window (widget, device);
+
+ /* Do not propagate more than once to the
+ * same window if non-multidevice aware.
+ */
+ if (!gdk_window_get_support_multidevice (window) &&
+ g_list_find (event_windows, window))
+ continue;
+
+ if (!gtk_widget_is_sensitive (widget))
+ _gtk_widget_synthesize_crossing (widget, NULL, d->data,
+ GDK_CROSSING_STATE_CHANGED);
+ else if (old_state == GTK_STATE_INSENSITIVE)
+ _gtk_widget_synthesize_crossing (NULL, widget, d->data,
+ GDK_CROSSING_STATE_CHANGED);
+
+ event_windows = g_list_prepend (event_windows, window);
+ }
+
+ g_list_free (event_windows);
+ g_list_free (devices);
+ }
if (GTK_IS_CONTAINER (widget))
{
@@ -11175,6 +11463,56 @@ gtk_widget_get_window (GtkWidget *widget)
return widget->window;
}
+/**
+ * gtk_widget_get_support_multidevice:
+ * @widget: a #GtkWidget
+ *
+ * Returns %TRUE if @widget is multiple pointer aware. See
+ * gtk_widget_set_support_multidevice() for more information.
+ *
+ * Returns: %TRUE is @widget is multidevice aware.
+ **/
+gboolean
+gtk_widget_get_support_multidevice (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ return GTK_WIDGET_FLAGS (widget) & GTK_MULTIDEVICE;
+}
+
+/**
+ * gtk_widget_set_support_multidevice:
+ * @widget: a #GtkWidget
+ * @support_multidevice: %TRUE to support input from multiple devices.
+ *
+ * Enables or disables multiple pointer awareness. If this setting is %TRUE,
+ * @widget will start receiving multiple, per device enter/leave events. Note
+ * that if custom #GdkWindow<!-- -->s are created in #GtkWidget::realize,
+ * gdk_window_set_support_multidevice() will have to be called manually on them.
+ *
+ * Since: 3.0
+ **/
+void
+gtk_widget_set_support_multidevice (GtkWidget *widget,
+ gboolean support_multidevice)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ if (support_multidevice)
+ {
+ GTK_WIDGET_SET_FLAGS (widget, GTK_MULTIDEVICE);
+ gtk_widget_set_extension_events (widget, GDK_EXTENSION_EVENTS_ALL);
+ }
+ else
+ {
+ GTK_WIDGET_UNSET_FLAGS (widget, GTK_MULTIDEVICE);
+ gtk_widget_set_extension_events (widget, GDK_EXTENSION_EVENTS_NONE);
+ }
+
+ if (gtk_widget_get_realized (widget))
+ gdk_window_set_support_multidevice (widget->window, support_multidevice);
+}
+
static void
_gtk_widget_set_has_focus (GtkWidget *widget,
gboolean has_focus)
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 38b2dca9c6..f42fa252c2 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -118,7 +118,8 @@ typedef enum
GTK_APP_PAINTABLE = 1 << 19,
GTK_RECEIVES_DEFAULT = 1 << 20,
GTK_DOUBLE_BUFFERED = 1 << 21,
- GTK_NO_SHOW_ALL = 1 << 22
+ GTK_NO_SHOW_ALL = 1 << 22,
+ GTK_MULTIDEVICE = 1 << 23
} GtkWidgetFlags;
/* Kinds of widget-specific help */
@@ -652,6 +653,10 @@ gboolean gtk_widget_get_receives_default (GtkWidget *widget);
gboolean gtk_widget_has_grab (GtkWidget *widget);
+gboolean gtk_widget_device_is_shadowed (GtkWidget *widget,
+ GdkDevice *device);
+
+
void gtk_widget_set_name (GtkWidget *widget,
const gchar *name);
G_CONST_RETURN gchar* gtk_widget_get_name (GtkWidget *widget);
@@ -733,6 +738,12 @@ void gtk_widget_set_events (GtkWidget *widget,
gint events);
void gtk_widget_add_events (GtkWidget *widget,
gint events);
+void gtk_widget_set_device_events (GtkWidget *widget,
+ GdkDevice *device,
+ GdkEventMask events);
+void gtk_widget_add_device_events (GtkWidget *widget,
+ GdkDevice *device,
+ GdkEventMask events);
void gtk_widget_set_extension_events (GtkWidget *widget,
GdkExtensionMode mode);
@@ -753,6 +764,11 @@ GtkClipboard *gtk_widget_get_clipboard (GtkWidget *widget,
GdkPixmap * gtk_widget_get_snapshot (GtkWidget *widget,
GdkRectangle *clip_rect);
+/* Multidevice support */
+gboolean gtk_widget_get_support_multidevice (GtkWidget *widget);
+void gtk_widget_set_support_multidevice (GtkWidget *widget,
+ gboolean support_multidevice);
+
/* Accessibility support */
AtkObject* gtk_widget_get_accessible (GtkWidget *widget);
@@ -766,6 +782,8 @@ void gtk_widget_set_colormap (GtkWidget *widget,
GdkColormap *colormap);
gint gtk_widget_get_events (GtkWidget *widget);
+GdkEventMask gtk_widget_get_device_events (GtkWidget *widget,
+ GdkDevice *device);
void gtk_widget_get_pointer (GtkWidget *widget,
gint *x,
gint *y);
@@ -959,12 +977,16 @@ void _gtk_widget_propagate_screen_changed (GtkWidget *widget,
GdkScreen *previous_screen);
void _gtk_widget_propagate_composited_changed (GtkWidget *widget);
-void _gtk_widget_set_pointer_window (GtkWidget *widget,
+void _gtk_widget_set_device_window (GtkWidget *widget,
+ GdkDevice *device,
GdkWindow *pointer_window);
-GdkWindow *_gtk_widget_get_pointer_window (GtkWidget *widget);
-gboolean _gtk_widget_is_pointer_widget (GtkWidget *widget);
+GdkWindow *_gtk_widget_get_device_window (GtkWidget *widget,
+ GdkDevice *device);
+GList * _gtk_widget_list_devices (GtkWidget *widget);
+
void _gtk_widget_synthesize_crossing (GtkWidget *from,
GtkWidget *to,
+ GdkDevice *device,
GdkCrossingMode mode);
GdkColormap* _gtk_widget_peek_colormap (void);
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 6ac97069d6..eab1ff5132 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -167,6 +167,7 @@ struct _GtkWindowGeometryInfo
};
#define GTK_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_WINDOW, GtkWindowPrivate))
+#define GTK_WINDOW_GROUP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_WINDOW_GROUP, GtkWindowGroupPrivate))
typedef struct _GtkWindowPrivate GtkWindowPrivate;
@@ -199,6 +200,21 @@ struct _GtkWindowPrivate
gchar *startup_id;
};
+typedef struct _GtkDeviceGrabInfo GtkDeviceGrabInfo;
+typedef struct _GtkWindowGroupPrivate GtkWindowGroupPrivate;
+
+struct _GtkDeviceGrabInfo
+{
+ GtkWidget *widget;
+ GdkDevice *device;
+ guint block_others : 1;
+};
+
+struct _GtkWindowGroupPrivate
+{
+ GSList *device_grabs;
+};
+
static void gtk_window_dispose (GObject *object);
static void gtk_window_destroy (GtkObject *object);
static void gtk_window_finalize (GObject *object);
@@ -5251,17 +5267,43 @@ static void
do_focus_change (GtkWidget *widget,
gboolean in)
{
- GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
-
- fevent->focus_change.type = GDK_FOCUS_CHANGE;
- fevent->focus_change.window = widget->window;
- fevent->focus_change.in = in;
- if (widget->window)
- g_object_ref (widget->window);
+ GdkDeviceManager *device_manager;
+ GList *devices, *d;
+
+ device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+ devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
+ devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
+
+ for (d = devices; d; d = d->next)
+ {
+ GdkDevice *dev = d->data;
+ GdkEvent *fevent;
- gtk_widget_send_focus_change (widget, fevent);
+ if (dev->source != GDK_SOURCE_KEYBOARD)
+ continue;
- gdk_event_free (fevent);
+ /* Skip non-master keyboards that haven't
+ * selected for events from this window
+ */
+ if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
+ widget->window &&
+ !gdk_window_get_device_events (widget->window, dev))
+ continue;
+
+ fevent = gdk_event_new (GDK_FOCUS_CHANGE);
+
+ fevent->focus_change.type = GDK_FOCUS_CHANGE;
+ fevent->focus_change.window = widget->window;
+ if (widget->window)
+ g_object_ref (widget->window);
+ fevent->focus_change.in = in;
+ gdk_event_set_device (fevent, dev);
+
+ gtk_widget_send_focus_change (widget, fevent);
+
+ gdk_event_free (fevent);
+ }
}
static gint
@@ -5753,11 +5795,16 @@ get_monitor_containing_pointer (GtkWindow *window)
gint monitor_num;
GdkScreen *window_screen;
GdkScreen *pointer_screen;
+ GdkDisplay *display;
+ GdkDevice *pointer;
window_screen = gtk_window_check_screen (window);
- gdk_display_get_pointer (gdk_screen_get_display (window_screen),
- &pointer_screen,
- &px, &py, NULL);
+ display = gdk_screen_get_display (window_screen);
+ pointer = gdk_display_get_core_pointer (display);
+
+ gdk_display_get_device_state (display, pointer,
+ &pointer_screen,
+ &px, &py, NULL);
if (pointer_screen == window_screen)
monitor_num = gdk_screen_get_monitor_at_point (pointer_screen, px, py);
@@ -5940,12 +5987,16 @@ gtk_window_compute_configure_request (GtkWindow *window,
gint screen_height = gdk_screen_get_height (screen);
gint monitor_num;
GdkRectangle monitor;
+ GdkDisplay *display;
+ GdkDevice *pointer;
GdkScreen *pointer_screen;
gint px, py;
-
- gdk_display_get_pointer (gdk_screen_get_display (screen),
- &pointer_screen,
- &px, &py, NULL);
+
+ display = gdk_screen_get_display (screen);
+ pointer = gdk_display_get_core_pointer (display);
+ gdk_display_get_device_state (display, pointer,
+ &pointer_screen,
+ &px, &py, NULL);
if (pointer_screen == screen)
monitor_num = gdk_screen_get_monitor_at_point (screen, px, py);
@@ -7594,6 +7645,7 @@ gtk_window_has_toplevel_focus (GtkWindow *window)
static void
gtk_window_group_class_init (GtkWindowGroupClass *klass)
{
+ g_type_class_add_private (klass, sizeof (GtkWindowGroupPrivate));
}
GType
@@ -7641,6 +7693,8 @@ static void
window_group_cleanup_grabs (GtkWindowGroup *group,
GtkWindow *window)
{
+ GtkWindowGroupPrivate *priv;
+ GtkDeviceGrabInfo *info;
GSList *tmp_list;
GSList *to_remove = NULL;
@@ -7658,6 +7712,27 @@ window_group_cleanup_grabs (GtkWindowGroup *group,
g_object_unref (to_remove->data);
to_remove = g_slist_delete_link (to_remove, to_remove);
}
+
+ priv = GTK_WINDOW_GROUP_GET_PRIVATE (group);
+ tmp_list = priv->device_grabs;
+
+ while (tmp_list)
+ {
+ info = tmp_list->data;
+
+ if (gtk_widget_get_toplevel (info->widget) == (GtkWidget *) window)
+ to_remove = g_slist_prepend (to_remove, info);
+
+ tmp_list = tmp_list->next;
+ }
+
+ while (to_remove)
+ {
+ info = to_remove->data;
+
+ gtk_device_grab_remove (info->widget, info->device);
+ to_remove = g_slist_delete_link (to_remove, to_remove);
+ }
}
/**
@@ -7784,6 +7859,131 @@ _gtk_window_group_get_current_grab (GtkWindowGroup *window_group)
return NULL;
}
+void
+_gtk_window_group_add_device_grab (GtkWindowGroup *window_group,
+ GtkWidget *widget,
+ GdkDevice *device,
+ gboolean block_others)
+{
+ GtkWindowGroupPrivate *priv;
+ GtkDeviceGrabInfo *info;
+
+ priv = GTK_WINDOW_GROUP_GET_PRIVATE (window_group);
+
+ info = g_slice_new0 (GtkDeviceGrabInfo);
+ info->widget = widget;
+ info->device = device;
+ info->block_others = block_others;
+
+ priv->device_grabs = g_slist_prepend (priv->device_grabs, info);
+}
+
+void
+_gtk_window_group_remove_device_grab (GtkWindowGroup *window_group,
+ GtkWidget *widget,
+ GdkDevice *device)
+{
+ GtkWindowGroupPrivate *priv;
+ GtkDeviceGrabInfo *info;
+ GSList *list, *node = NULL;
+ GdkDevice *other_device;
+
+ priv = GTK_WINDOW_GROUP_GET_PRIVATE (window_group);
+ other_device = gdk_device_get_associated_device (device);
+ list = priv->device_grabs;
+
+ while (list)
+ {
+ info = list->data;
+
+ if (info->widget == widget &&
+ (info->device == device ||
+ info->device == other_device))
+ {
+ node = list;
+ break;
+ }
+
+ list = list->next;
+ }
+
+ if (node)
+ {
+ info = node->data;
+
+ priv->device_grabs = g_slist_delete_link (priv->device_grabs, node);
+ g_slice_free (GtkDeviceGrabInfo, info);
+ }
+}
+
+/**
+ * gtk_window_group_get_current_device_grab:
+ * @window_group: a #GtkWindowGroup
+ * @device: a #GdkDevice
+ *
+ * Returns the current grab widget for @device, or %NULL if none.
+ *
+ * Returns: The grab widget, or %NULL
+ **/
+GtkWidget *
+gtk_window_group_get_current_device_grab (GtkWindowGroup *window_group,
+ GdkDevice *device)
+{
+ GtkWindowGroupPrivate *priv;
+ GtkDeviceGrabInfo *info;
+ GdkDevice *other_device;
+ GSList *list;
+
+ priv = GTK_WINDOW_GROUP_GET_PRIVATE (window_group);
+ list = priv->device_grabs;
+ other_device = gdk_device_get_associated_device (device);
+
+ while (list)
+ {
+ info = list->data;
+ list = list->next;
+
+ if (info->device == device ||
+ info->device == other_device)
+ return info->widget;
+ }
+
+ return NULL;
+}
+
+gboolean
+_gtk_window_group_widget_is_blocked_for_device (GtkWindowGroup *window_group,
+ GtkWidget *widget,
+ GdkDevice *device)
+{
+ GtkWindowGroupPrivate *priv;
+ GtkDeviceGrabInfo *info;
+ GdkDevice *other_device;
+ GSList *list;
+
+ priv = GTK_WINDOW_GROUP_GET_PRIVATE (window_group);
+ other_device = gdk_device_get_associated_device (device);
+ list = priv->device_grabs;
+
+ while (list)
+ {
+ info = list->data;
+ list = list->next;
+
+ /* Look for blocking grabs on other device pairs
+ * that have the passed widget within the GTK+ grab.
+ */
+ if (info->block_others &&
+ info->device != device &&
+ info->device != other_device &&
+ (info->widget == widget ||
+ gtk_widget_is_ancestor (widget, info->widget)))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
/*
Derived from XParseGeometry() in XFree86
diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h
index 22753fcd0e..fec9d99f19 100644
--- a/gtk/gtkwindow.h
+++ b/gtk/gtkwindow.h
@@ -395,6 +395,9 @@ void gtk_window_group_remove_window (GtkWindowGroup *window_grou
GtkWindow *window);
GList * gtk_window_group_list_windows (GtkWindowGroup *window_group);
+GtkWidget * gtk_window_group_get_current_device_grab (GtkWindowGroup *window_group,
+ GdkDevice *device);
+
/* --- internal functions --- */
void _gtk_window_internal_set_focus (GtkWindow *window,
@@ -412,6 +415,17 @@ void _gtk_window_constrain_size (GtkWindow *window,
gint *new_width,
gint *new_height);
GtkWidget *_gtk_window_group_get_current_grab (GtkWindowGroup *window_group);
+void _gtk_window_group_add_device_grab (GtkWindowGroup *window_group,
+ GtkWidget *widget,
+ GdkDevice *device,
+ gboolean block_others);
+void _gtk_window_group_remove_device_grab (GtkWindowGroup *window_group,
+ GtkWidget *widget,
+ GdkDevice *device);
+
+gboolean _gtk_window_group_widget_is_blocked_for_device (GtkWindowGroup *window_group,
+ GtkWidget *widget,
+ GdkDevice *device);
void _gtk_window_set_has_toplevel_focus (GtkWindow *window,
gboolean has_toplevel_focus);