Init
This commit is contained in:
		
							
								
								
									
										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
											
										
									
								
							
		Reference in New Issue
	
	Block a user