31 #include "uwac-priv.h"
32 #include "uwac-utils.h"
35 #include <uwac/config.h>
37 #define UWAC_INITIAL_BUFFERS 3ull
39 static int bppFromShmFormat(
enum wl_shm_format format)
43 case WL_SHM_FORMAT_ARGB8888:
44 case WL_SHM_FORMAT_XRGB8888:
50 static void buffer_release(
void* data,
struct wl_buffer* buffer)
52 UwacBufferReleaseData* releaseData = data;
53 UwacBuffer* uwacBuffer = &releaseData->window->buffers[releaseData->bufferIdx];
54 uwacBuffer->used =
false;
57 static const struct wl_buffer_listener buffer_listener = { buffer_release };
59 static void UwacWindowDestroyBuffers(UwacWindow* w)
61 for (
size_t i = 0; i < w->nbuffers; i++)
63 UwacBuffer* buffer = &w->buffers[i];
64 #ifdef UWAC_HAVE_PIXMAN_REGION
65 pixman_region32_fini(&buffer->damage);
67 region16_uninit(&buffer->damage);
69 UwacBufferReleaseData* releaseData =
70 (UwacBufferReleaseData*)wl_buffer_get_user_data(buffer->wayland_buffer);
71 wl_buffer_destroy(buffer->wayland_buffer);
73 munmap(buffer->data, buffer->size);
81 static int UwacWindowShmAllocBuffers(UwacWindow* w, uint64_t nbuffers, uint64_t allocSize,
82 uint32_t width, uint32_t height,
enum wl_shm_format format);
84 static void xdg_handle_toplevel_configure(
void* data,
struct xdg_toplevel* xdg_toplevel,
85 int32_t width, int32_t height,
struct wl_array* states)
87 UwacWindow* window = (UwacWindow*)data;
88 int scale = window->display->actual_scale;
89 int32_t actual_width = width;
90 int32_t actual_height = height;
93 UwacConfigureEvent*
event = NULL;
96 enum xdg_toplevel_state* state = NULL;
98 wl_array_for_each(state, states)
102 case XDG_TOPLEVEL_STATE_MAXIMIZED:
103 surfaceState |= UWAC_WINDOW_MAXIMIZED;
106 case XDG_TOPLEVEL_STATE_FULLSCREEN:
107 surfaceState |= UWAC_WINDOW_FULLSCREEN;
110 case XDG_TOPLEVEL_STATE_ACTIVATED:
111 surfaceState |= UWAC_WINDOW_ACTIVATED;
114 case XDG_TOPLEVEL_STATE_RESIZING:
115 surfaceState |= UWAC_WINDOW_RESIZING;
122 window->surfaceStates = surfaceState;
123 event = (UwacConfigureEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE);
127 assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY,
128 "failed to allocate a configure event\n"));
132 event->window = window;
133 event->states = surfaceState;
135 if ((width > 0 && height > 0) && (width != window->width || height != window->height))
137 event->width = width;
138 event->height = height;
139 UwacWindowDestroyBuffers(window);
140 window->width = width;
141 window->stride = width * bppFromShmFormat(window->format);
142 window->height = height;
144 UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, 1ull * window->stride * height,
145 width, height, window->format);
147 if (ret != UWAC_SUCCESS)
150 uwacErrorHandler(window->display, ret,
"failed to reallocate a wayland buffers\n"));
151 window->drawingBufferIdx = window->pendingBufferIdx = -1;
155 window->drawingBufferIdx = 0;
156 if (window->pendingBufferIdx != -1)
157 window->pendingBufferIdx = window->drawingBufferIdx;
159 if (window->viewport)
161 wp_viewport_set_source(window->viewport, wl_fixed_from_int(0), wl_fixed_from_int(0),
162 wl_fixed_from_int(actual_width),
163 wl_fixed_from_int(actual_height));
164 wp_viewport_set_destination(window->viewport, actual_width, actual_height);
169 event->width = window->width;
170 event->height = window->height;
174 static void xdg_handle_toplevel_close(
void* data,
struct xdg_toplevel* xdg_toplevel)
176 UwacCloseEvent*
event = NULL;
177 UwacWindow* window = (UwacWindow*)data;
178 event = (UwacCloseEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CLOSE);
182 assert(uwacErrorHandler(window->display, UWAC_ERROR_INTERNAL,
183 "failed to allocate a close event\n"));
187 event->window = window;
190 static const struct xdg_toplevel_listener xdg_toplevel_listener = {
191 xdg_handle_toplevel_configure,
192 xdg_handle_toplevel_close,
195 static void xdg_handle_surface_configure(
void* data,
struct xdg_surface* xdg_surface,
198 xdg_surface_ack_configure(xdg_surface, serial);
201 static const struct xdg_surface_listener xdg_surface_listener = {
202 .configure = xdg_handle_surface_configure,
207 static void ivi_handle_configure(
void* data,
struct ivi_surface* surface, int32_t width,
210 UwacWindow* window = (UwacWindow*)data;
211 UwacConfigureEvent*
event = NULL;
213 event = (UwacConfigureEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE);
217 assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY,
218 "failed to allocate a configure event\n"));
222 event->window = window;
227 event->width = width;
228 event->height = height;
229 UwacWindowDestroyBuffers(window);
230 window->width = width;
231 window->stride = width * bppFromShmFormat(window->format);
232 window->height = height;
234 UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, 1ull * window->stride * height,
235 width, height, window->format);
237 if (ret != UWAC_SUCCESS)
240 uwacErrorHandler(window->display, ret,
"failed to reallocate a wayland buffers\n"));
241 window->drawingBufferIdx = window->pendingBufferIdx = -1;
245 window->drawingBufferIdx = 0;
246 if (window->pendingBufferIdx != -1)
247 window->pendingBufferIdx = window->drawingBufferIdx;
251 event->width = window->width;
252 event->height = window->height;
256 static const struct ivi_surface_listener ivi_surface_listener = {
257 ivi_handle_configure,
261 static void shell_ping(
void* data,
struct wl_shell_surface* surface, uint32_t serial)
263 wl_shell_surface_pong(surface, serial);
266 static void shell_configure(
void* data,
struct wl_shell_surface* surface, uint32_t edges,
267 int32_t width, int32_t height)
269 UwacWindow* window = (UwacWindow*)data;
270 UwacConfigureEvent*
event = NULL;
272 event = (UwacConfigureEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE);
276 assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY,
277 "failed to allocate a configure event\n"));
281 event->window = window;
286 event->width = width;
287 event->height = height;
288 UwacWindowDestroyBuffers(window);
289 window->width = width;
290 window->stride = width * bppFromShmFormat(window->format);
291 window->height = height;
293 UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, 1ull * window->stride * height,
294 width, height, window->format);
296 if (ret != UWAC_SUCCESS)
299 uwacErrorHandler(window->display, ret,
"failed to reallocate a wayland buffers\n"));
300 window->drawingBufferIdx = window->pendingBufferIdx = -1;
304 window->drawingBufferIdx = 0;
305 if (window->pendingBufferIdx != -1)
306 window->pendingBufferIdx = window->drawingBufferIdx;
310 event->width = window->width;
311 event->height = window->height;
315 static void shell_popup_done(
void* data,
struct wl_shell_surface* surface)
319 static const struct wl_shell_surface_listener shell_listener = { shell_ping, shell_configure,
322 int UwacWindowShmAllocBuffers(UwacWindow* w, uint64_t nbuffers, uint64_t allocSize, uint32_t width,
323 uint32_t height,
enum wl_shm_format format)
325 int ret = UWAC_SUCCESS;
328 struct wl_shm_pool* pool = NULL;
330 if ((width > INT32_MAX) || (height > INT32_MAX))
331 return UWAC_ERROR_NOMEMORY;
333 const int64_t pagesize = sysconf(_SC_PAGESIZE);
335 return UWAC_ERROR_NOMEMORY;
338 const uint64_t test = (1ull * allocSize + (size_t)pagesize - 1ull) & ~((size_t)pagesize - 1);
339 if (test > INT64_MAX)
340 return UWAC_ERROR_NOMEMORY;
344 UwacBuffer* newBuffers =
345 xrealloc(w->buffers, (0ull + w->nbuffers + nbuffers) *
sizeof(UwacBuffer));
348 return UWAC_ERROR_NOMEMORY;
350 w->buffers = newBuffers;
351 memset(w->buffers + w->nbuffers, 0,
sizeof(UwacBuffer) * nbuffers);
353 const size_t allocbuffersize = 1ull * allocSize * nbuffers;
354 if (allocbuffersize > INT32_MAX)
355 return UWAC_ERROR_NOMEMORY;
357 fd = uwac_create_anonymous_file((off_t)allocbuffersize);
361 return UWAC_ERROR_INTERNAL;
364 data = mmap(NULL, allocbuffersize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
366 if (data == MAP_FAILED)
368 ret = UWAC_ERROR_NOMEMORY;
372 pool = wl_shm_create_pool(w->display->shm, fd, (int32_t)allocbuffersize);
376 munmap(data, allocbuffersize);
377 ret = UWAC_ERROR_NOMEMORY;
381 for (uint64_t i = 0; i < nbuffers; i++)
383 const size_t idx = (size_t)i;
384 const size_t bufferIdx = w->nbuffers + idx;
385 UwacBuffer* buffer = &w->buffers[bufferIdx];
387 #ifdef UWAC_HAVE_PIXMAN_REGION
388 pixman_region32_init(&buffer->damage);
390 region16_init(&buffer->damage);
392 const size_t offset = allocSize * idx;
393 if (offset > INT32_MAX)
396 buffer->data = &((
char*)data)[allocSize * idx];
397 buffer->size = allocSize;
398 buffer->wayland_buffer = wl_shm_pool_create_buffer(pool, (int32_t)offset, (int32_t)width,
399 (int32_t)height, w->stride, format);
400 UwacBufferReleaseData* listener_data = xmalloc(
sizeof(UwacBufferReleaseData));
401 listener_data->window = w;
402 listener_data->bufferIdx = bufferIdx;
403 wl_buffer_add_listener(buffer->wayland_buffer, &buffer_listener, listener_data);
406 wl_shm_pool_destroy(pool);
407 w->nbuffers += nbuffers;
413 static UwacBuffer* UwacWindowFindFreeBuffer(UwacWindow* w, ssize_t* index)
421 for (; i < w->nbuffers; i++)
423 if (!w->buffers[i].used)
425 w->buffers[i].used =
true;
428 return &w->buffers[i];
432 ret = UwacWindowShmAllocBuffers(w, 2, 1ull * w->stride * w->height, w->width, w->height,
435 if (ret != UWAC_SUCCESS)
437 w->display->last_error = ret;
441 w->buffers[i].used =
true;
444 return &w->buffers[i];
447 static UwacReturnCode UwacWindowSetDecorations(UwacWindow* w)
449 if (!w || !w->display)
450 return UWAC_ERROR_INTERNAL;
452 if (w->display->deco_manager)
454 w->deco = zxdg_decoration_manager_v1_get_toplevel_decoration(w->display->deco_manager,
458 uwacErrorHandler(w->display, UWAC_NOT_FOUND,
459 "Current window manager does not allow decorating with SSD");
462 zxdg_toplevel_decoration_v1_set_mode(w->deco,
463 ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
465 else if (w->display->kde_deco_manager)
468 org_kde_kwin_server_decoration_manager_create(w->display->kde_deco_manager, w->surface);
471 uwacErrorHandler(w->display, UWAC_NOT_FOUND,
472 "Current window manager does not allow decorating with SSD");
475 org_kde_kwin_server_decoration_request_mode(w->kde_deco,
476 ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER);
481 UwacWindow* UwacCreateWindowShm(UwacDisplay* display, uint32_t width, uint32_t height,
482 enum wl_shm_format format)
484 UwacWindow* w = NULL;
493 w = xzalloc(
sizeof(*w));
497 display->last_error = UWAC_ERROR_NOMEMORY;
501 w->display = display;
505 w->stride = width * bppFromShmFormat(format);
506 allocSize = w->stride * height;
507 ret = UwacWindowShmAllocBuffers(w, UWAC_INITIAL_BUFFERS, allocSize, width, height, format);
509 if (ret != UWAC_SUCCESS)
511 display->last_error = ret;
515 w->buffers[0].used =
true;
516 w->drawingBufferIdx = 0;
517 w->pendingBufferIdx = -1;
518 w->surface = wl_compositor_create_surface(display->compositor);
522 display->last_error = UWAC_ERROR_NOMEMORY;
523 goto out_error_surface;
526 wl_surface_set_user_data(w->surface, w);
529 uint32_t ivi_surface_id = 1;
530 char* env = getenv(
"IVI_SURFACE_ID");
533 unsigned long val = 0;
537 val = strtoul(env, &endp, 10);
539 if (!errno && val != 0 && val != UINT32_MAX)
540 ivi_surface_id = val;
543 if (display->ivi_application)
546 ivi_application_surface_create(display->ivi_application, ivi_surface_id, w->surface);
547 assert(w->ivi_surface);
548 ivi_surface_add_listener(w->ivi_surface, &ivi_surface_listener, w);
552 #if BUILD_FULLSCREEN_SHELL
553 if (display->fullscreen_shell)
555 zwp_fullscreen_shell_v1_present_surface(display->fullscreen_shell, w->surface,
556 ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER,
561 if (display->xdg_base)
563 w->xdg_surface = xdg_wm_base_get_xdg_surface(display->xdg_base, w->surface);
567 display->last_error = UWAC_ERROR_NOMEMORY;
568 goto out_error_shell;
571 xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w);
573 w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface);
574 if (!w->xdg_toplevel)
576 display->last_error = UWAC_ERROR_NOMEMORY;
577 goto out_error_shell;
580 assert(w->xdg_surface);
581 xdg_toplevel_add_listener(w->xdg_toplevel, &xdg_toplevel_listener, w);
582 wl_surface_commit(w->surface);
583 wl_display_roundtrip(w->display->display);
587 w->shell_surface = wl_shell_get_shell_surface(display->shell, w->surface);
588 assert(w->shell_surface);
589 wl_shell_surface_add_listener(w->shell_surface, &shell_listener, w);
590 wl_shell_surface_set_toplevel(w->shell_surface);
593 if (display->viewporter)
595 w->viewport = wp_viewporter_get_viewport(display->viewporter, w->surface);
596 if (display->actual_scale != 1)
597 wl_surface_set_buffer_scale(w->surface, display->actual_scale);
600 wl_list_insert(display->windows.prev, &w->link);
601 display->last_error = UWAC_SUCCESS;
602 UwacWindowSetDecorations(w);
605 wl_surface_destroy(w->surface);
607 UwacWindowDestroyBuffers(w);
613 UwacReturnCode UwacDestroyWindow(UwacWindow** pwindow)
615 UwacWindow* w = NULL;
618 UwacWindowDestroyBuffers(w);
621 zxdg_toplevel_decoration_v1_destroy(w->deco);
624 org_kde_kwin_server_decoration_destroy(w->kde_deco);
627 xdg_surface_destroy(w->xdg_surface);
632 ivi_surface_destroy(w->ivi_surface);
636 if (w->opaque_region)
637 wl_region_destroy(w->opaque_region);
640 wl_region_destroy(w->input_region);
643 wp_viewport_destroy(w->viewport);
645 wl_surface_destroy(w->surface);
646 wl_list_remove(&w->link);
652 UwacReturnCode UwacWindowSetOpaqueRegion(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
657 if (window->opaque_region)
658 wl_region_destroy(window->opaque_region);
660 window->opaque_region = wl_compositor_create_region(window->display->compositor);
662 if (!window->opaque_region)
663 return UWAC_ERROR_NOMEMORY;
665 wl_region_add(window->opaque_region, x, y, width, height);
666 wl_surface_set_opaque_region(window->surface, window->opaque_region);
670 UwacReturnCode UwacWindowSetInputRegion(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
675 if (window->input_region)
676 wl_region_destroy(window->input_region);
678 window->input_region = wl_compositor_create_region(window->display->compositor);
680 if (!window->input_region)
681 return UWAC_ERROR_NOMEMORY;
683 wl_region_add(window->input_region, x, y, width, height);
684 wl_surface_set_input_region(window->surface, window->input_region);
688 void* UwacWindowGetDrawingBuffer(UwacWindow* window)
690 UwacBuffer* buffer = NULL;
692 if (window->drawingBufferIdx < 0)
695 buffer = &window->buffers[window->drawingBufferIdx];
702 static void frame_done_cb(
void* data,
struct wl_callback* callback, uint32_t time);
704 static const struct wl_callback_listener frame_listener = { frame_done_cb };
706 #ifdef UWAC_HAVE_PIXMAN_REGION
707 static void damage_surface(UwacWindow* window, UwacBuffer* buffer,
int scale)
710 const pixman_box32_t* box = pixman_region32_rectangles(&buffer->damage, &nrects);
712 for (
int i = 0; i < nrects; i++, box++)
714 const int x = ((int)floor(box->x1 / scale)) - 1;
715 const int y = ((int)floor(box->y1 / scale)) - 1;
716 const int w = ((int)ceil((box->x2 - box->x1) / scale)) + 2;
717 const int h = ((int)ceil((box->y2 - box->y1) / scale)) + 2;
718 wl_surface_damage(window->surface, x, y, w, h);
721 pixman_region32_clear(&buffer->damage);
724 static void damage_surface(UwacWindow* window, UwacBuffer* buffer,
int scale)
727 const RECTANGLE_16* boxes = region16_rects(&buffer->damage, &nrects);
729 for (UINT32 i = 0; i < nrects; i++)
732 const double dx = floor(1.0 * box->left / scale);
733 const double dy = floor(1.0 * box->top / scale);
734 const double dw = ceil(1.0 * (box->right - box->left) / scale);
735 const double dh = ceil(1.0 * (box->bottom - box->top) / scale);
736 const int x = ((int)dx) - 1;
737 const int y = ((int)dy) - 1;
738 const int w = ((int)dw) + 2;
739 const int h = ((int)dh) + 2;
740 wl_surface_damage(window->surface, x, y, w, h);
743 region16_clear(&buffer->damage);
747 static void UwacSubmitBufferPtr(UwacWindow* window, UwacBuffer* buffer)
749 wl_surface_attach(window->surface, buffer->wayland_buffer, 0, 0);
751 int scale = window->display->actual_scale;
752 damage_surface(window, buffer, scale);
754 struct wl_callback* frame_callback = wl_surface_frame(window->surface);
755 wl_callback_add_listener(frame_callback, &frame_listener, window);
756 wl_surface_commit(window->surface);
757 buffer->dirty =
false;
760 static void frame_done_cb(
void* data,
struct wl_callback* callback, uint32_t time)
762 UwacWindow* window = (UwacWindow*)data;
763 UwacFrameDoneEvent*
event = NULL;
765 wl_callback_destroy(callback);
766 window->pendingBufferIdx = -1;
767 event = (UwacFrameDoneEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_FRAME_DONE);
770 event->window = window;
773 #ifdef UWAC_HAVE_PIXMAN_REGION
774 UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
777 UwacBuffer* buf = NULL;
779 if (window->drawingBufferIdx < 0)
780 return UWAC_ERROR_INTERNAL;
782 buf = &window->buffers[window->drawingBufferIdx];
783 if (!pixman_region32_union_rect(&buf->damage, &buf->damage, x, y, width, height))
784 return UWAC_ERROR_INTERNAL;
790 UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
794 UwacBuffer* buf = NULL;
798 box.right = x + width;
799 box.bottom = y + height;
801 if (window->drawingBufferIdx < 0)
802 return UWAC_ERROR_INTERNAL;
804 buf = &window->buffers[window->drawingBufferIdx];
806 return UWAC_ERROR_INTERNAL;
808 if (!region16_union_rect(&buf->damage, &buf->damage, &box))
809 return UWAC_ERROR_INTERNAL;
816 UwacReturnCode UwacWindowGetDrawingBufferGeometry(UwacWindow* window, UwacSize* geometry,
819 if (!window || (window->drawingBufferIdx < 0))
820 return UWAC_ERROR_INTERNAL;
824 geometry->width = window->width;
825 geometry->height = window->height;
829 *stride = window->stride;
834 UwacReturnCode UwacWindowSubmitBuffer(UwacWindow* window,
bool copyContentForNextFrame)
836 UwacBuffer* currentDrawingBuffer = NULL;
837 UwacBuffer* nextDrawingBuffer = NULL;
838 UwacBuffer* pendingBuffer = NULL;
840 if (window->drawingBufferIdx < 0)
841 return UWAC_ERROR_INTERNAL;
843 currentDrawingBuffer = &window->buffers[window->drawingBufferIdx];
845 if ((window->pendingBufferIdx >= 0) || !currentDrawingBuffer->dirty)
848 window->pendingBufferIdx = window->drawingBufferIdx;
849 nextDrawingBuffer = UwacWindowFindFreeBuffer(window, &window->drawingBufferIdx);
850 pendingBuffer = &window->buffers[window->pendingBufferIdx];
852 if ((!nextDrawingBuffer) || (window->drawingBufferIdx < 0))
853 return UWAC_ERROR_NOMEMORY;
855 if (copyContentForNextFrame)
856 memcpy(nextDrawingBuffer->data, pendingBuffer->data,
857 1ull * window->stride * window->height);
859 UwacSubmitBufferPtr(window, pendingBuffer);
863 UwacReturnCode UwacWindowGetGeometry(UwacWindow* window, UwacSize* geometry)
867 geometry->width = window->width;
868 geometry->height = window->height;
872 UwacReturnCode UwacWindowSetFullscreenState(UwacWindow* window, UwacOutput* output,
875 if (window->xdg_toplevel)
879 xdg_toplevel_set_fullscreen(window->xdg_toplevel, output ? output->output : NULL);
883 xdg_toplevel_unset_fullscreen(window->xdg_toplevel);
886 else if (window->shell_surface)
890 wl_shell_surface_set_fullscreen(window->shell_surface,
891 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0,
892 output ? output->output : NULL);
896 wl_shell_surface_set_toplevel(window->shell_surface);
903 void UwacWindowSetTitle(UwacWindow* window,
const char* name)
905 if (window->xdg_toplevel)
906 xdg_toplevel_set_title(window->xdg_toplevel, name);
907 else if (window->shell_surface)
908 wl_shell_surface_set_title(window->shell_surface, name);
911 void UwacWindowSetAppId(UwacWindow* window,
const char* app_id)
913 if (window->xdg_toplevel)
914 xdg_toplevel_set_app_id(window->xdg_toplevel, app_id);