windowscodecs: Enable WICPixelFormat32bppBGRA in BMP encoder.
[wine.git] / dlls / winewayland.drv / wayland_surface.c
blob5a808b3ac969dc036a78f0cf727c3814ff37fdc0
1 /*
2 * Wayland surfaces
4 * Copyright 2020 Alexandros Frantzis for Collabora Ltd
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
27 #include <stdlib.h>
28 #include <unistd.h>
30 #include "waylanddrv.h"
31 #include "wine/debug.h"
32 #include "wine/server.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
36 static void xdg_surface_handle_configure(void *data, struct xdg_surface *xdg_surface,
37 uint32_t serial)
39 struct wayland_surface *surface;
40 BOOL initial_configure = FALSE;
41 HWND hwnd = data;
43 TRACE("serial=%u\n", serial);
45 if (!(surface = wayland_surface_lock_hwnd(hwnd))) return;
47 /* Handle this event only if wayland_surface is still associated with
48 * the target xdg_surface. */
49 if (surface->xdg_surface == xdg_surface)
51 /* If we have a previously requested config, we have already sent a
52 * WM_WAYLAND_CONFIGURE which hasn't been handled yet. In that case,
53 * avoid sending another message to reduce message queue traffic. */
54 BOOL should_post = surface->requested.serial == 0;
55 initial_configure = surface->current.serial == 0;
56 surface->pending.serial = serial;
57 surface->requested = surface->pending;
58 memset(&surface->pending, 0, sizeof(surface->pending));
59 if (should_post) NtUserPostMessage(hwnd, WM_WAYLAND_CONFIGURE, 0, 0);
62 pthread_mutex_unlock(&surface->mutex);
64 /* Flush the window surface in case there is content that we weren't
65 * able to flush before due to the lack of the initial configure. */
66 if (initial_configure) wayland_window_flush(hwnd);
69 static const struct xdg_surface_listener xdg_surface_listener =
71 xdg_surface_handle_configure
74 static void xdg_toplevel_handle_configure(void *data,
75 struct xdg_toplevel *xdg_toplevel,
76 int32_t width, int32_t height,
77 struct wl_array *states)
79 struct wayland_surface *surface;
80 HWND hwnd = data;
81 uint32_t *state;
82 enum wayland_surface_config_state config_state = 0;
84 wl_array_for_each(state, states)
86 switch(*state)
88 case XDG_TOPLEVEL_STATE_MAXIMIZED:
89 config_state |= WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED;
90 break;
91 case XDG_TOPLEVEL_STATE_RESIZING:
92 config_state |= WAYLAND_SURFACE_CONFIG_STATE_RESIZING;
93 break;
94 case XDG_TOPLEVEL_STATE_TILED_LEFT:
95 case XDG_TOPLEVEL_STATE_TILED_RIGHT:
96 case XDG_TOPLEVEL_STATE_TILED_TOP:
97 case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
98 config_state |= WAYLAND_SURFACE_CONFIG_STATE_TILED;
99 break;
100 case XDG_TOPLEVEL_STATE_FULLSCREEN:
101 config_state |= WAYLAND_SURFACE_CONFIG_STATE_FULLSCREEN;
102 break;
103 default:
104 break;
108 TRACE("hwnd=%p %dx%d,%#x\n", hwnd, width, height, config_state);
110 if (!(surface = wayland_surface_lock_hwnd(hwnd))) return;
112 if (surface->xdg_toplevel == xdg_toplevel)
114 surface->pending.width = width;
115 surface->pending.height = height;
116 surface->pending.state = config_state;
119 pthread_mutex_unlock(&surface->mutex);
122 static void xdg_toplevel_handle_close(void *data, struct xdg_toplevel *xdg_toplevel)
124 NtUserPostMessage((HWND)data, WM_SYSCOMMAND, SC_CLOSE, 0);
127 static const struct xdg_toplevel_listener xdg_toplevel_listener =
129 xdg_toplevel_handle_configure,
130 xdg_toplevel_handle_close
133 /**********************************************************************
134 * wayland_surface_create
136 * Creates a role-less wayland surface.
138 struct wayland_surface *wayland_surface_create(HWND hwnd)
140 struct wayland_surface *surface;
142 surface = calloc(1, sizeof(*surface));
143 if (!surface)
145 ERR("Failed to allocate space for Wayland surface\n");
146 goto err;
149 TRACE("surface=%p\n", surface);
151 pthread_mutex_init(&surface->mutex, NULL);
153 surface->hwnd = hwnd;
154 surface->wl_surface = wl_compositor_create_surface(process_wayland.wl_compositor);
155 if (!surface->wl_surface)
157 ERR("Failed to create wl_surface Wayland surface\n");
158 goto err;
160 wl_surface_set_user_data(surface->wl_surface, hwnd);
162 if (process_wayland.wp_viewporter)
164 surface->wp_viewport =
165 wp_viewporter_get_viewport(process_wayland.wp_viewporter,
166 surface->wl_surface);
169 surface->window.scale = 1.0;
171 return surface;
173 err:
174 if (surface) wayland_surface_destroy(surface);
175 return NULL;
178 /**********************************************************************
179 * wayland_surface_destroy
181 * Destroys a wayland surface.
183 void wayland_surface_destroy(struct wayland_surface *surface)
185 pthread_mutex_lock(&process_wayland.pointer.mutex);
186 if (process_wayland.pointer.focused_hwnd == surface->hwnd)
188 process_wayland.pointer.focused_hwnd = NULL;
189 process_wayland.pointer.enter_serial = 0;
191 pthread_mutex_unlock(&process_wayland.pointer.mutex);
193 pthread_mutex_lock(&process_wayland.keyboard.mutex);
194 if (process_wayland.keyboard.focused_hwnd == surface->hwnd)
195 process_wayland.keyboard.focused_hwnd = NULL;
196 pthread_mutex_unlock(&process_wayland.keyboard.mutex);
198 pthread_mutex_lock(&surface->mutex);
200 if (surface->wp_viewport)
202 wp_viewport_destroy(surface->wp_viewport);
203 surface->wp_viewport = NULL;
206 if (surface->xdg_toplevel)
208 xdg_toplevel_destroy(surface->xdg_toplevel);
209 surface->xdg_toplevel = NULL;
212 if (surface->xdg_surface)
214 xdg_surface_destroy(surface->xdg_surface);
215 surface->xdg_surface = NULL;
218 if (surface->wl_surface)
220 wl_surface_destroy(surface->wl_surface);
221 surface->wl_surface = NULL;
224 pthread_mutex_unlock(&surface->mutex);
226 if (surface->latest_window_buffer)
227 wayland_shm_buffer_unref(surface->latest_window_buffer);
229 wl_display_flush(process_wayland.wl_display);
231 pthread_mutex_destroy(&surface->mutex);
233 free(surface);
236 /**********************************************************************
237 * wayland_surface_make_toplevel
239 * Gives the toplevel role to a plain wayland surface.
241 void wayland_surface_make_toplevel(struct wayland_surface *surface)
243 TRACE("surface=%p\n", surface);
245 surface->xdg_surface =
246 xdg_wm_base_get_xdg_surface(process_wayland.xdg_wm_base, surface->wl_surface);
247 if (!surface->xdg_surface) goto err;
248 xdg_surface_add_listener(surface->xdg_surface, &xdg_surface_listener, surface->hwnd);
250 surface->xdg_toplevel = xdg_surface_get_toplevel(surface->xdg_surface);
251 if (!surface->xdg_toplevel) goto err;
252 xdg_toplevel_add_listener(surface->xdg_toplevel, &xdg_toplevel_listener, surface->hwnd);
254 wl_surface_commit(surface->wl_surface);
255 wl_display_flush(process_wayland.wl_display);
257 return;
259 err:
260 wayland_surface_clear_role(surface);
261 ERR("Failed to assign toplevel role to wayland surface\n");
264 /**********************************************************************
265 * wayland_surface_clear_role
267 * Clears the role related Wayland objects of a Wayland surface, making it a
268 * plain surface again. We can later assign the same role (but not a
269 * different one!) to the surface.
271 void wayland_surface_clear_role(struct wayland_surface *surface)
273 TRACE("surface=%p\n", surface);
275 if (surface->xdg_toplevel)
277 xdg_toplevel_destroy(surface->xdg_toplevel);
278 surface->xdg_toplevel = NULL;
281 if (surface->xdg_surface)
283 xdg_surface_destroy(surface->xdg_surface);
284 surface->xdg_surface = NULL;
287 memset(&surface->pending, 0, sizeof(surface->pending));
288 memset(&surface->requested, 0, sizeof(surface->requested));
289 memset(&surface->processing, 0, sizeof(surface->processing));
290 memset(&surface->current, 0, sizeof(surface->current));
292 /* Ensure no buffer is attached, otherwise future role assignments may fail. */
293 wl_surface_attach(surface->wl_surface, NULL, 0, 0);
294 wl_surface_commit(surface->wl_surface);
296 wl_display_flush(process_wayland.wl_display);
299 /**********************************************************************
300 * wayland_surface_attach_shm
302 * Attaches a SHM buffer to a wayland surface.
304 * The buffer is marked as unavailable until committed and subsequently
305 * released by the compositor.
307 void wayland_surface_attach_shm(struct wayland_surface *surface,
308 struct wayland_shm_buffer *shm_buffer,
309 HRGN surface_damage_region)
311 RGNDATA *surface_damage;
313 TRACE("surface=%p shm_buffer=%p (%dx%d)\n",
314 surface, shm_buffer, shm_buffer->width, shm_buffer->height);
316 shm_buffer->busy = TRUE;
317 wayland_shm_buffer_ref(shm_buffer);
319 wl_surface_attach(surface->wl_surface, shm_buffer->wl_buffer, 0, 0);
321 /* Add surface damage, i.e., which parts of the surface have changed since
322 * the last surface commit. Note that this is different from the buffer
323 * damage region. */
324 surface_damage = get_region_data(surface_damage_region);
325 if (surface_damage)
327 RECT *rgn_rect = (RECT *)surface_damage->Buffer;
328 RECT *rgn_rect_end = rgn_rect + surface_damage->rdh.nCount;
330 for (;rgn_rect < rgn_rect_end; rgn_rect++)
332 wl_surface_damage_buffer(surface->wl_surface,
333 rgn_rect->left, rgn_rect->top,
334 rgn_rect->right - rgn_rect->left,
335 rgn_rect->bottom - rgn_rect->top);
337 free(surface_damage);
341 /**********************************************************************
342 * wayland_surface_config_is_compatible
344 * Checks whether a wayland_surface_config object is compatible with the
345 * the provided arguments.
347 BOOL wayland_surface_config_is_compatible(struct wayland_surface_config *conf,
348 int width, int height,
349 enum wayland_surface_config_state state)
351 static enum wayland_surface_config_state mask =
352 WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED;
354 /* We require the same state. */
355 if ((state & mask) != (conf->state & mask)) return FALSE;
357 /* The maximized state requires the configured size. During surface
358 * reconfiguration we can use surface geometry to provide smaller areas
359 * from larger sizes, so only smaller sizes are incompatible. */
360 if ((conf->state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) &&
361 (width < conf->width || height < conf->height))
363 return FALSE;
366 /* The fullscreen state requires a size smaller or equal to the configured
367 * size. If we have a larger size, we can use surface geometry during
368 * surface reconfiguration to provide the smaller size, so we are always
369 * compatible with a fullscreen state. */
371 return TRUE;
374 /**********************************************************************
375 * wayland_surface_get_rect_in_monitor
377 * Gets the largest rectangle within a surface's window (in window coordinates)
378 * that is visible in a monitor.
380 static void wayland_surface_get_rect_in_monitor(struct wayland_surface *surface,
381 RECT *rect)
383 HMONITOR hmonitor;
384 MONITORINFO mi;
386 mi.cbSize = sizeof(mi);
387 if (!(hmonitor = NtUserMonitorFromRect(&surface->window.rect, 0)) ||
388 !NtUserGetMonitorInfo(hmonitor, (MONITORINFO *)&mi))
390 SetRectEmpty(rect);
391 return;
394 intersect_rect(rect, &mi.rcMonitor, &surface->window.rect);
395 OffsetRect(rect, -surface->window.rect.left, -surface->window.rect.top);
398 /**********************************************************************
399 * wayland_surface_reconfigure_geometry
401 * Sets the xdg_surface geometry
403 static void wayland_surface_reconfigure_geometry(struct wayland_surface *surface,
404 int width, int height)
406 RECT rect;
408 /* If the window size is bigger than the current state accepts, use the
409 * largest visible (from Windows' perspective) subregion of the window. */
410 if ((surface->current.state & (WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED |
411 WAYLAND_SURFACE_CONFIG_STATE_FULLSCREEN)) &&
412 (width > surface->current.width || height > surface->current.height))
414 wayland_surface_get_rect_in_monitor(surface, &rect);
416 wayland_surface_coords_from_window(surface, rect.left, rect.top,
417 (int *)&rect.left, (int *)&rect.top);
418 wayland_surface_coords_from_window(surface, rect.right, rect.bottom,
419 (int *)&rect.right, (int *)&rect.bottom);
421 /* If the window rect in the monitor is smaller than required,
422 * fall back to an appropriately sized rect at the top-left. */
423 if ((surface->current.state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) &&
424 (rect.right - rect.left < surface->current.width ||
425 rect.bottom - rect.top < surface->current.height))
427 SetRect(&rect, 0, 0, surface->current.width, surface->current.height);
429 else
431 rect.right = min(rect.right, rect.left + surface->current.width);
432 rect.bottom = min(rect.bottom, rect.top + surface->current.height);
434 TRACE("Window is too large for Wayland state, using subregion\n");
436 else
438 SetRect(&rect, 0, 0, width, height);
441 TRACE("hwnd=%p geometry=%s\n", surface->hwnd, wine_dbgstr_rect(&rect));
443 if (!IsRectEmpty(&rect))
445 xdg_surface_set_window_geometry(surface->xdg_surface,
446 rect.left, rect.top,
447 rect.right - rect.left,
448 rect.bottom - rect.top);
452 /**********************************************************************
453 * wayland_surface_reconfigure_size
455 * Sets the surface size with viewporter
457 static void wayland_surface_reconfigure_size(struct wayland_surface *surface,
458 int width, int height)
460 TRACE("hwnd=%p size=%dx%d\n", surface->hwnd, width, height);
462 if (surface->wp_viewport)
464 if (width != 0 && height != 0)
465 wp_viewport_set_destination(surface->wp_viewport, width, height);
466 else
467 wp_viewport_set_destination(surface->wp_viewport, -1, -1);
471 /**********************************************************************
472 * wayland_surface_reconfigure_client
474 * Reconfigures the subsurface covering the client area.
476 static void wayland_surface_reconfigure_client(struct wayland_surface *surface)
478 struct wayland_window_config *window = &surface->window;
479 int client_x, client_y, x, y;
480 int client_width, client_height, width, height;
482 if (!surface->client) return;
484 /* The offset of the client area origin relatively to the window origin. */
485 client_x = window->client_rect.left - window->rect.left;
486 client_y = window->client_rect.top - window->rect.top;
488 client_width = window->client_rect.right - window->client_rect.left;
489 client_height = window->client_rect.bottom - window->client_rect.top;
491 wayland_surface_coords_from_window(surface, client_x, client_y, &x, &y);
492 wayland_surface_coords_from_window(surface, client_width, client_height,
493 &width, &height);
495 TRACE("hwnd=%p subsurface=%d,%d+%dx%d\n", surface->hwnd, x, y, width, height);
497 wl_subsurface_set_position(surface->client->wl_subsurface, x, y);
499 if (surface->client->wp_viewport)
501 if (width != 0 && height != 0)
503 wp_viewport_set_destination(surface->client->wp_viewport,
504 width, height);
506 else
508 /* We can't have a 0x0 destination, use 1x1 instead. */
509 wp_viewport_set_destination(surface->client->wp_viewport, 1, 1);
513 wl_surface_commit(surface->client->wl_surface);
516 /**********************************************************************
517 * wayland_surface_reconfigure
519 * Reconfigures the wayland surface as needed to match the latest requested
520 * state.
522 BOOL wayland_surface_reconfigure(struct wayland_surface *surface)
524 struct wayland_window_config *window = &surface->window;
525 int win_width, win_height, width, height;
527 if (!surface->xdg_toplevel) return TRUE;
529 win_width = surface->window.rect.right - surface->window.rect.left;
530 win_height = surface->window.rect.bottom - surface->window.rect.top;
532 wayland_surface_coords_from_window(surface, win_width, win_height,
533 &width, &height);
535 TRACE("hwnd=%p window=%dx%d,%#x processing=%dx%d,%#x current=%dx%d,%#x\n",
536 surface->hwnd, win_width, win_height, window->state,
537 surface->processing.width, surface->processing.height,
538 surface->processing.state, surface->current.width,
539 surface->current.height, surface->current.state);
541 /* Acknowledge any compatible processed config. */
542 if (surface->processing.serial && surface->processing.processed &&
543 wayland_surface_config_is_compatible(&surface->processing,
544 width, height,
545 window->state))
547 surface->current = surface->processing;
548 memset(&surface->processing, 0, sizeof(surface->processing));
549 xdg_surface_ack_configure(surface->xdg_surface, surface->current.serial);
551 /* If this is the initial configure, and we have a compatible requested
552 * config, use that, in order to draw windows that don't go through the
553 * message loop (e.g., some splash screens). */
554 else if (!surface->current.serial && surface->requested.serial &&
555 wayland_surface_config_is_compatible(&surface->requested,
556 width, height,
557 window->state))
559 surface->current = surface->requested;
560 memset(&surface->requested, 0, sizeof(surface->requested));
561 xdg_surface_ack_configure(surface->xdg_surface, surface->current.serial);
563 else if (!surface->current.serial ||
564 !wayland_surface_config_is_compatible(&surface->current,
565 width, height,
566 window->state))
568 return FALSE;
571 wayland_surface_reconfigure_geometry(surface, width, height);
572 wayland_surface_reconfigure_size(surface, width, height);
573 wayland_surface_reconfigure_client(surface);
575 return TRUE;
578 /**********************************************************************
579 * wayland_shm_buffer_ref
581 * Increases the reference count of a SHM buffer.
583 void wayland_shm_buffer_ref(struct wayland_shm_buffer *shm_buffer)
585 InterlockedIncrement(&shm_buffer->ref);
588 /**********************************************************************
589 * wayland_shm_buffer_unref
591 * Decreases the reference count of a SHM buffer (and may destroy it).
593 void wayland_shm_buffer_unref(struct wayland_shm_buffer *shm_buffer)
595 if (InterlockedDecrement(&shm_buffer->ref) > 0) return;
597 TRACE("destroying %p map=%p\n", shm_buffer, shm_buffer->map_data);
599 if (shm_buffer->wl_buffer)
600 wl_buffer_destroy(shm_buffer->wl_buffer);
601 if (shm_buffer->map_data)
602 NtUnmapViewOfSection(GetCurrentProcess(), shm_buffer->map_data);
603 if (shm_buffer->damage_region)
604 NtGdiDeleteObjectApp(shm_buffer->damage_region);
606 free(shm_buffer);
609 /**********************************************************************
610 * wayland_shm_buffer_create
612 * Creates a SHM buffer with the specified width, height and format.
614 struct wayland_shm_buffer *wayland_shm_buffer_create(int width, int height,
615 enum wl_shm_format format)
617 struct wayland_shm_buffer *shm_buffer = NULL;
618 HANDLE handle = 0;
619 int fd = -1;
620 SIZE_T view_size = 0;
621 LARGE_INTEGER section_size;
622 NTSTATUS status;
623 struct wl_shm_pool *pool;
624 int stride, size;
626 stride = width * WINEWAYLAND_BYTES_PER_PIXEL;
627 size = stride * height;
628 if (size == 0)
630 ERR("Invalid shm_buffer size %dx%d\n", width, height);
631 goto err;
634 shm_buffer = calloc(1, sizeof(*shm_buffer));
635 if (!shm_buffer)
637 ERR("Failed to allocate space for SHM buffer\n");
638 goto err;
641 TRACE("%p %dx%d format=%d size=%d\n", shm_buffer, width, height, format, size);
643 shm_buffer->ref = 1;
644 shm_buffer->width = width;
645 shm_buffer->height = height;
646 shm_buffer->map_size = size;
648 shm_buffer->damage_region = NtGdiCreateRectRgn(0, 0, width, height);
649 if (!shm_buffer->damage_region)
651 ERR("Failed to create buffer damage region\n");
652 goto err;
655 section_size.QuadPart = size;
656 status = NtCreateSection(&handle,
657 GENERIC_READ | SECTION_MAP_READ | SECTION_MAP_WRITE,
658 NULL, &section_size, PAGE_READWRITE, SEC_COMMIT, 0);
659 if (status)
661 ERR("Failed to create SHM section status=0x%lx\n", (long)status);
662 goto err;
665 status = NtMapViewOfSection(handle, GetCurrentProcess(),
666 (PVOID)&shm_buffer->map_data, 0, 0, NULL,
667 &view_size, ViewUnmap, 0, PAGE_READWRITE);
668 if (status)
670 shm_buffer->map_data = NULL;
671 ERR("Failed to create map SHM handle status=0x%lx\n", (long)status);
672 goto err;
675 status = wine_server_handle_to_fd(handle, FILE_READ_DATA, &fd, NULL);
676 if (status)
678 ERR("Failed to get fd from SHM handle status=0x%lx\n", (long)status);
679 goto err;
682 pool = wl_shm_create_pool(process_wayland.wl_shm, fd, size);
683 if (!pool)
685 ERR("Failed to create SHM pool fd=%d size=%d\n", fd, size);
686 goto err;
688 shm_buffer->wl_buffer = wl_shm_pool_create_buffer(pool, 0, width, height,
689 stride, format);
690 wl_shm_pool_destroy(pool);
691 if (!shm_buffer->wl_buffer)
693 ERR("Failed to create SHM buffer %dx%d\n", width, height);
694 goto err;
697 close(fd);
698 NtClose(handle);
700 TRACE("=> map=%p\n", shm_buffer->map_data);
702 return shm_buffer;
704 err:
705 if (fd >= 0) close(fd);
706 if (handle) NtClose(handle);
707 if (shm_buffer) wayland_shm_buffer_unref(shm_buffer);
708 return NULL;
711 /**********************************************************************
712 * wayland_surface_coords_from_window
714 * Converts the window (logical) coordinates to wayland surface-local coordinates.
716 void wayland_surface_coords_from_window(struct wayland_surface *surface,
717 int window_x, int window_y,
718 int *surface_x, int *surface_y)
720 *surface_x = round(window_x / surface->window.scale);
721 *surface_y = round(window_y / surface->window.scale);
724 /**********************************************************************
725 * wayland_surface_coords_to_window
727 * Converts the surface-local coordinates to window (logical) coordinates.
729 void wayland_surface_coords_to_window(struct wayland_surface *surface,
730 double surface_x, double surface_y,
731 int *window_x, int *window_y)
733 *window_x = round(surface_x * surface->window.scale);
734 *window_y = round(surface_y * surface->window.scale);
737 /**********************************************************************
738 * wayland_client_surface_release
740 BOOL wayland_client_surface_release(struct wayland_client_surface *client)
742 if (InterlockedDecrement(&client->ref)) return FALSE;
744 if (client->wp_viewport)
745 wp_viewport_destroy(client->wp_viewport);
746 if (client->wl_subsurface)
747 wl_subsurface_destroy(client->wl_subsurface);
748 if (client->wl_surface)
749 wl_surface_destroy(client->wl_surface);
751 free(client);
753 return TRUE;
756 /**********************************************************************
757 * wayland_surface_get_client
759 struct wayland_client_surface *wayland_surface_get_client(struct wayland_surface *surface)
761 struct wl_region *empty_region;
763 if (surface->client)
765 InterlockedIncrement(&surface->client->ref);
766 return surface->client;
769 surface->client = calloc(1, sizeof(*surface->client));
770 if (!surface->client)
772 ERR("Failed to allocate space for client surface\n");
773 goto err;
776 surface->client->ref = 1;
778 surface->client->wl_surface =
779 wl_compositor_create_surface(process_wayland.wl_compositor);
780 if (!surface->client->wl_surface)
782 ERR("Failed to create client wl_surface\n");
783 goto err;
785 wl_surface_set_user_data(surface->client->wl_surface, surface->hwnd);
787 /* Let parent handle all pointer events. */
788 empty_region = wl_compositor_create_region(process_wayland.wl_compositor);
789 if (!empty_region)
791 ERR("Failed to create wl_region\n");
792 goto err;
794 wl_surface_set_input_region(surface->client->wl_surface, empty_region);
795 wl_region_destroy(empty_region);
797 surface->client->wl_subsurface =
798 wl_subcompositor_get_subsurface(process_wayland.wl_subcompositor,
799 surface->client->wl_surface,
800 surface->wl_surface);
801 if (!surface->client->wl_subsurface)
803 ERR("Failed to create client wl_subsurface\n");
804 goto err;
807 if (process_wayland.wp_viewporter)
809 surface->client->wp_viewport =
810 wp_viewporter_get_viewport(process_wayland.wp_viewporter,
811 surface->client->wl_surface);
814 wayland_surface_reconfigure_client(surface);
816 return surface->client;
818 err:
819 if (surface->client)
821 wayland_client_surface_release(surface->client);
822 surface->client = NULL;
824 return NULL;