summaryrefslogtreecommitdiff
path: root/scratch/pad.lua
blob: a632f38031b9ae4176b84843573374a679cda0cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
---------------------------------------------------------------
-- Basic scratchpad manager for the awesome window manager
---------------------------------------------------------------
-- Coded by: * Adrian C. (anrxc) <anrxc@sysphere.org>
-- Licensed under the WTFPL version 2
--   * http://sam.zoy.org/wtfpl/COPYING
---------------------------------------------------------------
-- To use this module add:
--     local scratch = require("scratch")
-- to the top of your rc.lua, and call:
--     scratch.pad.set(c, width, height, sticky, screen)
-- from a clientkeys binding, and:
--     scratch.pad.toggle(screen)
-- from a globalkeys binding.
--
-- Parameters:
--     c      - Client to scratch or un-scratch
--     width  - Width in absolute pixels, or width percentage
--              when <= 1 (0.50 (50% of the screen) by default)
--     height - Height in absolute pixels, or height percentage
--              when <= 1 (0.50 (50% of the screen) by default)
--     sticky - Visible on all tags, false by default
--     screen - Screen (optional), mouse.screen by default
---------------------------------------------------------------

-- Grab environment
local pairs = pairs
local awful = require("awful")
local capi = {
    mouse = mouse,
    client = client,
    screen = screen
}

-- Scratchpad: basic scratchpad manager for the awesome window manager
module("scratch.pad")

local scratchpad = {}

-- Toggle a set of properties on a client.
local function toggleprop(c, prop)
    c.ontop  = prop.ontop  or false
    c.above  = prop.above  or false
    c.hidden = prop.hidden or false
    c.sticky = prop.stick  or false
    c.skip_taskbar = prop.task or false
end

-- Scratch the focused client, or un-scratch and tile it. If another
-- client is already scratched, replace it with the focused client.
function set(c, width, height, sticky, screen)
    width  = width  or 0.50
    height = height or 0.50
    sticky = sticky or false
    screen = screen or capi.mouse.screen

    local function setscratch(c)
        -- Scratchpad is floating and has no titlebar
        awful.client.floating.set(c, true); awful.titlebar.remove(c)

        -- Scratchpad client properties
        toggleprop(c, {ontop=true, above=true, task=true, stick=sticky})

        -- Scratchpad geometry and placement
        local screengeom = capi.screen[screen].workarea
        if width  <= 1 then width  = screengeom.width  * width  end
        if height <= 1 then height = screengeom.height * height end

        c:geometry({ -- Scratchpad is always centered on screen
            x = screengeom.x + (screengeom.width  - width)  / 2,
            y = screengeom.y + (screengeom.height - height) / 2,
            width = width,      height = height
        })

        -- Scratchpad should not loose focus
        c:raise(); capi.client.focus = c
    end

    -- Prepare a table for storing clients,
    if not scratchpad.pad then scratchpad.pad = {}
        -- add unmanage signal for scratchpad clients
        capi.client.add_signal("unmanage", function (c)
            for scr, cl in pairs(scratchpad.pad) do
                if cl == c then scratchpad.pad[scr] = nil end
            end
        end)
    end

    -- If the scratcphad is emtpy, store the client,
    if not scratchpad.pad[screen] then
        scratchpad.pad[screen] = c
        -- then apply geometry and properties
        setscratch(c)
    else -- If a client is already scratched,
        local oc = scratchpad.pad[screen]
        -- unscratch, and compare it with the focused client
        awful.client.floating.toggle(oc); toggleprop(oc, {})
        -- If it matches clear the table, if not replace it
        if   oc == c then scratchpad.pad[screen] =     nil
        else scratchpad.pad[screen] = c; setscratch(c) end
    end
end

-- Move the scratchpad to the current workspace, focus and raise it
-- when it's hidden, or hide it when it's visible.
function toggle(screen)
    screen = screen or capi.mouse.screen

    -- Check if we have a client on storage,
    if scratchpad.pad and
       scratchpad.pad[screen] ~= nil
    then -- and get it out, to play
        local c = scratchpad.pad[screen]

        -- If it's visible on another tag hide it,
        if c:isvisible() == false then c.hidden = true
            -- and move it to the current worskpace
            awful.client.movetotag(awful.tag.selected(screen), c)
        end

        -- Focus and raise if it's hidden,
        if c.hidden then
            awful.placement.centered(c)
            c.hidden = false
            c:raise(); capi.client.focus = c
        else -- hide it if it's not
            c.hidden = true
        end
    end
end