Last active
April 25, 2020 15:53
-
-
Save jaap-karssenberg/4f7d3dba7d5bc725dacf28a382893d69 to your computer and use it in GitHub Desktop.
Attempt to get clipboard "set_with_data()" to work using ctypes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ctypes | |
import gi | |
gi.require_version('Gtk', '3.0') | |
gi.require_version('GIRepository', '2.0') | |
from gi.repository import GIRepository | |
from gi.repository import Gtk | |
# Load the libraries we need via GIRepository | |
def _get_shared_library(n): | |
repo = GIRepository.Repository.get_default() | |
return repo.get_shared_library(n).split(',')[0] | |
libgtk = ctypes.CDLL(_get_shared_library('Gtk')) | |
libgdk = ctypes.CDLL(_get_shared_library('Gdk')) | |
def c_func(dll, name, args, res=None): | |
fn = getattr(dll, name) | |
fn.restype = res | |
fn.argtypes = args | |
return fn | |
def atom_p(name): | |
return libgdk.gdk_atom_intern_static_string(name, False) | |
print("---- clipboard ----") | |
clipboard = libgtk.gtk_clipboard_get(atom_p(b'CLIPBOARD')) | |
assert clipboard != 0 | |
# Test passing clipboard pointer works | |
gtk_clipboard_set_text = c_func(libgtk, 'gtk_clipboard_set_text', | |
(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint)) | |
gtk_clipboard_wait_for_text = c_func(libgtk, 'gtk_clipboard_wait_for_text', | |
(), res=ctypes.c_char_p) | |
gtk_clipboard_set_text(clipboard, b'Test 123', len(b'Test 123')) | |
print("Set text") | |
text = gtk_clipboard_wait_for_text(clipboard) | |
print("TEXT>", text) | |
assert text == b'Test 123' | |
print("----- target entry list ----") | |
targetentrylist = libgtk.gtk_target_list_new(None, 0) | |
libgtk.gtk_target_list_add( | |
targetentrylist, | |
atom_p(b'text/plain'), | |
0, | |
9, | |
) | |
gtk_target_list_find = c_func(libgtk, 'gtk_target_list_find', | |
(ctypes.c_void_p, ctypes.c_void_p), res=ctypes.c_bool) | |
ok = gtk_target_list_find(targetentrylist, atom_p(b'text/plain'), None) | |
print("FOUND TARGET:", ok) | |
assert ok | |
print("---- functions and set_with_data ----") | |
GetFuncType = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) | |
def get_func(clipboard, selection, info, data): | |
print("GET %r" % ((clipboard, selection, info, data),)) | |
libgtk.gtk_selection_data_set_text(selection, b'Test 456', len(b'Test 456')) | |
ClearFuncType = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p) | |
def clear_func(clipboard, data): | |
print("CLEAR %r" % ((clipboard, data),)) | |
c_get_func = GetFuncType(get_func) | |
c_clear_func = ClearFuncType(clear_func) | |
gtk_clipboard_set_with_data = c_func(libgtk, 'gtk_clipboard_set_with_data', | |
( | |
ctypes.c_void_p, | |
ctypes.c_void_p, | |
ctypes.c_uint, | |
ctypes.c_void_p, #ctypes.POINTER(GetFuncType), | |
ctypes.c_void_p, #ctypes.POINTER(ClearFuncType), | |
ctypes.c_void_p | |
), | |
res=ctypes.c_bool) | |
user_data = "userdata 123" | |
ok = gtk_clipboard_set_with_data( | |
clipboard, | |
targetentrylist, | |
1, | |
c_get_func, | |
c_clear_func, | |
user_data | |
) | |
print(">>>", ok) | |
assert ok | |
gtk_clipboard_wait_for_contents = c_func(libgtk, 'gtk_clipboard_wait_for_contents', | |
(ctypes.c_void_p, ctypes.c_void_p), res=ctypes.c_void_p) | |
data = gtk_clipboard_wait_for_contents(clipboard, atom_p(b'text/plain')) | |
print(">>>>", data) | |
text = gtk_clipboard_wait_for_text(clipboard) | |
print("TEXT>", text) | |
assert text == b'Test 456' | |
# PS need global cache for data so it will not get garbage collected before "clear" |
Yes I understand gtk4 will have an new clipboard API. But that doesn't
solve the issue now.
One way forward would be to write a small function in C that sets the
clipboard and has the soon hardcoded. Then use a ctypes wrapper to get the
data from the python code into this wrapper.
Op za 25 apr. 2020 14:41 schreef Mladen Mijatov <notifications@github.com>:
… ***@***.**** commented on this gist.
------------------------------
Well, it's an important fix but GTK+ developers decided to give up on
every language other than those with direct access to C library. Reason
they stated doesn't help either, they just said "The GtkClipboard api is
gone." Whatever that meant.
Anyway, I tried many different approaches with your code. From single atom
target, to all kinds of variations. I tried getting clipboard for current
display but that failed as well. What I found really odd is that even
simple set_text makes copied data unavailable to other programs, which
led me to believe that getting clipboard does something wrong, even though
atom value is correct.
Do you have some insights of your own which might aid me in pursuing this
issue?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<https://gist.github.com/4f7d3dba7d5bc725dacf28a382893d69#gistcomment-3269285>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAJQYHUQKTLKA55U2WTUSCDROLLAZANCNFSM4MQMXKYQ>
.
That's what I wanted to avoid. My application is entirely written in Python, which means it's architecture agnostic. I was really hoping I could upgrade your code to functional.
That said, I know Polari is doing the C function approach, since application is written in GJS and they are suffering from same stupid decision made by GTK developers. We should check what they are doing and perhaps take their solution.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Well, it's an important fix but GTK+ developers decided to give up on every language other than those with direct access to C library. Reason they stated doesn't help either, they just said "The GtkClipboard api is gone." Whatever that meant.
Anyway, I tried many different approaches with your code. From single atom target, to all kinds of variations. I tried getting clipboard for current display but that failed as well. What I found really odd is that even simple
set_text
makes copied data unavailable to other programs, which led me to believe that getting clipboard does something wrong, even though atom value is correct.Do you have some insights of your own which might aid me in pursuing this issue?