]> 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:

55117daf891abf2c29e28e3f93ea3320d1493915
[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, "XF86Calculator", function () awful.spawn(terminal .. " -e ipython3 --profile=calc") end),
945 awful.key(nil, "XF86Favorites", function () awful.spawn("systemctl suspend") end),
946
947 awful.key({ cmdkey }, "Multi_key", function () run_output_notify("flameshot gui", "Output") end),
948 awful.key({ cmdkey, "Shift" }, "Multi_key", function () run_output_notify("flameshot full --delay 2000 --clipboard", "Output") end),
949
950 awful.key({ cmdkey }, "Up", function () awful.spawn("pap prev") end),
951 awful.key({ cmdkey }, "Left", function () awful.spawn("pap seek -10") end),
952 awful.key({ cmdkey, "Shift" }, "Left", function () awful.spawn("pap seek -60") end),
953 awful.key({ cmdkey }, "Down", function () awful.spawn("pap next") end),
954 awful.key({ cmdkey }, "Right", function () awful.spawn("pap seek +10") end),
955 awful.key({ cmdkey, "Shift" }, "Right", function () awful.spawn("pap seek +60") end),
956 awful.key({ cmdkey }, "space", function () awful.spawn("pap pause") end),
957 awful.key({ cmdkey }, "\\", function () run_output_notify("pap info", "Track info") end),
958 awful.key({ cmdkey }, "]", function () run_output_notify("pap list", "Playlist") end)
959 )
960
961 function run_output_notify(cmd, title)
962     awful.spawn.easy_async(cmd, function(stdout, stderr, reason, exit_code)
963         if #stdout > 1 then
964             naughty.notify({
965                 preset = naughty.config.presets.low,
966                 title = title,
967                 text = stdout})
968             end
969         end)
970 end
971
972 -- Set keys
973 root.keys(globalkeys)
974 -- }}}
975
976 -- {{{ Rules
977 -- Rules to apply to new clients (through the "manage" signal).
978
979 local function float_client_in_the_middle_with_margins(client, leftright, topbottom)
980     local wa = client.screen.workarea
981     if topbottom then
982         client.y = wa.y + topbottom
983         client.height = wa.height - 2*topbottom
984     else
985         client.y = wa.y + (wa.height - client.height)/2
986     end
987     if leftright then
988         client.x = wa.x + leftright
989         client.width = wa.width - 2*leftright
990     else
991         client.x = wa.x + (wa.width - client.width)/2
992     end
993 end
994
995 local function move_to_tag_by_name(s, tagname)
996     return function(c)
997         local t = awful.tag.find_by_name(s, tagname)
998         if not t then
999             error("No tag by the name of " .. tagname)
1000             return
1001         end
1002         c:move_to_tag(t)
1003     end
1004 end
1005
1006 local function move_to_tag_or_create_volatile(s, tagname)
1007     return function(c)
1008         local t = awful.tag.find_by_name(s, tagname)
1009         if t then
1010             c:move_to_tag(t)
1011         else
1012             th.move_to_new_tag(c, tagname, {}, true, true, true)
1013         end
1014     end
1015 end
1016
1017 awful.rules.rules = {
1018     -- All clients will match this rule.
1019     { rule = { },
1020       properties = { border_width = beautiful.border_width,
1021                      border_color = beautiful.border_normal,
1022                      focus = awful.client.focus.filter,
1023                      raise = true,
1024                      keys = clientkeys,
1025                      buttons = clientbuttons,
1026                      screen = awful.screen.preferred,
1027                      placement = awful.placement.no_overlap+awful.placement.no_offscreen,
1028                      floating = false,
1029                      maximized = false,
1030                  },
1031     },
1032     { rule = { type = "dialog" },
1033       properties = { floating = true,
1034                      ontop = true,
1035                      skip_taskbar = true,
1036                      urgent = true,
1037                      --new_tag = true,
1038                      --switchtotag = true,
1039                      placement = awful.placement.centered
1040                    }
1041     },
1042     { rule = { class = "URxvt" },
1043       properties = { size_hints_honor = false, }
1044     },
1045     { rule = { instance = "irc" },
1046       callback = move_to_tag_by_name(nil, "irc"),
1047     },
1048     { rule = { class = "scrcpy" },
1049       callback = move_to_tag_by_name(nil, "[]"),
1050     },
1051     { rule_any = { class = { "Firefox", "firefox" } },
1052       callback = move_to_tag_by_name(nil, "ffx"),
1053     },
1054     { rule = { class = "Chromium" },
1055       callback = move_to_tag_by_name(nil, "chr"),
1056     },
1057     { rule_any = { class = { "thunderbird", "Thunderbird" } },
1058       callback = move_to_tag_by_name(nil, "cal"),
1059     },
1060     { rule = { instance = "mutt" },
1061       properties = {
1062           new_tag = {
1063               name = "mutt",
1064               layout = awful.layout.suit.fair.horizontal,
1065               volatile = true
1066           },
1067           switchtotag = true,
1068       },
1069     },
1070     { rule_any = { class = { "zoom" } },
1071       callback = move_to_tag_or_create_volatile(nil, "Zoom"),
1072     },
1073     { rule_any = { class = { "Ssvnc.tcl" },
1074                    class = { "Ssvnc" },
1075                    name = { "SSL/SSH VNC Viewer.-" },
1076                  },
1077       callback = move_to_tag_or_create_volatile(nil, "SSVNC"),
1078     },
1079     { rule_any = { class = {
1080         "Gxmessage",
1081         "Pinentry"
1082     }},
1083       properties = { floating = true,
1084                      maximized = false,
1085                      focus = true,
1086                      placement = awful.placement.centered,
1087                    },
1088     },
1089     { rule_any = { instance = {
1090         "tridactyl-edit",
1091         "pdfshuffler",
1092         "vlc",
1093         "pavucontrol"
1094     }},
1095       properties = { floating = true,
1096                      maximized = false,
1097                      focus = true,
1098                      placement = awful.placement.centered,
1099                    },
1100     },
1101     { rule_any = { class = {
1102                         "Gimp",
1103                         "Inkscape",
1104                         "Pitivi",
1105                         "Audacity",
1106                         "Microsoft Teams - Preview",
1107                         "org.remmina.Remmina",
1108                     },
1109                     instance = {
1110                         "libreoffice",
1111                     }
1112                 },
1113       except_any = { type = { "dialog" } },
1114       properties = { new_tag = {
1115                         layout = layouts.maximised,
1116                         volatile = true,
1117                     },
1118                      --switchtotag = true,
1119                      focus = true,
1120                    },
1121                },
1122     { rule_any = { class = {
1123                         "Gscan2pdf",
1124                     },
1125                 },
1126       except_any = { type = { "dialog" } },
1127       properties = { new_tag = {
1128                         layout = layouts.default,
1129                         volatile = true,
1130                     },
1131                     floating = true,
1132                     maximized = false,
1133                     focus = true,
1134                     placement = awful.placement.centered,
1135                     switchtotag = true,
1136                     focus = true,
1137                    },
1138                },
1139 --XX--    { rule = { class = "Gscan2pdf" },
1140 --XX--               properties = {
1141 --XX--                   switchtotag = true
1142 --XX--               },
1143 --XX--               callback = move_to_tag(1, 5)
1144 --XX--           },
1145 --XX--    { rule = { name = "gscan2pdf .*" },
1146 --XX--               properties = {
1147 --XX--                   floating = false,
1148 --XX--               },
1149 --XX--           },
1150 --XX--    { rule = { class = "Thunar", type = "normal" },
1151 --XX--               properties = {
1152 --XX--                   floating = false,
1153 --XX--               },
1154 --XX--           },
1155 --XX--    { rule = { class = "Pinentry", instance = "pinentry" },
1156 --XX--               properties = {
1157 --XX--                   floating = true,
1158 --XX--               },
1159 --XX--           },
1160 --XX--    { rule = { class = "Gxmessage" },
1161 --XX--               properties = {
1162 --XX--                   floating = true,
1163 --XX--               },
1164 --XX--           },
1165 --XX--}
1166 }
1167 -- }}}
1168
1169 -- {{{ Signals
1170 -- Signal function to execute when a new client appears.
1171 client.connect_signal("manage", function (c)
1172     -- Set the windows at the slave,
1173     -- i.e. put it at the end of others instead of setting it master.
1174     -- if not awesome.startup then awful.client.setslave(c) end
1175     --if not awesome.startup then
1176     --    local t = awful.screen.focused().selected_tag
1177     --    if t.name == "xmutt" then
1178     --        awful.client.setslave(c)
1179     --    end
1180     --end
1181
1182     if awesome.startup and
1183       not c.size_hints.user_position
1184       and not c.size_hints.program_position then
1185         -- Prevent clients from being unreachable after screen count changes.
1186         awful.placement.no_offscreen(c)
1187     end
1188
1189     c.maximized_horizontal = false
1190     c.maximized_vertical = false
1191 end)
1192
1193 -- Add a titlebar if titlebars_enabled is set to true in the rules.
1194 client.connect_signal("request::titlebars", function(c)
1195     -- buttons for the titlebar
1196     local buttons = gears.table.join(
1197         awful.button({ }, 1, function()
1198             client.focus = c
1199             c:raise()
1200             awful.mouse.client.move(c)
1201         end),
1202         awful.button({ }, 3, function()
1203             client.focus = c
1204             c:raise()
1205             awful.mouse.client.resize(c)
1206         end)
1207     )
1208
1209     awful.titlebar(c) : setup {
1210         { -- Left
1211             awful.titlebar.widget.iconwidget(c),
1212             buttons = buttons,
1213             layout  = wibox.layout.fixed.horizontal
1214         },
1215         { -- Middle
1216             { -- Title
1217                 align  = "center",
1218                 widget = awful.titlebar.widget.titlewidget(c)
1219             },
1220             buttons = buttons,
1221             layout  = wibox.layout.flex.horizontal
1222         },
1223         { -- Right
1224             awful.titlebar.widget.floatingbutton (c),
1225             awful.titlebar.widget.maximizedbutton(c),
1226             awful.titlebar.widget.stickybutton   (c),
1227             awful.titlebar.widget.ontopbutton    (c),
1228             awful.titlebar.widget.closebutton    (c),
1229             layout = wibox.layout.fixed.horizontal()
1230         },
1231         layout = wibox.layout.align.horizontal
1232     }
1233 end)
1234
1235 -- Enable sloppy focus, so that focus follows mouse.
1236 client.connect_signal("mouse::enter", function(c)
1237     if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
1238         and awful.client.focus.filter(c) then
1239         client.focus = c
1240     end
1241 --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 
1242 --                    something like this
1243 end)
1244
1245 client.connect_signal("focus", function(c)
1246     c.border_color = beautiful.border_focus
1247 end)
1248 client.connect_signal("unfocus", function(c)
1249     c.border_color = beautiful.border_normal
1250 end)
1251
1252 awful.ewmh.add_activate_filter(function(c, context, hints)
1253     if context == "ewmh" then
1254         if (c.class == "Firefox-esr" or c.class == "Firefox") then
1255             return false
1256         end
1257     end
1258 end)
1259
1260 client.connect_signal("request::activate", function(c, context, hints)
1261     if gears.table.hasitem({
1262         "client.focus.byidx",
1263         "client.jumpto",
1264         "autofocus.check_focus",
1265         "rules",
1266         "ewmh",
1267     }, context) then
1268         gears.timer.delayed_call(function()
1269             -- we need a delayed call so that we execute *after layout changes
1270             if hints.raise and c == client.focus and client.focus:isvisible() then
1271                 move_mouse_to_area(client.focus)
1272             end
1273         end)
1274     end
1275 end)
1276
1277 -- vim:ft=lua:sw=4:sts=4:ts=4:et