diff options
Diffstat (limited to 'widget/gtk/nsWaylandDisplay.cpp')
-rw-r--r-- | widget/gtk/nsWaylandDisplay.cpp | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/widget/gtk/nsWaylandDisplay.cpp b/widget/gtk/nsWaylandDisplay.cpp new file mode 100644 index 0000000000..0fc7433539 --- /dev/null +++ b/widget/gtk/nsWaylandDisplay.cpp @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsWaylandDisplay.h" + +#include <dlfcn.h> + +#include "base/message_loop.h" // for MessageLoop +#include "base/task.h" // for NewRunnableMethod, etc +#include "mozilla/gfx/Logging.h" // for gfxCriticalNote +#include "mozilla/StaticMutex.h" +#include "mozilla/Array.h" +#include "mozilla/StaticPtr.h" +#include "mozilla/ThreadLocal.h" +#include "mozilla/StaticPrefs_widget.h" +#include "mozilla/Sprintf.h" +#include "WidgetUtilsGtk.h" +#include "nsGtkKeyUtils.h" + +namespace mozilla::widget { + +static nsWaylandDisplay* gWaylandDisplay; + +void WaylandDisplayRelease() { + MOZ_RELEASE_ASSERT(NS_IsMainThread(), + "WaylandDisplay can be released in main thread only!"); + if (!gWaylandDisplay) { + NS_WARNING("WaylandDisplayRelease(): Wayland display is missing!"); + return; + } + delete gWaylandDisplay; + gWaylandDisplay = nullptr; +} + +wl_display* WaylandDisplayGetWLDisplay() { + GdkDisplay* disp = gdk_display_get_default(); + if (!GdkIsWaylandDisplay(disp)) { + return nullptr; + } + return gdk_wayland_display_get_wl_display(disp); +} + +nsWaylandDisplay* WaylandDisplayGet() { + if (!gWaylandDisplay) { + MOZ_RELEASE_ASSERT(NS_IsMainThread(), + "WaylandDisplay can be created in main thread only!"); + wl_display* waylandDisplay = WaylandDisplayGetWLDisplay(); + if (!waylandDisplay) { + return nullptr; + } + gWaylandDisplay = new nsWaylandDisplay(waylandDisplay); + } + return gWaylandDisplay; +} + +void nsWaylandDisplay::SetShm(wl_shm* aShm) { mShm = aShm; } + +void nsWaylandDisplay::SetCompositor(wl_compositor* aCompositor) { + mCompositor = aCompositor; +} + +void nsWaylandDisplay::SetSubcompositor(wl_subcompositor* aSubcompositor) { + mSubcompositor = aSubcompositor; +} + +void nsWaylandDisplay::SetIdleInhibitManager( + zwp_idle_inhibit_manager_v1* aIdleInhibitManager) { + mIdleInhibitManager = aIdleInhibitManager; +} + +void nsWaylandDisplay::SetViewporter(wp_viewporter* aViewporter) { + mViewporter = aViewporter; +} + +void nsWaylandDisplay::SetRelativePointerManager( + zwp_relative_pointer_manager_v1* aRelativePointerManager) { + mRelativePointerManager = aRelativePointerManager; +} + +void nsWaylandDisplay::SetPointerConstraints( + zwp_pointer_constraints_v1* aPointerConstraints) { + mPointerConstraints = aPointerConstraints; +} + +void nsWaylandDisplay::SetDmabuf(zwp_linux_dmabuf_v1* aDmabuf) { + mDmabuf = aDmabuf; +} + +void nsWaylandDisplay::SetXdgActivation(xdg_activation_v1* aXdgActivation) { + mXdgActivation = aXdgActivation; +} + +static void global_registry_handler(void* data, wl_registry* registry, + uint32_t id, const char* interface, + uint32_t version) { + auto* display = static_cast<nsWaylandDisplay*>(data); + if (!display) { + return; + } + + if (strcmp(interface, "wl_shm") == 0) { + auto* shm = WaylandRegistryBind<wl_shm>(registry, id, &wl_shm_interface, 1); + display->SetShm(shm); + } else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0) { + auto* idle_inhibit_manager = + WaylandRegistryBind<zwp_idle_inhibit_manager_v1>( + registry, id, &zwp_idle_inhibit_manager_v1_interface, 1); + display->SetIdleInhibitManager(idle_inhibit_manager); + } else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) { + auto* relative_pointer_manager = + WaylandRegistryBind<zwp_relative_pointer_manager_v1>( + registry, id, &zwp_relative_pointer_manager_v1_interface, 1); + display->SetRelativePointerManager(relative_pointer_manager); + } else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) { + auto* pointer_constraints = WaylandRegistryBind<zwp_pointer_constraints_v1>( + registry, id, &zwp_pointer_constraints_v1_interface, 1); + display->SetPointerConstraints(pointer_constraints); + } else if (strcmp(interface, "wl_compositor") == 0) { + // Requested wl_compositor version 4 as we need wl_surface_damage_buffer(). + auto* compositor = WaylandRegistryBind<wl_compositor>( + registry, id, &wl_compositor_interface, 4); + display->SetCompositor(compositor); + } else if (strcmp(interface, "wl_subcompositor") == 0) { + auto* subcompositor = WaylandRegistryBind<wl_subcompositor>( + registry, id, &wl_subcompositor_interface, 1); + display->SetSubcompositor(subcompositor); + } else if (strcmp(interface, "wp_viewporter") == 0) { + auto* viewporter = WaylandRegistryBind<wp_viewporter>( + registry, id, &wp_viewporter_interface, 1); + display->SetViewporter(viewporter); + } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version > 2) { + auto* dmabuf = WaylandRegistryBind<zwp_linux_dmabuf_v1>( + registry, id, &zwp_linux_dmabuf_v1_interface, 3); + display->SetDmabuf(dmabuf); + } else if (strcmp(interface, "xdg_activation_v1") == 0) { + auto* activation = WaylandRegistryBind<xdg_activation_v1>( + registry, id, &xdg_activation_v1_interface, 1); + display->SetXdgActivation(activation); + // Install keyboard handlers for main thread only + } else if (strcmp(interface, "wl_seat") == 0) { + auto* seat = + WaylandRegistryBind<wl_seat>(registry, id, &wl_seat_interface, 1); + KeymapWrapper::SetSeat(seat, id); + } +} + +static void global_registry_remover(void* data, wl_registry* registry, + uint32_t id) { + KeymapWrapper::ClearSeat(id); +} + +static const struct wl_registry_listener registry_listener = { + global_registry_handler, global_registry_remover}; + +nsWaylandDisplay::~nsWaylandDisplay() {} + +static void WlLogHandler(const char* format, va_list args) { + char error[1000]; + VsprintfLiteral(error, format, args); + gfxCriticalNote << "Wayland protocol error: " << error; +} + +nsWaylandDisplay::nsWaylandDisplay(wl_display* aDisplay) + : mThreadId(PR_GetCurrentThread()), mDisplay(aDisplay) { + // GTK sets the log handler on display creation, thus we overwrite it here + // in a similar fashion + wl_log_set_handler_client(WlLogHandler); + + mRegistry = wl_display_get_registry(mDisplay); + wl_registry_add_listener(mRegistry, ®istry_listener, this); + wl_display_roundtrip(mDisplay); + wl_display_roundtrip(mDisplay); + + // Check we have critical Wayland interfaces. + // Missing ones indicates a compositor bug and we can't continue. + MOZ_DIAGNOSTIC_ASSERT(GetShm(), "We're missing shm interface!"); + MOZ_DIAGNOSTIC_ASSERT(GetCompositor(), "We're missing compositor interface!"); + MOZ_DIAGNOSTIC_ASSERT(GetSubcompositor(), + "We're missing subcompositor interface!"); +} + +} // namespace mozilla::widget |