From a030ee7e286429f37d01d63d2691e1899cdbc3f6 Mon Sep 17 00:00:00 2001 From: Roland Pfeifer Date: Apr 26, 2020 7:41:38 AM based on thumbnail background patch (might not apply without it) saving text,file,uri,image 2 clipboard image with actual orientation with options to customize/disable it to reduce resource usage allow saving modified format with actual orientation diff --git a/src/Makefile.am b/src/Makefile.am index cfcd980..9d08582 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,7 @@ thumbnailer.c thumbnailer.h \ tumbler.c tumbler.h \ marshal.c marshal.h \ + clipboard_data.c clipboard_data.h \ file.c file.h \ privacy_dialog.h privacy_dialog.c \ util.c util.h \ diff --git a/src/clipboard_data.c b/src/clipboard_data.c new file mode 100644 index 0000000..f255159 --- /dev/null +++ b/src/clipboard_data.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) Stephan Arts 2006-2012 + * + * 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 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. + */ + +#include + +#include + +#include + +#if HAVE_MAGIC_H +#include +#endif + +#include "clipboard_data.h" + +enum +{ + RSTTO_CLIPBOARD_DATA_SIGNAL_CHANGED = 0, + RSTTO_CLIPBOARD_DATA_SIGNAL_COUNT +}; + +static gint +rstto_clipboard_data_signals[RSTTO_CLIPBOARD_DATA_SIGNAL_COUNT]; + +static void +rstto_clipboard_data_init (GObject *); +static void +rstto_clipboard_data_class_init (GObjectClass *); + +static void +rstto_clipboard_data_dispose (GObject *object); +static void +rstto_clipboard_data_finalize (GObject *object); + +static void +rstto_clipboard_data_set_property ( + GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec ); +static void +rstto_clipboard_data_get_property ( + GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec ); + +static GObjectClass *parent_class = NULL; + + +enum +{ + PROP_0, +}; + +GType +rstto_clipboard_data_get_type (void) +{ + static GType rstto_clipboard_data_type = 0; + + if (!rstto_clipboard_data_type) + { + static const GTypeInfo rstto_clipboard_data_info = + { + sizeof (RsttoClipboardDataClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) rstto_clipboard_data_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (RsttoClipboardData), + 0, + (GInstanceInitFunc) rstto_clipboard_data_init, + NULL + }; + + rstto_clipboard_data_type = g_type_register_static ( + G_TYPE_OBJECT, + "RsttoClipboardData", + &rstto_clipboard_data_info, + 0 ); + } + return rstto_clipboard_data_type; +} + +struct _RsttoClipboardDataPriv +{ + GFile *file; + + gchar *uri; + gchar *path; + + GdkPixbuf *pixbuf; +}; + + +static void +rstto_clipboard_data_init (GObject *object) +{ + RsttoClipboardData *r_clipboard_data = RSTTO_CLIPBOARD_DATA (object); + + r_clipboard_data->priv = g_new0 (RsttoClipboardDataPriv, 1); +} + + +static void +rstto_clipboard_data_class_init (GObjectClass *object_class) +{ + RsttoClipboardDataClass *file_class = RSTTO_CLIPBOARD_DATA_CLASS (object_class); + + parent_class = g_type_class_peek_parent (file_class); + + object_class->dispose = rstto_clipboard_data_dispose; + object_class->finalize = rstto_clipboard_data_finalize; + + object_class->set_property = rstto_clipboard_data_set_property; + object_class->get_property = rstto_clipboard_data_get_property; + + rstto_clipboard_data_signals[RSTTO_CLIPBOARD_DATA_SIGNAL_CHANGED] = g_signal_new("changed", + G_TYPE_FROM_CLASS(object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0, + NULL); +} + +/** + * rstto_clipboard_data_dispose: + * @object: + * + */ +static void +rstto_clipboard_data_dispose (GObject *object) +{ + RsttoClipboardData *r_clipboard_data = RSTTO_CLIPBOARD_DATA (object); + + if (r_clipboard_data->priv) + { + if (r_clipboard_data->priv->file) + { + g_object_unref (r_clipboard_data->priv->file); + r_clipboard_data->priv->file = NULL; + } + if (r_clipboard_data->priv->path) + { + g_free (r_clipboard_data->priv->path); + r_clipboard_data->priv->path = NULL; + } + if (r_clipboard_data->priv->uri) + { + g_free (r_clipboard_data->priv->uri); + r_clipboard_data->priv->uri = NULL; + } + if (r_clipboard_data->priv->pixbuf) + { + g_object_unref (r_clipboard_data->priv->pixbuf); + r_clipboard_data->priv->pixbuf = NULL; + } + + g_free (r_clipboard_data->priv); + r_clipboard_data->priv = NULL; + } +} + +/** + * rstto_clipboard_data_finalize: + * @object: + * + */ +static void +rstto_clipboard_data_finalize (GObject *object) +{ + /*RsttoClipboardData *file = RSTTO_CLIPBOARD_DATA (object);*/ +} + + + +/** + * rstto_cipboard_data_new: + * + * + */ +RsttoClipboardData * +rstto_clipboard_data_new ( GFile *file, GdkPixbuf *pixbuf ) +{ + RsttoClipboardData *r_clipboard_data = NULL; + + r_clipboard_data = g_object_new (RSTTO_TYPE_CLIPBOARD_DATA, NULL); + r_clipboard_data->priv->file = file; + g_object_ref (file); + r_clipboard_data->priv->pixbuf = pixbuf; + g_object_ref (pixbuf); + + return r_clipboard_data; +} + + +static void +rstto_clipboard_data_set_property ( + GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec ) +{ +} + +static void +rstto_clipboard_data_get_property ( + GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec ) +{ +} + +GFile * +rstto_clipboard_data_get_file ( RsttoClipboardData *r_clipboard_data ) +{ + return r_clipboard_data->priv->file; +} + +GdkPixbuf * +rstto_clipboard_data_get_pixbuf ( RsttoClipboardData *r_clipboard_data ) +{ + return r_clipboard_data->priv->pixbuf; +} + +const gchar * +rstto_clipboard_data_get_path ( RsttoClipboardData *r_clipboard_data ) +{ + g_return_val_if_fail (RSTTO_IS_CLIPBOARD_DATA (r_clipboard_data), NULL); + g_return_val_if_fail (G_IS_FILE (r_clipboard_data->priv->file), NULL); + + if ( NULL == r_clipboard_data->priv->path ) + { + r_clipboard_data->priv->path = g_file_get_path (r_clipboard_data->priv->file); + } + return (const gchar *)r_clipboard_data->priv->path; +} + +const gchar * +rstto_clipboard_data_get_uri ( RsttoClipboardData *r_clipboard_data ) +{ + if ( NULL == r_clipboard_data->priv->uri ) + { + r_clipboard_data->priv->uri = g_file_get_uri (r_clipboard_data->priv->file); + } + return (const gchar *)r_clipboard_data->priv->uri; +} + diff --git a/src/clipboard_data.h b/src/clipboard_data.h new file mode 100644 index 0000000..1f00112 --- /dev/null +++ b/src/clipboard_data.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) Stephan Arts 2006-2012 + * + * 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 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. + */ + +#ifndef __RISTRETTO_CLIPBOARD_DATA_H__ +#define __RISTRETTO_CLIPBOARD_DATA_H__ + +#include + +#include "util.h" + +G_BEGIN_DECLS + +#define RSTTO_TYPE_CLIPBOARD_DATA rstto_clipboard_data_get_type() + +#define RSTTO_CLIPBOARD_DATA(obj)( \ + G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + RSTTO_TYPE_CLIPBOARD_DATA, \ + RsttoClipboardData)) + +#define RSTTO_IS_CLIPBOARD_DATA(obj)( \ + G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + RSTTO_TYPE_CLIPBOARD_DATA)) + +#define RSTTO_CLIPBOARD_DATA_CLASS(klass)( \ + G_TYPE_CHECK_CLASS_CAST ((klass), \ + RSTTO_TYPE_CLIPBOARD_DATA, \ + RsttoClipboardDataClass)) + +#define RSTTO_IS_CLIPBOARD_DATA_CLASS(klass)( \ + G_TYPE_CHECK_CLASS_TYPE ((klass), \ + RSTTO_TYPE_CLIPBOARD_DATA())) + + +typedef struct _RsttoClipboardData RsttoClipboardData; +typedef struct _RsttoClipboardDataPriv RsttoClipboardDataPriv; + +struct _RsttoClipboardData +{ + GObject parent; + + RsttoClipboardDataPriv *priv; +}; + +typedef struct _RsttoClipboardDataClass RsttoClipboardDataClass; + +struct _RsttoClipboardDataClass +{ + GObjectClass parent_class; +}; + +RsttoClipboardData * +rstto_clipboard_data_new ( GFile *, GdkPixbuf * ); + +GType +rstto_clipboard_data_get_type ( void ); + +GFile * +rstto_clipboard_data_get_file ( RsttoClipboardData * ); + +GdkPixbuf * +rstto_clipboard_data_get_pixbuf ( RsttoClipboardData * ); + +const gchar * +rstto_clipboard_data_get_path ( RsttoClipboardData * ); + +const gchar * +rstto_clipboard_data_get_uri ( RsttoClipboardData * ); + +G_END_DECLS + +#endif /* __RISTRETTO_CLIPBOARD_DATA_H__ */ diff --git a/src/image_viewer.c b/src/image_viewer.c index ebacd73..1f972f9 100644 --- a/src/image_viewer.c +++ b/src/image_viewer.c @@ -30,6 +30,7 @@ #include "image_viewer.h" #include "settings.h" #include "marshal.h" +#include "clipboard_data.h" /* Do not make this buffer too large, * this breaks some pixbufloaders. @@ -68,6 +69,15 @@ RSTTO_IMAGE_VIEWER_MOTION_STATE_BOX_ZOOM, RSTTO_IMAGE_VIEWER_MOTION_STATE_MOVE } RsttoImageViewerMotionState; + +typedef enum +{ + UTF8_STRING, + TEXT_URI_LIST, + GNOME_COPIED_FILE, + PIXBUF_IMAGE +} RsttoImageViewerClipboardType; + typedef struct _RsttoImageViewerTransaction RsttoImageViewerTransaction; @@ -134,6 +144,9 @@ RsttoImageViewerMotionState state; } motion; + gboolean clipboard_ask_image_copy; + gboolean clipboard_image_copy; + gboolean clipboard_keep_content; /* CALLBACKS */ /*************/ void (*cb_value_changed)(GtkAdjustment *, RsttoImageViewer *); @@ -276,6 +289,21 @@ GObject *settings, GParamSpec *pspec, gpointer user_data); +static void +cb_rstto_image_viewer_clipboard_ask_image_copy ( + GObject *settings, + GParamSpec *pspec, + gpointer user_data); +static void +cb_rstto_image_viewer_clipboard_image_copy ( + GObject *settings, + GParamSpec *pspec, + gpointer user_data); +static void +cb_rstto_image_viewer_clipboard_keep_content ( + GObject *settings, + GParamSpec *pspec, + gpointer user_data); static void rstto_image_viewer_load_image ( @@ -284,6 +312,41 @@ gdouble scale); static void rstto_image_viewer_transaction_free (RsttoImageViewerTransaction *tr); + +static void +rstto_image_viewer_set_cairo_transform ( + RsttoImageViewer *viewer, + cairo_t *ctx, + gdouble x_offset, + gdouble y_offset, + gdouble scale, + gdouble hadjustment, + gdouble vadjustment); + +static void +cb_rstto_image_viewer_clipboard_get ( + GtkClipboard *clipboard, + GtkSelectionData *selection_data, + guint info, + gpointer user_data_or_owner); + +static void +cb_rstto_image_viewer_clipboard_clear ( + GtkClipboard *clipboard, + gpointer user_data_or_owner); + +static GdkPixbuf* +rstto_image_viewer_create_transformed_image ( + RsttoImageViewer *viewer); + +static GdkPixbufFormat * +rstto_image_viewer_find_format ( + const char *extension); + +static char * +rstto_image_viewer_extension ( + GFile *file); + static GtkWidgetClass *parent_class = NULL; static GdkScreen *default_screen = NULL; @@ -295,6 +358,8 @@ static void rstto_image_viewer_init (RsttoImageViewer *viewer) { + gchar* cb_name; + if (default_screen == NULL) { default_screen = gdk_screen_get_default(); @@ -349,6 +414,31 @@ "notify::invert-zoom-direction", G_CALLBACK (cb_rstto_zoom_direction_changed), viewer); + + cb_name = g_strdup_printf("notify::%s", SETTING_CLIPBOARD_ASK_IMAGE_COPY); + g_signal_connect ( + G_OBJECT(viewer->priv->settings), + cb_name, + G_CALLBACK (cb_rstto_image_viewer_clipboard_ask_image_copy), + viewer); + g_free(cb_name); + + cb_name = g_strdup_printf("notify::%s", SETTING_CLIPBOARD_IMAGE_COPY); + g_signal_connect ( + G_OBJECT(viewer->priv->settings), + cb_name, + G_CALLBACK (cb_rstto_image_viewer_clipboard_image_copy), + viewer); + g_free(cb_name); + + cb_name = g_strdup_printf("notify::%s", SETTING_CLIPBOARD_KEEP_CONTENT); + g_signal_connect ( + G_OBJECT(viewer->priv->settings), + cb_name, + G_CALLBACK (cb_rstto_image_viewer_clipboard_keep_content), + viewer); + g_free(cb_name); + g_signal_connect ( G_OBJECT(viewer), "drag-data-received", @@ -479,6 +569,9 @@ GValue val_bg_color_fs = {0, }; GValue val_limit_quality = {0, }; GValue val_invert_zoom = {0, }; + GValue val_clipboard_ask_image_copy = {0, }; + GValue val_clipboard_image_copy = {0, }; + GValue val_clipboard_keep_content = {0, }; GtkAllocation allocation; GdkWindowAttr attributes; @@ -495,6 +588,9 @@ g_value_init (&val_bg_color_override, G_TYPE_BOOLEAN); g_value_init (&val_limit_quality, G_TYPE_BOOLEAN); g_value_init (&val_invert_zoom, G_TYPE_BOOLEAN); + g_value_init (&val_clipboard_ask_image_copy, G_TYPE_BOOLEAN); + g_value_init (&val_clipboard_image_copy, G_TYPE_BOOLEAN); + g_value_init (&val_clipboard_keep_content, G_TYPE_BOOLEAN); gtk_widget_get_allocation (widget, &allocation); attributes.x = allocation.x; @@ -532,9 +628,24 @@ G_OBJECT(viewer->priv->settings), "invert-zoom-direction", &val_invert_zoom); + g_object_get_property ( + G_OBJECT(viewer->priv->settings), + SETTING_CLIPBOARD_ASK_IMAGE_COPY, + &val_clipboard_ask_image_copy); + g_object_get_property ( + G_OBJECT(viewer->priv->settings), + SETTING_CLIPBOARD_IMAGE_COPY, + &val_clipboard_image_copy); + g_object_get_property ( + G_OBJECT(viewer->priv->settings), + SETTING_CLIPBOARD_KEEP_CONTENT, + &val_clipboard_keep_content); viewer->priv->limit_quality = g_value_get_boolean (&val_limit_quality); viewer->priv->invert_zoom_direction = g_value_get_boolean (&val_invert_zoom); + viewer->priv->clipboard_ask_image_copy = g_value_get_boolean (&val_clipboard_ask_image_copy); + viewer->priv->clipboard_image_copy = g_value_get_boolean (&val_clipboard_image_copy); + viewer->priv->clipboard_keep_content = g_value_get_boolean (&val_clipboard_keep_content); if (TRUE == g_value_get_boolean (&val_bg_color_override)) { @@ -1161,7 +1272,6 @@ gint block_height = 10; gdouble bg_scale = 1.0; GtkAllocation allocation; - cairo_matrix_t transform_matrix; gtk_widget_get_allocation (widget, &allocation); @@ -1265,141 +1375,14 @@ /* END PAINT CHECKERED BACKGROUND */ cairo_restore (ctx); - switch (viewer->priv->orientation) - { - case RSTTO_IMAGE_ORIENT_FLIP_HORIZONTAL: - cairo_translate ( - ctx, - 0.0 - floor(gtk_adjustment_get_value (viewer->hadjustment)), - 0.0 - floor(gtk_adjustment_get_value (viewer->vadjustment))); - cairo_translate ( - ctx, - viewer->priv->image_width * viewer->priv->scale, - 0.0); - cairo_translate ( - ctx, - x_offset, - y_offset); - cairo_matrix_init_identity(&transform_matrix); - transform_matrix.xx = -1.0; - cairo_transform(ctx, &transform_matrix); - break; - case RSTTO_IMAGE_ORIENT_FLIP_VERTICAL: - cairo_translate ( - ctx, - 0.0 - floor(gtk_adjustment_get_value (viewer->hadjustment)), - 0.0 - floor(gtk_adjustment_get_value (viewer->vadjustment))); - cairo_translate ( - ctx, - 0.0, - viewer->priv->image_height * viewer->priv->scale); - cairo_translate ( - ctx, - x_offset, - y_offset); - cairo_matrix_init_identity(&transform_matrix); - transform_matrix.yy = -1.0; - cairo_transform(ctx, &transform_matrix); - break; - case RSTTO_IMAGE_ORIENT_FLIP_TRANSPOSE: - cairo_rotate ( ctx, M_PI*1.5); - cairo_translate ( - ctx, - floor(gtk_adjustment_get_value (viewer->vadjustment)), - floor(0.0 - gtk_adjustment_get_value (viewer->hadjustment))); - cairo_translate ( - ctx, - -1.0 * y_offset, - x_offset); - cairo_matrix_init_identity(&transform_matrix); - transform_matrix.xx = -1.0; - cairo_transform(ctx, &transform_matrix); - break; - case RSTTO_IMAGE_ORIENT_FLIP_TRANSVERSE: - cairo_rotate ( ctx, M_PI*0.5); - cairo_translate ( - ctx, - floor(0.0 - gtk_adjustment_get_value (viewer->vadjustment)), - floor(gtk_adjustment_get_value (viewer->hadjustment))); - cairo_translate ( - ctx, - viewer->priv->image_width * viewer->priv->scale, - -1.0 * viewer->priv->image_height * viewer->priv->scale); - cairo_translate ( - ctx, - y_offset, - -1.0 * x_offset); - cairo_matrix_init_identity(&transform_matrix); - transform_matrix.xx = -1.0; - cairo_transform(ctx, &transform_matrix); - break; - case RSTTO_IMAGE_ORIENT_90: - cairo_rotate ( - ctx, - M_PI*0.5); - cairo_translate ( - ctx, - floor(0.0 - gtk_adjustment_get_value (viewer->vadjustment)), - floor(gtk_adjustment_get_value (viewer->hadjustment))); - cairo_translate ( - ctx, - 0.0, - -1.0 * viewer->priv->image_height * viewer->priv->scale); - cairo_translate ( - ctx, - y_offset, - -1.0 * x_offset); - break; - case RSTTO_IMAGE_ORIENT_270: - cairo_rotate ( - ctx, - M_PI*1.5); - cairo_translate ( - ctx, - floor(gtk_adjustment_get_value (viewer->vadjustment)), - 0.0 - floor(gtk_adjustment_get_value (viewer->hadjustment))); - cairo_translate ( - ctx, - -1.0 * viewer->priv->image_width * viewer->priv->scale, - 0.0); - - cairo_translate ( - ctx, - -1.0 * y_offset, - x_offset); - break; - case RSTTO_IMAGE_ORIENT_180: - cairo_rotate ( - ctx, - M_PI); - cairo_translate ( - ctx, - floor(gtk_adjustment_get_value (viewer->hadjustment)), - floor(gtk_adjustment_get_value (viewer->vadjustment))); - cairo_translate ( - ctx, - -1.0 * viewer->priv->image_width * viewer->priv->scale, - -1.0 * viewer->priv->image_height * viewer->priv->scale); - - cairo_translate ( - ctx, - -1.0 * x_offset, - -1.0 * y_offset); - break; - case RSTTO_IMAGE_ORIENT_NONE: - default: - cairo_translate ( - ctx, - 0.0 - floor(gtk_adjustment_get_value (viewer->hadjustment)), - 0.0 - floor(gtk_adjustment_get_value (viewer->vadjustment))); - - cairo_translate ( - ctx, - x_offset, - y_offset); - break; - - } + rstto_image_viewer_set_cairo_transform ( + viewer, + ctx, + x_offset, + y_offset, + viewer->priv->scale, + gtk_adjustment_get_value (viewer->hadjustment), + gtk_adjustment_get_value (viewer->vadjustment)); cairo_scale ( ctx, @@ -1454,6 +1437,166 @@ } } +} + +void +rstto_image_viewer_set_cairo_transform ( + RsttoImageViewer *viewer, + cairo_t *ctx, + gdouble x_offset, + gdouble y_offset, + gdouble scale, + gdouble hadjustment, + gdouble vadjustment) +{ + cairo_matrix_t transform_matrix; + + switch (viewer->priv->orientation) + { + case RSTTO_IMAGE_ORIENT_FLIP_HORIZONTAL: + cairo_translate ( + ctx, + 0.0 - floor(hadjustment), + 0.0 - floor(vadjustment)); + cairo_translate ( + ctx, + viewer->priv->image_width * scale, + 0.0); + cairo_translate ( + ctx, + x_offset, + y_offset); + cairo_matrix_init_identity( + &transform_matrix); + transform_matrix.xx = -1.0; + cairo_transform( + ctx, + &transform_matrix); + break; + case RSTTO_IMAGE_ORIENT_FLIP_VERTICAL: + cairo_translate ( + ctx, + 0.0 - floor(hadjustment), + 0.0 - floor(vadjustment)); + cairo_translate ( + ctx, + 0.0, + viewer->priv->image_height * scale); + cairo_translate ( + ctx, + x_offset, + y_offset); + cairo_matrix_init_identity( + &transform_matrix); + transform_matrix.yy = -1.0; + cairo_transform( + ctx, + &transform_matrix); + break; + case RSTTO_IMAGE_ORIENT_FLIP_TRANSPOSE: + cairo_rotate ( ctx, M_PI*1.5); + cairo_translate ( + ctx, + floor(vadjustment), + floor(0.0 - hadjustment)); + cairo_translate ( + ctx, + -1.0 * y_offset, + x_offset); + cairo_matrix_init_identity( + &transform_matrix); + transform_matrix.xx = -1.0; + cairo_transform( + ctx, + &transform_matrix); + break; + case RSTTO_IMAGE_ORIENT_FLIP_TRANSVERSE: + cairo_rotate ( ctx, M_PI*0.5); + cairo_translate ( + ctx, + floor(0.0 - vadjustment), + floor(hadjustment)); + cairo_translate ( + ctx, + viewer->priv->image_width * scale, + -1.0 * viewer->priv->image_height * scale); + cairo_translate ( + ctx, + y_offset, + -1.0 * x_offset); + cairo_matrix_init_identity( + &transform_matrix); + transform_matrix.xx = -1.0; + cairo_transform( + ctx, + &transform_matrix); + break; + case RSTTO_IMAGE_ORIENT_90: + cairo_rotate ( + ctx, + M_PI*0.5); + cairo_translate ( + ctx, + floor(0.0 - vadjustment), + floor(hadjustment)); + cairo_translate ( + ctx, + 0.0, + -1.0 * viewer->priv->image_height * scale); + cairo_translate ( + ctx, + y_offset, + -1.0 * x_offset); + break; + case RSTTO_IMAGE_ORIENT_270: + cairo_rotate ( + ctx, + M_PI*1.5); + cairo_translate ( + ctx, + floor(vadjustment), + 0.0 - floor(hadjustment)); + cairo_translate ( + ctx, + -1.0 * viewer->priv->image_width * scale, + 0.0); + + cairo_translate ( + ctx, + -1.0 * y_offset, + x_offset); + break; + case RSTTO_IMAGE_ORIENT_180: + cairo_rotate ( + ctx, + M_PI); + cairo_translate ( + ctx, + floor(hadjustment), + floor(vadjustment)); + cairo_translate ( + ctx, + -1.0 * viewer->priv->image_width * scale, + -1.0 * viewer->priv->image_height * scale); + + cairo_translate ( + ctx, + -1.0 * x_offset, + -1.0 * y_offset); + break; + case RSTTO_IMAGE_ORIENT_NONE: + default: + cairo_translate ( + ctx, + 0.0 - floor(hadjustment), + 0.0 - floor(vadjustment)); + + cairo_translate ( + ctx, + x_offset, + y_offset); + break; + } } static void @@ -1991,10 +2134,473 @@ } +gboolean +rstto_image_viewer_save_file ( + GtkWidget *widget, + GtkWindow *window, + GFile *source_file, + GFile *target_file, + GError **error) +{ + gboolean ret = TRUE; +//#ifdef RSTTO_SAVE_IMAGE + GtkWidget *err_dialog; + GdkPixbuf* pixbuf = NULL; + GdkPixbufFormat *pixbuf_fmt; + char *path = NULL; + char *target_ext = NULL; + char *source_ext = NULL; + char *fmt_name; + + + RsttoImageViewer *viewer = RSTTO_IMAGE_VIEWER (widget); + target_ext = rstto_image_viewer_extension (target_file); + source_ext = rstto_image_viewer_extension (source_file); + + if (g_strcmp0(target_ext, source_ext) == 0 && // for a copy the extensions shoud match + viewer->priv->orientation == RSTTO_IMAGE_ORIENT_NONE) + { +//#endif + ret = g_file_copy ( + source_file, + target_file, + G_FILE_COPY_OVERWRITE, + NULL, NULL, NULL, + error); +//#ifdef RSTTO_SAVE_IMAGE + } + else + { + if (target_ext != NULL) + { + pixbuf_fmt = rstto_image_viewer_find_format(target_ext); + if (pixbuf_fmt != NULL) + { + fmt_name = gdk_pixbuf_format_get_name ( + pixbuf_fmt); + pixbuf = rstto_image_viewer_create_transformed_image ( + viewer); + path = g_file_get_path (target_file); + ret = gdk_pixbuf_save ( + pixbuf, + path, + fmt_name, error, NULL); + gdk_pixbuf_format_free ( + pixbuf_fmt); + g_object_unref (pixbuf); + } + else + { + err_dialog = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("No compatible format for extension available.")); + gtk_dialog_run(GTK_DIALOG(err_dialog)); + gtk_widget_destroy(err_dialog); + } + } + else + { + err_dialog = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("Coud not determine filetype to save from filename. (Use extension e.g. .png to save Png-file)")); + gtk_dialog_run(GTK_DIALOG(err_dialog)); + gtk_widget_destroy(err_dialog); + } + + } + if (path != NULL) + { + g_free (path); + } + if (target_ext != NULL) + { + g_free(target_ext); + } + if (source_ext != NULL) + { + g_free(source_ext); + } +//#endif + + return ret; +} + +static gboolean +rstto_image_viewer_ask_copy_image ( + RsttoImageViewer *viewer, + GtkWidget *window) +{ + GtkWidget *dialog = NULL; + GtkWidget *content_area; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *button; + GtkWidget *check_button_keep_content; + GtkWidget *check_button_do_not_ask; + GtkWidget *label; + int response; + + dialog = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (dialog), _("Copy to clipboard")); + gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window)); + gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + + button = xfce_gtk_button_new_mixed ("gtk-no", _("_No")); + gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_NO); + gtk_widget_show (button); + button = xfce_gtk_button_new_mixed ("gtk-yes", _("_Yes")); + gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_YES); + gtk_widget_show (button); + + content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10); + + check_button_keep_content = gtk_check_button_new_with_label (_("Keep clipboard content after ristretto exits (if you want to save resources disable this)")); + gtk_box_pack_start (GTK_BOX (vbox), check_button_keep_content, FALSE, FALSE, 0); + check_button_do_not_ask = gtk_check_button_new_with_mnemonic (_("Do not _ask again")); + gtk_box_pack_start (GTK_BOX (vbox), check_button_do_not_ask, FALSE, FALSE, 0); + label = gtk_label_new (_("Save image data to clipboard? (if you answer no the text, file and uri will still be available)")); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 10); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (content_area), hbox); + + gtk_toggle_button_set_active ( + GTK_TOGGLE_BUTTON (check_button_keep_content), + viewer->priv->clipboard_keep_content); + gtk_toggle_button_set_active ( + GTK_TOGGLE_BUTTON (check_button_do_not_ask), + !viewer->priv->clipboard_ask_image_copy); + + gtk_widget_show_all (content_area); + + response = gtk_dialog_run (GTK_DIALOG (dialog)); + viewer->priv->clipboard_image_copy = (response == GTK_RESPONSE_YES); + viewer->priv->clipboard_keep_content = gtk_toggle_button_get_active ( + GTK_TOGGLE_BUTTON (check_button_keep_content)); + viewer->priv->clipboard_ask_image_copy = !gtk_toggle_button_get_active ( + GTK_TOGGLE_BUTTON (check_button_do_not_ask)); + rstto_settings_set_boolean_property ( + viewer->priv->settings, + SETTING_CLIPBOARD_ASK_IMAGE_COPY, + viewer->priv->clipboard_ask_image_copy); + rstto_settings_set_boolean_property ( + viewer->priv->settings, + SETTING_CLIPBOARD_IMAGE_COPY, + viewer->priv->clipboard_image_copy); + rstto_settings_set_boolean_property ( + viewer->priv->settings, + SETTING_CLIPBOARD_KEEP_CONTENT, + viewer->priv->clipboard_keep_content); + + gtk_widget_destroy (dialog); + return viewer->priv->clipboard_image_copy; +} + +gboolean +rstto_image_viewer_copy_to_clipboard ( + RsttoImageViewer *viewer, + GtkWidget *window) +{ + GtkWidget *widget = GTK_WIDGET (viewer); + + if (viewer->priv->file || + viewer->priv->pixbuf) + { + gboolean rc = TRUE; + GtkTargetList* targets; + GdkDisplay *display = gtk_widget_get_display (widget); + GtkClipboard *clipboard = gtk_clipboard_get_default (display); + GtkTargetEntry entry; + GFile* file; + GdkPixbuf* pixbuf; + RsttoClipboardData *clipboardData; + gint n_entries; + GtkTargetEntry *entries; + + // there seems to be no simple function for this + entry.target = "x-special/gnome-copied-files"; + entry.flags = 0; + entry.info = GNOME_COPIED_FILE; + + targets = gtk_target_list_new ( + &entry, + viewer->priv->file ? 1 : 0); + if (viewer->priv->file) + { + // use the convenience functions to cover more options + gtk_target_list_add_text_targets ( + targets, + UTF8_STRING); + gtk_target_list_add_uri_targets ( + targets, + TEXT_URI_LIST); + } + if (viewer->priv->pixbuf) + { + gboolean copy_image = TRUE; + if (!viewer->priv->clipboard_ask_image_copy) + { + copy_image = viewer->priv->clipboard_image_copy; + } + else if (viewer->priv->image_width > 1000 && + viewer->priv->image_height > 1000) + { + copy_image = rstto_image_viewer_ask_copy_image ( + viewer, + window); + } + + if (copy_image) + { + // there is a internal conversion ongoing so this works + gtk_target_list_add_image_targets ( + targets, + PIXBUF_IMAGE, + FALSE); + } + } + file = viewer->priv->file ? rstto_file_get_file (viewer->priv->file) : NULL; + pixbuf = viewer->priv->pixbuf; + if (viewer->priv->pixbuf) + { + pixbuf = rstto_image_viewer_create_transformed_image ( + viewer); + } + // use some transfer type to capture the actual state + clipboardData = rstto_clipboard_data_new ( + file, + pixbuf); + + entries = gtk_target_table_new_from_list ( + targets, + &n_entries); + + // by owning the clipboard we are able to offer different flavors + rc = gtk_clipboard_set_with_owner ( + clipboard, + entries, + n_entries, + cb_rstto_image_viewer_clipboard_get, + cb_rstto_image_viewer_clipboard_clear, + (GObject *)clipboardData); + if (viewer->priv->clipboard_keep_content) + { + // if this is not executed the clipboard will be discarded if program exists + gtk_clipboard_set_can_store ( + clipboard, + NULL, 0); + gtk_clipboard_store ( + clipboard); + } + + g_object_unref (pixbuf); + gtk_target_table_free(entries, n_entries); + gtk_target_list_unref(targets); + return rc; + } + return FALSE; +} + +static gint +rstto_image_viewer_gdk2cairo ( + GdkPixbuf* pixbuf) +{ + gboolean hasAlpha = gdk_pixbuf_get_has_alpha ( + pixbuf); + gint bitsPerPixel = gdk_pixbuf_get_bits_per_sample ( + pixbuf); + GdkColorspace gdk_colorspace = gdk_pixbuf_get_colorspace ( + pixbuf); + + gint cairo_format = CAIRO_FORMAT_RGB24; // fallback to something common + switch (gdk_colorspace) + { + case GDK_COLORSPACE_RGB: // this seems to be the only option + if (bitsPerPixel <= 6) + { + cairo_format = CAIRO_FORMAT_RGB16_565; + } + else + { + if (bitsPerPixel <= 8) + { + cairo_format = hasAlpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24; + } + else + { + cairo_format = CAIRO_FORMAT_RGB30; + } + } + break; + } + return cairo_format; +} + +static GdkPixbuf* +rstto_image_viewer_create_transformed_image ( + RsttoImageViewer *viewer) +{ + gint width; + gint height; + gint cairo_format; + cairo_surface_t* cairo_surface; + cairo_t *ctx; + GdkPixbuf* pixbuf; + + if (viewer->priv->orientation == RSTTO_IMAGE_ORIENT_NONE) + { // simple case use existing map + g_object_ref (viewer->priv->pixbuf); // for a unified handling afterwards increase ref count + return viewer->priv->pixbuf; + } + + cairo_format = rstto_image_viewer_gdk2cairo( + viewer->priv->pixbuf); + switch (viewer->priv->orientation) + { + case RSTTO_IMAGE_ORIENT_90: + case RSTTO_IMAGE_ORIENT_270: + width = viewer->priv->image_height; + height = viewer->priv->image_width; + break; + + default: + width = viewer->priv->image_width; + height = viewer->priv->image_height; + break; + + } + + cairo_surface = cairo_image_surface_create ( + cairo_format, + width, + height); + + ctx = cairo_create (cairo_surface); + + rstto_image_viewer_set_cairo_transform ( + viewer, + ctx, + 0.0, 0.0, + 1.0, + 0.0, 0.0); + + gdk_cairo_set_source_pixbuf ( + ctx, + viewer->priv->pixbuf, + 0.0, + 0.0); + cairo_paint ( + ctx); + cairo_destroy ( + ctx); + cairo_surface_flush ( + cairo_surface); + pixbuf = gdk_pixbuf_get_from_surface ( + cairo_surface, + 0, 0, + width, height); + + cairo_surface_finish ( + cairo_surface); + cairo_surface_destroy ( + cairo_surface); + + return pixbuf; +} /************************/ /** CALLBACK FUNCTIONS **/ /************************/ + +static void +cb_rstto_image_viewer_clipboard_get ( + GtkClipboard *clipboard, + GtkSelectionData *selection_data, + guint info, + gpointer user_data_or_owner) +{ + RsttoClipboardData* clipboardData = RSTTO_CLIPBOARD_DATA (user_data_or_owner); + + GdkPixbuf* img; + const gchar* file_path; + gboolean rc; + gchar *uris[2]; + gchar *buf = NULL; + guchar *ubuf = NULL; + + switch (info) + { + case UTF8_STRING: + file_path = rstto_clipboard_data_get_path ( + clipboardData); + rc = gtk_selection_data_set_text ( + selection_data, + file_path, + strlen(file_path)); + break; + + case TEXT_URI_LIST: + buf = g_strdup ( + rstto_clipboard_data_get_uri ( + clipboardData)); + uris[0] = buf; + uris[1] = NULL; + rc = gtk_selection_data_set_uris ( + selection_data, + uris); + break; + + case GNOME_COPIED_FILE: + // alternative "cut\n", terminate by newline but last + ubuf = (guchar *)g_strdup_printf ("copy\n%s", + rstto_clipboard_data_get_uri ( + clipboardData)); + rc = FALSE; + gtk_selection_data_set ( + selection_data, + gtk_selection_data_get_target (selection_data), + 8, + ubuf, + strlen ((char *)ubuf)); + break; + + case PIXBUF_IMAGE: + img = rstto_clipboard_data_get_pixbuf ( + clipboardData); + rc = gtk_selection_data_set_pixbuf ( + selection_data, + img); + break; + + } + if (buf) + { + g_free(buf); + } + if (ubuf) + { + g_free(ubuf); + } +} + + +static void +cb_rstto_image_viewer_clipboard_clear ( + GtkClipboard *clipboard, + gpointer user_data_or_owner) +{ + RsttoClipboardData* clipboardData = RSTTO_CLIPBOARD_DATA (user_data_or_owner); + if (clipboardData) + { + g_object_unref (clipboardData); + } +} static void cb_rstto_image_viewer_value_changed (GtkAdjustment *adjustment, RsttoImageViewer *viewer) @@ -2817,6 +3423,36 @@ } static void +cb_rstto_image_viewer_clipboard_ask_image_copy ( + GObject *settings, + GParamSpec *pspec, + gpointer user_data) +{ + RsttoImageViewer *viewer = RSTTO_IMAGE_VIEWER (user_data); + viewer->priv->clipboard_ask_image_copy = rstto_settings_get_boolean_property ( + RSTTO_SETTINGS (settings), + SETTING_CLIPBOARD_ASK_IMAGE_COPY); +} + +static void +cb_rstto_image_viewer_clipboard_image_copy (GObject *settings, GParamSpec *pspec, gpointer user_data) +{ + RsttoImageViewer *viewer = RSTTO_IMAGE_VIEWER (user_data); + viewer->priv->clipboard_image_copy = rstto_settings_get_boolean_property ( + RSTTO_SETTINGS (settings), + SETTING_CLIPBOARD_IMAGE_COPY); +} + +static void +cb_rstto_image_viewer_clipboard_keep_content (GObject *settings, GParamSpec *pspec, gpointer user_data) +{ + RsttoImageViewer *viewer = RSTTO_IMAGE_VIEWER (user_data); + viewer->priv->clipboard_keep_content = rstto_settings_get_boolean_property ( + RSTTO_SETTINGS (settings), + SETTING_CLIPBOARD_KEEP_CONTENT); +} + +static void cb_rstto_bgcolor_changed (GObject *settings, GParamSpec *pspec, gpointer user_data) { RsttoImageViewer *viewer = RSTTO_IMAGE_VIEWER (user_data); @@ -3051,3 +3687,66 @@ g_signal_emit_by_name(viewer, "status-changed"); } + +//#ifdef RSTTO_SAVE_IMAGE +// get a matching format for extension (ext shoud be in lowercase) +// the returned format needs to freed by gdk_pixbuf_format_free +static GdkPixbufFormat * +rstto_image_viewer_find_format ( + const char *extension) +{ + GdkPixbufFormat *pixbuf_fmt_writeable = NULL; + GSList *formats = gdk_pixbuf_get_formats (); + + for (guint i = 0; i < g_slist_length (formats); ++i) + { + GdkPixbufFormat *pixbuf_fmt = g_slist_nth_data ( + formats, + i); + if (gdk_pixbuf_format_is_writable (pixbuf_fmt)) + { + char** exts = gdk_pixbuf_format_get_extensions ( + pixbuf_fmt); + for (int j = 0; exts[j] != NULL; ++j) + { + if (g_strcmp0(exts[j], extension) == 0) + { + pixbuf_fmt_writeable = gdk_pixbuf_format_copy ( + pixbuf_fmt); + break; + } + } + g_strfreev(exts); + if (pixbuf_fmt_writeable != NULL) + break; + } + } + g_slist_free (formats); + + return pixbuf_fmt_writeable; +} + +// return extension of file, NULL if non was found +// the return extension needs to be freed +static char * +rstto_image_viewer_extension ( + GFile *file) +{ + char *name = NULL; + char *ext_pos; + char *ext = NULL; + + name = g_file_get_basename (file); + ext_pos = g_strrstr_len (name, strlen(name), "."); + if (ext_pos != NULL) + { + ++ext_pos; + ext = g_ascii_strdown(ext_pos, -1); + } + if (name != NULL) + { + g_free (name); + } + return ext; +} +//#endif \ No newline at end of file diff --git a/src/image_viewer.h b/src/image_viewer.h index 7ce0615..495e45e 100644 --- a/src/image_viewer.h +++ b/src/image_viewer.h @@ -124,6 +124,18 @@ rstto_image_viewer_is_busy ( RsttoImageViewer *viewer ); +gboolean +rstto_image_viewer_copy_to_clipboard ( + RsttoImageViewer *viewer, + GtkWidget *window); + +gboolean +rstto_image_viewer_save_file ( + GtkWidget *widget, + GtkWindow *window, + GFile *s_file, + GFile *target_file, + GError **error); G_END_DECLS diff --git a/src/main_window.c b/src/main_window.c index 7978f79..fcb2dd2 100644 --- a/src/main_window.c +++ b/src/main_window.c @@ -389,6 +389,10 @@ GParamSpec *pspec, gpointer user_data); +static void +cb_rstto_main_window_copy_to_clipboard ( + GtkWidget *widget, + RsttoMainWindow *window); static GtkWidgetClass *parent_class = NULL; @@ -438,6 +442,12 @@ "Q", /* Keyboard shortcut */ N_ ("Quit Ristretto"), /* Tooltip text */ G_CALLBACK (cb_rstto_main_window_quit), }, + { "copy-to-clipboard", + "edit-copy", /* Icon-name */ + N_ ("_Copy"), /* Label-text */ + "C", /* Keyboard shortcut */ + N_ ("Copy image to clipboard"), /* Tooltip text */ + G_CALLBACK (cb_rstto_main_window_copy_to_clipboard), }, /* Edit Menu */ { "edit-menu", NULL, @@ -836,6 +846,7 @@ GClosure *quit_closure = g_cclosure_new ((GCallback)cb_rstto_main_window_quit, window, NULL); GClosure *delete_closure = g_cclosure_new ((GCallback)cb_rstto_main_window_delete, window, NULL); GClosure *refresh_closure = g_cclosure_new ((GCallback)cb_rstto_main_window_refresh, window, NULL); + GClosure *copy_to_clipboard_closure = g_cclosure_new ((GCallback)cb_rstto_main_window_copy_to_clipboard, window, NULL); guint navigationbar_position = 3; guint thumbnail_size = 3; @@ -924,6 +935,7 @@ gtk_accel_group_connect_by_path (accel_group, "/quit", quit_closure); gtk_accel_group_connect_by_path (accel_group, "/delete", delete_closure); gtk_accel_group_connect_by_path (accel_group, "/refresh", refresh_closure); + gtk_accel_group_connect_by_path (accel_group, "/copy-to-clipboard", copy_to_clipboard_closure); /* Set default accelerators */ @@ -1706,7 +1718,8 @@ //"/main-menu/file-menu/print", "/main-menu/file-menu/properties", "/main-menu/file-menu/close", - "/main-menu/edit-menu/delete" + "/main-menu/edit-menu/delete", + "/main-menu/edit-menu/copy-to-clipboard" }; for (i = 0; i < G_N_ELEMENTS (actions); ++i) @@ -1775,7 +1788,8 @@ "/image-viewer-menu/zoom-in", "/image-viewer-menu/zoom-out", "/image-viewer-menu/zoom-100", - "/image-viewer-menu/zoom-fit" + "/image-viewer-menu/zoom-fit", + "/image-viewer-menu/copy-to-clipboard" }; for (i = 0; i < G_N_ELEMENTS (actions); ++i) @@ -3497,6 +3511,7 @@ gint response; GFile *file, *s_file; RsttoFile *r_file; + GError *error = NULL; r_file = rstto_image_list_iter_get_file (window->priv->iter); @@ -3523,20 +3538,22 @@ { file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)); s_file = rstto_file_get_file(rstto_image_list_iter_get_file (window->priv->iter)); - if ( FALSE == g_file_copy ( - s_file, - file, - G_FILE_COPY_OVERWRITE, - NULL, - NULL, - NULL, - NULL) ) + if ( FALSE == rstto_image_viewer_save_file ( + window->priv->image_viewer, + GTK_WINDOW(window), + s_file, + file, + &error) ) { err_dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, - _("Could not save file")); + "%s\n%s", + _("Could not save file"), + error->message, + NULL); + g_error_free (error); gtk_dialog_run(GTK_DIALOG(err_dialog)); gtk_widget_destroy(err_dialog); } @@ -3644,6 +3661,25 @@ gtk_widget_hide (window->priv->warning); } +static void +cb_rstto_main_window_copy_to_clipboard ( + GtkWidget *widget, + RsttoMainWindow *window) +{ + if (!rstto_image_viewer_copy_to_clipboard ( + RSTTO_IMAGE_VIEWER( window->priv->image_viewer ), GTK_WIDGET( window ))) + { + GtkWidget *dialog = gtk_message_dialog_new ( + GTK_WINDOW (window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("An error occurred when copying image to clipboard.") ); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + } +} + /** * cb_rstto_main_window_edit: * @widget: diff --git a/src/main_window_ui.xml b/src/main_window_ui.xml index 600da60..6d5853a 100644 --- a/src/main_window_ui.xml +++ b/src/main_window_ui.xml @@ -25,6 +25,8 @@ + + @@ -106,6 +108,7 @@ + diff --git a/src/preferences_dialog.c b/src/preferences_dialog.c index 90700f3..d192e69 100644 --- a/src/preferences_dialog.c +++ b/src/preferences_dialog.c @@ -92,6 +92,18 @@ cb_slideshow_timeout_value_changed ( GtkRange *range, gpointer user_data); +static void +cb_ask_image_copy_check_button_toggled ( + GtkToggleButton *button, + gpointer user_data); +static void +cb_image_copy_check_button_toggled ( + GtkToggleButton *button, + gpointer user_data); +static void +cb_keep_content_check_button_toggled ( + GtkToggleButton *button, + gpointer user_data); static GtkWidgetClass *parent_class = NULL; @@ -160,6 +172,20 @@ GtkWidget *open_entire_folder_check_button; GtkWidget *wrap_images_check_button; } behaviour_tab; + + struct + { + GtkWidget *clipboard_frame; + GtkWidget *clipboard_vbox; + + GtkWidget *ask_image_copy_check_button; + gboolean ask_image_copy; + GtkWidget *image_copy_check_button; + gboolean image_copy; + GtkWidget *keep_content_check_button; + gboolean keep_content; + + } clipboard_tab; }; @@ -260,6 +286,8 @@ GtkWidget *behaviour_main_vbox; GtkWidget *behaviour_main_lbl; GtkWidget *behaviour_desktop_lbl; + GtkWidget *display_clipboard_vbox; + GtkWidget *display_clipboard_lbl; GtkWidget *notebook = gtk_notebook_new (); GtkWidget *button = xfce_gtk_button_new_mixed ("window-close", _("_Close")); gint n_pages, i; @@ -287,6 +315,9 @@ "show-clock", &bool_show_clock, "limit-quality", &bool_limit_quality, "use-thumbnail-background", &bool_use_thumbnail_background, + SETTING_CLIPBOARD_ASK_IMAGE_COPY, &dialog->priv->clipboard_tab.ask_image_copy, + SETTING_CLIPBOARD_IMAGE_COPY, &dialog->priv->clipboard_tab.image_copy, + SETTING_CLIPBOARD_KEEP_CONTENT, &dialog->priv->clipboard_tab.keep_content, NULL); /* @@ -539,6 +570,42 @@ g_signal_connect (G_OBJECT (dialog->priv->behaviour_tab.choose_desktop_combo_box), "changed", G_CALLBACK (cb_choose_desktop_combo_box_changed), dialog); + + /* + * Configure the clipboard tab + */ + display_clipboard_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + display_clipboard_lbl = gtk_label_new (_("Clipboard")); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), display_clipboard_vbox, display_clipboard_lbl); + + dialog->priv->clipboard_tab.clipboard_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4); + dialog->priv->clipboard_tab.clipboard_frame = xfce_gtk_frame_box_new_with_content (_("Image data"), dialog->priv->clipboard_tab.clipboard_vbox); + gtk_box_pack_start (GTK_BOX (display_clipboard_vbox), dialog->priv->clipboard_tab.clipboard_frame, FALSE, FALSE, 0); + + dialog->priv->clipboard_tab.ask_image_copy_check_button = gtk_check_button_new_with_label (_("Ask to save image to clipboard")); + gtk_container_add (GTK_CONTAINER (dialog->priv->clipboard_tab.clipboard_vbox), dialog->priv->clipboard_tab.ask_image_copy_check_button); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->clipboard_tab.ask_image_copy_check_button), + dialog->priv->clipboard_tab.ask_image_copy); + + g_signal_connect (G_OBJECT (dialog->priv->clipboard_tab.ask_image_copy_check_button), + "toggled", G_CALLBACK (cb_ask_image_copy_check_button_toggled), dialog); + + dialog->priv->clipboard_tab.image_copy_check_button = gtk_check_button_new_with_label (_("Save image to clipboard")); + gtk_container_add (GTK_CONTAINER (dialog->priv->clipboard_tab.clipboard_vbox), dialog->priv->clipboard_tab.image_copy_check_button); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->clipboard_tab.image_copy_check_button), + dialog->priv->clipboard_tab.image_copy); + + g_signal_connect (G_OBJECT (dialog->priv->clipboard_tab.image_copy_check_button), + "toggled", G_CALLBACK (cb_image_copy_check_button_toggled), dialog); + + dialog->priv->clipboard_tab.keep_content_check_button = gtk_check_button_new_with_label (_("Keep clipboard content after ristretto exits (if you want to save resources disable this)")); + gtk_container_add (GTK_CONTAINER (dialog->priv->clipboard_tab.clipboard_vbox), dialog->priv->clipboard_tab.keep_content_check_button); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->clipboard_tab.keep_content_check_button), + dialog->priv->clipboard_tab.keep_content); + + g_signal_connect (G_OBJECT (dialog->priv->clipboard_tab.keep_content_check_button), + "toggled", G_CALLBACK (cb_keep_content_check_button_toggled), dialog); + /* Increase left and top margins for the tabs' contents */ n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)); @@ -1127,3 +1194,60 @@ break; } } + +static void +cb_ask_image_copy_check_button_toggled ( + GtkToggleButton *button, + gpointer user_data) +{ + /* Variable Section */ + + RsttoPreferencesDialog *dialog = RSTTO_PREFERENCES_DIALOG ( user_data ); + dialog->priv->clipboard_tab.ask_image_copy = gtk_toggle_button_get_active ( button ); + + + /* Code Section */ + + rstto_settings_set_boolean_property ( + dialog->priv->settings, + SETTING_CLIPBOARD_ASK_IMAGE_COPY, + dialog->priv->clipboard_tab.ask_image_copy ); +} + +static void +cb_image_copy_check_button_toggled ( + GtkToggleButton *button, + gpointer user_data) +{ + /* Variable Section */ + + RsttoPreferencesDialog *dialog = RSTTO_PREFERENCES_DIALOG ( user_data ); + dialog->priv->clipboard_tab.image_copy = gtk_toggle_button_get_active ( button ); + + + /* Code Section */ + + rstto_settings_set_boolean_property ( + dialog->priv->settings, + SETTING_CLIPBOARD_IMAGE_COPY, + dialog->priv->clipboard_tab.image_copy ); +} + +static void +cb_keep_content_check_button_toggled ( + GtkToggleButton *button, + gpointer user_data) +{ + /* Variable Section */ + + RsttoPreferencesDialog *dialog = RSTTO_PREFERENCES_DIALOG ( user_data ); + dialog->priv->clipboard_tab.keep_content = gtk_toggle_button_get_active ( button ); + + + /* Code Section */ + + rstto_settings_set_boolean_property ( + dialog->priv->settings, + SETTING_CLIPBOARD_KEEP_CONTENT, + dialog->priv->clipboard_tab.keep_content ); +} diff --git a/src/settings.c b/src/settings.c index 529362f..fc7bfa0 100644 --- a/src/settings.c +++ b/src/settings.c @@ -83,6 +83,9 @@ PROP_SORT_TYPE, PROP_THUMBNAIL_SIZE, PROP_USE_THUMBNAIL_BACKGROUND, + PROP_CLIPBOARD_ASK_IMAGE_COPY, + PROP_CLIPBOARD_IMAGE_COPY, + PROP_CLIPBOARD_KEEP_CONTENT, }; GType @@ -137,6 +140,9 @@ gboolean maximize_on_startup; RsttoThumbnailSize thumbnail_size; gboolean use_thumbnail_background; + gboolean clipboard_ask_image_copy; + gboolean clipboard_image_copy; + gboolean clipboard_keep_content; RsttoSortType sort_type; @@ -150,6 +156,7 @@ rstto_settings_init (GObject *object) { gchar *accelmap_path = NULL; + gchar *conf_path; RsttoSettings *settings = RSTTO_SETTINGS (object); @@ -199,6 +206,9 @@ settings->priv->errors.missing_thumbnailer = TRUE; settings->priv->thumbnail_size = THUMBNAIL_SIZE_NORMAL; settings->priv->use_thumbnail_background = FALSE; + settings->priv->clipboard_ask_image_copy = TRUE; + settings->priv->clipboard_image_copy = FALSE; + settings->priv->clipboard_keep_content = FALSE; xfconf_g_property_bind ( settings->priv->channel, @@ -367,6 +377,38 @@ settings, "desktop-type"); + conf_path = g_strdup_printf ("/%s/%s", + SETTING_CLIPBOARD, + SETTING_CLIPBOARD_ASK_IMAGE_COPY); + xfconf_g_property_bind ( + settings->priv->channel, + conf_path, + G_TYPE_BOOLEAN, + settings, + SETTING_CLIPBOARD_ASK_IMAGE_COPY); + g_free (conf_path); + + conf_path = g_strdup_printf ("/%s/%s", + SETTING_CLIPBOARD, + SETTING_CLIPBOARD_IMAGE_COPY); + xfconf_g_property_bind ( + settings->priv->channel, + conf_path, + G_TYPE_BOOLEAN, + settings, + SETTING_CLIPBOARD_IMAGE_COPY); + g_free (conf_path); + + conf_path = g_strdup_printf ("/%s/%s", + SETTING_CLIPBOARD, + SETTING_CLIPBOARD_KEEP_CONTENT); + xfconf_g_property_bind ( + settings->priv->channel, + conf_path, + G_TYPE_BOOLEAN, + settings, + SETTING_CLIPBOARD_KEEP_CONTENT); + g_free (conf_path); } @@ -660,6 +702,39 @@ object_class, PROP_USE_THUMBNAIL_BACKGROUND, pspec); + + pspec = g_param_spec_boolean ( + SETTING_CLIPBOARD_ASK_IMAGE_COPY, + "", + "", + TRUE, + G_PARAM_READWRITE); + g_object_class_install_property ( + object_class, + PROP_CLIPBOARD_ASK_IMAGE_COPY, + pspec); + + pspec = g_param_spec_boolean ( + SETTING_CLIPBOARD_IMAGE_COPY, + "", + "", + FALSE, + G_PARAM_READWRITE); + g_object_class_install_property ( + object_class, + PROP_CLIPBOARD_IMAGE_COPY, + pspec); + + pspec = g_param_spec_boolean ( + SETTING_CLIPBOARD_KEEP_CONTENT, + "", + "", + FALSE, + G_PARAM_READWRITE); + g_object_class_install_property ( + object_class, + PROP_CLIPBOARD_KEEP_CONTENT, + pspec); } /** @@ -897,6 +972,15 @@ case PROP_USE_THUMBNAIL_BACKGROUND: settings->priv->use_thumbnail_background = g_value_get_boolean (value); break; + case PROP_CLIPBOARD_ASK_IMAGE_COPY: + settings->priv->clipboard_ask_image_copy = g_value_get_boolean (value); + break; + case PROP_CLIPBOARD_IMAGE_COPY: + settings->priv->clipboard_image_copy = g_value_get_boolean (value); + break; + case PROP_CLIPBOARD_KEEP_CONTENT: + settings->priv->clipboard_keep_content = g_value_get_boolean (value); + break; default: break; } @@ -991,6 +1075,21 @@ case PROP_USE_THUMBNAIL_BACKGROUND: g_value_set_boolean (value, settings->priv->use_thumbnail_background); break; + case PROP_CLIPBOARD_ASK_IMAGE_COPY: + g_value_set_boolean ( + value, + settings->priv->clipboard_ask_image_copy); + break; + case PROP_CLIPBOARD_IMAGE_COPY: + g_value_set_boolean ( + value, + settings->priv->clipboard_image_copy); + break; + case PROP_CLIPBOARD_KEEP_CONTENT: + g_value_set_boolean ( + value, + settings->priv->clipboard_keep_content); + break; default: break; diff --git a/src/settings.h b/src/settings.h index d3f4bea..bf801ba 100644 --- a/src/settings.h +++ b/src/settings.h @@ -77,6 +77,11 @@ void rstto_settings_set_boolean_property (RsttoSettings *, const gchar *, gboolean); gboolean rstto_settings_get_boolean_property (RsttoSettings *, const gchar *); +#define SETTING_CLIPBOARD "clipboard" +#define SETTING_CLIPBOARD_ASK_IMAGE_COPY "ask-image-copy" +#define SETTING_CLIPBOARD_IMAGE_COPY "image-copy" +#define SETTING_CLIPBOARD_KEEP_CONTENT "keep-content" + G_END_DECLS #endif /* __RISTRETTO_SETTINGS_H__ */