Commit fb02e429 authored by Cosimo Cecchi's avatar Cosimo Cecchi

housekeeping: use the nautilus DBus API to empty trash

https://bugzilla.gnome.org/show_bug.cgi?id=632154
parent 20427bb4
COMMON_FILES = \
gsd-disk-space.c \
gsd-disk-space.h \
gsd-ldsm-trash-empty.c \
gsd-ldsm-trash-empty.h \
gsd-ldsm-dialog.c \
gsd-ldsm-dialog.h
noinst_PROGRAMS = gsd-disk-space-test
noinst_PROGRAMS = gsd-disk-space-test gsd-empty-trash-test
gsd_disk_space_test_SOURCES = \
gsd-disk-space-test.c \
......@@ -18,6 +16,16 @@ gsd_disk_space_test_CFLAGS = \
$(LIBNOTIFY_CFLAGS) \
$(AM_CFLAGS)
gsd_empty_trash_test_SOURCES = \
gsd-empty-trash-test.c \
$(COMMON_FILES)
gsd_empty_trash_test_LDADD = $(SETTINGS_PLUGIN_LIBS) $(GIOUNIX_LIBS) $(LIBNOTIFY_LIBS)
gsd_empty_trash_test_CFLAGS = \
$(SETTINGS_PLUGIN_CFLAGS) \
$(GIOUNIX_CFLAGS) \
$(LIBNOTIFY_CFLAGS) \
$(AM_CFLAGS)
plugin_LTLIBRARIES = libhousekeeping.la
libhousekeeping_la_SOURCES = \
......
......@@ -37,8 +37,6 @@
#include "gsd-disk-space.h"
#include "gsd-ldsm-dialog.h"
#include "gsd-ldsm-trash-empty.h"
#define GIGABYTE 1024 * 1024 * 1024
......@@ -216,6 +214,69 @@ examine_callback (NotifyNotification *n,
notify_notification_close (n, NULL);
}
static void
nautilus_empty_trash_cb (GObject *object,
GAsyncResult *res,
gpointer _unused)
{
GDBusProxy *proxy = G_DBUS_PROXY (object);
GError *error = NULL;
g_dbus_proxy_call_finish (proxy, res, &error);
if (error != NULL) {
g_warning ("Unable to call EmptyTrash() on the Nautilus DBus interface: %s",
error->message);
g_error_free (error);
}
/* clean up the proxy object */
g_object_unref (proxy);
}
static void
nautilus_proxy_ready_cb (GObject *object,
GAsyncResult *res,
gpointer _unused)
{
GDBusProxy *proxy = NULL;
GError *error = NULL;
proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
if (proxy == NULL) {
g_warning ("Unable to create a proxy object for the Nautilus DBus interface: %s",
error->message);
g_error_free (error);
return;
}
g_dbus_proxy_call (proxy,
"EmptyTrash",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
nautilus_empty_trash_cb,
NULL);
}
void
gsd_ldsm_show_empty_trash (void)
{
/* prepare the Nautilus proxy object */
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
"org.gnome.Nautilus",
"/org/gnome/Nautilus",
"org.gnome.Nautilus.FileOperations",
NULL,
nautilus_proxy_ready_cb,
NULL);
}
static void
empty_trash_callback (NotifyNotification *n,
const char *action)
......@@ -223,7 +284,7 @@ empty_trash_callback (NotifyNotification *n,
g_assert (action != NULL);
g_assert (strcmp (action, "empty-trash") == 0);
gsd_ldsm_trash_empty ();
gsd_ldsm_show_empty_trash ();
notify_notification_close (n, NULL);
}
......@@ -355,7 +416,7 @@ ldsm_notify_for_mount (LdsmMountInfo *mount,
break;
case GSD_LDSM_DIALOG_RESPONSE_EMPTY_TRASH:
retval = TRUE;
gsd_ldsm_trash_empty ();
gsd_ldsm_show_empty_trash ();
break;
case GTK_RESPONSE_NONE:
case GTK_RESPONSE_DELETE_EVENT:
......@@ -798,7 +859,6 @@ gsd_ldsm_setup (gboolean check_now)
ldsm_timeout_id = g_timeout_add_seconds (CHECK_EVERY_X_SECONDS,
ldsm_check_all_mounts, NULL);
}
void
......
......@@ -31,6 +31,9 @@ G_BEGIN_DECLS
void gsd_ldsm_setup (gboolean check_now);
void gsd_ldsm_clean (void);
/* for the test */
void gsd_ldsm_show_empty_trash (void);
G_END_DECLS
#endif /* __GSD_DISK_SPACE_H */
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
* vim: set et sw=8 ts=8:
*
* Copyright (c) 2011, Red Hat, Inc.
*
* Authors: Cosimo Cecchi <cosimoc@redhat.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include "config.h"
#include <gtk/gtk.h>
#include "gsd-disk-space.h"
int
main (int argc,
char **argv)
{
GMainLoop *loop;
gtk_init (&argc, &argv);
loop = g_main_loop_new (NULL, FALSE);
gsd_ldsm_show_empty_trash ();
g_main_loop_run (loop);
g_main_loop_unref (loop);
return 0;
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* gsd-ldsm-trash-empty.c
* Copyright (C) Chris Coulson 2009 <chrisccoulson@googlemail.com>
* (C) Ryan Lortie 2008
*
* gsd-ldsm-trash-empty.c 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 3 of the License, or
* (at your option) any later version.
*
* gsd-ldsm-trash-empty.c 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 <http://www.gnu.org/licenses/>.
*/
#include <glib/gi18n.h>
#include <gio/gio.h>
#include "gsd-ldsm-trash-empty.h"
/* Some of this code has been borrowed from the trash-applet, courtesy of Ryan Lortie */
static GtkWidget *trash_empty_confirm_dialog = NULL;
static GtkWidget *trash_empty_dialog = NULL;
static GtkWidget *location_label;
static GtkWidget *file_label;
static GtkWidget *progressbar;
static gsize trash_empty_total_files;
static gboolean trash_empty_update_pending = FALSE;
static GFile *trash_empty_current_file = NULL;
static gsize trash_empty_deleted_files;
static GTimer *timer = NULL;
static gboolean trash_empty_actually_deleting;
static gboolean
trash_empty_done (gpointer data)
{
gtk_widget_destroy (trash_empty_dialog);
trash_empty_dialog = NULL;
if (timer) {
g_timer_destroy (timer);
timer = NULL;
}
return FALSE;
}
static gboolean
trash_empty_update_dialog (gpointer user_data)
{
gsize deleted, total;
GFile *file;
gboolean actually_deleting;
g_assert (trash_empty_update_pending);
deleted = trash_empty_deleted_files;
total = trash_empty_total_files;
file = trash_empty_current_file;
actually_deleting = trash_empty_actually_deleting;
/* maybe the done() got processed first. */
if (!trash_empty_dialog)
goto out;
if (!actually_deleting) {
/* If we havent finished counting yet, then pulse the progressbar every 100ms.
* This stops the user from thinking the dialog has frozen if there are
* a lot of files to delete. We don't pulse it every time we are called from the
* worker thread, otherwise it moves to fast and looks hideous
*/
if (timer) {
if (g_timer_elapsed (timer, NULL) > 0.1) {
gtk_progress_bar_pulse (GTK_PROGRESS_BAR (progressbar));
g_timer_start (timer);
}
} else {
timer = g_timer_new ();
g_timer_start (timer);
gtk_progress_bar_pulse (GTK_PROGRESS_BAR (progressbar));
}
} else {
gchar *text;
gchar *tmp;
gchar *markup;
gchar *deleted_str, *total_str;
GFile *parent;
deleted_str = g_strdup_printf ("%"G_GSIZE_FORMAT, deleted);
total_str = g_strdup_printf ("%"G_GSIZE_FORMAT, total);
text = g_strdup_printf (_("Removing item %s of %s"),
deleted_str, total_str);
gtk_progress_bar_set_text (GTK_PROGRESS_BAR (progressbar), text);
g_free (text);
g_free (deleted_str);
g_free (total_str);
if (deleted > total)
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progressbar), 1.0);
else
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progressbar),
(gdouble) deleted / (gdouble) total);
parent = g_file_get_parent (file);
text = g_file_get_uri (parent);
g_object_unref (parent);
gtk_label_set_text (GTK_LABEL (location_label), text);
g_free (text);
tmp = g_file_get_basename (file);
text = g_markup_printf_escaped (_("Removing: %s"), tmp);
markup = g_strdup_printf ("<i>%s</i>", text);
gtk_label_set_markup (GTK_LABEL (file_label), text);
g_free (markup);
g_free (text);
g_free (tmp);
/* unhide the labels */
gtk_widget_show_all (GTK_WIDGET (trash_empty_dialog));
}
out:
trash_empty_current_file = NULL;
g_object_unref (file);
trash_empty_update_pending = FALSE;
return FALSE;
}
/* Worker thread begin */
static void
trash_empty_maybe_schedule_update (GIOSchedulerJob *job,
GFile *file,
gsize deleted,
gboolean actually_deleting)
{
if (!trash_empty_update_pending) {
g_assert (trash_empty_current_file == NULL);
trash_empty_current_file = g_object_ref (file);
trash_empty_deleted_files = deleted;
trash_empty_actually_deleting = actually_deleting;
trash_empty_update_pending = TRUE;
g_io_scheduler_job_send_to_mainloop_async (job,
trash_empty_update_dialog,
NULL, NULL);
}
}
static void
trash_empty_delete_contents (GIOSchedulerJob *job,
GCancellable *cancellable,
GFile *file,
gboolean actually_delete,
gsize *deleted)
{
GFileEnumerator *enumerator;
GFileInfo *info;
GFile *child;
if (g_cancellable_is_cancelled (cancellable))
return;
enumerator = g_file_enumerate_children (file,
G_FILE_ATTRIBUTE_STANDARD_NAME ","
G_FILE_ATTRIBUTE_STANDARD_TYPE,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable, NULL);
if (enumerator) {
while ((info = g_file_enumerator_next_file (enumerator,
cancellable, NULL)) != NULL) {
child = g_file_get_child (file, g_file_info_get_name (info));
if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
trash_empty_delete_contents (job, cancellable, child,
actually_delete, deleted);
trash_empty_maybe_schedule_update (job, child, *deleted, actually_delete);
if (actually_delete)
g_file_delete (child, cancellable, NULL);
(*deleted)++;
g_object_unref (child);
g_object_unref (info);
if (g_cancellable_is_cancelled (cancellable))
break;
}
g_object_unref (enumerator);
}
}
static gboolean
trash_empty_job (GIOSchedulerJob *job,
GCancellable *cancellable,
gpointer user_data)
{
gsize deleted;
GFile *trash;
trash = g_file_new_for_uri ("trash:///");
/* first do a dry run to count the number of files */
deleted = 0;
trash_empty_delete_contents (job, cancellable, trash, FALSE, &deleted);
trash_empty_total_files = deleted;
/* now do the real thing */
deleted = 0;
trash_empty_delete_contents (job, cancellable, trash, TRUE, &deleted);
/* done */
g_object_unref (trash);
g_io_scheduler_job_send_to_mainloop_async (job,
trash_empty_done,
NULL, NULL);
return FALSE;
}
/* Worker thread end */
static void
trash_empty_start ()
{
GtkWidget *vbox1, *vbox2, *hbox;
GtkWidget *label1, *label3;
gchar *markup;
GCancellable *cancellable;
trash_empty_dialog = gtk_dialog_new ();
gtk_window_set_default_size (GTK_WINDOW (trash_empty_dialog), 400, -1);
gtk_window_set_icon_name (GTK_WINDOW (trash_empty_dialog), "user-trash");
gtk_window_set_title (GTK_WINDOW (trash_empty_dialog),
_("Emptying the trash"));
vbox1 = gtk_vbox_new (FALSE, 12);
vbox2 = gtk_vbox_new (FALSE, 0);
hbox = gtk_hbox_new (FALSE, 0);
label1 = gtk_label_new (NULL);
gtk_label_set_line_wrap (GTK_LABEL (label1), TRUE);
gtk_misc_set_alignment (GTK_MISC (label1), 0.0, 0.5);
label3 = gtk_label_new (NULL);
gtk_label_set_line_wrap (GTK_LABEL (label3), TRUE);
gtk_misc_set_alignment (GTK_MISC (label3), 0.0, 0.5);
gtk_widget_hide (label3);
location_label = gtk_label_new (NULL);
gtk_label_set_line_wrap (GTK_LABEL (location_label), TRUE);
gtk_misc_set_alignment (GTK_MISC (location_label), 0.0, 0.5);
file_label = gtk_label_new (NULL);
gtk_label_set_line_wrap (GTK_LABEL (file_label), TRUE);
gtk_misc_set_alignment (GTK_MISC (file_label), 0.0, 0.5);
progressbar = gtk_progress_bar_new ();
gtk_progress_bar_set_pulse_step (GTK_PROGRESS_BAR (progressbar), 0.1);
gtk_progress_bar_set_text (GTK_PROGRESS_BAR (progressbar), _("Preparing to empty trash…"));
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (trash_empty_dialog))), vbox1, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (vbox1), label1, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), label3, FALSE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), location_label, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (vbox1), hbox, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (vbox2), progressbar, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (vbox2), file_label, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (vbox1), vbox2, TRUE, TRUE, 0);
gtk_widget_show (label1);
gtk_widget_show (vbox1);
gtk_widget_show_all (vbox2);
gtk_widget_show (hbox);
gtk_widget_show (location_label);
gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (trash_empty_dialog))), 6);
gtk_container_set_border_width (GTK_CONTAINER (vbox1), 6);
gtk_dialog_add_button (GTK_DIALOG (trash_empty_dialog),
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL);
markup = g_markup_printf_escaped ("<big><b>%s</b></big>", _("Emptying the trash"));
gtk_label_set_markup (GTK_LABEL (label1), markup);
/* Translators: "Emptying trash from <device>" */
gtk_label_set_text (GTK_LABEL (label3), _("From: "));
cancellable = g_cancellable_new ();
g_signal_connect_object (trash_empty_dialog, "response",
G_CALLBACK (g_cancellable_cancel),
cancellable, G_CONNECT_SWAPPED);
g_io_scheduler_push_job (trash_empty_job, NULL, NULL, 0, cancellable);
gtk_widget_show (trash_empty_dialog);
g_free (markup);
g_object_unref (cancellable);
}
static void
trash_empty_confirmation_response (GtkDialog *dialog,
gint response_id,
gpointer user_data)
{
if (response_id == GTK_RESPONSE_YES)
trash_empty_start ();
gtk_widget_destroy (GTK_WIDGET (dialog));
trash_empty_confirm_dialog = NULL;
}
static gboolean
trash_empty_require_confirmation (void)
{
gboolean require_confirmation = TRUE;
const char * const *schemas;
guint i;
schemas = g_settings_list_schemas ();
for (i = 0; schemas[i] != NULL; i++) {
if (g_str_equal (schemas[i], "org.gnome.nautilus.preferences")) {
GSettings *settings;
settings = g_settings_new ("org.gnome.nautilus.preferences");
require_confirmation = g_settings_get_boolean (settings, "confirm-trash");
g_object_unref (settings);
break;
}
}
return require_confirmation;
}
static void
trash_empty_show_confirmation_dialog ()
{
GtkWidget *button;
if (!trash_empty_require_confirmation ()) {
trash_empty_start ();
return;
}
trash_empty_confirm_dialog = gtk_message_dialog_new (NULL, 0,
GTK_MESSAGE_WARNING,
GTK_BUTTONS_NONE,
_("Empty all of the items from the trash?"));
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (trash_empty_confirm_dialog),
_("If you choose to empty the trash, all items in "
"it will be permanently lost. Please note that "
"you can also delete them separately."));
gtk_dialog_add_button (GTK_DIALOG (trash_empty_confirm_dialog), GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL);
button = gtk_button_new_with_mnemonic (_("_Empty Trash"));
gtk_widget_show (button);
gtk_widget_set_can_default (button, TRUE);
gtk_dialog_add_action_widget (GTK_DIALOG (trash_empty_confirm_dialog),
button, GTK_RESPONSE_YES);
gtk_dialog_set_default_response (GTK_DIALOG (trash_empty_confirm_dialog),
GTK_RESPONSE_YES);
gtk_window_set_icon_name (GTK_WINDOW (trash_empty_confirm_dialog),
"user-trash");
gtk_widget_show (trash_empty_confirm_dialog);
g_signal_connect (trash_empty_confirm_dialog, "response",
G_CALLBACK (trash_empty_confirmation_response), NULL);
}
void
gsd_ldsm_trash_empty (void)
{
if (trash_empty_confirm_dialog)
gtk_window_present (GTK_WINDOW (trash_empty_confirm_dialog));
else if (trash_empty_dialog)
gtk_window_present (GTK_WINDOW (trash_empty_dialog));
else
trash_empty_show_confirmation_dialog ();
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* gsd-ldsm-trash-empty.h
* Copyright (C) Chris Coulson 2009 <chrisccoulson@googlemail.com>
*
* gsd-ldsm-trash-empty.h 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 3 of the License, or
* (at your option) any later version.
*
* gsd-ldsm-trash-empty.h 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _gsd_ldsm_trash_empty_h_
#define _gsd_ldsm_trash_empty_h_
#include <gtk/gtk.h>
void gsd_ldsm_trash_empty (void);
#endif /* _gsd_ldsm_trash_empty_h_ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment