GNOME Bugzilla – Bug 656312
gtk_clipboard_set_with_data/set_with_owner is binding-unfriendly
Last modified: 2018-05-02 15:10:41 UTC
These two methods are not bindable through gobject-introspection because they contain two callbacks, moreover with strange lifetime rules.
Created attachment 193602 [details] [review] New function gtk_clipboard_set_with_closures() Built on top of existing callbacks, no changes to clipboard internals were needed.
+ * @owner: (allow-none): an object that "owns" the data. This object + * will be passed to the callbacks when called. Why is it needed if GClosures already can have a "data" attribute? Not that it will matter to most languages, as they support closures natively...
(In reply to comment #2) > + * @owner: (allow-none): an object that "owns" the data. This object > + * will be passed to the callbacks when called. > > Why is it needed if GClosures already can have a "data" attribute? > > Not that it will matter to most languages, as they support closures natively... Passing owner does more than merely providing another argument in the callback. See gtk_clipboard_get_owner() and have_owner flag usage in gtkclipboard.c. I must admit that I do not fully understand all acrobatics the GtkClipboard does with have_owner; clipboard stores itself into owner's g_object_data, refs the owner in strange places etc., so I better added 'owner' argument functionality to _with_closures() too.
gtk_clipboard_set_with_data was override in the old pygtk bindings http://git.gnome.org/browse/pygtk/tree/gtk/gtk.override#n677 can the old code be ported to the new bindings? This bug is a blocker for us, any idea about what should be the right solution is welcome.
(In reply to comment #1) > Created an attachment (id=193602) [details] [review] > New function gtk_clipboard_set_with_closures() > > Built on top of existing callbacks, no changes to clipboard internals were > needed. Pavel, I am trying to test this patch, because I need the functionality using python. Can you provide one example of use? Thanks!
For that patch, pass owner as None to mimic the behaviour of gtk_clipboard_set_with_data(). The rest should be obvious; the API is otherwise the same. I'd be interested in knowing why gtk_clipboard_set_with_data() itself isn't introspectable; is it because the same user_data is passed to two independent callbacks? I'll be investigating that a little later.
Created attachment 230385 [details] [review] add annotations to existing functions I can't see why these functions were marked as non-introspectable. Here is a patch which adds suitable annotations and makes them available in the gir. Gonzalo, here is a temporary build you can use for testing this: http://arm.koji.fedoraproject.org/koji/taskinfo?taskID=1273675
(In reply to comment #7) > Created an attachment (id=230385) [details] [review] > add annotations to existing functions > > I can't see why these functions were marked as non-introspectable. Here is a > patch which adds suitable annotations and makes them available in the gir. > > Gonzalo, here is a temporary build you can use for testing this: > http://arm.koji.fedoraproject.org/koji/taskinfo?taskID=1273675 Generated gir is probably 'fine', but last time I looked, no binding was able to handle multiple closures bound to single user_data field. Therefore I originally marked the function as (skip).
(In reply to comment #8) > (In reply to comment #7) > > Created an attachment (id=230385) [details] [review] [details] [review] > > add annotations to existing functions > > > > I can't see why these functions were marked as non-introspectable. Here is a > > patch which adds suitable annotations and makes them available in the gir. > > > > Gonzalo, here is a temporary build you can use for testing this: > > http://arm.koji.fedoraproject.org/koji/taskinfo?taskID=1273675 > > Generated gir is probably 'fine', but last time I looked, no binding was able > to handle multiple closures bound to single user_data field. Therefore I > originally marked the function as (skip). Also, I'm not sure whether (scope async) annotation is right one for get_func; can't get_func() really be called multiple times, not only once as (scope async) expects?
Created attachment 230752 [details] Gtk2 testcase
Created attachment 230753 [details] Gtk3 testcase
I did compare a GTK2 and GTK3 python test case using the rpm Daniel provided. In the GTK3 test case get_func() gets never called. Meaning that GtkClipboardReceivedFunc [1] does not get the data meant to be copied. [1] http://developer.gnome.org/gtk3/3.4/gtk3-Clipboards.html#GtkClipboardReceivedFunc
(In reply to comment #9) > (In reply to comment #8) > > (In reply to comment #7) > > > Created an attachment (id=230385) [details] [review] [details] [review] [details] [review] > > > add annotations to existing functions > > > > > > I can't see why these functions were marked as non-introspectable. Here is a > > > patch which adds suitable annotations and makes them available in the gir. > > > > > > Gonzalo, here is a temporary build you can use for testing this: > > > http://arm.koji.fedoraproject.org/koji/taskinfo?taskID=1273675 > > > > Generated gir is probably 'fine', but last time I looked, no binding was able > > to handle multiple closures bound to single user_data field. Therefore I > > originally marked the function as (skip). > > Also, I'm not sure whether (scope async) annotation is right one for get_func; > can't get_func() really be called multiple times, not only once as (scope > async) expects? Yes, agreed, it should be able to call get_func several times (several pastes of one copy). clear_func should be only called once (when a new copy is made the clear_func of the previous copy is called), so here the scope looks correct. https://live.gnome.org/GObjectIntrospection/Annotations#Callbacks_Scope_Types I discussed with Daniel a bit more, the annotation for set_with_data is tricky: 2 callbacks, both of which share the same user_data (we have to check if that is handled by pygobject3 correctly) and I don't think there is a scope annotation which describes the behaviour and circumstances under which this callback will be called, so the callback can be freed up again. So it looks like, either we can get the annotation correct or we need new API, either using GDestroyNotify (and "notified" annotation) or a GClosure.
Created attachment 231391 [details] Gtk3 example using gtk_clipboard_set_with_closures
Pavel, I did modify my GTK3 example to use your gtk_clipboard_set_with_closures. When I run the code, get_func is never called and therefore the data is not passed. Do you see anything wrong with my test case? Or do you have a testcase using your patch? I did some print outs in gtk itself and "closures_get_func" seem to not be called at all.
(In reply to comment #15) > Pavel, I did modify my GTK3 example to use your > gtk_clipboard_set_with_closures. When I run the code, get_func is never called > and therefore the data is not passed. Do you see anything wrong with my test > case? Or do you have a testcase using your patch? > > I did some print outs in gtk itself and "closures_get_func" seem to not be > called at all. Simon, this is strange. I can confirm that running your sample does not invoke get_func() at all. However, I tried to rewrite your test in Lua, and there get_func() and clear_func() are clearly invoked correctly. However, selectiondata does not seem to carry data payload correctly, as seen from the transcript below, but this might also be bug in lgi Lua binding. I'll investigate more during the next weekend (hopefully). * clipboard_get_func lgi.obj 0x166bb80:Gtk.Clipboard(GtkClipboard) lgi.rec 0x1669a40:Gtk.SelectionData 0 * __paste_contents_received: lgi.obj 0x166bb80:Gtk.Clipboard(GtkClipboard) lgi.rec 0x7fff6bb46450:Gtk.SelectionData userdata: 0x7f93123ae240 --data= table: 0x167f1e0 --format= 0 --target= STRING
Created attachment 231512 [details] The same sample written in Lua Rewrite of pygobject previos test sample in Lua (using lgi binding)
Created attachment 231578 [details] [review] introspection patch, partially fixes issue AFAICS respectively setting notified/async scopes to get/clear_func is the right thing to do with those functions, there is still an unresolved issue though in the first GtkTargetEntry* argument though, as you can only do Gtk.TargetEntry.new() with python, and an array of those is actually a GtkTargetEntry** to the C side
Created attachment 231644 [details] [review] Add binding-friendly gtk_clipboard_set_with_closures() New method covers functionality of gtk_clipboard_set_with_data() and gtk_clipboard_set_with_owner(), but is gobject-introspection and language bindings friendly.
(In reply to comment #18) > Created an attachment (id=231578) [details] [review] > introspection patch, partially fixes issue > > AFAICS respectively setting notified/async scopes to get/clear_func is the > right thing to do with those functions, Thanks! This is clever, and it works for me for Lua/lgi binding. IMHO it is on the border of what bindings are supposed to support; two closures bound to single userdata, one of them marked as notified but no real GDestroyNotify handler is ever invoked, therefore it relying on resources for both closures freed by calling clear_func marked as async. > there is still an unresolved issue > though in the first GtkTargetEntry* argument though, as you can only do > Gtk.TargetEntry.new() with python, and an array of those is actually a > GtkTargetEntry** to the C side This would explain why Simon's example for _set_with_closures() fails with pygobject but works fine with lgi. The proposed patch also does not make _set_with_owner() work, but it most probably does not matter too much. In case that _set_with_owner will be needed, I attached fixed version of my original patch. Note that both approaches can be applied - Carlos annotation fix to make set_with_data() work and set_with_closures() to make set_with_owner() variant usable too.
Created attachment 231733 [details] [review] pygobject patch The remaining issue with the GtkTargetEntry array was indeed a pygobject glitch, this patch fixes the marshalling of arrays of boxed objects when the C side is expecting an array of structs.
Created attachment 231734 [details] working python testcase
Created attachment 231760 [details] [review] updated patch The other patch had bogus changes, my bad
Excellent work Carlos, with the GTK and Pygobject patch in place to test case passes fine now! Thanks!
(In reply to comment #23) > Created an attachment (id=231760) [details] [review] > updated patch + gboolean is_pointer = item_iface_cache->g_type == G_TYPE_POINTER; This flag isn't used (and compilation fails due to it); is that some debugging leftover? I'm not sure whether a "const GtkTargetEntry *targets" array would ever have a POINTER gtype, shouldn't that be the proper gtype of GtkTargetEntry as this is a boxed struct? I have some difficulties with coming up with a test case for this. The "working python test case" (https://bugzilla.gnome.org/attachment.cgi?id=231734) doesn't behave any different with and without this pygobject patch: in both cases __clipboard_clear_func_cb() is being called (according to the print), but __clipboard_get_func_cb() is never called. This might be due to the insufficient annotation patch (https://bugzilla.gnome.org/attachment.cgi?id=231578); this was already being discussed above, a function which shares user data between two callbacks is not introspectable; even more so, changing the scope to (notified) when the function doesn't actually take a GDestroyNotify can't work. So I'm trying to reduce this to a test case which actually checks this case: passing an array of struct values as an argument to a method (not an array of pointers to structs). I thought both cases were already covered by g-i's GIMarshallingTests, in gi_marshalling_tests_array_struct_in() (which is very similar to gtk_clipboard_set_with_data () wrt. the struct array) and gi_marshalling_tests_array_simple_struct_in() (which covers the "array of struct pointers" case). It seems we might need a third one for a value array of boxed structs, I'm trying that now.
Comment on attachment 231760 [details] [review] updated patch OK, got it. I added the missing test API in http://git.gnome.org/browse/gobject-introspection/commit/?id=2611eb1a69bfe4a098c60ab8efda32ec443c250c and committed Carlos' patch with the is_pointer, tab/space and changelog cleanup, together with a test case: http://git.gnome.org/browse/pygobject/commit/?id=9454c01f2b1b82d43eea0f72fe9a28ef50065fc9 Thank you!
Comment on attachment 231578 [details] [review] introspection patch, partially fixes issue Setting the annotation patch to "needs work", as this doesn't really help.
(In reply to comment #25) > __clipboard_get_func_cb() is never called. This might be due to the > insufficient annotation patch > (https://bugzilla.gnome.org/attachment.cgi?id=231578); this was already being > discussed above, a function which shares user data between two callbacks is not > introspectable; even more so, changing the scope to (notified) when the > function doesn't actually take a GDestroyNotify can't work. Carlos' introspection patch actually can work, if the binding is ready for that; the point is that both closures are bound to single user_data and one of the closures marked as async scope should cleanup resources for both closures after being executed, therefore no real GDestroyNotify callback for get_func() is provided/needed. This is how Lua/lgi implements it and thus it works fine here. I thought that other bindings might have problems with this, but seeing success report from Simon (comment 24) somehow made me think that even pygobject does handle that case (i.e. handling userdata/closure with 1:N relation instead of 1:1) - the only question is whether pygobject does not leak resources related to get_func() when it cleans up resources for clear_func() after being called. Of course, in case that it is decided that this is not the way to go, the original patch introducing set_with_closures() is still available, however I'd vote for including Carlos' annotation patch in any case.
(In reply to comment #28) > Carlos' introspection patch actually can work, if the binding is ready for > that; the point is that both closures are bound to single user_data and one of > the closures marked as async scope should cleanup resources for both closures > after being executed, therefore no real GDestroyNotify callback for get_func() > is provided/needed. That would work if it's guaranteed that the (notified) callback only gets called before the single (async) one, which certainly works in this case. But as I said, even with that annotation patch, the __clipboard_get_func_cb() callback never gets called, so I don't think pygobject handles this. > Of course, in case that it is decided that this is not the way to go, the > original patch introducing set_with_closures() is still available, however I'd > vote for including Carlos' annotation patch in any case. It doesn't hurt, but in order to work it has to assume that bindings actually handle this case which is a potential crasher or leak. Thanks!
(In reply to comment #29) > But as I said, even with that annotation patch, the __clipboard_get_func_cb() > callback never gets called, so I don't think pygobject handles this. That indeed deserves investigation, the annotation patch doesn't directly affect how this function is called within GTK+, but the pygobject patch you pushed as 9454c01f2b helped pass the right memory pointers as GtkTargetEntries. With pygobject from master and python 2.7.3, when I click copy, and then the paste button on the testcase in comment #22 , I get this on stdout * __clipboard_get_func_cb data= hello clipboard * __paste_contents_received: <GtkSelectionData at 0x7fffb3e5eea0> None - data= 8 - type= hello clipboard - format= STRING - target= foobar So get_func seems to be called here when requested for a known target atom
> with pygobject from master and python 2.7.3 I guess that's the difference. I tried this with Python 3.3, where the __clipboard_get_func_cb() never gets called.
This is certainly weird, I've setup a python3 pygobject env, and the function is indeed called. I've tried with different variants of the introspection patch and just removing (skip) from gtk+ master as-is gets this function called, the (closure user_data) in the patch has an effect on the data being None or valid though. Now, it seems to fail directly after, on the first argument of selectiondata.set(): carlos@sacarino:~/Source/gnome/pygobject$ python3 ~/Downloads/clipi_gtk3.py * __clipboard_get_func_cb data= hello clipboard Traceback (most recent call last):
+ Trace 231309
selectiondata.set(Gdk.Atom.intern('STRING', False), 8, data)
return info.invoke(*args, **kwargs) TypeError: Item 0: Must be number or single byte string, not str
- data= 0 - type= b'' - format= None - target= foobar It does look like the GdkAtom is being dealt with as a string there, maybe getting a bit unrelated to the original bug scope...
Created attachment 232000 [details] testcase adapted to python3 for reference
I confirm Carlos's observations: with the pygobject patch applied, and the GTK+ annotations patch, the example works fine (__clipboard_get_func_cb is called) under python2 and python3, but under python3 there is the exception with the Atom.
selectiondata.set(Gdk.Atom.intern('STRING', False), 8, data) The Python3-specific exception is related to the handling of the final parameter, "data". We pass this as a string from __copy_clicked_cb. The corresponding C parameter is a guchar*. In Python 2, when marshalling here, we hit the following code in _pygi_marshal_from_py_array(): if (sequence_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8 && PYGLIB_PyBytes_Check (py_arg)) { memcpy(array_->data, PYGLIB_PyBytes_AsString (py_arg), length); [...] goto array_success; } In Python 3, the same PYGLIB_PyBytes_Check fails, because a string is not directly equivalent to an array of bytes as it was before. The exception can be avoided in Python 3 by setting data to b'hello clipboard'. Similarly the same problem can be reproduced under Python 2 by setting data to u'hello clipboard'. Not sure if this is the intended behaviour or not. Anyway, it is a bit beside the point; I can confirm that the annotations and callbacks are working after the above patches, on both Python 2.7 and Python 3.3.
I am testing on F20 (gtk 3.10) and the patch add_annotations_to_existing_functions [1] never landed, in gtk-3-10 or master. I recompiled gtk (3.10) with the patch applied, and the testcase provided by garnacho works ok, then all the other pieces landed. Should I open another ticket? [1] https://bug656312.bugzilla-attachments.gnome.org/attachment.cgi?id=230385
Created attachment 277454 [details] [review] Same patch to add annotation, but with a little change to apply on master The only difference is the replace of “owns” by "owns".
Review of attachment 277454 [details] [review]: the functions are skipped because they are not really (scope async).
Hello everyone, my apologies for jumping in so late in the discussion, but I was wondering what would be missing to get any of these solutions upstream. Is there anything missing with Carlos solution? Daniel Drake and Gonzalo Odiard comments suggest that the annotations patch works. But, if there are fundamental problems with Carlos approach, why not falling back to the original closure approach? I am particularly interested in this issue, as this affects Sugar on newer platforms. Please let me know if there anything I can do to help.
*** Bug 682604 has been marked as a duplicate of this bug. ***
*** Bug 743054 has been marked as a duplicate of this bug. ***
I've been keen to see this issue solved since August 2014. See this StackOverflow question: http://stackoverflow.com/q/25151437/60075 I'd like to use the set_with_data() function to copy HTML (plus a plain text equivalent) to the clipboard. I'm interested in doing it first in Linux, but also cross-platform.
Storing multiple UTF-8 strings with different static-string targets, is the goal we're trying to achieve with gtk_clipboard_set_with_data. The method is low-level, so if it can't be made binding-friendly, maybe instead could someone please introduce a new helper method, set_targets? Not very familiar with C, but the signature might be something like: void gtk_clipboard_set_targets (GtkClipboard *clipboard, gchar **targets, gint *n_targets, gchar **texts, gint *n_texts); For example, it would let Craig above (#comment 42) write in Python: targets = ["text/html", "text/plain;charset=utf-8"] texts = ["<h1>Document title</h1>", "# Document title"] clipboard.set_targets(targets, texts) This is the call I'd like to make from Gjs: const targets = ["x-special/gnome-copied-files", "text/plain;charset=utf-8"]; const texts = ["copy\n" + uris, uris]; clipboard.set_targets(targets, texts); Under the hood, it could still use gtk_clipboard_set_with_data, with a get_func choosing one of the texts based on the target of selection_data.
It would also be nice for request_contents to have a form that accepts a string instead of the atom, and calls gdk_atom_intern_static_string internally. Apparently Gjs can't work with GdkAtom.
Well I implemented my suggestion, https://github.com/makepost/clippy lets one store multiple UTF-8 strings with different targets in GtkClipboard from Gjs. One difference because I misunderstood atoms at first, target strings in this case are not static, with equality check by value (gdk_atom_intern) rather than reference (gdk_atom_intern_static_string). To build and try demo, follow https://wiki.gnome.org/Newcomers/BuildProject with the repository link above. Please suggest what I should change so methods currently provided by this library can be merged into GtkClipboard itself.
Created attachment 363992 [details] [review] Add gtk_clipboard_set_targets() New methods provide binding-friendly copy&paste of x-special/gnome-copied-files, text/html etc. JavaScript demo works. https://bugzilla.gnome.org/show_bug.cgi?id=656312#c45
Comment on attachment 363992 [details] [review] Add gtk_clipboard_set_targets() >diff --git a/gtk/gtkclipboard.c b/gtk/gtkclipboard.c >index c328baded4..5e959cbf3c 100644 >--- a/gtk/gtkclipboard.c >+++ b/gtk/gtkclipboard.c >@@ -110,6 +110,7 @@ typedef struct _RequestRichTextInfo RequestRichTextInfo; > typedef struct _RequestImageInfo RequestImageInfo; > typedef struct _RequestURIInfo RequestURIInfo; > typedef struct _RequestTargetsInfo RequestTargetsInfo; >+typedef struct _SetTargetsContents SetTargetsContents; > > struct _RequestContentsInfo > { >@@ -150,6 +151,15 @@ struct _RequestTargetsInfo > gpointer user_data; > }; > >+struct _SetTargetsContents >+{ >+ gint n; >+ >+ GtkTargetEntry *targets; >+ >+ gchar **texts; >+}; >+ > static void gtk_clipboard_finalize (GObject *object); > static void gtk_clipboard_owner_change (GtkClipboard *clipboard, > GdkEventOwnerChange *event); >@@ -378,6 +388,26 @@ gtk_clipboard_get_default (GdkDisplay *display) > return gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD); > } > >+/** >+ * gtk_clipboard_get_for_string: >+ * @selection: a string which identifies the clipboard to use >+ * >+ * Returns the clipboard object for the given selection. >+ * See gtk_clipboard_get_for_display() for complete details. >+ * >+ * Returns: (transfer none): the appropriate clipboard object. If no clipboard >+ * already exists, a new one will be created. Once a clipboard >+ * object has been created, it is persistent and, since it is >+ * owned by GTK+, must not be freed or unreffed. >+ * >+ * Since: 3.94 >+ */ >+GtkClipboard * >+gtk_clipboard_get_for_string (const gchar *selection) >+{ >+ return gtk_clipboard_get (gdk_atom_intern (selection, FALSE)); >+} >+ > static void > selection_get_cb (GtkWidget *widget, > GtkSelectionData *selection_data, >@@ -890,6 +920,89 @@ gtk_clipboard_set_surface (GtkClipboard *clipboard, > > } > >+static void >+targets_get_func (GtkClipboard *clipboard, >+ GtkSelectionData *selection_data, >+ guint info, >+ gpointer data) >+{ >+ gint i; >+ SetTargetsContents *contents = data; >+ GdkAtom target = gtk_selection_data_get_target (selection_data); >+ >+ for (i = 0; i < contents->n; i++) >+ { >+ if (target == gdk_atom_intern (contents->targets[i].target, FALSE)) >+ { >+ gtk_selection_data_set (selection_data, target, 8, >+ (guchar *) contents->texts[i], >+ strlen (contents->texts[i])); >+ break; >+ } >+ } >+} >+ >+static void >+targets_clear_func (GtkClipboard *clipboard, >+ gpointer data) >+{ >+ SetTargetsContents *contents = data; >+ >+ gtk_target_table_free (contents->targets, contents->n); >+ g_strfreev (contents->texts); >+ g_free (contents); >+} >+ >+/** >+ * gtk_clipboard_set_targets: >+ * @clipboard: a #GtkClipboard object >+ * @targets: (array length=n_targets): array containing information >+ * about the available forms for the clipboard data >+ * @n_targets: number of elements in @targets >+ * @texts: (array length=n_texts): UTF-8 strings >+ * @n_texts: number of elements in @targets, must be equal to n_targets >+ * >+ * Sets the contents of the clipboard to the given UTF-8 strings, each >+ * corresponding to a given data type. >+ * >+ * Since: 3.94 >+ **/ >+void >+gtk_clipboard_set_targets (GtkClipboard *clipboard, >+ gchar **targets, >+ gint n_targets, >+ gchar **texts, >+ gint n_texts) >+{ >+ SetTargetsContents *contents; >+ gint i; >+ GtkTargetList *target_list; >+ >+ g_return_if_fail (GTK_IS_CLIPBOARD (clipboard)); >+ g_return_if_fail (targets != NULL); >+ g_return_if_fail (texts != NULL); >+ g_return_if_fail (n_targets == n_texts); >+ >+ contents = g_new (SetTargetsContents, 1); >+ contents->texts = g_strdupv (texts); >+ target_list = gtk_target_list_new (NULL, 0); >+ >+ for (i = 0; i < n_targets; i++) >+ gtk_target_list_add (target_list, >+ gdk_atom_intern (targets[i], FALSE), 0, 0); >+ >+ contents->targets = gtk_target_table_new_from_list (target_list, >+ &contents->n); >+ >+ gtk_clipboard_set_with_data (clipboard, >+ contents->targets, n_targets, >+ targets_get_func, targets_clear_func, >+ contents); >+ gtk_clipboard_set_can_store (clipboard, NULL, 0); >+ >+ gtk_target_list_unref (target_list); >+} >+ > static void > set_request_contents_info (GtkWidget *widget, > RequestContentsInfo *info) >@@ -1338,6 +1451,34 @@ gtk_clipboard_request_targets (GtkClipboard *clipboard, > info); > } > >+/** >+ * gtk_clipboard_request_target: >+ * @clipboard: a #GtkClipboard >+ * @target: information about the form into which the clipboard >+ * owner should convert the selection >+ * @callback: (scope async): A function to call when the results are received >+ * (or the retrieval fails). If the retrieval fails the length field of >+ * @selection_data will be negative. >+ * @user_data: user data to pass to @callback >+ * >+ * Requests the contents of clipboard as the given target. >+ * When the results of the result are later received the supplied callback >+ * will be called. >+ **/ >+void >+gtk_clipboard_request_target (GtkClipboard *clipboard, >+ const gchar *target, >+ GtkClipboardReceivedFunc callback, >+ gpointer user_data) >+{ >+ g_return_if_fail (GTK_IS_CLIPBOARD (clipboard)); >+ g_return_if_fail (callback != NULL); >+ >+ gtk_clipboard_request_contents (clipboard, >+ gdk_atom_intern (target, FALSE), >+ callback, user_data); >+} >+ > typedef struct > { > GMainLoop *loop; >diff --git a/gtk/gtkclipboard.h b/gtk/gtkclipboard.h >index ecc49bee10..73f3443857 100644 >--- a/gtk/gtkclipboard.h >+++ b/gtk/gtkclipboard.h >@@ -184,9 +184,10 @@ GtkClipboard *gtk_clipboard_get_for_display (GdkDisplay *display, > GdkAtom selection); > GDK_AVAILABLE_IN_ALL > GtkClipboard *gtk_clipboard_get (GdkAtom selection); >- > GDK_AVAILABLE_IN_3_16 >-GtkClipboard *gtk_clipboard_get_default (GdkDisplay *display); >+GtkClipboard *gtk_clipboard_get_default (GdkDisplay *display); >+GDK_AVAILABLE_IN_3_94 >+GtkClipboard *gtk_clipboard_get_for_string (const gchar *selection); > > GDK_AVAILABLE_IN_ALL > GdkDisplay *gtk_clipboard_get_display (GtkClipboard *clipboard); >@@ -218,6 +219,12 @@ void gtk_clipboard_set_image (GtkClipboard *clipboard, > GDK_AVAILABLE_IN_3_94 > void gtk_clipboard_set_surface (GtkClipboard *clipboard, > cairo_surface_t *surface); >+GDK_AVAILABLE_IN_3_94 >+void gtk_clipboard_set_targets (GtkClipboard *clipboard, >+ gchar **targets, >+ gint n_targets, >+ gchar **texts, >+ gint n_texts); > > GDK_AVAILABLE_IN_ALL > void gtk_clipboard_request_contents (GtkClipboard *clipboard, >@@ -245,6 +252,11 @@ GDK_AVAILABLE_IN_ALL > void gtk_clipboard_request_targets (GtkClipboard *clipboard, > GtkClipboardTargetsReceivedFunc callback, > gpointer user_data); >+GDK_AVAILABLE_IN_3_94 >+void gtk_clipboard_request_target (GtkClipboard *clipboard, >+ const gchar *target, >+ GtkClipboardReceivedFunc callback, >+ gpointer user_data); > > GDK_AVAILABLE_IN_ALL > GtkSelectionData *gtk_clipboard_wait_for_contents (GtkClipboard *clipboard,
Created attachment 364244 [details] [review] Add gtk_clipboard_set_targets() with brace indent fix Sorry for the accidental comment. Thought the "Edit Attachment As Comment" button would "Edit Attachment", but the real keywords are "As Comment".
Created attachment 364245 [details] [review] Add gtk_clipboard_set_targets() with brace indent fix and no quote Diff, not diff quote... Sorry for repeated noise.
-- GitLab Migration Automatic Message -- This bug has been migrated to GNOME's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/gtk/issues/364.