mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-26 12:15:34 +08:00
[feat] enable screen switch on Linux platform
This commit is contained in:
@@ -8,7 +8,8 @@ MouseController::MouseController() {}
|
|||||||
|
|
||||||
MouseController::~MouseController() { Destroy(); }
|
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);
|
display_ = XOpenDisplay(NULL);
|
||||||
if (!display_) {
|
if (!display_) {
|
||||||
LOG_ERROR("Cannot connect to X server");
|
LOG_ERROR("Cannot connect to X server");
|
||||||
@@ -16,8 +17,6 @@ int MouseController::Init(int screen_width, int screen_height) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
root_ = DefaultRootWindow(display_);
|
root_ = DefaultRootWindow(display_);
|
||||||
screen_width_ = screen_width;
|
|
||||||
screen_height_ = screen_height;
|
|
||||||
|
|
||||||
int event_base, error_base, major_version, minor_version;
|
int event_base, error_base, major_version, minor_version;
|
||||||
if (!XTestQueryExtension(display_, &event_base, &error_base, &major_version,
|
if (!XTestQueryExtension(display_, &event_base, &error_base, &major_version,
|
||||||
@@ -38,14 +37,19 @@ int MouseController::Destroy() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MouseController::SendMouseCommand(RemoteAction remote_action) {
|
int MouseController::SendMouseCommand(RemoteAction remote_action,
|
||||||
|
int display_index) {
|
||||||
switch (remote_action.type) {
|
switch (remote_action.type) {
|
||||||
case mouse:
|
case mouse:
|
||||||
switch (remote_action.m.flag) {
|
switch (remote_action.m.flag) {
|
||||||
case MouseFlag::move:
|
case MouseFlag::move:
|
||||||
SetMousePosition(
|
SetMousePosition(
|
||||||
static_cast<int>(remote_action.m.x * screen_width_),
|
static_cast<int>(remote_action.m.x *
|
||||||
static_cast<int>(remote_action.m.y * screen_height_));
|
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;
|
break;
|
||||||
case MouseFlag::left_down:
|
case MouseFlag::left_down:
|
||||||
XTestFakeButtonEvent(display_, 1, True, CurrentTime);
|
XTestFakeButtonEvent(display_, 1, True, CurrentTime);
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "device_controller.h"
|
#include "device_controller.h"
|
||||||
|
|
||||||
class MouseController : public DeviceController {
|
class MouseController : public DeviceController {
|
||||||
@@ -19,9 +21,9 @@ class MouseController : public DeviceController {
|
|||||||
virtual ~MouseController();
|
virtual ~MouseController();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual int Init(int screen_width, int screen_height);
|
virtual int Init(std::vector<DisplayInfo> display_info_list);
|
||||||
virtual int Destroy();
|
virtual int Destroy();
|
||||||
virtual int SendMouseCommand(RemoteAction remote_action);
|
virtual int SendMouseCommand(RemoteAction remote_action, int display_index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SimulateKeyDown(int kval);
|
void SimulateKeyDown(int kval);
|
||||||
@@ -31,6 +33,7 @@ class MouseController : public DeviceController {
|
|||||||
|
|
||||||
Display* display_ = nullptr;
|
Display* display_ = nullptr;
|
||||||
Window root_ = 0;
|
Window root_ = 0;
|
||||||
|
std::vector<DisplayInfo> display_info_list_;
|
||||||
int screen_width_ = 0;
|
int screen_width_ = 0;
|
||||||
int screen_height_ = 0;
|
int screen_height_ = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,6 +18,34 @@ int ScreenCapturerX11::Init(const int fps, cb_desktop_data cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
root_ = DefaultRootWindow(display_);
|
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;
|
XWindowAttributes attr;
|
||||||
XGetWindowAttributes(display_, root_, &attr);
|
XGetWindowAttributes(display_, root_, &attr);
|
||||||
|
|
||||||
@@ -40,7 +68,19 @@ int ScreenCapturerX11::Init(const int fps, cb_desktop_data cb) {
|
|||||||
|
|
||||||
int ScreenCapturerX11::Destroy() {
|
int ScreenCapturerX11::Destroy() {
|
||||||
Stop();
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,21 +103,43 @@ int ScreenCapturerX11::Stop() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ScreenCapturerX11::Pause() {
|
int ScreenCapturerX11::Pause(int monitor_index) {
|
||||||
paused_ = true;
|
paused_ = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ScreenCapturerX11::Resume() {
|
int ScreenCapturerX11::Resume(int monitor_index) {
|
||||||
paused_ = false;
|
paused_ = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenCapturerX11::OnFrame() {
|
int ScreenCapturerX11::SwitchTo(int monitor_index) {
|
||||||
if (!display_) return;
|
monitor_index_ = monitor_index;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
XImage* image =
|
std::vector<DisplayInfo> ScreenCapturerX11::GetDisplayInfoList() {
|
||||||
XGetImage(display_, root_, 0, 0, width_, height_, AllPlanes, ZPixmap);
|
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;
|
if (!image) return;
|
||||||
|
|
||||||
bool needs_copy = image->bytes_per_line != width_ * 4;
|
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());
|
nv12.insert(nv12.end(), uv_plane_.begin(), uv_plane_.end());
|
||||||
|
|
||||||
if (callback_) {
|
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);
|
XDestroyImage(image);
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenCapturerX11::CleanUp() {
|
|
||||||
if (display_) {
|
|
||||||
XCloseDisplay(display_);
|
|
||||||
display_ = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
|
#include <X11/extensions/Xrandr.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -17,17 +18,7 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class ScreenCapturer {
|
#include "screen_capturer.h"
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ScreenCapturerX11 : public ScreenCapturer {
|
class ScreenCapturerX11 : public ScreenCapturer {
|
||||||
public:
|
public:
|
||||||
@@ -40,24 +31,30 @@ class ScreenCapturerX11 : public ScreenCapturer {
|
|||||||
int Start() override;
|
int Start() override;
|
||||||
int Stop() override;
|
int Stop() override;
|
||||||
|
|
||||||
int Pause();
|
int Pause(int monitor_index) override;
|
||||||
int Resume();
|
int Resume(int monitor_index) override;
|
||||||
|
|
||||||
|
int SwitchTo(int monitor_index) override;
|
||||||
|
|
||||||
|
std::vector<DisplayInfo> GetDisplayInfoList() override;
|
||||||
|
|
||||||
void OnFrame();
|
void OnFrame();
|
||||||
|
|
||||||
protected:
|
|
||||||
void CleanUp();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Display* display_ = nullptr;
|
Display* display_ = nullptr;
|
||||||
Window root_ = 0;
|
Window root_ = 0;
|
||||||
|
XRRScreenResources* screen_res_ = nullptr;
|
||||||
|
int left_ = 0;
|
||||||
|
int top_ = 0;
|
||||||
int width_ = 0;
|
int width_ = 0;
|
||||||
int height_ = 0;
|
int height_ = 0;
|
||||||
std::thread thread_;
|
std::thread thread_;
|
||||||
std::atomic<bool> running_{false};
|
std::atomic<bool> running_{false};
|
||||||
std::atomic<bool> paused_{false};
|
std::atomic<bool> paused_{false};
|
||||||
|
std::atomic<int> monitor_index_{0};
|
||||||
int fps_ = 30;
|
int fps_ = 30;
|
||||||
cb_desktop_data callback_;
|
cb_desktop_data callback_;
|
||||||
|
std::vector<DisplayInfo> display_info_list_;
|
||||||
|
|
||||||
// 缓冲区
|
// 缓冲区
|
||||||
std::vector<uint8_t> y_plane_;
|
std::vector<uint8_t> y_plane_;
|
||||||
|
|||||||
@@ -22,13 +22,12 @@ class ScreenCapturerSck : public ScreenCapturer {
|
|||||||
~ScreenCapturerSck();
|
~ScreenCapturerSck();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual int Init(const int fps, cb_desktop_data cb) override;
|
int Init(const int fps, cb_desktop_data cb) override;
|
||||||
virtual int Destroy() override;
|
int Destroy() override;
|
||||||
virtual int Start() override;
|
int Start() override;
|
||||||
virtual int Stop() override;
|
int Stop() override;
|
||||||
|
|
||||||
int Pause(int monitor_index) override;
|
int Pause(int monitor_index) override;
|
||||||
|
|
||||||
int Resume(int monitor_index) override;
|
int Resume(int monitor_index) override;
|
||||||
|
|
||||||
int SwitchTo(int monitor_index) override;
|
int SwitchTo(int monitor_index) override;
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ class ScreenCapturerWgc : public ScreenCapturer,
|
|||||||
public:
|
public:
|
||||||
bool IsWgcSupported();
|
bool IsWgcSupported();
|
||||||
|
|
||||||
virtual int Init(const int fps, cb_desktop_data cb) override;
|
int Init(const int fps, cb_desktop_data cb) override;
|
||||||
virtual int Destroy() override;
|
int Destroy() override;
|
||||||
virtual int Start() override;
|
int Start() override;
|
||||||
virtual int Stop() override;
|
int Stop() override;
|
||||||
|
|
||||||
virtual int Pause(int monitor_index) override;
|
int Pause(int monitor_index) override;
|
||||||
virtual int Resume(int monitor_index) override;
|
int Resume(int monitor_index) override;
|
||||||
|
|
||||||
std::vector<DisplayInfo> GetDisplayInfoList() { return display_info_list_; }
|
std::vector<DisplayInfo> GetDisplayInfoList() { return display_info_list_; }
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ void Render::DrawConnectionStatusText(
|
|||||||
ImGui::SetCursorPos(
|
ImGui::SetCursorPos(
|
||||||
ImVec2((size.x - text_size.x) * 0.5f,
|
ImVec2((size.x - text_size.x) * 0.5f,
|
||||||
(size.y - text_size.y - title_bar_height_) * 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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ elseif is_os("linux") then
|
|||||||
add_requires("libyuv")
|
add_requires("libyuv")
|
||||||
add_syslinks("pthread", "dl")
|
add_syslinks("pthread", "dl")
|
||||||
add_linkdirs("thirdparty/projectx/thirdparty/nvcodec/lib/x64")
|
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")
|
add_cxflags("-Wno-unused-variable")
|
||||||
elseif is_os("macosx") then
|
elseif is_os("macosx") then
|
||||||
add_links("SDL2", "SDL2main")
|
add_links("SDL2", "SDL2main")
|
||||||
|
|||||||
Reference in New Issue
Block a user