diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 06cff98de..ecb41a603 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -685,19 +685,6 @@ static void handle_visibility_notify(xcb_visibility_notify_event_t *event) { } } -static int strcasecmp_nullable(const char *a, const char *b) { - if (a == b) { - return 0; - } - if (a == NULL) { - return -1; - } - if (b == NULL) { - return 1; - } - return strcasecmp(a, b); -} - /* * Comparison function to sort trayclients in ascending alphanumeric order * according to their class. @@ -1816,6 +1803,8 @@ void reconfig_windows(bool redraw_bars) { bar_height); /* Set the WM_CLASS and WM_NAME (we don't need UTF-8) atoms */ + char *class; + int len = sasprintf(&class, "%s%ci3bar%c", config.bar_id, 0, 0); xcb_void_cookie_t class_cookie; class_cookie = xcb_change_property(xcb_connection, XCB_PROP_MODE_REPLACE, @@ -1823,8 +1812,8 @@ void reconfig_windows(bool redraw_bars) { XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, - (strlen("i3bar") + 1) * 2, - "i3bar\0i3bar\0"); + len, + class); char *name; sasprintf(&name, "i3bar for output %s", walk->name); diff --git a/include/libi3.h b/include/libi3.h index 15d1bc76c..d9c89ddd5 100644 --- a/include/libi3.h +++ b/include/libi3.h @@ -181,6 +181,12 @@ ssize_t writeall_nonblock(int fd, const void *buf, size_t count); */ ssize_t swrite(int fd, const void *buf, size_t count); +/** + * Like strcasecmp but considers the case where either string is NULL. + * + */ +int strcasecmp_nullable(const char *a, const char *b); + /** * Build an i3String from an UTF-8 encoded string. * Returns the newly-allocated i3String. diff --git a/libi3/safewrappers.c b/libi3/safewrappers.c index 1802b327e..fdea636ee 100644 --- a/libi3/safewrappers.c +++ b/libi3/safewrappers.c @@ -110,3 +110,20 @@ ssize_t swrite(int fd, const void *buf, size_t count) { else return n; } + +/* + * Like strcasecmp but considers the case where either string is NULL. + * + */ +int strcasecmp_nullable(const char *a, const char *b) { + if (a == b) { + return 0; + } + if (a == NULL) { + return -1; + } + if (b == NULL) { + return 1; + } + return strcasecmp(a, b); +} diff --git a/src/con.c b/src/con.c index ba0eaa3cc..08bb7e4ed 100644 --- a/src/con.c +++ b/src/con.c @@ -132,6 +132,30 @@ static void _con_attach(Con *con, Con *parent, Con *previous, bool ignore_focus) goto add_to_focus_head; } + if (parent->type == CT_DOCKAREA) { + /* Insert dock client, sorting alphanumerically by class and then + * instance name. This makes dock client order deterministic. As a side + * effect, bars without a custom bar id will be sorted according to + * their declaration order in the config file. See #3491. */ + current = NULL; + TAILQ_FOREACH (loop, nodes_head, nodes) { + int result = strcasecmp_nullable(con->window->class_class, loop->window->class_class); + if (result == 0) { + result = strcasecmp_nullable(con->window->class_instance, loop->window->class_instance); + } + if (result < 0) { + current = loop; + break; + } + } + if (current) { + TAILQ_INSERT_BEFORE(loop, con, nodes); + } else { + TAILQ_INSERT_TAIL(nodes_head, con, nodes); + } + goto add_to_focus_head; + } + if (con->type == CT_FLOATING_CON) { DLOG("Inserting into floating containers\n"); TAILQ_INSERT_TAIL(&(parent->floating_head), con, floating_windows); diff --git a/src/handlers.c b/src/handlers.c index ed3f6c3ed..d6d6e20bc 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -1148,9 +1148,7 @@ static bool handle_strut_partial_change(Con *con, xcb_get_property_reply_t *prop /* attach the dock to the dock area */ con_detach(con); - con->parent = dockarea; - TAILQ_INSERT_HEAD(&(dockarea->focus_head), con, focused); - TAILQ_INSERT_HEAD(&(dockarea->nodes_head), con, nodes); + con_attach(con, dockarea, true); tree_render();