Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/XFCE/common/   (X11 Desktop Version 4.20©)  Datei vom 12.9.2024 mit Größe 19 kB image not shown  

Quelle  xfdesktop-thumbnailer.c

  Sprache: C
 

/*
 *  xfdesktop - xfce4's desktop manager
 *
 *  Copyright(c) 2006 Brian Tarricone, <brian@tarricone.org>
 *  Copyright(c) 2006 Benedikt Meurer, <benny@xfce.org>
 *  Copyright(c) 2010-2011 Jannis Pohlmann, <jannis@xfce.org>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software Foundation,
 *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 *  xfdesktop-thumbnailer is based on thumbnailer code from Ristretto
 *  Copyright (c) Stephan Arts 2009-2011 <stephan@xfce.org>
 *
 *  Thumbnailer Spec
 *  https://wiki.gnome.org/action/show/DraftSpecs/ThumbnailerSpec
 *  Thumbnail Managing Standard
 *  https://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html
 */


#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <string.h>

#include <gio/gio.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <libxfce4util/libxfce4util.h>

#include "tumbler.h"
#include "xfdesktop-common.h"
#include "xfdesktop-marshal.h"
#include "xfdesktop-thumbnailer.h"

struct _XfdesktopThumbnailer {
    GObject parent_instance;

    TumblerThumbnailer1 *proxy;

    GSList *queue;
    gchar **supported_mimetypes;
    gboolean big_thumbnails;
    guint handle;

    guint request_timer_id;
};

static void xfdesktop_thumbnailer_dispose(GObject *object);
static void xfdesktop_thumbnailer_finalize(GObject *object);

static void xfdesktop_thumbnailer_request_finished_dbus(TumblerThumbnailer1 *proxy,
                                                        guint arg_handle,
                                                        gpointer data);

static void xfdesktop_thumbnailer_thumbnail_ready_dbus(TumblerThumbnailer1 *proxy,
                                                       guint handle,
                                                       const gchar *const *uri,
                                                       gpointer data);

static gboolean xfdesktop_thumbnailer_queue_request_timer(gpointer user_data);

static XfdesktopThumbnailer *thumbnailer_object = NULL;

enum
{
    THUMBNAIL_READY,
    LAST_SIGNAL,
};

static guint thumbnailer_signals[LAST_SIGNAL] = { 0, };


G_DEFINE_TYPE(XfdesktopThumbnailer, xfdesktop_thumbnailer, G_TYPE_OBJECT);


static void
xfdesktop_thumbnailer_class_init(XfdesktopThumbnailerClass *klass)
{
    GObjectClass *object_class = G_OBJECT_CLASS(klass);

    object_class->dispose = xfdesktop_thumbnailer_dispose;
    object_class->finalize = xfdesktop_thumbnailer_finalize;

    thumbnailer_signals[THUMBNAIL_READY] = g_signal_new (
                        "thumbnail-ready",
                        G_OBJECT_CLASS_TYPE (object_class),
                        G_SIGNAL_RUN_LAST,
                        0,
                        NULL, NULL,
                        xfdesktop_marshal_VOID__STRING_STRING,
                        G_TYPE_NONE, 2,
                        G_TYPE_STRING, G_TYPE_STRING);
}

static void
xfdesktop_thumbnailer_init(XfdesktopThumbnailer *thumbnailer)
{
    GDBusConnection *connection;

    connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);

    if(connection) {
        thumbnailer->proxy = tumbler_thumbnailer1_proxy_new_sync(connection,
                                                                 G_DBUS_PROXY_FLAGS_NONE,
                                                                 "org.freedesktop.thumbnails.Thumbnailer1",
                                                                 "/org/freedesktop/thumbnails/Thumbnailer1",
                                                                 NULL,
                                                                 NULL);

        if(thumbnailer->proxy) {
            gchar **supported_uris = NULL;
            gchar **supported_flavors = NULL;


            g_signal_connect(thumbnailer->proxy,
                             "finished",
                             G_CALLBACK (xfdesktop_thumbnailer_request_finished_dbus),
                             thumbnailer);
            g_signal_connect(thumbnailer->proxy,
                             "ready",
                             G_CALLBACK(xfdesktop_thumbnailer_thumbnail_ready_dbus),
                             thumbnailer);

            tumbler_thumbnailer1_call_get_supported_sync(thumbnailer->proxy,
                                                         &supported_uris,
                                                         &thumbnailer->supported_mimetypes,
                                                         NULL,
                                                         NULL);

            tumbler_thumbnailer1_call_get_flavors_sync(thumbnailer->proxy,
                                                       &supported_flavors,
                                                       NULL,
                                                       NULL);

            if(supported_flavors != NULL) {
                gint n;
                for(n = 0; supported_flavors[n] != NULL; ++n) {
                    if(g_strcmp0(supported_flavors[n], "large")) {
                        thumbnailer->big_thumbnails = TRUE;
                    }
                }
            } else {
                thumbnailer->big_thumbnails = FALSE;
                g_warning("Thumbnailer failed calling GetFlavors");
            }

            g_strfreev(supported_flavors);
            g_strfreev(supported_uris);
        }

        g_object_unref(connection);
    }
}

/**
 * xfdesktop_thumbnailer_dispose:
 * @object:
 *
 */

static void
xfdesktop_thumbnailer_dispose(GObject *object)
{
    XfdesktopThumbnailer *thumbnailer = XFDESKTOP_THUMBNAILER(object);

    if (thumbnailer->request_timer_id != 0) {
        g_source_remove(thumbnailer->request_timer_id);
        thumbnailer->request_timer_id = 0;
    }

    g_clear_object(&thumbnailer->proxy);

    if (thumbnailer == thumbnailer_object) {
        thumbnailer_object = NULL;
    }

    G_OBJECT_CLASS(xfdesktop_thumbnailer_parent_class)->dispose(object);
}

/**
 * xfdesktop_thumbnailer_finalize:
 * @object:
 *
 */

static void
xfdesktop_thumbnailer_finalize(GObject *object)
{
    XfdesktopThumbnailer *thumbnailer = XFDESKTOP_THUMBNAILER(object);

    g_slist_free(thumbnailer->queue);

    if (thumbnailer->supported_mimetypes != NULL) {
        g_strfreev(thumbnailer->supported_mimetypes);
    }

    G_OBJECT_CLASS(xfdesktop_thumbnailer_parent_class)->finalize(object);
}

/**
 * xfdesktop_thumbnailer_new:
 *
 *
 * Singleton
 */

XfdesktopThumbnailer *
xfdesktop_thumbnailer_new(void)
{
    if(thumbnailer_object == NULL) {
        thumbnailer_object = g_object_new(XFDESKTOP_TYPE_THUMBNAILER, NULL);
    } else {
        g_object_ref(thumbnailer_object);
    }

    return thumbnailer_object;
}

gboolean xfdesktop_thumbnailer_service_available(XfdesktopThumbnailer *thumbnailer)
{
    g_return_val_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer), FALSE);
    return thumbnailer->proxy != NULL;
}

gboolean
xfdesktop_thumbnailer_is_supported(XfdesktopThumbnailer *thumbnailer,
                                   gchar *filename)
{
    guint        n;
    gchar       *mime_type = NULL;

    g_return_val_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer), FALSE);
    g_return_val_if_fail(filename != NULL, FALSE);

    GFile *file = g_file_new_for_path(filename);
    mime_type = xfdesktop_get_file_mimetype(file);
    g_object_unref(file);

    if(mime_type == NULL) {
        XF_DEBUG("File %s has no mime type", filename);
        return FALSE;
    }

    if (thumbnailer->supported_mimetypes != NULL) {
        for(n = 0; thumbnailer->supported_mimetypes[n] != NULL; ++n) {
            if(g_content_type_is_a (mime_type, thumbnailer->supported_mimetypes[n])) {
                g_free(mime_type);
                return TRUE;
            }
        }
    }

    g_free(mime_type);
    return FALSE;
}

/**
 * xfdesktop_thumbnailer_queue_thumbnail:
 *
 * Queues a file for thumbnail creation.
 * A "thumbnail-ready" signal will be emitted when the thumbnail is ready.
 * The signal will pass 2 parameters: a gchar *file which will be file
 * that's passed in here and a gchar *thumbnail_file which will be the
 * location of the thumbnail.
 */

gboolean
xfdesktop_thumbnailer_queue_thumbnail(XfdesktopThumbnailer *thumbnailer,
                                      gchar *file)
{
    g_return_val_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer), FALSE);
    g_return_val_if_fail(file != NULL, FALSE);

    if(!xfdesktop_thumbnailer_is_supported(thumbnailer, file)) {
        XF_DEBUG("file: %s not supported", file);
        return FALSE;
    }
    if (thumbnailer->request_timer_id != 0) {
        g_source_remove(thumbnailer->request_timer_id);

        if (thumbnailer->handle != 0 && thumbnailer->proxy != NULL) {
            if (!tumbler_thumbnailer1_call_dequeue_sync(thumbnailer->proxy,
                                                        thumbnailer->handle,
                                                        NULL,
                                                        NULL))
            {
                /* If this fails it usually means there's a thumbnail already
                 * being processed, no big deal */

                XF_DEBUG("Dequeue of thumbnailer->handle: %d failed",
                         thumbnailer->handle);
            }

            thumbnailer->handle = 0;
        }
    }

    if (g_slist_find(thumbnailer->queue, file) == NULL) {
        thumbnailer->queue = g_slist_prepend(thumbnailer->queue, g_strdup(file));
    }

    thumbnailer->request_timer_id = g_timeout_add_full(G_PRIORITY_LOW,
                                                       300,
                                                       xfdesktop_thumbnailer_queue_request_timer,
                                                       thumbnailer,
                                                       NULL);

    return TRUE;
}

static void
xfdesktop_thumbnailer_dequeue_foreach(gpointer data, gpointer user_data)
{
    xfdesktop_thumbnailer_dequeue_thumbnail(user_data, data);
}

/**
 * xfdesktop_thumbnailer_dequeue_thumbnail:
 *
 * Removes a file from the list of pending thumbnail creations.
 * This is not guaranteed to always remove the file, if processing
 * of that thumbnail has started it won't stop.
 */

void
xfdesktop_thumbnailer_dequeue_thumbnail(XfdesktopThumbnailer *thumbnailer,
                                        gchar *file)
{
    GSList *item;

    g_return_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer));
    g_return_if_fail(file != NULL);

    if (thumbnailer->request_timer_id != 0) {
        g_source_remove(thumbnailer->request_timer_id);

        if (thumbnailer->handle != 0 && thumbnailer->proxy != NULL) {
            if (!tumbler_thumbnailer1_call_dequeue_sync(thumbnailer->proxy,
                                                        thumbnailer->handle,
                                                        NULL,
                                                        NULL))
            {
                /* If this fails it usually means there's a thumbnail already
                 * being processed, no big deal */

                XF_DEBUG("Dequeue of thumbnailer->handle: %d failed",
                         thumbnailer->handle);
            }
        }
        thumbnailer->handle = 0;
    }

    item = g_slist_find(thumbnailer->queue, file);
    if(item != NULL) {
        g_free(item->data);
        thumbnailer->queue = g_slist_remove(thumbnailer->queue,
                                                  file);
    }

    thumbnailer->request_timer_id = g_timeout_add_full(G_PRIORITY_LOW,
                                                       300,
                                                       xfdesktop_thumbnailer_queue_request_timer,
                                                       thumbnailer,
                                                       NULL);
}

void xfdesktop_thumbnailer_dequeue_all_thumbnails(XfdesktopThumbnailer *thumbnailer)
{
    g_return_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer));

    g_slist_foreach(thumbnailer->queue, (GFunc)xfdesktop_thumbnailer_dequeue_foreach, thumbnailer);
}

static gboolean
xfdesktop_thumbnailer_queue_request_timer(gpointer user_data)
{
    XfdesktopThumbnailer *thumbnailer = user_data;
    gchar **uris;
    gchar **mimetypes;
    GSList *iter;
    gint i = 0;
    GFile *file;
    GError *error = NULL;
    gchar *thumbnail_flavor;

    g_return_val_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer), FALSE);

    uris = g_new0(gchar *, g_slist_length(thumbnailer->queue) + 1);
    mimetypes = g_new0(gchar *, g_slist_length (thumbnailer->queue) + 1);

    iter = thumbnailer->queue;
    while(iter) {
        if(iter->data) {
            file = g_file_new_for_path(iter->data);
            uris[i] = g_file_get_uri(file);
            mimetypes[i] = xfdesktop_get_file_mimetype(file);

            g_object_unref(file);
        }
        iter = g_slist_next(iter);
        i++;
    }

    if (thumbnailer->big_thumbnails) {
        thumbnail_flavor = "large";
    } else {
        thumbnail_flavor = "normal";
    }

    if (thumbnailer->proxy != NULL) {
        if (!tumbler_thumbnailer1_call_queue_sync(thumbnailer->proxy,
                                                  (const gchar * const*)uris,
                                                  (const gchar * const*)mimetypes,
                                                  thumbnail_flavor,
                                                  "default",
                                                  0,
                                                  &thumbnailer->handle,
                                                  NULL,
                                                  &error))
        {
            if(error != NULL)
                g_warning("DBUS-call failed: %s", error->message);
        }
    }

    /* Free the memory */
    i = 0;
    iter = thumbnailer->queue;
    while(iter) {
        if(iter->data) {
            g_free(uris[i]);
            g_free(mimetypes[i]);
        }
        iter = g_slist_next(iter);
        i++;
    }

    g_free(uris);
    g_free(mimetypes);
    g_clear_error(&error);

    thumbnailer->request_timer_id = 0;

    return FALSE;
}

static void
xfdesktop_thumbnailer_request_finished_dbus(TumblerThumbnailer1 *proxy,
                                            guint arg_handle,
                                            gpointer data)
{
    XfdesktopThumbnailer *thumbnailer = XFDESKTOP_THUMBNAILER(data);

    g_return_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer));

    thumbnailer->handle = 0;
}

static void
xfdesktop_thumbnailer_thumbnail_ready_dbus(TumblerThumbnailer1 *proxy,
                                           guint handle,
                                           const gchar *const *uri,
                                           gpointer data)
{
    XfdesktopThumbnailer *thumbnailer = XFDESKTOP_THUMBNAILER(data);
    gchar *thumbnail_location;
    GFile *file;
    GSList *iter = thumbnailer->queue;
    gchar *f_uri, *f_uri_checksum, *filename, *temp;
    gchar *thumbnail_flavor;
    gint x = 0;

    g_return_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer));

    while(iter) {
        if((uri[x] == NULL) || (iter->data == NULL)) {
            break;
        }

        file = g_file_new_for_path(iter->data);
        f_uri = g_file_get_uri(file);

        if(strcmp (uri[x], f_uri) == 0) {
            /* The thumbnail is in the format/location
             * $XDG_CACHE_HOME/thumbnails/(nromal|large)/MD5_Hash_Of_URI.png
             * for version 0.8.0 if XDG_CACHE_HOME is defined, otherwise
             * /homedir/.thumbnails/(normal|large)/MD5_Hash_Of_URI.png
             * will be used, which is also always used for versions prior
             * to 0.7.0.
             */

            f_uri_checksum = g_compute_checksum_for_string(G_CHECKSUM_MD5,
                                                           f_uri, strlen (f_uri));

            if (thumbnailer->big_thumbnails) {
                thumbnail_flavor = "large";
            } else {
                thumbnail_flavor = "normal";
            }

            filename = g_strconcat(f_uri_checksum, ".png", NULL);

            /* build and check if the thumbnail is in the new location */
            thumbnail_location = g_build_path("/", g_get_user_cache_dir(),
                                              "thumbnails", thumbnail_flavor,
                                              filename, NULL);

            if(!g_file_test(thumbnail_location, G_FILE_TEST_EXISTS)) {
                /* Fallback to old version */
                g_free(thumbnail_location);

                thumbnail_location = g_build_path("/", g_get_home_dir(),
                                                  ".thumbnails", thumbnail_flavor,
                                                  filename, NULL);
            }

            XF_DEBUG("thumbnail-ready src: %s thumbnail: %s",
                     (char*)iter->data,
                     thumbnail_location);

            if(g_file_test(thumbnail_location, G_FILE_TEST_EXISTS)) {
                g_signal_emit(G_OBJECT(thumbnailer),
                              thumbnailer_signals[THUMBNAIL_READY],
                              0,
                              iter->data,
                              thumbnail_location);
            }

            temp = iter->data;
            thumbnailer->queue = g_slist_remove(thumbnailer->queue, temp);

            iter = thumbnailer->queue;
            x++;

            g_free(filename);
            g_free(f_uri_checksum);
            g_free(thumbnail_location);
            g_free(temp);
        } else {
            iter = g_slist_next(iter);
        }

        g_object_unref(file);
        g_free(f_uri);
    }
}

/**
 * xfdesktop_thumbnailer_delete_thumbnail:
 *
 * Tells the thumbnail service the src_file will be deleted.
 * This function should be called when the file is deleted or moved so
 * the thumbnail file doesn't take up space on the user's drive.
 */

void
xfdesktop_thumbnailer_delete_thumbnail(XfdesktopThumbnailer *thumbnailer, gchar *src_file)
{
    GDBusConnection *connection;
    GVariantBuilder builder;
    GFile *file;
    GError *error = NULL;
    static GDBusProxy *cache = NULL;

    if(!cache) {
        connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
        if (connection != NULL) {
            cache = g_dbus_proxy_new_sync(connection,
                                          G_DBUS_PROXY_FLAGS_NONE,
                                          NULL,
                                          "org.freedesktop.thumbnails.Cache1",
                                          "/org/freedesktop/thumbnails/Cache1",
                                          "org.freedesktop.thumbnails.Cache1",
                                          NULL,
                                          NULL);

        g_object_unref(connection);
        }
    }

    file = g_file_new_for_path(src_file);

    if(cache) {
        g_variant_builder_init(&builder, G_VARIANT_TYPE ("as"));
        g_variant_builder_add(&builder, "s", g_file_get_uri(file));
        g_dbus_proxy_call_sync(cache,
                               "Delete",
                               g_variant_new("(as)", &builder),
                               G_DBUS_CALL_FLAGS_NONE,
                               -1,
                               NULL,
                               &error);
        if(error != NULL) {
            g_warning("DBUS-call failed:%s", error->message);
        }
    }

    g_object_unref(file);
    g_clear_error(&error);
}

Messung V0.5 in Prozent
C=98 H=94 G=95

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-07-10) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.