Skip to content

Instantly share code, notes, and snippets.

@X547
Created September 28, 2024 11:53
Show Gist options
  • Save X547/8931cb881dcf348f678a4c6cf7cd6ae8 to your computer and use it in GitHub Desktop.
Save X547/8931cb881dcf348f678a4c6cf7cd6ae8 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include "Wayland.h"
#include "XdgShell.h"
#include "linux/input-event-codes.h"
extern "C" {
#include "cat.h"
#include "shm.h"
}
class XdgSurface: public WlXdgSurface {
public:
XdgSurface(struct wl_proxy *proxy): WlXdgSurface(proxy) {}
virtual ~XdgSurface() = default;
void HandleConfigure(uint32_t serial) final;
};
class XdgToplevel: public WlXdgToplevel {
public:
virtual ~XdgToplevel() = default;
XdgToplevel(struct wl_proxy *proxy): WlXdgToplevel(proxy) {}
void HandleClose() final;
};
class Pointer: public WlPointer {
public:
virtual ~Pointer() = default;
Pointer(struct wl_proxy *proxy): WlPointer(proxy) {}
void HandleButton(uint32_t serial, uint32_t time, uint32_t button, uint32_t state) final;
};
class Seat: public WlSeat {
public:
virtual ~Seat() = default;
Seat(struct wl_proxy *proxy): WlSeat(proxy) {}
void HandleCapabilities(uint32_t capabilities) final;
void HandleName(const char *name) final {}
};
class Registry: public WlRegistry {
public:
virtual ~Registry() = default;
Registry(struct wl_proxy *proxy): WlRegistry(proxy) {}
void HandleGlobal(uint32_t name, const char *interface, uint32_t version) final;
};
static const int width = 128;
static const int height = 128;
static bool configured = false;
static bool running = true;
static WlShm *shm = NULL;
static Seat *seat = NULL;
static WlCompositor *compositor = NULL;
static WlXdgWmBase *xdg_wm_base = NULL;
static void *shm_data = NULL;
static WlSurface *surface = NULL;
static XdgToplevel *xdg_toplevel = NULL;
void XdgSurface::HandleConfigure(uint32_t serial)
{
SendAckConfigure(serial);
if (configured) {
surface->SendCommit();
}
configured = true;
}
void XdgToplevel::HandleClose()
{
running = false;
}
void Pointer::HandleButton(uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
{
if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED) {
xdg_toplevel->SendMove(seat->ToProxy(), serial);
}
}
void Seat::HandleCapabilities(uint32_t capabilities)
{
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
new Pointer(SendGetPointer());
}
}
void Registry::HandleGlobal(uint32_t name, const char *interface, uint32_t version)
{
if (strcmp(interface, wl_shm_interface.name) == 0) {
shm = new WlShm(SendBind(name, &wl_shm_interface, 1));
} else if (strcmp(interface, wl_seat_interface.name) == 0) {
seat = new Seat(SendBind(name, &wl_seat_interface, 1));
} else if (strcmp(interface, wl_compositor_interface.name) == 0) {
compositor = new WlCompositor(SendBind(name, &wl_compositor_interface, 1));
} else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
xdg_wm_base = new WlXdgWmBase(SendBind(name, &xdg_wm_base_interface, 1));
}
}
static struct WlBuffer *create_buffer(void)
{
int stride = width * 4;
int size = stride * height;
// Allocate a shared memory file with the right size
int fd = create_shm_file(size);
if (fd < 0) {
fprintf(stderr, "creating a buffer file for %d B failed: %m\n", size);
return NULL;
}
// Map the shared memory file
shm_data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (shm_data == MAP_FAILED) {
fprintf(stderr, "mmap failed: %m\n");
close(fd);
return NULL;
}
// Create a wl_buffer from our shared memory file descriptor
WlShmPool *pool = new WlShmPool(shm->SendCreatePool(fd, size));
WlBuffer *buffer = new WlBuffer(pool->SendCreateBuffer(0, width, height, stride, WL_SHM_FORMAT_ARGB8888));
pool->SendDestroy();
// Now that we've mapped the file and created the wl_buffer, we no longer
// need to keep file descriptor opened
close(fd);
// Copy pixels into our shared memory file (MagickImage is from cat.h)
memcpy(shm_data, MagickImage, size);
return buffer;
}
int main()
{
struct wl_display *display = wl_display_connect(NULL);
if (display == NULL) {
fprintf(stderr, "failed to create display\n");
return EXIT_FAILURE;
}
new Registry((struct wl_proxy*)wl_display_get_registry(display));
if (wl_display_roundtrip(display) == -1) {
return EXIT_FAILURE;
}
if (shm == NULL || compositor == NULL || xdg_wm_base == NULL) {
fprintf(stderr, "no wl_shm, wl_compositor or xdg_wm_base support\n");
return EXIT_FAILURE;
}
surface = new WlSurface(compositor->SendCreateSurface());
XdgSurface *xdg_surface = new XdgSurface(xdg_wm_base->SendGetXdgSurface(surface->ToProxy()));
xdg_toplevel = new XdgToplevel(xdg_surface->SendGetToplevel());
surface->SendCommit();
while (wl_display_dispatch(display) != -1 && !configured) {
// This space intentionally left blank
}
WlBuffer *buffer = create_buffer();
if (buffer == NULL) {
return EXIT_FAILURE;
}
surface->SendAttach(buffer->ToProxy(), 0, 0);
surface->SendCommit();
while (wl_display_dispatch(display) != -1 && running) {
// This space intentionally left blank
}
xdg_toplevel->SendDestroy();
xdg_surface->SendDestroy();
surface->SendDestroy();
buffer->SendDestroy();
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment