Thanks to visit codestin.com
Credit goes to Github.com

Skip to content

Conversation

@sigprof
Copy link
Contributor

@sigprof sigprof commented Mar 9, 2024

Inspired by #5384, but instead of just using the border width, this PR reports the actual frame extents for the window, which may also include the title bar (for floating windows and tiled windows in plain split containers, but not for tiled windows in stacked/tabbed containers).

The existing con_border_style_rect() function should already handle all configuration options which can affect the decoration sizes (if it does not, that would also show up in other places); its result just needs to be converted into the format used by the _NET_FRAME_EXTENTS property.

This PR fixes #4292 probably in the best way possible (the reported _NET_FRAME_EXTENTS values should always match the actual sizes of window frame elements which are actually drawn into the X11 frame window into which the client window is reparented). The only really problematic case is with the stacked/tabbed containers, for which the title bar is actually drawn into a completely separate window, therefore the title bar size cannot be reported in _NET_FRAME_EXTENTS (actually I tried to calculate the size of those decorations and add it to the top decoration size, but that did not change the behavior of picom).

Large screenshots here (3840×2160)

Example of configuration with hide_edge_borders smart — a single window does not have borders, so only the top frame size is non-zero:
2024-03-09_21-41

but multiple windows have borders:
2024-03-09_21-44

Changing border width works too (although with border normal 8 you can see that the top border overlaps the title text, because on the i3 side that border does not really exists, and picom just draws it over; also the pixel sizes reported by xprop and xwininfo are not identical to what is specified in i3, because I use 168 dpi on this system, therefore 4 px in the i3 config = 7 dpx):
2024-03-09_21-48

Handling of tabbed containers is less perfect though. Here is a single tabbed container with hide_edge_borders smart, so it does not really have a border — note that all frame extents are zero, and the titlebar is rounded separately (although it could easily be excluded from rounding, that does not really help much):
2024-03-09_22-02

Once the border actually appears, you may notice that the top part of the picom border actually gets drawn over the top part of the window, partially obscuring the top line in this terminal (picom does not mind that the top frame size is reported as 0):
2024-03-09_22-04

Some examples of floating windows (no major problems there):
2024-03-09_22-09

Options like hide_edge_borders both work too when gaps are removed (although the resulting behavior with picom is probably not very useful — the rounded border gets drawn only if all of the left, bottom and right borders are present):
2024-03-09_22-15

The same with border pixel 8 (note that windows with only the top border hidden still get the rounded border treatment by picom, but the border overlaps the top part of the window):
2024-03-09_22-21

sigprof added 2 commits March 9, 2024 20:48
Use `con_border_style_rect(con)` to retrieve the decoration size (that
function takes lots of special cases due to `hide_edge_borders`, border
style and width customizations, etc. into account), then massage the
result into the form suitable for `_NET_FRAME_EXTENTS`.

Signed-off-by: Sergey Vlasov <[email protected]>
@SolsticeSpectrum
Copy link

Can we accept this? This is actually perfect.

@dimkauzh
Copy link

This looks good to me, I would love to see this merged!

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i tried this and it finally fixes my picom and i3 border problem.

waiting for this to get merged...

@ahfriedman
Copy link

This appears to fix the issue with smart borders I'd noticed in the prior PR #5384 (comment).

With respect to tabbed/stacked in my opinion, this all makes me think that the solution is just getting picom to allow one to specify the radius of each corner (that way, we could just specify that the I3 frame only gets rounded on the top) such as in these PRs/Issues yshui/picom#918 yshui/picom#564. That said, I'm also using a fork of i3 where I only have indicators rendered on the bottom, so having indicators work perfectly is less of a concern for me, personally
image
image

@stickyautism
Copy link

This would be so great if it gets merged.

Copy link
Member

@orestisfl orestisfl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not perfect for stacked/tabbed but we are technically not lying so I am willing to merge this. However, it still needs tests.

@bsdice
Copy link

bsdice commented Apr 14, 2025

I have been using this patch for some months now to correct display issues of unmanaged windows in a Java software called "Trader Workstation" by Interactive Brokers. It doesn't fix all corner cases, compare the handling in https://github.com/qtile/qtile/blob/master/libqtile/layout/floating.py#L255 If there is an unofficial patch for that, too, I would gladly test. Thank you.

@orestisfl
Copy link
Member

Started adding some tests. @sigprof feel free to contribute to them otherwise I'll add more when I have the time.

@orestisfl orestisfl enabled auto-merge (squash) April 21, 2025 21:22
@orestisfl orestisfl merged commit cfa4cf1 into i3:next Apr 21, 2025
3 checks passed
@stapelberg
Copy link
Member

What about this code?

i3/src/handlers.c

Lines 817 to 847 in b933998

} else if (event->type == A__NET_REQUEST_FRAME_EXTENTS) {
/*
* A client can request an estimate for the frame size which the window
* manager will put around it before actually mapping its window. Java
* does this (as of openjdk-7).
*
* Note that the calculation below is not entirely accurate — once you
* set a different border type, it’s off. We _could_ request all the
* window properties (which have to be set up at this point according
* to EWMH), but that seems rather elaborate. The standard explicitly
* says the application must cope with an estimate that is not entirely
* accurate.
*/
DLOG("_NET_REQUEST_FRAME_EXTENTS for window 0x%08x\n", event->window);
/* The reply data: approximate frame size */
Rect r = {
config.default_border_width, /* left */
config.default_border_width, /* right */
render_deco_height(), /* top */
config.default_border_width /* bottom */
};
xcb_change_property(
conn,
XCB_PROP_MODE_REPLACE,
event->window,
A__NET_FRAME_EXTENTS,
XCB_ATOM_CARDINAL, 32, 4,
&r);
xcb_flush(conn);
} else if (event->type == A_WM_CHANGE_STATE) {

Should it be updated to match the extents calculation introduced in this PR?

@sigprof
Copy link
Contributor Author

sigprof commented Dec 19, 2025

The problem with the _NET_REQUEST_FRAME_EXTENTS message is that it gets sent before the window is actually mapped (that's the whole point of that message — the application can get the WM decoration size and calculate the requested window position and size according to that), so con_by_window_id(event->window) would probably be NULL, and the calculations based on con_border_style_rect(con) won't work.

In order to handle _NET_REQUEST_FRAME_EXTENTS 100% correctly i3 would need to pretend that the window is getting mapped, calculate the new layout according to the config and various window properties, extract the resulting decoration size, and then discard the result of layout calculations (basically do a part of manage_window() which includes at least run_assignments() to apply rules like for_window [foo] border <bar>, but in a way that does not actually affect the global state). I don't see a realistic way to implement that with the current i3 architecture.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Set _NET_FRAME_EXTENTS

8 participants