summaryrefslogtreecommitdiff
path: root/awesome/lib/shifty.lua
diff options
context:
space:
mode:
Diffstat (limited to 'awesome/lib/shifty.lua')
-rw-r--r--awesome/lib/shifty.lua1138
1 files changed, 0 insertions, 1138 deletions
diff --git a/awesome/lib/shifty.lua b/awesome/lib/shifty.lua
deleted file mode 100644
index 9320295..0000000
--- a/awesome/lib/shifty.lua
+++ /dev/null
@@ -1,1138 +0,0 @@
---- Shifty: Dynamic tagging library, version for awesome v3.5
--- @author koniu <gkusnierz@gmail.com>
--- @author resixian (aka bioe007) <resixian@gmail.com>
--- @author cdump <andreevmaxim@gmail.com>
---
--- https://github.com/cdump/awesome-shifty
--- http://awesome.naquadah.org/wiki/index.php?title=Shifty
-
--- environment
-local type = type
-local ipairs = ipairs
-local table = table
-local string = string
-local beautiful = require("beautiful")
-local awful = require("awful")
-local wibox = require("wibox")
-local pairs = pairs
-local io = io
-local math = math
-local tonumber = tonumber
-local dbg= dbg
-local capi = {
- client = client,
- tag = tag,
- screen = screen,
- button = button,
- mouse = mouse,
- root = root,
- timer = timer
-}
-
-local shifty = {}
-
--- variables
-shifty.config = {}
-shifty.config.tags = {}
-shifty.config.apps = {}
-shifty.config.defaults = {}
-shifty.config.float_bars = false
-shifty.config.guess_name = true
-shifty.config.guess_position = true
-shifty.config.remember_index = true
-shifty.config.sloppy = true
-shifty.config.default_name = "new"
-shifty.config.clientkeys = {}
-shifty.config.globalkeys = nil
-shifty.config.layouts = {}
-shifty.config.prompt_sources = {
- "config_tags",
- "config_apps",
- "existing",
- "history"
-}
-shifty.config.prompt_matchers = {
- "^",
- ":",
- ""
-}
-shifty.config.delete_deserted = true
-
-local matchp = ""
-local index_cache = {}
-for i = 1, capi.screen.count() do index_cache[i] = {} end
-
---name2tags: matches string 'name' to tag objects
--- @param name : tag name to find
--- @param scr : screen to look for tags on
--- @return table of tag objects or nil
-function name2tags(name, scr)
- local ret = {}
- local a, b = scr or 1, scr or capi.screen.count()
- for s = a, b do
- for i, t in ipairs(awful.tag.gettags(s)) do
- if name == t.name then
- table.insert(ret, t)
- end
- end
- end
- if #ret > 0 then return ret end
-end
-
-function name2tag(name, scr, idx)
- local ts = name2tags(name, scr)
- if ts then return ts[idx or 1] end
-end
-
---tag2index: finds index of a tag object
--- @param scr : screen number to look for tag on
--- @param tag : the tag object to find
--- @return the index [or zero] or end of the list
-function tag2index(scr, tag)
- for i, t in ipairs(awful.tag.gettags(scr)) do
- if t == tag then return i end
- end
-end
-
---rename
---@param tag: tag object to be renamed
---@param prefix: if any prefix is to be added
---@param no_selectall:
-function shifty.rename(tag, prefix, no_selectall)
- local theme = beautiful.get()
- local t = tag or awful.tag.selected(capi.mouse.screen)
-
- if t == nil then return end
-
- local scr = awful.tag.getscreen(t)
- local bg = nil
- local fg = nil
- local text = prefix or t.name
- local before = t.name
-
- if t == awful.tag.selected(scr) then
- bg = theme.bg_focus or '#535d6c'
- fg = theme.fg_urgent or '#ffffff'
- else
- bg = theme.bg_normal or '#222222'
- fg = theme.fg_urgent or '#ffffff'
- end
-
- local tag_index = tag2index(scr, t)
- -- Access to textbox widget in taglist
- local tb_widget = shifty.taglist[scr].widgets[tag_index].widget.widgets[2].widget
- awful.prompt.run({
- fg_cursor = fg, bg_cursor = bg, ul_cursor = "single",
- text = text, selectall = not no_selectall},
- tb_widget,
- function (name) if name:len() > 0 then t.name = name; end end,
- completion,
- awful.util.getdir("cache") .. "/history_tags",
- nil,
- function ()
- if t.name == before then
- if awful.tag.getproperty(t, "initial") then shifty.del(t) end
- else
- awful.tag.setproperty(t, "initial", true)
- set(t)
- end
- tagkeys(capi.screen[scr])
- t:emit_signal("property::name")
- end
- )
-end
-
---send: moves client to tag[idx]
--- maybe this isn't needed here in shifty?
--- @param idx the tag number to send a client to
-function send(idx)
- local scr = capi.client.focus.screen or capi.mouse.screen
- local sel = awful.tag.selected(scr)
- local sel_idx = tag2index(scr, sel)
- local tags = awful.tag.gettags(scr)
- local target = awful.util.cycle(#tags, sel_idx + idx)
- awful.client.movetotag(tags[target], capi.client.focus)
- awful.tag.viewonly(tags[target])
-end
-
-function shifty.send_next() send(1) end
-function shifty.send_prev() send(-1) end
-
---pos2idx: translate shifty position to tag index
---@param pos: position (an integer)
---@param scr: screen number
-function pos2idx(pos, scr)
- local v = 1
- if pos and scr then
- local tags = awful.tag.gettags(scr)
- for i = #tags , 1, -1 do
- local t = tags[i]
- if awful.tag.getproperty(t, "position") and
- awful.tag.getproperty(t, "position") <= pos then
- v = i + 1
- break
- end
- end
- end
- return v
-end
-
---select : helper function chooses the first non-nil argument
---@param args - table of arguments
-local function select(args)
- for i, a in pairs(args) do
- if a ~= nil then
- return a
- end
- end
-end
-
---tagtoscr : move an entire tag to another screen
---
---@param scr : the screen to move tag to
---@param t : the tag to be moved [awful.tag.selected()]
---@return the tag
-function shifty.tagtoscr(scr, t)
- -- break if called with an invalid screen number
- if not scr or scr < 1 or scr > capi.screen.count() then return end
- -- tag to move
- local otag = t or awful.tag.selected()
-
- awful.tag.setscreen(otag, scr)
- -- set screen and then reset tag to order properly
- if #otag:clients() > 0 then
- for _ , c in ipairs(otag:clients()) do
- if not c.sticky then
- c.screen = scr
- c:tags({otag})
- else
- awful.client.toggletag(otag, c)
- end
- end
- end
- return otag
-end
-
---set : set a tags properties
---@param t: the tag
---@param args : a table of optional (?) tag properties
---@return t - the tag object
-function set(t, args)
- if not t then return end
- if not args then args = {} end
-
- -- set the name
- t.name = args.name or t.name
-
- -- attempt to load preset on initial run
- local preset = (awful.tag.getproperty(t, "initial") and
- shifty.config.tags[t.name]) or {}
-
- -- pick screen and get its tag table
- local scr = args.screen or
- (not awful.tag.getscreen(t) and awful.tag.getscreen(preset)) or
- awful.tag.getscreen(t) or
- capi.mouse.screen
-
- local clientstomove = nil
- if scr > capi.screen.count() then scr = capi.screen.count() end
- if awful.tag.getscreen(t) and scr ~= awful.tag.getscreen(t) then
- shifty.tagtoscr(scr, t)
- awful.tag.setscreen(t, nil)
- end
- local tags = awful.tag.gettags(scr)
-
- -- try to guess position from the name
- local guessed_position = nil
- if not (args.position or preset.position) and shifty.config.guess_position then
- local num = t.name:find('^[1-9]')
- if num then guessed_position = tonumber(t.name:sub(1, 1)) end
- end
-
- -- allow preset.layout to be a table to provide a different layout per
- -- screen for a given tag
- local preset_layout = preset.layout
- if preset_layout and preset_layout[scr] then
- preset_layout = preset.layout[scr]
- end
-
- -- select from args, preset, getproperty,
- -- config.defaults.configs or defaults
- local props = {
- layout = select{args.layout, preset_layout,
- awful.tag.getproperty(t, "layout"),
- shifty.config.defaults.layout, awful.layout.suit.tile},
- mwfact = select{args.mwfact, preset.mwfact,
- awful.tag.getproperty(t, "mwfact"),
- shifty.config.defaults.mwfact, 0.55},
- nmaster = select{args.nmaster, preset.nmaster,
- awful.tag.getproperty(t, "nmaster"),
- shifty.config.defaults.nmaster, 1},
- ncol = select{args.ncol, preset.ncol,
- awful.tag.getproperty(t, "ncol"),
- shifty.config.defaults.ncol, 1},
- matched = select{args.matched, awful.tag.getproperty(t, "matched")},
- exclusive = select{args.exclusive, preset.exclusive,
- awful.tag.getproperty(t, "exclusive"),
- shifty.config.defaults.exclusive},
- persist = select{args.persist, preset.persist,
- awful.tag.getproperty(t, "persist"),
- shifty.config.defaults.persist},
- nopopup = select{args.nopopup, preset.nopopup,
- awful.tag.getproperty(t, "nopopup"),
- shifty.config.defaults.nopopup},
- leave_kills = select{args.leave_kills, preset.leave_kills,
- awful.tag.getproperty(t, "leave_kills"),
- shifty.config.defaults.leave_kills},
- max_clients = select{args.max_clients, preset.max_clients,
- awful.tag.getproperty(t, "max_clients"),
- shifty.config.defaults.max_clients},
- position = select{args.position, preset.position, guessed_position,
- awful.tag.getproperty(t, "position")},
- icon = select{args.icon and args.icon,
- preset.icon and preset.icon,
- awful.tag.getproperty(t, "icon"),
- shifty.config.defaults.icon and shifty.config.defaults.icon},
- icon_only = select{args.icon_only, preset.icon_only,
- awful.tag.getproperty(t, "icon_only"),
- shifty.config.defaults.icon_only},
- sweep_delay = select{args.sweep_delay, preset.sweep_delay,
- awful.tag.getproperty(t, "sweep_delay"),
- shifty.config.defaults.sweep_delay},
- overload_keys = select{args.overload_keys, preset.overload_keys,
- awful.tag.getproperty(t, "overload_keys"),
- shifty.config.defaults.overload_keys},
- }
-
- -- get layout by name if given as string
- if type(props.layout) == "string" then
- props.layout = getlayout(props.layout)
- end
-
- -- set keys
- if args.keys or preset.keys then
- local keys = awful.util.table.join(shifty.config.globalkeys,
- args.keys or preset.keys)
- if props.overload_keys then
- props.keys = keys
- else
- props.keys = squash_keys(keys)
- end
- end
-
- -- calculate desired taglist index
- local index = args.index or preset.index or shifty.config.defaults.index
- local rel_index = args.rel_index or
- preset.rel_index or
- shifty.config.defaults.rel_index
- local sel = awful.tag.selected(scr)
- --TODO: what happens with rel_idx if no tags selected
- local sel_idx = (sel and tag2index(scr, sel)) or 0
- local t_idx = tag2index(scr, t)
- local limit = (not t_idx and #tags + 1) or #tags
- local idx = nil
-
- if rel_index then
- idx = awful.util.cycle(limit, (t_idx or sel_idx) + rel_index)
- elseif index then
- idx = awful.util.cycle(limit, index)
- elseif props.position then
- idx = pos2idx(props.position, scr)
- if t_idx and t_idx < idx then idx = idx - 1 end
- elseif shifty.config.remember_index and index_cache[scr][t.name] then
- idx = math.min(index_cache[scr][t.name], #tags+1)
- elseif not t_idx then
- idx = #tags + 1
- end
-
- -- if we have a new index, remove from old index and insert
- if idx then
- if t_idx then table.remove(tags, t_idx) end
- table.insert(tags, idx, t)
- index_cache[scr][t.name] = idx
- end
-
- -- set tag properties and push the new tag table
- for i, tmp_tag in ipairs(tags) do
- awful.tag.setscreen(tmp_tag, scr)
- awful.tag.setproperty(tmp_tag, "index", i)
- end
- for prop, val in pairs(props) do awful.tag.setproperty(t, prop, val) end
-
- -- execute run/spawn
- if awful.tag.getproperty(t, "initial") then
- local spawn = args.spawn or preset.spawn or shifty.config.defaults.spawn
- local run = args.run or preset.run or shifty.config.defaults.run
- if spawn and args.matched ~= true then
- awful.util.spawn_with_shell(spawn, scr)
- end
- if run then run(t) end
- awful.tag.setproperty(t, "initial", nil)
- end
-
-
- return t
-end
-
-function shift_next() set(awful.tag.selected(), {rel_index = 1}) end
-function shift_prev() set(awful.tag.selected(), {rel_index = -1}) end
-
---add : adds a tag
---@param args: table of optional arguments
-function shifty.add(args)
- if not args then args = {} end
- local name = args.name or " "
-
- -- initialize a new tag object and its data structure
- local t = awful.tag.add(name, { initial = true })
-
-
- -- apply tag settings
- set(t, args)
-
- -- unless forbidden or if first tag on the screen, show the tag
- if not (awful.tag.getproperty(t, "nopopup") or args.noswitch) or
- #awful.tag.gettags(awful.tag.getscreen(t)) == 1 then
- awful.tag.viewonly(t)
- end
-
- -- get the name or rename
- if args.name then
- t.name = args.name
- else
- -- FIXME: hack to delay rename for un-named tags for
- -- tackling taglist refresh which disabled prompt
- -- from being rendered until input
- awful.tag.setproperty(t, "initial", true)
- local f
- local tmr
- if args.position then
- f = function() shifty.rename(t, args.rename, true); tmr:stop() end
- else
- f = function() shifty.rename(t); tmr:stop() end
- end
- tmr = capi.timer({timeout = 0.01})
- tmr:connect_signal("timeout", f)
- tmr:start()
- end
-
- return t
-end
-
---del : delete a tag
---@param tag : the tag to be deleted [current tag]
-function shifty.del(tag)
- local scr = (tag and awful.tag.getscreen(tag)) or capi.mouse.screen or 1
- local tags = awful.tag.gettags(scr)
- local sel = awful.tag.selected(scr)
- local t = tag or sel
- local idx = tag2index(scr, t)
-
- -- return if tag not empty (except sticky)
- local clients = t:clients()
- local sticky = 0
- for i, c in ipairs(clients) do
- if c.sticky then sticky = sticky + 1 end
- end
- if #clients > sticky then return end
-
- -- store index for later
- index_cache[scr][t.name] = idx
-
- -- remove tag
- awful.tag.delete(t)
-
- -- if the current tag is being deleted, restore from history
- if t == sel and #tags > 1 then
- awful.tag.history.restore(scr, 1)
- -- this is supposed to cycle if history is invalid?
- -- e.g. if many tags are deleted in a row
- if not awful.tag.selected(scr) then
- awful.tag.viewonly(tags[awful.util.cycle(#tags, idx - 1)])
- end
- end
-
- -- FIXME: what is this for??
- if capi.client.focus then capi.client.focus:raise() end
-end
-
---is_client_tagged : replicate behavior in tag.c - returns true if the
---given client is tagged with the given tag
-function is_client_tagged(tag, client)
- for i, c in ipairs(tag:clients()) do
- if c == client then
- return true
- end
- end
- return false
-end
-
---match : handles app->tag matching, a replacement for the manage hook in
--- rc.lua
---@param c : client to be matched
-function match(c, startup)
- local nopopup, intrusive, nofocus, run, slave
- local wfact, struts, geom, float
- local target_tag_names, target_tags = {}, {}
- local typ = c.type
- local cls = c.class
- local inst = c.instance
- local role = c.role
- local name = c.name
- local keys = shifty.config.clientkeys or c:keys() or {}
- local target_screen = capi.mouse.screen
-
- c.border_color = beautiful.border_normal
- c.border_width = beautiful.border_width
-
- -- try matching client to config.apps
- for i, a in ipairs(shifty.config.apps) do
- if a.match then
- local matched = false
- -- match only class
- if not matched and cls and a.match.class then
- for k, w in ipairs(a.match.class) do
- matched = cls:find(w)
- if matched then
- break
- end
- end
- end
- -- match only instance
- if not matched and inst and a.match.instance then
- for k, w in ipairs(a.match.instance) do
- matched = inst:find(w)
- if matched then
- break
- end
- end
- end
- -- match only name
- if not matched and name and a.match.name then
- for k, w in ipairs(a.match.name) do
- matched = name:find(w)
- if matched then
- break
- end
- end
- end
- -- match only role
- if not matched and role and a.match.role then
- for k, w in ipairs(a.match.role) do
- matched = role:find(w)
- if matched then
- break
- end
- end
- end
- -- match only type
- if not matched and typ and a.match.type then
- for k, w in ipairs(a.match.type) do
- matched = typ:find(w)
- if matched then
- break
- end
- end
- end
- -- check everything else against all attributes
- if not matched then
- for k, w in ipairs(a.match) do
- matched = (cls and cls:find(w)) or
- (inst and inst:find(w)) or
- (name and name:find(w)) or
- (role and role:find(w)) or
- (typ and typ:find(w))
- if matched then
- break
- end
- end
- end
- -- set attributes
- if matched then
- if a.screen then target_screen = a.screen end
- if a.tag then
- if type(a.tag) == "string" then
- target_tag_names = {a.tag}
- else
- target_tag_names = a.tag
- end
- end
- if a.startup and startup then
- a = awful.util.table.join(a, a.startup)
- end
- if a.geometry ~=nil then
- geom = {x = a.geometry[1],
- y = a.geometry[2],
- width = a.geometry[3],
- height = a.geometry[4]}
- end
- if a.float ~= nil then float = a.float end
- if a.slave ~=nil then slave = a.slave end
- if a.border_width ~= nil then
- c.border_width = a.border_width
- end
- if a.nopopup ~=nil then nopopup = a.nopopup end
- if a.intrusive ~=nil then
- intrusive = a.intrusive
- end
- if a.fullscreen ~=nil then
- c.fullscreen = a.fullscreen
- end
- if a.honorsizehints ~=nil then
- c.size_hints_honor = a.honorsizehints
- end
- if a.kill ~=nil then c:kill(); return end
- if a.ontop ~= nil then c.ontop = a.ontop end
- if a.above ~= nil then c.above = a.above end
- if a.below ~= nil then c.below = a.below end
- if a.buttons ~= nil then
- c:buttons(a.buttons)
- end
- if a.nofocus ~= nil then nofocus = a.nofocus end
- if a.keys ~= nil then
- keys = awful.util.table.join(keys, a.keys)
- end
- if a.hidden ~= nil then c.hidden = a.hidden end
- if a.minimized ~= nil then
- c.minimized = a.minimized
- end
- if a.dockable ~= nil then
- awful.client.dockable.set(c, a.dockable)
- end
- if a.urgent ~= nil then
- c.urgent = a.urgent
- end
- if a.opacity ~= nil then
- c.opacity = a.opacity
- end
- if a.run ~= nil then run = a.run end
- if a.sticky ~= nil then c.sticky = a.sticky end
- if a.wfact ~= nil then wfact = a.wfact end
- if a.struts then struts = a.struts end
- if a.skip_taskbar ~= nil then
- c.skip_taskbar = a.skip_taskbar
- end
- if a.props then
- for kk, vv in pairs(a.props) do
- awful.client.property.set(c, kk, vv)
- end
- end
- end
- end
- end
-
- -- set key bindings
- c:keys(keys)
-
- -- Add titlebars to all clients when the float, remove when they are
- -- tiled.
- if shifty.config.float_bars then
- shifty.create_titlebar(c)
-
- c:connect_signal("property::floating", function(c)
- if awful.client.floating.get(c) then
- awful.titlebar(c)
- else
- awful.titlebar(c, { size = 0 })
- end
- awful.placement.no_offscreen(c)
- end)
- end
-
- -- set properties of floating clients
- if float ~= nil then
- awful.client.floating.set(c, float)
- awful.placement.no_offscreen(c)
- end
-
- local sel = awful.tag.selectedlist(target_screen)
- if not target_tag_names or #target_tag_names == 0 then
- -- if not matched to some names try putting
- -- client in c.transient_for or current tags
- if c.transient_for then
- target_tags = c.transient_for:tags()
- elseif #sel > 0 then
- for i, t in ipairs(sel) do
- local mc = awful.tag.getproperty(t, "max_clients")
- if intrusive or
- not (awful.tag.getproperty(t, "exclusive") or
- (mc and mc >= #t:clients())) then
- table.insert(target_tags, t)
- end
- end
- end
- end
-
- if (not target_tag_names or #target_tag_names == 0) and
- (not target_tags or #target_tags == 0) then
- -- if we still don't know any target names/tags guess
- -- name from class or use default
- if shifty.config.guess_name and cls then
- target_tag_names = {cls:lower()}
- else
- target_tag_names = {shifty.config.default_name}
- end
- end
-
- if #target_tag_names > 0 and #target_tags == 0 then
- -- translate target names to tag objects, creating
- -- missing ones
- for i, tn in ipairs(target_tag_names) do
- local res = {}
- for j, t in ipairs(name2tags(tn, target_screen) or
- name2tags(tn) or {}) do
- local mc = awful.tag.getproperty(t, "max_clients")
- local tagged = is_client_tagged(t, c)
- if intrusive or
- not (mc and (((#t:clients() >= mc) and not
- tagged) or
- (#t:clients() > mc))) or
- intrusive then
- if awful.tag.getscreen(t) == mouse.screen then
- table.insert(res, t)
- end
- end
- end
- if #res == 0 then
- table.insert(target_tags,
- shifty.add({name = tn,
- noswitch = true,
- matched = true}))
- else
- target_tags = awful.util.table.join(target_tags, res)
- end
- end
- end
-
- -- set client's screen/tag if needed
- target_screen = awful.tag.getscreen(target_tags[1]) or target_screen
- if c.screen ~= target_screen then c.screen = target_screen end
- if slave then awful.client.setslave(c) end
- c:tags(target_tags)
-
- if wfact then awful.client.setwfact(wfact, c) end
- if geom then c:geometry(geom) end
- if struts then c:struts(struts) end
-
- local showtags = {}
- local u = nil
- if #target_tags > 0 and not startup then
- -- switch or highlight
- for i, t in ipairs(target_tags) do
- if not (nopopup or awful.tag.getproperty(t, "nopopup")) then
- table.insert(showtags, t)
- elseif not startup then
- c.urgent = true
- end
- end
- if #showtags > 0 then
- local ident = false
- -- iterate selected tags and and see if any targets
- -- currently selected
- for kk, vv in pairs(showtags) do
- for _, tag in pairs(sel) do
- if tag == vv then
- ident = true
- end
- end
- end
- if not ident then
- awful.tag.viewmore(showtags, c.screen)
- end
- end
- end
-
- if not (nofocus or c.hidden or c.minimized) then
- --focus and raise accordingly or lower if supressed
- if (target and target ~= sel) and
- (awful.tag.getproperty(target, "nopopup") or nopopup) then
- awful.client.focus.history.add(c)
- else
- capi.client.focus = c
- end
- c:raise()
- else
- c:lower()
- end
-
- if shifty.config.sloppy then
- -- Enable sloppy focus
- c:connect_signal("mouse::enter", function(c)
- if awful.client.focus.filter(c) and
- awful.layout.get(c.screen) ~= awful.layout.suit.magnifier then
- capi.client.focus = c
- end
- end)
- end
-
- -- execute run function if specified
- if run then run(c, target) end
-
-end
-
---sweep : hook function that marks tags as used, visited,
---deserted also handles deleting used and empty tags
-function sweep()
- for s = 1, capi.screen.count() do
- for i, t in ipairs(awful.tag.gettags(s)) do
- local clients = t:clients()
- local sticky = 0
- for i, c in ipairs(clients) do
- if c.sticky then sticky = sticky + 1 end
- end
- if #clients == sticky then
- if awful.tag.getproperty(t, "used") and
- not awful.tag.getproperty(t, "persist") then
- if awful.tag.getproperty(t, "deserted") or
- not awful.tag.getproperty(t, "leave_kills") then
- local delay = awful.tag.getproperty(t, "sweep_delay")
- if delay then
- local tmr
- local f = function()
- shifty.del(t); tmr:stop()
- end
- tmr = capi.timer({timeout = delay})
- tmr:connect_signal("timeout", f)
- tmr:start()
- else
- if shifty.config.delete_deserted then
- shifty.del(t)
- end
- end
- else
- if awful.tag.getproperty(t, "visited") and
- not t.selected then
- awful.tag.setproperty(t, "deserted", true)
- end
- end
- end
- else
- awful.tag.setproperty(t, "used", true)
- end
- if t.selected then
- awful.tag.setproperty(t, "visited", true)
- end
- end
- end
-end
-
---getpos : returns a tag to match position
--- @param pos : the index to find
--- @return v : the tag (found or created) at position == 'pos'
-function shifty.getpos(pos, scr_arg)
- local v = nil
- local existing = {}
- local selected = nil
- local scr = scr_arg or capi.mouse.screen or 1
-
- -- search for existing tag assigned to pos
- for i = 1, capi.screen.count() do
- for j, t in ipairs(awful.tag.gettags(i)) do
- if awful.tag.getproperty(t, "position") == pos then
- table.insert(existing, t)
- if t.selected and i == scr then
- selected = #existing
- end
- end
- end
- end
-
- if #existing > 0 then
- -- if there is no selected tag on current screen, look for the first one
- if not selected then
- for _, tag in pairs(existing) do
- if awful.tag.getscreen(tag) == scr then return tag end
- end
-
- -- no tag found, loop through the other tags
- selected = #existing
- end
-
- -- look for the next unselected tag
- i = selected
- repeat
- i = awful.util.cycle(#existing, i + 1)
- tag = existing[i]
-
- if (scr_arg == nil or awful.tag.getscreen(tag) == scr_arg) and not tag.selected then return tag end
- until i == selected
-
- -- if the screen is not specified or
- -- if a selected tag exists on the specified screen
- -- return the selected tag
- if scr_arg == nil or awful.tag.getscreen(existing[selected]) == scr then return existing[selected] end
-
- -- if scr_arg ~= nil and no tag exists on this screen, continue
- end
-
- local screens = {}
- for s = 1, capi.screen.count() do table.insert(screens, s) end
-
- -- search for preconf with 'pos' on current screen and create it
- for i, j in pairs(shifty.config.tags) do
- local tag_scr = j.screen or screens
- if type(tag_scr) ~= 'table' then tag_scr = {tag_scr} end
-
- if j.position == pos and awful.util.table.hasitem(tag_scr, scr) then
- return shifty.add({name = i,
- position = pos,
- noswitch = not switch})
- end
- end
-
- -- not existing, not preconfigured
- return shifty.add({position = pos,
- rename = pos .. ':',
- no_selectall = true,
- noswitch = not switch})
-end
-
---init : search config.tags for initial set of
---tags to open
-function shifty.init()
- local numscr = capi.screen.count()
-
- local screens = {}
- for s = 1, capi.screen.count() do table.insert(screens, s) end
-
- for i, j in pairs(shifty.config.tags) do
- local scr = j.screen or screens
- if type(scr) ~= 'table' then
- scr = {scr}
- end
- for _, s in pairs(scr) do
- if j.init and (s <= numscr) then
- shifty.add({name = i,
- persist = true,
- screen = s,
- layout = j.layout,
- mwfact = j.mwfact})
- end
- end
- end
-end
-
--- Create a titlebar for the given client
--- By default, make it invisible (size = 0)
-
-function shifty.create_titlebar(c)
- -- Widgets that are aligned to the left
- local left_layout = wibox.layout.fixed.horizontal()
- left_layout:add(awful.titlebar.widget.iconwidget(c))
-
- -- Widgets that are aligned to the right
- local right_layout = wibox.layout.fixed.horizontal()
- right_layout:add(awful.titlebar.widget.floatingbutton(c))
- right_layout:add(awful.titlebar.widget.maximizedbutton(c))
- right_layout:add(awful.titlebar.widget.stickybutton(c))
- right_layout:add(awful.titlebar.widget.ontopbutton(c))
- right_layout:add(awful.titlebar.widget.closebutton(c))
-
- -- The title goes in the middle
- local title = awful.titlebar.widget.titlewidget(c)
- title:buttons(awful.util.table.join(
- awful.button({ }, 1, function()
- client.focus = c
- c:raise()
- awful.mouse.client.move(c)
- end),
- awful.button({ }, 3, function()
- client.focus = c
- c:raise()
- awful.mouse.client.resize(c)
- end)
- ))
-
- -- Now bring it all together
- local layout = wibox.layout.align.horizontal()
- layout:set_left(left_layout)
- layout:set_right(right_layout)
- layout:set_middle(title)
-
- awful.titlebar(c, { size = 0 }):set_widget(layout)
-end
-
---count : utility function returns the index of a table element
---FIXME: this is currently used only in remove_dup, so is it really
---necessary?
-function count(table, element)
- local v = 0
- for i, e in pairs(table) do
- if element == e then v = v + 1 end
- end
- return v
-end
-
---remove_dup : used by shifty.completion when more than one
---tag at a position exists
-function remove_dup(table)
- local v = {}
- for i, entry in ipairs(table) do
- if count(v, entry) == 0 then v[#v+ 1] = entry end
- end
- return v
-end
-
---completion : prompt completion
---
-function completion(cmd, cur_pos, ncomp, sources, matchers)
-
- -- get sources and matches tables
- sources = sources or shifty.config.prompt_sources
- matchers = matchers or shifty.config.prompt_matchers
-
- local get_source = {
- -- gather names from config.tags
- config_tags = function()
- local ret = {}
- for n, p in pairs(shifty.config.tags) do
- table.insert(ret, n)
- end
- return ret
- end,
- -- gather names from config.apps
- config_apps = function()
- local ret = {}
- for i, p in pairs(shifty.config.apps) do
- if p.tag then
- if type(p.tag) == "string" then
- table.insert(ret, p.tag)
- else
- ret = awful.util.table.join(ret, p.tag)
- end
- end
- end
- return ret
- end,
- -- gather names from existing tags, starting with the
- -- current screen
- existing = function()
- local ret = {}
- for i = 1, capi.screen.count() do
- local s = awful.util.cycle(capi.screen.count(),
- capi.mouse.screen + i - 1)
- local tags = awful.tag.gettags(s)
- for j, t in pairs(tags) do
- table.insert(ret, t.name)
- end
- end
- return ret
- end,
- -- gather names from history
- history = function()
- local ret = {}
- local f = io.open(awful.util.getdir("cache") ..
- "/history_tags")
- for name in f:lines() do table.insert(ret, name) end
- f:close()
- return ret
- end,
- }
-
- -- if empty, match all
- if #cmd == 0 or cmd == " " then cmd = "" end
-
- -- match all up to the cursor if moved or no matchphrase
- if matchp == "" or
- cmd:sub(cur_pos, cur_pos+#matchp) ~= matchp then
- matchp = cmd:sub(1, cur_pos)
- end
-
- -- find matching commands
- local matches = {}
- for i, src in ipairs(sources) do
- local source = get_source[src]()
- for j, matcher in ipairs(matchers) do
- for k, name in ipairs(source) do
- if name:find(matcher .. matchp) then
- table.insert(matches, name)
- end
- end
- end
- end
-
- -- no matches
- if #matches == 0 then return cmd, cur_pos end
-
- -- remove duplicates
- matches = remove_dup(matches)
-
- -- cycle
- while ncomp > #matches do ncomp = ncomp - #matches end
-
- -- put cursor at the end of the matched phrase
- if #matches == 1 then
- cur_pos = #matches[ncomp] + 1
- else
- cur_pos = matches[ncomp]:find(matchp) + #matchp
- end
-
- -- return match and position
- return matches[ncomp], cur_pos
-end
-
--- tagkeys : hook function that sets keybindings per tag
-function tagkeys(s)
- local sel = awful.tag.selected(s.index)
- local keys = awful.tag.getproperty(sel, "keys") or
- shifty.config.globalkeys
- if keys and sel.selected then capi.root.keys(keys) end
-end
-
--- squash_keys: helper function which removes duplicate
--- keybindings by picking only the last one to be listed in keys
--- table arg
-function squash_keys(keys)
- local squashed = {}
- local ret = {}
- for i, k in ipairs(keys) do
- squashed[table.concat(k.modifiers) .. k.key] = k
- end
- for i, k in pairs(squashed) do
- table.insert(ret, k)
- end
- return ret
-end
-
--- getlayout: returns a layout by name
-function getlayout(name)
- for _, layout in ipairs(shifty.config.layouts) do
- if awful.layout.getname(layout) == name then
- return layout
- end
- end
-end
-
--- add signals before using them
--- Note: these signals are emitted when tag properties
--- are accessed through awful.tag.setproperty
-capi.tag.add_signal("property::initial")
-capi.tag.add_signal("property::used")
-capi.tag.add_signal("property::visited")
-capi.tag.add_signal("property::deserted")
-capi.tag.add_signal("property::matched")
-capi.tag.add_signal("property::selected")
-capi.tag.add_signal("property::position")
-capi.tag.add_signal("property::exclusive")
-capi.tag.add_signal("property::persist")
-capi.tag.add_signal("property::index")
-capi.tag.add_signal("property::nopopup")
-capi.tag.add_signal("property::leave_kills")
-capi.tag.add_signal("property::max_clients")
-capi.tag.add_signal("property::icon_only")
-capi.tag.add_signal("property::sweep_delay")
-capi.tag.add_signal("property::overload_keys")
-
--- replace awful's default hook
-capi.client.connect_signal("manage", match)
-capi.client.connect_signal("unmanage", sweep)
-capi.client.disconnect_signal("manage", awful.tag.withcurrent)
-
-for s = 1, capi.screen.count() do
- awful.tag.attached_connect_signal(s, "property::selected", sweep)
- awful.tag.attached_connect_signal(s, "tagged", sweep)
- capi.screen[s]:connect_signal("tag::history::update", tagkeys)
-end
-
-return shifty
-