I've implemented custom clipboard handling in my program that allows me to push to clipboard more than one clipboard format in parallel (plain text format plus "text/html" plus "HTML Format" on windows etc).

My issue is that from time to time I get report from users that they can not paste plain text into some text editor, and when they check the clipboard contents it is indeed the case that only HTML formats are present at the time (although the code always tries to push at least plain text format). The issue appears randomly, I myself have managed to reproduce it only once a long time ago.

The logs always show the following issue:
16:37:02.616 GTK [16]: gdkproperty-win32.c:200: OpenClipboard failed: Access is denied. 16:37:02.626 GTK [8]: inner_clipboard_window_procedure: assertion `success' failed

I've attached the example of the code quite similar to what I use.
It appears as if something is locking the clipboard, but not everything, HTML always seems to pass through.

Additionally, the code to block the default signal handler (g_signal_stop_emission_by_name part) seems to cause crash in my bigger program so I commented it in there.

Can anyone spot the possible issue in my code?

I am using GTK 2.24.10 for Windows here (from www.gtk.org). Compiler is Visual Studio 2008.
Does anyone know of any relevant fixes in the newer GTK in this regards.

Also any tips on what GTK 2.24.x build for Windows you use are welcome.

TIA,
  Miroslav
#include <gtk/gtk.h>
#include <string>

GtkWidget *window1;
GtkWidget *textview1;

GdkAtom atomString              = GDK_NONE;
GdkAtom atomTextHtml    = GDK_NONE;
#ifdef _WIN32
 GdkAtom atomTextHtmlWin= GDK_NONE;
#endif

std::string g_strClipTxt;
std::string g_strClipHtml;
std::string g_strClipHtmlWin;

void SuppressDefaultSignal(GtkWidget *widget, const char *szSignalName)
{
        //FIX: this version throws a warning in console if the signal was not 
fired
        g_signal_stop_emission_by_name(widget, szSignalName);

        GSignalInvocationHint* hint = g_signal_get_invocation_hint(widget);
        if(hint)        //has the code actually been invoked by a signal
        {
                gint signal_id = g_signal_lookup(szSignalName, G_OBJECT_TYPE 
(widget));
                if (signal_id > 0){
                        gulong nSignal = g_signal_handler_find(widget, 
G_SIGNAL_MATCH_ID, signal_id, 0, 0, 0, 0);
                        if(nSignal != 0){
                                if(g_signal_has_handler_pending(widget, 
signal_id, 0, true))
                                        g_signal_stop_emission (widget, 
signal_id, 0);
                        }
                }
        }
}

extern "C" void MyGtkClipboardGetFunc(GtkClipboard *clipboard, GtkSelectionData 
*selection_data, guint info, gpointer user_data_or_owner)
{
        GdkAtom atSelTarget = gtk_selection_data_get_target(selection_data);
        if(atSelTarget == atomTextHtml)
        {
                gtk_selection_data_set (selection_data, atomTextHtml, 8, 
(guchar *)g_strClipHtml.c_str(), g_strClipHtml.size());
        }
#ifdef _WIN32
        else if(atSelTarget == atomTextHtmlWin)
        {
                gtk_selection_data_set (selection_data, atomTextHtmlWin, 8, 
(guchar *)g_strClipHtmlWin.c_str(), g_strClipHtmlWin.size());
        }
#endif
        else
        {
                gtk_selection_data_set_text (selection_data, 
g_strClipTxt.c_str(), -1);
        }
}

void on_copy1_activate (GtkMenuItem *menuitem, gpointer user_data)
{
        //suppress default handler (copies plain text only)
        SuppressDefaultSignal(textview1, "copy_clipboard");

        //init data to be pushed
        g_strClipTxt = "Some text";
        g_strClipHtml = "Some <b>text</b>";
        //g_strClipHtmlWin = "";

        //initiate clipboard transfer
        GtkTargetList *list = gtk_target_list_new (NULL, 0);
        if(!g_strClipTxt.empty()){
                gtk_target_list_add(list, gdk_atom_intern("TEXT", FALSE), 0, 0);
                gtk_target_list_add(list, gdk_atom_intern("UTF8_STRING", 
FALSE), 0, 0);
                gtk_target_list_add(list, gdk_atom_intern("STRING", FALSE), 0, 
0);
        }
        if(!g_strClipHtml.empty()){
                gtk_target_list_add(list, atomTextHtml, 0, 0);
        }
#ifdef _WIN32
        if(!g_strClipHtmlWin.empty()){
                gtk_target_list_add(list, atomTextHtmlWin, 0, 0);
        }
#endif

        int nTargetCnt = 0;
        GtkTargetEntry *targets = gtk_target_table_new_from_list(list, 
&nTargetCnt);
        if(nTargetCnt < 1){
                gtk_target_table_free(targets, nTargetCnt);
                gtk_target_list_unref (list);
                return; //nothing to export
        }

        GdkDisplay *display = gtk_widget_get_display (textview1);
        GtkClipboard *clipboard = gtk_clipboard_get_for_display (display, 
GDK_SELECTION_CLIPBOARD);
        gboolean bOK = gtk_clipboard_set_with_data(clipboard, targets, 
nTargetCnt, MyGtkClipboardGetFunc, NULL, 0);
        if(bOK){
                gtk_clipboard_set_can_store (clipboard, NULL, 0);
        }

        gtk_target_table_free(targets, nTargetCnt);
        gtk_target_list_unref (list);
}

void create_gui()
{
        window1 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        gtk_window_set_title (GTK_WINDOW (window1), "Clipboard test");
        gtk_window_set_default_size (GTK_WINDOW (window1), 500, 350);
        gtk_widget_show (window1);

        GtkWidget *vbox1 = gtk_vbox_new (FALSE, 0);
        gtk_widget_show (vbox1);
        gtk_container_add (GTK_CONTAINER (window1), vbox1);

        GtkWidget *scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
        gtk_widget_show (scrolledwindow1);
        gtk_container_add (GTK_CONTAINER (vbox1), scrolledwindow1);
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), 
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

        GtkTextBuffer *buffer = gtk_text_buffer_new (NULL);
        textview1 = gtk_text_view_new_with_buffer (buffer);
        gtk_widget_show (textview1);
        gtk_container_add (GTK_CONTAINER (scrolledwindow1), textview1);

        g_signal_connect (textview1, "copy-clipboard", G_CALLBACK 
(on_copy1_activate), NULL);
        g_signal_connect (window1, "destroy", G_CALLBACK (gtk_main_quit), NULL);

        atomString       = gdk_atom_intern("STRING", FALSE);
        atomTextHtml = gdk_atom_intern_static_string("text/html");
#ifdef _WIN32
        atomTextHtmlWin = gdk_atom_intern_static_string("HTML Format");
#endif

}

int main (int argc, char *argv[])
{
        gtk_init (&argc, &argv);

        create_gui();

        gtk_main ();

        return 0;
}

#ifdef _WIN32
#include <windows.h>
int APIENTRY WinMain( HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpCmdLine, int nCmdShow)
{
        return main( __argc, __argv );
}
#endif

_______________________________________________
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list

Reply via email to