BAMF Application Matching Framework

Merge lp:~3v1n0/bamf/fixes into lp:bamf/0.4

Proposed by Marco Trevisan (Treviño) on 2011-06-22
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
To merge this branch: bzr merge lp:~3v1n0/bamf/fixes
Reviewer Review Type Date Requested Status
Jason Smith (community) 2011-06-22 Approve on 2011-07-13
Unity Community Hackers 2011-06-22 Pending
Review via email: mp+65434@code.launchpad.net

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.

[1] http://bazaar.launchpad.net/~3v1n0/bamf/fixes/changes

To post a comment you must log in.
lp:~3v1n0/bamf/fixes updated on 2011-06-26
423. By Marco Trevisan (Treviño) on 2011-06-26

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...

Jason Smith (jassmith) wrote :

+1 looks good :)

runs well too!

review: Approve

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 *

Subscribers

People subscribed via source and target branches