Allow Window resizing with the xcb version of capturing images
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "../main.h"
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <ifaddrs.h>
|
#include <ifaddrs.h>
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
#include <sunshine/task_pool.h>
|
||||||
|
|
||||||
namespace platf {
|
namespace platf {
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
@@ -57,6 +59,7 @@ class shm_data_t {
|
|||||||
public:
|
public:
|
||||||
shm_data_t() : data {(void*)-1 } {}
|
shm_data_t() : data {(void*)-1 } {}
|
||||||
shm_data_t(void *data) : data {data } {}
|
shm_data_t(void *data) : data {data } {}
|
||||||
|
|
||||||
shm_data_t(shm_data_t &&other) noexcept : data(other.data) {
|
shm_data_t(shm_data_t &&other) noexcept : data(other.data) {
|
||||||
other.data = (void*)-1;
|
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 {
|
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();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void 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();
|
refresh();
|
||||||
XImage *img { XGetImage(
|
XImage *img { XGetImage(
|
||||||
display.get(),
|
xdisplay.get(),
|
||||||
window,
|
xwindow,
|
||||||
0, 0,
|
0, 0,
|
||||||
attr.width, attr.height,
|
xattr.width, xattr.height,
|
||||||
AllPlanes, ZPixmap)
|
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);
|
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);
|
return std::make_unique<x11_img_t>((std::uint8_t*)img->data, img->width, img->height, img);
|
||||||
}
|
}
|
||||||
|
|
||||||
xdisplay_t display;
|
xdisplay_t xdisplay;
|
||||||
Window window;
|
Window xwindow;
|
||||||
XWindowAttributes attr;
|
XWindowAttributes xattr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct shm_attr_t : display_t {
|
struct shm_attr_t : public x11_attr_t {
|
||||||
xdisplay_t xdisplay;
|
xdisplay_t shm_xdisplay; // Prevent race condition with x11_attr_t::xdisplay
|
||||||
|
|
||||||
xcb_connect_t xcb;
|
xcb_connect_t xcb;
|
||||||
xcb_screen_t *display;
|
xcb_screen_t *display;
|
||||||
std::uint32_t seg;
|
std::uint32_t seg;
|
||||||
@@ -172,7 +174,31 @@ struct shm_attr_t : display_t {
|
|||||||
|
|
||||||
shm_data_t data;
|
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 {
|
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(
|
auto img_cookie = xcb_shm_get_image_unchecked(
|
||||||
xcb.get(),
|
xcb.get(),
|
||||||
display->root,
|
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) };
|
xcb_img_t img_reply { xcb_shm_get_image_reply(xcb.get(), img_cookie, nullptr) };
|
||||||
if(!img_reply) {
|
if(!img_reply) {
|
||||||
std::cout << "FATAL ERROR: Could not get image reply"sv << std::endl;
|
std::cout << "Info: Could not get image reply"sv << std::endl;
|
||||||
std::abort();
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto img = std::make_unique<shm_img_t>();
|
auto img = std::make_unique<shm_img_t>();
|
||||||
@@ -201,11 +227,52 @@ struct shm_attr_t : display_t {
|
|||||||
return img;
|
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;
|
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() {
|
std::uint32_t frame_size() {
|
||||||
return display->height_in_pixels * display->width_in_pixels * 4;
|
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() {
|
std::unique_ptr<display_t> shm_display() {
|
||||||
auto shm = std::make_unique<shm_attr_t>();
|
auto shm = std::make_unique<shm_attr_t>();
|
||||||
|
|
||||||
shm->xdisplay.reset(XOpenDisplay(nullptr));
|
if(shm->init()) {
|
||||||
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;
|
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user