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:

nicer spacer
[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
211 now = luatz.time_in(nil)
212 for c, tz in sorted_pairs(ZONES) do
213     t = luatz.time_in(tz)
214     print (c)
215     print (os.difftime(t, now))
216     if math.abs(os.difftime(t, now)) > 10 then
217         local widget = wibox.widget.textclock(c .. ": %H:%M (%a)", 60, tz)
218         table.insert(clocks, spacer)
219         table.insert(clocks, widget)
220     end
221 end
222
223 -- Create a wibox for each screen and add it
224 mywibox = {}
225 mypromptbox = {}
226 mylayoutbox = {}
227 mytaglist = {}
228 mytaglist.buttons = awful.util.table.join(
229                     awful.button({ }, 1, function(t) t:view_only() end),
230                     awful.button({ modkey }, 1, function(t)
231                                               if client.focus then
232                                                   client.focus:move_to_tag(t)
233                                               end
234                                           end),
235                     awful.button({ }, 3, awful.tag.viewtoggle),
236                     awful.button({ modkey }, 3, function(t)
237                                               if client.focus then
238                                                   client.focus:toggle_tag(t)
239                                               end
240                                           end),
241                     awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
242                     awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
243                 )
244
245 mytasklist = {}
246 mytasklist.buttons = awful.util.table.join(
247                      awful.button({ }, 1, function (c)
248                                               if c == client.focus then
249                                                   -- I don't like click-minimising
250                                                   -- c.minimized = true
251                                               else
252                                                   -- Without this, the following
253                                                   -- :isvisible() makes no sense
254                                                   c.minimized = false
255                                                   if not c:isvisible() and c.first_tag then
256                                                       c.first_tag:view_only()
257                                                   end
258                                                   -- This will also un-minimize
259                                                   -- the client, if needed
260                                                   client.focus = c
261                                                   c:raise()
262                                               end
263                                           end),
264                      awful.button({ }, 3, client_menu_toggle_fn()),
265                      awful.button({ }, 4, function ()
266                                               awful.client.focus.byidx(1)
267                                           end),
268                      awful.button({ }, 5, function ()
269                                               awful.client.focus.byidx(-1)
270                                           end))
271 -- }}}
272
273 -- {{{ Tags
274 tags = {}
275 tags.config = {}
276 tags.config["main"] = {
277     t1 = { layout = layout_default, selected = true },
278     t2 = { layout = layout_default },
279     t3 = { layout = layout_tiled },
280     t4 = { layout = layout_tiled },
281     t5 = { layout = layout_tiled },
282     t6 = { layout = layout_floating },
283     t7 = { layout = layout_maximised },
284     t8 = { layout = layout_maximised },
285     t9 = { layout = layout_maximised },
286 }
287 tags.config["aux"] = {
288     t1 = { layout = layout_default, selected = true },
289     t2 = { layout = layout_default },
290     t3 = { layout = layout_tiled },
291     t4 = { layout = layout_floating },
292     t5 = { layout = layout_floating },
293     t6 = { layout = layout_floating },
294     t7 = { layout = layout_floating },
295     t8 = { layout = layout_floating },
296     t9 = { layout = layout_maximised },
297 }
298
299 screentags = {}
300 screentags[1] = tags.config["main"]
301 if screen.count() == 2 then -- aux screen is on the right
302   screentags[2] = tags.config["aux"]
303 elseif screen.count() == 3 then -- main screen is still #1 in the middle
304   screentags[2] = tags.config["aux"]
305   screentags[3] = tags.config["aux"]
306 end
307
308 awful.screen.connect_for_each_screen(function(s)
309     -- Wallpaper
310     --DISABLED--if beautiful.wallpaper then
311     --DISABLED--    local wallpaper = beautiful.wallpaper
312     --DISABLED--    -- If wallpaper is a function, call it with the screen
313     --DISABLED--    if type(wallpaper) == "function" then
314     --DISABLED--        wallpaper = wallpaper(s)
315     --DISABLED--    end
316     --DISABLED--    gears.wallpaper.maximized(wallpaper, s, true)
317     --DISABLED--end
318
319     if not tags[s.index] then
320         tags[s.index] = {}
321     end
322     for n,p in sorted_pairs(screentags[s.index]) do
323         p["screen"] = s
324         n = string.sub(n, 2) -- remove leading 't' needed for syntax in table
325         table.insert(tags[s.index], awful.tag.add(n, p))
326     end
327
328     -- Create a promptbox for each screen
329     mypromptbox[s] = awful.widget.prompt()
330     -- Create an imagebox widget which will contains an icon indicating which layout we're using.
331     -- We need one layoutbox per screen.
332     mylayoutbox[s] = awful.widget.layoutbox(s)
333     mylayoutbox[s]:buttons(awful.util.table.join(
334                            awful.button({ }, 1, function () awful.layout.inc( 1) end),
335                            awful.button({ }, 3, function () awful.layout.inc(-1) end),
336                            awful.button({ }, 4, function () awful.layout.inc( 1) end),
337                            awful.button({ }, 5, function () awful.layout.inc(-1) end)))
338     -- Create a taglist widget
339     mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.filter.all, mytaglist.buttons)
340
341     -- Create a tasklist widget
342     mytasklist[s] = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, mytasklist.buttons)
343
344     -- Create the wibox
345     mywibox[s] = awful.wibar({ position = "top", screen = s })
346
347     -- Add widgets to the wibox
348     mywibox[s]:setup {
349         layout = wibox.layout.align.horizontal,
350         { -- Left widgets
351             layout = wibox.layout.fixed.horizontal,
352             -- mylauncher,
353             mytaglist[s],
354             mypromptbox[s],
355         },
356         mytasklist[s], -- Middle widget
357         awful.util.table.join( -- Right widgets
358             {
359                 layout = wibox.layout.fixed.horizontal,
360                 mykeyboardlayout,
361                 wibox.widget.systray(),
362                 btc_widget,
363                 spacer,
364                 lain_bat.widget,
365                 spacer,
366             },
367             clocks,
368             {
369                 mylayoutbox[s],
370             }
371         ),
372     }
373 end)
374 -- }}}
375
376 -- {{{ Mouse bindings
377 root.buttons(awful.util.table.join(
378     awful.button({ }, 3, function () mymainmenu:toggle() end),
379     awful.button({ }, 4, awful.tag.viewnext),
380     awful.button({ }, 5, awful.tag.viewprev)
381 ))
382 -- }}}
383
384 -- {{{ Key bindings
385 globalkeys = awful.util.table.join(
386     awful.key({ modkey,           }, "s",      hotkeys_popup.show_help,
387               {description="show help", group="awesome"}),
388     awful.key({ modkey,           }, "Left",   awful.tag.viewprev,
389               {description = "view previous", group = "tag"}),
390     awful.key({ modkey,           }, "Right",  awful.tag.viewnext,
391               {description = "view next", group = "tag"}),
392     awful.key({ modkey,           }, "Escape", awful.tag.history.restore,
393               {description = "go back", group = "tag"}),
394
395     awful.key({ modkey,           }, "k",
396         function ()
397             awful.client.focus.byidx( 1)
398         end,
399         {description = "focus next by index", group = "client"}
400     ),
401     awful.key({ modkey,           }, "j",
402         function ()
403             awful.client.focus.byidx(-1)
404         end,
405         {description = "focus previous by index", group = "client"}
406     ),
407     awful.key({ modkey,           }, "w", function () mymainmenu:show() end,
408               {description = "show main menu", group = "awesome"}),
409
410     -- Layout manipulation
411     awful.key({ modkey, "Shift"   }, "k", function () awful.client.swap.byidx(  1)    end,
412               {description = "swap with next client by index", group = "client"}),
413     awful.key({ modkey, "Shift"   }, "j", function () awful.client.swap.byidx( -1)    end,
414               {description = "swap with previous client by index", group = "client"}),
415     awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative( 1) end,
416               {description = "focus the next screen", group = "screen"}),
417     awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative(-1) end,
418               {description = "focus the previous screen", group = "screen"}),
419     awful.key({ modkey,           }, "u", awful.client.urgent.jumpto,
420               {description = "jump to urgent client", group = "client"}),
421     awful.key({ modkey,           }, "Tab",
422         function ()
423             awful.client.focus.history.previous()
424             if client.focus then
425                 client.focus:raise()
426             end
427         end,
428         {description = "go back", group = "client"}),
429
430     -- Standard program
431     awful.key({ modkey,           }, "Return", function () awful.spawn(terminal) end,
432               {description = "open a terminal", group = "launcher"}),
433     awful.key({ modkey, "Control" }, "r", awesome.restart,
434               {description = "reload awesome", group = "awesome"}),
435     awful.key({ modkey, "Shift"   }, "q", awesome.quit,
436               {description = "quit awesome", group = "awesome"}),
437
438     awful.key({ modkey,           }, "l",     function () awful.tag.incmwfact( 0.05)          end,
439               {description = "increase master width factor", group = "layout"}),
440     awful.key({ modkey,           }, "h",     function () awful.tag.incmwfact(-0.05)          end,
441               {description = "decrease master width factor", group = "layout"}),
442     awful.key({ modkey, "Shift"   }, "h",     function () awful.tag.incnmaster( 1, nil, true) end,
443               {description = "increase the number of master clients", group = "layout"}),
444     awful.key({ modkey, "Shift"   }, "l",     function () awful.tag.incnmaster(-1, nil, true) end,
445               {description = "decrease the number of master clients", group = "layout"}),
446     awful.key({ modkey, "Control" }, "h",     function () awful.tag.incncol( 1, nil, true)    end,
447               {description = "increase the number of columns", group = "layout"}),
448     awful.key({ modkey, "Control" }, "l",     function () awful.tag.incncol(-1, nil, true)    end,
449               {description = "decrease the number of columns", group = "layout"}),
450     awful.key({ modkey,           }, "space", function () awful.layout.inc( 1)                end,
451               {description = "select next", group = "layout"}),
452     awful.key({ modkey, "Shift"   }, "space", function () awful.layout.inc(-1)                end,
453               {description = "select previous", group = "layout"}),
454
455     awful.key({ modkey, "Control" }, "n",
456               function ()
457                   local c = awful.client.restore()
458                   -- Focus restored client
459                   if c then
460                       client.focus = c
461                       c:raise()
462                   end
463               end,
464               {description = "restore minimized", group = "client"}),
465
466     -- Prompt
467     awful.key({ modkey },            "r",     function () mypromptbox[awful.screen.focused()]:run() end,
468               {description = "run prompt", group = "launcher"}),
469
470     awful.key({ modkey }, "x",
471               function ()
472                   awful.prompt.run({ prompt = "Run Lua code: " },
473                   mypromptbox[awful.screen.focused()].widget,
474                   awful.util.eval, nil,
475                   awful.util.get_cache_dir() .. "/history_eval")
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 = awful.util.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 = "maximize", group = "client"})
515 )
516
517 -- Bind all key numbers to tags.
518 -- Be careful: we use keycodes to make it works on any keyboard layout.
519 -- This should map on the top row of your keyboard, usually 1 to 9.
520 for i = 1, 9 do
521     globalkeys = awful.util.table.join(globalkeys,
522         -- View tag only.
523         awful.key({ modkey }, "#" .. i + 9,
524                   function ()
525                         local screen = awful.screen.focused()
526                         local tag = screen.tags[i]
527                         if tag then
528                            tag:view_only()
529                         end
530                   end,
531                   {description = "view tag #"..i, group = "tag"}),
532         -- Toggle tag.
533         awful.key({ modkey, "Control" }, "#" .. i + 9,
534                   function ()
535                       local screen = awful.screen.focused()
536                       local tag = screen.tags[i]
537                       if tag then
538                          awful.tag.viewtoggle(tag)
539                       end
540                   end,
541                   {description = "toggle tag #" .. i, group = "tag"}),
542         -- Move client to tag.
543         awful.key({ modkey, "Shift" }, "#" .. i + 9,
544                   function ()
545                       if client.focus then
546                           local tag = client.focus.screen.tags[i]
547                           if tag then
548                               client.focus:move_to_tag(tag)
549                           end
550                      end
551                   end,
552                   {description = "move focused client to tag #"..i, group = "tag"}),
553         -- Toggle tag on focused client.
554         awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
555                   function ()
556                       if client.focus then
557                           local tag = client.focus.screen.tags[i]
558                           if tag then
559                               client.focus:toggle_tag(tag)
560                           end
561                       end
562                   end,
563                   {description = "toggle focused client on tag #" .. i, group = "tag"})
564     )
565 end
566
567 clientbuttons = awful.util.table.join(
568     awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
569     awful.button({ modkey }, 1, awful.mouse.client.move),
570     awful.button({ modkey }, 3, awful.mouse.client.resize))
571
572 -- misc apps
573 globalkeys = awful.util.table.join(globalkeys,
574 awful.key({ cmdkey }, "n", function () awful.spawn("firefox") end),
575 awful.key({ cmdkey }, "m", function () awful.spawn("chromium --enable-remote-extensions") end),
576 awful.key({ cmdkey }, "y", function () awful.spawn(terminal .. " -e python") end),
577 awful.key({ cmdkey }, "c", function () awful.spawn("thunderbird") end),
578 awful.key({ cmdkey }, "r", function () mypromptbox[mouse.screen]:run() end),
579 awful.key({ cmdkey }, "g", function () awful.spawn("gscan2pdf") end),
580 awful.key({ cmdkey }, "v", function () awful.spawn("virt-manager") end),
581 awful.key({ cmdkey }, "l", function () awful.spawn("libreoffice") end),
582 awful.key({ cmdkey }, "f", function () awful.spawn("thunar") end),
583 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),
584 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),
585 awful.key({ cmdkey, "Shift" }, "x", function () awful.spawn("xscreensaver-command -exit") end),
586
587 -- function keys
588 awful.key(nil, "XF86ScreenSaver", function () awful.spawn("xset dpms force off") end),
589 awful.key(nil, "XF86AudioMute", function () awful.spawn("pactl set-sink-mute 0 toggle") end),
590 awful.key({ cmdkey }, "End", function () awful.spawn("pactl set-sink-mute 0 toggle") end),
591 awful.key(nil, "XF86AudioLowerVolume", function () awful.spawn("pactl set-sink-volume 0 -2%") end),
592 awful.key({ cmdkey }, "Next", function () awful.spawn("pactl set-sink-volume 0 -2%") end),
593 awful.key(nil, "XF86AudioRaiseVolume", function () awful.spawn("pactl set-sink-volume 0 +2%") end),
594 awful.key({ cmdkey }, "Prior", function () awful.spawn("pactl set-sink-volume 0 +2%") end),
595 awful.key(nil, "XF86AudioMicMute", function () awful.spawn("pactl set-source-mute 1 toggle") end),
596 awful.key({ cmdkey }, "Home", function () awful.spawn("pactl set-source-mute 1 toggle") end),
597 awful.key(nil, "XF86MonBrightnessDown", function () awful.spawn("xbacklight -dec 5%") end),
598 awful.key(nil, "XF86MonBrightnessUp", function () awful.spawn("xbacklight -inc 5%") end),
599 awful.key(nil, "XF86Display", function () awful.spawn("") end),
600 awful.key(nil, "XF86WLAN", function () awful.spawn("") end),
601 awful.key(nil, "XF86Tools", function () awful.spawn("") end),
602 awful.key(nil, "XF86Search", function () awful.spawn("") end),
603 awful.key(nil, "XF86LaunchA", function () awful.spawn("") end),
604 awful.key(nil, "XF86Explorer", function () awful.spawn("") end)
605 )
606
607 -- Set keys
608 root.keys(globalkeys)
609 -- }}}
610
611 -- {{{ Rules
612 -- Rules to apply to new clients (through the "manage" signal).
613
614 local function move_to_tag(s, t)
615     return function(c)
616         c:move_to_tag(tags[s][t])
617     end
618 end
619
620 awful.rules.rules = {
621     -- All clients will match this rule.
622     { rule = { },
623       properties = { border_width = beautiful.border_width,
624                      border_color = beautiful.border_normal,
625                      focus = awful.client.focus.filter,
626                      raise = true,
627                      keys = clientkeys,
628                      buttons = clientbuttons,
629                      screen = awful.screen.preferred,
630                      placement = awful.placement.no_overlap+awful.placement.no_offscreen,
631                      floating = false
632                  },
633     },
634
635     -- Add titlebars to normal clients and dialogs
636     --DISABLED-- { rule_any = {type = { "normal", "dialog" }
637     --DISABLED--  }, properties = { titlebars_enabled = true }
638     --DISABLED-- },
639
640     { rule = { type = "dialog" },
641       properties = { floating = true,
642                      placement = awful.placement.centered
643                  }
644     },
645
646     { rule = { class = "URxvt" },
647                properties = {
648                    -- floating = false,
649                    size_hints_honor = false
650                } },
651     { rule = { class = "URxvt", instance = "irc" },
652                properties = {
653                    switchtotag = true
654                },
655                callback = move_to_tag(screen.count(), screen.count() == 1 and 2 or 1)
656            },
657     { rule = { class = "Firefox", instance = "Navigator" },
658                properties = {
659                    floating = false,
660                },
661                callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
662            },
663     { rule = { class = "Firefox-esr", instance = "Navigator" },
664                properties = {
665                    floating = false,
666                },
667                callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
668            },
669     { rule = { class = "Thunderbird", instance = "Mail" },
670                properties = {
671                    floating = false,
672                },
673                callback = move_to_tag(screen.count() == 1 and 1 or 2, 8)
674            },
675     { rule = { class = "Chromium", instance = "chromium" },
676                properties = {
677                    floating = false,
678                },
679                callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
680            },
681     { rule = { class = "Gscan2pdf" },
682                properties = {
683                    switchtotag = true
684                },
685                callback = move_to_tag(1, 5)
686            },
687     { rule = { name = "gscan2pdf .*" },
688                properties = {
689                    floating = false,
690                },
691            },
692     { rule = { class = "Thunar", type = "normal" },
693                properties = {
694                    floating = false,
695                },
696            },
697     { rule = { class = "MuPDF", instance = "mupdf" },
698                properties = {
699                    floating = true,
700                },
701            },
702     { rule = { class = "Pinentry", instance = "pinentry" },
703                properties = {
704                    floating = true,
705                },
706            },
707     { rule = { class = "Gxmessage" },
708                properties = {
709                    floating = true,
710                },
711            },
712 }
713 -- }}}
714
715 -- {{{ Signals
716 -- Signal function to execute when a new client appears.
717 client.connect_signal("manage", function (c)
718     -- Set the windows at the slave,
719     -- i.e. put it at the end of others instead of setting it master.
720     if not awesome.startup then awful.client.setslave(c) end
721
722     if awesome.startup and
723       not c.size_hints.user_position
724       and not c.size_hints.program_position then
725         -- Prevent clients from being unreachable after screen count changes.
726         awful.placement.no_offscreen(c)
727     end
728
729     c.maximized_horizontal = false
730     c.maximized_vertical = false
731 end)
732
733 -- Add a titlebar if titlebars_enabled is set to true in the rules.
734 client.connect_signal("request::titlebars", function(c)
735     -- buttons for the titlebar
736     local buttons = awful.util.table.join(
737         awful.button({ }, 1, function()
738             client.focus = c
739             c:raise()
740             awful.mouse.client.move(c)
741         end),
742         awful.button({ }, 3, function()
743             client.focus = c
744             c:raise()
745             awful.mouse.client.resize(c)
746         end)
747     )
748
749     awful.titlebar(c) : setup {
750         { -- Left
751             awful.titlebar.widget.iconwidget(c),
752             buttons = buttons,
753             layout  = wibox.layout.fixed.horizontal
754         },
755         { -- Middle
756             { -- Title
757                 align  = "center",
758                 widget = awful.titlebar.widget.titlewidget(c)
759             },
760             buttons = buttons,
761             layout  = wibox.layout.flex.horizontal
762         },
763         { -- Right
764             awful.titlebar.widget.floatingbutton (c),
765             awful.titlebar.widget.maximizedbutton(c),
766             awful.titlebar.widget.stickybutton   (c),
767             awful.titlebar.widget.ontopbutton    (c),
768             awful.titlebar.widget.closebutton    (c),
769             layout = wibox.layout.fixed.horizontal()
770         },
771         layout = wibox.layout.align.horizontal
772     }
773 end)
774
775 -- Enable sloppy focus
776 client.connect_signal("mouse::enter", function(c)
777     if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
778         and awful.client.focus.filter(c) then
779         client.focus = c
780     end
781 end)
782
783 client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end)
784 client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
785
786 awful.ewmh.add_activate_filter(function(c, context, hints)
787     if context == "ewmh" and (c.class == "Firefox-esr" or c.class == "Firefox") then return false end
788 end)
789
790 -- vim:ft=lua:sw=4:sts=4:ts=4:et