Merge pull request #1368 from ascent12/x11_backend

X11 backend improvements
master
emersion 6 years ago committed by GitHub
commit df7d4a71fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -62,12 +62,12 @@ If you choose to enable X11 support:
* xcb * xcb
* xcb-composite * xcb-composite
* xcb-xfixes * xcb-xfixes
* xcb-xinput
* xcb-image * xcb-image
* xcb-render * xcb-render
* x11-xcb * x11-xcb
* xcb-errors (optional, for improved error reporting) * xcb-errors (optional, for improved error reporting)
* x11-icccm (optional, for improved Xwayland introspection) * x11-icccm (optional, for improved Xwayland introspection)
* xcb-xkb (optional, for improved keyboard handling on the X11 backend)
Run these commands: Run these commands:

@ -1,25 +1,29 @@
#define _POSIX_C_SOURCE 200112L #define _POSIX_C_SOURCE 200112L
#include <assert.h> #include <assert.h>
#include <limits.h> #include <limits.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include <wlr/config.h>
#include <X11/Xlib-xcb.h>
#include <wayland-server.h> #include <wayland-server.h>
#include <xcb/xcb.h>
#include <xcb/xfixes.h>
#include <xcb/xinput.h>
#include <wlr/backend/interface.h> #include <wlr/backend/interface.h>
#include <wlr/backend/x11.h> #include <wlr/backend/x11.h>
#include <wlr/config.h>
#include <wlr/interfaces/wlr_input_device.h> #include <wlr/interfaces/wlr_input_device.h>
#include <wlr/interfaces/wlr_keyboard.h> #include <wlr/interfaces/wlr_keyboard.h>
#include <wlr/interfaces/wlr_pointer.h> #include <wlr/interfaces/wlr_pointer.h>
#include <wlr/render/egl.h> #include <wlr/render/egl.h>
#include <wlr/render/gles2.h> #include <wlr/render/wlr_renderer.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include <X11/Xlib-xcb.h>
#include <xcb/xcb.h>
#if WLR_HAS_XCB_XKB
#include <xcb/xkb.h>
#endif
#include "backend/x11.h" #include "backend/x11.h"
#include "util/signal.h" #include "util/signal.h"
@ -36,8 +40,6 @@ struct wlr_x11_output *get_x11_output_from_window_id(
static void handle_x11_event(struct wlr_x11_backend *x11, static void handle_x11_event(struct wlr_x11_backend *x11,
xcb_generic_event_t *event) { xcb_generic_event_t *event) {
handle_x11_input_event(x11, event);
switch (event->response_type & XCB_EVENT_RESPONSE_TYPE_MASK) { switch (event->response_type & XCB_EVENT_RESPONSE_TYPE_MASK) {
case XCB_EXPOSE: { case XCB_EXPOSE: {
xcb_expose_event_t *ev = (xcb_expose_event_t *)event; xcb_expose_event_t *ev = (xcb_expose_event_t *)event;
@ -69,6 +71,12 @@ static void handle_x11_event(struct wlr_x11_backend *x11,
} }
break; break;
} }
case XCB_GE_GENERIC: {
xcb_ge_generic_event_t *ev = (xcb_ge_generic_event_t *)event;
if (ev->extension == x11->xinput_opcode) {
handle_x11_xinput_event(x11, ev);
}
}
} }
} }
@ -81,7 +89,7 @@ static int x11_event(int fd, uint32_t mask, void *data) {
} }
xcb_generic_event_t *e; xcb_generic_event_t *e;
while ((e = xcb_poll_for_event(x11->xcb_conn))) { while ((e = xcb_poll_for_event(x11->xcb))) {
handle_x11_event(x11, e); handle_x11_event(x11, e);
free(e); free(e);
} }
@ -99,83 +107,6 @@ static bool backend_start(struct wlr_backend *backend) {
struct wlr_x11_backend *x11 = get_x11_backend_from_backend(backend); struct wlr_x11_backend *x11 = get_x11_backend_from_backend(backend);
x11->started = true; x11->started = true;
struct {
const char *name;
xcb_intern_atom_cookie_t cookie;
xcb_atom_t *atom;
} atom[] = {
{
.name = "WM_PROTOCOLS",
.atom = &x11->atoms.wm_protocols,
},
{
.name = "WM_DELETE_WINDOW",
.atom = &x11->atoms.wm_delete_window,
},
{
.name = "_NET_WM_NAME",
.atom = &x11->atoms.net_wm_name,
},
{
.name = "UTF8_STRING",
.atom = &x11->atoms.utf8_string,
},
};
for (size_t i = 0; i < sizeof(atom) / sizeof(atom[0]); ++i) {
atom[i].cookie = xcb_intern_atom(x11->xcb_conn,
true, strlen(atom[i].name), atom[i].name);
}
for (size_t i = 0; i < sizeof(atom) / sizeof(atom[0]); ++i) {
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(
x11->xcb_conn, atom[i].cookie, NULL);
if (reply) {
*atom[i].atom = reply->atom;
free(reply);
} else {
*atom[i].atom = XCB_ATOM_NONE;
}
}
// create a blank cursor
xcb_pixmap_t pix = xcb_generate_id(x11->xcb_conn);
xcb_create_pixmap(x11->xcb_conn, 1, pix, x11->screen->root, 1, 1);
x11->cursor = xcb_generate_id(x11->xcb_conn);
xcb_create_cursor(x11->xcb_conn, x11->cursor, pix, pix, 0, 0, 0, 0, 0, 0,
0, 0);
xcb_free_pixmap(x11->xcb_conn, pix);
#if WLR_HAS_XCB_XKB
const xcb_query_extension_reply_t *reply =
xcb_get_extension_data(x11->xcb_conn, &xcb_xkb_id);
if (reply != NULL && reply->present) {
x11->xkb_base_event = reply->first_event;
x11->xkb_base_error = reply->first_error;
xcb_xkb_use_extension_cookie_t cookie = xcb_xkb_use_extension(
x11->xcb_conn, XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION);
xcb_xkb_use_extension_reply_t *reply =
xcb_xkb_use_extension_reply(x11->xcb_conn, cookie, NULL);
if (reply != NULL && reply->supported) {
x11->xkb_supported = true;
xcb_xkb_select_events(x11->xcb_conn,
XCB_XKB_ID_USE_CORE_KBD,
XCB_XKB_EVENT_TYPE_STATE_NOTIFY,
0,
XCB_XKB_EVENT_TYPE_STATE_NOTIFY,
0,
0,
0);
free(reply);
}
}
#endif
wlr_signal_emit_safe(&x11->backend.events.new_input, &x11->keyboard_dev); wlr_signal_emit_safe(&x11->backend.events.new_input, &x11->keyboard_dev);
for (size_t i = 0; i < x11->requested_outputs; ++i) { for (size_t i = 0; i < x11->requested_outputs; ++i) {
@ -209,9 +140,6 @@ static void backend_destroy(struct wlr_backend *backend) {
wlr_renderer_destroy(x11->renderer); wlr_renderer_destroy(x11->renderer);
wlr_egl_finish(&x11->egl); wlr_egl_finish(&x11->egl);
if (x11->cursor) {
xcb_free_cursor(x11->xcb_conn, x11->cursor);
}
if (x11->xlib_conn) { if (x11->xlib_conn) {
XCloseDisplay(x11->xlib_conn); XCloseDisplay(x11->xlib_conn);
} }
@ -258,15 +186,82 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display,
goto error_x11; goto error_x11;
} }
x11->xcb_conn = XGetXCBConnection(x11->xlib_conn); x11->xcb = XGetXCBConnection(x11->xlib_conn);
if (!x11->xcb_conn || xcb_connection_has_error(x11->xcb_conn)) { if (!x11->xcb || xcb_connection_has_error(x11->xcb)) {
wlr_log(WLR_ERROR, "Failed to open xcb connection"); wlr_log(WLR_ERROR, "Failed to open xcb connection");
goto error_display; goto error_display;
} }
XSetEventQueueOwner(x11->xlib_conn, XCBOwnsEventQueue); XSetEventQueueOwner(x11->xlib_conn, XCBOwnsEventQueue);
int fd = xcb_get_file_descriptor(x11->xcb_conn); struct {
const char *name;
xcb_intern_atom_cookie_t cookie;
xcb_atom_t *atom;
} atom[] = {
{ .name = "WM_PROTOCOLS", .atom = &x11->atoms.wm_protocols },
{ .name = "WM_DELETE_WINDOW", .atom = &x11->atoms.wm_delete_window },
{ .name = "_NET_WM_NAME", .atom = &x11->atoms.net_wm_name },
{ .name = "UTF8_STRING", .atom = &x11->atoms.utf8_string },
};
for (size_t i = 0; i < sizeof(atom) / sizeof(atom[0]); ++i) {
atom[i].cookie = xcb_intern_atom(x11->xcb,
true, strlen(atom[i].name), atom[i].name);
}
for (size_t i = 0; i < sizeof(atom) / sizeof(atom[0]); ++i) {
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(
x11->xcb, atom[i].cookie, NULL);
if (reply) {
*atom[i].atom = reply->atom;
free(reply);
} else {
*atom[i].atom = XCB_ATOM_NONE;
}
}
const xcb_query_extension_reply_t *ext;
ext = xcb_get_extension_data(x11->xcb, &xcb_xfixes_id);
if (!ext || !ext->present) {
wlr_log(WLR_ERROR, "X11 does not support Xfixes extension");
goto error_display;
}
xcb_xfixes_query_version_cookie_t fixes_cookie =
xcb_xfixes_query_version(x11->xcb, 4, 0);
xcb_xfixes_query_version_reply_t *fixes_reply =
xcb_xfixes_query_version_reply(x11->xcb, fixes_cookie, NULL);
if (!fixes_reply || fixes_reply->major_version < 4) {
wlr_log(WLR_ERROR, "X11 does not support required Xfixes version");
free(fixes_reply);
goto error_display;
}
free(fixes_reply);
ext = xcb_get_extension_data(x11->xcb, &xcb_input_id);
if (!ext || !ext->present) {
wlr_log(WLR_ERROR, "X11 does not support Xinput extension");
goto error_display;
}
x11->xinput_opcode = ext->major_opcode;
xcb_input_xi_query_version_cookie_t xi_cookie =
xcb_input_xi_query_version(x11->xcb, 2, 0);
xcb_input_xi_query_version_reply_t *xi_reply =
xcb_input_xi_query_version_reply(x11->xcb, xi_cookie, NULL);
if (!xi_reply || xi_reply->major_version < 2) {
wlr_log(WLR_ERROR, "X11 does not support required Xinput version");
free(xi_reply);
goto error_display;
}
free(xi_reply);
int fd = xcb_get_file_descriptor(x11->xcb);
struct wl_event_loop *ev = wl_display_get_event_loop(display); struct wl_event_loop *ev = wl_display_get_event_loop(display);
uint32_t events = WL_EVENT_READABLE | WL_EVENT_ERROR | WL_EVENT_HANGUP; uint32_t events = WL_EVENT_READABLE | WL_EVENT_ERROR | WL_EVENT_HANGUP;
x11->event_source = wl_event_loop_add_fd(ev, fd, events, x11_event, x11); x11->event_source = wl_event_loop_add_fd(ev, fd, events, x11_event, x11);
@ -276,7 +271,7 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display,
} }
wl_event_source_check(x11->event_source); wl_event_source_check(x11->event_source);
x11->screen = xcb_setup_roots_iterator(xcb_get_setup(x11->xcb_conn)).data; x11->screen = xcb_setup_roots_iterator(xcb_get_setup(x11->xcb)).data;
if (!create_renderer_func) { if (!create_renderer_func) {
create_renderer_func = wlr_renderer_autocreate; create_renderer_func = wlr_renderer_autocreate;

@ -1,140 +1,201 @@
#include <stdlib.h> #include <stdlib.h>
#include <wlr/config.h> #include <wlr/config.h>
#include <wlr/interfaces/wlr_input_device.h>
#include <wlr/interfaces/wlr_keyboard.h>
#include <wlr/interfaces/wlr_pointer.h>
#include <wlr/util/log.h>
#include <xcb/xcb.h>
#ifdef __linux__ #ifdef __linux__
#include <linux/input-event-codes.h> #include <linux/input-event-codes.h>
#elif __FreeBSD__ #elif __FreeBSD__
#include <dev/evdev/input-event-codes.h> #include <dev/evdev/input-event-codes.h>
#endif #endif
#if WLR_HAS_XCB_XKB
#include <xcb/xkb.h> #include <xcb/xcb.h>
#endif #include <xcb/xfixes.h>
#include <xcb/xinput.h>
#include <wlr/interfaces/wlr_input_device.h>
#include <wlr/interfaces/wlr_keyboard.h>
#include <wlr/interfaces/wlr_pointer.h>
#include <wlr/util/log.h>
#include "backend/x11.h" #include "backend/x11.h"
#include "util/signal.h" #include "util/signal.h"
static uint32_t xcb_button_to_wl(uint32_t button) { static void send_key_event(struct wlr_x11_backend *x11, uint32_t key,
switch (button) { enum wlr_key_state st, xcb_timestamp_t time) {
case XCB_BUTTON_INDEX_1: return BTN_LEFT; struct wlr_event_keyboard_key ev = {
case XCB_BUTTON_INDEX_2: return BTN_MIDDLE; .time_msec = time,
case XCB_BUTTON_INDEX_3: return BTN_RIGHT; .keycode = key,
// XXX: I'm not sure the scroll-wheel direction is right .state = st,
case XCB_BUTTON_INDEX_4: return BTN_GEAR_UP; .update_state = true,
case XCB_BUTTON_INDEX_5: return BTN_GEAR_DOWN; };
default: return 0; wlr_keyboard_notify_key(&x11->keyboard, &ev);
}
} }
static void x11_handle_pointer_position(struct wlr_x11_output *output, static void send_button_event(struct wlr_x11_output *output, uint32_t key,
int16_t x, int16_t y, xcb_timestamp_t time) { enum wlr_button_state st, xcb_timestamp_t time) {
struct wlr_x11_backend *x11 = output->x11; struct wlr_event_pointer_button ev = {
struct wlr_output *wlr_output = &output->wlr_output;
struct wlr_event_pointer_motion_absolute event = {
.device = &output->pointer_dev, .device = &output->pointer_dev,
.time_msec = time, .time_msec = time,
.x = (double)x / wlr_output->width, .button = key,
.y = (double)y / wlr_output->height, .state = st,
}; };
wlr_signal_emit_safe(&output->pointer.events.motion_absolute, &event); wlr_signal_emit_safe(&output->pointer.events.button, &ev);
}
x11->time = time; static void send_axis_event(struct wlr_x11_output *output, int32_t delta,
xcb_timestamp_t time) {
struct wlr_event_pointer_axis ev = {
.device = &output->pointer_dev,
.time_msec = time,
.source = WLR_AXIS_SOURCE_WHEEL,
.orientation = WLR_AXIS_ORIENTATION_VERTICAL,
// 15 is a typical value libinput sends for one scroll
.delta = delta * 15,
.delta_discrete = delta,
};
wlr_signal_emit_safe(&output->pointer.events.axis, &ev);
} }
void handle_x11_input_event(struct wlr_x11_backend *x11, static void send_pointer_position_event(struct wlr_x11_output *output,
xcb_generic_event_t *event) { int16_t x, int16_t y, xcb_timestamp_t time) {
switch (event->response_type & XCB_EVENT_RESPONSE_TYPE_MASK) { struct wlr_event_pointer_motion_absolute ev = {
case XCB_KEY_PRESS: .device = &output->pointer_dev,
case XCB_KEY_RELEASE: { .time_msec = time,
xcb_key_press_event_t *ev = (xcb_key_press_event_t *)event; .x = (double)x / output->wlr_output.width,
struct wlr_event_keyboard_key key = { .y = (double)y / output->wlr_output.height,
.time_msec = ev->time,
.keycode = ev->detail - 8,
.state = event->response_type == XCB_KEY_PRESS ?
WLR_KEY_PRESSED : WLR_KEY_RELEASED,
.update_state = true,
}; };
wlr_signal_emit_safe(&output->pointer.events.motion_absolute, &ev);
}
void handle_x11_xinput_event(struct wlr_x11_backend *x11,
xcb_ge_generic_event_t *event) {
struct wlr_x11_output *output;
switch (event->event_type) {
case XCB_INPUT_KEY_PRESS: {
xcb_input_key_press_event_t *ev =
(xcb_input_key_press_event_t *)event;
// TODO use xcb-xkb for more precise modifiers state? wlr_keyboard_notify_modifiers(&x11->keyboard, ev->mods.base,
wlr_keyboard_notify_key(&x11->keyboard, &key); ev->mods.latched, ev->mods.locked, ev->mods.effective);
send_key_event(x11, ev->detail - 8, WLR_KEY_PRESSED, ev->time);
x11->time = ev->time; x11->time = ev->time;
break;
}
case XCB_INPUT_KEY_RELEASE: {
xcb_input_key_release_event_t *ev =
(xcb_input_key_release_event_t *)event;
wlr_keyboard_notify_modifiers(&x11->keyboard, ev->mods.base,
ev->mods.latched, ev->mods.locked, ev->mods.effective);
send_key_event(x11, ev->detail - 8, WLR_KEY_RELEASED, ev->time);
x11->time = ev->time;
break;
}
case XCB_INPUT_BUTTON_PRESS: {
xcb_input_button_press_event_t *ev =
(xcb_input_button_press_event_t *)event;
output = get_x11_output_from_window_id(x11, ev->event);
if (!output) {
return; return;
} }
case XCB_BUTTON_PRESS: {
xcb_button_press_event_t *ev = (xcb_button_press_event_t *)event;
struct wlr_x11_output *output = switch (ev->detail) {
get_x11_output_from_window_id(x11, ev->event); case XCB_BUTTON_INDEX_1:
if (output == NULL) { send_button_event(output, BTN_LEFT, WLR_BUTTON_PRESSED,
ev->time);
break;
case XCB_BUTTON_INDEX_2:
send_button_event(output, BTN_MIDDLE, WLR_BUTTON_PRESSED,
ev->time);
break;
case XCB_BUTTON_INDEX_3:
send_button_event(output, BTN_RIGHT, WLR_BUTTON_PRESSED,
ev->time);
break;
case XCB_BUTTON_INDEX_4:
send_axis_event(output, -1, ev->time);
break;
case XCB_BUTTON_INDEX_5:
send_axis_event(output, 1, ev->time);
break; break;
} }
if (ev->detail == XCB_BUTTON_INDEX_4 ||
ev->detail == XCB_BUTTON_INDEX_5) {
int32_t delta_discrete = ev->detail == XCB_BUTTON_INDEX_4 ? -1 : 1;
struct wlr_event_pointer_axis axis = {
.device = &output->pointer_dev,
.time_msec = ev->time,
.source = WLR_AXIS_SOURCE_WHEEL,
.orientation = WLR_AXIS_ORIENTATION_VERTICAL,
// 15 is a typical value libinput sends for one scroll
.delta = delta_discrete * 15,
.delta_discrete = delta_discrete,
};
wlr_signal_emit_safe(&output->pointer.events.axis, &axis);
x11->time = ev->time; x11->time = ev->time;
break; break;
} }
case XCB_INPUT_BUTTON_RELEASE: {
xcb_input_button_release_event_t *ev =
(xcb_input_button_release_event_t *)event;
output = get_x11_output_from_window_id(x11, ev->event);
if (!output) {
return;
} }
/* fallthrough */
case XCB_BUTTON_RELEASE: {
xcb_button_press_event_t *ev = (xcb_button_press_event_t *)event;
struct wlr_x11_output *output = switch (ev->detail) {
get_x11_output_from_window_id(x11, ev->event); case XCB_BUTTON_INDEX_1:
if (output == NULL) { send_button_event(output, BTN_LEFT, WLR_BUTTON_RELEASED,
ev->time);
break;
case XCB_BUTTON_INDEX_2:
send_button_event(output, BTN_MIDDLE, WLR_BUTTON_RELEASED,
ev->time);
break;
case XCB_BUTTON_INDEX_3:
send_button_event(output, BTN_RIGHT, WLR_BUTTON_RELEASED,
ev->time);
break; break;
} }
if (ev->detail != XCB_BUTTON_INDEX_4 && x11->time = ev->time;
ev->detail != XCB_BUTTON_INDEX_5) { break;
struct wlr_event_pointer_button button = { }
.device = &output->pointer_dev, case XCB_INPUT_MOTION: {
.time_msec = ev->time, xcb_input_motion_event_t *ev = (xcb_input_motion_event_t *)event;
.button = xcb_button_to_wl(ev->detail),
.state = event->response_type == XCB_BUTTON_PRESS ?
WLR_BUTTON_PRESSED : WLR_BUTTON_RELEASED,
};
wlr_signal_emit_safe(&output->pointer.events.button, &button); output = get_x11_output_from_window_id(x11, ev->event);
if (!output) {
return;
} }
send_pointer_position_event(output, ev->event_x >> 16,
ev->event_y >> 16, ev->time);
x11->time = ev->time; x11->time = ev->time;
break;
}
case XCB_INPUT_ENTER: {
xcb_input_enter_event_t *ev = (xcb_input_enter_event_t *)event;
output = get_x11_output_from_window_id(x11, ev->event);
if (!output) {
return; return;
} }
case XCB_MOTION_NOTIFY: {
xcb_motion_notify_event_t *ev = (xcb_motion_notify_event_t *)event;
struct wlr_x11_output *output = if (!output->cursor_hidden) {
get_x11_output_from_window_id(x11, ev->event); xcb_xfixes_hide_cursor(x11->xcb, output->win);
if (output != NULL) { xcb_flush(x11->xcb);
x11_handle_pointer_position(output, ev->event_x, ev->event_y, ev->time); output->cursor_hidden = true;
} }
return; break;
} }
default: case XCB_INPUT_LEAVE: {
#if WLR_HAS_XCB_XKB xcb_input_leave_event_t *ev = (xcb_input_leave_event_t *)event;
if (x11->xkb_supported && event->response_type == x11->xkb_base_event) {
xcb_xkb_state_notify_event_t *ev = output = get_x11_output_from_window_id(x11, ev->event);
(xcb_xkb_state_notify_event_t *)event; if (!output) {
wlr_keyboard_notify_modifiers(&x11->keyboard, ev->baseMods,
ev->latchedMods, ev->lockedMods, ev->lockedGroup);
return; return;
} }
#endif
if (output->cursor_hidden) {
xcb_xfixes_show_cursor(x11->xcb, output->win);
xcb_flush(x11->xcb);
output->cursor_hidden = false;
}
break; break;
} }
}
} }
static void input_device_destroy(struct wlr_input_device *wlr_device) { static void input_device_destroy(struct wlr_input_device *wlr_device) {
@ -166,14 +227,14 @@ void update_x11_pointer_position(struct wlr_x11_output *output,
struct wlr_x11_backend *x11 = output->x11; struct wlr_x11_backend *x11 = output->x11;
xcb_query_pointer_cookie_t cookie = xcb_query_pointer_cookie_t cookie =
xcb_query_pointer(x11->xcb_conn, output->win); xcb_query_pointer(x11->xcb, output->win);
xcb_query_pointer_reply_t *reply = xcb_query_pointer_reply_t *reply =
xcb_query_pointer_reply(x11->xcb_conn, cookie, NULL); xcb_query_pointer_reply(x11->xcb, cookie, NULL);
if (!reply) { if (!reply) {
return; return;
} }
x11_handle_pointer_position(output, reply->win_x, reply->win_y, time); send_pointer_position_event(output, reply->win_x, reply->win_y, time);
free(reply); free(reply);
} }

@ -1,10 +1,9 @@
x11_libs = [] x11_libs = []
x11_required = [ x11_required = [
'xcb',
'x11-xcb', 'x11-xcb',
] 'xcb',
x11_optional = [ 'xcb-xinput',
'xcb-xkb', 'xcb-xfixes',
] ]
foreach lib : x11_required foreach lib : x11_required
@ -16,14 +15,6 @@ foreach lib : x11_required
x11_libs += dep x11_libs += dep
endforeach endforeach
foreach lib : x11_optional
dep = dependency(lib, required: get_option(lib))
if dep.found()
x11_libs += dep
conf_data.set10('WLR_HAS_' + lib.underscorify().to_upper(), true)
endif
endforeach
lib_wlr_backend_x11 = static_library( lib_wlr_backend_x11 = static_library(
'wlr_backend_x11', 'wlr_backend_x11',
files( files(

@ -1,10 +1,16 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <xcb/xcb.h>
#include <xcb/xinput.h>
#include <wlr/interfaces/wlr_output.h> #include <wlr/interfaces/wlr_output.h>
#include <wlr/interfaces/wlr_pointer.h> #include <wlr/interfaces/wlr_pointer.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "backend/x11.h" #include "backend/x11.h"
#include "util/signal.h" #include "util/signal.h"
@ -16,8 +22,8 @@ static int signal_frame(void *data) {
} }
static void parse_xcb_setup(struct wlr_output *output, static void parse_xcb_setup(struct wlr_output *output,
xcb_connection_t *xcb_conn) { xcb_connection_t *xcb) {
const xcb_setup_t *xcb_setup = xcb_get_setup(xcb_conn); const xcb_setup_t *xcb_setup = xcb_get_setup(xcb);
snprintf(output->make, sizeof(output->make), "%.*s", snprintf(output->make, sizeof(output->make), "%.*s",
xcb_setup_vendor_length(xcb_setup), xcb_setup_vendor_length(xcb_setup),
@ -55,11 +61,11 @@ static bool output_set_custom_mode(struct wlr_output *wlr_output,
const uint32_t values[] = { width, height }; const uint32_t values[] = { width, height };
xcb_void_cookie_t cookie = xcb_configure_window_checked( xcb_void_cookie_t cookie = xcb_configure_window_checked(
x11->xcb_conn, output->win, x11->xcb, output->win,
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values);
xcb_generic_error_t *error; xcb_generic_error_t *error;
if ((error = xcb_request_check(x11->xcb_conn, cookie))) { if ((error = xcb_request_check(x11->xcb, cookie))) {
wlr_log(WLR_ERROR, "Could not set window size to %dx%d\n", wlr_log(WLR_ERROR, "Could not set window size to %dx%d\n",
width, height); width, height);
free(error); free(error);
@ -84,8 +90,8 @@ static void output_destroy(struct wlr_output *wlr_output) {
wl_list_remove(&output->link); wl_list_remove(&output->link);
wl_event_source_remove(output->frame_timer); wl_event_source_remove(output->frame_timer);
wlr_egl_destroy_surface(&x11->egl, output->surf); wlr_egl_destroy_surface(&x11->egl, output->surf);
xcb_destroy_window(x11->xcb_conn, output->win); xcb_destroy_window(x11->xcb, output->win);
xcb_flush(x11->xcb_conn); xcb_flush(x11->xcb);
free(output); free(output);
} }
@ -142,21 +148,32 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) {
snprintf(wlr_output->name, sizeof(wlr_output->name), "X11-%d", snprintf(wlr_output->name, sizeof(wlr_output->name), "X11-%d",
wl_list_length(&x11->outputs) + 1); wl_list_length(&x11->outputs) + 1);
parse_xcb_setup(wlr_output, x11->xcb_conn); parse_xcb_setup(wlr_output, x11->xcb);
uint32_t mask = XCB_CW_EVENT_MASK; uint32_t mask = XCB_CW_EVENT_MASK;
uint32_t values[] = { uint32_t values[] = {
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY
XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE |
XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_POINTER_MOTION |
XCB_EVENT_MASK_STRUCTURE_NOTIFY
}; };
output->win = xcb_generate_id(x11->xcb_conn); output->win = xcb_generate_id(x11->xcb);
xcb_create_window(x11->xcb_conn, XCB_COPY_FROM_PARENT, output->win, xcb_create_window(x11->xcb, XCB_COPY_FROM_PARENT, output->win,
x11->screen->root, 0, 0, wlr_output->width, wlr_output->height, 1, x11->screen->root, 0, 0, wlr_output->width, wlr_output->height, 1,
XCB_WINDOW_CLASS_INPUT_OUTPUT, x11->screen->root_visual, mask, values); XCB_WINDOW_CLASS_INPUT_OUTPUT, x11->screen->root_visual, mask, values);
struct {
xcb_input_event_mask_t head;
xcb_input_xi_event_mask_t mask;
} xinput_mask = {
.head = { .deviceid = XCB_INPUT_DEVICE_ALL_MASTER, .mask_len = 1 },
.mask = XCB_INPUT_XI_EVENT_MASK_KEY_PRESS |
XCB_INPUT_XI_EVENT_MASK_KEY_RELEASE |
XCB_INPUT_XI_EVENT_MASK_BUTTON_PRESS |
XCB_INPUT_XI_EVENT_MASK_BUTTON_RELEASE |
XCB_INPUT_XI_EVENT_MASK_MOTION |
XCB_INPUT_XI_EVENT_MASK_ENTER |
XCB_INPUT_XI_EVENT_MASK_LEAVE,
};
xcb_input_xi_select_events(x11->xcb, output->win, 1, &xinput_mask.head);
output->surf = wlr_egl_create_surface(&x11->egl, &output->win); output->surf = wlr_egl_create_surface(&x11->egl, &output->win);
if (!output->surf) { if (!output->surf) {
wlr_log(WLR_ERROR, "Failed to create EGL surface"); wlr_log(WLR_ERROR, "Failed to create EGL surface");
@ -164,23 +181,19 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) {
return NULL; return NULL;
} }
xcb_change_property(x11->xcb_conn, XCB_PROP_MODE_REPLACE, output->win, xcb_change_property(x11->xcb, XCB_PROP_MODE_REPLACE, output->win,
x11->atoms.wm_protocols, XCB_ATOM_ATOM, 32, 1, x11->atoms.wm_protocols, XCB_ATOM_ATOM, 32, 1,
&x11->atoms.wm_delete_window); &x11->atoms.wm_delete_window);
char title[32]; char title[32];
if (snprintf(title, sizeof(title), "wlroots - %s", wlr_output->name)) { if (snprintf(title, sizeof(title), "wlroots - %s", wlr_output->name)) {
xcb_change_property(x11->xcb_conn, XCB_PROP_MODE_REPLACE, output->win, xcb_change_property(x11->xcb, XCB_PROP_MODE_REPLACE, output->win,
x11->atoms.net_wm_name, x11->atoms.utf8_string, 8, x11->atoms.net_wm_name, x11->atoms.utf8_string, 8,
strlen(title), title); strlen(title), title);
} }
uint32_t cursor_values[] = { x11->cursor }; xcb_map_window(x11->xcb, output->win);
xcb_change_window_attributes(x11->xcb_conn, output->win, XCB_CW_CURSOR, xcb_flush(x11->xcb);
cursor_values);
xcb_map_window(x11->xcb_conn, output->win);
xcb_flush(x11->xcb_conn);
struct wl_event_loop *ev = wl_display_get_event_loop(x11->wl_display); struct wl_event_loop *ev = wl_display_get_event_loop(x11->wl_display);
output->frame_timer = wl_event_loop_add_timer(ev, signal_frame, output); output->frame_timer = wl_event_loop_add_timer(ev, signal_frame, output);

@ -2,14 +2,17 @@
#define BACKEND_X11_H #define BACKEND_X11_H
#include <stdbool.h> #include <stdbool.h>
#include <X11/Xlib-xcb.h>
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/config.h> #include <xcb/xcb.h>
#include <wlr/backend/x11.h> #include <wlr/backend/x11.h>
#include <wlr/config.h>
#include <wlr/interfaces/wlr_input_device.h> #include <wlr/interfaces/wlr_input_device.h>
#include <wlr/interfaces/wlr_output.h> #include <wlr/interfaces/wlr_output.h>
#include <wlr/render/egl.h> #include <wlr/render/egl.h>
#include <X11/Xlib-xcb.h> #include <wlr/render/wlr_renderer.h>
#include <xcb/xcb.h>
#define XCB_EVENT_RESPONSE_TYPE_MASK 0x7f #define XCB_EVENT_RESPONSE_TYPE_MASK 0x7f
@ -30,6 +33,8 @@ struct wlr_x11_output {
struct wl_event_source *frame_timer; struct wl_event_source *frame_timer;
int frame_delay; int frame_delay;
bool cursor_hidden;
}; };
struct wlr_x11_backend { struct wlr_x11_backend {
@ -38,7 +43,7 @@ struct wlr_x11_backend {
bool started; bool started;
Display *xlib_conn; Display *xlib_conn;
xcb_connection_t *xcb_conn; xcb_connection_t *xcb;
xcb_screen_t *screen; xcb_screen_t *screen;
size_t requested_outputs; size_t requested_outputs;
@ -61,14 +66,7 @@ struct wlr_x11_backend {
// The time we last received an event // The time we last received an event
xcb_timestamp_t time; xcb_timestamp_t time;
// A blank cursor uint8_t xinput_opcode;
xcb_cursor_t cursor;
#if WLR_HAS_XCB_XKB
bool xkb_supported;
uint8_t xkb_base_event;
uint8_t xkb_base_error;
#endif
struct wl_listener display_destroy; struct wl_listener display_destroy;
}; };
@ -82,8 +80,8 @@ extern const struct wlr_keyboard_impl keyboard_impl;
extern const struct wlr_pointer_impl pointer_impl; extern const struct wlr_pointer_impl pointer_impl;
extern const struct wlr_input_device_impl input_device_impl; extern const struct wlr_input_device_impl input_device_impl;
void handle_x11_input_event(struct wlr_x11_backend *x11, void handle_x11_xinput_event(struct wlr_x11_backend *x11,
xcb_generic_event_t *event); xcb_ge_generic_event_t *event);
void update_x11_pointer_position(struct wlr_x11_output *output, void update_x11_pointer_position(struct wlr_x11_output *output,
xcb_timestamp_t time); xcb_timestamp_t time);

@ -2,7 +2,9 @@
#define WLR_BACKEND_X11_H #define WLR_BACKEND_X11_H
#include <stdbool.h> #include <stdbool.h>
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/backend.h> #include <wlr/backend.h>
#include <wlr/types/wlr_input_device.h> #include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>

@ -12,6 +12,5 @@
#mesondefine WLR_HAS_XCB_ERRORS #mesondefine WLR_HAS_XCB_ERRORS
#mesondefine WLR_HAS_XCB_ICCCM #mesondefine WLR_HAS_XCB_ICCCM
#mesondefine WLR_HAS_XCB_XKB
#endif #endif

@ -35,7 +35,6 @@ conf_data.set10('WLR_HAS_X11_BACKEND', false)
conf_data.set10('WLR_HAS_XWAYLAND', false) conf_data.set10('WLR_HAS_XWAYLAND', false)
conf_data.set10('WLR_HAS_XCB_ERRORS', false) conf_data.set10('WLR_HAS_XCB_ERRORS', false)
conf_data.set10('WLR_HAS_XCB_ICCCM', false) conf_data.set10('WLR_HAS_XCB_ICCCM', false)
conf_data.set10('WLR_HAS_XCB_XKB', false)
wlr_inc = include_directories('.', 'include') wlr_inc = include_directories('.', 'include')

@ -3,7 +3,6 @@ option('logind', type: 'feature', value: 'auto', description: 'Enable support fo
option('logind-provider', type: 'combo', choices: ['systemd', 'elogind'], value: 'systemd', description: 'Provider of logind support library') option('logind-provider', type: 'combo', choices: ['systemd', 'elogind'], value: 'systemd', description: 'Provider of logind support library')
option('xcb-errors', type: 'feature', value: 'auto', description: 'Use xcb-errors util library') option('xcb-errors', type: 'feature', value: 'auto', description: 'Use xcb-errors util library')
option('xcb-icccm', type: 'feature', value: 'auto', description: 'Use xcb-icccm util library') option('xcb-icccm', type: 'feature', value: 'auto', description: 'Use xcb-icccm util library')
option('xcb-xkb', type: 'feature', value: 'auto', description: 'Use xcb-xkb util library')
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications') option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
option('x11-backend', type: 'feature', value: 'auto', description: 'Enable X11 backend') option('x11-backend', type: 'feature', value: 'auto', description: 'Enable X11 backend')
option('rootston', type: 'boolean', value: true, description: 'Build the rootston example compositor') option('rootston', type: 'boolean', value: true, description: 'Build the rootston example compositor')

Loading…
Cancel
Save