2020-09-16 19:21:01 +02:00
|
|
|
-- This project is licensed under the MIT License (see LICENSE).
|
|
|
|
|
2020-04-06 15:17:18 +02:00
|
|
|
--- Create new workspaces and launch accompanying clients.
|
2019-09-16 16:01:17 +02:00
|
|
|
--
|
|
|
|
-- @author James Reed <jcrd@tuta.io>
|
2020-08-19 20:36:08 +02:00
|
|
|
-- @copyright 2019-2020 James Reed
|
2019-09-16 16:01:17 +02:00
|
|
|
-- @module awesome-launch.workspace
|
|
|
|
|
|
|
|
local awful = require("awful")
|
2020-04-29 12:36:15 +02:00
|
|
|
local naughty = require("naughty")
|
2019-09-16 16:01:17 +02:00
|
|
|
local gtable = require("gears.table")
|
2020-08-02 01:28:19 +02:00
|
|
|
local gtimer = require("gears.timer")
|
2020-10-04 00:37:39 +02:00
|
|
|
local protected_call = require("gears.protected_call")
|
2019-09-16 16:01:17 +02:00
|
|
|
|
2020-10-04 00:37:39 +02:00
|
|
|
local lgi = require("lgi")
|
|
|
|
local Gio, GLib, GObject = lgi.Gio, lgi.GLib, lgi.GObject
|
|
|
|
|
2021-11-07 23:52:39 +01:00
|
|
|
local launch = require("awesome-launch")
|
|
|
|
local shared = require("awesome-launch.shared")
|
|
|
|
|
2019-09-16 16:01:17 +02:00
|
|
|
local ws = {}
|
|
|
|
ws.client = {}
|
|
|
|
|
2020-04-29 12:36:15 +02:00
|
|
|
ws.clients = {}
|
|
|
|
|
2020-10-04 00:37:39 +02:00
|
|
|
local function add_clients(cs, tag)
|
2020-04-29 12:36:15 +02:00
|
|
|
for _, c in ipairs(cs) do
|
|
|
|
local cmd
|
|
|
|
local cmdargs
|
|
|
|
if type(c) == "table" then
|
|
|
|
cmd = c[1]
|
2020-10-04 00:37:39 +02:00
|
|
|
if c[2] then
|
|
|
|
cmdargs = gtable.clone(c[2], false)
|
|
|
|
end
|
2020-04-29 12:36:15 +02:00
|
|
|
end
|
|
|
|
ws.client.add(cmd or c, cmdargs, tag)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-10-04 00:37:39 +02:00
|
|
|
local function handle_args(tag, args)
|
2020-04-06 15:17:18 +02:00
|
|
|
args = args or {}
|
|
|
|
|
|
|
|
if args.pwd then
|
|
|
|
tag.pwd = args.pwd
|
|
|
|
end
|
|
|
|
|
|
|
|
if args.replace and not tag.volatile then
|
2020-12-21 01:11:35 +01:00
|
|
|
for _, c in ipairs(tag:clients()) do
|
|
|
|
c:kill()
|
|
|
|
end
|
2020-04-06 15:17:18 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
if args.clients then
|
2020-04-29 12:36:15 +02:00
|
|
|
add_clients(args.clients, tag)
|
|
|
|
end
|
|
|
|
|
2020-04-06 15:17:18 +02:00
|
|
|
if args.callback then
|
|
|
|
args.callback(tag)
|
|
|
|
end
|
|
|
|
|
|
|
|
return tag
|
|
|
|
end
|
|
|
|
|
2019-09-16 16:01:17 +02:00
|
|
|
--- Spawn a command and add the client to a tag.
|
|
|
|
--
|
|
|
|
-- @param cmd The command.
|
|
|
|
-- @param args Table containing the single instance ID and additional arguments for spawn
|
|
|
|
-- @param args.id Single instance ID.
|
|
|
|
-- @param args.props Properties to apply to the client.
|
|
|
|
-- @param args.pwd Pathname to the working directory for new clients.
|
|
|
|
-- @param args.timeout Seconds after which to stop waiting for a client to spawn.
|
2020-08-05 22:13:23 +02:00
|
|
|
-- @param args.callback Function to call with client when it spawns.
|
2019-09-16 16:01:17 +02:00
|
|
|
-- @param args.factory The factory to use (see wm-launch's -f flag).
|
2020-08-19 20:36:08 +02:00
|
|
|
-- @param args.systemd If true, run cmd with systemd-run.
|
2019-09-16 16:01:17 +02:00
|
|
|
-- @param args.firejail If true, run cmd with firejail.
|
|
|
|
-- @param tag The tag.
|
|
|
|
-- @function client.add
|
|
|
|
function ws.client.add(cmd, args, tag)
|
|
|
|
args = args and gtable.clone(args) or {}
|
|
|
|
tag = tag or awful.screen.focused().selected_tag
|
|
|
|
args.props = args.props or {}
|
|
|
|
args.props.tag = tag
|
|
|
|
args.props.tags = nil
|
|
|
|
if tag.pwd then
|
|
|
|
args.pwd = tag.pwd
|
|
|
|
end
|
|
|
|
launch.spawn(cmd, args)
|
|
|
|
end
|
|
|
|
|
2020-04-06 15:17:18 +02:00
|
|
|
--- Create a new workspace and underlying (volatile) tag.
|
2019-09-16 16:01:17 +02:00
|
|
|
--
|
|
|
|
-- @param name The tag name.
|
|
|
|
-- @param args Table containing tag properties and additional workspace options
|
|
|
|
-- @param args.props Properties to apply to the tag.
|
|
|
|
-- @param args.pwd Pathname to the working directory for new clients.
|
|
|
|
-- @param args.clients Table containing client commands to spawn.
|
|
|
|
--
|
|
|
|
-- Example: `args.clients = { "xterm",
|
|
|
|
-- {"qutebrowser", {factory="qutebrowser"}} }`
|
|
|
|
--
|
2020-04-29 12:36:15 +02:00
|
|
|
-- @param args.load_workspace Path to directory containing workspace file to
|
|
|
|
-- load. Implies args.pwd.
|
2019-09-16 16:01:17 +02:00
|
|
|
-- @param args.callback Function to call with newly created tag.
|
|
|
|
-- @return The new tag.
|
2020-04-06 15:17:18 +02:00
|
|
|
-- @function new
|
|
|
|
function ws.new(name, args)
|
2019-09-16 16:01:17 +02:00
|
|
|
local props = {
|
|
|
|
screen = awful.screen.focused(),
|
2020-10-03 16:22:58 +02:00
|
|
|
layout = awful.layout.layouts[1],
|
2019-09-16 16:01:17 +02:00
|
|
|
}
|
2020-04-06 15:17:18 +02:00
|
|
|
if args and args.props then
|
|
|
|
gtable.crush(props, args.props)
|
2019-09-16 16:01:17 +02:00
|
|
|
end
|
2020-04-06 15:17:18 +02:00
|
|
|
local tag = awful.tag.add(name, props)
|
2019-09-16 16:01:17 +02:00
|
|
|
|
2020-10-06 00:34:28 +02:00
|
|
|
local function delete()
|
2020-08-02 01:28:19 +02:00
|
|
|
gtimer.delayed_call(function ()
|
2021-11-07 23:52:39 +01:00
|
|
|
for _, data in pairs(shared.pending) do
|
|
|
|
if data.props.tag and data.props.tag == tag then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
2020-10-06 00:34:28 +02:00
|
|
|
if not tag.selected and #tag:clients() == 0 then
|
2020-08-02 01:28:19 +02:00
|
|
|
tag:delete()
|
|
|
|
end
|
|
|
|
end)
|
2020-10-06 00:34:28 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
tag:connect_signal("property::selected", delete)
|
|
|
|
tag:connect_signal("untagged", delete)
|
2020-07-30 01:13:09 +02:00
|
|
|
|
2020-04-06 15:17:18 +02:00
|
|
|
return handle_args(tag, args)
|
|
|
|
end
|
2019-09-16 16:01:17 +02:00
|
|
|
|
2020-04-06 15:17:18 +02:00
|
|
|
--- Add to or replace a given tag's clients.
|
|
|
|
--
|
|
|
|
-- @param tag The tag to affect.
|
|
|
|
-- @param args Table containing tag properties and additional workspace options
|
|
|
|
-- @param args.pwd Pathname to the working directory for new clients.
|
|
|
|
-- @param args.replace Kill tag's existing clients if true.
|
|
|
|
-- @param args.clients Table containing client commands to spawn.
|
|
|
|
--
|
|
|
|
-- Example: `args.clients = { "xterm",
|
|
|
|
-- {"qutebrowser", {factory="qutebrowser"}} }`
|
|
|
|
--
|
2020-04-29 12:36:15 +02:00
|
|
|
-- @param args.load_workspace Path to directory containing workspace file to
|
|
|
|
-- load. Implies args.pwd.
|
2020-04-06 15:17:18 +02:00
|
|
|
-- @return The affected tag.
|
|
|
|
-- @function add
|
|
|
|
function ws.add(tag, args)
|
|
|
|
return handle_args(tag, args)
|
|
|
|
end
|
2019-09-16 16:01:17 +02:00
|
|
|
|
2020-04-06 15:17:18 +02:00
|
|
|
--- Add to or replace the selected tag's clients.
|
|
|
|
--
|
|
|
|
-- @param args Table containing tag properties and additional workspace options
|
|
|
|
-- @param args.pwd Pathname to the working directory for new clients.
|
|
|
|
-- @param args.replace Kill tag's existing clients if true.
|
|
|
|
-- @param args.clients Table containing client commands to spawn.
|
|
|
|
--
|
|
|
|
-- Example: `args.clients = { "xterm",
|
|
|
|
-- {"qutebrowser", {factory="qutebrowser"}} }`
|
|
|
|
--
|
2020-04-29 12:36:15 +02:00
|
|
|
-- @param args.load_workspace Path to directory containing workspace file to
|
|
|
|
-- load. Implies args.pwd.
|
2020-04-06 15:17:18 +02:00
|
|
|
-- @return The affected tag.
|
|
|
|
-- @function selected_tag
|
|
|
|
function ws.selected_tag(args)
|
|
|
|
return ws.add(awful.screen.focused().selected_tag, args)
|
2019-09-16 16:01:17 +02:00
|
|
|
end
|
|
|
|
|
2020-10-04 00:37:39 +02:00
|
|
|
local methods = {}
|
|
|
|
|
|
|
|
local function parse_client(s)
|
|
|
|
local c = {}
|
|
|
|
local i = 1
|
|
|
|
for t in string.gmatch(s, '[^%s]+') do
|
|
|
|
if i == 1 then
|
|
|
|
if t:sub(1, 1) == '@' then
|
|
|
|
local n = t:sub(2)
|
|
|
|
c = ws.clients[n]
|
|
|
|
if not c then
|
|
|
|
naughty.notify {
|
|
|
|
preset = naughty.config.presets.critical,
|
|
|
|
title = 'Client not defined',
|
|
|
|
text = n,
|
|
|
|
}
|
|
|
|
return
|
|
|
|
end
|
|
|
|
else
|
|
|
|
c[1] = t
|
|
|
|
end
|
|
|
|
else
|
|
|
|
c[1] = string.format('%s %s', c[1], t)
|
|
|
|
end
|
|
|
|
i = i + 1
|
|
|
|
end
|
|
|
|
return c
|
|
|
|
end
|
|
|
|
|
2020-12-21 21:08:10 +01:00
|
|
|
function methods.NewWorkspace(params, i)
|
2020-10-04 00:37:39 +02:00
|
|
|
local args = {
|
|
|
|
clients = {},
|
|
|
|
callback = function (t)
|
|
|
|
t:view_only()
|
|
|
|
end,
|
|
|
|
}
|
|
|
|
|
|
|
|
if params.value[2] ~= '' then
|
|
|
|
args.pwd = params.value[2]
|
|
|
|
end
|
|
|
|
|
|
|
|
for _, s in params:get_child_value(3 - 1):ipairs() do
|
|
|
|
local c = parse_client(s)
|
|
|
|
if c then
|
|
|
|
table.insert(args.clients, c)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
ws.new(params.value[1], args)
|
|
|
|
|
|
|
|
i:return_value(GLib.Variant('()'))
|
|
|
|
end
|
|
|
|
|
|
|
|
local function method_call(_, _, _, _, method, params, invocation)
|
|
|
|
if methods[method] then
|
|
|
|
protected_call(methods[method], params, invocation)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function on_bus_acquired(conn, _)
|
|
|
|
local function arg(name, sig)
|
|
|
|
return Gio.DBusArgInfo {
|
|
|
|
name = name,
|
|
|
|
signature = sig,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
local method = Gio.DBusMethodInfo
|
|
|
|
|
|
|
|
local iface = Gio.DBusInterfaceInfo {
|
|
|
|
name = 'com.github.jcrd.wm_launch.WindowManager',
|
|
|
|
methods = {
|
|
|
|
method {
|
2020-12-21 21:08:10 +01:00
|
|
|
name = 'NewWorkspace',
|
2020-10-04 00:37:39 +02:00
|
|
|
in_args = {
|
|
|
|
arg('name', 's'),
|
|
|
|
arg('pwd', 's'),
|
|
|
|
arg('clients', 'as'),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
conn:register_object('/com/github/jcrd/wm_launch/WindowManager',
|
|
|
|
iface,
|
|
|
|
GObject.Closure(method_call))
|
|
|
|
end
|
|
|
|
|
|
|
|
Gio.bus_own_name(Gio.BusType.SESSION,
|
|
|
|
'com.github.jcrd.wm_launch',
|
|
|
|
Gio.BusNameOwnerFlags.NONE,
|
|
|
|
GObject.Closure(on_bus_acquired))
|
|
|
|
|
2019-09-16 16:01:17 +02:00
|
|
|
return ws
|