Adopt shorter identifiers
Also, slightly reformat the source code according to clang-format.
This commit is contained in:
parent
c136c089fa
commit
b78010ccb1
|
@ -44,7 +44,7 @@ The standard means to adjust the looks of the program is through GTK+ 3 CSS.
|
||||||
As an example, to tightly pack browser items, put the following in your
|
As an example, to tightly pack browser items, put the following in your
|
||||||
_~/.config/gtk-3.0/gtk.css_:
|
_~/.config/gtk-3.0/gtk.css_:
|
||||||
|
|
||||||
fastiv-browser { -FastivBrowser-spacing: 0; padding: 0; border: 0; margin: 0; }
|
fiv-browser { -FivBrowser-spacing: 0; padding: 0; border: 0; margin: 0; }
|
||||||
|
|
||||||
The GTK+ inspector will be very helpful, should you want to experiment.
|
The GTK+ inspector will be very helpful, should you want to experiment.
|
||||||
|
|
||||||
|
|
108
fastiv.c
108
fastiv.c
|
@ -28,10 +28,10 @@
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "fastiv-browser.h"
|
#include "fiv-browser.h"
|
||||||
#include "fastiv-io.h"
|
#include "fiv-io.h"
|
||||||
#include "fastiv-sidebar.h"
|
#include "fiv-sidebar.h"
|
||||||
#include "fastiv-view.h"
|
#include "fiv-view.h"
|
||||||
#include "xdg.h"
|
#include "xdg.h"
|
||||||
|
|
||||||
// --- Utilities ---------------------------------------------------------------
|
// --- Utilities ---------------------------------------------------------------
|
||||||
|
@ -191,10 +191,10 @@ load_directory(const gchar *dirname)
|
||||||
g.files_index = -1;
|
g.files_index = -1;
|
||||||
|
|
||||||
GFile *file = g_file_new_for_path(g.directory);
|
GFile *file = g_file_new_for_path(g.directory);
|
||||||
fastiv_sidebar_set_location(FASTIV_SIDEBAR(g.browser_sidebar), file);
|
fiv_sidebar_set_location(FIV_SIDEBAR(g.browser_sidebar), file);
|
||||||
g_object_unref(file);
|
g_object_unref(file);
|
||||||
fastiv_browser_load(FASTIV_BROWSER(g.browser),
|
fiv_browser_load(
|
||||||
g.filtering ? is_supported : NULL, g.directory);
|
FIV_BROWSER(g.browser), g.filtering ? is_supported : NULL, g.directory);
|
||||||
|
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GDir *dir = g_dir_open(g.directory, 0, &error);
|
GDir *dir = g_dir_open(g.directory, 0, &error);
|
||||||
|
@ -240,7 +240,7 @@ open(const gchar *path)
|
||||||
g_return_if_fail(g_path_is_absolute(path));
|
g_return_if_fail(g_path_is_absolute(path));
|
||||||
|
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
if (!fastiv_view_open(FASTIV_VIEW(g.view), path, &error)) {
|
if (!fiv_view_open(FIV_VIEW(g.view), path, &error)) {
|
||||||
char *base = g_filename_display_basename(path);
|
char *base = g_filename_display_basename(path);
|
||||||
g_prefix_error(&error, "%s: ", base);
|
g_prefix_error(&error, "%s: ", base);
|
||||||
show_error_dialog(error);
|
show_error_dialog(error);
|
||||||
|
@ -284,7 +284,7 @@ create_open_dialog(void)
|
||||||
"_Open", GTK_RESPONSE_ACCEPT, NULL);
|
"_Open", GTK_RESPONSE_ACCEPT, NULL);
|
||||||
|
|
||||||
GtkFileFilter *filter = gtk_file_filter_new();
|
GtkFileFilter *filter = gtk_file_filter_new();
|
||||||
for (const char **p = fastiv_io_supported_media_types; *p; p++)
|
for (const char **p = fiv_io_supported_media_types; *p; p++)
|
||||||
gtk_file_filter_add_mime_type(filter, *p);
|
gtk_file_filter_add_mime_type(filter, *p);
|
||||||
#ifdef HAVE_GDKPIXBUF
|
#ifdef HAVE_GDKPIXBUF
|
||||||
gtk_file_filter_add_pixbuf_formats(filter);
|
gtk_file_filter_add_pixbuf_formats(filter);
|
||||||
|
@ -356,13 +356,13 @@ spawn_path(const char *path)
|
||||||
{
|
{
|
||||||
char *argv[] = {PROJECT_NAME, (char *) path, NULL};
|
char *argv[] = {PROJECT_NAME, (char *) path, NULL};
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
|
g_spawn_async(
|
||||||
NULL, &error);
|
NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error);
|
||||||
g_clear_error(&error);
|
g_clear_error(&error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_item_activated(G_GNUC_UNUSED FastivBrowser *browser, GFile *location,
|
on_item_activated(G_GNUC_UNUSED FivBrowser *browser, GFile *location,
|
||||||
GtkPlacesOpenFlags flags, G_GNUC_UNUSED gpointer data)
|
GtkPlacesOpenFlags flags, G_GNUC_UNUSED gpointer data)
|
||||||
{
|
{
|
||||||
gchar *path = g_file_get_path(location);
|
gchar *path = g_file_get_path(location);
|
||||||
|
@ -416,12 +416,12 @@ on_open_location(G_GNUC_UNUSED GtkPlacesSidebar *sidebar, GFile *location,
|
||||||
static void
|
static void
|
||||||
on_toolbar_zoom(G_GNUC_UNUSED GtkButton *button, gpointer user_data)
|
on_toolbar_zoom(G_GNUC_UNUSED GtkButton *button, gpointer user_data)
|
||||||
{
|
{
|
||||||
FastivIoThumbnailSize size = FASTIV_IO_THUMBNAIL_SIZE_COUNT;
|
FivIoThumbnailSize size = FIV_IO_THUMBNAIL_SIZE_COUNT;
|
||||||
g_object_get(g.browser, "thumbnail-size", &size, NULL);
|
g_object_get(g.browser, "thumbnail-size", &size, NULL);
|
||||||
|
|
||||||
size += (gintptr) user_data;
|
size += (gintptr) user_data;
|
||||||
g_return_if_fail(size >= FASTIV_IO_THUMBNAIL_SIZE_MIN &&
|
g_return_if_fail(size >= FIV_IO_THUMBNAIL_SIZE_MIN &&
|
||||||
size <= FASTIV_IO_THUMBNAIL_SIZE_MAX);
|
size <= FIV_IO_THUMBNAIL_SIZE_MAX);
|
||||||
|
|
||||||
g_object_set(g.browser, "thumbnail-size", size, NULL);
|
g_object_set(g.browser, "thumbnail-size", size, NULL);
|
||||||
}
|
}
|
||||||
|
@ -430,10 +430,10 @@ static void
|
||||||
on_notify_thumbnail_size(
|
on_notify_thumbnail_size(
|
||||||
GObject *object, GParamSpec *param_spec, G_GNUC_UNUSED gpointer user_data)
|
GObject *object, GParamSpec *param_spec, G_GNUC_UNUSED gpointer user_data)
|
||||||
{
|
{
|
||||||
FastivIoThumbnailSize size = 0;
|
FivIoThumbnailSize size = 0;
|
||||||
g_object_get(object, g_param_spec_get_name(param_spec), &size, NULL);
|
g_object_get(object, g_param_spec_get_name(param_spec), &size, NULL);
|
||||||
gtk_widget_set_sensitive(g.plus, size < FASTIV_IO_THUMBNAIL_SIZE_MAX);
|
gtk_widget_set_sensitive(g.plus, size < FIV_IO_THUMBNAIL_SIZE_MAX);
|
||||||
gtk_widget_set_sensitive(g.minus, size > FASTIV_IO_THUMBNAIL_SIZE_MIN);
|
gtk_widget_set_sensitive(g.minus, size > FIV_IO_THUMBNAIL_SIZE_MIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -482,8 +482,7 @@ on_key_press(G_GNUC_UNUSED GtkWidget *widget, GdkEventKey *event,
|
||||||
on_open();
|
on_open();
|
||||||
return TRUE;
|
return TRUE;
|
||||||
case GDK_KEY_l:
|
case GDK_KEY_l:
|
||||||
fastiv_sidebar_show_enter_location(
|
fiv_sidebar_show_enter_location(FIV_SIDEBAR(g.browser_sidebar));
|
||||||
FASTIV_SIDEBAR(g.browser_sidebar));
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
case GDK_KEY_n:
|
case GDK_KEY_n:
|
||||||
spawn_path(g.directory);
|
spawn_path(g.directory);
|
||||||
|
@ -641,11 +640,11 @@ toolbar_connect(int index, GCallback callback)
|
||||||
static void
|
static void
|
||||||
on_command(intptr_t command)
|
on_command(intptr_t command)
|
||||||
{
|
{
|
||||||
fastiv_view_command(FASTIV_VIEW(g.view), command);
|
fiv_view_command(FIV_VIEW(g.view), command);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
toolbar_command(int index, FastivViewCommand command)
|
toolbar_command(int index, FivViewCommand command)
|
||||||
{
|
{
|
||||||
g_signal_connect_swapped(g.toolbar[index], "clicked",
|
g_signal_connect_swapped(g.toolbar[index], "clicked",
|
||||||
G_CALLBACK(on_command), (void *) (intptr_t) command);
|
G_CALLBACK(on_command), (void *) (intptr_t) command);
|
||||||
|
@ -677,21 +676,21 @@ make_view_toolbar(void)
|
||||||
toolbar_connect(TOOLBAR_BROWSE, G_CALLBACK(switch_to_browser));
|
toolbar_connect(TOOLBAR_BROWSE, G_CALLBACK(switch_to_browser));
|
||||||
toolbar_connect(TOOLBAR_FILE_PREVIOUS, G_CALLBACK(on_previous));
|
toolbar_connect(TOOLBAR_FILE_PREVIOUS, G_CALLBACK(on_previous));
|
||||||
toolbar_connect(TOOLBAR_FILE_NEXT, G_CALLBACK(on_next));
|
toolbar_connect(TOOLBAR_FILE_NEXT, G_CALLBACK(on_next));
|
||||||
toolbar_command(TOOLBAR_PAGE_FIRST, FASTIV_VIEW_COMMAND_PAGE_FIRST);
|
toolbar_command(TOOLBAR_PAGE_FIRST, FIV_VIEW_COMMAND_PAGE_FIRST);
|
||||||
toolbar_command(TOOLBAR_PAGE_PREVIOUS, FASTIV_VIEW_COMMAND_PAGE_PREVIOUS);
|
toolbar_command(TOOLBAR_PAGE_PREVIOUS, FIV_VIEW_COMMAND_PAGE_PREVIOUS);
|
||||||
toolbar_command(TOOLBAR_PAGE_NEXT, FASTIV_VIEW_COMMAND_PAGE_NEXT);
|
toolbar_command(TOOLBAR_PAGE_NEXT, FIV_VIEW_COMMAND_PAGE_NEXT);
|
||||||
toolbar_command(TOOLBAR_PAGE_LAST, FASTIV_VIEW_COMMAND_PAGE_LAST);
|
toolbar_command(TOOLBAR_PAGE_LAST, FIV_VIEW_COMMAND_PAGE_LAST);
|
||||||
toolbar_command(TOOLBAR_SKIP_BACK, FASTIV_VIEW_COMMAND_FRAME_FIRST);
|
toolbar_command(TOOLBAR_SKIP_BACK, FIV_VIEW_COMMAND_FRAME_FIRST);
|
||||||
toolbar_command(TOOLBAR_SEEK_BACK, FASTIV_VIEW_COMMAND_FRAME_PREVIOUS);
|
toolbar_command(TOOLBAR_SEEK_BACK, FIV_VIEW_COMMAND_FRAME_PREVIOUS);
|
||||||
toolbar_command(TOOLBAR_SEEK_FORWARD, FASTIV_VIEW_COMMAND_FRAME_NEXT);
|
toolbar_command(TOOLBAR_SEEK_FORWARD, FIV_VIEW_COMMAND_FRAME_NEXT);
|
||||||
toolbar_command(TOOLBAR_PLUS, FASTIV_VIEW_COMMAND_ZOOM_IN);
|
toolbar_command(TOOLBAR_PLUS, FIV_VIEW_COMMAND_ZOOM_IN);
|
||||||
toolbar_command(TOOLBAR_MINUS, FASTIV_VIEW_COMMAND_ZOOM_OUT);
|
toolbar_command(TOOLBAR_MINUS, FIV_VIEW_COMMAND_ZOOM_OUT);
|
||||||
toolbar_command(TOOLBAR_ONE, FASTIV_VIEW_COMMAND_ZOOM_1);
|
toolbar_command(TOOLBAR_ONE, FIV_VIEW_COMMAND_ZOOM_1);
|
||||||
toolbar_command(TOOLBAR_PRINT, FASTIV_VIEW_COMMAND_PRINT);
|
toolbar_command(TOOLBAR_PRINT, FIV_VIEW_COMMAND_PRINT);
|
||||||
toolbar_command(TOOLBAR_SAVE, FASTIV_VIEW_COMMAND_SAVE_PAGE);
|
toolbar_command(TOOLBAR_SAVE, FIV_VIEW_COMMAND_SAVE_PAGE);
|
||||||
toolbar_command(TOOLBAR_LEFT, FASTIV_VIEW_COMMAND_ROTATE_LEFT);
|
toolbar_command(TOOLBAR_LEFT, FIV_VIEW_COMMAND_ROTATE_LEFT);
|
||||||
toolbar_command(TOOLBAR_MIRROR, FASTIV_VIEW_COMMAND_MIRROR);
|
toolbar_command(TOOLBAR_MIRROR, FIV_VIEW_COMMAND_MIRROR);
|
||||||
toolbar_command(TOOLBAR_RIGHT, FASTIV_VIEW_COMMAND_ROTATE_RIGHT);
|
toolbar_command(TOOLBAR_RIGHT, FIV_VIEW_COMMAND_ROTATE_RIGHT);
|
||||||
toolbar_connect(TOOLBAR_FULLSCREEN, G_CALLBACK(toggle_fullscreen));
|
toolbar_connect(TOOLBAR_FULLSCREEN, G_CALLBACK(toggle_fullscreen));
|
||||||
return view_toolbar;
|
return view_toolbar;
|
||||||
}
|
}
|
||||||
|
@ -724,7 +723,7 @@ main(int argc, char *argv[])
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (show_supported_media_types) {
|
if (show_supported_media_types) {
|
||||||
for (char **types = fastiv_io_all_supported_media_types(); *types; )
|
for (char **types = fiv_io_all_supported_media_types(); *types; )
|
||||||
g_print("%s\n", *types++);
|
g_print("%s\n", *types++);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -747,29 +746,29 @@ main(int argc, char *argv[])
|
||||||
// XXX: button.flat is too generic, it's only for the view toolbar.
|
// XXX: button.flat is too generic, it's only for the view toolbar.
|
||||||
// XXX: Similarly, box > separator.horizontal is a temporary hack.
|
// XXX: Similarly, box > separator.horizontal is a temporary hack.
|
||||||
// Consider using a #name or a .class here, possibly for a parent widget.
|
// Consider using a #name or a .class here, possibly for a parent widget.
|
||||||
const char *style = "@define-color fastiv-tile #3c3c3c; \
|
const char *style = "@define-color fiv-tile #3c3c3c; \
|
||||||
fastiv-view, fastiv-browser { background: @content_view_bg; } \
|
fiv-view, fiv-browser { background: @content_view_bg; } \
|
||||||
placessidebar.fastiv .toolbar { padding: 2px 6px; } \
|
placessidebar.fiv .toolbar { padding: 2px 6px; } \
|
||||||
placessidebar.fastiv box > separator { margin: 4px 0; } \
|
placessidebar.fiv box > separator { margin: 4px 0; } \
|
||||||
button.flat { padding-left: 0; padding-right: 0 } \
|
button.flat { padding-left: 0; padding-right: 0 } \
|
||||||
box > separator.horizontal { \
|
box > separator.horizontal { \
|
||||||
background: mix(@insensitive_fg_color, \
|
background: mix(@insensitive_fg_color, \
|
||||||
@insensitive_bg_color, 0.4); margin: 6px 0; \
|
@insensitive_bg_color, 0.4); margin: 6px 0; \
|
||||||
} \
|
} \
|
||||||
fastiv-browser { padding: 5px; } \
|
fiv-browser { padding: 5px; } \
|
||||||
fastiv-browser.item { \
|
fiv-browser.item { \
|
||||||
border: 1px solid rgba(255, 255, 255, 0.375); \
|
border: 1px solid rgba(255, 255, 255, 0.375); \
|
||||||
margin: 10px; color: #000; \
|
margin: 10px; color: #000; \
|
||||||
background: #333; \
|
background: #333; \
|
||||||
background-image: \
|
background-image: \
|
||||||
linear-gradient(45deg, @fastiv-tile 26%, transparent 26%), \
|
linear-gradient(45deg, @fiv-tile 26%, transparent 26%), \
|
||||||
linear-gradient(-45deg, @fastiv-tile 26%, transparent 26%), \
|
linear-gradient(-45deg, @fiv-tile 26%, transparent 26%), \
|
||||||
linear-gradient(45deg, transparent 74%, @fastiv-tile 74%), \
|
linear-gradient(45deg, transparent 74%, @fiv-tile 74%), \
|
||||||
linear-gradient(-45deg, transparent 74%, @fastiv-tile 74%); \
|
linear-gradient(-45deg, transparent 74%, @fiv-tile 74%); \
|
||||||
background-size: 40px 40px; \
|
background-size: 40px 40px; \
|
||||||
background-position: 0 0, 0 20px, 20px -20px, -20px 0px; \
|
background-position: 0 0, 0 20px, 20px -20px, -20px 0px; \
|
||||||
} \
|
} \
|
||||||
fastiv-browser.item.symbolic { \
|
fiv-browser.item.symbolic { \
|
||||||
border-color: transparent; color: @content_view_bg; \
|
border-color: transparent; color: @content_view_bg; \
|
||||||
background: @theme_bg_color; background-image: none; \
|
background: @theme_bg_color; background-image: none; \
|
||||||
}";
|
}";
|
||||||
|
@ -781,7 +780,7 @@ main(int argc, char *argv[])
|
||||||
g_object_unref(provider);
|
g_object_unref(provider);
|
||||||
|
|
||||||
GtkWidget *view_scroller = gtk_scrolled_window_new(NULL, NULL);
|
GtkWidget *view_scroller = gtk_scrolled_window_new(NULL, NULL);
|
||||||
g.view = g_object_new(FASTIV_TYPE_VIEW, NULL);
|
g.view = g_object_new(FIV_TYPE_VIEW, NULL);
|
||||||
g_signal_connect(g.view, "key-press-event",
|
g_signal_connect(g.view, "key-press-event",
|
||||||
G_CALLBACK(on_key_press_view), NULL);
|
G_CALLBACK(on_key_press_view), NULL);
|
||||||
g_signal_connect(g.view, "button-press-event",
|
g_signal_connect(g.view, "button-press-event",
|
||||||
|
@ -806,7 +805,7 @@ main(int argc, char *argv[])
|
||||||
gtk_widget_show_all(g.view_box);
|
gtk_widget_show_all(g.view_box);
|
||||||
|
|
||||||
g.browser_scroller = gtk_scrolled_window_new(NULL, NULL);
|
g.browser_scroller = gtk_scrolled_window_new(NULL, NULL);
|
||||||
g.browser = g_object_new(FASTIV_TYPE_BROWSER, NULL);
|
g.browser = g_object_new(FIV_TYPE_BROWSER, NULL);
|
||||||
gtk_widget_set_vexpand(g.browser, TRUE);
|
gtk_widget_set_vexpand(g.browser, TRUE);
|
||||||
gtk_widget_set_hexpand(g.browser, TRUE);
|
gtk_widget_set_hexpand(g.browser, TRUE);
|
||||||
g_signal_connect(g.browser, "item-activated",
|
g_signal_connect(g.browser, "item-activated",
|
||||||
|
@ -824,7 +823,7 @@ main(int argc, char *argv[])
|
||||||
// - C-h to filtering,
|
// - C-h to filtering,
|
||||||
// - M-Up to going a level above,
|
// - M-Up to going a level above,
|
||||||
// - mayhaps forward the rest to the sidebar, somehow.
|
// - mayhaps forward the rest to the sidebar, somehow.
|
||||||
g.browser_sidebar = g_object_new(FASTIV_TYPE_SIDEBAR, NULL);
|
g.browser_sidebar = g_object_new(FIV_TYPE_SIDEBAR, NULL);
|
||||||
g_signal_connect(g.browser_sidebar, "open-location",
|
g_signal_connect(g.browser_sidebar, "open-location",
|
||||||
G_CALLBACK(on_open_location), NULL);
|
G_CALLBACK(on_open_location), NULL);
|
||||||
|
|
||||||
|
@ -862,8 +861,7 @@ main(int argc, char *argv[])
|
||||||
g_signal_connect(funnel, "toggled",
|
g_signal_connect(funnel, "toggled",
|
||||||
G_CALLBACK(on_filtering_toggled), NULL);
|
G_CALLBACK(on_filtering_toggled), NULL);
|
||||||
|
|
||||||
GtkBox *toolbar =
|
GtkBox *toolbar = fiv_sidebar_get_toolbar(FIV_SIDEBAR(g.browser_sidebar));
|
||||||
fastiv_sidebar_get_toolbar(FASTIV_SIDEBAR(g.browser_sidebar));
|
|
||||||
gtk_box_pack_start(toolbar, zoom_group, FALSE, FALSE, 0);
|
gtk_box_pack_start(toolbar, zoom_group, FALSE, FALSE, 0);
|
||||||
gtk_box_pack_start(toolbar, funnel, FALSE, FALSE, 0);
|
gtk_box_pack_start(toolbar, funnel, FALSE, FALSE, 0);
|
||||||
gtk_widget_set_halign(GTK_WIDGET(toolbar), GTK_ALIGN_CENTER);
|
gtk_widget_set_halign(GTK_WIDGET(toolbar), GTK_ALIGN_CENTER);
|
||||||
|
@ -890,7 +888,7 @@ main(int argc, char *argv[])
|
||||||
G_CALLBACK(on_window_state_event), NULL);
|
G_CALLBACK(on_window_state_event), NULL);
|
||||||
gtk_container_add(GTK_CONTAINER(g.window), g.stack);
|
gtk_container_add(GTK_CONTAINER(g.window), g.stack);
|
||||||
|
|
||||||
char **types = fastiv_io_all_supported_media_types();
|
char **types = fiv_io_all_supported_media_types();
|
||||||
g.supported_globs = extract_mime_globs((const char **) types);
|
g.supported_globs = extract_mime_globs((const char **) types);
|
||||||
g_strfreev(types);
|
g_strfreev(types);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// fastiv-browser.c: fast image viewer - filesystem browser widget
|
// fiv-browser.c: fast image viewer - filesystem browser widget
|
||||||
//
|
//
|
||||||
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
||||||
//
|
//
|
||||||
|
@ -18,9 +18,9 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
|
|
||||||
#include "fastiv-browser.h"
|
#include "fiv-browser.h"
|
||||||
#include "fastiv-io.h"
|
#include "fiv-io.h"
|
||||||
#include "fastiv-view.h"
|
#include "fiv-view.h"
|
||||||
|
|
||||||
// --- Widget ------------------------------------------------------------------
|
// --- Widget ------------------------------------------------------------------
|
||||||
// _________________________________
|
// _________________________________
|
||||||
|
@ -38,10 +38,10 @@
|
||||||
// The glow is actually a glowing margin, the border is rendered in two parts.
|
// The glow is actually a glowing margin, the border is rendered in two parts.
|
||||||
//
|
//
|
||||||
|
|
||||||
struct _FastivBrowser {
|
struct _FivBrowser {
|
||||||
GtkWidget parent_instance;
|
GtkWidget parent_instance;
|
||||||
|
|
||||||
FastivIoThumbnailSize item_size; ///< Thumbnail size
|
FivIoThumbnailSize item_size; ///< Thumbnail size
|
||||||
int item_height; ///< Thumbnail height in pixels
|
int item_height; ///< Thumbnail height in pixels
|
||||||
int item_spacing; ///< Space between items in pixels
|
int item_spacing; ///< Space between items in pixels
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ row_free(Row *self)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
static void
|
static void
|
||||||
append_row(FastivBrowser *self, int *y, int x, GArray *items_array)
|
append_row(FivBrowser *self, int *y, int x, GArray *items_array)
|
||||||
{
|
{
|
||||||
if (self->layouted_rows->len)
|
if (self->layouted_rows->len)
|
||||||
*y += self->item_spacing;
|
*y += self->item_spacing;
|
||||||
|
@ -117,7 +117,7 @@ append_row(FastivBrowser *self, int *y, int x, GArray *items_array)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
relayout(FastivBrowser *self, int width)
|
relayout(FivBrowser *self, int width)
|
||||||
{
|
{
|
||||||
GtkWidget *widget = GTK_WIDGET(self);
|
GtkWidget *widget = GTK_WIDGET(self);
|
||||||
GtkStyleContext *style = gtk_widget_get_style_context(widget);
|
GtkStyleContext *style = gtk_widget_get_style_context(widget);
|
||||||
|
@ -161,7 +161,7 @@ relayout(FastivBrowser *self, int width)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
draw_outer_border(FastivBrowser *self, cairo_t *cr, int width, int height)
|
draw_outer_border(FivBrowser *self, cairo_t *cr, int width, int height)
|
||||||
{
|
{
|
||||||
int offset_x = cairo_image_surface_get_width(self->glow);
|
int offset_x = cairo_image_surface_get_width(self->glow);
|
||||||
int offset_y = cairo_image_surface_get_height(self->glow);
|
int offset_y = cairo_image_surface_get_height(self->glow);
|
||||||
|
@ -197,7 +197,7 @@ draw_outer_border(FastivBrowser *self, cairo_t *cr, int width, int height)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GdkRectangle
|
static GdkRectangle
|
||||||
item_extents(FastivBrowser *self, const Item *item, const Row *row)
|
item_extents(FivBrowser *self, const Item *item, const Row *row)
|
||||||
{
|
{
|
||||||
int width = cairo_image_surface_get_width(item->entry->thumbnail);
|
int width = cairo_image_surface_get_width(item->entry->thumbnail);
|
||||||
int height = cairo_image_surface_get_height(item->entry->thumbnail);
|
int height = cairo_image_surface_get_height(item->entry->thumbnail);
|
||||||
|
@ -210,7 +210,7 @@ item_extents(FastivBrowser *self, const Item *item, const Row *row)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const Entry *
|
static const Entry *
|
||||||
entry_at(FastivBrowser *self, int x, int y)
|
entry_at(FivBrowser *self, int x, int y)
|
||||||
{
|
{
|
||||||
for (guint i = 0; i < self->layouted_rows->len; i++) {
|
for (guint i = 0; i < self->layouted_rows->len; i++) {
|
||||||
const Row *row = &g_array_index(self->layouted_rows, Row, i);
|
const Row *row = &g_array_index(self->layouted_rows, Row, i);
|
||||||
|
@ -227,7 +227,7 @@ entry_at(FastivBrowser *self, int x, int y)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
draw_row(FastivBrowser *self, cairo_t *cr, const Row *row)
|
draw_row(FivBrowser *self, cairo_t *cr, const Row *row)
|
||||||
{
|
{
|
||||||
GtkStyleContext *style = gtk_widget_get_style_context(GTK_WIDGET(self));
|
GtkStyleContext *style = gtk_widget_get_style_context(GTK_WIDGET(self));
|
||||||
gtk_style_context_save(style);
|
gtk_style_context_save(style);
|
||||||
|
@ -350,10 +350,10 @@ entry_add_thumbnail(gpointer data, gpointer user_data)
|
||||||
g_clear_object(&self->icon);
|
g_clear_object(&self->icon);
|
||||||
g_clear_pointer(&self->thumbnail, cairo_surface_destroy);
|
g_clear_pointer(&self->thumbnail, cairo_surface_destroy);
|
||||||
|
|
||||||
FastivBrowser *browser = FASTIV_BROWSER(user_data);
|
FivBrowser *browser = FIV_BROWSER(user_data);
|
||||||
GFile *file = g_file_new_for_uri(self->uri);
|
GFile *file = g_file_new_for_uri(self->uri);
|
||||||
self->thumbnail = rescale_thumbnail(
|
self->thumbnail = rescale_thumbnail(
|
||||||
fastiv_io_lookup_thumbnail(file, browser->item_size),
|
fiv_io_lookup_thumbnail(file, browser->item_size),
|
||||||
browser->item_height);
|
browser->item_height);
|
||||||
if (self->thumbnail)
|
if (self->thumbnail)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -375,7 +375,7 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
materialize_icon(FastivBrowser *self, Entry *entry)
|
materialize_icon(FivBrowser *self, Entry *entry)
|
||||||
{
|
{
|
||||||
if (!entry->icon)
|
if (!entry->icon)
|
||||||
return;
|
return;
|
||||||
|
@ -419,7 +419,7 @@ materialize_icon(FastivBrowser *self, Entry *entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
reload_thumbnails(FastivBrowser *self)
|
reload_thumbnails(FivBrowser *self)
|
||||||
{
|
{
|
||||||
GThreadPool *pool = g_thread_pool_new(
|
GThreadPool *pool = g_thread_pool_new(
|
||||||
entry_add_thumbnail, self, g_get_num_processors(), FALSE, NULL);
|
entry_add_thumbnail, self, g_get_num_processors(), FALSE, NULL);
|
||||||
|
@ -597,9 +597,9 @@ show_context_menu(GtkWidget *widget, const char *uri)
|
||||||
// --- Boilerplate -------------------------------------------------------------
|
// --- Boilerplate -------------------------------------------------------------
|
||||||
|
|
||||||
// TODO(p): For proper navigation, we need to implement GtkScrollable.
|
// TODO(p): For proper navigation, we need to implement GtkScrollable.
|
||||||
G_DEFINE_TYPE_EXTENDED(FastivBrowser, fastiv_browser, GTK_TYPE_WIDGET, 0,
|
G_DEFINE_TYPE_EXTENDED(FivBrowser, fiv_browser, GTK_TYPE_WIDGET, 0,
|
||||||
/* G_IMPLEMENT_INTERFACE(GTK_TYPE_SCROLLABLE,
|
/* G_IMPLEMENT_INTERFACE(GTK_TYPE_SCROLLABLE,
|
||||||
fastiv_browser_scrollable_init) */)
|
fiv_browser_scrollable_init) */)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PROP_THUMBNAIL_SIZE = 1,
|
PROP_THUMBNAIL_SIZE = 1,
|
||||||
|
@ -617,22 +617,22 @@ enum {
|
||||||
static guint browser_signals[LAST_SIGNAL];
|
static guint browser_signals[LAST_SIGNAL];
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_browser_finalize(GObject *gobject)
|
fiv_browser_finalize(GObject *gobject)
|
||||||
{
|
{
|
||||||
FastivBrowser *self = FASTIV_BROWSER(gobject);
|
FivBrowser *self = FIV_BROWSER(gobject);
|
||||||
g_array_free(self->entries, TRUE);
|
g_array_free(self->entries, TRUE);
|
||||||
g_array_free(self->layouted_rows, TRUE);
|
g_array_free(self->layouted_rows, TRUE);
|
||||||
cairo_surface_destroy(self->glow);
|
cairo_surface_destroy(self->glow);
|
||||||
g_clear_object(&self->pointer);
|
g_clear_object(&self->pointer);
|
||||||
|
|
||||||
G_OBJECT_CLASS(fastiv_browser_parent_class)->finalize(gobject);
|
G_OBJECT_CLASS(fiv_browser_parent_class)->finalize(gobject);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_browser_get_property(
|
fiv_browser_get_property(
|
||||||
GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
|
GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
|
||||||
{
|
{
|
||||||
FastivBrowser *self = FASTIV_BROWSER(object);
|
FivBrowser *self = FIV_BROWSER(object);
|
||||||
switch (property_id) {
|
switch (property_id) {
|
||||||
case PROP_THUMBNAIL_SIZE:
|
case PROP_THUMBNAIL_SIZE:
|
||||||
g_value_set_enum(value, self->item_size);
|
g_value_set_enum(value, self->item_size);
|
||||||
|
@ -643,15 +643,14 @@ fastiv_browser_get_property(
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_item_size(FastivBrowser *self, FastivIoThumbnailSize size)
|
set_item_size(FivBrowser *self, FivIoThumbnailSize size)
|
||||||
{
|
{
|
||||||
if (size < FASTIV_IO_THUMBNAIL_SIZE_MIN ||
|
if (size < FIV_IO_THUMBNAIL_SIZE_MIN || size > FIV_IO_THUMBNAIL_SIZE_MAX)
|
||||||
size > FASTIV_IO_THUMBNAIL_SIZE_MAX)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (size != self->item_size) {
|
if (size != self->item_size) {
|
||||||
self->item_size = size;
|
self->item_size = size;
|
||||||
self->item_height = fastiv_io_thumbnail_sizes[self->item_size].size;
|
self->item_height = fiv_io_thumbnail_sizes[self->item_size].size;
|
||||||
reload_thumbnails(self);
|
reload_thumbnails(self);
|
||||||
|
|
||||||
g_object_notify_by_pspec(
|
g_object_notify_by_pspec(
|
||||||
|
@ -660,10 +659,10 @@ set_item_size(FastivBrowser *self, FastivIoThumbnailSize size)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_browser_set_property(
|
fiv_browser_set_property(
|
||||||
GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
|
GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
|
||||||
{
|
{
|
||||||
FastivBrowser *self = FASTIV_BROWSER(object);
|
FivBrowser *self = FIV_BROWSER(object);
|
||||||
switch (property_id) {
|
switch (property_id) {
|
||||||
case PROP_THUMBNAIL_SIZE:
|
case PROP_THUMBNAIL_SIZE:
|
||||||
set_item_size(self, g_value_get_enum(value));
|
set_item_size(self, g_value_get_enum(value));
|
||||||
|
@ -674,35 +673,33 @@ fastiv_browser_set_property(
|
||||||
}
|
}
|
||||||
|
|
||||||
static GtkSizeRequestMode
|
static GtkSizeRequestMode
|
||||||
fastiv_browser_get_request_mode(G_GNUC_UNUSED GtkWidget *widget)
|
fiv_browser_get_request_mode(G_GNUC_UNUSED GtkWidget *widget)
|
||||||
{
|
{
|
||||||
return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
|
return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_browser_get_preferred_width(
|
fiv_browser_get_preferred_width(GtkWidget *widget, gint *minimum, gint *natural)
|
||||||
GtkWidget *widget, gint *minimum, gint *natural)
|
|
||||||
{
|
{
|
||||||
FastivBrowser *self = FASTIV_BROWSER(widget);
|
FivBrowser *self = FIV_BROWSER(widget);
|
||||||
GtkStyleContext *style = gtk_widget_get_style_context(widget);
|
GtkStyleContext *style = gtk_widget_get_style_context(widget);
|
||||||
|
|
||||||
GtkBorder padding = {};
|
GtkBorder padding = {};
|
||||||
gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
|
gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
|
||||||
*minimum = *natural =
|
*minimum = *natural = g_permitted_width_multiplier * self->item_height +
|
||||||
g_permitted_width_multiplier * self->item_height +
|
|
||||||
padding.left + 2 * self->item_border_x + padding.right;
|
padding.left + 2 * self->item_border_x + padding.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_browser_get_preferred_height_for_width(
|
fiv_browser_get_preferred_height_for_width(
|
||||||
GtkWidget *widget, gint width, gint *minimum, gint *natural)
|
GtkWidget *widget, gint width, gint *minimum, gint *natural)
|
||||||
{
|
{
|
||||||
// XXX: This is rather ugly, the caller is only asking.
|
// XXX: This is rather ugly, the caller is only asking.
|
||||||
*minimum = *natural = relayout(FASTIV_BROWSER(widget), width);
|
*minimum = *natural = relayout(FIV_BROWSER(widget), width);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_browser_realize(GtkWidget *widget)
|
fiv_browser_realize(GtkWidget *widget)
|
||||||
{
|
{
|
||||||
GtkAllocation allocation;
|
GtkAllocation allocation;
|
||||||
gtk_widget_get_allocation(widget, &allocation);
|
gtk_widget_get_allocation(widget, &allocation);
|
||||||
|
@ -720,8 +717,7 @@ fastiv_browser_realize(GtkWidget *widget)
|
||||||
|
|
||||||
.visual = gtk_widget_get_visual(widget),
|
.visual = gtk_widget_get_visual(widget),
|
||||||
.event_mask = gtk_widget_get_events(widget) | GDK_KEY_PRESS_MASK |
|
.event_mask = gtk_widget_get_events(widget) | GDK_KEY_PRESS_MASK |
|
||||||
GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK |
|
GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_SCROLL_MASK,
|
||||||
GDK_SCROLL_MASK,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// We need this window to receive input events at all.
|
// We need this window to receive input events at all.
|
||||||
|
@ -732,25 +728,25 @@ fastiv_browser_realize(GtkWidget *widget)
|
||||||
gtk_widget_set_window(widget, window);
|
gtk_widget_set_window(widget, window);
|
||||||
gtk_widget_set_realized(widget, TRUE);
|
gtk_widget_set_realized(widget, TRUE);
|
||||||
|
|
||||||
FastivBrowser *self = FASTIV_BROWSER(widget);
|
FivBrowser *self = FIV_BROWSER(widget);
|
||||||
g_clear_object(&self->pointer);
|
g_clear_object(&self->pointer);
|
||||||
self->pointer =
|
self->pointer =
|
||||||
gdk_cursor_new_from_name(gdk_window_get_display(window), "pointer");
|
gdk_cursor_new_from_name(gdk_window_get_display(window), "pointer");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_browser_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
|
fiv_browser_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
|
||||||
{
|
{
|
||||||
GTK_WIDGET_CLASS(fastiv_browser_parent_class)
|
GTK_WIDGET_CLASS(fiv_browser_parent_class)
|
||||||
->size_allocate(widget, allocation);
|
->size_allocate(widget, allocation);
|
||||||
|
|
||||||
relayout(FASTIV_BROWSER(widget), allocation->width);
|
relayout(FIV_BROWSER(widget), allocation->width);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fastiv_browser_draw(GtkWidget *widget, cairo_t *cr)
|
fiv_browser_draw(GtkWidget *widget, cairo_t *cr)
|
||||||
{
|
{
|
||||||
FastivBrowser *self = FASTIV_BROWSER(widget);
|
FivBrowser *self = FIV_BROWSER(widget);
|
||||||
if (!gtk_cairo_should_draw_window(cr, gtk_widget_get_window(widget)))
|
if (!gtk_cairo_should_draw_window(cr, gtk_widget_get_window(widget)))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
@ -787,12 +783,12 @@ open_entry(GtkWidget *self, const Entry *entry, gboolean new_window)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fastiv_browser_button_press_event(GtkWidget *widget, GdkEventButton *event)
|
fiv_browser_button_press_event(GtkWidget *widget, GdkEventButton *event)
|
||||||
{
|
{
|
||||||
GTK_WIDGET_CLASS(fastiv_browser_parent_class)
|
GTK_WIDGET_CLASS(fiv_browser_parent_class)
|
||||||
->button_press_event(widget, event);
|
->button_press_event(widget, event);
|
||||||
|
|
||||||
FastivBrowser *self = FASTIV_BROWSER(widget);
|
FivBrowser *self = FIV_BROWSER(widget);
|
||||||
if (event->type != GDK_BUTTON_PRESS)
|
if (event->type != GDK_BUTTON_PRESS)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
@ -828,12 +824,12 @@ fastiv_browser_button_press_event(GtkWidget *widget, GdkEventButton *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
fastiv_browser_motion_notify_event(GtkWidget *widget, GdkEventMotion *event)
|
fiv_browser_motion_notify_event(GtkWidget *widget, GdkEventMotion *event)
|
||||||
{
|
{
|
||||||
GTK_WIDGET_CLASS(fastiv_browser_parent_class)
|
GTK_WIDGET_CLASS(fiv_browser_parent_class)
|
||||||
->motion_notify_event(widget, event);
|
->motion_notify_event(widget, event);
|
||||||
|
|
||||||
FastivBrowser *self = FASTIV_BROWSER(widget);
|
FivBrowser *self = FIV_BROWSER(widget);
|
||||||
if (event->state != 0)
|
if (event->state != 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
@ -844,9 +840,9 @@ fastiv_browser_motion_notify_event(GtkWidget *widget, GdkEventMotion *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fastiv_browser_scroll_event(GtkWidget *widget, GdkEventScroll *event)
|
fiv_browser_scroll_event(GtkWidget *widget, GdkEventScroll *event)
|
||||||
{
|
{
|
||||||
FastivBrowser *self = FASTIV_BROWSER(widget);
|
FivBrowser *self = FIV_BROWSER(widget);
|
||||||
if ((event->state & gtk_accelerator_get_default_mod_mask()) !=
|
if ((event->state & gtk_accelerator_get_default_mod_mask()) !=
|
||||||
GDK_CONTROL_MASK)
|
GDK_CONTROL_MASK)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -866,10 +862,10 @@ fastiv_browser_scroll_event(GtkWidget *widget, GdkEventScroll *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fastiv_browser_query_tooltip(GtkWidget *widget, gint x, gint y,
|
fiv_browser_query_tooltip(GtkWidget *widget, gint x, gint y,
|
||||||
G_GNUC_UNUSED gboolean keyboard_tooltip, GtkTooltip *tooltip)
|
G_GNUC_UNUSED gboolean keyboard_tooltip, GtkTooltip *tooltip)
|
||||||
{
|
{
|
||||||
FastivBrowser *self = FASTIV_BROWSER(widget);
|
FivBrowser *self = FIV_BROWSER(widget);
|
||||||
const Entry *entry = entry_at(self, x, y);
|
const Entry *entry = entry_at(self, x, y);
|
||||||
if (!entry)
|
if (!entry)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -889,11 +885,11 @@ fastiv_browser_query_tooltip(GtkWidget *widget, gint x, gint y,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_browser_style_updated(GtkWidget *widget)
|
fiv_browser_style_updated(GtkWidget *widget)
|
||||||
{
|
{
|
||||||
GTK_WIDGET_CLASS(fastiv_browser_parent_class)->style_updated(widget);
|
GTK_WIDGET_CLASS(fiv_browser_parent_class)->style_updated(widget);
|
||||||
|
|
||||||
FastivBrowser *self = FASTIV_BROWSER(widget);
|
FivBrowser *self = FIV_BROWSER(widget);
|
||||||
GtkStyleContext *style = gtk_widget_get_style_context(widget);
|
GtkStyleContext *style = gtk_widget_get_style_context(widget);
|
||||||
GtkBorder border = {}, margin = {};
|
GtkBorder border = {}, margin = {};
|
||||||
|
|
||||||
|
@ -931,8 +927,7 @@ fastiv_browser_style_updated(GtkWidget *widget)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->glow =
|
self->glow = cairo_image_surface_create(CAIRO_FORMAT_A8, glow_w, glow_h);
|
||||||
cairo_image_surface_create(CAIRO_FORMAT_A8, glow_w, glow_h);
|
|
||||||
unsigned char *data = cairo_image_surface_get_data(self->glow);
|
unsigned char *data = cairo_image_surface_get_data(self->glow);
|
||||||
int stride = cairo_image_surface_get_stride(self->glow);
|
int stride = cairo_image_surface_get_stride(self->glow);
|
||||||
|
|
||||||
|
@ -954,16 +949,16 @@ fastiv_browser_style_updated(GtkWidget *widget)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_browser_class_init(FastivBrowserClass *klass)
|
fiv_browser_class_init(FivBrowserClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||||
object_class->finalize = fastiv_browser_finalize;
|
object_class->finalize = fiv_browser_finalize;
|
||||||
object_class->get_property = fastiv_browser_get_property;
|
object_class->get_property = fiv_browser_get_property;
|
||||||
object_class->set_property = fastiv_browser_set_property;
|
object_class->set_property = fiv_browser_set_property;
|
||||||
|
|
||||||
browser_properties[PROP_THUMBNAIL_SIZE] = g_param_spec_enum(
|
browser_properties[PROP_THUMBNAIL_SIZE] = g_param_spec_enum(
|
||||||
"thumbnail-size", "Thumbnail size", "The thumbnail height to use",
|
"thumbnail-size", "Thumbnail size", "The thumbnail height to use",
|
||||||
FASTIV_TYPE_IO_THUMBNAIL_SIZE, FASTIV_IO_THUMBNAIL_SIZE_NORMAL,
|
FIV_TYPE_IO_THUMBNAIL_SIZE, FIV_IO_THUMBNAIL_SIZE_NORMAL,
|
||||||
G_PARAM_READWRITE);
|
G_PARAM_READWRITE);
|
||||||
g_object_class_install_properties(
|
g_object_class_install_properties(
|
||||||
object_class, N_PROPERTIES, browser_properties);
|
object_class, N_PROPERTIES, browser_properties);
|
||||||
|
@ -973,18 +968,18 @@ fastiv_browser_class_init(FastivBrowserClass *klass)
|
||||||
G_TYPE_NONE, 2, G_TYPE_FILE, GTK_TYPE_PLACES_OPEN_FLAGS);
|
G_TYPE_NONE, 2, G_TYPE_FILE, GTK_TYPE_PLACES_OPEN_FLAGS);
|
||||||
|
|
||||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
|
||||||
widget_class->get_request_mode = fastiv_browser_get_request_mode;
|
widget_class->get_request_mode = fiv_browser_get_request_mode;
|
||||||
widget_class->get_preferred_width = fastiv_browser_get_preferred_width;
|
widget_class->get_preferred_width = fiv_browser_get_preferred_width;
|
||||||
widget_class->get_preferred_height_for_width =
|
widget_class->get_preferred_height_for_width =
|
||||||
fastiv_browser_get_preferred_height_for_width;
|
fiv_browser_get_preferred_height_for_width;
|
||||||
widget_class->realize = fastiv_browser_realize;
|
widget_class->realize = fiv_browser_realize;
|
||||||
widget_class->draw = fastiv_browser_draw;
|
widget_class->draw = fiv_browser_draw;
|
||||||
widget_class->size_allocate = fastiv_browser_size_allocate;
|
widget_class->size_allocate = fiv_browser_size_allocate;
|
||||||
widget_class->button_press_event = fastiv_browser_button_press_event;
|
widget_class->button_press_event = fiv_browser_button_press_event;
|
||||||
widget_class->motion_notify_event = fastiv_browser_motion_notify_event;
|
widget_class->motion_notify_event = fiv_browser_motion_notify_event;
|
||||||
widget_class->scroll_event = fastiv_browser_scroll_event;
|
widget_class->scroll_event = fiv_browser_scroll_event;
|
||||||
widget_class->query_tooltip = fastiv_browser_query_tooltip;
|
widget_class->query_tooltip = fiv_browser_query_tooltip;
|
||||||
widget_class->style_updated = fastiv_browser_style_updated;
|
widget_class->style_updated = fiv_browser_style_updated;
|
||||||
|
|
||||||
// Could be split to also-idiomatic row-spacing/column-spacing properties.
|
// Could be split to also-idiomatic row-spacing/column-spacing properties.
|
||||||
// The GParamSpec is sinked by this call.
|
// The GParamSpec is sinked by this call.
|
||||||
|
@ -994,11 +989,11 @@ fastiv_browser_class_init(FastivBrowserClass *klass)
|
||||||
|
|
||||||
// TODO(p): Later override "screen_changed", recreate Pango layouts there,
|
// TODO(p): Later override "screen_changed", recreate Pango layouts there,
|
||||||
// if we get to have any, or otherwise reflect DPI changes.
|
// if we get to have any, or otherwise reflect DPI changes.
|
||||||
gtk_widget_class_set_css_name(widget_class, "fastiv-browser");
|
gtk_widget_class_set_css_name(widget_class, "fiv-browser");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_browser_init(FastivBrowser *self)
|
fiv_browser_init(FivBrowser *self)
|
||||||
{
|
{
|
||||||
gtk_widget_set_can_focus(GTK_WIDGET(self), TRUE);
|
gtk_widget_set_can_focus(GTK_WIDGET(self), TRUE);
|
||||||
gtk_widget_set_has_tooltip(GTK_WIDGET(self), TRUE);
|
gtk_widget_set_has_tooltip(GTK_WIDGET(self), TRUE);
|
||||||
|
@ -1008,7 +1003,7 @@ fastiv_browser_init(FastivBrowser *self)
|
||||||
self->layouted_rows = g_array_new(FALSE, TRUE, sizeof(Row));
|
self->layouted_rows = g_array_new(FALSE, TRUE, sizeof(Row));
|
||||||
g_array_set_clear_func(self->layouted_rows, (GDestroyNotify) row_free);
|
g_array_set_clear_func(self->layouted_rows, (GDestroyNotify) row_free);
|
||||||
|
|
||||||
set_item_size(self, FASTIV_IO_THUMBNAIL_SIZE_NORMAL);
|
set_item_size(self, FIV_IO_THUMBNAIL_SIZE_NORMAL);
|
||||||
self->selected = -1;
|
self->selected = -1;
|
||||||
self->glow = cairo_image_surface_create(CAIRO_FORMAT_A1, 0, 0);
|
self->glow = cairo_image_surface_create(CAIRO_FORMAT_A1, 0, 0);
|
||||||
|
|
||||||
|
@ -1025,15 +1020,15 @@ entry_compare(gconstpointer a, gconstpointer b)
|
||||||
const Entry *entry2 = b;
|
const Entry *entry2 = b;
|
||||||
GFile *location1 = g_file_new_for_uri(entry1->uri);
|
GFile *location1 = g_file_new_for_uri(entry1->uri);
|
||||||
GFile *location2 = g_file_new_for_uri(entry2->uri);
|
GFile *location2 = g_file_new_for_uri(entry2->uri);
|
||||||
gint result = fastiv_io_filecmp(location1, location2);
|
gint result = fiv_io_filecmp(location1, location2);
|
||||||
g_object_unref(location1);
|
g_object_unref(location1);
|
||||||
g_object_unref(location2);
|
g_object_unref(location2);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fastiv_browser_load(
|
fiv_browser_load(
|
||||||
FastivBrowser *self, FastivBrowserFilterCallback cb, const char *path)
|
FivBrowser *self, FivBrowserFilterCallback cb, const char *path)
|
||||||
{
|
{
|
||||||
g_array_set_size(self->entries, 0);
|
g_array_set_size(self->entries, 0);
|
||||||
g_array_set_size(self->layouted_rows, 0);
|
g_array_set_size(self->layouted_rows, 0);
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// fastiv-browser.h: fast image viewer - filesystem browser widget
|
// fiv-browser.h: fast image viewer - filesystem browser widget
|
||||||
//
|
//
|
||||||
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
||||||
//
|
//
|
||||||
|
@ -19,10 +19,10 @@
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
#define FASTIV_TYPE_BROWSER (fastiv_browser_get_type())
|
#define FIV_TYPE_BROWSER (fiv_browser_get_type())
|
||||||
G_DECLARE_FINAL_TYPE(FastivBrowser, fastiv_browser, FASTIV, BROWSER, GtkWidget)
|
G_DECLARE_FINAL_TYPE(FivBrowser, fiv_browser, FIV, BROWSER, GtkWidget)
|
||||||
|
|
||||||
typedef gboolean (*FastivBrowserFilterCallback) (const char *);
|
typedef gboolean (*FivBrowserFilterCallback) (const char *);
|
||||||
|
|
||||||
void fastiv_browser_load(
|
void fiv_browser_load(
|
||||||
FastivBrowser *self, FastivBrowserFilterCallback cb, const char *path);
|
FivBrowser *self, FivBrowserFilterCallback cb, const char *path);
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// fastiv-io-benchmark.c: see if we're worth the name
|
// fiv-io-benchmark.c: see if we're worth the name
|
||||||
//
|
//
|
||||||
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
||||||
//
|
//
|
||||||
|
@ -15,11 +15,11 @@
|
||||||
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <gdk/gdk.h>
|
|
||||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
|
#include <gdk/gdk.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "fastiv-io.h"
|
#include "fiv-io.h"
|
||||||
|
|
||||||
static double
|
static double
|
||||||
timestamp(void)
|
timestamp(void)
|
||||||
|
@ -33,7 +33,7 @@ static void
|
||||||
one_file(const char *filename)
|
one_file(const char *filename)
|
||||||
{
|
{
|
||||||
double since_us = timestamp();
|
double since_us = timestamp();
|
||||||
cairo_surface_t *loaded_by_us = fastiv_io_open(filename, NULL);
|
cairo_surface_t *loaded_by_us = fiv_io_open(filename, NULL);
|
||||||
if (!loaded_by_us)
|
if (!loaded_by_us)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// fastiv-io.c: image operations
|
// fiv-io.c: image operations
|
||||||
//
|
//
|
||||||
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
||||||
//
|
//
|
||||||
|
@ -47,8 +47,8 @@
|
||||||
#include <tiffio.h>
|
#include <tiffio.h>
|
||||||
#endif // HAVE_LIBTIFF
|
#endif // HAVE_LIBTIFF
|
||||||
#ifdef HAVE_GDKPIXBUF
|
#ifdef HAVE_GDKPIXBUF
|
||||||
#include <gdk/gdk.h>
|
|
||||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
|
#include <gdk/gdk.h>
|
||||||
#endif // HAVE_GDKPIXBUF
|
#endif // HAVE_GDKPIXBUF
|
||||||
|
|
||||||
#define WUFFS_IMPLEMENTATION
|
#define WUFFS_IMPLEMENTATION
|
||||||
|
@ -64,17 +64,17 @@
|
||||||
#define WUFFS_CONFIG__MODULE__ZLIB
|
#define WUFFS_CONFIG__MODULE__ZLIB
|
||||||
#include "wuffs-mirror-release-c/release/c/wuffs-v0.3.c"
|
#include "wuffs-mirror-release-c/release/c/wuffs-v0.3.c"
|
||||||
|
|
||||||
|
#include "fiv-io.h"
|
||||||
#include "xdg.h"
|
#include "xdg.h"
|
||||||
#include "fastiv-io.h"
|
|
||||||
|
|
||||||
#if CAIRO_VERSION >= 11702 && X11_ACTUALLY_SUPPORTS_RGBA128F_OR_WE_USE_OPENGL
|
#if CAIRO_VERSION >= 11702 && X11_ACTUALLY_SUPPORTS_RGBA128F_OR_WE_USE_OPENGL
|
||||||
#define FASTIV_CAIRO_RGBA128F
|
#define FIV_CAIRO_RGBA128F
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// A subset of shared-mime-info that produces an appropriate list of
|
// A subset of shared-mime-info that produces an appropriate list of
|
||||||
// file extensions. Chiefly motivated by the suckiness of raw photo formats:
|
// file extensions. Chiefly motivated by the suckiness of raw photo formats:
|
||||||
// someone else will maintain the list of file extensions for us.
|
// someone else will maintain the list of file extensions for us.
|
||||||
const char *fastiv_io_supported_media_types[] = {
|
const char *fiv_io_supported_media_types[] = {
|
||||||
"image/bmp",
|
"image/bmp",
|
||||||
"image/gif",
|
"image/gif",
|
||||||
"image/png",
|
"image/png",
|
||||||
|
@ -103,10 +103,10 @@ const char *fastiv_io_supported_media_types[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
char **
|
char **
|
||||||
fastiv_io_all_supported_media_types(void)
|
fiv_io_all_supported_media_types(void)
|
||||||
{
|
{
|
||||||
GPtrArray *types = g_ptr_array_new();
|
GPtrArray *types = g_ptr_array_new();
|
||||||
for (const char **p = fastiv_io_supported_media_types; *p; p++)
|
for (const char **p = fiv_io_supported_media_types; *p; p++)
|
||||||
g_ptr_array_add(types, g_strdup(*p));
|
g_ptr_array_add(types, g_strdup(*p));
|
||||||
|
|
||||||
#ifdef HAVE_GDKPIXBUF
|
#ifdef HAVE_GDKPIXBUF
|
||||||
|
@ -126,18 +126,18 @@ fastiv_io_all_supported_media_types(void)
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
#define FASTIV_IO_ERROR fastiv_io_error_quark()
|
#define FIV_IO_ERROR fiv_io_error_quark()
|
||||||
|
|
||||||
G_DEFINE_QUARK(fastiv-io-error-quark, fastiv_io_error)
|
G_DEFINE_QUARK(fiv-io-error-quark, fiv_io_error)
|
||||||
|
|
||||||
enum FastivIoError {
|
enum FivIoError {
|
||||||
FASTIV_IO_ERROR_OPEN
|
FIV_IO_ERROR_OPEN
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_error(GError **error, const char *message)
|
set_error(GError **error, const char *message)
|
||||||
{
|
{
|
||||||
g_set_error_literal(error, FASTIV_IO_ERROR, FASTIV_IO_ERROR_OPEN, message);
|
g_set_error_literal(error, FIV_IO_ERROR, FIV_IO_ERROR_OPEN, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -148,11 +148,10 @@ try_append_page(cairo_surface_t *surface, cairo_surface_t **result,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (*result) {
|
if (*result) {
|
||||||
cairo_surface_set_user_data(*result_tail,
|
cairo_surface_set_user_data(*result_tail, &fiv_io_key_page_next,
|
||||||
&fastiv_io_key_page_next, surface,
|
surface, (cairo_destroy_func_t) cairo_surface_destroy);
|
||||||
(cairo_destroy_func_t) cairo_surface_destroy);
|
cairo_surface_set_user_data(
|
||||||
cairo_surface_set_user_data(surface,
|
surface, &fiv_io_key_page_previous, *result_tail, NULL);
|
||||||
&fastiv_io_key_page_previous, *result_tail, NULL);
|
|
||||||
*result_tail = surface;
|
*result_tail = surface;
|
||||||
} else {
|
} else {
|
||||||
*result = *result_tail = surface;
|
*result = *result_tail = surface;
|
||||||
|
@ -224,8 +223,7 @@ pull_metadata(wuffs_base__image_decoder *dec, wuffs_base__io_buffer *src,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_byte_array_append(array,
|
g_byte_array_append(array, wuffs_base__io_buffer__reader_pointer(&dst),
|
||||||
wuffs_base__io_buffer__reader_pointer(&dst),
|
|
||||||
wuffs_base__io_buffer__reader_length(&dst));
|
wuffs_base__io_buffer__reader_length(&dst));
|
||||||
if (wuffs_base__status__is_ok(&status))
|
if (wuffs_base__status__is_ok(&status))
|
||||||
return g_byte_array_free_to_bytes(array);
|
return g_byte_array_free_to_bytes(array);
|
||||||
|
@ -410,26 +408,26 @@ load_wuffs_frame(struct load_wuffs_frame_context *ctx, GError **error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->meta_exif)
|
if (ctx->meta_exif)
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_exif,
|
cairo_surface_set_user_data(surface, &fiv_io_key_exif,
|
||||||
g_bytes_ref(ctx->meta_exif), (cairo_destroy_func_t) g_bytes_unref);
|
g_bytes_ref(ctx->meta_exif), (cairo_destroy_func_t) g_bytes_unref);
|
||||||
if (ctx->meta_iccp)
|
if (ctx->meta_iccp)
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_icc,
|
cairo_surface_set_user_data(surface, &fiv_io_key_icc,
|
||||||
g_bytes_ref(ctx->meta_iccp), (cairo_destroy_func_t) g_bytes_unref);
|
g_bytes_ref(ctx->meta_iccp), (cairo_destroy_func_t) g_bytes_unref);
|
||||||
if (ctx->meta_xmp)
|
if (ctx->meta_xmp)
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_xmp,
|
cairo_surface_set_user_data(surface, &fiv_io_key_xmp,
|
||||||
g_bytes_ref(ctx->meta_xmp), (cairo_destroy_func_t) g_bytes_unref);
|
g_bytes_ref(ctx->meta_xmp), (cairo_destroy_func_t) g_bytes_unref);
|
||||||
|
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_loops,
|
cairo_surface_set_user_data(surface, &fiv_io_key_loops,
|
||||||
(void *) (uintptr_t) wuffs_base__image_decoder__num_animation_loops(
|
(void *) (uintptr_t) wuffs_base__image_decoder__num_animation_loops(
|
||||||
ctx->dec), NULL);
|
ctx->dec), NULL);
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_frame_duration,
|
cairo_surface_set_user_data(surface, &fiv_io_key_frame_duration,
|
||||||
(void *) (intptr_t) (wuffs_base__frame_config__duration(&fc) /
|
(void *) (intptr_t) (wuffs_base__frame_config__duration(&fc) /
|
||||||
WUFFS_BASE__FLICKS_PER_MILLISECOND), NULL);
|
WUFFS_BASE__FLICKS_PER_MILLISECOND), NULL);
|
||||||
|
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_frame_previous,
|
cairo_surface_set_user_data(
|
||||||
ctx->result_tail, NULL);
|
surface, &fiv_io_key_frame_previous, ctx->result_tail, NULL);
|
||||||
if (ctx->result_tail)
|
if (ctx->result_tail)
|
||||||
cairo_surface_set_user_data(ctx->result_tail, &fastiv_io_key_frame_next,
|
cairo_surface_set_user_data(ctx->result_tail, &fiv_io_key_frame_next,
|
||||||
surface, (cairo_destroy_func_t) cairo_surface_destroy);
|
surface, (cairo_destroy_func_t) cairo_surface_destroy);
|
||||||
else
|
else
|
||||||
ctx->result = surface;
|
ctx->result = surface;
|
||||||
|
@ -536,9 +534,9 @@ open_wuffs(
|
||||||
|
|
||||||
// Cairo doesn't support transparency with RGB30, so no premultiplication.
|
// Cairo doesn't support transparency with RGB30, so no premultiplication.
|
||||||
ctx.pack_16_10 = opaque && (bpp > 24 || (bpp < 24 && bpp > 8));
|
ctx.pack_16_10 = opaque && (bpp > 24 || (bpp < 24 && bpp > 8));
|
||||||
#ifdef FASTIV_CAIRO_RGBA128F
|
#ifdef FIV_CAIRO_RGBA128F
|
||||||
ctx.expand_16_float = !opaque && (bpp > 24 || (bpp < 24 && bpp > 8));
|
ctx.expand_16_float = !opaque && (bpp > 24 || (bpp < 24 && bpp > 8));
|
||||||
#endif // FASTIV_CAIRO_RGBA128F
|
#endif // FIV_CAIRO_RGBA128F
|
||||||
|
|
||||||
// In Wuffs, /doc/note/pixel-formats.md declares "memory order", which,
|
// In Wuffs, /doc/note/pixel-formats.md declares "memory order", which,
|
||||||
// for our purposes, means big endian, and BGRA results in 32-bit ARGB
|
// for our purposes, means big endian, and BGRA results in 32-bit ARGB
|
||||||
|
@ -553,12 +551,12 @@ open_wuffs(
|
||||||
// Pre-multiplied alpha is used." CAIRO_FORMAT_RGB{24,30} are analogous.
|
// Pre-multiplied alpha is used." CAIRO_FORMAT_RGB{24,30} are analogous.
|
||||||
ctx.cairo_format = CAIRO_FORMAT_ARGB32;
|
ctx.cairo_format = CAIRO_FORMAT_ARGB32;
|
||||||
|
|
||||||
#ifdef FASTIV_CAIRO_RGBA128F
|
#ifdef FIV_CAIRO_RGBA128F
|
||||||
if (ctx.expand_16_float) {
|
if (ctx.expand_16_float) {
|
||||||
wuffs_format = WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL_4X16LE;
|
wuffs_format = WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL_4X16LE;
|
||||||
ctx.cairo_format = CAIRO_FORMAT_RGBA128F;
|
ctx.cairo_format = CAIRO_FORMAT_RGBA128F;
|
||||||
} else
|
} else
|
||||||
#endif // FASTIV_CAIRO_RGBA128F
|
#endif // FIV_CAIRO_RGBA128F
|
||||||
if (ctx.pack_16_10) {
|
if (ctx.pack_16_10) {
|
||||||
// TODO(p): Make Wuffs support A2RGB30 as a destination format;
|
// TODO(p): Make Wuffs support A2RGB30 as a destination format;
|
||||||
// in general, 16-bit depth swizzlers are stubbed.
|
// in general, 16-bit depth swizzlers are stubbed.
|
||||||
|
@ -589,8 +587,8 @@ open_wuffs(
|
||||||
|
|
||||||
// Wrap the chain around, since our caller receives only one pointer.
|
// Wrap the chain around, since our caller receives only one pointer.
|
||||||
if (ctx.result)
|
if (ctx.result)
|
||||||
cairo_surface_set_user_data(ctx.result, &fastiv_io_key_frame_previous,
|
cairo_surface_set_user_data(
|
||||||
ctx.result_tail, NULL);
|
ctx.result, &fiv_io_key_frame_previous, ctx.result_tail, NULL);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
free(ctx.workbuf.ptr);
|
free(ctx.workbuf.ptr);
|
||||||
|
@ -716,14 +714,14 @@ parse_jpeg_metadata(cairo_surface_t *surface, const gchar *data, gsize len)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exif->len)
|
if (exif->len)
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_exif,
|
cairo_surface_set_user_data(surface, &fiv_io_key_exif,
|
||||||
g_byte_array_free_to_bytes(exif),
|
g_byte_array_free_to_bytes(exif),
|
||||||
(cairo_destroy_func_t) g_bytes_unref);
|
(cairo_destroy_func_t) g_bytes_unref);
|
||||||
else
|
else
|
||||||
g_byte_array_free(exif, TRUE);
|
g_byte_array_free(exif, TRUE);
|
||||||
|
|
||||||
if (icc_done)
|
if (icc_done)
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_icc,
|
cairo_surface_set_user_data(surface, &fiv_io_key_icc,
|
||||||
g_byte_array_free_to_bytes(icc),
|
g_byte_array_free_to_bytes(icc),
|
||||||
(cairo_destroy_func_t) g_bytes_unref);
|
(cairo_destroy_func_t) g_bytes_unref);
|
||||||
else
|
else
|
||||||
|
@ -900,7 +898,7 @@ open_libraw(const gchar *data, gsize len, GError **error)
|
||||||
#endif // HAVE_LIBRAW ---------------------------------------------------------
|
#endif // HAVE_LIBRAW ---------------------------------------------------------
|
||||||
#ifdef HAVE_LIBRSVG // --------------------------------------------------------
|
#ifdef HAVE_LIBRSVG // --------------------------------------------------------
|
||||||
|
|
||||||
#ifdef FASTIV_RSVG_DEBUG
|
#ifdef FIV_RSVG_DEBUG
|
||||||
#include <cairo/cairo-script.h>
|
#include <cairo/cairo-script.h>
|
||||||
#include <cairo/cairo-svg.h>
|
#include <cairo/cairo-svg.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -911,8 +909,8 @@ open_librsvg(const gchar *data, gsize len, const gchar *path, GError **error)
|
||||||
{
|
{
|
||||||
GFile *base_file = g_file_new_for_path(path);
|
GFile *base_file = g_file_new_for_path(path);
|
||||||
GInputStream *is = g_memory_input_stream_new_from_data(data, len, NULL);
|
GInputStream *is = g_memory_input_stream_new_from_data(data, len, NULL);
|
||||||
RsvgHandle *handle = rsvg_handle_new_from_stream_sync(is, base_file,
|
RsvgHandle *handle = rsvg_handle_new_from_stream_sync(
|
||||||
RSVG_HANDLE_FLAG_KEEP_IMAGE_DATA, NULL, error);
|
is, base_file, RSVG_HANDLE_FLAG_KEEP_IMAGE_DATA, NULL, error);
|
||||||
g_object_unref(base_file);
|
g_object_unref(base_file);
|
||||||
g_object_unref(is);
|
g_object_unref(is);
|
||||||
if (!handle)
|
if (!handle)
|
||||||
|
@ -931,8 +929,8 @@ open_librsvg(const gchar *data, gsize len, const gchar *path, GError **error)
|
||||||
#endif
|
#endif
|
||||||
RsvgRectangle viewbox = {};
|
RsvgRectangle viewbox = {};
|
||||||
gboolean has_viewport = FALSE;
|
gboolean has_viewport = FALSE;
|
||||||
rsvg_handle_get_intrinsic_dimensions(handle, NULL, NULL, NULL, NULL,
|
rsvg_handle_get_intrinsic_dimensions(
|
||||||
&has_viewport, &viewbox);
|
handle, NULL, NULL, NULL, NULL, &has_viewport, &viewbox);
|
||||||
if (!has_viewport) {
|
if (!has_viewport) {
|
||||||
set_error(error, "cannot compute pixel dimensions");
|
set_error(error, "cannot compute pixel dimensions");
|
||||||
g_object_unref(handle);
|
g_object_unref(handle);
|
||||||
|
@ -948,7 +946,7 @@ open_librsvg(const gchar *data, gsize len, const gchar *path, GError **error)
|
||||||
cairo_surface_t *surface =
|
cairo_surface_t *surface =
|
||||||
cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA, &extents);
|
cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA, &extents);
|
||||||
|
|
||||||
#ifdef FASTIV_RSVG_DEBUG
|
#ifdef FIV_RSVG_DEBUG
|
||||||
cairo_device_t *script = cairo_script_create("cairo.script");
|
cairo_device_t *script = cairo_script_create("cairo.script");
|
||||||
cairo_surface_t *tee =
|
cairo_surface_t *tee =
|
||||||
cairo_script_surface_create_for_target(script, surface);
|
cairo_script_surface_create_for_target(script, surface);
|
||||||
|
@ -970,7 +968,7 @@ open_librsvg(const gchar *data, gsize len, const gchar *path, GError **error)
|
||||||
cairo_destroy(cr);
|
cairo_destroy(cr);
|
||||||
g_object_unref(handle);
|
g_object_unref(handle);
|
||||||
|
|
||||||
#ifdef FASTIV_RSVG_DEBUG
|
#ifdef FIV_RSVG_DEBUG
|
||||||
cairo_surface_t *svg = cairo_svg_surface_create("cairo.svg", w, h);
|
cairo_surface_t *svg = cairo_svg_surface_create("cairo.svg", w, h);
|
||||||
cr = cairo_create(svg);
|
cr = cairo_create(svg);
|
||||||
cairo_set_source_surface(cr, surface, 0, 0);
|
cairo_set_source_surface(cr, surface, 0, 0);
|
||||||
|
@ -996,16 +994,16 @@ open_librsvg(const gchar *data, gsize len, const gchar *path, GError **error)
|
||||||
|
|
||||||
// fmemopen is part of POSIX-1.2008, this exercise is technically unnecessary.
|
// fmemopen is part of POSIX-1.2008, this exercise is technically unnecessary.
|
||||||
// libXcursor checks for EOF rather than -1, it may eat your hamster.
|
// libXcursor checks for EOF rather than -1, it may eat your hamster.
|
||||||
struct fastiv_io_xcursor {
|
struct fiv_io_xcursor {
|
||||||
XcursorFile parent;
|
XcursorFile parent;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
long position, len;
|
long position, len;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
fastiv_io_xcursor_read(XcursorFile *file, unsigned char *buf, int len)
|
fiv_io_xcursor_read(XcursorFile *file, unsigned char *buf, int len)
|
||||||
{
|
{
|
||||||
struct fastiv_io_xcursor *fix = (struct fastiv_io_xcursor *) file;
|
struct fiv_io_xcursor *fix = (struct fiv_io_xcursor *) file;
|
||||||
if (fix->position < 0 || fix->position > fix->len) {
|
if (fix->position < 0 || fix->position > fix->len) {
|
||||||
errno = EOVERFLOW;
|
errno = EOVERFLOW;
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1021,7 +1019,7 @@ fastiv_io_xcursor_read(XcursorFile *file, unsigned char *buf, int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
fastiv_io_xcursor_write(G_GNUC_UNUSED XcursorFile *file,
|
fiv_io_xcursor_write(G_GNUC_UNUSED XcursorFile *file,
|
||||||
G_GNUC_UNUSED unsigned char *buf, G_GNUC_UNUSED int len)
|
G_GNUC_UNUSED unsigned char *buf, G_GNUC_UNUSED int len)
|
||||||
{
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
|
@ -1029,9 +1027,9 @@ fastiv_io_xcursor_write(G_GNUC_UNUSED XcursorFile *file,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
fastiv_io_xcursor_seek(XcursorFile *file, long offset, int whence)
|
fiv_io_xcursor_seek(XcursorFile *file, long offset, int whence)
|
||||||
{
|
{
|
||||||
struct fastiv_io_xcursor *fix = (struct fastiv_io_xcursor *) file;
|
struct fiv_io_xcursor *fix = (struct fiv_io_xcursor *) file;
|
||||||
switch (whence) {
|
switch (whence) {
|
||||||
case SEEK_SET:
|
case SEEK_SET:
|
||||||
fix->position = offset;
|
fix->position = offset;
|
||||||
|
@ -1054,11 +1052,11 @@ fastiv_io_xcursor_seek(XcursorFile *file, long offset, int whence)
|
||||||
return fix->position;
|
return fix->position;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const XcursorFile fastiv_io_xcursor_adaptor = {
|
static const XcursorFile fiv_io_xcursor_adaptor = {
|
||||||
.closure = NULL,
|
.closure = NULL,
|
||||||
.read = fastiv_io_xcursor_read,
|
.read = fiv_io_xcursor_read,
|
||||||
.write = fastiv_io_xcursor_write,
|
.write = fiv_io_xcursor_write,
|
||||||
.seek = fastiv_io_xcursor_seek,
|
.seek = fiv_io_xcursor_seek,
|
||||||
};
|
};
|
||||||
|
|
||||||
static cairo_surface_t *
|
static cairo_surface_t *
|
||||||
|
@ -1069,8 +1067,8 @@ open_xcursor(const gchar *data, gsize len, GError **error)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fastiv_io_xcursor file = {
|
struct fiv_io_xcursor file = {
|
||||||
.parent = fastiv_io_xcursor_adaptor,
|
.parent = fiv_io_xcursor_adaptor,
|
||||||
.data = (unsigned char *) data,
|
.data = (unsigned char *) data,
|
||||||
.position = 0,
|
.position = 0,
|
||||||
.len = len,
|
.len = len,
|
||||||
|
@ -1094,24 +1092,22 @@ open_xcursor(const gchar *data, gsize len, GError **error)
|
||||||
cairo_surface_t *surface = cairo_image_surface_create_for_data(
|
cairo_surface_t *surface = cairo_image_surface_create_for_data(
|
||||||
(unsigned char *) image->pixels, CAIRO_FORMAT_ARGB32,
|
(unsigned char *) image->pixels, CAIRO_FORMAT_ARGB32,
|
||||||
image->width, image->height, image->width * sizeof *image->pixels);
|
image->width, image->height, image->width * sizeof *image->pixels);
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_frame_duration,
|
cairo_surface_set_user_data(surface, &fiv_io_key_frame_duration,
|
||||||
(void *) (intptr_t) image->delay, NULL);
|
(void *) (intptr_t) image->delay, NULL);
|
||||||
|
|
||||||
if (pages && image->size == last_nominal) {
|
if (pages && image->size == last_nominal) {
|
||||||
cairo_surface_set_user_data(surface,
|
cairo_surface_set_user_data(
|
||||||
&fastiv_io_key_frame_previous, frames_tail, NULL);
|
surface, &fiv_io_key_frame_previous, frames_tail, NULL);
|
||||||
cairo_surface_set_user_data(frames_tail,
|
cairo_surface_set_user_data(frames_tail, &fiv_io_key_frame_next,
|
||||||
&fastiv_io_key_frame_next, surface,
|
surface, (cairo_destroy_func_t) cairo_surface_destroy);
|
||||||
(cairo_destroy_func_t) cairo_surface_destroy);
|
|
||||||
} else if (frames_head) {
|
} else if (frames_head) {
|
||||||
cairo_surface_set_user_data(frames_head,
|
cairo_surface_set_user_data(
|
||||||
&fastiv_io_key_frame_previous, frames_tail, NULL);
|
frames_head, &fiv_io_key_frame_previous, frames_tail, NULL);
|
||||||
|
|
||||||
cairo_surface_set_user_data(frames_head,
|
cairo_surface_set_user_data(frames_head, &fiv_io_key_page_next,
|
||||||
&fastiv_io_key_page_next, surface,
|
surface, (cairo_destroy_func_t) cairo_surface_destroy);
|
||||||
(cairo_destroy_func_t) cairo_surface_destroy);
|
cairo_surface_set_user_data(
|
||||||
cairo_surface_set_user_data(surface,
|
surface, &fiv_io_key_page_previous, frames_head, NULL);
|
||||||
&fastiv_io_key_page_previous, frames_head, NULL);
|
|
||||||
frames_head = surface;
|
frames_head = surface;
|
||||||
} else {
|
} else {
|
||||||
pages = frames_head = surface;
|
pages = frames_head = surface;
|
||||||
|
@ -1127,7 +1123,7 @@ open_xcursor(const gchar *data, gsize len, GError **error)
|
||||||
|
|
||||||
// Wrap around animations in the last page.
|
// Wrap around animations in the last page.
|
||||||
cairo_surface_set_user_data(
|
cairo_surface_set_user_data(
|
||||||
frames_head, &fastiv_io_key_frame_previous, frames_tail, NULL);
|
frames_head, &fiv_io_key_frame_previous, frames_tail, NULL);
|
||||||
|
|
||||||
// There is no need to copy data, assign it to the surface.
|
// There is no need to copy data, assign it to the surface.
|
||||||
static cairo_user_data_key_t key = {};
|
static cairo_user_data_key_t key = {};
|
||||||
|
@ -1214,7 +1210,7 @@ load_libwebp_frame(WebPAnimDecoder *dec, const WebPAnimInfo *info,
|
||||||
cairo_surface_mark_dirty(surface);
|
cairo_surface_mark_dirty(surface);
|
||||||
|
|
||||||
// This API is confusing and awkward.
|
// This API is confusing and awkward.
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_frame_duration,
|
cairo_surface_set_user_data(surface, &fiv_io_key_frame_duration,
|
||||||
(void *) (intptr_t) (timestamp - *last_timestamp), NULL);
|
(void *) (intptr_t) (timestamp - *last_timestamp), NULL);
|
||||||
*last_timestamp = timestamp;
|
*last_timestamp = timestamp;
|
||||||
return surface;
|
return surface;
|
||||||
|
@ -1248,20 +1244,19 @@ load_libwebp_animated(const WebPData *wd, GError **error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frames_tail)
|
if (frames_tail)
|
||||||
cairo_surface_set_user_data(frames_tail,
|
cairo_surface_set_user_data(frames_tail, &fiv_io_key_frame_next,
|
||||||
&fastiv_io_key_frame_next, surface,
|
surface, (cairo_destroy_func_t) cairo_surface_destroy);
|
||||||
(cairo_destroy_func_t) cairo_surface_destroy);
|
|
||||||
else
|
else
|
||||||
frames = surface;
|
frames = surface;
|
||||||
|
|
||||||
cairo_surface_set_user_data(surface,
|
cairo_surface_set_user_data(
|
||||||
&fastiv_io_key_frame_previous, frames_tail, NULL);
|
surface, &fiv_io_key_frame_previous, frames_tail, NULL);
|
||||||
frames_tail = surface;
|
frames_tail = surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frames) {
|
if (frames) {
|
||||||
cairo_surface_set_user_data(frames, &fastiv_io_key_frame_previous,
|
cairo_surface_set_user_data(
|
||||||
frames_tail, NULL);
|
frames, &fiv_io_key_frame_previous, frames_tail, NULL);
|
||||||
} else {
|
} else {
|
||||||
set_error(error, "the animation has no frames");
|
set_error(error, "the animation has no frames");
|
||||||
g_clear_pointer(&frames, cairo_surface_destroy);
|
g_clear_pointer(&frames, cairo_surface_destroy);
|
||||||
|
@ -1308,27 +1303,27 @@ open_libwebp(const gchar *data, gsize len, const gchar *path, GError **error)
|
||||||
uint32_t flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
|
uint32_t flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
|
||||||
if ((flags & EXIF_FLAG) &&
|
if ((flags & EXIF_FLAG) &&
|
||||||
WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter)) {
|
WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter)) {
|
||||||
cairo_surface_set_user_data(result, &fastiv_io_key_exif,
|
cairo_surface_set_user_data(result, &fiv_io_key_exif,
|
||||||
g_bytes_new(chunk_iter.chunk.bytes, chunk_iter.chunk.size),
|
g_bytes_new(chunk_iter.chunk.bytes, chunk_iter.chunk.size),
|
||||||
(cairo_destroy_func_t) g_bytes_unref);
|
(cairo_destroy_func_t) g_bytes_unref);
|
||||||
WebPDemuxReleaseChunkIterator(&chunk_iter);
|
WebPDemuxReleaseChunkIterator(&chunk_iter);
|
||||||
}
|
}
|
||||||
if ((flags & ICCP_FLAG) &&
|
if ((flags & ICCP_FLAG) &&
|
||||||
WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter)) {
|
WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter)) {
|
||||||
cairo_surface_set_user_data(result, &fastiv_io_key_icc,
|
cairo_surface_set_user_data(result, &fiv_io_key_icc,
|
||||||
g_bytes_new(chunk_iter.chunk.bytes, chunk_iter.chunk.size),
|
g_bytes_new(chunk_iter.chunk.bytes, chunk_iter.chunk.size),
|
||||||
(cairo_destroy_func_t) g_bytes_unref);
|
(cairo_destroy_func_t) g_bytes_unref);
|
||||||
WebPDemuxReleaseChunkIterator(&chunk_iter);
|
WebPDemuxReleaseChunkIterator(&chunk_iter);
|
||||||
}
|
}
|
||||||
if ((flags & XMP_FLAG) &&
|
if ((flags & XMP_FLAG) &&
|
||||||
WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter)) {
|
WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter)) {
|
||||||
cairo_surface_set_user_data(result, &fastiv_io_key_xmp,
|
cairo_surface_set_user_data(result, &fiv_io_key_xmp,
|
||||||
g_bytes_new(chunk_iter.chunk.bytes, chunk_iter.chunk.size),
|
g_bytes_new(chunk_iter.chunk.bytes, chunk_iter.chunk.size),
|
||||||
(cairo_destroy_func_t) g_bytes_unref);
|
(cairo_destroy_func_t) g_bytes_unref);
|
||||||
WebPDemuxReleaseChunkIterator(&chunk_iter);
|
WebPDemuxReleaseChunkIterator(&chunk_iter);
|
||||||
}
|
}
|
||||||
if (flags & ANIMATION_FLAG) {
|
if (flags & ANIMATION_FLAG) {
|
||||||
cairo_surface_set_user_data(result, &fastiv_io_key_loops,
|
cairo_surface_set_user_data(result, &fiv_io_key_loops,
|
||||||
(void *) (uintptr_t) WebPDemuxGetI(demux, WEBP_FF_LOOP_COUNT),
|
(void *) (uintptr_t) WebPDemuxGetI(demux, WEBP_FF_LOOP_COUNT),
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
@ -1419,7 +1414,7 @@ load_libheif_image(struct heif_image_handle *handle, GError **error)
|
||||||
g_warning("%s", err.message);
|
g_warning("%s", err.message);
|
||||||
g_free(exif);
|
g_free(exif);
|
||||||
} else {
|
} else {
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_exif,
|
cairo_surface_set_user_data(surface, &fiv_io_key_exif,
|
||||||
g_bytes_new_take(exif, exif_len),
|
g_bytes_new_take(exif, exif_len),
|
||||||
(cairo_destroy_func_t) g_bytes_unref);
|
(cairo_destroy_func_t) g_bytes_unref);
|
||||||
}
|
}
|
||||||
|
@ -1435,7 +1430,7 @@ load_libheif_image(struct heif_image_handle *handle, GError **error)
|
||||||
g_warning("%s", err.message);
|
g_warning("%s", err.message);
|
||||||
g_free(icc);
|
g_free(icc);
|
||||||
} else {
|
} else {
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_icc,
|
cairo_surface_set_user_data(surface, &fiv_io_key_icc,
|
||||||
g_bytes_new_take(icc, icc_len),
|
g_bytes_new_take(icc, icc_len),
|
||||||
(cairo_destroy_func_t) g_bytes_unref);
|
(cairo_destroy_func_t) g_bytes_unref);
|
||||||
}
|
}
|
||||||
|
@ -1463,8 +1458,8 @@ load_libheif_aux_images(const gchar *path, struct heif_image_handle *top,
|
||||||
n = heif_image_handle_get_list_of_auxiliary_image_IDs(top, filter, ids, n);
|
n = heif_image_handle_get_list_of_auxiliary_image_IDs(top, filter, ids, n);
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
struct heif_image_handle *handle = NULL;
|
struct heif_image_handle *handle = NULL;
|
||||||
struct heif_error err = heif_image_handle_get_auxiliary_image_handle(
|
struct heif_error err =
|
||||||
top, ids[i], &handle);
|
heif_image_handle_get_auxiliary_image_handle(top, ids[i], &handle);
|
||||||
if (err.code != heif_error_Ok) {
|
if (err.code != heif_error_Ok) {
|
||||||
g_warning("%s: %s", path, err.message);
|
g_warning("%s: %s", path, err.message);
|
||||||
continue;
|
continue;
|
||||||
|
@ -1534,7 +1529,7 @@ fail_read:
|
||||||
#endif // HAVE_LIBHEIF --------------------------------------------------------
|
#endif // HAVE_LIBHEIF --------------------------------------------------------
|
||||||
#ifdef HAVE_LIBTIFF //---------------------------------------------------------
|
#ifdef HAVE_LIBTIFF //---------------------------------------------------------
|
||||||
|
|
||||||
struct fastiv_io_tiff {
|
struct fiv_io_tiff {
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
gchar *error;
|
gchar *error;
|
||||||
|
|
||||||
|
@ -1544,9 +1539,9 @@ struct fastiv_io_tiff {
|
||||||
};
|
};
|
||||||
|
|
||||||
static tsize_t
|
static tsize_t
|
||||||
fastiv_io_tiff_read(thandle_t h, tdata_t buf, tsize_t len)
|
fiv_io_tiff_read(thandle_t h, tdata_t buf, tsize_t len)
|
||||||
{
|
{
|
||||||
struct fastiv_io_tiff *io = h;
|
struct fiv_io_tiff *io = h;
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
// What the FUCK! This argument is not supposed to be signed!
|
// What the FUCK! This argument is not supposed to be signed!
|
||||||
// How many mistakes can you make in such a basic API?
|
// How many mistakes can you make in such a basic API?
|
||||||
|
@ -1568,7 +1563,7 @@ fastiv_io_tiff_read(thandle_t h, tdata_t buf, tsize_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
static tsize_t
|
static tsize_t
|
||||||
fastiv_io_tiff_write(G_GNUC_UNUSED thandle_t h,
|
fiv_io_tiff_write(G_GNUC_UNUSED thandle_t h,
|
||||||
G_GNUC_UNUSED tdata_t buf, G_GNUC_UNUSED tsize_t len)
|
G_GNUC_UNUSED tdata_t buf, G_GNUC_UNUSED tsize_t len)
|
||||||
{
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
|
@ -1576,9 +1571,9 @@ fastiv_io_tiff_write(G_GNUC_UNUSED thandle_t h,
|
||||||
}
|
}
|
||||||
|
|
||||||
static toff_t
|
static toff_t
|
||||||
fastiv_io_tiff_seek(thandle_t h, toff_t offset, int whence)
|
fiv_io_tiff_seek(thandle_t h, toff_t offset, int whence)
|
||||||
{
|
{
|
||||||
struct fastiv_io_tiff *io = h;
|
struct fiv_io_tiff *io = h;
|
||||||
switch (whence) {
|
switch (whence) {
|
||||||
case SEEK_SET:
|
case SEEK_SET:
|
||||||
io->position = offset;
|
io->position = offset;
|
||||||
|
@ -1597,22 +1592,22 @@ fastiv_io_tiff_seek(thandle_t h, toff_t offset, int whence)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
fastiv_io_tiff_close(G_GNUC_UNUSED thandle_t h)
|
fiv_io_tiff_close(G_GNUC_UNUSED thandle_t h)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static toff_t
|
static toff_t
|
||||||
fastiv_io_tiff_size(thandle_t h)
|
fiv_io_tiff_size(thandle_t h)
|
||||||
{
|
{
|
||||||
return ((struct fastiv_io_tiff *) h)->len;
|
return ((struct fiv_io_tiff *) h)->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_io_tiff_error(thandle_t h,
|
fiv_io_tiff_error(
|
||||||
const char *module, const char *format, va_list ap)
|
thandle_t h, const char *module, const char *format, va_list ap)
|
||||||
{
|
{
|
||||||
struct fastiv_io_tiff *io = h;
|
struct fiv_io_tiff *io = h;
|
||||||
gchar *message = g_strdup_vprintf(format, ap);
|
gchar *message = g_strdup_vprintf(format, ap);
|
||||||
if (io->error)
|
if (io->error)
|
||||||
// I'm not sure if two errors can ever come in a succession,
|
// I'm not sure if two errors can ever come in a succession,
|
||||||
|
@ -1624,7 +1619,7 @@ fastiv_io_tiff_error(thandle_t h,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_io_tiff_warning(G_GNUC_UNUSED thandle_t h,
|
fiv_io_tiff_warning(G_GNUC_UNUSED thandle_t h,
|
||||||
const char *module, const char *format, va_list ap)
|
const char *module, const char *format, va_list ap)
|
||||||
{
|
{
|
||||||
gchar *message = g_strdup_vprintf(format, ap);
|
gchar *message = g_strdup_vprintf(format, ap);
|
||||||
|
@ -1683,25 +1678,23 @@ load_libtiff_directory(TIFF *tiff, GError **error)
|
||||||
const uint32_t meta_len = 0;
|
const uint32_t meta_len = 0;
|
||||||
const void *meta = NULL;
|
const void *meta = NULL;
|
||||||
if (TIFFGetField(tiff, TIFFTAG_ICCPROFILE, &meta_len, &meta)) {
|
if (TIFFGetField(tiff, TIFFTAG_ICCPROFILE, &meta_len, &meta)) {
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_icc,
|
cairo_surface_set_user_data(surface, &fiv_io_key_icc,
|
||||||
g_bytes_new(meta, meta_len),
|
g_bytes_new(meta, meta_len), (cairo_destroy_func_t) g_bytes_unref);
|
||||||
(cairo_destroy_func_t) g_bytes_unref);
|
|
||||||
}
|
}
|
||||||
if (TIFFGetField(tiff, TIFFTAG_XMLPACKET, &meta_len, &meta)) {
|
if (TIFFGetField(tiff, TIFFTAG_XMLPACKET, &meta_len, &meta)) {
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_xmp,
|
cairo_surface_set_user_data(surface, &fiv_io_key_xmp,
|
||||||
g_bytes_new(meta, meta_len),
|
g_bytes_new(meta, meta_len), (cairo_destroy_func_t) g_bytes_unref);
|
||||||
(cairo_destroy_func_t) g_bytes_unref);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't ask. The API is high, alright, I'm just not sure about the level.
|
// Don't ask. The API is high, alright, I'm just not sure about the level.
|
||||||
uint16_t orientation = 0;
|
uint16_t orientation = 0;
|
||||||
if (TIFFGetField(tiff, TIFFTAG_ORIENTATION, &orientation)) {
|
if (TIFFGetField(tiff, TIFFTAG_ORIENTATION, &orientation)) {
|
||||||
if (orientation == 5 || orientation == 7)
|
if (orientation == 5 || orientation == 7)
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_orientation,
|
cairo_surface_set_user_data(
|
||||||
(void *) (uintptr_t) 5, NULL);
|
surface, &fiv_io_key_orientation, (void *) (uintptr_t) 5, NULL);
|
||||||
if (orientation == 6 || orientation == 8)
|
if (orientation == 6 || orientation == 8)
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_orientation,
|
cairo_surface_set_user_data(
|
||||||
(void *) (uintptr_t) 7, NULL);
|
surface, &fiv_io_key_orientation, (void *) (uintptr_t) 7, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
@ -1716,9 +1709,9 @@ open_libtiff(const gchar *data, gsize len, const gchar *path, GError **error)
|
||||||
// Both kinds of handlers are called, redirect everything.
|
// Both kinds of handlers are called, redirect everything.
|
||||||
TIFFErrorHandler eh = TIFFSetErrorHandler(NULL);
|
TIFFErrorHandler eh = TIFFSetErrorHandler(NULL);
|
||||||
TIFFErrorHandler wh = TIFFSetWarningHandler(NULL);
|
TIFFErrorHandler wh = TIFFSetWarningHandler(NULL);
|
||||||
TIFFErrorHandlerExt ehe = TIFFSetErrorHandlerExt(fastiv_io_tiff_error);
|
TIFFErrorHandlerExt ehe = TIFFSetErrorHandlerExt(fiv_io_tiff_error);
|
||||||
TIFFErrorHandlerExt whe = TIFFSetWarningHandlerExt(fastiv_io_tiff_warning);
|
TIFFErrorHandlerExt whe = TIFFSetWarningHandlerExt(fiv_io_tiff_warning);
|
||||||
struct fastiv_io_tiff h = {
|
struct fiv_io_tiff h = {
|
||||||
.data = (unsigned char *) data,
|
.data = (unsigned char *) data,
|
||||||
.position = 0,
|
.position = 0,
|
||||||
.len = len,
|
.len = len,
|
||||||
|
@ -1726,8 +1719,8 @@ open_libtiff(const gchar *data, gsize len, const gchar *path, GError **error)
|
||||||
|
|
||||||
cairo_surface_t *result = NULL, *result_tail = NULL;
|
cairo_surface_t *result = NULL, *result_tail = NULL;
|
||||||
TIFF *tiff = TIFFClientOpen(path, "rm" /* Avoid mmap. */, &h,
|
TIFF *tiff = TIFFClientOpen(path, "rm" /* Avoid mmap. */, &h,
|
||||||
fastiv_io_tiff_read, fastiv_io_tiff_write, fastiv_io_tiff_seek,
|
fiv_io_tiff_read, fiv_io_tiff_write, fiv_io_tiff_seek,
|
||||||
fastiv_io_tiff_close, fastiv_io_tiff_size, NULL, NULL);
|
fiv_io_tiff_close, fiv_io_tiff_size, NULL, NULL);
|
||||||
if (!tiff)
|
if (!tiff)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
@ -1759,7 +1752,7 @@ open_libtiff(const gchar *data, gsize len, const gchar *path, GError **error)
|
||||||
// We inform about unsupported directories, but do not fail on them.
|
// We inform about unsupported directories, but do not fail on them.
|
||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
if (!try_append_page(
|
if (!try_append_page(
|
||||||
load_libtiff_directory(tiff, &err), &result, &result_tail)) {
|
load_libtiff_directory(tiff, &err), &result, &result_tail)) {
|
||||||
g_warning("%s: %s", path, err->message);
|
g_warning("%s: %s", path, err->message);
|
||||||
g_error_free(err);
|
g_error_free(err);
|
||||||
}
|
}
|
||||||
|
@ -1803,8 +1796,8 @@ open_gdkpixbuf(const gchar *data, gsize len, GError **error)
|
||||||
if (orientation && strlen(orientation) == 1) {
|
if (orientation && strlen(orientation) == 1) {
|
||||||
int n = *orientation - '0';
|
int n = *orientation - '0';
|
||||||
if (n >= 1 && n <= 8)
|
if (n >= 1 && n <= 8)
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_orientation,
|
cairo_surface_set_user_data(
|
||||||
(void *) (uintptr_t) n, NULL);
|
surface, &fiv_io_key_orientation, (void *) (uintptr_t) n, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *icc_profile = gdk_pixbuf_get_option(pixbuf, "icc-profile");
|
const char *icc_profile = gdk_pixbuf_get_option(pixbuf, "icc-profile");
|
||||||
|
@ -1812,7 +1805,7 @@ open_gdkpixbuf(const gchar *data, gsize len, GError **error)
|
||||||
gsize out_len = 0;
|
gsize out_len = 0;
|
||||||
guchar *raw = g_base64_decode(icc_profile, &out_len);
|
guchar *raw = g_base64_decode(icc_profile, &out_len);
|
||||||
if (raw) {
|
if (raw) {
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_icc,
|
cairo_surface_set_user_data(surface, &fiv_io_key_icc,
|
||||||
g_bytes_new_take(raw, out_len),
|
g_bytes_new_take(raw, out_len),
|
||||||
(cairo_destroy_func_t) g_bytes_unref);
|
(cairo_destroy_func_t) g_bytes_unref);
|
||||||
}
|
}
|
||||||
|
@ -1824,21 +1817,21 @@ open_gdkpixbuf(const gchar *data, gsize len, GError **error)
|
||||||
|
|
||||||
#endif // HAVE_GDKPIXBUF ------------------------------------------------------
|
#endif // HAVE_GDKPIXBUF ------------------------------------------------------
|
||||||
|
|
||||||
cairo_user_data_key_t fastiv_io_key_exif;
|
cairo_user_data_key_t fiv_io_key_exif;
|
||||||
cairo_user_data_key_t fastiv_io_key_orientation;
|
cairo_user_data_key_t fiv_io_key_orientation;
|
||||||
cairo_user_data_key_t fastiv_io_key_icc;
|
cairo_user_data_key_t fiv_io_key_icc;
|
||||||
cairo_user_data_key_t fastiv_io_key_xmp;
|
cairo_user_data_key_t fiv_io_key_xmp;
|
||||||
|
|
||||||
cairo_user_data_key_t fastiv_io_key_frame_next;
|
cairo_user_data_key_t fiv_io_key_frame_next;
|
||||||
cairo_user_data_key_t fastiv_io_key_frame_previous;
|
cairo_user_data_key_t fiv_io_key_frame_previous;
|
||||||
cairo_user_data_key_t fastiv_io_key_frame_duration;
|
cairo_user_data_key_t fiv_io_key_frame_duration;
|
||||||
cairo_user_data_key_t fastiv_io_key_loops;
|
cairo_user_data_key_t fiv_io_key_loops;
|
||||||
|
|
||||||
cairo_user_data_key_t fastiv_io_key_page_next;
|
cairo_user_data_key_t fiv_io_key_page_next;
|
||||||
cairo_user_data_key_t fastiv_io_key_page_previous;
|
cairo_user_data_key_t fiv_io_key_page_previous;
|
||||||
|
|
||||||
cairo_surface_t *
|
cairo_surface_t *
|
||||||
fastiv_io_open(const gchar *path, GError **error)
|
fiv_io_open(const gchar *path, GError **error)
|
||||||
{
|
{
|
||||||
// TODO(p): Don't always load everything into memory, test type first,
|
// TODO(p): Don't always load everything into memory, test type first,
|
||||||
// so that we can reject non-pictures early. Wuffs only needs the first
|
// so that we can reject non-pictures early. Wuffs only needs the first
|
||||||
|
@ -1859,14 +1852,14 @@ fastiv_io_open(const gchar *path, GError **error)
|
||||||
if (!g_file_get_contents(path, &data, &len, error))
|
if (!g_file_get_contents(path, &data, &len, error))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
cairo_surface_t *surface = fastiv_io_open_from_data(data, len, path, error);
|
cairo_surface_t *surface = fiv_io_open_from_data(data, len, path, error);
|
||||||
free(data);
|
free(data);
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_surface_t *
|
cairo_surface_t *
|
||||||
fastiv_io_open_from_data(const char *data, size_t len, const gchar *path,
|
fiv_io_open_from_data(
|
||||||
GError **error)
|
const char *data, size_t len, const gchar *path, GError **error)
|
||||||
{
|
{
|
||||||
wuffs_base__slice_u8 prefix =
|
wuffs_base__slice_u8 prefix =
|
||||||
wuffs_base__make_slice_u8((uint8_t *) data, len);
|
wuffs_base__make_slice_u8((uint8_t *) data, len);
|
||||||
|
@ -1972,11 +1965,11 @@ fastiv_io_open_from_data(const char *data, size_t len, const gchar *path,
|
||||||
gsize exif_len = 0;
|
gsize exif_len = 0;
|
||||||
gconstpointer exif_data = NULL;
|
gconstpointer exif_data = NULL;
|
||||||
if (surface &&
|
if (surface &&
|
||||||
(exif = cairo_surface_get_user_data(surface, &fastiv_io_key_exif)) &&
|
(exif = cairo_surface_get_user_data(surface, &fiv_io_key_exif)) &&
|
||||||
(exif_data = g_bytes_get_data(exif, &exif_len))) {
|
(exif_data = g_bytes_get_data(exif, &exif_len))) {
|
||||||
cairo_surface_set_user_data(surface, &fastiv_io_key_orientation,
|
cairo_surface_set_user_data(surface, &fiv_io_key_orientation,
|
||||||
(void *) (uintptr_t) fastiv_io_exif_orientation(
|
(void *) (uintptr_t) fiv_io_exif_orientation(exif_data, exif_len),
|
||||||
exif_data, exif_len), NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
@ -2067,11 +2060,11 @@ encode_webp_animation(WebPMux *mux, cairo_surface_t *page)
|
||||||
{
|
{
|
||||||
gboolean ok = TRUE;
|
gboolean ok = TRUE;
|
||||||
for (cairo_surface_t *frame = page; ok && frame; frame =
|
for (cairo_surface_t *frame = page; ok && frame; frame =
|
||||||
cairo_surface_get_user_data(frame, &fastiv_io_key_frame_next)) {
|
cairo_surface_get_user_data(frame, &fiv_io_key_frame_next)) {
|
||||||
WebPMuxFrameInfo info = {
|
WebPMuxFrameInfo info = {
|
||||||
.bitstream = encode_lossless_webp(frame),
|
.bitstream = encode_lossless_webp(frame),
|
||||||
.duration = (intptr_t) cairo_surface_get_user_data(
|
.duration = (intptr_t) cairo_surface_get_user_data(
|
||||||
frame, &fastiv_io_key_frame_duration),
|
frame, &fiv_io_key_frame_duration),
|
||||||
.id = WEBP_CHUNK_ANMF,
|
.id = WEBP_CHUNK_ANMF,
|
||||||
.dispose_method = WEBP_MUX_DISPOSE_NONE,
|
.dispose_method = WEBP_MUX_DISPOSE_NONE,
|
||||||
.blend_method = WEBP_MUX_NO_BLEND,
|
.blend_method = WEBP_MUX_NO_BLEND,
|
||||||
|
@ -2082,7 +2075,7 @@ encode_webp_animation(WebPMux *mux, cairo_surface_t *page)
|
||||||
WebPMuxAnimParams params = {
|
WebPMuxAnimParams params = {
|
||||||
.bgcolor = 0x00000000, // BGRA, curiously.
|
.bgcolor = 0x00000000, // BGRA, curiously.
|
||||||
.loop_count = (uintptr_t)
|
.loop_count = (uintptr_t)
|
||||||
cairo_surface_get_user_data(page, &fastiv_io_key_loops),
|
cairo_surface_get_user_data(page, &fiv_io_key_loops),
|
||||||
};
|
};
|
||||||
return ok && WebPMuxSetAnimationParams(mux, ¶ms) == WEBP_MUX_OK;
|
return ok && WebPMuxSetAnimationParams(mux, ¶ms) == WEBP_MUX_OK;
|
||||||
}
|
}
|
||||||
|
@ -2102,7 +2095,7 @@ transfer_metadata(WebPMux *mux, const char *fourcc, cairo_surface_t *page,
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
fastiv_io_save(cairo_surface_t *page, cairo_surface_t *frame, const gchar *path,
|
fiv_io_save(cairo_surface_t *page, cairo_surface_t *frame, const gchar *path,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail(page != NULL, FALSE);
|
g_return_val_if_fail(page != NULL, FALSE);
|
||||||
|
@ -2112,14 +2105,14 @@ fastiv_io_save(cairo_surface_t *page, cairo_surface_t *frame, const gchar *path,
|
||||||
WebPMux *mux = WebPMuxNew();
|
WebPMux *mux = WebPMuxNew();
|
||||||
if (frame)
|
if (frame)
|
||||||
ok = encode_webp_image(mux, frame);
|
ok = encode_webp_image(mux, frame);
|
||||||
else if (!cairo_surface_get_user_data(page, &fastiv_io_key_frame_next))
|
else if (!cairo_surface_get_user_data(page, &fiv_io_key_frame_next))
|
||||||
ok = encode_webp_image(mux, page);
|
ok = encode_webp_image(mux, page);
|
||||||
else
|
else
|
||||||
ok = encode_webp_animation(mux, page);
|
ok = encode_webp_animation(mux, page);
|
||||||
|
|
||||||
ok = ok && transfer_metadata(mux, "EXIF", page, &fastiv_io_key_exif);
|
ok = ok && transfer_metadata(mux, "EXIF", page, &fiv_io_key_exif);
|
||||||
ok = ok && transfer_metadata(mux, "ICCP", page, &fastiv_io_key_icc);
|
ok = ok && transfer_metadata(mux, "ICCP", page, &fiv_io_key_icc);
|
||||||
ok = ok && transfer_metadata(mux, "XMP ", page, &fastiv_io_key_xmp);
|
ok = ok && transfer_metadata(mux, "XMP ", page, &fiv_io_key_xmp);
|
||||||
|
|
||||||
WebPData assembled = {};
|
WebPData assembled = {};
|
||||||
WebPDataInit(&assembled);
|
WebPDataInit(&assembled);
|
||||||
|
@ -2137,8 +2130,8 @@ fastiv_io_save(cairo_surface_t *page, cairo_surface_t *frame, const gchar *path,
|
||||||
#endif // HAVE_LIBWEBP
|
#endif // HAVE_LIBWEBP
|
||||||
// --- Metadata ----------------------------------------------------------------
|
// --- Metadata ----------------------------------------------------------------
|
||||||
|
|
||||||
FastivIoOrientation
|
FivIoOrientation
|
||||||
fastiv_io_exif_orientation(const guint8 *tiff, gsize len)
|
fiv_io_exif_orientation(const guint8 *tiff, gsize len)
|
||||||
{
|
{
|
||||||
// libtiff also knows how to do this, but it's not a lot of code.
|
// libtiff also knows how to do this, but it's not a lot of code.
|
||||||
// The "Orientation" tag/field is part of Baseline TIFF 6.0 (1992),
|
// The "Orientation" tag/field is part of Baseline TIFF 6.0 (1992),
|
||||||
|
@ -2152,7 +2145,7 @@ fastiv_io_exif_orientation(const guint8 *tiff, gsize len)
|
||||||
uint16_t (*u16)(const uint8_t *) = NULL;
|
uint16_t (*u16)(const uint8_t *) = NULL;
|
||||||
uint32_t (*u32)(const uint8_t *) = NULL;
|
uint32_t (*u32)(const uint8_t *) = NULL;
|
||||||
if (tiff + 8 > end) {
|
if (tiff + 8 > end) {
|
||||||
return FastivIoOrientationUnknown;
|
return FivIoOrientationUnknown;
|
||||||
} else if (!memcmp(tiff, le, sizeof le)) {
|
} else if (!memcmp(tiff, le, sizeof le)) {
|
||||||
u16 = wuffs_base__peek_u16le__no_bounds_check;
|
u16 = wuffs_base__peek_u16le__no_bounds_check;
|
||||||
u32 = wuffs_base__peek_u32le__no_bounds_check;
|
u32 = wuffs_base__peek_u32le__no_bounds_check;
|
||||||
|
@ -2160,12 +2153,12 @@ fastiv_io_exif_orientation(const guint8 *tiff, gsize len)
|
||||||
u16 = wuffs_base__peek_u16be__no_bounds_check;
|
u16 = wuffs_base__peek_u16be__no_bounds_check;
|
||||||
u32 = wuffs_base__peek_u32be__no_bounds_check;
|
u32 = wuffs_base__peek_u32be__no_bounds_check;
|
||||||
} else {
|
} else {
|
||||||
return FastivIoOrientationUnknown;
|
return FivIoOrientationUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t *ifd0 = tiff + u32(tiff + 4);
|
const uint8_t *ifd0 = tiff + u32(tiff + 4);
|
||||||
if (ifd0 + 2 > end)
|
if (ifd0 + 2 > end)
|
||||||
return FastivIoOrientationUnknown;
|
return FivIoOrientationUnknown;
|
||||||
|
|
||||||
uint16_t fields = u16(ifd0);
|
uint16_t fields = u16(ifd0);
|
||||||
enum { BYTE = 1, ASCII, SHORT, LONG, RATIONAL,
|
enum { BYTE = 1, ASCII, SHORT, LONG, RATIONAL,
|
||||||
|
@ -2178,12 +2171,11 @@ fastiv_io_exif_orientation(const guint8 *tiff, gsize len)
|
||||||
value16 >= 1 && value16 <= 8)
|
value16 >= 1 && value16 <= 8)
|
||||||
return value16;
|
return value16;
|
||||||
}
|
}
|
||||||
return FastivIoOrientationUnknown;
|
return FivIoOrientationUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
fastiv_io_save_metadata(
|
fiv_io_save_metadata(cairo_surface_t *page, const gchar *path, GError **error)
|
||||||
cairo_surface_t *page, const gchar *path, GError **error)
|
|
||||||
{
|
{
|
||||||
g_return_val_if_fail(page != NULL, FALSE);
|
g_return_val_if_fail(page != NULL, FALSE);
|
||||||
|
|
||||||
|
@ -2204,7 +2196,7 @@ fastiv_io_save_metadata(
|
||||||
|
|
||||||
// Adobe XMP Specification Part 3: Storage in Files, 2020/1, 1.1.3
|
// Adobe XMP Specification Part 3: Storage in Files, 2020/1, 1.1.3
|
||||||
// I don't care if Exiv2 supports it this way.
|
// I don't care if Exiv2 supports it this way.
|
||||||
if ((data = cairo_surface_get_user_data(page, &fastiv_io_key_exif)) &&
|
if ((data = cairo_surface_get_user_data(page, &fiv_io_key_exif)) &&
|
||||||
(p = g_bytes_get_data(data, &len))) {
|
(p = g_bytes_get_data(data, &len))) {
|
||||||
while (len) {
|
while (len) {
|
||||||
gsize chunk = MIN(len, 0xFFFF - 2 - 6);
|
gsize chunk = MIN(len, 0xFFFF - 2 - 6);
|
||||||
|
@ -2221,7 +2213,7 @@ fastiv_io_save_metadata(
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.color.org/specification/ICC1v43_2010-12.pdf B.4
|
// https://www.color.org/specification/ICC1v43_2010-12.pdf B.4
|
||||||
if ((data = cairo_surface_get_user_data(page, &fastiv_io_key_icc)) &&
|
if ((data = cairo_surface_get_user_data(page, &fiv_io_key_icc)) &&
|
||||||
(p = g_bytes_get_data(data, &len))) {
|
(p = g_bytes_get_data(data, &len))) {
|
||||||
gsize limit = 0xFFFF - 2 - 12;
|
gsize limit = 0xFFFF - 2 - 12;
|
||||||
uint8_t current = 0, total = (len + limit - 1) / limit;
|
uint8_t current = 0, total = (len + limit - 1) / limit;
|
||||||
|
@ -2244,7 +2236,7 @@ fastiv_io_save_metadata(
|
||||||
// Adobe XMP Specification Part 3: Storage in Files, 2020/1, 1.1.3
|
// Adobe XMP Specification Part 3: Storage in Files, 2020/1, 1.1.3
|
||||||
// If the main segment overflows, then it's a sign of bad luck,
|
// If the main segment overflows, then it's a sign of bad luck,
|
||||||
// because 1.1.3.1 is way too complex.
|
// because 1.1.3.1 is way too complex.
|
||||||
if ((data = cairo_surface_get_user_data(page, &fastiv_io_key_xmp)) &&
|
if ((data = cairo_surface_get_user_data(page, &fiv_io_key_xmp)) &&
|
||||||
(p = g_bytes_get_data(data, &len))) {
|
(p = g_bytes_get_data(data, &len))) {
|
||||||
while (len) {
|
while (len) {
|
||||||
gsize chunk = MIN(len, 0xFFFF - 2 - 29);
|
gsize chunk = MIN(len, 0xFFFF - 2 - 29);
|
||||||
|
@ -2277,25 +2269,25 @@ fastiv_io_save_metadata(
|
||||||
// --- Thumbnails --------------------------------------------------------------
|
// --- Thumbnails --------------------------------------------------------------
|
||||||
|
|
||||||
GType
|
GType
|
||||||
fastiv_io_thumbnail_size_get_type(void)
|
fiv_io_thumbnail_size_get_type(void)
|
||||||
{
|
{
|
||||||
static gsize guard;
|
static gsize guard;
|
||||||
if (g_once_init_enter(&guard)) {
|
if (g_once_init_enter(&guard)) {
|
||||||
#define XX(name, value, dir) {FASTIV_IO_THUMBNAIL_SIZE_ ## name, \
|
#define XX(name, value, dir) {FIV_IO_THUMBNAIL_SIZE_ ## name, \
|
||||||
"FASTIV_IO_THUMBNAIL_SIZE_" #name, #name},
|
"FIV_IO_THUMBNAIL_SIZE_" #name, #name},
|
||||||
static const GEnumValue values[] = {FASTIV_IO_THUMBNAIL_SIZES(XX) {}};
|
static const GEnumValue values[] = {FIV_IO_THUMBNAIL_SIZES(XX) {}};
|
||||||
#undef XX
|
#undef XX
|
||||||
GType type = g_enum_register_static(
|
GType type = g_enum_register_static(
|
||||||
g_intern_static_string("FastivIoThumbnailSize"), values);
|
g_intern_static_string("FivIoThumbnailSize"), values);
|
||||||
g_once_init_leave(&guard, type);
|
g_once_init_leave(&guard, type);
|
||||||
}
|
}
|
||||||
return guard;
|
return guard;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define XX(name, value, dir) {value, dir},
|
#define XX(name, value, dir) {value, dir},
|
||||||
FastivIoThumbnailSizeInfo
|
FivIoThumbnailSizeInfo
|
||||||
fastiv_io_thumbnail_sizes[FASTIV_IO_THUMBNAIL_SIZE_COUNT] = {
|
fiv_io_thumbnail_sizes[FIV_IO_THUMBNAIL_SIZE_COUNT] = {
|
||||||
FASTIV_IO_THUMBNAIL_SIZES(XX)};
|
FIV_IO_THUMBNAIL_SIZES(XX)};
|
||||||
#undef XX
|
#undef XX
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -2436,10 +2428,10 @@ fail_init:
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_surface_t *
|
cairo_surface_t *
|
||||||
fastiv_io_lookup_thumbnail(GFile *target, FastivIoThumbnailSize size)
|
fiv_io_lookup_thumbnail(GFile *target, FivIoThumbnailSize size)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail(size >= FASTIV_IO_THUMBNAIL_SIZE_MIN &&
|
g_return_val_if_fail(size >= FIV_IO_THUMBNAIL_SIZE_MIN &&
|
||||||
size <= FASTIV_IO_THUMBNAIL_SIZE_MAX, NULL);
|
size <= FIV_IO_THUMBNAIL_SIZE_MAX, NULL);
|
||||||
|
|
||||||
// Local files only, at least for now.
|
// Local files only, at least for now.
|
||||||
gchar *path = g_file_get_path(target);
|
gchar *path = g_file_get_path(target);
|
||||||
|
@ -2459,13 +2451,13 @@ fastiv_io_lookup_thumbnail(GFile *target, FastivIoThumbnailSize size)
|
||||||
// The lookup sequence is: nominal..max, then mirroring back to ..min.
|
// The lookup sequence is: nominal..max, then mirroring back to ..min.
|
||||||
cairo_surface_t *result = NULL;
|
cairo_surface_t *result = NULL;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
for (int i = 0; i < FASTIV_IO_THUMBNAIL_SIZE_COUNT; i++) {
|
for (int i = 0; i < FIV_IO_THUMBNAIL_SIZE_COUNT; i++) {
|
||||||
int use = size + i;
|
int use = size + i;
|
||||||
if (use > FASTIV_IO_THUMBNAIL_SIZE_MAX)
|
if (use > FIV_IO_THUMBNAIL_SIZE_MAX)
|
||||||
use = FASTIV_IO_THUMBNAIL_SIZE_MAX - i;
|
use = FIV_IO_THUMBNAIL_SIZE_MAX - i;
|
||||||
|
|
||||||
gchar *path = g_strdup_printf("%s/thumbnails/%s/%s.png", cache_dir,
|
gchar *path = g_strdup_printf("%s/thumbnails/%s/%s.png", cache_dir,
|
||||||
fastiv_io_thumbnail_sizes[use].thumbnail_spec_name, sum);
|
fiv_io_thumbnail_sizes[use].thumbnail_spec_name, sum);
|
||||||
result = read_spng_thumbnail(path, uri, st.st_mtim.tv_sec, &error);
|
result = read_spng_thumbnail(path, uri, st.st_mtim.tv_sec, &error);
|
||||||
if (error) {
|
if (error) {
|
||||||
g_debug("%s: %s", path, error->message);
|
g_debug("%s: %s", path, error->message);
|
||||||
|
@ -2483,7 +2475,7 @@ fastiv_io_lookup_thumbnail(GFile *target, FastivIoThumbnailSize size)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fastiv_io_filecmp(GFile *location1, GFile *location2)
|
fiv_io_filecmp(GFile *location1, GFile *location2)
|
||||||
{
|
{
|
||||||
if (g_file_has_prefix(location1, location2))
|
if (g_file_has_prefix(location1, location2))
|
||||||
return +1;
|
return +1;
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// fastiv-io.h: image operations
|
// fiv-io.h: image operations
|
||||||
//
|
//
|
||||||
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
||||||
//
|
//
|
||||||
|
@ -18,105 +18,105 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
#include <glib.h>
|
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
extern const char *fastiv_io_supported_media_types[];
|
extern const char *fiv_io_supported_media_types[];
|
||||||
|
|
||||||
char **fastiv_io_all_supported_media_types(void);
|
char **fiv_io_all_supported_media_types(void);
|
||||||
|
|
||||||
// Userdata are typically attached to all Cairo surfaces in an animation.
|
// Userdata are typically attached to all Cairo surfaces in an animation.
|
||||||
|
|
||||||
/// GBytes with plain Exif/TIFF data.
|
/// GBytes with plain Exif/TIFF data.
|
||||||
extern cairo_user_data_key_t fastiv_io_key_exif;
|
extern cairo_user_data_key_t fiv_io_key_exif;
|
||||||
/// FastivIoOrientation, as a uintptr_t.
|
/// FivIoOrientation, as a uintptr_t.
|
||||||
extern cairo_user_data_key_t fastiv_io_key_orientation;
|
extern cairo_user_data_key_t fiv_io_key_orientation;
|
||||||
/// GBytes with plain ICC profile data.
|
/// GBytes with plain ICC profile data.
|
||||||
extern cairo_user_data_key_t fastiv_io_key_icc;
|
extern cairo_user_data_key_t fiv_io_key_icc;
|
||||||
/// GBytes with plain XMP data.
|
/// GBytes with plain XMP data.
|
||||||
extern cairo_user_data_key_t fastiv_io_key_xmp;
|
extern cairo_user_data_key_t fiv_io_key_xmp;
|
||||||
|
|
||||||
/// The next frame in a sequence, as a surface, in a chain, pre-composited.
|
/// The next frame in a sequence, as a surface, in a chain, pre-composited.
|
||||||
/// There is no wrap-around.
|
/// There is no wrap-around.
|
||||||
extern cairo_user_data_key_t fastiv_io_key_frame_next;
|
extern cairo_user_data_key_t fiv_io_key_frame_next;
|
||||||
/// The previous frame in a sequence, as a surface, in a chain, pre-composited.
|
/// The previous frame in a sequence, as a surface, in a chain, pre-composited.
|
||||||
/// This is a weak pointer that wraps around, and needn't be present
|
/// This is a weak pointer that wraps around, and needn't be present
|
||||||
/// for static images.
|
/// for static images.
|
||||||
extern cairo_user_data_key_t fastiv_io_key_frame_previous;
|
extern cairo_user_data_key_t fiv_io_key_frame_previous;
|
||||||
/// Frame duration in milliseconds as an intptr_t.
|
/// Frame duration in milliseconds as an intptr_t.
|
||||||
extern cairo_user_data_key_t fastiv_io_key_frame_duration;
|
extern cairo_user_data_key_t fiv_io_key_frame_duration;
|
||||||
/// How many times to repeat the animation, or zero for +inf, as a uintptr_t.
|
/// How many times to repeat the animation, or zero for +inf, as a uintptr_t.
|
||||||
extern cairo_user_data_key_t fastiv_io_key_loops;
|
extern cairo_user_data_key_t fiv_io_key_loops;
|
||||||
|
|
||||||
/// The first frame of the next page, as a surface, in a chain.
|
/// The first frame of the next page, as a surface, in a chain.
|
||||||
/// There is no wrap-around.
|
/// There is no wrap-around.
|
||||||
extern cairo_user_data_key_t fastiv_io_key_page_next;
|
extern cairo_user_data_key_t fiv_io_key_page_next;
|
||||||
/// The first frame of the previous page, as a surface, in a chain.
|
/// The first frame of the previous page, as a surface, in a chain.
|
||||||
/// There is no wrap-around. This is a weak pointer.
|
/// There is no wrap-around. This is a weak pointer.
|
||||||
extern cairo_user_data_key_t fastiv_io_key_page_previous;
|
extern cairo_user_data_key_t fiv_io_key_page_previous;
|
||||||
|
|
||||||
cairo_surface_t *fastiv_io_open(const gchar *path, GError **error);
|
cairo_surface_t *fiv_io_open(const gchar *path, GError **error);
|
||||||
cairo_surface_t *fastiv_io_open_from_data(
|
cairo_surface_t *fiv_io_open_from_data(
|
||||||
const char *data, size_t len, const gchar *path, GError **error);
|
const char *data, size_t len, const gchar *path, GError **error);
|
||||||
|
|
||||||
int fastiv_io_filecmp(GFile *f1, GFile *f2);
|
int fiv_io_filecmp(GFile *f1, GFile *f2);
|
||||||
|
|
||||||
// --- Export ------------------------------------------------------------------
|
// --- Export ------------------------------------------------------------------
|
||||||
|
|
||||||
/// Requires libwebp.
|
/// Requires libwebp.
|
||||||
/// If no exact frame is specified, this potentially creates an animation.
|
/// If no exact frame is specified, this potentially creates an animation.
|
||||||
gboolean fastiv_io_save(cairo_surface_t *page, cairo_surface_t *frame,
|
gboolean fiv_io_save(cairo_surface_t *page, cairo_surface_t *frame,
|
||||||
const gchar *path, GError **error);
|
const gchar *path, GError **error);
|
||||||
|
|
||||||
// --- Metadata ----------------------------------------------------------------
|
// --- Metadata ----------------------------------------------------------------
|
||||||
|
|
||||||
// https://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf Table 6
|
// https://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf Table 6
|
||||||
typedef enum _FastivIoOrientation {
|
typedef enum _FivIoOrientation {
|
||||||
FastivIoOrientationUnknown = 0,
|
FivIoOrientationUnknown = 0,
|
||||||
FastivIoOrientation0 = 1,
|
FivIoOrientation0 = 1,
|
||||||
FastivIoOrientationMirror0 = 2,
|
FivIoOrientationMirror0 = 2,
|
||||||
FastivIoOrientation180 = 3,
|
FivIoOrientation180 = 3,
|
||||||
FastivIoOrientationMirror180 = 4,
|
FivIoOrientationMirror180 = 4,
|
||||||
FastivIoOrientationMirror270 = 5,
|
FivIoOrientationMirror270 = 5,
|
||||||
FastivIoOrientation90 = 6,
|
FivIoOrientation90 = 6,
|
||||||
FastivIoOrientationMirror90 = 7,
|
FivIoOrientationMirror90 = 7,
|
||||||
FastivIoOrientation270 = 8
|
FivIoOrientation270 = 8
|
||||||
} FastivIoOrientation;
|
} FivIoOrientation;
|
||||||
|
|
||||||
FastivIoOrientation fastiv_io_exif_orientation(const guint8 *exif, gsize len);
|
FivIoOrientation fiv_io_exif_orientation(const guint8 *exif, gsize len);
|
||||||
|
|
||||||
/// Save metadata attached by this module in Exiv2 format.
|
/// Save metadata attached by this module in Exiv2 format.
|
||||||
gboolean fastiv_io_save_metadata(
|
gboolean fiv_io_save_metadata(
|
||||||
cairo_surface_t *page, const gchar *path, GError **error);
|
cairo_surface_t *page, const gchar *path, GError **error);
|
||||||
|
|
||||||
// --- Thumbnails --------------------------------------------------------------
|
// --- Thumbnails --------------------------------------------------------------
|
||||||
|
|
||||||
// And this is how you avoid glib-mkenums.
|
// And this is how you avoid glib-mkenums.
|
||||||
typedef enum _FastivIoThumbnailSize {
|
typedef enum _FivIoThumbnailSize {
|
||||||
#define FASTIV_IO_THUMBNAIL_SIZES(XX) \
|
#define FIV_IO_THUMBNAIL_SIZES(XX) \
|
||||||
XX(SMALL, 128, "normal") \
|
XX(SMALL, 128, "normal") \
|
||||||
XX(NORMAL, 256, "large") \
|
XX(NORMAL, 256, "large") \
|
||||||
XX(LARGE, 512, "x-large") \
|
XX(LARGE, 512, "x-large") \
|
||||||
XX(HUGE, 1024, "xx-large")
|
XX(HUGE, 1024, "xx-large")
|
||||||
#define XX(name, value, dir) FASTIV_IO_THUMBNAIL_SIZE_ ## name,
|
#define XX(name, value, dir) FIV_IO_THUMBNAIL_SIZE_ ## name,
|
||||||
FASTIV_IO_THUMBNAIL_SIZES(XX)
|
FIV_IO_THUMBNAIL_SIZES(XX)
|
||||||
#undef XX
|
#undef XX
|
||||||
FASTIV_IO_THUMBNAIL_SIZE_COUNT,
|
FIV_IO_THUMBNAIL_SIZE_COUNT,
|
||||||
|
|
||||||
FASTIV_IO_THUMBNAIL_SIZE_MIN = 0,
|
FIV_IO_THUMBNAIL_SIZE_MIN = 0,
|
||||||
FASTIV_IO_THUMBNAIL_SIZE_MAX = FASTIV_IO_THUMBNAIL_SIZE_COUNT - 1
|
FIV_IO_THUMBNAIL_SIZE_MAX = FIV_IO_THUMBNAIL_SIZE_COUNT - 1
|
||||||
} FastivIoThumbnailSize;
|
} FivIoThumbnailSize;
|
||||||
|
|
||||||
GType fastiv_io_thumbnail_size_get_type(void) G_GNUC_CONST;
|
GType fiv_io_thumbnail_size_get_type(void) G_GNUC_CONST;
|
||||||
#define FASTIV_TYPE_IO_THUMBNAIL_SIZE (fastiv_io_thumbnail_size_get_type())
|
#define FIV_TYPE_IO_THUMBNAIL_SIZE (fiv_io_thumbnail_size_get_type())
|
||||||
|
|
||||||
typedef struct _FastivIoThumbnailSizeInfo {
|
typedef struct _FivIoThumbnailSizeInfo {
|
||||||
int size; ///< Nominal size in pixels
|
int size; ///< Nominal size in pixels
|
||||||
const char *thumbnail_spec_name; ///< thumbnail-spec directory name
|
const char *thumbnail_spec_name; ///< thumbnail-spec directory name
|
||||||
} FastivIoThumbnailSizeInfo;
|
} FivIoThumbnailSizeInfo;
|
||||||
|
|
||||||
extern FastivIoThumbnailSizeInfo
|
extern FivIoThumbnailSizeInfo
|
||||||
fastiv_io_thumbnail_sizes[FASTIV_IO_THUMBNAIL_SIZE_COUNT];
|
fiv_io_thumbnail_sizes[FIV_IO_THUMBNAIL_SIZE_COUNT];
|
||||||
|
|
||||||
cairo_surface_t *fastiv_io_lookup_thumbnail(
|
cairo_surface_t *fiv_io_lookup_thumbnail(
|
||||||
GFile *target, FastivIoThumbnailSize size);
|
GFile *target, FivIoThumbnailSize size);
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// fastiv-sidebar.c: molesting GtkPlacesSidebar
|
// fiv-sidebar.c: molesting GtkPlacesSidebar
|
||||||
//
|
//
|
||||||
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
||||||
//
|
//
|
||||||
|
@ -17,10 +17,10 @@
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
#include "fastiv-io.h" // fastiv_io_filecmp
|
#include "fiv-io.h" // fiv_io_filecmp
|
||||||
#include "fastiv-sidebar.h"
|
#include "fiv-sidebar.h"
|
||||||
|
|
||||||
struct _FastivSidebar {
|
struct _FivSidebar {
|
||||||
GtkScrolledWindow parent_instance;
|
GtkScrolledWindow parent_instance;
|
||||||
GtkPlacesSidebar *places;
|
GtkPlacesSidebar *places;
|
||||||
GtkWidget *toolbar;
|
GtkWidget *toolbar;
|
||||||
|
@ -28,9 +28,9 @@ struct _FastivSidebar {
|
||||||
GFile *location;
|
GFile *location;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE(FastivSidebar, fastiv_sidebar, GTK_TYPE_SCROLLED_WINDOW)
|
G_DEFINE_TYPE(FivSidebar, fiv_sidebar, GTK_TYPE_SCROLLED_WINDOW)
|
||||||
|
|
||||||
G_DEFINE_QUARK(fastiv-sidebar-location-quark, fastiv_sidebar_location)
|
G_DEFINE_QUARK(fiv-sidebar-location-quark, fiv_sidebar_location)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
OPEN_LOCATION,
|
OPEN_LOCATION,
|
||||||
|
@ -41,19 +41,19 @@ enum {
|
||||||
static guint sidebar_signals[LAST_SIGNAL];
|
static guint sidebar_signals[LAST_SIGNAL];
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_sidebar_dispose(GObject *gobject)
|
fiv_sidebar_dispose(GObject *gobject)
|
||||||
{
|
{
|
||||||
FastivSidebar *self = FASTIV_SIDEBAR(gobject);
|
FivSidebar *self = FIV_SIDEBAR(gobject);
|
||||||
g_clear_object(&self->location);
|
g_clear_object(&self->location);
|
||||||
|
|
||||||
G_OBJECT_CLASS(fastiv_sidebar_parent_class)->dispose(gobject);
|
G_OBJECT_CLASS(fiv_sidebar_parent_class)->dispose(gobject);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_sidebar_class_init(FastivSidebarClass *klass)
|
fiv_sidebar_class_init(FivSidebarClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||||
object_class->dispose = fastiv_sidebar_dispose;
|
object_class->dispose = fiv_sidebar_dispose;
|
||||||
|
|
||||||
// You're giving me no choice, Adwaita.
|
// You're giving me no choice, Adwaita.
|
||||||
// Your style is hardcoded to match against the class' CSS name.
|
// Your style is hardcoded to match against the class' CSS name.
|
||||||
|
@ -117,7 +117,7 @@ create_row(GFile *file, const char *icon_name)
|
||||||
gtk_container_add(GTK_CONTAINER(revealer), rowbox);
|
gtk_container_add(GTK_CONTAINER(revealer), rowbox);
|
||||||
|
|
||||||
GtkWidget *row = gtk_list_box_row_new();
|
GtkWidget *row = gtk_list_box_row_new();
|
||||||
g_object_set_qdata_full(G_OBJECT(row), fastiv_sidebar_location_quark(),
|
g_object_set_qdata_full(G_OBJECT(row), fiv_sidebar_location_quark(),
|
||||||
g_object_ref(file), (GDestroyNotify) g_object_unref);
|
g_object_ref(file), (GDestroyNotify) g_object_unref);
|
||||||
gtk_container_add(GTK_CONTAINER(row), revealer);
|
gtk_container_add(GTK_CONTAINER(row), revealer);
|
||||||
gtk_widget_show_all(row);
|
gtk_widget_show_all(row);
|
||||||
|
@ -128,13 +128,13 @@ static gint
|
||||||
listbox_compare(
|
listbox_compare(
|
||||||
GtkListBoxRow *row1, GtkListBoxRow *row2, G_GNUC_UNUSED gpointer user_data)
|
GtkListBoxRow *row1, GtkListBoxRow *row2, G_GNUC_UNUSED gpointer user_data)
|
||||||
{
|
{
|
||||||
return fastiv_io_filecmp(
|
return fiv_io_filecmp(
|
||||||
g_object_get_qdata(G_OBJECT(row1), fastiv_sidebar_location_quark()),
|
g_object_get_qdata(G_OBJECT(row1), fiv_sidebar_location_quark()),
|
||||||
g_object_get_qdata(G_OBJECT(row2), fastiv_sidebar_location_quark()));
|
g_object_get_qdata(G_OBJECT(row2), fiv_sidebar_location_quark()));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_location(FastivSidebar *self, GFile *location)
|
update_location(FivSidebar *self, GFile *location)
|
||||||
{
|
{
|
||||||
if (location) {
|
if (location) {
|
||||||
g_clear_object(&self->location);
|
g_clear_object(&self->location);
|
||||||
|
@ -172,7 +172,7 @@ update_location(FastivSidebar *self, GFile *location)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO(p): gtk_list_box_set_filter_func(), or even use a model,
|
// TODO(p): gtk_list_box_set_filter_func(), or even use a model,
|
||||||
// which could be shared with FastivBrowser.
|
// which could be shared with FivBrowser.
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
GFileInfo *info = NULL;
|
GFileInfo *info = NULL;
|
||||||
GFile *child = NULL;
|
GFile *child = NULL;
|
||||||
|
@ -192,9 +192,9 @@ static void
|
||||||
on_open_breadcrumb(
|
on_open_breadcrumb(
|
||||||
G_GNUC_UNUSED GtkListBox *listbox, GtkListBoxRow *row, gpointer user_data)
|
G_GNUC_UNUSED GtkListBox *listbox, GtkListBoxRow *row, gpointer user_data)
|
||||||
{
|
{
|
||||||
FastivSidebar *self = FASTIV_SIDEBAR(user_data);
|
FivSidebar *self = FIV_SIDEBAR(user_data);
|
||||||
GFile *location =
|
GFile *location =
|
||||||
g_object_get_qdata(G_OBJECT(row), fastiv_sidebar_location_quark());
|
g_object_get_qdata(G_OBJECT(row), fiv_sidebar_location_quark());
|
||||||
g_signal_emit(self, sidebar_signals[OPEN_LOCATION], 0,
|
g_signal_emit(self, sidebar_signals[OPEN_LOCATION], 0,
|
||||||
location, GTK_PLACES_OPEN_NORMAL);
|
location, GTK_PLACES_OPEN_NORMAL);
|
||||||
}
|
}
|
||||||
|
@ -203,7 +203,7 @@ static void
|
||||||
on_open_location(G_GNUC_UNUSED GtkPlacesSidebar *sidebar, GFile *location,
|
on_open_location(G_GNUC_UNUSED GtkPlacesSidebar *sidebar, GFile *location,
|
||||||
GtkPlacesOpenFlags flags, gpointer user_data)
|
GtkPlacesOpenFlags flags, gpointer user_data)
|
||||||
{
|
{
|
||||||
FastivSidebar *self = FASTIV_SIDEBAR(user_data);
|
FivSidebar *self = FIV_SIDEBAR(user_data);
|
||||||
g_signal_emit(self, sidebar_signals[OPEN_LOCATION], 0, location, flags);
|
g_signal_emit(self, sidebar_signals[OPEN_LOCATION], 0, location, flags);
|
||||||
|
|
||||||
// Deselect the item in GtkPlacesSidebar, if unsuccessful.
|
// Deselect the item in GtkPlacesSidebar, if unsuccessful.
|
||||||
|
@ -216,7 +216,7 @@ complete_path(GFile *location, GtkListStore *model)
|
||||||
// TODO(p): Do not enter directories unless followed by '/'.
|
// TODO(p): Do not enter directories unless followed by '/'.
|
||||||
// This information has already been stripped from `location`.
|
// This information has already been stripped from `location`.
|
||||||
GFile *parent = G_FILE_TYPE_DIRECTORY ==
|
GFile *parent = G_FILE_TYPE_DIRECTORY ==
|
||||||
g_file_query_file_type(location, G_FILE_QUERY_INFO_NONE, NULL)
|
g_file_query_file_type(location, G_FILE_QUERY_INFO_NONE, NULL)
|
||||||
? g_object_ref(location)
|
? g_object_ref(location)
|
||||||
: g_file_get_parent(location);
|
: g_file_get_parent(location);
|
||||||
if (!parent)
|
if (!parent)
|
||||||
|
@ -257,7 +257,7 @@ fail_enumerator:
|
||||||
}
|
}
|
||||||
|
|
||||||
static GFile *
|
static GFile *
|
||||||
resolve_location(FastivSidebar *self, const char *text)
|
resolve_location(FivSidebar *self, const char *text)
|
||||||
{
|
{
|
||||||
// Relative paths produce invalid GFile objects with this function.
|
// Relative paths produce invalid GFile objects with this function.
|
||||||
// And even if they didn't, we have our own root for them.
|
// And even if they didn't, we have our own root for them.
|
||||||
|
@ -278,7 +278,7 @@ resolve_location(FastivSidebar *self, const char *text)
|
||||||
static void
|
static void
|
||||||
on_enter_location_changed(GtkEntry *entry, gpointer user_data)
|
on_enter_location_changed(GtkEntry *entry, gpointer user_data)
|
||||||
{
|
{
|
||||||
FastivSidebar *self = FASTIV_SIDEBAR(user_data);
|
FivSidebar *self = FIV_SIDEBAR(user_data);
|
||||||
const char *text = gtk_entry_get_text(entry);
|
const char *text = gtk_entry_get_text(entry);
|
||||||
GFile *location = resolve_location(self, text);
|
GFile *location = resolve_location(self, text);
|
||||||
|
|
||||||
|
@ -299,10 +299,10 @@ on_enter_location_changed(GtkEntry *entry, gpointer user_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_show_enter_location(G_GNUC_UNUSED GtkPlacesSidebar *sidebar,
|
on_show_enter_location(
|
||||||
G_GNUC_UNUSED gpointer user_data)
|
G_GNUC_UNUSED GtkPlacesSidebar *sidebar, G_GNUC_UNUSED gpointer user_data)
|
||||||
{
|
{
|
||||||
FastivSidebar *self = FASTIV_SIDEBAR(user_data);
|
FivSidebar *self = FIV_SIDEBAR(user_data);
|
||||||
GtkWidget *dialog = gtk_dialog_new_with_buttons("Enter location",
|
GtkWidget *dialog = gtk_dialog_new_with_buttons("Enter location",
|
||||||
GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(self))),
|
GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(self))),
|
||||||
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL |
|
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL |
|
||||||
|
@ -353,7 +353,7 @@ on_show_enter_location(G_GNUC_UNUSED GtkPlacesSidebar *sidebar,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_sidebar_init(FastivSidebar *self)
|
fiv_sidebar_init(FivSidebar *self)
|
||||||
{
|
{
|
||||||
// TODO(p): Transplant functionality from the shitty GtkPlacesSidebar.
|
// TODO(p): Transplant functionality from the shitty GtkPlacesSidebar.
|
||||||
// We cannot reasonably place any new items within its own GtkListBox,
|
// We cannot reasonably place any new items within its own GtkListBox,
|
||||||
|
@ -406,28 +406,28 @@ fastiv_sidebar_init(FastivSidebar *self)
|
||||||
gtk_style_context_add_class(gtk_widget_get_style_context(GTK_WIDGET(self)),
|
gtk_style_context_add_class(gtk_widget_get_style_context(GTK_WIDGET(self)),
|
||||||
GTK_STYLE_CLASS_SIDEBAR);
|
GTK_STYLE_CLASS_SIDEBAR);
|
||||||
gtk_style_context_add_class(gtk_widget_get_style_context(GTK_WIDGET(self)),
|
gtk_style_context_add_class(gtk_widget_get_style_context(GTK_WIDGET(self)),
|
||||||
"fastiv");
|
"fiv");
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Public interface --------------------------------------------------------
|
// --- Public interface --------------------------------------------------------
|
||||||
|
|
||||||
void
|
void
|
||||||
fastiv_sidebar_set_location(FastivSidebar *self, GFile *location)
|
fiv_sidebar_set_location(FivSidebar *self, GFile *location)
|
||||||
{
|
{
|
||||||
g_return_if_fail(FASTIV_IS_SIDEBAR(self));
|
g_return_if_fail(FIV_IS_SIDEBAR(self));
|
||||||
update_location(self, location);
|
update_location(self, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fastiv_sidebar_show_enter_location(FastivSidebar *self)
|
fiv_sidebar_show_enter_location(FivSidebar *self)
|
||||||
{
|
{
|
||||||
g_return_if_fail(FASTIV_IS_SIDEBAR(self));
|
g_return_if_fail(FIV_IS_SIDEBAR(self));
|
||||||
g_signal_emit_by_name(self->places, "show-enter-location");
|
g_signal_emit_by_name(self->places, "show-enter-location");
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkBox *
|
GtkBox *
|
||||||
fastiv_sidebar_get_toolbar(FastivSidebar *self)
|
fiv_sidebar_get_toolbar(FivSidebar *self)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail(FASTIV_IS_SIDEBAR(self), NULL);
|
g_return_val_if_fail(FIV_IS_SIDEBAR(self), NULL);
|
||||||
return GTK_BOX(self->toolbar);
|
return GTK_BOX(self->toolbar);
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// fastiv-sidebar.h: molesting GtkPlacesSidebar
|
// fiv-sidebar.h: molesting GtkPlacesSidebar
|
||||||
//
|
//
|
||||||
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
||||||
//
|
//
|
||||||
|
@ -19,10 +19,9 @@
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
#define FASTIV_TYPE_SIDEBAR (fastiv_sidebar_get_type())
|
#define FIV_TYPE_SIDEBAR (fiv_sidebar_get_type())
|
||||||
G_DECLARE_FINAL_TYPE(
|
G_DECLARE_FINAL_TYPE(FivSidebar, fiv_sidebar, FIV, SIDEBAR, GtkScrolledWindow)
|
||||||
FastivSidebar, fastiv_sidebar, FASTIV, SIDEBAR, GtkScrolledWindow)
|
|
||||||
|
|
||||||
void fastiv_sidebar_set_location(FastivSidebar *self, GFile *location);
|
void fiv_sidebar_set_location(FivSidebar *self, GFile *location);
|
||||||
void fastiv_sidebar_show_enter_location(FastivSidebar *self);
|
void fiv_sidebar_show_enter_location(FivSidebar *self);
|
||||||
GtkBox *fastiv_sidebar_get_toolbar(FastivSidebar *self);
|
GtkBox *fiv_sidebar_get_toolbar(FivSidebar *self);
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// fastiv-view.c: fast image viewer - view widget
|
// fiv-view.c: fast image viewer - view widget
|
||||||
//
|
//
|
||||||
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
||||||
//
|
//
|
||||||
|
@ -28,15 +28,15 @@
|
||||||
#include <gdk/gdkquartz.h>
|
#include <gdk/gdkquartz.h>
|
||||||
#endif // GDK_WINDOWING_QUARTZ
|
#endif // GDK_WINDOWING_QUARTZ
|
||||||
|
|
||||||
#include "fastiv-io.h"
|
#include "fiv-io.h"
|
||||||
#include "fastiv-view.h"
|
#include "fiv-view.h"
|
||||||
|
|
||||||
struct _FastivView {
|
struct _FivView {
|
||||||
GtkWidget parent_instance;
|
GtkWidget parent_instance;
|
||||||
cairo_surface_t *image; ///< The loaded image (sequence)
|
cairo_surface_t *image; ///< The loaded image (sequence)
|
||||||
cairo_surface_t *page; ///< Current page within image, weak
|
cairo_surface_t *page; ///< Current page within image, weak
|
||||||
cairo_surface_t *frame; ///< Current frame within page, weak
|
cairo_surface_t *frame; ///< Current frame within page, weak
|
||||||
FastivIoOrientation orientation; ///< Current page orientation
|
FivIoOrientation orientation; ///< Current page orientation
|
||||||
bool filter; ///< Smooth scaling toggle
|
bool filter; ///< Smooth scaling toggle
|
||||||
bool scale_to_fit; ///< Image no larger than the allocation
|
bool scale_to_fit; ///< Image no larger than the allocation
|
||||||
double scale; ///< Scaling factor
|
double scale; ///< Scaling factor
|
||||||
|
@ -46,42 +46,42 @@ struct _FastivView {
|
||||||
gulong frame_update_connection; ///< GdkFrameClock::update
|
gulong frame_update_connection; ///< GdkFrameClock::update
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE(FastivView, fastiv_view, GTK_TYPE_WIDGET)
|
G_DEFINE_TYPE(FivView, fiv_view, GTK_TYPE_WIDGET)
|
||||||
|
|
||||||
static FastivIoOrientation view_left[9] = {
|
static FivIoOrientation view_left[9] = {
|
||||||
[FastivIoOrientationUnknown] = FastivIoOrientationUnknown,
|
[FivIoOrientationUnknown] = FivIoOrientationUnknown,
|
||||||
[FastivIoOrientation0] = FastivIoOrientation270,
|
[FivIoOrientation0] = FivIoOrientation270,
|
||||||
[FastivIoOrientationMirror0] = FastivIoOrientationMirror270,
|
[FivIoOrientationMirror0] = FivIoOrientationMirror270,
|
||||||
[FastivIoOrientation180] = FastivIoOrientation90,
|
[FivIoOrientation180] = FivIoOrientation90,
|
||||||
[FastivIoOrientationMirror180] = FastivIoOrientationMirror90,
|
[FivIoOrientationMirror180] = FivIoOrientationMirror90,
|
||||||
[FastivIoOrientationMirror270] = FastivIoOrientationMirror180,
|
[FivIoOrientationMirror270] = FivIoOrientationMirror180,
|
||||||
[FastivIoOrientation90] = FastivIoOrientation0,
|
[FivIoOrientation90] = FivIoOrientation0,
|
||||||
[FastivIoOrientationMirror90] = FastivIoOrientationMirror0,
|
[FivIoOrientationMirror90] = FivIoOrientationMirror0,
|
||||||
[FastivIoOrientation270] = FastivIoOrientation180
|
[FivIoOrientation270] = FivIoOrientation180
|
||||||
};
|
};
|
||||||
|
|
||||||
static FastivIoOrientation view_mirror[9] = {
|
static FivIoOrientation view_mirror[9] = {
|
||||||
[FastivIoOrientationUnknown] = FastivIoOrientationUnknown,
|
[FivIoOrientationUnknown] = FivIoOrientationUnknown,
|
||||||
[FastivIoOrientation0] = FastivIoOrientationMirror0,
|
[FivIoOrientation0] = FivIoOrientationMirror0,
|
||||||
[FastivIoOrientationMirror0] = FastivIoOrientation0,
|
[FivIoOrientationMirror0] = FivIoOrientation0,
|
||||||
[FastivIoOrientation180] = FastivIoOrientationMirror180,
|
[FivIoOrientation180] = FivIoOrientationMirror180,
|
||||||
[FastivIoOrientationMirror180] = FastivIoOrientation180,
|
[FivIoOrientationMirror180] = FivIoOrientation180,
|
||||||
[FastivIoOrientationMirror270] = FastivIoOrientation270,
|
[FivIoOrientationMirror270] = FivIoOrientation270,
|
||||||
[FastivIoOrientation90] = FastivIoOrientationMirror270,
|
[FivIoOrientation90] = FivIoOrientationMirror270,
|
||||||
[FastivIoOrientationMirror90] = FastivIoOrientation90,
|
[FivIoOrientationMirror90] = FivIoOrientation90,
|
||||||
[FastivIoOrientation270] = FastivIoOrientationMirror270
|
[FivIoOrientation270] = FivIoOrientationMirror270
|
||||||
};
|
};
|
||||||
|
|
||||||
static FastivIoOrientation view_right[9] = {
|
static FivIoOrientation view_right[9] = {
|
||||||
[FastivIoOrientationUnknown] = FastivIoOrientationUnknown,
|
[FivIoOrientationUnknown] = FivIoOrientationUnknown,
|
||||||
[FastivIoOrientation0] = FastivIoOrientation90,
|
[FivIoOrientation0] = FivIoOrientation90,
|
||||||
[FastivIoOrientationMirror0] = FastivIoOrientationMirror90,
|
[FivIoOrientationMirror0] = FivIoOrientationMirror90,
|
||||||
[FastivIoOrientation180] = FastivIoOrientation270,
|
[FivIoOrientation180] = FivIoOrientation270,
|
||||||
[FastivIoOrientationMirror180] = FastivIoOrientationMirror270,
|
[FivIoOrientationMirror180] = FivIoOrientationMirror270,
|
||||||
[FastivIoOrientationMirror270] = FastivIoOrientationMirror0,
|
[FivIoOrientationMirror270] = FivIoOrientationMirror0,
|
||||||
[FastivIoOrientation90] = FastivIoOrientation180,
|
[FivIoOrientation90] = FivIoOrientation180,
|
||||||
[FastivIoOrientationMirror90] = FastivIoOrientationMirror180,
|
[FivIoOrientationMirror90] = FivIoOrientationMirror180,
|
||||||
[FastivIoOrientation270] = FastivIoOrientation0
|
[FivIoOrientation270] = FivIoOrientation0
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -94,19 +94,19 @@ enum {
|
||||||
static GParamSpec *view_properties[N_PROPERTIES];
|
static GParamSpec *view_properties[N_PROPERTIES];
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_view_finalize(GObject *gobject)
|
fiv_view_finalize(GObject *gobject)
|
||||||
{
|
{
|
||||||
FastivView *self = FASTIV_VIEW(gobject);
|
FivView *self = FIV_VIEW(gobject);
|
||||||
cairo_surface_destroy(self->image);
|
cairo_surface_destroy(self->image);
|
||||||
|
|
||||||
G_OBJECT_CLASS(fastiv_view_parent_class)->finalize(gobject);
|
G_OBJECT_CLASS(fiv_view_parent_class)->finalize(gobject);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_view_get_property(
|
fiv_view_get_property(
|
||||||
GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
|
GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
|
||||||
{
|
{
|
||||||
FastivView *self = FASTIV_VIEW(object);
|
FivView *self = FIV_VIEW(object);
|
||||||
switch (property_id) {
|
switch (property_id) {
|
||||||
case PROP_SCALE:
|
case PROP_SCALE:
|
||||||
g_value_set_double(value, self->scale);
|
g_value_set_double(value, self->scale);
|
||||||
|
@ -123,7 +123,7 @@ fastiv_view_get_property(
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_surface_dimensions(FastivView *self, double *width, double *height)
|
get_surface_dimensions(FivView *self, double *width, double *height)
|
||||||
{
|
{
|
||||||
*width = *height = 0;
|
*width = *height = 0;
|
||||||
if (!self->image)
|
if (!self->image)
|
||||||
|
@ -133,10 +133,10 @@ get_surface_dimensions(FastivView *self, double *width, double *height)
|
||||||
switch (cairo_surface_get_type(self->page)) {
|
switch (cairo_surface_get_type(self->page)) {
|
||||||
case CAIRO_SURFACE_TYPE_IMAGE:
|
case CAIRO_SURFACE_TYPE_IMAGE:
|
||||||
switch (self->orientation) {
|
switch (self->orientation) {
|
||||||
case FastivIoOrientation90:
|
case FivIoOrientation90:
|
||||||
case FastivIoOrientationMirror90:
|
case FivIoOrientationMirror90:
|
||||||
case FastivIoOrientation270:
|
case FivIoOrientation270:
|
||||||
case FastivIoOrientationMirror270:
|
case FivIoOrientationMirror270:
|
||||||
*width = cairo_image_surface_get_height(self->page);
|
*width = cairo_image_surface_get_height(self->page);
|
||||||
*height = cairo_image_surface_get_width(self->page);
|
*height = cairo_image_surface_get_width(self->page);
|
||||||
break;
|
break;
|
||||||
|
@ -160,7 +160,7 @@ get_surface_dimensions(FastivView *self, double *width, double *height)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_display_dimensions(FastivView *self, int *width, int *height)
|
get_display_dimensions(FivView *self, int *width, int *height)
|
||||||
{
|
{
|
||||||
double w, h;
|
double w, h;
|
||||||
get_surface_dimensions(self, &w, &h);
|
get_surface_dimensions(self, &w, &h);
|
||||||
|
@ -170,37 +170,37 @@ get_display_dimensions(FastivView *self, int *width, int *height)
|
||||||
}
|
}
|
||||||
|
|
||||||
static cairo_matrix_t
|
static cairo_matrix_t
|
||||||
get_orientation_matrix(FastivIoOrientation o, double width, double height)
|
get_orientation_matrix(FivIoOrientation o, double width, double height)
|
||||||
{
|
{
|
||||||
cairo_matrix_t matrix = {};
|
cairo_matrix_t matrix = {};
|
||||||
cairo_matrix_init_identity(&matrix);
|
cairo_matrix_init_identity(&matrix);
|
||||||
switch (o) {
|
switch (o) {
|
||||||
case FastivIoOrientation90:
|
case FivIoOrientation90:
|
||||||
cairo_matrix_rotate(&matrix, -M_PI_2);
|
cairo_matrix_rotate(&matrix, -M_PI_2);
|
||||||
cairo_matrix_translate(&matrix, -width, 0);
|
cairo_matrix_translate(&matrix, -width, 0);
|
||||||
break;
|
break;
|
||||||
case FastivIoOrientation180:
|
case FivIoOrientation180:
|
||||||
cairo_matrix_scale(&matrix, -1, -1);
|
cairo_matrix_scale(&matrix, -1, -1);
|
||||||
cairo_matrix_translate(&matrix, -width, -height);
|
cairo_matrix_translate(&matrix, -width, -height);
|
||||||
break;
|
break;
|
||||||
case FastivIoOrientation270:
|
case FivIoOrientation270:
|
||||||
cairo_matrix_rotate(&matrix, +M_PI_2);
|
cairo_matrix_rotate(&matrix, +M_PI_2);
|
||||||
cairo_matrix_translate(&matrix, 0, -height);
|
cairo_matrix_translate(&matrix, 0, -height);
|
||||||
break;
|
break;
|
||||||
case FastivIoOrientationMirror0:
|
case FivIoOrientationMirror0:
|
||||||
cairo_matrix_scale(&matrix, -1, +1);
|
cairo_matrix_scale(&matrix, -1, +1);
|
||||||
cairo_matrix_translate(&matrix, -width, 0);
|
cairo_matrix_translate(&matrix, -width, 0);
|
||||||
break;
|
break;
|
||||||
case FastivIoOrientationMirror90:
|
case FivIoOrientationMirror90:
|
||||||
cairo_matrix_rotate(&matrix, +M_PI_2);
|
cairo_matrix_rotate(&matrix, +M_PI_2);
|
||||||
cairo_matrix_scale(&matrix, -1, +1);
|
cairo_matrix_scale(&matrix, -1, +1);
|
||||||
cairo_matrix_translate(&matrix, -width, -height);
|
cairo_matrix_translate(&matrix, -width, -height);
|
||||||
break;
|
break;
|
||||||
case FastivIoOrientationMirror180:
|
case FivIoOrientationMirror180:
|
||||||
cairo_matrix_scale(&matrix, +1, -1);
|
cairo_matrix_scale(&matrix, +1, -1);
|
||||||
cairo_matrix_translate(&matrix, 0, -height);
|
cairo_matrix_translate(&matrix, 0, -height);
|
||||||
break;
|
break;
|
||||||
case FastivIoOrientationMirror270:
|
case FivIoOrientationMirror270:
|
||||||
cairo_matrix_rotate(&matrix, -M_PI_2);
|
cairo_matrix_rotate(&matrix, -M_PI_2);
|
||||||
cairo_matrix_scale(&matrix, -1, +1);
|
cairo_matrix_scale(&matrix, -1, +1);
|
||||||
default:
|
default:
|
||||||
|
@ -210,10 +210,9 @@ get_orientation_matrix(FastivIoOrientation o, double width, double height)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_view_get_preferred_height(
|
fiv_view_get_preferred_height(GtkWidget *widget, gint *minimum, gint *natural)
|
||||||
GtkWidget *widget, gint *minimum, gint *natural)
|
|
||||||
{
|
{
|
||||||
FastivView *self = FASTIV_VIEW(widget);
|
FivView *self = FIV_VIEW(widget);
|
||||||
if (self->scale_to_fit) {
|
if (self->scale_to_fit) {
|
||||||
double sw, sh;
|
double sw, sh;
|
||||||
get_surface_dimensions(self, &sw, &sh);
|
get_surface_dimensions(self, &sw, &sh);
|
||||||
|
@ -227,9 +226,9 @@ fastiv_view_get_preferred_height(
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_view_get_preferred_width(GtkWidget *widget, gint *minimum, gint *natural)
|
fiv_view_get_preferred_width(GtkWidget *widget, gint *minimum, gint *natural)
|
||||||
{
|
{
|
||||||
FastivView *self = FASTIV_VIEW(widget);
|
FivView *self = FIV_VIEW(widget);
|
||||||
if (self->scale_to_fit) {
|
if (self->scale_to_fit) {
|
||||||
double sw, sh;
|
double sw, sh;
|
||||||
get_surface_dimensions(self, &sw, &sh);
|
get_surface_dimensions(self, &sw, &sh);
|
||||||
|
@ -243,12 +242,11 @@ fastiv_view_get_preferred_width(GtkWidget *widget, gint *minimum, gint *natural)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_view_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
|
fiv_view_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
|
||||||
{
|
{
|
||||||
GTK_WIDGET_CLASS(fastiv_view_parent_class)
|
GTK_WIDGET_CLASS(fiv_view_parent_class)->size_allocate(widget, allocation);
|
||||||
->size_allocate(widget, allocation);
|
|
||||||
|
|
||||||
FastivView *self = FASTIV_VIEW(widget);
|
FivView *self = FIV_VIEW(widget);
|
||||||
if (!self->image || !self->scale_to_fit)
|
if (!self->image || !self->scale_to_fit)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -264,7 +262,7 @@ fastiv_view_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_view_realize(GtkWidget *widget)
|
fiv_view_realize(GtkWidget *widget)
|
||||||
{
|
{
|
||||||
GtkAllocation allocation;
|
GtkAllocation allocation;
|
||||||
gtk_widget_get_allocation(widget, &allocation);
|
gtk_widget_get_allocation(widget, &allocation);
|
||||||
|
@ -312,7 +310,7 @@ fastiv_view_realize(GtkWidget *widget)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fastiv_view_draw(GtkWidget *widget, cairo_t *cr)
|
fiv_view_draw(GtkWidget *widget, cairo_t *cr)
|
||||||
{
|
{
|
||||||
// Placed here due to our using a native GdkWindow on X11,
|
// Placed here due to our using a native GdkWindow on X11,
|
||||||
// which makes the widget have no double buffering or default background.
|
// which makes the widget have no double buffering or default background.
|
||||||
|
@ -321,7 +319,7 @@ fastiv_view_draw(GtkWidget *widget, cairo_t *cr)
|
||||||
gtk_render_background(gtk_widget_get_style_context(widget), cr, 0, 0,
|
gtk_render_background(gtk_widget_get_style_context(widget), cr, 0, 0,
|
||||||
allocation.width, allocation.height);
|
allocation.width, allocation.height);
|
||||||
|
|
||||||
FastivView *self = FASTIV_VIEW(widget);
|
FivView *self = FIV_VIEW(widget);
|
||||||
if (!self->image ||
|
if (!self->image ||
|
||||||
!gtk_cairo_should_draw_window(cr, gtk_widget_get_window(widget)))
|
!gtk_cairo_should_draw_window(cr, gtk_widget_get_window(widget)))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -386,10 +384,9 @@ fastiv_view_draw(GtkWidget *widget, cairo_t *cr)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fastiv_view_button_press_event(GtkWidget *widget, GdkEventButton *event)
|
fiv_view_button_press_event(GtkWidget *widget, GdkEventButton *event)
|
||||||
{
|
{
|
||||||
GTK_WIDGET_CLASS(fastiv_view_parent_class)
|
GTK_WIDGET_CLASS(fiv_view_parent_class)->button_press_event(widget, event);
|
||||||
->button_press_event(widget, event);
|
|
||||||
|
|
||||||
if (event->button == GDK_BUTTON_PRIMARY &&
|
if (event->button == GDK_BUTTON_PRIMARY &&
|
||||||
gtk_widget_get_focus_on_click(widget))
|
gtk_widget_get_focus_on_click(widget))
|
||||||
|
@ -402,7 +399,7 @@ fastiv_view_button_press_event(GtkWidget *widget, GdkEventButton *event)
|
||||||
#define SCALE_STEP 1.4
|
#define SCALE_STEP 1.4
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
set_scale_to_fit(FastivView *self, bool scale_to_fit)
|
set_scale_to_fit(FivView *self, bool scale_to_fit)
|
||||||
{
|
{
|
||||||
self->scale_to_fit = scale_to_fit;
|
self->scale_to_fit = scale_to_fit;
|
||||||
|
|
||||||
|
@ -413,7 +410,7 @@ set_scale_to_fit(FastivView *self, bool scale_to_fit)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
set_scale(FastivView *self, double scale)
|
set_scale(FivView *self, double scale)
|
||||||
{
|
{
|
||||||
self->scale = scale;
|
self->scale = scale;
|
||||||
g_object_notify_by_pspec(
|
g_object_notify_by_pspec(
|
||||||
|
@ -422,9 +419,9 @@ set_scale(FastivView *self, double scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fastiv_view_scroll_event(GtkWidget *widget, GdkEventScroll *event)
|
fiv_view_scroll_event(GtkWidget *widget, GdkEventScroll *event)
|
||||||
{
|
{
|
||||||
FastivView *self = FASTIV_VIEW(widget);
|
FivView *self = FIV_VIEW(widget);
|
||||||
if (!self->image)
|
if (!self->image)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (event->state & gtk_accelerator_get_default_mod_mask())
|
if (event->state & gtk_accelerator_get_default_mod_mask())
|
||||||
|
@ -443,7 +440,7 @@ fastiv_view_scroll_event(GtkWidget *widget, GdkEventScroll *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
stop_animating(FastivView *self)
|
stop_animating(FivView *self)
|
||||||
{
|
{
|
||||||
GdkFrameClock *clock = gtk_widget_get_frame_clock(GTK_WIDGET(self));
|
GdkFrameClock *clock = gtk_widget_get_frame_clock(GTK_WIDGET(self));
|
||||||
if (!clock || !self->frame_update_connection)
|
if (!clock || !self->frame_update_connection)
|
||||||
|
@ -458,10 +455,10 @@ stop_animating(FastivView *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
advance_frame(FastivView *self)
|
advance_frame(FivView *self)
|
||||||
{
|
{
|
||||||
cairo_surface_t *next =
|
cairo_surface_t *next =
|
||||||
cairo_surface_get_user_data(self->frame, &fastiv_io_key_frame_next);
|
cairo_surface_get_user_data(self->frame, &fiv_io_key_frame_next);
|
||||||
if (next) {
|
if (next) {
|
||||||
self->frame = next;
|
self->frame = next;
|
||||||
} else {
|
} else {
|
||||||
|
@ -474,13 +471,13 @@ advance_frame(FastivView *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
advance_animation(FastivView *self, GdkFrameClock *clock)
|
advance_animation(FivView *self, GdkFrameClock *clock)
|
||||||
{
|
{
|
||||||
gint64 now = gdk_frame_clock_get_frame_time(clock);
|
gint64 now = gdk_frame_clock_get_frame_time(clock);
|
||||||
while (true) {
|
while (true) {
|
||||||
// TODO(p): See if infinite frames can actually happen, and how.
|
// TODO(p): See if infinite frames can actually happen, and how.
|
||||||
intptr_t duration = (intptr_t) cairo_surface_get_user_data(
|
intptr_t duration = (intptr_t) cairo_surface_get_user_data(
|
||||||
self->frame, &fastiv_io_key_frame_duration);
|
self->frame, &fiv_io_key_frame_duration);
|
||||||
if (duration < 0)
|
if (duration < 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
@ -507,57 +504,56 @@ advance_animation(FastivView *self, GdkFrameClock *clock)
|
||||||
static void
|
static void
|
||||||
on_frame_clock_update(GdkFrameClock *clock, gpointer user_data)
|
on_frame_clock_update(GdkFrameClock *clock, gpointer user_data)
|
||||||
{
|
{
|
||||||
FastivView *self = FASTIV_VIEW(user_data);
|
FivView *self = FIV_VIEW(user_data);
|
||||||
if (!advance_animation(self, clock))
|
if (!advance_animation(self, clock))
|
||||||
stop_animating(self);
|
stop_animating(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
start_animating(FastivView *self)
|
start_animating(FivView *self)
|
||||||
{
|
{
|
||||||
stop_animating(self);
|
stop_animating(self);
|
||||||
|
|
||||||
GdkFrameClock *clock = gtk_widget_get_frame_clock(GTK_WIDGET(self));
|
GdkFrameClock *clock = gtk_widget_get_frame_clock(GTK_WIDGET(self));
|
||||||
if (!clock || !self->image ||
|
if (!clock || !self->image ||
|
||||||
!cairo_surface_get_user_data(self->page, &fastiv_io_key_frame_next))
|
!cairo_surface_get_user_data(self->page, &fiv_io_key_frame_next))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
self->frame_time = gdk_frame_clock_get_frame_time(clock);
|
self->frame_time = gdk_frame_clock_get_frame_time(clock);
|
||||||
self->frame_update_connection = g_signal_connect(
|
self->frame_update_connection = g_signal_connect(
|
||||||
clock, "update", G_CALLBACK(on_frame_clock_update), self);
|
clock, "update", G_CALLBACK(on_frame_clock_update), self);
|
||||||
self->remaining_loops = (uintptr_t) cairo_surface_get_user_data(
|
self->remaining_loops =
|
||||||
self->page, &fastiv_io_key_loops);
|
(uintptr_t) cairo_surface_get_user_data(self->page, &fiv_io_key_loops);
|
||||||
|
|
||||||
gdk_frame_clock_begin_updating(clock);
|
gdk_frame_clock_begin_updating(clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
switch_page(FastivView *self, cairo_surface_t *page)
|
switch_page(FivView *self, cairo_surface_t *page)
|
||||||
{
|
{
|
||||||
self->frame = self->page = page;
|
self->frame = self->page = page;
|
||||||
if ((self->orientation = (uintptr_t) cairo_surface_get_user_data(
|
if ((self->orientation = (uintptr_t) cairo_surface_get_user_data(
|
||||||
self->page, &fastiv_io_key_orientation)) ==
|
self->page, &fiv_io_key_orientation)) == FivIoOrientationUnknown)
|
||||||
FastivIoOrientationUnknown)
|
self->orientation = FivIoOrientation0;
|
||||||
self->orientation = FastivIoOrientation0;
|
|
||||||
|
|
||||||
start_animating(self);
|
start_animating(self);
|
||||||
gtk_widget_queue_resize(GTK_WIDGET(self));
|
gtk_widget_queue_resize(GTK_WIDGET(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_view_map(GtkWidget *widget)
|
fiv_view_map(GtkWidget *widget)
|
||||||
{
|
{
|
||||||
GTK_WIDGET_CLASS(fastiv_view_parent_class)->map(widget);
|
GTK_WIDGET_CLASS(fiv_view_parent_class)->map(widget);
|
||||||
|
|
||||||
// Loading before mapping will fail to obtain a GdkFrameClock.
|
// Loading before mapping will fail to obtain a GdkFrameClock.
|
||||||
start_animating(FASTIV_VIEW(widget));
|
start_animating(FIV_VIEW(widget));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fastiv_view_unmap(GtkWidget *widget)
|
fiv_view_unmap(GtkWidget *widget)
|
||||||
{
|
{
|
||||||
stop_animating(FASTIV_VIEW(widget));
|
stop_animating(FIV_VIEW(widget));
|
||||||
GTK_WIDGET_CLASS(fastiv_view_parent_class)->unmap(widget);
|
GTK_WIDGET_CLASS(fiv_view_parent_class)->unmap(widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -582,7 +578,7 @@ get_toplevel(GtkWidget *widget)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_draw_page(G_GNUC_UNUSED GtkPrintOperation *operation,
|
on_draw_page(G_GNUC_UNUSED GtkPrintOperation *operation,
|
||||||
GtkPrintContext *context, G_GNUC_UNUSED int page_nr, FastivView *self)
|
GtkPrintContext *context, G_GNUC_UNUSED int page_nr, FivView *self)
|
||||||
{
|
{
|
||||||
double surface_width_px = 0, surface_height_px = 0;
|
double surface_width_px = 0, surface_height_px = 0;
|
||||||
get_surface_dimensions(self, &surface_width_px, &surface_height_px);
|
get_surface_dimensions(self, &surface_width_px, &surface_height_px);
|
||||||
|
@ -606,7 +602,7 @@ on_draw_page(G_GNUC_UNUSED GtkPrintOperation *operation,
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
print(FastivView *self)
|
print(FivView *self)
|
||||||
{
|
{
|
||||||
GtkPrintOperation *print = gtk_print_operation_new();
|
GtkPrintOperation *print = gtk_print_operation_new();
|
||||||
gtk_print_operation_set_n_pages(print, 1);
|
gtk_print_operation_set_n_pages(print, 1);
|
||||||
|
@ -636,7 +632,7 @@ print(FastivView *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
save_as(FastivView *self, gboolean frame)
|
save_as(FivView *self, gboolean frame)
|
||||||
{
|
{
|
||||||
GtkWindow *window = get_toplevel(GTK_WIDGET(self));
|
GtkWindow *window = get_toplevel(GTK_WIDGET(self));
|
||||||
GtkWidget *dialog = gtk_file_chooser_dialog_new(
|
GtkWidget *dialog = gtk_file_chooser_dialog_new(
|
||||||
|
@ -680,11 +676,10 @@ save_as(FastivView *self, gboolean frame)
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
#ifdef HAVE_LIBWEBP
|
#ifdef HAVE_LIBWEBP
|
||||||
if (gtk_file_chooser_get_filter(chooser) == webp_filter)
|
if (gtk_file_chooser_get_filter(chooser) == webp_filter)
|
||||||
fastiv_io_save(self->page,
|
fiv_io_save(self->page, frame ? self->frame : NULL, path, &error);
|
||||||
frame ? self->frame : NULL, path, &error);
|
|
||||||
else
|
else
|
||||||
#endif // HAVE_LIBWEBP
|
#endif // HAVE_LIBWEBP
|
||||||
fastiv_io_save_metadata(self->page, path, &error);
|
fiv_io_save_metadata(self->page, path, &error);
|
||||||
if (error)
|
if (error)
|
||||||
show_error_dialog(window, error);
|
show_error_dialog(window, error);
|
||||||
g_free(path);
|
g_free(path);
|
||||||
|
@ -701,16 +696,16 @@ save_as(FastivView *self, gboolean frame)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
static inline gboolean
|
static inline gboolean
|
||||||
command(FastivView *self, FastivViewCommand command)
|
command(FivView *self, FivViewCommand command)
|
||||||
{
|
{
|
||||||
fastiv_view_command(self, command);
|
fiv_view_command(self, command);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fastiv_view_key_press_event(GtkWidget *widget, GdkEventKey *event)
|
fiv_view_key_press_event(GtkWidget *widget, GdkEventKey *event)
|
||||||
{
|
{
|
||||||
FastivView *self = FASTIV_VIEW(widget);
|
FivView *self = FIV_VIEW(widget);
|
||||||
if (!self->image)
|
if (!self->image)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
@ -722,15 +717,15 @@ fastiv_view_key_press_event(GtkWidget *widget, GdkEventKey *event)
|
||||||
if (state == GDK_CONTROL_MASK) {
|
if (state == GDK_CONTROL_MASK) {
|
||||||
switch (event->keyval) {
|
switch (event->keyval) {
|
||||||
case GDK_KEY_0:
|
case GDK_KEY_0:
|
||||||
return command(self, FASTIV_VIEW_COMMAND_ZOOM_1);
|
return command(self, FIV_VIEW_COMMAND_ZOOM_1);
|
||||||
case GDK_KEY_plus:
|
case GDK_KEY_plus:
|
||||||
return command(self, FASTIV_VIEW_COMMAND_ZOOM_IN);
|
return command(self, FIV_VIEW_COMMAND_ZOOM_IN);
|
||||||
case GDK_KEY_minus:
|
case GDK_KEY_minus:
|
||||||
return command(self, FASTIV_VIEW_COMMAND_ZOOM_OUT);
|
return command(self, FIV_VIEW_COMMAND_ZOOM_OUT);
|
||||||
case GDK_KEY_p:
|
case GDK_KEY_p:
|
||||||
return command(self, FASTIV_VIEW_COMMAND_PRINT);
|
return command(self, FIV_VIEW_COMMAND_PRINT);
|
||||||
case GDK_KEY_s:
|
case GDK_KEY_s:
|
||||||
return command(self, FASTIV_VIEW_COMMAND_SAVE_PAGE);
|
return command(self, FIV_VIEW_COMMAND_SAVE_PAGE);
|
||||||
case GDK_KEY_S:
|
case GDK_KEY_S:
|
||||||
return save_as(self, TRUE);
|
return save_as(self, TRUE);
|
||||||
}
|
}
|
||||||
|
@ -750,9 +745,9 @@ fastiv_view_key_press_event(GtkWidget *widget, GdkEventKey *event)
|
||||||
case GDK_KEY_9:
|
case GDK_KEY_9:
|
||||||
return set_scale(self, event->keyval - GDK_KEY_0);
|
return set_scale(self, event->keyval - GDK_KEY_0);
|
||||||
case GDK_KEY_plus:
|
case GDK_KEY_plus:
|
||||||
return command(self, FASTIV_VIEW_COMMAND_ZOOM_IN);
|
return command(self, FIV_VIEW_COMMAND_ZOOM_IN);
|
||||||
case GDK_KEY_minus:
|
case GDK_KEY_minus:
|
||||||
return command(self, FASTIV_VIEW_COMMAND_ZOOM_OUT);
|
return command(self, FIV_VIEW_COMMAND_ZOOM_OUT);
|
||||||
|
|
||||||
case GDK_KEY_x: // Inspired by gThumb.
|
case GDK_KEY_x: // Inspired by gThumb.
|
||||||
return set_scale_to_fit(self, !self->scale_to_fit);
|
return set_scale_to_fit(self, !self->scale_to_fit);
|
||||||
|
@ -765,31 +760,31 @@ fastiv_view_key_press_event(GtkWidget *widget, GdkEventKey *event)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
case GDK_KEY_less:
|
case GDK_KEY_less:
|
||||||
return command(self, FASTIV_VIEW_COMMAND_ROTATE_LEFT);
|
return command(self, FIV_VIEW_COMMAND_ROTATE_LEFT);
|
||||||
case GDK_KEY_equal:
|
case GDK_KEY_equal:
|
||||||
return command(self, FASTIV_VIEW_COMMAND_MIRROR);
|
return command(self, FIV_VIEW_COMMAND_MIRROR);
|
||||||
case GDK_KEY_greater:
|
case GDK_KEY_greater:
|
||||||
return command(self, FASTIV_VIEW_COMMAND_ROTATE_RIGHT);
|
return command(self, FIV_VIEW_COMMAND_ROTATE_RIGHT);
|
||||||
|
|
||||||
case GDK_KEY_bracketleft:
|
case GDK_KEY_bracketleft:
|
||||||
return command(self, FASTIV_VIEW_COMMAND_PAGE_PREVIOUS);
|
return command(self, FIV_VIEW_COMMAND_PAGE_PREVIOUS);
|
||||||
case GDK_KEY_bracketright:
|
case GDK_KEY_bracketright:
|
||||||
return command(self, FASTIV_VIEW_COMMAND_PAGE_NEXT);
|
return command(self, FIV_VIEW_COMMAND_PAGE_NEXT);
|
||||||
|
|
||||||
case GDK_KEY_braceleft:
|
case GDK_KEY_braceleft:
|
||||||
return command(self, FASTIV_VIEW_COMMAND_FRAME_PREVIOUS);
|
return command(self, FIV_VIEW_COMMAND_FRAME_PREVIOUS);
|
||||||
case GDK_KEY_braceright:
|
case GDK_KEY_braceright:
|
||||||
return command(self, FASTIV_VIEW_COMMAND_FRAME_NEXT);
|
return command(self, FIV_VIEW_COMMAND_FRAME_NEXT);
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_view_class_init(FastivViewClass *klass)
|
fiv_view_class_init(FivViewClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||||
object_class->finalize = fastiv_view_finalize;
|
object_class->finalize = fiv_view_finalize;
|
||||||
object_class->get_property = fastiv_view_get_property;
|
object_class->get_property = fiv_view_get_property;
|
||||||
|
|
||||||
view_properties[PROP_SCALE] = g_param_spec_double(
|
view_properties[PROP_SCALE] = g_param_spec_double(
|
||||||
"scale", "Scale", "Zoom level",
|
"scale", "Scale", "Zoom level",
|
||||||
|
@ -804,24 +799,24 @@ fastiv_view_class_init(FastivViewClass *klass)
|
||||||
object_class, N_PROPERTIES, view_properties);
|
object_class, N_PROPERTIES, view_properties);
|
||||||
|
|
||||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
|
||||||
widget_class->get_preferred_height = fastiv_view_get_preferred_height;
|
widget_class->get_preferred_height = fiv_view_get_preferred_height;
|
||||||
widget_class->get_preferred_width = fastiv_view_get_preferred_width;
|
widget_class->get_preferred_width = fiv_view_get_preferred_width;
|
||||||
widget_class->size_allocate = fastiv_view_size_allocate;
|
widget_class->size_allocate = fiv_view_size_allocate;
|
||||||
widget_class->map = fastiv_view_map;
|
widget_class->map = fiv_view_map;
|
||||||
widget_class->unmap = fastiv_view_unmap;
|
widget_class->unmap = fiv_view_unmap;
|
||||||
widget_class->realize = fastiv_view_realize;
|
widget_class->realize = fiv_view_realize;
|
||||||
widget_class->draw = fastiv_view_draw;
|
widget_class->draw = fiv_view_draw;
|
||||||
widget_class->button_press_event = fastiv_view_button_press_event;
|
widget_class->button_press_event = fiv_view_button_press_event;
|
||||||
widget_class->scroll_event = fastiv_view_scroll_event;
|
widget_class->scroll_event = fiv_view_scroll_event;
|
||||||
widget_class->key_press_event = fastiv_view_key_press_event;
|
widget_class->key_press_event = fiv_view_key_press_event;
|
||||||
|
|
||||||
// TODO(p): Later override "screen_changed", recreate Pango layouts there,
|
// TODO(p): Later override "screen_changed", recreate Pango layouts there,
|
||||||
// if we get to have any, or otherwise reflect DPI changes.
|
// if we get to have any, or otherwise reflect DPI changes.
|
||||||
gtk_widget_class_set_css_name(widget_class, "fastiv-view");
|
gtk_widget_class_set_css_name(widget_class, "fiv-view");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fastiv_view_init(FastivView *self)
|
fiv_view_init(FivView *self)
|
||||||
{
|
{
|
||||||
gtk_widget_set_can_focus(GTK_WIDGET(self), TRUE);
|
gtk_widget_set_can_focus(GTK_WIDGET(self), TRUE);
|
||||||
|
|
||||||
|
@ -833,9 +828,9 @@ fastiv_view_init(FastivView *self)
|
||||||
|
|
||||||
// TODO(p): Progressive picture loading, or at least async/cancellable.
|
// TODO(p): Progressive picture loading, or at least async/cancellable.
|
||||||
gboolean
|
gboolean
|
||||||
fastiv_view_open(FastivView *self, const gchar *path, GError **error)
|
fiv_view_open(FivView *self, const gchar *path, GError **error)
|
||||||
{
|
{
|
||||||
cairo_surface_t *surface = fastiv_io_open(path, error);
|
cairo_surface_t *surface = fiv_io_open(path, error);
|
||||||
if (!surface)
|
if (!surface)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (self->image)
|
if (self->image)
|
||||||
|
@ -849,75 +844,75 @@ fastiv_view_open(FastivView *self, const gchar *path, GError **error)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
page_step(FastivView *self, int step)
|
page_step(FivView *self, int step)
|
||||||
{
|
{
|
||||||
cairo_user_data_key_t *key =
|
cairo_user_data_key_t *key =
|
||||||
step < 0 ? &fastiv_io_key_page_previous : &fastiv_io_key_page_next;
|
step < 0 ? &fiv_io_key_page_previous : &fiv_io_key_page_next;
|
||||||
cairo_surface_t *page = cairo_surface_get_user_data(self->page, key);
|
cairo_surface_t *page = cairo_surface_get_user_data(self->page, key);
|
||||||
if (page)
|
if (page)
|
||||||
switch_page(self, page);
|
switch_page(self, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
frame_step(FastivView *self, int step)
|
frame_step(FivView *self, int step)
|
||||||
{
|
{
|
||||||
stop_animating(self);
|
stop_animating(self);
|
||||||
cairo_user_data_key_t *key =
|
cairo_user_data_key_t *key =
|
||||||
step < 0 ? &fastiv_io_key_frame_previous : &fastiv_io_key_frame_next;
|
step < 0 ? &fiv_io_key_frame_previous : &fiv_io_key_frame_next;
|
||||||
if (!step || !(self->frame = cairo_surface_get_user_data(self->frame, key)))
|
if (!step || !(self->frame = cairo_surface_get_user_data(self->frame, key)))
|
||||||
self->frame = self->page;
|
self->frame = self->page;
|
||||||
gtk_widget_queue_draw(GTK_WIDGET(self));
|
gtk_widget_queue_draw(GTK_WIDGET(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fastiv_view_command(FastivView *self, FastivViewCommand command)
|
fiv_view_command(FivView *self, FivViewCommand command)
|
||||||
{
|
{
|
||||||
g_return_if_fail(FASTIV_IS_VIEW(self));
|
g_return_if_fail(FIV_IS_VIEW(self));
|
||||||
|
|
||||||
GtkWidget *widget = GTK_WIDGET(self);
|
GtkWidget *widget = GTK_WIDGET(self);
|
||||||
if (!self->image)
|
if (!self->image)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
break; case FASTIV_VIEW_COMMAND_ROTATE_LEFT:
|
break; case FIV_VIEW_COMMAND_ROTATE_LEFT:
|
||||||
self->orientation = view_left[self->orientation];
|
self->orientation = view_left[self->orientation];
|
||||||
gtk_widget_queue_resize(widget);
|
gtk_widget_queue_resize(widget);
|
||||||
break; case FASTIV_VIEW_COMMAND_MIRROR:
|
break; case FIV_VIEW_COMMAND_MIRROR:
|
||||||
self->orientation = view_mirror[self->orientation];
|
self->orientation = view_mirror[self->orientation];
|
||||||
gtk_widget_queue_resize(widget);
|
gtk_widget_queue_resize(widget);
|
||||||
break; case FASTIV_VIEW_COMMAND_ROTATE_RIGHT:
|
break; case FIV_VIEW_COMMAND_ROTATE_RIGHT:
|
||||||
self->orientation = view_right[self->orientation];
|
self->orientation = view_right[self->orientation];
|
||||||
gtk_widget_queue_resize(widget);
|
gtk_widget_queue_resize(widget);
|
||||||
|
|
||||||
break; case FASTIV_VIEW_COMMAND_PAGE_FIRST:
|
break; case FIV_VIEW_COMMAND_PAGE_FIRST:
|
||||||
switch_page(self, self->image);
|
switch_page(self, self->image);
|
||||||
break; case FASTIV_VIEW_COMMAND_PAGE_PREVIOUS:
|
break; case FIV_VIEW_COMMAND_PAGE_PREVIOUS:
|
||||||
page_step(self, -1);
|
page_step(self, -1);
|
||||||
break; case FASTIV_VIEW_COMMAND_PAGE_NEXT:
|
break; case FIV_VIEW_COMMAND_PAGE_NEXT:
|
||||||
page_step(self, +1);
|
page_step(self, +1);
|
||||||
break; case FASTIV_VIEW_COMMAND_PAGE_LAST:
|
break; case FIV_VIEW_COMMAND_PAGE_LAST:
|
||||||
for (cairo_surface_t *s = self->page;
|
for (cairo_surface_t *s = self->page;
|
||||||
(s = cairo_surface_get_user_data(s, &fastiv_io_key_page_next)); )
|
(s = cairo_surface_get_user_data(s, &fiv_io_key_page_next)); )
|
||||||
self->page = s;
|
self->page = s;
|
||||||
switch_page(self, self->page);
|
switch_page(self, self->page);
|
||||||
|
|
||||||
break; case FASTIV_VIEW_COMMAND_FRAME_FIRST:
|
break; case FIV_VIEW_COMMAND_FRAME_FIRST:
|
||||||
frame_step(self, 0);
|
frame_step(self, 0);
|
||||||
break; case FASTIV_VIEW_COMMAND_FRAME_PREVIOUS:
|
break; case FIV_VIEW_COMMAND_FRAME_PREVIOUS:
|
||||||
frame_step(self, -1);
|
frame_step(self, -1);
|
||||||
break; case FASTIV_VIEW_COMMAND_FRAME_NEXT:
|
break; case FIV_VIEW_COMMAND_FRAME_NEXT:
|
||||||
frame_step(self, +1);
|
frame_step(self, +1);
|
||||||
|
|
||||||
break; case FASTIV_VIEW_COMMAND_PRINT:
|
break; case FIV_VIEW_COMMAND_PRINT:
|
||||||
print(self);
|
print(self);
|
||||||
break; case FASTIV_VIEW_COMMAND_SAVE_PAGE:
|
break; case FIV_VIEW_COMMAND_SAVE_PAGE:
|
||||||
save_as(self, FALSE);
|
save_as(self, FALSE);
|
||||||
|
|
||||||
break; case FASTIV_VIEW_COMMAND_ZOOM_IN:
|
break; case FIV_VIEW_COMMAND_ZOOM_IN:
|
||||||
set_scale(self, self->scale * SCALE_STEP);
|
set_scale(self, self->scale * SCALE_STEP);
|
||||||
break; case FASTIV_VIEW_COMMAND_ZOOM_OUT:
|
break; case FIV_VIEW_COMMAND_ZOOM_OUT:
|
||||||
set_scale(self, self->scale / SCALE_STEP);
|
set_scale(self, self->scale / SCALE_STEP);
|
||||||
break; case FASTIV_VIEW_COMMAND_ZOOM_1:
|
break; case FIV_VIEW_COMMAND_ZOOM_1:
|
||||||
set_scale(self, 1.0);
|
set_scale(self, 1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// fastiv-view.h: fast image viewer - view widget
|
// fiv-view.h: fast image viewer - view widget
|
||||||
//
|
//
|
||||||
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
// Copyright (c) 2021, Přemysl Eric Janouch <p@janouch.name>
|
||||||
//
|
//
|
||||||
|
@ -19,34 +19,34 @@
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
#define FASTIV_TYPE_VIEW (fastiv_view_get_type())
|
#define FIV_TYPE_VIEW (fiv_view_get_type())
|
||||||
G_DECLARE_FINAL_TYPE(FastivView, fastiv_view, FASTIV, VIEW, GtkWidget)
|
G_DECLARE_FINAL_TYPE(FivView, fiv_view, FIV, VIEW, GtkWidget)
|
||||||
|
|
||||||
/// Try to open the given file, synchronously, to be displayed by the widget.
|
/// Try to open the given file, synchronously, to be displayed by the widget.
|
||||||
gboolean fastiv_view_open(FastivView *self, const gchar *path, GError **error);
|
gboolean fiv_view_open(FivView *self, const gchar *path, GError **error);
|
||||||
|
|
||||||
typedef enum _FastivViewCommand {
|
typedef enum _FivViewCommand {
|
||||||
FASTIV_VIEW_COMMAND_ROTATE_LEFT = 1,
|
FIV_VIEW_COMMAND_ROTATE_LEFT = 1,
|
||||||
FASTIV_VIEW_COMMAND_MIRROR,
|
FIV_VIEW_COMMAND_MIRROR,
|
||||||
FASTIV_VIEW_COMMAND_ROTATE_RIGHT,
|
FIV_VIEW_COMMAND_ROTATE_RIGHT,
|
||||||
|
|
||||||
FASTIV_VIEW_COMMAND_PAGE_FIRST,
|
FIV_VIEW_COMMAND_PAGE_FIRST,
|
||||||
FASTIV_VIEW_COMMAND_PAGE_PREVIOUS,
|
FIV_VIEW_COMMAND_PAGE_PREVIOUS,
|
||||||
FASTIV_VIEW_COMMAND_PAGE_NEXT,
|
FIV_VIEW_COMMAND_PAGE_NEXT,
|
||||||
FASTIV_VIEW_COMMAND_PAGE_LAST,
|
FIV_VIEW_COMMAND_PAGE_LAST,
|
||||||
|
|
||||||
FASTIV_VIEW_COMMAND_FRAME_FIRST,
|
FIV_VIEW_COMMAND_FRAME_FIRST,
|
||||||
FASTIV_VIEW_COMMAND_FRAME_PREVIOUS,
|
FIV_VIEW_COMMAND_FRAME_PREVIOUS,
|
||||||
FASTIV_VIEW_COMMAND_FRAME_NEXT,
|
FIV_VIEW_COMMAND_FRAME_NEXT,
|
||||||
// Going to the end frame makes no sense, wrap around if needed.
|
// Going to the end frame makes no sense, wrap around if needed.
|
||||||
|
|
||||||
FASTIV_VIEW_COMMAND_PRINT,
|
FIV_VIEW_COMMAND_PRINT,
|
||||||
FASTIV_VIEW_COMMAND_SAVE_PAGE,
|
FIV_VIEW_COMMAND_SAVE_PAGE,
|
||||||
|
|
||||||
FASTIV_VIEW_COMMAND_ZOOM_IN,
|
FIV_VIEW_COMMAND_ZOOM_IN,
|
||||||
FASTIV_VIEW_COMMAND_ZOOM_OUT,
|
FIV_VIEW_COMMAND_ZOOM_OUT,
|
||||||
FASTIV_VIEW_COMMAND_ZOOM_1
|
FIV_VIEW_COMMAND_ZOOM_1
|
||||||
} FastivViewCommand;
|
} FivViewCommand;
|
||||||
|
|
||||||
/// Execute a user action.
|
/// Execute a user action.
|
||||||
void fastiv_view_command(FastivView *self, FastivViewCommand command);
|
void fiv_view_command(FivView *self, FivViewCommand command);
|
|
@ -1,3 +1,4 @@
|
||||||
|
# vim: noet ts=4 sts=4 sw=4:
|
||||||
project('fastiv', 'c',
|
project('fastiv', 'c',
|
||||||
default_options : ['c_std=gnu99', 'warning_level=2'],
|
default_options : ['c_std=gnu99', 'warning_level=2'],
|
||||||
version : '0.1.0')
|
version : '0.1.0')
|
||||||
|
@ -65,13 +66,13 @@ resources = gnome.compile_resources('resources',
|
||||||
c_name : 'resources',
|
c_name : 'resources',
|
||||||
)
|
)
|
||||||
|
|
||||||
exe = executable('fastiv', 'fastiv.c', 'fastiv-view.c', 'fastiv-io.c',
|
exe = executable('fastiv', 'fastiv.c', 'fiv-view.c', 'fiv-io.c',
|
||||||
'fastiv-browser.c', 'fastiv-sidebar.c', 'xdg.c', resources,
|
'fiv-browser.c', 'fiv-sidebar.c', 'xdg.c', resources,
|
||||||
install : true,
|
install : true,
|
||||||
dependencies : [dependencies])
|
dependencies : [dependencies])
|
||||||
|
|
||||||
if gdkpixbuf.found()
|
if gdkpixbuf.found()
|
||||||
executable('io-benchmark', 'fastiv-io-benchmark.c', 'fastiv-io.c', 'xdg.c',
|
executable('io-benchmark', 'fiv-io-benchmark.c', 'fiv-io.c', 'xdg.c',
|
||||||
build_by_default : false,
|
build_by_default : false,
|
||||||
dependencies : [dependencies, gdkpixbuf])
|
dependencies : [dependencies, gdkpixbuf])
|
||||||
endif
|
endif
|
||||||
|
|
Loading…
Reference in New Issue