From: joncruz Date: Sat, 17 May 2008 22:34:59 +0000 (+0000) Subject: Added external image edit launch and refresh on changed X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=c13deb2864f592ee41c14855ec09dca84e13025f;p=inkscape.git Added external image edit launch and refresh on changed --- diff --git a/src/sp-image.cpp b/src/sp-image.cpp index 6ba348fbe..7a1d3534d 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -27,6 +27,7 @@ //#include #include "display/nr-arena-image.h" #include +#include //Added for preserveAspectRatio support -- EAF #include "enums.h" @@ -77,7 +78,7 @@ static NR::Matrix sp_image_set_transform (SPItem *item, NR::Matrix const &xform) static void sp_image_set_curve(SPImage *image); -GdkPixbuf *sp_image_repr_read_image (const gchar *href, const gchar *absref, const gchar *base); +static GdkPixbuf *sp_image_repr_read_image( time_t& modTime, gchar*& pixPath, const gchar *href, const gchar *absref, const gchar *base ); static GdkPixbuf *sp_image_pixbuf_force_rgba (GdkPixbuf * pixbuf); static void sp_image_update_canvas_image (SPImage *image); static GdkPixbuf * sp_image_repr_read_dataURI (const gchar * uri_data); @@ -246,18 +247,33 @@ void user_flush_data( png_structp /*png_ptr*/ ) //g_message( "user_flush_data" ); } -GdkPixbuf* pixbuf_new_from_file( const char *filename, GError **/*error*/ ) +static GdkPixbuf* pixbuf_new_from_file( const char *filename, time_t &modTime, gchar*& pixPath, GError **/*error*/ ) { GdkPixbuf* buf = NULL; PushPull youme; gint dpiX = 0; gint dpiY = 0; + modTime = 0; + if ( pixPath ) { + g_free(pixPath); + pixPath = 0; + } //buf = gdk_pixbuf_new_from_file( filename, error ); dump_fopen_call( filename, "pixbuf_new_from_file" ); FILE* fp = fopen_utf8name( filename, "r" ); if ( fp ) { + { + struct stat st; + memset(&st, 0, sizeof(st)); + int val = g_stat(filename, &st); + if ( !val ) { + modTime = st.st_mtime; + pixPath = g_strdup(filename); + } + } + GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); if ( loader ) { @@ -507,67 +523,96 @@ GdkPixbuf* pixbuf_new_from_file( const char *filename, GError **/*error*/ ) return buf; } +GdkPixbuf* pixbuf_new_from_file( const char *filename, GError **error ) +{ + time_t modTime = 0; + gchar* pixPath = 0; + GdkPixbuf* result = pixbuf_new_from_file( filename, modTime, pixPath, error ); + if (pixPath) { + g_free(pixPath); + } + return result; +} + + } } GType sp_image_get_type (void) { - static GType image_type = 0; - if (!image_type) { - GTypeInfo image_info = { - sizeof (SPImageClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) sp_image_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (SPImage), - 16, /* n_preallocs */ - (GInstanceInitFunc) sp_image_init, - NULL, /* value_table */ - }; - image_type = g_type_register_static (sp_item_get_type (), "SPImage", &image_info, (GTypeFlags)0); - } - return image_type; + static GType image_type = 0; + if (!image_type) { + GTypeInfo image_info = { + sizeof (SPImageClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) sp_image_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (SPImage), + 16, /* n_preallocs */ + (GInstanceInitFunc) sp_image_init, + NULL, /* value_table */ + }; + image_type = g_type_register_static (sp_item_get_type (), "SPImage", &image_info, (GTypeFlags)0); + } + return image_type; } static void sp_image_class_init (SPImageClass * klass) { - GObjectClass * gobject_class; - SPObjectClass * sp_object_class; - SPItemClass * item_class; - - gobject_class = (GObjectClass *) klass; - sp_object_class = (SPObjectClass *) klass; - item_class = (SPItemClass *) klass; - - parent_class = (SPItemClass*)g_type_class_ref (sp_item_get_type ()); - - sp_object_class->build = sp_image_build; - sp_object_class->release = sp_image_release; - sp_object_class->set = sp_image_set; - sp_object_class->update = sp_image_update; - sp_object_class->write = sp_image_write; - - item_class->bbox = sp_image_bbox; - item_class->print = sp_image_print; - item_class->description = sp_image_description; - item_class->show = sp_image_show; - item_class->snappoints = sp_image_snappoints; - item_class->set_transform = sp_image_set_transform; + GObjectClass * gobject_class; + SPObjectClass * sp_object_class; + SPItemClass * item_class; + + gobject_class = (GObjectClass *) klass; + sp_object_class = (SPObjectClass *) klass; + item_class = (SPItemClass *) klass; + + parent_class = (SPItemClass*)g_type_class_ref (sp_item_get_type ()); + + sp_object_class->build = sp_image_build; + sp_object_class->release = sp_image_release; + sp_object_class->set = sp_image_set; + sp_object_class->update = sp_image_update; + sp_object_class->write = sp_image_write; + + item_class->bbox = sp_image_bbox; + item_class->print = sp_image_print; + item_class->description = sp_image_description; + item_class->show = sp_image_show; + item_class->snappoints = sp_image_snappoints; + item_class->set_transform = sp_image_set_transform; } -static void -sp_image_init (SPImage *image) +static void sp_image_init( SPImage *image ) { - image->x.unset(); - image->y.unset(); - image->width.unset(); - image->height.unset(); - image->aspect_align = SP_ASPECT_NONE; - image->curve = NULL; + image->x.unset(); + image->y.unset(); + image->width.unset(); + image->height.unset(); + image->aspect_align = SP_ASPECT_NONE; + + image->trimx = 0; + image->trimy = 0; + image->trimwidth = 0; + image->trimheight = 0; + image->viewx = 0; + image->viewy = 0; + image->viewwidth = 0; + image->viewheight = 0; + + image->curve = NULL; + + image->href = 0; +#if ENABLE_LCMS + image->color_profile = 0; +#endif // ENABLE_LCMS + image->pixbuf = 0; + image->pixPath = 0; + image->lastMod = 0; } static void @@ -591,38 +636,42 @@ sp_image_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *rep static void sp_image_release (SPObject *object) { - SPImage *image; - - image = SP_IMAGE (object); + SPImage *image = SP_IMAGE(object); - if (SP_OBJECT_DOCUMENT (object)) { - /* Unregister ourselves */ - sp_document_remove_resource (SP_OBJECT_DOCUMENT (object), "image", SP_OBJECT (object)); - } + if (SP_OBJECT_DOCUMENT (object)) { + /* Unregister ourselves */ + sp_document_remove_resource (SP_OBJECT_DOCUMENT (object), "image", SP_OBJECT (object)); + } - if (image->href) { - g_free (image->href); - image->href = NULL; - } + if (image->href) { + g_free (image->href); + image->href = NULL; + } - if (image->pixbuf) { - gdk_pixbuf_unref (image->pixbuf); - image->pixbuf = NULL; - } + if (image->pixbuf) { + gdk_pixbuf_unref (image->pixbuf); + image->pixbuf = NULL; + } #if ENABLE_LCMS - if (image->color_profile) { - g_free (image->color_profile); - image->color_profile = NULL; - } + if (image->color_profile) { + g_free (image->color_profile); + image->color_profile = NULL; + } #endif // ENABLE_LCMS + if (image->pixPath) { + g_free(image->pixPath); + image->pixPath = 0; + } + if (image->curve) { - image->curve = image->curve->unref(); - } + image->curve = image->curve->unref(); + } - if (((SPObjectClass *) parent_class)->release) - ((SPObjectClass *) parent_class)->release (object); + if (((SPObjectClass *) parent_class)->release) { + ((SPObjectClass *) parent_class)->release (object); + } } static void @@ -753,27 +802,32 @@ sp_image_set (SPObject *object, unsigned int key, const gchar *value) static void sp_image_update (SPObject *object, SPCtx *ctx, unsigned int flags) { - SPImage *image; - - image = (SPImage *) object; + SPImage *image = SP_IMAGE(object); SPDocument *doc = SP_OBJECT_DOCUMENT(object); - if (((SPObjectClass *) (parent_class))->update) - ((SPObjectClass *) (parent_class))->update (object, ctx, flags); + if (((SPObjectClass *) (parent_class))->update) + ((SPObjectClass *) (parent_class))->update (object, ctx, flags); - if (flags & SP_IMAGE_HREF_MODIFIED_FLAG) { - if (image->pixbuf) { - gdk_pixbuf_unref (image->pixbuf); - image->pixbuf = NULL; - } - if (image->href) { - GdkPixbuf *pixbuf; - pixbuf = sp_image_repr_read_image ( - object->repr->attribute("xlink:href"), - object->repr->attribute("sodipodi:absref"), - doc->base); - if (pixbuf) { - pixbuf = sp_image_pixbuf_force_rgba (pixbuf); + if (flags & SP_IMAGE_HREF_MODIFIED_FLAG) { + if (image->pixbuf) { + gdk_pixbuf_unref (image->pixbuf); + image->pixbuf = NULL; + } + if ( image->pixPath ) { + g_free(image->pixPath); + image->pixPath = 0; + } + image->lastMod = 0; + if (image->href) { + GdkPixbuf *pixbuf; + pixbuf = sp_image_repr_read_image ( + image->lastMod, + image->pixPath, + object->repr->attribute("xlink:href"), + object->repr->attribute("sodipodi:absref"), + doc->base); + if (pixbuf) { + pixbuf = sp_image_pixbuf_force_rgba (pixbuf); // BLIP #if ENABLE_LCMS if ( image->color_profile ) @@ -1105,12 +1159,16 @@ sp_image_show (SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int * */ -GdkPixbuf * -sp_image_repr_read_image (const gchar *href, const gchar *absref, const gchar *base) +GdkPixbuf *sp_image_repr_read_image( time_t& modTime, char*& pixPath, const gchar *href, const gchar *absref, const gchar *base ) { const gchar *filename, *docbase; gchar *fullname; GdkPixbuf *pixbuf; + modTime = 0; + if ( pixPath ) { + g_free(pixPath); + pixPath = 0; + } filename = href; if (filename != NULL) { @@ -1118,7 +1176,7 @@ sp_image_repr_read_image (const gchar *href, const gchar *absref, const gchar *b fullname = g_filename_from_uri(filename, NULL, NULL); if (fullname) { // TODO check this. Was doing a UTF-8 to filename conversion here. - pixbuf = Inkscape::IO::pixbuf_new_from_file (fullname, NULL); + pixbuf = Inkscape::IO::pixbuf_new_from_file (fullname, modTime, pixPath, NULL); if (pixbuf != NULL) return pixbuf; } } else if (strncmp (filename,"data:",5) == 0) { @@ -1138,7 +1196,7 @@ sp_image_repr_read_image (const gchar *href, const gchar *absref, const gchar *b // different dir) or unset (when doc is not saved yet), so we check for base+href existence first, // and if it fails, we also try to use bare href regardless of its g_path_is_absolute if (g_file_test (fullname, G_FILE_TEST_EXISTS) && !g_file_test (fullname, G_FILE_TEST_IS_DIR)) { - pixbuf = Inkscape::IO::pixbuf_new_from_file( fullname, NULL ); + pixbuf = Inkscape::IO::pixbuf_new_from_file( fullname, modTime, pixPath, NULL ); g_free (fullname); if (pixbuf != NULL) return pixbuf; } @@ -1146,7 +1204,7 @@ sp_image_repr_read_image (const gchar *href, const gchar *absref, const gchar *b /* try filename as absolute */ if (g_file_test (filename, G_FILE_TEST_EXISTS) && !g_file_test (filename, G_FILE_TEST_IS_DIR)) { - pixbuf = Inkscape::IO::pixbuf_new_from_file( filename, NULL ); + pixbuf = Inkscape::IO::pixbuf_new_from_file( filename, modTime, pixPath, NULL ); if (pixbuf != NULL) return pixbuf; } } @@ -1161,7 +1219,7 @@ sp_image_repr_read_image (const gchar *href, const gchar *absref, const gchar *b else g_warning ("xlink:href did not resolve to a valid image file, now trying sodipodi:absref=\"%s\"", absref); - pixbuf = Inkscape::IO::pixbuf_new_from_file( filename, NULL ); + pixbuf = Inkscape::IO::pixbuf_new_from_file( filename, modTime, pixPath, NULL ); if (pixbuf != NULL) return pixbuf; } /* Nope: We do not find any valid pixmap file :-( */ @@ -1487,6 +1545,25 @@ sp_image_get_curve (SPImage *image) return NULL; } +void sp_image_refresh_if_outdated( SPImage* image ) +{ + if ( image->href && image->lastMod ) { + // It *might* change + + struct stat st; + memset(&st, 0, sizeof(st)); + int val = g_stat(image->pixPath, &st); + if ( !val ) { + // stat call worked. Check time now + if ( st.st_mtime != image->lastMod ) { + SPCtx *ctx = 0; + unsigned int flags = SP_IMAGE_HREF_MODIFIED_FLAG; + sp_image_update(image, ctx, flags); + } + } + } +} + /* Local Variables: mode:c++ diff --git a/src/sp-image.h b/src/sp-image.h index 75194174e..7b00e0da3 100644 --- a/src/sp-image.h +++ b/src/sp-image.h @@ -33,30 +33,32 @@ class SPImageClass; #define SP_IMAGE_HREF_MODIFIED_FLAG SP_OBJECT_USER_MODIFIED_FLAG_A struct SPImage : public SPItem { - SVGLength x; - SVGLength y; - SVGLength width; - SVGLength height; - - // Added by EAF - /* preserveAspectRatio */ - unsigned int aspect_align : 4; - unsigned int aspect_clip : 1; - int trimx, trimy, trimwidth, trimheight; - double viewx, viewy, viewwidth, viewheight; - - SPCurve *curve; // This curve is at the image's boundary for snapping - - gchar *href; + SVGLength x; + SVGLength y; + SVGLength width; + SVGLength height; + + // Added by EAF + /* preserveAspectRatio */ + unsigned int aspect_align : 4; + unsigned int aspect_clip : 1; + int trimx, trimy, trimwidth, trimheight; + double viewx, viewy, viewwidth, viewheight; + + SPCurve *curve; // This curve is at the image's boundary for snapping + + gchar *href; #if ENABLE_LCMS - gchar *color_profile; + gchar *color_profile; #endif // ENABLE_LCMS - GdkPixbuf *pixbuf; + GdkPixbuf *pixbuf; + gchar *pixPath; + time_t lastMod; }; struct SPImageClass { - SPItemClass parent_class; + SPItemClass parent_class; }; GType sp_image_get_type (void); @@ -64,5 +66,6 @@ GType sp_image_get_type (void); /* Return duplicate of curve or NULL */ SPCurve *sp_image_get_curve (SPImage *image); +void sp_image_refresh_if_outdated( SPImage* image ); #endif diff --git a/src/ui/context-menu.cpp b/src/ui/context-menu.cpp index bb18d7422..442eb5ef6 100644 --- a/src/ui/context-menu.cpp +++ b/src/ui/context-menu.cpp @@ -17,6 +17,7 @@ #include "../xml/repr.h" #include "desktop.h" #include "document.h" +#include "message-stack.h" #include "ui/dialog/dialog-manager.h" static void sp_object_type_menu(GType type, SPObject *object, SPDesktop *desktop, GtkMenu *menu); @@ -280,21 +281,31 @@ sp_anchor_link_remove(GtkMenuItem */*menuitem*/, SPAnchor *anchor) /* Image */ static void sp_image_image_properties(GtkMenuItem *menuitem, SPAnchor *anchor); +static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor); static void sp_image_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m) { - SPItem *item; + SPItem *item = SP_ITEM(object); GtkWidget *w; - item = (SPItem *) object; - /* Link dialog */ w = gtk_menu_item_new_with_mnemonic(_("Image _Properties")); gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop); gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_image_image_properties), item); gtk_widget_show(w); gtk_menu_append(GTK_MENU(m), w); + + w = gtk_menu_item_new_with_mnemonic(_("Edit Image...")); + gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop); + gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_image_image_edit), item); + gtk_widget_show(w); + gtk_menu_append(GTK_MENU(m), w); + Inkscape::XML::Node *ir = SP_OBJECT_REPR(object); + const gchar *href = ir->attribute("xlink:href"); + if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) { + gtk_widget_set_sensitive( w, FALSE ); + } } static void @@ -303,6 +314,33 @@ sp_image_image_properties(GtkMenuItem */*menuitem*/, SPAnchor *anchor) sp_object_attributes_dialog(SP_OBJECT(anchor), "Image"); } +#define EDIT_APP "gimp" +//#define EDIT_APP "krita" +static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor) +{ + SPObject* obj = SP_OBJECT(anchor); + Inkscape::XML::Node *ir = SP_OBJECT_REPR(obj); + const gchar *href = ir->attribute("xlink:href"); + + GError* errThing = 0; + gchar const* args[] = {EDIT_APP, href, 0}; + g_spawn_async(0, // working dir + const_cast(args), + 0, //envp + G_SPAWN_SEARCH_PATH, + 0, // child_setup + 0, // user_data + 0, //GPid *child_pid + &errThing); + if ( errThing ) { + g_warning("Problem launching editor (%d). %s", errThing->code, errThing->message); + SPDesktop *desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop"); + desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, errThing->message); + g_error_free(errThing); + errThing = 0; + } +} + /* SPShape */ static void diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index df35f07f7..3fd0e529e 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -60,6 +60,7 @@ #include "color-profile-fns.h" #include "xml/node-observer.h" #include "box3d-context.h" +#include "sp-image.h" #if defined (SOLARIS_2_8) #include "round.h" @@ -440,7 +441,7 @@ sp_desktop_widget_init (SPDesktopWidget *dtw) style = gtk_style_copy (GTK_WIDGET (dtw->canvas)->style); style->bg[GTK_STATE_NORMAL] = style->white; gtk_widget_set_style (GTK_WIDGET (dtw->canvas), style); - if ( prefs_get_int_attribute ("options.useextinput", "value", 1) ) + if ( prefs_get_int_attribute ("options.useextinput", "value", 1) ) gtk_widget_set_extension_events(GTK_WIDGET (dtw->canvas) , GDK_EXTENSION_EVENTS_ALL); //set extension events for tablets, unless disabled in preferences g_signal_connect (G_OBJECT (dtw->canvas), "event", G_CALLBACK (sp_desktop_widget_event), dtw); gtk_table_attach (GTK_TABLE (canvas_tbl), GTK_WIDGET(dtw->canvas), 1, 2, 1, 2, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), 0, 0); @@ -1372,11 +1373,11 @@ sp_desktop_widget_update_hruler (SPDesktopWidget *dtw) { /* The viewbox (in integers) must exactly match the size of SPCanvasbuf's pixel buffer. * This is important because the former is being used for drawing the ruler, whereas - * the latter is used for drawing e.g. the grids and guides. Only when the viewbox + * the latter is used for drawing e.g. the grids and guides. Only when the viewbox * coincides with the pixel buffer, everything will line up nicely. - */ + */ NR::IRect viewbox = dtw->canvas->getViewboxIntegers(); - + double const scale = dtw->desktop->current_zoom(); double s = viewbox.min()[NR::X] / scale - dtw->ruler_origin[NR::X]; double e = viewbox.max()[NR::X] / scale - dtw->ruler_origin[NR::X]; @@ -1388,11 +1389,11 @@ sp_desktop_widget_update_vruler (SPDesktopWidget *dtw) { /* The viewbox (in integers) must exactly match the size of SPCanvasbuf's pixel buffer. * This is important because the former is being used for drawing the ruler, whereas - * the latter is used for drawing e.g. the grids and guides. Only when the viewbox + * the latter is used for drawing e.g. the grids and guides. Only when the viewbox * coincides with the pixel buffer, everything will line up nicely. */ NR::IRect viewbox = dtw->canvas->getViewboxIntegers(); - + double const scale = dtw->desktop->current_zoom(); double s = viewbox.min()[NR::Y] / -scale - dtw->ruler_origin[NR::Y]; double e = viewbox.max()[NR::Y] / -scale - dtw->ruler_origin[NR::Y]; @@ -1430,7 +1431,7 @@ sp_desktop_widget_adjustment_value_changed (GtkAdjustment */*adj*/, SPDesktopWid sp_desktop_widget_update_rulers (dtw); /* update perspective lines if we are in the 3D box tool (so that infinite ones are shown correctly) */ - sp_box3d_context_update_lines(dtw->desktop->event_context); + sp_box3d_context_update_lines(dtw->desktop->event_context); dtw->update = 0; } @@ -1438,6 +1439,14 @@ sp_desktop_widget_adjustment_value_changed (GtkAdjustment */*adj*/, SPDesktopWid /* we make the desktop window with focus active, signal is connected in interface.c */ bool SPDesktopWidget::onFocusInEvent(GdkEventFocus*) { + { + GSList const *imageList = sp_document_get_resource_list(desktop->doc(), "image"); + for (GSList const *p = imageList; p; p = p->next) { + SPImage* image = SP_IMAGE(p->data); + sp_image_refresh_if_outdated( image ); + } + } + inkscape_activate_desktop (desktop); return false;