GCC Code Coverage Report


Directory: src/gate/
File: src/gate/graphics/framebuffers.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 0 86 0.0%
Functions: 0 14 0.0%
Branches: 0 32 0.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/graphics/framebuffers.h"
30 #include "gate/atomics.h"
31 #include "gate/results.h"
32 #include "gate/times.h"
33
34 #if defined(GATE_SYS_WINSTORE)
35 # define GATE_GRAPHICS_FRAMEBUFFERS_DIRECTX
36 #elif defined(GATE_SYS_WIN16)
37 # define GATE_GRAPHICS_FRAMEBUFFERS_WIN16
38 #elif defined(GATE_SYS_WIN)
39 # define GATE_GRAPHICS_FRAMEBUFFERS_WIN32
40 #elif defined(GATE_SYS_ANDROID)
41 # define GATE_GRAPHICS_FRAMEBUFFERS_GL
42 #elif defined(GATE_SYS_OPENBSD) || defined(GATE_SYS_BEOS)
43 # define GATE_GRAPHICS_FRAMEBUFFERS_NOIMPL
44 #elif defined(GATE_SYS_DARWIN)
45 # define GATE_GRAPHICS_FRAMEBUFFERS_NOIMPL
46 #elif defined(GATE_SYS_POSIX)
47 # if defined(GATE_GRAPHICS_WAYLAND)
48 # define GATE_GRAPHICS_FRAMEBUFFERS_WAYLAND 1
49 # else
50 # if defined(HAVE_X11_HEADERS)
51 # define GATE_GRAPHICS_FRAMEBUFFERS_XLIB 1
52 # else
53 # define GATE_GRAPHICS_FRAMEBUFFERS_NOIMPL
54 # endif
55 # endif
56 #elif defined(GATE_SYS_EFI)
57 # define GATE_GRAPHICS_FRAMEBUFFERS_UGA
58 #elif defined(GATE_SYS_DOS)
59 # define GATE_GRAPHICS_FRAMEBUFFERS_INT10
60 #elif defined(GATE_SYS_WASM)
61 # define GATE_GRAPHICS_FRAMEBUFFERS_WASM
62 #else
63 # define GATE_GRAPHICS_FRAMEBUFFERS_NOIMPL
64 #endif
65
66
67
68 /**************************************************
69 * generic rasterimage framebuffer implementation *
70 **************************************************/
71
72 typedef struct rasterfb_impl
73 {
74 GATE_INTERFACE_VTBL(gate_framebuffer) const* vtbl;
75
76 gate_atomic_int_t ref_counter;
77
78 gate_rasterimage_t image_header;
79
80 gate_uint8_t image_data[8];
81 } rasterfb_t;
82
83
84 static char const* rasterfb_get_interface_name(void* obj)
85 {
86 GATE_UNUSED_ARG(obj);
87 return GATE_INTERFACE_NAME_FRAMEBUFFER;
88 }
89 static void rasterfb_release(void* obj)
90 {
91 rasterfb_t* const impl = (rasterfb_t*)obj;
92 if (0 == gate_atomic_int_dec(&impl->ref_counter))
93 {
94 gate_mem_clear(impl, sizeof(rasterfb_t));
95 gate_mem_dealloc(impl);
96 }
97 }
98 static int rasterfb_retain(void* obj)
99 {
100 rasterfb_t* const impl = (rasterfb_t*)obj;
101 return gate_atomic_int_inc(&impl->ref_counter);
102 }
103
104 static gate_result_t rasterfb_get_info(void* obj, gate_framebuffer_info_t* ptr_info)
105 {
106 rasterfb_t* const impl = (rasterfb_t*)obj;
107 gate_result_t ret = GATE_RESULT_INVALIDARG;
108 if (impl && ptr_info)
109 {
110 ptr_info->width = gate_rasterimage_width(&impl->image_header);
111 ptr_info->height = gate_rasterimage_height(&impl->image_header);
112 ptr_info->bits_per_pixel = 32;
113 ptr_info->format_id = 0;
114 ret = GATE_RESULT_OK;
115 }
116 return ret;
117 }
118 static gate_result_t rasterfb_get_property(void* obj, gate_string_t const* name, gate_property_t* prop)
119 {
120 GATE_UNUSED_ARG(obj);
121 GATE_UNUSED_ARG(name);
122 GATE_UNUSED_ARG(prop);
123 return GATE_RESULT_NOTSUPPORTED;
124 }
125 static gate_result_t rasterfb_set_property(void* obj, gate_string_t const* name, gate_property_t const* prop)
126 {
127 GATE_UNUSED_ARG(obj);
128 GATE_UNUSED_ARG(name);
129 GATE_UNUSED_ARG(prop);
130 return GATE_RESULT_NOTSUPPORTED;
131 }
132
133 static gate_result_t rasterfb_update(void* obj)
134 {
135 /* rasterimage framebuffer is always up-to-date */
136 GATE_UNUSED_ARG(obj);
137 return GATE_RESULT_OK;
138 }
139
140 static gate_result_t rasterfb_get_pixel(void* obj, gate_uint32_t x, gate_uint32_t y, gate_color_t* ptr_col)
141 {
142 rasterfb_t* const impl = (rasterfb_t*)obj;
143 return gate_rasterimage_get_pixel(&impl->image_header, x, y, ptr_col);
144 }
145 static gate_result_t rasterfb_set_pixel(void* obj, gate_uint32_t x, gate_uint32_t y, gate_color_t col)
146 {
147 rasterfb_t* const impl = (rasterfb_t*)obj;
148 return gate_rasterimage_set_pixel(&impl->image_header, x, y, &col);
149 }
150
151 static gate_result_t rasterfb_get_image(void* obj, gate_uint32_t src_x, gate_uint32_t src_y, gate_uint32_t width, gate_uint32_t height, gate_rasterimage_t* ptr_image)
152 {
153 rasterfb_t* const impl = (rasterfb_t*)obj;
154 gate_result_t ret = GATE_RESULT_FAILED;
155 gate_uint32_t fb_width = gate_rasterimage_width(&impl->image_header);
156 gate_uint32_t fb_height = gate_rasterimage_height(&impl->image_header);
157
158 if ((src_x == 0) && (src_y == 0) && (((width == 0) && (height == 0)) || ((width == fb_width) && (height == fb_height))))
159 {
160 if (gate_rasterimage_copy(ptr_image, &impl->image_header))
161 {
162 ret = GATE_RESULT_OK;
163 }
164 }
165 else
166 {
167 do
168 {
169 if (!gate_rasterimage_create(ptr_image, GATE_IMAGE_PIXELFORMAT_BGR32, width, height, NULL))
170 {
171 ret = GATE_RESULT_OUTOFMEMORY;
172 break;
173 }
174 ret = gate_rasterimage_paste_image(ptr_image, &impl->image_header, 0, 0, src_x, src_y, width, height, false);
175 if (GATE_FAILED(ret))
176 {
177 gate_rasterimage_release(ptr_image);
178 }
179 } while (0);
180 }
181 return ret;
182 }
183
184 static gate_result_t rasterfb_set_image(void* obj, gate_rasterimage_t const* ptr_image, gate_uint32_t dest_x, gate_uint32_t dest_y)
185 {
186 rasterfb_t* const impl = (rasterfb_t*)obj;
187 gate_result_t ret = GATE_RESULT_FAILED;
188 gate_uint32_t width = gate_rasterimage_width(ptr_image);
189 gate_uint32_t height = gate_rasterimage_height(ptr_image);
190
191 ret = gate_rasterimage_paste_image(&impl->image_header, ptr_image, dest_x, dest_y, 0, 0, width, height, false);
192 return ret;
193 }
194
195 static gate_result_t rasterfb_await_event(void* obj, gate_uint32_t timeout_ms, gate_framebuffer_event_t* ptr_received_evt)
196 {
197 GATE_UNUSED_ARG(obj);
198 GATE_UNUSED_ARG(timeout_ms);
199 GATE_UNUSED_ARG(ptr_received_evt);
200 return GATE_RESULT_NOTSUPPORTED;
201 }
202
203 static GATE_INTERFACE_VTBL(gate_framebuffer) gate_rasterfb_vtbl;
204 static void gate_init_rasterfb_vtbl()
205 {
206 if (!gate_rasterfb_vtbl.get_interface_name)
207 {
208 GATE_INTERFACE_VTBL(gate_framebuffer) const local_vtbl =
209 {
210 &rasterfb_get_interface_name,
211 &rasterfb_release,
212 &rasterfb_retain,
213
214 &rasterfb_get_info,
215 &rasterfb_get_property,
216 &rasterfb_set_property,
217
218 &rasterfb_update,
219
220 &rasterfb_get_pixel,
221 &rasterfb_set_pixel,
222
223 &rasterfb_get_image,
224 &rasterfb_set_image,
225
226 &rasterfb_await_event
227 };
228
229 gate_rasterfb_vtbl = local_vtbl;
230 }
231 }
232
233
234 gate_result_t gate_framebuffer_create_image(gate_uint32_t width, gate_uint32_t height, gate_framebuffer_t** ptr_framebuffer)
235 {
236 rasterfb_t* impl = NULL;
237 gate_result_t ret = GATE_RESULT_FAILED;
238 gate_size_t datasize;
239
240 do
241 {
242 datasize = sizeof(gate_color_t) * width * height;
243 impl = (rasterfb_t*)gate_mem_alloc(sizeof(rasterfb_t) + datasize);
244 if (!impl)
245 {
246 ret = GATE_RESULT_OUTOFMEMORY;
247 break;
248 }
249 gate_init_rasterfb_vtbl();
250 impl->vtbl = &gate_rasterfb_vtbl;
251 gate_atomic_int_init(&impl->ref_counter, 1);
252
253 impl->image_header.width = width;
254 impl->image_header.height = height;
255 impl->image_header.line_padding = 0;
256 impl->image_header.bits_per_pixel = sizeof(gate_color_t) * 8;
257 impl->image_header.data = &impl->image_data[0];
258 impl->image_header.databuffer = NULL;
259
260 gate_mem_clear(&impl->image_data[0], datasize);
261
262 if (ptr_framebuffer)
263 {
264 *ptr_framebuffer = (gate_framebuffer_t*)impl;
265 impl = NULL;
266 }
267 ret = GATE_RESULT_OK;
268 } while (0);
269
270 if (impl)
271 {
272 gate_mem_dealloc(impl);
273 }
274 return ret;
275 }
276
277
278
279 #if defined(GATE_GRAPHICS_FRAMEBUFFERS_DIRECTX)
280 #include "gate/graphics/platform/framebuffers_impl_directx.h"
281 #endif /* GATE_GRAPHICS_FRAMEBUFFERS_DIRECTX */
282
283
284 #if defined(GATE_GRAPHICS_FRAMEBUFFERS_WIN16)
285 #include "gate/graphics/platform/framebuffers_impl_win16.h"
286 #endif /* GATE_GRAPHICS_FRAMEBUFFERS_WIN16 */
287
288
289 #if defined(GATE_GRAPHICS_FRAMEBUFFERS_WIN32)
290 #include "gate/graphics/platform/framebuffers_impl_win32.h"
291 #endif /* GATE_GRAPHICS_FRAMEBUFFERS_WIN32 */
292
293
294 #if defined(GATE_GRAPHICS_FRAMEBUFFERS_WAYLAND)
295
296 #include "gate/graphics/platform/framebuffers_impl_wayland.h"
297 #include "gate/debugging.h"
298
299 #include "gate/graphics/framebuffers.h"
300 #include "gate/inputs.h"
301
302 #include <wayland-client.h>
303 #include <wayland-client-core.h>
304 #include <xdg-shell-client-protocol.h>
305 #include <time.h>
306 #include <unistd.h>
307 #include <sys/types.h>
308 #include <fcntl.h>
309 #include <errno.h>
310 #include <stdio.h>
311 #include <sys/mman.h>
312 #include <xkbcommon/xkbcommon.h>
313
314 typedef struct waylandfb_impl
315 {
316 GATE_INTERFACE_VTBL(gate_framebuffer) const* vtbl;
317
318 gate_atomic_int_t ref_counter;
319
320 unsigned int width;
321 unsigned int height;
322
323 struct wl_display* display;
324 struct wl_registry* registry;
325 struct wl_compositor* compositor;
326 struct wl_shm* shm;
327 struct xdg_wm_base* wm_base;
328
329 struct wl_surface* surface;
330 struct xdg_surface* xdgsurface;
331 struct xdg_toplevel* toplevel;
332
333 struct wl_seat* seat;
334 struct wl_keyboard* keyboard;
335 struct xkb_context* kb_context;
336 struct xkb_keymap* kb_keymap;
337 struct xkb_state* kb_state;
338 struct wl_pointer* pointer;
339
340 gate_rasterimage_t current_frame;
341
342 gate_arraylist_t events;
343
344 } waylandfb_t;
345
346 static void waylandfb_push_event(waylandfb_t* impl, gate_framebuffer_event_t const* evt)
347 {
348 GATE_DEBUG_TRACE("Push event");
349 gate_arraylist_add(impl->events, evt);
350 }
351
352 static gate_framebuffer_event_t const* waylandfb_get_event(waylandfb_t* impl)
353 {
354 if (gate_arraylist_length(impl->events) == 0)
355 {
356 return NULL;
357 }
358 return (gate_framebuffer_event_t const*)gate_arraylist_get(impl->events, 0);
359 }
360
361 static void waylandfb_pop_event(waylandfb_t* impl)
362 {
363 GATE_DEBUG_TRACE("Pop event");
364 gate_arraylist_remove(impl->events, 0, 1);
365 }
366
367
368
369 /********************
370 * WM_BASE events *
371 ********************/
372
373 static void xdg_wm_base_ping(void* data, struct xdg_wm_base* xdg_wm_base, uint32_t serial)
374 {
375 waylandfb_t* const impl = (waylandfb_t*)data;
376 xdg_wm_base_pong(xdg_wm_base, serial);
377 }
378
379 static const struct xdg_wm_base_listener xdg_wm_base_listener =
380 {
381 &xdg_wm_base_ping
382 };
383
384
385
386 /*********************
387 * KEYBOARD events *
388 *********************/
389
390 static void waylandfb_kb_map(void* data, struct wl_keyboard* kb, uint32_t frmt, int32_t fd, uint32_t sz)
391 {
392 waylandfb_t* const impl = (waylandfb_t*)data;
393 struct xkb_keymap* keymap = NULL;
394 struct xkb_state* keystate = NULL;
395 char* ptr_shared_map = MAP_FAILED;
396 do
397 {
398 if (frmt == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
399 {
400 if (NULL == impl->kb_context)
401 {
402 impl->kb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
403 if (NULL == impl->kb_context)
404 {
405 /* error */
406 break;
407 }
408 }
409
410 ptr_shared_map = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, fd, 0);
411 if (ptr_shared_map == MAP_FAILED)
412 {
413 /* error */
414 break;
415 }
416
417 keymap = xkb_keymap_new_from_string(impl->kb_context, ptr_shared_map, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
418 keystate = xkb_state_new(keymap);
419
420 if (keymap && keystate)
421 {
422 /* attach new objects to framebuffer object */
423 xkb_keymap_unref(impl->kb_keymap);
424 impl->kb_keymap = keymap;
425 keymap = NULL;
426
427 xkb_state_unref(impl->kb_state);
428 impl->kb_state = keystate;
429 keystate = NULL;
430 }
431 }
432
433 } while (0);
434
435 /* cleanup */
436 if (ptr_shared_map != MAP_FAILED)
437 {
438 munmap(ptr_shared_map, sz);
439 close(fd);
440 }
441 xkb_keymap_unref(keymap);
442 xkb_state_unref(keystate);
443 }
444
445 static void waylandfb_kb_enter(void* data, struct wl_keyboard* kb, uint32_t ser, struct wl_surface* srfc, struct wl_array* keys)
446 {
447 /* surface has received keyboard focus */
448 waylandfb_t* const impl = (waylandfb_t*)data;
449 uint32_t* key;
450 wl_array_for_each(key, keys)
451 {
452 xkb_keysym_t sym = xkb_state_key_get_one_sym(impl->kb_state, *key + 8);
453 /* TODO: handle already pressed keys */
454 }
455 }
456
457 static void waylandfb_kb_leave(void* data, struct wl_keyboard* kb, uint32_t ser, struct wl_surface* srfc)
458 {
459 /* surface has lost keyboard focus */
460 waylandfb_t* const impl = (waylandfb_t*)data;
461 }
462
463 static void waylandfb_kb_key(void* data, struct wl_keyboard* kb, uint32_t ser, uint32_t t, uint32_t key, uint32_t stat)
464 {
465 /* receive keyboard key */
466 waylandfb_t* const impl = (waylandfb_t*)data;
467
468 uint32_t const keycode = key + 8;
469 xkb_keysym_t const sym = xkb_state_key_get_one_sym(impl->kb_state, keycode);
470 gate_bool_t const pressed = (stat == WL_KEYBOARD_KEY_STATE_PRESSED);
471 uint32_t const chr32 = xkb_state_key_get_utf32(impl->kb_state, keycode);
472 gate_framebuffer_event_t evt;
473
474 evt.event_type = pressed ? GATE_FRAMEBUFFER_EVENT_KEY_DOWN : GATE_FRAMEBUFFER_EVENT_KEY_UP;
475 evt.event_data.key.native_code = key;
476 evt.event_data.key.key_states = 0; /* TODO */
477 evt.event_data.key.key_code = chr32;
478 evt.event_data.key.char_code = chr32;
479 waylandfb_push_event(impl, &evt);
480 }
481
482 static void waylandfb_kb_mod(void* data, struct wl_keyboard* kb, uint32_t ser, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group)
483 {
484 waylandfb_t* const impl = (waylandfb_t*)data;
485 if (impl && impl->kb_state)
486 {
487 xkb_state_update_mask(impl->kb_state, depressed, latched, locked, 0, 0, group);
488 }
489 }
490
491 static void waylandfb_kb_rep(void* data, struct wl_keyboard* kb, int32_t rate, int32_t del)
492 {
493 waylandfb_t* const impl = (waylandfb_t*)data;
494 }
495
496
497 static struct wl_keyboard_listener kb_listener =
498 {
499 &waylandfb_kb_map,
500 &waylandfb_kb_enter,
501 &waylandfb_kb_leave,
502 &waylandfb_kb_key,
503 &waylandfb_kb_mod,
504 &waylandfb_kb_rep
505 };
506
507
508
509 /***************************
510 * MOUSE / POINER events *
511 ***************************/
512
513 static void pointer_enter(void* data, struct wl_pointer* wl_pointer, uint32_t serial, struct wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y)
514 {
515 waylandfb_t* const impl = (waylandfb_t*)data;
516 }
517 static void pointer_leave(void* data, struct wl_pointer* wl_pointer, uint32_t serial, struct wl_surface* surface)
518 {
519 waylandfb_t* const impl = (waylandfb_t*)data;
520 }
521 static void pointer_motion(void* data, struct wl_pointer* wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
522 {
523 waylandfb_t* const impl = (waylandfb_t*)data;
524 }
525 static void pointer_button(void* data, struct wl_pointer* wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
526 {
527 waylandfb_t* const impl = (waylandfb_t*)data;
528 }
529 static void pointer_axis(void* data, struct wl_pointer* wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value)
530 {
531 waylandfb_t* const impl = (waylandfb_t*)data;
532 }
533 static void pointer_frame(void* data, struct wl_pointer* wl_pointer)
534 {
535 waylandfb_t* const impl = (waylandfb_t*)data;
536 }
537 static void pointer_axis_source(void* data, struct wl_pointer* wl_pointer, uint32_t axis_source)
538 {
539 waylandfb_t* const impl = (waylandfb_t*)data;
540 }
541 static void pointer_axis_stop(void* data, struct wl_pointer* wl_pointer, uint32_t time, uint32_t axis)
542 {
543 waylandfb_t* const impl = (waylandfb_t*)data;
544 }
545 static void pointer_axis_discrete(void* data, struct wl_pointer* wl_pointer, uint32_t axis, int32_t discrete)
546 {
547 waylandfb_t* const impl = (waylandfb_t*)data;
548 }
549 static void pointer_axis_value120(void* data, struct wl_pointer* wl_pointer, uint32_t axis, int32_t value120)
550 {
551 waylandfb_t* const impl = (waylandfb_t*)data;
552 }
553
554
555 static struct wl_pointer_listener pointer_listener =
556 {
557 &pointer_enter,
558 &pointer_leave,
559 &pointer_motion,
560 &pointer_button,
561 &pointer_axis,
562 &pointer_frame,
563 &pointer_axis_source,
564 &pointer_axis_stop,
565 &pointer_axis_discrete,
566 &pointer_axis_value120
567 };
568
569
570
571 /*****************
572 * SEAT events *
573 *****************/
574
575 static void seat_cap(void* data, struct wl_seat* seat, uint32_t cap)
576 {
577 waylandfb_t* const impl = (waylandfb_t*)data;
578
579 if ((cap & WL_SEAT_CAPABILITY_KEYBOARD) && (impl->keyboard == NULL))
580 {
581 impl->keyboard = wl_seat_get_keyboard(seat);
582 wl_keyboard_add_listener(impl->keyboard, &kb_listener, impl);
583 }
584 else if ((cap & WL_SEAT_CAPABILITY_POINTER) && (impl->pointer == NULL))
585 {
586 impl->pointer = wl_seat_get_pointer(seat);
587 wl_pointer_add_listener(impl->pointer, &pointer_listener, impl);
588 }
589 }
590
591 static void seat_name(void* data, struct wl_seat* seat, const char* name)
592 {
593 }
594
595 static struct wl_seat_listener seat_listener =
596 {
597 &seat_cap,
598 &seat_name
599 };
600
601
602 /*********************
603 * REGISTRY events *
604 *********************/
605
606 static void waylandfb_registry_global(void* data, struct wl_registry* wl_registry, uint32_t name, const char* interface, uint32_t version)
607 {
608 waylandfb_t* const impl = (waylandfb_t*)data;
609
610 if (gate_str_comp(interface, wl_shm_interface.name) == 0)
611 {
612 impl->shm = wl_registry_bind(wl_registry, name, &wl_shm_interface, 1);
613 }
614 else if (gate_str_comp(interface, wl_compositor_interface.name) == 0)
615 {
616 impl->compositor = wl_registry_bind(wl_registry, name, &wl_compositor_interface, 4);
617 }
618 else if (gate_str_comp(interface, xdg_wm_base_interface.name) == 0)
619 {
620 impl->wm_base = wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1);
621 xdg_wm_base_add_listener(impl->wm_base, &xdg_wm_base_listener, impl);
622 }
623 else if (gate_str_comp(interface, wl_seat_interface.name) == 0)
624 {
625 impl->seat = wl_registry_bind(wl_registry, name, &wl_seat_interface, 1);
626 wl_seat_add_listener(impl->seat, &seat_listener, impl);
627 }
628 }
629
630 static void waylandfb_registry_global_remove(void* data, struct wl_registry* wl_registry, uint32_t name)
631 {
632 waylandfb_t* const impl = (waylandfb_t*)data;
633 }
634
635 static struct wl_registry_listener const waylandfb_registry_listener =
636 {
637 &waylandfb_registry_global,
638 &waylandfb_registry_global_remove
639 };
640
641 static int open_gate_wl_shm(gate_size_t length)
642 {
643 const gate_uint32_t my_pid = (gate_uint32_t)getpid();
644 static gate_uint32_t rnd_counter = 0;
645 char buffer[255];
646 gate_strbuilder_t path;
647 int fd = -1;
648 unsigned retries = 1000;
649 int result;
650
651 do
652 {
653 gate_strbuilder_create_static(&path, buffer, sizeof(buffer), 0);
654 gate_strbuilder_append_cstr(&path, "/wl_shm-gate-fb-");
655 gate_strbuilder_append_uint32(&path, my_pid);
656 gate_strbuilder_append_cstr(&path, "-");
657 gate_strbuilder_append_uint32(&path, rnd_counter);
658
659 fd = shm_open(buffer, O_RDWR | O_CREAT | O_EXCL, 0600);
660 if (fd >= 0)
661 {
662 shm_unlink(buffer);
663 break;
664 }
665 ++rnd_counter;
666 --retries;
667 } while ((retries > 0) && (errno == EEXIST));
668
669 if (fd < 0)
670 {
671 return fd;
672 }
673
674 do
675 {
676 result = ftruncate(fd, length);
677 } while ((result < 0) && (errno == EINTR));
678
679 if (result < 0)
680 {
681 close(fd);
682 return -1;
683 }
684 return fd;
685 }
686
687 static void waylandfb_buffer_release(void* data, struct wl_buffer* wl_buffer)
688 {
689 wl_buffer_destroy(wl_buffer);
690 }
691
692 static const struct wl_buffer_listener waylandfb_buffer_listener =
693 {
694 .release = &waylandfb_buffer_release,
695 };
696
697 static struct wl_buffer* draw_frame(waylandfb_t* impl)
698 {
699 struct wl_buffer* ret = NULL;
700 int fd = -1;
701 gate_size_t stride;
702 gate_size_t length;
703 gate_uint32_t* ptr_pixels = NULL;
704 struct wl_shm_pool* pool = NULL;
705 unsigned y;
706
707 do
708 {
709 stride = (gate_size_t)impl->width * 4;
710 length = stride * (gate_size_t)impl->height;
711 fd = open_gate_wl_shm(length);
712 if (fd < 0)
713 {
714 break;
715 }
716
717 ptr_pixels = (gate_uint32_t*)mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
718 if (ptr_pixels == MAP_FAILED)
719 {
720 break;
721 }
722
723 pool = wl_shm_create_pool(impl->shm, fd, length);
724 if (pool == NULL)
725 {
726 break;
727 }
728
729 ret = wl_shm_pool_create_buffer(pool, 0, impl->width, impl->height, stride, WL_SHM_FORMAT_XRGB8888);
730
731 if (ret != NULL)
732 {
733 /* attach cleanup-callback */
734 wl_buffer_add_listener(ret, &waylandfb_buffer_listener, NULL);
735 }
736
737 if (!gate_rasterimage_is_empty(&impl->current_frame))
738 {
739 for (y = 0; y != impl->height; ++y)
740 {
741 void* ptr_src = gate_rasterimage_get_line_ptr(&impl->current_frame, y);
742 gate_uint32_t* ptr_dst = &ptr_pixels[y * impl->width];
743 gate_mem_copy(ptr_dst, ptr_src, stride);
744 }
745 }
746 } while (0);
747
748 if (pool != NULL)
749 {
750 wl_shm_pool_destroy(pool);
751 }
752
753 if (ptr_pixels != MAP_FAILED)
754 {
755 munmap(ptr_pixels, length);
756 }
757
758 if (fd >= 0)
759 {
760 close(fd);
761 }
762
763 return ret;
764 }
765
766 static void paint_frame_on_surface(waylandfb_t* impl)
767 {
768 struct wl_buffer* buffer = draw_frame(impl);
769 wl_surface_attach(impl->surface, buffer, 0, 0);
770 wl_surface_commit(impl->surface);
771 }
772
773 static void xdg_surface_configure(void* data, struct xdg_surface* xdg_surface, uint32_t serial)
774 {
775 waylandfb_t* const impl = (waylandfb_t*)data;
776 xdg_surface_ack_configure(xdg_surface, serial);
777
778 paint_frame_on_surface(impl);
779 }
780
781 static const struct xdg_surface_listener xdg_surface_listener =
782 {
783 &xdg_surface_configure,
784 };
785
786
787
788 static int waylandfb_displatch_events(waylandfb_t* impl, gate_uint32_t timeout_ms)
789 {
790 int events_dispatched;
791
792 events_dispatched = wl_display_roundtrip(impl->display);
793 /* events_dispatched = wl_display_dispatch_pending(impl->display); */
794
795 if ((timeout_ms > 0) && (events_dispatched >= 0))
796 {
797 #if 0
798 int awaited_events;
799 struct timespec timeout;
800 timeout.tv_sec = timeout_ms / 1000;
801 timeout.tv_nsec = (timeout_ms % 1000) * 1000000;
802 awaited_events = wl_display_dispatch_timeout(impl->display, &timeout);
803 if (awaited_events >= 0)
804 {
805 events_dispatched += awaited_events;
806 }
807 #endif
808 }
809 return events_dispatched;
810 }
811
812 static gate_result_t waylandfb_init(waylandfb_t* impl)
813 {
814 gate_result_t ret = GATE_RESULT_FAILED;
815 do
816 {
817 impl->display = wl_display_connect(NULL);
818 if (impl->display == NULL)
819 {
820 GATE_DEBUG_TRACE("Failed to connect to wayland display");
821 ret = GATE_RESULT_OUTOFRESOURCES;
822 break;
823 }
824
825 impl->registry = wl_display_get_registry(impl->display);
826 if (impl->registry == NULL)
827 {
828 GATE_DEBUG_TRACE("Failed to get wayland registry");
829 ret = GATE_RESULT_OUTOFRESOURCES;
830 break;
831 }
832
833 wl_registry_add_listener(impl->registry, &waylandfb_registry_listener, impl);
834 wl_display_roundtrip(impl->display);
835
836 if (impl->compositor == NULL)
837 {
838 GATE_DEBUG_TRACE("Missing wayland compositor");
839 ret = GATE_RESULT_OUTOFRESOURCES;
840 break;
841 }
842
843 impl->surface = wl_compositor_create_surface(impl->compositor);
844 if (NULL == impl->surface)
845 {
846 GATE_DEBUG_TRACE("Failed to create wayland surface");
847 ret = GATE_RESULT_OUTOFRESOURCES;
848 break;
849 }
850
851 if (impl->shm == NULL)
852 {
853 GATE_DEBUG_TRACE("Missing wayland SHM instance");
854 ret = GATE_RESULT_OUTOFRESOURCES;
855 break;
856 }
857
858 if (impl->wm_base == NULL)
859 {
860 GATE_DEBUG_TRACE("Missing wayland wm_base instance");
861 ret = GATE_RESULT_OUTOFRESOURCES;
862 break;
863 }
864
865 impl->xdgsurface = xdg_wm_base_get_xdg_surface(impl->wm_base, impl->surface);
866 if (impl->xdgsurface == NULL)
867 {
868 GATE_DEBUG_TRACE("Missing wayland XDG surface");
869 ret = GATE_RESULT_OUTOFRESOURCES;
870 break;
871 }
872
873 xdg_surface_add_listener(impl->xdgsurface, &xdg_surface_listener, impl);
874
875 impl->toplevel = xdg_surface_get_toplevel(impl->xdgsurface);
876 if (impl->toplevel == NULL)
877 {
878 GATE_DEBUG_TRACE("Missing wayland toplevel object");
879 ret = GATE_RESULT_OUTOFRESOURCES;
880 break;
881 }
882
883 xdg_toplevel_set_title(impl->toplevel, "GATE Framebuffer Window");
884
885 wl_surface_commit(impl->surface);
886
887 wl_display_roundtrip(impl->display);
888
889 ret = GATE_RESULT_OK;
890 } while (0);
891
892 return ret;
893 }
894
895 static void waylandfb_release_resources(waylandfb_t* impl)
896 {
897 if (impl->pointer)
898 {
899 wl_pointer_destroy(impl->pointer);
900 impl->pointer = NULL;
901 }
902 if (impl->keyboard)
903 {
904 wl_keyboard_destroy(impl->keyboard);
905 impl->keyboard = NULL;
906 }
907 if (impl->seat)
908 {
909 wl_seat_destroy(impl->seat);
910 impl->seat = NULL;
911 }
912 if (impl->toplevel)
913 {
914 xdg_toplevel_destroy(impl->toplevel);
915 impl->toplevel = NULL;
916 }
917
918 if (impl->xdgsurface)
919 {
920 xdg_surface_destroy(impl->xdgsurface);
921 impl->xdgsurface = NULL;
922 }
923
924 if (impl->surface)
925 {
926 wl_surface_destroy(impl->surface);
927 impl->surface = NULL;
928 }
929
930 if (impl->wm_base)
931 {
932 xdg_wm_base_destroy(impl->wm_base);
933 impl->wm_base = NULL;
934 }
935
936 if (impl->shm)
937 {
938 wl_shm_destroy(impl->shm);
939 impl->shm = NULL;
940 }
941 if (impl->compositor)
942 {
943 wl_compositor_destroy(impl->compositor);
944 impl->compositor = NULL;
945 }
946 if (impl->registry)
947 {
948 wl_registry_destroy(impl->registry);
949 impl->registry = NULL;
950 }
951 if (impl->display)
952 {
953 wl_display_disconnect(impl->display);
954 impl->display = NULL;
955 }
956 }
957
958
959 /****************************************
960 * GATE wayland framebuffer interface *
961 ****************************************/
962
963 static char const* waylandfb_get_interface_name(void* obj)
964 {
965 return GATE_INTERFACE_NAME_FRAMEBUFFER;
966 }
967
968 static void waylandfb_release(void* obj)
969 {
970 waylandfb_t* const impl = (waylandfb_t*)obj;
971 if (0 == gate_atomic_int_dec(&impl->ref_counter))
972 {
973 waylandfb_release_resources(impl);
974 gate_mem_dealloc(impl);
975 }
976 }
977 static int waylandfb_retain(void* obj)
978 {
979 waylandfb_t* const impl = (waylandfb_t*)obj;
980 return (int)gate_atomic_int_inc(&impl->ref_counter);
981 }
982
983 static gate_result_t waylandfb_get_info(void* obj, gate_framebuffer_info_t* ptr_info)
984 {
985 waylandfb_t* const impl = (waylandfb_t*)obj;
986
987 ptr_info->format_id = GATE_IMAGE_PIXELFORMAT_RGBA;
988 ptr_info->bits_per_pixel = 32;
989 ptr_info->width = impl->width;
990 ptr_info->height = impl->height;
991
992 return GATE_RESULT_OK;
993 }
994 static gate_result_t waylandfb_get_property(void* obj, gate_string_t const* name, gate_property_t* prop)
995 {
996 waylandfb_t* const impl = (waylandfb_t*)obj;
997 return GATE_RESULT_NOTIMPLEMENTED;
998 }
999 static gate_result_t waylandfb_set_property(void* obj, gate_string_t const* name, gate_property_t const* prop)
1000 {
1001 waylandfb_t* const impl = (waylandfb_t*)obj;
1002 return GATE_RESULT_NOTIMPLEMENTED;
1003 }
1004
1005 static gate_result_t waylandfb_update(void* obj)
1006 {
1007 waylandfb_t* const impl = (waylandfb_t*)obj;
1008
1009 paint_frame_on_surface(impl);
1010 wl_surface_damage(impl->surface, 0, 0, impl->width, impl->height);
1011 return GATE_RESULT_OK;
1012 }
1013
1014 static gate_result_t waylandfb_get_pixel(void* obj, gate_uint32_t x, gate_uint32_t y, gate_color_t* ptr_col)
1015 {
1016 waylandfb_t* const impl = (waylandfb_t*)obj;
1017 return GATE_RESULT_NOTIMPLEMENTED;
1018 }
1019 static gate_result_t waylandfb_set_pixel(void* obj, gate_uint32_t x, gate_uint32_t y, gate_color_t col)
1020 {
1021 waylandfb_t* const impl = (waylandfb_t*)obj;
1022 return GATE_RESULT_NOTIMPLEMENTED;
1023 }
1024
1025 static gate_result_t waylandfb_get_image(void* obj, gate_uint32_t src_x, gate_uint32_t src_y, gate_uint32_t width, gate_uint32_t height, gate_rasterimage_t* ptr_image)
1026 {
1027 waylandfb_t* const impl = (waylandfb_t*)obj;
1028 return GATE_RESULT_NOTIMPLEMENTED;
1029 }
1030 static gate_result_t waylandfb_set_image(void* obj, gate_rasterimage_t const* ptr_image, gate_uint32_t dest_x, gate_uint32_t dest_y)
1031 {
1032 waylandfb_t* const impl = (waylandfb_t*)obj;
1033 if (gate_rasterimage_is_empty(&impl->current_frame))
1034 {
1035 if (NULL == gate_rasterimage_create(&impl->current_frame, GATE_IMAGE_PIXELFORMAT_BGR32, impl->width, impl->height, NULL))
1036 {
1037 return GATE_RESULT_OUTOFMEMORY;
1038 }
1039 }
1040 return gate_rasterimage_paste_image(&impl->current_frame, ptr_image, dest_x, dest_y,
1041 0, 0, gate_rasterimage_width(ptr_image), gate_rasterimage_height(ptr_image), false);
1042 }
1043
1044 static gate_result_t waylandfb_await_event(void* obj, gate_uint32_t timeout_ms, gate_framebuffer_event_t* ptr_received_evt)
1045 {
1046 waylandfb_t* const impl = (waylandfb_t*)obj;
1047
1048 int events_dispatched = waylandfb_displatch_events(impl, timeout_ms);
1049 gate_framebuffer_event_t const* ptr_evt = waylandfb_get_event(impl);
1050
1051 if (ptr_evt != NULL)
1052 {
1053 gate_mem_copy(ptr_received_evt, ptr_evt, sizeof(gate_framebuffer_event_t));
1054 waylandfb_pop_event(impl);
1055 return GATE_RESULT_OK;
1056 }
1057
1058 if (events_dispatched == 0)
1059 {
1060 return GATE_RESULT_TIMEOUT;
1061 }
1062 else
1063 {
1064 gate_mem_clear(ptr_received_evt, sizeof(gate_framebuffer_event_t));
1065 ptr_received_evt->event_type = GATE_FRAMEBUFFER_EVENT_IDLE;
1066 return GATE_RESULT_OK;
1067 }
1068
1069 }
1070
1071 static GATE_INTERFACE_VTBL(gate_framebuffer)* gate_init_waylandfb_vtbl()
1072 {
1073 static GATE_INTERFACE_VTBL(gate_framebuffer) gate_waylandfb_vtbl;
1074 if (!gate_waylandfb_vtbl.get_interface_name)
1075 {
1076 GATE_INTERFACE_VTBL(gate_framebuffer) const local_vtbl =
1077 {
1078 &waylandfb_get_interface_name,
1079 &waylandfb_release,
1080 &waylandfb_retain,
1081
1082 &waylandfb_get_info,
1083 &waylandfb_get_property,
1084 &waylandfb_set_property,
1085
1086 &waylandfb_update,
1087
1088 &waylandfb_get_pixel,
1089 &waylandfb_set_pixel,
1090
1091 &waylandfb_get_image,
1092 &waylandfb_set_image,
1093
1094 &waylandfb_await_event
1095 };
1096 gate_waylandfb_vtbl = local_vtbl;
1097 }
1098 return &gate_waylandfb_vtbl;
1099 }
1100
1101 gate_size_t gate_framebuffer_enum_displays(gate_framebuffer_info_t* ptr_infos, gate_size_t infos_capacity)
1102 {
1103 gate_size_t ret = infos_capacity;
1104
1105 if (ret > 2)
1106 {
1107 ret = 2;
1108 }
1109
1110 if (ret >= 1)
1111 {
1112 ptr_infos[0].width = 640;
1113 ptr_infos[0].height = 480;
1114 ptr_infos[0].bits_per_pixel = 32;
1115 ptr_infos[0].format_id = 0;
1116 }
1117
1118 if (ret >= 2)
1119 {
1120 ptr_infos[1].width = 800;
1121 ptr_infos[1].height = 600;
1122 ptr_infos[1].bits_per_pixel = 32;
1123 ptr_infos[1].format_id = 0;
1124 }
1125
1126 return ret;
1127 }
1128
1129 gate_result_t gate_framebuffer_find_display(gate_uint32_t required_width, gate_uint32_t required_height, gate_framebuffer_info_t* ptr_found_display_info)
1130 {
1131 /* TODO */
1132 ptr_found_display_info->bits_per_pixel = 32;
1133 ptr_found_display_info->format_id = 0;
1134 ptr_found_display_info->width = required_width;
1135 ptr_found_display_info->height = required_height;
1136 return GATE_RESULT_OK;
1137 }
1138
1139 gate_result_t gate_framebuffer_open_display(gate_framebuffer_info_t const* ptr_infos, gate_framebuffer_t** ptr_framebuffer)
1140 {
1141 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
1142 waylandfb_t* impl = NULL;
1143
1144 do
1145 {
1146 impl = (waylandfb_t*)gate_mem_alloc(sizeof(waylandfb_t));
1147 if (impl == NULL)
1148 {
1149 ret = GATE_RESULT_OUTOFMEMORY;
1150 break;
1151 }
1152
1153 gate_mem_clear(impl, sizeof(waylandfb_t));
1154 impl->vtbl = gate_init_waylandfb_vtbl();
1155 gate_atomic_int_init(&impl->ref_counter, 1);
1156
1157 impl->width = ptr_infos->width;
1158 impl->height = ptr_infos->height;
1159
1160 impl->events = gate_arraylist_create(sizeof(gate_framebuffer_event_t), NULL, 0, NULL, NULL);
1161 if (impl->events == NULL)
1162 {
1163 ret = GATE_RESULT_OUTOFMEMORY;
1164 break;
1165 }
1166
1167 ret = waylandfb_init(impl);
1168 GATE_BREAK_IF_FAILED(ret);
1169
1170 if (ptr_framebuffer)
1171 {
1172 *ptr_framebuffer = (gate_framebuffer_t*)impl;
1173 impl = NULL;
1174 }
1175 ret = GATE_RESULT_OK;
1176
1177 } while (0);
1178
1179 if (impl)
1180 {
1181 waylandfb_release_resources(impl);
1182 gate_mem_dealloc(impl);
1183 }
1184
1185 return ret;
1186 }
1187
1188 #endif /* GATE_GRAPHICS_FRAMEBUFFERS_WAYLAND */
1189
1190 #if defined(GATE_GRAPHICS_FRAMEBUFFERS_XLIB)
1191 #include "gate/graphics/platform/framebuffers_impl_xlib.h"
1192 #endif /* GATE_GRAPHICS_FRAMEBUFFERS_XLIB */
1193
1194
1195 #if defined(GATE_GRAPHICS_FRAMEBUFFERS_GL)
1196 #include "gate/graphics/platform/framebuffers_impl_gl.h"
1197 #endif /* GATE_GRAPHICS_FRAMEBUFFERS_GL */
1198
1199
1200 #if defined(GATE_GRAPHICS_FRAMEBUFFERS_UGA)
1201 #include "gate/graphics/platform/framebuffers_impl_efigop.h"
1202 #endif /* GATE_GRAPHICS_FRAMEBUFFERS_UGA */
1203
1204
1205 #if defined(GATE_GRAPHICS_FRAMEBUFFERS_INT10)
1206 #include "gate/graphics/platform/framebuffers_impl_int10.h"
1207 #endif /* GATE_GRAPHICS_FRAMEBUFFERS_INT10 */
1208
1209
1210 #if defined(GATE_GRAPHICS_FRAMEBUFFERS_WASM)
1211 #include "gate/graphics/platform/framebuffers_impl_wasm.h"
1212 #endif /* GATE_GRAPHICS_FRAMEBUFFERS_WASM */
1213
1214 #if defined(GATE_GRAPHICS_FRAMEBUFFERS_NOIMPL)
1215
1216 gate_size_t gate_framebuffer_enum_displays(gate_framebuffer_info_t* ptr_infos, gate_size_t infos_capacity)
1217 {
1218 GATE_UNUSED_ARG(ptr_infos);
1219 GATE_UNUSED_ARG(infos_capacity);
1220 return 0;
1221 }
1222
1223 gate_result_t gate_framebuffer_find_display(gate_uint32_t required_width, gate_uint32_t required_height, gate_framebuffer_info_t* ptr_found_display_info)
1224 {
1225 GATE_UNUSED_ARG(required_width);
1226 GATE_UNUSED_ARG(required_height);
1227 GATE_UNUSED_ARG(ptr_found_display_info);
1228 return GATE_RESULT_NOMATCH;
1229 }
1230
1231 gate_result_t gate_framebuffer_open_display(gate_framebuffer_info_t const* ptr_infos, gate_framebuffer_t** ptr_framebuffer)
1232 {
1233 GATE_UNUSED_ARG(ptr_infos);
1234 GATE_UNUSED_ARG(ptr_framebuffer);
1235 return GATE_RESULT_NOMATCH;
1236 }
1237
1238
1239 #endif /* GATE_GRAPHICS_FRAMEBUFFERS_NOIMPL */
1240