Bug 1751217 Part 3: Make HDR-capable macOS screens report 30 pixelDepth. r=mstange
[gecko.git] / widget / gtk / MozContainerWayland.cpp
blobb2b6cbee4f76494407dc05abf460587bbba41738
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * MozContainerWayland is a wrapper over MozContainer which provides
9 * wl_surface for MozContainer widget.
11 * The widget scheme looks like:
13 * ---------------------------------------------------------
14 * | mShell Gtk widget (contains wl_surface owned by Gtk+) |
15 * | |
16 * | --------------------------------------------------- |
17 * | | mContainer (contains wl_surface owned by Gtk+) | |
18 * | | | |
19 * | | --------------------------------------------- | |
20 * | | | wl_subsurface (attached to wl_surface | | |
21 * | | | of mContainer) | | |
22 * | | | | | |
23 * | | | | | |
24 * | | --------------------------------------------- | |
25 * | --------------------------------------------------- |
26 * ---------------------------------------------------------
28 * We draw to wl_subsurface owned by MozContainerWayland.
29 * We need to wait until wl_surface of mContainer is created
30 * and then we create and attach our wl_subsurface to it.
32 * First wl_subsurface creation has these steps:
34 * 1) moz_container_wayland_size_allocate() handler is called when
35 * mContainer size/position is known.
36 * It calls moz_container_wayland_surface_create_locked(), registers
37 * a frame callback handler
38 * moz_container_wayland_frame_callback_handler().
40 * 2) moz_container_wayland_frame_callback_handler() is called
41 * when wl_surface owned by mozContainer is ready.
42 * We call initial_draw_cbs() handler and we can create our wl_subsurface
43 * on top of wl_surface owned by mozContainer.
45 * When MozContainer hides/show again, moz_container_wayland_size_allocate()
46 * handler may not be called as MozContainer size is set. So after first
47 * show/hide sequence use moz_container_wayland_map_event() to create
48 * wl_subsurface of MozContainer.
51 #include "MozContainer.h"
53 #include <dlfcn.h>
54 #include <glib.h>
55 #include <stdio.h>
56 #include <wayland-egl.h>
58 #include "mozilla/gfx/gfxVars.h"
59 #include "mozilla/StaticPrefs_widget.h"
60 #include "nsGtkUtils.h"
61 #include "nsWaylandDisplay.h"
62 #include "base/task.h"
64 #ifdef MOZ_LOGGING
66 # include "mozilla/Logging.h"
67 # include "nsTArray.h"
68 # include "Units.h"
69 # include "nsWindow.h"
70 extern mozilla::LazyLogModule gWidgetWaylandLog;
71 # define LOGWAYLAND(...) \
72 MOZ_LOG(gWidgetWaylandLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
73 #else
74 # define LOGWAYLAND(...)
75 #endif /* MOZ_LOGGING */
77 using namespace mozilla;
78 using namespace mozilla::widget;
80 /* init methods */
81 static void moz_container_wayland_destroy(GtkWidget* widget);
83 /* widget class methods */
84 static void moz_container_wayland_map(GtkWidget* widget);
85 static gboolean moz_container_wayland_map_event(GtkWidget* widget,
86 GdkEventAny* event);
87 static void moz_container_wayland_unmap(GtkWidget* widget);
88 static void moz_container_wayland_size_allocate(GtkWidget* widget,
89 GtkAllocation* allocation);
90 static bool moz_container_wayland_surface_create_locked(
91 const MutexAutoLock& aProofOfLock, MozContainer* container);
92 static void moz_container_wayland_set_opaque_region_locked(
93 const MutexAutoLock& aProofOfLock, MozContainer* container);
95 // Imlemented in MozContainer.cpp
96 void moz_container_realize(GtkWidget* widget);
98 // Invalidate gtk wl_surface to commit changes to wl_subsurface.
99 // wl_subsurface changes are effective when parent surface is commited.
100 static void moz_container_wayland_invalidate(MozContainer* container) {
101 LOGWAYLAND("moz_container_wayland_invalidate [%p]\n",
102 (void*)moz_container_get_nsWindow(container));
104 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
105 if (!window) {
106 LOGWAYLAND(" Failed - missing GdkWindow!\n");
107 return;
109 gdk_window_invalidate_rect(window, nullptr, true);
112 // Route input to parent wl_surface owned by Gtk+ so we get input
113 // events from Gtk+.
114 static void moz_container_clear_input_region(MozContainer* container) {
115 struct wl_compositor* compositor = WaylandDisplayGet()->GetCompositor();
116 MozContainerWayland* wl_container = &container->wl_container;
117 wl_region* region = wl_compositor_create_region(compositor);
118 wl_surface_set_input_region(wl_container->surface, region);
119 wl_region_destroy(region);
122 static void moz_container_wayland_move_locked(const MutexAutoLock& aProofOfLock,
123 MozContainer* container, int dx,
124 int dy) {
125 LOGWAYLAND("moz_container_wayland_move [%p] %d,%d\n",
126 (void*)moz_container_get_nsWindow(container), dx, dy);
128 MozContainerWayland* wl_container = &container->wl_container;
129 if (!wl_container->subsurface || (wl_container->subsurface_dx == dx &&
130 wl_container->subsurface_dy == dy)) {
131 return;
134 wl_container->subsurface_dx = dx;
135 wl_container->subsurface_dy = dy;
136 wl_subsurface_set_position(wl_container->subsurface,
137 wl_container->subsurface_dx,
138 wl_container->subsurface_dy);
141 // This is called from layout/compositor code only with
142 // size equal to GL rendering context. Otherwise there are
143 // rendering artifacts as wl_egl_window size does not match
144 // GL rendering pipeline setup.
145 void moz_container_wayland_egl_window_set_size(MozContainer* container,
146 int width, int height) {
147 MozContainerWayland* wl_container = &container->wl_container;
148 MutexAutoLock lock(*wl_container->container_lock);
149 if (wl_container->eglwindow) {
150 wl_egl_window_resize(wl_container->eglwindow, width, height, 0, 0);
154 void moz_container_wayland_class_init(MozContainerClass* klass) {
155 /*GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
156 GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); */
157 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
159 widget_class->map = moz_container_wayland_map;
160 widget_class->map_event = moz_container_wayland_map_event;
161 widget_class->destroy = moz_container_wayland_destroy;
162 widget_class->unmap = moz_container_wayland_unmap;
163 widget_class->realize = moz_container_realize;
164 widget_class->size_allocate = moz_container_wayland_size_allocate;
167 void moz_container_wayland_init(MozContainerWayland* container) {
168 container->surface = nullptr;
169 container->subsurface = nullptr;
170 container->eglwindow = nullptr;
171 container->frame_callback_handler = nullptr;
172 container->viewport = nullptr;
173 container->ready_to_draw = false;
174 container->opaque_region_needs_updates = false;
175 container->opaque_region_corner_radius = 0;
176 container->opaque_region_used = false;
177 container->subsurface_dx = 0;
178 container->subsurface_dy = 0;
179 container->before_first_size_alloc = true;
180 container->buffer_scale = 1;
181 container->initial_draw_cbs.clear();
182 container->container_lock = new mozilla::Mutex("MozContainer lock");
183 container->commit_to_parent = false;
186 static void moz_container_wayland_destroy(GtkWidget* widget) {
187 MozContainerWayland* container = &MOZ_CONTAINER(widget)->wl_container;
188 if (!container->container_lock) {
189 // moz_container_wayland_init was not called - it's a hidden container.
190 return;
192 moz_container_wayland_clear_initial_draw_callback(MOZ_CONTAINER(widget));
193 delete container->container_lock;
194 container->container_lock = nullptr;
197 void moz_container_wayland_add_initial_draw_callback(
198 MozContainer* container, const std::function<void(void)>& initial_draw_cb) {
199 MozContainerWayland* wl_container = &MOZ_CONTAINER(container)->wl_container;
201 MutexAutoLock lock(*container->wl_container.container_lock);
202 if (wl_container->ready_to_draw && !wl_container->surface) {
203 NS_WARNING(
204 "moz_container_wayland_add_initial_draw_callback: ready to draw "
205 "without wayland surface!");
207 if (!wl_container->ready_to_draw || !wl_container->surface) {
208 wl_container->initial_draw_cbs.push_back(initial_draw_cb);
209 return;
213 // We're ready to draw as
214 // wl_container->ready_to_draw && wl_container->surface
215 // call the callback directly instead of store them.
216 initial_draw_cb();
219 static void moz_container_wayland_clear_initial_draw_callback_locked(
220 const MutexAutoLock& aProofOfLock, MozContainer* container) {
221 MozContainerWayland* wl_container = &MOZ_CONTAINER(container)->wl_container;
222 g_clear_pointer(&wl_container->frame_callback_handler, wl_callback_destroy);
223 wl_container->initial_draw_cbs.clear();
226 void moz_container_wayland_clear_initial_draw_callback(
227 MozContainer* container) {
228 MutexAutoLock lock(*container->wl_container.container_lock);
229 moz_container_wayland_clear_initial_draw_callback_locked(lock, container);
232 static void moz_container_wayland_frame_callback_handler(
233 void* data, struct wl_callback* callback, uint32_t time) {
234 MozContainerWayland* wl_container = &MOZ_CONTAINER(data)->wl_container;
236 LOGWAYLAND(
237 "%s [%p] frame_callback_handler %p ready_to_draw %d (set to true)"
238 " initial_draw callback %zd\n",
239 __FUNCTION__, (void*)moz_container_get_nsWindow(MOZ_CONTAINER(data)),
240 (void*)wl_container->frame_callback_handler, wl_container->ready_to_draw,
241 wl_container->initial_draw_cbs.size());
243 std::vector<std::function<void(void)>> cbs;
245 // Protect mozcontainer internals changes by container_lock.
246 MutexAutoLock lock(*wl_container->container_lock);
247 g_clear_pointer(&wl_container->frame_callback_handler, wl_callback_destroy);
248 // It's possible that container is already unmapped so quit in such case.
249 if (!wl_container->surface) {
250 LOGWAYLAND(" container in unmapped, quit.");
251 MOZ_DIAGNOSTIC_ASSERT(wl_container->initial_draw_cbs.empty(),
252 "MozContainer should be unmapped.");
253 return;
255 if (wl_container->ready_to_draw) {
256 return;
258 wl_container->ready_to_draw = true;
259 cbs = std::move(wl_container->initial_draw_cbs);
262 // Call the callbacks registered by
263 // moz_container_wayland_add_initial_draw_callback().
264 // and we can't do that under mozcontainer lock.
265 for (auto const& cb : cbs) {
266 cb();
270 static const struct wl_callback_listener moz_container_frame_listener = {
271 moz_container_wayland_frame_callback_handler};
273 static void after_frame_clock_after_paint(GdkFrameClock* clock,
274 MozContainer* container) {
275 struct wl_surface* surface = moz_container_wayland_surface_lock(container);
276 if (surface) {
277 wl_surface_commit(surface);
278 moz_container_wayland_surface_unlock(container, &surface);
282 static bool moz_gdk_wayland_window_add_frame_callback_surface_locked(
283 const MutexAutoLock& aProofOfLock, MozContainer* container) {
284 static auto sGdkWaylandWindowAddCallbackSurface =
285 (void (*)(GdkWindow*, struct wl_surface*))dlsym(
286 RTLD_DEFAULT, "gdk_wayland_window_add_frame_callback_surface");
288 if (!StaticPrefs::widget_wayland_opaque_region_enabled_AtStartup() ||
289 !sGdkWaylandWindowAddCallbackSurface) {
290 return false;
293 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
294 MozContainerWayland* wl_container = &container->wl_container;
296 sGdkWaylandWindowAddCallbackSurface(window, wl_container->surface);
298 GdkFrameClock* frame_clock = gdk_window_get_frame_clock(window);
299 g_signal_connect_after(frame_clock, "after-paint",
300 G_CALLBACK(after_frame_clock_after_paint), container);
301 return true;
304 static void moz_gdk_wayland_window_remove_frame_callback_surface_locked(
305 const MutexAutoLock& aProofOfLock, MozContainer* container) {
306 static auto sGdkWaylandWindowRemoveCallbackSurface =
307 (void (*)(GdkWindow*, struct wl_surface*))dlsym(
308 RTLD_DEFAULT, "gdk_wayland_window_remove_frame_callback_surface");
310 if (!sGdkWaylandWindowRemoveCallbackSurface) {
311 return;
314 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
315 MozContainerWayland* wl_container = &container->wl_container;
317 if (wl_container->surface) {
318 sGdkWaylandWindowRemoveCallbackSurface(window, wl_container->surface);
321 GdkFrameClock* frame_clock = gdk_window_get_frame_clock(window);
322 g_signal_handlers_disconnect_by_func(
323 frame_clock, FuncToGpointer(after_frame_clock_after_paint), container);
326 static void moz_container_wayland_unmap_internal(MozContainer* container) {
327 MozContainerWayland* wl_container = &container->wl_container;
328 MutexAutoLock lock(*wl_container->container_lock);
330 LOGWAYLAND("%s [%p]\n", __FUNCTION__,
331 (void*)moz_container_get_nsWindow(container));
333 moz_container_wayland_clear_initial_draw_callback_locked(lock, container);
335 if (wl_container->opaque_region_used) {
336 moz_gdk_wayland_window_remove_frame_callback_surface_locked(lock,
337 container);
339 if (wl_container->commit_to_parent) {
340 wl_container->surface = nullptr;
343 g_clear_pointer(&wl_container->eglwindow, wl_egl_window_destroy);
344 g_clear_pointer(&wl_container->subsurface, wl_subsurface_destroy);
345 g_clear_pointer(&wl_container->surface, wl_surface_destroy);
346 g_clear_pointer(&wl_container->viewport, wp_viewport_destroy);
348 wl_container->ready_to_draw = false;
349 wl_container->buffer_scale = 1;
352 static gboolean moz_container_wayland_map_event(GtkWidget* widget,
353 GdkEventAny* event) {
354 MozContainerWayland* wl_container = &MOZ_CONTAINER(widget)->wl_container;
355 MutexAutoLock lock(*wl_container->container_lock);
357 LOGWAYLAND("%s [%p]\n", __FUNCTION__,
358 (void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget)));
360 // Don't create wl_subsurface in map_event when it's already created or
361 // if we create it for the first time.
362 if (wl_container->ready_to_draw || wl_container->before_first_size_alloc) {
363 return FALSE;
366 if (!wl_container->surface) {
367 if (!moz_container_wayland_surface_create_locked(lock,
368 MOZ_CONTAINER(widget))) {
369 return FALSE;
373 moz_container_wayland_set_scale_factor_locked(MOZ_CONTAINER(widget));
374 moz_container_wayland_set_opaque_region_locked(lock, MOZ_CONTAINER(widget));
375 moz_container_clear_input_region(MOZ_CONTAINER(widget));
376 moz_container_wayland_invalidate(MOZ_CONTAINER(widget));
377 return FALSE;
380 void moz_container_wayland_map(GtkWidget* widget) {
381 LOGWAYLAND("%s [%p]\n", __FUNCTION__,
382 (void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget)));
384 g_return_if_fail(IS_MOZ_CONTAINER(widget));
385 gtk_widget_set_mapped(widget, TRUE);
387 if (gtk_widget_get_has_window(widget)) {
388 gdk_window_show(gtk_widget_get_window(widget));
392 void moz_container_wayland_unmap(GtkWidget* widget) {
393 LOGWAYLAND("%s [%p]\n", __FUNCTION__,
394 (void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget)));
396 g_return_if_fail(IS_MOZ_CONTAINER(widget));
397 gtk_widget_set_mapped(widget, FALSE);
399 if (gtk_widget_get_has_window(widget)) {
400 gdk_window_hide(gtk_widget_get_window(widget));
401 moz_container_wayland_unmap_internal(MOZ_CONTAINER(widget));
405 void moz_container_wayland_size_allocate(GtkWidget* widget,
406 GtkAllocation* allocation) {
407 MozContainer* container;
408 GtkAllocation tmp_allocation;
410 g_return_if_fail(IS_MOZ_CONTAINER(widget));
412 LOGWAYLAND("moz_container_wayland_size_allocate [%p] %d,%d -> %d x %d\n",
413 (void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget)),
414 allocation->x, allocation->y, allocation->width,
415 allocation->height);
417 /* short circuit if you can */
418 container = MOZ_CONTAINER(widget);
419 gtk_widget_get_allocation(widget, &tmp_allocation);
420 if (!container->children && tmp_allocation.x == allocation->x &&
421 tmp_allocation.y == allocation->y &&
422 tmp_allocation.width == allocation->width &&
423 tmp_allocation.height == allocation->height) {
424 return;
426 gtk_widget_set_allocation(widget, allocation);
428 if (gtk_widget_get_has_window(widget) && gtk_widget_get_realized(widget)) {
429 gdk_window_move_resize(gtk_widget_get_window(widget), allocation->x,
430 allocation->y, allocation->width,
431 allocation->height);
432 // We need to position our subsurface according to GdkWindow
433 // when offset changes (GdkWindow is maximized for instance).
434 // see gtk-clutter-embed.c for reference.
435 MutexAutoLock lock(*container->wl_container.container_lock);
436 if (!container->wl_container.surface) {
437 if (!moz_container_wayland_surface_create_locked(lock, container)) {
438 return;
441 moz_container_wayland_set_scale_factor_locked(container);
442 moz_container_wayland_set_opaque_region_locked(lock, container);
443 moz_container_wayland_move_locked(lock, container, allocation->x,
444 allocation->y);
445 moz_container_clear_input_region(container);
446 moz_container_wayland_invalidate(MOZ_CONTAINER(widget));
447 container->wl_container.before_first_size_alloc = false;
451 static wl_region* moz_container_wayland_create_opaque_region(
452 int aX, int aY, int aWidth, int aHeight, int aCornerRadius) {
453 struct wl_compositor* compositor = WaylandDisplayGet()->GetCompositor();
454 wl_region* region = wl_compositor_create_region(compositor);
455 wl_region_add(region, aX, aY, aWidth, aHeight);
456 if (aCornerRadius) {
457 wl_region_subtract(region, aX, aY, aCornerRadius, aCornerRadius);
458 wl_region_subtract(region, aX + aWidth - aCornerRadius, aY, aCornerRadius,
459 aCornerRadius);
461 return region;
464 static void moz_container_wayland_set_opaque_region_locked(
465 const MutexAutoLock& aProofOfLock, MozContainer* container) {
466 MozContainerWayland* wl_container = &container->wl_container;
468 if (!wl_container->opaque_region_needs_updates) {
469 return;
472 if (!wl_container->opaque_region_used) {
473 wl_container->opaque_region_needs_updates = false;
474 return;
477 GtkAllocation allocation;
478 gtk_widget_get_allocation(GTK_WIDGET(container), &allocation);
480 wl_region* region = moz_container_wayland_create_opaque_region(
481 0, 0, allocation.width, allocation.height,
482 wl_container->opaque_region_corner_radius);
483 wl_surface_set_opaque_region(wl_container->surface, region);
484 wl_region_destroy(region);
485 wl_container->opaque_region_needs_updates = false;
488 static void moz_container_wayland_set_opaque_region(MozContainer* container) {
489 MozContainerWayland* wl_container = &container->wl_container;
490 MutexAutoLock lock(*wl_container->container_lock);
491 if (wl_container->surface) {
492 moz_container_wayland_set_opaque_region_locked(lock, container);
496 void moz_container_wayland_set_scale_factor_locked(MozContainer* container) {
497 if (gfx::gfxVars::UseWebRenderCompositor()) {
498 // the compositor backend handles scaling itself
499 return;
502 MozContainerWayland* wl_container = &container->wl_container;
503 wl_container->container_lock->AssertCurrentThreadOwns();
505 nsWindow* window = moz_container_get_nsWindow(container);
507 if (window && window->UseFractionalScale()) {
508 if (!wl_container->viewport) {
509 wl_container->viewport = wp_viewporter_get_viewport(
510 WaylandDisplayGet()->GetViewporter(), wl_container->surface);
513 GdkWindow* gdkWindow = gtk_widget_get_window(GTK_WIDGET(container));
514 wp_viewport_set_destination(wl_container->viewport,
515 gdk_window_get_width(gdkWindow),
516 gdk_window_get_height(gdkWindow));
517 } else {
518 int scale = window ? window->GdkCeiledScaleFactor() : 1;
520 if (scale == wl_container->buffer_scale) {
521 return;
524 LOGWAYLAND("%s [%p] scale %d\n", __FUNCTION__,
525 (void*)moz_container_get_nsWindow(container), scale);
526 wl_surface_set_buffer_scale(wl_container->surface, scale);
527 wl_container->buffer_scale = scale;
531 void moz_container_wayland_set_scale_factor(MozContainer* container) {
532 MutexAutoLock lock(*container->wl_container.container_lock);
533 if (container->wl_container.surface) {
534 moz_container_wayland_set_scale_factor_locked(container);
538 static bool moz_container_wayland_surface_create_locked(
539 const MutexAutoLock& aProofOfLock, MozContainer* container) {
540 MozContainerWayland* wl_container = &container->wl_container;
542 LOGWAYLAND("%s [%p]\n", __FUNCTION__,
543 (void*)moz_container_get_nsWindow(container));
545 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
546 wl_surface* parent_surface = gdk_wayland_window_get_wl_surface(window);
547 if (!parent_surface) {
548 LOGWAYLAND(" Failed - missing parent surface!");
549 return false;
551 LOGWAYLAND(" gtk wl_surface %p ID %d\n", (void*)parent_surface,
552 wl_proxy_get_id((struct wl_proxy*)parent_surface));
554 if (wl_container->commit_to_parent) {
555 LOGWAYLAND(" commit to parent");
556 wl_container->surface = parent_surface;
557 NS_DispatchToCurrentThread(NewRunnableFunction(
558 "moz_container_wayland_frame_callback_handler",
559 &moz_container_wayland_frame_callback_handler, container, nullptr, 0));
560 return true;
563 // Available as of GTK 3.8+
564 struct wl_compositor* compositor = WaylandDisplayGet()->GetCompositor();
565 wl_container->surface = wl_compositor_create_surface(compositor);
566 if (!wl_container->surface) {
567 LOGWAYLAND(" Failed - can't create surface!");
568 return false;
571 wl_container->subsurface =
572 wl_subcompositor_get_subsurface(WaylandDisplayGet()->GetSubcompositor(),
573 wl_container->surface, parent_surface);
574 if (!wl_container->subsurface) {
575 g_clear_pointer(&wl_container->surface, wl_surface_destroy);
576 LOGWAYLAND(" Failed - can't create sub-surface!");
577 return false;
579 wl_subsurface_set_desync(wl_container->subsurface);
581 // Try to guess subsurface offset to avoid potential flickering.
582 int dx, dy;
583 if (moz_container_get_nsWindow(container)->GetCSDDecorationOffset(&dx, &dy)) {
584 wl_container->subsurface_dx = dx;
585 wl_container->subsurface_dy = dy;
586 wl_subsurface_set_position(wl_container->subsurface, dx, dy);
587 LOGWAYLAND(" guessing subsurface position %d %d\n", dx, dy);
590 // If there's pending frame callback it's for wrong parent surface,
591 // so delete it.
592 if (wl_container->frame_callback_handler) {
593 g_clear_pointer(&wl_container->frame_callback_handler, wl_callback_destroy);
595 wl_container->frame_callback_handler = wl_surface_frame(parent_surface);
596 wl_callback_add_listener(wl_container->frame_callback_handler,
597 &moz_container_frame_listener, container);
598 LOGWAYLAND(
599 " created frame callback ID %d\n",
600 wl_proxy_get_id((struct wl_proxy*)wl_container->frame_callback_handler));
602 wl_surface_commit(wl_container->surface);
603 wl_display_flush(WaylandDisplayGet()->GetDisplay());
605 wl_container->opaque_region_used =
606 moz_gdk_wayland_window_add_frame_callback_surface_locked(aProofOfLock,
607 container);
609 LOGWAYLAND(" created surface %p ID %d\n", (void*)wl_container->surface,
610 wl_proxy_get_id((struct wl_proxy*)wl_container->surface));
611 return true;
614 struct wl_surface* moz_container_wayland_surface_lock(MozContainer* container)
615 NO_THREAD_SAFETY_ANALYSIS {
616 // LOGWAYLAND("%s [%p] surface %p ready_to_draw %d\n", __FUNCTION__,
617 // (void*)container, (void*)container->wl_container.surface,
618 // container->wl_container.ready_to_draw);
619 if (!container->wl_container.surface ||
620 !container->wl_container.ready_to_draw) {
621 return nullptr;
623 container->wl_container.container_lock->Lock();
624 return container->wl_container.surface;
627 void moz_container_wayland_surface_unlock(MozContainer* container,
628 struct wl_surface** surface)
629 NO_THREAD_SAFETY_ANALYSIS {
630 // Temporarily disabled to avoid log noise
631 // LOGWAYLAND("%s [%p] surface %p\n", __FUNCTION__, (void*)container,
632 // (void*)container->wl_container.surface);
633 if (*surface) {
634 container->wl_container.container_lock->Unlock();
635 *surface = nullptr;
639 struct wl_surface* moz_container_wayland_get_surface_locked(
640 const MutexAutoLock& aProofOfLock, MozContainer* container) {
641 LOGWAYLAND("%s [%p] surface %p ready_to_draw %d\n", __FUNCTION__,
642 (void*)moz_container_get_nsWindow(container),
643 (void*)container->wl_container.surface,
644 container->wl_container.ready_to_draw);
645 if (!container->wl_container.surface ||
646 !container->wl_container.ready_to_draw) {
647 return nullptr;
649 moz_container_wayland_set_scale_factor_locked(container);
650 return container->wl_container.surface;
653 void moz_container_wayland_lock(MozContainer* container)
654 NO_THREAD_SAFETY_ANALYSIS {
655 container->wl_container.container_lock->Lock();
658 void moz_container_wayland_unlock(MozContainer* container)
659 NO_THREAD_SAFETY_ANALYSIS {
660 container->wl_container.container_lock->Unlock();
663 struct wl_egl_window* moz_container_wayland_get_egl_window(
664 MozContainer* container, double scale) {
665 MozContainerWayland* wl_container = &container->wl_container;
667 LOGWAYLAND("%s [%p] eglwindow %p\n", __FUNCTION__,
668 (void*)moz_container_get_nsWindow(container),
669 (void*)wl_container->eglwindow);
671 MutexAutoLock lock(*wl_container->container_lock);
672 if (!wl_container->surface || !wl_container->ready_to_draw) {
673 return nullptr;
675 if (!wl_container->eglwindow) {
676 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
677 wl_container->eglwindow = wl_egl_window_create(
678 wl_container->surface, (int)round(gdk_window_get_width(window) * scale),
679 (int)round(gdk_window_get_height(window) * scale));
681 LOGWAYLAND("%s [%p] created eglwindow %p\n", __FUNCTION__,
682 (void*)moz_container_get_nsWindow(container),
683 (void*)wl_container->eglwindow);
685 return wl_container->eglwindow;
688 gboolean moz_container_wayland_has_egl_window(MozContainer* container) {
689 return container->wl_container.eglwindow != nullptr;
692 void moz_container_wayland_update_opaque_region(MozContainer* container,
693 int corner_radius) {
694 MozContainerWayland* wl_container = &container->wl_container;
695 wl_container->opaque_region_needs_updates = true;
696 wl_container->opaque_region_corner_radius = corner_radius;
698 // When GL compositor / WebRender is used,
699 // moz_container_wayland_get_egl_window() is called only once when window
700 // is created or resized so update opaque region now.
701 if (moz_container_wayland_has_egl_window(container)) {
702 moz_container_wayland_set_opaque_region(container);
706 gboolean moz_container_wayland_can_draw(MozContainer* container) {
707 MozContainerWayland* wl_container = &container->wl_container;
708 MutexAutoLock lock(*wl_container->container_lock);
709 return wl_container->ready_to_draw;
712 double moz_container_wayland_get_scale(MozContainer* container) {
713 nsWindow* window = moz_container_get_nsWindow(container);
714 return window ? window->FractionalScaleFactor() : 1;
717 void moz_container_wayland_set_commit_to_parent(MozContainer* container) {
718 MozContainerWayland* wl_container = &container->wl_container;
719 MOZ_DIAGNOSTIC_ASSERT(!wl_container->surface);
720 wl_container->commit_to_parent = true;
723 bool moz_container_wayland_is_commiting_to_parent(MozContainer* container) {
724 MozContainerWayland* wl_container = &container->wl_container;
725 return wl_container->commit_to_parent;