diff --git a/docs/module/scratch.md b/docs/module/scratch.md index 4b6c085..8259870 100644 --- a/docs/module/scratch.md +++ b/docs/module/scratch.md @@ -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 - diff --git a/helpers/client.lua b/helpers/client.lua index 4ab468e..d0eaf08 100644 --- a/helpers/client.lua +++ b/helpers/client.lua @@ -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 diff --git a/module/scratchpad.lua b/module/scratchpad.lua index 0dbd57d..301ca2d 100644 --- a/module/scratchpad.lua +++ b/module/scratchpad.lua @@ -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) -