index 53dd6c62c50c8f82ca52d755447cacb3278aed5a..fc68bcfc00a3c6ac304033832b183ab925738eab 100644 (file)
-#define __SP_CANVAS_C__
-
/** \file
* Port of GnomeCanvas for Inkscape needs
*
#include <gtkmm.h>
-#include <helper/sp-marshal.h>
+#include "helper/sp-marshal.h"
#include <helper/recthull.h>
-#include <display/sp-canvas.h>
-#include "display-forward.h"
-#include <libnr/nr-matrix-fns.h>
-#include <libnr/nr-matrix-ops.h>
-#include <libnr/nr-convex-hull.h>
+#include "display/sp-canvas.h"
+#include "display/sp-canvas-group.h"
+#include <2geom/matrix.h>
+#include "libnr/nr-convex-hull.h"
#include "preferences.h"
#include "inkscape.h"
#include "sodipodi-ctrlrect.h"
/* SPCanvasItem */
enum {ITEM_EVENT, ITEM_LAST_SIGNAL};
+enum {PROP_0, PROP_VISIBLE};
static void sp_canvas_request_update (SPCanvas *canvas);
static void sp_canvas_item_construct (SPCanvasItem *item, SPCanvasGroup *parent, gchar const *first_arg_name, va_list args);
static int emit_event (SPCanvas *canvas, GdkEvent *event);
+static int pick_current_item (SPCanvas *canvas, GdkEvent *event);
static guint item_signals[ITEM_LAST_SIGNAL] = { 0 };
-static GtkObjectClass *item_parent_class;
-
/**
* Registers the SPCanvasItem class with Glib and returns its type number.
*/
{
GObjectClass *object_class = (GObjectClass *) klass;
- /* fixme: Derive from GObject */
- item_parent_class = (GtkObjectClass*)gtk_type_class (GTK_TYPE_OBJECT);
-
item_signals[ITEM_EVENT] = g_signal_new ("event",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
static void
sp_canvas_item_init (SPCanvasItem *item)
{
+ // TODO items should not be visible on creation - this causes kludges with items
+ // that should be initially invisible; examples of such items: node handles, the CtrlRect
+ // used for rubberbanding, path outline, etc.
item->flags |= SP_CANVAS_ITEM_VISIBLE;
item->xform = Geom::Matrix(Geom::identity());
}
group_remove (SP_CANVAS_GROUP (item->parent), item);
}
- G_OBJECT_CLASS (item_parent_class)->dispose (object);
+ G_OBJECT_CLASS (g_type_class_peek(g_type_parent(sp_canvas_item_get_type())))->dispose (object);
}
/**
item->canvas->need_repick = TRUE;
}
+bool
+sp_canvas_item_is_visible (SPCanvasItem *item)
+{
+ return item->flags & SP_CANVAS_ITEM_VISIBLE;
+}
+
+
/**
* Sets visible flag on item and requests a redraw.
*/
@@ -543,8 +547,13 @@ sp_canvas_item_grab (SPCanvasItem *item, guint event_mask, GdkCursor *cursor, gu
if (item->canvas->grabbed_item)
return -1;
- if (!(item->flags & SP_CANVAS_ITEM_VISIBLE))
- return -1;
+ // This test disallows grabbing events by an invisible item, which may be useful
+ // sometimes. An example is the hidden control point used for the selector component,
+ // where it is used for object selection and rubberbanding. There seems to be nothing
+ // preventing this except this test, so I removed it.
+ // -- Krzysztof KosiĆski, 2009.08.12
+ //if (!(item->flags & SP_CANVAS_ITEM_VISIBLE))
+ // return -1;
if (HAS_BROKEN_MOTION_HINTS) {
event_mask &= ~GDK_POINTER_MOTION_HINT_MASK;
@@ -795,7 +804,7 @@ sp_canvas_group_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned
}
}
- boost::optional<Geom::Rect> const bounds = corners.bounds();
+ Geom::OptRect const bounds = corners.bounds();
if (bounds) {
item->x1 = bounds->min()[Geom::X];
item->y1 = bounds->min()[Geom::Y];
@@ -947,10 +956,6 @@ 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.
// See comment at in sp-canvas.h.
canvas->gen_all_enter_events = false;
+
+ canvas->drawing_disabled = false;
canvas->tiles=NULL;
canvas->tLeft=canvas->tTop=canvas->tRight=canvas->tBottom=0;
#endif // ENABLE_LCMS
canvas->is_scrolling = false;
-
- canvas->watchdog_id = 0;
- canvas->watchdog_event = NULL;
}
/**
}
widget->allocation = *allocation;
-
+
if (GTK_WIDGET_REALIZED (widget)) {
gdk_window_move_resize (widget->window,
widget->allocation.x, widget->allocation.y,
if (!(mask & canvas->grabbed_event_mask)) return FALSE;
}
- /* Convert to world coordinates -- we have two cases because of diferent
+ /* Convert to world coordinates -- we have two cases because of different
* offsets of the fields in the event structures.
*/
if (canvas->grabbed_item && !is_descendant (canvas->current_item, canvas->grabbed_item)) {
item = canvas->grabbed_item;
} else {
+ // Make sure that current_item is up-to-date. If a snap indicator was just deleted, then
+ // sp_canvas_item_dispose has been called and there is no current_item specified. We need
+ // that though because otherwise we don't know where to send this event to, leading to a
+ // lost event. We can't wait for idle events to have current_item updated, we need it now!
+ // Otherwise, scrolling when hovering above a pre-snap indicator won't work (for example)
+ // See this bug report: https://bugs.launchpad.net/inkscape/+bug/522335/comments/8
+ if (canvas->need_repick && !canvas->in_repick && event->type == GDK_SCROLL) {
+ // To avoid side effects, we'll only do this for scroll events, because this is the
+ // only thing we want to fix here. An example of a reported side effect is that
+ // otherwise selection of nodes in the node editor by dragging a rectangle using a
+ // tablet will break
+ canvas->need_repick = FALSE;
+ pick_current_item (canvas, (GdkEvent *) event);
+ }
item = canvas->current_item;
}
retval = emit_event (canvas, &new_event);
}
+
+
return retval;
}
int retval = FALSE;
- /* dispatch normally regardless of the event's window if an item has
+ /* dispatch normally regardless of the event's window if an item
has a pointer grab in effect */
if (!canvas->grabbed_item &&
event->window != SP_CANVAS_WINDOW (canvas))
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
- /* Pick the current item as if the button were not pressed, and
+ /* Pick the current item as if the button were not pressed, and
* then process the event.
*/
canvas->state = event->state;
break;
case GDK_BUTTON_RELEASE:
- /* Process the event as if the button were pressed, then repick
+ /* Process the event as if the button were pressed, then repick
* after the button has been released
*/
canvas->state = event->state;
canvas->state = event->state;
pick_current_item (canvas, (GdkEvent *) event);
event->state ^= mask;
+
break;
default:
static int
sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event)
{
- static guint32 prev_time;
- static boost::optional<Geom::Point> prev_pos;
-
- int status;
+ int status;
SPCanvas *canvas = SP_CANVAS (widget);
track_latency((GdkEvent *)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);
-
status = emit_event (canvas, (GdkEvent *) event);
-
if (event->is_hint) {
request_motions(widget->window, 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)
{
@@ -1706,7 +1640,7 @@ sp_canvas_paint_single_buffer (SPCanvas *canvas, int x0, int y0, int x1, int y1,
// Mark the region clean
sp_canvas_mark_rect(canvas, x0, y0, x1, y1, 0);
- buf.buf_rowstride = sw * 4;
+ buf.buf_rowstride = sw * 4;
buf.rect.x0 = x0;
buf.rect.y0 = y0;
buf.rect.x1 = x1;
@@ -1755,7 +1689,7 @@ sp_canvas_paint_single_buffer (SPCanvas *canvas, int x0, int y0, int x1, int y1,
#if ENABLE_LCMS
if ( transf && canvas->enable_cms_display_adj ) {
for ( gint yy = 0; yy < (y1 - y0); yy++ ) {
- guchar* p = buf.buf + (sw * 3) * yy;
+ guchar* p = buf.buf + (buf.buf_rowstride * yy);
cmsDoTransform( transf, p, p, (x1 - x0) );
}
}
} else {
// paths only, so 1M works faster
// 1M is the cached buffer and we need 4 channels
- setup.max_pixels = 262144;
+ setup.max_pixels = 262144;
}
// Start the clock
static int
do_update (SPCanvas *canvas)
{
- if (!canvas->root || !canvas->pixmap_gc) // canvas may have already be destroyed by closing desktop durring interrupted display!
+ if (!canvas->root || !canvas->pixmap_gc) // canvas may have already be destroyed by closing desktop during interrupted display!
+ return TRUE;
+
+ if (canvas->drawing_disabled)
return TRUE;
/* Cause the update if necessary */
@@ -2257,7 +2194,7 @@ sp_canvas_scroll_to (SPCanvas *canvas, double cx, double cy, unsigned int clear,
int ix = (int) round(cx); // ix and iy are the new canvas coordinates (integer screen pixels)
int iy = (int) round(cy); // cx might be negative, so (int)(cx + 0.5) will not do!
- int dx = ix - canvas->x0; // dx and dy specify the displacement (scroll) of the
+ int dx = ix - canvas->x0; // dx and dy specify the displacement (scroll) of the
int dy = iy - canvas->y0; // canvas w.r.t its previous position
canvas->dx0 = cx; // here the 'd' stands for double, not delta!
@@ -2278,6 +2215,7 @@ sp_canvas_scroll_to (SPCanvas *canvas, double cx, double cy, unsigned int clear,
} else {
// scrolling as part of zoom; do nothing here - the next do_update will perform full redraw
}
+
}
/**
@@ -2512,4 +2450,4 @@ void sp_canvas_mark_rect(SPCanvas* canvas, int nl, int nt, int nr, int nb, uint8
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :