1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
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/. */
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+) |
16 * | --------------------------------------------------- |
17 * | | mContainer (contains wl_surface owned by Gtk+) | |
19 * | | --------------------------------------------- | |
20 * | | | wl_subsurface (attached to wl_surface | | |
21 * | | | of mContainer) | | |
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"
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"
66 # include "mozilla/Logging.h"
67 # include "nsTArray.h"
69 # include "nsWindow.h"
70 extern mozilla::LazyLogModule gWidgetWaylandLog
;
71 # define LOGWAYLAND(...) \
72 MOZ_LOG(gWidgetWaylandLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
74 # define LOGWAYLAND(...)
75 #endif /* MOZ_LOGGING */
77 using namespace mozilla
;
78 using namespace mozilla::widget
;
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
,
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
));
106 LOGWAYLAND(" Failed - missing GdkWindow!\n");
109 gdk_window_invalidate_rect(window
, nullptr, true);
112 // Route input to parent wl_surface owned by Gtk+ so we get input
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
,
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
)) {
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.
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
) {
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
);
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.
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
;
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.");
255 if (wl_container
->ready_to_draw
) {
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
) {
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
);
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
) {
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
);
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
) {
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
,
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
) {
366 if (!wl_container
->surface
) {
367 if (!moz_container_wayland_surface_create_locked(lock
,
368 MOZ_CONTAINER(widget
))) {
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
));
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
,
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
) {
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
,
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
)) {
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
,
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
);
457 wl_region_subtract(region
, aX
, aY
, aCornerRadius
, aCornerRadius
);
458 wl_region_subtract(region
, aX
+ aWidth
- aCornerRadius
, aY
, aCornerRadius
,
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
) {
472 if (!wl_container
->opaque_region_used
) {
473 wl_container
->opaque_region_needs_updates
= false;
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
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
));
518 int scale
= window
? window
->GdkCeiledScaleFactor() : 1;
520 if (scale
== wl_container
->buffer_scale
) {
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!");
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));
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!");
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!");
579 wl_subsurface_set_desync(wl_container
->subsurface
);
581 // Try to guess subsurface offset to avoid potential flickering.
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,
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
);
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
,
609 LOGWAYLAND(" created surface %p ID %d\n", (void*)wl_container
->surface
,
610 wl_proxy_get_id((struct wl_proxy
*)wl_container
->surface
));
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
) {
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);
634 container
->wl_container
.container_lock
->Unlock();
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
) {
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
) {
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
,
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
;