Gtk4 win32: debug clipboard issue

Hi,

There is a long standing issue plaguing me with Gtk4 on Windows10 : after some time (can be minutes or days), randomly, my app stops receiving clipboard content from other apps.

Typically:

  • copy from Notepad++ , when pasting in my app I don’t get the Notepad++ text but the previous clipboard content.
  • copy from my app, paste in my app → works
  • copy from Notepad++, paste in other apps → works
  • copy from my app, paste in Notepad++ → works

Looks like at this point Gdk isn’t able to retrieve content from Win32 APIs anymore…

Some context: I’m using python-gobject, and had this issue since I started the porting from gtk3 to gtk4 about 1 year ago (i.e. not a recent regression). Gtk3 isn’t affected.

Anyone has knowledge about how Gdk-Win32 processes the incoming clipboard content? Is there an event on clipboard changes, or just polling? Any hints where in the code I can put some breakpoints to see what’s going on?

Hi @gwillems!

To get useful informations, try running with a debug build of GTK and set GDK_DEBUG=clipboard. See Gtk – 4.0: Running and debugging GTK Applications

In particular look what happens in calls to OpenClipboard and GetClipboardData inside gdk/win32/gdkclipdrop-win32.c · main · GNOME / gtk · GitLab

I’ll try reproducing the issue anyway :wink:

Thanks @lb90 !

I used GDK_DEBUG=clipboard,dnd to log more stuff, worked fine, but when the issue occurred no clipboard or dnd logs were printed anymore…

So I attached gdb and put a breakpoint in _clipboard_window_procedure.

  • when the clipboard worked fine, I saw the messages 775=WM_DESTROYCLIPBOARD then 776=WM_DRAWCLIPBOARD, plus some weird message 49918.
  • but after the issue, I could only see the messages 49918 events (so the clipboard_window seems alive). OpenClipboard and GetClipboardData don’t even get called anymore after this point.

I added more logs to see if I got WM_DESTROY or WM_CHANGECBCHAIN.
Let’s see how it goes.

Calls to Win32 clipboard APIs are all done from a worker thread named “GDK Win32 Clipboard Thread”: gdk/win32/gdkclipdrop-win32.c · 4.12.3 · GNOME / gtk · GitLab. It creates a hidden HWND for clipboard operations and then spins a Win32 message loop. Probably window message 49918 is the registered window message GDK_WORKER_THREAD_WAKEUP: gdk/win32/gdkclipdrop-win32.c · 4.12.3 · GNOME / gtk · GitLab

I’d check what the clipboard thread does when receiving the wakeup message in gdk/win32/gdkclipdrop-win32.c · 4.12.3 · GNOME / gtk · GitLab

Yes, it’s this clipboard_window variable.
The thread seems to run fine, events are dispatched to _clipboard_window_procedure().

Doesn’t seem so…
I don’t enter the if (message == thread_wakeup_message || message == WM_TIMER) block, the message 49918 just gets consumed in the default case by DefWindowProcW().
I see it typically when changing windows focus, I don’t think it’s related to clipboard processing.

Thanks for your support, by the way.

1 Like

Mmh ok, however 49918 is a registered window message, because it’s in the range 0xC000 - 0xFFFF. This was documented by Raymond Chen in Which message numbers belong to whom?. See also RegisterWindowMessageW function (winuser.h) - Win32 apps | Microsoft Learn. Of course it can be a different message than the one registered by GDK, after all messages can be sent from external sources, but seems quite unlikely. Could you print the value of thread_wakeup_message when the issue occurs? I suspect that the variable gets overwritten, somehow

Good point, I’ll check that.
Thanks!

Otherwise find out about the mysterious message with a call to…GetClipboardFormatName :slight_smile: c++ - Find original name of a message obtained by RegisterWindowMessage Windows API - Stack Overflow

It can even be called from an external process!

1 Like

Well, according to GetClipboardFormatName(), my message 49918 corresponds to WM_MSO_BROADCASTCHANGE. So just noise from Microsoft Office, nothing to worry about.

My thread_wakeup_message has a value = 49749, same as the one assigned at init, so not corrupted (I did put a watch on it with gdb, but did not trigger anyway).

That wakeup times doesn’t seem active:

(gdb) print *clipboard_thread_data
$5 = {clipboard_window = 0x1f0d9e, input_queue = 0x19a0b580ad0, stored_hwnd_owner = 0x0, owner_change_time = 359634149907, clipboard_opened_for = 0xffffffffffffffff, hwnd_next_viewer = 0x0, dequeued_items = 0x0, wakeup_timer = 0, cached_advertisement = 0x19a40252ae0,
  render_queue = 0x19a0b580c10, ignore_destroy_clipboard = 0}

No occurrences of WM_CHANGECBCHAIN nor WM_DESTROY in my logs.

I’m clueless :thinking:
I just don’t receive clipboard events anymore…

1 Like

From Microsoft docs:

https://learn.microsoft.com/en-us/windows/win32/dataxchg/using-the-clipboard#monitoring-clipboard-contents

They claim our “Clipboard Viewer Window” is obsolete and recommend using AddClipboardFormatListener() instead. Seems only available since Windows10, are older Windows version still supported by gtk? If not we could give it a try :slight_smile:

Yes, it was introduced in Windows Vista. See win32: use AddClipboardFormatListener when available (#442) · Issues · GNOME / gtk · GitLab. Looks like we made the switch for GTK3 but did not forward-port to GTK4!

From the issue report:

Clipboard viewer method has design issues, they can be easily broken by misbehaving applications

So could it be that the culprit is an external application?

1 Like

Good question :slight_smile: The doc says that when we use the “Clipboard Viewer Window” then we have to manage the clipboard chain (react on changes WM_CHANGECBCHAIN, remove ourselves from the chain on on WM_DESTROY).
I wonder what happens if another client doesn’t follow the rules, does it “breaks” that chain? Can it affect other apps? Sounds nuts, but, well, it’s Windows we’re talking about…

Thanks! I’ll have a look.

Many thanks @lb90 , I backported the gtk+3 fix, seems to work fine, no issue anymore on my side! :slight_smile:

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.