Bug 1507475 - [Wayland] Implement global wayland registry, r=jhorak

Differential Revision: https://phabricator.services.mozilla.com/D12255

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Martin Stransky 2018-11-23 07:04:16 +00:00
parent ae30c70345
commit 786a526298
15 changed files with 421 additions and 466 deletions

View File

@ -59,9 +59,6 @@ void WindowSurfaceProvider::Initialize(
#ifdef MOZ_WAYLAND
void WindowSurfaceProvider::Initialize(nsWindow *aWidget)
{
MOZ_ASSERT(aWidget->GetWaylandDisplay(),
"We are supposed to have a Wayland display!");
mWidget = aWidget;
mIsX11Display = false;
}

View File

@ -4,24 +4,25 @@
* 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 "WindowSurfaceWayland.h"
#include "base/message_loop.h" // for MessageLoop
#include "base/task.h" // for NewRunnableMethod, etc
#include "nsPrintfCString.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Tools.h"
#include "gfxPlatform.h"
#include "mozcontainer.h"
#include "nsTArray.h"
#include "mozilla/StaticMutex.h"
#include "mozwayland/mozwayland.h"
#include "base/message_loop.h" // for MessageLoop
#include "base/task.h" // for NewRunnableMethod, etc
#include <sys/mman.h>
#include <assert.h>
#include <fcntl.h>
#include <errno.h>
namespace mozilla {
namespace widget {
/*
Wayland multi-thread rendering scheme
@ -131,202 +132,8 @@ handle to wayland compositor by WindowBackBuffer/WindowSurfaceWayland
(wl_buffer/wl_surface).
*/
namespace mozilla {
namespace widget {
#define BUFFER_BPP 4
#define MAX_DISPLAY_CONNECTIONS 2
static nsWaylandDisplay* gWaylandDisplays[MAX_DISPLAY_CONNECTIONS];
static StaticMutex gWaylandDisplaysMutex;
// Each thread which is using wayland connection (wl_display) has to operate
// its own wl_event_queue. Main Firefox thread wl_event_queue is handled
// by Gtk main loop, other threads/wl_event_queue has to be handled by us.
//
// nsWaylandDisplay is our interface to wayland compositor. It provides wayland
// global objects as we need (wl_display, wl_shm) and operates wl_event_queue on
// compositor (not the main) thread.
static nsWaylandDisplay* WaylandDisplayGet(wl_display *aDisplay);
static void WaylandDisplayRelease(wl_display *aDisplay);
static void WaylandDisplayLoop(wl_display *aDisplay);
// TODO: Bug 1467125 - We need to integrate wl_display_dispatch_queue_pending() with
// compositor event loop.
#define EVENT_LOOP_DELAY (1000/240)
// Get WaylandDisplay for given wl_display and actual calling thread.
static nsWaylandDisplay*
WaylandDisplayGetLocked(wl_display *aDisplay, const StaticMutexAutoLock&)
{
for (auto& display: gWaylandDisplays) {
if (display && display->Matches(aDisplay)) {
NS_ADDREF(display);
return display;
}
}
for (auto& display: gWaylandDisplays) {
if (display == nullptr) {
display = new nsWaylandDisplay(aDisplay);
NS_ADDREF(display);
return display;
}
}
MOZ_CRASH("There's too many wayland display conections!");
return nullptr;
}
static nsWaylandDisplay*
WaylandDisplayGet(wl_display *aDisplay)
{
StaticMutexAutoLock lock(gWaylandDisplaysMutex);
return WaylandDisplayGetLocked(aDisplay, lock);
}
static bool
WaylandDisplayReleaseLocked(wl_display *aDisplay,
const StaticMutexAutoLock&)
{
for (auto& display: gWaylandDisplays) {
if (display && display->Matches(aDisplay)) {
int rc = display->Release();
if (rc == 0) {
display = nullptr;
}
return true;
}
}
MOZ_ASSERT(false, "Missing nsWaylandDisplay for this thread!");
return false;
}
static void
WaylandDisplayRelease(wl_display *aDisplay)
{
StaticMutexAutoLock lock(gWaylandDisplaysMutex);
WaylandDisplayReleaseLocked(aDisplay, lock);
}
static void
WaylandDisplayLoopLocked(wl_display* aDisplay,
const StaticMutexAutoLock&)
{
for (auto& display: gWaylandDisplays) {
if (display && display->Matches(aDisplay)) {
if (display->DisplayLoop()) {
MessageLoop::current()->PostDelayedTask(
NewRunnableFunction("WaylandDisplayLoop",
&WaylandDisplayLoop,
aDisplay),
EVENT_LOOP_DELAY);
}
break;
}
}
}
static void
WaylandDisplayLoop(wl_display* aDisplay)
{
MOZ_ASSERT(!NS_IsMainThread());
StaticMutexAutoLock lock(gWaylandDisplaysMutex);
WaylandDisplayLoopLocked(aDisplay, lock);
}
static void
global_registry_handler(void *data, wl_registry *registry, uint32_t id,
const char *interface, uint32_t version)
{
if (strcmp(interface, "wl_shm") == 0) {
auto interface = reinterpret_cast<nsWaylandDisplay *>(data);
auto shm = static_cast<wl_shm*>(
wl_registry_bind(registry, id, &wl_shm_interface, 1));
wl_proxy_set_queue((struct wl_proxy *)shm, interface->GetEventQueue());
interface->SetShm(shm);
}
}
static void
global_registry_remover(void *data, wl_registry *registry, uint32_t id)
{
}
static const struct wl_registry_listener registry_listener = {
global_registry_handler,
global_registry_remover
};
wl_shm*
nsWaylandDisplay::GetShm()
{
MOZ_ASSERT(mThreadId == PR_GetCurrentThread());
if (!mShm) {
// wl_shm is not provided by Gtk so we need to query wayland directly
// See weston/simple-shm.c and create_display() for reference.
wl_registry* registry = wl_display_get_registry(mDisplay);
wl_registry_add_listener(registry, &registry_listener, this);
wl_proxy_set_queue((struct wl_proxy *)registry, mEventQueue);
if (mEventQueue) {
wl_display_roundtrip_queue(mDisplay, mEventQueue);
} else {
wl_display_roundtrip(mDisplay);
}
MOZ_RELEASE_ASSERT(mShm, "Wayland registry query failed!");
}
return(mShm);
}
bool
nsWaylandDisplay::DisplayLoop()
{
wl_display_dispatch_queue_pending(mDisplay, mEventQueue);
return true;
}
bool
nsWaylandDisplay::Matches(wl_display *aDisplay)
{
return mThreadId == PR_GetCurrentThread() && aDisplay == mDisplay;
}
NS_IMPL_ISUPPORTS(nsWaylandDisplay, nsISupports);
nsWaylandDisplay::nsWaylandDisplay(wl_display *aDisplay)
: mThreadId(PR_GetCurrentThread())
// gfx::SurfaceFormat::B8G8R8A8 is a basic Wayland format
// and is always present.
// TODO: Provide also format without alpha (Bug 1470126).
, mFormat(gfx::SurfaceFormat::B8G8R8A8)
, mShm(nullptr)
, mDisplay(aDisplay)
{
if (NS_IsMainThread()) {
// Use default event queue in main thread operated by Gtk+.
mEventQueue = nullptr;
} else {
mEventQueue = wl_display_create_queue(mDisplay);
MessageLoop::current()->PostTask(NewRunnableFunction(
"WaylandDisplayLoop", &WaylandDisplayLoop, mDisplay));
}
}
nsWaylandDisplay::~nsWaylandDisplay()
{
MOZ_ASSERT(mThreadId == PR_GetCurrentThread());
// Owned by Gtk+, we don't need to release
mDisplay = nullptr;
if (mEventQueue) {
wl_event_queue_destroy(mEventQueue);
mEventQueue = nullptr;
}
}
gfx::SurfaceFormat WindowBackBuffer::mFormat = gfx::SurfaceFormat::B8G8R8A8;
int
WaylandShmPool::CreateTemporaryFile(int aSize)
@ -544,7 +351,7 @@ WindowBackBuffer::Lock()
return gfxPlatform::CreateDrawTargetForData(static_cast<unsigned char*>(mShmPool.GetImageData()),
lockSize,
BUFFER_BPP * mWidth,
mWaylandDisplay->GetSurfaceFormat());
mFormat);
}
static void
@ -562,7 +369,7 @@ static const struct wl_callback_listener frame_listener = {
WindowSurfaceWayland::WindowSurfaceWayland(nsWindow *aWindow)
: mWindow(aWindow)
, mWaylandDisplay(WaylandDisplayGet(aWindow->GetWaylandDisplay()))
, mWaylandDisplay(WaylandDisplayGet())
, mWaylandBuffer(nullptr)
, mFrameCallback(nullptr)
, mLastCommittedSurface(nullptr)
@ -610,9 +417,9 @@ WindowSurfaceWayland::~WindowSurfaceWayland()
mDisplayThreadMessageLoop->PostTask(
NewRunnableFunction("WaylandDisplayRelease",
&WaylandDisplayRelease,
mWaylandDisplay->GetDisplay()));
mWaylandDisplay));
} else {
WaylandDisplayRelease(mWaylandDisplay->GetDisplay());
WaylandDisplayRelease(mWaylandDisplay);
}
}
@ -700,7 +507,7 @@ WindowSurfaceWayland::LockImageSurface(const gfx::IntSize& aLockSize)
if (!mImageSurface || mImageSurface->CairoStatus() ||
!(aLockSize <= mImageSurface->GetSize())) {
mImageSurface = new gfxImageSurface(aLockSize,
SurfaceFormatToImageFormat(mWaylandDisplay->GetSurfaceFormat()));
SurfaceFormatToImageFormat(WindowBackBuffer::GetSurfaceFormat()));
if (mImageSurface->CairoStatus()) {
return nullptr;
}
@ -709,7 +516,7 @@ WindowSurfaceWayland::LockImageSurface(const gfx::IntSize& aLockSize)
return gfxPlatform::CreateDrawTargetForData(mImageSurface->Data(),
mImageSurface->GetSize(),
mImageSurface->Stride(),
mWaylandDisplay->GetSurfaceFormat());
WindowBackBuffer::GetSurfaceFormat());
}
/*

View File

@ -9,39 +9,13 @@
#include <prthread.h>
#include "mozilla/gfx/Types.h"
#include "nsWaylandDisplay.h"
#define BACK_BUFFER_NUM 2
namespace mozilla {
namespace widget {
// Our general connection to Wayland display server,
// holds our display connection and runs event loop.
class nsWaylandDisplay : public nsISupports {
NS_DECL_THREADSAFE_ISUPPORTS
public:
explicit nsWaylandDisplay(wl_display *aDisplay);
wl_shm* GetShm();
void SetShm(wl_shm* aShm) { mShm = aShm; };
wl_display* GetDisplay() { return mDisplay; };
wl_event_queue* GetEventQueue() { return mEventQueue; };
gfx::SurfaceFormat GetSurfaceFormat() { return mFormat; };
bool DisplayLoop();
bool Matches(wl_display *aDisplay);
private:
virtual ~nsWaylandDisplay();
PRThread* mThreadId;
gfx::SurfaceFormat mFormat;
wl_shm* mShm;
wl_event_queue* mEventQueue;
wl_display* mDisplay;
};
// Allocates and owns shared memory for Wayland drawing surface
class WaylandShmPool {
public:
@ -88,6 +62,11 @@ public:
return aBuffer->mWidth == mWidth && aBuffer->mHeight == mHeight;
}
static gfx::SurfaceFormat GetSurfaceFormat()
{
return mFormat;
}
private:
void Create(int aWidth, int aHeight);
void Release();
@ -102,6 +81,7 @@ private:
int mHeight;
bool mAttached;
nsWaylandDisplay* mWaylandDisplay;
static gfx::SurfaceFormat mFormat;
};
// WindowSurfaceWayland is an abstraction for wl_surface

View File

@ -17,6 +17,8 @@
namespace mozilla {
namespace widget {
using namespace mozilla::gfx;
// gfxImageSurface pixel format configuration.
#define SHAPED_IMAGE_SURFACE_BPP 4
#ifdef IS_BIG_ENDIAN

View File

@ -9,6 +9,7 @@
#ifdef MOZ_X11
#include <glib.h>
#include "WindowSurfaceX11.h"
#include "gfxXlibSurface.h"
#include "gfxImageSurface.h"

View File

@ -97,6 +97,7 @@ if CONFIG['MOZ_X11']:
if CONFIG['MOZ_WAYLAND']:
UNIFIED_SOURCES += [
'nsClipboardWayland.cpp',
'nsWaylandDisplay.cpp',
'WindowSurfaceWayland.cpp',
]

View File

@ -9,7 +9,7 @@
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#ifdef MOZ_WAYLAND
#include "mozwayland/mozwayland.h"
#include "nsWaylandDisplay.h"
#include <wayland-egl.h>
#endif
#include <stdio.h>
@ -20,6 +20,11 @@
#include "maiRedundantObjectFactory.h"
#endif
#ifdef MOZ_WAYLAND
using namespace mozilla;
using namespace mozilla::widget;
#endif
/* init methods */
static void moz_container_class_init (MozContainerClass *klass);
static void moz_container_init (MozContainer *container);
@ -168,37 +173,6 @@ moz_container_class_init (MozContainerClass *klass)
container_class->add = moz_container_add;
}
#if defined(MOZ_WAYLAND)
static void
registry_handle_global (void *data,
struct wl_registry *registry,
uint32_t name,
const char *interface,
uint32_t version)
{
MozContainer *container = MOZ_CONTAINER(data);
if(strcmp(interface, "wl_subcompositor") == 0) {
container->subcompositor =
static_cast<wl_subcompositor*>(wl_registry_bind(registry,
name,
&wl_subcompositor_interface,
1));
}
}
static void
registry_handle_global_remove (void *data,
struct wl_registry *registry,
uint32_t name)
{
}
static const struct wl_registry_listener registry_listener = {
registry_handle_global,
registry_handle_global_remove
};
#endif
void
moz_container_init (MozContainer *container)
{
@ -207,28 +181,11 @@ moz_container_init (MozContainer *container)
gtk_widget_set_redraw_on_allocate(GTK_WIDGET(container), FALSE);
#if defined(MOZ_WAYLAND)
{
container->subcompositor = nullptr;
container->surface = nullptr;
container->subsurface = nullptr;
container->eglwindow = nullptr;
container->parent_surface_committed = false;
container->needs_clear = true;
GdkDisplay *gdk_display = gtk_widget_get_display(GTK_WIDGET(container));
if (!GDK_IS_X11_DISPLAY(gdk_display)) {
// Available as of GTK 3.8+
static auto sGdkWaylandDisplayGetWlDisplay =
(wl_display *(*)(GdkDisplay *))
dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
wl_display* display = sGdkWaylandDisplayGetWlDisplay(gdk_display);
wl_registry* registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, container);
wl_display_dispatch(display);
wl_display_roundtrip(display);
}
}
container->surface = nullptr;
container->subsurface = nullptr;
container->eglwindow = nullptr;
container->parent_surface_committed = false;
container->needs_clear = true;
#endif
}
@ -284,6 +241,7 @@ moz_container_map_surface(MozContainer *container)
}
if (!container->surface) {
// TODO - use nsWaylandDisplay::compositor for compositor thread.
struct wl_compositor *compositor;
compositor = sGdkWaylandDisplayGetWlCompositor(display);
container->surface = wl_compositor_create_surface(compositor);
@ -298,11 +256,15 @@ moz_container_map_surface(MozContainer *container)
// to mContainer.
return false;
}
GdkDisplay* display = gtk_widget_get_display(GTK_WIDGET(container));
nsWaylandDisplay* waylandDisplay = WaylandDisplayGet(display);
wl_subcompositor* subcompositor = waylandDisplay->GetSubcompositor();
container->subsurface =
wl_subcompositor_get_subsurface(subcompositor,
container->surface,
gtk_surface);
WaylandDisplayRelease(waylandDisplay);
container->subsurface =
wl_subcompositor_get_subsurface (container->subcompositor,
container->surface,
gtk_surface);
gint x, y;
gdk_window_get_position(window, &x, &y);
wl_subsurface_set_position(container->subsurface, x, y);
@ -310,7 +272,6 @@ moz_container_map_surface(MozContainer *container)
// Route input to parent wl_surface owned by Gtk+ so we get input
// events from Gtk+.
GdkDisplay* display = gtk_widget_get_display(GTK_WIDGET (container));
wl_compositor* compositor = sGdkWaylandDisplayGetWlCompositor(display);
wl_region* region = wl_compositor_create_region(compositor);
wl_surface_set_input_region(container->surface, region);

View File

@ -58,7 +58,6 @@ typedef struct _MozContainerClass MozContainerClass;
* present in wayland-devel < 1.12
*/
#ifdef MOZ_WAYLAND
struct wl_subcompositor;
struct wl_surface;
struct wl_subsurface;
#endif
@ -69,7 +68,6 @@ struct _MozContainer
GList *children;
#ifdef MOZ_WAYLAND
struct wl_subcompositor *subcompositor;
struct wl_surface *surface;
struct wl_subsurface *subsurface;
struct wl_egl_window *eglwindow;

View File

@ -25,6 +25,7 @@
#include "mozilla/TimeStamp.h"
#include "nsDragService.h"
#include "mozwayland/mozwayland.h"
#include "nsWaylandDisplay.h"
#include "imgIContainer.h"
@ -514,7 +515,7 @@ nsRetrievalContextWayland::AddDragAndDropDataOffer(wl_data_offer *aDropDataOffer
NS_ASSERTION(dataOffer, "We're missing drag and drop data offer!");
if (dataOffer) {
g_hash_table_remove(mActiveOffers, aDropDataOffer);
mDragContext = new nsWaylandDragContext(dataOffer, mDisplay);
mDragContext = new nsWaylandDragContext(dataOffer, mDisplay->GetDisplay());
}
}
@ -704,72 +705,12 @@ gtk_primary_selection_device_listener primary_selection_device_listener = {
bool
nsRetrievalContextWayland::HasSelectionSupport(void)
{
return mPrimarySelectionDataDeviceManager != nullptr;
return mDisplay->GetPrimarySelectionDeviceManager() != nullptr;
}
void
nsRetrievalContextWayland::InitDataDeviceManager(wl_registry *registry,
uint32_t id,
uint32_t version)
{
int data_device_manager_version = MIN (version, 3);
mDataDeviceManager = (wl_data_device_manager *)wl_registry_bind(registry, id,
&wl_data_device_manager_interface, data_device_manager_version);
}
void
nsRetrievalContextWayland::InitPrimarySelectionDataDeviceManager(
wl_registry *registry, uint32_t id)
{
mPrimarySelectionDataDeviceManager =
(gtk_primary_selection_device_manager *)wl_registry_bind(registry, id,
&gtk_primary_selection_device_manager_interface, 1);
}
void
nsRetrievalContextWayland::InitSeat(wl_registry *registry,
uint32_t id, uint32_t version,
void *data)
{
mSeat = (wl_seat*)wl_registry_bind(registry, id, &wl_seat_interface, 1);
}
static void
gdk_registry_handle_global(void *data,
struct wl_registry *registry,
uint32_t id,
const char *interface,
uint32_t version)
{
nsRetrievalContextWayland *context =
static_cast<nsRetrievalContextWayland*>(data);
if (strcmp (interface, "wl_data_device_manager") == 0) {
context->InitDataDeviceManager(registry, id, version);
} else if (strcmp(interface, "wl_seat") == 0) {
context->InitSeat(registry, id, version, data);
} else if (strcmp (interface, "gtk_primary_selection_device_manager") == 0) {
context->InitPrimarySelectionDataDeviceManager(registry, id);
}
}
static void
gdk_registry_handle_global_remove(void *data,
struct wl_registry *registry,
uint32_t id)
{
}
static const struct wl_registry_listener clipboard_registry_listener = {
gdk_registry_handle_global,
gdk_registry_handle_global_remove
};
nsRetrievalContextWayland::nsRetrievalContextWayland(void)
: mInitialized(false)
, mSeat(nullptr)
, mDataDeviceManager(nullptr)
, mPrimarySelectionDataDeviceManager(nullptr)
, mDisplay(WaylandDisplayGet())
, mActiveOffers(g_hash_table_new(NULL, NULL))
, mClipboardOffer(nullptr)
, mPrimaryOffer(nullptr)
@ -778,38 +719,18 @@ nsRetrievalContextWayland::nsRetrievalContextWayland(void)
, mClipboardData(nullptr)
, mClipboardDataLength(0)
{
// Available as of GTK 3.8+
static auto sGdkWaylandDisplayGetWlDisplay =
(wl_display *(*)(GdkDisplay *))
dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
mDisplay = sGdkWaylandDisplayGetWlDisplay(gdk_display_get_default());
wl_registry_add_listener(wl_display_get_registry(mDisplay),
&clipboard_registry_listener, this);
// Call wl_display_roundtrip() twice to make sure all
// callbacks are processed.
wl_display_roundtrip(mDisplay);
wl_display_roundtrip(mDisplay);
// mSeat/mDataDeviceManager should be set now by
// gdk_registry_handle_global() as a response to
// wl_registry_add_listener() call.
if (!mDataDeviceManager || !mSeat)
return;
wl_data_device *dataDevice =
wl_data_device_manager_get_data_device(mDataDeviceManager, mSeat);
wl_data_device_manager_get_data_device(mDisplay->GetDataDeviceManager(),
mDisplay->GetSeat());
wl_data_device_add_listener(dataDevice, &data_device_listener, this);
// We have to call wl_display_roundtrip() twice otherwise data_offer_listener
// may not be processed because it's called from data_device_data_offer
// callback.
wl_display_roundtrip(mDisplay);
wl_display_roundtrip(mDisplay);
if (mPrimarySelectionDataDeviceManager) {
gtk_primary_selection_device_manager* manager =
mDisplay->GetPrimarySelectionDeviceManager();
if (manager) {
gtk_primary_selection_device *primaryDataDevice =
gtk_primary_selection_device_manager_get_device(mPrimarySelectionDataDeviceManager,
mSeat);
gtk_primary_selection_device_manager_get_device(manager,
mDisplay->GetSeat());
gtk_primary_selection_device_add_listener(primaryDataDevice,
&primary_selection_device_listener, this);
}
@ -833,6 +754,7 @@ nsRetrievalContextWayland::~nsRetrievalContextWayland(void)
{
g_hash_table_foreach_remove(mActiveOffers, offer_hash_remove, nullptr);
g_hash_table_destroy(mActiveOffers);
WaylandDisplayRelease(mDisplay);
}
GdkAtom*
@ -925,7 +847,7 @@ nsRetrievalContextWayland::GetClipboardData(const char* aMimeType,
mClipboardData = nullptr;
mClipboardDataLength = 0;
} else {
mClipboardData = dataOffer->GetData(mDisplay,
mClipboardData = dataOffer->GetData(mDisplay->GetDisplay(),
aMimeType, &mClipboardDataLength);
}
}

View File

@ -130,17 +130,11 @@ public:
void TransferFastTrackClipboard(int aClipboardRequestNumber,
GtkSelectionData *aSelectionData);
void InitDataDeviceManager(wl_registry *registry, uint32_t id, uint32_t version);
void InitPrimarySelectionDataDeviceManager(wl_registry *registry, uint32_t id);
void InitSeat(wl_registry *registry, uint32_t id, uint32_t version, void *data);
virtual ~nsRetrievalContextWayland() override;
private:
bool mInitialized;
wl_display *mDisplay;
wl_seat *mSeat;
wl_data_device_manager *mDataDeviceManager;
gtk_primary_selection_device_manager *mPrimarySelectionDataDeviceManager;
nsWaylandDisplay* mDisplay;
// Data offers provided by Wayland data device
GHashTable* mActiveOffers;

View File

@ -584,68 +584,37 @@ static const struct wl_keyboard_listener keyboard_listener = {
keyboard_handle_modifiers,
};
static void
seat_handle_capabilities(void *data, struct wl_seat *seat,
unsigned int caps)
{
static wl_keyboard *keyboard = nullptr;
if (caps & WL_SEAT_CAPABILITY_KEYBOARD) {
keyboard = wl_seat_get_keyboard(seat);
wl_keyboard_add_listener(keyboard, &keyboard_listener, nullptr);
} else if (keyboard && !(caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
wl_keyboard_destroy(keyboard);
keyboard = nullptr;
}
}
static const struct wl_seat_listener seat_listener = {
seat_handle_capabilities,
};
static void
gdk_registry_handle_global(void *data,
struct wl_registry *registry,
uint32_t id,
const char *interface,
uint32_t version)
{
if (strcmp(interface, "wl_seat") == 0) {
wl_seat *seat =
(wl_seat*)wl_registry_bind(registry, id, &wl_seat_interface, 1);
wl_seat_add_listener(seat, &seat_listener, data);
}
}
static void
gdk_registry_handle_global_remove(void *data,
struct wl_registry *registry,
uint32_t id)
{
}
static const struct wl_registry_listener keyboard_registry_listener = {
gdk_registry_handle_global,
gdk_registry_handle_global_remove
};
void
KeymapWrapper::InitBySystemSettingsWayland()
{
// Available as of GTK 3.8+
static auto sGdkWaylandDisplayGetWlDisplay =
(wl_display *(*)(GdkDisplay *))
dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
GdkDeviceManager* manager =
gdk_display_get_device_manager(gdk_display_get_default());
GList* devices =
gdk_device_manager_list_devices(manager, GDK_DEVICE_TYPE_MASTER);
GdkDevice* device = nullptr;
wl_display *display =
sGdkWaylandDisplayGetWlDisplay(gdk_display_get_default());
wl_registry_add_listener(wl_display_get_registry(display),
&keyboard_registry_listener, this);
GList* list = devices;
while (devices) {
device = static_cast<GdkDevice*>(devices->data);
if (gdk_device_get_source(device) == GDK_SOURCE_KEYBOARD) {
break;
}
devices = devices->next;
}
// Call wl_display_roundtrip() twice to make sure all
// callbacks are processed.
wl_display_roundtrip(display);
wl_display_roundtrip(display);
if (list) {
g_list_free(list);
}
if (device) {
// Present in Gtk+ 3.10
static auto sGdkWaylandDeviceGetWlKeyboard =
(struct wl_keyboard * (*)(GdkDevice *device))
dlsym(RTLD_DEFAULT, "gdk_wayland_device_get_wl_keyboard");
wl_keyboard_add_listener(sGdkWaylandDeviceGetWlKeyboard(device),
&keyboard_listener, nullptr);
}
}
#endif

View File

@ -8,6 +8,7 @@
#ifndef __nsLookAndFeel
#define __nsLookAndFeel
#include "X11UndefineNone.h"
#include "nsXPLookAndFeel.h"
#include "nsCOMPtr.h"
#include "gfxFont.h"

View File

@ -0,0 +1,267 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim:expandtab:shiftwidth=4:tabstop=4:
*/
/* 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 "base/message_loop.h" // for MessageLoop
#include "base/task.h" // for NewRunnableMethod, etc
#include "mozilla/StaticMutex.h"
namespace mozilla {
namespace widget {
#define MAX_DISPLAY_CONNECTIONS 2
static nsWaylandDisplay* gWaylandDisplays[MAX_DISPLAY_CONNECTIONS];
static StaticMutex gWaylandDisplaysMutex;
// Each thread which is using wayland connection (wl_display) has to operate
// its own wl_event_queue. Main Firefox thread wl_event_queue is handled
// by Gtk main loop, other threads/wl_event_queue has to be handled by us.
//
// nsWaylandDisplay is our interface to wayland compositor. It provides wayland
// global objects as we need (wl_display, wl_shm) and operates wl_event_queue on
// compositor (not the main) thread.
static void WaylandDisplayLoop(wl_display *aDisplay);
// Get WaylandDisplay for given wl_display and actual calling thread.
static nsWaylandDisplay*
WaylandDisplayGetLocked(wl_display *aDisplay, const StaticMutexAutoLock&)
{
for (auto& display: gWaylandDisplays) {
if (display && display->Matches(aDisplay)) {
NS_ADDREF(display);
return display;
}
}
for (auto& display: gWaylandDisplays) {
if (display == nullptr) {
display = new nsWaylandDisplay(aDisplay);
NS_ADDREF(display);
return display;
}
}
MOZ_CRASH("There's too many wayland display conections!");
return nullptr;
}
nsWaylandDisplay*
WaylandDisplayGet(GdkDisplay* aGdkDisplay)
{
if (!aGdkDisplay) {
aGdkDisplay = gdk_display_get_default();
}
// Available as of GTK 3.8+
static auto sGdkWaylandDisplayGetWlDisplay =
(wl_display *(*)(GdkDisplay *))
dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
wl_display *display = sGdkWaylandDisplayGetWlDisplay(aGdkDisplay);
StaticMutexAutoLock lock(gWaylandDisplaysMutex);
return WaylandDisplayGetLocked(display, lock);
}
static bool
WaylandDisplayReleaseLocked(nsWaylandDisplay* aDisplay,
const StaticMutexAutoLock&)
{
for (auto& display: gWaylandDisplays) {
if (display == aDisplay) {
int rc = display->Release();
if (rc == 0) {
display = nullptr;
}
return true;
}
}
MOZ_ASSERT(false, "Missing nsWaylandDisplay for this thread!");
return false;
}
void
WaylandDisplayRelease(nsWaylandDisplay* aDisplay)
{
StaticMutexAutoLock lock(gWaylandDisplaysMutex);
WaylandDisplayReleaseLocked(aDisplay, lock);
}
static void
WaylandDisplayLoopLocked(wl_display* aDisplay,
const StaticMutexAutoLock&)
{
for (auto& display: gWaylandDisplays) {
if (display && display->Matches(aDisplay)) {
if (display->DisplayLoop()) {
MessageLoop::current()->PostDelayedTask(
NewRunnableFunction("WaylandDisplayLoop",
&WaylandDisplayLoop,
aDisplay),
EVENT_LOOP_DELAY);
}
break;
}
}
}
static void
WaylandDisplayLoop(wl_display* aDisplay)
{
MOZ_ASSERT(!NS_IsMainThread());
StaticMutexAutoLock lock(gWaylandDisplaysMutex);
WaylandDisplayLoopLocked(aDisplay, lock);
}
void
nsWaylandDisplay::SetShm(wl_shm* aShm)
{
mShm = aShm;
}
void
nsWaylandDisplay::SetSubcompositor(wl_subcompositor* aSubcompositor)
{
mSubcompositor = aSubcompositor;
}
void
nsWaylandDisplay::SetDataDeviceManager(wl_data_device_manager* aDataDeviceManager)
{
mDataDeviceManager = aDataDeviceManager;
}
void
nsWaylandDisplay::SetSeat(wl_seat* aSeat)
{
mSeat = aSeat;
}
void
nsWaylandDisplay::SetPrimarySelectionDeviceManager(
gtk_primary_selection_device_manager* aPrimarySelectionDeviceManager)
{
mPrimarySelectionDeviceManager = aPrimarySelectionDeviceManager;
}
static void
global_registry_handler(void *data, wl_registry *registry, uint32_t id,
const char *interface, uint32_t version)
{
auto display = reinterpret_cast<nsWaylandDisplay *>(data);
if (strcmp(interface, "wl_shm") == 0) {
auto shm = static_cast<wl_shm*>(
wl_registry_bind(registry, id, &wl_shm_interface, 1));
wl_proxy_set_queue((struct wl_proxy *)shm,
display->GetEventQueue());
display->SetShm(shm);
} else if (strcmp(interface, "wl_data_device_manager") == 0) {
int data_device_manager_version = MIN(version, 3);
auto data_device_manager =
static_cast<wl_data_device_manager *>(wl_registry_bind(registry, id,
&wl_data_device_manager_interface,
data_device_manager_version));
wl_proxy_set_queue((struct wl_proxy *)data_device_manager,
display->GetEventQueue());
display->SetDataDeviceManager(data_device_manager);
} else if (strcmp(interface, "wl_seat") == 0) {
auto seat =
static_cast<wl_seat*>(wl_registry_bind(registry, id,
&wl_seat_interface, 1));
wl_proxy_set_queue((struct wl_proxy *)seat,
display->GetEventQueue());
display->SetSeat(seat);
} else if (strcmp(interface, "gtk_primary_selection_device_manager") == 0) {
auto primary_selection_device_manager =
static_cast<gtk_primary_selection_device_manager *>(
wl_registry_bind(registry, id,
&gtk_primary_selection_device_manager_interface, 1));
wl_proxy_set_queue((struct wl_proxy *)primary_selection_device_manager,
display->GetEventQueue());
display->SetPrimarySelectionDeviceManager(primary_selection_device_manager);
} else if(strcmp(interface, "wl_subcompositor") == 0) {
auto subcompositor =
static_cast<wl_subcompositor*>(wl_registry_bind(registry,
id,
&wl_subcompositor_interface,
1));
wl_proxy_set_queue((struct wl_proxy *)subcompositor,
display->GetEventQueue());
display->SetSubcompositor(subcompositor);
}
}
static void
global_registry_remover(void *data, wl_registry *registry, uint32_t id)
{
}
static const struct wl_registry_listener registry_listener = {
global_registry_handler,
global_registry_remover
};
bool
nsWaylandDisplay::DisplayLoop()
{
wl_display_dispatch_queue_pending(mDisplay, mEventQueue);
return true;
}
bool
nsWaylandDisplay::Matches(wl_display *aDisplay)
{
return mThreadId == PR_GetCurrentThread() && aDisplay == mDisplay;
}
NS_IMPL_ISUPPORTS(nsWaylandDisplay, nsISupports);
nsWaylandDisplay::nsWaylandDisplay(wl_display *aDisplay)
: mThreadId(PR_GetCurrentThread())
, mDisplay(aDisplay)
, mEventQueue(nullptr)
, mDataDeviceManager(nullptr)
, mSubcompositor(nullptr)
, mSeat(nullptr)
, mShm(nullptr)
, mPrimarySelectionDeviceManager(nullptr)
{
wl_registry* registry = wl_display_get_registry(mDisplay);
wl_registry_add_listener(registry, &registry_listener, this);
if (NS_IsMainThread()) {
// Use default event queue in main thread operated by Gtk+.
mEventQueue = nullptr;
wl_display_roundtrip(mDisplay);
wl_display_roundtrip(mDisplay);
} else {
mEventQueue = wl_display_create_queue(mDisplay);
MessageLoop::current()->PostTask(NewRunnableFunction(
"WaylandDisplayLoop", &WaylandDisplayLoop, mDisplay));
wl_proxy_set_queue((struct wl_proxy *)registry, mEventQueue);
wl_display_roundtrip_queue(mDisplay, mEventQueue);
wl_display_roundtrip_queue(mDisplay, mEventQueue);
}
}
nsWaylandDisplay::~nsWaylandDisplay()
{
MOZ_ASSERT(mThreadId == PR_GetCurrentThread());
// Owned by Gtk+, we don't need to release
mDisplay = nullptr;
if (mEventQueue) {
wl_event_queue_destroy(mEventQueue);
mEventQueue = nullptr;
}
}
} // namespace widget
} // namespace mozilla

View File

@ -0,0 +1,68 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim:expandtab:shiftwidth=4:tabstop=4:
*/
/* 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/. */
#ifndef __MOZ_WAYLAND_REGISTRY_H__
#define __MOZ_WAYLAND_REGISTRY_H__
#include "mozwayland/mozwayland.h"
#include "wayland/gtk-primary-selection-client-protocol.h"
namespace mozilla {
namespace widget {
// TODO: Bug 1467125 - We need to integrate wl_display_dispatch_queue_pending() with
// compositor event loop.
#define EVENT_LOOP_DELAY (1000/240)
// Our general connection to Wayland display server,
// holds our display connection and runs event loop.
class nsWaylandDisplay : public nsISupports {
NS_DECL_THREADSAFE_ISUPPORTS
public:
explicit nsWaylandDisplay(wl_display *aDisplay);
bool DisplayLoop();
bool Matches(wl_display *aDisplay);
wl_display* GetDisplay() { return mDisplay; };
wl_event_queue* GetEventQueue() { return mEventQueue; };
wl_subcompositor* GetSubcompositor(void) { return mSubcompositor; };
wl_data_device_manager* GetDataDeviceManager(void) { return mDataDeviceManager; };
wl_seat* GetSeat(void) { return mSeat; };
wl_shm* GetShm(void) { return mShm; };
gtk_primary_selection_device_manager*
GetPrimarySelectionDeviceManager(void) { return mPrimarySelectionDeviceManager; };
public:
void SetShm(wl_shm* aShm);
void SetSubcompositor(wl_subcompositor* aSubcompositor);
void SetDataDeviceManager(wl_data_device_manager* aDataDeviceManager);
void SetSeat(wl_seat* aSeat);
void SetPrimarySelectionDeviceManager(
gtk_primary_selection_device_manager* aPrimarySelectionDeviceManager);
private:
virtual ~nsWaylandDisplay();
PRThread* mThreadId;
wl_display* mDisplay;
wl_event_queue* mEventQueue;
wl_data_device_manager* mDataDeviceManager;
wl_subcompositor* mSubcompositor;
wl_seat* mSeat;
wl_shm* mShm;
gtk_primary_selection_device_manager* mPrimarySelectionDeviceManager;
};
nsWaylandDisplay* WaylandDisplayGet(GdkDisplay* aGdkDisplay = nullptr);
void WaylandDisplayRelease(nsWaylandDisplay* aDisplay);
} // namespace widget
} // namespace mozilla
#endif // __MOZ_WAYLAND_REGISTRY_H__

View File

@ -7303,19 +7303,6 @@ void nsWindow::GetCompositorWidgetInitData(mozilla::widget::CompositorWidgetInit
}
#ifdef MOZ_WAYLAND
wl_display*
nsWindow::GetWaylandDisplay()
{
// Available as of GTK 3.8+
static auto sGdkWaylandDisplayGetWlDisplay =
(wl_display *(*)(GdkDisplay *))
dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
GdkDisplay* gdkDisplay = gdk_display_get_default();
return mIsX11Display ? nullptr :
sGdkWaylandDisplayGetWlDisplay(gdkDisplay);
}
wl_surface*
nsWindow::GetWaylandSurface()
{