1 /*
2 This file is part of darktable,
3 Copyright (C) 2011-2020 darktable developers.
4
5 darktable 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 darktable 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 darktable. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "common/darktable.h"
20 #include "common/debug.h"
21 #include "common/file_location.h"
22 #include "common/image_cache.h"
23 #include "control/conf.h"
24 #include "control/control.h"
25 #include "develop/develop.h"
26 #include "dtgtk/thumbtable.h"
27 #include "gui/gtk.h"
28 #include "libs/lib.h"
29 #include "libs/lib_api.h"
30 #ifdef GDK_WINDOWING_QUARTZ
31 #include "osx/osx.h"
32 #endif
33
34 #include <librsvg/rsvg.h>
35 // ugh, ugly hack. why do people break stuff all the time?
36 #ifndef RSVG_CAIRO_H
37 #include <librsvg/rsvg-cairo.h>
38 #endif
39
40 DT_MODULE(1)
41
42
43 typedef struct dt_lib_darktable_t
44 {
45 // logo
46 cairo_surface_t *image;
47 guint8 *image_buffer;
48 int image_width, image_height;
49 // text with logo font
50 cairo_surface_t *text;
51 int text_width, text_height;
52 } dt_lib_darktable_t;
53
54
55 /* expose function for darktable module */
56 static gboolean _lib_darktable_draw_callback(GtkWidget *widget, cairo_t *cr, gpointer user_data);
57 /* button press callback */
58 static gboolean _lib_darktable_button_press_callback(GtkWidget *widget, GdkEventButton *event,
59 gpointer user_data);
60 /* show the about dialog */
61 static void _lib_darktable_show_about_dialog();
62
name(dt_lib_module_t * self)63 const char *name(dt_lib_module_t *self)
64 {
65 return _("darktable");
66 }
67
views(dt_lib_module_t * self)68 const char **views(dt_lib_module_t *self)
69 {
70 static const char *v[] = {"*", NULL};
71 return v;
72 }
73
container(dt_lib_module_t * self)74 uint32_t container(dt_lib_module_t *self)
75 {
76 return DT_UI_CONTAINER_PANEL_TOP_LEFT;
77 }
78
expandable(dt_lib_module_t * self)79 int expandable(dt_lib_module_t *self)
80 {
81 return 0;
82 }
83
position()84 int position()
85 {
86 return 1001;
87 }
88
gui_init(dt_lib_module_t * self)89 void gui_init(dt_lib_module_t *self)
90 {
91 /* initialize ui widgets */
92 dt_lib_darktable_t *d = (dt_lib_darktable_t *)g_malloc0(sizeof(dt_lib_darktable_t));
93 self->data = (void *)d;
94
95 /* create drawing area */
96 self->widget = gtk_event_box_new();
97
98 /* connect callbacks */
99 g_signal_connect(G_OBJECT(self->widget), "draw", G_CALLBACK(_lib_darktable_draw_callback), self);
100 g_signal_connect(G_OBJECT(self->widget), "button-press-event",
101 G_CALLBACK(_lib_darktable_button_press_callback), self);
102
103 /* create a cairo surface of dt icon */
104
105 // first we try the SVG
106 d->image = dt_util_get_logo(DT_PIXEL_APPLY_DPI(-1.0));
107 if(d->image)
108 d->image_buffer = cairo_image_surface_get_data(d->image);
109 else
110 {
111 // let's fall back to the PNG
112 char *logo;
113 char datadir[PATH_MAX] = { 0 };
114
115 dt_loc_get_datadir(datadir, sizeof(datadir));
116 const dt_logo_season_t season = dt_util_get_logo_season();
117 if(season != DT_LOGO_SEASON_NONE)
118 logo = g_strdup_printf("idbutton-%d.png", (int)season);
119 else
120 logo = g_strdup("idbutton.png");
121 char *filename = g_build_filename(datadir, "pixmaps", logo, NULL);
122
123 cairo_surface_t *surface = cairo_image_surface_create_from_png(filename);
124 g_free(logo);
125 if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
126 {
127 fprintf(stderr, "warning: can't load darktable logo from PNG file `%s'\n", filename);
128 goto done;
129 }
130 const int png_width = cairo_image_surface_get_width(surface),
131 png_height = cairo_image_surface_get_height(surface);
132
133 // blow up the PNG. Ugly, but at least it has the correct size afterwards :-/
134 const int width = DT_PIXEL_APPLY_DPI(png_width) * darktable.gui->ppd,
135 height = DT_PIXEL_APPLY_DPI(png_height) * darktable.gui->ppd;
136 const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
137
138 d->image_buffer = (guint8 *)calloc((size_t)stride * height, sizeof(guint8));
139 d->image
140 = dt_cairo_image_surface_create_for_data(d->image_buffer, CAIRO_FORMAT_ARGB32, width, height, stride);
141 if(cairo_surface_status(d->image) != CAIRO_STATUS_SUCCESS)
142 {
143 fprintf(stderr, "warning: can't load darktable logo from PNG file `%s'\n", filename);
144 free(d->image_buffer);
145 d->image_buffer = NULL;
146 cairo_surface_destroy(d->image);
147 d->image = NULL;
148 goto done;
149 }
150
151 cairo_t *cr = cairo_create(d->image);
152 cairo_rectangle(cr, 0, 0, width, height);
153 cairo_scale(cr, darktable.gui->dpi_factor, darktable.gui->dpi_factor);
154 cairo_set_source_surface(cr, surface, 0, 0);
155 cairo_fill(cr);
156 cairo_destroy(cr);
157 cairo_surface_flush(d->image);
158
159 done:
160 cairo_surface_destroy(surface);
161 g_free(filename);
162 }
163
164 d->image_width = d->image ? dt_cairo_image_surface_get_width(d->image) : 0;
165 d->image_height = d->image ? dt_cairo_image_surface_get_height(d->image) : 0;
166
167 /* try to load program name as svg */
168 d->text = dt_util_get_logo_text(DT_PIXEL_APPLY_DPI(-1.0));
169 /* no png fallback, we'll use text */
170 d->text_width = d->text ? dt_cairo_image_surface_get_width(d->text) : 0;
171 d->text_height = d->text ? dt_cairo_image_surface_get_height(d->text) : 0;
172
173 /* set size of drawing area */
174 gtk_widget_set_size_request(self->widget, d->image_width + (int)DT_PIXEL_APPLY_DPI(180),
175 d->image_height + (int)DT_PIXEL_APPLY_DPI(8));
176 }
177
gui_cleanup(dt_lib_module_t * self)178 void gui_cleanup(dt_lib_module_t *self)
179 {
180 dt_lib_darktable_t *d = (dt_lib_darktable_t *)self->data;
181 cairo_surface_destroy(d->image);
182 free(d->image_buffer);
183
184 // don't leak mem via text logo surface data
185 guint8 *text_img_buffer = NULL;
186 if(d->text)
187 text_img_buffer = cairo_image_surface_get_data(d->text);
188 cairo_surface_destroy(d->text);
189 free(text_img_buffer);
190 g_free(self->data);
191 self->data = NULL;
192 }
193
194
195
_lib_darktable_draw_callback(GtkWidget * widget,cairo_t * cr,gpointer user_data)196 static gboolean _lib_darktable_draw_callback(GtkWidget *widget, cairo_t *cr, gpointer user_data)
197 {
198 dt_lib_module_t *self = (dt_lib_module_t *)user_data;
199 dt_lib_darktable_t *d = (dt_lib_darktable_t *)self->data;
200
201 GtkStyleContext *context = gtk_widget_get_style_context(widget);
202
203 GtkAllocation allocation;
204 gtk_widget_get_allocation(widget, &allocation);
205 gtk_render_background(context, cr, 0, 0, allocation.width, allocation.height);
206
207 // Get the normal foreground color from the CSS stylesheet
208 GdkRGBA *tmpcolor;
209 gtk_style_context_get(context, GTK_STATE_FLAG_NORMAL, "color", &tmpcolor, NULL);
210
211 GtkStateFlags state = gtk_widget_get_state_flags(widget);
212
213 PangoFontDescription *font_desc = NULL;
214 gtk_style_context_get(context, state, "font", &font_desc, NULL);
215
216 /* paint icon image */
217 if(d->image)
218 {
219 cairo_set_source_surface(cr, d->image, 0, (int)DT_PIXEL_APPLY_DPI(7));
220 cairo_rectangle(cr, 0, 0, d->image_width + (int)DT_PIXEL_APPLY_DPI(8),
221 d->image_height + (int)DT_PIXEL_APPLY_DPI(8));
222 cairo_fill(cr);
223 }
224
225 /* create a pango layout and print fancy name/version string */
226 PangoLayout *layout;
227 layout = gtk_widget_create_pango_layout(widget, NULL);
228
229 /* try to use logo text in svg */
230 if(d->text)
231 {
232 cairo_set_source_surface(cr, d->text, d->image_width + (int)DT_PIXEL_APPLY_DPI(5),
233 (int)DT_PIXEL_APPLY_DPI(12));
234 cairo_rectangle(cr, 0, 0, d->image_width + d->text_width + (int)DT_PIXEL_APPLY_DPI(11),
235 d->text_height + (int)DT_PIXEL_APPLY_DPI(13));
236 cairo_fill(cr);
237 }
238 else
239 {
240 /* fallback using normal text */
241 pango_font_description_set_weight(font_desc, PANGO_WEIGHT_BOLD);
242 pango_font_description_set_absolute_size(font_desc, DT_PIXEL_APPLY_DPI(25) * PANGO_SCALE);
243
244 pango_layout_set_font_description(layout, font_desc);
245
246 pango_layout_set_text(layout, PACKAGE_NAME, -1);
247 cairo_set_source_rgba(cr, tmpcolor->red, tmpcolor->green, tmpcolor->blue, 0.7);
248 cairo_move_to(cr, d->image_width + DT_PIXEL_APPLY_DPI(3.0), DT_PIXEL_APPLY_DPI(5.0));
249 pango_cairo_show_layout(cr, layout);
250 }
251
252 /* print version */
253 pango_font_description_set_absolute_size(font_desc, DT_PIXEL_APPLY_DPI(10) * PANGO_SCALE);
254 pango_layout_set_font_description(layout, font_desc);
255 pango_layout_set_text(layout, darktable_package_version, -1);
256 cairo_move_to(cr, d->image_width + DT_PIXEL_APPLY_DPI(4.0), DT_PIXEL_APPLY_DPI(32.0));
257 cairo_set_source_rgba(cr, tmpcolor->red, tmpcolor->green, tmpcolor->blue, 0.3);
258 pango_cairo_show_layout(cr, layout);
259
260 /* cleanup */
261 gdk_rgba_free(tmpcolor);
262 g_object_unref(layout);
263 pango_font_description_free(font_desc);
264
265 return TRUE;
266 }
267
_lib_darktable_button_press_callback(GtkWidget * widget,GdkEventButton * event,gpointer user_data)268 static gboolean _lib_darktable_button_press_callback(GtkWidget *widget, GdkEventButton *event,
269 gpointer user_data)
270 {
271 /* show about box */
272 _lib_darktable_show_about_dialog();
273 return TRUE;
274 }
275
_lib_darktable_show_about_dialog()276 static void _lib_darktable_show_about_dialog()
277 {
278 GtkWidget *dialog = gtk_about_dialog_new();
279 gtk_widget_set_name (dialog, "about_dialog");
280 #ifdef GDK_WINDOWING_QUARTZ
281 dt_osx_disallow_fullscreen(dialog);
282 #endif
283 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), PACKAGE_NAME);
284 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), darktable_package_version);
285 char *copyright = g_strdup_printf(_("copyright (c) the authors 2009-%s"), darktable_last_commit_year);
286 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), copyright);
287 g_free(copyright);
288 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog),
289 _("organize and develop images from digital cameras"));
290 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "https://www.darktable.org/");
291 gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog), "website");
292 dt_logo_season_t season = dt_util_get_logo_season();
293 char *icon;
294 if(season != DT_LOGO_SEASON_NONE)
295 icon = g_strdup_printf("darktable-%d", (int)season);
296 else
297 icon = g_strdup("darktable");
298 gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(dialog), icon);
299 g_free(icon);
300
301 const char *str = _("all those of you that made previous releases possible");
302
303 #include "tools/darktable_authors.h"
304
305 const char *final[] = {str, NULL };
306 gtk_about_dialog_add_credit_section (GTK_ABOUT_DIALOG(dialog), _("and..."), final);
307
308 gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(dialog), _("translator-credits"));
309
310 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)));
311 gtk_dialog_run(GTK_DIALOG(dialog));
312 gtk_widget_destroy(dialog);
313 }
314 // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
315 // vim: shiftwidth=2 expandtab tabstop=2 cindent
316 // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
317