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 "system/macros.h"
22#include "common/paths.h" // DT_PATH_MAX
23#include "common/conf.h"
25#include "system/mem_alloc.h"
27#include "control/signal.h"
28#include "gui/application.h"
30#include "gui/actions/menu.h"
31#ifdef __APPLE__
32#include "osx/osx.h" // dt_osx_disallow_fullscreen(), used under GDK_WINDOWING_QUARTZ below
33#endif
34#include "common/collection.h"
35#include "common/image.h"
36#include "common/selection.h"
37#include "libs/collect.h"
38#include "gui/import.h"
39#include "libs/lib.h"
40#include "control/control.h"
43
44
45static void pretty_print_collection(const char *buf, char *out, size_t outsize)
46{
47 memset(out, 0, outsize);
48
49 if(IS_NULL_PTR(buf) || buf[0] == '\0') return;
50
51 int num_rules = 0;
52 char str[400] = { 0 };
53 int mode, item;
54 int c;
55 sscanf(buf, "%d", &num_rules);
56 while(buf[0] != '\0' && buf[0] != ':') buf++;
57 if(buf[0] == ':') buf++;
58
59 for(int k = 0; k < num_rules; k++)
60 {
61 const int n = sscanf(buf, "%d:%d:%399[^$]", &mode, &item, str);
62
63 if(n == 3)
64 {
65 if(k > 0) switch(mode)
66 {
68 c = g_strlcpy(out, _(" and "), outsize);
69 out += c;
70 outsize -= c;
71 break;
73 c = g_strlcpy(out, _(" or "), outsize);
74 out += c;
75 outsize -= c;
76 break;
77 default: // case DT_LIB_COLLECT_MODE_AND_NOT:
78 c = g_strlcpy(out, _(" but not "), outsize);
79 out += c;
80 outsize -= c;
81 break;
82 }
83 int i = 0;
84 while(str[i] != '\0' && str[i] != '$') i++;
85 if(str[i] == '$') str[i] = '\0';
86
87 c = snprintf(out, outsize, "%s %s", item < DT_COLLECTION_PROP_LAST ? dt_collection_name(item) : "???",
88 item == 0 ? dt_image_film_roll_name(str) : str);
89 out += c;
90 outsize -= c;
91 }
92 while(buf[0] != '$' && buf[0] != '\0') buf++;
93 if(buf[0] == '$') buf++;
94 }
95}
96
97
98static gboolean update_collection_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
99{
100 // Grab the position of current menuitem in menu list
101 const int index = GPOINTER_TO_INT(get_custom_data(GTK_WIDGET(user_data)));
102
103 // Grab the corresponding config line
104 char confname[200];
105 snprintf(confname, sizeof(confname), "plugins/lighttable/recentcollect/line%1d", index);
106 const char *collection = dt_conf_get_string_const(confname);
107
108 snprintf(confname, sizeof(confname), "plugins/lighttable/recentcollect/pos%1d", index);
109
110 // Update the collection to the value defined in config line
111 dt_collection_deserialize(collection);
112
113 return TRUE;
114}
115
116
117void init_collection_line(gpointer instance,
118 dt_collection_change_t query_change,
119 dt_collection_properties_t changed_property, gpointer imgs, int next,
120 gpointer user_data)
121{
122 GtkWidget *widget = GTK_WIDGET(user_data);
123
124 // Grab the position of current menuitem in menu list
125 const int index = GPOINTER_TO_INT(get_custom_data(widget));
126
127 // Grab the corresponding config line
128 char confname[200];
129 snprintf(confname, sizeof(confname), "plugins/lighttable/recentcollect/line%1d", index);
130
131 // Get the human-readable name of the collection
132 const char *collection = dt_conf_get_string_const(confname);
133
134
135 if(collection && collection[0] != '\0')
136 {
137 char label[2048] = { 0 };
138 pretty_print_collection(collection, label, sizeof(label));
139 dt_capitalize_label(label);
140
141 // Update the menu entry label for current collection name. Escape it: a collection value
142 // can contain markup-significant characters (e.g. the < > operators in date/numeric rules).
143 GtkWidget *child = gtk_bin_get_child(GTK_BIN(widget));
144 gchar *escaped = g_markup_escape_text(label, -1);
145 gtk_label_set_markup(GTK_LABEL(child), escaped);
146 g_free(escaped);
147 }
148}
149
150void _close_export_popup(GtkWidget *dialog, gint response_id, gpointer data)
151{
152 // We need to increase the reference count of the module,
153 // then remove it from the popup before closing it,
154 // otherwise it gets destroyed along with it.
155 dt_gui_get_global()->export_popup.module = (GtkWidget *)g_object_ref(dt_gui_get_global()->export_popup.module);
156 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dt_gui_get_global()->export_popup.window));
157 gtk_container_remove(GTK_CONTAINER(content), dt_gui_get_global()->export_popup.module);
159}
160
161static gboolean export_files_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
162{
163 if(dt_gui_get_global()->export_popup.window)
164 {
165 // if not NULL, we already have a popup open and can't re-instanciate a live GtkWidget
166 gtk_window_present_with_time(GTK_WINDOW(dt_gui_get_global()->export_popup.window), GDK_CURRENT_TIME);
167 return TRUE;
168 }
169
170 dt_lib_module_t *module = dt_lib_get_module("export");
171 if(IS_NULL_PTR(module)) return TRUE;
172
173 // get_expander actually builds the expander, it's not a getter despite what the name suggests.
174 // On first run we need to build, an the following runs, just fetch it
177 : dt_lib_gui_get_expander(module);
178 if(IS_NULL_PTR(w)) return TRUE;
179
180 // Save the module
181 dt_gui_get_global()->export_popup.module = w;
182
183 // Prepare the popup
184 GtkWidget *dialog = gtk_dialog_new();
185#ifdef GDK_WINDOWING_QUARTZ
186// TODO: On MacOS (at least on version 13) the dialog windows doesn't behave as expected. The dialog
187// needs to have a parent window. "set_parent_window" wasn't working, so set_transient_for is
188// the way to go. Still the window manager isn't dealing with the dialog properly, when the dialog
189// is shifted outside its parent. The dialog isn't visible any longer but still listed as a window
190// of the app.
192 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
193#endif
194 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
195 gtk_window_set_modal(GTK_WINDOW(dialog), FALSE);
196 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(dt_gui_main_window()));
197 gtk_window_set_title(GTK_WINDOW(dialog), _("Ansel - Export images"));
198 g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(_close_export_popup), NULL);
199
200 // Ensure the module is expanded
202 dt_gui_add_help_link(w, dt_get_help_url(module->plugin_name));
203 gtk_widget_set_size_request(w, DT_PIXEL_APPLY_DPI(450), -1);
204
205 // Populate popup and fire everything
206 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
207 gtk_box_pack_start(GTK_BOX(content), w, TRUE, TRUE, 0);
208 gtk_widget_set_visible(w, TRUE);
209 gtk_widget_show_all(dialog);
210
211 // Save the ref to the window. We don't reuse its content, we just need to know if it exists.
213
214 return TRUE;
215}
216
217
223
224// On screen and in the clipboard, both modes emit a single line ready to paste
225// as script arguments: IDs comma-separated (--ids 1,2,3), filenames
226// space-separated and shell-quoted (paths can contain spaces and
227// metacharacters; POSIX single-quote escaping also suits PowerShell — only
228// cmd.exe differs). Saved files instead get one raw item per line, unquoted:
229// files are read verbatim, not parsed by a shell.
230static gchar *_export_list_build(GList *imgids, const int mode, const gboolean one_per_line)
231{
232 GString *str = g_string_new(NULL);
233 for(GList *l = imgids; l; l = g_list_next(l))
234 {
235 const int32_t imgid = GPOINTER_TO_INT(l->data);
236 if(mode == DT_EXPORT_LIST_FILENAMES)
237 {
238 char path[DT_PATH_MAX] = { 0 };
239 gboolean from_cache = FALSE;
240 dt_image_full_path(imgid, path, sizeof(path), &from_cache, __FUNCTION__);
241 if(one_per_line)
242 g_string_append(str, path);
243 else
244 {
245 gchar *quoted = g_shell_quote(path);
246 g_string_append(str, quoted);
247 g_free(quoted);
248 }
249 }
250 else
251 g_string_append_printf(str, "%i", imgid);
252
253 if(one_per_line)
254 g_string_append_c(str, '\n');
255 else if(l->next)
256 g_string_append_c(str, mode == DT_EXPORT_LIST_FILENAMES ? ' ' : ',');
257 }
258 return g_string_free(str, FALSE);
259}
260
261static void _export_list_fill(GtkComboBox *combo, gpointer user_data)
262{
263 GtkTextBuffer *buffer = GTK_TEXT_BUFFER(user_data);
264 GList *imgids = (GList *)g_object_get_data(G_OBJECT(buffer), "imgids");
265 gchar *text = _export_list_build(imgids, gtk_combo_box_get_active(combo), FALSE);
266 gtk_text_buffer_set_text(buffer, text, -1);
267 g_free(text);
268}
269
270static void _export_list_save(GtkWidget *dialog, GtkTextBuffer *buffer)
271{
272 GList *imgids = (GList *)g_object_get_data(G_OBJECT(buffer), "imgids");
273 GtkComboBox *combo = GTK_COMBO_BOX(g_object_get_data(G_OBJECT(buffer), "combo"));
274 const int mode = gtk_combo_box_get_active(combo);
275
276 // GtkFileChooserNative uses the platform-native save dialog on Windows and macOS
277 GtkFileChooserNative *chooser
278 = gtk_file_chooser_native_new(_("Ansel - Save image list"), GTK_WINDOW(dialog),
279 GTK_FILE_CHOOSER_ACTION_SAVE, _("_Save"), _("_Cancel"));
280 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(chooser), TRUE);
281 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(chooser),
282 mode == DT_EXPORT_LIST_FILENAMES ? "ansel-image-files.txt"
283 : "ansel-image-ids.txt");
284 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(chooser)) == GTK_RESPONSE_ACCEPT)
285 {
286 gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser));
287 gchar *text = _export_list_build(imgids, mode, TRUE);
288 GError *error = NULL;
289 if(!g_file_set_contents(filename, text, -1, &error))
290 {
291 dt_control_log(_("could not save the image list to '%s': %s"), filename, error->message);
292 g_error_free(error);
293 }
294 g_free(text);
295 g_free(filename);
296 }
297 g_object_unref(chooser);
298}
299
300static void _export_list_response(GtkWidget *dialog, gint response_id, gpointer user_data)
301{
302 if(response_id == GTK_RESPONSE_OK)
303 _export_list_save(dialog, GTK_TEXT_BUFFER(user_data));
304 else if(response_id == GTK_RESPONSE_APPLY)
305 {
306 // GDK_SELECTION_CLIPBOARD is the explicit-copy clipboard on all backends
307 // (X11, Wayland, Windows, macOS) — as opposed to the X11-only PRIMARY selection.
308 GtkTextBuffer *buffer = GTK_TEXT_BUFFER(user_data);
309 GtkTextIter start, end;
310 gtk_text_buffer_get_bounds(buffer, &start, &end);
311 gchar *text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
312 GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
313 gtk_clipboard_set_text(clipboard, text, -1);
314 gtk_clipboard_store(clipboard);
315 g_free(text);
316 }
317 else
318 gtk_widget_destroy(dialog);
319}
320
321static gboolean export_image_list_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
322{
323 static GtkWidget *dialog = NULL;
324
325 // Rebuild from scratch on each call so the content always reflects the current selection
326 if(dialog) gtk_widget_destroy(dialog);
327
329 if(IS_NULL_PTR(imgids)) return TRUE;
330
331 dialog = gtk_dialog_new_with_buttons(_("Ansel - Export image list"),
332 GTK_WINDOW(dt_gui_main_window()),
333 GTK_DIALOG_DESTROY_WITH_PARENT,
334 _("Copy to clipboard"), GTK_RESPONSE_APPLY,
335 _("Save as file..."), GTK_RESPONSE_OK,
336 _("Close"), GTK_RESPONSE_CLOSE, NULL);
337#ifdef GDK_WINDOWING_QUARTZ
339 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
340#endif
341 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE);
342 gtk_window_set_modal(GTK_WINDOW(dialog), FALSE);
343 g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(gtk_widget_destroyed), &dialog);
344
345 GtkWidget *combo = gtk_combo_box_text_new();
346 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Image ID"));
347 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Image filename"));
348
349 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_PIXEL_APPLY_DPI(8));
350 gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("Export:")), FALSE, FALSE, 0);
351 gtk_box_pack_start(GTK_BOX(hbox), combo, TRUE, TRUE, 0);
352
353 GtkWidget *view = gtk_text_view_new();
354 gtk_text_view_set_editable(GTK_TEXT_VIEW(view), FALSE);
355 gtk_text_view_set_monospace(GTK_TEXT_VIEW(view), TRUE);
356 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD_CHAR);
357 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
358 g_object_set_data_full(G_OBJECT(buffer), "imgids", imgids, (GDestroyNotify)g_list_free);
359 g_object_set_data(G_OBJECT(buffer), "combo", combo);
360
361 GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL);
362 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
363 gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(scroll), DT_PIXEL_APPLY_DPI(450));
364 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scroll), DT_PIXEL_APPLY_DPI(300));
365 gtk_container_add(GTK_CONTAINER(scroll), view);
366
367 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
368 gtk_box_pack_start(GTK_BOX(content), hbox, FALSE, FALSE, DT_PIXEL_APPLY_DPI(4));
369 gtk_box_pack_start(GTK_BOX(content), scroll, TRUE, TRUE, 0);
370
371 g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(_export_list_fill), buffer);
372 g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(_export_list_response), buffer);
373
374 // Setting the active entry fires "changed", which fills the buffer
375 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), DT_EXPORT_LIST_IDS);
376
377 gtk_widget_show_all(dialog);
378 return TRUE;
379}
380
381
391
392void append_file(GtkWidget **menus, GList **lists, const dt_menus_t index)
393{
394 add_sub_menu_entry(menus, lists, _("Import..."), index, NULL, GET_ACCEL_WRAPPER(dt_images_import), NULL, NULL,
395 NULL, GDK_KEY_i, DT_PRIMARY_MASK | GDK_SHIFT_MASK);
396
397 add_sub_menu_entry(menus, lists, _("Export..."), index, NULL, export_files_callback, NULL, NULL,
398 NULL, GDK_KEY_e, DT_PRIMARY_MASK | GDK_SHIFT_MASK);
399
400 add_sub_menu_entry(menus, lists, _("Export image list..."), index, NULL, export_image_list_callback, NULL, NULL,
401 has_selection, 0, 0);
402
403 add_menu_separator(menus[index]);
404
405 add_top_submenu_entry(menus, lists, _("Recent collections"), index);
406 GtkWidget *parent = get_last_widget(lists);
407
408 for(int i = 0; i < NUM_LAST_COLLECTIONS; i++)
409 {
410 // Pass the position of current menuitem in list as custom-data pointer
411 gchar *item_label = g_strdup_printf(_("Most recent collection #%i"), i);
412 add_sub_sub_menu_entry(menus, parent, lists, item_label, index, GINT_TO_POINTER(i), update_collection_callback, NULL, NULL, NULL, 0, 0);
413 dt_free(item_label);
414
415 // Call init directly just this once
416 GtkWidget *this = get_last_widget(lists);
418
419 // Connect init to collection_changed signal for future updates
421 G_CALLBACK(init_collection_line), (gpointer)this);
422 }
423
424 add_menu_separator(menus[index]);
425
426 add_sub_menu_entry(menus, lists, _("Copy files on disk..."), index, NULL, GET_ACCEL_WRAPPER(dt_control_copy_images), NULL, NULL,
427 has_active_images, 0, 0);
428
429 add_sub_menu_entry(menus, lists, _("Move files on disk..."), index, NULL, GET_ACCEL_WRAPPER(dt_control_move_images), NULL, NULL,
430 has_active_images, 0, 0);
431
432 add_sub_menu_entry(menus, lists, _("Create a blended HDR"), index, NULL, GET_ACCEL_WRAPPER(dt_control_merge_hdr), NULL, NULL,
433 has_active_images, 0, 0);
434
435 add_menu_separator(menus[index]);
436
437 add_sub_menu_entry(menus, lists, _("Copy distant images locally"), index, NULL, GET_ACCEL_WRAPPER(dt_control_set_local_copy_images), NULL, NULL,
438 has_active_images, 0, 0);
439
440 add_sub_menu_entry(menus, lists, _("Resynchronize distant images"), index, NULL, GET_ACCEL_WRAPPER(dt_control_reset_local_copy_images), NULL, NULL,
441 has_active_images, 0, 0);
442
443 add_menu_separator(menus[index]);
444
445 add_no_accel_sub_menu_entry(menus, lists, _("Remove from library"), index, NULL, GET_ACCEL_WRAPPER(dt_control_remove_images), NULL, NULL,
446 has_active_image_in_lighttable, GDK_KEY_Delete, 0);
447
448 add_sub_menu_entry(menus, lists, _("Delete from disk"), index, NULL, GET_ACCEL_WRAPPER(dt_control_delete_images), NULL, NULL,
449 has_active_image_in_lighttable, GDK_KEY_Delete, GDK_SHIFT_MASK);
450
451 add_menu_separator(menus[index]);
452
453 add_sub_menu_entry(menus, lists, _("Quit"), index, NULL, GET_ACCEL_WRAPPER(dt_control_quit), NULL, NULL, NULL, GDK_KEY_q, DT_PRIMARY_MASK);
454}
Handle default and user-set shortcuts (accelerators)
#define DT_PRIMARY_MASK
GtkWidget * dt_gui_main_window(void)
void dt_gui_add_help_link(GtkWidget *widget, char *link)
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
@ DT_LIB_COLLECT_MODE_OR
Definition collect.h:39
@ DT_LIB_COLLECT_MODE_AND
Definition collect.h:38
const char * dt_collection_name(dt_collection_properties_t prop)
Definition collection.c:390
void dt_collection_deserialize(const char *buf)
Definition collection.c:763
dt_collection_properties_t
Definition collection.h:120
@ DT_COLLECTION_PROP_LAST
Definition collection.h:153
@ DT_COLLECTION_PROP_UNDEF
Definition collection.h:155
dt_collection_change_t
Definition collection.h:160
@ DT_COLLECTION_CHANGE_NONE
Definition collection.h:161
#define NUM_LAST_COLLECTIONS
Definition collection.h:54
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
const dt_colormatrix_t dt_aligned_pixel_t out
const char * dt_conf_get_string_const(const char *name)
Borrow the stored string for name without copying it.
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.
void dt_control_log(const char *msg,...)
Definition control.c:824
void dt_control_quit()
Definition control.c:452
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()
struct dt_gui_gtk_t * dt_gui_get_global(void)
Definition darktable.c:523
GtkWidget * view
the tree view
dt_export_list_mode_t
Definition file.c:219
@ DT_EXPORT_LIST_IDS
Definition file.c:220
@ DT_EXPORT_LIST_FILENAMES
Definition file.c:221
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:117
static gboolean export_files_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition file.c:161
static gboolean update_collection_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition file.c:98
static gchar * _export_list_build(GList *imgids, const int mode, const gboolean one_per_line)
Definition file.c:230
static gboolean export_image_list_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition file.c:321
static void _export_list_response(GtkWidget *dialog, gint response_id, gpointer user_data)
Definition file.c:300
void _close_export_popup(GtkWidget *dialog, gint response_id, gpointer data)
Definition file.c:150
static void _export_list_save(GtkWidget *dialog, GtkTextBuffer *buffer)
Definition file.c:270
static void pretty_print_collection(const char *buf, char *out, size_t outsize)
Definition file.c:45
static void _export_list_fill(GtkComboBox *combo, gpointer user_data)
Definition file.c:261
void append_file(GtkWidget **menus, GList **lists, const dt_menus_t index)
Definition file.c:392
void dt_images_import()
Definition import.c:1634
void dt_lib_gui_set_expanded(dt_lib_module_t *module, gboolean expanded)
Definition lib.c:854
GtkWidget * dt_lib_gui_get_expander(dt_lib_module_t *module)
Definition lib.c:1039
float *const restrict const size_t k
#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 macros.h:96
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
gboolean has_active_image_in_lighttable()
Definition menu.c:676
gboolean has_selection()
Definition menu.c:653
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:607
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:576
GtkWidget * get_last_widget(GList **list)
Definition menu.c:641
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:565
void * get_custom_data(GtkWidget *widget)
Definition menu.c:635
void add_top_submenu_entry(GtkWidget **menus, GList **lists, const gchar *label, const dt_menus_t index)
Definition menu.c:538
void add_menu_separator(GtkWidget *menu)
Definition menu.c:621
gboolean has_active_images()
Definition menu.c:659
#define GET_ACCEL_WRAPPER(cb)
Definition menu.h:239
#define MAKE_ACCEL_WRAPPER(cb)
Definition menu.h:227
dt_menus_t
Definition menu.h:42
void dt_osx_disallow_fullscreen(GtkWidget *widget)
Definition osx.mm:105
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
struct dt_selection_t * dt_selection_get_global(void)
Definition selection.c:80
GList * dt_selection_get_list(struct dt_selection_t *selection)
Definition selection.c:185
struct dt_control_signal_t * dt_control_signal_get_global(void)
Definition darktable.c:616
@ DT_SIGNAL_COLLECTION_CHANGED
This signal is raised when collection changed. To avoid leaking the list, dt_collection_t is connecte...
Definition signal.h:125
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
Definition signal.h:396
struct dt_gui_gtk_t::@34 export_popup
GtkWidget * window
char * dt_get_help_url(char *name)
#define DT_PIXEL_APPLY_DPI(value)
void dt_capitalize_label(gchar *text)