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:

print_table debug 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 -- Notification library
11 local naughty = require("naughty")
12 local menubar = require("menubar")
13 local hotkeys_popup = require("awful.hotkeys_popup").widget
14 -- }}}
15
16 -- {{{ Error handling
17 -- Check if awesome encountered an error during startup and fell back to
18 -- another config (This code will only ever execute for the fallback config)
19 if awesome.startup_errors then
20     naughty.notify({ preset = naughty.config.presets.critical,
21                      title = "Oops, there were errors during startup!",
22                      text = awesome.startup_errors })
23 end
24
25 -- Handle runtime errors after startup
26 do
27     local in_error = false
28     awesome.connect_signal("debug::error", function (err)
29         -- Make sure we don't go into an endless error loop
30         if in_error then return end
31         in_error = true
32
33         naughty.notify({ preset = naughty.config.presets.critical,
34                          title = "Oops, an error happened!",
35                          text = tostring(err) })
36         in_error = false
37     end)
38 end
39 -- }}}
40
41 -- {{{ Variable definitions
42 -- Themes define colours, icons, and wallpapers
43 beautiful.init(awful.util.get_themes_dir() .. "default/theme.lua")
44
45 -- This is used later as the default terminal and editor to run.
46 terminal = "x-terminal-emulator"
47 editor = "sensible-editor"
48 editor_cmd = terminal .. " -e " .. editor
49
50 -- Default modkey.
51 -- Usually, Mod4 is the key with a logo between Control and Alt.
52 -- If you do not like this or do not have such a key,
53 -- I suggest you to remap Mod4 to another key using xmodmap or other tools.
54 -- However, you can use another modifier like Mod1, but it may interact with others.
55 modkey = "Mod4"
56 cmdkey = "Mod3"
57
58 -- Table of layouts to cover with awful.layout.inc, order matters.
59 awful.layout.layouts = {
60     awful.layout.suit.fair,
61     awful.layout.suit.tile,
62     -- awful.layout.suit.tile.left,
63     -- awful.layout.suit.tile.bottom,
64     awful.layout.suit.tile.top,
65     -- awful.layout.suit.spiral,
66     -- awful.layout.suit.spiral.dwindle,
67     awful.layout.suit.max,
68     awful.layout.suit.max.fullscreen,
69     -- awful.layout.suit.magnifier,
70     -- awful.layout.suit.corner.nw,
71     -- awful.layout.suit.corner.ne,
72     -- awful.layout.suit.corner.sw,
73     -- awful.layout.suit.corner.se,
74     awful.layout.suit.floating,
75 }
76
77 layout_default = awful.layout.layouts[1]
78 layout_tiled = awful.layout.layouts[2]
79 layout_maximised = awful.layout.layouts[4]
80 layout_floating = awful.layout.layouts[5]
81 -- }}}
82
83 -- {{{ Helper functions
84 local function client_menu_toggle_fn()
85     local instance = nil
86
87     return function ()
88         if instance and instance.wibox.visible then
89             instance:hide()
90             instance = nil
91         else
92             instance = awful.menu.clients({ theme = { width = 250 } })
93         end
94     end
95 end
96
97 local function print_table(tbl, indent)
98     if not indent then indent = 0 end
99     for k, v in pairs(tbl) do
100         formatting = string.rep("  ", indent) .. k .. ": "
101         if type(v) == "table" then
102             print(formatting)
103             print_table(v, indent+1)
104         else
105             print(formatting .. tostring(v))
106         end
107     end
108 end
109 -- }}}
110
111 -- {{{ Menu
112 -- Create a launcher widget and a main menu
113 myawesomemenu = {
114    { "hotkeys", function() return false, hotkeys_popup.show_help end},
115    { "manual", terminal .. " -e man awesome" },
116    { "edit config", editor_cmd .. " " .. awesome.conffile },
117    { "restart", awesome.restart },
118    { "quit", awesome.quit }
119 }
120
121 mymainmenu = awful.menu({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon },
122                                     { "open terminal", terminal }
123                                   }
124                         })
125
126 mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
127                                      menu = mymainmenu })
128 -- }}}
129
130 -- {{{ Menubar configuration
131 menubar.utils.terminal = terminal -- Set the terminal for applications that require it
132 -- }}}
133
134 -- {{{ Wibox
135 -- Create a textclock widget
136 mytextclock = wibox.widget.textclock("%a %d %b %H:%M:%S", 1)
137
138 -- Keyboard map indicator and switcher
139 mykeyboardlayout = awful.widget.keyboardlayout()
140
141 -- Create a wibox for each screen and add it
142 mywibox = {}
143 mypromptbox = {}
144 mylayoutbox = {}
145 mytaglist = {}
146 mytaglist.buttons = awful.util.table.join(
147                     awful.button({ }, 1, function(t) t:view_only() end),
148                     awful.button({ modkey }, 1, function(t)
149                                               if client.focus then
150                                                   client.focus:move_to_tag(t)
151                                               end
152                                           end),
153                     awful.button({ }, 3, awful.tag.viewtoggle),
154                     awful.button({ modkey }, 3, function(t)
155                                               if client.focus then
156                                                   client.focus:toggle_tag(t)
157                                               end
158                                           end),
159                     awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
160                     awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
161                 )
162
163 mytasklist = {}
164 mytasklist.buttons = awful.util.table.join(
165                      awful.button({ }, 1, function (c)
166                                               if c == client.focus then
167                                                   c.minimized = true
168                                               else
169                                                   -- Without this, the following
170                                                   -- :isvisible() makes no sense
171                                                   c.minimized = false
172                                                   if not c:isvisible() and c.first_tag then
173                                                       c.first_tag:view_only()
174                                                   end
175                                                   -- This will also un-minimize
176                                                   -- the client, if needed
177                                                   client.focus = c
178                                                   c:raise()
179                                               end
180                                           end),
181                      awful.button({ }, 3, client_menu_toggle_fn()),
182                      awful.button({ }, 4, function ()
183                                               awful.client.focus.byidx(1)
184                                           end),
185                      awful.button({ }, 5, function ()
186                                               awful.client.focus.byidx(-1)
187                                           end))
188 -- }}}
189
190 -- {{{ Tags
191
192 awful.screen.connect_for_each_screen(function(s)
193     -- Wallpaper
194     --DISABLED--if beautiful.wallpaper then
195     --DISABLED--    local wallpaper = beautiful.wallpaper
196     --DISABLED--    -- If wallpaper is a function, call it with the screen
197     --DISABLED--    if type(wallpaper) == "function" then
198     --DISABLED--        wallpaper = wallpaper(s)
199     --DISABLED--    end
200     --DISABLED--    gears.wallpaper.maximized(wallpaper, s, true)
201     --DISABLED--end
202
203     -- Each screen has its own tag table.
204     tags = awful.tag.new({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, s, layout_default)
205     tags[7].layout = layout_maximised
206     tags[8].layout = layout_maximised
207     tags[9].layout = layout_maximised
208     tags[1].selected = true
209
210     -- Create a promptbox for each screen
211     mypromptbox[s] = awful.widget.prompt()
212     -- Create an imagebox widget which will contains an icon indicating which layout we're using.
213     -- We need one layoutbox per screen.
214     mylayoutbox[s] = awful.widget.layoutbox(s)
215     mylayoutbox[s]:buttons(awful.util.table.join(
216                            awful.button({ }, 1, function () awful.layout.inc( 1) end),
217                            awful.button({ }, 3, function () awful.layout.inc(-1) end),
218                            awful.button({ }, 4, function () awful.layout.inc( 1) end),
219                            awful.button({ }, 5, function () awful.layout.inc(-1) end)))
220     -- Create a taglist widget
221     mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.filter.all, mytaglist.buttons)
222
223     -- Create a tasklist widget
224     mytasklist[s] = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, mytasklist.buttons)
225
226     -- Create the wibox
227     mywibox[s] = awful.wibar({ position = "top", screen = s })
228
229     -- Add widgets to the wibox
230     mywibox[s]:setup {
231         layout = wibox.layout.align.horizontal,
232         { -- Left widgets
233             layout = wibox.layout.fixed.horizontal,
234             -- mylauncher,
235             mytaglist[s],
236             mypromptbox[s],
237         },
238         mytasklist[s], -- Middle widget
239         { -- Right widgets
240             layout = wibox.layout.fixed.horizontal,
241             mykeyboardlayout,
242             wibox.widget.systray(),
243             mytextclock,
244             mylayoutbox[s],
245         },
246     }
247 end)
248 -- }}}
249
250 -- {{{ Mouse bindings
251 root.buttons(awful.util.table.join(
252     awful.button({ }, 3, function () mymainmenu:toggle() end),
253     awful.button({ }, 4, awful.tag.viewnext),
254     awful.button({ }, 5, awful.tag.viewprev)
255 ))
256 -- }}}
257
258 -- {{{ Key bindings
259 globalkeys = awful.util.table.join(
260     awful.key({ modkey,           }, "s",      hotkeys_popup.show_help,
261               {description="show help", group="awesome"}),
262     awful.key({ modkey,           }, "Left",   awful.tag.viewprev,
263               {description = "view previous", group = "tag"}),
264     awful.key({ modkey,           }, "Right",  awful.tag.viewnext,
265               {description = "view next", group = "tag"}),
266     awful.key({ modkey,           }, "Escape", awful.tag.history.restore,
267               {description = "go back", group = "tag"}),
268
269     awful.key({ modkey,           }, "j",
270         function ()
271             awful.client.focus.byidx( 1)
272         end,
273         {description = "focus next by index", group = "client"}
274     ),
275     awful.key({ modkey,           }, "k",
276         function ()
277             awful.client.focus.byidx(-1)
278         end,
279         {description = "focus previous by index", group = "client"}
280     ),
281     awful.key({ modkey,           }, "w", function () mymainmenu:show() end,
282               {description = "show main menu", group = "awesome"}),
283
284     -- Layout manipulation
285     awful.key({ modkey, "Shift"   }, "j", function () awful.client.swap.byidx(  1)    end,
286               {description = "swap with next client by index", group = "client"}),
287     awful.key({ modkey, "Shift"   }, "k", function () awful.client.swap.byidx( -1)    end,
288               {description = "swap with previous client by index", group = "client"}),
289     awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative( 1) end,
290               {description = "focus the next screen", group = "screen"}),
291     awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative(-1) end,
292               {description = "focus the previous screen", group = "screen"}),
293     awful.key({ modkey,           }, "u", awful.client.urgent.jumpto,
294               {description = "jump to urgent client", group = "client"}),
295     awful.key({ modkey,           }, "Tab",
296         function ()
297             awful.client.focus.history.previous()
298             if client.focus then
299                 client.focus:raise()
300             end
301         end,
302         {description = "go back", group = "client"}),
303
304     -- Standard program
305     awful.key({ modkey,           }, "Return", function () awful.spawn(terminal) end,
306               {description = "open a terminal", group = "launcher"}),
307     awful.key({ modkey, "Control" }, "r", awesome.restart,
308               {description = "reload awesome", group = "awesome"}),
309     awful.key({ modkey, "Shift"   }, "q", awesome.quit,
310               {description = "quit awesome", group = "awesome"}),
311
312     awful.key({ modkey,           }, "l",     function () awful.tag.incmwfact( 0.05)          end,
313               {description = "increase master width factor", group = "layout"}),
314     awful.key({ modkey,           }, "h",     function () awful.tag.incmwfact(-0.05)          end,
315               {description = "decrease master width factor", group = "layout"}),
316     awful.key({ modkey, "Shift"   }, "h",     function () awful.tag.incnmaster( 1, nil, true) end,
317               {description = "increase the number of master clients", group = "layout"}),
318     awful.key({ modkey, "Shift"   }, "l",     function () awful.tag.incnmaster(-1, nil, true) end,
319               {description = "decrease the number of master clients", group = "layout"}),
320     awful.key({ modkey, "Control" }, "h",     function () awful.tag.incncol( 1, nil, true)    end,
321               {description = "increase the number of columns", group = "layout"}),
322     awful.key({ modkey, "Control" }, "l",     function () awful.tag.incncol(-1, nil, true)    end,
323               {description = "decrease the number of columns", group = "layout"}),
324     awful.key({ modkey,           }, "space", function () awful.layout.inc( 1)                end,
325               {description = "select next", group = "layout"}),
326     awful.key({ modkey, "Shift"   }, "space", function () awful.layout.inc(-1)                end,
327               {description = "select previous", group = "layout"}),
328
329     awful.key({ modkey, "Control" }, "n",
330               function ()
331                   local c = awful.client.restore()
332                   -- Focus restored client
333                   if c then
334                       client.focus = c
335                       c:raise()
336                   end
337               end,
338               {description = "restore minimized", group = "client"}),
339
340     -- Prompt
341     awful.key({ modkey },            "r",     function () mypromptbox[awful.screen.focused()]:run() end,
342               {description = "run prompt", group = "launcher"}),
343
344     awful.key({ modkey }, "x",
345               function ()
346                   awful.prompt.run({ prompt = "Run Lua code: " },
347                   mypromptbox[awful.screen.focused()].widget,
348                   awful.util.eval, nil,
349                   awful.util.get_cache_dir() .. "/history_eval")
350               end,
351               {description = "lua execute prompt", group = "awesome"}),
352     -- Menubar
353     awful.key({ modkey }, "p", function() menubar.show() end,
354               {description = "show the menubar", group = "launcher"})
355 )
356
357 clientkeys = awful.util.table.join(
358     awful.key({ modkey,           }, "f",
359         function (c)
360             c.fullscreen = not c.fullscreen
361             c:raise()
362         end,
363         {description = "toggle fullscreen", group = "client"}),
364     awful.key({ modkey, "Shift"   }, "c",      function (c) c:kill()                         end,
365               {description = "close", group = "client"}),
366     awful.key({ modkey, "Control" }, "space",  awful.client.floating.toggle                     ,
367               {description = "toggle floating", group = "client"}),
368     awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
369               {description = "move to master", group = "client"}),
370     awful.key({ modkey,           }, "o",      function (c) c:move_to_screen()               end,
371               {description = "move to screen", group = "client"}),
372     awful.key({ modkey,           }, "t",      function (c) c.ontop = not c.ontop            end,
373               {description = "toggle keep on top", group = "client"}),
374     awful.key({ modkey,           }, "n",
375         function (c)
376             -- The client currently has the input focus, so it cannot be
377             -- minimized, since minimized clients can't have the focus.
378             c.minimized = true
379         end ,
380         {description = "minimize", group = "client"}),
381     awful.key({ modkey,           }, "m",
382         function (c)
383             c.maximized = not c.maximized
384             c:raise()
385         end ,
386         {description = "maximize", group = "client"})
387 )
388
389 -- Bind all key numbers to tags.
390 -- Be careful: we use keycodes to make it works on any keyboard layout.
391 -- This should map on the top row of your keyboard, usually 1 to 9.
392 for i = 1, 9 do
393     globalkeys = awful.util.table.join(globalkeys,
394         -- View tag only.
395         awful.key({ modkey }, "#" .. i + 9,
396                   function ()
397                         local screen = awful.screen.focused()
398                         local tag = screen.tags[i]
399                         if tag then
400                            tag:view_only()
401                         end
402                   end,
403                   {description = "view tag #"..i, group = "tag"}),
404         -- Toggle tag.
405         awful.key({ modkey, "Control" }, "#" .. i + 9,
406                   function ()
407                       local screen = awful.screen.focused()
408                       local tag = screen.tags[i]
409                       if tag then
410                          awful.tag.viewtoggle(tag)
411                       end
412                   end,
413                   {description = "toggle tag #" .. i, group = "tag"}),
414         -- Move client to tag.
415         awful.key({ modkey, "Shift" }, "#" .. i + 9,
416                   function ()
417                       if client.focus then
418                           local tag = client.focus.screen.tags[i]
419                           if tag then
420                               client.focus:move_to_tag(tag)
421                           end
422                      end
423                   end,
424                   {description = "move focused client to tag #"..i, group = "tag"}),
425         -- Toggle tag on focused client.
426         awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
427                   function ()
428                       if client.focus then
429                           local tag = client.focus.screen.tags[i]
430                           if tag then
431                               client.focus:toggle_tag(tag)
432                           end
433                       end
434                   end,
435                   {description = "toggle focused client on tag #" .. i, group = "tag"})
436     )
437 end
438
439 clientbuttons = awful.util.table.join(
440     awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
441     awful.button({ modkey }, 1, awful.mouse.client.move),
442     awful.button({ modkey }, 3, awful.mouse.client.resize))
443
444 -- Set keys
445 root.keys(globalkeys)
446 -- }}}
447
448 -- {{{ Rules
449 -- Rules to apply to new clients (through the "manage" signal).
450 awful.rules.rules = {
451     -- All clients will match this rule.
452     { rule = { },
453       properties = { border_width = beautiful.border_width,
454                      border_color = beautiful.border_normal,
455                      focus = awful.client.focus.filter,
456                      size_hints_honor = false,
457                      raise = true,
458                      keys = clientkeys,
459                      buttons = clientbuttons,
460                      placement = awful.placement.no_overlap+awful.placement.no_offscreen
461      }
462     },
463
464     -- Floating clients.
465     { rule_any = {
466         instance = {
467           "DTA",  -- Firefox addon DownThemAll.
468           "copyq",  -- Includes session name in class.
469         },
470         class = {
471           "Arandr",
472           "Gpick",
473           "Kruler",
474           "MessageWin",  -- kalarm.
475           "Sxiv",
476           "Wpa_gui",
477           "pinentry",
478           "veromix",
479           "xtightvncviewer"},
480
481         name = {
482           "Event Tester",  -- xev.
483         },
484         role = {
485           "AlarmWindow",  -- Thunderbird's calendar.
486           "pop-up",       -- e.g. Google Chrome's (detached) Developer Tools.
487         }
488       }, properties = { floating = true }},
489
490     -- Add titlebars to normal clients and dialogs
491     { rule_any = {type = { "normal", "dialog" }
492       }, properties = { titlebars_enabled = false }
493     },
494
495     -- Set Firefox to always map on the tag named "2" on screen 1.
496     -- { rule = { class = "Firefox" },
497     --   properties = { screen = 1, tag = "2" } },
498 }
499 -- }}}
500
501 -- {{{ Signals
502 -- Signal function to execute when a new client appears.
503 client.connect_signal("manage", function (c)
504     -- Set the windows at the slave,
505     -- i.e. put it at the end of others instead of setting it master.
506     -- if not awesome.startup then awful.client.setslave(c) end
507
508     if awesome.startup and
509       not c.size_hints.user_position
510       and not c.size_hints.program_position then
511         -- Prevent clients from being unreachable after screen count changes.
512         awful.placement.no_offscreen(c)
513     end
514 end)
515
516 -- Add a titlebar if titlebars_enabled is set to true in the rules.
517 client.connect_signal("request::titlebars", function(c)
518     -- buttons for the titlebar
519     local buttons = awful.util.table.join(
520         awful.button({ }, 1, function()
521             client.focus = c
522             c:raise()
523             awful.mouse.client.move(c)
524         end),
525         awful.button({ }, 3, function()
526             client.focus = c
527             c:raise()
528             awful.mouse.client.resize(c)
529         end)
530     )
531
532     awful.titlebar(c) : setup {
533         { -- Left
534             awful.titlebar.widget.iconwidget(c),
535             buttons = buttons,
536             layout  = wibox.layout.fixed.horizontal
537         },
538         { -- Middle
539             { -- Title
540                 align  = "center",
541                 widget = awful.titlebar.widget.titlewidget(c)
542             },
543             buttons = buttons,
544             layout  = wibox.layout.flex.horizontal
545         },
546         { -- Right
547             awful.titlebar.widget.floatingbutton (c),
548             awful.titlebar.widget.maximizedbutton(c),
549             awful.titlebar.widget.stickybutton   (c),
550             awful.titlebar.widget.ontopbutton    (c),
551             awful.titlebar.widget.closebutton    (c),
552             layout = wibox.layout.fixed.horizontal()
553         },
554         layout = wibox.layout.align.horizontal
555     }
556 end)
557
558 -- Enable sloppy focus
559 client.connect_signal("mouse::enter", function(c)
560     if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
561         and awful.client.focus.filter(c) then
562         client.focus = c
563     end
564 end)
565
566 client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end)
567 client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
568 -- }}}
569
570 -- vim:ft=lua:sw=4:sts=4:ts=4:et