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:

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