/* * Copyright 2018 LarsGit223 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Code for file monitoring. */ #include #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include "wb_globals.h" #include "workbench.h" #include "wb_monitor.h" #include "utils.h" struct S_WB_MONITOR { GHashTable *monitors; }; typedef struct { GFileMonitor *monitor; WB_PROJECT *prj; WB_PROJECT_DIR *dir; }WB_MONITOR_ENTRY; /** Create a new, empty WB_MONITOR. * * @return Address of the new WB_MONITOR * **/ WB_MONITOR *wb_monitor_new(void) { WB_MONITOR *monitor; monitor = g_new0(WB_MONITOR, 1); return monitor; } /* Create a new monitor entry */ static WB_MONITOR_ENTRY *wb_monitor_entry_new (GFileMonitor *monitor, WB_PROJECT *prj, WB_PROJECT_DIR *dir) { WB_MONITOR_ENTRY *new; new = g_new0(WB_MONITOR_ENTRY, 1); new->monitor = monitor; new->prj = prj; new->dir = dir; return new; } /* Free a monitor entry */ static void wb_monitor_entry_free (gpointer data) { WB_MONITOR_ENTRY *entry = data; if (data != NULL) { g_object_unref(entry->monitor); g_free(entry); } } /* Callback function for file monitoring. */ static void wb_monitor_file_changed_cb(G_GNUC_UNUSED GFileMonitor *monitor, G_GNUC_UNUSED GFile *file, G_GNUC_UNUSED GFile *other_file, GFileMonitorEvent event, WB_MONITOR_ENTRY *entry) { const gchar *event_string = NULL; gchar *file_path, *other_file_path = NULL; g_return_if_fail(entry != NULL); g_message("%s: event: %d", G_STRFUNC, event); file_path = g_file_get_path (file); if (other_file != NULL) { other_file_path = g_file_get_path (other_file); } switch (event) { case G_FILE_MONITOR_EVENT_CREATED: event_string = "FILE_CREATED"; workbench_process_add_file_event (wb_globals.opened_wb, entry->prj, entry->dir, file_path); break; case G_FILE_MONITOR_EVENT_DELETED: event_string = "FILE_DELETED"; workbench_process_remove_file_event (wb_globals.opened_wb, entry->prj, entry->dir, file_path); break; default: break; } if (event_string != NULL) { g_message("%s: Prj: \"%s\" Dir: \"%s\" %s: \"%s\"", G_STRFUNC, wb_project_get_name(entry->prj), wb_project_dir_get_name(entry->dir), event_string, file_path); } g_free(file_path); g_free(other_file_path); } /** Add a new file monitor * * Add a new file monitor for dirpath. The monitor will only be created * if the settings option "Enable live monitor" is set to on and if * no file monitor exists for dirpath already. If monitor creation fails, * that means g_file_monitor_directory returns NULL, then a message is * output on the statusbar. * * @param monitor The global monitor management * @param prj The project to which dirpath belongs * @param dir The directory (WB_PROJECT_DIR) to which dirpath belongs * @param dirpath The path of the directory * **/ void wb_monitor_add_dir(WB_MONITOR *monitor, WB_PROJECT *prj, WB_PROJECT_DIR *dir, const gchar *dirpath) { GFileMonitor *newmon; GFile *file; GError *error = NULL; WB_MONITOR_ENTRY *entry; g_return_if_fail(monitor != NULL); g_return_if_fail(dir != NULL); g_return_if_fail(dirpath != NULL); if (workbench_get_enable_live_update(wb_globals.opened_wb) == FALSE) { /* Return if the feature is disabled. */ return; } if (monitor->monitors == NULL) { monitor->monitors = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, wb_monitor_entry_free); } if (g_hash_table_contains(monitor->monitors, dirpath)) { /* A monitor for that path already exists, do not create another one. */ return; } /* Setup file monitor for directory */ file = g_file_new_for_path(dirpath); newmon = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, &error); if (newmon == NULL) { /* Create monitor failed. Report error. */ ui_set_statusbar(TRUE, _("Could not setup file monitoring for directory: \"%s\". Error: %s"), dirpath, error->message); g_error_free (error); return; } else { /* Add file monitor to hash table. */ entry = wb_monitor_entry_new(newmon, prj, dir); g_hash_table_insert(monitor->monitors, (gpointer)g_strdup(dirpath), entry); g_signal_connect(newmon, "changed", G_CALLBACK(wb_monitor_file_changed_cb), entry); /* ToDo: make rate limit configurable */ g_file_monitor_set_rate_limit(newmon, 5 * 1000); } g_object_unref(file); } /** Remove a file monitor * * Remove the file monitor for dirpath. * * @param monitor The global monitor management * @param dirpath The path of the directory * **/ gboolean wb_monitor_remove_dir(WB_MONITOR *monitor, const gchar *dirpath) { if (monitor == NULL || dirpath == NULL) { return FALSE; } /* Free the entry. The hash table will call the destroy function wb_monitor_entry_free which is doing the work for us. */ return g_hash_table_remove(monitor->monitors, dirpath); } /** Free monitor management/all file monitors. * * @param monitor The global monitor management * **/ void wb_monitor_free(WB_MONITOR *monitor) { if (monitor != NULL) { if (monitor->monitors != NULL) { g_hash_table_unref(monitor->monitors); monitor->monitors = NULL; } } }