Merge lp:~3v1n0/bamf/fixes into lp:bamf/0.4
- fixes
- Merge into 0.4
Status: | Merged | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Merged at revision: | 412 | ||||||||||||
Proposed branch: | lp:~3v1n0/bamf/fixes | ||||||||||||
Merge into: | lp:bamf/0.4 | ||||||||||||
Diff against target: |
1121 lines (+555/-236) 3 files modified
src/bamf-application.c (+27/-14) src/bamf-application.h (+4/-4) src/bamf-matcher.c (+524/-218) |
||||||||||||
To merge this branch: | bzr merge lp:~3v1n0/bamf/fixes | ||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jason Smith (community) | Approve | ||
Unity Community Hackers | Pending | ||
Review via email:
|
Commit message
Description of the change
This is a branch I'm working on during my spare time since some weeks; it includes some BAMF miscellaneous fixes.
- Improved desktop folders monitoring support (fix bug #676593) supporting monitoring
newly added .desktop files, newly added folders containing .desktop files
(recursively), edited .desktop files (reducing the rate limit, to save CPU)
- Correctly clear from BAMF cache .desktop files that are removed from system
- Order correctly the .desktop file keeping their priority
- Support the ~/Desktop folder and $XDG_DATA_HOME as .desktop storages (with
highest priority, the order will be kept when adding new files) bug #768636
- Some memory leaks and coding style fixes...
I would have added also the support for dynamically update a bamf_application when a .desktop file (that matches it) is removed, but I guess that it's not vital... On next application reload the user will notice the change (however, if it is requested, I've already done something in it).
For more informations, look at the logs [1]; I've wrote anything there.
- 423. By Marco Trevisan (Treviño)
-
compare_sub_values optimization.
Generate the "prefix" string just once, and not for every sub-folder
.desktop item compared. This should save many allocations/copies. ..
Preview Diff
1 | === modified file 'src/bamf-application.c' |
2 | --- src/bamf-application.c 2011-04-18 17:34:28 +0000 |
3 | +++ src/bamf-application.c 2011-06-26 22:21:13 +0000 |
4 | @@ -237,21 +237,30 @@ |
5 | |
6 | void |
7 | bamf_application_set_desktop_file (BamfApplication *application, |
8 | - char * desktop_file) |
9 | + const char * desktop_file) |
10 | { |
11 | g_return_if_fail (BAMF_IS_APPLICATION (application)); |
12 | |
13 | - application->priv->desktop_file = g_strdup (desktop_file); |
14 | + if (application->priv->desktop_file) |
15 | + g_free (application->priv->desktop_file); |
16 | + |
17 | + if (desktop_file && desktop_file[0] != '\0') |
18 | + application->priv->desktop_file = g_strdup (desktop_file); |
19 | + else |
20 | + application->priv->desktop_file = NULL; |
21 | |
22 | bamf_application_setup_icon_and_name (application); |
23 | } |
24 | |
25 | void |
26 | bamf_application_set_wmclass (BamfApplication *application, |
27 | - char *wmclass) |
28 | + const char *wmclass) |
29 | { |
30 | g_return_if_fail (BAMF_IS_APPLICATION (application)); |
31 | |
32 | + if (application->priv->wmclass) |
33 | + g_free (application->priv->wmclass); |
34 | + |
35 | if (wmclass && wmclass[0] != '\0') |
36 | application->priv->wmclass = g_strdup (wmclass); |
37 | else |
38 | @@ -517,16 +526,24 @@ |
39 | g_return_if_fail (list); |
40 | |
41 | priv = self->priv; |
42 | - |
43 | + |
44 | + if (priv->desktop_file_list) |
45 | + { |
46 | + g_list_free_full (priv->desktop_file_list, g_free); |
47 | + priv->desktop_file_list = NULL; |
48 | + } |
49 | + |
50 | for (l = list; l; l = l->next) |
51 | priv->desktop_file_list = g_list_prepend (priv->desktop_file_list, g_strdup (l->data)); |
52 | - |
53 | + |
54 | + priv->desktop_file_list = g_list_reverse (priv->desktop_file_list); |
55 | + |
56 | desktop_file = bamf_application_favorite_from_list (self, priv->desktop_file_list); |
57 | |
58 | - /* items come in priority order */ |
59 | + /* items, after reversing them, are in priority order */ |
60 | if (!desktop_file) |
61 | desktop_file = list->data; |
62 | - |
63 | + |
64 | bamf_application_set_desktop_file (self, desktop_file); |
65 | } |
66 | |
67 | @@ -576,7 +593,6 @@ |
68 | { |
69 | BamfApplication *app; |
70 | BamfApplicationPrivate *priv; |
71 | - GList *l; |
72 | |
73 | app = BAMF_APPLICATION (object); |
74 | priv = app->priv; |
75 | @@ -589,10 +605,7 @@ |
76 | |
77 | if (priv->desktop_file_list) |
78 | { |
79 | - for (l = priv->desktop_file_list; l; l = l->next) |
80 | - g_free (l->data); |
81 | - |
82 | - g_list_free (priv->desktop_file_list); |
83 | + g_list_free_full (priv->desktop_file_list, g_free); |
84 | priv->desktop_file_list = NULL; |
85 | } |
86 | |
87 | @@ -676,7 +689,7 @@ |
88 | } |
89 | |
90 | BamfApplication * |
91 | -bamf_application_new_from_desktop_file (char * desktop_file) |
92 | +bamf_application_new_from_desktop_file (const char * desktop_file) |
93 | { |
94 | BamfApplication *application; |
95 | application = (BamfApplication *) g_object_new (BAMF_TYPE_APPLICATION, NULL); |
96 | @@ -698,7 +711,7 @@ |
97 | } |
98 | |
99 | BamfApplication * |
100 | -bamf_application_new_with_wmclass (char *wmclass) |
101 | +bamf_application_new_with_wmclass (const char *wmclass) |
102 | { |
103 | BamfApplication *application; |
104 | application = (BamfApplication *) g_object_new (BAMF_TYPE_APPLICATION, NULL); |
105 | |
106 | === modified file 'src/bamf-application.h' |
107 | --- src/bamf-application.h 2011-03-29 09:37:44 +0000 |
108 | +++ src/bamf-application.h 2011-06-26 22:21:13 +0000 |
109 | @@ -56,7 +56,7 @@ |
110 | |
111 | char * bamf_application_get_desktop_file (BamfApplication *application); |
112 | void bamf_application_set_desktop_file (BamfApplication *application, |
113 | - char * desktop_file); |
114 | + const char * desktop_file); |
115 | |
116 | GArray * bamf_application_get_xids (BamfApplication *application); |
117 | |
118 | @@ -68,15 +68,15 @@ |
119 | |
120 | char * bamf_application_get_wmclass (BamfApplication *application); |
121 | void bamf_application_set_wmclass (BamfApplication *application, |
122 | - char *wmclass); |
123 | + const char *wmclass); |
124 | |
125 | BamfApplication * bamf_application_new (void); |
126 | |
127 | -BamfApplication * bamf_application_new_from_desktop_file (char * desktop_file); |
128 | +BamfApplication * bamf_application_new_from_desktop_file (const char * desktop_file); |
129 | gboolean bamf_application_get_show_stubs (BamfApplication *application); |
130 | |
131 | BamfApplication * bamf_application_new_from_desktop_files (GList * desktop_files); |
132 | |
133 | -BamfApplication * bamf_application_new_with_wmclass (char *wmclass); |
134 | +BamfApplication * bamf_application_new_with_wmclass (const char *wmclass); |
135 | |
136 | #endif |
137 | |
138 | === modified file 'src/bamf-matcher.c' |
139 | --- src/bamf-matcher.c 2011-04-27 16:48:14 +0000 |
140 | +++ src/bamf-matcher.c 2011-06-26 22:21:13 +0000 |
141 | @@ -150,7 +150,7 @@ |
142 | type = bamf_view_get_view_type (view); |
143 | |
144 | g_signal_connect (G_OBJECT (view), "closed-internal", |
145 | - (GCallback) on_view_closed, self); |
146 | + (GCallback) on_view_closed, self); |
147 | g_signal_connect (G_OBJECT (view), "active-changed", |
148 | (GCallback) on_view_active_changed, self); |
149 | |
150 | @@ -275,28 +275,28 @@ |
151 | part = parts[i]; |
152 | |
153 | if (!g_str_has_prefix (part, "-")) |
154 | - { |
155 | - tmp = g_utf8_strrchr (part, -1, '/'); |
156 | - if (tmp) |
157 | - part = tmp + 1; |
158 | - |
159 | - regexFail = FALSE; |
160 | - for (j = 0; j < self->priv->bad_prefixes->len; j++) |
161 | - { |
162 | - regex = g_array_index (self->priv->bad_prefixes, GRegex *, j); |
163 | - if (g_regex_match (regex, part, 0, NULL)) |
164 | - { |
165 | - regexFail = TRUE; |
166 | - break; |
167 | - } |
168 | - } |
169 | - |
170 | - if (!regexFail) |
171 | - { |
172 | - result = g_strdup (part); |
173 | - break; |
174 | - } |
175 | - } |
176 | + { |
177 | + tmp = g_utf8_strrchr (part, -1, G_DIR_SEPARATOR); |
178 | + if (tmp) |
179 | + part = tmp + 1; |
180 | + |
181 | + regexFail = FALSE; |
182 | + for (j = 0; j < self->priv->bad_prefixes->len; j++) |
183 | + { |
184 | + regex = g_array_index (self->priv->bad_prefixes, GRegex *, j); |
185 | + if (g_regex_match (regex, part, 0, NULL)) |
186 | + { |
187 | + regexFail = TRUE; |
188 | + break; |
189 | + } |
190 | + } |
191 | + |
192 | + if (!regexFail) |
193 | + { |
194 | + result = g_strdup (part); |
195 | + break; |
196 | + } |
197 | + } |
198 | i++; |
199 | } |
200 | |
201 | @@ -404,6 +404,34 @@ |
202 | return !g_str_has_prefix (exec, "ooffice") && !g_str_has_prefix (exec, "libreoffice"); |
203 | } |
204 | |
205 | +static gboolean |
206 | +is_desktop_folder_item (const char *desktop_file_path, gssize max_len) |
207 | +{ |
208 | + gsize len; |
209 | + const char *desktop_folder; |
210 | + |
211 | + g_return_val_if_fail (desktop_file_path, FALSE); |
212 | + |
213 | + if (max_len > 0) |
214 | + { |
215 | + len = max_len; |
216 | + } |
217 | + else |
218 | + { |
219 | + char *tmp; |
220 | + tmp = strrchr (desktop_file_path, G_DIR_SEPARATOR); |
221 | + g_return_val_if_fail (tmp, FALSE); |
222 | + len = tmp - desktop_file_path; |
223 | + } |
224 | + |
225 | + desktop_folder = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP); |
226 | + |
227 | + if (strncmp (desktop_folder, desktop_file_path, len) == 0) |
228 | + return TRUE; |
229 | + |
230 | + return FALSE; |
231 | +} |
232 | + |
233 | static void |
234 | insert_data_into_tables (BamfMatcher *self, |
235 | const char *data, |
236 | @@ -421,20 +449,60 @@ |
237 | file_list = g_hash_table_lookup (desktop_file_table, exec); |
238 | id_list = g_hash_table_lookup (desktop_id_table, desktop_id); |
239 | |
240 | + if (g_list_find_custom (file_list, data, (GCompareFunc) g_strcmp0) && |
241 | + g_list_find_custom (id_list, data, (GCompareFunc) g_strcmp0)) |
242 | + { |
243 | + return; |
244 | + } |
245 | + |
246 | datadup = g_strdup (data); |
247 | - |
248 | + |
249 | /* order so that items whose desktop_id == exec string are first in the list */ |
250 | - if (g_strcmp0 (exec, desktop_id) == 0) |
251 | + |
252 | + if (g_strcmp0 (exec, desktop_id) == 0 || is_desktop_folder_item (datadup, -1)) |
253 | { |
254 | - file_list = g_list_prepend (file_list, datadup); |
255 | - id_list = g_list_prepend (id_list, datadup); |
256 | + GList *l, *last; |
257 | + last = NULL; |
258 | + |
259 | + for (l = file_list; l; l = l->next) |
260 | + { |
261 | + char *dpath; |
262 | + char *dname_start, *dname_end; |
263 | + size_t len; |
264 | + |
265 | + dpath = l->data; |
266 | + dname_start = strrchr (dpath, G_DIR_SEPARATOR); |
267 | + if (!dname_start) |
268 | + { |
269 | + continue; |
270 | + } |
271 | + |
272 | + dname_start++; |
273 | + dname_end = strrchr (dname_start, '.'); |
274 | + len = dname_end - dname_start; |
275 | + |
276 | + if (!dname_end || len < 1) |
277 | + { |
278 | + continue; |
279 | + } |
280 | + |
281 | + if (strncmp (desktop_id, dname_start, len) != 0 && |
282 | + !is_desktop_folder_item (dpath, (dname_start - dpath - 1))) |
283 | + { |
284 | + last = l; |
285 | + break; |
286 | + } |
287 | + } |
288 | + |
289 | + file_list = g_list_insert_before (file_list, last, datadup); |
290 | } |
291 | else |
292 | { |
293 | file_list = g_list_append (file_list, datadup); |
294 | - id_list = g_list_append (id_list, datadup); |
295 | } |
296 | |
297 | + id_list = g_list_append (id_list, datadup); |
298 | + |
299 | g_hash_table_insert (desktop_file_table, g_strdup (exec), file_list); |
300 | g_hash_table_insert (desktop_id_table, g_strdup (desktop_id), id_list); |
301 | } |
302 | @@ -530,8 +598,8 @@ |
303 | GFile *dir; |
304 | GFileEnumerator *enumerator; |
305 | GFileInfo *info; |
306 | - const char* name; |
307 | - const char *path; |
308 | + const char *name; |
309 | + char *path; |
310 | |
311 | dir = g_file_new_for_path (directory); |
312 | |
313 | @@ -558,7 +626,7 @@ |
314 | desktop_id_table, |
315 | desktop_class_table); |
316 | |
317 | - g_free ((gpointer) path); |
318 | + g_free (path); |
319 | g_object_unref (info); |
320 | } |
321 | |
322 | @@ -599,8 +667,8 @@ |
323 | while ((line = g_data_input_stream_read_line (input, &length, NULL, NULL)) != NULL) |
324 | { |
325 | char *exec; |
326 | + char *filename; |
327 | GString *desktop_id; |
328 | - GString *filename; |
329 | |
330 | gchar **parts = g_strsplit (line, "\t", 3); |
331 | |
332 | @@ -612,64 +680,37 @@ |
333 | exec = tmp; |
334 | } |
335 | |
336 | - char *name = g_build_filename (directory, parts[0], NULL); |
337 | - filename = g_string_new (name); |
338 | - g_free ((gpointer) name); |
339 | + filename = g_build_filename (directory, parts[0], NULL); |
340 | |
341 | desktop_id = g_string_new (parts[0]); |
342 | g_string_truncate (desktop_id, desktop_id->len - 8); |
343 | |
344 | - insert_data_into_tables (self, filename->str, exec, desktop_id->str, desktop_file_table, desktop_id_table); |
345 | - insert_desktop_file_class_into_table (self, filename->str, desktop_class_table); |
346 | + insert_data_into_tables (self, filename, exec, desktop_id->str, desktop_file_table, desktop_id_table); |
347 | + insert_desktop_file_class_into_table (self, filename, desktop_class_table); |
348 | |
349 | g_string_free (desktop_id, TRUE); |
350 | + g_free (filename); |
351 | + g_strfreev (parts); |
352 | length = 0; |
353 | - g_strfreev (parts); |
354 | } |
355 | - g_free ((gpointer) directory); |
356 | + |
357 | + g_object_unref (input); |
358 | + g_object_unref (stream); |
359 | + g_object_unref (file); |
360 | + g_free (directory); |
361 | } |
362 | |
363 | +static GList * get_directory_tree_list (GList *) G_GNUC_WARN_UNUSED_RESULT; |
364 | + |
365 | static GList * |
366 | -get_desktop_file_directories (BamfMatcher *self) |
367 | +get_directory_tree_list (GList *dirs) |
368 | { |
369 | + GList *l; |
370 | GFile *file; |
371 | + GFileEnumerator *enumerator; |
372 | GFileInfo *info; |
373 | - GFileEnumerator *enumerator; |
374 | - GList *dirs = NULL, *l; |
375 | - const char *env; |
376 | - char *path; |
377 | - char *subpath; |
378 | - char **data_dirs = NULL; |
379 | - char **data; |
380 | - |
381 | - env = g_getenv ("XDG_DATA_DIRS"); |
382 | - |
383 | - if (env) |
384 | - { |
385 | - data_dirs = g_strsplit (env, ":", 0); |
386 | - |
387 | - for (data = data_dirs; *data; data++) |
388 | - { |
389 | - path = g_build_filename (*data, "applications", NULL); |
390 | - if (g_file_test (path, G_FILE_TEST_IS_DIR)) |
391 | - dirs = g_list_prepend (dirs, path); |
392 | - else |
393 | - g_free (path); |
394 | - } |
395 | - } |
396 | - |
397 | - if (!g_list_find_custom (dirs, "/usr/share/applications", (GCompareFunc) g_strcmp0)) |
398 | - dirs = g_list_prepend (dirs, g_strdup ("/usr/share/applications")); |
399 | - |
400 | - if (!g_list_find_custom (dirs, "/usr/local/share/applications", (GCompareFunc) g_strcmp0)) |
401 | - dirs = g_list_prepend (dirs, g_strdup ("/usr/local/share/applications")); |
402 | - |
403 | - dirs = g_list_prepend (dirs, g_strdup (g_build_filename (g_get_home_dir (), ".local/share/applications", NULL))); |
404 | - |
405 | - if (data_dirs) |
406 | - g_strfreev (data_dirs); |
407 | - |
408 | - /* include subdirs */ |
409 | + gchar *path, *subpath; |
410 | + |
411 | for (l = dirs; l; l = l->next) |
412 | { |
413 | path = l->data; |
414 | @@ -698,8 +739,10 @@ |
415 | continue; |
416 | |
417 | subpath = g_build_filename (path, g_file_info_get_name (info), NULL); |
418 | - /* append for non-recursive recursion love */ |
419 | - dirs = g_list_append (dirs, subpath); |
420 | + /* append after the current list item for non-recursive recursion love |
421 | + * and to keep the priorities (hierarchy) of the .desktop directories. |
422 | + */ |
423 | + dirs = g_list_insert_before (dirs, l->next, subpath); |
424 | |
425 | g_object_unref (info); |
426 | } |
427 | @@ -707,42 +750,255 @@ |
428 | g_object_unref (enumerator); |
429 | g_object_unref (file); |
430 | } |
431 | - |
432 | - return dirs; |
433 | + |
434 | + return dirs; |
435 | +} |
436 | + |
437 | +static GList * get_desktop_file_env_directories (GList *, const gchar *) G_GNUC_WARN_UNUSED_RESULT; |
438 | + |
439 | +static GList * |
440 | +get_desktop_file_env_directories (GList *dirs, const gchar *varname) |
441 | +{ |
442 | + g_return_val_if_fail (varname, dirs); |
443 | + |
444 | + const gchar *env; |
445 | + char *path; |
446 | + char **data_dirs = NULL; |
447 | + char **data; |
448 | + |
449 | + env = g_getenv (varname); |
450 | + |
451 | + if (env) |
452 | + { |
453 | + data_dirs = g_strsplit (env, ":", 0); |
454 | + |
455 | + for (data = data_dirs; *data; data++) |
456 | + { |
457 | + path = g_build_filename (*data, "applications", NULL); |
458 | + if (g_file_test (path, G_FILE_TEST_IS_DIR) && |
459 | + !g_list_find_custom (dirs, path, (GCompareFunc) g_strcmp0)) |
460 | + { |
461 | + dirs = g_list_prepend (dirs, path); |
462 | + } |
463 | + else |
464 | + { |
465 | + g_free (path); |
466 | + } |
467 | + } |
468 | + |
469 | + if (data_dirs) |
470 | + g_strfreev (data_dirs); |
471 | + } |
472 | + |
473 | + return dirs; |
474 | +} |
475 | + |
476 | +static GList * |
477 | +get_desktop_file_directories (BamfMatcher *self) |
478 | +{ |
479 | + GList *dirs = NULL; |
480 | + char *path; |
481 | + |
482 | + dirs = get_desktop_file_env_directories(dirs, "XDG_DATA_DIRS"); |
483 | + |
484 | + if (!g_list_find_custom (dirs, "/usr/share/applications", (GCompareFunc) g_strcmp0)) |
485 | + dirs = g_list_prepend (dirs, g_strdup ("/usr/share/applications")); |
486 | + |
487 | + if (!g_list_find_custom (dirs, "/usr/local/share/applications", (GCompareFunc) g_strcmp0)) |
488 | + dirs = g_list_prepend (dirs, g_strdup ("/usr/local/share/applications")); |
489 | + |
490 | + dirs = get_desktop_file_env_directories(dirs, "XDG_DATA_HOME"); |
491 | + |
492 | + path = g_build_filename (g_get_home_dir (), ".local/share/applications", NULL); |
493 | + |
494 | + if (!g_list_find_custom (dirs, path, (GCompareFunc) g_strcmp0)) |
495 | + dirs = g_list_prepend (dirs, path); |
496 | + else |
497 | + g_free (path); |
498 | + |
499 | + /* include subdirs */ |
500 | + dirs = get_directory_tree_list (dirs); |
501 | + |
502 | + /* Include also the user desktop folder, but without its subfolders */ |
503 | + dirs = g_list_prepend (dirs, g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP))); |
504 | + |
505 | + return dirs; |
506 | +} |
507 | + |
508 | +static gint |
509 | +compare_sub_values (gconstpointer desktop_path, gconstpointer desktop_file) |
510 | +{ |
511 | + return !g_str_has_prefix (desktop_file, desktop_path); |
512 | +} |
513 | + |
514 | +static void |
515 | +hash_table_remove_sub_values (GHashTable *htable, GCompareFunc compare_func, |
516 | + GFreeFunc free_func, gpointer target, gboolean search_all) |
517 | +{ |
518 | + g_return_if_fail (htable); |
519 | + g_return_if_fail (compare_func); |
520 | + |
521 | + GHashTableIter iter; |
522 | + gpointer key; |
523 | + gpointer value; |
524 | + |
525 | + g_hash_table_iter_init (&iter, htable); |
526 | + |
527 | + while (g_hash_table_iter_next (&iter, &key, &value)) |
528 | + { |
529 | + GList *list, *l; |
530 | + gboolean found; |
531 | + |
532 | + list = value; |
533 | + found = FALSE; |
534 | + |
535 | + l = list; |
536 | + while (l) |
537 | + { |
538 | + GList *next = l->next; |
539 | + |
540 | + if (compare_func (target, l->data) == 0) |
541 | + { |
542 | + found = TRUE; |
543 | + |
544 | + if (!l->prev && !l->next) |
545 | + { |
546 | + if (free_func) |
547 | + g_list_free_full (list, free_func); |
548 | + else |
549 | + g_list_free (list); |
550 | + |
551 | + g_hash_table_iter_remove (&iter); |
552 | + |
553 | + next = NULL; |
554 | + break; |
555 | + } |
556 | + else |
557 | + { |
558 | + if (free_func) |
559 | + free_func (l->data); |
560 | + |
561 | + /* If the target is the first element of the list (and thanks to |
562 | +- * the previous check we're also sure that it's not the only one), |
563 | + * simply switch it with its follower, not to change the first |
564 | + * pointer and the hash table value for key |
565 | + */ |
566 | + if (l == list) |
567 | + { |
568 | + l->data = next->data; |
569 | + l = next; |
570 | + next = list; |
571 | + } |
572 | + |
573 | + list = g_list_delete_link (list, l); |
574 | + } |
575 | + |
576 | + if (!search_all) |
577 | + break; |
578 | + } |
579 | + l = next; |
580 | + } |
581 | + |
582 | + if (found && !search_all) |
583 | + break; |
584 | + } |
585 | } |
586 | |
587 | static gboolean |
588 | -hash_table_remove_values (gpointer key, gpointer value, gpointer target) |
589 | +hash_table_compare_sub_values (gpointer desktop_path, gpointer desktop_class, gpointer target_path) |
590 | { |
591 | - return g_strcmp0 ((char *) value, (char *) target) == 0; |
592 | + return !compare_sub_values (target_path, desktop_path); |
593 | } |
594 | |
595 | +static void fill_desktop_file_table (BamfMatcher *, GList *, GHashTable *, GHashTable *, GHashTable *); |
596 | + |
597 | static void |
598 | on_monitor_changed (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent type, BamfMatcher *self) |
599 | { |
600 | char *path; |
601 | + const char *monitored_dir; |
602 | + GFileType filetype; |
603 | |
604 | g_return_if_fail (G_IS_FILE_MONITOR (monitor)); |
605 | - g_return_if_fail (BAMF_IS_MATCHER (self)); |
606 | - |
607 | - if (type != G_FILE_MONITOR_EVENT_CHANGED && type != G_FILE_MONITOR_EVENT_DELETED) |
608 | - return; |
609 | - |
610 | g_return_if_fail (G_IS_FILE (file)); |
611 | + g_return_if_fail (BAMF_IS_MATCHER (self)); |
612 | + |
613 | + if (type != G_FILE_MONITOR_EVENT_CREATED && |
614 | + type != G_FILE_MONITOR_EVENT_DELETED && |
615 | + type != G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT) |
616 | + return; |
617 | + |
618 | path = g_file_get_path (file); |
619 | + filetype = g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL); |
620 | + monitored_dir = g_object_get_data (G_OBJECT (monitor), "root"); |
621 | |
622 | - if (!g_str_has_suffix (path, ".desktop")) |
623 | + if (!g_str_has_suffix (path, ".desktop") && |
624 | + filetype != G_FILE_TYPE_DIRECTORY && |
625 | + type != G_FILE_MONITOR_EVENT_DELETED) |
626 | goto out; |
627 | + |
628 | + if (type == G_FILE_MONITOR_EVENT_DELETED || |
629 | + type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT) |
630 | + { |
631 | + if (g_str_has_suffix (path, ".desktop")) |
632 | + { |
633 | + /* Remove all the .desktop file referencies from the hash tables. |
634 | + * Free the string itself only on the 2nd pass (tables share the same |
635 | + * string instance) |
636 | + */ |
637 | + hash_table_remove_sub_values (self->priv->desktop_id_table, |
638 | + (GCompareFunc) g_strcmp0, NULL, path, FALSE); |
639 | + hash_table_remove_sub_values (self->priv->desktop_file_table, |
640 | + (GCompareFunc) g_strcmp0, g_free, path, FALSE); |
641 | + g_hash_table_remove (self->priv->desktop_class_table, path); |
642 | + } |
643 | + else if (g_strcmp0 (monitored_dir, path) == 0) |
644 | + { |
645 | + /* Remove all the referencies to the .desktop files placed in subfolders |
646 | + * of the current path. Free the strings itself only on the 2nd pass |
647 | + * (as before, the tables share the same string instance) |
648 | + */ |
649 | + char *prefix = g_strconcat (path, G_DIR_SEPARATOR_S, NULL); |
650 | + |
651 | + hash_table_remove_sub_values (self->priv->desktop_id_table, |
652 | + compare_sub_values, NULL, prefix, TRUE); |
653 | + hash_table_remove_sub_values (self->priv->desktop_file_table, |
654 | + compare_sub_values, g_free, prefix, TRUE); |
655 | + g_hash_table_foreach_remove (self->priv->desktop_class_table, |
656 | + hash_table_compare_sub_values, prefix); |
657 | + |
658 | + g_signal_handlers_disconnect_by_func (monitor, on_monitor_changed, self); |
659 | + self->priv->monitors = g_list_remove (self->priv->monitors, monitor); |
660 | + g_object_unref (monitor); |
661 | + g_free (prefix); |
662 | + } |
663 | + } |
664 | + |
665 | + if (type == G_FILE_MONITOR_EVENT_CREATED || |
666 | + type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT) |
667 | + { |
668 | + if (filetype == G_FILE_TYPE_DIRECTORY) |
669 | + { |
670 | + const char *desktop_dir; |
671 | + desktop_dir = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP); |
672 | + |
673 | + if (g_strcmp0 (monitored_dir, desktop_dir) != 0) |
674 | + { |
675 | + GList *dirs = NULL; |
676 | + dirs = g_list_prepend (dirs, g_strdup (path)); |
677 | + dirs = get_directory_tree_list (dirs); |
678 | + fill_desktop_file_table (self, dirs, |
679 | + self->priv->desktop_file_table, |
680 | + self->priv->desktop_id_table, |
681 | + self->priv->desktop_class_table); |
682 | |
683 | - if (type == G_FILE_MONITOR_EVENT_CREATED) |
684 | - { |
685 | - bamf_matcher_load_desktop_file (self, path); |
686 | - } |
687 | - else if (type == G_FILE_MONITOR_EVENT_DELETED) |
688 | - { |
689 | - g_hash_table_foreach_remove (self->priv->desktop_id_table, (GHRFunc) hash_table_remove_values, path); |
690 | - g_hash_table_foreach_remove (self->priv->desktop_file_table, (GHRFunc) hash_table_remove_values, path); |
691 | - g_hash_table_remove (self->priv->desktop_class_table, path); |
692 | + g_list_free_full (dirs, (GDestroyNotify) g_free); |
693 | + } |
694 | + } |
695 | + else if (filetype != G_FILE_TYPE_UNKNOWN) |
696 | + { |
697 | + bamf_matcher_load_desktop_file (self, path); |
698 | + } |
699 | } |
700 | |
701 | out: |
702 | @@ -750,17 +1006,71 @@ |
703 | } |
704 | |
705 | static void |
706 | +bamf_add_new_monitored_directory (BamfMatcher * self, const gchar *directory) |
707 | +{ |
708 | + g_return_if_fail (BAMF_IS_MATCHER (self)); |
709 | + |
710 | + GFile *file; |
711 | + GFileMonitor *monitor; |
712 | + |
713 | + file = g_file_new_for_path (directory); |
714 | + monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); |
715 | + g_file_monitor_set_rate_limit (monitor, 1000); |
716 | + g_object_set_data_full (G_OBJECT (monitor), "root", g_strdup (directory), g_free); |
717 | + g_signal_connect (monitor, "changed", (GCallback) on_monitor_changed, self); |
718 | + self->priv->monitors = g_list_prepend (self->priv->monitors, monitor); |
719 | + |
720 | + g_object_unref (file); |
721 | +} |
722 | + |
723 | +static void |
724 | +fill_desktop_file_table (BamfMatcher * self, |
725 | + GList *directories, |
726 | + GHashTable *desktop_file_table, |
727 | + GHashTable *desktop_id_table, |
728 | + GHashTable *desktop_class_table) |
729 | +{ |
730 | + g_return_if_fail (BAMF_IS_MATCHER (self)); |
731 | + |
732 | + GList *l; |
733 | + char *directory; |
734 | + char *bamf_file; |
735 | + |
736 | + for (l = directories; l; l = l->next) |
737 | + { |
738 | + directory = l->data; |
739 | + |
740 | + if (!g_file_test (directory, G_FILE_TEST_IS_DIR)) |
741 | + continue; |
742 | + |
743 | + bamf_add_new_monitored_directory (self, directory); |
744 | + |
745 | + bamf_file = g_build_filename (directory, "bamf.index", NULL); |
746 | + |
747 | + if (g_file_test (bamf_file, G_FILE_TEST_EXISTS)) |
748 | + { |
749 | + load_index_file_to_table (self, bamf_file, desktop_file_table, |
750 | + desktop_id_table, desktop_class_table); |
751 | + } |
752 | + else |
753 | + { |
754 | + load_directory_to_table (self, directory, desktop_file_table, |
755 | + desktop_id_table, desktop_class_table); |
756 | + } |
757 | + |
758 | + g_free (bamf_file); |
759 | + } |
760 | +} |
761 | + |
762 | +static void |
763 | create_desktop_file_table (BamfMatcher * self, |
764 | GHashTable **desktop_file_table, |
765 | GHashTable **desktop_id_table, |
766 | GHashTable **desktop_class_table) |
767 | { |
768 | + g_return_if_fail (BAMF_IS_MATCHER (self)); |
769 | + |
770 | GList *directories; |
771 | - GList *l; |
772 | - char *directory; |
773 | - const char *bamf_file; |
774 | - GFile *file; |
775 | - GFileMonitor *monitor; |
776 | |
777 | *desktop_file_table = |
778 | g_hash_table_new_full ((GHashFunc) g_str_hash, |
779 | @@ -778,44 +1088,14 @@ |
780 | g_hash_table_new_full ((GHashFunc) g_str_hash, |
781 | (GEqualFunc) g_str_equal, |
782 | (GDestroyNotify) g_free, |
783 | - (GDestroyNotify) g_free); |
784 | - |
785 | - g_return_if_fail (BAMF_IS_MATCHER (self)); |
786 | + (GDestroyNotify) g_free); |
787 | |
788 | directories = get_desktop_file_directories (self); |
789 | |
790 | - for (l = directories; l; l = l->next) |
791 | - { |
792 | - directory = l->data; |
793 | - |
794 | - if (!g_file_test (directory, G_FILE_TEST_IS_DIR)) |
795 | - continue; |
796 | - |
797 | - file = g_file_new_for_path (directory); |
798 | - monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); |
799 | - |
800 | - self->priv->monitors = g_list_prepend (self->priv->monitors, monitor); |
801 | - |
802 | - g_signal_connect (monitor, "changed", (GCallback) on_monitor_changed, self); |
803 | - |
804 | - bamf_file = g_build_filename (directory, "bamf.index", NULL); |
805 | - |
806 | - if (g_file_test (bamf_file, G_FILE_TEST_EXISTS)) |
807 | - { |
808 | - load_index_file_to_table (self, bamf_file, *desktop_file_table, |
809 | - *desktop_id_table, *desktop_class_table); |
810 | - } |
811 | - else |
812 | - { |
813 | - load_directory_to_table (self, directory, *desktop_file_table, |
814 | - *desktop_id_table, *desktop_class_table); |
815 | - } |
816 | - |
817 | - g_free (directory); |
818 | - g_free ((gpointer) bamf_file); |
819 | - } |
820 | + fill_desktop_file_table (self, directories, *desktop_file_table, |
821 | + *desktop_id_table, *desktop_class_table); |
822 | |
823 | - g_list_free (directories); |
824 | + g_list_free_full (directories, (GDestroyNotify) g_free); |
825 | } |
826 | |
827 | static gboolean |
828 | @@ -861,17 +1141,17 @@ |
829 | atom = XInternAtom (XDisplay, atom_name, FALSE); |
830 | |
831 | int result = XGetWindowProperty (XDisplay, |
832 | - (gulong) bamf_legacy_window_get_xid (window), |
833 | - atom, |
834 | - 0, |
835 | - G_MAXINT, |
836 | - FALSE, |
837 | - XA_STRING, |
838 | - &type, |
839 | - &format, |
840 | - &numItems, |
841 | - &bytesAfter, |
842 | - &buffer); |
843 | + (gulong) bamf_legacy_window_get_xid (window), |
844 | + atom, |
845 | + 0, |
846 | + G_MAXINT, |
847 | + FALSE, |
848 | + XA_STRING, |
849 | + &type, |
850 | + &format, |
851 | + &numItems, |
852 | + &bytesAfter, |
853 | + &buffer); |
854 | |
855 | if (close_display) |
856 | XCloseDisplay (XDisplay); |
857 | @@ -912,24 +1192,18 @@ |
858 | } |
859 | |
860 | XChangeProperty (XDisplay, |
861 | - bamf_legacy_window_get_xid (window), |
862 | - XInternAtom (XDisplay, |
863 | - atom_name, |
864 | - FALSE), |
865 | - XA_STRING, |
866 | - 8, |
867 | - PropModeReplace, |
868 | - (unsigned char *) data, |
869 | - strlen (data)); |
870 | + bamf_legacy_window_get_xid (window), |
871 | + XInternAtom (XDisplay, |
872 | + atom_name, |
873 | + FALSE), |
874 | + XA_STRING, |
875 | + 8, |
876 | + PropModeReplace, |
877 | + (unsigned char *) data, |
878 | + strlen (data)); |
879 | |
880 | if (close_display) |
881 | - XCloseDisplay (XDisplay); |
882 | -} |
883 | - |
884 | -static char* |
885 | -window_class_name (BamfLegacyWindow *window) |
886 | -{ |
887 | - return g_strdup (bamf_legacy_window_get_class_name (window)); |
888 | + XCloseDisplay (XDisplay); |
889 | } |
890 | |
891 | static char * |
892 | @@ -951,7 +1225,7 @@ |
893 | { |
894 | g_string_append (exec, argv[i]); |
895 | if (argv[i + 1] != NULL) |
896 | - g_string_append (exec, " "); |
897 | + g_string_append (exec, " "); |
898 | g_free (argv[i]); |
899 | i++; |
900 | } |
901 | @@ -1084,7 +1358,7 @@ |
902 | } |
903 | else |
904 | { |
905 | - char *window_class = window_class_name (window); |
906 | + const char *window_class = bamf_legacy_window_get_class_name (window); |
907 | |
908 | char *desktop_file; |
909 | char *desktop_class; |
910 | @@ -1098,6 +1372,7 @@ |
911 | for (; l; l = l->next) |
912 | { |
913 | desktop_file = l->data; |
914 | + |
915 | if (desktop_file) |
916 | { |
917 | desktop_class = g_hash_table_lookup (priv->desktop_class_table, desktop_file); |
918 | @@ -1128,6 +1403,10 @@ |
919 | { |
920 | desktop_files = g_list_prepend (desktop_files, desktop_file); |
921 | } |
922 | + else |
923 | + { |
924 | + g_free (desktop_file); |
925 | + } |
926 | } |
927 | |
928 | pid = bamf_legacy_window_get_pid (window); |
929 | @@ -1139,26 +1418,56 @@ |
930 | for (l = pid_list; l; l = l->next) |
931 | { |
932 | desktop_file = l->data; |
933 | - if (g_list_find_custom (desktop_files, l->data, (GCompareFunc) g_strcmp0)) |
934 | - g_free (desktop_file); |
935 | + if (g_list_find_custom (desktop_files, desktop_file, (GCompareFunc) g_strcmp0)) |
936 | + { |
937 | + g_free (desktop_file); |
938 | + } |
939 | else |
940 | { |
941 | + gboolean append = FALSE; |
942 | + |
943 | if (window_class) |
944 | { |
945 | desktop_class = g_hash_table_lookup (priv->desktop_class_table, desktop_file); |
946 | - if ((desktop_class == NULL || g_strcmp0 (desktop_class, window_class) == 0) && |
947 | - !g_list_find_custom (desktop_files, desktop_file, |
948 | - (GCompareFunc) g_strcmp0)) |
949 | - { |
950 | - desktop_files = g_list_append (desktop_files, desktop_file); |
951 | - } |
952 | - } |
953 | - else |
954 | - desktop_files = g_list_append (desktop_files, desktop_file); |
955 | + if (desktop_class == NULL || g_strcmp0 (desktop_class, window_class) == 0) |
956 | + { |
957 | + append = TRUE; |
958 | + } |
959 | + } |
960 | + else |
961 | + { |
962 | + append = TRUE; |
963 | + } |
964 | + |
965 | + if (append) |
966 | + { |
967 | + /* If we're adding a .desktop file stored in the desktop folder, |
968 | + give it the priority it should have. */ |
969 | + GList *last = NULL; |
970 | + |
971 | + if (is_desktop_folder_item (desktop_file, -1)) |
972 | + { |
973 | + GList *ll; |
974 | + |
975 | + for (ll = desktop_files; ll; ll = ll->next) |
976 | + { |
977 | + if (!is_desktop_folder_item (ll->data, -1)) |
978 | + { |
979 | + last = ll; |
980 | + break; |
981 | + } |
982 | + } |
983 | + } |
984 | + |
985 | + desktop_files = g_list_insert_before (desktop_files, last, desktop_file); |
986 | + } |
987 | + else |
988 | + { |
989 | + g_free (desktop_file); |
990 | + } |
991 | } |
992 | } |
993 | |
994 | - g_free (window_class); |
995 | g_list_free (pid_list); |
996 | } |
997 | |
998 | @@ -1172,8 +1481,8 @@ |
999 | GList *possible_apps, *l; |
1000 | BamfLegacyWindow *window; |
1001 | GList *views, *a; |
1002 | + const char *win_class; |
1003 | char *desktop_file; |
1004 | - char *win_class; |
1005 | char *app_class; |
1006 | BamfApplication *app = NULL, *best = NULL; |
1007 | BamfView *view; |
1008 | @@ -1185,7 +1494,7 @@ |
1009 | views = self->priv->views; |
1010 | |
1011 | possible_apps = bamf_matcher_possible_applications_for_window (self, bamf_window); |
1012 | - win_class = window_class_name(window); |
1013 | + win_class = bamf_legacy_window_get_class_name (window); |
1014 | |
1015 | /* Loop over every application, inside that application see if its .desktop file |
1016 | * matches with any of our possible hits. If so we match it. If we have no possible hits |
1017 | @@ -1200,7 +1509,6 @@ |
1018 | |
1019 | app = BAMF_APPLICATION (view); |
1020 | app_class = bamf_application_get_wmclass (app); |
1021 | - |
1022 | desktop_file = bamf_application_get_desktop_file (app); |
1023 | |
1024 | if (possible_apps) |
1025 | @@ -1242,8 +1550,6 @@ |
1026 | g_object_unref (best); |
1027 | } |
1028 | |
1029 | - g_free (win_class); |
1030 | - |
1031 | for (l = possible_apps; l; l = l->next) |
1032 | { |
1033 | char *str = l->data; |
1034 | @@ -1912,51 +2218,51 @@ |
1035 | g_type_class_add_private (klass, sizeof (BamfMatcherPrivate)); |
1036 | |
1037 | dbus_g_object_type_install_info (BAMF_TYPE_MATCHER, |
1038 | - &dbus_glib_bamf_matcher_object_info); |
1039 | + &dbus_glib_bamf_matcher_object_info); |
1040 | |
1041 | matcher_signals [VIEW_OPENED] = |
1042 | - g_signal_new ("view-opened", |
1043 | - G_OBJECT_CLASS_TYPE (klass), |
1044 | - 0, |
1045 | - 0, NULL, NULL, |
1046 | - bamf_marshal_VOID__STRING_STRING, |
1047 | - G_TYPE_NONE, 2, |
1048 | - G_TYPE_STRING, G_TYPE_STRING); |
1049 | + g_signal_new ("view-opened", |
1050 | + G_OBJECT_CLASS_TYPE (klass), |
1051 | + 0, |
1052 | + 0, NULL, NULL, |
1053 | + bamf_marshal_VOID__STRING_STRING, |
1054 | + G_TYPE_NONE, 2, |
1055 | + G_TYPE_STRING, G_TYPE_STRING); |
1056 | |
1057 | matcher_signals [VIEW_CLOSED] = |
1058 | - g_signal_new ("view-closed", |
1059 | - G_OBJECT_CLASS_TYPE (klass), |
1060 | - 0, |
1061 | - 0, NULL, NULL, |
1062 | - bamf_marshal_VOID__STRING_STRING, |
1063 | - G_TYPE_NONE, 2, |
1064 | - G_TYPE_STRING, G_TYPE_STRING); |
1065 | + g_signal_new ("view-closed", |
1066 | + G_OBJECT_CLASS_TYPE (klass), |
1067 | + 0, |
1068 | + 0, NULL, NULL, |
1069 | + bamf_marshal_VOID__STRING_STRING, |
1070 | + G_TYPE_NONE, 2, |
1071 | + G_TYPE_STRING, G_TYPE_STRING); |
1072 | |
1073 | matcher_signals [ACTIVE_APPLICATION_CHANGED] = |
1074 | - g_signal_new ("active-application-changed", |
1075 | - G_OBJECT_CLASS_TYPE (klass), |
1076 | - 0, |
1077 | - 0, NULL, NULL, |
1078 | - bamf_marshal_VOID__STRING_STRING, |
1079 | - G_TYPE_NONE, 2, |
1080 | - G_TYPE_STRING, G_TYPE_STRING); |
1081 | + g_signal_new ("active-application-changed", |
1082 | + G_OBJECT_CLASS_TYPE (klass), |
1083 | + 0, |
1084 | + 0, NULL, NULL, |
1085 | + bamf_marshal_VOID__STRING_STRING, |
1086 | + G_TYPE_NONE, 2, |
1087 | + G_TYPE_STRING, G_TYPE_STRING); |
1088 | |
1089 | matcher_signals [ACTIVE_WINDOW_CHANGED] = |
1090 | - g_signal_new ("active-window-changed", |
1091 | - G_OBJECT_CLASS_TYPE (klass), |
1092 | - 0, |
1093 | - 0, NULL, NULL, |
1094 | - bamf_marshal_VOID__STRING_STRING, |
1095 | - G_TYPE_NONE, 2, |
1096 | - G_TYPE_STRING, G_TYPE_STRING); |
1097 | - |
1098 | + g_signal_new ("active-window-changed", |
1099 | + G_OBJECT_CLASS_TYPE (klass), |
1100 | + 0, |
1101 | + 0, NULL, NULL, |
1102 | + bamf_marshal_VOID__STRING_STRING, |
1103 | + G_TYPE_NONE, 2, |
1104 | + G_TYPE_STRING, G_TYPE_STRING); |
1105 | + |
1106 | matcher_signals [FAVORITES_CHANGED] = |
1107 | - g_signal_new ("favorites-changed", |
1108 | - G_OBJECT_CLASS_TYPE (klass), |
1109 | - 0, |
1110 | - 0, NULL, NULL, |
1111 | - g_cclosure_marshal_VOID__VOID, |
1112 | - G_TYPE_NONE, 0); |
1113 | + g_signal_new ("favorites-changed", |
1114 | + G_OBJECT_CLASS_TYPE (klass), |
1115 | + 0, |
1116 | + 0, NULL, NULL, |
1117 | + g_cclosure_marshal_VOID__VOID, |
1118 | + G_TYPE_NONE, 0); |
1119 | } |
1120 | |
1121 | BamfMatcher * |
+1 looks good :)
runs well too!