Add a simple toolbar to the view
There is still considerable work to be done.
This commit is contained in:
		
							
								
								
									
										142
									
								
								fastiv-view.c
									
									
									
									
									
								
							
							
						
						
									
										142
									
								
								fastiv-view.c
									
									
									
									
									
								
							@@ -530,7 +530,6 @@ start_animating(FastivView *self)
 | 
				
			|||||||
static void
 | 
					static void
 | 
				
			||||||
switch_page(FastivView *self, cairo_surface_t *page)
 | 
					switch_page(FastivView *self, cairo_surface_t *page)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	GtkWidget *widget = GTK_WIDGET(self);
 | 
					 | 
				
			||||||
	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, &fastiv_io_key_orientation)) ==
 | 
				
			||||||
@@ -538,7 +537,7 @@ switch_page(FastivView *self, cairo_surface_t *page)
 | 
				
			|||||||
		self->orientation = FastivIoOrientation0;
 | 
							self->orientation = FastivIoOrientation0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	start_animating(self);
 | 
						start_animating(self);
 | 
				
			||||||
	gtk_widget_queue_resize(widget);
 | 
						gtk_widget_queue_resize(GTK_WIDGET(self));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
@@ -697,6 +696,13 @@ save_as(FastivView *self, gboolean frame)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
					// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline gboolean
 | 
				
			||||||
 | 
					command(FastivView *self, FastivViewCommand command)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						fastiv_view_command(self, command);
 | 
				
			||||||
 | 
						return TRUE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static gboolean
 | 
					static gboolean
 | 
				
			||||||
fastiv_view_key_press_event(GtkWidget *widget, GdkEventKey *event)
 | 
					fastiv_view_key_press_event(GtkWidget *widget, GdkEventKey *event)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -712,15 +718,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 set_scale(self, 1.0);
 | 
								return command(self, FASTIV_VIEW_COMMAND_ZOOM_1);
 | 
				
			||||||
		case GDK_KEY_plus:
 | 
							case GDK_KEY_plus:
 | 
				
			||||||
			return set_scale(self, self->scale * SCALE_STEP);
 | 
								return command(self, FASTIV_VIEW_COMMAND_ZOOM_IN);
 | 
				
			||||||
		case GDK_KEY_minus:
 | 
							case GDK_KEY_minus:
 | 
				
			||||||
			return set_scale(self, self->scale / SCALE_STEP);
 | 
								return command(self, FASTIV_VIEW_COMMAND_ZOOM_OUT);
 | 
				
			||||||
		case GDK_KEY_p:
 | 
							case GDK_KEY_p:
 | 
				
			||||||
			return print(self);
 | 
								return command(self, FASTIV_VIEW_COMMAND_PRINT);
 | 
				
			||||||
		case GDK_KEY_s:
 | 
							case GDK_KEY_s:
 | 
				
			||||||
			return save_as(self, FALSE);
 | 
								return command(self, FASTIV_VIEW_COMMAND_SAVE_PAGE);
 | 
				
			||||||
		case GDK_KEY_S:
 | 
							case GDK_KEY_S:
 | 
				
			||||||
			return save_as(self, TRUE);
 | 
								return save_as(self, TRUE);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -740,9 +746,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 set_scale(self, self->scale * SCALE_STEP);
 | 
							return command(self, FASTIV_VIEW_COMMAND_ZOOM_IN);
 | 
				
			||||||
	case GDK_KEY_minus:
 | 
						case GDK_KEY_minus:
 | 
				
			||||||
		return set_scale(self, self->scale / SCALE_STEP);
 | 
							return command(self, FASTIV_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);
 | 
				
			||||||
@@ -753,47 +759,21 @@ fastiv_view_key_press_event(GtkWidget *widget, GdkEventKey *event)
 | 
				
			|||||||
		return TRUE;
 | 
							return TRUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case GDK_KEY_less:
 | 
						case GDK_KEY_less:
 | 
				
			||||||
		self->orientation = view_left[self->orientation];
 | 
							return command(self, FASTIV_VIEW_COMMAND_ROTATE_LEFT);
 | 
				
			||||||
		gtk_widget_queue_resize(widget);
 | 
					 | 
				
			||||||
		return TRUE;
 | 
					 | 
				
			||||||
	case GDK_KEY_equal:
 | 
						case GDK_KEY_equal:
 | 
				
			||||||
		self->orientation = view_mirror[self->orientation];
 | 
							return command(self, FASTIV_VIEW_COMMAND_MIRROR);
 | 
				
			||||||
		gtk_widget_queue_draw(widget);
 | 
					 | 
				
			||||||
		return TRUE;
 | 
					 | 
				
			||||||
	case GDK_KEY_greater:
 | 
						case GDK_KEY_greater:
 | 
				
			||||||
		self->orientation = view_right[self->orientation];
 | 
							return command(self, FASTIV_VIEW_COMMAND_ROTATE_RIGHT);
 | 
				
			||||||
		gtk_widget_queue_resize(widget);
 | 
					 | 
				
			||||||
		return TRUE;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case GDK_KEY_bracketleft: {
 | 
						case GDK_KEY_bracketleft:
 | 
				
			||||||
		cairo_surface_t *page = cairo_surface_get_user_data(
 | 
							return command(self, FASTIV_VIEW_COMMAND_PAGE_PREVIOUS);
 | 
				
			||||||
			self->page, &fastiv_io_key_page_previous);
 | 
						case GDK_KEY_bracketright:
 | 
				
			||||||
		if (page)
 | 
							return command(self, FASTIV_VIEW_COMMAND_PAGE_NEXT);
 | 
				
			||||||
			switch_page(self, page);
 | 
					 | 
				
			||||||
		return TRUE;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	case GDK_KEY_bracketright: {
 | 
					 | 
				
			||||||
		cairo_surface_t *page = cairo_surface_get_user_data(
 | 
					 | 
				
			||||||
			self->page, &fastiv_io_key_page_next);
 | 
					 | 
				
			||||||
		if (page)
 | 
					 | 
				
			||||||
			switch_page(self, page);
 | 
					 | 
				
			||||||
		return TRUE;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case GDK_KEY_braceleft:
 | 
						case GDK_KEY_braceleft:
 | 
				
			||||||
		stop_animating(self);
 | 
							return command(self, FASTIV_VIEW_COMMAND_FRAME_PREVIOUS);
 | 
				
			||||||
		if (!(self->frame = cairo_surface_get_user_data(
 | 
					 | 
				
			||||||
				self->frame, &fastiv_io_key_frame_previous)))
 | 
					 | 
				
			||||||
			self->frame = self->page;
 | 
					 | 
				
			||||||
		gtk_widget_queue_draw(widget);
 | 
					 | 
				
			||||||
		return TRUE;
 | 
					 | 
				
			||||||
	case GDK_KEY_braceright:
 | 
						case GDK_KEY_braceright:
 | 
				
			||||||
		stop_animating(self);
 | 
							return command(self, FASTIV_VIEW_COMMAND_FRAME_NEXT);
 | 
				
			||||||
		if (!(self->frame = cairo_surface_get_user_data(
 | 
					 | 
				
			||||||
				self->frame, &fastiv_io_key_frame_next)))
 | 
					 | 
				
			||||||
			self->frame = self->page;
 | 
					 | 
				
			||||||
		gtk_widget_queue_draw(widget);
 | 
					 | 
				
			||||||
		return TRUE;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return FALSE;
 | 
						return FALSE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -858,3 +838,77 @@ fastiv_view_open(FastivView *self, const gchar *path, GError **error)
 | 
				
			|||||||
	set_scale_to_fit(self, true);
 | 
						set_scale_to_fit(self, true);
 | 
				
			||||||
	return TRUE;
 | 
						return TRUE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					page_step(FastivView *self, int step)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						cairo_user_data_key_t *key =
 | 
				
			||||||
 | 
							step < 0 ? &fastiv_io_key_page_previous : &fastiv_io_key_page_next;
 | 
				
			||||||
 | 
						cairo_surface_t *page = cairo_surface_get_user_data(self->page, key);
 | 
				
			||||||
 | 
						if (page)
 | 
				
			||||||
 | 
							switch_page(self, page);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					frame_step(FastivView *self, int step)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						stop_animating(self);
 | 
				
			||||||
 | 
						cairo_user_data_key_t *key =
 | 
				
			||||||
 | 
							step < 0 ? &fastiv_io_key_frame_previous : &fastiv_io_key_frame_next;
 | 
				
			||||||
 | 
						if (!step || !(self->frame = cairo_surface_get_user_data(self->frame, key)))
 | 
				
			||||||
 | 
							self->frame = self->page;
 | 
				
			||||||
 | 
						gtk_widget_queue_draw(GTK_WIDGET(self));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					fastiv_view_command(FastivView *self, FastivViewCommand command)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						g_return_if_fail(FASTIV_IS_VIEW(self));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GtkWidget *widget = GTK_WIDGET(self);
 | 
				
			||||||
 | 
						if (!self->image)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (command) {
 | 
				
			||||||
 | 
						break; case FASTIV_VIEW_COMMAND_ROTATE_LEFT:
 | 
				
			||||||
 | 
							self->orientation = view_left[self->orientation];
 | 
				
			||||||
 | 
							gtk_widget_queue_resize(widget);
 | 
				
			||||||
 | 
						break; case FASTIV_VIEW_COMMAND_MIRROR:
 | 
				
			||||||
 | 
							self->orientation = view_mirror[self->orientation];
 | 
				
			||||||
 | 
							gtk_widget_queue_resize(widget);
 | 
				
			||||||
 | 
						break; case FASTIV_VIEW_COMMAND_ROTATE_RIGHT:
 | 
				
			||||||
 | 
							self->orientation = view_right[self->orientation];
 | 
				
			||||||
 | 
							gtk_widget_queue_resize(widget);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						break; case FASTIV_VIEW_COMMAND_PAGE_FIRST:
 | 
				
			||||||
 | 
							switch_page(self, self->image);
 | 
				
			||||||
 | 
						break; case FASTIV_VIEW_COMMAND_PAGE_PREVIOUS:
 | 
				
			||||||
 | 
							page_step(self, -1);
 | 
				
			||||||
 | 
						break; case FASTIV_VIEW_COMMAND_PAGE_NEXT:
 | 
				
			||||||
 | 
							page_step(self, +1);
 | 
				
			||||||
 | 
						break; case FASTIV_VIEW_COMMAND_PAGE_LAST:
 | 
				
			||||||
 | 
							for (cairo_surface_t *s = self->page;
 | 
				
			||||||
 | 
								 (s = cairo_surface_get_user_data(s, &fastiv_io_key_page_next)); )
 | 
				
			||||||
 | 
								self->page = s;
 | 
				
			||||||
 | 
							switch_page(self, self->page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						break; case FASTIV_VIEW_COMMAND_FRAME_FIRST:
 | 
				
			||||||
 | 
							frame_step(self, 0);
 | 
				
			||||||
 | 
						break; case FASTIV_VIEW_COMMAND_FRAME_PREVIOUS:
 | 
				
			||||||
 | 
							frame_step(self, -1);
 | 
				
			||||||
 | 
						break; case FASTIV_VIEW_COMMAND_FRAME_NEXT:
 | 
				
			||||||
 | 
							frame_step(self, +1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						break; case FASTIV_VIEW_COMMAND_PRINT:
 | 
				
			||||||
 | 
							print(self);
 | 
				
			||||||
 | 
						break; case FASTIV_VIEW_COMMAND_SAVE_PAGE:
 | 
				
			||||||
 | 
							save_as(self, FALSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						break; case FASTIV_VIEW_COMMAND_ZOOM_IN:
 | 
				
			||||||
 | 
							set_scale(self, self->scale * SCALE_STEP);
 | 
				
			||||||
 | 
						break; case FASTIV_VIEW_COMMAND_ZOOM_OUT:
 | 
				
			||||||
 | 
							set_scale(self, self->scale / SCALE_STEP);
 | 
				
			||||||
 | 
						break; case FASTIV_VIEW_COMMAND_ZOOM_1:
 | 
				
			||||||
 | 
							set_scale(self, 1.0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,3 +24,29 @@ G_DECLARE_FINAL_TYPE(FastivView, fastiv_view, FASTIV, 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 fastiv_view_open(FastivView *self, const gchar *path, GError **error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum _FastivViewCommand {
 | 
				
			||||||
 | 
						FASTIV_VIEW_COMMAND_ROTATE_LEFT = 1,
 | 
				
			||||||
 | 
						FASTIV_VIEW_COMMAND_MIRROR,
 | 
				
			||||||
 | 
						FASTIV_VIEW_COMMAND_ROTATE_RIGHT,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FASTIV_VIEW_COMMAND_PAGE_FIRST,
 | 
				
			||||||
 | 
						FASTIV_VIEW_COMMAND_PAGE_PREVIOUS,
 | 
				
			||||||
 | 
						FASTIV_VIEW_COMMAND_PAGE_NEXT,
 | 
				
			||||||
 | 
						FASTIV_VIEW_COMMAND_PAGE_LAST,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FASTIV_VIEW_COMMAND_FRAME_FIRST,
 | 
				
			||||||
 | 
						FASTIV_VIEW_COMMAND_FRAME_PREVIOUS,
 | 
				
			||||||
 | 
						FASTIV_VIEW_COMMAND_FRAME_NEXT,
 | 
				
			||||||
 | 
						// Going to the end frame makes no sense, wrap around if needed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FASTIV_VIEW_COMMAND_PRINT,
 | 
				
			||||||
 | 
						FASTIV_VIEW_COMMAND_SAVE_PAGE,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FASTIV_VIEW_COMMAND_ZOOM_IN,
 | 
				
			||||||
 | 
						FASTIV_VIEW_COMMAND_ZOOM_OUT,
 | 
				
			||||||
 | 
						FASTIV_VIEW_COMMAND_ZOOM_1
 | 
				
			||||||
 | 
					} FastivViewCommand;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Execute a user action.
 | 
				
			||||||
 | 
					void fastiv_view_command(FastivView *self, FastivViewCommand command);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										212
									
								
								fastiv.c
									
									
									
									
									
								
							
							
						
						
									
										212
									
								
								fastiv.c
									
									
									
									
									
								
							@@ -19,10 +19,11 @@
 | 
				
			|||||||
#include <glib/gstdio.h>
 | 
					#include <glib/gstdio.h>
 | 
				
			||||||
#include <gtk/gtk.h>
 | 
					#include <gtk/gtk.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <math.h>
 | 
				
			||||||
#include <stdarg.h>
 | 
					#include <stdarg.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <fnmatch.h>
 | 
					#include <fnmatch.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,6 +54,53 @@ exit_fatal(const gchar *format, ...)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// --- Main --------------------------------------------------------------------
 | 
					// --- Main --------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO(p): Add a toggle for a checkerboard background.
 | 
				
			||||||
 | 
					// TODO(p): Implement commented-out actions.
 | 
				
			||||||
 | 
					#define B make_toolbar_button
 | 
				
			||||||
 | 
					#define TOOLBAR(XX) \
 | 
				
			||||||
 | 
						XX(BROWSE,        B("view-grid-symbolic", "Browse")) \
 | 
				
			||||||
 | 
						XX(FILE_PREVIOUS, B("go-previous-symbolic", "Previous file")) \
 | 
				
			||||||
 | 
						XX(FILE_NEXT,     B("go-next-symbolic", "Next file")) \
 | 
				
			||||||
 | 
						XX(S1,            make_separator()) \
 | 
				
			||||||
 | 
						XX(PAGE_FIRST,    B("go-top-symbolic", "First page")) \
 | 
				
			||||||
 | 
						XX(PAGE_PREVIOUS, B("go-up-symbolic", "Previous page")) \
 | 
				
			||||||
 | 
						XX(PAGE_NEXT,     B("go-down-symbolic", "Next page")) \
 | 
				
			||||||
 | 
						XX(PAGE_LAST,     B("go-bottom-symbolic", "Last page")) \
 | 
				
			||||||
 | 
						XX(S2,            make_separator()) \
 | 
				
			||||||
 | 
						XX(SKIP_BACK,     B("media-skip-backward-symbolic", "Rewind playback")) \
 | 
				
			||||||
 | 
						XX(SEEK_BACK,     B("media-seek-backward-symbolic", "Previous frame")) \
 | 
				
			||||||
 | 
						/* TODO(p): The opposite is "media-playback-play-symbolic". */ \
 | 
				
			||||||
 | 
						/* XX(PAUSE,      B("media-playback-pause-symbolic", "Pause")) */ \
 | 
				
			||||||
 | 
						XX(SEEK_FORWARD,  B("media-seek-forward-symbolic", "Next frame")) \
 | 
				
			||||||
 | 
						XX(S3,            make_separator()) \
 | 
				
			||||||
 | 
						XX(PLUS,          B("zoom-in-symbolic", "Zoom in")) \
 | 
				
			||||||
 | 
						XX(SCALE,         gtk_label_new("100%")) \
 | 
				
			||||||
 | 
						XX(MINUS,         B("zoom-out-symbolic", "Zoom out")) \
 | 
				
			||||||
 | 
						XX(ONE,           B("zoom-original-symbolic", "Original size")) \
 | 
				
			||||||
 | 
						/* XX(FIT,        B("zoom-fit-best-symbolic", "Scale to fit")) */ \
 | 
				
			||||||
 | 
						XX(S4,            make_separator()) \
 | 
				
			||||||
 | 
						/* XX(PIN,        B("view-pin-symbolic", "Keep view configuration")) */ \
 | 
				
			||||||
 | 
						/* Or perhaps "blur-symbolic", also in the extended set. */ \
 | 
				
			||||||
 | 
						/* XX(SMOOTH,     B("blend-tool-symbolic", "Smooth scaling")) */ \
 | 
				
			||||||
 | 
						/* XX(COLOR,      B("preferences-color-symbolic", "Color management")) */ \
 | 
				
			||||||
 | 
						XX(SAVE,          B("document-save-as-symbolic", "Save as...")) \
 | 
				
			||||||
 | 
						XX(PRINT,         B("document-print-symbolic", "Print...")) \
 | 
				
			||||||
 | 
						/* XX(INFO,       B("info-symbolic", "Information")) */ \
 | 
				
			||||||
 | 
						XX(S5,            make_separator()) \
 | 
				
			||||||
 | 
						XX(LEFT,          B("object-rotate-left-symbolic", "Rotate left")) \
 | 
				
			||||||
 | 
						XX(MIRROR,        B("object-flip-horizontal-symbolic", "Mirror")) \
 | 
				
			||||||
 | 
						XX(RIGHT,         B("object-rotate-right-symbolic", "Rotate right")) \
 | 
				
			||||||
 | 
						XX(S6,            make_separator()) \
 | 
				
			||||||
 | 
						/* We are YouTube. */ \
 | 
				
			||||||
 | 
						XX(FULLSCREEN,    B("view-fullscreen-symbolic", "Fullscreen"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
					#define XX(id, constructor) TOOLBAR_ ## id,
 | 
				
			||||||
 | 
						TOOLBAR(XX)
 | 
				
			||||||
 | 
					#undef XX
 | 
				
			||||||
 | 
						TOOLBAR_COUNT
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct {
 | 
					struct {
 | 
				
			||||||
	gchar **supported_globs;
 | 
						gchar **supported_globs;
 | 
				
			||||||
	gboolean filtering;
 | 
						gboolean filtering;
 | 
				
			||||||
@@ -65,14 +113,17 @@ struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	GtkWidget *window;
 | 
						GtkWidget *window;
 | 
				
			||||||
	GtkWidget *stack;
 | 
						GtkWidget *stack;
 | 
				
			||||||
	GtkWidget *view;
 | 
					
 | 
				
			||||||
	GtkWidget *view_scroller;
 | 
					 | 
				
			||||||
	GtkWidget *browser;
 | 
					 | 
				
			||||||
	GtkWidget *browser_scroller;
 | 
					 | 
				
			||||||
	GtkWidget *browser_paned;
 | 
						GtkWidget *browser_paned;
 | 
				
			||||||
	GtkWidget *browser_sidebar;
 | 
						GtkWidget *browser_sidebar;
 | 
				
			||||||
	GtkWidget *plus;
 | 
						GtkWidget *plus;
 | 
				
			||||||
	GtkWidget *minus;
 | 
						GtkWidget *minus;
 | 
				
			||||||
 | 
						GtkWidget *browser_scroller;
 | 
				
			||||||
 | 
						GtkWidget *browser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GtkWidget *view_box;
 | 
				
			||||||
 | 
						GtkWidget *toolbar[TOOLBAR_COUNT];
 | 
				
			||||||
 | 
						GtkWidget *view;
 | 
				
			||||||
} g;
 | 
					} g;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static gboolean
 | 
					static gboolean
 | 
				
			||||||
@@ -119,7 +170,7 @@ static void
 | 
				
			|||||||
switch_to_view(const char *path)
 | 
					switch_to_view(const char *path)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	gtk_window_set_title(GTK_WINDOW(g.window), path);
 | 
						gtk_window_set_title(GTK_WINDOW(g.window), path);
 | 
				
			||||||
	gtk_stack_set_visible_child(GTK_STACK(g.stack), g.view_scroller);
 | 
						gtk_stack_set_visible_child(GTK_STACK(g.stack), g.view_box);
 | 
				
			||||||
	gtk_widget_grab_focus(g.view);
 | 
						gtk_widget_grab_focus(g.view);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -395,6 +446,20 @@ toggle_fullscreen(void)
 | 
				
			|||||||
		gtk_window_fullscreen(GTK_WINDOW(g.window));
 | 
							gtk_window_fullscreen(GTK_WINDOW(g.window));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_window_state_event(G_GNUC_UNUSED GtkWidget *widget,
 | 
				
			||||||
 | 
						GdkEventWindowState *event, G_GNUC_UNUSED gpointer user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!(event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const char *name = (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)
 | 
				
			||||||
 | 
							? "view-restore-symbolic"
 | 
				
			||||||
 | 
							: "view-fullscreen-symbolic";
 | 
				
			||||||
 | 
						gtk_button_set_image(GTK_BUTTON(g.toolbar[TOOLBAR_FULLSCREEN]),
 | 
				
			||||||
 | 
							gtk_image_new_from_icon_name(name, GTK_ICON_SIZE_BUTTON));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Cursor keys, e.g., simply cannot be bound through accelerators
 | 
					// Cursor keys, e.g., simply cannot be bound through accelerators
 | 
				
			||||||
// (and GtkWidget::keynav-failed would arguably be an awful solution).
 | 
					// (and GtkWidget::keynav-failed would arguably be an awful solution).
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
@@ -530,6 +595,107 @@ on_button_press_browser(G_GNUC_UNUSED GtkWidget *widget, GdkEventButton *event)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static GtkWidget *
 | 
				
			||||||
 | 
					make_toolbar_button(const gchar *symbolic, const gchar *tooltip)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GtkWidget *button =
 | 
				
			||||||
 | 
							gtk_button_new_from_icon_name(symbolic, GTK_ICON_SIZE_BUTTON);
 | 
				
			||||||
 | 
						gtk_widget_set_tooltip_text(button, tooltip);
 | 
				
			||||||
 | 
					//	gtk_widget_set_sensitive(button, FALSE);
 | 
				
			||||||
 | 
						gtk_widget_set_focus_on_click(button, FALSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gtk_style_context_add_class(
 | 
				
			||||||
 | 
							gtk_widget_get_style_context(button), GTK_STYLE_CLASS_FLAT);
 | 
				
			||||||
 | 
						return button;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static GtkWidget *
 | 
				
			||||||
 | 
					make_separator(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// TODO(p): See if it's possible to give the separator room to shrink
 | 
				
			||||||
 | 
						// by some minor amount of pixels, margin-wise.
 | 
				
			||||||
 | 
						GtkWidget *separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
 | 
				
			||||||
 | 
						gtk_widget_set_margin_start(separator, 10);
 | 
				
			||||||
 | 
						gtk_widget_set_margin_end(separator, 10);
 | 
				
			||||||
 | 
						return separator;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_notify_scale(
 | 
				
			||||||
 | 
						GObject *object, GParamSpec *param_spec, G_GNUC_UNUSED gpointer user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						double scale = 0;
 | 
				
			||||||
 | 
						g_object_get(object, g_param_spec_get_name(param_spec), &scale, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gchar *scale_str = g_strdup_printf("%.0f%%", round(scale * 100));
 | 
				
			||||||
 | 
						gtk_label_set_text(GTK_LABEL(g.toolbar[TOOLBAR_SCALE]), scale_str);
 | 
				
			||||||
 | 
						g_free(scale_str);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					toolbar_connect(int index, GCallback callback)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						g_signal_connect_swapped(g.toolbar[index], "clicked", callback, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_command(intptr_t command)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						fastiv_view_command(FASTIV_VIEW(g.view), command);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					toolbar_command(int index, FastivViewCommand command)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						g_signal_connect_swapped(g.toolbar[index], "clicked",
 | 
				
			||||||
 | 
							G_CALLBACK(on_command), (void *) (intptr_t) command);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO(p): The toolbar should not be visible in fullscreen,
 | 
				
			||||||
 | 
					// or show up only when the cursor reaches the bottom of the screen.
 | 
				
			||||||
 | 
					// Presumably, GtkOverlay could be used for this. Proximity-based?
 | 
				
			||||||
 | 
					// Might want to make the toolbar normally translucent.
 | 
				
			||||||
 | 
					// TODO(p): The text and icons should be faded, unless the mouse cursor
 | 
				
			||||||
 | 
					// is on the toolbar.
 | 
				
			||||||
 | 
					static GtkWidget *
 | 
				
			||||||
 | 
					make_view_toolbar(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#define XX(id, constructor) g.toolbar[TOOLBAR_ ## id] = constructor;
 | 
				
			||||||
 | 
						TOOLBAR(XX)
 | 
				
			||||||
 | 
					#undef XX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO(p): The scale should be at least as wide as "999%".
 | 
				
			||||||
 | 
						gtk_widget_set_margin_start(g.toolbar[TOOLBAR_SCALE], 5);
 | 
				
			||||||
 | 
						gtk_widget_set_margin_end(g.toolbar[TOOLBAR_SCALE], 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// GtkStatusBar solves a problem we do not have here.
 | 
				
			||||||
 | 
						GtkWidget *view_toolbar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
 | 
				
			||||||
 | 
						GtkBox *box = GTK_BOX(view_toolbar);
 | 
				
			||||||
 | 
						for (int i = 0; i < TOOLBAR_COUNT; i++)
 | 
				
			||||||
 | 
							gtk_box_pack_start(box, g.toolbar[i], FALSE, FALSE, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						toolbar_connect(TOOLBAR_BROWSE,        G_CALLBACK(switch_to_browser));
 | 
				
			||||||
 | 
						toolbar_connect(TOOLBAR_FILE_PREVIOUS, G_CALLBACK(on_previous));
 | 
				
			||||||
 | 
						toolbar_connect(TOOLBAR_FILE_NEXT,     G_CALLBACK(on_next));
 | 
				
			||||||
 | 
						toolbar_command(TOOLBAR_PAGE_FIRST,    FASTIV_VIEW_COMMAND_PAGE_FIRST);
 | 
				
			||||||
 | 
						toolbar_command(TOOLBAR_PAGE_PREVIOUS, FASTIV_VIEW_COMMAND_PAGE_PREVIOUS);
 | 
				
			||||||
 | 
						toolbar_command(TOOLBAR_PAGE_NEXT,     FASTIV_VIEW_COMMAND_PAGE_NEXT);
 | 
				
			||||||
 | 
						toolbar_command(TOOLBAR_PAGE_LAST,     FASTIV_VIEW_COMMAND_PAGE_LAST);
 | 
				
			||||||
 | 
						toolbar_command(TOOLBAR_SKIP_BACK,     FASTIV_VIEW_COMMAND_FRAME_FIRST);
 | 
				
			||||||
 | 
						toolbar_command(TOOLBAR_SEEK_BACK,     FASTIV_VIEW_COMMAND_FRAME_PREVIOUS);
 | 
				
			||||||
 | 
						toolbar_command(TOOLBAR_SEEK_FORWARD,  FASTIV_VIEW_COMMAND_FRAME_NEXT);
 | 
				
			||||||
 | 
						toolbar_command(TOOLBAR_PLUS,          FASTIV_VIEW_COMMAND_ZOOM_IN);
 | 
				
			||||||
 | 
						toolbar_command(TOOLBAR_MINUS,         FASTIV_VIEW_COMMAND_ZOOM_OUT);
 | 
				
			||||||
 | 
						toolbar_command(TOOLBAR_ONE,           FASTIV_VIEW_COMMAND_ZOOM_1);
 | 
				
			||||||
 | 
						toolbar_command(TOOLBAR_PRINT,         FASTIV_VIEW_COMMAND_PRINT);
 | 
				
			||||||
 | 
						toolbar_command(TOOLBAR_SAVE,          FASTIV_VIEW_COMMAND_SAVE_PAGE);
 | 
				
			||||||
 | 
						toolbar_command(TOOLBAR_LEFT,          FASTIV_VIEW_COMMAND_ROTATE_LEFT);
 | 
				
			||||||
 | 
						toolbar_command(TOOLBAR_MIRROR,        FASTIV_VIEW_COMMAND_MIRROR);
 | 
				
			||||||
 | 
						toolbar_command(TOOLBAR_RIGHT,         FASTIV_VIEW_COMMAND_ROTATE_RIGHT);
 | 
				
			||||||
 | 
						toolbar_connect(TOOLBAR_FULLSCREEN,    G_CALLBACK(toggle_fullscreen));
 | 
				
			||||||
 | 
						return view_toolbar;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
main(int argc, char *argv[])
 | 
					main(int argc, char *argv[])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -578,10 +744,18 @@ main(int argc, char *argv[])
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// This is incredibly broken https://stackoverflow.com/a/51054396/76313
 | 
						// This is incredibly broken https://stackoverflow.com/a/51054396/76313
 | 
				
			||||||
	// thus resolving the problem using overlaps.
 | 
						// thus resolving the problem using overlaps.
 | 
				
			||||||
 | 
						// XXX: button.flat is too generic, it's only for the view toolbar.
 | 
				
			||||||
 | 
						// XXX: Similarly, box > separator.horizontal is a temporary hack.
 | 
				
			||||||
 | 
						// 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 fastiv-tile #3c3c3c; \
 | 
				
			||||||
		fastiv-view, fastiv-browser { background: @content_view_bg; } \
 | 
							fastiv-view, fastiv-browser { background: @content_view_bg; } \
 | 
				
			||||||
		placessidebar.fastiv .toolbar { padding: 2px 6px; } \
 | 
							placessidebar.fastiv .toolbar { padding: 2px 6px; } \
 | 
				
			||||||
		placessidebar.fastiv box > separator { margin: 4px 0; } \
 | 
							placessidebar.fastiv box > separator { margin: 4px 0; } \
 | 
				
			||||||
 | 
							button.flat { padding-left: 0; padding-right: 0 } \
 | 
				
			||||||
 | 
							box > separator.horizontal { \
 | 
				
			||||||
 | 
								background: mix(@insensitive_fg_color, \
 | 
				
			||||||
 | 
									@insensitive_bg_color, 0.4); margin: 6px 0; \
 | 
				
			||||||
 | 
							} \
 | 
				
			||||||
		fastiv-browser { padding: 5px; } \
 | 
							fastiv-browser { padding: 5px; } \
 | 
				
			||||||
		fastiv-browser.item { \
 | 
							fastiv-browser.item { \
 | 
				
			||||||
			border: 1px solid rgba(255, 255, 255, 0.375); \
 | 
								border: 1px solid rgba(255, 255, 255, 0.375); \
 | 
				
			||||||
@@ -606,23 +780,31 @@ main(int argc, char *argv[])
 | 
				
			|||||||
		GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 | 
							GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 | 
				
			||||||
	g_object_unref(provider);
 | 
						g_object_unref(provider);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	g.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(FASTIV_TYPE_VIEW, NULL);
 | 
				
			||||||
	gtk_widget_set_vexpand(g.view, TRUE);
 | 
					 | 
				
			||||||
	gtk_widget_set_hexpand(g.view, TRUE);
 | 
					 | 
				
			||||||
	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",
 | 
				
			||||||
		G_CALLBACK(on_button_press_view), NULL);
 | 
							G_CALLBACK(on_button_press_view), NULL);
 | 
				
			||||||
	gtk_container_add(GTK_CONTAINER(g.view_scroller), g.view);
 | 
						g_signal_connect(g.view, "notify::scale",
 | 
				
			||||||
	gtk_widget_show_all(g.view_scroller);
 | 
							G_CALLBACK(on_notify_scale), NULL);
 | 
				
			||||||
 | 
						gtk_container_add(GTK_CONTAINER(view_scroller), g.view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Maybe our custom widgets should derive colours from the theme instead.
 | 
						// Maybe our custom widgets should derive colours from the theme instead.
 | 
				
			||||||
	gtk_scrolled_window_set_overlay_scrolling(
 | 
					 | 
				
			||||||
		GTK_SCROLLED_WINDOW(g.view_scroller), FALSE);
 | 
					 | 
				
			||||||
	g_object_set(gtk_settings_get_default(),
 | 
						g_object_set(gtk_settings_get_default(),
 | 
				
			||||||
		"gtk-application-prefer-dark-theme", TRUE, NULL);
 | 
							"gtk-application-prefer-dark-theme", TRUE, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GtkWidget *view_toolbar = make_view_toolbar();
 | 
				
			||||||
 | 
						gtk_widget_set_halign(view_toolbar, GTK_ALIGN_CENTER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Need to put the toolbar at the top, because of the horizontal scrollbar.
 | 
				
			||||||
 | 
						g.view_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
 | 
				
			||||||
 | 
						gtk_box_pack_start(GTK_BOX(g.view_box), view_toolbar, FALSE, FALSE, 0);
 | 
				
			||||||
 | 
						gtk_box_pack_start(GTK_BOX(g.view_box),
 | 
				
			||||||
 | 
							gtk_separator_new(GTK_ORIENTATION_VERTICAL), FALSE, FALSE, 0);
 | 
				
			||||||
 | 
						gtk_box_pack_start(GTK_BOX(g.view_box), view_scroller, TRUE, TRUE, 0);
 | 
				
			||||||
 | 
						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(FASTIV_TYPE_BROWSER, NULL);
 | 
				
			||||||
	gtk_widget_set_vexpand(g.browser, TRUE);
 | 
						gtk_widget_set_vexpand(g.browser, TRUE);
 | 
				
			||||||
@@ -696,7 +878,7 @@ main(int argc, char *argv[])
 | 
				
			|||||||
	g.stack = gtk_stack_new();
 | 
						g.stack = gtk_stack_new();
 | 
				
			||||||
	gtk_stack_set_transition_type(
 | 
						gtk_stack_set_transition_type(
 | 
				
			||||||
		GTK_STACK(g.stack), GTK_STACK_TRANSITION_TYPE_NONE);
 | 
							GTK_STACK(g.stack), GTK_STACK_TRANSITION_TYPE_NONE);
 | 
				
			||||||
	gtk_container_add(GTK_CONTAINER(g.stack), g.view_scroller);
 | 
						gtk_container_add(GTK_CONTAINER(g.stack), g.view_box);
 | 
				
			||||||
	gtk_container_add(GTK_CONTAINER(g.stack), g.browser_paned);
 | 
						gtk_container_add(GTK_CONTAINER(g.stack), g.browser_paned);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	g.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 | 
						g.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 | 
				
			||||||
@@ -704,6 +886,8 @@ main(int argc, char *argv[])
 | 
				
			|||||||
		G_CALLBACK(gtk_main_quit), NULL);
 | 
							G_CALLBACK(gtk_main_quit), NULL);
 | 
				
			||||||
	g_signal_connect(g.window, "key-press-event",
 | 
						g_signal_connect(g.window, "key-press-event",
 | 
				
			||||||
		G_CALLBACK(on_key_press), NULL);
 | 
							G_CALLBACK(on_key_press), NULL);
 | 
				
			||||||
 | 
						g_signal_connect(g.window, "window-state-event",
 | 
				
			||||||
 | 
							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 = fastiv_io_all_supported_media_types();
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										154
									
								
								resources/blend-tool-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								resources/blend-tool-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,154 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 | 
				
			||||||
 | 
					    <filter id="a" height="100%" width="100%" x="0%" y="0%">
 | 
				
			||||||
 | 
					        <feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
 | 
				
			||||||
 | 
					    </filter>
 | 
				
			||||||
 | 
					    <mask id="b">
 | 
				
			||||||
 | 
					        <g filter="url(#a)">
 | 
				
			||||||
 | 
					            <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.3"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					    </mask>
 | 
				
			||||||
 | 
					    <clipPath id="c">
 | 
				
			||||||
 | 
					        <path d="m 0 0 h 1024 v 800 h -1024 z"/>
 | 
				
			||||||
 | 
					    </clipPath>
 | 
				
			||||||
 | 
					    <mask id="d">
 | 
				
			||||||
 | 
					        <g filter="url(#a)">
 | 
				
			||||||
 | 
					            <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					    </mask>
 | 
				
			||||||
 | 
					    <clipPath id="e">
 | 
				
			||||||
 | 
					        <path d="m 0 0 h 1024 v 800 h -1024 z"/>
 | 
				
			||||||
 | 
					    </clipPath>
 | 
				
			||||||
 | 
					    <mask id="f">
 | 
				
			||||||
 | 
					        <g filter="url(#a)">
 | 
				
			||||||
 | 
					            <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					    </mask>
 | 
				
			||||||
 | 
					    <clipPath id="g">
 | 
				
			||||||
 | 
					        <path d="m 0 0 h 1024 v 800 h -1024 z"/>
 | 
				
			||||||
 | 
					    </clipPath>
 | 
				
			||||||
 | 
					    <mask id="h">
 | 
				
			||||||
 | 
					        <g filter="url(#a)">
 | 
				
			||||||
 | 
					            <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					    </mask>
 | 
				
			||||||
 | 
					    <clipPath id="i">
 | 
				
			||||||
 | 
					        <path d="m 0 0 h 1024 v 800 h -1024 z"/>
 | 
				
			||||||
 | 
					    </clipPath>
 | 
				
			||||||
 | 
					    <mask id="j">
 | 
				
			||||||
 | 
					        <g filter="url(#a)">
 | 
				
			||||||
 | 
					            <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					    </mask>
 | 
				
			||||||
 | 
					    <clipPath id="k">
 | 
				
			||||||
 | 
					        <path d="m 0 0 h 1024 v 800 h -1024 z"/>
 | 
				
			||||||
 | 
					    </clipPath>
 | 
				
			||||||
 | 
					    <mask id="l">
 | 
				
			||||||
 | 
					        <g filter="url(#a)">
 | 
				
			||||||
 | 
					            <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					    </mask>
 | 
				
			||||||
 | 
					    <clipPath id="m">
 | 
				
			||||||
 | 
					        <path d="m 0 0 h 1024 v 800 h -1024 z"/>
 | 
				
			||||||
 | 
					    </clipPath>
 | 
				
			||||||
 | 
					    <mask id="n">
 | 
				
			||||||
 | 
					        <g filter="url(#a)">
 | 
				
			||||||
 | 
					            <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					    </mask>
 | 
				
			||||||
 | 
					    <clipPath id="o">
 | 
				
			||||||
 | 
					        <path d="m 0 0 h 1024 v 800 h -1024 z"/>
 | 
				
			||||||
 | 
					    </clipPath>
 | 
				
			||||||
 | 
					    <mask id="p">
 | 
				
			||||||
 | 
					        <g filter="url(#a)">
 | 
				
			||||||
 | 
					            <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.3"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					    </mask>
 | 
				
			||||||
 | 
					    <clipPath id="q">
 | 
				
			||||||
 | 
					        <path d="m 0 0 h 1024 v 800 h -1024 z"/>
 | 
				
			||||||
 | 
					    </clipPath>
 | 
				
			||||||
 | 
					    <mask id="r">
 | 
				
			||||||
 | 
					        <g filter="url(#a)">
 | 
				
			||||||
 | 
					            <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.5"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					    </mask>
 | 
				
			||||||
 | 
					    <clipPath id="s">
 | 
				
			||||||
 | 
					        <path d="m 0 0 h 1024 v 800 h -1024 z"/>
 | 
				
			||||||
 | 
					    </clipPath>
 | 
				
			||||||
 | 
					    <mask id="t">
 | 
				
			||||||
 | 
					        <g filter="url(#a)">
 | 
				
			||||||
 | 
					            <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.4"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					    </mask>
 | 
				
			||||||
 | 
					    <clipPath id="u">
 | 
				
			||||||
 | 
					        <path d="m 0 0 h 1024 v 800 h -1024 z"/>
 | 
				
			||||||
 | 
					    </clipPath>
 | 
				
			||||||
 | 
					    <mask id="v">
 | 
				
			||||||
 | 
					        <g filter="url(#a)">
 | 
				
			||||||
 | 
					            <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.4"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					    </mask>
 | 
				
			||||||
 | 
					    <clipPath id="w">
 | 
				
			||||||
 | 
					        <path d="m 0 0 h 1024 v 800 h -1024 z"/>
 | 
				
			||||||
 | 
					    </clipPath>
 | 
				
			||||||
 | 
					    <mask id="x">
 | 
				
			||||||
 | 
					        <g filter="url(#a)">
 | 
				
			||||||
 | 
					            <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.5"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					    </mask>
 | 
				
			||||||
 | 
					    <clipPath id="y">
 | 
				
			||||||
 | 
					        <path d="m 0 0 h 1024 v 800 h -1024 z"/>
 | 
				
			||||||
 | 
					    </clipPath>
 | 
				
			||||||
 | 
					    <mask id="z">
 | 
				
			||||||
 | 
					        <g filter="url(#a)">
 | 
				
			||||||
 | 
					            <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.5"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					    </mask>
 | 
				
			||||||
 | 
					    <clipPath id="A">
 | 
				
			||||||
 | 
					        <path d="m 0 0 h 1024 v 800 h -1024 z"/>
 | 
				
			||||||
 | 
					    </clipPath>
 | 
				
			||||||
 | 
					    <g clip-path="url(#c)" mask="url(#b)" transform="matrix(1 0 0 1 -96 -620)">
 | 
				
			||||||
 | 
					        <path d="m 562.460938 212.058594 h 10.449218 c -1.183594 0.492187 -1.296875 2.460937 0 3 h -10.449218 z m 0 0" fill="#2e3436"/>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					    <g clip-path="url(#e)" mask="url(#d)" transform="matrix(1 0 0 1 -96 -620)">
 | 
				
			||||||
 | 
					        <path d="m 16 632 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					    <g clip-path="url(#g)" mask="url(#f)" transform="matrix(1 0 0 1 -96 -620)">
 | 
				
			||||||
 | 
					        <path d="m 17 631 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					    <g clip-path="url(#i)" mask="url(#h)" transform="matrix(1 0 0 1 -96 -620)">
 | 
				
			||||||
 | 
					        <path d="m 18 634 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					    <g clip-path="url(#k)" mask="url(#j)" transform="matrix(1 0 0 1 -96 -620)">
 | 
				
			||||||
 | 
					        <path d="m 16 634 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					    <g clip-path="url(#m)" mask="url(#l)" transform="matrix(1 0 0 1 -96 -620)">
 | 
				
			||||||
 | 
					        <path d="m 17 635 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					    <g clip-path="url(#o)" mask="url(#n)" transform="matrix(1 0 0 1 -96 -620)">
 | 
				
			||||||
 | 
					        <path d="m 19 635 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					    <g fill="#2e3436">
 | 
				
			||||||
 | 
					        <path d="m 1 1 v 14 h 14 v -14 z m 1 1 h 12 v 12 h -12 z m 0 0"/>
 | 
				
			||||||
 | 
					        <path d="m 6 11 h 1 v 1 h -1 z m 1 1 h 1 v 1 h -1 z m -1 -3 h 1 v 1 h -1 z m 1 1 h 1 v 1 h -1 z m -1 -3 h 1 v 1 h -1 z m 1 1 h 1 v 1 h -1 z m -1 -3 h 1 v 1 h -1 z m 1 1 h 1 v 1 h -1 z m -1 -3 h 1 v 1 h -1 z m 1 1 h 1 v 1 h -1 z m -4 -1 h 3 v 10 h -3 z m 0 0"/>
 | 
				
			||||||
 | 
					        <path d="m 8 3 h 1 v 10 h -1 z m 2 9 h 1 v 1 h -1 z m 0 -2 h 1 v 1 h -1 z m 0 -2 h 1 v 1 h -1 z m 0 -2 h 1 v 1 h -1 z m 0 -2 h 1 v 1 h -1 z m -1 7 h 1 v 1 h -1 z m 0 -2 h 1 v 1 h -1 z m 0 -2 h 1 v 1 h -1 z m 0 -2 h 1 v 1 h -1 z m 0 -2 h 1 v 1 h -1 z m 0 0" fill-opacity="0.524444"/>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					    <g clip-path="url(#q)" mask="url(#p)" transform="matrix(1 0 0 1 -96 -620)">
 | 
				
			||||||
 | 
					        <path d="m 136 660 v 7 h 7 v -7 z m 0 0" fill="#2e3436"/>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					    <g clip-path="url(#s)" mask="url(#r)" transform="matrix(1 0 0 1 -96 -620)">
 | 
				
			||||||
 | 
					        <path d="m 199 642 h 3 v 12 h -3 z m 0 0" fill="#2e3436"/>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					    <g clip-path="url(#u)" mask="url(#t)" transform="matrix(1 0 0 1 -96 -620)">
 | 
				
			||||||
 | 
					        <path d="m 209.5 144.160156 c 0.277344 0 0.5 0.222656 0.5 0.5 v 1 c 0 0.277344 -0.222656 0.5 -0.5 0.5 s -0.5 -0.222656 -0.5 -0.5 v -1 c 0 -0.277344 0.222656 -0.5 0.5 -0.5 z m 0 0" fill="#2e3436"/>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					    <g clip-path="url(#w)" mask="url(#v)" transform="matrix(1 0 0 1 -96 -620)">
 | 
				
			||||||
 | 
					        <path d="m 206.5 144.160156 c 0.277344 0 0.5 0.222656 0.5 0.5 v 1 c 0 0.277344 -0.222656 0.5 -0.5 0.5 s -0.5 -0.222656 -0.5 -0.5 v -1 c 0 -0.277344 0.222656 -0.5 0.5 -0.5 z m 0 0" fill="#2e3436"/>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					    <g clip-path="url(#y)" mask="url(#x)" transform="matrix(1 0 0 1 -96 -620)">
 | 
				
			||||||
 | 
					        <path d="m 229.5 143.160156 c -0.546875 0 -1 0.457032 -1 1 c 0 0.546875 0.453125 1 1 1 s 1 -0.453125 1 -1 c 0 -0.542968 -0.453125 -1 -1 -1 z m 0 0" fill="#2e3436"/>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					    <g clip-path="url(#A)" mask="url(#z)" transform="matrix(1 0 0 1 -96 -620)">
 | 
				
			||||||
 | 
					        <path d="m 226.453125 143.160156 c -0.519531 0 -0.953125 0.433594 -0.953125 0.953125 v 0.09375 c 0 0.519531 0.433594 0.953125 0.953125 0.953125 h 0.09375 c 0.519531 0 0.953125 -0.433594 0.953125 -0.953125 v -0.09375 c 0 -0.519531 -0.433594 -0.953125 -0.953125 -0.953125 z m 0 0" fill="#2e3436"/>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					</svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 6.6 KiB  | 
@@ -3,5 +3,6 @@
 | 
				
			|||||||
	<gresource prefix="/org/gnome/design/IconLibrary/">
 | 
						<gresource prefix="/org/gnome/design/IconLibrary/">
 | 
				
			||||||
		<file preprocess="xml-stripblanks">circle-filled-symbolic.svg</file>
 | 
							<file preprocess="xml-stripblanks">circle-filled-symbolic.svg</file>
 | 
				
			||||||
		<file preprocess="xml-stripblanks">funnel-symbolic.svg</file>
 | 
							<file preprocess="xml-stripblanks">funnel-symbolic.svg</file>
 | 
				
			||||||
 | 
							<file preprocess="xml-stripblanks">blend-tool-symbolic.svg</file>
 | 
				
			||||||
	</gresource>
 | 
						</gresource>
 | 
				
			||||||
</gresources>
 | 
					</gresources>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user