Compare commits
44 Commits
wip/css-op
...
touch-for-
Author | SHA1 | Date | |
---|---|---|---|
|
79adbda38f | ||
|
d9af0a5f75 | ||
|
f115a81b50 | ||
|
7a7108ba1a | ||
|
d6c1fd4ed4 | ||
|
a32dee7680 | ||
|
0eb89c7109 | ||
|
688a974570 | ||
|
f12f0b3e3a | ||
|
71a8c8007b | ||
|
8ac0f73f03 | ||
|
22c4b27fec | ||
|
8e9f616697 | ||
|
07b38f4658 | ||
|
16c6d9ce94 | ||
|
5d10309214 | ||
|
f18d8370f9 | ||
|
bfa2d55030 | ||
|
b7fbb544dc | ||
|
592ae129c3 | ||
|
cab579a11f | ||
|
bcf6d9d924 | ||
|
8f4fd88528 | ||
|
cb09e7d38b | ||
|
e4c52a8038 | ||
|
73093655e5 | ||
|
c569438e53 | ||
|
0c61976c74 | ||
|
6dc8f5b840 | ||
|
139a27a96f | ||
|
6840d3eda0 | ||
|
4ff34b7ca3 | ||
|
edebccd1ad | ||
|
b411a7e9fc | ||
|
a74b3356b3 | ||
|
3d1550be51 | ||
|
4276ff89b9 | ||
|
2a2fe61d46 | ||
|
5b01c7e691 | ||
|
73fc7c7fe5 | ||
|
d4c7234e70 | ||
|
f6c2d05cfe | ||
|
884a52fa7f | ||
|
51293f7137 |
@@ -935,7 +935,7 @@ if test "x$enable_x11_backend" = xyes; then
|
||||
have_base_x_pc=true
|
||||
X_PACKAGES="$X_PACKAGES x11 xext"
|
||||
x_libs="`$PKG_CONFIG --libs x11 xext`"
|
||||
X_CFLAGS="`$PKG_CONFIG --cflags x11 xext`"
|
||||
X_CFLAGS="`$PKG_CONFIG --cflags x11 xext` -DXINPUT2_1_USE_UNSTABLE_PROTOCOL -DXINPUT2_2_USE_UNSTABLE_PROTOCOL"
|
||||
|
||||
# Strip out any .la files that pkg-config might give us (this happens
|
||||
# with -uninstalled.pc files)
|
||||
@@ -1126,6 +1126,10 @@ if test "x$enable_x11_backend" = xyes; then
|
||||
AC_DEFINE(XINPUT_2, 1, [Define to 1 if XInput 2.0 is available]),
|
||||
X_EXTENSIONS="$X_EXTENSIONS XInput")
|
||||
|
||||
gtk_save_LIBS="$LIBS"
|
||||
LIBS="$LIBS -lXi"
|
||||
AC_CHECK_FUNC(XIAllowTouchEvents, AC_DEFINE(XINPUT_2_2, 1, [Define to 1 if XInput 2.2 is available]))
|
||||
LIBS="$gtk_save_LIBS"
|
||||
else
|
||||
AC_DEFINE(XINPUT_NONE, 1,
|
||||
[Define to 1 if no XInput should be used])
|
||||
|
@@ -790,6 +790,8 @@ gdk_event_get_root_coords
|
||||
gdk_event_get_scroll_direction
|
||||
gdk_event_get_state
|
||||
gdk_event_get_time
|
||||
GdkEventSequence
|
||||
gdk_event_get_event_sequence
|
||||
gdk_event_request_motions
|
||||
gdk_events_get_angle
|
||||
gdk_events_get_center
|
||||
@@ -827,6 +829,7 @@ GdkEvent
|
||||
GdkEventAny
|
||||
GdkEventKey
|
||||
GdkEventButton
|
||||
GdkEventTouch
|
||||
GdkEventScroll
|
||||
GdkEventMotion
|
||||
GdkEventExpose
|
||||
|
@@ -2939,6 +2939,10 @@ gtk_scrolled_window_get_min_content_width
|
||||
gtk_scrolled_window_set_min_content_width
|
||||
gtk_scrolled_window_get_min_content_height
|
||||
gtk_scrolled_window_set_min_content_height
|
||||
gtk_scrolled_window_set_kinetic_scrolling
|
||||
gtk_scrolled_window_get_kinetic_scrolling
|
||||
gtk_scrolled_window_set_capture_button_press
|
||||
gtk_scrolled_window_get_capture_button_press
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_SCROLLED_WINDOW
|
||||
|
@@ -168,6 +168,7 @@ gdk_event_get_scroll_direction
|
||||
gdk_event_get_source_device
|
||||
gdk_event_get_state
|
||||
gdk_event_get_time
|
||||
gdk_event_get_event_sequence
|
||||
gdk_event_get_type
|
||||
gdk_event_handler_set
|
||||
gdk_event_mask_get_type
|
||||
|
@@ -59,6 +59,10 @@ typedef enum
|
||||
* 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.
|
||||
* @GDK_SOURCE_TOUCHSCREEN: the device is a direct-input touch device, such
|
||||
* as a touchscreen or tablet. This device type has been added in 3.4.
|
||||
* @GDK_SOURCE_TOUCHPAD: the device is an indirect touch device, such
|
||||
* as a touchpad. This device type has been added in 3.4.
|
||||
*
|
||||
* An enumeration describing the type of an input device in general terms.
|
||||
*/
|
||||
@@ -68,7 +72,9 @@ typedef enum
|
||||
GDK_SOURCE_PEN,
|
||||
GDK_SOURCE_ERASER,
|
||||
GDK_SOURCE_CURSOR,
|
||||
GDK_SOURCE_KEYBOARD
|
||||
GDK_SOURCE_KEYBOARD,
|
||||
GDK_SOURCE_TOUCHSCREEN,
|
||||
GDK_SOURCE_TOUCHPAD
|
||||
} GdkInputSource;
|
||||
|
||||
/**
|
||||
|
137
gdk/gdkdisplay.c
137
gdk/gdkdisplay.c
@@ -186,6 +186,7 @@ gdk_display_init (GdkDisplay *display)
|
||||
display->double_click_time = 250;
|
||||
display->double_click_distance = 5;
|
||||
|
||||
display->touch_implicit_grabs = g_array_new (FALSE, FALSE, sizeof (GdkTouchGrabInfo));
|
||||
display->device_grabs = g_hash_table_new (NULL, NULL);
|
||||
display->motion_hint_info = g_hash_table_new_full (NULL, NULL, NULL,
|
||||
(GDestroyNotify) g_free);
|
||||
@@ -234,6 +235,8 @@ gdk_display_finalize (GObject *object)
|
||||
NULL);
|
||||
g_hash_table_destroy (display->device_grabs);
|
||||
|
||||
g_array_free (display->touch_implicit_grabs, TRUE);
|
||||
|
||||
g_hash_table_destroy (display->motion_hint_info);
|
||||
g_hash_table_destroy (display->pointers_info);
|
||||
g_hash_table_destroy (display->multiple_click_info);
|
||||
@@ -692,6 +695,73 @@ _gdk_display_add_device_grab (GdkDisplay *display,
|
||||
return info;
|
||||
}
|
||||
|
||||
static void
|
||||
_gdk_display_break_touch_grabs (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
GdkWindow *new_grab_window)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < display->touch_implicit_grabs->len; i++)
|
||||
{
|
||||
GdkTouchGrabInfo *info;
|
||||
|
||||
info = &g_array_index (display->touch_implicit_grabs,
|
||||
GdkTouchGrabInfo, i);
|
||||
|
||||
if (info->device == device && info->window != new_grab_window)
|
||||
generate_grab_broken_event (GDK_WINDOW (info->window),
|
||||
device, TRUE, new_grab_window);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_display_add_touch_grab (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
GdkEventSequence *sequence,
|
||||
GdkWindow *window,
|
||||
GdkWindow *native_window,
|
||||
GdkEventMask event_mask,
|
||||
unsigned long serial,
|
||||
guint32 time)
|
||||
{
|
||||
GdkTouchGrabInfo info;
|
||||
|
||||
info.device = device;
|
||||
info.sequence = sequence;
|
||||
info.window = g_object_ref (window);
|
||||
info.native_window = g_object_ref (native_window);
|
||||
info.serial = serial;
|
||||
info.event_mask = event_mask;
|
||||
info.time = time;
|
||||
|
||||
g_array_append_val (display->touch_implicit_grabs, info);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gdk_display_end_touch_grab (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
GdkEventSequence *sequence)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < display->touch_implicit_grabs->len; i++)
|
||||
{
|
||||
GdkTouchGrabInfo *info;
|
||||
|
||||
info = &g_array_index (display->touch_implicit_grabs,
|
||||
GdkTouchGrabInfo, i);
|
||||
|
||||
if (info->device == device && info->sequence == sequence)
|
||||
{
|
||||
g_array_remove_index_fast (display->touch_implicit_grabs, i);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* _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 */
|
||||
@@ -895,15 +965,26 @@ switch_to_pointer_grab (GdkDisplay *display,
|
||||
|
||||
if (grab == NULL) /* Ungrabbed, send events */
|
||||
{
|
||||
pointer_window = NULL;
|
||||
if (new_toplevel)
|
||||
{
|
||||
/* Find (possibly virtual) child window */
|
||||
pointer_window =
|
||||
_gdk_window_find_descendant_at (new_toplevel,
|
||||
x, y,
|
||||
NULL, NULL);
|
||||
}
|
||||
/* If the source device is a touch device, do not
|
||||
* propagate any enter event yet, until one is
|
||||
* synthesized when needed.
|
||||
*/
|
||||
if (source_device &&
|
||||
(gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN ||
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHPAD))
|
||||
info->need_touch_press_enter = TRUE;
|
||||
|
||||
pointer_window = NULL;
|
||||
|
||||
if (new_toplevel &&
|
||||
!info->need_touch_press_enter)
|
||||
{
|
||||
/* Find (possibly virtual) child window */
|
||||
pointer_window =
|
||||
_gdk_window_find_descendant_at (new_toplevel,
|
||||
x, y,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
if (pointer_window != last_grab->window)
|
||||
synthesize_crossing_events (display, device, source_device,
|
||||
@@ -962,12 +1043,15 @@ _gdk_display_device_grab_update (GdkDisplay *display,
|
||||
next_grab = NULL; /* Actually its not yet active */
|
||||
}
|
||||
|
||||
if (next_grab)
|
||||
_gdk_display_break_touch_grabs (display, device, next_grab->window);
|
||||
|
||||
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),
|
||||
(next_grab != NULL && current_grab->window != next_grab->window))
|
||||
generate_grab_broken_event (GDK_WINDOW (current_grab->window),
|
||||
device,
|
||||
current_grab->implicit,
|
||||
next_grab? next_grab->window : NULL);
|
||||
current_grab->implicit,
|
||||
next_grab? next_grab->window : NULL);
|
||||
|
||||
/* Remove old grab */
|
||||
grabs = g_list_delete_link (grabs, grabs);
|
||||
@@ -1026,6 +1110,33 @@ _gdk_display_has_device_grab (GdkDisplay *display,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GdkTouchGrabInfo *
|
||||
_gdk_display_has_touch_grab (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
GdkEventSequence *sequence,
|
||||
gulong serial)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < display->touch_implicit_grabs->len; i++)
|
||||
{
|
||||
GdkTouchGrabInfo *info;
|
||||
|
||||
info = &g_array_index (display->touch_implicit_grabs,
|
||||
GdkTouchGrabInfo, i);
|
||||
|
||||
if (info->device == device && info->sequence == sequence)
|
||||
{
|
||||
if (serial >= info->serial)
|
||||
return info;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returns true if last grab was ended
|
||||
* 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 */
|
||||
|
@@ -58,6 +58,19 @@ typedef struct
|
||||
guint implicit : 1;
|
||||
} GdkDeviceGrabInfo;
|
||||
|
||||
/* Tracks information about a touch implicit grab on this display */
|
||||
typedef struct
|
||||
{
|
||||
GdkDevice *device;
|
||||
GdkEventSequence *sequence;
|
||||
|
||||
GdkWindow *window;
|
||||
GdkWindow *native_window;
|
||||
gulong serial;
|
||||
guint event_mask;
|
||||
guint32 time;
|
||||
} GdkTouchGrabInfo;
|
||||
|
||||
/* Tracks information about which window and position the pointer last was in.
|
||||
* This is useful when we need to synthesize events later.
|
||||
* Note that we track toplevel_under_pointer using enter/leave events,
|
||||
@@ -74,6 +87,7 @@ typedef struct
|
||||
guint32 state;
|
||||
guint32 button;
|
||||
GdkDevice *last_slave;
|
||||
guint need_touch_press_enter : 1;
|
||||
} GdkPointerWindowInfo;
|
||||
|
||||
typedef struct
|
||||
@@ -102,6 +116,7 @@ struct _GdkDisplay
|
||||
guint closed : 1; /* Whether this display has been closed */
|
||||
guint ignore_core_events : 1; /* Don't send core motion and button event */
|
||||
|
||||
GArray *touch_implicit_grabs;
|
||||
GHashTable *device_grabs;
|
||||
GHashTable *motion_hint_info;
|
||||
GdkDeviceManager *device_manager;
|
||||
@@ -259,6 +274,21 @@ gboolean _gdk_display_end_device_grab (GdkDisplay *display
|
||||
gboolean _gdk_display_check_grab_ownership (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
gulong serial);
|
||||
void _gdk_display_add_touch_grab (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
GdkEventSequence *sequence,
|
||||
GdkWindow *window,
|
||||
GdkWindow *native_window,
|
||||
GdkEventMask event_mask,
|
||||
unsigned long serial_start,
|
||||
guint32 time);
|
||||
GdkTouchGrabInfo * _gdk_display_has_touch_grab (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
GdkEventSequence *sequence,
|
||||
gulong serial);
|
||||
gboolean _gdk_display_end_touch_grab (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
GdkEventSequence *sequence);
|
||||
void _gdk_display_enable_motion_hints (GdkDisplay *display,
|
||||
GdkDevice *device);
|
||||
GdkPointerWindowInfo * _gdk_display_get_pointer_info (GdkDisplay *display,
|
||||
|
139
gdk/gdkevents.c
139
gdk/gdkevents.c
@@ -457,6 +457,15 @@ gdk_event_new (GdkEventType type)
|
||||
new_event->button.x_root = 0.;
|
||||
new_event->button.y_root = 0.;
|
||||
break;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
new_event->touch.x = 0.;
|
||||
new_event->touch.y = 0.;
|
||||
new_event->touch.x_root = 0.;
|
||||
new_event->touch.y_root = 0.;
|
||||
break;
|
||||
case GDK_SCROLL:
|
||||
new_event->scroll.x = 0.;
|
||||
new_event->scroll.y = 0.;
|
||||
@@ -485,7 +494,31 @@ gdk_event_is_allocated (const GdkEvent *event)
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_gdk_event_set_pointer_emulated (GdkEvent *event,
|
||||
gboolean emulated)
|
||||
{
|
||||
if (gdk_event_is_allocated (event))
|
||||
{
|
||||
GdkEventPrivate *private = (GdkEventPrivate *) event;
|
||||
|
||||
if (emulated)
|
||||
private->flags |= GDK_EVENT_POINTER_EMULATED;
|
||||
else
|
||||
private->flags &= ~(GDK_EVENT_POINTER_EMULATED);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gdk_event_get_pointer_emulated (GdkEvent *event)
|
||||
{
|
||||
if (gdk_event_is_allocated (event))
|
||||
return (((GdkEventPrivate *) event)->flags & GDK_EVENT_POINTER_EMULATED) != 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_event_copy:
|
||||
* @event: a #GdkEvent
|
||||
@@ -561,6 +594,15 @@ gdk_event_copy (const GdkEvent *event)
|
||||
sizeof (gdouble) * gdk_device_get_n_axes (event->button.device));
|
||||
break;
|
||||
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
if (event->touch.axes)
|
||||
new_event->touch.axes = g_memdup (event->touch.axes,
|
||||
sizeof (gdouble) * gdk_device_get_n_axes (event->touch.device));
|
||||
break;
|
||||
|
||||
case GDK_MOTION_NOTIFY:
|
||||
if (event->motion.axes)
|
||||
new_event->motion.axes = g_memdup (event->motion.axes,
|
||||
@@ -639,7 +681,14 @@ gdk_event_free (GdkEvent *event)
|
||||
case GDK_BUTTON_RELEASE:
|
||||
g_free (event->button.axes);
|
||||
break;
|
||||
|
||||
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
g_free (event->touch.axes);
|
||||
break;
|
||||
|
||||
case GDK_EXPOSE:
|
||||
case GDK_DAMAGE:
|
||||
if (event->expose.region)
|
||||
@@ -700,6 +749,11 @@ gdk_event_get_time (const GdkEvent *event)
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
return event->button.time;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
return event->touch.time;
|
||||
case GDK_SCROLL:
|
||||
return event->scroll.time;
|
||||
case GDK_KEY_PRESS:
|
||||
@@ -775,7 +829,13 @@ gdk_event_get_state (const GdkEvent *event,
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
*state = event->button.state;
|
||||
*state = event->button.state;
|
||||
return TRUE;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
*state = event->touch.state;
|
||||
return TRUE;
|
||||
case GDK_SCROLL:
|
||||
*state = event->scroll.state;
|
||||
@@ -866,6 +926,13 @@ gdk_event_get_coords (const GdkEvent *event,
|
||||
x = event->button.x;
|
||||
y = event->button.y;
|
||||
break;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
x = event->touch.x;
|
||||
y = event->touch.y;
|
||||
break;
|
||||
case GDK_MOTION_NOTIFY:
|
||||
x = event->motion.x;
|
||||
y = event->motion.y;
|
||||
@@ -920,6 +987,13 @@ gdk_event_get_root_coords (const GdkEvent *event,
|
||||
x = event->button.x_root;
|
||||
y = event->button.y_root;
|
||||
break;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
x = event->touch.x_root;
|
||||
y = event->touch.y_root;
|
||||
break;
|
||||
case GDK_ENTER_NOTIFY:
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
x = event->crossing.x_root;
|
||||
@@ -1160,7 +1234,7 @@ gdk_event_get_axis (const GdkEvent *event,
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_MOTION_NOTIFY:
|
||||
x = event->motion.x;
|
||||
y = event->motion.y;
|
||||
break;
|
||||
@@ -1173,6 +1247,13 @@ gdk_event_get_axis (const GdkEvent *event,
|
||||
x = event->button.x;
|
||||
y = event->button.y;
|
||||
break;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
x = event->touch.x;
|
||||
y = event->touch.y;
|
||||
break;
|
||||
case GDK_ENTER_NOTIFY:
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
x = event->crossing.x;
|
||||
@@ -1196,6 +1277,14 @@ gdk_event_get_axis (const GdkEvent *event,
|
||||
device = event->button.device;
|
||||
axes = event->button.axes;
|
||||
}
|
||||
else if (event->type == GDK_TOUCH_BEGIN ||
|
||||
event->type == GDK_TOUCH_UPDATE ||
|
||||
event->type == GDK_TOUCH_END ||
|
||||
event->type == GDK_TOUCH_CANCEL)
|
||||
{
|
||||
device = event->touch.device;
|
||||
axes = event->touch.axes;
|
||||
}
|
||||
else if (event->type == GDK_MOTION_NOTIFY)
|
||||
{
|
||||
device = event->motion.device;
|
||||
@@ -1241,6 +1330,12 @@ gdk_event_set_device (GdkEvent *event,
|
||||
case GDK_BUTTON_RELEASE:
|
||||
event->button.device = device;
|
||||
break;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
event->touch.device = device;
|
||||
break;
|
||||
case GDK_SCROLL:
|
||||
event->scroll.device = device;
|
||||
break;
|
||||
@@ -1286,6 +1381,11 @@ gdk_event_get_device (const GdkEvent *event)
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
return event->button.device;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
return event->touch.device;
|
||||
case GDK_SCROLL:
|
||||
return event->scroll.device;
|
||||
case GDK_PROXIMITY_IN:
|
||||
@@ -1303,6 +1403,10 @@ gdk_event_get_device (const GdkEvent *event)
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
case GDK_ENTER_NOTIFY:
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
case GDK_FOCUS_CHANGE:
|
||||
@@ -1684,6 +1788,33 @@ gdk_event_get_screen (const GdkEvent *event)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_event_get_event_sequence:
|
||||
* @event: a #GdkEvent
|
||||
*
|
||||
* If @event if of type %GDK_TOUCH_BEGIN, %GDK_TOUCH_UPDATE,
|
||||
* %GDK_TOUCH_END or %GDK_TOUCH_CANCEL, returns the #GdkEventSequence
|
||||
* to which the event belongs. Otherwise, return %NULL.
|
||||
*
|
||||
* Returns: the event sequence that the event belongs to
|
||||
*
|
||||
* Since: 3.4
|
||||
*/
|
||||
GdkEventSequence *
|
||||
gdk_event_get_event_sequence (const GdkEvent *event)
|
||||
{
|
||||
if (!event)
|
||||
return NULL;
|
||||
|
||||
if (event->type == GDK_TOUCH_BEGIN ||
|
||||
event->type == GDK_TOUCH_UPDATE ||
|
||||
event->type == GDK_TOUCH_END ||
|
||||
event->type == GDK_TOUCH_CANCEL)
|
||||
return event->touch.sequence;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_set_show_events:
|
||||
* @show_events: %TRUE to output event debugging information.
|
||||
|
@@ -129,6 +129,7 @@ typedef struct _GdkEventExpose GdkEventExpose;
|
||||
typedef struct _GdkEventVisibility GdkEventVisibility;
|
||||
typedef struct _GdkEventMotion GdkEventMotion;
|
||||
typedef struct _GdkEventButton GdkEventButton;
|
||||
typedef struct _GdkEventTouch GdkEventTouch;
|
||||
typedef struct _GdkEventScroll GdkEventScroll;
|
||||
typedef struct _GdkEventKey GdkEventKey;
|
||||
typedef struct _GdkEventFocus GdkEventFocus;
|
||||
@@ -143,6 +144,8 @@ typedef struct _GdkEventWindowState GdkEventWindowState;
|
||||
typedef struct _GdkEventSetting GdkEventSetting;
|
||||
typedef struct _GdkEventGrabBroken GdkEventGrabBroken;
|
||||
|
||||
typedef struct _GdkEventSequence GdkEventSequence;
|
||||
|
||||
typedef union _GdkEvent GdkEvent;
|
||||
|
||||
/**
|
||||
@@ -262,6 +265,14 @@ typedef GdkFilterReturn (*GdkFilterFunc) (GdkXEvent *xevent,
|
||||
* was added in 2.8.
|
||||
* @GDK_DAMAGE: the content of the window has been changed. This event type
|
||||
* was added in 2.14.
|
||||
* @GDK_TOUCH_BEGIN: A new touch event sequence has just started. This event
|
||||
* type was added in 3.4.
|
||||
* @GDK_TOUCH_UPDATE: A touch event sequence has been updated. This event type
|
||||
* was added in 3.4.
|
||||
* @GDK_TOUCH_END: A touch event sequence has finished. This event type
|
||||
* was added in 3.4.
|
||||
* @GDK_TOUCH_CANCEL: A touch event sequence has been canceled. This event type
|
||||
* was added in 3.4.
|
||||
* @GDK_EVENT_LAST: marks the end of the GdkEventType enumeration. Added in 2.18
|
||||
*
|
||||
* Specifies the type of the event.
|
||||
@@ -309,6 +320,10 @@ typedef enum
|
||||
GDK_OWNER_CHANGE = 34,
|
||||
GDK_GRAB_BROKEN = 35,
|
||||
GDK_DAMAGE = 36,
|
||||
GDK_TOUCH_BEGIN = 37,
|
||||
GDK_TOUCH_UPDATE = 38,
|
||||
GDK_TOUCH_END = 39,
|
||||
GDK_TOUCH_CANCEL = 40,
|
||||
GDK_EVENT_LAST /* helper variable for decls */
|
||||
} GdkEventType;
|
||||
|
||||
@@ -384,6 +399,13 @@ typedef enum
|
||||
* @GDK_CROSSING_GTK_UNGRAB: crossing because a GTK+ grab is deactivated.
|
||||
* @GDK_CROSSING_STATE_CHANGED: crossing because a GTK+ widget changed
|
||||
* state (e.g. sensitivity).
|
||||
* @GDK_CROSSING_TOUCH_BEGIN: crossing because a touch sequence has begun,
|
||||
* this event is synthetic as the pointer might have not left the window.
|
||||
* @GDK_CROSSING_TOUCH_END: crossing because a touch sequence has ended,
|
||||
* this event is synthetic as the pointer might have not left the window.
|
||||
* @GDK_CROSSING_DEVICE_SWITCH: crossing because of a device switch (i.e.
|
||||
* a mouse taking control of the pointer after a touch device), this event
|
||||
* is synthetic as the pointer didn't leave the window.
|
||||
*
|
||||
* Specifies the crossing mode for #GdkEventCrossing.
|
||||
*/
|
||||
@@ -394,7 +416,10 @@ typedef enum
|
||||
GDK_CROSSING_UNGRAB,
|
||||
GDK_CROSSING_GTK_GRAB,
|
||||
GDK_CROSSING_GTK_UNGRAB,
|
||||
GDK_CROSSING_STATE_CHANGED
|
||||
GDK_CROSSING_STATE_CHANGED,
|
||||
GDK_CROSSING_TOUCH_BEGIN,
|
||||
GDK_CROSSING_TOUCH_END,
|
||||
GDK_CROSSING_DEVICE_SWITCH
|
||||
} GdkCrossingMode;
|
||||
|
||||
/**
|
||||
@@ -596,7 +621,7 @@ struct _GdkEventMotion
|
||||
*
|
||||
* Used for button press and button release events. The
|
||||
* @type field will be one of %GDK_BUTTON_PRESS,
|
||||
* %GDK_2BUTTON_PRESS, %GDK_3BUTTON_PRESS, and %GDK_BUTTON_RELEASE.
|
||||
* %GDK_2BUTTON_PRESS, %GDK_3BUTTON_PRESS or %GDK_BUTTON_RELEASE,
|
||||
*
|
||||
* Double and triple-clicks result in a sequence of events being received.
|
||||
* For double-clicks the order of events will be:
|
||||
@@ -644,6 +669,57 @@ struct _GdkEventButton
|
||||
gdouble x_root, y_root;
|
||||
};
|
||||
|
||||
/**
|
||||
* GdkEventTouch:
|
||||
* @type: the type of the event (%GDK_TOUCH_BEGIN, %GDK_TOUCH_UPDATE,
|
||||
* %GDK_TOUCH_END, %GDK_TOUCH_CANCEL)
|
||||
* @window: the window which received the event
|
||||
* @send_event: %TRUE if the event was sent explicitly (e.g. using
|
||||
* <function>XSendEvent</function>)
|
||||
* @time: the time of the event in milliseconds.
|
||||
* @x: the x coordinate of the pointer relative to the window
|
||||
* @y: the y coordinate of the pointer relative to the window
|
||||
* @axes: @x, @y translated to the axes of @device, or %NULL if @device is
|
||||
* the mouse
|
||||
* @state: (type GdkModifierType): a bit-mask representing the state of
|
||||
* the modifier keys (e.g. Control, Shift and Alt) and the pointer
|
||||
* buttons. See #GdkModifierType
|
||||
* @sequence: the event sequence that the event belongs to
|
||||
* @emulating_pointer: whether the event should be used for emulating
|
||||
* pointer event
|
||||
* @device: the device where the event originated
|
||||
* @x_root: the x coordinate of the pointer relative to the root of the
|
||||
* screen
|
||||
* @y_root: the y coordinate of the pointer relative to the root of the
|
||||
* screen
|
||||
*
|
||||
* Used for touch events.
|
||||
* @type field will be one of %GDK_TOUCH_BEGIN, %GDK_TOUCH_UPDATE,
|
||||
* %GDK_TOUCH_END or %GDK_TOUCH_CANCEL.
|
||||
*
|
||||
* Touch events are grouped into sequences by means of the @sequence
|
||||
* field, which can also be obtained with gdk_event_get_event_sequence().
|
||||
* Each sequence begins with a %GDK_TOUCH_BEGIN event, followed by
|
||||
* any number of %GDK_TOUCH_UPDATE events, and ends with a %GDK_TOUCH_END
|
||||
* (or %GDK_TOUCH_CANCEL) event. With multitouch devices, there may be
|
||||
* several active sequences at the same time.
|
||||
*/
|
||||
struct _GdkEventTouch
|
||||
{
|
||||
GdkEventType type;
|
||||
GdkWindow *window;
|
||||
gint8 send_event;
|
||||
guint32 time;
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
gdouble *axes;
|
||||
guint state;
|
||||
GdkEventSequence *sequence;
|
||||
gboolean emulating_pointer;
|
||||
GdkDevice *device;
|
||||
gdouble x_root, y_root;
|
||||
};
|
||||
|
||||
/**
|
||||
* GdkEventScroll:
|
||||
* @type: the type of the event (%GDK_SCROLL).
|
||||
@@ -1072,6 +1148,7 @@ union _GdkEvent
|
||||
GdkEventVisibility visibility;
|
||||
GdkEventMotion motion;
|
||||
GdkEventButton button;
|
||||
GdkEventTouch touch;
|
||||
GdkEventScroll scroll;
|
||||
GdkEventKey key;
|
||||
GdkEventCrossing crossing;
|
||||
@@ -1155,6 +1232,8 @@ void gdk_event_set_screen (GdkEvent *event,
|
||||
GdkScreen *screen);
|
||||
GdkScreen *gdk_event_get_screen (const GdkEvent *event);
|
||||
|
||||
GdkEventSequence *gdk_event_get_event_sequence (const GdkEvent *event);
|
||||
|
||||
void gdk_set_show_events (gboolean show_events);
|
||||
gboolean gdk_get_show_events (void);
|
||||
|
||||
|
@@ -148,7 +148,13 @@ typedef enum
|
||||
/* Following flag is set for events on the event queue during
|
||||
* translation and cleared afterwards.
|
||||
*/
|
||||
GDK_EVENT_PENDING = 1 << 0
|
||||
GDK_EVENT_PENDING = 1 << 0,
|
||||
|
||||
/* The following flag is set for:
|
||||
* 1) touch events emulating pointer events
|
||||
* 2) pointer events being emulated by a touch sequence.
|
||||
*/
|
||||
GDK_EVENT_POINTER_EMULATED = 1 << 1
|
||||
} GdkEventFlags;
|
||||
|
||||
struct _GdkEventPrivate
|
||||
@@ -273,6 +279,10 @@ GdkEvent* _gdk_event_unqueue (GdkDisplay *display);
|
||||
void _gdk_event_filter_unref (GdkWindow *window,
|
||||
GdkEventFilter *filter);
|
||||
|
||||
void _gdk_event_set_pointer_emulated (GdkEvent *event,
|
||||
gboolean emulated);
|
||||
gboolean _gdk_event_get_pointer_emulated (GdkEvent *event);
|
||||
|
||||
void _gdk_event_emit (GdkEvent *event);
|
||||
GList* _gdk_event_queue_find_first (GdkDisplay *display);
|
||||
void _gdk_event_queue_remove_link (GdkDisplay *display,
|
||||
|
@@ -348,6 +348,7 @@ typedef enum
|
||||
* @GDK_SUBSTRUCTURE_MASK: receive events about window configuration changes of
|
||||
* child windows
|
||||
* @GDK_SCROLL_MASK: receive scroll events
|
||||
* @GDK_TOUCH_MASK: receive touch events
|
||||
* @GDK_ALL_EVENTS_MASK: the combination of all the above event masks.
|
||||
*
|
||||
* A set of bit-flags to indicate which events a window is to receive.
|
||||
@@ -363,6 +364,13 @@ typedef enum
|
||||
* some of which are marked as a hint (the is_hint member is %TRUE).
|
||||
* To receive more motion events after a motion hint event, the application
|
||||
* needs to asks for more, by calling gdk_event_request_motions().
|
||||
*
|
||||
* If %GDK_TOUCH_MASK is enabled, the window will receive touch events
|
||||
* from touch-enabled devices. Those will come as sequences of #GdkEventTouch
|
||||
* with type %GDK_TOUCH_UPDATE, enclosed by two events with
|
||||
* type %GDK_TOUCH_BEGIN and %GDK_TOUCH_END (or %GDK_TOUCH_CANCEL).
|
||||
* gdk_event_get_event_sequence() returns the event sequence for these
|
||||
* events, so different sequences may be distinguished.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
@@ -387,7 +395,8 @@ typedef enum
|
||||
GDK_PROXIMITY_OUT_MASK = 1 << 19,
|
||||
GDK_SUBSTRUCTURE_MASK = 1 << 20,
|
||||
GDK_SCROLL_MASK = 1 << 21,
|
||||
GDK_ALL_EVENTS_MASK = 0x3FFFFE
|
||||
GDK_TOUCH_MASK = 1 << 22,
|
||||
GDK_ALL_EVENTS_MASK = 0x7FFFFE
|
||||
} GdkEventMask;
|
||||
|
||||
/**
|
||||
|
494
gdk/gdkwindow.c
494
gdk/gdkwindow.c
@@ -1243,11 +1243,12 @@ get_native_device_event_mask (GdkWindow *private,
|
||||
* lists due to some non-native child window.
|
||||
*/
|
||||
if (gdk_window_is_toplevel (private) ||
|
||||
mask & GDK_BUTTON_PRESS_MASK)
|
||||
mask |=
|
||||
GDK_POINTER_MOTION_MASK |
|
||||
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
|
||||
GDK_SCROLL_MASK;
|
||||
mask & GDK_BUTTON_PRESS_MASK)
|
||||
mask |=
|
||||
GDK_TOUCH_MASK |
|
||||
GDK_POINTER_MOTION_MASK |
|
||||
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
|
||||
GDK_SCROLL_MASK;
|
||||
|
||||
return mask;
|
||||
}
|
||||
@@ -8117,6 +8118,10 @@ static const guint type_masks[] = {
|
||||
0, /* GDK_OWNER_CHANGE = 34 */
|
||||
0, /* GDK_GRAB_BROKEN = 35 */
|
||||
0, /* GDK_DAMAGE = 36 */
|
||||
GDK_TOUCH_MASK, /* GDK_TOUCH_BEGIN = 37 */
|
||||
GDK_TOUCH_MASK, /* GDK_TOUCH_UPDATE = 38 */
|
||||
GDK_TOUCH_MASK, /* GDK_TOUCH_END = 39 */
|
||||
GDK_TOUCH_MASK /* GDK_TOUCH_CANCEL = 40 */
|
||||
};
|
||||
G_STATIC_ASSERT (G_N_ELEMENTS (type_masks) == GDK_EVENT_LAST);
|
||||
|
||||
@@ -8148,6 +8153,8 @@ is_button_type (GdkEventType type)
|
||||
type == GDK_2BUTTON_PRESS ||
|
||||
type == GDK_3BUTTON_PRESS ||
|
||||
type == GDK_BUTTON_RELEASE ||
|
||||
type == GDK_TOUCH_BEGIN ||
|
||||
type == GDK_TOUCH_END ||
|
||||
type == GDK_SCROLL;
|
||||
}
|
||||
|
||||
@@ -8155,10 +8162,20 @@ static gboolean
|
||||
is_motion_type (GdkEventType type)
|
||||
{
|
||||
return type == GDK_MOTION_NOTIFY ||
|
||||
type == GDK_TOUCH_UPDATE ||
|
||||
type == GDK_ENTER_NOTIFY ||
|
||||
type == GDK_LEAVE_NOTIFY;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_touch_type (GdkEventType type)
|
||||
{
|
||||
return type == GDK_TOUCH_BEGIN ||
|
||||
type == GDK_TOUCH_UPDATE ||
|
||||
type == GDK_TOUCH_END ||
|
||||
type == GDK_TOUCH_CANCEL;
|
||||
}
|
||||
|
||||
static GdkWindow *
|
||||
find_common_ancestor (GdkWindow *win1,
|
||||
GdkWindow *win2)
|
||||
@@ -8231,6 +8248,15 @@ _gdk_make_event (GdkWindow *window,
|
||||
event->button.state = the_state;
|
||||
break;
|
||||
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
event->touch.time = the_time;
|
||||
event->touch.axes = NULL;
|
||||
event->touch.state = the_state;
|
||||
break;
|
||||
|
||||
case GDK_SCROLL:
|
||||
event->scroll.time = the_time;
|
||||
event->scroll.state = the_state;
|
||||
@@ -8319,12 +8345,27 @@ send_crossing_event (GdkDisplay *display,
|
||||
GdkEvent *event;
|
||||
guint32 window_event_mask, type_event_mask;
|
||||
GdkDeviceGrabInfo *grab;
|
||||
GdkTouchGrabInfo *touch_grab = NULL;
|
||||
GdkPointerWindowInfo *pointer_info;
|
||||
gboolean block_event = FALSE;
|
||||
GdkEventSequence *sequence;
|
||||
|
||||
grab = _gdk_display_has_device_grab (display, device, serial);
|
||||
pointer_info = _gdk_display_get_pointer_info (display, device);
|
||||
|
||||
if (grab != NULL &&
|
||||
!grab->owner_events)
|
||||
sequence = gdk_event_get_event_sequence (event_in_queue);
|
||||
if (sequence)
|
||||
touch_grab = _gdk_display_has_touch_grab (display, device, sequence, serial);
|
||||
|
||||
if (touch_grab)
|
||||
{
|
||||
if (window != touch_grab->window)
|
||||
return;
|
||||
|
||||
window_event_mask = touch_grab->event_mask;
|
||||
}
|
||||
else if (grab != NULL &&
|
||||
!grab->owner_events)
|
||||
{
|
||||
/* !owner_event => only report events wrt grab window, ignore rest */
|
||||
if ((GdkWindow *)window != grab->window)
|
||||
@@ -8334,7 +8375,14 @@ send_crossing_event (GdkDisplay *display,
|
||||
else
|
||||
window_event_mask = window->event_mask;
|
||||
|
||||
if (type == GDK_LEAVE_NOTIFY)
|
||||
if (type == GDK_ENTER_NOTIFY &&
|
||||
pointer_info->need_touch_press_enter &&
|
||||
mode != GDK_CROSSING_TOUCH_BEGIN &&
|
||||
mode != GDK_CROSSING_TOUCH_END)
|
||||
{
|
||||
block_event = TRUE;
|
||||
}
|
||||
else if (type == GDK_LEAVE_NOTIFY)
|
||||
{
|
||||
type_event_mask = GDK_LEAVE_NOTIFY_MASK;
|
||||
window->devices_inside = g_list_remove (window->devices_inside, device);
|
||||
@@ -9082,17 +9130,54 @@ _gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
|
||||
static GdkWindow *
|
||||
get_event_window (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
GdkWindow *pointer_window,
|
||||
GdkEventType type,
|
||||
GdkModifierType mask,
|
||||
guint *evmask_out,
|
||||
gulong serial)
|
||||
GdkEventSequence *sequence,
|
||||
GdkWindow *pointer_window,
|
||||
GdkEventType type,
|
||||
GdkModifierType mask,
|
||||
guint *evmask_out,
|
||||
gboolean pointer_emulated,
|
||||
gulong serial)
|
||||
{
|
||||
guint evmask;
|
||||
guint evmask, emulated_mask = 0;
|
||||
GdkWindow *grab_window;
|
||||
GdkDeviceGrabInfo *grab;
|
||||
GdkTouchGrabInfo *touch_grab;
|
||||
|
||||
grab = _gdk_display_has_device_grab (display, device, serial);
|
||||
touch_grab = _gdk_display_has_touch_grab (display, device, sequence, serial);
|
||||
grab = _gdk_display_get_last_device_grab (display, device);
|
||||
|
||||
if (is_touch_type (type) && pointer_emulated)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case GDK_TOUCH_BEGIN:
|
||||
emulated_mask |= GDK_BUTTON_PRESS_MASK;
|
||||
break;
|
||||
case GDK_TOUCH_UPDATE:
|
||||
emulated_mask |= GDK_BUTTON_MOTION_MASK;
|
||||
break;
|
||||
case GDK_TOUCH_END:
|
||||
emulated_mask |= GDK_BUTTON_RELEASE_MASK;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (touch_grab != NULL &&
|
||||
(!grab || grab->implicit || touch_grab->serial >= grab->serial_start))
|
||||
{
|
||||
evmask = touch_grab->event_mask;
|
||||
evmask = update_evmask_for_button_motion (evmask, mask);
|
||||
|
||||
if (evmask & (type_masks[type] | emulated_mask))
|
||||
{
|
||||
if (evmask_out)
|
||||
*evmask_out = evmask;
|
||||
return touch_grab->window;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (grab != NULL && !grab->owner_events)
|
||||
{
|
||||
@@ -9101,7 +9186,7 @@ get_event_window (GdkDisplay *display,
|
||||
|
||||
grab_window = grab->window;
|
||||
|
||||
if (evmask & type_masks[type])
|
||||
if (evmask & (type_masks[type] | emulated_mask))
|
||||
{
|
||||
if (evmask_out)
|
||||
*evmask_out = evmask;
|
||||
@@ -9116,7 +9201,7 @@ get_event_window (GdkDisplay *display,
|
||||
evmask = pointer_window->event_mask;
|
||||
evmask = update_evmask_for_button_motion (evmask, mask);
|
||||
|
||||
if (evmask & type_masks[type])
|
||||
if (evmask & (type_masks[type] | emulated_mask))
|
||||
{
|
||||
if (evmask_out)
|
||||
*evmask_out = evmask;
|
||||
@@ -9132,7 +9217,7 @@ get_event_window (GdkDisplay *display,
|
||||
evmask = grab->event_mask;
|
||||
evmask = update_evmask_for_button_motion (evmask, mask);
|
||||
|
||||
if (evmask & type_masks[type])
|
||||
if (evmask & (type_masks[type] | emulated_mask))
|
||||
{
|
||||
if (evmask_out)
|
||||
*evmask_out = evmask;
|
||||
@@ -9158,8 +9243,10 @@ proxy_pointer_event (GdkDisplay *display,
|
||||
guint state;
|
||||
gdouble toplevel_x, toplevel_y;
|
||||
guint32 time_;
|
||||
gboolean non_linear;
|
||||
gboolean non_linear, need_synthetic_enter = FALSE;
|
||||
gint event_type;
|
||||
|
||||
event_type = source_event->type;
|
||||
event_window = source_event->any.window;
|
||||
gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
|
||||
gdk_event_get_state (source_event, &state);
|
||||
@@ -9178,6 +9265,16 @@ proxy_pointer_event (GdkDisplay *display,
|
||||
source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))
|
||||
non_linear = TRUE;
|
||||
|
||||
if (pointer_info->need_touch_press_enter &&
|
||||
gdk_device_get_source (pointer_info->last_slave) != GDK_SOURCE_TOUCHSCREEN &&
|
||||
gdk_device_get_source (pointer_info->last_slave) != GDK_SOURCE_TOUCHPAD &&
|
||||
(source_event->type != GDK_TOUCH_UPDATE ||
|
||||
_gdk_event_get_pointer_emulated (source_event)))
|
||||
{
|
||||
pointer_info->need_touch_press_enter = FALSE;
|
||||
need_synthetic_enter = TRUE;
|
||||
}
|
||||
|
||||
/* If we get crossing events with subwindow unexpectedly being NULL
|
||||
that means there is a native subwindow that gdk doesn't know about.
|
||||
We track these and forward them, with the correct virtual window
|
||||
@@ -9265,7 +9362,9 @@ proxy_pointer_event (GdkDisplay *display,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (pointer_info->window_under_pointer != pointer_window)
|
||||
if ((source_event->type != GDK_TOUCH_UPDATE ||
|
||||
_gdk_event_get_pointer_emulated (source_event)) &&
|
||||
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 */
|
||||
@@ -9282,28 +9381,71 @@ proxy_pointer_event (GdkDisplay *display,
|
||||
serial, non_linear);
|
||||
_gdk_display_set_window_under_pointer (display, device, pointer_window);
|
||||
}
|
||||
else if (source_event->type == GDK_MOTION_NOTIFY)
|
||||
else if (source_event->type == GDK_MOTION_NOTIFY ||
|
||||
source_event->type == GDK_TOUCH_UPDATE)
|
||||
{
|
||||
GdkWindow *event_win;
|
||||
guint evmask;
|
||||
gboolean is_hint;
|
||||
GdkEventSequence *sequence;
|
||||
|
||||
sequence = gdk_event_get_event_sequence (source_event);
|
||||
|
||||
event_win = get_event_window (display,
|
||||
device,
|
||||
sequence,
|
||||
pointer_window,
|
||||
source_event->type,
|
||||
state,
|
||||
&evmask,
|
||||
_gdk_event_get_pointer_emulated (source_event),
|
||||
serial);
|
||||
|
||||
if (event_type == GDK_TOUCH_UPDATE)
|
||||
{
|
||||
if (_gdk_event_get_pointer_emulated (source_event))
|
||||
{
|
||||
/* Touch events emulating pointer events are transformed back
|
||||
* to pointer events if:
|
||||
* 1 - The event window doesn't select for touch events
|
||||
* 2 - There's no touch grab for this sequence, which means
|
||||
* it was started as a pointer sequence, but a device
|
||||
* grab added touch events afterwards, the sequence must
|
||||
* not mutate in this case.
|
||||
*/
|
||||
if ((evmask & GDK_TOUCH_MASK) == 0 ||
|
||||
!_gdk_display_has_touch_grab (display, device, sequence, serial))
|
||||
event_type = GDK_MOTION_NOTIFY;
|
||||
}
|
||||
else if ((evmask & GDK_TOUCH_MASK) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (is_touch_type (source_event->type) && !is_touch_type (event_type))
|
||||
state |= GDK_BUTTON1_MASK;
|
||||
|
||||
if (event_win &&
|
||||
gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER &&
|
||||
gdk_window_get_device_events (event_win, device) == 0)
|
||||
return TRUE;
|
||||
|
||||
/* The last device to interact with the window was a touch device,
|
||||
* which synthesized a leave notify event, so synthesize another enter
|
||||
* notify to tell the pointer is on the window.
|
||||
*/
|
||||
if (need_synthetic_enter)
|
||||
_gdk_synthesize_crossing_events (display,
|
||||
NULL, pointer_window,
|
||||
device, source_device,
|
||||
GDK_CROSSING_DEVICE_SWITCH,
|
||||
toplevel_x, toplevel_y,
|
||||
state, time_, NULL,
|
||||
serial, FALSE);
|
||||
|
||||
is_hint = FALSE;
|
||||
|
||||
if (event_win &&
|
||||
event_type == GDK_MOTION_NOTIFY &&
|
||||
(evmask & GDK_POINTER_MOTION_HINT_MASK))
|
||||
{
|
||||
gulong *device_serial;
|
||||
@@ -9321,22 +9463,58 @@ proxy_pointer_event (GdkDisplay *display,
|
||||
}
|
||||
}
|
||||
|
||||
if (event_win && !display->ignore_core_events)
|
||||
{
|
||||
event = _gdk_make_event (event_win, GDK_MOTION_NOTIFY, source_event, FALSE);
|
||||
event->motion.time = time_;
|
||||
convert_toplevel_coords_to_window (event_win,
|
||||
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.state = state;
|
||||
event->motion.is_hint = is_hint;
|
||||
event->motion.device = source_event->motion.device;
|
||||
event->motion.axes = g_memdup (source_event->motion.axes,
|
||||
sizeof (gdouble) * gdk_device_get_n_axes (source_event->motion.device));
|
||||
if (!event_win)
|
||||
return TRUE;
|
||||
|
||||
if (!display->ignore_core_events)
|
||||
{
|
||||
event = gdk_event_new (event_type);
|
||||
event->any.window = g_object_ref (event_win);
|
||||
event->any.send_event = source_event->any.send_event;
|
||||
|
||||
gdk_event_set_device (event, gdk_event_get_device (source_event));
|
||||
gdk_event_set_source_device (event, source_device);
|
||||
}
|
||||
|
||||
if (event_type == GDK_TOUCH_UPDATE)
|
||||
{
|
||||
event->touch.time = time_;
|
||||
event->touch.state = state | GDK_BUTTON1_MASK;
|
||||
event->touch.sequence = source_event->touch.sequence;
|
||||
convert_toplevel_coords_to_window (event_win,
|
||||
toplevel_x, toplevel_y,
|
||||
&event->touch.x, &event->touch.y);
|
||||
gdk_event_get_root_coords (source_event,
|
||||
&event->touch.x_root,
|
||||
&event->touch.y_root);
|
||||
|
||||
event->touch.axes = g_memdup (source_event->touch.axes,
|
||||
sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
|
||||
}
|
||||
else
|
||||
{
|
||||
event->motion.time = time_;
|
||||
event->motion.state = state;
|
||||
event->motion.is_hint = is_hint;
|
||||
|
||||
convert_toplevel_coords_to_window (event_win,
|
||||
toplevel_x, toplevel_y,
|
||||
&event->motion.x, &event->motion.y);
|
||||
gdk_event_get_root_coords (source_event,
|
||||
&event->motion.x_root,
|
||||
&event->motion.y_root);
|
||||
|
||||
if (is_touch_type (source_event->type))
|
||||
event->motion.axes = g_memdup (source_event->touch.axes,
|
||||
sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
|
||||
else
|
||||
event->motion.axes = g_memdup (source_event->motion.axes,
|
||||
sizeof (gdouble) * gdk_device_get_n_axes (source_event->motion.device));
|
||||
}
|
||||
|
||||
/* Just insert the event */
|
||||
_gdk_event_queue_insert_after (gdk_window_get_display (event_win),
|
||||
source_event, event);
|
||||
}
|
||||
}
|
||||
|
||||
/* unlink all move events from queue.
|
||||
@@ -9359,6 +9537,8 @@ proxy_button_event (GdkEvent *source_event,
|
||||
GdkWindow *pointer_window;
|
||||
GdkWindow *parent;
|
||||
GdkEvent *event;
|
||||
GdkPointerWindowInfo *pointer_info;
|
||||
GdkDeviceGrabInfo *pointer_grab;
|
||||
guint state;
|
||||
guint32 time_;
|
||||
GdkEventType type;
|
||||
@@ -9366,6 +9546,8 @@ proxy_button_event (GdkEvent *source_event,
|
||||
GdkDisplay *display;
|
||||
GdkWindow *w;
|
||||
GdkDevice *device, *source_device;
|
||||
GdkEventMask evmask;
|
||||
GdkEventSequence *sequence;
|
||||
|
||||
type = source_event->any.type;
|
||||
event_window = source_event->any.window;
|
||||
@@ -9379,9 +9561,17 @@ proxy_button_event (GdkEvent *source_event,
|
||||
toplevel_x, toplevel_y,
|
||||
&toplevel_x, &toplevel_y);
|
||||
|
||||
if (type == GDK_BUTTON_PRESS &&
|
||||
sequence = gdk_event_get_event_sequence (source_event);
|
||||
|
||||
pointer_info = _gdk_display_get_pointer_info (display, device);
|
||||
pointer_grab = _gdk_display_has_device_grab (display, device, serial);
|
||||
|
||||
if ((type == GDK_BUTTON_PRESS ||
|
||||
type == GDK_TOUCH_BEGIN) &&
|
||||
!source_event->any.send_event &&
|
||||
_gdk_display_has_device_grab (display, device, serial) == NULL)
|
||||
(!pointer_grab ||
|
||||
(type == GDK_TOUCH_BEGIN && pointer_grab->implicit &&
|
||||
!_gdk_event_get_pointer_emulated (source_event))))
|
||||
{
|
||||
pointer_window =
|
||||
_gdk_window_find_descendant_at (toplevel_window,
|
||||
@@ -9394,23 +9584,46 @@ proxy_button_event (GdkEvent *source_event,
|
||||
(parent = get_event_parent (w)) != NULL &&
|
||||
parent->window_type != GDK_WINDOW_ROOT)
|
||||
{
|
||||
if (w->event_mask & GDK_BUTTON_PRESS_MASK)
|
||||
if (w->event_mask & GDK_BUTTON_PRESS_MASK &&
|
||||
(type == GDK_BUTTON_PRESS ||
|
||||
_gdk_event_get_pointer_emulated (source_event)))
|
||||
break;
|
||||
|
||||
if (type == GDK_TOUCH_BEGIN &&
|
||||
w->event_mask & GDK_TOUCH_MASK)
|
||||
break;
|
||||
|
||||
w = parent;
|
||||
}
|
||||
pointer_window = (GdkWindow *)w;
|
||||
pointer_window = w;
|
||||
|
||||
_gdk_display_add_device_grab (display,
|
||||
device,
|
||||
pointer_window,
|
||||
event_window,
|
||||
GDK_OWNERSHIP_NONE,
|
||||
FALSE,
|
||||
gdk_window_get_events (pointer_window),
|
||||
serial,
|
||||
time_,
|
||||
TRUE);
|
||||
_gdk_display_device_grab_update (display, device, source_device, serial);
|
||||
if (pointer_window)
|
||||
{
|
||||
if (type == GDK_TOUCH_BEGIN &&
|
||||
pointer_window->event_mask & GDK_TOUCH_MASK)
|
||||
{
|
||||
_gdk_display_add_touch_grab (display, device, sequence,
|
||||
pointer_window, event_window,
|
||||
gdk_window_get_events (pointer_window),
|
||||
serial, time_);
|
||||
}
|
||||
else if (type == GDK_BUTTON_PRESS ||
|
||||
_gdk_event_get_pointer_emulated (source_event))
|
||||
{
|
||||
_gdk_display_add_device_grab (display,
|
||||
device,
|
||||
pointer_window,
|
||||
event_window,
|
||||
GDK_OWNERSHIP_NONE,
|
||||
FALSE,
|
||||
gdk_window_get_events (pointer_window),
|
||||
serial,
|
||||
time_,
|
||||
TRUE);
|
||||
_gdk_display_device_grab_update (display, device,
|
||||
source_device, serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pointer_window = get_pointer_window (display, toplevel_window, device,
|
||||
@@ -9419,9 +9632,32 @@ proxy_button_event (GdkEvent *source_event,
|
||||
|
||||
event_win = get_event_window (display,
|
||||
device,
|
||||
pointer_window,
|
||||
type, state,
|
||||
NULL, serial);
|
||||
sequence,
|
||||
pointer_window,
|
||||
type, state,
|
||||
&evmask,
|
||||
_gdk_event_get_pointer_emulated (source_event),
|
||||
serial);
|
||||
|
||||
if (type == GDK_TOUCH_BEGIN || type == GDK_TOUCH_END)
|
||||
{
|
||||
if (_gdk_event_get_pointer_emulated (source_event))
|
||||
{
|
||||
if ((evmask & GDK_TOUCH_MASK) == 0 ||
|
||||
!_gdk_display_has_touch_grab (display, device, sequence, serial))
|
||||
{
|
||||
if (type == GDK_TOUCH_BEGIN)
|
||||
type = GDK_BUTTON_PRESS;
|
||||
else if (type == GDK_TOUCH_END)
|
||||
type = GDK_BUTTON_RELEASE;
|
||||
}
|
||||
}
|
||||
else if ((evmask & GDK_TOUCH_MASK) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (source_event->type == GDK_TOUCH_END && !is_touch_type (type))
|
||||
state |= GDK_BUTTON1_MASK;
|
||||
|
||||
if (event_win == NULL || display->ignore_core_events)
|
||||
return TRUE;
|
||||
@@ -9430,6 +9666,33 @@ proxy_button_event (GdkEvent *source_event,
|
||||
gdk_window_get_device_events (event_win, device) == 0)
|
||||
return TRUE;
|
||||
|
||||
if ((type == GDK_BUTTON_PRESS ||
|
||||
(type == GDK_TOUCH_BEGIN &&
|
||||
_gdk_event_get_pointer_emulated (source_event))) &&
|
||||
pointer_info->need_touch_press_enter)
|
||||
{
|
||||
GdkCrossingMode mode;
|
||||
|
||||
/* The last device to interact with the window was a touch device,
|
||||
* which synthesized a leave notify event, so synthesize another enter
|
||||
* notify to tell the pointer is on the window.
|
||||
*/
|
||||
if (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN ||
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHPAD)
|
||||
mode = GDK_CROSSING_TOUCH_BEGIN;
|
||||
else
|
||||
mode = GDK_CROSSING_DEVICE_SWITCH;
|
||||
|
||||
pointer_info->need_touch_press_enter = FALSE;
|
||||
_gdk_synthesize_crossing_events (display,
|
||||
NULL,
|
||||
pointer_info->window_under_pointer,
|
||||
device, source_device, mode,
|
||||
toplevel_x, toplevel_y,
|
||||
state, time_, source_event,
|
||||
serial, FALSE);
|
||||
}
|
||||
|
||||
event = _gdk_make_event (event_win, type, source_event, FALSE);
|
||||
|
||||
switch (type)
|
||||
@@ -9440,17 +9703,85 @@ proxy_button_event (GdkEvent *source_event,
|
||||
convert_toplevel_coords_to_window (event_win,
|
||||
toplevel_x, toplevel_y,
|
||||
&event->button.x, &event->button.y);
|
||||
event->button.x_root = source_event->button.x_root;
|
||||
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) * gdk_device_get_n_axes (source_event->button.device));
|
||||
gdk_event_get_root_coords (source_event,
|
||||
&event->button.x_root,
|
||||
&event->button.y_root);
|
||||
gdk_event_set_device (event, gdk_event_get_device (source_event));
|
||||
gdk_event_set_source_device (event, source_device);
|
||||
|
||||
if (type == GDK_BUTTON_RELEASE)
|
||||
event->button.state |= GDK_BUTTON1_MASK;
|
||||
|
||||
if (is_touch_type (source_event->type))
|
||||
{
|
||||
event->button.button = 1;
|
||||
event->button.axes = g_memdup (source_event->touch.axes,
|
||||
sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
|
||||
}
|
||||
else
|
||||
{
|
||||
event->button.button = source_event->button.button;
|
||||
event->button.axes = g_memdup (source_event->button.axes,
|
||||
sizeof (gdouble) * gdk_device_get_n_axes (source_event->button.device));
|
||||
}
|
||||
|
||||
if (type == GDK_BUTTON_PRESS)
|
||||
_gdk_event_button_generate (display, event);
|
||||
else if ((type == GDK_BUTTON_RELEASE ||
|
||||
(type == GDK_TOUCH_END &&
|
||||
_gdk_event_get_pointer_emulated (source_event))) &&
|
||||
pointer_window == pointer_info->window_under_pointer &&
|
||||
(gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN ||
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHPAD))
|
||||
{
|
||||
/* Synthesize a leave notify event
|
||||
* whenever a touch device is released
|
||||
*/
|
||||
pointer_info->need_touch_press_enter = TRUE;
|
||||
_gdk_synthesize_crossing_events (display,
|
||||
pointer_window, NULL,
|
||||
device, source_device,
|
||||
GDK_CROSSING_TOUCH_END,
|
||||
toplevel_x, toplevel_y,
|
||||
state, time_, NULL,
|
||||
serial, FALSE);
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_END:
|
||||
convert_toplevel_coords_to_window (event_win,
|
||||
toplevel_x, toplevel_y,
|
||||
&event->button.x, &event->button.y);
|
||||
gdk_event_get_root_coords (source_event,
|
||||
&event->touch.x_root,
|
||||
&event->touch.y_root);
|
||||
event->touch.state = state;
|
||||
event->touch.device = source_event->touch.device;
|
||||
event->touch.axes = g_memdup (source_event->touch.axes,
|
||||
sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
|
||||
event->touch.sequence = source_event->touch.sequence;
|
||||
|
||||
gdk_event_set_source_device (event, source_device);
|
||||
|
||||
if (type == GDK_BUTTON_PRESS)
|
||||
_gdk_event_button_generate (display, event);
|
||||
if ((type == GDK_TOUCH_END &&
|
||||
_gdk_event_get_pointer_emulated (source_event)) &&
|
||||
pointer_window == pointer_info->window_under_pointer &&
|
||||
(gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN ||
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHPAD))
|
||||
{
|
||||
/* Synthesize a leave notify event
|
||||
* whenever a touch device is released
|
||||
*/
|
||||
pointer_info->need_touch_press_enter = TRUE;
|
||||
_gdk_synthesize_crossing_events (display,
|
||||
pointer_window, NULL,
|
||||
device, source_device,
|
||||
GDK_CROSSING_TOUCH_END,
|
||||
toplevel_x, toplevel_y,
|
||||
state, time_, NULL,
|
||||
serial, FALSE);
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case GDK_SCROLL:
|
||||
@@ -9680,7 +10011,9 @@ _gdk_windowing_got_event (GdkDisplay *display,
|
||||
}
|
||||
}
|
||||
|
||||
if (pointer_info)
|
||||
if (pointer_info &&
|
||||
(!is_touch_type (event->type) ||
|
||||
_gdk_event_get_pointer_emulated (event)))
|
||||
{
|
||||
guint old_state, old_button;
|
||||
|
||||
@@ -9697,6 +10030,9 @@ _gdk_windowing_got_event (GdkDisplay *display,
|
||||
if (event->type == GDK_BUTTON_PRESS ||
|
||||
event->type == GDK_BUTTON_RELEASE)
|
||||
pointer_info->button = event->button.button;
|
||||
else if (event->type == GDK_TOUCH_BEGIN ||
|
||||
event->type == GDK_TOUCH_END)
|
||||
pointer_info->button = 1;
|
||||
|
||||
if (device &&
|
||||
(pointer_info->state != old_state ||
|
||||
@@ -9710,16 +10046,32 @@ _gdk_windowing_got_event (GdkDisplay *display,
|
||||
else if (is_button_type (event->type))
|
||||
unlink_event = proxy_button_event (event, serial);
|
||||
|
||||
if (event->type == GDK_BUTTON_RELEASE && !event->any.send_event)
|
||||
if ((event->type == GDK_BUTTON_RELEASE ||
|
||||
event->type == GDK_TOUCH_END) &&
|
||||
!event->any.send_event)
|
||||
{
|
||||
button_release_grab = _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)
|
||||
GdkEventSequence *sequence;
|
||||
|
||||
sequence = gdk_event_get_event_sequence (event);
|
||||
if (event->type == GDK_TOUCH_END && sequence)
|
||||
{
|
||||
button_release_grab->serial_end = serial;
|
||||
button_release_grab->implicit_ungrab = FALSE;
|
||||
_gdk_display_device_grab_update (display, device, source_device, serial);
|
||||
_gdk_display_end_touch_grab (display, device, sequence);
|
||||
}
|
||||
|
||||
if (event->type == GDK_BUTTON_RELEASE ||
|
||||
_gdk_event_get_pointer_emulated (event))
|
||||
{
|
||||
button_release_grab =
|
||||
_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_device_grab_update (display, device, source_device, serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -7,6 +7,8 @@ libgdkx11includedir = $(includedir)/gtk-3.0/gdk/x11
|
||||
AM_CPPFLAGS = \
|
||||
-DG_LOG_DOMAIN=\"Gdk\" \
|
||||
-DGDK_COMPILATION \
|
||||
-DXINPUT2_2_USE_UNSTABLE_PROTOCOL \
|
||||
-DXINPUT2_1_USE_UNSTABLE_PROTOCOL \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/gdk \
|
||||
-I$(top_builddir)/gdk \
|
||||
|
@@ -386,6 +386,7 @@ gdk_x11_device_xi2_grab (GdkDevice *device,
|
||||
guint32 time_)
|
||||
{
|
||||
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
|
||||
GdkX11DeviceManagerXI2 *device_manager_xi2;
|
||||
GdkDisplay *display;
|
||||
XIEventMask mask;
|
||||
Window xwindow;
|
||||
@@ -393,6 +394,7 @@ gdk_x11_device_xi2_grab (GdkDevice *device,
|
||||
gint status;
|
||||
|
||||
display = gdk_device_get_display (device);
|
||||
device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (gdk_display_get_device_manager (display));
|
||||
|
||||
/* FIXME: confine_to is actually unused */
|
||||
|
||||
@@ -407,7 +409,9 @@ gdk_x11_device_xi2_grab (GdkDevice *device,
|
||||
}
|
||||
|
||||
mask.deviceid = device_xi2->device_id;
|
||||
mask.mask = _gdk_x11_device_xi2_translate_event_mask (event_mask, &mask.mask_len);
|
||||
mask.mask = _gdk_x11_device_xi2_translate_event_mask (device_manager_xi2,
|
||||
event_mask,
|
||||
&mask.mask_len);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
|
||||
@@ -623,10 +627,17 @@ gdk_x11_device_xi2_select_window_events (GdkDevice *device,
|
||||
GdkEventMask event_mask)
|
||||
{
|
||||
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
|
||||
GdkX11DeviceManagerXI2 *device_manager_xi2;
|
||||
GdkDisplay *display;
|
||||
XIEventMask evmask;
|
||||
|
||||
display = gdk_device_get_display (device);
|
||||
device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (gdk_display_get_device_manager (display));
|
||||
|
||||
evmask.deviceid = device_xi2->device_id;
|
||||
evmask.mask = _gdk_x11_device_xi2_translate_event_mask (event_mask, &evmask.mask_len);
|
||||
evmask.mask = _gdk_x11_device_xi2_translate_event_mask (device_manager_xi2,
|
||||
event_mask,
|
||||
&evmask.mask_len);
|
||||
|
||||
XISelectEvents (GDK_WINDOW_XDISPLAY (window),
|
||||
GDK_WINDOW_XID (window),
|
||||
@@ -636,10 +647,14 @@ gdk_x11_device_xi2_select_window_events (GdkDevice *device,
|
||||
}
|
||||
|
||||
guchar *
|
||||
_gdk_x11_device_xi2_translate_event_mask (GdkEventMask event_mask,
|
||||
gint *len)
|
||||
_gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *device_manager_xi2,
|
||||
GdkEventMask event_mask,
|
||||
gint *len)
|
||||
{
|
||||
guchar *mask;
|
||||
gint minor;
|
||||
|
||||
g_object_get (device_manager_xi2, "minor", &minor, NULL);
|
||||
|
||||
*len = XIMaskLen (XI_LASTEVENT);
|
||||
mask = g_new0 (guchar, *len);
|
||||
@@ -688,6 +703,17 @@ _gdk_x11_device_xi2_translate_event_mask (GdkEventMask event_mask,
|
||||
XISetMask (mask, XI_FocusOut);
|
||||
}
|
||||
|
||||
#ifdef XINPUT_2_2
|
||||
/* XInput 2.2 includes multitouch support */
|
||||
if (minor >= 2 &&
|
||||
event_mask & GDK_TOUCH_MASK)
|
||||
{
|
||||
XISetMask (mask, XI_TouchBegin);
|
||||
XISetMask (mask, XI_TouchUpdate);
|
||||
XISetMask (mask, XI_TouchEnd);
|
||||
}
|
||||
#endif /* XINPUT_2_2 */
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
@@ -52,7 +52,11 @@ _gdk_x11_device_manager_new (GdkDisplay *display)
|
||||
int major, minor;
|
||||
|
||||
major = 2;
|
||||
#ifdef XINPUT_2_2
|
||||
minor = 2;
|
||||
#else
|
||||
minor = 0;
|
||||
#endif /* XINPUT_2_2 */
|
||||
|
||||
if (!_gdk_disable_multidevice &&
|
||||
XIQueryVersion (xdisplay, &major, &minor) != BadRequest)
|
||||
@@ -64,6 +68,8 @@ _gdk_x11_device_manager_new (GdkDisplay *display)
|
||||
device_manager_xi2 = g_object_new (GDK_TYPE_X11_DEVICE_MANAGER_XI2,
|
||||
"display", display,
|
||||
"opcode", opcode,
|
||||
"major", major,
|
||||
"minor", minor,
|
||||
NULL);
|
||||
|
||||
return GDK_DEVICE_MANAGER (device_manager_xi2);
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include "gdkprivate-x11.h"
|
||||
#include "gdkintl.h"
|
||||
#include "gdkkeysyms.h"
|
||||
#include "gdkinternals.h"
|
||||
|
||||
#ifdef XINPUT_2
|
||||
|
||||
@@ -47,6 +48,8 @@ struct _GdkX11DeviceManagerXI2
|
||||
GList *devices;
|
||||
|
||||
gint opcode;
|
||||
gint major;
|
||||
gint minor;
|
||||
};
|
||||
|
||||
struct _GdkX11DeviceManagerXI2Class
|
||||
@@ -94,7 +97,9 @@ static GdkWindow * gdk_x11_device_manager_xi2_get_window (GdkEventTra
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_OPCODE
|
||||
PROP_OPCODE,
|
||||
PROP_MAJOR,
|
||||
PROP_MINOR
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -118,6 +123,20 @@ gdk_x11_device_manager_xi2_class_init (GdkX11DeviceManagerXI2Class *klass)
|
||||
P_("Opcode for XInput2 requests"),
|
||||
0, G_MAXINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_MAJOR,
|
||||
g_param_spec_int ("major",
|
||||
P_("Major"),
|
||||
P_("Major version number"),
|
||||
0, G_MAXINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_MINOR,
|
||||
g_param_spec_int ("minor",
|
||||
P_("Minor"),
|
||||
P_("Minor version number"),
|
||||
0, G_MAXINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -146,8 +165,10 @@ _gdk_x11_device_manager_xi2_select_events (GdkDeviceManager *device_manager,
|
||||
static void
|
||||
translate_valuator_class (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
XIValuatorClassInfo *info,
|
||||
gint n_valuator)
|
||||
Atom valuator_label,
|
||||
gdouble min,
|
||||
gdouble max,
|
||||
gdouble resolution)
|
||||
{
|
||||
static gboolean initialized = FALSE;
|
||||
static Atom label_atoms [GDK_AXIS_LAST] = { 0 };
|
||||
@@ -168,24 +189,19 @@ translate_valuator_class (GdkDisplay *display,
|
||||
|
||||
for (i = GDK_AXIS_IGNORE; i < GDK_AXIS_LAST; i++)
|
||||
{
|
||||
if (label_atoms[i] == info->label)
|
||||
if (label_atoms[i] == valuator_label)
|
||||
{
|
||||
use = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->label != None)
|
||||
label = gdk_x11_xatom_to_atom_for_display (display, info->label);
|
||||
if (valuator_label != None)
|
||||
label = gdk_x11_xatom_to_atom_for_display (display, valuator_label);
|
||||
else
|
||||
label = GDK_NONE;
|
||||
|
||||
_gdk_device_add_axis (device,
|
||||
label,
|
||||
use,
|
||||
info->min,
|
||||
info->max,
|
||||
info->resolution);
|
||||
_gdk_device_add_axis (device, label, use, min, max, resolution);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -194,7 +210,7 @@ translate_device_classes (GdkDisplay *display,
|
||||
XIAnyClassInfo **classes,
|
||||
guint n_classes)
|
||||
{
|
||||
gint i, n_valuator = 0;
|
||||
gint i;
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (device));
|
||||
|
||||
@@ -216,10 +232,14 @@ translate_device_classes (GdkDisplay *display,
|
||||
}
|
||||
break;
|
||||
case XIValuatorClass:
|
||||
translate_valuator_class (display, device,
|
||||
(XIValuatorClassInfo *) class_info,
|
||||
n_valuator);
|
||||
n_valuator++;
|
||||
{
|
||||
XIValuatorClassInfo *valuator_info = (XIValuatorClassInfo *) class_info;
|
||||
translate_valuator_class (display, device,
|
||||
valuator_info->label,
|
||||
valuator_info->min,
|
||||
valuator_info->max,
|
||||
valuator_info->resolution);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Ignore */
|
||||
@@ -230,18 +250,58 @@ translate_device_classes (GdkDisplay *display,
|
||||
g_object_thaw_notify (G_OBJECT (device));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_touch_device (XIAnyClassInfo **classes,
|
||||
guint n_classes,
|
||||
GdkInputSource *device_type,
|
||||
gint *num_touches)
|
||||
{
|
||||
#ifdef XINPUT_2_2
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < n_classes; i++)
|
||||
{
|
||||
XITouchClassInfo *class = (XITouchClassInfo *) classes[i];
|
||||
|
||||
if (class->type != XITouchClass)
|
||||
continue;
|
||||
|
||||
if (class->num_touches > 0)
|
||||
{
|
||||
if (class->mode == XIDirectTouch)
|
||||
*device_type = GDK_SOURCE_TOUCHSCREEN;
|
||||
else if (class->mode == XIDependentTouch)
|
||||
*device_type = GDK_SOURCE_TOUCHPAD;
|
||||
else
|
||||
continue;
|
||||
|
||||
*num_touches = class->num_touches;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GdkDevice *
|
||||
create_device (GdkDeviceManager *device_manager,
|
||||
GdkDisplay *display,
|
||||
XIDeviceInfo *dev)
|
||||
{
|
||||
GdkInputSource input_source;
|
||||
GdkInputSource touch_source;
|
||||
GdkDeviceType type;
|
||||
GdkDevice *device;
|
||||
GdkInputMode mode;
|
||||
gint num_touches = 0;
|
||||
|
||||
if (dev->use == XIMasterKeyboard || dev->use == XISlaveKeyboard)
|
||||
input_source = GDK_SOURCE_KEYBOARD;
|
||||
else if (dev->use == XISlavePointer &&
|
||||
is_touch_device (dev->classes, dev->num_classes, &touch_source, &num_touches))
|
||||
input_source = touch_source;
|
||||
else
|
||||
{
|
||||
gchar *tmp_name;
|
||||
@@ -252,6 +312,10 @@ create_device (GdkDeviceManager *device_manager,
|
||||
input_source = GDK_SOURCE_ERASER;
|
||||
else if (strstr (tmp_name, "cursor"))
|
||||
input_source = GDK_SOURCE_CURSOR;
|
||||
else if (strstr (tmp_name, "finger") ||
|
||||
(strstr (tmp_name, "touch") &&
|
||||
!strstr (tmp_name, "touchpad")))
|
||||
input_source = GDK_SOURCE_TOUCHSCREEN;
|
||||
else if (strstr (tmp_name, "wacom") ||
|
||||
strstr (tmp_name, "pen"))
|
||||
input_source = GDK_SOURCE_PEN;
|
||||
@@ -280,6 +344,20 @@ create_device (GdkDeviceManager *device_manager,
|
||||
break;
|
||||
}
|
||||
|
||||
GDK_NOTE (INPUT,
|
||||
({
|
||||
const gchar *type_names[] = { "master", "slave", "floating" };
|
||||
const gchar *source_names[] = { "mouse", "pen", "eraser", "cursor", "keyboard", "direct touch", "indirect touch" };
|
||||
const gchar *mode_names[] = { "disabled", "screen", "window" };
|
||||
g_message ("input device:\n\tname: %s\n\ttype: %s\n\tsource: %s\n\tmode: %s\n\thas cursor: %d\n\ttouches: %d",
|
||||
dev->name,
|
||||
type_names[type],
|
||||
source_names[input_source],
|
||||
mode_names[mode],
|
||||
dev->use == XIMasterPointer,
|
||||
num_touches);
|
||||
}));
|
||||
|
||||
device = g_object_new (GDK_TYPE_X11_DEVICE_XI2,
|
||||
"name", dev->name,
|
||||
"type", type,
|
||||
@@ -406,6 +484,8 @@ gdk_x11_device_manager_xi2_constructed (GObject *object)
|
||||
display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
|
||||
xdisplay = GDK_DISPLAY_XDISPLAY (display);
|
||||
|
||||
g_assert (device_manager->major == 2);
|
||||
|
||||
masters = g_hash_table_new (NULL, NULL);
|
||||
slaves = g_hash_table_new (NULL, NULL);
|
||||
|
||||
@@ -531,6 +611,12 @@ gdk_x11_device_manager_xi2_set_property (GObject *object,
|
||||
case PROP_OPCODE:
|
||||
device_manager->opcode = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_MAJOR:
|
||||
device_manager->major = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_MINOR:
|
||||
device_manager->minor = g_value_get_int (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -552,6 +638,12 @@ gdk_x11_device_manager_xi2_get_property (GObject *object,
|
||||
case PROP_OPCODE:
|
||||
g_value_set_int (value, device_manager->opcode);
|
||||
break;
|
||||
case PROP_MAJOR:
|
||||
g_value_set_int (value, device_manager->major);
|
||||
break;
|
||||
case PROP_MINOR:
|
||||
g_value_set_int (value, device_manager->minor);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -821,6 +913,11 @@ get_event_window (GdkEventTranslator *translator,
|
||||
case XI_ButtonPress:
|
||||
case XI_ButtonRelease:
|
||||
case XI_Motion:
|
||||
#ifdef XINPUT_2_2
|
||||
case XI_TouchUpdate:
|
||||
case XI_TouchBegin:
|
||||
case XI_TouchEnd:
|
||||
#endif /* XINPUT_2_2 */
|
||||
{
|
||||
XIDeviceEvent *xev = (XIDeviceEvent *) ev;
|
||||
|
||||
@@ -1045,51 +1142,39 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
XIDeviceEvent *xev = (XIDeviceEvent *) ev;
|
||||
GdkDevice *source_device;
|
||||
|
||||
switch (xev->detail)
|
||||
if (ev->evtype == XI_ButtonPress &&
|
||||
(xev->detail >= 4 && xev->detail <= 7))
|
||||
{
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
/* Button presses of button 4-7 are scroll events */
|
||||
if (ev->evtype == XI_ButtonPress)
|
||||
{
|
||||
event->scroll.type = GDK_SCROLL;
|
||||
/* Button presses of button 4-7 are scroll events */
|
||||
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;
|
||||
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.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.device = g_hash_table_lookup (device_manager->id_table,
|
||||
GUINT_TO_POINTER (xev->deviceid));
|
||||
|
||||
source_device = g_hash_table_lookup (device_manager->id_table,
|
||||
GUINT_TO_POINTER (xev->sourceid));
|
||||
gdk_event_set_source_device (event, source_device);
|
||||
source_device = g_hash_table_lookup (device_manager->id_table,
|
||||
GUINT_TO_POINTER (xev->sourceid));
|
||||
gdk_event_set_source_device (event, source_device);
|
||||
|
||||
event->scroll.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
|
||||
break;
|
||||
}
|
||||
/* Button presses of button 4-7 are scroll events, so ignore the release */
|
||||
else if (ev->evtype == XI_ButtonRelease)
|
||||
{
|
||||
return_val = FALSE;
|
||||
break;
|
||||
}
|
||||
/* else (XI_ButtonRelease) fall thru */
|
||||
default:
|
||||
event->scroll.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
|
||||
}
|
||||
else
|
||||
{
|
||||
event->button.type = (ev->evtype == XI_ButtonPress) ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
|
||||
|
||||
event->button.window = window;
|
||||
@@ -1122,9 +1207,13 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
}
|
||||
|
||||
event->button.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
|
||||
|
||||
event->button.button = xev->detail;
|
||||
}
|
||||
|
||||
if (xev->flags & XIPointerEmulated)
|
||||
_gdk_event_set_pointer_emulated (event, TRUE);
|
||||
|
||||
if (return_val == FALSE)
|
||||
break;
|
||||
|
||||
@@ -1139,15 +1228,14 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case XI_Motion:
|
||||
{
|
||||
XIDeviceEvent *xev = (XIDeviceEvent *) ev;
|
||||
GdkDevice *source_device;
|
||||
|
||||
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;
|
||||
@@ -1163,6 +1251,9 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
|
||||
event->motion.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
|
||||
|
||||
if (xev->flags & XIPointerEmulated)
|
||||
_gdk_event_set_pointer_emulated (event, TRUE);
|
||||
|
||||
/* There doesn't seem to be motion hints in XI */
|
||||
event->motion.is_hint = FALSE;
|
||||
|
||||
@@ -1182,6 +1273,137 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef XINPUT_2_2
|
||||
case XI_TouchBegin:
|
||||
case XI_TouchEnd:
|
||||
{
|
||||
XIDeviceEvent *xev = (XIDeviceEvent *) ev;
|
||||
GdkDevice *source_device;
|
||||
|
||||
GDK_NOTE(EVENTS,
|
||||
g_message ("touch %s:\twindow %ld\n\ttouch id: %u\n\tpointer emulating: %d",
|
||||
ev->evtype == XI_TouchBegin ? "begin" : "end",
|
||||
xev->event,
|
||||
xev->detail,
|
||||
xev->flags & XITouchEmulatingPointer));
|
||||
|
||||
if (ev->evtype == XI_TouchBegin)
|
||||
event->touch.type = GDK_TOUCH_BEGIN;
|
||||
else if (ev->evtype == XI_TouchEnd)
|
||||
event->touch.type = GDK_TOUCH_END;
|
||||
|
||||
event->touch.window = window;
|
||||
event->touch.time = xev->time;
|
||||
event->touch.x = (gdouble) xev->event_x;
|
||||
event->touch.y = (gdouble) xev->event_y;
|
||||
event->touch.x_root = (gdouble) xev->root_x;
|
||||
event->touch.y_root = (gdouble) xev->root_y;
|
||||
|
||||
event->touch.device = g_hash_table_lookup (device_manager->id_table,
|
||||
GUINT_TO_POINTER (xev->deviceid));
|
||||
|
||||
source_device = g_hash_table_lookup (device_manager->id_table,
|
||||
GUINT_TO_POINTER (xev->sourceid));
|
||||
gdk_event_set_source_device (event, source_device);
|
||||
|
||||
event->touch.axes = translate_axes (event->touch.device,
|
||||
event->touch.x,
|
||||
event->touch.y,
|
||||
event->touch.window,
|
||||
&xev->valuators);
|
||||
|
||||
if (gdk_device_get_mode (event->touch.device) == GDK_MODE_WINDOW)
|
||||
{
|
||||
GdkDevice *device = event->touch.device;
|
||||
|
||||
/* Update event coordinates from axes */
|
||||
gdk_device_get_axis (device, event->touch.axes, GDK_AXIS_X, &event->touch.x);
|
||||
gdk_device_get_axis (device, event->touch.axes, GDK_AXIS_Y, &event->touch.y);
|
||||
}
|
||||
|
||||
event->touch.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
|
||||
|
||||
if (ev->evtype == XI_TouchBegin)
|
||||
event->touch.state |= GDK_BUTTON1_MASK;
|
||||
|
||||
event->touch.sequence = GUINT_TO_POINTER (xev->detail);
|
||||
|
||||
if (xev->flags & XITouchEmulatingPointer)
|
||||
{
|
||||
event->touch.emulating_pointer = TRUE;
|
||||
_gdk_event_set_pointer_emulated (event, TRUE);
|
||||
}
|
||||
|
||||
if (return_val == FALSE)
|
||||
break;
|
||||
|
||||
if (!set_screen_from_root (display, event, xev->root))
|
||||
{
|
||||
return_val = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ev->evtype == XI_TouchBegin)
|
||||
set_user_time (event);
|
||||
}
|
||||
break;
|
||||
|
||||
case XI_TouchUpdate:
|
||||
{
|
||||
XIDeviceEvent *xev = (XIDeviceEvent *) ev;
|
||||
GdkDevice *source_device;
|
||||
|
||||
GDK_NOTE(EVENTS,
|
||||
g_message ("touch update:\twindow %ld\n\ttouch id: %u\n\tpointer emulating: %d",
|
||||
xev->event,
|
||||
xev->detail,
|
||||
xev->flags & XITouchEmulatingPointer));
|
||||
|
||||
event->touch.window = window;
|
||||
event->touch.sequence = GUINT_TO_POINTER (xev->detail);
|
||||
event->touch.type = GDK_TOUCH_UPDATE;
|
||||
event->touch.time = xev->time;
|
||||
event->touch.x = (gdouble) xev->event_x;
|
||||
event->touch.y = (gdouble) xev->event_y;
|
||||
event->touch.x_root = (gdouble) xev->root_x;
|
||||
event->touch.y_root = (gdouble) xev->root_y;
|
||||
|
||||
event->touch.device = g_hash_table_lookup (device_manager->id_table,
|
||||
GINT_TO_POINTER (xev->deviceid));
|
||||
|
||||
source_device = g_hash_table_lookup (device_manager->id_table,
|
||||
GUINT_TO_POINTER (xev->sourceid));
|
||||
gdk_event_set_source_device (event, source_device);
|
||||
|
||||
event->touch.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
|
||||
|
||||
event->touch.state |= GDK_BUTTON1_MASK;
|
||||
|
||||
if (xev->flags & XITouchEmulatingPointer)
|
||||
{
|
||||
event->touch.emulating_pointer = TRUE;
|
||||
_gdk_event_set_pointer_emulated (event, TRUE);
|
||||
}
|
||||
|
||||
event->touch.axes = translate_axes (event->touch.device,
|
||||
event->touch.x,
|
||||
event->touch.y,
|
||||
event->touch.window,
|
||||
&xev->valuators);
|
||||
|
||||
if (gdk_device_get_mode (event->touch.device) == GDK_MODE_WINDOW)
|
||||
{
|
||||
GdkDevice *device = event->touch.device;
|
||||
|
||||
/* Update event coordinates from axes */
|
||||
gdk_device_get_axis (device, event->touch.axes, GDK_AXIS_X, &event->touch.x);
|
||||
gdk_device_get_axis (device, event->touch.axes, GDK_AXIS_Y, &event->touch.y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case XI_Enter:
|
||||
case XI_Leave:
|
||||
{
|
||||
@@ -1278,7 +1500,8 @@ gdk_x11_device_manager_xi2_get_handled_events (GdkEventTranslator *translator)
|
||||
GDK_BUTTON2_MOTION_MASK |
|
||||
GDK_BUTTON3_MOTION_MASK |
|
||||
GDK_BUTTON_MOTION_MASK |
|
||||
GDK_FOCUS_CHANGE_MASK);
|
||||
GDK_FOCUS_CHANGE_MASK |
|
||||
GDK_TOUCH_MASK);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1292,7 +1515,9 @@ gdk_x11_device_manager_xi2_select_window_events (GdkEventTranslator *translator,
|
||||
device_manager = GDK_DEVICE_MANAGER (translator);
|
||||
|
||||
event_mask.deviceid = XIAllMasterDevices;
|
||||
event_mask.mask = _gdk_x11_device_xi2_translate_event_mask (evmask, &event_mask.mask_len);
|
||||
event_mask.mask = _gdk_x11_device_xi2_translate_event_mask (GDK_X11_DEVICE_MANAGER_XI2 (device_manager),
|
||||
evmask,
|
||||
&event_mask.mask_len);
|
||||
|
||||
_gdk_x11_device_manager_xi2_select_events (device_manager, window, &event_mask);
|
||||
g_free (event_mask.mask);
|
||||
|
@@ -245,8 +245,9 @@ void _gdk_x11_device_xi_translate_axes (GdkDevice *device,
|
||||
#endif
|
||||
|
||||
#ifdef XINPUT_2
|
||||
guchar * _gdk_x11_device_xi2_translate_event_mask (GdkEventMask event_mask,
|
||||
gint *len);
|
||||
guchar * _gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *device_manager_xi2,
|
||||
GdkEventMask event_mask,
|
||||
gint *len);
|
||||
guint _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
|
||||
XIButtonState *buttons_state,
|
||||
XIGroupState *group_state);
|
||||
|
@@ -2367,6 +2367,8 @@ gtk_scrollbar_new
|
||||
gtk_scrolled_window_add_with_viewport
|
||||
gtk_scrolled_window_get_hadjustment
|
||||
gtk_scrolled_window_get_hscrollbar
|
||||
gtk_scrolled_window_get_kinetic_scrolling
|
||||
gtk_scrolled_window_get_capture_button_press
|
||||
gtk_scrolled_window_get_min_content_height
|
||||
gtk_scrolled_window_get_min_content_width
|
||||
gtk_scrolled_window_get_placement
|
||||
@@ -2377,6 +2379,8 @@ gtk_scrolled_window_get_vadjustment
|
||||
gtk_scrolled_window_get_vscrollbar
|
||||
gtk_scrolled_window_new
|
||||
gtk_scrolled_window_set_hadjustment
|
||||
gtk_scrolled_window_set_kinetic_scrolling
|
||||
gtk_scrolled_window_set_capture_button_press
|
||||
gtk_scrolled_window_set_min_content_height
|
||||
gtk_scrolled_window_set_min_content_width
|
||||
gtk_scrolled_window_set_placement
|
||||
|
@@ -122,6 +122,8 @@ static gint gtk_button_button_press (GtkWidget * widget,
|
||||
GdkEventButton * event);
|
||||
static gint gtk_button_button_release (GtkWidget * widget,
|
||||
GdkEventButton * event);
|
||||
static gboolean gtk_button_touch (GtkWidget *widget,
|
||||
GdkEventTouch *event);
|
||||
static gint gtk_button_grab_broken (GtkWidget * widget,
|
||||
GdkEventGrabBroken * event);
|
||||
static gint gtk_button_key_release (GtkWidget * widget, GdkEventKey * event);
|
||||
@@ -207,6 +209,7 @@ gtk_button_class_init (GtkButtonClass *klass)
|
||||
widget_class->draw = gtk_button_draw;
|
||||
widget_class->button_press_event = gtk_button_button_press;
|
||||
widget_class->button_release_event = gtk_button_button_release;
|
||||
widget_class->touch_event = gtk_button_touch;
|
||||
widget_class->grab_broken_event = gtk_button_grab_broken;
|
||||
widget_class->key_release_event = gtk_button_key_release;
|
||||
widget_class->enter_notify_event = gtk_button_enter_notify;
|
||||
@@ -1429,9 +1432,10 @@ gtk_button_realize (GtkWidget *widget)
|
||||
attributes.wclass = GDK_INPUT_ONLY;
|
||||
attributes.event_mask = gtk_widget_get_events (widget);
|
||||
attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
|
||||
GDK_BUTTON_RELEASE_MASK |
|
||||
GDK_ENTER_NOTIFY_MASK |
|
||||
GDK_LEAVE_NOTIFY_MASK);
|
||||
GDK_BUTTON_RELEASE_MASK |
|
||||
GDK_TOUCH_MASK |
|
||||
GDK_ENTER_NOTIFY_MASK |
|
||||
GDK_LEAVE_NOTIFY_MASK);
|
||||
|
||||
attributes_mask = GDK_WA_X | GDK_WA_Y;
|
||||
|
||||
@@ -1841,6 +1845,28 @@ gtk_button_button_release (GtkWidget *widget,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_button_touch (GtkWidget *widget,
|
||||
GdkEventTouch *event)
|
||||
{
|
||||
GtkButton *button = GTK_BUTTON (widget);
|
||||
GtkButtonPrivate *priv = button->priv;
|
||||
|
||||
if (event->type == GDK_TOUCH_BEGIN)
|
||||
{
|
||||
if (priv->focus_on_click && !gtk_widget_has_focus (widget))
|
||||
gtk_widget_grab_focus (widget);
|
||||
|
||||
g_signal_emit (button, button_signals[PRESSED], 0);
|
||||
}
|
||||
else if (event->type == GDK_TOUCH_END)
|
||||
{
|
||||
g_signal_emit (button, button_signals[RELEASED], 0);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_button_grab_broken (GtkWidget *widget,
|
||||
GdkEventGrabBroken *event)
|
||||
@@ -1930,6 +1956,40 @@ gtk_real_button_pressed (GtkButton *button)
|
||||
gtk_button_update_state (button);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
touch_release_in_button (GtkButton *button)
|
||||
{
|
||||
GtkButtonPrivate *priv;
|
||||
gint width, height;
|
||||
GdkEvent *event;
|
||||
gdouble x, y;
|
||||
|
||||
priv = button->priv;
|
||||
event = gtk_get_current_event ();
|
||||
|
||||
if (!event)
|
||||
return FALSE;
|
||||
|
||||
if (event->type != GDK_TOUCH_END ||
|
||||
event->touch.window != priv->event_window)
|
||||
{
|
||||
gdk_event_free (event);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gdk_event_get_coords (event, &x, &y);
|
||||
width = gdk_window_get_width (priv->event_window);
|
||||
height = gdk_window_get_height (priv->event_window);
|
||||
|
||||
gdk_event_free (event);
|
||||
|
||||
if (x >= 0 && x <= width &&
|
||||
y >= 0 && y <= height)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_real_button_released (GtkButton *button)
|
||||
{
|
||||
@@ -1942,7 +2002,8 @@ gtk_real_button_released (GtkButton *button)
|
||||
if (priv->activate_timeout)
|
||||
return;
|
||||
|
||||
if (priv->in_button)
|
||||
if (priv->in_button ||
|
||||
touch_release_in_button (button))
|
||||
gtk_button_clicked (button);
|
||||
|
||||
gtk_button_update_state (button);
|
||||
|
251
gtk/gtkmain.c
251
gtk/gtkmain.c
@@ -1339,6 +1339,14 @@ rewrite_event_for_window (GdkEvent *event,
|
||||
new_window,
|
||||
&event->motion.x, &event->motion.y);
|
||||
break;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
rewrite_events_translate (event->any.window,
|
||||
new_window,
|
||||
&event->touch.x, &event->touch.y);
|
||||
break;
|
||||
case GDK_KEY_PRESS:
|
||||
case GDK_KEY_RELEASE:
|
||||
case GDK_PROXIMITY_IN:
|
||||
@@ -1384,6 +1392,10 @@ rewrite_event_for_grabs (GdkEvent *event)
|
||||
case GDK_PROXIMITY_OUT:
|
||||
case GDK_KEY_PRESS:
|
||||
case GDK_KEY_RELEASE:
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
display = gdk_window_get_display (event->any.window);
|
||||
device = gdk_event_get_device (event);
|
||||
|
||||
@@ -1471,6 +1483,7 @@ gtk_main_do_event (GdkEvent *event)
|
||||
{
|
||||
GtkWidget *event_widget;
|
||||
GtkWidget *grab_widget = NULL;
|
||||
GtkWidget *topmost_widget = NULL;
|
||||
GtkWindowGroup *window_group;
|
||||
GdkEvent *rewritten_event = NULL;
|
||||
GdkDevice *device;
|
||||
@@ -1530,6 +1543,14 @@ gtk_main_do_event (GdkEvent *event)
|
||||
if (!grab_widget)
|
||||
grab_widget = gtk_window_group_get_current_grab (window_group);
|
||||
|
||||
/* Find out the topmost widget where captured event propagation
|
||||
* should start, which is the widget holding the GTK+ grab
|
||||
* if any, otherwise it's left NULL and events are emitted
|
||||
* from the toplevel (or topmost parentless parent).
|
||||
*/
|
||||
if (grab_widget)
|
||||
topmost_widget = grab_widget;
|
||||
|
||||
/* If the grab widget is an ancestor of the event widget
|
||||
* then we send the event to the original event widget.
|
||||
* This is the key to implementing modality.
|
||||
@@ -1626,14 +1647,17 @@ gtk_main_do_event (GdkEvent *event)
|
||||
case GDK_WINDOW_STATE:
|
||||
case GDK_GRAB_BROKEN:
|
||||
case GDK_DAMAGE:
|
||||
gtk_widget_event (event_widget, event);
|
||||
if (!_gtk_widget_captured_event (event_widget, event))
|
||||
gtk_widget_event (event_widget, event);
|
||||
break;
|
||||
|
||||
case GDK_SCROLL:
|
||||
case GDK_BUTTON_PRESS:
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
gtk_propagate_event (grab_widget, event);
|
||||
case GDK_TOUCH_BEGIN:
|
||||
if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
|
||||
gtk_propagate_event (grab_widget, event);
|
||||
break;
|
||||
|
||||
case GDK_KEY_PRESS:
|
||||
@@ -1682,7 +1706,11 @@ gtk_main_do_event (GdkEvent *event)
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_PROXIMITY_IN:
|
||||
case GDK_PROXIMITY_OUT:
|
||||
gtk_propagate_event (grab_widget, event);
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
|
||||
gtk_propagate_event (grab_widget, event);
|
||||
break;
|
||||
|
||||
case GDK_ENTER_NOTIFY:
|
||||
@@ -1691,7 +1719,8 @@ gtk_main_do_event (GdkEvent *event)
|
||||
_gtk_widget_set_device_window (event_widget,
|
||||
gdk_event_get_device (event),
|
||||
event->any.window);
|
||||
if (gtk_widget_is_sensitive (grab_widget))
|
||||
if (gtk_widget_is_sensitive (grab_widget) &&
|
||||
!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
|
||||
gtk_widget_event (grab_widget, event);
|
||||
break;
|
||||
|
||||
@@ -1701,7 +1730,8 @@ gtk_main_do_event (GdkEvent *event)
|
||||
_gtk_widget_set_device_window (event_widget,
|
||||
gdk_event_get_device (event),
|
||||
NULL);
|
||||
if (gtk_widget_is_sensitive (grab_widget))
|
||||
if (gtk_widget_is_sensitive (grab_widget) &&
|
||||
!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
|
||||
gtk_widget_event (grab_widget, event);
|
||||
break;
|
||||
|
||||
@@ -1729,6 +1759,7 @@ gtk_main_do_event (GdkEvent *event)
|
||||
|| event->type == GDK_DRAG_ENTER
|
||||
|| event->type == GDK_GRAB_BROKEN
|
||||
|| event->type == GDK_MOTION_NOTIFY
|
||||
|| event->type == GDK_TOUCH_UPDATE
|
||||
|| event->type == GDK_SCROLL)
|
||||
{
|
||||
_gtk_tooltip_handle_event (event);
|
||||
@@ -2331,6 +2362,135 @@ gtk_get_event_widget (GdkEvent *event)
|
||||
return widget;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
propagate_event_up (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkWidget *topmost)
|
||||
{
|
||||
gboolean handled_event = FALSE;
|
||||
|
||||
/* Propagate event up the widget tree so that
|
||||
* parents can see the button and motion
|
||||
* events of the children.
|
||||
*/
|
||||
while (TRUE)
|
||||
{
|
||||
GtkWidget *tmp;
|
||||
|
||||
g_object_ref (widget);
|
||||
|
||||
/* Scroll events are special cased here because it
|
||||
* feels wrong when scrolling a GtkViewport, say,
|
||||
* to have children of the viewport eat the scroll
|
||||
* event
|
||||
*/
|
||||
if (!gtk_widget_is_sensitive (widget))
|
||||
handled_event = event->type != GDK_SCROLL;
|
||||
else
|
||||
handled_event = gtk_widget_event (widget, event);
|
||||
|
||||
tmp = gtk_widget_get_parent (widget);
|
||||
g_object_unref (widget);
|
||||
|
||||
if (widget == topmost)
|
||||
break;
|
||||
|
||||
widget = tmp;
|
||||
|
||||
if (handled_event || !widget)
|
||||
break;
|
||||
}
|
||||
|
||||
return handled_event;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
propagate_event_down (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkWidget *topmost)
|
||||
{
|
||||
gint handled_event = FALSE;
|
||||
GList *widgets = NULL;
|
||||
GList *l;
|
||||
|
||||
widgets = g_list_prepend (widgets, g_object_ref (widget));
|
||||
while (widget && widget != topmost)
|
||||
{
|
||||
widget = gtk_widget_get_parent (widget);
|
||||
if (!widget)
|
||||
break;
|
||||
|
||||
widgets = g_list_prepend (widgets, g_object_ref (widget));
|
||||
|
||||
if (widget == topmost)
|
||||
break;
|
||||
}
|
||||
|
||||
for (l = widgets; l && !handled_event; l = g_list_next (l))
|
||||
{
|
||||
widget = (GtkWidget *)l->data;
|
||||
|
||||
if (!gtk_widget_is_sensitive (widget))
|
||||
handled_event = TRUE;
|
||||
else
|
||||
handled_event = _gtk_widget_captured_event (widget, event);
|
||||
}
|
||||
g_list_free_full (widgets, (GDestroyNotify)g_object_unref);
|
||||
|
||||
return handled_event;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
propagate_event (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
gboolean captured,
|
||||
GtkWidget *topmost)
|
||||
{
|
||||
gboolean handled_event = FALSE;
|
||||
gboolean (* propagate_func) (GtkWidget *widget, GdkEvent *event);
|
||||
|
||||
propagate_func = captured ? _gtk_widget_captured_event : gtk_widget_event;
|
||||
|
||||
if (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE)
|
||||
{
|
||||
/* Only send key events within Window widgets to the Window
|
||||
* The Window widget will in turn pass the
|
||||
* key event on to the currently focused widget
|
||||
* for that window.
|
||||
*/
|
||||
GtkWidget *window;
|
||||
|
||||
window = gtk_widget_get_toplevel (widget);
|
||||
if (GTK_IS_WINDOW (window))
|
||||
{
|
||||
g_object_ref (widget);
|
||||
/* If there is a grab within the window, give the grab widget
|
||||
* a first crack at the key event
|
||||
*/
|
||||
if (widget != window && gtk_widget_has_grab (widget))
|
||||
handled_event = propagate_func (widget, event);
|
||||
|
||||
if (!handled_event)
|
||||
{
|
||||
window = gtk_widget_get_toplevel (widget);
|
||||
if (GTK_IS_WINDOW (window))
|
||||
{
|
||||
if (gtk_widget_is_sensitive (window))
|
||||
handled_event = propagate_func (window, event);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (widget);
|
||||
return handled_event;
|
||||
}
|
||||
}
|
||||
|
||||
/* Other events get propagated up/down the widget tree */
|
||||
return captured ?
|
||||
propagate_event_down (widget, event, topmost) :
|
||||
propagate_event_up (widget, event, topmost);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_propagate_event:
|
||||
* @widget: a #GtkWidget
|
||||
@@ -2359,79 +2519,16 @@ void
|
||||
gtk_propagate_event (GtkWidget *widget,
|
||||
GdkEvent *event)
|
||||
{
|
||||
gint handled_event;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
g_return_if_fail (event != NULL);
|
||||
|
||||
handled_event = FALSE;
|
||||
|
||||
g_object_ref (widget);
|
||||
|
||||
if ((event->type == GDK_KEY_PRESS) ||
|
||||
(event->type == GDK_KEY_RELEASE))
|
||||
{
|
||||
/* Only send key events within Window widgets to the Window
|
||||
* The Window widget will in turn pass the
|
||||
* key event on to the currently focused widget
|
||||
* for that window.
|
||||
*/
|
||||
GtkWidget *window;
|
||||
|
||||
window = gtk_widget_get_toplevel (widget);
|
||||
if (GTK_IS_WINDOW (window))
|
||||
{
|
||||
/* If there is a grab within the window, give the grab widget
|
||||
* a first crack at the key event
|
||||
*/
|
||||
if (widget != window && gtk_widget_has_grab (widget))
|
||||
handled_event = gtk_widget_event (widget, event);
|
||||
|
||||
if (!handled_event)
|
||||
{
|
||||
window = gtk_widget_get_toplevel (widget);
|
||||
if (GTK_IS_WINDOW (window))
|
||||
{
|
||||
if (gtk_widget_is_sensitive (window))
|
||||
gtk_widget_event (window, event);
|
||||
}
|
||||
}
|
||||
|
||||
handled_event = TRUE; /* don't send to widget */
|
||||
}
|
||||
}
|
||||
|
||||
/* Other events get propagated up the widget tree
|
||||
* so that parents can see the button and motion
|
||||
* events of the children.
|
||||
*/
|
||||
if (!handled_event)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
GtkWidget *tmp;
|
||||
|
||||
/* Scroll events are special cased here because it
|
||||
* feels wrong when scrolling a GtkViewport, say,
|
||||
* to have children of the viewport eat the scroll
|
||||
* event
|
||||
*/
|
||||
if (!gtk_widget_is_sensitive (widget))
|
||||
handled_event = event->type != GDK_SCROLL;
|
||||
else
|
||||
handled_event = gtk_widget_event (widget, event);
|
||||
|
||||
tmp = gtk_widget_get_parent (widget);
|
||||
g_object_unref (widget);
|
||||
|
||||
widget = tmp;
|
||||
|
||||
if (!handled_event && widget)
|
||||
g_object_ref (widget);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
g_object_unref (widget);
|
||||
propagate_event (widget, event, FALSE, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gtk_propagate_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkWidget *topmost)
|
||||
{
|
||||
return propagate_event (widget, event, TRUE, topmost);
|
||||
}
|
||||
|
511
gtk/gtkmenu.c
511
gtk/gtkmenu.c
@@ -108,8 +108,10 @@
|
||||
#include "gtksettings.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
|
||||
#include "deprecated/gtktearoffmenuitem.h"
|
||||
|
||||
@@ -225,12 +227,13 @@ static void gtk_menu_scroll_to (GtkMenu *menu,
|
||||
gint offset);
|
||||
static void gtk_menu_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed);
|
||||
static gboolean gtk_menu_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event);
|
||||
|
||||
|
||||
static void gtk_menu_stop_scrolling (GtkMenu *menu);
|
||||
static void gtk_menu_remove_scroll_timeout (GtkMenu *menu);
|
||||
static gboolean gtk_menu_scroll_timeout (gpointer data);
|
||||
static gboolean gtk_menu_scroll_timeout_initial (gpointer data);
|
||||
static void gtk_menu_start_scrolling (GtkMenu *menu);
|
||||
|
||||
static void gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell,
|
||||
GtkWidget *menu_item);
|
||||
@@ -1064,9 +1067,12 @@ gtk_menu_init (GtkMenu *menu)
|
||||
priv->needs_destruction_ref = TRUE;
|
||||
|
||||
priv->monitor_num = -1;
|
||||
priv->drag_start_y = -1;
|
||||
|
||||
context = gtk_widget_get_style_context (GTK_WIDGET (menu));
|
||||
gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENU);
|
||||
|
||||
_gtk_widget_set_captured_event_handler (GTK_WIDGET (menu), gtk_menu_captured_event);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1472,7 +1478,7 @@ gtk_menu_popup_for_device (GtkMenu *menu,
|
||||
GtkMenuShell *menu_shell;
|
||||
gboolean grab_keyboard;
|
||||
GtkWidget *parent_toplevel;
|
||||
GdkDevice *keyboard, *pointer;
|
||||
GdkDevice *keyboard, *pointer, *source_device = NULL;
|
||||
|
||||
g_return_if_fail (GTK_IS_MENU (menu));
|
||||
g_return_if_fail (device == NULL || GDK_IS_DEVICE (device));
|
||||
@@ -1609,6 +1615,7 @@ gtk_menu_popup_for_device (GtkMenu *menu,
|
||||
(current_event->type != GDK_ENTER_NOTIFY))
|
||||
menu_shell->priv->ignore_enter = TRUE;
|
||||
|
||||
source_device = gdk_event_get_source_device (current_event);
|
||||
gdk_event_free (current_event);
|
||||
}
|
||||
else
|
||||
@@ -1678,17 +1685,9 @@ gtk_menu_popup_for_device (GtkMenu *menu,
|
||||
gtk_menu_scroll_to (menu, priv->scroll_offset);
|
||||
|
||||
/* if no item is selected, select the first one */
|
||||
if (!menu_shell->priv->active_menu_item)
|
||||
{
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
if (touchscreen_mode)
|
||||
gtk_menu_shell_select_first (menu_shell, TRUE);
|
||||
}
|
||||
if (!menu_shell->priv->active_menu_item &&
|
||||
source_device && gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
|
||||
gtk_menu_shell_select_first (menu_shell, TRUE);
|
||||
|
||||
/* Once everything is set up correctly, map the toplevel */
|
||||
gtk_widget_show (priv->toplevel);
|
||||
@@ -3323,34 +3322,6 @@ gtk_menu_get_preferred_height_for_width (GtkWidget *widget,
|
||||
g_free (nat_heights);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
gtk_menu_button_scroll (GtkMenu *menu,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GtkMenuPrivate *priv = menu->priv;
|
||||
|
||||
if (priv->upper_arrow_prelight || priv->lower_arrow_prelight)
|
||||
{
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
if (touchscreen_mode)
|
||||
gtk_menu_handle_scrolling (menu,
|
||||
event->x_root, event->y_root,
|
||||
event->type == GDK_BUTTON_PRESS,
|
||||
FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pointer_in_menu_window (GtkWidget *widget,
|
||||
gdouble x_root,
|
||||
@@ -3387,13 +3358,16 @@ static gboolean
|
||||
gtk_menu_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GdkDevice *source_device;
|
||||
GtkWidget *event_widget;
|
||||
GtkMenu *menu;
|
||||
|
||||
if (event->type != GDK_BUTTON_PRESS)
|
||||
return FALSE;
|
||||
|
||||
/* Don't pass down to menu shell for presses over scroll arrows
|
||||
*/
|
||||
if (gtk_menu_button_scroll (GTK_MENU (widget), event))
|
||||
return TRUE;
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
event_widget = gtk_get_event_widget ((GdkEvent *) event);
|
||||
menu = GTK_MENU (widget);
|
||||
|
||||
/* Don't pass down to menu shell if a non-menuitem part of the menu
|
||||
* was clicked. The check for the event_widget being a GtkMenuShell
|
||||
@@ -3402,10 +3376,16 @@ gtk_menu_button_press (GtkWidget *widget,
|
||||
* the menu or on its border are delivered relative to
|
||||
* menu_shell->window.
|
||||
*/
|
||||
if (GTK_IS_MENU_SHELL (gtk_get_event_widget ((GdkEvent *) event)) &&
|
||||
if (GTK_IS_MENU_SHELL (event_widget) &&
|
||||
pointer_in_menu_window (widget, event->x_root, event->y_root))
|
||||
return TRUE;
|
||||
|
||||
if (GTK_IS_MENU_ITEM (event_widget) &&
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN &&
|
||||
GTK_MENU_ITEM (event_widget)->priv->submenu != NULL &&
|
||||
!gtk_widget_is_drawable (GTK_MENU_ITEM (event_widget)->priv->submenu))
|
||||
menu->priv->ignore_button_release = TRUE;
|
||||
|
||||
return GTK_WIDGET_CLASS (gtk_menu_parent_class)->button_press_event (widget, event);
|
||||
}
|
||||
|
||||
@@ -3424,11 +3404,6 @@ gtk_menu_button_release (GtkWidget *widget,
|
||||
if (event->type != GDK_BUTTON_RELEASE)
|
||||
return FALSE;
|
||||
|
||||
/* Don't pass down to menu shell for releases over scroll arrows
|
||||
*/
|
||||
if (gtk_menu_button_scroll (GTK_MENU (widget), event))
|
||||
return TRUE;
|
||||
|
||||
/* Don't pass down to menu shell if a non-menuitem part of the menu
|
||||
* was clicked (see comment in button_press()).
|
||||
*/
|
||||
@@ -3672,10 +3647,14 @@ gtk_menu_motion_notify (GtkWidget *widget,
|
||||
GtkMenu *menu;
|
||||
GtkMenuShell *menu_shell;
|
||||
GtkWidget *parent;
|
||||
GdkDevice *source_device;
|
||||
|
||||
gboolean need_enter;
|
||||
|
||||
if (GTK_IS_MENU (widget))
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
|
||||
if (GTK_IS_MENU (widget) &&
|
||||
gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN)
|
||||
{
|
||||
GtkMenuPrivate *priv = GTK_MENU(widget)->priv;
|
||||
|
||||
@@ -3839,90 +3818,17 @@ gtk_menu_scroll_by (GtkMenu *menu,
|
||||
gtk_menu_scroll_to (menu, offset);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_do_timeout_scroll (GtkMenu *menu,
|
||||
gboolean touchscreen_mode)
|
||||
{
|
||||
GtkMenuPrivate *priv = menu->priv;
|
||||
gboolean upper_visible;
|
||||
gboolean lower_visible;
|
||||
|
||||
upper_visible = priv->upper_arrow_visible;
|
||||
lower_visible = priv->lower_arrow_visible;
|
||||
|
||||
gtk_menu_scroll_by (menu, priv->scroll_step);
|
||||
|
||||
if (touchscreen_mode &&
|
||||
(upper_visible != priv->upper_arrow_visible ||
|
||||
lower_visible != priv->lower_arrow_visible))
|
||||
{
|
||||
/* We are about to hide a scroll arrow while the mouse is pressed,
|
||||
* this would cause the uncovered menu item to be activated on button
|
||||
* release. Therefore we need to ignore button release here
|
||||
*/
|
||||
GTK_MENU_SHELL (menu)->priv->ignore_enter = TRUE;
|
||||
priv->ignore_button_release = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_menu_scroll_timeout (gpointer data)
|
||||
{
|
||||
GtkMenu *menu;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
menu = GTK_MENU (data);
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
|
||||
gtk_menu_scroll_by (menu, menu->priv->scroll_step);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_menu_scroll_timeout_initial (gpointer data)
|
||||
{
|
||||
GtkMenu *menu;
|
||||
guint timeout;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
menu = GTK_MENU (data);
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-timeout-repeat", &timeout,
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
|
||||
menu->priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout, menu);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_start_scrolling (GtkMenu *menu)
|
||||
{
|
||||
guint timeout;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-timeout-repeat", &timeout,
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
|
||||
|
||||
menu->priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout_initial, menu);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_menu_scroll (GtkWidget *widget,
|
||||
GdkEventScroll *event)
|
||||
@@ -4046,14 +3952,9 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
|
||||
gboolean in_arrow;
|
||||
gboolean scroll_fast = FALSE;
|
||||
gint top_x, top_y;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
menu_shell = GTK_MENU_SHELL (menu);
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
gdk_window_get_position (gtk_widget_get_window (priv->toplevel),
|
||||
&top_x, &top_y);
|
||||
x -= top_x;
|
||||
@@ -4071,82 +3972,44 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
|
||||
in_arrow = TRUE;
|
||||
}
|
||||
|
||||
if (touchscreen_mode)
|
||||
priv->upper_arrow_prelight = in_arrow;
|
||||
|
||||
if ((priv->upper_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
|
||||
{
|
||||
gboolean arrow_pressed = FALSE;
|
||||
|
||||
if (priv->upper_arrow_visible && !priv->tearoff_active)
|
||||
{
|
||||
if (touchscreen_mode)
|
||||
scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE);
|
||||
|
||||
if (enter && in_arrow &&
|
||||
(!priv->upper_arrow_prelight ||
|
||||
priv->scroll_fast != scroll_fast))
|
||||
{
|
||||
if (enter && priv->upper_arrow_prelight)
|
||||
{
|
||||
if (priv->scroll_timeout == 0)
|
||||
{
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
priv->upper_arrow_prelight = TRUE;
|
||||
priv->scroll_fast = scroll_fast;
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = -MENU_SCROLL_STEP2; /* always fast */
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
|
||||
if (!motion)
|
||||
{
|
||||
/* Only do stuff on click. */
|
||||
gtk_menu_start_scrolling (menu);
|
||||
arrow_pressed = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arrow_pressed = TRUE;
|
||||
}
|
||||
}
|
||||
else if (!enter)
|
||||
{
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = scroll_fast
|
||||
? -MENU_SCROLL_STEP2
|
||||
: -MENU_SCROLL_STEP1;
|
||||
|
||||
priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (scroll_fast
|
||||
? MENU_SCROLL_TIMEOUT2
|
||||
: MENU_SCROLL_TIMEOUT1,
|
||||
gtk_menu_scroll_timeout, menu);
|
||||
}
|
||||
else /* !touchscreen_mode */
|
||||
else if (!enter && !in_arrow && priv->upper_arrow_prelight)
|
||||
{
|
||||
scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE);
|
||||
|
||||
if (enter && in_arrow &&
|
||||
(!priv->upper_arrow_prelight ||
|
||||
priv->scroll_fast != scroll_fast))
|
||||
{
|
||||
priv->upper_arrow_prelight = TRUE;
|
||||
priv->scroll_fast = scroll_fast;
|
||||
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = scroll_fast
|
||||
? -MENU_SCROLL_STEP2
|
||||
: -MENU_SCROLL_STEP1;
|
||||
|
||||
priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (scroll_fast
|
||||
? MENU_SCROLL_TIMEOUT2
|
||||
: MENU_SCROLL_TIMEOUT1,
|
||||
gtk_menu_scroll_timeout, menu);
|
||||
}
|
||||
else if (!enter && !in_arrow && priv->upper_arrow_prelight)
|
||||
{
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
}
|
||||
|
||||
/* gtk_menu_start_scrolling() might have hit the top of the
|
||||
* menu, so check if the button isn't insensitive before
|
||||
/* check if the button isn't insensitive before
|
||||
* changing it to something else.
|
||||
*/
|
||||
if ((priv->upper_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
|
||||
@@ -4181,82 +4044,44 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
|
||||
in_arrow = TRUE;
|
||||
}
|
||||
|
||||
if (touchscreen_mode)
|
||||
priv->lower_arrow_prelight = in_arrow;
|
||||
|
||||
if ((priv->lower_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
|
||||
{
|
||||
gboolean arrow_pressed = FALSE;
|
||||
|
||||
if (priv->lower_arrow_visible && !priv->tearoff_active)
|
||||
{
|
||||
if (touchscreen_mode)
|
||||
scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
|
||||
|
||||
if (enter && in_arrow &&
|
||||
(!priv->lower_arrow_prelight ||
|
||||
priv->scroll_fast != scroll_fast))
|
||||
{
|
||||
if (enter && priv->lower_arrow_prelight)
|
||||
{
|
||||
if (priv->scroll_timeout == 0)
|
||||
{
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
priv->lower_arrow_prelight = TRUE;
|
||||
priv->scroll_fast = scroll_fast;
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = MENU_SCROLL_STEP2; /* always fast */
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
|
||||
if (!motion)
|
||||
{
|
||||
/* Only do stuff on click. */
|
||||
gtk_menu_start_scrolling (menu);
|
||||
arrow_pressed = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arrow_pressed = TRUE;
|
||||
}
|
||||
}
|
||||
else if (!enter)
|
||||
{
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = scroll_fast
|
||||
? MENU_SCROLL_STEP2
|
||||
: MENU_SCROLL_STEP1;
|
||||
|
||||
priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (scroll_fast
|
||||
? MENU_SCROLL_TIMEOUT2
|
||||
: MENU_SCROLL_TIMEOUT1,
|
||||
gtk_menu_scroll_timeout, menu);
|
||||
}
|
||||
else /* !touchscreen_mode */
|
||||
else if (!enter && !in_arrow && priv->lower_arrow_prelight)
|
||||
{
|
||||
scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
|
||||
|
||||
if (enter && in_arrow &&
|
||||
(!priv->lower_arrow_prelight ||
|
||||
priv->scroll_fast != scroll_fast))
|
||||
{
|
||||
priv->lower_arrow_prelight = TRUE;
|
||||
priv->scroll_fast = scroll_fast;
|
||||
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = scroll_fast
|
||||
? MENU_SCROLL_STEP2
|
||||
: MENU_SCROLL_STEP1;
|
||||
|
||||
priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (scroll_fast
|
||||
? MENU_SCROLL_TIMEOUT2
|
||||
: MENU_SCROLL_TIMEOUT1,
|
||||
gtk_menu_scroll_timeout, menu);
|
||||
}
|
||||
else if (!enter && !in_arrow && priv->lower_arrow_prelight)
|
||||
{
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
}
|
||||
|
||||
/* gtk_menu_start_scrolling() might have hit the bottom of the
|
||||
* menu, so check if the button isn't insensitive before
|
||||
/* check if the button isn't insensitive before
|
||||
* changing it to something else.
|
||||
*/
|
||||
if ((priv->lower_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
|
||||
@@ -4286,19 +4111,18 @@ gtk_menu_enter_notify (GtkWidget *widget,
|
||||
{
|
||||
GtkWidget *menu_item;
|
||||
GtkWidget *parent;
|
||||
gboolean touchscreen_mode;
|
||||
GdkDevice *source_device;
|
||||
|
||||
if (event->mode == GDK_CROSSING_GTK_GRAB ||
|
||||
event->mode == GDK_CROSSING_GTK_UNGRAB ||
|
||||
event->mode == GDK_CROSSING_STATE_CHANGED)
|
||||
return TRUE;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (widget),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
menu_item = gtk_get_event_widget ((GdkEvent*) event);
|
||||
if (GTK_IS_MENU (widget))
|
||||
|
||||
if (GTK_IS_MENU (widget) &&
|
||||
gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN)
|
||||
{
|
||||
GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
|
||||
|
||||
@@ -4307,7 +4131,8 @@ gtk_menu_enter_notify (GtkWidget *widget,
|
||||
event->x_root, event->y_root, TRUE, TRUE);
|
||||
}
|
||||
|
||||
if (!touchscreen_mode && GTK_IS_MENU_ITEM (menu_item))
|
||||
if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN &&
|
||||
GTK_IS_MENU_ITEM (menu_item))
|
||||
{
|
||||
GtkWidget *menu = gtk_widget_get_parent (menu_item);
|
||||
|
||||
@@ -4364,6 +4189,7 @@ gtk_menu_leave_notify (GtkWidget *widget,
|
||||
GtkMenu *menu;
|
||||
GtkMenuItem *menu_item;
|
||||
GtkWidget *event_widget;
|
||||
GdkDevice *source_device;
|
||||
|
||||
if (event->mode == GDK_CROSSING_GTK_GRAB ||
|
||||
event->mode == GDK_CROSSING_GTK_UNGRAB ||
|
||||
@@ -4376,7 +4202,10 @@ gtk_menu_leave_notify (GtkWidget *widget,
|
||||
if (gtk_menu_navigating_submenu (menu, event->x_root, event->y_root))
|
||||
return TRUE;
|
||||
|
||||
gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE, TRUE);
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
|
||||
if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN)
|
||||
gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE, TRUE);
|
||||
|
||||
event_widget = gtk_get_event_widget ((GdkEvent*) event);
|
||||
|
||||
@@ -4411,6 +4240,142 @@ gtk_menu_leave_notify (GtkWidget *widget,
|
||||
return GTK_WIDGET_CLASS (gtk_menu_parent_class)->leave_notify_event (widget, event);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pointer_on_menu_widget (GtkMenu *menu,
|
||||
gdouble x_root,
|
||||
gdouble y_root)
|
||||
{
|
||||
GtkMenuPrivate *priv = menu->priv;
|
||||
GtkAllocation allocation;
|
||||
gint window_x, window_y;
|
||||
|
||||
gtk_widget_get_allocation (GTK_WIDGET (menu), &allocation);
|
||||
gdk_window_get_position (gtk_widget_get_window (priv->toplevel),
|
||||
&window_x, &window_y);
|
||||
|
||||
if (x_root >= window_x && x_root < window_x + allocation.width &&
|
||||
y_root >= window_y && y_root < window_y + allocation.height)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_menu_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event)
|
||||
{
|
||||
GdkDevice *source_device;
|
||||
gboolean retval = FALSE;
|
||||
GtkMenuPrivate *priv;
|
||||
GtkMenu *menu;
|
||||
gdouble x_root, y_root;
|
||||
guint button;
|
||||
GdkModifierType state;
|
||||
|
||||
menu = GTK_MENU (widget);
|
||||
priv = menu->priv;
|
||||
|
||||
if (!priv->upper_arrow_visible && !priv->lower_arrow_visible)
|
||||
return retval;
|
||||
|
||||
source_device = gdk_event_get_source_device (event);
|
||||
gdk_event_get_root_coords (event, &x_root, &y_root);
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_BUTTON_PRESS:
|
||||
if ((!gdk_event_get_button (event, &button) || button == 1) &&
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN &&
|
||||
pointer_on_menu_widget (menu, x_root, y_root))
|
||||
{
|
||||
priv->drag_start_y = event->button.y_root;
|
||||
priv->initial_drag_offset = priv->scroll_offset;
|
||||
priv->drag_scroll_started = FALSE;
|
||||
}
|
||||
else
|
||||
priv->drag_start_y = -1;
|
||||
|
||||
priv->drag_already_pressed = TRUE;
|
||||
break;
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
if (priv->drag_scroll_started)
|
||||
{
|
||||
priv->drag_scroll_started = FALSE;
|
||||
priv->drag_start_y = -1;
|
||||
priv->drag_already_pressed = FALSE;
|
||||
retval = TRUE;
|
||||
}
|
||||
break;
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_MOTION_NOTIFY:
|
||||
if ((!gdk_event_get_state (event, &state) || (state & GDK_BUTTON1_MASK)
|
||||
!= 0) &&
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
|
||||
{
|
||||
if (!priv->drag_already_pressed)
|
||||
{
|
||||
if (pointer_on_menu_widget (menu, x_root, y_root))
|
||||
{
|
||||
priv->drag_start_y = y_root;
|
||||
priv->initial_drag_offset = priv->scroll_offset;
|
||||
priv->drag_scroll_started = FALSE;
|
||||
}
|
||||
else
|
||||
priv->drag_start_y = -1;
|
||||
|
||||
priv->drag_already_pressed = TRUE;
|
||||
}
|
||||
|
||||
if (priv->drag_start_y < 0 && !priv->drag_scroll_started)
|
||||
break;
|
||||
|
||||
if (priv->drag_scroll_started)
|
||||
{
|
||||
gint offset, view_height;
|
||||
GtkBorder arrow_border;
|
||||
gdouble y_diff;
|
||||
|
||||
y_diff = y_root - priv->drag_start_y;
|
||||
offset = priv->initial_drag_offset - y_diff;
|
||||
|
||||
view_height = gdk_window_get_height (gtk_widget_get_window (widget));
|
||||
get_arrows_border (menu, &arrow_border);
|
||||
|
||||
if (priv->upper_arrow_visible)
|
||||
view_height -= arrow_border.top;
|
||||
|
||||
if (priv->lower_arrow_visible)
|
||||
view_height -= arrow_border.bottom;
|
||||
|
||||
offset = CLAMP (offset, 0, priv->requested_height - view_height);
|
||||
gtk_menu_scroll_to (menu, offset);
|
||||
|
||||
retval = TRUE;
|
||||
}
|
||||
else if (gtk_drag_check_threshold (widget,
|
||||
0, priv->drag_start_y,
|
||||
0, y_root))
|
||||
{
|
||||
priv->drag_scroll_started = TRUE;
|
||||
gtk_menu_shell_deselect (GTK_MENU_SHELL (menu));
|
||||
retval = TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GDK_ENTER_NOTIFY:
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
if (priv->drag_scroll_started)
|
||||
retval = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_stop_navigating_submenu (GtkMenu *menu)
|
||||
{
|
||||
@@ -4853,19 +4818,10 @@ static void
|
||||
gtk_menu_stop_scrolling (GtkMenu *menu)
|
||||
{
|
||||
GtkMenuPrivate *priv = menu->priv;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
if (!touchscreen_mode)
|
||||
{
|
||||
priv->upper_arrow_prelight = FALSE;
|
||||
priv->lower_arrow_prelight = FALSE;
|
||||
}
|
||||
priv->upper_arrow_prelight = FALSE;
|
||||
priv->lower_arrow_prelight = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -5671,7 +5627,6 @@ gtk_menu_real_move_scroll (GtkMenu *menu,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gtk_menu_set_monitor:
|
||||
* @menu: a #GtkMenu
|
||||
@@ -5748,11 +5703,13 @@ static void
|
||||
gtk_menu_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed)
|
||||
{
|
||||
GtkMenu *menu;
|
||||
GtkWidget *toplevel;
|
||||
GtkWindowGroup *group;
|
||||
GtkWidget *grab;
|
||||
GdkDevice *pointer;
|
||||
|
||||
menu = GTK_MENU (widget);
|
||||
pointer = _gtk_menu_shell_get_grab_device (GTK_MENU_SHELL (widget));
|
||||
|
||||
if (!pointer ||
|
||||
@@ -5769,6 +5726,8 @@ gtk_menu_grab_notify (GtkWidget *widget,
|
||||
|
||||
if (GTK_MENU_SHELL (widget)->priv->active && !GTK_IS_MENU_SHELL (grab))
|
||||
gtk_menu_shell_cancel (GTK_MENU_SHELL (widget));
|
||||
|
||||
menu->priv->drag_scroll_started = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1688,13 +1688,20 @@ static void
|
||||
gtk_real_menu_item_select (GtkMenuItem *menu_item)
|
||||
{
|
||||
GtkMenuItemPrivate *priv = menu_item->priv;
|
||||
gboolean touchscreen_mode;
|
||||
GdkDevice *source_device = NULL;
|
||||
GdkEvent *current_event;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_item)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
current_event = gtk_get_current_event ();
|
||||
|
||||
if (!touchscreen_mode && priv->submenu &&
|
||||
if (current_event)
|
||||
{
|
||||
source_device = gdk_event_get_source_device (current_event);
|
||||
gdk_event_free (current_event);
|
||||
}
|
||||
|
||||
if ((!source_device ||
|
||||
gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN) &&
|
||||
priv->submenu &&
|
||||
(!gtk_widget_get_mapped (priv->submenu) ||
|
||||
GTK_MENU (priv->submenu)->priv->tearoff_active))
|
||||
{
|
||||
|
@@ -99,6 +99,8 @@ struct _GtkMenuPrivate
|
||||
guint seen_item_enter : 1;
|
||||
guint ignore_button_release : 1;
|
||||
guint no_toggle_size : 1;
|
||||
guint drag_already_pressed : 1;
|
||||
guint drag_scroll_started : 1;
|
||||
|
||||
/* info used for the table */
|
||||
guint *heights;
|
||||
@@ -125,6 +127,9 @@ struct _GtkMenuPrivate
|
||||
gint navigation_height;
|
||||
|
||||
guint navigation_timeout;
|
||||
|
||||
gdouble drag_start_y;
|
||||
gint initial_drag_offset;
|
||||
};
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -1083,13 +1083,11 @@ gtk_menu_shell_enter_notify (GtkWidget *widget,
|
||||
|
||||
if (!gtk_widget_get_visible (GTK_MENU_ITEM (menu_item)->priv->submenu))
|
||||
{
|
||||
gboolean touchscreen_mode;
|
||||
GdkDevice *source_device;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (widget),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
|
||||
if (touchscreen_mode)
|
||||
if (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
|
||||
_gtk_menu_item_popup_submenu (menu_item, TRUE);
|
||||
}
|
||||
}
|
||||
@@ -1611,45 +1609,19 @@ gtk_real_menu_shell_move_current (GtkMenuShell *menu_shell,
|
||||
GtkMenuShellPrivate *priv = menu_shell->priv;
|
||||
GtkMenuShell *parent_menu_shell = NULL;
|
||||
gboolean had_selection;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
priv->in_unselectable_item = FALSE;
|
||||
|
||||
had_selection = priv->active_menu_item != NULL;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
if (priv->parent_menu_shell)
|
||||
parent_menu_shell = GTK_MENU_SHELL (priv->parent_menu_shell);
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case GTK_MENU_DIR_PARENT:
|
||||
if (touchscreen_mode &&
|
||||
priv->active_menu_item &&
|
||||
GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu &&
|
||||
gtk_widget_get_visible (GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu))
|
||||
if (parent_menu_shell)
|
||||
{
|
||||
/* if we are on a menu item that has an open submenu but the
|
||||
* focus is not in that submenu (e.g. because it's empty or
|
||||
* has only insensitive items), close that submenu instead of
|
||||
* running into the code below which would close *this* menu.
|
||||
*/
|
||||
_gtk_menu_item_popdown_submenu (priv->active_menu_item);
|
||||
_gtk_menu_shell_update_mnemonics (menu_shell);
|
||||
}
|
||||
else if (parent_menu_shell)
|
||||
{
|
||||
if (touchscreen_mode)
|
||||
{
|
||||
/* close menu when returning from submenu. */
|
||||
_gtk_menu_item_popdown_submenu (GTK_MENU (menu_shell)->priv->parent_menu_item);
|
||||
_gtk_menu_shell_update_mnemonics (parent_menu_shell);
|
||||
break;
|
||||
}
|
||||
|
||||
if (GTK_MENU_SHELL_GET_CLASS (parent_menu_shell)->submenu_placement ==
|
||||
GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement)
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
|
358
gtk/gtkpaned.c
358
gtk/gtkpaned.c
@@ -34,6 +34,8 @@
|
||||
#include "gtktypebuiltins.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "a11y/gtkpanedaccessible.h"
|
||||
|
||||
/**
|
||||
@@ -96,6 +98,17 @@ enum {
|
||||
CHILD2
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GdkWindow *pane_window;
|
||||
GdkDevice *device;
|
||||
GdkEventSequence *sequence;
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
GdkEvent *button_press_event;
|
||||
guint press_consumed : 1;
|
||||
} TouchInfo;
|
||||
|
||||
struct _GtkPanedPrivate
|
||||
{
|
||||
GtkPaned *first_paned;
|
||||
@@ -122,6 +135,8 @@ struct _GtkPanedPrivate
|
||||
|
||||
guint32 grab_time;
|
||||
|
||||
GArray *touches;
|
||||
|
||||
guint handle_prelit : 1;
|
||||
guint in_drag : 1;
|
||||
guint in_recursion : 1;
|
||||
@@ -253,6 +268,8 @@ static gboolean gtk_paned_toggle_handle_focus (GtkPaned *paned);
|
||||
static GType gtk_paned_child_type (GtkContainer *container);
|
||||
static void gtk_paned_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed);
|
||||
static gboolean gtk_paned_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkPaned, gtk_paned, GTK_TYPE_CONTAINER,
|
||||
@@ -706,6 +723,11 @@ gtk_paned_init (GtkPaned *paned)
|
||||
priv->handle_pos.y = -1;
|
||||
|
||||
priv->drag_pos = -1;
|
||||
|
||||
priv->touches = g_array_sized_new (FALSE, FALSE,
|
||||
sizeof (TouchInfo), 2);
|
||||
|
||||
_gtk_widget_set_captured_event_handler (GTK_WIDGET (paned), gtk_paned_captured_event);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -861,9 +883,11 @@ static void
|
||||
gtk_paned_finalize (GObject *object)
|
||||
{
|
||||
GtkPaned *paned = GTK_PANED (object);
|
||||
|
||||
GtkPanedPrivate *priv = paned->priv;
|
||||
|
||||
gtk_paned_set_saved_focus (paned, NULL);
|
||||
gtk_paned_set_first_paned (paned, NULL);
|
||||
g_array_free (priv->touches, TRUE);
|
||||
|
||||
G_OBJECT_CLASS (gtk_paned_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -1279,7 +1303,9 @@ gtk_paned_create_child_window (GtkPaned *paned,
|
||||
|
||||
attributes.window_type = GDK_WINDOW_CHILD;
|
||||
attributes.wclass = GDK_INPUT_OUTPUT;
|
||||
attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
|
||||
attributes.event_mask = gtk_widget_get_events (widget) |
|
||||
GDK_EXPOSURE_MASK | GDK_TOUCH_MASK;
|
||||
|
||||
if (child)
|
||||
{
|
||||
GtkAllocation allocation;
|
||||
@@ -1569,7 +1595,8 @@ gtk_paned_enter (GtkWidget *widget,
|
||||
GtkPaned *paned = GTK_PANED (widget);
|
||||
GtkPanedPrivate *priv = paned->priv;
|
||||
|
||||
if (priv->in_drag)
|
||||
if (priv->in_drag &&
|
||||
priv->touches->len == 0)
|
||||
update_drag (paned, event->x, event->y);
|
||||
else
|
||||
{
|
||||
@@ -1591,7 +1618,8 @@ gtk_paned_leave (GtkWidget *widget,
|
||||
GtkPaned *paned = GTK_PANED (widget);
|
||||
GtkPanedPrivate *priv = paned->priv;
|
||||
|
||||
if (priv->in_drag)
|
||||
if (priv->in_drag &&
|
||||
priv->touches->len == 0)
|
||||
update_drag (paned, event->x, event->y);
|
||||
else
|
||||
{
|
||||
@@ -1624,6 +1652,38 @@ gtk_paned_focus (GtkWidget *widget,
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_drag (GtkPaned *paned,
|
||||
GdkDevice *device,
|
||||
int xpos,
|
||||
int ypos,
|
||||
guint time)
|
||||
{
|
||||
GtkPanedPrivate *priv = paned->priv;
|
||||
|
||||
if (gdk_device_grab (device,
|
||||
priv->handle,
|
||||
GDK_OWNERSHIP_WINDOW, FALSE,
|
||||
GDK_BUTTON1_MOTION_MASK
|
||||
| GDK_BUTTON_RELEASE_MASK
|
||||
| GDK_ENTER_NOTIFY_MASK
|
||||
| GDK_LEAVE_NOTIFY_MASK
|
||||
| GDK_TOUCH_MASK,
|
||||
NULL, time) != GDK_GRAB_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
priv->in_drag = TRUE;
|
||||
priv->grab_time = time;
|
||||
priv->grab_device = device;
|
||||
|
||||
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
priv->drag_pos = xpos;
|
||||
else
|
||||
priv->drag_pos = ypos;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_paned_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
@@ -1634,27 +1694,10 @@ gtk_paned_button_press (GtkWidget *widget,
|
||||
if (!priv->in_drag &&
|
||||
(event->window == priv->handle) && (event->button == GDK_BUTTON_PRIMARY))
|
||||
{
|
||||
/* 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_device_grab (event->device,
|
||||
priv->handle,
|
||||
GDK_OWNERSHIP_WINDOW, FALSE,
|
||||
GDK_BUTTON1_MOTION_MASK
|
||||
| GDK_BUTTON_RELEASE_MASK
|
||||
| GDK_ENTER_NOTIFY_MASK
|
||||
| GDK_LEAVE_NOTIFY_MASK,
|
||||
NULL, event->time) != GDK_GRAB_SUCCESS)
|
||||
if (!start_drag (paned, event->device,
|
||||
event->x, event->y, event->time))
|
||||
return FALSE;
|
||||
|
||||
priv->in_drag = TRUE;
|
||||
priv->grab_time = event->time;
|
||||
priv->grab_device = event->device;
|
||||
|
||||
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
priv->drag_pos = event->x;
|
||||
else
|
||||
priv->drag_pos = event->y;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -1668,9 +1711,13 @@ gtk_paned_grab_broken (GtkWidget *widget,
|
||||
GtkPaned *paned = GTK_PANED (widget);
|
||||
GtkPanedPrivate *priv = paned->priv;
|
||||
|
||||
priv->in_drag = FALSE;
|
||||
priv->drag_pos = -1;
|
||||
priv->position_set = TRUE;
|
||||
if (event->grab_window != priv->handle &&
|
||||
gdk_event_get_device ((GdkEvent *) event) == priv->grab_device)
|
||||
{
|
||||
priv->in_drag = FALSE;
|
||||
priv->drag_pos = -1;
|
||||
priv->position_set = TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1685,7 +1732,7 @@ stop_drag (GtkPaned *paned)
|
||||
priv->position_set = TRUE;
|
||||
|
||||
gdk_device_ungrab (priv->grab_device,
|
||||
priv->grab_time);
|
||||
gtk_get_current_event_time ());
|
||||
priv->grab_device = NULL;
|
||||
}
|
||||
|
||||
@@ -1760,6 +1807,263 @@ gtk_paned_motion (GtkWidget *widget,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GdkWindow *
|
||||
_gtk_paned_find_pane_window (GtkWidget *widget,
|
||||
GdkEvent *event)
|
||||
{
|
||||
GtkPanedPrivate *priv = GTK_PANED (widget)->priv;
|
||||
GtkWidget *event_widget;
|
||||
|
||||
event_widget = gtk_get_event_widget (event);
|
||||
|
||||
if (event_widget == widget)
|
||||
{
|
||||
if (event->any.window == priv->child1_window)
|
||||
return priv->child1_window;
|
||||
else if (event->any.window == priv->child2_window)
|
||||
return priv->child2_window;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
else if (event_widget == priv->child1 ||
|
||||
gtk_widget_is_ancestor (event_widget, priv->child1))
|
||||
return priv->child1_window;
|
||||
else if (event_widget == priv->child2 ||
|
||||
gtk_widget_is_ancestor (event_widget, priv->child2))
|
||||
return priv->child2_window;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static TouchInfo *
|
||||
_gtk_paned_find_touch (GtkPaned *paned,
|
||||
GdkDevice *device,
|
||||
GdkEventSequence *sequence,
|
||||
guint *index)
|
||||
{
|
||||
GtkPanedPrivate *priv = paned->priv;
|
||||
TouchInfo *info;
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < priv->touches->len; i++)
|
||||
{
|
||||
info = &g_array_index (priv->touches, TouchInfo, i);
|
||||
|
||||
if (info->device == device && info->sequence == sequence)
|
||||
{
|
||||
if (index)
|
||||
*index = i;
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_paned_release_captured_event (GtkPaned *paned,
|
||||
TouchInfo *touch,
|
||||
gboolean emit)
|
||||
{
|
||||
GtkPanedPrivate *priv = paned->priv;
|
||||
GtkWidget *event_widget, *child;
|
||||
|
||||
if (!touch->button_press_event)
|
||||
return;
|
||||
|
||||
event_widget = gtk_get_event_widget (touch->button_press_event);
|
||||
|
||||
if (touch->pane_window == priv->child1_window)
|
||||
child = priv->child1;
|
||||
else if (touch->pane_window == priv->child2_window)
|
||||
child = priv->child2;
|
||||
else
|
||||
return;
|
||||
|
||||
if (emit &&
|
||||
!_gtk_propagate_captured_event (event_widget,
|
||||
touch->button_press_event,
|
||||
child))
|
||||
gtk_propagate_event (event_widget, touch->button_press_event);
|
||||
|
||||
gdk_event_free (touch->button_press_event);
|
||||
touch->button_press_event = NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_paned_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event)
|
||||
{
|
||||
GtkPaned *paned = GTK_PANED (widget);
|
||||
GtkPanedPrivate *priv = paned->priv;
|
||||
GdkDevice *device, *source_device;
|
||||
GdkWindow *pane_window;
|
||||
TouchInfo new = { 0 }, *info;
|
||||
GdkEventSequence *sequence;
|
||||
guint index;
|
||||
gdouble event_x, event_y;
|
||||
gint x, y;
|
||||
|
||||
device = gdk_event_get_device (event);
|
||||
source_device = gdk_event_get_source_device (event);
|
||||
|
||||
/* We possibly deal with both pointer and touch events,
|
||||
* depending on the target window event mask, so assume
|
||||
* touch ID = 0 for pointer events to ease handling.
|
||||
*/
|
||||
sequence = gdk_event_get_event_sequence (event);
|
||||
|
||||
gdk_event_get_coords (event, &event_x, &event_y);
|
||||
|
||||
if (!source_device ||
|
||||
gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN)
|
||||
return FALSE;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_BUTTON_PRESS:
|
||||
case GDK_TOUCH_BEGIN:
|
||||
if (priv->touches->len == 2)
|
||||
return FALSE;
|
||||
|
||||
pane_window = _gtk_paned_find_pane_window (widget, event);
|
||||
gtk_widget_translate_coordinates (gtk_get_event_widget (event),
|
||||
widget,
|
||||
(gint)event_x, (gint)event_y,
|
||||
&x, &y);
|
||||
|
||||
for (index = 0; index < priv->touches->len; index++)
|
||||
{
|
||||
info = &g_array_index (priv->touches, TouchInfo, index);
|
||||
|
||||
/* There was already a touch in this pane */
|
||||
if (info->pane_window == pane_window)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
new.device = device;
|
||||
new.sequence = sequence;
|
||||
new.pane_window = pane_window;
|
||||
new.x = x;
|
||||
new.y = y;
|
||||
g_array_append_val (priv->touches, new);
|
||||
|
||||
if (priv->touches->len == 1)
|
||||
{
|
||||
/* It's the first touch, store the event and set
|
||||
* a timeout in order to release the event if no
|
||||
* second touch happens timely.
|
||||
*/
|
||||
info = &g_array_index (priv->touches, TouchInfo, 0);
|
||||
info->button_press_event = gdk_event_copy (event);
|
||||
return TRUE;
|
||||
}
|
||||
else if (priv->touches->len == 2)
|
||||
{
|
||||
GtkWidget *event_widget;
|
||||
|
||||
/* It's the second touch, release (don't emit) the
|
||||
* held button/touch presses.
|
||||
*/
|
||||
for (index = 0; index < priv->touches->len; index++)
|
||||
{
|
||||
info = &g_array_index (priv->touches, TouchInfo, index);
|
||||
gtk_paned_release_captured_event (paned, info, FALSE);
|
||||
info->press_consumed = TRUE;
|
||||
}
|
||||
|
||||
event_widget = gtk_get_event_widget (event);
|
||||
|
||||
if (event_widget == widget)
|
||||
{
|
||||
if (pane_window == priv->child2_window)
|
||||
{
|
||||
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
event_x += priv->handle_pos.x + priv->handle_pos.width;
|
||||
else
|
||||
event_y += priv->handle_pos.y + priv->handle_pos.height;
|
||||
}
|
||||
}
|
||||
else
|
||||
gtk_widget_translate_coordinates (event_widget, widget,
|
||||
(gint)event_x, (gint)event_y,
|
||||
&x, &y);
|
||||
|
||||
start_drag (paned, device, x, y,
|
||||
event->button.time);
|
||||
|
||||
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
priv->drag_pos = x - priv->handle_pos.x;
|
||||
else
|
||||
priv->drag_pos = y - priv->handle_pos.y;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
break;
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_TOUCH_END:
|
||||
info = _gtk_paned_find_touch (GTK_PANED (widget), device, sequence, &index);
|
||||
|
||||
if (info)
|
||||
{
|
||||
gboolean press_consumed;
|
||||
|
||||
if (priv->touches->len == 2)
|
||||
stop_drag (paned);
|
||||
|
||||
press_consumed = info->press_consumed;
|
||||
|
||||
/* Release the held button/touch press, if still queued */
|
||||
gtk_paned_release_captured_event (paned, info, TRUE);
|
||||
g_array_remove_index_fast (priv->touches, index);
|
||||
|
||||
if (press_consumed)
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
info = _gtk_paned_find_touch (GTK_PANED (widget), device, sequence, &index);
|
||||
|
||||
if (info)
|
||||
{
|
||||
gtk_widget_translate_coordinates (gtk_get_event_widget (event),
|
||||
widget,
|
||||
event_x, event_y,
|
||||
&x, &y);
|
||||
|
||||
/* If there is a single touch and this isn't a continuation
|
||||
* from a previous successful 2-touch operation, check
|
||||
* the threshold to let the child handle events.
|
||||
*/
|
||||
if (priv->touches->len == 1 &&
|
||||
gtk_drag_check_threshold (widget, info->x, info->y, x, y))
|
||||
{
|
||||
gtk_paned_release_captured_event (paned, info, TRUE);
|
||||
g_array_remove_index_fast (priv->touches, index);
|
||||
return FALSE;
|
||||
}
|
||||
else if (priv->touches->len == 2 && index == 1)
|
||||
{
|
||||
/* The device grab on priv->handle is in effect now,
|
||||
* so the event coordinates are already relative to
|
||||
* that window.
|
||||
*/
|
||||
update_drag (paned, event_x, event_y);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_paned_new:
|
||||
* @orientation: the paned's orientation.
|
||||
|
@@ -72,6 +72,10 @@ gboolean _gtk_translate_keyboard_accel_state (GdkKeymap *keymap,
|
||||
gint *level,
|
||||
GdkModifierType *consumed_modifiers);
|
||||
|
||||
gboolean _gtk_propagate_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkWidget *topmost);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_PRIVATE_H__ */
|
||||
|
@@ -2007,15 +2007,11 @@ gtk_range_draw (GtkWidget *widget,
|
||||
GtkStateFlags widget_state;
|
||||
gint focus_line_width = 0;
|
||||
gint focus_padding = 0;
|
||||
gboolean touchscreen;
|
||||
gboolean draw_trough = TRUE;
|
||||
gboolean draw_slider = TRUE;
|
||||
GtkStyleContext *context;
|
||||
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
g_object_get (gtk_widget_get_settings (widget),
|
||||
"gtk-touchscreen-mode", &touchscreen,
|
||||
NULL);
|
||||
|
||||
if (GTK_IS_SCALE (widget) &&
|
||||
gtk_adjustment_get_upper (priv->adjustment) == gtk_adjustment_get_lower (priv->adjustment))
|
||||
@@ -2277,7 +2273,7 @@ gtk_range_draw (GtkWidget *widget,
|
||||
|
||||
state &= ~(GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_ACTIVE);
|
||||
|
||||
if (!touchscreen && priv->mouse_location == MOUSE_SLIDER && !(state & GTK_STATE_FLAG_INSENSITIVE))
|
||||
if (priv->mouse_location == MOUSE_SLIDER && !(state & GTK_STATE_FLAG_INSENSITIVE))
|
||||
state |= GTK_STATE_FLAG_PRELIGHT;
|
||||
|
||||
if (priv->grab_location == MOUSE_SLIDER)
|
||||
@@ -2307,28 +2303,28 @@ gtk_range_draw (GtkWidget *widget,
|
||||
draw_stepper (range, STEPPER_A, cr,
|
||||
priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT,
|
||||
priv->grab_location == MOUSE_STEPPER_A,
|
||||
!touchscreen && priv->mouse_location == MOUSE_STEPPER_A,
|
||||
priv->mouse_location == MOUSE_STEPPER_A,
|
||||
widget_state);
|
||||
|
||||
if (priv->has_stepper_b)
|
||||
draw_stepper (range, STEPPER_B, cr,
|
||||
priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT,
|
||||
priv->grab_location == MOUSE_STEPPER_B,
|
||||
!touchscreen && priv->mouse_location == MOUSE_STEPPER_B,
|
||||
priv->mouse_location == MOUSE_STEPPER_B,
|
||||
widget_state);
|
||||
|
||||
if (priv->has_stepper_c)
|
||||
draw_stepper (range, STEPPER_C, cr,
|
||||
priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT,
|
||||
priv->grab_location == MOUSE_STEPPER_C,
|
||||
!touchscreen && priv->mouse_location == MOUSE_STEPPER_C,
|
||||
priv->mouse_location == MOUSE_STEPPER_C,
|
||||
widget_state);
|
||||
|
||||
if (priv->has_stepper_d)
|
||||
draw_stepper (range, STEPPER_D, cr,
|
||||
priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT,
|
||||
priv->grab_location == MOUSE_STEPPER_D,
|
||||
!touchscreen && priv->mouse_location == MOUSE_STEPPER_D,
|
||||
priv->mouse_location == MOUSE_STEPPER_D,
|
||||
widget_state);
|
||||
|
||||
return FALSE;
|
||||
@@ -2526,7 +2522,8 @@ gtk_range_button_press (GtkWidget *widget,
|
||||
{
|
||||
GtkRange *range = GTK_RANGE (widget);
|
||||
GtkRangePrivate *priv = range->priv;
|
||||
GdkDevice *device;
|
||||
GdkDevice *device, *source_device;
|
||||
GdkInputSource source;
|
||||
|
||||
if (!gtk_widget_has_focus (widget))
|
||||
gtk_widget_grab_focus (widget);
|
||||
@@ -2536,6 +2533,9 @@ gtk_range_button_press (GtkWidget *widget,
|
||||
return FALSE;
|
||||
|
||||
device = gdk_event_get_device ((GdkEvent *) event);
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
source = gdk_device_get_source (source_device);
|
||||
|
||||
priv->mouse_x = event->x;
|
||||
priv->mouse_y = event->y;
|
||||
|
||||
@@ -2552,23 +2552,24 @@ gtk_range_button_press (GtkWidget *widget,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (priv->mouse_location == MOUSE_TROUGH &&
|
||||
if (source != GDK_SOURCE_TOUCHSCREEN &&
|
||||
priv->mouse_location == MOUSE_TROUGH &&
|
||||
event->button == GDK_BUTTON_PRIMARY)
|
||||
{
|
||||
/* button 1 steps by page increment, as with button 2 on a stepper
|
||||
*/
|
||||
GtkScrollType scroll;
|
||||
gdouble click_value;
|
||||
|
||||
|
||||
click_value = coord_to_value (range,
|
||||
priv->orientation == GTK_ORIENTATION_VERTICAL ?
|
||||
event->y : event->x);
|
||||
|
||||
priv->trough_click_forward = click_value > gtk_adjustment_get_value (priv->adjustment);
|
||||
range_grab_add (range, device, MOUSE_TROUGH, event->button);
|
||||
|
||||
|
||||
scroll = range_get_scroll_for_grab (range);
|
||||
|
||||
|
||||
gtk_range_add_step_timer (range, scroll);
|
||||
|
||||
return TRUE;
|
||||
@@ -2603,17 +2604,17 @@ gtk_range_button_press (GtkWidget *widget,
|
||||
return TRUE;
|
||||
}
|
||||
else if ((priv->mouse_location == MOUSE_TROUGH &&
|
||||
event->button == GDK_BUTTON_MIDDLE) ||
|
||||
(source == GDK_SOURCE_TOUCHSCREEN || event->button == GDK_BUTTON_MIDDLE)) ||
|
||||
priv->mouse_location == MOUSE_SLIDER)
|
||||
{
|
||||
gboolean need_value_update = FALSE;
|
||||
|
||||
/* Any button can be used to drag the slider, but you can start
|
||||
* dragging the slider with a trough click using button 2;
|
||||
* On button 2 press, we warp the slider to mouse position,
|
||||
* then begin the slider drag.
|
||||
* On button 2 press and touch devices, we warp the slider to
|
||||
* mouse position, then begin the slider drag.
|
||||
*/
|
||||
if (event->button == GDK_BUTTON_MIDDLE)
|
||||
if (event->button == GDK_BUTTON_MIDDLE || source == GDK_SOURCE_TOUCHSCREEN)
|
||||
{
|
||||
gdouble slider_low_value, slider_high_value, new_value;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -115,6 +115,13 @@ void gtk_scrolled_window_set_min_content_width (GtkScrolledWindow *sc
|
||||
gint gtk_scrolled_window_get_min_content_height (GtkScrolledWindow *scrolled_window);
|
||||
void gtk_scrolled_window_set_min_content_height (GtkScrolledWindow *scrolled_window,
|
||||
gint height);
|
||||
void gtk_scrolled_window_set_kinetic_scrolling (GtkScrolledWindow *scrolled_window,
|
||||
gboolean kinetic_scrolling);
|
||||
gboolean gtk_scrolled_window_get_kinetic_scrolling (GtkScrolledWindow *scrolled_window);
|
||||
|
||||
void gtk_scrolled_window_set_capture_button_press (GtkScrolledWindow *scrolled_window,
|
||||
gboolean capture_button_press);
|
||||
gboolean gtk_scrolled_window_get_capture_button_press (GtkScrolledWindow *scrolled_window);
|
||||
|
||||
gint _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window);
|
||||
|
||||
|
@@ -700,13 +700,16 @@ gtk_settings_class_init (GtkSettingsClass *class)
|
||||
* functionality.
|
||||
*
|
||||
* Since: 2.10
|
||||
*
|
||||
* Deprecated: 3.4. Generally the behavior touchscreen input should be
|
||||
* performed dynamically based on gdk_event_get_source_device().
|
||||
*/
|
||||
result = settings_install_property_parser (class,
|
||||
g_param_spec_boolean ("gtk-touchscreen-mode",
|
||||
P_("Enable Touchscreen Mode"),
|
||||
P_("When TRUE, there are no motion notify events delivered on this screen"),
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE),
|
||||
GTK_PARAM_READWRITE | G_PARAM_DEPRECATED),
|
||||
NULL);
|
||||
|
||||
g_assert (result == PROP_TOUCHSCREEN_MODE);
|
||||
|
@@ -656,13 +656,9 @@ gtk_toggle_button_update_state (GtkButton *button)
|
||||
{
|
||||
GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button);
|
||||
GtkToggleButtonPrivate *priv = toggle_button->priv;
|
||||
gboolean depressed, touchscreen;
|
||||
gboolean depressed;
|
||||
GtkStateFlags new_state = 0;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (button)),
|
||||
"gtk-touchscreen-mode", &touchscreen,
|
||||
NULL);
|
||||
|
||||
new_state = gtk_widget_get_state_flags (GTK_WIDGET (button)) &
|
||||
~(GTK_STATE_FLAG_INCONSISTENT |
|
||||
GTK_STATE_FLAG_PRELIGHT |
|
||||
@@ -678,7 +674,7 @@ gtk_toggle_button_update_state (GtkButton *button)
|
||||
else
|
||||
depressed = priv->active;
|
||||
|
||||
if (!touchscreen && button->priv->in_button && (!button->priv->button_down || priv->draw_indicator))
|
||||
if (button->priv->in_button && (!button->priv->button_down || priv->draw_indicator))
|
||||
new_state |= GTK_STATE_FLAG_PRELIGHT;
|
||||
|
||||
if (depressed)
|
||||
|
@@ -1535,22 +1535,33 @@ _gtk_tooltip_hide (GtkWidget *widget)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tooltips_enabled (GdkWindow *window)
|
||||
tooltips_enabled (GdkEvent *event)
|
||||
{
|
||||
GdkDevice *source_device;
|
||||
GdkInputSource source;
|
||||
GdkWindow *window;
|
||||
gboolean enabled;
|
||||
gboolean touchscreen;
|
||||
GdkScreen *screen;
|
||||
GtkSettings *settings;
|
||||
|
||||
window = event->any.window;
|
||||
source_device = gdk_event_get_source_device (event);
|
||||
|
||||
if (!source_device)
|
||||
return FALSE;
|
||||
|
||||
source = gdk_device_get_source (source_device);
|
||||
screen = gdk_window_get_screen (window);
|
||||
settings = gtk_settings_get_for_screen (screen);
|
||||
|
||||
g_object_get (settings,
|
||||
"gtk-touchscreen-mode", &touchscreen,
|
||||
"gtk-enable-tooltips", &enabled,
|
||||
NULL);
|
||||
|
||||
return (!touchscreen && enabled);
|
||||
if (enabled && source != GDK_SOURCE_TOUCHSCREEN)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1562,7 +1573,7 @@ _gtk_tooltip_handle_event (GdkEvent *event)
|
||||
GdkDisplay *display;
|
||||
GtkTooltip *current_tooltip;
|
||||
|
||||
if (!tooltips_enabled (event->any.window))
|
||||
if (!tooltips_enabled (event))
|
||||
return;
|
||||
|
||||
/* Returns coordinates relative to has_tooltip_widget's allocation. */
|
||||
|
@@ -682,7 +682,7 @@ gtk_viewport_realize (GtkWidget *widget)
|
||||
event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
|
||||
/* We select on button_press_mask so that button 4-5 scrolls are trapped.
|
||||
*/
|
||||
attributes.event_mask = event_mask | GDK_BUTTON_PRESS_MASK;
|
||||
attributes.event_mask = event_mask | GDK_BUTTON_PRESS_MASK | GDK_TOUCH_MASK;
|
||||
|
||||
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
|
||||
|
||||
|
143
gtk/gtkwidget.c
143
gtk/gtkwidget.c
@@ -482,6 +482,7 @@ enum {
|
||||
QUERY_TOOLTIP,
|
||||
DRAG_FAILED,
|
||||
STYLE_UPDATED,
|
||||
TOUCH_EVENT,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
@@ -587,6 +588,8 @@ static gboolean gtk_widget_real_focus_in_event (GtkWidget *widget,
|
||||
GdkEventFocus *event);
|
||||
static gboolean gtk_widget_real_focus_out_event (GtkWidget *widget,
|
||||
GdkEventFocus *event);
|
||||
static gboolean gtk_widget_real_touch_event (GtkWidget *widget,
|
||||
GdkEventTouch *event);
|
||||
static gboolean gtk_widget_real_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
static void gtk_widget_real_move_focus (GtkWidget *widget,
|
||||
@@ -703,6 +706,7 @@ static void gtk_widget_set_device_enabled_internal (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
gboolean recurse,
|
||||
gboolean enabled);
|
||||
static gboolean event_window_is_still_viewable (GdkEvent *event);
|
||||
|
||||
/* --- variables --- */
|
||||
static gpointer gtk_widget_parent_class = NULL;
|
||||
@@ -902,6 +906,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
|
||||
klass->button_press_event = NULL;
|
||||
klass->button_release_event = NULL;
|
||||
klass->motion_notify_event = NULL;
|
||||
klass->touch_event = gtk_widget_real_touch_event;
|
||||
klass->delete_event = NULL;
|
||||
klass->destroy_event = NULL;
|
||||
klass->key_press_event = gtk_widget_real_key_press_event;
|
||||
@@ -1886,6 +1891,15 @@ gtk_widget_class_init (GtkWidgetClass *klass)
|
||||
G_TYPE_BOOLEAN, 1,
|
||||
GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||
|
||||
widget_signals[TOUCH_EVENT] =
|
||||
g_signal_new (I_("touch-event"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkWidgetClass, touch_event),
|
||||
_gtk_boolean_handled_accumulator, NULL,
|
||||
_gtk_marshal_BOOLEAN__BOXED,
|
||||
G_TYPE_BOOLEAN, 1,
|
||||
GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||
/**
|
||||
* GtkWidget::scroll-event:
|
||||
* @widget: the object which received the signal.
|
||||
@@ -5830,6 +5844,76 @@ gtk_widget_real_focus_out_event (GtkWidget *widget,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_widget_real_touch_event (GtkWidget *widget,
|
||||
GdkEventTouch *event)
|
||||
{
|
||||
GdkEvent *bevent;
|
||||
gboolean return_val;
|
||||
gint signum;
|
||||
|
||||
if (!event->emulating_pointer)
|
||||
return FALSE;
|
||||
|
||||
if (event->type == GDK_TOUCH_BEGIN ||
|
||||
event->type == GDK_TOUCH_END)
|
||||
{
|
||||
GdkEventType type;
|
||||
|
||||
if (event->type == GDK_TOUCH_BEGIN)
|
||||
{
|
||||
type = GDK_BUTTON_PRESS;
|
||||
signum = BUTTON_PRESS_EVENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = GDK_BUTTON_RELEASE;
|
||||
signum = BUTTON_RELEASE_EVENT;
|
||||
}
|
||||
bevent = gdk_event_new (type);
|
||||
bevent->any.window = g_object_ref (event->window);
|
||||
bevent->any.send_event = FALSE;
|
||||
bevent->button.time = event->time;
|
||||
bevent->button.state = event->state;
|
||||
bevent->button.button = 1;
|
||||
bevent->button.x_root = event->x_root;
|
||||
bevent->button.y_root = event->y_root;
|
||||
bevent->button.x = event->x;
|
||||
bevent->button.y = event->y;
|
||||
bevent->button.device = event->device;
|
||||
bevent->button.axes = g_memdup (event->axes,
|
||||
sizeof (gdouble) * gdk_device_get_n_axes (event->device));
|
||||
gdk_event_set_source_device (bevent, gdk_event_get_source_device ((GdkEvent*)event));
|
||||
}
|
||||
else if (event->type == GDK_TOUCH_UPDATE)
|
||||
{
|
||||
signum = MOTION_NOTIFY_EVENT;
|
||||
bevent = gdk_event_new (GDK_MOTION_NOTIFY);
|
||||
bevent->any.window = g_object_ref (event->window);
|
||||
bevent->any.send_event = FALSE;
|
||||
bevent->motion.time = event->time;
|
||||
bevent->motion.state = event->state;
|
||||
bevent->motion.x_root = event->x_root;
|
||||
bevent->motion.y_root = event->y_root;
|
||||
bevent->motion.x = event->x;
|
||||
bevent->motion.y = event->y;
|
||||
bevent->motion.device = event->device;
|
||||
bevent->motion.is_hint = FALSE;
|
||||
bevent->motion.axes = g_memdup (event->axes,
|
||||
sizeof (gdouble) * gdk_device_get_n_axes (event->device));
|
||||
gdk_event_set_source_device (bevent, gdk_event_get_source_device ((GdkEvent*)event));
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
g_signal_emit (widget, widget_signals[signum], 0, bevent, &return_val);
|
||||
|
||||
gdk_event_free (bevent);
|
||||
|
||||
return return_val;
|
||||
}
|
||||
|
||||
|
||||
#define WIDGET_REALIZED_FOR_EVENT(widget, event) \
|
||||
(event->type == GDK_FOCUS_CHANGE || gtk_widget_get_realized(widget))
|
||||
|
||||
@@ -5868,6 +5952,59 @@ gtk_widget_event (GtkWidget *widget,
|
||||
return gtk_widget_event_internal (widget, event);
|
||||
}
|
||||
|
||||
void
|
||||
_gtk_widget_set_captured_event_handler (GtkWidget *widget,
|
||||
GtkCapturedEventHandler callback)
|
||||
{
|
||||
g_object_set_data (G_OBJECT (widget), "captured-event-handler", callback);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gtk_widget_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event)
|
||||
{
|
||||
gboolean return_val = FALSE;
|
||||
GtkCapturedEventHandler handler;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);
|
||||
g_return_val_if_fail (WIDGET_REALIZED_FOR_EVENT (widget, event), TRUE);
|
||||
|
||||
if (event->type == GDK_EXPOSE)
|
||||
{
|
||||
g_warning ("Events of type GDK_EXPOSE cannot be synthesized. To get "
|
||||
"the same effect, call gdk_window_invalidate_rect/region(), "
|
||||
"followed by gdk_window_process_updates().");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!event_window_is_still_viewable (event))
|
||||
return TRUE;
|
||||
|
||||
handler = g_object_get_data (G_OBJECT (widget), "captured-event-handler");
|
||||
if (!handler)
|
||||
return FALSE;
|
||||
|
||||
g_object_ref (widget);
|
||||
|
||||
return_val = handler (widget, event);
|
||||
return_val |= !WIDGET_REALIZED_FOR_EVENT (widget, event);
|
||||
|
||||
/* The widget that was originally to receive the event
|
||||
* handles motion hints, but the capturing widget might
|
||||
* not, so ensure we get further motion events.
|
||||
*/
|
||||
if (return_val &&
|
||||
event->type == GDK_MOTION_NOTIFY &&
|
||||
event->motion.is_hint &&
|
||||
(gdk_window_get_events (event->any.window) &
|
||||
GDK_POINTER_MOTION_HINT_MASK) != 0)
|
||||
gdk_event_request_motions (&event->motion);
|
||||
|
||||
g_object_unref (widget);
|
||||
|
||||
return return_val;
|
||||
}
|
||||
|
||||
/* Returns TRUE if a translation should be done */
|
||||
gboolean
|
||||
_gtk_widget_get_translation_to_window (GtkWidget *widget,
|
||||
@@ -6068,6 +6205,12 @@ gtk_widget_event_internal (GtkWidget *widget,
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
signal_num = BUTTON_PRESS_EVENT;
|
||||
break;
|
||||
case GDK_TOUCH_BEGIN:
|
||||
case GDK_TOUCH_UPDATE:
|
||||
case GDK_TOUCH_END:
|
||||
case GDK_TOUCH_CANCEL:
|
||||
signal_num = TOUCH_EVENT;
|
||||
break;
|
||||
case GDK_SCROLL:
|
||||
signal_num = SCROLL_EVENT;
|
||||
|
@@ -423,6 +423,9 @@ struct _GtkWidgetClass
|
||||
|
||||
void (* style_updated) (GtkWidget *widget);
|
||||
|
||||
gboolean (* touch_event) (GtkWidget *widget,
|
||||
GdkEventTouch *event);
|
||||
|
||||
/*< private >*/
|
||||
|
||||
GtkWidgetClassPrivate *priv;
|
||||
@@ -434,7 +437,6 @@ struct _GtkWidgetClass
|
||||
void (*_gtk_reserved5) (void);
|
||||
void (*_gtk_reserved6) (void);
|
||||
void (*_gtk_reserved7) (void);
|
||||
void (*_gtk_reserved8) (void);
|
||||
};
|
||||
|
||||
struct _GtkWidgetAuxInfo
|
||||
|
@@ -165,6 +165,13 @@ GtkStyle * _gtk_widget_get_style (GtkWidget *widget);
|
||||
void _gtk_widget_set_style (GtkWidget *widget,
|
||||
GtkStyle *style);
|
||||
|
||||
typedef gboolean (*GtkCapturedEventHandler) (GtkWidget *widget, GdkEvent *event);
|
||||
|
||||
void _gtk_widget_set_captured_event_handler (GtkWidget *widget,
|
||||
GtkCapturedEventHandler handler);
|
||||
|
||||
gboolean _gtk_widget_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@@ -64,6 +64,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \
|
||||
testicontheme \
|
||||
testimage \
|
||||
testinput \
|
||||
testkineticscrolling \
|
||||
testlockbutton \
|
||||
testmenubars \
|
||||
testmountoperation \
|
||||
@@ -182,6 +183,7 @@ testgrid_DEPENDENCIES = $(TEST_DEPS)
|
||||
testgtk_DEPENDENCIES = $(TEST_DEPS)
|
||||
testinput_DEPENDENCIES = $(TEST_DEPS)
|
||||
testimage_DEPENDENCIES = $(TEST_DEPS)
|
||||
testkineticscrolling_DEPENDENCIES = $(TEST_DEPS)
|
||||
testlockbutton_DEPENDENCIES = $(TEST_DEPS)
|
||||
testmenubars_DEPENDENCIES = $(TEST_DEPS)
|
||||
testmountoperation_DEPENDENCIES = $(TEST_DEPS)
|
||||
@@ -282,6 +284,7 @@ testiconview_LDADD = $(LDADDS)
|
||||
testiconview_keynav_LDADD = $(LDADDS)
|
||||
testinput_LDADD = $(LDADDS)
|
||||
testimage_LDADD = $(LDADDS)
|
||||
testkineticscrolling_LDADD = $(LDADDS)
|
||||
testlockbutton_LDADD = $(LDADDS)
|
||||
testmenubars_LDADD = $(LDADDS)
|
||||
testmountoperation_LDADD = $(LDADDS)
|
||||
@@ -530,6 +533,8 @@ testpixbuf_save_SOURCES = testpixbuf-save.c
|
||||
|
||||
testcolorchooser_SOURCES = testcolorchooser.c
|
||||
|
||||
testkineticscrolling_SOURCES = testkineticscrolling.c
|
||||
|
||||
EXTRA_DIST += \
|
||||
gradient1.png \
|
||||
prop-editor.h \
|
||||
|
148
tests/testkineticscrolling.c
Normal file
148
tests/testkineticscrolling.c
Normal file
@@ -0,0 +1,148 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
enum
|
||||
{
|
||||
TARGET_GTK_TREE_MODEL_ROW
|
||||
};
|
||||
|
||||
static GtkTargetEntry row_targets[] =
|
||||
{
|
||||
{ "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, TARGET_GTK_TREE_MODEL_ROW }
|
||||
};
|
||||
|
||||
static void
|
||||
on_button_clicked (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
g_print ("Button %d clicked\n", GPOINTER_TO_INT (data));
|
||||
}
|
||||
|
||||
static void
|
||||
kinetic_scrolling (void)
|
||||
{
|
||||
GtkWidget *window, *swindow, *grid;
|
||||
GtkWidget *label;
|
||||
GtkWidget *button_grid, *button;
|
||||
GtkWidget *treeview;
|
||||
GtkCellRenderer *renderer;
|
||||
GtkListStore *store;
|
||||
GtkWidget *textview;
|
||||
gint i;
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (window), 5);
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
|
||||
g_signal_connect (window, "delete_event",
|
||||
G_CALLBACK (gtk_main_quit), NULL);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
|
||||
label = gtk_label_new ("Non scrollable widget using viewport");
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
|
||||
gtk_widget_set_hexpand (label, TRUE);
|
||||
gtk_widget_show (label);
|
||||
|
||||
label = gtk_label_new ("Scrollable widget: TreeView");
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 1, 0, 1, 1);
|
||||
gtk_widget_set_hexpand (label, TRUE);
|
||||
gtk_widget_show (label);
|
||||
|
||||
label = gtk_label_new ("Scrollable widget: TextView");
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 2, 0, 1, 1);
|
||||
gtk_widget_set_hexpand (label, TRUE);
|
||||
gtk_widget_show (label);
|
||||
|
||||
button_grid = gtk_grid_new ();
|
||||
for (i = 0; i < 80; i++)
|
||||
{
|
||||
gchar *label = g_strdup_printf ("Button number %d", i);
|
||||
|
||||
button = gtk_button_new_with_label (label);
|
||||
gtk_grid_attach (GTK_GRID (button_grid), button, 0, i, 1, 1);
|
||||
gtk_widget_set_hexpand (button, TRUE);
|
||||
gtk_widget_show (button);
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (on_button_clicked),
|
||||
GINT_TO_POINTER (i));
|
||||
g_free (label);
|
||||
}
|
||||
|
||||
swindow = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_kinetic_scrolling (GTK_SCROLLED_WINDOW (swindow), TRUE);
|
||||
gtk_scrolled_window_set_capture_button_press (GTK_SCROLLED_WINDOW (swindow), TRUE);
|
||||
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (swindow), button_grid);
|
||||
gtk_widget_show (button_grid);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), swindow, 0, 1, 1, 1);
|
||||
gtk_widget_show (swindow);
|
||||
|
||||
treeview = gtk_tree_view_new ();
|
||||
gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (treeview),
|
||||
GDK_BUTTON1_MASK,
|
||||
row_targets,
|
||||
G_N_ELEMENTS (row_targets),
|
||||
GDK_ACTION_MOVE | GDK_ACTION_COPY);
|
||||
gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (treeview),
|
||||
row_targets,
|
||||
G_N_ELEMENTS (row_targets),
|
||||
GDK_ACTION_MOVE | GDK_ACTION_COPY);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new ();
|
||||
g_object_set (renderer, "editable", TRUE, NULL);
|
||||
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
||||
0, "Title",
|
||||
renderer,
|
||||
"text", 0,
|
||||
NULL);
|
||||
store = gtk_list_store_new (1, G_TYPE_STRING);
|
||||
for (i = 0; i < 80; i++)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
gchar *label = g_strdup_printf ("Row number %d", i);
|
||||
|
||||
gtk_list_store_append (store, &iter);
|
||||
gtk_list_store_set (store, &iter, 0, label, -1);
|
||||
g_free (label);
|
||||
}
|
||||
gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
|
||||
g_object_unref (store);
|
||||
|
||||
swindow = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_kinetic_scrolling (GTK_SCROLLED_WINDOW (swindow), TRUE);
|
||||
gtk_scrolled_window_set_capture_button_press (GTK_SCROLLED_WINDOW (swindow), TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (swindow), treeview);
|
||||
gtk_widget_show (treeview);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), swindow, 1, 1, 1, 1);
|
||||
gtk_widget_set_hexpand (swindow, TRUE);
|
||||
gtk_widget_set_vexpand (swindow, TRUE);
|
||||
gtk_widget_show (swindow);
|
||||
|
||||
textview = gtk_text_view_new ();
|
||||
swindow = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_kinetic_scrolling (GTK_SCROLLED_WINDOW (swindow), TRUE);
|
||||
gtk_scrolled_window_set_capture_button_press (GTK_SCROLLED_WINDOW (swindow), TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (swindow), textview);
|
||||
gtk_widget_show (textview);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), swindow, 2, 1, 1, 1);
|
||||
gtk_widget_set_hexpand (swindow, TRUE);
|
||||
gtk_widget_set_vexpand (swindow, TRUE);
|
||||
gtk_widget_show (swindow);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (window), grid);
|
||||
gtk_widget_show (grid);
|
||||
|
||||
gtk_widget_show (window);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gtk_init (NULL, NULL);
|
||||
|
||||
kinetic_scrolling ();
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
@@ -53,6 +53,16 @@ content_height_changed (GtkSpinButton *spin_button,
|
||||
gtk_scrolled_window_set_min_content_height (swindow, (gint)value);
|
||||
}
|
||||
|
||||
static void
|
||||
kinetic_scrolling_changed (GtkToggleButton *toggle_button,
|
||||
gpointer data)
|
||||
{
|
||||
GtkScrolledWindow *swindow = data;
|
||||
gboolean enabled = gtk_toggle_button_get_active (toggle_button);
|
||||
|
||||
gtk_scrolled_window_set_kinetic_scrolling (swindow, enabled);
|
||||
}
|
||||
|
||||
static void
|
||||
scrollable_policy (void)
|
||||
{
|
||||
@@ -199,6 +209,13 @@ scrollable_policy (void)
|
||||
g_signal_connect (G_OBJECT (widget), "changed",
|
||||
G_CALLBACK (label_flip_changed), label);
|
||||
|
||||
/* Add Kinetic scrolling control here */
|
||||
widget = gtk_check_button_new_with_label ("Kinetic scrolling");
|
||||
gtk_widget_show (widget);
|
||||
gtk_box_pack_start (GTK_BOX (cntl), widget, TRUE, TRUE, 0);
|
||||
g_signal_connect (G_OBJECT (widget), "toggled",
|
||||
G_CALLBACK (kinetic_scrolling_changed), swindow);
|
||||
|
||||
gtk_widget_show (window);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user