ssokolow / quicktile

Adds window-tiling hotkeys to any X11 desktop. (An analogue to WinSplit Revolution for people who don't want to use Compiz Grid)
https://ssokolow.com/quicktile/
GNU General Public License v2.0
860 stars 78 forks source link

Small gap between windows on widescreen monitors #140

Closed guiambros closed 1 month ago

guiambros commented 1 month ago

When tiling 3 windows side-by-side on a wide screen monitor, there's a perceptible small gap between the edges of adjacent windows.

On 5120 px wide monitor, the gap is 6px between left and center windows, and 1px between center and right window.

Specifically: the left window will be 0.333 5120 = 1704 px wide, while the center window will be 5120 0.667 - 1704 = 1711 px wide. See image.

before

This is caused by round() on make_winsplit_positions() and GravityLayout class using only 3 decimal places . This shouldn't be a problem in lower resolutions, but as the screen size increases, the gap becomes more noticeable.

Adjusting to 10 decimal places in this line and this line fixes the problem.

after

I'd be glad to send a PR if helpful; just wanted to check if it won't break anything else.

Debug log -- Before:

DEBUG: Received keybind: <Primary><Alt><Mod2>KP_Left
DEBUG: Executing command 'left' with arguments (), {}
DEBUG: Found GNOME Shell workarea information...
DEBUG: Usable desktop region calculated as: Region(<Monitors=[Rectangle(x=0, y=27, width=5120, height=2100)], Struts=[]>)
DEBUG: Operating on window <Wnck.Window object at 0x7fe7f1dd6800 (WnckWindow at 0x55d17af4e100)> with title "ssokolow/quicktile: Adds window-tiling hotkeys to any X11 desktop. (An analogue to WinSplit Revolution for people who don't want to use Compiz Grid) - Google Chrome" and geometry Rectangle(x=0, y=27, width=2560, height=2100)
DEBUG:  Window is on monitor 0, which has geometry Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG: Selected preset sequence:
        ((0.0, 0.0, 0.5, 1.0), (0.0, 0.0, 0.333, 1.0), (0.0, 0.0, 0.667, 1.0))
DEBUG: Selected preset sequence resolves to these monitor-relative pixel dimensions:
        [Rectangle(x=0, y=0, width=2560, height=2160), Rectangle(x=0, y=0, width=1704, height=2160), Rectangle(x=0, y=0, width=3415, height=2160)]
DEBUG: Got saved cycle position: 3, 0
DEBUG: Target preset is Rectangle(x=0, y=0, width=1704, height=2160) relative to monitor Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG: Result exceeds usable (non-rectangular) region of desktop. (overlapped a non-fullwidth panel?) Reducing to within largest usable rectangle: Rectangle(x=0, y=27, width=1704, height=2100)
DEBUG: Calling reposition() with default gravity and dimensions Rectangle(x=0, y=27, width=1704, height=2100)
DEBUG:  Window is on monitor 0, which has geometry Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG:  Repositioning to Rectangle(x=0, y=27, width=1704, height=2100))
-------------------------------------

DEBUG: Received keybind: <Primary><Alt><Mod2>KP_Begin
DEBUG: Executing command 'center' with arguments (), {}
DEBUG: Found GNOME Shell workarea information...
DEBUG: Usable desktop region calculated as: Region(<Monitors=[Rectangle(x=0, y=27, width=5120, height=2100)], Struts=[]>)
DEBUG: Operating on window <Wnck.Window object at 0x7fe7f1b491c0 (WnckWindow at 0x55d17af4ea00)> with title "ssokolow/quicktile: Adds window-tiling hotkeys to any X11 desktop. (An analogue to WinSplit Revolution for people who don't want to use Compiz Grid) - Google Chrome" and geometry Rectangle(x=0, y=27, width=5120, height=2100)
DEBUG:  Window is on monitor 0, which has geometry Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG: Selected preset sequence:
        ((0.0, 0.0, 1.0, 1.0), (0.334, 0.0, 0.333, 1.0), (0.166, 0.0, 0.667, 1.0))
DEBUG: Selected preset sequence resolves to these monitor-relative pixel dimensions:
        [Rectangle(x=0, y=0, width=5120, height=2160), Rectangle(x=1710, y=0, width=1704, height=2160), Rectangle(x=849, y=0, width=3415, height=2160)]
DEBUG: Got saved cycle position: 0, 0
DEBUG: Target preset is Rectangle(x=1710, y=0, width=1704, height=2160) relative to monitor Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG: Result exceeds usable (non-rectangular) region of desktop. (overlapped a non-fullwidth panel?) Reducing to within largest usable rectangle: Rectangle(x=1710, y=27, width=1704, height=2100)
DEBUG: Calling reposition() with default gravity and dimensions Rectangle(x=1710, y=27, width=1704, height=2100)
DEBUG:  Window is on monitor 0, which has geometry Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG:  Repositioning to Rectangle(x=1710, y=27, width=1704, height=2100))
-------------------------------------

DEBUG: Received keybind: <Primary><Alt><Mod2>KP_Right
DEBUG: Executing command 'right' with arguments (), {}
DEBUG: Found GNOME Shell workarea information...
DEBUG: Usable desktop region calculated as: Region(<Monitors=[Rectangle(x=0, y=27, width=5120, height=2100)], Struts=[]>)
DEBUG: Operating on window <Wnck.Window object at 0x7fe7f1b49d80 (WnckWindow at 0x55d17af4eb20)> with title "ssokolow/quicktile: Adds window-tiling hotkeys to any X11 desktop. (An analogue to WinSplit Revolution for people who don't want to use Compiz Grid) - Google Chrome" and geometry Rectangle(x=2560, y=27, width=2560, height=2100)
DEBUG:  Window is on monitor 0, which has geometry Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG: Selected preset sequence:
        ((0.5, 0.0, 0.5, 1.0), (0.667, 0.0, 0.333, 1.0), (0.333, 0.0, 0.667, 1.0))
DEBUG: Selected preset sequence resolves to these monitor-relative pixel dimensions:
        [Rectangle(x=2560, y=0, width=2560, height=2160), Rectangle(x=3415, y=0, width=1704, height=2160), Rectangle(x=1704, y=0, width=3415, height=2160)]
DEBUG: Got saved cycle position: 4, 0
DEBUG: Target preset is Rectangle(x=3415, y=0, width=1704, height=2160) relative to monitor Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG: Result exceeds usable (non-rectangular) region of desktop. (overlapped a non-fullwidth panel?) Reducing to within largest usable rectangle: Rectangle(x=3415, y=27, width=1704, height=2100)
DEBUG: Calling reposition() with default gravity and dimensions Rectangle(x=3415, y=27, width=1704, height=2100)
DEBUG:  Window is on monitor 0, which has geometry Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG:  Repositioning to Rectangle(x=3415, y=27, width=1704, height=2100))

Debug log -- After:

DEBUG: Received keybind: <Primary><Alt><Mod2>KP_Left
DEBUG: Executing command 'left' with arguments (), {}
DEBUG: Found GNOME Shell workarea information...
DEBUG: Usable desktop region calculated as: Region(<Monitors=[Rectangle(x=0, y=27, width=5120, height=2100)], Struts=[]>)
DEBUG: Operating on window <Wnck.Window object at 0x7f17d86c2f40 (WnckWindow at 0x564366d976a0)> with title "ssokolow/quicktile: Adds window-tiling hotkeys to any X11 desktop. (An analogue to WinSplit Revolution for people who don't want to use Compiz Grid) - Google Chrome" and geometry Rectangle(x=0, y=27, width=2560, height=2100)
DEBUG:  Window is on monitor 0, which has geometry Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG: Selected preset sequence:
        ((0.0, 0.0, 0.5, 1.0), (0.0, 0.0, 0.3333333333, 1.0), (0.0, 0.0, 0.6666666667, 1.0))
DEBUG: Selected preset sequence resolves to these monitor-relative pixel dimensions:
        [Rectangle(x=0, y=0, width=2560, height=2160), Rectangle(x=0, y=0, width=1706, height=2160), Rectangle(x=0, y=0, width=3413, height=2160)]
DEBUG: Got saved cycle position: 3, 0
DEBUG: Target preset is Rectangle(x=0, y=0, width=1706, height=2160) relative to monitor Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG: Result exceeds usable (non-rectangular) region of desktop. (overlapped a non-fullwidth panel?) Reducing to within largest usable rectangle: Rectangle(x=0, y=27, width=1706, height=2100)
DEBUG: Calling reposition() with default gravity and dimensions Rectangle(x=0, y=27, width=1706, height=2100)
DEBUG:  Window is on monitor 0, which has geometry Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG:  Repositioning to Rectangle(x=0, y=27, width=1706, height=2100))
-------------------------------------

DEBUG: Received keybind: <Primary><Alt><Mod2>KP_Begin
DEBUG: Executing command 'center' with arguments (), {}
DEBUG: Found GNOME Shell workarea information...
DEBUG: Usable desktop region calculated as: Region(<Monitors=[Rectangle(x=0, y=27, width=5120, height=2100)], Struts=[]>)
DEBUG: Operating on window <Wnck.Window object at 0x7f17d86c3c40 (WnckWindow at 0x564366d977c0)> with title "ssokolow/quicktile: Adds window-tiling hotkeys to any X11 desktop. (An analogue to WinSplit Revolution for people who don't want to use Compiz Grid) - Google Chrome" and geometry Rectangle(x=0, y=27, width=5120, height=2100)
DEBUG:  Window is on monitor 0, which has geometry Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG: Selected preset sequence:
        ((0.0, 0.0, 1.0, 1.0), (0.3333333334, 0.0, 0.3333333333, 1.0), (0.1666666667, 0.0, 0.6666666667, 1.0))
DEBUG: Selected preset sequence resolves to these monitor-relative pixel dimensions:
        [Rectangle(x=0, y=0, width=5120, height=2160), Rectangle(x=1706, y=0, width=1706, height=2160), Rectangle(x=853, y=0, width=3413, height=2160)]
DEBUG: Got saved cycle position: 0, 0
DEBUG: Target preset is Rectangle(x=1706, y=0, width=1706, height=2160) relative to monitor Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG: Result exceeds usable (non-rectangular) region of desktop. (overlapped a non-fullwidth panel?) Reducing to within largest usable rectangle: Rectangle(x=1706, y=27, width=1706, height=2100)
DEBUG: Calling reposition() with default gravity and dimensions Rectangle(x=1706, y=27, width=1706, height=2100)
DEBUG:  Window is on monitor 0, which has geometry Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG:  Repositioning to Rectangle(x=1706, y=27, width=1706, height=2100))
-------------------------------------

DEBUG: Received keybind: <Primary><Alt><Mod2>KP_Right
DEBUG: Executing command 'right' with arguments (), {}
DEBUG: Found GNOME Shell workarea information...
DEBUG: Usable desktop region calculated as: Region(<Monitors=[Rectangle(x=0, y=27, width=5120, height=2100)], Struts=[]>)
DEBUG: Operating on window <Wnck.Window object at 0x7f17d86d4980 (WnckWindow at 0x564366d978e0)> with title "ssokolow/quicktile: Adds window-tiling hotkeys to any X11 desktop. (An analogue to WinSplit Revolution for people who don't want to use Compiz Grid) - Google Chrome" and geometry Rectangle(x=2560, y=27, width=2560, height=2100)
DEBUG:  Window is on monitor 0, which has geometry Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG: Selected preset sequence:
        ((0.5, 0.0, 0.5, 1.0), (0.6666666667, 0.0, 0.3333333333, 1.0), (0.3333333333, 0.0, 0.6666666667, 1.0))
DEBUG: Selected preset sequence resolves to these monitor-relative pixel dimensions:
        [Rectangle(x=2560, y=0, width=2560, height=2160), Rectangle(x=3413, y=0, width=1706, height=2160), Rectangle(x=1706, y=0, width=3413, height=2160)]
DEBUG: Got saved cycle position: 4, 0
DEBUG: Target preset is Rectangle(x=3413, y=0, width=1706, height=2160) relative to monitor Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG: Result exceeds usable (non-rectangular) region of desktop. (overlapped a non-fullwidth panel?) Reducing to within largest usable rectangle: Rectangle(x=3413, y=27, width=1706, height=2100)
DEBUG: Calling reposition() with default gravity and dimensions Rectangle(x=3413, y=27, width=1706, height=2100)
DEBUG:  Window is on monitor 0, which has geometry Rectangle(x=0, y=0, width=5120, height=2160)
DEBUG:  Repositioning to Rectangle(x=3413, y=27, width=1706, height=2100))

To be 100% precise, there's still a some residual rounding error that results in a tiny 1px gap, where the right window starts at 3413, but 2 x 1706 = 3412, so the border of the windows don't overlap. Depending on the window manager and translucency of the theme used, you may see a 1px wide shade of the desktop background between the center and right window:

final

But it's really imperceptible, and fixing would require a lot of additional changes on how the split is calculated depending on the col_number, so I'd say it's not worth it.

ssokolow commented 1 month ago

Thanks for identifying the source. I'll give it a look either in the morning or, if I can't fit it, during the next few days.

I have had people report one-pixel gaps, but I hadn't made it an exceptionally high priority because, before unexpected stuff came up and put QuickTile on the back burner for a while, I'd been planning to finally get around to the deep architectural changes needed for #10, which would involve a complete rewrite the positioning system to more of a grid system where every pixel is assigned to some cell and this kind of bug can't crop up.

(After I finished the plans to rework the config file handling to fix #13. When I had to put QuickTile on the back burner, I had mostly completed a "just press the key combo you want to assign" GUI for mapping hotkeys to action commands to make up for switching to something less friendly to manual editing but more suitable for hierarchical data, like JSON. I think most of what remains is regression testing to make sure I'm properly mapping between what the GUI captures and what the keybinding layer expects.)

ssokolow commented 1 month ago

Replicated using this quick-and-dirty HiDPI simulation and I don't see any problems with the change for low or high DPIs on my end. (Thanks to this page that I just discovered now.)

#!/bin/sh
cd -- "$(dirname -- "$(readlink -f -- "$0")")" || exit 1
Xephyr -screen 3840/508x2160/286 :1 &
sleep 1
export DISPLAY=:1
kwin_x11 &
gvim &
gvim &
gvim &
./quicktile.sh -b

Either you can make a PR or I can make the change myself.

In the former case, please edit docs/authors/index.rst and run docs/update_authors.sh to add an entry for yourself with something like "Diagnosed and fixed HiDPI layout bug".

In the latter case, please let me know whether Gui Ambros is your preferred way to be cited in that list.

guiambros commented 1 month ago

Thanks @ssokolow! If you can make the change it'd be great (just so I don't have to go through my employer OSS contributing process). Yes, name is fine, but honestly no need to worry with credit. Just glad to have found QuickTile. Thank you!

ssokolow commented 1 month ago

Will do. It may take me a day or two more though. I've been taking advantage of favourable weather to get some home maintenance done in preparation for summer.

ssokolow commented 1 month ago

Change pushed. Sorry for the extra delay.

guiambros commented 1 month ago

Tested and confirmed working. Thank you so much!