1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /*
4 nemo-trash-monitor.c: Nemo trash state watcher.
5
6 Copyright (C) 2000, 2001 Eazel, Inc.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12
13 This program 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 GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public
19 License along with this program; if not, write to the
20 Free Software Foundation, Inc., 51 Franklin Street - Suite 500,
21 Boston, MA 02110-1335, USA.
22
23 Author: Pavel Cisler <pavel@eazel.com>
24 */
25
26 #include <config.h>
27 #include "nemo-trash-monitor.h"
28
29 #include "nemo-directory-notify.h"
30 #include "nemo-directory.h"
31 #include "nemo-file-attributes.h"
32 #include "nemo-icon-names.h"
33 #include <eel/eel-debug.h>
34 #include <gio/gio.h>
35 #include <string.h>
36
37 struct NemoTrashMonitorDetails {
38 gboolean empty;
39 GIcon *icon;
40 const gchar *symbolic_icon_name;
41 GFileMonitor *file_monitor;
42 };
43
44 enum {
45 TRASH_STATE_CHANGED,
46 LAST_SIGNAL
47 };
48
49 static guint signals[LAST_SIGNAL] = { 0 };
50 static NemoTrashMonitor *nemo_trash_monitor = NULL;
51
G_DEFINE_TYPE(NemoTrashMonitor,nemo_trash_monitor,G_TYPE_OBJECT)52 G_DEFINE_TYPE(NemoTrashMonitor, nemo_trash_monitor, G_TYPE_OBJECT)
53
54 static void
55 nemo_trash_monitor_finalize (GObject *object)
56 {
57 NemoTrashMonitor *trash_monitor;
58
59 trash_monitor = NEMO_TRASH_MONITOR (object);
60
61 if (trash_monitor->details->icon) {
62 g_object_unref (trash_monitor->details->icon);
63 }
64
65 if (trash_monitor->details->file_monitor) {
66 g_object_unref (trash_monitor->details->file_monitor);
67 }
68
69 G_OBJECT_CLASS (nemo_trash_monitor_parent_class)->finalize (object);
70 }
71
72 static void
nemo_trash_monitor_class_init(NemoTrashMonitorClass * klass)73 nemo_trash_monitor_class_init (NemoTrashMonitorClass *klass)
74 {
75 GObjectClass *object_class;
76
77 object_class = G_OBJECT_CLASS (klass);
78
79 object_class->finalize = nemo_trash_monitor_finalize;
80
81 signals[TRASH_STATE_CHANGED] = g_signal_new
82 ("trash_state_changed",
83 G_TYPE_FROM_CLASS (object_class),
84 G_SIGNAL_RUN_LAST,
85 G_STRUCT_OFFSET (NemoTrashMonitorClass, trash_state_changed),
86 NULL, NULL,
87 g_cclosure_marshal_VOID__BOOLEAN,
88 G_TYPE_NONE, 1,
89 G_TYPE_BOOLEAN);
90
91 g_type_class_add_private (object_class, sizeof(NemoTrashMonitorDetails));
92 }
93
94 static void
update_icon(NemoTrashMonitor * trash_monitor)95 update_icon (NemoTrashMonitor *trash_monitor)
96 {
97 g_clear_object (&trash_monitor->details->icon);
98
99 if (trash_monitor->details->empty) {
100 trash_monitor->details->icon = g_themed_icon_new (NEMO_ICON_TRASH);
101 trash_monitor->details->symbolic_icon_name = NEMO_ICON_SYMBOLIC_TRASH;
102 } else {
103 trash_monitor->details->icon = g_themed_icon_new (NEMO_ICON_TRASH_FULL);
104 trash_monitor->details->symbolic_icon_name = NEMO_ICON_SYMBOLIC_TRASH_FULL;
105 }
106 }
107
108 static void
update_empty_info(NemoTrashMonitor * trash_monitor,gboolean is_empty)109 update_empty_info (NemoTrashMonitor *trash_monitor,
110 gboolean is_empty)
111 {
112 if (trash_monitor->details->empty == is_empty) {
113 return;
114 }
115
116 trash_monitor->details->empty = is_empty;
117 update_icon (trash_monitor);
118
119 /* trash got empty or full, notify everyone who cares */
120 g_signal_emit (trash_monitor,
121 signals[TRASH_STATE_CHANGED], 0,
122 trash_monitor->details->empty);
123 }
124
125 /* Use G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT since we only want to know whether the
126 * trash is empty or not, not access its children. This is available for the
127 * trash backend since it uses a cache. In this way we prevent flooding the
128 * trash backend with enumeration requests when trashing > 1000 files
129 */
130 static void
trash_query_info_cb(GObject * source,GAsyncResult * res,gpointer user_data)131 trash_query_info_cb (GObject *source,
132 GAsyncResult *res,
133 gpointer user_data)
134 {
135 NemoTrashMonitor *trash_monitor = user_data;
136 GFileInfo *info;
137 guint32 item_count;
138 gboolean is_empty = TRUE;
139
140 info = g_file_query_info_finish (G_FILE (source), res, NULL);
141
142 if (info != NULL) {
143 item_count = g_file_info_get_attribute_uint32 (info,
144 G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT);
145 is_empty = item_count == 0;
146
147 g_object_unref (info);
148
149 }
150
151 update_empty_info (trash_monitor, is_empty);
152
153 g_object_unref (trash_monitor);
154 }
155
156 static void
schedule_update_info(NemoTrashMonitor * trash_monitor)157 schedule_update_info (NemoTrashMonitor *trash_monitor)
158 {
159 GFile *location;
160
161 location = g_file_new_for_uri ("trash:///");
162 g_file_query_info_async (location,
163 G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT,
164 G_FILE_QUERY_INFO_NONE,
165 G_PRIORITY_DEFAULT, NULL,
166 trash_query_info_cb, g_object_ref (trash_monitor));
167
168 g_object_unref (location);
169 }
170
171 static void
file_changed(GFileMonitor * monitor,GFile * child,GFile * other_file,GFileMonitorEvent event_type,gpointer user_data)172 file_changed (GFileMonitor* monitor,
173 GFile *child,
174 GFile *other_file,
175 GFileMonitorEvent event_type,
176 gpointer user_data)
177 {
178 NemoTrashMonitor *trash_monitor;
179
180 trash_monitor = NEMO_TRASH_MONITOR (user_data);
181
182 schedule_update_info (trash_monitor);
183 }
184
185 static void
nemo_trash_monitor_init(NemoTrashMonitor * trash_monitor)186 nemo_trash_monitor_init (NemoTrashMonitor *trash_monitor)
187 {
188 GFile *location;
189
190 trash_monitor->details = G_TYPE_INSTANCE_GET_PRIVATE (trash_monitor,
191 NEMO_TYPE_TRASH_MONITOR,
192 NemoTrashMonitorDetails);
193
194 trash_monitor->details->empty = TRUE;
195 update_icon (trash_monitor);
196
197 location = g_file_new_for_uri ("trash:///");
198
199 trash_monitor->details->file_monitor = g_file_monitor_file (location, 0, NULL, NULL);
200
201 g_signal_connect (trash_monitor->details->file_monitor, "changed",
202 (GCallback)file_changed, trash_monitor);
203
204 g_object_unref (location);
205
206 schedule_update_info (trash_monitor);
207 }
208
209 static void
unref_trash_monitor(void)210 unref_trash_monitor (void)
211 {
212 g_object_unref (nemo_trash_monitor);
213 }
214
215 NemoTrashMonitor *
nemo_trash_monitor_get(void)216 nemo_trash_monitor_get (void)
217 {
218 if (nemo_trash_monitor == NULL) {
219 /* not running yet, start it up */
220
221 nemo_trash_monitor = NEMO_TRASH_MONITOR
222 (g_object_new (NEMO_TYPE_TRASH_MONITOR, NULL));
223 eel_debug_call_at_shutdown (unref_trash_monitor);
224 }
225
226 return nemo_trash_monitor;
227 }
228
229 gboolean
nemo_trash_monitor_is_empty(void)230 nemo_trash_monitor_is_empty (void)
231 {
232 NemoTrashMonitor *monitor;
233
234 monitor = nemo_trash_monitor_get ();
235 return monitor->details->empty;
236 }
237
238 GIcon *
nemo_trash_monitor_get_icon(void)239 nemo_trash_monitor_get_icon (void)
240 {
241 NemoTrashMonitor *monitor;
242
243 monitor = nemo_trash_monitor_get ();
244 if (monitor->details->icon) {
245 return g_object_ref (monitor->details->icon);
246 }
247 return NULL;
248 }
249
250 gchar *
nemo_trash_monitor_get_symbolic_icon_name(void)251 nemo_trash_monitor_get_symbolic_icon_name (void)
252 {
253 NemoTrashMonitor *monitor;
254
255 monitor = nemo_trash_monitor_get ();
256 if (monitor->details->symbolic_icon_name) {
257 return g_strdup (monitor->details->symbolic_icon_name);
258 }
259 return NULL;
260 }
261
262 void
nemo_trash_monitor_add_new_trash_directories(void)263 nemo_trash_monitor_add_new_trash_directories (void)
264 {
265 /* We trashed something... */
266 }
267