awesomeWM / awesome

awesome window manager
https://awesomewm.org/
GNU General Public License v2.0
6.35k stars 598 forks source link

Top bar duplicated (and overlapping) on bottom bar when switching workspaces #2590

Closed lukasbash closed 5 years ago

lukasbash commented 5 years ago

Output of awesome --version:

awesome v4.2 (Human after all) • Compiled against Lua 5.3.5 (running with Lua 5.3) • D-Bus support: ✔ • execinfo support: ✔ • xcb-randr version: 1.6 • LGI version: 0.9.2

How to reproduce the issue:

Randomly switch between empty workspaces with keybindings. NOTE: There must be at least one non-empty tag!

Actual result:

At some point the top panel is duplicated to the bottom panel (even though no keys are working on the bottom panel then and on the top they are). screen01

Expected result:

The bottom panel should not be inferred in any way by the top panel. screen02

Notes: I used the multiclor theme from awesome-copycats. Here my rc.lua:


     Awesome WM configuration template
     github.com/lcpz

--]]

-- {{{ Required libraries
local awesome, client, mouse, screen, tag = awesome, client, mouse, screen, tag
local ipairs, string, os, table, tostring, tonumber, type = ipairs, string, os, table, tostring, tonumber, type

local gears         = require("gears")
local awful         = require("awful")
                      require("awful.autofocus")
local wibox         = require("wibox")
local beautiful     = require("beautiful")
local naughty       = require("naughty")
local lain          = require("lain")
--local menubar       = require("menubar")
local freedesktop   = require("freedesktop")
local hotkeys_popup = require("awful.hotkeys_popup").widget
                      require("awful.hotkeys_popup.keys")
local my_table      = awful.util.table or gears.table -- 4.{0,1} compatibility
-- }}}

-- {{{ Error handling
-- Check if awesome encountered an error during startup and fell back to
-- another config (This code will only ever execute for the fallback config)
if awesome.startup_errors then
    naughty.notify({ preset = naughty.config.presets.critical,
                     title = "Oops, there were errors during startup!",
                     text = awesome.startup_errors })
end

-- Handle runtime errors after startup
do
    local in_error = false
    awesome.connect_signal("debug::error", function (err)
        if in_error then return end
        in_error = true

        naughty.notify({ preset = naughty.config.presets.critical,
                         title = "Oops, an error happened!",
                         text = tostring(err) })
        in_error = false
    end)
end
-- }}}

-- {{{ Autostart windowless processes

-- This function will run once every time Awesome is started
local function run_once(cmd_arr)
    for _, cmd in ipairs(cmd_arr) do
        awful.spawn.with_shell(string.format("pgrep -u $USER -fx '%s' > /dev/null || (%s)", cmd, cmd))
    end
end

run_once({ "urxvtd", "unclutter -root" }) -- entries must be separated by commas

-- This function implements the XDG autostart specification
awful.spawn.with_shell(
    'if (xrdb -query | grep -q "^awesome\\.started:\\s*true$"); then exit; fi;' ..
    'xrdb -merge <<< "awesome.started:true";' ..
    -- list each of your autostart commands, followed by ; inside single quotes, followed by ..
    -- 'dex --environment Awesome --autostart --search-paths "$XDG_CONFIG_DIRS/autostart:$XDG_CONFIG_HOME/autostart"' -- https://github.com/jceb/dex
    'wal -R'
)

-- }}}

-- {{{ Variable definitions

local themes = {
    "blackburn",       -- 1
    "copland",         -- 2
    "dremora",         -- 3
    "holo",            -- 4
    "multicolor",      -- 5
    "powerarrow",      -- 6
    "powerarrow-dark", -- 7
    "rainbow",         -- 8
    "steamburn",       -- 9
    "vertex",          -- 10
}

local chosen_theme = themes[5]
local modkey       = "Mod4"
local altkey       = "Mod1"
local terminal     = "urxvtc"
local editor       = os.getenv("EDITOR") or "nano"
local gui_editor   = "code"
local browser      = "google-chrome-stable"
local guieditor    = "code"
local scrlocker    = "slock"

awful.util.terminal = terminal
-- awful.util.tagnames = { "term", "dev", "www", "doc", "media", "social", "etc"}
awful.util.tagnames = { "1", "2", "3", "4", "5" }
awful.layout.layouts = {
    awful.layout.suit.tile,
    awful.layout.suit.tile,
    awful.layout.suit.tile,
    awful.layout.suit.tile,
    awful.layout.suit.tile,
    -- awful.layout.suit.tile,
    -- awful.layout.suit.tile,
    -- awful.layout.suit.floating,
    -- 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,
    --lain.layout.cascade,
    --lain.layout.cascade.tile,
    --lain.layout.centerwork,
    --lain.layout.centerwork.horizontal,
    --lain.layout.termfair,
    --lain.layout.termfair.center,
}

awful.util.taglist_buttons = my_table.join(
    awful.button({ }, 1, function(t) t:view_only() end),
    awful.button({ modkey }, 1, function(t)
        if client.focus then
            client.focus:move_to_tag(t)
        end
    end),
    awful.button({ }, 3, awful.tag.viewtoggle),
    awful.button({ modkey }, 3, function(t)
        if client.focus then
            client.focus:toggle_tag(t)
        end
    end),
    awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
    awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
)

awful.util.tasklist_buttons = my_table.join(
    awful.button({ }, 1, function (c)
        if c == client.focus then
            c.minimized = true
        else
            --c:emit_signal("request::activate", "tasklist", {raise = true})<Paste>

            -- Without this, the following
            -- :isvisible() makes no sense
            c.minimized = false
            if not c:isvisible() and c.first_tag then
                c.first_tag:view_only()
            end
            -- This will also un-minimize
            -- the client, if needed
            client.focus = c
            c:raise()
        end
    end),
    awful.button({ }, 2, function (c) c:kill() end),
    awful.button({ }, 3, function ()
        local instance = nil

        return function ()
            if instance and instance.wibox.visible then
                instance:hide()
                instance = nil
            else
                instance = awful.menu.clients({theme = {width = 250}})
            end
        end
    end),
    awful.button({ }, 4, function () awful.client.focus.byidx(1) end),
    awful.button({ }, 5, function () awful.client.focus.byidx(-1) end)
)

lain.layout.termfair.nmaster           = 3
lain.layout.termfair.ncol              = 1
lain.layout.termfair.center.nmaster    = 3
lain.layout.termfair.center.ncol       = 1
lain.layout.cascade.tile.offset_x      = 2
lain.layout.cascade.tile.offset_y      = 32
lain.layout.cascade.tile.extra_padding = 5
lain.layout.cascade.tile.nmaster       = 5
lain.layout.cascade.tile.ncol          = 2

beautiful.init(string.format("%s/.config/awesome/themes/%s/theme-personal.lua", os.getenv("HOME"), chosen_theme))
-- }}}

-- {{{ Menu
local myawesomemenu = {
    { "hotkeys", function() return false, hotkeys_popup.show_help end },
    { "manual", terminal .. " -e man awesome" },
    { "edit config", string.format("%s %s", gui_editor, awesome.conffile) },
    { "restart", awesome.restart },
    { "quit", function() awesome.quit() end }
}
awful.util.mymainmenu = freedesktop.menu.build({
    icon_size = beautiful.menu_height or 16,
    before = {
        { "Awesome", myawesomemenu, beautiful.awesome_icon },
        -- other triads can be put here
    }
        -- },
    -- after = {
    --     { "Open terminal", terminal },
    --     -- other triads can be put here
    -- }
})
-- hide menu when mouse leaves it
--awful.util.mymainmenu.wibox:connect_signal("mouse::leave", function() awful.util.mymainmenu:hide() end)

--menubar.utils.terminal = terminal -- Set the Menubar terminal for applications that require it
-- }}}

-- {{{ Screen
-- Re-set wallpaper when a screen's geometry changes (e.g. different resolution)
screen.connect_signal("property::geometry", function(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
end)
-- Create a wibox for each screen and add it
awful.screen.connect_for_each_screen(function(s) beautiful.at_screen_connect(s) end)
-- }}}

-- {{{ Mouse bindings
root.buttons(my_table.join(
    awful.button({ }, 3, function () awful.util.mymainmenu:toggle() end),
    awful.button({ }, 4, awful.tag.viewnext),
    awful.button({ }, 5, awful.tag.viewprev)
))
-- }}}

-- {{{ Key bindings
globalkeys = my_table.join(
    -- Take a screenshot
    -- https://github.com/lcpz/dots/blob/master/bin/screenshot
    awful.key({ altkey }, "p", function() os.execute("flameshot gui") end,
              {description = "take a screenshot", group = "hotkeys"}),

    -- X screen locker
    awful.key({ altkey, "Control" }, "l", function () os.execute(scrlocker) end,
              {description = "lock screen", group = "hotkeys"}),

    -- Hotkeys
    awful.key({ modkey,           }, "s",      hotkeys_popup.show_help,
              {description = "show help", group="awesome"}),
    -- Tag browsing
    awful.key({ modkey,           }, "Left",   awful.tag.viewprev,
              {description = "view previous", group = "tag"}),
    awful.key({ modkey,           }, "Right",  awful.tag.viewnext,
              {description = "view next", group = "tag"}),
    awful.key({ modkey,           }, "Escape", awful.tag.history.restore,
              {description = "go back", group = "tag"}),

    -- Non-empty tag browsing
    awful.key({ altkey }, "Left", function () lain.util.tag_view_nonempty(-1) end,
              {description = "view  previous nonempty", group = "tag"}),
    awful.key({ altkey }, "Right", function () lain.util.tag_view_nonempty(1) end,
              {description = "view  previous nonempty", group = "tag"}),

    -- Default client focus
    awful.key({ altkey,           }, "j",
        function ()
            awful.client.focus.byidx( 1)
        end,
        {description = "focus next by index", group = "client"}
    ),
    awful.key({ altkey,           }, "k",
        function ()
            awful.client.focus.byidx(-1)
        end,
        {description = "focus previous by index", group = "client"}
    ),

    -- By direction client focus
    awful.key({ modkey }, "j",
        function()
            awful.client.focus.global_bydirection("down")
            if client.focus then client.focus:raise() end
        end,
        {description = "focus down", group = "client"}),
    awful.key({ modkey }, "k",
        function()
            awful.client.focus.global_bydirection("up")
            if client.focus then client.focus:raise() end
        end,
        {description = "focus up", group = "client"}),
    awful.key({ modkey }, "h",
        function()
            awful.client.focus.global_bydirection("left")
            if client.focus then client.focus:raise() end
        end,
        {description = "focus left", group = "client"}),
    awful.key({ modkey }, "l",
        function()
            awful.client.focus.global_bydirection("right")
            if client.focus then client.focus:raise() end
        end,
        {description = "focus right", group = "client"}),
    awful.key({ modkey,           }, "w", function () awful.util.mymainmenu:show() end,
              {description = "show main menu", group = "awesome"}),

    -- Layout manipulation
    awful.key({ modkey, "Shift"   }, "j", 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,
              {description = "swap with previous client by index", group = "client"}),
    awful.key({ modkey, "Control" }, "j", 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,
              {description = "focus the previous screen", group = "screen"}),
    awful.key({ modkey,           }, "u", awful.client.urgent.jumpto,
              {description = "jump to urgent client", group = "client"}),
    awful.key({ modkey,           }, "Tab",
        function ()
            awful.client.focus.history.previous()
            if client.focus then
                client.focus:raise()
            end
        end,
        {description = "go back", group = "client"}),

    -- Show/Hide Wibox
    awful.key({ modkey }, "b", function ()
            for s in screen do
                s.mywibox.visible = not s.mywibox.visible
                if s.mybottomwibox then
                    s.mybottomwibox.visible = not s.mybottomwibox.visible
                end
            end
        end,
        {description = "toggle wibox", group = "awesome"}),

    -- On the fly useless gaps change
    awful.key({ altkey, "Control" }, "+", function () lain.util.useless_gaps_resize(1) end,
              {description = "increment useless gaps", group = "tag"}),
    awful.key({ altkey, "Control" }, "-", function () lain.util.useless_gaps_resize(-1) end,
              {description = "decrement useless gaps", group = "tag"}),

    -- Dynamic tagging
    awful.key({ modkey, "Shift" }, "n", function () lain.util.add_tag() end,
              {description = "add new tag", group = "tag"}),
    awful.key({ modkey, "Shift" }, "r", function () lain.util.rename_tag() end,
              {description = "rename tag", group = "tag"}),
    awful.key({ modkey, "Shift" }, "Left", function () lain.util.move_tag(-1) end,
              {description = "move tag to the left", group = "tag"}),
    awful.key({ modkey, "Shift" }, "Right", function () lain.util.move_tag(1) end,
              {description = "move tag to the right", group = "tag"}),
    awful.key({ modkey, "Shift" }, "d", function () lain.util.delete_tag() end,
              {description = "delete tag", group = "tag"}),

    -- Standard program
    awful.key({ modkey,           }, "Return", function () awful.spawn(terminal) end,
              {description = "open a terminal", group = "launcher"}),
    awful.key({ modkey, "Control" }, "r", awesome.restart,
              {description = "reload awesome", group = "awesome"}),
    awful.key({ modkey, "Shift"   }, "q", awesome.quit,
              {description = "quit awesome", group = "awesome"}),

    awful.key({ altkey, "Shift"   }, "l",     function () awful.tag.incmwfact( 0.05)          end,
              {description = "increase master width factor", group = "layout"}),
    awful.key({ altkey, "Shift"   }, "h",     function () awful.tag.incmwfact(-0.05)          end,
              {description = "decrease master width factor", group = "layout"}),
    awful.key({ modkey, "Shift"   }, "h",     function () awful.tag.incnmaster( 1, nil, true) end,
              {description = "increase the number of master clients", group = "layout"}),
    awful.key({ modkey, "Shift"   }, "l",     function () awful.tag.incnmaster(-1, nil, true) end,
              {description = "decrease the number of master clients", group = "layout"}),
    awful.key({ modkey, "Control" }, "h",     function () awful.tag.incncol( 1, nil, true)    end,
              {description = "increase the number of columns", group = "layout"}),
    awful.key({ modkey, "Control" }, "l",     function () awful.tag.incncol(-1, nil, true)    end,
              {description = "decrease the number of columns", group = "layout"}),
    awful.key({ modkey,           }, "space", function () awful.layout.inc( 1)                end,
              {description = "select next", group = "layout"}),
    awful.key({ modkey, "Shift"   }, "space", function () awful.layout.inc(-1)                end,
              {description = "select previous", group = "layout"}),

    awful.key({ modkey, "Control" }, "n",
              function ()
                  local c = awful.client.restore()
                  -- Focus restored client
                  if c then
                      client.focus = c
                      c:raise()
                  end
              end,
              {description = "restore minimized", group = "client"}),

    -- Dropdown application
    awful.key({ modkey, }, "z", function () awful.screen.focused().quake:toggle() end,
              {description = "dropdown application", group = "launcher"}),

    -- Widgets popups
    awful.key({ altkey, }, "c", function () if beautiful.cal then beautiful.cal.show(7) end end,
              {description = "show calendar", group = "widgets"}),
    awful.key({ altkey, }, "h", function () if beautiful.fs then beautiful.fs.show(7) end end,
              {description = "show filesystem", group = "widgets"}),
    awful.key({ altkey, }, "w", function () if beautiful.weather then beautiful.weather.show(7) end end,
              {description = "show weather", group = "widgets"}),

    -- Brightness
    awful.key({ }, "XF86MonBrightnessUp", function () os.execute("xbacklight -inc 10") end,
              {description = "+10%", group = "hotkeys"}),
    awful.key({ }, "XF86MonBrightnessDown", function () os.execute("xbacklight -dec 10") end,
              {description = "-10%", group = "hotkeys"}),

    -- ALSA volume control
    awful.key({ }, "XF86AudioRaiseVolume",
        function ()
            os.execute(string.format("amixer -q set %s 1%%+", beautiful.volume.channel))
            beautiful.volume.update()
        end,
        {description = "volume up", group = "hotkeys"}),
    awful.key({ }, "XF86AudioLowerVolume",
        function ()
            os.execute(string.format("amixer -q set %s 1%%-", beautiful.volume.channel))
            beautiful.volume.update()
        end,
        {description = "volume down", group = "hotkeys"}),
    awful.key({ }, "XF86AudioMute",
        function ()
            os.execute(string.format("amixer -q set %s toggle", beautiful.volume.togglechannel or beautiful.volume.channel))
            beautiful.volume.update()
        end,
        {description = "toggle mute", group = "hotkeys"}),

    -- Copy primary to clipboard (terminals to gtk)
    awful.key({ modkey }, "c", function () awful.spawn.with_shell("xsel | xsel -i -b") end,
              {description = "copy terminal to gtk", group = "hotkeys"}),
    -- Copy clipboard to primary (gtk to terminals)
    awful.key({ modkey }, "v", function () awful.spawn.with_shell("xsel -b | xsel") end,
              {description = "copy gtk to terminal", group = "hotkeys"}),

    -- User programs
    awful.key({ modkey }, "q", function () awful.spawn(browser) end,
              {description = "run browser", group = "launcher"}),
    awful.key({ modkey }, "a", function () awful.spawn(guieditor) end,
              {description = "run gui editor", group = "launcher"}),

    -- Default
    --[[ Menubar
    awful.key({ modkey }, "p", function() menubar.show() end,
              {description = "show the menubar", group = "launcher"})
    --]]
    --[[ dmenu
    awful.key({ modkey }, "x", function ()
            os.execute(string.format("dmenu_run -i -fn 'Monospace' -nb '%s' -nf '%s' -sb '%s' -sf '%s'",
            beautiful.bg_normal, beautiful.fg_normal, beautiful.bg_focus, beautiful.fg_focus))
        end,
        {description = "show dmenu", group = "launcher"})
    --]]
    -- Prompt
    awful.key({ modkey }, "r", function () awful.screen.focused().mypromptbox:run() end,
              {description = "run prompt", group = "launcher"}),

    awful.key({ modkey }, "x",
              function ()
                  awful.prompt.run {
                    prompt       = "Run Lua code: ",
                    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"})
    --]]
)

clientkeys = my_table.join(
    awful.key({ altkey, "Shift"   }, "m",      lain.util.magnify_client,
              {description = "magnify client", group = "client"}),
    awful.key({ modkey,           }, "f",
        function (c)
            c.fullscreen = not c.fullscreen
            c:raise()
        end,
        {description = "toggle fullscreen", group = "client"}),
    awful.key({ modkey, "Shift"   }, "c",      function (c) c:kill()                         end,
              {description = "close", group = "client"}),
    awful.key({ modkey, "Control" }, "space",  awful.client.floating.toggle                     ,
              {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",
        function (c)
            -- The client currently has the input focus, so it cannot be
            -- minimized, since minimized clients can't have the focus.
            c.minimized = true
        end ,
        {description = "minimize", group = "client"}),
    awful.key({ modkey,           }, "m",
        function (c)
            c.maximized = not c.maximized
            c:raise()
        end ,
        {description = "maximize", group = "client"})
)

-- Bind all key numbers to tags.
-- Be careful: we use keycodes to make it works on any keyboard layout.
-- This should map on the top row of your keyboard, usually 1 to 9.
for i = 1, 9 do
    -- Hack to only show tags 1 and 9 in the shortcut window (mod+s)
    local descr_view, descr_toggle, descr_move, descr_toggle_focus
    if i == 1 or i == 9 then
        descr_view = {description = "view tag #", group = "tag"}
        descr_toggle = {description = "toggle tag #", group = "tag"}
        descr_move = {description = "move focused client to tag #", group = "tag"}
        descr_toggle_focus = {description = "toggle focused client on tag #", group = "tag"}
    end
    globalkeys = my_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,
                  descr_view),
        -- 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,
                  descr_toggle),
        -- Move client to tag.
        awful.key({ modkey, "Shift" }, "#" .. i + 9,
                  function ()
                      if client.focus then
                          local tag = client.focus.screen.tags[i]
                          if tag then
                              client.focus:move_to_tag(tag)
                          end
                     end
                  end,
                  descr_move),
        -- Toggle tag on focused client.
        awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
                  function ()
                      if client.focus then
                          local tag = client.focus.screen.tags[i]
                          if tag then
                              client.focus:toggle_tag(tag)
                          end
                      end
                  end,
                  descr_toggle_focus)
    )
end

clientbuttons = gears.table.join(
    awful.button({ }, 1, function (c)
        c:emit_signal("request::activate", "mouse_click", {raise = true})
    end),
    awful.button({ modkey }, 1, function (c)
        c:emit_signal("request::activate", "mouse_click", {raise = true})
        awful.mouse.client.move(c)
    end),
    awful.button({ modkey }, 3, function (c)
        c:emit_signal("request::activate", "mouse_click", {raise = true})
        awful.mouse.client.resize(c)
    end)
)

-- Set keys
root.keys(globalkeys)
-- }}}

-- {{{ Rules
-- Rules to apply to new clients (through the "manage" signal).
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,
                     raise = true,
                     keys = clientkeys,
                     buttons = clientbuttons,
                     screen = awful.screen.preferred,
                     placement = awful.placement.no_overlap+awful.placement.no_offscreen,
                     size_hints_honor = false
     }
    },

    -- Titlebars
    { rule_any = { type = { "dialog", "normal" } },
      properties = { titlebars_enabled = false } },

    { rule_any = { class = { "Google-chrome", "google-chrome" } },
      properties = { tag = awful.util.tagnames[3], maximized = true } },

    { rule_any = { class = { "urxvt", "URxvt" } },
      properties = { tag = awful.util.tagnames[1] } },

    { rule_any = { class = { "Code", "code" } },
          properties = { tag = awful.util.tagnames[2], maximized = true } },
}
-- }}}

-- {{{ Signals
-- Signal function to execute when a new client appears.
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 awesome.startup and
      not c.size_hints.user_position
      and not c.size_hints.program_position then
        -- Prevent clients from being unreachable after screen count changes.
        awful.placement.no_offscreen(c)
    end
end)

-- Enable sloppy focus, so that focus follows mouse.
client.connect_signal("mouse::enter", function(c)
    c:emit_signal("request::activate", "mouse_enter", {raise = true})
end)

-- No border for maximized clients
function border_adjust(c)
    if c.maximized then -- no borders if only 1 client visible
        c.border_width = 0
    elseif #awful.screen.focused().clients > 1 then
        c.border_width = beautiful.border_width
        c.border_color = beautiful.border_focus
    end
end

client.connect_signal("property::maximized", border_adjust)
client.connect_signal("focus", border_adjust)
client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)

-- possible workaround for tag preservation when switching back to default screen:
-- https://github.com/lcpz/awesome-copycats/issues/251
-- }}}

And the theme file:

--[[

     Multicolor Awesome WM theme 2.0
     github.com/lcpz

--]]

local gears = require("gears")
local lain  = require("lain")
local awful = require("awful")
local wibox = require("wibox")

local os = os
local my_table = awful.util.table or gears.table -- 4.{0,1} compatibility

local theme                                     = {}
theme.confdir                                   = os.getenv("HOME") .. "/.config/awesome/themes/multicolor"
theme.wallpaper                                 = os.getenv("HOME") .. "/Pictures/wallhaven-640342.jpg"
theme.font                                      = "Fantasque Sans Mono 12"
theme.icon_font                                 = "Font Awesome 5 Free Solid 10"
theme.menu_bg_normal                            = "#000000"
theme.menu_bg_focus                             = "#000000"
theme.bg_normal                                 = "#000000"
theme.bg_focus                                  = "#000000"
theme.bg_urgent                                 = "#000000"
theme.fg_normal                                 = "#aaaaaa"
theme.fg_focus                                  = "#ff8c00"
theme.fg_urgent                                 = "#af1d18"
theme.fg_minimize                               = "#ffffff"
theme.border_width                              = 1
theme.border_normal                             = "#1c2022"
theme.border_focus                              = "#606060"
theme.border_marked                             = "#3ca4d8"
theme.menu_border_width                         = 0
theme.menu_width                                = 130
theme.menu_submenu_icon                         = theme.confdir .. "/icons/submenu.png"
theme.menu_fg_normal                            = "#aaaaaa"
theme.menu_fg_focus                             = "#ff8c00"
theme.menu_bg_normal                            = "#050505dd"
theme.menu_bg_focus                             = "#050505dd"
theme.taglist_squares_sel                       = theme.confdir .. "/icons/square_a.png"
theme.taglist_squares_unsel                     = theme.confdir .. "/icons/square_b.png"
theme.tasklist_plain_task_name                  = true
theme.tasklist_disable_icon                     = true
theme.useless_gap                               = 5
theme.layout_tile                               = theme.confdir .. "/icons/tile.png"
theme.layout_tilegaps                           = theme.confdir .. "/icons/tilegaps.png"
theme.layout_tileleft                           = theme.confdir .. "/icons/tileleft.png"
theme.layout_tilebottom                         = theme.confdir .. "/icons/tilebottom.png"
theme.layout_tiletop                            = theme.confdir .. "/icons/tiletop.png"
theme.layout_fairv                              = theme.confdir .. "/icons/fairv.png"
theme.layout_fairh                              = theme.confdir .. "/icons/fairh.png"
theme.layout_spiral                             = theme.confdir .. "/icons/spiral.png"
theme.layout_dwindle                            = theme.confdir .. "/icons/dwindle.png"
theme.layout_max                                = theme.confdir .. "/icons/max.png"
theme.layout_fullscreen                         = theme.confdir .. "/icons/fullscreen.png"
theme.layout_magnifier                          = theme.confdir .. "/icons/magnifier.png"
theme.layout_floating                           = theme.confdir .. "/icons/floating.png"

local markup = lain.util.markup

-- Textclock
os.setlocale(os.getenv("LANG")) -- to localize the clock
local clockicon = wibox.widget.textbox(markup("#de5e1e", "")) --wibox.widget.imagebox(theme.widget_clock)
clockicon.font = theme.icon_font
local mytextclock = wibox.widget.textclock(markup("#7788af", " %A %d %B ") .. markup("#ab7367", ">") .. markup("#de5e1e", " %H:%M:%S "), 1)
mytextclock.font = theme.font

-- Calendar
theme.cal = lain.widget.cal({
    attach_to = { mytextclock },
    notification_preset = {
        font = "Hack 10",
        fg   = theme.fg_normal,
        bg   = theme.bg_normal
    }
})

-- Weather
local weathericon = wibox.widget.textbox(markup("#eca4c4", ""))
weathericon.font = theme.icon_font
theme.weather = lain.widget.weather({
    city_id = 2761369, -- placeholder (London)
    notification_preset = { font = "Hack 10", fg = theme.fg_normal },
    weather_na_markup = markup.fontfg(theme.font, "#eca4c4", " N/A "),
    settings = function()
        descr = weather_now["weather"][1]["description"]:lower()
        units = math.floor(weather_now["main"]["temp"])
        widget:set_markup(markup.fontfg(theme.font, "#eca4c4", " " .. descr .. " @ " .. units .. "°C"))
    end
})

-- / fs
local fsicon = wibox.widget.textbox(markup("#80d9d8", ""))
fsicon.font = theme.icon_font
theme.fs = lain.widget.fs({
    notification_preset = { font = "Hack 10", fg = theme.fg_normal },
    settings  = function()
        widget:set_markup(
            markup.fontfg(theme.font, "#80d9d8", " " .. fs_now["/"].percentage .. "% (" ..
            string.format("%.2f", fs_now["/"].free) .. " " .. fs_now["/"].units .. " left)")
        )
    end
})

-- Mail IMAP check
--[[ commented because it needs to be set before use
local mailicon = wibox.widget.imagebox()
theme.mail = lain.widget.imap({
    timeout  = 180,
    server   = "server",
    mail     = "mail",
    password = "keyring get mail",
    settings = function()
        if mailcount > 0 then
            mailicon:set_image(theme.widget_mail)
            widget:set_markup(markup.fontfg(theme.font, "#cccccc", mailcount .. " "))
        else
            widget:set_text("")
            --mailicon:set_image() -- not working in 4.0
            mailicon._private.image = nil
            mailicon:emit_signal("widget::redraw_needed")
            mailicon:emit_signal("widget::layout_changed")
        end
    end
})
--]]

-- CPU
local cpuicon = wibox.widget.textbox(markup("#e33a6e", ""))
cpuicon.font = theme.icon_font
local cpu = lain.widget.cpu({
    settings = function()
        widget:set_markup(markup.fontfg(theme.font, "#e33a6e", " " .. cpu_now.usage .. "%"))
    end
})

-- Coretemp
local tempicon = wibox.widget.textbox(markup("#f1af5f", ""))
tempicon.font = theme.icon_font
local temp = lain.widget.temp({
    settings = function()
        widget:set_markup(markup.fontfg(theme.font, "#f1af5f", " " .. coretemp_now .. "°C"))
    end
})

-- Battery
local baticon = wibox.widget.textbox(markup(theme.fg_normal, ""))
baticon.font = theme.icon_font
local bat = lain.widget.bat({
    settings = function()
        local perc = bat_now.perc ~= "N/A" and bat_now.perc .. "%" or bat_now.perc

        if bat_now.ac_status == 1 then
            perc = perc .. " (plugged)"
        end

        widget:set_markup(markup.fontfg(theme.font, theme.fg_normal, " " .. perc))
    end
})

-- ALSA volume
local volicon = wibox.widget.textbox(markup("#7493d2", ""))
volicon.font = theme.icon_font
theme.volume = lain.widget.alsa({
    settings = function()
        if volume_now.status == "off" then
            volume_now.level = volume_now.level .. "M"
        end

        -- widget:set_text(" " .. volume_now.level .. "%")
        -- widget:set_markup(" " .. volume_now.level .. "%")
        widget:set_markup(markup.fontfg(theme.font, "#7493d2", " " .. volume_now.level .. "%"))
    end
})

-- Net
local netdownicon = wibox.widget.textbox(markup("#87af5f", ""))
netdownicon.font = theme.icon_font
local netdowninfo = wibox.widget.textbox()
local netupicon = wibox.widget.textbox(markup("#e54c62", ""))
netupicon.font = theme.icon_font
local netupinfo = lain.widget.net({
    settings = function()
        if iface ~= "network off" and
           string.match(theme.weather.widget.text, " N/A")
        then
            theme.weather.update()
        end

        widget:set_markup(markup.fontfg(theme.font, "#e54c62", " " .. net_now.sent))
        netdowninfo:set_markup(markup.fontfg(theme.font, "#87af5f", " " .. net_now.received .. " "))
    end
})

-- MEM
local memicon = wibox.widget.textbox(markup("#e0da37", ""))
memicon.font = theme.icon_font
local memory = lain.widget.mem({
    settings = function()
        widget:set_markup(markup.fontfg(theme.font, "#e0da37", " " .. mem_now.used .. "M"))
    end
})

local tbox_separator = wibox.widget.textbox(markup("#ab7367", " // "))
tbox_separator.font = theme.font

function theme.at_screen_connect(s)
    -- Quake application
    s.quake = lain.util.quake({ app = awful.util.terminal })

    -- If wallpaper is a function, call it with the screen
    local wallpaper = theme.wallpaper
    if type(wallpaper) == "function" then
        wallpaper = wallpaper(s)
    end
    gears.wallpaper.maximized(wallpaper, s, true)

    -- Tags
    awful.tag(awful.util.tagnames, s, awful.layout.layouts)

    -- Create a promptbox for each screen
    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.
    s.mylayoutbox = awful.widget.layoutbox(s)
    s.mylayoutbox:buttons(my_table.join(
                           awful.button({}, 1, function () awful.layout.inc( 1) end),
                           awful.button({}, 2, function () awful.layout.set( awful.layout.layouts[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
    s.mytaglist = awful.widget.taglist(s, awful.widget.taglist.filter.all, awful.util.taglist_buttons)

    -- Create a tasklist widget
    s.mytasklist = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, awful.util.tasklist_buttons)

    -- Create the wibox
    s.mywibox = awful.wibar({ position = "top", screen = s, height = 24, bg = theme.bg_normal, fg = theme.fg_normal })

    -- Add widgets to the wibox
    s.mywibox:setup {
        layout = wibox.layout.align.horizontal,
        { -- Left widgets
            layout = wibox.layout.fixed.horizontal,
            --s.mylayoutbox,
            s.mytaglist,
            s.mypromptbox,
        },
        --s.mytasklist, -- Middle widget
        nil,
        { -- Right widgets
            layout = wibox.layout.fixed.horizontal,
            wibox.widget.systray(),
            --mailicon,
            --theme.mail.widget,
            netdownicon,
            netdowninfo,
            netupicon,
            netupinfo.widget,
            tbox_separator,
            volicon,
            theme.volume.widget,
            tbox_separator,
            memicon,
            memory.widget,
            tbox_separator,
            cpuicon,
            cpu.widget,
            tbox_separator,
            fsicon,
            theme.fs.widget,
            tbox_separator,
            weathericon,
            theme.weather.widget,
            tbox_separator,
            tempicon,
            temp.widget,
            tbox_separator,
            baticon,
            bat.widget,
            tbox_separator,
            clockicon,
            mytextclock,
        },
    }

    -- Create the bottom wibox
    s.mybottomwibox = awful.wibar({ position = "bottom", screen = s, border_width = 0, height = 24, bg = theme.bg_normal, fg = theme.fg_normal })

    -- Add widgets to the bottom wibox
    s.mybottomwibox:setup {
        layout = wibox.layout.align.horizontal,
        { -- Left widgets
            layout = wibox.layout.fixed.horizontal,
        },
        s.mytasklist, -- Middle widget
        { -- Right widgets
            layout = wibox.layout.fixed.horizontal,
            s.mylayoutbox,
        },
    }
end

return theme
Elv13 commented 5 years ago

How many screens do you have, can you give the relevant xrandr output? How were the screens configured?

lukasbash commented 5 years ago

@Elv13 I have just one screen (it is my notebook). xrandr outputs:

Screen 0: minimum 8 x 8, current 1920 x 1080, maximum 32767 x 32767
eDP1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 290mm x 170mm
   1920x1080     60.00*+  59.93    48.00  
   1680x1050     59.88  
   1400x1050     59.98  
   1600x900      60.00    59.95    59.82  
   1280x1024     60.02  
   1400x900      59.96    59.88  
   1280x960      60.00  
   1368x768      60.00    59.88    59.85  
   1280x800      59.81    59.91  
   1280x720      59.86    60.00    59.74  
   1024x768      60.00  
   1024x576      60.00    59.90    59.82  
   960x540       60.00    59.63    59.82  
   800x600       60.32    56.25  
   864x486       60.00    59.92    59.57  
   640x480       59.94  
   720x405       59.51    60.00    58.99  
   640x360       59.84    59.32    60.00  
DP1 disconnected (normal left inverted right x axis y axis)
DP2 disconnected (normal left inverted right x axis y axis)
VIRTUAL1 disconnected (normal left inverted right x axis y axis)

What do you mean how the screens were configured? I did not start with plain xorg. As I still have gnome installed, they might be configured through the gnome shell. (I am also launching awesome through GDM). Or do you refer to any specific configuration?

lukasbash commented 5 years ago

Update: It seems that it is related to the layoutbox at the bottom bar. If I remove the layoutbox from the bar, there seems to be no issue.

How could it be?

-- Add widgets to the bottom wibox
    s.mybottomwibox:setup {
        layout = wibox.layout.align.horizontal,
        { -- Left widgets
            layout = wibox.layout.fixed.horizontal,
        },
        s.mytasklist, -- Middle widget
        { -- Right widgets
            layout = wibox.layout.fixed.horizontal,
            -- If line below is commented, there seems to be no issue
            -- s.mylayoutbox,
        },
    }
psychon commented 5 years ago

Similar symptom: #2470

Elv13 commented 5 years ago

Wow, it used to happen often back in Awesome 3.4 days (10 years ago) and it was a driver issue (and usually had some pink artifact for some reasons), but before #2470 and this I havn't heard of a corrupted surface bug in a long time.

When it happen, can you try to call awesome-client "mouse.screen.mybottomwibox.draw()" (and/or awesome-client 'mouse.screen.mybottomwibox._drawable._do_complete_repaint()') and see what happen?

actionless commented 5 years ago

wasn't it id-related problem? (in related ticket, not in 3.4)

lukasbash commented 5 years ago

Thank you for all the responses so far!

@Elv13 I tried to execute the two lines you posted. awesome-client "mouse.screen.mybottomwibox.draw()" actually did nothing. awesome-client 'mouse.screen.mybottomwibox._drawable._do_complete_repaint()' fixed the bottom bar again.

What does this mean now?

Elv13 commented 5 years ago

That it's a duplicate of #2470. The surface gets corrupted with precisely the content of another surface with no artifacts, which is a red flag in itself. Can you try with git-master? It's weird because if it was really an awesome bug, why did it take more than a year to show up in a stable release... Also that code is like from 2011 so saying it has been battle tested would be an understatement.

May I ask for a "fun" experiment. Can you make one of the 2 bar taller than the other and reproduce the problem. If they both get rendered correctly (correct height) then it means Awesome paints the wrong layout on the surface. It would rule out driver issues.

lukasbash commented 5 years ago

@Elv13 Your "fun" experiment leads to the following result:

So the issue is only gone when I use double the size of the bottom bar. Increasing or decreasing with lower numbers does not do anything. Sounds very weird.

I will not try to install it from git master. Question to this: Is the package receipt still valid for arch linux? The package seems to be outdated. Should I checkout the repo or can I use the AUR?

See https://aur.archlinux.org/packages/awesome-git

psychon commented 5 years ago

Random data point: Both #2470 and this issue are with Lua 5.3 (but 5.3.4 vs 5.3.5).

The package seems to be outdated. Should I checkout the repo or can I use the AUR?

Why does it seem to be outdated? The AUR package looks fine to me.

Randomly switch between empty workspaces with keybindings.

Looking at the config: In the top wibar, this updates the taglist. This causes a relayout and also a redraw (at least two of the taglist widgets change their background). There are also lots of other widgets in there that I did not look at... The bottom wibar only has a tasklist and a layoutbox. The tasklist does a delayed update and the layoutbox does an immediate update. Thus, I guess there will actually be two redraws, one for the layoutbox and then later for the tasklist.

The "broken" screenshot shows that the layoutbox is drawn ontop of the contents of the upper wibar, so the "copying of contents" must happen before the layoutbox is drawn...

Apropos copying: I do not think that a tag change should cause a complete repaint; only the changed parts are redrawn. Thus, if this were just painting to the wrong surface, I'd only expect a partial copy of the top wibar.

It seems that it is related to the layoutbox at the bottom bar. If I remove the layoutbox from the bar, there seems to be no issue.

So... given that the layoutbox is ontop of the content of the top wibar.... I don't know. The layoutbox is also only shown in one of the wibars, so this cannot be something due to the widget appearing twice.

Setting the bottom bar to height 22 instead of 24 -> issue still persists Setting the bottom bar to height 26 instead of 24 -> issue still persists Setting the bottom bar to height 12 instead of 24 -> issue still persists

How does the result look like? E.g. if the bottom bar has height 26, is the copy of the top bar drawn with height 24 or 26? And with height 12, is it cut of or "scaled"?

lukasbash commented 5 years ago

@psychon

Why does it seem to be outdated? The AUR package looks fine to me.

I was just curious because the package has not been updated since more than a year. No dependency, nothing. That's why I was asking. Also the package details show a lower version than I have actually installed. It shows awesome-git 4.0.225.gd6412b96-1

The result of the height changes looks like this: Height 26 (instead of 24): screen03

Height 12 (instead of 24): screen04

So it actually seems it is not "scaled" but drawn with its original height (top bar copy).

Elv13 commented 5 years ago

Can you try with https://aur.archlinux.org/packages/awesome-luajit-git/

Now we know much more.

The next test will use a different Lua version, so we will know if it is related to the Lua version or the LGI binding Lua version. That will narrow the possibilities.

psychon commented 5 years ago

Why does it seem to be outdated? The AUR package looks fine to me.

I was just curious because [...]

The PKGBUILD contains source=("$pkgname::git+https://github.com/awesomeWM/awesome.git"), so it will build from git. I'm no expert, but I don't see anything in there forcing a specific git hash. I guess they just have to provide some pkgver for AUR.

So it actually seems it is not "scaled" but drawn with its original height (top bar copy).

Wow. If this would persist, I had an idea on what kind of "memory corruption" could cause this. But for just a single draw... I'm confused.

Another random idea: Does running awesome with --no-argb make the issue go away as well? [If yes: This points fingers at the X11 server / video driver]

lukasbash commented 5 years ago

So I used https://aur.archlinux.org/packages/awesome-git to install it.

To be precise, here you have another version output:

awesome v4.2-598-g8fe06f95 (Human after all)
 • Compiled against Lua 5.3.5 (running with Lua 5.3)
 • D-Bus support: ✔
 • execinfo support: ✔
 • xcb-randr version: 1.6
 • LGI version: 0.9.2

Unfortunately the issue still persists. See: screen05

Should I still try to use https://aur.archlinux.org/packages/awesome-luajit-git/ ?

EDIT: Issue reproducible also with https://aur.archlinux.org/packages/awesome-luajit-git/

lukasbash commented 5 years ago

@Elv13 @psychon

LOL what a guess!!

Another random idea: Does running awesome with --no-argb make the issue go away as well?

Yes it indeed goes away. What the heck is happening here? XD

(But as I am launching awesome from GDM I would like to avoid passing this argument as I would have to login from another TTY.)

Is there a fix necessary in awesome itself? Or did I configure something wrong on X?

psychon commented 5 years ago

(But as I am launching awesome from GDM I would like to avoid passing this argument as I would have to login from another TTY.)

Personally, I have some hack in /usr/share/xsessions/own-awesome-session.desktop:

[Desktop Entry]
Name=awesomeSession
Exec=/home/psychon/bin/awesome-session
Type=XSession

I use this to also start some other stuff (e.g. compton) when I log in. You could do something similar with a shell script that simply does exec awesome --no-argb.

Is there a fix necessary in awesome itself? Or did I configure something wrong on X?

No and no.

Things are complicated. But --no-argb does not really change anything in awesome. The only difference is that awesome now creates all its windows with 32 bits per pixel (alpha/red/green/blue) instead of 24 bits per pixel (red/green/blue). Also, awesome tells cairo about this difference and cairo handles all the actual differences in drawing things for us.

Without an (unused) alpha channel, true transparency does not work, but that requires running a compositing manager like compton anyway to work. The plus side of having this is that awesome "behaves more" like most other window managers in that it creates 24 bpp windows. Apparently, the 32bpp code in Xorg still has some problems and gets random things wrong (although I haven't heard about a problem like this before).

Does this clear things up for you or should I bore you with more technical details?

On what happens next: I don't know. I'm 99.8% sure that the issue is not in awesome itself. Also, I'm 99.5% sure that I won't be able to figure out a bug in Xorg that I cannot even reproduce, so I guess this bug will just linger around forever until the Xorg people accidentally fix this bug. I don't even think that this is worth reporting upstream, because instructions like "install this, put this file here, and then do these steps 10 times and hope that the issue shows up" are scary and already sound time-intensive. And even then one would need a good idea on how to debug this.

Sorry.

lukasbash commented 5 years ago

Personally, I have some hack [...]

I guess I have no other choice to also get this kind of workaround in place.

Apparently, the 32bpp code in Xorg still has some problems and gets random things wrong [...]

Can you control whether awesome creates windows/drawings in 32bpp or 24bpp? Wouldn't it make sense then to not use the alpha channel at all? Or is it automatic if the --no-argb flag is/is not passed?

[...] so I guess this bug will just linger around forever until the Xorg people accidentally fix this [...]

That's so sad. But I absolutely understand you. Maybe at some point they fix it. Maybe at some point it turns out that the issue is actually caused by awesome. You never know.

Sorry.

Really thank you for the efforts to debug and trace this with me. No need to say sorry at all. If you need any more information, help or steps to reproduce and fix this issue, just ping me.

For now, to resolve this issue, I will either create my own session entry and pass the --no-argb flag, or I will just remove the bottom bar.

Elv13 commented 5 years ago

Can you control whether awesome creates windows/drawings in 32bpp or 24bpp? Wouldn't it make sense then to not use the alpha channel at all? Or is it automatic if the --no-argb flag is/is not passed?

All Awesome API widgets (bars, titlebars, notification, etc) support transparency. There is no real way to detect if the user theme has transparency. Nor if it will have in the future. The only thing that could be done is using 24bpp when there is no compositing then reloading all surfaces with 32bpp, including reparenting all clients, when a compositor shows up. This would be more complex and probably would cause more bugs, not less. ARGB surfaces are officially supported by Xorg. If they don't work, then its the driver developer problem to fix it. Please note that some web browser have an explicit blacklist of open source drivers because of related issues. We wont start to keep that kind of version per version blacklist of all drivers. They release much more often than us anyway.

lukasbash commented 5 years ago

But that would mean, that if I actively use the alpha channel or transparency in my bars it could be that it suddenly works right? Maybe I should give it a try (also with a running composition manager maybe).

Still I am curious if this does not happen in other places as well (and other window managers or desktop environments)...

lukasbash commented 5 years ago

Hello again guys,

I told you that I will get back to you :laughing: I think we should close the issue. The issue was resolved for me by using a composition manager. Even without using the argb flag on session start.

Thank you guys for the help!