diff options
Diffstat (limited to 'xwayland')
-rw-r--r-- | xwayland/meson.build | 40 | ||||
-rw-r--r-- | xwayland/xwayland.c | 26 | ||||
-rw-r--r-- | xwayland/xwm.c | 129 |
3 files changed, 161 insertions, 34 deletions
diff --git a/xwayland/meson.build b/xwayland/meson.build index ec486f58..0bd88924 100644 --- a/xwayland/meson.build +++ b/xwayland/meson.build @@ -1,3 +1,32 @@ +xwayland_libs = [] +xwayland_required = [ + 'xcb', + 'xcb-composite', + 'xcb-render', + 'xcb-xfixes', +] +xwayland_optional = [ + 'xcb-errors', + 'xcb-icccm', +] + +foreach lib : xwayland_required + dep = dependency(lib, required: get_option('xwayland')) + if not dep.found() + subdir_done() + endif + + xwayland_libs += dep +endforeach + +foreach lib : xwayland_optional + dep = dependency(lib, required: get_option(lib)) + if dep.found() + xwayland_libs += dep + conf_data.set('WLR_HAS_' + lib.underscorify().to_upper(), true) + endif +endforeach + lib_wlr_xwayland = static_library( 'wlr_xwayland', files( @@ -12,14 +41,11 @@ lib_wlr_xwayland = static_library( include_directories: wlr_inc, dependencies: [ wayland_server, - xcb, - xcb_composite, - xcb_xfixes, - xcb_image, - xcb_render, - xcb_icccm, - xcb_errors, + xwayland_libs, xkbcommon, pixman, ], ) + +wlr_parts += lib_wlr_xwayland +conf_data.set('WLR_HAS_XWAYLAND', true) diff --git a/xwayland/xwayland.c b/xwayland/xwayland.c index 1068b942..fe09ea5e 100644 --- a/xwayland/xwayland.c +++ b/xwayland/xwayland.c @@ -74,6 +74,7 @@ static int fill_arg(char ***argv, const char *fmt, ...) { return len; } +_Noreturn static void exec_xwayland(struct wlr_xwayland *wlr_xwayland) { if (unset_cloexec(wlr_xwayland->x_fd[0]) || unset_cloexec(wlr_xwayland->x_fd[1]) || @@ -123,9 +124,26 @@ static void exec_xwayland(struct wlr_xwayland *wlr_xwayland) { wlr_xwayland->wl_fd[1], wlr_xwayland->display, wlr_xwayland->x_fd[0], wlr_xwayland->x_fd[1], wlr_xwayland->wm_fd[1]); - // TODO: close stdout/err depending on log level + // Closes stdout/stderr depending on log verbosity + enum wlr_log_importance verbosity = wlr_log_get_verbosity(); + int devnull = open("/dev/null", O_WRONLY | O_CREAT, 0666); + if (devnull < 0) { + wlr_log_errno(WLR_ERROR, "XWayland: failed to open /dev/null"); + _exit(EXIT_FAILURE); + } + if (verbosity < WLR_INFO) { + dup2(devnull, STDOUT_FILENO); + } + if (verbosity < WLR_ERROR) { + dup2(devnull, STDERR_FILENO); + } + // This returns if and only if the call fails execvp("Xwayland", argv); + + wlr_log_errno(WLR_ERROR, "failed to exec Xwayland"); + close(devnull); + _exit(EXIT_FAILURE); } static void xwayland_finish_server(struct wlr_xwayland *wlr_xwayland) { @@ -346,8 +364,6 @@ static bool xwayland_start_server(struct wlr_xwayland *wlr_xwayland) { sigprocmask(SIG_BLOCK, &sigset, NULL); if ((pid = fork()) == 0) { exec_xwayland(wlr_xwayland); - wlr_log_errno(WLR_ERROR, "failed to exec Xwayland"); - _exit(EXIT_FAILURE); } if (pid < 0) { wlr_log_errno(WLR_ERROR, "second fork failed"); @@ -390,6 +406,10 @@ static bool xwayland_start_server_lazy(struct wlr_xwayland *wlr_xwayland) { } void wlr_xwayland_destroy(struct wlr_xwayland *wlr_xwayland) { + if (!wlr_xwayland) { + return; + } + wlr_xwayland_set_seat(wlr_xwayland, NULL); xwayland_finish_server(wlr_xwayland); xwayland_finish_display(wlr_xwayland); diff --git a/xwayland/xwm.c b/xwayland/xwm.c index bee3a005..9c803543 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -24,6 +24,7 @@ const char *atom_map[ATOM_LAST] = { "WM_HINTS", "WM_NORMAL_HINTS", "WM_SIZE_HINTS", + "WM_WINDOW_ROLE", "_MOTIF_WM_HINTS", "UTF8_STRING", "WM_S0", @@ -39,6 +40,7 @@ const char *atom_map[ATOM_LAST] = { "_NET_WM_MOVERESIZE", "_NET_WM_NAME", "_NET_SUPPORTING_WM_CHECK", + "_NET_WM_STATE_MODAL", "_NET_WM_STATE_FULLSCREEN", "_NET_WM_STATE_MAXIMIZED_VERT", "_NET_WM_STATE_MAXIMIZED_HORZ", @@ -147,13 +149,17 @@ static struct wlr_xwayland_surface *xwayland_surface_create( wl_signal_init(&surface->events.request_resize); wl_signal_init(&surface->events.request_maximize); wl_signal_init(&surface->events.request_fullscreen); + wl_signal_init(&surface->events.request_activate); wl_signal_init(&surface->events.map); wl_signal_init(&surface->events.unmap); wl_signal_init(&surface->events.set_class); + wl_signal_init(&surface->events.set_role); wl_signal_init(&surface->events.set_title); wl_signal_init(&surface->events.set_parent); wl_signal_init(&surface->events.set_pid); wl_signal_init(&surface->events.set_window_type); + wl_signal_init(&surface->events.set_hints); + wl_signal_init(&surface->events.set_override_redirect); wl_signal_init(&surface->events.ping_timeout); xcb_get_geometry_reply_t *geometry_reply = @@ -240,8 +246,7 @@ static void xwm_send_focus_window(struct wlr_xwm *xwm, XCB_CONFIG_WINDOW_STACK_MODE, values); } - -void xwm_surface_activate(struct wlr_xwm *xwm, +static void xwm_surface_activate(struct wlr_xwm *xwm, struct wlr_xwayland_surface *xsurface) { if (xwm->focus_surface == xsurface || (xsurface && xsurface->override_redirect)) { @@ -267,6 +272,9 @@ static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { int i; i = 0; + if (xsurface->modal) { + property[i++] = xwm->atoms[_NET_WM_STATE_MODAL]; + } if (xsurface->fullscreen) { property[i++] = xwm->atoms[_NET_WM_STATE_FULLSCREEN]; } @@ -321,6 +329,7 @@ static void xwayland_surface_destroy( free(xsurface->title); free(xsurface->class); free(xsurface->instance); + free(xsurface->role); free(xsurface->window_type); free(xsurface->protocols); free(xsurface->hints); @@ -359,6 +368,28 @@ static void read_surface_class(struct wlr_xwm *xwm, wlr_signal_emit_safe(&surface->events.set_class, surface); } +static void read_surface_role(struct wlr_xwm *xwm, + struct wlr_xwayland_surface *xsurface, + xcb_get_property_reply_t *reply) { + if (reply->type != XCB_ATOM_STRING && + reply->type != xwm->atoms[UTF8_STRING]) { + return; + } + + size_t len = xcb_get_property_value_length(reply); + char *role = xcb_get_property_value(reply); + + free(xsurface->role); + if (len > 0) { + xsurface->role = strndup(role, len); + } else { + xsurface->role = NULL; + } + + wlr_log(WLR_DEBUG, "XCB_ATOM_WM_WINDOW_ROLE: %s", xsurface->role); + wlr_signal_emit_safe(&xsurface->events.set_role, xsurface); +} + static void read_surface_title(struct wlr_xwm *xwm, struct wlr_xwayland_surface *xsurface, xcb_get_property_reply_t *reply) { @@ -492,6 +523,7 @@ static void read_surface_hints(struct wlr_xwm *xwm, xsurface->hints_urgency = xcb_icccm_wm_hints_get_urgency(&hints); wlr_log(WLR_DEBUG, "WM_HINTS (%d)", reply->value_len); + wlr_signal_emit_safe(&xsurface->events.set_hints, xsurface); } #else static void read_surface_hints(struct wlr_xwm *xwm, @@ -573,7 +605,9 @@ static void read_surface_net_wm_state(struct wlr_xwm *xwm, xsurface->fullscreen = 0; xcb_atom_t *atom = xcb_get_property_value(reply); for (uint32_t i = 0; i < reply->value_len; i++) { - if (atom[i] == xwm->atoms[_NET_WM_STATE_FULLSCREEN]) { + if (atom[i] == xwm->atoms[_NET_WM_STATE_MODAL]) { + xsurface->modal = true; + } else if (atom[i] == xwm->atoms[_NET_WM_STATE_FULLSCREEN]) { xsurface->fullscreen = true; } else if (atom[i] == xwm->atoms[_NET_WM_STATE_MAXIMIZED_VERT]) { xsurface->maximized_vert = true; @@ -629,6 +663,8 @@ static void read_surface_property(struct wlr_xwm *xwm, read_surface_normal_hints(xwm, xsurface, reply); } else if (property == xwm->atoms[MOTIF_WM_HINTS]) { read_surface_motif_hints(xwm, xsurface, reply); + } else if (property == xwm->atoms[WM_WINDOW_ROLE]) { + read_surface_role(xwm, xsurface, reply); } else { char *prop_name = xwm_get_atom_name(xwm, property); wlr_log(WLR_DEBUG, "unhandled X11 property %u (%s) for window %u", @@ -652,9 +688,27 @@ static void xwayland_surface_role_commit(struct wlr_surface *wlr_surface) { } } +static void xwayland_surface_role_precommit(struct wlr_surface *wlr_surface) { + assert(wlr_surface->role == &xwayland_surface_role); + struct wlr_xwayland_surface *surface = wlr_surface->role_data; + if (surface == NULL) { + return; + } + + if (wlr_surface->pending.committed & WLR_SURFACE_STATE_BUFFER && + wlr_surface->pending.buffer_resource == NULL) { + // This is a NULL commit + if (surface->mapped) { + wlr_signal_emit_safe(&surface->events.unmap, surface); + surface->mapped = false; + } + } +} + static const struct wlr_surface_role xwayland_surface_role = { .name = "wlr_xwayland_surface", .commit = xwayland_surface_role_commit, + .precommit = xwayland_surface_role_precommit, }; static void handle_surface_destroy(struct wl_listener *listener, void *data) { @@ -764,9 +818,7 @@ static void xwm_handle_configure_request(struct wlr_xwm *xwm, static void xwm_handle_configure_notify(struct wlr_xwm *xwm, xcb_configure_notify_event_t *ev) { - struct wlr_xwayland_surface *xsurface = - lookup_surface(xwm, ev->window); - + struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->window); if (!xsurface) { return; } @@ -775,6 +827,11 @@ static void xwm_handle_configure_notify(struct wlr_xwm *xwm, xsurface->y = ev->y; xsurface->width = ev->width; xsurface->height = ev->height; + + if (xsurface->override_redirect != ev->override_redirect) { + xsurface->override_redirect = ev->override_redirect; + wlr_signal_emit_safe(&xsurface->events.set_override_redirect, xsurface); + } } #define ICCCM_WITHDRAWN_STATE 0 @@ -814,6 +871,15 @@ static void xwm_handle_map_request(struct wlr_xwm *xwm, static void xwm_handle_map_notify(struct wlr_xwm *xwm, xcb_map_notify_event_t *ev) { wlr_log(WLR_DEBUG, "XCB_MAP_NOTIFY (%u)", ev->window); + struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->window); + if (!xsurface) { + return; + } + + if (xsurface->override_redirect != ev->override_redirect) { + xsurface->override_redirect = ev->override_redirect; + wlr_signal_emit_safe(&xsurface->events.set_override_redirect, xsurface); + } } static void xwm_handle_unmap_notify(struct wlr_xwm *xwm, @@ -996,7 +1062,10 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, for (size_t i = 0; i < 2; ++i) { uint32_t property = client_message->data.data32[1 + i]; - if (property == xwm->atoms[_NET_WM_STATE_FULLSCREEN] && + if (property == xwm->atoms[_NET_WM_STATE_MODAL] && + update_state(action, &xsurface->modal)) { + xsurface_set_net_wm_state(xsurface); + } else if (property == xwm->atoms[_NET_WM_STATE_FULLSCREEN] && update_state(action, &xsurface->fullscreen)) { xsurface_set_net_wm_state(xsurface); } else if (property == xwm->atoms[_NET_WM_STATE_MAXIMIZED_VERT] && @@ -1055,6 +1124,15 @@ static void xwm_handle_wm_protocols_message(struct wlr_xwm *xwm, } } +static void xwm_handle_net_active_window_message(struct wlr_xwm *xwm, + xcb_client_message_event_t *ev) { + struct wlr_xwayland_surface *surface = lookup_surface(xwm, ev->window); + if (surface == NULL) { + return; + } + wlr_signal_emit_safe(&surface->events.request_activate, surface); +} + static void xwm_handle_client_message(struct wlr_xwm *xwm, xcb_client_message_event_t *ev) { wlr_log(WLR_DEBUG, "XCB_CLIENT_MESSAGE (%u)", ev->window); @@ -1067,6 +1145,8 @@ static void xwm_handle_client_message(struct wlr_xwm *xwm, xwm_handle_net_wm_moveresize_message(xwm, ev); } else if (ev->type == xwm->atoms[WM_PROTOCOLS]) { xwm_handle_wm_protocols_message(xwm, ev); + } else if (ev->type == xwm->atoms[_NET_ACTIVE_WINDOW]) { + xwm_handle_net_active_window_message(xwm, ev); } else if (!xwm_handle_selection_client_message(xwm, ev)) { char *type_name = xwm_get_atom_name(xwm, ev->type); wlr_log(WLR_DEBUG, "unhandled x11 client message %u (%s)", ev->type, @@ -1598,6 +1678,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland) { xwm->atoms[NET_WM_STATE], xwm->atoms[_NET_ACTIVE_WINDOW], xwm->atoms[_NET_WM_MOVERESIZE], + xwm->atoms[_NET_WM_STATE_MODAL], xwm->atoms[_NET_WM_STATE_FULLSCREEN], xwm->atoms[_NET_WM_STATE_MAXIMIZED_VERT], xwm->atoms[_NET_WM_STATE_MAXIMIZED_HORZ], @@ -1659,8 +1740,22 @@ bool xwm_atoms_contains(struct wlr_xwm *xwm, xcb_atom_t *atoms, return false; } -bool wlr_xwayland_surface_is_unmanaged( +void wlr_xwayland_surface_ping(struct wlr_xwayland_surface *surface) { + xcb_client_message_data_t data = { 0 }; + data.data32[0] = surface->xwm->atoms[_NET_WM_PING]; + data.data32[1] = XCB_CURRENT_TIME; + data.data32[2] = surface->window_id; + + xwm_send_wm_message(surface, &data, XCB_EVENT_MASK_NO_EVENT); + + wl_event_source_timer_update(surface->ping_timer, + surface->xwm->ping_timeout); + surface->pinging = true; +} + +bool wlr_xwayland_or_surface_wants_focus( const struct wlr_xwayland_surface *surface) { + bool ret = true; static enum atom_name needles[] = { NET_WM_WINDOW_TYPE_COMBO, NET_WM_WINDOW_TYPE_DND, @@ -1672,26 +1767,12 @@ bool wlr_xwayland_surface_is_unmanaged( NET_WM_WINDOW_TYPE_TOOLTIP, NET_WM_WINDOW_TYPE_UTILITY, }; - for (size_t i = 0; i < sizeof(needles) / sizeof(needles[0]); ++i) { if (xwm_atoms_contains(surface->xwm, surface->window_type, surface->window_type_len, needles[i])) { - return true; + ret = false; } } - return false; -} - -void wlr_xwayland_surface_ping(struct wlr_xwayland_surface *surface) { - xcb_client_message_data_t data = { 0 }; - data.data32[0] = surface->xwm->atoms[_NET_WM_PING]; - data.data32[1] = XCB_CURRENT_TIME; - data.data32[2] = surface->window_id; - - xwm_send_wm_message(surface, &data, XCB_EVENT_MASK_NO_EVENT); - - wl_event_source_timer_update(surface->ping_timer, - surface->xwm->ping_timeout); - surface->pinging = true; + return ret; } |