Browser
/* $Id$ */
/* Copyright (c) 2011-2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS Desktop Browser */
/* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
#include <System.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libintl.h>
#include "Browser.h"
#define _(string) gettext(string)
#define N_(string) (string)
#ifndef max
# define max(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef min
# define min(a, b) ((a) < (b) ? (a) : (b))
#endif
/* Preview */
/* private */
/* types */
typedef enum _PreviewImageHow
{
PREVIEW_IMAGE_HOW_FIT = 0,
PREVIEW_IMAGE_HOW_ORIGINAL,
PREVIEW_IMAGE_HOW_SCALE
} PreviewImageHow;
typedef struct _BrowserPlugin
{
BrowserPluginHelper * helper;
char * path;
guint source;
/* widgets */
GtkWidget * widget;
GtkWidget * name;
GtkWidget * toolbar;
GtkToolItem * open;
GtkToolItem * edit;
GtkToolItem * copy;
GtkToolItem * select_all;
GtkToolItem * zoom_100;
GtkToolItem * zoom_fit;
GtkToolItem * zoom_out;
GtkToolItem * zoom_in;
GtkWidget * view_image;
GtkWidget * view_image_image;
PreviewImageHow view_image_how;
gint view_image_height;
gint view_image_width;
gdouble view_image_scale;
GtkWidget * view_text;
GtkTextBuffer * view_text_tbuf;
} Preview;
/* constants */
#define PREVIEW_IMAGE_SIZE_DEFAULT 96
/* prototypes */
/* plug-in */
static Preview * _preview_init(BrowserPluginHelper * helper);
static void _preview_destroy(Preview * preview);
static GtkWidget * _preview_get_widget(Preview * preview);
static void _preview_refresh(Preview * preview, GList * selection);
/* accessors */
static void _preview_get_image_size(Preview * preview, gint * width,
gint * height);
static void _preview_get_widget_size(Preview * preview, gint * width,
gint * height);
/* callbacks */
static void _preview_on_copy(gpointer data);
static void _preview_on_edit(gpointer data);
static gboolean _preview_on_idle_image(gpointer data);
static gboolean _preview_on_idle_text(gpointer data);
static void _preview_on_open(gpointer data);
static void _preview_on_select_all(gpointer data);
static void _preview_on_zoom_100(gpointer data);
static void _preview_on_zoom_fit(gpointer data);
static void _preview_on_zoom_in(gpointer data);
static void _preview_on_zoom_out(gpointer data);
/* public */
/* variables */
BrowserPluginDefinition plugin =
{
N_("Preview"),
"gtk-find",
NULL,
_preview_init,
_preview_destroy,
_preview_get_widget,
_preview_refresh
};
/* private */
/* functions */
/* preview_init */
static Preview * _preview_init(BrowserPluginHelper * helper)
{
Preview * preview;
PangoFontDescription * font;
GtkWidget * vbox;
GtkWidget * widget;
String const * p;
if((preview = object_new(sizeof(*preview))) == NULL)
return NULL;
preview->helper = helper;
preview->path = NULL;
preview->source = 0;
if((p = helper->config_get(helper->browser, "preview", "size")) != NULL)
preview->view_image_how = strtol(p, NULL, 0);
else
preview->view_image_how = PREVIEW_IMAGE_HOW_FIT;
/* widgets */
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
preview->widget = vbox;
/* toolbar */
preview->toolbar = gtk_toolbar_new();
gtk_widget_set_no_show_all(preview->toolbar, TRUE);
/* mime */
preview->open = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN);
g_signal_connect_swapped(preview->open, "clicked", G_CALLBACK(
_preview_on_open), preview);
gtk_toolbar_insert(GTK_TOOLBAR(preview->toolbar), preview->open, -1);
preview->edit = gtk_tool_button_new_from_stock(GTK_STOCK_EDIT);
g_signal_connect_swapped(preview->edit, "clicked", G_CALLBACK(
_preview_on_edit), preview);
gtk_toolbar_insert(GTK_TOOLBAR(preview->toolbar), preview->edit, -1);
/* copy */
preview->copy = gtk_tool_button_new_from_stock(GTK_STOCK_COPY);
g_signal_connect_swapped(preview->copy, "clicked", G_CALLBACK(
_preview_on_copy), preview);
gtk_toolbar_insert(GTK_TOOLBAR(preview->toolbar), preview->copy, -1);
/* select all */
#if GTK_CHECK_VERSION(2, 10, 0)
preview->select_all = gtk_tool_button_new_from_stock(
GTK_STOCK_SELECT_ALL);
#else
widget = gtk_image_new_from_icon_name("edit-select-all",
gtk_toolbar_get_icon_size(GTK_TOOLBAR(
preview->toolbar)));
preview->select_all = gtk_tool_button_new(widget, "Select all");
#endif
g_signal_connect_swapped(preview->select_all, "clicked", G_CALLBACK(
_preview_on_select_all), preview);
gtk_toolbar_insert(GTK_TOOLBAR(preview->toolbar), preview->select_all,
-1);
/* zoom */
preview->zoom_100 = gtk_tool_button_new_from_stock(GTK_STOCK_ZOOM_100);
g_signal_connect_swapped(preview->zoom_100, "clicked", G_CALLBACK(
_preview_on_zoom_100), preview);
gtk_toolbar_insert(GTK_TOOLBAR(preview->toolbar), preview->zoom_100,
-1);
preview->zoom_fit = gtk_tool_button_new_from_stock(GTK_STOCK_ZOOM_FIT);
g_signal_connect_swapped(preview->zoom_fit, "clicked", G_CALLBACK(
_preview_on_zoom_fit), preview);
gtk_toolbar_insert(GTK_TOOLBAR(preview->toolbar), preview->zoom_fit,
-1);
preview->zoom_out = gtk_tool_button_new_from_stock(GTK_STOCK_ZOOM_OUT);
g_signal_connect_swapped(preview->zoom_out, "clicked", G_CALLBACK(
_preview_on_zoom_out), preview);
gtk_toolbar_insert(GTK_TOOLBAR(preview->toolbar), preview->zoom_out,
-1);
preview->zoom_in = gtk_tool_button_new_from_stock(GTK_STOCK_ZOOM_IN);
g_signal_connect_swapped(preview->zoom_in, "clicked", G_CALLBACK(
_preview_on_zoom_in), preview);
gtk_toolbar_insert(GTK_TOOLBAR(preview->toolbar), preview->zoom_in, -1);
gtk_box_pack_start(GTK_BOX(vbox), preview->toolbar, FALSE, TRUE, 0);
/* name */
preview->name = gtk_label_new(NULL);
gtk_label_set_ellipsize(GTK_LABEL(preview->name),
PANGO_ELLIPSIZE_MIDDLE);
#if GTK_CHECK_VERSION(3, 0, 0)
g_object_set(preview->name, "halign", GTK_ALIGN_START, NULL);
#else
gtk_misc_set_alignment(GTK_MISC(preview->name), 0.0, 0.5);
#endif
font = pango_font_description_new();
pango_font_description_set_weight(font, PANGO_WEIGHT_BOLD);
#if GTK_CHECK_VERSION(3, 0, 0)
gtk_widget_override_font(preview->name, font);
#else
gtk_widget_modify_font(preview->name, font);
#endif
pango_font_description_free(font);
if((p = helper->config_get(helper->browser, "preview", "label")) != NULL
&& strtol(p, NULL, 0) == 0)
gtk_widget_set_no_show_all(preview->name, TRUE);
gtk_box_pack_start(GTK_BOX(vbox), preview->name, FALSE, TRUE, 0);
/* image */
preview->view_image = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(preview->view_image),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_widget_set_no_show_all(preview->view_image, TRUE);
preview->view_image_image = gtk_image_new();
gtk_widget_show(preview->view_image_image);
#if GTK_CHECK_VERSION(3, 0, 0)
gtk_container_add(GTK_CONTAINER(preview->view_image),
preview->view_image_image);
#else
gtk_scrolled_window_add_with_viewport(
GTK_SCROLLED_WINDOW(preview->view_image),
preview->view_image_image);
#endif
preview->view_image_scale = 1.0;
preview->view_image_height = -1;
preview->view_image_width = -1;
gtk_box_pack_start(GTK_BOX(vbox), preview->view_image, TRUE, TRUE, 0);
/* text */
preview->view_text = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(preview->view_text),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_widget_set_no_show_all(preview->view_text, TRUE);
font = pango_font_description_new();
pango_font_description_set_family(font, "monospace");
widget = gtk_text_view_new();
preview->view_text_tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(
widget));
gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(widget), FALSE);
gtk_text_view_set_editable(GTK_TEXT_VIEW(widget), FALSE);
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(widget), GTK_WRAP_WORD_CHAR);
#if GTK_CHECK_VERSION(3, 0, 0)
gtk_widget_override_font(widget, font);
#else
gtk_widget_modify_font(widget, font);
#endif
gtk_widget_show(widget);
pango_font_description_free(font);
#if GTK_CHECK_VERSION(3, 0, 0)
gtk_container_add(GTK_CONTAINER(preview->view_text), widget);
#else
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(
preview->view_text), widget);
#endif
gtk_box_pack_start(GTK_BOX(vbox), preview->view_text, TRUE, TRUE, 0);
gtk_widget_show_all(vbox);
return preview;
}
/* preview_destroy */
static void _preview_destroy(Preview * preview)
{
if(preview->source != 0)
g_source_remove(preview->source);
free(preview->path);
object_delete(preview);
}
/* preview_get_widget */
static GtkWidget * _preview_get_widget(Preview * preview)
{
return preview->widget;
}
/* preview_refresh */
static void _refresh_mime(Preview * preview, Mime * mime, char const * type);
static int _refresh_name(Preview * preview, char const * path);
static void _refresh_reset(Preview * preview);
static void _preview_refresh(Preview * preview, GList * selection)
{
char * path = (selection != NULL) ? selection->data : NULL;
Mime * mime = preview->helper->get_mime(preview->helper->browser);
struct stat st;
char const image[6] = "image/";
char const text[5] = "text/";
char const * types[] = { "application/x-perl",
"application/x-shellscript",
"application/xml",
"application/xslt+xml" };
char const * type;
size_t i;
_refresh_reset(preview);
if(path == NULL)
return;
if(_refresh_name(preview, path) != 0)
return;
/* ignore directories */
if(lstat(path, &st) == 0 && S_ISDIR(st.st_mode))
return;
/* XXX avoid stat() and use vfs_mime_type() instead */
if((type = mime_type(mime, path)) == NULL)
return;
_refresh_mime(preview, mime, type);
if(strncmp(type, image, sizeof(image)) == 0)
preview->source = g_idle_add(_preview_on_idle_image, preview);
else if(strncmp(type, text, sizeof(text)) == 0)
preview->source = g_idle_add(_preview_on_idle_text, preview);
else
for(i = 0; i < sizeof(types) / sizeof(*types); i++)
if(strcmp(types[i], type) == 0)
{
preview->source = g_idle_add(
_preview_on_idle_text, preview);
break;
}
}
static void _refresh_mime(Preview * preview, Mime * mime, char const * type)
{
if(mime_get_handler(mime, type, "open") != NULL)
{
gtk_widget_show(GTK_WIDGET(preview->open));
gtk_widget_show(preview->toolbar);
}
if(mime_get_handler(mime, type, "edit") != NULL)
{
gtk_widget_show(GTK_WIDGET(preview->edit));
gtk_widget_show(preview->toolbar);
}
}
static int _refresh_name(Preview * preview, char const * path)
{
BrowserPluginHelper * helper = preview->helper;
gchar * p;
free(preview->path);
if((preview->path = strdup(path)) == NULL)
return -helper->error(helper->browser, strerror(errno), 1);
p = g_filename_display_basename(path);
gtk_label_set_text(GTK_LABEL(preview->name), p);
g_free(p);
return 0;
}
static void _refresh_reset(Preview * preview)
{
if(preview->source != 0)
g_source_remove(preview->source);
preview->source = 0;
preview->view_image_width = -1;
preview->view_image_height = -1;
gtk_widget_hide(preview->toolbar);
gtk_widget_hide(GTK_WIDGET(preview->open));
gtk_widget_hide(GTK_WIDGET(preview->edit));
gtk_widget_hide(GTK_WIDGET(preview->copy));
gtk_widget_hide(GTK_WIDGET(preview->select_all));
gtk_widget_hide(GTK_WIDGET(preview->zoom_100));
gtk_widget_hide(GTK_WIDGET(preview->zoom_fit));
gtk_widget_hide(GTK_WIDGET(preview->zoom_out));
gtk_widget_hide(GTK_WIDGET(preview->zoom_in));
gtk_widget_hide(preview->view_image);
gtk_widget_hide(preview->view_text);
}
/* accessors */
/* preview_get_image_size */
static void _preview_get_image_size(Preview * preview, gint * width,
gint * height)
{
BrowserPluginHelper * helper = preview->helper;
GdkPixbuf * pixbuf;
GError * error = NULL;
/* check if we have cached the values */
if(preview->view_image_width > 0
&& preview->view_image_height > 0)
{
*width = preview->view_image_width;
*height = preview->view_image_height;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() %dx%d (cached)\n", __func__,
*width, *height);
#endif
return;
}
*width = PREVIEW_IMAGE_SIZE_DEFAULT;
*height = PREVIEW_IMAGE_SIZE_DEFAULT;
if(preview->path != NULL
&& (pixbuf = gdk_pixbuf_new_from_file(preview->path,
&error)) != NULL)
{
*width = gdk_pixbuf_get_width(pixbuf);
*height = gdk_pixbuf_get_height(pixbuf);
g_object_unref(pixbuf);
/* cache the values */
preview->view_image_width = *width;
preview->view_image_height = *height;
}
if(error != NULL)
{
helper->error(NULL, error->message, 1);
g_error_free(error);
}
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() %dx%d\n", __func__, *width, *height);
#endif
}
/* preview_get_widget_size */
static void _preview_get_widget_size(Preview * preview, gint * width,
gint * height)
{
#if GTK_CHECK_VERSION(2, 14, 0)
GdkWindow * window;
if((window = gtk_widget_get_window(preview->view_image)) != NULL)
{
# if GTK_CHECK_VERSION(2, 24, 0)
*width = gdk_window_get_width(window);
*height = gdk_window_get_height(window);
# else
gdk_drawable_get_size(GDK_DRAWABLE(window), width, height);
# endif
}
else
#endif
{
*width = PREVIEW_IMAGE_SIZE_DEFAULT;
*height = PREVIEW_IMAGE_SIZE_DEFAULT;
}
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() %dx%d\n", __func__, *width, *height);
#endif
}
/* callbacks */
/* preview_on_copy */
static void _preview_on_copy(gpointer data)
{
Preview * preview = data;
GtkClipboard * clipboard;
clipboard = gtk_widget_get_clipboard(preview->view_text,
GDK_SELECTION_CLIPBOARD);
gtk_text_buffer_copy_clipboard(preview->view_text_tbuf, clipboard);
}
/* preview_on_edit */
static void _preview_on_edit(gpointer data)
{
Preview * preview = data;
Mime * mime = preview->helper->get_mime(preview->helper->browser);
if(preview->path != NULL)
mime_action(mime, "edit", preview->path);
}
/* preview_on_idle_image */
static void _idle_image_100(Preview * preview);
static void _idle_image_fit(Preview * preview);
static void _idle_image_load(Preview * preview, gint height, gint width);
static void _idle_image_load_animation(Preview * preview);
static void _idle_image_load_pixbuf(Preview * preview, gint width, gint height);
static void _idle_image_scale(Preview * preview);
static gboolean _preview_on_idle_image(gpointer data)
{
Preview * preview = data;
preview->source = 0;
/* show the toolbar */
gtk_widget_show(GTK_WIDGET(preview->zoom_100));
gtk_widget_show(GTK_WIDGET(preview->zoom_fit));
gtk_widget_show(GTK_WIDGET(preview->zoom_out));
gtk_widget_show(GTK_WIDGET(preview->zoom_in));
gtk_widget_show(preview->toolbar);
switch(preview->view_image_how)
{
case PREVIEW_IMAGE_HOW_FIT:
_idle_image_fit(preview);
break;
case PREVIEW_IMAGE_HOW_ORIGINAL:
_idle_image_100(preview);
break;
case PREVIEW_IMAGE_HOW_SCALE:
default:
_idle_image_scale(preview);
break;
}
gtk_widget_show(preview->view_image);
return FALSE;
}
static void _idle_image_100(Preview * preview)
{
_idle_image_load(preview, 0, 0);
}
static void _idle_image_fit(Preview * preview)
{
gint iwidth;
gint iheight;
gint wwidth;
gint wheight;
_preview_get_image_size(preview, &iwidth, &iheight);
_preview_get_widget_size(preview, &wwidth, &wheight);
/* scale the image accordingly */
preview->view_image_scale = min((gdouble)wwidth / (gdouble)iwidth,
(gdouble)wheight / (gdouble)iheight);
_idle_image_load(preview, 0, 0);
}
static void _idle_image_load(Preview * preview, gint height, gint width)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%d, %d)\n", __func__, width, height);
#endif
if(width <= 0 && height <= 0 && preview->view_image_scale == 1.0)
_idle_image_load_animation(preview);
else
{
if(width <= 0 || height <= 0)
_preview_get_image_size(preview, &width, &height);
_idle_image_load_pixbuf(preview,
width * preview->view_image_scale,
height * preview->view_image_scale);
}
}
static void _idle_image_load_animation(Preview * preview)
{
BrowserPluginHelper * helper = preview->helper;
GdkPixbufAnimation * pixbuf;
GError * error = NULL;
if((pixbuf = gdk_pixbuf_animation_new_from_file(preview->path, &error))
== NULL)
{
helper->error(helper->browser, error->message, 1);
g_error_free(error);
return;
}
if(error != NULL)
{
helper->error(NULL, error->message, 1);
g_error_free(error);
}
gtk_image_set_from_animation(GTK_IMAGE(preview->view_image_image),
pixbuf);
g_object_unref(pixbuf);
}
static void _idle_image_load_pixbuf(Preview * preview, gint width, gint height)
{
BrowserPluginHelper * helper = preview->helper;
GdkPixbuf * pixbuf;
GError * error = NULL;
if(width <= 0)
width = 1;
if(height <= 0)
height = 1;
#if GTK_CHECK_VERSION(2, 6, 0)
if((pixbuf = gdk_pixbuf_new_from_file_at_scale(preview->path, width,
height, TRUE, &error)) == NULL)
#else
if((pixbuf = gdk_pixbuf_new_from_file_at_size(preview->path, width,
height, &error)) == NULL)
#endif
{
helper->error(helper->browser, error->message, 1);
g_error_free(error);
return;
}
if(error != NULL)
{
helper->error(NULL, error->message, 1);
g_error_free(error);
}
gtk_image_set_from_pixbuf(GTK_IMAGE(preview->view_image_image), pixbuf);
g_object_unref(pixbuf);
}
static void _idle_image_scale(Preview * preview)
{
_idle_image_load(preview, 0, 0);
}
/* preview_on_idle_text */
static gboolean _preview_on_idle_text(gpointer data)
{
Preview * preview = data;
BrowserPluginHelper * helper = preview->helper;
GtkTextBuffer * tbuf;
GtkTextIter iter;
int fd;
char buf[256];
ssize_t s;
String const * p = NULL;
preview->source = 0;
gtk_widget_show(GTK_WIDGET(preview->copy));
gtk_widget_show(GTK_WIDGET(preview->select_all));
gtk_widget_show(preview->toolbar);
tbuf = preview->view_text_tbuf;
gtk_text_buffer_set_text(tbuf, "", 0);
gtk_text_buffer_get_end_iter(tbuf, &iter);
if((fd = open(preview->path, O_RDONLY)) < 0)
{
helper->error(helper->browser, strerror(errno), 1);
return FALSE;
}
/* FIXME use a GIOChannel instead */
while((s = read(fd, buf, sizeof(buf))) > 0)
{
if(p == NULL)
{
if((p = helper->config_get(helper->browser, "preview",
"ellipsize")) == NULL
|| strtol(p, NULL, 0) != 0)
{
if(s == sizeof(buf))
{
buf[sizeof(buf) - 3] = '.';
buf[sizeof(buf) - 2] = '.';
buf[sizeof(buf) - 1] = '.';
}
gtk_text_buffer_set_text(tbuf, buf, s);
break;
}
}
gtk_text_buffer_insert(preview->view_text_tbuf, &iter, buf, s);
}
close(fd);
gtk_widget_show(preview->view_text);
return FALSE;
}
/* preview_on_open */
static void _preview_on_open(gpointer data)
{
Preview * preview = data;
Mime * mime = preview->helper->get_mime(preview->helper->browser);
if(preview->path != NULL)
mime_action(mime, "open", preview->path);
}
/* preview_on_select_all */
static void _preview_on_select_all(gpointer data)
{
Preview * preview = data;
GtkTextIter start;
GtkTextIter end;
gtk_text_buffer_get_start_iter(preview->view_text_tbuf, &start);
gtk_text_buffer_get_end_iter(preview->view_text_tbuf, &end);
gtk_text_buffer_select_range(preview->view_text_tbuf, &start, &end);
}
/* preview_on_zoom_100 */
static void _preview_on_zoom_100(gpointer data)
{
Preview * preview = data;
preview->view_image_how = PREVIEW_IMAGE_HOW_ORIGINAL;
preview->view_image_scale = 1.0;
if(preview->source != 0)
g_source_remove(preview->source);
/* XXX may not always be an image */
preview->source = g_idle_add(_preview_on_idle_image, preview);
}
/* preview_on_zoom_fit */
static void _preview_on_zoom_fit(gpointer data)
{
Preview * preview = data;
preview->view_image_how = PREVIEW_IMAGE_HOW_FIT;
if(preview->source != 0)
g_source_remove(preview->source);
/* XXX may not always be an image */
preview->source = g_idle_add(_preview_on_idle_image, preview);
}
/* preview_on_zoom_in */
static void _preview_on_zoom_in(gpointer data)
{
Preview * preview = data;
preview->view_image_how = PREVIEW_IMAGE_HOW_SCALE;
preview->view_image_scale *= 1.25;
if(preview->view_image_scale > 4.0)
preview->view_image_scale = 4.0;
if(preview->source != 0)
g_source_remove(preview->source);
/* XXX may not always be an image */
preview->source = g_idle_add(_preview_on_idle_image, preview);
}
/* preview_on_zoom_out */
static void _preview_on_zoom_out(gpointer data)
{
Preview * preview = data;
preview->view_image_how = PREVIEW_IMAGE_HOW_SCALE;
preview->view_image_scale /= 1.25;
if(preview->view_image_scale < 0.1)
preview->view_image_scale = 0.1;
if(preview->source != 0)
g_source_remove(preview->source);
/* XXX may not always be an image */
preview->source = g_idle_add(_preview_on_idle_image, preview);
}