1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
2 
3    caja-monitor.c: file and directory change monitoring for caja
4 
5    Copyright (C) 2000, 2001 Eazel, Inc.
6 
7    This program is free software; you can redistribute it and/or
8    modify it under the terms of the GNU General Public License as
9    published by the Free Software Foundation; either version 2 of the
10    License, or (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16 
17    You should have received a copy of the GNU General Public
18    License along with this program; if not, write to the
19    Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20    Boston, MA 02110-1301, USA.
21 
22    Authors: Seth Nickell <seth@eazel.com>
23             Darin Adler <darin@bentspoon.com>
24 	    Alex Graveley <alex@ximian.com>
25 */
26 
27 #include <config.h>
28 #include "caja-monitor.h"
29 #include "caja-file-changes-queue.h"
30 #include "caja-file-utilities.h"
31 
32 #include <gio/gio.h>
33 
34 struct CajaMonitor
35 {
36     GFileMonitor *monitor;
37     GVolumeMonitor *volume_monitor;
38     GMount *mount;
39     GFile *location;
40 };
41 
42 gboolean
caja_monitor_active(void)43 caja_monitor_active (void)
44 {
45     static gboolean tried_monitor = FALSE;
46     static gboolean monitor_success;
47     GFileMonitor *dir_monitor;
48 
49     if (tried_monitor == FALSE)
50     {
51         GFile *file;
52 
53         file = g_file_new_for_path (g_get_home_dir ());
54         dir_monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
55         g_object_unref (file);
56 
57         monitor_success = (dir_monitor != NULL);
58         if (dir_monitor)
59         {
60             g_object_unref (dir_monitor);
61         }
62 
63         tried_monitor = TRUE;
64     }
65 
66     return monitor_success;
67 }
68 
69 static gboolean call_consume_changes_idle_id = 0;
70 
71 static gboolean
call_consume_changes_idle_cb(gpointer not_used)72 call_consume_changes_idle_cb (gpointer not_used)
73 {
74     caja_file_changes_consume_changes (TRUE);
75     call_consume_changes_idle_id = 0;
76     return FALSE;
77 }
78 
79 static void
schedule_call_consume_changes(void)80 schedule_call_consume_changes (void)
81 {
82     if (call_consume_changes_idle_id == 0) {
83 	    call_consume_changes_idle_id =
84         g_idle_add (call_consume_changes_idle_cb, NULL);
85 	}
86 }
87 
88 static void
mount_removed(GVolumeMonitor * volume_monitor,GMount * mount,gpointer user_data)89 mount_removed (GVolumeMonitor *volume_monitor,
90                GMount *mount,
91                gpointer user_data)
92 {
93     CajaMonitor *monitor = user_data;
94     if (mount == monitor->mount) {
95         caja_file_changes_queue_file_removed (monitor->location);
96         schedule_call_consume_changes ();
97     }
98 }
99 
100 static void
dir_changed(GFileMonitor * monitor,GFile * child,GFile * other_file,GFileMonitorEvent event_type,gpointer user_data)101 dir_changed (GFileMonitor* monitor,
102              GFile *child,
103              GFile *other_file,
104              GFileMonitorEvent event_type,
105              gpointer user_data)
106 {
107     char *uri, *to_uri;
108 
109     uri = g_file_get_uri (child);
110     to_uri = NULL;
111     if (other_file)
112     {
113         to_uri = g_file_get_uri (other_file);
114     }
115 
116     switch (event_type)
117     {
118     default:
119     case G_FILE_MONITOR_EVENT_CHANGED:
120         /* ignore */
121         break;
122     case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
123     case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
124         caja_file_changes_queue_file_changed (child);
125         break;
126     case G_FILE_MONITOR_EVENT_DELETED:
127         caja_file_changes_queue_file_removed (child);
128         break;
129     case G_FILE_MONITOR_EVENT_CREATED:
130         caja_file_changes_queue_file_added (child);
131         break;
132 
133     case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
134         /* TODO: Do something */
135         break;
136     case G_FILE_MONITOR_EVENT_UNMOUNTED:
137         /* TODO: Do something */
138         break;
139     }
140 
141     g_free (uri);
142     g_free (to_uri);
143     schedule_call_consume_changes ();
144 }
145 
146 CajaMonitor *
caja_monitor_directory(GFile * location)147 caja_monitor_directory (GFile *location)
148 {
149     GFileMonitor *dir_monitor;
150     CajaMonitor *ret;
151 
152     ret = g_new0 (CajaMonitor, 1);
153     dir_monitor = g_file_monitor_directory (location, G_FILE_MONITOR_WATCH_MOUNTS, NULL, NULL);
154 
155     if (dir_monitor != NULL) {
156         ret->monitor = dir_monitor;
157     }
158     /*This caused a crash on umounting remote shares
159     else if (!g_file_is_native (location)) {
160         ret->mount = caja_get_mounted_mount_for_root (location);
161         ret->location = g_object_ref (location);
162         ret->volume_monitor = g_volume_monitor_get ();
163     }
164     */
165     if (ret->monitor != NULL) {
166         g_signal_connect (ret->monitor, "changed",
167                   G_CALLBACK (dir_changed), ret);
168     }
169 
170     if (ret->monitor) {
171         g_signal_connect (ret->monitor, "changed", (GCallback)dir_changed, ret);
172     }
173 
174     if (ret->volume_monitor != NULL) {
175         g_signal_connect (ret->volume_monitor, "mount-removed",
176                     G_CALLBACK (mount_removed), ret);
177     }
178 
179     /* We return a monitor even on failure, so we can avoid later trying again */
180     return ret;
181 }
182 
183 void
caja_monitor_cancel(CajaMonitor * monitor)184 caja_monitor_cancel (CajaMonitor *monitor)
185 {
186     if (monitor->monitor != NULL)
187     {
188         g_signal_handlers_disconnect_by_func (monitor->monitor, dir_changed, monitor);
189         g_file_monitor_cancel (monitor->monitor);
190         g_object_unref (monitor->monitor);
191     }
192 
193     if (monitor->volume_monitor != NULL) {
194         g_signal_handlers_disconnect_by_func (monitor->volume_monitor, mount_removed, monitor);
195         g_object_unref (monitor->volume_monitor);
196     }
197 
198     g_clear_object (&monitor->location);
199     g_clear_object (&monitor->mount);
200     g_free (monitor);
201 }
202