]> git.madduck.net Git - etc/awesome.git/blobdiff - .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:

add virt tab
[etc/awesome.git] / .config / awesome / rc.lua
index 5a4db6934974182ac822b3522d3658825278ab76..afbcb7d233705a245ce5368af86146000313301b 100644 (file)
@@ -1,10 +1,13 @@
 -- {{{ Imports
+
 -- Standard awesome library
 local gears = require("gears")
 local awful = require("awful")
 require("awful.autofocus")
 -- Widget and layout library
 local wibox = require("wibox")
+-- Tyrannical tab handling
+--local tyrannical = require("tyrannical")
 -- Theme handling library
 local beautiful = require("beautiful")
 local xrdb = beautiful.xresources
@@ -20,10 +23,12 @@ require("awful.hotkeys_popup.keys")
 local debian = require("debian.menu")
 local has_fdo, freedesktop = pcall(require, "freedesktop")
 -- Other libraries
-local tblutils = require("tblutils")
 local lain = require("lain")
 local ccwidgets = require("cryptocoin_widgets")
+--local fxwidgets = require("forex_widgets")
 local clocksarray = require("clocksarray")
+local dbg = require("debugfunc")
+local th = require("taghelpers")
 -- }}}
 
 -- {{{ Error handling
@@ -56,11 +61,10 @@ end
 --xrdb.set_dpi(120, screen[2])
 
 -- Themes define colours, icons, font and wallpapers.
-beautiful.init(gears.filesystem.get_themes_dir() .. "default/theme.lua")
-beautiful.font = 'Sans 10'
+beautiful.init(gears.filesystem.get_configuration_dir () .. "theme/theme.lua")
 
 -- This is used later as the default terminal and editor to run.
-terminal = "x-terminal-emulator"
+terminal = "rxvt-unicode"
 editor = os.getenv("EDITOR") or "editor"
 editor_cmd = terminal .. " -e " .. editor
 
@@ -73,29 +77,22 @@ modkey = "Mod4"
 cmdkey = "Mod3"
 
 -- Table of layouts to cover with awful.layout.inc, order matters.
+local layouts = {
+    default = awful.layout.suit.fair,
+    default_horiz = awful.layout.suit.fair.horizontal,
+    tiled = awful.layout.suit.tile,
+    tiled_horiz = awful.layout.suit.tile.top,
+    floating = awful.layout.suit.floating,
+    maximised = awful.layout.suit.max
+}
 awful.layout.layouts = {
-    awful.layout.suit.floating,
-    awful.layout.suit.tile,
-    awful.layout.suit.tile.left,
-    awful.layout.suit.tile.bottom,
-    awful.layout.suit.tile.top,
-    awful.layout.suit.fair,
-    awful.layout.suit.fair.horizontal,
-    awful.layout.suit.spiral,
-    awful.layout.suit.spiral.dwindle,
-    awful.layout.suit.max,
-    awful.layout.suit.max.fullscreen,
-    awful.layout.suit.magnifier,
-    awful.layout.suit.corner.nw,
-    -- awful.layout.suit.corner.ne,
-    -- awful.layout.suit.corner.sw,
-    -- awful.layout.suit.corner.se,
+    layouts.default,
+    layouts.tiled,
+    layouts.maximised,
+    layouts.floating,
+    layouts.default_horiz,
+    layouts.tiled_horiz,
 }
-
-layout_default = awful.layout.layouts[6]
-layout_tiled = awful.layout.layouts[2]
-layout_maximised = awful.layout.layouts[10]
-layout_floating = awful.layout.layouts[1]
 -- }}}
 
 -- {{{ Helper functions
@@ -123,6 +120,21 @@ local function set_wallpaper(s)
         gears.wallpaper.maximized(wallpaper, s, true)
     end
 end
+
+local function move_mouse_to_area(a)
+    local coords = mouse.coords()
+    if (coords.x < a.x or
+        coords.x > (a.x+a.width) or
+        coords.y < a.y or
+        coords.y > (a.y+a.height)) then
+
+        mouse.coords({
+            x = a.x + a.width/2,
+            y = a.y + a.height/2,
+        }, true)
+    end
+end
+
 -- }}}
 
 -- {{{ Menu
@@ -162,8 +174,16 @@ menubar.utils.terminal = terminal -- Set the terminal for applications that requ
 -- }}}
 
 -- {{{ Wibar
-local spacer = wibox.widget.textbox()
-spacer:set_text(' │ ')
+--local spacer = wibox.widget {
+--    color = beautiful.bg_minimize,
+--    forced_width = 4,
+--    widget = wibox.widget.separator
+--}
+local function make_spacer(text)
+    local spacer = wibox.widget.textbox()
+    spacer:set_text(text or " │ ")
+    return spacer
+end
 
 -- Keyboard map indicator and switcher
 mykeyboardlayout = awful.widget.keyboardlayout()
@@ -180,9 +200,9 @@ local lain_bat = lain.widget.bat({
 
 -- Create a textclock widget
 clocksarray = clocksarray.get_clocksarray("%a %d %b %H:%M:%S %Z", {
-        ["NZ"] = "Pacific/Auckland",
+--        ["NZ"] = "Pacific/Auckland",
         ["DE"] = "Europe/Berlin"
-    }, spacer)
+    }, make_spacer())
 
 -- Create a wibox for each screen and add it
 local taglist_buttons = gears.table.join(
@@ -229,105 +249,387 @@ local tasklist_buttons = gears.table.join(
                                           end))
 -- }}}
 
+-- {{{ Screens
+
 -- Re-set wallpaper when a screen's geometry changes (e.g. different resolution)
 screen.connect_signal("property::geometry", set_wallpaper)
 
--- {{{ Tags
-tags = {}
-tags.config = {}
-tags.config["main"] = {
-    t1 = { layout = layout_default, selected = true },
-    t2 = { layout = layout_default },
-    t3 = { layout = layout_tiled },
-    t4 = { layout = layout_tiled },
-    t5 = { layout = layout_tiled },
-    t6 = { layout = layout_floating },
-    t7 = { layout = layout_maximised },
-    t8 = { layout = layout_maximised },
-    t9 = { layout = layout_maximised },
-}
-tags.config["aux"] = {
-    t1 = { layout = layout_default, selected = true },
-    t2 = { layout = layout_default },
-    t3 = { layout = layout_tiled },
-    t4 = { layout = layout_floating },
-    t5 = { layout = layout_floating },
-    t6 = { layout = layout_floating },
-    t7 = { layout = layout_floating },
-    t8 = { layout = layout_floating },
-    t9 = { layout = layout_maximised },
-}
-
-screentags = {}
-screentags[1] = tags.config["main"]
-if screen.count() == 2 then -- aux screen is on the right
-  screentags[2] = tags.config["aux"]
-elseif screen.count() == 3 then -- main screen is still #1 in the middle
-  screentags[2] = tags.config["aux"]
-  screentags[3] = tags.config["aux"]
+-- {{{ Basic setup for screens
+local function screen_set_profile(s, profile)
+    s.profile = profile
+    s.outputstr = table.concat(gears.table.keys(s.outputs), "+")
+    s.name = s.profile .. "/" .. s.outputstr
 end
 
 awful.screen.connect_for_each_screen(function(s)
-    -- local fontsize = math.floor(250 * xrdb.get_dpi(s)/s.geometry.width)
-    -- beautiful.font = "Sans " .. tostring(fontsize)
 
-    if not tags[s.index] then
-        tags[s.index] = {}
-    end
-    for n,p in tblutils.sorted_pairs(screentags[s.index]) do
-        p["screen"] = s
-        n = string.sub(n, 2) -- remove leading 't' needed for syntax in table
-        table.insert(tags[s.index], awful.tag.add(n, p))
-    end
+    s.set_profile = screen_set_profile
+
+    -- Wallpaper
+    set_wallpaper(s)
+
+    -- Create a text widget to display screen name
+    s.namebox = wibox.container.background(wibox.widget.textbox(s.name),
+      beautiful.bg_minimize)
 
     -- Create a promptbox for each screen
-    mypromptbox[s] = awful.widget.prompt()
+    s.mypromptbox = awful.widget.prompt()
     -- Create an imagebox widget which will contains an icon indicating which layout we're using.
     -- We need one layoutbox per screen.
-    mylayoutbox[s] = awful.widget.layoutbox(s)
-    mylayoutbox[s]:buttons(awful.util.table.join(
+    s.mylayoutbox = awful.widget.layoutbox(s)
+    s.mylayoutbox:buttons(awful.util.table.join(
                            awful.button({ }, 1, function () awful.layout.inc( 1) end),
                            awful.button({ }, 3, function () awful.layout.inc(-1) end),
                            awful.button({ }, 4, function () awful.layout.inc( 1) end),
                            awful.button({ }, 5, function () awful.layout.inc(-1) end)))
     -- Create a taglist widget
-    mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.filter.all, mytaglist.buttons)
+    s.mytaglist = awful.widget.taglist(s, awful.widget.taglist.filter.all, taglist_buttons)
 
     -- Create a tasklist widget
-    mytasklist[s] = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, mytasklist.buttons)
+    s.mytasklist = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, tasklist_buttons)
 
-    -- Create the wibox
-    mywibox[s] = awful.wibar({ position = "top", screen = s })
+    -- Create the wibox, but only if there isn't one yet
+    if not s.mywibox then
+        s.mywibox = awful.wibar({ position = "top", screen = s })
+    end
 
     -- Add widgets to the wibox
-    mywibox[s]:setup {
+    local right_widgets = gears.table.join(clocksarray, {
+        make_spacer(" "),
+        wibox.widget.systray(),
+        s.mylayoutbox,
+        layout = wibox.layout.fixed.horizontal,
+    })
+
+--    if s == screen.primary then
+        right_widgets = gears.table.join({
+            make_spacer(" "),
+            ccwidgets.btc_widget,
+            make_spacer(),
+            --ccwidgets.eth_widget,
+            --make_spacer(),
+            --fxwidgets.ecb_widget,
+            --make_spacer(),
+            lain_bat.widget,
+            make_spacer(),
+        }, right_widgets)
+--    end
+
+    s.mywibox:setup {
         layout = wibox.layout.align.horizontal,
         { -- Left widgets
             layout = wibox.layout.fixed.horizontal,
-            -- mylauncher,
-            mytaglist[s],
-            mypromptbox[s],
+            --s.namebox,
+            s.mytaglist,
+            make_spacer(" "),
+            s.mypromptbox,
         },
-        mytasklist[s], -- Middle widget
-        awful.util.table.join( -- Right widgets
-            {
-                layout = wibox.layout.fixed.horizontal,
-                mykeyboardlayout,
-                wibox.widget.systray(),
-                ccwidgets.btc_widget,
-                spacer,
-                ccwidgets.eth_widget,
-                spacer,
-                lain_bat.widget,
-                spacer,
-            },
-            clocksarray,
-            {
-                mylayoutbox[s],
-            }
-        ),
+        s.mytasklist, -- Middle widget
+        right_widgets,
     }
+end) -- }}}
+
+-- {{{ autorandr integration
+local function find_screen_by_pattern(pattern)
+    for s in screen do
+        print(s.name .. " :: " .. pattern)
+        if s.name:match(pattern) then
+            return s
+        end
+    end
+end
+
+local function get_target_screen_for_tag(tag)
+    local function primary_screen(reason)
+        local s = screen.primary
+        local msg = "  → primary screen \"" .. s.name .. "\""
+        if reason then msg = msg .. " (" .. reason .. ")" end
+        print(msg)
+        return s
+    end
+
+    print("Figuring out target screen for tag " .. tag.name .. "…")
+    if tag.targets then
+        if type(tag.targets) == "table" then
+            for _,target in ipairs(tag.targets) do
+                local s = find_screen_by_pattern(target:gsub('%-', '%%-'))
+                if s then
+                    print("  → screen " .. s.name)
+                    return s
+                end
+            end
+        elseif tag.targets == "primary" then
+            return primary_screen("explicit request")
+        end
+        return primary_screen("no matching target in " .. table.concat(tag.targets, ","))
+    else
+        return primary_screen("no targets specified")
+    end
+end
+
+local function move_tag_to_target_screen(tag)
+    tag.screen = get_target_screen_for_tag(tag)
+end
+
+local function move_tags_to_target_screens()
+    for _,tag in ipairs(root.tags()) do
+        move_tag_to_target_screen(tag)
+    end
+end
+
+tag.connect_signal("request::screen", function(t)
+    -- throw the tag onto any other screen, it'll get reassigned later when
+    -- a new profile has been processed.
+    for s in screen do
+        if s ~= t.screen then
+            t.screen = s
+            t.selected = false
+            break
+        end
+    end
+    naughty.notify({
+        title = "Screen removed",
+        text = "Salvaged tab " .. t.name,
+    })
 end)
+
+function handle_new_autorandr_profile(newprofile)
+    -- The main idea here is that autorandr invokes this via awesome-client
+    -- after switching to a new profile. Awesome will have already set up all
+    -- the screens long before this function is called. Therefore, we just do
+    -- the necessary modifications to the existing screens, and move tags
+    -- around.
+
+    if not newprofile then
+        error("Missing new profile name")
+    end
+
+    naughty.notify({
+        preset = naughty.config.presets.low,
+        title = "New autorandr profile",
+        text = "Reconfiguring for profile <b>" .. newprofile .. "</b>",
+    })
+
+    for s in screen do
+        s:set_profile(newprofile)
+    end
+    move_tags_to_target_screens()
+end
+
+local function initialise_to_autorandr_profile()
+    local profile
+    profile = nil
+
+    local function process_line(line)
+        if profile then return end
+        local match = string.match(line, "^([^%s]+) %(detected%)")
+        if match then
+            profile = match
+        end
+    end
+
+    local function output_done()
+        if not profile then
+            error("autorandr detected no profile")
+            profile = "awesome"
+        end
+        handle_new_autorandr_profile(profile)
+    end
+
+    local function handle_exit(reason, code)
+        if not (reason == "exit" and code == 0) then
+            error("autorandr error: " .. reason .. ": " .. tostring(code))
+        end
+    end
+
+    awful.spawn.with_line_callback('autorandr', {
+        stdout = process_line,
+        output_done = output_done,
+        exit = handle_exit
+    })
+end
+awesome.connect_signal("startup", initialise_to_autorandr_profile)
+-- }}}
+
+-- }}}
+
+-- {{{ Tags
+
+local default_tag = {
+    name        = nil,
+    init        = true,
+    layout      = layouts.default,
+    fallback    = true,
+    targets     = "primary",
+}
+local default_tags = {}
+for i = 1, 9 do
+    default_tags[i] = {}
+    for k,v in pairs(default_tag) do
+        default_tags[i][k] = v
+    end
+    default_tags[i].name = tostring(i)
+end
+default_tags[1].selected = true
+
+default_tags = gears.table.join(default_tags, {
+  {
+    name        = "vrt",
+    init        = true,
+    exclusive   = true,
+    layout      = layouts.maximised,
+    selected    = false,
+    exec_once   = { "remmina" },
+    instance    = { "Remmina" },
+    targets     = {
+                    "gern/DP-?[12]-1",
+                    "gauting/eDP-?1",
+                    "toni/eDP-?1",
+                    "krafftwerk/DP-?1-1-5",
+                    "krafftwerk/DisplayPort-2",
+                    "cafe/eDP-?1"
+                },
+  },
+  {
+    name        = "irc",
+    init        = true,
+    exclusive   = true,
+    layout      = layouts.tiled,
+    selected    = false,
+    exec_once   = { terminal .. " -name irc -e env MOSH_TITLE_NOPREFIX=true mosh --family=all -- irc-host tmux new -As irc irssi" },
+    instance    = { "irc" },
+    targets     = {
+                    "gern/DP-?[12]-1",
+                    "gauting/eDP-?1",
+                    "toni/eDP-?1",
+                    "krafftwerk/DP-?1-1-5",
+                    "krafftwerk/DisplayPort-2",
+                    "cafe/eDP-?1"
+                },
+  },
+  {
+    name        = "[]",
+    init        = true,
+    exclusive   = true,
+    master_count = 0,
+    column_count = 4,
+    layout      = layouts.tiled,
+    selected    = false,
+    targets     = {
+                    "gern/DP-?[12]-1",
+                    "gauting/eDP-?1",
+                    "toni/eDP-?1",
+                    "krafftwerk/DP-?1-1-5",
+                    "krafftwerk/DisplayPort-2",
+                    "cafe/eDP-?1"
+                },
+  },
+  {
+    name        = "dflt",
+    init        = false,
+    fallback    = true,
+    layout      = layouts.floating,
+    volatile    = true,
+    selected    = true,
+  },
+  {
+    name        = "cal",
+    init        = true,
+    exclusive   = true,
+    layout      = layouts.default,
+    exec_once   = { "thunderbird" },
+    class       = { "thunderbird" },
+    targets     = {
+                    "gern/DP-?[12]-1",
+                    "gauting/eDP-?1",
+                    "toni/eDP-?1",
+                    "krafftwerk/DP-?1-1-6",
+                    "krafftwerk/DisplayPort-0",
+                    "cafe/eDP-?1"
+                },
+  },
+  {
+    name        = "chr",
+    init        = true,
+    exclusive   = true,
+    layout      = layouts.default,
+    exec_once   = { "chromium" },
+    class       = { "Chromium" },
+    targets     = {
+                    "gern/DP-?[12]-1",
+                    "gauting/eDP-?1",
+                    "toni/DP-?2-2",
+                    "krafftwerk/DP-?1-1-6",
+                    "krafftwerk/DisplayPort-0",
+                    "present/HDMI.*",
+                    "cafe/eDP-?1"
+                },
+  },
+  {
+    name        = "ffx",
+    init        = true,
+    exclusive   = true,
+    layout      = layouts.default,
+    exec_once   = { "firefox" },
+    class       = { "Firefox" },
+    targets     = {
+                    "gern/DP-?[12]-1",
+                    "gauting/eDP-?1",
+                    "toni/DP-?2-2",
+                    "krafftwerk/DP-?1-1-6",
+                    "krafftwerk/DisplayPort-0",
+                    "present/HDMI.*",
+                    "cafe/eDP-?1"
+                },
+  },
+})
+
+if not tyrannical then
+
+for _,t in ipairs(default_tags) do
+    if t.init then
+        t.screen = t.screen or screen.primary
+        t.layout = t.layout or layouts.default
+        local newt = th.add_tag(t.name, t, false)
+    end
+end
+
+else -- {{{ tyrannical is loaded
+tyrannical.settings.default_layout = layouts.default
+tyrannical.settings.master_width_factor = 0.5
+tyrannical.settings.block_children_focus_stealing = true
+tyrannical.settings.group_children = true
+
+tyrannical.tags = default_tags
+
+tyrannical.properties.size_hints_honor = { URxvt = false }
+
+--XX---- Ignore the tag "exclusive" property for the following clients (matched by classes)
+--XX--tyrannical.properties.intrusive = {
+--XX--  "ksnapshot"     , "pinentry"       , "gtksu"     , "kcalc"        , "xcalc"               ,
+--XX--  "feh"           , "Gradient editor", "About KDE" , "Paste Special", "Background color"    ,
+--XX--  "kcolorchooser" , "plasmoidviewer" , "Xephyr"    , "kruler"       , "plasmaengineexplorer",
+--XX--}
+--XX--
+--XX---- Ignore the tiled layout for the matching clients
+--XX--tyrannical.properties.floating = {
+--XX--  "MPlayer"      , "pinentry"        , "ksnapshot"  , "pinentry"     , "gtksu"          ,
+--XX--  "xine"         , "feh"             , "kmix"       , "kcalc"        , "xcalc"          ,
+--XX--  "yakuake"      , "Select Color$"   , "kruler"     , "kcolorchooser", "Paste Special"  ,
+--XX--  "New Form"     , "Insert Picture"  , "kcharselect", "mythfrontend" , "plasmoidviewer"
+--XX--}
+--XX--
+--XX---- Make the matching clients (by classes) on top of the default layout
+--XX--tyrannical.properties.ontop = {
+--XX--  "Xephyr"       , "ksnapshot"       , "kruler"
+--XX--}
+--XX--
+--XX---- Force the matching clients (by classes) to be centered on the screen on init
+--XX--tyrannical.properties.centered = {
+--XX--  "kcalc"
+--XX--}
+end -- }}}
+
 -- }}}
 
 -- {{{ Mouse bindings
@@ -339,6 +641,32 @@ root.buttons(gears.table.join(
 -- }}}
 
 -- {{{ Key bindings
+
+local function toggle_tag_by_name(tagname, exclusive)
+    return function()
+        local t = awful.tag.find_by_name(nil, tagname)
+        if t then
+            if exclusive then
+                t:view_only()
+            else
+                awful.tag.viewtoggle(t)
+            end
+            cf = awful.client.getmaster(t.screen)
+            if cf then
+                cf:jump_to()
+            end
+        end
+    end
+end
+
+local function move_tags_to_screen_relative(direction)
+    local s = awful.screen.focused()
+    for _,tag in ipairs(s.selected_tags) do
+        print("index: " .. s.index .. " count: " .. screen:count())
+        tag.screen = screen[(s.index + screen:count() + direction) % screen.count()]
+    end
+end
+
 globalkeys = gears.table.join(
     awful.key({ modkey,           }, "s",      hotkeys_popup.show_help,
               {description="show help", group="awesome"}),
@@ -361,19 +689,21 @@ globalkeys = gears.table.join(
         end,
         {description = "focus previous by index", group = "client"}
     ),
-    awful.key({ modkey,           }, "w", function () mymainmenu:show() end,
-              {description = "show main menu", group = "awesome"}),
 
     -- Layout manipulation
-    awful.key({ modkey, "Shift"   }, "k", function () awful.client.swap.byidx(  1)    end,
+    awful.key({ modkey, "Shift"   }, "k", function () awful.client.swap.byidx( 1)    end,
               {description = "swap with next client by index", group = "client"}),
-    awful.key({ modkey, "Shift"   }, "j", function () awful.client.swap.byidx( -1)    end,
+    awful.key({ modkey, "Shift"   }, "j", function () awful.client.swap.byidx(-1)    end,
               {description = "swap with previous client by index", group = "client"}),
     awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative( 1) end,
               {description = "focus the next screen", group = "screen"}),
     awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative(-1) end,
               {description = "focus the previous screen", group = "screen"}),
-    awful.key({ modkey,           }, "u", awful.client.urgent.jumpto,
+    awful.key({ modkey, "Shift", "Control" }, "k", function () move_tags_to_screen_relative( 1) end,
+              {description = "move tags to the next screen", group = "screen"}),
+    awful.key({ modkey, "Shift", "Control" }, "j", function () move_tags_to_screen_relative(-1) end,
+              {description = "move tags to the previous screen", group = "screen"}),
+    awful.key({ modkey, "Shift"   }, "Return", awful.client.urgent.jumpto,
               {description = "jump to urgent client", group = "client"}),
     awful.key({ modkey,           }, "Tab",
         function ()
@@ -387,6 +717,11 @@ globalkeys = gears.table.join(
     -- Standard program
     awful.key({ modkey,           }, "Return", function () awful.spawn(terminal) end,
               {description = "open a terminal", group = "launcher"}),
+    awful.key({ modkey,           }, "r", function()
+        package.loaded.rc = nil
+        require("rc")
+    end,
+              {description = "reload rc.lua", group = "awesome"}),
     awful.key({ modkey, "Control" }, "r", awesome.restart,
               {description = "reload awesome", group = "awesome"}),
     awful.key({ modkey, "Shift"   }, "q", awesome.quit,
@@ -421,13 +756,60 @@ globalkeys = gears.table.join(
               {description = "restore minimized", group = "client"}),
 
     -- Prompt
-    awful.key({ modkey },            "r",     function () awful.screen.focused().mypromptbox:run() end,
+    awful.key({ cmdkey },            "r",
+              function ()
+                  local widget = awful.screen.focused().mypromptbox.widget
+                  local function spawn(command, args)
+                      gears.debug.dump(args)
+                      awful.spawn(command, args)
+                  end
+
+                  awful.prompt.run {
+                    prompt       = "Exec: ",
+                    bg_cursor    = '#ff0000',
+                    textbox      = widget,
+                    history_path = awful.util.get_cache_dir() .. "/history",
+                    completion_callback = awful.completion.shell,
+                    hooks = {
+                        -- Replace the 'normal' Return with a custom one
+                        {{         }, 'Return', function(command)
+                            spawn(command)
+                        end},
+                        -- Spawn method to spawn in the current tag
+                        {{'Mod1'   }, 'Return', function(command)
+                            spawn(command,{
+                                intrusive = true,
+                                tag       = mouse.screen.selected_tag
+                            })
+                        end},
+                        -- Spawn in the current tag as floating and on top
+                        {{'Shift'  }, 'Return', function(command)
+                            spawn(command,{
+                                ontop     = true,
+                                floating  = true,
+                                tag       = mouse.screen.selected_tag
+                            })
+                        end},
+                        -- Spawn in a new tag
+                        {{'Control'}, 'Return', function(command)
+                            spawn(command,{
+                                new_tag = true,
+                                layout = layouts.default,
+                                volatile = true,
+                            })
+                        end},
+                        -- Cancel
+                        {{         }, 'Escape', function(_) return end},
+                    },
+                }
+        end,
               {description = "run prompt", group = "launcher"}),
 
     awful.key({ modkey }, "x",
               function ()
                   awful.prompt.run {
-                    prompt       = "Run Lua code: ",
+                    prompt       = "Eval: ",
+                    bg_cursor    = '#ff0000',
                     textbox      = awful.screen.focused().mypromptbox.widget,
                     exe_callback = awful.util.eval,
                     history_path = awful.util.get_cache_dir() .. "/history_eval"
@@ -435,9 +817,56 @@ globalkeys = gears.table.join(
               end,
               {description = "lua execute prompt", group = "awesome"}),
     -- Menubar
-    awful.key({ modkey }, "p", function() menubar.show() end,
-              {description = "show the menubar", group = "launcher"})
-)
+    awful.key({ modkey }, "w", function() menubar.show() end,
+              {description = "show the menubar", group = "launcher"}),
+
+    -- Tag helpers
+    awful.key({ modkey,           }, "a", function()
+        th.add_tag(nil, {layout=layouts.default} ,true)
+    end,
+    {description = "add a tag", group = "tag"}),
+    awful.key({ modkey,           }, "d", th.delete_tag,
+              {description = "delete the current tag", group = "tag"}),
+    awful.key({ modkey, "Shift",           }, "a", function()
+        th.move_to_new_tag(nil, nil, { layout = layouts.maximised },true,true,true)
+    end,
+              {description = "add a volatile tag with the focused client", group = "tag"}),
+    awful.key({ modkey, "Shift", "Control" }, "a", function()
+        th.move_to_new_tag(nil, nil, { layout = layouts.maximised },false,true,true)
+    end,
+              {description = "add a permanent tag with the focused client", group = "tag"}),
+    awful.key({ modkey, "Mod1"   }, "a", th.copy_tag,
+              {description = "create a copy of the current tag", group = "tag"}),
+    awful.key({ modkey, "Control"   }, "a", th.rename_tag,
+              {description = "rename the current tag", group = "tag"}),
+    awful.key({ modkey, "Control", "Shift", "Mod1" }, "a", th.collect_orphan_clients_to_tag,
+              {description = "collect all orphaned clients", group = "client"}),
+
+    awful.key({ modkey }, "t", toggle_tag_by_name("vrt", true),
+              {description = "view tag 'vrt'", group = "tag"}),
+    awful.key({ modkey, "Control" }, "t", toggle_tag_by_name("vrt"),
+              {description = "toggle tag 'vrt'", group = "tag"}),
+    awful.key({ modkey }, "y", toggle_tag_by_name("irc", true),
+              {description = "view tag 'irc'", group = "tag"}),
+    awful.key({ modkey, "Control" }, "y", toggle_tag_by_name("irc"),
+              {description = "toggle tag 'irc'", group = "tag"}),
+    awful.key({ modkey }, "u", toggle_tag_by_name("[]", true),
+              {description = "view tag '[]'", group = "tag"}),
+    awful.key({ modkey, "Control" }, "u", toggle_tag_by_name("[]"),
+              {description = "toggle tag '[]'", group = "tag"}),
+    awful.key({ modkey }, "i", toggle_tag_by_name("cal", true),
+              {description = "view tag 'cal'", group = "tag"}),
+    awful.key({ modkey, "Control" }, "i", toggle_tag_by_name("cal"),
+              {description = "toggle tag 'cal'", group = "tag"}),
+    awful.key({ modkey }, "o", toggle_tag_by_name("chr", true),
+              {description = "view tag 'chr'", group = "tag"}),
+    awful.key({ modkey, "Control" }, "o", toggle_tag_by_name("chr"),
+              {description = "toggle tag 'chr'", group = "tag"}),
+    awful.key({ modkey }, "p", toggle_tag_by_name("ffx", true),
+              {description = "view tag 'ff'", group = "tag"}),
+    awful.key({ modkey, "Control" }, "p", toggle_tag_by_name("ffx"),
+              {description = "toggle tag 'ff'", group = "tag"}),
+{})
 
 clientkeys = gears.table.join(
     awful.key({ modkey,           }, "f",
@@ -452,10 +881,10 @@ clientkeys = gears.table.join(
               {description = "toggle floating", group = "client"}),
     awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
               {description = "move to master", group = "client"}),
-    awful.key({ modkey,           }, "o",      function (c) c:move_to_screen()               end,
+    awful.key({ modkey,           }, "z",      function (c) c:move_to_screen() end,
               {description = "move to screen", group = "client"}),
-    awful.key({ modkey,           }, "t",      function (c) c.ontop = not c.ontop            end,
-              {description = "toggle keep on top", group = "client"}),
+    --awful.key({ modkey,           }, "t",      function (c) c.ontop = not c.ontop            end,
+    --          {description = "toggle keep on top", group = "client"}),
     awful.key({ modkey,           }, "n",
         function (c)
             -- The client currently has the input focus, so it cannot be
@@ -491,30 +920,16 @@ clientkeys = gears.table.join(
 for i = 1, 9 do
     globalkeys = gears.table.join(globalkeys,
         -- View tag only.
-        awful.key({ modkey }, "#" .. i + 9,
-                  function ()
-                        local screen = awful.screen.focused()
-                        local tag = screen.tags[i]
-                        if tag then
-                           tag:view_only()
-                        end
-                  end,
+        awful.key({ modkey }, "#" .. i + 9, toggle_tag_by_name(tostring(i), true),
                   {description = "view tag #"..i, group = "tag"}),
         -- Toggle tag display.
-        awful.key({ modkey, "Control" }, "#" .. i + 9,
-                  function ()
-                      local screen = awful.screen.focused()
-                      local tag = screen.tags[i]
-                      if tag then
-                         awful.tag.viewtoggle(tag)
-                      end
-                  end,
+        awful.key({ modkey, "Control" }, "#" .. i + 9, toggle_tag_by_name(tostring(i)),
                   {description = "toggle tag #" .. i, group = "tag"}),
         -- Move client to tag.
         awful.key({ modkey, "Shift" }, "#" .. i + 9,
                   function ()
                       if client.focus then
-                          local tag = client.focus.screen.tags[i]
+                          local tag = awful.tag.find_by_name(screen.primary, tostring(i))
                           if tag then
                               client.focus:move_to_tag(tag)
                           end
@@ -525,7 +940,7 @@ for i = 1, 9 do
         awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
                   function ()
                       if client.focus then
-                          local tag = client.focus.screen.tags[i]
+                          local tag = awful.tag.find_by_name(screen.primary, tostring(i))
                           if tag then
                               client.focus:toggle_tag(tag)
                           end
@@ -543,38 +958,73 @@ clientbuttons = gears.table.join(
 -- misc apps
 globalkeys = awful.util.table.join(globalkeys,
 awful.key({ cmdkey }, "n", function () awful.spawn("firefox") end),
-awful.key({ cmdkey }, "m", function () awful.spawn("chromium --enable-remote-extensions") end),
-awful.key({ cmdkey }, "y", function () awful.spawn(terminal .. " -e python") end),
-awful.key({ cmdkey }, "c", function () awful.spawn("thunderbird") end),
-awful.key({ cmdkey }, "r", function () mypromptbox[mouse.screen]:run() end),
+awful.key({ cmdkey }, "c", function () awful.spawn("chromium --enable-remote-extensions") end),
+awful.key({ cmdkey }, "y", function () awful.spawn(terminal .. " -e ipython3") end),
+awful.key({ cmdkey }, "m", function () awful.spawn(terminal .. " -name mutt -e mutt") end),
+awful.key({ cmdkey }, "t", function () awful.spawn("thunderbird") end),
 awful.key({ cmdkey }, "g", function () awful.spawn("gscan2pdf") end),
-awful.key({ cmdkey }, "v", function () awful.spawn("virt-manager") end),
+awful.key({ cmdkey, "Shift" }, "v", function () awful.spawn("virt-manager") end),
+awful.key({ cmdkey, "Shift" }, "r", function () awful.spawn("remmina") end),
 awful.key({ cmdkey }, "l", function () awful.spawn("libreoffice") end),
-awful.key({ cmdkey }, "f", function () awful.spawn("thunar") end),
-awful.key({ cmdkey }, "i", function () awful.spawn(terminal .. " -name irc -e env MOSH_TITLE_NOPREFIX=true mosh -4 -- irc-host tmux new -As irc irssi") end),
-awful.key({ cmdkey }, "x", function () awful.spawn.with_shell("/sbin/start-stop-daemon --start --background --exec /usr/bin/xscreensaver -- -no-capture-stderr; sleep 2; xscreensaver-command -lock") end),
-awful.key({ cmdkey, "Shift" }, "x", function () awful.spawn("xscreensaver-command -exit") end),
+awful.key({ cmdkey }, "v", function () awful.spawn("virt-viewer") end),
+awful.key({ cmdkey }, "p", function () awful.spawn("pavucontrol") end),
+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),
+awful.key({ cmdkey }, "x", function ()
+    run_output_notify("sh -c '. ~/.xsession.d/10-xautolock; echo \"Locking…\"; sleep 1; xautolock -locknow'", "Enabling xautolock")
+end),
+awful.key({ cmdkey, "Shift" }, "x", function () run_output_notify("pkill -e xautolock", "Disabling xautolock") end),
+
+awful.key({ cmdkey }, "BackSpace", function () awful.spawn("pkill -USR1 offlineimap") end),
 
 -- function keys
 awful.key(nil, "XF86ScreenSaver", function () awful.spawn("xset dpms force off") end),
-awful.key(nil, "XF86AudioMute", function () awful.spawn("pactl set-sink-mute 0 toggle") end),
-awful.key({ cmdkey }, "End", function () awful.spawn("pactl set-sink-mute 0 toggle") end),
-awful.key(nil, "XF86AudioLowerVolume", function () awful.spawn("pactl set-sink-volume 0 -2%") end),
-awful.key({ cmdkey }, "Next", function () awful.spawn("pactl set-sink-volume 0 -2%") end),
-awful.key(nil, "XF86AudioRaiseVolume", function () awful.spawn("pactl set-sink-volume 0 +2%") end),
-awful.key({ cmdkey }, "Prior", function () awful.spawn("pactl set-sink-volume 0 +2%") end),
-awful.key(nil, "XF86AudioMicMute", function () awful.spawn("pactl set-source-mute 1 toggle") end),
-awful.key({ cmdkey }, "Home", function () awful.spawn("pactl set-source-mute 1 toggle") end),
-awful.key(nil, "XF86MonBrightnessDown", function () awful.spawn("xbacklight -dec 5%") end),
-awful.key(nil, "XF86MonBrightnessUp", function () awful.spawn("xbacklight -inc 5%") end),
-awful.key(nil, "XF86Display", function () awful.spawn("") end),
+awful.key(nil, "XF86AudioMute", function () awful.spawn("pactl set-sink-mute @DEFAULT_SINK@ toggle") end),
+awful.key({ cmdkey }, "End", function () awful.spawn("pactl set-sink-mute @DEFAULT_SINK@ toggle") end),
+awful.key(nil, "XF86AudioLowerVolume", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ -2%") end),
+awful.key({ cmdkey }, "Next", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ -2%") end),
+awful.key(nil, "XF86AudioRaiseVolume", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ +2%") end),
+awful.key({ cmdkey }, "Prior", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ +2%") end),
+awful.key(nil, "XF86AudioMicMute", function () awful.spawn("pactl set-source-mute @DEFAULT_SOURCE@ toggle") end),
+awful.key({ cmdkey }, "Home", function () awful.spawn("pactl set-source-mute @DEFAULT_SOURCE@ toggle") end),
+awful.key({ cmdkey }, "Insert", function () awful.spawn("pa_cycle_default source") end),
+awful.key({ cmdkey }, "Delete", function () awful.spawn("pa_cycle_default sink") end),
+awful.key(nil, "XF86MonBrightnessDown", function () awful.spawn("light -U 10") end),
+awful.key(nil, "XF86MonBrightnessUp", function () awful.spawn("light -A 10") end),
+awful.key(nil, "XF86Display", function () awful.spawn("autorandr --change --force"); initialise_to_autorandr_profile() end),
+awful.key(nil, "XF86AudioStop", function () awful.spawn("autorandr --change --force"); initialise_to_autorandr_profile() end),
 awful.key(nil, "XF86WLAN", function () awful.spawn("") end),
 awful.key(nil, "XF86Tools", function () awful.spawn("") end),
 awful.key(nil, "XF86Search", function () awful.spawn("") end),
 awful.key(nil, "XF86LaunchA", function () awful.spawn("") end),
-awful.key(nil, "XF86Explorer", function () awful.spawn("") end)
+awful.key(nil, "XF86Explorer", function () awful.spawn("") end),
+awful.key(nil, "XF86Calculator", function () awful.spawn(terminal .. " -e ipython3 --profile=calc") end),
+awful.key(nil, "XF86Favorites", function () awful.spawn("systemctl suspend") end),
+
+awful.key({ cmdkey }, "Multi_key", function () run_output_notify("flameshot gui", "Output") end),
+awful.key({ cmdkey, "Shift" }, "Multi_key", function () run_output_notify("flameshot full --delay 2000 --clipboard", "Output") end),
+
+awful.key({ cmdkey }, "Up", function () awful.spawn("pap prev") end),
+awful.key({ cmdkey }, "Left", function () awful.spawn("pap seek -10") end),
+awful.key({ cmdkey, "Shift" }, "Left", function () awful.spawn("pap seek -60") end),
+awful.key({ cmdkey }, "Down", function () awful.spawn("pap next") end),
+awful.key({ cmdkey }, "Right", function () awful.spawn("pap seek +10") end),
+awful.key({ cmdkey, "Shift" }, "Right", function () awful.spawn("pap seek +60") end),
+awful.key({ cmdkey }, "space", function () awful.spawn("pap pause") end),
+awful.key({ cmdkey }, "\\", function () run_output_notify("pap info", "Track info") end),
+awful.key({ cmdkey }, "]", function () run_output_notify("pap list", "Playlist") end)
 )
 
+function run_output_notify(cmd, title)
+    awful.spawn.easy_async(cmd, function(stdout, stderr, reason, exit_code)
+        if #stdout > 1 then
+            naughty.notify({
+                preset = naughty.config.presets.low,
+                title = title,
+                text = stdout})
+            end
+        end)
+end
+
 -- Set keys
 root.keys(globalkeys)
 -- }}}
@@ -582,9 +1032,41 @@ root.keys(globalkeys)
 -- {{{ Rules
 -- Rules to apply to new clients (through the "manage" signal).
 
-local function move_to_tag(s, t)
+local function float_client_in_the_middle_with_margins(client, leftright, topbottom)
+    local wa = client.screen.workarea
+    if topbottom then
+        client.y = wa.y + topbottom
+        client.height = wa.height - 2*topbottom
+    else
+        client.y = wa.y + (wa.height - client.height)/2
+    end
+    if leftright then
+        client.x = wa.x + leftright
+        client.width = wa.width - 2*leftright
+    else
+        client.x = wa.x + (wa.width - client.width)/2
+    end
+end
+
+local function move_to_tag_by_name(s, tagname)
     return function(c)
-        c:move_to_tag(tags[s][t])
+        local t = awful.tag.find_by_name(s, tagname)
+        if not t then
+            error("No tag by the name of " .. tagname)
+            return
+        end
+        c:move_to_tag(t)
+    end
+end
+
+local function move_to_tag_or_create_volatile(s, tagname)
+    return function(c)
+        local t = awful.tag.find_by_name(s, tagname)
+        if t then
+            c:move_to_tag(t)
+        else
+            th.move_to_new_tag(c, tagname, {}, true, true, true)
+        end
     end
 end
 
@@ -599,87 +1081,149 @@ awful.rules.rules = {
                      buttons = clientbuttons,
                      screen = awful.screen.preferred,
                      placement = awful.placement.no_overlap+awful.placement.no_offscreen,
-                     floating = false
+                     floating = false,
+                     maximized = false,
                  },
     },
-
-    -- Add titlebars to normal clients and dialogs
-    --DISABLED-- { rule_any = {type = { "normal", "dialog" }
-    --DISABLED--  }, properties = { titlebars_enabled = true }
-    --DISABLED-- },
-
     { rule = { type = "dialog" },
       properties = { floating = true,
+                     ontop = true,
+                     skip_taskbar = true,
+                     urgent = true,
+                     --new_tag = true,
+                     --switchtotag = true,
                      placement = awful.placement.centered
-                 }
+                   }
     },
-
     { rule = { class = "URxvt" },
-               properties = {
-                   -- floating = false,
-                   size_hints_honor = false
-               } },
-    { rule = { class = "URxvt", instance = "irc" },
-               properties = {
-                   switchtotag = true
-               },
-               callback = move_to_tag(screen.count(), screen.count() == 1 and 2 or 1)
-           },
-    { rule = { class = "Firefox", instance = "Navigator" },
-               properties = {
-                   floating = false,
-               },
-               callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
-           },
-    { rule = { class = "Firefox-esr", instance = "Navigator" },
-               properties = {
-                   floating = false,
-               },
-               callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
-           },
-    { rule = { class = "Thunderbird", instance = "Mail" },
-               properties = {
-                   floating = false,
-               },
-               callback = move_to_tag(screen.count() == 1 and 1 or 2, 8)
-           },
-    { rule = { class = "Chromium", instance = "chromium" },
-               properties = {
-                   floating = false,
-               },
-               callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
-           },
-    { rule = { class = "Gscan2pdf" },
-               properties = {
-                   switchtotag = true
-               },
-               callback = move_to_tag(1, 5)
-           },
-    { rule = { name = "gscan2pdf .*" },
-               properties = {
-                   floating = false,
-               },
-           },
-    { rule = { class = "Thunar", type = "normal" },
-               properties = {
-                   floating = false,
-               },
-           },
-    { rule = { class = "MuPDF", instance = "mupdf" },
-               properties = {
-                   floating = true,
-               },
-           },
-    { rule = { class = "Pinentry", instance = "pinentry" },
-               properties = {
-                   floating = true,
+      properties = { size_hints_honor = false, }
+    },
+    { rule = { instance = "irc" },
+      callback = move_to_tag_by_name(nil, "irc"),
+    },
+    { rule = { class = "scrcpy" },
+      callback = move_to_tag_by_name(nil, "[]"),
+    },
+    { rule_any = { class = { "Firefox", "firefox" } },
+      callback = move_to_tag_by_name(nil, "ffx"),
+    },
+    { rule_any = { class = { "org.remmina.Remmina",
+                             "Virt-viewer",
+                             "Virt-manager"
+                           },
+                 },
+      callback = move_to_tag_by_name(nil, "vrt"),
+    },
+    { rule = { class = "Chromium" },
+      callback = move_to_tag_by_name(nil, "chr"),
+    },
+    { rule_any = { class = { "thunderbird", "Thunderbird" } },
+      callback = move_to_tag_by_name(nil, "cal"),
+    },
+    { rule = { instance = "mutt" },
+      properties = {
+          new_tag = {
+              name = "mutt",
+              layout = awful.layout.suit.fair.horizontal,
+              volatile = true
+          },
+          switchtotag = true,
+      },
+    },
+    { rule_any = { class = { "zoom" } },
+      callback = move_to_tag_or_create_volatile(nil, "Zoom"),
+    },
+    { rule_any = { class = { "Ssvnc.tcl" },
+                   class = { "Ssvnc" },
+                   name = { "SSL/SSH VNC Viewer.-" },
+                 },
+      callback = move_to_tag_or_create_volatile(nil, "SSVNC"),
+    },
+    { rule_any = { class = {
+        "Gxmessage",
+        "Pinentry"
+    }},
+      properties = { floating = true,
+                     maximized = false,
+                     focus = true,
+                     placement = awful.placement.centered,
+                   },
+    },
+    { rule_any = { instance = {
+        "tridactyl-edit",
+        "pdfshuffler",
+        "vlc",
+        "pavucontrol"
+    }},
+      properties = { floating = true,
+                     maximized = false,
+                     focus = true,
+                     placement = awful.placement.centered,
+                   },
+    },
+    { rule_any = { class = {
+                        "Gimp",
+                        "Inkscape",
+                        "Pitivi",
+                        "Audacity",
+                    },
+                    instance = {
+                        "libreoffice",
+                    }
+                },
+      except_any = { type = { "dialog" } },
+      properties = { new_tag = {
+                        layout = layouts.maximised,
+                        volatile = true,
+                    },
+                     switchtotag = true,
+                     focus = true,
+                   },
                },
-           },
-    { rule = { class = "Gxmessage" },
-               properties = {
-                   floating = true,
+    { rule_any = { class = {
+                        "Gscan2pdf",
+                    },
+                },
+      except_any = { type = { "dialog" } },
+      properties = { new_tag = {
+                        layout = layouts.default,
+                        volatile = true,
+                    },
+                    floating = true,
+                    maximized = false,
+                    focus = true,
+                    placement = awful.placement.centered,
+                    switchtotag = true,
+                    focus = true,
+                   },
                },
-           },
+--XX--    { rule = { class = "Gscan2pdf" },
+--XX--               properties = {
+--XX--                   switchtotag = true
+--XX--               },
+--XX--               callback = move_to_tag(1, 5)
+--XX--           },
+--XX--    { rule = { name = "gscan2pdf .*" },
+--XX--               properties = {
+--XX--                   floating = false,
+--XX--               },
+--XX--           },
+--XX--    { rule = { class = "Thunar", type = "normal" },
+--XX--               properties = {
+--XX--                   floating = false,
+--XX--               },
+--XX--           },
+--XX--    { rule = { class = "Pinentry", instance = "pinentry" },
+--XX--               properties = {
+--XX--                   floating = true,
+--XX--               },
+--XX--           },
+--XX--    { rule = { class = "Gxmessage" },
+--XX--               properties = {
+--XX--                   floating = true,
+--XX--               },
+--XX--           },
+--XX--}
 }
 -- }}}
 
@@ -688,7 +1232,13 @@ awful.rules.rules = {
 client.connect_signal("manage", function (c)
     -- Set the windows at the slave,
     -- i.e. put it at the end of others instead of setting it master.
-    if not awesome.startup then awful.client.setslave(c) end
+    -- if not awesome.startup then awful.client.setslave(c) end
+    --if not awesome.startup then
+    --    local t = awful.screen.focused().selected_tag
+    --    if t.name == "xmutt" then
+    --        awful.client.setslave(c)
+    --    end
+    --end
 
     if awesome.startup and
       not c.size_hints.user_position
@@ -749,13 +1299,40 @@ client.connect_signal("mouse::enter", function(c)
         and awful.client.focus.filter(c) then
         client.focus = c
     end
+--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 
+--                    something like this
 end)
 
-client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end)
-client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
+client.connect_signal("focus", function(c)
+    c.border_color = beautiful.border_focus
+end)
+client.connect_signal("unfocus", function(c)
+    c.border_color = beautiful.border_normal
+end)
 
 awful.ewmh.add_activate_filter(function(c, context, hints)
-    if context == "ewmh" and (c.class == "Firefox-esr" or c.class == "Firefox") then return false end
+    if context == "ewmh" then
+        if (c.class == "Firefox-esr" or c.class == "Firefox") then
+            return false
+        end
+    end
+end)
+
+client.connect_signal("request::activate", function(c, context, hints)
+    if gears.table.hasitem({
+        "client.focus.byidx",
+        "client.jumpto",
+        "autofocus.check_focus",
+        "rules",
+        "ewmh",
+    }, context) then
+        gears.timer.delayed_call(function()
+            -- we need a delayed call so that we execute *after layout changes
+            if hints.raise and c == client.focus and client.focus:isvisible() then
+                move_mouse_to_area(client.focus)
+            end
+        end)
+    end
 end)
 
 -- vim:ft=lua:sw=4:sts=4:ts=4:et