c.cc · 412 linesall
// ImportC shim for the F16 clipboard + DnD demo (see ./app.d and
// ../../f16-clipboard-dnd.md). The scaffold shim (../scaffold/c.c) plus:
//
//   - wl_data_device_manager / wl_data_source / wl_data_device /
//     wl_data_offer helpers — the SHARED machinery behind both the
//     clipboard (set_selection) and drag-and-drop (start_drag), all core
//     protocol, bound at v3 for the dnd-action negotiation
//     (set_actions / action / finish),
//   - wl_seat / wl_pointer / wl_keyboard helpers (selection offers are
//     delivered on keyboard-focus enter; the drag serial comes from a
//     pointer button press),
//   - <poll.h> + pipe2/read/write for the fd-based data transfer (both
//     directions: serve `send` events, drain `receive` pipes),
//   - hand-written zwlr_virtual_pointer_v1 tables (f13 pattern, plus
//     motion_absolute) for the scripted ./inject.d gesture sessions.
//
// Nix's cc wrapper injects -D_FORTIFY_SOURCE, and glibc's fortify wrappers
// use __builtin_dynamic_object_size, which ImportC does not implement.
#undef _FORTIFY_SOURCE
#define _GNU_SOURCE 1 /* memfd_create(2), pipe2(2) */

#pragma attribute(push, nogc, nothrow)
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <sys/mman.h>
#include <wayland-client.h>
#include "xdg-shell-client-protocol.h"

int wsi_pipe2_cloexec(int fds[2])
{
    return pipe2(fds, O_CLOEXEC);
}

/* ---- bootstrap (core protocol) ------------------------------------- */

struct wl_registry *wsi_display_get_registry(struct wl_display *d)
{
    return wl_display_get_registry(d);
}

int wsi_registry_add_listener(struct wl_registry *r,
    const struct wl_registry_listener *l, void *data)
{
    return wl_registry_add_listener(r, l, data);
}

void *wsi_registry_bind(struct wl_registry *r, uint32_t name,
    const struct wl_interface *iface, uint32_t version)
{
    return wl_registry_bind(r, name, iface, version);
}

/* ---- wl_compositor / wl_surface ------------------------------------ */

struct wl_surface *wsi_compositor_create_surface(struct wl_compositor *c)
{
    return wl_compositor_create_surface(c);
}

void wsi_surface_attach(struct wl_surface *s, struct wl_buffer *b, int32_t x, int32_t y)
{
    wl_surface_attach(s, b, x, y);
}

void wsi_surface_damage_buffer(struct wl_surface *s, int32_t x, int32_t y,
    int32_t w, int32_t h)
{
    wl_surface_damage_buffer(s, x, y, w, h);
}

void wsi_surface_commit(struct wl_surface *s)
{
    wl_surface_commit(s);
}

struct wl_callback *wsi_surface_frame(struct wl_surface *s)
{
    return wl_surface_frame(s);
}

void wsi_surface_destroy(struct wl_surface *s)
{
    wl_surface_destroy(s);
}

int wsi_callback_add_listener(struct wl_callback *cb,
    const struct wl_callback_listener *l, void *data)
{
    return wl_callback_add_listener(cb, l, data);
}

void wsi_callback_destroy(struct wl_callback *cb)
{
    wl_callback_destroy(cb);
}

/* ---- wl_shm (software buffers) ------------------------------------- */

struct wl_shm_pool *wsi_shm_create_pool(struct wl_shm *shm, int32_t fd, int32_t size)
{
    return wl_shm_create_pool(shm, fd, size);
}

struct wl_buffer *wsi_shm_pool_create_buffer(struct wl_shm_pool *p, int32_t offset,
    int32_t w, int32_t h, int32_t stride, uint32_t format)
{
    return wl_shm_pool_create_buffer(p, offset, w, h, stride, format);
}

void wsi_shm_pool_destroy(struct wl_shm_pool *p)
{
    wl_shm_pool_destroy(p);
}

int wsi_buffer_add_listener(struct wl_buffer *b,
    const struct wl_buffer_listener *l, void *data)
{
    return wl_buffer_add_listener(b, l, data);
}

void wsi_buffer_destroy(struct wl_buffer *b)
{
    wl_buffer_destroy(b);
}

/* ---- wl_seat / wl_pointer / wl_keyboard ------------------------------ */

int wsi_seat_add_listener(struct wl_seat *s, const struct wl_seat_listener *l, void *data)
{
    return wl_seat_add_listener(s, l, data);
}

struct wl_pointer *wsi_seat_get_pointer(struct wl_seat *s)
{
    return wl_seat_get_pointer(s);
}

struct wl_keyboard *wsi_seat_get_keyboard(struct wl_seat *s)
{
    return wl_seat_get_keyboard(s);
}

void wsi_seat_destroy(struct wl_seat *s)
{
    wl_seat_destroy(s);
}

int wsi_pointer_add_listener(struct wl_pointer *p,
    const struct wl_pointer_listener *l, void *data)
{
    return wl_pointer_add_listener(p, l, data);
}

void wsi_pointer_destroy(struct wl_pointer *p)
{
    wl_pointer_destroy(p);
}

int wsi_keyboard_add_listener(struct wl_keyboard *k,
    const struct wl_keyboard_listener *l, void *data)
{
    return wl_keyboard_add_listener(k, l, data);
}

void wsi_keyboard_destroy(struct wl_keyboard *k)
{
    wl_keyboard_destroy(k);
}

/* ---- xdg-shell (generated glue) ------------------------------------- */

int wsi_wm_base_add_listener(struct xdg_wm_base *b,
    const struct xdg_wm_base_listener *l, void *data)
{
    return xdg_wm_base_add_listener(b, l, data);
}

void wsi_wm_base_pong(struct xdg_wm_base *b, uint32_t serial)
{
    xdg_wm_base_pong(b, serial);
}

struct xdg_surface *wsi_wm_base_get_xdg_surface(struct xdg_wm_base *b,
    struct wl_surface *s)
{
    return xdg_wm_base_get_xdg_surface(b, s);
}

void wsi_wm_base_destroy(struct xdg_wm_base *b)
{
    xdg_wm_base_destroy(b);
}

int wsi_xdg_surface_add_listener(struct xdg_surface *s,
    const struct xdg_surface_listener *l, void *data)
{
    return xdg_surface_add_listener(s, l, data);
}

struct xdg_toplevel *wsi_xdg_surface_get_toplevel(struct xdg_surface *s)
{
    return xdg_surface_get_toplevel(s);
}

void wsi_xdg_surface_ack_configure(struct xdg_surface *s, uint32_t serial)
{
    xdg_surface_ack_configure(s, serial);
}

void wsi_xdg_surface_destroy(struct xdg_surface *s)
{
    xdg_surface_destroy(s);
}

int wsi_toplevel_add_listener(struct xdg_toplevel *t,
    const struct xdg_toplevel_listener *l, void *data)
{
    return xdg_toplevel_add_listener(t, l, data);
}

void wsi_toplevel_set_title(struct xdg_toplevel *t, const char *title)
{
    xdg_toplevel_set_title(t, title);
}

void wsi_toplevel_set_app_id(struct xdg_toplevel *t, const char *app_id)
{
    xdg_toplevel_set_app_id(t, app_id);
}

void wsi_toplevel_destroy(struct xdg_toplevel *t)
{
    xdg_toplevel_destroy(t);
}

/* ---- wl_data_device_manager (clipboard + DnD, core protocol) --------- */

struct wl_data_device *wsi_ddm_get_data_device(struct wl_data_device_manager *m,
    struct wl_seat *seat)
{
    return wl_data_device_manager_get_data_device(m, seat);
}

struct wl_data_source *wsi_ddm_create_data_source(struct wl_data_device_manager *m)
{
    return wl_data_device_manager_create_data_source(m);
}

void wsi_ddm_destroy(struct wl_data_device_manager *m)
{
    wl_data_device_manager_destroy(m);
}

int wsi_data_source_add_listener(struct wl_data_source *s,
    const struct wl_data_source_listener *l, void *data)
{
    return wl_data_source_add_listener(s, l, data);
}

void wsi_data_source_offer(struct wl_data_source *s, const char *mime)
{
    wl_data_source_offer(s, mime);
}

void wsi_data_source_set_actions(struct wl_data_source *s, uint32_t actions)
{
    wl_data_source_set_actions(s, actions); /* since v3, drag sources only */
}

void wsi_data_source_destroy(struct wl_data_source *s)
{
    wl_data_source_destroy(s);
}

int wsi_data_device_add_listener(struct wl_data_device *d,
    const struct wl_data_device_listener *l, void *data)
{
    return wl_data_device_add_listener(d, l, data);
}

void wsi_data_device_set_selection(struct wl_data_device *d,
    struct wl_data_source *src, uint32_t serial)
{
    wl_data_device_set_selection(d, src, serial);
}

void wsi_data_device_start_drag(struct wl_data_device *d,
    struct wl_data_source *src, struct wl_surface *origin,
    struct wl_surface *icon, uint32_t serial)
{
    wl_data_device_start_drag(d, src, origin, icon, serial);
}

void wsi_data_device_release(struct wl_data_device *d)
{
    wl_data_device_release(d); /* since v2 */
}

int wsi_data_offer_add_listener(struct wl_data_offer *o,
    const struct wl_data_offer_listener *l, void *data)
{
    return wl_data_offer_add_listener(o, l, data);
}

void wsi_data_offer_accept(struct wl_data_offer *o, uint32_t serial, const char *mime)
{
    wl_data_offer_accept(o, serial, mime);
}

void wsi_data_offer_receive(struct wl_data_offer *o, const char *mime, int32_t fd)
{
    wl_data_offer_receive(o, mime, fd);
}

void wsi_data_offer_set_actions(struct wl_data_offer *o, uint32_t actions, uint32_t preferred)
{
    wl_data_offer_set_actions(o, actions, preferred); /* since v3 */
}

void wsi_data_offer_finish(struct wl_data_offer *o)
{
    wl_data_offer_finish(o); /* since v3, dnd offers only */
}

void wsi_data_offer_destroy(struct wl_data_offer *o)
{
    wl_data_offer_destroy(o);
}
#pragma attribute(pop)

/* ---- zwlr_virtual_pointer_v1 (hand-written interface tables) --------- */
/* The demo's `inject` mode (see ./inject.d) plugs ONE virtual pointer in and
 * scripts a whole popup scenario inside that single device session — a
 * per-gesture plug/unplug (the wlrctl model) would flap the seat's pointer
 * capability mid-grab, and whether THAT dismisses the popup must stay a
 * controlled measurement, not an accident. Tables hand-derived from
 * wlr-virtual-pointer-unstable-v1.xml exactly as in the F13 shim, plus
 * motion_absolute (opcode 1) for global-coordinate scripting. */

#pragma attribute(push, nogc, nothrow)

static const struct wl_interface *vp_null_types[5] = { NULL, NULL, NULL, NULL, NULL };

static const struct wl_message wsi_vptr_requests[] = {
    { "motion", "uff", vp_null_types },
    { "motion_absolute", "uuuuu", vp_null_types },
    { "button", "uuu", vp_null_types },
    { "axis", "uuf", vp_null_types },
    { "frame", "", vp_null_types },
    { "axis_source", "u", vp_null_types },
    { "axis_stop", "uu", vp_null_types },
    { "axis_discrete", "uufi", vp_null_types },
    { "destroy", "", vp_null_types },
};

const struct wl_interface wsi_virtual_pointer_interface = {
    "zwlr_virtual_pointer_v1", 2, 9, wsi_vptr_requests, 0, NULL,
};

static const struct wl_interface *vpm_create_types[2];

static const struct wl_message wsi_vpm_requests[] = {
    { "create_virtual_pointer", "?on", vpm_create_types },
    { "destroy", "", vp_null_types },
};

const struct wl_interface wsi_virtual_pointer_manager_interface = {
    "zwlr_virtual_pointer_manager_v1", 2, 2, wsi_vpm_requests, 0, NULL,
};

struct wl_proxy *wsi_vpm_create_virtual_pointer(struct wl_proxy *mgr, struct wl_seat *seat)
{
    vpm_create_types[0] = &wl_seat_interface;
    vpm_create_types[1] = &wsi_virtual_pointer_interface;
    return wl_proxy_marshal_flags(mgr, 0, &wsi_virtual_pointer_interface,
        wl_proxy_get_version(mgr), 0, seat, NULL);
}

void wsi_vpm_destroy(struct wl_proxy *mgr)
{
    wl_proxy_marshal_flags(mgr, 1, NULL, wl_proxy_get_version(mgr), WL_MARSHAL_FLAG_DESTROY);
}

void wsi_vptr_motion_absolute(struct wl_proxy *p, uint32_t time,
    uint32_t x, uint32_t y, uint32_t x_extent, uint32_t y_extent)
{
    wl_proxy_marshal_flags(p, 1, NULL, wl_proxy_get_version(p), 0,
        time, x, y, x_extent, y_extent);
}

void wsi_vptr_button(struct wl_proxy *p, uint32_t time, uint32_t button, uint32_t state)
{
    wl_proxy_marshal_flags(p, 2, NULL, wl_proxy_get_version(p), 0, time, button, state);
}

void wsi_vptr_frame(struct wl_proxy *p)
{
    wl_proxy_marshal_flags(p, 4, NULL, wl_proxy_get_version(p), 0);
}

void wsi_vptr_destroy(struct wl_proxy *p)
{
    wl_proxy_marshal_flags(p, 8, NULL, wl_proxy_get_version(p), WL_MARSHAL_FLAG_DESTROY);
}

#pragma attribute(pop)

// The generated request-marshalling tables (`xdg_wm_base_interface`, …).
// Textually included so the package stays a single C translation unit (see
// `excludedSourceFiles` in ./dub.sdl and the scaffold notes).
#include "xdg-shell-protocol.c"