Init
This commit is contained in:
commit
998164d7f9
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
build/
|
||||||
|
.vscode/
|
||||||
|
.cache/
|
41
CMakeLists.txt
Normal file
41
CMakeLists.txt
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.0 )
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
project(wlgol
|
||||||
|
VERSION 0.0.1
|
||||||
|
DESCRIPTION "Wayland Game Of Life"
|
||||||
|
LANGUAGES C)
|
||||||
|
|
||||||
|
# Download xdg-shell.xml
|
||||||
|
# file(DOWNLOAD "https://cgit.freedesktop.org/wayland/wayland-protocols/plain/stable/xdg-shell/xdg-shell.xml" "${CMAKE_CURRENT_BINARY_DIR}/xdg-shell.xml")
|
||||||
|
|
||||||
|
# Generation of xdg-shell.h and xdg-shell.c
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/include/xdg-shell.h
|
||||||
|
COMMAND wayland-scanner client-header ${CMAKE_SOURCE_DIR}/xdg-shell.xml ${CMAKE_CURRENT_BINARY_DIR}/include/xdg-shell.h
|
||||||
|
DEPENDS ${CMAKE_SOURCE_DIR}/xdg-shell.xml
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell.c
|
||||||
|
COMMAND wayland-scanner private-code ${CMAKE_SOURCE_DIR}/xdg-shell.xml ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell.c
|
||||||
|
DEPENDS ${CMAKE_SOURCE_DIR}/xdg-shell.xml
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
wlgol.c
|
||||||
|
tkeyboard.c
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/xdg-shell.c
|
||||||
|
)
|
||||||
|
|
||||||
|
set(GENHEADERS
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/include/xdg-shell.h
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(wlgol ${SOURCES} ${GENHEADERS})
|
||||||
|
|
||||||
|
target_include_directories(wlgol
|
||||||
|
PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include
|
||||||
|
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(wlgol wayland-client)
|
28
include/puzzle.h
Normal file
28
include/puzzle.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#ifndef PUZZLE_H
|
||||||
|
#define PUZZLE_H
|
||||||
|
|
||||||
|
enum colors
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
EL = 1,
|
||||||
|
T = 2,
|
||||||
|
POLE = 3,
|
||||||
|
SQUARE = 4,
|
||||||
|
LZIG = 5,
|
||||||
|
RZIG = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct puzzle
|
||||||
|
* Represents a puzzle in the Tetris game.
|
||||||
|
*/
|
||||||
|
struct puzzle {
|
||||||
|
int with; // The width of the puzzle
|
||||||
|
int height; // The height of the puzzle
|
||||||
|
unsigned char *data; // The data of the puzzle
|
||||||
|
enum colors type; // The type of the puzzle
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
9
include/tkeyboard.h
Normal file
9
include/tkeyboard.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef TKEYBOARD_H
|
||||||
|
#define TKEYBOARD_H
|
||||||
|
|
||||||
|
//#include <wayland-client-protocol.h>
|
||||||
|
#include <wayland-client.h>
|
||||||
|
|
||||||
|
extern const struct wl_keyboard_listener keyboard_listener;
|
||||||
|
|
||||||
|
#endif
|
46
tkeyboard.c
Normal file
46
tkeyboard.c
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <tkeyboard.h>
|
||||||
|
|
||||||
|
static void keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size)
|
||||||
|
{
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
|
||||||
|
{
|
||||||
|
printf("keyboard_enter\n");
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface)
|
||||||
|
{
|
||||||
|
printf("keyboard_leave\n");
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
|
||||||
|
{
|
||||||
|
printf("keyboard_key: %d %d\n", key, state);
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
|
||||||
|
{
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay)
|
||||||
|
{
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct wl_keyboard_listener keyboard_listener = {
|
||||||
|
.keymap = keyboard_keymap,
|
||||||
|
.enter = keyboard_enter,
|
||||||
|
.leave = keyboard_leave,
|
||||||
|
.key = keyboard_key,
|
||||||
|
.modifiers = keyboard_modifiers,
|
||||||
|
.repeat_info = keyboard_repeat_info
|
||||||
|
};
|
||||||
|
|
306
wlgol.c
Normal file
306
wlgol.c
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
#include <bits/time.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <syscall.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <xdg-shell.h>
|
||||||
|
#include <wayland-client-protocol.h>
|
||||||
|
#include <wayland-client.h>
|
||||||
|
|
||||||
|
#include <puzzle.h>
|
||||||
|
#include <tkeyboard.h>
|
||||||
|
|
||||||
|
struct wl_compositor *compositor;
|
||||||
|
struct wl_shm *shm;
|
||||||
|
struct xdg_wm_base *xdg_shell;
|
||||||
|
struct wl_seat *wl_seat;
|
||||||
|
|
||||||
|
int running = 1;
|
||||||
|
int released = 0;
|
||||||
|
struct timespec mytime;
|
||||||
|
|
||||||
|
struct canvas
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int stride;
|
||||||
|
int size;
|
||||||
|
struct wl_buffer *buffer;
|
||||||
|
unsigned char *data;
|
||||||
|
struct wl_surface *surface;
|
||||||
|
struct wl_callback *frame;
|
||||||
|
} canvas;
|
||||||
|
|
||||||
|
// registry
|
||||||
|
void registry_global_handler(
|
||||||
|
void *data, struct wl_registry *registry,
|
||||||
|
uint32_t name, const char *interface,
|
||||||
|
uint32_t version)
|
||||||
|
{
|
||||||
|
// printf(" -> %s\n", interface);
|
||||||
|
if (strcmp(interface, wl_compositor_interface.name) == 0)
|
||||||
|
{
|
||||||
|
compositor = wl_registry_bind(registry, name, &wl_compositor_interface, wl_compositor_interface.version);
|
||||||
|
printf("Got wl_compositor %d\n", version);
|
||||||
|
}
|
||||||
|
else if (strcmp(interface, wl_shm_interface.name) == 0)
|
||||||
|
{
|
||||||
|
shm = wl_registry_bind(registry, name, &wl_shm_interface, wl_shm_interface.version);
|
||||||
|
printf("Got wl_shm %d\n", version);
|
||||||
|
}
|
||||||
|
else if (strcmp(interface, xdg_wm_base_interface.name) == 0)
|
||||||
|
{
|
||||||
|
xdg_shell = wl_registry_bind(registry, name, &xdg_wm_base_interface, 4);
|
||||||
|
printf("Got xdg_wm_base %d\n", version);
|
||||||
|
}
|
||||||
|
else if (strcmp(interface, wl_seat_interface.name) == 0)
|
||||||
|
{
|
||||||
|
wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, 5);
|
||||||
|
printf("Got wl_seat (%d)\n", version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void registry_global_remove_handler(
|
||||||
|
void *data, struct wl_registry *registry,
|
||||||
|
uint32_t name)
|
||||||
|
{
|
||||||
|
// notging
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct wl_registry_listener registry_listener = {
|
||||||
|
.global = registry_global_handler,
|
||||||
|
.global_remove = registry_global_remove_handler};
|
||||||
|
|
||||||
|
// xdg_toplevel
|
||||||
|
void xdg_toplevel_configure_handler(
|
||||||
|
void *data,
|
||||||
|
struct xdg_toplevel *xdg_toplevel,
|
||||||
|
int32_t width, int32_t height,
|
||||||
|
struct wl_array *states)
|
||||||
|
{
|
||||||
|
printf("xdg_toplevel_configure: %dx%d\n", width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xdg_toplevel_close_handler(void *data, struct xdg_toplevel *xdg_toplevel)
|
||||||
|
{
|
||||||
|
printf("xdg_toplevel_close\n");
|
||||||
|
running = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xdg_toplevel_configure_bounds_handler(
|
||||||
|
void *data,
|
||||||
|
struct xdg_toplevel *xdg_toplevel,
|
||||||
|
int32_t width,
|
||||||
|
int32_t height)
|
||||||
|
{
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
||||||
|
.configure = xdg_toplevel_configure_handler,
|
||||||
|
.close = xdg_toplevel_close_handler,
|
||||||
|
.configure_bounds = xdg_toplevel_configure_bounds_handler};
|
||||||
|
|
||||||
|
// xdg_surface
|
||||||
|
void xdg_surface_configure_handler(void *data, struct xdg_surface *xdg_surface,
|
||||||
|
uint32_t serial)
|
||||||
|
{
|
||||||
|
printf("xdg_surface_configure\n");
|
||||||
|
xdg_surface_ack_configure(xdg_surface, serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct xdg_surface_listener xdg_surface_listener = {
|
||||||
|
.configure = xdg_surface_configure_handler};
|
||||||
|
|
||||||
|
// xdg_shell
|
||||||
|
void xdg_wm_base_ping_handler(void *data, struct xdg_wm_base *xdg_shell,
|
||||||
|
uint32_t serial)
|
||||||
|
{
|
||||||
|
xdg_wm_base_pong(xdg_shell, serial);
|
||||||
|
// printf("wm_base ping-pong\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct xdg_wm_base_listener xdg_shell_listener = {
|
||||||
|
.ping = xdg_wm_base_ping_handler};
|
||||||
|
|
||||||
|
|
||||||
|
void wl_buffer_release_handler(void *data, struct wl_buffer * wl_buffer) {
|
||||||
|
// printf("wl_buffer_release\n");
|
||||||
|
released = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct wl_buffer_listener wl_buffer_listener = {
|
||||||
|
.release = wl_buffer_release_handler};
|
||||||
|
|
||||||
|
|
||||||
|
void redraw(); // forward declaration
|
||||||
|
|
||||||
|
void wl_callack_done(void *data, struct wl_callback *callback, uint32_t time) {
|
||||||
|
if (canvas.frame) {
|
||||||
|
wl_callback_destroy(canvas.frame);
|
||||||
|
canvas.frame = NULL;
|
||||||
|
}
|
||||||
|
if (released) {
|
||||||
|
redraw();
|
||||||
|
released = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct wl_callback_listener wl_surface_frame_listener = {
|
||||||
|
.done = wl_callack_done};
|
||||||
|
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &mytime);
|
||||||
|
|
||||||
|
struct wl_display *display = wl_display_connect(NULL);
|
||||||
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
|
|
||||||
|
// wait for the "initial" set of globals to appear
|
||||||
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
|
xdg_wm_base_add_listener(xdg_shell, &xdg_shell_listener, NULL);
|
||||||
|
|
||||||
|
canvas.surface = wl_compositor_create_surface(compositor);
|
||||||
|
|
||||||
|
struct xdg_surface *xdg_surface = xdg_wm_base_get_xdg_surface(xdg_shell, canvas.surface);
|
||||||
|
struct xdg_toplevel *xdg_toplevel = xdg_surface_get_toplevel(xdg_surface);
|
||||||
|
|
||||||
|
xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, NULL);
|
||||||
|
xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL);
|
||||||
|
|
||||||
|
xdg_toplevel_set_app_id(xdg_toplevel, "eu.ar76.wlgol");
|
||||||
|
xdg_toplevel_set_title(xdg_toplevel, "Game Of Life.");
|
||||||
|
|
||||||
|
// signal that the surface is ready to be configured
|
||||||
|
wl_surface_commit(canvas.surface);
|
||||||
|
|
||||||
|
struct wl_keyboard *wl_keyboard = wl_seat_get_keyboard(wl_seat);
|
||||||
|
wl_keyboard_add_listener(wl_keyboard, &keyboard_listener, NULL);
|
||||||
|
|
||||||
|
canvas.width = 400;
|
||||||
|
canvas.height = 400;
|
||||||
|
canvas.stride = canvas.width * 4;
|
||||||
|
canvas.size = canvas.stride * canvas.height; // bytes
|
||||||
|
|
||||||
|
// open an anonymous file and write some zero bytes to it
|
||||||
|
int fd = syscall(SYS_memfd_create, "buffer", 0);
|
||||||
|
ftruncate(fd, canvas.size);
|
||||||
|
|
||||||
|
// map it to the memory
|
||||||
|
canvas.data =
|
||||||
|
mmap(NULL, canvas.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
|
||||||
|
// turn it into a shared memory pool
|
||||||
|
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, canvas.size);
|
||||||
|
|
||||||
|
close(fd); // mapped, so can be closed
|
||||||
|
|
||||||
|
// allocate the buffer in that pool
|
||||||
|
canvas.buffer = wl_shm_pool_create_buffer(
|
||||||
|
pool, 0, canvas.width, canvas.height, canvas.stride, WL_SHM_FORMAT_ARGB8888);
|
||||||
|
|
||||||
|
wl_buffer_add_listener(canvas.buffer, &wl_buffer_listener, NULL);
|
||||||
|
// wait for the surface to be configured
|
||||||
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
|
redraw();
|
||||||
|
|
||||||
|
while (wl_display_dispatch(display) != -1 && running)
|
||||||
|
{
|
||||||
|
// nothing inside
|
||||||
|
}
|
||||||
|
|
||||||
|
xdg_toplevel_destroy(xdg_toplevel);
|
||||||
|
xdg_surface_destroy(xdg_surface);
|
||||||
|
wl_surface_destroy(canvas.surface);
|
||||||
|
wl_shm_pool_destroy(pool);
|
||||||
|
wl_registry_destroy(registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char mycolour = 0;
|
||||||
|
char direction = 1;
|
||||||
|
int framecounter = 0;
|
||||||
|
|
||||||
|
void redraw()
|
||||||
|
{
|
||||||
|
clock_t start = clock();
|
||||||
|
|
||||||
|
mycolour += direction;
|
||||||
|
switch (mycolour) {
|
||||||
|
case 0: // lower limit, start to increase
|
||||||
|
direction = 1;
|
||||||
|
break;
|
||||||
|
case 255: // upper limit, start to decrease
|
||||||
|
direction = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// printf("dred=%d\n", dred);
|
||||||
|
// draw into buffer
|
||||||
|
for (int x = 0; x < canvas.width; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < canvas.height; y++)
|
||||||
|
{
|
||||||
|
struct pixel
|
||||||
|
{
|
||||||
|
// little-endian ARGB
|
||||||
|
unsigned char blue;
|
||||||
|
unsigned char green;
|
||||||
|
unsigned char red;
|
||||||
|
unsigned char alpha;
|
||||||
|
} *px = (struct pixel *)(canvas.data + y * canvas.stride + x * 4);
|
||||||
|
|
||||||
|
// draw a stripes pattern
|
||||||
|
if ((x + y) % 30 < 10)
|
||||||
|
{
|
||||||
|
// transparent
|
||||||
|
px->alpha = 0;
|
||||||
|
}
|
||||||
|
else if ((x + y) % 30 < 20)
|
||||||
|
{
|
||||||
|
// yellow
|
||||||
|
px->alpha = 255;
|
||||||
|
px->red = 255;
|
||||||
|
px->green = 255;
|
||||||
|
px->blue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// semitransparent red
|
||||||
|
px->alpha = 128;
|
||||||
|
px->red = mycolour;
|
||||||
|
px->green = 0;
|
||||||
|
px->blue = (255 - mycolour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// callback
|
||||||
|
canvas.frame = wl_surface_frame(canvas.surface);
|
||||||
|
wl_callback_add_listener(canvas.frame, &wl_surface_frame_listener, NULL);
|
||||||
|
wl_surface_attach(canvas.surface, canvas.buffer, 0, 0);
|
||||||
|
wl_surface_damage(canvas.surface, 0, 0, canvas.width, canvas.height);
|
||||||
|
wl_surface_commit(canvas.surface);
|
||||||
|
|
||||||
|
framecounter++;
|
||||||
|
|
||||||
|
struct timespec ntime;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ntime);
|
||||||
|
double elapsed_time = (ntime.tv_sec - mytime.tv_sec) + (ntime.tv_nsec - mytime.tv_nsec) / 1e9;
|
||||||
|
|
||||||
|
if (elapsed_time > 1.0) {
|
||||||
|
clock_t end = clock();
|
||||||
|
double dur = ((double) end - start) / CLOCKS_PER_SEC;
|
||||||
|
printf("FPS: %d in %g sec\n", framecounter, dur);
|
||||||
|
mytime = ntime;
|
||||||
|
framecounter = 0;
|
||||||
|
}
|
||||||
|
}
|
1386
xdg-shell.xml
Normal file
1386
xdg-shell.xml
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user