Compare commits

...

8 Commits

Author SHA1 Message Date
Matthias Clasen
426d6e8241 Track only motion
The fact that the buttons right above the touchpad actually report
events for the trackpoint puts a wrench into the current device
tracking idea. I always use those buttons together with the touchpad,
so I constantly change the current device between touchpad and
trackpoint, which ruins the experience.

To overcome this problem, use only motion events for the current
tracking, eliminating the problem, but making this tracking less
generally useful. It is really tailored towards overlay scrolling
now.
2014-11-28 14:28:50 -05:00
Matthias Clasen
7359a9daec Update overlay scrolling when current device changes
Instead of looking for the mere presence of a mouse, we now
look for what device was most recently used to move the pointer
around. With this approach, we can now treat trackpoints like
mice, since their presence wont hurt unless they are used.
2014-11-28 14:28:50 -05:00
Matthias Clasen
a0e294dba9 Track the most-recently used device
Add a ::current-device property to GdkDeviceManager which tracks
the most recently used slave device.
2014-11-28 14:28:50 -05:00
Matthias Clasen
0851e8d47e overlay scrolling: Use device timestamps in heuristics
Use the device timestamps when determining whether to show overlay
scrollbars or not. This lets us treat trackpoints like mice, without
enforcing traditional scrollbars for thinkpad users who never use
the trackpoint.
2014-11-28 14:28:50 -05:00
Matthias Clasen
ad8830815a x11: Make device timestamps work
We need to set the time of the event before associating the
device with it.
2014-11-28 14:28:50 -05:00
Matthias Clasen
8c63fe64e6 Wayland: Make device timestamps work
We need to set the time of the event before associating the
device with it.
2014-11-28 14:28:50 -05:00
Matthias Clasen
6c8d86c9bb Update device timestamps
Update device timestamps when a device is associated with an event.
2014-11-28 14:28:50 -05:00
Matthias Clasen
e83b934272 GdkDevice: Add a last-used timestamp
This will be used in determining whether to treat the system as
touch or not.
2014-11-28 14:28:50 -05:00
9 changed files with 129 additions and 26 deletions

View File

@@ -20,6 +20,7 @@
#include <math.h>
#include "gdkdeviceprivate.h"
#include "gdkdevicemanagerprivate.h"
#include "gdkdisplayprivate.h"
#include "gdkinternals.h"
#include "gdkintl.h"
@@ -1757,3 +1758,33 @@ gdk_device_get_last_event_window (GdkDevice *device)
return info->window_under_pointer;
}
/**
* gdk_device_get_motion_time:
* @device: a #GdkDevice
*
* Returns the timestamp of the last motion event involving this device
* that GDK has received.
*
* Returns: the timestamp of the last event for this device
*
* Since: 3.16
*/
guint32
gdk_device_get_motion_time (GdkDevice *device)
{
g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
return device->time;
}
void
_gdk_device_set_motion_time (GdkDevice *device,
guint32 time)
{
if (time > device->time)
{
device->time = time;
_gdk_device_manager_update_current_device (device->manager, device);
}
}

View File

@@ -274,6 +274,9 @@ gboolean gdk_device_grab_info_libgtk_only (GdkDisplay *display,
GDK_AVAILABLE_IN_3_12
GdkWindow *gdk_device_get_last_event_window (GdkDevice *device);
GDK_AVAILABLE_IN_3_16
guint32 gdk_device_get_motion_time (GdkDevice *device);
G_END_DECLS
#endif /* __GDK_DEVICE_H__ */

View File

@@ -154,13 +154,15 @@ G_DEFINE_ABSTRACT_TYPE (GdkDeviceManager, gdk_device_manager, G_TYPE_OBJECT)
enum {
PROP_0,
PROP_DISPLAY
PROP_DISPLAY,
PROP_CURRENT_DEVICE
};
enum {
DEVICE_ADDED,
DEVICE_REMOVED,
DEVICE_CHANGED,
CURRENT_DEVICE_CHANGED,
LAST_SIGNAL
};
@@ -184,6 +186,22 @@ gdk_device_manager_class_init (GdkDeviceManagerClass *klass)
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
/**
* GdkDeviceManager:current-device:
*
* The device that we have most recently seen a motion event for.
*
* Since: 3.16
*/
g_object_class_install_property (object_class,
PROP_CURRENT_DEVICE,
g_param_spec_object ("current-device",
P_("Current device"),
P_("Most recently used device"),
GDK_TYPE_DEVICE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* GdkDeviceManager::device-added:
* @device_manager: the object on which the signal is emitted
@@ -283,6 +301,9 @@ gdk_device_manager_get_property (GObject *object,
case PROP_DISPLAY:
g_value_set_object (value, GDK_DEVICE_MANAGER (object)->display);
break;
case PROP_CURRENT_DEVICE:
g_value_set_object (value, GDK_DEVICE_MANAGER (object)->current_device);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -356,3 +377,22 @@ gdk_device_manager_get_client_pointer (GdkDeviceManager *device_manager)
return GDK_DEVICE_MANAGER_GET_CLASS (device_manager)->get_client_pointer (device_manager);
}
void
_gdk_device_manager_update_current_device (GdkDeviceManager *device_manager,
GdkDevice *device)
{
if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_SLAVE)
return;
if (device_manager->current_device == device)
return;
if (device_manager->current_device == NULL ||
device == NULL ||
gdk_device_get_motion_time (device) >= gdk_device_get_motion_time (device_manager->current_device))
{
device_manager->current_device = device;
g_object_notify (G_OBJECT (device_manager), "current-device");
}
}

View File

@@ -36,6 +36,7 @@ struct _GdkDeviceManager
/*< private >*/
GdkDisplay *display;
GdkDevice *current_device;
};
struct _GdkDeviceManagerClass
@@ -56,6 +57,10 @@ struct _GdkDeviceManagerClass
GdkDevice * (* get_client_pointer) (GdkDeviceManager *device_manager);
};
void
_gdk_device_manager_update_current_device (GdkDeviceManager *device_manager,
GdkDevice *device);
G_END_DECLS
#endif

View File

@@ -56,6 +56,7 @@ struct _GdkDevice
GList *slaves;
GdkDeviceType type;
GArray *axes;
guint32 time;
};
struct _GdkDeviceClass
@@ -173,6 +174,9 @@ GdkWindow * _gdk_device_window_at_position (GdkDevice *device,
GdkModifierType *mask,
gboolean get_toplevel);
void _gdk_device_set_motion_time (GdkDevice *device,
guint32 time);
G_END_DECLS
#endif /* __GDK_DEVICE_PRIVATE_H__ */

View File

@@ -26,6 +26,7 @@
#include "gdkinternals.h"
#include "gdkdisplayprivate.h"
#include "gdkdeviceprivate.h"
#include <string.h>
#include <math.h>
@@ -1481,6 +1482,7 @@ gdk_event_set_device (GdkEvent *event,
{
case GDK_MOTION_NOTIFY:
event->motion.device = device;
_gdk_device_set_motion_time (device, gdk_event_get_time (event));
break;
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
@@ -1629,6 +1631,8 @@ gdk_event_set_source_device (GdkEvent *event,
private = (GdkEventPrivate *) event;
private->source_device = device;
if (event->type == GDK_MOTION_NOTIFY)
_gdk_device_set_motion_time (device, gdk_event_get_time (event));
}
/**

View File

@@ -748,11 +748,11 @@ pointer_handle_enter (void *data,
device->enter_serial = serial;
event = gdk_event_new (GDK_ENTER_NOTIFY);
event->crossing.time = (guint32)(g_get_monotonic_time () / 1000);
event->crossing.window = g_object_ref (device->pointer_focus);
gdk_event_set_device (event, device->master_pointer);
gdk_event_set_source_device (event, device->pointer);
event->crossing.subwindow = NULL;
event->crossing.time = (guint32)(g_get_monotonic_time () / 1000);
event->crossing.mode = GDK_CROSSING_NORMAL;
event->crossing.detail = GDK_NOTIFY_ANCESTOR;
event->crossing.focus = TRUE;
@@ -794,11 +794,11 @@ pointer_handle_leave (void *data,
_gdk_wayland_display_update_serial (wayland_display, serial);
event = gdk_event_new (GDK_LEAVE_NOTIFY);
event->crossing.time = (guint32)(g_get_monotonic_time () / 1000);
event->crossing.window = g_object_ref (device->pointer_focus);
gdk_event_set_device (event, device->master_pointer);
gdk_event_set_source_device (event, device->pointer);
event->crossing.subwindow = NULL;
event->crossing.time = (guint32)(g_get_monotonic_time () / 1000);
event->crossing.mode = GDK_CROSSING_NORMAL;
event->crossing.detail = GDK_NOTIFY_ANCESTOR;
event->crossing.focus = TRUE;
@@ -846,10 +846,10 @@ pointer_handle_motion (void *data,
device->surface_y = wl_fixed_to_double (sy);
event->motion.type = GDK_MOTION_NOTIFY;
event->motion.time = time;
event->motion.window = g_object_ref (device->pointer_focus);
gdk_event_set_device (event, device->master_pointer);
gdk_event_set_source_device (event, device->pointer);
event->motion.time = time;
event->motion.axes = NULL;
event->motion.state = device->modifiers;
event->motion.is_hint = 0;
@@ -906,10 +906,10 @@ pointer_handle_button (void *data,
device->button_press_serial = serial;
event = gdk_event_new (state ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE);
event->button.time = time;
event->button.window = g_object_ref (device->pointer_focus);
gdk_event_set_device (event, device->master_pointer);
gdk_event_set_source_device (event, device->pointer);
event->button.time = time;
event->button.axes = NULL;
event->button.state = device->modifiers;
event->button.button = gdk_button;
@@ -966,10 +966,10 @@ pointer_handle_axis (void *data,
device->time = time;
event = gdk_event_new (GDK_SCROLL);
event->scroll.time = time;
event->scroll.window = g_object_ref (device->pointer_focus);
gdk_event_set_device (event, device->master_pointer);
gdk_event_set_source_device (event, device->pointer);
event->scroll.time = time;
event->scroll.direction = GDK_SCROLL_SMOOTH;
event->scroll.delta_x = delta_x;
event->scroll.delta_y = delta_y;
@@ -1229,10 +1229,10 @@ deliver_key_event (GdkWaylandDeviceData *device,
device->modifiers = gdk_keymap_get_modifier_state (keymap);
event = gdk_event_new (state ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
event->key.time = time_;
event->key.window = device->keyboard_focus ? g_object_ref (device->keyboard_focus) : NULL;
gdk_event_set_device (event, device->master_keyboard);
gdk_event_set_source_device (event, device->keyboard);
event->key.time = time_;
event->key.state = device->modifiers;
event->key.group = 0;
event->key.hardware_keycode = key;
@@ -1402,10 +1402,10 @@ _create_touch_event (GdkWaylandDeviceData *device,
GdkEvent *event;
event = gdk_event_new (evtype);
event->touch.time = time;
event->touch.window = g_object_ref (touch->window);
gdk_event_set_device (event, device->master_pointer);
gdk_event_set_source_device (event, device->touch);
event->touch.time = time;
event->touch.state = device->modifiers;
gdk_event_set_screen (event, display->screen);
event->touch.sequence = GDK_SLOT_TO_EVENT_SEQUENCE (touch->id);

View File

@@ -595,6 +595,7 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
event->crossing.type = GDK_ENTER_NOTIFY;
event->crossing.window = window;
event->crossing.time = xevent->xcrossing.time;
gdk_event_set_device (event, device_manager->core_pointer);
/* If the subwindow field of the XEvent is non-NULL, then
@@ -605,7 +606,6 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
else
event->crossing.subwindow = NULL;
event->crossing.time = xevent->xcrossing.time;
event->crossing.x = (gdouble) xevent->xcrossing.x / scale;
event->crossing.y = (gdouble) xevent->xcrossing.y / scale;
event->crossing.x_root = (gdouble) xevent->xcrossing.x_root / scale;
@@ -639,6 +639,7 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
event->crossing.type = GDK_LEAVE_NOTIFY;
event->crossing.window = window;
event->crossing.time = xevent->xcrossing.time;
gdk_event_set_device (event, device_manager->core_pointer);
/* If the subwindow field of the XEvent is non-NULL, then
@@ -649,7 +650,6 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
else
event->crossing.subwindow = NULL;
event->crossing.time = xevent->xcrossing.time;
event->crossing.x = (gdouble) xevent->xcrossing.x / scale;
event->crossing.y = (gdouble) xevent->xcrossing.y / scale;
event->crossing.x_root = (gdouble) xevent->xcrossing.x_root / scale;

View File

@@ -3593,6 +3593,7 @@ setup_indicator (GtkScrolledWindow *scrolled_window,
gdk_window_hide (indicator->window);
gtk_widget_set_opacity (scrollbar, 0.0);
indicator->current_pos = 0.0;
indicator->target_pos = 0.5;
}
static void
@@ -3641,17 +3642,20 @@ remove_indicator (GtkScrolledWindow *scrolled_window,
gtk_widget_set_opacity (scrollbar, 1.0);
indicator->current_pos = 1.0;
indicator->target_pos = 0.5;
}
static gboolean
device_manager_has_mouse (GdkDeviceManager *dm)
device_manager_mouse_is_current (GdkDeviceManager *dm)
{
GdkDevice *cp;
GList *slaves, *s;
GdkDevice *device;
gboolean found;
guint32 mouse_time;
guint32 touch_time;
found = FALSE;
mouse_time = 0;
touch_time = 0;
cp = gdk_device_manager_get_client_pointer (dm);
slaves = gdk_device_list_slave_devices (cp);
@@ -3659,24 +3663,25 @@ device_manager_has_mouse (GdkDeviceManager *dm)
{
device = s->data;
if (gdk_device_get_source (device) != GDK_SOURCE_MOUSE)
continue;
if (strstr (gdk_device_get_name (device), "XTEST"))
continue;
if (strstr (gdk_device_get_name (device), "TrackPoint"))
continue;
if (g_object_get_data (G_OBJECT (device), "removed"))
continue;
found = TRUE;
break;
switch (gdk_device_get_source (device))
{
case GDK_SOURCE_MOUSE:
mouse_time = MAX (mouse_time, gdk_device_get_motion_time (device));
break;
case GDK_SOURCE_TOUCHPAD:
case GDK_SOURCE_TOUCHSCREEN:
touch_time = MAX (touch_time, gdk_device_get_motion_time (device));
break;
default:
break;
}
}
g_list_free (slaves);
return found;
return mouse_time > touch_time;
}
static void
@@ -3699,7 +3704,7 @@ gtk_scrolled_window_update_touch_mode (GtkScrolledWindow *scrolled_window)
{
GdkDeviceManager *dm;
dm = gdk_display_get_device_manager (gtk_widget_get_display (GTK_WIDGET (scrolled_window)));
touch_mode = !device_manager_has_mouse (dm);
touch_mode = !device_manager_mouse_is_current (dm);
}
if (priv->touch_mode != touch_mode)
@@ -3741,6 +3746,14 @@ gtk_scrolled_window_device_removed (GdkDeviceManager *dm,
gtk_scrolled_window_update_touch_mode (scrolled_window);
}
static void
gtk_scrolled_window_device_changed (GdkDeviceManager *dm,
GParamSpec *pspec,
GtkScrolledWindow *scrolled_window)
{
gtk_scrolled_window_update_touch_mode (scrolled_window);
}
static void
gtk_scrolled_window_realize (GtkWidget *widget)
{
@@ -3760,6 +3773,8 @@ gtk_scrolled_window_realize (GtkWidget *widget)
G_CALLBACK (gtk_scrolled_window_device_added), scrolled_window);
g_signal_connect (dm, "device-removed",
G_CALLBACK (gtk_scrolled_window_device_removed), scrolled_window);
g_signal_connect (dm, "notify::current-device",
G_CALLBACK (gtk_scrolled_window_device_changed), scrolled_window);
}
static void
@@ -3772,6 +3787,7 @@ gtk_scrolled_window_unrealize (GtkWidget *widget)
dm = gdk_display_get_device_manager (gtk_widget_get_display (widget));
g_signal_handlers_disconnect_by_func (dm, gtk_scrolled_window_device_added, scrolled_window);
g_signal_handlers_disconnect_by_func (dm, gtk_scrolled_window_device_removed, scrolled_window);
g_signal_handlers_disconnect_by_func (dm, gtk_scrolled_window_device_changed, scrolled_window);
gtk_widget_set_parent_window (priv->hscrollbar, NULL);
gtk_widget_unregister_window (widget, priv->hindicator.window);