diff --git a/src/layer-surface.c b/src/layer-surface.c index 15c52c7..6a5907c 100644 --- a/src/layer-surface.c +++ b/src/layer-surface.c @@ -549,15 +549,18 @@ gint find_layer_surface_with_wl_surface (gconstpointer layer_surface, gconstpoin return wl_surface == needle ? 0 : 1; } -struct wl_proxy * +gboolean layer_surface_handle_request ( struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, - union wl_argument *args) + union wl_argument *args, + struct wl_proxy **ret_proxy) { + (void)interface; + (void)flags; const char* type = proxy->object.interface->name; if (strcmp(type, xdg_wm_base_interface.name) == 0) { if (opcode == XDG_WM_BASE_GET_XDG_SURFACE) { @@ -574,7 +577,8 @@ layer_surface_handle_request ( self); self->client_facing_xdg_surface = (struct xdg_surface *)xdg_surface; layer_surface_create_surface_object(self, wl_surface); - return xdg_surface; + *ret_proxy = xdg_surface; + return TRUE; } } } else if (strcmp(type, xdg_surface_interface.name) == 0) { @@ -587,13 +591,15 @@ layer_surface_handle_request ( NULL, (struct xdg_positioner *)args[2].o); zwlr_layer_surface_v1_get_popup (self->layer_surface, xdg_popup); - return (struct wl_proxy *)xdg_popup; + *ret_proxy = (struct wl_proxy *)xdg_popup; + return TRUE; } else { g_critical ("tried to create popup before layer shell surface"); - return libwayland_shim_create_client_proxy (proxy, &xdg_popup_interface, version, NULL, NULL, NULL); + *ret_proxy = libwayland_shim_create_client_proxy (proxy, &xdg_popup_interface, version, NULL, NULL, NULL); + return TRUE; } } } } - return libwayland_shim_real_wl_proxy_marshal_array_flags (proxy, opcode, interface, version, flags, args); + return FALSE; } diff --git a/src/layer-surface.h b/src/layer-surface.h index 84d422b..69c746f 100644 --- a/src/layer-surface.h +++ b/src/layer-surface.h @@ -62,12 +62,13 @@ void layer_surface_set_keyboard_mode (LayerSurface *self, GtkLayerShellKeyboardM const char* layer_surface_get_namespace (LayerSurface *self); // Used by libwayland wrappers -struct wl_proxy *layer_surface_handle_request ( +gboolean layer_surface_handle_request ( struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, - union wl_argument *args); + union wl_argument *args, + struct wl_proxy **ret_proxy); #endif // LAYER_SHELL_SURFACE_H diff --git a/src/libwayland-shim.c b/src/libwayland-shim.c index 08be624..cff0dff 100644 --- a/src/libwayland-shim.c +++ b/src/libwayland-shim.c @@ -190,6 +190,58 @@ libwayland_shim_get_client_proxy_data (struct wl_proxy *proxy, void* expected_ha } } +// Returns true if any arguments are proxies created by us (not known to libwayland) +gboolean +args_contains_client_facing_proxy ( + struct wl_proxy *proxy, + uint32_t opcode, + const struct wl_interface *interface, + union wl_argument *args) +{ + (void)interface; + const char *sig_iter = proxy->object.interface->methods[opcode].signature; + int i = 0; + while (true) { + struct argument_details arg; + sig_iter = get_next_argument(sig_iter, &arg); + switch (arg.type) { + case 'o': + if (args[i].o && args[i].o->id == client_facing_proxy_id) { + return TRUE; + } + break; + + case '\0': + return FALSE; + } + i++; + } +} + +// Returns the interface of the proxy object that this request is supposed to create, or NULL if none +const struct wl_interface* +get_interface_of_object_created_by_request ( + struct wl_proxy *proxy, + uint32_t opcode, + const struct wl_interface *interface) +{ + const char *sig_iter = proxy->object.interface->methods[opcode].signature; + int i = 0; + while (true) { + struct argument_details arg; + sig_iter = get_next_argument(sig_iter, &arg); + switch (arg.type) { + case 'n': + g_assert(interface[i].name); + return interface + i; + + case '\0': + return NULL; + } + i++; + } +} + // Overrides the function in wayland-client.c in libwayland void wl_proxy_destroy (struct wl_proxy *proxy) @@ -221,6 +273,8 @@ wl_proxy_marshal_array_flags ( { libwayland_shim_init (); if (proxy->object.id == client_facing_proxy_id) { + // libwayland doesn't know about the object this request is on. It must not find out about this object. If it + // finds out it will be very upset. struct wrapped_proxy *wrapper = (struct wrapped_proxy *)proxy; struct wl_proxy *result = NULL; if (wrapper->handler) @@ -229,7 +283,26 @@ wl_proxy_marshal_array_flags ( wl_proxy_destroy(proxy); return result; } else { - return layer_surface_handle_request (proxy, opcode, interface, version, flags, args); + struct wl_proxy *ret_proxy = NULL; + if (layer_surface_handle_request (proxy, opcode, interface, version, flags, args, &ret_proxy)) { + // The behavior of the request has been overridden + return ret_proxy; + } else if (args_contains_client_facing_proxy (proxy, opcode, interface, args)) { + // We can't do the normal thing because one of the arguments is an object libwayand doesn't know about, but + // no override behavior was taken. Hopefully we can safely ignore this request. + const struct wl_interface *created = get_interface_of_object_created_by_request(proxy, opcode, interface); + if (created) { + // We need to create a stub object to make the client happy, it will ignore all requests and represents + // nothing in libwayland/the server + return libwayland_shim_create_client_proxy (proxy, created, created->version, NULL, NULL, NULL); + } else { + // Ignore the request + return NULL; + } + } else { + // Forward the request on to libwayland without modification, this is the most common path + return libwayland_shim_real_wl_proxy_marshal_array_flags (proxy, opcode, interface, version, flags, args); + } } } diff --git a/src/libwayland-shim.h b/src/libwayland-shim.h index be391e9..c84cf8d 100644 --- a/src/libwayland-shim.h +++ b/src/libwayland-shim.h @@ -57,12 +57,4 @@ void libwayland_shim_clear_client_proxy_data (struct wl_proxy *proxy); void *libwayland_shim_get_client_proxy_data (struct wl_proxy *proxy, void* expected_handler); -extern struct wl_proxy * (*libwayland_shim_real_wl_proxy_marshal_array_flags) ( - struct wl_proxy *proxy, - uint32_t opcode, - const struct wl_interface *interface, - uint32_t version, - uint32_t flags, - union wl_argument *args); - #endif // LIBWAYLAND_SHIM_H