231 lines
6.5 KiB
Lua
231 lines
6.5 KiB
Lua
local spawn = require("awful.spawn")
|
|
local gtimer = require("gears.timer")
|
|
|
|
local lua_executable = os.getenv("LUA")
|
|
if lua_executable == nil or lua_executable == "" then
|
|
lua_executable = "lua"
|
|
end
|
|
|
|
-- This file provide a simple, yet flexible, test client.
|
|
-- It is used to test the `ruled.client`
|
|
|
|
local test_client_source = [[
|
|
pcall(require, 'luarocks.loader')
|
|
local lgi = require 'lgi'
|
|
local GLib = lgi.require('GLib')
|
|
local Gdk = lgi.require('Gdk')
|
|
local Gtk = lgi.require('Gtk', '3.0')
|
|
local Gio = lgi.require('Gio')
|
|
Gtk.init()
|
|
|
|
local function open_window(class, title, options)
|
|
local window = Gtk.Window {
|
|
default_width = options.default_width or 100,
|
|
default_height = options.default_height or 100,
|
|
title = title
|
|
}
|
|
if options.gravity then
|
|
window:set_gravity(tonumber(options.gravity))
|
|
end
|
|
if options.snid and options.snid ~= "" then
|
|
window:set_startup_id(options.snid)
|
|
end
|
|
if options.resize_increment then
|
|
-- This requires Gtk3, but fails with an obscure message with Gtk2.
|
|
-- Produce a better error message instead.
|
|
assert(tonumber(require("lgi").Gtk._version) >= 3, "Gtk 3 required, but not found")
|
|
local geom = Gdk.Geometry {
|
|
width_inc = 200,
|
|
height_inc = 200,
|
|
}
|
|
window:set_geometry_hints(nil, geom, Gdk.WindowHints.RESIZE_INC)
|
|
end
|
|
if options.maximize_before then
|
|
window:maximize()
|
|
elseif options.unminimize_after then
|
|
window:iconify()
|
|
end
|
|
window:set_wmclass(class, class)
|
|
window:show_all()
|
|
if options.maximize_after then
|
|
window:maximize()
|
|
elseif options.unmaximize_after then
|
|
window:unmaximize()
|
|
elseif options.minimize_after then
|
|
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, function()
|
|
window:iconify()
|
|
end)
|
|
elseif options.unminimize_after then
|
|
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, function()
|
|
window:deiconify()
|
|
end)
|
|
end
|
|
if options.resize_after_width and options.resize_after_height then
|
|
window:resize(
|
|
tonumber(options.resize_after_width), tonumber(options.resize_after_height)
|
|
)
|
|
end
|
|
end
|
|
|
|
local function parse_options(options)
|
|
local result = {}
|
|
for word in string.gmatch(options, "([^,]+)") do
|
|
local key, value = string.match(word, "([^=]+)=?(.*)")
|
|
result[key] = value
|
|
end
|
|
return result
|
|
end
|
|
|
|
-- Start a coroutine for nicer input handling
|
|
local coro = coroutine.wrap(function()
|
|
while true do
|
|
local class = coroutine.yield()
|
|
local title = coroutine.yield()
|
|
local options = coroutine.yield()
|
|
open_window(class, title, parse_options(options))
|
|
end
|
|
end)
|
|
coro()
|
|
|
|
-- Read lines from stdin and feed them to the coroutine
|
|
local stdin = Gio.UnixInputStream.new(0, false)
|
|
stdin = Gio.DataInputStream.new(stdin)
|
|
|
|
local read_start, read_finish
|
|
read_start = function()
|
|
stdin:read_line_async(0, nil, read_finish)
|
|
end
|
|
read_finish = function(...)
|
|
local line, length = stdin.read_line_finish(...)
|
|
if type(length) ~= "number" then
|
|
error("Error reading line: " .. tostring(length))
|
|
end
|
|
|
|
local eof = not line -- Behaviour of up-to-date LGI
|
|
or (tostring(line) == "" and #line ~= length) -- (Ab)use uninitialized variable
|
|
if eof then
|
|
Gtk.main_quit()
|
|
else
|
|
coro(tostring(line)) -- tostring() needed for older LGI versions
|
|
read_start()
|
|
end
|
|
end
|
|
|
|
read_start()
|
|
Gtk:main{...}
|
|
]]
|
|
|
|
local lgi = require("lgi")
|
|
local Gio = lgi.require("Gio")
|
|
|
|
local initialized = false
|
|
local pipe, pid
|
|
|
|
local function init()
|
|
if initialized then return end
|
|
initialized = true
|
|
local cmd = { lua_executable, "-e", test_client_source }
|
|
local _pid, _, stdin, stdout, stderr = awesome.spawn(cmd, false, true, true, true)
|
|
pipe = Gio.UnixOutputStream.new(stdin, true)
|
|
pid = _pid
|
|
stdout = Gio.UnixInputStream.new(stdout, true)
|
|
stderr = Gio.UnixInputStream.new(stderr, true)
|
|
spawn.read_lines(stdout, function(...) print("_client", ...) end)
|
|
spawn.read_lines(stderr, function(...) print("_client", ...) end)
|
|
end
|
|
|
|
-- Hack needed for awesome's Startup Notification machinery
|
|
local function get_snid(sn_rules, callback)
|
|
local success, snid = spawn({ "/bin/true" }, sn_rules, callback)
|
|
assert(success)
|
|
assert(snid)
|
|
return snid
|
|
end
|
|
|
|
local module = {}
|
|
|
|
function module.terminate()
|
|
if not initialized then return end
|
|
|
|
for _, c in ipairs(client.get()) do
|
|
c:kill()
|
|
end
|
|
|
|
pipe:close()
|
|
initialized, pipe = false, nil
|
|
|
|
-- Make a copy to avoid the re-initialized race condition.
|
|
local original_pid = pid
|
|
|
|
gtimer.delayed_call(function()
|
|
awesome.kill(original_pid, 9)
|
|
end)
|
|
|
|
return true
|
|
end
|
|
|
|
local function new(_, class, title, sn_rules, callback, resize_increment, args)
|
|
args = args or {}
|
|
class = class or "test_app"
|
|
title = title or "Awesome test client"
|
|
|
|
init()
|
|
local options = ""
|
|
local snid
|
|
if sn_rules or callback then
|
|
snid = get_snid(sn_rules, callback)
|
|
options = options .. "snid=" .. snid .. ","
|
|
end
|
|
if resize_increment then
|
|
options = options .. "resize_increment,"
|
|
end
|
|
if args.maximize_before then
|
|
options = options .. "maximize_before,"
|
|
end
|
|
if args.maximize_after then
|
|
options = options .. "maximize_after,"
|
|
end
|
|
if args.unmaximize_after then
|
|
options = options .. "unmaximize_after,"
|
|
end
|
|
if args.unminimize_after then
|
|
options = options .. "unminimize_after,"
|
|
end
|
|
if args.minimize_after then
|
|
options = options .. "minimize_after,"
|
|
end
|
|
|
|
if args.size then
|
|
options = table.concat {
|
|
options,
|
|
"default_width=",
|
|
args.size.width, ",",
|
|
"default_height=",
|
|
args.size.height, ","
|
|
}
|
|
end
|
|
if args.resize then
|
|
options = table.concat {
|
|
options,
|
|
"resize_after_width=",
|
|
args.resize.width, ",",
|
|
"resize_after_height=",
|
|
args.resize.height, ","
|
|
}
|
|
end
|
|
if args.gravity then
|
|
assert(type(args.gravity)=="number","Use `lgi.Gdk.Gravity.NORTH_WEST`")
|
|
options = options .. "gravity=" .. args.gravity .. ","
|
|
end
|
|
|
|
local data = class .. "\n" .. title .. "\n" .. options .. "\n"
|
|
local success, msg = pipe:write_all(data)
|
|
assert(success, tostring(msg))
|
|
|
|
return snid
|
|
end
|
|
|
|
return setmetatable(module, {__call = new })
|
|
|
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|