【问题标题】:Inserting uris into Gtk.Clipboard with vala使用 vala 将 uris 插入 Gtk.Clipboard
【发布时间】:2018-05-13 18:38:58
【问题描述】:

我目前正在尝试为我的应用程序实现复制和粘贴,问题是我只能根据Gtk.Clipboard的文档将纯文本或图像复制到剪贴板:https://valadoc.org/gtk+-3.0/Gtk.Clipboard.htmlset_text/set_image

但是还有这个方法https://valadoc.org/gtk+-3.0/Gtk.Clipboard.set_with_data.htmlset_with_data,我想我可以用它来添加一个uri或一个uris数组。但我不知道怎么做,也没有找到任何好的例子。

更新

使用给定的答案,我可以用 uris 数组填充剪贴板,但我可以读取它们,当我尝试时,它只需再次调用 get_func 并重新填充它。

CTRL C pressed
clipboard get_func called
Received: file:///home/marcel/Downloads/.gitignore

CTRL V pressd
clipboard get_func called
Received: file:///home/marcel/Downloads
Try Pasting: file:///home/marcel/Downloads

这是我用来测试CTRL + V的代码:

print ("\nCTRL V pressd\n");
clipboard.request_uris ((clipboard, uris) => {
    foreach ( string content in uris ) {
        print ("Try Pasting: ");
        print (content);
        print ("\n");
    }
});

这是get_funcCTRL + C 的相关部分:

clipboard.set_with_owner (
    clipboard_targets,
    (clipboard, selection_data, info, user_data_or_owner) => {
    print ("clipboard get_func called\n");
    var w = user_data_or_owner as Window;
    File[] files = { w.get_selected_file () };

    switch ( info ) {
        case ClipboardProtocol.TEXT_URI_LIST:
            print ("Received: ");
            string[] uris = {};
            foreach ( var file in files ) {
                print (file.get_uri ());
                print ("\n");
                uris += file.get_uri ();
            }
            selection_data.set_uris (uris);
            break; 

正如您在上面的终端输出中看到的,它只是重新填充剪贴板,丢弃之前的值。

【问题讨论】:

  • 嗨 ScriptKiddy。我是这里的编辑,并编辑了您的一些问题。你最新的看起来不错,但我要解决的剩下的事情是人称代词“I”,你经常用小写字母写它。这个词在英文中总是大写的,所以如果你可以这样写,它将节省一些编辑工作。谢谢!

标签: linux gtk uri clipboard vala


【解决方案1】:

根据要求,我提供了将 URI 写入剪贴板和从剪贴板获取 URI 的示例。这些示例基本上是立即获取/设置剪贴板的命令行程序。在实际的 GUI 应用程序中,您可能会对按下按钮或捕捉 CtrlC / CtrlV 做出反应事件,使用Gtk.Widget.add_events() 并在处理Gtk.Widget.event 信号时获取/设置剪贴板。

获取剪贴板

您可以使用Gtk.Clipboard.request_uris () 从 X11 剪贴板请求 URI。此函数接受一个回调,一旦 URI 可用,就会调用该回调。

例子:

public void main (string[] args) {
    Gtk.init (ref args);

    Gdk.Display display = Gdk.Display.get_default ();
    Gtk.Clipboard clipboard = Gtk.Clipboard.get_for_display (display, Gdk.SELECTION_CLIPBOARD);

    clipboard.request_uris (recieved_func);
    Gtk.main ();
}

/* Gtk.ClipboardURIRecievedFunc */
private void recieved_func (Gtk.Clipboard clipboard, string[] uris) {
    foreach (var uri in uris) {
        print (uri + "\n");
    }
    Gtk.main_quit ();
}

valac clipget.vala --pkg=gtk+-3.0编译

设置剪贴板

理论:

来自Qt4 documentation

由于没有标准的方法来复制和粘贴文件 X11 上的应用程序,目前各种 MIME 类型和约定 正在使用。例如,Nautilus 期望文件提供一个 x-special/gnome-copied-files MIME 类型,数据以 剪切/复制操作、换行符和文件的 URL。

Gtk.Clipboard 没有预先设置剪贴板来复制/剪切文件。正如你所说,没有这样的Gtk.Clipboard.set_uris()

相反,您应该通过提供回调来设置剪贴板,让 X11 从请求中获取剪贴板内容。

这些是所需的步骤:

  • 创建一组Gtk.TargetEntrys,指定您的应用程序可以处理哪些剪贴板协议。您需要处理协议text/uri-listx-special/gnome-copied-filesUTF8_STRING。每个TargetEntry 都由其info 字段标识,因此该数字应该是唯一的(请参阅下面示例中的enum ClipboardProtocol

  • 实现Gtk.ClipboardGetFunc 类型的方法。此方法应填充与要复制/剪切的文件路径一起传递的Gtk.SelectionData 对象。检查info 参数以根据指定的协议设置SelectionData 参数。

  • 使用Gtk.Clipboard.set_with_ownerGtk.Clipboard.set_with_data注册回调和X11实现的协议

示例:

enum ClipboardProtocol {
    TEXT_URI_LIST,
    GNOME_COPIED_FILES,
    UTF8_STRING
}

public void main (string[] args) {
    Gtk.init (ref args);

    Gdk.Display display = Gdk.Display.get_default ();
    Gtk.Clipboard clipboard = Gtk.Clipboard.get_for_display (display, Gdk.SELECTION_CLIPBOARD);

    var clipboard_targets = new Gtk.TargetEntry[3];

    Gtk.TargetEntry target_entry = { "text/uri-list", 0, ClipboardProtocol.TEXT_URI_LIST };
    clipboard_targets[0] = target_entry;

    target_entry = { "x-special/gnome-copied-files", 0, ClipboardProtocol.GNOME_COPIED_FILES };
    clipboard_targets[1] = target_entry;

    target_entry = { "UTF8_STRING", 0, ClipboardProtocol.UTF8_STRING };
    clipboard_targets[2] = target_entry;

    var owner = new Object ();

    var rc = clipboard.set_with_owner (
        clipboard_targets,
        get_func,
        clear_func,
        owner
    );
    assert (rc);
    clipboard.store ();

    Gtk.main ();
}

/* Gtk.ClipboardGetFunc */
private void get_func (
    Gtk.Clipboard clipboard,
    Gtk.SelectionData selection_data,
    uint info, 
    void* user_data_or_owner
) {
    print ("GET FUNC!\n");

    File my_file = File.new_for_path ("/home/lukas/tmp/test.txt");
    File my_2nd_file = File.new_for_path ("/home/lukas/tmp/test2.txt");
    File[] files = { my_file, my_2nd_file };

    switch (info) {
        case ClipboardProtocol.TEXT_URI_LIST:
            string[] uris = {};
            foreach (var file in files) {
                uris += file.get_uri ();
            }
            selection_data.set_uris (uris);
            break;

        case ClipboardProtocol.GNOME_COPIED_FILES:
            var prefix = "copy\n"; 
            //var prefix = "cut\n";
            /* use one of the above */

            var builder = new StringBuilder (prefix);
            for (int i = 0; i < files.length; i++) {
                builder.append (files[i].get_uri ()); 
                /* dont put the newline if this is the last file */
                if (i != files.length - 1)
                    builder.append_c ('\n');
            }
            selection_data.set (
                selection_data.get_target (),
                8,
                builder.data
            );
            break;

        case ClipboardProtocol.UTF8_STRING:
            var builder = new StringBuilder ();
            foreach (var file in files) {
                builder.append (file.get_parse_name ());
            }
            builder.append_c ('\n');
            selection_data.set_text (builder.str, -1);
            break;
        default:
            assert_not_reached ();
    }
    Gtk.main_quit ();
}

/* Gtk.ClipboardClearFunc */
private void clear_func (Gtk.Clipboard clipboard, void* data) {
    ;
}

valac clipset.vala --pkg=gtk+-3.0编译

几点说明:

  • 在我的示例中,我只能测试 x-special/gnome-copied-files,因为我目前只安装了 Nautilus。我改编了 Thunar 源代码中的所有协议(请参阅下面的源代码),但它们可能仍需要故障排除*

  • 如果你不想自己实现这个麻烦,你也可以使用 xclip 命令行工具:https://askubuntu.com/a/210428/345569 但是,恕我直言,自己实现这个更优雅。

来源:

【讨论】:

  • 好吧,我现在可以填充剪贴板,但不知道如何阅读。 Ofc 这仍然回答了我最初的问题 :D 但每当我尝试获取内容时,它只会再次填充它。我可能有点误解了整件事?
  • 我不完全明白你所说的“它只是再次填充它”是什么意思。您通常可以使用 Gtk.Clipboard.request_uris () 从剪贴板读取 URI
  • 为 Gtk.Clipboard.request_uris() 添加了一个示例
  • 更新问题
  • @stunningpotato 谢谢!!!此外,非常感谢您也回答了这个问题stackoverflow.com/questions/36215967/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-31
  • 2022-12-27
相关资源
最近更新 更多