Skip to content
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

Allow sharing of individual windows. #107

Open
selflein opened this issue Apr 9, 2021 · 36 comments
Open

Allow sharing of individual windows. #107

selflein opened this issue Apr 9, 2021 · 36 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@selflein
Copy link

selflein commented Apr 9, 2021

Adding the option to share individual windows was discussed in different issues/PRs but there is no corresponding open issue right now.

@selflein
Copy link
Author

selflein commented Apr 9, 2021

Some discussion can be found here

@danshick
Copy link
Collaborator

danshick commented Apr 9, 2021

True, thanks. Also worth linking to the corresponding wlr-protocols issue, which I would consider a prerequisite/blocker for this feature.

@timsofteng
Copy link

Hello. What is a current state of this feature?

@hugopeixoto
Copy link

Here's the link to the same issue mentioned by danshick in the new forge: https://gitlab.freedesktop.org/wlroots/wlr-protocols/-/issues/93

@tm512
Copy link

tm512 commented Mar 2, 2022

I'd really like to see a feature like this implemented. My streaming setup on X11 involves having a game in a window on one side of the screen with stuff like terminals and twitch's dashboard on the other side of the screen. Since I'm stuck with a single-monitor setup, I don't have the option of just running the game fullscreen on one monitor and using fullscreen capture, with everything else on the other monitor.

It sounds like some other Wayland compositors like GNOME already provide the ability for single-window capture? Maybe I'm misunderstanding, but if that's the case then what are they doing that makes that possible that wlroots doesn't do?

@columbarius
Copy link
Collaborator

GNOME/mutter uses a completely different base. There is currently no way to export a toplevel buffer in wlroots. The current roadmap (and take this with a grain of salt is):

  1. Finish ext-screencopy
  2. Create a way to export handles for toplevels (windows) from the compositor
  3. Expand ext-screencopy to accept these handles
  4. Expand the chooser protocol to account for them (Create a more extendable chooser protocol #169)
  5. Add this together to share window buffers

For the meantime there is #156 to share a region of the screen.

@tm512
Copy link

tm512 commented Mar 2, 2022

For the meantime there is #156 to share a region of the screen.

Unfortunately specifying the cropping region ahead of time isn't really practical without a way to precisely move and resize a window into that region (like what xdotool can easily do on X11). While things are limited to capturing entire outputs, would it be possible to run the game to be captured inside of a nested wayland compositor running in a window? I'm not sure if its buffer would then be available for capture via xdpw. The ability to set the resolution of the nested compositor would also be important in that case.

If that's not feasible, I've been thinking of just hacking whatever compositor I settle on to keep a tmpfile with a full list of windows and their size/position, then pass those into slurp to interactively select which window to capture, using that with wf-recorder or ffmpeg w/ kmsgrab.

@wallabra
Copy link

If that's not feasible, I've been thinking of just hacking whatever compositor I settle on to keep a tmpfile with a full list of windows and their size/position, then pass those into slurp to interactively select which window to capture, using that with wf-recorder or ffmpeg w/ kmsgrab.

@tm512 Another concern is that a window is not always in the foreground, like when using workspaces or a tabbed container in Sway.

@spagootie
Copy link

This feature would be great to have, because it's on virtually every platform other than wlroots compositors.

@sfrique
Copy link

sfrique commented Dec 3, 2022

It's bad, but it's able to share only "a few things" if you need. For me it solved the biggest problem, not wanting to show my full output.

it seems to work just "fine", but did not test it enough.

You will need to run a nested Wayland session.. i tested with sway what i did to make it work:

  1. Created a clean sway config (no auto start bar etc...) run sway -c ..../sway-nested
  2. Created a pass-through mode on my main sway (to be able to run any command on my nested sway)
  3. Created a chromium/firefox profile (just so i don't have to close my current one at the "main" sway)
  4. Killed all xdg portal (if i did not do this, it would share the whole output, even when at nested session)
  5. Share the output, since this is nested, it only shared the nested session, that on my test was a floating windows of sway with whenever opened there

as I said, it's ugly.. I just did some initial testing, did not check audio etc etc yet.
I was just trying to solve a problem I now have, since i am moving to a single big monitor, i wasn't able to share my second output and keep doing stuff while sharing the screen, but this should solve this.. since nothing would be running at nested, only what i actually want.

I don't know if nested session work with all the apps and etc.. but if it's only one instance of it, and it's running in the nested, should be fine.

There is a lot of improvement and tests that can be made, i just wanted to share something i just got working.

Hope that helps people =]

@wallabra
Copy link

wallabra commented Dec 16, 2022

You see, this nesting should naturally derive from "surfaces" as a first-class abstraction of rendered regions, indifferent to whether it's a desktop, a window, or whatever else. A tree of surfaces should be enumerable and visible from anywhere in it, globally but probably with some sort of access control scheme. The issue is this was not considered initially in the design of wlroots, which will haunt it for a very long time because of a little something called technical debt.

@cmprmsd
Copy link

cmprmsd commented Dec 17, 2022

I wonder why nested Sway is a functioning workaround but it's not possible to share individual windows. For now I just share via xwayland, which works okay and is more easy to use than having nested WMs.

@ckcr4lyf
Copy link

For now I just share via xwayland

@cmprmsd can you expand on this - do you mean the specific window you want to share is what you launch via xwayland?

@cmprmsd
Copy link

cmprmsd commented Jan 13, 2023

Sure thing.
When you explicitly launch two applications like chromium and e.g. VMware workstation with xwayland, than both will use "the old" methods for sharing and therefore see each other.

In Chromium you'll notice that for example in Teams you will see all xwayland windows. The monitor share tabs will show black screens. But if you switch to single window, than you can select windows started under xwayland.

Hope this helps for the time being.

@WhyNotHugo
Copy link

Following up on the roadmap above:

  • Create a way to export handles for toplevels (windows) from the compositor

This will be covered by ext-foreign-toplevel-info.

@cmprmsd
Copy link

cmprmsd commented Feb 12, 2023

My workaround does not work any more since some weeks. I don't know why but some component been updated and now only the "Wayland-dialog" is visible even for Chromium or Firefox which have been started with xWayland instead of Wayland. :/

I looked at the pipewire settings and some other flags but nothing did work. 😢

@clushie
Copy link

clushie commented Mar 2, 2023

Thanks @sfrique for your idea. I'm quite happy with that solution. Changing the nested sway window size will automatically resize the screen-sharing appropriately. If you are sharing a window and move to another space, the content that is getting shared won't update while it's not visible for you. Really feels like sharing a window, it's quite perfect for me. Hope this helps others who want to share a window/part of their screen.

Here is how I've accomplished everything:

A script to allow using the sway shortcuts in either the main session or the sub-session if that one is selected:

~/bin/swaymsg-nested

#!/usr/bin/env bash
set -ueo pipefail

if pid="$(swaymsg -t get_tree | jq -e '.. | select(.type?) | select(.focused==true) | select(.app_id=="wlroots").pid')"; then
 export SWAYSOCK="/run/user/${UID}/sway-ipc.${UID}.${pid}.sock"
fi

swaymsg "${@}"

I just check if the window is wlroots which is the window of the nested session, if that's the case I already have the PID of that session an can set it as a socket and then pass it to swaymsg in my ~/.config/sway/config I simply did a find/replace with vim :%s/\(^bindsym \S*\) \(.*\)/\1 exec \~\/bin\/swaymsg-nested \2/g and then had to fix few places where I was doing bindsym --locked and similar.

Only difficulty is that I forward everything to that window, which means I can't control it like other windows 😆 not sure what to do about that yet.

For starting the nested session I just have to make sure to later restore. I'm doing that in a script

~/bin/sway-nested

#!/usr/bin/env bash
set -ueo pipefail

sway -c ~/.config/sway/nested || true

dbus-update-activation-environment --systemd WAYLAND_DISPLAY SWAYSOCK
systemctl --user restart xdg-desktop-portal.service xdg-desktop-portal-wlr.service

and in the .config/sway/nested I simply duplicated most of my main swaywm config and removed any exec or bindsym configs) and made sure to include:

exec dbus-update-activation-environment --systemd WAYLAND_DISPLAY SWAYSOCK
exec systemctl --user restart xdg-desktop-portal.service
exec systemctl --user restart xdg-desktop-portal-wlr.service

Now I can simply start the sway nested session, share that nested window via Firefox/Chromium from the main (since the connection happens via dbus which is shared for both instances). If I wanted to share a whole browser, I'd have to close it and then re-open it inside the nested session.

@jalvesaq
Copy link

A workaround for this is to create a virtual output (HEADLESS-1), move the window to it, and share the virtual output. My configuration for this is:

~/.config/xdg-desktop-portal-wlr/config:

[screencast]
chooser_type=dmenu
chooser_cmd=swaymsg -t get_outputs | jq '.[] | .name' | sed 's/"//g' | wofi -d
max_fps=30

~/.config/sway/config:

# Do the following command in a terminal emulator when you need the virtual output:
# swaymsg create_output

output HEADLESS-1 resolution 1280x720 position 0,1080
output HEADLESS-1 bg "#220900" solid_color
workspace 0 output HEADLESS-1
bindsym $mod+0 workspace number 0
bindsym $mod+Shift+0 move container to workspace number 0

The command swaymsg create_output creates the virtual output HEADLESS-1 the first time that it is run. If you repeat the command, it will create the virtual outputs HEADLESS-2, HEADLESS-3, and so on...

By default, when I try to share an output, the cursor turns a cross (slurp -o is running) and I have to click anywhere in the output to choose it. I could move the cursor to the virtual output, but I prefer to see the list of available outputs. That's why I configured xdg-desktop-portal-wlr to use wofi instead of slurp.

@clushie
Copy link

clushie commented Jun 19, 2023

@jalvesaq Oh cool, so the idea is to overlay a headless output (what you are doing by picking the right pixel position on creation) with a regular output and then to share that headless output? I just tested it quickly by using wdisplay to move the headless output on the same screen as I'm currently at, unfortunately only shows up if I set it to floating and place it within the positioning of the headless output. How do you solve this? PS: You can do jq -r to remove the " symbols.

@jalvesaq
Copy link

Thanks for the tip on how to remove the " symbols!

I can use wl-mirror to visualize the headless output:

wl-mirror HEADLESS-1

But I can also see it in Google Meet (if I'm sharing the output) or preview it in OBS as a "Screen Capture (PipeWire)" source.

@trinitronx
Copy link

trinitronx commented Dec 8, 2023

I can use wl-mirror to visualize the headless output

Very nice! I'll have to try this method out.

But I can also see it in Google Meet (if I'm sharing the output) or preview it in OBS as a "Screen Capture (PipeWire)" source.

Another way that I've found is to use wayvnc + VNC client to view the headless output:

wayvnc --gpu --performance --output=HEADLESS-1
# Then connect to 127.0.0.1:5900 with VNC client (e.g. Remmina)

Keyboard capture becomes somewhat of an obstacle with this method, but usually I can switch back out of the HEADLESS-* output VNC window using the Sway workspace switching keyboard shortcuts. Also, unfortunately the VNC "Host key" doesn't work very well (default in Remmina is Ctrl_R / right Ctrl).

@paolomainardi
Copy link

I am curious to know if other portals have found a solution to this problem?

@paolomainardi
Copy link

Hyprland supports this, so at least their portal started as a fork of this one: #253.
This should be the code used to implement this feature, I am not sure why they didn't try to merge back here.

@WhyNotHugo
Copy link

WhyNotHugo commented Dec 18, 2023

@paolomainardi Hyperland uses the hyprland-toplevel-export-v1 protocol, which wlroots does not support.


Based on the roadmap above, the current state is:

Finish ext-screencopy

Still in progress, lots of unsolved discussion there.

Create a way to export handles for toplevels (windows) from the compositor

Done. Implemented via the ext-foreign-toplevel-list protocol.

Expand ext-screencopy to accept these handles

This could be implemented experimentally in zwlr_screencopy_manager_v1. Although I'd ask the wlroots devs if they'd merge such a change at this stage or would rather wait for ext-screencopy.

Expand the chooser protocol to account for them (#169)

The OUTPUT CHOOSER protocol can be extended to take a value matching a ext_foreign_toplevel_handle_v1::identifier.

Given that, potentially, and output name can match a toplevel name (it would be terrible, but nothing explicitly forbids this), I think a prefix of toplevel: should be used here.

Add this together to share window buffers

Blocked by the items above

@paolomainardi
Copy link

Wow, thanks, @WhyNotHugo. That's a great summary. So we have to help to push ext-screenshopy further.

@amano-kenji
Copy link

Is hyprland already more mature than sway? I already found a few things that work properly only in hyprland.

@RioMeYeah
Copy link

Still nothing with Sway?

@ngotchac
Copy link

I have this little script to start a new headless output for screen sharing:

#!/usr/bin/env bash

# Step 1: Create a new output
swaymsg create_output

# Step 2: Find the name of the newly created output
NEW_OUTPUT=$(swaymsg -t get_outputs | jq -r '.[] | select(.name | startswith("HEADLESS-")) | .name' | sort | tail -n 1)

# Check if the output was successfully created
if [ -z "$NEW_OUTPUT" ]; then
    echo "Failed to create a new output."
    exit 1
fi

# Step 3: Assign a workspace to the new output
swaymsg workspace sshr output "$NEW_OUTPUT"

# Step 4: Set the resolution for the new output
swaymsg output "$NEW_OUTPUT" resolution 1280x720

# Step 5: Set the background color for the new output
swaymsg output "$NEW_OUTPUT" bg "#220900" solid_color

# Step 6: Switch to workspace sshr and then back to the previous workspace
CURRENT_WORKSPACE=$(swaymsg -t get_workspaces | jq -r '.[] | select(.focused) | .name')
swaymsg workspace sshr
swaymsg workspace "$CURRENT_WORKSPACE"

wl-mirror "$NEW_OUTPUT"

notify-send "Created new output $NEW_OUTPUT."

with keybindings in my sway config for workspace sshr.

It creates the new output, assign the sshr workspace to it, switch back and forth to it (since when the output is created, the next available workspace is assigned to it), open wl-mirror to it, and send a notification.

@rmasad
Copy link

rmasad commented May 26, 2024

Nice, the problem is that now Chrome doesn't let me share windows, only tabs. Pressing on windows returns me to the tabs section.

@jalvesaq
Copy link

@rmasad, you can share the whole virtual (headless) output and use wl-mirror only to visualize the output outside the browser.

@YellowOnion
Copy link

@paolomainardi Hyperland uses the hyprland-toplevel-export-v1 protocol, which wlroots does not support.

Hyprland uses a fork of wlroots, the question of why they haven't migrated these changes to upstream is valid, though I think just a boring answer where they just want to move fast and break things without worrying about compatibility till designs are stable or trying be considerate of ever potential use case, I also have a suspicion that wlroots/wayland devs have other priorities, hyprland has a focus on features that make using OBS good, like global hotkey support, that's been a stagnant in wayland for about 8 years, and hyprland is the only wl-wm with support for it.

@Php22
Copy link

Php22 commented Jun 14, 2024

I have this little script to start a new headless output for screen sharing:

#!/usr/bin/env bash

# Step 1: Create a new output
swaymsg create_output

# Step 2: Find the name of the newly created output
NEW_OUTPUT=$(swaymsg -t get_outputs | jq -r '.[] | select(.name | startswith("HEADLESS-")) | .name' | sort | tail -n 1)

# Check if the output was successfully created
if [ -z "$NEW_OUTPUT" ]; then
    echo "Failed to create a new output."
    exit 1
fi

# Step 3: Assign a workspace to the new output
swaymsg workspace sshr output "$NEW_OUTPUT"

# Step 4: Set the resolution for the new output
swaymsg output "$NEW_OUTPUT" resolution 1280x720

# Step 5: Set the background color for the new output
swaymsg output "$NEW_OUTPUT" bg "#220900" solid_color

# Step 6: Switch to workspace sshr and then back to the previous workspace
CURRENT_WORKSPACE=$(swaymsg -t get_workspaces | jq -r '.[] | select(.focused) | .name')
swaymsg workspace sshr
swaymsg workspace "$CURRENT_WORKSPACE"

wl-mirror "$NEW_OUTPUT"

notify-send "Created new output $NEW_OUTPUT."

A awesome script! just one question, how do i delete the virtual output (the "headless" one) after i'm done recording/sharing screen?

@ngotchac
Copy link

A awesome script! just one question, how do i delete the virtual output (the "headless" one) after i'm done recording/sharing screen?

I use this script for stopping the screenshare:

#!/usr/bin/env bash

# Get all outputs with names starting with HEADLESS-
headless_outputs=$(swaymsg -t get_outputs | jq -r '.[] | select(.name | startswith("HEADLESS-")) | .name')

# Check if there are any HEADLESS outputs
if [ -z "$headless_outputs" ]; then
    echo "No HEADLESS outputs found."
    exit 0
fi

# Unplug each HEADLESS output
for output in $headless_outputs; do
    echo "Unplugging $output..."
    swaymsg output "$output" unplug
done

notify-send "All HEADLESS outputs have been unplugged."

@pm4rcin
Copy link

pm4rcin commented Aug 11, 2024

@WhyNotHugo so now things just need to be implemented in wlroots and integrate OUTPUT CHOOSER and finally there's a generic way to share windows on wlroots based compositors right? :)
EDIT: Context for everyone https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/124

@WhyNotHugo
Copy link

Indeed. An updated version of the previous roadmap is:

@llyyr
Copy link

llyyr commented Nov 3, 2024

wlroots implementation (https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4545)

This doesn't actually implement ext_foreign_toplevel_image_capture_source_manager_v1 so that's not sufficient btw.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests