-
Notifications
You must be signed in to change notification settings - Fork 0
Add toplevel geometry tracker protocol. #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,267 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<protocol name="shell_foreign_toplevel_geometry_tracker_v1"> | ||
<copyright> | ||
Copyright © 2025 outfoxxed | ||
|
||
Permission to use, copy, modify, distribute, and sell this | ||
software and its documentation for any purpose is hereby granted | ||
without fee, provided that the above copyright notice appear in | ||
all copies and that both that copyright notice and this permission | ||
notice appear in supporting documentation, and that the name of | ||
the copyright holders not be used in advertising or publicity | ||
pertaining to distribution of the software without specific, | ||
written prior permission. The copyright holders make no | ||
representations about the suitability of this software for any | ||
purpose. It is provided "as is" without express or implied | ||
warranty. | ||
|
||
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | ||
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | ||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | ||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | ||
THIS SOFTWARE. | ||
</copyright> | ||
|
||
<description summary="protocol allowing clients to track foreign toplevel geometry"> | ||
This protocol allows clients to track the geometry of toplevels | ||
relative to outputs or workspaces, enabling workspace overviews | ||
and window picking. | ||
|
||
This protocol is privileged and should be limited to trusted clients. | ||
|
||
The key words "must", "must not", "required", "shall", "shall not", | ||
"should", "should not", "recommended", "may", and "optional" in this | ||
document are to be interpreted as described in IETF RFC 2119. | ||
|
||
Warning! The protocol described in this file is intended as a stopgap | ||
and is expected to be superseded by a solution in wayland-protocols. | ||
Clients should not assume this protocol will continue to exist in the | ||
future. | ||
</description> | ||
|
||
<interface name="shell_foreign_toplevel_geometry_tracker_manager_v1" version="1"> | ||
<description summary="manager for geometry trackers"> | ||
This global creates and synchronizes geometry trackers. | ||
</description> | ||
|
||
<enum name="error"> | ||
<entry name="live_trackers" | ||
summary="destroyed geometry tracker manager while trackers were live" | ||
value="1"/> | ||
</enum> | ||
|
||
<request name="destroy" type="destructor"> | ||
<description summary="destroy the manager"> | ||
Destroy the manager. Destroying the manager prior to | ||
the destruction of all trackers created by it is a protocol | ||
error, as the manager is responsible for synchronization. | ||
</description> | ||
</request> | ||
|
||
<event name="done"> | ||
<description summary="all geometry tracker events have been sent"> | ||
This event signals that all events related to created geometry | ||
trackers and their members have been sent. | ||
</description> | ||
</event> | ||
|
||
<request name="get_output_tracker"> | ||
<description summary="create a geometry tracker for a given output"> | ||
Creates a geometry tracker which tracks toplevels on a given output. | ||
</description> | ||
|
||
<arg name="tracker" type="new_id" interface="shell_foreign_toplevel_geometry_tracker_v1"/> | ||
<arg name="output" type="object" interface="wl_output"/> | ||
</request> | ||
|
||
<request name="get_workspace_tracker"> | ||
<description summary="create a geometry tracker for a given workspace"> | ||
Creates a geometry tracker which tracks toplevels on a given workspace. | ||
</description> | ||
|
||
<arg name="tracker" type="new_id" interface="shell_foreign_toplevel_geometry_tracker_v1"/> | ||
<arg name="workspace" type="object" interface="ext_workspace_handle_v1"/> | ||
</request> | ||
</interface> | ||
|
||
<interface name="shell_foreign_toplevel_geometry_tracker_v1" version="1"> | ||
<description summary="tracks relative geometry of intersecting objects"> | ||
A geometry tracker tracks the relative geometry of toplevels | ||
intersecting with an output or workspace. | ||
Comment on lines
+92
to
+93
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this is "intersecting", as in a window visible on two outputs shows up on both trackers? As opposed to only showing up on a single tracker for this window's "main" output (i.e. one that it receives scale or frame callbacks for). Would be good to clarify There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. The primary output and workspace can be determined via existing toplevel and workspace protocols if the compositor wishes to send only one, but any toplevel even partially on the workspace should be listed. |
||
|
||
Upon creation, an 'area' event must be sent. | ||
</description> | ||
|
||
<enum name="error"> | ||
<entry name="reset_toplevel_list" | ||
summary="attempted to assign a toplevel list to the tracker multiple times" | ||
value="1"/> | ||
<entry name="destroyed_toplevel_list" | ||
summary="toplevel list used in a geometry tracker was destroyed" | ||
value="2"/> | ||
</enum> | ||
|
||
<request name="destroy" type="destructor"> | ||
<description summary="destroy the tracker"> | ||
Destroy the tracker. All tracker members must receive a | ||
finished event following this request. | ||
</description> | ||
</request> | ||
|
||
<event name="area"> | ||
<description summary="reports the geometry of the tracked area"> | ||
Comment on lines
+114
to
+115
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would rename this to |
||
This event reports the geometry of the tracked area. | ||
|
||
Reported width and height should match the dimensions of the | ||
tracked area in logical pixels. | ||
Comment on lines
+118
to
+119
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does this mean? Isn't this the tracked area? Or this is some other area (which?) that matches the tracked area? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was a couple different things during editing. Must've forgotten to clean that up. |
||
|
||
This event must be sent upon creation of the tracker, and | ||
whenever the tracked area changes. This event is double-buffered | ||
and must be followed by a | ||
'shell_foreign_toplevel_geometry_tracker_manager_v1.done' event. | ||
</description> | ||
|
||
<arg name="width" type="int"/> | ||
<arg name="height" type="int"/> | ||
Comment on lines
+127
to
+128
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With fractional scale the logical size isn't necessarily an int. While there's currently no good way to request a fractional size for e.g. fullscreen windows or anchored layer-shell elements or the lock surface, at least in niri the area is tracked in fractional logical pixels for the purpose of toplevel placement and such. So might be good to have some forward compatibility here when fractional sizes become more widely representable? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was probably thinking in physical pixels when I wrote it, but logical pixels make more sense if the workspace is on a single monitor. This does highlight the issue of a single workspace spanning multiple monitors with mismatched geometry though. I'll have to revise that. To account for workspaces spanning multiple monitors with potentially different DPIs or scaling ratios, should the compositor just pick some number that makes the math work out for relative positioning or something else you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure about others, niri layout uses fractional logical coords and sizes everywhere and it seems to work alright (though, niri also doesn't do workspaces spanning several monitors). I expect that others either do the same or round sizes to logical ints There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Niri and Hyprland don't care about this since workspaces cant be on more than one monitor at once, but its likely a concern for KDE and such. |
||
</event> | ||
|
||
<event name="margins"> | ||
<description summary="reports insets into the tracked area"> | ||
This event reports margins into the tracked area where toplevels | ||
may not normally be placed, such as exclusive zones of layer | ||
surfaces. Clients may use this information to avoid showing | ||
gaps in visual representations of the tracked area. | ||
Comment on lines
+133
to
+136
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In niri (and other tiling WMs too) there are separate margins for tiled windows and for floating windows, i.e. floating windows can go to the edges of the screen, while tiled windows can have extra "outer gaps". I'm guessing these margins should not include these tiling-only "outer gaps"? Would be good to clarify There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would be specifying outer gaps, as you can move floating windows over layer surfaces as well as the gap region. For compositors that don't let you move windows over an exclusive layer, I'm thinking that region shouldn't be included in the tracked size. |
||
|
||
Reported margins must be in the same coordinate space as | ||
those reported by 'area'. | ||
|
||
This event may be sent upon creation of the tracker, and | ||
whenever insets change. This event is double-buffered | ||
and must be followed by a | ||
'shell_foreign_toplevel_geometry_tracker_manager_v1.done' event. | ||
</description> | ||
|
||
<arg name="left" type="int"/> | ||
<arg name="top" type="int"/> | ||
<arg name="right" type="int"/> | ||
<arg name="bottom" type="int"/> | ||
Comment on lines
+147
to
+150
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, not necessarily ints, can be fractional logical. |
||
</event> | ||
|
||
<event name="entered"> | ||
<description name="an entity has entered the tracker area"> | ||
This event reports that a toplevel has entered the tracking | ||
area. Untracked entities must not receive 'entered' events. | ||
</description> | ||
|
||
<arg name="member" type="new_id" interface="shell_foreign_toplevel_geometry_tracker_member_v1"/> | ||
</evnt> | ||
|
||
<request name="track_toplevels"> | ||
<description summary="begins tracking toplevels"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: should this include toplevels currently being interactively dragged with the cursor? I suppose this should be up to compositor policy; in niri even if dragged floating windows should be included, I would probably still exclude dragged tiled windows. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Most clients I can think of would prefer a stream of events as position changes, matching how the toplevels are visible to the user. E.g. animations switching window positions and mouse drags should be reported as they happen, not as a single reposition at the end. |
||
This request asks the compositor to track all toplevels created by the | ||
given toplevel list that enter the tracking area. | ||
|
||
Upon request, all toplevels that qualify as members of the tracker | ||
must be provided via an 'enter' event. | ||
|
||
Attempting to set the toplevel list more than once is an error, as | ||
is destroying the toplevel list prior to the destruction of | ||
this object. | ||
</description> | ||
|
||
<arg name="list" type="object" interface="ext_foreign_toplevel_list_v1"/> | ||
</request> | ||
</interface> | ||
|
||
<interface name="shell_foreign_toplevel_geometry_tracker_member_v1" version="1"> | ||
<description summary="tracked entity visible on a geometry tracker"> | ||
A toplevel tracked by a geometry tracker. | ||
|
||
Upon creation, toplevel, geometry, and optionally stacking order | ||
events must be sent by the compositor. | ||
</description> | ||
|
||
<request name="destroy" type="destructor"> | ||
<description summary="destroy the member"> | ||
Destroys the tracker member object. | ||
</description> | ||
</request> | ||
|
||
<event name="left"> | ||
<description summary="the toplevel has left the tracked area"> | ||
The toplevel has left the tracked area. A toplevel must not be | ||
considered to have left until the toplevel's geometry has no | ||
intersection with the geometry tracker. | ||
Comment on lines
+195
to
+197
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In niri, windows can scroll outside a workspace, but they for all intents and purposes remain on that workspace. How should it behave wrt. this entered and left event? Would be good to clarify There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was thinking the entire workspace strip should be considered to be the workspace, including parts that are currently out of view. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about minimized (on a workspace) or otherwise hidden (in niri's case, unfocused in a tabbed column) windows? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minimized windows should not be included in the workspace. Tabs I'm unsure of. We could either stack the windows directly on top of eachother in position events or not send them at all. I'm leaning towards stacking them. |
||
|
||
Following this event, the member object should be destroyed and no more | ||
events will be sent to it. If the toplevel later re-enters the tracked | ||
area it will do so as a new object. | ||
|
||
This event is double-buffered and must be followed by a | ||
'shell_foreign_toplevel_geometry_tracker_manager_v1.done' event. | ||
</description> | ||
</event> | ||
|
||
<event name="geometry"> | ||
<description summary="geometry of the toplevel has changed"> | ||
New toplevel geometry information is available. | ||
This event is sent upon creation of the member object or changes | ||
to the toplevel's geometry. | ||
|
||
Compositor policy dictates which window decorations are included | ||
in the toplevel's geometry, but excluding non-window extents | ||
such as shadows is recommended. | ||
|
||
This event is double-buffered and must be followed by a | ||
'shell_foreign_toplevel_geometry_tracker_manager_v1.done' event. | ||
</description> | ||
|
||
<arg name="x" type="int"/> | ||
<arg name="y" type="int"/> | ||
Comment on lines
+222
to
+223
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These definitely shouldn't be ints, there's nothing in Wayland that restricts windows to integer logical placement |
||
<arg name="width" type="int"/> | ||
<arg name="height" type="int"/> | ||
Comment on lines
+224
to
+225
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While window geometry can only be integer logical currently due to Wayland, if you include compositor decorations, then it easily goes into fractional logical size |
||
</event> | ||
|
||
<event name="above"> | ||
<description summary="the toplevel is now above another"> | ||
This event reports that the toplevel is now directly above the | ||
given sibling in Z-order. | ||
|
||
This event is double-buffered and must be followed by a | ||
'shell_foreign_toplevel_geometry_tracker_manager_v1.done' event. | ||
</description> | ||
|
||
<arg name="sibling" type="object" interface="shell_foreign_toplevel_geometry_tracker_member_v1"/> | ||
</event> | ||
|
||
<event name="below"> | ||
<description summary="the toplevel is now below another"> | ||
This event reports that the toplevel is now directly below the | ||
given sibling in Z-order. | ||
|
||
This event is double-buffered and must be followed by a | ||
'shell_foreign_toplevel_geometry_tracker_manager_v1.done' event. | ||
</description> | ||
|
||
<arg name="sibling" type="object" interface="shell_foreign_toplevel_geometry_tracker_member_v1"/> | ||
</event> | ||
Comment on lines
+228
to
+250
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess there can't be cycles between these two? Also, if the compositor restacks windows, should it send all changed "above" and "below" for all tracked objects? I.e. if you click on a bottommost window and it goes all the way to the top, should it send a ton of "above" requests (one for each other visible window), plus a ton of "below" requests? Sounds a bit spammy There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only a single one. Placing a toplevel above the topmost current one would implicitly require it to be above all the others as well. As such no more than one above/below should be sent per reposition. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So if the toplevel is placed in the middle, only a single "above" (for the window immediately below) or "below" (for the window immediately above) suffices? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, what about tiled windows, which also technically have an above/below ordering, but for most intents and purposes it doesn't matter (since the geometries don't overlap), so the compositor can reorder them very frequently (it's convenient in the code, and it technically does show up visually in some ways, but probably not important enough to spam the protocol)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes. Which one is sent is up to the compositor.
It shouldn't usually matter yeah. I think it makes sense to include it in case a client wants to make visual effects based on it though. Best to leave it open to that sort of thing.
I'm personally not very concerned about protocol spam on events that are triggered by user input, especially relatively infrequent ones. Wayland effectively batches events so if you're sending one (geometry changed) you might as well send more (stacking order changed). |
||
|
||
<event name="toplevel"> | ||
<description summary="this member has been marked as a toplevel"> | ||
This event sets the toplevel the tracker member refers to. This | ||
event can only be sent once, prior to the first 'done' event | ||
following the creation of the member object. | ||
|
||
A 'left' event must be sent upon closure of the toplevel. | ||
|
||
This event is double-buffered and must be followed by a | ||
'shell_foreign_toplevel_geometry_tracker_manager_v1.done' event. | ||
</description> | ||
|
||
<arg name="toplevel" type="object" interface="ext_foreign_toplevel_handle_v1"/> | ||
</event> | ||
</interface> | ||
</protocol> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vaxerski thoughts on splitting this apart similarly to the image capture protocol? I'm not sure what sources other than a workspace or output would make sense but it might make sense to at least make workspace support optional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
meh, I don't see any other possible tracker, so I don't really care