2008-04-30 Cosimo Cecchi <cosimoc@gnome.org>
[nautilus.git] / src / nautilus-information-panel.c
blob9d1f631de54dbb293b7e004ba6b5bb14ab4ab8c1
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 /*
4 * Nautilus
6 * Copyright (C) 1999, 2000, 2001 Eazel, Inc.
8 * Nautilus 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 2 of the License, or
11 * (at your option) any later version.
13 * Nautilus 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.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Author: Andy Hertzfeld <andy@eazel.com>
26 #include <config.h>
27 #include "nautilus-information-panel.h"
29 #include "nautilus-sidebar-title.h"
31 #include <eel/eel-background.h>
32 #include <eel/eel-glib-extensions.h>
33 #include <eel/eel-gtk-extensions.h>
34 #include <eel/eel-gtk-macros.h>
35 #include <eel/eel-stock-dialogs.h>
36 #include <eel/eel-string.h>
37 #include <eel/eel-vfs-extensions.h>
38 #include <gdk-pixbuf/gdk-pixbuf.h>
39 #include <gtk/gtkdnd.h>
40 #include <gtk/gtkhbox.h>
41 #include <glib/gi18n.h>
42 #include <libgnomeui/gnome-uidefs.h>
43 #include <libnautilus-private/nautilus-dnd.h>
44 #include <libnautilus-private/nautilus-directory.h>
45 #include <libnautilus-private/nautilus-file-dnd.h>
46 #include <libnautilus-private/nautilus-file.h>
47 #include <libnautilus-private/nautilus-global-preferences.h>
48 #include <libnautilus-private/nautilus-keep-last-vertical-box.h>
49 #include <libnautilus-private/nautilus-metadata.h>
50 #include <libnautilus-private/nautilus-mime-actions.h>
51 #include <libnautilus-private/nautilus-program-choosing.h>
52 #include <libnautilus-private/nautilus-sidebar-provider.h>
53 #include <libnautilus-private/nautilus-module.h>
55 struct NautilusInformationPanelDetails {
56 GtkVBox *container;
57 NautilusWindowInfo *window;
58 NautilusSidebarTitle *title;
59 GtkHBox *button_box_centerer;
60 GtkVBox *button_box;
61 gboolean has_buttons;
62 NautilusFile *file;
63 guint file_changed_connection;
64 gboolean background_connected;
66 char *default_background_color;
67 char *default_background_image;
68 char *current_background_color;
69 char *current_background_image;
72 /* button assignments */
73 #define CONTEXTUAL_MENU_BUTTON 3
75 static gboolean nautilus_information_panel_press_event (GtkWidget *widget,
76 GdkEventButton *event);
77 static void nautilus_information_panel_finalize (GObject *object);
78 static void nautilus_information_panel_drag_data_received (GtkWidget *widget,
79 GdkDragContext *context,
80 int x,
81 int y,
82 GtkSelectionData *selection_data,
83 guint info,
84 guint time);
85 static void nautilus_information_panel_read_defaults (NautilusInformationPanel *information_panel);
86 static void nautilus_information_panel_style_set (GtkWidget *widget,
87 GtkStyle *previous_style);
88 static void nautilus_information_panel_theme_changed (gpointer user_data);
89 static void nautilus_information_panel_update_appearance (NautilusInformationPanel *information_panel);
90 static void nautilus_information_panel_update_buttons (NautilusInformationPanel *information_panel);
91 static void add_command_buttons (NautilusInformationPanel *information_panel,
92 GList *application_list);
93 static void background_metadata_changed_callback (NautilusInformationPanel *information_panel);
94 static void nautilus_information_panel_iface_init (NautilusSidebarIface *iface);
95 static void nautilus_information_panel_iface_init (NautilusSidebarIface *iface);
96 static void sidebar_provider_iface_init (NautilusSidebarProviderIface *iface);
97 static GType nautilus_information_panel_provider_get_type (void);
99 enum {
100 LOCATION_CHANGED,
101 LAST_SIGNAL
104 static guint signals[LAST_SIGNAL];
106 /* drag and drop definitions */
108 enum {
109 TARGET_URI_LIST,
110 TARGET_COLOR,
111 TARGET_BGIMAGE,
112 TARGET_KEYWORD,
113 TARGET_BACKGROUND_RESET,
114 TARGET_GNOME_URI_LIST
117 static const GtkTargetEntry target_table[] = {
118 { "text/uri-list", 0, TARGET_URI_LIST },
119 { "application/x-color", 0, TARGET_COLOR },
120 { "property/bgimage", 0, TARGET_BGIMAGE },
121 { "property/keyword", 0, TARGET_KEYWORD },
122 { "x-special/gnome-reset-background", 0, TARGET_BACKGROUND_RESET },
123 { "x-special/gnome-icon-list", 0, TARGET_GNOME_URI_LIST }
126 typedef enum {
127 NO_PART,
128 BACKGROUND_PART,
129 ICON_PART
130 } InformationPanelPart;
132 typedef struct {
133 GObject parent;
134 } NautilusInformationPanelProvider;
136 typedef struct {
137 GObjectClass parent;
138 } NautilusInformationPanelProviderClass;
141 G_DEFINE_TYPE_WITH_CODE (NautilusInformationPanel, nautilus_information_panel, EEL_TYPE_BACKGROUND_BOX,
142 G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_SIDEBAR,
143 nautilus_information_panel_iface_init));
144 /* for EEL_CALL_PARENT */
145 #define parent_class nautilus_information_panel_parent_class
147 G_DEFINE_TYPE_WITH_CODE (NautilusInformationPanelProvider, nautilus_information_panel_provider, G_TYPE_OBJECT,
148 G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_SIDEBAR_PROVIDER,
149 sidebar_provider_iface_init));
152 static const char *
153 nautilus_information_panel_get_sidebar_id (NautilusSidebar *sidebar)
155 return NAUTILUS_INFORMATION_PANEL_ID;
158 static char *
159 nautilus_information_panel_get_tab_label (NautilusSidebar *sidebar)
161 return g_strdup (_("Information"));
164 static char *
165 nautilus_information_panel_get_tab_tooltip (NautilusSidebar *sidebar)
167 return g_strdup (_("Show Information"));
170 static GdkPixbuf *
171 nautilus_information_panel_get_tab_icon (NautilusSidebar *sidebar)
173 return NULL;
176 static void
177 nautilus_information_panel_is_visible_changed (NautilusSidebar *sidebar,
178 gboolean is_visible)
180 /* Do nothing */
183 static void
184 nautilus_information_panel_iface_init (NautilusSidebarIface *iface)
186 iface->get_sidebar_id = nautilus_information_panel_get_sidebar_id;
187 iface->get_tab_label = nautilus_information_panel_get_tab_label;
188 iface->get_tab_tooltip = nautilus_information_panel_get_tab_tooltip;
189 iface->get_tab_icon = nautilus_information_panel_get_tab_icon;
190 iface->is_visible_changed = nautilus_information_panel_is_visible_changed;
193 /* initializing the class object by installing the operations we override */
194 static void
195 nautilus_information_panel_class_init (NautilusInformationPanelClass *klass)
197 GtkWidgetClass *widget_class;
198 GObjectClass *gobject_class;
200 gobject_class = G_OBJECT_CLASS (klass);
201 widget_class = GTK_WIDGET_CLASS (klass);
203 gobject_class->finalize = nautilus_information_panel_finalize;
205 widget_class->drag_data_received = nautilus_information_panel_drag_data_received;
206 widget_class->button_press_event = nautilus_information_panel_press_event;
207 widget_class->style_set = nautilus_information_panel_style_set;
209 /* add the "location changed" signal */
210 signals[LOCATION_CHANGED] = g_signal_new
211 ("location_changed",
212 G_TYPE_FROM_CLASS (klass),
213 G_SIGNAL_RUN_LAST,
214 G_STRUCT_OFFSET (NautilusInformationPanelClass,
215 location_changed),
216 NULL, NULL,
217 g_cclosure_marshal_VOID__STRING,
218 G_TYPE_NONE, 1, G_TYPE_STRING);
221 /* utility routine to allocate the box the holds the command buttons */
222 static void
223 make_button_box (NautilusInformationPanel *information_panel)
225 information_panel->details->button_box_centerer = GTK_HBOX (gtk_hbox_new (FALSE, 0));
226 gtk_box_pack_start_defaults (GTK_BOX (information_panel->details->container),
227 GTK_WIDGET (information_panel->details->button_box_centerer));
229 information_panel->details->button_box = GTK_VBOX (nautilus_keep_last_vertical_box_new (GNOME_PAD_SMALL));
230 gtk_container_set_border_width (GTK_CONTAINER (information_panel->details->button_box), GNOME_PAD);
231 gtk_widget_show (GTK_WIDGET (information_panel->details->button_box));
232 gtk_box_pack_start (GTK_BOX (information_panel->details->button_box_centerer),
233 GTK_WIDGET (information_panel->details->button_box),
234 TRUE, TRUE, 0);
235 information_panel->details->has_buttons = FALSE;
238 /* initialize the instance's fields, create the necessary subviews, etc. */
240 static void
241 nautilus_information_panel_init (NautilusInformationPanel *information_panel)
243 GtkWidget *widget;
245 widget = GTK_WIDGET (information_panel);
247 information_panel->details = g_new0 (NautilusInformationPanelDetails, 1);
249 /* load the default background */
250 nautilus_information_panel_read_defaults (information_panel);
252 /* enable mouse tracking */
253 gtk_widget_add_events (GTK_WIDGET (information_panel), GDK_POINTER_MOTION_MASK);
255 /* create the container box */
256 information_panel->details->container = GTK_VBOX (gtk_vbox_new (FALSE, 0));
257 gtk_container_set_border_width (GTK_CONTAINER (information_panel->details->container), 0);
258 gtk_widget_show (GTK_WIDGET (information_panel->details->container));
259 gtk_container_add (GTK_CONTAINER (information_panel),
260 GTK_WIDGET (information_panel->details->container));
262 /* allocate and install the index title widget */
263 information_panel->details->title = NAUTILUS_SIDEBAR_TITLE (nautilus_sidebar_title_new ());
264 gtk_widget_show (GTK_WIDGET (information_panel->details->title));
265 gtk_box_pack_start (GTK_BOX (information_panel->details->container),
266 GTK_WIDGET (information_panel->details->title),
267 FALSE, FALSE, GNOME_PAD);
269 /* allocate and install the command button container */
270 make_button_box (information_panel);
272 /* add a callback for when the theme changes */
273 eel_preferences_add_callback (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_SET, nautilus_information_panel_theme_changed, information_panel);
274 eel_preferences_add_callback (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_COLOR, nautilus_information_panel_theme_changed, information_panel);
275 eel_preferences_add_callback (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_FILENAME, nautilus_information_panel_theme_changed, information_panel);
277 /* prepare ourselves to receive dropped objects */
278 gtk_drag_dest_set (GTK_WIDGET (information_panel),
279 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP,
280 target_table, G_N_ELEMENTS (target_table),
281 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK);
284 static void
285 nautilus_information_panel_finalize (GObject *object)
287 NautilusInformationPanel *information_panel;
289 information_panel = NAUTILUS_INFORMATION_PANEL (object);
291 if (information_panel->details->file != NULL) {
292 nautilus_file_monitor_remove (information_panel->details->file, information_panel);
293 nautilus_file_unref (information_panel->details->file);
296 g_free (information_panel->details->default_background_color);
297 g_free (information_panel->details->default_background_image);
298 g_free (information_panel->details->current_background_color);
299 g_free (information_panel->details->current_background_image);
300 g_free (information_panel->details);
302 eel_preferences_remove_callback (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_SET,
303 nautilus_information_panel_theme_changed,
304 information_panel);
305 eel_preferences_remove_callback (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_COLOR,
306 nautilus_information_panel_theme_changed,
307 information_panel);
308 eel_preferences_remove_callback (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_FILENAME,
309 nautilus_information_panel_theme_changed,
310 information_panel);
312 EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
315 /* callback to handle resetting the background */
316 static void
317 reset_background_callback (GtkWidget *menu_item, GtkWidget *information_panel)
319 EelBackground *background;
321 background = eel_get_widget_background (information_panel);
322 if (background != NULL) {
323 eel_background_reset (background);
327 static gboolean
328 information_panel_has_background (NautilusInformationPanel *information_panel)
330 EelBackground *background;
331 gboolean has_background;
332 char *color;
333 char *image;
335 background = eel_get_widget_background (GTK_WIDGET(information_panel));
337 color = eel_background_get_color (background);
338 image = eel_background_get_image_uri (background);
340 has_background = (color || image);
342 return has_background;
345 /* create the context menu */
346 static GtkWidget *
347 nautilus_information_panel_create_context_menu (NautilusInformationPanel *information_panel)
349 GtkWidget *menu, *menu_item;
351 menu = gtk_menu_new ();
352 gtk_menu_set_screen (GTK_MENU (menu),
353 gtk_widget_get_screen (GTK_WIDGET (information_panel)));
355 /* add the reset background item, possibly disabled */
356 menu_item = gtk_menu_item_new_with_mnemonic (_("Use _Default Background"));
357 gtk_widget_show (menu_item);
358 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
359 gtk_widget_set_sensitive (menu_item, information_panel_has_background (information_panel));
360 g_signal_connect_object (menu_item, "activate",
361 G_CALLBACK (reset_background_callback), information_panel, 0);
363 return menu;
366 /* set up the default backgrounds and images */
367 static void
368 nautilus_information_panel_read_defaults (NautilusInformationPanel *information_panel)
370 gboolean background_set;
371 char *background_color, *background_image;
373 background_set = eel_preferences_get_boolean (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_SET);
375 background_color = NULL;
376 background_image = NULL;
377 if (background_set) {
378 background_color = eel_preferences_get (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_COLOR);
379 background_image = eel_preferences_get (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_FILENAME);
382 g_free (information_panel->details->default_background_color);
383 information_panel->details->default_background_color = NULL;
384 g_free (information_panel->details->default_background_image);
385 information_panel->details->default_background_image = NULL;
387 if (background_color && strlen (background_color)) {
388 information_panel->details->default_background_color = g_strdup (background_color);
391 /* set up the default background image */
393 if (background_image && strlen (background_image)) {
394 information_panel->details->default_background_image = g_strdup (background_image);
397 g_free (background_color);
398 g_free (background_image);
401 /* handler for handling theme changes */
403 static void
404 nautilus_information_panel_theme_changed (gpointer user_data)
406 NautilusInformationPanel *information_panel;
408 information_panel = NAUTILUS_INFORMATION_PANEL (user_data);
409 nautilus_information_panel_read_defaults (information_panel);
410 nautilus_information_panel_update_appearance (information_panel);
411 gtk_widget_queue_draw (GTK_WIDGET (information_panel)) ;
414 /* hit testing */
416 static InformationPanelPart
417 hit_test (NautilusInformationPanel *information_panel,
418 int x, int y)
420 if (nautilus_sidebar_title_hit_test_icon (information_panel->details->title, x, y)) {
421 return ICON_PART;
424 if (eel_point_in_widget (GTK_WIDGET (information_panel), x, y)) {
425 return BACKGROUND_PART;
428 return NO_PART;
431 /* utility to test if a uri refers to a local image */
432 static gboolean
433 uri_is_local_image (const char *uri)
435 GdkPixbuf *pixbuf;
436 char *image_path;
438 image_path = g_filename_from_uri (uri, NULL, NULL);
439 if (image_path == NULL) {
440 return FALSE;
443 pixbuf = gdk_pixbuf_new_from_file (image_path, NULL);
444 g_free (image_path);
446 if (pixbuf == NULL) {
447 return FALSE;
449 g_object_unref (pixbuf);
450 return TRUE;
453 static void
454 receive_dropped_uri_list (NautilusInformationPanel *information_panel,
455 GdkDragAction action,
456 int x, int y,
457 GtkSelectionData *selection_data)
459 char **uris;
460 gboolean exactly_one;
461 GtkWindow *window;
463 uris = g_uri_list_extract_uris ((gchar *) selection_data->data);
464 exactly_one = uris[0] != NULL && (uris[1] == NULL || uris[1][0] == '\0');
465 window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (information_panel)));
467 switch (hit_test (information_panel, x, y)) {
468 case NO_PART:
469 case BACKGROUND_PART:
470 /* FIXME bugzilla.gnome.org 42507: Does this work for all images, or only background images?
471 * Other views handle background images differently from other URIs.
473 if (exactly_one && uri_is_local_image (uris[0])) {
474 if (action == GDK_ACTION_ASK) {
475 action = nautilus_drag_drop_background_ask (GTK_WIDGET (information_panel), NAUTILUS_DND_ACTION_SET_AS_BACKGROUND | NAUTILUS_DND_ACTION_SET_AS_GLOBAL_BACKGROUND);
478 if (action > 0) {
479 eel_background_receive_dropped_background_image
480 (eel_get_widget_background (GTK_WIDGET (information_panel)),
481 action,
482 uris[0]);
484 } else if (exactly_one) {
485 g_signal_emit (information_panel,
486 signals[LOCATION_CHANGED], 0,
487 uris[0]);
489 break;
490 case ICON_PART:
491 /* handle images dropped on the logo specially */
493 if (!exactly_one) {
494 eel_show_error_dialog (
495 _("You cannot assign more than one custom icon at a time."),
496 _("Please drag just one image to set a custom icon."),
497 window);
498 break;
501 if (uri_is_local_image (uris[0])) {
502 if (information_panel->details->file != NULL) {
503 nautilus_file_set_metadata (information_panel->details->file,
504 NAUTILUS_METADATA_KEY_CUSTOM_ICON,
505 NULL,
506 uris[0]);
507 nautilus_file_set_metadata (information_panel->details->file,
508 NAUTILUS_METADATA_KEY_ICON_SCALE,
509 NULL,
510 NULL);
512 } else {
513 GFile *f;
515 f = g_file_new_for_uri (uris[0]);
516 if (!g_file_is_native (f)) {
517 eel_show_error_dialog (
518 _("The file that you dropped is not local."),
519 _("You can only use local images as custom icons."),
520 window);
522 } else {
523 eel_show_error_dialog (
524 _("The file that you dropped is not an image."),
525 _("You can only use images as custom icons."),
526 window);
528 g_object_unref (f);
530 break;
533 g_strfreev (uris);
536 static void
537 receive_dropped_color (NautilusInformationPanel *information_panel,
538 GdkDragAction action,
539 int x, int y,
540 GtkSelectionData *selection_data)
542 guint16 *channels;
543 char color_spec[8];
545 if (selection_data->length != 8 || selection_data->format != 16) {
546 g_warning ("received invalid color data");
547 return;
550 channels = (guint16 *) selection_data->data;
551 g_snprintf (color_spec, sizeof (color_spec),
552 "#%02X%02X%02X", channels[0] >> 8, channels[1] >> 8, channels[2] >> 8);
554 switch (hit_test (information_panel, x, y)) {
555 case NO_PART:
556 g_warning ("dropped color, but not on any part of information_panel");
557 break;
558 case ICON_PART:
559 case BACKGROUND_PART:
560 if (action == GDK_ACTION_ASK) {
561 action = nautilus_drag_drop_background_ask (GTK_WIDGET (information_panel), NAUTILUS_DND_ACTION_SET_AS_BACKGROUND | NAUTILUS_DND_ACTION_SET_AS_GLOBAL_BACKGROUND);
564 if (action > 0) {
565 /* Let the background change based on the dropped color. */
566 eel_background_receive_dropped_color
567 (eel_get_widget_background (GTK_WIDGET (information_panel)),
568 GTK_WIDGET (information_panel),
569 action, x, y, selection_data);
572 break;
576 /* handle receiving a dropped keyword */
578 static void
579 receive_dropped_keyword (NautilusInformationPanel *information_panel,
580 int x, int y,
581 GtkSelectionData *selection_data)
583 nautilus_drag_file_receive_dropped_keyword (information_panel->details->file, selection_data->data);
585 /* regenerate the display */
586 nautilus_information_panel_update_appearance (information_panel);
589 static void
590 nautilus_information_panel_drag_data_received (GtkWidget *widget, GdkDragContext *context,
591 int x, int y,
592 GtkSelectionData *selection_data,
593 guint info, guint time)
595 NautilusInformationPanel *information_panel;
596 EelBackground *background;
598 g_return_if_fail (NAUTILUS_IS_INFORMATION_PANEL (widget));
600 information_panel = NAUTILUS_INFORMATION_PANEL (widget);
602 switch (info) {
603 case TARGET_GNOME_URI_LIST:
604 case TARGET_URI_LIST:
605 receive_dropped_uri_list (information_panel, context->action, x, y, selection_data);
606 break;
607 case TARGET_COLOR:
608 receive_dropped_color (information_panel, context->action, x, y, selection_data);
609 break;
610 case TARGET_BGIMAGE:
611 if (hit_test (information_panel, x, y) == BACKGROUND_PART)
612 receive_dropped_uri_list (information_panel, context->action, x, y, selection_data);
613 break;
614 case TARGET_BACKGROUND_RESET:
615 background = eel_get_widget_background ( GTK_WIDGET (information_panel));
616 if (background != NULL) {
617 eel_background_reset (background);
619 break;
620 case TARGET_KEYWORD:
621 receive_dropped_keyword (information_panel, x, y, selection_data);
622 break;
623 default:
624 g_warning ("unknown drop type");
628 /* handle the context menu if necessary */
629 static gboolean
630 nautilus_information_panel_press_event (GtkWidget *widget, GdkEventButton *event)
632 NautilusInformationPanel *information_panel;
633 GtkWidget *menu;
635 if (widget->window != event->window) {
636 return FALSE;
639 information_panel = NAUTILUS_INFORMATION_PANEL (widget);
641 /* handle the context menu */
642 if (event->button == CONTEXTUAL_MENU_BUTTON) {
643 menu = nautilus_information_panel_create_context_menu (information_panel);
644 eel_pop_up_context_menu (GTK_MENU(menu),
645 EEL_DEFAULT_POPUP_MENU_DISPLACEMENT,
646 EEL_DEFAULT_POPUP_MENU_DISPLACEMENT,
647 event);
649 return TRUE;
652 static gboolean
653 value_different (const char *a, const char *b)
655 if (!a && !b)
656 return FALSE;
658 if (!a || !b)
659 return TRUE;
661 return strcmp (a, b);
664 /* Handle the background changed signal by writing out the settings to metadata.
666 static void
667 background_settings_changed_callback (EelBackground *background, GdkDragAction action, NautilusInformationPanel *information_panel)
669 char *image;
670 char *color;
672 g_assert (EEL_IS_BACKGROUND (background));
673 g_assert (NAUTILUS_IS_INFORMATION_PANEL (information_panel));
675 if (information_panel->details->file == NULL) {
676 return;
679 /* Block so we don't respond to our own metadata changes.
681 g_signal_handlers_block_by_func (information_panel->details->file,
682 G_CALLBACK (background_metadata_changed_callback),
683 information_panel);
685 color = eel_background_get_color (background);
686 image = eel_background_get_image_uri (background);
688 if (action != NAUTILUS_DND_ACTION_SET_AS_BACKGROUND) {
689 nautilus_file_set_metadata (information_panel->details->file,
690 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR,
691 NULL,
692 NULL);
694 nautilus_file_set_metadata (information_panel->details->file,
695 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE,
696 NULL,
697 NULL);
699 eel_preferences_set
700 (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_COLOR, color ? color : "");
701 eel_preferences_set
702 (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_FILENAME, image ? image : "");
703 eel_preferences_set_boolean
704 (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_SET, TRUE);
705 } else {
706 nautilus_file_set_metadata (information_panel->details->file,
707 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR,
708 NULL,
709 color);
711 nautilus_file_set_metadata (information_panel->details->file,
712 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE,
713 NULL,
714 image);
717 if (value_different (information_panel->details->current_background_color, color)) {
718 g_free (information_panel->details->current_background_color);
719 information_panel->details->current_background_color = g_strdup (color);
722 if (value_different (information_panel->details->current_background_image, image)) {
723 g_free (information_panel->details->current_background_image);
724 information_panel->details->current_background_image = g_strdup (image);
727 g_free (color);
728 g_free (image);
730 g_signal_handlers_unblock_by_func (information_panel->details->file,
731 G_CALLBACK (background_metadata_changed_callback),
732 information_panel);
735 /* handle the background reset signal by writing out NULL to metadata and setting the backgrounds
736 fields to their default values */
737 static void
738 background_reset_callback (EelBackground *background, NautilusInformationPanel *information_panel)
740 char *color;
741 char *image;
742 g_assert (EEL_IS_BACKGROUND (background));
743 g_assert (NAUTILUS_IS_INFORMATION_PANEL (information_panel));
745 if (information_panel->details->file == NULL) {
746 return;
749 /* Block so we don't respond to our own metadata changes.
751 g_signal_handlers_block_by_func (information_panel->details->file,
752 G_CALLBACK (background_metadata_changed_callback),
753 information_panel);
755 color = nautilus_file_get_metadata (information_panel->details->file,
756 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR,
757 NULL);
759 image = nautilus_file_get_metadata (information_panel->details->file,
760 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE,
761 NULL);
762 if (color || image) {
763 nautilus_file_set_metadata (information_panel->details->file,
764 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR,
765 NULL,
766 NULL);
768 nautilus_file_set_metadata (information_panel->details->file,
769 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE,
770 NULL,
771 NULL);
772 } else {
773 eel_preferences_set_boolean (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_SET, FALSE);
776 g_signal_handlers_unblock_by_func (information_panel->details->file,
777 G_CALLBACK (background_metadata_changed_callback),
778 information_panel);
780 /* Force a read from the metadata to set the defaults
782 background_metadata_changed_callback (information_panel);
785 static GtkWindow *
786 nautilus_information_panel_get_window (NautilusInformationPanel *information_panel)
788 GtkWidget *result;
790 result = gtk_widget_get_ancestor (GTK_WIDGET (information_panel), GTK_TYPE_WINDOW);
792 return result == NULL ? NULL : GTK_WINDOW (result);
795 static void
796 command_button_callback (GtkWidget *button, GAppInfo *application)
798 NautilusInformationPanel *information_panel;
799 GList files;
801 information_panel = NAUTILUS_INFORMATION_PANEL (g_object_get_data (G_OBJECT (button), "user_data"));
803 files.next = NULL;
804 files.prev = NULL;
805 files.data = information_panel->details->file;
806 nautilus_launch_application (application, &files,
807 nautilus_information_panel_get_window (information_panel));
810 /* interpret commands for buttons specified by metadata. Handle some built-in ones explicitly, or fork
811 a shell to handle general ones */
812 /* for now, we don't have any of these */
813 static void
814 metadata_button_callback (GtkWidget *button, const char *command_str)
816 NautilusInformationPanel *information_panel;
818 information_panel = NAUTILUS_INFORMATION_PANEL (g_object_get_data (G_OBJECT (button), "user_data"));
821 /* utility routine that allocates the command buttons from the command list */
823 static void
824 add_command_buttons (NautilusInformationPanel *information_panel, GList *application_list)
826 char *temp_str;
827 GList *p;
828 GtkWidget *temp_button, *label;
829 GAppInfo *application;
831 /* There's always at least the "Open with..." button */
832 information_panel->details->has_buttons = TRUE;
834 for (p = application_list; p != NULL; p = p->next) {
835 application = p->data;
837 temp_str = g_strdup_printf (_("Open with %s"), g_app_info_get_name (application));
838 temp_button = gtk_button_new_with_label (temp_str);
839 label = GTK_BIN (temp_button)->child;
840 gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_START);
841 g_free (temp_str);
842 gtk_box_pack_start (GTK_BOX (information_panel->details->button_box),
843 temp_button,
844 FALSE, FALSE,
847 g_signal_connect_data (temp_button,
848 "clicked",
849 G_CALLBACK (command_button_callback),
850 g_object_ref (application),
851 (GClosureNotify)g_object_unref,
854 g_object_set_data (G_OBJECT (temp_button), "user_data", information_panel);
856 gtk_widget_show (temp_button);
860 /* utility to construct command buttons for the information_panel from the passed in metadata string */
862 static void
863 add_buttons_from_metadata (NautilusInformationPanel *information_panel, const char *button_data)
865 char **terms;
866 char *current_term, *temp_str;
867 char *button_name, *command_string;
868 const char *term;
869 int index;
870 GtkWidget *temp_button;
872 /* split the button specification into a set of terms */
873 button_name = NULL;
874 terms = g_strsplit (button_data, ";", 0);
876 /* for each term, either create a button or attach a property to one */
877 for (index = 0; (term = terms[index]) != NULL; index++) {
878 current_term = g_strdup (term);
879 temp_str = strchr (current_term, '=');
880 if (temp_str) {
881 *temp_str = '\0';
882 if (!g_ascii_strcasecmp (current_term, "button")) {
883 button_name = g_strdup (temp_str + 1);
884 } else if (!g_ascii_strcasecmp (current_term, "script")) {
885 if (button_name != NULL) {
886 temp_button = gtk_button_new_with_label (button_name);
887 gtk_box_pack_start (GTK_BOX (information_panel->details->button_box),
888 temp_button,
889 FALSE, FALSE,
891 information_panel->details->has_buttons = TRUE;
892 command_string = g_strdup (temp_str + 1);
893 g_free (button_name);
895 g_signal_connect_data (temp_button,
896 "clicked",
897 G_CALLBACK (metadata_button_callback),
898 command_string,
899 (GClosureNotify)g_free,
902 g_object_set_data (G_OBJECT (temp_button), "user_data", information_panel);
904 gtk_widget_show (temp_button);
908 g_free(current_term);
910 g_strfreev (terms);
914 * nautilus_information_panel_update_buttons:
916 * Update the list of program-launching buttons based on the current uri.
918 static void
919 nautilus_information_panel_update_buttons (NautilusInformationPanel *information_panel)
921 char *button_data;
922 GList *short_application_list;
924 /* dispose of any existing buttons */
925 if (information_panel->details->has_buttons) {
926 gtk_container_remove (GTK_CONTAINER (information_panel->details->container),
927 GTK_WIDGET (information_panel->details->button_box_centerer));
928 make_button_box (information_panel);
931 /* create buttons from file metadata if necessary */
932 button_data = nautilus_file_get_metadata (information_panel->details->file,
933 NAUTILUS_METADATA_KEY_SIDEBAR_BUTTONS,
934 NULL);
935 if (button_data) {
936 add_buttons_from_metadata (information_panel, button_data);
937 g_free(button_data);
940 /* Make buttons for each application */
941 if (nautilus_mime_has_any_applications_for_file (information_panel->details->file)) {
942 short_application_list =
943 nautilus_mime_get_applications_for_file (information_panel->details->file);
944 add_command_buttons (information_panel, short_application_list);
945 eel_g_object_list_free (short_application_list);
948 gtk_widget_show (GTK_WIDGET (information_panel->details->button_box_centerer));
951 static void
952 nautilus_information_panel_update_appearance (NautilusInformationPanel *information_panel)
954 EelBackground *background;
955 char *background_color;
956 char *background_image;
958 g_return_if_fail (NAUTILUS_IS_INFORMATION_PANEL (information_panel));
960 /* Connect the background changed signal to code that writes the color. */
961 background = eel_get_widget_background (GTK_WIDGET (information_panel));
962 if (!information_panel->details->background_connected) {
963 information_panel->details->background_connected = TRUE;
964 g_signal_connect_object (background,"settings_changed",
965 G_CALLBACK (background_settings_changed_callback), information_panel, 0);
966 g_signal_connect_object (background, "reset",
967 G_CALLBACK (background_reset_callback), information_panel, 0);
970 /* Set up the background color and image from the metadata. */
971 background_color = nautilus_file_get_metadata (information_panel->details->file,
972 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR,
973 NULL);
974 background_image = nautilus_file_get_metadata (information_panel->details->file,
975 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE,
976 NULL);
978 if (background_color == NULL && background_image == NULL) {
979 background_color = g_strdup (information_panel->details->default_background_color);
980 background_image = g_strdup (information_panel->details->default_background_image);
983 /* Block so we don't write these settings out in response to our set calls below */
984 g_signal_handlers_block_by_func (background,
985 G_CALLBACK (background_settings_changed_callback),
986 information_panel);
988 if (value_different (information_panel->details->current_background_color, background_color) ||
989 value_different (information_panel->details->current_background_image, background_image)) {
991 g_free (information_panel->details->current_background_color);
992 information_panel->details->current_background_color = g_strdup (background_color);
993 g_free (information_panel->details->current_background_image);
994 information_panel->details->current_background_image = g_strdup (background_image);
996 eel_background_set_image_uri (background, background_image);
997 eel_background_set_color (background, background_color);
999 nautilus_sidebar_title_select_text_color
1000 (information_panel->details->title, background,
1001 !information_panel_has_background (information_panel));
1004 g_free (background_color);
1005 g_free (background_image);
1007 g_signal_handlers_unblock_by_func (background,
1008 G_CALLBACK (background_settings_changed_callback),
1009 information_panel);
1012 static void
1013 background_metadata_changed_callback (NautilusInformationPanel *information_panel)
1015 NautilusFileAttributes attributes;
1016 gboolean ready;
1018 attributes = nautilus_mime_actions_get_required_file_attributes ();
1019 ready = nautilus_file_check_if_ready (information_panel->details->file, attributes);
1021 if (ready) {
1022 nautilus_information_panel_update_appearance (information_panel);
1024 /* set up the command buttons */
1025 nautilus_information_panel_update_buttons (information_panel);
1029 /* here is the key routine that populates the information_panel with the appropriate information when the uri changes */
1031 static void
1032 nautilus_information_panel_set_uri (NautilusInformationPanel *information_panel,
1033 const char* new_uri,
1034 const char* initial_title)
1036 NautilusFile *file;
1037 NautilusFileAttributes attributes;
1039 g_return_if_fail (NAUTILUS_IS_INFORMATION_PANEL (information_panel));
1040 g_return_if_fail (new_uri != NULL);
1041 g_return_if_fail (initial_title != NULL);
1043 /* there's nothing to do if the uri is the same as the current one */
1044 if (information_panel->details->file != NULL &&
1045 nautilus_file_matches_uri (information_panel->details->file, new_uri)) {
1046 return;
1049 if (information_panel->details->file != NULL) {
1050 g_signal_handler_disconnect (information_panel->details->file,
1051 information_panel->details->file_changed_connection);
1052 nautilus_file_monitor_remove (information_panel->details->file, information_panel);
1055 file = nautilus_file_get_by_uri (new_uri);
1057 nautilus_file_unref (information_panel->details->file);
1058 information_panel->details->file = file;
1060 information_panel->details->file_changed_connection =
1061 g_signal_connect_object (information_panel->details->file, "changed",
1062 G_CALLBACK (background_metadata_changed_callback),
1063 information_panel, G_CONNECT_SWAPPED);
1065 attributes = nautilus_mime_actions_get_required_file_attributes ();
1066 nautilus_file_monitor_add (information_panel->details->file, information_panel, attributes);
1068 background_metadata_changed_callback (information_panel);
1070 /* tell the title widget about it */
1071 nautilus_sidebar_title_set_file (information_panel->details->title,
1072 information_panel->details->file,
1073 initial_title);
1076 static void
1077 title_changed_callback (NautilusWindowInfo *window,
1078 char *new_title,
1079 NautilusInformationPanel *panel)
1081 nautilus_sidebar_title_set_text (panel->details->title,
1082 new_title);
1085 /* ::style_set handler for the information_panel */
1086 static void
1087 nautilus_information_panel_style_set (GtkWidget *widget, GtkStyle *previous_style)
1089 NautilusInformationPanel *information_panel;
1091 information_panel = NAUTILUS_INFORMATION_PANEL (widget);
1093 nautilus_information_panel_theme_changed (information_panel);
1096 static void
1097 loading_uri_callback (NautilusWindowInfo *window,
1098 char *uri,
1099 NautilusInformationPanel *panel)
1101 char *title;
1103 title = nautilus_window_info_get_title (window);
1104 nautilus_information_panel_set_uri (panel,
1105 uri,
1106 title);
1107 g_free (title);
1110 static void
1111 nautilus_information_panel_set_parent_window (NautilusInformationPanel *panel,
1112 NautilusWindowInfo *window)
1114 char *title, *location;
1116 panel->details->window = window;
1118 g_signal_connect_object (window, "loading_uri",
1119 G_CALLBACK (loading_uri_callback), panel, 0);
1120 g_signal_connect_object (window, "title_changed",
1121 G_CALLBACK (title_changed_callback), panel, 0);
1123 title = nautilus_window_info_get_title (window);
1124 location = nautilus_window_info_get_current_location (window);
1125 nautilus_information_panel_set_uri (panel,
1126 location,
1127 title);
1128 g_free (location);
1129 g_free (title);
1132 static NautilusSidebar *
1133 nautilus_information_panel_create (NautilusSidebarProvider *provider,
1134 NautilusWindowInfo *window)
1136 NautilusInformationPanel *panel;
1138 panel = g_object_new (nautilus_information_panel_get_type (), NULL);
1139 nautilus_information_panel_set_parent_window (panel, window);
1140 g_object_ref (panel);
1141 gtk_object_sink (GTK_OBJECT (panel));
1143 return NAUTILUS_SIDEBAR (panel);
1146 static void
1147 sidebar_provider_iface_init (NautilusSidebarProviderIface *iface)
1149 iface->create = nautilus_information_panel_create;
1152 static void
1153 nautilus_information_panel_provider_init (NautilusInformationPanelProvider *sidebar)
1157 static void
1158 nautilus_information_panel_provider_class_init (NautilusInformationPanelProviderClass *class)
1162 void
1163 nautilus_information_panel_register (void)
1165 nautilus_module_add_type (nautilus_information_panel_provider_get_type ());