Be notified when custom attributes in a file change

Hello:

I have files with the “metadata::custom-icon” custom attribute, and I need to detect when that attribute changes. I tried using a file monitor both in the file itself and in the folder that contains the file, but I don’t receive notifications in that case. I know that nautilus detects it, but I’ve been checking the code without luck.

How can I detect it?

Thanks.

EDIT: I found that there is a DBus interface, org.gtk.vfs.Metadata, but there is no signal for specify that something changed.

EDIT2: I found that the metadata is stored at ~/.local/share/gvfs-metadata, in, at least, two files: home, and home-XXXXXX.log. The later one seems to be updated every time a change is made to a metadata key-value, and the former seems to be updated with a lot of delay. I found some info at https://gitlab.gnome.org/GNOME/gvfs/-/blob/master/metadata/file-format.txt, but there doesn’t explain how to know which of all those files contain the journal (in my system I have several .log files, but all but one are quite old…).

EDIT3: Tried to use a GLib.Monitor checking that folder, but doesn’t work as expected. There is a big delay between when the data is updated and when the events are generated. Even with a C program using inotify there are big delays (about 40 seconds). Maybe is it because the files are MMAPed? (Can’t confirm because gitlab.gnome.org is down, so I can’t get the code for the metadata daemon). If that’s the case, is there a way of being notified of a change in an MMAPed file using GLib and Javascript?

EDIT4: I forgot to comment that Nautilus does all the notification internally. When it changes the property, it notifies with a GLib signal, to which, of course, an external process can’t connect.

Hey, do you mind giving a bit more context ?

Like, metadata::custom-icon is a path to the icon file right? But what is exactly changing? The contents of the same file? or the value of custom-icon , e.g. to a different file?

Yes, it is a path to the icon file. And what I want to detect is when the user changes the custom icon to another file, to update the icon in the desktop (it is for Desktop Icons NG extension); this is, I want to detect when the path stored in the metadata changes. Currently, the process is:

  • From Desktop Icons NG (DING), the user right-click in an icon and chooses “Properties”
  • DING, using DBus, asks Nautilus to show the Properties dialog
  • In the Nautilus dialog, the user chooses a new icon (or restores the default one)
  • Nautilus uses the gio_fileinfo API to set the value of “metadata::custom-icon” to a string with the path of the icon (or removes the entry if the user wants to restore the default icon).
  • Internally, it all goes through DBus to gvfs-metadata daemon, who is the responsible of writing the data in a file at .local/share/gvfs-metadata, using some kind of journal system to ensure integrity (because, if I understood it right, only the writing is done through the daemon; reading is done directly by each program by reading that file).

And that is the problem: since DING is a different program, I can’t modify the Nautilus property dialog to send a GLib signal when the user changes the icon. Also, since the metadata is not stored in the file itself, it neither work to monitor the file whose the user is changing its icon, nor the folder that contains it. I tried monitoring the folder where the metadata files are stored, but there is a very big delay (about 40 seconds) between the user changing the icon and the file being updated in the disk (and I suspect that it is because it is mmaped by the daemon).

Oddly enough, a user tested the patch that I did for DING for supporting this and says that, under Ubuntu 19.10, as soon as he changes the icon in Nautilus, DING also changes the icon (when, in that patch, there is nothing to detect changes in the metadata). But in my system, with Debian SID, I can’t reproduce that: changing the icon from Nautilus doesn’t trigger DING (I’m installing now a virtual machine with ubuntu to test this by myself).

I see, so what you’re saying is:

  1. org.gtk.vfs.Metadata interface doesn’t implement PropertyChanged signal.
  2. GFileInfo doesn’t implement any signal either.
  3. .local/share/gvfs-metadata is cached in memory so monitoring is not an option, due the write-to-disk delays.

If that all happens to be correct, the next question would be, roughly how many files do you need to monitor at time? e.g. 100 ? And, what would be the minimum delay you consider acceptable ?

Because, if the number of files is low, and if you can live with a reasonable delay. Something like this could do the job:

from gi.repository import Gio, GLib

ATTRIBUTE = 'metadata::custom-icon'


def _on_monitor_custom_icon(file):
    info = file.query_info(ATTRIBUTE, Gio.FileQueryInfoFlags.NONE, None)
    print(info.get_attribute_string(ATTRIBUTE))
    return True

file = Gio.File.new_for_path('./a_file')
GLib.timeout_add(2000, _on_monitor_custom_icon, file)

GLib.MainLoop().run()

NOTE: You could wrap that into a GObject with a custom-icon property, and then just connect('notify::custom-icon' ...). So you can abstract from it’s ugliness hah.

I know that it would work, but the point is that changes in the metadata are very uncommon, but at the same time when the user changes them, expects the change to be instantaneous, so checking each second for something that only happens maybe once or twice a day if you are lucky is extremely ugly. That’s why I was asking if there was another way.

In fact, I did some test to add a signal to gvfs-metadata, and seems to work, but if there was another solution that didn’t require to modify the daemon, I would prefer it.

Agreed, it really comes down to how important this “feature” really is for whatever you’re building (to live without it) vs having something ugly that works (to live with it). Until a better solution is found.

Re. your changes to the daemon, I would definitely share with the vfs metadata maintainers. It looks useful to me, and it would be the right solution for you in the long term.

Yes, my intention is to send a patch to the maintainers. Also, in the meantime, maybe I can do a trick, like use exponential times to check for changes, and reset the timer every time the user opens the property window… Even more ugly :smiley:

Odd… Confirmed that in Ubuntu 19.10 it detects the change…

Ok, here is the odd thing… In Ubuntu, when the icon is changed, a change in “show-hide” property is triggered, but not in Debian.

Which show-hide property are you referring to ? where is it?

org.gtk.Settings.FileChooser.show-hidden

(I wrote it wrong in the other message)

And the point is that the value hasn’t really changed… (I added a line to print the old and the new values)

Ok, first proposal (which surely will need a lot of reviews) https://gitlab.gnome.org/GNOME/gvfs/-/merge_requests/84

1 Like

Found more things: the “change” signal is emitted by the File Chooser widget; using Drag’n’Drop for changing the icon doesn’t trigger it.