Автозапуск программ на определенных тегах экрана

Моя цель - автоматически запускать несколько программ с определенными тегами при первом запуске awesome, например. запуск Chromium на экране 1, тег 1; запуск gVim на экране 2, тег 1. Я нашел несколько мест в Интернете, которые рекомендуют использовать следующую функцию:

function spawn_once(command, class, tag) 
  -- create move callback
  local callback 
  callback = function(c) 
    if c.class == class then 
      awful.client.movetotag(tag, c) 
      client.remove_signal("manage", callback) 
    end 
  end 
  client.add_signal("manage", callback) 
  -- now check if not already running!     
  local findme = command
  local firstspace = findme:find(" ")
  if firstspace then
    findme = findme:sub(0, firstspace-1)
  end
  -- finally run it
  awful.util.spawn_with_shell("pgrep -u $USER -x " .. findme .. " > /dev/null || (" .. command .. ")")
end

spawn_once("chromium", "Chromium", root.tags()[2][1])
spawn_once("gvim", "gVim", root.tags()[1][2])

К сожалению, эта функция не работает в новых версиях awesome. Независимо от того, какой тег я выберу или внесу незначительное обновление в функцию, он помещает программу в первый тег. См. комментарии: https://gist.github.com/Flowkap/8858434

Не работает должным образом. То же, что dvd001. Таким образом, программы запускаются с тегом 1 независимо от указанного тега.

Как мне сделать это в более новых версиях awesome (v4.2+)?

Вот мой rc.lua:

-- libraries
local naughty = require("naughty")
local gears = require("gears")
local beautiful = require("beautiful")
local awful = require("awful")
    require("awful.autofocus")
local wibox = require("wibox")

-- errors
if awesome.startup_errors then
    naughty.notify({
        preset = naughty.config.presets.critical,
        title = "Startup errors",
        text = awesome.startup_errors})
end

do
    local in_error = false
    awesome.connect_signal("debug::error", function (err)
        if in_error then return end
        in_error = true
        naughty.notify({preset = naughty.config.presets.critical,
            title = "Error",
            text = tostring(err)})
        in_error = false
    end)
end

-- variables
local modkey = "Mod4"
local terminal = "xterm"

-- layouts
awful.layout.layouts = {
    awful.layout.suit.tile.left,
    awful.layout.suit.max,
    awful.layout.suit.floating,
}

-- helper functions
local function client_menu_toggle_fn()
    local instance = nil

    return function ()
        if instance and instance.wibox.visible then
            instance:hide()
            instance = nil
        else
            instance = awful.menu.clients({theme = {width = 250}})
        end
    end
end

local function set_wallpaper(s)
    if beautiful.wallpaper then
        local wallpaper = beautiful.wallpaper
        if type(wallpaper) == "function" then
            wallpaper = wallpaper(s)
        end
        gears.wallpaper.maximized(wallpaper, s, true)
    end
end


-- init theme
beautiful.init(gears.filesystem.get_configuration_dir() .. "themes/shane/theme.lua")

-- change wallpaper on screen resize
screen.connect_signal("property::geometry", set_wallpaper)

-- tag buttons
local tag_buttons = gears.table.join(
    awful.button({}, 1, function (t) t:view_only() end),
    awful.button({modkey}, 1, function (t)
        if client.focus then
            client.focus:move_to_tag(t)
        end
    end),
    awful.button({}, 3, function (t)
        if client.focus then
            client.focus:toggle_tag(t)
        end
    end),
    awful.button({}, 4, function (t) awful.tag.viewnext(t.screen) end),
    awful.button({}, 5, function (t) awful.tag.viewprev(t.screen) end)
)

-- task buttons
local task_buttons = gears.table.join(
    awful.button({}, 1, function (c)
        if c == client.focus then
            c.minimized = true
        else
            c.minimized = false
            if not c:isvisible() and c.first_tag then
                c.first_tag:view_only()
            end
            client.focus = c
            c:raise()
        end
    end),
    awful.button({}, 3, client_menu_toggle_fn()),
    awful.button({}, 4, function ()
        awful.client.focus.byidx(1)
    end),
    awful.button({}, 5, function ()
        awful.client.focus.byidx(-1)
    end)
)

-- create clock
clock = wibox.widget.textclock(" %A, %B %d %l:%M%p ")

-- init screen
awful.screen.connect_for_each_screen(function (s)
    -- set wallpaper
    set_wallpaper(s)

    -- create tags
    if (s.index == 1) then
        awful.tag({"  1. Browser  ", "  2. Database  ", "  3. Files  ", "  4. Break  ", "  5. Music  ", "  6. Misc  "},
            s, awful.layout.layouts[1])
    else
        awful.tag({"  1. Terminal  ", "  2. Edit  ", "  3. Passwords  ", "  4. Misc  "}, s, awful.layout.layouts[1])
    end

    -- create tag list
    s.taglist = awful.widget.taglist(s, awful.widget.taglist.filter.all, tag_buttons)

    -- create prompt
    s.prompt = awful.widget.prompt({prompt = " Run: ", prompt_fg = "#f0f"})

    -- create tasks
    s.tasks = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, task_buttons)

    -- create the main bar
    s.bar = awful.wibar({position = "top", screen = s, height = 32})
    s.bar:setup {
        layout = wibox.layout.align.horizontal,
        { layout = wibox.layout.fixed.horizontal,
            s.taglist,
            s.prompt },
        { layout = wibox.layout.fixed.horizontal },
        { layout = wibox.layout.fixed.horizontal,
            clock },
    }

    -- task bar
    s.taskbar = awful.wibar({position = "bottom", screen = s, height = 32})
    s.taskbar:setup {
        layout = wibox.layout.align.horizontal,
        s.tasks,
    }
end)

-- startup programs
function spawn_once(command, class, tag)
    -- create move callback
    local callback
    callback = function(c)
        if c.class == class then
            awful.client.movetotag(tag, c)
            client.remove_signal("manage", callback)
        end
    end
    client.add_signal("manage", callback)
    -- now check if not already running!
    local findme = command
    local firstspace = findme:find(" ")
    if firstspace then
        findme = findme:sub(0, firstspace-1)
    end
    -- finally run it
    awful.util.spawn_with_shell("pgrep -u $USER -x " .. findme .. " > /dev/null || (" .. command .. ")")
end

spawn_once("chromium", "Chromium", screen[1].tags[1])
spawn_once("gvim", "gVim", screen[2].tags[2])

-- keybindings
keybindings = gears.table.join(
    awful.key({modkey, "Shift"}, "q", awesome.quit,
        {description = "quit awesome", group = "awesome"}),
    awful.key({modkey, "Shift"}, "r", awesome.restart,
        {description = "restart awesome", group = "awesome"}),
    awful.key({modkey}, "r", function () awful.screen.focused().prompt:run() end,
        {description = "run prompt", group = "launcher"}),
    awful.key({modkey}, "Left", awful.tag.viewprev,
        {description = "previous tag", group = "tag"}),
    awful.key({modkey}, "Right", awful.tag.viewnext,
        {description = "next tag", group = "tag"}),
    awful.key({modkey}, "j", function () awful.client.focus.byidx(1) end,
        {description = "focus next window", group = "client"}),
    awful.key({modkey}, "k", function () awful.client.focus.byidx(-1) end,
        {description = "focus previous window", group = "client"}),
    awful.key({modkey, "Shift"}, "j", function () awful.client.swap.byidx(1) end,
        {description = "swap with next client", group = "client"}),
    awful.key({modkey, "Shift"}, "k", function () awful.client.swap.byidx(-1) end,
        {description = "swap with previous client", group = "client"}),
    awful.key({modkey, "Control"}, "j", function () awful.screen.focus_relative(1) end,
        {description = "focus next screen", group = "screen"}),
    awful.key({modkey, "Control"}, "k", function () awful.screen.focus_relative(-1) end,
        {description = "focus previous screen", group = "screen"}),
    awful.key({modkey}, "Tab", function ()
        awful.client.focus.history.previous()
        if client.focus then client.focus:raise() end end,
        {description = "focus last client", group = "client"}),
    awful.key({modkey}, "Return", function () awful.spawn(terminal) end,
        {description = "open a terminal", group = "launcher"}),
    awful.key({modkey}, "l", function () awful.tag.incmwfact(0.05) end,
        {description = "increase master width", group = "layout"}),
    awful.key({modkey}, "h", function () awful.tag.incmwfact(-0.05) end,
        {description = "decrease master width", group = "layout"}),
    awful.key({modkey, "Shift"}, "h", function () awful.tag.incnmaster(1, nil, true) end,
        {description = "increase number of master clients", group = "layout"}),
    awful.key({modkey, "Shift"}, "l", function () awful.tag.incnmaster(-1, nil, true) end,
        {description = "decrease number of master clients", group = "layout"}),
    awful.key({modkey, "Control"}, "h", function () awful.tag.incncol(1, nil, true) end,
        {description = "increase number of columns", group = "layout"}),
    awful.key({modkey, "Control"}, "l", function () awful.tag.incncol(-1, nil, true) end,
        {description = "decrease number of columns", group = "layout"}),
    awful.key({modkey}, "space", function () awful.layout.inc(1) end,
        {description = "next layout", group = "layout"}),
    awful.key({modkey, "Shift"}, "space", function () awful.layout.inc(-1) end,
        {description = "previous layout", group = "layout"}),
    awful.key({modkey}, "c", function () awful.spawn("chromium") end,
        {description = "start chrome", group = "launcher"}),
    awful.key({modkey}, "v", function () awful.spawn("gvim") end,
        {description = "start gvim", group = "launcher"}),
    awful.key({}, "XF86AudioRaiseVolume", function () awful.spawn("pactl set-sink-volume 2 +2%", false) end,
        {description = "raise volume", group = "launcher"}),
    awful.key({}, "XF86AudioLowerVolume", function () awful.spawn("pactl set-sink-volume 2 -2%", false) end,
        {description = "lower volume", group = "launcher"}),
    awful.key({}, "XF86AudioPlay", function () awful.spawn("lollypop -t", false) end,
        {description = "play track", group = "launcher"}),
    awful.key({}, "XF86AudioPause", function () awful.spawn("lollypop -t", false) end,
        {description = "pause track", group = "launcher"}),
    awful.key({}, "XF86AudioNext", function () awful.spawn("lollypop -n", false) end,
        {description = "next track", group = "launcher"}),
    awful.key({}, "XF86AudioPrev", function () awful.spawn("lollypop -p", false) end,
        {description = "previous track", group = "launcher"})
)

-- bind numbers to tags
for i = 1, 9 do
    keybindings = gears.table.join(keybindings,
        awful.key({modkey}, "#" .. i + 9,
            function ()
                local screen = awful.screen.focused()
                local tag = screen.tags[i]
                if tag then
                    tag:view_only()
                end
            end, {description = "view tag #" .. i, group = "tag"}),
        awful.key({modkey, "Control"}, "#" .. i + 9,
            function ()
                local screen = awful.screen.focused()
                local tag = screen.tags[i]
                if tag then
                    awful.tag.viewtoggle(tag)
                end
            end, {description = "toggle tag #" .. i, group = "tag"}),
        awful.key({modkey, "Shift"}, "#" .. i + 9,
            function ()
                if client.focus then
                    local tag = client.focus.screen.tags[i]
                    if tag then
                        client.focus:move_to_tag(tag)
                    end
                end
            end, {description = "move focused client to tag #" .. i, group = "tag"}),
        awful.key({modkey, "Control", "Shift"}, "#" .. i + 9,
            function ()
                if client.focus then
                    local tag = client.focus.screen.tags[i]
                    if tag then
                        client.focus:toggle_tag(tag)
                    end
                end
            end, {description = "toggle focused client on tag #" .. i, group = "tag"})
    )
end

root.keys(keybindings)

-- client keys
client_keybindings = gears.table.join(
    awful.key({modkey, "Shift"}, "c", function (c) c:kill() end,
        {description = "close", group = "client"}),
    awful.key({modkey}, "m", function (c)
        c.maximized = not c.maximized
        c:raise()
    end, {description = "toggle maximized", group = "client"})
)

-- client buttons
client_buttons = gears.table.join(
    awful.button({}, 1, function (c) client.focus = c; c:raise() end),
    awful.button({modkey}, 1, awful.mouse.client.move),
    awful.button({modkey}, 3, awful.mouse.client.resize)
)

-- client rules
awful.rules.rules = {
    {
        rule = {},
        properties = {
            border_width = beautiful.border_width,
            border_color = beautiful.border_normal,
            focus = awful.client.focus.filter,
            raise = true,
            keys = client_keybindings,
            buttons = client_buttons,
            screen = awful.screen.preferred,
            placement = awful.placement.no_overlap+awful.placement.no_offscreen,
            size_hints_honor = false
        }
    }
}

-- signals
client.connect_signal("manage", function (c)
    if awesome.startup
        and not c.size_hints.user_position
        and not c.size_hints.program_position then
            awful.placement.no_offscreen(c)
    end
end)

person Shane    schedule 26.09.2018    source источник
comment
Хм... у вас есть идеи, почему это больше не работает? Любые сообщения об ошибках на stderr? На первый взгляд, я бы, по крайней мере, ожидал, что Command not found: gVim.   -  person Uli Schlachter    schedule 27.09.2018
comment
@UliSchlachter gVim здесь была опечатка. Я не получаю ошибок. Он просто каждый раз открывает программы на первой вкладке первого экрана, что бы я ни выбирал для индексов. Изменить: я отредактировал приведенный выше пример кода, чтобы точно отразить то, что находится в моем файле rc.lua.   -  person Shane    schedule 27.09.2018


Ответы (2)


Еще одна альтернатива здесь — использовать xproperties и команды spawn, поддерживаемые уведомлением о запуске.

Во-первых, вам нужно зарегистрировать xproperty [1]. После этого вы пишете функцию, которая зацикливается на запущенных клиентах и ​​проверяет, установлено ли для них ваше свойство. Если это не так, вы используете второй аргумент awful.spawn, чтобы установить свой магический токен. Обратите внимание, что вы также можете добавить источник awful.rules для решения проблемы при перезапуске Awesome и установке тега на основе волшебного токена[2].

Для этого решения вам нужно использовать Awesome v4.3+ и применить этот хак:

Заставить приложения поддерживать уведомления о запуске

[1] https://awesomewm.org/apidoc/classes/client.html#awful.client.property.persist

[2] https://awesomewm.org/apidoc/libraries/awful.rules.html#add_rule_source

person Emmanuel Lepage Vallee    schedule 29.09.2018
comment
Спасибо за это. Я не буду пробовать это до выхода 4.3. - person Shane; 01.10.2018
comment
Я завершил реализацию на github.com/awesomeWM/awesome/pull/2409, если вы хотите бета-тест. Я воспользуюсь этим. Никакой патч (надеюсь) больше не понадобится. - person Emmanuel Lepage Vallee; 02.10.2018
comment
Вот это да. Вы действительно превзошли все ожидания. Спасибо. Я тестирую это прямо сейчас. Как лучше всего задокументировать любые проблемы, с которыми я сталкиваюсь? - person Shane; 03.10.2018
comment
Если это произойдет до того, как этот PR будет объединен, прокомментируйте там. Если это произойдет после, сообщите об ошибках. Chromium не реализует протокол уведомления о запуске, поэтому вам придется применить обходной путь, найденный в документации client.startup_id, указанной выше, чтобы это работало. - person Emmanuel Lepage Vallee; 03.10.2018

root.tags()[2][1]

Это не работает. Попробуйте, например. naughty.notify{ text = "tag is " .. tostring(root.tags()[2][1]) }. Он скажет вам, что это nil. root.tags() дает вам простой список всех тегов, поэтому root.tags()[2] — это второй тег. Затем вы индексируете этот тег с помощью [1], что даст вам nil (наверное...).

Попробуйте screen[2].tags[1], предполагая, что это то, что вы пытаетесь выразить.

Изменить: при попытке использовать ваш код я также заметил, что remove_signal должно быть disconnect_signal, а add_signal должно быть connect_signal. С этими изменениями это теперь действительно работает для меня на git/master.

person Uli Schlachter    schedule 28.09.2018
comment
Это становится где-то сейчас. Когда я уведомляю screen[1].tags[5], я получаю ненулевое значение. Тем не менее, он по-прежнему помещает его в первый тег на первом экране, независимо от того, на какой тег или экран я ссылаюсь. - person Shane; 28.09.2018
comment
Жаль, что я не попробовал это сам раньше. Смотрите мое редактирование ответа. - person Uli Schlachter; 29.09.2018
comment
После замены remove_signal на disconnect_signal и add_signal на connect_signal все равно открывает обе программы по первому тегу первого экрана. Вы упомянули, что работали на git/master — значит, не на 4.3? В таком случае мне придется подождать. - person Shane; 01.10.2018