module/i3: allow 'content' to also contain a regular 'label'

Previously, the 'content' of i3 was a map, where the keys where i3
workspace names, mapping to a particle template.

Now, that configuration type is still allowed. But we also allow a
variant where the 'content' is a list, of either 1 or 2 entries.

Both entries *must* be dictionaries. The key is either 'dynlist',
which is the same as the dictionary-only type of
configuration. I.e. it maps to a dictionary where the keys are
workspace names, mapping to particle templates.

If the key is *not* dynlist, then it is assumed to be a particle name,
and we treat that as a "regular" label, that will be appended after
the workspace dynlist when instantiating the content.

This particle will be instantiated with, for now, the title and
application of the _currently focused_ workspace.
This commit is contained in:
Daniel Eklöf 2019-02-09 13:06:36 +01:00
parent d565fbe2f0
commit 4100922b7a

View file

@ -69,6 +69,8 @@ struct private {
struct workspace *v; struct workspace *v;
size_t count; size_t count;
} workspaces; } workspaces;
struct particle *label;
}; };
static bool static bool
@ -736,6 +738,9 @@ destroy(struct module *mod)
free(m->ws_content.v); free(m->ws_content.v);
workspaces_free(m); workspaces_free(m);
if (m->label != NULL)
m->label->destroy(m->label);
free(m); free(m);
module_default_destroy(mod); module_default_destroy(mod);
} }
@ -759,7 +764,7 @@ content(struct module *mod)
mtx_lock(&mod->lock); mtx_lock(&mod->lock);
struct exposable *particles[m->workspaces.count]; struct exposable *particles[m->workspaces.count + (m->label != NULL)];
size_t particle_count = 0; size_t particle_count = 0;
for (size_t i = 0; i < m->workspaces.count; i++) { for (size_t i = 0; i < m->workspaces.count; i++) {
@ -805,6 +810,32 @@ content(struct module *mod)
tag_set_destroy(&tags); tag_set_destroy(&tags);
} }
/* Find currently focused workspace */
const struct workspace *ws = NULL;
size_t count = 0;
for (size_t i = 0; i < m->workspaces.count; i++) {
if (m->workspaces.v[i].focused) {
ws = &m->workspaces.v[i];
count++;
}
}
assert(count <= 1);
assert(count == 0 || ws != NULL);
if (ws != NULL && m->label != NULL) {
struct tag_set tags = {
.tags = (struct tag *[]){
tag_new_string(mod, "application", ws->window.application),
tag_new_string(mod, "title", ws->window.title),
},
.count = 2,
};
particles[particle_count++] = m->label->instantiate(m->label, &tags);
tag_set_destroy(&tags);
}
mtx_unlock(&mod->lock); mtx_unlock(&mod->lock);
return dynlist_exposable_new( return dynlist_exposable_new(
particles, particle_count, m->left_spacing, m->right_spacing); particles, particle_count, m->left_spacing, m->right_spacing);
@ -818,7 +849,7 @@ struct i3_workspaces {
static struct module * static struct module *
i3_new(struct i3_workspaces workspaces[], size_t workspace_count, i3_new(struct i3_workspaces workspaces[], size_t workspace_count,
int left_spacing, int right_spacing) struct particle *label, int left_spacing, int right_spacing)
{ {
struct private *m = calloc(1, sizeof(*m)); struct private *m = calloc(1, sizeof(*m));
@ -833,6 +864,8 @@ i3_new(struct i3_workspaces workspaces[], size_t workspace_count,
m->ws_content.v[i].content = workspaces[i].content; m->ws_content.v[i].content = workspaces[i].content;
} }
m->label = label;
struct module *mod = module_common_new(); struct module *mod = module_common_new();
mod->private = m; mod->private = m;
mod->run = &run; mod->run = &run;
@ -854,10 +887,37 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
int right = spacing != NULL ? yml_value_as_int(spacing) : int right = spacing != NULL ? yml_value_as_int(spacing) :
right_spacing != NULL ? yml_value_as_int(right_spacing) : 0; right_spacing != NULL ? yml_value_as_int(right_spacing) : 0;
struct i3_workspaces workspaces[yml_dict_length(c)]; const struct yml_node *ws_root_node = NULL;
struct particle *label = NULL;
if (yml_is_dict(c)) {
ws_root_node = c;
} else {
for (struct yml_list_iter it = yml_list_iter(c);
it.node != NULL;
yml_list_next(&it))
{
assert(yml_is_dict(it.node));
assert(yml_dict_length(it.node) == 1);
const struct yml_dict_iter item = yml_dict_iter(it.node);
const char *key = yml_value_as_string(item.key);
if (strcmp(key, "dynlist") == 0) {
ws_root_node = item.value;
} else {
assert(label == NULL);
label = conf_to_particle(it.node, inherited);
}
}
}
assert(yml_is_dict(ws_root_node));
const size_t ws_count = yml_dict_length(ws_root_node);
struct i3_workspaces workspaces[ws_count];
size_t idx = 0; size_t idx = 0;
for (struct yml_dict_iter it = yml_dict_iter(c); for (struct yml_dict_iter it = yml_dict_iter(ws_root_node);
it.key != NULL; it.key != NULL;
yml_dict_next(&it), idx++) yml_dict_next(&it), idx++)
{ {
@ -865,18 +925,13 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
workspaces[idx].content = conf_to_particle(it.value, inherited); workspaces[idx].content = conf_to_particle(it.value, inherited);
} }
return i3_new(workspaces, yml_dict_length(c), left, right); return i3_new(workspaces, ws_count, label, left, right);
} }
static bool static bool
verify_content(keychain_t *chain, const struct yml_node *node) verify_content_dynlist(keychain_t *chain, const struct yml_node *node)
{ {
if (!yml_is_dict(node)) { assert(yml_is_dict(node));
LOG_ERR(
"%s: must be a dictionary of workspace-name: particle mappings",
conf_err_prefix(chain, node));
return false;
}
for (struct yml_dict_iter it = yml_dict_iter(node); for (struct yml_dict_iter it = yml_dict_iter(node);
it.key != NULL; it.key != NULL;
@ -898,6 +953,59 @@ verify_content(keychain_t *chain, const struct yml_node *node)
return true; return true;
} }
static bool
verify_content(keychain_t *chain, const struct yml_node *node)
{
if (!yml_is_dict(node) && !yml_is_list(node)) {
LOG_ERR(
"%s: must be a dictionary of workspace-name: particle mappings",
conf_err_prefix(chain, node));
return false;
}
if (yml_is_dict(node))
return verify_content_dynlist(chain, node);
if (yml_list_length(node) > 2) {
LOG_ERR("%s: must be a list of at most 2 entries",
conf_err_prefix(chain, node));
return false;
}
for (struct yml_list_iter it = yml_list_iter(node);
it.node != NULL;
yml_list_next(&it))
{
if (!yml_is_dict(it.node) || yml_dict_length(it.node) != 1) {
LOG_ERR(
"%s: item must be a dictionary with a single item; "
"either a 'dynlist', or a particle name",
conf_err_prefix(chain, it.node));
return false;
}
const struct yml_dict_iter item = yml_dict_iter(it.node);
const char *key = yml_value_as_string(item.key);
if (key == NULL) {
LOG_ERR("%s: key must be a string; either 'dynlist', or a particle name",
conf_err_prefix(chain, item.key));
return false;
}
if (strcmp(key, "dynlist") == 0) {
if (!verify_content_dynlist(chain_push(chain, key), item.value))
return false;
chain_pop(chain);
} else {
if (!conf_verify_particle(chain, it.node))
return false;
}
}
return true;
}
static bool static bool
verify_conf(keychain_t *chain, const struct yml_node *node) verify_conf(keychain_t *chain, const struct yml_node *node)
{ {