X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fdisplay%2Fsp-canvas.cpp;h=fc68bcfc00a3c6ac304033832b183ab925738eab;hb=0dc33d4ce43e0bb49c63aa53b826ec4a1ff68e28;hp=592085bcd9ccb0f69f1eccc8851586c7b32bd135;hpb=1d55f93a54a61c40523eaa9e1d55fc836ac880f9;p=inkscape.git diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 592085bcd..fc68bcfc0 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -1,5 +1,3 @@ -#define __SP_CANVAS_C__ - /** \file * Port of GnomeCanvas for Inkscape needs * @@ -28,13 +26,13 @@ #include -#include -#include -#include "display-forward.h" -#include -#include -#include -#include "prefs-utils.h" +#include "helper/sp-marshal.h" +#include +#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" #if ENABLE_LCMS @@ -44,6 +42,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; @@ -101,6 +101,7 @@ static void group_remove (SPCanvasGroup *group, SPCanvasItem *item); /* SPCanvasItem */ enum {ITEM_EVENT, ITEM_LAST_SIGNAL}; +enum {PROP_0, PROP_VISIBLE}; static void sp_canvas_request_update (SPCanvas *canvas); @@ -112,11 +113,10 @@ static void sp_canvas_item_dispose (GObject *object); 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. */ @@ -149,9 +149,6 @@ sp_canvas_item_class_init (SPCanvasItemClass *klass) { 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, @@ -170,8 +167,11 @@ sp_canvas_item_class_init (SPCanvasItemClass *klass) 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 = NR::Matrix(NR::identity()); + item->xform = Geom::Matrix(Geom::identity()); } /** @@ -246,7 +246,7 @@ sp_canvas_item_dispose (GObject *object) // this redraws only the stroke of the rect to be deleted, // avoiding redraw of the entire area if (SP_IS_CTRLRECT(item)) { - SP_CTRLRECT(object)->setRectangle(NR::Rect(NR::Point(0,0),NR::Point(0,0))); + SP_CTRLRECT(object)->setRectangle(Geom::Rect(Geom::Point(0,0),Geom::Point(0,0))); SP_CTRLRECT(object)->update(item->xform, 0); } else { redraw_if_visible (item); @@ -275,7 +275,7 @@ sp_canvas_item_dispose (GObject *object) 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); } /** @@ -284,10 +284,10 @@ sp_canvas_item_dispose (GObject *object) * NB! affine is parent2canvas. */ static void -sp_canvas_item_invoke_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags) +sp_canvas_item_invoke_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags) { /* Apply the child item's transform */ - NR::Matrix child_affine = item->xform * affine; + Geom::Matrix child_affine = item->xform * affine; /* apply object flags to child flags */ int child_flags = flags & ~SP_CANVAS_UPDATE_REQUESTED; @@ -315,7 +315,7 @@ sp_canvas_item_invoke_update (SPCanvasItem *item, NR::Matrix const &affine, unsi * maintaining the affine invariant. */ static double -sp_canvas_item_invoke_point (SPCanvasItem *item, NR::Point p, SPCanvasItem **actual_item) +sp_canvas_item_invoke_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item) { if (SP_CANVAS_ITEM_GET_CLASS (item)->point) return SP_CANVAS_ITEM_GET_CLASS (item)->point (item, p, actual_item); @@ -331,7 +331,7 @@ sp_canvas_item_invoke_point (SPCanvasItem *item, NR::Point p, SPCanvasItem **act * @affine: An affine transformation matrix. */ void -sp_canvas_item_affine_absolute (SPCanvasItem *item, NR::Matrix const &affine) +sp_canvas_item_affine_absolute (SPCanvasItem *item, Geom::Matrix const &affine) { item->xform = affine; @@ -475,6 +475,13 @@ sp_canvas_item_lower (SPCanvasItem *item, int positions) 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. */ @@ -540,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; @@ -586,11 +598,11 @@ sp_canvas_item_ungrab (SPCanvasItem *item, guint32 etime) * Returns the product of all transformation matrices from the root item down * to the item. */ -NR::Matrix sp_canvas_item_i2w_affine(SPCanvasItem const *item) +Geom::Matrix sp_canvas_item_i2w_affine(SPCanvasItem const *item) { g_assert (SP_IS_CANVAS_ITEM (item)); // should we get this? - NR::Matrix affine = NR::identity(); + Geom::Matrix affine = Geom::identity(); while (item) { affine *= item->xform; @@ -685,8 +697,8 @@ static void sp_canvas_group_class_init (SPCanvasGroupClass *klass); static void sp_canvas_group_init (SPCanvasGroup *group); static void sp_canvas_group_destroy (GtkObject *object); -static void sp_canvas_group_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags); -static double sp_canvas_group_point (SPCanvasItem *item, NR::Point p, SPCanvasItem **actual_item); +static void sp_canvas_group_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags); +static double sp_canvas_group_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); static void sp_canvas_group_render (SPCanvasItem *item, SPCanvasBuf *buf); static SPCanvasItemClass *group_parent_class; @@ -770,10 +782,10 @@ sp_canvas_group_destroy (GtkObject *object) * Update handler for canvas groups */ static void -sp_canvas_group_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags) +sp_canvas_group_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags) { SPCanvasGroup const *group = SP_CANVAS_GROUP (item); - NR::ConvexHull corners(NR::Point(0, 0)); + Geom::RectHull corners(Geom::Point(0, 0)); bool empty=true; for (GList *list = group->items; list; list = list->next) { @@ -783,21 +795,21 @@ sp_canvas_group_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned i if ( i->x2 > i->x1 && i->y2 > i->y1 ) { if (empty) { - corners = NR::ConvexHull(NR::Point(i->x1, i->y1)); + corners = Geom::RectHull(Geom::Point(i->x1, i->y1)); empty = false; } else { - corners.add(NR::Point(i->x1, i->y1)); + corners.add(Geom::Point(i->x1, i->y1)); } - corners.add(NR::Point(i->x2, i->y2)); + corners.add(Geom::Point(i->x2, i->y2)); } } - NR::Maybe const bounds = corners.bounds(); + Geom::OptRect const bounds = corners.bounds(); if (bounds) { - item->x1 = bounds->min()[NR::X]; - item->y1 = bounds->min()[NR::Y]; - item->x2 = bounds->max()[NR::X]; - item->y2 = bounds->max()[NR::Y]; + item->x1 = bounds->min()[Geom::X]; + item->y1 = bounds->min()[Geom::Y]; + item->x2 = bounds->max()[Geom::X]; + item->y2 = bounds->max()[Geom::Y]; } else { // FIXME ? item->x1 = item->x2 = item->y1 = item->y2 = 0; @@ -808,11 +820,11 @@ sp_canvas_group_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned i * Point handler for canvas groups. */ static double -sp_canvas_group_point (SPCanvasItem *item, NR::Point p, SPCanvasItem **actual_item) +sp_canvas_group_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item) { SPCanvasGroup const *group = SP_CANVAS_GROUP (item); - double const x = p[NR::X]; - double const y = p[NR::Y]; + double const x = p[Geom::X]; + double const y = p[Geom::Y]; int x1 = (int)(x - item->canvas->close_enough); int y1 = (int)(y - item->canvas->close_enough); int x2 = (int)(x + item->canvas->close_enough); @@ -1026,6 +1038,8 @@ sp_canvas_init (SPCanvas *canvas) // 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; @@ -1040,7 +1054,6 @@ sp_canvas_init (SPCanvas *canvas) #endif // ENABLE_LCMS canvas->is_scrolling = false; - } /** @@ -1105,7 +1118,7 @@ static void track_latency(GdkEvent const *event) { GdkEventLatencyTracker &tracker = GdkEventLatencyTracker::default_tracker(); boost::optional 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()); } } @@ -1156,7 +1169,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); @@ -1225,7 +1239,7 @@ sp_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation) } widget->allocation = *allocation; - + if (GTK_WIDGET_REALIZED (widget)) { gdk_window_move_resize (widget->window, widget->allocation.x, widget->allocation.y, @@ -1278,7 +1292,7 @@ emit_event (SPCanvas *canvas, GdkEvent *event) 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. */ @@ -1312,6 +1326,20 @@ emit_event (SPCanvas *canvas, GdkEvent *event) 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; } @@ -1421,7 +1449,7 @@ pick_current_item (SPCanvas *canvas, GdkEvent *event) /* find the closest item */ if (canvas->root->flags & SP_CANVAS_ITEM_VISIBLE) { - sp_canvas_item_invoke_point (canvas->root, NR::Point(x, y), &canvas->new_current_item); + sp_canvas_item_invoke_point (canvas->root, Geom::Point(x, y), &canvas->new_current_item); } else { canvas->new_current_item = NULL; } @@ -1477,6 +1505,8 @@ pick_current_item (SPCanvas *canvas, GdkEvent *event) retval = emit_event (canvas, &new_event); } + + return retval; } @@ -1490,7 +1520,7 @@ sp_canvas_button (GtkWidget *widget, GdkEventButton *event) 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)) @@ -1521,7 +1551,7 @@ sp_canvas_button (GtkWidget *widget, GdkEventButton *event) 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; @@ -1531,7 +1561,7 @@ sp_canvas_button (GtkWidget *widget, GdkEventButton *event) 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; @@ -1540,6 +1570,7 @@ sp_canvas_button (GtkWidget *widget, GdkEventButton *event) canvas->state = event->state; pick_current_item (canvas, (GdkEvent *) event); event->state ^= mask; + break; default: @@ -1586,9 +1617,7 @@ sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event) 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); } @@ -1611,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; @@ -1634,7 +1663,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 { @@ -1659,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) ); } } @@ -1734,7 +1764,7 @@ struct PaintRectSetup { NRRectL big_rect; GTimeVal start_time; int max_pixels; - NR::Point mouse_loc; + Geom::Point mouse_loc; }; /** @@ -1821,7 +1851,7 @@ The default for now is the strips mode. lo.x1 = mid; hi.x0 = mid; - if (setup->mouse_loc[NR::X] < mid) { + if (setup->mouse_loc[Geom::X] < mid) { // Always paint towards the mouse first return sp_canvas_paint_rect_internal(setup, lo) && sp_canvas_paint_rect_internal(setup, hi); @@ -1838,7 +1868,7 @@ The default for now is the strips mode. lo.y1 = mid; hi.y0 = mid; - if (setup->mouse_loc[NR::Y] < mid) { + if (setup->mouse_loc[Geom::Y] < mid) { // Always paint towards the mouse first return sp_canvas_paint_rect_internal(setup, lo) && sp_canvas_paint_rect_internal(setup, hi); @@ -1890,7 +1920,7 @@ sp_canvas_paint_rect (SPCanvas *canvas, int xx0, int yy0, int xx1, int yy1) // Save the mouse location gint x, y; gdk_window_get_pointer (GTK_WIDGET(canvas)->window, &x, &y, NULL); - setup.mouse_loc = sp_canvas_window_to_world (canvas, NR::Point(x,y)); + setup.mouse_loc = sp_canvas_window_to_world (canvas, Geom::Point(x,y)); if (canvas->rendermode != Inkscape::RENDERMODE_OUTLINE) { // use 256K as a compromise to not slow down gradients @@ -1899,7 +1929,7 @@ sp_canvas_paint_rect (SPCanvas *canvas, int xx0, int yy0, int xx1, int yy1) } 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 @@ -2029,7 +2059,7 @@ static int paint (SPCanvas *canvas) { if (canvas->need_update) { - sp_canvas_item_invoke_update (canvas->root, NR::identity(), 0); + sp_canvas_item_invoke_update (canvas->root, Geom::identity(), 0); canvas->need_update = FALSE; } @@ -2081,12 +2111,15 @@ paint (SPCanvas *canvas) 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 */ if (canvas->need_update) { - sp_canvas_item_invoke_update (canvas->root, NR::identity(), 0); + sp_canvas_item_invoke_update (canvas->root, Geom::identity(), 0); canvas->need_update = FALSE; } @@ -2161,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! @@ -2182,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 } + } /** @@ -2269,50 +2303,48 @@ void sp_canvas_world_to_window(SPCanvas const *canvas, double worldx, double wor /** * Converts point from win to world coordinates. */ -NR::Point sp_canvas_window_to_world(SPCanvas const *canvas, NR::Point const win) +Geom::Point sp_canvas_window_to_world(SPCanvas const *canvas, Geom::Point const win) { g_assert (canvas != NULL); g_assert (SP_IS_CANVAS (canvas)); - return NR::Point(canvas->x0 + win[0], canvas->y0 + win[1]); + return Geom::Point(canvas->x0 + win[0], canvas->y0 + win[1]); } /** * Converts point from world to win coordinates. */ -NR::Point sp_canvas_world_to_window(SPCanvas const *canvas, NR::Point const world) +Geom::Point sp_canvas_world_to_window(SPCanvas const *canvas, Geom::Point const world) { g_assert (canvas != NULL); g_assert (SP_IS_CANVAS (canvas)); - return NR::Point(world[0] - canvas->x0, world[1] - canvas->y0); + return Geom::Point(world[0] - canvas->x0, world[1] - canvas->y0); } /** * Returns true if point given in world coordinates is inside window. */ -bool sp_canvas_world_pt_inside_window(SPCanvas const *canvas, NR::Point const &world) +bool sp_canvas_world_pt_inside_window(SPCanvas const *canvas, Geom::Point const &world) { g_assert( canvas != NULL ); g_assert(SP_IS_CANVAS(canvas)); - using NR::X; - using NR::Y; GtkWidget const &w = *GTK_WIDGET(canvas); - return ( ( canvas->x0 <= world[X] ) && - ( canvas->y0 <= world[Y] ) && - ( world[X] < canvas->x0 + w.allocation.width ) && - ( world[Y] < canvas->y0 + w.allocation.height ) ); + return ( ( canvas->x0 <= world[Geom::X] ) && + ( canvas->y0 <= world[Geom::Y] ) && + ( world[Geom::X] < canvas->x0 + w.allocation.width ) && + ( world[Geom::Y] < canvas->y0 + w.allocation.height ) ); } /** - * Return canvas window coordinates as NR::Rect. + * Return canvas window coordinates as Geom::Rect. */ -NR::Rect SPCanvas::getViewbox() const +Geom::Rect SPCanvas::getViewbox() const { GtkWidget const *w = GTK_WIDGET(this); - return NR::Rect(NR::Point(dx0, dy0), - NR::Point(dx0 + w->allocation.width, dy0 + w->allocation.height)); + return Geom::Rect(Geom::Point(dx0, dy0), + Geom::Point(dx0 + w->allocation.width, dy0 + w->allocation.height)); } /** @@ -2418,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 :