mirror of
https://github.com/thinkonmay/sunshine-sdk.git
synced 2025-12-26 22:48:09 +00:00
Allow Window resizing with the xcb version of capturing images
This commit is contained in:
parent
330b0ef8ef
commit
1e2faea1ac
@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
#include "common.h"
|
||||
#include "../main.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <ifaddrs.h>
|
||||
@ -22,6 +23,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <bitset>
|
||||
#include <sunshine/task_pool.h>
|
||||
|
||||
namespace platf {
|
||||
using namespace std::literals;
|
||||
@ -57,6 +59,7 @@ class shm_data_t {
|
||||
public:
|
||||
shm_data_t() : data {(void*)-1 } {}
|
||||
shm_data_t(void *data) : data {data } {}
|
||||
|
||||
shm_data_t(shm_data_t &&other) noexcept : data(other.data) {
|
||||
other.data = (void*)-1;
|
||||
}
|
||||
@ -130,21 +133,21 @@ void blend_cursor(Display *display, std::uint8_t *img_data, int width, int heigh
|
||||
}
|
||||
}
|
||||
struct x11_attr_t : public display_t {
|
||||
x11_attr_t() : display {XOpenDisplay(nullptr) }, window {DefaultRootWindow(display.get()) }, attr {} {
|
||||
x11_attr_t() : xdisplay {XOpenDisplay(nullptr) }, xwindow {DefaultRootWindow(xdisplay.get()) }, xattr {} {
|
||||
refresh();
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
XGetWindowAttributes(display.get(), window, &attr);
|
||||
XGetWindowAttributes(xdisplay.get(), xwindow, &xattr);
|
||||
}
|
||||
|
||||
std::unique_ptr<img_t> snapshot(bool cursor) {
|
||||
std::unique_ptr<img_t> snapshot(bool cursor) override {
|
||||
refresh();
|
||||
XImage *img { XGetImage(
|
||||
display.get(),
|
||||
window,
|
||||
xdisplay.get(),
|
||||
xwindow,
|
||||
0, 0,
|
||||
attr.width, attr.height,
|
||||
xattr.width, xattr.height,
|
||||
AllPlanes, ZPixmap)
|
||||
};
|
||||
|
||||
@ -152,18 +155,17 @@ struct x11_attr_t : public display_t {
|
||||
return std::make_unique<x11_img_t>((std::uint8_t*)img->data, img->width, img->height, img);
|
||||
}
|
||||
|
||||
blend_cursor(display.get(), (std::uint8_t*)img->data, img->width, img->height);
|
||||
blend_cursor(xdisplay.get(), (std::uint8_t*)img->data, img->width, img->height);
|
||||
return std::make_unique<x11_img_t>((std::uint8_t*)img->data, img->width, img->height, img);
|
||||
}
|
||||
|
||||
xdisplay_t display;
|
||||
Window window;
|
||||
XWindowAttributes attr;
|
||||
xdisplay_t xdisplay;
|
||||
Window xwindow;
|
||||
XWindowAttributes xattr;
|
||||
};
|
||||
|
||||
struct shm_attr_t : display_t {
|
||||
xdisplay_t xdisplay;
|
||||
|
||||
struct shm_attr_t : public x11_attr_t {
|
||||
xdisplay_t shm_xdisplay; // Prevent race condition with x11_attr_t::xdisplay
|
||||
xcb_connect_t xcb;
|
||||
xcb_screen_t *display;
|
||||
std::uint32_t seg;
|
||||
@ -172,7 +174,31 @@ struct shm_attr_t : display_t {
|
||||
|
||||
shm_data_t data;
|
||||
|
||||
util::TaskPool::task_id_t refresh_task_id;
|
||||
void delayed_refresh() {
|
||||
refresh();
|
||||
|
||||
refresh_task_id = task_pool.pushDelayed(&shm_attr_t::delayed_refresh, 1s, this).task_id;
|
||||
}
|
||||
|
||||
shm_attr_t() : x11_attr_t(), shm_xdisplay {XOpenDisplay(nullptr) } {
|
||||
refresh_task_id = task_pool.pushDelayed(&shm_attr_t::delayed_refresh, 1s, this).task_id;
|
||||
}
|
||||
|
||||
~shm_attr_t() {
|
||||
while(!task_pool.cancel(refresh_task_id));
|
||||
}
|
||||
|
||||
std::unique_ptr<img_t> snapshot(bool cursor) override {
|
||||
if(display->width_in_pixels != xattr.width || display->height_in_pixels != xattr.height) {
|
||||
deinit();
|
||||
if(init()) {
|
||||
std::cout << "FATAL ERROR: Couldn't reinitialize shm_attr_t"sv << std::endl;
|
||||
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
auto img_cookie = xcb_shm_get_image_unchecked(
|
||||
xcb.get(),
|
||||
display->root,
|
||||
@ -186,8 +212,8 @@ struct shm_attr_t : display_t {
|
||||
|
||||
xcb_img_t img_reply { xcb_shm_get_image_reply(xcb.get(), img_cookie, nullptr) };
|
||||
if(!img_reply) {
|
||||
std::cout << "FATAL ERROR: Could not get image reply"sv << std::endl;
|
||||
std::abort();
|
||||
std::cout << "Info: Could not get image reply"sv << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto img = std::make_unique<shm_img_t>();
|
||||
@ -201,11 +227,52 @@ struct shm_attr_t : display_t {
|
||||
return img;
|
||||
}
|
||||
|
||||
blend_cursor(xdisplay.get(), img->data, img->width, img->height);
|
||||
blend_cursor(shm_xdisplay.get(), img->data, img->width, img->height);
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
void deinit() {
|
||||
data.~shm_data_t();
|
||||
shm_id.~shm_id_t();
|
||||
xcb.reset(nullptr);
|
||||
}
|
||||
|
||||
int init() {
|
||||
shm_xdisplay.reset(XOpenDisplay(nullptr));
|
||||
xcb.reset(xcb_connect(nullptr, nullptr));
|
||||
if(xcb_connection_has_error(xcb.get())) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!xcb_get_extension_data(xcb.get(), &xcb_shm_id)->present) {
|
||||
std::cout << "Missing SHM extension"sv << std::endl;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto iter = xcb_setup_roots_iterator(xcb_get_setup(xcb.get()));
|
||||
display = iter.data;
|
||||
seg = xcb_generate_id(xcb.get());
|
||||
|
||||
shm_id.id = shmget(IPC_PRIVATE, frame_size(), IPC_CREAT | 0777);
|
||||
if(shm_id.id == -1) {
|
||||
std::cout << "shmget failed"sv << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
xcb_shm_attach(xcb.get(), seg, shm_id.id, false);
|
||||
data.data = shmat(shm_id.id, nullptr, 0);
|
||||
|
||||
if ((uintptr_t)data.data == -1) {
|
||||
std::cout << "shmat failed"sv << std::endl;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::uint32_t frame_size() {
|
||||
return display->height_in_pixels * display->width_in_pixels * 4;
|
||||
}
|
||||
@ -233,34 +300,7 @@ struct mic_attr_t : public mic_t {
|
||||
std::unique_ptr<display_t> shm_display() {
|
||||
auto shm = std::make_unique<shm_attr_t>();
|
||||
|
||||
shm->xdisplay.reset(XOpenDisplay(nullptr));
|
||||
shm->xcb.reset(xcb_connect(nullptr, nullptr));
|
||||
if(xcb_connection_has_error(shm->xcb.get())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(!xcb_get_extension_data(shm->xcb.get(), &xcb_shm_id)->present) {
|
||||
std::cout << "Missing SHM extension"sv << std::endl;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto iter = xcb_setup_roots_iterator(xcb_get_setup(shm->xcb.get()));
|
||||
shm->display = iter.data;
|
||||
shm->seg = xcb_generate_id(shm->xcb.get());
|
||||
|
||||
shm->shm_id.id = shmget(IPC_PRIVATE, shm->frame_size(), IPC_CREAT | 0777);
|
||||
if(shm->shm_id.id == -1) {
|
||||
std::cout << "shmget failed"sv << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
xcb_shm_attach(shm->xcb.get(), shm->seg, shm->shm_id.id, false);
|
||||
shm->data.data = shmat(shm->shm_id.id, nullptr, 0);
|
||||
|
||||
if ((uintptr_t)shm->data.data == -1) {
|
||||
std::cout << "shmat failed"sv << std::endl;
|
||||
|
||||
if(shm->init()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user