From 23c922db3dc4dda1f3f28168be45aa5497e4d159 Mon Sep 17 00:00:00 2001 From: crater2150 Date: Fri, 16 Mar 2012 00:52:06 +0100 Subject: [PATCH] modal bindings and extended mpd capabilities --- aweswt.lua | 34 ++- bindings.lua | 238 ++++++++-------- localconf.lua.template | 2 - luampd.lua | 601 +++++++++++++++++++++++++++++++++++++++++ modalbind.lua | 148 ++++++++++ mpd.lua | 150 ++++++++++ mpd_prompt.lua | 78 ------ rc.lua | 3 - rules.lua | 2 +- tags.lua | 18 +- wibox.lua | 4 +- zenburn/theme.lua | 2 +- 12 files changed, 1064 insertions(+), 216 deletions(-) create mode 100644 luampd.lua create mode 100644 modalbind.lua create mode 100644 mpd.lua delete mode 100644 mpd_prompt.lua diff --git a/aweswt.lua b/aweswt.lua index c9c8120..f743c45 100644 --- a/aweswt.lua +++ b/aweswt.lua @@ -1,17 +1,24 @@ -- aweswt.lua -- Application switcher using dmenu -- -local io = io -local table = table -local pairs = pairs -local awful = awful -local client = client -local string = string -local USE_NAME = true -module("aweswt") +local M = {} -function get_out (a) +local dmenu = "dmenu -nf '#888888' -nb '#222222' -sf '#ffffff' -sb '#285577' -p 'switch to application:' -fn 'Terminus 8' -i" + +local get_out, get_input, _switch + +-- switch with window titles +M.switch = function() + _switch(true) +end + +-- switch with client instance and class +M.switch_class = function() + _switch(false) +end + +get_out = function (a) local f = io.popen(a) t = {} for line in f:lines() do @@ -20,13 +27,12 @@ function get_out (a) return t end -function get_input (a) - local dmenu = "dmenu -nf '#888888' -nb '#222222' -sf '#ffffff' -sb '#285577' -p 'switch to application:' -fn 'Terminus 8' -i" +get_input = function (a) s1 = 'echo "' .. a .. '" | ' .. dmenu return get_out(s1) end -function switch () +_switch = function(use_name) local clients = client.get() if table.getn(clients) == 0 then @@ -39,8 +45,7 @@ function switch () for key, client in pairs(clients) do local app - if USE_NAME then - --app = key .. ':' .. string.sub(client['name'], 1, 20) + if use_name then app = client['name'] else app = key .. ':' .. client['instance'] .. '.' .. client['class'] @@ -64,3 +69,4 @@ function switch () end end +return M diff --git a/bindings.lua b/bindings.lua index 1d93296..d6a1141 100644 --- a/bindings.lua +++ b/bindings.lua @@ -1,3 +1,6 @@ +local aweswt = require("aweswt") +local mb = require("modalbind") +local mpd = require("mpd") -- {{{ Mouse bindings root.buttons(awful.util.table.join( @@ -7,128 +10,149 @@ awful.button({ }, 5, awful.tag.viewprev) -- }}} +mpdmap = { + name = "MPD", + m = mpd.ctrl.toggle, + n = mpd.ctrl.next, + N = mpd.ctrl.prev, + s = function() awful.util.spawn("mpd") end, + g = function () awful.util.spawn(cmd.mpd_client) end, + d = mpd.disconnect, + c = mpd.connect +} +mpdpromts = { + name = "MPD PROMPTS", + a = mpd.prompt.artist, + A = mpd.prompt.album, + t = mpd.prompt.title, + r = mpd.prompt.toggle_replace_on_search, +} + +progmap = { + name = "PROGRAMS", + f = function () awful.util.spawn(cmd.browser) end, + i = function () awful.util.spawn(cmd.im_client) end, + m = function () awful.util.spawn(cmd.mail_client) end +} + -- {{{ Key bindings globalkeys = awful.util.table.join( ---{{{ Focus and Tags - awful.key({ modkey, }, "Left", awful.tag.viewprev ), - awful.key({ modkey, }, "Right", awful.tag.viewnext ), - awful.key({ modkey, }, "Escape", awful.tag.history.restore), + --{{{ Focus and Tags + awful.key({ modkey, }, "Left", awful.tag.viewprev ), + awful.key({ modkey, }, "Right", awful.tag.viewnext ), + awful.key({ modkey, }, "Escape", awful.tag.history.restore), - 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), + 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), - awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative( 1) end), - awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative(-1) end), ---}}} + awful.key({ modkey, "Control" }, "j", function () + awful.screen.focus_relative( 1) + end), - --{{{ Layout manipulation - 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, }, "u", awful.client.urgent.jumpto), - 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), - --}}} --- - --{{{ Spawns - awful.key({ modkey, }, "Return", function () awful.util.spawn(terminal) end), - awful.key({ modkey, }, "f", function () awful.util.spawn("webbrowser") end), - awful.key({ modkey, }, "t", function () awful.util.spawn("mail-client") end), - awful.key({ modkey, }, "p", function () awful.util.spawn("im-client") end), - awful.key({ modkey, }, "g", function () awful.util.spawn("gmpc") end), - awful.key({ modkey, }, "w", function () awful.util.spawn("awsetbg -a -r /home/crater2150/.config/awesome/walls/ &") end), - awful.key({ modkey, "Control" }, "r", awesome.restart), - awful.key({ modkey, "Shift" }, "q", awesome.quit), - awful.key({ }, "Menu", aweswt.switch), - awful.key({ modkey }, "BackSpace", rodentbane.start), - --}}} - - --{{{ tabletpc keys + awful.key({ modkey, "Control" }, "k", function () + awful.screen.focus_relative(-1) + end), - awful.key({ hyper }, "6", function () awful.util.spawn("/usr/local/bin/rotate") end), - awful.key({ modkey }, "x", function () teardrop("cellwriter","top","center", 0.99, 0.4)end ), - awful.key({ modkey, "Control" }, "Delete", function () awful.util.spawn("xlock") end), + awful.key({ }, "Menu", aweswt.switch), + --}}} - awful.key({ hyper }, "1", function () awful.util.spawn("/usr/local/bin/tabletstick 1") end), - awful.key({ hyper }, "2", function () awful.util.spawn("/usr/local/bin/tabletstick 2") end), - awful.key({ hyper }, "3", function () awful.util.spawn("/usr/local/bin/tabletstick 3") end), - awful.key({ hyper }, "4", function () awful.util.spawn("/usr/local/bin/tabletstick 4") end), - awful.key({ hyper }, "5", function () awful.util.spawn("/usr/local/bin/tabletstick 4") end), + --{{{ Layout manipulation + 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, }, "u", awful.client.urgent.jumpto), + 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, }, "l", function () awful.tag.incmwfact( 0.05) end), + awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end), + awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1) end), + awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end), + awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1) end), + awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1) end), + awful.key({ modkey, }, "space", function () awful.layout.inc(layouts, 1) end), + awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, 0) end), + + --}}} + + awful.key({ modkey, "Control" }, "r", awesome.restart), + awful.key({ modkey, "Shift" }, "q", awesome.quit), + awful.key({ modkey, }, "Return", function () awful.util.spawn(cmd.terminal) end), + + --{{{ Modal mappings + + awful.key({ modkey }, "m", function () mb.grab(mpdmap, true) end), + awful.key({ modkey, "Shift" }, "m", function () mb.grab(mpdpromts) end), + awful.key({ modkey }, "c", function () mb.grab(progmap) end), + + --}}} + + --{{{ Audio control + + awful.key({ }, "XF86AudioLowerVolume", function () awful.util.spawn("amixer set Master 2%-")end ), + awful.key({ }, "XF86AudioRaiseVolume", function () awful.util.spawn("amixer set Master 2%+")end ), + awful.key({ }, "XF86AudioMute", function () awful.util.spawn("amixer set Master toggle") end), + awful.key({ }, "XF86AudioPlay", mpd.ctrl.toggle), + awful.key({ }, "XF86AudioNext", mpd.ctrl.next), + awful.key({ }, "XF86AudioPrev", mpd.ctrl.prev), --}}} - --{{{ thinkpad + -- {{{ teardrops + awful.key({ }, "F12", function () teardrop(cmd.terminal,"center","center", 0.99, 0.7)end ), + awful.key({ modkey }, "`", function () teardrop("urxvtc -e ncmpcpp","bottom","center", 0.99, 0.4)end ), + awful.key({ }, "Print", function () teardrop("urxvtc -e alsamixer","top","center", 0.99, 0.4)end ), + -- }}} - awful.key({ }, "XF86Sleep", function () awful.util.spawn("/usr/local/bin/s2ram")end ), - awful.key({ }, "XF86Away", function () awful.util.spawn("xlock")end ), - awful.key({ }, "XF86TouchpadToggle", function () awful.util.spawn("touchpad")end ), + --{{{ Prompt + + awful.key({ modkey }, "r", function () + obvious.popup_run_prompt.set_prompt_string(" Run~ ") + obvious.popup_run_prompt.set_cache("history") + obvious.popup_run_prompt.set_run_function(awful.util.spawn) + obvious.popup_run_prompt.run_prompt() + end), + awful.key({ modkey }, "e", function () + obvious.popup_run_prompt.set_prompt_string(" exec Lua~ ") + obvious.popup_run_prompt.set_cache("history_eval") + obvious.popup_run_prompt.set_run_function(awful.util.eval) + obvious.popup_run_prompt.run_prompt() + end), --}}} - - --{{{ Audio control - awful.key({ }, "Print", function () teardrop("urxvtc -e alsamixer","top","center", 0.99, 0.4)end ), - awful.key({ }, "XF86AudioLowerVolume", function () awful.util.spawn("amixer set Master 2%-")end ), - awful.key({ }, "XF86AudioRaiseVolume", function () awful.util.spawn("amixer set Master 2%+")end ), - awful.key({ }, "XF86AudioMute", function () awful.util.spawn("amixer set Master toggle") end), - awful.key({ modkey }, "m", function () awful.util.spawn("mpc toggle") end), - awful.key({ modkey }, ">", function () awful.util.spawn("mpc next") end), - awful.key({ modkey }, "<", function () awful.util.spawn("mpc prev") end), - awful.key({ modkey , "Shift" }, "m", mpd_prompt.grabber), - awful.key({ }, "XF86AudioPlay", function () awful.util.spawn("mpc toggle") end), - awful.key({ }, "XF86AudioNext", function () awful.util.spawn("mpc next") end), - awful.key({ }, "XF86AudioPrev", function () awful.util.spawn("mpc prev") end), - awful.key({ modkey }, "`", function () teardrop("urxvtc -e ncmpcpp","bottom","center", 0.99, 0.4)end ), - --}}} + --{{{ misc. XF86 Keys - --{{{ Prompt + awful.key({ }, "XF86Sleep", function () awful.util.spawn("/usr/local/bin/s2ram")end ), + awful.key({ }, "XF86Away", function () awful.util.spawn("xlock")end ), + awful.key({ }, "XF86TouchpadToggle", function () awful.util.spawn("touchpad")end ), - awful.key({ modkey }, "r", function () - obvious.popup_run_prompt.set_prompt_string(" Run~ ") - obvious.popup_run_prompt.set_cache("history") - obvious.popup_run_prompt.set_run_function(awful.util.spawn) - obvious.popup_run_prompt.run_prompt() - end), - awful.key({ modkey }, "e", function () - obvious.popup_run_prompt.set_prompt_string(" exec Lua~ ") - obvious.popup_run_prompt.set_cache("history_eval") - obvious.popup_run_prompt.set_run_function(awful.util.eval) - obvious.popup_run_prompt.run_prompt() - end), - awful.key({ }, "F12", function () teardrop(terminal,"center","center", 0.99, 0.7)end ), + --}}} - --}}} - - --{{{ Default - awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end), - awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end), - awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1) end), - awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end), - awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1) end), - awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1) end), - awful.key({ modkey, }, "space", function () awful.layout.inc(layouts, 1) end), - awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, 0) end) - - --}}} + awful.key({ modkey }, "BackSpace", rodentbane.start) ) function client_opacity_set(c, default, max, step) @@ -159,7 +183,7 @@ clientkeys = awful.util.table.join( awful.key({ }, "XF86Calculater", awful.client.movetoscreen ) ) --- Compute the maximum number of digit we need, limited to 9 +-- Compute the maximum number of digit we need, limited to 22 keynumber = 0 for s = 1, screen.count() do keynumber = math.min(22, math.max(#tags[s], keynumber)); @@ -214,3 +238,5 @@ clientbuttons = awful.util.table.join( -- Set keys root.keys(globalkeys) -- }}} +-- vim: set fenc=utf-8 tw=80 foldmethod=marker : + diff --git a/localconf.lua.template b/localconf.lua.template index 2007e58..78c312d 100644 --- a/localconf.lua.template +++ b/localconf.lua.template @@ -1,5 +1,3 @@ terminal = "urxvtc -e tmux" -editor_cmd = "urxvtc -e vim" modkey = "Mod4" -hyper = "Mod3" rule_screen=1 diff --git a/luampd.lua b/luampd.lua new file mode 100644 index 0000000..72f205a --- /dev/null +++ b/luampd.lua @@ -0,0 +1,601 @@ +------------------------------------------------------------------- +-- Copyright (c) 2006 Stephen M. Jothen +-- All rights reserved. +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions +-- are met: +-- 1. Redistributions of source code must retain the above copyright +-- notice, this list of conditions and the following disclaimer. +-- 2. Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- 3. The name of the author may not be used to endorse or promote products +-- derived from this software without specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +-- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +-- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +------------------------------------------------------------------- +-- LuaMPD - Lua interface to the MusicPD protocol +-- +-- Author: Steve Jothen +------------------------------------------------------------------- + +------------------------------------------------ +-- Classes and requires +------------------------------------------------ + +local socket = require("socket") +local luampd = {} + +------------------------------------------------ +-- Private functions and tables +------------------------------------------------ + +-- errors taken from ack.h in the mpd sources +local err_table = { + ["1"] = "ACK_ERROR_NOT_LIST", + ["2"] = "ACK_ERROR_ARG", + ["3"] = "ACK_ERROR_PASSWORD", + ["4"] = "ACK_ERROR_PERMISSION", + ["5"] = "ACK_ERROR_UNKNOWN", + + ["50"] = "ACK_ERROR_NO_EXIST", + ["51"] = "ACK_ERROR_PLAYLIST_MAX", + ["52"] = "ACK_ERROR_SYSTEM", + ["53"] = "ACK_ERROR_PLAYLIST_LOAD", + ["54"] = "ACK_ERROR_UPDATE_ALREADY", + ["55"] = "ACK_ERROR_PLAYER_SYNC", + ["56"] = "ACK_ERROR_EXIST", +} + +-- turns a table of strings into groups seperated by a +-- delimiting string, and then turns each group of lines +-- into key, value pair tables +local function multi_hash(delimiter, lines) + local size = table.maxn(lines) + local patches = {} + local patch = {} + + while size >= 1 do + + if string.find(lines[size], delimiter) then + -- add to the patches repository + local k, v = socket.skip(2, string.find(lines[size], "(.+):%s(.+)")) + + if k and v then + -- we have our key value pair! + patch[string.lower(k)] = v + -- we want the key to be lowercase + end + + table.insert(patches, patch) + patch = {} + + else + -- were still modifying the current patch + local k, v = socket.skip(2, string.find(lines[size], "(.+):%s(.+)")) + + if k and v then + patch[string.lower(k)] = v + end + + end + + size = size - 1 + + end + + return patches +end + +-- will turn a table of strings that match +-- key: value +-- into a table such as { key = value, key2 = value2 } +local function hash(lines) + local hash = {} + for key, value in pairs(lines) do + local k, v = socket.skip(2, string.find(value, "(.+):%s(.+)")) + if k and v then + -- lowercase the key for easier access (tabl.artist rather than tabl.Artist) + hash[string.lower(k)] = v + end + end + return hash +end + + +local function handle_error(line) + -- line is the actual error line received from mpd + local err_num, com_num = socket.skip(2, string.find(line, "ACK %[(%d+)@(%d+)%]")) + if err_table[err_num] then + error(err_table[err_num]) + else + -- unknown error + error(err_table["5"]) + end +end + +local function get_response(obj, command) + + -- collect the lines into this table + local response_lines = {} + + if obj.socket then + obj.socket:send(command .. '\n') + -- send the command with newline and collect response + -- a response is everything up until an ACK or OK + local line = obj.socket:receive("*l") + while (line ~= "OK") do + if line == nil then + -- bug?? on ubuntu mpd will close socket randomly + -- with large playlists while listing them + -- try playlistinfo (with playlist size > 13000) + error("SOCKET_ERROR") + elseif string.sub(line, 1, 3) == "ACK" then + break + -- let us handle this erro + end + table.insert(response_lines, line) + line = obj.socket:receive("*l") + end + -- if we stopped on an ACK then we better return information about it.. + -- last line in the table will be the ack message + if string.sub(line, 1, 3) == "ACK" then + handle_error(line) + --elseif line == "OK" then + -- return true + else + return response_lines + end + else + -- not connected?? + error("SOCKET_ERROR") + end + +end + +------------------------------------------------ +-- Public instance methods +------------------------------------------------ + +function luampd:new(info) + + -- local instance of object + + local instance = { + hostname = info.hostname or "localhost", + password = info.password or nil, + port = info.port or 6600, + debug = info.debug or false, + } + + instance.socket = socket.connect(instance.hostname, instance.port) + + if instance.socket then + -- try and get ok from the server + local line = instance.socket:receive("*l") + if line:find("OK MPD (.+)") then + -- connected, send password + if instance.password then + instance.socket:send(string.format("password %s\n", self.password)) + -- correct password? + local ok_pass = instance.socket:receive("*l") + if ok_pass ~= "OK" then + error(string.format("Wrong password to %s:d", instance.hostname, instance.port)) + end + end + else + -- not mpd or wrong hostname + error(string.format("Cant get response from %s:%d", instance.hostname, instance.port)) + end + else + -- socket.connect returns nil, somethings wrong + error(string.format("Socket cant connect to %s:%d", instance.hostname, instance.port)) + end + + return setmetatable(instance, { __index = luampd }) + +end + +------------------------------------------------ +-- Admin functions +------------------------------------------------ + +-- Some of these functions are in the documentation but dont work? +-- disableoutput, enableoutput +function luampd:disableoutput(outputid) + get_response(self, string.format("disableoutput %d", outputid)) +end + +function luampd:enableoutput(outputid) + get_response(self, string.format("enableoutput %d", outputid)) +end + +function luampd:kill() + get_response(self, "kill") + self.socket = nil +end + +function luampd:outputs() + local response = get_response(self, "outputs") + return hash(response) +end + +function luampd:update() + get_response(self, "update") +end + +------------------------------------------------ +-- Database functions +------------------------------------------------ + +function luampd:find(stype, swhat) + local send_string = string.format("find %s \"%s\"", stype, swhat) + local data = get_response(self, send_string) + return multi_hash("^file:", data) +end + +-- how should we handle these functions? +-- list/listall/lsinfo +function luampd:list(meta, meta2, search) +end + +function luampd:listall(path) +end + +function luampd:listallinfo(path) + local send_string + if path then + send_string = string.format("listallinfo \"%s\"", path) + else + send_string = "listallinfo" + end + local response = get_response(self, send_string) + local songs = multi_hash("file:(.+)", response) + return songs +end + +function luampd:lsinfo(path) +end + +function luampd:search(stype, swhat) + local send_string = string.format("search %s \"%s\"", stype, swhat) + local data = get_response(self, send_string) + return multi_hash("^file:", data) +end + +------------------------------------------------ +-- Playlist functions +------------------------------------------------ + +function luampd:add(file) + local add = string.format("add \"%s\"", file) + get_response(self, add) +end + +function luampd:clear() + get_response(self, "clear") +end + +function luampd:currentsong() + local song = get_response(self, "currentsong") + local hash = hash(song) + return hash +end + +function luampd:delete(song) + get_response(self, string.format("delete %d", song)) +end + +function luampd:deleteid(songid) + get_response(self, string.format("deleteid %s", songid)) +end + +function luampd:load_playlist(path) + get_response(self, string.format("load %s", path)) +end + +function luampd:move(from, to) + get_response(self, string.format("move %d %d", from, to)) +end + +function luampd:moveid(fromid, toid) + get_response(self, string.format("moveid %d %d", fromid, toid)) +end + +function luampd:playlistinfo(song) + local send_string + if song then + send_string = string.format("playlistinfo %d", song) + local response = get_response(self, send_string) + return hash(response) + else + send_string = "playlistinfo" + local response = get_response(self, send_string) + return multi_hash("^file:", response) + end +end + +function luampd:playlistid(songid) + local send_string + if songid then + send_string = string.format("playlistid %d", songid) + local response = get_response(self, send_string) + return hash(response) + else + send_string = "playlistid" + local response = get_response(self, send_string) + return multi_hash("^file:", response) + end +end + +function luampd:plchanges(version) + local send_string = string.format("plchanges %d", version) + local response = get_response(self, send_string) + return multi_hash(response) +end + +function luampd:plchangesposid(version) +end + +function luampd:rm(name) + get_response(self, + string.format("rm \"%s\"", name)) +end + +function luampd:save(name) + get_response(self, + string.format("save \"%s\"", name)) +end + +function luampd:shuffle() + get_response(self, "shuffle") +end + +function luampd:swap(song1, song2) + get_response(self, + string.format("swap %d %d", song1, song2)) +end + +function luampd:swapid(songid1, songid2) + get_response(self, + string.format("swapid %d %d", songid1, songid2)) +end + +------------------------------------------------ +-- Playback functions +------------------------------------------------ + +-- Some of the common tables: +-- +-- Status: +-- Fields: volume, repeat, random, playlist, playlistlength, xfade, +-- state, song, songid, time, bitrate, audio +-- +-- CurrentSong: +-- Fields: file, artist, album, track, title, time, pos, id + +-- sets the crossfading to seconds and returns the xfade status +-- +function luampd:crossfade(seconds) + get_response(self, + string.format("crossfade %d", seconds)) + return self:status() +end + +-- go to next song, returns song table +-- +function luampd:next_() + get_response(self, "next") + return self:currentsong() +end + +-- pause the current song, returns true/false +-- (play, pause, stop, etc) +-- +function luampd:pause() + get_response(self, "pause") + if self:status()["state"] == "pause" then + return true + else + return false + end +end + +-- starts playing, returns the current song as a table +-- +function luampd:play() + get_response(self, "play") + return self:currentsong() +end + +-- start playing a song by its song id +-- +function luampd:playid(songid) + get_response(self, + string.format("playid %d", songid)) + return self:currentsong() +end + +-- go to the previous song and return the current song +-- +function luampd:previous() + get_response(self, "previous") + return self:currentsong() +end + +-- sets random on or off (state should be either +-- 1 (for on) or 0 (for off)) +-- +function luampd:random(state) + get_response(self, + string.format("random %d", state)) + if self:state()["random"] == tostring(state) then + return true + else + return false + end +end + +-- sets repeat (see above about state) +-- +function luampd:repeat_(state) + get_response(self, + string.format("repeat %d", state)) + if self:state()["repeat"] == tostring(state) then + return true + else + return false + end +end + +-- seeks to the specified time (in seconds) in the song +-- returns status +function luampd:seek(song, time) + get_response(self, + string.format("seek %d %d", song, time)) + return self:status() +end + +-- same as above, except uses songid instead of song +-- returns status +function luampd:seekid(songid, time) + get_response(self, + string.format("seekid %d %d", songid, time)) + return self:status() +end + +-- set the volume (0-100), anything lower or higher should be handled +-- by the server (-10 will become 0, 110 will become 100) +-- returns status object +-- +function luampd:setvol(vol) + get_response(self, + string.format("setvol %d", vol)) + if self:status()["volume"] == tostring(vol) then + return true + else + return false + end +end + +-- stops playing and returns the current status object +function luampd:stop() + get_response(self, "stop") + if self:status()["state"] == "stop" then + return true + else + return false + end +end + +------------------------------------------------ +-- Miscellaneous functions +------------------------------------------------ + +function luampd:clearerror() + get_response(self, "clearerror") +end + +-- +function luampd:close() + get_response(self, "close") + self.socket = nil +end + +function luampd:commands() +end + +function luampd:notcommands() +end + +-- wrong password handled in get_response +function luampd:password(pass) + get_response(self, + string.format("password %s", pass)) +end + +function luampd:ping() + get_response(self, "ping") +end + +function luampd:stats() + local stats = get_response(self, "stats") + return hash(stats) +end + +function luampd:status() + local status = get_response(self, "status") + return hash(status) +end + +------------------------------------------------ +-- More lua-esque functions, iterators +------------------------------------------------ +-- 2011-03-15 crater2150: let iterators return size, which is already calculated +-- anyway + +function luampd:database() + local dbase = self:listallinfo(nil) + local count = 0 + local size = table.maxn(dbase) + return function() + count = count + 1 + if count <= size then + return dbase[count] + end + end, size +end + +function luampd:playlist() + local plist = self:playlistinfo(nil) + local count = 0 + local size = table.maxn(plist) + return function() + count = count + 1 + if count <= size then + return plist[count] + end + end, size +end + +function luampd:ifind(stype, swhat) + local found = self:find(stype, swhat) + local count = 0 + local size = table.maxn(found) + return function() + count = count + 1 + if count <= size then + return found[count] + end + end, size +end + +function luampd:isearch(stype, swhat) + local found = self:search(stype, swhat) + local count = 0 + local size = table.maxn(found) + return function() + count = count + 1 + if count <= size then + return found[count] + end + end, size +end + +function luampd:iadd(file_iterator) + for song in file_iterator do + self:add(song.file) + end +end + +return luampd diff --git a/modalbind.lua b/modalbind.lua new file mode 100644 index 0000000..ee56437 --- /dev/null +++ b/modalbind.lua @@ -0,0 +1,148 @@ +local M = {} +local inited = false +local modewidget = {} +local modewibox = { screen = -1 } + +--local functions +local ensure_init, set_default, update_settings, show_box, hide_box +M.grab = function(keymap, stay_in_mode) + if keymap.name then show_box(mouse.screen, keymap) end + + keygrabber.run(function(mod, key, event) + if key == "Escape" then + keygrabber.stop() + hide_box(); + return true + end + + if event == "release" then return true end + + if keymap[key] then + keygrabber.stop() + keymap[key]() + if stay_in_mode then + M.grab(keymap, true) + else + hide_box() + return true + end + end + + return true + end) +end + +-- Partially adapted from Obvious Widget Library module "popup_run_prompt" -- +-- Original Author: Andrei "Garoth" Thorp -- +-- Copyright 2009 Andrei "Garoth" Thorp -- + +local defaults = {} +-- Default is 1 for people without compositing +defaults.opacity = 1.0 +defaults.height = 22 +defaults.border_width = 1 +defaults.x_offset = 18 +defaults.show_options = true + +-- Clone the defaults for the used settings +local settings = {} +for key, value in pairs(defaults) do + settings[key] = value +end + + +M.set_opacity = function (amount) + settings.opacity = amount or defaults.opacity + update_settings() +end + +M.set_height = function (amount) + settings.height = amount or defaults.height + update_settings() +end + +M.set_border_width = function (amount) + settings.border_width = amount or defaults.border_width + update_settings() +end + +M.set_x_offset = function (amount) + settings.x_offset = amount or defaults.x_offset + update_settings() +end + +M.set_show_options = function (bool) + settings.show_options = bool +end + +ensure_init = function () + if inited then + return + end + + inited = true + for s = 1, screen.count() do + modewidget[s] = widget({ + type = "textbox", + name = "modewidget" .. s, + align = "center" + }) + + modewibox[s] = wibox({ + fg = beautiful.fg_normal, + bg = beautiful.bg_normal, + border_width = settings.border_width, + border_color = beautiful.bg_focus, + }) + set_default(s) + modewibox[s].visible = false + modewibox[s].screen = s + modewibox[s].ontop = true + + -- Widgets for prompt wibox + modewibox[s].widgets = { + modewidget[s], + layout = awful.widget.layout.vertical.center + } + end +end + +set_default = function (s) + modewibox[s]:geometry({ + width = modewidget[s].extents(modewidget[s]).width, + height = settings.height, + x = settings.x_offset < 0 and + screen[s].geometry.x - width + settings.x_offset or + settings.x_offset, + y = screen[s].geometry.y + screen[s].geometry.height - settings.height + }) +end + +update_settings = function () + for s, value in ipairs(modewibox) do + value.border_width = settings.border_width + set_default(s) + value.opacity = settings.opacity + end +end + +show_box = function (s, map) + ensure_init() + modewibox.screen = s + local label = " -- " .. map.name .. " -- " + if settings.show_options then + for key in pairs(map) do + if key ~= "name" then label = label .. " " .. key end + end + end + modewidget[s].text = label + set_default(s) + modewibox[s].visible = true +end + +hide_box = function () + local s = modewibox.screen + if s ~= -1 then modewibox[s].visible = false end +end + +return M diff --git a/mpd.lua b/mpd.lua new file mode 100644 index 0000000..8493880 --- /dev/null +++ b/mpd.lua @@ -0,0 +1,150 @@ +local luampd = require("luampd") +local M = {} + +local type = "" + +-- local functions +local show, mpc_play_search, notify + +local conn = nil + +local defaults = {} +local settings = {} + +defaults.host = "127.0.0.1" +defaults.port = 6600 +defaults.replace_on_search = true + +for key, value in pairs(defaults) do + settings[key] = value +end + +-- {{{ basic functions + +M.connect = function () + print("Connecting to mpd") + conn = luampd:new({ + hostname = settings.hostname, + port = settings.port, + debug = false + }) +end + +M.disconnect = function() + if conn ~= nil then conn:close() end + conn = nil +end + +M.ensure_connection = function() + if conn == nil then M.connect() end +end + +-- }}} + +-- {{{ mpd.ctrl submodule + +M.ctrl = {} + +M.ctrl.toggle = function () + M.ensure_connection() + local status = conn:status() + if status["state"] == "pause" or status["state"] == "stop" then + conn:play() + else + conn:pause() + end +end + +M.ctrl.play = function () + M.ensure_connection() + conn:play() + -- TODO widget updating +end + +M.ctrl.pause = function () + M.ensure_connection() + conn:pause() + -- TODO widget updating +end + +M.ctrl.next = function () + M.ensure_connection() + conn:next_() + -- TODO widget updating +end + +M.ctrl.prev = function () + M.ensure_connection() + conn:previous() + -- TODO widget updating +end + +-- }}} + +-- {{{ mpd.prompt submodule + +local clear_before = cfg.mpd_prompt_clear_before == nil and + true or + cfg.mpd_prompt_clear_before + +M.prompt = {} + +M.prompt.artist = function() + type = "artist" + show() +end + +M.prompt.album = function() + type = "album" + show() +end + + +M.prompt.title = function() + type = "title" + show() +end +M.prompt.title = title + +M.prompt.replace_on_search = function(bool) + clear_before = bool +end + +M.prompt.toggle_replace_on_search = function() + clear_before = not clear_before + notify("MPD prompts now " ..( + clear_before and "replace" or "add to" + ).. " the playlist") +end + +function show() + obvious.popup_run_prompt.set_prompt_string("Play ".. type .. ":") + obvious.popup_run_prompt.set_cache("/mpd_ ".. type); + obvious.popup_run_prompt.set_run_function(mpc_play_search) + obvious.popup_run_prompt.run_prompt() +end + +function mpc_play_search(s) + M.ensure_connection() + if clear_before then conn:clear() end + local result, num = conn:isearch(type, s) + notify("Found " .. (num) .. " matches"); + conn:iadd(result) + conn:play() +end + +-- }}} + +-- {{{ notify wrapper +notify = function(stext) + if not (naughty == nil) then + naughty.notify({ + text= stext + }) + end +end +--}}} + +return M + +-- vim: set fenc=utf-8 tw=80 foldmethod=marker : diff --git a/mpd_prompt.lua b/mpd_prompt.lua deleted file mode 100644 index 6b241d0..0000000 --- a/mpd_prompt.lua +++ /dev/null @@ -1,78 +0,0 @@ -local awful = awful -local obvious = obvious -local naughty = naughty -local keygrabber = keygrabber -local io = io -local pairs = pairs - -local M = {} - -local type = "" -local clear_before = true - -local keymap = {} - -local show, - mpc_play_search - -M.grabber = function() - keygrabber.run(function(mod, key, event) - if event == "release" then return true end - keygrabber.stop() - if keymap[key] then keymap[key]() end - return true - end) -end - -M.artist = function() - type = "artist" - show() -end - -M.album = function() - type = "album" - show() -end - - -M.title = function() - type = "title" - show() -end -M.title = title - -M.replace_on_search = function(bool) - clear_before = bool -end - -M.toggle_replace_on_search = function() - clear_before = not clear_before - if not (naughty == nil) then - naughty.notify({ - text="MPD prompts now " ..( - clear_before and "replace" or "add to" - ).. " the playlist" - }) - end -end - -function show() - obvious.popup_run_prompt.set_prompt_string("Play ".. type .. ":") - obvious.popup_run_prompt.set_run_function(mpc_play_search) - obvious.popup_run_prompt.run_prompt() -end - -function mpc_play_search(s) - if clear_before then awful.util.spawn("mpc clear") end - awful.util.spawn_with_shell("mpc search ".. type .." '" .. s .. "' | mpc add") - awful.util.spawn("mpc play"); -end - -keymap = { - a = M.artist, - A = M.album, - t = M.title, - r = M.toggle_replace_on_search -} - -return M diff --git a/rc.lua b/rc.lua index 5fa9e66..5cd37d5 100644 --- a/rc.lua +++ b/rc.lua @@ -9,11 +9,8 @@ require("teardrop") require("obvious.popup_run_prompt") require("vicious") require("rodentbane.rodentbane") -require("aweswt") -mpd_prompt = require("mpd_prompt") MY_PATH = os.getenv("HOME") .. "/.config/awesome/" -WALLPATH = MY_PATH .. "walls/" dofile (MY_PATH .. "localconf.lua") diff --git a/rules.lua b/rules.lua index 222710f..475b6f5 100644 --- a/rules.lua +++ b/rules.lua @@ -31,7 +31,7 @@ awful.rules.rules = { { rule = { role = "buddy_list" }, properties = { master = true } }, { rule = { role = "conversation" }, - callback = awful.client.setslave}, + callback = awful.client.setslave }, { rule = { instance = "Weechat"}, properties = { tag = tags[rule_screen][3]} , callback = awful.client.setslave}, diff --git a/tags.lua b/tags.lua index f36117e..643730e 100644 --- a/tags.lua +++ b/tags.lua @@ -15,15 +15,15 @@ tags.setup = { { name = "F1:☭", layout = layouts[1] }, { name = "F2:♚", layout = layouts[1] }, { name = "F3:♛", layout = layouts[1] }, - { name = "F4:♜", layout = layouts[1] }, - { name = "F5:♝", layout = layouts[1] }, - { name = "F6:♞", layout = layouts[1] }, - { name = "F7:♟", layout = layouts[1] }, - { name = "F8:⚖", layout = layouts[1] }, - { name = "F9:⚛", layout = layouts[1] }, - { name = "F10:⚡", layout = layouts[1] }, - { name = "F11:⚰", layout = layouts[1] }, - { name = "F12:⚙", layout = layouts[1] } + { name = "F4:♜", layout = layouts[1] }--, + -- { name = "F5:♝", layout = layouts[1] }, + -- { name = "F6:♞", layout = layouts[1] }, + -- { name = "F7:♟", layout = layouts[1] }, + -- { name = "F8:⚖", layout = layouts[1] }, + -- { name = "F9:⚛", layout = layouts[1] }, + -- { name = "F10:⚡", layout = layouts[1] }, + -- { name = "F11:⚰", layout = layouts[1] }, + -- { name = "F12:⚙", layout = layouts[1] } } for s = 1, screen.count() do diff --git a/wibox.lua b/wibox.lua index 42a1ccf..607aec7 100644 --- a/wibox.lua +++ b/wibox.lua @@ -170,8 +170,8 @@ for s = 1, screen.count() do -- Create the wibox - leftwibox[s] = awful.wibox({ position = "left", screen = s }) - rightwibox[s] = awful.wibox({ position = "right", screen = s }) + leftwibox[s] = awful.wibox({ position = "left", screen = s, width = 18 }) + rightwibox[s] = awful.wibox({ position = "right", screen = s , width = 18}) -- Add widgets to the wibox - order matters leftwibox[s].widgets = { mytaglist[s], diff --git a/zenburn/theme.lua b/zenburn/theme.lua index 031c54a..a567a08 100644 --- a/zenburn/theme.lua +++ b/zenburn/theme.lua @@ -12,7 +12,7 @@ theme.wallpaper_cmd = { "awsetbg -l" } -- }}} -- {{{ Styles -theme.font = "sans 8" +theme.font = "dejavu 7" -- {{{ Colors theme.fg_normal = "#DCDCDC"