Separate custom bindings from generic bindings

This commit is contained in:
crater2150 2016-04-04 14:54:30 +02:00
parent 6f0a85e0db
commit 6ec1f92bc9
9 changed files with 330 additions and 279 deletions

199
separable/binder.lua Normal file
View file

@ -0,0 +1,199 @@
-- key bindings
local awful = require("awful")
local beautiful = beautiful
local modkey = conf.modkey or "Mod4"
local mb = require("separable.modalbind")
local globalkeys = {}
app_folders = {
"/usr/share/applications",
"/usr/local/share/applications",
os.getenv("HOME") .. "/.local/applications",
os.getenv("HOME") .. "/Desktop"
}
local menubar = require("menubar")
menubar.utils.terminal = conf.cmd.terminal -- Set the terminal for applications that require it
local binder = {modal = mb}
-- {{{ Mouse bindings
root.buttons(awful.util.table.join(
awful.button({ }, 4, awful.tag.viewnext),
awful.button({ }, 5, awful.tag.viewprev)
))
-- }}}
local function spawnf(cmd) return function() awful.util.spawn(cmd) end end
binder.spawn = spawnf
conf.cmd.run = conf.cmd.run or spawnf("dmenu_run")
local function use_layout(layout) return function() awful.layout.set(layout) end end
layoutmap = {
f = { func = use_layout(awful.layout.suit.fair), desc ="Fair" },
h = { func = use_layout(awful.layout.suit.fair.horizontal), desc ="Fair Horizontal" },
t = { func = use_layout(awful.layout.suit.tile), desc ="Tile" },
b = { func = use_layout(awful.layout.suit.tile.bottom), desc ="Tile Bottom" },
m = { func = use_layout(awful.layout.suit.max), desc ="Maximized" },
F = { func = use_layout(awful.layout.suit.max.fullscreen), desc ="Fullscreen" },
Space = { func = use_layout(awful.layout.suit.floating), desc ="Float" }
}
layoutsettings = {
l = { func = function () awful.tag.incmwfact( 0.05) end, desc = "Master bigger" },
h = { func = function () awful.tag.incmwfact(-0.05) end, desc = "Master smaller" },
H = { func = function () awful.tag.incnmaster( 1) end, desc = "More masters" },
L = { func = function () awful.tag.incnmaster(-1) end, desc = "Less masters" },
c = { func = function () awful.tag.incncol( 1) end, desc = "More columns" },
C = { func = function () awful.tag.incncol(-1) end, desc = "Less columns" },
}
local default_bindings = awful.util.table.join(
awful.key({ modkey, "Control" }, "r", awesome.restart),
awful.key({ modkey, "Shift" }, "q", awesome.quit),
awful.key({ modkey, }, "Return", spawnf(conf.cmd.terminal)),
awful.key({ modkey, "Control" }, "n", awful.client.restore),
awful.key({ modkey, "Shift" }, "n",
function()
local tag = awful.tag.selected()
for i=1, #tag:clients() do
awful.client.restore(tag:clients()[i])
end
end),
--{{{ Layout manipulation and client position
awful.key({ modkey }, "j", function ()
awful.client.focus.byidx( 1)
if client.focus then client.focus:raise() end
end),
awful.key({ modkey }, "k", function ()
awful.client.focus.byidx(-1)
if client.focus then client.focus:raise() end
end),
-- Layout manipulation
awful.key({ modkey }, "Tab", function ()
awful.client.focus.history.previous()
if client.focus then
client.focus:raise()
end
end),
awful.key({ "Mod1", }, "Tab", function ()
awful.client.focus.history.previous()
if client.focus then
client.focus:raise()
end
end),
awful.key({ modkey, "Shift" }, "j", function ()
awful.client.swap.byidx( 1)
end),
awful.key({ modkey, "Shift" }, "k", function ()
awful.client.swap.byidx( -1)
end),
awful.key({ modkey, }, "h", function ()
awful.screen.focus_relative(-1)
end),
awful.key({ modkey, }, "l", function ()
awful.screen.focus_relative(1)
end),
--}}}
--{{{ Modal mappings
awful.key({ modkey }, "space", mb.grabf(layoutmap, "Layouts")),
awful.key({ modkey, "Control" }, "space", mb.grabf(layoutsettings, "Layout settings", true)),
--}}}
--{{{ Audio control
awful.key({ }, "XF86AudioLowerVolume", spawnf("amixer set Master 2%-")),
awful.key({ }, "XF86AudioRaiseVolume", spawnf("amixer set Master 2%+")),
awful.key({ }, "XF86AudioMute", spawnf("amixer set Master toggle")),
--}}}
--{{{ Prompt
awful.key({ modkey }, "r", conf.cmd.run),
awful.key({ modkey, "Shift" }, "r", menubar.show)
--}}}
)
function binder.add_bindings(keys)
globalkeys = awful.util.table.join(globalkeys, keys);
return binder
end
function binder.add_default_bindings()
return binder.add_bindings(default_bindings)
end
function binder.apply()
root.keys(globalkeys)
end
local function client_opacity_set(c, default, max, step)
if c.opacity < 0 or c.opacity > 1 then
c.opacity = default
end
if c.opacity * step < (max-step) * step then
c.opacity = c.opacity + step
else
c.opacity = max
end
end
local clientkeys = awful.util.table.join(
awful.key({ modkey, "Shift" }, "f", function (c) c.fullscreen = not c.fullscreen end),
awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end),
awful.key({ modkey, }, "f", awful.client.floating.toggle ),
awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end),
awful.key({ modkey, }, "o", awful.client.movetoscreen ),
awful.key({ modkey, "Shift" }, "h", function (c)
awful.client.movetoscreen(c, mouse.screen - 1)
end),
awful.key({ modkey, "Shift" }, "l", function (c)
awful.client.movetoscreen(c, mouse.screen + 1)
end),
awful.key({ modkey, "Control" }, "o", function (c) c.ontop = not c.ontop end),
awful.key({ modkey, "Shift" }, "a", function (c) c.sticky = not c.sticky end),
awful.key({ modkey, "Shift" }, "r", function (c) c:redraw() end),
awful.key({ modkey, }, "n", function (c) c.minimized = not c.minimized end),
awful.key({ modkey, }, "b", function (c) c.border_width = c.border_width > 0 and 0 or beautiful.border_width end),
awful.key({ modkey, }, "Up", function(c) client_opacity_set(c, 1, 1, 0.1) end),
awful.key({ modkey, }, "Down", function(c) client_opacity_set(c, 1, 0, -0.1) end),
awful.key({ }, "XF86Calculater", awful.client.movetoscreen )
)
local clientbuttons = awful.util.table.join(
awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
awful.button({ modkey }, 1, awful.mouse.client.move),
awful.button({ modkey }, 3, awful.mouse.client.resize))
binder.client = {}
function binder.client.buttons()
return clientbuttons
end
function binder.client.keys()
return clientkeys
end
function binder.client.add_buttons(buttons)
clientbuttons = awful.util.table.join(clientbuttons, buttons);
end
function binder.client.add_bindings(keys)
clientkeys = awful.util.table.join(clientkeys, keys);
end
return binder
-- vim: set fenc=utf-8 tw=80 foldmethod=marker :

238
separable/calendar.lua Normal file
View file

@ -0,0 +1,238 @@
local beautiful = require("beautiful")
local wibox = require("wibox")
local conf = conf
local awful = require("awful")
local log = log
local calendar = {}
local weekdays = {"Su","Mo","Tu","We","Th","Fr","Sa"}
local monthdays = {31,28,31,30,31,30,31,31,30,31,30,31}
local monthnames = {"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"}
local num_rows = 6
local function get_weekday(day)
index = day + conf.calendar.start_week
if index > 7 then
index = index - math.floor(index / 7) * 7
end
print(index)
return weekdays[index]
end
function calendar.setup()
local cal = {}
setmetatable(cal, { __index = calendar })
cal.wibox = wibox({
fg = beautiful.fg_normal,
bg = beautiful.bg_normal,
border_width = 1,
border_color = beautiful.bg_focus,
})
cal.title = wibox.widget.textbox()
cal.layout = wibox.layout.fixed.vertical()
cal.layout:add(cal.title)
cal.wibox:set_widget(cal.layout)
cal.wibox.screen = 1
cal.wibox.visible = false
cal.wibox.ontop = true
cal.title:set_align("center")
cal:set_title("Calendar loading")
local wdays = wibox.layout.flex.horizontal()
local fieldwidth = 0
for day = 1,7,1 do
local label = wibox.widget.textbox()
wdays:add(label)
label:set_align("center")
label:set_markup("<b><i>"..get_weekday(day).."</i></b>")
local w,_ = label:fit(screen[1].geometry.width, screen[1].geometry.height)
fieldwidth = math.max(w, fieldwidth)
if beautiful.fontface then
label:set_font(beautiful.fontface .. " " .. (beautiful.fontsize + 4))
end
end
cal.layout:add(wdays)
local _, title_h = cal.title:fit(0, 0)
local _, wdays_h = wdays:fit(0, 0)
cal.header_height = title_h + wdays_h
cal.header_width = (fieldwidth + 10) * 7
local cols = {}
local days = {}
for row = 1, num_rows, 1 do
days[row] = {}
cols[row] = wibox.layout.flex.horizontal()
for day = 1,7,1 do
days[row][day] = wibox.widget.textbox()
local d = days[row][day]
cols[row]:add(d)
d:set_text("[99]")
d:set_align("center")
if beautiful.fontface then
d:set_font(beautiful.fontface .. " " .. (beautiful.fontsize + 4))
end
end
cal.layout:add(cols[row])
end
cal.cols = cols
cal.days = days
cal.offset = 0
cal:calculate_size()
cal:fill_days()
cal.layout:buttons(awful.util.table.join(
awful.button({ }, 1, function () cal:next() end),
awful.button({ }, 2, function () cal:now() end),
awful.button({ }, 3, function () cal:prev() end)
));
return cal
end
function calendar:calculate_size()
local minheight = 0
local fieldwidth = 0
local inner_minheight = 0
for row = 1, num_rows, 1 do
for day = 1,7,1 do
local w,_ = self.days[row][day]:fit(screen[1].geometry.width, screen[1].geometry.height)
fieldwidth = math.max(w, fieldwidth)
end
_, inner_minheight = self.cols[row]:fit(0, 0)
minheight = minheight + inner_minheight
end
-- _, inner_minheight = self.title:fit(screen[1].geometry.width, screen[1].geometry.height)
-- minheight = minheight + inner_minheight
self.wibox.width = math.max(fieldwidth * 9, self.header_width);
self.wibox.height = math.max(50, minheight) + self.header_height
self.wibox.x = 18
self.wibox.y = 0 -- screen[1].geometry.height - self.wibox.height - 50
end
function calendar:set_day_by_date(row, col, date, current)
if(current == date.day) then
self.days[row][col]:set_markup(
"<span background=\"" .. beautiful.bg_focus
.. "\" foreground=\""..beautiful.fg_focus
.. "\" weight=\"ultrabold\">["..current.."]</span>")
else
self.days[row][col]:set_text(current)
end
end
function calendar:set_day_label(row, col, label)
self.days[row][col]:set_markup(label)
end
function calendar:next()
self.offset = self.offset + 1
self:fill_days()
end
function calendar:prev()
self.offset = self.offset - 1
self:fill_days()
end
function calendar:now()
self.offset = 0
self:fill_days()
end
function calendar:fill_days()
local date = os.date("*t")
if self.offset ~= 0 then
local newdate = {}
newdate.year = date.year
newdate.day = 1
newdate.month = date.month + self.offset
while newdate.month < 1 do
newdate.year = newdate.year - 1
newdate.month = newdate.month + 12
end
while newdate.month > 12 do
newdate.year = newdate.year + 1
newdate.month = newdate.month - 12
end
date = os.date("*t", os.time(newdate))
end
self:set_title(monthnames[date.month] .. " " .. date.year)
local startday = (date.wday - date.day - conf.calendar.start_week) % 7 + 1
local cur_day = 1
for d = 1, startday - 1, 1 do
self.days[1][d]:set_text("")
end
for d = startday, 7, 1 do
if self.offset == 0 then
self:set_day_by_date(1, d, date, cur_day)
else
self.days[1][d]:set_text(cur_day)
end
cur_day = cur_day + 1
end
for r = 2,num_rows,1 do
for d = 1, 7, 1 do
if(cur_day > monthdays[date.month]) then
self.days[r][d]:set_text("")
else
if self.offset == 0 then
self:set_day_by_date(r, d, date, cur_day)
else
self.days[r][d]:set_text(cur_day)
end
end
cur_day = cur_day + 1
end
end
end
function calendar:toggle()
self:update_before_showing()
self.wibox.visible = not self.wibox.visible
end
function calendar:show()
self:update_before_showing()
self.wibox.visible = true
end
function calendar:hide()
self.wibox.visible = false
end
function calendar:update_before_showing()
if not self.wibox.visible then
self:now()
end
end
function calendar:set_title(text)
self.title:set_markup("<span weight=\"bold\" size=\"larger\">"..text.."</span>")
end
-- settings.x_offset < 0 and
-- screen[s].geometry.x - width + settings.x_offset or
-- settings.x_offset
return calendar.setup()

254
separable/modalbind.lua Normal file
View file

@ -0,0 +1,254 @@
local modalbind = {}
local wibox = require("wibox")
local inited = false
local modewidget = {}
local modewibox = { screen = -1 }
local nesting = 0
--local functions
local defaults = {}
defaults.opacity = 1.0
defaults.height = 22
defaults.border_width = 1
defaults.x_offset = 0
defaults.y_offset = 0
defaults.show_options = true
-- Clone the defaults for the used settings
local settings = {}
for key, value in pairs(defaults) do
settings[key] = value
end
local function update_settings()
for s, value in ipairs(modewibox) do
value.border_width = settings.border_width
set_default(s)
value.opacity = settings.opacity
end
end
local aliases = {}
aliases[" "] = "Space"
--- Change the opacity of the modebox.
-- @param amount opacity between 0.0 and 1.0, or nil to use default
function set_opacity(amount)
settings.opacity = amount or defaults.opacity
update_settings()
end
modalbind.set_opacity = set_opacity
--- Change height of the modebox.
-- @param amount height in pixels, or nil to use default
function set_height(amount)
settings.height = amount or defaults.height
update_settings()
end
modalbind.set_height = set_height
--- Change border width of the modebox.
-- @param amount width in pixels, or nil to use default
function set_border_width(amount)
settings.border_width = amount or defaults.border_width
update_settings()
end
modalbind.set_border_width = set_border_width
--- Change horizontal offset of the modebox.
-- set location for the box with set_corner(). The box is shifted to the right
-- if it is in one of the left corners or to the left otherwise
-- @param amount horizontal shift in pixels, or nil to use default
function set_x_offset (amount)
settings.x_offset = amount or defaults.x_offset
update_settings()
end
modalbind.set_x_offset = set_x_offset
--- Change vertical offset of the modebox.
-- set location for the box with set_corner(). The box is shifted downwards if it
-- is in one of the upper corners or upwards otherwise.
-- @param amount vertical shift in pixels, or nil to use default
function set_y_offset(amount)
settings.y_offset = amount or defaults.y_offset
update_settings()
end
modalbind.set_y_offset = set_y_offset
--- Set the corner, where the modebox will be displayed
-- If a parameter is not a valid orientation (see below), the function returns
-- without doing anything
-- @param vertical either top or bottom
-- @param horizontal either left or right
function set_corner(vertical, horizontal)
if (vertical ~= "top" and vertical ~= "bottom") then
return
end
if (horizontal ~= "left" and horizontal ~= "right") then
return
end
settings.corner_v = vertical or defaults.corner_v
settings.corner_h = horizontal or defaults.corner_h
end
modalbind.set_corner = set_corner
function set_show_options(bool)
settings.show_options = bool
end
modalbind.set_show_options = set_show_options
local function getXOffset(s, position)
local offset = 0
if type(position) == "table" then
offset = position.x + screen[s].geometry.x
elseif position == "topleft" or position == "bottomleft" then
offset = screen[s].geometry.x
elseif position == "topright" or position == "bottomright" then
offset = screen[s].geometry.x + screen[s].geometry.width - modewibox[s].width
end
return offset + settings.x_offset
end
local function getYOffset(s,position)
local offset = 0
if type(position) == "table" then
offset = position.y + screen[s].geometry.y
elseif position == "topleft" or position == "topright" then
offset = screen[s].geometry.y
elseif position == "bottomleft" or position == "bottomright" then
offset = screen[s].geometry.y + screen[s].geometry.height - modewibox[s].height
end
return offset + settings.y_offset
end
local function set_default(s, position)
local minwidth, minheight = modewidget[s]:fit(screen[s].geometry.width,
screen[s].geometry.height)
modewibox[s].width = minwidth + 1;
modewibox[s].height = math.max(settings.height, minheight)
local pos = position or "bottomleft"
modewibox[s].x = getXOffset(s, pos)
modewibox[s].y = getYOffset(s, pos)
end
local function ensure_init()
if inited then
return
end
inited = true
for s = 1, screen.count() do
modewidget[s] = wibox.widget.textbox()
modewidget[s]:set_align("left")
if beautiful.fontface then
modewidget[s]:set_font(beautiful.fontface .. " " .. (beautiful.fontsize + 4))
end
modewibox[s] = wibox({
fg = beautiful.fg_normal,
bg = beautiful.bg_normal,
border_width = settings.border_width,
border_color = beautiful.bg_focus,
screen = s
})
local modelayout = {}
modelayout[s] = wibox.layout.fixed.horizontal()
modelayout[s]:add(modewidget[s])
modewibox[s]:set_widget(modelayout[s]);
set_default(s)
modewibox[s].visible = false
modewibox[s].ontop = true
-- Widgets for prompt wibox
modewibox[s].widgets = {
modewidget[s],
layout = wibox.layout.fixed.horizontal
}
end
end
local function show_box(s, map, name)
ensure_init()
modewibox.screen = s
local label = "<b>" .. name .. "</b>"
if settings.show_options then
for key, mapping in pairs(map) do
if key ~= "onClose" then
label = label .. "\n<b>" .. key .. "</b>"
if type(mapping) == "table" then
label = label .. "\t" .. (mapping.desc or "???")
end
end
end
end
modewidget[s]:set_markup(label)
modewibox[s].visible = true
set_default(s)
end
local function hide_box()
local s = modewibox.screen
if s ~= -1 then modewibox[s].visible = false end
end
function grab(keymap, name, stay_in_mode)
if name then
show_box(mouse.screen, keymap, name)
nesting = nesting + 1
end
keygrabber.run(function(mod, key, event)
if key == "Escape" then
if keymap["onClose"] then
keymap["onClose"]()
end
keygrabber.stop()
nesting = 0
hide_box();
return true
end
if event == "release" then return true end
if aliases[key] then
key = aliases[key]
end
if keymap[key] then
keygrabber.stop()
if type(keymap[key]) == "table" then
keymap[key].func()
else
keymap[key]()
end
if stay_in_mode then
grab(keymap, name, true)
else
nesting = nesting - 1
if nesting < 1 then hide_box() end
return true
end
else
print("Unmapped key: \"" .. key .. "\"")
end
return true
end)
end
modalbind.grab = grab
function grabf(keymap, name, stay_in_mode)
return function() grab(keymap, name, stay_in_mode) end
end
modalbind.grabf = grabf
function modebox() return modewibox[mouse.screen] end
modalbind.modebox = modebox
return modalbind

112
separable/mpd.lua Normal file
View file

@ -0,0 +1,112 @@
-- MPD control and playlist editing
-- prompts require dmpc script
local M = {}
local conf = conf
local awful = awful
local log = log
-- local functions
local dmenu, notify, mpc
local defaults = {}
local settings = {}
defaults.replace_on_search = true
defaults.host = "127.0.0.1"
defaults.port = "6600"
for key, value in pairs(defaults) do
settings[key] = value
end
for key, value in pairs(conf.mpd) do
settings[key] = value
end
-- {{{ local helpers
local function mpc(command)
log.spawn("mpc -h " .. settings.host .. " -p " .. settings.port .. " " .. command)
end
local function dmenu(opts)
log.spawn("dmpc -h " .. settings.host .. " -p " .. settings.port .. " " ..
(settings.replace_on_search and "-r" or "-R") .. " " .. opts)
end
local function notify(stext)
if not (naughty == nil) then
naughty.notify({
text= stext
})
end
end
--}}}
M.set_server = function(host, port)
settings.host = host
settings.port = port
notify("Using mpd server " .. settings.host .. ":" .. settings.port)
end
-- {{{ mpd.ctrl submodule
M.ctrl = {}
M.ctrl.toggle = function ()
mpc("toggle")
end
M.ctrl.play = function ()
mpc("play")
end
M.ctrl.pause = function ()
mpc("pause")
end
M.ctrl.next = function ()
mpc("next")
end
M.ctrl.prev = function ()
mpc("prev")
end
-- }}}
-- {{{ mpd.prompt submodule
M.prompt = {}
M.prompt.artist = function()
dmenu("-a")
end
M.prompt.album = function()
dmenu("-a -b")
end
M.prompt.title = function()
dmenu("-a -b -t")
end
M.prompt.title = title
M.prompt.replace_on_search = function(bool)
settings.replace_on_search = bool
end
M.prompt.toggle_replace_on_search = function()
settings.replace_on_search = not settings.replace_on_search
notify("MPD prompts now " ..(
settings.replace_on_search and "replace" or "add to"
).. " the playlist")
end
-- }}}
return M
-- vim: set fenc=utf-8 tw=80 foldmethod=marker :