/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ /* caja-directory-background.c: Helper for the background of a widget that is viewing a particular location. Copyright (C) 2000 Eazel, Inc. Copyright (C) 2012 Jasmine Hassan <jasmine.aura@gmail.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. Authors: Darin Adler <darin@bentspoon.com> Jasmine Hassan <jasmine.aura@gmail.com> */ #include <config.h> #include "caja-directory-background.h" #include <eel/eel-gdk-extensions.h> #include <eel/eel-gtk-extensions.h> #include <eel/eel-background.h> #include "caja-dnd.h" #include "caja-global-preferences.h" #include "caja-metadata.h" #include "caja-file-attributes.h" #include <gtk/gtk.h> #include <string.h> #define MATE_DESKTOP_USE_UNSTABLE_API #include <libmate-desktop/mate-bg.h> static void caja_background_changed_cb (EelBackground *background, GdkDragAction action, CajaFile *file); static void caja_background_get_default_settings (char **color, char **image) { gboolean background_set; background_set = g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_BACKGROUND_SET); if (background_set && color) *color = g_settings_get_string (caja_preferences, CAJA_PREFERENCES_BACKGROUND_COLOR); if (background_set && image) *image = g_settings_get_string (caja_preferences, CAJA_PREFERENCES_BACKGROUND_URI); } static void caja_background_load_from_file_metadata (CajaFile *file, EelBackground *background) { char *color, *image; g_assert (EEL_IS_BACKGROUND (background)); g_assert (CAJA_IS_FILE (file)); g_assert (g_object_get_data (G_OBJECT (background), "eel_background_file") == file); color = caja_file_get_metadata (file, CAJA_METADATA_KEY_LOCATION_BACKGROUND_COLOR, NULL); image = caja_file_get_metadata (file, CAJA_METADATA_KEY_LOCATION_BACKGROUND_IMAGE, NULL); /* if there's none, read the default from the theme */ if (color == NULL && image == NULL) caja_background_get_default_settings (&color, &image); /* Block the other handler while we are responding to changes * in the metadata so it doesn't try to change the metadata. */ g_signal_handlers_block_by_func (background, G_CALLBACK (caja_background_changed_cb), file); eel_background_set_color (background, color); /* non-tiled only available for desktop, at least for now */ eel_bg_set_placement (background, MATE_BG_PLACEMENT_TILED); eel_background_set_image_uri (background, image); /* Unblock the handler. */ g_signal_handlers_unblock_by_func (background, G_CALLBACK (caja_background_changed_cb), file); g_free (color); g_free (image); } /* handle the file changed signal */ static void caja_background_settings_notify_cb (CajaFile *file, EelBackground *background) { caja_background_load_from_file_metadata (file, background); } /* handle the theme changing */ static void caja_background_theme_notify_cb (GSettings *settings, const gchar *key, gpointer user_data) { CajaFile *file; EelBackground *background = EEL_BACKGROUND (user_data); file = g_object_get_data (G_OBJECT (background), "eel_background_file"); if (file) caja_background_settings_notify_cb (file, background); } /* handle the background changed signal */ static void caja_background_changed_cb (EelBackground *background, GdkDragAction action, CajaFile *file) { g_assert (EEL_IS_BACKGROUND (background)); g_assert (CAJA_IS_FILE (file)); g_assert (g_object_get_data (G_OBJECT (background), "eel_background_file") == file); char *color = eel_background_get_color (background); char *image = eel_background_get_image_uri (background); /* Block the other handler while we are writing metadata so it doesn't * try to change the background. */ g_signal_handlers_block_by_func (file, G_CALLBACK (caja_background_settings_notify_cb), background); if (action != (GdkDragAction) CAJA_DND_ACTION_SET_AS_FOLDER_BACKGROUND && action != (GdkDragAction) CAJA_DND_ACTION_SET_AS_GLOBAL_BACKGROUND) { action = (GdkDragAction) GPOINTER_TO_INT (g_object_get_data (G_OBJECT (background), "default_drag_action")); } if (action == (GdkDragAction) CAJA_DND_ACTION_SET_AS_GLOBAL_BACKGROUND) { caja_file_set_metadata (file, CAJA_METADATA_KEY_LOCATION_BACKGROUND_COLOR, NULL, NULL); caja_file_set_metadata (file, CAJA_METADATA_KEY_LOCATION_BACKGROUND_IMAGE, NULL, NULL); g_signal_handlers_block_by_func (caja_preferences, G_CALLBACK (caja_background_theme_notify_cb), background); g_settings_set_string (caja_preferences, CAJA_PREFERENCES_BACKGROUND_COLOR, color ? color : ""); g_settings_set_string (caja_preferences, CAJA_PREFERENCES_BACKGROUND_URI, image ? image : ""); g_settings_set_boolean (caja_preferences, CAJA_PREFERENCES_BACKGROUND_SET, TRUE); g_signal_handlers_unblock_by_func (caja_preferences, G_CALLBACK (caja_background_theme_notify_cb), background); } else { caja_file_set_metadata (file, CAJA_METADATA_KEY_LOCATION_BACKGROUND_COLOR, NULL, color); caja_file_set_metadata (file, CAJA_METADATA_KEY_LOCATION_BACKGROUND_IMAGE, NULL, image); } /* Unblock the handler. */ g_signal_handlers_unblock_by_func (file, G_CALLBACK (caja_background_settings_notify_cb), background); g_free (color); g_free (image); } /* handle the background reset signal by setting values from the current theme */ static void caja_background_reset_cb (EelBackground *background, CajaFile *file) { char *color, *image; /* Block the other handler while we are writing metadata so it doesn't * try to change the background. */ g_signal_handlers_block_by_func (file, G_CALLBACK (caja_background_settings_notify_cb), background); color = caja_file_get_metadata (file, CAJA_METADATA_KEY_LOCATION_BACKGROUND_COLOR, NULL); image = caja_file_get_metadata (file, CAJA_METADATA_KEY_LOCATION_BACKGROUND_IMAGE, NULL); if (!color && !image) { g_signal_handlers_block_by_func (caja_preferences, G_CALLBACK (caja_background_theme_notify_cb), background); g_settings_set_boolean (caja_preferences, CAJA_PREFERENCES_BACKGROUND_SET, FALSE); g_signal_handlers_unblock_by_func (caja_preferences, G_CALLBACK (caja_background_theme_notify_cb), background); } else { /* reset the metadata */ caja_file_set_metadata (file, CAJA_METADATA_KEY_LOCATION_BACKGROUND_COLOR, NULL, NULL); caja_file_set_metadata (file, CAJA_METADATA_KEY_LOCATION_BACKGROUND_IMAGE, NULL, NULL); } g_free (color); g_free (image); /* Unblock the handler. */ g_signal_handlers_unblock_by_func (file, G_CALLBACK (caja_background_settings_notify_cb), background); caja_background_settings_notify_cb (file, background); } /* handle the background destroyed signal */ static void caja_background_weak_notify (gpointer data, GObject *background) { CajaFile *file = CAJA_FILE (data); g_signal_handlers_disconnect_by_func (file, G_CALLBACK (caja_background_settings_notify_cb), background); caja_file_monitor_remove (file, background); g_signal_handlers_disconnect_by_func (caja_preferences, caja_background_theme_notify_cb, background); } /* key routine that hooks up a background and location */ void caja_connect_background_to_file_metadata (GtkWidget *widget, CajaFile *file, GdkDragAction default_drag_action) { EelBackground *background; gpointer old_file; /* Get at the background object we'll be connecting. */ background = eel_get_widget_background (widget); /* Check if it is already connected. */ old_file = g_object_get_data (G_OBJECT (background), "eel_background_file"); if (old_file == file) return; /* Disconnect old signal handlers. */ if (old_file != NULL) { g_assert (CAJA_IS_FILE (old_file)); g_signal_handlers_disconnect_by_func (background, G_CALLBACK (caja_background_changed_cb), old_file); g_signal_handlers_disconnect_by_func (background, G_CALLBACK (caja_background_reset_cb), old_file); g_object_weak_unref (G_OBJECT (background), caja_background_weak_notify, old_file); g_signal_handlers_disconnect_by_func (old_file, G_CALLBACK (caja_background_settings_notify_cb), background); caja_file_monitor_remove (old_file, background); g_signal_handlers_disconnect_by_func (caja_preferences, caja_background_theme_notify_cb, background); } /* Attach the new directory. */ caja_file_ref (file); g_object_set_data_full (G_OBJECT (background), "eel_background_file", file, (GDestroyNotify) caja_file_unref); g_object_set_data (G_OBJECT (background), "default_drag_action", GINT_TO_POINTER (default_drag_action)); /* Connect new signal handlers. */ if (file != NULL) { g_signal_connect_object (background, "settings_changed", G_CALLBACK (caja_background_changed_cb), file, 0); g_signal_connect_object (background, "reset", G_CALLBACK (caja_background_reset_cb), file, 0); g_signal_connect_object (file, "changed", G_CALLBACK (caja_background_settings_notify_cb), background, 0); g_object_weak_ref (G_OBJECT (background), caja_background_weak_notify, file); /* arrange to receive file metadata */ caja_file_monitor_add (file, background, CAJA_FILE_ATTRIBUTE_INFO); /* arrange for notification when the theme changes */ g_signal_connect (caja_preferences, "changed::" CAJA_PREFERENCES_BACKGROUND_SET, G_CALLBACK(caja_background_theme_notify_cb), background); g_signal_connect (caja_preferences, "changed::" CAJA_PREFERENCES_BACKGROUND_COLOR, G_CALLBACK(caja_background_theme_notify_cb), background); g_signal_connect (caja_preferences, "changed::" CAJA_PREFERENCES_BACKGROUND_URI, G_CALLBACK(caja_background_theme_notify_cb), background); } /* Update the background based on the file metadata. */ caja_background_load_from_file_metadata (file, background); } /** * DESKTOP BACKGROUND HANDLING */ /* handle the desktop background "settings_changed" signal */ static void desktop_background_changed_cb (EelBackground *background, GdkDragAction action, gpointer user_data) { eel_bg_save_to_gsettings (background, mate_background_preferences); } /* delayed initializor of desktop background after GSettings changes */ static gboolean desktop_background_prefs_change_event_idle_cb (EelBackground *background) { eel_bg_load_from_gsettings (background, mate_background_preferences); eel_background_set_color (background, eel_bg_get_desktop_color (background)); g_object_unref (background); return FALSE; /* remove from the list of event sources */ } /* handle the desktop background "reset" signal: reset to schema's defaults */ static void desktop_background_reset_cb (EelBackground *background, gpointer user_data) { /* Reset to defaults, and save */ eel_bg_load_from_system_gsettings (background, mate_background_preferences, TRUE); /* Reload from saved settings */ g_idle_add ((GSourceFunc) desktop_background_prefs_change_event_idle_cb, g_object_ref (background)); } /* handle the desktop GSettings "change-event" (batch changes) signal */ static gboolean desktop_background_prefs_change_event_cb (GSettings *settings, gpointer keys, gint n_keys, gpointer user_data) { EelBackground *background = user_data; /* Defer signal processing to avoid making the dconf backend deadlock, and * hold a ref to avoid accessing fields of an object that was destroyed. */ g_idle_add ((GSourceFunc) desktop_background_prefs_change_event_idle_cb, g_object_ref (background)); return FALSE; /* let the event propagate further */ } static void desktop_background_weak_notify (gpointer data, GObject *object) { g_signal_handlers_disconnect_by_func (mate_background_preferences, G_CALLBACK (desktop_background_prefs_change_event_cb), object); } void caja_connect_desktop_background_to_settings (CajaIconContainer *icon_container) { EelBackground *background; background = eel_get_widget_background (GTK_WIDGET (icon_container)); eel_background_set_desktop (background, GTK_WIDGET (icon_container), TRUE); g_signal_connect_object (background, "settings_changed", G_CALLBACK (desktop_background_changed_cb), NULL, 0); g_signal_connect_object (background, "reset", G_CALLBACK (desktop_background_reset_cb), NULL, 0); eel_bg_load_from_gsettings (background, mate_background_preferences); /* Connect to "change-event" signal to receive *groups of changes* before * they are split out into multiple emissions of the "changed" signal. */ g_signal_connect (mate_background_preferences, "change-event", G_CALLBACK (desktop_background_prefs_change_event_cb), background); g_object_weak_ref (G_OBJECT (background), desktop_background_weak_notify, NULL); }