1 /*
2 * Copyright 2018 LarsGit223
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 /*
20 * Code for file monitoring.
21 */
22 #include <glib/gstdio.h>
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <geanyplugin.h>
29 #include "wb_globals.h"
30 #include "workbench.h"
31 #include "wb_monitor.h"
32 #include "utils.h"
33
34
35 struct S_WB_MONITOR
36 {
37 GHashTable *monitors;
38 };
39
40 typedef struct
41 {
42 GFileMonitor *monitor;
43 WB_PROJECT *prj;
44 WB_PROJECT_DIR *dir;
45 }WB_MONITOR_ENTRY;
46
47
48 /** Create a new, empty WB_MONITOR.
49 *
50 * @return Address of the new WB_MONITOR
51 *
52 **/
wb_monitor_new(void)53 WB_MONITOR *wb_monitor_new(void)
54 {
55 WB_MONITOR *monitor;
56
57 monitor = g_new0(WB_MONITOR, 1);
58
59 return monitor;
60 }
61
62
63 /* Create a new monitor entry */
wb_monitor_entry_new(GFileMonitor * monitor,WB_PROJECT * prj,WB_PROJECT_DIR * dir)64 static WB_MONITOR_ENTRY *wb_monitor_entry_new (GFileMonitor *monitor,
65 WB_PROJECT *prj, WB_PROJECT_DIR *dir)
66 {
67 WB_MONITOR_ENTRY *new;
68
69 new = g_new0(WB_MONITOR_ENTRY, 1);
70 new->monitor = monitor;
71 new->prj = prj;
72 new->dir = dir;
73
74 return new;
75 }
76
77
78 /* Free a monitor entry */
wb_monitor_entry_free(gpointer data)79 static void wb_monitor_entry_free (gpointer data)
80 {
81 WB_MONITOR_ENTRY *entry = data;
82
83 if (data != NULL)
84 {
85 g_object_unref(entry->monitor);
86 g_free(entry);
87 }
88 }
89
90
91 /* Callback function for file monitoring. */
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)92 static void wb_monitor_file_changed_cb(G_GNUC_UNUSED GFileMonitor *monitor,
93 G_GNUC_UNUSED GFile *file,
94 G_GNUC_UNUSED GFile *other_file,
95 GFileMonitorEvent event,
96 WB_MONITOR_ENTRY *entry)
97 {
98 const gchar *event_string = NULL;
99 gchar *file_path, *other_file_path = NULL;
100
101 g_return_if_fail(entry != NULL);
102
103 g_message("%s: event: %d", G_STRFUNC, event);
104
105 file_path = g_file_get_path (file);
106 if (other_file != NULL)
107 {
108 other_file_path = g_file_get_path (other_file);
109 }
110 switch (event)
111 {
112 case G_FILE_MONITOR_EVENT_CREATED:
113 event_string = "FILE_CREATED";
114 workbench_process_add_file_event (wb_globals.opened_wb,
115 entry->prj, entry->dir, file_path);
116 break;
117
118 case G_FILE_MONITOR_EVENT_DELETED:
119 event_string = "FILE_DELETED";
120 workbench_process_remove_file_event (wb_globals.opened_wb,
121 entry->prj, entry->dir, file_path);
122 break;
123
124 default:
125 break;
126 }
127
128 if (event_string != NULL)
129 {
130 g_message("%s: Prj: \"%s\" Dir: \"%s\" %s: \"%s\"", G_STRFUNC, wb_project_get_name(entry->prj),
131 wb_project_dir_get_name(entry->dir), event_string, file_path);
132 }
133
134 g_free(file_path);
135 g_free(other_file_path);
136 }
137
138
139 /** Add a new file monitor
140 *
141 * Add a new file monitor for dirpath. The monitor will only be created
142 * if the settings option "Enable live monitor" is set to on and if
143 * no file monitor exists for dirpath already. If monitor creation fails,
144 * that means g_file_monitor_directory returns NULL, then a message is
145 * output on the statusbar.
146 *
147 * @param monitor The global monitor management
148 * @param prj The project to which dirpath belongs
149 * @param dir The directory (WB_PROJECT_DIR) to which dirpath belongs
150 * @param dirpath The path of the directory
151 *
152 **/
wb_monitor_add_dir(WB_MONITOR * monitor,WB_PROJECT * prj,WB_PROJECT_DIR * dir,const gchar * dirpath)153 void wb_monitor_add_dir(WB_MONITOR *monitor, WB_PROJECT *prj,
154 WB_PROJECT_DIR *dir, const gchar *dirpath)
155 {
156 GFileMonitor *newmon;
157 GFile *file;
158 GError *error = NULL;
159 WB_MONITOR_ENTRY *entry;
160
161 g_return_if_fail(monitor != NULL);
162 g_return_if_fail(dir != NULL);
163 g_return_if_fail(dirpath != NULL);
164
165 if (workbench_get_enable_live_update(wb_globals.opened_wb) == FALSE)
166 {
167 /* Return if the feature is disabled. */
168 return;
169 }
170
171 if (monitor->monitors == NULL)
172 {
173 monitor->monitors = g_hash_table_new_full
174 (g_str_hash, g_str_equal, g_free, wb_monitor_entry_free);
175 }
176 if (g_hash_table_contains(monitor->monitors, dirpath))
177 {
178 /* A monitor for that path already exists,
179 do not create another one. */
180 return;
181 }
182
183 /* Setup file monitor for directory */
184 file = g_file_new_for_path(dirpath);
185 newmon = g_file_monitor_directory
186 (file, G_FILE_MONITOR_NONE, NULL, &error);
187 if (newmon == NULL)
188 {
189 /* Create monitor failed. Report error. */
190 ui_set_statusbar(TRUE,
191 _("Could not setup file monitoring for directory: \"%s\". Error: %s"),
192 dirpath, error->message);
193 g_error_free (error);
194 return;
195 }
196 else
197 {
198 /* Add file monitor to hash table. */
199 entry = wb_monitor_entry_new(newmon, prj, dir);
200 g_hash_table_insert(monitor->monitors, (gpointer)g_strdup(dirpath), entry);
201
202 g_signal_connect(newmon, "changed",
203 G_CALLBACK(wb_monitor_file_changed_cb), entry);
204
205 /* ToDo: make rate limit configurable */
206 g_file_monitor_set_rate_limit(newmon, 5 * 1000);
207 }
208 g_object_unref(file);
209 }
210
211
212 /** Remove a file monitor
213 *
214 * Remove the file monitor for dirpath.
215 *
216 * @param monitor The global monitor management
217 * @param dirpath The path of the directory
218 *
219 **/
wb_monitor_remove_dir(WB_MONITOR * monitor,const gchar * dirpath)220 gboolean wb_monitor_remove_dir(WB_MONITOR *monitor, const gchar *dirpath)
221 {
222 if (monitor == NULL || dirpath == NULL)
223 {
224 return FALSE;
225 }
226
227 /* Free the entry. The hash table will call the destroy function
228 wb_monitor_entry_free which is doing the work for us. */
229 return g_hash_table_remove(monitor->monitors, dirpath);
230 }
231
232
233 /** Free monitor management/all file monitors.
234 *
235 * @param monitor The global monitor management
236 *
237 **/
wb_monitor_free(WB_MONITOR * monitor)238 void wb_monitor_free(WB_MONITOR *monitor)
239 {
240 if (monitor != NULL)
241 {
242 if (monitor->monitors != NULL)
243 {
244 g_hash_table_unref(monitor->monitors);
245 monitor->monitors = NULL;
246 }
247 }
248 }
249