I've been working on a Dropbox indicator for Wingpanel and one of the features I've been trying to implement is a list of recent activity, that is, a list of the most recent modified/created files.
I know we do have inotify. However, it has two limitations:
- it doesn't watch for changes in subfolder;
- there is a max number of folders you can watch at once.
So, my approach is the following one: I run through the entire tree structure comparing modification dates of each folder. If some change is detected I emit a signal and stop. However, in order to avoid freezing the GUI while performing this search, I have to execute it in another thread.
So, my indicator runs this search at every 3s. It has worked just fine for me. However, some users have pointed out a Segmentation Fault error exactly while this search is being executed. In a specific case, the folder structure has like 23k files and folders.
Does anyone have a better solution? Thank you all in advance!
I post my code below.
The following code is executed at every 3s and it creates a new Thread where I perform the looking for changes.
private async bool core () throws ThreadError {
// Do not create a new Thread if there is another
if (is_working == false) {
is_working = true;
SourceFunc callback = core.callback;
ThreadFunc<bool> run = () => {
File dir_root = File.new_for_path (path);
try {
FileInfo info = dir_root.query_info ("*", 0);
string iso = info.get_modification_time().to_iso8601();
GLib.DateTime file_modification_date = new GLib.DateTime.from_iso8601 (iso, null);
// Check if the root dir has changed
if (last_check_date.compare (file_modification_date) == -1) {
is_working = false;
// emitting change signal
changed (info);
} else {
compare_modification_date (path, last_check_date);
is_working = false;
}
last_check_date = new DateTime.now_local ();
Idle.add ((owned)callback);
return true;
} catch (Error e) {
print ("Error getting info: %s",e.message);
return false;
}
};
new Thread<bool>("compare-dir", run);
yield;
}
return true;
}
The code below is the recursive function that does the job of comparing modification dates.
private void compare_modification_date (string dir_path, GLib.DateTime d) {
File dir = File.new_for_path (dir_path);
//
try {
FileEnumerator files = dir.enumerate_children("*", FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
FileInfo info = files.next_file (null);
while(info != null) {
if(info.get_file_type() == FileType.DIRECTORY && !info.get_name().has_prefix(".") ) {
string iso = info.get_modification_time().to_iso8601();
GLib.DateTime file_modification_date = new GLib.DateTime.from_iso8601 (iso, null);
if (d.compare(file_modification_date) == -1) {
print ("The dir %s has been modified.", info.get_name());
// emitting change signal
changed (info);
break;
} else {
compare_modification_date(dir_path+"/"+info.get_name(), d);
info =files.next_file (null);
}
} else {
info = files.next_file(null);
}
}
} catch (Error e) {
print ("Error comparing dates:%s", e.message);
}
}
}