Awesome: Screen ordering can cause issues with where clients spawn

Created on 15 Jul 2015  Â·  26Comments  Â·  Source: awesomeWM/awesome

I have an issue where I can't spawn clients on one of my screens. my screen layout is illustrated below.

| 3 | 1 | 2 |
+-----------+

the screen I can't spawn windows on is 2. they always appear on 1. the reason for this ordering is because I configured X to treat 1 as my primary display. awesome counts forward from there it seems and loops around. that being said if I spawn clients on 3 it works fine.

I've tried using the version of awesome that shipped with Fedora 22 and it was exhibiting the issue. I tried using master. I even tried moving .config/awesome to see if it was a configuration issue.

~ % awesome --version
awesome v3.5.2-530-g1e9da09 (The Fox)
 • Build: Jul 14 2015 23:13:10 for x86_64 by gcc version 5.1.1 ([email protected])
 • Compiled against Lua 5.3.0 (running with Lua 5.3)
 • D-Bus support: ✔

let me know if I missed anything or if there's something I can do to help troubleshoot this.

thanks!

confirmed

All 26 comments

I just had a thought and tested around with the ordering of my displays. I moved screen 3 so that it appears after screen 2 in X. the new layout illustrated below:

| 1 | 2 | 3 |
+-----------+

I no longer have the issue it seems! strange!

Could you add this to the end of the default config, try to open a single client and see what it reports? (Code untested)
This should report lots and lots of stuff, especially about how it gets moved between screens.

function connect(signal)
    client.connect_signal(signal, function(c)
        local g = c:geometry()
        print(signal, c, c.name, c.screen, c.border_width, g.x,g.y,g.width,g.height, debug.traceback())
    end)
end
connect("manage")
connect("property::screen")
connect("property::border_width")
connect("tagged")
connect("untagged")
connect("focus")
connect("unfocus")
connect("list")
for s=1, screen.count() do
    local g = screen[s].geometry
    print("screen",s,g.x,g.y,g.width,g.height)
end

I am intermittently having the same problem, I think. I loaded your code psychon, and it actually seemed to jog it into working again. Actually the code had an error in it, complaining that you are trying to index c which is a nil value in line "local g = c:geometry()". I removed it and reloaded the config and the problem was fixed, strangely!

Only two screens set up on my system:
xrandr --output HDMI1 --mode 1920x1080 --left-of eDP1 --primary &

When I tried to spawn windows on eDP1 (the right screen, my built-in laptop screen) it would spawn one or two windows only, placed poorly, and the rest would get spawned on HDMI1 (the left screen) with placement somewhere in between the two screens. Pretty strange. Maybe this is a different problem? I'm happy to create a new issue if it is, as I don't want to hijack this one.

@psychon sorry I haven't gotten around to try that debug code. I'll get a report for you tonight. I hope the issue is still reproducible.

Might be related to / fixed by https://github.com/awesomeWM/awesome/pull/331?! (without much investigation)

the good news is that I just confirmed this can still be replicated. I'll schedule some time in to get that debugging info.

Closing since the reporter vanished. Feel free to reopen if needed.

sorry it's taken me almost a year to get this output but I was able to replicate it now.

britestar ~ % awesome --version
awesome v3.5.2-1867-g45d555d (The Fox)
 • Compiled against Lua 5.3.3 (running with Lua 5.3)
 • D-Bus support: ✘
britestar ~ %

and the logging info:

xterm: cannot load font '-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1'
property::screen        window/client(): 0x16cc108        nil        screen: 0xa98298        0        0        0        0        0        stack traceback:
        /home/spyroboy/.config/awesome/rc.lua:450: in function </home/spyroboy/.config/awesome/rc.lua:448>
property::border_width        window/client(): 0x16cc108        nil        screen: 0xa98298        1        0        0        499        316        stack traceback:
        /home/spyroboy/.config/awesome/rc.lua:450: in function </home/spyroboy/.config/awesome/rc.lua:448>
2016-08-19 18:25:34 W: awesome: luaA_dofunction:77: error while running function!
stack traceback:
        /home/spyroboy/.config/awesome/rc.lua:449: in function </home/spyroboy/.config/awesome/rc.lua:448>
error: /home/spyroboy/.config/awesome/rc.lua:449: attempt to index a nil value (local 'c')
property::screen        window/client(xterm): 0x16cc108        xterm        screen: 0xaa9908        1        3840        -60        499        316        stack traceback:
        /home/spyroboy/.config/awesome/rc.lua:450: in function </home/spyroboy/.config/awesome/rc.lua:448>
        [C]: in metamethod '__newindex'
        /usr/local/share/awesome/lib/awful/tag.lua:1284: in function </usr/local/share/awesome/lib/awful/tag.lua:1273>
property::screen        window/client(xterm): 0x16cc108        xterm        screen: 0xaa9908        1        3840        -60        499        316        stack traceback:
        /home/spyroboy/.config/awesome/rc.lua:450: in function </home/spyroboy/.config/awesome/rc.lua:448>
        [C]: in metamethod '__newindex'
        /usr/local/share/awesome/lib/awful/tag.lua:1284: in function </usr/local/share/awesome/lib/awful/tag.lua:1273>
tagged        window/client(xterm): 0x16cc108        xterm        screen: 0xaa9908        1        3840        -60        499        316        stack traceback:
        /home/spyroboy/.config/awesome/rc.lua:450: in function </home/spyroboy/.config/awesome/rc.lua:448>
        [C]: in method 'tags'
        /usr/local/share/awesome/lib/awful/client.lua:461: in method 'to_selected_tags'
        /usr/local/share/awesome/lib/awful/ewmh.lua:138: in function 'awful.ewmh.tag'
        [C]: in method 'emit_signal'
        /usr/local/share/awesome/lib/awful/rules.lua:431: in function 'awful.rules.execute'
        /usr/local/share/awesome/lib/awful/rules.lua:210: in function 'awful.rules.apply'
unfocus        window/client(Terminal): 0x16ad6a8        Terminal        screen: 0xaa9908        1        1920        20        1915        1174        stack traceback:
        /home/spyroboy/.config/awesome/rc.lua:450: in function </home/spyroboy/.config/awesome/rc.lua:448>
        [C]: in metamethod '__newindex'
        /usr/local/share/awesome/lib/awful/ewmh.lua:115: in function 'awful.ewmh.activate'
        [C]: in method 'emit_signal'
        /usr/local/share/awesome/lib/awful/rules.lua:491: in function 'awful.rules.execute'
        /usr/local/share/awesome/lib/awful/rules.lua:210: in function 'awful.rules.apply'
focus        window/client(xterm): 0x16cc108        xterm        screen: 0xaa9908        1        3840        -60        499        316        stack traceback:
        /home/spyroboy/.config/awesome/rc.lua:450: in function </home/spyroboy/.config/awesome/rc.lua:448>
        [C]: in metamethod '__newindex'
        /usr/local/share/awesome/lib/awful/ewmh.lua:115: in function 'awful.ewmh.activate'
        [C]: in method 'emit_signal'
        /usr/local/share/awesome/lib/awful/rules.lua:491: in function 'awful.rules.execute'
        /usr/local/share/awesome/lib/awful/rules.lua:210: in function 'awful.rules.apply'
manage        window/client(xterm): 0x16cc108        xterm        screen: 0xaa9908        1        1920        20        499        316        stack traceback:
        /home/spyroboy/.config/awesome/rc.lua:450: in function </home/spyroboy/.config/awesome/rc.lua:448>

I'm having this (or a very similar problem) as well.
I've got my screens like [3][2][1]. Every terminal I spawn is spawned on [1] no matter where my focus is.
How ever, if I spawn something else from the terminal, like arandr it goes like this:

terminal on [3] ==> arandr spawns on [1]
terminal on [2] ==> arandr spawns on [3]
terminal on [1] ==> arandr spawns on [1]

My xrandr line looks like this

xrandr --output VIRTUAL1 --off --output eDP1 --mode 1920x1080 --pos 0x840 --rotate normal --output DP1 --off --output HDMI2 --mode 1920x1080 --pos 1920x0 --rotate left --output HDMI1 --primary --mode 1920x1080 --pos 3000x560 --rotate normal --output DP2 --off

Using awesome 3.5.9 on Arch.

qwelyt@machine ~ % awesome --version
awesome v3.5.9 (Mighty Ravendark)
 • Build: Mar 12 2016 01:11:40 for x86_64 by gcc version 5.3.0 (builduser@rw)
 • Compiled against Lua 5.3.2 (running with Lua 5.3)
 • D-Bus support: ✔

qwelyt@machine ~ % uname -a
Linux machine 4.8.6-1-ARCH #1 SMP PREEMPT Mon Oct 31 18:51:30 CET 2016 x86_64 GNU/Linux

I tried to get the log part, but I don't seem to be able to find where awesome prints to.

just tested this in 4.0. issue is gone now. solved by #1091

I'm using 4.0 and I still have this problem.

qwelyt@machine ~ % awesome --version
awesome v4.0 (Harder, Better, Faster, Stronger)
 • Compiled against Lua 5.3.3 (running with Lua 5.3)
 • D-Bus support: ✔
 • execinfo support: ✔
 • RandR 1.5 support: ✔
 • LGI version: 0.9.1

qwelyt@machine ~ % uname -a
Linux fibe-Dator 4.8.13-1-ARCH #1 SMP PREEMPT Fri Dec 9 07:24:34 CET 2016 x86_64 GNU/Linux

My screens are ordered like [1][3][2].
My xrandr is

#!/bin/sh
xrandr --output VIRTUAL1 --off --output eDP1 --mode 1920x1080 --pos 0x840 --rotate normal --output DP1 --off --output HDMI2 --mode 1920x1080 --pos 1920x0 --rotate left --output HDMI1 --mode 1920x1080 --pos 3000x560 --rotate normal --output DP2 --off

When I'm on [1], my terminals spawn on [1].
When I'm on [3], my terminals spawn on [3].
When I'm on [2], my terminals spawn on [3].

@syphoxy Could you open this issue again please?

@qwelyt
Does it happen with the default config?
Make sure to have this change: https://github.com/awesomeWM/awesome/commit/1c177cabce1557f6eacf517dee0e8ff0f4cb02fe

@blueyed Yes. It happens with the default config. And that line is there as well. In my own config as well.

So:

Output | Resolution | Position | rotate
------ | ---------- | -------- | ------
eDP1 | 1920x1080 | 0x840 | normal
HDMI2 | 1920x1080 | 1920x0 | left
HDMI1 | 1920x1080 | 3000x560 | normal

@qwelyt Could you try adding your config to _multi_screen.lua and run the tests (you need Xephyr for this). There is a test-case very similar to this and it passes fine. I find strange that you still have the issue...

(Technically this should be a new issue, but ok)
Another idea: Could it be that the C code is mis-handling the rotations?
I'd like to see xrandr output and output from awesome-client 'local result = {} for s in screen do result[s] = s.geometry end return require("gears.debug").dump_return(result)' to see if this is the case. (However, I guess not because in that case the wibar would be in the wrong place, wouldn't it?).

My setup also has a rotated screen on the left and it works fine (but I only have 2 screens)

./dev/awesome/utils/awesome-client   'local result = {} for s in screen do result[s] = s.geometry end return require("gears.debug").dump_return(result)'
   string "table: 0xfe28ec0
  screen: 0x7cadd8 : table: 0x1fb8deb0
    y : 0 (number)
    x : 900 (number)
    height : 1080 (number)
    width : 1920 (number)
  screen: 0x7cb388 : table: 0x1fb8df00
    y : 0 (number)
    x : 0 (number)
    height : 1600 (number)
    width : 900 (number)"

@Elv13 I checked out the source-code and tried to build it (instructions are not overly clear what you are supposed to do when adding tests).
I do seem unable to build Awesome though.

[  7%] Linking C executable awesome
CMakeFiles/awesome.dir/dbus.c.o: In function `a_dbus_message_iter':
/home/qwelyt/code/git/awesome/.build-machine-x86_64-pc-linux-gnu-6.3.1/dbus.c:119: undefined reference to `lua_rotate'
/home/qwelyt/code/git/awesome/.build-machine-x86_64-pc-linux-gnu-6.3.1/dbus.c:210: undefined reference to `lua_rotate'
/home/qwelyt/code/git/awesome/.build-machine-x86_64-pc-linux-gnu-6.3.1/dbus.c:193: undefined reference to `lua_rotate'
CMakeFiles/awesome.dir/dbus.c.o: In function `luaA_object_push':
/home/qwelyt/code/git/awesome/.build-machine-x86_64-pc-linux-gnu-6.3.1/common/luaobject.h:148: undefined reference to `lua_rotate'
CMakeFiles/awesome.dir/dbus.c.o: In function `luaA_dofunction':
/home/qwelyt/code/git/awesome/.build-machine-x86_64-pc-linux-gnu-6.3.1/common/lualib.h:69: undefined reference to `lua_rotate'
CMakeFiles/awesome.dir/dbus.c.o:/home/qwelyt/code/git/awesome/.build-machine-x86_64-pc-linux-gnu-6.3.1/common/lualib.h:73: more undefined references to `lua_rotate' follow
collect2: error: ld returned 1 exit status
make[3]: *** [CMakeFiles/awesome.dir/build.make:1113: awesome] Error 1
make[2]: *** [CMakeFiles/Makefile2:70: CMakeFiles/awesome.dir/all] Error 2
make[1]: *** [Makefile:128: all] Error 2
make: *** [Makefile:28: cmake-build] Error 2

And, I suppose this is the correct way to add a new test?

local dispositions = {

    {
        function() return { x = 0  , y = 840, width  = 1920, height = 1080, } end,
        function() return { x = 1920  , y = 840, width  = 1920, height = 1080, } end,
        function() return { x = 3000  , y = 560, width  = 1920, height = 1080, } end,
    },
[...]

@psychon

qwelyt@machine ~ % awesome-client 'local result = {} for s in screen do result[s] = s.geometry end return require("gears.debug").dump_return(result)'
   string "table: 0x2201fd0
  screen: 0x785c38 : table: 0x1fdcc50
    width : 1920 (number)
    height : 1080 (number)
    y : 560 (number)
    x : 3000 (number)
  screen: 0x7861c8 : table: 0x1fdcd20
    width : 1080 (number)
    height : 1920 (number)
    y : 0 (number)
    x : 1920 (number)
  screen: 0x7856f8 : table: 0x1fdcb80
    width : 1920 (number)
    height : 1080 (number)
    y : 840 (number)
    x : 0 (number)"

qwelyt@machine ~ % xrandr
Screen 0: minimum 8 x 8, current 4920 x 1920, maximum 32767 x 32767
eDP1 connected primary 1920x1080+0+840 (normal left inverted right x axis y axis) 310mm x 170mm
   1920x1080     60.02*+  47.99  
   1400x1050     59.98  
   1600x900      60.00  
   1280x1024     60.02  
   1280x960      60.00  
   1368x768      60.00  
   1280x720      60.00  
   1024x768      60.00  
   1024x576      60.00  
   960x540       60.00  
   800x600       60.32    56.25  
   864x486       60.00  
   640x480       59.94  
   720x405       60.00  
   640x360       60.00  
DP1 disconnected (normal left inverted right x axis y axis)
DP2 disconnected (normal left inverted right x axis y axis)
HDMI1 connected 1920x1080+3000+560 (normal left inverted right x axis y axis) 530mm x 300mm
   1920x1080     60.00*+
   1600x900      60.00  
   1280x1024     75.02    60.02  
   1152x864      75.00  
   1024x768      75.03    60.00  
   800x600       75.00    60.32  
   640x480       75.00    59.94  
   720x400       70.08  
HDMI2 connected 1080x1920+1920+0 left (normal left inverted right x axis y axis) 530mm x 300mm
   1920x1080     60.00*+
   1600x900      60.00  
   1280x1024     75.02    60.02  
   1152x864      75.00  
   1024x768      75.03    60.00  
   800x600       75.00    60.32  
   640x480       75.00    59.94  
   720x400       70.08  
VIRTUAL1 disconnected (normal left inverted right x axis y axis)

Since I couldn't build Awesome with the 4.0 source due to the

CMakeFiles/awesome.dir/dbus.c.o: In function `a_dbus_message_iter':
/home/qwelyt/code/git/awesome/.build-machine-x86_64-pc-linux-gnu-6.3.1/dbus.c:119: undefined reference to `lua_rotate'

error, I copied my installed executable from /usr/bin/awesome to my build source and ran run.sh pointing to that binary.

Now It runs some tests but I get

qwelyt@machine ~/awesome-4.0/tests % ./run.sh
awesome_log: /tmp/tmp.J3qM9I90T9/_awesome_test.log
== Running /home/qwelyt/awesome-4.0/tests/test-awesomerc.lua ==
Error: timeout waiting for signal in step 3/11 (@5).
^C%  

So it hangs in step 3. (The ^C is where i terminated the process).

After some further testing (without running the tests in Awesome as they never go past 3

qwelyt@machine ~/awesome-4.0/tests % ./run.sh
awesome_log: /tmp/tmp.Zj8wz0lCxt/_awesome_test.log
== Running /home/qwelyt/awesome-4.0/tests/test-awesomerc.lua ==
Error: timeout waiting for signal in step 3/11 (@5).

(process:5000): GLib-WARNING **: poll(2) failed due to: Resource temporarily unavailable.
Awesome was killed due to timeout after 180 seconds
===> ERROR running /home/qwelyt/awesome-4.0/tests/test-awesomerc.lua! <===
Error: timeout waiting for signal in step 3/11 (@5).

) it seems that awesome has a real problem handling 3 screens. No matter my configuration, Awesome just refuses to spawn terminals on the third one. I've switched places on my HDMI1 and HDMI2, but awesome still can't spawn terminals on the right-most screen. Even if I don' have any screen tilted.

Summary, the previous setup I've posted ([1][3][2] with 3-left-tilted) doesn't work. And neither does [1][2][3] all normal, or [1][2][3] 2-left-tilted.

After getting some support in https://github.com/awesomeWM/awesome/issues/1495 I can now report that the tests give an error given the _multi_screen.lua test for my setup.

Add to _multi_screen.lua

local dispositions = {

    {
        function() return { x = 0  , y = 840, width  = 1920, height = 1080, } end,
        function() return { x = 1920  , y = 840, width  = 1920, height = 1080, } end,
        function() return { x = 3000  , y = 560, width  = 1920, height = 1080, } end,
    },
[...]

Run run.sh

[...]
== Running /home/qwelyt/git/awesome/tests/test-awful-client.lua ==
2017-01-31 14:59:33 W: awesome: a_glib_poll:389: Last main loop iteration took 0.271062 seconds! Increasing limit for this warning to that value.
An unexpected screen change did occur
stack traceback:
    [string "local awful = require("awful")..."]:140: in function <[string "local awful = require("awful")..."]:136>
    [C]: in metamethod '__newindex'
    lib/awful/rules.lua:440: in function 'awful.rules.execute'
    lib/awful/rules.lua:528: in function 'awful.rules.completed_with_payload_callback'
    [C]: in method 'emit_signal'
    lib/awful/spawn.lua:217: in function 'awful.spawn.on_snid_callback'
screen3 Screen: 1
Error: running function for step 9/135 (@2): [string "local awful = require("awful")..."]:169: assertion failed!
stack traceback:
    [C]: in function 'assert'
    [string "local awful = require("awful")..."]:169: in function <[string "local awful = require("awful")..."]:165>
    (...tail calls...)
    [C]: in function 'xpcall'
    /home/qwelyt/git/awesome/tests/_runner.lua:47: in function </home/qwelyt/git/awesome/tests/_runner.lua:41>
    [C]: in function 'xpcall'
    lib/gears/protected_call.lua:36: in function <lib/gears/protected_call.lua:35>
    (...tail calls...)
    lib/gears/timer.lua:226: in function <lib/gears/timer.lua:224>!
===> ERROR running /home/qwelyt/git/awesome/tests/test-awful-client.lua <===
Error: running function for step 9/135 (@2): [string "local awful = require("awful")..."]:169: assertion failed!
[...]

Sorry to bother with this again, but I'm somewhat curios as to whether this is being worked on at the moment?

I'm on (currently) latest git src and I can't spawn any terminals on my third monitor. Sort of annoying.

qwelyt@machine ~ % awesome --version
awesome v4.1-68-g5e431d2f-dirty (Technologic)
 • Compiled against Lua 5.3.4 (running with Lua 5.3)
 • D-Bus support: ✔
 • execinfo support: ✔
 • xcb-randr version: 1.5
 • LGI version: 0.9.1

Add this to tests/_multi_screen.lua

    {
        function() return { x=0, y=840, width=1920, height=1080 } end,
        function() return { x=1920, y=0, width=1080, height=1920 } end,
        function() return { x=3000, y=560, width=1920, height=1080 } end
    },

And the test will fail.

I would be happy to help out, but unfortunately I don't know C. :/
My guess is that Awesome can't handle an increase in Y when moving along the X axis. Since my setup is basically _ ‾ –, if you understand what I mean.

Edit

Actually even the simple test case

    {
        function() return { x = 0 , y = 0, width  = 1920, height = 1080, } end,
        function() return { x = 1920 , y = 0, width  = 1920, height = 1080, } end
    },

fails.
Here's the console output:

== Running /home/qwelyt/git/awesome/tests/test-awful-client.lua ==
2017-05-09 14:22:48 W: awesome: a_glib_poll:432: Last main loop iteration took 0.176753 seconds! Increasing limit for this warning to that value.
An unexpected screen change did occur
stack traceback:
    [string "local awful = require("awful")..."]:140: in function <[string "local awful = require("awful")..."]:136>
    [C]: in metamethod '__newindex'
    lib/awful/rules.lua:456: in function 'awful.rules.execute'
    lib/awful/rules.lua:539: in function 'awful.rules.completed_with_payload_callback'
    [C]: in method 'emit_signal'
    lib/awful/spawn.lua:219: in function 'awful.spawn.on_snid_callback'
screen2 Screen: 1
Error: running function for step 9/135 (@2): [string "local awful = require("awful")..."]:171: assertion failed!
stack traceback:
    [C]: in function 'assert'
    [string "local awful = require("awful")..."]:171: in function <[string "local awful = require("awful")..."]:167>
    (...tail calls...)
    [C]: in function 'xpcall'
    /home/qwelyt/git/awesome/tests/_runner.lua:48: in function </home/qwelyt/git/awesome/tests/_runner.lua:42>
    [C]: in function 'xpcall'
    lib/gears/protected_call.lua:36: in function <lib/gears/protected_call.lua:35>
    (...tail calls...)
    lib/gears/timer.lua:226: in function <lib/gears/timer.lua:224>!
===> ERROR running /home/qwelyt/git/awesome/tests/test-awful-client.lua <===
Error: running function for step 9/135 (@2): [string "local awful = require("awful")..."]:171: assertion failed!

Sorry to bother with this again, but I'm somewhat curios as to whether this is being worked on at the moment?

Nope, sorry.

Actually even the simple test case

Hm, that's a red hering. Some inconsistency in the internal state causes c.screen = s to actually assign a different screen than s. The "fix" would be something like the following, but this whole problem is just an artifact of the test mode and would not happen in the real world:

diff --git a/objects/client.c b/objects/client.c
index 3e871fe..cd4e254 100644
--- a/objects/client.c
+++ b/objects/client.c
@@ -1748,6 +1748,7 @@ client_resize(client_t *c, area_t geometry, bool honor_hints)
     /* offscreen appearance fixes */
     area = display_area_get();

+    /*/
     if(geometry.x > area.width)
         geometry.x = area.width - geometry.width;
     if(geometry.y > area.height)
@@ -1756,6 +1757,7 @@ client_resize(client_t *c, area_t geometry, bool honor_hints)
         geometry.x = 0;
     if(geometry.y + geometry.height < 0)
         geometry.y = 0;
+       /* */

     if (honor_hints) {
         /* We could get integer underflows in client_remove_titlebar_geometry()
diff --git a/tests/_multi_screen.lua b/tests/_multi_screen.lua
index ddd578e..aa1952c 100644
--- a/tests/_multi_screen.lua
+++ b/tests/_multi_screen.lua
@@ -338,6 +338,19 @@ local function check_tag_indexes()
     end
 end

+local function check_root_size()
+    local width, height = root.size()
+    local max_width, max_height = 0, 0
+    for s in screen do
+        local geo = s.geometry
+        max_width = math.max(max_width, geo.x + geo.width)
+        max_height = math.max(max_height, geo.y + geo.height)
+    end
+    if width < max_width or height < max_height then
+        print("WARNING: Some screen is outside of the root window, the C code around display_area_get() will misbehave")
+    end
+end
+
 local colors = {
     "#000030",
     "#300000",
@@ -489,6 +502,7 @@ local function add_steps(real_steps, new_steps)
             end
         end

+        check_root_size()
         show_screens()

         -- Check the result is correct

Add this to tests/_multi_screen.lua

Ok, this does count as a bug. The problem is that the client initially opens at position 0x0 with size 100x100 and that is completely outside of any screen. When moving a client to another screen, the client gets moved by the difference between the top-left corners of the two screens. Since the new position is outside of the new screen, some code kicks in and picks some screen.

Fix might be:

diff --git a/objects/screen.c b/objects/screen.c
index f81073f..931898d 100644
--- a/objects/screen.c
+++ b/objects/screen.c
@@ -914,8 +914,13 @@ screen_client_moveto(client_t *c, screen_t *new_screen, bool doresize)

     area_t new_geometry = c->geometry;

-    new_geometry.x = to.x + new_geometry.x - from.x;
-    new_geometry.y = to.y + new_geometry.y - from.y;
+    if (screen_area_in_screen(old_screen, c->geometry)) {
+        new_geometry.x = to.x + new_geometry.x - from.x;
+        new_geometry.y = to.y + new_geometry.y - from.y;
+    } else {
+        new_geometry.x = to.x;
+        new_geometry.y = to.y;
+    }

     /* resize the client if it doesn't fit the new screen */
     if(new_geometry.width > to.width)

Nope, sorry.

Sad for me. But good to know, thanks!

Hm, that's a red hering.

I thought it was sort of weird. Because there is an existing test case that does the "exact" same thing but does not fail.

    {
        function() return { x = 0, y = 0, width  = half_w, height = canvas_h, }  end,
        function() return { x = half_w, y = 0, width = half_w, height = canvas_h, } end,
    },

So really, it should work. And, as you say, it works when running for real.

Ok, this does count as a bug.

♥♥♥ It works! All standard tests passes as normal.
I say all standard tests passes, because adding a simple new test, much like my setup but very small screens, it fails.

    {
        function() return { x = 0, y = 32, width  = 32, height = 32, } end,
        function() return { x = 32, y = 0, width = 32, height = 32, } end,
        function() return { x = 64, y = 16, width = 32, height = 32, } end,
    },

But this might be due to the red herring you were talking about.
Anyhow. Adding what you posted and building and I can now spawn terminals on my third monitor! Big thanks!

I say all standard tests passes, because adding a simple new test, much like my setup but very small screens, it fails.

Sigh. Another case of "this fails because the client is (more or less) outside of its current screen". I added "more or less", because it actually does cover some screen.

Adding some debug-prints to the function that assigns a client to a new screen:

diff --git a/objects/screen.c b/objects/screen.c
index f81073f..d920730 100644
--- a/objects/screen.c
+++ b/objects/screen.c
@@ -873,6 +873,11 @@ display_area_get(void)
     return area;
 }

+static void print_geo(const char *c, area_t geo)
+{
+    printf("%s: %dx%d size %dx%d\n", c, geo.x, geo.y, geo.width, geo.height);
+}
+
 /** Move a client to a virtual screen.
  * \param c The client to move.
  * \param new_screen The destination screen.
@@ -909,26 +914,36 @@ screen_client_moveto(client_t *c, screen_t *new_screen, bool doresize)
         return;
     }

+    warn("Moving %p to screen %p", c, new_screen);
+
     from = old_screen->geometry;
     to = c->screen->geometry;

     area_t new_geometry = c->geometry;

+    print_geo("current client geo", c->geometry);
+
     new_geometry.x = to.x + new_geometry.x - from.x;
     new_geometry.y = to.y + new_geometry.y - from.y;

+    print_geo("after moving by difference of screen positions", new_geometry);
+
     /* resize the client if it doesn't fit the new screen */
     if(new_geometry.width > to.width)
         new_geometry.width = to.width;
     if(new_geometry.height > to.height)
         new_geometry.height = to.height;

+    print_geo("after resize to fit the new screen", new_geometry);
+
     /* make sure the client is still on the screen */
     if(new_geometry.x + new_geometry.width > to.x + to.width)
         new_geometry.x = to.x + to.width - new_geometry.width;
     if(new_geometry.y + new_geometry.height > to.y + to.height)
         new_geometry.y = to.y + to.height - new_geometry.height;

+    print_geo("after moving into new screen", new_geometry);
+
     /* move / resize the client */
     client_resize(c, new_geometry, false);

@@ -944,6 +959,8 @@ screen_client_moveto(client_t *c, screen_t *new_screen, bool doresize)
         luaA_object_emit_signal(L, -2, "property::screen", 1);
         lua_pop(L, 1);
     }
+    if (c->screen != new_screen)
+        warn("Client ended up with a different screen?!");

     if(had_focus)
         client_focus(c);
diff --git a/objects/client.c b/objects/client.c
index 3e871fe..3109dfc 100644
--- a/objects/client.c
+++ b/objects/client.c
@@ -1681,7 +1681,10 @@ client_resize_do(client_t *c, area_t geometry)

     screen_t *new_screen = c->screen;
     if(!screen_area_in_screen(new_screen, geometry))
+    {
+        warn("client does not fit its screen");
         new_screen = screen_getbycoord(geometry.x, geometry.y);
+    }

     /* Also store geometry including border */
     area_t old_geometry = c->geometry;

Output is (for the client that should end up on screen 3):

2017-05-10 08:59:08 W: awesome: screen_client_moveto:917: Moving 0x2bc89a8 to screen 0x2873738
current client geo: 0x0 size 100x100
after moving by difference of screen positions: 64x-16 size 100x100
after resize to fit the new screen: 64x-16 size 32x32
after moving into new screen: 64x-16 size 32x32
2017-05-10 08:59:08 W: awesome: client_resize_do:1685: client does not fit its screen
2017-05-10 08:59:08 W: awesome: screen_client_moveto:963: Client ended up with a different screen?!

So, the client starts with position 0x0, size 100x100 (and screen 1). Then, awful.rules tries to assign the client to screen 3. The difference between the top-left corner of these screens is 64x-16, so that's the new position of the client. Next, the code notices that the client is larger than its new screen, so it restricts the client to the size of its new screen. Afterwards, the code checks if the bottom-right corner is outside (to the bottom-right) of its screen, which is not the case and does not do anything.

Then, client_resize is called to move the client to where we want it to end up. This function notices that the calculated position is outside of the client's new screen and thus it gets assigned to another screen. (client_resize is also called when you move a client directly. So this does have to assign new screens when you move a client from one screen to another)

So... A fix could be to check if the geometry that we ended up with is actually on the screen. This patch can replace my patch from the previous comment (it also handles that case).

diff --git a/objects/screen.c b/objects/screen.c
index f81073f..1bd4e07 100644
--- a/objects/screen.c
+++ b/objects/screen.c
@@ -928,6 +928,12 @@ screen_client_moveto(client_t *c, screen_t *new_screen, bool doresize)
         new_geometry.x = to.x + to.width - new_geometry.width;
     if(new_geometry.y + new_geometry.height > to.y + to.height)
         new_geometry.y = to.y + to.height - new_geometry.height;
+    if(!screen_area_in_screen(new_screen, new_geometry))
+    {
+        /* If all else fails, use brute force */
+        new_geometry.x = to.x;
+        new_geometry.y = to.y;
+    }

     /* move / resize the client */
     client_resize(c, new_geometry, false);

Edit:
I don't intend to complain, but I just want to point out that figuring all of this out was not easy for me either:
Today I saw your new comment when it was less than 5 minutes old. So today, figuring this new part out took me half an hour (your comment is 30 minutes old). For yesterday I am not sure, but I guess that I stared at this for about one and a half hours.

Oh, another thing that someone should look into and/or do (I guess future-me, when he has enough time to prepare the necessary pull requests): With the above patch, I guess we should revert commit d5e365804ca7823799fbfc85691d12d39e52cd70. Daniel seems to have run into basically the same problem, but fixed a symptom instead of the underlying problem.

Was this page helpful?
0 / 5 - 0 ratings