Allow Window resizing with the xcb version of capturing images

This commit is contained in:
loki 2019-12-30 21:58:53 +01:00
parent 330b0ef8ef
commit 1e2faea1ac

View File

@ -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;
}