1 /* Exif-display -- display information about digital pictures
2 *
3 * Copyright (C) 2009 The Free Software Foundation
4 *
5 * Author: Emmanuel Touzery <emmanuel.touzery@free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <gtk/gtk.h>
27
28 #include <glib/gi18n-lib.h>
29 #include <eog/eog-debug.h>
30
31 // TODO: This is not cool. We need to find a better way to organize the API.
32 #ifndef HAVE_EXIF
33 #define HAVE_EXIF 1
34 #endif
35 #include <eog/eog-image.h>
36
37 #include <eog/eog-thumb-view.h>
38 #include <eog/eog-job-scheduler.h>
39 #include <eog/eog-exif-util.h>
40 #include <eog/eog-sidebar.h>
41 #include <eog/eog-window-activatable.h>
42
43 #include "eog-exif-display-plugin-settings.h"
44 #include "eog-exif-display-plugin-setup.h"
45 #include "eog-exif-display-plugin.h"
46
47 #define GRESOURCE_PATH "/org/gnome/eog/plugins/exif-display/exif-display.ui"
48
49 enum {
50 PROP_O,
51 PROP_DRAW_CHAN_HISTOGRAM,
52 PROP_DRAW_RGB_HISTOGRAM,
53 PROP_ENABLE_STATUSBAR,
54 PROP_WINDOW
55 };
56
57 static void
58 eog_window_activatable_iface_init (EogWindowActivatableInterface *iface);
59
60 G_DEFINE_DYNAMIC_TYPE_EXTENDED (EogExifDisplayPlugin, eog_exif_display_plugin,
61 PEAS_TYPE_EXTENSION_BASE, 0,
62 G_IMPLEMENT_INTERFACE_DYNAMIC(EOG_TYPE_WINDOW_ACTIVATABLE,
63 eog_window_activatable_iface_init))
64
65 static void
eog_exif_display_plugin_init(EogExifDisplayPlugin * plugin)66 eog_exif_display_plugin_init (EogExifDisplayPlugin *plugin)
67 {
68 }
69
70 /* eog_util_make_valid_utf8 is not exported so it's duped here */
71 gchar *
_eog_util_make_valid_utf8(const gchar * str)72 _eog_util_make_valid_utf8 (const gchar *str)
73 {
74 GString *string;
75 const char *remainder, *invalid;
76 int remaining_bytes, valid_bytes;
77
78 string = NULL;
79 remainder = str;
80 remaining_bytes = strlen (str);
81
82 while (remaining_bytes != 0) {
83 if (g_utf8_validate (remainder, remaining_bytes, &invalid)) {
84 break;
85 }
86
87 valid_bytes = invalid - remainder;
88
89 if (string == NULL) {
90 string = g_string_sized_new (remaining_bytes);
91 }
92
93 g_string_append_len (string, remainder, valid_bytes);
94 g_string_append_c (string, '?');
95
96 remaining_bytes -= valid_bytes + 1;
97 remainder = invalid + 1;
98 }
99
100 if (string == NULL) {
101 return g_strdup (str);
102 }
103
104 g_string_append (string, remainder);
105 g_string_append (string, _(" (invalid Unicode)"));
106
107 g_assert (g_utf8_validate (string->str, -1, NULL));
108
109 return g_string_free (string, FALSE);
110 }
111
112 /* stolen from eog-properties-dialog.c*/
113 static void
eog_exif_set_label(GtkWidget * w,ExifData * exif_data,gint tag_id)114 eog_exif_set_label (GtkWidget *w, ExifData *exif_data, gint tag_id)
115 {
116 gchar exif_buffer[512];
117 const gchar *buf_ptr;
118 gchar *label_text = NULL;
119
120 if (exif_data) {
121 buf_ptr = eog_exif_data_get_value (exif_data, tag_id,
122 exif_buffer, 512);
123
124 if (tag_id == EXIF_TAG_DATE_TIME_ORIGINAL && buf_ptr)
125 label_text = eog_exif_util_format_date (buf_ptr);
126 else
127 label_text = _eog_util_make_valid_utf8 (buf_ptr);
128 }
129
130 gtk_label_set_text (GTK_LABEL (w), label_text);
131 g_free (label_text);
132 }
133
set_exif_label(ExifData * exif_data,int exif_tag,GtkBuilder * gtk_builder,const gchar * gtk_builder_label_name,gboolean tooltip)134 static void set_exif_label (ExifData *exif_data, int exif_tag,
135 GtkBuilder *gtk_builder,
136 const gchar *gtk_builder_label_name,
137 gboolean tooltip)
138 {
139 GtkWidget *widget = GTK_WIDGET (gtk_builder_get_object (
140 gtk_builder, gtk_builder_label_name));
141 eog_exif_set_label (widget, exif_data, exif_tag);
142
143 if (tooltip) {
144 gtk_widget_set_tooltip_text (widget, gtk_label_get_label (GTK_LABEL (widget)));
145 }
146 }
147
148 /* stolen from eog-properties-dialog and slightly modified
149 * you must g_free () the gchar* that I return!
150 * */
151 static gchar*
eog_exif_get_focal_length_desc(ExifData * exif_data)152 eog_exif_get_focal_length_desc (ExifData *exif_data)
153 {
154 ExifEntry *entry = NULL, *entry35mm = NULL;
155 ExifByteOrder byte_order;
156 gfloat f_val = 0.0;
157 gchar *fl_text = NULL,*fl35_text = NULL;
158 gchar *result;
159
160 /* If no ExifData is supplied the label will be
161 * cleared later as fl35_text is NULL. */
162 if (exif_data != NULL) {
163 entry = exif_data_get_entry (exif_data, EXIF_TAG_FOCAL_LENGTH);
164 entry35mm = exif_data_get_entry (exif_data,
165 EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM);
166 byte_order = exif_data_get_byte_order (exif_data);
167 }
168
169 if (entry && G_LIKELY (entry->format == EXIF_FORMAT_RATIONAL)) {
170 ExifRational value;
171
172 /* Decode value by hand as libexif is not necessarily returning
173 * it in the format we want it to be.
174 */
175 value = exif_get_rational (entry->data, byte_order);
176 /* Guard against div by zero */
177 if (G_LIKELY(value.denominator != 0))
178 f_val = (gfloat)value.numerator/
179 (gfloat)value.denominator;
180
181 /* TRANSLATORS: This is the actual focal length used when
182 the image was taken.*/
183 fl_text = g_strdup_printf (_("%.1fmm (lens)"), f_val);
184
185 }
186 if (entry35mm && G_LIKELY (entry35mm->format == EXIF_FORMAT_SHORT)) {
187 ExifShort s_val;
188
189 s_val = exif_get_short (entry35mm->data, byte_order);
190
191 /* Print as float to get a similar look as above. */
192 /* TRANSLATORS: This is the equivalent focal length assuming
193 a 35mm film camera. */
194 fl35_text = g_strdup_printf(_("%.1fmm (35mm film)"),(float)s_val);
195 }
196 if (fl_text) {
197 if (fl35_text) {
198 result = g_strconcat (fl35_text,", ", fl_text, NULL);
199
200 g_free (fl35_text);
201 g_free (fl_text);
202
203 } else {
204 result = fl_text;
205 g_free (fl35_text);
206 }
207 } else {
208 result = fl35_text;
209 g_free (fl_text);
210 }
211
212 return result;
213 }
214
215 /* stolen from eog-properties-dialog and modified */
216 static void
eog_exif_set_focal_length_label(GtkWidget * w,ExifData * exif_data)217 eog_exif_set_focal_length_label (GtkWidget *w, ExifData *exif_data)
218 {
219 gchar *focal_length_desc = eog_exif_get_focal_length_desc (exif_data);
220 gtk_label_set_text (GTK_LABEL (w), focal_length_desc);
221
222 g_free (focal_length_desc);
223 }
224
manage_exif_data(EogExifDisplayPlugin * plugin)225 static void manage_exif_data (EogExifDisplayPlugin *plugin)
226 {
227 EogImage *image;
228 ExifData *exif_data;
229
230 image = eog_thumb_view_get_first_selected_image (plugin->thumbview);
231 g_return_if_fail (image != NULL);
232
233 exif_data = (ExifData *)eog_image_get_exif_info (image);
234
235 set_exif_label (exif_data, EXIF_TAG_DATE_TIME_ORIGINAL, plugin->sidebar_builder, "takenon_label", TRUE);
236
237 eog_exif_set_focal_length_label (GTK_WIDGET (gtk_builder_get_object (
238 plugin->sidebar_builder, "focal_length_label")), exif_data);
239
240 set_exif_label (exif_data, EXIF_TAG_EXPOSURE_BIAS_VALUE,
241 plugin->sidebar_builder, "exposure_bias_label", FALSE);
242
243 set_exif_label (exif_data, EXIF_TAG_EXPOSURE_TIME,
244 plugin->sidebar_builder, "exposure_time_label", FALSE);
245
246 set_exif_label (exif_data, EXIF_TAG_MODEL,
247 plugin->sidebar_builder, "camera_model_label", FALSE);
248
249 set_exif_label (exif_data, EXIF_TAG_FNUMBER,
250 plugin->sidebar_builder, "aperture_label", FALSE);
251
252 set_exif_label (exif_data, EXIF_TAG_ISO_SPEED_RATINGS,
253 plugin->sidebar_builder, "iso_label", FALSE);
254
255 set_exif_label (exif_data, EXIF_TAG_FLASH,
256 plugin->sidebar_builder, "flash_label", TRUE);
257
258 set_exif_label (exif_data, EXIF_TAG_METERING_MODE,
259 plugin->sidebar_builder, "metering_mode_label", TRUE);
260
261 set_exif_label (exif_data, EXIF_TAG_USER_COMMENT,
262 plugin->sidebar_builder, "desc_label", TRUE);
263
264 set_exif_label (exif_data, EXIF_TAG_EXPOSURE_BIAS_VALUE,
265 plugin->sidebar_builder, "exposure_bias_label", FALSE);
266
267 exif_data_unref (exif_data);
268
269 g_object_unref (image);
270 }
271
manage_exif_data_cb(EogJob * job,gpointer data)272 static void manage_exif_data_cb (EogJob *job, gpointer data)
273 {
274 if (!job->error) {
275 manage_exif_data (EOG_EXIF_DISPLAY_PLUGIN(data));
276 }
277 }
278
279 static gboolean
calculate_histogram(EogExifDisplayPlugin * plugin,EogImage * eog_image)280 calculate_histogram (EogExifDisplayPlugin *plugin, EogImage *eog_image)
281 {
282 int rowstride;
283 int width, height;
284 int row, col;
285 GdkPixbuf *image_pixbuf;
286 guchar *pixels;
287 int array_sums_elt = 0;
288
289 /* for the red when we calculate we store
290 * the values in a temporary array.
291 * only when everything is calculated
292 * we copy the pointers to the real
293 * plugin->histogram_values_red.
294 * That way we'll try to display
295 * the histogram only once it's fully
296 * calculated.*/
297 int *histogram_values_red_temp;
298
299 if (eog_image == NULL) {
300 return FALSE;
301 }
302
303 g_free (plugin->histogram_values_red);
304 plugin->histogram_values_red = NULL;
305
306 g_free (plugin->histogram_values_green);
307 plugin->histogram_values_green = NULL;
308
309 g_free (plugin->histogram_values_blue);
310 plugin->histogram_values_blue = NULL;
311
312 g_free (plugin->histogram_values_rgb);
313 plugin->histogram_values_rgb = NULL;
314
315 image_pixbuf = eog_image_get_pixbuf (eog_image);
316 if (image_pixbuf == NULL) {
317 return FALSE;
318 }
319
320 if ((gdk_pixbuf_get_colorspace (image_pixbuf) != GDK_COLORSPACE_RGB)
321 || (gdk_pixbuf_get_bits_per_sample (image_pixbuf) > 8)) {
322 g_object_unref (image_pixbuf);
323 return FALSE;
324 }
325
326 rowstride = gdk_pixbuf_get_rowstride (image_pixbuf);
327
328 width = gdk_pixbuf_get_width (image_pixbuf);
329 height = gdk_pixbuf_get_height (image_pixbuf);
330
331 pixels = gdk_pixbuf_get_pixels (image_pixbuf);
332
333 histogram_values_red_temp = g_new0 (int, 256);
334
335 plugin->histogram_values_green = g_new0 (int, 256);
336 plugin->histogram_values_blue = g_new0 (int, 256);
337 plugin->max_of_array_sums = 0;
338
339 plugin->histogram_values_rgb = g_new0 (int, 256);
340 plugin->max_of_array_sums_rgb = 0;
341
342 for (row = 0; row < height; row++) {
343 guchar *row_cur_idx = pixels + row*rowstride;
344 for (col = 0; col < width; col++) {
345 guchar red = *row_cur_idx++;
346 guchar green = *row_cur_idx++;
347 guchar blue = *row_cur_idx++;
348
349 histogram_values_red_temp[red] += 1;
350 plugin->histogram_values_green[green] += 1;
351 plugin->histogram_values_blue[blue] += 1;
352 plugin->histogram_values_rgb[MAX (red, MAX (green, blue))] += 1;
353 }
354 }
355 for (array_sums_elt=0;array_sums_elt<256;array_sums_elt++) {
356 if (histogram_values_red_temp[array_sums_elt] > plugin->max_of_array_sums) {
357 plugin->max_of_array_sums = histogram_values_red_temp[array_sums_elt];
358 }
359 if (plugin->histogram_values_green[array_sums_elt] > plugin->max_of_array_sums) {
360 plugin->max_of_array_sums = plugin->histogram_values_green[array_sums_elt];
361 }
362 if (plugin->histogram_values_blue[array_sums_elt] > plugin->max_of_array_sums) {
363 plugin->max_of_array_sums = plugin->histogram_values_blue[array_sums_elt];
364 }
365 }
366
367 for (array_sums_elt=0;array_sums_elt<256;array_sums_elt++) {
368 if (plugin->histogram_values_rgb[array_sums_elt] > plugin->max_of_array_sums_rgb) {
369 plugin->max_of_array_sums_rgb = plugin->histogram_values_rgb[array_sums_elt];
370 }
371 }
372
373 plugin->histogram_values_red = histogram_values_red_temp;
374
375 g_object_unref (image_pixbuf);
376
377 return TRUE;
378 }
379
380 static void
draw_histogram_graph(cairo_t * cr,int * histogram_values,int max_of_array_sums)381 draw_histogram_graph (cairo_t *cr, int *histogram_values, int max_of_array_sums)
382 {
383 int i;
384
385 cairo_move_to (cr, 0, 1);
386 for (i = 0; i < 256; i++) {
387 cairo_line_to (cr, ((float)i)/(256.0), 1.0 - ((float)histogram_values[i])/max_of_array_sums);
388 }
389 cairo_line_to (cr, 1, 1);
390 cairo_close_path (cr);
391 cairo_fill (cr);
392 }
393
394 static void
drawing_area_draw_cb(GtkDrawingArea * drawing_area,cairo_t * cr,EogExifDisplayPlugin * plugin)395 drawing_area_draw_cb (GtkDrawingArea *drawing_area, cairo_t *cr,
396 EogExifDisplayPlugin *plugin)
397 {
398 gboolean draw_channels_histogram, draw_rgb_histogram;
399 EogImage *eog_image;
400 gint drawing_area_width, drawing_area_height;
401 int scale_factor_y;
402 GtkStyleContext *style_ctx;
403
404 if (!gtk_widget_get_realized (GTK_WIDGET (drawing_area)))
405 return;
406
407 draw_channels_histogram = plugin->draw_chan_histogram;
408 draw_rgb_histogram = plugin->draw_rgb_histogram;
409
410 eog_image = eog_thumb_view_get_first_selected_image (plugin->thumbview);
411 g_return_if_fail (eog_image != NULL);
412
413 if (plugin->histogram_values_red == NULL) {
414 /* when calculate_histogram was called previously,
415 * the picture was not loaded yet.
416 * Now it's loaded, let's ask to calculate the
417 * histogram again... */
418 calculate_histogram (plugin, eog_image);
419 }
420
421 drawing_area_width = gtk_widget_get_allocated_width (GTK_WIDGET (drawing_area));
422 drawing_area_height = gtk_widget_get_allocated_height (GTK_WIDGET (drawing_area));
423
424 scale_factor_y = drawing_area_height;
425 if (scale_factor_y > drawing_area_width/2) {
426 /* histogram taller than it is wide looks ugly.
427 * it must be wider than it is tall for aesthetics.
428 */
429 scale_factor_y = drawing_area_width/2;
430 }
431 cairo_scale (cr, drawing_area_width, scale_factor_y);
432
433 /* clear the display */
434 style_ctx = gtk_widget_get_style_context (GTK_WIDGET (drawing_area));
435 gtk_render_background (style_ctx, cr, 0, 0,
436 drawing_area_width, drawing_area_height);
437
438 if (plugin->histogram_values_red == NULL) {
439 /* it's possible, if the image
440 * is not loaded and histogram
441 * can't be calculated, we go this
442 * far to clear the display.
443 * now exit, we won't draw any
444 * histogram without the data.
445 */
446 return;
447 }
448
449 if (draw_channels_histogram) {
450 cairo_set_source_rgba (cr, 1, 0, 0, 0.5);
451 draw_histogram_graph (cr, plugin->histogram_values_red,
452 plugin->max_of_array_sums);
453
454 cairo_set_source_rgba (cr, 0, 1, 0, 0.5);
455 draw_histogram_graph (cr, plugin->histogram_values_green,
456 plugin->max_of_array_sums);
457
458 cairo_set_source_rgba (cr, 0, 0, 1, 0.5);
459 draw_histogram_graph (cr, plugin->histogram_values_blue,
460 plugin->max_of_array_sums);
461 }
462 if (draw_rgb_histogram) {
463 cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
464 draw_histogram_graph (cr, plugin->histogram_values_rgb,
465 plugin->max_of_array_sums_rgb);
466 }
467
468 g_object_unref (eog_image);
469 }
470
calculate_histogram_cb(EogJob * job,gpointer data)471 static void calculate_histogram_cb (EogJob *job, gpointer data)
472 {
473 EogExifDisplayPlugin *plugin = EOG_EXIF_DISPLAY_PLUGIN (data);
474
475 if (!job->error) {
476 EogImage *eog_image =
477 eog_thumb_view_get_first_selected_image (plugin->thumbview);
478 calculate_histogram (plugin, eog_image);
479 g_object_unref (eog_image);
480 gtk_widget_queue_draw (GTK_WIDGET (plugin->drawing_area));
481 }
482 }
483
484 static void
statusbar_update_exif_data(GtkStatusbar * statusbar,EogThumbView * view)485 statusbar_update_exif_data (GtkStatusbar *statusbar, EogThumbView *view)
486 {
487 EogImage *image;
488 ExifData *exif_data;
489 gchar *exif_desc = NULL;
490
491 if (eog_thumb_view_get_n_selected (view) == 0)
492 return;
493
494 image = eog_thumb_view_get_first_selected_image (view);
495
496 gtk_statusbar_pop (statusbar, 0);
497
498 if (!eog_image_has_data (image, EOG_IMAGE_DATA_EXIF)) {
499 if (!eog_image_load (image, EOG_IMAGE_DATA_EXIF, NULL, NULL)) {
500 gtk_widget_hide (GTK_WIDGET (statusbar));
501 }
502 }
503
504 exif_data = (ExifData *) eog_image_get_exif_info (image);
505 if (exif_data) {
506 ExifEntry *exif_entry;
507 gchar exposition_time[512];
508 gchar aperture[512];
509 gchar iso[512];
510 gchar *focal_length;
511
512 exposition_time[0] = 0;
513 exif_entry = exif_data_get_entry (exif_data, EXIF_TAG_EXPOSURE_TIME);
514 exif_entry_get_value (exif_entry, exposition_time, sizeof(exposition_time));
515
516 aperture[0] = 0;
517 exif_entry = exif_data_get_entry (exif_data, EXIF_TAG_FNUMBER);
518 exif_entry_get_value (exif_entry, aperture, sizeof(aperture));
519
520 iso[0] = 0;
521 exif_entry = exif_data_get_entry (exif_data, EXIF_TAG_ISO_SPEED_RATINGS);
522 exif_entry_get_value (exif_entry, iso, sizeof(iso));
523
524 focal_length = eog_exif_get_focal_length_desc (exif_data);
525
526 exif_desc = g_strdup_printf ("ISO%s %s %s %s",
527 iso, exposition_time, aperture, focal_length);
528
529 g_free (focal_length);
530
531 exif_data_unref (exif_data);
532 }
533 g_object_unref (image);
534
535 if (exif_desc) {
536 gtk_statusbar_push (statusbar, 0, exif_desc);
537 gtk_widget_show (GTK_WIDGET (statusbar));
538 g_free (exif_desc);
539 } else {
540 gtk_widget_hide (GTK_WIDGET (statusbar));
541 }
542 }
543
544
545 static void
selection_changed_cb(EogThumbView * view,EogExifDisplayPlugin * plugin)546 selection_changed_cb (EogThumbView *view, EogExifDisplayPlugin *plugin)
547 {
548 EogImage *image;
549
550 if (!eog_thumb_view_get_n_selected (view)) {
551 return;
552 }
553
554 image = eog_thumb_view_get_first_selected_image (view);
555 g_return_if_fail (image != NULL);
556
557 if (plugin->enable_statusbar) {
558 statusbar_update_exif_data (GTK_STATUSBAR (plugin->statusbar_exif), view);
559 }
560
561 if (!eog_image_has_data (image, EOG_IMAGE_DATA_EXIF)) {
562 EogJob *job;
563
564 job = eog_job_load_new (image, EOG_IMAGE_DATA_EXIF);
565 g_signal_connect (G_OBJECT (job), "finished",
566 G_CALLBACK (manage_exif_data_cb),
567 plugin);
568 eog_job_scheduler_add_job (job);
569 g_object_unref (job);
570 } else {
571 manage_exif_data (plugin);
572 }
573
574 /* the selected image changed, the histogram must
575 * be recalculated. */
576 if (!eog_image_has_data (image, EOG_IMAGE_DATA_IMAGE)) {
577 EogJob *job;
578
579 job = eog_job_load_new (image, EOG_IMAGE_DATA_IMAGE);
580 g_signal_connect (G_OBJECT (job), "finished",
581 G_CALLBACK (calculate_histogram_cb),
582 plugin);
583 eog_job_scheduler_add_job (job);
584 g_object_unref (job);
585 }
586
587 g_object_unref (image);
588 }
589
590 static void
remove_statusbar_entry(EogExifDisplayPlugin * plugin)591 remove_statusbar_entry (EogExifDisplayPlugin *plugin)
592 {
593 GtkWidget *statusbar = eog_window_get_statusbar (plugin->window);
594
595 if (plugin->statusbar_exif == NULL) {
596 return;
597 }
598 gtk_container_remove (GTK_CONTAINER (statusbar),
599 plugin->statusbar_exif);
600 plugin->statusbar_exif = NULL;
601 }
602
603 static void
setup_statusbar_exif(EogExifDisplayPlugin * plugin)604 setup_statusbar_exif (EogExifDisplayPlugin *plugin)
605 {
606 GtkWidget *statusbar = eog_window_get_statusbar (plugin->window);
607
608 if (plugin->enable_statusbar) {
609 plugin->statusbar_exif = gtk_statusbar_new ();
610 gtk_widget_set_size_request (plugin->statusbar_exif, 280, 10);
611 gtk_box_pack_end (GTK_BOX (statusbar),
612 plugin->statusbar_exif,
613 FALSE, FALSE, 0);
614
615 statusbar_update_exif_data (GTK_STATUSBAR (plugin->statusbar_exif), plugin->thumbview);
616 }
617 else {
618 remove_statusbar_entry (plugin);
619 }
620 }
621
622 static void
impl_activate(EogWindowActivatable * activatable)623 impl_activate (EogWindowActivatable *activatable)
624 {
625 EogExifDisplayPlugin *plugin = EOG_EXIF_DISPLAY_PLUGIN (activatable);
626 EogWindow *window = plugin->window;
627 GSettings *settings;
628 GtkWidget *thumbview;
629 GtkWidget *sidebar;
630 GtkWidget *drawing_area;
631 GError* error = NULL;
632
633 settings = g_settings_new (EOG_EXIF_DISPLAY_CONF_SCHEMA_ID);
634
635 thumbview = eog_window_get_thumb_view (window);
636 plugin->thumbview = EOG_THUMB_VIEW (thumbview);
637
638 plugin->histogram_values_red = NULL;
639 plugin->histogram_values_green = NULL;
640 plugin->histogram_values_blue = NULL;
641 plugin->histogram_values_rgb = NULL;
642
643 plugin->statusbar_exif = NULL;
644
645 plugin->selection_changed_id = g_signal_connect (G_OBJECT (thumbview),
646 "selection-changed",
647 G_CALLBACK (selection_changed_cb),
648 plugin);
649
650 sidebar = eog_window_get_sidebar (window);
651
652 plugin->sidebar_builder = gtk_builder_new ();
653 gtk_builder_set_translation_domain (plugin->sidebar_builder,
654 GETTEXT_PACKAGE);
655 if (!gtk_builder_add_from_resource (plugin->sidebar_builder,
656 GRESOURCE_PATH, &error))
657 {
658 g_warning ("Couldn't load UI resource: %s", error->message);
659 g_error_free (error);
660 }
661 plugin->gtkbuilder_widget = GTK_WIDGET (gtk_builder_get_object (plugin->sidebar_builder, "viewport1"));
662
663 drawing_area = GTK_WIDGET (gtk_builder_get_object (plugin->sidebar_builder, "drawingarea1"));
664 g_signal_connect (drawing_area, "draw",
665 G_CALLBACK (drawing_area_draw_cb), plugin);
666 plugin->drawing_area = GTK_DRAWING_AREA (drawing_area);
667
668 eog_sidebar_add_page (EOG_SIDEBAR (sidebar), "Details",
669 plugin->gtkbuilder_widget);
670 gtk_widget_show_all (plugin->gtkbuilder_widget);
671
672 g_settings_bind (settings, EOG_EXIF_DISPLAY_CONF_CHANNELS_HISTOGRAM,
673 plugin, "draw-chan-histogram", G_SETTINGS_BIND_GET);
674 g_settings_bind (settings, EOG_EXIF_DISPLAY_CONF_RGB_HISTOGRAM,
675 plugin, "draw-rgb-histogram", G_SETTINGS_BIND_GET);
676 g_settings_bind (settings, EOG_EXIF_DISPLAY_CONF_EXIF_IN_STATUSBAR,
677 plugin, "enable-statusbar", G_SETTINGS_BIND_GET);
678
679 setup_statusbar_exif (plugin);
680
681 /* force display of data now */
682 selection_changed_cb (plugin->thumbview, plugin);
683 if (plugin->enable_statusbar)
684 {
685 statusbar_update_exif_data (GTK_STATUSBAR (plugin->statusbar_exif),
686 EOG_THUMB_VIEW (thumbview));
687 }
688
689 g_object_unref (settings);
690 }
691
692 static void
impl_deactivate(EogWindowActivatable * activatable)693 impl_deactivate (EogWindowActivatable *activatable)
694 {
695 EogExifDisplayPlugin *plugin = EOG_EXIF_DISPLAY_PLUGIN (activatable);
696 GtkWidget *sidebar, *thumbview;
697
698 remove_statusbar_entry (plugin);
699
700 sidebar = eog_window_get_sidebar (plugin->window);
701 eog_sidebar_remove_page(EOG_SIDEBAR (sidebar),
702 plugin->gtkbuilder_widget);
703
704 thumbview = eog_window_get_thumb_view (plugin->window);
705 g_signal_handler_disconnect (thumbview, plugin->selection_changed_id);
706
707 g_free (plugin->histogram_values_red);
708 plugin->histogram_values_red = NULL;
709 g_free (plugin->histogram_values_green);
710 plugin->histogram_values_green = NULL;
711 g_free (plugin->histogram_values_blue);
712 plugin->histogram_values_blue = NULL;
713 g_free (plugin->histogram_values_rgb);
714 plugin->histogram_values_rgb = NULL;
715
716 g_object_unref (plugin->sidebar_builder);
717 plugin->sidebar_builder = NULL;
718 }
719
720
721 static void
eog_exif_display_plugin_set_draw_chan_histogram(EogExifDisplayPlugin * plugin,gboolean value)722 eog_exif_display_plugin_set_draw_chan_histogram (EogExifDisplayPlugin *plugin,
723 gboolean value)
724 {
725 if (plugin->draw_chan_histogram == value)
726 return;
727
728 plugin->draw_chan_histogram = value;
729
730 gtk_widget_queue_draw (GTK_WIDGET (plugin->drawing_area));
731
732 g_object_notify (G_OBJECT (plugin), "draw-chan-histogram");
733 }
734
735 static void
eog_exif_display_plugin_set_draw_rgb_histogram(EogExifDisplayPlugin * plugin,gboolean value)736 eog_exif_display_plugin_set_draw_rgb_histogram (EogExifDisplayPlugin *plugin,
737 gboolean value)
738 {
739 if (plugin->draw_rgb_histogram == value)
740 return;
741
742 plugin->draw_rgb_histogram = value;
743
744 gtk_widget_queue_draw (GTK_WIDGET (plugin->drawing_area));
745
746 g_object_notify (G_OBJECT (plugin), "draw-rgb-histogram");
747 }
748
749 static void
eog_exif_display_plugin_enable_statusbar(EogExifDisplayPlugin * plugin,gboolean value)750 eog_exif_display_plugin_enable_statusbar (EogExifDisplayPlugin *plugin,
751 gboolean value)
752 {
753 if (plugin->enable_statusbar == value)
754 return;
755
756 plugin->enable_statusbar = value;
757
758 setup_statusbar_exif (plugin);
759
760 g_object_notify (G_OBJECT (plugin), "enable-statusbar");
761 }
762
763 static void
eog_exif_display_plugin_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)764 eog_exif_display_plugin_get_property (GObject *object,
765 guint prop_id,
766 GValue *value,
767 GParamSpec *pspec)
768 {
769 EogExifDisplayPlugin *plugin = EOG_EXIF_DISPLAY_PLUGIN (object);
770
771 switch (prop_id)
772 {
773 case PROP_DRAW_CHAN_HISTOGRAM:
774 g_value_set_boolean (value, plugin->draw_chan_histogram);
775 break;
776 case PROP_DRAW_RGB_HISTOGRAM:
777 g_value_set_boolean (value, plugin->draw_rgb_histogram);
778 break;
779 case PROP_ENABLE_STATUSBAR:
780 g_value_set_boolean (value, plugin->enable_statusbar);
781 break;
782 case PROP_WINDOW:
783 g_value_set_object (value, plugin->window);
784 break;
785
786 default:
787 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
788 break;
789 }
790 }
791
792 static void
eog_exif_display_plugin_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)793 eog_exif_display_plugin_set_property (GObject *object,
794 guint prop_id,
795 const GValue *value,
796 GParamSpec *pspec)
797 {
798 EogExifDisplayPlugin *plugin = EOG_EXIF_DISPLAY_PLUGIN (object);
799
800 switch (prop_id)
801 {
802 case PROP_DRAW_CHAN_HISTOGRAM:
803 eog_exif_display_plugin_set_draw_chan_histogram (plugin,
804 g_value_get_boolean (value));
805 break;
806 case PROP_DRAW_RGB_HISTOGRAM:
807 eog_exif_display_plugin_set_draw_rgb_histogram (plugin,
808 g_value_get_boolean (value));
809 break;
810 case PROP_ENABLE_STATUSBAR:
811 eog_exif_display_plugin_enable_statusbar (plugin,
812 g_value_get_boolean (value));
813 break;
814 case PROP_WINDOW:
815 plugin->window = EOG_WINDOW (g_value_dup_object (value));
816 break;
817
818 default:
819 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
820 break;
821 }
822 }
823
824 static void
eog_exif_display_plugin_dispose(GObject * object)825 eog_exif_display_plugin_dispose (GObject *object)
826 {
827 EogExifDisplayPlugin *plugin = EOG_EXIF_DISPLAY_PLUGIN (object);
828
829 eog_debug_message (DEBUG_PLUGINS, "EogPostrPlugin disposing");
830
831 if (plugin->window != NULL) {
832 g_object_unref (plugin->window);
833 plugin->window = NULL;
834 }
835
836 G_OBJECT_CLASS (eog_exif_display_plugin_parent_class)->dispose (object);
837 }
838 static void
eog_exif_display_plugin_class_init(EogExifDisplayPluginClass * klass)839 eog_exif_display_plugin_class_init (EogExifDisplayPluginClass *klass)
840 {
841 GObjectClass *object_class = G_OBJECT_CLASS (klass);
842
843 object_class->dispose = eog_exif_display_plugin_dispose;
844 object_class->set_property = eog_exif_display_plugin_set_property;
845 object_class->get_property = eog_exif_display_plugin_get_property;
846
847 g_object_class_install_property (object_class, PROP_DRAW_CHAN_HISTOGRAM,
848 g_param_spec_boolean ("draw-chan-histogram", NULL, NULL, FALSE,
849 G_PARAM_READWRITE | G_PARAM_STATIC_NAME));
850
851 g_object_class_install_property (object_class, PROP_DRAW_RGB_HISTOGRAM,
852 g_param_spec_boolean ("draw-rgb-histogram", NULL, NULL, FALSE,
853 G_PARAM_READWRITE | G_PARAM_STATIC_NAME));
854
855 g_object_class_install_property (object_class, PROP_ENABLE_STATUSBAR,
856 g_param_spec_boolean ("enable-statusbar", NULL, NULL, FALSE,
857 G_PARAM_READWRITE | G_PARAM_STATIC_NAME));
858
859 g_object_class_override_property (object_class, PROP_WINDOW, "window");
860 }
861
862 static void
eog_window_activatable_iface_init(EogWindowActivatableInterface * iface)863 eog_window_activatable_iface_init (EogWindowActivatableInterface *iface)
864 {
865 iface->activate = impl_activate;
866 iface->deactivate = impl_deactivate;
867 }
868
869 static void
eog_exif_display_plugin_class_finalize(EogExifDisplayPluginClass * klass)870 eog_exif_display_plugin_class_finalize (EogExifDisplayPluginClass *klass)
871 {
872 /* Dummy needed for G_DEFINE_DYNAMIC_TYPE_EXTENDED */
873 }
874
875 G_MODULE_EXPORT void
peas_register_types(PeasObjectModule * module)876 peas_register_types (PeasObjectModule *module)
877 {
878 eog_exif_display_plugin_register_type (G_TYPE_MODULE (module));
879 peas_object_module_register_extension_type (module,
880 EOG_TYPE_WINDOW_ACTIVATABLE,
881 EOG_TYPE_EXIF_DISPLAY_PLUGIN);
882
883 eog_exif_display_plugin_setup_register_types (module);
884 }
885