]> git.madduck.net Git - etc/awesome.git/blob - .config/awesome/rc.lua

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:

a3833bda975684f708c3dba3ee5c21869a865484
[etc/awesome.git] / .config / awesome / rc.lua
1 -- {{{ Imports
2
3 -- Standard awesome library
4 local gears = require("gears")
5 local awful = require("awful")
6 require("awful.autofocus")
7 -- Widget and layout library
8 local wibox = require("wibox")
9 -- Tyrannical tab handling
10 --local tyrannical = require("tyrannical")
11 -- Theme handling library
12 local beautiful = require("beautiful")
13 local xrdb = beautiful.xresources
14 -- Notification library
15 local naughty = require("naughty")
16 local menubar = require("menubar")
17 local hotkeys_popup = require("awful.hotkeys_popup").widget
18 -- Enable hotkeys help widget for VIM and other apps
19 -- when client with a matching name is opened:
20 require("awful.hotkeys_popup.keys")
21
22 -- Load Debian menu entries
23 local debian = require("debian.menu")
24 local has_fdo, freedesktop = pcall(require, "freedesktop")
25 -- Other libraries
26 local lain = require("lain")
27 local ccwidgets = require("cryptocoin_widgets")
28 local fxwidgets = require("forex_widgets")
29 local clocksarray = require("clocksarray")
30 local dbg = require("debugfunc")
31 local th = require("taghelpers")
32 -- }}}
33
34 -- {{{ Error handling
35 -- Check if awesome encountered an error during startup and fell back to
36 -- another config (This code will only ever execute for the fallback config)
37 if awesome.startup_errors then
38     naughty.notify({ preset = naughty.config.presets.critical,
39                      title = "Oops, there were errors during startup!",
40                      text = awesome.startup_errors })
41 end
42
43 -- Handle runtime errors after startup
44 do
45     local in_error = false
46     awesome.connect_signal("debug::error", function (err)
47         -- Make sure we don't go into an endless error loop
48         if in_error then return end
49         in_error = true
50
51         naughty.notify({ preset = naughty.config.presets.critical,
52                          title = "Oops, an error happened!",
53                          text = tostring(err) })
54         in_error = false
55     end)
56 end
57 -- }}}
58
59 -- {{{ Variable definitions
60 --xrdb.set_dpi(95, screen[1])
61 --xrdb.set_dpi(120, screen[2])
62
63 -- Themes define colours, icons, font and wallpapers.
64 beautiful.init(gears.filesystem.get_configuration_dir () .. "theme/theme.lua")
65
66 -- This is used later as the default terminal and editor to run.
67 terminal = "rxvt-unicode"
68 editor = os.getenv("EDITOR") or "editor"
69 editor_cmd = terminal .. " -e " .. editor
70
71 -- Default modkey.
72 -- Usually, Mod4 is the key with a logo between Control and Alt.
73 -- If you do not like this or do not have such a key,
74 -- I suggest you to remap Mod4 to another key using xmodmap or other tools.
75 -- However, you can use another modifier like Mod1, but it may interact with others.
76 modkey = "Mod4"
77 cmdkey = "Mod3"
78
79 -- Table of layouts to cover with awful.layout.inc, order matters.
80 local layouts = {
81     default = awful.layout.suit.fair,
82     default_horiz = awful.layout.suit.fair.horizontal,
83     tiled = awful.layout.suit.tile,
84     tiled_horiz = awful.layout.suit.tile.top,
85     floating = awful.layout.suit.floating,
86     maximised = awful.layout.suit.max
87 }
88 awful.layout.layouts = {
89     layouts.default,
90     layouts.tiled,
91     layouts.maximised,
92     layouts.floating,
93     layouts.default_horiz,
94     layouts.tiled_horiz,
95 }
96 -- }}}
97
98 -- {{{ Helper functions
99 local function client_menu_toggle_fn()
100     local instance = nil
101
102     return function ()
103         if instance and instance.wibox.visible then
104             instance:hide()
105             instance = nil
106         else
107             instance = awful.menu.clients({ theme = { width = 250 } })
108         end
109     end
110 end
111
112 local function set_wallpaper(s)
113     -- Wallpaper
114     if beautiful.wallpaper then
115         local wallpaper = beautiful.wallpaper
116         -- If wallpaper is a function, call it with the screen
117         if type(wallpaper) == "function" then
118             wallpaper = wallpaper(s)
119         end
120         gears.wallpaper.maximized(wallpaper, s, true)
121     end
122 end
123
124 local function move_mouse_to_area(a)
125     local coords = mouse.coords()
126     if (coords.x < a.x or
127         coords.x > (a.x+a.width) or
128         coords.y < a.y or
129         coords.y > (a.y+a.height)) then
130
131         mouse.coords({
132             x = a.x + a.width/2,
133             y = a.y + a.height/2,
134         }, true)
135     end
136 end
137
138 -- }}}
139
140 -- {{{ Menu
141 -- Create a launcher widget and a main menu
142 myawesomemenu = {
143    { "hotkeys", function() return false, hotkeys_popup.show_help end},
144    { "manual", terminal .. " -e man awesome" },
145    { "edit config", editor_cmd .. " " .. awesome.conffile },
146    { "restart", awesome.restart },
147    { "quit", function() awesome.quit() end}
148 }
149
150 local menu_awesome = { "awesome", myawesomemenu, beautiful.awesome_icon }
151 local menu_terminal = { "open terminal", terminal }
152
153 if has_fdo then
154     mymainmenu = freedesktop.menu.build({
155         before = { menu_awesome },
156         after =  { menu_terminal }
157     })
158 else
159     mymainmenu = awful.menu({
160         items = {
161                   menu_awesome,
162                   { "Debian", debian.menu.Debian_menu.Debian },
163                   menu_terminal,
164                 }
165     })
166 end
167
168
169 mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
170                                      menu = mymainmenu })
171
172 -- Menubar configuration
173 menubar.utils.terminal = terminal -- Set the terminal for applications that require it
174 -- }}}
175
176 -- {{{ Wibar
177 --local spacer = wibox.widget {
178 --    color = beautiful.bg_minimize,
179 --    forced_width = 4,
180 --    widget = wibox.widget.separator
181 --}
182 local function make_spacer(text)
183     local spacer = wibox.widget.textbox()
184     spacer:set_text(text or " │ ")
185     return spacer
186 end
187
188 -- Keyboard map indicator and switcher
189 mykeyboardlayout = awful.widget.keyboardlayout()
190
191 local lain_bat = lain.widget.bat({
192     batteries = {"BAT0", "BAT1"},
193     settings = function()
194         local delim = "↓"
195         if bat_now.status == "Charging" then delim = "↑"
196         elseif bat_now.status == "Unknown" then delim = "٭" end
197         widget:set_text(bat_now.perc .. "% " .. delim .. " " .. bat_now.time)
198     end,
199 })
200
201 -- Create a textclock widget
202 clocksarray = clocksarray.get_clocksarray("%a %d %b %H:%M:%S %Z", {
203 --        ["NZ"] = "Pacific/Auckland",
204         ["DE"] = "Europe/Berlin"
205     }, make_spacer())
206
207 -- Create a wibox for each screen and add it
208 local taglist_buttons = gears.table.join(
209                     awful.button({ }, 1, function(t) t:view_only() end),
210                     awful.button({ modkey }, 1, function(t)
211                                               if client.focus then
212                                                   client.focus:move_to_tag(t)
213                                               end
214                                           end),
215                     awful.button({ }, 3, awful.tag.viewtoggle),
216                     awful.button({ modkey }, 3, function(t)
217                                               if client.focus then
218                                                   client.focus:toggle_tag(t)
219                                               end
220                                           end),
221                     awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
222                     awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
223                 )
224
225 local tasklist_buttons = gears.table.join(
226                      awful.button({ }, 1, function (c)
227                                               if c == client.focus then
228                                                   -- I don't like click-minimising
229                                                   -- c.minimized = true
230                                               else
231                                                   -- Without this, the following
232                                                   -- :isvisible() makes no sense
233                                                   c.minimized = false
234                                                   if not c:isvisible() and c.first_tag then
235                                                       c.first_tag:view_only()
236                                                   end
237                                                   -- This will also un-minimize
238                                                   -- the client, if needed
239                                                   client.focus = c
240                                                   c:raise()
241                                               end
242                                           end),
243                      awful.button({ }, 3, client_menu_toggle_fn()),
244                      awful.button({ }, 4, function ()
245                                               awful.client.focus.byidx(1)
246                                           end),
247                      awful.button({ }, 5, function ()
248                                               awful.client.focus.byidx(-1)
249                                           end))
250 -- }}}
251
252 -- {{{ Screens
253
254 -- Re-set wallpaper when a screen's geometry changes (e.g. different resolution)
255 screen.connect_signal("property::geometry", set_wallpaper)
256
257 -- {{{ Basic setup for screens
258 local function screen_set_profile(s, profile)
259     s.profile = profile
260     s.outputstr = table.concat(gears.table.keys(s.outputs), "+")
261     s.name = s.profile .. "/" .. s.outputstr
262 end
263
264 awful.screen.connect_for_each_screen(function(s)
265
266     s.set_profile = screen_set_profile
267
268     -- Wallpaper
269     set_wallpaper(s)
270
271     -- Create a text widget to display screen name
272     s.namebox = wibox.container.background(wibox.widget.textbox(s.name),
273       beautiful.bg_minimize)
274
275     -- Create a promptbox for each screen
276     s.mypromptbox = awful.widget.prompt()
277     -- Create an imagebox widget which will contains an icon indicating which layout we're using.
278     -- We need one layoutbox per screen.
279     s.mylayoutbox = awful.widget.layoutbox(s)
280     s.mylayoutbox:buttons(awful.util.table.join(
281                            awful.button({ }, 1, function () awful.layout.inc( 1) end),
282                            awful.button({ }, 3, function () awful.layout.inc(-1) end),
283                            awful.button({ }, 4, function () awful.layout.inc( 1) end),
284                            awful.button({ }, 5, function () awful.layout.inc(-1) end)))
285     -- Create a taglist widget
286     s.mytaglist = awful.widget.taglist(s, awful.widget.taglist.filter.all, taglist_buttons)
287
288     -- Create a tasklist widget
289     s.mytasklist = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, tasklist_buttons)
290
291     -- Create the wibox, but only if there isn't one yet
292     if not s.mywibox then
293         s.mywibox = awful.wibar({ position = "top", screen = s })
294     end
295
296     -- Add widgets to the wibox
297     local right_widgets = gears.table.join(clocksarray, {
298         make_spacer(" "),
299         wibox.widget.systray(),
300         s.mylayoutbox,
301         layout = wibox.layout.fixed.horizontal,
302     })
303
304 --    if s == screen.primary then
305         right_widgets = gears.table.join({
306             make_spacer(" "),
307             ccwidgets.btc_widget,
308             make_spacer(),
309             ccwidgets.eth_widget,
310             make_spacer(),
311             fxwidgets.ecb_widget,
312             make_spacer(),
313             lain_bat.widget,
314             make_spacer(),
315         }, right_widgets)
316 --    end
317
318     s.mywibox:setup {
319         layout = wibox.layout.align.horizontal,
320         { -- Left widgets
321             layout = wibox.layout.fixed.horizontal,
322             --s.namebox,
323             s.mytaglist,
324             make_spacer(" "),
325             s.mypromptbox,
326         },
327         s.mytasklist, -- Middle widget
328         right_widgets,
329     }
330 end) -- }}}
331
332 -- {{{ autorandr integration
333 local function find_screen_by_pattern(pattern)
334     for s in screen do
335         print(s.name .. " :: " .. pattern)
336         if s.name:match(pattern) then
337             return s
338         end
339     end
340 end
341
342 local function get_target_screen_for_tag(tag)
343     local function primary_screen(reason)
344         local s = screen.primary
345         local msg = "  → primary screen \"" .. s.name .. "\""
346         if reason then msg = msg .. " (" .. reason .. ")" end
347         print(msg)
348         return s
349     end
350
351     print("Figuring out target screen for tag " .. tag.name .. "…")
352     if tag.targets then
353         if type(tag.targets) == "table" then
354             for _,target in ipairs(tag.targets) do
355                 local s = find_screen_by_pattern(target:gsub('%-', '%%-'))
356                 if s then
357                     print("  → screen " .. s.name)
358                     return s
359                 end
360             end
361         elseif tag.targets == "primary" then
362             return primary_screen("explicit request")
363         end
364         return primary_screen("no matching target in " .. table.concat(tag.targets, ","))
365     else
366         return primary_screen("no targets specified")
367     end
368 end
369
370 local function move_tag_to_target_screen(tag)
371     tag.screen = get_target_screen_for_tag(tag)
372 end
373
374 local function move_tags_to_target_screens()
375     for _,tag in ipairs(root.tags()) do
376         move_tag_to_target_screen(tag)
377     end
378 end
379
380 tag.connect_signal("request::screen", function(t)
381     -- throw the tag onto any other screen, it'll get reassigned later when
382     -- a new profile has been processed.
383     for s in screen do
384         if s ~= t.screen then
385             t.screen = s
386             t.selected = false
387             break
388         end
389     end
390     naughty.notify({
391         title = "Screen removed",
392         text = "Salvaged tab " .. t.name,
393     })
394 end)
395
396 function handle_new_autorandr_profile(newprofile)
397     -- The main idea here is that autorandr invokes this via awesome-client
398     -- after switching to a new profile. Awesome will have already set up all
399     -- the screens long before this function is called. Therefore, we just do
400     -- the necessary modifications to the existing screens, and move tags
401     -- around.
402
403     if not newprofile then
404         error("Missing new profile name")
405     end
406
407     naughty.notify({
408         preset = naughty.config.presets.low,
409         title = "New autorandr profile",
410         text = "Reconfiguring for profile <b>" .. newprofile .. "</b>",
411     })
412
413     for s in screen do
414         s:set_profile(newprofile)
415     end
416     move_tags_to_target_screens()
417 end
418
419 local function initialise_to_autorandr_profile()
420     local profile
421     profile = nil
422
423     local function process_line(line)
424         if profile then return end
425         local match = string.match(line, "^([^%s]+) %(detected%)")
426         if match then
427             profile = match
428         end
429     end
430
431     local function output_done()
432         if not profile then
433             error("autorandr detected no profile")
434             profile = "awesome"
435         end
436         handle_new_autorandr_profile(profile)
437     end
438
439     local function handle_exit(reason, code)
440         if not (reason == "exit" and code == 0) then
441             error("autorandr error: " .. reason .. ": " .. tostring(code))
442         end
443     end
444
445     awful.spawn.with_line_callback('autorandr', {
446         stdout = process_line,
447         output_done = output_done,
448         exit = handle_exit
449     })
450 end
451 awesome.connect_signal("startup", initialise_to_autorandr_profile)
452 -- }}}
453
454 -- }}}
455
456 -- {{{ Tags
457
458 local default_tag = {
459     name        = nil,
460     init        = true,
461     layout      = layouts.default,
462     fallback    = true,
463     targets     = "primary",
464 }
465 local default_tags = {}
466 for i = 1, 9 do
467     default_tags[i] = {}
468     for k,v in pairs(default_tag) do
469         default_tags[i][k] = v
470     end
471     default_tags[i].name = tostring(i)
472 end
473 default_tags[1].selected = true
474
475 default_tags = gears.table.join(default_tags, {
476   {
477     name        = "irc",
478     init        = true,
479     exclusive   = true,
480     layout      = layouts.tiled,
481     selected    = true,
482     exec_once   = { terminal .. " -name irc -e env MOSH_TITLE_NOPREFIX=true mosh --family=all -- irc-host tmux new -As irc irssi" },
483     instance    = { "irc" },
484     targets     = { "gauting/eDP-?1", "lehel/DisplayPort-2" },
485   },
486   {
487     name        = "[]",
488     init        = true,
489     exclusive   = true,
490     master_count = 0,
491     column_count = 3,
492     layout      = layouts.tiled,
493     selected    = false,
494     exec_once   = { "revolt" },
495     instance    = { "Revolt" },
496     targets     = { "gauting/eDP-?1", "lehel/DisplayPort-2" },
497   },
498   {
499     name        = "dflt",
500     init        = false,
501     fallback    = true,
502     layout      = layouts.floating,
503     volatile    = true,
504     selected    = true,
505   },
506   {
507     name        = "cal",
508     init        = true,
509     exclusive   = true,
510     layout      = layouts.default,
511     exec_once   = { "thunderbird" },
512     class       = { "thunderbird" },
513     targets     = { "gauting/eDP-?1", "lehel/DisplayPort-1" },
514   },
515   {
516     name        = "chr",
517     init        = true,
518     exclusive   = true,
519     layout      = layouts.default,
520     exec_once   = { "chromium" },
521     class       = { "Chromium" },
522     targets     = { "gauting/eDP-?1", "lehel/DisplayPort-1", "present/HDMI.*" },
523   },
524   {
525     name        = "ffx",
526     init        = true,
527     exclusive   = true,
528     layout      = layouts.default,
529     exec_once   = { "firefox" },
530     class       = { "Firefox" },
531     targets     = { "gauting/eDP-?1", "lehel/DisplayPort-1", "present/HDMI.*" },
532   },
533 })
534
535 if not tyrannical then
536
537 for _,t in ipairs(default_tags) do
538     if t.init then
539         t.screen = t.screen or screen.primary
540         t.layout = t.layout or layouts.default
541         local newt = th.add_tag(t.name, t, false)
542     end
543 end
544
545 else -- {{{ tyrannical is loaded
546 tyrannical.settings.default_layout = layouts.default
547 tyrannical.settings.master_width_factor = 0.5
548 tyrannical.settings.block_children_focus_stealing = true
549 tyrannical.settings.group_children = true
550
551 tyrannical.tags = default_tags
552
553 tyrannical.properties.size_hints_honor = { URxvt = false }
554
555 --XX---- Ignore the tag "exclusive" property for the following clients (matched by classes)
556 --XX--tyrannical.properties.intrusive = {
557 --XX--  "ksnapshot"     , "pinentry"       , "gtksu"     , "kcalc"        , "xcalc"               ,
558 --XX--  "feh"           , "Gradient editor", "About KDE" , "Paste Special", "Background color"    ,
559 --XX--  "kcolorchooser" , "plasmoidviewer" , "Xephyr"    , "kruler"       , "plasmaengineexplorer",
560 --XX--}
561 --XX--
562 --XX---- Ignore the tiled layout for the matching clients
563 --XX--tyrannical.properties.floating = {
564 --XX--  "MPlayer"      , "pinentry"        , "ksnapshot"  , "pinentry"     , "gtksu"          ,
565 --XX--  "xine"         , "feh"             , "kmix"       , "kcalc"        , "xcalc"          ,
566 --XX--  "yakuake"      , "Select Color$"   , "kruler"     , "kcolorchooser", "Paste Special"  ,
567 --XX--  "New Form"     , "Insert Picture"  , "kcharselect", "mythfrontend" , "plasmoidviewer"
568 --XX--}
569 --XX--
570 --XX---- Make the matching clients (by classes) on top of the default layout
571 --XX--tyrannical.properties.ontop = {
572 --XX--  "Xephyr"       , "ksnapshot"       , "kruler"
573 --XX--}
574 --XX--
575 --XX---- Force the matching clients (by classes) to be centered on the screen on init
576 --XX--tyrannical.properties.centered = {
577 --XX--  "kcalc"
578 --XX--}
579 end -- }}}
580
581 -- }}}
582
583 -- {{{ Mouse bindings
584 root.buttons(gears.table.join(
585     awful.button({ }, 3, function () mymainmenu:toggle() end),
586     awful.button({ }, 4, awful.tag.viewnext),
587     awful.button({ }, 5, awful.tag.viewprev)
588 ))
589 -- }}}
590
591 -- {{{ Key bindings
592
593 local function toggle_tag_by_name(tagname, exclusive)
594     return function()
595         local t = awful.tag.find_by_name(nil, tagname)
596         if t then
597             if exclusive then
598                 t:view_only()
599             else
600                 awful.tag.viewtoggle(t)
601             end
602             cf = awful.client.getmaster(t.screen)
603             if cf then
604                 cf:jump_to()
605             end
606         end
607     end
608 end
609
610 local function move_tags_to_screen_relative(direction)
611     local s = awful.screen.focused()
612     for _,tag in ipairs(s.selected_tags) do
613         print("index: " .. s.index .. " count: " .. screen:count())
614         tag.screen = screen[(s.index + screen:count() + direction) % screen.count()]
615     end
616 end
617
618 globalkeys = gears.table.join(
619     awful.key({ modkey,           }, "s",      hotkeys_popup.show_help,
620               {description="show help", group="awesome"}),
621     awful.key({ modkey,           }, "Left",   awful.tag.viewprev,
622               {description = "view previous", group = "tag"}),
623     awful.key({ modkey,           }, "Right",  awful.tag.viewnext,
624               {description = "view next", group = "tag"}),
625     awful.key({ modkey,           }, "Escape", awful.tag.history.restore,
626               {description = "go back", group = "tag"}),
627
628     awful.key({ modkey,           }, "k",
629         function ()
630             awful.client.focus.byidx( 1)
631         end,
632         {description = "focus next by index", group = "client"}
633     ),
634     awful.key({ modkey,           }, "j",
635         function ()
636             awful.client.focus.byidx(-1)
637         end,
638         {description = "focus previous by index", group = "client"}
639     ),
640
641     -- Layout manipulation
642     awful.key({ modkey, "Shift"   }, "k", function () awful.client.swap.byidx( 1)    end,
643               {description = "swap with next client by index", group = "client"}),
644     awful.key({ modkey, "Shift"   }, "j", function () awful.client.swap.byidx(-1)    end,
645               {description = "swap with previous client by index", group = "client"}),
646     awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative( 1) end,
647               {description = "focus the next screen", group = "screen"}),
648     awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative(-1) end,
649               {description = "focus the previous screen", group = "screen"}),
650     awful.key({ modkey, "Shift", "Control" }, "k", function () move_tags_to_screen_relative( 1) end,
651               {description = "move tags to the next screen", group = "screen"}),
652     awful.key({ modkey, "Shift", "Control" }, "j", function () move_tags_to_screen_relative(-1) end,
653               {description = "move tags to the previous screen", group = "screen"}),
654     awful.key({ modkey, "Shift"   }, "Return", awful.client.urgent.jumpto,
655               {description = "jump to urgent client", group = "client"}),
656     awful.key({ modkey,           }, "Tab",
657         function ()
658             awful.client.focus.history.previous()
659             if client.focus then
660                 client.focus:raise()
661             end
662         end,
663         {description = "go back", group = "client"}),
664
665     -- Standard program
666     awful.key({ modkey,           }, "Return", function () awful.spawn(terminal) end,
667               {description = "open a terminal", group = "launcher"}),
668     awful.key({ modkey,           }, "r", function()
669         package.loaded.rc = nil
670         require("rc")
671     end,
672               {description = "reload rc.lua", group = "awesome"}),
673     awful.key({ modkey, "Control" }, "r", awesome.restart,
674               {description = "reload awesome", group = "awesome"}),
675     awful.key({ modkey, "Shift"   }, "q", awesome.quit,
676               {description = "quit awesome", group = "awesome"}),
677
678     awful.key({ modkey,           }, "l",     function () awful.tag.incmwfact( 0.05)          end,
679               {description = "increase master width factor", group = "layout"}),
680     awful.key({ modkey,           }, "h",     function () awful.tag.incmwfact(-0.05)          end,
681               {description = "decrease master width factor", group = "layout"}),
682     awful.key({ modkey, "Shift"   }, "h",     function () awful.tag.incnmaster( 1, nil, true) end,
683               {description = "increase the number of master clients", group = "layout"}),
684     awful.key({ modkey, "Shift"   }, "l",     function () awful.tag.incnmaster(-1, nil, true) end,
685               {description = "decrease the number of master clients", group = "layout"}),
686     awful.key({ modkey, "Control" }, "h",     function () awful.tag.incncol( 1, nil, true)    end,
687               {description = "increase the number of columns", group = "layout"}),
688     awful.key({ modkey, "Control" }, "l",     function () awful.tag.incncol(-1, nil, true)    end,
689               {description = "decrease the number of columns", group = "layout"}),
690     awful.key({ modkey,           }, "space", function () awful.layout.inc( 1)                end,
691               {description = "select next", group = "layout"}),
692     awful.key({ modkey, "Shift"   }, "space", function () awful.layout.inc(-1)                end,
693               {description = "select previous", group = "layout"}),
694
695     awful.key({ modkey, "Control" }, "n",
696               function ()
697                   local c = awful.client.restore()
698                   -- Focus restored client
699                   if c then
700                       client.focus = c
701                       c:raise()
702                   end
703               end,
704               {description = "restore minimized", group = "client"}),
705
706     -- Prompt
707     awful.key({ cmdkey },            "r",
708               function ()
709                   local widget = awful.screen.focused().mypromptbox.widget
710                   local function spawn(command, args)
711                       gears.debug.dump(args)
712                       awful.spawn(command, args)
713                   end
714
715                   awful.prompt.run {
716                     prompt       = "Exec: ",
717                     bg_cursor    = '#ff0000',
718                     textbox      = widget,
719                     history_path = awful.util.get_cache_dir() .. "/history",
720                     completion_callback = awful.completion.shell,
721                     hooks = {
722                         -- Replace the 'normal' Return with a custom one
723                         {{         }, 'Return', function(command)
724                             spawn(command)
725                         end},
726                         -- Spawn method to spawn in the current tag
727                         {{'Mod1'   }, 'Return', function(command)
728                             spawn(command,{
729                                 intrusive = true,
730                                 tag       = mouse.screen.selected_tag
731                             })
732                         end},
733                         -- Spawn in the current tag as floating and on top
734                         {{'Shift'  }, 'Return', function(command)
735                             spawn(command,{
736                                 ontop     = true,
737                                 floating  = true,
738                                 tag       = mouse.screen.selected_tag
739                             })
740                         end},
741                         -- Spawn in a new tag
742                         {{'Control'}, 'Return', function(command)
743                             spawn(command,{
744                                 new_tag = true,
745                                 layout = layouts.default,
746                                 volatile = true,
747                             })
748                         end},
749                         -- Cancel
750                         {{         }, 'Escape', function(_) return end},
751                     },
752                 }
753         end,
754               {description = "run prompt", group = "launcher"}),
755
756     awful.key({ modkey }, "x",
757               function ()
758                   awful.prompt.run {
759                     prompt       = "Eval: ",
760                     bg_cursor    = '#ff0000',
761                     textbox      = awful.screen.focused().mypromptbox.widget,
762                     exe_callback = awful.util.eval,
763                     history_path = awful.util.get_cache_dir() .. "/history_eval"
764                   }
765               end,
766               {description = "lua execute prompt", group = "awesome"}),
767     -- Menubar
768     awful.key({ modkey }, "w", function() menubar.show() end,
769               {description = "show the menubar", group = "launcher"}),
770
771     -- Tag helpers
772     awful.key({ modkey,           }, "a", function()
773         th.add_tag(nil, {layout=layouts.default} ,true)
774     end,
775     {description = "add a tag", group = "tag"}),
776     awful.key({ modkey,           }, "d", th.delete_tag,
777               {description = "delete the current tag", group = "tag"}),
778     awful.key({ modkey, "Shift",           }, "a", function()
779         th.move_to_new_tag(nil, nil, { layout = layouts.maximised },true,true,true)
780     end,
781               {description = "add a volatile tag with the focused client", group = "tag"}),
782     awful.key({ modkey, "Shift", "Control" }, "a", function()
783         th.move_to_new_tag(nil, nil, { layout = layouts.maximised },false,true,true)
784     end,
785               {description = "add a permanent tag with the focused client", group = "tag"}),
786     awful.key({ modkey, "Mod1"   }, "a", th.copy_tag,
787               {description = "create a copy of the current tag", group = "tag"}),
788     awful.key({ modkey, "Control"   }, "a", th.rename_tag,
789               {description = "rename the current tag", group = "tag"}),
790     awful.key({ modkey, "Control", "Shift", "Mod1" }, "a", th.collect_orphan_clients_to_tag,
791               {description = "collect all orphaned clients", group = "client"}),
792
793     awful.key({ modkey }, "y", toggle_tag_by_name("irc", true),
794               {description = "view tag 'irc'", group = "tag"}),
795     awful.key({ modkey, "Control" }, "y", toggle_tag_by_name("irc"),
796               {description = "toggle tag 'irc'", group = "tag"}),
797     awful.key({ modkey }, "u", toggle_tag_by_name("[]", true),
798               {description = "view tag '[]'", group = "tag"}),
799     awful.key({ modkey, "Control" }, "u", toggle_tag_by_name("[]"),
800               {description = "toggle tag '[]'", group = "tag"}),
801     awful.key({ modkey }, "i", toggle_tag_by_name("cal", true),
802               {description = "view tag 'cal'", group = "tag"}),
803     awful.key({ modkey, "Control" }, "i", toggle_tag_by_name("cal"),
804               {description = "toggle tag 'cal'", group = "tag"}),
805     awful.key({ modkey }, "o", toggle_tag_by_name("chr", true),
806               {description = "view tag 'chr'", group = "tag"}),
807     awful.key({ modkey, "Control" }, "o", toggle_tag_by_name("chr"),
808               {description = "toggle tag 'chr'", group = "tag"}),
809     awful.key({ modkey }, "p", toggle_tag_by_name("ffx", true),
810               {description = "view tag 'ff'", group = "tag"}),
811     awful.key({ modkey, "Control" }, "p", toggle_tag_by_name("ffx"),
812               {description = "toggle tag 'ff'", group = "tag"}),
813 {})
814
815 clientkeys = gears.table.join(
816     awful.key({ modkey,           }, "f",
817         function (c)
818             c.fullscreen = not c.fullscreen
819             c:raise()
820         end,
821         {description = "toggle fullscreen", group = "client"}),
822     awful.key({ modkey, "Shift"   }, "c",      function (c) c:kill()                         end,
823               {description = "close", group = "client"}),
824     awful.key({ modkey, "Control" }, "space",  awful.client.floating.toggle                     ,
825               {description = "toggle floating", group = "client"}),
826     awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
827               {description = "move to master", group = "client"}),
828     awful.key({ modkey,           }, "z",      function (c) c:move_to_screen() end,
829               {description = "move to screen", group = "client"}),
830     awful.key({ modkey,           }, "t",      function (c) c.ontop = not c.ontop            end,
831               {description = "toggle keep on top", group = "client"}),
832     awful.key({ modkey,           }, "n",
833         function (c)
834             -- The client currently has the input focus, so it cannot be
835             -- minimized, since minimized clients can't have the focus.
836             c.minimized = true
837         end ,
838         {description = "minimize", group = "client"}),
839     awful.key({ modkey,           }, "m",
840         function (c)
841             c.maximized = not c.maximized
842             c.maximized_horizontal = false
843             c.maximized_vertical = false
844             c:raise()
845         end ,
846         {description = "(un)maximize", group = "client"}),
847     awful.key({ modkey, "Control" }, "m",
848         function (c)
849             c.maximized_vertical = not c.maximized_vertical
850             c:raise()
851         end ,
852         {description = "(un)maximize vertically", group = "client"}),
853     awful.key({ modkey, "Shift"   }, "m",
854         function (c)
855             c.maximized_horizontal = not c.maximized_horizontal
856             c:raise()
857         end ,
858         {description = "(un)maximize horizontally", group = "client"})
859 )
860
861 -- Bind all key numbers to tags.
862 -- Be careful: we use keycodes to make it work on any keyboard layout.
863 -- This should map on the top row of your keyboard, usually 1 to 9.
864 for i = 1, 9 do
865     globalkeys = gears.table.join(globalkeys,
866         -- View tag only.
867         awful.key({ modkey }, "#" .. i + 9, toggle_tag_by_name(tostring(i), true),
868                   {description = "view tag #"..i, group = "tag"}),
869         -- Toggle tag display.
870         awful.key({ modkey, "Control" }, "#" .. i + 9, toggle_tag_by_name(tostring(i)),
871                   {description = "toggle tag #" .. i, group = "tag"}),
872         -- Move client to tag.
873         awful.key({ modkey, "Shift" }, "#" .. i + 9,
874                   function ()
875                       if client.focus then
876                           local tag = awful.tag.find_by_name(screen.primary, tostring(i))
877                           if tag then
878                               client.focus:move_to_tag(tag)
879                           end
880                      end
881                   end,
882                   {description = "move focused client to tag #"..i, group = "tag"}),
883         -- Toggle tag on focused client.
884         awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
885                   function ()
886                       if client.focus then
887                           local tag = awful.tag.find_by_name(screen.primary, tostring(i))
888                           if tag then
889                               client.focus:toggle_tag(tag)
890                           end
891                       end
892                   end,
893                   {description = "toggle focused client on tag #" .. i, group = "tag"})
894     )
895 end
896
897 clientbuttons = gears.table.join(
898     awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
899     awful.button({ modkey }, 1, awful.mouse.client.move),
900     awful.button({ modkey }, 3, awful.mouse.client.resize))
901
902 -- misc apps
903 globalkeys = awful.util.table.join(globalkeys,
904 awful.key({ cmdkey }, "n", function () awful.spawn("firefox") end),
905 awful.key({ cmdkey }, "c", function () awful.spawn("chromium --enable-remote-extensions") end),
906 awful.key({ cmdkey }, "y", function () awful.spawn(terminal .. " -e ipython3") end),
907 awful.key({ cmdkey }, "m", function () awful.spawn(terminal .. " -name mutt -e mutt") end),
908 awful.key({ cmdkey }, "t", function () awful.spawn("thunderbird") end),
909 awful.key({ cmdkey }, "g", function () awful.spawn("gscan2pdf") end),
910 awful.key({ cmdkey, "Shift" }, "v", function () awful.spawn("virt-manager") end),
911 awful.key({ cmdkey }, "l", function () awful.spawn("libreoffice") end),
912 awful.key({ cmdkey }, "v", function () awful.spawn("remmina") end),
913 awful.key({ cmdkey }, "p", function () awful.spawn("pavucontrol") end),
914 awful.key({ cmdkey }, "i", function () awful.spawn(terminal .. " -name irc -e env MOSH_TITLE_NOPREFIX=true mosh --family=all -- irc-host tmux new -As irc irssi") end),
915 awful.key({ cmdkey }, "x", function ()
916     awful.spawn("xautolock -enable")
917     awful.spawn("xautolock -locknow")
918 end),
919 awful.key({ cmdkey, "Shift" }, "x", function () awful.spawn("xautolock -disable") end),
920
921 awful.key({ cmdkey }, "BackSpace", function () awful.spawn("pkill -USR1 offlineimap") end),
922
923 -- function keys
924 awful.key(nil, "XF86ScreenSaver", function () awful.spawn("xset dpms force off") end),
925 awful.key(nil, "XF86AudioMute", function () awful.spawn("pactl set-sink-mute @DEFAULT_SINK@ toggle") end),
926 awful.key({ cmdkey }, "End", function () awful.spawn("pactl set-sink-mute @DEFAULT_SINK@ toggle") end),
927 awful.key(nil, "XF86AudioLowerVolume", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ -2%") end),
928 awful.key({ cmdkey }, "Next", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ -2%") end),
929 awful.key(nil, "XF86AudioRaiseVolume", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ +2%") end),
930 awful.key({ cmdkey }, "Prior", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ +2%") end),
931 awful.key(nil, "XF86AudioMicMute", function () awful.spawn("pactl set-source-mute @DEFAULT_SOURCE@ toggle") end),
932 awful.key({ cmdkey }, "Home", function () awful.spawn("pactl set-source-mute @DEFAULT_SOURCE@ toggle") end),
933 awful.key({ cmdkey }, "Insert", function () awful.spawn("pa_cycle_default source") end),
934 awful.key({ cmdkey }, "Delete", function () awful.spawn("pa_cycle_default sink") end),
935 awful.key(nil, "XF86MonBrightnessDown", function () awful.spawn("light -U 10") end),
936 awful.key(nil, "XF86MonBrightnessUp", function () awful.spawn("light -A 10") end),
937 awful.key(nil, "XF86Display", function () awful.spawn("autorandr --change --force"); initialise_to_autorandr_profile() end),
938 awful.key(nil, "XF86AudioStop", function () awful.spawn("autorandr --change --force"); initialise_to_autorandr_profile() end),
939 awful.key(nil, "XF86WLAN", function () awful.spawn("") end),
940 awful.key(nil, "XF86Tools", function () awful.spawn("") end),
941 awful.key(nil, "XF86Search", function () awful.spawn("") end),
942 awful.key(nil, "XF86LaunchA", function () awful.spawn("") end),
943 awful.key(nil, "XF86Explorer", function () awful.spawn("") end),
944 awful.key(nil, "XF86Favorites", function () awful.spawn("systemctl suspend") end),
945
946 awful.key({ cmdkey }, "Multi_key", function () run_output_notify("flameshot gui", "Output") end),
947 awful.key({ cmdkey, "Shift" }, "Multi_key", function () run_output_notify("flameshot full --delay 2000 --clipboard", "Output") end),
948
949 awful.key({ cmdkey }, "Up", function () awful.spawn("pap prev") end),
950 awful.key({ cmdkey }, "Left", function () awful.spawn("pap seek -10") end),
951 awful.key({ cmdkey, "Shift" }, "Left", function () awful.spawn("pap seek -60") end),
952 awful.key({ cmdkey }, "Down", function () awful.spawn("pap next") end),
953 awful.key({ cmdkey }, "Right", function () awful.spawn("pap seek +10") end),
954 awful.key({ cmdkey, "Shift" }, "Right", function () awful.spawn("pap seek +60") end),
955 awful.key({ cmdkey }, "space", function () awful.spawn("pap pause") end),
956 awful.key({ cmdkey }, "\\", function () run_output_notify("pap info", "Track info") end),
957 awful.key({ cmdkey }, "]", function () run_output_notify("pap list", "Playlist") end)
958 )
959
960 function run_output_notify(cmd, title)
961     awful.spawn.easy_async(cmd, function(stdout, stderr, reason, exit_code)
962         if #stdout > 1 then
963             naughty.notify({
964                 preset = naughty.config.presets.low,
965                 title = title,
966                 text = stdout})
967             end
968         end)
969 end
970
971 -- Set keys
972 root.keys(globalkeys)
973 -- }}}
974
975 -- {{{ Rules
976 -- Rules to apply to new clients (through the "manage" signal).
977
978 local function float_client_in_the_middle_with_margins(client, leftright, topbottom)
979     local wa = client.screen.workarea
980     if topbottom then
981         client.y = wa.y + topbottom
982         client.height = wa.height - 2*topbottom
983     else
984         client.y = wa.y + (wa.height - client.height)/2
985     end
986     if leftright then
987         client.x = wa.x + leftright
988         client.width = wa.width - 2*leftright
989     else
990         client.x = wa.x + (wa.width - client.width)/2
991     end
992 end
993
994 local function move_to_tag_by_name(s, tagname)
995     return function(c)
996         local t = awful.tag.find_by_name(s, tagname)
997         if not t then
998             error("No tag by the name of " .. tagname)
999             return
1000         end
1001         c:move_to_tag(t)
1002     end
1003 end
1004
1005 local function move_to_tag_or_create_volatile(s, tagname)
1006     return function(c)
1007         local t = awful.tag.find_by_name(s, tagname)
1008         if t then
1009             c:move_to_tag(t)
1010         else
1011             th.move_to_new_tag(c, tagname, {}, true, true, true)
1012         end
1013     end
1014 end
1015
1016 awful.rules.rules = {
1017     -- All clients will match this rule.
1018     { rule = { },
1019       properties = { border_width = beautiful.border_width,
1020                      border_color = beautiful.border_normal,
1021                      focus = awful.client.focus.filter,
1022                      raise = true,
1023                      keys = clientkeys,
1024                      buttons = clientbuttons,
1025                      screen = awful.screen.preferred,
1026                      placement = awful.placement.no_overlap+awful.placement.no_offscreen,
1027                      floating = false,
1028                      maximized = false,
1029                  },
1030     },
1031     { rule = { type = "dialog" },
1032       properties = { floating = true,
1033                      ontop = true,
1034                      skip_taskbar = true,
1035                      urgent = true,
1036                      --new_tag = true,
1037                      --switchtotag = true,
1038                      placement = awful.placement.centered
1039                    }
1040     },
1041     { rule = { class = "URxvt" },
1042       properties = { size_hints_honor = false, }
1043     },
1044     { rule = { instance = "irc" },
1045       callback = move_to_tag_by_name(nil, "irc"),
1046     },
1047     { rule = { class = "scrcpy" },
1048       callback = move_to_tag_by_name(nil, "[]"),
1049     },
1050     { rule_any = { class = { "Firefox", "firefox" } },
1051       callback = move_to_tag_by_name(nil, "ffx"),
1052     },
1053     { rule = { class = "Chromium" },
1054       callback = move_to_tag_by_name(nil, "chr"),
1055     },
1056     { rule_any = { class = { "thunderbird", "Thunderbird" } },
1057       callback = move_to_tag_by_name(nil, "cal"),
1058     },
1059     { rule = { instance = "mutt" },
1060       properties = {
1061           new_tag = {
1062               name = "mutt",
1063               layout = awful.layout.suit.fair.horizontal,
1064               volatile = true
1065           },
1066           switchtotag = true,
1067       },
1068     },
1069     { rule_any = { class = { "zoom" } },
1070       callback = move_to_tag_or_create_volatile(nil, "Zoom"),
1071     },
1072     { rule_any = { class = { "Ssvnc.tcl" },
1073                    class = { "Ssvnc" },
1074                    name = { "SSL/SSH VNC Viewer.-" },
1075                  },
1076       callback = move_to_tag_or_create_volatile(nil, "SSVNC"),
1077     },
1078     { rule_any = { class = {
1079         "Gxmessage",
1080         "Pinentry"
1081     }},
1082       properties = { floating = true,
1083                      maximized = false,
1084                      focus = true,
1085                      placement = awful.placement.centered,
1086                    },
1087     },
1088     { rule_any = { instance = {
1089         "tridactyl-edit",
1090         "pdfshuffler",
1091         "vlc",
1092         "pavucontrol"
1093     }},
1094       properties = { floating = true,
1095                      maximized = false,
1096                      focus = true,
1097                      placement = awful.placement.centered,
1098                    },
1099     },
1100     { rule_any = { class = {
1101                         "Gimp",
1102                         "Inkscape",
1103                         "Pitivi",
1104                         "Audacity",
1105                         "Microsoft Teams - Preview",
1106                         "org.remmina.Remmina",
1107                     },
1108                     instance = {
1109                         "libreoffice",
1110                     }
1111                 },
1112       except_any = { type = { "dialog" } },
1113       properties = { new_tag = {
1114                         layout = layouts.maximised,
1115                         volatile = true,
1116                     },
1117                      --switchtotag = true,
1118                      focus = true,
1119                    },
1120                },
1121     { rule_any = { class = {
1122                         "Gscan2pdf",
1123                     },
1124                 },
1125       except_any = { type = { "dialog" } },
1126       properties = { new_tag = {
1127                         layout = layouts.default,
1128                         volatile = true,
1129                     },
1130                     floating = true,
1131                     maximized = false,
1132                     focus = true,
1133                     placement = awful.placement.centered,
1134                     switchtotag = true,
1135                     focus = true,
1136                    },
1137                },
1138 --XX--    { rule = { class = "Gscan2pdf" },
1139 --XX--               properties = {
1140 --XX--                   switchtotag = true
1141 --XX--               },
1142 --XX--               callback = move_to_tag(1, 5)
1143 --XX--           },
1144 --XX--    { rule = { name = "gscan2pdf .*" },
1145 --XX--               properties = {
1146 --XX--                   floating = false,
1147 --XX--               },
1148 --XX--           },
1149 --XX--    { rule = { class = "Thunar", type = "normal" },
1150 --XX--               properties = {
1151 --XX--                   floating = false,
1152 --XX--               },
1153 --XX--           },
1154 --XX--    { rule = { class = "Pinentry", instance = "pinentry" },
1155 --XX--               properties = {
1156 --XX--                   floating = true,
1157 --XX--               },
1158 --XX--           },
1159 --XX--    { rule = { class = "Gxmessage" },
1160 --XX--               properties = {
1161 --XX--                   floating = true,
1162 --XX--               },
1163 --XX--           },
1164 --XX--}
1165 }
1166 -- }}}
1167
1168 -- {{{ Signals
1169 -- Signal function to execute when a new client appears.
1170 client.connect_signal("manage", function (c)
1171     -- Set the windows at the slave,
1172     -- i.e. put it at the end of others instead of setting it master.
1173     -- if not awesome.startup then awful.client.setslave(c) end
1174     --if not awesome.startup then
1175     --    local t = awful.screen.focused().selected_tag
1176     --    if t.name == "xmutt" then
1177     --        awful.client.setslave(c)
1178     --    end
1179     --end
1180
1181     if awesome.startup and
1182       not c.size_hints.user_position
1183       and not c.size_hints.program_position then
1184         -- Prevent clients from being unreachable after screen count changes.
1185         awful.placement.no_offscreen(c)
1186     end
1187
1188     c.maximized_horizontal = false
1189     c.maximized_vertical = false
1190 end)
1191
1192 -- Add a titlebar if titlebars_enabled is set to true in the rules.
1193 client.connect_signal("request::titlebars", function(c)
1194     -- buttons for the titlebar
1195     local buttons = gears.table.join(
1196         awful.button({ }, 1, function()
1197             client.focus = c
1198             c:raise()
1199             awful.mouse.client.move(c)
1200         end),
1201         awful.button({ }, 3, function()
1202             client.focus = c
1203             c:raise()
1204             awful.mouse.client.resize(c)
1205         end)
1206     )
1207
1208     awful.titlebar(c) : setup {
1209         { -- Left
1210             awful.titlebar.widget.iconwidget(c),
1211             buttons = buttons,
1212             layout  = wibox.layout.fixed.horizontal
1213         },
1214         { -- Middle
1215             { -- Title
1216                 align  = "center",
1217                 widget = awful.titlebar.widget.titlewidget(c)
1218             },
1219             buttons = buttons,
1220             layout  = wibox.layout.flex.horizontal
1221         },
1222         { -- Right
1223             awful.titlebar.widget.floatingbutton (c),
1224             awful.titlebar.widget.maximizedbutton(c),
1225             awful.titlebar.widget.stickybutton   (c),
1226             awful.titlebar.widget.ontopbutton    (c),
1227             awful.titlebar.widget.closebutton    (c),
1228             layout = wibox.layout.fixed.horizontal()
1229         },
1230         layout = wibox.layout.align.horizontal
1231     }
1232 end)
1233
1234 -- Enable sloppy focus, so that focus follows mouse.
1235 client.connect_signal("mouse::enter", function(c)
1236     if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
1237         and awful.client.focus.filter(c) then
1238         client.focus = c
1239     end
1240 --17 18:03 < psychon> madduck: yes. In the default config at the very end there is code that actives a client on mouse::enter. Just add if c.class == "whatever virt-viewer uses" then return end to that, or 
1241 --                    something like this
1242 end)
1243
1244 client.connect_signal("focus", function(c)
1245     c.border_color = beautiful.border_focus
1246 end)
1247 client.connect_signal("unfocus", function(c)
1248     c.border_color = beautiful.border_normal
1249 end)
1250
1251 awful.ewmh.add_activate_filter(function(c, context, hints)
1252     if context == "ewmh" then
1253         if (c.class == "Firefox-esr" or c.class == "Firefox") then
1254             return false
1255         end
1256     end
1257 end)
1258
1259 client.connect_signal("request::activate", function(c, context, hints)
1260     if gears.table.hasitem({
1261         "client.focus.byidx",
1262         "client.jumpto",
1263         "autofocus.check_focus",
1264         "rules",
1265         "ewmh",
1266     }, context) then
1267         gears.timer.delayed_call(function()
1268             -- we need a delayed call so that we execute *after layout changes
1269             if hints.raise and c == client.focus and client.focus:isvisible() then
1270                 move_mouse_to_area(client.focus)
1271             end
1272         end)
1273     end
1274 end)
1275
1276 -- vim:ft=lua:sw=4:sts=4:ts=4:et