Awestore support for scratchpads (#40)
* remove deprecated code * Anims Added awestore support for scratchpad * add checks and fixed bugs * Fixed Bug This fixes the weird behaviour where toggling in the middle of an animation breaks everything. * Tag Preview Edit (Not related to this PR) This makes it so that hidden and minimized windows don't show up on the preview. * add some more checks * added docs
This commit is contained in:
parent
1febdb6978
commit
5b6cab4099
|
@ -6,12 +6,33 @@ An easy way to create multiple scratchpads.
|
|||
|
||||
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.
|
||||
|
||||
### Awestore Animation Support
|
||||
|
||||
To use [awestore](https://github.com/K4rakara/awestore) for animations, you must first install it with `luarocks`.
|
||||
```bash
|
||||
sudo luarocks --lua-version 5.3 install awestore
|
||||
```
|
||||
The animations are completely optional, and if you chose not to use it, you do not need awestore installed.
|
||||
|
||||
### Usage
|
||||
|
||||
To initalize a scratchpad you can do something like the following:
|
||||
|
||||
```lua
|
||||
local bling = require("bling")
|
||||
local awestore = require("awestore") -- Totally optional, only required if you are using animations.
|
||||
|
||||
-- These are example awestore tween stores. You can use one for just y, just x, or both.
|
||||
-- The duration and easing is up to you. Please check out the awestore docs to learn more.
|
||||
local anim_y = awestore.tweened(1100, {
|
||||
duration = 300,
|
||||
easing = awestore.easing.cubic_in_out
|
||||
})
|
||||
|
||||
local anim_x = awestore.tweened(1920, {
|
||||
duration = 300,
|
||||
easing = awestore.easing.cubic_in_out
|
||||
})
|
||||
|
||||
local term_scratch = bling.module.scratchpad:new {
|
||||
command = "wezterm start --class spad", -- How to spawn the scratchpad
|
||||
|
@ -22,6 +43,7 @@ local term_scratch = bling.module.scratchpad:new {
|
|||
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
|
||||
awestore = {x = anim_x, y = anim_y} -- Optional. This is how you can pass in the stores for animations. If you don't want animations, you can ignore this option.
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ local _client = {}
|
|||
--
|
||||
-- @param c A client
|
||||
function _client.turn_off(c)
|
||||
local current_tag = awful.tag.selected(c.screen)
|
||||
local current_tag = c.screen.selected_tag
|
||||
local ctags = {}
|
||||
for k, tag in pairs(c:tags()) do
|
||||
if tag ~= current_tag then table.insert(ctags, tag) end
|
||||
|
@ -20,7 +20,7 @@ end
|
|||
--
|
||||
-- @param c A client
|
||||
function _client.turn_on(c)
|
||||
local current_tag = awful.tag.selected(c.screen)
|
||||
local current_tag = c.screen.selected_tag
|
||||
ctags = {current_tag}
|
||||
for k, tag in pairs(c:tags()) do
|
||||
if tag ~= current_tag then table.insert(ctags, tag) end
|
||||
|
@ -60,8 +60,8 @@ function _client.is_child_of(c, pid)
|
|||
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)
|
||||
return tostring(parent_pid) == tostring(pid) or tostring(parent_pid) ==
|
||||
tostring(c.pid)
|
||||
end
|
||||
|
||||
--- Finds all clients that satisfy the passed rule
|
||||
|
@ -81,5 +81,4 @@ function _client.find(rule)
|
|||
return matches
|
||||
end
|
||||
|
||||
|
||||
return _client
|
||||
|
|
|
@ -3,6 +3,7 @@ local awful = require("awful")
|
|||
local helpers = require(tostring(...):match(".*bling") .. ".helpers")
|
||||
|
||||
local Scratchpad = {}
|
||||
local in_anim = false
|
||||
|
||||
--- Creates a new scratchpad object based on the argument
|
||||
--
|
||||
|
@ -10,6 +11,7 @@ local Scratchpad = {}
|
|||
-- @return The new scratchpad object
|
||||
function Scratchpad:new(info)
|
||||
info = info or {}
|
||||
info.awestore = info.awestore or {}
|
||||
setmetatable(info, self)
|
||||
self.__index = self
|
||||
return info
|
||||
|
@ -44,17 +46,58 @@ end
|
|||
--- Turns the scratchpad on
|
||||
function Scratchpad:turn_on()
|
||||
local matches = self:find()
|
||||
if matches[1] then
|
||||
if matches[1] and not in_anim 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
|
||||
local new_y = c.y
|
||||
local new_x = c.x
|
||||
|
||||
-- Get the tweens
|
||||
local anim_x = self.awestore.x
|
||||
local anim_y = self.awestore.y
|
||||
|
||||
-- Subscribe
|
||||
if anim_x then
|
||||
anim_x:subscribe(function(x)
|
||||
if c and c.valid then c.x = x end
|
||||
in_anim = true
|
||||
end)
|
||||
end
|
||||
if anim_y then
|
||||
anim_y:subscribe(function(y)
|
||||
if c and c.valid then c.y = y end
|
||||
in_anim = true
|
||||
end)
|
||||
end
|
||||
|
||||
helpers.client.turn_on(c)
|
||||
|
||||
-- Unsubscribe
|
||||
if anim_x then
|
||||
anim_x:set(new_x)
|
||||
local unsub_x
|
||||
unsub_x = anim_x.ended:subscribe(
|
||||
function()
|
||||
in_anim = false
|
||||
unsub_x()
|
||||
end)
|
||||
end
|
||||
if anim_y then
|
||||
anim_y:set(new_y)
|
||||
local unsub_y
|
||||
unsub_y = anim_y.ended:subscribe(
|
||||
function()
|
||||
in_anim = false
|
||||
unsub_y()
|
||||
end)
|
||||
end
|
||||
return
|
||||
else
|
||||
-- if no client was found, spawn one, find the corresponding window,
|
||||
-- apply the properties only once (until the next closing)
|
||||
-- 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
|
||||
|
@ -69,9 +112,51 @@ end
|
|||
function Scratchpad:turn_off()
|
||||
local matches = self:find()
|
||||
local c = matches[1]
|
||||
if c then
|
||||
if c and not in_anim then
|
||||
c.sticky = false
|
||||
helpers.client.turn_off(c)
|
||||
|
||||
-- Get the tweens
|
||||
local anim_x = self.awestore.x
|
||||
local anim_y = self.awestore.y
|
||||
|
||||
-- Subscribe
|
||||
if anim_x then
|
||||
anim_x:subscribe(function(x)
|
||||
if c and c.valid then c.x = x end
|
||||
in_anim = true
|
||||
end)
|
||||
end
|
||||
if anim_y then
|
||||
anim_y:subscribe(function(y)
|
||||
if c and c.valid then c.y = y end
|
||||
in_anim = true
|
||||
end)
|
||||
end
|
||||
|
||||
-- Unsubscribe
|
||||
if anim_x then
|
||||
anim_x:set(anim_x:initial())
|
||||
local unsub
|
||||
unsub = anim_x.ended:subscribe(
|
||||
function()
|
||||
in_anim = false
|
||||
helpers.client.turn_off(c)
|
||||
unsub()
|
||||
end)
|
||||
end
|
||||
if anim_y then
|
||||
anim_y:set(anim_y:initial())
|
||||
|
||||
local unsub
|
||||
unsub = anim_y.ended:subscribe(
|
||||
function()
|
||||
in_anim = false
|
||||
helpers.client.turn_off(c)
|
||||
unsub()
|
||||
end)
|
||||
end
|
||||
|
||||
if not anim_x and not anim_y then helpers.client.turn_off(c) end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -26,72 +26,74 @@ local function draw_widget(tag_preview_box, t, tag_preview_image, scale,
|
|||
local tag_screen = t.screen
|
||||
for i, c in ipairs(t:clients()) do
|
||||
|
||||
local img_box = wibox.widget {
|
||||
image = gears.surface.load(c.icon),
|
||||
resize = true,
|
||||
forced_height = 100 * scale,
|
||||
forced_width = 100 * scale,
|
||||
widget = wibox.widget.imagebox
|
||||
}
|
||||
if not c.hidden and not c.minimized then
|
||||
|
||||
if tag_preview_image then
|
||||
if c.prev_content or t.selected then
|
||||
local content
|
||||
if t.selected then
|
||||
content = gears.surface(c.content)
|
||||
else
|
||||
content = gears.surface(c.prev_content)
|
||||
local img_box = wibox.widget {
|
||||
image = gears.surface.load(c.icon),
|
||||
resize = true,
|
||||
forced_height = 100 * scale,
|
||||
forced_width = 100 * scale,
|
||||
widget = wibox.widget.imagebox
|
||||
}
|
||||
|
||||
if tag_preview_image then
|
||||
if c.prev_content or t.selected then
|
||||
local content
|
||||
if t.selected then
|
||||
content = gears.surface(c.content)
|
||||
else
|
||||
content = gears.surface(c.prev_content)
|
||||
end
|
||||
local cr = cairo.Context(content)
|
||||
local x, y, w, h = cr:clip_extents()
|
||||
local img = cairo.ImageSurface.create(cairo.Format.ARGB32,
|
||||
w - x, h - y)
|
||||
cr = cairo.Context(img)
|
||||
cr:set_source_surface(content, 0, 0)
|
||||
cr.operator = cairo.Operator.SOURCE
|
||||
cr:paint()
|
||||
|
||||
img_box = wibox.widget {
|
||||
image = gears.surface.load(img),
|
||||
resize = true,
|
||||
opacity = client_opacity,
|
||||
forced_height = math.floor(c.height * scale),
|
||||
forced_width = math.floor(c.width * scale),
|
||||
widget = wibox.widget.imagebox
|
||||
}
|
||||
end
|
||||
local cr = cairo.Context(content)
|
||||
local x, y, w, h = cr:clip_extents()
|
||||
local img = cairo.ImageSurface.create(cairo.Format.ARGB32,
|
||||
w - x, h - y)
|
||||
cr = cairo.Context(img)
|
||||
cr:set_source_surface(content, 0, 0)
|
||||
cr.operator = cairo.Operator.SOURCE
|
||||
cr:paint()
|
||||
|
||||
img_box = wibox.widget {
|
||||
image = gears.surface.load(img),
|
||||
resize = true,
|
||||
opacity = client_opacity,
|
||||
forced_height = math.floor(c.height * scale),
|
||||
forced_width = math.floor(c.width * scale),
|
||||
widget = wibox.widget.imagebox
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
local client_box = wibox.widget {
|
||||
{
|
||||
nil,
|
||||
local client_box = wibox.widget {
|
||||
{
|
||||
nil,
|
||||
img_box,
|
||||
{
|
||||
nil,
|
||||
img_box,
|
||||
nil,
|
||||
expand = "outside",
|
||||
layout = wibox.layout.align.horizontal
|
||||
},
|
||||
nil,
|
||||
expand = "outside",
|
||||
layout = wibox.layout.align.horizontal
|
||||
widget = wibox.layout.align.vertical
|
||||
},
|
||||
nil,
|
||||
expand = "outside",
|
||||
widget = wibox.layout.align.vertical
|
||||
},
|
||||
forced_height = math.floor(c.height * scale),
|
||||
forced_width = math.floor(c.width * scale),
|
||||
bg = client_bg,
|
||||
border_color = client_border_color,
|
||||
border_width = client_border_width,
|
||||
shape = helpers.shape.rrect(client_radius),
|
||||
widget = wibox.container.background
|
||||
}
|
||||
forced_height = math.floor(c.height * scale),
|
||||
forced_width = math.floor(c.width * scale),
|
||||
bg = client_bg,
|
||||
border_color = client_border_color,
|
||||
border_width = client_border_width,
|
||||
shape = helpers.shape.rrect(client_radius),
|
||||
widget = wibox.container.background
|
||||
}
|
||||
|
||||
client_box.point = {
|
||||
x = math.floor((c.x - geo.x) * scale),
|
||||
y = math.floor((c.y - geo.y) * scale)
|
||||
}
|
||||
|
||||
client_list:add(client_box)
|
||||
client_box.point = {
|
||||
x = math.floor((c.x - geo.x) * scale),
|
||||
y = math.floor((c.y - geo.y) * scale)
|
||||
}
|
||||
|
||||
client_list:add(client_box)
|
||||
end
|
||||
end
|
||||
|
||||
tag_preview_box:setup{
|
||||
|
|
Loading…
Reference in New Issue