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

only move mouse pointer if target client will be visible/raised/focused
[etc/awesome.git] / .config / awesome / rc.lua
index d4d0cc31a3aa51936da4655c94b13c723c709aa2..aab31ddce7a1a92dde8d3a5e36e6b01183d80758 100644 (file)
@@ -5,6 +5,8 @@ local awful = require("awful")
 require("awful.autofocus")
 -- Widget and layout library
 local wibox = require("wibox")
 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
 -- Theme handling library
 local beautiful = require("beautiful")
 local xrdb = beautiful.xresources
@@ -20,10 +22,11 @@ require("awful.hotkeys_popup.keys")
 local debian = require("debian.menu")
 local has_fdo, freedesktop = pcall(require, "freedesktop")
 -- Other libraries
 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 lain = require("lain")
 local ccwidgets = require("cryptocoin_widgets")
-local luatz = require("luatz")
+local clocksarray = require("clocksarray")
+local dbg = require("debugfunc")
+local th = require("taghelpers")
 -- }}}
 
 -- {{{ Error handling
 -- }}}
 
 -- {{{ Error handling
@@ -56,11 +59,10 @@ end
 --xrdb.set_dpi(120, screen[2])
 
 -- Themes define colours, icons, font and wallpapers.
 --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.
 
 -- 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
 
 editor = os.getenv("EDITOR") or "editor"
 editor_cmd = terminal .. " -e " .. editor
 
@@ -73,29 +75,18 @@ modkey = "Mod4"
 cmdkey = "Mod3"
 
 -- Table of layouts to cover with awful.layout.inc, order matters.
 cmdkey = "Mod3"
 
 -- Table of layouts to cover with awful.layout.inc, order matters.
+local layouts = {
+    default = awful.layout.suit.fair,
+    tiled = awful.layout.suit.tile,
+    floating = awful.layout.suit.floating,
+    maximised = awful.layout.suit.max
+}
 awful.layout.layouts = {
 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,
 }
 }
-
-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
 -- }}}
 
 -- {{{ Helper functions
@@ -124,15 +115,20 @@ local function set_wallpaper(s)
     end
 end
 
     end
 end
 
-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,
-})
+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
 -- }}}
 
 -- {{{ Menu
@@ -172,28 +168,35 @@ menubar.utils.terminal = terminal -- Set the terminal for applications that requ
 -- }}}
 
 -- {{{ Wibar
 -- }}}
 
 -- {{{ 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()
 
 
 -- Keyboard map indicator and switcher
 mykeyboardlayout = awful.widget.keyboardlayout()
 
--- Create a textclock widget
-clocks = { wibox.widget.textclock("%a %d %b %H:%M:%S %Z", 1) }
+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,
+})
 
 
-ZONES = {
-  ["NZ"] = "Pacific/Auckland",
-  ["DE"] = "Europe/Berlin"
-}
-local now = luatz.time_in(nil)
-for c, tz in tblutils.sorted_pairs(ZONES) do
-    local t = luatz.time_in(tz)
-    if math.abs(os.difftime(t, now)) > 10 then
-        local widget = wibox.widget.textclock(c .. ": %H:%M (%a)", 60, tz)
-        table.insert(clocks, 1, spacer)
-        table.insert(clocks, 1, widget)
-    end
-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
 local taglist_buttons = gears.table.join(
 
 -- Create a wibox for each screen and add it
 local taglist_buttons = gears.table.join(
@@ -240,103 +243,331 @@ local tasklist_buttons = gears.table.join(
                                           end))
 -- }}}
 
                                           end))
 -- }}}
 
+-- {{{ Screens
+
 -- Re-set wallpaper when a screen's geometry changes (e.g. different resolution)
 screen.connect_signal("property::geometry", set_wallpaper)
 
 -- 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)
 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
 
     -- 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.
     -- 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
                            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
 
     -- 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
 
     -- 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(),
+            lain_bat.widget,
+            make_spacer(),
+        }, right_widgets)
+    end
+
+    s.mywibox:setup {
         layout = wibox.layout.align.horizontal,
         { -- Left widgets
             layout = wibox.layout.fixed.horizontal,
         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,
-                lain_bat.widget,
-                spacer,
-            },
-            clocks,
-            {
-                mylayoutbox[s],
-            }
-        ),
+        s.mytasklist, -- Middle widget
+        right_widgets,
     }
     }
+end) -- }}}
+
+-- {{{ autorandr integration
+local function find_screen_by_name(name)
+    for s in screen do
+        if s.name == name 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_name(target)
+                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 .. " onto screen " .. t.screen.name,
+    })
 end)
 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
+
+    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', {
+        stderr = 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,
+    master_width_factor = 0.33,
+    layout      = layouts.tiled,
+    selected    = true,
+    exec_once   = { terminal .. " -name irc -e env MOSH_TITLE_NOPREFIX=true mosh -4 -- irc-host tmux new -As irc irssi" },
+    instance    = { "irc" },
+    targets     = { "catalyst/eDP1", "mtvic/eDP1" },
+  },
+  {
+    name        = "[m]",
+    init        = true,
+    exclusive   = true,
+    master_width_factor = 0.67,
+    layout      = layouts.tiled,
+    selected    = true,
+    exec_once   = { "revolt" },
+    instance    = { "Revolt" },
+    targets     = { "catalyst/eDP1", "mtvic/eDP1" },
+  },
+  {
+    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     = { "catalyst/HDMI1", "mtvic/eDP1" },
+  },
+  {
+    name        = "chr",
+    init        = true,
+    exclusive   = true,
+    layout      = layouts.default,
+    exec_once   = { "chromium" },
+    class       = { "Chromium" },
+    targets     = { "catalyst/HDMI1", "mtvic/eDP1" },
+  },
+  {
+    name        = "ffx",
+    init        = true,
+    exclusive   = true,
+    layout      = layouts.default,
+    exec_once   = { "firefox" },
+    class       = { "Firefox" },
+    targets     = { "catalyst/HDMI1", "mtvic/eDP1" },
+  },
+})
+
+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
 -- }}}
 
 -- {{{ Mouse bindings
@@ -348,6 +579,24 @@ root.buttons(gears.table.join(
 -- }}}
 
 -- {{{ Key bindings
 -- }}}
 
 -- {{{ 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
+
 globalkeys = gears.table.join(
     awful.key({ modkey,           }, "s",      hotkeys_popup.show_help,
               {description="show help", group="awesome"}),
 globalkeys = gears.table.join(
     awful.key({ modkey,           }, "s",      hotkeys_popup.show_help,
               {description="show help", group="awesome"}),
@@ -370,8 +619,6 @@ globalkeys = gears.table.join(
         end,
         {description = "focus previous by index", group = "client"}
     ),
         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,
 
     -- Layout manipulation
     awful.key({ modkey, "Shift"   }, "k", function () awful.client.swap.byidx(  1)    end,
@@ -382,7 +629,7 @@ globalkeys = gears.table.join(
               {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"}),
               {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"   }, "Return", awful.client.urgent.jumpto,
               {description = "jump to urgent client", group = "client"}),
     awful.key({ modkey,           }, "Tab",
         function ()
               {description = "jump to urgent client", group = "client"}),
     awful.key({ modkey,           }, "Tab",
         function ()
@@ -396,6 +643,11 @@ globalkeys = gears.table.join(
     -- Standard program
     awful.key({ modkey,           }, "Return", function () awful.spawn(terminal) end,
               {description = "open a terminal", group = "launcher"}),
     -- 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,
     awful.key({ modkey, "Control" }, "r", awesome.restart,
               {description = "reload awesome", group = "awesome"}),
     awful.key({ modkey, "Shift"   }, "q", awesome.quit,
@@ -430,13 +682,59 @@ globalkeys = gears.table.join(
               {description = "restore minimized", group = "client"}),
 
     -- Prompt
               {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",
+                    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 {
               {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"
                     textbox      = awful.screen.focused().mypromptbox.widget,
                     exe_callback = awful.util.eval,
                     history_path = awful.util.get_cache_dir() .. "/history_eval"
@@ -444,9 +742,52 @@ globalkeys = gears.table.join(
               end,
               {description = "lua execute prompt", group = "awesome"}),
     -- Menubar
               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,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,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("[m]", true),
+              {description = "view tag '[m]'", group = "tag"}),
+    awful.key({ modkey, "Control" }, "u", toggle_tag_by_name("[m]"),
+              {description = "toggle tag '[m]'", 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",
 
 clientkeys = gears.table.join(
     awful.key({ modkey,           }, "f",
@@ -461,8 +802,6 @@ 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"}),
               {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,
-              {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,           }, "n",
     awful.key({ modkey,           }, "t",      function (c) c.ontop = not c.ontop            end,
               {description = "toggle keep on top", group = "client"}),
     awful.key({ modkey,           }, "n",
@@ -500,30 +839,16 @@ clientkeys = gears.table.join(
 for i = 1, 9 do
     globalkeys = gears.table.join(globalkeys,
         -- View tag only.
 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.
                   {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
                   {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
                           if tag then
                               client.focus:move_to_tag(tag)
                           end
@@ -534,7 +859,7 @@ for i = 1, 9 do
         awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
                   function ()
                       if client.focus then
         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
                           if tag then
                               client.focus:toggle_tag(tag)
                           end
@@ -555,13 +880,16 @@ 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 }, "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 }, "g", function () awful.spawn("gscan2pdf") end),
 awful.key({ cmdkey }, "v", function () awful.spawn("virt-manager") 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 }, "g", function () awful.spawn("gscan2pdf") end),
 awful.key({ cmdkey }, "v", function () awful.spawn("virt-manager") 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 }, "x", function ()
+    awful.spawn("/usr/bin/xscreensaver -no-capture-stderr")
+    os.execute("sleep 5")
+    awful.spawn("xscreensaver-command -lock")
+end),
 awful.key({ cmdkey, "Shift" }, "x", function () awful.spawn("xscreensaver-command -exit") end),
 
 -- function keys
 awful.key({ cmdkey, "Shift" }, "x", function () awful.spawn("xscreensaver-command -exit") end),
 
 -- function keys
@@ -591,9 +919,30 @@ root.keys(globalkeys)
 -- {{{ Rules
 -- Rules to apply to new clients (through the "manage" signal).
 
 -- {{{ 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)
     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
 
     end
 end
 
@@ -608,87 +957,91 @@ awful.rules.rules = {
                      buttons = clientbuttons,
                      screen = awful.screen.preferred,
                      placement = awful.placement.no_overlap+awful.placement.no_offscreen,
                      buttons = clientbuttons,
                      screen = awful.screen.preferred,
                      placement = awful.placement.no_overlap+awful.placement.no_offscreen,
-                     floating = false
+                     --floating = 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,
     { rule = { type = "dialog" },
       properties = { floating = true,
+                     ontop = true,
+                     skip_taskbar = true,
+                     urgent = true,
+                     --new_tag = true,
+                     --switchtotag = true,
                      placement = awful.placement.centered
                      placement = awful.placement.centered
-                 }
+                   }
     },
     },
-
     { rule = { class = "URxvt" },
     { 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,
-               },
-           },
-    { rule = { class = "Gxmessage" },
-               properties = {
-                   floating = true,
-               },
-           },
+      properties = { size_hints_honor = false, }
+    },
+    { rule = { instance =  "irc" },
+      callback = move_to_tag_by_name(nil, "irc"),
+    },
+    { rule = { class = "Revolt" },
+      callback = move_to_tag_by_name(nil, "[m]"),
+    },
+    { rule = { class = "Firefox" },
+      callback = move_to_tag_by_name(nil, "ffx"),
+    },
+    { rule = { class = "Chromium" },
+      callback = move_to_tag_by_name(nil, "chr"),
+    },
+    { rule = { class = "Thunderbird" },
+      callback = move_to_tag_by_name(nil, "cal"),
+    },
+    { rule_any = { class = {
+        "MuPDF",
+        "Wicd-client.py",
+    }},
+      properties = { floating = true,
+                     focus = true,
+                     placement = function(c)
+                         float_client_in_the_middle_with_margins(c, 50, 25)
+                     end,
+                   },
+    },
+    { rule_any = { class = {
+                        "Gscan2pdf",
+                        "Gimp",
+                    },
+                    instance = {
+                        "libreoffice",
+                    }
+                },
+      properties = { new_tag = {
+                        layout = layouts.maximised,
+                        volatile = true,
+                    },
+                     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--}
 }
 -- }}}
 
 }
 -- }}}
 
@@ -697,7 +1050,7 @@ 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.
 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 awesome.startup and
       not c.size_hints.user_position
 
     if awesome.startup and
       not c.size_hints.user_position
@@ -760,11 +1113,36 @@ client.connect_signal("mouse::enter", function(c)
     end
 end)
 
     end
 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)
 
 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
 end)
 
 -- vim:ft=lua:sw=4:sts=4:ts=4:et