Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/libwayland-shim.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ struct wrapped_proxy {

struct request_hook {
const char* interface_name;
uint32_t opcode;
int opcode;
libwayland_shim_request_handler_func_t handler;
void* data;
};
Expand Down Expand Up @@ -62,7 +62,7 @@ static void libwayland_shim_init() {

void libwayland_shim_install_request_hook(
struct wl_interface const* interface,
uint32_t opcode,
int opcode,
libwayland_shim_request_handler_func_t handler,
void* data
) {
Expand Down Expand Up @@ -282,7 +282,9 @@ struct wl_proxy* wl_proxy_marshal_array_flags(
} else {
const char* interface_name = proxy->object.interface->name;
for (int i = 0; i < request_hook_count; i++) {
if (strcmp(request_hooks[i].interface_name, interface_name) == 0 && request_hooks[i].opcode == opcode) {
if (strcmp(request_hooks[i].interface_name, interface_name) == 0 &&
(request_hooks[i].opcode < 0 || request_hooks[i].opcode == (int)opcode)
) {
struct wl_proxy* ret_proxy = NULL;
if (request_hooks[i].handler(
request_hooks[i].data,
Expand Down
4 changes: 2 additions & 2 deletions src/libwayland-shim.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ typedef void (*libwayland_shim_destroy_handler_func_t)(void* data, struct wl_pro
bool libwayland_shim_has_initialized();

// The handler will be called and can optionally handle all matching requests. There is no way to uninstall a hook, and
// installing too many hooks may hurt performance.
// installing too many hooks may hurt performance. If opcode < 0 all requests are matched for that interface.
void libwayland_shim_install_request_hook(
struct wl_interface const* interface,
uint32_t opcode,
int opcode,
libwayland_shim_request_handler_func_t handler,
void* data
);
Expand Down
1 change: 1 addition & 0 deletions src/lock-surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,5 @@ void lock_surface_install_hook(lock_surface_hook_callback_t callback) {
xdg_wm_base_get_xdg_surface_hook,
callback
);
stubbed_surface_install_positioner_hook();
}
22 changes: 21 additions & 1 deletion src/registry.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ struct zwlr_layer_shell_v1* layer_shell_global = NULL;
bool session_lock_requested = false;
struct ext_session_lock_manager_v1* session_lock_global = NULL;

bool subcompositor_requested = false;
struct wl_subcompositor* subcompositor_global = NULL;

static void wl_registry_handle_global(
void* _data,
struct wl_registry* registry,
Expand All @@ -25,7 +28,15 @@ static void wl_registry_handle_global(
(void)_data;

// pull out needed globals
if (layer_shell_requested && strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
if (subcompositor_requested && strcmp(interface, wl_subcompositor_interface.name) == 0) {
uint32_t supported_version = wl_subcompositor_interface.version;
subcompositor_global = wl_registry_bind(
registry,
id,
&wl_subcompositor_interface,
supported_version < version ? supported_version : version
);
} else if (layer_shell_requested && strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
uint32_t supported_version = zwlr_layer_shell_v1_interface.version;
layer_shell_global = wl_registry_bind(
registry,
Expand Down Expand Up @@ -88,10 +99,19 @@ struct zwlr_layer_shell_v1* get_layer_shell_global_from_display(struct wl_displa
struct ext_session_lock_manager_v1* get_session_lock_global_from_display(struct wl_display* display) {
if (!session_lock_requested) {
session_lock_requested = true;
subcompositor_requested = true; // If session lock is in use the subcompositor will likely be needed
bind_globals(display);
if (!session_lock_global) {
fprintf(stderr, "it appears your Wayland compositor does not support the Session Lock protocol\n");
}
}
return session_lock_global;
}

struct wl_subcompositor* get_subcompositor_global_from_display(struct wl_display* display) {
if (!subcompositor_requested) {
subcompositor_requested = true;
bind_globals(display);
}
return subcompositor_global;
}
1 change: 1 addition & 0 deletions src/registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ struct wl_display;

struct zwlr_layer_shell_v1* get_layer_shell_global_from_display(struct wl_display* display);
struct ext_session_lock_manager_v1* get_session_lock_global_from_display(struct wl_display* display);
struct wl_subcompositor* get_subcompositor_global_from_display(struct wl_display* display);
125 changes: 123 additions & 2 deletions src/stubbed-surface.c
Original file line number Diff line number Diff line change
@@ -1,21 +1,51 @@
#include "stubbed-surface.h"
#include "libwayland-shim.h"
#include "xdg-surface-server.h"
#include "layer-surface.h"
#include "registry.h"

#include <wayland-client.h>
#include <xdg-shell-client.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

struct geom_point_t {
int x, y;
};

struct geom_rect_t {
struct geom_point_t top_left;
struct geom_size_t size;
};

struct stubbed_surface_t {
struct xdg_surface_server_t super;
struct geom_rect_t configure;
struct wl_subsurface* subsurface;
};

static struct {
void* wayland_object;
struct geom_size_t size;
struct geom_rect_t anchor_rect;
enum xdg_positioner_anchor anchor;
enum xdg_positioner_gravity gravity;
uint32_t constraint_adjustment;
struct geom_point_t offset;
} current_positioner;

static void stubbed_configure_callback(void *data, struct wl_callback *callback, uint32_t callback_data) {
(void)callback, (void)callback_data;
struct stubbed_surface_t* self = data;

xdg_surface_server_send_configure(&self->super, 0, 0, 100, 100, 0);
xdg_surface_server_send_configure(
&self->super,
self->configure.top_left.x, self->configure.top_left.y,
self->configure.size.width, self->configure.size.height,
0
);
}

static const struct wl_callback_listener stubbed_configure_callback_listener = { stubbed_configure_callback };
Expand All @@ -24,7 +54,8 @@ static void stubbed_role_created(struct xdg_surface_server_t* super) {
struct stubbed_surface_t* self = (void*)super;

if (self->super.xdg_popup) {
fprintf(stderr, "stubbed popup not displayed\n");
self->configure.top_left = current_positioner.anchor_rect.top_left;
self->configure.size = current_positioner.size;
} else if (self->super.xdg_toplevel) {
fprintf(stderr, "stubbed toplevel not displayed\n");
}
Expand All @@ -41,6 +72,34 @@ static void stubbed_role_created(struct xdg_surface_server_t* super) {
struct wl_callback* callback = wl_display_sync(wrapped_display);
wl_callback_add_listener(callback, &stubbed_configure_callback_listener, self);
wl_proxy_wrapper_destroy(wrapped_display);

struct xdg_surface_server_t* parent_surface = get_xdg_surface_server_from_xdg_surface(super->popup_parent);
if (parent_surface) {
struct wl_subcompositor* subcompositor = get_subcompositor_global_from_display(display);
assert(subcompositor);
self->subsurface = wl_subcompositor_get_subsurface(
subcompositor,
super->wl_surface,
parent_surface->wl_surface
);
wl_subsurface_set_desync(self->subsurface);
wl_subsurface_set_position(self->subsurface, self->configure.top_left.x, self->configure.top_left.y);
// Trigger parent commit to make subsurface appear
xdg_surface_server_send_configure(
parent_surface,
parent_surface->last_configure.x, parent_surface->last_configure.y,
parent_surface->last_configure.width, parent_surface->last_configure.height,
0
);
}
}

static void stubbed_role_destroyed(struct xdg_surface_server_t* super) {
struct stubbed_surface_t* self = (void*)super;

if (self->subsurface) {
wl_subsurface_destroy(self->subsurface);
}
}

void stubbed_surface_destroyed(struct xdg_surface_server_t* super) {
Expand All @@ -52,5 +111,67 @@ struct wl_proxy* stubbed_surface_init(struct xdg_wm_base* creating_object, struc
struct stubbed_surface_t* self = calloc(1, sizeof(struct stubbed_surface_t));
self->super.popup_created = stubbed_role_created;
self->super.toplevel_created = stubbed_role_created;
self->super.popup_destroyed = stubbed_role_destroyed;
self->super.toplevel_destroyed = stubbed_role_destroyed;
return xdg_surface_server_get_xdg_surface(&self->super, creating_object, surface);
}

static bool xdg_positioner_hook(
void* data,
struct wl_proxy* proxy,
uint32_t opcode,
const struct wl_interface* create_interface,
uint32_t create_version,
uint32_t flags,
union wl_argument* args,
struct wl_proxy** ret_proxy
) {
(void)data, (void)opcode, (void)create_interface, (void)create_version, (void)flags, (void)ret_proxy;
if (opcode == XDG_POSITIONER_DESTROY) return false;

if (current_positioner.wayland_object != proxy) {
memset(&current_positioner, 0, sizeof(current_positioner));
current_positioner.wayland_object = proxy;
}

switch (opcode) {
case XDG_POSITIONER_SET_SIZE:
current_positioner.size = (struct geom_size_t){args[0].i, args[1].i};
break;

case XDG_POSITIONER_SET_ANCHOR_RECT:
current_positioner.anchor_rect.top_left = (struct geom_point_t){args[0].i, args[1].i};
current_positioner.anchor_rect.size = (struct geom_size_t){args[2].i, args[3].i};
break;

case XDG_POSITIONER_SET_ANCHOR:
current_positioner.anchor = args[0].u;
break;

case XDG_POSITIONER_SET_GRAVITY:
current_positioner.gravity = args[0].u;
break;

case XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT:
current_positioner.constraint_adjustment = args[0].u;
break;

case XDG_POSITIONER_SET_OFFSET:
current_positioner.offset = (struct geom_point_t){args[0].i, args[1].i};
break;
}
return false;
}

void stubbed_surface_install_positioner_hook() {
static bool installed = false;
if (!installed) {
installed = true;
libwayland_shim_install_request_hook(
&xdg_positioner_interface,
-1,
xdg_positioner_hook,
NULL
);
}
}
1 change: 1 addition & 0 deletions src/stubbed-surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
#include <xdg-shell-client.h>

struct wl_proxy* stubbed_surface_init(struct xdg_wm_base* creating_object, struct wl_surface* surface);
void stubbed_surface_install_positioner_hook();
6 changes: 6 additions & 0 deletions src/xdg-surface-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ static bool xdg_surface_handle_request(
self
);
self->xdg_popup = (struct xdg_popup*)*ret_proxy;
self->popup_parent = (struct xdg_surface*)args[1].o;
if (self->popup_created) self->popup_created(self);
return true;

Expand Down Expand Up @@ -139,6 +140,11 @@ void xdg_surface_server_send_configure(
int width, int height,
uint32_t serial
) {
self->last_configure.x = x;
self->last_configure.y = y;
self->last_configure.width = width;
self->last_configure.height = height;

if (self->xdg_toplevel) {
struct wl_array states;
wl_array_init(&states);
Expand Down
4 changes: 4 additions & 0 deletions src/xdg-surface-server.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ struct xdg_surface_server_t {

struct wl_surface* wl_surface;
struct xdg_surface* xdg_surface;
struct xdg_surface* popup_parent;
struct xdg_popup* xdg_popup;
struct xdg_toplevel* xdg_toplevel;
struct {
int x, y, width, height;
} last_configure;
};

// If the xdg_surface is managed by a surface server, this returns the surface server
Expand Down