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:

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