Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clipboard causing app to freeze for 1-2 seconds #284

Open
georgi-kanchev opened this issue Feb 3, 2025 · 2 comments
Open

Clipboard causing app to freeze for 1-2 seconds #284

georgi-kanchev opened this issue Feb 3, 2025 · 2 comments

Comments

@georgi-kanchev
Copy link

I've had numerous performance issues when getting SFML's Clipboard every frame (especially on Windows (10 FPS), on Linux it wasn't as bad (70 FPS), which may be hardware related) and I mostly worked around that by caching the Clipboard on my side upon window focus. Which lead me to the following issue.

A very bad hiccup occurs when getting SFML.Window.Clipboard.Contents while the contents are not text (image pixels for example). On my Linux machine, the app freezes for about 1 or 2 seconds.

From what I saw in the binding implementation - SFML assumes the clipboard contents are always text and does the parsing all the time. Perhaps there may be an OS-dependent way to check whether the clipboard contents are text before parsing the data and skip doing so if non-textual data is present.

Minimal example:

  • Make sure to copy image pixels from some image editor software beforehand
  • Screenshot may also work
using SFML.Graphics;
using SFML.System;
using SFML.Window;

namespace MinimalExampleClipboardIssue;

public class Program
{
    public static void Main()
    {
        var window = new RenderWindow(new(1280, 720), "Clipboard Hiccup Issue");
        var rect = new RectangleShape(new Vector2f(200, 200));

        window.GainedFocus += (_, _) => _ = Clipboard.Contents;

        while (window.IsOpen)
        {
            rect.Position = window.MapPixelToCoords(Mouse.GetPosition(window));
            
            window.DispatchEvents();
            window.Clear();
            window.Draw(rect);
            window.Display();
        }
    }
}
@FRex
Copy link

FRex commented Feb 3, 2025

On X Server clipboard getting is a request sent to another process to send over the data (that's why for some programs copying then closing it will remove the data and prevent you from copy pasting).

SFML waits for 1 second: https://github.com/SFML/SFML/blob/master/src/SFML/Window/Unix/ClipboardImpl.cpp#L145

I looked and SDL has similar wait (also 1 second) but also has some code to not wait again if called again (I didn't look into logic of it, I don't want to read SDL code too much if I contribute to SFML).

More info (I don't know if up to date but I assume so, X is pretty stable/legacy): https://www.uninformativ.de/blog/postings/2017-04-02/0/POSTING-en.html

@georgi-kanchev
Copy link
Author

In case anyone else comes across this (which I doubt), here is my working solution for the time being:

public string Clipboard { get; set; }

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int XInitThreadsDelegate();

bool shouldGetClipboard;

SomeInitFunction()
{
    window.GainedFocus += (_, _) => shouldGetClipboard = true;

    if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && NativeLibrary.TryLoad("libX11.so.6", out var libX11))
    {
        var funcPtr = NativeLibrary.GetExport(libX11, "XInitThreads");
        var func = Marshal.GetDelegateForFunctionPointer<XInitThreadsDelegate>(funcPtr);
        var result = func.Invoke(); // 1 should be ok, 0 fail
    }
    var thread = new Thread(() =>
    {
        while (true)
        {
            if (shouldGetClipboard)
            {
                shouldGetClipboard = false;
                Clipboard = SFML.Window.Clipboard.Contents;
            }
            Thread.Sleep(100);
        }
    });
    thread.Start();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants