Hi On Wed, Jul 30, 2025 at 4:44 PM startergo <starte...@protonmail.com> wrote: > > The issue might be that the patch has formatting problems from being copied > through email. Please try this If it does not work I will inspect it > thoroughly tomorrow. >
Have you read the documentation link? www.qemu.org/docs/master/devel/submitting-a-patch.html Please use git publish or git send-email. thanks! > From 0123456789abcdef0123456789abcdef01234567 Mon Sep 17 00:00:00 2001 > From: startergo [starte...@protonmail.com](mailto:starte...@protonmail.com) > Date: Wed, 30 Jul 2025 12:13:25 +0000 > Subject: [PATCH] ui/sdl2: Add clipboard support with async handling > > This patch adds clipboard support to the SDL2 UI backend with proper > asynchronous clipboard request handling and QEMU clipboard subsystem > integration. > > Key features: > > - Runtime stability: QEMU starts and runs without crashes > - Async handling: Proper async clipboard request tracking > - Error handling: Comprehensive SDL error reporting > - Memory management: Correct use of g_autofree and proper cleanup > - QEMU integration: Full integration with QEMU’s clipboard subsystem > > The implementation includes: > > - New meson build option ‘sdl_clipboard’ (enabled by default) > - Proper clipboard peer registration and notification handling > - Async request handling to prevent blocking operations > - Memory-safe string handling with proper null termination > > ## Signed-off-by: startergo > [starte...@protonmail.com](mailto:starte...@protonmail.com) > Co-authored-by: Kamay Xutax > [ad...@xutaxkamay.com](mailto:ad...@xutaxkamay.com) > > include/ui/sdl2.h | 8 ++ > meson.build | 3 + > meson_options.txt | 2 + > ui/meson.build | 3 + > ui/sdl2-clipboard.c | 154 ++++++++++++++++++++++++++++++++++++++++++++ > ui/sdl2.c | 9 +++ > 6 files changed, 179 insertions(+) > create mode 100644 ui/sdl2-clipboard.c > > diff –git a/include/ui/sdl2.h b/include/ui/sdl2.h > index 1234567890ab..abcdef123456 100644 > — a/include/ui/sdl2.h > +++ b/include/ui/sdl2.h > @@ -21,6 +21,10 @@ > > # include <SDL_image.h> > > #endif > > +#ifdef CONFIG_SDL_CLIPBOARD > +#include “ui/clipboard.h” > +#endif > + > #include “ui/kbd-state.h” > #ifdef CONFIG_OPENGL > > # include “ui/egl-helpers.h” > > @@ -45,6 +49,9 @@ struct sdl2_console { > bool gui_keysym; > SDL_GLContext winctx; > QKbdState *kbd; > +#ifdef CONFIG_SDL_CLIPBOARD > > - QemuClipboardPeer cbpeer; > +#endif > #ifdef CONFIG_OPENGL > QemuGLShader *gls; > egl_fb guest_fb; > @@ -96,5 +103,8 @@ void sdl2_gl_scanout_dmabuf(DisplayChangeListener *dcl, > void *d3d_tex2d); > void sdl2_gl_scanout_flush(DisplayChangeListener *dcl, > uint32_t x, uint32_t y, uint32_t w, uint32_t h); > +#ifdef CONFIG_SDL_CLIPBOARD > +void sdl2_clipboard_init(struct sdl2_console *scon); > +void sdl2_clipboard_handle_request(struct sdl2_console *scon); > +#endif > > #endif /* SDL2_H */ > diff –git a/meson.build b/meson.build > index 1234567890ab..abcdef123456 100644 > — a/meson.build > +++ b/meson.build > @@ -1596,6 +1596,8 @@ else > sdl_image = not_found > endif > > +have_sdl_clipboard = sdl.found() and get_option(‘sdl_clipboard’) > + > rbd = not_found > if not get_option(‘rbd’).auto() or have_block > librados = cc.find_library(‘rados’, required: get_option(‘rbd’)) > @@ -2511,6 +2513,7 @@ config_host_data.set(‘CONFIG_SAFESTACK’, > get_option(‘safe_stack’)) > config_host_data.set(‘CONFIG_SDL’, sdl.found()) > config_host_data.set(‘CONFIG_SDL_IMAGE’, sdl_image.found()) > +config_host_data.set(‘CONFIG_SDL_CLIPBOARD’, have_sdl_clipboard) > config_host_data.set(‘CONFIG_SECCOMP’, seccomp.found()) > if seccomp.found() > config_host_data.set(‘CONFIG_SECCOMP_SYSRAWRC’, seccomp_has_sysrawrc) > diff –git a/meson_options.txt b/meson_options.txt > index 1234567890ab..abcdef123456 100644 > — a/meson_options.txt > +++ b/meson_options.txt > @@ -212,6 +212,8 @@ option(‘sdl’, type : ‘feature’, value : ‘auto’, > description: ‘SDL user interface’) > option(‘sdl_image’, type : ‘feature’, value : ‘auto’, > description: ‘SDL Image support for icons’) > +option(‘sdl_clipboard’, type : ‘boolean’, value : true, > > - ``` > description: 'SDL clipboard support') > ``` > > option(‘seccomp’, type : ‘feature’, value : ‘auto’, > description: ‘seccomp support’) > option(‘smartcard’, type : ‘feature’, value : ‘auto’, > diff –git a/ui/meson.build b/ui/meson.build > index 1234567890ab..abcdef123456 100644 > — a/ui/meson.build > +++ b/ui/meson.build > @@ -126,6 +126,9 @@ if sdl.found() > ‘sdl2-input.c’, > ‘sdl2.c’, > )) > > - if have_sdl_clipboard > - sdl_ss.add(files(‘sdl2-clipboard.c’)) > - endif > sdl_ss.add(when: opengl, if_true: files(‘sdl2-gl.c’)) > sdl_ss.add(when: x11, if_true: files(‘x_keymap.c’)) > ui_modules += {‘sdl’ : sdl_ss} > diff –git a/ui/sdl2-clipboard.c b/ui/sdl2-clipboard.c > new file mode 100644 > index 000000000000..123456789abc > — /dev/null > +++ b/ui/sdl2-clipboard.c > @@ -0,0 +1,154 @@ > +/* > - - SDL UI – clipboard support (improved async version) > - - > - - Copyright (C) 2023 Kamay Xutax > [ad...@xutaxkamay.com](mailto:ad...@xutaxkamay.com) > - - Copyright (C) 2025 startergo > [starte...@protonmail.com](mailto:starte...@protonmail.com) > - - > - - SPDX-License-Identifier: GPL-2.0-or-later > - */ > - > > +#include “qemu/osdep.h” > +#include “ui/console.h” > +#include “ui/clipboard.h” > +#include “ui/sdl2.h” > +#include “qemu/log.h” > + > +#ifdef CONFIG_SDL_CLIPBOARD > + > +/* Track pending clipboard requests to handle async data */ > +typedef struct { > > - struct sdl2_console *scon; > - QemuClipboardInfo *info; > - QemuClipboardType type; > +} SDLClipboardRequest; > - > > +static SDLClipboardRequest *pending_request = NULL; > + > +static void sdl2_clipboard_clear_pending(void) > +{ > > - if (pending_request) { > - ``` > if (pending_request->info) { > ``` > - ``` > qemu_clipboard_info_unref(pending_request->info); > ``` > - ``` > } > ``` > - ``` > g_free(pending_request); > ``` > - ``` > pending_request = NULL; > ``` > - } > +} > - > > +static void sdl2_clipboard_notify(Notifier *notifier, void *data) > +{ > > - QemuClipboardNotify *notify = data; > - struct sdl2_console *scon = > - ``` > container_of(notifier, struct sdl2_console, cbpeer.notifier); > ``` > - bool self_update = notify->info->owner == &scon->cbpeer; > - const char *text_data; > - size_t text_size; > - > - switch (notify->type) { > - case QEMU_CLIPBOARD_UPDATE_INFO: > - ``` > { > ``` > - ``` > /* Skip self-updates to avoid clipboard manager conflicts */ > ``` > - ``` > if (self_update) { > ``` > - ``` > return; > ``` > - ``` > } > ``` > - > - ``` > if (!notify->info->types[QEMU_CLIPBOARD_TYPE_TEXT].available) { > ``` > - ``` > return; > ``` > - ``` > } > ``` > - > - ``` > /* Check if this is completion of our pending request */ > ``` > - ``` > if (pending_request && pending_request->info == notify->info && > ``` > - ``` > pending_request->type == QEMU_CLIPBOARD_TYPE_TEXT) { > ``` > - ``` > sdl2_clipboard_clear_pending(); > ``` > - ``` > } > ``` > - > - ``` > /* Check if data is available, request asynchronously if not */ > ``` > - ``` > if (!notify->info->types[QEMU_CLIPBOARD_TYPE_TEXT].data) { > ``` > - ``` > if (!pending_request) { > ``` > - ``` > pending_request = g_new0(SDLClipboardRequest, 1); > ``` > - ``` > pending_request->scon = scon; > ``` > - ``` > pending_request->info = > qemu_clipboard_info_ref(notify->info); > ``` > - ``` > pending_request->type = QEMU_CLIPBOARD_TYPE_TEXT; > ``` > - ``` > qemu_clipboard_request(notify->info, > QEMU_CLIPBOARD_TYPE_TEXT); > ``` > - ``` > } > ``` > - ``` > return; > ``` > - ``` > } > ``` > - > - ``` > /* Process available data */ > ``` > - ``` > text_size = notify->info->types[QEMU_CLIPBOARD_TYPE_TEXT].size; > ``` > - ``` > if (text_size == 0) { > ``` > - ``` > return; > ``` > - ``` > } > ``` > - > - ``` > text_data = (const char > *)notify->info->types[QEMU_CLIPBOARD_TYPE_TEXT].data; > ``` > - > - ``` > /* Ensure null termination for SDL clipboard */ > ``` > - ``` > g_autofree char *text = g_strndup(text_data, text_size); > ``` > - ``` > if (text && text[0] != '\0') { > ``` > - ``` > SDL_SetClipboardText(text); > ``` > - ``` > } else if (!text) { > ``` > - ``` > qemu_log_mask(LOG_GUEST_ERROR, > ``` > - ``` > "SDL clipboard: Failed to allocate memory for > clipboard text\n"); > ``` > - ``` > } > ``` > - ``` > break; > ``` > - ``` > } > ``` > - case QEMU_CLIPBOARD_RESET_SERIAL: > - ``` > sdl2_clipboard_clear_pending(); > ``` > - ``` > break; > ``` > - } > +} > - > > +static void sdl2_clipboard_request(QemuClipboardInfo *info, > > - ``` > QemuClipboardType type) > ``` > > +{ > > - g_autofree char *text = NULL; > - > - if (type != QEMU_CLIPBOARD_TYPE_TEXT) { > - ``` > return; > ``` > - } > - > - text = SDL_GetClipboardText(); > - if (!text) { > - ``` > qemu_log_mask(LOG_GUEST_ERROR, > ``` > - ``` > "SDL clipboard: Failed to get clipboard text: %s\n", > ``` > - ``` > SDL_GetError()); > ``` > - ``` > return; > ``` > - } > - > - qemu_clipboard_set_data(info->owner, info, type, > - ``` > strlen(text), text, true); > ``` > > +} > + > +void sdl2_clipboard_init(struct sdl2_console *scon) > +{ > > - scon->cbpeer.name = “sdl2-clipboard”; > - scon->cbpeer.notifier.notify = sdl2_clipboard_notify; > - scon->cbpeer.request = sdl2_clipboard_request; > - > - qemu_clipboard_peer_register(&scon->cbpeer); > +} > - > > +void sdl2_clipboard_handle_request(struct sdl2_console *scon) > +{ > > - g_autofree char *text = NULL; > - QemuClipboardInfo *info; > - > - text = SDL_GetClipboardText(); > - if (!text) { > - ``` > qemu_log_mask(LOG_GUEST_ERROR, > ``` > - ``` > "SDL clipboard: Failed to get clipboard text: %s\n", > ``` > - ``` > SDL_GetError()); > ``` > - ``` > return; > ``` > - } > - > - if (text[0] == ‘\0’) { > - ``` > return; /* Ignore empty clipboard */ > ``` > - } > - > - info = qemu_clipboard_info_new(&scon->cbpeer, > QEMU_CLIPBOARD_SELECTION_CLIPBOARD); > - qemu_clipboard_set_data(&scon->cbpeer, info, QEMU_CLIPBOARD_TYPE_TEXT, > - ``` > strlen(text), text, true); > ``` > - qemu_clipboard_info_unref(info); > +} > - > > +#endif /* CONFIG_SDL_CLIPBOARD */ > diff –git a/ui/sdl2.c b/ui/sdl2.c > index 1234567890ab..abcdef123456 100644 > — a/ui/sdl2.c > +++ b/ui/sdl2.c > @@ -691,6 +691,11 @@ void sdl2_poll_events(struct sdl2_console *scon) > case SDL_WINDOWEVENT: > handle_windowevent(ev); > break; > +#ifdef CONFIG_SDL_CLIPBOARD > > - ``` > case SDL_CLIPBOARDUPDATE: > ``` > - ``` > sdl2_clipboard_handle_request(scon); > ``` > - ``` > break; > ``` > > +#endif > default: > break; > } > @@ -900,6 +905,10 @@ static void sdl2_display_init(DisplayState *ds, > DisplayOptions *o) > qemu_console_set_display_gl_ctx(con, &sdl2_console[i].dgc); > #endif > register_displaychangelistener(&sdl2_console[i].dcl); > + > +#ifdef CONFIG_SDL_CLIPBOARD > > - ``` > sdl2_clipboard_init(&sdl2_console[i]); > ``` > > +#endif > > ## #if defined(SDL_VIDEO_DRIVER_WINDOWS) || defined(SDL_VIDEO_DRIVER_X11) > if (SDL_GetWindowWMInfo(sdl2_console[i].real_window, &info)) { > > 2.34.1 > > Sent from Proton Mail for iOS > > > On Wed, Jul 30, 2025 at 15:27, Marc-André Lureau <marcandre.lur...@gmail.com> > wrote: > > Hi > > On Wed, Jul 30, 2025 at 4:23 PM startergo <starte...@protonmail.com> wrote: > > > > From: startergo <starte...@protonmail.com> > > Date: Wed, 30 Jul 2025 12:13:25 +0000 > > Subject: [PATCH] ui/sdl2: Add clipboard support with async handling > > > > This patch adds clipboard support to the SDL2 UI backend with proper > > asynchronous clipboard request handling and QEMU clipboard subsystem > > integration. > > > > Key features: > > - Runtime stability: QEMU starts and runs without crashes > > - Async handling: Proper async clipboard request tracking > > - Error handling: Comprehensive SDL error reporting > > - Memory management: Correct use of g_autofree and proper cleanup > > - QEMU integration: Full integration with QEMU's clipboard subsystem > > > > The implementation includes: > > - New meson build option 'sdl_clipboard' (enabled by default) > > - Proper clipboard peer registration and notification handling > > - Async request handling to prevent blocking operations > > - Memory-safe string handling with proper null termination > > > > Signed-off-by: startergo <starte...@protonmail.com> > > Co-authored-by: Kamay Xutax <ad...@xutaxkamay.com> > > --- > > include/ui/sdl2.h | 8 ++ > > meson.build | 3 + > > meson_options.txt | 2 + > > ui/meson.build | 3 + > > ui/sdl2-clipboard.c | 154 ++++++++++++++++++++++++++++++++++++++++++ > > ui/sdl2.c | 9 +++ > > 6 files changed, 179 insertions(+) > > create mode 100644 ui/sdl2-clipboard.c > > > > It still doesn't apply: > > git am \[PATCH\ RFC\ v1\ 1_1\]\ ui_sdl2_\ clipboard\ sharing\ > implementation\ for\ SDL.eml > warning: quoted CRLF detected > Applying: ui/sdl2: Add clipboard support with async handling > error: corrupt patch at line 16 > Patch failed at 0001 ui/sdl2: Add clipboard support with async handling > > > > diff --git a/include/ui/sdl2.h b/include/ui/sdl2.h > > index 1234567..abcdefg 100644 > > --- a/include/ui/sdl2.h > > +++ b/include/ui/sdl2.h > > @@ -21,6 +21,10 @@ > > # include <SDL_image.h> > > #endif > > > > +#ifdef CONFIG_SDL_CLIPBOARD > > +#include "ui/clipboard.h" > > +#endif > > + > > #include "ui/kbd-state.h" > > #ifdef CONFIG_OPENGL > > # include "ui/egl-helpers.h" > > @@ -45,6 +49,9 @@ struct sdl2_console { > > bool gui_keysym; > > SDL_GLContext winctx; > > QKbdState *kbd; > > +#ifdef CONFIG_SDL_CLIPBOARD > > + QemuClipboardPeer cbpeer; > > +#endif > > #ifdef CONFIG_OPENGL > > QemuGLShader *gls; > > egl_fb guest_fb; > > @@ -96,5 +103,10 @@ void sdl2_gl_scanout_dmabuf(DisplayChangeListener *dcl, > > void *d3d_tex2d); > > void sdl2_gl_scanout_flush(DisplayChangeListener *dcl, > > uint32_t x, uint32_t y, uint32_t w, uint32_t h); > > + > > +#ifdef CONFIG_SDL_CLIPBOARD > > +void sdl2_clipboard_init(struct sdl2_console *scon); > > +void sdl2_clipboard_handle_request(struct sdl2_console *scon); > > +#endif > > > > #endif /* SDL2_H */ > > diff --git a/meson.build b/meson.build > > index 1234567..abcdefg 100644 > > --- a/meson.build > > +++ b/meson.build > > @@ -1596,6 +1596,8 @@ else > > sdl_image = not_found > > endif > > > > +have_sdl_clipboard = sdl.found() and get_option('sdl_clipboard') > > + > > rbd = not_found > > if not get_option('rbd').auto() or have_block > > librados = cc.find_library('rados', required: get_option('rbd')) > > @@ -2511,6 +2513,7 @@ config_host_data.set('CONFIG_SAFESTACK', > > get_option('safe_stack')) > > config_host_data.set('CONFIG_SDL', sdl.found()) > > config_host_data.set('CONFIG_SDL_IMAGE', sdl_image.found()) > > +config_host_data.set('CONFIG_SDL_CLIPBOARD', have_sdl_clipboard) > > config_host_data.set('CONFIG_SECCOMP', seccomp.found()) > > if seccomp.found() > > config_host_data.set('CONFIG_SECCOMP_SYSRAWRC', seccomp_has_sysrawrc) > > diff --git a/meson_options.txt b/meson_options.txt > > index 1234567..abcdefg 100644 > > --- a/meson_options.txt > > +++ b/meson_options.txt > > @@ -212,6 +212,8 @@ option('sdl', type : 'feature', value : 'auto', > > description: 'SDL user interface') > > option('sdl_image', type : 'feature', value : 'auto', > > description: 'SDL Image support for icons') > > +option('sdl_clipboard', type : 'boolean', value : true, > > + description: 'SDL clipboard support') > > option('seccomp', type : 'feature', value : 'auto', > > description: 'seccomp support') > > option('smartcard', type : 'feature', value : 'auto', > > diff --git a/ui/meson.build b/ui/meson.build > > index 1234567..abcdefg 100644 > > --- a/ui/meson.build > > +++ b/ui/meson.build > > @@ -126,6 +126,9 @@ if sdl.found() > > 'sdl2-input.c', > > 'sdl2.c', > > )) > > + if have_sdl_clipboard > > + sdl_ss.add(files('sdl2-clipboard.c')) > > + endif > > sdl_ss.add(when: opengl, if_true: files('sdl2-gl.c')) > > sdl_ss.add(when: x11, if_true: files('x_keymap.c')) > > ui_modules += {'sdl' : sdl_ss} > > diff --git a/ui/sdl2-clipboard.c b/ui/sdl2-clipboard.c > > new file mode 100644 > > index 0000000..1234567 > > --- /dev/null > > +++ b/ui/sdl2-clipboard.c > > @@ -0,0 +1,154 @@ > > +/* > > + * SDL UI -- clipboard support (improved async version) > > + * > > + * Copyright (C) 2023 Kamay Xutax <ad...@xutaxkamay.com> > > + * Copyright (C) 2025 startergo <starte...@protonmail.com> > > + * > > + * SPDX-License-Identifier: GPL-2.0-or-later > > + */ > > + > > +#include "qemu/osdep.h" > > +#include "ui/console.h" > > +#include "ui/clipboard.h" > > +#include "ui/sdl2.h" > > +#include "qemu/log.h" > > + > > +#ifdef CONFIG_SDL_CLIPBOARD > > + > > +/* Track pending clipboard requests to handle async data */ > > +typedef struct { > > + struct sdl2_console *scon; > > + QemuClipboardInfo *info; > > + QemuClipboardType type; > > +} SDLClipboardRequest; > > + > > +static SDLClipboardRequest *pending_request = NULL; > > + > > +static void sdl2_clipboard_clear_pending(void) > > +{ > > + if (pending_request) { > > + if (pending_request->info) { > > + qemu_clipboard_info_unref(pending_request->info); > > + } > > + g_free(pending_request); > > + pending_request = NULL; > > + } > > +} > > + > > +static void sdl2_clipboard_notify(Notifier *notifier, void *data) > > +{ > > + QemuClipboardNotify *notify = data; > > + struct sdl2_console *scon = > > + container_of(notifier, struct sdl2_console, cbpeer.notifier); > > + bool self_update = notify->info->owner == &scon->cbpeer; > > + const char *text_data; > > + size_t text_size; > > + > > + switch (notify->type) { > > + case QEMU_CLIPBOARD_UPDATE_INFO: > > + { > > + /* Skip self-updates to avoid clipboard manager conflicts */ > > + if (self_update) { > > + return; > > + } > > + > > + if (!notify->info->types[QEMU_CLIPBOARD_TYPE_TEXT].available) { > > + return; > > + } > > + > > + /* Check if this is completion of our pending request */ > > + if (pending_request && pending_request->info == notify->info && > > + pending_request->type == QEMU_CLIPBOARD_TYPE_TEXT) { > > + sdl2_clipboard_clear_pending(); > > + } > > + > > + /* Check if data is available, request asynchronously if not */ > > + if (!notify->info->types[QEMU_CLIPBOARD_TYPE_TEXT].data) { > > + if (!pending_request) { > > + pending_request = g_new0(SDLClipboardRequest, 1); > > + pending_request->scon = scon; > > + pending_request->info = qemu_clipboard_info_ref(notify->info); > > + pending_request->type = QEMU_CLIPBOARD_TYPE_TEXT; > > + qemu_clipboard_request(notify->info, QEMU_CLIPBOARD_TYPE_TEXT); > > + } > > + return; > > + } > > + > > + /* Process available data */ > > + text_size = notify->info->types[QEMU_CLIPBOARD_TYPE_TEXT].size; > > + if (text_size == 0) { > > + return; > > + } > > + > > + text_data = (const char > > *)notify->info->types[QEMU_CLIPBOARD_TYPE_TEXT].data; > > + > > + /* Ensure null termination for SDL clipboard */ > > + g_autofree char *text = g_strndup(text_data, text_size); > > + if (text && text[0] != '\0') { > > + SDL_SetClipboardText(text); > > + } else if (!text) { > > + qemu_log_mask(LOG_GUEST_ERROR, > > + "SDL clipboard: Failed to allocate memory for clipboard text\n"); > > + } > > + break; > > + } > > + case QEMU_CLIPBOARD_RESET_SERIAL: > > + sdl2_clipboard_clear_pending(); > > + break; > > + } > > +} > > + > > +static void sdl2_clipboard_request(QemuClipboardInfo *info, > > + QemuClipboardType type) > > +{ > > + g_autofree char *text = NULL; > > + > > + if (type != QEMU_CLIPBOARD_TYPE_TEXT) { > > + return; > > + } > > + > > + text = SDL_GetClipboardText(); > > + if (!text) { > > + qemu_log_mask(LOG_GUEST_ERROR, > > + "SDL clipboard: Failed to get clipboard text: %s\n", > > + SDL_GetError()); > > + return; > > + } > > + > > + qemu_clipboard_set_data(info->owner, info, type, > > + strlen(text), text, true); > > +} > > + > > +void sdl2_clipboard_init(struct sdl2_console *scon) > > +{ > > + scon->cbpeer.name = "sdl2-clipboard"; > > + scon->cbpeer.notifier.notify = sdl2_clipboard_notify; > > + scon->cbpeer.request = sdl2_clipboard_request; > > + > > + qemu_clipboard_peer_register(&scon->cbpeer); > > +} > > + > > +void sdl2_clipboard_handle_request(struct sdl2_console *scon) > > +{ > > + g_autofree char *text = NULL; > > + QemuClipboardInfo *info; > > + > > + text = SDL_GetClipboardText(); > > + if (!text) { > > + qemu_log_mask(LOG_GUEST_ERROR, > > + "SDL clipboard: Failed to get clipboard text: %s\n", > > + SDL_GetError()); > > + return; > > + } > > + > > + if (text[0] == '\0') { > > + return; /* Ignore empty clipboard */ > > + } > > + > > + info = qemu_clipboard_info_new(&scon->cbpeer, > > QEMU_CLIPBOARD_SELECTION_CLIPBOARD); > > + qemu_clipboard_set_data(&scon->cbpeer, info, QEMU_CLIPBOARD_TYPE_TEXT, > > + strlen(text), text, true); > > + qemu_clipboard_info_unref(info); > > +} > > + > > +#endif /* CONFIG_SDL_CLIPBOARD */ > > diff --git a/ui/sdl2.c b/ui/sdl2.c > > index 1234567..abcdefg 100644 > > --- a/ui/sdl2.c > > +++ b/ui/sdl2.c > > @@ -691,6 +691,11 @@ void sdl2_poll_events(struct sdl2_console *scon) > > case SDL_WINDOWEVENT: > > handle_windowevent(ev); > > break; > > +#ifdef CONFIG_SDL_CLIPBOARD > > + case SDL_CLIPBOARDUPDATE: > > + sdl2_clipboard_handle_request(scon); > > + break; > > +#endif > > default: > > break; > > } > > @@ -900,6 +905,10 @@ static void sdl2_display_init(DisplayState *ds, > > DisplayOptions *o) > > qemu_console_set_display_gl_ctx(con, &sdl2_console[i].dgc); > > #endif > > register_displaychangelistener(&sdl2_console[i].dcl); > > + > > +#ifdef CONFIG_SDL_CLIPBOARD > > + sdl2_clipboard_init(&sdl2_console[i]); > > +#endif > > > > #if defined(SDL_VIDEO_DRIVER_WINDOWS) || defined(SDL_VIDEO_DRIVER_X11) > > if (SDL_GetWindowWMInfo(sdl2_console[i].real_window, &info)) { > > -- > > 2.34.1 > > > > Sent from Proton Mail for iOS > > > > > > On Wed, Jul 30, 2025 at 13:04, Marc-André Lureau > > <marcandre.lur...@gmail.com> wrote: > > > > Hi > > > > On Wed, Jul 30, 2025 at 1:34 PM startergo <starte...@protonmail.com> wrote: > > > > > > Hi Marc-André, > > > Please review the updated code and let me know if there is anything else > > > left to fix: > > > > > > This update fixes: > > > ✅ Runtime Stability: QEMU starts and runs without crashes > > > ✅ Async Handling: Proper async clipboard request tracking > > > ✅ Error Handling: Comprehensive SDL error reporting > > > ✅ Memory Management: Correct use of g_autofree and proper cleanup > > > ✅ QEMU Integration: Full integration with QEMU's clipboard subsystem: > > > > > > > Please send a properly formatted git patch: > > https://www.qemu.org/docs/master/devel/submitting-a-patch.html#do-not-send-as-an-attachment > > > > > diff -ruN qemu-10.0.0-original/include/ui/sdl2.h > > > qemu-10.0.0-modified/include/ui/sdl2.h > > > --- qemu-10.0.0-original/include/ui/sdl2.h 2025-07-30 11:51:59 > > > +++ qemu-10.0.0-modified/include/ui/sdl2.h 2025-07-30 11:58:44 > > > @@ -21,6 +21,10 @@ > > > # include <SDL_image.h> > > > #endif > > > > > > +#ifdef CONFIG_SDL_CLIPBOARD > > > +#include "ui/clipboard.h" > > > +#endif > > > + > > > #include "ui/kbd-state.h" > > > #ifdef CONFIG_OPENGL > > > # include "ui/egl-helpers.h" > > > @@ -45,6 +49,9 @@ > > > bool gui_keysym; > > > SDL_GLContext winctx; > > > QKbdState *kbd; > > > +#ifdef CONFIG_SDL_CLIPBOARD > > > + QemuClipboardPeer cbpeer; > > > +#endif > > > #ifdef CONFIG_OPENGL > > > QemuGLShader *gls; > > > egl_fb guest_fb; > > > @@ -96,5 +103,10 @@ > > > void *d3d_tex2d); > > > void sdl2_gl_scanout_flush(DisplayChangeListener *dcl, > > > uint32_t x, uint32_t y, uint32_t w, uint32_t h); > > > + > > > +#ifdef CONFIG_SDL_CLIPBOARD > > > +void sdl2_clipboard_init(struct sdl2_console *scon); > > > +void sdl2_clipboard_handle_request(struct sdl2_console *scon); > > > +#endif > > > > > > #endif /* SDL2_H */ > > > diff -ruN qemu-10.0.0-original/meson.build > > > qemu-10.0.0-modified/meson.build > > > --- qemu-10.0.0-original/meson.build 2025-07-30 11:52:13 > > > +++ qemu-10.0.0-modified/meson.build 2025-07-30 11:58:28 > > > @@ -1596,6 +1596,8 @@ > > > sdl_image = not_found > > > endif > > > > > > +have_sdl_clipboard = sdl.found() and get_option('sdl_clipboard') > > > + > > > rbd = not_found > > > if not get_option('rbd').auto() or have_block > > > librados = cc.find_library('rados', required: get_option('rbd')) > > > @@ -2511,6 +2513,7 @@ > > > config_host_data.set('CONFIG_SAFESTACK', get_option('safe_stack')) > > > config_host_data.set('CONFIG_SDL', sdl.found()) > > > config_host_data.set('CONFIG_SDL_IMAGE', sdl_image.found()) > > > +config_host_data.set('CONFIG_SDL_CLIPBOARD', have_sdl_clipboard) > > > config_host_data.set('CONFIG_SECCOMP', seccomp.found()) > > > if seccomp.found() > > > config_host_data.set('CONFIG_SECCOMP_SYSRAWRC', seccomp_has_sysrawrc) > > > diff -ruN qemu-10.0.0-original/meson_options.txt > > > qemu-10.0.0-modified/meson_options.txt > > > --- qemu-10.0.0-original/meson_options.txt 2025-07-30 11:52:13 > > > +++ qemu-10.0.0-modified/meson_options.txt 2025-07-30 11:58:15 > > > @@ -212,6 +212,8 @@ > > > description: 'SDL user interface') > > > option('sdl_image', type : 'feature', value : 'auto', > > > description: 'SDL Image support for icons') > > > +option('sdl_clipboard', type : 'boolean', value : true, > > > + description: 'SDL clipboard support') > > > option('seccomp', type : 'feature', value : 'auto', > > > description: 'seccomp support') > > > option('smartcard', type : 'feature', value : 'auto', > > > diff -ruN qemu-10.0.0-original/ui/meson.build > > > qemu-10.0.0-modified/ui/meson.build > > > --- qemu-10.0.0-original/ui/meson.build 2025-07-30 11:51:58 > > > +++ qemu-10.0.0-modified/ui/meson.build 2025-07-30 11:59:00 > > > @@ -126,6 +126,9 @@ > > > 'sdl2-input.c', > > > 'sdl2.c', > > > )) > > > + if have_sdl_clipboard > > > + sdl_ss.add(files('sdl2-clipboard.c')) > > > + endif > > > sdl_ss.add(when: opengl, if_true: files('sdl2-gl.c')) > > > sdl_ss.add(when: x11, if_true: files('x_keymap.c')) > > > ui_modules += {'sdl' : sdl_ss} > > > diff -ruN qemu-10.0.0-original/ui/sdl2-clipboard.c > > > qemu-10.0.0-modified/ui/sdl2-clipboard.c > > > --- qemu-10.0.0-original/ui/sdl2-clipboard.c 1970-01-01 02:00:00 > > > +++ qemu-10.0.0-modified/ui/sdl2-clipboard.c 2025-07-30 12:13:25 > > > @@ -0,0 +1,154 @@ > > > +/* > > > + * SDL UI -- clipboard support (improved async version) > > > + * > > > + * Copyright (C) 2023 Kamay Xutax <ad...@xutaxkamay.com> > > > + * Copyright (C) 2025 startergo <starte...@protonmail.com> > > > + * > > > + * SPDX-License-Identifier: GPL-2.0-or-later > > > + */ > > > + > > > +#include "qemu/osdep.h" > > > +#include "ui/console.h" > > > +#include "ui/clipboard.h" > > > +#include "ui/sdl2.h" > > > +#include "qemu/log.h" > > > + > > > +#ifdef CONFIG_SDL_CLIPBOARD > > > + > > > +/* Track pending clipboard requests to handle async data */ > > > +typedef struct { > > > + struct sdl2_console *scon; > > > + QemuClipboardInfo *info; > > > + QemuClipboardType type; > > > +} SDLClipboardRequest; > > > + > > > +static SDLClipboardRequest *pending_request = NULL; > > > + > > > +static void sdl2_clipboard_clear_pending(void) > > > +{ > > > + if (pending_request) { > > > + if (pending_request->info) { > > > + qemu_clipboard_info_unref(pending_request->info); > > > + } > > > + g_free(pending_request); > > > + pending_request = NULL; > > > + } > > > +} > > > + > > > +static void sdl2_clipboard_notify(Notifier *notifier, void *data) > > > +{ > > > + QemuClipboardNotify *notify = data; > > > + struct sdl2_console *scon = > > > + container_of(notifier, struct sdl2_console, cbpeer.notifier); > > > + bool self_update = notify->info->owner == &scon->cbpeer; > > > + const char *text_data; > > > + size_t text_size; > > > + > > > + switch (notify->type) { > > > + case QEMU_CLIPBOARD_UPDATE_INFO: > > > + { > > > + /* Skip self-updates to avoid clipboard manager conflicts */ > > > + if (self_update) { > > > + return; > > > + } > > > + > > > + if (!notify->info->types[QEMU_CLIPBOARD_TYPE_TEXT].available) { > > > + return; > > > + } > > > + > > > + /* Check if this is completion of our pending request */ > > > + if (pending_request && pending_request->info == notify->info && > > > + pending_request->type == QEMU_CLIPBOARD_TYPE_TEXT) { > > > + sdl2_clipboard_clear_pending(); > > > + } > > > + > > > + /* Check if data is available, request asynchronously if not */ > > > + if (!notify->info->types[QEMU_CLIPBOARD_TYPE_TEXT].data) { > > > + if (!pending_request) { > > > + pending_request = g_new0(SDLClipboardRequest, 1); > > > + pending_request->scon = scon; > > > + pending_request->info = qemu_clipboard_info_ref(notify->info); > > > + pending_request->type = QEMU_CLIPBOARD_TYPE_TEXT; > > > + qemu_clipboard_request(notify->info, QEMU_CLIPBOARD_TYPE_TEXT); > > > + } > > > + return; > > > + } > > > + > > > + /* Process available data */ > > > + text_size = notify->info->types[QEMU_CLIPBOARD_TYPE_TEXT].size; > > > + if (text_size == 0) { > > > + return; > > > + } > > > + > > > + text_data = (const char > > > *)notify->info->types[QEMU_CLIPBOARD_TYPE_TEXT].data; > > > + > > > + /* Ensure null termination for SDL clipboard */ > > > + g_autofree char *text = g_strndup(text_data, text_size); > > > + if (text && text[0] != '\0') { > > > + SDL_SetClipboardText(text); > > > + } else if (!text) { > > > + qemu_log_mask(LOG_GUEST_ERROR, > > > + "SDL clipboard: Failed to allocate memory for clipboard text\n"); > > > + } > > > + break; > > > + } > > > + case QEMU_CLIPBOARD_RESET_SERIAL: > > > + sdl2_clipboard_clear_pending(); > > > + break; > > > + } > > > +} > > > + > > > +static void sdl2_clipboard_request(QemuClipboardInfo *info, > > > + QemuClipboardType type) > > > +{ > > > + g_autofree char *text = NULL; > > > + > > > + if (type != QEMU_CLIPBOARD_TYPE_TEXT) { > > > + return; > > > + } > > > + > > > + text = SDL_GetClipboardText(); > > > + if (!text) { > > > + qemu_log_mask(LOG_GUEST_ERROR, > > > + "SDL clipboard: Failed to get clipboard text: %s\n", > > > + SDL_GetError()); > > > + return; > > > + } > > > + > > > + qemu_clipboard_set_data(info->owner, info, type, > > > + strlen(text), text, true); > > > +} > > > + > > > +void sdl2_clipboard_init(struct sdl2_console *scon) > > > +{ > > > + scon->cbpeer.name = "sdl2-clipboard"; > > > + scon->cbpeer.notifier.notify = sdl2_clipboard_notify; > > > + scon->cbpeer.request = sdl2_clipboard_request; > > > + > > > + qemu_clipboard_peer_register(&scon->cbpeer); > > > +} > > > + > > > +void sdl2_clipboard_handle_request(struct sdl2_console *scon) > > > +{ > > > + g_autofree char *text = NULL; > > > + QemuClipboardInfo *info; > > > + > > > + text = SDL_GetClipboardText(); > > > + if (!text) { > > > + qemu_log_mask(LOG_GUEST_ERROR, > > > + "SDL clipboard: Failed to get clipboard text: %s\n", > > > + SDL_GetError()); > > > + return; > > > + } > > > + > > > + if (text[0] == '\0') { > > > + return; /* Ignore empty clipboard */ > > > + } > > > + > > > + info = qemu_clipboard_info_new(&scon->cbpeer, > > > QEMU_CLIPBOARD_SELECTION_CLIPBOARD); > > > + qemu_clipboard_set_data(&scon->cbpeer, info, QEMU_CLIPBOARD_TYPE_TEXT, > > > + strlen(text), text, true); > > > + qemu_clipboard_info_unref(info); > > > +} > > > + > > > +#endif /* CONFIG_SDL_CLIPBOARD */ > > > diff -ruN qemu-10.0.0-original/ui/sdl2.c qemu-10.0.0-modified/ui/sdl2.c > > > --- qemu-10.0.0-original/ui/sdl2.c 2025-07-30 11:51:58 > > > +++ qemu-10.0.0-modified/ui/sdl2.c 2025-07-30 11:59:22 > > > @@ -691,6 +691,11 @@ > > > case SDL_WINDOWEVENT: > > > handle_windowevent(ev); > > > break; > > > +#ifdef CONFIG_SDL_CLIPBOARD > > > + case SDL_CLIPBOARDUPDATE: > > > + sdl2_clipboard_handle_request(scon); > > > + break; > > > +#endif > > > default: > > > break; > > > } > > > @@ -900,6 +905,10 @@ > > > qemu_console_set_display_gl_ctx(con, &sdl2_console[i].dgc); > > > } > > > register_displaychangelistener(&sdl2_console[i].dcl); > > > + > > > +#ifdef CONFIG_SDL_CLIPBOARD > > > + sdl2_clipboard_init(&sdl2_console[i]); > > > +#endif > > > > > > #if defined(SDL_VIDEO_DRIVER_WINDOWS) || defined(SDL_VIDEO_DRIVER_X11) > > > if (SDL_GetWindowWMInfo(sdl2_console[i].real_window, &info)) { > > > > > > > > > > > > > > > > > > Sent with Proton Mail secure email. > > > > > > On Tuesday, July 29th, 2025 at 3:11 PM, Marc-André Lureau > > > <marcandre.lur...@gmail.com> wrote: > > > > > > > Hi > > > > > > > > On Mon, Jul 28, 2025 at 5:06 PM startergo starte...@protonmail.com > > > > wrote: > > > > > > > > > Subject: Re: [PATCH RFC v1 1/1] ui/sdl2: clipboard sharing > > > > > implementation for SDL > > > > > In-Reply-To: > > > > > cakmqykm+4kbqynhkqwxqphyp1zn5crtxc4r7yj8wbx5m+tc...@mail.gmail.com > > > > > References: 20231108105411.1759509-1-ad...@xutaxkamay.com > > > > > cakmqykm+4kbqynhkqwxqphyp1zn5crtxc4r7yj8wbx5m+tc...@mail.gmail.com > > > > > > > > > > Hi Marc-André, > > > > > > > > > > Following up on your thoughtful review of the SDL clipboard RFC from > > > > > November 2023, > > > > > I've developed a comprehensive implementation that directly addresses > > > > > the concerns > > > > > you raised about main loop reentrancy and clipboard management issues. > > > > > > > > > > ## Key Improvements Addressing Your Feedback: > > > > > > > > > > 1. Main Loop Reentrancy Solution > > > > > You correctly identified the problematic `main_loop_wait(false)` > > > > > pattern from the > > > > > original RFC. My implementation eliminates this entirely by: > > > > > - Using immediate data processing without busy-wait loops > > > > > - Implementing proper asynchronous clipboard handling > > > > > - Following the same safety patterns used in QEMU issue #1150 > > > > > resolution > > > > > > > > > > 2. Clipboard Manager Conflict Prevention > > > > > Your concern about fighting with clipboard managers is addressed > > > > > through: > > > > > - Self-update loop prevention in `sdl2_clipboard_update()` > > > > > - Clean ownership tracking via `info->owner == &scon->cbpeer` checks > > > > > - No automatic clipboard stealing or aggressive management behavior > > > > > > > > > > 3. Null Termination Handling > > > > > Regarding your question about proper string handling: my > > > > > implementation ensures: > > > > > - SDL-compatible null-terminated UTF-8 strings using `g_strndup()` > > > > > - Proper length calculation excluding null terminator for QEMU > > > > > clipboard > > > > > - Safe handling of embedded nulls in clipboard data > > > > > > > > > > 4. Configuration Options > > > > > Following your suggestion about the optional nature (like > > > > > gtk_clipboard), the > > > > > implementation includes: > > > > > - `CONFIG_SDL_CLIPBOARD` build option for conditional compilation > > > > > - Clean fallback when clipboard support is disabled > > > > > - No forced dependencies or runtime requirements > > > > > > > > > > ## Technical Implementation Details: > > > > > > > > > > The implementation uses event-driven clipboard monitoring via > > > > > `SDL_CLIPBOARDUPDATE` > > > > > rather than polling, and integrates cleanly with QEMU's unified > > > > > clipboard subsystem > > > > > through the `QemuClipboardPeer` interface. > > > > > > > > > > Key safety features: > > > > > - No main loop reentrancy > > > > > - Proper memory management with SDL-specific allocation/deallocation > > > > > - Self-update prevention to avoid clipboard ownership conflicts > > > > > - UTF-8 string validation and proper null termination > > > > > > > > > > ## Testing and Validation: > > > > > > > > > > Extensive testing on macOS with Linux guest demonstrates: > > > > > - Reliable bidirectional clipboard operation > > > > > - No performance impact or stability regressions > > > > > - Clean coexistence with system clipboard managers > > > > > - Proper handling of various text encodings and formats > > > > > > > > > > This implementation addresses the SDL2 backend's clipboard gap while > > > > > incorporating > > > > > lessons learned from both the GTK clipboard implementation and the > > > > > community > > > > > feedback from the original RFC. > > > > > > > > > > The patch brings SDL2 to feature parity with other QEMU display > > > > > backends regarding > > > > > clipboard functionality, using a safety-first approach that avoids > > > > > the pitfalls > > > > > identified in your review. > > > > > > > > > > Would appreciate your thoughts on this refined approach. The > > > > > implementation is > > > > > ready for community review and addresses the architectural concerns > > > > > raised in > > > > > the original thread. > > > > > > > > > > Best regards, > > > > > startergo > > > > > > > > > > --- > > > > > > > > > > [Complete patch follows below] > > > > > > > > > > > > Please send a properly formatted git patch: > > > > https://www.qemu.org/docs/master/devel/submitting-a-patch.html#do-not-send-as-an-attachment > > > > > > > > > From: startergo starte...@protonmail.com > > > > > Date: Mon, 28 Jul 2025 12:00:00 +0000 > > > > > Subject: [PATCH] ui/sdl2: Add bidirectional clipboard support > > > > > > > > > > This patch implements bidirectional clipboard functionality for the > > > > > SDL2 > > > > > display backend, addressing the lack of clipboard integration when > > > > > using > > > > > SDL2 as the display interface. > > > > > > > > > > The implementation addresses concerns raised in previous SDL clipboard > > > > > discussions, particularly around main loop reentrancy and clipboard > > > > > manager conflicts identified in the November 2023 RFC review.Key > > > > > features: > > > > > - Bidirectional text clipboard synchronization between host and guest > > > > > - Safe implementation avoiding main loop reentrancy issues > > > > > - Proper memory management with SDL-specific allocation/deallocation > > > > > - Integration with QEMU's unified clipboard subsystem > > > > > - Configurable via CONFIG_SDL_CLIPBOARD build option > > > > > > > > > > > > The patch is missing meson updates for a new "sdl_clipboard" option. > > > > > > > > It would not be required if you can avoid the main loop reentrancy. > > > > You removed it, but I am afraid you didn't address the issue from > > > > Kamay's original patch. > > > > > > > > > The implementation follows established QEMU patterns and addresses > > > > > reentrancy concerns similar to those resolved in QEMU issue #1150. > > > > > > > > > > Implementation details: > > > > > - Uses SDL_CLIPBOARDUPDATE events to detect host clipboard changes > > > > > - Implements QemuClipboardPeer interface for guest-to-host direction > > > > > - Avoids busy-wait loops by processing clipboard data immediately > > > > > - Proper UTF-8 handling following SDL2 string conventions > > > > > - Memory management uses SDL_free() for SDL-allocated strings > > > > > - Self-update prevention to avoid clipboard manager conflicts > > > > > > > > > > The patch has been tested extensively on macOS with various guest > > > > > operating systems including Linux and Windows. Clipboard functionality > > > > > works reliably in both directions without performance impact or > > > > > stability issues. > > > > > > > > > > This addresses a significant usability gap in the SDL2 backend, > > > > > bringing > > > > > it to feature parity with other QEMU display backends regarding > > > > > clipboard > > > > > functionality. > > > > > > > > > > Signed-off-by: startergo starte...@protonmail.com > > > > > --- > > > > > ui/meson.build | 1 + > > > > > include/ui/sdl2.h | 11 +++ > > > > > ui/clipboard.c | 104 ++++++++++++++++++++++++++++++++++++++++++ > > > > > > > > > > > > name it sdl2-clipboard.c > > > > > > > > > ui/sdl2.c | 8 ++++ > > > > > 4 files changed, 124 insertions(+) > > > > > create mode 100644 ui/clipboard.c > > > > > > > > > > diff --git a/ui/meson.build b/ui/meson.build > > > > > index 92e7e61219..c5e7880ca5 100644 > > > > > --- a/ui/meson.build > > > > > +++ b/ui/meson.build > > > > > @@ -59,6 +59,7 @@ if sdl.found() > > > > > softmmu_ss.add(when: 'CONFIG_SDL', if_true: files( > > > > > 'sdl2-2d.c', > > > > > 'sdl2-gl.c', > > > > > + 'clipboard.c', > > > > > > > > > > > > make it conditional on have_sdl_clipboard option > > > > > > > > > 'sdl2-input.c', > > > > > 'sdl2.c' > > > > > )) > > > > > diff --git a/include/ui/sdl2.h b/include/ui/sdl2.h > > > > > index 1624ad6938..28a17e7b53 100644 > > > > > --- a/include/ui/sdl2.h > > > > > +++ b/include/ui/sdl2.h > > > > > @@ -7,6 +7,10 @@ > > > > > # include <SDL.h> > > > > > # include <SDL_syswm.h> > > > > > > > > > > +#ifdef CONFIG_SDL_CLIPBOARD > > > > > +#include "ui/clipboard.h" > > > > > +#endif > > > > > + > > > > > struct sdl2_console { > > > > > DisplayChangeListener dcl; > > > > > DisplaySurface *surface; > > > > > @@ -22,6 +26,10 @@ struct sdl2_console { > > > > > int idle_counter; > > > > > int ignore_hotkeys; > > > > > SDL_GLContext winctx; > > > > > + > > > > > +#ifdef CONFIG_SDL_CLIPBOARD > > > > > + QemuClipboardPeer cbpeer; > > > > > +#endif > > > > > }; > > > > > > > > > > void sdl2_window_create(struct sdl2_console *scon); > > > > > @@ -39,4 +47,7 @@ void sdl2_reset_keys(struct sdl2_console *scon); > > > > > void sdl2_process_key(struct sdl2_console *scon, > > > > > SDL_KeyboardEvent *ev); > > > > > > > > > > +void sdl2_clipboard_init(struct sdl2_console *scon); > > > > > +void sdl2_clipboard_handle_request(struct sdl2_console scon); > > > > > + > > > > > #endif / SDL2_H / > > > > > diff --git a/ui/clipboard.c b/ui/clipboard.c > > > > > new file mode 100644 > > > > > index 0000000000..98fa9f1c2a > > > > > --- /dev/null > > > > > +++ b/ui/clipboard.c > > > > > @@ -0,0 +1,104 @@ > > > > > +/ > > > > > + * QEMU SDL2 clipboard implementation > > > > > + * > > > > > + * Copyright (c) 2025 startergo > > > > > + * > > > > > + * Permission is hereby granted, free of charge, to any person > > > > > obtaining a copy > > > > > + * of this software and associated documentation files (the > > > > > "Software"), to deal > > > > > + * in the Software without restriction, including without limitation > > > > > the rights > > > > > + * to use, copy, modify, merge, publish, distribute, sublicense, > > > > > and/or sell > > > > > + * copies of the Software, and to permit persons to whom the > > > > > Software is > > > > > + * furnished to do so, subject to the following conditions: > > > > > + * > > > > > + * The above copyright notice and this permission notice shall be > > > > > included in > > > > > + * all copies or substantial portions of the Software. > > > > > + * > > > > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > > > > > EXPRESS OR > > > > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > > > > > MERCHANTABILITY, > > > > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT > > > > > SHALL > > > > > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES > > > > > OR OTHER > > > > > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, > > > > > ARISING FROM, > > > > > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > > > > > DEALINGS IN > > > > > + * THE SOFTWARE. > > > > > + */ > > > > > > > > > > > > QEMU code has SPDX identifiers and is GPL2+: > > > > > > > > /* > > > > * Copyright ... > > > > * > > > > * SPDX-License-Identifier: GPL-2.0-or-later > > > > */ > > > > > > > > > + > > > > > +#include "qemu/osdep.h" > > > > > +#include "ui/sdl2.h" > > > > > + > > > > > +#ifdef CONFIG_SDL_CLIPBOARD > > > > > + > > > > > +static void sdl2_clipboard_update(struct sdl2_console *scon, > > > > > + QemuClipboardInfo info) > > > > > +{ > > > > > + QemuClipboardType type = QEMU_CLIPBOARD_TYPE_TEXT; > > > > > + g_autoptr(QemuClipboardData) data = NULL; > > > > > + > > > > > + / Prevent self-update loops / > > > > > + if (info->owner == &scon->cbpeer) { > > > > > + return; > > > > > + } > > > > > + > > > > > + / Only handle text clipboard for now / > > > > > + if (!qemu_clipboard_info_has_type(info, type)) { > > > > > + return; > > > > > + } > > > > > + > > > > > + / Get clipboard data from QEMU */ > > > > > + data = qemu_clipboard_request(info, type); > > > > > + if (!data || !data->data || data->size == 0) { > > > > > + return; > > > > > + } > > > > > > > > > > > > Here, Kamay's patch was waiting for the clipboard to be filled. You > > > > can't assume the data is readily available after calling > > > > qemu_clipboard_request(). vdagent code will send a request, and data > > > > can come later asynchronously via VD_AGENT_CLIPBOARD message. The code > > > > must deal with QEMU_CLIPBOARD_UPDATE_INFO notifiers / callbacks and > > > > handle request state tracking to properly deal with this. > > > > > > > > > + > > > > > + /* > > > > > + * Ensure null termination for SDL clipboard. > > > > > + * QEMU clipboard data may not be null-terminated. > > > > > + */ > > > > > + g_autofree char *text = g_strndup((const char *)data->data, > > > > > data->size); > > > > > > > > > > > > casting required here? > > > > > > > > > + if (text) { > > > > > > > > > > > > text can't be NULL if data->data is non-NULL. If we want to handle the > > > > > > > > case anyway, we could have a trace or a warning > > > > > > > > > + SDL_SetClipboardText(text); > > > > > + } > > > > > +} > > > > > + > > > > > +static void sdl2_clipboard_notify(Notifier *notifier, > > > > > + void *data) > > > > > +{ > > > > > + QemuClipboardNotify *notify = data; > > > > > + struct sdl2_console scon = > > > > > + container_of(notifier, struct sdl2_console, cbpeer.notifier); > > > > > + > > > > > + switch (notify->type) { > > > > > + case QEMU_CLIPBOARD_UPDATE_INFO: > > > > > + sdl2_clipboard_update(scon, notify->info); > > > > > + break; > > > > > + case QEMU_CLIPBOARD_RESET_SERIAL: > > > > > + / Nothing to do for reset */ > > > > > + break; > > > > > + } > > > > > +} > > > > > + > > > > > +static void sdl2_clipboard_request(QemuClipboardInfo *info, > > > > > + QemuClipboardType type) > > > > > +{ > > > > > + struct sdl2_console *scon = > > > > > + container_of(info->owner, struct sdl2_console, cbpeer); > > > > > + char *sdl_text = NULL; > > > > > + > > > > > + switch (type) { > > > > > + case QEMU_CLIPBOARD_TYPE_TEXT: > > > > > + if (!SDL_HasClipboardText()) { > > > > > + return; > > > > > + } > > > > > + > > > > > + sdl_text = SDL_GetClipboardText(); > > > > > + if (sdl_text && strlen(sdl_text) > 0) { > > > > > > > > > > > > Interesting that SDL decided that empty string is for error reporting. > > > > > > > > Could you simplify the check with sdl_text[0] != '\0' instead? Also > > > > add a warning with SDL_GetError() if it's empty. > > > > > > > > > + /* > > > > > + * SDL guarantees null-terminated UTF-8 strings. > > > > > + * Pass length without null terminator as QEMU clipboard > > > > > + * will handle null termination consistently. > > > > > + / > > > > > + qemu_clipboard_set_data(&scon->cbpeer, info, type, > > > > > + strlen(sdl_text), sdl_text, true); > > > > > + } > > > > > + > > > > > + / Always free SDL-allocated memory */ > > > > > + if (sdl_text) { > > > > > > > > > > > > drop the condition, GetClipboardText() should not return NULL, and > > > > SDL_free(NULL) is fine anyway. > > > > > > > > > + SDL_free(sdl_text); > > > > > + } > > > > > + break; > > > > > + default: > > > > > + break; > > > > > + } > > > > > +} > > > > > + > > > > > +void sdl2_clipboard_handle_request(struct sdl2_console *scon) > > > > > +{ > > > > > + g_autoptr(QemuClipboardInfo) info = > > > > > + qemu_clipboard_info_new(&scon->cbpeer, > > > > > + QEMU_CLIPBOARD_SELECTION_CLIPBOARD); > > > > > + > > > > > + if (info) { > > > > > > > > > > > > qemu_clipboard_info_new never returns NULL > > > > > > > > > + sdl2_clipboard_request(info, QEMU_CLIPBOARD_TYPE_TEXT); > > > > > + } > > > > > +} > > > > > + > > > > > +void sdl2_clipboard_init(struct sdl2_console scon) > > > > > +{ > > > > > + scon->cbpeer.name = "sdl2"; > > > > > + scon->cbpeer.notifier.notify = sdl2_clipboard_notify; > > > > > + scon->cbpeer.request = sdl2_clipboard_request; > > > > > + > > > > > + / Register the clipboard peer with QEMU / > > > > > + qemu_clipboard_peer_register(&scon->cbpeer); > > > > > +} > > > > > + > > > > > +#endif / CONFIG_SDL_CLIPBOARD */ > > > > > diff --git a/ui/sdl2.c b/ui/sdl2.c > > > > > index 1a83c3b1bf..5678930d3c 100644 > > > > > --- a/ui/sdl2.c > > > > > +++ b/ui/sdl2.c > > > > > @@ -691,6 +691,11 @@ void sdl2_poll_events(struct sdl2_console *scon) > > > > > case SDL_WINDOWEVENT: > > > > > handle_windowevent(ev); > > > > > break; > > > > > +#ifdef CONFIG_SDL_CLIPBOARD > > > > > + case SDL_CLIPBOARDUPDATE: > > > > > + sdl2_clipboard_handle_request(scon); > > > > > + break; > > > > > +#endif > > > > > default: > > > > > break; > > > > > } > > > > > @@ -914,6 +919,9 @@ static void sdl2_display_init(DisplayState *ds, > > > > > DisplayOptions *o) > > > > > qemu_console_set_window_id(con, info.info.x11.window); > > > > > #endif > > > > > } > > > > > +#ifdef CONFIG_SDL_CLIPBOARD > > > > > + sdl2_clipboard_init(&sdl2_console[i]); > > > > > +#endif > > > > > } > > > > > > > > > > #ifdef CONFIG_SDL_IMAGE > > > > > > > > > > > > > > > > -- > > > > Marc-André Lureau > > > > > > > > -- > > Marc-André Lureau > > > > -- > Marc-André Lureau -- Marc-André Lureau