Bläddra i källkod

clipboard: include mime types in SDL_ClipboarUpdate

This patch modifies the clipboard handling so that when we receive an external
clipboard update, the suppported mime types are included in the SDL_ClipboarUpdate
event. The patch also introduces the owner field that allows to know if the update
is because we own the clipboard (internal update) or if it was an external update.
David Fort 6 månader sedan
förälder
incheckning
e00b1fdd67

+ 3 - 0
include/SDL3/SDL_events.h

@@ -845,6 +845,9 @@ typedef struct SDL_ClipboardEvent
     SDL_EventType type; /**< SDL_EVENT_CLIPBOARD_UPDATE */
     Uint32 reserved;
     Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
+    bool owner;       /**< are we owning the clipboard (internal update) */
+    Sint32 n_mime_types;     /**< number of mime types */
+    const char **mime_types; /**< current mime types */
 } SDL_ClipboardEvent;
 
 /**

+ 2 - 1
src/core/android/SDL_android.c

@@ -1377,7 +1377,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeAccel)(
 JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeClipboardChanged)(
     JNIEnv *env, jclass jcls)
 {
-    SDL_SendClipboardUpdate();
+    // TODO: compute new mime types
+    SDL_SendClipboardUpdate(false, NULL, 0);
 }
 
 // Low memory

+ 7 - 2
src/events/SDL_clipboardevents.c

@@ -25,12 +25,17 @@
 #include "SDL_events_c.h"
 #include "SDL_clipboardevents_c.h"
 
-void SDL_SendClipboardUpdate(void)
+void SDL_SendClipboardUpdate(bool owner, char **mime_types, size_t n_mime_types)
 {
     if (SDL_EventEnabled(SDL_EVENT_CLIPBOARD_UPDATE)) {
         SDL_Event event;
         event.type = SDL_EVENT_CLIPBOARD_UPDATE;
-        event.clipboard.timestamp = 0;
+
+        SDL_ClipboardEvent *cevent = &event.clipboard;
+        cevent->timestamp = 0;
+        cevent->owner = owner;
+        cevent->mime_types = (const char **)mime_types;
+        cevent->n_mime_types = (Uint32)n_mime_types;
         SDL_PushEvent(&event);
     }
 }

+ 1 - 1
src/events/SDL_clipboardevents_c.h

@@ -23,6 +23,6 @@
 #ifndef SDL_clipboardevents_c_h_
 #define SDL_clipboardevents_c_h_
 
-extern void SDL_SendClipboardUpdate(void);
+extern void SDL_SendClipboardUpdate(bool owner, char **mime_types, size_t n_mime_types);
 
 #endif // SDL_clipboardevents_c_h_

+ 3 - 0
src/events/SDL_events.c

@@ -235,6 +235,9 @@ static void SDL_TransferTemporaryMemoryToEvent(SDL_EventEntry *event)
         SDL_LinkTemporaryMemoryToEvent(event, event->event.drop.source);
         SDL_LinkTemporaryMemoryToEvent(event, event->event.drop.data);
         break;
+    case SDL_EVENT_CLIPBOARD_UPDATE:
+        SDL_LinkTemporaryMemoryToEvent(event, event->event.clipboard.mime_types);
+        break;
     default:
         break;
     }

+ 50 - 29
src/video/SDL_clipboard.c

@@ -22,13 +22,25 @@
 
 #include "SDL_clipboard_c.h"
 #include "SDL_sysvideo.h"
+#include "../events/SDL_events_c.h"
 #include "../events/SDL_clipboardevents_c.h"
 
+void SDL_FreeClipboardMimeTypes(SDL_VideoDevice *_this)
+{
+    if (_this->clipboard_mime_types) {
+        for (size_t i = 0; i < _this->num_clipboard_mime_types; ++i) {
+            SDL_free(_this->clipboard_mime_types[i]);
+        }
+        SDL_free(_this->clipboard_mime_types);
+        _this->clipboard_mime_types = NULL;
+        _this->num_clipboard_mime_types = 0;
+    }
+}
+
 
 void SDL_CancelClipboardData(Uint32 sequence)
 {
     SDL_VideoDevice *_this = SDL_GetVideoDevice();
-    size_t i;
 
     if (sequence != _this->clipboard_sequence) {
         // This clipboard data was already canceled
@@ -39,14 +51,7 @@ void SDL_CancelClipboardData(Uint32 sequence)
         _this->clipboard_cleanup(_this->clipboard_userdata);
     }
 
-    if (_this->clipboard_mime_types) {
-        for (i = 0; i < _this->num_clipboard_mime_types; ++i) {
-            SDL_free(_this->clipboard_mime_types[i]);
-        }
-        SDL_free(_this->clipboard_mime_types);
-        _this->clipboard_mime_types = NULL;
-        _this->num_clipboard_mime_types = 0;
-    }
+    SDL_FreeClipboardMimeTypes(_this);
 
     _this->clipboard_callback = NULL;
     _this->clipboard_cleanup = NULL;
@@ -135,7 +140,11 @@ bool SDL_SetClipboardData(SDL_ClipboardDataCallback callback, SDL_ClipboardClean
         }
     }
 
-    SDL_SendClipboardUpdate();
+    char **mime_types_copy = SDL_CopyClipboardMimeTypes(mime_types, num_mime_types, true);
+    if (!mime_types_copy)
+        return SDL_SetError("unable to copy current mime types");
+
+    SDL_SendClipboardUpdate(true, mime_types_copy, num_mime_types);
     return true;
 }
 
@@ -232,44 +241,52 @@ bool SDL_HasClipboardData(const char *mime_type)
     }
 }
 
-char **SDL_GetClipboardMimeTypes(size_t *num_mime_types)
+char **SDL_CopyClipboardMimeTypes(const char **clipboard_mime_types, size_t num_mime_types, bool temporary)
 {
-    SDL_VideoDevice *_this = SDL_GetVideoDevice();
-
-    if (!_this) {
-        SDL_SetError("Video subsystem must be initialized to query clipboard mime types");
-        return NULL;
-    }
-
     size_t allocSize = sizeof(char *);
-    for (size_t i = 0; i < _this->num_clipboard_mime_types; i++) {
-        allocSize += sizeof(char *) + SDL_strlen(_this->clipboard_mime_types[i]) + 1;
+    for (size_t i = 0; i < num_mime_types; i++) {
+        allocSize += sizeof(char *) + SDL_strlen(clipboard_mime_types[i]) + 1;
     }
 
-    char *ret = (char *)SDL_malloc(allocSize);
+    char *ret;
+    if (temporary)
+        ret = (char *)SDL_AllocateTemporaryMemory(allocSize);
+    else
+        ret = (char *)SDL_malloc(allocSize);
     if (!ret) {
         return NULL;
     }
 
     char **result = (char **)ret;
-    ret += sizeof(char *) * (_this->num_clipboard_mime_types + 1);
+    ret += sizeof(char *) * (num_mime_types + 1);
 
-    for (size_t i = 0; i < _this->num_clipboard_mime_types; i++) {
+    for (size_t i = 0; i < num_mime_types; i++) {
         result[i] = ret;
 
-        const char *mime_type = _this->clipboard_mime_types[i];
+        const char *mime_type = clipboard_mime_types[i];
         // Copy the whole string including the terminating null char
         char c;
         do {
             c = *ret++ = *mime_type++;
         } while (c != '\0');
     }
-    result[_this->num_clipboard_mime_types] = NULL;
+    result[num_mime_types] = NULL;
 
-    if (num_mime_types) {
-        *num_mime_types = _this->num_clipboard_mime_types;
-    }
     return result;
+
+}
+
+char **SDL_GetClipboardMimeTypes(size_t *num_mime_types)
+{
+    SDL_VideoDevice *_this = SDL_GetVideoDevice();
+
+    if (!_this) {
+        SDL_SetError("Video subsystem must be initialized to query clipboard mime types");
+        return NULL;
+    }
+
+    *num_mime_types = _this->num_clipboard_mime_types;
+    return SDL_CopyClipboardMimeTypes((const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types, false);
 }
 
 // Clipboard text
@@ -392,7 +409,11 @@ bool SDL_SetPrimarySelectionText(const char *text)
         _this->primary_selection_text = SDL_strdup(text);
     }
 
-    SDL_SendClipboardUpdate();
+    char **mime_types = SDL_CopyClipboardMimeTypes((const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types, true);
+    if (!mime_types)
+        return SDL_SetError("unable to copy current mime types");
+
+    SDL_SendClipboardUpdate(true, mime_types, _this->num_clipboard_mime_types);
     return true;
 }
 

+ 3 - 0
src/video/SDL_clipboard_c.h

@@ -39,4 +39,7 @@ extern bool SDL_HasInternalClipboardData(SDL_VideoDevice *_this, const char *mim
 // General purpose clipboard text callback
 const void * SDLCALL SDL_ClipboardTextCallback(void *userdata, const char *mime_type, size_t *size);
 
+void SDLCALL SDL_FreeClipboardMimeTypes(SDL_VideoDevice *_this);
+char ** SDLCALL SDL_CopyClipboardMimeTypes(const char **clipboard_mime_types, size_t num_mime_types, bool temporary);
+
 #endif // SDL_clipboard_c_h_

+ 2 - 1
src/video/cocoa/SDL_cocoaclipboard.m

@@ -83,7 +83,8 @@ void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data)
         count = [pasteboard changeCount];
         if (count != data.clipboard_count) {
             if (data.clipboard_count) {
-                SDL_SendClipboardUpdate();
+                // TODO: compute mime types
+                SDL_SendClipboardUpdate(false, NULL, 0);
             }
             data.clipboard_count = count;
         }

+ 2 - 1
src/video/uikit/SDL_uikitclipboard.m

@@ -80,7 +80,8 @@ void UIKit_InitClipboard(SDL_VideoDevice *_this)
                                           object:nil
                                            queue:nil
                                       usingBlock:^(NSNotification *note) {
-                                        SDL_SendClipboardUpdate();
+                                        // TODO: compute mime types
+                                        SDL_SendClipboardUpdate(false, NULL, 0);
                                       }];
 
         data.pasteboardObserver = observer;

+ 36 - 2
src/video/wayland/SDL_waylandevents.c

@@ -2277,6 +2277,40 @@ static void data_device_handle_drop(void *data, struct wl_data_device *wl_data_d
     data_device->drag_offer = NULL;
 }
 
+static void notifyFromMimes(struct wl_list *mimes) {
+    int nformats = 0;
+    char **new_mime_types = NULL;
+    if (mimes) {
+        nformats = WAYLAND_wl_list_length(mimes);
+        size_t alloc_size = (nformats + 1) * sizeof(char *);
+
+        /* do a first pass to compute allocation size */
+        SDL_MimeDataList *item = NULL;
+        wl_list_for_each(item, mimes, link) {
+            alloc_size += SDL_strlen(item->mime_type) + 1;
+        }
+
+        new_mime_types = SDL_AllocateTemporaryMemory(alloc_size);
+        if (!new_mime_types) {
+            SDL_LogError(SDL_LOG_CATEGORY_INPUT, "unable to allocate new_mime_types");
+            return;
+        }
+
+        /* second pass to fill*/
+        char *strPtr = (char *)(new_mime_types + nformats + 1);
+        item = NULL;
+        int i = 0;
+        wl_list_for_each(item, mimes, link) {
+            new_mime_types[i] = strPtr;
+            strPtr = stpcpy(strPtr, item->mime_type) + 1;
+            i++;
+        }
+        new_mime_types[nformats] = NULL;
+    }
+
+    SDL_SendClipboardUpdate(false, new_mime_types, nformats);
+}
+
 static void data_device_handle_selection(void *data, struct wl_data_device *wl_data_device,
                                          struct wl_data_offer *id)
 {
@@ -2295,7 +2329,7 @@ static void data_device_handle_selection(void *data, struct wl_data_device *wl_d
         data_device->selection_offer = offer;
     }
 
-    SDL_SendClipboardUpdate();
+    notifyFromMimes(offer ? &offer->mimes : NULL);
 }
 
 static const struct wl_data_device_listener data_device_listener = {
@@ -2341,7 +2375,7 @@ static void primary_selection_device_handle_selection(void *data, struct zwp_pri
                  ". In zwp_primary_selection_device_v1_listener . primary_selection_device_handle_selection on primary_selection_offer 0x%08x\n",
                  (id ? WAYLAND_wl_proxy_get_id((struct wl_proxy *)id) : -1));
 
-    SDL_SendClipboardUpdate();
+    notifyFromMimes(offer ? &offer->mimes : NULL);
 }
 
 static const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = {

+ 64 - 4
src/video/windows/SDL_windowsclipboard.c

@@ -25,6 +25,7 @@
 #include "SDL_windowsvideo.h"
 #include "SDL_windowswindow.h"
 #include "../SDL_clipboard_c.h"
+#include "../../events/SDL_events_c.h"
 #include "../../events/SDL_clipboardevents_c.h"
 
 #ifdef UNICODE
@@ -329,14 +330,73 @@ bool WIN_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
     return false;
 }
 
+static char **GetMimeTypes(int *pnformats)
+{
+    *pnformats = 0;
+
+    int nformats = CountClipboardFormats();
+    size_t allocSize = (nformats + 1) * sizeof(char*);
+
+    UINT format = 0;
+    int formatsSz = 0;
+    int i;
+    for (i = 0; i < nformats; i++) {
+        format = EnumClipboardFormats(format);
+        if (!format) {
+            nformats = i;
+            break;
+        }
+
+        char mimeType[200];
+        int nchars = GetClipboardFormatNameA(format, mimeType, sizeof(mimeType));
+        formatsSz += nchars + 1;
+    }
+
+    char **new_mime_types = SDL_AllocateTemporaryMemory(allocSize + formatsSz);
+    if (!new_mime_types)
+        return NULL;
+
+    format = 0;
+    char *strPtr = (char *)(new_mime_types + nformats + 1);
+    int formatRemains = formatsSz;
+    for (i = 0; i < nformats; i++) {
+        format = EnumClipboardFormats(format);
+        if (!format) {
+            nformats = i;
+            break;
+        }
+
+        new_mime_types[i] = strPtr;
+
+        int nchars = GetClipboardFormatNameA(format, strPtr, formatRemains-1);
+        strPtr += nchars;
+        *strPtr = '\0';
+        strPtr++;
+
+        formatRemains -= (nchars + 1);
+    }
+
+    new_mime_types[nformats] = NULL;
+    *pnformats = nformats;
+    return new_mime_types;
+}
+
 void WIN_CheckClipboardUpdate(struct SDL_VideoData *data)
 {
-    const DWORD count = GetClipboardSequenceNumber();
-    if (count != data->clipboard_count) {
+    const DWORD seq = GetClipboardSequenceNumber();
+    if (seq != data->clipboard_count) {
         if (data->clipboard_count) {
-            SDL_SendClipboardUpdate();
+            int nformats = 0;
+            char **new_mime_types = GetMimeTypes(&nformats);
+            if (new_mime_types) {
+                SDL_SendClipboardUpdate(false, new_mime_types, nformats);
+            } else {
+                WIN_SetError("Couldn't get clipboard mime types");
+            }
+
         }
-        data->clipboard_count = count;
+
+        data->clipboard_count = seq;
     }
 }
 

+ 1 - 1
src/video/x11/SDL_x11clipboard.c

@@ -38,7 +38,7 @@ static const char *text_mime_types[] = {
 };
 
 // Get any application owned window handle for clipboard association
-static Window GetWindow(SDL_VideoDevice *_this)
+Window GetWindow(SDL_VideoDevice *_this)
 {
     SDL_VideoData *data = _this->internal;
 

+ 1 - 0
src/video/x11/SDL_x11clipboard.h

@@ -41,5 +41,6 @@ extern bool X11_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text
 extern char *X11_GetPrimarySelectionText(SDL_VideoDevice *_this);
 extern bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this);
 extern void X11_QuitClipboard(SDL_VideoDevice *_this);
+Window GetWindow(SDL_VideoDevice *_this);
 
 #endif // SDL_x11clipboard_h_

+ 61 - 12
src/video/x11/SDL_x11events.c

@@ -415,7 +415,7 @@ static void DispatchWindowMove(SDL_VideoDevice *_this, const SDL_WindowData *dat
 
     evt.xclient.type = ClientMessage;
     evt.xclient.window = data->xwindow;
-    evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True);
+    evt.xclient.message_type = videodata->atoms._NET_WM_MOVERESIZE;
     evt.xclient.format = 32;
     evt.xclient.data.l[0] = (size_t)window->x + point->x;
     evt.xclient.data.l[1] = (size_t)window->y + point->y;
@@ -450,7 +450,7 @@ static void InitiateWindowResize(SDL_VideoDevice *_this, const SDL_WindowData *d
 
     evt.xclient.type = ClientMessage;
     evt.xclient.window = data->xwindow;
-    evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True);
+    evt.xclient.message_type = videodata->atoms._NET_WM_MOVERESIZE;
     evt.xclient.format = 32;
     evt.xclient.data.l[0] = (size_t)window->x + point->x;
     evt.xclient.data.l[1] = (size_t)window->y + point->y;
@@ -553,7 +553,7 @@ static void X11_HandleClipboardEvent(SDL_VideoDevice *_this, const XEvent *xeven
         int mime_formats;
         unsigned char *seln_data;
         size_t seln_length = 0;
-        Atom XA_TARGETS = X11_XInternAtom(display, "TARGETS", 0);
+        Atom XA_TARGETS = videodata->atoms.TARGETS;
         SDLX11_ClipboardData *clipboard;
 
 #ifdef DEBUG_XEVENTS
@@ -627,17 +627,52 @@ static void X11_HandleClipboardEvent(SDL_VideoDevice *_this, const XEvent *xeven
 
     case SelectionNotify:
     {
+        const XSelectionEvent *xsel = &xevent->xselection;
 #ifdef DEBUG_XEVENTS
-        SDL_Log("window CLIPBOARD: SelectionNotify (requestor = 0x%lx, target = 0x%lx)\n",
-               xevent->xselection.requestor, xevent->xselection.target);
-#endif
+        const char *propName = xsel->property ? X11_XGetAtomName(display, xsel->property) : "None";
+        const char *targetName = xsel->target ? X11_XGetAtomName(display, xsel->target) : "None";
+
+        SDL_Log("window CLIPBOARD: SelectionNotify (requestor = 0x%lx, target = %s, property = %s)\n",
+               xsel->requestor, targetName, propName);
+#endif
+        if (xsel->target == videodata->atoms.TARGETS && xsel->property == videodata->atoms.SDL_FORMATS) {
+            /* the new mime formats are the SDL_FORMATS property as an array of Atoms */
+            Atom atom = None;
+            Atom *patom;
+            unsigned char* data = NULL;
+            int format_property = 0;
+            unsigned long length = 0;
+            unsigned long bytes_left = 0;
+            int j;
+
+            X11_XGetWindowProperty(display, GetWindow(_this), videodata->atoms.SDL_FORMATS, 0, 200,
+                                            0, XA_ATOM, &atom, &format_property, &length, &bytes_left, &data);
+
+            int allocationsize = (length + 1) * sizeof(char*);
+            for (j = 0, patom = (Atom*)data; j < length; j++, patom++) {
+                allocationsize += SDL_strlen( X11_XGetAtomName(display, *patom) ) + 1;
+            }
+
+            char **new_mime_types = SDL_AllocateTemporaryMemory(allocationsize);
+            if (new_mime_types) {
+                char *strPtr = (char *)(new_mime_types + length + 1);
+
+                for (j = 0, patom = (Atom*)data; j < length; j++, patom++) {
+                    new_mime_types[j] = strPtr;
+                    strPtr = stpcpy(strPtr, X11_XGetAtomName(display, *patom)) + 1;
+                }
+                new_mime_types[length] = NULL;
+
+                SDL_SendClipboardUpdate(false, new_mime_types, length);
+            }
+        }
+
         videodata->selection_waiting = false;
     } break;
 
     case SelectionClear:
     {
-        // !!! FIXME: cache atoms
-        Atom XA_CLIPBOARD = X11_XInternAtom(display, "CLIPBOARD", 0);
+        Atom XA_CLIPBOARD = videodata->atoms.CLIPBOARD;
         SDLX11_ClipboardData *clipboard = NULL;
 
 #ifdef DEBUG_XEVENTS
@@ -994,11 +1029,25 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
                X11_XGetAtomName(display, ev->selection));
 #endif
 
-        if (ev->selection == XA_PRIMARY ||
-            (videodata->atoms.CLIPBOARD != None && ev->selection == videodata->atoms.CLIPBOARD)) {
-            SDL_SendClipboardUpdate();
-            return;
+        if (ev->subtype == XFixesSetSelectionOwnerNotify)
+        {
+            if (ev->selection != videodata->atoms.CLIPBOARD)
+                return;
+
+            if (X11_XGetSelectionOwner(display, ev->selection) == videodata->clipboard_window)
+                return;
+
+            /* when here we're notified that the clipboard had an external change, we request the
+             * available mime types by asking for a conversion to the TARGETS format. We should get a
+             * SelectionNotify event later, and when treating these results, we will push a ClipboardUpdated
+             * event
+             */
+
+            X11_XConvertSelection(display, videodata->atoms.CLIPBOARD, videodata->atoms.TARGETS,
+                    videodata->atoms.SDL_FORMATS, GetWindow(_this), CurrentTime);
         }
+
+        return;
     }
 #endif // SDL_VIDEO_DRIVER_X11_XFIXES
 

+ 4 - 0
src/video/x11/SDL_x11video.c

@@ -403,6 +403,7 @@ static bool X11_VideoInit(SDL_VideoDevice *_this)
     GET_ATOM(_NET_WM_STATE_ABOVE);
     GET_ATOM(_NET_WM_STATE_SKIP_TASKBAR);
     GET_ATOM(_NET_WM_STATE_SKIP_PAGER);
+    GET_ATOM(_NET_WM_MOVERESIZE);
     GET_ATOM(_NET_WM_STATE_MODAL);
     GET_ATOM(_NET_WM_ALLOWED_ACTIONS);
     GET_ATOM(_NET_WM_ACTION_FULLSCREEN);
@@ -420,6 +421,9 @@ static bool X11_VideoInit(SDL_VideoDevice *_this)
     GET_ATOM(CLIPBOARD);
     GET_ATOM(INCR);
     GET_ATOM(SDL_SELECTION);
+    GET_ATOM(TARGETS);
+    GET_ATOM(SDL_FORMATS);
+    GET_ATOM(XdndAware);
     GET_ATOM(XdndEnter);
     GET_ATOM(XdndPosition);
     GET_ATOM(XdndStatus);

+ 4 - 0
src/video/x11/SDL_x11video.h

@@ -82,6 +82,7 @@ struct SDL_VideoData
         Atom _NET_WM_STATE_SKIP_TASKBAR;
         Atom _NET_WM_STATE_SKIP_PAGER;
         Atom _NET_WM_STATE_MODAL;
+        Atom _NET_WM_MOVERESIZE;
         Atom _NET_WM_ALLOWED_ACTIONS;
         Atom _NET_WM_ACTION_FULLSCREEN;
         Atom _NET_WM_NAME;
@@ -98,6 +99,9 @@ struct SDL_VideoData
         Atom CLIPBOARD;
         Atom INCR;
         Atom SDL_SELECTION;
+        Atom TARGETS;
+        Atom SDL_FORMATS;
+        Atom XdndAware;
         Atom XdndEnter;
         Atom XdndPosition;
         Atom XdndStatus;

+ 1 - 1
src/video/x11/SDL_x11window.c

@@ -2001,7 +2001,7 @@ void X11_AcceptDragAndDrop(SDL_Window *window, bool accept)
 {
     SDL_WindowData *data = window->internal;
     Display *display = data->videodata->display;
-    Atom XdndAware = X11_XInternAtom(display, "XdndAware", False);
+    Atom XdndAware = data->videodata->atoms.XdndAware;
 
     if (accept) {
         Atom xdnd_version = 5;

+ 1 - 1
src/video/x11/SDL_x11xfixes.c

@@ -51,7 +51,7 @@ void X11_InitXfixes(SDL_VideoDevice *_this)
     int event, error;
     int fixes_opcode;
 
-    Atom XA_CLIPBOARD = X11_XInternAtom(data->display, "CLIPBOARD", 0);
+    Atom XA_CLIPBOARD = data->atoms.CLIPBOARD;
 
     if (!SDL_X11_HAVE_XFIXES ||
         !X11_XQueryExtension(data->display, "XFIXES", &fixes_opcode, &event, &error)) {