Merge lp:~3v1n0/bamf/desktop-class-matching-improved into lp:bamf/0.4

Proposed by Marco Trevisan (Treviño) on 2012-04-19
Status: Merged
Approved by: Marco Trevisan (Treviño) on 2012-04-24
Approved revision: 469
Merged at revision: 460
Proposed branch: lp:~3v1n0/bamf/desktop-class-matching-improved
Merge into: lp:bamf/0.4
Diff against target: 1185 lines (+459/-304)
6 files modified
src/bamf-legacy-window.c (+51/-16)
src/bamf-legacy-window.h (+14/-15)
src/bamf-matcher.c (+319/-250)
src/bamf-view.c (+3/-1)
src/bamf-xutils.c (+68/-20)
src/bamf-xutils.h (+4/-2)
To merge this branch: bzr merge lp:~3v1n0/bamf/desktop-class-matching-improved
Reviewer Review Type Date Requested Status
Jason Smith (community) 2012-04-19 Approve on 2012-04-24
Review via email: mp+102741@code.launchpad.net

Commit message

BamfLegacyWindow and BamfMatcher changes needed to get the proper WM_CLASS / desktop-class matching in BAMF.

Description of the change

BamfLegacyWindow and BamfMatcher changes needed to get the proper WM_CLASS matching in BAMF.

This mostly allow to get the wanted experience with the Chrome/Chromium web applications
so now:
 - When a Web application is launched and has a matching .desktop file (this means that
   the file should include the StartupWMClass parameter that matches the window's class
   instance name) then it's matched as a new application using that file.
 - When a Web application is launched and has not a matching .desktop file (no file
   matches its class), then we fallback to the know .desktop files (so very likely to the
   parent application desktop).

Changes include:
 - BamfLegacyWindow is now able to fetch both the window class name and instance name also
   for non-gtk3 builds (instead of using libwnck, we fallback to Xlib)
 - BamfXutils now avoid to open a display connection per request.
 - BamfMatcher includes now the utility function
   bamf_matcher_get_application_by_desktop_file that allows to remove a lot of code
   duplication. It correctly matches the chromium web applications and avoids the re-usage
   of non-optimum running .desktop files.

To post a comment you must log in.
467. By Marco Trevisan (Treviño) on 2012-04-19

BamfMatcher: free the temporary list we use to order the windows by stack

468. By Marco Trevisan (Treviño) on 2012-04-19

BamfMatcher: be more explicit about the desktop file to use for a new application.

469. By Marco Trevisan (Treviño) on 2012-04-20

BamfMatcher: oops... Forgot an else when checking the type of new application we should create

Jason Smith (jassmith) wrote :

+1 looks okay

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/bamf-legacy-window.c'
--- src/bamf-legacy-window.c 2012-02-10 20:05:54 +0000
+++ src/bamf-legacy-window.c 2012-04-20 17:39:18 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2010 Canonical Ltd2 * Copyright (C) 2010-2012 Canonical Ltd
3 *3 *
4 * This program is free software: you can redistribute it and/or modify4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as5 * it under the terms of the GNU General Public License version 3 as
@@ -14,6 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Jason Smith <jason.smith@canonical.com>16 * Authored by: Jason Smith <jason.smith@canonical.com>
17 * Marco Trevisan (Treviño) <3v1n0@ubuntu.com>
17 *18 *
18 */19 */
1920
@@ -47,6 +48,10 @@
47{48{
48 WnckWindow * legacy_window;49 WnckWindow * legacy_window;
49 char * mini_icon_path;50 char * mini_icon_path;
51#ifndef USE_GTK3
52 char * group_name;
53 char * instance_name;
54#endif
50 gulong closed_id;55 gulong closed_id;
51 gulong name_changed_id;56 gulong name_changed_id;
52 gulong state_changed_id;57 gulong state_changed_id;
@@ -105,7 +110,6 @@
105 return wnck_window_is_skip_tasklist (self->priv->legacy_window);110 return wnck_window_is_skip_tasklist (self->priv->legacy_window);
106}111}
107112
108#ifdef USE_GTK3
109const char *113const char *
110bamf_legacy_window_get_class_instance_name (BamfLegacyWindow *self)114bamf_legacy_window_get_class_instance_name (BamfLegacyWindow *self)
111{115{
@@ -115,17 +119,29 @@
115119
116 window = self->priv->legacy_window;120 window = self->priv->legacy_window;
117121
122 if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_class_instance_name)
123 return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_class_instance_name (self);
124
118 if (!window)125 if (!window)
119 return NULL;126 return NULL;
120127
128#ifdef USE_GTK3
121 return wnck_window_get_class_instance_name (window);129 return wnck_window_get_class_instance_name (window);
130
131#else
132 if (!self->priv->instance_name)
133 {
134 Window xid = wnck_window_get_xid (window);
135 bamf_xutils_get_window_class_hints (xid, &self->priv->instance_name, NULL);
136 }
137
138 return self->priv->instance_name;
139#endif
122}140}
123#endif
124141
125const char *142const char *
126bamf_legacy_window_get_class_name (BamfLegacyWindow *self)143bamf_legacy_window_get_class_name (BamfLegacyWindow *self)
127{144{
128 WnckClassGroup *group;
129 WnckWindow *window;145 WnckWindow *window;
130146
131 g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);147 g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
@@ -138,12 +154,18 @@
138 if (!window)154 if (!window)
139 return NULL;155 return NULL;
140156
141 group = wnck_window_get_class_group (window);157#ifdef USE_GTK3
142158 return wnck_window_get_class_group_name (window);
143 if (!group)159
144 return NULL;160#else
145161 if (!self->priv->group_name)
146 return wnck_class_group_get_res_class (group);162 {
163 Window xid = wnck_window_get_xid (window);
164 bamf_xutils_get_window_class_hints (xid, NULL, &self->priv->group_name);
165 }
166
167 return self->priv->group_name;
168#endif
147}169}
148170
149const char *171const char *
@@ -186,7 +208,7 @@
186 {208 {
187 g_string_append (exec, argv[i]);209 g_string_append (exec, argv[i]);
188 if (argv[i + 1] != NULL)210 if (argv[i + 1] != NULL)
189 g_string_append (exec, " ");211 g_string_append (exec, " ");
190 g_free (argv[i]);212 g_free (argv[i]);
191 i++;213 i++;
192 }214 }
@@ -253,7 +275,6 @@
253{275{
254 g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), 0);276 g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), 0);
255277
256
257 if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_xid)278 if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_xid)
258 return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_xid (self);279 return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_xid (self);
259280
@@ -347,10 +368,10 @@
347bamf_legacy_window_get_geometry (BamfLegacyWindow *self, gint *x, gint *y,368bamf_legacy_window_get_geometry (BamfLegacyWindow *self, gint *x, gint *y,
348 gint *width, gint *height)369 gint *width, gint *height)
349{370{
350 *x = 0;371 if (x) *x = 0;
351 *y = 0;372 if (y) *y = 0;
352 *width = 0;373 if (width) *width = 0;
353 *height = 0;374 if (height) *height = 0;
354375
355 g_return_if_fail (BAMF_IS_LEGACY_WINDOW (self));376 g_return_if_fail (BAMF_IS_LEGACY_WINDOW (self));
356377
@@ -478,6 +499,20 @@
478 self->priv->mini_icon_path = NULL;499 self->priv->mini_icon_path = NULL;
479 }500 }
480501
502#ifndef USE_GTK3
503 if (self->priv->group_name)
504 {
505 g_free (self->priv->group_name);
506 self->priv->group_name = NULL;
507 }
508
509 if (self->priv->instance_name)
510 {
511 g_free (self->priv->instance_name);
512 self->priv->instance_name = NULL;
513 }
514#endif
515
481 if (self->priv->legacy_window)516 if (self->priv->legacy_window)
482 {517 {
483 g_signal_handler_disconnect (self->priv->legacy_window,518 g_signal_handler_disconnect (self->priv->legacy_window,
484519
=== modified file 'src/bamf-legacy-window.h'
--- src/bamf-legacy-window.h 2012-02-10 17:33:51 +0000
+++ src/bamf-legacy-window.h 2012-04-20 17:39:18 +0000
@@ -70,19 +70,20 @@
70{70{
71 GObjectClass parent;71 GObjectClass parent;
7272
73 const char * (*get_name) (BamfLegacyWindow *legacy_window);73 const char * (*get_name) (BamfLegacyWindow *legacy_window);
74 const char * (*get_class_name) (BamfLegacyWindow *legacy_window);74 const char * (*get_class_name) (BamfLegacyWindow *legacy_window);
75 char * (*get_exec_string) (BamfLegacyWindow *legacy_window);75 const char * (*get_class_instance_name) (BamfLegacyWindow *legacy_window);
76 char * (*get_app_id) (BamfLegacyWindow *legacy_window);76 char * (*get_exec_string) (BamfLegacyWindow *legacy_window);
77 char * (*get_unique_bus_name) (BamfLegacyWindow *legacy_window);77 char * (*get_app_id) (BamfLegacyWindow *legacy_window);
78 char * (*get_menu_object_path) (BamfLegacyWindow *legacy_window);78 char * (*get_unique_bus_name) (BamfLegacyWindow *legacy_window);
79 gint (*get_pid) (BamfLegacyWindow *legacy_window);79 char * (*get_menu_object_path) (BamfLegacyWindow *legacy_window);
80 guint32 (*get_xid) (BamfLegacyWindow *legacy_window);80 gint (*get_pid) (BamfLegacyWindow *legacy_window);
81 gboolean (*needs_attention) (BamfLegacyWindow *legacy_window);81 guint32 (*get_xid) (BamfLegacyWindow *legacy_window);
82 gboolean (*is_active) (BamfLegacyWindow *legacy_window);82 gboolean (*needs_attention) (BamfLegacyWindow *legacy_window);
83 gboolean (*is_skip_tasklist) (BamfLegacyWindow *legacy_window);83 gboolean (*is_active) (BamfLegacyWindow *legacy_window);
84 gboolean (*is_desktop) (BamfLegacyWindow *legacy_window);84 gboolean (*is_skip_tasklist) (BamfLegacyWindow *legacy_window);
85 gboolean (*is_dialog) (BamfLegacyWindow *legacy_window);85 gboolean (*is_desktop) (BamfLegacyWindow *legacy_window);
86 gboolean (*is_dialog) (BamfLegacyWindow *legacy_window);
86 BamfWindowMaximizationType (*maximized) (BamfLegacyWindow *legacy_window);87 BamfWindowMaximizationType (*maximized) (BamfLegacyWindow *legacy_window);
8788
88 void (*get_geometry) (BamfLegacyWindow *self,89 void (*get_geometry) (BamfLegacyWindow *self,
@@ -126,9 +127,7 @@
126127
127BamfWindowMaximizationType bamf_legacy_window_maximized (BamfLegacyWindow *self);128BamfWindowMaximizationType bamf_legacy_window_maximized (BamfLegacyWindow *self);
128129
129#ifdef USE_GTK3
130const char * bamf_legacy_window_get_class_instance_name (BamfLegacyWindow *self);130const char * bamf_legacy_window_get_class_instance_name (BamfLegacyWindow *self);
131#endif
132131
133const char * bamf_legacy_window_get_class_name (BamfLegacyWindow *self);132const char * bamf_legacy_window_get_class_name (BamfLegacyWindow *self);
134133
135134
=== modified file 'src/bamf-matcher.c'
--- src/bamf-matcher.c 2012-03-19 17:11:35 +0000
+++ src/bamf-matcher.c 2012-04-20 17:39:18 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2010-2011 Canonical Ltd2 * Copyright (C) 2010-2012 Canonical Ltd
3 *3 *
4 * This program is free software: you can redistribute it and/or modify4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as5 * it under the terms of the GNU General Public License version 3 as
@@ -28,6 +28,7 @@
28#include "bamf-legacy-screen.h"28#include "bamf-legacy-screen.h"
29#include "bamf-indicator-source.h"29#include "bamf-indicator-source.h"
30#include "bamf-xutils.h"30#include "bamf-xutils.h"
31#include <strings.h>
3132
32G_DEFINE_TYPE (BamfMatcher, bamf_matcher, BAMF_DBUS_TYPE_MATCHER_SKELETON);33G_DEFINE_TYPE (BamfMatcher, bamf_matcher, BAMF_DBUS_TYPE_MATCHER_SKELETON);
33#define BAMF_MATCHER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE(obj, \34#define BAMF_MATCHER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE(obj, \
@@ -126,6 +127,37 @@
126127
127static void bamf_matcher_unregister_view (BamfMatcher *self, BamfView *view);128static void bamf_matcher_unregister_view (BamfMatcher *self, BamfView *view);
128129
130static BamfApplication *
131bamf_matcher_get_application_by_desktop_file (BamfMatcher *self, const char *desktop_file)
132{
133 GList *l;
134 BamfView *view;
135
136 g_return_val_if_fail (BAMF_IS_MATCHER (self), NULL);
137
138 if (!desktop_file)
139 return NULL;
140
141 for (l = self->priv->views; l; l = l->next)
142 {
143 view = l->data;
144
145 if (!BAMF_IS_APPLICATION (view))
146 continue;
147
148 BamfApplication *app = BAMF_APPLICATION (view);
149 const gchar *app_desktop;
150 app_desktop = bamf_application_get_desktop_file (app);
151
152 if (g_strcmp0 (desktop_file, app_desktop) == 0)
153 {
154 return app;
155 }
156 }
157
158 return NULL;
159}
160
129static gboolean161static gboolean
130emit_paths_changed (gpointer user_data)162emit_paths_changed (gpointer user_data)
131{163{
@@ -177,11 +209,7 @@
177209
178static void bamf_matcher_prepare_path_change (BamfMatcher *self, const gchar *desktop_file, ViewChangeType change_type)210static void bamf_matcher_prepare_path_change (BamfMatcher *self, const gchar *desktop_file, ViewChangeType change_type)
179{211{
180 GList *l;
181 BamfView *view;
182 BamfMatcherPrivate *priv;212 BamfMatcherPrivate *priv;
183 const char *app_desktop;
184 gboolean found = FALSE;
185213
186 if (desktop_file == NULL) return;214 if (desktop_file == NULL) return;
187215
@@ -189,26 +217,12 @@
189217
190 priv = self->priv;218 priv = self->priv;
191219
192 for (l = priv->views; l; l = l->next)
193 {
194 view = l->data;
195
196 if (!BAMF_IS_APPLICATION (view) || !bamf_view_is_running (view))
197 continue;
198
199 app_desktop = bamf_application_get_desktop_file (BAMF_APPLICATION (view));
200 if (!app_desktop) continue;
201
202 if (g_strcmp0 (desktop_file, app_desktop) == 0)
203 {
204 found = TRUE;
205 break;
206 }
207 }
208
209 /* the app was already running (ADDED) / had more instances which are still220 /* the app was already running (ADDED) / had more instances which are still
210 * there (REMOVED) */221 * there (REMOVED) */
211 if (found) return;222 if (bamf_matcher_get_application_by_desktop_file (self, desktop_file))
223 {
224 return;
225 }
212226
213 if (!priv->opened_closed_paths_table)227 if (!priv->opened_closed_paths_table)
214 {228 {
@@ -258,7 +272,7 @@
258 self->priv->views = g_list_prepend (self->priv->views, view);272 self->priv->views = g_list_prepend (self->priv->views, view);
259273
260 g_signal_emit_by_name (self, "view-opened", path, type);274 g_signal_emit_by_name (self, "view-opened", path, type);
261 275
262 // trigger manually since this is already active276 // trigger manually since this is already active
263 if (bamf_view_is_active (view))277 if (bamf_view_is_active (view))
264 on_view_active_changed (view, TRUE, self);278 on_view_active_changed (view, TRUE, self);
@@ -1514,59 +1528,134 @@
1514is_web_app_window (BamfMatcher *self, BamfLegacyWindow *window)1528is_web_app_window (BamfMatcher *self, BamfLegacyWindow *window)
1515{1529{
1516 const char *window_class = bamf_legacy_window_get_class_name (window);1530 const char *window_class = bamf_legacy_window_get_class_name (window);
1517#ifdef USE_GTK3
1518 const char *instance_name = bamf_legacy_window_get_class_instance_name(window);1531 const char *instance_name = bamf_legacy_window_get_class_instance_name(window);
1519 // chromium uses url wm_class strings to represent its web apps. These apps1532
1520 // will still have the same parent pid and hints as the main chrome window, so we1533 // Chrome/Chromium uses url wm_class strings to represent its web apps.
1521 // skip the hint check. We can tell a window is a chrome web app window if its instance1534 // These apps will still have the same parent pid and hints as the main chrome
1522 // name is google-chrome but its window class is not Google-chrome1535 // window, so we skip the hint check.
1523 return !g_strcmp0(instance_name, "google-chrome") && g_strcmp0(window_class, "Google-chrome");1536 // We can tell a window is a chrome web app window if its instance name is
1524#else1537 // not google-chrome but its window class is Google-chrome
1525 return g_str_has_prefix(window_class, "crx_");1538 // We can tell a window is chromium web app window if its instance name is
1526#endif1539 // not chromium-browser but its window class is Chromium Browser
1540
1541 gboolean valid_app = FALSE;
1542
1543 if (g_strcmp0 (window_class, "Google-chrome") == 0 &&
1544 g_strcmp0 (instance_name, "google-chrome") != 0)
1545 {
1546 valid_app = TRUE;
1547 }
1548 else if (g_strcmp0 (window_class, "Chromium-browser") == 0 &&
1549 g_strcmp0 (instance_name, "chromium-browser") != 0)
1550 {
1551 valid_app = TRUE;
1552 }
1553
1554 return valid_app;
1555}
1556
1557static gboolean
1558bamf_matcher_window_skips_hint_set (BamfMatcher *self, BamfLegacyWindow *window)
1559{
1560 gboolean skip_hint_set = FALSE;
1561 g_return_val_if_fail (BAMF_IS_MATCHER (self), TRUE);
1562
1563 skip_hint_set = is_web_app_window (self, window);
1564
1565 return skip_hint_set;
1566}
1567
1568static GList *
1569bamf_matcher_get_class_matching_desktop_files (BamfMatcher *self, const gchar *class_name)
1570{
1571 GList* desktop_files = NULL;
1572 gpointer key;
1573 gpointer value;
1574 GHashTableIter iter;
1575
1576 g_return_val_if_fail (BAMF_IS_MATCHER (self), NULL);
1577 g_hash_table_iter_init (&iter, self->priv->desktop_class_table);
1578
1579 while (g_hash_table_iter_next (&iter, &key, &value))
1580 {
1581 gchar* desktop_file = g_strdup (key);
1582 gchar* desktop_class = value;
1583
1584 if (g_strcmp0 (desktop_class, class_name) == 0)
1585 {
1586 desktop_files = g_list_prepend (desktop_files, desktop_file);
1587 }
1588 }
1589
1590 return desktop_files;
1591}
1592
1593static gboolean
1594bamf_matcher_has_instance_class_desktop_file (BamfMatcher *self, const gchar *class_name)
1595{
1596 gpointer key;
1597 gpointer value;
1598 GHashTableIter iter;
1599
1600 g_return_val_if_fail (BAMF_IS_MATCHER (self), FALSE);
1601 g_hash_table_iter_init (&iter, self->priv->desktop_class_table);
1602
1603 while (g_hash_table_iter_next (&iter, &key, &value))
1604 {
1605 gchar* desktop_class = value;
1606
1607 if (g_strcmp0 (desktop_class, class_name) == 0)
1608 {
1609 return TRUE;
1610 }
1611 }
1612
1613 return FALSE;
1527}1614}
15281615
1529static GList *1616static GList *
1530bamf_matcher_possible_applications_for_window (BamfMatcher *self,1617bamf_matcher_possible_applications_for_window (BamfMatcher *self,
1531 BamfWindow *bamf_window)1618 BamfWindow *bamf_window)
1532{1619{
1533 char *hint = NULL;
1534 BamfMatcherPrivate *priv;1620 BamfMatcherPrivate *priv;
1535 gint pid;
1536 BamfLegacyWindow *window;1621 BamfLegacyWindow *window;
1537 GList *desktop_files = NULL, *pid_list = NULL, *l;1622 GList *desktop_files = NULL, *l;
1623 char *desktop_file = NULL;
1624 char *desktop_class = NULL;
15381625
1539 g_return_val_if_fail (BAMF_IS_WINDOW (bamf_window), NULL);1626 g_return_val_if_fail (BAMF_IS_WINDOW (bamf_window), NULL);
1540 g_return_val_if_fail (BAMF_IS_MATCHER (self), NULL);1627 g_return_val_if_fail (BAMF_IS_MATCHER (self), NULL);
15411628
1542 priv = self->priv;1629 priv = self->priv;
1543
1544 window = bamf_window_get_window (bamf_window);1630 window = bamf_window_get_window (bamf_window);
15451631
1546 hint = get_window_hint (window, _NET_WM_DESKTOP_FILE);1632 desktop_file = get_window_hint (window, _NET_WM_DESKTOP_FILE);
1547 const char *window_class = bamf_legacy_window_get_class_name (window);1633
15481634 const char *class_name = bamf_legacy_window_get_class_name (window);
1549 if (hint)1635 const char *instance_name = bamf_legacy_window_get_class_instance_name (window);
1636 gboolean known_desktop_class = bamf_matcher_has_instance_class_desktop_file (self, instance_name);
1637
1638 if (desktop_file)
1550 {1639 {
1551 /* whew, hard work, didn't even have to make a copy! */1640 desktop_class = g_hash_table_lookup (priv->desktop_class_table, desktop_file);
1552 if (hint[0] != '\0' && !is_web_app_window(self, window))1641
1642 if (!known_desktop_class || g_strcmp0 (desktop_class, desktop_file) == 0)
1553 {1643 {
1554 desktop_files = g_list_prepend (desktop_files, hint);1644 desktop_files = g_list_prepend (desktop_files, desktop_file);
1555 }1645 }
1556 else1646 else
1557 {1647 {
1558 g_free (hint);1648 g_free (desktop_file);
1559 }1649 }
1560 }1650 }
1561 else1651
1652 desktop_file = NULL;
1653
1654 if (!desktop_files)
1562 {1655 {
1563 1656 if (class_name)
1564 char *desktop_file;
1565 char *desktop_class;
1566
1567 if (window_class)
1568 {1657 {
1569 char *window_class_down = g_ascii_strdown (window_class, -1);1658 char *window_class_down = g_ascii_strdown (class_name, -1);
1570 l = g_hash_table_lookup (priv->desktop_id_table, window_class_down);1659 l = g_hash_table_lookup (priv->desktop_id_table, window_class_down);
1571 g_free (window_class_down);1660 g_free (window_class_down);
15721661
@@ -1577,11 +1666,14 @@
1577 if (desktop_file)1666 if (desktop_file)
1578 {1667 {
1579 desktop_class = g_hash_table_lookup (priv->desktop_class_table, desktop_file);1668 desktop_class = g_hash_table_lookup (priv->desktop_class_table, desktop_file);
1580 if ((desktop_class == NULL || g_strcmp0 (desktop_class, window_class) == 0) &&1669
1581 !g_list_find_custom (desktop_files, desktop_file,1670 if (!known_desktop_class || g_strcmp0 (desktop_class, instance_name) == 0)
1582 (GCompareFunc) g_strcmp0))
1583 {1671 {
1584 desktop_files = g_list_prepend (desktop_files, g_strdup (desktop_file));1672 if (!g_list_find_custom (desktop_files, desktop_file,
1673 (GCompareFunc) g_strcmp0))
1674 {
1675 desktop_files = g_list_prepend (desktop_files, g_strdup (desktop_file));
1676 }
1585 }1677 }
1586 }1678 }
1587 }1679 }
@@ -1589,31 +1681,10 @@
1589 desktop_files = g_list_reverse (desktop_files);1681 desktop_files = g_list_reverse (desktop_files);
1590 }1682 }
15911683
1592 /* Iterate over the desktop class table, and add matching desktop files */1684 gint pid = bamf_legacy_window_get_pid (window);
1593 gpointer key;1685 GList *pid_list = bamf_matcher_possible_applications_for_pid (self, pid);
1594 gpointer value;
1595 GHashTableIter iter;
1596 g_hash_table_iter_init (&iter, priv->desktop_class_table);
1597
1598 while (g_hash_table_iter_next (&iter, &key, &value))
1599 {
1600 desktop_file = g_strdup (key);
1601 desktop_class = value;
1602 if (g_strcmp0 (desktop_class, window_class) == 0 &&
1603 !g_list_find_custom (desktop_files, desktop_file, (GCompareFunc) g_strcmp0))
1604 {
1605 desktop_files = g_list_prepend (desktop_files, desktop_file);
1606 }
1607 else
1608 {
1609 g_free (desktop_file);
1610 }
1611 }
1612
1613 pid = bamf_legacy_window_get_pid (window);
1614 pid_list = bamf_matcher_possible_applications_for_pid (self, pid);
1615 1686
1616 /* Append these files to the end to give preference to window_class style picking.1687 /* Append these files to the end to give preference to class_name style picking.
1617 This style of matching is prefered and used by GNOME Shell however does not work1688 This style of matching is prefered and used by GNOME Shell however does not work
1618 very well in practice, thus requiring the fallback here */1689 very well in practice, thus requiring the fallback here */
1619 for (l = pid_list; l; l = l->next)1690 for (l = pid_list; l; l = l->next)
@@ -1627,10 +1698,10 @@
1627 {1698 {
1628 gboolean append = FALSE;1699 gboolean append = FALSE;
16291700
1630 if (window_class)1701 if (instance_name)
1631 {1702 {
1632 desktop_class = g_hash_table_lookup (priv->desktop_class_table, desktop_file);1703 desktop_class = g_hash_table_lookup (priv->desktop_class_table, desktop_file);
1633 if (desktop_class == NULL || g_strcmp0 (desktop_class, window_class) == 0)1704 if (!known_desktop_class || g_strcmp0 (desktop_class, instance_name) == 0)
1634 {1705 {
1635 append = TRUE;1706 append = TRUE;
1636 }1707 }
@@ -1671,7 +1742,12 @@
16711742
1672 g_list_free (pid_list);1743 g_list_free (pid_list);
1673 }1744 }
1674 1745
1746 if (!desktop_files && known_desktop_class)
1747 {
1748 desktop_files = bamf_matcher_get_class_matching_desktop_files (self, instance_name);
1749 }
1750
1675 return desktop_files;1751 return desktop_files;
1676}1752}
16771753
@@ -1681,75 +1757,141 @@
1681{1757{
1682 GList *possible_apps, *l;1758 GList *possible_apps, *l;
1683 BamfLegacyWindow *window;1759 BamfLegacyWindow *window;
1684 GList *views, *a;1760 const gchar *app_class;
1685 const char *win_class;1761 const gchar *app_desktop = NULL;
1686 const char *desktop_file;
1687 const char *app_class;
1688 BamfApplication *app = NULL, *best = NULL;1762 BamfApplication *app = NULL, *best = NULL;
1689 BamfView *view;
16901763
1691 g_return_if_fail (BAMF_IS_MATCHER (self));1764 g_return_if_fail (BAMF_IS_MATCHER (self));
1692 g_return_if_fail (BAMF_IS_WINDOW (bamf_window));1765 g_return_if_fail (BAMF_IS_WINDOW (bamf_window));
16931766
1694 window = bamf_window_get_window (bamf_window);1767 window = bamf_window_get_window (bamf_window);
1695 views = self->priv->views;
16961768
1697 possible_apps = bamf_matcher_possible_applications_for_window (self, bamf_window);1769 possible_apps = bamf_matcher_possible_applications_for_window (self, bamf_window);
1698 win_class = bamf_legacy_window_get_class_name (window);1770 const char *win_instance = bamf_legacy_window_get_class_instance_name (window);
16991771 const char *win_class_name = bamf_legacy_window_get_class_name (window);
1700 /* Loop over every application, inside that application see if its .desktop file1772
1701 * matches with any of our possible hits. If so we match it. If we have no possible hits1773 app_class = win_instance;
1702 * fall back to secondary matching. 1774
1703 */1775 /* Loop over every possible desktop file that could match the window, and try
1704 for (a = views; a; a = a->next)1776 * to reuse an already-opened window that uses it.
1705 {1777 * Desktop files are ordered by priority, so we try to use the first possible,
1706 view = a->data;1778 * wm_class matching applications have the priority, btw. */
17071779 if (possible_apps)
1708 if (!BAMF_IS_APPLICATION (view))1780 {
1709 continue;1781 /* primary matching */
17101782 for (l = possible_apps; l; l = l->next)
1711 app = BAMF_APPLICATION (view);1783 {
1712 app_class = bamf_application_get_wmclass (app);1784 const gchar *desktop_file = l->data;
1713 desktop_file = bamf_application_get_desktop_file (app);1785 app = bamf_matcher_get_application_by_desktop_file (self, desktop_file);
17141786
1715 if (possible_apps)1787 if (BAMF_IS_APPLICATION (app))
1716 {1788 {
1717 /* primary matching */1789 const gchar *app_desktop_class;
17181790 app_desktop_class = bamf_application_get_wmclass (app);
1719 for (l = possible_apps; l; l = l->next)1791
1720 {1792 if (win_instance && app_desktop_class && strcasecmp (win_instance, app_desktop_class) == 0)
1721 if (g_strcmp0 (desktop_file, l->data) == 0)1793 {
1722 {1794 best = app;
1723 if (!best || !g_strcmp0 (win_class, app_class))1795 break;
1724 best = app;1796 }
1725 break;1797 else if (!best)
1726 }1798 {
1727 }1799 best = app;
1728 }1800 }
1729 else if (desktop_file == NULL) 1801 }
1730 {1802 }
1731 /* secondary matching */1803
1732 1804 /* If a "best" application has been found, we should check again if the
1733 if (bamf_application_contains_similar_to_window (app, bamf_window) && (!best || !g_strcmp0 (win_class, app_class)))1805 * desktop file that is going to be used is really the best one we have.
1734 best = app;1806 * To do this, we compare the window class name with the desktop class
1807 * of both candidates to ensure that really is the best one.
1808 * This is important to avoid that very-similar (which differ only by
1809 * StartupWMClass) running desktop files, would be wrongly used to match
1810 * an incompatible window. */
1811 if (BAMF_IS_APPLICATION (best) && possible_apps)
1812 {
1813 const gchar *best_app_desktop = bamf_application_get_desktop_file (best);
1814 const gchar *best_desktop = possible_apps->data;
1815
1816 if (win_class_name && g_strcmp0 (best_app_desktop, best_desktop) != 0)
1817 {
1818 const gchar *best_app_class;
1819 const gchar *best_desktop_class;
1820
1821 best_app_class = bamf_application_get_wmclass (best);
1822 best_desktop_class = g_hash_table_lookup (self->priv->desktop_class_table, best_desktop);
1823
1824 /* We compare the two classes using their "distance" from the
1825 * desidered class value */
1826 if (best_app_class && best_desktop_class)
1827 {
1828 int max_chars = strlen (win_class_name);
1829 int app_diff = strncasecmp (win_class_name, best_app_class, max_chars);
1830 int desktop_diff = strncasecmp (win_class_name, best_desktop_class, max_chars);
1831
1832 if (abs (desktop_diff) < abs (app_diff))
1833 {
1834 best = bamf_matcher_get_application_by_desktop_file (self, best_desktop);
1835 app_desktop = best_desktop;
1836 }
1837 }
1838 }
1839 }
1840 }
1841 else
1842 {
1843 /* secondary matching */
1844 GList *a;
1845 BamfView *view;
1846 const gchar *app_desktop_class;
1847
1848 for (a = self->priv->views; a; a = a->next)
1849 {
1850 view = a->data;
1851
1852 if (!BAMF_IS_APPLICATION (view))
1853 continue;
1854
1855 app = BAMF_APPLICATION (view);
1856 app_desktop_class = bamf_application_get_wmclass (app);
1857
1858 if (bamf_application_contains_similar_to_window (app, bamf_window))
1859 {
1860 if (win_instance && g_strcmp0 (win_instance, app_desktop_class) == 0)
1861 {
1862 best = app;
1863 break;
1864 }
1865 else if (!best)
1866 {
1867 best = app;
1868 }
1869 }
1735 }1870 }
1736 }1871 }
17371872
1738 if (!best)1873 if (!best)
1739 {1874 {
1740 if (possible_apps)1875 if (app_desktop)
1741 best = bamf_application_new_from_desktop_files (possible_apps);1876 {
1877 best = bamf_application_new_from_desktop_file (app_desktop);
1878 }
1879 else if (possible_apps)
1880 {
1881 best = bamf_application_new_from_desktop_files (possible_apps);
1882 }
1742 else1883 else
1743 best = bamf_application_new ();1884 {
17441885 best = bamf_application_new ();
1745 bamf_application_set_wmclass (best, win_class);1886 }
17461887
1888 bamf_application_set_wmclass (best, app_class);
1747 bamf_matcher_register_view_stealing_ref (self, BAMF_VIEW (best));1889 bamf_matcher_register_view_stealing_ref (self, BAMF_VIEW (best));
1748 }1890 }
17491891
1750 g_list_free_full (possible_apps, g_free);
1751
1752 bamf_view_add_child (BAMF_VIEW (best), BAMF_VIEW (bamf_window));1892 bamf_view_add_child (BAMF_VIEW (best), BAMF_VIEW (bamf_window));
1893
1894 g_list_free_full (possible_apps, g_free);
1753}1895}
17541896
1755/* Ensures that the window hint is set if a registered pid matches, and that set window hints1897/* Ensures that the window hint is set if a registered pid matches, and that set window hints
@@ -1760,7 +1902,7 @@
1760{1902{
1761 GArray *pids;1903 GArray *pids;
1762 GHashTable *registered_pids;1904 GHashTable *registered_pids;
1763 char *window_hint = NULL;1905 char *desktop_file_hint = NULL;
1764 gint i, pid;1906 gint i, pid;
1765 gpointer key;1907 gpointer key;
17661908
@@ -1769,51 +1911,35 @@
17691911
1770 registered_pids = self->priv->registered_pids;1912 registered_pids = self->priv->registered_pids;
17711913
1772 // web apps can end up forcing their parent browsers to match on them, so remove from pid table if this is the case1914 /* Some windows such as web applications shares the pid with their parent
1773 if (is_web_app_window (self, window))1915 * browser so, we have to ignore them */
1774 {1916 if (bamf_matcher_window_skips_hint_set (self, window))
1917 {
1918 return;
1919 }
1920
1921 desktop_file_hint = get_window_hint (window, _NET_WM_DESKTOP_FILE);
1922
1923 if (desktop_file_hint)
1924 {
1925 /* already set, make sure we know about this
1926 * fact for future windows of this applications */
1775 pid = bamf_legacy_window_get_pid (window);1927 pid = bamf_legacy_window_get_pid (window);
17761928
1777 if (pid > 0)1929 if (pid > 0)
1778 {1930 {
1779 gpointer key = GINT_TO_POINTER (pid);1931 key = GINT_TO_POINTER (pid);
1780 const char* result = g_hash_table_lookup (registered_pids, key);1932
1781 if (result && g_str_has_prefix (result, "/home/"))1933 if (!g_hash_table_lookup (registered_pids, key))
1782 {1934 {
1783 g_hash_table_remove (registered_pids, key);1935 g_hash_table_insert (registered_pids, key, g_strdup (desktop_file_hint));
1784 }1936 }
1785 }1937 }
17861938
1939 g_free (desktop_file_hint);
1787 return;1940 return;
1788 }1941 }
17891942
1790 window_hint = get_window_hint (window, _NET_WM_DESKTOP_FILE);
1791 if (window_hint)
1792 {
1793 if (window_hint[0] != '\0')
1794 {
1795 /* already set, make sure we know about this
1796 * fact for future windows of this applications */
1797 pid = bamf_legacy_window_get_pid (window);
1798
1799 if (pid > 0)
1800 {
1801 key = GINT_TO_POINTER (pid);
1802
1803 if (!g_hash_table_lookup (registered_pids, key))
1804 {
1805 g_hash_table_insert (registered_pids, key, g_strdup (window_hint));
1806 }
1807 }
1808
1809 g_free (window_hint);
1810 return;
1811 }
1812
1813 g_free (window_hint);
1814 window_hint = NULL;
1815 }
1816
1817 pids = pid_parent_tree (self, bamf_legacy_window_get_pid (window));1943 pids = pid_parent_tree (self, bamf_legacy_window_get_pid (window));
18181944
1819 for (i = 0; i < pids->len; i++)1945 for (i = 0; i < pids->len; i++)
@@ -1821,15 +1947,15 @@
1821 pid = g_array_index (pids, gint, i);1947 pid = g_array_index (pids, gint, i);
1822 key = GINT_TO_POINTER (pid);1948 key = GINT_TO_POINTER (pid);
18231949
1824 window_hint = g_hash_table_lookup (registered_pids, key);1950 desktop_file_hint = g_hash_table_lookup (registered_pids, key);
1825 if (window_hint != NULL && window_hint[0] != '\0')1951 if (desktop_file_hint != NULL && desktop_file_hint[0] != '\0')
1826 break;1952 break;
1827 }1953 }
18281954
1829 g_array_free (pids, TRUE);1955 g_array_free (pids, TRUE);
18301956
1831 if (window_hint)1957 if (desktop_file_hint)
1832 set_window_hint (window, _NET_WM_DESKTOP_FILE, window_hint);1958 set_window_hint (window, _NET_WM_DESKTOP_FILE, desktop_file_hint);
1833}1959}
18341960
1835static void1961static void
@@ -1895,13 +2021,6 @@
1895 g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (window), NULL);2021 g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (window), NULL);
18962022
1897 role = get_window_hint (window, WM_WINDOW_ROLE);2023 role = get_window_hint (window, WM_WINDOW_ROLE);
1898
1899 if (role && role[0] == '\0')
1900 {
1901 g_free (role);
1902 role = NULL;
1903 }
1904
1905 exec = g_strconcat ("gnome-control-center", (role ? " " : NULL), role, NULL);2024 exec = g_strconcat ("gnome-control-center", (role ? " " : NULL), role, NULL);
19062025
1907 desktopFileTable = self->priv->desktop_file_table;2026 desktopFileTable = self->priv->desktop_file_table;
@@ -2013,15 +2132,11 @@
2013bamf_matcher_setup_indicator_state (BamfMatcher *self, BamfIndicator *indicator)2132bamf_matcher_setup_indicator_state (BamfMatcher *self, BamfIndicator *indicator)
2014{2133{
2015 GList *possible_apps, *l;2134 GList *possible_apps, *l;
2016 GList *views, *a;
2017 const char *desktop_file;2135 const char *desktop_file;
2018 BamfApplication *app = NULL, *best = NULL;2136 BamfApplication *app = NULL, *best = NULL;
2019 BamfView *view;
20202137
2021 g_return_if_fail (BAMF_IS_MATCHER (self));2138 g_return_if_fail (BAMF_IS_MATCHER (self));
2022 g_return_if_fail (BAMF_IS_INDICATOR (indicator));2139 g_return_if_fail (BAMF_IS_INDICATOR (indicator));
2023
2024 views = self->priv->views;
20252140
2026 possible_apps = bamf_matcher_possible_applications_for_pid (self, bamf_indicator_get_pid (indicator));2141 possible_apps = bamf_matcher_possible_applications_for_pid (self, bamf_indicator_get_pid (indicator));
20272142
@@ -2029,27 +2144,17 @@
2029 * matches with any of our possible hits. If so we match it. If we have no possible hits2144 * matches with any of our possible hits. If so we match it. If we have no possible hits
2030 * fall back to secondary matching. 2145 * fall back to secondary matching.
2031 */2146 */
2032 for (a = views; a && !best; a = a->next)2147 if (possible_apps)
2033 {2148 {
2034 view = a->data;2149 for (l = possible_apps; l; l = l->next)
2035
2036 if (!BAMF_IS_APPLICATION (view))
2037 continue;
2038
2039 app = BAMF_APPLICATION (view);
2040 desktop_file = bamf_application_get_desktop_file (app);
2041
2042 if (possible_apps)
2043 {2150 {
2044 /* primary matching */2151 desktop_file = l->data;
2152 app = bamf_matcher_get_application_by_desktop_file (self, desktop_file);
20452153
2046 for (l = possible_apps; l; l = l->next)2154 if (BAMF_IS_APPLICATION (app))
2047 {2155 {
2048 if (g_strcmp0 (desktop_file, l->data) == 0)2156 best = app;
2049 {2157 break;
2050 best = app;
2051 break;
2052 }
2053 }2158 }
2054 }2159 }
2055 }2160 }
@@ -2270,6 +2375,7 @@
2270 }2375 }
2271 }2376 }
22722377
2378 g_list_free (windows);
2273 g_variant_builder_close (&b);2379 g_variant_builder_close (&b);
22742380
2275 return g_variant_builder_end (&b);2381 return g_variant_builder_end (&b);
@@ -2279,27 +2385,15 @@
2279bamf_matcher_application_is_running (BamfMatcher *matcher,2385bamf_matcher_application_is_running (BamfMatcher *matcher,
2280 const char *application)2386 const char *application)
2281{2387{
2282 const char * desktop_file;2388 BamfApplication *app;
2283 GList *l;
2284 BamfView *view;
2285 BamfMatcherPrivate *priv;
22862389
2287 g_return_val_if_fail (BAMF_IS_MATCHER (matcher), FALSE);2390 g_return_val_if_fail (BAMF_IS_MATCHER (matcher), FALSE);
22882391
2289 priv = matcher->priv;2392 app = bamf_matcher_get_application_by_desktop_file (matcher, application);
22902393
2291 for (l = priv->views; l; l = l->next)2394 if (BAMF_IS_APPLICATION (app))
2292 {2395 {
2293 view = l->data;2396 return bamf_view_is_running (BAMF_VIEW (app));
2294
2295 if (!BAMF_IS_APPLICATION (view))
2296 continue;
2297
2298 desktop_file = bamf_application_get_desktop_file (BAMF_APPLICATION (view));
2299 if (g_strcmp0 (desktop_file, application) == 0)
2300 {
2301 return bamf_view_is_running (view);
2302 }
2303 }2397 }
23042398
2305 return FALSE;2399 return FALSE;
@@ -2370,27 +2464,15 @@
2370 const char *application)2464 const char *application)
2371{2465{
2372 const char * path = "";2466 const char * path = "";
2373 const char * desktop_file;2467 BamfApplication *app;
2374 GList *l;
2375 BamfView *view;
2376 BamfMatcherPrivate *priv;
23772468
2378 g_return_val_if_fail (BAMF_IS_MATCHER (matcher), NULL);2469 g_return_val_if_fail (BAMF_IS_MATCHER (matcher), NULL);
23792470
2380 priv = matcher->priv;2471 app = bamf_matcher_get_application_by_desktop_file (matcher, application);
23812472
2382 for (l = priv->views; l; l = l->next)2473 if (BAMF_IS_APPLICATION (app))
2383 {2474 {
2384 view = l->data;2475 return bamf_view_get_path (BAMF_VIEW (app));
2385
2386 if (!BAMF_IS_APPLICATION (view))
2387 continue;
2388
2389 desktop_file = bamf_application_get_desktop_file (BAMF_APPLICATION (view));
2390 if (g_strcmp0 (desktop_file, application) == 0)
2391 {
2392 path = bamf_view_get_path (view);
2393 }
2394 }2476 }
23952477
2396 return path;2478 return path;
@@ -2530,29 +2612,16 @@
2530{2612{
2531 GVariantBuilder b;2613 GVariantBuilder b;
2532 GVariant *xids;2614 GVariant *xids;
2533 const char * desktop_file;2615 BamfApplication *app;
2534 GList *l;
2535 BamfView *view;
2536 BamfMatcherPrivate *priv;
25372616
2538 g_return_val_if_fail (BAMF_IS_MATCHER (matcher), NULL);2617 g_return_val_if_fail (BAMF_IS_MATCHER (matcher), NULL);
25392618
2540 priv = matcher->priv;
2541 xids = NULL;2619 xids = NULL;
2620 app = bamf_matcher_get_application_by_desktop_file (matcher, application);
25422621
2543 for (l = priv->views; l; l = l->next)2622 if (BAMF_IS_APPLICATION (app))
2544 {2623 {
2545 view = l->data;2624 xids = bamf_application_get_xids (app);
2546
2547 if (!BAMF_IS_APPLICATION (view))
2548 continue;
2549
2550 desktop_file = bamf_application_get_desktop_file (BAMF_APPLICATION (view));
2551 if (g_strcmp0 (desktop_file, application) == 0)
2552 {
2553 xids = bamf_application_get_xids (BAMF_APPLICATION (view));
2554 break;
2555 }
2556 }2625 }
25572626
2558 if (!xids)2627 if (!xids)
25592628
=== modified file 'src/bamf-view.c'
--- src/bamf-view.c 2012-03-16 19:39:34 +0000
+++ src/bamf-view.c 2012-04-20 17:39:18 +0000
@@ -465,7 +465,9 @@
465465
466 ifaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (view));466 ifaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (view));
467467
468 for (l = ifaces; l; l = l->next)468 /* The dbus object interface list is in reversed order, we try to export
469 * the interfaces in bottom to top order (BamfView should be the first) */
470 for (l = g_list_last(ifaces); l; l = l->prev)
469 {471 {
470 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (l->data),472 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (l->data),
471 connection, path, &error);473 connection, path, &error);
472474
=== modified file 'src/bamf-xutils.c'
--- src/bamf-xutils.c 2012-02-10 20:05:54 +0000
+++ src/bamf-xutils.c 2012-04-20 17:39:18 +0000
@@ -21,6 +21,29 @@
21#include "bamf-xutils.h"21#include "bamf-xutils.h"
22#include <string.h>22#include <string.h>
2323
24static Display *
25get_xdisplay (gboolean *opened)
26{
27 Display *xdisplay;
28 xdisplay = gdk_x11_get_default_xdisplay ();
29
30 if (opened)
31 *opened = FALSE;
32
33 if (!xdisplay)
34 {
35 xdisplay = XOpenDisplay (NULL);
36
37 if (xdisplay)
38 {
39 if (opened)
40 *opened = TRUE;
41 }
42 }
43
44 return xdisplay;
45}
46
24char *47char *
25bamf_xutils_get_window_hint (Window xid, const char *atom_name, Atom type)48bamf_xutils_get_window_hint (Window xid, const char *atom_name, Atom type)
26{49{
@@ -32,22 +55,17 @@
32 gulong numItems;55 gulong numItems;
33 gulong bytesAfter;56 gulong bytesAfter;
34 unsigned char *buffer;57 unsigned char *buffer;
35 gboolean close_display = TRUE;58 gboolean close_display = FALSE;
3659
37 g_return_val_if_fail ((xid != 0), NULL);60 g_return_val_if_fail ((xid != 0), NULL);
38 g_return_val_if_fail (atom_name, NULL);61 g_return_val_if_fail (atom_name, NULL);
3962
40 XDisplay = XOpenDisplay (NULL);63 XDisplay = get_xdisplay (&close_display);
64
41 if (!XDisplay)65 if (!XDisplay)
42 {66 {
43 XDisplay = gdk_x11_get_default_xdisplay ();67 g_warning ("%s: Unable to get a valid XDisplay", G_STRFUNC);
44 if (!XDisplay)68 return NULL;
45 {
46 g_warning ("%s: Unable to get a valid XDisplay", G_STRFUNC);
47 return hint;
48 }
49
50 close_display = FALSE;
51 }69 }
5270
53 atom = XInternAtom (XDisplay, atom_name, FALSE);71 atom = XInternAtom (XDisplay, atom_name, FALSE);
@@ -70,7 +88,9 @@
7088
71 if (result == Success && numItems > 0)89 if (result == Success && numItems > 0)
72 {90 {
73 hint = g_strdup ((char*) buffer);91 if (buffer && buffer[0] != '\0')
92 hint = g_strdup ((char*) buffer);
93
74 XFree (buffer);94 XFree (buffer);
75 }95 }
7696
@@ -81,22 +101,18 @@
81bamf_xutils_set_window_hint (Window xid, const char *atom_name, Atom type, const char *data)101bamf_xutils_set_window_hint (Window xid, const char *atom_name, Atom type, const char *data)
82{102{
83 Display *XDisplay;103 Display *XDisplay;
84 gboolean close_display = TRUE;104 gboolean close_display = FALSE;
85105
86 g_return_if_fail (xid != 0);106 g_return_if_fail (xid != 0);
87 g_return_if_fail (atom_name);107 g_return_if_fail (atom_name);
88 g_return_if_fail (data);108 g_return_if_fail (data);
89 109
90 XDisplay = XOpenDisplay (NULL);110 XDisplay = get_xdisplay (&close_display);
111
91 if (!XDisplay)112 if (!XDisplay)
92 {113 {
93 XDisplay = gdk_x11_get_default_xdisplay ();114 g_warning ("%s: Unable to get a valid XDisplay", G_STRFUNC);
94 if (!XDisplay)115 return;
95 {
96 g_warning ("%s: Unable to get a valid XDisplay", G_STRFUNC);
97 return;
98 }
99 close_display = FALSE;
100 }116 }
101117
102 XChangeProperty (XDisplay,118 XChangeProperty (XDisplay,
@@ -113,3 +129,35 @@
113 if (close_display)129 if (close_display)
114 XCloseDisplay (XDisplay);130 XCloseDisplay (XDisplay);
115}131}
132
133void
134bamf_xutils_get_window_class_hints (Window xid, char **class_instance_name, char **class_name)
135{
136 Display *xdisplay;
137 gboolean close_display = FALSE;
138
139 xdisplay = get_xdisplay (&close_display);
140
141 if (!xdisplay)
142 {
143 g_warning ("%s: Unable to get a valid XDisplay", G_STRFUNC);
144 return;
145 }
146
147 XClassHint class_hint;
148 class_hint.res_name = NULL;
149 class_hint.res_class = NULL;
150
151 XGetClassHint(xdisplay, xid, &class_hint);
152
153 if (class_name && class_hint.res_class && class_hint.res_class[0] != 0)
154 *class_name = g_convert (class_hint.res_class, -1, "utf-8", "iso-8859-1",
155 NULL, NULL, NULL);
156
157 if (class_instance_name && class_hint.res_name && class_hint.res_name[0] != 0)
158 *class_instance_name = g_convert (class_hint.res_name, -1, "utf-8", "iso-8859-1",
159 NULL, NULL, NULL);
160
161 XFree (class_hint.res_class);
162 XFree (class_hint.res_name);
163}
116164
=== modified file 'src/bamf-xutils.h'
--- src/bamf-xutils.h 2012-02-10 20:05:54 +0000
+++ src/bamf-xutils.h 2012-04-20 17:39:18 +0000
@@ -18,8 +18,8 @@
18 */18 */
1919
2020
21#ifndef __BAMFXUTILS_H__21#ifndef __BAMF_XUTILS_H__
22#define __BAMFXUTILS_H__22#define __BAMF_XUTILS_H__
2323
24#include <glib.h>24#include <glib.h>
25#include <X11/Xatom.h>25#include <X11/Xatom.h>
@@ -29,4 +29,6 @@
29void bamf_xutils_set_window_hint (Window xid, const char *atom_name, Atom type, const char *data);29void bamf_xutils_set_window_hint (Window xid, const char *atom_name, Atom type, const char *data);
30char* bamf_xutils_get_window_hint (Window xid, const char *atom_name, Atom type);30char* bamf_xutils_get_window_hint (Window xid, const char *atom_name, Atom type);
3131
32void bamf_xutils_get_window_class_hints (Window xid, char **class_instance_name, char **class_name);
33
32#endif34#endif

Subscribers

People subscribed via source and target branches