Code

NR::Maybe => boost::optional
[inkscape.git] / src / display / sp-canvas.cpp
index 4ac8df5a29ada09c0c1ee6a101c71bb0bbbbed09..a558774c451dd35933405a22f40da46d439e5cea 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <gtk/gtkmain.h>
 #include <gtk/gtksignal.h>
+#include <gtk/gtkversion.h>
 
 #include <gtkmm.h>
 
 #include "display/rendermode.h"
 #include "libnr/nr-blit.h"
 #include "display/inkscape-cairo.h"
+#include "debug/gdk-event-latency-tracker.h"
+
+using Inkscape::Debug::GdkEventLatencyTracker;
+
+// GTK_CHECK_VERSION returns false on failure
+#define HAS_GDK_EVENT_REQUEST_MOTIONS GTK_CHECK_VERSION(2, 12, 0)
+
+// gtk_check_version returns non-NULL on failure
+static bool const HAS_BROKEN_MOTION_HINTS =
+  true || gtk_check_version(2, 12, 0) != NULL || !HAS_GDK_EVENT_REQUEST_MOTIONS;
 
 // Define this to visualize the regions to be redrawn
 //#define DEBUG_REDRAW 1;
@@ -94,6 +105,7 @@ enum {ITEM_EVENT, ITEM_LAST_SIGNAL};
 
 static void sp_canvas_request_update (SPCanvas *canvas);
 
+static void track_latency(GdkEvent const *event);
 static void sp_canvas_item_class_init (SPCanvasItemClass *klass);
 static void sp_canvas_item_init (SPCanvasItem *item);
 static void sp_canvas_item_dispose (GObject *object);
@@ -531,6 +543,10 @@ sp_canvas_item_grab (SPCanvasItem *item, guint event_mask, GdkCursor *cursor, gu
     if (!(item->flags & SP_CANVAS_ITEM_VISIBLE))
         return -1;
 
+    if (HAS_BROKEN_MOTION_HINTS) {
+        event_mask &= ~GDK_POINTER_MOTION_HINT_MASK;
+    }
+
     /* fixme: Top hack (Lauris) */
     /* fixme: If we add key masks to event mask, Gdk will abort (Lauris) */
     /* fixme: But Canvas actualle does get key events, so all we need is routing these here */
@@ -776,7 +792,7 @@ sp_canvas_group_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned i
         }
     }
 
-    NR::Maybe<NR::Rect> const bounds = corners.bounds();
+    boost::optional<NR::Rect> const bounds = corners.bounds();
     if (bounds) {
         item->x1 = bounds->min()[NR::X];
         item->y1 = bounds->min()[NR::Y];
@@ -1085,6 +1101,14 @@ sp_canvas_destroy (GtkObject *object)
         (* GTK_OBJECT_CLASS (canvas_parent_class)->destroy) (object);
 }
 
+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());
+    }
+}
+
 /**
  * Returns new canvas as widget.
  */
@@ -1118,6 +1142,8 @@ sp_canvas_realize (GtkWidget *widget)
                              GDK_BUTTON_PRESS_MASK |
                              GDK_BUTTON_RELEASE_MASK |
                              GDK_POINTER_MOTION_MASK |
+                             ( HAS_BROKEN_MOTION_HINTS ?
+                               0 : GDK_POINTER_MOTION_HINT_MASK ) |
                              GDK_PROXIMITY_IN_MASK |
                              GDK_PROXIMITY_OUT_MASK |
                              GDK_KEY_PRESS_MASK |
@@ -1534,31 +1560,40 @@ sp_canvas_scroll (GtkWidget *widget, GdkEventScroll *event)
     return emit_event (SP_CANVAS (widget), (GdkEvent *) event);
 }
 
+static inline void request_motions(GdkWindow *w, GdkEventMotion *event) {
+    gdk_window_get_pointer(w, NULL, NULL, NULL);
+#if HAS_GDK_EVENT_REQUEST_MOTIONS
+    gdk_event_request_motions(event);
+#endif
+}
+
 /**
  * Motion event handler for the canvas.
  */
 static int
 sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event)
 {
+    int status;
     SPCanvas *canvas = SP_CANVAS (widget);
 
+    track_latency((GdkEvent *)event);
+
     if (event->window != SP_CANVAS_WINDOW (canvas))
         return FALSE;
 
     if (canvas->pixmap_gc == NULL) // canvas being deleted
         return FALSE;
 
-    if (canvas->grabbed_event_mask & GDK_POINTER_MOTION_HINT_MASK) {
-        gint x, y;
-        gdk_window_get_pointer (widget->window, &x, &y, NULL);
-        event->x = x;
-        event->y = y;
-    }
-
     canvas->state = event->state;
     pick_current_item (canvas, (GdkEvent *) event);
 
-    return emit_event (canvas, (GdkEvent *) event);
+    status = emit_event (canvas, (GdkEvent *) event);
+
+    if (event->is_hint) {
+        request_motions(widget->window, event);
+    }
+
+    return status;
 }
 
 static void
@@ -1641,18 +1676,18 @@ sp_canvas_paint_single_buffer (SPCanvas *canvas, int x0, int y0, int x1, int y1,
 
 #ifdef CANVAS_OUTPUT_VIA_CAIRO
 
-    buf.cst = cairo_image_surface_create_for_data (
-        buf.buf,
-        CAIRO_FORMAT_ARGB32,  // unpacked, i.e. 32 bits! one byte is unused
-        x1 - x0, y1 - y0,
-        buf.buf_rowstride
-        );
-    cairo_t *window_ct = gdk_cairo_create(SP_CANVAS_WINDOW (canvas));
-    cairo_set_source_surface (window_ct, buf.cst, x0 - canvas->x0, y0 - canvas->y0);
-    cairo_paint (window_ct);
-    cairo_destroy (window_ct);
-    cairo_surface_finish (buf.cst);
-    cairo_surface_destroy (buf.cst);
+        buf.cst = cairo_image_surface_create_for_data (
+            buf.buf,
+            CAIRO_FORMAT_ARGB32,  // unpacked, i.e. 32 bits! one byte is unused
+            x1 - x0, y1 - y0,
+            buf.buf_rowstride
+            );
+        cairo_t *window_ct = gdk_cairo_create(SP_CANVAS_WINDOW (canvas));
+        cairo_set_source_surface (window_ct, buf.cst, x0 - canvas->x0, y0 - canvas->y0);
+        cairo_paint (window_ct);
+        cairo_destroy (window_ct);
+        cairo_surface_finish (buf.cst);
+        cairo_surface_destroy (buf.cst);
 
 #else
 
@@ -1661,9 +1696,9 @@ sp_canvas_paint_single_buffer (SPCanvas *canvas, int x0, int y0, int x1, int y1,
 
         NRPixBlock b4;
         nr_pixblock_setup_extern (&b4, NR_PIXBLOCK_MODE_R8G8B8A8P, x0, y0, x1, y1,
-                                      buf.buf,
-                                      buf.buf_rowstride,
-                                      FALSE, FALSE);
+                                  buf.buf,
+                                  buf.buf_rowstride,
+                                  FALSE, FALSE);
 
         // this does the 32->24 squishing, using an assembler routine:
         nr_blit_pixblock_pixblock (&b3, &b4);
@@ -1673,15 +1708,13 @@ sp_canvas_paint_single_buffer (SPCanvas *canvas, int x0, int y0, int x1, int y1,
                                       x0 - canvas->x0, y0 - canvas->y0,
                                       x1 - x0, y1 - y0,
                                       GDK_RGB_DITHER_MAX,
-                                      b3.data.px,
+                                      NR_PIXBLOCK_PX(&b3),
                                       sw * 3,
                                       x0 - canvas->x0, y0 - canvas->y0);
 
         nr_pixblock_release (&b3);
         nr_pixblock_release (&b4);
-
 #endif
-
     }
 
     cairo_surface_t *cst = cairo_get_target(buf.ct);