logo

bytemedia

Home to byte-level sounds, images, videos, … git clone https://hacktivis.me/git/bytemedia.git

wayland.c (8041B)


  1. #define _POSIX_C_SOURCE 200112L
  2. #include "xdg-shell-client-protocol.h"
  3. #include <errno.h>
  4. #include <fcntl.h>
  5. #include <limits.h>
  6. #include <stdbool.h>
  7. #include <stdlib.h> /* exit(), EXIT_FAILURE */
  8. #include <stdio.h> /* fputs(), stderr */
  9. #include <string.h>
  10. #include <sys/mman.h>
  11. #include <time.h>
  12. #include <unistd.h>
  13. #include <wayland-client.h>
  14. /* Shared memory support code */
  15. static void
  16. randname(char *buf)
  17. {
  18. struct timespec ts;
  19. clock_gettime(CLOCK_REALTIME, &ts);
  20. long r = ts.tv_nsec;
  21. for(int i = 0; i < 6; ++i)
  22. {
  23. buf[i] = 'A' + (r & 15) + (r & 16) * 2;
  24. r >>= 5;
  25. }
  26. }
  27. static int
  28. create_shm_file(void)
  29. {
  30. int retries = 100;
  31. do
  32. {
  33. char name[] = "/wl_shm-XXXXXX";
  34. randname(name + sizeof(name) - 7);
  35. --retries;
  36. int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
  37. if(fd >= 0)
  38. {
  39. shm_unlink(name);
  40. return fd;
  41. }
  42. } while(retries > 0 && errno == EEXIST);
  43. return -1;
  44. }
  45. static int
  46. allocate_shm_file(size_t size)
  47. {
  48. int fd = create_shm_file();
  49. if(fd < 0) return -1;
  50. int ret;
  51. do
  52. {
  53. ret = ftruncate(fd, size);
  54. } while(ret < 0 && errno == EINTR);
  55. if(ret < 0)
  56. {
  57. close(fd);
  58. return -1;
  59. }
  60. return fd;
  61. }
  62. /* Wayland code */
  63. struct client_state
  64. {
  65. /* Globals */
  66. struct wl_display *wl_display;
  67. struct wl_registry *wl_registry;
  68. struct wl_compositor *wl_compositor;
  69. struct xdg_wm_base *xdg_wm_base;
  70. struct wl_shm *wl_shm;
  71. struct wl_buffer *wl_buffer;
  72. uint32_t *shm_data;
  73. /* Objects */
  74. struct wl_surface *wl_surface;
  75. struct xdg_surface *xdg_surface;
  76. struct xdg_toplevel *xdg_toplevel;
  77. /* State */
  78. float offset;
  79. uint32_t last_frame;
  80. int width, height;
  81. bool closed;
  82. };
  83. static void
  84. draw_frame(struct client_state *state)
  85. {
  86. int t = (int)state->offset;
  87. /* Let the fun begin! */
  88. for(int y = 0; y < state->height; y++)
  89. {
  90. int x_base = y * state->width;
  91. for(int x = 0; x < state->width; x++)
  92. {
  93. //if (((x + offset) + (y + offset) / 8 * 8) % 16 < 8)
  94. // data[y * WIDTH + x] = 0xFF666666;
  95. //else
  96. // data[y * WIDTH + x] = 0xFFEEEEEE;
  97. // munching squares
  98. //state->shm_data[y * state->width + x] = (x - t | y - t) + t << 16;
  99. state->shm_data[x_base + x] = (x|y) * t <<16;
  100. //glichy munching squares
  101. //state->shm_data[y * state->width + x] = (x | y) * t;
  102. // color enumeration
  103. //state->shm_data[y * state->width + x] = t*2|t*4<<8|t*8<<16;
  104. }
  105. }
  106. }
  107. static void
  108. allocate_wl_shm_buffer(struct client_state *state)
  109. {
  110. struct wl_shm_pool *pool;
  111. int stride = state->width * 4;
  112. int size = stride * state->height;
  113. int shm_fd = allocate_shm_file(size);
  114. if(shm_fd == -1)
  115. {
  116. return;
  117. }
  118. state->shm_data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
  119. if(state->shm_data == MAP_FAILED)
  120. {
  121. close(shm_fd);
  122. return;
  123. }
  124. pool = wl_shm_create_pool(state->wl_shm, shm_fd, size);
  125. state->wl_buffer = wl_shm_pool_create_buffer(
  126. pool, 0, state->width, state->height, stride, WL_SHM_FORMAT_XRGB8888);
  127. wl_shm_pool_destroy(pool);
  128. close(shm_fd);
  129. }
  130. static void
  131. xdg_toplevel_configure(void *data,
  132. struct xdg_toplevel *xdg_toplevel,
  133. int32_t width,
  134. int32_t height,
  135. struct wl_array *states)
  136. {
  137. struct client_state *state = data;
  138. if(width != 0 && height != 0)
  139. {
  140. munmap(state->shm_data, state->width * state->height * 4);
  141. state->width = width;
  142. state->height = height;
  143. allocate_wl_shm_buffer(state);
  144. }
  145. }
  146. static void
  147. xdg_toplevel_close(void *data, struct xdg_toplevel *toplevel)
  148. {
  149. struct client_state *state = data;
  150. state->closed = true;
  151. }
  152. static const struct xdg_toplevel_listener xdg_toplevel_listener = {
  153. .configure = xdg_toplevel_configure,
  154. .close = xdg_toplevel_close,
  155. };
  156. static void
  157. xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial)
  158. {
  159. struct client_state *state = data;
  160. xdg_surface_ack_configure(xdg_surface, serial);
  161. draw_frame(state);
  162. wl_surface_attach(state->wl_surface, state->wl_buffer, 0, 0);
  163. wl_surface_commit(state->wl_surface);
  164. }
  165. static const struct xdg_surface_listener xdg_surface_listener = {
  166. .configure = xdg_surface_configure,
  167. };
  168. static void
  169. xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
  170. {
  171. xdg_wm_base_pong(xdg_wm_base, serial);
  172. }
  173. static const struct xdg_wm_base_listener xdg_wm_base_listener = {
  174. .ping = xdg_wm_base_ping,
  175. };
  176. static const struct wl_callback_listener wl_surface_frame_listener;
  177. static void
  178. wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time)
  179. {
  180. /* Destroy this callback */
  181. wl_callback_destroy(cb);
  182. /* Request another frame */
  183. struct client_state *state = data;
  184. cb = wl_surface_frame(state->wl_surface);
  185. wl_callback_add_listener(cb, &wl_surface_frame_listener, state);
  186. /* Update scroll amount at 24 pixels per second */
  187. if(state->last_frame != 0)
  188. {
  189. int elapsed = time - state->last_frame;
  190. state->offset += elapsed / 1000.0 * 24;
  191. }
  192. /* Submit a frame for this event */
  193. draw_frame(state);
  194. wl_surface_attach(state->wl_surface, state->wl_buffer, 0, 0);
  195. wl_surface_damage_buffer(state->wl_surface, 0, 0, INT32_MAX, INT32_MAX);
  196. wl_surface_commit(state->wl_surface);
  197. state->last_frame = time;
  198. }
  199. static const struct wl_callback_listener wl_surface_frame_listener = {
  200. .done = wl_surface_frame_done,
  201. };
  202. static void
  203. registry_global(void *data,
  204. struct wl_registry *wl_registry,
  205. uint32_t name,
  206. const char *interface,
  207. uint32_t version)
  208. {
  209. struct client_state *state = data;
  210. if(strcmp(interface, wl_shm_interface.name) == 0)
  211. {
  212. state->wl_shm = wl_registry_bind(wl_registry, name, &wl_shm_interface, 1);
  213. allocate_wl_shm_buffer(state);
  214. }
  215. else if(strcmp(interface, wl_compositor_interface.name) == 0)
  216. {
  217. state->wl_compositor = wl_registry_bind(wl_registry, name, &wl_compositor_interface, 4);
  218. }
  219. else if(strcmp(interface, xdg_wm_base_interface.name) == 0)
  220. {
  221. state->xdg_wm_base = wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1);
  222. xdg_wm_base_add_listener(state->xdg_wm_base, &xdg_wm_base_listener, state);
  223. }
  224. }
  225. static void
  226. registry_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name)
  227. {
  228. /* This space deliberately left blank */
  229. }
  230. static const struct wl_registry_listener wl_registry_listener = {
  231. .global = registry_global,
  232. .global_remove = registry_global_remove,
  233. };
  234. static void
  235. fatal(const char *message) {
  236. fputs(message, stderr);
  237. exit(EXIT_FAILURE);
  238. }
  239. int
  240. main(int argc, char *argv[])
  241. {
  242. struct client_state state = {0};
  243. state.width = 800;
  244. state.height = 600;
  245. state.closed = false;
  246. state.wl_display = wl_display_connect(NULL);
  247. if(!state.wl_display) fatal("Failed to connect to wayland display, exiting...\n");
  248. state.wl_registry = wl_display_get_registry(state.wl_display);
  249. wl_registry_add_listener(state.wl_registry, &wl_registry_listener, &state);
  250. wl_display_roundtrip(state.wl_display);
  251. if(!state.wl_shm) fatal("wl_shm protocol not found, exiting...\n");
  252. if(!state.wl_compositor) fatal("wl_compositor protocol not found, exiting...\n");
  253. if(!state.xdg_wm_base) fatal("xdg_wm_base protocol not found, exiting...\n");
  254. state.wl_surface = wl_compositor_create_surface(state.wl_compositor);
  255. state.xdg_surface = xdg_wm_base_get_xdg_surface(state.xdg_wm_base, state.wl_surface);
  256. xdg_surface_add_listener(state.xdg_surface, &xdg_surface_listener, &state);
  257. state.xdg_toplevel = xdg_surface_get_toplevel(state.xdg_surface);
  258. xdg_toplevel_add_listener(state.xdg_toplevel, &xdg_toplevel_listener, &state);
  259. xdg_toplevel_set_title(state.xdg_toplevel, "Bytemedia wayland");
  260. wl_surface_commit(state.wl_surface);
  261. struct wl_callback *cb = wl_surface_frame(state.wl_surface);
  262. wl_callback_add_listener(cb, &wl_surface_frame_listener, &state);
  263. while(wl_display_dispatch(state.wl_display) && !state.closed)
  264. {
  265. /* This space deliberately left blank */
  266. }
  267. munmap(state.shm_data, state.width * state.height * 4);
  268. return 0;
  269. }