Branch data Line data Source code
1 : : /* GIO - GLib Input, Output and Streaming Library
2 : : *
3 : : * Copyright (C) 2006-2007 Red Hat, Inc.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library 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 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General
18 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : *
20 : : * Author: Alexander Larsson <alexl@redhat.com>
21 : : */
22 : :
23 : : #include "config.h"
24 : : #include <string.h>
25 : :
26 : : #include "gfile.h"
27 : : #include "gfilemonitor.h"
28 : : #include "gioenumtypes.h"
29 : : #include "glib.h"
30 : : #include "glibintl.h"
31 : : #include "gmarshal-internal.h"
32 : : #include "gvfs.h"
33 : :
34 : : /**
35 : : * GFileMonitor:
36 : : *
37 : : * Monitors a file or directory for changes.
38 : : *
39 : : * To obtain a `GFileMonitor` for a file or directory, use
40 : : * [method@Gio.File.monitor], [method@Gio.File.monitor_file], or
41 : : * [method@Gio.File.monitor_directory].
42 : : *
43 : : * To get informed about changes to the file or directory you are
44 : : * monitoring, connect to the [signal@Gio.FileMonitor::changed] signal. The
45 : : * signal will be emitted in the thread-default main context (see
46 : : * [method@GLib.MainContext.push_thread_default]) of the thread that the monitor
47 : : * was created in (though if the global default main context is blocked, this
48 : : * may cause notifications to be blocked even if the thread-default
49 : : * context is still running).
50 : : **/
51 : :
52 : : #define DEFAULT_RATE_LIMIT_MSECS 800
53 : :
54 : : typedef enum {
55 : : CANCEL_STATE_NONE,
56 : : CANCEL_STATE_CANCELLING,
57 : : CANCEL_STATE_CANCELLED,
58 : : } GFileMonitorCancelState;
59 : :
60 : : struct _GFileMonitorPrivate
61 : : {
62 : : int cancelled; /* atomic */
63 : : };
64 : :
65 : 3643 : G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GFileMonitor, g_file_monitor, G_TYPE_OBJECT)
66 : :
67 : : typedef enum
68 : : {
69 : : PROP_RATE_LIMIT = 1,
70 : : PROP_CANCELLED
71 : : } GFileMonitorProperty;
72 : :
73 : : static GParamSpec *props[PROP_CANCELLED + 1];
74 : : static guint g_file_monitor_changed_signal;
75 : :
76 : : static void
77 : 0 : g_file_monitor_set_property (GObject *object,
78 : : guint prop_id,
79 : : const GValue *value,
80 : : GParamSpec *pspec)
81 : : {
82 : 0 : switch ((GFileMonitorProperty) prop_id)
83 : : {
84 : 0 : case PROP_RATE_LIMIT:
85 : : /* not supported by default */
86 : 0 : break;
87 : :
88 : 0 : case PROP_CANCELLED:
89 : : /* Read only */
90 : : g_assert_not_reached ();
91 : : break;
92 : :
93 : 0 : default:
94 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
95 : 0 : break;
96 : : }
97 : 0 : }
98 : :
99 : : static void
100 : 0 : g_file_monitor_get_property (GObject *object,
101 : : guint prop_id,
102 : : GValue *value,
103 : : GParamSpec *pspec)
104 : : {
105 : 0 : GFileMonitor *self = G_FILE_MONITOR (object);
106 : :
107 : 0 : switch ((GFileMonitorProperty) prop_id)
108 : : {
109 : 0 : case PROP_RATE_LIMIT:
110 : : /* we expect this to be overridden... */
111 : 0 : g_value_set_int (value, DEFAULT_RATE_LIMIT_MSECS);
112 : 0 : break;
113 : :
114 : 0 : case PROP_CANCELLED:
115 : 0 : g_value_set_boolean (value, g_file_monitor_is_cancelled (self));
116 : 0 : break;
117 : :
118 : 0 : default:
119 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
120 : 0 : break;
121 : : }
122 : 0 : }
123 : :
124 : : static void
125 : 469 : g_file_monitor_dispose (GObject *object)
126 : : {
127 : 469 : GFileMonitor *monitor = G_FILE_MONITOR (object);
128 : :
129 : : /* Make sure we cancel on last unref */
130 : 469 : g_file_monitor_cancel (monitor);
131 : :
132 : 469 : G_OBJECT_CLASS (g_file_monitor_parent_class)->dispose (object);
133 : 469 : }
134 : :
135 : : static void
136 : 681 : g_file_monitor_init (GFileMonitor *monitor)
137 : : {
138 : 681 : monitor->priv = g_file_monitor_get_instance_private (monitor);
139 : 681 : }
140 : :
141 : : static void
142 : 60 : g_file_monitor_class_init (GFileMonitorClass *klass)
143 : : {
144 : : GObjectClass *object_class;
145 : :
146 : 60 : object_class = G_OBJECT_CLASS (klass);
147 : 60 : object_class->dispose = g_file_monitor_dispose;
148 : 60 : object_class->get_property = g_file_monitor_get_property;
149 : 60 : object_class->set_property = g_file_monitor_set_property;
150 : :
151 : : /**
152 : : * GFileMonitor::changed:
153 : : * @monitor: a #GFileMonitor.
154 : : * @file: a #GFile.
155 : : * @other_file: (nullable): a #GFile or #NULL.
156 : : * @event_type: a #GFileMonitorEvent.
157 : : *
158 : : * Emitted when @file has been changed.
159 : : *
160 : : * If using %G_FILE_MONITOR_WATCH_MOVES on a directory monitor, and
161 : : * the information is available (and if supported by the backend),
162 : : * @event_type may be %G_FILE_MONITOR_EVENT_RENAMED,
163 : : * %G_FILE_MONITOR_EVENT_MOVED_IN or %G_FILE_MONITOR_EVENT_MOVED_OUT.
164 : : *
165 : : * In all cases @file will be a child of the monitored directory. For
166 : : * renames, @file will be the old name and @other_file is the new
167 : : * name. For "moved in" events, @file is the name of the file that
168 : : * appeared and @other_file is the old name that it was moved from (in
169 : : * another directory). For "moved out" events, @file is the name of
170 : : * the file that used to be in this directory and @other_file is the
171 : : * name of the file at its new location.
172 : : *
173 : : * It makes sense to treat %G_FILE_MONITOR_EVENT_MOVED_IN as
174 : : * equivalent to %G_FILE_MONITOR_EVENT_CREATED and
175 : : * %G_FILE_MONITOR_EVENT_MOVED_OUT as equivalent to
176 : : * %G_FILE_MONITOR_EVENT_DELETED, with extra information.
177 : : * %G_FILE_MONITOR_EVENT_RENAMED is equivalent to a delete/create
178 : : * pair. This is exactly how the events will be reported in the case
179 : : * that the %G_FILE_MONITOR_WATCH_MOVES flag is not in use.
180 : : *
181 : : * If using the deprecated flag %G_FILE_MONITOR_SEND_MOVED flag and @event_type is
182 : : * %G_FILE_MONITOR_EVENT_MOVED, @file will be set to a #GFile containing the
183 : : * old path, and @other_file will be set to a #GFile containing the new path.
184 : : *
185 : : * In all the other cases, @other_file will be set to #NULL.
186 : : **/
187 : 60 : g_file_monitor_changed_signal = g_signal_new (I_("changed"),
188 : : G_TYPE_FILE_MONITOR,
189 : : G_SIGNAL_RUN_LAST,
190 : : G_STRUCT_OFFSET (GFileMonitorClass, changed),
191 : : NULL, NULL,
192 : : _g_cclosure_marshal_VOID__OBJECT_OBJECT_ENUM,
193 : : G_TYPE_NONE, 3,
194 : : G_TYPE_FILE, G_TYPE_FILE, G_TYPE_FILE_MONITOR_EVENT);
195 : 60 : g_signal_set_va_marshaller (g_file_monitor_changed_signal,
196 : : G_TYPE_FROM_CLASS (klass),
197 : : _g_cclosure_marshal_VOID__OBJECT_OBJECT_ENUMv);
198 : :
199 : : /**
200 : : * GFileMonitor:rate-limit:
201 : : *
202 : : * The limit of the monitor to watch for changes, in milliseconds.
203 : : */
204 : 60 : props[PROP_RATE_LIMIT] =
205 : 60 : g_param_spec_int ("rate-limit", NULL, NULL,
206 : : 0, G_MAXINT, DEFAULT_RATE_LIMIT_MSECS, G_PARAM_READWRITE |
207 : : G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
208 : :
209 : : /**
210 : : * GFileMonitor:cancelled:
211 : : *
212 : : * Whether the monitor has been cancelled.
213 : : */
214 : 60 : props[PROP_CANCELLED] =
215 : 60 : g_param_spec_boolean ("cancelled", NULL, NULL,
216 : : FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
217 : :
218 : 60 : g_object_class_install_properties (object_class, G_N_ELEMENTS (props), props);
219 : 60 : }
220 : :
221 : : /**
222 : : * g_file_monitor_is_cancelled:
223 : : * @monitor: a #GFileMonitor
224 : : *
225 : : * Returns whether the monitor is canceled.
226 : : *
227 : : * Returns: %TRUE if monitor is canceled. %FALSE otherwise.
228 : : **/
229 : : gboolean
230 : 10 : g_file_monitor_is_cancelled (GFileMonitor *monitor)
231 : : {
232 : 10 : g_return_val_if_fail (G_IS_FILE_MONITOR (monitor), FALSE);
233 : :
234 : 10 : return g_atomic_int_get (&monitor->priv->cancelled) == CANCEL_STATE_CANCELLED;
235 : : }
236 : :
237 : : /**
238 : : * g_file_monitor_cancel:
239 : : * @monitor: a #GFileMonitor.
240 : : *
241 : : * Cancels a file monitor.
242 : : *
243 : : * Returns: always %TRUE
244 : : **/
245 : : gboolean
246 : 830 : g_file_monitor_cancel (GFileMonitor *monitor)
247 : : {
248 : 830 : g_return_val_if_fail (G_IS_FILE_MONITOR (monitor), FALSE);
249 : :
250 : 830 : if (g_atomic_int_compare_and_exchange (&monitor->priv->cancelled,
251 : : CANCEL_STATE_NONE,
252 : : CANCEL_STATE_CANCELLING))
253 : : {
254 : 469 : G_FILE_MONITOR_GET_CLASS (monitor)->cancel (monitor);
255 : :
256 : 469 : g_atomic_int_set (&monitor->priv->cancelled, CANCEL_STATE_CANCELLED);
257 : 469 : g_object_notify_by_pspec (G_OBJECT (monitor), props[PROP_CANCELLED]);
258 : : }
259 : :
260 : 830 : return TRUE;
261 : : }
262 : :
263 : : /**
264 : : * g_file_monitor_set_rate_limit:
265 : : * @monitor: a #GFileMonitor.
266 : : * @limit_msecs: a non-negative integer with the limit in milliseconds
267 : : * to poll for changes
268 : : *
269 : : * Sets the rate limit to which the @monitor will report
270 : : * consecutive change events to the same file.
271 : : */
272 : : void
273 : 12 : g_file_monitor_set_rate_limit (GFileMonitor *monitor,
274 : : gint limit_msecs)
275 : : {
276 : 12 : g_object_set (monitor, "rate-limit", limit_msecs, NULL);
277 : 12 : }
278 : :
279 : : /**
280 : : * g_file_monitor_emit_event:
281 : : * @monitor: a #GFileMonitor.
282 : : * @child: a #GFile.
283 : : * @other_file: (nullable): a #GFile, or %NULL.
284 : : * @event_type: a set of #GFileMonitorEvent flags.
285 : : *
286 : : * Emits the #GFileMonitor::changed signal if a change
287 : : * has taken place. Should be called from file monitor
288 : : * implementations only.
289 : : *
290 : : * Implementations are responsible to call this method from the
291 : : * thread-default main context (see [method@GLib.MainContext.push_thread_default])
292 : : * of the thread that the monitor was created in.
293 : : **/
294 : : void
295 : 527 : g_file_monitor_emit_event (GFileMonitor *monitor,
296 : : GFile *child,
297 : : GFile *other_file,
298 : : GFileMonitorEvent event_type)
299 : : {
300 : 527 : g_return_if_fail (G_IS_FILE_MONITOR (monitor));
301 : 527 : g_return_if_fail (G_IS_FILE (child));
302 : 527 : g_return_if_fail (!other_file || G_IS_FILE (other_file));
303 : :
304 : 527 : if (g_atomic_int_get (&monitor->priv->cancelled) != CANCEL_STATE_NONE)
305 : 13 : return;
306 : :
307 : 514 : g_signal_emit (monitor, g_file_monitor_changed_signal, 0, child, other_file, event_type);
308 : : }
|