summaryrefslogtreecommitdiff
path: root/scratchpad.lua
blob: fa905f5d47a22ffa65d6836d2dcf60b91e6dd846 (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
131
132
133
134
135
136
---------------------------------------------------------------
-- Basic scratchpad manager for the awesome window manager
---------------------------------------------------------------
-- Coded by: Adrian C. <anrxc@sysphere.org>
-- Licensed under the WTFPL version 2
--   * http://sam.zoy.org/wtfpl/COPYING
---------------------------------------------------------------
-- To use this module add:
--     require("scratchpad")
-- to the top of your rc.lua, and call:
--     scratchpad.set(c, width, height, sticky, screen)
-- from a clientkeys binding, and:
--     scratchpad.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 awful = require("awful")
local capi = {
    mouse = mouse,
    client = client,
    screen = screen
}

-- Scratchpad: Basic scratchpad manager for the awesome window manager
module("scratchpad")

local scratch = {}

-- 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)
    local width  = width  or 0.50
    local height = height or 0.50
    local sticky = sticky or false
    local screen = screen or capi.mouse.screen

    local function setscratch(c)
        -- Scratchpad is floating
        awful.client.floating.set(c, true)

        -- 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({ -- Client is always centered on screen
            x = screengeom.x + (screengeom.width  - width)  / 2,
            y = screengeom.y + (screengeom.height - height) / 2,
            width = width,      height = height
        })

        -- Scratchpad properties
        c.ontop = true
        c.above = true
        c.skip_taskbar = true
        if sticky then c.sticky = true end
        if c.titlebar then awful.titlebar.remove(c) end

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

    -- Prepare a table for storing clients,
    if not scratch.pad then scratch.pad = {}
        -- add unmanage signal for scratchpad clients
        capi.client.add_signal("unmanage", function (c)
            local oc = scratch.pad[screen]
            if oc == c then
                scratch.pad[screen] = nil
            end
        end)
    end

    -- If the scratcphad is emtpy, store the client,
    if not scratch.pad[screen] then
        scratch.pad[screen] = c
        -- then apply geometry and properties
        setscratch(c)
    else -- If a client is already scratched,
        local oc = scratch.pad[screen]
        -- compare it with the focused client
        if oc == c then
            -- If it matches then unscratch and clear the table
            awful.client.floating.toggle(oc)
            oc.sticky, oc.ontop, oc.above = false, false, false
            scratch.pad[screen] = nil
        else -- If they don't match, unscratch and replace it
            oc.hidden, oc.sticky = false, false
            oc.ontop,  oc.above  = false, false
            awful.client.floating.toggle(oc)
            scratch.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)
    local screen = screen or capi.mouse.screen

    -- Check if we have a client on storage,
    if scratch.pad and
       scratch.pad[screen] ~= nil
    then -- and get it out, to play
        local c = scratch.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