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);
159 GtkIconInfo *info = gtk_icon_theme_lookup_icon(gtk_icon_theme_get_default(), icon_name,
MAX(
width,
height),
160 GTK_ICON_LOOKUP_FORCE_SYMBOLIC);
163 gtk_image_set_from_icon_name(GTK_IMAGE(image), icon_name,
size);
168 ? gtk_icon_info_load_symbolic_for_context(info, gtk_widget_get_style_context(image), NULL, NULL)
169 : gtk_icon_info_load_symbolic(info, color, color, color, color, NULL, NULL);
170 g_object_unref(info);
174 if(gdk_pixbuf_get_width(pixbuf) !=
width || gdk_pixbuf_get_height(pixbuf) !=
height)
176 GdkPixbuf *scaled = gdk_pixbuf_scale_simple(pixbuf,
width,
height, GDK_INTERP_BILINEAR);
177 g_object_unref(pixbuf);
180 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
181 g_object_unref(pixbuf);
220 fprintf(stderr,
"[dt_gui_freeze] unbalanced end at %s:%d (depth was %d); "
221 "look for a freeze begin without a matching end.\n",
243 if(gdk_event_get_pointer_emulated((GdkEvent*)event))
return FALSE;
245 gboolean handled =
FALSE;
246 switch(event->direction)
249 case GDK_SCROLL_LEFT:
253 if(delta_y) *delta_y = 0.0;
257 case GDK_SCROLL_RIGHT:
261 if(delta_y) *delta_y = 0.0;
268 if(delta_x) *delta_x = 0.0;
273 case GDK_SCROLL_DOWN:
276 if(delta_x) *delta_x = 0.0;
282 case GDK_SCROLL_SMOOTH:
283 if((delta_x && event->delta_x != 0) || (delta_y && event->delta_y != 0))
285#ifdef GDK_WINDOWING_QUARTZ
286 if(delta_x) *delta_x =
dt_conf_get_bool(
"scroll/reverse_x") ? -
event->delta_x / 50. :
event->delta_x / 50.;
287 if(delta_y) *delta_y =
dt_conf_get_bool(
"scroll/reverse_y") ? -
event->delta_y / 50. :
event->delta_y / 50.;
289 if(delta_x) *delta_x =
dt_conf_get_bool(
"scroll/reverse_x") ? -
event->delta_x :
event->delta_x;
290 if(delta_y) *delta_y =
dt_conf_get_bool(
"scroll/reverse_y") ? -
event->delta_y :
event->delta_y;
303 if(gdk_event_get_pointer_emulated((GdkEvent*)event))
return FALSE;
306 static gdouble acc_x = 0.0, acc_y = 0.0;
308 gboolean handled =
FALSE;
310 switch(event->direction)
313 case GDK_SCROLL_LEFT:
317 if(delta_y) *delta_y = 0;
321 case GDK_SCROLL_RIGHT:
325 if(delta_y) *delta_y = 0;
332 if(delta_x) *delta_x = 0;
337 case GDK_SCROLL_DOWN:
340 if(delta_x) *delta_x = 0;
346 case GDK_SCROLL_SMOOTH:
356#ifdef GDK_WINDOWING_QUARTZ
357 acc_x +=
dt_conf_get_bool(
"scroll/reverse_x") ? -
event->delta_x / 50. :
event->delta_x / 50.;
358 acc_y +=
dt_conf_get_bool(
"scroll/reverse_y") ? -
event->delta_y / 50. :
event->delta_y / 50.;
360 acc_x +=
dt_conf_get_bool(
"scroll/reverse_x") ? -
event->delta_x :
event->delta_x;
361 acc_y +=
dt_conf_get_bool(
"scroll/reverse_y") ? -
event->delta_y :
event->delta_y;
363 const gdouble amt_x = trunc(acc_x);
364 const gdouble amt_y = trunc(acc_y);
365 if(amt_x != 0 || amt_y != 0)
369 if((delta_x && amt_x != 0) || (delta_y && amt_y != 0))
371 if(delta_x) *delta_x = (int)amt_x;
372 if(delta_y) *delta_y = (int)amt_y;
385 gdouble delta_x, delta_y;
388 *
delta = delta_x + delta_y;
396 int delta_x, delta_y;
399 *
delta = delta_x + delta_y;
418void dt_gtk_widget_queue_draw_ext(
GtkWidget *widget,
const char *
name,
const char *file,
const int line)
420 if(!GTK_IS_WIDGET(widget))
422 dt_print(
DT_DEBUG_GTK,
"gtk_widget_queue_draw(%s) called with a non-WIDGET or NULL widget at %s:%d (widget=%p)\n",
423 name, file, line, widget);
428 name, gtk_widget_get_name(widget), file, line);
431 (gtk_widget_queue_draw)(widget);
434void dt_gtk_toggle_button_set_active_ext(GtkToggleButton *toggle_button,
const char *
name,
const gboolean active,
435 const char *file,
const int line)
437 if(!GTK_IS_TOGGLE_BUTTON(toggle_button))
439 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",
440 name, file, line, toggle_button);
444 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)),
445 active ?
"active" :
"inactive", file, line);
447 (gtk_toggle_button_set_active)(toggle_button, active);
460 event->state, delta_y);
471 const GdkWindowState window_state = gdk_window_get_state(gtk_widget_get_window(widget));
472 dt_conf_set_bool(
"ui_last/maximized", (window_state & GDK_WINDOW_STATE_MAXIMIZED));
474 gtk_window_get_size(GTK_WINDOW(widget), &
width, &
height);
478 gboolean save_window_position =
TRUE;
479#ifdef GDK_WINDOWING_WAYLAND
480 GdkDisplay *display = gtk_widget_get_display(widget);
481 if(GDK_IS_WAYLAND_DISPLAY(display))
482 save_window_position =
FALSE;
485 if(save_window_position)
487 GdkWindow *gdk_window = gtk_widget_get_window(widget);
488 GdkDisplay *window_display = gtk_widget_get_display(widget);
491 GdkMonitor *monitor = gdk_display_get_monitor_at_window(window_display, gdk_window);
494 const int n_monitors = gdk_display_get_n_monitors(window_display);
495 int monitor_index = -1;
496 for(
int i = 0;
i < n_monitors;
i++)
498 if(gdk_display_get_monitor(window_display,
i) == monitor)
504 if(monitor_index >= 0)
509 if(!(window_state & GDK_WINDOW_STATE_MAXIMIZED))
512 gtk_window_get_position(GTK_WINDOW(widget), &
x, &y);
526 cairo_set_source_rgb(cr, bc.red, bc.green, bc.blue);
532 cairo_set_source_rgba(cr, bc.red, bc.green, bc.blue, bc.alpha * opacity_coef);
539 gtk_window_set_title(GTK_WINDOW(win), _(
"closing Ansel..."));
562#ifdef MAC_INTEGRATION
563#ifdef GTK_TYPE_OSX_APPLICATION
564static gboolean _osx_quit_callback(GtkOSXApplication *OSXapp, gpointer user_data)
566static gboolean _osx_quit_callback(GtkosxApplication *OSXapp, gpointer user_data)
570 windows = gtk_window_list_toplevels();
572 if(gtk_window_get_modal(GTK_WINDOW(
window->data)) && gtk_widget_get_visible(GTK_WIDGET(
window->data)))
575 g_list_free(windows);
580#ifdef GTK_TYPE_OSX_APPLICATION
581static gboolean _osx_openfile_callback(GtkOSXApplication *OSXapp, gchar *path, gpointer user_data)
583static gboolean _osx_openfile_callback(GtkosxApplication *OSXapp, gchar *path, gpointer user_data)
595 if(oldw != event->width || oldh != event->height)
598 cairo_surface_t *tmpsurface
606 cairo_t *cr = cairo_create(tmpsurface);
618 oldh =
event->height;
620#ifndef GDK_WINDOWING_QUARTZ
631 if(oldx != event->configure.x || oldy != event->configure.y)
635 oldx =
event->configure.x;
636 oldy =
event->configure.y;
667 case GDK_MOTION_NOTIFY:
668 return ((
const GdkEventMotion *)event)->axes;
669 case GDK_BUTTON_PRESS:
670 case GDK_2BUTTON_PRESS:
671 case GDK_3BUTTON_PRESS:
672 case GDK_BUTTON_RELEASE:
673 return ((
const GdkEventButton *)event)->axes;
680 const GdkAxisUse axis,
double *
value, gboolean *from_source_map)
682 if(from_source_map) *from_source_map =
FALSE;
686 if(source_device && axes)
688 double source_value = 0.0;
689 if(gdk_device_get_axis(source_device, (gdouble *)axes, axis, &source_value))
691 *
value = source_value;
692 if(from_source_map) *from_source_map =
TRUE;
697 return gdk_event_get_axis((GdkEvent *)event, axis,
value);
701 const GdkAxisUse axis,
double *
value)
704 if(gdk_device_get_source(device) == GDK_SOURCE_KEYBOARD)
return FALSE;
705 if(gdk_device_get_device_type(device) == GDK_DEVICE_TYPE_SLAVE)
707 GdkDisplay *display = gdk_device_get_display(device);
708 if(!display || !gdk_display_device_is_grabbed(display, device))
return FALSE;
711 const int n_axes = gdk_device_get_n_axes(device);
712 if(n_axes <= 0)
return FALSE;
714 double *axes = g_newa(
double, n_axes);
715 memset(axes, 0,
sizeof(
double) * n_axes);
716 GdkModifierType modifiers = 0;
717 gdk_device_get_state(device,
window, axes, &modifiers);
718 return gdk_device_get_axis(device, axes, axis,
value);
722 double *pressure, gboolean *have_pressure,
723 double *tilt_x,
double *tilt_y, gboolean *have_tilt,
724 const char **picked_device_name)
726 if(pressure) *pressure = 0.0;
727 if(have_pressure) *have_pressure =
FALSE;
728 if(tilt_x) *tilt_x = 0.0;
729 if(tilt_y) *tilt_y = 0.0;
730 if(have_tilt) *have_tilt =
FALSE;
731 if(picked_device_name) *picked_device_name = NULL;
734 GdkWindow *
window = gdk_event_get_window((GdkEvent *)event);
740 gboolean best_have_p =
FALSE;
741 double best_tx = 0.0;
742 double best_ty = 0.0;
743 gboolean best_have_t =
FALSE;
744 const char *best_name = NULL;
746 GdkSeat *seat = gdk_display_get_default() ? gdk_display_get_default_seat(gdk_display_get_default()) : NULL;
747 GList *runtime_devices = seat ? gdk_seat_get_slaves(seat, GDK_SEAT_CAPABILITY_ALL_POINTING) : NULL;
749 for(GList *l = runtime_devices; l; l = g_list_next(l))
751 GdkDevice *device = (GdkDevice *)l->data;
753 const GdkInputSource source = gdk_device_get_source(device);
754 if(source == GDK_SOURCE_KEYBOARD)
continue;
755 if(gdk_device_get_device_type(device) == GDK_DEVICE_TYPE_SLAVE)
757 GdkDisplay *display = gdk_device_get_display(device);
760 if(!display || !gdk_display_device_is_grabbed(display, device))
continue;
763 const GdkAxisFlags axis_flags = gdk_device_get_axes(device);
764 const gboolean supports_pressure = (axis_flags & GDK_AXIS_FLAG_PRESSURE) != 0;
765 const gboolean supports_x_tilt = (axis_flags & GDK_AXIS_FLAG_XTILT) != 0;
766 const gboolean supports_y_tilt = (axis_flags & GDK_AXIS_FLAG_YTILT) != 0;
767 const gboolean pen_like = (source == GDK_SOURCE_PEN || source == GDK_SOURCE_ERASER || source == GDK_SOURCE_CURSOR);
768 if(!supports_pressure && !supports_x_tilt && !supports_y_tilt && !pen_like)
continue;
770 const int n_axes = gdk_device_get_n_axes(device);
771 if(n_axes <= 0)
continue;
772 double *axes = g_newa(
double, n_axes);
773 memset(axes, 0,
sizeof(
double) * n_axes);
774 GdkModifierType modifiers = 0;
775 gdk_device_get_state(device,
window, axes, &modifiers);
778 gboolean have_p =
FALSE;
781 gboolean have_tx =
FALSE;
782 gboolean have_ty =
FALSE;
784 for(
int i = 0;
i < n_axes;
i++)
786 const GdkAxisUse use = gdk_device_get_axis_use(device,
i);
787 if(use == GDK_AXIS_PRESSURE)
792 else if(use == GDK_AXIS_XTILT)
797 else if(use == GDK_AXIS_YTILT)
804 const gboolean have_t = have_tx || have_ty;
805 const int score = (have_p ? 2 : 0) + (have_t ? 2 : 0) + (
p > 1e-4 ? 4 : 0)
806 + ((hypot(tx, ty) > 1e-4) ? 3 : 0) + (pen_like ? 1 : 0);
807 if(score <= best_score)
continue;
811 best_have_p = have_p;
814 best_have_t = have_t;
815 best_name = gdk_device_get_name(device);
819 g_list_free(runtime_devices);
820 runtime_devices = NULL;
823 if(best_score < 0)
return FALSE;
824 if(pressure) *pressure = best_p;
825 if(have_pressure) *have_pressure = best_have_p;
826 if(tilt_x) *tilt_x = best_tx;
827 if(tilt_y) *tilt_y = best_ty;
828 if(have_tilt) *have_tilt = best_have_t;
829 if(picked_device_name) *picked_device_name = best_name;
834 const guint32 time_ms,
const gboolean reset_kinematics,
841 GdkDevice *source_device = gdk_event_get_source_device((GdkEvent *)event);
842 GdkDevice *event_device = gdk_event_get_device((GdkEvent *)event);
843 GdkDevice *device = source_device ? source_device : event_device;
844 const GdkInputSource source = device ? gdk_device_get_source(device) : GDK_SOURCE_MOUSE;
845 const GdkAxisFlags axis_flags = device ? gdk_device_get_axes(device) : 0;
846 const gboolean supports_pressure = (axis_flags & GDK_AXIS_FLAG_PRESSURE) != 0;
847 const gboolean supports_x_tilt = (axis_flags & GDK_AXIS_FLAG_XTILT) != 0;
848 const gboolean supports_y_tilt = (axis_flags & GDK_AXIS_FLAG_YTILT) != 0;
849 gboolean read_pressure =
FALSE;
850 gboolean read_x_tilt =
FALSE;
851 gboolean read_y_tilt =
FALSE;
852 gboolean map_pressure_source =
FALSE;
853 gboolean map_xtilt_source =
FALSE;
854 gboolean map_ytilt_source =
FALSE;
855 gboolean state_pressure_source =
FALSE;
856 gboolean state_pressure_event =
FALSE;
857 gboolean state_xtilt_source =
FALSE;
858 gboolean state_ytilt_source =
FALSE;
859 gboolean fallback_pressure =
FALSE;
860 gboolean fallback_tilt =
FALSE;
861 const char *fallback_device_name = NULL;
862 GdkDeviceTool *tool = gdk_event_get_device_tool((GdkEvent *)event);
863 const int tool_type = tool ? (int)gdk_device_tool_get_tool_type(tool) : -1;
864 const gboolean tool_is_stylus
865 = tool && (tool_type == GDK_DEVICE_TOOL_TYPE_PEN || tool_type == GDK_DEVICE_TOOL_TYPE_ERASER
866 || tool_type == GDK_DEVICE_TOOL_TYPE_BRUSH || tool_type == GDK_DEVICE_TOOL_TYPE_PENCIL
867 || tool_type == GDK_DEVICE_TOOL_TYPE_AIRBRUSH);
868 gboolean is_tablet_like = supports_pressure || supports_x_tilt || supports_y_tilt || tool_is_stylus;
869 GdkWindow *
window = gdk_event_get_window((GdkEvent *)event);
873 double pressure = 0.0;
876 read_pressure =
TRUE;
887 else if(!is_tablet_like)
895 double p_state = 0.0;
899 state_pressure_source =
TRUE;
905 state_pressure_event =
TRUE;
912 const gboolean has_x_tilt
914 const gboolean has_y_tilt
916 read_x_tilt = has_x_tilt;
917 read_y_tilt = has_y_tilt;
918 if(has_x_tilt || has_y_tilt)
920 input.
tilt_x = CLAMP(x_tilt, -1.0, 1.0);
921 input.
tilt_y = CLAMP(y_tilt, -1.0, 1.0);
933 else if(!is_tablet_like)
941 double tx_state = 0.0, ty_state = 0.0;
946 input.
tilt_x = CLAMP(tx_state, -1.0, 1.0);
947 input.
tilt_y = CLAMP(ty_state, -1.0, 1.0);
952 state_xtilt_source = has_tx;
953 state_ytilt_source = has_ty;
964 double fb_pressure = 0.0;
965 gboolean fb_have_pressure =
FALSE;
966 double fb_tilt_x = 0.0;
967 double fb_tilt_y = 0.0;
968 gboolean fb_have_tilt =
FALSE;
970 &fb_tilt_x, &fb_tilt_y, &fb_have_tilt,
971 &fallback_device_name))
977 fallback_pressure =
TRUE;
981 input.
tilt_x = CLAMP(fb_tilt_x, -1.0, 1.0);
982 input.
tilt_y = CLAMP(fb_tilt_y, -1.0, 1.0);
985 fallback_tilt =
TRUE;
1008 const double speed_px_s = hypot(dx, dy) / dt_s;
1027 "[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",
1028 tag ? tag :
"event",
1029 device ? gdk_device_get_name(device) :
"<none>",
1030 source_device ? gdk_device_get_name(source_device) :
"<none>",
1031 event_device ? gdk_device_get_name(event_device) :
"<none>",
1033 is_tablet_like ? 1 : 0,
1035 supports_pressure ? 1 : 0,
1036 supports_x_tilt ? 1 : 0,
1037 supports_y_tilt ? 1 : 0,
1038 read_pressure ? 1 : 0,
1039 read_x_tilt ? 1 : 0,
1040 read_y_tilt ? 1 : 0,
1041 map_pressure_source ? 1 : 0,
1042 map_xtilt_source ? 1 : 0,
1043 map_ytilt_source ? 1 : 0,
1044 state_pressure_source ? 1 : 0,
1045 state_pressure_event ? 1 : 0,
1046 state_xtilt_source ? 1 : 0,
1047 state_ytilt_source ? 1 : 0,
1048 fallback_pressure ? 1 : 0,
1049 fallback_tilt ? 1 : 0,
1050 fallback_device_name ? fallback_device_name :
"<none>",
1058 reset_kinematics ? 1 : 0);
1069 gtk_widget_grab_focus(w);
1072 event->time,
TRUE,
"button-press");
1083 event->time,
FALSE,
"button-release");
1095 event->time,
FALSE,
"motion");
1104#define DT_WIN32_CURSOR_SUBCLASS_CENTER ((UINT_PTR)0x41534e4e)
1106static LRESULT CALLBACK _center_win32_cursor_proc(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param,
1107 UINT_PTR subclass_id, DWORD_PTR ref_data)
1114 if(subclass_id == DT_WIN32_CURSOR_SUBCLASS_CENTER && message == WM_SETCURSOR && LOWORD(l_param) == HTCLIENT)
1117 return DefSubclassProc(hwnd, message, w_param, l_param);
1120static void _center_realize(
GtkWidget *widget, gpointer user_data)
1122 GdkWindow *center_window = gtk_widget_get_window(widget);
1123 HWND center_hwnd = center_window ? (HWND)gdk_win32_window_get_handle(center_window) : NULL;
1125 SetWindowSubclass(center_hwnd, _center_win32_cursor_proc, DT_WIN32_CURSOR_SUBCLASS_CENTER, (DWORD_PTR)widget);
1128static void _center_unrealize(
GtkWidget *widget, gpointer user_data)
1130 GdkWindow *center_window = gtk_widget_get_window(widget);
1131 HWND center_hwnd = center_window ? (HWND)gdk_win32_window_get_handle(center_window) : NULL;
1133 RemoveWindowSubclass(center_hwnd, _center_win32_cursor_proc, DT_WIN32_CURSOR_SUBCLASS_CENTER);
1158 static const gchar *SOURCE_NAMES[]
1159 = {
"GDK_SOURCE_MOUSE",
"GDK_SOURCE_PEN",
"GDK_SOURCE_ERASER",
"GDK_SOURCE_CURSOR",
1160 "GDK_SOURCE_KEYBOARD",
"GDK_SOURCE_TOUCHSCREEN",
"GDK_SOURCE_TOUCHPAD",
"GDK_SOURCE_TRACKPOINT",
1161 "GDK_SOURCE_TABLET_PAD" };
1162 if(pos >= G_N_ELEMENTS(SOURCE_NAMES))
return "<UNKNOWN>";
1163 return SOURCE_NAMES[pos];
1168 static const gchar *MODE_NAMES[] = {
"GDK_MODE_DISABLED",
"GDK_MODE_SCREEN",
"GDK_MODE_WINDOW" };
1169 if(pos >= G_N_ELEMENTS(MODE_NAMES))
return "<UNKNOWN>";
1170 return MODE_NAMES[pos];
1175 static const gchar *AXIS_NAMES[]
1176 = {
"GDK_AXIS_IGNORE",
"GDK_AXIS_X",
"GDK_AXIS_Y",
"GDK_AXIS_PRESSURE",
1177 "GDK_AXIS_XTILT",
"GDK_AXIS_YTILT",
"GDK_AXIS_WHEEL",
"GDK_AXIS_DISTANCE",
1178 "GDK_AXIS_ROTATION",
"GDK_AXIS_SLIDER",
"GDK_AXIS_LAST" };
1179 if(pos >= G_N_ELEMENTS(AXIS_NAMES))
return "<UNKNOWN>";
1180 return AXIS_NAMES[pos];
1193 g_setenv(
"GTK_OVERLAY_SCROLLING",
"0", 0);
1196 g_setenv(
"LIBOVERLAY_SCROLLBAR",
"0", 0);
1206 g_strlcpy(gui->
gtkrc, css_theme,
sizeof(gui->
gtkrc));
1208 g_snprintf(gui->
gtkrc,
sizeof(gui->
gtkrc),
"ansel");
1210#ifdef MAC_INTEGRATION
1211#ifdef GTK_TYPE_OSX_APPLICATION
1212 GtkOSXApplication *OSXApp = g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1213 gtk_osxapplication_set_menu_bar(
1214 OSXApp, GTK_MENU_SHELL(gtk_menu_bar_new()));
1216 GtkosxApplication *OSXApp = g_object_new(GTKOSX_TYPE_APPLICATION, NULL);
1217 gtkosx_application_set_menu_bar(
1218 OSXApp, GTK_MENU_SHELL(gtk_menu_bar_new()));
1220 g_signal_connect(G_OBJECT(OSXApp),
"NSApplicationBlockTermination", G_CALLBACK(_osx_quit_callback), NULL);
1221 g_signal_connect(G_OBJECT(OSXApp),
"NSApplicationOpenFile", G_CALLBACK(_osx_openfile_callback), NULL);
1238 gui->
scroll_mask = GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK;
1248 gchar *keyboardrc_path = g_build_filename(configdir, keyboardrc, NULL);
1250 GtkAccelFlags
flags = 0;
1263 gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), path);
1265 gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), path);
1270 gtk_widget_set_can_focus(widget,
TRUE);
1271 gtk_widget_set_visible(widget,
TRUE);
1272 gtk_widget_grab_focus(widget);
1273 gtk_widget_add_events(widget, GDK_PROXIMITY_IN_MASK | GDK_PROXIMITY_OUT_MASK | GDK_TABLET_PAD_MASK);
1274 g_signal_connect(G_OBJECT(widget),
"configure-event", G_CALLBACK(
_configure), gui);
1275 g_signal_connect(G_OBJECT(widget),
"draw", G_CALLBACK(
_draw), NULL);
1276 g_signal_connect(G_OBJECT(widget),
"motion-notify-event", G_CALLBACK(
_mouse_moved), NULL);
1277 g_signal_connect(G_OBJECT(widget),
"key-press-event", G_CALLBACK(
_key_pressed), NULL);
1278 g_signal_connect(G_OBJECT(widget),
"leave-notify-event", G_CALLBACK(
_center_leave), NULL);
1279 g_signal_connect(G_OBJECT(widget),
"enter-notify-event", G_CALLBACK(
_center_enter), NULL);
1280 g_signal_connect(G_OBJECT(widget),
"button-press-event", G_CALLBACK(
_button_pressed), NULL);
1281 g_signal_connect(G_OBJECT(widget),
"button-release-event", G_CALLBACK(
_button_released), NULL);
1282 g_signal_connect(G_OBJECT(widget),
"scroll-event", G_CALLBACK(
_scrolled), NULL);
1284 g_signal_connect(G_OBJECT(widget),
"realize", G_CALLBACK(_center_realize), NULL);
1285 g_signal_connect(G_OBJECT(widget),
"unrealize", G_CALLBACK(_center_unrealize), NULL);
1286 if(gtk_widget_get_realized(widget))
1287 _center_realize(widget, NULL);
1295 g_signal_connect(G_OBJECT(widget),
"configure-event", G_CALLBACK(
_window_configure), NULL);
1305 GList *input_devices
1306 = gdk_seat_get_slaves(gdk_display_get_default_seat(gdk_display_get_default()), GDK_SEAT_CAPABILITY_ALL);
1307 const int manager_slave_count = 0;
1308 const int manager_floating_count = 0;
1309 GList *stylus_devices
1310 = gdk_seat_get_slaves(gdk_display_get_default_seat(gdk_display_get_default()), GDK_SEAT_CAPABILITY_TABLET_STYLUS);
1312 (
unsigned int)gdk_seat_get_capabilities(gdk_display_get_default_seat(gdk_display_get_default())));
1313 dt_print(
DT_DEBUG_INPUT,
"[input device] stylus-capable devices reported by seat: %d\n", g_list_length(stylus_devices));
1314 dt_print(
DT_DEBUG_INPUT,
"[input device] manager fallback devices: slave=%d floating=%d merged_total=%d\n",
1315 manager_slave_count, manager_floating_count, g_list_length(input_devices));
1316 for(GList *l = stylus_devices; !
IS_NULL_PTR(l); l = g_list_next(l))
1318 GdkDevice *device = (GdkDevice *)l->data;
1321 gdk_device_get_name(device),
_get_source_name(gdk_device_get_source(device)),
1322 (
unsigned int)gdk_device_get_axes(device), gdk_device_get_n_axes(device));
1326 g_list_free(stylus_devices);
1327 stylus_devices = NULL;
1329 for(GList *l = input_devices; !
IS_NULL_PTR(l); l = g_list_next(l))
1331 GdkDevice *device = (GdkDevice *)l->data;
1333 const GdkInputSource source = gdk_device_get_source(device);
1334 const gint n_axes = (source == GDK_SOURCE_KEYBOARD ? 0 : gdk_device_get_n_axes(device));
1338 gdk_device_set_mode(device, GDK_MODE_SCREEN);
1340 dt_print(
DT_DEBUG_INPUT,
"%s (%s), source: %s, mode: %s, %d axes, %d keys\n", gdk_device_get_name(device),
1341 (source != GDK_SOURCE_KEYBOARD) && gdk_device_get_has_cursor(device) ?
"with cursor" :
"no cursor",
1344 source != GDK_SOURCE_KEYBOARD ? gdk_device_get_n_keys(device) : 0);
1346 for(
int i = 0;
i < n_axes;
i++)
1354 g_list_free(input_devices);
1355 input_devices = NULL;
1374 GtkAllocation allocation;
1375 gtk_widget_get_allocation(widget, &allocation);
1389#ifdef MAC_INTEGRATION
1390#ifdef GTK_TYPE_OSX_APPLICATION
1391 gtk_osxapplication_ready(g_object_new(GTK_TYPE_OSX_APPLICATION, NULL));
1393 gtkosx_application_ready(g_object_new(GTKOSX_TYPE_APPLICATION, NULL));
1396#ifdef GDK_WINDOWING_QUARTZ
1415#ifdef GDK_WINDOWING_QUARTZ
1418 res = gtk_widget_get_scale_factor(widget);
1420 if((res < 1.0f) || (res > 4.0f))
1438 if(screen_dpi_overwrite > 0.0)
1440 gui->
dpi = screen_dpi_overwrite;
1441 gdk_screen_set_resolution(gtk_widget_get_screen(widget), screen_dpi_overwrite);
1443 "the configuration file\n",
1444 screen_dpi_overwrite);
1448#ifdef GDK_WINDOWING_QUARTZ
1451 gui->
dpi = gdk_screen_get_resolution(gtk_widget_get_screen(widget));
1455 gdk_screen_set_resolution(gtk_widget_get_screen(widget), 96.0);
1484 if(gtk_box_get_spacing(GTK_BOX(w)) == c->old_s) gtk_box_set_spacing(GTK_BOX(w), c->new_s);
1486 else if(GTK_IS_FLOW_BOX(w))
1488 if((gint)gtk_flow_box_get_row_spacing(GTK_FLOW_BOX(w)) == c->old_s)
1489 gtk_flow_box_set_row_spacing(GTK_FLOW_BOX(w), c->new_s);
1490 if((gint)gtk_flow_box_get_column_spacing(GTK_FLOW_BOX(w)) == c->old_s)
1491 gtk_flow_box_set_column_spacing(GTK_FLOW_BOX(w), c->new_s);
1493 else if(GTK_IS_GRID(w))
1495 if((gint)gtk_grid_get_row_spacing(GTK_GRID(w)) == c->old_s)
1496 gtk_grid_set_row_spacing(GTK_GRID(w), c->new_s);
1497 if((gint)gtk_grid_get_column_spacing(GTK_GRID(w)) == c->old_s)
1498 gtk_grid_set_column_spacing(GTK_GRID(w), c->new_s);
1501 if(GTK_IS_CONTAINER(w))
1514 GList *toplevels = gtk_window_list_toplevels();
1515 for(GList *l = toplevels; l; l = l->next)
1517 g_list_free(toplevels);
1527 GtkStyleContext *ctx = gtk_widget_get_style_context(gui->
ui->
main_window);
1528 PangoFontDescription *desc = NULL;
1529 gtk_style_context_get(ctx, gtk_style_context_get_state(ctx), GTK_STYLE_PROPERTY_FONT, &desc, NULL);
1532 const gint
size = pango_font_description_get_size(desc);
1535 if(pango_font_description_get_size_is_absolute(desc))
1542 pango_font_description_free(desc);
1553 pango_cairo_context_set_resolution(pango_layout_get_context(layout),
darktable.
gui->
dpi);
1565 const cairo_font_options_t *fo = NULL;
1569 PangoContext *pc = gtk_widget_get_pango_context(widget);
1570 if(pc) fo = pango_cairo_context_get_font_options(pc);
1575 if(pc) fo = pango_cairo_context_get_font_options(pc);
1579 GdkScreen *screen = gdk_screen_get_default();
1580 if(screen) fo = gdk_screen_get_font_options(screen);
1584 if(fo) cairo_set_font_options(cr, fo);
1589 gtk_window_set_urgency_hint(GTK_WINDOW(widget),
FALSE);
1595 gtk_widget_hide(GTK_WIDGET(user_data));
1601 gtk_widget_hide(GTK_WIDGET(user_data));
1613 gtk_window_set_role(GTK_WINDOW(gui->
ui->
main_window ),
"main-app");
1614 gtk_window_set_icon_name(GTK_WINDOW(gui->
ui->
main_window ),
"ansel");
1615 gtk_window_set_title(GTK_WINDOW(gui->
ui->
main_window ),
"Ansel");
1627 gboolean restore_window_position =
TRUE;
1628#ifdef GDK_WINDOWING_WAYLAND
1629 GdkDisplay *display = gtk_widget_get_display(gui->
ui->
main_window);
1630 if(GDK_IS_WAYLAND_DISPLAY(display))
1631 restore_window_position =
FALSE;
1634 if(restore_window_position)
1636 GdkDisplay *window_display = gtk_widget_get_display(gui->
ui->
main_window);
1637 GdkMonitor *monitor = NULL;
1644 if(monitor_index >= 0 && monitor_index < gdk_display_get_n_monitors(window_display))
1645 monitor = gdk_display_get_monitor(window_display, monitor_index);
1654 monitor = gdk_display_get_monitor_at_point(window_display,
x, y);
1658 monitor = gdk_display_get_primary_monitor(window_display);
1659 if(
IS_NULL_PTR(monitor) && gdk_display_get_n_monitors(window_display) > 0)
1660 monitor = gdk_display_get_monitor(window_display, 0);
1665 GdkRectangle workarea = { 0 };
1666 gdk_monitor_get_workarea(monitor, &workarea);
1667 gtk_window_move(GTK_WINDOW(gui->
ui->
main_window), workarea.x, workarea.y);
1679 gboolean restore_window_position =
TRUE;
1680#ifdef GDK_WINDOWING_WAYLAND
1681 GdkDisplay *display = gtk_widget_get_display(gui->
ui->
main_window);
1682 if(GDK_IS_WAYLAND_DISPLAY(display))
1683 restore_window_position =
FALSE;
1686 if(restore_window_position
1695 GdkDisplay *window_display = gtk_widget_get_display(gui->
ui->
main_window);
1696 GdkMonitor *monitor = NULL;
1703 if(monitor_index >= 0 && monitor_index < gdk_display_get_n_monitors(window_display))
1704 monitor = gdk_display_get_monitor(window_display, monitor_index);
1708 monitor = gdk_display_get_monitor_at_point(window_display,
x +
width / 2, y +
height / 2);
1710 monitor = gdk_display_get_primary_monitor(window_display);
1711 if(
IS_NULL_PTR(monitor) && gdk_display_get_n_monitors(window_display) > 0)
1712 monitor = gdk_display_get_monitor(window_display, 0);
1717 GdkRectangle workarea = { 0 };
1718 gdk_monitor_get_workarea(monitor, &workarea);
1720 const int max_x = workarea.x +
MAX(0, workarea.width -
width);
1721 const int max_y = workarea.y +
MAX(0, workarea.height -
height);
1722 clamped_x = CLAMP(
x, workarea.x, max_x);
1723 clamped_y = CLAMP(y, workarea.y, max_y);
1726 gtk_window_move(GTK_WINDOW(gui->
ui->
main_window), clamped_x, clamped_y);
1741 gtk_container_add(GTK_CONTAINER(
container), widget);
1742 gtk_widget_show(widget);
1761 gtk_widget_set_valign(eb, GTK_ALIGN_CENTER);
1762 gtk_widget_set_halign(eb, GTK_ALIGN_CENTER);
1767 eb = gtk_event_box_new();
1772 g_signal_connect(G_OBJECT(eb),
"scroll-event", G_CALLBACK(
_scrolled), NULL);
1775 PangoAttrList *attrlist = pango_attr_list_new();
1776 PangoAttribute *attr = pango_attr_font_features_new(
"tnum");
1777 pango_attr_list_insert(attrlist, attr);
1779 pango_attr_list_unref(attrlist);
1783 gtk_widget_set_valign(eb, GTK_ALIGN_START);
1784 gtk_widget_set_halign(eb, GTK_ALIGN_CENTER);
1806 g_return_if_fail(GTK_IS_CONTAINER(ui->
containers[c]));
1808 if(GTK_WIDGET(ui->
containers[c]) != gtk_widget_get_parent(w))
return;
1810 gtk_container_set_focus_child(GTK_CONTAINER(ui->
containers[c]), w);
1816 g_return_if_fail(GTK_IS_CONTAINER(ui->
containers[c]));
1817 gtk_container_foreach(GTK_CONTAINER(ui->
containers[c]), callback, (gpointer)ui->
containers[c]);
1830#ifdef MAC_INTEGRATION
1831#ifdef GTK_TYPE_OSX_APPLICATION
1832 gtk_osxapplication_attention_request(g_object_new(GTK_TYPE_OSX_APPLICATION, NULL), INFO_REQUEST);
1834 gtkosx_application_attention_request(g_object_new(GTKOSX_TYPE_APPLICATION, NULL), INFO_REQUEST);
1843 gtk_widget_queue_draw(widget);
1850 if(!GTK_IS_LABEL(widget))
1859 gtk_widget_show(widget);
1863 gtk_widget_hide(widget);
1872 if(!GTK_IS_LABEL(widget))
1881 if(!gtk_widget_get_visible(widget))
1884 gtk_widget_set_margin_bottom(gtk_widget_get_parent(widget), 0.15 * h -
DT_PIXEL_APPLY_DPI(10));
1885 gtk_widget_show(widget);
1890 if(gtk_widget_get_visible(widget)) gtk_widget_hide(widget);
1897 GList *renderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(cbox));
1898 for(
const GList *it = renderers; it; it = g_list_next(it))
1900 GtkCellRendererText *tr = GTK_CELL_RENDERER_TEXT(it->data);
1901 g_object_set(G_OBJECT(tr),
"ellipsize", PANGO_ELLIPSIZE_MIDDLE, (gchar *)0);
1903 g_list_free(renderers);
1918 if(gtk_main_level() > 0) gtk_main_quit();
1925 if((
void *)button == (
void *)result->
button_yes)
1926 result->
result = RESULT_YES;
1927 else if((
void *)button == (
void *)result->
button_no)
1928 result->
result = RESULT_NO;
1931 result->
entry_text = g_strdup(gtk_entry_get_text(GTK_ENTRY(result->
entry)));
1932 gtk_widget_destroy(result->
window);
1942 if(GTK_IS_WINDOW(main_window)) parent = GTK_WINDOW(main_window);
1945 if(GTK_IS_WINDOW(parent)) gtk_window_present(parent);
1947#ifdef GDK_WINDOWING_QUARTZ
1953 const char *yes_text)
1956#ifdef GDK_WINDOWING_QUARTZ
1963 gtk_window_set_icon_name(GTK_WINDOW(
window),
"ansel");
1964 gtk_window_set_title(GTK_WINDOW(
window), title);
1967 gtk_window_set_position(GTK_WINDOW(
window), GTK_WIN_POS_CENTER);
1973 if(GTK_IS_WINDOW(main_window))
1975 GtkWindow *win = GTK_WINDOW(main_window);
1976 gtk_window_set_transient_for(GTK_WINDOW(
window), win);
1977 gtk_window_set_modal(GTK_WINDOW(
window),
TRUE);
1978 if(gtk_widget_get_visible(GTK_WIDGET(win)))
1980 gtk_window_set_position(GTK_WINDOW(
window), GTK_WIN_POS_CENTER_ON_PARENT);
1986 gtk_container_add(GTK_CONTAINER(
window), vbox);
1989 gtk_box_pack_start(GTK_BOX(vbox), mhbox,
TRUE,
TRUE, padding);
1993 gtk_box_pack_start(GTK_BOX(mhbox),
1998 gtk_label_set_markup(GTK_LABEL(label), markup);
1999 gtk_box_pack_start(GTK_BOX(mhbox), label,
TRUE,
TRUE, padding);
2003 gtk_box_pack_start(GTK_BOX(mhbox),
2008 gtk_box_pack_start(GTK_BOX(vbox), hbox,
TRUE,
TRUE, 0);
2016 button = gtk_button_new_with_label(no_text);
2019 gtk_box_pack_start(GTK_BOX(hbox), button,
TRUE,
TRUE, 0);
2024 button = gtk_button_new_with_label(yes_text);
2027 gtk_box_pack_start(GTK_BOX(hbox), button,
TRUE,
TRUE, 0);
2030 gtk_widget_show_all(
window);
2033 return result.
result == RESULT_YES;
2050 else if((
void *)button == (
void *)result->
button_third)
2053 gtk_widget_destroy(result->
window);
2058 const char *second_text,
const char *third_text)
2061#ifdef GDK_WINDOWING_QUARTZ
2068 gtk_window_set_icon_name(GTK_WINDOW(
window),
"ansel");
2069 gtk_window_set_title(GTK_WINDOW(
window), title);
2072 gtk_window_set_position(GTK_WINDOW(
window), GTK_WIN_POS_CENTER);
2078 if(GTK_IS_WINDOW(main_window))
2080 GtkWindow *win = GTK_WINDOW(main_window);
2081 gtk_window_set_transient_for(GTK_WINDOW(
window), win);
2082 gtk_window_set_modal(GTK_WINDOW(
window),
TRUE);
2083 if(gtk_widget_get_visible(GTK_WIDGET(win)))
2085 gtk_window_set_position(GTK_WINDOW(
window), GTK_WIN_POS_CENTER_ON_PARENT);
2091 gtk_container_add(GTK_CONTAINER(
window), vbox);
2094 gtk_box_pack_start(GTK_BOX(vbox), mhbox,
TRUE,
TRUE, padding);
2098 gtk_box_pack_start(GTK_BOX(mhbox),
2103 gtk_label_set_markup(GTK_LABEL(label), markup);
2104 gtk_box_pack_start(GTK_BOX(mhbox), label,
TRUE,
TRUE, padding);
2108 gtk_box_pack_start(GTK_BOX(mhbox),
2113 gtk_box_pack_start(GTK_BOX(vbox), hbox,
TRUE,
TRUE, 0);
2121 button = gtk_button_new_with_label(first_text);
2124 gtk_box_pack_start(GTK_BOX(hbox), button,
TRUE,
TRUE, 0);
2129 button = gtk_button_new_with_label(second_text);
2132 gtk_box_pack_start(GTK_BOX(hbox), button,
TRUE,
TRUE, 0);
2137 button = gtk_button_new_with_label(third_text);
2140 gtk_box_pack_start(GTK_BOX(hbox), button,
TRUE,
TRUE, 0);
2143 gtk_widget_show_all(
window);
2150 const char *no_text,
const char *yes_text)
2153#ifdef GDK_WINDOWING_QUARTZ
2157 gtk_window_set_icon_name(GTK_WINDOW(
window),
"ansel");
2158 gtk_window_set_title(GTK_WINDOW(
window), title);
2161 gtk_window_set_position(GTK_WINDOW(
window), GTK_WIN_POS_MOUSE);
2167 if(GTK_IS_WINDOW(main_window))
2169 GtkWindow *win = GTK_WINDOW(main_window);
2170 gtk_window_set_transient_for(GTK_WINDOW(
window), win);
2171 if(gtk_widget_get_visible(GTK_WIDGET(win)))
2173 gtk_window_set_position(GTK_WINDOW(
window), GTK_WIN_POS_CENTER_ON_PARENT);
2179 gtk_widget_set_margin_start(vbox, 10);
2180 gtk_widget_set_margin_end(vbox, 10);
2181 gtk_widget_set_margin_top(vbox, 7);
2182 gtk_widget_set_margin_bottom(vbox, 5);
2183 gtk_container_add(GTK_CONTAINER(
window), vbox);
2186 gtk_label_set_markup(GTK_LABEL(label), markup);
2187 gtk_box_pack_start(GTK_BOX(vbox), label,
TRUE,
TRUE, 0);
2192 g_object_ref(entry);
2194 gtk_entry_set_placeholder_text(GTK_ENTRY(entry), placeholder);
2195 gtk_box_pack_start(GTK_BOX(vbox), entry,
TRUE,
TRUE, 0);
2198 gtk_widget_set_margin_top(hbox, 10);
2199 gtk_box_pack_start(GTK_BOX(vbox), hbox,
TRUE,
TRUE, 0);
2207 button = gtk_button_new_with_label(no_text);
2210 gtk_box_pack_start(GTK_BOX(hbox), button,
TRUE,
TRUE, 0);
2215 button = gtk_button_new_with_label(yes_text);
2218 gtk_box_pack_start(GTK_BOX(hbox), button,
TRUE,
TRUE, 0);
2221 gtk_widget_show_all(
window);
2224 if(result.
result == RESULT_YES)
2234 g_object_set_data_full(G_OBJECT(widget),
"dt-help-url", link, g_free);
2235 gtk_widget_add_events(widget, GDK_BUTTON_PRESS_MASK);
2242 g_snprintf(theme_css,
sizeof(theme_css),
"%s.css", theme);
2249 gtk_settings_reset_property(gtk_settings_get_default(),
"gtk-font-name");
2256 gchar *font_name = g_strdup_printf(_(
"Sans %s"), font_size_updated);
2257 g_object_set(gtk_settings_get_default(),
"gtk-font-name", font_name, NULL);
2263 gchar *path, *usercsspath;
2269 path = g_build_filename(configdir,
"themes", theme_css, NULL);
2270 if(!g_file_test(path, G_FILE_TEST_EXISTS))
2274 path = g_build_filename(datadir,
"themes", theme_css, NULL);
2275 if(!g_file_test(path, G_FILE_TEST_EXISTS))
2279 path = g_build_filename(datadir,
"themes",
"ansel.css", NULL);
2288 GError *
error = NULL;
2290 GtkStyleProvider *themes_style_provider = GTK_STYLE_PROVIDER(gtk_css_provider_new());
2291 gtk_style_context_add_provider_for_screen
2292 (gdk_screen_get_default(), themes_style_provider, GTK_STYLE_PROVIDER_PRIORITY_USER + 1);
2294 usercsspath = g_build_filename(configdir,
"user.css", NULL);
2296 gchar *path_uri = g_filename_to_uri(path, NULL, &
error);
2298 fprintf(stderr,
"%s: could not convert path %s to URI. Error: %s\n", G_STRFUNC, path,
error->message);
2300 gchar *usercsspath_uri = g_filename_to_uri(usercsspath, NULL, &
error);
2302 fprintf(stderr,
"%s: could not convert path %s to URI. Error: %s\n", G_STRFUNC, usercsspath,
error->message);
2304 gchar *themecss = NULL;
2305 if(
dt_conf_get_bool(
"themes/usercss") && g_file_test(usercsspath, G_FILE_TEST_EXISTS))
2307 themecss = g_strjoin(NULL,
"@import url('", path_uri,
2308 "'); @import url('", usercsspath_uri,
"');", NULL);
2312 themecss = g_strjoin(NULL,
"@import url('", path_uri,
"');", NULL);
2322 gchar *newcss = g_strjoin(NULL, themecss,
" tooltip {opacity: 0; background: transparent;}", NULL);
2327 if(!gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(themes_style_provider), themecss, -1, &
error))
2329 fprintf(stderr,
"%s: error parsing combined CSS %s: %s\n", G_STRFUNC, themecss,
error->message);
2330 g_clear_error(&
error);
2335 g_object_unref(themes_style_provider);
2341 GtkStyleContext *ctx = gtk_widget_get_style_context(main_window);
2348 GdkRGBA default_col;
2386 if(!gtk_style_context_lookup_color(ctx,
init[
i].
name, &c[
i]))
2388 c[
i] =
init[
i].default_col;
2401 gdk_device_get_state(gdk_seat_get_pointer(gdk_display_get_default_seat(gdk_window_get_display(
window))),
window, NULL, &
state);
2412 const int n = gtk_notebook_get_n_pages(
notebook);
2413 g_return_if_fail(
n > 0);
2415 GtkRequestedSize *sizes = g_malloc_n(
n,
sizeof(GtkRequestedSize));
2417 for(
int i = 0;
i <
n;
i++)
2419 sizes[
i].data = gtk_notebook_get_tab_label(
notebook, gtk_notebook_get_nth_page(
notebook,
i));
2420 sizes[
i].minimum_size = 0;
2421 GtkRequisition natural_size;
2422 gtk_widget_get_preferred_size(sizes[
i].data, NULL, &natural_size);
2423 sizes[
i].natural_size = natural_size.width;
2426 GtkAllocation first, last;
2427 gtk_widget_get_allocation(sizes[0].data, &first);
2428 gtk_widget_get_allocation(sizes[
n - 1].data, &last);
2430 const gint total_space = last.x + last.width - first.x;
2434 gtk_distribute_natural_allocation(total_space,
n, sizes);
2436 for(
int i = 0;
i <
n;
i++)
2437 gtk_widget_set_size_request(sizes[
i].data, sizes[
i].minimum_size, -1);
2439 gtk_widget_size_allocate(GTK_WIDGET(
notebook), allocation);
2441 for(
int i = 0;
i <
n;
i++)
2442 gtk_widget_set_size_request(sizes[
i].data, -1, -1);
2452 GtkAllocation notebook_alloc, label_alloc;
2453 gtk_widget_get_allocation(widget, ¬ebook_alloc);
2455 GtkNotebook *
notebook = GTK_NOTEBOOK(widget);
2456 const int n = gtk_notebook_get_n_pages(
notebook);
2457 for(
int i = 0;
i <
n;
i++)
2459 gtk_widget_get_allocation(gtk_notebook_get_tab_label(
notebook, gtk_notebook_get_nth_page(
notebook,
i)), &label_alloc);
2467 return GTK_NOTEBOOK(gtk_notebook_new());
2472 gchar *text_cpy = g_strdup(_(text));
2474 GtkWidget *label = gtk_label_new(text_cpy);
2477 if(strlen(text) > 2)
2478 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
2482 gint page_num = gtk_notebook_append_page(
notebook, page, label);
2483 gtk_container_child_set(GTK_CONTAINER(
notebook), page,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
2508 const gulong existing = g_signal_handler_find(G_OBJECT(
notebook), G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
2510 if(existing) g_signal_handler_disconnect(G_OBJECT(
notebook), existing);
2519 if(GTK_IS_TREE_VIEW(w))
2521 gint row_height = 0;
2523 const gint num_columns = gtk_tree_view_get_n_columns(GTK_TREE_VIEW(w));
2524 for(
int c = 0; c < num_columns; c++)
2526 gint cell_height = 0;
2527 gtk_tree_view_column_cell_get_size(gtk_tree_view_get_column(GTK_TREE_VIEW(w), c),
2528 NULL, NULL, NULL, NULL, &cell_height);
2529 if(cell_height > row_height) row_height = cell_height;
2531 GValue separation = { G_TYPE_INT };
2532 gtk_widget_style_get_property(w,
"vertical-separator", &separation);
2534 if(row_height > 0)
height = row_height + g_value_get_int(&separation);
2536 else if(GTK_IS_TEXT_VIEW(w))
2538 PangoLayout *layout = gtk_widget_create_pango_layout(w,
"X");
2539 pango_layout_get_pixel_size(layout, NULL, &
height);
2540 g_object_unref(layout);
2547 height = gtk_widget_get_allocated_height(child);
2559 if(!GTK_IS_WIDGET(w))
return NULL;
2564 if(GTK_IS_SCROLLED_WINDOW(parent))
break;
2565 parent = gtk_widget_get_parent(parent);
2568 return GTK_IS_SCROLLED_WINDOW(parent) ? parent : NULL;
2574 if(!GTK_IS_TREE_MODEL(
model))
return 0;
2577 gboolean valid = parent ? gtk_tree_model_iter_children(
model, &iter, parent)
2578 : gtk_tree_model_get_iter_first(
model, &iter);
2586 if(gtk_tree_model_iter_has_child(
model, &iter))
2588 GtkTreePath *path = gtk_tree_model_get_path(
model, &iter);
2591 if(gtk_tree_view_row_expanded(treeview, path))
2595 gtk_tree_path_free(path);
2599 valid = gtk_tree_model_iter_next(
model, &iter);
2607 if(!GTK_IS_TEXT_VIEW(textview))
return 0;
2609 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
2610 if(!GTK_IS_TEXT_BUFFER(buffer))
return 0;
2613 return MAX(0, gtk_text_buffer_get_line_count(buffer));
2623 if(
state->model_row_inserted) g_signal_handler_disconnect(
model,
state->model_row_inserted);
2624 if(
state->model_row_deleted) g_signal_handler_disconnect(
model,
state->model_row_deleted);
2625 if(
state->model_row_changed) g_signal_handler_disconnect(
model,
state->model_row_changed);
2626 if(
state->model_rows_reordered) g_signal_handler_disconnect(
model,
state->model_rows_reordered);
2627 g_object_remove_weak_pointer(G_OBJECT(
model), (gpointer *)&
state->model);
2630 if(GTK_IS_TREE_VIEW(treeview))
2632 if(
state->model_row_expanded) g_signal_handler_disconnect(treeview,
state->model_row_expanded);
2633 if(
state->model_row_collapsed) g_signal_handler_disconnect(treeview,
state->model_row_collapsed);
2636 state->model = NULL;
2637 state->model_row_inserted = 0;
2638 state->model_row_deleted = 0;
2639 state->model_row_changed = 0;
2640 state->model_rows_reordered = 0;
2641 state->model_row_expanded = 0;
2642 state->model_row_collapsed = 0;
2649 GtkTextBuffer *buffer =
state->buffer;
2652 if(
state->buffer_changed) g_signal_handler_disconnect(buffer,
state->buffer_changed);
2653 g_object_remove_weak_pointer(G_OBJECT(buffer), (gpointer *)&
state->buffer);
2656 state->buffer = NULL;
2657 state->buffer_changed = 0;
2688 if(!GTK_IS_SCROLLED_WINDOW(sw))
return;
2691 const gint min_size =
MAX(1,
state->min_size);
2706 const gboolean row_based = GTK_IS_TREE_VIEW(w) || GTK_IS_TEXT_VIEW(w);
2710 if(GTK_IS_TREE_VIEW(w))
2713 content =
MAX(1, rows) * increment;
2715 else if(GTK_IS_TEXT_VIEW(w))
2718 content =
MAX(1, rows) * increment;
2722 gtk_widget_get_preferred_height(w, NULL, &content);
2725 const gint cap = has_conf ? CLAMP(
dt_conf_get_int(
state->config_str), min_size, max_height) : max_height;
2726 height = CLAMP(
MIN(content, cap), min_size, max_height);
2738 gtk_style_context_get_padding(gtk_widget_get_style_context(sw),
2739 gtk_widget_get_state_flags(sw), &padding);
2741 gint old_height = 0;
2742 gtk_widget_get_size_request(sw, NULL, &old_height);
2743 const gint new_height =
height + padding.top + padding.bottom + (GTK_IS_TEXT_VIEW(w) ? 2 : 0);
2744 if(new_height != old_height)
2745 gtk_widget_set_size_request(sw, -1, new_height);
2781 return state->last_height;
2810 gint *new_order, gpointer user_data)
2823 (
void)expanded_iter;
2832 (
void)collapsed_iter;
2847 if(!GTK_IS_TREE_VIEW(treeview))
return;
2852 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
2856 if(!GTK_IS_TREE_MODEL(
model))
return;
2859 g_object_add_weak_pointer(G_OBJECT(
model), (gpointer *)&
state->model);
2860 state->model_row_inserted = g_signal_connect(
model,
"row-inserted",
2862 state->model_row_deleted = g_signal_connect(
model,
"row-deleted",
2864 state->model_row_changed = g_signal_connect(
model,
"row-changed",
2866 state->model_rows_reordered = g_signal_connect(
model,
"rows-reordered",
2868 state->model_row_expanded = g_signal_connect(treeview,
"row-expanded",
2870 state->model_row_collapsed = g_signal_connect(treeview,
"row-collapsed",
2876 if(!GTK_IS_TEXT_VIEW(textview))
return;
2881 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
2882 if(buffer ==
state->buffer)
return;
2885 if(!GTK_IS_TEXT_BUFFER(buffer))
return;
2887 state->buffer = buffer;
2888 g_object_add_weak_pointer(G_OBJECT(buffer), (gpointer *)&
state->buffer);
2889 state->buffer_changed = g_signal_connect(buffer,
"changed",
2915 g_free(
state->config_str);
2921 if(!GTK_IS_TEXT_VIEW(textview))
return;
2947 GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL);
2948 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
2950 gtk_container_add(GTK_CONTAINER(sw), w);
2954 state->config_str = g_strdup(config_str);
2965 if(GTK_IS_TREE_VIEW(w))
2970 else if(GTK_IS_TEXT_VIEW(w))
2992 _(
"Drag to resize"),
2997 gtk_container_add(GTK_CONTAINER(over), sw);
2998 gtk_overlay_add_overlay(GTK_OVERLAY(over), handle);
3009 if(!GTK_IS_CONTAINER(wrapper))
return NULL;
3010 GList *children = gtk_container_get_children(GTK_CONTAINER(wrapper));
3012 for(GList *l = children; l; l = g_list_next(l))
3014 if(GTK_IS_SCROLLED_WINDOW(l->data))
3016 sw = GTK_WIDGET(l->data);
3020 g_list_free(children);
3043 g_free(
state->config_str);
3049 GtkWidget *area = GTK_WIDGET(user_data);
3052 return gtk_widget_get_allocated_height(area);
3057 GtkWidget *area = GTK_WIDGET(user_data);
3063 gtk_widget_set_size_request(area, -1,
height);
3071 state->config_str = g_strdup(config_str);
3079 gtk_widget_set_size_request(area, -1,
height);
3085 _(
"Drag to resize"),
3089 gtk_container_add(GTK_CONTAINER(over), area);
3090 gtk_overlay_add_overlay(GTK_OVERLAY(over), handle);
3097 GList *children = gtk_container_get_children(
container);
3099 g_list_free(children);
3101 return has_children;
3107 GList *children = gtk_container_get_children(
container);
3108 int num_children = g_list_length(children);
3109 g_list_free(children);
3111 return num_children;
3116 g_return_val_if_fail(GTK_IS_CONTAINER(
container), NULL);
3117 GList *children = gtk_container_get_children(
container);
3119 g_list_free(children);
3126 g_return_val_if_fail(GTK_IS_CONTAINER(
container), NULL);
3127 GList *children = gtk_container_get_children(
container);
3129 g_list_free(children);
3136 gtk_container_remove((GtkContainer*)data, widget);
3141 g_return_if_fail(GTK_IS_CONTAINER(
container));
3148 gtk_widget_destroy(widget);
3153 g_return_if_fail(GTK_IS_CONTAINER(
container));
3164 for(
GtkWidget *parent = gtk_widget_get_parent(widget); parent; parent = gtk_widget_get_parent(parent))
3165 if(GTK_IS_POPOVER(parent)) relative = parent;
3171 rect->
width =
MAX(gtk_widget_get_allocated_width(widget), 1);
3172 rect->height =
MAX(gtk_widget_get_allocated_height(widget), 1);
3174 if(relative != widget
3175 && !gtk_widget_translate_coordinates(widget, relative, 0, 0, &
rect->
x, &
rect->
y))
3187 gtk_widget_show_all(GTK_WIDGET(menu));
3189 GdkEvent *
event = gtk_get_current_event();
3192 GdkRectangle
rect = { 0 };
3195 if(relative && relative != button && gtk_widget_get_window(relative))
3196 gtk_menu_popup_at_rect(menu, gtk_widget_get_window(relative), &
rect, widget_anchor, menu_anchor, event);
3198 gtk_menu_popup_at_widget(menu, button, widget_anchor, menu_anchor, event);
3204 event = gdk_event_new(GDK_BUTTON_PRESS);
3205 event->button.device = gdk_seat_get_pointer(gdk_display_get_default_seat(gdk_display_get_default()));
3207 g_object_ref(event->button.window);
3210 gtk_menu_popup_at_pointer(menu, event);
3212 gdk_event_free(event);
3217 GdkRectangle
rect = { 0 };
3219 gtk_popover_set_relative_to(popover, relative ? relative : button);
3220 gtk_popover_set_pointing_to(popover, &
rect);
3226 const float radius =
height / 5.0f;
3227 const float degrees =
M_PI / 180.0;
3228 cairo_new_sub_path(cr);
3229 cairo_arc(cr,
x +
width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
3230 cairo_arc(cr,
x +
width - radius, y +
height - radius, radius, 0 * degrees, 90 * degrees);
3231 cairo_arc(cr,
x + radius, y +
height - radius, radius, 90 * degrees, 180 * degrees);
3232 cairo_arc(cr,
x + radius, y + radius, radius, 180 * degrees, 270 * degrees);
3233 cairo_close_path(cr);
3239 if(gtk_search_entry_handle_event(entry, (GdkEvent *)event))
3241 gtk_entry_grab_focus_without_selecting(GTK_ENTRY(entry));
3250 gtk_widget_grab_focus(widget);
3252 gtk_entry_set_text(GTK_ENTRY(entry),
"");
3254 if(GTK_IS_TREE_VIEW(widget))
3256 GtkTreePath *path = NULL;
3257 gtk_tree_view_get_cursor(GTK_TREE_VIEW(widget), &path, NULL);
3258 gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)), path);
3259 gtk_tree_path_free(path);
3273 gtk_widget_set_state_flags(GTK_WIDGET(cs->
expander), GTK_STATE_FLAG_NORMAL,
TRUE);
3285 if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cs->
toggle)))
3286 gtk_widget_hide(widget);
3293 const gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cs->
toggle));
3303 if(e->type == GDK_2BUTTON_PRESS || e->type == GDK_3BUTTON_PRESS)
return;
3307 const gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cs->
toggle));
3308 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cs->
toggle), !active);
3314 const gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cs->
toggle));
3320 gtk_widget_show(GTK_WIDGET(cs->
container));
3322 gtk_widget_hide(GTK_WIDGET(cs->
container));
3329 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cs->
toggle),
FALSE);
3330 gtk_widget_hide(GTK_WIDGET(cs->
container));
3335 const char *confname,
const char *label,
3336 GtkBox *parent, GtkPackType pack)
3345 GtkWidget *header_evb = gtk_event_box_new();
3348 gtk_container_add(GTK_CONTAINER(header_evb), cs->
label);
3352 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cs->
toggle), expanded);
3356 gtk_widget_set_name(GTK_WIDGET(cs->
container),
"collapsible");
3357 gtk_box_pack_start(GTK_BOX(destdisp_head), header_evb,
TRUE,
TRUE, 0);
3364 g_signal_connect(G_OBJECT(cs->
container),
"show",
3367 if(pack == GTK_PACK_START)
3372 gtk_widget_set_name(cs->
expander,
"collapse-block");
3374 g_signal_connect(G_OBJECT(cs->
toggle),
"toggled",
3377 g_signal_connect(G_OBJECT(header_evb),
"button-release-event",
3384 if(!text || !text[0])
return;
3388 if(*
p ==
'_' &&
p[1])
p++;
3396 gunichar c = g_utf8_get_char_validated(
p, -1);
3397 if(c == (gunichar)-1 || c == (gunichar)-2)
return;
3399 gunichar upper = g_unichar_toupper(c);
3400 if(upper == c)
return;
3402 gchar utf8_buf[6] = { 0 };
3403 gint
n = g_unichar_to_utf8(upper, utf8_buf);
3404 gint orig_len = g_utf8_next_char(
p) -
p;
3408 if(
n == orig_len) memcpy(
p, utf8_buf,
n);
3415 gtk_box_pack_start(GTK_BOX(box), widget,
FALSE,
FALSE, 0);
3418 GtkWidget *button = gtk_menu_button_new();
3420 GtkWidget *image = gtk_image_new_from_icon_name(icon, GTK_ICON_SIZE_BUTTON);
3421 gtk_button_set_image(GTK_BUTTON(button), image);
3422 gtk_widget_set_hexpand(button,
FALSE);
3423 gtk_widget_set_vexpand(button,
FALSE);
3425 gtk_box_pack_start(GTK_BOX(box), button,
FALSE,
FALSE, 0);
3429 gtk_box_pack_start(GTK_BOX(popover_box), content,
FALSE,
FALSE, 0);
3432 GtkWidget *popover = gtk_popover_new(button);
3433 gtk_container_add(GTK_CONTAINER(popover), popover_box);
3434 gtk_popover_set_modal(GTK_POPOVER(popover),
FALSE);
3436 gtk_menu_button_set_popover(GTK_MENU_BUTTON(button), popover);
3437 gtk_widget_show_all(popover_box);
3439 return GTK_BOX(box);
3445 GtkWidget *popover_label = gtk_label_new(label);
3446 gtk_label_set_line_wrap(GTK_LABEL(popover_label),
TRUE);
3447 gtk_label_set_max_width_chars(GTK_LABEL(popover_label), 60);
3465 if(event->keyval == GDK_KEY_Escape)
3475 gtk_widget_add_events(widget, GDK_FOCUS_CHANGE_MASK);
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 void _three_choice_button_handler(GtkButton *button, gpointer data)
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)
void dt_gui_freeze_reset(void)
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)
void dt_gui_freeze_end_(const char *file, int line)
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.
int dt_gui_show_standalone_three_choice_dialog(const char *title, const char *markup, const char *first_text, const char *second_text, const char *third_text)
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 gboolean _dt_on_gui_thread(void)
static void _init_widgets(dt_gui_gtk_t *gui)
void dt_gui_set_symbolic_icon(GtkWidget *image, const char *icon_name, GtkIconSize size, const GdkRGBA *color)
Set a symbolic icon on an image widget, optionally forcing a specific color.
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
gboolean dt_gui_widgets_suppressed(void)
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)
void dt_gui_refocus_parent(GtkWindow *parent)
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)
static void _notebook_switch_page_signal_relay(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data)
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_notebook_set_picker_owner(GtkNotebook *notebook, gpointer owner)
Register an opaque owner for a GtkNotebook's page switches, and relay every "switch_page" as DT_SIGNA...
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)
void dt_gui_freeze_begin_(const char *file, int line)
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)
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
@ 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_NOTEBOOK_TAB_CHANGED
This signal is raised when a GtkNotebook created/registered via dt_ui_notebook_set_picker_owner() swi...
@ 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]
GtkWidget * button_second
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]
int32_t _widget_suppress_depth
struct dt_gui_gtk_t::@50 export_popup
cairo_surface_t * surface
struct dt_gui_gtk_t::@51 styles_popup
GtkMenu * presets_popup_menu
GtkWidget * has_scroll_focus
gboolean selection_stacked
struct dt_gui_gtk_t::@49 mouse
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::@52 result
typedef double((*spd)(unsigned long int wavelength, double TempK))
gchar * dt_util_str_replace(const gchar *string, const gchar *pattern, const gchar *substitute)
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)
const dt_view_t * dt_view_manager_get_current_view(dt_view_manager_t *vm)
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)