1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
4 nautilus-directory-background.c: Helper for the background of a widget
5 that is viewing a particular location.
7 Copyright (C) 2000 Eazel, Inc.
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU General Public
20 License along with this program; if not, write to the
21 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.
24 Author: Darin Adler <darin@bentspoon.com>
28 #include "nautilus-directory-background.h"
30 #include <eel/eel-gdk-extensions.h>
31 #include <eel/eel-gtk-extensions.h>
32 #include <eel/eel-background.h>
33 #include "nautilus-dnd.h"
34 #include "nautilus-global-preferences.h"
35 #include "nautilus-metadata.h"
36 #include "nautilus-file-attributes.h"
37 #include <gtk/gtkmain.h>
38 #include <libbackground/preferences.h>
40 static void background_changed_callback (EelBackground
*background
,
43 static void background_reset_callback (EelBackground
*background
,
46 static void saved_settings_changed_callback (NautilusFile
*file
,
47 EelBackground
*background
);
49 static void nautilus_file_background_receive_gconf_changes (EelBackground
*background
);
51 static void nautilus_file_background_write_desktop_settings (char *color
,
53 EelBackgroundImagePlacement placement
);
54 static void nautilus_file_background_theme_changed (gpointer user_data
);
57 nautilus_connect_desktop_background_to_file_metadata (NautilusIconContainer
*icon_container
,
60 EelBackground
*background
;
62 background
= eel_get_widget_background (GTK_WIDGET (icon_container
));
64 eel_background_set_desktop (background
, GTK_WIDGET (icon_container
), TRUE
);
66 /* Strictly speaking, we don't need to know about metadata changes, since
67 * the desktop setting aren't stored there. But, hooking up to metadata
68 * changes is actually a small part of what this fn does, and we do need
69 * the other stuff (hooked up to background & theme changes, initialize
70 * the background). Being notified of metadata changes on the file is a
71 * waste, but won't hurt, so I don't think it's worth refactoring the fn
74 nautilus_connect_background_to_file_metadata (GTK_WIDGET (icon_container
), file
, NAUTILUS_DND_ACTION_SET_AS_FOLDER_BACKGROUND
);
76 nautilus_file_background_receive_gconf_changes (background
);
80 nautilus_file_background_get_default_settings (char **color
,
82 EelBackgroundImagePlacement
*placement
)
84 gboolean background_set
;
86 background_set
= eel_preferences_get_boolean
87 (NAUTILUS_PREFERENCES_BACKGROUND_SET
);
89 if (background_set
&& color
) {
90 *color
= eel_preferences_get (NAUTILUS_PREFERENCES_BACKGROUND_COLOR
);
93 if (background_set
&& image
) {
94 *image
= eel_preferences_get (NAUTILUS_PREFERENCES_BACKGROUND_FILENAME
);
98 *placement
= EEL_BACKGROUND_TILED
;
104 nautilus_file_background_read_desktop_settings (char **color
,
106 EelBackgroundImagePlacement
*placement
)
110 gboolean use_gradient
;
111 gboolean is_horizontal
;
113 BGPreferences
*prefs
;
115 prefs
= BG_PREFERENCES (bg_preferences_new ());
117 bg_preferences_load (prefs
);
119 if (prefs
->wallpaper_enabled
) {
120 if (prefs
->wallpaper_filename
!= NULL
&&
121 prefs
->wallpaper_filename
[0] != '\0') {
122 *image
= g_filename_to_uri (prefs
->wallpaper_filename
, NULL
, NULL
);
131 switch (prefs
->wallpaper_type
) {
133 g_assert_not_reached ();
135 /* case WPTYPE_EMBOSSED:*/
136 /* FIXME bugzilla.gnome.org 42193: we don't support embossing.
137 * Just treat it as centered - ugh.
139 case WPTYPE_CENTERED
:
140 *placement
= EEL_BACKGROUND_CENTERED
;
143 *placement
= EEL_BACKGROUND_TILED
;
145 case WPTYPE_STRETCHED
:
146 *placement
= EEL_BACKGROUND_SCALED
;
149 *placement
= EEL_BACKGROUND_SCALED_ASPECT
;
152 *placement
= EEL_BACKGROUND_ZOOM
;
156 end_color
= eel_gdk_rgb_to_color_spec (eel_gdk_color_to_rgb (prefs
->color2
));
157 start_color
= eel_gdk_rgb_to_color_spec (eel_gdk_color_to_rgb (prefs
->color1
));
158 use_gradient
= prefs
->gradient_enabled
;
159 is_horizontal
= (prefs
->orientation
== ORIENTATION_HORIZ
);
162 *color
= eel_gradient_new (start_color
, end_color
, is_horizontal
);
164 *color
= g_strdup (start_color
);
167 g_free (start_color
);
170 g_object_unref (prefs
);
174 nautilus_file_background_write_desktop_settings (char *color
, char *image
, EelBackgroundImagePlacement placement
)
178 char *original_filename
;
180 wallpaper_type_t wallpaper_align
;
181 BGPreferences
*prefs
;
183 prefs
= BG_PREFERENCES (bg_preferences_new ());
184 bg_preferences_load (prefs
);
187 start_color
= eel_gradient_get_start_color_spec (color
);
188 gdk_color_parse (start_color
, prefs
->color1
);
189 g_free (start_color
);
191 /* if color is not a gradient, this ends up writing same as start_color */
192 end_color
= eel_gradient_get_end_color_spec (color
);
193 gdk_color_parse (end_color
, prefs
->color2
);
196 if (eel_gradient_is_gradient (color
)) {
197 prefs
->gradient_enabled
= TRUE
;
198 prefs
->orientation
= eel_gradient_is_horizontal (color
) ? ORIENTATION_HORIZ
: ORIENTATION_VERT
;
200 prefs
->gradient_enabled
= FALSE
;
201 prefs
->orientation
= ORIENTATION_SOLID
;
204 /* We set it to white here because that's how backgrounds with a NULL color
205 * are drawn by Nautilus - due to usage of eel_gdk_color_parse_with_white_default.
207 gdk_color_parse ("#FFFFFF", prefs
->color1
);
208 gdk_color_parse ("#FFFFFF", prefs
->color2
);
209 prefs
->gradient_enabled
= FALSE
;
210 prefs
->orientation
= ORIENTATION_SOLID
;
213 original_filename
= prefs
->wallpaper_filename
;
215 prefs
->wallpaper_filename
= g_filename_from_uri (image
, NULL
, NULL
);
216 prefs
->wallpaper_enabled
= TRUE
;
218 case EEL_BACKGROUND_TILED
:
219 wallpaper_align
= WPTYPE_TILED
;
221 case EEL_BACKGROUND_CENTERED
:
222 wallpaper_align
= WPTYPE_CENTERED
;
224 case EEL_BACKGROUND_SCALED
:
225 wallpaper_align
= WPTYPE_STRETCHED
;
227 case EEL_BACKGROUND_SCALED_ASPECT
:
228 wallpaper_align
= WPTYPE_SCALED
;
230 case EEL_BACKGROUND_ZOOM
:
231 wallpaper_align
= WPTYPE_ZOOM
;
234 g_assert_not_reached ();
235 wallpaper_align
= WPTYPE_TILED
;
239 prefs
->wallpaper_type
= wallpaper_align
;
241 prefs
->wallpaper_enabled
= FALSE
;
242 prefs
->wallpaper_filename
= g_strdup (original_filename
);
244 g_free (original_filename
);
246 bg_preferences_save (prefs
);
247 g_object_unref (prefs
);
251 nautilus_file_background_write_desktop_default_settings (void)
253 /* We just unset all the gconf keys so they go back to
259 client
= gconf_client_get_default ();
260 set
= gconf_change_set_new ();
262 /* the list of keys here has to be kept in sync with libgnome
263 * schemas, which isn't the most maintainable thing ever.
265 gconf_change_set_unset (set
, "/desktop/gnome/background/picture_options");
266 gconf_change_set_unset (set
, "/desktop/gnome/background/picture_filename");
267 gconf_change_set_unset (set
, "/desktop/gnome/background/picture_opacity");
268 gconf_change_set_unset (set
, "/desktop/gnome/background/primary_color");
269 gconf_change_set_unset (set
, "/desktop/gnome/background/secondary_color");
270 gconf_change_set_unset (set
, "/desktop/gnome/background/color_shading_type");
272 /* this isn't atomic yet so it'll be a bit inefficient, but
273 * someday it might be atomic.
275 gconf_client_commit_change_set (client
, set
, FALSE
, NULL
);
277 gconf_change_set_unref (set
);
279 g_object_unref (G_OBJECT (client
));
283 call_settings_changed (EelBackground
*background
)
286 file
= g_object_get_data (G_OBJECT (background
), "eel_background_file");
288 saved_settings_changed_callback (file
, background
);
290 g_object_set_data (G_OBJECT (background
), "desktop_gconf_notification_timeout", GUINT_TO_POINTER (0));
295 desktop_background_destroyed_callback (EelBackground
*background
, void *georgeWBush
)
297 guint notification_id
;
298 guint notification_timeout_id
;
300 notification_id
= GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (background
), "desktop_gconf_notification"));
301 eel_gconf_notification_remove (notification_id
);
303 notification_timeout_id
= GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (background
), "desktop_gconf_notification_timeout"));
304 if (notification_timeout_id
!= 0) {
305 g_source_remove (notification_timeout_id
);
310 desktop_background_gconf_notify_cb (GConfClient
*client
, guint notification_id
, GConfEntry
*entry
, gpointer data
)
312 EelBackground
*background
;
313 guint notification_timeout_id
;
315 background
= EEL_BACKGROUND (data
);
317 * Wallpaper capplet changes picture, background color and placement with
318 * gconf_change_set API, but unfortunately, this operation is not atomic in
319 * GConf as it should be. So we update background after small timeout to
320 * let GConf change all values.
322 notification_timeout_id
= g_timeout_add (300, (GSourceFunc
) call_settings_changed
, background
);
324 g_object_set_data (G_OBJECT (background
), "desktop_gconf_notification_timeout", GUINT_TO_POINTER (notification_timeout_id
));
328 nautilus_file_background_receive_gconf_changes (EelBackground
*background
)
330 guint notification_id
;
332 eel_gconf_monitor_add ("/desktop/gnome/background");
333 notification_id
= eel_gconf_notification_add ("/desktop/gnome/background", desktop_background_gconf_notify_cb
, background
);
335 g_object_set_data (G_OBJECT (background
), "desktop_gconf_notification", GUINT_TO_POINTER (notification_id
));
337 g_signal_connect (background
, "destroy",
338 G_CALLBACK (desktop_background_destroyed_callback
), NULL
);
341 /* return true if the background is not in the default state */
343 nautilus_file_background_is_set (EelBackground
*background
)
350 color
= eel_background_get_color (background
);
351 image
= eel_background_get_image_uri (background
);
353 is_set
= (color
|| image
);
361 /* handle the background changed signal */
363 background_changed_callback (EelBackground
*background
,
364 GdkDragAction action
,
370 g_assert (EEL_IS_BACKGROUND (background
));
371 g_assert (NAUTILUS_IS_FILE (file
));
372 g_assert (g_object_get_data (G_OBJECT (background
), "eel_background_file") == file
);
375 color
= eel_background_get_color (background
);
376 image
= eel_background_get_image_uri (background
);
378 if (eel_background_is_desktop (background
)) {
379 nautilus_file_background_write_desktop_settings (color
, image
, eel_background_get_image_placement (background
));
381 /* Block the other handler while we are writing metadata so it doesn't
382 * try to change the background.
384 g_signal_handlers_block_by_func (
385 file
, G_CALLBACK (saved_settings_changed_callback
), background
);
387 if (action
!= NAUTILUS_DND_ACTION_SET_AS_FOLDER_BACKGROUND
&& action
!= NAUTILUS_DND_ACTION_SET_AS_GLOBAL_BACKGROUND
) {
388 GdkDragAction default_drag_action
;
390 default_drag_action
= GPOINTER_TO_INT (g_object_get_data (G_OBJECT (background
), "default_drag_action"));
393 action
= default_drag_action
;
396 if (action
== NAUTILUS_DND_ACTION_SET_AS_GLOBAL_BACKGROUND
) {
397 nautilus_file_set_metadata (file
,
398 NAUTILUS_METADATA_KEY_LOCATION_BACKGROUND_COLOR
,
402 nautilus_file_set_metadata (file
,
403 NAUTILUS_METADATA_KEY_LOCATION_BACKGROUND_IMAGE
,
408 (NAUTILUS_PREFERENCES_BACKGROUND_COLOR
, color
? color
: "");
410 (NAUTILUS_PREFERENCES_BACKGROUND_FILENAME
, image
? image
: "");
411 eel_preferences_set_boolean
412 (NAUTILUS_PREFERENCES_BACKGROUND_SET
, TRUE
);
414 nautilus_file_set_metadata (file
,
415 NAUTILUS_METADATA_KEY_LOCATION_BACKGROUND_COLOR
,
419 nautilus_file_set_metadata (file
,
420 NAUTILUS_METADATA_KEY_LOCATION_BACKGROUND_IMAGE
,
425 /* Unblock the handler. */
426 g_signal_handlers_unblock_by_func (
427 file
, G_CALLBACK (saved_settings_changed_callback
), background
);
435 initialize_background_from_settings (NautilusFile
*file
,
436 EelBackground
*background
)
440 EelBackgroundImagePlacement placement
;
442 g_assert (NAUTILUS_IS_FILE (file
));
443 g_assert (EEL_IS_BACKGROUND (background
));
444 g_assert (g_object_get_data (G_OBJECT (background
), "eel_background_file")
447 if (eel_background_is_desktop (background
)) {
448 nautilus_file_background_read_desktop_settings (&color
, &image
, &placement
);
450 color
= nautilus_file_get_metadata (file
,
451 NAUTILUS_METADATA_KEY_LOCATION_BACKGROUND_COLOR
,
453 image
= nautilus_file_get_metadata (file
,
454 NAUTILUS_METADATA_KEY_LOCATION_BACKGROUND_IMAGE
,
456 placement
= EEL_BACKGROUND_TILED
; /* non-tiled only avail for desktop, at least for now */
458 /* if there's none, read the default from the theme */
459 if (color
== NULL
&& image
== NULL
) {
460 nautilus_file_background_get_default_settings
461 (&color
, &image
, &placement
);
465 /* Block the other handler while we are responding to changes
466 * in the metadata so it doesn't try to change the metadata.
468 g_signal_handlers_block_by_func
470 G_CALLBACK (background_changed_callback
),
473 eel_background_set_color (background
, color
);
474 if (eel_background_is_desktop(background
)) {
475 eel_background_set_image_uri_sync (background
, image
);
478 eel_background_set_image_uri (background
, image
);
480 eel_background_set_image_placement (background
, placement
);
482 /* Unblock the handler. */
483 g_signal_handlers_unblock_by_func
485 G_CALLBACK (background_changed_callback
),
492 /* handle the file changed signal */
494 saved_settings_changed_callback (NautilusFile
*file
,
495 EelBackground
*background
)
497 initialize_background_from_settings (file
, background
);
500 /* handle the theme changing */
502 nautilus_file_background_theme_changed (gpointer user_data
)
505 EelBackground
*background
;
507 background
= EEL_BACKGROUND (user_data
);
508 file
= g_object_get_data (G_OBJECT (background
), "eel_background_file");
510 saved_settings_changed_callback (file
, background
);
514 /* handle the background reset signal by setting values from the current theme */
516 background_reset_callback (EelBackground
*background
,
522 if (eel_background_is_desktop (background
)) {
523 nautilus_file_background_write_desktop_default_settings ();
525 /* Block the other handler while we are writing metadata so it doesn't
526 * try to change the background.
528 g_signal_handlers_block_by_func (
530 G_CALLBACK (saved_settings_changed_callback
),
533 color
= nautilus_file_get_metadata (file
,
534 NAUTILUS_METADATA_KEY_LOCATION_BACKGROUND_COLOR
,
536 image
= nautilus_file_get_metadata (file
,
537 NAUTILUS_METADATA_KEY_LOCATION_BACKGROUND_IMAGE
,
539 if (!color
&& !image
) {
540 eel_preferences_set_boolean (NAUTILUS_PREFERENCES_BACKGROUND_SET
,
543 /* reset the metadata */
544 nautilus_file_set_metadata (file
,
545 NAUTILUS_METADATA_KEY_LOCATION_BACKGROUND_COLOR
,
549 nautilus_file_set_metadata (file
,
550 NAUTILUS_METADATA_KEY_LOCATION_BACKGROUND_IMAGE
,
557 /* Unblock the handler. */
558 g_signal_handlers_unblock_by_func (
560 G_CALLBACK (saved_settings_changed_callback
),
564 saved_settings_changed_callback (file
, background
);
567 /* handle the background destroyed signal */
569 background_destroyed_callback (EelBackground
*background
,
572 g_signal_handlers_disconnect_by_func
574 G_CALLBACK (saved_settings_changed_callback
), background
);
575 nautilus_file_monitor_remove (file
, background
);
576 eel_preferences_remove_callback (NAUTILUS_PREFERENCES_THEME
,
577 nautilus_file_background_theme_changed
,
579 eel_preferences_remove_callback (NAUTILUS_PREFERENCES_BACKGROUND_SET
,
580 nautilus_file_background_theme_changed
,
582 eel_preferences_remove_callback (NAUTILUS_PREFERENCES_BACKGROUND_COLOR
,
583 nautilus_file_background_theme_changed
,
585 eel_preferences_remove_callback (NAUTILUS_PREFERENCES_BACKGROUND_FILENAME
,
586 nautilus_file_background_theme_changed
,
590 /* key routine that hooks up a background and location */
592 nautilus_connect_background_to_file_metadata (GtkWidget
*widget
,
594 GdkDragAction default_drag_action
)
596 EelBackground
*background
;
599 /* Get at the background object we'll be connecting. */
600 background
= eel_get_widget_background (widget
);
602 /* Check if it is already connected. */
603 old_file
= g_object_get_data (G_OBJECT (background
), "eel_background_file");
604 if (old_file
== file
) {
608 /* Disconnect old signal handlers. */
609 if (old_file
!= NULL
) {
610 g_assert (NAUTILUS_IS_FILE (old_file
));
611 g_signal_handlers_disconnect_by_func
613 G_CALLBACK (background_changed_callback
), old_file
);
614 g_signal_handlers_disconnect_by_func
616 G_CALLBACK (background_destroyed_callback
), old_file
);
617 g_signal_handlers_disconnect_by_func
619 G_CALLBACK (background_reset_callback
), old_file
);
620 g_signal_handlers_disconnect_by_func
622 G_CALLBACK (saved_settings_changed_callback
), background
);
623 nautilus_file_monitor_remove (old_file
, background
);
624 eel_preferences_remove_callback (NAUTILUS_PREFERENCES_THEME
,
625 nautilus_file_background_theme_changed
,
627 eel_preferences_remove_callback (NAUTILUS_PREFERENCES_BACKGROUND_SET
,
628 nautilus_file_background_theme_changed
,
630 eel_preferences_remove_callback (NAUTILUS_PREFERENCES_BACKGROUND_COLOR
,
631 nautilus_file_background_theme_changed
,
633 eel_preferences_remove_callback (NAUTILUS_PREFERENCES_BACKGROUND_FILENAME
,
634 nautilus_file_background_theme_changed
,
639 /* Attach the new directory. */
640 nautilus_file_ref (file
);
641 g_object_set_data_full (G_OBJECT (background
), "eel_background_file",
642 file
, (GDestroyNotify
) nautilus_file_unref
);
644 g_object_set_data (G_OBJECT (background
), "default_drag_action", GINT_TO_POINTER (default_drag_action
));
646 /* Connect new signal handlers. */
648 g_signal_connect_object (background
, "settings_changed",
649 G_CALLBACK (background_changed_callback
), file
, 0);
650 g_signal_connect_object (background
, "destroy",
651 G_CALLBACK (background_destroyed_callback
), file
, 0);
652 g_signal_connect_object (background
, "reset",
653 G_CALLBACK (background_reset_callback
), file
, 0);
654 g_signal_connect_object (file
, "changed",
655 G_CALLBACK (saved_settings_changed_callback
), background
, 0);
657 /* arrange to receive file metadata */
658 nautilus_file_monitor_add (file
,
660 NAUTILUS_FILE_ATTRIBUTE_METADATA
);
662 /* arrange for notification when the theme changes */
663 eel_preferences_add_callback (NAUTILUS_PREFERENCES_THEME
,
664 nautilus_file_background_theme_changed
, background
);
665 eel_preferences_add_callback (NAUTILUS_PREFERENCES_BACKGROUND_SET
,
666 nautilus_file_background_theme_changed
, background
);
667 eel_preferences_add_callback (NAUTILUS_PREFERENCES_BACKGROUND_COLOR
,
668 nautilus_file_background_theme_changed
, background
);
669 eel_preferences_add_callback (NAUTILUS_PREFERENCES_BACKGROUND_FILENAME
,
670 nautilus_file_background_theme_changed
, background
);
673 /* Update the background based on the file metadata. */
674 initialize_background_from_settings (file
, background
);