Allow window matching based on the group leader's name and class (Fix bug 5721)
In Openbox 3.4 we used the group leader's WM_CLASS value when it was available. This prevents windows in the group from overriding with a specific value, however which is bad. More rationale can be found in http://icculus.org/pipermail/openbox/2010-September/006790.html Some applications (eg. Firefox) use command line flags to set the WM_CLASS property on the group leader but do not change the property on the mapped windows themselves. This makes matching these windows not possible in Openbox 3.5. We resolve this by exposing the group's WM_CLASS values alongside the individual window's values. We add _OB_APP_GROUP_NAME and _OB_APP_GROUP_CLASS properties along with "groupname" and "classname" attributes for the rc.xml application tag.
This commit is contained in:
parent
51d735672c
commit
6eb740cf11
8 changed files with 71 additions and 6 deletions
|
@ -652,6 +652,8 @@
|
||||||
|
|
||||||
<application name="the window's _OB_APP_NAME property (see obxprop)"
|
<application name="the window's _OB_APP_NAME property (see obxprop)"
|
||||||
class="the window's _OB_APP_CLASS property (see obxprop)"
|
class="the window's _OB_APP_CLASS property (see obxprop)"
|
||||||
|
groupname="the window's _OB_APP_GROUP_NAME property (see obxprop)"
|
||||||
|
groupclass="the window's _OB_APP_GROUP_CLASS property (see obxprop)"
|
||||||
role="the window's _OB_APP_ROLE property (see obxprop)"
|
role="the window's _OB_APP_ROLE property (see obxprop)"
|
||||||
title="the window's _OB_APP_TITLE property (see obxprop)"
|
title="the window's _OB_APP_TITLE property (see obxprop)"
|
||||||
type="the window's _OB_APP_TYPE property (see obxprob)..
|
type="the window's _OB_APP_TYPE property (see obxprob)..
|
||||||
|
|
|
@ -197,6 +197,8 @@ void obt_prop_startup(void)
|
||||||
CREATE_(OB_APP_TITLE);
|
CREATE_(OB_APP_TITLE);
|
||||||
CREATE_(OB_APP_NAME);
|
CREATE_(OB_APP_NAME);
|
||||||
CREATE_(OB_APP_CLASS);
|
CREATE_(OB_APP_CLASS);
|
||||||
|
CREATE_(OB_APP_GROUP_NAME);
|
||||||
|
CREATE_(OB_APP_GROUP_CLASS);
|
||||||
CREATE_(OB_APP_TYPE);
|
CREATE_(OB_APP_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -219,6 +219,8 @@ typedef enum {
|
||||||
OBT_PROP_OB_APP_TITLE,
|
OBT_PROP_OB_APP_TITLE,
|
||||||
OBT_PROP_OB_APP_NAME,
|
OBT_PROP_OB_APP_NAME,
|
||||||
OBT_PROP_OB_APP_CLASS,
|
OBT_PROP_OB_APP_CLASS,
|
||||||
|
OBT_PROP_OB_APP_GROUP_NAME,
|
||||||
|
OBT_PROP_OB_APP_GROUP_CLASS,
|
||||||
OBT_PROP_OB_APP_TYPE,
|
OBT_PROP_OB_APP_TYPE,
|
||||||
|
|
||||||
OBT_PROP_NUM_ATOMS
|
OBT_PROP_NUM_ATOMS
|
||||||
|
|
|
@ -250,6 +250,8 @@ void client_manage(Window window, ObPrompt *prompt)
|
||||||
ob_debug("Window group: 0x%x", self->group?self->group->leader:0);
|
ob_debug("Window group: 0x%x", self->group?self->group->leader:0);
|
||||||
ob_debug("Window name: %s class: %s role: %s title: %s",
|
ob_debug("Window name: %s class: %s role: %s title: %s",
|
||||||
self->name, self->class, self->role, self->title);
|
self->name, self->class, self->role, self->title);
|
||||||
|
ob_debug("Window group name: %s group class: %s",
|
||||||
|
self->group_name, self->group_class);
|
||||||
|
|
||||||
/* per-app settings override stuff from client_get_all, and return the
|
/* per-app settings override stuff from client_get_all, and return the
|
||||||
settings for other uses too. the returned settings is a shallow copy,
|
settings for other uses too. the returned settings is a shallow copy,
|
||||||
|
@ -723,6 +725,8 @@ void client_unmanage(ObClient *self)
|
||||||
g_free(self->name);
|
g_free(self->name);
|
||||||
g_free(self->class);
|
g_free(self->class);
|
||||||
g_free(self->role);
|
g_free(self->role);
|
||||||
|
g_free(self->group_name);
|
||||||
|
g_free(self->group_class);
|
||||||
g_free(self->client_machine);
|
g_free(self->client_machine);
|
||||||
g_free(self->sm_client_id);
|
g_free(self->sm_client_id);
|
||||||
g_slice_free(ObClient, self);
|
g_slice_free(ObClient, self);
|
||||||
|
@ -915,15 +919,25 @@ static ObAppSettings *client_get_settings_state(ObClient *self)
|
||||||
|
|
||||||
g_assert(app->name != NULL || app->class != NULL ||
|
g_assert(app->name != NULL || app->class != NULL ||
|
||||||
app->role != NULL || app->title != NULL ||
|
app->role != NULL || app->title != NULL ||
|
||||||
|
app->group_name != NULL || app->group_class != NULL ||
|
||||||
(signed)app->type >= 0);
|
(signed)app->type >= 0);
|
||||||
|
|
||||||
if (app->name &&
|
if (app->name &&
|
||||||
!g_pattern_match(app->name, strlen(self->name), self->name, NULL))
|
!g_pattern_match(app->name, strlen(self->name), self->name, NULL))
|
||||||
match = FALSE;
|
match = FALSE;
|
||||||
|
else if (app->group_name &&
|
||||||
|
!g_pattern_match(app->group_name,
|
||||||
|
strlen(self->group_name), self->group_name, NULL))
|
||||||
|
match = FALSE;
|
||||||
else if (app->class &&
|
else if (app->class &&
|
||||||
!g_pattern_match(app->class,
|
!g_pattern_match(app->class,
|
||||||
strlen(self->class), self->class, NULL))
|
strlen(self->class), self->class, NULL))
|
||||||
match = FALSE;
|
match = FALSE;
|
||||||
|
else if (app->group_class &&
|
||||||
|
!g_pattern_match(app->group_class,
|
||||||
|
strlen(self->group_class), self->group_class,
|
||||||
|
NULL))
|
||||||
|
match = FALSE;
|
||||||
else if (app->role &&
|
else if (app->role &&
|
||||||
!g_pattern_match(app->role,
|
!g_pattern_match(app->role,
|
||||||
strlen(self->role), self->role, NULL))
|
strlen(self->role), self->role, NULL))
|
||||||
|
@ -2365,6 +2379,25 @@ static void client_get_session_ids(ObClient *self)
|
||||||
if (self->name == NULL) self->name = g_strdup("");
|
if (self->name == NULL) self->name = g_strdup("");
|
||||||
if (self->class == NULL) self->class = g_strdup("");
|
if (self->class == NULL) self->class = g_strdup("");
|
||||||
|
|
||||||
|
/* get the WM_CLASS (name and class) from the group leader. make them "" if
|
||||||
|
they are not provided */
|
||||||
|
if (leader)
|
||||||
|
got = OBT_PROP_GETSS_TYPE(leader, WM_CLASS, STRING_NO_CC, &ss);
|
||||||
|
else
|
||||||
|
got = FALSE;
|
||||||
|
|
||||||
|
if (got) {
|
||||||
|
if (ss[0]) {
|
||||||
|
self->group_name = g_strdup(ss[0]);
|
||||||
|
if (ss[1])
|
||||||
|
self->group_class = g_strdup(ss[1]);
|
||||||
|
}
|
||||||
|
g_strfreev(ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->group_name == NULL) self->group_name = g_strdup("");
|
||||||
|
if (self->group_class == NULL) self->group_class = g_strdup("");
|
||||||
|
|
||||||
/* get the WM_WINDOW_ROLE. make it "" if it is not provided */
|
/* get the WM_WINDOW_ROLE. make it "" if it is not provided */
|
||||||
got = OBT_PROP_GETS_XPCS(self->window, WM_WINDOW_ROLE, &s);
|
got = OBT_PROP_GETS_XPCS(self->window, WM_WINDOW_ROLE, &s);
|
||||||
|
|
||||||
|
@ -2434,6 +2467,8 @@ static void client_save_app_rule_values(ObClient *self)
|
||||||
OBT_PROP_SETS(self->window, OB_APP_ROLE, self->role);
|
OBT_PROP_SETS(self->window, OB_APP_ROLE, self->role);
|
||||||
OBT_PROP_SETS(self->window, OB_APP_NAME, self->name);
|
OBT_PROP_SETS(self->window, OB_APP_NAME, self->name);
|
||||||
OBT_PROP_SETS(self->window, OB_APP_CLASS, self->class);
|
OBT_PROP_SETS(self->window, OB_APP_CLASS, self->class);
|
||||||
|
OBT_PROP_SETS(self->window, OB_APP_GROUP_NAME, self->group_name);
|
||||||
|
OBT_PROP_SETS(self->window, OB_APP_GROUP_CLASS, self->group_class);
|
||||||
OBT_PROP_SETS(self->window, OB_APP_TITLE, self->original_title);
|
OBT_PROP_SETS(self->window, OB_APP_TITLE, self->original_title);
|
||||||
|
|
||||||
switch (self->type) {
|
switch (self->type) {
|
||||||
|
|
|
@ -127,6 +127,10 @@ struct _ObClient
|
||||||
gchar *class;
|
gchar *class;
|
||||||
/*! The specified role of the window, used for identification */
|
/*! The specified role of the window, used for identification */
|
||||||
gchar *role;
|
gchar *role;
|
||||||
|
/*! The application that created the window's group. */
|
||||||
|
gchar *group_name;
|
||||||
|
/*! The class of the window's group, can used for grouping */
|
||||||
|
gchar *group_class;
|
||||||
/*! The session client id for the window. *This can be NULL!* */
|
/*! The session client id for the window. *This can be NULL!* */
|
||||||
gchar *sm_client_id;
|
gchar *sm_client_id;
|
||||||
|
|
||||||
|
|
|
@ -215,8 +215,9 @@ static void parse_per_app_settings(xmlNodePtr node, gpointer d)
|
||||||
{
|
{
|
||||||
xmlNodePtr app = obt_xml_find_node(node->children, "application");
|
xmlNodePtr app = obt_xml_find_node(node->children, "application");
|
||||||
gchar *name = NULL, *class = NULL, *role = NULL, *title = NULL,
|
gchar *name = NULL, *class = NULL, *role = NULL, *title = NULL,
|
||||||
*type_str = NULL;
|
*type_str = NULL, *group_name = NULL, *group_class = NULL;
|
||||||
gboolean name_set, class_set, type_set, role_set, title_set;
|
gboolean name_set, class_set, type_set, role_set, title_set,
|
||||||
|
group_name_set, group_class_set;
|
||||||
ObClientType type;
|
ObClientType type;
|
||||||
gboolean x_pos_given;
|
gboolean x_pos_given;
|
||||||
|
|
||||||
|
@ -225,6 +226,8 @@ static void parse_per_app_settings(xmlNodePtr node, gpointer d)
|
||||||
|
|
||||||
class_set = obt_xml_attr_string(app, "class", &class);
|
class_set = obt_xml_attr_string(app, "class", &class);
|
||||||
name_set = obt_xml_attr_string(app, "name", &name);
|
name_set = obt_xml_attr_string(app, "name", &name);
|
||||||
|
group_class_set = obt_xml_attr_string(app, "groupclass", &group_class);
|
||||||
|
group_name_set = obt_xml_attr_string(app, "groupname", &group_name);
|
||||||
type_set = obt_xml_attr_string(app, "type", &type_str);
|
type_set = obt_xml_attr_string(app, "type", &type_str);
|
||||||
role_set = obt_xml_attr_string(app, "role", &role);
|
role_set = obt_xml_attr_string(app, "role", &role);
|
||||||
title_set = obt_xml_attr_string(app, "title", &title);
|
title_set = obt_xml_attr_string(app, "title", &title);
|
||||||
|
@ -251,7 +254,9 @@ static void parse_per_app_settings(xmlNodePtr node, gpointer d)
|
||||||
type_set = FALSE; /* not valid! */
|
type_set = FALSE; /* not valid! */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (class_set || name_set || role_set || title_set || type_set) {
|
if (class_set || name_set || role_set || title_set || type_set ||
|
||||||
|
group_class_set || group_name_set)
|
||||||
|
{
|
||||||
xmlNodePtr n, c;
|
xmlNodePtr n, c;
|
||||||
ObAppSettings *settings = config_create_app_settings();
|
ObAppSettings *settings = config_create_app_settings();
|
||||||
|
|
||||||
|
@ -261,6 +266,12 @@ static void parse_per_app_settings(xmlNodePtr node, gpointer d)
|
||||||
if (class_set)
|
if (class_set)
|
||||||
settings->class = g_pattern_spec_new(class);
|
settings->class = g_pattern_spec_new(class);
|
||||||
|
|
||||||
|
if (group_name_set)
|
||||||
|
settings->group_name = g_pattern_spec_new(group_name);
|
||||||
|
|
||||||
|
if (group_class_set)
|
||||||
|
settings->group_class = g_pattern_spec_new(group_class);
|
||||||
|
|
||||||
if (role_set)
|
if (role_set)
|
||||||
settings->role = g_pattern_spec_new(role);
|
settings->role = g_pattern_spec_new(role);
|
||||||
|
|
||||||
|
@ -377,10 +388,13 @@ static void parse_per_app_settings(xmlNodePtr node, gpointer d)
|
||||||
(gpointer) settings);
|
(gpointer) settings);
|
||||||
g_free(name);
|
g_free(name);
|
||||||
g_free(class);
|
g_free(class);
|
||||||
|
g_free(group_name);
|
||||||
|
g_free(group_class);
|
||||||
g_free(role);
|
g_free(role);
|
||||||
g_free(title);
|
g_free(title);
|
||||||
g_free(type_str);
|
g_free(type_str);
|
||||||
name = class = role = title = type_str = NULL;
|
name = class = group_name = group_class = role = title = type_str =
|
||||||
|
NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
app = obt_xml_find_node(app->next, "application");
|
app = obt_xml_find_node(app->next, "application");
|
||||||
|
@ -1132,10 +1146,12 @@ void config_shutdown(void)
|
||||||
|
|
||||||
for (it = config_per_app_settings; it; it = g_slist_next(it)) {
|
for (it = config_per_app_settings; it; it = g_slist_next(it)) {
|
||||||
ObAppSettings *itd = (ObAppSettings *)it->data;
|
ObAppSettings *itd = (ObAppSettings *)it->data;
|
||||||
if (itd->name) g_pattern_spec_free(itd->name);
|
if (itd->name) g_pattern_spec_free(itd->name);
|
||||||
if (itd->role) g_pattern_spec_free(itd->role);
|
if (itd->role) g_pattern_spec_free(itd->role);
|
||||||
if (itd->title) g_pattern_spec_free(itd->title);
|
if (itd->title) g_pattern_spec_free(itd->title);
|
||||||
if (itd->class) g_pattern_spec_free(itd->class);
|
if (itd->class) g_pattern_spec_free(itd->class);
|
||||||
|
if (itd->group_name) g_pattern_spec_free(itd->group_name);
|
||||||
|
if (itd->group_class) g_pattern_spec_free(itd->group_class);
|
||||||
g_slice_free(ObAppSettings, it->data);
|
g_slice_free(ObAppSettings, it->data);
|
||||||
}
|
}
|
||||||
g_slist_free(config_per_app_settings);
|
g_slist_free(config_per_app_settings);
|
||||||
|
|
|
@ -38,6 +38,8 @@ struct _ObAppSettings
|
||||||
GPatternSpec *class;
|
GPatternSpec *class;
|
||||||
GPatternSpec *name;
|
GPatternSpec *name;
|
||||||
GPatternSpec *role;
|
GPatternSpec *role;
|
||||||
|
GPatternSpec *group_class;
|
||||||
|
GPatternSpec *group_name;
|
||||||
GPatternSpec *title;
|
GPatternSpec *title;
|
||||||
ObClientType type;
|
ObClientType type;
|
||||||
|
|
||||||
|
|
|
@ -305,6 +305,8 @@ gboolean screen_annex(void)
|
||||||
supported[i++] = OBT_PROP_ATOM(OB_APP_TITLE);
|
supported[i++] = OBT_PROP_ATOM(OB_APP_TITLE);
|
||||||
supported[i++] = OBT_PROP_ATOM(OB_APP_NAME);
|
supported[i++] = OBT_PROP_ATOM(OB_APP_NAME);
|
||||||
supported[i++] = OBT_PROP_ATOM(OB_APP_CLASS);
|
supported[i++] = OBT_PROP_ATOM(OB_APP_CLASS);
|
||||||
|
supported[i++] = OBT_PROP_ATOM(OB_APP_GROUP_NAME);
|
||||||
|
supported[i++] = OBT_PROP_ATOM(OB_APP_GROUP_CLASS);
|
||||||
supported[i++] = OBT_PROP_ATOM(OB_APP_TYPE);
|
supported[i++] = OBT_PROP_ATOM(OB_APP_TYPE);
|
||||||
g_assert(i == num_support);
|
g_assert(i == num_support);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue