101#include <gdk/gdkkeysyms.h>
102#ifdef GDK_WINDOWING_WAYLAND
103#include <gdk/gdkwayland.h>
106#include <gdk/gdkwin32.h>
114#ifdef MAC_INTEGRATION
115#include <gtkosxapplication.h>
117#ifdef GDK_WINDOWING_QUARTZ
135 GtkStyleContext *context = gtk_widget_get_style_context(widget);
136 if(!gtk_style_context_has_class(context, class_name))
138 gtk_style_context_add_class(context, class_name);
139 gtk_widget_queue_draw(widget);
145 GtkStyleContext *context = gtk_widget_get_style_context(widget);
146 if(gtk_style_context_has_class(context, class_name))
148 gtk_style_context_remove_class(context, class_name);
149 gtk_widget_queue_draw(widget);
162 if(gdk_event_get_pointer_emulated((GdkEvent*)event))
return FALSE;
164 gboolean handled =
FALSE;
165 switch(event->direction)
168 case GDK_SCROLL_LEFT:
172 if(delta_y) *delta_y = 0.0;
176 case GDK_SCROLL_RIGHT:
180 if(delta_y) *delta_y = 0.0;
187 if(delta_x) *delta_x = 0.0;
192 case GDK_SCROLL_DOWN:
195 if(delta_x) *delta_x = 0.0;
201 case GDK_SCROLL_SMOOTH:
202 if((delta_x && event->delta_x != 0) || (delta_y && event->delta_y != 0))
204#ifdef GDK_WINDOWING_QUARTZ
205 if(delta_x) *delta_x =
dt_conf_get_bool(
"scroll/reverse_x") ? -
event->delta_x / 50. :
event->delta_x / 50.;
206 if(delta_y) *delta_y =
dt_conf_get_bool(
"scroll/reverse_y") ? -
event->delta_y / 50. :
event->delta_y / 50.;
208 if(delta_x) *delta_x =
dt_conf_get_bool(
"scroll/reverse_x") ? -
event->delta_x :
event->delta_x;
209 if(delta_y) *delta_y =
dt_conf_get_bool(
"scroll/reverse_y") ? -
event->delta_y :
event->delta_y;
222 if(gdk_event_get_pointer_emulated((GdkEvent*)event))
return FALSE;
225 static gdouble acc_x = 0.0, acc_y = 0.0;
227 gboolean handled =
FALSE;
229 switch(event->direction)
232 case GDK_SCROLL_LEFT:
236 if(delta_y) *delta_y = 0;
240 case GDK_SCROLL_RIGHT:
244 if(delta_y) *delta_y = 0;
251 if(delta_x) *delta_x = 0;
256 case GDK_SCROLL_DOWN:
259 if(delta_x) *delta_x = 0;
265 case GDK_SCROLL_SMOOTH:
275#ifdef GDK_WINDOWING_QUARTZ
276 acc_x +=
dt_conf_get_bool(
"scroll/reverse_x") ? -
event->delta_x / 50. :
event->delta_x / 50.;
277 acc_y +=
dt_conf_get_bool(
"scroll/reverse_y") ? -
event->delta_y / 50. :
event->delta_y / 50.;
279 acc_x +=
dt_conf_get_bool(
"scroll/reverse_x") ? -
event->delta_x :
event->delta_x;
280 acc_y +=
dt_conf_get_bool(
"scroll/reverse_y") ? -
event->delta_y :
event->delta_y;
282 const gdouble amt_x = trunc(acc_x);
283 const gdouble amt_y = trunc(acc_y);
284 if(amt_x != 0 || amt_y != 0)
288 if((delta_x && amt_x != 0) || (delta_y && amt_y != 0))
290 if(delta_x) *delta_x = (int)amt_x;
291 if(delta_y) *delta_y = (int)amt_y;
304 gdouble delta_x, delta_y;
307 *
delta = delta_x + delta_y;
315 int delta_x, delta_y;
318 *
delta = delta_x + delta_y;
337void dt_gtk_widget_queue_draw_ext(
GtkWidget *widget,
const char *
name,
const char *file,
const int line)
339 if(!GTK_IS_WIDGET(widget))
341 dt_print(
DT_DEBUG_GTK,
"gtk_widget_queue_draw(%s) called with a non-WIDGET or NULL widget at %s:%d (widget=%p)\n",
342 name, file, line, widget);
347 name, gtk_widget_get_name(widget), file, line);
350 (gtk_widget_queue_draw)(widget);
353void dt_gtk_toggle_button_set_active_ext(GtkToggleButton *toggle_button,
const char *
name,
const gboolean active,
354 const char *file,
const int line)
356 if(!GTK_IS_TOGGLE_BUTTON(toggle_button))
358 dt_print(
DT_DEBUG_GTK,
"gtk_toggle_button_set_active(%s) called with a non-TOGGLE_BUTTON or NULL widget at %s:%d (toggle_button=%p)\n",
359 name, file, line, toggle_button);
363 dt_print(
DT_DEBUG_GTK,
"setting toggle button `%s` (`%s`) to %s at %s:%d\n",
name, gtk_widget_get_name(GTK_WIDGET(toggle_button)),
364 active ?
"active" :
"inactive", file, line);
366 (gtk_toggle_button_set_active)(toggle_button, active);
379 event->state, delta_y);
390 const GdkWindowState window_state = gdk_window_get_state(gtk_widget_get_window(widget));
391 dt_conf_set_bool(
"ui_last/maximized", (window_state & GDK_WINDOW_STATE_MAXIMIZED));
393 gtk_window_get_size(GTK_WINDOW(widget), &
width, &
height);
397 gboolean save_window_position =
TRUE;
398#ifdef GDK_WINDOWING_WAYLAND
399 GdkDisplay *display = gtk_widget_get_display(widget);
400 if(GDK_IS_WAYLAND_DISPLAY(display))
401 save_window_position =
FALSE;
404 if(save_window_position)
406 GdkWindow *gdk_window = gtk_widget_get_window(widget);
407 GdkDisplay *window_display = gtk_widget_get_display(widget);
410 GdkMonitor *monitor = gdk_display_get_monitor_at_window(window_display, gdk_window);
413 const int n_monitors = gdk_display_get_n_monitors(window_display);
414 int monitor_index = -1;
415 for(
int i = 0;
i < n_monitors;
i++)
417 if(gdk_display_get_monitor(window_display,
i) == monitor)
423 if(monitor_index >= 0)
428 if(!(window_state & GDK_WINDOW_STATE_MAXIMIZED))
431 gtk_window_get_position(GTK_WINDOW(widget), &
x, &y);
445 cairo_set_source_rgb(cr, bc.red, bc.green, bc.blue);
451 cairo_set_source_rgba(cr, bc.red, bc.green, bc.blue, bc.alpha * opacity_coef);
458 gtk_window_set_title(GTK_WINDOW(win), _(
"closing Ansel..."));
481#ifdef MAC_INTEGRATION
482#ifdef GTK_TYPE_OSX_APPLICATION
483static gboolean _osx_quit_callback(GtkOSXApplication *OSXapp, gpointer user_data)
485static gboolean _osx_quit_callback(GtkosxApplication *OSXapp, gpointer user_data)
488 GList *windows, *window;
489 windows = gtk_window_list_toplevels();
490 for(window = windows; !
IS_NULL_PTR(window); window = g_list_next(window))
491 if(gtk_window_get_modal(GTK_WINDOW(window->data)) && gtk_widget_get_visible(GTK_WIDGET(window->data)))
494 g_list_free(windows);
499#ifdef GTK_TYPE_OSX_APPLICATION
500static gboolean _osx_openfile_callback(GtkOSXApplication *OSXapp, gchar *path, gpointer user_data)
502static gboolean _osx_openfile_callback(GtkosxApplication *OSXapp, gchar *path, gpointer user_data)
514 if(oldw != event->width || oldh != event->height)
517 cairo_surface_t *tmpsurface
525 cairo_t *cr = cairo_create(tmpsurface);
537 oldh =
event->height;
539#ifndef GDK_WINDOWING_QUARTZ
550 if(oldx != event->configure.x || oldy != event->configure.y)
554 oldx =
event->configure.x;
555 oldy =
event->configure.y;
586 case GDK_MOTION_NOTIFY:
587 return ((
const GdkEventMotion *)event)->axes;
588 case GDK_BUTTON_PRESS:
589 case GDK_2BUTTON_PRESS:
590 case GDK_3BUTTON_PRESS:
591 case GDK_BUTTON_RELEASE:
592 return ((
const GdkEventButton *)event)->axes;
599 const GdkAxisUse axis,
double *
value, gboolean *from_source_map)
601 if(from_source_map) *from_source_map =
FALSE;
605 if(source_device && axes)
607 double source_value = 0.0;
608 if(gdk_device_get_axis(source_device, (gdouble *)axes, axis, &source_value))
610 *
value = source_value;
611 if(from_source_map) *from_source_map =
TRUE;
616 return gdk_event_get_axis((GdkEvent *)event, axis,
value);
620 const GdkAxisUse axis,
double *
value)
623 if(gdk_device_get_source(device) == GDK_SOURCE_KEYBOARD)
return FALSE;
624 if(gdk_device_get_device_type(device) == GDK_DEVICE_TYPE_SLAVE)
626 GdkDisplay *display = gdk_device_get_display(device);
627 if(!display || !gdk_display_device_is_grabbed(display, device))
return FALSE;
630 const int n_axes = gdk_device_get_n_axes(device);
631 if(n_axes <= 0)
return FALSE;
633 double *axes = g_newa(
double, n_axes);
634 memset(axes, 0,
sizeof(
double) * n_axes);
635 GdkModifierType modifiers = 0;
636 gdk_device_get_state(device, window, axes, &modifiers);
637 return gdk_device_get_axis(device, axes, axis,
value);
641 double *pressure, gboolean *have_pressure,
642 double *tilt_x,
double *tilt_y, gboolean *have_tilt,
643 const char **picked_device_name)
645 if(pressure) *pressure = 0.0;
646 if(have_pressure) *have_pressure =
FALSE;
647 if(tilt_x) *tilt_x = 0.0;
648 if(tilt_y) *tilt_y = 0.0;
649 if(have_tilt) *have_tilt =
FALSE;
650 if(picked_device_name) *picked_device_name = NULL;
653 GdkWindow *window = gdk_event_get_window((GdkEvent *)event);
659 gboolean best_have_p =
FALSE;
660 double best_tx = 0.0;
661 double best_ty = 0.0;
662 gboolean best_have_t =
FALSE;
663 const char *best_name = NULL;
665 GdkSeat *seat = gdk_display_get_default() ? gdk_display_get_default_seat(gdk_display_get_default()) : NULL;
666 GList *runtime_devices = seat ? gdk_seat_get_slaves(seat, GDK_SEAT_CAPABILITY_ALL_POINTING) : NULL;
668 for(GList *l = runtime_devices; l; l = g_list_next(l))
670 GdkDevice *device = (GdkDevice *)l->data;
672 const GdkInputSource source = gdk_device_get_source(device);
673 if(source == GDK_SOURCE_KEYBOARD)
continue;
674 if(gdk_device_get_device_type(device) == GDK_DEVICE_TYPE_SLAVE)
676 GdkDisplay *display = gdk_device_get_display(device);
679 if(!display || !gdk_display_device_is_grabbed(display, device))
continue;
682 const GdkAxisFlags axis_flags = gdk_device_get_axes(device);
683 const gboolean supports_pressure = (axis_flags & GDK_AXIS_FLAG_PRESSURE) != 0;
684 const gboolean supports_x_tilt = (axis_flags & GDK_AXIS_FLAG_XTILT) != 0;
685 const gboolean supports_y_tilt = (axis_flags & GDK_AXIS_FLAG_YTILT) != 0;
686 const gboolean pen_like = (source == GDK_SOURCE_PEN || source == GDK_SOURCE_ERASER || source == GDK_SOURCE_CURSOR);
687 if(!supports_pressure && !supports_x_tilt && !supports_y_tilt && !pen_like)
continue;
689 const int n_axes = gdk_device_get_n_axes(device);
690 if(n_axes <= 0)
continue;
691 double *axes = g_newa(
double, n_axes);
692 memset(axes, 0,
sizeof(
double) * n_axes);
693 GdkModifierType modifiers = 0;
694 gdk_device_get_state(device, window, axes, &modifiers);
697 gboolean have_p =
FALSE;
700 gboolean have_tx =
FALSE;
701 gboolean have_ty =
FALSE;
703 for(
int i = 0;
i < n_axes;
i++)
705 const GdkAxisUse use = gdk_device_get_axis_use(device,
i);
706 if(use == GDK_AXIS_PRESSURE)
711 else if(use == GDK_AXIS_XTILT)
716 else if(use == GDK_AXIS_YTILT)
723 const gboolean have_t = have_tx || have_ty;
724 const int score = (have_p ? 2 : 0) + (have_t ? 2 : 0) + (
p > 1e-4 ? 4 : 0)
725 + ((hypot(tx, ty) > 1e-4) ? 3 : 0) + (pen_like ? 1 : 0);
726 if(score <= best_score)
continue;
730 best_have_p = have_p;
733 best_have_t = have_t;
734 best_name = gdk_device_get_name(device);
738 g_list_free(runtime_devices);
739 runtime_devices = NULL;
742 if(best_score < 0)
return FALSE;
743 if(pressure) *pressure = best_p;
744 if(have_pressure) *have_pressure = best_have_p;
745 if(tilt_x) *tilt_x = best_tx;
746 if(tilt_y) *tilt_y = best_ty;
747 if(have_tilt) *have_tilt = best_have_t;
748 if(picked_device_name) *picked_device_name = best_name;
753 const guint32 time_ms,
const gboolean reset_kinematics,
760 GdkDevice *source_device = gdk_event_get_source_device((GdkEvent *)event);
761 GdkDevice *event_device = gdk_event_get_device((GdkEvent *)event);
762 GdkDevice *device = source_device ? source_device : event_device;
763 const GdkInputSource source = device ? gdk_device_get_source(device) : GDK_SOURCE_MOUSE;
764 const GdkAxisFlags axis_flags = device ? gdk_device_get_axes(device) : 0;
765 const gboolean supports_pressure = (axis_flags & GDK_AXIS_FLAG_PRESSURE) != 0;
766 const gboolean supports_x_tilt = (axis_flags & GDK_AXIS_FLAG_XTILT) != 0;
767 const gboolean supports_y_tilt = (axis_flags & GDK_AXIS_FLAG_YTILT) != 0;
768 gboolean read_pressure =
FALSE;
769 gboolean read_x_tilt =
FALSE;
770 gboolean read_y_tilt =
FALSE;
771 gboolean map_pressure_source =
FALSE;
772 gboolean map_xtilt_source =
FALSE;
773 gboolean map_ytilt_source =
FALSE;
774 gboolean state_pressure_source =
FALSE;
775 gboolean state_pressure_event =
FALSE;
776 gboolean state_xtilt_source =
FALSE;
777 gboolean state_ytilt_source =
FALSE;
778 gboolean fallback_pressure =
FALSE;
779 gboolean fallback_tilt =
FALSE;
780 const char *fallback_device_name = NULL;
781 GdkDeviceTool *tool = gdk_event_get_device_tool((GdkEvent *)event);
782 const int tool_type = tool ? (int)gdk_device_tool_get_tool_type(tool) : -1;
783 const gboolean tool_is_stylus
784 = tool && (tool_type == GDK_DEVICE_TOOL_TYPE_PEN || tool_type == GDK_DEVICE_TOOL_TYPE_ERASER
785 || tool_type == GDK_DEVICE_TOOL_TYPE_BRUSH || tool_type == GDK_DEVICE_TOOL_TYPE_PENCIL
786 || tool_type == GDK_DEVICE_TOOL_TYPE_AIRBRUSH);
787 gboolean is_tablet_like = supports_pressure || supports_x_tilt || supports_y_tilt || tool_is_stylus;
788 GdkWindow *window = gdk_event_get_window((GdkEvent *)event);
792 double pressure = 0.0;
795 read_pressure =
TRUE;
806 else if(!is_tablet_like)
814 double p_state = 0.0;
818 state_pressure_source =
TRUE;
824 state_pressure_event =
TRUE;
831 const gboolean has_x_tilt
833 const gboolean has_y_tilt
835 read_x_tilt = has_x_tilt;
836 read_y_tilt = has_y_tilt;
837 if(has_x_tilt || has_y_tilt)
839 input.
tilt_x = CLAMP(x_tilt, -1.0, 1.0);
840 input.
tilt_y = CLAMP(y_tilt, -1.0, 1.0);
852 else if(!is_tablet_like)
860 double tx_state = 0.0, ty_state = 0.0;
865 input.
tilt_x = CLAMP(tx_state, -1.0, 1.0);
866 input.
tilt_y = CLAMP(ty_state, -1.0, 1.0);
871 state_xtilt_source = has_tx;
872 state_ytilt_source = has_ty;
883 double fb_pressure = 0.0;
884 gboolean fb_have_pressure =
FALSE;
885 double fb_tilt_x = 0.0;
886 double fb_tilt_y = 0.0;
887 gboolean fb_have_tilt =
FALSE;
889 &fb_tilt_x, &fb_tilt_y, &fb_have_tilt,
890 &fallback_device_name))
896 fallback_pressure =
TRUE;
900 input.
tilt_x = CLAMP(fb_tilt_x, -1.0, 1.0);
901 input.
tilt_y = CLAMP(fb_tilt_y, -1.0, 1.0);
904 fallback_tilt =
TRUE;
927 const double speed_px_s = hypot(dx, dy) / dt_s;
946 "[tablet] %s dev='%s' src_dev='%s' evt_dev='%s' src=%d tablet=%d tool=%d supports[p=%d xt=%d yt=%d] read[p=%d xt=%d yt=%d] map_src[p=%d xt=%d yt=%d] state[p_src=%d p_evt=%d xt_src=%d yt_src=%d] fallback[p=%d t=%d dev='%s'] values[p=%.4f tx=%.4f ty=%.4f t=%.4f a=%.4f] xy=(%.1f, %.1f) t_ms=%u reset=%d\n",
948 device ? gdk_device_get_name(device) :
"<none>",
949 source_device ? gdk_device_get_name(source_device) :
"<none>",
950 event_device ? gdk_device_get_name(event_device) :
"<none>",
952 is_tablet_like ? 1 : 0,
954 supports_pressure ? 1 : 0,
955 supports_x_tilt ? 1 : 0,
956 supports_y_tilt ? 1 : 0,
957 read_pressure ? 1 : 0,
960 map_pressure_source ? 1 : 0,
961 map_xtilt_source ? 1 : 0,
962 map_ytilt_source ? 1 : 0,
963 state_pressure_source ? 1 : 0,
964 state_pressure_event ? 1 : 0,
965 state_xtilt_source ? 1 : 0,
966 state_ytilt_source ? 1 : 0,
967 fallback_pressure ? 1 : 0,
968 fallback_tilt ? 1 : 0,
969 fallback_device_name ? fallback_device_name :
"<none>",
977 reset_kinematics ? 1 : 0);
988 gtk_widget_grab_focus(w);
991 event->time,
TRUE,
"button-press");
1002 event->time,
FALSE,
"button-release");
1014 event->time,
FALSE,
"motion");
1023#define DT_WIN32_CURSOR_SUBCLASS_CENTER ((UINT_PTR)0x41534e4e)
1025static LRESULT CALLBACK _center_win32_cursor_proc(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param,
1026 UINT_PTR subclass_id, DWORD_PTR ref_data)
1033 if(subclass_id == DT_WIN32_CURSOR_SUBCLASS_CENTER && message == WM_SETCURSOR && LOWORD(l_param) == HTCLIENT)
1036 return DefSubclassProc(hwnd, message, w_param, l_param);
1039static void _center_realize(
GtkWidget *widget, gpointer user_data)
1041 GdkWindow *center_window = gtk_widget_get_window(widget);
1042 HWND center_hwnd = center_window ? (HWND)gdk_win32_window_get_handle(center_window) : NULL;
1044 SetWindowSubclass(center_hwnd, _center_win32_cursor_proc, DT_WIN32_CURSOR_SUBCLASS_CENTER, (DWORD_PTR)widget);
1047static void _center_unrealize(
GtkWidget *widget, gpointer user_data)
1049 GdkWindow *center_window = gtk_widget_get_window(widget);
1050 HWND center_hwnd = center_window ? (HWND)gdk_win32_window_get_handle(center_window) : NULL;
1052 RemoveWindowSubclass(center_hwnd, _center_win32_cursor_proc, DT_WIN32_CURSOR_SUBCLASS_CENTER);
1077 static const gchar *SOURCE_NAMES[]
1078 = {
"GDK_SOURCE_MOUSE",
"GDK_SOURCE_PEN",
"GDK_SOURCE_ERASER",
"GDK_SOURCE_CURSOR",
1079 "GDK_SOURCE_KEYBOARD",
"GDK_SOURCE_TOUCHSCREEN",
"GDK_SOURCE_TOUCHPAD",
"GDK_SOURCE_TRACKPOINT",
1080 "GDK_SOURCE_TABLET_PAD" };
1081 if(pos >= G_N_ELEMENTS(SOURCE_NAMES))
return "<UNKNOWN>";
1082 return SOURCE_NAMES[pos];
1087 static const gchar *MODE_NAMES[] = {
"GDK_MODE_DISABLED",
"GDK_MODE_SCREEN",
"GDK_MODE_WINDOW" };
1088 if(pos >= G_N_ELEMENTS(MODE_NAMES))
return "<UNKNOWN>";
1089 return MODE_NAMES[pos];
1094 static const gchar *AXIS_NAMES[]
1095 = {
"GDK_AXIS_IGNORE",
"GDK_AXIS_X",
"GDK_AXIS_Y",
"GDK_AXIS_PRESSURE",
1096 "GDK_AXIS_XTILT",
"GDK_AXIS_YTILT",
"GDK_AXIS_WHEEL",
"GDK_AXIS_DISTANCE",
1097 "GDK_AXIS_ROTATION",
"GDK_AXIS_SLIDER",
"GDK_AXIS_LAST" };
1098 if(pos >= G_N_ELEMENTS(AXIS_NAMES))
return "<UNKNOWN>";
1099 return AXIS_NAMES[pos];
1112 g_setenv(
"GTK_OVERLAY_SCROLLING",
"0", 0);
1115 g_setenv(
"LIBOVERLAY_SCROLLBAR",
"0", 0);
1125 g_strlcpy(gui->
gtkrc, css_theme,
sizeof(gui->
gtkrc));
1127 g_snprintf(gui->
gtkrc,
sizeof(gui->
gtkrc),
"ansel");
1129#ifdef MAC_INTEGRATION
1130#ifdef GTK_TYPE_OSX_APPLICATION
1131 GtkOSXApplication *OSXApp = g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1132 gtk_osxapplication_set_menu_bar(
1133 OSXApp, GTK_MENU_SHELL(gtk_menu_bar_new()));
1135 GtkosxApplication *OSXApp = g_object_new(GTKOSX_TYPE_APPLICATION, NULL);
1136 gtkosx_application_set_menu_bar(
1137 OSXApp, GTK_MENU_SHELL(gtk_menu_bar_new()));
1139 g_signal_connect(G_OBJECT(OSXApp),
"NSApplicationBlockTermination", G_CALLBACK(_osx_quit_callback), NULL);
1140 g_signal_connect(G_OBJECT(OSXApp),
"NSApplicationOpenFile", G_CALLBACK(_osx_openfile_callback), NULL);
1157 gui->
scroll_mask = GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK;
1167 gchar *keyboardrc_path = g_build_filename(configdir, keyboardrc, NULL);
1169 GtkAccelFlags
flags = 0;
1182 gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), path);
1184 gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), path);
1189 gtk_widget_set_can_focus(widget,
TRUE);
1190 gtk_widget_set_visible(widget,
TRUE);
1191 gtk_widget_grab_focus(widget);
1192 gtk_widget_add_events(widget, GDK_PROXIMITY_IN_MASK | GDK_PROXIMITY_OUT_MASK | GDK_TABLET_PAD_MASK);
1193 g_signal_connect(G_OBJECT(widget),
"configure-event", G_CALLBACK(
_configure), gui);
1194 g_signal_connect(G_OBJECT(widget),
"draw", G_CALLBACK(
_draw), NULL);
1195 g_signal_connect(G_OBJECT(widget),
"motion-notify-event", G_CALLBACK(
_mouse_moved), NULL);
1196 g_signal_connect(G_OBJECT(widget),
"key-press-event", G_CALLBACK(
_key_pressed), NULL);
1197 g_signal_connect(G_OBJECT(widget),
"leave-notify-event", G_CALLBACK(
_center_leave), NULL);
1198 g_signal_connect(G_OBJECT(widget),
"enter-notify-event", G_CALLBACK(
_center_enter), NULL);
1199 g_signal_connect(G_OBJECT(widget),
"button-press-event", G_CALLBACK(
_button_pressed), NULL);
1200 g_signal_connect(G_OBJECT(widget),
"button-release-event", G_CALLBACK(
_button_released), NULL);
1201 g_signal_connect(G_OBJECT(widget),
"scroll-event", G_CALLBACK(
_scrolled), NULL);
1203 g_signal_connect(G_OBJECT(widget),
"realize", G_CALLBACK(_center_realize), NULL);
1204 g_signal_connect(G_OBJECT(widget),
"unrealize", G_CALLBACK(_center_unrealize), NULL);
1205 if(gtk_widget_get_realized(widget))
1206 _center_realize(widget, NULL);
1214 g_signal_connect(G_OBJECT(widget),
"configure-event", G_CALLBACK(
_window_configure), NULL);
1224 GList *input_devices
1225 = gdk_seat_get_slaves(gdk_display_get_default_seat(gdk_display_get_default()), GDK_SEAT_CAPABILITY_ALL);
1226 const int manager_slave_count = 0;
1227 const int manager_floating_count = 0;
1228 GList *stylus_devices
1229 = gdk_seat_get_slaves(gdk_display_get_default_seat(gdk_display_get_default()), GDK_SEAT_CAPABILITY_TABLET_STYLUS);
1231 (
unsigned int)gdk_seat_get_capabilities(gdk_display_get_default_seat(gdk_display_get_default())));
1232 dt_print(
DT_DEBUG_INPUT,
"[input device] stylus-capable devices reported by seat: %d\n", g_list_length(stylus_devices));
1233 dt_print(
DT_DEBUG_INPUT,
"[input device] manager fallback devices: slave=%d floating=%d merged_total=%d\n",
1234 manager_slave_count, manager_floating_count, g_list_length(input_devices));
1235 for(GList *l = stylus_devices; !
IS_NULL_PTR(l); l = g_list_next(l))
1237 GdkDevice *device = (GdkDevice *)l->data;
1240 gdk_device_get_name(device),
_get_source_name(gdk_device_get_source(device)),
1241 (
unsigned int)gdk_device_get_axes(device), gdk_device_get_n_axes(device));
1245 g_list_free(stylus_devices);
1246 stylus_devices = NULL;
1248 for(GList *l = input_devices; !
IS_NULL_PTR(l); l = g_list_next(l))
1250 GdkDevice *device = (GdkDevice *)l->data;
1252 const GdkInputSource source = gdk_device_get_source(device);
1253 const gint n_axes = (source == GDK_SOURCE_KEYBOARD ? 0 : gdk_device_get_n_axes(device));
1257 gdk_device_set_mode(device, GDK_MODE_SCREEN);
1259 dt_print(
DT_DEBUG_INPUT,
"%s (%s), source: %s, mode: %s, %d axes, %d keys\n", gdk_device_get_name(device),
1260 (source != GDK_SOURCE_KEYBOARD) && gdk_device_get_has_cursor(device) ?
"with cursor" :
"no cursor",
1263 source != GDK_SOURCE_KEYBOARD ? gdk_device_get_n_keys(device) : 0);
1265 for(
int i = 0;
i < n_axes;
i++)
1273 g_list_free(input_devices);
1274 input_devices = NULL;
1293 GtkAllocation allocation;
1294 gtk_widget_get_allocation(widget, &allocation);
1308#ifdef MAC_INTEGRATION
1309#ifdef GTK_TYPE_OSX_APPLICATION
1310 gtk_osxapplication_ready(g_object_new(GTK_TYPE_OSX_APPLICATION, NULL));
1312 gtkosx_application_ready(g_object_new(GTKOSX_TYPE_APPLICATION, NULL));
1315#ifdef GDK_WINDOWING_QUARTZ
1334#ifdef GDK_WINDOWING_QUARTZ
1337 res = gtk_widget_get_scale_factor(widget);
1339 if((res < 1.0f) || (res > 4.0f))
1357 if(screen_dpi_overwrite > 0.0)
1359 gui->
dpi = screen_dpi_overwrite;
1360 gdk_screen_set_resolution(gtk_widget_get_screen(widget), screen_dpi_overwrite);
1362 "the configuration file\n",
1363 screen_dpi_overwrite);
1367#ifdef GDK_WINDOWING_QUARTZ
1370 gui->
dpi = gdk_screen_get_resolution(gtk_widget_get_screen(widget));
1374 gdk_screen_set_resolution(gtk_widget_get_screen(widget), 96.0);
1403 if(gtk_box_get_spacing(GTK_BOX(w)) == c->old_s) gtk_box_set_spacing(GTK_BOX(w), c->new_s);
1405 else if(GTK_IS_FLOW_BOX(w))
1407 if((gint)gtk_flow_box_get_row_spacing(GTK_FLOW_BOX(w)) == c->old_s)
1408 gtk_flow_box_set_row_spacing(GTK_FLOW_BOX(w), c->new_s);
1409 if((gint)gtk_flow_box_get_column_spacing(GTK_FLOW_BOX(w)) == c->old_s)
1410 gtk_flow_box_set_column_spacing(GTK_FLOW_BOX(w), c->new_s);
1412 else if(GTK_IS_GRID(w))
1414 if((gint)gtk_grid_get_row_spacing(GTK_GRID(w)) == c->old_s)
1415 gtk_grid_set_row_spacing(GTK_GRID(w), c->new_s);
1416 if((gint)gtk_grid_get_column_spacing(GTK_GRID(w)) == c->old_s)
1417 gtk_grid_set_column_spacing(GTK_GRID(w), c->new_s);
1420 if(GTK_IS_CONTAINER(w))
1433 GList *toplevels = gtk_window_list_toplevels();
1434 for(GList *l = toplevels; l; l = l->next)
1436 g_list_free(toplevels);
1446 GtkStyleContext *ctx = gtk_widget_get_style_context(gui->
ui->
main_window);
1447 PangoFontDescription *desc = NULL;
1448 gtk_style_context_get(ctx, gtk_style_context_get_state(ctx), GTK_STYLE_PROPERTY_FONT, &desc, NULL);
1451 const gint
size = pango_font_description_get_size(desc);
1454 if(pango_font_description_get_size_is_absolute(desc))
1461 pango_font_description_free(desc);
1472 pango_cairo_context_set_resolution(pango_layout_get_context(layout),
darktable.
gui->
dpi);
1484 const cairo_font_options_t *fo = NULL;
1488 PangoContext *pc = gtk_widget_get_pango_context(widget);
1489 if(pc) fo = pango_cairo_context_get_font_options(pc);
1494 if(pc) fo = pango_cairo_context_get_font_options(pc);
1498 GdkScreen *screen = gdk_screen_get_default();
1499 if(screen) fo = gdk_screen_get_font_options(screen);
1503 if(fo) cairo_set_font_options(cr, fo);
1508 gtk_window_set_urgency_hint(GTK_WINDOW(widget),
FALSE);
1514 gtk_widget_hide(GTK_WIDGET(user_data));
1520 gtk_widget_hide(GTK_WIDGET(user_data));
1532 gtk_window_set_role(GTK_WINDOW(gui->
ui->
main_window ),
"main-app");
1533 gtk_window_set_icon_name(GTK_WINDOW(gui->
ui->
main_window ),
"ansel");
1534 gtk_window_set_title(GTK_WINDOW(gui->
ui->
main_window ),
"Ansel");
1546 gboolean restore_window_position =
TRUE;
1547#ifdef GDK_WINDOWING_WAYLAND
1548 GdkDisplay *display = gtk_widget_get_display(gui->
ui->
main_window);
1549 if(GDK_IS_WAYLAND_DISPLAY(display))
1550 restore_window_position =
FALSE;
1553 if(restore_window_position)
1555 GdkDisplay *window_display = gtk_widget_get_display(gui->
ui->
main_window);
1556 GdkMonitor *monitor = NULL;
1563 if(monitor_index >= 0 && monitor_index < gdk_display_get_n_monitors(window_display))
1564 monitor = gdk_display_get_monitor(window_display, monitor_index);
1573 monitor = gdk_display_get_monitor_at_point(window_display,
x, y);
1577 monitor = gdk_display_get_primary_monitor(window_display);
1578 if(
IS_NULL_PTR(monitor) && gdk_display_get_n_monitors(window_display) > 0)
1579 monitor = gdk_display_get_monitor(window_display, 0);
1584 GdkRectangle workarea = { 0 };
1585 gdk_monitor_get_workarea(monitor, &workarea);
1586 gtk_window_move(GTK_WINDOW(gui->
ui->
main_window), workarea.x, workarea.y);
1598 gboolean restore_window_position =
TRUE;
1599#ifdef GDK_WINDOWING_WAYLAND
1600 GdkDisplay *display = gtk_widget_get_display(gui->
ui->
main_window);
1601 if(GDK_IS_WAYLAND_DISPLAY(display))
1602 restore_window_position =
FALSE;
1605 if(restore_window_position
1614 GdkDisplay *window_display = gtk_widget_get_display(gui->
ui->
main_window);
1615 GdkMonitor *monitor = NULL;
1622 if(monitor_index >= 0 && monitor_index < gdk_display_get_n_monitors(window_display))
1623 monitor = gdk_display_get_monitor(window_display, monitor_index);
1627 monitor = gdk_display_get_monitor_at_point(window_display,
x +
width / 2, y +
height / 2);
1629 monitor = gdk_display_get_primary_monitor(window_display);
1630 if(
IS_NULL_PTR(monitor) && gdk_display_get_n_monitors(window_display) > 0)
1631 monitor = gdk_display_get_monitor(window_display, 0);
1636 GdkRectangle workarea = { 0 };
1637 gdk_monitor_get_workarea(monitor, &workarea);
1639 const int max_x = workarea.x +
MAX(0, workarea.width -
width);
1640 const int max_y = workarea.y +
MAX(0, workarea.height -
height);
1641 clamped_x = CLAMP(
x, workarea.x, max_x);
1642 clamped_y = CLAMP(y, workarea.y, max_y);
1645 gtk_window_move(GTK_WINDOW(gui->
ui->
main_window), clamped_x, clamped_y);
1660 gtk_container_add(GTK_CONTAINER(
container), widget);
1661 gtk_widget_show(widget);
1680 gtk_widget_set_valign(eb, GTK_ALIGN_CENTER);
1681 gtk_widget_set_halign(eb, GTK_ALIGN_CENTER);
1686 eb = gtk_event_box_new();
1691 g_signal_connect(G_OBJECT(eb),
"scroll-event", G_CALLBACK(
_scrolled), NULL);
1694 PangoAttrList *attrlist = pango_attr_list_new();
1695 PangoAttribute *attr = pango_attr_font_features_new(
"tnum");
1696 pango_attr_list_insert(attrlist, attr);
1698 pango_attr_list_unref(attrlist);
1702 gtk_widget_set_valign(eb, GTK_ALIGN_START);
1703 gtk_widget_set_halign(eb, GTK_ALIGN_CENTER);
1725 g_return_if_fail(GTK_IS_CONTAINER(ui->
containers[c]));
1727 if(GTK_WIDGET(ui->
containers[c]) != gtk_widget_get_parent(w))
return;
1729 gtk_container_set_focus_child(GTK_CONTAINER(ui->
containers[c]), w);
1735 g_return_if_fail(GTK_IS_CONTAINER(ui->
containers[c]));
1736 gtk_container_foreach(GTK_CONTAINER(ui->
containers[c]), callback, (gpointer)ui->
containers[c]);
1749#ifdef MAC_INTEGRATION
1750#ifdef GTK_TYPE_OSX_APPLICATION
1751 gtk_osxapplication_attention_request(g_object_new(GTK_TYPE_OSX_APPLICATION, NULL), INFO_REQUEST);
1753 gtkosx_application_attention_request(g_object_new(GTKOSX_TYPE_APPLICATION, NULL), INFO_REQUEST);
1762 gtk_widget_queue_draw(widget);
1769 if(!GTK_IS_LABEL(widget))
1778 gtk_widget_show(widget);
1782 gtk_widget_hide(widget);
1791 if(!GTK_IS_LABEL(widget))
1800 if(!gtk_widget_get_visible(widget))
1803 gtk_widget_set_margin_bottom(gtk_widget_get_parent(widget), 0.15 * h -
DT_PIXEL_APPLY_DPI(10));
1804 gtk_widget_show(widget);
1809 if(gtk_widget_get_visible(widget)) gtk_widget_hide(widget);
1816 GList *renderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(cbox));
1817 for(
const GList *it = renderers; it; it = g_list_next(it))
1819 GtkCellRendererText *tr = GTK_CELL_RENDERER_TEXT(it->data);
1820 g_object_set(G_OBJECT(tr),
"ellipsize", PANGO_ELLIPSIZE_MIDDLE, (gchar *)0);
1822 g_list_free(renderers);
1837 if(gtk_main_level() > 0) gtk_main_quit();
1844 if((
void *)button == (
void *)result->
button_yes)
1845 result->
result = RESULT_YES;
1846 else if((
void *)button == (
void *)result->
button_no)
1847 result->
result = RESULT_NO;
1850 result->
entry_text = g_strdup(gtk_entry_get_text(GTK_ENTRY(result->
entry)));
1851 gtk_widget_destroy(result->
window);
1856 const char *yes_text)
1858 GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1859#ifdef GDK_WINDOWING_QUARTZ
1866 gtk_window_set_icon_name(GTK_WINDOW(window),
"ansel");
1867 gtk_window_set_title(GTK_WINDOW(window), title);
1870 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
1876 if(GTK_IS_WINDOW(main_window))
1878 GtkWindow *win = GTK_WINDOW(main_window);
1879 gtk_window_set_transient_for(GTK_WINDOW(window), win);
1880 gtk_window_set_modal(GTK_WINDOW(window),
TRUE);
1881 if(gtk_widget_get_visible(GTK_WIDGET(win)))
1883 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ON_PARENT);
1889 gtk_container_add(GTK_CONTAINER(window), vbox);
1892 gtk_box_pack_start(GTK_BOX(vbox), mhbox,
TRUE,
TRUE, padding);
1896 gtk_box_pack_start(GTK_BOX(mhbox),
1901 gtk_label_set_markup(GTK_LABEL(label), markup);
1902 gtk_box_pack_start(GTK_BOX(mhbox), label,
TRUE,
TRUE, padding);
1906 gtk_box_pack_start(GTK_BOX(mhbox),
1911 gtk_box_pack_start(GTK_BOX(vbox), hbox,
TRUE,
TRUE, 0);
1919 button = gtk_button_new_with_label(no_text);
1922 gtk_box_pack_start(GTK_BOX(hbox), button,
TRUE,
TRUE, 0);
1927 button = gtk_button_new_with_label(yes_text);
1930 gtk_box_pack_start(GTK_BOX(hbox), button,
TRUE,
TRUE, 0);
1933 gtk_widget_show_all(window);
1936 return result.
result == RESULT_YES;
1940 const char *no_text,
const char *yes_text)
1942 GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1943#ifdef GDK_WINDOWING_QUARTZ
1947 gtk_window_set_icon_name(GTK_WINDOW(window),
"ansel");
1948 gtk_window_set_title(GTK_WINDOW(window), title);
1951 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_MOUSE);
1957 if(GTK_IS_WINDOW(main_window))
1959 GtkWindow *win = GTK_WINDOW(main_window);
1960 gtk_window_set_transient_for(GTK_WINDOW(window), win);
1961 if(gtk_widget_get_visible(GTK_WIDGET(win)))
1963 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ON_PARENT);
1969 gtk_widget_set_margin_start(vbox, 10);
1970 gtk_widget_set_margin_end(vbox, 10);
1971 gtk_widget_set_margin_top(vbox, 7);
1972 gtk_widget_set_margin_bottom(vbox, 5);
1973 gtk_container_add(GTK_CONTAINER(window), vbox);
1976 gtk_label_set_markup(GTK_LABEL(label), markup);
1977 gtk_box_pack_start(GTK_BOX(vbox), label,
TRUE,
TRUE, 0);
1982 g_object_ref(entry);
1984 gtk_entry_set_placeholder_text(GTK_ENTRY(entry), placeholder);
1985 gtk_box_pack_start(GTK_BOX(vbox), entry,
TRUE,
TRUE, 0);
1988 gtk_widget_set_margin_top(hbox, 10);
1989 gtk_box_pack_start(GTK_BOX(vbox), hbox,
TRUE,
TRUE, 0);
1997 button = gtk_button_new_with_label(no_text);
2000 gtk_box_pack_start(GTK_BOX(hbox), button,
TRUE,
TRUE, 0);
2005 button = gtk_button_new_with_label(yes_text);
2008 gtk_box_pack_start(GTK_BOX(hbox), button,
TRUE,
TRUE, 0);
2011 gtk_widget_show_all(window);
2014 if(result.
result == RESULT_YES)
2024 g_object_set_data_full(G_OBJECT(widget),
"dt-help-url", link, g_free);
2025 gtk_widget_add_events(widget, GDK_BUTTON_PRESS_MASK);
2032 g_snprintf(theme_css,
sizeof(theme_css),
"%s.css", theme);
2039 gtk_settings_reset_property(gtk_settings_get_default(),
"gtk-font-name");
2046 gchar *font_name = g_strdup_printf(_(
"Sans %s"), font_size_updated);
2047 g_object_set(gtk_settings_get_default(),
"gtk-font-name", font_name, NULL);
2053 gchar *path, *usercsspath;
2059 path = g_build_filename(configdir,
"themes", theme_css, NULL);
2060 if(!g_file_test(path, G_FILE_TEST_EXISTS))
2064 path = g_build_filename(datadir,
"themes", theme_css, NULL);
2065 if(!g_file_test(path, G_FILE_TEST_EXISTS))
2069 path = g_build_filename(datadir,
"themes",
"ansel.css", NULL);
2078 GError *
error = NULL;
2080 GtkStyleProvider *themes_style_provider = GTK_STYLE_PROVIDER(gtk_css_provider_new());
2081 gtk_style_context_add_provider_for_screen
2082 (gdk_screen_get_default(), themes_style_provider, GTK_STYLE_PROVIDER_PRIORITY_USER + 1);
2084 usercsspath = g_build_filename(configdir,
"user.css", NULL);
2086 gchar *path_uri = g_filename_to_uri(path, NULL, &
error);
2088 fprintf(stderr,
"%s: could not convert path %s to URI. Error: %s\n", G_STRFUNC, path,
error->message);
2090 gchar *usercsspath_uri = g_filename_to_uri(usercsspath, NULL, &
error);
2092 fprintf(stderr,
"%s: could not convert path %s to URI. Error: %s\n", G_STRFUNC, usercsspath,
error->message);
2094 gchar *themecss = NULL;
2095 if(
dt_conf_get_bool(
"themes/usercss") && g_file_test(usercsspath, G_FILE_TEST_EXISTS))
2097 themecss = g_strjoin(NULL,
"@import url('", path_uri,
2098 "'); @import url('", usercsspath_uri,
"');", NULL);
2102 themecss = g_strjoin(NULL,
"@import url('", path_uri,
"');", NULL);
2112 gchar *newcss = g_strjoin(NULL, themecss,
" tooltip {opacity: 0; background: transparent;}", NULL);
2117 if(!gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(themes_style_provider), themecss, -1, &
error))
2119 fprintf(stderr,
"%s: error parsing combined CSS %s: %s\n", G_STRFUNC, themecss,
error->message);
2120 g_clear_error(&
error);
2125 g_object_unref(themes_style_provider);
2131 GtkStyleContext *ctx = gtk_widget_get_style_context(main_window);
2138 GdkRGBA default_col;
2175 if(!gtk_style_context_lookup_color(ctx,
init[
i].
name, &c[
i]))
2177 c[
i] =
init[
i].default_col;
2190 gdk_device_get_state(gdk_seat_get_pointer(gdk_display_get_default_seat(gdk_window_get_display(window))), window, NULL, &
state);
2201 const int n = gtk_notebook_get_n_pages(notebook);
2202 g_return_if_fail(
n > 0);
2204 GtkRequestedSize *sizes = g_malloc_n(
n,
sizeof(GtkRequestedSize));
2206 for(
int i = 0;
i <
n;
i++)
2208 sizes[
i].data = gtk_notebook_get_tab_label(notebook, gtk_notebook_get_nth_page(notebook,
i));
2209 sizes[
i].minimum_size = 0;
2210 GtkRequisition natural_size;
2211 gtk_widget_get_preferred_size(sizes[
i].data, NULL, &natural_size);
2212 sizes[
i].natural_size = natural_size.width;
2215 GtkAllocation first, last;
2216 gtk_widget_get_allocation(sizes[0].data, &first);
2217 gtk_widget_get_allocation(sizes[
n - 1].data, &last);
2219 const gint total_space = last.x + last.width - first.x;
2223 gtk_distribute_natural_allocation(total_space,
n, sizes);
2225 for(
int i = 0;
i <
n;
i++)
2226 gtk_widget_set_size_request(sizes[
i].data, sizes[
i].minimum_size, -1);
2228 gtk_widget_size_allocate(GTK_WIDGET(notebook), allocation);
2230 for(
int i = 0;
i <
n;
i++)
2231 gtk_widget_set_size_request(sizes[
i].data, -1, -1);
2241 GtkAllocation notebook_alloc, label_alloc;
2242 gtk_widget_get_allocation(widget, ¬ebook_alloc);
2244 GtkNotebook *notebook = GTK_NOTEBOOK(widget);
2245 const int n = gtk_notebook_get_n_pages(notebook);
2246 for(
int i = 0;
i <
n;
i++)
2248 gtk_widget_get_allocation(gtk_notebook_get_tab_label(notebook, gtk_notebook_get_nth_page(notebook,
i)), &label_alloc);
2256 return GTK_NOTEBOOK(gtk_notebook_new());
2261 gchar *text_cpy = g_strdup(_(text));
2263 GtkWidget *label = gtk_label_new(text_cpy);
2266 if(strlen(text) > 2)
2267 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
2269 gtk_widget_set_has_tooltip(GTK_WIDGET(notebook),
FALSE);
2271 gint page_num = gtk_notebook_append_page(notebook, page, label);
2272 gtk_container_child_set(GTK_CONTAINER(notebook), page,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
2287 if(GTK_IS_TREE_VIEW(w))
2289 gint row_height = 0;
2291 const gint num_columns = gtk_tree_view_get_n_columns(GTK_TREE_VIEW(w));
2292 for(
int c = 0; c < num_columns; c++)
2294 gint cell_height = 0;
2295 gtk_tree_view_column_cell_get_size(gtk_tree_view_get_column(GTK_TREE_VIEW(w), c),
2296 NULL, NULL, NULL, NULL, &cell_height);
2297 if(cell_height > row_height) row_height = cell_height;
2299 GValue separation = { G_TYPE_INT };
2300 gtk_widget_style_get_property(w,
"vertical-separator", &separation);
2302 if(row_height > 0)
height = row_height + g_value_get_int(&separation);
2304 else if(GTK_IS_TEXT_VIEW(w))
2306 PangoLayout *layout = gtk_widget_create_pango_layout(w,
"X");
2307 pango_layout_get_pixel_size(layout, NULL, &
height);
2308 g_object_unref(layout);
2315 height = gtk_widget_get_allocated_height(child);
2327 if(!GTK_IS_WIDGET(w))
return NULL;
2332 if(GTK_IS_SCROLLED_WINDOW(parent))
break;
2333 parent = gtk_widget_get_parent(parent);
2336 return GTK_IS_SCROLLED_WINDOW(parent) ? parent : NULL;
2342 if(!GTK_IS_TREE_MODEL(
model))
return 0;
2345 gboolean valid = parent ? gtk_tree_model_iter_children(
model, &iter, parent)
2346 : gtk_tree_model_get_iter_first(
model, &iter);
2354 if(gtk_tree_model_iter_has_child(
model, &iter))
2356 GtkTreePath *path = gtk_tree_model_get_path(
model, &iter);
2359 if(gtk_tree_view_row_expanded(treeview, path))
2363 gtk_tree_path_free(path);
2367 valid = gtk_tree_model_iter_next(
model, &iter);
2375 if(!GTK_IS_TEXT_VIEW(textview))
return 0;
2377 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
2378 if(!GTK_IS_TEXT_BUFFER(buffer))
return 0;
2381 return MAX(0, gtk_text_buffer_get_line_count(buffer));
2391 if(
state->model_row_inserted) g_signal_handler_disconnect(
model,
state->model_row_inserted);
2392 if(
state->model_row_deleted) g_signal_handler_disconnect(
model,
state->model_row_deleted);
2393 if(
state->model_row_changed) g_signal_handler_disconnect(
model,
state->model_row_changed);
2394 if(
state->model_rows_reordered) g_signal_handler_disconnect(
model,
state->model_rows_reordered);
2395 g_object_remove_weak_pointer(G_OBJECT(
model), (gpointer *)&
state->model);
2398 if(GTK_IS_TREE_VIEW(treeview))
2400 if(
state->model_row_expanded) g_signal_handler_disconnect(treeview,
state->model_row_expanded);
2401 if(
state->model_row_collapsed) g_signal_handler_disconnect(treeview,
state->model_row_collapsed);
2404 state->model = NULL;
2405 state->model_row_inserted = 0;
2406 state->model_row_deleted = 0;
2407 state->model_row_changed = 0;
2408 state->model_rows_reordered = 0;
2409 state->model_row_expanded = 0;
2410 state->model_row_collapsed = 0;
2417 GtkTextBuffer *buffer =
state->buffer;
2420 if(
state->buffer_changed) g_signal_handler_disconnect(buffer,
state->buffer_changed);
2421 g_object_remove_weak_pointer(G_OBJECT(buffer), (gpointer *)&
state->buffer);
2424 state->buffer = NULL;
2425 state->buffer_changed = 0;
2456 if(!GTK_IS_SCROLLED_WINDOW(sw))
return;
2459 const gint min_size =
MAX(1,
state->min_size);
2474 const gboolean row_based = GTK_IS_TREE_VIEW(w) || GTK_IS_TEXT_VIEW(w);
2478 if(GTK_IS_TREE_VIEW(w))
2481 content =
MAX(1, rows) * increment;
2483 else if(GTK_IS_TEXT_VIEW(w))
2486 content =
MAX(1, rows) * increment;
2490 gtk_widget_get_preferred_height(w, NULL, &content);
2493 const gint cap = has_conf ? CLAMP(
dt_conf_get_int(
state->config_str), min_size, max_height) : max_height;
2494 height = CLAMP(
MIN(content, cap), min_size, max_height);
2506 gtk_style_context_get_padding(gtk_widget_get_style_context(sw),
2507 gtk_widget_get_state_flags(sw), &padding);
2509 gint old_height = 0;
2510 gtk_widget_get_size_request(sw, NULL, &old_height);
2511 const gint new_height =
height + padding.top + padding.bottom + (GTK_IS_TEXT_VIEW(w) ? 2 : 0);
2512 if(new_height != old_height)
2513 gtk_widget_set_size_request(sw, -1, new_height);
2549 return state->last_height;
2578 gint *new_order, gpointer user_data)
2591 (
void)expanded_iter;
2600 (
void)collapsed_iter;
2615 if(!GTK_IS_TREE_VIEW(treeview))
return;
2620 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
2624 if(!GTK_IS_TREE_MODEL(
model))
return;
2627 g_object_add_weak_pointer(G_OBJECT(
model), (gpointer *)&
state->model);
2628 state->model_row_inserted = g_signal_connect(
model,
"row-inserted",
2630 state->model_row_deleted = g_signal_connect(
model,
"row-deleted",
2632 state->model_row_changed = g_signal_connect(
model,
"row-changed",
2634 state->model_rows_reordered = g_signal_connect(
model,
"rows-reordered",
2636 state->model_row_expanded = g_signal_connect(treeview,
"row-expanded",
2638 state->model_row_collapsed = g_signal_connect(treeview,
"row-collapsed",
2644 if(!GTK_IS_TEXT_VIEW(textview))
return;
2649 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
2650 if(buffer ==
state->buffer)
return;
2653 if(!GTK_IS_TEXT_BUFFER(buffer))
return;
2655 state->buffer = buffer;
2656 g_object_add_weak_pointer(G_OBJECT(buffer), (gpointer *)&
state->buffer);
2657 state->buffer_changed = g_signal_connect(buffer,
"changed",
2683 g_free(
state->config_str);
2689 if(!GTK_IS_TEXT_VIEW(textview))
return;
2715 GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL);
2716 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
2718 gtk_container_add(GTK_CONTAINER(sw), w);
2722 state->config_str = g_strdup(config_str);
2733 if(GTK_IS_TREE_VIEW(w))
2738 else if(GTK_IS_TEXT_VIEW(w))
2760 _(
"Drag to resize"),
2765 gtk_container_add(GTK_CONTAINER(over), sw);
2766 gtk_overlay_add_overlay(GTK_OVERLAY(over), handle);
2777 if(!GTK_IS_CONTAINER(wrapper))
return NULL;
2778 GList *children = gtk_container_get_children(GTK_CONTAINER(wrapper));
2780 for(GList *l = children; l; l = g_list_next(l))
2782 if(GTK_IS_SCROLLED_WINDOW(l->data))
2784 sw = GTK_WIDGET(l->data);
2788 g_list_free(children);
2811 g_free(
state->config_str);
2817 GtkWidget *area = GTK_WIDGET(user_data);
2820 return gtk_widget_get_allocated_height(area);
2825 GtkWidget *area = GTK_WIDGET(user_data);
2831 gtk_widget_set_size_request(area, -1,
height);
2839 state->config_str = g_strdup(config_str);
2847 gtk_widget_set_size_request(area, -1,
height);
2853 _(
"Drag to resize"),
2857 gtk_container_add(GTK_CONTAINER(over), area);
2858 gtk_overlay_add_overlay(GTK_OVERLAY(over), handle);
2865 GList *children = gtk_container_get_children(
container);
2867 g_list_free(children);
2869 return has_children;
2875 GList *children = gtk_container_get_children(
container);
2876 int num_children = g_list_length(children);
2877 g_list_free(children);
2879 return num_children;
2884 g_return_val_if_fail(GTK_IS_CONTAINER(
container), NULL);
2885 GList *children = gtk_container_get_children(
container);
2887 g_list_free(children);
2894 g_return_val_if_fail(GTK_IS_CONTAINER(
container), NULL);
2895 GList *children = gtk_container_get_children(
container);
2897 g_list_free(children);
2904 gtk_container_remove((GtkContainer*)data, widget);
2909 g_return_if_fail(GTK_IS_CONTAINER(
container));
2916 gtk_widget_destroy(widget);
2921 g_return_if_fail(GTK_IS_CONTAINER(
container));
2932 for(
GtkWidget *parent = gtk_widget_get_parent(widget); parent; parent = gtk_widget_get_parent(parent))
2933 if(GTK_IS_POPOVER(parent)) relative = parent;
2939 rect->
width =
MAX(gtk_widget_get_allocated_width(widget), 1);
2940 rect->height =
MAX(gtk_widget_get_allocated_height(widget), 1);
2942 if(relative != widget
2943 && !gtk_widget_translate_coordinates(widget, relative, 0, 0, &
rect->
x, &
rect->
y))
2955 gtk_widget_show_all(GTK_WIDGET(menu));
2957 GdkEvent *
event = gtk_get_current_event();
2960 GdkRectangle
rect = { 0 };
2963 if(relative && relative != button && gtk_widget_get_window(relative))
2964 gtk_menu_popup_at_rect(menu, gtk_widget_get_window(relative), &
rect, widget_anchor, menu_anchor, event);
2966 gtk_menu_popup_at_widget(menu, button, widget_anchor, menu_anchor, event);
2972 event = gdk_event_new(GDK_BUTTON_PRESS);
2973 event->button.device = gdk_seat_get_pointer(gdk_display_get_default_seat(gdk_display_get_default()));
2975 g_object_ref(event->button.window);
2978 gtk_menu_popup_at_pointer(menu, event);
2980 gdk_event_free(event);
2985 GdkRectangle
rect = { 0 };
2987 gtk_popover_set_relative_to(popover, relative ? relative : button);
2988 gtk_popover_set_pointing_to(popover, &
rect);
2994 const float radius =
height / 5.0f;
2995 const float degrees =
M_PI / 180.0;
2996 cairo_new_sub_path(cr);
2997 cairo_arc(cr,
x +
width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
2998 cairo_arc(cr,
x +
width - radius, y +
height - radius, radius, 0 * degrees, 90 * degrees);
2999 cairo_arc(cr,
x + radius, y +
height - radius, radius, 90 * degrees, 180 * degrees);
3000 cairo_arc(cr,
x + radius, y + radius, radius, 180 * degrees, 270 * degrees);
3001 cairo_close_path(cr);
3007 if(gtk_search_entry_handle_event(entry, (GdkEvent *)event))
3009 gtk_entry_grab_focus_without_selecting(GTK_ENTRY(entry));
3018 gtk_widget_grab_focus(widget);
3020 gtk_entry_set_text(GTK_ENTRY(entry),
"");
3022 if(GTK_IS_TREE_VIEW(widget))
3024 GtkTreePath *path = NULL;
3025 gtk_tree_view_get_cursor(GTK_TREE_VIEW(widget), &path, NULL);
3026 gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)), path);
3027 gtk_tree_path_free(path);
3041 gtk_widget_set_state_flags(GTK_WIDGET(cs->
expander), GTK_STATE_FLAG_NORMAL,
TRUE);
3053 if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cs->
toggle)))
3054 gtk_widget_hide(widget);
3061 const gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cs->
toggle));
3071 if(e->type == GDK_2BUTTON_PRESS || e->type == GDK_3BUTTON_PRESS)
return;
3075 const gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cs->
toggle));
3076 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cs->
toggle), !active);
3082 const gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cs->
toggle));
3088 gtk_widget_show(GTK_WIDGET(cs->
container));
3090 gtk_widget_hide(GTK_WIDGET(cs->
container));
3097 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cs->
toggle),
FALSE);
3098 gtk_widget_hide(GTK_WIDGET(cs->
container));
3103 const char *confname,
const char *label,
3104 GtkBox *parent, GtkPackType pack)
3113 GtkWidget *header_evb = gtk_event_box_new();
3116 gtk_container_add(GTK_CONTAINER(header_evb), cs->
label);
3120 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cs->
toggle), expanded);
3124 gtk_widget_set_name(GTK_WIDGET(cs->
container),
"collapsible");
3125 gtk_box_pack_start(GTK_BOX(destdisp_head), header_evb,
TRUE,
TRUE, 0);
3132 g_signal_connect(G_OBJECT(cs->
container),
"show",
3135 if(pack == GTK_PACK_START)
3140 gtk_widget_set_name(cs->
expander,
"collapse-block");
3142 g_signal_connect(G_OBJECT(cs->
toggle),
"toggled",
3145 g_signal_connect(G_OBJECT(header_evb),
"button-release-event",
3154 const char *underscore =
"_";
3157 if(text[0] == underscore[0])
3158 text[1] = g_unichar_toupper(text[1]);
3160 text[0] = g_unichar_toupper(text[0]);
3168 gtk_box_pack_start(GTK_BOX(box), widget,
FALSE,
FALSE, 0);
3171 GtkWidget *button = gtk_menu_button_new();
3172 GtkWidget *image = gtk_image_new_from_icon_name(icon, GTK_ICON_SIZE_BUTTON);
3173 gtk_button_set_image(GTK_BUTTON(button), image);
3174 gtk_widget_set_hexpand(button,
FALSE);
3175 gtk_widget_set_vexpand(button,
FALSE);
3177 gtk_box_pack_start(GTK_BOX(box), button,
FALSE,
FALSE, 0);
3181 gtk_box_pack_start(GTK_BOX(popover_box), content,
FALSE,
FALSE, 0);
3184 GtkWidget *popover = gtk_popover_new(button);
3185 gtk_container_add(GTK_CONTAINER(popover), popover_box);
3186 gtk_popover_set_modal(GTK_POPOVER(popover),
FALSE);
3188 gtk_menu_button_set_popover(GTK_MENU_BUTTON(button), popover);
3189 gtk_widget_show_all(popover_box);
3191 return GTK_BOX(box);
3197 GtkWidget *popover_label = gtk_label_new(label);
3198 gtk_label_set_line_wrap(GTK_LABEL(popover_label),
TRUE);
3199 gtk_label_set_max_width_chars(GTK_LABEL(popover_label), 60);
3217 if(event->keyval == GDK_KEY_Escape)
3227 gtk_widget_add_events(widget, GDK_FOCUS_CHANGE_MASK);
3245 if(g_strcmp0(current_view,
"lighttable"))
gboolean dt_accels_dispatch(GtkWidget *w, GdkEvent *event, gpointer user_data)
Force our listener for all key strokes to bypass reserved Gtk keys.
dt_accels_t * dt_accels_init(char *config_file, GtkAccelFlags flags)
static void dt_accels_disable(dt_accels_t *accels, gboolean state)
static void error(char *msg)
void init(dt_imageio_module_format_t *self)
uint32_t container(dt_lib_module_t *self)
GtkWidget * dt_bauhaus_resize_handle_new(GtkOrientation orientation, gboolean invert, const char *tooltip, dt_bauhaus_resize_handle_get_size_f get_size, dt_bauhaus_resize_handle_resize_f resize, gpointer user_data)
Create a themed handle widget driving one-dimensional resize gestures.
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
void dt_colorspaces_set_display_profile(const dt_colorspaces_color_profile_type_t profile_type)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_conf_set_bool(const char *name, int val)
int dt_conf_get_bool(const char *name)
int dt_conf_key_exists(const char *key)
float dt_conf_get_float(const char *name)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
void dt_conf_set_string(const char *name, const char *val)
const char * dt_conf_get_string_const(const char *name)
void dt_control_key_pressed(GdkEventKey *event)
void dt_control_button_pressed(double x, double y, double pressure, int which, int type, uint32_t state)
void * dt_control_expose(void *voidptr)
void dt_control_mouse_leave()
gboolean dt_control_configure(GtkWidget *da, GdkEventConfigure *event, gpointer user_data)
void dt_control_button_released(double x, double y, int which, uint32_t state)
void dt_control_set_pointer_input(const dt_control_pointer_input_t *input)
void dt_control_mouse_moved(double x, double y, double pressure, int which)
void dt_control_mouse_enter()
#define dt_control_change_cursor(cursor)
int dt_load_from_string(const gchar *input, gboolean open_image_in_dr, gboolean *single_image)
void dt_concat_path_file(char destination[PATH_MAX], const char path[PATH_MAX], const char *const file)
void dt_print(dt_debug_thread_t thread, const char *msg,...)
static const dt_aligned_pixel_simd_t value
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
void dtgtk_cairo_paint_solid_arrow(cairo_t *cr, gint x, int y, gint w, gint h, gint flags, void *data)
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
void dtgtk_expander_set_expanded(GtkDarktableExpander *expander, gboolean expanded)
GtkWidget * dtgtk_expander_new(GtkWidget *header, GtkWidget *body)
#define DTGTK_EXPANDER(obj)
void dt_loc_get_sharedir(char *sharedir, size_t bufsize)
void dt_loc_get_datadir(char *datadir, size_t bufsize)
void dt_loc_get_user_config_dir(char *configdir, size_t bufsize)
static const char * _get_source_name(int pos)
gboolean dt_gui_get_scroll_deltas(const GdkEventScroll *event, gdouble *delta_x, gdouble *delta_y)
static double _clamp01d(const double value)
static void _widget_auto_model_rows_reordered(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gint *new_order, gpointer user_data)
static gboolean _sample_tablet_state_from_devices(const GdkEvent *event, double *pressure, gboolean *have_pressure, double *tilt_x, double *tilt_y, gboolean *have_tilt, const char **picked_device_name)
static void _ui_widget_redraw_callback(gpointer instance, GtkWidget *widget)
GtkBox * attach_help_popover(GtkWidget *widget, const char *label)
static gboolean _button_released(GtkWidget *w, GdkEventButton *event, gpointer user_data)
void dt_gui_menu_popup(GtkMenu *menu, GtkWidget *button, GdkGravity widget_anchor, GdkGravity menu_anchor)
static dt_control_pointer_input_t _extract_pointer_input(const GdkEvent *event, const double x, const double y, const guint32 time_ms, const gboolean reset_kinematics, const char *tag)
static gboolean _text_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
void dt_gui_cairo_set_font_options(cairo_t *cr, GtkWidget *widget)
void dt_ui_container_foreach(dt_ui_t *ui, const dt_ui_container_t c, GtkCallback callback)
calls a callback on all children widgets from container
gboolean dt_gui_get_scroll_delta(const GdkEventScroll *event, gdouble *delta)
void dt_gui_container_remove_children(GtkContainer *container)
static int _resizable_scroll_handle_resize(int requested_size, gboolean finished, gpointer user_data)
gboolean dt_gui_quit_callback(GtkWidget *widget, GdkEvent *event, gpointer user_data)
gboolean dt_gui_get_scroll_unit_deltas(const GdkEventScroll *event, int *delta_x, int *delta_y)
static void _widget_auto_on_buffer_changed(GObject *textview, GParamSpec *pspec, gpointer user_data)
static int _textview_count_visible_rows(GtkWidget *textview)
static gboolean _center_leave(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
static int _resizable_area_resize(int requested_size, gboolean finished, gpointer user_data)
static const gdouble * _event_axes(const GdkEvent *event)
gboolean dt_gui_get_scroll_unit_delta(const GdkEventScroll *event, int *delta)
static void _collapsible_container_show(GtkWidget *widget, gpointer user_data)
void dt_gui_search_stop(GtkSearchEntry *entry, GtkWidget *widget)
static void _widget_auto_connect_model(GtkWidget *treeview)
void dt_gui_hide_collapsible_section(dt_gui_collapsible_section_t *cs)
static void _widget_auto_model_row_expanded(GtkTreeView *tree_view, GtkTreeIter *expanded_iter, GtkTreePath *path, gpointer user_data)
static void _delete_child(GtkWidget *widget, gpointer data)
static const char * _get_mode_name(int pos)
void dt_gui_remove_class(GtkWidget *widget, const gchar *class_name)
static void _widget_auto_model_row_changed(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
GtkWidget * dt_ui_resizable_drawing_area(GtkWidget *area, char *config_str, int default_height, int min_height)
Make a self-drawing widget (typically a GtkDrawingArea graph or scope) vertically resizable.
static void _remove_child(GtkWidget *widget, gpointer data)
void dt_gui_new_collapsible_section(dt_gui_collapsible_section_t *cs, const char *confname, const char *label, GtkBox *parent, GtkPackType pack)
Create a collapsible section and pack it into the parent box.
static int _resizable_area_get_size(gpointer user_data)
static gboolean _key_pressed(GtkWidget *w, GdkEventKey *event)
static void _gtk_main_quit_safe(GtkWidget *widget, gpointer data)
static gint _get_container_row_heigth(GtkWidget *w)
static gboolean _notebook_motion_notify_callback(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
static void _widget_auto_connect_buffer(GtkWidget *textview)
GtkWidget * dt_ui_notebook_page(GtkNotebook *notebook, const char *text, const char *tooltip)
static gboolean _center_enter(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
GtkNotebook * dt_ui_notebook_new()
static gboolean _ui_toast_button_press_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
static gboolean _button_pressed(GtkWidget *w, GdkEventButton *event, gpointer user_data)
static dt_tablet_motion_state_t _tablet_motion_state
static void _resizable_scroll_realize(GtkWidget *w, gpointer user_data)
static gboolean _draw(GtkWidget *da, cairo_t *cr, gpointer user_data)
static gboolean _ui_log_button_press_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
static void _coeffs_button_changed(GtkDarktableToggleButton *widget, gpointer user_data)
void dt_ui_container_destroy_children(dt_ui_t *ui, const dt_ui_container_t c)
destroy all child widgets from container
char * dt_gui_show_standalone_string_dialog(const char *title, const char *markup, const char *placeholder, const char *no_text, const char *yes_text)
static void _widget_auto_height_free(gpointer data)
static void _widget_auto_model_row_collapsed(GtkTreeView *tree_view, GtkTreeIter *collapsed_iter, GtkTreePath *path, gpointer user_data)
static int _resizable_scroll_handle_get_size(gpointer user_data)
static void _collapsible_set_states(dt_gui_collapsible_section_t *cs, gboolean active)
static void _widget_auto_model_row_deleted(GtkTreeModel *model, GtkTreePath *path, gpointer user_data)
int dt_gui_container_num_children(GtkContainer *container)
static void _widget_auto_disconnect_buffer(dt_gui_widget_auto_height_t *state)
void dt_gui_gtk_set_source_rgb(cairo_t *cr, dt_gui_color_t color)
void dt_gui_draw_rounded_rectangle(cairo_t *cr, float width, float height, float x, float y)
GtkWidget * dt_gui_container_nth_child(GtkContainer *container, int which)
static GtkWidget * _search_parent_scrolled_window(GtkWidget *w)
static void _coeffs_expander_click(GtkWidget *widget, GdkEventButton *e, gpointer user_data)
void dt_gui_update_collapsible_section(dt_gui_collapsible_section_t *cs)
void dt_gui_textview_set_padding(GtkTextView *textview)
Apply the standard recessed-input text padding to a GtkTextView.
void dt_gui_load_theme(const char *theme)
GtkWidget * dt_ui_scroll_wrap_get_scrolled_window(GtkWidget *wrapper)
Return the inner scrolled window of a dt_ui_scroll_wrap() wrapper, or NULL.
static void _widget_auto_text_buffer_changed(GtkTextBuffer *buffer, gpointer user_data)
void dt_capitalize_label(gchar *text)
int dt_gui_gtk_write_config()
static void _yes_no_button_handler(GtkButton *button, gpointer data)
void dt_gui_store_last_preset(const char *name)
void dt_ellipsize_combo(GtkComboBox *cbox)
GdkModifierType dt_key_modifier_state()
void dt_configure_ppd_dpi(dt_gui_gtk_t *gui)
static gint _resizable_scroll_max_height(void)
Window-height ceiling shared by the auto-size rule and the drag handle.
static void _resizable_area_free(gpointer data)
static gboolean _get_axis_value_for_source(const GdkEvent *event, GdkDevice *source_device, const GdkAxisUse axis, double *value, gboolean *from_source_map)
static const char * _get_axis_name(int pos)
static void _init_widgets(dt_gui_gtk_t *gui)
gboolean dt_gui_search_start(GtkWidget *widget, GdkEventKey *event, GtkSearchEntry *entry)
static const char *const DT_GUI_WIDGET_AUTO_HEIGHT_KEY
static void _notebook_size_callback(GtkNotebook *notebook, GdkRectangle *allocation, gpointer *data)
void dt_gui_gtk_set_source_rgba(cairo_t *cr, dt_gui_color_t color, float opacity_coef)
double dt_get_system_gui_ppd(GtkWidget *widget)
static gboolean _mouse_moved(GtkWidget *w, GdkEventMotion *event, gpointer user_data)
void dt_gui_container_destroy_children(GtkContainer *container)
static void _widget_auto_model_row_inserted(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
void dt_gui_add_help_link(GtkWidget *widget, char *link)
void dt_ui_notify_user()
draw user's attention
gboolean dt_gui_show_standalone_yes_no_dialog(const char *title, const char *markup, const char *no_text, const char *yes_text)
static gboolean _focus_in_out_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
static void _ui_log_redraw_callback(gpointer instance, GtkWidget *widget)
GtkWidget * dt_gui_get_popup_relative_widget(GtkWidget *widget, GdkRectangle *rect)
Resolve the widget used as parent for nested popups on Wayland.
static void _widget_auto_on_model_changed(GObject *treeview, GParamSpec *pspec, gpointer user_data)
int dt_gui_gtk_init(dt_gui_gtk_t *gui)
static void _resizable_scroll_apply(GtkWidget *w)
The single sizing rule for every dt_ui_scroll_wrap area.
static void _widget_auto_update(GtkWidget *widget)
gboolean dt_gui_container_has_children(GtkContainer *container)
void dt_gui_refocus_center()
static const char *const DT_UI_RESIZABLE_AREA_KEY
static void _refresh_all_container_spacing(void)
static gint _last_box_spacing
void dt_gui_set_pango_resolution(PangoLayout *layout)
GtkBox * attach_popover(GtkWidget *widget, const char *icon, GtkWidget *content)
static void _popover_set_relative_to_topmost_parent(GtkPopover *popover, GtkWidget *button)
static gboolean _configure(GtkWidget *da, GdkEventConfigure *event, gpointer user_data)
static int _treeview_count_visible_rows(GtkTreeView *treeview, GtkTreeModel *model, GtkTreeIter *parent)
static gboolean _scrolled(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
GtkWidget * dt_ui_scroll_wrap(GtkWidget *w, gint min_size, char *config_str, dt_ui_resize_mode_t mode)
Wrap a scrollable content widget in a recessed, vertically resizable scrolled window.
static void _ui_toast_redraw_callback(gpointer instance, GtkWidget *widget)
void dt_gui_gtk_run(dt_gui_gtk_t *gui)
static gboolean _text_entry_focus_out_event(GtkWidget *self, GdkEventFocus event, gpointer user_data)
GtkWidget * dt_gui_container_first_child(GtkContainer *container)
void dt_accels_disconnect_on_text_input(GtkWidget *widget)
Disconnects accels when a text or search entry gets the focus, and reconnects them when it looses it....
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
static gboolean _text_entry_focus_in_event(GtkWidget *self, GdkEventFocus event, gpointer user_data)
static void _refresh_container_spacing(GtkWidget *w, gpointer user_data)
static gboolean _window_configure(GtkWidget *da, GdkEvent *event, gpointer user_data)
void dt_ui_container_focus_widget(dt_ui_t *ui, const dt_ui_container_t c, GtkWidget *w)
gives a widget focus in the container
static gboolean _sample_axis_from_device_state(GdkWindow *window, GdkDevice *device, const GdkAxisUse axis, double *value)
void dt_gui_update_em(void)
static void _widget_auto_disconnect_model(dt_gui_widget_auto_height_t *state, GtkWidget *treeview)
static gboolean _resizable_scroll_draw(GtkWidget *w, cairo_t *cr, gpointer user_data)
GtkWidget * dt_ui_toast_msg(dt_ui_t *ui)
get the toast message widget
GtkWidget * dt_ui_center(dt_ui_t *ui)
get the center drawable widget
@ DT_GUI_COLOR_DARKROOM_PREVIEW_BG
@ DT_GUI_COLOR_LIGHTTABLE_FONT
@ DT_GUI_COLOR_MAP_LOC_SHAPE_HIGH
@ DT_GUI_COLOR_BRUSH_CURSOR
@ DT_GUI_COLOR_THUMBNAIL_FONT
@ DT_GUI_COLOR_THUMBNAIL_SELECTED_BG
@ DT_GUI_COLOR_MAP_COUNT_BG
@ DT_GUI_COLOR_THUMBNAIL_SELECTED_BORDER
@ DT_GUI_COLOR_THUMBNAIL_OUTLINE
@ DT_GUI_COLOR_MAP_LOC_SHAPE_LOW
@ DT_GUI_COLOR_LIGHTTABLE_BG
@ DT_GUI_COLOR_DARKROOM_BG
@ DT_GUI_COLOR_THUMBNAIL_BORDER
@ DT_GUI_COLOR_LIGHTTABLE_PREVIEW_BG
@ DT_GUI_COLOR_MAP_COUNT_SAME_LOC
@ DT_GUI_COLOR_MAP_COUNT_DIFF_LOC
@ DT_GUI_COLOR_THUMBNAIL_BG
@ DT_GUI_COLOR_PREVIEW_HOVER_BORDER
@ DT_GUI_COLOR_FILMSTRIP_BG
@ DT_GUI_COLOR_BRUSH_TRACE
@ DT_GUI_COLOR_THUMBNAIL_SELECTED_FONT
@ DT_GUI_COLOR_THUMBNAIL_SELECTED_OUTLINE
@ DT_GUI_COLOR_THUMBNAIL_HOVER_BG
@ DT_GUI_COLOR_MAP_LOC_SHAPE_DEF
@ DT_GUI_COLOR_THUMBNAIL_HOVER_FONT
@ DT_GUI_COLOR_THUMBNAIL_HOVER_OUTLINE
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
GtkWidget * dt_ui_log_msg(dt_ui_t *ui)
get the log message widget
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
static GtkWidget * dt_ui_section_label_new(const gchar *str)
#define DT_UI_SCALE_DEVICE(value)
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
GtkWidget * dt_ui_center_base(dt_ui_t *ui)
void dt_gui_presets_init()
void dt_guides_set_overlay_colors()
const char * dt_l10n_get_current_lang(dt_l10n_t *l10n)
dt_mipmap_buffer_dsc_flags flags
void dt_osx_focus_window()
void dt_osx_autoset_dpi(GtkWidget *widget)
void dt_osx_disallow_fullscreen(GtkWidget *widget)
@ DT_SIGNAL_CONTROL_REDRAW_ALL
This signal is raised when dt_control_queue_redraw() is called. no param, no returned value.
@ DT_SIGNAL_CONTROL_TOAST_REDRAW
This signal is raised when dt_control_toast_redraw() is called. no param, no returned value.
@ DT_SIGNAL_CONTROL_LOG_REDRAW
This signal is raised when dt_control_log_redraw() is called. no param, no returned value.
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
void dt_gui_splash_set_transient_for(GtkWidget *parent)
struct _GtkWidget GtkWidget
const float uint32_t state[4]
struct dt_gui_gtk_t * gui
struct dt_control_signal_t * signals
struct dt_view_manager_t * view_manager
struct dt_control_t * control
char toast_message[10][300]
dt_pthread_mutex_t log_mutex
dt_pthread_mutex_t toast_mutex
char log_message[10][1000]
cairo_surface_t * surface
struct dt_gui_gtk_t::@47 mouse
GtkMenu * presets_popup_menu
GtkWidget * has_scroll_focus
struct dt_gui_gtk_t::@48 export_popup
struct dt_gui_gtk_t::@49 styles_popup
gboolean selection_stacked
cairo_filter_t filter_image
GdkRGBA colors[DT_GUI_COLOR_LAST]
dt_thumbtable_t * thumbtable_lighttable
GtkWidget * containers[DT_UI_CONTAINER_SIZE]
enum result_t::@51 result
typedef double((*spd)(unsigned long int wavelength, double TempK))
gchar * dt_util_str_replace(const gchar *string, const gchar *pattern, const gchar *substitute)
const char * dt_view_manager_name(dt_view_manager_t *vm)
void dt_view_manager_configure(dt_view_manager_t *vm, int width, int height)
int dt_view_manager_scrolled(dt_view_manager_t *vm, double x, double y, int up, int state, int delta_y)
void dt_ui_cleanup_titlebar(dt_ui_t *ui)
void dt_ui_init_titlebar(dt_ui_t *ui)
void dt_ui_init_main_table(GtkWidget *parent, dt_ui_t *ui)