[gtk+/2.24: 5/7] win32: retry loop when calling OpenClipboard()



commit 92e9edfc5f11a8a75296ff58d2323dfb764e838e
Author: Marc-André Lureau <marcandre lureau gmail com>
Date:   Thu Aug 22 17:28:59 2013 +0200

    win32: retry loop when calling OpenClipboard()
    
    The msdn page says: "OpenClipboard fails if another window has the
    clipboard open". And there doesn't seem to be any event when the
    clipboard is free again. Since multiple applications may watch and open
    it simultaneously, it is easy to reach this error. So do a best effort
    with a horrible blocking retry loop...
    
    https://bugzilla.gnome.org/show_bug.cgi?id=706610

 gdk/win32/gdkdisplay-win32.c   |    2 +-
 gdk/win32/gdkprivate-win32.h   |    2 +
 gdk/win32/gdkproperty-win32.c  |    2 +-
 gdk/win32/gdkselection-win32.c |   49 +++++++++++++++++++++++++++++++---------
 4 files changed, 42 insertions(+), 13 deletions(-)
---
diff --git a/gdk/win32/gdkdisplay-win32.c b/gdk/win32/gdkdisplay-win32.c
index bc90c3a..735069c 100644
--- a/gdk/win32/gdkdisplay-win32.c
+++ b/gdk/win32/gdkdisplay-win32.c
@@ -377,7 +377,7 @@ inner_clipboard_window_procedure (HWND   hwnd,
         GdkEvent *event;
         GdkWindow *owner;
 
-        success = OpenClipboard (hwnd);
+        success = _gdk_win32_open_clipboard (hwnd);
         g_return_val_if_fail (success, 0);
         hwndOwner = GetClipboardOwner ();
         owner = gdk_win32_window_lookup_for_display (_gdk_display, hwndOwner);
diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h
index 7899533..93a60c0 100644
--- a/gdk/win32/gdkprivate-win32.h
+++ b/gdk/win32/gdkprivate-win32.h
@@ -291,6 +291,8 @@ void        _gdk_win32_adjust_client_rect   (GdkWindow *window,
 
 void    _gdk_selection_property_delete (GdkWindow *);
 
+gboolean _gdk_win32_open_clipboard      (HWND new_owner);
+
 void    _gdk_dropfiles_store (gchar *data);
 
 void    _gdk_wchar_text_handle    (GdkFont       *font,
diff --git a/gdk/win32/gdkproperty-win32.c b/gdk/win32/gdkproperty-win32.c
index 9a7537b..ce25780 100644
--- a/gdk/win32/gdkproperty-win32.c
+++ b/gdk/win32/gdkproperty-win32.c
@@ -196,7 +196,7 @@ gdk_property_change (GdkWindow    *window,
     {
       if (type == _utf8_string)
        {
-         if (!OpenClipboard (GDK_WINDOW_HWND (window)))
+          if (!_gdk_win32_open_clipboard (GDK_WINDOW_HWND (window)))
            {
              WIN32_API_FAILED ("OpenClipboard");
              return;
diff --git a/gdk/win32/gdkselection-win32.c b/gdk/win32/gdkselection-win32.c
index 41d4d3d..94e8350 100644
--- a/gdk/win32/gdkselection-win32.c
+++ b/gdk/win32/gdkselection-win32.c
@@ -294,8 +294,8 @@ gdk_selection_owner_set_for_display (GdkDisplay *display,
   else
     hwnd = NULL;
 
-  if (!API_CALL (OpenClipboard, (hwnd)))
-    return FALSE;
+  if (!_gdk_win32_open_clipboard (hwnd))
+      return FALSE;
 
   _ignore_destroy_clipboard = TRUE;
   GDK_NOTE (DND, g_print ("... EmptyClipboard()\n"));
@@ -420,8 +420,8 @@ gdk_selection_convert (GdkWindow *requestor,
       gboolean has_png = FALSE;
       gboolean has_bmp = FALSE;
 
-      if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
-       return;
+      if (!_gdk_win32_open_clipboard (GDK_WINDOW_HWND (requestor)))
+        return;
 
       targets = g_new (GdkAtom, CountClipboardFormats ());
       ntargets = 0;
@@ -524,8 +524,8 @@ gdk_selection_convert (GdkWindow *requestor,
        * contents of the clipboard. Get the clipboard data, and store
        * it for later.
        */
-      if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
-       return;
+      if (!_gdk_win32_open_clipboard (GDK_WINDOW_HWND (requestor)))
+        return;
 
       if ((hdata = GetClipboardData (CF_UNICODETEXT)) != NULL)
        {
@@ -571,8 +571,8 @@ gdk_selection_convert (GdkWindow *requestor,
     }
   else if (selection == GDK_SELECTION_CLIPBOARD && target == _image_bmp)
     {
-      if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
-       return;
+      if (!_gdk_win32_open_clipboard (GDK_WINDOW_HWND (requestor)))
+        return;
 
       if ((hdata = GetClipboardData (CF_DIB)) != NULL)
         {
@@ -748,8 +748,8 @@ gdk_selection_convert (GdkWindow *requestor,
       gchar *mapped_target_name;
       UINT fmt = 0;
 
-      if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
-       return;
+      if (!_gdk_win32_open_clipboard (GDK_WINDOW_HWND (requestor)))
+        return;
 
       mapped_target_name = get_mapped_gdk_atom_name (target);
 
@@ -862,6 +862,33 @@ gdk_selection_property_get (GdkWindow  *requestor,
   return prop->length;
 }
 
+gboolean
+_gdk_win32_open_clipboard (HWND new_owner)
+{
+  guint8 tries;
+
+  /* msdn: "OpenClipboard fails if another window has the clipboard
+   * open" There doesn't seem to be an event when the clipboard is
+   * free again. Since multiple applications may watch and open it
+   * simultaneously we do our best effort here with this horrible
+   * blocking retry loop...
+   */
+
+  /* try 8 * 1/4s = 2s */
+  for (tries = 0; tries < 8; tries++)
+    {
+      if (OpenClipboard (new_owner))
+        return TRUE;
+
+      GDK_NOTE (DND, g_print ("_gdk_win32_open_clipboard: try %d, error %d\n",
+                              tries, GetLastError ()));
+
+      g_usleep (G_USEC_PER_SEC / 4);
+    }
+
+  return FALSE;
+}
+
 void
 _gdk_selection_property_delete (GdkWindow *window)
 {
@@ -1191,7 +1218,7 @@ gdk_win32_selection_add_targets (GdkWindow  *owner,
       hwnd = GDK_WINDOW_HWND (owner);
     }
 
-  if (!API_CALL (OpenClipboard, (hwnd)))
+  if (!_gdk_win32_open_clipboard (hwnd))
     return;
 
   /* We have a very simple strategy: If some kind of pixmap image


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]