Scratchpad improvements (#96)
* Make scratchpads work with rubato * Set floating to true when animating * Fix for clients becoming invisible after toggling off on other tags * Fixes for animations not getting played when opening/closing scratchpad on multiple tags * Remove old debug code * Fix for edge case when launching an app (not via a scratchpad) and then toggle it off via a scratchpad * Handle changing tag mid turn off animation * Remove disable_floating_on_close * Reorder some stuff * Use the new ended event * Refactor to reduce code duplication * Fix an issue caused by not unsubscribing when switching tag mid animation * Animate also when launching the client * also for 4.3 * Emit the inital_apply signal on unstable * Rename awestore to animation * Consistency * No need for this anymore as we are recalling :apply anyway * Can't have scratchpads opened up as fullscreen / maximized * Floating must be true for animations * Rename awestore to animation * Fix clients teleporting on turn_off when the position was changed from the initial scratchpad position * Rename animation to rubato and notify that awestore is no longer supported * Update documentation * Update scratchpad.lua Co-authored-by: gokul <33443763+JavaCafe01@users.noreply.github.com>
This commit is contained in:
parent
048cf41e0a
commit
0fb8534191
|
@ -6,13 +6,11 @@ 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
|
||||
### Rubato 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.
|
||||
#### Awestore is now deprecated from Bling, we are switching to Rubato.
|
||||
|
||||
Please go over to the [rubato](https://github.com/andOrlando/rubato) repository for installation instructions. Give it a star as well! The animations are completely optional, and if you choose not to use it, you do not need rubato installed.
|
||||
|
||||
### Usage
|
||||
|
||||
|
@ -20,30 +18,38 @@ 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.
|
||||
local rubato = require("rubato") -- 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
|
||||
})
|
||||
-- These are example rubato tables. You can use one for just y, just x, or both.
|
||||
-- The duration and easing is up to you. Please check out the rubato docs to learn more.
|
||||
local anim_y = rubato.timed {
|
||||
pos = 1090,
|
||||
rate = 60,
|
||||
easing = rubato.quadratic,
|
||||
intro = 0.1,
|
||||
duration = 0.3,
|
||||
awestore_compat = true -- This option must be set to true.
|
||||
}
|
||||
|
||||
local anim_x = awestore.tweened(1920, {
|
||||
duration = 300,
|
||||
easing = awestore.easing.cubic_in_out
|
||||
})
|
||||
local anim_x = rubato.timed {
|
||||
pos = -970,
|
||||
rate = 60,
|
||||
easing = rubato.quadratic,
|
||||
intro = 0.1,
|
||||
duration = 0.3,
|
||||
awestore_compat = true -- This option must be set to true.
|
||||
}
|
||||
|
||||
local term_scratch = bling.module.scratchpad {
|
||||
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
|
||||
floating = true, -- Whether it should be floating (MUST BE TRUE FOR ANIMATIONS)
|
||||
geometry = {x=360, y=90, height=900, width=1200}, -- The geometry in a floating state
|
||||
reapply = true, -- Whether all those properties should be reapplied on every new opening of the scratchpad (MUST BE TRUE FOR ANIMATIONS)
|
||||
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.
|
||||
rubato = {x = anim_x, y = anim_y} -- Optional. This is how you can pass in the rubato tables for animations. If you don't want animations, you can ignore this option.
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -67,4 +73,3 @@ The following signals are currently available. `turn_on`, `turn_off` and `inital
|
|||
- `turn_off` fires when the scratchpad is turned off on a tag
|
||||
- `spawn` fires when the scratchpad is launched with the given command
|
||||
- `inital_apply` fires after `spawn`, when a corresponding client has been found and the properties have been applied
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ local _client = {}
|
|||
-- Remove current tag from window's tags
|
||||
--
|
||||
-- @param c A client
|
||||
function _client.turn_off(c)
|
||||
local current_tag = c.screen.selected_tag
|
||||
function _client.turn_off(c, current_tag)
|
||||
if current_tag == nil then current_tag = c.screen.selected_tag end
|
||||
local ctags = {}
|
||||
for k, tag in pairs(c:tags()) do
|
||||
if tag ~= current_tag then table.insert(ctags, tag) end
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
local awful = require("awful")
|
||||
local gears = require("gears")
|
||||
local naughty = require("naughty")
|
||||
|
||||
local ruled
|
||||
if awesome.version ~= "v4.3" then ruled = require("ruled") end
|
||||
|
@ -14,7 +15,11 @@ local Scratchpad = { mt = {} }
|
|||
-- @return The new scratchpad object
|
||||
function Scratchpad:new(args)
|
||||
args = args or {}
|
||||
args.awestore = args.awestore or {}
|
||||
if args.awestore then
|
||||
naughty.notify({title = "Bling Error", text = "Awestore is no longer supported! Please take a look at the scratchpad documentation and use rubato for animations instead."})
|
||||
end
|
||||
|
||||
args.rubato = args.rubato or {}
|
||||
args.in_anim = false
|
||||
local ret = gears.object {}
|
||||
gears.table.crush(ret, Scratchpad)
|
||||
|
@ -34,6 +39,8 @@ function Scratchpad:apply(c)
|
|||
if not c or not c.valid then return end
|
||||
c.floating = self.floating
|
||||
c.sticky = self.sticky
|
||||
c.fullscreen = false
|
||||
c.maximized = false
|
||||
c:geometry({
|
||||
x = self.geometry.x + awful.screen.focused().geometry.x,
|
||||
y = self.geometry.y + awful.screen.focused().geometry.y,
|
||||
|
@ -50,8 +57,42 @@ end
|
|||
|
||||
--- Turns the scratchpad on
|
||||
function Scratchpad:turn_on()
|
||||
local matches = self:find()
|
||||
local c = matches[1]
|
||||
local function animate(c, anim, axis)
|
||||
-- Check for the following scenerio:
|
||||
-- Toggle on scratchpad at tag 1
|
||||
-- Toggle on scratchpad at tag 2
|
||||
-- The animation will instantly end
|
||||
-- as the timer pos is already at the on position
|
||||
-- from toggling on the scratchpad at tag 1
|
||||
if axis == "x" and anim.pos == self.geometry.x then
|
||||
anim.pos = anim:initial()
|
||||
else
|
||||
if anim.pos == self.geometry.y then anim.pos = anim:initial() end
|
||||
end
|
||||
|
||||
anim:subscribe(function(pos)
|
||||
if c and c.valid then
|
||||
if axis == "x" then c.x = pos
|
||||
else c.y = pos end
|
||||
end
|
||||
self.in_anim = true
|
||||
end)
|
||||
|
||||
if axis == "x" then anim:set(self.geometry.x)
|
||||
else anim:set(self.geometry.y) end
|
||||
|
||||
anim.ended:subscribe(function()
|
||||
self.in_anim = false
|
||||
anim:unsubscribe()
|
||||
anim.ended:unsubscribe()
|
||||
anim:reset()
|
||||
end)
|
||||
end
|
||||
|
||||
local c = self:find()[1]
|
||||
local anim_x = self.rubato.x
|
||||
local anim_y = self.rubato.y
|
||||
|
||||
if c and not self.in_anim and c.first_tag and c.first_tag.selected then
|
||||
c:raise()
|
||||
client.focus = c
|
||||
|
@ -62,49 +103,13 @@ function Scratchpad:turn_on()
|
|||
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
|
||||
self.in_anim = true
|
||||
end)
|
||||
end
|
||||
if anim_y then
|
||||
anim_y:subscribe(function(y)
|
||||
if c and c.valid then c.y = y end
|
||||
self.in_anim = true
|
||||
end)
|
||||
end
|
||||
if anim_x then animate(c, anim_x, "x") end
|
||||
if anim_y then animate(c, anim_y, "y") end
|
||||
|
||||
helpers.client.turn_on(c)
|
||||
self:emit_signal("turn_on", c)
|
||||
|
||||
-- Unsubscribe
|
||||
if anim_x then
|
||||
anim_x:set(new_x)
|
||||
local unsub_x
|
||||
unsub_x = anim_x.ended:subscribe(
|
||||
function()
|
||||
self.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()
|
||||
self.in_anim = false
|
||||
unsub_y()
|
||||
end)
|
||||
end
|
||||
return
|
||||
end
|
||||
if not c then
|
||||
|
@ -135,6 +140,11 @@ function Scratchpad:turn_on()
|
|||
-- Some clients fail to gain focus
|
||||
c:activate{}
|
||||
|
||||
if anim_x then animate(c, anim_x, "x") end
|
||||
if anim_y then animate(c, anim_y, "y") end
|
||||
|
||||
self:emit_signal("inital_apply", c)
|
||||
|
||||
-- Discord spawns 2 windows, so keep the rule until the 2nd window shows
|
||||
if c.name ~= "Discord Updater" then ruled.client.remove_rule("scratchpad") end
|
||||
-- In a case Discord is killed before the second window spawns
|
||||
|
@ -146,6 +156,8 @@ function Scratchpad:turn_on()
|
|||
local function inital_apply(c1)
|
||||
if helpers.client.is_child_of(c1, pid) then
|
||||
self:apply(c1)
|
||||
if anim_x then animate(c1, anim_x, "x") end
|
||||
if anim_y then animate(c1, anim_y, "y") end
|
||||
self:emit_signal("inital_apply", c1)
|
||||
client.disconnect_signal("manage", inital_apply)
|
||||
end
|
||||
|
@ -157,53 +169,72 @@ end
|
|||
|
||||
--- Turns the scratchpad off
|
||||
function Scratchpad:turn_off()
|
||||
local matches = self:find()
|
||||
local c = matches[1]
|
||||
local c = self:find()[1]
|
||||
if c and not self.in_anim then
|
||||
local function animate(anim, initial_pos, axis)
|
||||
local current_tag_on_toggled_scratchpad = c.screen.selected_tag
|
||||
|
||||
-- Can't animate non floating clients
|
||||
c.floating = true
|
||||
|
||||
if axis == "x" then anim.pos = c.x
|
||||
else anim.pos = c.y end
|
||||
|
||||
anim:subscribe(function(pos)
|
||||
if c and c.valid then
|
||||
if axis == "x" then c.x = pos
|
||||
else c.y = pos end
|
||||
end
|
||||
self.in_anim = true
|
||||
|
||||
-- Handles changing tag mid animation
|
||||
-- Check for the following scenerio:
|
||||
-- Toggle on scratchpad at tag 1
|
||||
-- Toggle on scratchpad at tag 2
|
||||
-- Toggle off scratchpad at tag 1
|
||||
-- Switch to tag 2
|
||||
-- The client will remain on tag 1
|
||||
-- The client will be removed from tag 2
|
||||
if c.screen.selected_tag ~= current_tag_on_toggled_scratchpad then
|
||||
self.in_anim = false
|
||||
anim:abort()
|
||||
anim:reset()
|
||||
anim:unsubscribe()
|
||||
anim.ended:unsubscribe()
|
||||
if axis == "x" then anim.pos = self.geometry.x
|
||||
else anim.pos = self.geometry.y end
|
||||
helpers.client.turn_off(c, current_tag_on_toggled_scratchpad)
|
||||
self:apply(c)
|
||||
self:emit_signal("turn_off", c)
|
||||
end
|
||||
end)
|
||||
|
||||
anim:set(anim:initial())
|
||||
|
||||
anim.ended:subscribe(function()
|
||||
self.in_anim = false
|
||||
anim:reset()
|
||||
anim:unsubscribe()
|
||||
anim.ended:unsubscribe()
|
||||
helpers.client.turn_off(c)
|
||||
|
||||
-- When toggling off a scratchpad that's present on multiple tags
|
||||
-- depsite still being unminizmied on the other tags it will become invisible
|
||||
-- as it's position could be outside the screen from the animation
|
||||
self:apply(c)
|
||||
|
||||
self:emit_signal("turn_off", c)
|
||||
end)
|
||||
end
|
||||
|
||||
c.sticky = false
|
||||
|
||||
-- Get the tweens
|
||||
local anim_x = self.awestore.x
|
||||
local anim_y = self.awestore.y
|
||||
local anim_x = self.rubato.x
|
||||
local anim_y = self.rubato.y
|
||||
|
||||
-- Subscribe
|
||||
if anim_x then
|
||||
anim_x:subscribe(function(x)
|
||||
if c and c.valid then c.x = x end
|
||||
self.in_anim = true
|
||||
end)
|
||||
end
|
||||
if anim_y then
|
||||
anim_y:subscribe(function(y)
|
||||
if c and c.valid then c.y = y end
|
||||
self.in_anim = true
|
||||
end)
|
||||
end
|
||||
|
||||
-- Unsubscribe
|
||||
if anim_x then
|
||||
anim_x:set(anim_x:initial())
|
||||
local unsub
|
||||
unsub = anim_x.ended:subscribe(
|
||||
function()
|
||||
self.in_anim = false
|
||||
helpers.client.turn_off(c)
|
||||
self:emit_signal("turn_off", c)
|
||||
unsub()
|
||||
end)
|
||||
end
|
||||
if anim_y then
|
||||
anim_y:set(anim_y:initial())
|
||||
|
||||
local unsub
|
||||
unsub = anim_y.ended:subscribe(
|
||||
function()
|
||||
self.in_anim = false
|
||||
helpers.client.turn_off(c)
|
||||
self:emit_signal("turn_off", c)
|
||||
unsub()
|
||||
end)
|
||||
end
|
||||
if anim_x then animate(anim_x, self.geometry.x, "x") end
|
||||
if anim_y then animate(anim_y, self.geometry.y, "y") end
|
||||
|
||||
if not anim_x and not anim_y then
|
||||
helpers.client.turn_off(c)
|
||||
|
@ -215,11 +246,11 @@ end
|
|||
--- Turns the scratchpad off if it is focused otherwise it raises the scratchpad
|
||||
function Scratchpad:toggle()
|
||||
local is_turn_off = false
|
||||
local matches = self:find()
|
||||
local c = self:find()[1]
|
||||
if self.dont_focus_before_close then
|
||||
if matches[1] then
|
||||
local current_tag = matches[1].screen.selected_tag
|
||||
for k, tag in pairs(matches[1]:tags()) do
|
||||
if c then
|
||||
local current_tag = c.screen.selected_tag
|
||||
for k, tag in pairs(c:tags()) do
|
||||
if tag == current_tag then
|
||||
is_turn_off = true
|
||||
break
|
||||
|
@ -234,9 +265,6 @@ function Scratchpad:toggle()
|
|||
end
|
||||
|
||||
if is_turn_off then
|
||||
if self.disable_floating_on_close and matches[1].floating == true then
|
||||
matches[1].floating = false
|
||||
end
|
||||
self:turn_off()
|
||||
else
|
||||
self:turn_on()
|
||||
|
@ -252,4 +280,3 @@ function Scratchpad.mt:__call(...)
|
|||
end
|
||||
|
||||
return setmetatable(Scratchpad, Scratchpad.mt)
|
||||
|
||||
|
|
Loading…
Reference in New Issue