Sort dock clients by class and instance
This is similar to #3820 but does not use qsort but an insertion sort in
con_attach.
Since each bar block automatically gets its own incremental bar id,
bards end up being sorted according to their definition order in the
config file.
For i3bar, the WM_CLASS is modified to include an instance name which
depends on the bar_id. This could be useful for other reason, e.g. users
targeting a specific bar instance.
Fixes #3491
Orestis Floros
4 years ago
181 | 181 |
ssize_t swrite(int fd, const void *buf, size_t count);
|
182 | 182 |
|
183 | 183 |
/**
|
|
184 |
* Like strcasecmp but considers the case where either string is NULL.
|
|
185 |
*
|
|
186 |
*/
|
|
187 |
int strcasecmp_nullable(const char *a, const char *b);
|
|
188 |
|
|
189 |
/**
|
184 | 190 |
* Build an i3String from an UTF-8 encoded string.
|
185 | 191 |
* Returns the newly-allocated i3String.
|
186 | 192 |
*
|
109 | 109 |
else
|
110 | 110 |
return n;
|
111 | 111 |
}
|
|
112 |
|
|
113 |
/*
|
|
114 |
* Like strcasecmp but considers the case where either string is NULL.
|
|
115 |
*
|
|
116 |
*/
|
|
117 |
int strcasecmp_nullable(const char *a, const char *b) {
|
|
118 |
if (a == b) {
|
|
119 |
return 0;
|
|
120 |
}
|
|
121 |
if (a == NULL) {
|
|
122 |
return -1;
|
|
123 |
}
|
|
124 |
if (b == NULL) {
|
|
125 |
return 1;
|
|
126 |
}
|
|
127 |
return strcasecmp(a, b);
|
|
128 |
}
|
127 | 127 |
else
|
128 | 128 |
TAILQ_INSERT_TAIL(nodes_head, con, nodes);
|
129 | 129 |
}
|
|
130 |
}
|
|
131 |
goto add_to_focus_head;
|
|
132 |
}
|
|
133 |
|
|
134 |
if (parent->type == CT_DOCKAREA) {
|
|
135 |
/* Insert dock client, sorting alphanumerically by class and then
|
|
136 |
* instance name. This makes dock client order deterministic. As a side
|
|
137 |
* effect, bars without a custom bar id will be sorted according to
|
|
138 |
* their declaration order in the config file. See #3491. */
|
|
139 |
current = NULL;
|
|
140 |
TAILQ_FOREACH (loop, nodes_head, nodes) {
|
|
141 |
int result = strcasecmp_nullable(con->window->class_class, loop->window->class_class);
|
|
142 |
if (result == 0) {
|
|
143 |
result = strcasecmp_nullable(con->window->class_instance, loop->window->class_instance);
|
|
144 |
}
|
|
145 |
if (result < 0) {
|
|
146 |
current = loop;
|
|
147 |
break;
|
|
148 |
}
|
|
149 |
}
|
|
150 |
if (current) {
|
|
151 |
TAILQ_INSERT_BEFORE(loop, con, nodes);
|
|
152 |
} else {
|
|
153 |
TAILQ_INSERT_TAIL(nodes_head, con, nodes);
|
130 | 154 |
}
|
131 | 155 |
goto add_to_focus_head;
|
132 | 156 |
}
|