1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=4:tabstop=4:
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.
10 *
11 * The widget scheme looks like:
12 *
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 * ---------------------------------------------------------
27 *
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.
31 *
32 * First wl_subsurface creation has these steps:
33 *
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().
39 *
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.
44 *
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.
49 */
50
51 #include "MozContainer.h"
52
53 #include <dlfcn.h>
54 #include <glib.h>
55 #include <stdio.h>
56 #include <wayland-egl.h>
57
58 #include "nsGtkUtils.h"
59 #include "nsWaylandDisplay.h"
60
61 #ifdef MOZ_LOGGING
62
63 # include "mozilla/Logging.h"
64 # include "nsTArray.h"
65 # include "Units.h"
66 # include "nsWindow.h"
67 extern mozilla::LazyLogModule gWidgetWaylandLog;
68 # define LOGWAYLAND(args) \
69 MOZ_LOG(gWidgetWaylandLog, mozilla::LogLevel::Debug, args)
70 #else
71 # define LOGWAYLAND(args)
72 #endif /* MOZ_LOGGING */
73
74 using namespace mozilla;
75 using namespace mozilla::widget;
76
77 /* init methods */
78 static void moz_container_wayland_destroy(GtkWidget* widget);
79
80 /* widget class methods */
81 static void moz_container_wayland_map(GtkWidget* widget);
82 static gboolean moz_container_wayland_map_event(GtkWidget* widget,
83 GdkEventAny* event);
84 static void moz_container_wayland_unmap(GtkWidget* widget);
85 static void moz_container_wayland_size_allocate(GtkWidget* widget,
86 GtkAllocation* allocation);
87 static bool moz_container_wayland_surface_create_locked(
88 MozContainer* container);
89 static void moz_container_wayland_set_scale_factor_locked(
90 MozContainer* container);
91 static void moz_container_wayland_set_opaque_region_locked(
92 MozContainer* container);
93
moz_container_get_nsWindow(MozContainer * container)94 static nsWindow* moz_container_get_nsWindow(MozContainer* container) {
95 gpointer user_data = g_object_get_data(G_OBJECT(container), "nsWindow");
96 return static_cast<nsWindow*>(user_data);
97 }
98
99 // Imlemented in MozContainer.cpp
100 void moz_container_realize(GtkWidget* widget);
101
102 // Invalidate gtk wl_surface to commit changes to wl_subsurface.
103 // wl_subsurface changes are effective when parent surface is commited.
moz_container_wayland_invalidate(MozContainer * container)104 static void moz_container_wayland_invalidate(MozContainer* container) {
105 LOGWAYLAND(("moz_container_wayland_invalidate [%p]\n", (void*)container));
106
107 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
108 if (!window) {
109 LOGWAYLAND((" Failed - missing GdkWindow!\n"));
110 return;
111 }
112
113 GdkRectangle rect = (GdkRectangle){0, 0, gdk_window_get_width(window),
114 gdk_window_get_height(window)};
115 gdk_window_invalidate_rect(window, &rect, true);
116 }
117
118 // Route input to parent wl_surface owned by Gtk+ so we get input
119 // events from Gtk+.
moz_container_clear_input_region(MozContainer * container)120 static void moz_container_clear_input_region(MozContainer* container) {
121 struct wl_compositor* compositor = WaylandDisplayGet()->GetCompositor();
122 MozContainerWayland* wl_container = &container->wl_container;
123 wl_region* region = wl_compositor_create_region(compositor);
124 wl_surface_set_input_region(wl_container->surface, region);
125 wl_region_destroy(region);
126 }
127
moz_container_wayland_move_locked(MozContainer * container,int dx,int dy)128 static void moz_container_wayland_move_locked(MozContainer* container, int dx,
129 int dy) {
130 LOGWAYLAND(
131 ("moz_container_wayland_move [%p] %d,%d\n", (void*)container, dx, dy));
132
133 MozContainerWayland* wl_container = &container->wl_container;
134
135 if (wl_container->subsurface_dx == dx && wl_container->subsurface_dy == dy) {
136 return;
137 }
138
139 wl_container->subsurface_dx = dx;
140 wl_container->subsurface_dy = dy;
141 wl_subsurface_set_position(wl_container->subsurface,
142 wl_container->subsurface_dx,
143 wl_container->subsurface_dy);
144 }
145
146 // This is called from layout/compositor code only with
147 // size equal to GL rendering context. Otherwise there are
148 // rendering artifacts as wl_egl_window size does not match
149 // GL rendering pipeline setup.
moz_container_wayland_egl_window_set_size(MozContainer * container,int width,int height)150 void moz_container_wayland_egl_window_set_size(MozContainer* container,
151 int width, int height) {
152 MozContainerWayland* wl_container = &container->wl_container;
153 MutexAutoLock lock(*wl_container->container_lock);
154 if (wl_container->eglwindow) {
155 wl_egl_window_resize(wl_container->eglwindow, width, height, 0, 0);
156 }
157 }
158
moz_container_wayland_class_init(MozContainerClass * klass)159 void moz_container_wayland_class_init(MozContainerClass* klass) {
160 /*GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
161 GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); */
162 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
163
164 widget_class->map = moz_container_wayland_map;
165 widget_class->map_event = moz_container_wayland_map_event;
166 widget_class->destroy = moz_container_wayland_destroy;
167 widget_class->unmap = moz_container_wayland_unmap;
168 widget_class->realize = moz_container_realize;
169 widget_class->size_allocate = moz_container_wayland_size_allocate;
170 }
171
moz_container_wayland_init(MozContainerWayland * container)172 void moz_container_wayland_init(MozContainerWayland* container) {
173 container->surface = nullptr;
174 container->subsurface = nullptr;
175 container->eglwindow = nullptr;
176 container->frame_callback_handler = nullptr;
177 container->viewport = nullptr;
178 container->ready_to_draw = false;
179 container->opaque_region_needs_updates = false;
180 container->opaque_region_subtract_corners = false;
181 container->opaque_region_used = false;
182 container->surface_needs_clear = true;
183 container->container_remapped = true;
184 container->subsurface_dx = 0;
185 container->subsurface_dy = 0;
186 container->before_first_size_alloc = true;
187 container->buffer_scale = 1;
188 container->initial_draw_cbs.clear();
189 container->container_lock = new mozilla::Mutex("MozContainer lock");
190 }
191
moz_container_wayland_destroy(GtkWidget * widget)192 static void moz_container_wayland_destroy(GtkWidget* widget) {
193 MozContainerWayland* container = &MOZ_CONTAINER(widget)->wl_container;
194 delete container->container_lock;
195 container->container_lock = nullptr;
196 container->initial_draw_cbs.clear();
197 }
198
moz_container_wayland_add_initial_draw_callback(MozContainer * container,const std::function<void (void)> & initial_draw_cb)199 void moz_container_wayland_add_initial_draw_callback(
200 MozContainer* container, const std::function<void(void)>& initial_draw_cb) {
201 container->wl_container.initial_draw_cbs.push_back(initial_draw_cb);
202 }
203
moz_container_wayland_frame_callback_handler(void * data,struct wl_callback * callback,uint32_t time)204 static void moz_container_wayland_frame_callback_handler(
205 void* data, struct wl_callback* callback, uint32_t time) {
206 MozContainerWayland* wl_container = &MOZ_CONTAINER(data)->wl_container;
207
208 LOGWAYLAND(
209 ("%s [%p] frame_callback_handler %p ready_to_draw %d (set to true)"
210 " initial_draw callback %zd\n",
211 __FUNCTION__, (void*)MOZ_CONTAINER(data),
212 (void*)wl_container->frame_callback_handler, wl_container->ready_to_draw,
213 wl_container->initial_draw_cbs.size()));
214
215 g_clear_pointer(&wl_container->frame_callback_handler, wl_callback_destroy);
216
217 if (!wl_container->ready_to_draw) {
218 wl_container->ready_to_draw = true;
219 for (auto const& cb : wl_container->initial_draw_cbs) {
220 cb();
221 }
222 wl_container->initial_draw_cbs.clear();
223 }
224 }
225
226 static const struct wl_callback_listener moz_container_frame_listener = {
227 moz_container_wayland_frame_callback_handler};
228
after_frame_clock_after_paint(GdkFrameClock * clock,MozContainer * container)229 static void after_frame_clock_after_paint(GdkFrameClock* clock,
230 MozContainer* container) {
231 struct wl_surface* surface = moz_container_wayland_surface_lock(container);
232 if (surface) {
233 wl_surface_commit(surface);
234 moz_container_wayland_surface_unlock(container, &surface);
235 }
236 }
237
moz_gdk_wayland_window_add_frame_callback_surface_locked(MozContainer * container)238 static bool moz_gdk_wayland_window_add_frame_callback_surface_locked(
239 MozContainer* container) {
240 static auto sGdkWaylandWindowAddCallbackSurface =
241 (void (*)(GdkWindow*, struct wl_surface*))dlsym(
242 RTLD_DEFAULT, "gdk_wayland_window_add_frame_callback_surface");
243
244 if (!StaticPrefs::widget_wayland_opaque_region_enabled_AtStartup() ||
245 !sGdkWaylandWindowAddCallbackSurface) {
246 return false;
247 }
248
249 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
250 MozContainerWayland* wl_container = &container->wl_container;
251
252 sGdkWaylandWindowAddCallbackSurface(window, wl_container->surface);
253
254 GdkFrameClock* frame_clock = gdk_window_get_frame_clock(window);
255 g_signal_connect_after(frame_clock, "after-paint",
256 G_CALLBACK(after_frame_clock_after_paint), container);
257 return true;
258 }
259
moz_gdk_wayland_window_remove_frame_callback_surface_locked(MozContainer * container)260 static void moz_gdk_wayland_window_remove_frame_callback_surface_locked(
261 MozContainer* container) {
262 static auto sGdkWaylandWindowRemoveCallbackSurface =
263 (void (*)(GdkWindow*, struct wl_surface*))dlsym(
264 RTLD_DEFAULT, "gdk_wayland_window_remove_frame_callback_surface");
265
266 if (!sGdkWaylandWindowRemoveCallbackSurface) {
267 return;
268 }
269
270 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
271 MozContainerWayland* wl_container = &container->wl_container;
272
273 if (wl_container->surface) {
274 sGdkWaylandWindowRemoveCallbackSurface(window, wl_container->surface);
275 }
276
277 GdkFrameClock* frame_clock = gdk_window_get_frame_clock(window);
278 g_signal_handlers_disconnect_by_func(
279 frame_clock, FuncToGpointer(after_frame_clock_after_paint), container);
280 }
281
moz_container_wayland_unmap_internal(MozContainer * container)282 static void moz_container_wayland_unmap_internal(MozContainer* container) {
283 MozContainerWayland* wl_container = &container->wl_container;
284 MutexAutoLock lock(*wl_container->container_lock);
285
286 LOGWAYLAND(("%s [%p]\n", __FUNCTION__, (void*)container));
287
288 if (wl_container->opaque_region_used) {
289 moz_gdk_wayland_window_remove_frame_callback_surface_locked(container);
290 }
291
292 g_clear_pointer(&wl_container->eglwindow, wl_egl_window_destroy);
293 g_clear_pointer(&wl_container->subsurface, wl_subsurface_destroy);
294 g_clear_pointer(&wl_container->surface, wl_surface_destroy);
295 g_clear_pointer(&wl_container->viewport, wp_viewport_destroy);
296 g_clear_pointer(&wl_container->frame_callback_handler, wl_callback_destroy);
297
298 wl_container->surface_needs_clear = true;
299 wl_container->ready_to_draw = false;
300 wl_container->buffer_scale = 1;
301 wl_container->container_remapped = true;
302 }
303
moz_container_wayland_map_event(GtkWidget * widget,GdkEventAny * event)304 static gboolean moz_container_wayland_map_event(GtkWidget* widget,
305 GdkEventAny* event) {
306 MozContainerWayland* wl_container = &MOZ_CONTAINER(widget)->wl_container;
307 LOGWAYLAND(("%s [%p]\n", __FUNCTION__, (void*)MOZ_CONTAINER(widget)));
308
309 // Don't create wl_subsurface in map_event when it's already created or
310 // if we create it for the first time.
311 if (wl_container->ready_to_draw || wl_container->before_first_size_alloc) {
312 return FALSE;
313 }
314
315 MutexAutoLock lock(*wl_container->container_lock);
316 if (!wl_container->surface) {
317 if (!moz_container_wayland_surface_create_locked(MOZ_CONTAINER(widget))) {
318 return FALSE;
319 }
320 }
321
322 moz_container_wayland_set_scale_factor_locked(MOZ_CONTAINER(widget));
323 moz_container_wayland_set_opaque_region_locked(MOZ_CONTAINER(widget));
324 moz_container_clear_input_region(MOZ_CONTAINER(widget));
325 moz_container_wayland_invalidate(MOZ_CONTAINER(widget));
326 return FALSE;
327 }
328
moz_container_wayland_map(GtkWidget * widget)329 void moz_container_wayland_map(GtkWidget* widget) {
330 LOGWAYLAND(("%s [%p]\n", __FUNCTION__, (void*)widget));
331
332 g_return_if_fail(IS_MOZ_CONTAINER(widget));
333 gtk_widget_set_mapped(widget, TRUE);
334
335 if (gtk_widget_get_has_window(widget)) {
336 gdk_window_show(gtk_widget_get_window(widget));
337 }
338 }
339
moz_container_wayland_unmap(GtkWidget * widget)340 void moz_container_wayland_unmap(GtkWidget* widget) {
341 LOGWAYLAND(("%s [%p]\n", __FUNCTION__, (void*)widget));
342
343 g_return_if_fail(IS_MOZ_CONTAINER(widget));
344 gtk_widget_set_mapped(widget, FALSE);
345
346 if (gtk_widget_get_has_window(widget)) {
347 gdk_window_hide(gtk_widget_get_window(widget));
348 moz_container_wayland_unmap_internal(MOZ_CONTAINER(widget));
349 }
350 }
351
moz_container_wayland_size_allocate(GtkWidget * widget,GtkAllocation * allocation)352 void moz_container_wayland_size_allocate(GtkWidget* widget,
353 GtkAllocation* allocation) {
354 MozContainer* container;
355 GtkAllocation tmp_allocation;
356
357 g_return_if_fail(IS_MOZ_CONTAINER(widget));
358
359 LOGWAYLAND(("moz_container_wayland_size_allocate [%p] %d,%d -> %d x %d\n",
360 (void*)widget, allocation->x, allocation->y, allocation->width,
361 allocation->height));
362
363 /* short circuit if you can */
364 container = MOZ_CONTAINER(widget);
365 gtk_widget_get_allocation(widget, &tmp_allocation);
366 if (!container->children && tmp_allocation.x == allocation->x &&
367 tmp_allocation.y == allocation->y &&
368 tmp_allocation.width == allocation->width &&
369 tmp_allocation.height == allocation->height) {
370 return;
371 }
372 gtk_widget_set_allocation(widget, allocation);
373
374 if (gtk_widget_get_has_window(widget) && gtk_widget_get_realized(widget)) {
375 gdk_window_move_resize(gtk_widget_get_window(widget), allocation->x,
376 allocation->y, allocation->width,
377 allocation->height);
378 // We need to position our subsurface according to GdkWindow
379 // when offset changes (GdkWindow is maximized for instance).
380 // see gtk-clutter-embed.c for reference.
381 MutexAutoLock lock(*container->wl_container.container_lock);
382 if (!container->wl_container.surface) {
383 if (!moz_container_wayland_surface_create_locked(container)) {
384 return;
385 }
386 }
387 moz_container_wayland_set_scale_factor_locked(container);
388 moz_container_wayland_set_opaque_region_locked(container);
389 moz_container_wayland_move_locked(container, allocation->x, allocation->y);
390 moz_container_clear_input_region(container);
391 moz_container_wayland_invalidate(MOZ_CONTAINER(widget));
392 container->wl_container.before_first_size_alloc = false;
393 }
394 }
395
moz_container_wayland_create_opaque_region(int aX,int aY,int aWidth,int aHeight,bool aSubtractCorners)396 static wl_region* moz_container_wayland_create_opaque_region(
397 int aX, int aY, int aWidth, int aHeight, bool aSubtractCorners) {
398 struct wl_compositor* compositor = WaylandDisplayGet()->GetCompositor();
399 wl_region* region = wl_compositor_create_region(compositor);
400 wl_region_add(region, aX, aY, aWidth, aHeight);
401 if (aSubtractCorners) {
402 wl_region_subtract(region, aX, aY, TITLEBAR_SHAPE_MASK_HEIGHT,
403 TITLEBAR_SHAPE_MASK_HEIGHT);
404 wl_region_subtract(region, aX + aWidth - TITLEBAR_SHAPE_MASK_HEIGHT, aY,
405 TITLEBAR_SHAPE_MASK_HEIGHT, TITLEBAR_SHAPE_MASK_HEIGHT);
406 }
407 return region;
408 }
409
moz_container_wayland_set_opaque_region_locked(MozContainer * container)410 static void moz_container_wayland_set_opaque_region_locked(
411 MozContainer* container) {
412 MozContainerWayland* wl_container = &container->wl_container;
413
414 if (!wl_container->opaque_region_needs_updates) {
415 return;
416 }
417
418 if (!wl_container->opaque_region_used) {
419 wl_container->opaque_region_needs_updates = false;
420 return;
421 }
422
423 GtkAllocation allocation;
424 gtk_widget_get_allocation(GTK_WIDGET(container), &allocation);
425
426 wl_region* region = moz_container_wayland_create_opaque_region(
427 0, 0, allocation.width, allocation.height,
428 wl_container->opaque_region_subtract_corners);
429 wl_surface_set_opaque_region(wl_container->surface, region);
430 wl_region_destroy(region);
431 wl_container->opaque_region_needs_updates = false;
432 }
433
moz_container_wayland_set_opaque_region(MozContainer * container)434 static void moz_container_wayland_set_opaque_region(MozContainer* container) {
435 MozContainerWayland* wl_container = &container->wl_container;
436 MutexAutoLock lock(*wl_container->container_lock);
437 if (wl_container->surface) {
438 moz_container_wayland_set_opaque_region_locked(container);
439 }
440 }
441
moz_container_wayland_set_scale_factor_locked(MozContainer * container)442 static void moz_container_wayland_set_scale_factor_locked(
443 MozContainer* container) {
444 MozContainerWayland* wl_container = &container->wl_container;
445 nsWindow* window = moz_container_get_nsWindow(container);
446
447 if (window && window->UseFractionalScale()) {
448 if (!wl_container->viewport) {
449 wl_container->viewport = wp_viewporter_get_viewport(
450 WaylandDisplayGet()->GetViewporter(), wl_container->surface);
451 }
452
453 GdkWindow* gdkWindow = gtk_widget_get_window(GTK_WIDGET(container));
454 wp_viewport_set_destination(wl_container->viewport,
455 gdk_window_get_width(gdkWindow),
456 gdk_window_get_height(gdkWindow));
457 } else {
458 int scale = window ? window->GdkCeiledScaleFactor() : 1;
459
460 if (scale == wl_container->buffer_scale) {
461 return;
462 }
463
464 LOGWAYLAND(("%s [%p] scale %d\n", __FUNCTION__, (void*)container, scale));
465 wl_surface_set_buffer_scale(wl_container->surface, scale);
466 wl_container->buffer_scale = scale;
467 }
468 }
469
moz_container_wayland_set_scale_factor(MozContainer * container)470 void moz_container_wayland_set_scale_factor(MozContainer* container) {
471 MutexAutoLock lock(*container->wl_container.container_lock);
472 if (container->wl_container.surface) {
473 moz_container_wayland_set_scale_factor_locked(container);
474 }
475 }
476
moz_container_wayland_surface_create_locked(MozContainer * container)477 static bool moz_container_wayland_surface_create_locked(
478 MozContainer* container) {
479 MozContainerWayland* wl_container = &container->wl_container;
480
481 LOGWAYLAND(("%s [%p]\n", __FUNCTION__, (void*)container));
482
483 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
484 wl_surface* parent_surface = gdk_wayland_window_get_wl_surface(window);
485 if (!parent_surface) {
486 LOGWAYLAND((" Failed - missing parent surface!"));
487 return false;
488 }
489 LOGWAYLAND((" gtk wl_surface %p ID %d\n", (void*)parent_surface,
490 wl_proxy_get_id((struct wl_proxy*)parent_surface)));
491
492 // Available as of GTK 3.8+
493 struct wl_compositor* compositor = WaylandDisplayGet()->GetCompositor();
494 wl_container->surface = wl_compositor_create_surface(compositor);
495 if (!wl_container->surface) {
496 LOGWAYLAND((" Failed - can't create surface!"));
497 return false;
498 }
499
500 wl_container->subsurface =
501 wl_subcompositor_get_subsurface(WaylandDisplayGet()->GetSubcompositor(),
502 wl_container->surface, parent_surface);
503 if (!wl_container->subsurface) {
504 g_clear_pointer(&wl_container->surface, wl_surface_destroy);
505 LOGWAYLAND((" Failed - can't create sub-surface!"));
506 return false;
507 }
508 wl_subsurface_set_desync(wl_container->subsurface);
509
510 // Try to guess subsurface offset to avoid potential flickering.
511 int dx, dy;
512 if (moz_container_get_nsWindow(container)->GetCSDDecorationOffset(&dx, &dy)) {
513 wl_container->subsurface_dx = dx;
514 wl_container->subsurface_dy = dy;
515 wl_subsurface_set_position(wl_container->subsurface, dx, dy);
516 LOGWAYLAND((" guessing subsurface position %d %d\n", dx, dy));
517 }
518
519 // If there's pending frame callback it's for wrong parent surface,
520 // so delete it.
521 if (wl_container->frame_callback_handler) {
522 g_clear_pointer(&wl_container->frame_callback_handler, wl_callback_destroy);
523 }
524 wl_container->frame_callback_handler = wl_surface_frame(parent_surface);
525 wl_callback_add_listener(wl_container->frame_callback_handler,
526 &moz_container_frame_listener, container);
527 LOGWAYLAND((
528 " created frame callback ID %d\n",
529 wl_proxy_get_id((struct wl_proxy*)wl_container->frame_callback_handler)));
530
531 wl_surface_commit(wl_container->surface);
532 wl_display_flush(WaylandDisplayGet()->GetDisplay());
533
534 wl_container->opaque_region_used =
535 moz_gdk_wayland_window_add_frame_callback_surface_locked(container);
536
537 LOGWAYLAND((" created surface %p ID %d\n", (void*)wl_container->surface,
538 wl_proxy_get_id((struct wl_proxy*)wl_container->surface)));
539 return true;
540 }
541
moz_container_wayland_surface_lock(MozContainer * container)542 struct wl_surface* moz_container_wayland_surface_lock(MozContainer* container) {
543 // Temporary disabled to avoid log noise
544 // LOGWAYLAND(("%s [%p] surface %p ready_to_draw %d\n", __FUNCTION__,
545 // (void*)container, (void*)container->wl_container.surface,
546 // container->wl_container.ready_to_draw));
547 if (!container->wl_container.surface ||
548 !container->wl_container.ready_to_draw) {
549 return nullptr;
550 }
551
552 container->wl_container.container_lock->Lock();
553
554 moz_container_wayland_set_scale_factor_locked(container);
555 return container->wl_container.surface;
556 }
557
moz_container_wayland_surface_unlock(MozContainer * container,struct wl_surface ** surface)558 void moz_container_wayland_surface_unlock(MozContainer* container,
559 struct wl_surface** surface) {
560 // Temporary disabled to avoid log noise
561 // LOGWAYLAND(("%s [%p] surface %p\n", __FUNCTION__, (void*)container,
562 // (void*)container->wl_container.surface));
563 if (*surface) {
564 container->wl_container.container_lock->Unlock();
565 *surface = nullptr;
566 }
567 }
568
moz_container_wayland_get_egl_window(MozContainer * container,double scale)569 struct wl_egl_window* moz_container_wayland_get_egl_window(
570 MozContainer* container, double scale) {
571 MozContainerWayland* wl_container = &container->wl_container;
572
573 LOGWAYLAND(("%s [%p] eglwindow %p\n", __FUNCTION__, (void*)container,
574 (void*)wl_container->eglwindow));
575
576 MutexAutoLock lock(*wl_container->container_lock);
577 if (!wl_container->surface || !wl_container->ready_to_draw) {
578 return nullptr;
579 }
580 if (!wl_container->eglwindow) {
581 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
582 wl_container->eglwindow = wl_egl_window_create(
583 wl_container->surface, (int)round(gdk_window_get_width(window) * scale),
584 (int)round(gdk_window_get_height(window) * scale));
585
586 LOGWAYLAND(("%s [%p] created eglwindow %p\n", __FUNCTION__,
587 (void*)container, (void*)wl_container->eglwindow));
588 }
589 return wl_container->eglwindow;
590 }
591
moz_container_wayland_has_egl_window(MozContainer * container)592 gboolean moz_container_wayland_has_egl_window(MozContainer* container) {
593 return container->wl_container.eglwindow != nullptr;
594 }
595
moz_container_wayland_surface_needs_clear(MozContainer * container)596 gboolean moz_container_wayland_surface_needs_clear(MozContainer* container) {
597 int ret = container->wl_container.surface_needs_clear;
598 container->wl_container.surface_needs_clear = false;
599 return ret;
600 }
601
moz_container_wayland_get_and_reset_remapped(MozContainer * container)602 gboolean moz_container_wayland_get_and_reset_remapped(MozContainer* container) {
603 int ret = container->wl_container.container_remapped;
604 container->wl_container.container_remapped = false;
605 return ret;
606 }
607
moz_container_wayland_update_opaque_region(MozContainer * container,bool aSubtractCorners)608 void moz_container_wayland_update_opaque_region(MozContainer* container,
609 bool aSubtractCorners) {
610 MozContainerWayland* wl_container = &container->wl_container;
611 wl_container->opaque_region_needs_updates = true;
612 wl_container->opaque_region_subtract_corners = aSubtractCorners;
613
614 // When GL compositor / WebRender is used,
615 // moz_container_wayland_get_egl_window() is called only once when window
616 // is created or resized so update opaque region now.
617 if (moz_container_wayland_has_egl_window(container)) {
618 moz_container_wayland_set_opaque_region(container);
619 }
620 }
621
moz_container_wayland_can_draw(MozContainer * container)622 gboolean moz_container_wayland_can_draw(MozContainer* container) {
623 return container ? container->wl_container.ready_to_draw : false;
624 }
625
moz_container_wayland_get_scale(MozContainer * container)626 double moz_container_wayland_get_scale(MozContainer* container) {
627 MozContainerWayland* wl_container = &container->wl_container;
628 MutexAutoLock lock(*wl_container->container_lock);
629
630 nsWindow* window = moz_container_get_nsWindow(container);
631 return window ? window->FractionalScaleFactor() : 1;
632 }
633
moz_container_wayland_get_viewport(MozContainer * container)634 struct wp_viewport* moz_container_wayland_get_viewport(
635 MozContainer* container) {
636 MozContainerWayland* wl_container = &container->wl_container;
637 MutexAutoLock lock(*wl_container->container_lock);
638
639 if (!wl_container->viewport) {
640 wl_container->viewport = wp_viewporter_get_viewport(
641 WaylandDisplayGet()->GetViewporter(), wl_container->surface);
642 }
643 return wl_container->viewport;
644 }
645