如何用X11复制到剪贴板?

发布于 2024-08-14 04:20:30 字数 1073 浏览 7 评论 0原文

使用 OS X 上的框架,我可以使用以下命令将 PNG 复制到粘贴板(在 C 语言中 — 显然我可以将 NSPasteboard 与 Cocoa 一起使用):

#include <ApplicationServices/ApplicationServices.h>

int copyThatThing(void)
{
    PasteboardRef clipboard;
    if (PasteboardCreate(kPasteboardClipboard, &clipboard) != noErr) {
        return -1;
    }

    if (PasteboardClear(clipboard) != noErr) {
        CFRelease(clipboard);
        return -1;
    }

    size_t len;
    char *pngbuf = createMyPNGBuffer(&len); /* Defined somewhere else */
    if (pngbuf == NULL) {
        CFRelease(clipboard);
        return -1;
    }

    CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, pngbuf, 
                                         len, kCFAllocatorNull);
    if (data == NULL) {
        CFRelease(clipboard);
        free(pngbuf);
        return -1;
    }

    OSStatus err;
    err = PasteboardPutItemFlavor(clipboard, NULL, kUTTypePNG, data, 0);
    CFRelease(clipboard);
    CFRelease(data);
    free(pngbuf);

    return 0;
}

我有兴趣将此功能移植到 Linux/*BSD 平台。我如何使用 X 复制这个?

Using the frameworks on OS X, I can use the following to copy a PNG to the pasteboard (in C — obviously I could use NSPasteboard with Cocoa):

#include <ApplicationServices/ApplicationServices.h>

int copyThatThing(void)
{
    PasteboardRef clipboard;
    if (PasteboardCreate(kPasteboardClipboard, &clipboard) != noErr) {
        return -1;
    }

    if (PasteboardClear(clipboard) != noErr) {
        CFRelease(clipboard);
        return -1;
    }

    size_t len;
    char *pngbuf = createMyPNGBuffer(&len); /* Defined somewhere else */
    if (pngbuf == NULL) {
        CFRelease(clipboard);
        return -1;
    }

    CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, pngbuf, 
                                         len, kCFAllocatorNull);
    if (data == NULL) {
        CFRelease(clipboard);
        free(pngbuf);
        return -1;
    }

    OSStatus err;
    err = PasteboardPutItemFlavor(clipboard, NULL, kUTTypePNG, data, 0);
    CFRelease(clipboard);
    CFRelease(data);
    free(pngbuf);

    return 0;
}

I'm interested in porting this functionality to Linux/*BSD platforms. How can I replicate this using X?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

随梦而飞# 2024-08-21 04:20:30

在进行任何操作之前,请先阅读X 选择、剪切缓冲区和 Kill Rings别的。 X11 有一个相当独特的系统,似乎没有其他人可以复制。

与大多数其他系统不同的一个奇怪之处是:如果拥有选择的程序(剪贴板)消失,那么选择也会消失。因此,当您的程序显示“我有一个选择(恰好是一个图像)”然后退出时,没有人能够向您请求该图像的副本。为了有用,剪贴板所有者需要至少坚持到另一个程序进行选择为止。

还在这里吗?这是一个简短的程序,可以使用 PyGTK 执行您想要的操作(因为 C 很痛苦)。

#!/usr/bin/env python
import gtk
import sys

count = 0
def handle_owner_change(clipboard, event):
    global count
    print 'clipboard.owner-change(%r, %r)' % (clipboard, event)
    count += 1
    if count > 1:
        sys.exit(0)

image = gtk.gdk.pixbuf_new_from_file(sys.argv[1])
clipboard = gtk.clipboard_get()
clipboard.connect('owner-change', handle_owner_change)
clipboard.set_image(image)
clipboard.store()
gtk.main()

幕后发生了什么:

  • Gdk 加载图像。
  • Gtk 声明对 CLIPBOARD 选择的所有权。
  • Gtk 请求 CLIPBOARD_MANAGER 复制并获取选择。 (可能没有一个正在运行,因此这可能不会发生。)
  • 当另一个程序请求我们选择的数据时,Gtk 会处理从图像到目标的数据转换和传输。
  • 第一个 OWNER_CHANGE 事件对应于我们取得所有权;等待与我们失去所有权相对应的下一个,然后退出。

如果剪贴板管理器正在运行,该程序可能会立即退出。否则,它将等待,直到在另一个程序中执行“剪切/复制”。

Go read X Selections, Cut Buffers, and Kill Rings before anything else. X11 has a rather unique system that nobody else seems to have copied.

One oddity that is different from most other systems: if the program owning the selection (clipboard) goes away, so does the selection. So when your program says "I have a selection (which happens to be an image)" and then exits, nobody will be able to request a copy of that image from you. In order to be useful, the clipboard owner needs to stick around at least until another program takes the selection.

Still here? Here's a short program that does what you want, using PyGTK (because C is a pain).

#!/usr/bin/env python
import gtk
import sys

count = 0
def handle_owner_change(clipboard, event):
    global count
    print 'clipboard.owner-change(%r, %r)' % (clipboard, event)
    count += 1
    if count > 1:
        sys.exit(0)

image = gtk.gdk.pixbuf_new_from_file(sys.argv[1])
clipboard = gtk.clipboard_get()
clipboard.connect('owner-change', handle_owner_change)
clipboard.set_image(image)
clipboard.store()
gtk.main()

What happens under the hood:

  • Gdk loads an image.
  • Gtk claims ownership of the CLIPBOARD selection.
  • Gtk requests that the CLIPBOARD_MANAGER copy and take the selection. (There might not be one running, so this might not happen.)
  • When another program requests data from our selection, Gtk handles the conversion and transfer of data from the image to the target.
  • The first OWNER_CHANGE event corresponds to us taking ownership; wait for the next one corresponding to us losing ownership, and exit.

If a clipboard manager is running, this program may exit immediately. Otherwise, it will wait until "cut/copy" is performed in another program.

旧时浪漫 2024-08-21 04:20:30

程序终止后在 GTK 剪贴板上存储数据的功能没有得到很好的支持。 GTK.clipboard.store 可能无法存储较大的图像(大于几百 kB),并且像 compiz 这样的高级桌面功能可能会与此机制发生冲突。没有这些缺点的一种解决方案是在后台运行一个简单的 gtk 应用程序。以下Python服务器应用程序使用Pyro包公开ImageToClipboard的方法:


#! /usr/bin/env python
# gclipboard-imaged.py
import gtk, sys, threading;
import Pyro.core;

class ImageToClipboard(Pyro.core.ObjBase):
   def __init__(self, daemon):
      Pyro.core.ObjBase.__init__(self)
      self.daemon = daemon;
   def _set_image(self, img):
      clp = gtk.clipboard_get();
      clp.set_image(img);
   def set_image_from_filename(self, filename):
      with gtk.gdk.lock:
         img = gtk.gdk.pixbuf_new_from_file(filename);
         self._set_image(img);
   def quit(self):
      with gtk.gdk.lock:
         gtk.main_quit();
      self.daemon.shutdown();

class gtkThread( threading.Thread ):
   def run(self):
      gtk.main();

def main():
   gtk.gdk.threads_init();
   gtkThread().start();
   Pyro.core.initServer();
   daemon = Pyro.core.Daemon();
   uri = daemon.connect(ImageToClipboard(daemon),"imagetoclipboard")
   print "The daemon running on port:",daemon.port
   print "The object's uri is:",uri
   daemon.requestLoop();
   print "Shutting down."
   return 0;

if __name__=="__main__":
   sys.exit( main() )

将此程序作为后台进程启动,即

gclipboard-imaged.py &

以下示例客户端应用程序使用命令行中给定的文件名设置剪贴板图像:


#! /usr/bin/env python
# gclipboard-setimage.py
import Pyro.core, sys;

serverobj =  Pyro.core.getProxyForURI("PYROLOC://localhost:7766/imagetoclipboard");
filename = sys.argv[1];
serverobj.set_image_from_filename(filename);

要将图像复制到剪贴板,请运行

gclipboard-setimage.py picname.png

The ability to store data on the GTK clipboard after a program terminates is not well supported. GTK.clipboard.store may fail to store larger images (greater than several hundred kB), and advanced desktop features like compiz may conflict with this mechanism. One solution without these drawbacks is to run a simple gtk application in the background. The following Python server application uses the Pyro package to expose the methods of ImageToClipboard:


#! /usr/bin/env python
# gclipboard-imaged.py
import gtk, sys, threading;
import Pyro.core;

class ImageToClipboard(Pyro.core.ObjBase):
   def __init__(self, daemon):
      Pyro.core.ObjBase.__init__(self)
      self.daemon = daemon;
   def _set_image(self, img):
      clp = gtk.clipboard_get();
      clp.set_image(img);
   def set_image_from_filename(self, filename):
      with gtk.gdk.lock:
         img = gtk.gdk.pixbuf_new_from_file(filename);
         self._set_image(img);
   def quit(self):
      with gtk.gdk.lock:
         gtk.main_quit();
      self.daemon.shutdown();

class gtkThread( threading.Thread ):
   def run(self):
      gtk.main();

def main():
   gtk.gdk.threads_init();
   gtkThread().start();
   Pyro.core.initServer();
   daemon = Pyro.core.Daemon();
   uri = daemon.connect(ImageToClipboard(daemon),"imagetoclipboard")
   print "The daemon running on port:",daemon.port
   print "The object's uri is:",uri
   daemon.requestLoop();
   print "Shutting down."
   return 0;

if __name__=="__main__":
   sys.exit( main() )

Start this program as a background process, i.e.

gclipboard-imaged.py &

The following example client application sets the clipboard image using a filename given at the command line:


#! /usr/bin/env python
# gclipboard-setimage.py
import Pyro.core, sys;

serverobj =  Pyro.core.getProxyForURI("PYROLOC://localhost:7766/imagetoclipboard");
filename = sys.argv[1];
serverobj.set_image_from_filename(filename);

To copy an image to the clipboard, run

gclipboard-setimage.py picname.png

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文