diff options
-rw-r--r-- | fastiv.c | 36 | ||||
-rw-r--r-- | fiv-view.c | 15 | ||||
-rw-r--r-- | fiv-view.h | 1 |
3 files changed, 45 insertions, 7 deletions
@@ -70,12 +70,11 @@ exit_fatal(const gchar *format, ...) 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(PLAY_PAUSE, B("media-playback-start-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(SCALE, gtk_label_new("")) \ XX(MINUS, B("zoom-out-symbolic", "Zoom out")) \ XX(ONE, B("zoom-original-symbolic", "Original size")) \ XX(FIT, T("zoom-fit-best-symbolic", "Scale to fit")) \ @@ -457,8 +456,10 @@ on_window_state_event(G_GNUC_UNUSED GtkWidget *widget, 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)); + + GtkButton *button = GTK_BUTTON(g.toolbar[TOOLBAR_FULLSCREEN]); + GtkImage *image = GTK_IMAGE(gtk_button_get_image(button)); + gtk_image_set_from_icon_name(image, name, GTK_ICON_SIZE_BUTTON); } // Cursor keys, e.g., simply cannot be bound through accelerators @@ -650,6 +651,21 @@ on_notify_view_scale( } static void +on_notify_view_playing( + GObject *object, GParamSpec *param_spec, G_GNUC_UNUSED gpointer user_data) +{ + gboolean b = FALSE; + g_object_get(object, g_param_spec_get_name(param_spec), &b, NULL); + const char *name = b + ? "media-playback-pause-symbolic" + : "media-playback-start-symbolic"; + + GtkButton *button = GTK_BUTTON(g.toolbar[TOOLBAR_PLAY_PAUSE]); + GtkImage *image = GTK_IMAGE(gtk_button_get_image(button)); + gtk_image_set_from_icon_name(image, name, GTK_ICON_SIZE_BUTTON); +} + +static void on_notify_view_boolean( GObject *object, GParamSpec *param_spec, gpointer user_data) { @@ -728,6 +744,7 @@ make_view_toolbar(void) toolbar_command(TOOLBAR_PAGE_LAST, FIV_VIEW_COMMAND_PAGE_LAST); toolbar_command(TOOLBAR_SKIP_BACK, FIV_VIEW_COMMAND_FRAME_FIRST); toolbar_command(TOOLBAR_SEEK_BACK, FIV_VIEW_COMMAND_FRAME_PREVIOUS); + toolbar_command(TOOLBAR_PLAY_PAUSE, FIV_VIEW_COMMAND_TOGGLE_PLAYBACK); toolbar_command(TOOLBAR_SEEK_FORWARD, FIV_VIEW_COMMAND_FRAME_NEXT); toolbar_command(TOOLBAR_PLUS, FIV_VIEW_COMMAND_ZOOM_IN); toolbar_command(TOOLBAR_MINUS, FIV_VIEW_COMMAND_ZOOM_OUT); @@ -741,10 +758,17 @@ make_view_toolbar(void) toolbar_command(TOOLBAR_RIGHT, FIV_VIEW_COMMAND_ROTATE_RIGHT); toolbar_connect(TOOLBAR_FULLSCREEN, G_CALLBACK(toggle_fullscreen)); + g_signal_connect(g.view, "notify::scale", + G_CALLBACK(on_notify_view_scale), NULL); + g_signal_connect(g.view, "notify::playing", + G_CALLBACK(on_notify_view_playing), NULL); g_signal_connect(g.view, "notify::scale-to-fit", G_CALLBACK(on_notify_view_boolean), g.toolbar[TOOLBAR_FIT]); g_signal_connect(g.view, "notify::filter", G_CALLBACK(on_notify_view_boolean), g.toolbar[TOOLBAR_SMOOTH]); + + g_object_notify(G_OBJECT(g.view), "scale"); + g_object_notify(G_OBJECT(g.view), "playing"); g_object_notify(G_OBJECT(g.view), "scale-to-fit"); g_object_notify(G_OBJECT(g.view), "filter"); return view_toolbar; @@ -840,8 +864,6 @@ main(int argc, char *argv[]) G_CALLBACK(on_key_press_view), NULL); g_signal_connect(g.view, "button-press-event", G_CALLBACK(on_button_press_view), NULL); - g_signal_connect(g.view, "notify::scale", - G_CALLBACK(on_notify_view_scale), NULL); gtk_container_add(GTK_CONTAINER(view_scroller), g.view); // Maybe our custom widgets should derive colours from the theme instead. @@ -88,6 +88,7 @@ enum { PROP_SCALE = 1, PROP_SCALE_TO_FIT, PROP_FILTER, + PROP_PLAYING, N_PROPERTIES }; @@ -117,6 +118,9 @@ fiv_view_get_property( case PROP_FILTER: g_value_set_boolean(value, self->filter); break; + case PROP_PLAYING: + g_value_set_boolean(value, !!self->frame_update_connection); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); } @@ -472,6 +476,7 @@ stop_animating(FivView *self) self->frame_time = 0; self->frame_update_connection = 0; self->remaining_loops = 0; + g_object_notify_by_pspec(G_OBJECT(self), view_properties[PROP_PLAYING]); } static gboolean @@ -546,6 +551,7 @@ start_animating(FivView *self) (uintptr_t) cairo_surface_get_user_data(self->page, &fiv_io_key_loops); gdk_frame_clock_begin_updating(clock); + g_object_notify_by_pspec(G_OBJECT(self), view_properties[PROP_PLAYING]); } static void @@ -790,6 +796,8 @@ fiv_view_key_press_event(GtkWidget *widget, GdkEventKey *event) return command(self, FIV_VIEW_COMMAND_FRAME_PREVIOUS); case GDK_KEY_braceright: return command(self, FIV_VIEW_COMMAND_FRAME_NEXT); + case GDK_KEY_space: + return command(self, FIV_VIEW_COMMAND_TOGGLE_PLAYBACK); } return FALSE; } @@ -811,6 +819,9 @@ fiv_view_class_init(FivViewClass *klass) view_properties[PROP_FILTER] = g_param_spec_boolean( "filter", "Use filtering", "Scale images smoothly", TRUE, G_PARAM_READWRITE); + view_properties[PROP_PLAYING] = g_param_spec_boolean( + "playing", "Playing animation", "An animation is running", + TRUE, G_PARAM_READWRITE); g_object_class_install_properties( object_class, N_PROPERTIES, view_properties); @@ -918,6 +929,10 @@ fiv_view_command(FivView *self, FivViewCommand command) frame_step(self, -1); break; case FIV_VIEW_COMMAND_FRAME_NEXT: frame_step(self, +1); + break; case FIV_VIEW_COMMAND_TOGGLE_PLAYBACK: + self->frame_update_connection + ? stop_animating(self) + : start_animating(self); break; case FIV_VIEW_COMMAND_TOGGLE_FILTER: self->filter = !self->filter; @@ -39,6 +39,7 @@ typedef enum _FivViewCommand { FIV_VIEW_COMMAND_FRAME_PREVIOUS, FIV_VIEW_COMMAND_FRAME_NEXT, // Going to the end frame makes no sense, wrap around if needed. + FIV_VIEW_COMMAND_TOGGLE_PLAYBACK, FIV_VIEW_COMMAND_TOGGLE_FILTER, FIV_VIEW_COMMAND_PRINT, |