gtk实现spice剪切板

news/2024/11/28 21:32:31/

 

重要的函数:
void spice_main_channel_clipboard_selection_grab(SpiceMainChannel *channel, guint selection,
guint32 *types, int ntypes);  抓取剪切板
void spice_main_channel_clipboard_selection_release(SpiceMainChannel *channel, guint selection);  剪切板释放
void spice_main_channel_clipboard_selection_notify(SpiceMainChannel *channel, guint selection,guint32 type, const guchar *data, size_t size);   通知剪切板内容
void spice_main_channel_clipboard_selection_request(SpiceMainChannel *channel, guint selection,guint32 type); 请求剪切板
1、host--> guest复制粘贴
1.1、宿主机复制:监听剪切板变化,获取剪切板内容
1.1.1、连接剪切板内容变化的回调函数
void spice_gtk_session_copy_to_guest(SpiceGtkSession *self)
{g_return_if_fail(SPICE_IS_GTK_SESSION(self));g_return_if_fail(read_only(self) == FALSE);SpiceGtkSessionPrivate *s = self->priv;int selection = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;if (s->clip_hasdata[selection] && !s->clip_grabbed[selection]) {gtk_clipboard_request_targets(s->clipboard, clipboard_get_targets,get_weak_ref(self)); //剪贴板收到支持类型的内容之后时,callback将被调用。}
}
1.1.2、剪切板内容处理
static void clipboard_get_targets(GtkClipboard *clipboard,GdkAtom *atoms,gint n_atoms, gpointer user_data)
{SpiceGtkSession *self = free_weak_ref(user_data);SPICE_DEBUG("%s:", __FUNCTION__);if (self == NULL)return;g_return_if_fail(SPICE_IS_GTK_SESSION(self));if (atoms == NULL) {SPICE_DEBUG("Retrieving the clipboard data has failed");return;}SpiceGtkSessionPrivate *s = self->priv;guint32 types[SPICE_N_ELEMENTS(atom2agent)] = { 0 };gint num_types;int a;int selection;if (s->main == NULL)return;selection = get_selection_from_clipboard(s, clipboard);g_return_if_fail(selection != -1);/* GTK+ does seem to cache atoms, but not for Wayland */g_free(s->atoms[selection]);s->atoms[selection] = g_memdup(atoms, n_atoms * sizeof(GdkAtom));s->n_atoms[selection] = n_atoms;if (s->clip_grabbed[selection]) {SPICE_DEBUG("Clipboard is already grabbed, re-grab: %d atoms", n_atoms);}/* Set all Atoms that matches our current protocol implementation */num_types = 0;for (a = 0; a < n_atoms; a++) {guint m;gchar *name = gdk_atom_name(atoms[a]);SPICE_DEBUG(" \"%s\"", name);for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) {guint t;if (strcasecmp(name, atom2agent[m].xatom) != 0) {continue;}if (atom2agent[m].vdagent == VD_AGENT_CLIPBOARD_FILE_LIST) {
#ifdef HAVE_PHODAV_VIRTUALif (!clipboard_get_open_webdav(s->session)) {SPICE_DEBUG("Received %s target, but the clipboard webdav channel isn't available, skipping", atom2agent[m].xatom);break;}
#elsebreak;
#endif}/* check if type is already in list */for (t = 0; t < num_types; t++) {if (types[t] == atom2agent[m].vdagent) {break;}}if (t == num_types) {/* add type to empty slot */types[t] = atom2agent[m].vdagent;num_types++;}}g_free(name);}if (num_types == 0) {SPICE_DEBUG("No GdkAtoms will be sent from %d", n_atoms);return;}s->clip_grabbed[selection] = TRUE;if (spice_main_channel_agent_test_capability(s->main, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND))spice_main_channel_clipboard_selection_grab(s->main, selection, types, num_types);///* Sending a grab causes the agent to do an implicit release */s->nclip_targets[selection] = 0;
}
1.2、guest粘贴:发送request请求获取内容
1.2.1、连接回调函数
static void channel_new(SpiceSession *session, SpiceChannel *channel,gpointer user_data)
{g_return_if_fail(SPICE_IS_GTK_SESSION(user_data));SpiceGtkSession *self = user_data;SpiceGtkSessionPrivate *s = self->priv;if (SPICE_IS_MAIN_CHANNEL(channel)) {SPICE_DEBUG("Changing main channel from %p to %p", s->main, channel);s->main = SPICE_MAIN_CHANNEL(channel);g_signal_connect(channel, "main-clipboard-selection-grab",G_CALLBACK(clipboard_grab), self);g_signal_connect(channel, "main-clipboard-selection-request",G_CALLBACK(clipboard_request), self);g_signal_connect(channel, "main-clipboard-selection-release",G_CALLBACK(clipboard_release_delay), self);}if (SPICE_IS_INPUTS_CHANNEL(channel)) {spice_g_signal_connect_object(channel, "inputs-modifiers",G_CALLBACK(guest_modifiers_changed), self, 0);spice_gtk_session_sync_keyboard_modifiers_for_channel(self, SPICE_INPUTS_CHANNEL(channel), TRUE);}
}
1.2.2、收到服务器的request请求剪切板内容
static gboolean clipboard_request(SpiceMainChannel *main, guint selection,guint type, gpointer user_data)
{g_return_val_if_fail(SPICE_IS_GTK_SESSION(user_data), FALSE);SpiceGtkSession *self = user_data;SpiceGtkSessionPrivate *s = self->priv;GdkAtom atom;GtkClipboard* cb;int m;cb = get_clipboard_from_selection(s, selection);g_return_val_if_fail(cb != NULL, FALSE);g_return_val_if_fail(s->clipboard_by_guest[selection] == FALSE, FALSE);g_return_val_if_fail(s->clip_grabbed[selection], FALSE);if (read_only(self))return FALSE;if (type == VD_AGENT_CLIPBOARD_UTF8_TEXT) {gtk_clipboard_request_text(cb, clipboard_received_text_cb,get_weak_ref(self)); //发送文本} else if (type == VD_AGENT_CLIPBOARD_FILE_LIST) {
#ifdef HAVE_PHODAV_VIRTUALatom = clipboard_select_uris_atom(s, selection);if (atom == GDK_NONE) {return FALSE;}gtk_clipboard_request_contents(cb, atom, clipboard_received_uri_contents_cb, get_weak_ref(self));//发视其他内容
#elsereturn FALSE;
#endif} else {for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) {if (atom2agent[m].vdagent == type)break;}g_return_val_if_fail(m < SPICE_N_ELEMENTS(atom2agent), FALSE);atom = gdk_atom_intern_static_string(atom2agent[m].xatom);gtk_clipboard_request_contents(cb, atom, clipboard_received_cb,get_weak_ref(self));}return TRUE;
}
static gboolean clipboard_grab(SpiceMainChannel *main, guint selection,guint32* types, guint32 ntypes,gpointer user_data)
{g_return_val_if_fail(SPICE_IS_GTK_SESSION(user_data), FALSE);SpiceGtkSession *self = user_data;SpiceGtkSessionPrivate *s = self->priv;GtkTargetEntry targets[SPICE_N_ELEMENTS(atom2agent)];gboolean target_selected[SPICE_N_ELEMENTS(atom2agent)] = { FALSE, };gboolean found;GtkClipboard* cb;int m, n;int num_targets = 0;clipboard_release_delay_remove(self, selection, false);cb = get_clipboard_from_selection(s, selection);g_return_val_if_fail(cb != NULL, FALSE);for (n = 0; n < ntypes; ++n) {found = FALSE;for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) {if (atom2agent[m].vdagent == types[n] && !target_selected[m]) {found = TRUE;g_return_val_if_fail(num_targets < SPICE_N_ELEMENTS(atom2agent), FALSE);targets[num_targets].target = (gchar*)atom2agent[m].xatom;targets[num_targets].info = m;target_selected[m] = TRUE;num_targets++;}}if (!found) {g_warning("clipboard: couldn't find a matching type for: %u",types[n]);}}g_free(s->clip_targets[selection]);s->nclip_targets[selection] = num_targets;s->clip_targets[selection] = g_memdup(targets, sizeof(GtkTargetEntry) * num_targets);/* Receiving a grab implies we've released our own grab */s->clip_grabbed[selection] = FALSE;if (read_only(self) ||!s->auto_clipboard_enable ||s->nclip_targets[selection] == 0) {return TRUE;}if (!gtk_clipboard_set_with_owner(cb,targets,num_targets,clipboard_get,clipboard_clear,G_OBJECT(self))) {g_warning("clipboard grab failed");return FALSE;}s->clipboard_by_guest[selection] = TRUE;s->clip_hasdata[selection] = FALSE;return TRUE;
}
2、guest --> host复制粘贴
2.1、剪切板粘贴时调用函数 clipboard_get
void spice_gtk_session_paste_from_guest(SpiceGtkSession *self)
{g_return_if_fail(SPICE_IS_GTK_SESSION(self));g_return_if_fail(read_only(self) == FALSE);SpiceGtkSessionPrivate *s = self->priv;int selection = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;if (s->nclip_targets[selection] == 0) {g_warning("Guest clipboard is not available.");return;}if (!gtk_clipboard_set_with_owner(s->clipboard, s->clip_targets[selection], s->nclip_targets[selection], clipboard_get, clipboard_clear, G_OBJECT(self))) {g_warning("Clipboard grab failed");return;}s->clipboard_by_guest[selection] = TRUE;s->clip_hasdata[selection] = FALSE;
}
2.2、连接主通道信号 main-clipboard-selection处理粘贴内容
static void clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gpointer user_data)
{g_return_if_fail(SPICE_IS_GTK_SESSION(user_data));RunInfo ri = { NULL, };SpiceGtkSession *self = user_data;SpiceGtkSessionPrivate *s = self->priv;gboolean agent_connected = FALSE;gulong clipboard_handler;gulong agent_handler;int selection;SPICE_DEBUG("clipboard get");selection = get_selection_from_clipboard(s, clipboard);g_return_if_fail(selection != -1);g_return_if_fail(info < SPICE_N_ELEMENTS(atom2agent));g_return_if_fail(s->main != NULL);if (s->clipboard_release_delay[selection]) {SPICE_DEBUG("not requesting data from guest during delayed release");return;}ri.selection_data = selection_data;ri.info = info;ri.loop = g_main_loop_new(NULL, FALSE);ri.selection = selection;ri.self = self;clipboard_handler = g_signal_connect(s->main, "main-clipboard-selection",G_CALLBACK(clipboard_got_from_guest),&ri);agent_handler = g_signal_connect_swapped(s->main, "notify::agent-connected",G_CALLBACK(clipboard_agent_connected),&ri);spice_main_channel_clipboard_selection_request(s->main, selection,atom2agent[info].vdagent);g_object_get(s->main, "agent-connected", &agent_connected, NULL);if (!agent_connected) {SPICE_DEBUG("canceled clipboard_get, before running loop");goto cleanup;}/* This is modeled on the implementation of gtk_dialog_run() even though* these thread functions are deprecated and appears to be needed to avoid* dead-lock from gtk_dialog_run().*/G_GNUC_BEGIN_IGNORE_DEPRECATIONSgdk_threads_leave();g_main_loop_run(ri.loop);gdk_threads_enter();G_GNUC_END_IGNORE_DEPRECATIONScleanup:g_clear_pointer(&ri.loop, g_main_loop_unref);g_signal_handler_disconnect(s->main, clipboard_handler);g_signal_handler_disconnect(s->main, agent_handler);
}
2.3、将内容设置到剪切板上面
static void clipboard_got_from_guest(SpiceMainChannel *main, guint selection,guint type, const guchar *data, guint size,gpointer user_data)
{RunInfo *ri = user_data;SpiceGtkSessionPrivate *s = ri->self->priv;gchar *conv = NULL;g_return_if_fail(selection == ri->selection);SPICE_DEBUG("clipboard got data");if (atom2agent[ri->info].vdagent == VD_AGENT_CLIPBOARD_UTF8_TEXT) {/* on windows, gtk+ would already convert to LF endings, butnot on unix */if (spice_main_channel_agent_test_capability(s->main, VD_AGENT_CAP_GUEST_LINEEND_CRLF)) {conv = spice_dos2unix((gchar*)data, size);size = strlen(conv);}gtk_selection_data_set_text(ri->selection_data, conv ?: (gchar*)data, size);} else {gtk_selection_data_set(ri->selection_data,gdk_atom_intern_static_string(atom2agent[ri->info].xatom),8, data, size);}if (g_main_loop_is_running (ri->loop))g_main_loop_quit (ri->loop);g_free(conv);
}


http://www.ppmy.cn/news/380630.html

相关文章

论文可视化分析神器——CiteSpace和vosviewer

文献计量学是指用数学和统计学的方法&#xff0c;定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体&#xff0c;注重量化的综合性知识体系。特别是&#xff0c;信息可视化技术手段和方法的运用&#xff0c;可直观的展示主题的研究发展历程、研究现状、研究…

嵌入式系统开发中的常见挑战和困难

当涉及嵌入式系统开发时&#xff0c;可能会遇到以下一些常见的挑战和困难&#xff1a; 复杂的硬件和软件集成&#xff1a;嵌入式系统通常涉及硬件和软件的紧密集成&#xff0c;需要同时理解和处理硬件和软件层面的问题。这种复杂性可能导致调试和故障排除变得更加困难。 有限…

php移除excel密码,excel保护密码忘记怎么撤销保护工作表

excel保护密码忘记撤销保护工作表的方法&#xff1a; 第一步&#xff0c;先找到一个带有有工作表保护密码的Excel工作表&#xff0c;然后把后缀名称改为.rar。 第二步&#xff0c;用压缩文件打开&#xff0c;然后找压缩的对应路径。 第三步&#xff0c;把从压缩文件里面找到的.…

Excel忘记保护密码

将工作簿文件名name.xlsx改为name.rar 打开rar文件&#xff0c;进入xl目录 1. 解除工作表保护 进入worksheets目录&#xff0c;右击待解除密码的sheet1.xml&#xff0c;选择编辑 ctrlF找到关键字sheetProtection&#xff0c;把包含关键字的<>段落删除&#xff0c;保存…

excel保护密码怎么解除

excel文件想要解除工作表保护密码&#xff0c;只需要在上方工具栏中找到【审阅】-【撤销工作表保护】输入之前设置的加密密码就可以了。 但是如果你没有保护密码&#xff0c;想要撤销的话就不能使用上面的方法了。需要使用解密软件来帮我们解决问题。【EXCEL解密大师】快速找回…

Excel保护密码破解 打开密码和只读密码等四个密码找回

亲测有用&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; https://download.csdn.net/download/ystyaoshengting/11206062

两种方法清除Excel保护密码

一、利用VBA脚本直接清除 打Excel&#xff0c;打开脚本编辑器&#xff08;AltF11&#xff09;或者如图&#xff0c;右键sheet名称 输入代码并运行&#xff0c;即可清除密码保护&#xff1a; Sub DeletePW()ActiveSheet.Protect DrawingObjects:True, Contents:True, AllowFil…

忘记了Excel工作表保护密码的解决办法

忘记了Excel工作表保护密码&#xff0c;出现这种情况应该怎么解决&#xff1f;&#x1f62d;&#x1f62d;&#x1f62d;&#x1f62d;&#x1f62d;&#x1f62d; 解决办法操作步骤如下&#xff1a; 1、首先将需要解除密码的excel文件的后缀名(.xlsx)改为.rar 2、然后打开后…