32#include "uwac-utils.h"
35#include <uwac/config.h>
37#include <winpr/cast.h>
39#define UWAC_INITIAL_BUFFERS 3ull
41static int bppFromShmFormat(
enum wl_shm_format format)
45 case WL_SHM_FORMAT_ARGB8888:
46 case WL_SHM_FORMAT_XRGB8888:
52static 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;
59static const struct wl_buffer_listener buffer_listener = { buffer_release };
61static 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);
83static int UwacWindowShmAllocBuffers(UwacWindow* w, uint64_t nbuffers, uint64_t allocSize,
84 uint32_t width, uint32_t height,
enum wl_shm_format format);
86static 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;
176static 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;
192static const struct xdg_toplevel_listener xdg_toplevel_listener = {
193 xdg_handle_toplevel_configure,
194 xdg_handle_toplevel_close,
197static void xdg_handle_surface_configure(
void* data,
struct xdg_surface* xdg_surface,
200 xdg_surface_ack_configure(xdg_surface, serial);
203static const struct xdg_surface_listener xdg_surface_listener = {
204 .configure = xdg_handle_surface_configure,
209static 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;
258static const struct ivi_surface_listener ivi_surface_listener = {
259 ivi_handle_configure,
263static void shell_ping(
void* data,
struct wl_shell_surface* surface, uint32_t serial)
265 wl_shell_surface_pong(surface, serial);
268static 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;
317static void shell_popup_done(
void* data,
struct wl_shell_surface* surface)
321static const struct wl_shell_surface_listener shell_listener = { shell_ping, shell_configure,
324int 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;
415static 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];
449static 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);
483UwacWindow* 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;
532 char* env = getenv(
"IVI_SURFACE_ID");
535 unsigned long val = 0;
539 val = strtoul(env, &endp, 10);
541 if (!errno && val != 0 && val != UINT32_MAX)
542 ivi_surface_id = val;
545 if (display->ivi_application)
548 ivi_application_surface_create(display->ivi_application, ivi_surface_id, w->surface);
549 assert(w->ivi_surface);
550 ivi_surface_add_listener(w->ivi_surface, &ivi_surface_listener, w);
554#if BUILD_FULLSCREEN_SHELL
555 if (display->fullscreen_shell)
557 zwp_fullscreen_shell_v1_present_surface(display->fullscreen_shell, w->surface,
558 ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER,
563 if (display->xdg_base)
565 w->xdg_surface = xdg_wm_base_get_xdg_surface(display->xdg_base, w->surface);
569 display->last_error = UWAC_ERROR_NOMEMORY;
570 goto out_error_shell;
573 xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w);
575 w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface);
576 if (!w->xdg_toplevel)
578 display->last_error = UWAC_ERROR_NOMEMORY;
579 goto out_error_shell;
582 assert(w->xdg_surface);
583 xdg_toplevel_add_listener(w->xdg_toplevel, &xdg_toplevel_listener, w);
584 wl_surface_commit(w->surface);
585 wl_display_roundtrip(w->display->display);
589 w->shell_surface = wl_shell_get_shell_surface(display->shell, w->surface);
590 assert(w->shell_surface);
591 wl_shell_surface_add_listener(w->shell_surface, &shell_listener, w);
592 wl_shell_surface_set_toplevel(w->shell_surface);
595 if (display->viewporter)
597 w->viewport = wp_viewporter_get_viewport(display->viewporter, w->surface);
598 if (display->actual_scale != 1)
599 wl_surface_set_buffer_scale(w->surface, display->actual_scale);
602 wl_list_insert(display->windows.prev, &w->link);
603 display->last_error = UWAC_SUCCESS;
604 UwacWindowSetDecorations(w);
607 wl_surface_destroy(w->surface);
609 UwacWindowDestroyBuffers(w);
615UwacReturnCode UwacDestroyWindow(UwacWindow** pwindow)
617 UwacWindow* w = NULL;
620 UwacWindowDestroyBuffers(w);
623 zxdg_toplevel_decoration_v1_destroy(w->deco);
626 org_kde_kwin_server_decoration_destroy(w->kde_deco);
629 xdg_surface_destroy(w->xdg_surface);
634 ivi_surface_destroy(w->ivi_surface);
638 if (w->opaque_region)
639 wl_region_destroy(w->opaque_region);
642 wl_region_destroy(w->input_region);
645 wp_viewport_destroy(w->viewport);
647 wl_surface_destroy(w->surface);
648 wl_list_remove(&w->link);
654UwacReturnCode UwacWindowSetOpaqueRegion(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
659 if (window->opaque_region)
660 wl_region_destroy(window->opaque_region);
662 window->opaque_region = wl_compositor_create_region(window->display->compositor);
664 if (!window->opaque_region)
665 return UWAC_ERROR_NOMEMORY;
667 wl_region_add(window->opaque_region, WINPR_ASSERTING_INT_CAST(int32_t, x),
668 WINPR_ASSERTING_INT_CAST(int32_t, y), WINPR_ASSERTING_INT_CAST(int32_t, width),
669 WINPR_ASSERTING_INT_CAST(int32_t, height));
670 wl_surface_set_opaque_region(window->surface, window->opaque_region);
674UwacReturnCode UwacWindowSetInputRegion(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
679 if (window->input_region)
680 wl_region_destroy(window->input_region);
682 window->input_region = wl_compositor_create_region(window->display->compositor);
684 if (!window->input_region)
685 return UWAC_ERROR_NOMEMORY;
687 wl_region_add(window->input_region, WINPR_ASSERTING_INT_CAST(int32_t, x),
688 WINPR_ASSERTING_INT_CAST(int32_t, y), WINPR_ASSERTING_INT_CAST(int32_t, width),
689 WINPR_ASSERTING_INT_CAST(int32_t, height));
690 wl_surface_set_input_region(window->surface, window->input_region);
694void* UwacWindowGetDrawingBuffer(UwacWindow* window)
696 UwacBuffer* buffer = NULL;
698 if (window->drawingBufferIdx < 0)
701 buffer = &window->buffers[window->drawingBufferIdx];
708static void frame_done_cb(
void* data,
struct wl_callback* callback, uint32_t time);
710static const struct wl_callback_listener frame_listener = { frame_done_cb };
712#ifdef UWAC_HAVE_PIXMAN_REGION
713static void damage_surface(UwacWindow* window, UwacBuffer* buffer,
int scale)
716 const pixman_box32_t* box = pixman_region32_rectangles(&buffer->damage, &nrects);
718 for (
int i = 0; i < nrects; i++, box++)
720 const int x = ((int)floor(box->x1 / scale)) - 1;
721 const int y = ((int)floor(box->y1 / scale)) - 1;
722 const int w = ((int)ceil((box->x2 - box->x1) / scale)) + 2;
723 const int h = ((int)ceil((box->y2 - box->y1) / scale)) + 2;
724 wl_surface_damage(window->surface, x, y, w, h);
727 pixman_region32_clear(&buffer->damage);
730static void damage_surface(UwacWindow* window, UwacBuffer* buffer,
int scale)
733 const RECTANGLE_16* boxes = region16_rects(&buffer->damage, &nrects);
735 for (UINT32 i = 0; i < nrects; i++)
738 const double dx = floor(1.0 * box->left / scale);
739 const double dy = floor(1.0 * box->top / scale);
740 const double dw = ceil(1.0 * (box->right - box->left) / scale);
741 const double dh = ceil(1.0 * (box->bottom - box->top) / scale);
742 const int x = ((int)dx) - 1;
743 const int y = ((int)dy) - 1;
744 const int w = ((int)dw) + 2;
745 const int h = ((int)dh) + 2;
746 wl_surface_damage(window->surface, x, y, w, h);
749 region16_clear(&buffer->damage);
753static void UwacSubmitBufferPtr(UwacWindow* window, UwacBuffer* buffer)
755 wl_surface_attach(window->surface, buffer->wayland_buffer, 0, 0);
757 int scale = window->display->actual_scale;
758 damage_surface(window, buffer, scale);
760 struct wl_callback* frame_callback = wl_surface_frame(window->surface);
761 wl_callback_add_listener(frame_callback, &frame_listener, window);
762 wl_surface_commit(window->surface);
763 buffer->dirty =
false;
766static void frame_done_cb(
void* data,
struct wl_callback* callback, uint32_t time)
768 UwacWindow* window = (UwacWindow*)data;
769 UwacFrameDoneEvent*
event = NULL;
771 wl_callback_destroy(callback);
772 window->pendingBufferIdx = -1;
773 event = (UwacFrameDoneEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_FRAME_DONE);
776 event->window = window;
779#ifdef UWAC_HAVE_PIXMAN_REGION
780UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
783 UwacBuffer* buf = NULL;
785 if (window->drawingBufferIdx < 0)
786 return UWAC_ERROR_INTERNAL;
788 buf = &window->buffers[window->drawingBufferIdx];
789 if (!pixman_region32_union_rect(&buf->damage, &buf->damage, x, y, width, height))
790 return UWAC_ERROR_INTERNAL;
796UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
800 UwacBuffer* buf = NULL;
804 box.right = x + width;
805 box.bottom = y + height;
807 if (window->drawingBufferIdx < 0)
808 return UWAC_ERROR_INTERNAL;
810 buf = &window->buffers[window->drawingBufferIdx];
812 return UWAC_ERROR_INTERNAL;
814 if (!region16_union_rect(&buf->damage, &buf->damage, &box))
815 return UWAC_ERROR_INTERNAL;
822UwacReturnCode UwacWindowGetDrawingBufferGeometry(UwacWindow* window, UwacSize* geometry,
825 if (!window || (window->drawingBufferIdx < 0))
826 return UWAC_ERROR_INTERNAL;
830 geometry->width = window->width;
831 geometry->height = window->height;
835 *stride = window->stride;
840UwacReturnCode UwacWindowSubmitBuffer(UwacWindow* window,
bool copyContentForNextFrame)
842 UwacBuffer* currentDrawingBuffer = NULL;
843 UwacBuffer* nextDrawingBuffer = NULL;
844 UwacBuffer* pendingBuffer = NULL;
846 if (window->drawingBufferIdx < 0)
847 return UWAC_ERROR_INTERNAL;
849 currentDrawingBuffer = &window->buffers[window->drawingBufferIdx];
851 if ((window->pendingBufferIdx >= 0) || !currentDrawingBuffer->dirty)
854 window->pendingBufferIdx = window->drawingBufferIdx;
855 nextDrawingBuffer = UwacWindowFindFreeBuffer(window, &window->drawingBufferIdx);
856 pendingBuffer = &window->buffers[window->pendingBufferIdx];
858 if ((!nextDrawingBuffer) || (window->drawingBufferIdx < 0))
859 return UWAC_ERROR_NOMEMORY;
861 if (copyContentForNextFrame)
862 memcpy(nextDrawingBuffer->data, pendingBuffer->data,
863 1ull * window->stride * window->height);
865 UwacSubmitBufferPtr(window, pendingBuffer);
869UwacReturnCode UwacWindowGetGeometry(UwacWindow* window, UwacSize* geometry)
873 geometry->width = window->width;
874 geometry->height = window->height;
878UwacReturnCode UwacWindowSetFullscreenState(UwacWindow* window, UwacOutput* output,
881 if (window->xdg_toplevel)
885 xdg_toplevel_set_fullscreen(window->xdg_toplevel, output ? output->output : NULL);
889 xdg_toplevel_unset_fullscreen(window->xdg_toplevel);
892 else if (window->shell_surface)
896 wl_shell_surface_set_fullscreen(window->shell_surface,
897 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0,
898 output ? output->output : NULL);
902 wl_shell_surface_set_toplevel(window->shell_surface);
909void UwacWindowSetTitle(UwacWindow* window,
const char* name)
911 if (window->xdg_toplevel)
912 xdg_toplevel_set_title(window->xdg_toplevel, name);
913 else if (window->shell_surface)
914 wl_shell_surface_set_title(window->shell_surface, name);
917void UwacWindowSetAppId(UwacWindow* window,
const char* app_id)
919 if (window->xdg_toplevel)
920 xdg_toplevel_set_app_id(window->xdg_toplevel, app_id);