Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit 71f8bab

Browse files
committed
Bug 1667674 - [Wayland] Support public primary-selection unstable protocol. r=stransky
This is required to support pasting the primary selection into Firefox on compositors only supporting the public protocol, such as KWin. Getting the selection *from* Firefox is done via GTK and will be supported from GTK 3.24.23 on. The public protocol, while practically identical, will replace the gtk-private one eventually. However, support for the private one will still be needed for a while. Note: this also updates the auto-generated gtk-primary-selection files. Differential Revision: https://phabricator.services.mozilla.com/D91594
1 parent 4a8c5a1 commit 71f8bab

10 files changed

Lines changed: 880 additions & 57 deletions

.clang-format-ignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ media/mp4parse-rust/mp4parse.h
4242
security/manager/ssl/StaticHPKPins.h
4343
widget/gtk/wayland/gtk-primary-selection-client-protocol.h
4444
widget/gtk/wayland/gtk-primary-selection-protocol.c
45+
widget/gtk/wayland/primary-selection-unstable-v1-client-protocol.h
46+
widget/gtk/wayland/primary-selection-unstable-v1-protocol.c
4547

4648
# Ignored because these files are used to generate a windows.h STL wrapper,
4749
# and reformatting them can break generating that wrapper.

widget/gtk/nsClipboardWayland.cpp

Lines changed: 111 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -314,15 +314,27 @@ WaylandDataOffer::~WaylandDataOffer(void) {
314314
}
315315

316316
bool PrimaryDataOffer::RequestDataTransfer(const char* aMimeType, int fd) {
317-
if (mPrimaryDataOffer) {
318-
gtk_primary_selection_offer_receive(mPrimaryDataOffer, aMimeType, fd);
317+
if (mPrimaryDataOfferGtk) {
318+
gtk_primary_selection_offer_receive(mPrimaryDataOfferGtk, aMimeType, fd);
319+
return true;
320+
}
321+
if (mPrimaryDataOfferZwpV1) {
322+
zwp_primary_selection_offer_v1_receive(mPrimaryDataOfferZwpV1, aMimeType,
323+
fd);
319324
return true;
320325
}
321326
return false;
322327
}
323328

324329
static void primary_data_offer(
325-
void* data, gtk_primary_selection_offer* gtk_primary_selection_offer,
330+
void* data, gtk_primary_selection_offer* primary_selection_offer,
331+
const char* mime_type) {
332+
auto* offer = static_cast<DataOffer*>(data);
333+
offer->AddMIMEType(mime_type);
334+
}
335+
336+
static void primary_data_offer(
337+
void* data, zwp_primary_selection_offer_v1* primary_selection_offer,
326338
const char* mime_type) {
327339
auto* offer = static_cast<DataOffer*>(data);
328340
offer->AddMIMEType(mime_type);
@@ -334,18 +346,31 @@ static void primary_data_offer(
334346
* gtk_primary_selection_offer.
335347
*/
336348
static const struct gtk_primary_selection_offer_listener
337-
primary_selection_offer_listener = {primary_data_offer};
349+
primary_selection_offer_listener_gtk = {primary_data_offer};
350+
351+
static const struct zwp_primary_selection_offer_v1_listener
352+
primary_selection_offer_listener_zwp_v1 = {primary_data_offer};
338353

339354
PrimaryDataOffer::PrimaryDataOffer(
340355
gtk_primary_selection_offer* aPrimaryDataOffer)
341-
: mPrimaryDataOffer(aPrimaryDataOffer) {
356+
: mPrimaryDataOfferGtk(aPrimaryDataOffer), mPrimaryDataOfferZwpV1(nullptr) {
342357
gtk_primary_selection_offer_add_listener(
343-
aPrimaryDataOffer, &primary_selection_offer_listener, this);
358+
aPrimaryDataOffer, &primary_selection_offer_listener_gtk, this);
359+
}
360+
361+
PrimaryDataOffer::PrimaryDataOffer(
362+
zwp_primary_selection_offer_v1* aPrimaryDataOffer)
363+
: mPrimaryDataOfferGtk(nullptr), mPrimaryDataOfferZwpV1(aPrimaryDataOffer) {
364+
zwp_primary_selection_offer_v1_add_listener(
365+
aPrimaryDataOffer, &primary_selection_offer_listener_zwp_v1, this);
344366
}
345367

346368
PrimaryDataOffer::~PrimaryDataOffer(void) {
347-
if (mPrimaryDataOffer) {
348-
gtk_primary_selection_offer_destroy(mPrimaryDataOffer);
369+
if (mPrimaryDataOfferGtk) {
370+
gtk_primary_selection_offer_destroy(mPrimaryDataOfferGtk);
371+
}
372+
if (mPrimaryDataOfferZwpV1) {
373+
zwp_primary_selection_offer_v1_destroy(mPrimaryDataOfferZwpV1);
349374
}
350375
}
351376

@@ -444,6 +469,20 @@ void nsRetrievalContextWayland::RegisterNewDataOffer(
444469
}
445470
}
446471

472+
void nsRetrievalContextWayland::RegisterNewDataOffer(
473+
zwp_primary_selection_offer_v1* aPrimaryDataOffer) {
474+
DataOffer* dataOffer = static_cast<DataOffer*>(
475+
g_hash_table_lookup(mActiveOffers, aPrimaryDataOffer));
476+
MOZ_ASSERT(
477+
dataOffer == nullptr,
478+
"Registered PrimaryDataOffer already exists. Wayland protocol error?");
479+
480+
if (!dataOffer) {
481+
dataOffer = new PrimaryDataOffer(aPrimaryDataOffer);
482+
g_hash_table_insert(mActiveOffers, aPrimaryDataOffer, dataOffer);
483+
}
484+
}
485+
447486
void nsRetrievalContextWayland::SetClipboardDataOffer(
448487
wl_data_offer* aWaylandDataOffer) {
449488
// Delete existing clipboard data offer
@@ -480,6 +519,24 @@ void nsRetrievalContextWayland::SetPrimaryDataOffer(
480519
}
481520
}
482521

522+
void nsRetrievalContextWayland::SetPrimaryDataOffer(
523+
zwp_primary_selection_offer_v1* aPrimaryDataOffer) {
524+
// Release any primary offer we have.
525+
mPrimaryOffer = nullptr;
526+
527+
// aPrimaryDataOffer can be null which means we lost
528+
// the mouse selection.
529+
if (aPrimaryDataOffer) {
530+
DataOffer* dataOffer = static_cast<DataOffer*>(
531+
g_hash_table_lookup(mActiveOffers, aPrimaryDataOffer));
532+
NS_ASSERTION(dataOffer, "We're missing primary data offer!");
533+
if (dataOffer) {
534+
g_hash_table_remove(mActiveOffers, aPrimaryDataOffer);
535+
mPrimaryOffer = WrapUnique(dataOffer);
536+
}
537+
}
538+
}
539+
483540
void nsRetrievalContextWayland::AddDragAndDropDataOffer(
484541
wl_data_offer* aDropDataOffer) {
485542
// Remove any existing D&D contexts.
@@ -615,25 +672,44 @@ static const struct wl_data_device_listener data_device_listener = {
615672
data_device_data_offer, data_device_enter, data_device_leave,
616673
data_device_motion, data_device_drop, data_device_selection};
617674

675+
static void primary_selection_data_offer(
676+
void* data, struct gtk_primary_selection_device* primary_selection_device,
677+
struct gtk_primary_selection_offer* primary_offer) {
678+
LOGCLIP(("primary_selection_data_offer() callback\n"));
679+
// create and add listener
680+
nsRetrievalContextWayland* context =
681+
static_cast<nsRetrievalContextWayland*>(data);
682+
context->RegisterNewDataOffer(primary_offer);
683+
}
684+
618685
static void primary_selection_data_offer(
619686
void* data,
620-
struct gtk_primary_selection_device* gtk_primary_selection_device,
621-
struct gtk_primary_selection_offer* gtk_primary_offer) {
687+
struct zwp_primary_selection_device_v1* primary_selection_device,
688+
struct zwp_primary_selection_offer_v1* primary_offer) {
622689
LOGCLIP(("primary_selection_data_offer() callback\n"));
623690
// create and add listener
624691
nsRetrievalContextWayland* context =
625692
static_cast<nsRetrievalContextWayland*>(data);
626-
context->RegisterNewDataOffer(gtk_primary_offer);
693+
context->RegisterNewDataOffer(primary_offer);
694+
}
695+
696+
static void primary_selection_selection(
697+
void* data, struct gtk_primary_selection_device* primary_selection_device,
698+
struct gtk_primary_selection_offer* primary_offer) {
699+
LOGCLIP(("primary_selection_selection() callback\n"));
700+
nsRetrievalContextWayland* context =
701+
static_cast<nsRetrievalContextWayland*>(data);
702+
context->SetPrimaryDataOffer(primary_offer);
627703
}
628704

629705
static void primary_selection_selection(
630706
void* data,
631-
struct gtk_primary_selection_device* gtk_primary_selection_device,
632-
struct gtk_primary_selection_offer* gtk_primary_offer) {
707+
struct zwp_primary_selection_device_v1* primary_selection_device,
708+
struct zwp_primary_selection_offer_v1* primary_offer) {
633709
LOGCLIP(("primary_selection_selection() callback\n"));
634710
nsRetrievalContextWayland* context =
635711
static_cast<nsRetrievalContextWayland*>(data);
636-
context->SetPrimaryDataOffer(gtk_primary_offer);
712+
context->SetPrimaryDataOffer(primary_offer);
637713
}
638714

639715
/* gtk_primary_selection_device callback description:
@@ -650,13 +726,20 @@ static void primary_selection_selection(
650726
* there's no primary selection.
651727
*/
652728
static const struct gtk_primary_selection_device_listener
653-
primary_selection_device_listener = {
729+
primary_selection_device_listener_gtk = {
730+
primary_selection_data_offer,
731+
primary_selection_selection,
732+
};
733+
734+
static const struct zwp_primary_selection_device_v1_listener
735+
primary_selection_device_listener_zwp_v1 = {
654736
primary_selection_data_offer,
655737
primary_selection_selection,
656738
};
657739

658740
bool nsRetrievalContextWayland::HasSelectionSupport(void) {
659-
return mDisplay->GetPrimarySelectionDeviceManager() != nullptr;
741+
return (mDisplay->GetPrimarySelectionDeviceManagerZwpV1() != nullptr ||
742+
mDisplay->GetPrimarySelectionDeviceManagerGtk() != nullptr);
660743
}
661744

662745
nsRetrievalContextWayland::nsRetrievalContextWayland(void)
@@ -673,14 +756,20 @@ nsRetrievalContextWayland::nsRetrievalContextWayland(void)
673756
mDisplay->GetDataDeviceManager(), mDisplay->GetSeat());
674757
wl_data_device_add_listener(dataDevice, &data_device_listener, this);
675758

676-
gtk_primary_selection_device_manager* manager =
677-
mDisplay->GetPrimarySelectionDeviceManager();
678-
if (manager) {
759+
if (mDisplay->GetPrimarySelectionDeviceManagerZwpV1()) {
760+
zwp_primary_selection_device_v1* primaryDataDevice =
761+
zwp_primary_selection_device_manager_v1_get_device(
762+
mDisplay->GetPrimarySelectionDeviceManagerZwpV1(),
763+
mDisplay->GetSeat());
764+
zwp_primary_selection_device_v1_add_listener(
765+
primaryDataDevice, &primary_selection_device_listener_zwp_v1, this);
766+
} else if (mDisplay->GetPrimarySelectionDeviceManagerGtk()) {
679767
gtk_primary_selection_device* primaryDataDevice =
680-
gtk_primary_selection_device_manager_get_device(manager,
681-
mDisplay->GetSeat());
768+
gtk_primary_selection_device_manager_get_device(
769+
mDisplay->GetPrimarySelectionDeviceManagerGtk(),
770+
mDisplay->GetSeat());
682771
gtk_primary_selection_device_add_listener(
683-
primaryDataDevice, &primary_selection_device_listener, this);
772+
primaryDataDevice, &primary_selection_device_listener_gtk, this);
684773
}
685774

686775
mInitialized = true;

widget/gtk/nsClipboardWayland.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
#include "mozilla/UniquePtr.h"
1616
#include "nsClipboard.h"
1717
#include "nsWaylandDisplay.h"
18-
#include "mozwayland/mozwayland.h"
19-
#include "wayland/gtk-primary-selection-client-protocol.h"
2018

2119
struct FastTrackClipboard;
2220

@@ -69,14 +67,16 @@ class WaylandDataOffer : public DataOffer {
6967
class PrimaryDataOffer : public DataOffer {
7068
public:
7169
explicit PrimaryDataOffer(gtk_primary_selection_offer* aPrimaryDataOffer);
70+
explicit PrimaryDataOffer(zwp_primary_selection_offer_v1* aPrimaryDataOffer);
7271
void SetAvailableDragActions(uint32_t aWaylandActions){};
7372

7473
virtual ~PrimaryDataOffer();
7574

7675
private:
7776
bool RequestDataTransfer(const char* aMimeType, int fd) override;
7877

79-
gtk_primary_selection_offer* mPrimaryDataOffer;
78+
gtk_primary_selection_offer* mPrimaryDataOfferGtk;
79+
zwp_primary_selection_offer_v1* mPrimaryDataOfferZwpV1;
8080
};
8181

8282
class nsWaylandDragContext : public nsISupports {
@@ -124,9 +124,11 @@ class nsRetrievalContextWayland : public nsRetrievalContext {
124124

125125
void RegisterNewDataOffer(wl_data_offer* aWaylandDataOffer);
126126
void RegisterNewDataOffer(gtk_primary_selection_offer* aPrimaryDataOffer);
127+
void RegisterNewDataOffer(zwp_primary_selection_offer_v1* aPrimaryDataOffer);
127128

128129
void SetClipboardDataOffer(wl_data_offer* aWaylandDataOffer);
129130
void SetPrimaryDataOffer(gtk_primary_selection_offer* aPrimaryDataOffer);
131+
void SetPrimaryDataOffer(zwp_primary_selection_offer_v1* aPrimaryDataOffer);
130132
void AddDragAndDropDataOffer(wl_data_offer* aWaylandDataOffer);
131133
nsWaylandDragContext* GetDragContext();
132134

widget/gtk/nsWaylandDisplay.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,12 @@ void nsWaylandDisplay::SetSeat(wl_seat* aSeat) { mSeat = aSeat; }
127127

128128
void nsWaylandDisplay::SetPrimarySelectionDeviceManager(
129129
gtk_primary_selection_device_manager* aPrimarySelectionDeviceManager) {
130-
mPrimarySelectionDeviceManager = aPrimarySelectionDeviceManager;
130+
mPrimarySelectionDeviceManagerGtk = aPrimarySelectionDeviceManager;
131+
}
132+
133+
void nsWaylandDisplay::SetPrimarySelectionDeviceManager(
134+
zwp_primary_selection_device_manager_v1* aPrimarySelectionDeviceManager) {
135+
mPrimarySelectionDeviceManagerZwpV1 = aPrimarySelectionDeviceManager;
131136
}
132137

133138
void nsWaylandDisplay::SetIdleInhibitManager(
@@ -167,6 +172,15 @@ static void global_registry_handler(void* data, wl_registry* registry,
167172
wl_proxy_set_queue((struct wl_proxy*)primary_selection_device_manager,
168173
display->GetEventQueue());
169174
display->SetPrimarySelectionDeviceManager(primary_selection_device_manager);
175+
} else if (strcmp(interface, "zwp_primary_selection_device_manager_v1") ==
176+
0) {
177+
auto* primary_selection_device_manager =
178+
WaylandRegistryBind<gtk_primary_selection_device_manager>(
179+
registry, id, &zwp_primary_selection_device_manager_v1_interface,
180+
1);
181+
wl_proxy_set_queue((struct wl_proxy*)primary_selection_device_manager,
182+
display->GetEventQueue());
183+
display->SetPrimarySelectionDeviceManager(primary_selection_device_manager);
170184
} else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0) {
171185
auto* idle_inhibit_manager =
172186
WaylandRegistryBind<zwp_idle_inhibit_manager_v1>(
@@ -284,7 +298,8 @@ nsWaylandDisplay::nsWaylandDisplay(wl_display* aDisplay, bool aLighWrapper)
284298
mSeat(nullptr),
285299
mShm(nullptr),
286300
mSyncCallback(nullptr),
287-
mPrimarySelectionDeviceManager(nullptr),
301+
mPrimarySelectionDeviceManagerGtk(nullptr),
302+
mPrimarySelectionDeviceManagerZwpV1(nullptr),
288303
mIdleInhibitManager(nullptr),
289304
mRegistry(nullptr),
290305
mExplicitSync(false) {

widget/gtk/nsWaylandDisplay.h

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88
#ifndef __MOZ_WAYLAND_DISPLAY_H__
99
#define __MOZ_WAYLAND_DISPLAY_H__
1010

11-
#include "mozilla/widget/mozwayland.h"
12-
#include "mozilla/widget/gtk-primary-selection-client-protocol.h"
13-
#include "mozilla/widget/idle-inhibit-unstable-v1-client-protocol.h"
14-
1511
#include "base/message_loop.h" // for MessageLoop
1612
#include "base/task.h" // for NewRunnableMethod, etc
1713
#include "mozilla/StaticMutex.h"
1814

15+
#include "mozilla/widget/mozwayland.h"
1916
#include "mozilla/widget/gbm.h"
17+
#include "mozilla/widget/gtk-primary-selection-client-protocol.h"
18+
#include "mozilla/widget/idle-inhibit-unstable-v1-client-protocol.h"
2019
#include "mozilla/widget/linux-dmabuf-unstable-v1-client-protocol.h"
20+
#include "mozilla/widget/primary-selection-unstable-v1-client-protocol.h"
2121

2222
namespace mozilla {
2323
namespace widget {
@@ -51,8 +51,13 @@ class nsWaylandDisplay {
5151
};
5252
wl_seat* GetSeat(void) { return mSeat; };
5353
wl_shm* GetShm(void) { return mShm; };
54-
gtk_primary_selection_device_manager* GetPrimarySelectionDeviceManager(void) {
55-
return mPrimarySelectionDeviceManager;
54+
gtk_primary_selection_device_manager* GetPrimarySelectionDeviceManagerGtk(
55+
void) {
56+
return mPrimarySelectionDeviceManagerGtk;
57+
};
58+
zwp_primary_selection_device_manager_v1*
59+
GetPrimarySelectionDeviceManagerZwpV1(void) {
60+
return mPrimarySelectionDeviceManagerZwpV1;
5661
};
5762
zwp_idle_inhibit_manager_v1* GetIdleInhibitManager(void) {
5863
return mIdleInhibitManager;
@@ -67,6 +72,8 @@ class nsWaylandDisplay {
6772
void SetSeat(wl_seat* aSeat);
6873
void SetPrimarySelectionDeviceManager(
6974
gtk_primary_selection_device_manager* aPrimarySelectionDeviceManager);
75+
void SetPrimarySelectionDeviceManager(
76+
zwp_primary_selection_device_manager_v1* aPrimarySelectionDeviceManager);
7077
void SetIdleInhibitManager(zwp_idle_inhibit_manager_v1* aIdleInhibitManager);
7178

7279
MessageLoop* GetThreadLoop() { return mThreadLoop; }
@@ -87,7 +94,8 @@ class nsWaylandDisplay {
8794
wl_seat* mSeat;
8895
wl_shm* mShm;
8996
wl_callback* mSyncCallback;
90-
gtk_primary_selection_device_manager* mPrimarySelectionDeviceManager;
97+
gtk_primary_selection_device_manager* mPrimarySelectionDeviceManagerGtk;
98+
zwp_primary_selection_device_manager_v1* mPrimarySelectionDeviceManagerZwpV1;
9199
zwp_idle_inhibit_manager_v1* mIdleInhibitManager;
92100
wl_registry* mRegistry;
93101
bool mExplicitSync;

widget/gtk/wayland/gtk-primary-selection-client-protocol.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Generated by wayland-scanner 1.14.0 */
1+
/* Generated by wayland-scanner 1.18.0 */
22

33
#ifndef GTK_PRIMARY_SELECTION_CLIENT_PROTOCOL_H
44
#define GTK_PRIMARY_SELECTION_CLIENT_PROTOCOL_H

0 commit comments

Comments
 (0)