X-Git-Url: https://git.madduck.net/etc/awesome.git/blobdiff_plain/01e8bae5bdc4719c23fbd479814c35dddff5fbab..9ab190ce855df436019905153582c406299197e6:/.config/awesome/rc.lua

diff --git a/.config/awesome/rc.lua b/.config/awesome/rc.lua
index 4f9fe01..74da4ba 100644
--- a/.config/awesome/rc.lua
+++ b/.config/awesome/rc.lua
@@ -1,16 +1,34 @@
 -- {{{ 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
 -- Notification library
 local naughty = require("naughty")
 local menubar = require("menubar")
 local hotkeys_popup = require("awful.hotkeys_popup").widget
+-- Enable hotkeys help widget for VIM and other apps
+-- when client with a matching name is opened:
+require("awful.hotkeys_popup.keys")
+
+-- Load Debian menu entries
+local debian = require("debian.menu")
+local has_fdo, freedesktop = pcall(require, "freedesktop")
+-- Other libraries
+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
@@ -39,12 +57,15 @@ end
 -- }}}
 
 -- {{{ Variable definitions
--- Themes define colours, icons, and wallpapers
-beautiful.init(awful.util.get_themes_dir() .. "default/theme.lua")
+--xrdb.set_dpi(95, screen[1])
+--xrdb.set_dpi(120, screen[2])
+
+-- Themes define colours, icons, font and wallpapers.
+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"
-editor = "sensible-editor"
+terminal = "rxvt-unicode"
+editor = os.getenv("EDITOR") or "editor"
 editor_cmd = terminal .. " -e " .. editor
 
 -- Default modkey.
@@ -56,28 +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.fair,
-    awful.layout.suit.tile,
-    -- awful.layout.suit.tile.left,
-    -- awful.layout.suit.tile.bottom,
-    awful.layout.suit.tile.top,
-    -- 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,
-    awful.layout.suit.floating,
+    layouts.default,
+    layouts.tiled,
+    layouts.maximised,
+    layouts.floating,
+    layouts.default_horiz,
+    layouts.tiled_horiz,
 }
-
-layout_default = awful.layout.layouts[1]
-layout_tiled = awful.layout.layouts[2]
-layout_maximised = awful.layout.layouts[4]
-layout_floating = awful.layout.layouts[5]
 -- }}}
 
 -- {{{ Helper functions
@@ -94,32 +109,32 @@ local function client_menu_toggle_fn()
     end
 end
 
-local function sorted_pairs(t, f)
-    local a = {}
-    for n in pairs(t) do table.insert(a, n) end
-    table.sort(a, f)
-    local i = 0      -- iterator variable
-    local iter = function ()   -- iterator function
-        i = i + 1
-        if a[i] == nil then return nil
-        else return a[i], t[a[i]]
+local function set_wallpaper(s)
+    -- Wallpaper
+    if beautiful.wallpaper then
+        local wallpaper = beautiful.wallpaper
+        -- If wallpaper is a function, call it with the screen
+        if type(wallpaper) == "function" then
+            wallpaper = wallpaper(s)
         end
+        gears.wallpaper.maximized(wallpaper, s, true)
     end
-    return iter
 end
 
-local function print_table(tbl, indent)
-    if not indent then indent = 0 end
-    for k, v in pairs(tbl) do
-        formatting = string.rep("  ", indent) .. k .. ": "
-        if type(v) == "table" then
-            print(formatting)
-            print_table(v, indent+1)
-        else
-            print(formatting .. tostring(v))
-        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
@@ -129,35 +144,68 @@ myawesomemenu = {
    { "manual", terminal .. " -e man awesome" },
    { "edit config", editor_cmd .. " " .. awesome.conffile },
    { "restart", awesome.restart },
-   { "quit", awesome.quit }
+   { "quit", function() awesome.quit() end}
 }
 
-mymainmenu = awful.menu({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon },
-                                    { "open terminal", terminal }
-                                  }
-                        })
+local menu_awesome = { "awesome", myawesomemenu, beautiful.awesome_icon }
+local menu_terminal = { "open terminal", terminal }
+
+if has_fdo then
+    mymainmenu = freedesktop.menu.build({
+        before = { menu_awesome },
+        after =  { menu_terminal }
+    })
+else
+    mymainmenu = awful.menu({
+        items = {
+                  menu_awesome,
+                  { "Debian", debian.menu.Debian_menu.Debian },
+                  menu_terminal,
+                }
+    })
+end
+
 
 mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
                                      menu = mymainmenu })
--- }}}
 
--- {{{ Menubar configuration
+-- Menubar configuration
 menubar.utils.terminal = terminal -- Set the terminal for applications that require it
 -- }}}
 
--- {{{ Wibox
--- Create a textclock widget
-mytextclock = wibox.widget.textclock("%a %d %b %H:%M:%S", 1)
+-- {{{ Wibar
+--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()
 
+local lain_bat = lain.widget.bat({
+    batteries = {"BAT0", "BAT1"},
+    settings = function()
+        local delim = "↓"
+        if bat_now.status == "Charging" then delim = "↑"
+        elseif bat_now.status == "Unknown" then delim = "Ù­" end
+        widget:set_text(bat_now.perc .. "% " .. delim .. " " .. bat_now.time)
+    end,
+})
+
+-- Create a textclock widget
+clocksarray = clocksarray.get_clocksarray("%a %d %b %H:%M:%S %Z", {
+--        ["NZ"] = "Pacific/Auckland",
+        ["DE"] = "Europe/Berlin"
+    }, make_spacer())
+
 -- Create a wibox for each screen and add it
-mywibox = {}
-mypromptbox = {}
-mylayoutbox = {}
-mytaglist = {}
-mytaglist.buttons = awful.util.table.join(
+local taglist_buttons = gears.table.join(
                     awful.button({ }, 1, function(t) t:view_only() end),
                     awful.button({ modkey }, 1, function(t)
                                               if client.focus then
@@ -174,11 +222,11 @@ mytaglist.buttons = awful.util.table.join(
                     awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
                 )
 
-mytasklist = {}
-mytasklist.buttons = awful.util.table.join(
+local tasklist_buttons = gears.table.join(
                      awful.button({ }, 1, function (c)
                                               if c == client.focus then
-                                                  c.minimized = true
+                                                  -- I don't like click-minimising
+                                                  -- c.minimized = true
                                               else
                                                   -- Without this, the following
                                                   -- :isvisible() makes no sense
@@ -201,103 +249,374 @@ mytasklist.buttons = awful.util.table.join(
                                           end))
 -- }}}
 
--- {{{ 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 },
-}
+-- {{{ Screens
 
-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"]
+-- Re-set wallpaper when a screen's geometry changes (e.g. different resolution)
+screen.connect_signal("property::geometry", set_wallpaper)
+
+-- {{{ 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)
+
+    s.set_profile = screen_set_profile
+
     -- Wallpaper
-    --DISABLED--if beautiful.wallpaper then
-    --DISABLED--    local wallpaper = beautiful.wallpaper
-    --DISABLED--    -- If wallpaper is a function, call it with the screen
-    --DISABLED--    if type(wallpaper) == "function" then
-    --DISABLED--        wallpaper = wallpaper(s)
-    --DISABLED--    end
-    --DISABLED--    gears.wallpaper.maximized(wallpaper, s, true)
-    --DISABLED--end
-
-    if not tags[s.index] then
-        tags[s.index] = {}
-    end
-    for n,p in 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
+    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],
-        },
-        mytasklist[s], -- Middle widget
-        { -- Right widgets
-            layout = wibox.layout.fixed.horizontal,
-            mykeyboardlayout,
-            wibox.widget.systray(),
-            mytextclock,
-            mylayoutbox[s],
+            --s.namebox,
+            s.mytaglist,
+            make_spacer(" "),
+            s.mypromptbox,
         },
+        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        = "irc",
+    init        = true,
+    exclusive   = true,
+    layout      = layouts.tiled,
+    selected    = true,
+    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
-root.buttons(awful.util.table.join(
+root.buttons(gears.table.join(
     awful.button({ }, 3, function () mymainmenu:toggle() end),
     awful.button({ }, 4, awful.tag.viewnext),
     awful.button({ }, 5, awful.tag.viewprev)
@@ -305,7 +624,33 @@ root.buttons(awful.util.table.join(
 -- }}}
 
 -- {{{ Key bindings
-globalkeys = awful.util.table.join(
+
+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"}),
     awful.key({ modkey,           }, "Left",   awful.tag.viewprev,
@@ -315,31 +660,33 @@ globalkeys = awful.util.table.join(
     awful.key({ modkey,           }, "Escape", awful.tag.history.restore,
               {description = "go back", group = "tag"}),
 
-    awful.key({ modkey,           }, "j",
+    awful.key({ modkey,           }, "k",
         function ()
             awful.client.focus.byidx( 1)
         end,
         {description = "focus next by index", group = "client"}
     ),
-    awful.key({ modkey,           }, "k",
+    awful.key({ modkey,           }, "j",
         function ()
             awful.client.focus.byidx(-1)
         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"   }, "j", 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"   }, "k", 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" }, "j", function () awful.screen.focus_relative( 1) end,
+    awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative( 1) end,
               {description = "focus the next screen", group = "screen"}),
-    awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative(-1) end,
+    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 ()
@@ -353,6 +700,11 @@ globalkeys = awful.util.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,
@@ -387,23 +739,115 @@ globalkeys = awful.util.table.join(
               {description = "restore minimized", group = "client"}),
 
     -- Prompt
-    awful.key({ modkey },            "r",     function () mypromptbox[awful.screen.focused()]: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: " },
-                  mypromptbox[awful.screen.focused()].widget,
-                  awful.util.eval, nil,
-                  awful.util.get_cache_dir() .. "/history_eval")
+                  awful.prompt.run {
+                    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"
+                  }
               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"}),
 
-clientkeys = awful.util.table.join(
+    -- 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 }, "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",
         function (c)
             c.fullscreen = not c.fullscreen
@@ -416,7 +860,7 @@ clientkeys = awful.util.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"}),
@@ -430,41 +874,41 @@ clientkeys = awful.util.table.join(
     awful.key({ modkey,           }, "m",
         function (c)
             c.maximized = not c.maximized
+            c.maximized_horizontal = false
+            c.maximized_vertical = false
+            c:raise()
+        end ,
+        {description = "(un)maximize", group = "client"}),
+    awful.key({ modkey, "Control" }, "m",
+        function (c)
+            c.maximized_vertical = not c.maximized_vertical
             c:raise()
         end ,
-        {description = "maximize", group = "client"})
+        {description = "(un)maximize vertically", group = "client"}),
+    awful.key({ modkey, "Shift"   }, "m",
+        function (c)
+            c.maximized_horizontal = not c.maximized_horizontal
+            c:raise()
+        end ,
+        {description = "(un)maximize horizontally", group = "client"})
 )
 
 -- Bind all key numbers to tags.
--- Be careful: we use keycodes to make it works on any keyboard layout.
+-- Be careful: we use keycodes to make it work on any keyboard layout.
 -- This should map on the top row of your keyboard, usually 1 to 9.
 for i = 1, 9 do
-    globalkeys = awful.util.table.join(globalkeys,
+    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.
-        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,
+        -- Toggle tag display.
+        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
@@ -475,7 +919,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
@@ -485,65 +929,275 @@ for i = 1, 9 do
     )
 end
 
-clientbuttons = awful.util.table.join(
+clientbuttons = gears.table.join(
     awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
     awful.button({ modkey }, 1, awful.mouse.client.move),
     awful.button({ modkey }, 3, awful.mouse.client.resize))
 
+-- misc apps
+globalkeys = awful.util.table.join(globalkeys,
+awful.key({ cmdkey }, "n", function () awful.spawn("firefox") 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, "Shift" }, "v", function () awful.spawn("virt-manager") end),
+awful.key({ cmdkey }, "l", function () awful.spawn("libreoffice") end),
+awful.key({ cmdkey }, "v", function () awful.spawn("remmina") 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 ()
+    awful.spawn("xautolock -enable")
+    awful.spawn("xautolock -locknow")
+end),
+awful.key({ cmdkey, "Shift" }, "x", function () awful.spawn("xautolock -disable") 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 @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, "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)
 -- }}}
 
 -- {{{ Rules
 -- Rules to apply to new clients (through the "manage" signal).
+
+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)
+        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
+
 awful.rules.rules = {
     -- All clients will match this rule.
     { rule = { },
       properties = { border_width = beautiful.border_width,
                      border_color = beautiful.border_normal,
                      focus = awful.client.focus.filter,
-                     size_hints_honor = false,
                      raise = true,
                      keys = clientkeys,
                      buttons = clientbuttons,
-                     placement = awful.placement.no_overlap+awful.placement.no_offscreen
-     }
+                     screen = awful.screen.preferred,
+                     placement = awful.placement.no_overlap+awful.placement.no_offscreen,
+                     floating = false,
+                     maximized = false,
+                 },
     },
-
-    -- Floating clients.
-    { rule_any = {
-        instance = {
-          "DTA",  -- Firefox addon DownThemAll.
-          "copyq",  -- Includes session name in class.
-        },
-        class = {
-          "Arandr",
-          "Gpick",
-          "Kruler",
-          "MessageWin",  -- kalarm.
-          "Sxiv",
-          "Wpa_gui",
-          "pinentry",
-          "veromix",
-          "xtightvncviewer"},
-
-        name = {
-          "Event Tester",  -- xev.
-        },
-        role = {
-          "AlarmWindow",  -- Thunderbird's calendar.
-          "pop-up",       -- e.g. Google Chrome's (detached) Developer Tools.
-        }
-      }, properties = { floating = true }},
-
-    -- Add titlebars to normal clients and dialogs
-    { rule_any = {type = { "normal", "dialog" }
-      }, properties = { titlebars_enabled = false }
+    { rule = { type = "dialog" },
+      properties = { floating = true,
+                     ontop = true,
+                     skip_taskbar = true,
+                     urgent = true,
+                     --new_tag = true,
+                     --switchtotag = true,
+                     placement = awful.placement.centered
+                   }
     },
-
-    -- Set Firefox to always map on the tag named "2" on screen 1.
-    -- { rule = { class = "Firefox" },
-    --   properties = { screen = 1, tag = "2" } },
+    { rule = { class = "URxvt" },
+      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 = { 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",
+                        "Microsoft Teams - Preview",
+                        "org.remmina.Remmina",
+                    },
+                    instance = {
+                        "libreoffice",
+                    }
+                },
+      except_any = { type = { "dialog" } },
+      properties = { new_tag = {
+                        layout = layouts.maximised,
+                        volatile = true,
+                    },
+                     --switchtotag = true,
+                     focus = 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--}
 }
 -- }}}
 
@@ -553,6 +1207,12 @@ 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
+    --    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
@@ -560,12 +1220,15 @@ client.connect_signal("manage", function (c)
         -- Prevent clients from being unreachable after screen count changes.
         awful.placement.no_offscreen(c)
     end
+
+    c.maximized_horizontal = false
+    c.maximized_vertical = false
 end)
 
 -- Add a titlebar if titlebars_enabled is set to true in the rules.
 client.connect_signal("request::titlebars", function(c)
     -- buttons for the titlebar
-    local buttons = awful.util.table.join(
+    local buttons = gears.table.join(
         awful.button({ }, 1, function()
             client.focus = c
             c:raise()
@@ -604,16 +1267,46 @@ client.connect_signal("request::titlebars", function(c)
     }
 end)
 
--- Enable sloppy focus
+-- Enable sloppy focus, so that focus follows mouse.
 client.connect_signal("mouse::enter", function(c)
     if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
         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" 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