diff --git a/objects/client.c b/objects/client.c index e1c82e2de..dbc725eb2 100644 --- a/objects/client.c +++ b/objects/client.c @@ -723,12 +723,59 @@ * identifier remain the same. This allow to match a spawn event to an actual * client. * + * This is used to display a different mouse cursor when the application is + * loading and also to attach some properties to the newly created client (like + * a `tag` or `floating` state). + * + * Some applications, like `xterm`, don't support startup notification. While + * not perfect, the addition the following code to `rc.lua` will mitigate the + * issue. Please note that this code is Linux specific. + * + * local blacklisted_snid = setmetatable({}, {__mode = "v" }) + * + * --- Make startup notification work for some clients like XTerm. This is ugly + * -- but works often enough to be useful. + * local function fix_startup_id(c) + * -- Prevent "broken" sub processes created by `c` to inherit its SNID + * if c.startup_id then + * blacklisted_snid[c.startup_id] = blacklisted_snid[c.startup_id] or c + * return + * end + * + * if not c.pid then return end + * + * -- Read the process environment variables + * local f = io.open("/proc/"..c.pid.."/environ", "rb") + * + * -- It will only work on Linux, that's already 99% of the userbase. + * if not f then return end + * + * local value = _VERSION <= "Lua 5.1" and "([^\z]*)\0" or "([^\0]*)\0" + * local snid = f:read("*all"):match("STARTUP_ID=" .. value) + * f:close() + * + * -- If there is already a client using this SNID, it means it's either a + * -- subprocess or another window for the same process. While it makes sense + * -- in some case to apply the same rules, it is not always the case, so + * -- better doing nothing rather than something stupid. + * if blacklisted_snid[snid] then return end + * + * c.startup_id = snid + * + * blacklisted_snid[snid] = c + * end + * + * awful.rules.add_rule_source( + * "snid", fix_startup_id, {}, {"awful.spawn", "awful.rules"} + * ) + * * **Signal:** * * * *property::startup\_id* * * @property startup_id * @param string + * @see awful.spawn */ /** @@ -906,6 +953,7 @@ DO_CLIENT_SET_STRING_PROPERTY(name) DO_CLIENT_SET_STRING_PROPERTY2(alt_name, name) DO_CLIENT_SET_STRING_PROPERTY(icon_name) DO_CLIENT_SET_STRING_PROPERTY2(alt_icon_name, icon_name) +DO_CLIENT_SET_STRING_PROPERTY2(startup_id, startup_id) DO_CLIENT_SET_STRING_PROPERTY(role) DO_CLIENT_SET_STRING_PROPERTY(machine) #undef DO_CLIENT_SET_STRING_PROPERTY @@ -3057,6 +3105,14 @@ luaA_client_get_icon_name(lua_State *L, client_t *c) return 1; } +static int +luaA_client_set_startup_id(lua_State *L, client_t *c) +{ + const char *startup_id = luaL_checkstring(L, -1); + client_set_startup_id(L, 1, a_strdup(startup_id)); + return 0; +} + LUA_OBJECT_EXPORT_OPTIONAL_PROPERTY(client, client_t, screen, luaA_object_push, NULL) LUA_OBJECT_EXPORT_PROPERTY(client, client_t, class, lua_pushstring) LUA_OBJECT_EXPORT_PROPERTY(client, client_t, instance, lua_pushstring) @@ -3717,9 +3773,9 @@ client_class_setup(lua_State *L) (lua_class_propfunc_t) luaA_client_get_shape_input, (lua_class_propfunc_t) luaA_client_set_shape_input); luaA_class_add_property(&client_class, "startup_id", - NULL, + (lua_class_propfunc_t) luaA_client_set_startup_id, (lua_class_propfunc_t) luaA_client_get_startup_id, - NULL); + (lua_class_propfunc_t) luaA_client_set_startup_id); luaA_class_add_property(&client_class, "client_shape_bounding", NULL, (lua_class_propfunc_t) luaA_client_get_client_shape_bounding,