madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

font experiments
[etc/awesome.git] / .config / awesome / rc.lua
1 -- {{{ Imports
2 -- Standard awesome library
3 local gears = require("gears")
4 local awful = require("awful")
5 require("awful.autofocus")
6 -- Widget and layout library
7 local wibox = require("wibox")
8 -- Theme handling library
9 local beautiful = require("beautiful")
10 local xrdb = beautiful.xresources
11 -- Notification library
12 local naughty = require("naughty")
13 local menubar = require("menubar")
14 local hotkeys_popup = require("awful.hotkeys_popup").widget
15 local lain = require("lain")
16 local dkjson = require("lain.util").dkjson
17 local math = require("math")
18 local freedesktop = require("freedesktop")
19 local luatz = require("luatz")
20 -- }}}
21
22 -- {{{ Error handling
23 -- Check if awesome encountered an error during startup and fell back to
24 -- another config (This code will only ever execute for the fallback config)
25 if awesome.startup_errors then
26     naughty.notify({ preset = naughty.config.presets.critical,
27                      title = "Oops, there were errors during startup!",
28                      text = awesome.startup_errors })
29 end
30
31 -- Handle runtime errors after startup
32 do
33     local in_error = false
34     awesome.connect_signal("debug::error", function (err)
35         -- Make sure we don't go into an endless error loop
36         if in_error then return end
37         in_error = true
38
39         naughty.notify({ preset = naughty.config.presets.critical,
40                          title = "Oops, an error happened!",
41                          text = tostring(err) })
42         in_error = false
43     end)
44 end
45 -- }}}
46
47 -- {{{ Variable definitions
48 --xrdb.set_dpi(95, screen[1])
49 --xrdb.set_dpi(120, screen[2])
50
51 -- Themes define colours, icons, and wallpapers
52 beautiful.init(awful.util.get_themes_dir() .. "default/theme.lua")
53 beautiful.font = 'Sans 10'
54
55 -- This is used later as the default terminal and editor to run.
56 terminal = "x-terminal-emulator"
57 editor = "sensible-editor"
58 editor_cmd = terminal .. " -e " .. editor
59
60 -- Default modkey.
61 -- Usually, Mod4 is the key with a logo between Control and Alt.
62 -- If you do not like this or do not have such a key,
63 -- I suggest you to remap Mod4 to another key using xmodmap or other tools.
64 -- However, you can use another modifier like Mod1, but it may interact with others.
65 modkey = "Mod4"
66 cmdkey = "Mod3"
67
68 -- Table of layouts to cover with awful.layout.inc, order matters.
69 awful.layout.layouts = {
70     awful.layout.suit.fair,
71     awful.layout.suit.tile,
72     -- awful.layout.suit.tile.left,
73     -- awful.layout.suit.tile.bottom,
74     awful.layout.suit.tile.top,
75     -- awful.layout.suit.spiral,
76     -- awful.layout.suit.spiral.dwindle,
77     awful.layout.suit.max,
78     -- awful.layout.suit.max.fullscreen,
79     -- awful.layout.suit.magnifier,
80     -- awful.layout.suit.corner.nw,
81     -- awful.layout.suit.corner.ne,
82     -- awful.layout.suit.corner.sw,
83     -- awful.layout.suit.corner.se,
84     awful.layout.suit.floating,
85 }
86
87 layout_default = awful.layout.layouts[1]
88 layout_tiled = awful.layout.layouts[2]
89 layout_maximised = awful.layout.layouts[4]
90 layout_floating = awful.layout.layouts[5]
91 -- }}}
92
93 -- {{{ Helper functions
94 local function client_menu_toggle_fn()
95     local instance = nil
96
97     return function ()
98         if instance and instance.wibox.visible then
99             instance:hide()
100             instance = nil
101         else
102             instance = awful.menu.clients({ theme = { width = 250 } })
103         end
104     end
105 end
106
107 local function sorted_pairs(t, f)
108     local a = {}
109     for n in pairs(t) do table.insert(a, n) end
110     table.sort(a, f)
111     local i = 0      -- iterator variable
112     local iter = function ()   -- iterator function
113         i = i + 1
114         if a[i] == nil then return nil
115         else return a[i], t[a[i]]
116         end
117     end
118     return iter
119 end
120
121 local function print_table(tbl, indent)
122     if not indent then indent = 0 end
123     for k, v in pairs(tbl) do
124         formatting = string.rep("  ", indent) .. k .. ": "
125         if type(v) == "table" then
126             print(formatting)
127             print_table(v, indent+1)
128         else
129             print(formatting .. tostring(v))
130         end
131     end
132 end
133
134 local lain_bat = lain.widget.bat({
135     batteries = {"BAT0", "BAT1"},
136     settings = function()
137         local delim = "↓"
138         if bat_now.status == "Charging" then delim = "↑"
139         elseif bat_now.status == "Unknown" then delim = "٭" end
140         widget:set_text(bat_now.perc .. "% " .. delim .. " " .. bat_now.time)
141     end,
142 })
143
144 local function poloniex_price(output, pair, prec)
145     local xc, pos, err = dkjson.decode(output, 1, nil)
146     if not prec then prec = 4 end
147     val = (xc and xc[pair]["last"]) or 0
148     val = math.floor(val*10^prec+0.5)/10^prec
149     return (not err and val) or "n/a"
150 end
151
152 local eth_widget = lain.widget.watch({
153     cmd = "curl -m5 -s 'https://poloniex.com/public?command=returnTicker'",
154     timeout = 600,
155     settings = function()
156         widget:set_text(poloniex_price(output, 'BTC_ETH') .. " Ƀ/Ξ")
157     end
158 })
159
160 local function coindesk_price(output, base, prec)
161     local xc, pos, err = dkjson.decode(output, 1, nil)
162     if not prec then prec = 4 end
163     val = (xc and xc["bpi"][base]["rate_float"]) or 0
164     val = math.floor(val*10^prec+0.5)/10^prec
165     return (not err and val) or "n/a"
166 end
167
168 local btc_widget = lain.widget.watch({
169     cmd = "curl -m5 -Ls 'https://api.coindesk.com/v1/bpi/currentprice/EUR.json'",
170     timeout = 600,
171     settings = function()
172         widget:set_text(coindesk_price(output, "EUR", 2) .. " €/Ƀ")
173     end
174 })
175
176 -- }}}
177
178 -- {{{ Menu
179 -- Create a launcher widget and a main menu
180 myawesomemenu = {
181    { "hotkeys", function() return false, hotkeys_popup.show_help end},
182    { "manual", terminal .. " -e man awesome" },
183    { "edit config", editor_cmd .. " " .. awesome.conffile },
184    { "restart", awesome.restart },
185    { "quit", awesome.quit }
186 }
187
188 mymainmenu = freedesktop.menu.build({
189     before = {
190         { "awesome", myawesomemenu, beautiful.awesome_icon },
191         { "terminal", terminal },
192     },
193     after = {
194     }
195 })
196
197 mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
198                                      menu = mymainmenu })
199 -- }}}
200
201 -- {{{ Menubar configuration
202 menubar.utils.terminal = terminal -- Set the terminal for applications that require it
203 -- }}}
204
205 -- {{{ Wibox
206 local spacer = wibox.widget.textbox()
207 spacer:set_text(' │ ')
208 -- Create a textclock widget
209 clocks = { wibox.widget.textclock("%a %d %b %H:%M:%S %Z", 1) }
210
211 ZONES = {
212   ["NZ"] = "Pacific/Auckland",
213   ["DE"] = "Europe/Berlin"
214 }
215 local now = luatz.time_in(nil)
216 for c, tz in sorted_pairs(ZONES) do
217     local t = luatz.time_in(tz)
218     if math.abs(os.difftime(t, now)) > 10 then
219         local widget = wibox.widget.textclock(c .. ": %H:%M (%a)", 60, tz)
220         table.insert(clocks, 1, spacer)
221         table.insert(clocks, 1, widget)
222     end
223 end
224
225 -- Create a wibox for each screen and add it
226 mywibox = {}
227 mypromptbox = {}
228 mylayoutbox = {}
229 mytaglist = {}
230 mytaglist.buttons = awful.util.table.join(
231                     awful.button({ }, 1, function(t) t:view_only() end),
232                     awful.button({ modkey }, 1, function(t)
233                                               if client.focus then
234                                                   client.focus:move_to_tag(t)
235                                               end
236                                           end),
237                     awful.button({ }, 3, awful.tag.viewtoggle),
238                     awful.button({ modkey }, 3, function(t)
239                                               if client.focus then
240                                                   client.focus:toggle_tag(t)
241                                               end
242                                           end),
243                     awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
244                     awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
245                 )
246
247 mytasklist = {}
248 mytasklist.buttons = awful.util.table.join(
249                      awful.button({ }, 1, function (c)
250                                               if c == client.focus then
251                                                   -- I don't like click-minimising
252                                                   -- c.minimized = true
253                                               else
254                                                   -- Without this, the following
255                                                   -- :isvisible() makes no sense
256                                                   c.minimized = false
257                                                   if not c:isvisible() and c.first_tag then
258                                                       c.first_tag:view_only()
259                                                   end
260                                                   -- This will also un-minimize
261                                                   -- the client, if needed
262                                                   client.focus = c
263                                                   c:raise()
264                                               end
265                                           end),
266                      awful.button({ }, 3, client_menu_toggle_fn()),
267                      awful.button({ }, 4, function ()
268                                               awful.client.focus.byidx(1)
269                                           end),
270                      awful.button({ }, 5, function ()
271                                               awful.client.focus.byidx(-1)
272                                           end))
273 -- }}}
274
275 -- {{{ Tags
276 tags = {}
277 tags.config = {}
278 tags.config["main"] = {
279     t1 = { layout = layout_default, selected = true },
280     t2 = { layout = layout_default },
281     t3 = { layout = layout_tiled },
282     t4 = { layout = layout_tiled },
283     t5 = { layout = layout_tiled },
284     t6 = { layout = layout_floating },
285     t7 = { layout = layout_maximised },
286     t8 = { layout = layout_maximised },
287     t9 = { layout = layout_maximised },
288 }
289 tags.config["aux"] = {
290     t1 = { layout = layout_default, selected = true },
291     t2 = { layout = layout_default },
292     t3 = { layout = layout_tiled },
293     t4 = { layout = layout_floating },
294     t5 = { layout = layout_floating },
295     t6 = { layout = layout_floating },
296     t7 = { layout = layout_floating },
297     t8 = { layout = layout_floating },
298     t9 = { layout = layout_maximised },
299 }
300
301 screentags = {}
302 screentags[1] = tags.config["main"]
303 if screen.count() == 2 then -- aux screen is on the right
304   screentags[2] = tags.config["aux"]
305 elseif screen.count() == 3 then -- main screen is still #1 in the middle
306   screentags[2] = tags.config["aux"]
307   screentags[3] = tags.config["aux"]
308 end
309
310 awful.screen.connect_for_each_screen(function(s)
311     -- local fontsize = math.floor(250 * xrdb.get_dpi(s)/s.geometry.width)
312     -- beautiful.font = "Sans " .. tostring(fontsize)
313     -- Wallpaper
314     --DISABLED--if beautiful.wallpaper then
315     --DISABLED--    local wallpaper = beautiful.wallpaper
316     --DISABLED--    -- If wallpaper is a function, call it with the screen
317     --DISABLED--    if type(wallpaper) == "function" then
318     --DISABLED--        wallpaper = wallpaper(s)
319     --DISABLED--    end
320     --DISABLED--    gears.wallpaper.maximized(wallpaper, s, true)
321     --DISABLED--end
322
323     if not tags[s.index] then
324         tags[s.index] = {}
325     end
326     for n,p in sorted_pairs(screentags[s.index]) do
327         p["screen"] = s
328         n = string.sub(n, 2) -- remove leading 't' needed for syntax in table
329         table.insert(tags[s.index], awful.tag.add(n, p))
330     end
331
332     -- Create a promptbox for each screen
333     mypromptbox[s] = awful.widget.prompt()
334     -- Create an imagebox widget which will contains an icon indicating which layout we're using.
335     -- We need one layoutbox per screen.
336     mylayoutbox[s] = awful.widget.layoutbox(s)
337     mylayoutbox[s]:buttons(awful.util.table.join(
338                            awful.button({ }, 1, function () awful.layout.inc( 1) end),
339                            awful.button({ }, 3, function () awful.layout.inc(-1) end),
340                            awful.button({ }, 4, function () awful.layout.inc( 1) end),
341                            awful.button({ }, 5, function () awful.layout.inc(-1) end)))
342     -- Create a taglist widget
343     mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.filter.all, mytaglist.buttons)
344
345     -- Create a tasklist widget
346     mytasklist[s] = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, mytasklist.buttons)
347
348     -- Create the wibox
349     mywibox[s] = awful.wibar({ position = "top", screen = s })
350
351     -- Add widgets to the wibox
352     mywibox[s]:setup {
353         layout = wibox.layout.align.horizontal,
354         { -- Left widgets
355             layout = wibox.layout.fixed.horizontal,
356             -- mylauncher,
357             mytaglist[s],
358             mypromptbox[s],
359         },
360         mytasklist[s], -- Middle widget
361         awful.util.table.join( -- Right widgets
362             {
363                 layout = wibox.layout.fixed.horizontal,
364                 mykeyboardlayout,
365                 wibox.widget.systray(),
366                 btc_widget,
367                 spacer,
368                 lain_bat.widget,
369                 spacer,
370             },
371             clocks,
372             {
373                 mylayoutbox[s],
374             }
375         ),
376     }
377 end)
378 -- }}}
379
380 -- {{{ Mouse bindings
381 root.buttons(awful.util.table.join(
382     awful.button({ }, 3, function () mymainmenu:toggle() end),
383     awful.button({ }, 4, awful.tag.viewnext),
384     awful.button({ }, 5, awful.tag.viewprev)
385 ))
386 -- }}}
387
388 -- {{{ Key bindings
389 globalkeys = awful.util.table.join(
390     awful.key({ modkey,           }, "s",      hotkeys_popup.show_help,
391               {description="show help", group="awesome"}),
392     awful.key({ modkey,           }, "Left",   awful.tag.viewprev,
393               {description = "view previous", group = "tag"}),
394     awful.key({ modkey,           }, "Right",  awful.tag.viewnext,
395               {description = "view next", group = "tag"}),
396     awful.key({ modkey,           }, "Escape", awful.tag.history.restore,
397               {description = "go back", group = "tag"}),
398
399     awful.key({ modkey,           }, "k",
400         function ()
401             awful.client.focus.byidx( 1)
402         end,
403         {description = "focus next by index", group = "client"}
404     ),
405     awful.key({ modkey,           }, "j",
406         function ()
407             awful.client.focus.byidx(-1)
408         end,
409         {description = "focus previous by index", group = "client"}
410     ),
411     awful.key({ modkey,           }, "w", function () mymainmenu:show() end,
412               {description = "show main menu", group = "awesome"}),
413
414     -- Layout manipulation
415     awful.key({ modkey, "Shift"   }, "k", function () awful.client.swap.byidx(  1)    end,
416               {description = "swap with next client by index", group = "client"}),
417     awful.key({ modkey, "Shift"   }, "j", function () awful.client.swap.byidx( -1)    end,
418               {description = "swap with previous client by index", group = "client"}),
419     awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative( 1) end,
420               {description = "focus the next screen", group = "screen"}),
421     awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative(-1) end,
422               {description = "focus the previous screen", group = "screen"}),
423     awful.key({ modkey,           }, "u", awful.client.urgent.jumpto,
424               {description = "jump to urgent client", group = "client"}),
425     awful.key({ modkey,           }, "Tab",
426         function ()
427             awful.client.focus.history.previous()
428             if client.focus then
429                 client.focus:raise()
430             end
431         end,
432         {description = "go back", group = "client"}),
433
434     -- Standard program
435     awful.key({ modkey,           }, "Return", function () awful.spawn(terminal) end,
436               {description = "open a terminal", group = "launcher"}),
437     awful.key({ modkey, "Control" }, "r", awesome.restart,
438               {description = "reload awesome", group = "awesome"}),
439     awful.key({ modkey, "Shift"   }, "q", awesome.quit,
440               {description = "quit awesome", group = "awesome"}),
441
442     awful.key({ modkey,           }, "l",     function () awful.tag.incmwfact( 0.05)          end,
443               {description = "increase master width factor", group = "layout"}),
444     awful.key({ modkey,           }, "h",     function () awful.tag.incmwfact(-0.05)          end,
445               {description = "decrease master width factor", group = "layout"}),
446     awful.key({ modkey, "Shift"   }, "h",     function () awful.tag.incnmaster( 1, nil, true) end,
447               {description = "increase the number of master clients", group = "layout"}),
448     awful.key({ modkey, "Shift"   }, "l",     function () awful.tag.incnmaster(-1, nil, true) end,
449               {description = "decrease the number of master clients", group = "layout"}),
450     awful.key({ modkey, "Control" }, "h",     function () awful.tag.incncol( 1, nil, true)    end,
451               {description = "increase the number of columns", group = "layout"}),
452     awful.key({ modkey, "Control" }, "l",     function () awful.tag.incncol(-1, nil, true)    end,
453               {description = "decrease the number of columns", group = "layout"}),
454     awful.key({ modkey,           }, "space", function () awful.layout.inc( 1)                end,
455               {description = "select next", group = "layout"}),
456     awful.key({ modkey, "Shift"   }, "space", function () awful.layout.inc(-1)                end,
457               {description = "select previous", group = "layout"}),
458
459     awful.key({ modkey, "Control" }, "n",
460               function ()
461                   local c = awful.client.restore()
462                   -- Focus restored client
463                   if c then
464                       client.focus = c
465                       c:raise()
466                   end
467               end,
468               {description = "restore minimized", group = "client"}),
469
470     -- Prompt
471     awful.key({ modkey },            "r",     function () mypromptbox[awful.screen.focused()]:run() end,
472               {description = "run prompt", group = "launcher"}),
473
474     awful.key({ modkey }, "x",
475               function ()
476                   awful.prompt.run({ prompt = "Run Lua code: " },
477                   mypromptbox[awful.screen.focused()].widget,
478                   awful.util.eval, nil,
479                   awful.util.get_cache_dir() .. "/history_eval")
480               end,
481               {description = "lua execute prompt", group = "awesome"}),
482     -- Menubar
483     awful.key({ modkey }, "p", function() menubar.show() end,
484               {description = "show the menubar", group = "launcher"})
485 )
486
487 clientkeys = awful.util.table.join(
488     awful.key({ modkey,           }, "f",
489         function (c)
490             c.fullscreen = not c.fullscreen
491             c:raise()
492         end,
493         {description = "toggle fullscreen", group = "client"}),
494     awful.key({ modkey, "Shift"   }, "c",      function (c) c:kill()                         end,
495               {description = "close", group = "client"}),
496     awful.key({ modkey, "Control" }, "space",  awful.client.floating.toggle                     ,
497               {description = "toggle floating", group = "client"}),
498     awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
499               {description = "move to master", group = "client"}),
500     awful.key({ modkey,           }, "o",      function (c) c:move_to_screen()               end,
501               {description = "move to screen", group = "client"}),
502     awful.key({ modkey,           }, "t",      function (c) c.ontop = not c.ontop            end,
503               {description = "toggle keep on top", group = "client"}),
504     awful.key({ modkey,           }, "n",
505         function (c)
506             -- The client currently has the input focus, so it cannot be
507             -- minimized, since minimized clients can't have the focus.
508             c.minimized = true
509         end ,
510         {description = "minimize", group = "client"}),
511     awful.key({ modkey,           }, "m",
512         function (c)
513             c.maximized = not c.maximized
514             c.maximized_horizontal = false
515             c.maximized_vertical = false
516             c:raise()
517         end ,
518         {description = "maximize", group = "client"})
519 )
520
521 -- Bind all key numbers to tags.
522 -- Be careful: we use keycodes to make it works on any keyboard layout.
523 -- This should map on the top row of your keyboard, usually 1 to 9.
524 for i = 1, 9 do
525     globalkeys = awful.util.table.join(globalkeys,
526         -- View tag only.
527         awful.key({ modkey }, "#" .. i + 9,
528                   function ()
529                         local screen = awful.screen.focused()
530                         local tag = screen.tags[i]
531                         if tag then
532                            tag:view_only()
533                         end
534                   end,
535                   {description = "view tag #"..i, group = "tag"}),
536         -- Toggle tag.
537         awful.key({ modkey, "Control" }, "#" .. i + 9,
538                   function ()
539                       local screen = awful.screen.focused()
540                       local tag = screen.tags[i]
541                       if tag then
542                          awful.tag.viewtoggle(tag)
543                       end
544                   end,
545                   {description = "toggle tag #" .. i, group = "tag"}),
546         -- Move client to tag.
547         awful.key({ modkey, "Shift" }, "#" .. i + 9,
548                   function ()
549                       if client.focus then
550                           local tag = client.focus.screen.tags[i]
551                           if tag then
552                               client.focus:move_to_tag(tag)
553                           end
554                      end
555                   end,
556                   {description = "move focused client to tag #"..i, group = "tag"}),
557         -- Toggle tag on focused client.
558         awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
559                   function ()
560                       if client.focus then
561                           local tag = client.focus.screen.tags[i]
562                           if tag then
563                               client.focus:toggle_tag(tag)
564                           end
565                       end
566                   end,
567                   {description = "toggle focused client on tag #" .. i, group = "tag"})
568     )
569 end
570
571 clientbuttons = awful.util.table.join(
572     awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
573     awful.button({ modkey }, 1, awful.mouse.client.move),
574     awful.button({ modkey }, 3, awful.mouse.client.resize))
575
576 -- misc apps
577 globalkeys = awful.util.table.join(globalkeys,
578 awful.key({ cmdkey }, "n", function () awful.spawn("firefox") end),
579 awful.key({ cmdkey }, "m", function () awful.spawn("chromium --enable-remote-extensions") end),
580 awful.key({ cmdkey }, "y", function () awful.spawn(terminal .. " -e python") end),
581 awful.key({ cmdkey }, "c", function () awful.spawn("thunderbird") end),
582 awful.key({ cmdkey }, "r", function () mypromptbox[mouse.screen]:run() end),
583 awful.key({ cmdkey }, "g", function () awful.spawn("gscan2pdf") end),
584 awful.key({ cmdkey }, "v", function () awful.spawn("virt-manager") end),
585 awful.key({ cmdkey }, "l", function () awful.spawn("libreoffice") end),
586 awful.key({ cmdkey }, "f", function () awful.spawn("thunar") end),
587 awful.key({ cmdkey }, "i", function () awful.spawn(terminal .. " -name irc -e env MOSH_TITLE_NOPREFIX=true mosh -4 -- irc-host tmux new -As irc irssi") end),
588 awful.key({ cmdkey }, "x", function () awful.spawn.with_shell("/sbin/start-stop-daemon --start --background --exec /usr/bin/xscreensaver -- -no-capture-stderr; sleep 2; xscreensaver-command -lock") end),
589 awful.key({ cmdkey, "Shift" }, "x", function () awful.spawn("xscreensaver-command -exit") end),
590
591 -- function keys
592 awful.key(nil, "XF86ScreenSaver", function () awful.spawn("xset dpms force off") end),
593 awful.key(nil, "XF86AudioMute", function () awful.spawn("pactl set-sink-mute 0 toggle") end),
594 awful.key({ cmdkey }, "End", function () awful.spawn("pactl set-sink-mute 0 toggle") end),
595 awful.key(nil, "XF86AudioLowerVolume", function () awful.spawn("pactl set-sink-volume 0 -2%") end),
596 awful.key({ cmdkey }, "Next", function () awful.spawn("pactl set-sink-volume 0 -2%") end),
597 awful.key(nil, "XF86AudioRaiseVolume", function () awful.spawn("pactl set-sink-volume 0 +2%") end),
598 awful.key({ cmdkey }, "Prior", function () awful.spawn("pactl set-sink-volume 0 +2%") end),
599 awful.key(nil, "XF86AudioMicMute", function () awful.spawn("pactl set-source-mute 1 toggle") end),
600 awful.key({ cmdkey }, "Home", function () awful.spawn("pactl set-source-mute 1 toggle") end),
601 awful.key(nil, "XF86MonBrightnessDown", function () awful.spawn("xbacklight -dec 5%") end),
602 awful.key(nil, "XF86MonBrightnessUp", function () awful.spawn("xbacklight -inc 5%") end),
603 awful.key(nil, "XF86Display", function () awful.spawn("") end),
604 awful.key(nil, "XF86WLAN", function () awful.spawn("") end),
605 awful.key(nil, "XF86Tools", function () awful.spawn("") end),
606 awful.key(nil, "XF86Search", function () awful.spawn("") end),
607 awful.key(nil, "XF86LaunchA", function () awful.spawn("") end),
608 awful.key(nil, "XF86Explorer", function () awful.spawn("") end)
609 )
610
611 -- Set keys
612 root.keys(globalkeys)
613 -- }}}
614
615 -- {{{ Rules
616 -- Rules to apply to new clients (through the "manage" signal).
617
618 local function move_to_tag(s, t)
619     return function(c)
620         c:move_to_tag(tags[s][t])
621     end
622 end
623
624 awful.rules.rules = {
625     -- All clients will match this rule.
626     { rule = { },
627       properties = { border_width = beautiful.border_width,
628                      border_color = beautiful.border_normal,
629                      focus = awful.client.focus.filter,
630                      raise = true,
631                      keys = clientkeys,
632                      buttons = clientbuttons,
633                      screen = awful.screen.preferred,
634                      placement = awful.placement.no_overlap+awful.placement.no_offscreen,
635                      floating = false
636                  },
637     },
638
639     -- Add titlebars to normal clients and dialogs
640     --DISABLED-- { rule_any = {type = { "normal", "dialog" }
641     --DISABLED--  }, properties = { titlebars_enabled = true }
642     --DISABLED-- },
643
644     { rule = { type = "dialog" },
645       properties = { floating = true,
646                      placement = awful.placement.centered
647                  }
648     },
649
650     { rule = { class = "URxvt" },
651                properties = {
652                    -- floating = false,
653                    size_hints_honor = false
654                } },
655     { rule = { class = "URxvt", instance = "irc" },
656                properties = {
657                    switchtotag = true
658                },
659                callback = move_to_tag(screen.count(), screen.count() == 1 and 2 or 1)
660            },
661     { rule = { class = "Firefox", instance = "Navigator" },
662                properties = {
663                    floating = false,
664                },
665                callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
666            },
667     { rule = { class = "Firefox-esr", instance = "Navigator" },
668                properties = {
669                    floating = false,
670                },
671                callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
672            },
673     { rule = { class = "Thunderbird", instance = "Mail" },
674                properties = {
675                    floating = false,
676                },
677                callback = move_to_tag(screen.count() == 1 and 1 or 2, 8)
678            },
679     { rule = { class = "Chromium", instance = "chromium" },
680                properties = {
681                    floating = false,
682                },
683                callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
684            },
685     { rule = { class = "Gscan2pdf" },
686                properties = {
687                    switchtotag = true
688                },
689                callback = move_to_tag(1, 5)
690            },
691     { rule = { name = "gscan2pdf .*" },
692                properties = {
693                    floating = false,
694                },
695            },
696     { rule = { class = "Thunar", type = "normal" },
697                properties = {
698                    floating = false,
699                },
700            },
701     { rule = { class = "MuPDF", instance = "mupdf" },
702                properties = {
703                    floating = true,
704                },
705            },
706     { rule = { class = "Pinentry", instance = "pinentry" },
707                properties = {
708                    floating = true,
709                },
710            },
711     { rule = { class = "Gxmessage" },
712                properties = {
713                    floating = true,
714                },
715            },
716 }
717 -- }}}
718
719 -- {{{ Signals
720 -- Signal function to execute when a new client appears.
721 client.connect_signal("manage", function (c)
722     -- Set the windows at the slave,
723     -- i.e. put it at the end of others instead of setting it master.
724     if not awesome.startup then awful.client.setslave(c) end
725
726     if awesome.startup and
727       not c.size_hints.user_position
728       and not c.size_hints.program_position then
729         -- Prevent clients from being unreachable after screen count changes.
730         awful.placement.no_offscreen(c)
731     end
732
733     c.maximized_horizontal = false
734     c.maximized_vertical = false
735 end)
736
737 -- Add a titlebar if titlebars_enabled is set to true in the rules.
738 client.connect_signal("request::titlebars", function(c)
739     -- buttons for the titlebar
740     local buttons = awful.util.table.join(
741         awful.button({ }, 1, function()
742             client.focus = c
743             c:raise()
744             awful.mouse.client.move(c)
745         end),
746         awful.button({ }, 3, function()
747             client.focus = c
748             c:raise()
749             awful.mouse.client.resize(c)
750         end)
751     )
752
753     awful.titlebar(c) : setup {
754         { -- Left
755             awful.titlebar.widget.iconwidget(c),
756             buttons = buttons,
757             layout  = wibox.layout.fixed.horizontal
758         },
759         { -- Middle
760             { -- Title
761                 align  = "center",
762                 widget = awful.titlebar.widget.titlewidget(c)
763             },
764             buttons = buttons,
765             layout  = wibox.layout.flex.horizontal
766         },
767         { -- Right
768             awful.titlebar.widget.floatingbutton (c),
769             awful.titlebar.widget.maximizedbutton(c),
770             awful.titlebar.widget.stickybutton   (c),
771             awful.titlebar.widget.ontopbutton    (c),
772             awful.titlebar.widget.closebutton    (c),
773             layout = wibox.layout.fixed.horizontal()
774         },
775         layout = wibox.layout.align.horizontal
776     }
777 end)
778
779 -- Enable sloppy focus
780 client.connect_signal("mouse::enter", function(c)
781     if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
782         and awful.client.focus.filter(c) then
783         client.focus = c
784     end
785 end)
786
787 client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end)
788 client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
789
790 awful.ewmh.add_activate_filter(function(c, context, hints)
791     if context == "ewmh" and (c.class == "Firefox-esr" or c.class == "Firefox") then return false end
792 end)
793
794 -- vim:ft=lua:sw=4:sts=4:ts=4:et