如何在 Gnome 中创建一个虚拟显示器,然后将其它电脑变成副屏

如何在 Gnome 中创建一个虚拟显示器,然后将其它电脑变成副屏

如何在 Gnome 中创建一个虚拟显示器,然后将其它电脑变成副屏-零修论坛
如何在 Gnome 中创建一个虚拟显示器,然后将其它电脑变成副屏
此内容为付费阅读,请付费后查看
30积分
零修客服
付费阅读

事情是这样的.我希望在教师机上用机房管理软件播放自己 ubuntu 笔记本上的内容,最好是作为副屏,方便我放课件的时候看备注(pympress).然后就有了这么个邪修 workflow.

首先是创建一块虚拟显示器.这一步我折腾了好久.因为我用的是 wayland,查到的好多资料都只在 x11 上可用.ai 向我推荐了内核级的虚拟显示器,但是都不太好用,gnome 压根不识别.

查找了 100 年,我发现 [一篇文章](https://ubuntuhandbook.org/index.php/2023/07/share-extended-screen-gnome/) 介绍了 ubuntu 远程桌面可以创建一块虚拟屏幕,让其他电脑通过 rdp 连接.但是很遗憾,我这里不能显示鼠标光标.

但是这说明 gnome 肯定是支持在用户侧创建一个虚拟显示器的.我选择直接询问 ai 是怎么实现的,原来是有一个专门的 dbus 接口.由于我不熟悉操作 dbus,直接让 ai 给我写了个脚本.

“`python
#!/usr/bin/env /usr/bin/python3

import sys
import argparse
import dbus
from gi.repository import GLib
from dbus.mainloop.glib import DBusGMainLoop

import gi
gi.require_version(‘Gst’, ‘1.0’)
from gi.repository import Gst

DBusGMainLoop(set_as_default=True)
Gst.init(None)

loop = GLib.MainLoop()
pipeline = None

def main():
global pipeline

parser = argparse.ArgumentParser(description=”Create a virtual monitor in GNOME Wayland”)
parser.add_argument(“-W”, “–width”, type=int, default=1920, help=”Width of the virtual monitor”)
parser.add_argument(“-H”, “–height”, type=int, default=1080, help=”Height of the virtual monitor”)
parser.add_argument(“-f”, “–fps”, type=int, default=60, help=”Framerate of the virtual monitor”)
parser.add_argument(“-v”, “–view”, action=”store_true”, help=”Show the virtual monitor in a local window (useful for testing)”)
args = parser.parse_args()

bus = dbus.SessionBus()
screen_cast_iface = ‘org.gnome.Mutter.ScreenCast’
screen_cast_session_iface = ‘org.gnome.Mutter.ScreenCast.Session’

# 1. 连接到 Mutter 的 ScreenCast API
try:
screen_cast = bus.get_object(screen_cast_iface, ‘/org/gnome/Mutter/ScreenCast’)
except dbus.exceptions.DBusException as e:
print(f”Failed to connect to Mutter ScreenCast API: {e}”)
print(“Are you running GNOME on Wayland?”)
sys.exit(1)

print(“1. Creating screen cast session…”)
session_path = screen_cast.CreateSession([], dbus_interface=screen_cast_iface)
print(f” Session path: {session_path}”)
session = bus.get_object(screen_cast_iface, session_path)

print(f”2. Requesting virtual monitor creation ({args.width}x{args.height}@{args.fps})…”)
# 属性配置:is-platform 表示捕获整个 stage 渲染,cursor-mode 1 表示嵌入鼠标指针
properties = dbus.Dictionary({
‘is-platform’: dbus.Boolean(True, variant_level=1),
‘cursor-mode’: dbus.UInt32(1, variant_level=1)
}, signature=’sv’)

# 核心 API:RecordVirtual
stream_path = session.RecordVirtual(properties, dbus_interface=screen_cast_session_iface)
print(f” Stream path: {stream_path}”)
stream = bus.get_object(screen_cast_iface, stream_path)

def terminate():
global pipeline
if pipeline is not None:
print(“\nStopping GStreamer pipeline…”)
pipeline.send_event(Gst.Event.new_eos())
pipeline.set_state(Gst.State.NULL)
print(“Stopping Mutter session…”)
session.Stop(dbus_interface=screen_cast_session_iface)
loop.quit()

def on_message(bus, message):
t = message.type
if t == Gst.MessageType.EOS or t == Gst.MessageType.ERROR:
terminate()

def on_pipewire_stream_added(node_id):
global pipeline
print(f”3. PipeWire stream added! Node ID: {node_id}”)

# 如果指定了 –view,则在本地打开一个窗口显示虚拟屏幕内容;否则使用 fakesink 仅保持连接
sink = “autovideosink” if args.view else “fakesink”

# 关键点:通过 video/x-raw 的 caps 限制,告诉 PipeWire (及 Mutter) 我们需要的分辨率
pipeline_str = (
f’pipewiresrc path={node_id} ! ‘
f’video/x-raw,max-framerate={args.fps}/1,width={args.width},height={args.height} ! ‘
f’videoconvert ! {sink}’
)
print(f” Starting pipeline: {pipeline_str}”)
pipeline = Gst.parse_launch(pipeline_str)
pipeline.set_state(Gst.State.PLAYING)
pipeline.get_bus().connect(‘message’, on_message)
print(“✅ Virtual monitor is now active! Check your GNOME Display Settings.”)

# 监听 PipeWire 流就绪信号
stream.connect_to_signal(“PipeWireStreamAdded”, on_pipewire_stream_added)

print(“4. Starting session…”)
session.Start(dbus_interface=screen_cast_session_iface)
print(“Press Ctrl+C to destroy the virtual monitor and exit.”)

try:
loop.run()
except KeyboardInterrupt:
print(“\nInterrupted by user.”)
terminate()

if __name__ == ‘__main__’:
main()
“`

然后就是共享桌面了.我选择的是 [deskreen](https://github.com/pavlobu/deskreen),在浏览器里就能直接使用.

如果你愿意花十块钱买一个 HDMI 欺骗器就可以省去第一步.反正我不愿意.

© 版权声明
THE END
喜欢就支持一下吧
点赞20 分享
评论 共1条

请登录后发表评论

    暂无评论内容