From 344d6d533ab9415b2d225fc8d257c80cf5aae484 Mon Sep 17 00:00:00 2001 From: crater2150 Date: Sat, 24 Oct 2009 16:50:19 +0000 Subject: [PATCH] Initial commit --- back.rc.lua | 469 ++++++++++ gitrc.lua | 437 ++++++++++ icons/LICENSE | 12 + icons/awesome.png | Bin 0 -> 205 bytes icons/background.png | Bin 0 -> 43786 bytes icons/bat.png | Bin 0 -> 214 bytes icons/cal.png | Bin 0 -> 217 bytes icons/chat.png | Bin 0 -> 216 bytes icons/cpu.png | Bin 0 -> 235 bytes icons/crypto.png | Bin 0 -> 219 bytes icons/disk.png | Bin 0 -> 201 bytes icons/down.png | Bin 0 -> 250 bytes icons/info.png | Bin 0 -> 189 bytes icons/layouts/dwindle.png | Bin 0 -> 216 bytes icons/layouts/fairh.png | Bin 0 -> 194 bytes icons/layouts/fairhw.png | Bin 0 -> 179 bytes icons/layouts/fairv.png | Bin 0 -> 201 bytes icons/layouts/fairvw.png | Bin 0 -> 180 bytes icons/layouts/floating.png | Bin 0 -> 395 bytes icons/layouts/floatingw.png | Bin 0 -> 190 bytes icons/layouts/fullscreen.png | Bin 0 -> 202 bytes icons/layouts/fullscreenw.png | Bin 0 -> 182 bytes icons/layouts/magnifier.png | Bin 0 -> 209 bytes icons/layouts/magnifierw.png | Bin 0 -> 184 bytes icons/layouts/max.png | Bin 0 -> 313 bytes icons/layouts/maxw.png | Bin 0 -> 190 bytes icons/layouts/spiral.png | Bin 0 -> 215 bytes icons/layouts/tile.png | Bin 0 -> 174 bytes icons/layouts/tilebottom.png | Bin 0 -> 195 bytes icons/layouts/tilebottomw.png | Bin 0 -> 177 bytes icons/layouts/tileleft.png | Bin 0 -> 172 bytes icons/layouts/tileleftw.png | Bin 0 -> 189 bytes icons/layouts/tiletop.png | Bin 0 -> 195 bytes icons/layouts/tiletopw.png | Bin 0 -> 177 bytes icons/layouts/tilew.png | Bin 0 -> 192 bytes icons/mail.png | Bin 0 -> 213 bytes icons/mem.png | Bin 0 -> 203 bytes icons/music.png | Bin 0 -> 192 bytes icons/pacman.png | Bin 0 -> 226 bytes icons/phones.png | Bin 0 -> 232 bytes icons/power.png | Bin 0 -> 222 bytes icons/rss.png | Bin 0 -> 203 bytes icons/sat.png | Bin 0 -> 226 bytes icons/submenu.png | Bin 0 -> 440 bytes icons/sun.png | Bin 0 -> 203 bytes icons/taglist/squarefw.png | Bin 0 -> 187 bytes icons/taglist/squarefz.png | Bin 0 -> 377 bytes icons/taglist/squarefza.png | Bin 0 -> 163 bytes icons/taglist/squarew.png | Bin 0 -> 210 bytes icons/taglist/squarez.png | Bin 0 -> 377 bytes icons/taglist/squareza.png | Bin 0 -> 377 bytes icons/tasklist/floating.png | Bin 0 -> 345 bytes icons/tasklist/floatingw.png | Bin 0 -> 334 bytes icons/temp.png | Bin 0 -> 240 bytes icons/theme.lua | 92 ++ icons/time.png | Bin 0 -> 225 bytes icons/titlebar/close_focus.png | Bin 0 -> 666 bytes icons/titlebar/close_normal.png | Bin 0 -> 893 bytes icons/titlebar/floating_focus_active.png | Bin 0 -> 598 bytes icons/titlebar/floating_focus_inactive.png | Bin 0 -> 818 bytes icons/titlebar/floating_normal_active.png | Bin 0 -> 799 bytes icons/titlebar/floating_normal_inactive.png | Bin 0 -> 814 bytes icons/titlebar/maximized_focus_active.png | Bin 0 -> 1013 bytes icons/titlebar/maximized_focus_inactive.png | Bin 0 -> 1277 bytes icons/titlebar/maximized_normal_active.png | Bin 0 -> 1208 bytes icons/titlebar/maximized_normal_inactive.png | Bin 0 -> 1251 bytes icons/titlebar/ontop_focus_active.png | Bin 0 -> 774 bytes icons/titlebar/ontop_focus_inactive.png | Bin 0 -> 1073 bytes icons/titlebar/ontop_normal_active.png | Bin 0 -> 965 bytes icons/titlebar/ontop_normal_inactive.png | Bin 0 -> 1073 bytes icons/titlebar/sticky_focus_active.png | Bin 0 -> 833 bytes icons/titlebar/sticky_focus_inactive.png | Bin 0 -> 836 bytes icons/titlebar/sticky_normal_active.png | Bin 0 -> 967 bytes icons/titlebar/sticky_normal_inactive.png | Bin 0 -> 872 bytes icons/up.png | Bin 0 -> 277 bytes icons/vol.png | Bin 0 -> 228 bytes icons/wifi.png | Bin 0 -> 213 bytes json.lua | 515 +++++++++++ lib/mpd.lua | 150 ++++ lib/shifty.lua | 779 +++++++++++++++++ rc.lua | 335 ++++++++ scratchpad.lua | 136 +++ teardrop.lua | 128 +++ theme.lua | 142 ++++ wicked.lua | 848 +++++++++++++++++++ zenburn.lua | 141 +++ 86 files changed, 4184 insertions(+) create mode 100644 back.rc.lua create mode 100644 gitrc.lua create mode 100644 icons/LICENSE create mode 100644 icons/awesome.png create mode 100644 icons/background.png create mode 100644 icons/bat.png create mode 100644 icons/cal.png create mode 100644 icons/chat.png create mode 100644 icons/cpu.png create mode 100644 icons/crypto.png create mode 100644 icons/disk.png create mode 100644 icons/down.png create mode 100644 icons/info.png create mode 100644 icons/layouts/dwindle.png create mode 100644 icons/layouts/fairh.png create mode 100644 icons/layouts/fairhw.png create mode 100644 icons/layouts/fairv.png create mode 100644 icons/layouts/fairvw.png create mode 100644 icons/layouts/floating.png create mode 100644 icons/layouts/floatingw.png create mode 100644 icons/layouts/fullscreen.png create mode 100644 icons/layouts/fullscreenw.png create mode 100644 icons/layouts/magnifier.png create mode 100644 icons/layouts/magnifierw.png create mode 100644 icons/layouts/max.png create mode 100644 icons/layouts/maxw.png create mode 100644 icons/layouts/spiral.png create mode 100644 icons/layouts/tile.png create mode 100644 icons/layouts/tilebottom.png create mode 100644 icons/layouts/tilebottomw.png create mode 100644 icons/layouts/tileleft.png create mode 100644 icons/layouts/tileleftw.png create mode 100644 icons/layouts/tiletop.png create mode 100644 icons/layouts/tiletopw.png create mode 100644 icons/layouts/tilew.png create mode 100644 icons/mail.png create mode 100644 icons/mem.png create mode 100644 icons/music.png create mode 100644 icons/pacman.png create mode 100644 icons/phones.png create mode 100644 icons/power.png create mode 100644 icons/rss.png create mode 100644 icons/sat.png create mode 100644 icons/submenu.png create mode 100644 icons/sun.png create mode 100644 icons/taglist/squarefw.png create mode 100644 icons/taglist/squarefz.png create mode 100644 icons/taglist/squarefza.png create mode 100644 icons/taglist/squarew.png create mode 100644 icons/taglist/squarez.png create mode 100644 icons/taglist/squareza.png create mode 100644 icons/tasklist/floating.png create mode 100644 icons/tasklist/floatingw.png create mode 100644 icons/temp.png create mode 100644 icons/theme.lua create mode 100644 icons/time.png create mode 100644 icons/titlebar/close_focus.png create mode 100644 icons/titlebar/close_normal.png create mode 100644 icons/titlebar/floating_focus_active.png create mode 100644 icons/titlebar/floating_focus_inactive.png create mode 100644 icons/titlebar/floating_normal_active.png create mode 100644 icons/titlebar/floating_normal_inactive.png create mode 100644 icons/titlebar/maximized_focus_active.png create mode 100644 icons/titlebar/maximized_focus_inactive.png create mode 100644 icons/titlebar/maximized_normal_active.png create mode 100644 icons/titlebar/maximized_normal_inactive.png create mode 100644 icons/titlebar/ontop_focus_active.png create mode 100644 icons/titlebar/ontop_focus_inactive.png create mode 100644 icons/titlebar/ontop_normal_active.png create mode 100644 icons/titlebar/ontop_normal_inactive.png create mode 100644 icons/titlebar/sticky_focus_active.png create mode 100644 icons/titlebar/sticky_focus_inactive.png create mode 100644 icons/titlebar/sticky_normal_active.png create mode 100644 icons/titlebar/sticky_normal_inactive.png create mode 100644 icons/up.png create mode 100644 icons/vol.png create mode 100644 icons/wifi.png create mode 100644 json.lua create mode 100644 lib/mpd.lua create mode 100644 lib/shifty.lua create mode 100644 rc.lua create mode 100644 scratchpad.lua create mode 100644 teardrop.lua create mode 100644 theme.lua create mode 100644 wicked.lua create mode 100644 zenburn.lua diff --git a/back.rc.lua b/back.rc.lua new file mode 100644 index 0000000..04074d2 --- /dev/null +++ b/back.rc.lua @@ -0,0 +1,469 @@ +-- Standard awesome library +require("awful") +-- Theme handling library +require("beautiful") +-- Notification library +require("naughty") + +-- Load Debian menu entries +require("debian.menu") + +-- {{{ Variable definitions +-- Themes define colours, icons, and wallpapers +-- The default is a dark theme +theme_path = "/home/jack/.config/awesome/theme.lua" +-- Uncommment this for a lighter theme +-- theme_path = "/usr/share/awesome/themes/sky/theme.lua" + +-- Actually load theme +beautiful.init(theme_path) + +-- This is used later as the default terminal and editor to run. +terminal = "x-terminal-emulator" +editor = os.getenv("EDITOR") or "editor" +editor_cmd = terminal .. " -e " .. editor + +-- Default modkey. +-- Usually, Mod4 is the key with a logo between Control and Alt. +-- If you do not like this or do not have such a key, +-- I suggest you to remap Mod4 to another key using xmodmap or other tools. +-- However, you can use another modifier like Mod1, but it may interact with others. +modkey = "Mod1" + +-- Table of layouts to cover with awful.layout.inc, order matters. +layouts = +{ + awful.layout.suit.tile, + awful.layout.suit.tile.left, + awful.layout.suit.tile.bottom, + awful.layout.suit.tile.top, + awful.layout.suit.fair, + awful.layout.suit.fair.horizontal, + awful.layout.suit.max, + awful.layout.suit.max.fullscreen, + awful.layout.suit.magnifier, + awful.layout.suit.floating +} + +-- Table of clients that should be set floating. The index may be either +-- the application class or instance. The instance is useful when running +-- a console app in a terminal like (Music on Console) +-- x-terminal-emulator -name mocp -e mocp +floatapps = +{ + -- by class + ["MPlayer"] = true, + ["pinentry"] = true, + ["gimp"] = true, + -- by instance + ["mocp"] = true +} + +-- Applications to be moved to a pre-defined tag by class or instance. +-- Use the screen and tags indices. +apptags = +{ + -- ["Firefox"] = { screen = 1, tag = 2 }, + -- ["mocp"] = { screen = 2, tag = 4 }, +} + +-- Define if we want to use titlebar on all applications. +use_titlebar = false +-- }}} + +-- {{{ Tags +-- Define tags table. +tags = {} +tags.setup = { + { name = "terms" }, + { name = "web" }, + { name = "music" }, + { name = "dls" }, + { name = "files" }, + { name = "images" }, + { name = "videos" }, + { name = "exps" }, + { name = "other" }, + { name = "nil" } +} +for s = 1, screen.count() do + tags[s] = {} + for i, t in ipairs(tags.setup) do + tags[s][i] = tag({ name = t.name }) + tags[s][i].screen = s + awful.layout.set(layouts[1], tags[s][i]) + end + tags[s][1].selected = true +end +--local tags = {} +-- tags.setup = { +-- { name = "term", layout = layouts[3] }, + -- { name = "emacs", layout = layouts[1] }, + -- { name = "web", layout = layouts[1] }, + --{ name = "mail", layout = layouts[5] }, + --{ name = "im", layout = layouts[1], mwfact = 0.13 }, + -- { name = "6", layout = layouts[7], hide = true }, + -- { name = "7", layout = layouts[7], hide = true }, + -- { name = "rss", layout = layouts[6] }, + -- { name = "media", layout = layouts[7] } +-- } + +-- for s = 1, screen.count() do +-- tags[s] = {} + -- for i, t in ipairs(tags.setup) do + -- tags[s][i] = tag({ name = t.name }) +-- tags[s][i].screen = s +-- awful.tag.setproperty(tags[s][i], "layout", t.layout) + -- awful.tag.setproperty(tags[s][i], "mwfact", t.mwfact) + -- awful.tag.setproperty(tags[s][i], "hide", t.hide) + -- end + -- tags[s][1].selected = true +-- end + +-- }}} + +-- {{{ Wibox +-- Create a textbox widget +mytextbox = widget({ type = "textbox", align = "right" }) +-- Set the default text in textbox +mytextbox.text = " loading... " + +-- Create a laucher widget and a main menu +myawesomemenu = { + { "manual", terminal .. " -e man awesome" }, + { "edit config", editor_cmd .. " " .. awful.util.getdir("config") .. "/rc.lua" }, + { "restart", awesome.restart }, + { "quit", awesome.quit } +} + +mymainmenu = awful.menu.new({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon }, + { "open terminal", terminal }, + { "Debian", debian.menu.Debian_menu.Debian } + } + }) + +mylauncher = awful.widget.launcher({ image = image(beautiful.awesome_icon), + menu = mymainmenu }) + +-- Create a systray +mysystray = widget({ type = "systray", align = "right" }) + +-- Create a wibox for each screen and add it +mywibox = {} +mypromptbox = {} +mylayoutbox = {} +mytaglist = {} +mytaglist.buttons = awful.util.table.join( + awful.button({ }, 1, awful.tag.viewonly), + awful.button({ modkey }, 1, awful.client.movetotag), + awful.button({ }, 3, function (tag) tag.selected = not tag.selected end), + awful.button({ modkey }, 3, awful.client.toggletag), + awful.button({ }, 4, awful.tag.viewnext), + awful.button({ }, 5, awful.tag.viewprev) + ) +mytasklist = {} +mytasklist.buttons = awful.util.table.join( + awful.button({ }, 1, function (c) + if not c:isvisible() then + awful.tag.viewonly(c:tags()[1]) + end + client.focus = c + c:raise() + end), + awful.button({ }, 3, function () + if instance then + instance:hide() + instance = nil + else + instance = awful.menu.clients({ width=250 }) + end + end), + awful.button({ }, 4, function () + awful.client.focus.byidx(1) + if client.focus then client.focus:raise() end + end), + awful.button({ }, 5, function () + awful.client.focus.byidx(-1) + if client.focus then client.focus:raise() end + end)) + +for s = 1, screen.count() do + -- Create a promptbox for each screen + mypromptbox[s] = awful.widget.prompt({ align = "left" }) + -- Create an imagebox widget which will contains an icon indicating which layout we're using. + -- We need one layoutbox per screen. + mylayoutbox[s] = widget({ type = "imagebox", align = "right" }) + mylayoutbox[s]:buttons(awful.util.table.join( + awful.button({ }, 1, function () awful.layout.inc(layouts, 1) end), + awful.button({ }, 3, function () awful.layout.inc(layouts, -1) end), + awful.button({ }, 4, function () awful.layout.inc(layouts, 1) end), + awful.button({ }, 5, function () awful.layout.inc(layouts, -1) end))) + -- Create a taglist widget + mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.label.all, mytaglist.buttons) + + -- Create a tasklist widget + mytasklist[s] = awful.widget.tasklist(function(c) + return awful.widget.tasklist.label.currenttags(c, s) + end, mytasklist.buttons) + + -- Create the wibox + mywibox[s] = wibox({ position = "top", fg = beautiful.fg_normal, bg = beautiful.bg_normal }) + -- Add widgets to the wibox - order matters + mywibox[s].widgets = { mylauncher, + mytaglist[s], + --mylayoutbox[s], + --mytasklist[s], + mypromptbox[s], + mytextbox, + s == 1 and mysystray or nil } + mywibox[s].screen = s +end +-- }}} + +-- {{{ Mouse bindings +root.buttons(awful.util.table.join( + awful.button({ }, 3, function () mymainmenu:toggle() end), + awful.button({ }, 4, awful.tag.viewnext), + awful.button({ }, 5, awful.tag.viewprev) +)) +-- }}} + +-- {{{ Key bindings +globalkeys = awful.util.table.join( + awful.key({ modkey, }, "comma", awful.tag.viewprev ), + awful.key({ modkey, }, "period", awful.tag.viewnext ), + awful.key({ modkey, }, "Escape", awful.tag.history.restore), + + awful.key({ modkey, }, "t", + function () + awful.client.focus.byidx( 1) + if client.focus then client.focus:raise() end + end), + awful.key({ modkey, }, "n", + function () + awful.client.focus.byidx(-1) + if client.focus then client.focus:raise() end + end), + awful.key({ modkey, }, "w", function () mymainmenu:show(true) end), + + -- Layout manipulation + awful.key({ modkey, "Shift" }, "t", function () awful.client.swap.byidx( 1) end), + awful.key({ modkey, "Shift" }, "n", function () awful.client.swap.byidx( -1) end), + awful.key({ modkey, "Control" }, "t", function () awful.screen.focus( 1) end), + awful.key({ modkey, "Control" }, "n", function () awful.screen.focus(-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), + + -- Standard program + awful.key({ modkey, }, "Return", function () awful.util.spawn(terminal) end), + awful.key({ modkey, "Control" }, "r", awesome.restart), + awful.key({ modkey, "Shift" }, "q", awesome.quit), + + awful.key({ modkey, }, "s", 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" }, "s", function () awful.tag.incnmaster(-1) end), + awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1) end), + awful.key({ modkey, "Control" }, "s", 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, -1) end), + + -- Prompt + awful.key({ modkey }, "apostrophe", function () mypromptbox[mouse.screen]:run() end), + + awful.key({ modkey }, "x", + function () + awful.prompt.run({ prompt = "Run Lua code: " }, + mypromptbox[mouse.screen].widget, + awful.util.eval, nil, + awful.util.getdir("cache") .. "/history_eval") + end) +) + +-- Client awful tagging: this is useful to tag some clients and then do stuff like move to tag on them +clientkeys = awful.util.table.join( + awful.key({ modkey, }, "f", function (c) c.fullscreen = not c.fullscreen end), + awful.key({ modkey, }, "semicolon", function (c) c:kill() end), + awful.key({ modkey, "Control" }, "space", 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" }, "r", function (c) c:redraw() end), + awful.key({ modkey }, "w", awful.client.togglemarked), + awful.key({ modkey,}, "m", + function (c) + c.maximized_horizontal = not c.maximized_horizontal + c.maximized_vertical = not c.maximized_vertical + end) +) + +-- Compute the maximum number of digit we need, limited to 9 +keynumber = 0 +for s = 1, screen.count() do + keynumber = math.min(9, math.max(#tags[s], keynumber)); +end + +for i = 1, keynumber do + globalkeys = awful.util.table.join(globalkeys, + awful.key({ modkey }, i, + function () + local screen = mouse.screen + if tags[screen][i] then + awful.tag.viewonly(tags[screen][i]) + end + end), + awful.key({ modkey, "Control" }, i, + function () + local screen = mouse.screen + if tags[screen][i] then + tags[screen][i].selected = not tags[screen][i].selected + end + end), + awful.key({ modkey, "Shift" }, i, + function () + if client.focus and tags[client.focus.screen][i] then + awful.client.movetotag(tags[client.focus.screen][i]) + end + end), + awful.key({ modkey, "Control", "Shift" }, i, + function () + if client.focus and tags[client.focus.screen][i] then + awful.client.toggletag(tags[client.focus.screen][i]) + end + end), + awful.key({ modkey, "Shift" }, "F" .. i, + function () + local screen = mouse.screen + if tags[screen][i] then + for k, c in pairs(awful.client.getmarked()) do + awful.client.movetotag(tags[screen][i], c) + end + end + end)) +end + +-- Set keys +root.keys(globalkeys) +-- }}} + +-- {{{ Hooks +-- Hook function to execute when focusing a client. +awful.hooks.focus.register(function (c) + if not awful.client.ismarked(c) then + c.border_color = beautiful.border_focus + end +end) + +-- Hook function to execute when unfocusing a client. +awful.hooks.unfocus.register(function (c) + if not awful.client.ismarked(c) then + c.border_color = beautiful.border_normal + end +end) + +-- Hook function to execute when marking a client +awful.hooks.marked.register(function (c) + c.border_color = beautiful.border_marked +end) + +-- Hook function to execute when unmarking a client. +awful.hooks.unmarked.register(function (c) + c.border_color = beautiful.border_focus +end) + +-- Hook function to execute when the mouse enters a client. +awful.hooks.mouse_enter.register(function (c) + -- Sloppy focus, but disabled for magnifier layout + if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier + and awful.client.focus.filter(c) then + client.focus = c + end +end) + +-- Hook function to execute when a new client appears. +awful.hooks.manage.register(function (c, startup) + -- If we are not managing this application at startup, + -- move it to the screen where the mouse is. + -- We only do it for filtered windows (i.e. no dock, etc). + if not startup and awful.client.focus.filter(c) then + c.screen = mouse.screen + end + + if use_titlebar then + -- Add a titlebar + awful.titlebar.add(c, { modkey = modkey }) + end + -- Add mouse bindings + c:buttons(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) + )) + -- New client may not receive focus + -- if they're not focusable, so set border anyway. + c.border_width = beautiful.border_width + c.border_color = beautiful.border_normal + + -- Check if the application should be floating. + local cls = c.class + local inst = c.instance + if floatapps[cls] ~= nil then + awful.client.floating.set(c, floatapps[cls]) + elseif floatapps[inst] ~= nil then + awful.client.floating.set(c, floatapps[inst]) + end + + -- Check application->screen/tag mappings. + local target + if apptags[cls] then + target = apptags[cls] + elseif apptags[inst] then + target = apptags[inst] + end + if target then + c.screen = target.screen + awful.client.movetotag(tags[target.screen][target.tag], c) + end + c.size_hints_honor = false + -- Do this after tag mapping, so you don't see it on the wrong tag for a split second. + client.focus = c + + -- Set key bindings + c:keys(clientkeys) + + -- Set the windows at the slave, + -- i.e. put it at the end of others instead of setting it master. + -- awful.client.setslave(c) + + -- Honor size hints: if you want to drop the gaps between windows, set this to false. + -- c.size_hints_honor = false +end) + +-- Hook function to execute when arranging the screen. +-- (tag switch, new client, etc) +awful.hooks.arrange.register(function (screen) + local layout = awful.layout.getname(awful.layout.get(screen)) + if layout and beautiful["layout_" ..layout] then + mylayoutbox[screen].image = image(beautiful["layout_" .. layout]) + else + mylayoutbox[screen].image = nil + end + + -- Give focus to the latest client in history if no window has focus + -- or if the current window is a desktop or a dock one. + if not client.focus then + local c = awful.client.focus.history.get(screen, 0) + if c then client.focus = c end + end +end) + +-- Hook called every minute +awful.hooks.timer.register(10, function () + awful.util.spawn("awst") +end) +-- }}} diff --git a/gitrc.lua b/gitrc.lua new file mode 100644 index 0000000..a699196 --- /dev/null +++ b/gitrc.lua @@ -0,0 +1,437 @@ +--### +-- Standard awesome library +require("awful") +-- Theme handling library +require("beautiful") +-- Notification library +require("naughty") +-- Dynamic tagging with shifty +require("lib/shifty") + +-- Wicked +require("wicked") + +-- {{{ Variable definitions +-- Themes define colours, icons, and wallpapers +-- Just link your theme to ~/.awesome_theme +theme_path = os.getenv("HOME") .. "/.config/awesome/theme.lua" + +-- Actually load theme +beautiful.init(theme_path) + +-- Default applications +terminal = "terminal" +-- Editor to use +editor = "terminal -e vim" +-- this is the default level when adding a todo note +todo_level = "high" +-- Default modkey. l +-- Usually, Mod4 is the key with a logo between Control and Alt. +-- If you do not like this or do not have such a key, +-- I suggest you to remap Mod4 to another key using xmodmap or other tools. +-- However, you can use another modifier like Mod1, but it may interact with others. +modkey = "Mod1" +-- Table of layouts to cover with awful.layout.inc, order matters. +layouts = +{ + awful.layout.suit.tile, + awful.layout.suit.tile.left, + awful.layout.suit.tile.bottom, + awful.layout.suit.tile.top, + awful.layout.suit.fair, + awful.layout.suit.fair.horizontal, + awful.layout.suit.max, + awful.layout.suit.max.fullscreen, + awful.layout.suit.floating +} + +-- Table of clients that should be set floating. The index may be either +-- the application class or instance. The instance is useful when running +-- a console app in a terminal like (Music on Console) +-- xterm -name mocp -e mocp +floatapps = +{ + -- by class + ["MPlayer"] = true, + ["Xmessage"] = true, + ["Wireshark"] = true, + ["XBoard"] = true, + ["feh"] = true, + ["nitrogen"] = true, + ["Wicd-client.py"] = true, + ["gimp"] = true, + ["XCalc"] = true, + ["display"] = true, + ["Preferences"] = true, + ["XClipboard"] = true, + ["Imagemagick"] = true, + ["Snes9X"] = true, + ["Add-ons"] = true, + ["Wine desktop"] = true +} + +-- Define if we want to use titlebar on all applications. +use_titlebar = false +-- }}} + +--{{{ Shifty + +shifty.config.defaults = { + layout = "tilebottom", +} +shifty.config.tags = { + ["1:terms"] = { init = true, }, + ["2:web"] = { init = true, nopopup = true }, + ["3:music"] = { init =false, nopopup = true, position = 3, spawn = "ario" }, + ["4:dls"] = { init =false, nopopup =false, position = 4, spawn = "dtella && linuxdcpp" }, + ["5:files"] = { init =false, nopopup =false, position = 5 }, + ["6:images"] = { init =false, nopopup =false, position = 6, layout = "float" }, + ["7:videos"] = { init =false, nopopup =false, position = 7, layout = "float" }, + ["8:exps"] = { init =false, nopopup =false, position = 8, layout = "float" }, + ["9:work"] = { init =false, nopopup =false, position = 9 }, +} + +shifty.config.apps = { + { match = { "VLC.*" }, float = true }, + { match = { "" }, honorsizehints= false, + buttons = { + button({ }, 1, function (c) client.focus = c; c:raise() end), + button({ modkey }, 1, function (c) awful.mouse.client.move() end), + button({ modkey }, 3, awful.mouse.client.resize ), }, }, + } + +-- tag defaults +shifty.config.defaults = { + layout = "tilebottom", + ncol = 1, + floatBars = true, +} +shifty.config.layouts = layouts +shifty.config.guess_position = true +shifty.config.remember_index = true +shifty.init() +-- }}} + +-- {{{ Widgets +-- Create a systray +mysystray = widget({ type = "systray", align = "right" }) + +-- Create a wibox for each screen and add it +mywibox = {} +mypromptbox = {} +mylayoutbox = {} +mytaglist = {} +mytaglist.buttons = { button({ }, 1, awful.tag.viewonly), + button({ modkey }, 1, awful.client.movetotag), + button({ }, 3, function (tag) tag.selected = not tag.selected end), + button({ modkey }, 3, awful.client.toggletag), + button({ }, 4, awful.tag.viewnext), + button({ }, 5, awful.tag.viewprev) } + shifty.taglist = mytaglist +mytasklist = {} +mytasklist.buttons = { button({ }, 1, function (c) client.focus = c; c:raise() end), + button({ }, 3, function () awful.menu.clients({ width=250 }) end), + button({ }, 4, function () awful.client.focus.byidx(1) end), + button({ }, 5, function () awful.client.focus.byidx(-1) end) } + +for s = 1, screen.count() do + -- Create a promptbox for each screen + mypromptbox[s] = widget({ type = "textbox" }) + +-- Create a datebox widget +datebox = widget({ type = "textbox", align = "right" }) + -- Create an imagebox widget which will contains an icon indicating which layout we're using. + -- We need one layoutbox per screen. + mylayoutbox[s] = widget({ type = "imagebox" }) + mylayoutbox[s]:buttons({ button({ }, 1, function () awful.layout.inc(layouts, 1) end), + button({ }, 3, function () awful.layout.inc(layouts, -1) end), + button({ }, 4, function () awful.layout.inc(layouts, 1) end), + button({ }, 5, function () awful.layout.inc(layouts, -1) end) }) + -- Create a taglist widget + mytaglist[s] = awful.widget.taglist.new(s, awful.widget.taglist.label.all, mytaglist.buttons) + -- Create a tasklist widget + mytasklist[s] = awful.widget.tasklist.new(function(c) + return awful.widget.tasklist.label.currenttags(c, s) + end, mytasklist.buttons) +--}}} + +--{{{ Wibox + mywibox[s] = wibox({ position = "top", fg = beautiful.fg_normal, bg = beautiful.bg_normal }) + -- Add widgets to the wibox - order matters + mywibox[s].widgets = { + mylayoutbox[s], + mytaglist[s], + mypromptbox[s], + mysystray, + datebox, + } + mywibox[s].screen = s +end +--}}} + +--{{{ Functions + +--{{{ Add a todo note + + function addtodo (todo) + infobox.text = "| todo: " .. "" .. awful.util.spawn("todo --add --priority high " .. "'" .. todo .. "'") .. "" + end +--}}} + +--{{{ Show todos + function show_todo() + local todo = awful.util.pread("todo --mono") + todo = naughty.notify({ + text = string.format(os.date("%a, %d %B %Y") .. "\n" .. todo), + timeout = 6, + width = 300, + }) + end +--}}} + + + +--}}} + +--{{{ Keybindings +-- {{{ Mouse bindings +root.buttons(awful.util.table.join( + awful.button({ }, 4, awful.tag.viewnext), + awful.button({ }, 5, awful.tag.viewprev) +)) +-- }}} + +-- {{{ Key bindings +globalkeys = awful.util.table.join( + -- Bindings for shifty + awful.key({ modkey, }, "comma", awful.tag.viewprev ), + awful.key({ modkey, "Shift" }, "comma", shifty.shift_prev ), + awful.key({ modkey, "Shift" }, "period", shifty.shift_next ), + awful.key({ modkey, }, "period", awful.tag.viewnext ), + awful.key({ modkey, }, "Escape", awful.tag.history.restore), + awful.key({ modkey }, "t", function() shifty.add({ rel_index = 1 }) end), + awful.key({ modkey, "Control" }, "t", function() shifty.add({ rel_index = 1, nopopup = true }) end), + awful.key({ modkey }, "r", shifty.rename), + awful.key({ modkey }, "w", shifty.delete), + awful.key({ modkey, "Shift" }, "o", function() shifty.set(awful.tag.selected(mouse.screen), { screen = awful.util.cycle(screen.count() , mouse.screen + 1) }) end), + awful.key({ modkey, }, "y", function() list = naughty.notify({ + text = get_albumart(), + width = 400 }) 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), + + -- 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, "Control" }, "j", function () awful.screen.focus( 1) end), + awful.key({ modkey, "Control" }, "k", function () awful.screen.focus(-1) end), + awful.key({ modkey, "Shift" }, "u", awful.client.urgent.jumpto), + awful.key({ modkey, }, "Tab", + function () + awful.client.focus.byidx( 1) + if client.focus then client.focus:raise() end + end), + awful.key({ modkey, "Shift" }, "Tab", + function () + awful.client.focus.byidx(-1) + if client.focus then client.focus:raise() end + end), + + + -- Standard program + awful.key({ modkey, }, "Return", function () awful.util.spawn(terminal) end), + awful.key({ modkey, "Shift" }, "Return", function () awful.util.spawn(editor) end), + awful.key({ modkey, "Control" }, "r", awesome.restart), + awful.key({ modkey, "Shift" }, "q", awesome.quit), + + -- display playlist + awful.key({ modkey, }, "p", function() list = naughty.notify({ + text = get_playlist(), + width = 400 }) end), + + -- Display the todo list + awful.key({ modkey, }, "d", function () show_todo() end), + + -- Paste content of the xbuffer + awful.key({ modkey, "Control" }, "p", function () + awful.prompt.run({ prompt = "Paste to: "}, + mypromptbox[mouse.screen], + function (s) paste(s) end, + awful.completion.shell) end), + -- Lock the screen + + awful.key({ modkey }, "t", function() shifty.add({ rel_index = 1 }) end), + awful.key({ modkey, "Control" }, "t", function() shifty.add({ rel_index = 1, nopopup = true }) end), + awful.key({ modkey }, "r", shifty.rename), + awful.key({ modkey }, "w", shifty.del), + awful.key({ modkey, "Control" }, "o", function () shifty.set(awful.tag.selected(mouse.screen), { screen = awful.util.cycle(mouse.screen + 1, screen.count()) }) 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, -1) end), + + -- Prompt + -- add a todo + awful.key({ modkey, "Shift" }, "d", + function () + awful.prompt.run({ prompt = " Add Todo Note: " }, + mypromptbox[mouse.screen], + addtodo(t), t, + awful.util.getdir("cache") .. "/todos") + end), + awful.key({ modkey }, "F2", + function () + awful.prompt.run({ fg_cursor = 'orange', bg_cursor = beautiful.bg_normal, + ul_cursor = "single", prompt = " Run: " }, + mypromptbox[mouse.screen], + awful.util.spawn, awful.completion.shell, + awful.util.getdir("cache") .. "/history") + end), + awful.key({ modkey }, "F4", + function () + awful.prompt.run({ prompt = " Run Lua code: " }, + mypromptbox[mouse.screen], + awful.util.eval, nil, + awful.util.getdir("cache") .. "/history_eval") + end) +) + +-- Client awful tagging: this is useful to tag some clients and then do stuff like move to tag on them +clientkeys = awful.util.table.join( + awful.key({ modkey, }, "f", function (c) c.fullscreen = not c.fullscreen end), + awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end), + awful.key({ modkey, }, "semicolon", function (c) c:kill() end), + awful.key({ modkey, "Control" }, "space", 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" }, "r", function (c) c:redraw() end), + awful.key({ modkey }, "t", awful.client.togglemarked), + awful.key({ modkey,}, "m", + function (c) + c.maximized_horizontal = not c.maximized_horizontal + c.maximized_vertical = not c.maximized_vertical + end) +) + +for i=1,9 do + + globalkeys = awful.util.table.join(globalkeys, awful.key({ modkey }, i, + function () + local t = awful.tag.viewonly(shifty.getpos(i)) + end)) + globalkeys = awful.util.table.join(globalkeys, awful.key({ modkey, "Control" }, i, + function () + local t = shifty.getpos(i) + t.selected = not t.selected + end)) + globalkeys = awful.util.table.join(globalkeys, awful.key({ modkey, "Control", "Shift" }, i, + function () + if client.focus then + awful.client.toggletag(shifty.getpos(i)) + end + end)) + -- move clients to other tags + globalkeys = awful.util.table.join(globalkeys, awful.key({ modkey, "Shift" }, i, + function () + if client.focus then + local t = shifty.getpos(i) + awful.client.movetotag(t) + awful.tag.viewonly(t) + end + end)) +end +-- Set keys +root.keys(globalkeys) +shifty.config.globalkeys = globalkeys +shifty.config.clientkeys = clientkeys +--}}} +--}}} + +-- {{{ Hooks +-- Hook function to execute when focusing a client. +awful.hooks.focus.register(function (c) + if not awful.client.ismarked(c) then + c.border_color = beautiful.border_focus + end +end) + +-- Hook function to execute when unfocusing a client. +awful.hooks.unfocus.register(function (c) + if not awful.client.ismarked(c) then + c.border_color = beautiful.border_normal + end +end) + +-- Hook function to execute when marking a client +awful.hooks.marked.register(function (c) + c.border_color = beautiful.border_marked +end) + +-- Hook function to execute when unmarking a client. +awful.hooks.unmarked.register(function (c) + c.border_color = beautiful.border_focus +end) + +-- Hook function to execute when the mouse enters a client. +awful.hooks.mouse_enter.register(function (c) + -- Sloppy focus, but disabled for magnifier layout + if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier + and awful.client.focus.filter(c) then + client.focus = c + end +end) + +-- Hook function to execute when arranging the screen. +-- (tag switch, new client, etc) +awful.hooks.arrange.register(function (screen) + local layout = awful.layout.getname(awful.layout.get(screen)) + if layout and beautiful["layout_" ..layout] then + mylayoutbox[screen].image = image(beautiful["layout_" .. layout]) + else + mylayoutbox[screen].image = nil + end + + -- Give focus to the latest client in history if no window has focus + -- or if the current window is a desktop or a dock one. + if not client.focus then + local c = awful.client.focus.history.get(screen, 0) + if c then client.focus = c end + end +end) + +-- Hook called every 15 seconds, displays info +function hook_date () + -- writes status to .status + os.execute("echo $(mpc | grep -) $(gmail.py) $(acpi -b | sed -e 's/%.*/%/;s/.*, //') $(date +'%a %d %b') $(date +'%I:%M') > ~/.status") + -- read .status + io.input("/home/jack/.status") + datebox.text = io.read("*line") +end + +-- Set timers for the hooks +awful.hooks.timer.register(15, hook_date) + +-- run the hook so we don't have to wait +hook_date() + +--}}} + +-- startup commands +os.execute("xmodmap ~/.xmodmap &") +os.execute("xbindkeys &") +os.execute("nitrogen --restore &") +os.execute("xsetroot -cursor_name left_ptr &") + +-- vim: foldmethod=marker:filetype=lua:expandtab:shiftwidth=2:tabstop=2:softtabstop=2:encoding=utf-8:textwidth=80 diff --git a/icons/LICENSE b/icons/LICENSE new file mode 100644 index 0000000..ce5da9d --- /dev/null +++ b/icons/LICENSE @@ -0,0 +1,12 @@ +All 'awesome' icons in this package were created by Adrian C. (anrxc). +They are licensed under the same terms as the awesome distribution itself +- GNU General Public License version 2. To view a human-readable summary +of this license, visit: http://creativecommons.org/licenses/GPL/2.0/ + +The widget icons with the exception of: 'chat', 'crypt', 'power' and +'rss' icons (which were made by me) were originally made by 'sm4tik' +for purposes of 'dzen', I could not find any licensing information +attached to those original bitmaps. Assuming they are in the public +domain I am licensing the widget icons under the terms of the +Creative Commons Attribution-Share Alike license. To view a copy of +this license, visit: http://creativecommons.org/licenses/by-sa/3.0/ diff --git a/icons/awesome.png b/icons/awesome.png new file mode 100644 index 0000000000000000000000000000000000000000..44697e6d80972753bf5eb4722c1768ca84dd4440 GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}oCO|{#X!Z^ zL734=V|E2lkiEpy*OmPyBcHgH-VvYs?LeV;PZ!4!jq`UWT5~l72r#R^zMNexqMxZ) zXLhYFV1t0+(@BYmi?(H-ZD!&BY!~s&ur&09iQpoWjfH{V+T~AKHtdY>;}%$u>c#ta vjrRq!z>{2(1`k&8EuP(f>8H`JmN}va+2uAdSzFBlTE*b$>gTe~DWM4f96>?g literal 0 HcmV?d00001 diff --git a/icons/background.png b/icons/background.png new file mode 100644 index 0000000000000000000000000000000000000000..0d882b7790c2b47508bab27e3e994fd02c1fd2bf GIT binary patch literal 43786 zcmeEucT`i`*6$7=AV?7uP@0N@inOB=I##d&Dk>^XL`4OXP!nom0Yn5;L{XaM2uBeR z3keWNs8JA5Q39k=Lrp>r5E9-Fmhatr?)9Aa#vO0GKW+vNR`%YkHPxBIq%Z&=@lsk6yt2~RWeWTy5wv6P5oz!fDShS|_A&xs)Ld9vsq zWXJk+6nJq(@b2Tm&hT@=NUy-N01}Bbya4kJ^7cZUHG~KHq_eG70>JaQy}Py_L3Iq% zSm7G>4<3FhCk<#lOFX}B-`d@ravnWm-{ThQI+a6fuRY%}dt=KjGux)uWgWVU)0f|e zM=hP_%nLd5$H28jpFNEE@!j8sfFcI+ZS;$Q#HsHO|6%}9`~J+|7;FPX90EVT82o~q zpSONN&Yy4n$LNY$`i*$t&ujeo%719ppN#ss_g@VDOvRtC{0+K*AJ6<;{1<~?kn{7F z#3@gS@2vYV_0Ki_Jov?8KX3h<`tJ<>%!EH*`47?ce?;J)srd61NSmtIH`e`}`WJ)$ z6gPg-@gHK#-=XX0Gd~yq#o#|g*H2ddT>KY z|2y+n#QZmi{1?IhFLd_jEij0b{%;WZr=;zt;r?RqH*ET+I{yL#f8P2jlfN_g1zkUH z{S5+tF8+50{}1WbB5Ry=d%6w)^;e$yr9d?Xi$azEVYBYoM`vXNSN4HtnjREQUD<-IBZp8;BZ2O%W8> zqEiw~6MA08Sk&)OF=J^Ws8XOb9|6OUWW*55y$+xDf4q9P*JGWbaT#a*XHkZ$)6PU0 zde!Upat?iMb_OINY7(auG32WQ!yEE1tsuPgy#y=~GX`hT!TJ*7HcAuIJ0WN2a_<_; zl5g|f~00SDkjld9lXa0+Q623T^SGHa*k;=f;} zMVc7*SIdC%|Epy<_7cCQRSDDVnjvDr0x>!ZNd6(YMf@Zg(H{Q&W~zkVs+*b= zL2fKCWkCf_4H=18BN8P9qLy}9oMd?N*XzUsk#2z90#m_hM1!T6e1d3JMa*_UQsUGp zr5&eUn(h466Jqk2xW5qbS~2ckP-Nevw=l2+iiJDCS;0j_8hmN5S>)KOUn_w#qUX+n z0{vS}+9Jjs(Elsx9QrjO7tBKYp8uKY)e<{slsOvk1_1Z`74EU=994+s9r0!t6S$zFPiTJ4EL9FRT(2_BR}QvJ@8h z7i3`e{~BYI7Zb^xUvtBF(Y;@zP>$EdN(o4t_?`u!h)jRMTETC23pP70$xQz>6)A|x zKJkRjzZ5I8!{8satAO_)kkh$YiA#=4{svVdoCU?>XKLh0NT>DR&U*Q98O9p3OoU2i z73FcwVVQf0PltFC%u83vyN1rcSb!FARh%d2WCOKtVurBVCrM!B0W`*JTMa}28y5I4 z^$ov4JG-%}DHH!@j5(T+>dMnD27;uWZM?m03hOtP)lLe zKj5JvhBOp6B6Td3ZC$kedbW#)nsu14bV1bsX(ITewM|B3%EJ(mUjSw7F`uiAsgCk* zWreWE{J-nGD7*%TQ^4VGFem~tJAj@MI&5API9t`2>Z}TTkzs-MR>^S8C^Mx*hw=tH zDC9jqKvNR*PuqTc5kZ~`rbxK2=2MGHAR%c(0S_(suhF%j<5Pr7o-QeHgKmuu6&bdvG76oO_4QyzbtVI z6r9MJ{)0{p72di0Vcn0v{BCmpYObpw?138kGu{vdGSVW&{s*T{UUv1k?vKs?`wb`~ zgx7zFSQJ8m;T`7B&d{MMCJ*`7GT8qE@j>za>n*PBdiqbR{R@a**Yi2#@9?34%=ue< z2)X%BYyPVpt_Bzj@bV)P1nK`4054GTJq#+`iwhsR^fzX!-1;{*5DS9T0!)05Pyd}D zskon7{0l)YCMN&2gnVVH9ytE6Sy501#&g?#NbP?DHC<+FIq8RniHz{y80I1{rTS;Z z{uf-^fD7{c>qT>xVzjN6|1b)Xr~212*nrdjYrSqkfF9*<$lx;n?{IAmWV+<) z6e#};NB<2{4KjRxJoDYm!Hxd7q6Wc9={32Jm+t~O_5?N2^UntJ56WxxyL*?4X4yFN z8Gzqw6}|D_GbRQ1UXp3RpB-Iq|4KQvQ5VS(_^HyTA%awk`cqus|-zol% zG;vWhHQKnI?A5KVRpGHySj1(tRA||R{Q`HLb6C$lmu}Y+0Fk9}(l|8Ab;Z6}$n?Qx z+rp#h+>3R6oca8+p~)6j;ZJ=06Dl*`UnM(~*0R@%A?)7pSvjGYYldrAzNwI6YR283 zGlwY+&6jX<;=9`BY#UM<^5%K=P98t;5cDViWLSrG4(Hf*zhNx?q`3dEXPlsPegY@n zWqKIdIVd59_}Yv-JX#SQToKLpVv|REO4Rpznd_`CEbsdXHVawsPvGLdgiO00@n3od zdNkNy>7>2oB8yu9SjZ4?PRaik_{<5I_a$}0vm1{qur-% zQt@V)_^I%pq7&IV82kK0bf--K0X0*6`i&s!v{!MuwB@srP)lj80V(EYnmuvE@7%%) ztWFrgZf~q$__$_kaF{2_+owQY8A~n@oN)Cva$23dYSni?xR6SK^MAMQ6AH()2z!j` zo2+ljE4&$_J!c=@9W(FIko+iqzrdXGc}5@kS%E0kw5;aY&P=}7Bx6O2jSZ_&cXBZk zEHGreYyQG5nx87yi%}+e%eJQG7T(LbMQ~aTchA@%%r+PifA!65xM>^~$2!t(jh1cH z!2Qh&4E#<(`c{CHemBv4sjvUG>?Y5W^4ZzI2e%eG=h_aZ#U{L$V(R2&lO7#XAxUQ#7{o8Zmx4z`mkK4}-R`xTVI3dRW0@p4bjlsBAsY zvrVNrT@?!Y7kx8O=Al_$)6UlOV3CKs=MLroa>e;PUsIFdvnlvz((kZQ z&F@pug2-ScP)kUCHrYDm18d(QH89%NQ74ozaYm9II86E^nY0D5<-z>0#YF>qCb~5zHJ`B)rJSW&$MNe(C1+vRc z>(5&k1DO{AVF0Nz(f7gI*C|-dxzeF}zo?lI|I#VDy7uq|>}LMX9;n`IRR;%4bgf?& zjL~E+x+mkiF4qspLSJK#v(2e>7KNtmz+BJSCkNHxvLrLt1IMyVPo^KBzZN_Wx0-uZCI8z1`NwhukWFus!DUo6;bv^ zx+^gXZz($>R;y^wX(bTix{`9QFL3SL#o~40Mhc?T$jZWY#NxN~x%BH13fbRO&nIjj zl9bhbKf6KLttyp(b;i4lv6 zaFs`j7Pzqxu&)B(GGS0r07|Vxqs^@%f+}Arvn0dSiq2k;?aOayDV@aH*(i!}rK|j3 zZ1%+pL#^5k9(KodYU~o!Sl4^79GfU1er&L@EY(vX!(SVrQ%iZyYEu!EKGdy9$MtOXv3<%xpFi02%{B#fwkRH;`)~ zX5lX!&-_;E7)(cQ`U+T0ZO)LrJeE|g?;73cF`i|Gj5^}890cHR1;Yhs=dKlahh2o~ z58Kgf%x%9kHCa%!^qF;u*rKKa+A@gQzCScw(j0W(ncgVyPMNjvYkoAI8TYQUYjCgK zsu^I8^1jkr*iT2?46=?COeNbv%-%m6Nb*qUX_npb1CrjlPbsoY=INpZRlE$ir*)N6CC13)K>$K0B8j2dL4MvGt^PZdv zdQ^qN-8+VxoBn1`d$7su5fLd`~68Cz&|#M{w8g>e@ObulBDKat)S~AjVBR|EP4xS9r5C4E-5`6PUK|%p~A@v2%di23=^|?ODEgZO|<< zs@~hg8c=V)m0=cAPYqixER%BE9NM3x-&2=>i&{h#HtnYrv(A)4P}h#9pZ+~@j*Bmo z8r!PJ2v5)g>n@A!Y7J5l7TYIno4<&2TZ`tX_7TcEktX33y0boom({dv$E;cIA8}EM zuEHRGvffIJl-U#Wa|h^Slz1xn9bNbK>(=gumKs-bZak>2KawZVY2nIWY(@^%QKeTy zpI%cJV=L^Gq}KU#6xb5?nF6-a?G~*$%g%e-yh+mXPNBWRp4_uoyJ49a;=&!Oa;0KX zpn~_!NYLAqvKR>{_-}iRj_Fw#XquREY@^NJGg9Vv9k-MVVFzBT4FiF5(D%%|^82si zV}!okc*5?kYCWTWQrJ48CBZr8+@s|_U2IcaKHC3 zuDILay8g4m>M5-fv-29%Qr3r;Q=i|0j458WBZ2|Hdrk2LN%awFX-112kz^mF8*KyuAW~-( z!1E?h(QF<3!0P+kXkOQ}OwCjYty+7w0P{R@cV>Rx?6o>qWcG(_fbF%?{MHGEfKcoL9dQpp$KX?t2qqMZ6#E!B}}H!aW9e@%%{_ud%o2y*Ay@Y#;r}EVg-&P>n8|{`mLYc}MA#r|RGYR0!tC~Y@ z2UO&ttc%xcj=z0+&JQ*=`(O}s9car#-us99w&RW-fGJ^;-TKcdl~kkf{DY2w4I*c> zXEc13&6Wq-zSoOIiGtOA03X#H4-Y^ZaO)IGQ<6)>W2mcjVCg|HIC_f|}m7$GkK9*%wPSbjV|o5}eQT*TJ7Lur%CYAVlqp2Rpd(b>HzNK`R9rh`hhJgK^Po@bBJrR` zMcam7XxoNMepVLTy?qRV+GJu~0`ZAaX7ij|bfYxU1e<4gqt5pdiu9;G{jRsf>Ho1h=KDp=y^^#n zZ}zIy$cNV`6L<=D9^1`p0rRJV$NqVzC_Dd1R5>pt{dxmzUfqVhSAtm=z=_NaeIZnT zQZ#SnFq~c|fq0wUeyf((sF6!rmf>4*H)kaVJ8ZLp_o7#RN8q8gO|nFSc1c@<#28v9 zw)-*Q7SV<4-kd}h8y%*@eainqg3o}A4|f}^VXxiv`a;cbSstnJALBk7Jb`^C$$Yse zc=EiflBea8;{2Wd$(KSu9149m@P*3(tBpnpcgk@$ADU(Jdu#MCmQmu{u0r+RL_FC& zYZ5;EsDwS_UkaH%BG~F2vpJP7^G<|QVTt%Qm`uqztE8n#NbLe`%oCWirnwqAvBth4 zb0=Qwno~x(?zd*df^var4qemw%NUz zM$*LmEhrM$^gVLgu7g7_qezB4rA^4G5y1Nv=sL`0iQU%*b~*$g)qiif))ZA9tz{Ol z6%-`v2!A{^efZ8{rCWKD-Jnx>HaQW%=tMbr05&Mo**Bv%D^X5OzrX$;@J0j@^ye2t zP&YTw-dtfHKg~Y48ryguYst&p3k6){upy5}YEF-sb^A%ViX+wRsz_EbfR*1WeA?A) zg~Oydvf&JXpDm;FIlCL6+Yaa+K`LdEmfyeUnXZs^U^4)h8_F+*hbEvx1260{j3>oF zP!IF-((Oc~6?`p!zy5O3|B%96E6z2tPe~}x?3&To9bn8e_F%fH!M2e!4%+F z(;7?OTQBO-BxJvrBf2|k-HYp<{e)`nl%0X#YJVSXyBy%rztH>=1wZGMC7EcycI?IZ zdRwg4@%Cc=uFH_=<35M5*q~s0wP1cy$8r+NNSDJ2dmoiuKm`yvFfD6A|7eU zGb!fYU9`I#8P1yiDeL>`>VZg-T**_P&OWOp`^^EKGF;t`0`c}o-zvUhtZr@bCV72l zclHhdram1#@UEcx!1h7N^u4b`yI-hf)vK?yTbixoIW867Aon;BM861>vU|_?ZT@xA zYXHyjdkav58wRzWjAm7{duw((h063ai0_OY0aRl(m&Ce=nwTM4GP4idWo*~-7=LpV}P7# z%r;OVXK$oOtfc`NAq0WIBYKi9BxNUm$hvZswYu|o9s-}rIfMv(L1)?Cig@&DGN-`i1Ct#IOp96CKp_E6)`@xdHLR`ap=|wlTX&cn4}dCTH@=~ zJzs--wVcWxn(*s+g>chIZtxC(frk1tJO8p1aNem%fK7U-k+_E&Wtdd}AR>~w0w4989`3^x1?79~=`43Cf$3*U_ zXYcQe%7?jyYow^Ft47SO_}|z=;i*)+`;qz9^)I3|oTZ5YI~Z@@w@2MrbCi&D4{p70 z7TH7o>g$5QEE@^a*NQHU%`U()tK%=9Ph67Ww0 zklsv#ap&8R>0Rfj{uRrE$X>`bhp@eO8{8#mx+d7t$@qA8sg_KDZN&^#gvUu2(?}gt zmrU7HRROtfdP^}*IV)`nlgXo3C%BWiK>d-$OivedGsTXJvs?C1htzlcQc3bls_uH# za+tP7lyzgotT;qwK^-sErU@ zeN<$+G2U!zIK0+K_GtN>TZ|}?J8L12OsX)|t3mn9) zg4|I1rJ+!-FC&Kiu*hwxWg#AQ)i3XeBNz~DGlJs&X2j-;-QqV_{5E80o~|NgfZD@+ z?^|xyXzgd=qLd8?{U>?&s7>08GgBWs%{@-RwC~0(sc$Ikj8j%1I*>g-RR`ps$IljN zuLo^E;{w%vldya}z$=mqae0Iq5E}Oa_~>Mhc?W8d*r?w{RPHk`QNI9eUO}eQEfuoX zDWk5SRrmY`%!mGF$xb?T5gF_SefkH*`(r+S>TQ}>_&W?`3q5oxj3Pm4Eh@(D zv83K5bTXW5f#kKzvT&c$%O_5c3|WH?kHpz#t4#G)XtKWAdv|+@1DG`40=3*$8~1T= zxLdc=?A#VZd7`GDgS$Csotv8Ei1voT#fw6^_uzBG)(QpZs~~1W(bhw9RPjY!?O$FR zZxS`ez+#E!d|LV-t%AQR6o{UFfi-wQk)*qoRm=`xmEQ{r{NkgU*wV$P*%re|wu4!P zS|K_Tw6kY@dU7-{W!G_|;xGYtwj%!{EmU2A&BH00X=QS>Tp1yZQHBcP!b#b?2({BY^ zPs~jU*BAjD^T49kBcp9P0rX?!4HC>={=`0bzhQj!QKXFT%D8z!L!er5>YHyZ815c# zPDNo6lG1UaJYhQ&ZV{@2vCQa7T!A9@(1^dU#Mm!I>ZyeCua$Z)F6~v(jukvW0c^dl zx^(==8mjzqe=x4rX@i+Xz5wHC`OH%Kg*m=pZ8~j>7^1y-)+{HVq>Ug;{gI$r2lztl7G1p3j%xK%3uG#yGk86V`kFq9^aVzae2D$Qs4 z0Ts4LhKEp>eJ;T4^8_L>C>EV2TRlIXA`*tEw@CFKrrD}SDBN=#g}q-47ErAcR-)#Y zujZ=krmt~TT0(S1V&(AGb+lNYVVSa`CotjfJ5%FM6SPXx`~WS_ntW{pUmlyeh*FfX zm{QqF>>S^317ufxLNBul$#dqbrGlAe)>mJ*djy41I>O{}TgI*dV_e8L zLYghLoQ<2(!HlWv;?(5?qqef|D#dOAO zj^!23CC7uhzkoX`ecqg@or&0s1ft*eRg7n)Xo>a#a}X#=E@44Py#QQg4}#+Vw0b;C+sAAA<8aAWa=cgb*mqxRdSFWEtrDT& zccc92BP=Qq*}%>K=C~&g-@^9St^Ep?lDT#rcf&FQutV{*G%qaSk970No8!jA*fZkX zp+8n*ldq|7Wlm|rA{2_d+b^3%T8Z?jSqy=HSAtezzkEm|k6-LkCPpNC`l=DiqFQRw zo{WDy6m~6*x@i?W(%;Dx(5^T#aHE?F?R~qXuEaj#$c@?($aK$Fm6Tfdt6gLK>r^0e z;xOJn*V|DEx}@fU6tiVfSy19ud9rN~&QVQBHnJzgc8url4sDQvK5)kw# zmqsX6lrQ2j{nRsyZ(+~h26v}i;sYqG3{%JRgS+SZhU7l9S}&Gls$GJ%PO#r~!7h3s z-~HiwL8gl${_2i6S8+A;J%+L$r`aA>v=pl-uN?%otj@8vPi#|dx_SMJ9)?%op38j0#JPoWM)$JdcvyG(_@G3$;pqT+k)D*3+mM&+AnuVF zT5S3-!ABXXaV)8dS?mB9PT))KjhlhQ)UZUiAjU)P!L+OSIGEcA#w5e=9NM zqG6oDF4K(EvF@a5S?6+-opAaVcs@W4>Jd04zT>;sIW)9d=icVKw;$8v${UxbpQbt( z4A)&NO;A=`k)jl&@Gjc&cHfm$l9T7#>m}}S)ZnfW>Bs&o7QUD=2#ve}X8D_;QZiSN zWdV0TO;1^a$TnXQZtXVR?$3>lvC%8gC-q(G8oRl@r1=_kirR}|^BIG6t9-bpyrI%gZ6bG%fUIL;eC8alc$xtiuAr=S!& zUVMul;y1O)ZzQr4-DY=E(dXZ!^%z{o zkKcu#(p`!nsi356;Yf)9=&hHoegen|FqaLfPO~hyneK-l+0;>Nnfx|kMOe1n{+zxu}EM?#JQ;};l*VghAJ*gY6-0!u@(`H5!{}) z=Y5v*mdEon3AfcT-f$@G#HxaqwZUT$-1*#s=K;8T&pO%Ilq8i{f`e?Fk8kG+%Dms$ zh3^o7Vz%+So4iCa;H*Dc8r;n=F;4<_Ag>73B+SXyF> z!hL6@{R;0w!RjE`J4w|JF1u0kX(t<43Ju3={?=AZy^Gs%b8)sem_Qr*w>nIhVVMWj zS$o>w)`)W}Qbwcg9~?NyQ^|Nz(|c`uN!&H6%eDgLq-3y{fVK>OI;PGZ)GYcGwO+U~ z223PwPSCLK>xa7ic?+OGSm5Z zHQ919r0vsdtkSh>JgAwK3dlb%h?TKDKeo=`UVR*Tr?_6m(1U!L9_Vt}dC` z5?F(xj)hp!fXJoCTF~6C@|nMIm`4#aKAfIuIkt65>p?l*6$rPx9Y1&Q-V%KN=|r({C_JC4otmB!IF{lqBA6oGX~sNN_LIoM|mkNiU;-CilR z?D~6ayPnxmv*<1I@cO-@yfeJP(xSoi;pcH(L$`JYY}aTCYw50ZChI#XlWgvRTQrmb zoz49Uv;GOhF%2+qZe~;)jr447GRE(H%r)}F-V}CHR6aj*lKtLfHn`03D@BHQsnNGi zdpEXO-u;-4^$$t~GWPX1M)>&NhM1k~8999&OIl2q2EnrULsT7YpBHb>+n4G7-B(^& z+ZTeHw_hIoq=s6c1M?g$1_LEizdL@1+!W7Ov9`o4W*%QU`7TE4W#wCn(`})qIb!fw z86){R{Ey?=2yH_{-qO^F#CM5Zqc1;Ax0UP?=N9F)+k3rfOI$a#E5J(w3@sY58HTng zxP)!^`I@i8;~$dU+1w>v!ftLwH&`_Zdl1`s{1A$1Z1o^0rh0Q}c5;)XwGdexGZDSu zt#ec`dXbTa{*Y7o(x4!CRULVm+zwXmq#xhl3ghN-PQH&ewn&x@;g? ze6*{457^C663lfP>c-{4^fLp2EcAHj$dk-i`Rd2qdcx-7n_As(z#fGtmUUYeiPcP_ zG?hdTCz^kyY@BGd%7xAmu*(-QYj$w(GwSL7gzUYb>DfyYpCsdpnwW`%-9avwunA0!op$eyD%Wj?xW_ao++gO{&no~rtAJIF33Bq0<;r5Z3|$)Rd!SEuX<(T=&cDikoO=jbcQrXg27>cH z;;+6b**^3})7P13u~TvJ|mtT3G}m^Mh)b?kr2IJ!-;G&-=kZQ%9w*vVEsV^D_2@ebfAsDqAD_ z?=ArsHA{Y)cyDXpO=BibM_d*!I%t&S8dQ zlxFDMTxP$?V}*_Wx%v7IZ+MES{N#6X1q0$&yS*+4Oj$77W+-5c zKWrTkHJXT&OKw-&sHiH*+{04jZ8djO!>GgbX{0X*nsG)bki~eP*KouOL+U^l7<1=;r$A=ziDS_5*{D`k0oVbsmJCDOw|N>u4Y7!85(le@7T-x zyMPKr?l^#26RYpErxD9>2Wx2D!O4)3Mwz0VC*FR&H2;Hay*1DTl0((#^yL8hNhazQ zWZJHiz43(Q>l+&twaXu8$+!qqM0QukYL?$k4&A3K zqi3;BBZ$(kwjE_4GyhU020N_!Evg)EbeLvaQBkGHmzyIZu9xqY?WzK-x}MQrd@MV~ zw)5dvydDq~d=TRX?}X3ag4UViO>$6DOYkKXHhcKiUxB%a5Rw=67-K~B4oXj{rQK5yJI*llV!@%#3H)lt<8%Vrkk+w??-h+ z1rv!%+}TZzTY-5SSz?%F{vB7a)EIDSbDSkhR3XM7 zX1-E|RqLr%(%8hR_l}G8tXAW-Vv=9jcjki*4$S6F;XsycHS}42h9$MGzgr`g1 zd2wFZCi@H7OV5y+sBt`7cj$|*aSeHLmX-^K@Lz}gQ{J=IxJ&jLt_idq#g!qbvks2# zHC-78GyDJ#cj&p17h{5JiI2U_9!PY(3otVRv@K|j?bYs%a@tm522g-ZaV({*rKBBL5)?t1J>;+8IE|x+{2%tQ52v zPbYclvr1)aODSe9iRC8}xpp*Rl*~Z@tPUc z6nmyY(3(!bO$GTRmKLF24Kq4~B|Nm;^)7J*!aLitOeLU-wKX1~x|o%>w!U`E%)&Wm zHV7-8YGINy2;_@07OlrRGOzZmgp};HDo{@%Dc&ec+f<-@9qe0=i)2_?6S!Kv$N8u<&d?o^w@C^{SJpLY26mYPm+t z{M+$&^$HZI-2&8HIwOWSUUQY{8d3#)J3yZgH3gyb)BW-oh*>2lPO9q}W8bN7vNq!jw;3$x=ocKtW|-bAUuK~7n}TL=oODT%80MF;bPMgX;U@m(M16TqWBX*EF91XKAsAj}a52>UXkKEonwIx6I=XA$D+o%sK37w{ zMy86DqEMCCtfqKdh@n=BeGRM}ZlJ~JbSy{Tm`vE&Y z5C(?<(Gz&9=_y=d(AT!~km{5{352I}c~mU@lhe54>ajiv`f04o)H*8&mGK4kHJ-+< zhNb^OG3}qy4D?<^RZeV96RZqO^32)+RFL^i(lPh6kkm)KxeM=J~q+$_L zaLo#3#$E;1ylegS62N#mMVh$#bX}(kWuH-@sOupxc*OAHn?S!(xHRL}gF9sd_k{iU=;0uo6p~_L(Bt^l+(4!3d zX;O?VPv#i?!DDgI$Y-$$`|r-rbF5HzXUb>C3zOdpGr8>6-MomghhOsfPGBAg zzUeqH96Op9r%rPle^^tk6e7gZN)Df{&Muk!<6|tLyY-cQN@z&?2uXd@{C$41r|wMY zSZ8;xTsGzH5*PJ%vk?Wf3;k0miR_OxlVy``W#e01t{pu}!|}GvgtVoo!Y@WOMag=4 z*A@0hOtX^-U~pH$@9+HsZ9mrI**)lCbiuFMH*%(f+1`K!UCh<&k~}%`u~dWnv-v$Y=$GIrO@aD~E+oOT=UuK0bb|z;N9LJEojeJ`cdjPsI zA}OFGR=0VtWK^j0(217YD$Rt!x%Qmq*;rJoT2_8|pXiYCx6jW3_yWkc&%YmlEdTb% zF9u+r|JyU*U`a2Bz!K2j-3#-qk94fb}r%a&Y;V|msoML^Yf!ExgpvK zQGaw-pq`)M_0$ zwx)nIq_r%Z{!UEYV$6zlFVy{l8rx;SnO*Br0=NNc~VrG?<>d6RQ zlX?8(fz8PZvVB>(Ur_SSQwMxHXPSq@4pwYzPOr~8@ik0%bZXPc{({>+$e`vKAd(MvL?)zgy^2S=oI^1TC z5UWpZl0gT0c*j|OlA)z%KTqduQNa_%47xSnEsQx!Zkibyj`ihICrkP*Dk2+=!lTmAn&z)g4ZQVXhYXxAs3qez z7A7q%3E%fK zlYLbd!LX{ z_Hmr{F*Y6HN~VVl@tiv8WNOZd25D)fw1#C`P~z^c`mTdh=Pt!SUGCWlZ8v*IpLmGQUfO#v-`cl6LM3&QdQn(%>@DD-fq%U- zH0G4M%9G7HK{U)JMNy@i>uNq1{m0Vi`T8Yqgv2{E>t!RE)7&&4u@{O2<WsHONW6kbRHLqyc9A1C)L-T*nwU}5 z?@2NVs{YSOwCmYP`w?b!;Tvkx?<*%g|e^)Qeys$uSHp-=8aq^eoX&piv5 z7Os*I9iASo=G?RBs3J{Ycr}lcJG`+9kLg$`CW;+z4Gr-ir!~X7~PRHCUzIDvUfJW==QMPQI(iKk? z3Fce=%i`526G>b6vMUtWK-S=)t>X~0W75$_^&|-SOD{7PS2nmFyBEVW+97&T;KnN9 z-57?^(rQlbU?+CpTw=-Bpt~;-^I(@7z1L+zMf1%l$d4BoSS1Gq5=Q3_DQa}TV9qFlH9O&v*$<~> zTz4jS-eA5`oGV%@fxf=-vV%Biwc8S=`AGgVhC?ZBJaRfS%u@-oIVYO2C39AD)m-%C zxhW2qV3)}g-WG=ygcQT67Z|SA2l#h)Gv>Gy?g2(D#gdd%!78K*4I^#AqK3QEbdFji zKdF2~FWfbjE`5uKT_e@>K^O_P1EROT^IzeoZr3()HWYq(oo9O8Xi3PyCIv7*$2(dA zg&xh-oQO}8t3oxBR>XQcF5xM~q)1oM9HhZMR3RhXbtip5R}xCqEv>&_*=e($BOJQe z6t!(w&CPUqWM0=1L>Q3eVj^MN?;X(}zS<0I#7?=L?pJg(m7B{svvNA$|IrgaSphOe zad^fE)Y_bA9VdZd4I|!BU>L{P+6%$;hBm{W!+CSB)(Y>^wiwhgpbQaYEtg<6Dn-MS zR?SVBj8MMbubAoNh30@&@N8cQZqsaN>C^G)D{uy=#z)}%kFM5Z1v8)%k*msfigH+9 zus6m8dzzTI+!s4yb8Hw|Utw4DIItJvrj(eiE3#MXAs$*d`*FQIa#<`tOQk?FMj6~Q zY=yhV743B^F-8UwOp5wxL~6(dA0J7VG#RjawV$;}LGyA$ahyEw9e5CRMCdECdfMSL zWZI!u8n1Slu{@6X%Ks6gO{HTC*gjlxz*LwM-U_#MCVUk~lsXf@zJ)40=k3?=JJp;- zSQY$UONDQfyT`p?fW2Y1E^SP+_A0!v5*j`1Z~e(tDV#tdz{t-Ty5Mo-TB_-2@i`{- zWdHdRPfGje9TargXO;_hGJbhVdTjTLQy>6?xlKOfEqatk=(jkuZV5I^jlD|7$yOQ( z)zsK5nX7>zwi6FZj!5_HE&w zZ-U*P0X>^=atESgc5KAW$KW}JDj12B{!%#0%4eCBdqejPuzgy1Yq zbkAZ@tY+&n$1)?iBNty`_YJ$tln*%?NY7KgkdJki9?|bNmB)SE>7NdioprGW-wXI$ zQmXB&2Pr+h2evXXVaI3-D_)d(Pmghgb0LrRslk@VD11$*+926k=W0hvlh^u9(#KCZ zQi{0($$v4$|yf&_o$7i zeGs#!if+p=g&*<-<2w-4&6l;mN>{4qUXm5(c9b8#Ai+N8+Mm`!Y>^>4KWyCP=MhQf~EuC)T#wbpK2PgXY{#RC}>BjW@ZR9pA{BWh5TX6Zj~!rx)T<<%bHq` zj@I&^G_MXlUZ8#>VdrSwo&}FT!R2Qm4b-fp?diW+JXNEj()(BXNb*dUTWMbgAxYH- zGTjQTzRG;H`LdDfRVE&o8+HXeQmVEf4gvB!x7|x|^B0(XOF_h#+r&y7q`?;(h$V<# zt2Vw5V&iY4Sn_7{{w}a}m~nniZZ&w&a;|jyTxRPD0`zemV@qyygH{p<7L=`Bocx&S z^l%_+$MlGA2i7lwMSlVx-oUt4iEL~ppx^p}CtEHu{Z}B9 zF(LkPnsTOr^~Wf7_yuDK-0QoXXjTkoG*}ElcC}8{UjRqiRFijnh58lFE3Qw90x^$# z|1lWDQ1jITy(P%#5v${kNzxmIuC%K?rbW0DYYkRmEX=W?Nk_0hJ1w1;nn|ac8htY145F-r%r`2L{EX9^3M9tmI zVjnTW{(%EbNoS(=J~4!&gz$*crSYuoDvl8H4Pur$=<7}mvD#V)S4a$n%vwf01ovrz zQ?{~&09Th_LQ`|lS6sjoTNhybO~NE2p`#x7lHF`#cpV4hYK_gDPFxv1bbxP4r<=nj z+;7+pfOO|SQ;wk6)B6Ij4le~oAExB*%%%HZ4phB`yQop19s@E!&&UO@^(LXxq&OaC zxt!`Q%|@=l`T6#TMP9y_U6z0&JG6En&oOh;>Jt+j0_utDN9mxea6}qt%_} zrT}zDG%v_g%Pb^Rx0R>dFOOt-1L-q%CUL7JN24BD-g#CyeBf1CVH23U~=xJa&Gz( z$){K12+~$hfsDfv^1K}(;s}^T#aBk?#}htcP#I!s4(7EEmv&p4+PI86{zjae0A0QY z(Zzx&*ese`eSZV9IY(4-G!|Gs9$;ManU}W~@C|i@p{f|tW`Vlygrc`s)ljih`pS)Y%?cBISTIjPr7ycF)TWfqW|^Dc?q%c2|S_A zb={as4XvuJ)c?~wjAD!HO@8LFzDd63Xca=RUPDjPNe9TD&eyOWH@T6TxO_FXaRORe=8@ z_b3_EEW|8x0~5Q>naDZ(Kul|H(@edbWV-g84ADJXkUluU zsSeIT7s}fT%FM+P@9z_G_chHqoTjjn^w8c}la#PI>-LSpXgQ*uo-(GP3f}%Z{6@d) zy6Iz!%S%Q>h909~FO4X7#lq0%1~?ug@A}8KnT5v3aBUn(&$BF*1Q^?84*?i$p$lL5Zq;|xW1Xga7E)VrLl8aDUAM{l;3~NT*X6O5y0F*` zlK162c-R0Q!P8EvJs*W~AIlN1THiYta%;srLpjm+8Tz8MPD%qchT*=oAxS1M7(f!A zk&ot01sacCDTtIhbyF-5Brkdr1Ub|Ify%b>$au+myiN7yx%+~g@)H{wdWa3CGmw?4 z-H?c%#rc0XiBR!|bSD2-s|=Y9934>PrXyNkWncS1ki(YyCR%SOQ|S*e+X*>+5W@bu z9+m}z=vw|&jy|}Nar$Q&bgy8rp8&6`UFb6W2wAY&0fO5&S0GVu-z!-CgSq$;7io4~ zeC!57Kv`FCG@ijDn>+R|1^vFkA0L%U-0U}`f6J}e6@DZQEj|`K?j@i+sKh8k2@tCU z-)KLv&j$bOo%WNqij8xwxX8aVdBzg;c_#%qZ5_VCd}2$Ny9E_yI0C!CMMyq!S-k$V zu~>bYjh`?l8o7Zpe-9Fh4TiWR*W>f;1W>j5kz2C_%^r5ja{f?9^Nb6&M3UZ_idT}i zIjM{3#xfgWPRts{$(t*yA64OBM(>7~^GA1Gn?chY`w%#_aXR_I zAW#mq4qGBiG0KsuUQzmyd1Cb&gcuXkT!i;ZhiHB2?}D6_*}MK{(1 z`TZ#{?hp#0N%`zKfTZFq|NaS)H`z?LShZcV(_M36?OD@Mjx43x1}xzNAhm|HsXSoD z6yekR)`GSGLu)E;Qi#E&3NzmFmTM=+=~Bw4*TY}etojlmE0}!9k3~JcqY$ZCvDpuA zU;jd&ven?TTaKWe9>lyzE;27ILX79qF3X|5g{7sEN=uACW$tD zzse~Q6=I;L`er7-_!D~0-wsu5LU+R`W?M3>2jgT66Yr(H=or0tnAMX~bKZg-`Xgu2 z|4aH`Hg(Yb8}w|>vZv$Lx*PoEDJpj&Zoc_>beZg>bIey%=yAB9f#sS6^Tof?5x6;LeZwdr{m4SUf z!LYTgPsU1;ij#3RBno&i0Qj}27F&#I~_+CBO$|69IV(V0L`p*67SPpZ7 zN;^um^fka7Ojv+9&dz(D9iHqz#6c$15E3I?aGe0*rFs#-Me^C>F8QcrY;IQGtRiLr zBf-Rfd__O3c?=T%H~^xPwWQpQ>jGltBeeb0S_#!+cq2o>R{%!k87oB6U#LcER?W{6 zroC2w{BY$P%(n}aKY%X5e@0j_44wMzEIfISsV_-J`SZ$HdBY|jrG@k%Q>@tUc=+FB;fAs#}|7y!r)Sn(`{{`R>G3(e?kH@(@jT?f+S=h=UlZ$HPpWZ7JAzcu-$j(xupb0qUqqD5N&rJw_95hN4d#f3LXQcRKsT?vY<>7y zYAbb1b?YHc#e__to)Eo6IVxSUepFudWq@*&Ct|bma57`Wz9B!kLH&^=a!YIz{qE9| zmQxaF=6HbAvpH4Xdf?SqGw?L0=q9Q_TfSV1$c80 z0?IIqee`e7P=hzj=L^M1-7u;8^G)oj4@}IiHJ2plJV8DJl*Z1Y z0H#GdPqn9aCdib3q5wRCo9412fvMa^{|0R1WzvWVm+O0CWmRoW5aN>^!k1ZTNHuhthoJds6TXFa0wwC~wj)qt7wvzB4+!j*WU}R8;x0b6{>Dp$G%~A=lAlS(Yth-md3THR z@^{Wdlu9P8%Ah?DJKe-X`j1z6Ni`V|LQ&>JKE0#exv57J1JJHN2%1>$#KgzS*M7D&Q=?5wut<2b)y)~{W z4}jR|u6<>rJPbKwN(a9SKnPohr(v2qGn$9g;MPxAZB9#v-!JxmUsd@tOtmO98kjr2SD5CXzz>DD(k1G3>3`BzbmACS3T_p7iE9fL`dg##_(04S z0WY@4N{5DhZf9s6<)LHrquqp=uWXpFufTLA*||qRT>5!V$m!xA7jT*%TPyLzD~EJ8 zzt_I%vplBc>X>KIM=D`))h3s#)a_fl+P-#u?nD6?3UkS2N6`LwnrItMB?`4V2G`^* z7>^sPhSeG81wd40x7P(RF}9VeS`zi5F?1sVo*kQP3e8&TAaHGsAQ4N4s z0ie-!F#+DnyjAAW%8L>zQ+}N5(P-{jnBBG#n4XD3Jm5l*;@&REY2Tx%)pyoVDewL5 zgpD#)R%ej;hpgGGoz=LrGZo~sW0o)O5b_7QnjAHufe!;AW&kCtn^Y6Km8cv?dsK$m z(SYgQN7wp-G34oln1Du@h4DA&ga?ITzD;b35%C~Ib4z$MT2+pf4%Dk`Bl|J_#HP#k zbl*R0oovlPNfe~8!1b@322-+eJmC`D@1zD*1q6B=6{KG{N-Dgf~mAZY3n3T~O( zWDBb>`|6o&U5R?nEs_nujV;uzqt7|qZXo8$th})k3BRNgwKZF;Gp&J}p4<>L`gD&> zq%MUwu~OZk6cduvs2s=C89?W>GmDQXt%U-CG=FLSW39cRo%_ulf>|4f1H6N(Kh(K6 zhvv}>i1;90&s3@M;f29gw%1+!f*Bci1kZJyh^M#b%rEO*%po)p z@iaaYgfyboKWwg#h;U^Ts_=D!r&=6?hL2~VwO~+Tx=i$>FcU=A;`!!^LNZJQBOeR5 z6HC*SXuI8n6`Ve|8x*90wi6}i2@84s*IjY0JB%;BOuA6j_aLkzD_nOr+~Bu})P=lU zZJvzSwZ0g^|58RJ}E`VX83NUa}rEOjyChv=t{lof z+bF;r=p5>2Iucy9goMC&O8=j<$EMJ(LEn|Az_%17m&UpievT$NGGU}-N*sP*BnlOO> z{8T*eY3HH2J;2zBYr9J)@maI}0}kSduU=wi9%zGjDSF^+^cpTGFVy z$MQ%l*b2s*^TC0vJ2xRE{6to`D_1(4E?U>9%XjS?Y%Mswog!;*q@#eP&~MoA;27FY zB3wUe>M0!*vF8z;9A%?I$ZAGNiCVITunka$@46dIkqTkvOi1VmIr>`=_8I!q38rv& zV_6gWJN7vtp~+3G*;Z{jbgyJYxR^j-K<#*xerCAm-qcMO&OiiXq(nQW#Vcm+z{k;*N&&IeKK*4fY|(=)VH$Ju>! z`7hjX;+Szn393>Pl!cjE({XSUlt|qyx1p#`^TsA%QU`^1`}K3f=En%z!p)!ix0Z7F z+Obn4HN+ad@CPSer64Nl82Tc_MSq>urLimU{VRqaaIOpofj6JKedUmygvz)d2fejX zF(1v#1zXX@Zx}lAwZq>~>Qa#mkS}N5 z#7DE_d!0uv%Xw%mr-&TIU3yM^G895Aj04j3L!CPF@Ds#0#Fl`MgGlpR(9Yec^7o1! z&+y@62waNqYA>K<(aDF5_F2CT=nS|~n`G_B#0?y@eJy^!5PeubjGrpgWx0opt~~?J zmi286z(%`0T9|Un8eQQiqWZZO?e9wU!}(2dL`syR>b{9KLBwO}ObLgxbl$_WJrgxlyE)dc-$W4czgyEMzwDDcNo*gPcr#YtHf;!@>72|WE| zbq37IBe-(6G|4ce^4#uJ*~Fx)-aKQ_NvJ3nwd03jD6aP@FQCl_ZK)P!=NwA>Sli|w z?h>VNdlQ56_>AF%wK(DMATp;s@b?Xm`E7}4a+9pXv6b8>;MLp!}meK;*(2UrS z+#j#{@ErxA`5WmszhJ^WN71_3+au{UifgCniDctZD|!$h5029HZyw7AxeKdB%Qrwi z&m_XjXll9Y&wfW9(5MiyMd2a28u{oZ`gwjwfQB5TjI+A1CP;9avp8qQPPA@D4{kG= z9%mpmV%n5q2CbPjv!Bm_mZ3WI$NPfc_n+UE>Qjpb#X2oRXvz^K!!3>?pvF0|sC9sY zDXf(gBfWj*o0{=GC8F$s@E9&w*CLtN&=nipNtr=BVrnWH5 zjnW#}TQ=7-pMLJQMY%|nY>82wKcsB(zOR9}iFw0Tw9AGG0-942_$ARMnS!|d7Urey zrj8BX)Z-MJy{QUGvxP}b^vtCtO{cEcIiA&lYu+ZKI~0v#QukLoNWDdTUknoEGjPR| ziTg;_S%8f?PNV$sCbDhB|Pr;}X^` z?1Jd#Dp0~CQjNFQ$j1N;0}v2s*Y1WWbkl7?s1O6+C%~J>Lrjiy5U^omRY1@l5`bJ^om#R^tKEQ{{^7-Uo_pu?cy5Dry zuXu)ULmC`*0!UKSerLDf$`&E-mE#mMS&Tx`e&NByFR+!cSEas<^Ti(w-=FWYQc0h9 z8XUMU)U;^D=}$z8lHkdH0bW4z1q^$pB9JR+AIv|8%%A#_n9xGbYUU%16J>?e7 z`=7jk7wQ7UbOn29&s=~)h^j*>@uCNJWFrIZ_xX_<3OH<50)g)u@F(YT2vU-Dnt-Oe z^3u(^G1Xu2Ecvd8q*_3&JB8B@2s=_VmfVg)I*s&Um-s|UZ|T!oa*l!~gIGz(w0l6) z@{g9uuiFlYkR%#6p5-n4sS!JAD_*D)nbe%x_{v?BN z01BxK%X8p#B-FYRGeJ}ZO6y;ArtG8FcFv`g5zEK;ie|TT^dNGp^57@N@J?WpE{v{V zMlu^(^eWe}d=r9uLYTqb-{n%fIMGr=dXUfQjY40tZ`@$XOzo5{G1AV)sPywTa0=HPs~_EJ#0KCQ(NyH50iqw5jnQ^OUcR zzV|${^PF0yk;>bSkn-#YOZ`*WqfdqT-0J_-<$a2RZWY_u4S~+R|Cn$Akp(XDNH|f%FgV8&2E)9B5H%n3GQpcl{cjA{7+W0_fp6UUp5!S z5+s^}$jlTo0JZ4WafU}cdOUu!_(*8Tog+@rEnJzz!IptX4KU;(m((^U`}EJpwDKG; z1-Sd%-I{Ed!glS>ySr29{x=YFOduPK7;LWAdxp$;MMbCGnwzrwsNuhjcDGZMv_S=v2k?!8lBmNZDVTY*owDFHd%SY#v!4rG$@AT4F7g|CsO|? zC1N*nOXB{P0gd#Q2l!{5eW}&{FrBnECjEFAbxX;O^Z1&Q&~Ts3bcuon?&R@nedI#G zL`|N@iWA_bLp>tZa-}c)qmc{mkkidbnrZVTh>99(!Jq-I#|eklnJw13S3%*fKLJTa zUpmLJJA&CgQp6xQ46p+liTwVGw(BaYC(QmVgtdENK{k{`%vn_b0#V8xOy0#yz3~Cx zjm@#*3%Sehx0$q#Gk~CM0jz-i7M|N^8xk0ZbDtW)95@SuiU6bxfo>LTCNXN7Ee@SM zTM+AZS^{d~#`6Z|^~`)orViqB#Lg1M+sh&?)Ruw3hDzH*sd8x<8+>@iKl8Nj@+jI|HjLTu3&WGc|XB?ot@~*LoYf8?27PP|G;Zv|NsI_Bm+)EO&9(BOONMFc+E%8dyDfYrF-UpBw9Xw^YpBw zOzL_m2_25sItptCfv#>9m0avT!afzaY-dsdbJ^MRT%gbuSg5JKYH{(JSBt4@ zU@vTC_b?=McI}zs;)Kw^7+;#RbmZGI4+(FnUV(ZT>!T~ z8!L7PBp?FJ5ScUDX%5J64uIALx?~-RAt>O5UZC33-*>IID-JU=IvJ6lT|-WBvju2w-2e+P*vL6gYG0qw#i z>utNXA%8neu~ONe;q?TOcFl;bKILvK>`BscG3hoMbw(*t z-HIyNh*b5)eEGU#xQCzm|L%Vif0uh=@;&^W|7>|SL@D6%O~v3zFS^s7g@-vLMV8GB z%U&y~ikbR*;bRn(;hE~tk@qYPy;-@-u93zm&nruD{peyM;<{pRf4 zb8RcY5)e=YfsH5)Z|Q)^d|%HuB-yP4(K;cA0P+tkl@CN6(6U z9(vhpW*NECvjA);5RtG2Wh_>S02*661LaY3>$={zaL~5o3U!C+MC+qotYQGXnR=Kc zR&(kQB%bs^N1dG`0;>PXBWT@p{095!rPsrjsQl0HPzN>vY{y#2;AchVCz?SSW^D}< zV7{Wkgscqz{An49pZc_P4k>7iom+E>A;su4A-wCcD&CW^l$l55KTqNhf>5wy zmhHrXtiQ1&!BxA&>LE$%C~b%Dk4B@4(y7N;)<6?w(LG@7P zQ%u4uT5uUK*p?Y+TxcR{40ObcZl)dIS{niX*-#iXQeCGn$(tF%SDF(W=cCcYy&xMS zN#5I8bJ1~+n3SG&jZ)mK%Jo>bRSx#~$3{+iBK!nCa|h_dGTphOcKs#m&p)GKPSOc^ zdz2zkl=kp9m!2c}dZ?&*KuXmtxZ_rbN+jD9Dd+qVzprG%J?wY;x4WJ^Um=Q=O3mjZ zh-kPu&3zLECxajVll6E2vQq2(dFsGlrWo?>8>Hwt$@*)z@ODGk@-^&^pd_4Ec<$E7 zCK;12g+X}+2{ngtNJ&&cC*kzC`kcYz3GLfNI?9|*56wbr6~9R|>4r!&SqZ>ew>QliiiZR_`GQgk-@=ZQ{SPdlH;TXub9IcGj9LSl%Z5+27pO#{id|+0t;onhL~;T= ztY|o87x35OD{h?qgxKNNrsO}`#HzN5ZM@BH`S381K z&nMTE9YfK2I;ud-vQA1S*cB&1{MfjP2EiIhxO(B1kn&D;h4lu|hGd&}{c1_W#r@2h zhwM>8XeZDoT;i)UfeNseyw!ukbh@%vd*i1X! zSBAOB>;3Eaw)B1oaz4t*;a;OR&nh>4aB-gFOAtgbb z=%Y&E{T51{%TAymxuxf;n|L#j^j+ms_MkV5pKtWQ8H&dN$%qWnz9rd`E=7yx{F8MG z{*)&Vr8yt)+mMq1x_q;EwC?O1gfzmp3DFS| z*uR~7_#?5c+&>VcI9pzBK=sL@DlzS3gQ~9g%kQoZY4_t6SMwGHU`yMHrZKd`D20{G zA9wdLgHDP8p<~#!G^>g_w-FqsbS#i1CE)BtnpD#z>Q&v@$JSZYnuIHr=>6j(_DxK7 z$5KsWN64r0IO9wu7qRA`yx#*EUwIVf%UhKl^4*hwM0cpgLX>c)oekC_58I>4VCLK6 zBL=UHv+bv|blqJLb615PYMy?*63%5_w0Ko};;Kufj+`yjose_C_L#@kS7F+d>&28z z?8S3@H&-ep3UTFK$~L6$0AeZz&~-$GJ>&7Bp4_q<)mFN9wVrImA>u1_!C9lZg7ijZgMcQ=@6GC;QG{jLXz$2|3TwIz=3AklQT zAWnY(%?r^7emeI#>*3ew0RZh_)^zPLxp0F(^mDvbd1AMnAtZjvoeYBrM<6v*dtnrDD(!Hi;3WJ_9HlAa@Z!bln#vMv){CRJWjk8 zfEE8vNF?Y9qWXl`MWn?xf@RJ?ifm9)Oh{`@Nc+THXyYL^`So3>`CRROfVf{ z5~%FMef?f2F=!_>8m7Z+IQc+y;L@$Y`s3Mvp97fO<<98BB$jT-z43rFzI~zcn^K#^ z`zo2LqsMiU+c!u1T)ZF|fto0tWbSxpfDQCMRdSA;P#ZC8{|1D`zfXpLI|JY1mBg3P zAr&L@Fq9a6VmI<4Bz1=mxtSsv&6>)dZ*lzH^X?|aVPgBiSnBSj1VWnFAaYjw@ocAy zB-eQugfV4Nv-&{_nn6vbZnUtI$?p}fJ;qy)<Fu4vQn2e;`X z4V4auSZYefm1Uy|=YD-gTd6+pZoqaY~ywW$K8*E0V^3c#>yA za-rjo`2hg&j$>1+1CyQDM_+JZH3+lY1Ql-(_aKq8MWgd6*m~YLUkP87{j}o|U zs%>Hk1Qg+0Z7%caC6Q#;)p_UdSwpc0DZWaQGo26#DEmQ|Qb`aC?RX2O>mI*pzZLux zsn0!_bG&BaJaBqwO&%{sR4Z{}t1UQfXTp2cUdmcMjt2>L z(D1lq!YE&kxePZLU;3*mQl+6T>{;l47t6kNAYx z;z#=9VusKwAg1jQwc5UTZ~TWjB&~^S&g^ih4J*- zQk4W(uKv+%ZdDB1mh77_X+5B0FQ@j8(i=%-f zwH-iaiPBQ;a>LdfI<|9dgX-d$bx@;pO#OR;*OUv4ci#t+suYZ%OMnnoeL>bX9TPWL z1CYHZCD~(Z6BZ@C-j&n1ufN}du?5h9+<>B~7n4E*{dZv@i7<0Wgx9-{xozs+93xP0 zy*T?Jx~)rJ+x&XRLNWQele&`BmNZ{MpHB%+O7|w)h8E5)o;`tXPdbza8bQ*V=}5xu zEK7yOkZ*op4+Ct3%Z3S?{&;MO%{5YW^%vYhN>6reM+&}ZZE3$busph-$l!an zF8*qyj!M~5W9#>E?u~)6Ck6W(5$;#>`?qnb*w&i!`0JhIf~vhhBG)*3ktl~|kaN=n zU_woACu#)qDOftrGY;$l<&PH&{vz-_;9#%KLL18l&+YT)EpO${bsH@)jUS&7}&T^v-pJ}$%B(V>3+3E-1qteWRU- z^VdWr4InN;Izw!4DtgC@RbA7=d};MR-ji9yzPGs^_1cP>+l2hyPDQKU!xK(>bQ3oJ zRMA%;EJPyIZfNscRz&n0+Ufbe*0}fk=lJA%q#3q?i4x#-7e0_ut^Gid(UEFa70yzT zjIf~v5cP16ka7v0)&ty)07LXFlF{=1l z`3KIEk6kR-hcc_RAJsai;v?ii#IeHOQ2=WFeoAe`L9fn56o{ECQ+=3TM4k5R(h!Rr zMGXtSO{nN(Xy-CE6Rd})G`?$aTC)aL&+Oy4Uj)*&Q5NyKbU$b~2o$WPcvGJ@tm@_b z`0S5X)9!dHXQ6=sn3LI2rM1+W3y%It<8KiK#yM)aNzFl0EwD{F^0-Y*!x8`Ace zfz@vzAL4X|egaX)&cvEyKbPB_*mT?OaNIry+e}BR`Y20XI>TxJR0(=!jceSkMDCT8 z@}E(0k1zF~(k@hw87L`8q=Uv;O&gwqS}yINsxRFsDx0^Zx-}0zk}(YUTYJ8EO7QQ?J$alHf+K{}{X)S9i4ms|&rjU5g5aL0&-e;O_T|h;Zj=VF<&6P}Y(O&}~ z(&+&NMh1^~A2xR=BvzYzlq-lF4Rhk$5V{33-!htGBWG5M z1ASbSZ_i#0;9YXa)nM(B#b;^R`71VZ^eX~Vr$3e7RPhMzgM)V8cigOp+;a-DIN~ap@EhBcv!U0B39~j)u|J|C)!uQ{XZDGc%0oix$DlI96}o){ zLX;GDbL-c6%@=M2+oluWdUJd3g#w&JE?4H-q*cEMwxrOulxbBe&h%GjcZBl`B$*qK zjxtd7A>s3+owK7O1;OqC7m{#~zhR~Q^SxTK^()}-2wiusfJF5trpiHG2tJcGWz5le zL|ETExx)CEQD>?S0YL;v!7j>Bry2(@o$awpI-+E2LX!G){KLC2w#jSGVl!A<`tcgs z#90+|T&ex{+XHr;dpi?a9%v-_79`o{922eEyd4t*MkfP{DgP!{c zhj-fI^+S7X77|b z%c1YFp)MqTx$%NG*CM5Ixy+i9BL(`~P^IGa{r+p2GLeob9}A(iiH}iTAJsMvd_C^u zmI&PEw-pd2U&45a1!z+2vbyvwcWz`gMSfOwhc`Zg2P8kBqO)wWdMLGR>9 zrNe3@srD2%pQC43T3RIWPr7O`53F9*;bQ2^W`#R8QH4!**)Qe_MaX-JXGfuPQbVYL zddHt&4_#S)zF1*igOmkgM5ky6(yfKOO#o^>P}`YO`7xJtXF^exw@6w?htyF&p?@yPrCk$ek9yK4f`*pdx2X*VH zNJ-yuiyv}0T2=JYX_pQc^pyvwBgY8R;3+$N-fNZUa2!iHeKco(V$?nn6347`-}w?> zMCpq(McclIo5-MS<09yF&FD#~yf~TkdUOzkG@6#mvz{n2y{KZ{)j^|<5!rAuD!F`vCukR7J`S)xeI>GHh#Y#Z6a*M8knY6#*)^T>np+}Ruq~rRMbl8F zimu%%Fj-*WeeWupTIjaz(n1J%D*X{A0ykHw!!AZvA}x{9_Y_-) z8lO2)kT}4?f2j=VPNPSgD*WU`TF}nav}X0Efs+J>xPf+SYMnF@FW@v82+Z_Vc}zQN=JD3)=MXekI~*$ zI=?}iN6w*Z*L)vJ)pxlDL$t{`5A82F zT}o#P{;&YP6}z0Cq3`3k8Wgl<0(+|HSAb+cM=q^i_Qd32Uy`>5pjKUe!zs^p*#i;_ zoLqyM{b+4-zNNqqYF(~4UNe1AZFM%{u|{ftK=9W;rh5W<#_8oAZv)wvofK0X!$dO8 zqVsZRMitlVM#*MYmP2(0R;J0RsqHOKvQs`RzA-V@fyRzV={>zR?|JNT>yqQ#(45NJ ztmG=Lpb6v+uw~`>KhTd53GeC@Ob?&#t=+qk5n@H2LX%a{>j#7=dDL1i@13^;>owP9 zodUN@04a7n@+8;hTgMbj-}e%xHQ>`YrX1^>(d-NXL1oB*#q{vo?U9~^x7|85RX~IF z{?4U6kTisa^7dpYi-tfd_{f9NAk1@+`6Eot$4tYBs2^c|~NNn+7U>V5)nxU^zLx^pirmbXX~^MP@Ol@}BnlrlR@-_mXAr5Y&7^ zjEE!S_YLz_Ez6q=O;Zuv!T6MTi z7qTzgf2sWQb+QaHe*mGwz)?^XBUQ}zybLxs^NSvIYK5DlE#BOwiCGGEqySkr$Po%%J%SLtD4ar_b8(j#TE*2w#ULyaCX< zr*BM};CKf?7G5lU>Tm801&NG=R|1L7&S9+CB*5*CL${ZRC+euS>?a{fOjxO3+=*Xk&5 zmKXL0{2W_0#Wj8qJH_b%pXsu8g<6?XI$DQ1pP20DZ{k}5JUD{e=)#*@kY zEUT{u?O|9-asQqd`{zXZ0>lbFAr*Vy( zAZN-qZL-rW9BaCpt&r|vJ$&^-iP)#%_e%1Q_eakrb8421GR#IzyT7TM`9MQz>QIAY zH~7@oL_Owp`3^Sg3HH(Ruo8mGif=e#glLx+9n#jn{ma503eFIj8&8-Zl5Vi?z{A3k ztA5CF8ZAcWCy6DrI@`CV$*1CRP4Hciv}`Nxr9b#g8s8W_VR*JmOGiq0gxBk&nxj5A zJK@aZje14DPp91M5C%*9kR*&O%|=(a_@6{xHN; zRqALX;{N#!9BfE?NDO76ostwO{`18@OmCP-r`R-kj}#Ar#b4n_3}yJDjb=Ci0(D>N-QiMb*&Dah z*wZIqXr*6vX+gYV@v@>aA{`rYyI}cl5h^KskrkRMRh3UZAWnerMM6D6qU}XsO@%TI zNS_Ibp-+bI+uW8d$WEtnW$sTl&UkZ}i`Orgh<9*BI-LcU5XozA!y#r)<`(na-@Us@ zX^a~-5!$2dgJAt@fRHA}f=eM}v%|&)rUbd`zGdcNl9$w{lFz^;aPhU1>t%~8WU>b% zH)C`CSsBOo8-J3)Bc(LbDrVAjlOaaKM^B?m>?r- z0hA%xwCnM?n6Al9jCZXaw@bZc43JlG+MTtV-&JvqY@_4i`z_WhDs+2u4cME5S^7xT zx-wP<+tTT$Qil{w7;dWa)0jDas&muuu|IO<9`4^Tt8%wW*GM(m!X^Z~1T&xaU~YT$ z=ySEY+Vl8#VRw6;FE^8L(#F1*a0Z<~HazyCLcis{B~k4!zeAYK8u+eFy(W}Geja4K z-*EXIUB%I_!(CRa%^%92`8YeNh=1C3w@MF2S2yCujFmcm1jQnw>fsYhYv~kr(-qOt zmJR4jcoprM0NW3ecAt8h`+ycAQ6C-&F-dV%Y;v2zudFs0PM-5$zygbmZF;+OFi%J&F|uOV=AZ(^5_LE2a^0su05 zo-xOacGWtZZa1*~)Dzo>g=LXzVb11o!KpLPbL2d`7MG(xN|SeQ_-irEXr~bC8JDw* z=K{|-CwvsRRb_N&Q_IK#hqCR7qJ^K%ab4BOQg)yEDczaLOY^6?Nv`+CBuhG&6=wBu zw(WogoF18a6gYPKzuEKoq54!+=v216r*7Z!My@>s0^B$VrzC$SVuQ*tN1>6|??Yb& z_PWUMsoXv=ciU6nE5Y+!9>HN!`i0ma(zz8A-P#w3OZKUSVLcCeDs+Oe*o$;uQak`Y zkXrkEKl_)--fX!9`AJO-=S?F8y-v#6lh1tZLvv-H;)~Z7Pn1sfew&xjtfq2_1i8bG z=G}hy`R7-{jG?cbl5}Ox;{1qPt_%FMJ|OZ*9kcvDWr=+WI~%+T3C)DwCdPLgb0SMa ze(!ZMh2XKG%9FN(j{`DaBU3P@LVpq0>mjRo#FV4hEVn(bAkeEcMCxNI?ei++Xz<6s2sQjRLIYZZv*{L1HSnDdHusc=(4Wh zUl0AH8~*Sg27ER9^ZJLu&lT_=`Zoh0T>iTLp9lXionN>9VLJc))_-hXKVtu${6FmP zuUo*({_FaO!G9g@uT%bq!GDeb{^xo9n)1Jx;D2gf|GRO2NgDp?{MyrBoAPf4zfSER z2LIwff6?HtS^UG`KQ*skQ~nnd{DY+?n{{ttuyuF3xUZ$#={fT{8G`d1tMpD`l- z)132*ZU4>S*USH5@QeEXVIa_(^!LvF_ig>}zxjVJ0sOs)|Ih^gfgXR|+6f8S_4ix< zVSj(!`VSH2FWUHrbN_Yg*USH5@Gs`|{|S-)zZ>^|yHWo~2m1e;jid2YC#~JHqvRb_ Q`FwrC%FeRn*yX7I3)m+Xj{pDw literal 0 HcmV?d00001 diff --git a/icons/bat.png b/icons/bat.png new file mode 100644 index 0000000000000000000000000000000000000000..8ca804a8590d181db2abbdd53e6ecff78e28180a GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}Y)RhkE)4%c zaKYZ?lYt_f1s;*b3=G`DAk4@xYmNj^kiEpy*OmPyBR3}t*NiuD$v~knPZ!4!jq}L~ z5=ISzGe6tw@SMy0aOKbW0|yRV*zngXhWGKR(1J>_lF12DA0!(>mCamVv>6%z!NX6^ z&C8$F=SXp6sj!^5cB1L>%8Y+1Udnd+c^w%TmQ0p-y}Crd5NHE~r>mdKI;Vst05kza AlK=n! literal 0 HcmV?d00001 diff --git a/icons/cal.png b/icons/cal.png new file mode 100644 index 0000000000000000000000000000000000000000..a93384cc2fb977c0eb60c53f94db96f625662cc4 GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}Y)RhkE)4Yy z^BL;5n8Y&zMK}vQB8wRqxP?KOkzv*x37{Z*iKnkC`%NZ3226!m5dm5F_yR5Ol$S5qf z@xMhzlayrPg)18;3ZDJkQ*nr0Y!?p*=vd@Pw=ggyDCFVdQ&MBb@ E0BP|;W&i*H literal 0 HcmV?d00001 diff --git a/icons/disk.png b/icons/disk.png new file mode 100644 index 0000000000000000000000000000000000000000..fea47b9be75368cb7a67ef650a874ed5d5ab4099 GIT binary patch literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}Y)RhkE)4%c zaKYZ?lYt_f1s;*b3=G`DAk4@xYmNj^kiEpy*OmPyBR40Df^+!vtw149PZ!4!jq}L~ z5=ISzGlT8-|FgF{+S}P%@KxuPi`~c0~*TU>FVdQ&MBb@09}+l=>Px# literal 0 HcmV?d00001 diff --git a/icons/down.png b/icons/down.png new file mode 100644 index 0000000000000000000000000000000000000000..22d5855cb7bd055c589b29005dfdb235abd0aaea GIT binary patch literal 250 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}Y)RhkE)4%c zaKYZ?lYt_f1s;*b3=G`DAk4@xYmNj^kiEpy*OmPyBR40D`GFRpBA`%}r;B5V#`&uO zj(p7qJjE{@CR==%@h0+_>6geiwm!l-FnZxSmujzICZN>j#R~*<0|{XNQQXiiv@Vipc|$7S`p*Sa~bvdTs0VdBVo`*L0Gs dg);{OL$E2&mHXO1mjVr9@O1TaS?83{1OPi4F?;|3 literal 0 HcmV?d00001 diff --git a/icons/layouts/dwindle.png b/icons/layouts/dwindle.png new file mode 100644 index 0000000000000000000000000000000000000000..1e0aa0a005b3a2cd7db7996f61841c43afd0452b GIT binary patch literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}Y)RhkE)4%c zaKYZ?lYt_f1s;*b3=G`DAk4@xYmNj^kiEpy*OmPyJC6v9f~#FtKTs&b)5S4F<9u?0 zg0O*+fq}uDoyBb`zFJypOK!7lZh3lcuJQkkJD6rmbou%``8BaM#@H?~$*bhgaiQf;7=tFO1Kn9{D5X}w+#v+CgTd3)&t;ucLK6Tu Cz&`5$ literal 0 HcmV?d00001 diff --git a/icons/layouts/fairh.png b/icons/layouts/fairh.png new file mode 100644 index 0000000000000000000000000000000000000000..b4e289d6e7dc711098035859923a4aa556350ca9 GIT binary patch literal 194 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0P3?wHke>@jRF%}28J29*~C-V}>VGHmHab;j= z1TsG~WlRJ~mjw9*GdMiEkp|)S$Ssku=CXLI5gE>Fl<{iyR+DaxtN(b;^Tv) c2W7?#Q5UwKdX~4(6sU*6)78&qol`;+0FA~n^#A|> literal 0 HcmV?d00001 diff --git a/icons/layouts/fairhw.png b/icons/layouts/fairhw.png new file mode 100644 index 0000000000000000000000000000000000000000..65b4555b939d6a32bb8b0f92e58d7d0538e13ab2 GIT binary patch literal 179 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=-3?y@QpIZW?7>k44ofy`glX(f`um$*pxB}__ z|Nk$&IsYz5x+KUin8D%MjWiG^$=lt9p@UV{1IXbl@Q5sCVBi)8VMc~ob0mO*>?NMQ zuIx9tgau_-s~FOmfI^auN NJYD@<);T3K0RXIcEwKOq literal 0 HcmV?d00001 diff --git a/icons/layouts/fairv.png b/icons/layouts/fairv.png new file mode 100644 index 0000000000000000000000000000000000000000..e5aad70fd0dee93bf5987c968eaec04632271909 GIT binary patch literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0P3?wHke>@jRF%}28J29*~C-V}>VGHmHaorvf z0AwZ}6I=z7E(!7rW^j0RBMrn!@^*J&=wOxg0CG4BJR*x37`TN&n2}-D90{Nxdx@v7 zEBg&jE-?Y~T?g)E1BLWGT^vI+&L{uiXXTmE!_HH~!^6t+rg=JJ*>m>9a_fNv3TdP%DF{tDnm{r-UW|=^-*L literal 0 HcmV?d00001 diff --git a/icons/layouts/fairvw.png b/icons/layouts/fairvw.png new file mode 100644 index 0000000000000000000000000000000000000000..583b4d5bdc44ca1a53a47f6a76b9ac838a626841 GIT binary patch literal 180 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=-3?y@QpIZW?7>k44ofy`glX(f`um$*pxB}__ z|Nk$&IsYz5x+KUin8D%MjWiG^$=lt9p@UV{1IXbl@Q5sCVBi)8VMc~ob0mO*>?NMQ zuIx9tgoQ+Tm&d)vn!|{*$swq}RtpZ-lgPfKLZFPvMiv1F zG@`+l@rK8%|(~rp)>ulg6X0sQUMQ-X`S9%#{HpkGtcC7J;u8tnPqQ;K1|{&c*Hls>~j6` z>4iq`PCs-BGI_8sqrrX3!s)E7KZ%W&#v)(2-b=*N;o4M hJGp*tUnjrJ2TskWA0%rfHcEg3+0)g}Wt~$(696K5rDOmA literal 0 HcmV?d00001 diff --git a/icons/layouts/floatingw.png b/icons/layouts/floatingw.png new file mode 100644 index 0000000000000000000000000000000000000000..6e261a4135ec47da8f2c8214e385cdcd3121260d GIT binary patch literal 190 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$0wn*`OvwRKjKx9jP7LeL$-D$|n3BBRT^O#$ zn6PF7d7K3vk;M!Q+`=Ht$S`Y;1W=H@#M9T6{U(>NAit$aLzFmB$jQ^iF+}2W>nTUB zh5#Psi=8h%-T%KLucdI|ij3~aB@?bUD9k@|+;iUI2QHJP+}N|(quKv7h`M-oR(;>v fTm0qgdnIeR?P6k03tzqmn#SPi>gTe~DWM4fe@{CD literal 0 HcmV?d00001 diff --git a/icons/layouts/fullscreen.png b/icons/layouts/fullscreen.png new file mode 100644 index 0000000000000000000000000000000000000000..46716f58bd9ef9d1f4b29fbfabb3d2522bb5c777 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0P3?wHke>@jRF%}28J29*~C-V}>VGHmHah*QB z9?1M!cjX^Qx+KUin8D%MjWiG^$=lt9p@UV{1IXbl@Q5sCVBi)8VMc~ob0mO*>?NMQ zuIx8iID}*wH06u3fIpTc#qhuI*O`Sg$f|M@@m kI6g|#GAwXYedof&@Gf+rSGq>{ZJ=HTPgg&ebxsLQ01GuXdH?_b literal 0 HcmV?d00001 diff --git a/icons/layouts/fullscreenw.png b/icons/layouts/fullscreenw.png new file mode 100644 index 0000000000000000000000000000000000000000..bc09ae8d08660bbfb08acc270211d70df2e313f5 GIT binary patch literal 182 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=-3?y@QpIZW?7>k44ofy`glX(f`um$*pxB}__ z|Nk$&IsYz5x+KUin8D%MjWiG^$=lt9p@UV{1IXbl@Q5sCVBi)8VMc~ob0mO*>?NMQ zuIx9tgat({Th=Z(0~C_+ba4#fxSssuf8#<&hL&gC20jdnD-GCO{`_ZW*tVGS&n2rB QY(RAkp00i_>zopr0I3r(U;qFB literal 0 HcmV?d00001 diff --git a/icons/layouts/magnifier.png b/icons/layouts/magnifier.png new file mode 100644 index 0000000000000000000000000000000000000000..14765551c75feaa2fe8600ab10667900a10a9b94 GIT binary patch literal 209 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0P3?wHke>@jRF%}28J29*~C-V}>VGHmHah*QB z9?1M!cjX^Qx+KUin8D%MjWiG^$=lt9p@UV{1IXbl@Q5sCVBi)8VMc~ob0mO*>?NMQ zuIxA1ctxd|Qym|v0ENswT^vI+&L{uiXXTmE!_LEVhL?xuO>_T2zM}igZ+O@g7R+J% sVkgkx%skgoSNp@yqzSAR?_8J|1Z-DvKR)ew5oiR1r>mdKI;Vst0DW{g4FCWD literal 0 HcmV?d00001 diff --git a/icons/layouts/magnifierw.png b/icons/layouts/magnifierw.png new file mode 100644 index 0000000000000000000000000000000000000000..3dcc2f893114be3321924a9d9eccb0d9f73dfcb2 GIT binary patch literal 184 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=-3?y@QpIZW?7>k44ofy`glX(f`um$*pxB}__ z|Nk$&IsYz5x+KUin8D%MjWiG^$=lt9p@UV{1IXbl@Q5sCVBi)8VMc~ob0mO*>?NMQ zuIx9tgat(zZm-Zd0u++-ba4#fxSssuf8#<=hOTG+2|qqGCLUrDVAlKbpPAuV2hYmJ T52x+{RWf+G`njxgN@xNAKzKBW literal 0 HcmV?d00001 diff --git a/icons/layouts/max.png b/icons/layouts/max.png new file mode 100644 index 0000000000000000000000000000000000000000..4246d56c71bf5fa103d0c038194871be572b4309 GIT binary patch literal 313 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0L3?#3!&-4XSoB=)|u0R?HrcbYLZ8bj%WHFWm z`2{mLJiCzw;v{*yyD+73*Q5YB7d>4ZLo9lyPT44UM1hCJpHVf&eu{&_ul%RXDi>Zf z{V#v;@y(2_4(iFK;ti!cT`4|?0##TZY6!7EtPqM; zknuNC<2XK9fc=9epGW6f22Dw02d@s6JzWg$Nw1rfB|kS6E6XJ;oR>eplrd+i<$>D{ zOpoj;LS(2IoTr(2EM78o?@b|g z&K{Rl?S4s`2d8Fy|8TnE1jEUWuZmL)uR8wwo&JGQWO;~S{OPR6K+iFFy85}Sb4q9e E0Q-1zcmMzZ literal 0 HcmV?d00001 diff --git a/icons/layouts/maxw.png b/icons/layouts/maxw.png new file mode 100644 index 0000000000000000000000000000000000000000..0c769ee0ffb29d72f320267a9adba4504c913605 GIT binary patch literal 190 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=-3?y@QpIZW?7>k44ofy`glX(f`um$*pxB}__ z|Nk$&IsYz5x+KUin8D%MjWiG^$=lt9p@UV{1IXbl@Q5sCVBi)8VMc~ob0mO*>?NMQ zuIx9tgat)Kx0RmJ2MVcpx;Tb#Tu=V-zwu!M@@ryijJ=`YYyB?_OLhfI zp1k@)-m)b$#7E-fCc$U+NsAuaPusDCXTmHSLk5O=O(``^z9(0JRxo(F`njxgN@xNA DgkwTF literal 0 HcmV?d00001 diff --git a/icons/layouts/tile.png b/icons/layouts/tile.png new file mode 100644 index 0000000000000000000000000000000000000000..071a385f1d1c84b1efb108b0c547447f892032da GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0L3?#3!&-4XSJOMr-u0Z<#|NlU8`tEwu3HVF>yH3sBsY80av^ zRI9<6LHP&=w-4(hHa0e0E6xLN)EyHVV!DDG<~YdtE?>d)Vxn(NA_K$Q)sm-gi<^NQ Oz~JfX=d#Wzp$Pz0pD-%` literal 0 HcmV?d00001 diff --git a/icons/layouts/tilebottom.png b/icons/layouts/tilebottom.png new file mode 100644 index 0000000000000000000000000000000000000000..aeedbe23034788bf0502779da1764a7ebd518eea GIT binary patch literal 195 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0P3?wHke>@jRF%}28J29*~C-V}>VGHmHah*QB z9?1M!cjX^Qx+KUin8D%MjWiG^$=lt9p@UV{1IXbl@Q5sCVBi)8VMc~ob0mO*>?NMQ zuIx7$`MG#m=f7kU019b(x;TbtoKOD2&&o5Shnk44ofy`glX(f`um$*pxB}__ z|Nk$&IsYz5x+KUin8D%MjWiG^$=lt9p@UV{1IXbl@Q5sCVBi)8VMc~ob0mO*>?NMQ zuIx9tgayTgq|~kXfI{M)E{-7_*OPzzZ(Qig(AaRtk5RxWiGks!3s2$e<2=?tB@CXf KelF{r5}E)jzbp9w literal 0 HcmV?d00001 diff --git a/icons/layouts/tileleft.png b/icons/layouts/tileleft.png new file mode 100644 index 0000000000000000000000000000000000000000..ab55e087479efb9254f0efabc7720acc3a4eb123 GIT binary patch literal 172 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0L3?#3!&-4XSJOMr-u0Z<#|NlU8`tEwu3HVF>yH9Wk$(OgHkB@Q@b zhcNguhy|%|tVu{nU@AJq=D{Gh{RlVDmdhtOo?I;H(rPgF>D1?8*cqnwWxuBCLZDd; Mp00i_>zopr0Gs+QHvj+t literal 0 HcmV?d00001 diff --git a/icons/layouts/tileleftw.png b/icons/layouts/tileleftw.png new file mode 100644 index 0000000000000000000000000000000000000000..f8e10c7e2ae768fccff76ae6c0505954bb383f49 GIT binary patch literal 189 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$0wn*`OvwRKjKx9jP7LeL$-D$|n3BBRT^O#$ zn6PF7d7K3vk;M!Q+`=Ht$S`Y;1W=H@#M9T6{U(>Npp@{9zS65eAxBRa#}J9jQ!f~D z9WdZ=zPNnC@A#XtT#B4u19+oa_O}K-4HkCHmdKI;Vst0JW4gy#N3J literal 0 HcmV?d00001 diff --git a/icons/layouts/tiletop.png b/icons/layouts/tiletop.png new file mode 100644 index 0000000000000000000000000000000000000000..3febc350b624ef65bd088cea0cc23d204e5eebca GIT binary patch literal 195 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0P3?wHke>@jRF%}28J29*~C-V}>VGHmHaRt&q zurz(=c_77D666=m;PC858ivL>4nJa0`PlBg3pY5H=O z_8W}+T)gJtcEJ;XLYkf~jv*T7lYj8D^33RA=c(c0VdZ)AC4omMUEsMK+cP${4UZ-s dIv^{>P_SynnunQ7a)6o`JYD@<);T3K0RSpqFw+14 literal 0 HcmV?d00001 diff --git a/icons/layouts/tiletopw.png b/icons/layouts/tiletopw.png new file mode 100644 index 0000000000000000000000000000000000000000..3edfebaa7c3971b81acdd8eadb468e909f431a5c GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=-3?y@QpIZW?7>k44ofy`glX(f`um$*pxB}__ z|Nk$&IsYz5x+KUin8D%MjWiG^$=lt9p@UV{1IXbl@Q5sCVBi)8VMc~ob0mO*>?NMQ zuIx9tgaxIn-&)_*2MURMx;Tb#Tu=V-zcKL;i-1#_38%t^|NIQ{{(P+wr;o7%l`wd^ L`njxgN@xNAeK9S8 literal 0 HcmV?d00001 diff --git a/icons/layouts/tilew.png b/icons/layouts/tilew.png new file mode 100644 index 0000000000000000000000000000000000000000..3c602d154339292f2a208738eb9de134b40de93b GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$0wn*`OvwRKjKx9jP7LeL$-D$|n3BBRT^O#$ zn6PF7d7K3vk;M!Q+`=Ht$S`Y;1W=H@#M9T6{U(>NpoA#%?M+EQAs0^<#}J9jwG$k< z4mfZyr+5ATUsSbX>Fy2JoC6*uTxdxaP56G$Uw=kt8&jsx4UVhf*|D}V;x|5DwXzBO hm)}$9e)y%Txqg$7s{4a^e}LvOc)I$ztaD0e0szywI&J^} literal 0 HcmV?d00001 diff --git a/icons/mail.png b/icons/mail.png new file mode 100644 index 0000000000000000000000000000000000000000..f489e88a6113274c49da0f2f7ca6b4f983e066f8 GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}Y)RhkE)4%c zaKYZ?lYt_f1s;*b3=G`DAk4@xYmNj^kiEpy*OmPyBR40j@Y6ZR9|46zJzX3_G|nd{ zNEkH;&fJ`JRclYz;X{WW-PyL#bT1sGUUanh=)rF@sF616r7CAe5w%}b; zpBG&hOp`CSJao^QRrqr@>-6~?tRmbS8;x5S8IE`>OS;H!0a?J{>FVdQ&MBb@0Bwpz AUH||9 literal 0 HcmV?d00001 diff --git a/icons/mem.png b/icons/mem.png new file mode 100644 index 0000000000000000000000000000000000000000..b088d4a9b6d234b1c3e8f3c87b00d2a45ee70af2 GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}Y)RhkE)4%c zaKYZ?lYt_f1s;*b3=G`DAk4@xYmNj^kiEpy*OmPyBR40ramNaWH9#S6PZ!4!jq}L~ z5=IS@Ge6tw^fWG1dGepJ?4w)GmxI0R(urA;h9-{~dsc@Xys7hI67RfO{|jHmv~K9= qjIqBIuY9xdaEo?9!9`~Q28J!w3S1uRtquZ>W$<+Mb6Mw<&;$VRus<#U literal 0 HcmV?d00001 diff --git a/icons/music.png b/icons/music.png new file mode 100644 index 0000000000000000000000000000000000000000..4c2764d1099f4009c710b762915ba088572fc601 GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}Y)RhkE)4%c zaKYZ?lYt_f1s;*b3=G`DAk4@xYmNj^kiEpy*OmPyBcGUw=qt8DDWH≺B5V#`)v~ z38MzVnV;=-dK!UX;lbd~_GU+WJ9`Vh`aHRHqRD$v;_p(C>kD=_lGBGv^3Z-n6Xk?R81%ZSn4f0!Hnu z)8#iO^;E{wmAY(E-T^vI+&R-35 zNav2&T4AVHTb*eBdP(N?_zFnBX!>)XyOShV* zPR5RhKm4v7ShR8-Z~gU|oS|hr3{C3xj4wi8oc!8)TV3q)nfe#!_VseTpROYzKKrlh V;(UQ${XjbzJYD@<);T3K0RVSDPO1O^ literal 0 HcmV?d00001 diff --git a/icons/power.png b/icons/power.png new file mode 100644 index 0000000000000000000000000000000000000000..b8add29a1cef8567acba867f4c447a2b6e55f8a2 GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}Y)RhkE)4Yy z^BL;5n8Y&zMK}vQB8wRqxP?KOkzv*x37{Z*iKnkC`%QK(VOh}?EB)RAh2lJ2978nD zCnrc4H3-fOw%;!|^S6AgZ*r1y%p}h4#Q)OU;@gWCy!rp4YsQ9*q?`{|Tr$2~Ny)fT zH&-y$Sa@fhOhs=G@4Q+67d9T^;0|0N;l;DzLC2#1Cm37SWp*$!aG6O7zs@Ot4z!8E M)78&qol`;+0M6q^WB>pF literal 0 HcmV?d00001 diff --git a/icons/rss.png b/icons/rss.png new file mode 100644 index 0000000000000000000000000000000000000000..62d361e08b35527630ea372cac31da025f390fca GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}Y)RhkE)4%c zaKYZ?lYt_f1s;*b3=G`DAk4@xYmNj^kiEpy*OmPy8^3^%_OlflAalJvT^vI+&L<~G z7&Qpa47T6@&))86Z)b18SDhD=cyF&aPP%;M!OG4g4Q|7(4U)&4TEsV4&F5@C_J4NZYsSBZCINI$e|=Wb=`*UyZn2XZj1T9mi9W0lfL zn?j4@Pd1*{*nP{;FiCJ#SN)NmP~%Sqv-5R!SH+*a9e$SQ_SK39`qd0xlY)#BqBg7s P+Q#7N>gTe~DWM4fYSK#< literal 0 HcmV?d00001 diff --git a/icons/submenu.png b/icons/submenu.png new file mode 100644 index 0000000000000000000000000000000000000000..b2778e2ebe7f632abc51257e3609992bda592a83 GIT binary patch literal 440 zcmV;p0Z0CcP)P000>X1^@s6#OZ}&00004b3#c}2nYxW zd2z8Hj+`L9UQg2LG>t}MEh2;Ea(U|nQA(kdBAd<9YPAv(`2en+Ap7$9 zJe^KwE+TKhr4wXdu~;OEA~PC|UVw8a$i8y9{L}CE<2a6=fKw-kQVQSqsaC6BA~H^r z;!9XEzPZ!4!jq}L~ z5=ISzGe7_TU(W^vZTzu&k#Kyzopr08v0TEC2ui literal 0 HcmV?d00001 diff --git a/icons/taglist/squarefw.png b/icons/taglist/squarefw.png new file mode 100644 index 0000000000000000000000000000000000000000..2a864309ed683bfeea13b4b5127b17f20acc9496 GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^96+qV!3HGtKUiJ>QjEnx?oJHr&dIz4a@dl*-CY>| zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sf4K5~rW#b#FTbqDFk|nMYCC>S| zxv6<249-QVi6yBi3gww484B*6z5(HleBwYwVxBIJAr_~TfA}*P^a!vnP7vu~;$dKz X$MK&rzAi=usDi=M)z4*}Q$iB}5zjAs literal 0 HcmV?d00001 diff --git a/icons/taglist/squarefz.png b/icons/taglist/squarefz.png new file mode 100644 index 0000000000000000000000000000000000000000..6291037ffa9ea8e9d497fdab715740ab0093d3ec GIT binary patch literal 377 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c1!3HEbvi3>UvL&q;7`lBp*qZctt^$=ac)I$ztaD0e0sz=aDT4q2 literal 0 HcmV?d00001 diff --git a/icons/taglist/squarew.png b/icons/taglist/squarew.png new file mode 100644 index 0000000000000000000000000000000000000000..c750e54e7ec9b7436bff0642ae2baa0e93bad41c GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^96+qV!3HGtKUiJ>QjEnx?oJHr&dIz4a@dl*-CY>A zGu&qQkbcyC8&HI^z$3Dlfq`2Xgc%uT&5-~KvX^-Jy0YKo5*8BEj;ptk0}4r&xJHyX z=jZ08=9Mrw7o{eaq^2m8XO?6rxO@5rgg5eu0~P6dx;TbdoKF7p|NsAbHk*ddMuvn& xLkUSq$%(27YQiRsMXWs{zmr6IngSa*8Q3g&IJYh~(Ew^>@O1TaS?83{1OQ$(Hx&Q? literal 0 HcmV?d00001 diff --git a/icons/taglist/squarez.png b/icons/taglist/squarez.png new file mode 100644 index 0000000000000000000000000000000000000000..df652487bf1b6f4c2cbd5c3f5dd7ba28a7cfdb4b GIT binary patch literal 377 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c1!3HEbvi3>RZu2cXbTPZ!4!4q3)` y41)g|@7y`_A1Ho z*92^Mer#4?rRwc>IUX9fi*!GyTvy>Vwu-CSxnbQ4_sH9e1***6{uVjZJgtzqwEbP{ z1#zbxr3qo@=FB_OE^se(Ug(o6F_z`8Zp;pMKR4&aEHeW&Q`OMRMJux-udd=;DY*Yl k#Fiy5<3D>`d0N99QfGYPmE_VDKtC{ey85}Sb4q9e0NKlaX8-^I literal 0 HcmV?d00001 diff --git a/icons/tasklist/floatingw.png b/icons/tasklist/floatingw.png new file mode 100644 index 0000000000000000000000000000000000000000..eb802aeebfd3632131a4f00e3fa2e934d5306c54 GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~g!2%@3w~L7bDaPU;cPEB*=VV?2Ih+L^k;M!Q z+`=Ht$S`Y;1W=H@#M9T6{RTTHmmFv8?4?(MLXst}5hc#~xw)x%B@E6*sfi`2DGKG8 zB^e6tp1uL$jeH=JnUcKST^JZv^(q?yd22mg977}|OAi`qw=goWJ@_t>60~WSh}hwi zS^Mh`6inP?AhB+<=k`r^7wiyimQOU5I6w_xk2}(ah#ma(7lPOE}mUT5V=(TeUgS_w=T=nLS0%9K4nPZ(N%cW2?IV X(dwl}PXAwnyusk<>gTe~DWM4fUetK} literal 0 HcmV?d00001 diff --git a/icons/temp.png b/icons/temp.png new file mode 100644 index 0000000000000000000000000000000000000000..2e712e93839b986276603ad9f8e2686dc7cae96f GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}Y)RhkE)4%c zaKYZ?lYt_f1s;*b3=G`DAk4@xYmNj^kiEpy*OmPyBcGTl?}Ne{yg;D>PZ!4!jq_K7 z9Qhg)cwS#LQm!L4nqdxa eM9Q)FGR9|41#K?sNnt>{89ZJ6T-G@yGywpMuvGB? literal 0 HcmV?d00001 diff --git a/icons/theme.lua b/icons/theme.lua new file mode 100644 index 0000000..d4b103e --- /dev/null +++ b/icons/theme.lua @@ -0,0 +1,92 @@ +--------------------------- +-- Default awesome theme -- +--------------------------- + +theme = {} + +theme.font = "fixed 6" + +theme.bg_normal = "#222222" +theme.bg_focus = "#535d6c" +theme.bg_urgent = "#ff0000" +theme.bg_minimize = "#444444" + +theme.fg_normal = "#aaaaaa" +theme.fg_focus = "#ffffff" +theme.fg_urgent = "#ffffff" +theme.fg_minimize = "#ffffff" + +theme.border_width = "0" +theme.border_normal = "#00000000" +theme.border_focus = "#535d6c55" +theme.border_marked = "#91231c55" + +-- There are another variables sets +-- overriding the default one when +-- defined, the sets are: +-- [taglist|tasklist]_[bg|fg]_[focus|urgent] +-- titlebar_[bg|fg]_[normal|focus] +-- Example: +--taglist_bg_focus = #ff0000 + +-- Display the taglist squares +theme.taglist_squares_sel = "/usr/share/awesome/themes/default/taglist/squarefw.png" +theme.taglist_squares_unsel = "/usr/share/awesome/themes/default/taglist/squarefw.png" + +theme.tasklist_floating_icon = "/usr/share/awesome/themes/default/tasklist/floatingw.png" + +-- Variables set for theming menu +-- menu_[bg|fg]_[normal|focus] +-- menu_[border_color|border_width] +theme.menu_submenu_icon = "/usr/share/awesome/themes/default/submenu.png" +theme.menu_height = "12" +theme.menu_width = "100" + +-- You can add as many variables as +-- you wish and access them by using +-- beautiful.variable in your rc.lua +--bg_widget = #cc0000 + +-- Define the image to load +theme.titlebar_close_button_normal = "/usr/share/awesome/themes/default/titlebar/close_normal.png" +theme.titlebar_close_button_focus = "/usr/share/awesome/themes/default/titlebar/close_focus.png" + +theme.titlebar_ontop_button_normal_inactive = "/usr/share/awesome/themes/default/titlebar/ontop_normal_inactive.png" +theme.titlebar_ontop_button_focus_inactive = "/usr/share/awesome/themes/default/titlebar/ontop_focus_inactive.png" +theme.titlebar_ontop_button_normal_active = "/usr/share/awesome/themes/default/titlebar/ontop_normal_active.png" +theme.titlebar_ontop_button_focus_active = "/usr/share/awesome/themes/default/titlebar/ontop_focus_active.png" + +theme.titlebar_sticky_button_normal_inactive = "/usr/share/awesome/themes/default/titlebar/sticky_normal_inactive.png" +theme.titlebar_sticky_button_focus_inactive = "/usr/share/awesome/themes/default/titlebar/sticky_focus_inactive.png" +theme.titlebar_sticky_button_normal_active = "/usr/share/awesome/themes/default/titlebar/sticky_normal_active.png" +theme.titlebar_sticky_button_focus_active = "/usr/share/awesome/themes/default/titlebar/sticky_focus_active.png" + +theme.titlebar_floating_button_normal_inactive = "/usr/share/awesome/themes/default/titlebar/floating_normal_inactive.png" +theme.titlebar_floating_button_focus_inactive = "/usr/share/awesome/themes/default/titlebar/floating_focus_inactive.png" +theme.titlebar_floating_button_normal_active = "/usr/share/awesome/themes/default/titlebar/floating_normal_active.png" +theme.titlebar_floating_button_focus_active = "/usr/share/awesome/themes/default/titlebar/floating_focus_active.png" + +theme.titlebar_maximized_button_normal_inactive = "/usr/share/awesome/themes/default/titlebar/maximized_normal_inactive.png" +theme.titlebar_maximized_button_focus_inactive = "/usr/share/awesome/themes/default/titlebar/maximized_focus_inactive.png" +theme.titlebar_maximized_button_normal_active = "/usr/share/awesome/themes/default/titlebar/maximized_normal_active.png" +theme.titlebar_maximized_button_focus_active = "/usr/share/awesome/themes/default/titlebar/maximized_focus_active.png" + +-- You can use your own command to set your wallpaper +-- theme.wallpaper_cmd = { "awsetbg /usr/share/awesome/themes/default/background.png" } + +-- You can use your own layout icons like this: +theme.layout_fairh = "/usr/share/awesome/themes/default/layouts/fairhw.png" +theme.layout_fairv = "/usr/share/awesome/themes/default/layouts/fairvw.png" +theme.layout_floating = "/usr/share/awesome/themes/default/layouts/floatingw.png" +theme.layout_magnifier = "/usr/share/awesome/themes/default/layouts/magnifierw.png" +theme.layout_max = "/usr/share/awesome/themes/default/layouts/maxw.png" +theme.layout_fullscreen = "/usr/share/awesome/themes/default/layouts/fullscreenw.png" +theme.layout_tilebottom = "/usr/share/awesome/themes/default/layouts/tilebottomw.png" +theme.layout_tileleft = "/usr/share/awesome/themes/default/layouts/tileleftw.png" +theme.layout_tile = "/usr/share/awesome/themes/default/layouts/tilew.png" +theme.layout_tiletop = "/usr/share/awesome/themes/default/layouts/tiletopw.png" + +theme.awesome_icon = "/usr/share/awesome/themes/default/layouts/taglist/squarew.png" + +return theme +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/icons/time.png b/icons/time.png new file mode 100644 index 0000000000000000000000000000000000000000..929327eaf3a724f9f5acbce198a4a3b71c21db05 GIT binary patch literal 225 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}Y)RhkE)4%c zaKYZ?lYt_f1s;*b3=G`DAk4@xYmNj^kiEpy*OmPyBR7YnT+NIgQ=m|yr;B5V#`&ug zcJm%E;Beu8uAJ)Q-!$V$^s;Wx$xMO^zL(m){J4gB8Yk=Bqs{rz9@E(zaLrSVSRJ3Y*v{1S}*~AOunfA~uR$#KKgm zQl+x8(DP3cmMDrSh=>F?>U~BroV~U;8EJ0L@vbSw1Yjf3OOVfkWu}!y){gzJxEQ z#eB{u!$W9kq!T|cXRvfY{Kb7`_y#x%)rA>oaTaR-cz1FUa4l#u$Ueu$XDZ{suI0-FQ!V`dmLv%rpv(fj6W70W>-Ia=(}6VDJcc_*Uq&!6Fco^bIEGl9-g@=C zw@9MIfsgNbUhj76Yir)MMo%Y7M6`23h`^<@&U@mfbse(LKRH>UM?lu5;zYp4$%zU& zA&WfUsAiU@%_*P9x4HXw_4h~BHHmgMpZ`?Id%NtIc$sVdnFW5!3fcbtyKHdoxXG%k zTcQI6OGJV#W*w4cC{142uwZ-Jtis)*b8D*4pWQPr_}BveyYDJ^ulCFHt#GUlt=ygmFFV3pTl>Ec>!%jT@ z+s}Qme5%K~S*#Y?`~Uy=^-4=ac!y^92~(be7msF1%#A;(QC`PbBfm^&t zDT94W)(!EuoXk1*y*{XW_su$SC)4TtIqf(9JFFI!T3lW0pWWJYz+~YM!Imb5!v2RF ztz*r$g(UlZRQ|vlnY!^ogcr-+yiz%(-Qu?*{%-!vl`hU0!u!L?jOH((@GU zt?QQYN^ec%-#4r4fk27#Ulcm{=K^Ya19?85rb#IeibNAvZrIGp!OsgQ0GY`6#5dKYoA>zk-ApQ@;_ZcF76#y~Z ziy$@-H-OZ**FFAUzWhHNmn{DEUnuz-NS_0y!J(hlGlYHl544~FZ)AWR5ccJ~YTnoX zp%eeZv0=r}|3LBimi)Ic!7 zWE1?#fFbC`f3UBh;Vz%||G#Y`0s|uvE(f&aKT!R9f(C;P4}6vYGF-j*|9|s3+*mvl zXhFb}_dxXqL>UY=-2XuWL%^f|iuwQl>sMf6;WVJ3e)rx3)fr%95Q2vL-bw&!{x6yJ zAMAP<=1v3}>T}~gP~HG*&LhfjpBq5K?|@whay>YFeQtoT1I{c>s^Q?Y4>2?WZ&^X2 k;q!4B3YH%&=xJ^+0CnFED5!2~q5uE@07*qoM6N<$f?snX`2YX_ literal 0 HcmV?d00001 diff --git a/icons/titlebar/floating_focus_inactive.png b/icons/titlebar/floating_focus_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..fd8e622ce0a98a9dbd95920837f1315a4a72d4bf GIT binary patch literal 818 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fY)RhkE%y{W;-5-!(S%G6ZkOu2#xO4Pn1Oo$8w5N+>h{fr*SND5I2Z|i{_`Y`kJ8r$e z=?@fkv4~u`a`33CWQ!Qf<&Dw5#XbJF{NwDKd*<5KxvnKACO9hocjT3*f8tr=B5&AV ze*SHO^0H}H`1o4mb{yVYV0WkZ{LYxvwNF*sJ}bSl=UjdE>{<2MtxgL?SPpJ`|2s7y zFEzDw^=j=~Z_OMw-+%vp&fK|Ij~%@C_~?-%E^(S$UsuMJ*4ECwdNnjHEzOOoudmPR zYgO&`>#uX8v+t{U78!jzk|;54N)WrWwDixdTTPo3BxYyrjZ4qZ*B6`k^I(F&f3a`1 z`tBoqC_zrU0p+a`}0?>T=6JaeDT4LA3qFyFP{>w$j;VYKjjzS zlSbhL_8+rSZ*n#~uPi=Lolu>asJMT}jvoSZQYC-?{(a}(y|7I>)-^o4k0yQO4q&pA zO1{_W;p`$8Bs?*~g>P!meCxUAUR(5WM`ce^S$O|_a?irsZA7ol8QIspepLD0x1_w>ebzGm0=?4c6pNM=jUf+Yunp#;q}*~1)to1 zsNXX=wq@P=^{W#l9_@O^p`+vyc;x5LpSG`dolQT;(D&G6vrhKW!kDX3k1hC)N%R<& zSjpnAUG^t-P3hUobw#+d85X_41qcA29^*FwuWMFfEpM)UHx3vIVCg!0F4P?iU0rr literal 0 HcmV?d00001 diff --git a/icons/titlebar/floating_normal_active.png b/icons/titlebar/floating_normal_active.png new file mode 100644 index 0000000000000000000000000000000000000000..a7413150edea987f7ef7c30593a48564ad36de06 GIT binary patch literal 799 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fY)RhkE%y{W;-5-!(S%G6ZkOu2#xO4Pn1Oo$;ho_5Uh{fr*Q&0N~2a2@spP6|)C})jN z?;)qtYdNl%Nc8Nw;36ci!=Yo66Eoq%_L&mGkDU?|1!f&`pj^eM}8f1S_b?bN~be2qtTPy>tl3Rb7L zA60e*9zOF)l;N=P%pSkvU!0rM{g#HR+*;-Q`67F6amn4>Ct1l$bRHJ|7x9mmteLkj z^MPT&emP@)mUO2~-WP9n8LuhZa$iA$L*~Y-&Ekjm$n45}_|YZj*c#h|GapQ8TT)_X zzBjaX)7dvky3ewB80tf(UHhRvOX~H-bFQZ+wX?Zb+85S3=9qp7Z|GdV(&Ln}1FO%6 zT81>&f15Zbto$Xxr01wv`0r7VRKDjM73;FbCkcY;%fEEjoOZI@QTfzvk`U|DUX3k& z@2*#=8LVr%ENP>hEiQG)`rpy@me-zf?b3+x{ww$Xu=cgaPcb6-lE0n)p0t`{+EBhT zb!o1hK-l5s+wY6S3*31hb!`5c+vQr{+V)-hFsJ>8Nx(L3-YX|sw%(nw)a1dg+v3%X zclLZe&MNrLmU)hdYV)hjMuLjPMm(zN*OdZ0I3(*m*wXJZEq@;{Tir|6YTe9Rvt}n0 z%jT@U6gK@poZRLQUA2p@B+67RZN0tr@vN1HrW+PX2W%?OO=g|*rh_$Xe!*^Di$!4^ z>)nr^UjAljAeWkj>Wx!P+pU-k6!y%U%V@EQgR`pCM*C@v^wJ4;S&CT{RA1=Me!M?u z`}~5re}3p^v?_T1ub+_2{+~hp_|LwM2a3MH1g2Wz8c~v5l$uzQs+$5N7>o=IEOkN1 zJjBS@%EZLV$XwgNz{tc)$K3@jlUYz@WU05vdpy85}S Ib4q9e0C@{W=>Px# literal 0 HcmV?d00001 diff --git a/icons/titlebar/floating_normal_inactive.png b/icons/titlebar/floating_normal_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..3f8f456196f8e5be08316bbe7ddcaa43d8fbd771 GIT binary patch literal 814 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fY)RhkE%y{W;-5-!(S%G6ZkOu2#xO4Pn1Oo$8xTlL_h{fr*SND6%IEozj`2Nnn9mYGl zcb%$apZIvfWjF1IQHo7dLwEgYd>M3t^Pq!Df}l>2>XHB!>E1UxPoH}8cFpT|eqApf z9(`iM*zLf!Y)0a}c5~x?$%R{=X+}NuyizYD_O|Tzy(fj{-ZmiAA&o3@0n2@; ztiYkt@Vt`m0%O>$v&;7G+GWMFZ{NPO`uh1gr^}iYEOv8C_qsi1eZVMx*q~E!GjrCFLZ3-0BCd`y$2FGvx#_LfIlWBak*|pB!T0Ab zm)=dA_ncw=A%mFpSF^Ug-eu2ld5H$s`O>@3nxB3Xeg*VH)U?(_2?mS4!&k0cDLDJ` zrDkd*(}YyX)X21BU%q^a`0?tMSLo`{$Z4tBd3k*^XG*TRsulG*asHe+M+#-S79|)+ zq&RilYyRLX)|eV;)c1H=?rjc5jnhR-+yh+%SR^lWKenh4sR?FmOq2l0rbdQnO;xO_ ztn`#JOsq@|v<(cb3=9@c`{N1Ikei>9nN~?a!(a8TTA&67 MPgg&ebxsLQ08AlZ`Tzg` literal 0 HcmV?d00001 diff --git a/icons/titlebar/maximized_focus_active.png b/icons/titlebar/maximized_focus_active.png new file mode 100644 index 0000000000000000000000000000000000000000..78a291453222dd16bf5358a1c3b607cbcf848df5 GIT binary patch literal 1013 zcmV_YnDIDh0x1W|)H}iJ{J*W}9s;s3yy z=aCWy28QYB>BnZf#ZW_)I{9JRSB7y(L_aC?tU|w1sP(O62J6e|tFPc@!&%Jc-??o( z$_?EU7(}e+)pz$qDn+y^`mw1}s9Bw~uWx|v?ps(aU09pyXl?zOj;%?2p-ON@B<`N* z36Zk8s33kwj^~eeR%6dvgDr18HjN*H?=E5}CxM||s}N|}OoW{)@8a39u;l^V zT7Q~Dgv$%2(f?*Bz3XSOTcLZrp?T`1ig9dmMQBQlfcK-hlMzA9oM~Ko*oR@Q5AKW* z%=sJ0o$Od;i4;|@Q0UGlacz&~WVk<{M+f3cyC2eLsk&!kK9s|b$-q}PN$}peVyt?6 z9?slV9GE+U<1xXwGNWLdDpj#&w4s)QG_ocNn>L8PofzDbDn-`9g^ctXao)JX{>Ne|jC_ci#3;Jojwdg`7mGIP z-)U(}Su{S}_=>D*+a3r#M_{mq?#APMxkU@k>y#}P@`I*36mr_K@liD`%W!7KkRRaV z*^BdjTdk9#p2`K#yBGRTj^a35a9u6nyLEC}0g;~5SvD`nxg%cHJ#c)~v+7p^rv#dD(b_fYZhg%cI#svrX)2lUOA5d3n}cz! zn8u8t-qTF=)J|v;F1#rE?o%PSn`hEnDO@iW8s88uCQF%0@EBM-Vbrq>FNouuMocP3 jm7*Gr=u{%7`h)!&401`p9ZAH400000NkvXXu0mjfjHK)| literal 0 HcmV?d00001 diff --git a/icons/titlebar/maximized_focus_inactive.png b/icons/titlebar/maximized_focus_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..3f2c8917ef8fc3a7bd78c1899ae8bb77b985fc5d GIT binary patch literal 1277 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmUzPnffIy#(^vlDyqr z82*Fcg1yTp14TFsJR*yMvQ&rUPlPc?@@szKmdCVE*Xo;uvCadhMn2 z{=tzV2R^>fj?dH$TAdIvBS4Aiqx&U01ue!&V!ja?T-w`q6gWGzU0fkx_J_TP+brjn zM6aP#LdwBSDlHo(Ofc8WIOA=_Blt6M!gqmN-*0`-OIL2Y$XI`7&Xc@zmOt+l7xy3e zFA%;i=H=%KoBbl<;^DjQ=J6bM_@|#>BE{=9$wZE;bTTc znVejTlcwv%c9oQt2FAqn9DjUplaA5MGv^Qb`uZMpS~y`(+1scmudc5CQDgV%rwzmD z)2DOt^IzNZ#P6%I)M)Ye_WiqiRCM&or$tXbSDKlb-MD)|^%(vWC7_~?;Rr;F2e9qnx!HY{L@uaC2k>AQaAO3D2lh0P8M4fo%x z3vevRlzRH~>5OHasgW|)Wju!sA|fIloSdv)r8m8M<*HThEZ_Zo(aJ6U==u5i@AI;= znHL0TFih}U9vK;_IQ_Jtxq18b*Qx>>AKu-ymb0x|5FJh5PdHLjQ*-k2jO^^z0X0U)#Dwgx*~t?S z9W7lbv%ILTuC5A**Nf%m=Bmo@1#5`Rm^bg(`|pc2xa9iVFI@@(M$cjM{ChR6b#3;d z$<-%cy?T}C8n~#pxA)DPHwKoLo}QkZXV0G9aW_wCBFF66vpE#`VtlVp?`&*r1o=>T zl1k!jGynN^PhVVIyk+awhu?p5wmLDqdG}6k*XREY@-`J0o`0?SFC!(@)#jww*4}Pe z_s3%H+__JREK?$n70MXR*uLF-g$CEkkS?IxPMtn&$kSY5 zbMDnEt!0^$PNqaeM*cLbd46v0i%wznUshID6H;eBeVQsIB{gH#tVeHeZ&wlGylZln zbNcDl#}<3)|IeGQAOGsWk%b!s9zDCcIh}Ds?rh`qa|Peu#a?=8vUTfL;hQ;OjQ@a! z)YzThoPNIKvPtr+Wh>hc^*wf3wQALd+~1!!>U5_VbqYKx_q{yrn_lgoABNf4+1vS? z8K2CXH*dlH_x-(?WrqaPn`=U;L;ljpDp!~S=#V}G@%?Q3Q7*q(p?-XxVw&I^p9Ke%T|$jZk4 zl6$b=hxGoF*S}oKYtjam1ga&j5hck*sfi`2x+y?{!N|bCQWu2GLyU~AOiZkd%(V>+ ztPBitzns1Y(~z5=l9^VCp~29=%GlD%z!IXt)==yXP=h4MhT#0PlJdl&R0hYC{G?O` d&)mfH)S%SFl*+=BsWw1G44$rjF6*2UngFe+NM`^5 literal 0 HcmV?d00001 diff --git a/icons/titlebar/maximized_normal_active.png b/icons/titlebar/maximized_normal_active.png new file mode 100644 index 0000000000000000000000000000000000000000..e907412177aeb70e08d284ac8afbf7b19425453a GIT binary patch literal 1208 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 YN=;0uEIgTN160J|>FVdQ&MBb@0NSF*zW@LL literal 0 HcmV?d00001 diff --git a/icons/titlebar/ontop_normal_active.png b/icons/titlebar/ontop_normal_active.png new file mode 100644 index 0000000000000000000000000000000000000000..dfccec3a06f0af9a8fb77cfbebb60787aca7e5a1 GIT binary patch literal 965 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmT$6^TbY*8=%$N#5=* z4F5rJ!QSPQfg+p*9+AaB+5?Q;PG;MI1j`B>(}6VDJcc_*Uq&!6FzxhoaSX9Iy>`l3 z?~p)=WA)c(U*EXLs>HZJW98W!?ZU2twH{olVUN^!jAO2-MSY9^BERKq=;}KfF0&0p z)+}h6)nc@2rqprG=gTaEjqeqox71xXb@E}81^jc)R^ESp{P1r%zL1r7EO*`6ToQUa zKG^qi692Rim!(+JFe^qSK-5r)9|B9~{=(cR@u(584 zJ(+oz2!2Ly#|=8HW{&bN$8H^1|VVQ>@BbB4y@o{zi#EuOyOgJt6P*JYuf0)Iytb%z7zspu8XIs3`Jsx4)^-|fzX)8GJawT*OdES!_o7-Y(mYyw(mi`y<)a}ML z&SHxtfhk(G#5JNMxhOTUBvm&BNH7=~7+C6pka>uav6YF5m65r&fq|8QLGG8+_h1@w z^HVa@Dls$|8dw=yS{YbEG}s!7y#Z>F1lbUrpH@wT5r literal 0 HcmV?d00001 diff --git a/icons/titlebar/ontop_normal_inactive.png b/icons/titlebar/ontop_normal_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..ee37d8421b87eedf4345c7f676e14a64467dcca8 GIT binary patch literal 1073 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmT$6^TbY*8=%$N#5=* zKpF^sI`6IrQk(@Ik;OpT1B~5HX4`=T%L*LRfi&1WhC4@JMldiit9rUPhFF|lJLSB$ zvZu)L{kg}zq&U}|Tj&EpX0O zMP?_K(ht|Ad;&Ztlz8}*?pDvYtM8Re|;s*RFjDw4IKqlRZ^@U z{@xW`9<);Mu)&{csft3K2Ml=rKYH}&#O{M$EBiM_@C11Y2tN8~(edK(?gOV!pRS9& z-Y(qflCC?`$Ladlhd+N-{+}(k{Bq|0pi}-XXG-rX2s&~kaw-0q=<&p}Y29lHS=plx zA3l6vTwL5Iu*k_}LQq&|hqvZjAGOCBFH3$IGq5l*3JA8fwLSP+bx^_?=u8V4HbL9Q z>{)G_Hyg{y%O5V3x$?SnikGT~ruAla2fyoIXTE%yIb#{8A`3%F!rQXl*{i3e9^ACX zPrTQS+1lEAMTpjeInPZPBI4uwcdfG)?mup5X7=scP8&`or^Oc?%x1glO>Yj;ntuLy zea3&zYuBzVa_V?lVRO!DVZiwdReSrK7B=kNYwPE7|I^Pu{0tZ5xPw=QOz8O6aWv_S z$=UFQ>s~LqnX@QD=g_uXKbQF8oiSUBPxK$%mb+a|UEO||?c1jqose)|eYNT;-(drVr95S~s|DYDthkV4#`vfDX$ObheE!-zeCce!AOmm9w+`D(k+@o6J8c~v5l$uzQs+$5N7>o=IEOkN1JjBS@%EZLV)Ii(7z{CF zFb%o+DVb@N1T_3r@2UlAkObKfoS#-wo>-L1;Fyx1l&avFo0y&&l$w}QS$Hzl2B?U^ M)78&qol`;+0BldnQ~&?~ literal 0 HcmV?d00001 diff --git a/icons/titlebar/sticky_focus_active.png b/icons/titlebar/sticky_focus_active.png new file mode 100644 index 0000000000000000000000000000000000000000..1106399d777ad671051f94a7f15f0e1addfacb78 GIT binary patch literal 833 zcmV-H1HSx;P)f@kD}&@elCK z!KfEO!9>j-jI!Bv$U<28F;v)`0CQ>uJ@_$d*AA(M1^mW)? zd1K{LGiuak_oZ2Czx(am4@RGi2hYpZl*C(yj-5Mq;`}>SECz#}SvW2LD|3NE73nNb zu~>{0U^M|ZqDE6XnE`ix*Fh6DO6R5*=;7*|7VYp$uRC zaq<4faD8V&QJ@3@z(Zv#_(H$kJ@L`Ihu>SY-ePlu^%mz{QNAU!>7LtQFkIWY#(KQo zk!9&f2%QbC{7(b)9fEzLVHTsh)!^^CV*N{*Os7zWgabp6ffD7nxHuhPbJq3Bo zt{Zb>G+^W52EX6^m3#Icq6HNyCZe7|C&2x1Jm_C;U43-192%bo@O2d)&#E3`OqS8o5v3&R!gXQ-SWSX84@oMx9(-utsCe9@k#p1_e{DLDQt zc;!}Q)q7c!z(b&rV0vDl9;nY$+1PBKZCwZss*k5*G>AA*JwUBi=h4m4H`h-OKAh{% z3vxAmZbmJ-afiitiF(*zGuoVgx={?Udf1?!^ywviI<*e1sKtYDyHYBOmxy-Urd#XM zOZvQ0f0gCtYs6u#GQVP=5jJT>Ef%VabZZ^@^+WWM9?EWhVek;S00000 LNkvXXu0mjfSX_`J literal 0 HcmV?d00001 diff --git a/icons/titlebar/sticky_focus_inactive.png b/icons/titlebar/sticky_focus_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..d7487b9896cf62ea7d52de58f9dea40aa6122825 GIT binary patch literal 836 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fY)RhkE)4%caKYZ?lYt_f1s;*b zK-vS0-A-oPfdtD69Mgd`SUzt&!c%7ux=As#WT#IZKPx)4mzCY6&GW`KZ>ZY3!3<&+W#? z7(7wkHuBot-*>Lx|6U^|m>6y%)hm8A>+AH_yW-03A3ofivo&h#>eZ{?t&8fLvm!+6 z{_C&5q}Q7E7|yO_eDKyW;h4nqphFVPzB^v;+PQUS_b~~tgPF_NpG5w!PsnL9_B_ux zIf%>Jrf%LN70-DQjxN<}H=H|n&Tj6!d39n=5v!Gylrq+K8mgUox@kY}ogB0O-+ur7 zDU}krL5JI=%l6l&lOLoWVh;@H`o@RSj)P?2V%M!7(X~L~ejOFF! z9gig*f2^opUYy{6;Fv^dZSCIj&--?sm0L3<$i{P0vC=QL11X|wpM6>S{`dOr2h}H^ z%vbs~S$1pa-n}t;`y(ow<5pkQJ7n-@#y;a?1tldc=RXS^|9JlN>C@k>XKz2h+QjC( zvjEG7TKT@m33l`4>vk_qI9@2=D%f>Y>5zes=;r2wnJkVC20Ygb?tfQosgS!-8e1{1 z-DzQi0tZmlB8?^irSJMDV^x&STDA)?^*vrwt0&eyA?Vq;_;pE|Pp>~L_~GRx>9ago z?zkcU;R)WFp}X(eonQTzo$=j;eW8Et%z+6^wZt`|B)KRxu_RSD1xPR$85mgVf{=NL zk+GGDiItJLwt<0_fkEz<)AwK+a`RI%(<(7E7#dg^TUr@dLNwSKioF49kObKfoS#-w oo>-L101Q*T%)IR4PlAb7#(tJikVE zPDGcWfOSlV$RuwSz9;86IiHw2?qPhyS;WrCXIbd9^FS-d5|<8UmwlFT>IWUWu6e$> z`}6YE%a>)gUC&XFQ`!CMf|T#|>-$%|(|S7Ru}bj#)lWYCo-NNi$t32E`qC}d_O^cx z)?M}U>*9U6!CY_d?+3H{_s6b|J$q;Ccm1c`vk%M-ZmeDGJ>-Os%LL27BgnWuD%6$|40T{dgk8&~jkZT3a`g#B7) z-|pW2dhvcWwg!fPx?D%wXO25|{yVpOe%#Gh*{d%ubBpfX_~`QWkkZZtf~s=5ckFkZ zzj#Td@cqOI41yCFYS|4x%)P}?*r?^(7~z|0ax80$XwTISN{$_4HzxQvo&FntK zS)C<~=WP$1F1z4#L*g-)ra{<>+};SsHI8d4o|@i%oLg7_i(Ox>-8l5(o(acS9DQ}} zz^+T{jGk`v%58O8_NJ#?qW8Omtz=;LG1oJfctp6`gV!&JYuzsJ&+?Y}_ILM`{EPce zDIYt3Tx9a6{o8rC4fvm%7Cb#Dap&GW<$u>_)oVvL{AQjy>uNHCE+*tBc*sEq;w`8;e7nh@q*}WTkSs#+>a;NoQ^mdZZUoB1a(W-n3BG; z=YpS4TgG`f=R{WByzbMlbJpYu9Q}CnK%&ef70$|8#ftH%wNHJ`!u5sQFG?QZyUxw@ zNJHuEa-PYG**B%~_2Unj-DTdn` z@E7-whPPKuTxpjBOyjC0t`Q~4MX8A;sk$jZg2BkZz)}~4%tMTftxQa;jLfwS46F(}6TtKf|4)FC!Qjm~uQ_978NlFP(DQJK9m==y{uW*#`UuY@#tD zn>NlCTN1D#cGchNKgaJ}b=|$WG??2dT+8LLQlR0-wiVwE*X!NlG&EDb$}B&;xVrs&_udWha@1s9 z`*p{ZAbG}`I~4kC#NKDSl{}ex9sTyea731 zG~~Wqmtamlb6O~S?Zc`!L4Jp7m7=4g^Uci7?;k7lnG&?2o@K46MDmuaS*(|J4UQ$0 zmz(e3w{IGQ1Bc}FtzyjwABe|CMrN*EzurB_Yf37o=F?`)6Pt48T*xh`s^W6;*t27Y zMDe+U63zlF59Tx%_Z>cbIQ&kOch{l@X6>a4OKVKFACp*;*|m7F@{&xhV-hj9PO39R zWFMRwWOmvpW9{(=FRkqD-FM$TR$$TMZNWQxp4z#rAHmIR2f zN+c)roNe(v6~%q;WyzCs=lEI#cI@8my#N03w{PE0em3*+hwltKuictAcdl*bhu-TY z^OsJUHa+!cu8GuM=7i<^3=Ug^R+{`{mFHorO+GUr$V$$1`}x0r|MEZj-F)rZHM=WW zTd(K&YPyQJdQ4)OK7IPzy?ghr-@M2Fo~U1zopr01<6-$^ZZW literal 0 HcmV?d00001 diff --git a/icons/up.png b/icons/up.png new file mode 100644 index 0000000000000000000000000000000000000000..94d4898c01776143d7071689dfa5a088d2302e00 GIT binary patch literal 277 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}Y)RhkE)4%c zaKYZ?lYt_f1s;*b3=G`DAk4@xYmNj^kiEpy*OmPyBR40j{;AKqQ-MNLJzX3_G|pcQ zI>>v-fX7C?k^RwCPKjRM9JS1_gyu5lGDnXN1=;yq7O9E8|5dr|{W*2!+d7jJG*u>l z^Ljf~rC&7q4BK{X2CLIyY6mvmWh}|ysneFzxxM)5v2$WBDbsqp-*K+rYTR~v!Q;|B zYc!W-t+&|9q0n`rN8SC;w-jOZhEMu)YLf$P5`SmdKI;Vst0JoE3xc~qF literal 0 HcmV?d00001 diff --git a/icons/vol.png b/icons/vol.png new file mode 100644 index 0000000000000000000000000000000000000000..09714c8e89bdacc191ee4496960b7f0e2c7b2b89 GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}Y)RhkE)4%c zaKYZ?lYt_f1s;*b3=G`DAk4@xYmNj^kiEpy*OmPyBR3}-i*J(PGoVn4r;B5V#`&uO z2L%r(aB#;=PZSX^kb73h=$0t+YxB1Dt=H%8nWQYhvBCGE$D(U}TRm3%Ts#hQ6r`3|HoC@mLTm{^`~9n@0bn&)xbc7+|&H*%Z#rEkC@yuP1 SRcCR?o)9*4Fm+x@2O`9;uI+2Ubm# x;B~Q_n$ZhVsKm~8(o86s;a`C2LDpuVP3rmD0+ZLN>;hWA;OXk;vd$@?2>{97K8gSU literal 0 HcmV?d00001 diff --git a/json.lua b/json.lua new file mode 100644 index 0000000..841b0cb --- /dev/null +++ b/json.lua @@ -0,0 +1,515 @@ +--[[ + + JSON Encoder and Parser for Lua 5.1 + + Copyright © 2007 Shaun Brown (http://www.chipmunkav.com). + All Rights Reserved. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + If you find this software useful please give www.chipmunkav.com a mention. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Usage: + + -- Lua script: + local t = { + ["name1"] = "value1", + ["name2"] = {1, false, true, 23.54, "a \021 string"}, + name3 = Json.Null() + } + + local json = Json.Encode (t) + print (json) + --> {"name1":"value1","name3":null,"name2":[1,false,true,23.54,"a \u0015 string"]} + + local t = Json.Decode(json) + print(t.name2[4]) + --> 23.54 + + Notes: + 1) Encodable Lua types: string, number, boolean, table, nil + 2) Use Json.Null() to insert a null value into a Json object + 3) All control chars are encoded to \uXXXX format eg "\021" encodes to "\u0015" + 4) All Json \uXXXX chars are decoded to chars (0-255 byte range only) + 5) Json single line // and /* */ block comments are discarded during decoding + 6) Numerically indexed Lua arrays are encoded to Json Lists eg [1,2,3] + 7) Lua dictionary tables are converted to Json objects eg {"one":1,"two":2} + 8) Json nulls are decoded to Lua nil and treated by Lua in the normal way + +--]] + +local string = string +local math = math +local table = table +local error = error +local tonumber = tonumber +local tostring = tostring +local type = type +local setmetatable = setmetatable +local pairs = pairs +local ipairs = ipairs +local assert = assert +local Chipmunk = Chipmunk + +module("Json") + +local StringBuilder = { + buffer = {} +} + +function StringBuilder:New() + local o = {} + setmetatable(o, self) + self.__index = self + o.buffer = {} + return o +end + +function StringBuilder:Append(s) + self.buffer[#self.buffer+1] = s +end + +function StringBuilder:ToString() + return table.concat(self.buffer) +end + +local JsonWriter = { + backslashes = { + ['\b'] = "\\b", + ['\t'] = "\\t", + ['\n'] = "\\n", + ['\f'] = "\\f", + ['\r'] = "\\r", + ['"'] = "\\\"", + ['\\'] = "\\\\", + ['/'] = "\\/" + } +} + +function JsonWriter:New() + local o = {} + o.writer = StringBuilder:New() + setmetatable(o, self) + self.__index = self + return o +end + +function JsonWriter:Append(s) + self.writer:Append(s) +end + +function JsonWriter:ToString() + return self.writer:ToString() +end + +function JsonWriter:Write(o) + local t = type(o) + if t == "nil" then + self:WriteNil() + elseif t == "boolean" then + self:WriteString(o) + elseif t == "number" then + self:WriteString(o) + elseif t == "string" then + self:ParseString(o) + elseif t == "table" then + self:WriteTable(o) + elseif t == "function" then + self:WriteFunction(o) + elseif t == "thread" then + self:WriteError(o) + elseif t == "userdata" then + self:WriteError(o) + end +end + +function JsonWriter:WriteNil() + self:Append("null") +end + +function JsonWriter:WriteString(o) + self:Append(tostring(o)) +end + +function JsonWriter:ParseString(s) + self:Append('"') + self:Append(string.gsub(s, "[%z%c\\\"/]", function(n) + local c = self.backslashes[n] + if c then return c end + return string.format("\\u%.4X", string.byte(n)) + end)) + self:Append('"') +end + +function JsonWriter:IsArray(t) + local count = 0 + local isindex = function(k) + if type(k) == "number" and k > 0 then + if math.floor(k) == k then + return true + end + end + return false + end + for k,v in pairs(t) do + if not isindex(k) then + return false, '{', '}' + else + count = math.max(count, k) + end + end + return true, '[', ']', count +end + +function JsonWriter:WriteTable(t) + local ba, st, et, n = self:IsArray(t) + self:Append(st) + if ba then + for i = 1, n do + self:Write(t[i]) + if i < n then + self:Append(',') + end + end + else + local first = true; + for k, v in pairs(t) do + if not first then + self:Append(',') + end + first = false; + self:ParseString(k) + self:Append(':') + self:Write(v) + end + end + self:Append(et) +end + +function JsonWriter:WriteError(o) + error(string.format( + "Encoding of %s unsupported", + tostring(o))) +end + +function JsonWriter:WriteFunction(o) + if o == Null then + self:WriteNil() + else + self:WriteError(o) + end +end + +local StringReader = { + s = "", + i = 0 +} + +function StringReader:New(s) + local o = {} + setmetatable(o, self) + self.__index = self + o.s = s or o.s + return o +end + +function StringReader:Peek() + local i = self.i + 1 + if i <= #self.s then + return string.sub(self.s, i, i) + end + return nil +end + +function StringReader:Next() + self.i = self.i+1 + if self.i <= #self.s then + return string.sub(self.s, self.i, self.i) + end + return nil +end + +function StringReader:All() + return self.s +end + +local JsonReader = { + escapes = { + ['t'] = '\t', + ['n'] = '\n', + ['f'] = '\f', + ['r'] = '\r', + ['b'] = '\b', + } +} + +function JsonReader:New(s) + local o = {} + o.reader = StringReader:New(s) + setmetatable(o, self) + self.__index = self + return o; +end + +function JsonReader:Read() + self:SkipWhiteSpace() + local peek = self:Peek() + if peek == nil then + error(string.format( + "Nil string: '%s'", + self:All())) + elseif peek == '{' then + return self:ReadObject() + elseif peek == '[' then + return self:ReadArray() + elseif peek == '"' then + return self:ReadString() + elseif string.find(peek, "[%+%-%d]") then + return self:ReadNumber() + elseif peek == 't' then + return self:ReadTrue() + elseif peek == 'f' then + return self:ReadFalse() + elseif peek == 'n' then + return self:ReadNull() + elseif peek == '/' then + self:ReadComment() + return self:Read() + else + error(string.format( + "Invalid input: '%s'", + self:All())) + end +end + +function JsonReader:ReadTrue() + self:TestReservedWord{'t','r','u','e'} + return true +end + +function JsonReader:ReadFalse() + self:TestReservedWord{'f','a','l','s','e'} + return false +end + +function JsonReader:ReadNull() + self:TestReservedWord{'n','u','l','l'} + return nil +end + +function JsonReader:TestReservedWord(t) + for i, v in ipairs(t) do + if self:Next() ~= v then + error(string.format( + "Error reading '%s': %s", + table.concat(t), + self:All())) + end + end +end + +function JsonReader:ReadNumber() + local result = self:Next() + local peek = self:Peek() + while peek ~= nil and string.find( + peek, + "[%+%-%d%.eE]") do + result = result .. self:Next() + peek = self:Peek() + end + result = tonumber(result) + if result == nil then + error(string.format( + "Invalid number: '%s'", + result)) + else + return result + end +end + +function JsonReader:ReadString() + local result = "" + assert(self:Next() == '"') + while self:Peek() ~= '"' do + local ch = self:Next() + if ch == '\\' then + ch = self:Next() + if self.escapes[ch] then + ch = self.escapes[ch] + end + end + result = result .. ch + end + assert(self:Next() == '"') + local fromunicode = function(m) + return string.char(tonumber(m, 16)) + end + return string.gsub( + result, + "u%x%x(%x%x)", + fromunicode) +end + +function JsonReader:ReadComment() + assert(self:Next() == '/') + local second = self:Next() + if second == '/' then + self:ReadSingleLineComment() + elseif second == '*' then + self:ReadBlockComment() + else + error(string.format( + "Invalid comment: %s", + self:All())) + end +end + +function JsonReader:ReadBlockComment() + local done = false + while not done do + local ch = self:Next() + if ch == '*' and self:Peek() == '/' then + done = true + end + if not done and + ch == '/' and + self:Peek() == "*" then + error(string.format( + "Invalid comment: %s, '/*' illegal.", + self:All())) + end + end + self:Next() +end + +function JsonReader:ReadSingleLineComment() + local ch = self:Next() + while ch ~= '\r' and ch ~= '\n' do + ch = self:Next() + end +end + +function JsonReader:ReadArray() + local result = {} + assert(self:Next() == '[') + local done = false + if self:Peek() == ']' then + done = true; + end + while not done do + local item = self:Read() + result[#result+1] = item + self:SkipWhiteSpace() + if self:Peek() == ']' then + done = true + end + if not done then + local ch = self:Next() + if ch ~= ',' then + error(string.format( + "Invalid array: '%s' due to: '%s'", + self:All(), ch)) + end + end + end + assert(']' == self:Next()) + return result +end + +function JsonReader:ReadObject() + local result = {} + assert(self:Next() == '{') + local done = false + if self:Peek() == '}' then + done = true + end + while not done do + local key = self:Read() + if type(key) ~= "string" then + error(string.format( + "Invalid non-string object key: %s", + key)) + end + self:SkipWhiteSpace() + local ch = self:Next() + if ch ~= ':' then + error(string.format( + "Invalid object: '%s' due to: '%s'", + self:All(), + ch)) + end + self:SkipWhiteSpace() + local val = self:Read() + result[key] = val + self:SkipWhiteSpace() + if self:Peek() == '}' then + done = true + end + if not done then + ch = self:Next() + if ch ~= ',' then + error(string.format( + "Invalid array: '%s' near: '%s'", + self:All(), + ch)) + end + end + end + assert(self:Next() == "}") + return result +end + +function JsonReader:SkipWhiteSpace() + local p = self:Peek() + while p ~= nil and string.find(p, "[%s/]") do + if p == '/' then + self:ReadComment() + else + self:Next() + end + p = self:Peek() + end +end + +function JsonReader:Peek() + return self.reader:Peek() +end + +function JsonReader:Next() + return self.reader:Next() +end + +function JsonReader:All() + return self.reader:All() +end + +function Encode(o) + local writer = JsonWriter:New() + writer:Write(o) + return writer:ToString() +end + +function Decode(s) + local reader = JsonReader:New(s) + return reader:Read() +end + +function Null() + return Null +end + diff --git a/lib/mpd.lua b/lib/mpd.lua new file mode 100644 index 0000000..df52ec5 --- /dev/null +++ b/lib/mpd.lua @@ -0,0 +1,150 @@ +-- Small interface to MusicPD +-- use luasocket, with a persistant connection to the MPD server. +-- +-- Author: Alexandre "kAworu" Perrin +-- +-- based on a netcat version from Steve Jothen +-- (see http://github.com/otkrove/ion3-config/tree/master/mpd.lua) +require("socket") + +-- Grab env +local socket = socket +local string = string +local tonumber = tonumber +local setmetatable = setmetatable +local os = os + +-- Music Player Daemon Lua library. +module("mpd") + +MPD = { +} MPD_mt = { __index = MPD } + +-- create and return a new mpd client. +-- the settings argument is a table with theses keys: +-- hostname: the MPD's host (default localhost) +-- port: MPD's port to connect to (default 6600) +-- desc: server's description (default hostname) +-- password: the server's password (default nil, no password) +-- timeout: time in sec to wait for connect() and receive() (default 1) +-- retry: time in sec to wait before reconnect if error (default 60) +function new(settings) + local client = {} + if settings == nil then settings = {} end + + client.hostname = settings.hostname or "localhost" + client.port = settings.port or 6600 + client.desc = settings.desc or client.hostname + client.password = settings.password + client.timeout = settings.timeout or 1 + client.retry = settings.retry or 60 + + setmetatable(client, MPD_mt) + + return client +end + + +-- calls the action and returns the server's response. +-- Example: if the server's response to "status" action is: +-- volume: 20 +-- repeat: 0 +-- random: 0 +-- playlist: 599 +-- ... +-- then the returned table is: +-- { volume = 20, repeat = 0, random = 0, playlist = 599, ... } +function MPD:send(action) + local command = string.format("%s\n", action) + local values = {} + + -- connect to MPD server if not already done. + if not self.connected then + if not self.last_try or (os.time() - self.last_try) > self.retry then + self.socket = socket.tcp() + self.socket:settimeout(self.timeout, 't') + self.last_try = os.time() + self.connected = self.socket:connect(self.hostname, self.port) + if self.connected and self.password then + self:send(string.format("password %s", self.password)) + end + end + end + + if not self.connected then + return {} + end + + self.socket:send(command) + + local line = "" + while not line:match("^OK$") do + line = self.socket:receive("*l") + if not line then -- closed,timeout (mpd killed?) + self.connected = false + return self:send(action) + end + + if line:match(string.format("^ACK", action)) then + return { errormsg = line } + end + + local _, _, key, value = string.find(line, "([^:]+):%s(.+)") + if key then + values[string.lower(key)] = value + end + end + + return values +end + +function MPD:next() + self:send("next") +end + +function MPD:previous() + self:send("previous") +end + +function MPD:stop() + self:send("stop") +end + +-- no need to check the new value, mpd will set the volume in [0,100] +function MPD:volume_up(delta) + local stats = self:send("status") + local new_volume = tonumber(stats.volume) + delta + self:send(string.format("setvol %d", new_volume)) +end + +function MPD:volume_down(delta) + self:volume_up(-delta) +end + +function MPD:toggle_random() + local stats = self:send("status") + if tonumber(stats.random) == 0 then + self:send("random 1") + else + self:send("random 0") + end +end + +function MPD:toggle_repeat() + local stats = self:send("status") + if tonumber(stats["repeat"]) == 0 then + self:send("repeat 1") + else + self:send("repeat 0") + end +end + +function MPD:toggle_play() + if self:send("status").state == "stop" then + self:send("play") + else + self:send("pause") + end +end + +-- vim:filetype=lua:tabstop=8:shiftwidth=2:fdm=marker: diff --git a/lib/shifty.lua b/lib/shifty.lua new file mode 100644 index 0000000..75a9f76 --- /dev/null +++ b/lib/shifty.lua @@ -0,0 +1,779 @@ +--- Shifty: Dynamic tagging library for awesome3-git +-- @author koniu <gkusnierz@gmail.com> +-- @author bioe007 <perry.hargrave@gmail.com> +-- +-- http://awesome.naquadah.org/wiki/index.php?title=Shifty + +-- package env +local type = type +local tag = tag +local ipairs = ipairs +local table = table +local client = client +local image = image +local string = string +local screen = screen +local button = button +local mouse = mouse +local beautiful = require("beautiful") +local awful = require("awful") +local pairs = pairs +local io = io +local tonumber = tonumber +local wibox = wibox +local root = root +local dbg= dbg +module("shifty") + +config = {} +config.tags = {} +config.apps = {} +config.defaults = {} +config.guess_name = true +config.guess_position = true +config.remember_index = true +config.default_name = "new" +config.clientkeys = {} +config.globalkeys = nil +config.layouts = {} +config.prompt_sources = { "config_tags", "config_apps", "existing", "history" } +config.prompt_matchers = { "^", ":", "" } + +local matchp = "" +local index_cache = {} +for i = 1, 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 screen.count() + for s = a, b do + for i, t in ipairs(screen[s]:tags()) 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(screen[scr]:tags()) 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 rename(tag, prefix, no_selectall) + local theme = beautiful.get() + local t = tag or awful.tag.selected(mouse.screen) + local scr = t.screen + 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 + + awful.prompt.run( { + fg_cursor = fg, bg_cursor = bg, ul_cursor = "single", + text = text, selectall = not no_selectall, prompt = " " }, + taglist[scr][tag2index(scr,t)*2], + 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 del(t) end + else + awful.tag.setproperty(t, "initial", true) + set(t) + end + awful.hooks.user.call("tags", scr) + 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 = client.focus.screen or mouse.screen + local sel = awful.tag.selected(scr) + local sel_idx = tag2index(scr,sel) + local target = awful.util.cycle(#screen[scr]:tags(), sel_idx + idx) + awful.tag.viewonly(screen[scr]:tags()[target]) + awful.client.movetotag(screen[scr]:tags()[target], client.focus) +end + +function send_next() send(1) end +function send_prev() send(-1) end +--}}} + +function shift_next() set(awful.tag.selected(), { rel_index = 1 }) end +function shift_prev() set(awful.tag.selected(), { rel_index = -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 + for i = #screen[scr]:tags() , 1, -1 do + local t = screen[scr]: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 +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 tagtoscr(scr, t) + -- break if called with an invalid screen number + if not scr or scr < 1 or scr > screen.count() then return end + -- tag to move + local otag = t or awful.tag.selected() + + -- 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 config.tags[t.name]) or {} + + -- pick screen and get its tag table + local scr = args.screen or (not t.screen and preset.screen) or t.screen or mouse.screen + if scr > screen.count() then scr = screen.count() end + if t.screen and scr ~= t.screen then + tagtoscr(scr, t) + t.screen = nil + end + local tags = screen[scr]:tags() + + -- try to guess position from the name + local guessed_position = nil + if not (args.position or preset.position) and config.guess_position then + local num = t.name:find('^[1-9]') + if num then guessed_position = tonumber(t.name:sub(1,1)) end + end + + -- select from args, preset, getproperty, config.defaults.configs or defaults + local props = { + layout = select{ args.layout, preset.layout, awful.tag.getproperty(t,"layout"), config.defaults.layout, awful.layout.suit.tile }, + mwfact = select{ args.mwfact, preset.mwfact, awful.tag.getproperty(t,"mwfact"), config.defaults.mwfact, 0.55 }, + nmaster = select{ args.nmaster, preset.nmaster, awful.tag.getproperty(t,"nmaster"), config.defaults.nmaster, 1 }, + ncol = select{ args.ncol, preset.ncol, awful.tag.getproperty(t,"ncol"), config.defaults.ncol, 1 }, + matched = select{ args.matched, awful.tag.getproperty(t,"matched") }, + exclusive = select{ args.exclusive, preset.exclusive, awful.tag.getproperty(t,"exclusive"), config.defaults.exclusive }, + persist = select{ args.persist, preset.persist, awful.tag.getproperty(t,"persist"), config.defaults.persist }, + nopopup = select{ args.nopopup, preset.nopopup, awful.tag.getproperty(t,"nopopup"), config.defaults.nopopup }, + leave_kills = select{ args.leave_kills, preset.leave_kills, awful.tag.getproperty(t,"leave_kills"), config.defaults.leave_kills }, + max_clients = select{ args.max_clients, preset.max_clients, awful.tag.getproperty(t,"max_clients"), config.defaults.max_clients }, + position = select{ args.position, preset.position, guessed_position, awful.tag.getproperty(t,"position" ) }, + icon = select{ args.icon and image(args.icon), preset.icon and image(preset.icon), awful.tag.getproperty(t,"icon"), config.defaults.icon and image(config.defaults.icon) }, + icon_only = select{ args.icon_only, preset.icon_only, awful.tag.getproperty(t,"icon_only"), config.defaults.icon_only }, + sweep_delay = select{ args.sweep_delay, preset.sweep_delay, awful.tag.getproperty(t,"sweep_delay"), config.defaults.sweep_delay }, + overload_keys = select{ args.overload_keys, preset.overload_keys, awful.tag.getproperty(t,"overload_keys"), 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(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 config.defaults.index + local rel_index = args.rel_index or preset.rel_index or config.defaults.rel_index + local sel = awful.tag.selected(scr) + local sel_idx = (sel and tag2index(scr,sel)) or 0 --TODO: what happens with rel_idx if no tags selected + 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 config.remember_index and index_cache[scr][t.name] then + idx = index_cache[scr][t.name] + 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 prop, val in pairs(props) do awful.tag.setproperty(t, prop, val) end + screen[scr]:tags(tags) + + -- execute run/spawn + if awful.tag.getproperty(t, "initial") then + local spawn = args.spawn or preset.spawn or config.defaults.spawn + local run = args.run or preset.run or 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 +--}}} + +--{{{ add : adds a tag +--@param args: table of optional arguments +-- +function add(args) + if not args then args = {} end + local name = args.name or " " + + -- initialize a new tag object and its data structure + local t = tag( name ) + + -- tell set() that this is the first time + awful.tag.setproperty(t, "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 #screen[t.screen]:tags() == 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) + if args.position then + f = function() rename(t, args.rename, true); awful.hooks.timer.unregister(f) end + else + f = function() rename(t); awful.hooks.timer.unregister(f) end + end + awful.hooks.timer.register(0.01, f) + end + + return t +end +--}}} + +--{{{ del : delete a tag +--@param tag : the tag to be deleted [current tag] +function del(tag) + local scr = (tag and tag.screen) or mouse.screen or 1 + local tags = screen[scr]:tags() + 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 + t.screen = nil + + -- if the current tag is being deleted, restore from history + if t == sel and #tags > 1 then + awful.tag.history.restore(scr) + -- 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 client.focus then client.focus:raise() end +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, wfact, struts, geom + 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 = config.clientkeys or c:keys() or {} + local target_screen = 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(config.apps) do + if a.match then + for k, w in ipairs(a.match) do + if + (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)) + 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.float ~= nil then awful.client.floating.set(c, a.float) 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.slave ~=nil then slave = a.slave 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.hide ~= nil then c.hide = a.hide 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.titlebar ~= nil then awful.titlebar.add(c, { modkey = modkey }) 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 + end + end + end + end + + -- set key bindings + c:keys(keys) + + -- set properties of floating clients + if awful.client.floating.get(c) then + if config.defaults.floatBars then -- add a titlebar if requested in config.defaults + awful.titlebar.add( c, { modkey = modkey } ) + end + awful.placement.centered(c, c.transient_for) + awful.placement.no_offscreen(c) -- this always seems to stick the client at 0,0 (incl titlebar) + end + + -- if not matched to some names try putting client in c.transient_for or current tags + local sel = awful.tag.selectedlist(target_screen) + if not target_tag_names or #target_tag_names == 0 then + 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 not (awful.tag.getproperty(t,"exclusive") or (mc and mc >= #t:clients())) or intrusive then + table.insert(target_tags, t) + end + end + end + end + + -- if we still don't know any target names/tags guess name from class or use default + if (not target_tag_names or #target_tag_names == 0) and (not target_tags or #target_tags == 0) then + if config.guess_name and cls then + target_tag_names = { cls:lower() } + else + target_tag_names = { config.default_name } + end + end + + -- translate target names to tag objects, creating missing ones + if #target_tag_names > 0 and #target_tags == 0 then + 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") + if not (mc and (#t:clients() >= mc)) or intrusive then + table.insert(res, t) + end + end + if #res == 0 then + table.insert(target_tags, 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 = target_tags[1].screen or target_screen + if c.screen ~= target_screen then c.screen = target_screen end + c:tags( target_tags ) + if slave then awful.client.setslave(c) end + if wfact then awful.client.setwfact(wfact, c) end + if geom then c:geometry(geom) end + if struts then c:struts(struts) end + + -- switch or highlight + local showtags = {} + local u = nil + if #target_tags > 0 then + for i,t in ipairs(target_tags) do + if not(awful.tag.getproperty(t,"nopopup") or nopopup) then + table.insert(showtags, t) + elseif not startup then + c.urgent = true + end + end + if #showtags > 0 then + awful.tag.viewmore(showtags, c.screen) + end + end + + -- focus and raise accordingly or lower if supressed + if not (nofocus or c.hide or c.minimized) then + if (awful.tag.getproperty(target,"nopopup") or nopopup) and (target and target ~= sel) then + awful.client.focus.history.add(c) + else + client.focus = c + end + c:raise() + else + c:lower() + 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, screen.count() do + for i, t in ipairs(screen[s]:tags()) 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 not awful.tag.getproperty(t,"persist") and awful.tag.getproperty(t,"used") 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 + --FIXME: global f, what if more than one at a time is being swept + f = function() del(t); awful.hooks.timer.unregister(f) end + awful.hooks.timer.register(delay, f) + else + del(t) + end + else + if not t.selected and awful.tag.getproperty(t,"visited") 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 +-- * originally this function did a lot of client stuff, i think its +-- * better to leave what can be done by awful to be done by awful +-- * -perry +-- @param pos : the index to find +-- @return v : the tag (found or created) at position == 'pos' +function getpos(pos) + local v = nil + local existing = {} + local selected = nil + local scr = mouse.screen or 1 + -- search for existing tag assigned to pos + for i = 1, screen.count() do + local s = awful.util.cycle(screen.count(), scr + i - 1) + for j, t in ipairs(screen[s]:tags()) do + if awful.tag.getproperty(t,"position") == pos then + table.insert(existing, t) + if t.selected and s == scr then selected = #existing end + end + end + end + if #existing > 0 then + -- if makeing another of an existing tag, return the end of the list + if selected then v = existing[awful.util.cycle(#existing, selected + 1)] else v = existing[1] end + end + if not v then + -- search for preconf with 'pos' and create it + for i, j in pairs(config.tags) do + if j.position == pos then v = add({ name = i, position = pos, noswitch = not switch }) end + end + end + if not v then + -- not existing, not preconfigured + v = add({ position = pos, rename = pos .. ':', no_selectall = true, noswitch = not switch }) + end + return v +end +--}}} + +--{{{ init : search shifty.config.tags for initial set of tags to open +function init() + local numscr = screen.count() + + for i, j in pairs(config.tags) do + local scr = j.screen or 1 + if j.init and ( scr <= numscr ) then + add({ name = i, persist = true, screen = scr, layout = j.layout, mwfact = j.mwfact }) + end + end +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 config.prompt_sources + matchers = matchers or config.prompt_matchers + + local get_source = { + -- gather names from config.tags + config_tags = function() + local ret = {} + for n, p in pairs(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(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, screen.count() do + local s = awful.util.cycle(screen.count(), mouse.screen + i - 1) + local tags = screen[s]:tags() + 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) + local keys = awful.tag.getproperty(sel, "keys") or config.globalkeys + if keys then 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.keysym] = 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(config.layouts) do + if awful.layout.getname(layout) == name then return layout end + end +end +-- }}} + +awful.hooks.manage.unregister(awful.tag.withcurrent) +awful.hooks.tags.register(sweep) +awful.hooks.arrange.register(sweep) +awful.hooks.arrange.register(tagkeys) +awful.hooks.clients.register(sweep) +awful.hooks.manage.register(match) + +-- vim: foldmethod=marker:filetype=lua:expandtab:shiftwidth=2:tabstop=2:softtabstop=2:encoding=utf-8:textwidth=80 diff --git a/rc.lua b/rc.lua new file mode 100644 index 0000000..9518105 --- /dev/null +++ b/rc.lua @@ -0,0 +1,335 @@ +-- Standard awesome library +require("awful") +require("awful.autofocus") +require("awful.rules") +-- Theme handling library +require("beautiful") +-- Notification library +require("naughty") +require("teardrop") + +-- {{{ Variable definitions +-- Themes define colours, icons, and wallpapers +beautiful.init("/usr/share/awesome/themes/default/theme.lua") + +-- This is used later as the default terminal and editor to run. +terminal = "terminal" +editor = os.getenv("EDITOR") or "vim" +editor_cmd = terminal .. " -e " .. editor + +-- Default modkey. +-- Usually, Mod4 is the key with a logo between Control and Alt. +-- If you do not like this or do not have such a key, +-- I suggest you to remap Mod4 to another key using xmodmap or other tools. +-- However, you can use another modifier like Mod1, but it may interact with others. +modkey = "Mod4" + +-- Table of layouts to cover with awful.layout.inc, order matters. +layouts = +{ + awful.layout.suit.tile, + awful.layout.suit.tile.left, + awful.layout.suit.tile.bottom, + awful.layout.suit.tile.top, + awful.layout.suit.fair, + awful.layout.suit.fair.horizontal, + awful.layout.suit.spiral, + awful.layout.suit.spiral.dwindle, + awful.layout.suit.max, + awful.layout.suit.max.fullscreen, + awful.layout.suit.magnifier, + awful.layout.suit.floating +} +-- }}} + +-- {{{ Tags +-- Define a tag table which hold all screen tags. +tags = {} +for s = 1, screen.count() do + -- Each screen has its own tag table. + tags[s] = awful.tag({ 1, 2, 3, 4, 5, 6, 7, 8, 9 }, s) +end +-- }}} + +-- {{{ Menu +-- Create a laucher widget and a main menu +myawesomemenu = { + { "manual", terminal .. " -e man awesome" }, + { "edit config", editor_cmd .. " " .. awful.util.getdir("config") .. "/rc.lua" }, + { "restart", awesome.restart }, + { "quit", awesome.quit } +} + +mymainmenu = awful.menu({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon }, + { "open terminal", terminal } + } + }) + +mylauncher = awful.widget.launcher({ image = image(beautiful.awesome_icon), + menu = mymainmenu }) +-- }}} + +-- {{{ Wibox +-- Create a textclock widget +mytextclock = awful.widget.textclock({ align = "right" }) + +-- Create a systray +mysystray = widget({ type = "systray" }) + +-- Create a wibox for each screen and add it +mywibox = {} +mypromptbox = {} +mylayoutbox = {} +mytaglist = {} +mytaglist.buttons = awful.util.table.join( + awful.button({ }, 1, awful.tag.viewonly), + awful.button({ modkey }, 1, awful.client.movetotag), + awful.button({ }, 3, awful.tag.viewtoggle), + awful.button({ modkey }, 3, awful.client.toggletag), + awful.button({ }, 4, awful.tag.viewnext), + awful.button({ }, 5, awful.tag.viewprev) + ) +mytasklist = {} +mytasklist.buttons = awful.util.table.join( + awful.button({ }, 1, function (c) + if not c:isvisible() then + awful.tag.viewonly(c:tags()[1]) + end + client.focus = c + c:raise() + end), + awful.button({ }, 3, function () + if instance then + instance:hide() + instance = nil + else + instance = awful.menu.clients({ width=250 }) + end + end), + awful.button({ }, 4, function () + awful.client.focus.byidx(1) + if client.focus then client.focus:raise() end + end), + awful.button({ }, 5, function () + awful.client.focus.byidx(-1) + if client.focus then client.focus:raise() end + end)) + +for s = 1, screen.count() do + -- Create a promptbox for each screen + mypromptbox[s] = awful.widget.prompt({ layout = awful.widget.layout.horizontal.leftright }) + -- Create an imagebox widget which will contains an icon indicating which layout we're using. + -- We need one layoutbox per screen. + mylayoutbox[s] = awful.widget.layoutbox(s) + mylayoutbox[s]:buttons(awful.util.table.join( + awful.button({ }, 1, function () awful.layout.inc(layouts, 1) end), + awful.button({ }, 3, function () awful.layout.inc(layouts, -1) end), + awful.button({ }, 4, function () awful.layout.inc(layouts, 1) end), + awful.button({ }, 5, function () awful.layout.inc(layouts, -1) end))) + -- Create a taglist widget + mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.label.all, mytaglist.buttons) + + -- Create a tasklist widget + mytasklist[s] = awful.widget.tasklist(function(c) + return awful.widget.tasklist.label.currenttags(c, s) + end, mytasklist.buttons) + + -- Create the wibox + mywibox[s] = awful.wibox({ position = "top", screen = s }) + -- Add widgets to the wibox - order matters + mywibox[s].widgets = { + { + mylauncher, + mytaglist[s], + mypromptbox[s], + layout = awful.widget.layout.horizontal.leftright + }, + mylayoutbox[s], + mytextclock, + s == 1 and mysystray or nil, + mytasklist[s], + layout = awful.widget.layout.horizontal.rightleft + } +end +-- }}} + +-- {{{ Mouse bindings +root.buttons(awful.util.table.join( + awful.button({ }, 3, function () mymainmenu:toggle() end), + awful.button({ }, 4, awful.tag.viewnext), + awful.button({ }, 5, awful.tag.viewprev) +)) +-- }}} + +-- {{{ Key bindings +globalkeys = awful.util.table.join( + 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, }, "w", function () mymainmenu:show(true) 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, "Control" }, "j", function () awful.screen.focus_relative( 1) end), + awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative(-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), + + -- Standard program + awful.key({ modkey, }, "Return", function () awful.util.spawn(terminal) end), + awful.key({ modkey, "Control" }, "r", awesome.restart), + awful.key({ modkey, "Shift" }, "q", awesome.quit), + + 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, -1) end), + + -- Prompt + awful.key({ modkey }, "r", function () mypromptbox[mouse.screen]:run() end), + + awful.key({ modkey }, "x", + function () + awful.prompt.run({ prompt = "Run Lua code: " }, + mypromptbox[mouse.screen].widget, + awful.util.eval, nil, + awful.util.getdir("cache") .. "/history_eval") + end) +) + +clientkeys = awful.util.table.join( + awful.key({ modkey, }, "f", function (c) c.fullscreen = not c.fullscreen end), + awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end), + awful.key({ modkey, "Control" }, "space", 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" }, "r", function (c) c:redraw() end), + awful.key({ modkey, }, "n", function (c) c.minimized = not c.minimized end), + awful.key({ modkey, }, "m", + function (c) + c.maximized_horizontal = not c.maximized_horizontal + c.maximized_vertical = not c.maximized_vertical + end) +) + +-- Compute the maximum number of digit we need, limited to 9 +keynumber = 0 +for s = 1, screen.count() do + keynumber = math.min(9, math.max(#tags[s], keynumber)); +end + +-- Bind all key numbers to tags. +-- Be careful: we use keycodes to make it works on any keyboard layout. +-- This should map on the top row of your keyboard, usually 1 to 9. +for i = 1, keynumber do + globalkeys = awful.util.table.join(globalkeys, + awful.key({ modkey }, "#" .. i + 9, + function () + local screen = mouse.screen + if tags[screen][i] then + awful.tag.viewonly(tags[screen][i]) + end + end), + awful.key({ modkey, "Control" }, "#" .. i + 9, + function () + local screen = mouse.screen + if tags[screen][i] then + awful.tag.viewtoggle(tags[screen][i]) + end + end), + awful.key({ modkey, "Shift" }, "#" .. i + 9, + function () + if client.focus and tags[client.focus.screen][i] then + awful.client.movetotag(tags[client.focus.screen][i]) + end + end), + awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9, + function () + if client.focus and tags[client.focus.screen][i] then + awful.client.toggletag(tags[client.focus.screen][i]) + end + end)) +end + +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)) + +-- Set keys +root.keys(globalkeys) +-- }}} + +-- {{{ Rules +awful.rules.rules = { + -- All clients will match this rule. + { rule = { }, + properties = { border_width = beautiful.border_width, + border_color = beautiful.border_normal, + focus = true, + keys = clientkeys, + buttons = clientbuttons } }, + { rule = { class = "MPlayer" }, + properties = { floating = true } }, + { rule = { class = "pinentry" }, + properties = { floating = true } }, + { rule = { class = "gimp" }, + properties = { floating = true } }, + -- Set Firefox to always map on tags number 2 of screen 1. + -- { rule = { class = "Firefox" }, + -- properties = { tag = tags[1][2] } }, +} +-- }}} + +-- {{{ Signals +-- Signal function to execute when a new client appears. +client.add_signal("manage", function (c, startup) + -- Add a titlebar + -- awful.titlebar.add(c, { modkey = modkey }) + + -- Enable sloppy focus + c:add_signal("mouse::enter", function(c) + if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier + and awful.client.focus.filter(c) then + client.focus = c + end + end) + + if not startup then + -- Set the windows at the slave, + -- i.e. put it at the end of others instead of setting it master. + -- awful.client.setslave(c) + + -- Put windows in a smart way, only if they does not set an initial position. + if not c.size_hints.user_position and not c.size_hints.program_position then + awful.placement.no_overlap(c) + awful.placement.no_offscreen(c) + end + end +end) + +client.add_signal("focus", function(c) c.border_color = beautiful.border_focus end) +client.add_signal("unfocus", function(c) c.border_color = beautiful.border_normal end) +-- }}} diff --git a/scratchpad.lua b/scratchpad.lua new file mode 100644 index 0000000..c196fc3 --- /dev/null +++ b/scratchpad.lua @@ -0,0 +1,136 @@ +--------------------------------------------------------------- +-- Basic scratchpad manager for the awesome window manager +--------------------------------------------------------------- +-- Adrian C. +-- 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 = false + oc.ontop = false; oc.above = false + scratch["pad"][screen] = nil + else -- If they don't match, unscratch and replace it + oc.hidden = false; oc.sticky = false + oc.ontop = false; oc.above = 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 diff --git a/teardrop.lua b/teardrop.lua new file mode 100644 index 0000000..f9ce7bb --- /dev/null +++ b/teardrop.lua @@ -0,0 +1,128 @@ +---------------------------------------------------------------- +-- Drop-down applications manager for the awesome window manager +---------------------------------------------------------------- +-- Adrian C. +-- Licensed under the WTFPL version 2 +-- * http://sam.zoy.org/wtfpl/COPYING +---------------------------------------------------------------- +-- To use this module add: +-- require("teardrop") +-- to the top of your rc.lua, and call it from a keybinding: +-- teardrop(prog, vert, horiz, width, height, sticky, screen) +-- +-- Parameters: +-- prog - Program to run; "urxvt", "gmrun", "thunderbird" +-- vert - Vertical; "bottom", "center" or "top" (default) +-- horiz - Horizontal; "left", "right" or "center" (default) +-- width - Width in absolute pixels, or width percentage +-- when < 1 (0.9999 (99.9% of the screen) by default) +-- height - Height in absolute pixels, or height percentage +-- when < 1 (0.25 (25% of the screen) by default) +-- sticky - Visible on all tags, false by default +-- screen - Screen (optional), mouse.screen by default +---------------------------------------------------------------- + +-- Grab environment +local pairs = pairs +local awful = require("awful") +local setmetatable = setmetatable +local capi = { + mouse = mouse, + client = client, + screen = screen +} + +-- Teardrop: Drop-down applications manager for the awesome window manager +module("teardrop") + +local dropdown = {} + +-- Create a new window for the drop-down application when it doesn't +-- exist, or toggle between hidden and visible states when it does +function toggle(prog, vert, horiz, width, height, sticky, screen) + local vert = vert or "top" + local horiz = horiz or "center" + local width = width or 0.9999 + local height = height or 0.25 + local sticky = sticky or false + local screen = screen or capi.mouse.screen + + if not dropdown[prog] then + dropdown[prog] = {} + + -- Add unmanage signal for teardrop programs + capi.client.add_signal("unmanage", function (c) + for scr, cl in pairs(dropdown[prog]) do + if cl == c then + dropdown[prog][scr] = nil + end + end + end) + end + + if not dropdown[prog][screen] then + spawnw = function (c) + dropdown[prog][screen] = c + + -- Teardrop clients are floaters + awful.client.floating.set(c, true) + + -- Client 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 + + if horiz == "left" then x = screengeom.x + elseif horiz == "right" then x = screengeom.width - width + else x = screengeom.x+(screengeom.width-width)/2 end + + if vert == "bottom" then y = screengeom.height + screengeom.y - height + elseif vert == "center" then y = screengeom.y+(screengeom.height-height)/2 + else y = screengeom.y - screengeom.y end + + -- Client properties + c:geometry({ x = x, y = y, width = width, height = height }) + 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 + + c:raise() + capi.client.focus = c + capi.client.remove_signal("manage", spawnw) + end + + -- Add manage signal and spawn the program + capi.client.add_signal("manage", spawnw) + awful.util.spawn(prog, false) + else + -- Get a running client + c = dropdown[prog][screen] + + -- Switch the client to the current workspace + if c:isvisible() == false then c.hidden = true; + awful.client.movetotag(awful.tag.selected(screen), c) + end + + -- Focus and raise if hidden + if c.hidden then + -- Make sure it is centered + if vert == "center" then awful.placement.center_vertical(c) end + if horiz == "center" then awful.placement.center_horizontal(c) end + c.hidden = false + c:raise() + capi.client.focus = c + else -- Hide and detach tags if not + c.hidden = true + local ctags = c:tags() + for i, v in pairs(ctags) do + ctags[i] = nil + end + c:tags(ctags) + end + end +end + +setmetatable(_M, { __call = function(_, ...) return toggle(...) end }) diff --git a/theme.lua b/theme.lua new file mode 100644 index 0000000..df83de0 --- /dev/null +++ b/theme.lua @@ -0,0 +1,142 @@ +------------------------------- +-- "Zenburn" awesome theme -- +-- By Adrian C. (anrxc) -- +------------------------------- + + +-- {{{ Main +theme = {} +confdir = awful.util.getdir("config") +theme.wallpaper_cmd = { "/usr/bin/nitrogen --restore" } +--theme.wallpaper_cmd = { "awsetbg /usr/share/awesome/themes/zenburn/zenburn-background.png" } +-- }}} + + +-- {{{ Styles +theme.font = "fixed 6" + +-- {{{ Colors +theme.fg_normal = "#DCDCCC" +theme.fg_focus = "#F0DFAF" +theme.fg_urgent = "#CC9393" +theme.bg_normal = "#3F3F3F" +theme.bg_focus = "#1E2320" +theme.bg_urgent = "#3F3F3F" +-- }}} + +-- {{{ Borders +theme.border_width = "1" +theme.border_normal = "#3F3F3F" +theme.border_focus = "#6F6F6F" +theme.border_marked = "#CC9393" +-- }}} + +-- {{{ Titlebars +theme.titlebar_bg_focus = "#5F5F5F" +theme.titlebar_bg_normal = "#3F3F3F" +-- theme.titlebar_[normal|focus] +-- }}} + +-- {{{ Widgets +theme.fg_widget = "#AECF96" +theme.fg_center_widget = "#88A175" +theme.fg_end_widget = "#FF5656" +theme.fg_off_widget = "#494B4F" +theme.fg_netup_widget = "#7F9F7F" +theme.fg_netdn_widget = "#CC9393" +theme.bg_widget = "#3F3F3F" +theme.border_widget = "#3F3F3F" +-- }}} + +-- {{{ Mouse finder +theme.mouse_finder_color = "#CC9393" +-- theme.mouse_finder_[timeout|animate_timeout|radius|factor] +-- }}} + +-- {{{ Tooltips +-- theme.tooltip_[font|opacity|fg_color|bg_color|border_width|border_color] +-- }}} + +-- {{{ Taglist and Tasklist +-- theme.[taglist|tasklist]_[bg|fg]_[focus|urgent] +-- }}} + +-- {{{ Menu +-- theme.menu_[height|width] +-- theme.menu_[bg|fg]_[normal|focus] +-- theme.menu_[border_color|border_width] +-- }}} +-- }}} + + +-- {{{ Icons +-- +-- {{{ Taglist icons +theme.taglist_squares_sel = confdir .. "/icons/taglist/squarefw.png" +theme.taglist_squares_unsel = confdir .. "/icons/taglist/squarew.png" +--theme.taglist_squares_resize = "false" +-- }}} + +-- {{{ Misc icons +--theme.awesome_icon = confdir .. "/icons/awesome.png" +--theme.menu_submenu_icon = "/usr/share/awesome/themes/default/submenu.png" +--theme.tasklist_floating_icon = "/usr/share/awesome/themes/default/tasklist/floatingw.png" +-- }}} + +-- {{{ Layout icons +theme.layout_tile = confdir .. "/icons/layouts/tilew.png" +theme.layout_tileleft = confdir .. "/icons/layouts/tileleftw.png" +theme.layout_tilebottom = confdir .. "/icons/layouts/tilebottomw.png" +theme.layout_tiletop = confdir .. "/icons/layouts/tiletopw.png" +theme.layout_fairv = confdir .. "/icons/layouts/fairvw.png" +theme.layout_fairh = confdir .. "/icons/layouts/fairhw.png" +theme.layout_spiral = confdir .. "/icons/layouts/spiralw.png" +theme.layout_dwindle = confdir .. "/icons/layouts/dwindlew.png" +theme.layout_max = confdir .. "/icons/layouts/maxw.png" +theme.layout_fullscreen = confdir .. "/icons/layouts/fullscreenw.png" +theme.layout_magnifier = confdir .. "/icons/layouts/magnifierw.png" +theme.layout_floating = confdir .. "/icons/layouts/floatingw.png" +-- }}} + +-- {{{ Widget icons +theme.widget_cpu = confdir .. "/icons/cpu.png" +theme.widget_bat = confdir .. "/icons/bat.png" +theme.widget_mem = confdir .. "/icons/mem.png" +theme.widget_fs = confdir .. "/icons/disk.png" +theme.widget_net = confdir .. "/icons/down.png" +theme.widget_netup = confdir .. "/icons/up.png" +theme.widget_mail = confdir .. "/icons/mail.png" +theme.widget_vol = confdir .. "/icons/vol.png" +theme.widget_org = confdir .. "/icons/cal.png" +theme.widget_date = confdir .. "/icons/time.png" +theme.widget_crypto = confdir .. "/icons/crypto.png" +-- }}} + +-- {{{ Titlebar icons +theme.titlebar_close_button_focus = confdir .. "/icons/titlebar/close_focus.png" +theme.titlebar_close_button_normal = confdir .. "/icons/titlebar/close_normal.png" + +theme.titlebar_ontop_button_focus_active = confdir .. "/icons/titlebar/ontop_focus_active.png" +theme.titlebar_ontop_button_normal_active = confdir .. "/icons/titlebar/ontop_normal_active.png" +theme.titlebar_ontop_button_focus_inactive = confdir .. "/icons/titlebar/ontop_focus_inactive.png" +theme.titlebar_ontop_button_normal_inactive = confdir .. "/icons/titlebar/ontop_normal_inactive.png" + +theme.titlebar_sticky_button_focus_active = confdir .. "/icons/titlebar/sticky_focus_active.png" +theme.titlebar_sticky_button_normal_active = confdir .. "/icons/titlebar/sticky_normal_active.png" +theme.titlebar_sticky_button_focus_inactive = confdir .. "/icons/titlebar/sticky_focus_inactive.png" +theme.titlebar_sticky_button_normal_inactive = confdir .. "/icons/titlebar/sticky_normal_inactive.png" + +theme.titlebar_floating_button_focus_active = confdir .. "/icons/titlebar/floating_focus_active.png" +theme.titlebar_floating_button_normal_active = confdir .. "/icons/titlebar/floating_normal_active.png" +theme.titlebar_floating_button_focus_inactive = confdir .. "/icons/titlebar/floating_focus_inactive.png" +theme.titlebar_floating_button_normal_inactive = confdir .. "/icons/titlebar/floating_normal_inactive.png" + +theme.titlebar_maximized_button_focus_active = confdir .. "/icons/titlebar/maximized_focus_active.png" +theme.titlebar_maximized_button_normal_active = confdir .. "/icons/titlebar/maximized_normal_active.png" +theme.titlebar_maximized_button_focus_inactive = confdir .. "/icons/titlebar/maximized_focus_inactive.png" +theme.titlebar_maximized_button_normal_inactive = confdir .. "/icons/titlebar/maximized_normal_inactive.png" +-- }}} +-- }}} + + +return theme diff --git a/wicked.lua b/wicked.lua new file mode 100644 index 0000000..064d928 --- /dev/null +++ b/wicked.lua @@ -0,0 +1,848 @@ +--------------------------------------------------------------------------- +-- Wicked widgets for the awesome window manager +--------------------------------------------------------------------------- +-- Lucas de Vries +-- Licensed under the WTFPL +-- Version: v1.0pre-awe3.0rc4 +--------------------------------------------------------------------------- + +-- Require libs +require("awful") + +---- {{{ Grab environment +local ipairs = ipairs +local pairs = pairs +local print = print +local type = type +local tonumber = tonumber +local tostring = tostring +local math = math +local table = table +local awful = awful +local os = os +local io = io +local string = string + +-- Grab C API +local capi = +{ + awesome = awesome, + screen = screen, + client = client, + mouse = mouse, + button = button, + titlebar = titlebar, + widget = widget, + hooks = hooks, + keygrabber = keygrabber +} + +-- }}} + +-- Wicked: Widgets for the awesome window manager +module("wicked") + +---- {{{ Initialise variables +local registered = {} +local widget_cache = {} + +-- Initialise function tables +widgets = {} +helper = {} + +local nets = {} +local cpu_total = {} +local cpu_active = {} +local cpu_usage = {} + +-- }}} + +---- {{{ Helper functions + +----{{{ Max width +function helper.max_width(str, width) + l = str:len() + + if l > width then + r = math.floor(width/2) + a = str:sub(1,r) + b = str:sub(l-r, l) + str = a .. "..." .. b + end + + return str +end +----}}} + +----{{{ Force a fixed width on a string with spaces +function helper.fixed_width(str, width) + l = str:len() + n = width-l + if n >= 0 then + for i = 1, n do + str = str.." " + end + else + str = str:sub(0, l+n) + end + return str +end +----}}} + +---- {{{ Format a string with args +function helper.format(format, args) + -- TODO: Find a more efficient way to do this + + -- Format a string + for var,val in pairs(args) do + format = string.gsub(format, '$'..var, val) + end + + -- Return formatted string + return format +end +-- }}} + +---- {{{ Padd a number to a minimum amount of digits +function helper.padd(number, padding) + s = tostring(number) + + if padding == nil then + return s + end + + for i=1,padding do + if math.floor(number/math.pow(10,(i-1))) == 0 then + s = "0"..s + end + end + + if number == 0 then + s = s:sub(2) + end + + return s +end +-- }}} + +---- {{{ Convert amount of bytes to string +function helper.bytes_to_string(bytes, sec, padding) + if bytes == nil or tonumber(bytes) == nil then + return '' + end + + bytes = tonumber(bytes) + + signs = {} + signs[1] = ' b' + signs[2] = 'KiB' + signs[3] = 'MiB' + signs[4] = 'GiB' + signs[5] = 'TiB' + + sign = 1 + + while bytes/1024 > 1 and signs[sign+1] ~= nil do + bytes = bytes/1024 + sign = sign+1 + end + + bytes = bytes*10 + bytes = math.floor(bytes)/10 + + if padding then + bytes = helper.padd(bytes*10, padding+1) + bytes = bytes:sub(1, bytes:len()-1).."."..bytes:sub(bytes:len()) + end + + if sec then + return tostring(bytes)..signs[sign]..'ps' + else + return tostring(bytes)..signs[sign] + end +end +-- }}} + +---- {{{ Split by whitespace +function helper.splitbywhitespace(str) + values = {} + start = 1 + splitstart, splitend = string.find(str, ' ', start) + + while splitstart do + m = string.sub(str, start, splitstart-1) + if m:gsub(' ','') ~= '' then + table.insert(values, m) + end + + start = splitend+1 + splitstart, splitend = string.find(str, ' ', start) + end + + m = string.sub(str, start) + if m:gsub(' ','') ~= '' then + table.insert(values, m) + end + + return values +end +-- }}} + +--{{{ Escape a string +function helper.escape(text) + if text then + text = text:gsub("&", "&") + text = text:gsub("<", "<") + text = text:gsub(">", ">") + text = text:gsub("'", "'") + text = text:gsub("\"", """) + end + return text +end + +-- }}} + +-- }}} + +---- {{{ Widget types + +---- {{{ MPD widget type +function widgets.mpd() + ---- Get data from mpc + local nowplaying_file = io.popen('mpc') + local nowplaying = nowplaying_file:read() + + -- Close the command + nowplaying_file:close() + + -- Check that it's not nil + if nowplaying == nil then + return {''} + end + + -- Escape + nowplaying = helper.escape(nowplaying) + + -- Return it + return {nowplaying} +end + +widget_cache[widgets.mpd] = {} +-- }}} + +---- {{{ MOCP widget type +function widgets.mocp(format, max_width) + local playing = '' + + ---- Get data from mocp + local info = io.popen('mocp -i') + local state = info:read() + state = state.gsub(state, 'State: ', '') + + if (state == "PLAY") then + local file = info:read() + file = file.gsub(file, 'File: ', '') + local title = info:read() + title = title.gsub(title, 'Title: ', '') + local artist = info:read() + artist = artist.gsub(artist, 'Artist: ', '') + local songtitle = info:read() + songtitle = songtitle.gsub(songtitle, 'SongTitle: ', '') + local album = info:read() + album = album.gsub(album, 'Album: ', '') + + -- Try artist - (song)title + if (artist:len() > 0) then + playing = artist .. ' - ' .. (songtitle ~= '' and songtitle or title) + + -- Else try title or songtitle + elseif (artist:len() == 0 and (title:len() > 0 or songtitle:len() > 0)) then + playing = (title ~= '' and title or songtitle) + + -- Else use the filename + else + file = string.reverse(file) + i = string.find(file, '/') + if (i ~= nil) then + file = string.sub(file, 0, i-1) + end + playing = string.reverse(file) + end + else + playing = state + end + + -- Close file + info:close() + + -- Apply maximum width + if (max_width ~= nil) then + playing = helper.max_width(playing, max_width) + end + + playing = helper.escape(playing) + + -- Return it + return {playing} +end + +widget_cache[widgets.mocp] = {} +-- }}} + +---- {{{ CPU widget type +function widgets.cpu(format, padding) + -- Calculate CPU usage for all available CPUs / cores and return the + -- usage + + -- Perform a new measurement + ---- Get /proc/stat + local cpu_lines = {} + local cpu_usage_file = io.open('/proc/stat') + for line in cpu_usage_file:lines() do + if string.sub(line, 1, 3) == 'cpu' then + table.insert(cpu_lines, helper.splitbywhitespace(line)) + end + end + cpu_usage_file:close() + + ---- Ensure tables are initialized correctly + while #cpu_total < #cpu_lines do + table.insert(cpu_total, 0) + end + while #cpu_active < #cpu_lines do + table.insert(cpu_active, 0) + end + while #cpu_usage < #cpu_lines do + table.insert(cpu_usage, 0) + end + + ---- Setup tables + total_new = {} + active_new = {} + diff_total = {} + diff_active = {} + + for i,v in ipairs(cpu_lines) do + ---- Calculate totals + total_new[i] = 0 + for j = 2, #v do + total_new[i] = total_new[i] + v[j] + end + active_new[i] = v[2] + v[3] + v[4] + + ---- Calculate percentage + diff_total[i] = total_new[i] - cpu_total[i] + diff_active[i] = active_new[i] - cpu_active[i] + cpu_usage[i] = math.floor(diff_active[i] / diff_total[i] * 100) + + ---- Store totals + cpu_total[i] = total_new[i] + cpu_active[i] = active_new[i] + end + + if padding ~= nil then + for k,v in pairs(cpu_usage) do + if type(padding) == "table" then + p = padding[k] + else + p = padding + end + + cpu_usage[k] = helper.padd(cpu_usage[k], p) + end + end + + return cpu_usage +end + +widget_cache[widgets.cpu] = {} +-- }}} + +---- {{{ Memory widget type +function widgets.mem(format, padding) + -- Return MEM usage values + local f = io.open('/proc/meminfo') + + ---- Get data + for line in f:lines() do + line = helper.splitbywhitespace(line) + + if line[1] == 'MemTotal:' then + mem_total = math.floor(line[2]/1024) + elseif line[1] == 'MemFree:' then + free = math.floor(line[2]/1024) + elseif line[1] == 'Buffers:' then + buffers = math.floor(line[2]/1024) + elseif line[1] == 'Cached:' then + cached = math.floor(line[2]/1024) + end + end + f:close() + + ---- Calculate percentage + mem_free=free+buffers+cached + mem_inuse=mem_total-mem_free + mem_usepercent = math.floor(mem_inuse/mem_total*100) + + if padding then + if type(padding) == "table" then + mem_usepercent = helper.padd(mem_usepercent, padding[1]) + mem_inuse = helper.padd(mem_inuse, padding[2]) + mem_total = helper.padd(mem_total, padding[3]) + mem_free = helper.padd(mem_free, padding[4]) + else + mem_usepercent = helper.padd(mem_usepercent, padding) + mem_inuse = helper.padd(mem_inuse, padding) + mem_total = helper.padd(mem_total, padding) + mem_free = helper.padd(mem_free, padding) + end + end + + return {mem_usepercent, mem_inuse, mem_total, mem_free} +end + +widget_cache[widgets.mem] = {} +-- }}} + +---- {{{ Swap widget type +function widgets.swap(format, padding) + -- Return SWAP usage values + local f = io.open('/proc/meminfo') + + ---- Get data + for line in f:lines() do + line = helper.splitbywhitespace(line) + + if line[1] == 'SwapTotal:' then + swap_total = math.floor(line[2]/1024) + elseif line[1] == 'SwapFree:' then + free = math.floor(line[2]/1024) + elseif line[1] == 'SwapCached:' then + cached = math.floor(line[2]/1024) + end + end + f:close() + + ---- Calculate percentage + swap_free=free+cached + swap_inuse=swap_total-swap_free + swap_usepercent = math.floor(swap_inuse/swap_total*100) + + if padding then + if type(padding) == "table" then + swap_usepercent = helper.padd(swap_usepercent, padding[1]) + swap_inuse = helper.padd(swap_inuse, padding[2]) + swap_total = helper.padd(swap_total, padding[3]) + swap_free = helper.padd(swap_free, padding[4]) + else + swap_usepercent = helper.padd(swap_usepercent, padding) + swap_inuse = helper.padd(swap_inuse, padding) + swap_total = helper.padd(swap_total, padding) + swap_free = helper.padd(swap_free, padding) + end + end + + return {swap_usepercent, swap_inuse, swap_total, swap_free} +end + +widget_cache[widgets.swap] = {} +-- }}} + +---- {{{ Date widget type +function widgets.date(format) + -- Get format + if format == nil then + return os.date() + else + return os.date(format) + end +end +-- }}} + +---- {{{ Filesystem widget type +function widgets.fs(format, padding) + local f = io.popen('df -hP') + local args = {} + + for line in f:lines() do + vars = helper.splitbywhitespace(line) + + if vars[1] ~= 'Filesystem' and #vars == 6 then + vars[5] = vars[5]:gsub('%%','') + + if padding then + if type(padding) == "table" then + vars[2] = helper.padd(vars[2], padding[1]) + vars[3] = helper.padd(vars[3], padding[2]) + vars[4] = helper.padd(vars[4], padding[3]) + vars[5] = helper.padd(vars[5], padding[4]) + else + vars[2] = helper.padd(vars[2], padding) + vars[3] = helper.padd(vars[3], padding) + vars[4] = helper.padd(vars[4], padding) + vars[5] = helper.padd(vars[5], padding) + end + end + + args['{'..vars[6]..' size}'] = vars[2] + args['{'..vars[6]..' used}'] = vars[3] + args['{'..vars[6]..' avail}'] = vars[4] + args['{'..vars[6]..' usep}'] = vars[5] + end + end + + f:close() + return args +end +-- }}} + +---- {{{ Net widget type +function widgets.net(format, padding) + local f = io.open('/proc/net/dev') + args = {} + + for line in f:lines() do + line = helper.splitbywhitespace(line) + + local p = line[1]:find(':') + if p ~= nil then + name = line[1]:sub(0,p-1) + line[1] = line[1]:sub(p+1) + + if tonumber(line[1]) == nil then + line[1] = line[2] + line[9] = line[10] + end + + if padding then + args['{'..name..' rx}'] = helper.bytes_to_string(line[1], nil, padding) + args['{'..name..' tx}'] = helper.bytes_to_string(line[9], nil, padding) + else + args['{'..name..' rx}'] = helper.bytes_to_string(line[1]) + args['{'..name..' tx}'] = helper.bytes_to_string(line[9]) + end + + args['{'..name..' rx_b}'] = math.floor(line[1]*10)/10 + args['{'..name..' tx_b}'] = math.floor(line[9]*10)/10 + + args['{'..name..' rx_kb}'] = math.floor(line[1]/1024*10)/10 + args['{'..name..' tx_kb}'] = math.floor(line[9]/1024*10)/10 + + args['{'..name..' rx_mb}'] = math.floor(line[1]/1024/1024*10)/10 + args['{'..name..' tx_mb}'] = math.floor(line[9]/1024/1024*10)/10 + + args['{'..name..' rx_gb}'] = math.floor(line[1]/1024/1024/1024*10)/10 + args['{'..name..' tx_gb}'] = math.floor(line[9]/1024/1024/1024*10)/10 + + if nets[name] == nil then + nets[name] = {} + args['{'..name..' down}'] = 'n/a' + args['{'..name..' up}'] = 'n/a' + + args['{'..name..' down_b}'] = 0 + args['{'..name..' up_b}'] = 0 + + args['{'..name..' down_kb}'] = 0 + args['{'..name..' up_kb}'] = 0 + + args['{'..name..' down_mb}'] = 0 + args['{'..name..' up_mb}'] = 0 + + args['{'..name..' down_gb}'] = 0 + args['{'..name..' up_gb}'] = 0 + + nets[name].time = os.time() + else + interval = os.time()-nets[name].time + nets[name].time = os.time() + + down = (line[1]-nets[name][1])/interval + up = (line[9]-nets[name][2])/interval + + if padding then + args['{'..name..' down}'] = helper.bytes_to_string(down, true, padding) + args['{'..name..' up}'] = helper.bytes_to_string(up, true, padding) + else + args['{'..name..' down}'] = helper.bytes_to_string(down, true) + args['{'..name..' up}'] = helper.bytes_to_string(up, true) + end + + args['{'..name..' down_b}'] = math.floor(down*10)/10 + args['{'..name..' up_b}'] = math.floor(up*10)/10 + + args['{'..name..' down_kb}'] = math.floor(down/1024*10)/10 + args['{'..name..' up_kb}'] = math.floor(up/1024*10)/10 + + args['{'..name..' down_mb}'] = math.floor(down/1024/1024*10)/10 + args['{'..name..' up_mb}'] = math.floor(up/1024/1024*10)/10 + + args['{'..name..' down_gb}'] = math.floor(down/1024/1024/1024*10)/10 + args['{'..name..' up_gb}'] = math.floor(up/1024/1024/1024*10)/10 + end + + nets[name][1] = line[1] + nets[name][2] = line[9] + end + end + + f:close() + return args +end +widget_cache[widgets.net] = {} +-- }}} + +---- {{{ Uptime widget type +function widgets.uptime(format, padding) + --Get uptime from /proc/uptime + local f = io.open("/proc/uptime") + uptime_line = f:read() + + f:close() + + args = {} + --/proc/uptime has the format " " + if uptime_line:find(" ") ~= nil then + + pend = uptime_line:find(" ",0,true) + + uptime_line_part = uptime_line:sub(0,pend-1) + + total_uptime = math.floor( tonumber(uptime_line_part) ) + + uptime_days = math.floor( total_uptime / (3600 * 24) ) + uptime_hours = math.floor( ( total_uptime % (3600 * 24) ) / 3600 ) + uptime_minutes = math.floor( ( ( total_uptime % (3600 * 24) ) % 3600 ) / 60 ) + uptime_seconds = math.floor( ( ( total_uptime % (3600 * 24) ) % 3600) % 60 ) + + if padding then + + if type(padding) == "table" then + total_uptime = helper.padd(total_uptime , padding[1]) + uptime_days = helper.padd(uptime_days , padding[2]) + uptime_hours = helper.padd(uptime_hours , padding[3]) + uptime_minutes = helper.padd(uptime_minutes , padding[4]) + uptime_seconds = helper.padd(uptime_seconds , padding[5]) + else + total_uptime = helper.padd(total_uptime , padding) + uptime_days = helper.padd(uptime_days , padding) + uptime_hours = helper.padd(uptime_hours , padding) + uptime_minutes = helper.padd(uptime_minutes , padding) + uptime_seconds = helper.padd(uptime_seconds , padding) + end + + end + end + + return {total_uptime, uptime_days, uptime_hours, uptime_minutes, uptime_seconds} + +end +widget_cache[widgets.uptime] = {} +-- }}} + +-- For backwards compatibility: custom function +widgets["function"] = function () + return {} +end + +-- }}} + +---- {{{ Main functions +---- {{{ Register widget +function register(widget, wtype, format, timer, field, padd) + local reg = {} + local widget = widget + + -- Set properties + reg.type = wtype + reg.format = format + reg.timer = timer + reg.field = field + reg.padd = padd + reg.widget = widget + + -- Update function + reg.update = function () + update(widget, reg) + end + + -- Default to timer=1 + if reg.timer == nil then + reg.timer = 1 + end + + -- Allow using a string widget type + if type(reg.type) == "string" then + reg.type = widgets[reg.type] + end + + -- Register reg object + regregister(reg) + + -- Return reg object for reuse + return reg +end +-- }}} + +-- {{{ Register from reg object +function regregister(reg) + if not reg.running then + -- Put widget in table + if registered[reg.widget] == nil then + registered[reg.widget] = {} + table.insert(registered[reg.widget], reg) + else + already = false + + for w, i in pairs(registered) do + if w == reg.widget then + for k,v in pairs(i) do + if v == reg then + already = true + break + end + end + + if already then + break + end + end + end + + if not already then + table.insert(registered[reg.widget], reg) + end + end + + -- Start timer + if reg.timer > 0 then + awful.hooks.timer.register(reg.timer, reg.update) + end + + -- Initial update + reg.update() + + -- Set running + reg.running = true + end +end +-- }}} + +-- {{{ Unregister widget +function unregister(widget, keep, reg) + if reg == nil then + for w, i in pairs(registered) do + if w == widget then + for k,v in pairs(i) do + reg = unregister(w, keep, v) + end + end + end + + return reg + end + + if not keep then + for w, i in pairs(registered) do + if w == widget then + for k,v in pairs(i) do + if v == reg then + table.remove(registered[w], k) + end + end + end + end + end + + awful.hooks.timer.unregister(reg.update) + + reg.running = false + return reg +end +-- }}} + +-- {{{ Suspend wicked, halt all widget updates +function suspend() + for w, i in pairs(registered) do + for k,v in pairs(i) do + unregister(w, true, v) + end + end +end +-- }}} + +-- {{{ Activate wicked, restart all widget updates +function activate(widget) + for w, i in pairs(registered) do + if widget == nil or w == widget then + for k,v in pairs(i) do + regregister(v) + end + end + end +end +-- }}} + +-- {{{ Enable caching for a widget type +function enable_caching(widget) + if widget_cache[widget] == nil then + widget_cache[widget] = {} + end +end +-- }}} + +---- {{{ Update widget +function update(widget, reg, disablecache) + -- Check if there are any equal widgets + if reg == nil then + for w, i in pairs(registered) do + if w == widget then + for k,v in pairs(i) do + update(w, v, disablecache) + end + end + end + + return + end + + local t = os.time() + local data = {} + + -- Check if we have output chached for this widget, + -- newer than last widget update. + if widget_cache[reg.type] ~= nil then + local c = widget_cache[reg.type] + + if c.time == nil or c.time <= t-reg.timer or disablecache then + c.time = t + c.data = reg.type(reg.format, reg.padd) + end + + data = c.data + else + data = reg.type(reg.format, reg.padd) + end + + if type(data) == "table" then + if type(reg.format) == "string" then + data = helper.format(reg.format, data) + elseif type(reg.format) == "function" then + data = reg.format(widget, data) + end + end + + if reg.field == nil then + widget.text = data + elseif widget.plot_data_add ~= nil then + widget:plot_data_add(reg.field, tonumber(data)) + elseif widget.bar_data_add ~= nil then + widget:bar_data_add(reg.field, tonumber(data)) + end + return data +end + +-- }}} + +-- }}} + +-- vim: set filetype=lua fdm=marker tabstop=4 shiftwidth=4 nu: diff --git a/zenburn.lua b/zenburn.lua new file mode 100644 index 0000000..ad1979f --- /dev/null +++ b/zenburn.lua @@ -0,0 +1,141 @@ +------------------------------- +-- "Zenburn" awesome theme -- +-- By Adrian C. (anrxc) -- +------------------------------- + + +-- {{{ Main +theme = {} +theme.confdir = awful.util.getdir("config") +theme.wallpaper_cmd = { "/usr/bin/nitrogen --restore" } +--theme.wallpaper_cmd = { "awsetbg /usr/share/awesome/themes/zenburn/zenburn-background.png" } +-- }}} + + +-- {{{ Styles +theme.font = "Profont 8" + +-- {{{ Colors +theme.fg_normal = "#DCDCCC" +theme.fg_focus = "#F0DFAF" +theme.fg_urgent = "#CC9393" +theme.bg_normal = "#3F3F3F" +theme.bg_focus = "#1E2320" +theme.bg_urgent = "#3F3F3F" +-- }}} + +-- {{{ Borders +theme.border_width = "1" +theme.border_normal = "#3F3F3F" +theme.border_focus = "#6F6F6F" +theme.border_marked = "#CC9393" +-- }}} + +-- {{{ Titlebars +theme.titlebar_bg_focus = "#3F3F3F" +theme.titlebar_bg_normal = "#3F3F3F" +-- theme.titlebar_[normal|focus] +-- }}} + +-- {{{ Widgets +theme.fg_widget = "#AECF96" +theme.fg_center_widget = "#88A175" +theme.fg_end_widget = "#FF5656" +theme.fg_off_widget = "#494B4F" +theme.fg_netup_widget = "#7F9F7F" +theme.fg_netdn_widget = "#CC9393" +theme.bg_widget = "#3F3F3F" +theme.border_widget = "#3F3F3F" +-- }}} + +-- {{{ Mouse finder +theme.mouse_finder_color = "#CC9393" +-- theme.mouse_finder_[timeout|animate_timeout|radius|factor] +-- }}} + +-- {{{ Tooltips +-- theme.tooltip_[font|opacity|fg_color|bg_color|border_width|border_color] +-- }}} + +-- {{{ Taglist and Tasklist +-- theme.[taglist|tasklist]_[bg|fg]_[focus|urgent] +-- }}} + +-- {{{ Menu +-- theme.menu_[bg|fg]_[normal|focus] +-- theme.menu_[height|width|border_color|border_width] +-- }}} +-- }}} + + +-- {{{ Icons +-- +-- {{{ Taglist icons +theme.taglist_squares_sel = theme.confdir .. "/icons/taglist/squarefz.png" +theme.taglist_squares_unsel = theme.confdir .. "/icons/taglist/squareza.png" +--theme.taglist_squares_resize = "false" +-- }}} + +-- {{{ Misc icons +--theme.awesome_icon = theme.confdir .. "/icons/awesome.png" +--theme.menu_submenu_icon = "/usr/share/awesome/themes/default/submenu.png" +--theme.tasklist_floating_icon = "/usr/share/awesome/themes/default/tasklist/floatingw.png" +-- }}} + +-- {{{ Layout icons +theme.layout_tile = theme.confdir .. "/icons/layouts/tile.png" +theme.layout_tileleft = theme.confdir .. "/icons/layouts/tileleft.png" +theme.layout_tilebottom = theme.confdir .. "/icons/layouts/tilebottom.png" +theme.layout_tiletop = theme.confdir .. "/icons/layouts/tiletop.png" +theme.layout_fairv = theme.confdir .. "/icons/layouts/fairv.png" +theme.layout_fairh = theme.confdir .. "/icons/layouts/fairh.png" +theme.layout_spiral = theme.confdir .. "/icons/layouts/spiral.png" +theme.layout_dwindle = theme.confdir .. "/icons/layouts/dwindle.png" +theme.layout_max = theme.confdir .. "/icons/layouts/max.png" +theme.layout_fullscreen = theme.confdir .. "/icons/layouts/fullscreen.png" +theme.layout_magnifier = theme.confdir .. "/icons/layouts/magnifier.png" +theme.layout_floating = theme.confdir .. "/icons/layouts/floating.png" +-- }}} + +-- {{{ Widget icons +theme.widget_cpu = theme.confdir .. "/icons/cpu.png" +theme.widget_bat = theme.confdir .. "/icons/bat.png" +theme.widget_mem = theme.confdir .. "/icons/mem.png" +theme.widget_fs = theme.confdir .. "/icons/disk.png" +theme.widget_net = theme.confdir .. "/icons/down.png" +theme.widget_netup = theme.confdir .. "/icons/up.png" +theme.widget_mail = theme.confdir .. "/icons/mail.png" +theme.widget_vol = theme.confdir .. "/icons/vol.png" +theme.widget_org = theme.confdir .. "/icons/cal.png" +theme.widget_date = theme.confdir .. "/icons/time.png" +theme.widget_crypto = theme.confdir .. "/icons/crypto.png" +-- }}} + +-- {{{ Titlebar icons +theme.titlebar_close_button_focus = theme.confdir .. "/icons/titlebar/close_focus.png" +theme.titlebar_close_button_normal = theme.confdir .. "/icons/titlebar/close_normal.png" + +theme.titlebar_ontop_button_focus_active = theme.confdir .. "/icons/titlebar/ontop_focus_active.png" +theme.titlebar_ontop_button_normal_active = theme.confdir .. "/icons/titlebar/ontop_normal_active.png" +theme.titlebar_ontop_button_focus_inactive = theme.confdir .. "/icons/titlebar/ontop_focus_inactive.png" +theme.titlebar_ontop_button_normal_inactive = theme.confdir .. "/icons/titlebar/ontop_normal_inactive.png" + +theme.titlebar_sticky_button_focus_active = theme.confdir .. "/icons/titlebar/sticky_focus_active.png" +theme.titlebar_sticky_button_normal_active = theme.confdir .. "/icons/titlebar/sticky_normal_active.png" +theme.titlebar_sticky_button_focus_inactive = theme.confdir .. "/icons/titlebar/sticky_focus_inactive.png" +theme.titlebar_sticky_button_normal_inactive = theme.confdir .. "/icons/titlebar/sticky_normal_inactive.png" + +theme.titlebar_floating_button_focus_active = theme.confdir .. "/icons/titlebar/floating_focus_active.png" +theme.titlebar_floating_button_normal_active = theme.confdir .. "/icons/titlebar/floating_normal_active.png" +theme.titlebar_floating_button_focus_inactive = theme.confdir .. "/icons/titlebar/floating_focus_inactive.png" +theme.titlebar_floating_button_normal_inactive = theme.confdir .. "/icons/titlebar/floating_normal_inactive.png" + +theme.titlebar_maximized_button_focus_active = theme.confdir .. "/icons/titlebar/maximized_focus_active.png" +theme.titlebar_maximized_button_normal_active = theme.confdir .. "/icons/titlebar/maximized_normal_active.png" +theme.titlebar_maximized_button_focus_inactive = theme.confdir .. "/icons/titlebar/maximized_focus_inactive.png" +theme.titlebar_maximized_button_normal_inactive = theme.confdir .. "/icons/titlebar/maximized_normal_inactive.png" +-- }}} +-- }}} + + +return theme