[feat] enable screen switch on Linux platform

This commit is contained in:
dijunkun
2025-05-29 18:09:34 +08:00
parent d72c6d9df7
commit 094204361c
8 changed files with 111 additions and 52 deletions

View File

@@ -8,7 +8,8 @@ MouseController::MouseController() {}
MouseController::~MouseController() { Destroy(); }
int MouseController::Init(int screen_width, int screen_height) {
int MouseController::Init(std::vector<DisplayInfo> display_info_list) {
display_info_list_ = display_info_list;
display_ = XOpenDisplay(NULL);
if (!display_) {
LOG_ERROR("Cannot connect to X server");
@@ -16,8 +17,6 @@ int MouseController::Init(int screen_width, int screen_height) {
}
root_ = DefaultRootWindow(display_);
screen_width_ = screen_width;
screen_height_ = screen_height;
int event_base, error_base, major_version, minor_version;
if (!XTestQueryExtension(display_, &event_base, &error_base, &major_version,
@@ -38,14 +37,19 @@ int MouseController::Destroy() {
return 0;
}
int MouseController::SendMouseCommand(RemoteAction remote_action) {
int MouseController::SendMouseCommand(RemoteAction remote_action,
int display_index) {
switch (remote_action.type) {
case mouse:
switch (remote_action.m.flag) {
case MouseFlag::move:
SetMousePosition(
static_cast<int>(remote_action.m.x * screen_width_),
static_cast<int>(remote_action.m.y * screen_height_));
static_cast<int>(remote_action.m.x *
display_info_list_[display_index].width +
display_info_list_[display_index].left),
static_cast<int>(remote_action.m.y *
display_info_list_[display_index].height +
display_info_list_[display_index].top));
break;
case MouseFlag::left_down:
XTestFakeButtonEvent(display_, 1, True, CurrentTime);

View File

@@ -11,6 +11,8 @@
#include <X11/Xutil.h>
#include <unistd.h>
#include <vector>
#include "device_controller.h"
class MouseController : public DeviceController {
@@ -19,9 +21,9 @@ class MouseController : public DeviceController {
virtual ~MouseController();
public:
virtual int Init(int screen_width, int screen_height);
virtual int Init(std::vector<DisplayInfo> display_info_list);
virtual int Destroy();
virtual int SendMouseCommand(RemoteAction remote_action);
virtual int SendMouseCommand(RemoteAction remote_action, int display_index);
private:
void SimulateKeyDown(int kval);
@@ -31,6 +33,7 @@ class MouseController : public DeviceController {
Display* display_ = nullptr;
Window root_ = 0;
std::vector<DisplayInfo> display_info_list_;
int screen_width_ = 0;
int screen_height_ = 0;
};

View File

@@ -18,6 +18,34 @@ int ScreenCapturerX11::Init(const int fps, cb_desktop_data cb) {
}
root_ = DefaultRootWindow(display_);
screen_res_ = XRRGetScreenResources(display_, root_);
if (!screen_res_) {
LOG_ERROR("Failed to get screen resources");
XCloseDisplay(display_);
return 1;
}
for (int i = 0; i < screen_res_->noutput; ++i) {
RROutput output = screen_res_->outputs[i];
XRROutputInfo* output_info =
XRRGetOutputInfo(display_, screen_res_, output);
if (output_info->connection == RR_Connected && output_info->crtc != 0) {
XRRCrtcInfo* crtc_info =
XRRGetCrtcInfo(display_, screen_res_, output_info->crtc);
display_info_list_.push_back(
DisplayInfo((void*)display_, output_info->name, true, crtc_info->x,
crtc_info->y, crtc_info->width, crtc_info->height));
XRRFreeCrtcInfo(crtc_info);
}
if (output_info) {
XRRFreeOutputInfo(output_info);
}
}
XWindowAttributes attr;
XGetWindowAttributes(display_, root_, &attr);
@@ -40,7 +68,19 @@ int ScreenCapturerX11::Init(const int fps, cb_desktop_data cb) {
int ScreenCapturerX11::Destroy() {
Stop();
CleanUp();
y_plane_.clear();
uv_plane_.clear();
if (screen_res_) {
XRRFreeScreenResources(screen_res_);
screen_res_ = nullptr;
}
if (display_) {
XCloseDisplay(display_);
display_ = nullptr;
}
return 0;
}
@@ -63,21 +103,43 @@ int ScreenCapturerX11::Stop() {
return 0;
}
int ScreenCapturerX11::Pause() {
int ScreenCapturerX11::Pause(int monitor_index) {
paused_ = true;
return 0;
}
int ScreenCapturerX11::Resume() {
int ScreenCapturerX11::Resume(int monitor_index) {
paused_ = false;
return 0;
}
void ScreenCapturerX11::OnFrame() {
if (!display_) return;
int ScreenCapturerX11::SwitchTo(int monitor_index) {
monitor_index_ = monitor_index;
return 0;
}
XImage* image =
XGetImage(display_, root_, 0, 0, width_, height_, AllPlanes, ZPixmap);
std::vector<DisplayInfo> ScreenCapturerX11::GetDisplayInfoList() {
return display_info_list_;
}
void ScreenCapturerX11::OnFrame() {
if (!display_) {
LOG_ERROR("Display is not initialized");
return;
}
if (monitor_index_ < 0 || monitor_index_ >= display_info_list_.size()) {
LOG_ERROR("Invalid monitor index: {}", monitor_index_.load());
return;
}
left_ = display_info_list_[monitor_index_].left;
top_ = display_info_list_[monitor_index_].top;
width_ = display_info_list_[monitor_index_].width;
height_ = display_info_list_[monitor_index_].height;
XImage* image = XGetImage(display_, root_, left_, top_, width_, height_,
AllPlanes, ZPixmap);
if (!image) return;
bool needs_copy = image->bytes_per_line != width_ * 4;
@@ -104,15 +166,9 @@ void ScreenCapturerX11::OnFrame() {
nv12.insert(nv12.end(), uv_plane_.begin(), uv_plane_.end());
if (callback_) {
callback_(nv12.data(), width_ * height_ * 3 / 2, width_, height_, "");
callback_(nv12.data(), width_ * height_ * 3 / 2, width_, height_,
display_info_list_[monitor_index_].name.c_str());
}
XDestroyImage(image);
}
void ScreenCapturerX11::CleanUp() {
if (display_) {
XCloseDisplay(display_);
display_ = nullptr;
}
}

View File

@@ -9,6 +9,7 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xrandr.h>
#include <atomic>
#include <cstring>
@@ -17,17 +18,7 @@
#include <thread>
#include <vector>
class ScreenCapturer {
public:
typedef std::function<void(unsigned char*, int width, int height, int stride)>
cb_desktop_data;
virtual ~ScreenCapturer() {}
virtual int Init(const int fps, cb_desktop_data cb) = 0;
virtual int Destroy() = 0;
virtual int Start() = 0;
virtual int Stop() = 0;
};
#include "screen_capturer.h"
class ScreenCapturerX11 : public ScreenCapturer {
public:
@@ -40,24 +31,30 @@ class ScreenCapturerX11 : public ScreenCapturer {
int Start() override;
int Stop() override;
int Pause();
int Resume();
int Pause(int monitor_index) override;
int Resume(int monitor_index) override;
int SwitchTo(int monitor_index) override;
std::vector<DisplayInfo> GetDisplayInfoList() override;
void OnFrame();
protected:
void CleanUp();
private:
Display* display_ = nullptr;
Window root_ = 0;
XRRScreenResources* screen_res_ = nullptr;
int left_ = 0;
int top_ = 0;
int width_ = 0;
int height_ = 0;
std::thread thread_;
std::atomic<bool> running_{false};
std::atomic<bool> paused_{false};
std::atomic<int> monitor_index_{0};
int fps_ = 30;
cb_desktop_data callback_;
std::vector<DisplayInfo> display_info_list_;
// 缓冲区
std::vector<uint8_t> y_plane_;

View File

@@ -22,13 +22,12 @@ class ScreenCapturerSck : public ScreenCapturer {
~ScreenCapturerSck();
public:
virtual int Init(const int fps, cb_desktop_data cb) override;
virtual int Destroy() override;
virtual int Start() override;
virtual int Stop() override;
int Init(const int fps, cb_desktop_data cb) override;
int Destroy() override;
int Start() override;
int Stop() override;
int Pause(int monitor_index) override;
int Resume(int monitor_index) override;
int SwitchTo(int monitor_index) override;

View File

@@ -20,13 +20,13 @@ class ScreenCapturerWgc : public ScreenCapturer,
public:
bool IsWgcSupported();
virtual int Init(const int fps, cb_desktop_data cb) override;
virtual int Destroy() override;
virtual int Start() override;
virtual int Stop() override;
int Init(const int fps, cb_desktop_data cb) override;
int Destroy() override;
int Start() override;
int Stop() override;
virtual int Pause(int monitor_index) override;
virtual int Resume(int monitor_index) override;
int Pause(int monitor_index) override;
int Resume(int monitor_index) override;
std::vector<DisplayInfo> GetDisplayInfoList() { return display_info_list_; }

View File

@@ -25,7 +25,7 @@ void Render::DrawConnectionStatusText(
ImGui::SetCursorPos(
ImVec2((size.x - text_size.x) * 0.5f,
(size.y - text_size.y - title_bar_height_) * 0.5f));
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), text.c_str());
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), "%s", text.c_str());
}
}

View File

@@ -30,7 +30,7 @@ elseif is_os("linux") then
add_requires("libyuv")
add_syslinks("pthread", "dl")
add_linkdirs("thirdparty/projectx/thirdparty/nvcodec/lib/x64")
add_links("SDL2", "cuda", "nvidia-encode", "nvcuvid", "X11", "Xtst")
add_links("SDL2", "cuda", "nvidia-encode", "nvcuvid", "X11", "Xtst", "Xrandr")
add_cxflags("-Wno-unused-variable")
elseif is_os("macosx") then
add_links("SDL2", "SDL2main")