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:

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