mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-29 01:02:44 +08:00
[fix] restore clipboard sync after focus returns, refs #121
This commit is contained in:
@@ -4382,15 +4382,20 @@ void GuiApplication::SelectStreamTab(int index) {
|
|||||||
(*ui_->stream)->set_has_frame(false);
|
(*ui_->stream)->set_has_frame(false);
|
||||||
}
|
}
|
||||||
std::shared_ptr<RemoteSession> selected_session;
|
std::shared_ptr<RemoteSession> selected_session;
|
||||||
|
bool clipboard_resumed = false;
|
||||||
{
|
{
|
||||||
std::lock_guard delivery_lock(audio_delivery_mutex_);
|
std::lock_guard delivery_lock(audio_delivery_mutex_);
|
||||||
std::shared_lock lock(remote_sessions_mutex_);
|
std::shared_lock lock(remote_sessions_mutex_);
|
||||||
for (auto& [id, props] : remote_sessions_) {
|
for (auto& [id, props] : remote_sessions_) {
|
||||||
if (props) {
|
if (props) {
|
||||||
props->tab_selected_ = id == focused_remote_id_;
|
props->tab_selected_ = id == focused_remote_id_;
|
||||||
props->clipboard_allowed_ = props->tab_selected_ &&
|
const bool clipboard_allowed = props->tab_selected_ &&
|
||||||
props->control_mouse_ &&
|
props->control_mouse_ &&
|
||||||
focus_on_stream_window_;
|
focus_on_stream_window_;
|
||||||
|
if (!props->clipboard_allowed_.exchange(clipboard_allowed) &&
|
||||||
|
clipboard_allowed) {
|
||||||
|
clipboard_resumed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto selected = remote_sessions_.find(selected_remote_id);
|
const auto selected = remote_sessions_.find(selected_remote_id);
|
||||||
@@ -4402,6 +4407,11 @@ void GuiApplication::SelectStreamTab(int index) {
|
|||||||
selected_session->connection_status_.load() ==
|
selected_session->connection_status_.load() ==
|
||||||
ConnectionStatus::Connected;
|
ConnectionStatus::Connected;
|
||||||
}
|
}
|
||||||
|
if (clipboard_resumed) {
|
||||||
|
// Flush a copy made in another local app before the next paste shortcut,
|
||||||
|
// instead of waiting for the periodic clipboard poll.
|
||||||
|
clipboard_.HandleLocalUpdate();
|
||||||
|
}
|
||||||
SyncAudioPlayback();
|
SyncAudioPlayback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ uint32_t ClipboardController::event_type() const { return event_type_; }
|
|||||||
|
|
||||||
void ClipboardController::Initialize() {
|
void ClipboardController::Initialize() {
|
||||||
last_text_.clear();
|
last_text_.clear();
|
||||||
|
deferred_local_session_.reset();
|
||||||
|
|
||||||
char *clipboard_text = SDL_GetClipboardText();
|
char *clipboard_text = SDL_GetClipboardText();
|
||||||
if (clipboard_text) {
|
if (clipboard_text) {
|
||||||
@@ -42,6 +43,7 @@ void ClipboardController::Initialize() {
|
|||||||
|
|
||||||
void ClipboardController::Shutdown() {
|
void ClipboardController::Shutdown() {
|
||||||
events_enabled_.store(false, std::memory_order_release);
|
events_enabled_.store(false, std::memory_order_release);
|
||||||
|
deferred_local_session_.reset();
|
||||||
std::lock_guard<std::mutex> lock(pending_mutex_);
|
std::lock_guard<std::mutex> lock(pending_mutex_);
|
||||||
pending_remote_text_.reset();
|
pending_remote_text_.reset();
|
||||||
}
|
}
|
||||||
@@ -126,6 +128,7 @@ void ClipboardController::ApplyPendingRemoteText() {
|
|||||||
// SDL will normally emit SDL_EVENT_CLIPBOARD_UPDATE for this write. Update
|
// SDL will normally emit SDL_EVENT_CLIPBOARD_UPDATE for this write. Update
|
||||||
// the baseline first so that event cannot echo the text back to the sender.
|
// the baseline first so that event cannot echo the text back to the sender.
|
||||||
last_text_ = std::move(*pending_text);
|
last_text_ = std::move(*pending_text);
|
||||||
|
deferred_local_session_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClipboardController::HandleLocalUpdate() {
|
void ClipboardController::HandleLocalUpdate() {
|
||||||
@@ -134,6 +137,7 @@ void ClipboardController::HandleLocalUpdate() {
|
|||||||
}
|
}
|
||||||
if (!SDL_HasClipboardText()) {
|
if (!SDL_HasClipboardText()) {
|
||||||
last_text_.clear();
|
last_text_.clear();
|
||||||
|
deferred_local_session_.reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,12 +150,14 @@ void ClipboardController::HandleLocalUpdate() {
|
|||||||
std::string text(clipboard_text);
|
std::string text(clipboard_text);
|
||||||
SDL_free(clipboard_text);
|
SDL_free(clipboard_text);
|
||||||
if (text == last_text_) {
|
if (text == last_text_) {
|
||||||
|
SendDeferredLocalText();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record the value before sending. Duplicate SDL notifications and a
|
// Record the value before sending. Duplicate SDL notifications and a
|
||||||
// remote write of the same value must not create a clipboard feedback loop.
|
// remote write of the same value must not create a clipboard feedback loop.
|
||||||
last_text_ = text;
|
last_text_ = text;
|
||||||
|
deferred_local_session_.reset();
|
||||||
if (text.empty()) {
|
if (text.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -163,11 +169,50 @@ void ClipboardController::HandleLocalUpdate() {
|
|||||||
SendToPeers(text);
|
SendToPeers(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClipboardController::SendDeferredLocalText() {
|
||||||
|
const auto session = deferred_local_session_.lock();
|
||||||
|
if (!session) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_lock lock(owner_.remote_sessions_mutex_);
|
||||||
|
const auto current = owner_.remote_sessions_.find(session->remote_id_);
|
||||||
|
if (current == owner_.remote_sessions_.end() || current->second != session ||
|
||||||
|
session->closing_ || !session->peer_ || !session->connection_established_ ||
|
||||||
|
!session->tab_opened_ || !session->tab_selected_ ||
|
||||||
|
!session->control_mouse_) {
|
||||||
|
deferred_local_session_.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!session->clipboard_allowed_.load()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int ret = SendReliableDataFrame(
|
||||||
|
session->peer_, last_text_.data(), last_text_.size(),
|
||||||
|
session->clipboard_label_.c_str());
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_WARN("Failed to send deferred clipboard data to peer [{}], ret={}",
|
||||||
|
session->remote_id_, ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
deferred_local_session_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
int ClipboardController::SendToPeers(const std::string &text) {
|
int ClipboardController::SendToPeers(const std::string &text) {
|
||||||
std::shared_lock lock(owner_.remote_sessions_mutex_);
|
std::shared_lock lock(owner_.remote_sessions_mutex_);
|
||||||
for (const auto &[remote_id, props] : owner_.remote_sessions_) {
|
for (const auto &[remote_id, props] : owner_.remote_sessions_) {
|
||||||
if (!props || !props->peer_ || !props->connection_established_ ||
|
if (!props || props->closing_ || !props->peer_ ||
|
||||||
!props->clipboard_allowed_.load()) {
|
!props->connection_established_) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!props->clipboard_allowed_.load()) {
|
||||||
|
// Copying in another local app temporarily releases keyboard control.
|
||||||
|
// Keep this copy for the same selected stream, without sharing it with
|
||||||
|
// background tabs or DeskHub previews.
|
||||||
|
if (props->tab_opened_ && props->tab_selected_ && props->control_mouse_) {
|
||||||
|
deferred_local_session_ = props;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
int SendToPeers(const std::string &text);
|
int SendToPeers(const std::string &text);
|
||||||
|
void SendDeferredLocalText();
|
||||||
|
|
||||||
GuiRuntime &owner_;
|
GuiRuntime &owner_;
|
||||||
uint32_t event_type_ = 0;
|
uint32_t event_type_ = 0;
|
||||||
@@ -51,8 +52,11 @@ private:
|
|||||||
std::weak_ptr<gui_detail::RemoteSession> pending_session_;
|
std::weak_ptr<gui_detail::RemoteSession> pending_session_;
|
||||||
uint64_t pending_generation_ = 0;
|
uint64_t pending_generation_ = 0;
|
||||||
std::string last_text_;
|
std::string last_text_;
|
||||||
|
// UI thread only. Retain the destination of a local copy while its stream
|
||||||
|
// window is unfocused; last_text_ holds the latest value to send on return.
|
||||||
|
std::weak_ptr<gui_detail::RemoteSession> deferred_local_session_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace crossdesk
|
} // namespace crossdesk
|
||||||
|
|
||||||
#endif // _CLIPBOARD_CONTROLLER_H_
|
#endif // _CLIPBOARD_CONTROLLER_H_
|
||||||
|
|||||||
Reference in New Issue
Block a user