2 * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
3 * Copyright(C) 2019 the Claws Mail Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write tothe Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include "claws-features.h"
23 #include "common/utils.h"
25 #include "container_linux.h"
29 static GdkPixbuf *lh_get_image(const litehtml::tchar_t* url)
32 GdkPixbuf *pixbuf = NULL;
33 http* http_loader = NULL;
35 if (!lh_prefs_get()->enable_remote_content) {
36 debug_print("blocking download of image from '%s'\n", url);
40 debug_print("allowing download of image from '%s'\n", url);
42 http_loader = new http();
43 GInputStream *image = http_loader->load_url(url, &error);
45 if (error || !image) {
47 g_warning("lh_get_image: Could not create pixbuf %s",
49 g_clear_error(&error);
54 pixbuf = gdk_pixbuf_new_from_stream(image, NULL, &error);
56 g_warning("lh_get_image: Could not create pixbuf %s",
59 g_clear_error(&error);
71 container_linux *container;
75 static void get_image_threaded(GTask *task, gpointer source, gpointer task_data, GCancellable *cancellable)
77 struct FetchCtx *ctx = (struct FetchCtx *)task_data;
78 GdkPixbuf *pixbuf = lh_get_image(ctx->url);
80 g_task_return_pointer(task, pixbuf, NULL);
83 static void get_image_callback(GObject *source, GAsyncResult *res, gpointer user_data)
86 struct FetchCtx *ctx = (struct FetchCtx *)user_data;
88 pixbuf = GDK_PIXBUF(g_task_propagate_pointer(G_TASK(res), NULL));
91 ctx->container->add_image_to_cache(ctx->url, pixbuf);
92 ctx->container->redraw(true);
99 void container_linux::load_image( const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, bool redraw_on_ready )
101 litehtml::tstring url;
102 make_url(src, baseurl, url);
107 for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
108 const image *i = &(*ii);
110 if (!strcmp(i->first.c_str(), url.c_str())) {
116 unlock_images_cache();
119 struct FetchCtx *ctx = g_new(struct FetchCtx, 1);
120 ctx->url = g_strdup(url.c_str());
121 ctx->container = this;
123 GTask *task = g_task_new(this, NULL, get_image_callback, ctx);
124 g_task_set_task_data(task, ctx, NULL);
125 g_task_run_in_thread(task, get_image_threaded);
127 debug_print("found image in cache: '%s'\n", url.c_str());
131 void container_linux::get_image_size( const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, litehtml::size& sz )
133 litehtml::tstring url;
134 make_url(src, baseurl, url);
136 const image *img = NULL;
140 for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
141 const image *i = &(*ii);
142 if (i->first == url) {
151 sz.width = gdk_pixbuf_get_width(img->second);
152 sz.height = gdk_pixbuf_get_height(img->second);
159 unlock_images_cache();
162 void container_linux::add_image_to_cache(const gchar *url, GdkPixbuf *image)
164 g_return_if_fail(url != NULL);
165 g_return_if_fail(image != NULL);
167 debug_print("adding image to cache: '%s'\n", url);
169 m_images.push_back(std::make_pair(url, image));
170 unlock_images_cache();
172 void container_linux::lock_images_cache(void)
174 g_rec_mutex_lock(&m_images_lock);
177 void container_linux::unlock_images_cache(void)
179 g_rec_mutex_unlock(&m_images_lock);
182 void container_linux::clear_images()
186 for(auto i = m_images.begin(); i != m_images.end(); ++i) {
190 g_object_unref(img->second);
196 unlock_images_cache();
199 gint container_linux::clear_images(gint desired_size)
206 /* First, tally up size of all the stored GdkPixbufs and
207 * deallocate those which make the total size be above
208 * the desired_size limit. We will remove their list
210 for (auto i = m_images.rbegin(); i != m_images.rend(); ++i) {
214 if (img->second == NULL)
217 cursize = gdk_pixbuf_get_byte_length(img->second);
219 if (size + cursize > desired_size) {
220 g_object_unref(img->second);
228 /* Remove elements whose GdkPixbuf pointers point to NULL. */
229 m_images.remove_if([&](image _img) -> bool {
230 if (_img.second == NULL)
235 unlock_images_cache();