Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
file.c
Go to the documentation of this file.
1/*
2 This file is part of the Ansel project.
3 Copyright (C) 2023-2025 Aurélien PIERRE.
4 Copyright (C) 2023 lologor.
5 Copyright (C) 2023 Luca Zulberti.
6 Copyright (C) 2024, 2026 Guillaume Stutin.
7
8 Ansel is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 Ansel is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
20*/
21#include "common/darktable.h"
22#include "gui/actions/menu.h"
23#include "common/collection.h"
24#include "common/image.h"
25#include "common/selection.h"
26#include "libs/collect.h"
27#include "common/import.h"
28#include "libs/lib.h"
29#include "control/control.h"
30
31
32static void pretty_print_collection(const char *buf, char *out, size_t outsize)
33{
34 memset(out, 0, outsize);
35
36 if(IS_NULL_PTR(buf) || buf[0] == '\0') return;
37
38 int num_rules = 0;
39 char str[400] = { 0 };
40 int mode, item;
41 int c;
42 sscanf(buf, "%d", &num_rules);
43 while(buf[0] != '\0' && buf[0] != ':') buf++;
44 if(buf[0] == ':') buf++;
45
46 for(int k = 0; k < num_rules; k++)
47 {
48 const int n = sscanf(buf, "%d:%d:%399[^$]", &mode, &item, str);
49
50 if(n == 3)
51 {
52 if(k > 0) switch(mode)
53 {
55 c = g_strlcpy(out, _(" and "), outsize);
56 out += c;
57 outsize -= c;
58 break;
60 c = g_strlcpy(out, _(" or "), outsize);
61 out += c;
62 outsize -= c;
63 break;
64 default: // case DT_LIB_COLLECT_MODE_AND_NOT:
65 c = g_strlcpy(out, _(" but not "), outsize);
66 out += c;
67 outsize -= c;
68 break;
69 }
70 int i = 0;
71 while(str[i] != '\0' && str[i] != '$') i++;
72 if(str[i] == '$') str[i] = '\0';
73
74 c = snprintf(out, outsize, "%s %s", item < DT_COLLECTION_PROP_LAST ? dt_collection_name(item) : "???",
75 item == 0 ? dt_image_film_roll_name(str) : str);
76 out += c;
77 outsize -= c;
78 }
79 while(buf[0] != '$' && buf[0] != '\0') buf++;
80 if(buf[0] == '$') buf++;
81 }
82}
83
84
85static gboolean update_collection_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
86{
87 // Grab the position of current menuitem in menu list
88 const int index = GPOINTER_TO_INT(get_custom_data(GTK_WIDGET(user_data)));
89
90 // Grab the corresponding config line
91 char confname[200];
92 snprintf(confname, sizeof(confname), "plugins/lighttable/recentcollect/line%1d", index);
93 const char *collection = dt_conf_get_string_const(confname);
94
95 snprintf(confname, sizeof(confname), "plugins/lighttable/recentcollect/pos%1d", index);
96
97 // Update the collection to the value defined in config line
98 dt_collection_deserialize(collection);
99
100 return TRUE;
101}
102
103
104void init_collection_line(gpointer instance,
105 dt_collection_change_t query_change,
106 dt_collection_properties_t changed_property, gpointer imgs, int next,
107 gpointer user_data)
108{
109 GtkWidget *widget = GTK_WIDGET(user_data);
110
111 // Grab the position of current menuitem in menu list
112 const int index = GPOINTER_TO_INT(get_custom_data(widget));
113
114 // Grab the corresponding config line
115 char confname[200];
116 snprintf(confname, sizeof(confname), "plugins/lighttable/recentcollect/line%1d", index);
117
118 // Get the human-readable name of the collection
119 const char *collection = dt_conf_get_string_const(confname);
120
121
122 if(collection && collection[0] != '\0')
123 {
124 char label[2048] = { 0 };
125 pretty_print_collection(collection, label, sizeof(label));
126 dt_capitalize_label(label);
127
128 // Update the menu entry label for current collection name. Escape it: a collection value
129 // can contain markup-significant characters (e.g. the < > operators in date/numeric rules).
130 GtkWidget *child = gtk_bin_get_child(GTK_BIN(widget));
131 gchar *escaped = g_markup_escape_text(label, -1);
132 gtk_label_set_markup(GTK_LABEL(child), escaped);
133 g_free(escaped);
134 }
135}
136
137void _close_export_popup(GtkWidget *dialog, gint response_id, gpointer data)
138{
139 // We need to increase the reference count of the module,
140 // then remove it from the popup before closing it,
141 // otherwise it gets destroyed along with it.
142 darktable.gui->export_popup.module = (GtkWidget *)g_object_ref(darktable.gui->export_popup.module);
143 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(darktable.gui->export_popup.window));
144 gtk_container_remove(GTK_CONTAINER(content), darktable.gui->export_popup.module);
146}
147
148static gboolean export_files_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
149{
151 {
152 // if not NULL, we already have a popup open and can't re-instanciate a live GtkWidget
153 gtk_window_present_with_time(GTK_WINDOW(darktable.gui->export_popup.window), GDK_CURRENT_TIME);
154 return TRUE;
155 }
156
157 dt_lib_module_t *module = dt_lib_get_module("export");
158 if(IS_NULL_PTR(module)) return TRUE;
159
160 // get_expander actually builds the expander, it's not a getter despite what the name suggests.
161 // On first run we need to build, an the following runs, just fetch it
163 ? darktable.gui->export_popup.module
164 : dt_lib_gui_get_expander(module);
165 if(IS_NULL_PTR(w)) return TRUE;
166
167 // Save the module
168 darktable.gui->export_popup.module = w;
169
170 // Prepare the popup
171 GtkWidget *dialog = gtk_dialog_new();
172#ifdef GDK_WINDOWING_QUARTZ
173// TODO: On MacOS (at least on version 13) the dialog windows doesn't behave as expected. The dialog
174// needs to have a parent window. "set_parent_window" wasn't working, so set_transient_for is
175// the way to go. Still the window manager isn't dealing with the dialog properly, when the dialog
176// is shifted outside its parent. The dialog isn't visible any longer but still listed as a window
177// of the app.
179 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
180#endif
181 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
182 gtk_window_set_modal(GTK_WINDOW(dialog), FALSE);
183 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)));
184 gtk_window_set_title(GTK_WINDOW(dialog), _("Ansel - Export images"));
185 g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(_close_export_popup), NULL);
186
187 // Ensure the module is expanded
189 dt_gui_add_help_link(w, dt_get_help_url(module->plugin_name));
190 gtk_widget_set_size_request(w, DT_PIXEL_APPLY_DPI(450), -1);
191
192 // Populate popup and fire everything
193 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
194 gtk_box_pack_start(GTK_BOX(content), w, TRUE, TRUE, 0);
195 gtk_widget_set_visible(w, TRUE);
196 gtk_widget_show_all(dialog);
197
198 // Save the ref to the window. We don't reuse its content, we just need to know if it exists.
200
201 return TRUE;
202}
203
204
210
211// On screen and in the clipboard, both modes emit a single line ready to paste
212// as script arguments: IDs comma-separated (--ids 1,2,3), filenames
213// space-separated and shell-quoted (paths can contain spaces and
214// metacharacters; POSIX single-quote escaping also suits PowerShell — only
215// cmd.exe differs). Saved files instead get one raw item per line, unquoted:
216// files are read verbatim, not parsed by a shell.
217static gchar *_export_list_build(GList *imgids, const int mode, const gboolean one_per_line)
218{
219 GString *str = g_string_new(NULL);
220 for(GList *l = imgids; l; l = g_list_next(l))
221 {
222 const int32_t imgid = GPOINTER_TO_INT(l->data);
223 if(mode == DT_EXPORT_LIST_FILENAMES)
224 {
225 char path[PATH_MAX] = { 0 };
226 gboolean from_cache = FALSE;
227 dt_image_full_path(imgid, path, sizeof(path), &from_cache, __FUNCTION__);
228 if(one_per_line)
229 g_string_append(str, path);
230 else
231 {
232 gchar *quoted = g_shell_quote(path);
233 g_string_append(str, quoted);
234 g_free(quoted);
235 }
236 }
237 else
238 g_string_append_printf(str, "%i", imgid);
239
240 if(one_per_line)
241 g_string_append_c(str, '\n');
242 else if(l->next)
243 g_string_append_c(str, mode == DT_EXPORT_LIST_FILENAMES ? ' ' : ',');
244 }
245 return g_string_free(str, FALSE);
246}
247
248static void _export_list_fill(GtkComboBox *combo, gpointer user_data)
249{
250 GtkTextBuffer *buffer = GTK_TEXT_BUFFER(user_data);
251 GList *imgids = (GList *)g_object_get_data(G_OBJECT(buffer), "imgids");
252 gchar *text = _export_list_build(imgids, gtk_combo_box_get_active(combo), FALSE);
253 gtk_text_buffer_set_text(buffer, text, -1);
254 g_free(text);
255}
256
257static void _export_list_save(GtkWidget *dialog, GtkTextBuffer *buffer)
258{
259 GList *imgids = (GList *)g_object_get_data(G_OBJECT(buffer), "imgids");
260 GtkComboBox *combo = GTK_COMBO_BOX(g_object_get_data(G_OBJECT(buffer), "combo"));
261 const int mode = gtk_combo_box_get_active(combo);
262
263 // GtkFileChooserNative uses the platform-native save dialog on Windows and macOS
264 GtkFileChooserNative *chooser
265 = gtk_file_chooser_native_new(_("Ansel - Save image list"), GTK_WINDOW(dialog),
266 GTK_FILE_CHOOSER_ACTION_SAVE, _("_Save"), _("_Cancel"));
267 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(chooser), TRUE);
268 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(chooser),
269 mode == DT_EXPORT_LIST_FILENAMES ? "ansel-image-files.txt"
270 : "ansel-image-ids.txt");
271 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(chooser)) == GTK_RESPONSE_ACCEPT)
272 {
273 gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser));
274 gchar *text = _export_list_build(imgids, mode, TRUE);
275 GError *error = NULL;
276 if(!g_file_set_contents(filename, text, -1, &error))
277 {
278 dt_control_log(_("could not save the image list to '%s': %s"), filename, error->message);
279 g_error_free(error);
280 }
281 g_free(text);
282 g_free(filename);
283 }
284 g_object_unref(chooser);
285}
286
287static void _export_list_response(GtkWidget *dialog, gint response_id, gpointer user_data)
288{
289 if(response_id == GTK_RESPONSE_OK)
290 _export_list_save(dialog, GTK_TEXT_BUFFER(user_data));
291 else if(response_id == GTK_RESPONSE_APPLY)
292 {
293 // GDK_SELECTION_CLIPBOARD is the explicit-copy clipboard on all backends
294 // (X11, Wayland, Windows, macOS) — as opposed to the X11-only PRIMARY selection.
295 GtkTextBuffer *buffer = GTK_TEXT_BUFFER(user_data);
296 GtkTextIter start, end;
297 gtk_text_buffer_get_bounds(buffer, &start, &end);
298 gchar *text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
299 GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
300 gtk_clipboard_set_text(clipboard, text, -1);
301 gtk_clipboard_store(clipboard);
302 g_free(text);
303 }
304 else
305 gtk_widget_destroy(dialog);
306}
307
308static gboolean export_image_list_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
309{
310 static GtkWidget *dialog = NULL;
311
312 // Rebuild from scratch on each call so the content always reflects the current selection
313 if(dialog) gtk_widget_destroy(dialog);
314
316 if(IS_NULL_PTR(imgids)) return TRUE;
317
318 dialog = gtk_dialog_new_with_buttons(_("Ansel - Export image list"),
319 GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)),
320 GTK_DIALOG_DESTROY_WITH_PARENT,
321 _("Copy to clipboard"), GTK_RESPONSE_APPLY,
322 _("Save as file..."), GTK_RESPONSE_OK,
323 _("Close"), GTK_RESPONSE_CLOSE, NULL);
324#ifdef GDK_WINDOWING_QUARTZ
326 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
327#endif
328 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE);
329 gtk_window_set_modal(GTK_WINDOW(dialog), FALSE);
330 g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(gtk_widget_destroyed), &dialog);
331
332 GtkWidget *combo = gtk_combo_box_text_new();
333 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Image ID"));
334 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Image filename"));
335
336 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_PIXEL_APPLY_DPI(8));
337 gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("Export:")), FALSE, FALSE, 0);
338 gtk_box_pack_start(GTK_BOX(hbox), combo, TRUE, TRUE, 0);
339
340 GtkWidget *view = gtk_text_view_new();
341 gtk_text_view_set_editable(GTK_TEXT_VIEW(view), FALSE);
342 gtk_text_view_set_monospace(GTK_TEXT_VIEW(view), TRUE);
343 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD_CHAR);
344 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
345 g_object_set_data_full(G_OBJECT(buffer), "imgids", imgids, (GDestroyNotify)g_list_free);
346 g_object_set_data(G_OBJECT(buffer), "combo", combo);
347
348 GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL);
349 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
350 gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(scroll), DT_PIXEL_APPLY_DPI(450));
351 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scroll), DT_PIXEL_APPLY_DPI(300));
352 gtk_container_add(GTK_CONTAINER(scroll), view);
353
354 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
355 gtk_box_pack_start(GTK_BOX(content), hbox, FALSE, FALSE, DT_PIXEL_APPLY_DPI(4));
356 gtk_box_pack_start(GTK_BOX(content), scroll, TRUE, TRUE, 0);
357
358 g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(_export_list_fill), buffer);
359 g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(_export_list_response), buffer);
360
361 // Setting the active entry fires "changed", which fills the buffer
362 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), DT_EXPORT_LIST_IDS);
363
364 gtk_widget_show_all(dialog);
365 return TRUE;
366}
367
368
378
379void append_file(GtkWidget **menus, GList **lists, const dt_menus_t index)
380{
381 add_sub_menu_entry(menus, lists, _("Import..."), index, NULL, GET_ACCEL_WRAPPER(dt_images_import), NULL, NULL,
382 NULL, GDK_KEY_i, GDK_CONTROL_MASK | GDK_SHIFT_MASK);
383
384 add_sub_menu_entry(menus, lists, _("Export..."), index, NULL, export_files_callback, NULL, NULL,
385 NULL, GDK_KEY_e, GDK_CONTROL_MASK | GDK_SHIFT_MASK);
386
387 add_sub_menu_entry(menus, lists, _("Export image list..."), index, NULL, export_image_list_callback, NULL, NULL,
388 has_selection, 0, 0);
389
390 add_menu_separator(menus[index]);
391
392 add_top_submenu_entry(menus, lists, _("Recent collections"), index);
393 GtkWidget *parent = get_last_widget(lists);
394
395 for(int i = 0; i < NUM_LAST_COLLECTIONS; i++)
396 {
397 // Pass the position of current menuitem in list as custom-data pointer
398 gchar *item_label = g_strdup_printf(_("Most recent collection #%i"), i);
399 add_sub_sub_menu_entry(menus, parent, lists, item_label, index, GINT_TO_POINTER(i), update_collection_callback, NULL, NULL, NULL, 0, 0);
400 dt_free(item_label);
401
402 // Call init directly just this once
403 GtkWidget *this = get_last_widget(lists);
405
406 // Connect init to collection_changed signal for future updates
408 G_CALLBACK(init_collection_line), (gpointer)this);
409 }
410
411 add_menu_separator(menus[index]);
412
413 add_sub_menu_entry(menus, lists, _("Copy files on disk..."), index, NULL, GET_ACCEL_WRAPPER(dt_control_copy_images), NULL, NULL,
414 has_active_images, 0, 0);
415
416 add_sub_menu_entry(menus, lists, _("Move files on disk..."), index, NULL, GET_ACCEL_WRAPPER(dt_control_move_images), NULL, NULL,
417 has_active_images, 0, 0);
418
419 add_sub_menu_entry(menus, lists, _("Create a blended HDR"), index, NULL, GET_ACCEL_WRAPPER(dt_control_merge_hdr), NULL, NULL,
420 has_active_images, 0, 0);
421
422 add_menu_separator(menus[index]);
423
424 add_sub_menu_entry(menus, lists, _("Copy distant images locally"), index, NULL, GET_ACCEL_WRAPPER(dt_control_set_local_copy_images), NULL, NULL,
425 has_active_images, 0, 0);
426
427 add_sub_menu_entry(menus, lists, _("Resynchronize distant images"), index, NULL, GET_ACCEL_WRAPPER(dt_control_reset_local_copy_images), NULL, NULL,
428 has_active_images, 0, 0);
429
430 add_menu_separator(menus[index]);
431
432 add_no_accel_sub_menu_entry(menus, lists, _("Remove from library"), index, NULL, GET_ACCEL_WRAPPER(dt_control_remove_images), NULL, NULL,
433 has_active_image_in_lighttable, GDK_KEY_Delete, 0);
434
435 add_sub_menu_entry(menus, lists, _("Delete from disk"), index, NULL, GET_ACCEL_WRAPPER(dt_control_delete_images), NULL, NULL,
436 has_active_image_in_lighttable, GDK_KEY_Delete, GDK_SHIFT_MASK);
437
438 add_menu_separator(menus[index]);
439
440 add_sub_menu_entry(menus, lists, _("Quit"), index, NULL, GET_ACCEL_WRAPPER(dt_control_quit), NULL, NULL, NULL, GDK_KEY_q, GDK_CONTROL_MASK);
441}
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
@ DT_LIB_COLLECT_MODE_OR
Definition collect.h:38
@ DT_LIB_COLLECT_MODE_AND
Definition collect.h:37
const char * dt_collection_name(dt_collection_properties_t prop)
Definition collection.c:657
void dt_collection_deserialize(const char *buf)
dt_collection_properties_t
Definition collection.h:107
@ DT_COLLECTION_PROP_LAST
Definition collection.h:140
@ DT_COLLECTION_PROP_UNDEF
Definition collection.h:142
dt_collection_change_t
Definition collection.h:147
@ DT_COLLECTION_CHANGE_NONE
Definition collection.h:148
#define NUM_LAST_COLLECTIONS
Definition collection.h:53
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
const char * dt_image_film_roll_name(const char *path)
void dt_image_full_path(const int32_t imgid, char *pathname, size_t pathname_len, gboolean *from_cache, const char *calling_func)
Get the full path of an image out of the database.
const char * dt_conf_get_string_const(const char *name)
void dt_control_log(const char *msg,...)
Definition control.c:777
void dt_control_quit()
Definition control.c:443
void dt_control_delete_images()
void dt_control_move_images()
void dt_control_reset_local_copy_images()
void dt_control_set_local_copy_images()
gboolean dt_control_remove_images()
void dt_control_merge_hdr()
void dt_control_copy_images()
uint32_t view(const dt_view_t *self)
Definition darkroom.c:228
darktable_t darktable
Definition darktable.c:183
#define dt_free(ptr)
Definition darktable.h:478
#define PATH_MAX
Definition darktable.h:1189
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:293
dt_export_list_mode_t
Definition file.c:206
@ DT_EXPORT_LIST_IDS
Definition file.c:207
@ DT_EXPORT_LIST_FILENAMES
Definition file.c:208
void init_collection_line(gpointer instance, dt_collection_change_t query_change, dt_collection_properties_t changed_property, gpointer imgs, int next, gpointer user_data)
Definition file.c:104
static gboolean export_files_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition file.c:148
static gboolean update_collection_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition file.c:85
static gchar * _export_list_build(GList *imgids, const int mode, const gboolean one_per_line)
Definition file.c:217
static gboolean export_image_list_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition file.c:308
static void _export_list_response(GtkWidget *dialog, gint response_id, gpointer user_data)
Definition file.c:287
void _close_export_popup(GtkWidget *dialog, gint response_id, gpointer data)
Definition file.c:137
static void _export_list_save(GtkWidget *dialog, GtkTextBuffer *buffer)
Definition file.c:257
static void pretty_print_collection(const char *buf, char *out, size_t outsize)
Definition file.c:32
static void _export_list_fill(GtkComboBox *combo, gpointer user_data)
Definition file.c:248
void append_file(GtkWidget **menus, GList **lists, const dt_menus_t index)
Definition file.c:379
void dt_capitalize_label(gchar *text)
Definition gtk.c:3382
void dt_gui_add_help_link(GtkWidget *widget, char *link)
Definition gtk.c:2232
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
#define DT_PIXEL_APPLY_DPI(value)
Definition gtk.h:90
void dt_images_import()
Definition import.c:1497
void dt_lib_gui_set_expanded(dt_lib_module_t *module, gboolean expanded)
Definition lib.c:1064
GtkWidget * dt_lib_gui_get_expander(dt_lib_module_t *module)
Definition lib.c:1240
float *const restrict const size_t k
gboolean has_active_image_in_lighttable()
Definition menu.c:652
gboolean has_selection()
Definition menu.c:629
void add_sub_sub_menu_entry(GtkWidget **menus, GtkWidget *parent, GList **lists, const gchar *label, const dt_menus_t index, void *data, gboolean(*action_callback)(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data), gboolean(*checked_callback)(GtkWidget *widget), gboolean(*active_callback)(GtkWidget *widget), gboolean(*sensitive_callback)(GtkWidget *widget), guint key_val, GdkModifierType mods)
Definition menu.c:583
void add_no_accel_sub_menu_entry(GtkWidget **menus, GList **lists, const gchar *label, const dt_menus_t index, void *data, gboolean(*action_callback)(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data), gboolean(*checked_callback)(GtkWidget *widget), gboolean(*active_callback)(GtkWidget *widget), gboolean(*sensitive_callback)(GtkWidget *widget), guint key_val, GdkModifierType mods)
Definition menu.c:552
GtkWidget * get_last_widget(GList **list)
Definition menu.c:617
void add_sub_menu_entry(GtkWidget **menus, GList **lists, const gchar *label, const dt_menus_t index, void *data, gboolean(*action_callback)(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data), gboolean(*checked_callback)(GtkWidget *widget), gboolean(*active_callback)(GtkWidget *widget), gboolean(*sensitive_callback)(GtkWidget *widget), guint key_val, GdkModifierType mods)
Definition menu.c:541
void * get_custom_data(GtkWidget *widget)
Definition menu.c:611
void add_top_submenu_entry(GtkWidget **menus, GList **lists, const gchar *label, const dt_menus_t index)
Definition menu.c:514
void add_menu_separator(GtkWidget *menu)
Definition menu.c:597
gboolean has_active_images()
Definition menu.c:635
#define GET_ACCEL_WRAPPER(cb)
Definition menu.h:235
#define MAKE_ACCEL_WRAPPER(cb)
Definition menu.h:223
dt_menus_t
Definition menu.h:42
void dt_osx_disallow_fullscreen(GtkWidget *widget)
Definition osx.mm:104
GList * dt_selection_get_list(struct dt_selection_t *selection)
Definition selection.c:172
@ DT_SIGNAL_COLLECTION_CHANGED
This signal is raised when collection changed. To avoid leaking the list, dt_collection_t is connecte...
Definition signal.h:122
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
Definition signal.h:376
struct _GtkWidget GtkWidget
Definition splash.h:29
struct dt_gui_gtk_t * gui
Definition darktable.h:803
struct dt_selection_t * selection
Definition darktable.h:810
struct dt_control_signal_t * signals
Definition darktable.h:802
struct dt_gui_gtk_t::@50 export_popup
dt_ui_t * ui
Definition gtk.h:165
GtkWidget * window
Definition gtk.h:241
char * dt_get_help_url(char *name)