Skip to content

Commit d45b8d1

Browse files
committed
Defer the data device initialization. (#1441)
Seems there could be certain issue when both wlr / ext are initialized when compositor supports both. defer refreshSeat() to avoid both are initialized.
1 parent 47811e6 commit d45b8d1

File tree

2 files changed

+61
-31
lines changed

2 files changed

+61
-31
lines changed

src/modules/clipboard/waylandclipboard.cpp

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -275,70 +275,93 @@ WaylandClipboard::WaylandClipboard(Clipboard *clipboard, std::string name,
275275
globalConn_ = display_->globalCreated().connect(
276276
[this](const std::string &interface, const std::shared_ptr<void> &ptr) {
277277
if (interface == wayland::ExtDataControlManagerV1::interface) {
278-
if (ptr != ext_manager_) {
279-
deviceMap_.clear();
280-
ext_manager_ =
278+
if (ptr != extManager_) {
279+
extDeviceMap_.clear();
280+
extManager_ =
281281
display_->getGlobal<wayland::ExtDataControlManagerV1>();
282282
}
283-
refreshSeat();
283+
parent_->instance()->eventDispatcher().schedule(
284+
[this]() { refreshSeat(); });
285+
deferRefreshSeat();
284286
} else if (interface ==
285287
wayland::ZwlrDataControlManagerV1::interface) {
286-
if (ptr != wlr_manager_) {
287-
deviceMap_.clear();
288-
wlr_manager_ =
288+
if (ptr != wlrManager_) {
289+
wlrDeviceMap_.clear();
290+
wlrManager_ =
289291
display_
290292
->getGlobal<wayland::ZwlrDataControlManagerV1>();
291293
}
292-
refreshSeat();
294+
deferRefreshSeat();
293295
} else if (interface == wayland::WlSeat::interface) {
294-
refreshSeat();
296+
deferRefreshSeat();
295297
}
296298
});
297299
globalRemoveConn_ = display_->globalRemoved().connect(
298300
[this](const std::string &interface, const std::shared_ptr<void> &ptr) {
299-
if (interface == wayland::ZwlrDataControlManagerV1::interface) {
300-
deviceMap_.clear();
301-
if (wlr_manager_ == ptr) {
302-
wlr_manager_.reset();
301+
if (interface == wayland::ExtDataControlManagerV1::interface) {
302+
extDeviceMap_.clear();
303+
if (extManager_ == ptr) {
304+
extManager_.reset();
305+
}
306+
} else if (interface ==
307+
wayland::ZwlrDataControlManagerV1::interface) {
308+
wlrDeviceMap_.clear();
309+
if (wlrManager_ == ptr) {
310+
wlrManager_.reset();
303311
}
304312
} else if (interface == wayland::WlSeat::interface) {
305-
deviceMap_.erase(static_cast<wayland::WlSeat *>(ptr.get()));
313+
wlrDeviceMap_.erase(static_cast<wayland::WlSeat *>(ptr.get()));
314+
extDeviceMap_.erase(static_cast<wayland::WlSeat *>(ptr.get()));
306315
}
307316
});
308317

309318
if (auto manager =
310319
display_->getGlobal<wayland::ZwlrDataControlManagerV1>()) {
311-
wlr_manager_ = std::move(manager);
320+
wlrManager_ = std::move(manager);
312321
}
313322
refreshSeat();
314323
}
315324

325+
void WaylandClipboard::deferRefreshSeat() {
326+
// The initial global registration update is more likely happen in one
327+
// message loop, so we defer so we can decide to only initialize ext or wlr.
328+
parent_->instance()->eventDispatcher().scheduleWithContext(
329+
watch(), [this]() { refreshSeat(); });
330+
}
331+
316332
void WaylandClipboard::refreshSeat() {
317-
if (!wlr_manager_ && !ext_manager_) {
333+
if (!wlrManager_ && !extManager_) {
318334
return;
319335
}
320336

321337
auto seats = display_->getGlobals<wayland::WlSeat>();
322338
for (const auto &seat : seats) {
323-
if (deviceMap_.contains(seat.get())) {
324-
continue;
325-
}
326-
327-
if (ext_manager_) {
328-
auto *device = ext_manager_->getDataDevice(seat.get());
329-
deviceMap_.emplace(
339+
if (extManager_) {
340+
if (extDeviceMap_.contains(seat.get())) {
341+
continue;
342+
}
343+
auto *device = extManager_->getDataDevice(seat.get());
344+
extDeviceMap_.emplace(
330345
seat.get(),
331346
std::make_unique<DataDevice<wayland::ExtDataControlDeviceV1>>(
332347
this, device));
333348
continue;
334-
} else if (wlr_manager_) {
335-
auto *device = wlr_manager_->getDataDevice(seat.get());
336-
deviceMap_.emplace(
349+
} else if (wlrManager_) {
350+
if (wlrDeviceMap_.contains(seat.get())) {
351+
continue;
352+
}
353+
auto *device = wlrManager_->getDataDevice(seat.get());
354+
wlrDeviceMap_.emplace(
337355
seat.get(),
338356
std::make_unique<DataDevice<wayland::ZwlrDataControlDeviceV1>>(
339357
this, device));
340358
}
341359
}
360+
361+
// If both are available, prefer ext.
362+
if (extManager_ && wlrManager_) {
363+
wlrDeviceMap_.clear();
364+
}
342365
}
343366

344367
void WaylandClipboard::setClipboard(const std::string &str, bool password) {

src/modules/clipboard/waylandclipboard.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ class DataDevice : public DataDeviceInterface {
176176
std::list<ScopedConnection> conns_;
177177
};
178178

179-
class WaylandClipboard {
179+
class WaylandClipboard : public TrackableObject<WaylandClipboard> {
180180

181181
public:
182182
WaylandClipboard(Clipboard *clipboard, std::string name,
@@ -188,16 +188,23 @@ class WaylandClipboard {
188188
auto parent() const { return parent_; }
189189

190190
private:
191+
void deferRefreshSeat();
191192
void refreshSeat();
192193
Clipboard *parent_;
193194
std::string name_;
194195
wayland::Display *display_;
195196
ScopedConnection globalConn_;
196197
ScopedConnection globalRemoveConn_;
197-
std::shared_ptr<wayland::ExtDataControlManagerV1> ext_manager_;
198-
std::shared_ptr<wayland::ZwlrDataControlManagerV1> wlr_manager_;
199-
std::unordered_map<wayland::WlSeat *, std::unique_ptr<DataDeviceInterface>>
200-
deviceMap_;
198+
std::shared_ptr<wayland::ExtDataControlManagerV1> extManager_;
199+
std::shared_ptr<wayland::ZwlrDataControlManagerV1> wlrManager_;
200+
std::unordered_map<
201+
wayland::WlSeat *,
202+
std::unique_ptr<DataDevice<wayland::ExtDataControlDeviceV1>>>
203+
extDeviceMap_;
204+
std::unordered_map<
205+
wayland::WlSeat *,
206+
std::unique_ptr<DataDevice<wayland::ZwlrDataControlDeviceV1>>>
207+
wlrDeviceMap_;
201208
};
202209

203210
} // namespace fcitx

0 commit comments

Comments
 (0)