Code

Use subdirectories with icon sizes.
[inkscape.git] / src / widgets / icon.cpp
index 743502d2702365012d3b57919caee5fb8afb990e..70dee457c961b7e03a786c4563902b18ad73bdae 100644 (file)
@@ -5,6 +5,7 @@
  * Author:
  *   Lauris Kaplinski <lauris@kaplinski.com>
  *   Jon A. Cruz <jon@joncruz.org>
+ *   Abhishek Sharma
  *
  * Copyright (C) 2002 Lauris Kaplinski
  *
@@ -19,6 +20,7 @@
 #include <glib/gmem.h>
 #include <gtk/gtk.h>
 #include <gtkmm.h>
+#include <gdkmm/pixbuf.h>
 
 #include "path-prefix.h"
 #include "preferences.h"
@@ -219,7 +221,7 @@ void sp_icon_fetch_pixbuf( SPIcon *icon )
     }
 }
 
-static GdkPixbuf* renderup( gchar const* name, Inkscape::IconSize lsize, unsigned psize ) {
+GdkPixbuf* renderup( gchar const* name, Inkscape::IconSize lsize, unsigned psize ) {
     GtkIconTheme *theme = gtk_icon_theme_get_default();
 
     GdkPixbuf *pb = 0;
@@ -541,8 +543,7 @@ static void setupLegacyNaming() {
     legacyNames["zoom"] ="sticky_zoom";
 }
 
-static GtkWidget *
-sp_icon_new_full( Inkscape::IconSize lsize, gchar const *name )
+static GtkWidget *sp_icon_new_full( Inkscape::IconSize lsize, gchar const *name )
 {
     static bool dump = Inkscape::Preferences::get()->getBool("/debug/icons/dumpGtk");
 
@@ -918,13 +919,13 @@ sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root,
         SPObject *object = doc->getObjectById(name);
         if (object && SP_IS_ITEM(object)) {
             /* Find bbox in document */
-            Geom::Matrix const i2doc(sp_item_i2doc_affine(SP_ITEM(object)));
+            Geom::Matrix const i2doc(SP_ITEM(object)->i2doc_affine());
             Geom::OptRect dbox = SP_ITEM(object)->getBounds(i2doc);
 
             if ( SP_OBJECT_PARENT(object) == NULL )
             {
                 dbox = Geom::Rect(Geom::Point(0, 0),
-                                Geom::Point(sp_document_width(doc), sp_document_height(doc)));
+                                Geom::Point(doc->getWidth(), doc->getHeight()));
             }
 
             /* This is in document coordinates, i.e. pixels */
@@ -1105,18 +1106,37 @@ static guchar *load_svg_pixels(gchar const *name,
         /* Try to load from document. */
         if (!info &&
             Inkscape::IO::file_test( doc_filename, G_FILE_TEST_IS_REGULAR ) &&
-            (doc = sp_document_new( doc_filename, FALSE )) ) {
+            (doc = SPDocument::createNewDoc( doc_filename, FALSE )) ) {
 
             //g_message("Loaded icon file %s", doc_filename);
             // prep the document
-            sp_document_ensure_up_to_date(doc);
+            doc->ensureUpToDate();
             /* Create new arena */
             NRArena *arena = NRArena::create();
             /* Create ArenaItem and set transform */
-            unsigned visionkey = sp_item_display_key_new(1);
+            unsigned visionkey = SPItem::display_key_new(1);
             /* fixme: Memory manage root if needed (Lauris) */
-            root = sp_item_invoke_show( SP_ITEM(SP_DOCUMENT_ROOT(doc)),
-                                        arena, visionkey, SP_ITEM_SHOW_DISPLAY );
+            // This needs to be fixed indeed; this leads to a memory leak of a few megabytes these days
+            // because shapes are being rendered which are not being freed
+            // Valgrind output:
+            /*==7014== 1,548,344 bytes in 599 blocks are possibly lost in loss record 20,361 of 20,362
+            ==7014==    at 0x4A05974: operator new(unsigned long) (vg_replace_malloc.c:220)
+            ==7014==    by 0x4F1015: __gnu_cxx::new_allocator<Shape::point_data>::allocate(unsigned long, void const*) (new_allocator.h:89)
+            ==7014==    by 0x4F02AC: std::_Vector_base<Shape::point_data, std::allocator<Shape::point_data> >::_M_allocate(unsigned long) (stl_vector.h:140)
+            ==7014==    by 0xCF62D7: std::vector<Shape::point_data, std::allocator<Shape::point_data> >::_M_fill_insert(__gnu_cxx::__normal_iterator<Shape::point_data*, std::vector<Shape::point_data, std::allocator<Shape::point_data> > >, unsigned long, Shape::point_data const&) (vector.tcc:414)
+            ==7014==    by 0xCF4D45: std::vector<Shape::point_data, std::allocator<Shape::point_data> >::insert(__gnu_cxx::__normal_iterator<Shape::point_data*, std::vector<Shape::point_data, std::allocator<Shape::point_data> > >, unsigned long, Shape::point_data const&) (stl_vector.h:851)
+            ==7014==    by 0xCF3DCD: std::vector<Shape::point_data, std::allocator<Shape::point_data> >::resize(unsigned long, Shape::point_data) (stl_vector.h:557)
+            ==7014==    by 0xCEA771: Shape::AddPoint(Geom::Point) (Shape.cpp:326)
+            ==7014==    by 0xD0F413: Shape::ConvertToShape(Shape*, fill_typ, bool) (ShapeSweep.cpp:257)
+            ==7014==    by 0x5ECD4F: nr_arena_shape_update_stroke(NRArenaShape*, NRGC*, NRRectL*) (nr-arena-shape.cpp:651)
+            ==7014==    by 0x5EE0DA: nr_arena_shape_render(_cairo*, NRArenaItem*, NRRectL*, NRPixBlock*, unsigned int) (nr-arena-shape.cpp:862)
+            ==7014==    by 0x5E72FB: nr_arena_item_invoke_render(_cairo*, NRArenaItem*, NRRectL const*, NRPixBlock*, unsigned int) (nr-arena-item.cpp:578)
+            ==7014==    by 0x5E9DDE: nr_arena_group_render(_cairo*, NRArenaItem*, NRRectL*, NRPixBlock*, unsigned int) (nr-arena-group.cpp:228)
+            ==7014==    by 0x5E72FB: nr_arena_item_invoke_render(_cairo*, NRArenaItem*, NRRectL const*, NRPixBlock*, unsigned int) (nr-arena-item.cpp:578)
+            ==7014==    by 0x5E9DDE: nr_arena_group_render(_cairo*, NRArenaItem*, NRRectL*, NRPixBlock*, unsigned int) (nr-arena-group.cpp:228)
+            ==7014==    by 0x5E72FB: nr_arena_item_invoke_render(_cairo*, NRArenaItem*, NRRectL const*, NRPixBlock*, unsigned int) (nr-arena-item.cpp:578)
+            */
+            root = SP_ITEM(doc->getRoot())->invoke_show(arena, visionkey, SP_ITEM_SHOW_DISPLAY );
 
             // store into the cache
             info = new svg_doc_cache_t;
@@ -1164,7 +1184,8 @@ void Inkscape::queueIconPrerender( Glib::ustring const &name, Inkscape::IconSize
 {
     GtkStockItem stock;
     gboolean stockFound = gtk_stock_lookup( name.c_str(), &stock );
-    if (!stockFound && !gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), name.c_str()) ) {
+    gboolean themedFound = gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), name.c_str());
+    if (!stockFound && !themedFound ) {
         gint trySize = CLAMP( static_cast<gint>(lsize), 0, static_cast<gint>(G_N_ELEMENTS(iconSizeLookup) - 1) );
         if ( !sizeMapDone ) {
             injectCustomSize();
@@ -1177,11 +1198,25 @@ void Inkscape::queueIconPrerender( Glib::ustring const &name, Inkscape::IconSize
     }
 }
 
+static std::map<unsigned, Glib::ustring> sizePaths;
+
+static std::string getDestDir( unsigned psize )
+{
+    if ( sizePaths.find(psize) == sizePaths.end() ) {
+        gchar *tmp = g_strdup_printf("%dx%d", psize, psize);
+        sizePaths[psize] = tmp;
+        g_free(tmp);
+    }
+
+    return sizePaths[psize];
+}
+
 // returns true if icon needed preloading, false if nothing was done
 bool prerender_icon(gchar const *name, GtkIconSize lsize, unsigned psize)
 {
     bool loadNeeded = false;
     static bool dump = Inkscape::Preferences::get()->getBool("/debug/icons/dumpGtk");
+    static bool useCache = Inkscape::Preferences::get()->getBool("/debug/icons/useCache");
 
     Glib::ustring key = icon_cache_key(name, psize);
     if ( !get_cached_pixbuf(key) ) {
@@ -1190,28 +1225,75 @@ bool prerender_icon(gchar const *name, GtkIconSize lsize, unsigned psize)
             if (dump) {
                 g_message("prerender_icon  [%s] %d:%d", name, lsize, psize);
             }
-            guchar* px = load_svg_pixels(name, lsize, psize);
-            if ( !px ) {
-                // check for a fallback name
-                if ( legacyNames.find(name) != legacyNames.end() ) {
-                    if ( dump ) {
-                        g_message("load_svg_pixels([%s]=%s, %d, %d)", name, legacyNames[name].c_str(), lsize, psize);
+
+            std::string potentialFile;
+            bool dataLoaded = false;
+            if ( useCache ) {
+                // In file encoding:
+                std::string iconCacheDir = Glib::build_filename(Glib::build_filename(Glib::get_user_cache_dir(), "inkscape"), "icons");
+                std::string subpart = getDestDir(psize);
+                if (subpart.empty()) {
+                    g_message("Is empty");
+                }
+                std::string subdir = Glib::build_filename( iconCacheDir, subpart );
+                if ( !Glib::file_test(subdir, Glib::FILE_TEST_EXISTS) ) {
+                    g_message("NEED SUB OF   [%s]", subdir.c_str());
+                    g_mkdir_with_parents( subdir.c_str(), 0x1ED );
+                }
+                potentialFile = Glib::build_filename( subdir, name );
+                potentialFile += ".png";
+
+                if ( Glib::file_test(potentialFile, Glib::FILE_TEST_EXISTS) && Glib::file_test(potentialFile, Glib::FILE_TEST_IS_REGULAR) ) {
+                    Glib::RefPtr<Gdk::Pixbuf> pb = Gdk::Pixbuf::create_from_file(potentialFile);
+                    if (pb) {
+                        dataLoaded = true;
+                        GdkPixbuf *obj = pb->gobj();
+                        g_object_ref(obj);
+                        pb_cache[key] = obj;
+                        addToIconSet(obj, name, lsize, psize);
+                        loadNeeded = true;
+                        if (internalNames.find(name) == internalNames.end()) {
+                            internalNames.insert(name);
+                        }
                     }
-                    px = load_svg_pixels(legacyNames[name].c_str(), lsize, psize);
                 }
             }
-            if (px) {
-                GdkPixbuf* pb = gdk_pixbuf_new_from_data( px, GDK_COLORSPACE_RGB, TRUE, 8,
-                                                          psize, psize, psize * 4,
-                                                          reinterpret_cast<GdkPixbufDestroyNotify>(g_free), NULL );
-                pb_cache[key] = pb;
-                addToIconSet(pb, name, lsize, psize);
-                loadNeeded = true;
-                if (internalNames.find(name) == internalNames.end()) {
-                    internalNames.insert(name);
+
+            if (!dataLoaded) {
+                guchar* px = load_svg_pixels(name, lsize, psize);
+                if ( !px ) {
+                    // check for a fallback name
+                    if ( legacyNames.find(name) != legacyNames.end() ) {
+                        if ( dump ) {
+                            g_message("load_svg_pixels([%s]=%s, %d, %d)", name, legacyNames[name].c_str(), lsize, psize);
+                        }
+                        px = load_svg_pixels(legacyNames[name].c_str(), lsize, psize);
+                    }
+                }
+                if (px) {
+                    GdkPixbuf* pb = gdk_pixbuf_new_from_data( px, GDK_COLORSPACE_RGB, TRUE, 8,
+                                                              psize, psize, psize * 4,
+                                                              reinterpret_cast<GdkPixbufDestroyNotify>(g_free), NULL );
+                    pb_cache[key] = pb;
+                    addToIconSet(pb, name, lsize, psize);
+                    loadNeeded = true;
+                    if (internalNames.find(name) == internalNames.end()) {
+                        internalNames.insert(name);
+                    }
+                    if (useCache) {
+                        g_object_ref(pb);
+                        Glib::RefPtr<Gdk::Pixbuf> ppp = Glib::wrap(pb);
+                        try {
+                            ppp->save( potentialFile, "png" );
+                        } catch ( Glib::FileError &ex ) {
+                            g_warning("FileError    [%s]", ex.what().c_str());
+                        } catch ( Gdk::PixbufError &ex ) {
+                            g_warning("PixbufError  [%s]", ex.what().c_str());
+                        }
+                    }
+                } else if (dump) {
+                    g_message("XXXXXXXXXXXXXXXXXXXXXXXXXXXXX  error!!! pixels not found for '%s'", name);
                 }
-            } else if (dump) {
-                g_message("XXXXXXXXXXXXXXXXXXXXXXXXXXXXX  error!!! pixels not found for '%s'", name);
             }
         }
         else if (dump) {
@@ -1329,7 +1411,9 @@ static void addPreRender( GtkIconSize lsize, gchar const *name )
 }
 
 gboolean icon_prerender_task(gpointer /*data*/) {
-    if (!pendingRenders.empty()) {
+    if ( inkscapeIsCrashing() ) {
+        // stop
+    } else if (!pendingRenders.empty()) {
         bool workDone = false;
         do {
             preRenderItem single = pendingRenders.front();
@@ -1339,7 +1423,7 @@ gboolean icon_prerender_task(gpointer /*data*/) {
         } while (!pendingRenders.empty() && !workDone);
     }
 
-    if (!pendingRenders.empty()) {
+    if (!inkscapeIsCrashing() && !pendingRenders.empty()) {
         return TRUE;
     } else {
         callbackHooked = false;
@@ -1420,4 +1504,4 @@ static void imageMapNamedCB(GtkWidget* widget, gpointer user_data) {
   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 :