Scratchpad feature (#35)

This commit is contained in:
Nooo37 2021-04-08 20:17:10 +02:00 committed by GitHub
parent 1f4b1094dc
commit da886cb1c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 174 additions and 10 deletions

View File

@ -19,14 +19,16 @@ All documentation, instructions, and previews are [here](https://nooo37.github.i
- Tiled Wallpaper
- Wallpaper Easy Setup
- Window Swallowing
- Scratchpad
- Signals
- Playerctl
- Widgets
- Tag Preview
## TODO
- [ ] Add a built-in option to animate scratchpads with [awestore](https://github.com/K4rakara/awestore)
- [ ] Add external sources management for the wallpaper module (URLs, RSS feeds, NASA picture of the day, ...)
- [ ] Scratchpad module
- [x] Scratchpad module
- [x] Some more documentation on the tabbed module
- [x] Add a cool alternative tabbar style
- [x] Add another cool tabbar style (we need more styles)

View File

@ -8,6 +8,7 @@
- [Tiled Wallpaper](module/twall.md)
- [Wallpaper Easy Setup](module/wall.md)
- [Window Swallowing](module/swal.md)
- [Scratchpad](module/scratch.md)
- Signals
- [Playerctl](signals/pctl.md)

34
docs/module/scratch.md Normal file
View File

@ -0,0 +1,34 @@
## 🍃 Scratchpad <!-- {docsify-ignore} -->
An easy way to create multiple scratchpads.
### A... what?
You can think about a scratchpad as a window whose visibility can be toggled, but still runs in the background without being visible (or minimized) most of the time. Many people use it to have one terminal in which to perform minor tasks, but it is the most useful for windows which only need a couple seconds in between your actual activity, such as music players or chat applications.
### Usage
To initalize a scratchpad you can do something like the following:
```lua
local bling = require("bling")
local term_scratch = bling.module.scratchpad:new {
command = "wezterm start --class spad", -- How to spawn the scratchpad
rule = { instance = "spad" }, -- The rule that the scratchpad will be searched by
sticky = true, -- Whether the scratchpad should be sticky
autoclose = true, -- Whether it should hide itself when losing focus
floating = true, -- Whether it should be floating
geometry = {x=360, y=90, height=900, width=1200}, -- The geometry in a floating state
reapply = false, -- Whether all those properties should be reapplied on every new opening of the scratchpad
dont_focus_before_close = false, -- When set to true, the scratchpad will be closed by the toggle function regardless of whether its focused or not. When set to false, the toggle function will first bring the scratchpad into focus and only close it on a second call
}
```
Once initalized, you can use the object (which in this case is named `term_scratch`) like this:
```lua
term_scratch:toggle() -- toggles the scratchpads visibility
term_scratch:turn_on() -- turns the scratchpads visibility on
term_scratch:turn_off() -- turns the scratchpads visibility off
```

View File

@ -1,11 +1,12 @@
local awful = require("awful")
local gears = require("gears")
local _client = {}
--- Turn off passed client
-- Remove current tag from window's tags
--
-- @param c a client
-- @param c A client
function _client.turn_off(c)
local current_tag = awful.tag.selected(c.screen)
local ctags = {}
@ -45,5 +46,40 @@ function _client.sync(to_c, from_c)
-- TODO: Should also copy over the position in a tiling layout
end
--- Checks whether the passed client is a childprocess of a given process ID
--
-- @param c A client
-- @param pid The process ID
-- @return True if the passed client is a childprocess of the given PID otherwise false
function _client.is_child_of(c, pid)
-- io.popen is normally discouraged. Should probably be changed
if not c or not c.valid then return false end
if tostring(c.pid) == tostring(pid) then return true end
local pid_cmd = [[pstree -T -p -a -s ]] .. tostring(c.pid) ..
[[ | sed '2q;d' | grep -o '[0-9]*$' | tr -d '\n']]
local handle = io.popen(pid_cmd)
local parent_pid = handle:read("*a")
handle:close()
return tostring(parent_pid) == tostring(pid) or
tostring(parent_pid) == tostring(c.pid)
end
--- Finds all clients that satisfy the passed rule
--
-- @param rule The rule to be searched for
function _client.find(rule)
local function matcher(c) return awful.rules.match(c, rule) end
local clients = client.get()
local findex = gears.table.hasitem(clients, client.focus) or 1
local start = gears.math.cycle(#clients, findex + 1)
local matches = {}
for c in awful.client.iterate(matcher, start) do
matches[#matches + 1] = c
end
return matches
end
return _client

View File

@ -3,5 +3,6 @@ return {
tiled_wallpaper = require(... .. ".tiled_wallpaper"),
wallpaper = require(... .. ".wallpaper"),
flash_focus = require(... .. ".flash_focus"),
tabbed = require(... .. ".tabbed")
tabbed = require(... .. ".tabbed"),
scratchpad = require(... .. ".scratchpad")
}

95
module/scratchpad.lua Normal file
View File

@ -0,0 +1,95 @@
local awful = require("awful")
local helpers = require(tostring(...):match(".*bling") .. ".helpers")
local Scratchpad = {}
--- Creates a new scratchpad object based on the argument
--
-- @param info A table of possible arguments
-- @return The new scratchpad object
function Scratchpad:new(info)
info = info or {}
setmetatable(info, self)
self.__index = self
return info
end
--- Find all clients that satisfy the the rule
--
-- @return A list of all clients that satisfy the rule
function Scratchpad:find()
return helpers.client.find(self.rule)
end
--- Applies the objects scratchpad properties to a given client
--
-- @param c A client to which to apply the properties
function Scratchpad:apply(c)
if not c or not c.valid then return end
c.floating = self.floating
c.sticky = self.sticky
c:geometry(self.geometry)
if self.autoclose then
c:connect_signal("unfocus", function(c)
c.sticky = false -- client won't turn off if sticky
helpers.client.turn_off(c)
end)
end
end
--- Turns the scratchpad on
function Scratchpad:turn_on()
local matches = self:find()
if matches[1] then
-- if a client was found, turn it on
c = matches[1]
if self.reapply then self:apply(c) end
-- c.sticky was set to false in turn_off so it has to be reapplied anyway
c.sticky = self.sticky
helpers.client.turn_on(c)
return
else
-- if no client was found, spawn one, find the corresponding window,
-- apply the properties only once (until the next closing)
local pid = awful.spawn.with_shell(self.command)
local function inital_apply(c)
if helpers.client.is_child_of(c, pid) then self:apply(c) end
client.disconnect_signal("manage", inital_apply)
end
client.connect_signal("manage", inital_apply)
return
end
end
--- Turns the scratchpad off
function Scratchpad:turn_off()
local matches = self:find()
local c = matches[1]
if c then
c.sticky = false
helpers.client.turn_off(c)
end
end
--- Turns the scratchpad off if it is focused otherwise it raises the scratchpad
function Scratchpad:toggle()
local is_turn_off = false
if self.dont_focus_before_close then
local matches = self:find()
if matches[1] and matches[1].first_tag then
is_turn_off = matches[1].first_tag.selected
end
else
is_turn_off = client.focus and awful.rules.match(client.focus, self.rule)
end
if is_turn_off then
self:turn_off()
else
self:turn_on()
end
end
return Scratchpad

View File

@ -31,14 +31,9 @@ end
local function manage_clientspawn(c)
-- get the last focused window to check if it is a parent window
local parent_client=awful.client.focus.history.get(c.screen, 1)
if not parent_client then return end
if not parent_client or not parent_client.valid then return end
-- io.popen is normally discouraged. Should probably be changed
local handle = io.popen([[pstree -T -p -a -s ]] .. tostring(c.pid) .. [[ | sed '2q;d' | grep -o '[0-9]*$' | tr -d '\n']])
local parent_pid = handle:read("*a")
handle:close()
if (tostring(parent_pid) == tostring(parent_client.pid)) and check_if_swallow(c) then
if helpers.client.is_child_of(c, parent_client.pid) and check_if_swallow(c) then
c:connect_signal("unmanage", function()
helpers.client.turn_on(parent_client)