Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
splash.c
Go to the documentation of this file.
1/*
2 This file is part of the Ansel project.
3 Copyright (C) 2026 Aurélien PIERRE.
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include "gui/splash.h"
20
21#include "system/macros.h"
22#include "system/mem_alloc.h"
23#include "common/paths.h"
26
27#include <glib/gi18n.h>
28#include <gtk/gtk.h>
29#include <math.h>
30#include <pango/pangocairo.h>
31#include <stdlib.h>
32#include "config.h"
54
55typedef struct dt_splash_slide_t
56{
57 gchar *path;
58 gchar *author;
60
61static dt_splash_t *splash = NULL;
62
63static gboolean _splash_env_is_truthy(const char *value)
64{
65 if(IS_NULL_PTR(value)) return FALSE;
66 if(value[0] == '\0') return TRUE;
67 if(g_ascii_strcasecmp(value, "0") == 0) return FALSE;
68 if(g_ascii_strcasecmp(value, "false") == 0) return FALSE;
69 if(g_ascii_strcasecmp(value, "no") == 0) return FALSE;
70 if(g_ascii_strcasecmp(value, "off") == 0) return FALSE;
71 return TRUE;
72}
73
74static gboolean _splash_is_disabled(void)
75{
76 return _splash_env_is_truthy(g_getenv("ANSEL_NO_SPLASH"))
77 || _splash_env_is_truthy(g_getenv("ANSEL_DISABLE_SPLASH"))
78 || _splash_env_is_truthy(g_getenv("DARKTABLE_NO_SPLASH"))
79 || _splash_env_is_truthy(g_getenv("DARKTABLE_DISABLE_SPLASH"));
80}
81
83{
84 if(IS_NULL_PTR(splash) || IS_NULL_PTR(splash->window) || IS_NULL_PTR(parent)) return;
85 gtk_window_set_transient_for(GTK_WINDOW(splash->window), GTK_WINDOW(parent));
86 gtk_window_set_keep_above(GTK_WINDOW(splash->window), TRUE);
87}
88
89static void _splash_force_show(void)
90{
92
93 gtk_widget_show_all(splash->window);
94 gtk_window_present(GTK_WINDOW(splash->window));
95 gtk_widget_show_now(splash->window);
96 gtk_widget_queue_draw(splash->drawing);
97 gtk_widget_queue_draw(splash->window);
98
99 GdkDisplay *display = gdk_display_get_default();
100 if(display) gdk_display_flush(display);
101
102 splash->shown = TRUE;
103}
104
106{
107 if(IS_NULL_PTR(splash)) return;
109 {
110 g_object_unref(splash->slide_pixbuf);
111 splash->slide_pixbuf = NULL;
112 }
117}
118
119static void _splash_add_css(const char *data)
120{
121 if(IS_NULL_PTR(splash) || IS_NULL_PTR(splash->css)) return;
122 gtk_css_provider_load_from_data(splash->css, data, -1, NULL);
123}
124
125static gchar *_splash_build_data_path(const char *subpath)
126{
127 char datadir[DT_PATH_MAX] = { 0 };
128 dt_loc_get_datadir(datadir, sizeof(datadir));
129 return g_build_filename(datadir, "pixmaps", "splash", subpath, NULL);
130}
131
132static gchar *_splash_build_author_list(guint max_names)
133{
135 return g_strdup(_("Contributors"));
136
137 GString *buf = g_string_new(NULL);
138 guint used = 0;
139 g_string_append(buf, "© ");
140
141 for(guint i = 0; i < splash->authors->len && used < max_names; i++)
142 {
143 const gchar *name = (const gchar *)splash->authors->pdata[i];
144 if(IS_NULL_PTR(name) || !name[0]) continue;
145 used++;
146
147 g_string_append(buf, name);
148
149 if(used < max_names)
150 g_string_append(buf, ", ");
151 }
152
153 g_string_append(buf, "… and all contributors.");
154
155 return g_string_free(buf, FALSE);
156}
157
158static GtkWidget *_splash_shadow_label_new(const gchar *text, const gchar *name, const gchar *shadow_name,
159 GtkWidget **out_main)
160{
161 GtkWidget *fixed = gtk_fixed_new();
162 GtkWidget *shadow1 = gtk_label_new(text);
163 GtkWidget *shadow2 = gtk_label_new(text);
164 GtkWidget *label = gtk_label_new(text);
165
166 if(shadow_name) gtk_widget_set_name(shadow1, shadow_name);
167 if(shadow_name) gtk_widget_set_name(shadow2, shadow_name);
168 if(name) gtk_widget_set_name(label, name);
169
170 PangoAttrList *shadow_attrs = pango_attr_list_new();
171 PangoAttribute *fg = pango_attr_foreground_new(0, 0, 0);
172 PangoAttribute *alpha = pango_attr_foreground_alpha_new((guint16)(0.75 * 65535));
173 pango_attr_list_insert(shadow_attrs, fg);
174 pango_attr_list_insert(shadow_attrs, alpha);
175 gtk_label_set_attributes(GTK_LABEL(shadow1), shadow_attrs);
176 gtk_label_set_attributes(GTK_LABEL(shadow2), shadow_attrs);
177 pango_attr_list_unref(shadow_attrs);
178
179 PangoAttrList *main_attrs = pango_attr_list_new();
180 PangoAttribute *main_fg = pango_attr_foreground_new(65535, 65535, 65535);
181 PangoAttribute *main_alpha = pango_attr_foreground_alpha_new(65535);
182 pango_attr_list_insert(main_attrs, main_fg);
183 pango_attr_list_insert(main_attrs, main_alpha);
184 gtk_label_set_attributes(GTK_LABEL(label), main_attrs);
185 pango_attr_list_unref(main_attrs);
186
187 gtk_fixed_put(GTK_FIXED(fixed), shadow1, 1, 1);
188 gtk_fixed_put(GTK_FIXED(fixed), shadow2, 2, 2);
189 gtk_fixed_put(GTK_FIXED(fixed), label, 0, 0);
190
191 GList *shadows = NULL;
192 shadows = g_list_append(shadows, shadow1);
193 shadows = g_list_append(shadows, shadow2);
194 g_object_set_data_full(G_OBJECT(label), "splash-shadow-labels", shadows, (GDestroyNotify)g_list_free);
195
196 if(out_main) *out_main = label;
197
198 return fixed;
199}
200
201static void _splash_shadow_label_set_text(GtkWidget *label, const gchar *text)
202{
203 if(IS_NULL_PTR(label)) return;
204 gtk_label_set_text(GTK_LABEL(label), text);
205 GList *shadows = (GList *)g_object_get_data(G_OBJECT(label), "splash-shadow-labels");
206 for(GList *iter = shadows; iter; iter = g_list_next(iter))
207 gtk_label_set_text(GTK_LABEL(iter->data), text);
208}
209
210static dt_splash_slide_t *_splash_slide_new(const gchar *path, const gchar *author)
211{
212 dt_splash_slide_t *slide = g_malloc0(sizeof(dt_splash_slide_t));
213 slide->path = g_strdup(path);
214 slide->author = author ? g_strdup(author) : NULL;
215 return slide;
216}
217
218static void _splash_slide_free(gpointer data)
219{
220 dt_splash_slide_t *slide = (dt_splash_slide_t *)data;
221 if(IS_NULL_PTR(slide)) return;
222 dt_free(slide->path);
223 dt_free(slide->author);
224 dt_free(slide);
225}
226
227static gboolean _splash_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
228{
229 if(IS_NULL_PTR(splash) || !splash->slides || splash->slides->len == 0) return FALSE;
230
231 GtkAllocation alloc;
232 gtk_widget_get_allocation(widget, &alloc);
233 const int width = alloc.width;
234 const int height = alloc.height;
235
237 if(!slide || !slide->path) return FALSE;
238
239 int scale_factor = gtk_widget_get_scale_factor(widget);
240 if(scale_factor < 1) scale_factor = 1;
241 const int dev_width = width * scale_factor;
242 const int dev_height = height * scale_factor;
243
244 const int slide_index = splash->current_slide % splash->slides->len;
245 const gboolean cache_ok = splash->slide_pixbuf
246 && splash->slide_cache_index == slide_index
247 && splash->slide_cache_width == dev_width
248 && splash->slide_cache_height == dev_height
249 && splash->slide_cache_scale == scale_factor;
250
251 if(!cache_ok)
252 {
254
255 GError *error = NULL;
256 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(slide->path, &error);
257 if(IS_NULL_PTR(pixbuf))
258 {
259 if(error) g_error_free(error);
260 return FALSE;
261 }
262
263 const int img_w = gdk_pixbuf_get_width(pixbuf);
264 const int img_h = gdk_pixbuf_get_height(pixbuf);
265 const double scale = fmax((double)dev_width / img_w, (double)dev_height / img_h);
266 const int scaled_w = (int)ceil(img_w * scale);
267 const int scaled_h = (int)ceil(img_h * scale);
268
269 splash->slide_pixbuf = gdk_pixbuf_scale_simple(pixbuf, scaled_w, scaled_h, GDK_INTERP_HYPER);
270 g_object_unref(pixbuf);
271 splash->slide_cache_index = slide_index;
272 splash->slide_cache_width = dev_width;
273 splash->slide_cache_height = dev_height;
274 splash->slide_cache_scale = scale_factor;
275 }
276
277 const int scaled_w = gdk_pixbuf_get_width(splash->slide_pixbuf);
278 const int scaled_h = gdk_pixbuf_get_height(splash->slide_pixbuf);
279 const int offset_x = (dev_width - scaled_w) / 2;
280 const int offset_y = (dev_height - scaled_h) / 2;
281
282 cairo_save(cr);
283 cairo_scale(cr, 1.0 / scale_factor, 1.0 / scale_factor);
284 cairo_rectangle(cr, 0, 0, dev_width, dev_height);
285 cairo_clip(cr);
286
287 gdk_cairo_set_source_pixbuf(cr, splash->slide_pixbuf, offset_x, offset_y);
288 cairo_paint(cr);
289
290 cairo_restore(cr);
291
292 if(slide->author && slide->author[0])
293 {
294 gchar *label = g_strdup_printf(_("© %s"), slide->author);
295 PangoLayout *layout = gtk_widget_create_pango_layout(widget, label);
296 PangoFontDescription *desc = pango_font_description_from_string("14px Roboto");
297 pango_layout_set_font_description(layout, desc);
298 pango_font_description_free(desc);
299 pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
300 pango_layout_set_width(layout, (width - 32) * PANGO_SCALE);
301
302 int text_w = 0, text_h = 0;
303 pango_layout_get_pixel_size(layout, &text_w, &text_h);
304
305 const int pad = 6;
306 const int margin = 0;
307 int box_w = text_w + pad * 2;
308 int box_h = text_h + pad * 2;
309 int x = width - box_w - margin;
310 int y = margin;
311
312 cairo_save(cr);
313 cairo_rectangle(cr, x, y, box_w, box_h);
314 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.55);
315 cairo_fill(cr);
316
317 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.85);
318 cairo_move_to(cr, x + pad, y + pad);
319 pango_cairo_show_layout(cr, layout);
320 cairo_restore(cr);
321
322 g_object_unref(layout);
323 dt_free(label);
324 }
325
326 return FALSE;
327}
328
329static gboolean _splash_slide_advance(gpointer user_data)
330{
331 if(IS_NULL_PTR(splash) || !splash->drawing) return G_SOURCE_REMOVE;
332 if(!splash->slides || splash->slides->len == 0) return G_SOURCE_CONTINUE;
335 gtk_widget_queue_draw(splash->drawing);
336 return G_SOURCE_CONTINUE;
337}
338
339static void _splash_load_authors(void)
340{
341 char datadir[DT_PATH_MAX] = { 0 };
342 dt_loc_get_datadir(datadir, sizeof(datadir));
343 gchar *path = g_build_filename(datadir, "AUTHORS", NULL);
344 gchar *content = NULL;
345 gsize len = 0;
346
347 if(g_file_get_contents(path, &content, &len, NULL) && content)
348 {
349 gchar **lines = g_strsplit(content, "\n", -1);
350 for(gint i = 0; lines[i]; i++)
351 {
352 gchar *trim = g_strstrip(lines[i]);
353 if(trim[0] == '\0') continue;
354 if(trim[0] == '*') continue;
355 g_ptr_array_add(splash->authors, g_strdup(trim));
356 }
357 g_strfreev(lines);
358 dt_free(content);
359 }
360 dt_free(path);
361
362 if(splash->authors->len == 0)
363 {
364 g_ptr_array_add(splash->authors, g_strdup(_("Darktable & Ansel contributors")));
365 }
366}
367
368static void _splash_load_slides(void)
369{
370 const gchar *default_author = _("Boilerplate image");
371 gchar *list_path = _splash_build_data_path("slides.txt");
372 gchar *content = NULL;
373 gsize len = 0;
374 if(g_file_get_contents(list_path, &content, &len, NULL) && content)
375 {
376 gchar **lines = g_strsplit(content, "\n", -1);
377 for(gint i = 0; lines[i]; i++)
378 {
379 gchar *line = g_strstrip(lines[i]);
380 if(line[0] == '\0' || line[0] == '#') continue;
381
382 gchar **parts = g_strsplit(line, "|", 2);
383 const gchar *name = parts[0] ? g_strstrip(parts[0]) : NULL;
384 const gchar *author = (parts[1] && parts[1][0]) ? g_strstrip(parts[1]) : default_author;
385 if(name && name[0])
386 {
387 gchar *path = NULL;
388 if(g_path_is_absolute(name))
389 path = g_strdup(name);
390 else
392
393 if(g_file_test(path, G_FILE_TEST_EXISTS))
394 g_ptr_array_add(splash->slides, _splash_slide_new(path, author));
395 dt_free(path);
396 }
397 g_strfreev(parts);
398 }
399 g_strfreev(lines);
400 dt_free(content);
401 }
402 dt_free(list_path);
403}
404
405static void _splash_update_message(const gchar *message)
406{
410 gtk_widget_queue_draw(splash->label_message);
411 gtk_widget_queue_draw(splash->drawing);
412 for(int i = 0; i < 2; i++)
413 gtk_main_iteration_do(FALSE);
414}
415
416static gchar *_splash_capitalize_name(const char *name)
417{
418 if(IS_NULL_PTR(name) || !name[0]) return g_strdup("");
419 gchar *out = g_strdup(name);
420 out[0] = g_ascii_toupper(out[0]);
421 return out;
422}
423
424static gboolean _splash_logo_set_from_path(GtkWidget *logo, const char *path, int target_size, int scale_factor)
425{
426 if(IS_NULL_PTR(logo) || IS_NULL_PTR(path)) return FALSE;
427 if(scale_factor < 1) scale_factor = 1;
428
429 const int target_px = target_size * scale_factor;
430 GError *error = NULL;
431 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_scale(path, target_px, target_px, TRUE, &error);
432 if(IS_NULL_PTR(pixbuf))
433 {
434 if(error) g_error_free(error);
435 return FALSE;
436 }
437
438 cairo_surface_t *surface = gdk_cairo_surface_create_from_pixbuf(pixbuf, scale_factor, NULL);
439 g_object_unref(pixbuf);
440 if(IS_NULL_PTR(surface)) return FALSE;
441
442 gtk_image_set_from_surface(GTK_IMAGE(logo), surface);
443 cairo_surface_destroy(surface);
444 return TRUE;
445}
446
447static GtkWidget *_splash_create_logo(int target_size, int scale_factor, gchar **out_path)
448{
449 char datadir[DT_PATH_MAX] = { 0 };
450 char sharedir[DT_PATH_MAX] = { 0 };
451 dt_loc_get_datadir(datadir, sizeof(datadir));
452 dt_loc_get_sharedir(sharedir, sizeof(sharedir));
453
454 // Best effort to find a logo
455 GtkWidget *image = gtk_image_new();
456 GPtrArray *paths = g_ptr_array_new_with_free_func(g_free);
457 g_ptr_array_add(paths, g_build_filename(datadir, "pixmaps", "scalable", "ansel.svg", NULL));
458 g_ptr_array_add(paths, g_build_filename(sharedir, "icons", "hicolor", "scalable", "apps", "ansel.svg", NULL));
459 const char *sizes[] = { "256x256", "128x128", "64x64", NULL };
460 for(guint i = 0; sizes[i]; i++)
461 {
462 g_ptr_array_add(paths, g_build_filename(datadir, "pixmaps", sizes[i], "ansel.png", NULL));
463 g_ptr_array_add(paths, g_build_filename(sharedir, "icons", "hicolor", sizes[i], "apps", "ansel.png", NULL));
464 }
465
466 gboolean loaded = FALSE;
467 for(guint i = 0; i < paths->len && !loaded; i++)
468 {
469 const gchar *path = (const gchar *)paths->pdata[i];
470 if(path && g_file_test(path, G_FILE_TEST_EXISTS))
471 {
472 if(_splash_logo_set_from_path(image, path, target_size, scale_factor))
473 {
474 if(out_path) *out_path = g_strdup(path);
475 loaded = TRUE;
476 }
477 }
478 }
479
480 if(!loaded)
481 {
482 gtk_image_set_from_icon_name(GTK_IMAGE(image), "ansel", GTK_ICON_SIZE_DIALOG);
483 gtk_image_set_pixel_size(GTK_IMAGE(image), target_size);
484 }
485
486 g_ptr_array_free(paths, TRUE);
487 return image;
488}
489
491{
493
494 GtkWidget *scale_widget = splash->window ? splash->window : splash->logo;
495 int scale_factor = gtk_widget_get_scale_factor(scale_widget);
496 if(scale_factor < 1) scale_factor = 1;
497 if(scale_factor == splash->logo_scale_factor) return;
498
499 const int target_size = 128;
500 if(_splash_logo_set_from_path(splash->logo, splash->logo_path, target_size, scale_factor))
501 splash->logo_scale_factor = scale_factor;
502}
503
504static void _splash_scale_factor_changed(GObject *object, GParamSpec *pspec, gpointer user_data)
505{
506 (void)object;
507 (void)pspec;
508 (void)user_data;
510}
511
513{
514 if(splash) return;
515 if(_splash_is_disabled()) return;
516
517 splash = calloc(1, sizeof(dt_splash_t));
518 splash->authors = g_ptr_array_new_with_free_func(g_free);
519 splash->slides = g_ptr_array_new_with_free_func(_splash_slide_free);
521 splash->shown = FALSE;
522
525
526 splash->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
527 gtk_window_set_decorated(GTK_WINDOW(splash->window), FALSE);
528 gtk_window_set_resizable(GTK_WINDOW(splash->window), FALSE);
529 gtk_window_set_position(GTK_WINDOW(splash->window), GTK_WIN_POS_CENTER);
530 gtk_window_set_type_hint(GTK_WINDOW(splash->window), GDK_WINDOW_TYPE_HINT_SPLASHSCREEN);
531 gtk_window_set_keep_above(GTK_WINDOW(splash->window), TRUE);
532 gtk_window_set_default_size(GTK_WINDOW(splash->window), 960, 600);
533 gtk_widget_set_app_paintable(splash->window, TRUE);
534 gtk_widget_set_name(splash->window, "ansel-splash");
535 g_signal_connect(G_OBJECT(splash->window), "notify::scale-factor",
536 G_CALLBACK(_splash_scale_factor_changed), NULL);
537
538 GtkWidget *overlay = gtk_overlay_new();
539 gtk_container_add(GTK_CONTAINER(splash->window), overlay);
540
541 splash->drawing = gtk_drawing_area_new();
542 gtk_widget_set_hexpand(splash->drawing, TRUE);
543 gtk_widget_set_vexpand(splash->drawing, TRUE);
544 gtk_widget_set_name(splash->drawing, "splash-background");
545 gtk_container_add(GTK_CONTAINER(overlay), splash->drawing);
546 g_signal_connect(G_OBJECT(splash->drawing), "draw", G_CALLBACK(_splash_draw), NULL);
547
548 GtkWidget *info_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
549 gtk_widget_set_name(info_box, "splash-info");
550 gtk_widget_set_halign(info_box, GTK_ALIGN_START);
551 gtk_widget_set_valign(info_box, GTK_ALIGN_END);
552 gtk_overlay_add_overlay(GTK_OVERLAY(overlay), info_box);
553
554 GtkWidget *header = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
555 gtk_widget_set_name(header, "splash-header");
556 gtk_box_pack_start(GTK_BOX(info_box), header, FALSE, FALSE, 0);
557
559 splash->logo_path = NULL;
561 if(splash->logo)
562 {
563 gtk_widget_set_name(splash->logo, "splash-logo");
564 gtk_widget_set_size_request(splash->logo, 128, 128);
565 gtk_widget_set_halign(splash->logo, GTK_ALIGN_START);
566 gtk_widget_set_valign(splash->logo, GTK_ALIGN_START);
567 gtk_box_pack_start(GTK_BOX(header), splash->logo, FALSE, FALSE, 0);
568 }
569
570 GtkWidget *title_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
571 gtk_widget_set_name(title_box, "splash-title-box");
572 gtk_box_pack_start(GTK_BOX(header), title_box, FALSE, FALSE, 0);
573
574 gchar *app_name = _splash_capitalize_name(PACKAGE_NAME);
575 GtkWidget *title_fixed = _splash_shadow_label_new(app_name, "splash-title", "splash-title-shadow", NULL);
576 dt_free(app_name);
577 gtk_box_pack_start(GTK_BOX(title_box), title_fixed, FALSE, FALSE, 0);
578
579 GtkWidget *version_fixed = _splash_shadow_label_new(darktable_package_string, "splash-version",
580 "splash-version-shadow", NULL);
581 gtk_box_pack_start(GTK_BOX(title_box), version_fixed, FALSE, FALSE, 0);
582
583 gchar *authors_line = _splash_build_author_list(5);
584 GtkWidget *authors_fixed = _splash_shadow_label_new(authors_line, "splash-authors", "splash-authors-shadow", NULL);
585 dt_free(authors_line);
586 gtk_box_pack_start(GTK_BOX(title_box), authors_fixed, FALSE, FALSE, 0);
587
588 GtkWidget *ticker_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
589 gtk_widget_set_name(ticker_box, "splash-ticker");
590 gtk_widget_set_halign(ticker_box, GTK_ALIGN_FILL);
591 gtk_widget_set_valign(ticker_box, GTK_ALIGN_END);
592 gtk_widget_set_hexpand(ticker_box, TRUE);
593 gtk_widget_set_size_request(ticker_box, -1, 28);
594 gtk_overlay_add_overlay(GTK_OVERLAY(overlay), ticker_box);
595
596 GtkWidget *message_fixed = _splash_shadow_label_new(_("Starting..."), "splash-message",
597 "splash-message-shadow",
599 gtk_box_pack_start(GTK_BOX(ticker_box), message_fixed, FALSE, FALSE, 0);
600
601 splash->css = gtk_css_provider_new();
603 "#ansel-splash {"
604 " background-color: #777777;"
605 "}"
606 "#splash-info {"
607 " background-color: transparent;"
608 " background-image: none;"
609 " box-shadow: none;"
610 " margin: 12px 0;"
611 " padding: 12px 0;"
612 " -GtkBox-spacing: 12px;"
613 "}"
614 "#splash-header {"
615 " -GtkBox-spacing: 12px;"
616 " margin: 12px 0;"
617 " padding: 12px 0;"
618 "}"
619 "#splash-title-box {"
620 " -GtkBox-spacing: 12px;"
621 " padding-top: 18px;"
622 "}"
623 "#splash-logo {"
624 " padding: 0;"
625 " margin: 0;"
626 "}"
627 "#splash-title {"
628 " color: #f2f2f2;"
629 " font: 700 40px \"Roboto\";"
630 "}"
631 "#splash-title-shadow {"
632 " color: rgba(0,0,0,0.75);"
633 " font: 700 40px \"Roboto\";"
634 "}"
635 "#splash-version {"
636 " color: rgb(255,255,255);"
637 " font: 16px \"Roboto\";"
638 "}"
639 "#splash-version-shadow {"
640 " color: rgba(0,0,0,0.75);"
641 " font: 16px \"Roboto\";"
642 "}"
643 "#splash-message {"
644 " color: rgba(255,255,255,0.9);"
645 " font: 16px \"Roboto\";"
646 "}"
647 "#splash-message-shadow {"
648 " color: rgba(0,0,0,0.75);"
649 " font: 16px \"Roboto\";"
650 "}"
651 "#splash-ticker {"
652 " background: transparent;"
653 " padding: 24px;"
654 " background-image: none;"
655 " box-shadow: none;"
656 " margin: 0;"
657 "}"
658 "#splash-authors {"
659 " color: rgba(255,255,255,0.92);"
660 " font: 16px \"Roboto\";"
661 " margin: 6px 0;"
662 "}"
663 "#splash-authors-shadow {"
664 " color: rgba(0,0,0,0.75);"
665 " font: 16px \"Roboto\";"
666 " margin: 6px 0;"
667 "}"
668 );
669
670 GdkScreen *screen = gdk_screen_get_default();
671 if(screen)
672 gtk_style_context_add_provider_for_screen(screen, GTK_STYLE_PROVIDER(splash->css),
673 GTK_STYLE_PROVIDER_PRIORITY_USER + 2);
674
677
678 splash->slide_timeout_id = g_timeout_add(4000, _splash_slide_advance, NULL);
679}
680
681void dt_gui_splash_update(const char *message)
682{
683 if(IS_NULL_PTR(splash) || IS_NULL_PTR(message)) return;
684 _splash_update_message(message);
685}
686
687void dt_gui_splash_updatef(const char *format, ...)
688{
689 if(IS_NULL_PTR(splash) || IS_NULL_PTR(format)) return;
690 va_list ap;
691 va_start(ap, format);
692 gchar *buf = g_strdup_vprintf(format, ap);
693 va_end(ap);
695 dt_free(buf);
696}
697
699{
700 if(IS_NULL_PTR(splash)) return;
701
702 if(splash->slide_timeout_id) g_source_remove(splash->slide_timeout_id);
703
704 gtk_widget_destroy(splash->window);
705 GdkScreen *screen = gdk_screen_get_default();
706 if(screen)
707 gtk_style_context_remove_provider_for_screen(screen, GTK_STYLE_PROVIDER(splash->css));
708 g_object_unref(splash->css);
709
710 g_ptr_array_free(splash->authors, TRUE);
711 g_ptr_array_free(splash->slides, TRUE);
714
716}
717
718// clang-format off
719// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
720// vim: shiftwidth=2 expandtab tabstop=2 cindent
721// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
722// clang-format on
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))
static const float x
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
const dt_colormatrix_t dt_aligned_pixel_t out
#define PACKAGE_NAME
const char darktable_package_string[]
void dt_loc_get_sharedir(char *sharedir, size_t bufsize)
void dt_loc_get_datadir(char *datadir, size_t bufsize)
#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
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
const char * name
Definition pdf.h:90
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
static void _splash_load_slides(void)
Definition splash.c:368
static gboolean _splash_slide_advance(gpointer user_data)
Definition splash.c:329
static GtkWidget * _splash_create_logo(int target_size, int scale_factor, gchar **out_path)
Definition splash.c:447
static void _splash_clear_slide_cache(void)
Definition splash.c:105
static gchar * _splash_build_author_list(guint max_names)
Definition splash.c:132
void dt_gui_splash_init(void)
Definition splash.c:512
static dt_splash_slide_t * _splash_slide_new(const gchar *path, const gchar *author)
Definition splash.c:210
static void _splash_load_authors(void)
Definition splash.c:339
static gboolean _splash_is_disabled(void)
Definition splash.c:74
static gchar * _splash_build_data_path(const char *subpath)
Definition splash.c:125
static void _splash_slide_free(gpointer data)
Definition splash.c:218
void dt_gui_splash_updatef(const char *format,...)
Definition splash.c:687
static void _splash_add_css(const char *data)
Definition splash.c:119
static GtkWidget * _splash_shadow_label_new(const gchar *text, const gchar *name, const gchar *shadow_name, GtkWidget **out_main)
Definition splash.c:158
static gboolean _splash_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
Definition splash.c:227
static gboolean _splash_env_is_truthy(const char *value)
Definition splash.c:63
static void _splash_force_show(void)
Definition splash.c:89
void dt_gui_splash_update(const char *message)
Definition splash.c:681
static gchar * _splash_capitalize_name(const char *name)
Definition splash.c:416
void dt_gui_splash_set_transient_for(GtkWidget *parent)
Definition splash.c:82
static void _splash_update_message(const gchar *message)
Definition splash.c:405
static void _splash_scale_factor_changed(GObject *object, GParamSpec *pspec, gpointer user_data)
Definition splash.c:504
void dt_gui_splash_close(void)
Definition splash.c:698
static dt_splash_t * splash
Definition splash.c:61
static gboolean _splash_logo_set_from_path(GtkWidget *logo, const char *path, int target_size, int scale_factor)
Definition splash.c:424
static void _splash_update_logo_for_scale(void)
Definition splash.c:490
static void _splash_shadow_label_set_text(GtkWidget *label, const gchar *text)
Definition splash.c:201
gchar * path
Definition splash.c:57
gchar * author
Definition splash.c:58
GtkWidget * logo
Definition splash.c:38
int logo_scale_factor
Definition splash.c:40
GdkPixbuf * slide_pixbuf
Definition splash.c:41
GtkWidget * drawing
Definition splash.c:36
gchar * logo_path
Definition splash.c:39
GtkWidget * window
Definition splash.c:35
int slide_cache_height
Definition splash.c:43
GPtrArray * slides
Definition splash.c:50
gint current_slide
Definition splash.c:51
int slide_cache_scale
Definition splash.c:44
gboolean shown
Definition splash.c:46
GPtrArray * authors
Definition splash.c:49
int slide_cache_index
Definition splash.c:45
guint slide_timeout_id
Definition splash.c:52
GtkCssProvider * css
Definition splash.c:47
GtkWidget * label_message
Definition splash.c:37
int slide_cache_width
Definition splash.c:42
#define DT_GUI_BOX_SPACING