Simple Directmedia Layer
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

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.

authored by

David Fort and committed by
Sam Lantinga
e00b1fdd 2880b40e

+245 -55
+3
include/SDL3/SDL_events.h
··· 845 845 SDL_EventType type; /**< SDL_EVENT_CLIPBOARD_UPDATE */ 846 846 Uint32 reserved; 847 847 Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ 848 + bool owner; /**< are we owning the clipboard (internal update) */ 849 + Sint32 n_mime_types; /**< number of mime types */ 850 + const char **mime_types; /**< current mime types */ 848 851 } SDL_ClipboardEvent; 849 852 850 853 /**
+2 -1
src/core/android/SDL_android.c
··· 1377 1377 JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeClipboardChanged)( 1378 1378 JNIEnv *env, jclass jcls) 1379 1379 { 1380 - SDL_SendClipboardUpdate(); 1380 + // TODO: compute new mime types 1381 + SDL_SendClipboardUpdate(false, NULL, 0); 1381 1382 } 1382 1383 1383 1384 // Low memory
+7 -2
src/events/SDL_clipboardevents.c
··· 25 25 #include "SDL_events_c.h" 26 26 #include "SDL_clipboardevents_c.h" 27 27 28 - void SDL_SendClipboardUpdate(void) 28 + void SDL_SendClipboardUpdate(bool owner, char **mime_types, size_t n_mime_types) 29 29 { 30 30 if (SDL_EventEnabled(SDL_EVENT_CLIPBOARD_UPDATE)) { 31 31 SDL_Event event; 32 32 event.type = SDL_EVENT_CLIPBOARD_UPDATE; 33 - event.clipboard.timestamp = 0; 33 + 34 + SDL_ClipboardEvent *cevent = &event.clipboard; 35 + cevent->timestamp = 0; 36 + cevent->owner = owner; 37 + cevent->mime_types = (const char **)mime_types; 38 + cevent->n_mime_types = (Uint32)n_mime_types; 34 39 SDL_PushEvent(&event); 35 40 } 36 41 }
+1 -1
src/events/SDL_clipboardevents_c.h
··· 23 23 #ifndef SDL_clipboardevents_c_h_ 24 24 #define SDL_clipboardevents_c_h_ 25 25 26 - extern void SDL_SendClipboardUpdate(void); 26 + extern void SDL_SendClipboardUpdate(bool owner, char **mime_types, size_t n_mime_types); 27 27 28 28 #endif // SDL_clipboardevents_c_h_
+3
src/events/SDL_events.c
··· 235 235 SDL_LinkTemporaryMemoryToEvent(event, event->event.drop.source); 236 236 SDL_LinkTemporaryMemoryToEvent(event, event->event.drop.data); 237 237 break; 238 + case SDL_EVENT_CLIPBOARD_UPDATE: 239 + SDL_LinkTemporaryMemoryToEvent(event, event->event.clipboard.mime_types); 240 + break; 238 241 default: 239 242 break; 240 243 }
+50 -29
src/video/SDL_clipboard.c
··· 22 22 23 23 #include "SDL_clipboard_c.h" 24 24 #include "SDL_sysvideo.h" 25 + #include "../events/SDL_events_c.h" 25 26 #include "../events/SDL_clipboardevents_c.h" 26 27 28 + void SDL_FreeClipboardMimeTypes(SDL_VideoDevice *_this) 29 + { 30 + if (_this->clipboard_mime_types) { 31 + for (size_t i = 0; i < _this->num_clipboard_mime_types; ++i) { 32 + SDL_free(_this->clipboard_mime_types[i]); 33 + } 34 + SDL_free(_this->clipboard_mime_types); 35 + _this->clipboard_mime_types = NULL; 36 + _this->num_clipboard_mime_types = 0; 37 + } 38 + } 39 + 27 40 28 41 void SDL_CancelClipboardData(Uint32 sequence) 29 42 { 30 43 SDL_VideoDevice *_this = SDL_GetVideoDevice(); 31 - size_t i; 32 44 33 45 if (sequence != _this->clipboard_sequence) { 34 46 // This clipboard data was already canceled ··· 39 51 _this->clipboard_cleanup(_this->clipboard_userdata); 40 52 } 41 53 42 - if (_this->clipboard_mime_types) { 43 - for (i = 0; i < _this->num_clipboard_mime_types; ++i) { 44 - SDL_free(_this->clipboard_mime_types[i]); 45 - } 46 - SDL_free(_this->clipboard_mime_types); 47 - _this->clipboard_mime_types = NULL; 48 - _this->num_clipboard_mime_types = 0; 49 - } 54 + SDL_FreeClipboardMimeTypes(_this); 50 55 51 56 _this->clipboard_callback = NULL; 52 57 _this->clipboard_cleanup = NULL; ··· 135 140 } 136 141 } 137 142 138 - SDL_SendClipboardUpdate(); 143 + char **mime_types_copy = SDL_CopyClipboardMimeTypes(mime_types, num_mime_types, true); 144 + if (!mime_types_copy) 145 + return SDL_SetError("unable to copy current mime types"); 146 + 147 + SDL_SendClipboardUpdate(true, mime_types_copy, num_mime_types); 139 148 return true; 140 149 } 141 150 ··· 232 241 } 233 242 } 234 243 235 - char **SDL_GetClipboardMimeTypes(size_t *num_mime_types) 244 + char **SDL_CopyClipboardMimeTypes(const char **clipboard_mime_types, size_t num_mime_types, bool temporary) 236 245 { 237 - SDL_VideoDevice *_this = SDL_GetVideoDevice(); 238 - 239 - if (!_this) { 240 - SDL_SetError("Video subsystem must be initialized to query clipboard mime types"); 241 - return NULL; 242 - } 243 - 244 246 size_t allocSize = sizeof(char *); 245 - for (size_t i = 0; i < _this->num_clipboard_mime_types; i++) { 246 - allocSize += sizeof(char *) + SDL_strlen(_this->clipboard_mime_types[i]) + 1; 247 + for (size_t i = 0; i < num_mime_types; i++) { 248 + allocSize += sizeof(char *) + SDL_strlen(clipboard_mime_types[i]) + 1; 247 249 } 248 250 249 - char *ret = (char *)SDL_malloc(allocSize); 251 + char *ret; 252 + if (temporary) 253 + ret = (char *)SDL_AllocateTemporaryMemory(allocSize); 254 + else 255 + ret = (char *)SDL_malloc(allocSize); 250 256 if (!ret) { 251 257 return NULL; 252 258 } 253 259 254 260 char **result = (char **)ret; 255 - ret += sizeof(char *) * (_this->num_clipboard_mime_types + 1); 261 + ret += sizeof(char *) * (num_mime_types + 1); 256 262 257 - for (size_t i = 0; i < _this->num_clipboard_mime_types; i++) { 263 + for (size_t i = 0; i < num_mime_types; i++) { 258 264 result[i] = ret; 259 265 260 - const char *mime_type = _this->clipboard_mime_types[i]; 266 + const char *mime_type = clipboard_mime_types[i]; 261 267 // Copy the whole string including the terminating null char 262 268 char c; 263 269 do { 264 270 c = *ret++ = *mime_type++; 265 271 } while (c != '\0'); 266 272 } 267 - result[_this->num_clipboard_mime_types] = NULL; 273 + result[num_mime_types] = NULL; 274 + 275 + return result; 268 276 269 - if (num_mime_types) { 270 - *num_mime_types = _this->num_clipboard_mime_types; 277 + } 278 + 279 + char **SDL_GetClipboardMimeTypes(size_t *num_mime_types) 280 + { 281 + SDL_VideoDevice *_this = SDL_GetVideoDevice(); 282 + 283 + if (!_this) { 284 + SDL_SetError("Video subsystem must be initialized to query clipboard mime types"); 285 + return NULL; 271 286 } 272 - return result; 287 + 288 + *num_mime_types = _this->num_clipboard_mime_types; 289 + return SDL_CopyClipboardMimeTypes((const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types, false); 273 290 } 274 291 275 292 // Clipboard text ··· 392 409 _this->primary_selection_text = SDL_strdup(text); 393 410 } 394 411 395 - SDL_SendClipboardUpdate(); 412 + char **mime_types = SDL_CopyClipboardMimeTypes((const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types, true); 413 + if (!mime_types) 414 + return SDL_SetError("unable to copy current mime types"); 415 + 416 + SDL_SendClipboardUpdate(true, mime_types, _this->num_clipboard_mime_types); 396 417 return true; 397 418 } 398 419
+3
src/video/SDL_clipboard_c.h
··· 39 39 // General purpose clipboard text callback 40 40 const void * SDLCALL SDL_ClipboardTextCallback(void *userdata, const char *mime_type, size_t *size); 41 41 42 + void SDLCALL SDL_FreeClipboardMimeTypes(SDL_VideoDevice *_this); 43 + char ** SDLCALL SDL_CopyClipboardMimeTypes(const char **clipboard_mime_types, size_t num_mime_types, bool temporary); 44 + 42 45 #endif // SDL_clipboard_c_h_
+2 -1
src/video/cocoa/SDL_cocoaclipboard.m
··· 83 83 count = [pasteboard changeCount]; 84 84 if (count != data.clipboard_count) { 85 85 if (data.clipboard_count) { 86 - SDL_SendClipboardUpdate(); 86 + // TODO: compute mime types 87 + SDL_SendClipboardUpdate(false, NULL, 0); 87 88 } 88 89 data.clipboard_count = count; 89 90 }
+2 -1
src/video/uikit/SDL_uikitclipboard.m
··· 80 80 object:nil 81 81 queue:nil 82 82 usingBlock:^(NSNotification *note) { 83 - SDL_SendClipboardUpdate(); 83 + // TODO: compute mime types 84 + SDL_SendClipboardUpdate(false, NULL, 0); 84 85 }]; 85 86 86 87 data.pasteboardObserver = observer;
+36 -2
src/video/wayland/SDL_waylandevents.c
··· 2277 2277 data_device->drag_offer = NULL; 2278 2278 } 2279 2279 2280 + static void notifyFromMimes(struct wl_list *mimes) { 2281 + int nformats = 0; 2282 + char **new_mime_types = NULL; 2283 + if (mimes) { 2284 + nformats = WAYLAND_wl_list_length(mimes); 2285 + size_t alloc_size = (nformats + 1) * sizeof(char *); 2286 + 2287 + /* do a first pass to compute allocation size */ 2288 + SDL_MimeDataList *item = NULL; 2289 + wl_list_for_each(item, mimes, link) { 2290 + alloc_size += SDL_strlen(item->mime_type) + 1; 2291 + } 2292 + 2293 + new_mime_types = SDL_AllocateTemporaryMemory(alloc_size); 2294 + if (!new_mime_types) { 2295 + SDL_LogError(SDL_LOG_CATEGORY_INPUT, "unable to allocate new_mime_types"); 2296 + return; 2297 + } 2298 + 2299 + /* second pass to fill*/ 2300 + char *strPtr = (char *)(new_mime_types + nformats + 1); 2301 + item = NULL; 2302 + int i = 0; 2303 + wl_list_for_each(item, mimes, link) { 2304 + new_mime_types[i] = strPtr; 2305 + strPtr = stpcpy(strPtr, item->mime_type) + 1; 2306 + i++; 2307 + } 2308 + new_mime_types[nformats] = NULL; 2309 + } 2310 + 2311 + SDL_SendClipboardUpdate(false, new_mime_types, nformats); 2312 + } 2313 + 2280 2314 static void data_device_handle_selection(void *data, struct wl_data_device *wl_data_device, 2281 2315 struct wl_data_offer *id) 2282 2316 { ··· 2295 2329 data_device->selection_offer = offer; 2296 2330 } 2297 2331 2298 - SDL_SendClipboardUpdate(); 2332 + notifyFromMimes(offer ? &offer->mimes : NULL); 2299 2333 } 2300 2334 2301 2335 static const struct wl_data_device_listener data_device_listener = { ··· 2341 2375 ". In zwp_primary_selection_device_v1_listener . primary_selection_device_handle_selection on primary_selection_offer 0x%08x\n", 2342 2376 (id ? WAYLAND_wl_proxy_get_id((struct wl_proxy *)id) : -1)); 2343 2377 2344 - SDL_SendClipboardUpdate(); 2378 + notifyFromMimes(offer ? &offer->mimes : NULL); 2345 2379 } 2346 2380 2347 2381 static const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = {
+64 -4
src/video/windows/SDL_windowsclipboard.c
··· 25 25 #include "SDL_windowsvideo.h" 26 26 #include "SDL_windowswindow.h" 27 27 #include "../SDL_clipboard_c.h" 28 + #include "../../events/SDL_events_c.h" 28 29 #include "../../events/SDL_clipboardevents_c.h" 29 30 30 31 #ifdef UNICODE ··· 329 330 return false; 330 331 } 331 332 333 + static char **GetMimeTypes(int *pnformats) 334 + { 335 + *pnformats = 0; 336 + 337 + int nformats = CountClipboardFormats(); 338 + size_t allocSize = (nformats + 1) * sizeof(char*); 339 + 340 + UINT format = 0; 341 + int formatsSz = 0; 342 + int i; 343 + for (i = 0; i < nformats; i++) { 344 + format = EnumClipboardFormats(format); 345 + if (!format) { 346 + nformats = i; 347 + break; 348 + } 349 + 350 + char mimeType[200]; 351 + int nchars = GetClipboardFormatNameA(format, mimeType, sizeof(mimeType)); 352 + formatsSz += nchars + 1; 353 + } 354 + 355 + char **new_mime_types = SDL_AllocateTemporaryMemory(allocSize + formatsSz); 356 + if (!new_mime_types) 357 + return NULL; 358 + 359 + format = 0; 360 + char *strPtr = (char *)(new_mime_types + nformats + 1); 361 + int formatRemains = formatsSz; 362 + for (i = 0; i < nformats; i++) { 363 + format = EnumClipboardFormats(format); 364 + if (!format) { 365 + nformats = i; 366 + break; 367 + } 368 + 369 + new_mime_types[i] = strPtr; 370 + 371 + int nchars = GetClipboardFormatNameA(format, strPtr, formatRemains-1); 372 + strPtr += nchars; 373 + *strPtr = '\0'; 374 + strPtr++; 375 + 376 + formatRemains -= (nchars + 1); 377 + } 378 + 379 + new_mime_types[nformats] = NULL; 380 + *pnformats = nformats; 381 + return new_mime_types; 382 + } 383 + 332 384 void WIN_CheckClipboardUpdate(struct SDL_VideoData *data) 333 385 { 334 - const DWORD count = GetClipboardSequenceNumber(); 335 - if (count != data->clipboard_count) { 386 + const DWORD seq = GetClipboardSequenceNumber(); 387 + if (seq != data->clipboard_count) { 336 388 if (data->clipboard_count) { 337 - SDL_SendClipboardUpdate(); 389 + int nformats = 0; 390 + char **new_mime_types = GetMimeTypes(&nformats); 391 + if (new_mime_types) { 392 + SDL_SendClipboardUpdate(false, new_mime_types, nformats); 393 + } else { 394 + WIN_SetError("Couldn't get clipboard mime types"); 395 + } 396 + 338 397 } 339 - data->clipboard_count = count; 398 + 399 + data->clipboard_count = seq; 340 400 } 341 401 } 342 402
+1 -1
src/video/x11/SDL_x11clipboard.c
··· 38 38 }; 39 39 40 40 // Get any application owned window handle for clipboard association 41 - static Window GetWindow(SDL_VideoDevice *_this) 41 + Window GetWindow(SDL_VideoDevice *_this) 42 42 { 43 43 SDL_VideoData *data = _this->internal; 44 44
+1
src/video/x11/SDL_x11clipboard.h
··· 41 41 extern char *X11_GetPrimarySelectionText(SDL_VideoDevice *_this); 42 42 extern bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this); 43 43 extern void X11_QuitClipboard(SDL_VideoDevice *_this); 44 + Window GetWindow(SDL_VideoDevice *_this); 44 45 45 46 #endif // SDL_x11clipboard_h_
+60 -11
src/video/x11/SDL_x11events.c
··· 415 415 416 416 evt.xclient.type = ClientMessage; 417 417 evt.xclient.window = data->xwindow; 418 - evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True); 418 + evt.xclient.message_type = videodata->atoms._NET_WM_MOVERESIZE; 419 419 evt.xclient.format = 32; 420 420 evt.xclient.data.l[0] = (size_t)window->x + point->x; 421 421 evt.xclient.data.l[1] = (size_t)window->y + point->y; ··· 450 450 451 451 evt.xclient.type = ClientMessage; 452 452 evt.xclient.window = data->xwindow; 453 - evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True); 453 + evt.xclient.message_type = videodata->atoms._NET_WM_MOVERESIZE; 454 454 evt.xclient.format = 32; 455 455 evt.xclient.data.l[0] = (size_t)window->x + point->x; 456 456 evt.xclient.data.l[1] = (size_t)window->y + point->y; ··· 553 553 int mime_formats; 554 554 unsigned char *seln_data; 555 555 size_t seln_length = 0; 556 - Atom XA_TARGETS = X11_XInternAtom(display, "TARGETS", 0); 556 + Atom XA_TARGETS = videodata->atoms.TARGETS; 557 557 SDLX11_ClipboardData *clipboard; 558 558 559 559 #ifdef DEBUG_XEVENTS ··· 627 627 628 628 case SelectionNotify: 629 629 { 630 + const XSelectionEvent *xsel = &xevent->xselection; 630 631 #ifdef DEBUG_XEVENTS 631 - SDL_Log("window CLIPBOARD: SelectionNotify (requestor = 0x%lx, target = 0x%lx)\n", 632 - xevent->xselection.requestor, xevent->xselection.target); 632 + const char *propName = xsel->property ? X11_XGetAtomName(display, xsel->property) : "None"; 633 + const char *targetName = xsel->target ? X11_XGetAtomName(display, xsel->target) : "None"; 634 + 635 + SDL_Log("window CLIPBOARD: SelectionNotify (requestor = 0x%lx, target = %s, property = %s)\n", 636 + xsel->requestor, targetName, propName); 633 637 #endif 638 + if (xsel->target == videodata->atoms.TARGETS && xsel->property == videodata->atoms.SDL_FORMATS) { 639 + /* the new mime formats are the SDL_FORMATS property as an array of Atoms */ 640 + Atom atom = None; 641 + Atom *patom; 642 + unsigned char* data = NULL; 643 + int format_property = 0; 644 + unsigned long length = 0; 645 + unsigned long bytes_left = 0; 646 + int j; 647 + 648 + X11_XGetWindowProperty(display, GetWindow(_this), videodata->atoms.SDL_FORMATS, 0, 200, 649 + 0, XA_ATOM, &atom, &format_property, &length, &bytes_left, &data); 650 + 651 + int allocationsize = (length + 1) * sizeof(char*); 652 + for (j = 0, patom = (Atom*)data; j < length; j++, patom++) { 653 + allocationsize += SDL_strlen( X11_XGetAtomName(display, *patom) ) + 1; 654 + } 655 + 656 + char **new_mime_types = SDL_AllocateTemporaryMemory(allocationsize); 657 + if (new_mime_types) { 658 + char *strPtr = (char *)(new_mime_types + length + 1); 659 + 660 + for (j = 0, patom = (Atom*)data; j < length; j++, patom++) { 661 + new_mime_types[j] = strPtr; 662 + strPtr = stpcpy(strPtr, X11_XGetAtomName(display, *patom)) + 1; 663 + } 664 + new_mime_types[length] = NULL; 665 + 666 + SDL_SendClipboardUpdate(false, new_mime_types, length); 667 + } 668 + } 669 + 634 670 videodata->selection_waiting = false; 635 671 } break; 636 672 637 673 case SelectionClear: 638 674 { 639 - // !!! FIXME: cache atoms 640 - Atom XA_CLIPBOARD = X11_XInternAtom(display, "CLIPBOARD", 0); 675 + Atom XA_CLIPBOARD = videodata->atoms.CLIPBOARD; 641 676 SDLX11_ClipboardData *clipboard = NULL; 642 677 643 678 #ifdef DEBUG_XEVENTS ··· 994 1029 X11_XGetAtomName(display, ev->selection)); 995 1030 #endif 996 1031 997 - if (ev->selection == XA_PRIMARY || 998 - (videodata->atoms.CLIPBOARD != None && ev->selection == videodata->atoms.CLIPBOARD)) { 999 - SDL_SendClipboardUpdate(); 1000 - return; 1032 + if (ev->subtype == XFixesSetSelectionOwnerNotify) 1033 + { 1034 + if (ev->selection != videodata->atoms.CLIPBOARD) 1035 + return; 1036 + 1037 + if (X11_XGetSelectionOwner(display, ev->selection) == videodata->clipboard_window) 1038 + return; 1039 + 1040 + /* when here we're notified that the clipboard had an external change, we request the 1041 + * available mime types by asking for a conversion to the TARGETS format. We should get a 1042 + * SelectionNotify event later, and when treating these results, we will push a ClipboardUpdated 1043 + * event 1044 + */ 1045 + 1046 + X11_XConvertSelection(display, videodata->atoms.CLIPBOARD, videodata->atoms.TARGETS, 1047 + videodata->atoms.SDL_FORMATS, GetWindow(_this), CurrentTime); 1001 1048 } 1049 + 1050 + return; 1002 1051 } 1003 1052 #endif // SDL_VIDEO_DRIVER_X11_XFIXES 1004 1053
+4
src/video/x11/SDL_x11video.c
··· 403 403 GET_ATOM(_NET_WM_STATE_ABOVE); 404 404 GET_ATOM(_NET_WM_STATE_SKIP_TASKBAR); 405 405 GET_ATOM(_NET_WM_STATE_SKIP_PAGER); 406 + GET_ATOM(_NET_WM_MOVERESIZE); 406 407 GET_ATOM(_NET_WM_STATE_MODAL); 407 408 GET_ATOM(_NET_WM_ALLOWED_ACTIONS); 408 409 GET_ATOM(_NET_WM_ACTION_FULLSCREEN); ··· 420 421 GET_ATOM(CLIPBOARD); 421 422 GET_ATOM(INCR); 422 423 GET_ATOM(SDL_SELECTION); 424 + GET_ATOM(TARGETS); 425 + GET_ATOM(SDL_FORMATS); 426 + GET_ATOM(XdndAware); 423 427 GET_ATOM(XdndEnter); 424 428 GET_ATOM(XdndPosition); 425 429 GET_ATOM(XdndStatus);
+4
src/video/x11/SDL_x11video.h
··· 82 82 Atom _NET_WM_STATE_SKIP_TASKBAR; 83 83 Atom _NET_WM_STATE_SKIP_PAGER; 84 84 Atom _NET_WM_STATE_MODAL; 85 + Atom _NET_WM_MOVERESIZE; 85 86 Atom _NET_WM_ALLOWED_ACTIONS; 86 87 Atom _NET_WM_ACTION_FULLSCREEN; 87 88 Atom _NET_WM_NAME; ··· 98 99 Atom CLIPBOARD; 99 100 Atom INCR; 100 101 Atom SDL_SELECTION; 102 + Atom TARGETS; 103 + Atom SDL_FORMATS; 104 + Atom XdndAware; 101 105 Atom XdndEnter; 102 106 Atom XdndPosition; 103 107 Atom XdndStatus;
+1 -1
src/video/x11/SDL_x11window.c
··· 2001 2001 { 2002 2002 SDL_WindowData *data = window->internal; 2003 2003 Display *display = data->videodata->display; 2004 - Atom XdndAware = X11_XInternAtom(display, "XdndAware", False); 2004 + Atom XdndAware = data->videodata->atoms.XdndAware; 2005 2005 2006 2006 if (accept) { 2007 2007 Atom xdnd_version = 5;
+1 -1
src/video/x11/SDL_x11xfixes.c
··· 51 51 int event, error; 52 52 int fixes_opcode; 53 53 54 - Atom XA_CLIPBOARD = X11_XInternAtom(data->display, "CLIPBOARD", 0); 54 + Atom XA_CLIPBOARD = data->atoms.CLIPBOARD; 55 55 56 56 if (!SDL_X11_HAVE_XFIXES || 57 57 !X11_XQueryExtension(data->display, "XFIXES", &fixes_opcode, &event, &error)) {