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:

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