Commit 8155cb55 authored by Snir Sheriber's avatar Snir Sheriber Committed by Frediano Ziglio

Convert cursor-updater from xlib to xcb

Signed-off-by: Snir Sheriber's avatarSnir Sheriber <ssheribe@redhat.com>
Acked-by: Frediano Ziglio's avatarFrediano Ziglio <fziglio@redhat.com>
parent 03659dd1
......@@ -7,7 +7,7 @@ License: ASL 2.0
URL: https://www.redhat.com
Source0: %{name}-%{version}.tar.xz
BuildRequires: spice-protocol >= @SPICE_PROTOCOL_MIN_VER@
BuildRequires: libX11-devel libXfixes-devel
BuildRequires: libX11-devel
BuildRequires: libjpeg-turbo-devel
BuildRequires: catch-devel
BuildRequires: pkgconfig(udev)
......
......@@ -16,7 +16,6 @@
#include <vector>
#include <syslog.h>
#include <unistd.h>
#include <X11/extensions/Xfixes.h>
namespace spice {
......@@ -69,17 +68,42 @@ public:
CursorUpdater::CursorUpdater(StreamPort *stream_port) : stream_port(stream_port)
{
display = XOpenDisplay(nullptr);
if (display == nullptr) {
throw Error("Failed to open X display");
con = xcb_connect(nullptr, nullptr);
if (xcb_connection_has_error(con)) {
throw Error("Failed to initiate connection to X");
}
int error_base;
if (!XFixesQueryExtension(display, &xfixes_event_base, &error_base)) {
throw Error("XFixesQueryExtension failed");
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(con)).data;
if (!screen) {
xcb_disconnect(con);
throw Error("Cannot get XCB screen");
}
XFixesSelectCursorInput(display, DefaultRootWindow(display), XFixesDisplayCursorNotifyMask);
// init xfixes
const xcb_query_extension_reply_t *reply = xcb_get_extension_data(con, &xcb_xfixes_id);
if (!reply || !reply->present) {
xcb_disconnect(con);
throw Error("Get xfixes extension failed");
}
xfixes_event_base = reply->first_event;
xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
xcb_xfixes_query_version_reply_t *xfixes_query_reply;
xcb_generic_error_t *error = 0;
xfixes_query_cookie = xcb_xfixes_query_version(con, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION);
xfixes_query_reply = xcb_xfixes_query_version_reply(con, xfixes_query_cookie, &error);
if (!xfixes_query_reply || error) {
free(error);
xcb_disconnect(con);
throw Error("Query xfixes extension failed");
}
free(xfixes_query_reply);
// register to cursor events
xcb_xfixes_select_cursor_input(con ,screen->root , XCB_XFIXES_CURSOR_NOTIFY_MASK_DISPLAY_CURSOR);
xcb_flush(con);
}
void CursorUpdater::operator()()
......@@ -88,41 +112,46 @@ void CursorUpdater::operator()()
while (1) {
try {
XEvent event;
XNextEvent(display, &event);
if (event.type != xfixes_event_base + 1) {
continue;
}
XFixesCursorImage *cursor = XFixesGetCursorImage(display);
if (!cursor) {
continue;
}
if (cursor->cursor_serial == last_serial) {
continue;
while (auto event = xcb_wait_for_event(con)) {
if (event->response_type != xfixes_event_base + XCB_XFIXES_CURSOR_NOTIFY) {
continue;
}
xcb_xfixes_get_cursor_image_cookie_t cookie;
xcb_xfixes_get_cursor_image_reply_t* cursor_reply;
cookie = xcb_xfixes_get_cursor_image(con);
cursor_reply = xcb_xfixes_get_cursor_image_reply(con, cookie, nullptr);
if (cursor_reply->cursor_serial == last_serial) {
free(cursor_reply);
continue;
}
if (cursor_reply->width > STREAM_MSG_CURSOR_SET_MAX_WIDTH ||
cursor_reply->height > STREAM_MSG_CURSOR_SET_MAX_HEIGHT) {
::syslog(LOG_WARNING, "cursor updater thread: ignoring cursor: too big %ux%u",
cursor_reply->width, cursor_reply->height);
free(cursor_reply);
continue;
}
last_serial = cursor_reply->cursor_serial;
// the X11 cursor data may be in a wrong format, copy them to an uint32_t array
size_t pixcount = xcb_xfixes_get_cursor_image_cursor_image_length(cursor_reply);
std::vector<uint32_t> pixels;
pixels.reserve(pixcount);
const uint32_t *reply_pixels = xcb_xfixes_get_cursor_image_cursor_image(cursor_reply);
for (size_t i = 0; i < pixcount; ++i) {
pixels.push_back(reply_pixels[i]);
}
stream_port->send<CursorMessage>(cursor_reply->width, cursor_reply->height,
cursor_reply->xhot, cursor_reply->yhot, pixels);
free(cursor_reply);
}
if (cursor->width > STREAM_MSG_CURSOR_SET_MAX_WIDTH ||
cursor->height > STREAM_MSG_CURSOR_SET_MAX_HEIGHT) {
::syslog(LOG_WARNING, "cursor updater thread: ignoring cursor: too big %ux%u",
cursor->width, cursor->height);
continue;
}
last_serial = cursor->cursor_serial;
// the X11 cursor data may be in a wrong format, copy them to an uint32_t array
size_t pixcount = cursor->width * cursor->height;
std::vector<uint32_t> pixels;
pixels.reserve(pixcount);
for (size_t i = 0; i < pixcount; ++i) {
pixels.push_back(cursor->pixels[i]);
}
stream_port->send<CursorMessage>(cursor->width, cursor->height,
cursor->xhot, cursor->yhot, pixels);
} catch (const std::exception &e) {
::syslog(LOG_ERR, "Error in cursor updater thread: %s", e.what());
sleep(1); // rate-limit the error
......
......@@ -9,7 +9,7 @@
#include "stream-port.hpp"
#include <X11/Xlib.h>
#include <xcb/xfixes.h>
namespace spice {
......@@ -24,8 +24,8 @@ public:
private:
StreamPort *stream_port;
Display *display; // the X11 display
int xfixes_event_base; // event number for the XFixes events
xcb_connection_t* con; // connection to X11
uint32_t xfixes_event_base; // event number for the XFixes events
};
}} // namespace spice::streaming_agent
......@@ -40,7 +40,7 @@ agent_cpp_args = [
]
agent_link_args = global_link_args
agent_deps = spice_common_deps
foreach dep : ['libjpeg', 'libdrm', 'x11', 'xfixes', 'xrandr']
foreach dep : ['libjpeg', 'libdrm', 'x11', 'xcb', 'xcb-xfixes', 'xrandr']
agent_deps += dependency(dep)
endforeach
agent_deps += cc.find_library('dl', required : false)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment