Merge lp:~3v1n0/bamf/wmclass-matching into lp:bamf/0.4
- wmclass-matching
- Merge into 0.4
Proposed by
Marco Trevisan (Treviño)
Status: | Merged | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Merged at revision: | 387 | ||||||||||||
Proposed branch: | lp:~3v1n0/bamf/wmclass-matching | ||||||||||||
Merge into: | lp:bamf/0.4 | ||||||||||||
Diff against target: |
488 lines (+198/-40) 3 files modified
src/bamf-application.c (+50/-3) src/bamf-application.h (+6/-0) src/bamf-matcher.c (+142/-37) |
||||||||||||
To merge this branch: | bzr merge lp:~3v1n0/bamf/wmclass-matching | ||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jason Smith (community) | Approve | ||
Review via email: mp+54941@code.launchpad.net |
Commit message
Description of the change
Now bamf uses also the window WMCLASS parameter and the .desktop file StartupWMClass to associate a window to its application.
This causes that each bamf application should now have its own class; a window is considered as part of that application only if its wmclass matches the application one.
A desktop file is now associated to an application also considering the StartupWMClass key value.
To post a comment you must log in.
Revision history for this message
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote : | # |
Yes, you're right about that. I'll fix it.
lp:~3v1n0/bamf/wmclass-matching
updated
- 392. By Marco Trevisan (Treviño)
-
application_class renamed as application_wmclass
To avoid gobjet get_class function overriding
- 393. By Marco Trevisan (Treviño)
-
Some code spaces cleanup.
Revision history for this message
Jason Smith (jassmith) wrote : | # |
Works for me, looks good
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/bamf-application.c' |
2 | --- src/bamf-application.c 2011-01-14 15:53:35 +0000 |
3 | +++ src/bamf-application.c 2011-03-29 11:26:03 +0000 |
4 | @@ -48,6 +48,7 @@ |
5 | GList * desktop_file_list; |
6 | char * app_type; |
7 | char * icon; |
8 | + char * wmclass; |
9 | gboolean is_tab_container; |
10 | gboolean show_stubs; |
11 | }; |
12 | @@ -83,6 +84,19 @@ |
13 | return result; |
14 | } |
15 | |
16 | +char * |
17 | +bamf_application_get_wmclass (BamfApplication *application) |
18 | +{ |
19 | + BamfApplicationPrivate *priv; |
20 | + char *result = NULL; |
21 | + |
22 | + g_return_val_if_fail (BAMF_IS_APPLICATION (application), NULL); |
23 | + priv = application->priv; |
24 | + |
25 | + result = g_strdup (priv->wmclass); |
26 | + return result; |
27 | +} |
28 | + |
29 | static gboolean |
30 | icon_name_is_valid (char *name) |
31 | { |
32 | @@ -212,6 +226,18 @@ |
33 | bamf_application_setup_icon_and_name (application); |
34 | } |
35 | |
36 | +void |
37 | +bamf_application_set_wmclass (BamfApplication *application, |
38 | + char *wmclass) |
39 | +{ |
40 | + g_return_if_fail (BAMF_IS_APPLICATION (application)); |
41 | + |
42 | + if (wmclass && wmclass[0] != '\0') |
43 | + application->priv->wmclass = g_strdup (wmclass); |
44 | + else |
45 | + application->priv->wmclass = NULL; |
46 | +} |
47 | + |
48 | GArray * |
49 | bamf_application_get_xids (BamfApplication *application) |
50 | { |
51 | @@ -312,12 +338,15 @@ |
52 | GList *children, *l; |
53 | BamfView *child; |
54 | |
55 | - g_return_val_if_fail (BAMF_IS_APPLICATION (view), NULL); |
56 | + g_return_val_if_fail (BAMF_IS_APPLICATION (view), NULL); |
57 | self = BAMF_APPLICATION (view); |
58 | - |
59 | + |
60 | + if (self->priv->wmclass) |
61 | + return g_strdup_printf ("application%i", abs (g_str_hash (self->priv->wmclass))); |
62 | + |
63 | if (self->priv->desktop_file) |
64 | return g_strdup_printf ("application%i", abs (g_str_hash (self->priv->desktop_file))); |
65 | - |
66 | + |
67 | children = bamf_view_get_children (BAMF_VIEW (self)); |
68 | for (l = children; l; l = l->next) |
69 | { |
70 | @@ -562,6 +591,12 @@ |
71 | g_free (priv->app_type); |
72 | priv->app_type = NULL; |
73 | } |
74 | + |
75 | + if (priv->wmclass) |
76 | + { |
77 | + g_free (priv->wmclass); |
78 | + priv->wmclass = NULL; |
79 | + } |
80 | |
81 | g_signal_handlers_disconnect_by_func (G_OBJECT (bamf_matcher_get_default ()), matcher_favorites_changed, object); |
82 | |
83 | @@ -577,6 +612,7 @@ |
84 | priv->is_tab_container = FALSE; |
85 | priv->app_type = g_strdup ("system"); |
86 | priv->show_stubs = TRUE; |
87 | + priv->wmclass = NULL; |
88 | |
89 | g_signal_connect (G_OBJECT (bamf_matcher_get_default ()), "favorites-changed", |
90 | (GCallback) matcher_favorites_changed, self); |
91 | @@ -651,6 +687,17 @@ |
92 | return application; |
93 | } |
94 | |
95 | +BamfApplication * |
96 | +bamf_application_new_with_wmclass (char *wmclass) |
97 | +{ |
98 | + BamfApplication *application; |
99 | + application = (BamfApplication *) g_object_new (BAMF_TYPE_APPLICATION, NULL); |
100 | + |
101 | + bamf_application_set_wmclass (application, wmclass); |
102 | + |
103 | + return application; |
104 | +} |
105 | + |
106 | /** |
107 | bamf_application_get_show_stubs: |
108 | @application: Application to check for menu stubs |
109 | |
110 | === modified file 'src/bamf-application.h' |
111 | --- src/bamf-application.h 2010-09-11 02:52:33 +0000 |
112 | +++ src/bamf-application.h 2011-03-29 11:26:03 +0000 |
113 | @@ -66,6 +66,10 @@ |
114 | gboolean bamf_application_contains_similar_to_window (BamfApplication *app, |
115 | BamfWindow *window); |
116 | |
117 | +char * bamf_application_get_wmclass (BamfApplication *application); |
118 | +void bamf_application_set_wmclass (BamfApplication *application, |
119 | + char *wmclass); |
120 | + |
121 | BamfApplication * bamf_application_new (void); |
122 | |
123 | BamfApplication * bamf_application_new_from_desktop_file (char * desktop_file); |
124 | @@ -73,4 +77,6 @@ |
125 | |
126 | BamfApplication * bamf_application_new_from_desktop_files (GList * desktop_files); |
127 | |
128 | +BamfApplication * bamf_application_new_with_wmclass (char *wmclass); |
129 | + |
130 | #endif |
131 | |
132 | === modified file 'src/bamf-matcher.c' |
133 | --- src/bamf-matcher.c 2011-03-15 12:09:16 +0000 |
134 | +++ src/bamf-matcher.c 2011-03-29 11:26:03 +0000 |
135 | @@ -61,6 +61,7 @@ |
136 | GArray * known_pids; |
137 | GHashTable * desktop_id_table; |
138 | GHashTable * desktop_file_table; |
139 | + GHashTable * desktop_class_table; |
140 | GHashTable * exec_list; |
141 | GHashTable * registered_pids; |
142 | GList * views; |
143 | @@ -416,17 +417,43 @@ |
144 | file_list = g_list_append (file_list, datadup); |
145 | id_list = g_list_append (id_list, datadup); |
146 | } |
147 | - |
148 | + |
149 | g_hash_table_insert (desktop_file_table, g_strdup (exec), file_list); |
150 | g_hash_table_insert (desktop_id_table, g_strdup (desktop_id), id_list); |
151 | - |
152 | +} |
153 | + |
154 | +static void |
155 | +insert_desktop_file_class_into_table (BamfMatcher *self, |
156 | + const char *desktop_file, |
157 | + GHashTable *desktop_class_table) |
158 | +{ |
159 | + GKeyFile *desktop_keyfile; |
160 | + char *class; |
161 | + |
162 | + g_return_if_fail (desktop_file); |
163 | + |
164 | + desktop_keyfile = g_key_file_new (); |
165 | + |
166 | + if (g_key_file_load_from_file (desktop_keyfile, desktop_file, G_KEY_FILE_NONE, |
167 | + NULL)) |
168 | + { |
169 | + class = g_key_file_get_string (desktop_keyfile, |
170 | + G_KEY_FILE_DESKTOP_GROUP, |
171 | + G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS, |
172 | + NULL); |
173 | + if (class) |
174 | + g_hash_table_insert (desktop_class_table, g_strdup (desktop_file), class); |
175 | + |
176 | + g_key_file_free (desktop_keyfile); |
177 | + } |
178 | } |
179 | |
180 | static void |
181 | load_desktop_file_to_table (BamfMatcher * self, |
182 | const char *file, |
183 | GHashTable *desktop_file_table, |
184 | - GHashTable *desktop_id_table) |
185 | + GHashTable *desktop_id_table, |
186 | + GHashTable *desktop_class_table) |
187 | { |
188 | GAppInfo *desktop_file; |
189 | char *exec; |
190 | @@ -467,6 +494,7 @@ |
191 | desktop_id = g_string_truncate (desktop_id, desktop_id->len - 8); /* remove last 8 characters for .desktop */ |
192 | |
193 | insert_data_into_tables (self, file, exec, desktop_id->str, desktop_file_table, desktop_id_table); |
194 | + insert_desktop_file_class_into_table (self, file, desktop_class_table); |
195 | |
196 | g_free (exec); |
197 | g_string_free (desktop_id, TRUE); |
198 | @@ -476,7 +504,8 @@ |
199 | load_directory_to_table (BamfMatcher * self, |
200 | const char *directory, |
201 | GHashTable *desktop_file_table, |
202 | - GHashTable *desktop_id_table) |
203 | + GHashTable *desktop_id_table, |
204 | + GHashTable *desktop_class_table) |
205 | { |
206 | GFile *dir; |
207 | GFileEnumerator *enumerator; |
208 | @@ -506,7 +535,8 @@ |
209 | load_desktop_file_to_table (self, |
210 | path, |
211 | desktop_file_table, |
212 | - desktop_id_table); |
213 | + desktop_id_table, |
214 | + desktop_class_table); |
215 | |
216 | g_free ((gpointer) path); |
217 | g_object_unref (info); |
218 | @@ -520,7 +550,8 @@ |
219 | load_index_file_to_table (BamfMatcher * self, |
220 | const char *index_file, |
221 | GHashTable *desktop_file_table, |
222 | - GHashTable *desktop_id_table) |
223 | + GHashTable *desktop_id_table, |
224 | + GHashTable *desktop_class_table) |
225 | { |
226 | GFile *file; |
227 | GFileInputStream *stream; |
228 | @@ -569,6 +600,7 @@ |
229 | g_string_truncate (desktop_id, desktop_id->len - 8); |
230 | |
231 | insert_data_into_tables (self, filename->str, exec, desktop_id->str, desktop_file_table, desktop_id_table); |
232 | + insert_desktop_file_class_into_table (self, filename->str, desktop_class_table); |
233 | |
234 | g_string_free (desktop_id, TRUE); |
235 | length = 0; |
236 | @@ -612,7 +644,7 @@ |
237 | if (!g_list_find_custom (dirs, "/usr/local/share/applications", (GCompareFunc) g_strcmp0)) |
238 | dirs = g_list_prepend (dirs, g_strdup ("/usr/local/share/applications")); |
239 | |
240 | - dirs = g_list_prepend (dirs, g_strdup (g_build_filename (g_get_home_dir (), ".share/applications", NULL))); |
241 | + dirs = g_list_prepend (dirs, g_strdup (g_build_filename (g_get_home_dir (), ".local/share/applications", NULL))); |
242 | |
243 | if (data_dirs) |
244 | g_strfreev (data_dirs); |
245 | @@ -690,6 +722,7 @@ |
246 | { |
247 | g_hash_table_foreach_remove (self->priv->desktop_id_table, (GHRFunc) hash_table_remove_values, path); |
248 | g_hash_table_foreach_remove (self->priv->desktop_file_table, (GHRFunc) hash_table_remove_values, path); |
249 | + g_hash_table_remove (self->priv->desktop_class_table, path); |
250 | } |
251 | |
252 | out: |
253 | @@ -697,7 +730,10 @@ |
254 | } |
255 | |
256 | static void |
257 | -create_desktop_file_table (BamfMatcher * self, GHashTable **desktop_file_table, GHashTable **desktop_id_table) |
258 | +create_desktop_file_table (BamfMatcher * self, |
259 | + GHashTable **desktop_file_table, |
260 | + GHashTable **desktop_id_table, |
261 | + GHashTable **desktop_class_table) |
262 | { |
263 | GList *directories; |
264 | GList *l; |
265 | @@ -718,6 +754,12 @@ |
266 | (GDestroyNotify) g_free, |
267 | NULL); |
268 | |
269 | + *desktop_class_table = |
270 | + g_hash_table_new_full ((GHashFunc) g_str_hash, |
271 | + (GEqualFunc) g_str_equal, |
272 | + (GDestroyNotify) g_free, |
273 | + (GDestroyNotify) g_free); |
274 | + |
275 | g_return_if_fail (BAMF_IS_MATCHER (self)); |
276 | |
277 | directories = get_desktop_file_directories (self); |
278 | @@ -740,11 +782,13 @@ |
279 | |
280 | if (g_file_test (bamf_file, G_FILE_TEST_EXISTS)) |
281 | { |
282 | - load_index_file_to_table (self, bamf_file, *desktop_file_table, *desktop_id_table); |
283 | + load_index_file_to_table (self, bamf_file, *desktop_file_table, |
284 | + *desktop_id_table, *desktop_class_table); |
285 | } |
286 | else |
287 | { |
288 | - load_directory_to_table (self, directory, *desktop_file_table, *desktop_id_table); |
289 | + load_directory_to_table (self, directory, *desktop_file_table, |
290 | + *desktop_id_table, *desktop_class_table); |
291 | } |
292 | |
293 | g_free (directory); |
294 | @@ -993,38 +1037,81 @@ |
295 | } |
296 | else |
297 | { |
298 | - char *class_name = window_class_name (window); |
299 | - |
300 | - if (class_name) |
301 | + char *window_class = window_class_name (window); |
302 | + |
303 | + char *desktop_file; |
304 | + char *desktop_class; |
305 | + |
306 | + if (window_class) |
307 | { |
308 | - class_name = g_ascii_strdown (class_name, -1); |
309 | - l = g_hash_table_lookup (priv->desktop_id_table, class_name); |
310 | + char *window_class_down = g_ascii_strdown (g_strdup(window_class), -1); |
311 | + l = g_hash_table_lookup (priv->desktop_id_table, window_class_down); |
312 | + g_free (window_class_down); |
313 | |
314 | for (; l; l = l->next) |
315 | { |
316 | - if (l->data && !g_list_find_custom (desktop_files, l->data, (GCompareFunc) g_strcmp0)) |
317 | - desktop_files = g_list_prepend (desktop_files, g_strdup (l->data)); |
318 | - } |
319 | - |
320 | - desktop_files = g_list_reverse (desktop_files); |
321 | - g_free (class_name); |
322 | - } |
323 | + desktop_file = l->data; |
324 | + if (desktop_file) |
325 | + { |
326 | + desktop_class = g_hash_table_lookup (priv->desktop_class_table, desktop_file); |
327 | + if ((desktop_class == NULL || g_strcmp0 (desktop_class, window_class) == 0) && |
328 | + !g_list_find_custom (desktop_files, desktop_file, |
329 | + (GCompareFunc) g_strcmp0)) |
330 | + { |
331 | + desktop_files = g_list_prepend (desktop_files, g_strdup (desktop_file)); |
332 | + } |
333 | + } |
334 | + } |
335 | + |
336 | + desktop_files = g_list_reverse (desktop_files); |
337 | + } |
338 | + |
339 | + /* Iterate over the desktop class table, and add matching desktop files */ |
340 | + gpointer key; |
341 | + gpointer value; |
342 | + GHashTableIter iter; |
343 | + g_hash_table_iter_init (&iter, priv->desktop_class_table); |
344 | + |
345 | + while (g_hash_table_iter_next (&iter, &key, &value)) |
346 | + { |
347 | + desktop_file = g_strdup (key); |
348 | + desktop_class = value; |
349 | + if (g_strcmp0 (desktop_class, window_class) == 0 && |
350 | + !g_list_find_custom (desktop_files, desktop_file, (GCompareFunc) g_strcmp0)) |
351 | + { |
352 | + desktop_files = g_list_prepend (desktop_files, desktop_file); |
353 | + } |
354 | + } |
355 | |
356 | pid = bamf_legacy_window_get_pid (window); |
357 | - |
358 | pid_list = bamf_matcher_possible_applications_for_pid (self, pid); |
359 | |
360 | - /* Append these files to the end to give preference to class_name style picking. |
361 | + /* Append these files to the end to give preference to window_class style picking. |
362 | This style of matching is prefered and used by GNOME Shell however does not work |
363 | very well in practice, thus requiring the fallback here */ |
364 | for (l = pid_list; l; l = l->next) |
365 | { |
366 | + desktop_file = l->data; |
367 | if (g_list_find_custom (desktop_files, l->data, (GCompareFunc) g_strcmp0)) |
368 | - g_free (l->data); |
369 | + g_free (desktop_file); |
370 | else |
371 | - desktop_files = g_list_append (desktop_files, l->data); |
372 | + { |
373 | + if (window_class) |
374 | + { |
375 | + desktop_class = g_hash_table_lookup (priv->desktop_class_table, desktop_file); |
376 | + if ((desktop_class == NULL || g_strcmp0 (desktop_class, window_class) == 0) && |
377 | + !g_list_find_custom (desktop_files, desktop_file, |
378 | + (GCompareFunc) g_strcmp0)) |
379 | + { |
380 | + desktop_files = g_list_append (desktop_files, desktop_file); |
381 | + } |
382 | + } |
383 | + else |
384 | + desktop_files = g_list_append (desktop_files, desktop_file); |
385 | + } |
386 | } |
387 | - |
388 | + |
389 | + g_free (window_class); |
390 | g_list_free (pid_list); |
391 | } |
392 | |
393 | @@ -1039,6 +1126,8 @@ |
394 | BamfLegacyWindow *window; |
395 | GList *views, *a; |
396 | char *desktop_file; |
397 | + char *win_class; |
398 | + char *app_class; |
399 | BamfApplication *app = NULL, *best = NULL; |
400 | BamfView *view; |
401 | |
402 | @@ -1049,6 +1138,7 @@ |
403 | views = self->priv->views; |
404 | |
405 | possible_apps = bamf_matcher_possible_applications_for_window (self, bamf_window); |
406 | + win_class = window_class_name(window); |
407 | |
408 | /* Loop over every application, inside that application see if its .desktop file |
409 | * matches with any of our possible hits. If so we match it. If we have no possible hits |
410 | @@ -1062,8 +1152,16 @@ |
411 | continue; |
412 | |
413 | app = BAMF_APPLICATION (view); |
414 | + app_class = bamf_application_get_wmclass (app); |
415 | + |
416 | + if (app_class != NULL && g_strcmp0 (win_class, app_class) != 0) |
417 | + { |
418 | + g_free (app_class); |
419 | + continue; |
420 | + } |
421 | + |
422 | desktop_file = bamf_application_get_desktop_file (app); |
423 | - |
424 | + |
425 | if (possible_apps) |
426 | { |
427 | /* primary matching */ |
428 | @@ -1084,7 +1182,8 @@ |
429 | if (bamf_application_contains_similar_to_window (app, bamf_window)) |
430 | best = app; |
431 | } |
432 | - |
433 | + |
434 | + g_free (app_class); |
435 | g_free (desktop_file); |
436 | } |
437 | |
438 | @@ -1095,16 +1194,19 @@ |
439 | else |
440 | best = bamf_application_new (); |
441 | |
442 | + bamf_application_set_wmclass (best, win_class); |
443 | + |
444 | bamf_matcher_register_view (self, BAMF_VIEW (best)); |
445 | g_object_unref (best); |
446 | } |
447 | |
448 | - for (l = possible_apps; l; l = l->next) |
449 | - { |
450 | - char *str = l->data; |
451 | - g_free (str); |
452 | - } |
453 | + g_free (win_class); |
454 | |
455 | + for (l = possible_apps; l; l = l->next) |
456 | + { |
457 | + char *str = l->data; |
458 | + g_free (str); |
459 | + } |
460 | |
461 | g_list_free (possible_apps); |
462 | |
463 | @@ -1340,7 +1442,8 @@ |
464 | load_desktop_file_to_table (self, |
465 | desktop_file, |
466 | self->priv->desktop_file_table, |
467 | - self->priv->desktop_id_table); |
468 | + self->priv->desktop_id_table, |
469 | + self->priv->desktop_class_table); |
470 | } |
471 | |
472 | void |
473 | @@ -1731,11 +1834,13 @@ |
474 | |
475 | g_array_free (prefixstrings, TRUE); |
476 | |
477 | - create_desktop_file_table (self, &(priv->desktop_file_table), &(priv->desktop_id_table)); |
478 | + create_desktop_file_table (self, &(priv->desktop_file_table), |
479 | + &(priv->desktop_id_table), |
480 | + &(priv->desktop_class_table)); |
481 | |
482 | screen = bamf_legacy_screen_get_default (); |
483 | g_signal_connect (G_OBJECT (screen), "window-opened", |
484 | - (GCallback) handle_window_opened, self); |
485 | + (GCallback) handle_window_opened, self); |
486 | |
487 | approver = bamf_indicator_source_get_default (); |
488 | g_signal_connect (G_OBJECT (approver), "indicator-opened", |
I am not sure I'm the right person to review this branch, but I got one nitpick nontheless :-)
The get_class() and set_class() methods on BamfApplication are not very binding friendly. If I called app.get_class() from Vala or PyGI it would normally give me the GObjectClass struct for the object, but this patch would override that method.
Maybe get/set_wmclass() instead?