/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Pix
*
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* 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, see .
*/
#include
#include
#include
#include
#include "actions.h"
#define DESKTOP_BACKGROUND_PROPERTIES_COMMAND "gnome-control-center background"
#define DESKTOP_BACKGROUND_PROPERTIES_UNITY_COMMAND "unity-control-center appearance"
#define DESKTOP_BACKGROUND_SCHEMA "org.gnome.desktop.background"
#define CINNAMON_DESKTOP_BACKGROUND_SCHEMA "org.cinnamon.desktop.background"
#define MATE_DESKTOP_BACKGROUND_SCHEMA "org.mate.background"
#define GNOME_DESKTOP_BACKGROUND_SCHEMA "org.gnome.desktop.background"
#define DESKTOP_BACKGROUND_FILE_KEY "picture-uri"
#define MATE_DESKTOP_BACKGROUND_FILE_KEY "picture-filename"
typedef struct {
GFile *file;
} WallpaperStyle;
typedef struct {
GthBrowser *browser;
WallpaperStyle old_style;
WallpaperStyle new_style;
gulong response_id;
} WallpaperData;
static void
wallpaper_style_init (WallpaperStyle *style)
{
style->file = NULL;
}
static void
wallpaper_style_init_from_current (WallpaperStyle *style)
{
GSettings *settings;
char *location;
if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "XFCE") == 0) {
// Don't support undo in Xfce
return;
}
if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Cinnamon") == 0 || g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "X-Cinnamon") == 0) {
settings = g_settings_new (CINNAMON_DESKTOP_BACKGROUND_SCHEMA);
}
else if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "MATE") == 0) {
settings = g_settings_new (MATE_DESKTOP_BACKGROUND_SCHEMA);
}
else {
settings = g_settings_new (GNOME_DESKTOP_BACKGROUND_SCHEMA);
}
if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "MATE") == 0) {
location = g_settings_get_string (settings, MATE_DESKTOP_BACKGROUND_FILE_KEY);
style->file = (location != NULL) ? g_file_new_for_path (location) : NULL;
}
else {
location = g_settings_get_string (settings, DESKTOP_BACKGROUND_FILE_KEY);
style->file = (location != NULL) ? g_file_new_for_uri (location) : NULL;
}
g_free (location);
g_object_unref (settings);
}
static void
wallpaper_style_set_as_current (WallpaperStyle *style)
{
char *location;
if (style->file == NULL)
return;
if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "XFCE") == 0) {
location = g_file_get_path(style->file);
gchar *command = g_strdup_printf("xfce4-set-wallpaper '%s'", location);
system(command);
g_free(command);
g_free(location);
return;
}
if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "MATE") == 0) {
location = g_file_get_path (style->file);
}
else {
location = g_file_get_uri (style->file);
}
if (location != NULL) {
GSettings *settings;
if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Cinnamon") == 0 || g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "X-Cinnamon") == 0) {
settings = g_settings_new (CINNAMON_DESKTOP_BACKGROUND_SCHEMA);
}
else if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "MATE") == 0) {
settings = g_settings_new (MATE_DESKTOP_BACKGROUND_SCHEMA);
}
else {
settings = g_settings_new (GNOME_DESKTOP_BACKGROUND_SCHEMA);
}
if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "MATE") == 0) {
g_settings_set_string (settings, MATE_DESKTOP_BACKGROUND_FILE_KEY, location);
}
else {
g_settings_set_string (settings, DESKTOP_BACKGROUND_FILE_KEY, location);
}
g_object_unref (settings);
}
g_free (location);
}
static void
wallpaper_style_free (WallpaperStyle *style)
{
_g_object_unref (style->file);
wallpaper_style_init (style);
}
/* -- get_new_wallpaper_file_async -- */
typedef struct {
GFile *folder;
int max_n;
GList *wallpaper_files;
GRegex *wallpaper_name_regex;
} NewWallpaperData;
static void
new_wallpaper_data_free (NewWallpaperData *data)
{
_g_object_unref (data->folder);
_g_string_list_free (data->wallpaper_files);
g_regex_unref (data->wallpaper_name_regex);
g_slice_free (NewWallpaperData, data);
}
static void
nw_for_each_file_func (GFile *file,
GFileInfo *info,
gpointer user_data)
{
GTask *task = user_data;
NewWallpaperData *nw_data = g_task_get_task_data (task);
const char *filename;
char **tokens;
filename = g_file_info_get_name (info);
tokens = g_regex_split (nw_data->wallpaper_name_regex, filename, 0);
if (g_strv_length (tokens) >= 2) {
int n = atoi (tokens[1]);
if (n > nw_data->max_n)
nw_data->max_n = n;
nw_data->wallpaper_files = g_list_prepend (nw_data->wallpaper_files, g_strdup (filename));
}
g_strfreev (tokens);
}
static void
nw_done_func (GError *error,
gpointer user_data)
{
GTask *task = user_data;
NewWallpaperData *nw_data = g_task_get_task_data (task);
GList *scan;
char *display_name;
GFile *proposed_file;
if (error != NULL) {
g_task_return_error (task, error);
g_object_unref (task);
return;
}
/* delete the old wallpapers */
for (scan = nw_data->wallpaper_files; scan; scan = scan->next) {
char *name = scan->data;
GFile *file;
file = g_file_get_child (nw_data->folder, name);
g_file_delete (file, NULL, NULL);
g_object_unref (file);
}
/* use a unique name to force a reload */
display_name = g_strdup_printf ("wallpaper%d.jpeg", nw_data->max_n + 1);
proposed_file = g_file_get_child_for_display_name (nw_data->folder, display_name, NULL);
g_task_return_pointer (task, proposed_file, g_object_unref);
g_free (display_name);
g_object_unref (task);
}
static void
get_new_wallpaper_file_async (GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
NewWallpaperData *nw_data;
GTask *task;
nw_data = g_slice_new (NewWallpaperData);
nw_data->folder = gth_user_dir_get_dir_for_write (GTH_DIR_DATA, PIX_DIR, NULL);
nw_data->max_n = 0;
nw_data->wallpaper_files = NULL;
nw_data->wallpaper_name_regex = g_regex_new ("wallpaper([0-9]+).jpeg", 0, 0, NULL);
task = g_task_new (NULL, cancellable, callback, user_data);
g_task_set_task_data (task, nw_data, (GDestroyNotify) new_wallpaper_data_free);
_g_directory_foreach_child (nw_data->folder,
FALSE,
FALSE,
GFILE_NAME_TYPE_ATTRIBUTES,
cancellable,
NULL,
nw_for_each_file_func,
nw_done_func,
task);
}
static GFile *
get_new_wallpaper_file_finish (GAsyncResult *result,
GError **error)
{
return g_task_propagate_pointer (G_TASK (result), error);
}
static WallpaperData *
wallpaper_data_new (GthBrowser *browser,
GFile *wallpaper_file)
{
WallpaperData *wdata;
wdata = g_new0 (WallpaperData, 1);
wdata->browser = browser;
wallpaper_style_init_from_current (&wdata->old_style);
wallpaper_style_init (&wdata->new_style);
wdata->new_style.file = g_object_ref (wallpaper_file);
return wdata;
}
static void
wallpaper_data_free (WallpaperData *wdata)
{
g_signal_handler_disconnect (gth_browser_get_infobar (wdata->browser), wdata->response_id);
wallpaper_style_free (&wdata->old_style);
wallpaper_style_free (&wdata->new_style);
g_free (wdata);
}
enum {
_RESPONSE_PREFERENCES = 1,
_RESPONSE_UNDO
};
static void
infobar_response_cb (GtkInfoBar *info_bar,
int response_id,
gpointer user_data)
{
WallpaperData *wdata = user_data;
const gchar *control_center_command = NULL;
GError *error = NULL;
g_return_if_fail (GTH_IS_BROWSER (wdata->browser));
switch (response_id) {
case _RESPONSE_PREFERENCES:
if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Cinnamon") == 0 || g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "X-Cinnamon") == 0)
control_center_command = "cinnamon-settings backgrounds";
else if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "MATE") == 0)
control_center_command = "mate-appearance-properties -p background";
else if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "XFCE") == 0)
control_center_command = "xfdesktop-settings";
else if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "GNOME") == 0)
control_center_command = "gnome-control-center appearance";
else if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity") == 0)
control_center_command = "unity-control-center appearance";
if (control_center_command != NULL && ! g_spawn_command_line_async (control_center_command, &error)) {
_gtk_error_dialog_from_gerror_run (GTK_WINDOW (wdata->browser), _("Could not show the desktop background properties"), error);
g_clear_error (&error);
}
break;
case _RESPONSE_UNDO:
wallpaper_style_set_as_current (&wdata->old_style);
break;
}
gtk_widget_hide (GTK_WIDGET (info_bar));
wallpaper_data_free (wdata);
}
static void
wallpaper_data_set__step2 (WallpaperData *wdata)
{
GtkWidget *infobar;
wallpaper_style_set_as_current (&wdata->new_style);
infobar = gth_browser_get_infobar (wdata->browser);
gth_info_bar_set_icon_name (GTH_INFO_BAR (infobar), "dialog-information-symbolic", GTK_ICON_SIZE_DIALOG);
{
char *name;
char *msg;
name = _g_file_get_display_name (wdata->new_style.file);
msg = g_strdup_printf ("The image \"%s\" has been set as desktop background", name);
gth_info_bar_set_primary_text (GTH_INFO_BAR (infobar), msg);
g_free (msg);
g_free (name);
}
_gtk_info_bar_clear_action_area (GTK_INFO_BAR (infobar));
gtk_orientable_set_orientation (GTK_ORIENTABLE (gtk_info_bar_get_action_area (GTK_INFO_BAR (infobar))), GTK_ORIENTATION_HORIZONTAL);
gtk_info_bar_set_message_type (GTK_INFO_BAR (infobar), GTK_MESSAGE_INFO);
gtk_info_bar_add_buttons (GTK_INFO_BAR (infobar),
_("_Preferences"), _RESPONSE_PREFERENCES,
_("_Undo"), _RESPONSE_UNDO,
_GTK_LABEL_CLOSE, GTK_RESPONSE_CLOSE,
NULL);
gtk_info_bar_set_response_sensitive (GTK_INFO_BAR (infobar),
_RESPONSE_UNDO,
wdata->old_style.file != NULL);
wdata->response_id = g_signal_connect (infobar,
"response",
G_CALLBACK (infobar_response_cb),
wdata);
gtk_widget_show (infobar);
}
static void
wallpaper_metadata_ready_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
WallpaperData *wdata = user_data;
GList *file_list;
GError *error = NULL;
GthFileData *file_data;
int image_width;
int image_height;
GdkRectangle monitor_geometry;
file_list = _g_query_metadata_finish (result, &error);
if (error != NULL) {
_gtk_error_dialog_from_gerror_run (GTK_WINDOW (wdata->browser), _("Could not set the desktop background"), error);
wallpaper_data_free (wdata);
return;
}
/* use ZOOM if the image has a size similar to the monitor's */
#if GTK_CHECK_VERSION(3, 22, 0)
gdk_monitor_get_geometry (gdk_display_get_monitor_at_window (gtk_widget_get_display (GTK_WIDGET (wdata->browser)), gtk_widget_get_window (GTK_WIDGET (wdata->browser))), &monitor_geometry);
#else
gdk_screen_get_monitor_geometry (gtk_widget_get_screen (GTK_WIDGET (wdata->browser)), 0, &monitor_geometry);
#endif
file_data = file_list->data;
image_width = g_file_info_get_attribute_int32 (file_data->info, "image::width");
image_height = g_file_info_get_attribute_int32 (file_data->info, "image::height");
wallpaper_data_set__step2 (wdata);
}
static void
wallpaper_data_set (WallpaperData *wdata)
{
GList *file_list;
file_list = g_list_append (NULL, gth_file_data_new (wdata->new_style.file, NULL));
_g_query_metadata_async (file_list,
"image::width,image::height",
NULL,
wallpaper_metadata_ready_cb,
wdata);
_g_object_list_unref (file_list);
}
static void
save_wallpaper_task_completed_cb (GthTask *task,
GError *error,
gpointer user_data)
{
WallpaperData *wdata = user_data;
if (error != NULL) {
_gtk_error_dialog_from_gerror_run (GTK_WINDOW (wdata->browser), _("Could not set the desktop background"), error);
wallpaper_data_free (wdata);
}
else
wallpaper_data_set (wdata);
_g_object_unref (task);
}
static void
copy_wallpaper_ready_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
WallpaperData *wdata = user_data;
GError *error = NULL;
if (! g_file_copy_finish (G_FILE (source_object), res, &error)) {
_gtk_error_dialog_from_gerror_run (GTK_WINDOW (wdata->browser), _("Could not set the desktop background"), error);
g_clear_error (&error);
wallpaper_data_free (wdata);
return;
}
wallpaper_data_set (wdata);
}
static void
wallpaper_file_read_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GthBrowser *browser = GTH_BROWSER (user_data);
GFile *wallpaper_file;
GError **error = NULL;
WallpaperData *wdata;
gboolean saving_wallpaper = FALSE;
GList *items;
GList *file_list;
GthFileData *file_data;
const char *mime_type;
wallpaper_file = get_new_wallpaper_file_finish (res, error);
if (wallpaper_file == NULL) {
_gtk_error_dialog_from_gerror_show (GTK_WINDOW (browser), _("Could not set the desktop background"), *error);
g_clear_error (error);
return;
}
wdata = wallpaper_data_new (browser, wallpaper_file);
g_object_unref (wallpaper_file);
items = gth_file_selection_get_selected (GTH_FILE_SELECTION (gth_browser_get_file_list_view (browser)));
file_list = gth_file_list_get_files (GTH_FILE_LIST (gth_browser_get_file_list (browser)), items);
file_data = (file_list != NULL) ? file_list->data : NULL;
mime_type = (file_data != NULL) ? gth_file_data_get_mime_type (file_data) : NULL;
if (gth_main_extension_is_active ("image_viewer")
&& (gth_browser_get_file_modified (browser) || ! _gdk_pixbuf_mime_type_is_readable (mime_type)))
{
GthViewerPage *viewer_page;
viewer_page = gth_browser_get_viewer_page (browser);
if (viewer_page != NULL) {
GthImage *image;
GthTask *task;
if (gth_image_viewer_page_get_is_modified (GTH_IMAGE_VIEWER_PAGE (viewer_page)))
image = gth_image_new_for_surface (gth_image_viewer_page_get_modified_image (GTH_IMAGE_VIEWER_PAGE (viewer_page)));
else
image = gth_image_new_for_surface (gth_image_viewer_page_get_current_image (GTH_IMAGE_VIEWER_PAGE (viewer_page)));
file_data = gth_file_data_new (wdata->new_style.file, NULL);
task = gth_save_image_task_new (image,
"image/jpeg",
file_data,
GTH_OVERWRITE_RESPONSE_YES);
g_signal_connect (task,
"completed",
G_CALLBACK (save_wallpaper_task_completed_cb),
wdata);
gth_browser_exec_task (GTH_BROWSER (browser), task, GTH_TASK_FLAGS_IGNORE_ERROR);
saving_wallpaper = TRUE;
g_object_unref (image);
}
}
if (saving_wallpaper)
return;
if (file_data == NULL)
return;
if (g_file_is_native (file_data->file)) {
_g_object_unref (wdata->new_style.file);
wdata->new_style.file = g_file_dup (file_data->file);
wallpaper_data_set (wdata);
}
else
g_file_copy_async (file_data->file,
wdata->new_style.file,
G_FILE_COPY_OVERWRITE,
G_PRIORITY_DEFAULT,
NULL,
NULL,
NULL,
copy_wallpaper_ready_cb,
wdata);
_g_object_list_unref (file_list);
_gtk_tree_path_list_free (items);
}
void
gth_browser_activate_set_desktop_background (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
get_new_wallpaper_file_async (NULL, wallpaper_file_read_cb, user_data);
}