1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
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>
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
{
57 NautilusWindowInfo
*window
;
58 NautilusSidebarTitle
*title
;
59 GtkHBox
*button_box_centerer
;
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
,
82 GtkSelectionData
*selection_data
,
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);
104 static guint signals
[LAST_SIGNAL
];
106 /* drag and drop definitions */
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
}
130 } InformationPanelPart
;
134 } NautilusInformationPanelProvider
;
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
));
153 nautilus_information_panel_get_sidebar_id (NautilusSidebar
*sidebar
)
155 return NAUTILUS_INFORMATION_PANEL_ID
;
159 nautilus_information_panel_get_tab_label (NautilusSidebar
*sidebar
)
161 return g_strdup (_("Information"));
165 nautilus_information_panel_get_tab_tooltip (NautilusSidebar
*sidebar
)
167 return g_strdup (_("Show Information"));
171 nautilus_information_panel_get_tab_icon (NautilusSidebar
*sidebar
)
177 nautilus_information_panel_is_visible_changed (NautilusSidebar
*sidebar
,
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 */
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
212 G_TYPE_FROM_CLASS (klass
),
214 G_STRUCT_OFFSET (NautilusInformationPanelClass
,
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 */
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
),
235 information_panel
->details
->has_buttons
= FALSE
;
238 /* initialize the instance's fields, create the necessary subviews, etc. */
241 nautilus_information_panel_init (NautilusInformationPanel
*information_panel
)
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
);
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
,
305 eel_preferences_remove_callback (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_COLOR
,
306 nautilus_information_panel_theme_changed
,
308 eel_preferences_remove_callback (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_FILENAME
,
309 nautilus_information_panel_theme_changed
,
312 EEL_CALL_PARENT (G_OBJECT_CLASS
, finalize
, (object
));
315 /* callback to handle resetting the background */
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
);
328 information_panel_has_background (NautilusInformationPanel
*information_panel
)
330 EelBackground
*background
;
331 gboolean has_background
;
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 */
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);
366 /* set up the default backgrounds and images */
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 */
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
)) ;
416 static InformationPanelPart
417 hit_test (NautilusInformationPanel
*information_panel
,
420 if (nautilus_sidebar_title_hit_test_icon (information_panel
->details
->title
, x
, y
)) {
424 if (eel_point_in_widget (GTK_WIDGET (information_panel
), x
, y
)) {
425 return BACKGROUND_PART
;
431 /* utility to test if a uri refers to a local image */
433 uri_is_local_image (const char *uri
)
438 image_path
= g_filename_from_uri (uri
, NULL
, NULL
);
439 if (image_path
== NULL
) {
443 pixbuf
= gdk_pixbuf_new_from_file (image_path
, NULL
);
446 if (pixbuf
== NULL
) {
449 g_object_unref (pixbuf
);
454 receive_dropped_uri_list (NautilusInformationPanel
*information_panel
,
455 GdkDragAction action
,
457 GtkSelectionData
*selection_data
)
460 gboolean exactly_one
;
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
)) {
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
);
479 eel_background_receive_dropped_background_image
480 (eel_get_widget_background (GTK_WIDGET (information_panel
)),
484 } else if (exactly_one
) {
485 g_signal_emit (information_panel
,
486 signals
[LOCATION_CHANGED
], 0,
491 /* handle images dropped on the logo specially */
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."),
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
,
507 nautilus_file_set_metadata (information_panel
->details
->file
,
508 NAUTILUS_METADATA_KEY_ICON_SCALE
,
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."),
523 eel_show_error_dialog (
524 _("The file that you dropped is not an image."),
525 _("You can only use images as custom icons."),
537 receive_dropped_color (NautilusInformationPanel
*information_panel
,
538 GdkDragAction action
,
540 GtkSelectionData
*selection_data
)
545 if (selection_data
->length
!= 8 || selection_data
->format
!= 16) {
546 g_warning ("received invalid color data");
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
)) {
556 g_warning ("dropped color, but not on any part of information_panel");
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
);
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
);
576 /* handle receiving a dropped keyword */
579 receive_dropped_keyword (NautilusInformationPanel
*information_panel
,
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
);
590 nautilus_information_panel_drag_data_received (GtkWidget
*widget
, GdkDragContext
*context
,
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
);
603 case TARGET_GNOME_URI_LIST
:
604 case TARGET_URI_LIST
:
605 receive_dropped_uri_list (information_panel
, context
->action
, x
, y
, selection_data
);
608 receive_dropped_color (information_panel
, context
->action
, x
, y
, selection_data
);
611 if (hit_test (information_panel
, x
, y
) == BACKGROUND_PART
)
612 receive_dropped_uri_list (information_panel
, context
->action
, x
, y
, selection_data
);
614 case TARGET_BACKGROUND_RESET
:
615 background
= eel_get_widget_background ( GTK_WIDGET (information_panel
));
616 if (background
!= NULL
) {
617 eel_background_reset (background
);
621 receive_dropped_keyword (information_panel
, x
, y
, selection_data
);
624 g_warning ("unknown drop type");
628 /* handle the context menu if necessary */
630 nautilus_information_panel_press_event (GtkWidget
*widget
, GdkEventButton
*event
)
632 NautilusInformationPanel
*information_panel
;
635 if (widget
->window
!= event
->window
) {
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
,
653 value_different (const char *a
, const char *b
)
661 return strcmp (a
, b
);
664 /* Handle the background changed signal by writing out the settings to metadata.
667 background_settings_changed_callback (EelBackground
*background
, GdkDragAction action
, NautilusInformationPanel
*information_panel
)
672 g_assert (EEL_IS_BACKGROUND (background
));
673 g_assert (NAUTILUS_IS_INFORMATION_PANEL (information_panel
));
675 if (information_panel
->details
->file
== NULL
) {
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
),
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
,
694 nautilus_file_set_metadata (information_panel
->details
->file
,
695 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE
,
700 (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_COLOR
, color
? color
: "");
702 (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_FILENAME
, image
? image
: "");
703 eel_preferences_set_boolean
704 (NAUTILUS_PREFERENCES_SIDE_PANE_BACKGROUND_SET
, TRUE
);
706 nautilus_file_set_metadata (information_panel
->details
->file
,
707 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR
,
711 nautilus_file_set_metadata (information_panel
->details
->file
,
712 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_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
);
730 g_signal_handlers_unblock_by_func (information_panel
->details
->file
,
731 G_CALLBACK (background_metadata_changed_callback
),
735 /* handle the background reset signal by writing out NULL to metadata and setting the backgrounds
736 fields to their default values */
738 background_reset_callback (EelBackground
*background
, NautilusInformationPanel
*information_panel
)
742 g_assert (EEL_IS_BACKGROUND (background
));
743 g_assert (NAUTILUS_IS_INFORMATION_PANEL (information_panel
));
745 if (information_panel
->details
->file
== NULL
) {
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
),
755 color
= nautilus_file_get_metadata (information_panel
->details
->file
,
756 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR
,
759 image
= nautilus_file_get_metadata (information_panel
->details
->file
,
760 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE
,
762 if (color
|| image
) {
763 nautilus_file_set_metadata (information_panel
->details
->file
,
764 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_COLOR
,
768 nautilus_file_set_metadata (information_panel
->details
->file
,
769 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE
,
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
),
780 /* Force a read from the metadata to set the defaults
782 background_metadata_changed_callback (information_panel
);
786 nautilus_information_panel_get_window (NautilusInformationPanel
*information_panel
)
790 result
= gtk_widget_get_ancestor (GTK_WIDGET (information_panel
), GTK_TYPE_WINDOW
);
792 return result
== NULL
? NULL
: GTK_WINDOW (result
);
796 command_button_callback (GtkWidget
*button
, GAppInfo
*application
)
798 NautilusInformationPanel
*information_panel
;
801 information_panel
= NAUTILUS_INFORMATION_PANEL (g_object_get_data (G_OBJECT (button
), "user_data"));
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 */
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 */
824 add_command_buttons (NautilusInformationPanel
*information_panel
, GList
*application_list
)
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
);
842 gtk_box_pack_start (GTK_BOX (information_panel
->details
->button_box
),
847 g_signal_connect_data (temp_button
,
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 */
863 add_buttons_from_metadata (NautilusInformationPanel
*information_panel
, const char *button_data
)
866 char *current_term
, *temp_str
;
867 char *button_name
, *command_string
;
870 GtkWidget
*temp_button
;
872 /* split the button specification into a set of terms */
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
, '=');
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
),
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
,
897 G_CALLBACK (metadata_button_callback
),
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
);
914 * nautilus_information_panel_update_buttons:
916 * Update the list of program-launching buttons based on the current uri.
919 nautilus_information_panel_update_buttons (NautilusInformationPanel
*information_panel
)
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
,
936 add_buttons_from_metadata (information_panel
, 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
));
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
,
974 background_image
= nautilus_file_get_metadata (information_panel
->details
->file
,
975 NAUTILUS_METADATA_KEY_SIDEBAR_BACKGROUND_IMAGE
,
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
),
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
),
1013 background_metadata_changed_callback (NautilusInformationPanel
*information_panel
)
1015 NautilusFileAttributes attributes
;
1018 attributes
= nautilus_mime_actions_get_required_file_attributes ();
1019 ready
= nautilus_file_check_if_ready (information_panel
->details
->file
, attributes
);
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 */
1032 nautilus_information_panel_set_uri (NautilusInformationPanel
*information_panel
,
1033 const char* new_uri
,
1034 const char* initial_title
)
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
)) {
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
,
1077 title_changed_callback (NautilusWindowInfo
*window
,
1079 NautilusInformationPanel
*panel
)
1081 nautilus_sidebar_title_set_text (panel
->details
->title
,
1085 /* ::style_set handler for the information_panel */
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
);
1097 loading_uri_callback (NautilusWindowInfo
*window
,
1099 NautilusInformationPanel
*panel
)
1103 title
= nautilus_window_info_get_title (window
);
1104 nautilus_information_panel_set_uri (panel
,
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
,
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
);
1147 sidebar_provider_iface_init (NautilusSidebarProviderIface
*iface
)
1149 iface
->create
= nautilus_information_panel_create
;
1153 nautilus_information_panel_provider_init (NautilusInformationPanelProvider
*sidebar
)
1158 nautilus_information_panel_provider_class_init (NautilusInformationPanelProviderClass
*class)
1163 nautilus_information_panel_register (void)
1165 nautilus_module_add_type (nautilus_information_panel_provider_get_type ());