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:

add freedesktop menu
[etc/awesome.git] / .config / awesome / rc.lua
1 -- {{{ Imports
2 -- Standard awesome library
3 local gears = require("gears")
4 local awful = require("awful")
5 require("awful.autofocus")
6 -- Widget and layout library
7 local wibox = require("wibox")
8 -- Theme handling library
9 local beautiful = require("beautiful")
10 -- Notification library
11 local naughty = require("naughty")
12 local menubar = require("menubar")
13 local hotkeys_popup = require("awful.hotkeys_popup").widget
14 local lain = require("lain")
15 local dkjson = require("lain.util").dkjson
16 local math = require("math")
17 local freedesktop = require("freedesktop")
18 -- }}}
19
20 -- {{{ Error handling
21 -- Check if awesome encountered an error during startup and fell back to
22 -- another config (This code will only ever execute for the fallback config)
23 if awesome.startup_errors then
24     naughty.notify({ preset = naughty.config.presets.critical,
25                      title = "Oops, there were errors during startup!",
26                      text = awesome.startup_errors })
27 end
28
29 -- Handle runtime errors after startup
30 do
31     local in_error = false
32     awesome.connect_signal("debug::error", function (err)
33         -- Make sure we don't go into an endless error loop
34         if in_error then return end
35         in_error = true
36
37         naughty.notify({ preset = naughty.config.presets.critical,
38                          title = "Oops, an error happened!",
39                          text = tostring(err) })
40         in_error = false
41     end)
42 end
43 -- }}}
44
45 -- {{{ Variable definitions
46 -- Themes define colours, icons, and wallpapers
47 beautiful.init(awful.util.get_themes_dir() .. "default/theme.lua")
48
49 -- This is used later as the default terminal and editor to run.
50 terminal = "x-terminal-emulator"
51 editor = "sensible-editor"
52 editor_cmd = terminal .. " -e " .. editor
53
54 -- Default modkey.
55 -- Usually, Mod4 is the key with a logo between Control and Alt.
56 -- If you do not like this or do not have such a key,
57 -- I suggest you to remap Mod4 to another key using xmodmap or other tools.
58 -- However, you can use another modifier like Mod1, but it may interact with others.
59 modkey = "Mod4"
60 cmdkey = "Mod3"
61
62 -- Table of layouts to cover with awful.layout.inc, order matters.
63 awful.layout.layouts = {
64     awful.layout.suit.fair,
65     awful.layout.suit.tile,
66     -- awful.layout.suit.tile.left,
67     -- awful.layout.suit.tile.bottom,
68     awful.layout.suit.tile.top,
69     -- awful.layout.suit.spiral,
70     -- awful.layout.suit.spiral.dwindle,
71     awful.layout.suit.max,
72     -- awful.layout.suit.max.fullscreen,
73     -- awful.layout.suit.magnifier,
74     -- awful.layout.suit.corner.nw,
75     -- awful.layout.suit.corner.ne,
76     -- awful.layout.suit.corner.sw,
77     -- awful.layout.suit.corner.se,
78     awful.layout.suit.floating,
79 }
80
81 layout_default = awful.layout.layouts[1]
82 layout_tiled = awful.layout.layouts[2]
83 layout_maximised = awful.layout.layouts[4]
84 layout_floating = awful.layout.layouts[5]
85 -- }}}
86
87 -- {{{ Helper functions
88 local function client_menu_toggle_fn()
89     local instance = nil
90
91     return function ()
92         if instance and instance.wibox.visible then
93             instance:hide()
94             instance = nil
95         else
96             instance = awful.menu.clients({ theme = { width = 250 } })
97         end
98     end
99 end
100
101 local function sorted_pairs(t, f)
102     local a = {}
103     for n in pairs(t) do table.insert(a, n) end
104     table.sort(a, f)
105     local i = 0      -- iterator variable
106     local iter = function ()   -- iterator function
107         i = i + 1
108         if a[i] == nil then return nil
109         else return a[i], t[a[i]]
110         end
111     end
112     return iter
113 end
114
115 local function print_table(tbl, indent)
116     if not indent then indent = 0 end
117     for k, v in pairs(tbl) do
118         formatting = string.rep("  ", indent) .. k .. ": "
119         if type(v) == "table" then
120             print(formatting)
121             print_table(v, indent+1)
122         else
123             print(formatting .. tostring(v))
124         end
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
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 = freedesktop.menu.build({
183     before = {
184         { "awesome", myawesomemenu, beautiful.awesome_icon },
185         { "terminal", terminal },
186     },
187     after = {
188     }
189 })
190
191 mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
192                                      menu = mymainmenu })
193 -- }}}
194
195 -- {{{ Menubar configuration
196 menubar.utils.terminal = terminal -- Set the terminal for applications that require it
197 -- }}}
198
199 -- {{{ Wibox
200 local spacer = wibox.widget.textbox()
201 spacer:set_text(' | ')
202 -- Create a textclock widget
203 mytextclock = wibox.widget.textclock("%a %d %b %H:%M:%S", 1)
204
205 -- Create a wibox for each screen and add it
206 mywibox = {}
207 mypromptbox = {}
208 mylayoutbox = {}
209 mytaglist = {}
210 mytaglist.buttons = awful.util.table.join(
211                     awful.button({ }, 1, function(t) t:view_only() end),
212                     awful.button({ modkey }, 1, function(t)
213                                               if client.focus then
214                                                   client.focus:move_to_tag(t)
215                                               end
216                                           end),
217                     awful.button({ }, 3, awful.tag.viewtoggle),
218                     awful.button({ modkey }, 3, function(t)
219                                               if client.focus then
220                                                   client.focus:toggle_tag(t)
221                                               end
222                                           end),
223                     awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
224                     awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
225                 )
226
227 mytasklist = {}
228 mytasklist.buttons = awful.util.table.join(
229                      awful.button({ }, 1, function (c)
230                                               if c == client.focus then
231                                                   -- I don't like click-minimising
232                                                   -- c.minimized = true
233                                               else
234                                                   -- Without this, the following
235                                                   -- :isvisible() makes no sense
236                                                   c.minimized = false
237                                                   if not c:isvisible() and c.first_tag then
238                                                       c.first_tag:view_only()
239                                                   end
240                                                   -- This will also un-minimize
241                                                   -- the client, if needed
242                                                   client.focus = c
243                                                   c:raise()
244                                               end
245                                           end),
246                      awful.button({ }, 3, client_menu_toggle_fn()),
247                      awful.button({ }, 4, function ()
248                                               awful.client.focus.byidx(1)
249                                           end),
250                      awful.button({ }, 5, function ()
251                                               awful.client.focus.byidx(-1)
252                                           end))
253 -- }}}
254
255 -- {{{ Tags
256 tags = {}
257 tags.config = {}
258 tags.config["main"] = {
259     t1 = { layout = layout_default, selected = true },
260     t2 = { layout = layout_default },
261     t3 = { layout = layout_tiled },
262     t4 = { layout = layout_tiled },
263     t5 = { layout = layout_tiled },
264     t6 = { layout = layout_floating },
265     t7 = { layout = layout_maximised },
266     t8 = { layout = layout_maximised },
267     t9 = { layout = layout_maximised },
268 }
269 tags.config["aux"] = {
270     t1 = { layout = layout_default, selected = true },
271     t2 = { layout = layout_default },
272     t3 = { layout = layout_tiled },
273     t4 = { layout = layout_floating },
274     t5 = { layout = layout_floating },
275     t6 = { layout = layout_floating },
276     t7 = { layout = layout_floating },
277     t8 = { layout = layout_floating },
278     t9 = { layout = layout_maximised },
279 }
280
281 screentags = {}
282 screentags[1] = tags.config["main"]
283 if screen.count() == 2 then -- aux screen is on the right
284   screentags[2] = tags.config["aux"]
285 elseif screen.count() == 3 then -- main screen is still #1 in the middle
286   screentags[2] = tags.config["aux"]
287   screentags[3] = tags.config["aux"]
288 end
289
290 awful.screen.connect_for_each_screen(function(s)
291     -- Wallpaper
292     --DISABLED--if beautiful.wallpaper then
293     --DISABLED--    local wallpaper = beautiful.wallpaper
294     --DISABLED--    -- If wallpaper is a function, call it with the screen
295     --DISABLED--    if type(wallpaper) == "function" then
296     --DISABLED--        wallpaper = wallpaper(s)
297     --DISABLED--    end
298     --DISABLED--    gears.wallpaper.maximized(wallpaper, s, true)
299     --DISABLED--end
300
301     if not tags[s.index] then
302         tags[s.index] = {}
303     end
304     for n,p in sorted_pairs(screentags[s.index]) do
305         p["screen"] = s
306         n = string.sub(n, 2) -- remove leading 't' needed for syntax in table
307         table.insert(tags[s.index], awful.tag.add(n, p))
308     end
309
310     -- Create a promptbox for each screen
311     mypromptbox[s] = awful.widget.prompt()
312     -- Create an imagebox widget which will contains an icon indicating which layout we're using.
313     -- We need one layoutbox per screen.
314     mylayoutbox[s] = awful.widget.layoutbox(s)
315     mylayoutbox[s]:buttons(awful.util.table.join(
316                            awful.button({ }, 1, function () awful.layout.inc( 1) end),
317                            awful.button({ }, 3, function () awful.layout.inc(-1) end),
318                            awful.button({ }, 4, function () awful.layout.inc( 1) end),
319                            awful.button({ }, 5, function () awful.layout.inc(-1) end)))
320     -- Create a taglist widget
321     mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.filter.all, mytaglist.buttons)
322
323     -- Create a tasklist widget
324     mytasklist[s] = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, mytasklist.buttons)
325
326     -- Create the wibox
327     mywibox[s] = awful.wibar({ position = "top", screen = s })
328
329     -- Add widgets to the wibox
330     mywibox[s]:setup {
331         layout = wibox.layout.align.horizontal,
332         { -- Left widgets
333             layout = wibox.layout.fixed.horizontal,
334             -- mylauncher,
335             mytaglist[s],
336             mypromptbox[s],
337         },
338         mytasklist[s], -- Middle widget
339         { -- Right widgets
340             layout = wibox.layout.fixed.horizontal,
341             mykeyboardlayout,
342             wibox.widget.systray(),
343             btc_widget,
344             spacer,
345             lain_bat.widget,
346             spacer,
347             mytextclock,
348             mylayoutbox[s],
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