31 #include "uwac-priv.h"
32 #include "uwac-utils.h"
35 #include <uwac/config.h>
37 #include <winpr/cast.h>
39 #define UWAC_INITIAL_BUFFERS 3ull
41 static int bppFromShmFormat(
enum wl_shm_format format)
45 case WL_SHM_FORMAT_ARGB8888:
46 case WL_SHM_FORMAT_XRGB8888:
52 static void buffer_release(
void* data,
struct wl_buffer* buffer)
54 UwacBufferReleaseData* releaseData = data;
55 UwacBuffer* uwacBuffer = &releaseData->window->buffers[releaseData->bufferIdx];
56 uwacBuffer->used =
false;
59 static const struct wl_buffer_listener buffer_listener = { buffer_release };
61 static void UwacWindowDestroyBuffers(UwacWindow* w)
63 for (
size_t i = 0; i < w->nbuffers; i++)
65 UwacBuffer* buffer = &w->buffers[i];
66 #ifdef UWAC_HAVE_PIXMAN_REGION
67 pixman_region32_fini(&buffer->damage);
69 region16_uninit(&buffer->damage);
71 UwacBufferReleaseData* releaseData =
72 (UwacBufferReleaseData*)wl_buffer_get_user_data(buffer->wayland_buffer);
73 wl_buffer_destroy(buffer->wayland_buffer);
75 munmap(buffer->data, buffer->size);
83 static int UwacWindowShmAllocBuffers(UwacWindow* w, uint64_t nbuffers, uint64_t allocSize,
84 uint32_t width, uint32_t height,
enum wl_shm_format format);
86 static void xdg_handle_toplevel_configure(
void* data,
struct xdg_toplevel* xdg_toplevel,
87 int32_t width, int32_t height,
struct wl_array* states)
89 UwacWindow* window = (UwacWindow*)data;
90 int scale = window->display->actual_scale;
91 int32_t actual_width = width;
92 int32_t actual_height = height;
95 UwacConfigureEvent*
event = NULL;
98 enum xdg_toplevel_state* state = NULL;
100 wl_array_for_each(state, states)
104 case XDG_TOPLEVEL_STATE_MAXIMIZED:
105 surfaceState |= UWAC_WINDOW_MAXIMIZED;
108 case XDG_TOPLEVEL_STATE_FULLSCREEN:
109 surfaceState |= UWAC_WINDOW_FULLSCREEN;
112 case XDG_TOPLEVEL_STATE_ACTIVATED:
113 surfaceState |= UWAC_WINDOW_ACTIVATED;
116 case XDG_TOPLEVEL_STATE_RESIZING:
117 surfaceState |= UWAC_WINDOW_RESIZING;
124 window->surfaceStates = surfaceState;
125 event = (UwacConfigureEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE);
129 assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY,
130 "failed to allocate a configure event\n"));
134 event->window = window;
135 event->states = surfaceState;
137 if ((width > 0 && height > 0) && (width != window->width || height != window->height))
139 event->width = width;
140 event->height = height;
141 UwacWindowDestroyBuffers(window);
142 window->width = width;
143 window->stride = width * bppFromShmFormat(window->format);
144 window->height = height;
146 UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, 1ull * window->stride * height,
147 width, height, window->format);
149 if (ret != UWAC_SUCCESS)
152 uwacErrorHandler(window->display, ret,
"failed to reallocate a wayland buffers\n"));
153 window->drawingBufferIdx = window->pendingBufferIdx = -1;
157 window->drawingBufferIdx = 0;
158 if (window->pendingBufferIdx != -1)
159 window->pendingBufferIdx = window->drawingBufferIdx;
161 if (window->viewport)
163 wp_viewport_set_source(window->viewport, wl_fixed_from_int(0), wl_fixed_from_int(0),
164 wl_fixed_from_int(actual_width),
165 wl_fixed_from_int(actual_height));
166 wp_viewport_set_destination(window->viewport, actual_width, actual_height);
171 event->width = window->width;
172 event->height = window->height;
176 static void xdg_handle_toplevel_close(
void* data,
struct xdg_toplevel* xdg_toplevel)
178 UwacCloseEvent*
event = NULL;
179 UwacWindow* window = (UwacWindow*)data;
180 event = (UwacCloseEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CLOSE);
184 assert(uwacErrorHandler(window->display, UWAC_ERROR_INTERNAL,
185 "failed to allocate a close event\n"));
189 event->window = window;
192 static const struct xdg_toplevel_listener xdg_toplevel_listener = {
193 xdg_handle_toplevel_configure,
194 xdg_handle_toplevel_close,
197 static void xdg_handle_surface_configure(
void* data,
struct xdg_surface* xdg_surface,
200 xdg_surface_ack_configure(xdg_surface, serial);
203 static const struct xdg_surface_listener xdg_surface_listener = {
204 .configure = xdg_handle_surface_configure,
209 static void ivi_handle_configure(
void* data,
struct ivi_surface* surface, int32_t width,
212 UwacWindow* window = (UwacWindow*)data;
213 UwacConfigureEvent*
event = NULL;
215 event = (UwacConfigureEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE);
219 assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY,
220 "failed to allocate a configure event\n"));
224 event->window = window;
229 event->width = width;
230 event->height = height;
231 UwacWindowDestroyBuffers(window);
232 window->width = width;
233 window->stride = width * bppFromShmFormat(window->format);
234 window->height = height;
236 UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, 1ull * window->stride * height,
237 width, height, window->format);
239 if (ret != UWAC_SUCCESS)
242 uwacErrorHandler(window->display, ret,
"failed to reallocate a wayland buffers\n"));
243 window->drawingBufferIdx = window->pendingBufferIdx = -1;
247 window->drawingBufferIdx = 0;
248 if (window->pendingBufferIdx != -1)
249 window->pendingBufferIdx = window->drawingBufferIdx;
253 event->width = window->width;
254 event->height = window->height;
258 static const struct ivi_surface_listener ivi_surface_listener = {
259 ivi_handle_configure,
263 static void shell_ping(
void* data,
struct wl_shell_surface* surface, uint32_t serial)
265 wl_shell_surface_pong(surface, serial);
268 static void shell_configure(
void* data,
struct wl_shell_surface* surface, uint32_t edges,
269 int32_t width, int32_t height)
271 UwacWindow* window = (UwacWindow*)data;
272 UwacConfigureEvent*
event = NULL;
274 event = (UwacConfigureEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE);
278 assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY,
279 "failed to allocate a configure event\n"));
283 event->window = window;
288 event->width = width;
289 event->height = height;
290 UwacWindowDestroyBuffers(window);
291 window->width = width;
292 window->stride = width * bppFromShmFormat(window->format);
293 window->height = height;
295 UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, 1ull * window->stride * height,
296 width, height, window->format);
298 if (ret != UWAC_SUCCESS)
301 uwacErrorHandler(window->display, ret,
"failed to reallocate a wayland buffers\n"));
302 window->drawingBufferIdx = window->pendingBufferIdx = -1;
306 window->drawingBufferIdx = 0;
307 if (window->pendingBufferIdx != -1)
308 window->pendingBufferIdx = window->drawingBufferIdx;
312 event->width = window->width;
313 event->height = window->height;
317 static void shell_popup_done(
void* data,
struct wl_shell_surface* surface)
321 static const struct wl_shell_surface_listener shell_listener = { shell_ping, shell_configure,
324 int UwacWindowShmAllocBuffers(UwacWindow* w, uint64_t nbuffers, uint64_t allocSize, uint32_t width,
325 uint32_t height,
enum wl_shm_format format)
327 int ret = UWAC_SUCCESS;
330 struct wl_shm_pool* pool = NULL;
332 if ((width > INT32_MAX) || (height > INT32_MAX))
333 return UWAC_ERROR_NOMEMORY;
335 const int64_t pagesize = sysconf(_SC_PAGESIZE);
337 return UWAC_ERROR_NOMEMORY;
340 const uint64_t test = (1ull * allocSize + (size_t)pagesize - 1ull) & ~((size_t)pagesize - 1);
341 if (test > INT64_MAX)
342 return UWAC_ERROR_NOMEMORY;
346 UwacBuffer* newBuffers =
347 xrealloc(w->buffers, (0ull + w->nbuffers + nbuffers) *
sizeof(UwacBuffer));
350 return UWAC_ERROR_NOMEMORY;
352 w->buffers = newBuffers;
353 memset(w->buffers + w->nbuffers, 0,
sizeof(UwacBuffer) * nbuffers);
355 const size_t allocbuffersize = 1ull * allocSize * nbuffers;
356 if (allocbuffersize > INT32_MAX)
357 return UWAC_ERROR_NOMEMORY;
359 fd = uwac_create_anonymous_file(WINPR_ASSERTING_INT_CAST(off_t, allocbuffersize));
363 return UWAC_ERROR_INTERNAL;
366 data = mmap(NULL, allocbuffersize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
368 if (data == MAP_FAILED)
370 ret = UWAC_ERROR_NOMEMORY;
374 pool = wl_shm_create_pool(w->display->shm, fd, (int32_t)allocbuffersize);
378 munmap(data, allocbuffersize);
379 ret = UWAC_ERROR_NOMEMORY;
383 for (uint64_t i = 0; i < nbuffers; i++)
385 const size_t idx = (size_t)i;
386 const size_t bufferIdx = w->nbuffers + idx;
387 UwacBuffer* buffer = &w->buffers[bufferIdx];
389 #ifdef UWAC_HAVE_PIXMAN_REGION
390 pixman_region32_init(&buffer->damage);
392 region16_init(&buffer->damage);
394 const size_t offset = allocSize * idx;
395 if (offset > INT32_MAX)
398 buffer->data = &((
char*)data)[allocSize * idx];
399 buffer->size = allocSize;
400 buffer->wayland_buffer = wl_shm_pool_create_buffer(pool, (int32_t)offset, (int32_t)width,
401 (int32_t)height, w->stride, format);
402 UwacBufferReleaseData* listener_data = xmalloc(
sizeof(UwacBufferReleaseData));
403 listener_data->window = w;
404 listener_data->bufferIdx = bufferIdx;
405 wl_buffer_add_listener(buffer->wayland_buffer, &buffer_listener, listener_data);
408 wl_shm_pool_destroy(pool);
409 w->nbuffers += nbuffers;
415 static UwacBuffer* UwacWindowFindFreeBuffer(UwacWindow* w, ssize_t* index)
423 for (; i < w->nbuffers; i++)
425 if (!w->buffers[i].used)
427 w->buffers[i].used =
true;
429 *index = WINPR_ASSERTING_INT_CAST(ssize_t, i);
430 return &w->buffers[i];
434 ret = UwacWindowShmAllocBuffers(w, 2, 1ull * w->stride * w->height, w->width, w->height,
437 if (ret != UWAC_SUCCESS)
439 w->display->last_error = ret;
443 w->buffers[i].used =
true;
445 *index = WINPR_ASSERTING_INT_CAST(ssize_t, i);
446 return &w->buffers[i];
449 static UwacReturnCode UwacWindowSetDecorations(UwacWindow* w)
451 if (!w || !w->display)
452 return UWAC_ERROR_INTERNAL;
454 if (w->display->deco_manager)
456 w->deco = zxdg_decoration_manager_v1_get_toplevel_decoration(w->display->deco_manager,
460 uwacErrorHandler(w->display, UWAC_NOT_FOUND,
461 "Current window manager does not allow decorating with SSD");
464 zxdg_toplevel_decoration_v1_set_mode(w->deco,
465 ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
467 else if (w->display->kde_deco_manager)
470 org_kde_kwin_server_decoration_manager_create(w->display->kde_deco_manager, w->surface);
473 uwacErrorHandler(w->display, UWAC_NOT_FOUND,
474 "Current window manager does not allow decorating with SSD");
477 org_kde_kwin_server_decoration_request_mode(w->kde_deco,
478 ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER);
483 UwacWindow* UwacCreateWindowShm(UwacDisplay* display, uint32_t width, uint32_t height,
484 enum wl_shm_format format)
486 UwacWindow* w = NULL;
494 w = xzalloc(
sizeof(*w));
498 display->last_error = UWAC_ERROR_NOMEMORY;
502 w->display = display;
504 w->width = WINPR_ASSERTING_INT_CAST(int32_t, width);
505 w->height = WINPR_ASSERTING_INT_CAST(int32_t, height);
506 w->stride = WINPR_ASSERTING_INT_CAST(int32_t, width* bppFromShmFormat(format));
507 const size_t allocSize = 1ULL * w->stride * height;
508 ret = UwacWindowShmAllocBuffers(w, UWAC_INITIAL_BUFFERS, allocSize, width, height, format);
510 if (ret != UWAC_SUCCESS)
512 display->last_error = ret;
516 w->buffers[0].used =
true;
517 w->drawingBufferIdx = 0;
518 w->pendingBufferIdx = -1;
519 w->surface = wl_compositor_create_surface(display->compositor);
523 display->last_error = UWAC_ERROR_NOMEMORY;
524 goto out_error_surface;
527 wl_surface_set_user_data(w->surface, w);
530 uint32_t ivi_surface_id = 1;
531 char* env = getenv(
"IVI_SURFACE_ID");
534 unsigned long val = 0;
538 val = strtoul(env, &endp, 10);
540 if (!errno && val != 0 && val != UINT32_MAX)
541 ivi_surface_id = val;
544 if (display->ivi_application)
547 ivi_application_surface_create(display->ivi_application, ivi_surface_id, w->surface);
548 assert(w->ivi_surface);
549 ivi_surface_add_listener(w->ivi_surface, &ivi_surface_listener, w);
553 #if BUILD_FULLSCREEN_SHELL
554 if (display->fullscreen_shell)
556 zwp_fullscreen_shell_v1_present_surface(display->fullscreen_shell, w->surface,
557 ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER,
562 if (display->xdg_base)
564 w->xdg_surface = xdg_wm_base_get_xdg_surface(display->xdg_base, w->surface);
568 display->last_error = UWAC_ERROR_NOMEMORY;
569 goto out_error_shell;
572 xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w);
574 w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface);
575 if (!w->xdg_toplevel)
577 display->last_error = UWAC_ERROR_NOMEMORY;
578 goto out_error_shell;
581 assert(w->xdg_surface);
582 xdg_toplevel_add_listener(w->xdg_toplevel, &xdg_toplevel_listener, w);
583 wl_surface_commit(w->surface);
584 wl_display_roundtrip(w->display->display);
588 w->shell_surface = wl_shell_get_shell_surface(display->shell, w->surface);
589 assert(w->shell_surface);
590 wl_shell_surface_add_listener(w->shell_surface, &shell_listener, w);
591 wl_shell_surface_set_toplevel(w->shell_surface);
594 if (display->viewporter)
596 w->viewport = wp_viewporter_get_viewport(display->viewporter, w->surface);
597 if (display->actual_scale != 1)
598 wl_surface_set_buffer_scale(w->surface, display->actual_scale);
601 wl_list_insert(display->windows.prev, &w->link);
602 display->last_error = UWAC_SUCCESS;
603 UwacWindowSetDecorations(w);
606 wl_surface_destroy(w->surface);
608 UwacWindowDestroyBuffers(w);
614 UwacReturnCode UwacDestroyWindow(UwacWindow** pwindow)
616 UwacWindow* w = NULL;
619 UwacWindowDestroyBuffers(w);
622 zxdg_toplevel_decoration_v1_destroy(w->deco);
625 org_kde_kwin_server_decoration_destroy(w->kde_deco);
628 xdg_surface_destroy(w->xdg_surface);
633 ivi_surface_destroy(w->ivi_surface);
637 if (w->opaque_region)
638 wl_region_destroy(w->opaque_region);
641 wl_region_destroy(w->input_region);
644 wp_viewport_destroy(w->viewport);
646 wl_surface_destroy(w->surface);
647 wl_list_remove(&w->link);
653 UwacReturnCode UwacWindowSetOpaqueRegion(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
658 if (window->opaque_region)
659 wl_region_destroy(window->opaque_region);
661 window->opaque_region = wl_compositor_create_region(window->display->compositor);
663 if (!window->opaque_region)
664 return UWAC_ERROR_NOMEMORY;
666 wl_region_add(window->opaque_region, WINPR_ASSERTING_INT_CAST(int32_t, x),
667 WINPR_ASSERTING_INT_CAST(int32_t, y), WINPR_ASSERTING_INT_CAST(int32_t, width),
668 WINPR_ASSERTING_INT_CAST(int32_t, height));
669 wl_surface_set_opaque_region(window->surface, window->opaque_region);
673 UwacReturnCode UwacWindowSetInputRegion(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
678 if (window->input_region)
679 wl_region_destroy(window->input_region);
681 window->input_region = wl_compositor_create_region(window->display->compositor);
683 if (!window->input_region)
684 return UWAC_ERROR_NOMEMORY;
686 wl_region_add(window->input_region, x, y, width, height);
687 wl_surface_set_input_region(window->surface, window->input_region);
691 void* UwacWindowGetDrawingBuffer(UwacWindow* window)
693 UwacBuffer* buffer = NULL;
695 if (window->drawingBufferIdx < 0)
698 buffer = &window->buffers[window->drawingBufferIdx];
705 static void frame_done_cb(
void* data,
struct wl_callback* callback, uint32_t time);
707 static const struct wl_callback_listener frame_listener = { frame_done_cb };
709 #ifdef UWAC_HAVE_PIXMAN_REGION
710 static void damage_surface(UwacWindow* window, UwacBuffer* buffer,
int scale)
713 const pixman_box32_t* box = pixman_region32_rectangles(&buffer->damage, &nrects);
715 for (
int i = 0; i < nrects; i++, box++)
717 const int x = ((int)floor(box->x1 / scale)) - 1;
718 const int y = ((int)floor(box->y1 / scale)) - 1;
719 const int w = ((int)ceil((box->x2 - box->x1) / scale)) + 2;
720 const int h = ((int)ceil((box->y2 - box->y1) / scale)) + 2;
721 wl_surface_damage(window->surface, x, y, w, h);
724 pixman_region32_clear(&buffer->damage);
727 static void damage_surface(UwacWindow* window, UwacBuffer* buffer,
int scale)
730 const RECTANGLE_16* boxes = region16_rects(&buffer->damage, &nrects);
732 for (UINT32 i = 0; i < nrects; i++)
735 const double dx = floor(1.0 * box->left / scale);
736 const double dy = floor(1.0 * box->top / scale);
737 const double dw = ceil(1.0 * (box->right - box->left) / scale);
738 const double dh = ceil(1.0 * (box->bottom - box->top) / scale);
739 const int x = ((int)dx) - 1;
740 const int y = ((int)dy) - 1;
741 const int w = ((int)dw) + 2;
742 const int h = ((int)dh) + 2;
743 wl_surface_damage(window->surface, x, y, w, h);
746 region16_clear(&buffer->damage);
750 static void UwacSubmitBufferPtr(UwacWindow* window, UwacBuffer* buffer)
752 wl_surface_attach(window->surface, buffer->wayland_buffer, 0, 0);
754 int scale = window->display->actual_scale;
755 damage_surface(window, buffer, scale);
757 struct wl_callback* frame_callback = wl_surface_frame(window->surface);
758 wl_callback_add_listener(frame_callback, &frame_listener, window);
759 wl_surface_commit(window->surface);
760 buffer->dirty =
false;
763 static void frame_done_cb(
void* data,
struct wl_callback* callback, uint32_t time)
765 UwacWindow* window = (UwacWindow*)data;
766 UwacFrameDoneEvent*
event = NULL;
768 wl_callback_destroy(callback);
769 window->pendingBufferIdx = -1;
770 event = (UwacFrameDoneEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_FRAME_DONE);
773 event->window = window;
776 #ifdef UWAC_HAVE_PIXMAN_REGION
777 UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
780 UwacBuffer* buf = NULL;
782 if (window->drawingBufferIdx < 0)
783 return UWAC_ERROR_INTERNAL;
785 buf = &window->buffers[window->drawingBufferIdx];
786 if (!pixman_region32_union_rect(&buf->damage, &buf->damage, x, y, width, height))
787 return UWAC_ERROR_INTERNAL;
793 UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
797 UwacBuffer* buf = NULL;
801 box.right = x + width;
802 box.bottom = y + height;
804 if (window->drawingBufferIdx < 0)
805 return UWAC_ERROR_INTERNAL;
807 buf = &window->buffers[window->drawingBufferIdx];
809 return UWAC_ERROR_INTERNAL;
811 if (!region16_union_rect(&buf->damage, &buf->damage, &box))
812 return UWAC_ERROR_INTERNAL;
819 UwacReturnCode UwacWindowGetDrawingBufferGeometry(UwacWindow* window, UwacSize* geometry,
822 if (!window || (window->drawingBufferIdx < 0))
823 return UWAC_ERROR_INTERNAL;
827 geometry->width = window->width;
828 geometry->height = window->height;
832 *stride = window->stride;
837 UwacReturnCode UwacWindowSubmitBuffer(UwacWindow* window,
bool copyContentForNextFrame)
839 UwacBuffer* currentDrawingBuffer = NULL;
840 UwacBuffer* nextDrawingBuffer = NULL;
841 UwacBuffer* pendingBuffer = NULL;
843 if (window->drawingBufferIdx < 0)
844 return UWAC_ERROR_INTERNAL;
846 currentDrawingBuffer = &window->buffers[window->drawingBufferIdx];
848 if ((window->pendingBufferIdx >= 0) || !currentDrawingBuffer->dirty)
851 window->pendingBufferIdx = window->drawingBufferIdx;
852 nextDrawingBuffer = UwacWindowFindFreeBuffer(window, &window->drawingBufferIdx);
853 pendingBuffer = &window->buffers[window->pendingBufferIdx];
855 if ((!nextDrawingBuffer) || (window->drawingBufferIdx < 0))
856 return UWAC_ERROR_NOMEMORY;
858 if (copyContentForNextFrame)
859 memcpy(nextDrawingBuffer->data, pendingBuffer->data,
860 1ull * window->stride * window->height);
862 UwacSubmitBufferPtr(window, pendingBuffer);
866 UwacReturnCode UwacWindowGetGeometry(UwacWindow* window, UwacSize* geometry)
870 geometry->width = window->width;
871 geometry->height = window->height;
875 UwacReturnCode UwacWindowSetFullscreenState(UwacWindow* window, UwacOutput* output,
878 if (window->xdg_toplevel)
882 xdg_toplevel_set_fullscreen(window->xdg_toplevel, output ? output->output : NULL);
886 xdg_toplevel_unset_fullscreen(window->xdg_toplevel);
889 else if (window->shell_surface)
893 wl_shell_surface_set_fullscreen(window->shell_surface,
894 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0,
895 output ? output->output : NULL);
899 wl_shell_surface_set_toplevel(window->shell_surface);
906 void UwacWindowSetTitle(UwacWindow* window,
const char* name)
908 if (window->xdg_toplevel)
909 xdg_toplevel_set_title(window->xdg_toplevel, name);
910 else if (window->shell_surface)
911 wl_shell_surface_set_title(window->shell_surface, name);
914 void UwacWindowSetAppId(UwacWindow* window,
const char* app_id)
916 if (window->xdg_toplevel)
917 xdg_toplevel_set_app_id(window->xdg_toplevel, app_id);