comparison src/info.c @ 9:d907d608745f

Sync to GQview 1.5.9 release. ######## DO NOT BASE ENHANCEMENTS OR TRANSLATION UPDATES ON CODE IN THIS CVS! This CVS is never up to date with current development and is provided solely for reference purposes, please use the latest official release package when making any changes or translation updates. ########
author gqview
date Sat, 26 Feb 2005 00:13:35 +0000
parents
children 3263965d5f9e
comparison
equal deleted inserted replaced
8:e0d0593d519e 9:d907d608745f
1 /*
2 * GQview
3 * (C) 2004 John Ellis
4 *
5 * Author: John Ellis
6 *
7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
10 */
11
12
13 #include "gqview.h"
14 #include "info.h"
15
16 #include "bar_info.h"
17 #include "bar_exif.h"
18 #include "dnd.h"
19 #include "filelist.h"
20 #include "image.h"
21 #include "image-load.h"
22 #include "ui_bookmark.h"
23 #include "ui_fileops.h"
24 #include "ui_misc.h"
25
26 #include <pwd.h>
27 #include <grp.h>
28
29
30 #define IMAGE_SIZE_W 200
31 #define IMAGE_SIZE_H 200
32
33 #define DEF_PROPERTY_WIDTH 510
34 #define DEF_PROPERTY_HEIGHT 390
35
36 typedef struct _TabData TabData;
37 struct _TabData
38 {
39 void (*func_free)(gpointer data);
40 void (*func_sync)(InfoData *id, gpointer data);
41 void (*func_image)(InfoData *id, gpointer data);
42 gpointer data;
43 };
44
45
46 /*
47 *-------------------------------------------------------------------
48 * table utils
49 *-------------------------------------------------------------------
50 */
51
52 GtkWidget *table_add_line(GtkWidget *table, gint x, gint y,
53 const gchar *description, const gchar *text)
54 {
55 GtkWidget *label;
56
57 if (!text) text = "";
58
59 label = pref_table_label(table, x, y, description, 1.0);
60 pref_label_bold(label, TRUE, FALSE);
61
62 label = pref_table_label(table, x + 1, y, text, 0.0);
63 return label;
64 }
65
66 /*
67 *-------------------------------------------------------------------
68 * EXIF tab
69 *-------------------------------------------------------------------
70 */
71
72 static void info_tab_exif_image(InfoData *id, gpointer data)
73 {
74 GtkWidget *bar = data;
75 const gchar *path;
76
77 if (id->image->unknown)
78 {
79 path = NULL;
80 }
81 else
82 {
83 path = id->image->image_path;
84 }
85
86 bar_exif_set(bar, path);
87 }
88
89 static void info_tab_exif_sync(InfoData *id, gpointer data)
90 {
91 GtkWidget *bar = data;
92
93 bar_exif_set(bar, NULL);
94 }
95
96 static TabData *info_tab_exif_new(InfoData *id)
97 {
98 TabData *td;
99 GtkWidget *bar;
100 GtkWidget *label;
101
102 bar = bar_exif_new(FALSE, NULL, FALSE, NULL);
103 gtk_container_set_border_width(GTK_CONTAINER(bar), PREF_PAD_BORDER);
104
105 label = gtk_label_new(_("Exif"));
106 gtk_notebook_append_page(GTK_NOTEBOOK(id->notebook), bar, label);
107 gtk_widget_show(bar);
108
109 /* register */
110 td = g_new0(TabData, 1);
111 td->func_free = NULL;
112 td->func_sync = info_tab_exif_sync;
113 td->func_image = info_tab_exif_image;
114 td->data = bar;
115
116 return td;
117 }
118
119 /*
120 *-------------------------------------------------------------------
121 * file attributes tab
122 *-------------------------------------------------------------------
123 */
124
125 typedef struct _InfoTabMeta InfoTabMeta;
126 struct _InfoTabMeta
127 {
128 GtkWidget *bar_info;
129 };
130
131 static void info_tab_meta_free(gpointer data)
132 {
133 InfoTabMeta *tab = data;
134
135 g_free(tab);
136 }
137
138 static void info_tab_meta_sync(InfoData *id, gpointer data)
139 {
140 InfoTabMeta *tab = data;
141
142 bar_info_set(tab->bar_info, id->path);
143 }
144
145 static GList *info_tab_meta_list_cb(gpointer data)
146 {
147 InfoData *id = data;
148
149 return path_list_copy(id->list);
150 }
151
152 static TabData *info_tab_meta_new(InfoData *id)
153 {
154 TabData *td;
155 InfoTabMeta *tab;
156 GtkWidget *label;
157
158 tab = g_new0(InfoTabMeta, 1);
159
160 tab->bar_info = bar_info_new(NULL, TRUE, NULL);
161 bar_info_set_selection_func(tab->bar_info, info_tab_meta_list_cb, id);
162 bar_info_selection(tab->bar_info, g_list_length(id->list) - 1);
163
164 gtk_container_set_border_width(GTK_CONTAINER(tab->bar_info), PREF_PAD_BORDER);
165
166 label = gtk_label_new(_("Keywords"));
167 gtk_notebook_append_page(GTK_NOTEBOOK(id->notebook), tab->bar_info, label);
168 gtk_widget_show(tab->bar_info);
169
170 /* register */
171 td = g_new0(TabData, 1);
172 td->func_free = info_tab_meta_free;
173 td->func_sync = info_tab_meta_sync;
174 td->func_image = NULL;
175 td->data = tab;
176
177 return td;
178 }
179
180 /*
181 *-------------------------------------------------------------------
182 * general tab
183 *-------------------------------------------------------------------
184 */
185
186 typedef struct _InfoTabGeneral InfoTabGeneral;
187 struct _InfoTabGeneral
188 {
189 GtkWidget *label_file_time;
190 GtkWidget *label_file_size;
191 GtkWidget *label_dimensions;
192 GtkWidget *label_transparent;
193 GtkWidget *label_image_size;
194 GtkWidget *label_compression;
195 GtkWidget *label_mime_type;
196
197 GtkWidget *label_user;
198 GtkWidget *label_group;
199 GtkWidget *label_perms;
200
201 gint compression_done;
202 gint64 byte_size;
203 };
204
205 static void info_tab_general_image(InfoData *id, gpointer data)
206 {
207 InfoTabGeneral *tab = data;
208 gchar *buf;
209 guint mem_size;
210 gint has_alpha;
211
212 if (id->image->unknown) return;
213
214 buf = g_strdup_printf("%d x %d", id->image->image_width, id->image->image_height);
215 gtk_label_set_text(GTK_LABEL(tab->label_dimensions), buf);
216 g_free(buf);
217
218 if (id->image->pixbuf)
219 {
220 has_alpha = gdk_pixbuf_get_has_alpha(id->image->pixbuf);
221 }
222 else
223 {
224 has_alpha = FALSE;
225 }
226 gtk_label_set_text(GTK_LABEL(tab->label_transparent), has_alpha ? _("yes") : _("no"));
227
228 mem_size = id->image->image_width * id->image->image_height * ((has_alpha) ? 4 : 3);
229 buf = text_from_size_abrev(mem_size);
230 gtk_label_set_text(GTK_LABEL(tab->label_image_size), buf);
231 g_free(buf);
232
233 if (!tab->compression_done && mem_size > 0)
234 {
235 buf = g_strdup_printf("%.1f%%", (float)tab->byte_size / mem_size * 100.0);
236 gtk_label_set_text(GTK_LABEL(tab->label_compression), buf);
237 g_free(buf);
238
239 tab->compression_done = TRUE;
240 }
241
242 buf = image_loader_get_format(id->image->il);
243 if (buf)
244 gtk_label_set_text(GTK_LABEL(tab->label_mime_type), buf);
245 g_free(buf);
246 }
247
248 static gchar *mode_number(mode_t m)
249 {
250 int mb, mu, mg, mo;
251
252 mb = mu = mg = mo = 0;
253
254 if (m & S_ISUID) mb |= 4;
255 if (m & S_ISGID) mb |= 2;
256 if (m & S_ISVTX) mb |= 1;
257
258 if (m & S_IRUSR) mu |= 4;
259 if (m & S_IWUSR) mu |= 2;
260 if (m & S_IXUSR) mu |= 1;
261
262 if (m & S_IRGRP) mg |= 4;
263 if (m & S_IWGRP) mg |= 2;
264 if (m & S_IXGRP) mg |= 1;
265
266 if (m & S_IROTH) mo |= 4;
267 if (m & S_IWOTH) mo |= 2;
268 if (m & S_IXOTH) mo |= 1;
269
270 return g_strdup_printf("%d%d%d%d", mb, mu, mg, mo);
271 }
272
273 static void info_tab_general_sync_perm(InfoTabGeneral *tab, InfoData *id)
274 {
275 struct stat st;
276
277 if (!stat_utf8(id->path, &st))
278 {
279 gtk_label_set_text(GTK_LABEL(tab->label_user), "");
280 gtk_label_set_text(GTK_LABEL(tab->label_group), "");
281 gtk_label_set_text(GTK_LABEL(tab->label_perms), "");
282 }
283 else
284 {
285 struct passwd *user;
286 struct group *grp;
287 gchar pbuf[12];
288 gchar *pmod;
289 gchar *buf;
290
291 user = getpwuid(st.st_uid);
292 gtk_label_set_text(GTK_LABEL(tab->label_user), (user) ? user->pw_name : "");
293
294 grp = getgrgid(st.st_gid);
295 gtk_label_set_text(GTK_LABEL(tab->label_group), (grp) ? grp->gr_name : "");
296
297 pbuf[0] = (st.st_mode & S_IRUSR) ? 'r' : '-';
298 pbuf[1] = (st.st_mode & S_IWUSR) ? 'w' : '-';
299 pbuf[2] = (st.st_mode & S_IXUSR) ? 'x' : '-';
300 pbuf[3] = (st.st_mode & S_IRGRP) ? 'r' : '-';
301 pbuf[4] = (st.st_mode & S_IWGRP) ? 'w' : '-';
302 pbuf[5] = (st.st_mode & S_IXGRP) ? 'x' : '-';
303 pbuf[6] = (st.st_mode & S_IROTH) ? 'r' : '-';
304 pbuf[7] = (st.st_mode & S_IWOTH) ? 'w' : '-';
305 pbuf[8] = (st.st_mode & S_IXOTH) ? 'x' : '-';
306 pbuf[9] = '\0';
307
308 pmod = mode_number(st.st_mode);
309 buf = g_strdup_printf("%s (%s)", pbuf, pmod);
310 gtk_label_set_text(GTK_LABEL(tab->label_perms), buf);
311 g_free(buf);
312 g_free(pmod);
313 }
314 }
315
316 static void info_tab_general_sync(InfoData *id, gpointer data)
317 {
318 InfoTabGeneral *tab = data;
319 gchar *buf;
320
321 gtk_label_set_text(GTK_LABEL(tab->label_file_time), text_from_time(filetime(id->path)));
322
323 tab->byte_size = filesize(id->path);
324
325 buf = text_from_size(tab->byte_size);
326 gtk_label_set_text(GTK_LABEL(tab->label_file_size), buf);
327 g_free(buf);
328
329 gtk_label_set_text(GTK_LABEL(tab->label_dimensions), "");
330 gtk_label_set_text(GTK_LABEL(tab->label_transparent), "");
331 gtk_label_set_text(GTK_LABEL(tab->label_image_size), "");
332
333 gtk_label_set_text(GTK_LABEL(tab->label_compression), "");
334 gtk_label_set_text(GTK_LABEL(tab->label_mime_type), "");
335
336 info_tab_general_sync_perm(tab, id);
337
338 tab->compression_done = FALSE;
339 }
340
341 static void info_tab_general_free(gpointer data)
342 {
343 InfoTabGeneral *tab = data;
344
345 g_free(tab);
346 }
347
348 static TabData *info_tab_general_new(InfoData *id)
349 {
350 TabData *td;
351 InfoTabGeneral *tab;
352 GtkWidget *table;
353 GtkWidget *label;
354
355 tab = g_new0(InfoTabGeneral, 1);
356
357 table = pref_table_new(NULL, 2, 11, FALSE, FALSE);
358 gtk_container_set_border_width(GTK_CONTAINER(table), PREF_PAD_BORDER);
359
360 tab->label_file_time = table_add_line(table, 0, 0, _("File date:"), NULL);
361 tab->label_file_size = table_add_line(table, 0, 1, _("File size:"), NULL);
362
363 tab->label_dimensions = table_add_line(table, 0, 2, _("Dimensions:"), NULL);
364 tab->label_transparent = table_add_line(table, 0, 3, _("Transparent:"), NULL);
365 tab->label_image_size = table_add_line(table, 0, 4, _("Image size:"), NULL);
366
367 tab->label_compression = table_add_line(table, 0, 5, _("Compress ratio:"), NULL);
368 tab->label_mime_type = table_add_line(table, 0, 6, _("File type:"), NULL);
369
370 tab->label_user = table_add_line(table, 0, 7, _("Owner:"), NULL);
371 tab->label_group = table_add_line(table, 0, 8, _("Group:"), NULL);
372 tab->label_perms = table_add_line(table, 0, 9, "", NULL);
373
374 label = gtk_label_new(_("General"));
375 gtk_notebook_append_page(GTK_NOTEBOOK(id->notebook), table, label);
376 gtk_widget_show(table);
377
378 /* register */
379 td = g_new0(TabData, 1);
380 td->func_free = info_tab_general_free;
381 td->func_sync = info_tab_general_sync;
382 td->func_image = info_tab_general_image;
383 td->data = tab;
384
385 return td;
386 }
387
388 /*
389 *-------------------------------------------------------------------
390 * tabs
391 *-------------------------------------------------------------------
392 */
393
394 static void info_tabs_sync(InfoData *id, gint image)
395 {
396 GList *work;
397
398 work = id->tab_list;
399 while (work)
400 {
401 TabData *td = work->data;
402 work = work->next;
403
404 if (image)
405 {
406 if (td->func_image) td->func_image(id, td->data);
407 }
408 else
409 {
410 if (td->func_sync) td->func_sync(id, td->data);
411 }
412 }
413 }
414
415 static void info_tabs_free(InfoData *id)
416 {
417 GList *work;
418
419 work = id->tab_list;
420 while (work)
421 {
422 TabData *td = work->data;
423 work = work->next;
424
425 if (td->func_free) td->func_free(td->data);
426 g_free(td);
427 }
428 g_list_free(id->tab_list);
429 id->tab_list = NULL;
430 }
431
432 static void info_tabs_init(InfoData *id)
433 {
434 id->tab_list = g_list_append(id->tab_list, info_tab_general_new(id));
435 id->tab_list = g_list_append(id->tab_list, info_tab_meta_new(id));
436 id->tab_list = g_list_append(id->tab_list, info_tab_exif_new(id));
437 }
438
439 /*
440 *-------------------------------------------------------------------
441 * sync
442 *-------------------------------------------------------------------
443 */
444
445 static void info_window_sync(InfoData *id, const gchar *path)
446 {
447
448 if (!path) return;
449
450 gtk_entry_set_text(GTK_ENTRY(id->name_entry), filename_from_path(path));
451
452 if (id->label_count)
453 {
454 gchar *buf;
455 buf = g_strdup_printf(_("Image %d of %d"),
456 g_list_index(id->list, (gpointer)path) + 1,
457 g_list_length(id->list));
458 gtk_label_set_text(GTK_LABEL(id->label_count), buf);
459 g_free(buf);
460 }
461
462 info_tabs_sync(id, FALSE);
463
464 id->updated = FALSE;
465 image_change_path(id->image, path, 0.0);
466 }
467
468 /*
469 *-------------------------------------------------------------------
470 * drag n drop (dropping not supported!)
471 *-------------------------------------------------------------------
472 */
473
474 static void info_window_dnd_data_set(GtkWidget *widget, GdkDragContext *context,
475 GtkSelectionData *selection_data, guint info,
476 guint time, gpointer data)
477 {
478 InfoData *id = data;
479 const gchar *path;
480
481 path = image_get_path(id->image);
482 if (path)
483 {
484 gchar *text;
485 gint len;
486 GList *list;
487 gint plain_text;
488
489 switch (info)
490 {
491 case TARGET_URI_LIST:
492 plain_text = FALSE;
493 break;
494 case TARGET_TEXT_PLAIN:
495 default:
496 plain_text = TRUE;
497 break;
498 }
499 list = g_list_append(NULL, (gchar *)path);
500 text = uri_text_from_list(list, &len, plain_text);
501 g_list_free(list);
502
503 gtk_selection_data_set(selection_data, selection_data->target,
504 8, text, len);
505 g_free(text);
506 }
507 }
508
509 static void info_window_dnd_init(InfoData *id)
510 {
511 ImageWindow *imd;
512
513 imd = id->image;
514
515 gtk_drag_source_set(imd->image, GDK_BUTTON2_MASK,
516 dnd_file_drag_types, dnd_file_drag_types_count,
517 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
518 g_signal_connect(G_OBJECT(imd->image), "drag_data_get",
519 G_CALLBACK(info_window_dnd_data_set), id);
520
521 #if 0
522 gtk_drag_dest_set(imd->image,
523 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
524 dnd_file_drop_types, dnd_file_drop_types_count,
525 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
526 g_signal_connect(G_OBJECT(imd->image), "drag_data_received",
527 G_CALLBACK(info_window_dnd_data_get), id);
528 #endif
529 }
530
531 /*
532 *-------------------------------------------------------------------
533 * base window
534 *-------------------------------------------------------------------
535 */
536
537 static gint info_window_last_width = DEF_PROPERTY_WIDTH;
538 static gint info_window_last_height = DEF_PROPERTY_HEIGHT;
539
540 static void info_window_image_update_cb(ImageWindow *imd, gpointer data)
541 {
542 InfoData *id = data;
543
544 /* only do this once after when loading a new image,
545 * for tabs that depend on image data (exif)
546 * Subsequent updates are ignored, as the image
547 * should not really changed if id->updated is TRUE.
548 */
549
550 if (id->updated) return;
551 if (imd->unknown) return;
552
553 info_tabs_sync(id, TRUE);
554 id->updated = TRUE;
555 }
556
557 static void info_window_back_cb(GtkWidget *widget, gpointer data)
558 {
559 InfoData *id = data;
560 GList *work;
561
562 work = g_list_find(id->list, (gpointer)id->path);
563 if (!work || !work->prev) return;
564
565 work = work->prev;
566 id->path = work->data;
567
568 info_window_sync(id, id->path);
569
570 gtk_widget_set_sensitive(id->button_back, (work->prev != NULL));
571 gtk_widget_set_sensitive(id->button_next, TRUE);
572 }
573
574 static void info_window_next_cb(GtkWidget *widget, gpointer data)
575 {
576 InfoData *id = data;
577 GList *work;
578
579 work = g_list_find(id->list, (gpointer)id->path);
580 if (!work || !work->next) return;
581
582 work = work->next;
583 id->path = work->data;
584
585 info_window_sync(id, id->path);
586
587 gtk_widget_set_sensitive(id->button_next, (work->next != NULL));
588 gtk_widget_set_sensitive(id->button_back, TRUE);
589 }
590
591 static void info_window_image_button_cb(ImageWindow *imd, gint button, guint32 time,
592 gdouble x, gdouble y, guint state, gpointer data)
593 {
594 if (button == 1)
595 {
596 info_window_next_cb(NULL, data);
597 }
598 else if (button == 2 || button == 3)
599 {
600 info_window_back_cb(NULL, data);
601 }
602 }
603
604 static void info_window_image_scroll_cb(ImageWindow *imd, GdkScrollDirection direction, guint32 time,
605 gdouble x, gdouble y, guint state, gpointer data)
606 {
607 if (direction == GDK_SCROLL_UP)
608 {
609 info_window_back_cb(NULL, data);
610 }
611 else if (direction == GDK_SCROLL_DOWN)
612 {
613 info_window_next_cb(NULL, data);
614 }
615 }
616
617 static void info_window_close(InfoData *id)
618 {
619 gdk_drawable_get_size(id->window->window, &info_window_last_width, &info_window_last_height);
620 info_window_last_width = MAX(info_window_last_width, DEF_PROPERTY_WIDTH);
621 info_window_last_height = MAX(info_window_last_height, DEF_PROPERTY_HEIGHT);
622
623 gtk_widget_destroy(id->window);
624 }
625
626 static void info_window_close_cb(GtkWidget *widget, gpointer data)
627 {
628 InfoData *id = data;
629
630 info_window_close(id);
631 }
632
633 static gint info_window_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer data)
634 {
635 InfoData *id = data;
636
637 info_window_close(id);
638 return TRUE;
639 }
640
641 static void info_window_destroy_cb(GtkWidget *widget, gpointer data)
642 {
643 InfoData *id = data;
644
645 info_tabs_free(id);
646 path_list_free(id->list);
647 g_free(id);
648 }
649
650 void info_window_new(const gchar *path, GList *list)
651 {
652 InfoData *id;
653 GtkWidget *main_vbox;
654 GtkWidget *paned;
655 GtkWidget *hbox;
656 GtkWidget *button;
657 GtkWidget *label;
658 GdkGeometry geometry;
659
660 if (!path && !list) return;
661
662 if (!list)
663 {
664 list = g_list_append(NULL, g_strdup(path));
665 }
666
667 id = g_new0(InfoData, 1);
668
669 id->list = list;
670 id->path = (gchar *)id->list->data;
671 id->updated = FALSE;
672
673 id->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
674 gtk_window_set_type_hint(GTK_WINDOW(id->window), GDK_WINDOW_TYPE_HINT_DIALOG);
675 window_set_icon(id->window, NULL, NULL);
676
677 gtk_window_set_resizable(GTK_WINDOW(id->window), TRUE);
678 gtk_window_set_title(GTK_WINDOW(id->window), _("Image properties - GQview"));
679 gtk_window_set_wmclass(GTK_WINDOW(id->window), "properties", "GQview");
680
681 geometry.min_width = 32;
682 geometry.min_height = 32;
683 geometry.base_width = DEF_PROPERTY_WIDTH;
684 geometry.base_height = DEF_PROPERTY_HEIGHT;
685 gtk_window_set_geometry_hints(GTK_WINDOW(id->window), NULL, &geometry,
686 GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE);
687
688
689 gtk_window_set_default_size(GTK_WINDOW(id->window), info_window_last_width, info_window_last_height);
690 gtk_container_set_border_width(GTK_CONTAINER(id->window), PREF_PAD_BORDER);
691
692 g_signal_connect(G_OBJECT(id->window), "delete_event",
693 G_CALLBACK(info_window_delete_cb), id);
694 g_signal_connect(G_OBJECT(id->window), "destroy",
695 G_CALLBACK(info_window_destroy_cb), id);
696
697 paned = gtk_hpaned_new();
698 gtk_container_add(GTK_CONTAINER(id->window), paned);
699 gtk_widget_show(paned);
700
701 id->image = image_new(FALSE);
702 image_set_update_func(id->image, info_window_image_update_cb, id);
703
704 image_set_button_func(id->image, info_window_image_button_cb, id);
705 image_set_scroll_func(id->image, info_window_image_scroll_cb, id);
706
707 gtk_widget_set_size_request(id->image->widget, IMAGE_SIZE_W, IMAGE_SIZE_H);
708 gtk_paned_pack1(GTK_PANED(paned), id->image->widget, FALSE, TRUE);
709 gtk_widget_show(id->image->widget);
710
711 main_vbox = gtk_vbox_new(FALSE, 0);
712 gtk_paned_pack2(GTK_PANED(paned), main_vbox, TRUE, TRUE);
713 gtk_widget_show(main_vbox);
714
715 hbox = pref_box_new(main_vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
716 label = pref_label_new(hbox, _("Filename:"));
717 pref_label_bold(label, TRUE, FALSE);
718
719 id->name_entry = gtk_entry_new();
720 gtk_editable_set_editable(GTK_EDITABLE(id->name_entry), FALSE);
721 gtk_box_pack_start(GTK_BOX(hbox), id->name_entry, TRUE, TRUE, 0);
722 gtk_widget_show(id->name_entry);
723
724 id->notebook = gtk_notebook_new();
725 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(id->notebook), GTK_POS_TOP);
726 gtk_box_pack_start(GTK_BOX(main_vbox), id->notebook, TRUE, TRUE, 5);
727 gtk_widget_show(id->notebook);
728
729 pref_spacer(main_vbox, PREF_PAD_GAP);
730
731 hbox = pref_box_new(main_vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP);
732
733 id->button_back = pref_button_new(hbox, GTK_STOCK_GO_BACK, NULL, TRUE,
734 G_CALLBACK(info_window_back_cb), id);
735 gtk_widget_set_sensitive(id->button_back, FALSE);
736
737 id->button_next = pref_button_new(hbox, GTK_STOCK_GO_FORWARD, NULL, TRUE,
738 G_CALLBACK(info_window_next_cb), id);
739 gtk_widget_set_sensitive(id->button_next, (id->list->next != NULL));
740
741 if (id->list->next)
742 {
743 id->label_count = pref_label_new(hbox, "");
744 }
745
746 button = pref_button_new(NULL, GTK_STOCK_CLOSE, NULL, FALSE,
747 G_CALLBACK(info_window_close_cb), id);
748 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
749 gtk_widget_show(button);
750
751 /* set up tabs */
752
753 info_tabs_init(id);
754
755 /* fill it */
756
757 info_window_sync(id, id->path);
758
759 /* finish */
760
761 info_window_dnd_init(id);
762
763 gtk_widget_show(id->window);
764 }
765