From 373e7726405a9d778b96dab577c1e2089e31a5f5 Mon Sep 17 00:00:00 2001 From: Diederik ter Rahe Date: Thu, 23 Jan 2025 19:43:49 -0500 Subject: [PATCH 1/3] show snapshots side-by-side --- src/control/control.c | 3 +-- src/control/control.h | 2 +- src/gui/gtk.c | 63 +++++++++++++++++++++++++++---------------- src/gui/gtk.h | 2 ++ src/libs/snapshots.c | 36 ++++++++++++++++++++----- 5 files changed, 74 insertions(+), 32 deletions(-) diff --git a/src/control/control.c b/src/control/control.c index a6e88b4f9901..237d12a86814 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -431,7 +431,7 @@ void dt_control_draw_busy_msg(cairo_t *cr, int width, int height) g_object_unref(layout); } -void *dt_control_expose(void *voidptr) +void *dt_control_expose(GtkWidget *widget) { int pointerx, pointery; if(!darktable.gui->surface) return NULL; @@ -439,7 +439,6 @@ void *dt_control_expose(void *voidptr) dt_control_t *dc = darktable.control; const int width = dt_cairo_image_surface_get_width(darktable.gui->surface); const int height = dt_cairo_image_surface_get_height(darktable.gui->surface); - GtkWidget *widget = dt_ui_center(darktable.gui->ui); gdk_window_get_device_position(gtk_widget_get_window(widget), gdk_seat_get_pointer(gdk_display_get_default_seat(gtk_widget_get_display(widget))), &pointerx, &pointery, NULL); diff --git a/src/control/control.h b/src/control/control.h index 07e76c6d607a..420ee9cbddb6 100644 --- a/src/control/control.h +++ b/src/control/control.h @@ -46,7 +46,7 @@ struct dt_lib_backgroundjob_element_t; typedef GdkCursorType dt_cursor_t; // called from gui -void *dt_control_expose(void *voidptr); +void *dt_control_expose(GtkWidget *widget); gboolean dt_control_draw_endmarker(GtkWidget *widget, cairo_t *crf, gpointer user_data); void dt_control_button_pressed(double x, double y, double pressure, int which, int type, uint32_t state); void dt_control_button_released(double x, double y, int which, uint32_t state); diff --git a/src/gui/gtk.c b/src/gui/gtk.c index c14b0221c203..c524dce5d08e 100644 --- a/src/gui/gtk.c +++ b/src/gui/gtk.c @@ -102,6 +102,7 @@ typedef struct dt_ui_t /* center widget */ GtkWidget *center; GtkWidget *center_base; + GtkWidget *snapshot; /* main widget */ GtkWidget *main_window; @@ -711,7 +712,11 @@ static gboolean _draw(GtkWidget *da, cairo_t *cr, gpointer user_data) { - dt_control_expose(NULL); + GtkWidget *ss = dt_ui_snapshot(darktable.gui->ui); + darktable.gui->drawing_snapshot = da == ss; + if(!darktable.gui->drawing_snapshot) gtk_widget_queue_draw(ss); + + dt_control_expose(da); if(darktable.gui->surface) { cairo_set_source_surface(cr, darktable.gui->surface, 0, 0); @@ -1388,23 +1393,30 @@ int dt_gui_gtk_init(dt_gui_gtk_t *gui) _init_widgets(gui); widget = dt_ui_center(darktable.gui->ui); - g_signal_connect(G_OBJECT(widget), "configure-event", - G_CALLBACK(_configure), gui); - g_signal_connect(G_OBJECT(widget), "draw", - G_CALLBACK(_draw), NULL); - g_signal_connect(G_OBJECT(widget), "motion-notify-event", - G_CALLBACK(_mouse_moved), gui); - g_signal_connect(G_OBJECT(widget), "leave-notify-event", - G_CALLBACK(_center_leave), NULL); - g_signal_connect(G_OBJECT(widget), "enter-notify-event", - G_CALLBACK(_center_enter), NULL); - g_signal_connect(G_OBJECT(widget), "button-press-event", - G_CALLBACK(_button_pressed), NULL); - g_signal_connect(G_OBJECT(widget), "button-release-event", - G_CALLBACK(_button_released), NULL); - g_signal_connect(G_OBJECT(widget), "scroll-event", - G_CALLBACK(_scrolled), NULL); + G_CALLBACK(_configure), gui); + for(int i = 2; i; i--, widget = dt_ui_snapshot(darktable.gui->ui)) + { + gtk_widget_add_events(widget, + GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK | darktable.gui->scroll_mask); + + g_signal_connect(G_OBJECT(widget), "draw", + G_CALLBACK(_draw), NULL); + g_signal_connect(G_OBJECT(widget), "motion-notify-event", + G_CALLBACK(_mouse_moved), gui); + g_signal_connect(G_OBJECT(widget), "leave-notify-event", + G_CALLBACK(_center_leave), NULL); + g_signal_connect(G_OBJECT(widget), "enter-notify-event", + G_CALLBACK(_center_enter), NULL); + g_signal_connect(G_OBJECT(widget), "button-press-event", + G_CALLBACK(_button_pressed), NULL); + g_signal_connect(G_OBJECT(widget), "button-release-event", + G_CALLBACK(_button_released), NULL); + g_signal_connect(G_OBJECT(widget), "scroll-event", + G_CALLBACK(_scrolled), NULL); + } // TODO: left, right, top, bottom: // leave-notify-event @@ -1859,13 +1871,14 @@ static void _init_main_table(GtkWidget *container) gtk_widget_set_hexpand(ocda, TRUE); gtk_widget_set_vexpand(ocda, TRUE); gtk_widget_set_app_paintable(cda, TRUE); - gtk_widget_set_events(cda, - GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK - | GDK_LEAVE_NOTIFY_MASK | darktable.gui->scroll_mask); gtk_widget_set_can_focus(cda, TRUE); - gtk_widget_set_visible(cda, TRUE); - gtk_overlay_add_overlay(GTK_OVERLAY(ocda), cda); + darktable.gui->ui->snapshot = gtk_drawing_area_new(); + gtk_widget_set_no_show_all(darktable.gui->ui->snapshot, TRUE); + GtkWidget *sidebyside = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_pack_start(GTK_BOX(sidebyside), cda, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(sidebyside), darktable.gui->ui->snapshot, TRUE, TRUE, 0); + gtk_box_set_homogeneous(GTK_BOX(sidebyside), TRUE); + gtk_overlay_add_overlay(GTK_OVERLAY(ocda), sidebyside); gtk_grid_attach(GTK_GRID(centergrid), ocda, 0, 0, 1, 1); darktable.gui->ui->center = cda; @@ -2332,6 +2345,10 @@ GtkWidget *dt_ui_center_base(dt_ui_t *ui) { return ui->center_base; } +GtkWidget *dt_ui_snapshot(dt_ui_t *ui) +{ + return ui->snapshot; +} dt_thumbtable_t *dt_ui_thumbtable(struct dt_ui_t *ui) { return ui->thumbtable; diff --git a/src/gui/gtk.h b/src/gui/gtk.h index 9c9bd8e5a943..4fdd7acf910a 100644 --- a/src/gui/gtk.h +++ b/src/gui/gtk.h @@ -113,6 +113,7 @@ typedef struct dt_gui_gtk_t dt_gui_scrollbars_t scrollbars; cairo_surface_t *surface; + gboolean drawing_snapshot; char *last_preset; @@ -372,6 +373,7 @@ gboolean dt_ui_panel_ancestor(struct dt_ui_t *ui, /** \brief get the center drawable widget */ GtkWidget *dt_ui_center(struct dt_ui_t *ui); GtkWidget *dt_ui_center_base(struct dt_ui_t *ui); +GtkWidget *dt_ui_snapshot(struct dt_ui_t *ui); /** \brief get the main window widget */ GtkWidget *dt_ui_main_window(struct dt_ui_t *ui); /** \brief get the thumb table */ diff --git a/src/libs/snapshots.c b/src/libs/snapshots.c index c6eb8a076d11..7f59c1730491 100644 --- a/src/libs/snapshots.c +++ b/src/libs/snapshots.c @@ -76,11 +76,11 @@ typedef struct dt_lib_snapshots_t dt_lib_snapshot_t snapshot[MAX_SNAPSHOT]; /* change snapshot overlay controls */ - gboolean dragging, vertical, inverted, panning; + gboolean dragging, vertical, inverted, panning, sidebyside; double vp_width, vp_height, vp_xpointer, vp_ypointer, vp_xrotate, vp_yrotate; gboolean on_going; - GtkWidget *take_button; + GtkWidget *take_button, *sidebyside_button; } dt_lib_snapshots_t; /* callback for take snapshot */ @@ -188,6 +188,9 @@ void gui_post_expose(dt_lib_module_t *self, dt_lib_snapshots_t *d = self->data; dt_develop_t *dev = darktable.develop; + if(d->sidebyside && (!darktable.gui->drawing_snapshot ^ !d->inverted)) + return; + if(d->selected >= 0) { dt_lib_snapshot_t *snap = &d->snapshot[d->selected]; @@ -241,8 +244,8 @@ void gui_post_expose(dt_lib_module_t *self, d->vp_width = width; d->vp_height = height; - const double lx = width * d->vp_xpointer; - const double ly = height * d->vp_ypointer; + const double lx = d->sidebyside ? d->inverted ? 0 : width : width * d->vp_xpointer; + const double ly = d->sidebyside ? d->inverted ? 0 : height : height * d->vp_ypointer; const double size = DT_PIXEL_APPLY_DPI(d->inverted ? -15 : 15); @@ -329,7 +332,7 @@ void gui_post_expose(dt_lib_module_t *self, } /* if mouse over control lets draw center rotate control, hide if split is dragged */ - if(!d->dragging) + if(!d->dragging && !d->sidebyside) { const double s = fmin(24, width * HANDLE_SIZE); const gint rx = (d->vertical ? width * d->vp_xpointer : width * 0.5) - (s * 0.5); @@ -405,6 +408,7 @@ int button_pressed(struct dt_lib_module_t *self, || ((!d->vertical && yp > d->vp_ypointer - hhs && yp < d->vp_ypointer + hhs) && xp > 0.5 - hhs && xp < 0.5 + hhs) + || d->sidebyside || (d->vp_xrotate > xp - hhs && d->vp_xrotate <= xp + hhs && d->vp_yrotate > yp - hhs @@ -414,6 +418,7 @@ int button_pressed(struct dt_lib_module_t *self, _lib_snapshot_rotation_cnt++; d->vertical = !d->vertical; + gtk_orientable_set_orientation(GTK_ORIENTABLE(gtk_widget_get_parent(dt_ui_snapshot(darktable.gui->ui))), d->vertical ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL); if(_lib_snapshot_rotation_cnt % 2) d->inverted = !d->inverted; d->vp_xpointer = xp; @@ -724,6 +729,14 @@ static void _signal_image_changed(gpointer instance, dt_lib_module_t *self) dt_control_queue_redraw_center(); } +static void _sidebyside_button_clicked(GtkWidget *widget, dt_lib_module_t *self) +{ + dt_lib_snapshots_t *d = self->data; + + d->sidebyside = !d->sidebyside; + gtk_widget_set_visible(dt_ui_snapshot(darktable.gui->ui), d->sidebyside && d->selected >= 0); +} + void gui_init(dt_lib_module_t *self) { /* initialize ui widgets */ @@ -804,7 +817,17 @@ void gui_init(dt_lib_module_t *self) dt_ui_resize_wrap(d->snapshots_box, 1, "plugins/darkroom/snapshots/windowheight"), TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(self->widget), d->take_button, TRUE, TRUE, 0); + + GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_pack_start(GTK_BOX(hbox), d->take_button, TRUE, TRUE, 0); + d->sidebyside_button = dtgtk_togglebutton_new(dtgtk_cairo_paint_lt_mode_culling_dynamic, 0, NULL); + gtk_box_pack_start(GTK_BOX(hbox), d->sidebyside_button, FALSE, TRUE, 0); + g_signal_connect(G_OBJECT(d->sidebyside_button), "clicked", + G_CALLBACK(_sidebyside_button_clicked), self); + gtk_widget_set_tooltip_text(GTK_WIDGET(d->sidebyside_button), + _("place the snapshot side-by-side / above-below the current image instead of overlaying")); + + gtk_box_pack_start(GTK_BOX(self->widget), hbox, TRUE, TRUE, 0); dt_action_register(DT_ACTION(self), N_("toggle last snapshot"), _lib_snapshots_toggle_last, 0, 0); @@ -935,6 +958,7 @@ static void _lib_snapshots_toggled_callback(GtkToggleButton *widget, dt_lib_modu gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d->snapshot[k].button), FALSE); } darktable.lib->proxy.snapshots.enabled = d->selected >= 0; + gtk_widget_set_visible(dt_ui_snapshot(darktable.gui->ui), d->sidebyside && d->selected >= 0); --darktable.gui->reset; From 89764470fd2f10c4fa74ba0b6605b5b7765b1d94 Mon Sep 17 00:00:00 2001 From: Diederik ter Rahe Date: Sat, 25 Jan 2025 15:33:27 -0500 Subject: [PATCH 2/3] remove unnecessary double buffering gtk (since 2.0) already takes care of this. Added extra checks to avoid warnings. --- src/control/control.c | 53 +++++-------------------------------------- src/control/control.h | 2 +- src/develop/develop.c | 7 ++++-- src/gui/gtk.c | 47 ++------------------------------------ src/gui/gtk.h | 1 - src/views/darkroom.c | 2 +- src/views/view.c | 2 ++ 7 files changed, 17 insertions(+), 97 deletions(-) diff --git a/src/control/control.c b/src/control/control.c index 237d12a86814..240b75a0cbda 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -391,14 +391,6 @@ gboolean dt_control_configure(GtkWidget *da, return TRUE; } -static GdkRGBA _lookup_color(GtkStyleContext *context, const char *name) -{ - GdkRGBA color, fallback = {1.0, 0.0, 0.0, 1.0}; - if(!gtk_style_context_lookup_color (context, name, &color)) - color = fallback; - return color; -} - void dt_control_draw_busy_msg(cairo_t *cr, int width, int height) { PangoRectangle ink; @@ -431,59 +423,26 @@ void dt_control_draw_busy_msg(cairo_t *cr, int width, int height) g_object_unref(layout); } -void *dt_control_expose(GtkWidget *widget) +void dt_control_expose(GtkWidget *widget, cairo_t *cr) { int pointerx, pointery; - if(!darktable.gui->surface) return NULL; - - dt_control_t *dc = darktable.control; - const int width = dt_cairo_image_surface_get_width(darktable.gui->surface); - const int height = dt_cairo_image_surface_get_height(darktable.gui->surface); gdk_window_get_device_position(gtk_widget_get_window(widget), gdk_seat_get_pointer(gdk_display_get_default_seat(gtk_widget_get_display(widget))), &pointerx, &pointery, NULL); - // create a gtk-independent surface to draw on - cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - cairo_t *cr = cairo_create(cst); - - // TODO: control_expose: only redraw the part not overlapped by - // temporary control panel show! - // - dc->width = width; - dc->height = height; - - GtkStyleContext *context = gtk_widget_get_style_context(widget); - - // look up some colors once - const GdkRGBA bg_color = _lookup_color(context, "bg_color"); + dt_control_t *dc = darktable.control; + dc->width = gtk_widget_get_allocated_width(widget); + dc->height = gtk_widget_get_allocated_height(widget); - gdk_cairo_set_source_rgba(cr, &bg_color); - cairo_save(cr); - cairo_rectangle(cr, 0, 0, width, height); - cairo_clip(cr); - cairo_new_path(cr); - // draw view - dt_view_manager_expose(darktable.view_manager, cr, width, height, pointerx, pointery); - cairo_restore(cr); + dt_view_manager_expose(darktable.view_manager, cr, dc->width, dc->height, pointerx, pointery); // draw busy indicator dt_pthread_mutex_lock(&dc->log_mutex); if(dc->log_busy > 0) { - dt_control_draw_busy_msg(cr, width, height); + dt_control_draw_busy_msg(cr, dc->width, dc->height); } dt_pthread_mutex_unlock(&dc->log_mutex); - - cairo_destroy(cr); - - cairo_t *cr_pixmap = cairo_create(darktable.gui->surface); - cairo_set_source_surface(cr_pixmap, cst, 0, 0); - cairo_paint(cr_pixmap); - cairo_destroy(cr_pixmap); - - cairo_surface_destroy(cst); - return NULL; } gboolean dt_control_draw_endmarker(GtkWidget *widget, diff --git a/src/control/control.h b/src/control/control.h index 420ee9cbddb6..61163eaace1f 100644 --- a/src/control/control.h +++ b/src/control/control.h @@ -46,7 +46,7 @@ struct dt_lib_backgroundjob_element_t; typedef GdkCursorType dt_cursor_t; // called from gui -void *dt_control_expose(GtkWidget *widget); +void dt_control_expose(GtkWidget *widget, cairo_t *cr); gboolean dt_control_draw_endmarker(GtkWidget *widget, cairo_t *crf, gpointer user_data); void dt_control_button_pressed(double x, double y, double pressure, int which, int type, uint32_t state); void dt_control_button_released(double x, double y, int which, uint32_t state); diff --git a/src/develop/develop.c b/src/develop/develop.c index 051a5f3e1115..5467461a5613 100644 --- a/src/develop/develop.c +++ b/src/develop/develop.c @@ -572,8 +572,11 @@ float dt_dev_get_zoom_scale(dt_dev_viewport_t *port, break; } - if(preview) zoom_scale *= (float)darktable.develop->full.pipe->processed_width - / darktable.develop->preview_pipe->processed_width; + if(!zoom_scale) zoom_scale = 1.0f; + + if(preview && darktable.develop->preview_pipe->processed_width) + zoom_scale *= (float)darktable.develop->full.pipe->processed_width + / darktable.develop->preview_pipe->processed_width; return zoom_scale; } diff --git a/src/gui/gtk.c b/src/gui/gtk.c index c524dce5d08e..0e283b4f0c32 100644 --- a/src/gui/gtk.c +++ b/src/gui/gtk.c @@ -716,12 +716,7 @@ static gboolean _draw(GtkWidget *da, darktable.gui->drawing_snapshot = da == ss; if(!darktable.gui->drawing_snapshot) gtk_widget_queue_draw(ss); - dt_control_expose(da); - if(darktable.gui->surface) - { - cairo_set_source_surface(cr, darktable.gui->surface, 0, 0); - cairo_paint(cr); - } + dt_control_expose(da, cr); return TRUE; } @@ -956,35 +951,6 @@ static gboolean _configure(GtkWidget *da, GdkEventConfigure *event, gpointer user_data) { - static int oldw = 0; - static int oldh = 0; - // make our selves a properly sized pixmap if our window has been resized - if(oldw != event->width || oldh != event->height) - { - // create our new pixmap with the correct size. - cairo_surface_t *tmpsurface - = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, event->width, event->height); - // copy the contents of the old pixmap to the new pixmap. This keeps ugly uninitialized - // pixmaps from being painted upon resize - // int minw = oldw, minh = oldh; - // if(event->width < minw) minw = event->width; - // if(event->height < minh) minh = event->height; - - cairo_t *cr = cairo_create(tmpsurface); - cairo_set_source_surface(cr, darktable.gui->surface, 0, 0); - cairo_paint(cr); - cairo_destroy(cr); - - // we're done with our old pixmap, so we can get rid of it and - // replace it with our properly-sized one. - cairo_surface_destroy(darktable.gui->surface); - darktable.gui->surface = tmpsurface; - dt_colorspaces_set_display_profile( - DT_COLORSPACE_DISPLAY); // maybe we are on another screen now with > 50% of the area - } - oldw = event->width; - oldh = event->height; - #ifndef GDK_WINDOWING_QUARTZ dt_configure_ppd_dpi((dt_gui_gtk_t *) user_data); #endif @@ -1357,7 +1323,6 @@ int dt_gui_gtk_init(dt_gui_gtk_t *gui) GtkWidget *widget; if(!gui->ui) gui->ui = g_malloc0(sizeof(dt_ui_t)); - gui->surface = NULL; gui->hide_tooltips = dt_conf_get_bool("ui/hide_tooltips") ? 1 : 0; gui->grouping = dt_conf_get_bool("ui_last/grouping"); gui->expanded_group_id = NO_IMGID; @@ -1575,9 +1540,7 @@ void dt_gui_gtk_run(dt_gui_gtk_t *gui) GtkWidget *widget = dt_ui_center(darktable.gui->ui); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); - darktable.gui->surface - = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - allocation.width, allocation.height); + // need to pre-configure views to avoid crash caused by draw coming // before configure-event darktable.control->tabborder = 8; @@ -1597,12 +1560,6 @@ void dt_gui_gtk_run(dt_gui_gtk_t *gui) gtk_main(); g_atomic_int_set(&darktable.gui_running, 0); } - - if(darktable.gui->surface) - { - cairo_surface_destroy(darktable.gui->surface); - darktable.gui->surface = NULL; - } } // refactored function to read current ppd, because gtk for osx has diff --git a/src/gui/gtk.h b/src/gui/gtk.h index 4fdd7acf910a..516d87abff34 100644 --- a/src/gui/gtk.h +++ b/src/gui/gtk.h @@ -112,7 +112,6 @@ typedef struct dt_gui_gtk_t dt_gui_scrollbars_t scrollbars; - cairo_surface_t *surface; gboolean drawing_snapshot; char *last_preset; diff --git a/src/views/darkroom.c b/src/views/darkroom.c index ef5678fc5927..bc2dd8401b56 100644 --- a/src/views/darkroom.c +++ b/src/views/darkroom.c @@ -667,7 +667,7 @@ void expose(dt_view_t *self, if(_preview2_request(dev)) dt_dev_process_preview2(dev); /* if we are in full preview mode, we don"t want anything else than the image */ - if(dev->full_preview) + if(dev->full_preview || !darktable.develop->preview_pipe->processed_width) return; float wd, ht; diff --git a/src/views/view.c b/src/views/view.c index b5211d6a2288..43c319315981 100644 --- a/src/views/view.c +++ b/src/views/view.c @@ -1669,6 +1669,8 @@ void dt_view_paint_surface(cairo_t *cr, int processed_width, processed_height; dt_dev_get_processed_size(port, &processed_width, &processed_height); + if(!processed_width || !processed_height) + return; float pts[] = { buf_zoom_x, buf_zoom_y, dev->preview_pipe->backbuf_zoom_x, dev->preview_pipe->backbuf_zoom_y, From d47e35da0ce22df164392c881a67bf36ae92586e Mon Sep 17 00:00:00 2001 From: Diederik ter Rahe Date: Sat, 25 Jan 2025 18:24:07 -0500 Subject: [PATCH 3/3] make sure snapshot updates after rotating in sbs --- src/libs/snapshots.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libs/snapshots.c b/src/libs/snapshots.c index 7f59c1730491..cb87332c1d73 100644 --- a/src/libs/snapshots.c +++ b/src/libs/snapshots.c @@ -420,6 +420,8 @@ int button_pressed(struct dt_lib_module_t *self, d->vertical = !d->vertical; gtk_orientable_set_orientation(GTK_ORIENTABLE(gtk_widget_get_parent(dt_ui_snapshot(darktable.gui->ui))), d->vertical ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL); if(_lib_snapshot_rotation_cnt % 2) d->inverted = !d->inverted; + if(d->sidebyside) + d->snap_requested = TRUE; d->vp_xpointer = xp; d->vp_ypointer = yp; @@ -734,7 +736,9 @@ static void _sidebyside_button_clicked(GtkWidget *widget, dt_lib_module_t *self) dt_lib_snapshots_t *d = self->data; d->sidebyside = !d->sidebyside; - gtk_widget_set_visible(dt_ui_snapshot(darktable.gui->ui), d->sidebyside && d->selected >= 0); + d->snap_requested = TRUE; + gtk_widget_set_visible(dt_ui_snapshot(darktable.gui->ui), + d->sidebyside && d->selected >= 0); } void gui_init(dt_lib_module_t *self)