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:

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