use simple pattern matching for per-app settings. all rules that match are applied to a window rather than just the first
This commit is contained in:
parent
add9c3c1bb
commit
fd8ce9414a
6 changed files with 129 additions and 55 deletions
13
data/rc.xml
13
data/rc.xml
|
@ -506,11 +506,15 @@
|
|||
want to use it -->
|
||||
<applications>
|
||||
<!-- the name or the class can be set, or both. this is used to match
|
||||
windows when they appear
|
||||
windows when they appear. role can optionally be set as well, to
|
||||
further restrict your matches
|
||||
|
||||
role can optionally be set, and only as much as you provide will be
|
||||
checked to see if it matches, eg. if you set role="abc" and the window's
|
||||
role is actually "abcde" it would match.
|
||||
the name, class, and role use simple globbing rules such as those
|
||||
used by a shell. you can use * to match any characters and ? to match
|
||||
any single character.
|
||||
|
||||
when multiple rules match a window, they will all be applied, in the
|
||||
order that they appear in this list
|
||||
-->
|
||||
<application name="first element of window's WM_CLASS property (see xprop)"
|
||||
class="second element of window's WM_CLASS property (see xprop)"
|
||||
|
@ -520,6 +524,7 @@
|
|||
change that attribute of the window -->
|
||||
|
||||
<decor>yes</decor>
|
||||
<!-- enable or disable window decorations -->
|
||||
|
||||
<shade>no</shade>
|
||||
|
||||
|
|
|
@ -153,6 +153,7 @@
|
|||
<xsd:complexType name="window_position">
|
||||
<xsd:element name="x" type="ob:center_or_int"/>
|
||||
<xsd:element name="y" type="ob:center_or_int"/>
|
||||
<xsd:element name="monitor" type="ob:mouse_or_int"/>
|
||||
<xsd:element minOccurs="0" name="head" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="application">
|
||||
|
@ -330,6 +331,13 @@
|
|||
<xsd:pattern value="center|0|[1-9][0-9]*"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="mouse_or_int">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<!-- ob: atoi($_) unless $_ eq 'center'; -->
|
||||
<!-- I think the regexp DTRT WRT atoi. -->
|
||||
<xsd:pattern value="mouse|0|[1-9][0-9]*"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="contextname">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="Desktop"/>
|
||||
|
|
|
@ -314,7 +314,8 @@ void client_manage(Window window)
|
|||
grab_server(FALSE);
|
||||
|
||||
/* per-app settings override stuff from client_get_all, and return the
|
||||
settings for other uses too */
|
||||
settings for other uses too. the returned settings is a shallow copy,
|
||||
that needs to be freed with g_free(). */
|
||||
settings = client_get_settings_state(self);
|
||||
/* the session should get the last say thought */
|
||||
client_restore_session_state(self);
|
||||
|
@ -506,6 +507,9 @@ void client_manage(Window window)
|
|||
/* update the list hints */
|
||||
client_set_list();
|
||||
|
||||
/* free the ObAppSettings shallow copy */
|
||||
g_free(settings);
|
||||
|
||||
ob_debug("Managed window 0x%lx plate 0x%x (%s)\n",
|
||||
window, self->frame->plate, self->class);
|
||||
|
||||
|
@ -527,7 +531,7 @@ ObClient *client_fake_manage(Window window)
|
|||
|
||||
client_get_all(self, FALSE);
|
||||
/* per-app settings override stuff, and return the settings for other
|
||||
uses too */
|
||||
uses too. this returns a shallow copy that needs to be freed */
|
||||
settings = client_get_settings_state(self);
|
||||
|
||||
client_setup_decor_and_functions(self);
|
||||
|
@ -535,6 +539,10 @@ ObClient *client_fake_manage(Window window)
|
|||
/* create the decoration frame for the client window and adjust its size */
|
||||
self->frame = frame_new(self);
|
||||
frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
|
||||
|
||||
/* free the ObAppSettings shallow copy */
|
||||
g_free(settings);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -694,30 +702,39 @@ void client_fake_unmanage(ObClient *self)
|
|||
g_free(self);
|
||||
}
|
||||
|
||||
/*! Returns a new structure containing the per-app settings for this client.
|
||||
The returned structure needs to be freed with g_free. */
|
||||
static ObAppSettings *client_get_settings_state(ObClient *self)
|
||||
{
|
||||
ObAppSettings *settings = NULL;
|
||||
ObAppSettings *settings;
|
||||
GSList *it;
|
||||
|
||||
settings = config_create_app_settings();
|
||||
|
||||
for (it = config_per_app_settings; it; it = g_slist_next(it)) {
|
||||
ObAppSettings *app = it->data;
|
||||
|
||||
if ((app->name && !app->class && !strcmp(app->name, self->name))
|
||||
|| (app->class && !app->name && !strcmp(app->class, self->class))
|
||||
|| (app->class && app->name && !strcmp(app->class, self->class)
|
||||
&& !strcmp(app->name, self->name)))
|
||||
{
|
||||
/* Match if no role was specified in the per app setting, or if the
|
||||
* string matches the beginning of the role, since apps like to set
|
||||
* the role to things like browser-window-23c4b2f */
|
||||
if (!app->role
|
||||
|| !strncmp(app->role, self->role, strlen(app->role)))
|
||||
{
|
||||
ob_debug("Window matching: %s\n", app->name);
|
||||
/* use this one */
|
||||
settings = app;
|
||||
break;
|
||||
}
|
||||
gboolean match = TRUE;
|
||||
|
||||
g_assert(app->name != NULL || app->class != NULL);
|
||||
|
||||
/* we know that either name or class is not NULL so it will have to
|
||||
match to use the rule */
|
||||
if (app->name &&
|
||||
!g_pattern_match(app->name, strlen(self->name), self->name, NULL))
|
||||
match = FALSE;
|
||||
if (app->class &&
|
||||
!g_pattern_match(app->class, strlen(self->class),self->class,NULL))
|
||||
match = FALSE;
|
||||
if (app->role &&
|
||||
!g_pattern_match(app->role, strlen(self->role), self->role, NULL))
|
||||
match = FALSE;
|
||||
|
||||
if (match) {
|
||||
ob_debug("Window matching: %s\n", app->name);
|
||||
|
||||
/* copy the settings to our struct, overriding the existing
|
||||
settings if they are not defaults */
|
||||
config_app_settings_copy_non_defaults(app, settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ struct _ObSessionState;
|
|||
|
||||
typedef struct _ObClient ObClient;
|
||||
typedef struct _ObClientIcon ObClientIcon;
|
||||
typedef struct _ObAppSettings ObAppSettings;
|
||||
|
||||
/* The value in client.transient_for indicating it is a transient for its
|
||||
group instead of for a single window */
|
||||
|
|
|
@ -89,6 +89,54 @@ gint config_resist_edge;
|
|||
|
||||
GSList *config_per_app_settings;
|
||||
|
||||
ObAppSettings* config_create_app_settings()
|
||||
{
|
||||
ObAppSettings *settings = g_new0(ObAppSettings, 1);
|
||||
settings->decor = -1;
|
||||
settings->shade = -1;
|
||||
settings->monitor = -1;
|
||||
settings->focus = -1;
|
||||
settings->desktop = 0;
|
||||
settings->layer = -2;
|
||||
settings->iconic = -1;
|
||||
settings->skip_pager = -1;
|
||||
settings->skip_taskbar = -1;
|
||||
settings->fullscreen = -1;
|
||||
settings->max_horz = -1;
|
||||
settings->max_vert = -1;
|
||||
return settings;
|
||||
}
|
||||
|
||||
#define copy_if(setting, default) \
|
||||
if (src->setting != default) dst->setting = src->setting
|
||||
void config_app_settings_copy_non_defaults(const ObAppSettings *src,
|
||||
ObAppSettings *dst)
|
||||
{
|
||||
g_assert(src != NULL);
|
||||
g_assert(dst != NULL);
|
||||
|
||||
copy_if(decor, -1);
|
||||
copy_if(shade, -1);
|
||||
copy_if(focus, -1);
|
||||
copy_if(desktop, 0);
|
||||
copy_if(layer, -2);
|
||||
copy_if(iconic, -1);
|
||||
copy_if(skip_pager, -1);
|
||||
copy_if(skip_taskbar, -1);
|
||||
copy_if(fullscreen, -1);
|
||||
copy_if(max_horz, -1);
|
||||
copy_if(max_vert, -1);
|
||||
|
||||
if (src->pos_given) {
|
||||
dst->pos_given = TRUE;
|
||||
dst->center_x = src->center_x;
|
||||
dst->center_y = src->center_y;
|
||||
dst->position.x = src->position.x;
|
||||
dst->position.y = src->position.y;
|
||||
dst->monitor = src->monitor;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
<applications>
|
||||
<application name="aterm">
|
||||
|
@ -121,7 +169,7 @@ static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
|
|||
xmlNodePtr node, gpointer d)
|
||||
{
|
||||
xmlNodePtr app = parse_find_node("application", node->children);
|
||||
gchar *name, *class;
|
||||
gchar *name = NULL, *class = NULL, *role = NULL;
|
||||
gboolean name_set, class_set;
|
||||
gboolean x_pos_given;
|
||||
|
||||
|
@ -132,33 +180,25 @@ static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
|
|||
name_set = parse_attr_string("name", app, &name);
|
||||
if (class_set || name_set) {
|
||||
xmlNodePtr n, c;
|
||||
ObAppSettings *settings = g_new0(ObAppSettings, 1);
|
||||
ObAppSettings *settings = config_create_app_settings();;
|
||||
|
||||
if (name_set)
|
||||
settings->name = name;
|
||||
else
|
||||
settings->name = NULL;
|
||||
settings->name = g_pattern_spec_new(name);
|
||||
|
||||
if (class_set)
|
||||
settings->class = class;
|
||||
else
|
||||
settings->class = NULL;
|
||||
settings->class = g_pattern_spec_new(class);
|
||||
|
||||
if (!parse_attr_string("role", app, &settings->role))
|
||||
settings->role = NULL;
|
||||
if (parse_attr_string("role", app, &role))
|
||||
settings->role = g_pattern_spec_new(role);
|
||||
|
||||
settings->decor = -1;
|
||||
if ((n = parse_find_node("decor", app->children)))
|
||||
if (!parse_contains("default", doc, n))
|
||||
settings->decor = parse_bool(doc, n);
|
||||
|
||||
settings->shade = -1;
|
||||
if ((n = parse_find_node("shade", app->children)))
|
||||
if (!parse_contains("default", doc, n))
|
||||
settings->shade = parse_bool(doc, n);
|
||||
|
||||
settings->position.x = settings->position.y = 0;
|
||||
settings->pos_given = FALSE;
|
||||
if ((n = parse_find_node("position", app->children))) {
|
||||
if ((c = parse_find_node("x", n->children)))
|
||||
if (!parse_contains("default", doc, c)) {
|
||||
|
@ -198,7 +238,6 @@ static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
|
|||
}
|
||||
}
|
||||
|
||||
settings->focus = -1;
|
||||
if ((n = parse_find_node("focus", app->children)))
|
||||
if (!parse_contains("default", doc, n))
|
||||
settings->focus = parse_bool(doc, n);
|
||||
|
@ -214,11 +253,9 @@ static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
|
|||
settings->desktop = i;
|
||||
}
|
||||
g_free(s);
|
||||
} else
|
||||
settings->desktop = 0;
|
||||
}
|
||||
}
|
||||
|
||||
settings->layer = -2;
|
||||
if ((n = parse_find_node("layer", app->children)))
|
||||
if (!parse_contains("default", doc, n)) {
|
||||
gchar *s = parse_string(doc, n);
|
||||
|
@ -231,28 +268,22 @@ static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
|
|||
g_free(s);
|
||||
}
|
||||
|
||||
settings->iconic = -1;
|
||||
if ((n = parse_find_node("iconic", app->children)))
|
||||
if (!parse_contains("default", doc, n))
|
||||
settings->iconic = parse_bool(doc, n);
|
||||
|
||||
settings->skip_pager = -1;
|
||||
if ((n = parse_find_node("skip_pager", app->children)))
|
||||
if (!parse_contains("default", doc, n))
|
||||
settings->skip_pager = parse_bool(doc, n);
|
||||
|
||||
settings->skip_taskbar = -1;
|
||||
if ((n = parse_find_node("skip_taskbar", app->children)))
|
||||
if (!parse_contains("default", doc, n))
|
||||
settings->skip_taskbar = parse_bool(doc, n);
|
||||
|
||||
settings->fullscreen = -1;
|
||||
if ((n = parse_find_node("fullscreen", app->children)))
|
||||
if (!parse_contains("default", doc, n))
|
||||
settings->fullscreen = parse_bool(doc, n);
|
||||
|
||||
settings->max_horz = -1;
|
||||
settings->max_vert = -1;
|
||||
if ((n = parse_find_node("maximized", app->children)))
|
||||
if (!parse_contains("default", doc, n)) {
|
||||
gchar *s = parse_string(doc, n);
|
||||
|
@ -274,6 +305,10 @@ static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
|
|||
|
||||
app = parse_find_node("application", app->next);
|
||||
}
|
||||
|
||||
g_free(name);
|
||||
g_free(class);
|
||||
g_free(role);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -917,9 +952,9 @@ void config_shutdown()
|
|||
|
||||
for (it = config_per_app_settings; it; it = g_slist_next(it)) {
|
||||
ObAppSettings *itd = (ObAppSettings *)it->data;
|
||||
g_free(itd->name);
|
||||
g_free(itd->role);
|
||||
g_free(itd->class);
|
||||
if (itd->name) g_pattern_spec_free(itd->name);
|
||||
if (itd->role) g_pattern_spec_free(itd->role);
|
||||
if (itd->class) g_pattern_spec_free(itd->class);
|
||||
g_free(it->data);
|
||||
}
|
||||
g_slist_free(config_per_app_settings);
|
||||
|
|
|
@ -30,11 +30,13 @@
|
|||
|
||||
struct _ObParseInst;
|
||||
|
||||
typedef struct _ObAppSettings ObAppSettings;
|
||||
|
||||
struct _ObAppSettings
|
||||
{
|
||||
gchar *class;
|
||||
gchar *name;
|
||||
gchar *role;
|
||||
GPatternSpec *class;
|
||||
GPatternSpec *name;
|
||||
GPatternSpec *role;
|
||||
|
||||
Point position;
|
||||
gboolean center_x;
|
||||
|
@ -166,4 +168,12 @@ extern GSList *config_per_app_settings;
|
|||
void config_startup(struct _ObParseInst *i);
|
||||
void config_shutdown();
|
||||
|
||||
/*! Create an ObAppSettings structure with the default values */
|
||||
ObAppSettings* config_create_app_settings();
|
||||
/*! Copies any settings in src to dest, if they are their default value in
|
||||
src. */
|
||||
void config_app_settings_copy_non_defaults(const ObAppSettings *src,
|
||||
ObAppSettings *dest);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue