diff --git a/DefineOptions.cmake b/DefineOptions.cmake index 729faed12ecb..2c1f64f2a4cd 100644 --- a/DefineOptions.cmake +++ b/DefineOptions.cmake @@ -1,20 +1,20 @@ -option(USE_CAMERA_SUPPORT "Detect and use camera support if available." ON) -option(USE_COLORD "Enable colord support" ON) -option(USE_MAP "Build Map View parts" ON) -option(USE_LUA "Build lua scripting support" ON) +option(USE_CAMERA_SUPPORT "Detect and use camera support if available." OFF) +option(USE_COLORD "Enable colord support" OFF) +option(USE_MAP "Build Map View parts" OFF) +option(USE_LUA "Build lua scripting support" OFF) option(DONT_USE_INTERNAL_LUA "Never fall back to the intree copy of lua" ON) -option(USE_KWALLET "Build kwallet password storage back-end" ON) -option(USE_LIBSECRET "Build libsecret password storage back-end" ON) +option(USE_KWALLET "Build kwallet password storage back-end" OFF) +option(USE_LIBSECRET "Build libsecret password storage back-end" OFF) option(USE_UNITY "Use libunity to report progress in the launcher" OFF) option(USE_OPENMP "Use OpenMP threading support." ON) option(USE_OPENCL "Use OpenCL support." ON) -option(USE_GRAPHICSMAGICK "Use GraphicsMagick library for image import." ON) +option(USE_GRAPHICSMAGICK "Use GraphicsMagick library for image import." OFF) option(USE_IMAGEMAGICK "Use ImageMagick library for image import." OFF) option(USE_DARKTABLE_PROFILING OFF) option(CUSTOM_CFLAGS "Don't override compiler optimization flags." OFF) option(BINARY_PACKAGE_BUILD "Sets march optimization to generic" OFF) option(USE_XMLLINT "Run xmllint to test if darktableconfig.xml is valid" ON) -option(USE_PORTMIDI "Enable MIDI device support using PortMidi" ON) +option(USE_PORTMIDI "Enable MIDI device support using PortMidi" OFF) option(USE_OPENJPEG "Enable JPEG 2000 support" ON) option(USE_JXL "Enable JPEG XL support" ON) option(USE_WEBP "Enable WebP support" ON) @@ -26,17 +26,17 @@ option(USE_LIBRAW "Enable LibRaw support" ON) option(DONT_USE_INTERNAL_LIBRAW "If possible, use system instead of intree copy of LibRaw" OFF) option(BUILD_CMSTEST "Build a test program to check your system's color management setup" ON) option(USE_OPENEXR "Enable OpenEXR support" ON) -option(BUILD_PRINT "Build the print module" ON) +option(BUILD_PRINT "Build the print module" OFF) option(BUILD_RS_IDENTIFY "Build the darktable-rs-identify debug aid" ON) option(BUILD_SSE2_CODEPATHS "(EXPERIMENTAL OPTION, DO NOT DISABLE) Building SSE2-optimized codepaths" ON) option(VALIDATE_APPDATA_FILE "Use appstream-util (if found) to validate the .appdata file" OFF) option(BUILD_MSYS2_INSTALL "Build an MSYS2 version of the install, aka for Windows platform, but without dependency installs" OFF) option(BUILD_NOISE_TOOLS "Build tools for generating noise profiles" OFF) option(BUILD_CURVE_TOOLS "Build tools for generating base and tone curves" OFF) -option(USE_GMIC "Use G'MIC image processing framework." ON) +option(USE_GMIC "Use G'MIC image processing framework." OFF) option(USE_ICU "Use ICU - International Components for Unicode." ON) option(FORCE_COLORED_OUTPUT "Always produce ANSI-colored output (GNU/Clang only)." OFF) -option(USE_SDL2 "Enable SDL2 support" ON) +option(USE_SDL2 "Enable SDL2 support" OFF) if (USE_OPENCL) option(TESTBUILD_OPENCL_PROGRAMS "Test-compile OpenCL programs (needs LLVM and Clang 7+)" ON) @@ -45,7 +45,7 @@ else () endif () if(APPLE) - option(USE_MAC_INTEGRATION "Enable macOS integration" ON) + option(USE_MAC_INTEGRATION "Enable macOS integration" OFF) else(APPLE) set(USE_MAC_INTEGRATION OFF) endif(APPLE) diff --git a/cmake/modules/FindGTK4.cmake b/cmake/modules/FindGTK4.cmake new file mode 100644 index 000000000000..ef28243e33a4 --- /dev/null +++ b/cmake/modules/FindGTK4.cmake @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.18) + +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK4 REQUIRED IMPORTED_TARGET gtk4) \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ed77c93cdad6..57735988e601 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -124,7 +124,6 @@ FILE(GLOB SOURCE_FILES "dtgtk/drawingarea.c" "dtgtk/expander.c" "dtgtk/gradientslider.c" - "dtgtk/icon.c" "dtgtk/paint.c" "dtgtk/range.c" "dtgtk/resetlabel.c" @@ -295,11 +294,11 @@ include_directories(SYSTEM ${Glib_INCLUDE_DIRS}) list(APPEND LIBS ${Glib_LIBRARIES}) # GTK3 pulls in ATK, GDK, GDK-PIXBUF, CAIRO, GLIB, PANGO -find_package(GTK3 3.24.15 REQUIRED) -add_definitions("-DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_3_24") -#add_definitions("-DGDK_VERSION_MAX_ALLOWED=GDK_VERSION_MIN_REQUIRED") -include_directories(SYSTEM ${GTK3_INCLUDE_DIRS}) -list(APPEND LIBS ${GTK3_LIBRARIES}) +find_package(GTK4 4.8.3 REQUIRED) +add_definitions("-DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_4_0") +add_definitions("-DGDK_VERSION_MAX_ALLOWED=GDK_VERSION_4_18") +include_directories(SYSTEM ${GTK4_INCLUDE_DIRS}) +list(APPEND LIBS ${GTK4_LIBRARIES}) # Check for libxml2 / broken cmake module can't be included in the foreach() below find_package(LibXml2 2.6 REQUIRED) diff --git a/src/bauhaus/bauhaus.c b/src/bauhaus/bauhaus.c index 268cb9d9f756..6dc3a7947c85 100644 --- a/src/bauhaus/bauhaus.c +++ b/src/bauhaus/bauhaus.c @@ -23,15 +23,13 @@ #include "control/conf.h" #include "develop/develop.h" #include "develop/imageop.h" +#include "dtgtk/drawingarea.h" #include "gui/accelerators.h" #include "gui/color_picker_proxy.h" #include "gui/gtk.h" #ifdef GDK_WINDOWING_QUARTZ #include "osx/osx.h" #endif -#ifdef GDK_WINDOWING_WAYLAND -#include -#endif #include @@ -306,12 +304,7 @@ static int _show_pango_text(dt_bauhaus_widget_t *w, pango_layout_set_width(layout, (int)(PANGO_SCALE * max_width + 0.5f)); } - PangoFontDescription *font_desc = 0; - gtk_style_context_get(context, - gtk_widget_get_state_flags(GTK_WIDGET(w)), "font", - &font_desc, NULL); - - pango_layout_set_font_description(layout, font_desc); + pango_layout_set_font_description(layout, darktable.bauhaus->pango_font_desc); PangoAttrList *attrlist = pango_attr_list_new(); pango_attr_list_insert(attrlist, pango_attr_font_features_new("tnum")); @@ -349,7 +342,6 @@ static int _show_pango_text(dt_bauhaus_widget_t *w, cairo_move_to(cr, x_pos, y_pos); pango_cairo_show_layout(cr, layout); } - pango_font_description_free(font_desc); g_object_unref(layout); return text_width; @@ -766,7 +758,7 @@ static void _widget_finalize(GObject *widget) void dt_bauhaus_load_theme() { GtkWidget *root_window = dt_ui_main_window(darktable.gui->ui); - GtkStyleContext *ctx = gtk_style_context_new(); + GtkStyleContext *ctx = gtk_widget_get_style_context(root_window); GtkWidgetPath *path = gtk_widget_path_new(); const int pos = gtk_widget_path_append_type(path, GTK_TYPE_WIDGET); gtk_widget_path_iter_add_class(path, pos, "dt_bauhaus"); @@ -823,11 +815,10 @@ void dt_bauhaus_load_theme() &bh->colorlabels[DT_COLORLABELS_PURPLE]); // make sure we release previously loaded font + PangoContext *pango_context = gtk_widget_get_pango_context(root_window); if(bh->pango_font_desc) pango_font_description_free(bh->pango_font_desc); - bh->pango_font_desc = NULL; - gtk_style_context_get(ctx, GTK_STATE_FLAG_NORMAL, "font", - &bh->pango_font_desc, NULL); + bh->pango_font_desc = pango_font_description_copy_static(pango_context_get_font_description(pango_context)); cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 128, 128); cairo_t *cr = cairo_create(cst); @@ -883,7 +874,7 @@ void dt_bauhaus_init() GDK_WINDOW_TYPE_HINT_POPUP_MENU); pop->area = gtk_drawing_area_new(); - g_object_set(pop->area, "expand", TRUE, NULL); + // GTK4 g_object_set(pop->area, "expand", TRUE, NULL); gtk_container_add(GTK_CONTAINER(pop->window), pop->area); gtk_widget_set_can_focus(pop->area, TRUE); gtk_widget_add_events(pop->area, @@ -1129,7 +1120,7 @@ gchar *dt_bauhaus_widget_get_tooltip_markup(GtkWidget *widget, && DT_IS_BAUHAUS_WIDGET(widget) && DT_BAUHAUS_WIDGET(widget)->tooltip ? g_markup_escape_text(DT_BAUHAUS_WIDGET(widget)->tooltip, -1) - : gtk_widget_get_tooltip_markup(widget); + : g_strdup(gtk_widget_get_tooltip_markup(widget)); if(!darktable.control->mapping_widget && dt_bauhaus_widget_get_type(widget) == DT_BAUHAUS_SLIDER) { @@ -2607,15 +2598,19 @@ static gboolean _popup_draw(GtkWidget *widget, return TRUE; } -static gboolean _widget_draw(GtkWidget *widget, - cairo_t *crf) + +static void _widget_snapshot(GtkWidget* widget, + GtkSnapshot* snapshot) { GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); + + graphene_rect_t bounds; + graphene_rect_init(&bounds, 0, 0, allocation.width, allocation.height); + cairo_t* cr = gtk_snapshot_append_cairo(snapshot, &bounds); + dt_bauhaus_widget_t *w = DT_BAUHAUS_WIDGET(widget); const int width = allocation.width, height = allocation.height; - cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - cairo_t *cr = cairo_create(cst); GtkStyleContext *context = gtk_widget_get_style_context(widget); GdkRGBA *fg_color = _default_color_assign(); @@ -2627,7 +2622,9 @@ static gboolean _widget_draw(GtkWidget *widget, gtk_style_context_get_color(context, state, text_color); gtk_style_context_get_color(context, state, fg_color); - gtk_style_context_get(context, state, "background-color", &bg_color, NULL); + // gtk_style_context_get(context, state, "background-color", &bg_color, NULL); + GdkRGBA color = {.red = 0.0f, .green = 0.0f, .blue = 0.0f, .alpha = 1.0f}; + bg_color = gdk_rgba_copy(&color); // translate to account for the widget spacing const int h2 = height - w->margin.top - w->margin.bottom; @@ -2756,18 +2753,12 @@ static gboolean _widget_draw(GtkWidget *widget, default: break; } - cairo_restore(cr); cairo_destroy(cr); - cairo_set_source_surface(crf, cst, 0, 0); - cairo_paint(crf); - cairo_surface_destroy(cst); - gtk_render_frame(context, crf, w->margin.left, w->margin.top, w2, h2); + gtk_render_frame(context, cr, w->margin.left, w->margin.top, w2, h2); gdk_rgba_free(text_color); gdk_rgba_free(fg_color); gdk_rgba_free(bg_color); - - return TRUE; } static gint _natural_width(GtkWidget *widget, @@ -2839,34 +2830,35 @@ static gint _natural_width(GtkWidget *widget, return natural_size; } -static void _widget_get_preferred_width(GtkWidget *widget, - gint *minimum_width, - gint *natural_width) +static void _widget_measure(GtkWidget* widget, + GtkOrientation orientation, + int for_size, + int* minimum, + int* natural, + int* minimum_baseline, + int* natural_baseline) { dt_bauhaus_widget_t *w = (dt_bauhaus_widget_t *)widget; _margins_retrieve(w); - - *natural_width = _natural_width(widget, FALSE) - + w->margin.left + w->margin.right + w->padding.left + w->padding.right; -} - -static void _widget_get_preferred_height(GtkWidget *widget, - gint *minimum_height, - gint *natural_height) -{ - dt_bauhaus_widget_t *w = (dt_bauhaus_widget_t *)widget; - _margins_retrieve(w); - - *minimum_height = w->margin.top + w->margin.bottom + w->padding.top + w->padding.bottom - + darktable.bauhaus->line_height; - if(w->type == DT_BAUHAUS_SLIDER) + if(orientation == GTK_ORIENTATION_HORIZONTAL) { - // the lower thing to draw is indicator. See _draw_baseline for compute details - *minimum_height += INNER_PADDING - + darktable.bauhaus->baseline_size + 1.5f * darktable.bauhaus->border_width; + + *natural = _natural_width(widget, FALSE) + + w->margin.left + w->margin.right + w->padding.left + w->padding.right; } + else + { + *minimum = w->margin.top + w->margin.bottom + w->padding.top + w->padding.bottom + + darktable.bauhaus->line_height; + if(w->type == DT_BAUHAUS_SLIDER) + { + // the lower thing to draw is indicator. See _draw_baseline for compute details + *minimum += INNER_PADDING + + darktable.bauhaus->baseline_size + 1.5f * darktable.bauhaus->border_width; + } - *natural_height = *minimum_height; + *natural = *minimum; + } } static void _popup_hide() @@ -2894,6 +2886,7 @@ static void _popup_hide() static void _popup_show(GtkWidget *widget) { + return; // GTK4 dt_bauhaus_widget_t *w = DT_BAUHAUS_WIDGET(widget); dt_bauhaus_t *bh = darktable.bauhaus; dt_bauhaus_popup_t *pop = &bh->popup; @@ -3072,19 +3065,21 @@ static void _slider_add_step(GtkWidget *widget, dt_bauhaus_slider_set(widget, CLAMP(value + delta, d->min, d->max)); } -static gboolean _widget_scroll(GtkWidget *widget, - GdkEventScroll *event) +static gboolean _widget_scroll(GtkEventControllerScroll* self, + gdouble dx, + gdouble dy, + GtkWidget *widget) { - if(dt_gui_ignore_scroll(event)) return FALSE; +// GTK4 +// if(dt_gui_ignore_scroll(event)) return FALSE; - // handle speed adjustment in mapping mode in dispatcher - if(darktable.control->mapping_widget) - return dt_shortcut_dispatcher(widget, (GdkEvent*)event, NULL); +// // handle speed adjustment in mapping mode in dispatcher +// if(darktable.control->mapping_widget) +// return dt_shortcut_dispatcher(widget, (GdkEvent*)event, NULL); gtk_widget_grab_focus(widget); - int delta_y = 0; - if(dt_gui_get_scroll_unit_delta(event, &delta_y)) + int delta_y = dx + dy; { if(delta_y == 0) return TRUE; @@ -3093,15 +3088,17 @@ static gboolean _widget_scroll(GtkWidget *widget, if(w->type == DT_BAUHAUS_SLIDER) { - const gboolean force = darktable.control->element == DT_ACTION_ELEMENT_FORCE - && event->window == gtk_widget_get_window(widget); - if(force && dt_modifier_is(event->state, GDK_SHIFT_MASK | GDK_CONTROL_MASK)) - { - _slider_zoom_range(w, delta_y); - _slider_zoom_toast(w); - } - else - _slider_add_step(widget, - delta_y, event->state, force); + // GTK4 + // gboolean force = darktable.control->element == DT_ACTION_ELEMENT_FORCE + // && event->window == gtk_widget_get_window(widget); + // if(force && dt_modifier_is(event->state, GDK_SHIFT_MASK | GDK_CONTROL_MASK)) + // { + // _slider_zoom_range(w, delta_y); + // _slider_zoom_toast(w); + // } + // else + // _slider_add_step(widget, - delta_y, event->state, force); + _slider_add_step(widget, - delta_y, gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(self)), FALSE); } else _combobox_next_sensitive(w, delta_y, 0, FALSE); @@ -3567,7 +3564,7 @@ static void _widget_button_press(GtkGestureSingle *gesture, } else if(button == GDK_BUTTON_SECONDARY || w->type == DT_BAUHAUS_COMBOBOX) { - bh->opentime = gdk_event_get_time(gtk_get_current_event()); + bh->opentime = gtk_event_controller_get_current_event_time(GTK_EVENT_CONTROLLER(gesture)); bh->mouse_x = x; bh->mouse_y = y; _popup_show(widget); @@ -3650,8 +3647,7 @@ static void _widget_motion(GtkEventControllerMotion *controller, const float scaled_step = width * dt_bauhaus_slider_get_step(widget) / (d->max - d->min); const float steps = floorf((x - bh->mouse_x) / scaled_step); - GdkEventMotion *event = (GdkEventMotion *)gtk_get_current_event(); // TODO cleanup - _slider_add_step(widget, copysignf(1, d->factor) * steps, event->state, FALSE); + _slider_add_step(widget, copysignf(1, d->factor) * steps, dt_controller_state(controller), FALSE); bh->mouse_x += steps * scaled_step; } @@ -3680,20 +3676,17 @@ static void dt_bh_class_init(DtBauhausWidgetClass *class) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class); - widget_class->draw = _widget_draw; - // widget_class->snapshot = _widget_snapshot; - widget_class->scroll_event = _widget_scroll; - widget_class->key_press_event = _widget_key_press; - widget_class->get_preferred_width = _widget_get_preferred_width; - widget_class->get_preferred_height = _widget_get_preferred_height; - // widget_class->measure = _widget_measure; + widget_class->snapshot = _widget_snapshot; + // widget_class->scroll_event = _widget_scroll; + // widget_class->key_press_event = _widget_key_press; + widget_class->measure = _widget_measure; G_OBJECT_CLASS(class)->finalize = _widget_finalize; // for histogram -> exposure proxy bh->press = _widget_button_press; bh->release = _widget_button_release; bh->motion = _widget_motion; - bh->scroll = _widget_scroll; + // bh->scroll = _widget_scroll; GTK4 } static void dt_bh_init(DtBauhausWidget *w) @@ -3719,9 +3712,9 @@ static void dt_bh_init(DtBauhausWidget *w) dt_gui_connect_motion(w, _widget_motion, _widget_enter, _widget_leave, widget); - // GtkEventController *controller = gtk_event_controller_scroll_new(GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE); - // gtk_widget_add_controller(GTK_WIDGET(w), GTK_EVENT_CONTROLLER(controller)); - // g_signal_connect(controller, "scroll", G_CALLBACK(_widget_scroll), w); + GtkEventController *controller = gtk_event_controller_scroll_new(GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE); + gtk_widget_add_controller(GTK_WIDGET(w), GTK_EVENT_CONTROLLER(controller)); + g_signal_connect(controller, "scroll", G_CALLBACK(_widget_scroll), w); gtk_widget_set_can_focus(widget, TRUE); dt_gui_add_class(widget, "dt_bauhaus"); diff --git a/src/chart/main.c b/src/chart/main.c index 875c562fc7b2..d0fd9656918e 100644 --- a/src/chart/main.c +++ b/src/chart/main.c @@ -1659,7 +1659,7 @@ static void image_lab_to_xyz(float *image, const int width, const int height) static int main_gui(dt_lut_t *self, int argc, char *argv[]) { - gtk_init(&argc, &argv); + gtk_init(); char *source_filename = argc >= 2 ? argv[1] : NULL; char *cht_filename = argc >= 3 ? argv[2] : NULL; diff --git a/src/common/darktable.c b/src/common/darktable.c index bf2fe6bebe11..61f82016827d 100644 --- a/src/common/darktable.c +++ b/src/common/darktable.c @@ -1538,7 +1538,7 @@ int dt_init(int argc, // however after gtk_disable_setlocale if(init_gui) { - gtk_init(&argc, &argv); + gtk_init(); darktable.themes = NULL; dt_gui_theme_init(darktable.gui); @@ -1934,6 +1934,18 @@ int dt_init(int argc, dt_view_manager_gui_init(darktable.view_manager); } + + + + + + // g_log_set_always_fatal(G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL); + + + + + + /* init lua last, since it's user made stuff it must be in the real environment */ #ifdef USE_LUA darktable_splash_screen_set_progress(_("initializing Lua")); @@ -1959,8 +1971,16 @@ int dt_init(int argc, dt_shortcuts_save(NULL, TRUE); // connect the shortcut dispatcher - g_signal_connect(dt_ui_main_window(darktable.gui->ui), "event", - G_CALLBACK(dt_shortcut_dispatcher), NULL); + // GtkEventController *legacy_controller = gtk_event_controller_legacy_new(); + // gtk_widget_add_controller(dt_ui_main_window(darktable.gui->ui), legacy_controller); + // g_signal_connect(legacy_controller, "event", + // G_CALLBACK(dt_shortcut_dispatcher), NULL); + const gchar *eventnames[] = { "key-press-event", "key-release-event", + "button-press-event", "button-release-event", + "scroll-event", NULL }; + for(int i = 0; eventnames[i] != NULL; i++) + g_signal_connect(dt_ui_main_window(darktable.gui->ui), eventnames[i], + G_CALLBACK(dt_shortcut_dispatcher), NULL); // load image(s) specified on cmdline. this has to happen after // lua is initialized as image import can run lua code @@ -2025,7 +2045,7 @@ int dt_init(int argc, if(init_gui) { // show the main window and restore its geometry to that saved in the config file - gtk_widget_show_all(dt_ui_main_window(darktable.gui->ui)); + gtk_window_present(GTK_WINDOW(dt_ui_main_window(darktable.gui->ui))); dt_gui_gtk_load_config(); darktable_splash_screen_destroy(); @@ -2695,6 +2715,320 @@ void dt_print_mem_usage(char *info) #endif } + + + + + + +// GTK4 + + +void gtk_container_add(GtkContainer *container, GtkWidget *child) +{ + g_return_if_fail(GTK_IS_WIDGET(container)); + g_return_if_fail(GTK_IS_WIDGET(child)); + + if(GTK_IS_BOX(container)) + gtk_box_append(GTK_BOX(container), child); + else if(GTK_IS_GRID(container)) + gtk_grid_attach(GTK_GRID (container), child, 0, 0, 1, 1); + else if(GTK_IS_OVERLAY(container)) + gtk_overlay_set_child(GTK_OVERLAY(container), child); + else if(GTK_IS_SCROLLED_WINDOW(container)) + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(container), child); + else if(GTK_IS_FRAME(container)) + gtk_frame_set_child(GTK_FRAME(container), child); + else if(GTK_IS_WINDOW(container)) + gtk_window_set_child(GTK_WINDOW(container), child); + else if(GTK_IS_EXPANDER(container)) + gtk_expander_set_child(GTK_EXPANDER(container), child); + else if(GTK_IS_LIST_BOX(container)) + gtk_list_box_append(GTK_LIST_BOX (container), child); + else if(GTK_IS_STACK (container)) + gtk_stack_add_child(GTK_STACK(container), child); + else if(GTK_IS_NOTEBOOK(container)) + gtk_notebook_append_page(GTK_NOTEBOOK (container), child, NULL); + else if(GTK_IS_POPOVER(container)) + gtk_popover_set_child(GTK_POPOVER(container), child); + else if(GTK_IS_VIEWPORT(container)) + gtk_viewport_set_child(GTK_VIEWPORT(container), child); + else if(GTK_IS_BUTTON(container)) + gtk_button_set_child(GTK_BUTTON(container), child); + else if(GTK_IS_CHECK_BUTTON(container)) + gtk_check_button_set_child(GTK_CHECK_BUTTON(container), child); + else if(GTK_IS_REVEALER(container)) + gtk_revealer_set_child(GTK_REVEALER(container), child); + else if(GTK_IS_FLOW_BOX(container)) + gtk_flow_box_append(GTK_FLOW_BOX(container), child); + else + g_warning("gtk_container_add: unsupported container type %s", + G_OBJECT_TYPE_NAME (container)); +} + +GList *gtk_container_get_children(GtkContainer *container) +{ + GList *children = NULL; + GtkWidget *child = gtk_widget_get_first_child(GTK_WIDGET(container)); + while(child) + { + children = g_list_append(children, child); + child = gtk_widget_get_next_sibling(child); + } + return children; +} + +GtkWidget *gtk_bin_get_child(gpointer bin) +{ + GtkWidget *child = gtk_widget_get_first_child(GTK_WIDGET(bin)); + // in gtkcheckbox label is not first child + while(child && GTK_IS_CHECK_BUTTON(bin) && !GTK_IS_LABEL(child)) + child = gtk_widget_get_next_sibling(child); + return child; +} + +typedef struct _wrapped_data_t +{ + gpointer instance; + GCallback c_handler; + gpointer user_data; + GClosureNotify destroy_data; + gint type; + gboolean swapped; +} _wrapped_data_t; + +void _free_wrapped_data(_wrapped_data_t *data) +{ + if(data->destroy_data) + data->destroy_data(data->user_data, NULL); + g_free(data); +} + +static void _widget_button(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + _wrapped_data_t *data) +{ + GdkEventButton event = { + .type = data->type ? n_press > 1 ? GDK_DOUBLE_BUTTON_PRESS + n_press - 2 : GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE, + .window = gtk_widget_get_window(widget), + .send_event = TRUE, + .x = x, + .y = y, + .axes = NULL, + .time = gtk_event_controller_get_current_event_time(GTK_EVENT_CONTROLLER(gesture)), + .state = gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(gesture)), + .button = gtk_gesture_single_get_current_button(gesture), + .device = gdk_seat_get_pointer(gdk_display_get_default_seat(gdk_display_get_default())) }; + gboolean ret = ((gboolean(*)(GtkWidget*, GdkEventButton*, gpointer))data->c_handler)(data->instance, &event, data->user_data); + if(ret) dt_gui_claim(gesture); +} + +static void _widget_motion(GtkEventControllerMotion *controller, + double x, + double y, + _wrapped_data_t *data) +{ + if(data->type > 0) + { + GdkEventMotion event = { + .type = GDK_MOTION_NOTIFY, + .window = gtk_widget_get_window(widget), + .send_event = TRUE, + .x = x, + .y = y, + .axes = NULL, + .time = gtk_event_controller_get_current_event_time(GTK_EVENT_CONTROLLER(controller)), + .state = gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(controller)) , + .device = gdk_seat_get_pointer(gdk_display_get_default_seat(gdk_display_get_default())) }; + ((gboolean(*)(GtkWidget*, GdkEventMotion*, gpointer))data->c_handler)(data->instance, &event, data->user_data); + } + else + { + GdkEventCrossing event = { + .type = data->type ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY, + .window = gtk_widget_get_window(widget), + .send_event = TRUE, + .x = x, + .y = y, + .time = gtk_event_controller_get_current_event_time(GTK_EVENT_CONTROLLER(controller)), + .state = gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(controller)) }; + ((gboolean(*)(GtkWidget*, GdkEventCrossing*, gpointer))data->c_handler)(data->instance, &event, data->user_data); + } +} + +static gboolean _widget_scroll(GtkEventControllerScroll* controller, + gdouble dx, + gdouble dy, + _wrapped_data_t *data) +{ + GdkEventScroll event = { + .type = GDK_SCROLL, + .window = gtk_widget_get_window(widget), + .send_event = TRUE, + .time = gtk_event_controller_get_current_event_time(GTK_EVENT_CONTROLLER(controller)), + // .state = gtk_event_controller_get_current_event_state(), doesn't work properly with scroll gestures + .state = gdk_event_get_modifier_state(gtk_event_controller_get_current_event(GTK_EVENT_CONTROLLER(controller))), + .direction = GDK_SCROLL_SMOOTH, + .delta_x = dx, + .delta_y = dy, + .device = gdk_seat_get_pointer(gdk_display_get_default_seat(gdk_display_get_default())) }; + return ((gboolean(*)(GtkWidget*, GdkEventScroll*, gpointer))data->c_handler)(data->instance, &event, data->user_data);; +} + +static void _widget_focus(GtkEventControllerFocus *controller, + _wrapped_data_t *data) +{ + GdkEventCrossing event = { + .type = data->type ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY, + .window = gtk_widget_get_window(widget), + .send_event = TRUE, + .time = gtk_event_controller_get_current_event_time(GTK_EVENT_CONTROLLER(controller)), + .state = gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(controller)) }; + ((gboolean(*)(GtkWidget*, GdkEventCrossing*, gpointer))data->c_handler)(data->instance, &event, data->user_data); +} + +static gboolean _widget_key(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + _wrapped_data_t *data) +{ + GdkEventKey event = { + .type =data->type ? GDK_KEY_PRESS : GDK_KEY_RELEASE, + .window = gtk_widget_get_window(widget), + .send_event = TRUE, + .time = gtk_event_controller_get_current_event_time(GTK_EVENT_CONTROLLER(controller)), + .keyval = keyval, + .hardware_keycode = keycode, + .state = state }; + return ((gboolean(*)(GtkWidget*, GdkEventKey*, gpointer))data->c_handler)(data->instance, &event, data->user_data); +} + +gulong dt_signal_connect_data_with_caller(gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + gpointer user_data, + GClosureNotify destroy_data, + GConnectFlags connect_flags, + gboolean gboolean_return, + const char *function, + const char *file, + const int line) +{ + guint signal_id = 0; + GQuark detail = 0; + GtkEventController *controller = NULL; + gint type = 0; + const gchar *signal_name = NULL; + GCallback handler = NULL; + + if(!(instance)) + dt_print(DT_DEBUG_ALWAYS, "warning: instance is NULL in %s at %s:%d", function, file, line); + else if(g_signal_parse_name(detailed_signal, G_OBJECT_TYPE(instance), &signal_id, &detail, FALSE)) + { + GSignalQuery type_query = {}; + return (g_signal_connect_data)(instance, detailed_signal, c_handler, user_data, destroy_data, connect_flags); + } + else if(!strcmp(detailed_signal, "scroll-event")) + { + signal_name = "scroll"; + controller = gtk_event_controller_scroll_new(GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE); + handler = G_CALLBACK(_widget_scroll); + } + else if(g_str_has_prefix(detailed_signal, "focus-")) + { + type = strcmp(detailed_signal, "focus-out-event"); + signal_name = type ? "enter" : "leave"; + controller = gtk_event_controller_focus_new(); + handler = G_CALLBACK(_widget_focus); + } + else if(g_str_has_prefix(detailed_signal, "key-")) + { + type = strcmp(detailed_signal, "key-release-event"); + signal_name = type ? "key-pressed" : "key-released"; + controller = gtk_event_controller_key_new(); + handler = G_CALLBACK(_widget_key); + } + else if(g_str_has_prefix(detailed_signal, "button-")) + { + type = strcmp(detailed_signal, "button-release-event"); + signal_name = type ? "pressed" : "released"; + if(!(controller = g_object_get_data(instance, "click"))) + g_object_set_data(instance, "click", + controller = GTK_EVENT_CONTROLLER(gtk_gesture_click_new())); + gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(controller), 0); + handler = G_CALLBACK(_widget_button); + } + else if(g_str_has_suffix(detailed_signal, "-notify-event")) + { + type = strcmp(detailed_signal,"leave-notify-event"); + signal_name = type > 0 ? "motion" : type ? "enter" : "leave"; + if(!(controller = g_object_get_data(instance, "motion"))) + g_object_set_data(instance, "motion", + controller = gtk_event_controller_motion_new()); + handler = G_CALLBACK(_widget_motion); + } + else if(g_str_has_prefix(detailed_signal, "drag-") + ||!strcmp(detailed_signal, "style-updated") + ||!strcmp(detailed_signal, "size-allocate") + ||!strcmp(detailed_signal, "draw")) + ; // GTK4 FIXME not yet supported + else + dt_print(DT_DEBUG_ALWAYS, "warning: no signal '%s' for %s in %s at %s:%d", detailed_signal, g_type_name(G_OBJECT_TYPE(instance)), function, file, line); + + if(controller) + { + _wrapped_data_t *data = g_new(_wrapped_data_t, 1); + data->instance = connect_flags & G_CONNECT_SWAPPED ? user_data : instance; + data->c_handler = c_handler; + data->user_data = connect_flags & G_CONNECT_SWAPPED ? instance : user_data; + data->destroy_data = destroy_data; + data->type = type; + if(!gtk_event_controller_get_widget(controller)) + gtk_widget_add_controller(instance, controller); + (g_signal_connect_data)(controller, signal_name, handler, data, (GClosureNotify)_free_wrapped_data, /*connect_flags*/0); + } + + return 0; +} + +static void _dialog_response(GtkDialog *dialog, + int response_id, + int *response_ptr) +{ + *response_ptr = response_id; +} +int _wait_for_dialog_response(gpointer dialog) +{ + int response_id = G_MAXINT; + g_signal_connect(dialog, "response", G_CALLBACK(_dialog_response), &response_id); +// FIXME GTK4 doesn't really support reentrent event loops so all calls to dialog_run should be converted to respond to "response" directly. + while(response_id == G_MAXINT + && g_list_model_get_n_items(gtk_window_get_toplevels()) > 0) + g_main_context_iteration(NULL, FALSE); + return response_id; +} +int gtk_dialog_run(GtkDialog *dialog) +{ + GtkWindow *win = GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)); + if(!gtk_window_get_transient_for(GTK_WINDOW(dialog))) + gtk_window_set_transient_for(GTK_WINDOW(dialog), win); + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + gtk_window_present(GTK_WINDOW(dialog)); + return _wait_for_dialog_response(dialog); +} +int gtk_native_dialog_run(GtkNativeDialog *dialog) +{ + GtkWindow *win = GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)); + if(!gtk_native_dialog_get_transient_for(GTK_NATIVE_DIALOG(dialog))) + gtk_native_dialog_set_transient_for(GTK_NATIVE_DIALOG(dialog), win); + gtk_native_dialog_set_modal(GTK_NATIVE_DIALOG(dialog), TRUE); + gtk_native_dialog_show(GTK_NATIVE_DIALOG(dialog)); + return _wait_for_dialog_response(dialog); +} + // clang-format off // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py // vim: shiftwidth=2 expandtab tabstop=2 cindent diff --git a/src/common/darktable.h b/src/common/darktable.h index 359759598121..ec584616b270 100644 --- a/src/common/darktable.h +++ b/src/common/darktable.h @@ -982,6 +982,550 @@ static inline gboolean dt_check_gimpmode_ok(const char *mode) return darktable.gimp.mode ? !darktable.gimp.error && strcmp(darktable.gimp.mode, mode) == 0 : FALSE; } + + + + + + + +// GTK4 compatibility stubs + + +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-const-variable" +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wuninitialized" +// #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +// #pragma GCC diagnostic ignored "-Wimplicit-function-declaration" +#pragma GCC diagnostic ignored "-Wswitch" + +typedef int gboolean; +typedef struct {void *dummy;} *GdkAtom; +typedef struct {void *dummy;} GdkWindow; +typedef struct {void *dummy;} GdkScreen; +typedef struct {void *dummy;} GtkContainer; +typedef struct {void *dummy;} GtkMenu; +typedef struct {void *dummy;} GtkMenuItem; +typedef struct {void *dummy;} GtkMenuShell; +typedef struct {void *dummy;} GdkDragContext; +typedef struct {void *dummy;} GdkVisual; +typedef struct {void *dummy;} GtkSelectionData; +typedef struct {void *dummy;} GtkWidgetPath; +typedef struct {void *dummy;} GdkKeymap; +typedef struct {void *dummy;} GtkTargetList; +typedef struct {void *dummy;} GtkFileChooserButton; +typedef struct {void *dummy;} GtkRadioButton; + +typedef enum +{ + GDK_X_CURSOR = 0, + GDK_BOTTOM_LEFT_CORNER = 12, + GDK_BOTTOM_RIGHT_CORNER = 14, + GDK_BOTTOM_SIDE = 16, + GDK_CROSS = 30, + GDK_CROSSHAIR = 34, + GDK_FLEUR = 52, + GDK_HAND1 = 58, + GDK_LEFT_PTR = 68, + GDK_LEFT_SIDE = 70, + GDK_PIRATE = 88, + GDK_PLUS = 90, + GDK_QUESTION_ARROW = 92, + GDK_RIGHT_SIDE = 96, + GDK_SB_H_DOUBLE_ARROW = 108, + GDK_SB_V_DOUBLE_ARROW = 116, + GDK_TOP_LEFT_CORNER = 134, + GDK_TOP_RIGHT_CORNER = 136, + GDK_TOP_SIDE = 138, + GDK_WATCH = 150, + GDK_BLANK_CURSOR = -2, +} GdkCursorType; +typedef struct GtkFileFilterInfo +{ + // GtkFileFilterFlags contains; + + const gchar *filename; + const gchar *uri; + const gchar *display_name; + const gchar *mime_type; +} GtkFileFilterInfo; +typedef enum +{ + GTK_WINDOW_TOPLEVEL, + GTK_WINDOW_POPUP +} GtkWindowType; + +typedef struct GtkTargetEntry +{ + gchar *target; + guint flags; + guint info; +} GtkTargetEntry; +typedef enum +{ + GTK_DRAG_RESULT_SUCCESS, + GTK_DRAG_RESULT_NO_TARGET, + GTK_DRAG_RESULT_USER_CANCELLED, + GTK_DRAG_RESULT_TIMEOUT_EXPIRED, + GTK_DRAG_RESULT_GRAB_BROKEN, + GTK_DRAG_RESULT_ERROR +} GtkDragResult; +typedef enum { + GTK_TARGET_SAME_APP = 1 << 0, /*< nick=same-app >*/ + GTK_TARGET_SAME_WIDGET = 1 << 1, /*< nick=same-widget >*/ + GTK_TARGET_OTHER_APP = 1 << 2, /*< nick=other-app >*/ + GTK_TARGET_OTHER_WIDGET = 1 << 3 /*< nick=other-widget >*/ +} GtkTargetFlags; +typedef enum { + GTK_DEST_DEFAULT_MOTION = 1 << 0, + GTK_DEST_DEFAULT_HIGHLIGHT = 1 << 1, + GTK_DEST_DEFAULT_DROP = 1 << 2, + GTK_DEST_DEFAULT_ALL = 0x07 +} GtkDestDefaults; +typedef enum +{ + GDK_WINDOW_STATE_MAXIMIZED = 1 << 2, + GDK_WINDOW_STATE_FULLSCREEN = 1 << 4, + GDK_WINDOW_STATE_FOCUSED = 1 << 7, +} GdkWindowState; + +typedef struct GdkEventCrossing +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkWindow *subwindow; + guint32 time; + gdouble x; + gdouble y; + gdouble x_root; + gdouble y_root; + GdkCrossingMode mode; + GdkNotifyType detail; + gboolean focus; + guint state; +} GdkEventCrossing; +typedef struct GdkEventScroll +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + gdouble x; + gdouble y; + guint state; + GdkScrollDirection direction; + GdkDevice *device; + gdouble x_root, y_root; + gdouble delta_x; + gdouble delta_y; + guint is_stop : 1; +} GdkEventScroll; +typedef struct GdkEventKey +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + guint state; + guint keyval; + gint length; + gchar *string; + guint16 hardware_keycode; + guint8 group; + guint is_modifier : 1; +} GdkEventKey; +typedef struct GdkEventButton +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + gdouble x; + gdouble y; + gdouble *axes; + guint state; + guint button; + GdkDevice *device; + gdouble x_root, y_root; +} GdkEventButton; + +typedef struct GdkEventConfigure +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + gint x, y; + gint width; + gint height; +} GdkEventConfigure; +typedef struct GdkEventMotion +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + gdouble x; + gdouble y; + gdouble *axes; + guint state; + gint16 is_hint; + GdkDevice *device; + gdouble x_root, y_root; +} GdkEventMotion; +typedef struct GdkEventFocus +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + gint16 in; +} GdkEventFocus; +typedef struct GdkEventGrabBroken { + GdkEventType type; + GdkWindow *window; + gint8 send_event; + gboolean keyboard; + gboolean implicit; + GdkWindow *grab_window; +} GdkEventGrabBroken; +typedef struct GdkEventWindowState +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkWindowState changed_mask; + GdkWindowState new_window_state; +} GdkEventWindowState; + +typedef union GdkEventOld +{ + GdkEventType type; + // GdkEventAny any; + // GdkEventExpose expose; + // GdkEventVisibility visibility; + GdkEventMotion motion; + GdkEventButton button; + // GdkEventTouch touch; + GdkEventScroll scroll; + GdkEventKey key; + GdkEventCrossing crossing; + GdkEventFocus focus_change; + GdkEventConfigure configure; + // GdkEventProperty property; + // GdkEventSelection selection; + // GdkEventOwnerChange owner_change; + // GdkEventProximity proximity; + // GdkEventDND dnd; + GdkEventWindowState window_state; + // GdkEventSetting setting; + GdkEventGrabBroken grab_broken; + // GdkEventTouchpadSwipe touchpad_swipe; + // GdkEventTouchpadPinch touchpad_pinch; + // GdkEventPadButton pad_button; + // GdkEventPadAxis pad_axis; + // GdkEventPadGroupMode pad_group_mode; +} GdkEventOld; +#define GdkEvent GdkEventOld + +#define g_date_time_get_day_of_month(...) 0 +#define gdk_cairo_surface_create_from_pixbuf(...) NULL +#define gdk_cursor_new_from_surface(...) NULL +#define gdk_device_get_axis_use(...) 0 +#define gdk_device_get_mode(...) 0 +#define gdk_device_get_n_axes(...) 0 +#define gdk_device_get_n_keys(...) 0 +#define gdk_device_get_state(...) NULL +#define gdk_device_get_window_at_position(...) NULL +#define gdk_display_get_default_cursor_size(...) 0 +#define gdk_display_get_monitor_at_window(...) NULL +#define gdk_display_get_monitor(...) NULL +#define gdk_display_get_n_monitors(...) 1 +#define gdk_drag_status(...) +#define gdk_event_free(...) +#define gdk_event_get_axis(...) +#define gdk_event_get_keyval(...) +#define gdk_event_get_pointer_emulated(...) 0 +#define gdk_event_get_source_device(...) NULL +#define gdk_event_handler_set(...) +#define GDK_IS_WAYLAND_DISPLAY(...) 0 +#define gdk_keymap_get_entries_for_keyval(...) 0 +#define gdk_keymap_get_for_display(...) NULL +#define gdk_keymap_get_modifier_mask(...) 0 +#define gdk_keymap_get_modifier_state(...) 0 +#define gdk_keymap_translate_keyboard_state(...) 0 +#define gdk_monitor_get_workarea(...) +#define gdk_monitor_get_geometry(...) +#define gdk_property_get(...) +#define gdk_screen_get_default(...) NULL +#define gdk_screen_get_resolution(...) 0 +#define gdk_screen_get_rgba_visual(...) NULL +#define gdk_screen_set_resolution(...) +#define gdk_seat_get_slaves(...) NULL +#define gdk_seat_grab(...) +#define gdk_seat_ungrab(...) +#define gdk_threads_add_idle(...) +#define gdk_window_get_cursor(...) NULL +#define gdk_window_get_device_position(...) +#define gdk_window_get_display(...) NULL +#define gdk_window_get_height(...) 0 +#define gdk_window_get_origin(...) +#define gdk_window_get_state(...) 0 +#define gdk_window_get_toplevel(...) NULL +#define gdk_window_get_user_data(...) +#define gdk_window_get_width(...) 0 +#define gdk_window_move_to_rect(...) +#define gdk_window_move(...) +#define gdk_window_resize(...) +#define gdk_window_set_cursor(...) +#define gdk_window_set_transient_for(...) +#define gtk_box_query_child_packing(...) +#define gtk_box_set_center_widget(...) +#define gtk_button_box_set_child_non_homogeneous(...) +#define gtk_calendar_get_date(...) +#define gtk_calendar_mark_day(...) +#define gtk_calendar_select_month(...) +#define gtk_check_menu_item_get_active(...) 0 +#define gtk_check_menu_item_new_with_label(...) NULL +#define gtk_check_menu_item_set_active(...) +#define gtk_check_menu_item_set_inconsistent(...) +#define gtk_clipboard_set_text(...) +#define gtk_container_get_focus_child(...) NULL +#define gtk_container_set_border_width(...) +#define gtk_container_set_focus_child(...) +#define gtk_drag_begin_with_coordinates(...) NULL +#define gtk_drag_dest_set(...) +#define gtk_drag_dest_unset(...) +#define gtk_drag_finish(...) +#define gtk_drag_get_source_widget(...) NULL +#define gtk_drag_set_icon_pixbuf(...) +#define gtk_drag_set_icon_surface(...) +#define gtk_drag_set_icon_widget(...) +#define gtk_drag_source_set(...) +#define gtk_drag_source_unset(...) +#define gtk_entry_get_layout(...) NULL +#define gtk_entry_set_max_width_chars(...) +#define gtk_entry_set_width_chars(...) +#define gtk_event_box_set_visible_window(...) +#define gtk_file_chooser_add_filter(...) +#define gtk_file_chooser_button_set_title(...) +#define gtk_file_chooser_button_set_width_chars(...) +#define gtk_file_chooser_get_current_folder(...) NULL +#define gtk_file_chooser_get_filename(...) NULL +#define gtk_file_chooser_get_filenames(...) NULL +#define gtk_file_chooser_get_uri(...) NULL +#define gtk_file_chooser_select_filename(...) +#define gtk_file_chooser_set_current_folder(...) +#define gtk_file_chooser_set_current_folder(...) +#define gtk_file_chooser_set_current_name(...) +#define gtk_file_chooser_set_do_overwrite_confirmation(...) +#define gtk_file_chooser_set_extra_widget(...) +#define gtk_file_chooser_set_filename(...) +#define gtk_file_chooser_unselect_all(...) +#define gtk_file_filter_add_custom(...) +#define gtk_file_filter_add_pattern(...) +#define gtk_file_filter_set_name(...) +#define gtk_font_button_set_show_size(...) +#define gtk_get_event_widget(...) NULL +#define gtk_grab_add(...) +#define gtk_grab_remove(...) +#define gtk_header_bar_set_custom_title(...) +#define gtk_header_bar_set_has_subtitle(...) +#define gtk_header_bar_set_show_close_button(...) +#define gtk_icon_theme_append_search_path(...) +#define GTK_IS_CHECK_MENU_ITEM(...) 0 +#define gtk_main_do_event(...) +#define gtk_menu_item_get_label(...) NULL +#define gtk_menu_item_get_submenu(...) NULL +#define gtk_menu_item_new_with_label(...) NULL +#define gtk_menu_item_new_with_mnemonic(...) NULL +#define gtk_menu_item_set_submenu(...) +#define GTK_MENU_ITEM(...) NULL +#define gtk_menu_new(...) NULL +#define gtk_menu_popup_at_pointer(...) +#define gtk_menu_popup_at_widget(...) +#define gtk_menu_shell_append(...) +#define gtk_menu_shell_insert(...) +#define gtk_menu_shell_prepend(...) +#define GTK_MENU_SHELL(...) NULL +#define GTK_MENU(...) NULL +#define gtk_overlay_reorder_overlay(...) +#define gtk_overlay_set_overlay_pass_through(...) +#define gtk_parse_args(...) 0 +#define gtk_popover_get_default_widget(...) NULL +#define gtk_popover_get_relative_to(...) NULL +#define gtk_popover_set_modal(...) +#define gtk_popover_set_relative_to(...) +#define gtk_propagate_event(...) +#define gtk_scrolled_window_set_shadow_type(...) NULL +#define gtk_search_entry_handle_event(...) 0 +#define gtk_selection_data_get_data(...) NULL +#define gtk_selection_data_get_length(...) 0 +#define gtk_selection_data_set(...) +#define gtk_separator_menu_item_new(...) NULL +#define gtk_show_uri_on_window(...) 0 +#define gtk_style_context_get(...) +#define gtk_style_context_list_classes(...) NULL +#define gtk_style_context_set_path(...) +#define gtk_style_context_set_screen(...) +#define gtk_target_list_new(...) NULL +#define gtk_target_list_unref(...) +#define gtk_text_view_add_child_in_window(...) +#define gtk_text_view_im_context_filter_keypress(...) 0 +#define gtk_tooltip_trigger_tooltip_query(...) +#define gtk_tree_view_column_cell_get_size(...) +#define gtk_tree_view_create_row_drag_icon(...) NULL +#define gtk_tree_view_get_tooltip_context(...) 0 +#define gtk_tree_view_set_search_entry(...) +#define GTK_TYPE_CONTAINER(...) 0 +#define gtk_viewport_set_shadow_type(...) +#define gtk_widget_add_events(...) +#define gtk_widget_draw(...) +#define gtk_widget_event(...) 0 +#define gtk_widget_get_preferred_width(...) 0 +#define gtk_widget_get_screen(...) NULL +#define gtk_widget_get_tooltip_text(...) NULL +#define gtk_widget_get_toplevel(...) NULL +#define gtk_widget_get_window(...) NULL +#define gtk_widget_has_grab(...) 0 +#define gtk_widget_path_append_type(...) 0 +#define gtk_widget_path_free(...) +#define gtk_widget_path_iter_add_class(...) +#define gtk_widget_path_iter_add_class(...) +#define gtk_widget_path_new(...) NULL +#define gtk_widget_set_app_paintable(...) +#define gtk_widget_set_can_default(...) +#define gtk_widget_set_events(...) +#define gtk_widget_set_has_window(...) +#define gtk_widget_set_no_show_all(...) +#define gtk_widget_set_visual(...) +#define gtk_widget_size_allocate(...) +#define gtk_widget_style_get_property(...) +#define gtk_widget_translate_coordinates(...) +#define gtk_window_get_position(...) +#define gtk_window_get_size(...) +#define gtk_window_get_window_type(...) 0 +#define gtk_window_move(...) +#define gtk_window_resize(...) +#define gtk_window_set_attached_to(...) +#define gtk_window_set_gravity(...) +#define gtk_window_set_keep_above(...) +#define gtk_window_set_position(...) +#define gtk_window_set_type_hint(...) +#define gtk_window_set_urgency_hint(...) + +#define GDK_NONE NULL +#define GDK_2BUTTON_PRESS 0123 +#define GDK_3BUTTON_PRESS 0124 +#define GDK_WINDOW_STATE 0125 +#define GDK_DOUBLE_BUTTON_PRESS GDK_2BUTTON_PRESS +#define GDK_TRIPLE_BUTTON_PRESS GDK_3BUTTON_PRESS +#define GTK_SHADOW_NONE 0 +#define GDK_MOD1_MASK GDK_ALT_MASK +#define GDK_MOD2_MASK 0 +#define GDK_MOD5_MASK 0 +#define GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR 0 +#define GDK_SCROLL_MASK 0 +#define GDK_SMOOTH_SCROLL_MASK 0 + +typedef void (*GtkCallback)(GtkWidget *widget, gpointer data); +gulong dt_signal_connect_data_with_caller(gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + gpointer user_data, + GClosureNotify destroy_data, + GConnectFlags connect_flags, + gboolean gboolean_return, + const char *function, + const char *file, + const int line); + +#define g_signal_connect_data(instance, detailed_signal, c_handler, data, destroy, flags) \ + dt_signal_connect_data_with_caller((instance), (detailed_signal), (c_handler), (data), (destroy), (flags), \ + /*_Generic((DISABLINGPREFIX##c_handler), gboolean(*)() : TRUE, default: */FALSE, \ + __FUNCTION__, __FILE__, __LINE__) + +#define gtk_scrolled_window_new(...) gtk_scrolled_window_new() +#define gtk_window_new(...) gtk_window_new() + +#define gtk_style_context_get_border(context, state, border) gtk_style_context_get_border(context, border) +#define gtk_style_context_get_color(context, state, color) gtk_style_context_get_color(context, color) +#define gtk_style_context_get_margin(context, state, margin) gtk_style_context_get_margin(context, margin) +#define gtk_style_context_get_padding(context, state, padding) gtk_style_context_get_padding(context, padding) + +#define GTK_BIN(bin) (gpointer)bin +GtkWidget *gtk_bin_get_child(gpointer bin); +#define GTK_CONTAINER(container) (GtkContainer *)(container) +#define GTK_IS_CONTAINER(container) GTK_IS_WIDGET(container) +void gtk_container_add(GtkContainer *container, GtkWidget *child); +#define gtk_container_remove(container, child) gtk_widget_unparent(child) +GList *gtk_container_get_children(GtkContainer *container); +static inline void gtk_container_child_get(GtkContainer *box, GtkWidget *child, const char *property_name, int *value, ...) +{ + *value = 0; + for(GtkWidget *w = gtk_widget_get_first_child(GTK_WIDGET(box)); w && w != child; w = gtk_widget_get_next_sibling(w)) + (*value)++; +} +static inline void gtk_box_reorder_child(GtkBox *box, GtkWidget *child, int position) +{ + GtkWidget *sibling = NULL; + for(GtkWidget *w = gtk_widget_get_first_child(GTK_WIDGET(box)); w && position--; w = gtk_widget_get_next_sibling(w)) + sibling = w; + gtk_box_reorder_child_after(box, child, sibling); +} +static inline void gtk_container_foreach(GtkContainer *container, GtkCallback callback, gpointer user_data) +{ + for(GtkWidget *child = gtk_widget_get_first_child(GTK_WIDGET(container)); child; child = gtk_widget_get_next_sibling(child)) + callback(child, user_data); +} + +#define gtk_box_pack_end(box, child, expand, fill, padding) gtk_box_prepend(box, child) +#define gtk_box_pack_start(box, child, expand, fill, padding) gtk_box_append(box, child) +#define gtk_paned_pack1(paned, child, resize, shrink) gtk_paned_set_start_child(paned, child) +#define gtk_paned_pack2(paned, child, resize, shrink) gtk_paned_set_end_child(paned, child) +#define gtk_event_box_new(...) gtk_box_new(0,0) +#define GTK_IS_EVENT_BOX(widget) GTK_IS_BOX(widget) +#define GTK_EVENT_BOX(widget) GTK_BOX(widget) +#define GTK_LAYOUT GTK_FIXED +#define gtk_layout_new(...) gtk_fixed_new() +#define gtk_layout_move gtk_fixed_move +#define gtk_layout_put gtk_fixed_put + +#undef GTK_ENTRY +#define GTK_ENTRY (gpointer) +#define gtk_entry_get_text(entry) gtk_editable_get_text(GTK_EDITABLE(entry)) +#define gtk_entry_set_text(entry, text) gtk_editable_set_text(GTK_EDITABLE(entry), text) + +#undef GTK_TOGGLE_BUTTON +#define GTK_TOGGLE_BUTTON (gpointer) +#define gtk_toggle_button_get_active(button) (GTK_IS_CHECK_BUTTON(button) ? gtk_check_button_get_active(GTK_CHECK_BUTTON(button)) : gtk_toggle_button_get_active((GtkToggleButton *)(button))) +#define gtk_toggle_button_set_active(button, active) (GTK_IS_CHECK_BUTTON(button) ? gtk_check_button_set_active(GTK_CHECK_BUTTON(button), active) : gtk_toggle_button_set_active((GtkToggleButton *)(button), active)) + +#define gdk_cursor_new_from_name(display, name) gdk_cursor_new_from_name(name, NULL) +#define gtk_image_new_from_icon_name(name, size) gtk_image_new_from_icon_name(name) + +#define gdk_event_new(event_type) g_memdup(&(GdkEvent){.type = event_type}, sizeof(GdkEvent)) +#define gtk_button_clicked(button) g_signal_emit_by_name(button, "clicked") +#define gtk_file_chooser_button_new(...) gtk_button_new() +#define gtk_label_set_line_wrap gtk_label_set_wrap +#define gtk_popover_new(...) gtk_popover_new() +#define gtk_stack_set_homogeneous gtk_stack_set_vhomogeneous +#define gtk_widget_destroy(widget) GTK_IS_WINDOW(widget) ? gtk_window_destroy(GTK_WINDOW(widget)) : gtk_widget_unparent(widget) +#define gtk_get_current_event(...) (GdkEventOld[]){{GDK_KEY_PRESS}} +static void gtk_widget_destroyed(){}; +static void gtk_main_quit(){}; +static void gtk_main(){}; +static void gtk_widget_show_all(GtkWidget*w){gtk_widget_show(w);}; +int gtk_dialog_run(GtkDialog *dialog); +int gtk_native_dialog_run(GtkNativeDialog *dialog); + +// WIN32 +#define GDK_WINDOW_HWND(...) NULL +#define gdk_win32_window_get_handle(...) NULL +#define DwmSetWindowAttribute(...) 0 + G_END_DECLS // clang-format off diff --git a/src/control/control.c b/src/control/control.c index ca397e2831a1..452e4e6133d4 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -257,11 +257,33 @@ void dt_control_allow_change_cursor() void dt_control_change_cursor(dt_cursor_t curs) { - GdkWindow *window = gtk_widget_get_window(dt_ui_main_window(darktable.gui->ui)); + GtkWidget *window = dt_ui_main_window(darktable.gui->ui); if(!darktable.control->lock_cursor_shape && window) { - GdkCursor *cursor = gdk_cursor_new_for_display(gdk_window_get_display(window), curs); - gdk_window_set_cursor(window, cursor); + GdkCursor *cursor = gdk_cursor_new_from_name(gdk_window_get_display(window), + curs == GDK_X_CURSOR ? "crosshair" : + curs == GDK_BOTTOM_LEFT_CORNER ? "sw-resize" : + curs == GDK_BOTTOM_RIGHT_CORNER ? "se-resize" : + curs == GDK_BOTTOM_SIDE ? "s-resize" : + curs == GDK_CROSS ? "crosshair" : + curs == GDK_CROSSHAIR ? "crosshair" : + curs == GDK_FLEUR ? "move" : + curs == GDK_HAND1 ? "pointer" : + curs == GDK_LEFT_PTR ? "default" : + curs == GDK_LEFT_SIDE ? "w-resize" : + curs == GDK_PLUS ? "cell" : + curs == GDK_QUESTION_ARROW ? "help" : + curs == GDK_RIGHT_SIDE ? "e-resize" : + curs == GDK_SB_H_DOUBLE_ARROW ? "ew-resize" : + curs == GDK_SB_V_DOUBLE_ARROW ? "ns-resize" : + curs == GDK_TOP_LEFT_CORNER ? "nw-resize" : + curs == GDK_TOP_RIGHT_CORNER ? "ne-resize" : + curs == GDK_TOP_SIDE ? "n-resize" : + curs == GDK_WATCH ? "wait" : + curs == GDK_PIRATE ? NULL : // no direct equivalent + curs == GDK_BLANK_CURSOR ? NULL : // invisible + "default"); + gtk_widget_set_cursor(window, cursor); g_object_unref(cursor); } } @@ -285,7 +307,7 @@ void dt_control_change_cursor(dt_cursor_t curs) gboolean dt_control_running() { - return dt_atomic_get_int(&darktable.control->running) == DT_CONTROL_STATE_RUNNING; + return darktable.control && dt_atomic_get_int(&darktable.control->running) == DT_CONTROL_STATE_RUNNING; } void dt_control_quit() @@ -393,11 +415,12 @@ void dt_control_cleanup(const gboolean withgui) // ================================================================================ gboolean dt_control_configure(GtkWidget *da, - GdkEventConfigure *event, + gint width, + gint height, gpointer user_data) { // re-configure all components: - dt_view_manager_configure(darktable.view_manager, event->width, event->height); + dt_view_manager_configure(darktable.view_manager, width, height); return TRUE; } diff --git a/src/control/control.h b/src/control/control.h index d4a0c8e192f0..20899c57a925 100644 --- a/src/control/control.h +++ b/src/control/control.h @@ -53,7 +53,7 @@ void dt_control_button_released(double x, double y, int which, uint32_t state); void dt_control_mouse_moved(double x, double y, double pressure, int which); void dt_control_mouse_leave(void); void dt_control_mouse_enter(void); -gboolean dt_control_configure(GtkWidget *da, GdkEventConfigure *event, gpointer user_data); +gboolean dt_control_configure(GtkWidget *da, gint width, gint height, gpointer user_data); void dt_control_log(const char *msg, ...) __attribute__((format(printf, 1, 2))); void dt_toast_log(const char *msg, ...) __attribute__((format(printf, 1, 2))); void dt_toast_markup_log(const char *msg, ...) __attribute__((format(printf, 1, 2))); diff --git a/src/control/progress.c b/src/control/progress.c index bf301e40e704..39265f144bed 100644 --- a/src/control/progress.c +++ b/src/control/progress.c @@ -28,7 +28,7 @@ #endif #ifdef _WIN32 -#include +// #include #ifndef ITaskbarList3_SetProgressValue #define ITaskbarList3_SetProgressValue(This,hwnd,ullCompleted,ullTotal) (This)->lpVtbl->SetProgressValue(This,hwnd,ullCompleted,ullTotal) #endif diff --git a/src/develop/blend_gui.c b/src/develop/blend_gui.c index 6394bd0fc427..f8f1cd2f64a9 100644 --- a/src/develop/blend_gui.c +++ b/src/develop/blend_gui.c @@ -586,7 +586,7 @@ static void _add_wrapped_box(GtkWidget *container, gchar *help_url) { GtkWidget *event_box = gtk_event_box_new(); - GtkWidget *revealer = gtk_revealer_new(); + GtkWidget *revealer = dt_gui_expand(gtk_revealer_new()); gtk_container_add(GTK_CONTAINER(revealer), GTK_WIDGET(box)); gtk_container_add(GTK_CONTAINER(event_box), revealer); gtk_container_add(GTK_CONTAINER(container), event_box); @@ -602,7 +602,7 @@ static void _box_set_visible(GtkBox *box, gboolean visible) GtkRevealer *revealer = GTK_REVEALER(gtk_widget_get_parent(GTK_WIDGET(box))); gtk_revealer_set_transition_duration(revealer, dt_conf_get_int("darkroom/ui/transition_duration")); - gtk_revealer_set_reveal_child(revealer, visible); + gtk_revealer_set_reveal_child(revealer, TRUE);//GTK4 visible); } static void _blendop_masks_mode_callback(const dt_develop_mask_mode_t mask_mode, @@ -796,6 +796,7 @@ static void _blendop_masks_combine_callback(GtkWidget *combo, static void _blendop_blendif_highlight_changed_tabs(dt_iop_module_t *module) { +return; // GTK4 disabled for now dt_iop_gui_blend_data_t *bd = module->blend_data; dt_develop_blend_params_t *bp = module->blend_params; dt_develop_blend_params_t *dp = module->default_blendop_params; @@ -2522,7 +2523,8 @@ void dt_iop_gui_update_blendif(dt_iop_module_t *module) dt_iop_color_picker_reset(module, TRUE); /* remove tabs before adding others */ - dt_gui_container_destroy_children(GTK_CONTAINER(bd->channel_tabs)); + while(gtk_notebook_get_n_pages(bd->channel_tabs) > 0) + gtk_notebook_remove_page(bd->channel_tabs, 0); bd->channel_tabs_csp = bd->csp; diff --git a/src/develop/imageop.c b/src/develop/imageop.c index 67a1bc1c8e8e..8fd4d994598f 100644 --- a/src/develop/imageop.c +++ b/src/develop/imageop.c @@ -39,7 +39,6 @@ #include "dtgtk/button.h" #include "dtgtk/expander.h" #include "dtgtk/gradientslider.h" -#include "dtgtk/icon.h" #include "gui/accelerators.h" #include "gui/color_picker_proxy.h" #include "gui/drag_and_drop.h" @@ -455,19 +454,23 @@ static gboolean _header_enter_notify_callback(GtkWidget *eventbox, return FALSE; } -static gboolean _header_motion_notify_show_callback(GtkWidget *eventbox, - GdkEventCrossing *event, - dt_iop_module_t *module) +static void _header_motion_notify_show_callback + (GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *module) { + GdkEventCrossing *event = NULL; // GTK4 darktable.control->element = DT_ACTION_ELEMENT_SHOW; - return dt_iop_show_hide_header_buttons(module, event, TRUE, FALSE); + dt_iop_show_hide_header_buttons(module, event, TRUE, FALSE); } -static gboolean _header_motion_notify_hide_callback(GtkWidget *eventbox, - GdkEventCrossing *event, - dt_iop_module_t *module) +static void _header_motion_notify_hide_callback + (GtkEventControllerMotion *controller, + dt_iop_module_t *module) { - return dt_iop_show_hide_header_buttons(module, event, FALSE, FALSE); + GdkEventCrossing *event = NULL; // GTK4 + dt_iop_show_hide_header_buttons(module, event, FALSE, FALSE); } static void _header_menu_deactivate_callback(GtkMenuShell *menushell, @@ -640,16 +643,15 @@ static void _gui_movedown_callback(GtkButton *button, dt_iop_module_t *module) if(!moved) return; // we move the headers - GValue gv = { 0, { { 0 } } }; - g_value_init(&gv, G_TYPE_INT); - gtk_container_child_get_property( + int position = 0; + gtk_container_child_get( GTK_CONTAINER(dt_ui_get_container(darktable.gui->ui, DT_UI_CONTAINER_PANEL_RIGHT_CENTER)), prev->expander, - "position", &gv); + "position", &position, NULL); gtk_box_reorder_child(dt_ui_get_container(darktable.gui->ui, DT_UI_CONTAINER_PANEL_RIGHT_CENTER), - module->expander, g_value_get_int(&gv)); + module->expander, position); dt_dev_add_history_item(prev->dev, module, TRUE); @@ -675,17 +677,15 @@ static void _gui_moveup_callback(GtkButton *button, dt_iop_module_t *module) if(!moved) return; // we move the headers - GValue gv = { 0, { { 0 } } }; - g_value_init(&gv, G_TYPE_INT); - gtk_container_child_get_property( + int position = 0; + gtk_container_child_get( GTK_CONTAINER(dt_ui_get_container(darktable.gui->ui, DT_UI_CONTAINER_PANEL_RIGHT_CENTER)), next->expander, - "position", &gv); - + "position", &position, NULL); gtk_box_reorder_child(dt_ui_get_container(darktable.gui->ui, DT_UI_CONTAINER_PANEL_RIGHT_CENTER), - module->expander, g_value_get_int(&gv)); + module->expander, position); dt_dev_add_history_item(next->dev, module, TRUE); @@ -737,16 +737,15 @@ dt_iop_module_t *dt_iop_gui_duplicate(dt_iop_module_t *base, /* add module to right panel */ dt_iop_gui_set_expander(module); - GValue gv = { 0, { { 0 } } }; - g_value_init(&gv, G_TYPE_INT); - gtk_container_child_get_property( + int position = 0; + gtk_container_child_get( GTK_CONTAINER(dt_ui_get_container(darktable.gui->ui, DT_UI_CONTAINER_PANEL_RIGHT_CENTER)), - base->expander, "position", &gv); + base->expander, "position", &position, NULL); gtk_box_reorder_child(dt_ui_get_container(darktable.gui->ui, DT_UI_CONTAINER_PANEL_RIGHT_CENTER), module->expander, - g_value_get_int(&gv) + pos_base - pos_module + 1); + position + pos_base - pos_module + 1); dt_iop_gui_set_expanded(module, TRUE, FALSE); dt_iop_reload_defaults(module); // some modules like profiled @@ -1281,6 +1280,7 @@ void dt_iop_gui_init(dt_iop_module_t *module) --darktable.bauhaus->skip_accel; dt_pthread_mutex_init(&module->gui_lock, NULL); if(module->gui_init) module->gui_init(module); + if(module->widget) g_object_ref(module->widget); ++darktable.bauhaus->skip_accel; --darktable.gui->reset; } @@ -2209,7 +2209,12 @@ void dt_iop_gui_cleanup_module(dt_iop_module_t *module) module->widget_list = NULL; DT_CONTROL_SIGNAL_DISCONNECT_ALL(module, module->so->op); if(module->gui_cleanup) module->gui_cleanup(module); - gtk_widget_destroy(module->expander ? module->expander : module->widget); + GtkWidget *top = module->expander ? module->expander : module->widget; + GtkWidget *parent = gtk_widget_get_parent(top); + if(parent) + gtk_box_remove(GTK_BOX(parent), top); + else + g_object_unref(top); dt_iop_gui_cleanup_blending(module); dt_pthread_mutex_destroy(&module->gui_lock); dt_free_align(module->gui_data); @@ -2529,48 +2534,45 @@ void dt_iop_gui_update_expanded(dt_iop_module_t *module) dtgtk_expander_set_expanded(DTGTK_EXPANDER(module->expander), expanded); } -static gboolean _iop_plugin_body_button_press(GtkWidget *w, - GdkEventButton *e, - gpointer user_data) +static void _iop_plugin_body_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *module) { - dt_iop_module_t *module = (dt_iop_module_t *)user_data; - if(e->button == GDK_BUTTON_PRIMARY) - { + guint button = gtk_gesture_single_get_current_button(gesture); + if(button == GDK_BUTTON_PRIMARY) dt_iop_request_focus(module); - return TRUE; - } - else if(e->button == GDK_BUTTON_SECONDARY) - { + else if(button == GDK_BUTTON_SECONDARY) _presets_popup_callback(NULL, NULL, module); - return TRUE; - } - return FALSE; + dt_gui_claim(gesture); } -static gboolean _iop_plugin_header_button_release(GtkWidget *w, - GdkEventButton *e, - gpointer user_data) +static void _iop_plugin_header_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *module) { - if(e->type == GDK_2BUTTON_PRESS || e->type == GDK_3BUTTON_PRESS) return TRUE; - if(GTK_IS_BUTTON(gtk_get_event_widget((GdkEvent*)e))) return FALSE; - - dt_iop_module_t *module = (dt_iop_module_t *)user_data; + if(n_press > 1) return; - if(e->button == GDK_BUTTON_PRIMARY) + guint button = gtk_gesture_single_get_current_button(gesture); + if(button == GDK_BUTTON_PRIMARY) { - if(dt_modifier_is(e->state, GDK_SHIFT_MASK | GDK_CONTROL_MASK)) + if(dt_modifier_eq(gesture, GDK_SHIFT_MASK | GDK_CONTROL_MASK)) ; // do nothing (for easier dragging) - else if(dt_modifier_is(e->state, GDK_CONTROL_MASK)) + else if(dt_modifier_eq(gesture, GDK_CONTROL_MASK)) { dt_iop_gui_rename_module(module); - return TRUE; + dt_gui_claim(gesture); + return; } else { const gboolean collapse_others = !dt_conf_get_bool("darkroom/ui/single_module") - != (!dt_modifier_is(e->state, GDK_SHIFT_MASK)); + != (!dt_modifier_eq(gesture, GDK_SHIFT_MASK)); dt_iop_gui_set_expanded(module, !module->expanded, collapse_others); @@ -2580,16 +2582,17 @@ static gboolean _iop_plugin_header_button_release(GtkWidget *w, //used to take focus away from module search text input box when module selected gtk_widget_grab_focus(dt_ui_center(darktable.gui->ui)); - return TRUE; + dt_gui_claim(gesture); + return; } } - else if(e->button == GDK_BUTTON_SECONDARY) + else if(button == GDK_BUTTON_SECONDARY) { _presets_popup_callback(NULL, NULL, module); - return TRUE; + dt_gui_claim(gesture); + return; } - return FALSE; } static void _header_size_callback(GtkWidget *widget, @@ -2733,7 +2736,7 @@ gboolean dt_iop_show_hide_header_buttons(dt_iop_module_t *module, gtk_widget_set_visible(GTK_WIDGET(button->data), show_buttons && !always_hide && !disabled); gtk_widget_set_opacity(GTK_WIDGET(button->data), opacity); } - if(GTK_IS_DRAWING_AREA(button->data)) + if(button && GTK_IS_DRAWING_AREA(button->data)) { // temporarily or permanently (de)activate width trigger widget if(dynamic) @@ -2867,14 +2870,13 @@ void dt_iop_add_remove_mask_indicator(dt_iop_module_t *module, gboolean add) child && GTK_IS_BUTTON(child->data); child = g_list_previous(child)); - if(GTK_IS_DRAWING_AREA(child->data)) + if(child && GTK_IS_DRAWING_AREA(child->data)) // GTK4 { - GValue position = G_VALUE_INIT; - g_value_init (&position, G_TYPE_INT); - gtk_container_child_get_property(GTK_CONTAINER(module->header), - child->data ,"position", &position); + int position = 0; + gtk_container_child_get(GTK_CONTAINER(module->header), + child->data ,"position", &position, NULL); gtk_box_reorder_child(GTK_BOX(module->header), module->mask_indicator, - g_value_get_int(&position)); + position); } g_list_free(children); @@ -2982,7 +2984,7 @@ GtkWidget *dt_iop_gui_header_button(dt_iop_module_t *module, gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), module->enabled); g_signal_connect(button, "toggled", G_CALLBACK(_gui_off_callback), module); - gtk_box_pack_start(GTK_BOX(header), button, FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(header), button, FALSE, FALSE, 0); } else { @@ -3118,26 +3120,17 @@ void dt_iop_gui_set_expander(dt_iop_module_t *module) gtk_drag_dest_set(expander, GTK_DEST_DEFAULT_DROP | GTK_DEST_DEFAULT_HIGHLIGHT, target_list, 1, GDK_ACTION_COPY); g_signal_connect(expander, "drag-motion", G_CALLBACK(_on_drag_motion), module); g_signal_connect(expander, "drag-drop", G_CALLBACK(_on_drag_drop), module); - module->header = header; /* setup the header box */ - g_signal_connect(G_OBJECT(header_evb), "button-release-event", - G_CALLBACK(_iop_plugin_header_button_release), module); - gtk_widget_add_events(header_evb, GDK_POINTER_MOTION_MASK); - g_signal_connect(G_OBJECT(header_evb), "enter-notify-event", - G_CALLBACK(_header_motion_notify_show_callback), module); - g_signal_connect(G_OBJECT(header_evb), "leave-notify-event", - G_CALLBACK(_header_motion_notify_hide_callback), module); + dt_gui_connect_click_all(header_evb, _iop_plugin_header_button_press, NULL, module); + dt_gui_connect_motion(header_evb, NULL, _header_motion_notify_show_callback, + _header_motion_notify_hide_callback, module); /* connect mouse button callbacks for focus and presets */ - g_signal_connect(G_OBJECT(body_evb), "button-press-event", - G_CALLBACK(_iop_plugin_body_button_press), module); - gtk_widget_add_events(body_evb, GDK_POINTER_MOTION_MASK); - g_signal_connect(G_OBJECT(body_evb), "enter-notify-event", - G_CALLBACK(_header_motion_notify_show_callback), module); - g_signal_connect(G_OBJECT(body_evb), "leave-notify-event", - G_CALLBACK(_header_motion_notify_hide_callback), module); + dt_gui_connect_click_all(body_evb, _iop_plugin_body_button_press, NULL, module); + dt_gui_connect_motion(body_evb, NULL, _header_motion_notify_show_callback, + _header_motion_notify_hide_callback, module); /* * initialize the header widgets @@ -3204,6 +3197,10 @@ void dt_iop_gui_set_expander(dt_iop_module_t *module) gtk_widget_set_tooltip_text(module->presets_button, _("presets\nright-click to apply on new instance")); + gtk_box_prepend(GTK_BOX(header), dt_gui_expand(module->instance_name)); + gtk_box_prepend(GTK_BOX(header), lab); + gtk_box_prepend(GTK_BOX(header), icon); + /* add enabled button */ module->off = dt_iop_gui_header_button(module, dtgtk_cairo_paint_switch, @@ -3213,10 +3210,6 @@ void dt_iop_gui_set_expander(dt_iop_module_t *module) dt_iop_gui_set_enable_button_icon(module->off, module); gtk_widget_set_sensitive(module->off, !module->hide_enable_button); - gtk_box_pack_start(GTK_BOX(header), icon, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(header), lab, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(header), module->instance_name, FALSE, FALSE, 0); - dt_gui_add_help_link(lab, module->op); dt_gui_add_help_link(expander, module->op); dt_gui_add_help_link(header, "module_header"); @@ -3246,7 +3239,7 @@ void dt_iop_gui_set_expander(dt_iop_module_t *module) /* update header */ dt_iop_gui_update_header(module); - gtk_widget_set_hexpand(module->widget, FALSE); + // gtk_widget_set_hexpand(module->widget, FALSE);// GTK4 gtk_widget_set_vexpand(module->widget, FALSE); gtk_widget_show_all(expander); diff --git a/src/develop/imageop_gui.c b/src/develop/imageop_gui.c index 1b11d6e1d29d..42c2efaadcc7 100644 --- a/src/develop/imageop_gui.c +++ b/src/develop/imageop_gui.c @@ -280,7 +280,13 @@ GtkWidget *dt_iop_togglebutton_new(dt_iop_module_t *self, const char *section, c } gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), FALSE); - if(GTK_IS_BOX(box)) gtk_box_pack_end(GTK_BOX(box), w, FALSE, FALSE, 0); + if(GTK_IS_BOX(box)) + { + GtkWidget *other = gtk_widget_get_last_child(box); + for(; other; other = gtk_widget_get_prev_sibling(other)) + if(!GTK_IS_BUTTON(other)) break; + gtk_box_insert_child_after(GTK_BOX(box), w, other); + } dt_action_define_iop(self, section, label, w, &dt_action_def_toggle); diff --git a/src/dtgtk/button.c b/src/dtgtk/button.c index 500479f586bc..bac3569760e7 100644 --- a/src/dtgtk/button.c +++ b/src/dtgtk/button.c @@ -27,10 +27,15 @@ static void dtgtk_button_init(GtkDarktableButton *button) { } -static gboolean _button_draw(GtkWidget *widget, cairo_t *cr) +static void _button_snapshot(GtkWidget* widget, + GtkSnapshot* snapshot) { - g_return_val_if_fail(widget != NULL, FALSE); - g_return_val_if_fail(DTGTK_IS_BUTTON(widget), FALSE); + g_return_if_fail(widget != NULL); + g_return_if_fail(DTGTK_IS_BUTTON(widget)); + + graphene_rect_t bounds; + graphene_rect_init(&bounds, 0, 0, gtk_widget_get_width(widget), gtk_widget_get_height(widget)); + cairo_t* cr = gtk_snapshot_append_cairo(snapshot, &bounds); GtkStateFlags state = gtk_widget_get_state_flags(widget); @@ -100,14 +105,15 @@ static gboolean _button_draw(GtkWidget *widget, cairo_t *cr) DTGTK_BUTTON(widget)->icon(cr, startx, starty, cwidth, cheight, flags, icon_data); } - return FALSE; + cairo_destroy(cr); } +static guint _button_press_signal = 0; + static void dtgtk_button_class_init(GtkDarktableButtonClass *klass) { GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; - - widget_class->draw = _button_draw; + widget_class->snapshot = _button_snapshot; } // Public functions diff --git a/src/dtgtk/drawingarea.c b/src/dtgtk/drawingarea.c index 7ba98fecb8d7..25af8c25a826 100644 --- a/src/dtgtk/drawingarea.c +++ b/src/dtgtk/drawingarea.c @@ -17,41 +17,78 @@ */ #include "dtgtk/drawingarea.h" +#include "common/darktable.h" +#include "gui/gtk.h" G_DEFINE_TYPE(GtkDarktableDrawingArea, dtgtk_drawing_area, GTK_TYPE_DRAWING_AREA); -static GtkSizeRequestMode dtgtk_drawing_area_get_request_mode(GtkWidget *widget) +static GtkSizeRequestMode _widget_get_request_mode(GtkWidget *widget) { return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; }; -static void dtgtk_drawing_area_get_preferred_height_for_width(GtkWidget *widget, gint for_width, - gint *min_height, gint *nat_height) +static void _widget_measure(GtkWidget* widget, + GtkOrientation orientation, + int for_size, + int* minimum, + int* natural, + int* minimum_baseline, + int* natural_baseline) { - GtkDarktableDrawingArea *da = DTGTK_DRAWING_AREA(widget); - - if(da->height == 0) - { - // initialize with height = width - *min_height = *nat_height = for_width; - } - else if(da->height == -1) - { - // initialize with aspect ratio - *min_height = *nat_height = for_width * da->aspect; - } - else + if(orientation == GTK_ORIENTATION_VERTICAL) { - *min_height = *nat_height = da->height; + GtkDarktableDrawingArea *da = DTGTK_DRAWING_AREA(widget); + + if(da->height == 0) + { + // initialize with height = width + *minimum = *natural = for_size; + } + else if(da->height == -1) + { + // initialize with aspect ratio + *minimum = *natural = -1; // for_size * da->aspect; + } + else + { + *minimum = *natural = da->height; + } } } +static guint _drawing_area_draw_signal = 0; + +static void _widget_snapshot(GtkWidget* widget, + GtkSnapshot* snapshot) +{ + graphene_rect_t bounds; + graphene_rect_init(&bounds, 0, 0, gtk_widget_get_width(widget), gtk_widget_get_height(widget)); + cairo_t* cr = gtk_snapshot_append_cairo(snapshot, &bounds); + + g_signal_emit(widget, _drawing_area_draw_signal, 0, cr); + + cairo_destroy(cr); + + dt_gui_draw_resize_handle(widget, snapshot, &bounds); +} + static void dtgtk_drawing_area_class_init(GtkDarktableDrawingAreaClass *class) { GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class); - widget_class->get_request_mode = dtgtk_drawing_area_get_request_mode; - widget_class->get_preferred_height_for_width = dtgtk_drawing_area_get_preferred_height_for_width; + widget_class->get_request_mode = _widget_get_request_mode; + widget_class->measure = _widget_measure; + widget_class->snapshot = _widget_snapshot; + + _drawing_area_draw_signal = + g_signal_new ("draw", + G_TYPE_FROM_CLASS(class), + G_SIGNAL_RUN_LAST, + 0, // class offset + NULL, NULL, // accumulator, data + g_cclosure_marshal_VOID__POINTER, // marshaller + G_TYPE_NONE, 1, // return type + G_TYPE_POINTER); // parameter: cairo_t* } static void dtgtk_drawing_area_init(GtkDarktableDrawingArea *da) @@ -59,6 +96,17 @@ static void dtgtk_drawing_area_init(GtkDarktableDrawingArea *da) } // public functions +GtkWidget *dtgtk_drawing_area_new(void) +{ + GtkDarktableDrawingArea *da; + da = g_object_new(dtgtk_drawing_area_get_type(), NULL); + da->aspect = 1.0f; // square by default + da->height = -1; + + return (GtkWidget *)da; +} + + GtkWidget *dtgtk_drawing_area_new_with_aspect_ratio(double aspect) { GtkDarktableDrawingArea *da; diff --git a/src/dtgtk/drawingarea.h b/src/dtgtk/drawingarea.h index 9425aa0b1fce..0dffbea31e06 100644 --- a/src/dtgtk/drawingarea.h +++ b/src/dtgtk/drawingarea.h @@ -45,11 +45,14 @@ struct _GtkDarktableDrawingArea GType dtgtk_drawing_area_get_type(void); +GtkWidget *dtgtk_drawing_area_new(void); GtkWidget *dtgtk_drawing_area_new_with_aspect_ratio(double aspect); GtkWidget *dtgtk_drawing_area_new_with_height(int height); void dtgtk_drawing_area_set_aspect_ratio(GtkWidget *w, double aspect); void dtgtk_drawing_area_set_height(GtkWidget *w, int height); +#define gtk_drawing_area_new dtgtk_drawing_area_new + G_END_DECLS // clang-format off diff --git a/src/dtgtk/expander.c b/src/dtgtk/expander.c index 543816e38e83..16ffba40cce2 100644 --- a/src/dtgtk/expander.c +++ b/src/dtgtk/expander.c @@ -272,24 +272,22 @@ GtkWidget *dtgtk_expander_new(GtkWidget *header, GtkWidget *body) expander->body = body; expander->header_evb = gtk_event_box_new(); - gtk_container_add(GTK_CONTAINER(expander->header_evb), expander->header); + dt_gui_box_add(expander->header_evb, expander->header); expander->body_evb = gtk_event_box_new(); if(expander->body) - gtk_container_add(GTK_CONTAINER(expander->body_evb), expander->body); + dt_gui_box_add(expander->body_evb, dt_gui_expand(expander->body)); GtkWidget *frame = gtk_frame_new(NULL); - gtk_container_add(GTK_CONTAINER(frame), expander->body_evb); + gtk_frame_set_child(GTK_FRAME(frame), expander->body_evb); expander->frame = gtk_revealer_new(); gtk_revealer_set_transition_duration(GTK_REVEALER(expander->frame), 0); gtk_revealer_set_reveal_child(GTK_REVEALER(expander->frame), TRUE); - gtk_container_add(GTK_CONTAINER(expander->frame), frame); + gtk_revealer_set_child(GTK_REVEALER(expander->frame), frame); dt_gui_box_add(expander, expander->header_evb, expander->frame); - g_signal_connect(expander->header_evb, "drag-begin", G_CALLBACK(_expander_drag_begin), NULL); g_signal_connect(expander->header_evb, "drag-end", G_CALLBACK(_expander_drag_end), NULL); g_signal_connect(expander, "drag-leave", G_CALLBACK(_expander_drag_leave), NULL); g_signal_connect(expander, "size-allocate", G_CALLBACK(_expander_resize), frame); - return GTK_WIDGET(expander); } diff --git a/src/dtgtk/gradientslider.c b/src/dtgtk/gradientslider.c index 2fb341c6f2d2..542b613b5f44 100644 --- a/src/dtgtk/gradientslider.c +++ b/src/dtgtk/gradientslider.c @@ -42,7 +42,7 @@ static void _gradient_slider_get_preferred_height(GtkWidget *widget, static void _gradient_slider_get_preferred_width(GtkWidget *widget, gint *min_width, gint *nat_width); -static gboolean _gradient_slider_draw(GtkWidget *widget, cairo_t *cr); +static void _gradient_slider_snapshot(GtkWidget *widget, GtkSnapshot *snapshot); static void _gradient_slider_destroy(GtkWidget *widget); // Events @@ -478,19 +478,19 @@ static gboolean _gradient_slider_key_press_event(GtkWidget *widget, static void _gradient_slider_class_init(GtkDarktableGradientSliderClass *klass) { GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; - - widget_class->get_preferred_height = _gradient_slider_get_preferred_height; - widget_class->get_preferred_width = _gradient_slider_get_preferred_width; - widget_class->draw = _gradient_slider_draw; - widget_class->destroy = _gradient_slider_destroy; - - widget_class->enter_notify_event = _gradient_slider_enter_notify_event; - widget_class->leave_notify_event = _gradient_slider_leave_notify_event; - widget_class->button_press_event = _gradient_slider_button_press; - widget_class->button_release_event = _gradient_slider_button_release; - widget_class->motion_notify_event = _gradient_slider_motion_notify; - widget_class->scroll_event = _gradient_slider_scroll_event; - widget_class->key_press_event = _gradient_slider_key_press_event; + widget_class->snapshot = _gradient_slider_snapshot; + // widget_class->get_preferred_height = _gradient_slider_get_preferred_height; + // widget_class->get_preferred_width = _gradient_slider_get_preferred_width; + // widget_class->draw = _gradient_slider_draw; + // widget_class->destroy = _gradient_slider_destroy; + + // widget_class->enter_notify_event = _gradient_slider_enter_notify_event; + // widget_class->leave_notify_event = _gradient_slider_leave_notify_event; + // widget_class->button_press_event = _gradient_slider_button_press; + // widget_class->button_release_event = _gradient_slider_button_release; + // widget_class->motion_notify_event = _gradient_slider_motion_notify; + // widget_class->scroll_event = _gradient_slider_scroll_event; + // widget_class->key_press_event = _gradient_slider_key_press_event; _signals[VALUE_CHANGED] = g_signal_new("value-changed", G_TYPE_FROM_CLASS(klass), @@ -581,15 +581,19 @@ static void _gradient_slider_destroy(GtkWidget *widget) gslider->colors = NULL; - GTK_WIDGET_CLASS(parent_class)->destroy(widget); + // GTK_WIDGET_CLASS(parent_class)->destroy(widget); } -static gboolean _gradient_slider_draw(GtkWidget *widget, - cairo_t *cr) +static void _gradient_slider_snapshot(GtkWidget *widget, + GtkSnapshot *snapshot) { - g_return_val_if_fail(DTGTK_IS_GRADIENT_SLIDER(widget), FALSE); + g_return_if_fail(DTGTK_IS_GRADIENT_SLIDER(widget)); GtkDarktableGradientSlider *gslider = DTGTK_GRADIENT_SLIDER(widget); + graphene_rect_t bounds; + graphene_rect_init(&bounds, 0, 0, gtk_widget_get_width(widget), gtk_widget_get_height(widget)); + cairo_t* cr = gtk_snapshot_append_cairo(snapshot, &bounds); + assert(gslider->position > 0); GtkStyleContext *context = gtk_widget_get_style_context(widget); @@ -699,7 +703,7 @@ static gboolean _gradient_slider_draw(GtkWidget *widget, } } - return FALSE; + cairo_destroy(cr); } gint _list_find_by_position(gconstpointer a, gconstpointer b) diff --git a/src/dtgtk/icon.c b/src/dtgtk/icon.c deleted file mode 100644 index 049cbd34a892..000000000000 --- a/src/dtgtk/icon.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - This file is part of darktable, - Copyright (C) 2011-2020 darktable developers. - - darktable is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - darktable is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with darktable. If not, see . -*/ -#include "icon.h" -#include "gui/gtk.h" -#include - -G_DEFINE_TYPE(GtkDarktableIcon, dtgtk_icon, GTK_TYPE_EVENT_BOX); - -static gboolean _icon_draw(GtkWidget *widget, cairo_t *cr); - -static void dtgtk_icon_class_init(GtkDarktableIconClass *klass) -{ - GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; - widget_class->draw = _icon_draw; -} - -static void dtgtk_icon_init(GtkDarktableIcon *icon) -{ -} - -static gboolean _icon_draw(GtkWidget *widget, cairo_t *cr) -{ - g_return_val_if_fail(widget != NULL, FALSE); - g_return_val_if_fail(DTGTK_IS_ICON(widget), FALSE); - - /* begin cairo drawing */ - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - - GtkStateFlags state = gtk_widget_get_state_flags(widget); - - GdkRGBA fg_color; - GtkStyleContext *context = gtk_widget_get_style_context(widget); - gtk_style_context_get_color(context, state, &fg_color); - - gdk_cairo_set_source_rgba(cr, &fg_color); - - /* draw icon */ - if(DTGTK_ICON(widget)->icon) - DTGTK_ICON(widget)->icon(cr, 0, 0, allocation.width, allocation.height, DTGTK_ICON(widget)->icon_flags, - DTGTK_ICON(widget)->icon_data); - - return FALSE; -} - -// Public functions -GtkWidget *dtgtk_icon_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata) -{ - GtkDarktableIcon *icon; - icon = g_object_new(dtgtk_icon_get_type(), NULL); - gtk_event_box_set_visible_window(GTK_EVENT_BOX(icon), FALSE); - icon->icon = paint; - icon->icon_flags = paintflags; - icon->icon_data = paintdata; - gtk_widget_set_name(GTK_WIDGET(icon), "dt-icon"); - return (GtkWidget *)icon; -} - -void dtgtk_icon_set_paint(GtkWidget *icon, DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata) -{ - g_return_if_fail(icon != NULL); - DTGTK_ICON(icon)->icon = paint; - DTGTK_ICON(icon)->icon_flags = paintflags; - DTGTK_ICON(icon)->icon_data = paintdata; - gtk_widget_queue_draw(icon); -} - -// clang-format off -// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py -// vim: shiftwidth=2 expandtab tabstop=2 cindent -// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified; -// clang-format on - diff --git a/src/dtgtk/icon.h b/src/dtgtk/icon.h deleted file mode 100644 index 3922c5d9149d..000000000000 --- a/src/dtgtk/icon.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - This file is part of darktable, - Copyright (C) 2011-2020 darktable developers. - - darktable is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - darktable is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with darktable. If not, see . -*/ - -#pragma once - -#include "paint.h" -#include - -G_BEGIN_DECLS - -#define DTGTK_TYPE_ICON dtgtk_icon_get_type() -G_DECLARE_FINAL_TYPE(GtkDarktableIcon, dtgtk_icon, DTGTK, ICON, GtkEventBox) - -struct _GtkDarktableIcon -{ - GtkEventBox widget; - DTGTKCairoPaintIconFunc icon; - gint icon_flags; - void *icon_data; -}; - -/** instantiate a new darktable icon control passing paint function as content */ -GtkWidget *dtgtk_icon_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata); - -/** set the paint function for a icon */ -void dtgtk_icon_set_paint(GtkWidget *icon, DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata); - -G_END_DECLS - -// clang-format off -// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py -// vim: shiftwidth=2 expandtab tabstop=2 cindent -// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified; -// clang-format on - diff --git a/src/dtgtk/range.c b/src/dtgtk/range.c index 4fae45590752..7d28097e4e9a 100644 --- a/src/dtgtk/range.c +++ b/src/dtgtk/range.c @@ -19,6 +19,7 @@ #include "bauhaus/bauhaus.h" #include "control/control.h" #include "gui/gtk.h" +#include "dtgtk/drawingarea.h" #include #include @@ -27,7 +28,7 @@ #define BAR_WIDTH 4 // define GTypes -G_DEFINE_TYPE(GtkDarktableRangeSelect, dtgtk_range_select, GTK_TYPE_EVENT_BOX); +G_DEFINE_TYPE(GtkDarktableRangeSelect, dtgtk_range_select, GTK_TYPE_BOX); typedef struct _range_date_popup { @@ -171,13 +172,13 @@ static void _range_select_destroy(GtkWidget *widget) g_free(range->cur_help); range->cur_help = NULL; - GTK_WIDGET_CLASS(dtgtk_range_select_parent_class)->destroy(widget); + // GTK_WIDGET_CLASS(dtgtk_range_select_parent_class)->destroy(widget); } static void dtgtk_range_select_class_init(GtkDarktableRangeSelectClass *klass) { GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; - widget_class->destroy = _range_select_destroy; + // widget_class->destroy = _range_select_destroy; _signals[VALUE_CHANGED] = g_signal_new("value-changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); @@ -618,7 +619,7 @@ static void _current_show_popup(GtkDarktableRangeSelect *range) gtk_label_set_xalign(GTK_LABEL(lb), 0.0); if(range->cur_help) gtk_label_set_markup(GTK_LABEL(lb), range->cur_help); gtk_container_add(GTK_CONTAINER(range->cur_window), dt_gui_vbox(range->cur_label, lb)); - gtk_widget_show_all(range->cur_window); + // GTK4 gtk_widget_show_all(range->cur_window); } static void _bound_change(GtkDarktableRangeSelect *range, const gchar *val, const _range_bound bound) diff --git a/src/dtgtk/range.h b/src/dtgtk/range.h index 2dc5c3c9269d..b9d437251e95 100644 --- a/src/dtgtk/range.h +++ b/src/dtgtk/range.h @@ -37,7 +37,7 @@ G_BEGIN_DECLS #define DTGTK_TYPE_RANGE_SELECT dtgtk_range_select_get_type() -G_DECLARE_FINAL_TYPE(GtkDarktableRangeSelect, dtgtk_range_select, DTGTK, RANGE_SELECT, GtkEventBox) +G_DECLARE_FINAL_TYPE(GtkDarktableRangeSelect, dtgtk_range_select, DTGTK, RANGE_SELECT, GtkBox) typedef double (*DTGTKTranslateValueFunc)(const double value); typedef gchar *(*DTGTKPrintValueFunc)(const double value, const gboolean detailled); @@ -63,7 +63,7 @@ typedef enum dt_range_type_t struct _GtkDarktableRangeSelect { - GtkEventBox widget; + GtkBox widget; dt_range_type_t type; diff --git a/src/dtgtk/resetlabel.c b/src/dtgtk/resetlabel.c index dcc43ebbc746..80e437b6fc46 100644 --- a/src/dtgtk/resetlabel.c +++ b/src/dtgtk/resetlabel.c @@ -18,7 +18,7 @@ #include "dtgtk/resetlabel.h" -G_DEFINE_TYPE(GtkDarktableResetLabel, dtgtk_reset_label, GTK_TYPE_EVENT_BOX); +G_DEFINE_TYPE(GtkDarktableResetLabel, dtgtk_reset_label, GTK_TYPE_BOX); static void dtgtk_reset_label_class_init(GtkDarktableResetLabelClass *klass) { diff --git a/src/dtgtk/resetlabel.h b/src/dtgtk/resetlabel.h index 19d8199c9e5b..531c0182a5c0 100644 --- a/src/dtgtk/resetlabel.h +++ b/src/dtgtk/resetlabel.h @@ -24,11 +24,11 @@ G_BEGIN_DECLS #define DTGTK_TYPE_RESET_LABEL dtgtk_reset_label_get_type() -G_DECLARE_FINAL_TYPE(GtkDarktableResetLabel, dtgtk_reset_label, DTGTK, RESET_LABEL, GtkEventBox) +G_DECLARE_FINAL_TYPE(GtkDarktableResetLabel, dtgtk_reset_label, DTGTK, RESET_LABEL, GtkBox) struct _GtkDarktableResetLabel { - GtkEventBox widget; + GtkBox widget; GtkLabel *lb; dt_iop_module_t *module; int offset; // offset in params to reset diff --git a/src/dtgtk/sidepanel.c b/src/dtgtk/sidepanel.c index 8dd664f2e9d9..5d30662be1a0 100644 --- a/src/dtgtk/sidepanel.c +++ b/src/dtgtk/sidepanel.c @@ -33,8 +33,8 @@ static void dtgtk_side_panel_get_preferred_width(GtkWidget *widget, gint *minimum_size, gint *natural_size) { - GTK_WIDGET_CLASS(dtgtk_side_panel_parent_class)->get_preferred_width - (widget, minimum_size, natural_size); + // GTK_WIDGET_CLASS(dtgtk_side_panel_parent_class)->get_preferred_width + // (widget, minimum_size, natural_size); const int width = dt_ui_panel_get_size(darktable.gui->ui, @@ -47,10 +47,10 @@ static void dtgtk_side_panel_get_preferred_width(GtkWidget *widget, static void dtgtk_side_panel_class_init(GtkDarktableSidePanelClass *class) { - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class); + // GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class); - widget_class->get_request_mode = dtgtk_side_panel_get_request_mode; - widget_class->get_preferred_width = dtgtk_side_panel_get_preferred_width; + // widget_class->get_request_mode = dtgtk_side_panel_get_request_mode; + // widget_class->get_preferred_width = dtgtk_side_panel_get_preferred_width; } static void dtgtk_side_panel_init(GtkDarktableSidePanel *panel) diff --git a/src/dtgtk/thumbnail.c b/src/dtgtk/thumbnail.c index ff71fbfe3401..c567e0d2a4c9 100644 --- a/src/dtgtk/thumbnail.c +++ b/src/dtgtk/thumbnail.c @@ -32,8 +32,8 @@ #include "common/selection.h" #include "common/variables.h" #include "control/control.h" +#include "dtgtk/drawingarea.h" #include "dtgtk/button.h" -#include "dtgtk/icon.h" #include "dtgtk/thumbnail_btn.h" #include "gui/drag_and_drop.h" #include "gui/accelerators.h" @@ -969,18 +969,17 @@ static void _thumbs_show_overlays(dt_thumbnail_t *thumb) } } -static gboolean _event_main_motion(GtkWidget *widget, - GdkEventMotion *event, - gpointer user_data) +static void _event_main_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_thumbnail_t *thumb) { - if(!user_data) return TRUE; - dt_thumbnail_t *thumb = (dt_thumbnail_t *)user_data; + if(!thumb) return; // first, we hide the block overlays after a delay if the mouse hasn't move _thumbs_show_overlays(thumb); if(!thumb->mouse_over && !thumb->disable_mouseover) dt_control_set_mouse_over_id(thumb->imgid); - return FALSE; } static gboolean _event_rating_press(GtkWidget *widget, @@ -1260,20 +1259,24 @@ static gboolean _event_box_enter_leave(GtkWidget *widget, return FALSE; } -static gboolean _event_image_enter_leave(GtkWidget *widget, - GdkEventCrossing *event, - gpointer user_data) +static void _event_image_leave(GtkEventControllerMotion *controller, + dt_thumbnail_t *thumb) { - dt_thumbnail_t *thumb = (dt_thumbnail_t *)user_data; - // we ensure that the image has mouse over - if(!thumb->mouse_over && event->type == GDK_ENTER_NOTIFY + if(!thumb->mouse_over && controller == NULL && !thumb->disable_mouseover) dt_control_set_mouse_over_id(thumb->imgid); _set_flag(thumb->w_image_box, GTK_STATE_FLAG_PRELIGHT, - (event->type == GDK_ENTER_NOTIFY)); - return FALSE; + (controller == NULL)); +} + +static void _event_image_enter(GtkEventControllerMotion *controller, + double x, + double y, + dt_thumbnail_t *thumb) +{ + _event_image_leave(NULL, thumb); } static gboolean _event_btn_enter_leave(GtkWidget *widget, @@ -1347,13 +1350,12 @@ static gboolean _event_star_leave(GtkWidget *widget, return TRUE; } -static gboolean _event_main_leave(GtkWidget *widget, - GdkEventCrossing *event, - gpointer user_data) +static void _event_main_leave(GtkEventControllerMotion *controller, + dt_thumbnail_t *thumb) { // if we leave for ancestor, that means we leave for blank thumbtable area - if(event->detail == GDK_NOTIFY_ANCESTOR) dt_control_set_mouse_over_id(NO_IMGID); - return FALSE; + if(!gtk_event_controller_motion_contains_pointer(controller)) + dt_control_set_mouse_over_id(NO_IMGID); } // we only want to specify that the mouse is hovereing the thumbnail @@ -1364,7 +1366,7 @@ static gboolean _event_main_drag_motion(GtkWidget *widget, const guint time, gpointer user_data) { - _event_main_motion(widget, NULL, user_data); + _event_main_motion(NULL, .0f, .0f, user_data); return TRUE; } @@ -1425,16 +1427,9 @@ GtkWidget *dt_thumbnail_create_widget(dt_thumbnail_t *thumb, // the background thumb->w_back = gtk_event_box_new(); - gtk_widget_set_events(thumb->w_back, - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_STRUCTURE_MASK - | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK - | GDK_POINTER_MOTION_MASK); + gtk_widget_set_events(thumb->w_back, GDK_STRUCTURE_MASK); // TODO: Needed? gtk_widget_set_name(thumb->w_back, "thumb-back"); - g_signal_connect(G_OBJECT(thumb->w_back), "motion-notify-event", - G_CALLBACK(_event_main_motion), thumb); - g_signal_connect(G_OBJECT(thumb->w_back), "leave-notify-event", - G_CALLBACK(_event_main_leave), thumb); + dt_gui_connect_motion(thumb->w_back, _event_main_motion, NULL, _event_main_leave, thumb); gtk_widget_show(thumb->w_back); gtk_container_add(GTK_CONTAINER(thumb->w_main), thumb->w_back); @@ -1464,12 +1459,7 @@ GtkWidget *dt_thumbnail_create_widget(dt_thumbnail_t *thumb, | GDK_STRUCTURE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK); - g_signal_connect(G_OBJECT(evt_image), "motion-notify-event", - G_CALLBACK(_event_main_motion), thumb); - g_signal_connect(G_OBJECT(evt_image), "enter-notify-event", - G_CALLBACK(_event_image_enter_leave), thumb); - g_signal_connect(G_OBJECT(evt_image), "leave-notify-event", - G_CALLBACK(_event_image_enter_leave), thumb); + dt_gui_connect_motion(evt_image, _event_main_motion, _event_image_enter, _event_image_leave, thumb); gtk_widget_show(evt_image); gtk_overlay_add_overlay(GTK_OVERLAY(thumb->w_image_box), evt_image); thumb->w_image = gtk_drawing_area_new(); @@ -1483,12 +1473,7 @@ GtkWidget *dt_thumbnail_create_widget(dt_thumbnail_t *thumb, | GDK_POINTER_MOTION_MASK); g_signal_connect(G_OBJECT(thumb->w_image), "draw", G_CALLBACK(_event_image_draw), thumb); - g_signal_connect(G_OBJECT(thumb->w_image), "motion-notify-event", - G_CALLBACK(_event_main_motion), thumb); - g_signal_connect(G_OBJECT(thumb->w_image), "enter-notify-event", - G_CALLBACK(_event_image_enter_leave), thumb); - g_signal_connect(G_OBJECT(thumb->w_image), "leave-notify-event", - G_CALLBACK(_event_image_enter_leave), thumb); + dt_gui_connect_motion(thumb->w_image, _event_main_motion, _event_image_enter, _event_image_leave, thumb); g_signal_connect(G_OBJECT(thumb->w_image), "style-updated", G_CALLBACK(_event_image_style_updated), thumb); gtk_widget_show(thumb->w_image); diff --git a/src/dtgtk/thumbnail_btn.c b/src/dtgtk/thumbnail_btn.c index b2e42d004cd5..715dc91d0f3b 100644 --- a/src/dtgtk/thumbnail_btn.c +++ b/src/dtgtk/thumbnail_btn.c @@ -21,45 +21,43 @@ G_DEFINE_TYPE(GtkDarktableThumbnailBtn, dtgtk_thumbnail_btn, GTK_TYPE_DRAWING_AREA); -static gboolean _thumbnail_btn_draw(GtkWidget *widget, cairo_t *cr); +static void _thumbnail_btn_snapshot(GtkWidget *widget, GtkSnapshot* snapshot); static gboolean _thumbnail_btn_enter_leave_notify_callback(GtkWidget *widget, GdkEventCrossing *event); static void dtgtk_thumbnail_btn_class_init(GtkDarktableThumbnailBtnClass *klass) { GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; - widget_class->draw = _thumbnail_btn_draw; - widget_class->enter_notify_event = _thumbnail_btn_enter_leave_notify_callback; - widget_class->leave_notify_event = _thumbnail_btn_enter_leave_notify_callback; + widget_class->snapshot = _thumbnail_btn_snapshot; + // widget_class->enter_notify_event = _thumbnail_btn_enter_leave_notify_callback; + // widget_class->leave_notify_event = _thumbnail_btn_enter_leave_notify_callback; } static void dtgtk_thumbnail_btn_init(GtkDarktableThumbnailBtn *button) { } -static gboolean _thumbnail_btn_draw(GtkWidget *widget, cairo_t *cr) +static void _thumbnail_btn_snapshot(GtkWidget *widget, GtkSnapshot* snapshot) { - g_return_val_if_fail(DTGTK_IS_THUMBNAIL_BTN(widget), FALSE); + if(gtk_widget_get_allocated_height(widget) < 2 || gtk_widget_get_allocated_width(widget) < 2) return; - if(gtk_widget_get_allocated_height(widget) < 2 || gtk_widget_get_allocated_width(widget) < 2) return TRUE; + graphene_rect_t bounds; + graphene_rect_init(&bounds, 0, 0, gtk_widget_get_width(widget), gtk_widget_get_height(widget)); + cairo_t* cr = gtk_snapshot_append_cairo(snapshot, &bounds); GtkStateFlags state = gtk_widget_get_state_flags(widget); - GdkRGBA *fg_color, *bg_color; + GdkRGBA fg_color; GtkStyleContext *context = gtk_widget_get_style_context(widget); - gtk_style_context_get(context, state, GTK_STYLE_PROPERTY_COLOR, &fg_color, GTK_STYLE_PROPERTY_BACKGROUND_COLOR, - &bg_color, NULL); - if(fg_color->alpha == 0 && bg_color->alpha == 0) + gtk_style_context_get_color(context, state, &fg_color); + if(fg_color.alpha == 0) { DTGTK_THUMBNAIL_BTN(widget)->hidden = TRUE; - gdk_rgba_free(fg_color); - gdk_rgba_free(bg_color); - return TRUE; + return; } DTGTK_THUMBNAIL_BTN(widget)->hidden = FALSE; - cairo_save(cr); - gdk_cairo_set_source_rgba(cr, fg_color); + gdk_cairo_set_source_rgba(cr, &fg_color); /* draw icon */ if(DTGTK_THUMBNAIL_BTN(widget)->icon) @@ -87,16 +85,14 @@ static gboolean _thumbnail_btn_draw(GtkWidget *widget, cairo_t *cr) const float icon_h = allocation.height - (padding.top + padding.bottom) * allocation.height / 100.0f; DTGTK_THUMBNAIL_BTN(widget)->icon( cr, icon_x, icon_y, icon_w, icon_h, flags, - DTGTK_THUMBNAIL_BTN(widget)->icon_data ? DTGTK_THUMBNAIL_BTN(widget)->icon_data : bg_color); + DTGTK_THUMBNAIL_BTN(widget)->icon_data ? DTGTK_THUMBNAIL_BTN(widget)->icon_data : NULL); } // and eventually the image border cairo_restore(cr); gtk_render_frame(context, cr, 0, 0, gtk_widget_get_allocated_width(widget), gtk_widget_get_allocated_height(widget)); - gdk_rgba_free(fg_color); - gdk_rgba_free(bg_color); - return TRUE; + cairo_destroy(cr); } static gboolean _thumbnail_btn_enter_leave_notify_callback(GtkWidget *widget, GdkEventCrossing *event) diff --git a/src/dtgtk/togglebutton.c b/src/dtgtk/togglebutton.c index 5a978d2b3078..1a324ba70fce 100644 --- a/src/dtgtk/togglebutton.c +++ b/src/dtgtk/togglebutton.c @@ -23,23 +23,28 @@ G_DEFINE_TYPE(GtkDarktableToggleButton, dtgtk_togglebutton, GTK_TYPE_TOGGLE_BUTTON); -static gboolean _togglebutton_draw(GtkWidget *widget, cairo_t *cr); +static void _togglebutton_snapshot(GtkWidget *widget, GtkSnapshot* snapshot); static void dtgtk_togglebutton_class_init(GtkDarktableToggleButtonClass *klass) { GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; - widget_class->draw = _togglebutton_draw; + widget_class->snapshot = _togglebutton_snapshot; } static void dtgtk_togglebutton_init(GtkDarktableToggleButton *slider) { } -static gboolean _togglebutton_draw(GtkWidget *widget, cairo_t *cr) +static void _togglebutton_snapshot(GtkWidget* widget, + GtkSnapshot* snapshot) { - g_return_val_if_fail(widget != NULL, FALSE); - g_return_val_if_fail(DTGTK_IS_TOGGLEBUTTON(widget), FALSE); + g_return_if_fail(widget != NULL); + g_return_if_fail(DTGTK_IS_TOGGLEBUTTON(widget)); + + graphene_rect_t bounds; + graphene_rect_init(&bounds, 0, 0, gtk_widget_get_width(widget), gtk_widget_get_height(widget)); + cairo_t* cr = gtk_snapshot_append_cairo(snapshot, &bounds); GtkStateFlags state = gtk_widget_get_state_flags(widget); @@ -126,7 +131,7 @@ static gboolean _togglebutton_draw(GtkWidget *widget, cairo_t *cr) DTGTK_TOGGLEBUTTON(widget)->icon(cr, startx, starty, cwidth, cheight, flags, icon_data); } - return FALSE; + cairo_destroy(cr); } // Public functions diff --git a/src/generate-cache/main.c b/src/generate-cache/main.c index eb75ab089217..57967cecbf41 100644 --- a/src/generate-cache/main.c +++ b/src/generate-cache/main.c @@ -156,8 +156,6 @@ int main(int argc, char *arg[]) bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); textdomain(GETTEXT_PACKAGE); - gtk_init_check(&argc, &arg); - // parse command line arguments dt_mipmap_size_t min_mip = DT_MIPMAP_0; dt_mipmap_size_t max_mip = DT_MIPMAP_2; diff --git a/src/gui/accelerators.c b/src/gui/accelerators.c index 464eff9f5194..77e844e1b546 100644 --- a/src/gui/accelerators.c +++ b/src/gui/accelerators.c @@ -213,27 +213,26 @@ static float _action_process_toggle(gpointer target, if(DT_ACTION_TOGGLE_NEEDED(effect, move_size, value) && gtk_widget_get_ancestor(target, GTK_TYPE_WINDOW)) { - GdkEvent *event = gdk_event_new(GDK_BUTTON_PRESS); - event->button.state = (effect == DT_ACTION_EFFECT_TOGGLE_CTRL - || effect == DT_ACTION_EFFECT_ON_CTRL) - ? GDK_CONTROL_MASK : 0; - event->button.button = (effect == DT_ACTION_EFFECT_TOGGLE_RIGHT - || effect == DT_ACTION_EFFECT_ON_RIGHT) - ? GDK_BUTTON_SECONDARY : GDK_BUTTON_PRIMARY; + // GTK4 FIXME how to pass right and ctrl clicks to event controllers? + // event->button.state = (effect == DT_ACTION_EFFECT_TOGGLE_CTRL + // || effect == DT_ACTION_EFFECT_ON_CTRL) + // ? GDK_CONTROL_MASK : 0; + // event->button.button = (effect == DT_ACTION_EFFECT_TOGGLE_RIGHT + // || effect == DT_ACTION_EFFECT_ON_RIGHT) + // ? GDK_BUTTON_SECONDARY : GDK_BUTTON_PRIMARY; if(!gtk_widget_get_realized(target)) gtk_widget_realize(target); - event->button.window = gtk_widget_get_window(target); - g_object_ref(event->button.window); // some togglebuttons connect to the clicked signal, others to toggled or button-press-event // gtk_widget_event does not work when widgets are hidden in event boxes or some other conditions - gboolean handled; - g_signal_emit_by_name(G_OBJECT(target), "button-press-event", event, &handled); - if(!handled) gtk_button_clicked(GTK_BUTTON(target)); - event->type = GDK_BUTTON_RELEASE; - g_signal_emit_by_name(G_OBJECT(target), "button-release-event", event, &handled); - - gdk_event_free(event); + GtkEventController *controller = g_object_get_data(target, "click"); + if(controller) + { + g_signal_emit_by_name(G_OBJECT(controller), "pressed", 1, 0, 0); + g_signal_emit_by_name(G_OBJECT(controller), "released", 1, 0, 0); + } + // else + gtk_button_clicked(GTK_BUTTON(target)); value = gtk_toggle_button_get_active(target); @@ -1011,9 +1010,9 @@ gboolean dt_shortcut_tooltip_callback(GtkWidget *widget, GtkTooltip *tooltip, GtkWidget *vbox) { - GtkWindow *top = GTK_WINDOW(gtk_widget_get_toplevel(widget)); + GtkWindow *top = GTK_WINDOW(gtk_widget_get_root(widget)); if(!gtk_window_is_active(top) - && gtk_window_get_window_type(top) != GTK_WINDOW_POPUP) + )//GTK4 && gtk_window_get_window_type(top) != GTK_WINDOW_POPUP) return FALSE; if(dt_key_modifier_state() & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK|GDK_BUTTON3_MASK @@ -1474,6 +1473,7 @@ static gboolean _insert_shortcut(dt_shortcut_t *shortcut, shortcut->speed = s->speed = roundf(s->speed * e->speed * 1000.) / 1000.; if(fabsf(s->speed) >= .001 && fabsf(s->speed) <= 1000.) { + if(0) // GTK4 _remove_shortcut(existing); if(s->speed != 1.0) { @@ -2516,7 +2516,7 @@ static void _restore_clicked(GtkButton *button, gpointer user_data) { enum { - _DEFAULTS = 1, + _DEFAULTS, _STARTUP, _EDITS, }; @@ -2717,7 +2717,7 @@ static void _import_clicked(GtkButton *button, gpointer user_data) g_signal_connect(combo_from_id, "changed", G_CALLBACK(_import_id_changed), combo_to_id); dt_gui_dialog_add(GTK_DIALOG(dialog), label, combo_dev, device_grid, clear); - gtk_widget_show_all(dialog); + // gtk_widget_show_all(dialog); gtk_combo_box_set_active(GTK_COMBO_BOX(combo_dev), 0); @@ -2887,8 +2887,8 @@ GtkWidget *dt_shortcuts_prefs(GtkWidget *widget) gtk_tree_view_set_search_column(shortcuts_view, 0); // fake column for _search_func gtk_tree_view_set_search_equal_func(shortcuts_view, _search_func, shortcuts_view, NULL); GtkWidget *search_shortcuts = gtk_search_entry_new(); - gtk_entry_set_placeholder_text(GTK_ENTRY(search_shortcuts), - _("search shortcuts list")); + gtk_search_entry_set_placeholder_text(GTK_SEARCH_ENTRY(search_shortcuts), + _("search shortcuts list")); gtk_widget_set_tooltip_text(GTK_WIDGET(search_shortcuts), _("incrementally search the list of shortcuts\npress up or down keys to cycle through matches")); g_signal_connect(G_OBJECT(search_shortcuts), "activate", @@ -2988,8 +2988,8 @@ GtkWidget *dt_shortcuts_prefs(GtkWidget *widget) gtk_tree_view_set_search_column(actions_view, 1); // fake column for _search_func gtk_tree_view_set_search_equal_func(actions_view, _search_func, actions_view, NULL); GtkWidget *search_actions = gtk_search_entry_new(); - gtk_entry_set_placeholder_text(GTK_ENTRY(search_actions), - _("search actions list")); + gtk_search_entry_set_placeholder_text(GTK_SEARCH_ENTRY(search_actions), + _("search actions list")); gtk_widget_set_tooltip_text(GTK_WIDGET(search_actions), _("incrementally search the list of actions\npress up or down keys to cycle through matches")); g_signal_connect(G_OBJECT(search_actions), "activate", @@ -4523,9 +4523,8 @@ gboolean dt_shortcut_key_active(dt_input_device_t id, guint key) static guint _fix_keyval(GdkEvent *event) { guint keyval = 0; - GdkKeymap *keymap = gdk_keymap_get_for_display(gdk_display_get_default()); - gdk_keymap_translate_keyboard_state(keymap, event->key.hardware_keycode, 0, 0, - &keyval, NULL, NULL, NULL); + gdk_display_translate_key(gdk_display_get_default(), event->key.hardware_keycode, 0, 0, + &keyval, NULL, NULL, NULL); return keyval; } @@ -5008,17 +5007,15 @@ void dt_shortcut_register(dt_action_t *owner, { if(accel_key != 0 && !darktable.control->accel_initialised) { - GdkKeymap *keymap = gdk_keymap_get_for_display(gdk_display_get_default()); - GdkKeymapKey *keys; gint n_keys, i = 0; - if(!gdk_keymap_get_entries_for_keyval(keymap, accel_key, &keys, &n_keys)) return; + if(!gdk_display_map_keyval(gdk_display_get_default(), accel_key, &keys, &n_keys)) return; // GTK4 for(int j = 0; j < n_keys; j++) { - gdk_keymap_translate_keyboard_state(keymap, keys[j].keycode, 0, 0, - &keys[j].keycode, NULL, NULL, NULL); + gdk_display_translate_key(gdk_display_get_default(), keys[j].keycode, 0, 0, + &keys[j].keycode, NULL, NULL, NULL); if(_is_kp_key(keys[j].keycode)) keys[j].group = 10; @@ -5030,9 +5027,9 @@ void dt_shortcut_register(dt_action_t *owner, } if(keys[i].level & 1) mods |= GDK_SHIFT_MASK; - if(keys[i].level & 2) mods |= GDK_MOD5_MASK; + if(keys[i].level & 2) mods |= GDK_ALT_MASK; // GTK4 - mods = _mods_fix_primary(mods); + // mods = _mods_fix_primary(mods); // GTK4 dt_shortcut_t s = { .key_device = DT_SHORTCUT_DEVICE_KEYBOARD_MOUSE, .key = keys[i].keycode, diff --git a/src/gui/gtk.c b/src/gui/gtk.c index 228f9ad21f63..7a07ee7eb922 100644 --- a/src/gui/gtk.c +++ b/src/gui/gtk.c @@ -48,9 +48,6 @@ #include "gui/preferences.h" #include -#ifdef GDK_WINDOWING_WAYLAND -#include -#endif #include #include #include @@ -59,13 +56,16 @@ #ifdef MAC_INTEGRATION #include #endif -#ifdef GDK_WINDOWING_QUARTZ +#ifdef __APPLE__ #include "osx/osx.h" #endif -#ifdef _WIN32 +#ifdef X_WIN32 #include #include #endif +#ifdef GDK_WINDOWING_WAYLAND +#include +#endif #include /* @@ -990,12 +990,12 @@ dt_gui_session_type_t dt_gui_get_session_type(void) return DT_GUI_SESSION_QUARTZ; #elif defined(GDK_WINDOWING_WAYLAND) GdkDisplay* disp = gdk_display_get_default(); - return G_TYPE_CHECK_INSTANCE_TYPE(disp, GDK_TYPE_WAYLAND_DISPLAY) + return GDK_IS_WAYLAND_DISPLAY(disp) ? DT_GUI_SESSION_WAYLAND : DT_GUI_SESSION_X11; #elif defined(GDK_WINDOWING_X11) GdkDisplay* disp = gdk_display_get_default(); - retun G_TYPE_CHECK_INSTANCE_TYPE(disp, GDK_TYPE_X11_DISPLAY) + return GDK_IS_X11_DISPLAY(disp) ? DT_GUI_SESSION_X11 : DT_GUI_SESSION_WAYLAND; #else @@ -1003,15 +1003,16 @@ dt_gui_session_type_t dt_gui_get_session_type(void) #endif } -static gboolean _configure(GtkWidget *da, - GdkEventConfigure *event, - const gpointer user_data) +static void _configure(GtkWidget *da, + gint width, + gint height, + const gpointer user_data) { #ifndef GDK_WINDOWING_QUARTZ dt_configure_ppd_dpi((dt_gui_gtk_t *) user_data); #endif - return dt_control_configure(da, event, user_data); + dt_control_configure(da, width, height, user_data); } static gboolean _window_configure(GtkWidget *da, @@ -1430,32 +1431,6 @@ int dt_gui_gtk_init(dt_gui_gtk_t *gui) // Initializing widgets _init_widgets(gui); - widget = dt_ui_center(darktable.gui->ui); - g_signal_connect(G_OBJECT(widget), "configure-event", - 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 @@ -1625,7 +1600,11 @@ void dt_gui_gtk_run(dt_gui_gtk_t *gui) if(dt_control_running()) { g_atomic_int_set(&darktable.gui_running, 1); - gtk_main(); + + //GTK4 gtk_application_new? +while (g_list_model_get_n_items (gtk_window_get_toplevels ()) > 0) + g_main_context_iteration (NULL, TRUE); + g_atomic_int_set(&darktable.gui_running, 0); } if(darktable.gui->surface) @@ -1685,7 +1664,7 @@ void dt_configure_ppd_dpi(dt_gui_gtk_t *gui) gui->ppd = gui->ppd_thb = dt_get_system_gui_ppd(widget); gui->filter_image = CAIRO_FILTER_GOOD; gui->dpi = dt_get_screen_resolution(widget); - gui->dpi_factor = gui->dpi / DT_UI_DEFAULT_DPI_RESOLUTION; + gui->dpi_factor = 1;//GTK4 gui->dpi / DT_UI_DEFAULT_DPI_RESOLUTION; } static gboolean _focus_in_out_event(GtkWidget *widget, @@ -1743,7 +1722,7 @@ static void _init_widgets(dt_gui_gtk_t *gui) // Creating the main window widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_name(widget, "main_window"); - gui->ui->main_window = widget; + g_set_weak_pointer(&gui->ui->main_window, widget); #ifdef GDK_WINDOWING_WAYLAND if(dt_gui_get_session_type() == DT_GUI_SESSION_WAYLAND) @@ -1752,7 +1731,6 @@ static void _init_widgets(dt_gui_gtk_t *gui) gtk_window_set_type_hint(GTK_WINDOW(widget), GDK_WINDOW_TYPE_HINT_NORMAL); GtkWidget *header_bar = gtk_header_bar_new(); - gtk_header_bar_set_title(GTK_HEADER_BAR(header_bar), "darktable"); gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(header_bar), TRUE); gtk_window_set_titlebar(GTK_WINDOW(widget), header_bar); gtk_widget_show(header_bar); @@ -1778,7 +1756,7 @@ static void _init_widgets(dt_gui_gtk_t *gui) // Adding the outermost vbox widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_container_add(GTK_CONTAINER(container), widget); + gtk_window_set_child(GTK_WINDOW(container), widget); /* connect to signal redraw all */ DT_CONTROL_SIGNAL_CONNECT(DT_SIGNAL_CONTROL_REDRAW_ALL, _ui_widget_redraw_callback, gui->ui->main_window); @@ -1803,6 +1781,34 @@ static void _init_widgets(dt_gui_gtk_t *gui) static const dt_action_def_t _action_def_focus_tabs; +static GtkWidget *_central_image_new() +{ + GtkWidget *widget = gtk_drawing_area_new(); + g_signal_connect(G_OBJECT(widget), "resize", + G_CALLBACK(_configure), darktable.gui); + + 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), darktable.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); + return widget; +} + static void _init_main_table(GtkWidget *container) { GtkWidget *widget; @@ -1842,14 +1848,14 @@ static void _init_main_table(GtkWidget *container) /* setup center drawing area */ GtkWidget *ocda = gtk_overlay_new(); - GtkWidget *cda = gtk_drawing_area_new(); + GtkWidget *cda = _central_image_new(); gtk_widget_set_size_request(cda, DT_PIXEL_APPLY_DPI(50), DT_PIXEL_APPLY_DPI(200)); gtk_widget_set_hexpand(ocda, TRUE); gtk_widget_set_vexpand(ocda, TRUE); gtk_widget_set_app_paintable(cda, TRUE); gtk_widget_set_can_focus(cda, TRUE); - darktable.gui->ui->snapshot = gtk_drawing_area_new(); - gtk_widget_set_no_show_all(darktable.gui->ui->snapshot, TRUE); + darktable.gui->ui->snapshot = _central_image_new(); + gtk_widget_hide(darktable.gui->ui->snapshot); 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); @@ -1857,7 +1863,7 @@ static void _init_main_table(GtkWidget *container) gtk_overlay_add_overlay(GTK_OVERLAY(ocda), sidebyside); gtk_grid_attach(GTK_GRID(centergrid), ocda, 0, 0, 1, 1); - darktable.gui->ui->center = cda; + g_set_weak_pointer(&darktable.gui->ui->center, cda); darktable.gui->ui->center_base = ocda; /* initialize the thumb panel */ @@ -1943,7 +1949,7 @@ static void _init_main_table(GtkWidget *container) void dt_ui_container_swap_left_right(struct dt_ui_t *ui, const gboolean swap) { - if(swap ^ strcmp("left", gtk_widget_get_name(gtk_widget_get_ancestor(*ui->containers, DTGTK_TYPE_SIDE_PANEL)))) + if(swap ^ g_strcmp0("left", gtk_widget_get_name(gtk_widget_get_ancestor(*ui->containers, DTGTK_TYPE_SIDE_PANEL)))) for(GtkWidget **c = ui->containers; c < ui->containers + 3; c++) {GtkWidget *tmp = *c; *c = c[3]; c[3] = tmp;} } @@ -2126,7 +2132,7 @@ void dt_ui_update_scrollbars(dt_ui_t *ui) if(cv->vscroll_size > cv->vscroll_viewport_size) { gtk_adjustment_configure - (gtk_range_get_adjustment(GTK_RANGE(darktable.gui->scrollbars.vscrollbar)), + (gtk_scrollbar_get_adjustment(GTK_SCROLLBAR(darktable.gui->scrollbars.vscrollbar)), cv->vscroll_pos, cv->vscroll_lower, cv->vscroll_size, 0, cv->vscroll_viewport_size, cv->vscroll_viewport_size); @@ -2135,7 +2141,7 @@ void dt_ui_update_scrollbars(dt_ui_t *ui) if(cv->hscroll_size > cv->hscroll_viewport_size) { gtk_adjustment_configure - (gtk_range_get_adjustment(GTK_RANGE(darktable.gui->scrollbars.hscrollbar)), + (gtk_scrollbar_get_adjustment(GTK_SCROLLBAR(darktable.gui->scrollbars.hscrollbar)), cv->hscroll_pos, cv->hscroll_lower, cv->hscroll_size, 0, cv->hscroll_viewport_size, cv->hscroll_viewport_size); @@ -2504,7 +2510,8 @@ static GtkWidget *_ui_init_panel_container_center(GtkWidget *container, container = widget; widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_widget_set_name(widget, "plugins_vbox_left"); - gtk_container_add(GTK_CONTAINER(container), widget); + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(container), widget); + gtk_widget_set_vexpand(widget, TRUE); g_signal_connect_swapped(widget, "draw", G_CALLBACK(_side_panel_draw), NULL); GtkWidget *empty = gtk_event_box_new(); @@ -2626,7 +2633,7 @@ static void _ui_init_panel_left(dt_ui_t *ui, gtk_widget_set_name(widget, "left"); GtkWidget *over = gtk_overlay_new(); - gtk_container_add(GTK_CONTAINER(over), widget); + gtk_overlay_set_child(GTK_OVERLAY(over), widget); // we add a transparent overlay over the modules margins to resize the panel GtkWidget *handle = gtk_drawing_area_new(); gtk_widget_set_halign(handle, GTK_ALIGN_END); @@ -2677,7 +2684,7 @@ static void _ui_init_panel_right(dt_ui_t *ui, gtk_widget_set_name(widget, "right"); GtkWidget *over = gtk_overlay_new(); - gtk_container_add(GTK_CONTAINER(over), widget); + gtk_overlay_set_child(GTK_OVERLAY(over), widget); // we add a transparent overlay over the modules margins to resize the panel GtkWidget *handle = gtk_drawing_area_new(); gtk_widget_set_halign(handle, GTK_ALIGN_START); @@ -2825,13 +2832,13 @@ static void _ui_init_panel_center_top(dt_ui_t *ui, gtk_box_pack_start(GTK_BOX(widget), ui->containers[DT_UI_CONTAINER_PANEL_CENTER_TOP_CENTER], TRUE, FALSE, DT_UI_PANEL_MODULE_SPACING); + gtk_widget_set_halign(dt_gui_expand(ui->containers[DT_UI_CONTAINER_PANEL_CENTER_TOP_CENTER]), + GTK_ALIGN_CENTER); /* add container for center top right */ ui->containers[DT_UI_CONTAINER_PANEL_CENTER_TOP_RIGHT] = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_box_pack_end(GTK_BOX(widget), - ui->containers[DT_UI_CONTAINER_PANEL_CENTER_TOP_RIGHT], FALSE, FALSE, - DT_UI_PANEL_MODULE_SPACING); + gtk_box_append(GTK_BOX(widget), ui->containers[DT_UI_CONTAINER_PANEL_CENTER_TOP_RIGHT]); } static void _ui_init_panel_center_bottom(dt_ui_t *ui, @@ -2861,6 +2868,8 @@ static void _ui_init_panel_center_bottom(dt_ui_t *ui, ui->containers[DT_UI_CONTAINER_PANEL_CENTER_BOTTOM_CENTER], FALSE, TRUE, DT_UI_PANEL_MODULE_SPACING); + gtk_widget_set_halign(dt_gui_expand(ui->containers[DT_UI_CONTAINER_PANEL_CENTER_BOTTOM_CENTER]), + GTK_ALIGN_CENTER); /* adding the right toolbox */ ui->containers[DT_UI_CONTAINER_PANEL_CENTER_BOTTOM_RIGHT] = @@ -3447,8 +3456,8 @@ void dt_gui_load_theme(const char *theme) GError *error = NULL; GtkStyleProvider *themes_style_provider = GTK_STYLE_PROVIDER(gtk_css_provider_new()); - gtk_style_context_add_provider_for_screen - (gdk_screen_get_default(), themes_style_provider, GTK_STYLE_PROVIDER_PRIORITY_USER + 1); + gtk_style_context_add_provider_for_display + (gdk_display_get_default(), themes_style_provider, GTK_STYLE_PROVIDER_PRIORITY_USER + 1); usercsspath = g_build_filename(configdir, "user.css", NULL); @@ -3490,14 +3499,7 @@ void dt_gui_load_theme(const char *theme) themecss = newcss; } - if(!gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(themes_style_provider), - themecss, -1, &error)) - { - dt_print(DT_DEBUG_ALWAYS, - "%s: error parsing combined CSS %s: %s", - G_STRFUNC, themecss, error->message); - g_clear_error(&error); - } + gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(themes_style_provider), themecss, -1); g_free(themecss); @@ -3572,12 +3574,10 @@ void dt_gui_apply_theme() GdkModifierType dt_key_modifier_state() { - guint state = 0; - GdkWindow *window = gtk_widget_get_window(dt_ui_main_window(darktable.gui->ui)); - gdk_device_get_state - (gdk_seat_get_pointer(gdk_display_get_default_seat - (gdk_window_get_display(window))), window, NULL, &state); - return state; + GdkDisplay *display = gtk_widget_get_display(dt_ui_main_window(darktable.gui->ui)); + GdkSeat *seat = gdk_display_get_default_seat(display); + GdkDevice *device = gdk_seat_get_pointer(seat); + return gdk_device_get_modifier_state(device); /* FIXME double check correct way of doing this (merge conflict with Input System NG 20210319) @@ -3808,17 +3808,15 @@ GtkWidget *dt_ui_notebook_page(GtkNotebook *notebook, } GtkWidget *label = gtk_label_new(_(text)); GtkWidget *page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - if(strlen(text) > 2) - gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END); + // if(strlen(text) > 2) // GTK4 + // gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END); gtk_widget_set_tooltip_text(label, tooltip ? tooltip : _(text)); gtk_widget_set_has_tooltip(GTK_WIDGET(notebook), FALSE); const gint page_num = gtk_notebook_append_page(notebook, page, label); - gtk_container_child_set(GTK_CONTAINER(notebook), page, - "tab-expand", TRUE, "tab-fill", TRUE, NULL); + dt_gui_expand(gtk_notebook_get_tab_label(notebook, page)); if(page_num == 1 && - !g_signal_handler_find(G_OBJECT(notebook), - G_SIGNAL_MATCH_FUNC, 0, 0, NULL, _notebook_size_callback, NULL)) + !g_object_get_data(G_OBJECT(notebook), "click")) { g_signal_connect(G_OBJECT(notebook), "size-allocate", G_CALLBACK(_notebook_size_callback), NULL); @@ -3875,14 +3873,11 @@ static const dt_action_def_t _action_def_focus_tabs DT_ACTION_ELEMENTS_NUM(tabs), NULL, TRUE }; -static void _get_height_if_visible(GtkWidget *w, - gint *height) -{ - if(gtk_widget_get_visible(w)) *height = gtk_widget_get_allocated_height(w); -} - static gint _get_container_row_heigth(GtkWidget *w) { + if(GTK_IS_VIEWPORT(w)) + w = gtk_viewport_get_child(GTK_VIEWPORT(w)); + gint height = DT_PIXEL_APPLY_DPI(10); if(GTK_IS_TREE_VIEW(w)) @@ -3892,10 +3887,14 @@ static gint _get_container_row_heigth(GtkWidget *w) const gint num_columns = gtk_tree_view_get_n_columns(GTK_TREE_VIEW(w)); for(int c = 0; c < num_columns; c++) { - gint cell_height = 0; - gtk_tree_view_column_cell_get_size(gtk_tree_view_get_column(GTK_TREE_VIEW(w), c), - NULL, NULL, NULL, NULL, &cell_height); - if(cell_height > row_height) row_height = cell_height; + GList *renderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(gtk_tree_view_get_column(GTK_TREE_VIEW(w), c))); + for(GList *l = renderers; l; l = g_list_delete_link(l, l)) + { + GtkCellRenderer *renderer = l->data; + int natural_height; + gtk_cell_renderer_get_preferred_height(renderer, w, NULL, &natural_height); + if(natural_height > row_height) row_height = natural_height; + } } GValue separation = { G_TYPE_INT }; gtk_widget_style_get_property(w, "vertical-separator", &separation); @@ -3909,108 +3908,55 @@ static gint _get_container_row_heigth(GtkWidget *w) g_object_unref(layout); } else - gtk_container_foreach(GTK_CONTAINER(w), (GtkCallback)_get_height_if_visible, &height); - - return height; -} - -static gboolean _resize_wrap_draw(GtkWidget *w, - void *cr, - const char *config_str) -{ - GtkWidget *sw = gtk_widget_get_parent(w); - if(GTK_IS_VIEWPORT(sw)) sw = gtk_widget_get_parent(sw); - - const gint increment = _get_container_row_heigth(w); - - gint height = dt_conf_get_int(config_str); - - const gint max_height = DT_PIXEL_APPLY_DPI(1000); - - height = (height < 1) ? 1 : (height > max_height) ? max_height : height; - - dt_conf_set_int(config_str, height); - - gint content_height; - gtk_widget_get_preferred_height(w, NULL, &content_height); - - const gint min_height = - -gtk_scrolled_window_get_min_content_height(GTK_SCROLLED_WINDOW(sw)); - - if(content_height < min_height) content_height = min_height; - - if(height > content_height) height = content_height; - - height += increment - 1; - height -= height % increment; - - GtkBorder padding, margin; - gtk_style_context_get_padding(gtk_widget_get_style_context(w), - gtk_widget_get_state_flags(w), - &padding); - gtk_style_context_get_margin(gtk_widget_get_style_context(sw), - gtk_widget_get_state_flags(sw), - &margin); - - gint old_height = 0; - gtk_widget_get_size_request(sw, NULL, &old_height); - const gint new_height = - height + padding.top + padding.bottom + margin.top + margin.bottom; - - if(new_height != old_height) { - gtk_widget_set_size_request(sw, -1, new_height); - - GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(sw)); - gint value = gtk_adjustment_get_value(adj); - value -= value % increment; - gtk_adjustment_set_value(adj, value); + GtkWidget *child = gtk_widget_get_first_child(w); + while(child && !(height = gtk_widget_get_allocated_height(child))) + child = gtk_widget_get_next_sibling(child); } - return FALSE; + return height; } -static gboolean _resize_wrap_scroll(GtkScrolledWindow *sw, - GdkEventScroll *event, - const char *config_str) -{ - // no move needed - int delta_y = 0; - dt_gui_get_scroll_unit_delta(event, &delta_y); - if(delta_y == 0 ) - return FALSE; - GtkWidget *w = gtk_bin_get_child(GTK_BIN(sw)); +static gboolean _resize_wrap_scroll(GtkEventControllerScroll* controller, + gdouble dx, + gdouble dy, + char *config_str) +{ + GtkWidget *sw = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); - if(GTK_IS_VIEWPORT(w)) - w = gtk_bin_get_child(GTK_BIN(w)); + GdkModifierType state = gdk_event_get_modifier_state( + gtk_event_controller_get_current_event( + GTK_EVENT_CONTROLLER(controller))); + GtkWidget *w = gtk_scrolled_window_get_child(GTK_SCROLLED_WINDOW(sw)); const gint increment = _get_container_row_heigth(w); - if(dt_modifier_is(event->state, GDK_SHIFT_MASK | GDK_MOD1_MASK)) + if(dt_modifier_is(state, GDK_SHIFT_MASK | GDK_MOD1_MASK)) { - const gint new_size = dt_conf_get_int(config_str) + increment*delta_y; + const gint new_size = dt_conf_get_int(config_str) + increment*dy; dt_toast_log(_("never show more than %d lines"), 1 + new_size / increment); dt_conf_set_int(config_str, new_size); - gtk_widget_queue_draw(w); + gtk_widget_queue_resize(w); } else { - GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment(sw); + GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(sw)); const gint before = gtk_adjustment_get_value(adj); - gint value = before + increment*delta_y; + gint value = before + increment*dy; value -= value % increment; gtk_adjustment_set_value(adj, value); const gint after = gtk_adjustment_get_value(adj); if(after == before) - gtk_propagate_event(gtk_widget_get_parent(GTK_WIDGET(sw)), (GdkEvent*)event); + return FALSE; + // gtk_propagate_event(gtk_widget_get_parent(GTK_WIDGET(sw)), (GdkEvent*)event); } return TRUE; @@ -4039,98 +3985,200 @@ static gboolean _scroll_wrap_height(GtkWidget *w, static gboolean _resize_wrap_dragging = FALSE; static GtkWidget *_resize_wrap_hovered = NULL; -static gboolean _resize_wrap_draw_handle(GtkWidget *w, - void *cr, - gpointer user_data) +void dt_gui_draw_resize_handle(GtkWidget *widget, + GtkSnapshot *snapshot, + graphene_rect_t *bounds) { - if(w != _resize_wrap_hovered) - return FALSE; - - GtkAllocation allocation; - gtk_widget_get_allocation(w, &allocation); + if(widget != _resize_wrap_hovered) + return; - set_color(cr, darktable.bauhaus->color_fg_insensitive); - cairo_move_to(cr, allocation.width / 8 * 3, - allocation.height - DT_RESIZE_HANDLE_SIZE / 4 * 3); - cairo_line_to(cr, allocation.width / 8 * 5, - allocation.height - DT_RESIZE_HANDLE_SIZE / 4 * 3); - cairo_set_line_width(cr, DT_RESIZE_HANDLE_SIZE / 2); - cairo_stroke(cr); + GskPathBuilder *path = gsk_path_builder_new(); + gsk_path_builder_move_to(path, bounds->size.width / 8 * 3, bounds->size.height - DT_RESIZE_HANDLE_SIZE / 4 * 3); + gsk_path_builder_line_to(path, bounds->size.width / 8 * 5, bounds->size.height - DT_RESIZE_HANDLE_SIZE / 4 * 3); - return FALSE; + GskStroke *stroke = gsk_stroke_new(DT_RESIZE_HANDLE_SIZE / 2); + gtk_snapshot_push_stroke(snapshot, gsk_path_builder_free_to_path(path), stroke); + gtk_snapshot_append_color(snapshot, &darktable.bauhaus->color_fg_insensitive, bounds); + gtk_snapshot_pop(snapshot); + gsk_stroke_free(stroke); } -static gboolean _resize_wrap_motion(GtkWidget *widget, - const GdkEventMotion *event, - const char *config_str) +static void _resize_wrap_motion(GtkEventControllerMotion *controller, + double x, + double y, + char *config_str) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); if(_resize_wrap_dragging) { + dt_conf_set_int(config_str, y); if(DTGTK_IS_DRAWING_AREA(widget)) { // enforce configuration limits - dt_conf_set_int(config_str, event->y); const int height = dt_conf_get_int(config_str); dtgtk_drawing_area_set_height(widget, height); } else - { - dt_conf_set_int(config_str, event->y); - gtk_widget_queue_draw(gtk_bin_get_child(GTK_BIN(gtk_bin_get_child(GTK_BIN(widget))))); - } - return TRUE; + gtk_widget_queue_resize(widget); } - else if(!(event->state & GDK_BUTTON1_MASK) - && event->window == gtk_widget_get_window(widget) - && event->y > gtk_widget_get_allocated_height(widget) - DT_RESIZE_HANDLE_SIZE) + else if(!(dt_key_modifier_state() & GDK_BUTTON1_MASK) + && y > gtk_widget_get_allocated_height(widget) - DT_RESIZE_HANDLE_SIZE) { dt_control_change_cursor(GDK_SB_V_DOUBLE_ARROW); - return TRUE; } + else + dt_control_change_cursor(GDK_LEFT_PTR); +} - dt_control_change_cursor(GDK_LEFT_PTR); - return FALSE; +static void _resize_wrap_enter(GtkEventControllerMotion *controller, + double x, + double y, + char *config_str) +{ + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + _resize_wrap_hovered = widget; + gtk_widget_queue_draw(widget); } -static gboolean _resize_wrap_button(GtkWidget *widget, - const GdkEventButton *event, - const char *config_str) +static void _resize_wrap_leave(GtkEventControllerMotion *controller, + char *config_str) { - if(_resize_wrap_dragging - && event->type == GDK_BUTTON_RELEASE) + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + _resize_wrap_hovered = NULL; + gtk_widget_queue_draw(widget); + if(!_resize_wrap_dragging) + dt_control_change_cursor(GDK_LEFT_PTR); +} + +static void _resize_wrap_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + GtkWidget *widget) +{ + if(y > gtk_widget_get_allocated_height(widget) - DT_RESIZE_HANDLE_SIZE) + { + _resize_wrap_dragging = TRUE; + dt_gui_claim(gesture); + } +} + +static void _resize_wrap_button_release(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + GtkWidget *widget) +{ + if(_resize_wrap_dragging) { _resize_wrap_dragging = FALSE; dt_control_change_cursor(GDK_LEFT_PTR); - return TRUE; + dt_gui_claim(gesture); } - else if(event->y > gtk_widget_get_allocated_height(widget) - DT_RESIZE_HANDLE_SIZE - && event->type == GDK_BUTTON_PRESS - && event->button == GDK_BUTTON_PRIMARY) +} + +typedef struct _GtkDarktableScrollSizer { + GtkBox parent_instance; + GtkWidget *scroll; + const char *config_str; + gint min; +} GtkDarktableScrollSizer; + +G_DECLARE_FINAL_TYPE(GtkDarktableScrollSizer, dtgtk_scroll_sizer, DTGTK, scroll_sizer, GtkWidget) +G_DEFINE_TYPE(GtkDarktableScrollSizer, dtgtk_scroll_sizer, GTK_TYPE_WIDGET); + +static void _scroll_sizer_snapshot(GtkWidget *w, + GtkSnapshot* snapshot) +{ + GtkDarktableScrollSizer *self = (GtkDarktableScrollSizer*)w; + + gtk_widget_snapshot_child(w, self->scroll, snapshot); + + dt_gui_draw_resize_handle(w, snapshot, &GRAPHENE_RECT_INIT(0, 0, + gtk_widget_get_width(w), gtk_widget_get_height(w))); +} + +static void _scroll_sizer_measure(GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *baseline_minimum, + int *baseline_natural) +{ + GtkDarktableScrollSizer *self = (GtkDarktableScrollSizer*)widget; + + GtkWidget *child = gtk_scrolled_window_get_child(GTK_SCROLLED_WINDOW(self->scroll)); + + gtk_widget_measure(child, + orientation, + for_size, + minimum, + natural, + baseline_minimum, + baseline_natural); + + if(orientation == GTK_ORIENTATION_HORIZONTAL) return; + + gint height = dt_conf_get_int(self->config_str); + + const gint max_height = DT_PIXEL_APPLY_DPI(1000); + + if(height < 1) height = 1; + if(height > max_height) height = max_height; + + dt_conf_set_int(self->config_str, height); + + gint content_height = *natural; + + const gint min_height = self->min; + + if(content_height < min_height) content_height = min_height; + + if(height > content_height) height = content_height; + + const gint increment = _get_container_row_heigth(child); + if(increment) { - _resize_wrap_dragging = TRUE; - return TRUE; + height += increment - 1; + height -= height % increment; + + GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(self->scroll)); + gint value = gtk_adjustment_get_value(adj); + value -= value % increment; + gtk_adjustment_set_value(adj, value); } - return FALSE; + GtkBorder padding, margin; + gtk_style_context_get_padding(gtk_widget_get_style_context(child), + gtk_widget_get_state_flags(child), + &padding); + gtk_style_context_get_margin(gtk_widget_get_style_context(child), + gtk_widget_get_state_flags(child), + &margin); + height += padding.top + padding.bottom + margin.top + margin.bottom; + + *natural = *minimum = height + DT_RESIZE_HANDLE_SIZE; } -static gboolean _resize_wrap_enter_leave(GtkWidget *widget, - const GdkEventCrossing *event, - const char *config_str) +static void _scroll_sizer_size_allocate(GtkWidget *widget, + int width, int height, + int baseline) { - _resize_wrap_hovered = - event->type == GDK_ENTER_NOTIFY - || event->detail == GDK_NOTIFY_INFERIOR - || _resize_wrap_dragging ? widget : NULL; - - gtk_widget_queue_draw(widget); + GtkDarktableScrollSizer *self = (GtkDarktableScrollSizer*)widget; + gtk_widget_allocate(self->scroll, width, height, baseline, NULL); +} - if(event->mode == GDK_CROSSING_GTK_UNGRAB) - _resize_wrap_dragging = FALSE; - if(!_resize_wrap_dragging) - dt_control_change_cursor(GDK_LEFT_PTR); +static void dtgtk_scroll_sizer_class_init(GtkDarktableScrollSizerClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + widget_class->measure = _scroll_sizer_measure; + widget_class->size_allocate = _scroll_sizer_size_allocate; + widget_class->snapshot = _scroll_sizer_snapshot; +} - return FALSE; +static void dtgtk_scroll_sizer_init(GtkDarktableScrollSizer *self) +{ } GtkWidget *dt_ui_resize_wrap(GtkWidget *w, @@ -4140,6 +4188,7 @@ GtkWidget *dt_ui_resize_wrap(GtkWidget *w, if(!w) w = dtgtk_drawing_area_new_with_height(min_size); + gtk_widget_set_hexpand(w, TRUE); gtk_widget_set_has_tooltip(w, TRUE); g_object_set_data(G_OBJECT(w), "scroll-resize-tooltip", GINT_TO_POINTER(TRUE)); @@ -4155,35 +4204,25 @@ GtkWidget *dt_ui_resize_wrap(GtkWidget *w, else { GtkWidget *sw = dt_gui_scroll_wrap(w); + GtkDarktableScrollSizer *sizer = g_object_new(dtgtk_scroll_sizer_get_type(), NULL); + sizer->min = min_size; + sizer->config_str = config_str; + sizer->scroll = sw; + w = GTK_WIDGET(sizer); + gtk_widget_set_parent(sw, w); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_min_content_height - (GTK_SCROLLED_WINDOW(sw), - DT_PIXEL_APPLY_DPI(min_size)); - g_signal_connect(G_OBJECT(sw), "scroll-event", - G_CALLBACK(_resize_wrap_scroll), config_str); - g_signal_connect(G_OBJECT(w), "draw", - G_CALLBACK(_resize_wrap_draw), config_str); + GtkEventController *controller = gtk_event_controller_scroll_new(GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE); + gtk_widget_add_controller(sw, controller); + g_signal_connect(controller, "scroll", G_CALLBACK(_resize_wrap_scroll), config_str); gtk_widget_set_margin_bottom(sw, DT_RESIZE_HANDLE_SIZE); - w = gtk_event_box_new(); - gtk_container_add(GTK_CONTAINER(w), sw); } gtk_widget_add_events(w, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK | darktable.gui->scroll_mask); - g_signal_connect(G_OBJECT(w), "motion-notify-event", - G_CALLBACK(_resize_wrap_motion), config_str); - g_signal_connect(G_OBJECT(w), "button-press-event", - G_CALLBACK(_resize_wrap_button), config_str); - g_signal_connect(G_OBJECT(w), "button-release-event", - G_CALLBACK(_resize_wrap_button), config_str); - g_signal_connect(G_OBJECT(w), "enter-notify-event", - G_CALLBACK(_resize_wrap_enter_leave), config_str); - g_signal_connect(G_OBJECT(w), "leave-notify-event", - G_CALLBACK(_resize_wrap_enter_leave), config_str); - g_signal_connect_after(G_OBJECT(w), "draw", - G_CALLBACK(_resize_wrap_draw_handle), NULL); - + dt_gui_connect_click(w, _resize_wrap_button_press, _resize_wrap_button_release, w); + dt_gui_connect_motion(w, _resize_wrap_motion, _resize_wrap_enter, _resize_wrap_leave, config_str); return w; } @@ -4245,8 +4284,14 @@ static void _delete_child(GtkWidget *widget, void dt_gui_container_destroy_children(GtkContainer *container) { - g_return_if_fail(GTK_IS_CONTAINER(container)); - gtk_container_foreach(container, _delete_child, NULL); + GtkWidget *child = gtk_widget_get_first_child(GTK_WIDGET(container)); + while(child) + { + GtkWidget *next = gtk_widget_get_next_sibling(child); + gtk_widget_unparent(child); + // g_object_unref(child); + child = next; + } } void dt_gui_menu_popup(GtkMenu *menu, @@ -4398,12 +4443,8 @@ void dt_gui_new_collapsible_section(dt_gui_collapsible_section_t *cs, cs->module = module; // collapsible section header - GtkWidget *destdisp_head = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_BAUHAUS_SPACE); - GtkWidget *header_evb = gtk_event_box_new(); GtkWidget *destdisp = dt_ui_section_label_new(label); cs->label = destdisp; - dt_gui_add_class(destdisp_head, "dt_section_expander"); - gtk_container_add(GTK_CONTAINER(header_evb), destdisp); cs->toggle = dtgtk_togglebutton_new(dtgtk_cairo_paint_solid_arrow, (expanded @@ -4416,19 +4457,17 @@ void dt_gui_new_collapsible_section(dt_gui_collapsible_section_t *cs, cs->container = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_BAUHAUS_SPACE)); gtk_widget_set_name(GTK_WIDGET(cs->container), "collapsible"); - gtk_box_pack_start(GTK_BOX(destdisp_head), header_evb, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(destdisp_head), cs->toggle, FALSE, FALSE, 0); + g_signal_connect(G_OBJECT(cs->toggle), "toggled", + G_CALLBACK(_collapse_button_changed), cs); + g_signal_connect(G_OBJECT(cs->toggle), "button-press-event", // GTK4 should be whole header (but button-press only works on dtgtk) + G_CALLBACK(_collapse_expander_click), cs); + GtkWidget *destdisp_head = dt_gui_hbox(dt_gui_expand(destdisp), cs->toggle); + dt_gui_add_class(destdisp_head, "dt_section_expander"); cs->expander = dtgtk_expander_new(destdisp_head, GTK_WIDGET(cs->container)); gtk_box_pack_end(cs->parent, cs->expander, FALSE, FALSE, 0); dtgtk_expander_set_expanded(DTGTK_EXPANDER(cs->expander), expanded); gtk_widget_set_name(cs->expander, "collapse-block"); - - g_signal_connect(G_OBJECT(cs->toggle), "toggled", - G_CALLBACK(_collapse_button_changed), cs); - - g_signal_connect(G_OBJECT(header_evb), "button-press-event", - G_CALLBACK(_collapse_expander_click), cs); } void dt_gui_collapsible_section_set_label(dt_gui_collapsible_section_t *cs, @@ -4460,11 +4499,9 @@ GtkGestureSingle *(dt_gui_connect_click)(GtkWidget *widget, GCallback released, gpointer data) { - GtkGesture *gesture = gtk_gesture_multi_press_new(widget); - g_object_weak_ref(G_OBJECT (widget), (GWeakNotify) g_object_unref, gesture); - // GTK4 GtkGesture *gesture = gtk_gesture_click_new(); - // gtk_widget_add_controller(widget, GTK_EVENT_CONTROLLER(gesture)); - + GtkGesture *gesture = gtk_gesture_click_new(); + gtk_widget_add_controller(widget, GTK_EVENT_CONTROLLER(gesture)); + if(pressed) g_signal_connect(gesture, "pressed", pressed, data); if(released) { @@ -4481,12 +4518,9 @@ GtkEventController *(dt_gui_connect_motion)(GtkWidget *widget, GCallback leave, gpointer data) { - GtkEventController *controller = gtk_event_controller_motion_new(widget); + GtkEventController *controller = gtk_event_controller_motion_new(); gtk_event_controller_set_propagation_phase(controller, GTK_PHASE_TARGET); - g_object_weak_ref(G_OBJECT (widget), (GWeakNotify) g_object_unref, controller); - // GTK4 gtk_widget_add_controller(widget, GTK_EVENT_CONTROLLER(controller)); - - gtk_widget_add_events(widget, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); // still needed for now by _main_do_event_keymap + gtk_widget_add_controller(widget, controller); if(motion) g_signal_connect(controller, "motion", motion, data); if(enter) g_signal_connect(controller, "enter", enter, data); @@ -4511,7 +4545,7 @@ void dt_gui_cursor_set_busy() GdkWindow *window = gtk_widget_get_window(toplevel); busy_prev_cursor = gdk_window_get_cursor(window); g_object_ref(busy_prev_cursor); - GdkCursor *watch = gdk_cursor_new_for_display(gtk_widget_get_display(toplevel), GDK_WATCH); + GdkCursor *watch = gdk_cursor_new_from_name(gtk_widget_get_display(toplevel), "wait"); gdk_window_set_cursor(window, watch); g_object_unref(watch); // since the main reason for calling this function is that we won't be running the Gtk main @@ -4598,7 +4632,7 @@ GtkWidget *(dt_gui_box_add)(const char *file, const int line, const char *functi else if(gtk_widget_get_parent(*list)) dt_print(DT_DEBUG_ALWAYS, "%s:%d %s: trying to add widget that already has a parent to box (#%d)", file, line, function, i); else - gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(*list)); // GTK4 gtk_box_append + gtk_box_append(box, GTK_WIDGET(*list)); } return GTK_WIDGET(box); diff --git a/src/gui/gtk.h b/src/gui/gtk.h index 8ee46777e981..e5eb39eb72bb 100644 --- a/src/gui/gtk.h +++ b/src/gui/gtk.h @@ -395,6 +395,7 @@ void dt_ellipsize_combo(GtkComboBox *cbox); static inline void dt_ui_section_label_set(GtkWidget *label) { + gtk_widget_set_hexpand(label, TRUE); // GTK4 gtk_widget_set_halign(label, GTK_ALIGN_FILL); // make it span the whole available width gtk_label_set_xalign (GTK_LABEL(label), 0.5f); gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END); // ellipsize labels @@ -573,6 +574,8 @@ GtkEventController *(dt_gui_connect_motion)(GtkWidget *widget, #define dt_modifier_eq(controller, mask)\ dt_modifier_is(dt_key_modifier_state(), mask) +#define dt_controller_state(controller) gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(controller)) + // control whether the mouse pointer displays as a "busy" cursor, e.g. watch or timer // the calls may be nested, but must be matched void dt_gui_cursor_set_busy(); @@ -624,6 +627,10 @@ static inline GtkWidget *dt_gui_scroll_wrap(GtkWidget *widget) return scrolled_window; } +void dt_gui_draw_resize_handle(GtkWidget *widget, + GtkSnapshot *snapshot, + graphene_rect_t *bounds); + // Simulate a mouse button event (button is 1, 2, 3 - mouse button) sent to a Widget void dt_gui_simulate_button_event(GtkWidget *widget, const GdkEventType eventtype, diff --git a/src/gui/guides.c b/src/gui/guides.c index f0060e522370..483c80f0dedb 100644 --- a/src/gui/guides.c +++ b/src/gui/guides.c @@ -1017,8 +1017,6 @@ static void _settings_autoshow_menu(GtkWidget *button, GtkWidget *popover = darktable.view_manager->guides_popover; gtk_popover_set_relative_to(GTK_POPOVER(popover), button); - g_object_set(G_OBJECT(popover), "transitions-enabled", FALSE, NULL); - dt_guides_update_popover_values(); gtk_widget_show_all(popover); diff --git a/src/gui/import_metadata.c b/src/gui/import_metadata.c index a30ec603d09a..a11d74d0b133 100644 --- a/src/gui/import_metadata.c +++ b/src/gui/import_metadata.c @@ -420,16 +420,16 @@ static void _fill_metadata_grid(dt_import_metadata_t *metadata) const char *str = dt_conf_get_string_const(setting); _set_up_entry(metadata_entry, str, metadata_name, i + DT_META_META_VALUE, metadata); g_free(setting); - g_signal_connect(GTK_ENTRY(metadata_entry), "changed", + g_signal_connect(metadata_entry, "changed", G_CALLBACK(_import_metadata_changed), metadata); - g_signal_connect(GTK_EVENT_BOX(labelev), "button-press-event", + g_signal_connect(labelev, "button-press-event", G_CALLBACK(_import_metadata_reset), metadata_entry); GtkWidget *metadata_imported = gtk_check_button_new(); g_object_set_data(G_OBJECT(metadata_imported), "tagname", md->tagname); _set_up_toggle_button(metadata_imported, flag & DT_METADATA_FLAG_IMPORTED, metadata_name, i + DT_META_META_VALUE, metadata); - g_signal_connect(GTK_TOGGLE_BUTTON(metadata_imported), "toggled", + g_signal_connect(metadata_imported, "toggled", G_CALLBACK(_import_metadata_toggled), metadata); i++; } @@ -459,7 +459,7 @@ void dt_import_metadata_init(dt_import_metadata_t *metadata) gtk_widget_set_tooltip_text(GTK_WIDGET(label), _("metadata to be applied per default" "\ndouble-click on a label to clear the corresponding entry" "\ndouble-click on 'preset' to clear all entries")); - g_signal_connect(GTK_EVENT_BOX(labelev), "button-press-event", + g_signal_connect(labelev, "button-press-event", G_CALLBACK(_import_metadata_reset_all), metadata); @@ -495,15 +495,15 @@ void dt_import_metadata_init(dt_import_metadata_t *metadata) const char *str = dt_conf_get_string_const("ui_last/import_last_tags"); _set_up_entry(entry, str, "tags", metadata->num_grid_rows + DT_META_TAGS_HEADER, metadata); gtk_widget_set_tooltip_text(entry, _("comma separated list of tags")); - g_signal_connect(GTK_ENTRY(entry), "changed", + g_signal_connect(entry, "changed", G_CALLBACK(_import_tags_changed), metadata); - g_signal_connect(GTK_EVENT_BOX(labelev), "button-press-event", + g_signal_connect(labelev, "button-press-event", G_CALLBACK(_import_metadata_reset), entry); GtkWidget *tags_imported = gtk_check_button_new(); _set_up_toggle_button(tags_imported, dt_conf_get_bool("ui_last/import_last_tags_imported"), "tags", metadata->num_grid_rows + DT_META_TAGS_HEADER, metadata); - g_signal_connect(GTK_TOGGLE_BUTTON(tags_imported), "toggled", + g_signal_connect(tags_imported, "toggled", G_CALLBACK(_import_metadata_toggled), metadata); // overall diff --git a/src/gui/preferences.c b/src/gui/preferences.c index d839bb1257f2..f26c576e638e 100644 --- a/src/gui/preferences.c +++ b/src/gui/preferences.c @@ -211,7 +211,7 @@ static void save_usercss(GtkTextBuffer *buffer) // write to file GError *error = NULL; - if(!g_file_set_contents(usercsspath, usercsscontent, -1, &error)) + if(!g_file_set_contents(usercsspath, usercsscontent, -1, &error) && error) { dt_print(DT_DEBUG_ALWAYS, "%s: error saving css to %s: %s", G_STRFUNC, usercsspath, error->message); @@ -606,7 +606,7 @@ void dt_gui_preferences_show() GtkGrid* lua_grid = init_tab_lua(_preferences_dialog, stack); #endif - gtk_widget_show_all(_preferences_dialog); + gtk_widget_show(_preferences_dialog); //open in the appropriate tab if currently in darkroom or lighttable view const gchar *current_view = dt_view_manager_name(darktable.view_manager); @@ -987,7 +987,7 @@ static void init_tab_presets(GtkWidget *stack) GtkWidget *search_presets = gtk_search_entry_new(); gtk_box_pack_start(GTK_BOX(hbox), search_presets, FALSE, TRUE, 0); - gtk_entry_set_placeholder_text(GTK_ENTRY(search_presets), _("search presets list")); + gtk_search_entry_set_placeholder_text(GTK_SEARCH_ENTRY(search_presets), _("search presets list")); gtk_widget_set_tooltip_text (GTK_WIDGET(search_presets), _("incrementally search the list of presets\n" diff --git a/src/gui/splash.c b/src/gui/splash.c index b8f0e0ed2da6..0d5bec9a035f 100644 --- a/src/gui/splash.c +++ b/src/gui/splash.c @@ -149,15 +149,15 @@ void darktable_splash_screen_create(GtkWindow *parent_window, #else GtkDialogFlags flags = GTK_DIALOG_DESTROY_WITH_PARENT; #endif - splash_screen = - gtk_dialog_new_with_buttons(_("darktable starting"), - parent_window, flags, - NULL, - GTK_RESPONSE_NONE, // <-- fake button list for compiler - NULL); + g_set_weak_pointer(&splash_screen, + gtk_dialog_new_with_buttons(_("darktable starting"), + parent_window, flags, + NULL, + GTK_RESPONSE_NONE, // <-- fake button list for compiler + NULL)); gtk_window_set_position(GTK_WINDOW(splash_screen), GTK_WIN_POS_CENTER); gtk_widget_set_name(splash_screen, "splashscreen"); - progress_text = gtk_label_new(_("initializing")); + g_set_weak_pointer(&progress_text, gtk_label_new(_("initializing"))); gtk_widget_set_name(progress_text, "splashscreen-progress"); remaining_text = gtk_label_new(""); gtk_widget_set_name(remaining_text, "splashscreen-remaining"); @@ -291,12 +291,7 @@ void darktable_splash_screen_set_progress_percent(const char *msg, void darktable_splash_screen_destroy() { if(splash_screen) - { - gtk_widget_destroy(progress_text); - progress_text = NULL; - gtk_widget_destroy(splash_screen); - splash_screen = NULL; - } + gtk_window_destroy(GTK_WINDOW(splash_screen)); } void darktable_exit_screen_create(GtkWindow *parent_window, diff --git a/src/iop/atrous.c b/src/iop/atrous.c index 1ea3d3282364..d232585e8b85 100644 --- a/src/iop/atrous.c +++ b/src/iop/atrous.c @@ -1079,17 +1079,23 @@ void gui_update(dt_iop_module_t *self) // gui stuff: -static gboolean area_enter_leave_notify(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self) +static void _atrous_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_atrous_gui_data_t *g = self->gui_data; - g->in_curve = event->type == GDK_ENTER_NOTIFY; + g->in_curve = controller == NULL; if(!g->dragging) g->x_move = -1; - gtk_widget_queue_draw(widget); - return FALSE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); +} + +static void _atrous_enter(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) +{ + _atrous_leave(NULL, self); } // fills in new parameters based on mouse position (in 0,1) @@ -1426,19 +1432,21 @@ static gboolean area_draw(GtkWidget *widget, return FALSE; } -static gboolean area_motion_notify(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self) +static void _atrous_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { dt_iop_atrous_gui_data_t *g = self->gui_data; dt_iop_atrous_params_t *p = self->params; + const int inset = INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); const int height = allocation.height - 2 * inset - DT_RESIZE_HANDLE_SIZE; const int width = allocation.width - 2 * inset; - if(!g->dragging) g->mouse_x = CLAMP(event->x - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(event->y - inset, 0, height) / (float)height; + if(!g->dragging) g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; darktable.control->element = 0; @@ -1452,7 +1460,7 @@ static gboolean area_motion_notify(GtkWidget *widget, *p = g->drag_params; if(g->x_move >= 0) { - const float mx = CLAMP(event->x - inset, 0, width) / (float)width; + const float mx = CLAMP(x - inset, 0, width) / (float)width; if(g->x_move > 0 && g->x_move < BANDS - 1) { const float minx = p->x[g->channel][g->x_move - 1] + 0.001f; @@ -1464,10 +1472,9 @@ static gboolean area_motion_notify(GtkWidget *widget, { get_params(p, g->channel2, g->mouse_x, g->mouse_y + g->mouse_pick, g->mouse_radius); } - gtk_widget_queue_draw(widget); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + g->channel); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area + g->channel); } - else if(event->y > height) + else if(y > height) { // move x-positions g->x_move = 0; @@ -1482,8 +1489,6 @@ static gboolean area_motion_notify(GtkWidget *widget, } } darktable.control->element = g->x_move + 1; - - gtk_widget_queue_draw(widget); } else { @@ -1504,61 +1509,57 @@ static gboolean area_motion_notify(GtkWidget *widget, } // don't move x-positions: g->x_move = -1; - gtk_widget_queue_draw(widget); } - return TRUE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } -static gboolean area_button_press(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _atrous_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - if(event->button == GDK_BUTTON_PRIMARY && event->type == GDK_2BUTTON_PRESS) + dt_iop_atrous_gui_data_t *g = self->gui_data; + if(n_press == 2) { // reset current curve dt_iop_atrous_params_t *p = self->params; const dt_iop_atrous_params_t *const d = self->default_params; - dt_iop_atrous_gui_data_t *g = self->gui_data; reset_mix(self); for(int k = 0; k < BANDS; k++) { p->x[g->channel2][k] = d->x[g->channel2][k]; p->y[g->channel2][k] = d->y[g->channel2][k]; } - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + g->channel2); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area + g->channel2); } - else if(event->button == GDK_BUTTON_PRIMARY) + else { // set active point - dt_iop_atrous_gui_data_t *g = self->gui_data; reset_mix(self); const int inset = INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); const int height = allocation.height - 2 * inset - DT_RESIZE_HANDLE_SIZE; const int width = allocation.width - 2 * inset; g->mouse_pick = dt_draw_curve_calc_value(g->minmax_curve, - CLAMP(event->x - inset, 0, width) / (float)width); - g->mouse_pick -= 1.0 - CLAMP(event->y - inset, 0, height) / (float)height; + CLAMP(x - inset, 0, width) / (float)width); + g->mouse_pick -= 1.0 - CLAMP(y - inset, 0, height) / (float)height; g->dragging = 1; - return TRUE; + dt_gui_claim(gesture); } - return FALSE; } -static gboolean area_button_release(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _atrous_button_release(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - if(event->button == GDK_BUTTON_PRIMARY) - { - dt_iop_atrous_gui_data_t *g = self->gui_data; - g->dragging = 0; - reset_mix(self); - return TRUE; - } - return FALSE; + dt_iop_atrous_gui_data_t *g = self->gui_data; + g->dragging = 0; + reset_mix(self); } static gboolean area_scrolled(GtkWidget *widget, @@ -1810,16 +1811,8 @@ void gui_init(dt_iop_module_t *self) dt_action_define_iop(self, NULL, N_("graph"), GTK_WIDGET(g->area), &_action_def_equalizer); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(area_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(area_button_press), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", - G_CALLBACK(area_button_release), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(area_motion_notify), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", - G_CALLBACK(area_enter_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "enter-notify-event", - G_CALLBACK(area_enter_leave_notify), self); + dt_gui_connect_click(g->area, _atrous_button_press, _atrous_button_release, self); + dt_gui_connect_motion(g->area, _atrous_motion, _atrous_enter, _atrous_leave, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(area_scrolled), self); diff --git a/src/iop/basecurve.c b/src/iop/basecurve.c index a222747199a6..5139395ffb75 100644 --- a/src/iop/basecurve.c +++ b/src/iop/basecurve.c @@ -1565,15 +1565,14 @@ void cleanup_global(dt_iop_module_so_t *self) self->data = NULL; } -static gboolean dt_iop_basecurve_leave_notify(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self) +static void _basecurve_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { + GdkModifierType state = gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(controller)); dt_iop_basecurve_gui_data_t *g = self->gui_data; - if(!(event->state & GDK_BUTTON1_MASK)) + if(!(state & GDK_BUTTON1_MASK)) g->selected = -1; - gtk_widget_queue_draw(widget); - return FALSE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } static float to_log(const float x, const float base) @@ -1810,9 +1809,10 @@ static gboolean _move_point_internal(dt_iop_module_t *self, float dy, const guint state); -static gboolean dt_iop_basecurve_motion_notify(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self) +static void _basecurve_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { dt_iop_basecurve_gui_data_t *g = self->gui_data; dt_iop_basecurve_params_t *p = self->params; @@ -1821,19 +1821,20 @@ static gboolean dt_iop_basecurve_motion_notify(GtkWidget *widget, dt_iop_basecurve_node_t *basecurve = p->basecurve[ch]; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); const int inset = DT_GUI_CURVE_EDITOR_INSET; int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; const double old_m_x = g->mouse_x; const double old_m_y = g->mouse_y; - g->mouse_x = event->x - inset; - g->mouse_y = event->y - inset; + g->mouse_x = x - inset; + g->mouse_y = y - inset; const float mx = CLAMP(g->mouse_x, 0, width) / (float)width; const float my = 1.0f - CLAMP(g->mouse_y, 0, height) / (float)height; const float linx = to_lin(mx, g->loglogscale), liny = to_lin(my, g->loglogscale); - if(event->state & GDK_BUTTON1_MASK) + GdkModifierType state = dt_controller_state(controller); + if(!(state & GDK_BUTTON1_MASK)) { // got a vertex selected: if(g->selected >= 0) @@ -1847,13 +1848,14 @@ static gboolean dt_iop_basecurve_motion_notify(GtkWidget *widget, const float dy = to_lin(1 - g->mouse_y / height - translate_mouse_y, g->loglogscale) - to_lin(1 - old_m_y / height - translate_mouse_y, g->loglogscale); - return _move_point_internal(self, widget, dx, dy, event->state); + _move_point_internal(self, GTK_WIDGET(g->area), dx, dy, state); + return; } else if(nodes < MAXNODES && g->selected >= -1) { // no vertex was close, create a new one! g->selected = _add_node(basecurve, &p->basecurve_nodes[ch], linx, liny); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area); } } else @@ -1875,14 +1877,15 @@ static gboolean dt_iop_basecurve_motion_notify(GtkWidget *widget, } g->selected = nearest; } - if(g->selected >= 0) gtk_widget_grab_focus(widget); - gtk_widget_queue_draw(widget); - return TRUE; + if(g->selected >= 0) gtk_widget_grab_focus(GTK_WIDGET(g->area)); + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } -static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _basecurve_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { dt_iop_basecurve_params_t *p = self->params; const dt_iop_basecurve_params_t *const d = self->default_params; @@ -1892,18 +1895,20 @@ static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, int nodes = p->basecurve_nodes[ch]; dt_iop_basecurve_node_t *basecurve = p->basecurve[ch]; - if(event->button == GDK_BUTTON_PRIMARY) + dt_gui_claim(gesture); + guint button = gtk_gesture_single_get_current_button(gesture); + if(button == GDK_BUTTON_PRIMARY) { - if(event->type == GDK_BUTTON_PRESS && dt_modifier_is(event->state, GDK_CONTROL_MASK) + if(n_press == 1 && dt_modifier_eq(gesture, GDK_CONTROL_MASK) && nodes < MAXNODES && g->selected == -1) { // if we are not on a node -> add a new node at the current x of the pointer and y of the curve at that x const int inset = DT_GUI_CURVE_EDITOR_INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); int width = allocation.width - 2 * inset; - g->mouse_x = event->x - inset; - g->mouse_y = event->y - inset; + g->mouse_x = x - inset; + g->mouse_y = y - inset; const float mx = CLAMP(g->mouse_x, 0, width) / (float)width; const float linx = to_lin(mx, g->loglogscale); @@ -1930,12 +1935,12 @@ static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, (selected < nodes && basecurve[selected].x - linx <= 0.025))) { // evaluate the curve at the current x position - const float y = dt_draw_curve_calc_value(g->minmax_curve, linx); + const float calc_y = dt_draw_curve_calc_value(g->minmax_curve, linx); - if(y >= 0.0 && y <= 1.0) // never add something outside the viewport, you couldn't change it afterwards + if(calc_y >= 0.0 && calc_y <= 1.0) // never add something outside the viewport, you couldn't change it afterwards { // create a new node - selected = _add_node(basecurve, &p->basecurve_nodes[ch], linx, y); + selected = _add_node(basecurve, &p->basecurve_nodes[ch], linx, calc_y); // maybe set the new one as being selected float min = .04f; @@ -1943,17 +1948,16 @@ static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, for(int k = 0; k < nodes; k++) { float other_y = to_log(basecurve[k].y, g->loglogscale); - float dist = (y - other_y) * (y - other_y); + float dist = (calc_y - other_y) * (calc_y - other_y); if(dist < min) g->selected = selected; } - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } } - return TRUE; } - else if(event->type == GDK_2BUTTON_PRESS) + else if(n_press == 2) { // reset current curve p->basecurve_nodes[ch] = d->basecurve_nodes[ch]; @@ -1964,20 +1968,19 @@ static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, p->basecurve[ch][k].y = d->basecurve[ch][k].y; } g->selected = -2; // avoid motion notify re-inserting immediately. - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area); gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; } } - else if(event->button == GDK_BUTTON_SECONDARY && g->selected >= 0) + else if(button == GDK_BUTTON_SECONDARY && g->selected >= 0) { if(g->selected == 0 || g->selected == nodes - 1) { float reset_value = g->selected == 0 ? 0 : 1; basecurve[g->selected].y = basecurve[g->selected].x = reset_value; gtk_widget_queue_draw(GTK_WIDGET(g->area)); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget); - return TRUE; + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area); + return; } for(int k = g->selected; k < nodes - 1; k++) @@ -1989,10 +1992,8 @@ static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, g->selected = -2; // avoid re-insertion of that point immediately after this p->basecurve_nodes[ch]--; gtk_widget_queue_draw(GTK_WIDGET(g->area)); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget); - return TRUE; + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area); } - return FALSE; } static gboolean _move_point_internal(dt_iop_module_t *self, @@ -2164,9 +2165,8 @@ void gui_init(dt_iop_module_t *self) | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(dt_iop_basecurve_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", G_CALLBACK(dt_iop_basecurve_button_press), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", G_CALLBACK(dt_iop_basecurve_motion_notify), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", G_CALLBACK(dt_iop_basecurve_leave_notify), self); + dt_gui_connect_click_all(g->area, _basecurve_button_press, NULL, self); + dt_gui_connect_motion(g->area, _basecurve_motion, NULL, _basecurve_leave, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(_scrolled), self); g_signal_connect(G_OBJECT(g->area), "key-press-event", G_CALLBACK(dt_iop_basecurve_key_press), self); } diff --git a/src/iop/bilat.c b/src/iop/bilat.c index 698dbc8aaebb..819e81d420a5 100644 --- a/src/iop/bilat.c +++ b/src/iop/bilat.c @@ -491,11 +491,11 @@ void gui_init(dt_iop_module_t *self) " increase for more powerful local contrast")); // work around multi-instance issue which calls show all a fair bit: - g_object_set(G_OBJECT(g->highlights), "no-show-all", TRUE, NULL); - g_object_set(G_OBJECT(g->shadows), "no-show-all", TRUE, NULL); - g_object_set(G_OBJECT(g->midtone), "no-show-all", TRUE, NULL); - g_object_set(G_OBJECT(g->range), "no-show-all", TRUE, NULL); - g_object_set(G_OBJECT(g->spatial), "no-show-all", TRUE, NULL); + gtk_widget_set_no_show_all(g->highlights, TRUE); + gtk_widget_set_no_show_all(g->shadows, TRUE); + gtk_widget_set_no_show_all(g->midtone, TRUE); + gtk_widget_set_no_show_all(g->range, TRUE); + gtk_widget_set_no_show_all(g->spatial, TRUE); } diff --git a/src/iop/colorbalance.c b/src/iop/colorbalance.c index 0ca694cb4b5e..44274c5b04fb 100644 --- a/src/iop/colorbalance.c +++ b/src/iop/colorbalance.c @@ -1720,7 +1720,7 @@ static void _configure_slider_blocks(gpointer instance, dt_iop_module_t *self) for(int i=0; i<3; i++) { g_object_ref(G_OBJECT(g->blocks[i])); - if(old_container) gtk_container_remove(GTK_CONTAINER(old_container), g->blocks[i]); + // GTK4 if(old_container) gtk_container_remove(GTK_CONTAINER(old_container), g->blocks[i]); } if(old_container) gtk_widget_destroy(old_container); diff --git a/src/iop/colorchecker.c b/src/iop/colorchecker.c index 41e0b5237e34..957fd58bf781 100644 --- a/src/iop/colorchecker.c +++ b/src/iop/colorchecker.c @@ -1379,22 +1379,22 @@ static gboolean checker_draw(GtkWidget *widget, return TRUE; } -static gboolean checker_motion_notify( - GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self) +static void _colorchecker_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { // highlight? dt_iop_colorchecker_params_t *p = self->params; dt_iop_colorchecker_gui_data_t *g = self->gui_data; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); const int width = allocation.width; const int height = allocation.height; - const float mouse_x = CLAMP(event->x, 0, width); - const float mouse_y = CLAMP(event->y, 0, height); + const float mouse_x = CLAMP(x, 0, width); + const float mouse_y = CLAMP(y, 0, height); int cells_x = 6, cells_y = 4; if(p->num_patches > 24) { @@ -1404,7 +1404,7 @@ static gboolean checker_motion_notify( const float mx = mouse_x * cells_x / (float)width; const float my = mouse_y * cells_y / (float)height; const int patch = (int)mx + cells_x * (int)my; - if(patch < 0 || patch >= p->num_patches) return FALSE; + if(patch < 0 || patch >= p->num_patches) return; char tooltip[1024]; snprintf(tooltip, sizeof(tooltip), _("(%2.2f %2.2f %2.2f)\n" @@ -1415,21 +1415,22 @@ static gboolean checker_motion_notify( "shift+click while color picking to replace patch"), p->source_L[patch], p->source_a[patch], p->source_b[patch]); gtk_widget_set_tooltip_text(g->area, tooltip); - return TRUE; } -static gboolean checker_button_press( - GtkWidget *widget, GdkEventButton *event, - dt_iop_module_t *self) +static void _colorchecker_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { dt_iop_colorchecker_params_t *p = self->params; dt_iop_colorchecker_gui_data_t *g = self->gui_data; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); int width = allocation.width, height = allocation.height; - const float mouse_x = CLAMP(event->x, 0, width); - const float mouse_y = CLAMP(event->y, 0, height); + const float mouse_x = CLAMP(x, 0, width); + const float mouse_y = CLAMP(y, 0, height); int cells_x = 6, cells_y = 4; if(p->num_patches > 24) { @@ -1439,9 +1440,12 @@ static gboolean checker_button_press( const float mx = mouse_x * cells_x / (float)width; const float my = mouse_y * cells_y / (float)height; int patch = (int)mx + cells_x*(int)my; - if(event->button == GDK_BUTTON_PRIMARY && event->type == GDK_2BUTTON_PRESS) + + dt_gui_claim(gesture); + guint button = gtk_gesture_single_get_current_button(gesture); + if(button == GDK_BUTTON_PRIMARY && n_press == 2) { // reset on double click - if(patch < 0 || patch >= p->num_patches) return FALSE; + if(patch < 0 || patch >= p->num_patches) return; p->target_L[patch] = p->source_L[patch]; p->target_a[patch] = p->source_a[patch]; p->target_b[patch] = p->source_b[patch]; @@ -1450,12 +1454,13 @@ static gboolean checker_button_press( _colorchecker_update_sliders(self); --darktable.gui->reset; gtk_widget_queue_draw(g->area); - return TRUE; + dt_gui_claim(gesture); + return; } - else if(event->button == GDK_BUTTON_SECONDARY && (patch < p->num_patches)) + else if(button == GDK_BUTTON_SECONDARY && (patch < p->num_patches)) { // right click: delete patch, move others up - if(patch < 0 || patch >= p->num_patches) return FALSE; + if(patch < 0 || patch >= p->num_patches) return; memmove(p->target_L+patch, p->target_L+patch+1, sizeof(float)*(p->num_patches-1-patch)); memmove(p->target_a+patch, p->target_a+patch+1, @@ -1475,10 +1480,11 @@ static gboolean checker_button_press( _colorchecker_update_sliders(self); --darktable.gui->reset; gtk_widget_queue_draw(g->area); - return TRUE; + dt_gui_claim(gesture); + return; } - else if((event->button == GDK_BUTTON_PRIMARY) && - dt_modifier_is(event->state, GDK_SHIFT_MASK) && + else if((button == GDK_BUTTON_PRIMARY) && + dt_modifier_eq(gesture, GDK_SHIFT_MASK) && (self->request_color_pick == DT_REQUEST_COLORPICK_MODULE)) { // shift-left while colour picking: replace source colour @@ -1519,11 +1525,12 @@ static gboolean checker_button_press( g->patch = g->drawn_patch = patch; gtk_widget_queue_draw(g->area); } - return TRUE; + dt_gui_claim(gesture); + return; } if(patch >= p->num_patches) patch = p->num_patches-1; dt_bauhaus_combobox_set(g->combobox_patch, patch); - return FALSE; + return; } void gui_init(dt_iop_module_t *self) @@ -1533,16 +1540,10 @@ void gui_init(dt_iop_module_t *self) // custom 24-patch widget in addition to combo box g->area = dtgtk_drawing_area_new_with_aspect_ratio(4.0/6.0); - gtk_widget_add_events(GTK_WIDGET(g->area), - GDK_POINTER_MOTION_MASK - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_LEAVE_NOTIFY_MASK); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(checker_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(checker_button_press), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(checker_motion_notify), self); + dt_gui_connect_click_all(g->area, _colorchecker_button_press, NULL, self); + dt_gui_connect_motion(g->area, _colorchecker_motion, NULL, NULL, self); g->patch = 0; g->drawn_patch = -1; diff --git a/src/iop/colorcorrection.c b/src/iop/colorcorrection.c index 8a7551e3c5b4..719177ab789c 100644 --- a/src/iop/colorcorrection.c +++ b/src/iop/colorcorrection.c @@ -219,12 +219,17 @@ void gui_update(dt_iop_module_t *self) static gboolean dt_iop_colorcorrection_draw(GtkWidget *widget, cairo_t *cr, dt_iop_module_t *self); -static gboolean dt_iop_colorcorrection_motion_notify(GtkWidget *widget, GdkEventMotion *event, - dt_iop_module_t *self); -static gboolean dt_iop_colorcorrection_button_press(GtkWidget *widget, GdkEventButton *event, - dt_iop_module_t *self); -static gboolean dt_iop_colorcorrection_leave_notify(GtkWidget *widget, GdkEventCrossing *event, - dt_iop_module_t *self); +static void _colorcorrection_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self); +static void _colorcorrection_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self); +static void _colorcorrection_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self); static gboolean dt_iop_colorcorrection_scrolled(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self); static gboolean dt_iop_colorcorrection_key_press(GtkWidget *widget, GdkEventKey *event, @@ -242,17 +247,11 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("drag the line for split-toning. " "bright means highlights, dark means shadows. " "use mouse wheel to change saturation.")); - gtk_widget_add_events(GTK_WIDGET(g->area), GDK_POINTER_MOTION_MASK | darktable.gui->scroll_mask - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); + gtk_widget_add_events(GTK_WIDGET(g->area), darktable.gui->scroll_mask); gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(dt_iop_colorcorrection_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", G_CALLBACK(dt_iop_colorcorrection_button_press), - self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", G_CALLBACK(dt_iop_colorcorrection_motion_notify), - self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", G_CALLBACK(dt_iop_colorcorrection_leave_notify), - self); + dt_gui_connect_click(g->area, _colorcorrection_button_press, NULL, self); + dt_gui_connect_motion(g->area, _colorcorrection_motion, NULL, _colorcorrection_leave, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(dt_iop_colorcorrection_scrolled), self); g_signal_connect(G_OBJECT(g->area), "key-press-event", G_CALLBACK(dt_iop_colorcorrection_key_press), self); @@ -346,20 +345,22 @@ static gboolean dt_iop_colorcorrection_draw(GtkWidget *widget, cairo_t *crf, dt_ return TRUE; } -static gboolean dt_iop_colorcorrection_motion_notify(GtkWidget *widget, GdkEventMotion *event, - dt_iop_module_t *self) +static void _colorcorrection_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { dt_iop_colorcorrection_gui_data_t *g = self->gui_data; dt_iop_colorcorrection_params_t *p = self->params; const int inset = DT_COLORCORRECTION_INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); int width = allocation.width - 2 * inset, height = allocation.height - 2 * inset; - const float mouse_x = CLAMP(event->x - inset, 0, width); - const float mouse_y = CLAMP(height - 1 - event->y + inset, 0, height); + const float mouse_x = CLAMP(x - inset, 0, width); + const float mouse_y = CLAMP(height - 1 - y + inset, 0, height); const float ma = (2.0 * mouse_x - width) * DT_COLORCORRECTION_MAX / (float)width; const float mb = (2.0 * mouse_y - height) * DT_COLORCORRECTION_MAX / (float)height; - if(event->state & GDK_BUTTON1_MASK) + if(dt_controller_state(controller) & GDK_BUTTON1_MASK) { if(g->selected == 1) { @@ -385,15 +386,18 @@ static gboolean dt_iop_colorcorrection_motion_notify(GtkWidget *widget, GdkEvent else if(disthi < thrs * thrs && disthi <= distlo) g->selected = 2; } - if(g->selected > 0) gtk_widget_grab_focus(widget); + if(g->selected > 0) gtk_widget_grab_focus(GTK_WIDGET(g->area)); gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; } -static gboolean dt_iop_colorcorrection_button_press(GtkWidget *widget, GdkEventButton *event, - dt_iop_module_t *self) +static void _colorcorrection_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - if(event->button == GDK_BUTTON_PRIMARY && event->type == GDK_2BUTTON_PRESS) + dt_gui_claim(gesture); + if(n_press == 2) { // double click resets: dt_iop_colorcorrection_gui_data_t *g = self->gui_data; @@ -415,17 +419,14 @@ static gboolean dt_iop_colorcorrection_button_press(GtkWidget *widget, GdkEventB dt_dev_add_history_item(darktable.develop, self, TRUE); } } - return TRUE; } - return FALSE; } -static gboolean dt_iop_colorcorrection_leave_notify(GtkWidget *widget, GdkEventCrossing *event, - dt_iop_module_t *self) +static void _colorcorrection_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_colorcorrection_gui_data_t *g = self->gui_data; gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; } static gboolean dt_iop_colorcorrection_scrolled(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self) diff --git a/src/iop/colorequal.c b/src/iop/colorequal.c index eb44791463e4..ba3821a0ab3f 100644 --- a/src/iop/colorequal.c +++ b/src/iop/colorequal.c @@ -2742,76 +2742,68 @@ static gboolean _area_scrolled_callback(GtkWidget *widget, return gtk_widget_event(w, (GdkEvent*)event); } -static gboolean _area_motion_notify_callback(GtkWidget *widget, - const GdkEventMotion *event, - const dt_iop_module_t *self) +static void _colorequal_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { dt_iop_colorequal_gui_data_t *g = self->gui_data; if(g->dragging && g->on_node) - _area_set_pos(g, event->y); + _area_set_pos(g, y); else { // look if close to a node const float epsilon = DT_PIXEL_APPLY_DPI(10.0); const int oldsel = g->selected; const int oldon = g->on_node; - g->selected = (int)(((float)event->x - g->points[0][0]) + g->selected = (int)(((float)x - g->points[0][0]) / (g->points[1][0] - g->points[0][0]) + 0.5f) % NODES; - g->on_node = fabsf(g->points[g->selected][1] - (float)event->y) < epsilon; + g->on_node = fabsf(g->points[g->selected][1] - (float)y) < epsilon; darktable.control->element = g->selected; if(oldsel != g->selected || oldon != g->on_node) gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - - return TRUE; } -static gboolean _area_button_press_callback(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _colorequal_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { dt_iop_colorequal_gui_data_t *g = self->gui_data; - if(event->button == GDK_BUTTON_MIDDLE - || (event->button == GDK_BUTTON_PRIMARY // Ctrl+Click alias for macOS - && dt_modifier_is(event->state, GDK_CONTROL_MASK))) + guint button = gtk_gesture_single_get_current_button(gesture); + if(button == GDK_BUTTON_MIDDLE + || (button == GDK_BUTTON_PRIMARY // Ctrl+Click alias for macOS + && dt_modifier_eq(gesture, GDK_CONTROL_MASK))) { dt_conf_set_bool("plugins/darkroom/colorequal/show_sliders", gtk_notebook_get_n_pages(g->notebook) != 4); gui_update(self); } - else if(event->button == GDK_BUTTON_PRIMARY) + else if(button == GDK_BUTTON_PRIMARY) { - if(event->type == GDK_2BUTTON_PRESS) - { + dt_gui_claim(gesture); + if(n_press == 2) _area_reset_nodes(g); - return TRUE; - } else - { g->dragging = TRUE; - } } - else - return gtk_widget_event(_get_slider(g, g->selected), (GdkEvent*)event); - - return FALSE; + // FIXME + // else + // return gtk_widget_event(_get_slider(g, g->selected), (GdkEvent*)event); } -static gboolean _area_button_release_callback(GtkWidget *widget, - const GdkEventButton *event, - const dt_iop_module_t *self) +static void _colorequal_button_release(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { dt_iop_colorequal_gui_data_t *g = self->gui_data; - - if(event->button == GDK_BUTTON_PRIMARY) - { - g->dragging = FALSE; - return TRUE; - } - - return FALSE; + g->dragging = FALSE; } static gboolean _area_size_callback(GtkWidget *widget, @@ -2917,10 +2909,12 @@ void gui_update(dt_iop_module_t *self) const int nbpage = gtk_notebook_get_n_pages(g->notebook); if((nbpage == 4) ^ show_sliders) { + ++darktable.gui->reset; if(show_sliders) gtk_widget_show(dt_ui_notebook_page(g->notebook, N_("options"), _("options"))); else gtk_notebook_remove_page(g->notebook, 3); + --darktable.gui->reset; GtkDarktableExpander *exp = DTGTK_EXPANDER(g->cs.expander); gtk_widget_set_visible(dtgtk_expander_get_header(exp), !show_sliders); @@ -3018,22 +3012,13 @@ void gui_init(dt_iop_module_t *self) dt_action_define_iop(self, NULL, N_("graph"), GTK_WIDGET(g->area), &_action_def_coloreq); gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("double-click to reset the curve\nmiddle-click to toggle sliders visibility\nalt+scroll to change page")); gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); - gtk_widget_add_events(GTK_WIDGET(g->area), - GDK_BUTTON_PRESS_MASK - | GDK_POINTER_MOTION_MASK - | GDK_BUTTON_RELEASE_MASK - | GDK_SCROLL_MASK - | GDK_SMOOTH_SCROLL_MASK); + gtk_widget_add_events(GTK_WIDGET(g->area), darktable.gui->scroll_mask); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_iop_colorequalizer_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(_area_button_press_callback), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", - G_CALLBACK(_area_button_release_callback), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(_area_motion_notify_callback), self); + dt_gui_connect_click_all(g->area, _colorequal_button_press, _colorequal_button_release, self); + dt_gui_connect_motion(g->area, _colorequal_motion, NULL, NULL, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(_area_scrolled_callback), self); - g_signal_connect(G_OBJECT(g->area), "size_allocate", + g_signal_connect(G_OBJECT(g->area), "size-allocate", G_CALLBACK(_area_size_callback), self); GtkWidget *box = self->widget = dt_gui_vbox(g->notebook, g->area); diff --git a/src/iop/colorzones.c b/src/iop/colorzones.c index e79d373e56a5..13900c303a75 100644 --- a/src/iop/colorzones.c +++ b/src/iop/colorzones.c @@ -1919,15 +1919,18 @@ static gboolean _area_scrolled_callback(GtkWidget *widget, return TRUE; } -static gboolean _area_motion_notify_callback(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self) +static void _colorzones_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { dt_iop_colorzones_gui_data_t *g = self->gui_data; dt_iop_colorzones_params_t *p = self->params; const int inset = DT_IOP_COLORZONES_INSET; + const GdkModifierType state = dt_controller_state(controller); + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); @@ -1940,10 +1943,10 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, const float mx = g->mouse_x; const float my = g->mouse_y; - g->mouse_x = CLAMP(event->x - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(event->y - inset, 0, height) / (float)height; + g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; - if(event->state & GDK_BUTTON1_MASK) + if(state & GDK_BUTTON1_MASK) { g->offset_x += (mx - g->mouse_x) / g->zoom_factor; g->offset_y += (my - g->mouse_y) / g->zoom_factor; @@ -1953,7 +1956,7 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - return TRUE; + return; } const int ch = g->channel; @@ -1963,8 +1966,8 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, const double old_m_x = g->mouse_x; const double old_m_y = fabs(g->mouse_y); - g->mouse_x = CLAMP(event->x - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(event->y - inset, 0, height) / (float)height; + g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; darktable.control->element = (int)(8.0 * @@ -1972,7 +1975,7 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, g->zoom_factor, g->offset_x) + 0.5f) % 8; // move a node - if(event->state & GDK_BUTTON1_MASK) + if(state & GDK_BUTTON1_MASK) { if(g->edit_by_area) { @@ -2003,7 +2006,8 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, g->zoom_factor, g->offset_y); dt_iop_color_picker_reset(self, TRUE); - return _move_point_internal(self, widget, g->selected, dx, dy, event->state); + _move_point_internal(self, widget, g->selected, dx, dy, state); + return; } } @@ -2019,7 +2023,7 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); } } - else if(event->y > height) + else if(y > height) { g->x_move = 0; const int bands = p->curve_num_nodes[g->channel]; @@ -2042,7 +2046,7 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, } else { - if(event->state & GDK_BUTTON1_MASK) + if(state & GDK_BUTTON1_MASK) { if(nodes < DT_IOP_COLORZONES_MAXNODES && g->selected == -1) { @@ -2085,33 +2089,37 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, } gtk_widget_queue_draw(widget); - return TRUE; + return; } -static gboolean _area_button_press_callback(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _colorzones_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { dt_iop_colorzones_gui_data_t *g = self->gui_data; dt_iop_colorzones_params_t *p = self->params; const dt_iop_colorzones_params_t *const d = self->default_params; - if(darktable.develop->darkroom_skip_mouse_events) return TRUE; + if(darktable.develop->darkroom_skip_mouse_events) return; int ch = g->channel; int nodes = p->curve_num_nodes[ch]; dt_iop_colorzones_node_t *curve = p->curve[ch]; - if(event->button == GDK_BUTTON_PRIMARY) + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + guint button = gtk_gesture_single_get_current_button(gesture); + if(button == GDK_BUTTON_PRIMARY) { - if(g->edit_by_area && event->type != GDK_2BUTTON_PRESS - && !dt_modifier_is(event->state, GDK_CONTROL_MASK)) + if(g->edit_by_area && n_press != 2 + && !dt_modifier_eq(gesture, GDK_CONTROL_MASK)) { g->dragging = 1; - return TRUE; + return; } - else if(event->type == GDK_BUTTON_PRESS - && dt_modifier_is(event->state, GDK_CONTROL_MASK) + else if(n_press == 1 + && dt_modifier_eq(gesture, GDK_CONTROL_MASK) && nodes < DT_IOP_COLORZONES_MAXNODES && (g->selected == -1 || g->edit_by_area)) { @@ -2123,8 +2131,8 @@ static gboolean _area_button_press_callback(GtkWidget *widget, const int height = allocation.height - 2 * inset; const int width = allocation.width - 2 * inset; - g->mouse_x = CLAMP(event->x - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(event->y - inset, 0, height) / (float)height; + g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; const float mx = _mouse_to_curve(g->mouse_x, g->zoom_factor, g->offset_x); @@ -2146,14 +2154,14 @@ static gboolean _area_button_press_callback(GtkWidget *widget, if(selected == -1) selected = nodes; // evaluate the curve at the current x position - const float y = dt_draw_curve_calc_value(g->minmax_curve[ch], mx); + const float calc_y = dt_draw_curve_calc_value(g->minmax_curve[ch], mx); - if(y >= 0.0f && y <= 1.0f) // never add something outside the - // viewport, you couldn't change it - // afterwards + if(calc_y >= 0.0f && calc_y <= 1.0f) // never add something outside the + // viewport, you couldn't change it + // afterwards { // create a new node - selected = _add_node(curve, &p->curve_num_nodes[ch], mx, y); + selected = _add_node(curve, &p->curve_num_nodes[ch], mx, calc_y); // maybe set the new one as being selected const float min = .04f * .04f; // comparing against square @@ -2161,7 +2169,7 @@ static gboolean _area_button_press_callback(GtkWidget *widget, for(int k = 0; k < nodes; k++) { const float other_y = _curve_to_mouse(curve[k].y, g->zoom_factor, g->offset_y); - const float dist = (y - other_y) * (y - other_y); + const float dist = (calc_y - other_y) * (calc_y - other_y); if(dist < min) g->selected = selected; } @@ -2170,9 +2178,9 @@ static gboolean _area_button_press_callback(GtkWidget *widget, gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - return TRUE; + return; } - else if(event->type == GDK_2BUTTON_PRESS) + else if(n_press == 2) { // reset current curve p->curve_num_nodes[ch] = d->curve_num_nodes[ch]; @@ -2188,11 +2196,12 @@ static gboolean _area_button_press_callback(GtkWidget *widget, dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; + return; } } - else if(event->button == GDK_BUTTON_SECONDARY && g->selected >= 0) + else if(button == GDK_BUTTON_SECONDARY && g->selected >= 0) { + dt_gui_claim(gesture); if((g->selected == 0 || g->selected == nodes - 1) && p->splines_version == DT_IOP_COLORZONES_SPLINES_V1) { @@ -2213,48 +2222,42 @@ static gboolean _area_button_press_callback(GtkWidget *widget, dt_iop_color_picker_reset(self, TRUE); gtk_widget_queue_draw(GTK_WIDGET(g->area)); dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); - return TRUE; + return; } // right click deletes the node, ctrl+right click reset the node to y-zero _delete_node(self, curve, &p->curve_num_nodes[ch], - g->selected, dt_modifier_is(event->state, GDK_CONTROL_MASK)); + g->selected, dt_modifier_eq(gesture, GDK_CONTROL_MASK)); g->selected = -2; // avoid re-insertion of that point immediately after this - - return TRUE; } - - return FALSE; } -static gboolean _area_button_release_callback(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _colorzones_button_release(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - if(darktable.develop->darkroom_skip_mouse_events) return TRUE; + if(darktable.develop->darkroom_skip_mouse_events) return; - if(event->button == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) { dt_iop_colorzones_gui_data_t *g = self->gui_data; g->dragging = 0; - return TRUE; } - return FALSE; } -static gboolean _area_leave_notify_callback(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self) +static void _colorzones_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { - if(darktable.develop->darkroom_skip_mouse_events) return TRUE; + if(darktable.develop->darkroom_skip_mouse_events) return; dt_iop_colorzones_gui_data_t *g = self->gui_data; // for fluxbox g->mouse_y = -fabs(g->mouse_y); - if(!(event->state & GDK_BUTTON1_MASK)) + if(!(dt_controller_state(controller) & GDK_BUTTON1_MASK)) g->selected = -1; - gtk_widget_queue_draw(widget); - return TRUE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } static gboolean _area_key_press_callback(GtkWidget *widget, @@ -2709,14 +2712,8 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_area_draw_callback), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(_area_button_press_callback), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", - G_CALLBACK(_area_button_release_callback), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(_area_motion_notify_callback), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", - G_CALLBACK(_area_leave_notify_callback), self); + dt_gui_connect_click(g->area, _colorzones_button_press, _colorzones_button_release, self); + dt_gui_connect_motion(g->area, _colorzones_motion, NULL, _colorzones_leave, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(_area_scrolled_callback), self); g_signal_connect(G_OBJECT(g->area), "key-press-event", diff --git a/src/iop/denoiseprofile.c b/src/iop/denoiseprofile.c index 1f57e36269e7..42fb18369146 100644 --- a/src/iop/denoiseprofile.c +++ b/src/iop/denoiseprofile.c @@ -3613,18 +3613,19 @@ static gboolean denoiseprofile_draw(GtkWidget *widget, return FALSE; } -static gboolean denoiseprofile_motion_notify(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self) +static void _denoiseprofile_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { dt_iop_denoiseprofile_gui_data_t *g = self->gui_data; dt_iop_denoiseprofile_params_t *p = self->params; const int inset = DT_IOP_DENOISE_PROFILE_INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; - if(!g->dragging) g->mouse_x = CLAMP(event->x - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(event->y - inset, 0, height) / (float)height; + if(!g->dragging) g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; if(g->dragging) { *p = g->drag_params; @@ -3640,17 +3641,18 @@ static gboolean denoiseprofile_motion_notify(GtkWidget *widget, { g->x_move = -1; } - gtk_widget_queue_draw(widget); - return TRUE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } -static gboolean denoiseprofile_button_press(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _denoiseprofile_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { dt_iop_denoiseprofile_gui_data_t *g = self->gui_data; const int ch = g->channel; - if(event->button == 1 && event->type == GDK_2BUTTON_PRESS) + if(n_press == 2) { // reset current curve dt_iop_denoiseprofile_params_t *p = self->params; @@ -3664,44 +3666,37 @@ static gboolean denoiseprofile_button_press(GtkWidget *widget, dt_dev_add_history_item(darktable.develop, self, TRUE); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - else if(event->button == GDK_BUTTON_PRIMARY) + else { g->drag_params = *(dt_iop_denoiseprofile_params_t *)self->params; const int inset = DT_IOP_DENOISE_PROFILE_INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; g->mouse_pick = dt_draw_curve_calc_value(g->transition_curve, - CLAMP(event->x - inset, 0, width) / (float)width); - g->mouse_pick -= 1.0 - CLAMP(event->y - inset, 0, height) / (float)height; + CLAMP(x - inset, 0, width) / (float)width); + g->mouse_pick -= 1.0 - CLAMP(y - inset, 0, height) / (float)height; g->dragging = 1; - return TRUE; } - return FALSE; } -static gboolean denoiseprofile_button_release(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _denoiseprofile_button_release(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - if(event->button == GDK_BUTTON_PRIMARY) - { - dt_iop_denoiseprofile_gui_data_t *g = self->gui_data; - g->dragging = 0; - return TRUE; - } - return FALSE; + dt_iop_denoiseprofile_gui_data_t *g = self->gui_data; + g->dragging = 0; } -static gboolean denoiseprofile_leave_notify(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self) +static void _denoiseprofile_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_denoiseprofile_gui_data_t *g = self->gui_data; if(!g->dragging) g->mouse_y = -1.0; - gtk_widget_queue_draw(widget); - return TRUE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } static gboolean denoiseprofile_scrolled(GtkWidget *widget, @@ -3803,14 +3798,8 @@ void gui_init(dt_iop_module_t *self) dt_action_define_iop(self, NULL, N_("graph"), GTK_WIDGET(g->area), NULL); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(denoiseprofile_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(denoiseprofile_button_press), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", - G_CALLBACK(denoiseprofile_button_release), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(denoiseprofile_motion_notify), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", - G_CALLBACK(denoiseprofile_leave_notify), self); + dt_gui_connect_click(g->area, _denoiseprofile_button_press, _denoiseprofile_button_release, self); + dt_gui_connect_motion(g->area, _denoiseprofile_motion, NULL, _denoiseprofile_leave, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(denoiseprofile_scrolled), self); diff --git a/src/iop/exposure.c b/src/iop/exposure.c index 2b23da4dd2a1..814d27409e6d 100644 --- a/src/iop/exposure.c +++ b/src/iop/exposure.c @@ -33,6 +33,7 @@ #include "develop/imageop_math.h" #include "develop/imageop_gui.h" #include "develop/pixelpipe.h" +#include "dtgtk/drawingarea.h" #include "dtgtk/paint.h" #include "dtgtk/resetlabel.h" #include "gui/accelerators.h" @@ -686,7 +687,7 @@ void gui_update(dt_iop_module_t *self) p->compensate_exposure_bias); gchar *label = g_strdup_printf(_("compensate camera exposure (%+.1f EV)"), _get_exposure_bias(self)); - gtk_button_set_label(GTK_BUTTON(g->compensate_exposure_bias), label); + gtk_check_button_set_label(GTK_CHECK_BUTTON(g->compensate_exposure_bias), label); gtk_label_set_ellipsize (GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->compensate_exposure_bias))), PANGO_ELLIPSIZE_MIDDLE); @@ -697,7 +698,7 @@ void gui_update(dt_iop_module_t *self) p->compensate_hilite_pres); /* xgettext:no-c-format */ label = g_strdup_printf(_("highlight preservation mode (%.1f EV)"), hlbias); - gtk_button_set_label(GTK_BUTTON(g->compensate_hilite_preserv), label); + gtk_check_button_set_label(GTK_CHECK_BUTTON(g->compensate_hilite_preserv), label); gtk_label_set_ellipsize (GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->compensate_hilite_preserv))), PANGO_ELLIPSIZE_MIDDLE); diff --git a/src/iop/filmicrgb.c b/src/iop/filmicrgb.c index e8d2d75dc2a1..e71238895a13 100644 --- a/src/iop/filmicrgb.c +++ b/src/iop/filmicrgb.c @@ -4183,9 +4183,13 @@ static gboolean dt_iop_tonecurve_draw(GtkWidget *widget, cairo_t *crf, dt_iop_mo return FALSE; } -static gboolean area_button_press(GtkWidget *widget, const GdkEventButton *event, dt_iop_module_t *self) +static void _filmicrgb_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - if(darktable.gui->reset) return TRUE; + if(darktable.gui->reset) return; dt_iop_filmicrgb_gui_data_t *g = self->gui_data; @@ -4193,8 +4197,8 @@ static gboolean area_button_press(GtkWidget *widget, const GdkEventButton *event if(g->active_button != DT_FILMIC_GUI_BUTTON_LAST) { - - if(event->button == GDK_BUTTON_PRIMARY && event->type == GDK_2BUTTON_PRESS) + guint button = gtk_gesture_single_get_current_button(gesture); + if(button == GDK_BUTTON_PRIMARY && n_press == 2) { // double click resets view if(g->active_button == DT_FILMIC_GUI_BUTTON_TYPE) @@ -4202,14 +4206,9 @@ static gboolean area_button_press(GtkWidget *widget, const GdkEventButton *event g->gui_mode = DT_FILMIC_GUI_LOOK; gtk_widget_queue_draw(GTK_WIDGET(g->area)); dt_conf_set_int("plugins/darkroom/filmicrgb/graph_view", g->gui_mode); - return TRUE; - } - else - { - return FALSE; } } - else if(event->button == GDK_BUTTON_PRIMARY) + else if(button == GDK_BUTTON_PRIMARY) { // simple left click cycles through modes in positive direction if(g->active_button == DT_FILMIC_GUI_BUTTON_TYPE) @@ -4222,24 +4221,17 @@ static gboolean area_button_press(GtkWidget *widget, const GdkEventButton *event gtk_widget_queue_draw(GTK_WIDGET(g->area)); dt_conf_set_int("plugins/darkroom/filmicrgb/graph_view", g->gui_mode); - return TRUE; } else if(g->active_button == DT_FILMIC_GUI_BUTTON_LABELS) { g->gui_show_labels = !g->gui_show_labels; gtk_widget_queue_draw(GTK_WIDGET(g->area)); dt_conf_set_int("plugins/darkroom/filmicrgb/graph_show_labels", g->gui_show_labels); - return TRUE; - } - else - { - // we should never get there since (g->active_button != DT_FILMIC_GUI_BUTTON_LAST) - // and any other case has been processed above. - return FALSE; } } - else if(event->button == GDK_BUTTON_SECONDARY) + else if(button == GDK_BUTTON_SECONDARY) { + dt_gui_claim(gesture); // simple right click cycles through modes in negative direction if(g->active_button == DT_FILMIC_GUI_BUTTON_TYPE) { @@ -4250,44 +4242,44 @@ static gboolean area_button_press(GtkWidget *widget, const GdkEventButton *event gtk_widget_queue_draw(GTK_WIDGET(g->area)); dt_conf_set_int("plugins/darkroom/filmicrgb/graph_view", g->gui_mode); - return TRUE; } else if(g->active_button == DT_FILMIC_GUI_BUTTON_LABELS) { g->gui_show_labels = !g->gui_show_labels; gtk_widget_queue_draw(GTK_WIDGET(g->area)); dt_conf_set_int("plugins/darkroom/filmicrgb/graph_show_labels", g->gui_show_labels); - return TRUE; - } - else - { - return FALSE; } } } - - return FALSE; } -static gboolean area_enter_leave_notify(GtkWidget *widget, const GdkEventCrossing *event, const dt_iop_module_t *self) +static void _filmicrgb_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_filmicrgb_gui_data_t *g = self->gui_data; - g->gui_hover = event->type == GDK_ENTER_NOTIFY; + g->gui_hover = controller == NULL; gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return FALSE; } -static gboolean area_motion_notify(GtkWidget *widget, const GdkEventMotion *event, const dt_iop_module_t *self) +static void _filmicrgb_enter(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) +{ + _filmicrgb_leave(NULL, self); +} + +static void _filmicrgb_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { - if(darktable.gui->reset) return 1; + if(darktable.gui->reset) return; dt_iop_filmicrgb_gui_data_t *g = self->gui_data; - if(!g->gui_sizes_inited) return FALSE; + if(!g->gui_sizes_inited) return; // get in-widget coordinates - const float y = event->y; - const float x = event->x; - if(x > 0. && x < g->allocation.width && y > 0. && y < g->allocation.height) g->gui_hover = TRUE; const gint save_active_button = g->active_button; @@ -4340,13 +4332,11 @@ static gboolean area_motion_notify(GtkWidget *widget, const GdkEventMotion *even } if(save_active_button != g->active_button) gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; } else { g->active_button = DT_FILMIC_GUI_BUTTON_LAST; if(save_active_button != g->active_button) (GTK_WIDGET(g->area)); - return FALSE; } } @@ -4368,10 +4358,8 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(dt_iop_tonecurve_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", G_CALLBACK(area_button_press), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", G_CALLBACK(area_enter_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "enter-notify-event", G_CALLBACK(area_enter_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", G_CALLBACK(area_motion_notify), self); + dt_gui_connect_click_all(g->area, _filmicrgb_button_press, NULL, self); + dt_gui_connect_motion(g->area, _filmicrgb_motion, _filmicrgb_enter, _filmicrgb_leave, self); // Init GTK notebook static struct dt_action_def_t notebook_def = { }; diff --git a/src/iop/levels.c b/src/iop/levels.c index e13f41cb0599..07d74ffa2bc8 100644 --- a/src/iop/levels.c +++ b/src/iop/levels.c @@ -46,10 +46,22 @@ DT_MODULE_INTROSPECTION(2, dt_iop_levels_params_t) static gboolean dt_iop_levels_area_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t *self); -static gboolean dt_iop_levels_motion_notify(GtkWidget *widget, GdkEventMotion *event, dt_iop_module_t *self); -static gboolean dt_iop_levels_button_press(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self); -static gboolean dt_iop_levels_button_release(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self); -static gboolean dt_iop_levels_leave_notify(GtkWidget *widget, GdkEventCrossing *event, dt_iop_module_t *self); +static void _levels_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self); +static void _levels_button_release(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self); +static void _levels_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self); +static void _levels_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self); static gboolean dt_iop_levels_scroll(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self); static void dt_iop_levels_autoadjust_callback(GtkRange *range, dt_iop_module_t *self); //static void dt_iop_levels_mode_callback(GtkWidget *combo, gpointer user_data); @@ -636,10 +648,8 @@ void gui_init(dt_iop_module_t *self) dt_action_define_iop(self, NULL, N_("levels"), GTK_WIDGET(g->area), NULL); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(dt_iop_levels_area_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", G_CALLBACK(dt_iop_levels_button_press), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", G_CALLBACK(dt_iop_levels_button_release), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", G_CALLBACK(dt_iop_levels_motion_notify), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", G_CALLBACK(dt_iop_levels_leave_notify), self); + dt_gui_connect_click(g->area, _levels_button_press, _levels_button_release, self); + dt_gui_connect_motion(g->area, _levels_motion, NULL, _levels_leave, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(dt_iop_levels_scroll), self); GtkWidget *autobutton = gtk_button_new_with_label(_("auto")); @@ -696,12 +706,12 @@ void gui_cleanup(dt_iop_module_t *self) g_list_free(g->modes); } -static gboolean dt_iop_levels_leave_notify(GtkWidget *widget, GdkEventCrossing *event, dt_iop_module_t *self) +static void _levels_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_levels_gui_data_t *g = self->gui_data; g->mouse_x = g->mouse_y = -1.0; - gtk_widget_queue_draw(widget); - return TRUE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } static gboolean dt_iop_levels_area_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t *self) @@ -862,26 +872,29 @@ static void dt_iop_levels_move_handle(dt_iop_module_t *self, int handle_move, fl g->last_picked_color = -1; } -static gboolean dt_iop_levels_motion_notify(GtkWidget *widget, GdkEventMotion *event, dt_iop_module_t *self) +static void _levels_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { dt_iop_levels_gui_data_t *g = self->gui_data; dt_iop_levels_params_t *p = self->params; const int inset = DT_GUI_CURVE_EDITOR_INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); int height = allocation.height - 2 * inset - DT_RESIZE_HANDLE_SIZE, width = allocation.width - 2 * inset; if(!g->dragging) { - g->mouse_x = CLAMP(event->x - inset, 0, width); + g->mouse_x = CLAMP(x - inset, 0, width); g->drag_start_percentage = (p->levels[1] - p->levels[0]) / (p->levels[2] - p->levels[0]); } - g->mouse_y = CLAMP(event->y - inset, 0, height); + g->mouse_y = CLAMP(y - inset, 0, height); if(g->dragging) { if(g->handle_move >= 0 && g->handle_move < 3) { - const float mx = (CLAMP(event->x - inset, 0, width)) / (float)width; + const float mx = (CLAMP(x - inset, 0, width)) / (float)width; dt_iop_levels_move_handle(self, g->handle_move, mx, p->levels, g->drag_start_percentage); } @@ -890,7 +903,7 @@ static gboolean dt_iop_levels_motion_notify(GtkWidget *widget, GdkEventMotion *e else { g->handle_move = 0; - const float mx = CLAMP(event->x - inset, 0, width) / (float)width; + const float mx = CLAMP(x - inset, 0, width) / (float)width; float dist = fabsf(p->levels[0] - mx); for(int k = 1; k < 3; k++) { @@ -902,49 +915,45 @@ static gboolean dt_iop_levels_motion_notify(GtkWidget *widget, GdkEventMotion *e } } } - gtk_widget_queue_draw(widget); - - return TRUE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } -static gboolean dt_iop_levels_button_press(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) +static void _levels_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { // set active point - if(event->button == GDK_BUTTON_PRIMARY) - { - if(darktable.develop->gui_module != self) dt_iop_request_focus(self); + if(darktable.develop->gui_module != self) dt_iop_request_focus(self); - if(event->type == GDK_2BUTTON_PRESS) - { - // Reset - dt_iop_levels_gui_data_t *g = self->gui_data; - memcpy(self->params, self->default_params, self->params_size); + if(n_press == 2) + { + // Reset + dt_iop_levels_gui_data_t *g = self->gui_data; + memcpy(self->params, self->default_params, self->params_size); - // Needed in case the user scrolls or drags immediately after a reset, - // as drag_start_percentage is only updated when the mouse is moved. - g->drag_start_percentage = 0.5; - dt_dev_add_history_item(darktable.develop, self, TRUE); - gtk_widget_queue_draw(GTK_WIDGET(g->area)); - } - else - { - dt_iop_levels_gui_data_t *g = self->gui_data; - g->dragging = 1; - } - return TRUE; + // Needed in case the user scrolls or drags immediately after a reset, + // as drag_start_percentage is only updated when the mouse is moved. + g->drag_start_percentage = 0.5; + dt_dev_add_history_item(darktable.develop, self, TRUE); + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - return FALSE; -} - -static gboolean dt_iop_levels_button_release(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) -{ - if(event->button == GDK_BUTTON_PRIMARY) + else { dt_iop_levels_gui_data_t *g = self->gui_data; - g->dragging = 0; - return TRUE; + g->dragging = 1; } - return FALSE; +} + +static void _levels_button_release(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) +{ + dt_iop_levels_gui_data_t *g = self->gui_data; + g->dragging = 0; } static gboolean dt_iop_levels_scroll(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self) diff --git a/src/iop/lowlight.c b/src/iop/lowlight.c index 83b747858d4d..e38db4a6a05e 100644 --- a/src/iop/lowlight.c +++ b/src/iop/lowlight.c @@ -663,22 +663,25 @@ static gboolean lowlight_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t * return FALSE; } -static gboolean lowlight_motion_notify(GtkWidget *widget, GdkEventMotion *event, dt_iop_module_t *self) +static void _lowlight_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { dt_iop_lowlight_gui_data_t *g = self->gui_data; dt_iop_lowlight_params_t *p = self->params; const int inset = DT_IOP_LOWLIGHT_INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); int height = allocation.height - 2 * inset - DT_RESIZE_HANDLE_SIZE, width = allocation.width - 2 * inset; - if(!g->dragging) g->mouse_x = CLAMP(event->x - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(event->y - inset, 0, height) / (float)height; + if(!g->dragging) g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; if(g->dragging) { *p = g->drag_params; if(g->x_move >= 0) { - const float mx = CLAMP(event->x - inset, 0, width) / (float)width; + const float mx = CLAMP(x - inset, 0, width) / (float)width; if(g->x_move > 0 && g->x_move < DT_IOP_LOWLIGHT_BANDS - 1) { const float minx = p->transition_x[g->x_move - 1] + 0.001f; @@ -690,10 +693,9 @@ static gboolean lowlight_motion_notify(GtkWidget *widget, GdkEventMotion *event, { dt_iop_lowlight_get_params(p, g->mouse_x, g->mouse_y + g->mouse_pick, g->mouse_radius); } - gtk_widget_queue_draw(widget); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area); } - else if(event->y > height) + else if(y > height) { g->x_move = 0; float dist = fabs(p->transition_x[0] - g->mouse_x); @@ -706,20 +708,22 @@ static gboolean lowlight_motion_notify(GtkWidget *widget, GdkEventMotion *event, dist = d2; } } - gtk_widget_queue_draw(widget); } else { g->x_move = -1; - gtk_widget_queue_draw(widget); } - return TRUE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } -static gboolean lowlight_button_press(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) +static void _lowlight_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { dt_iop_lowlight_gui_data_t *g = self->gui_data; - if(event->button == GDK_BUTTON_PRIMARY && event->type == GDK_2BUTTON_PRESS) + if(n_press == 2) { // reset current curve dt_iop_lowlight_params_t *p = self->params; @@ -729,42 +733,39 @@ static gboolean lowlight_button_press(GtkWidget *widget, GdkEventButton *event, p->transition_x[k] = d->transition_x[k]; p->transition_y[k] = d->transition_y[k]; } - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - else if(event->button == GDK_BUTTON_PRIMARY) + else { g->drag_params = *(dt_iop_lowlight_params_t *)self->params; const int inset = DT_IOP_LOWLIGHT_INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); int height = allocation.height - 2 * inset - DT_RESIZE_HANDLE_SIZE, width = allocation.width - 2 * inset; g->mouse_pick - = dt_draw_curve_calc_value(g->transition_curve, CLAMP(event->x - inset, 0, width) / (float)width); - g->mouse_pick -= 1.0 - CLAMP(event->y - inset, 0, height) / (float)height; + = dt_draw_curve_calc_value(g->transition_curve, CLAMP(x - inset, 0, width) / (float)width); + g->mouse_pick -= 1.0 - CLAMP(y - inset, 0, height) / (float)height; g->dragging = 1; - return TRUE; } - return FALSE; } -static gboolean lowlight_button_release(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) +static void _lowlight_button_release(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - if(event->button == GDK_BUTTON_PRIMARY) - { - dt_iop_lowlight_gui_data_t *g = self->gui_data; - g->dragging = 0; - return TRUE; - } - return FALSE; + dt_iop_lowlight_gui_data_t *g = self->gui_data; + g->dragging = 0; } -static gboolean lowlight_leave_notify(GtkWidget *widget, GdkEventCrossing *event, dt_iop_module_t *self) +static void _lowlight_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_lowlight_gui_data_t *g = self->gui_data; if(!g->dragging) g->mouse_y = -1.0; - gtk_widget_queue_draw(widget); - return TRUE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } static gboolean lowlight_scrolled(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self) @@ -808,10 +809,8 @@ void gui_init(dt_iop_module_t *self) self->widget = dt_gui_vbox(g->area); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(lowlight_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", G_CALLBACK(lowlight_button_press), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", G_CALLBACK(lowlight_button_release), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", G_CALLBACK(lowlight_motion_notify), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", G_CALLBACK(lowlight_leave_notify), self); + dt_gui_connect_click(g->area, _lowlight_button_press, _lowlight_button_release, self); + dt_gui_connect_motion(g->area, _lowlight_motion, NULL, _lowlight_leave, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(lowlight_scrolled), self); g->scale_blueness = dt_bauhaus_slider_from_params(self, "blueness"); diff --git a/src/iop/monochrome.c b/src/iop/monochrome.c index 4187e14efa91..2508ce72fffc 100644 --- a/src/iop/monochrome.c +++ b/src/iop/monochrome.c @@ -450,7 +450,10 @@ void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpi dt_control_queue_redraw_widget(self->widget); } -static gboolean _monochrome_motion_notify(GtkWidget *widget, GdkEventMotion *event, dt_iop_module_t *self) +static void _monochrome_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { dt_iop_monochrome_gui_data_t *g = self->gui_data; dt_iop_monochrome_params_t *p = self->params; @@ -459,73 +462,68 @@ static gboolean _monochrome_motion_notify(GtkWidget *widget, GdkEventMotion *eve const float old_a = p->a, old_b = p->b; const int inset = DT_COLORCORRECTION_INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); int width = allocation.width - 2 * inset, height = allocation.height - 2 * inset; - const float mouse_x = CLAMP(event->x - inset, 0, width); - const float mouse_y = CLAMP(height - 1 - event->y + inset, 0, height); + const float mouse_x = CLAMP(x - inset, 0, width); + const float mouse_y = CLAMP(height - 1 - y + inset, 0, height); p->a = PANEL_WIDTH * (mouse_x - width * 0.5f) / (float)width; p->b = PANEL_WIDTH * (mouse_y - height * 0.5f) / (float)height; if(old_a != p->a || old_b != p->b) dt_dev_add_history_item(darktable.develop, self, TRUE); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - return TRUE; } -static gboolean _monochrome_button_press(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) +static void _monochrome_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - if(event->button == GDK_BUTTON_PRIMARY) + dt_iop_monochrome_gui_data_t *g = self->gui_data; + dt_iop_monochrome_params_t *p = self->params; + dt_iop_color_picker_reset(self, TRUE); + if(n_press == 2) { - dt_iop_monochrome_gui_data_t *g = self->gui_data; - dt_iop_monochrome_params_t *p = self->params; - dt_iop_color_picker_reset(self, TRUE); - if(event->type == GDK_2BUTTON_PRESS) - { - // reset - const dt_iop_monochrome_params_t *const p0 = self->default_params; - p->a = p0->a; - p->b = p0->b; - p->size = p0->size; - } - else - { - const int inset = DT_COLORCORRECTION_INSET; - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - int width = allocation.width - 2 * inset, height = allocation.height - 2 * inset; - const float mouse_x = CLAMP(event->x - inset, 0, width); - const float mouse_y = CLAMP(height - 1 - event->y + inset, 0, height); - p->a = PANEL_WIDTH * (mouse_x - width * 0.5f) / (float)width; - p->b = PANEL_WIDTH * (mouse_y - height * 0.5f) / (float)height; - g->dragging = 1; - g_object_set(G_OBJECT(widget), "has-tooltip", FALSE, (gchar *)0); - } - gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; + // reset + const dt_iop_monochrome_params_t *const p0 = self->default_params; + p->a = p0->a; + p->b = p0->b; + p->size = p0->size; } - return FALSE; + else + { + const int inset = DT_COLORCORRECTION_INSET; + GtkAllocation allocation; + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); + int width = allocation.width - 2 * inset, height = allocation.height - 2 * inset; + const float mouse_x = CLAMP(x - inset, 0, width); + const float mouse_y = CLAMP(height - 1 - y + inset, 0, height); + p->a = PANEL_WIDTH * (mouse_x - width * 0.5f) / (float)width; + p->b = PANEL_WIDTH * (mouse_y - height * 0.5f) / (float)height; + g->dragging = 1; + } + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } -static gboolean _monochrome_button_release(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) +static void _monochrome_button_release(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - if(event->button == GDK_BUTTON_PRIMARY) - { - dt_iop_monochrome_gui_data_t *g = self->gui_data; - dt_iop_color_picker_reset(self, TRUE); - g->dragging = 0; - dt_dev_add_history_item(darktable.develop, self, TRUE); - g_object_set(G_OBJECT(widget), "has-tooltip", TRUE, (gchar *)0); - return TRUE; - } - return FALSE; + dt_iop_monochrome_gui_data_t *g = self->gui_data; + dt_iop_color_picker_reset(self, TRUE); + g->dragging = 0; + dt_dev_add_history_item(darktable.develop, self, TRUE); } -static gboolean _monochrome_leave_notify(GtkWidget *widget, GdkEventCrossing *event, dt_iop_module_t *self) +static void _monochrome_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_monochrome_gui_data_t *g = self->gui_data; g->dragging = 0; gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; } static gboolean _monochrome_scrolled(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self) @@ -559,16 +557,10 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("drag and scroll mouse wheel to adjust the virtual color filter")); dt_action_define_iop(self, NULL, N_("grid"), GTK_WIDGET(g->area), NULL); - gtk_widget_add_events(GTK_WIDGET(g->area), GDK_POINTER_MOTION_MASK - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_LEAVE_NOTIFY_MASK | darktable.gui->scroll_mask); + gtk_widget_add_events(GTK_WIDGET(g->area), darktable.gui->scroll_mask); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_monochrome_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", G_CALLBACK(_monochrome_button_press), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", G_CALLBACK(_monochrome_button_release), - self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", G_CALLBACK(_monochrome_motion_notify), - self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", G_CALLBACK(_monochrome_leave_notify), self); + dt_gui_connect_click(g->area, _monochrome_button_press, _monochrome_button_release, self); + dt_gui_connect_motion(g->area, _monochrome_motion, NULL, _monochrome_leave, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(_monochrome_scrolled), self); g->highlights diff --git a/src/iop/rawdenoise.c b/src/iop/rawdenoise.c index 59779cb76276..0ab711d02f87 100644 --- a/src/iop/rawdenoise.c +++ b/src/iop/rawdenoise.c @@ -763,16 +763,19 @@ static gboolean rawdenoise_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t return FALSE; } -static gboolean rawdenoise_motion_notify(GtkWidget *widget, GdkEventMotion *event, dt_iop_module_t *self) +static void _rawdenoise_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { dt_iop_rawdenoise_gui_data_t *g = self->gui_data; dt_iop_rawdenoise_params_t *p = self->params; const int inset = DT_IOP_RAWDENOISE_INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; - if(!g->dragging) g->mouse_x = CLAMP(event->x - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(event->y - inset, 0, height) / (float)height; + if(!g->dragging) g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; if(g->dragging) { *p = g->drag_params; @@ -780,22 +783,24 @@ static gboolean rawdenoise_motion_notify(GtkWidget *widget, GdkEventMotion *even { dt_iop_rawdenoise_get_params(p, g->channel, g->mouse_x, g->mouse_y + g->mouse_pick, g->mouse_radius); } - gtk_widget_queue_draw(widget); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + g->channel); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area + g->channel); } else { g->x_move = -1; - gtk_widget_queue_draw(widget); } - return TRUE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } -static gboolean rawdenoise_button_press(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) +static void _rawdenoise_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { dt_iop_rawdenoise_gui_data_t *g = self->gui_data; const int ch = g->channel; - if(event->button == GDK_BUTTON_PRIMARY && event->type == GDK_2BUTTON_PRESS) + if(n_press == 2) { // reset current curve dt_iop_rawdenoise_params_t *p = self->params; @@ -805,42 +810,39 @@ static gboolean rawdenoise_button_press(GtkWidget *widget, GdkEventButton *event p->x[ch][k] = d->x[ch][k]; p->y[ch][k] = d->y[ch][k]; } - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area + ch); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - else if(event->button == GDK_BUTTON_PRIMARY) + else { g->drag_params = *(dt_iop_rawdenoise_params_t *)self->params; const int inset = DT_IOP_RAWDENOISE_INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; g->mouse_pick - = dt_draw_curve_calc_value(g->transition_curve, CLAMP(event->x - inset, 0, width) / (float)width); - g->mouse_pick -= 1.0 - CLAMP(event->y - inset, 0, height) / (float)height; + = dt_draw_curve_calc_value(g->transition_curve, CLAMP(x - inset, 0, width) / (float)width); + g->mouse_pick -= 1.0 - CLAMP(y - inset, 0, height) / (float)height; g->dragging = 1; - return TRUE; } - return FALSE; } -static gboolean rawdenoise_button_release(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) +static void _rawdenoise_button_release(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - if(event->button == GDK_BUTTON_PRIMARY) - { - dt_iop_rawdenoise_gui_data_t *g = self->gui_data; - g->dragging = 0; - return TRUE; - } - return FALSE; + dt_iop_rawdenoise_gui_data_t *g = self->gui_data; + g->dragging = 0; } -static gboolean rawdenoise_leave_notify(GtkWidget *widget, GdkEventCrossing *event, dt_iop_module_t *self) +static void _rawdenoise_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_rawdenoise_gui_data_t *g = self->gui_data; if(!g->dragging) g->mouse_y = -1.0; - gtk_widget_queue_draw(widget); - return TRUE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } static gboolean rawdenoise_scrolled(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self) @@ -910,10 +912,8 @@ void gui_init(dt_iop_module_t *self) GtkWidget *box_raw = self->widget = dt_gui_vbox(g->channel_tabs, g->area); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(rawdenoise_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", G_CALLBACK(rawdenoise_button_press), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", G_CALLBACK(rawdenoise_button_release), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", G_CALLBACK(rawdenoise_motion_notify), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", G_CALLBACK(rawdenoise_leave_notify), self); + dt_gui_connect_click(g->area, _rawdenoise_button_press, _rawdenoise_button_release, self); + dt_gui_connect_motion(g->area, _rawdenoise_motion, NULL, _rawdenoise_leave, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(rawdenoise_scrolled), self); g->threshold = dt_bauhaus_slider_from_params(self, "threshold"); diff --git a/src/iop/rgbcurve.c b/src/iop/rgbcurve.c index a976f5fec56a..d7de6be9349f 100644 --- a/src/iop/rgbcurve.c +++ b/src/iop/rgbcurve.c @@ -745,16 +745,14 @@ static gboolean _area_key_press_callback(GtkWidget *widget, #undef RGBCURVE_DEFAULT_STEP -static gboolean _area_leave_notify_callback(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self) +static void _rgbcurve_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_rgbcurve_gui_data_t *g = self->gui_data; - if(!(event->state & GDK_BUTTON1_MASK)) + if(!(dt_controller_state(controller) & GDK_BUTTON1_MASK)) g->selected = -1; - gtk_widget_queue_draw(widget); - return FALSE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } static gboolean _area_draw_callback(GtkWidget *widget, @@ -1165,30 +1163,31 @@ static gboolean _area_draw_callback(GtkWidget *widget, return TRUE; } -static gboolean _area_motion_notify_callback(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self) +static void _rgbcurve_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { dt_iop_rgbcurve_gui_data_t *g = self->gui_data; dt_iop_rgbcurve_params_t *p = self->params; const int inset = DT_GUI_CURVE_EDITOR_INSET; + GtkAllocation allocation; + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); + const int height = allocation.height - 2 * inset; + const int width = allocation.width - 2 * inset; + GdkModifierType state = dt_controller_state(controller); // drag the draw area if(darktable.develop->darkroom_skip_mouse_events) { - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - const int height = allocation.height - 2 * inset; - const int width = allocation.width - 2 * inset; - const float mx = g->mouse_x; const float my = g->mouse_y; - g->mouse_x = CLAMP(event->x - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(event->y - inset, 0, height) / (float)height; + g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; - if(event->state & GDK_BUTTON1_MASK) + if(state & GDK_BUTTON1_MASK) { g->offset_x += (mx - g->mouse_x) / g->zoom_factor; g->offset_y += (my - g->mouse_y) / g->zoom_factor; @@ -1198,7 +1197,7 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - return TRUE; + return; } const int ch = g->channel; @@ -1210,22 +1209,18 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, && g->channel != DT_IOP_RGBCURVE_R) goto finally; - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - const int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; - const double old_m_x = g->mouse_x; const double old_m_y = g->mouse_y; - g->mouse_x = CLAMP(event->x - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(event->y - inset, 0, height) / (float)height; + g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; const float mx = g->mouse_x; const float my = g->mouse_y; const float linx = _mouse_to_curve(mx, g->zoom_factor, g->offset_x), liny = _mouse_to_curve(my, g->zoom_factor, g->offset_y); - if(event->state & GDK_BUTTON1_MASK) + if(state & GDK_BUTTON1_MASK) { // got a vertex selected: if(g->selected >= 0) @@ -1249,14 +1244,15 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, g->zoom_factor, g->offset_y); dt_iop_color_picker_reset(self, TRUE); - return _move_point_internal(self, widget, dx, dy, event->state); + _move_point_internal(self, GTK_WIDGET(g->area), dx, dy, state); + return; } else if(nodes < DT_IOP_RGBCURVE_MAXNODES && g->selected >= -1) { dt_iop_color_picker_reset(self, TRUE); // no vertex was close, create a new one! g->selected = _add_node(curve_nodes, &p->curve_num_nodes[ch], linx, liny); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area + ch); } } else @@ -1283,43 +1279,45 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, g->selected = nearest; } finally: - if(g->selected >= 0) gtk_widget_grab_focus(widget); - gtk_widget_queue_draw(widget); - return TRUE; + if(g->selected >= 0) gtk_widget_grab_focus(GTK_WIDGET(g->area)); + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } -static gboolean _area_button_press_callback(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _rgbcurve_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { dt_iop_rgbcurve_params_t *p = self->params; const dt_iop_rgbcurve_params_t *const d = self->default_params; dt_iop_rgbcurve_gui_data_t *g = self->gui_data; - if(darktable.develop->darkroom_skip_mouse_events) - return TRUE; + if(darktable.develop->darkroom_skip_mouse_events) return; const int ch = g->channel; const int autoscale = p->curve_autoscale; const int nodes = p->curve_num_nodes[ch]; dt_iop_rgbcurve_node_t *curve_nodes = p->curve_nodes[ch]; - if(event->button == GDK_BUTTON_PRIMARY) + guint button = gtk_gesture_single_get_current_button(gesture); + if(button == GDK_BUTTON_PRIMARY) { - if(event->type == GDK_BUTTON_PRESS - && dt_modifier_is(event->state, GDK_CONTROL_MASK) + dt_gui_claim(gesture); + if(n_press == 1 + && dt_modifier_eq(gesture, GDK_CONTROL_MASK) && nodes < DT_IOP_RGBCURVE_MAXNODES && g->selected == -1) { // if we are not on a node -> add a new node at the current x of // the pointer and y of the curve at that x const int inset = DT_GUI_CURVE_EDITOR_INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); const int width = allocation.width - 2 * inset; const int height = allocation.height - 2 * inset; - g->mouse_x = CLAMP(event->x - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(event->y - inset, 0, height) / (float)height; + g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; const float mx = g->mouse_x; const float linx = _mouse_to_curve(mx, g->zoom_factor, g->offset_x); @@ -1342,34 +1340,32 @@ static gboolean _area_button_press_callback(GtkWidget *widget, } if(selected == -1) selected = nodes; - // evaluate the curve at the current x position - const float y = dt_draw_curve_calc_value(g->minmax_curve[ch], linx); + // evaluate the curve at the current x position + const float calc_y = dt_draw_curve_calc_value(g->minmax_curve[ch], linx); - if(y >= 0.0f && y <= 1.0f) // never add something outside the - // viewport, you couldn't change it - // afterwards - { - // create a new node - selected = _add_node(curve_nodes, &p->curve_num_nodes[ch], linx, y); - - // maybe set the new one as being selected - const float min = .04f * .04f; // comparing against square - for(int k = 0; k < nodes; k++) - { - const float other_y = - _curve_to_mouse(curve_nodes[k].y, g->zoom_factor, g->offset_y); - const float dist = (y - other_y) * (y - other_y); - if(dist < min) g->selected = selected; - } + if(calc_y >= 0.0f && calc_y <= 1.0f) // never add something outside the + // viewport, you couldn't change it + // afterwards + { + // create a new node + selected = _add_node(curve_nodes, &p->curve_num_nodes[ch], linx, calc_y); - dt_iop_color_picker_reset(self, TRUE); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); - gtk_widget_queue_draw(GTK_WIDGET(g->area)); + // maybe set the new one as being selected + const float min = .04f * .04f; // comparing against square + for(int k = 0; k < nodes; k++) + { + const float other_y = + _curve_to_mouse(curve_nodes[k].y, g->zoom_factor, g->offset_y); + const float dist = (calc_y - other_y) * (calc_y - other_y); + if(dist < min) g->selected = selected; } - return TRUE; + dt_iop_color_picker_reset(self, TRUE); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area + ch); + gtk_widget_queue_draw(GTK_WIDGET(g->area)); + } } - else if(event->type == GDK_2BUTTON_PRESS) + else if(n_press == 2) { // reset current curve // if autoscale is on: allow only reset of L curve @@ -1385,7 +1381,7 @@ static gboolean _area_button_press_callback(GtkWidget *widget, g->selected = -2; // avoid motion notify re-inserting immediately. dt_bauhaus_combobox_set(g->interpolator, p->curve_type[DT_IOP_RGBCURVE_R]); dt_iop_color_picker_reset(self, TRUE); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area + ch); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } else @@ -1396,23 +1392,23 @@ static gboolean _area_button_press_callback(GtkWidget *widget, g->selected = -2; // avoid motion notify re-inserting immediately. dt_bauhaus_combobox_set(g->autoscale, 1); dt_iop_color_picker_reset(self, TRUE); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area + ch); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } } - return TRUE; } } - else if(event->button == GDK_BUTTON_SECONDARY && g->selected >= 0) + else if(button == GDK_BUTTON_SECONDARY && g->selected >= 0) { + dt_gui_claim(gesture); if(g->selected == 0 || g->selected == nodes - 1) { const float reset_value = g->selected == 0 ? 0.f : 1.f; curve_nodes[g->selected].y = curve_nodes[g->selected].x = reset_value; dt_iop_color_picker_reset(self, TRUE); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area + ch); gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; + return; } for(int k = g->selected; k < nodes - 1; k++) @@ -1424,11 +1420,9 @@ static gboolean _area_button_press_callback(GtkWidget *widget, g->selected = -2; // avoid re-insertion of that point immediately after this p->curve_num_nodes[ch]--; dt_iop_color_picker_reset(self, TRUE); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area + ch); gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; } - return FALSE; } void gui_reset(dt_iop_module_t *self) @@ -1527,19 +1521,12 @@ void gui_init(dt_iop_module_t *self) // gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("double click // to reset curve")); - gtk_widget_add_events(GTK_WIDGET(g->area), - GDK_POINTER_MOTION_MASK | darktable.gui->scroll_mask - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); + gtk_widget_add_events(GTK_WIDGET(g->area), darktable.gui->scroll_mask); gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_area_draw_callback), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(_area_button_press_callback), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(_area_motion_notify_callback), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", - G_CALLBACK(_area_leave_notify_callback), self); + dt_gui_connect_click_all(g->area, _rgbcurve_button_press, NULL, self); + dt_gui_connect_motion(g->area, _rgbcurve_motion, NULL, _rgbcurve_leave, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(_area_scrolled_callback), self); g_signal_connect(G_OBJECT(g->area), "key-press-event", diff --git a/src/iop/rgblevels.c b/src/iop/rgblevels.c index 1a7aeafb46ad..93f81a52a31d 100644 --- a/src/iop/rgblevels.c +++ b/src/iop/rgblevels.c @@ -359,14 +359,12 @@ void gui_post_expose(dt_iop_module_t *self, cairo_stroke(cr); } -static gboolean _area_leave_notify_callback(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self) +static void _rgblevels_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_rgblevels_gui_data_t *g = self->gui_data; g->mouse_x = g->mouse_y = -1.0; - gtk_widget_queue_draw(widget); - return TRUE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } static gboolean _area_draw_callback(GtkWidget *widget, @@ -548,28 +546,29 @@ static void _rgblevels_move_handle(dt_iop_module_t *self, gtk_widget_queue_draw(GTK_WIDGET(g->area)); } -static gboolean _area_motion_notify_callback(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self) +static void _rgblevels_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { dt_iop_rgblevels_gui_data_t *g = self->gui_data; dt_iop_rgblevels_params_t *p = self->params; const int inset = DT_GUI_CURVE_EDITOR_INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); int height = allocation.height - 2 * inset - DT_RESIZE_HANDLE_SIZE, width = allocation.width - 2 * inset; if(!g->dragging) { - g->mouse_x = CLAMP(event->x - inset, 0, width); + g->mouse_x = CLAMP(x - inset, 0, width); g->drag_start_percentage = (p->levels[g->channel][1] - p->levels[g->channel][0]) / (p->levels[g->channel][2] - p->levels[g->channel][0]); } - g->mouse_y = CLAMP(event->y - inset, 0, height); + g->mouse_y = CLAMP(y - inset, 0, height); if(g->dragging) { if(g->handle_move >= 0 && g->handle_move < 3) { - const float mx = (CLAMP(event->x - inset, 0, width)) / (float)width; + const float mx = (CLAMP(x - inset, 0, width)) / (float)width; _rgblevels_move_handle(self, g->handle_move, mx, p->levels[g->channel], g->drag_start_percentage); } @@ -577,7 +576,7 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, else { g->handle_move = 0; - const float mx = CLAMP(event->x - inset, 0, width) / (float)width; + const float mx = CLAMP(x - inset, 0, width) / (float)width; float dist = fabsf(p->levels[g->channel][0] - mx); for(int k = 1; k < 3; k++) { @@ -591,62 +590,55 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, darktable.control->element = g->handle_move; - gtk_widget_queue_draw(widget); + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - - return TRUE; } -static gboolean _area_button_press_callback(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _rgblevels_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { // set active point - if(event->button == GDK_BUTTON_PRIMARY) - { - if(darktable.develop->gui_module != self) dt_iop_request_focus(self); + if(darktable.develop->gui_module != self) dt_iop_request_focus(self); - if(event->type == GDK_2BUTTON_PRESS) - { - _turn_selregion_picker_off(self); + dt_gui_claim(gesture); + if(n_press == 2) + { + _turn_selregion_picker_off(self); - // Reset - dt_iop_rgblevels_gui_data_t *g = self->gui_data; - dt_iop_rgblevels_params_t *p = self->params; - const dt_iop_rgblevels_params_t *const default_params = self->default_params; + // Reset + dt_iop_rgblevels_gui_data_t *g = self->gui_data; + dt_iop_rgblevels_params_t *p = self->params; + const dt_iop_rgblevels_params_t *const default_params = self->default_params; - for(int i = 0; i < 3; i++) - p->levels[g->channel][i] = default_params->levels[g->channel][i]; + for(int i = 0; i < 3; i++) + p->levels[g->channel][i] = default_params->levels[g->channel][i]; - // Needed in case the user scrolls or drags immediately after a reset, - // as drag_start_percentage is only updated when the mouse is moved. - g->drag_start_percentage = 0.5; - dt_dev_add_history_item(darktable.develop, self, TRUE); - gtk_widget_queue_draw(GTK_WIDGET(g->area)); - } - else - { - _turn_selregion_picker_off(self); + // Needed in case the user scrolls or drags immediately after a reset, + // as drag_start_percentage is only updated when the mouse is moved. + g->drag_start_percentage = 0.5; + dt_dev_add_history_item(darktable.develop, self, TRUE); + gtk_widget_queue_draw(GTK_WIDGET(g->area)); + } + else + { + _turn_selregion_picker_off(self); - dt_iop_rgblevels_gui_data_t *g = self->gui_data; - g->dragging = 1; - } - return TRUE; + dt_iop_rgblevels_gui_data_t *g = self->gui_data; + g->dragging = 1; } - return FALSE; } -static gboolean _area_button_release_callback(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _rgblevels_button_release(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - if(event->button == GDK_BUTTON_PRIMARY) - { - dt_iop_rgblevels_gui_data_t *g = self->gui_data; - g->dragging = 0; - return TRUE; - } - return FALSE; + dt_iop_rgblevels_gui_data_t *g = self->gui_data; + g->dragging = 0; } static gboolean _area_scroll_callback(GtkWidget *widget, @@ -1054,14 +1046,8 @@ void gui_init(dt_iop_module_t *self) "operates on L channel.")); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_area_draw_callback), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(_area_button_press_callback), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", - G_CALLBACK(_area_button_release_callback), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(_area_motion_notify_callback), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", - G_CALLBACK(_area_leave_notify_callback), self); + dt_gui_connect_click(g->area, _rgblevels_button_press, _rgblevels_button_release, self); + dt_gui_connect_motion(g->area, _rgblevels_motion, NULL, _rgblevels_leave, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(_area_scroll_callback), self); diff --git a/src/iop/tonecurve.c b/src/iop/tonecurve.c index 73b41414caab..bb2159a5908d 100644 --- a/src/iop/tonecurve.c +++ b/src/iop/tonecurve.c @@ -50,15 +50,17 @@ DT_MODULE_INTROSPECTION(5, dt_iop_tonecurve_params_t) static gboolean dt_iop_tonecurve_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t *self); -static gboolean dt_iop_tonecurve_motion_notify(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self); -static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self); -static gboolean dt_iop_tonecurve_leave_notify(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self); +static void _tonecurve_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self); +static void _tonecurve_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self); +static void _tonecurve_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self); static gboolean dt_iop_tonecurve_key_press(GtkWidget *widget, GdkEventKey *event, dt_iop_module_t *self); @@ -1290,17 +1292,11 @@ void gui_init(dt_iop_module_t *self) // FIXME: that tooltip goes in the way of the numbers when you hover a node to get a reading //gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("double click to reset curve")); - gtk_widget_add_events(GTK_WIDGET(g->area), GDK_POINTER_MOTION_MASK | darktable.gui->scroll_mask - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); + gtk_widget_add_events(GTK_WIDGET(g->area), darktable.gui->scroll_mask); gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(dt_iop_tonecurve_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(dt_iop_tonecurve_button_press), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(dt_iop_tonecurve_motion_notify), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", - G_CALLBACK(dt_iop_tonecurve_leave_notify), self); + dt_gui_connect_click_all(g->area, _tonecurve_button_press, NULL, self); + dt_gui_connect_motion(g->area, _tonecurve_motion, NULL, _tonecurve_leave, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(_scrolled), self); g_signal_connect(G_OBJECT(g->area), "key-press-event", @@ -1343,15 +1339,13 @@ void gui_cleanup(dt_iop_module_t *self) dt_draw_curve_destroy(g->minmax_curve[ch_b]); } -static gboolean dt_iop_tonecurve_leave_notify(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self) +static void _tonecurve_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_tonecurve_gui_data_t *g = self->gui_data; - if(!(event->state & GDK_BUTTON1_MASK)) + if(!(dt_controller_state(controller) & GDK_BUTTON1_MASK)) g->selected = -1; - gtk_widget_queue_draw(widget); - return FALSE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } static void picker_scale(const float *in, float *out) @@ -1751,12 +1745,14 @@ static inline int _add_node(dt_iop_tonecurve_node_t *tonecurve, return selected; } -static gboolean dt_iop_tonecurve_motion_notify(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self) +static void _tonecurve_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { dt_iop_tonecurve_gui_data_t *g = self->gui_data; dt_iop_tonecurve_params_t *p = self->params; + GtkWidget *widget = GTK_WIDGET(g->area); int ch = g->channel; int nodes = p->tonecurve_nodes[ch]; @@ -1772,15 +1768,17 @@ static gboolean dt_iop_tonecurve_motion_notify(GtkWidget *widget, int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; double old_m_x = g->mouse_x; double old_m_y = g->mouse_y; - g->mouse_x = event->x - inset; - g->mouse_y = event->y - inset; + g->mouse_x = x - inset; + g->mouse_y = y - inset; const float mx = CLAMP(g->mouse_x, 0, width) / width; const float my = 1.0f - CLAMP(g->mouse_y, 0, height) / height; const float linx = to_lin(mx, g->loglogscale, ch, g->semilog, 0), liny = to_lin(my, g->loglogscale, ch, g->semilog, 1); - if(event->state & GDK_BUTTON1_MASK) + GdkModifierType state = dt_controller_state(controller); + + if(state & GDK_BUTTON1_MASK) { // got a vertex selected: if(g->selected >= 0) @@ -1794,7 +1792,8 @@ static gboolean dt_iop_tonecurve_motion_notify(GtkWidget *widget, - to_lin(old_m_x / width - translate_mouse_x, g->loglogscale, ch, g->semilog, 0); const float dy = to_lin(1 - g->mouse_y / height - translate_mouse_y, g->loglogscale, ch, g->semilog, 1) - to_lin(1 - old_m_y / height - translate_mouse_y, g->loglogscale, ch, g->semilog, 1); - return _move_point_internal(self, widget, dx, dy, event->state); + _move_point_internal(self, widget, dx, dy, state); + return; } else if(nodes < DT_IOP_TONECURVE_MAXNODES && g->selected >= -1) { @@ -1825,12 +1824,13 @@ static gboolean dt_iop_tonecurve_motion_notify(GtkWidget *widget, finally: if(g->selected >= 0) gtk_widget_grab_focus(widget); gtk_widget_queue_draw(widget); - return TRUE; } -static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _tonecurve_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { dt_iop_tonecurve_params_t *p = self->params; const dt_iop_tonecurve_params_t *const d = self->default_params; @@ -1841,10 +1841,12 @@ static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, int nodes = p->tonecurve_nodes[ch]; dt_iop_tonecurve_node_t *tonecurve = p->tonecurve[ch]; - if(event->button == GDK_BUTTON_PRIMARY) + guint button = gtk_gesture_single_get_current_button(gesture); + if(button == GDK_BUTTON_PRIMARY) { - if(event->type == GDK_BUTTON_PRESS - && dt_modifier_is(event->state, GDK_CONTROL_MASK) + dt_gui_claim(gesture); + if(n_press == 1 + && dt_modifier_eq(event->state, GDK_CONTROL_MASK) && nodes < DT_IOP_TONECURVE_MAXNODES && g->selected == -1) { @@ -1852,10 +1854,10 @@ static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, // the pointer and y of the curve at that x const int inset = DT_GUI_CURVE_EDITOR_INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(GTK_WIDGET(g->area), &allocation); int width = allocation.width - 2 * inset; - g->mouse_x = event->x - inset; - g->mouse_y = event->y - inset; + g->mouse_x = x - inset; + g->mouse_y = y - inset; const float mx = CLAMP(g->mouse_x, 0, width) / (float)width; const float linx = to_lin(mx, g->loglogscale, ch, g->semilog, 0); @@ -1882,12 +1884,12 @@ static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, (selected < nodes && tonecurve[selected].x - linx <= 0.025))) { // evaluate the curve at the current x position - const float y = dt_draw_curve_calc_value(g->minmax_curve[ch], linx); + const float calc_y = dt_draw_curve_calc_value(g->minmax_curve[ch], linx); - if(y >= 0.0 && y <= 1.0) // never add something outside the viewport, you couldn't change it afterwards + if(calc_y >= 0.0 && calc_y <= 1.0) // never add something outside the viewport, you couldn't change it afterwards { // create a new node - selected = _add_node(tonecurve, &p->tonecurve_nodes[ch], linx, y); + selected = _add_node(tonecurve, &p->tonecurve_nodes[ch], linx, calc_y); // maybe set the new one as being selected float min = .04f; @@ -1895,17 +1897,16 @@ static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, for(int k = 0; k < nodes; k++) { float other_y = to_log(tonecurve[k].y, g->loglogscale, ch, g->semilog, 1); - float dist = (y - other_y) * (y - other_y); + float dist = (calc_y - other_y) * (calc_y - other_y); if(dist < min) g->selected = selected; } - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area + ch); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } } - return TRUE; } - else if(event->type == GDK_2BUTTON_PRESS) + else if(n_press == 2) { // reset current curve // if autoscale_ab is on: allow only reset of L curve @@ -1920,7 +1921,7 @@ static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, } g->selected = -2; // avoid motion notify re-inserting immediately. dt_bauhaus_combobox_set(g->interpolator, p->tonecurve_type[ch_L]); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area + ch); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } else @@ -1930,22 +1931,22 @@ static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, p->tonecurve_autoscale_ab = DT_S_SCALE_MANUAL; g->selected = -2; // avoid motion notify re-inserting immediately. dt_bauhaus_combobox_set(g->autoscale_ab, 1); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area + ch); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } } - return TRUE; } } - else if(event->button == GDK_BUTTON_SECONDARY && g->selected >= 0) + else if(button == GDK_BUTTON_SECONDARY && g->selected >= 0) { + dt_gui_claim(gesture); if(g->selected == 0 || g->selected == nodes - 1) { float reset_value = g->selected == 0 ? 0 : 1; tonecurve[g->selected].y = tonecurve[g->selected].x = reset_value; gtk_widget_queue_draw(GTK_WIDGET(g->area)); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); - return TRUE; + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area + ch); + return; } for(int k = g->selected; k < nodes - 1; k++) @@ -1957,10 +1958,8 @@ static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, g->selected = -2; // avoid re-insertion of that point immediately after this p->tonecurve_nodes[ch]--; gtk_widget_queue_draw(GTK_WIDGET(g->area)); - dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); - return TRUE; + dt_dev_add_history_item_target(darktable.develop, self, TRUE, g->area + ch); } - return FALSE; } // clang-format off diff --git a/src/iop/toneequal.c b/src/iop/toneequal.c index 81a29351fdf8..bc73da0e5570 100644 --- a/src/iop/toneequal.c +++ b/src/iop/toneequal.c @@ -2935,13 +2935,13 @@ static gboolean area_draw(GtkWidget *widget, return TRUE; } - -static gboolean area_enter_leave_notify(GtkWidget *widget, - const GdkEventCrossing *event, - dt_iop_module_t *self) +static void _toneequal_enter(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { - if(darktable.gui->reset) return TRUE; - if(!self->enabled) return FALSE; + if(darktable.gui->reset) return; + if(!self->enabled) return; dt_iop_toneequalizer_gui_data_t *g = self->gui_data; @@ -2955,8 +2955,8 @@ static gboolean area_enter_leave_notify(GtkWidget *widget, dt_dev_add_history_item(darktable.develop, self, FALSE); } dt_iop_gui_enter_critical_section(self); - g->area_x = (event->x - g->inset); - g->area_y = (event->y - g->inset); + g->area_x = (x - g->inset); + g->area_y = (y - g->inset); g->area_dragging = FALSE; g->area_active_node = -1; g->area_cursor_valid = (g->area_x > 0.0f @@ -2966,22 +2966,21 @@ static gboolean area_enter_leave_notify(GtkWidget *widget, dt_iop_gui_leave_critical_section(self); gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return FALSE; } - -static gboolean area_button_press(GtkWidget *widget, - const GdkEventButton *event, - dt_iop_module_t *self) +static void _toneequal_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - - if(darktable.gui->reset) return TRUE; + if(darktable.gui->reset) return; dt_iop_toneequalizer_gui_data_t *g = self->gui_data; dt_iop_request_focus(self); - if(event->button == GDK_BUTTON_PRIMARY && event->type == GDK_2BUTTON_PRESS) + if(n_press == 2) { dt_iop_toneequalizer_params_t *p = self->params; const dt_iop_toneequalizer_params_t *const d = self->default_params; @@ -3003,9 +3002,8 @@ static gboolean area_button_press(GtkWidget *widget, // Redraw graph gtk_widget_queue_draw(GTK_WIDGET(g->area)); dt_dev_add_history_item(darktable.develop, self, TRUE); - return TRUE; } - else if(event->button == GDK_BUTTON_PRIMARY) + else { if(self->enabled) { @@ -3016,22 +3014,19 @@ static gboolean area_button_press(GtkWidget *widget, { dt_dev_add_history_item(darktable.develop, self, TRUE); } - return TRUE; } // Unlock the colour picker so we can display our own custom cursor dt_iop_color_picker_reset(self, TRUE); - - return FALSE; } - -static gboolean area_motion_notify(GtkWidget *widget, - const GdkEventMotion *event, - dt_iop_module_t *self) +static void _toneequal_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { - if(darktable.gui->reset) return TRUE; - if(!self->enabled) return FALSE; + if(darktable.gui->reset) return; + if(!self->enabled) return; dt_iop_toneequalizer_gui_data_t *g = self->gui_data; dt_iop_toneequalizer_params_t *p = self->params; @@ -3041,7 +3036,7 @@ static gboolean area_motion_notify(GtkWidget *widget, // vertical distance travelled since button_pressed event dt_iop_gui_enter_critical_section(self); // graph spans over 4 EV - const float offset = (-event->y + g->area_y) / g->graph_height * 4.0f; + const float offset = (-y + g->area_y) / g->graph_height * 4.0f; const float cursor_exposure = g->area_x / g->graph_width * 8.0f - 8.0f; // Get the desired correction on exposure channels @@ -3051,8 +3046,8 @@ static gboolean area_motion_notify(GtkWidget *widget, } dt_iop_gui_enter_critical_section(self); - g->area_x = event->x - g->inset; - g->area_y = event->y; + g->area_x = x - g->inset; + g->area_y = y; g->area_cursor_valid = (g->area_x > 0.0f && g->area_x < g->graph_width && g->area_y > 0.0f @@ -3076,23 +3071,25 @@ static gboolean area_motion_notify(GtkWidget *widget, dt_iop_gui_leave_critical_section(self); gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; } -static gboolean area_button_release(GtkWidget *widget, - const GdkEventButton *event, - dt_iop_module_t *self) +static void _toneequal_button_release(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - if(darktable.gui->reset) return TRUE; - if(!self->enabled) return FALSE; + if(darktable.gui->reset) return; + if(!self->enabled) return; dt_iop_toneequalizer_gui_data_t *g = self->gui_data; // Give focus to module dt_iop_request_focus(self); - if(event->button == GDK_BUTTON_PRIMARY) + guint button = gtk_gesture_single_get_current_button(gesture); + if(button == GDK_BUTTON_PRIMARY) { const dt_iop_toneequalizer_params_t *p = self->params; @@ -3106,11 +3103,9 @@ static gboolean area_button_release(GtkWidget *widget, dt_iop_gui_enter_critical_section(self); g->area_dragging = FALSE; dt_iop_gui_leave_critical_section(self); - - return TRUE; + return; } } - return FALSE; } static gboolean area_scroll(GtkWidget *widget, @@ -3278,23 +3273,12 @@ void gui_init(dt_iop_module_t *self) g_object_set_data(G_OBJECT(wrapper), "iop-instance", self); gtk_widget_set_name(GTK_WIDGET(wrapper), "toneeqgraph"); dt_action_define_iop(self, NULL, N_("graph"), GTK_WIDGET(wrapper), NULL); - gtk_widget_add_events(GTK_WIDGET(g->area), - GDK_POINTER_MOTION_MASK | darktable.gui->scroll_mask - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); + gtk_widget_add_events(GTK_WIDGET(g->area), darktable.gui->scroll_mask); gtk_widget_set_vexpand(GTK_WIDGET(g->area), TRUE); gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(area_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(area_button_press), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", - G_CALLBACK(area_button_release), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", - G_CALLBACK(area_enter_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "enter-notify-event", - G_CALLBACK(area_enter_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(area_motion_notify), self); + dt_gui_connect_click(g->area, _toneequal_button_press, _toneequal_button_release, self); + dt_gui_connect_motion(g->area, _toneequal_motion, _toneequal_enter, NULL, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(area_scroll), self); gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("double-click to reset the curve")); diff --git a/src/iop/watermark.c b/src/iop/watermark.c index 31b121441a50..1ec4eb5721a7 100644 --- a/src/iop/watermark.c +++ b/src/iop/watermark.c @@ -1336,8 +1336,8 @@ void gui_init(dt_iop_module_t *self) label = dtgtk_reset_label_new(_("font"), self, &p->font, sizeof(p->font)); const char *str = dt_conf_get_string_const("plugins/darkroom/watermark/font"); g->fontsel = gtk_font_button_new_with_font(str==NULL?"DejaVu Sans 10":str); - GtkWidget *child = dt_gui_container_first_child(GTK_CONTAINER(gtk_bin_get_child(GTK_BIN(g->fontsel)))); - gtk_label_set_ellipsize(GTK_LABEL(child), PANGO_ELLIPSIZE_MIDDLE); + // GTK4 GtkWidget *child = dt_gui_container_first_child(GTK_CONTAINER(gtk_bin_get_child(GTK_BIN(g->fontsel)))); + // gtk_label_set_ellipsize(GTK_LABEL(child), PANGO_ELLIPSIZE_MIDDLE); gtk_widget_set_tooltip_text(g->fontsel, _("text font, tags:\n$(WATERMARK_FONT_FAMILY)\n" "$(WATERMARK_FONT_STYLE)\n$(WATERMARK_FONT_WEIGHT)")); gtk_font_button_set_show_size (GTK_FONT_BUTTON(g->fontsel), FALSE); diff --git a/src/iop/zonesystem.c b/src/iop/zonesystem.c index 3adb8be831d8..ca22d735c95a 100644 --- a/src/iop/zonesystem.c +++ b/src/iop/zonesystem.c @@ -385,14 +385,22 @@ static gboolean dt_iop_zonesystem_preview_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t *self); static gboolean dt_iop_zonesystem_bar_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t *self); -static gboolean dt_iop_zonesystem_bar_motion_notify(GtkWidget *widget, GdkEventMotion *event, - dt_iop_module_t *self); -static gboolean dt_iop_zonesystem_bar_leave_notify(GtkWidget *widget, GdkEventCrossing *event, - dt_iop_module_t *self); -static gboolean dt_iop_zonesystem_bar_button_press(GtkWidget *widget, GdkEventButton *event, - dt_iop_module_t *self); -static gboolean dt_iop_zonesystem_bar_button_release(GtkWidget *widget, GdkEventButton *event, - dt_iop_module_t *self); +static void _zonesystem_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self); +static void _zonesystem_button_release(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self); +static void _zonesystem_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self); +static void _zonesystem_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self); static gboolean dt_iop_zonesystem_bar_scrolled(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self); @@ -432,9 +440,6 @@ void gui_init(dt_iop_module_t *self) g->preview = dtgtk_drawing_area_new_with_height(0); g_signal_connect(G_OBJECT(g->preview), "size-allocate", G_CALLBACK(size_allocate_callback), self); g_signal_connect(G_OBJECT(g->preview), "draw", G_CALLBACK(dt_iop_zonesystem_preview_draw), self); - gtk_widget_add_events(GTK_WIDGET(g->preview), GDK_POINTER_MOTION_MASK - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_LEAVE_NOTIFY_MASK); /* create the zonesystem bar widget */ g->zones = gtk_drawing_area_new(); @@ -442,18 +447,10 @@ void gui_init(dt_iop_module_t *self) "left-click on a border to create a marker\n" "right-click on a marker to delete it")); g_signal_connect(G_OBJECT(g->zones), "draw", G_CALLBACK(dt_iop_zonesystem_bar_draw), self); - g_signal_connect(G_OBJECT(g->zones), "motion-notify-event", G_CALLBACK(dt_iop_zonesystem_bar_motion_notify), - self); - g_signal_connect(G_OBJECT(g->zones), "leave-notify-event", G_CALLBACK(dt_iop_zonesystem_bar_leave_notify), - self); - g_signal_connect(G_OBJECT(g->zones), "button-press-event", G_CALLBACK(dt_iop_zonesystem_bar_button_press), - self); - g_signal_connect(G_OBJECT(g->zones), "button-release-event", - G_CALLBACK(dt_iop_zonesystem_bar_button_release), self); + dt_gui_connect_click_all(g->zones, _zonesystem_button_press, _zonesystem_button_release, self); + dt_gui_connect_motion(g->zones, _zonesystem_motion, NULL, _zonesystem_leave, self); g_signal_connect(G_OBJECT(g->zones), "scroll-event", G_CALLBACK(dt_iop_zonesystem_bar_scrolled), self); - gtk_widget_add_events(GTK_WIDGET(g->zones), GDK_POINTER_MOTION_MASK - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_LEAVE_NOTIFY_MASK | darktable.gui->scroll_mask); + gtk_widget_add_events(GTK_WIDGET(g->zones), darktable.gui->scroll_mask); gtk_widget_set_size_request(g->zones, -1, DT_PIXEL_APPLY_DPI(40)); self->widget = dt_gui_vbox(g->preview, g->zones); @@ -571,14 +568,17 @@ static gboolean dt_iop_zonesystem_bar_draw(GtkWidget *widget, cairo_t *crf, dt_i return TRUE; } -static gboolean dt_iop_zonesystem_bar_button_press(GtkWidget *widget, GdkEventButton *event, - dt_iop_module_t *self) +static void _zonesystem_button_press(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { dt_iop_zonesystem_params_t *p = self->params; dt_iop_zonesystem_gui_data_t *g = self->gui_data; const int inset = DT_ZONESYSTEM_INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(g->zones, &allocation); int width = allocation.width - 2 * inset; /*, height = allocation.height - 2*inset;*/ /* calculate zonemap */ @@ -590,8 +590,8 @@ static gboolean dt_iop_zonesystem_bar_button_press(GtkWidget *widget, GdkEventBu float zw = zonemap[k + 1] - zonemap[k]; if((g->mouse_x / width) > zonemap[k] + (zw / 2)) k++; - - if(event->button == GDK_BUTTON_PRIMARY) + guint button = gtk_gesture_single_get_current_button(gesture); + if(button == GDK_BUTTON_PRIMARY) { if(p->zone[k] == -1) { @@ -601,25 +601,26 @@ static gboolean dt_iop_zonesystem_bar_button_press(GtkWidget *widget, GdkEventBu g->is_dragging = TRUE; g->current_zone = k; } - else if(event->button == GDK_BUTTON_SECONDARY) + else if(button == GDK_BUTTON_SECONDARY) { /* clear the controlpoint */ p->zone[k] = -1; dt_dev_add_history_item(darktable.develop, self, TRUE); } - - return TRUE; } -static gboolean dt_iop_zonesystem_bar_button_release(GtkWidget *widget, GdkEventButton *event, - dt_iop_module_t *self) +static void _zonesystem_button_release(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { dt_iop_zonesystem_gui_data_t *g = self->gui_data; - if(event->button == GDK_BUTTON_PRIMARY) + guint button = gtk_gesture_single_get_current_button(gesture); + if(button == GDK_BUTTON_PRIMARY) { g->is_dragging = FALSE; } - return TRUE; } static gboolean dt_iop_zonesystem_bar_scrolled(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self) @@ -641,23 +642,24 @@ static gboolean dt_iop_zonesystem_bar_scrolled(GtkWidget *widget, GdkEventScroll return TRUE; } -static gboolean dt_iop_zonesystem_bar_leave_notify(GtkWidget *widget, GdkEventCrossing *event, - dt_iop_module_t *self) +static void _zonesystem_leave(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_zonesystem_gui_data_t *g = self->gui_data; g->hilite_zone = FALSE; gtk_widget_queue_draw(g->preview); - return TRUE; } -static gboolean dt_iop_zonesystem_bar_motion_notify(GtkWidget *widget, GdkEventMotion *event, - dt_iop_module_t *self) +static void _zonesystem_motion(GtkEventControllerMotion *controller, + double x, + double y, + dt_iop_module_t *self) { dt_iop_zonesystem_params_t *p = self->params; dt_iop_zonesystem_gui_data_t *g = self->gui_data; const int inset = DT_ZONESYSTEM_INSET; GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(g->zones, &allocation); int width = allocation.width - 2 * inset, height = allocation.height - 2 * inset; /* calculate zonemap */ @@ -665,8 +667,8 @@ static gboolean dt_iop_zonesystem_bar_motion_notify(GtkWidget *widget, GdkEventM _iop_zonesystem_calculate_zonemap(p, zonemap); /* record mouse position within control */ - g->mouse_x = CLAMP(event->x - inset, 0, width); - g->mouse_y = CLAMP(height - 1 - event->y + inset, 0, height); + g->mouse_x = CLAMP(x - inset, 0, width); + g->mouse_y = CLAMP(height - 1 - y + inset, 0, height); if(g->is_dragging) { @@ -703,7 +705,6 @@ static gboolean dt_iop_zonesystem_bar_motion_notify(GtkWidget *widget, GdkEventM gtk_widget_queue_draw(self->widget); gtk_widget_queue_draw(g->preview); - return TRUE; } diff --git a/src/libs/backgroundjobs.c b/src/libs/backgroundjobs.c index b791f704293f..5d8e4da65e2d 100644 --- a/src/libs/backgroundjobs.c +++ b/src/libs/backgroundjobs.c @@ -134,7 +134,7 @@ static gboolean _added_gui_thread(gpointer user_data) gtk_widget_show_all(params->instance_widget); gtk_widget_show(params->self_widget); - GdkCursor *cursor = gdk_cursor_new_for_display(gdk_display_get_default(), GDK_LEFT_PTR); + GdkCursor *cursor = gdk_cursor_new_from_name(gdk_display_get_default(), "default"); gdk_window_set_cursor(gtk_widget_get_window(params->instance_widget), cursor); g_object_unref(cursor); diff --git a/src/libs/colorpicker.c b/src/libs/colorpicker.c index 980b89318552..3119623acabe 100644 --- a/src/libs/colorpicker.c +++ b/src/libs/colorpicker.c @@ -26,6 +26,7 @@ #include "develop/develop.h" #include "develop/imageop.h" #include "dtgtk/button.h" +#include "dtgtk/drawingarea.h" #include "dtgtk/togglebutton.h" #include "gui/accelerators.h" #include "gui/color_picker_proxy.h" @@ -402,11 +403,9 @@ static gboolean _sample_tooltip_callback(GtkWidget *widget, static GtkWidget *view = NULL; if(!view) { - view = gtk_text_view_new(); + g_set_weak_pointer(&view, gtk_text_view_new()); dt_gui_add_class(view, "dt_transparent_background"); dt_gui_add_class(view, "dt_monospace"); - g_signal_connect(G_OBJECT(view), "destroy", - G_CALLBACK(gtk_widget_destroyed), &view); } GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)); diff --git a/src/libs/export.c b/src/libs/export.c index f0fde6b71cd0..620c15c84511 100644 --- a/src/libs/export.c +++ b/src/libs/export.c @@ -490,6 +490,7 @@ static void _batch_export_button_clicked(GtkWidget *widget, dt_lib_module_t *sel static void _scale_changed(GtkEntry *spin, dt_lib_export_t *d) { + if(darktable.gui->reset) return; const char *validSign = ",.0123456789"; const gchar *value = gtk_entry_get_text(spin); @@ -546,7 +547,9 @@ static void _scale_changed(GtkEntry *spin, } } dt_conf_set_string(CONFIG_PREFIX "resizing_factor", new_value); + ++darktable.gui->reset; gtk_entry_set_text(spin, new_value); + --darktable.gui->reset; } static void _width_changed(GtkEditable *entry, gpointer user_data); diff --git a/src/libs/filtering.c b/src/libs/filtering.c index e6a9bfb5dafc..570a5ca8b15d 100644 --- a/src/libs/filtering.c +++ b/src/libs/filtering.c @@ -1729,7 +1729,6 @@ static void _topbar_show_pref_menu(dt_lib_module_t *self, GtkWidget *bt) // initialize the popover d->topbar_popup = gtk_popover_new(bt); - g_object_set(G_OBJECT(d->topbar_popup), "transitions-enabled", FALSE, NULL); GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_container_add(GTK_CONTAINER(d->topbar_popup), vbox); diff --git a/src/libs/filters/rating_range.c b/src/libs/filters/rating_range.c index aa16f8585730..1c4f3b0a65f1 100644 --- a/src/libs/filters/rating_range.c +++ b/src/libs/filters/rating_range.c @@ -179,7 +179,7 @@ static void _rating_paint_icon(cairo_t *cr, gint x, gint y, gint w, gint h, gint { // first, we set the color depending on the flags void *my_data = NULL; - GdkRGBA shade_color; + struct { gdouble red; gdouble green; gdouble blue; gdouble alpha;} shade_color; if((flags & CPF_PRELIGHT) || (flags & CPF_ACTIVE)) { diff --git a/src/libs/histogram.c b/src/libs/histogram.c index 72ce7f1e0efb..46ac6cce81ce 100644 --- a/src/libs/histogram.c +++ b/src/libs/histogram.c @@ -1640,7 +1640,7 @@ static void _drawable_motion(GtkEventControllerMotion *controller, double y, dt_lib_histogram_t *d) { - if(dt_key_modifier_state() & GDK_BUTTON1_MASK) + if(dt_controller_state(controller) & GDK_BUTTON1_MASK) { if(d->scope_type != DT_LIB_HISTOGRAM_SCOPE_HISTOGRAM && d->scope_orient != DT_LIB_HISTOGRAM_ORIENT_VERT) @@ -1818,7 +1818,7 @@ static void _drawable_leave(GtkEventControllerMotion *controller, // if dragging, gtk keeps up motion notifications until mouse button // is released, at which point we'll get another leave event for // drawable if pointer is still outside of the widget - if(!(dt_key_modifier_state() & GDK_BUTTON1_MASK) + if(!(dt_controller_state(controller) & GDK_BUTTON1_MASK) && d->highlight != DT_LIB_HISTOGRAM_HIGHLIGHT_NONE) { d->highlight = DT_LIB_HISTOGRAM_HIGHLIGHT_NONE; diff --git a/src/libs/history.c b/src/libs/history.c index 94e343064582..be6f3ebdf507 100644 --- a/src/libs/history.c +++ b/src/libs/history.c @@ -182,7 +182,6 @@ static GtkWidget *_lib_history_create_button(dt_lib_module_t *self, const gboolean deprecated) { /* create label */ - GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gchar numlab[10]; g_snprintf(numlab, sizeof(numlab), "%2d", num + 1); @@ -243,11 +242,7 @@ static GtkWidget *_lib_history_create_button(dt_lib_module_t *self, g_object_set_data(G_OBJECT(widget), "history-number", GINT_TO_POINTER(num + 1)); g_object_set_data(G_OBJECT(widget), "label", (gpointer)label); - gtk_box_pack_start(GTK_BOX(hbox), numwidget, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - gtk_box_pack_end(GTK_BOX(hbox), onoff, FALSE, FALSE, 0); - - return hbox; + return dt_gui_hbox(numwidget, dt_gui_expand(widget), onoff); } static void _reset_module_instance(GList *hist, @@ -1033,14 +1028,9 @@ static gboolean _changes_tooltip_callback(GtkWidget *widget, if(show_tooltip) { - static GtkWidget *view = NULL; - if(!view) - { - view = gtk_text_view_new(); - dt_gui_add_class(view, "dt_transparent_background"); - dt_gui_add_class(view, "dt_monospace"); - g_signal_connect(G_OBJECT(view), "destroy", G_CALLBACK(gtk_widget_destroyed), &view); - } + GtkWidget *view = gtk_text_view_new(); + dt_gui_add_class(view, "dt_transparent_background"); + dt_gui_add_class(view, "dt_monospace"); // find tabs to align columns and decimals int t[5] = { 0 }; @@ -1092,9 +1082,7 @@ static gboolean _changes_tooltip_callback(GtkWidget *widget, GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)); gtk_text_buffer_set_text(buffer, tooltip_text, -1); gtk_tooltip_set_custom(tooltip, view); - gtk_widget_map(view); // FIXME: workaround added in order to fix - // #9908, probably a Gtk issue, remove when - // fixed upstream + // GTK4 tooltip does not get resized automatically } g_free(tooltip_text); diff --git a/src/libs/image.c b/src/libs/image.c index 01276b1b49b3..2a5330f95414 100644 --- a/src/libs/image.c +++ b/src/libs/image.c @@ -614,7 +614,7 @@ void gui_init(dt_lib_module_t *self) dt_conf_get_bool("plugins/lighttable/copy_metadata/" #item)); \ dt_action_define(DT_ACTION(meta), N_("flags"), \ label, flag, &dt_action_def_toggle); \ - g_signal_connect(G_OBJECT(flag), "clicked", \ + g_signal_connect(G_OBJECT(flag), "toggled", \ G_CALLBACK(_##item##_flag_callback), self); } META_FLAG_BUTTON(N_("ratings"), rating, 0, _("select ratings metadata")); diff --git a/src/libs/lib.c b/src/libs/lib.c index 78c21d493e3f..d4bc754dd40a 100644 --- a/src/libs/lib.c +++ b/src/libs/lib.c @@ -24,7 +24,6 @@ #include "control/control.h" #include "dtgtk/button.h" #include "dtgtk/expander.h" -#include "dtgtk/icon.h" #include "gui/accelerators.h" #include "gui/drag_and_drop.h" #include "gui/gtk.h" @@ -854,8 +853,16 @@ static gboolean _lib_draw_callback(GtkWidget *widget, } void dt_lib_gui_queue_update(dt_lib_module_t *module) +{ + // module->gui_uptodate = FALSE; + +// GTK4 need to implement class with snapshot override in expander for delayed updating +if(module->gui_uptodate) { module->gui_uptodate = FALSE; + dt_lib_gui_update(module); +} + gtk_widget_queue_draw(module->widget); } @@ -882,9 +889,10 @@ static void dt_lib_init_module(void *m) if(module->widget) { g_object_ref_sink(module->widget); - if(module->gui_update) - g_signal_connect(G_OBJECT(module->widget), "draw", - G_CALLBACK(_lib_draw_callback), module); +module->gui_uptodate = TRUE; // GTK4 + // if(module->gui_update) + // g_signal_connect(G_OBJECT(module->widget), "draw", + // G_CALLBACK(_lib_draw_callback), module); } } } @@ -1265,7 +1273,6 @@ GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module) g_signal_connect(G_OBJECT(module->arrow), "button-press-event", G_CALLBACK(_lib_plugin_arrow_button_press), module); dt_action_define(&module->actions, NULL, NULL, module->arrow, NULL); - gtk_box_pack_start(GTK_BOX(header), module->arrow, FALSE, FALSE, 0); /* add module label */ GtkWidget *label = gtk_label_new(""); @@ -1282,7 +1289,6 @@ GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module) g_object_set(G_OBJECT(label), "halign", GTK_ALIGN_START, "xalign", 0.0, (gchar *)0); gtk_widget_set_name(label, "lib-panel-label"); dt_action_define(&module->actions, NULL, NULL, label_evb, NULL); - gtk_box_pack_start(GTK_BOX(header), label_evb, FALSE, FALSE, 0); /* add preset button if module has implementation */ module->presets_button = dtgtk_button_new(dtgtk_cairo_paint_presets, 0, NULL); @@ -1297,7 +1303,6 @@ GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module) gtk_widget_set_sensitive(GTK_WIDGET(module->presets_button), FALSE); dt_action_define(&module->actions, NULL, NULL, module->presets_button, NULL); - gtk_box_pack_end(GTK_BOX(header), module->presets_button, FALSE, FALSE, 0); /* add reset button if module has implementation */ module->reset_button = dtgtk_button_new(dtgtk_cairo_paint_reset, 0, NULL); @@ -1308,7 +1313,8 @@ GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module) GINT_TO_POINTER(DT_ACTION_ELEMENT_RESET)); if(!module->gui_reset) gtk_widget_set_sensitive(module->reset_button, FALSE); dt_action_define(&module->actions, NULL, NULL, module->reset_button, NULL); - gtk_box_pack_end(GTK_BOX(header), module->reset_button, FALSE, FALSE, 0); + + dt_gui_box_add(header, module->arrow, dt_gui_expand(label_evb), module->reset_button, module->presets_button); /* add button box - for module's specific action button */ if(module->gui_tool_box) @@ -1319,7 +1325,7 @@ GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module) if(module->widget) { dt_gui_add_class(module->widget, "dt_plugin_ui_main"); - gtk_widget_set_hexpand(module->widget, FALSE); + // gtk_widget_set_hexpand(module->widget, FALSE); // GTK4 gtk_widget_set_vexpand(module->widget, FALSE); } dt_gui_add_class(pluginui_frame, "dt_plugin_ui"); diff --git a/src/libs/location.c b/src/libs/location.c index 5be0ce9f8af0..651548a02a24 100644 --- a/src/libs/location.c +++ b/src/libs/location.c @@ -22,7 +22,6 @@ #include "control/conf.h" #include "control/control.h" #include "control/jobs.h" -#include "dtgtk/icon.h" #include "gui/gtk.h" #include "libs/lib.h" #include "libs/lib_api.h" diff --git a/src/libs/modulegroups.c b/src/libs/modulegroups.c index 7690e939dbfc..28f5b68b41a8 100644 --- a/src/libs/modulegroups.c +++ b/src/libs/modulegroups.c @@ -25,7 +25,6 @@ #include "control/control.h" #include "develop/develop.h" #include "dtgtk/button.h" -#include "dtgtk/icon.h" #include "gui/accelerators.h" #include "gui/gtk.h" #include "gui/presets.h" @@ -536,7 +535,7 @@ static void _basics_add_widget(dt_lib_module_t *self, dt_lib_modulegroups_basic_ g_object_ref(item->widget); gtk_container_remove(GTK_CONTAINER(item->old_parent), item->widget); gtk_box_pack_start(GTK_BOX(item->box), item->widget, TRUE, TRUE, 0); - gtk_widget_set_hexpand(item->widget, FALSE); + gtk_widget_set_hexpand(item->widget, TRUE); g_object_unref(item->widget); // change the widget label to integrate section name @@ -645,7 +644,7 @@ static void _basics_add_widget(dt_lib_module_t *self, dt_lib_modulegroups_basic_ GtkWidget *sect = dt_ui_section_label_new(item->module->name()); gtk_label_set_xalign(GTK_LABEL(sect), 0.5); // we center the module name gtk_widget_show(sect); - gtk_box_pack_start(GTK_BOX(header_box), sect, TRUE, TRUE, 0); + gtk_box_insert_child_after(GTK_BOX(header_box), sect, btn); } else if(item_pos == FIRST_MODULE) // if there is no label, we handle separately in css the first module header @@ -2917,8 +2916,8 @@ void gui_init(dt_lib_module_t *self) /* search box */ d->text_entry = gtk_search_entry_new(); dt_action_define(&darktable.view_manager->proxy.darkroom.view->actions, NULL, N_("search modules"), d->text_entry, &dt_action_def_entry); - gtk_entry_set_placeholder_text(GTK_ENTRY(d->text_entry), - _("search modules by name or tag")); + gtk_search_entry_set_placeholder_text(GTK_SEARCH_ENTRY(d->text_entry), + _("search modules by name or tag")); g_signal_connect(G_OBJECT(d->text_entry), "search-changed", G_CALLBACK(_text_entry_changed_callback), self); g_signal_connect(G_OBJECT(d->text_entry), "stop-search", @@ -2932,8 +2931,8 @@ void gui_init(dt_lib_module_t *self) gtk_box_pack_start(GTK_BOX(d->hbox_search_box), visibility_wrapper, TRUE, TRUE, 0); gtk_entry_set_width_chars(GTK_ENTRY(d->text_entry), 0); gtk_entry_set_max_width_chars(GTK_ENTRY(d->text_entry), 35); - gtk_entry_set_icon_tooltip_text(GTK_ENTRY(d->text_entry), - GTK_ENTRY_ICON_SECONDARY, _("clear text")); + // GTK4 gtk_entry_set_icon_tooltip_text(GTK_ENTRY(d->text_entry), + // GTK_ENTRY_ICON_SECONDARY, _("clear text")); gtk_box_pack_start(GTK_BOX(self->widget), d->hbox_buttons, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(self->widget), d->hbox_search_box, TRUE, TRUE, 0); diff --git a/src/libs/snapshots.c b/src/libs/snapshots.c index ae403636dfd0..7ffe46b898a4 100644 --- a/src/libs/snapshots.c +++ b/src/libs/snapshots.c @@ -130,11 +130,13 @@ enum _lib_snapshot_button_items } _lib_snapshot_button_items; static GtkWidget *_lib_snapshot_button_get_item(GtkWidget *button, - const int num) + int num) { - GtkWidget *cont = gtk_bin_get_child(GTK_BIN(button)); - GList *items = gtk_container_get_children(GTK_CONTAINER(cont)); - return (GtkWidget *)g_list_nth_data(items, num); + GtkWidget *cont = gtk_button_get_child(GTK_BUTTON(button)); + GtkWidget *child = gtk_widget_get_first_child(cont); + while(child && num--) + child = gtk_widget_get_next_sibling(child); + return child; } // draw snapshot sign @@ -621,8 +623,7 @@ static void _clear_snapshot_entry(dt_lib_snapshot_t *s) GtkWidget *lstatus = _lib_snapshot_button_get_item(s->button, _SNAPSHOT_BUTTON_STATUS); gtk_widget_set_tooltip_text(s->button, ""); gtk_widget_set_tooltip_text(lstatus, ""); - gtk_widget_hide(s->button); - gtk_widget_hide(s->restore_button); + gtk_widget_hide(s->bbox); } g_free(s->module); @@ -826,33 +827,18 @@ void gui_init(dt_lib_module_t *self) _clear_snapshot_entry(s); _init_snapshot_entry(self, s); - GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - - // 4 items inside box, num, status, name, label - - gtk_box_pack_start(GTK_BOX(box), s->num, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box), s->status, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box), s->name, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(box), s->entry, TRUE, TRUE, 0); - - gtk_widget_show_all(box); - // hide entry, will be used only when editing gtk_widget_hide(s->entry); - gtk_container_add(GTK_CONTAINER(s->button), box); + gtk_button_set_child(GTK_BUTTON(s->button), dt_gui_hbox( + s->num, s->status, dt_gui_expand(s->name), dt_gui_expand(s->entry))); // add snap button and restore button - s->bbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_box_pack_start(GTK_BOX(s->bbox), s->button, TRUE, TRUE, 0); - gtk_box_pack_end(GTK_BOX(s->bbox), s->restore_button, FALSE, FALSE, 0); + s->bbox = dt_gui_hbox(dt_gui_expand(s->button), s->restore_button); /* add button to snapshot box */ - gtk_box_pack_end(GTK_BOX(d->snapshots_box), s->bbox, FALSE, FALSE, 0); - - /* prevent widget to show on external show all */ - gtk_widget_set_no_show_all(s->button, TRUE); - gtk_widget_set_no_show_all(s->restore_button, TRUE); + gtk_box_append(GTK_BOX(d->snapshots_box), s->bbox); + gtk_widget_hide(s->bbox); } /* add snapshot box and take snapshot button to widget ui*/ @@ -962,8 +948,7 @@ static void _lib_snapshots_add_button_clicked_callback(GtkWidget *widget, /* show active snapshot slots */ for(uint32_t k = 0; k < d->num_snapshots; k++) { - gtk_widget_show(d->snapshot[k].button); - gtk_widget_show(d->snapshot[k].restore_button); + gtk_widget_show(d->snapshot[k].bbox); } if(d->num_snapshots == MAX_SNAPSHOT) diff --git a/src/libs/tagging.c b/src/libs/tagging.c index 07055024ed13..ccbca2abe12e 100644 --- a/src/libs/tagging.c +++ b/src/libs/tagging.c @@ -3478,7 +3478,7 @@ void gui_init(dt_lib_module_t *self) renderer = gtk_cell_renderer_toggle_new(); gtk_tree_view_column_pack_start(col, renderer, TRUE); gtk_tree_view_column_set_cell_data_func(col, renderer, _tree_select_show, NULL, NULL); - g_object_set(renderer, "indicator-size", 8, NULL); // too big by default + // GTK4 g_object_set(renderer, "indicator-size", 8, NULL); // too big by default col = gtk_tree_view_column_new(); gtk_tree_view_append_column(view, col); @@ -3617,7 +3617,7 @@ void gui_init(dt_lib_module_t *self) gtk_tree_view_column_pack_start(col, renderer, TRUE); gtk_cell_renderer_toggle_set_activatable(GTK_CELL_RENDERER_TOGGLE(renderer), TRUE); gtk_tree_view_column_set_cell_data_func(col, renderer, _tree_select_show, NULL, NULL); - g_object_set(renderer, "indicator-size", 8, NULL); // too big by default + // GTK4 _object_set(renderer, "indicator-size", 8, NULL); // too big by default col = gtk_tree_view_column_new(); gtk_tree_view_append_column(view, col); diff --git a/src/libs/tools/global_toolbox.c b/src/libs/tools/global_toolbox.c index 5ab5b172282c..c914771ba369 100644 --- a/src/libs/tools/global_toolbox.c +++ b/src/libs/tools/global_toolbox.c @@ -331,21 +331,31 @@ static void _overlays_show_popup(GtkWidget *button, dt_lib_module_t *self) { GdkDevice *pointer = gdk_seat_get_pointer(gdk_display_get_default_seat(gdk_display_get_default())); - int x, y; - GdkWindow *pointer_window = gdk_device_get_window_at_position(pointer, &x, &y); + double x, y; + GdkSurface *surface = gdk_device_get_surface_at_position(pointer, &x, &y); gpointer pointer_widget = NULL; - if(pointer_window) - gdk_window_get_user_data(pointer_window, &pointer_widget); - - GdkRectangle rect = { gtk_widget_get_allocated_width(button) / 2, - gtk_widget_get_allocated_height(button), 1, 1 }; - - if(pointer_widget && button != pointer_widget) - gtk_widget_translate_coordinates(pointer_widget, button, x, y, &rect.x, &rect.y); + if(surface) + { + GtkNative *native = gtk_native_get_for_surface(surface); + pointer_widget = gtk_widget_pick(GTK_WIDGET(native), x, y, GTK_PICK_DEFAULT); + } - gtk_popover_set_pointing_to(GTK_POPOVER(d->over_popup), &rect); + // GTK4 FIXME position when called from shortcut + graphene_rect_t rect = {}; + if(gtk_widget_compute_bounds(button, button, &rect)) + { + // rect now contains the bounds of the button relative to itself + // For a popover, you typically want it pointing to the entire button + GdkRectangle gdk_rect = { + .x = rect.origin.x + rect.size.width / 2, + .y = rect.origin.y + rect.size.height, + .width = 1, .height = 1 + }; + gtk_popover_set_pointing_to(GTK_POPOVER(d->over_popup), &gdk_rect); + gtk_popover_set_position(GTK_POPOVER(d->over_popup), GTK_POS_BOTTOM); + } - gtk_widget_show(d->over_popup); + gtk_popover_popup(GTK_POPOVER(d->over_popup)); } else dt_control_log(_("overlays not available here...")); @@ -401,8 +411,8 @@ void gui_init(dt_lib_module_t *self) dt_action_define(&darktable.control->actions_global, NULL, N_("thumbnail overlays options"), d->overlays_button, &dt_action_def_button); gtk_widget_set_tooltip_text(d->overlays_button, _("click to change the type of overlays shown on thumbnails")); d->over_popup = gtk_popover_new(d->overlays_button); + gtk_widget_set_parent(d->over_popup, d->overlays_button); gtk_widget_set_size_request(d->over_popup, 350, -1); - g_object_set(G_OBJECT(d->over_popup), "transitions-enabled", FALSE, NULL); g_signal_connect(G_OBJECT(d->overlays_button), "clicked", G_CALLBACK(_overlays_show_popup), self); // we register size of overlay icon to keep in sync thumbtable overlays g_signal_connect(G_OBJECT(d->overlays_button), "size-allocate", G_CALLBACK(_main_icons_register_size), NULL); @@ -411,10 +421,10 @@ void gui_init(dt_lib_module_t *self) gtk_container_add(GTK_CONTAINER(d->over_popup), vbox); -#define NEW_RADIO(widget, box, callback, label) \ - rb = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(rb), _(label)); \ +#define NEW_RADIO(widget, box, callback, label) \ + rb = gtk_check_button_new_with_label(_(label)); \ dt_action_define(ac, NULL, label, rb, &dt_action_def_button); \ - g_signal_connect(G_OBJECT(rb), "clicked", G_CALLBACK(callback), self); \ + g_signal_connect(G_OBJECT(rb), "toggled", G_CALLBACK(callback), self); \ gtk_box_pack_start(GTK_BOX(box), rb, TRUE, TRUE, 0); \ widget = rb; diff --git a/src/libs/tools/ratings.c b/src/libs/tools/ratings.c index e5fe913bbd4f..ebcba8fa3925 100644 --- a/src/libs/tools/ratings.c +++ b/src/libs/tools/ratings.c @@ -21,6 +21,7 @@ #include "common/debug.h" #include "control/control.h" #include "dtgtk/button.h" +#include "dtgtk/drawingarea.h" #include "gui/draw.h" #include "gui/gtk.h" #include "gui/accelerators.h" diff --git a/src/lua/init.c b/src/lua/init.c index 54e7f79397e4..746edd0ab30d 100644 --- a/src/lua/init.c +++ b/src/lua/init.c @@ -221,7 +221,7 @@ static int load_from_lua(lua_State *L) lua_pop(L, lua_gettop(L)); argv[argc] = NULL; argv_copy[argc] = NULL; - gtk_init(&argc, &argv); + gtk_init(); if(dt_init(argc, argv, FALSE, TRUE, L)) { luaL_error(L,"Starting darktable failed."); } diff --git a/src/views/darkroom.c b/src/views/darkroom.c index 79024b965534..f6312abfa517 100644 --- a/src/views/darkroom.c +++ b/src/views/darkroom.c @@ -1518,29 +1518,40 @@ static gboolean _toolbar_show_popup(gpointer user_data) { GtkPopover *popover = GTK_POPOVER(user_data); - GtkWidget *button = gtk_popover_get_relative_to(popover); + GtkWidget *button = gtk_widget_get_parent(GTK_WIDGET(popover)); GdkDevice *pointer = gdk_seat_get_pointer(gdk_display_get_default_seat(gdk_display_get_default())); - int x, y; - GdkWindow *pointer_window = gdk_device_get_window_at_position(pointer, &x, &y); + double x, y; + GdkSurface *surface = gdk_device_get_surface_at_position(pointer, &x, &y); gpointer pointer_widget = NULL; - if(pointer_window) - gdk_window_get_user_data(pointer_window, &pointer_widget); - - GdkRectangle rect = { gtk_widget_get_allocated_width(button) / 2, 0, 1, 1 }; - - if(pointer_widget && button != pointer_widget) - gtk_widget_translate_coordinates(pointer_widget, button, x, y, &rect.x, &rect.y); - - gtk_popover_set_pointing_to(popover, &rect); + if(surface) + { + GtkNative *native = gtk_native_get_for_surface(surface); + pointer_widget = gtk_widget_pick(GTK_WIDGET(native), x, y, GTK_PICK_DEFAULT); + } +// GTK4 FIXME position when called from shortcut + graphene_rect_t rect; + if(gtk_widget_compute_bounds(button, button, &rect)) + { + // rect now contains the bounds of the button relative to itself + // For a popover, you typically want it pointing to the entire button + GdkRectangle gdk_rect = { + .x = rect.origin.x + rect.size.width / 2, + .y = rect.origin.y, + .width = 1, .height = 1 + }; +dt_print(0, "button rect: x=%d y=%d w=%d h=%d\n", gdk_rect.x, gdk_rect.y, gdk_rect.width, gdk_rect.height); + gtk_popover_set_pointing_to(GTK_POPOVER(popover), &gdk_rect); + gtk_popover_set_position(GTK_POPOVER(popover), GTK_POS_TOP); + } // for the guides popover, it need to be updated before we show it if(darktable.view_manager && GTK_WIDGET(popover) == darktable.view_manager->guides_popover) dt_guides_update_popover_values(); - gtk_widget_show_all(GTK_WIDGET(popover)); + gtk_popover_popup(popover); // cancel glib timeout if invoked by long button press return FALSE; @@ -2419,9 +2430,10 @@ static gboolean _quickbutton_press_release(GtkWidget *button, if((event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_SECONDARY) || (event->type == GDK_BUTTON_RELEASE && event->time - start_time > delay)) { - gtk_popover_set_relative_to(GTK_POPOVER(popover), button); - - g_object_set(G_OBJECT(popover), "transitions-enabled", FALSE, NULL); + g_object_ref(popover); + gtk_widget_unparent(popover); + gtk_widget_set_parent(popover, button); + g_object_unref(popover); _toolbar_show_popup(popover); return TRUE; @@ -2733,8 +2745,8 @@ void gui_init(dt_view_t *self) dev->profile.floating_window); connect_button_press_release(dev->profile.gamut_button, dev->profile.floating_window); // randomly connect to one of the buttons, so widgets can be realized - gtk_popover_set_relative_to(GTK_POPOVER(dev->profile.floating_window), - dev->second_wnd_button); + gtk_widget_set_parent(GTK_WIDGET(dev->profile.floating_window), + dev->second_wnd_button); /** let's fill the encapsulating widgets */ const int force_lcms2 = dt_conf_get_bool("plugins/lighttable/export/force_lcms2"); diff --git a/src/views/lighttable.c b/src/views/lighttable.c index 0d8e7bb990a9..9bb6cb5c011d 100644 --- a/src/views/lighttable.c +++ b/src/views/lighttable.c @@ -1242,7 +1242,6 @@ void gui_init(dt_view_t *self) // and the popup window lib->profile_floating_window = gtk_popover_new(profile_button); - g_object_set(G_OBJECT(lib->profile_floating_window), "transitions-enabled", FALSE, NULL); g_signal_connect_swapped(G_OBJECT(profile_button), "button-press-event", G_CALLBACK(gtk_widget_show_all), lib->profile_floating_window); diff --git a/src/views/view.c b/src/views/view.c index bebc33493f90..0d9d434f4c72 100644 --- a/src/views/view.c +++ b/src/views/view.c @@ -280,11 +280,6 @@ gboolean dt_view_manager_switch_by_view(dt_view_manager_t *vm, } } - /* remove all widgets in all containers */ - for(int l = 0; l < DT_UI_CONTAINER_SIZE; l++) - dt_ui_container_destroy_children(darktable.gui->ui, l); - vm->current_view = NULL; - /* remove sticky accels window */ if(vm->accels_window.window) dt_view_accels_hide(vm); @@ -338,9 +333,9 @@ gboolean dt_view_manager_switch_by_view(dt_view_manager_t *vm, so remove the child before that */ if(plugin->widget) - gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(plugin->widget)), plugin->widget); + gtk_widget_unparent(plugin->widget); if(plugin->expander) - gtk_widget_destroy(plugin->expander); + gtk_widget_unparent(plugin->expander); } plugin->expander = NULL; }