summaryrefslogtreecommitdiffstats
path: root/src/display/sp-canvas.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/display/sp-canvas.cpp')
-rw-r--r--src/display/sp-canvas.cpp107
1 files changed, 101 insertions, 6 deletions
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index d82e39238..53dd6c62c 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -35,7 +35,7 @@
#include <libnr/nr-matrix-fns.h>
#include <libnr/nr-matrix-ops.h>
#include <libnr/nr-convex-hull.h>
-#include "prefs-utils.h"
+#include "preferences.h"
#include "inkscape.h"
#include "sodipodi-ctrlrect.h"
#if ENABLE_LCMS
@@ -45,6 +45,8 @@
#include "libnr/nr-blit.h"
#include "display/inkscape-cairo.h"
#include "debug/gdk-event-latency-tracker.h"
+#include "desktop.h"
+#include "sp-namedview.h"
using Inkscape::Debug::GdkEventLatencyTracker;
@@ -945,6 +947,10 @@ static void sp_canvas_dirty_rect(SPCanvas* canvas, int nl, int nt, int nr, int n
static void sp_canvas_mark_rect(SPCanvas* canvas, int nl, int nt, int nr, int nb, uint8_t val);
static int do_update (SPCanvas *canvas);
+static gboolean sp_canvas_snap_watchdog_callback(gpointer data);
+static void sp_canvas_snap_watchdog_set(SPCanvas *canvas, GdkEventMotion *event);
+static void sp_canvas_snap_watchdog_kill(SPCanvas *canvas);
+
/**
* Registers the SPCanvas class if necessary, and returns the type ID
* associated to it.
@@ -1042,6 +1048,8 @@ sp_canvas_init (SPCanvas *canvas)
canvas->is_scrolling = false;
+ canvas->watchdog_id = 0;
+ canvas->watchdog_event = NULL;
}
/**
@@ -1106,7 +1114,7 @@ static void track_latency(GdkEvent const *event) {
GdkEventLatencyTracker &tracker = GdkEventLatencyTracker::default_tracker();
boost::optional<double> latency = tracker.process(event);
if (latency && *latency > 2.0) {
- g_warning("Event latency reached %f sec (%1.4f)", *latency, tracker.getSkew());
+ //g_warning("Event latency reached %f sec (%1.4f)", *latency, tracker.getSkew());
}
}
@@ -1157,7 +1165,8 @@ sp_canvas_realize (GtkWidget *widget)
widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
gdk_window_set_user_data (widget->window, widget);
- if ( prefs_get_int_attribute ("options.useextinput", "value", 1) )
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ if ( prefs->getBool("/options/useextinput/value", true) )
gtk_widget_set_events(widget, attributes.event_mask);
widget->style = gtk_style_attach (widget->style, widget->window);
@@ -1574,7 +1583,10 @@ static inline void request_motions(GdkWindow *w, GdkEventMotion *event) {
static int
sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event)
{
- int status;
+ static guint32 prev_time;
+ static boost::optional<Geom::Point> prev_pos;
+
+ int status;
SPCanvas *canvas = SP_CANVAS (widget);
track_latency((GdkEvent *)event);
@@ -1584,7 +1596,52 @@ sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event)
if (canvas->pixmap_gc == NULL) // canvas being deleted
return FALSE;
-
+
+ // Snap when speed drops below e.g. 0.1 px/msec, or when no motion events have occured for 100 msec.
+ // i.e. snap when we're at stand still. The speed threshold enforces snapping for tablets, which will never
+ // be full at stand still and might keep spitting out motion events.
+
+ // When moving at speeds around the speed limit, Inkscape might snap for one motion event but not for the
+ // next, which will make the object that's being dragged jump from the snapped position to the mouse
+ // position and back again. That could be annoying, but I don't see an easy way around this.
+
+ if (event->type == GDK_MOTION_NOTIFY) {
+ Geom::Point event_pos(event->x, event->y);
+ guint32 event_t = gdk_event_get_time ( (GdkEvent *) event );
+
+ sp_canvas_snap_watchdog_kill(canvas);
+ SPDesktop *dt = SP_ACTIVE_DESKTOP;
+
+ if (prev_pos) {
+ Geom::Coord dist = Geom::L2(event_pos - *prev_pos);
+ guint32 delta_t = event_t - prev_time;
+ gdouble speed = delta_t > 0 ? dist/delta_t : 1000;
+ // std::cout << "speed = " << speed << " px/msec " << "| time passed = " << delta_t << " msec" << std::endl;
+ if (speed < 0.1) {
+ if (dt) {
+ dt->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false);
+ }
+ } else {
+ // We're moving fast, so postpone any snapping until the next GDK_MOTION_NOTIFY event.
+ if (dt) {
+ dt->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(true);
+ }
+ // We must snap at some point in time though, so set a watchdog timer at 100 msec from
+ // now, just in case there's no future motion event that's under the speed limit.
+ sp_canvas_snap_watchdog_set(canvas, event);
+ }
+ } else {
+ // This is the first GDK_MOTION_NOTIFY event, so postpone snapping and set the watchdog
+ if (dt) {
+ dt->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(true);
+ }
+ sp_canvas_snap_watchdog_set(canvas, event);
+ }
+
+ prev_pos = event_pos;
+ prev_time = event_t;
+ }
+
canvas->state = event->state;
pick_current_item (canvas, (GdkEvent *) event);
@@ -1597,6 +1654,43 @@ sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event)
return status;
}
+gboolean sp_canvas_snap_watchdog_callback(gpointer data)
+{
+ SPDesktop *dt = SP_ACTIVE_DESKTOP;
+ if (dt) {
+ dt->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false);
+ }
+
+ SPCanvas *canvas = reinterpret_cast<SPCanvas *>(data);
+ emit_event(canvas, canvas->watchdog_event);
+ gdk_event_free(canvas->watchdog_event);
+ canvas->watchdog_event = NULL;
+ canvas->watchdog_id = 0;
+
+ return FALSE;
+}
+
+void sp_canvas_snap_watchdog_set(SPCanvas *canvas, GdkEventMotion *event)
+{
+ g_assert(canvas->watchdog_id == 0);
+ canvas->watchdog_id = g_timeout_add(100, &sp_canvas_snap_watchdog_callback, canvas);
+ g_assert(canvas->watchdog_event == NULL);
+ canvas->watchdog_event = gdk_event_copy( (GdkEvent *) event);
+}
+
+void sp_canvas_snap_watchdog_kill(SPCanvas *canvas)
+{
+ if (canvas->watchdog_id) {
+ g_source_remove(canvas->watchdog_id); // Kill the watchdog
+ canvas->watchdog_id = 0;
+ }
+
+ if (canvas->watchdog_event) {
+ gdk_event_free(canvas->watchdog_event);
+ canvas->watchdog_event = NULL;
+ }
+}
+
static void
sp_canvas_paint_single_buffer (SPCanvas *canvas, int x0, int y0, int x1, int y1, int draw_x1, int draw_y1, int draw_x2, int draw_y2, int sw)
{
@@ -1635,7 +1729,8 @@ sp_canvas_paint_single_buffer (SPCanvas *canvas, int x0, int y0, int x1, int y1,
#if ENABLE_LCMS
cmsHTRANSFORM transf = 0;
- long long int fromDisplay = prefs_get_int_attribute_limited( "options.displayprofile", "from_display", 0, 0, 1 );
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool fromDisplay = prefs->getBool( "/options/displayprofile/from_display");
if ( fromDisplay ) {
transf = Inkscape::colorprofile_get_display_per( canvas->cms_key ? *(canvas->cms_key) : "" );
} else {