]> code.delx.au - gnu-emacs/blobdiff - src/gfilenotify.c
Use g_clear_error instead of g_error_free
[gnu-emacs] / src / gfilenotify.c
index e03bec93541a4591b42af199ed9fc5a4c9d11310..69f635d4115ed9d702378ab9d185dd9479991715 100644 (file)
@@ -29,6 +29,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "process.h"
 
 \f
 #include "process.h"
 
 \f
+/* This is a list, elements are triples (DESCRIPTOR FILE FLAGS CALLBACK)  */
 static Lisp_Object watch_list;
 
 /* This is the callback function for arriving signals from
 static Lisp_Object watch_list;
 
 /* This is the callback function for arriving signals from
@@ -41,7 +42,7 @@ dir_monitor_callback (GFileMonitor *monitor,
                      GFileMonitorEvent event_type,
                      gpointer user_data)
 {
                      GFileMonitorEvent event_type,
                      gpointer user_data)
 {
-  Lisp_Object symbol, monitor_object, watch_object;
+  Lisp_Object symbol, monitor_object, watch_object, flags;
   char *name = g_file_get_parse_name (file);
   char *oname = other_file ? g_file_get_parse_name (other_file) : NULL;
 
   char *name = g_file_get_parse_name (file);
   char *oname = other_file ? g_file_get_parse_name (other_file) : NULL;
 
@@ -83,20 +84,36 @@ dir_monitor_callback (GFileMonitor *monitor,
 
   if (CONSP (watch_object))
     {
 
   if (CONSP (watch_object))
     {
-      /* Construct an event.  */
       struct input_event event;
       Lisp_Object otail = oname ? list1 (build_string (oname)) : Qnil;
       struct input_event event;
       Lisp_Object otail = oname ? list1 (build_string (oname)) : Qnil;
-      EVENT_INIT (event);
-      event.kind = FILE_NOTIFY_EVENT;
-      event.frame_or_window = Qnil;
-      event.arg = list2 (Fcons (monitor_object,
-                               Fcons (symbol,
-                                      Fcons (build_string (name),
-                                             otail))),
-                        XCDR (watch_object));
-
-      /* Store it into the input event queue.  */
-      kbd_buffer_store_event (&event);
+
+      /* Check, whether event_type is expected.  */
+      flags = XCAR (XCDR (XCDR (watch_object)));
+      if ((!NILP (Fmember (Qchange, flags)) &&
+          !NILP (Fmember (symbol, list5 (Qchanged, Qchanges_done_hint,
+                                         Qdeleted, Qcreated, Qmoved)))) ||
+         (!NILP (Fmember (Qattribute_change, flags)) &&
+          ((EQ (symbol, Qattribute_changed)))))
+       {
+         /* Construct an event.  */
+         EVENT_INIT (event);
+         event.kind = FILE_NOTIFY_EVENT;
+         event.frame_or_window = Qnil;
+         event.arg = list2 (Fcons (monitor_object,
+                                   Fcons (symbol,
+                                          Fcons (build_string (name),
+                                                 otail))),
+                            XCAR (XCDR (XCDR (XCDR (watch_object)))));
+
+         /* Store it into the input event queue.  */
+         kbd_buffer_store_event (&event);
+         // XD_DEBUG_MESSAGE ("%s", XD_OBJECT_TO_STRING (event.arg));
+       }
+
+      /* Cancel monitor if file or directory is deleted.  */
+      if (!NILP (Fmember (symbol, list2 (Qdeleted, Qmoved))) &&
+         !g_file_monitor_is_cancelled (monitor))
+       g_file_monitor_cancel (monitor);
     }
 
   /* Cleanup.  */
     }
 
   /* Cleanup.  */
@@ -119,9 +136,13 @@ watched for some reason, this function signals a `file-notify-error' error.
 FLAGS is a list of conditions to set what will be watched for.  It can
 include the following symbols:
 
 FLAGS is a list of conditions to set what will be watched for.  It can
 include the following symbols:
 
-  'watch-mounts' -- watch for mount events
-  'send-moved'   -- pair 'deleted' and 'created' events caused by file
-                    renames and send a single 'renamed' event instead
+  `change'           -- watch for file changes
+  `attribute-change' -- watch for file attributes changes, like
+                        permissions or modification time
+  `watch-mounts'     -- watch for mount events
+  `send-moved'       -- pair `deleted' and `created' events caused by
+                        file renames and send a single `renamed' event
+                        instead
 
 When any event happens, Emacs will call the CALLBACK function passing
 it a single argument EVENT, which is of the form
 
 When any event happens, Emacs will call the CALLBACK function passing
 it a single argument EVENT, which is of the form
@@ -132,24 +153,25 @@ DESCRIPTOR is the same object as the one returned by this function.
 ACTION is the description of the event.  It could be any one of the
 following:
 
 ACTION is the description of the event.  It could be any one of the
 following:
 
-  'changed'           -- FILE has changed
-  'changes-done-hint' -- a hint that this was probably the last change
+  `changed'           -- FILE has changed
+  `changes-done-hint' -- a hint that this was probably the last change
                          in a set of changes
                          in a set of changes
-  'deleted'           -- FILE was deleted
-  'created'           -- FILE was created
-  'attribute-changed' -- a FILE attribute was changed
-  'pre-unmount'       -- the FILE location will soon be unmounted
-  'unmounted'         -- the FILE location was unmounted
-  'moved'             -- FILE was moved to FILE1
+  `deleted'           -- FILE was deleted
+  `created'           -- FILE was created
+  `attribute-changed' -- a FILE attribute was changed
+  `pre-unmount'       -- the FILE location will soon be unmounted
+  `unmounted'         -- the FILE location was unmounted
+  `moved'             -- FILE was moved to FILE1
 
 FILE is the name of the file whose event is being reported.  FILE1
 
 FILE is the name of the file whose event is being reported.  FILE1
-will be reported only in case of the 'moved' event.  */)
+will be reported only in case of the `moved' event.  */)
   (Lisp_Object file, Lisp_Object flags, Lisp_Object callback)
 {
   Lisp_Object watch_object;
   GFile *gfile;
   GFileMonitor *monitor;
   GFileMonitorFlags gflags = G_FILE_MONITOR_NONE;
   (Lisp_Object file, Lisp_Object flags, Lisp_Object callback)
 {
   Lisp_Object watch_object;
   GFile *gfile;
   GFileMonitor *monitor;
   GFileMonitorFlags gflags = G_FILE_MONITOR_NONE;
+  GError *gerror = NULL;
 
   /* Check parameters.  */
   CHECK_STRING (file);
 
   /* Check parameters.  */
   CHECK_STRING (file);
@@ -172,7 +194,15 @@ will be reported only in case of the 'moved' event.  */)
     gflags |= G_FILE_MONITOR_SEND_MOVED;
 
   /* Enable watch.  */
     gflags |= G_FILE_MONITOR_SEND_MOVED;
 
   /* Enable watch.  */
-  monitor = g_file_monitor (gfile, gflags, NULL, NULL);
+  monitor = g_file_monitor (gfile, gflags, NULL, &gerror);
+  g_object_unref (gfile);
+  if (gerror)
+    {
+      char msg[1024];
+      strcpy (msg, gerror->message);
+      g_error_free (gerror);
+      xsignal1 (Qfile_notify_error, build_string (msg));
+    }
   if (! monitor)
     xsignal2 (Qfile_notify_error, build_string ("Cannot watch file"), file);
 
   if (! monitor)
     xsignal2 (Qfile_notify_error, build_string ("Cannot watch file"), file);
 
@@ -186,11 +216,15 @@ will be reported only in case of the 'moved' event.  */)
                file);
     }
 
                file);
     }
 
+  /* The default rate limit is 800 msec.  We adapt this.  */
+  g_file_monitor_set_rate_limit (monitor, 100);
+
+  /* Subscribe to the "changed" signal.  */
   g_signal_connect (monitor, "changed",
                    (GCallback) dir_monitor_callback, NULL);
 
   /* Store watch object in watch list.  */
   g_signal_connect (monitor, "changed",
                    (GCallback) dir_monitor_callback, NULL);
 
   /* Store watch object in watch list.  */
-  watch_object = Fcons (watch_descriptor, callback);
+  watch_object = list4 (watch_descriptor, file, flags, callback);
   watch_list = Fcons (watch_object, watch_list);
 
   return watch_descriptor;
   watch_list = Fcons (watch_object, watch_list);
 
   return watch_descriptor;
@@ -210,11 +244,12 @@ WATCH-DESCRIPTOR should be an object returned by `gfile-add-watch'.  */)
 
   eassert (INTEGERP (watch_descriptor));
   GFileMonitor *monitor = XINTPTR (watch_descriptor);
 
   eassert (INTEGERP (watch_descriptor));
   GFileMonitor *monitor = XINTPTR (watch_descriptor);
-  if (!g_file_monitor_cancel (monitor))
-    xsignal2 (Qfile_notify_error, build_string ("Could not rm watch"),
-             watch_descriptor);
+  if (!g_file_monitor_is_cancelled (monitor) &&
+      !g_file_monitor_cancel (monitor))
+      xsignal2 (Qfile_notify_error, build_string ("Could not rm watch"),
+               watch_descriptor);
 
 
-  /* Remove watch descriptor from watch list. */
+  /* Remove watch descriptor from watch list.  */
   watch_list = Fdelq (watch_object, watch_list);
 
   /* Cleanup.  */
   watch_list = Fdelq (watch_object, watch_list);
 
   /* Cleanup.  */
@@ -223,6 +258,27 @@ WATCH-DESCRIPTOR should be an object returned by `gfile-add-watch'.  */)
   return Qt;
 }
 
   return Qt;
 }
 
+DEFUN ("gfile-valid-p", Fgfile_valid_p, Sgfile_valid_p, 1, 1, 0,
+       doc: /* "Check a watch specified by its WATCH-DESCRIPTOR.
+
+WATCH-DESCRIPTOR should be an object returned by `gfile-add-watch'.
+
+A watch can become invalid if the file or directory it watches is
+deleted, or if the watcher thread exits abnormally for any other
+reason.  Removing the watch by calling `gfile-rm-watch' also makes it
+invalid.  */)
+     (Lisp_Object watch_descriptor)
+{
+  Lisp_Object watch_object = Fassoc (watch_descriptor, watch_list);
+  if (NILP (watch_object))
+    return Qnil;
+  else
+    {
+      GFileMonitor *monitor = XINTPTR (watch_descriptor);
+      return g_file_monitor_is_cancelled (monitor) ? Qnil : Qt;
+    }
+}
+
 \f
 void
 globals_of_gfilenotify (void)
 \f
 void
 globals_of_gfilenotify (void)
@@ -236,13 +292,13 @@ globals_of_gfilenotify (void)
 void
 syms_of_gfilenotify (void)
 {
 void
 syms_of_gfilenotify (void)
 {
-  DEFSYM (Qgfile_add_watch, "gfile-add-watch");
   defsubr (&Sgfile_add_watch);
   defsubr (&Sgfile_add_watch);
-
-  DEFSYM (Qgfile_rm_watch, "gfile-rm-watch");
   defsubr (&Sgfile_rm_watch);
   defsubr (&Sgfile_rm_watch);
+  defsubr (&Sgfile_valid_p);
 
   /* Filter objects.  */
 
   /* Filter objects.  */
+  DEFSYM (Qchange, "change");
+  DEFSYM (Qattribute_change, "attribute-change");
   DEFSYM (Qwatch_mounts, "watch-mounts"); /* G_FILE_MONITOR_WATCH_MOUNTS  */
   DEFSYM (Qsend_moved, "send-moved");  /* G_FILE_MONITOR_SEND_MOVED  */
 
   DEFSYM (Qwatch_mounts, "watch-mounts"); /* G_FILE_MONITOR_WATCH_MOUNTS  */
   DEFSYM (Qsend_moved, "send-moved");  /* G_FILE_MONITOR_SEND_MOVED  */