phillipberndt/fakexrandr

Add libxcb support [Faked screens not recognized with Awesome WM]

Opened this issue · 11 comments

Hi,

I would like to split a huge 4K screen in two or more virtual screens.

I successfully compiled and installed your library.

$ ldd /usr/bin/xrandr
    linux-vdso.so.1 =>  (0x00007ffeb21dc000)
    libXrandr.so.2 => /usr/local/lib/libXrandr.so.2 (0x00007f62f5992000)
    libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f62f565d000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f62f5356000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f62f4f91000)
    libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f62f4d72000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f62f4b6d000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f62f5bbe000)
    libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007f62f4969000)
    libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f62f4763000)
$ xrandr
Screen 0: minimum 320 x 200, current 6240 x 2160, maximum 8192 x 8192
DVI-I-1 connected 1200x1920+0+0 left (normal left inverted right x axis y axis) 518mm x 324mm
   1920x1200      60.0*+
   1920x1080      60.0  
   1600x1200      60.0  
   1680x1050      60.0  
   1280x1024      60.0  
   1280x960       60.0  
   1024x768       60.0  
   800x600        60.3  
   640x480        60.0  
   720x400        70.1  
DVI-D-1 connected 1200x1920+5040+0 left (normal left inverted right x axis y axis) 518mm x 324mm
   1920x1200      60.0*+
   1920x1080      60.0  
   1600x1200      60.0  
   1680x1050      59.9  
   1280x1024      60.0  
   1280x960       60.0  
   1024x768       60.0  
   800x600        60.3  
   640x480        60.0  
   720x400        70.1  
HDMI-1 disconnected (normal left inverted right x axis y axis)
DP-1~1 connected 2550x2160+1200+0 (normal left inverted right x axis y axis) 583mm x 485mm
   2550x2160      60.0* 
   3840x2160      60.0     30.0     30.0     24.0  
   2560x1440      60.0  
   2048x1080      60.0  
   1920x1080      60.0     60.0     50.0     59.9  
   1920x1080i     60.1     50.0     60.0  
   1680x1050      60.0  
   1280x1024      75.0     60.0  
   1440x900       75.0     59.9  
   1280x960       60.0  
   1280x720       60.0     60.0     50.0     59.9  
   1024x768       75.1     60.0  
   800x600        75.0     60.3  
   720x576        50.0  
   720x480        60.0     59.9  
   640x480        75.0     72.8     66.7     60.0     59.9  
   720x400        70.1  
DP-1~2 connected 1290x2160+3750+0 (normal left inverted right x axis y axis) 294mm x 485mm
   1290x2160      60.0* 
   3840x2160      60.0     30.0     30.0     24.0  
   2560x1440      60.0  
   2048x1080      60.0  
   1920x1080      60.0     60.0     50.0     59.9  
   1920x1080i     60.1     50.0     60.0  
   1680x1050      60.0  
   1280x1024      75.0     60.0  
   1440x900       75.0     59.9  
   1280x960       60.0  
   1280x720       60.0     60.0     50.0     59.9  
   1024x768       75.1     60.0  
   800x600        75.0     60.3  
   720x576        50.0  
   720x480        60.0     59.9  
   640x480        75.0     72.8     66.7     60.0     59.9  
   720x400        70.1  

However, the windows manager Awesome WM doesn't seem to recognize these virtual screens. When I move a window on the primary screen it still uses the full screen area instead of the virual one.

Do you have some advices ? Are there any logs which can be useful ?

Many thanks,

Awesome uses libxcb, but fakexrandr currently only supports Xlib.

Since libxcb uses a different API to access RandR, it does not suffice to add some aliases. I guess the simplest approach would be to write a separate libxcb-randr wrapper (which can reuse the skeleton-generator code I use for libXrandr) that internally passes the important requests to the existing fakexrandr code, and the remainder to the original libxcb.

Ok, thank you for your quick answer, your code example and your advices.

However, I think this task is surely too high due to my lack of knowledge of C and linux internals.

Hope, you'll find some time to work on this enhancement.

Many thanks again for taking the time to study my issue.

I won't give this priority, but I'll keep it on my list. In case someone else needs this and finds the time to implement it, I already generated the libxcb source files that are necessary for the implementation: https://gist.github.com/phillipberndt/9a116e1b8e32050e822b. The xcb_randr_get_screen_resources_reply function seems to be a good starting point.

marad commented

I've stumbled upon the exact same problem with i3wm. Thanks for generating initial structure. I think I may try to implement this. I've never used libxcb but I need this badly ;)

@marad I as well am using i3 and desperately want this feature (libxcb support). Let me know if I can help; have you made any progress?

While this isn't the level of support I'm looking for, i3 includes an undocumented feature, fake-outputs, you may find useful: https://faq.i3wm.org/question/2729/sub-output-support-50-on-left-50-on-right/

marad commented

@nmschulte-aviture I haven't had time yet. If you have any experience with such tools then go for it. @phillipberndt prepared a branch of fakexrandr for xcb: https://github.com/phillipberndt/fakexrandr/tree/xcb

I started looking at this tonight.

We'll need to add the XCB equivalent of the RRGetScreenResourcesCurrent X request, xcb_randr_get_screen_resources_current (and friends ..._reply and ..._unchecked), as i3 uses this version.

I see now that the libXrandr code supports this request already, and the libxcb impl. approach should follow just as the other requests do. We should be able to re-use a lot of the existing code with minimal refactoring/reorganizing, and only really have to worry about the ..._reply implementations; they'll need to extend the responses (as config'd) just as the libXrandr code does. I don't think it'll be useful to genericize this code (with e.g. macros or w/e is most sensible, my C fu has never been very strong) to support multiple adaptations, but I should be able to mirror its flow/behavior and only really change the data/structure-access code. Any thoughts regarding this approach, @phillipberndt?

Yep, I concur. The xcb data structures are not binary compatible with Xrandr's, in a way that the preprocessor won't fix. Writing a second library with a similar behaviour will be easiest.

The only code I'd aim to generalize and share between both libraries is the configuration file parsing. But I'd suggest that we wait with this until the xcb version works and then refactor.

I recall there being a test driver somewhere for this functionality; does that exist or am I losing my mind?

The fakexrandr one is what I was recalling: https://gist.github.com/phillipberndt/9f2e4b29c6c500b2f0bb

Slightly off-topic but I figure if someone has a similar problem he my end up here like I did so:
If you just have a big monitor you want to treat like multiple monitors, bspwm (similar to i3wm) supports this natively. You can even dynamically create/remove/resize "monitors".
For example, to split one 1920x1080 monitor named HDMI-1 in 2 equal halves:

bspc wm --add-monitor hdmi1_left 960x1080+0+0
bspc wm --add-monitor hdmi1_right 960x1080+960+0
bspc wm --remove-monitor HDMI-1

You could then for example use this script:

# resize-monitors
#!/bin/bash
# Get the current dimensions of the focused monitor and the one right of it
# Since this is not exactly a planned usecase there is no command for this
# I just dump the complete layout information and grep/sed the inforamtion I need
focused=$(bspc query -M -m focused)
focused_info=$(bspc wm -d | grep -P -o '{"name":"'${focused}'".*?}')
focused_x=$(echo "$focused_info" | sed 's/.*"x":\([0-9]\+\).*/\1/')
focused_y=$(echo "$focused_info" | sed 's/.*"y":\([0-9]\+\).*/\1/')
focused_width=$(echo "$focused_info" | sed 's/.*"width":\([0-9]\+\).*/\1/')
focused_height=$(echo "$focused_info" | sed 's/.*"height":\([0-9]\+\).*/\1/')

east=$(bspc query -M -m east)
east_info=$(bspc wm -d | grep -P -o '{"name":"'${east}'".*?}')
east_x=$(echo "$east_info" | sed 's/.*"x":\([0-9]\+\).*/\1/')
east_y=$(echo "$east_info" | sed 's/.*"y":\([0-9]\+\).*/\1/')
east_width=$(echo "$east_info" | sed 's/.*"width":\([0-9]\+\).*/\1/')
east_height=$(echo "$east_info" | sed 's/.*"height":\([0-9]\+\).*/\1/')

# Resize
(( east_width += $1))
(( east_x -= $1))
(( focused_width -= $1))
# Apply new sizes
bspc monitor $focused --rectangle ${focused_width}x${focused_height}+${focused_x}+${focused_y}
bspc monitor $east --rectangle ${east_width}x${east_height}+${east_x}+${east_y}

To increase the size of the current monitor the the right while shrinking the right one:
resize-monitors 30 while hdmi_left is focused, now hdmi_left is 990 pixels wide and hdmi_right 930.

FWIW: hax11 (my project) switched from hooking library calls to intercepting the X11 connection. This allows it to work with any X11 client library, even when it's statically linked (as with some games) or embedded (some SDL versions interface with X11 directly) in the application. However, it does not currently support adding monitors.