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:

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