diff --git a/docs/reST/ref/scrap.rst b/docs/reST/ref/scrap.rst index e44f6e28f3..27d1cc281a 100644 --- a/docs/reST/ref/scrap.rst +++ b/docs/reST/ref/scrap.rst @@ -77,43 +77,21 @@ data (MIME) types are defined and registered: :: - pygame string - constant value description - -------------------------------------------------- - SCRAP_TEXT "text/plain" plain text - SCRAP_BMP "image/bmp" BMP encoded image data - SCRAP_PBM "image/pbm" PBM encoded image data - SCRAP_PPM "image/ppm" PPM encoded image data - -``pygame.SCRAP_PPM``, ``pygame.SCRAP_PBM`` and ``pygame.SCRAP_BMP`` are -suitable for surface buffers to be shared with other applications. -``pygame.SCRAP_TEXT`` is an alias for the plain text clipboard type. - -Depending on the platform, additional types are automatically registered when -data is placed into the clipboard to guarantee a consistent sharing behaviour -with other applications. The following listed types can be used as strings to -be passed to the respective :mod:`pygame.scrap` module functions. + "text/plain" Plain text (also accessible via the SCRAP_TEXT constant) + "text/plain;charset=utf-8" UTF-8 encoded text For **Windows** platforms, these additional types are supported automatically and resolve to their internal definitions: :: - "text/plain;charset=utf-8" UTF-8 encoded text + "image/bmp" BMP encoded image data (also accessible via the SCRAP_BMP constant) "audio/wav" WAV encoded audio "image/tiff" TIFF encoded image data -For **X11** platforms, these additional types are supported automatically and -resolve to their internal definitions: - -:: - - "text/plain;charset=utf-8" UTF-8 encoded text - "UTF8_STRING" UTF-8 encoded text - "COMPOUND_TEXT" COMPOUND text -User defined types can be used, but the data might not be accessible by other -applications unless they know what data type to look for. +User defined types can be used on **Windows**, but the data might not be +accessible by other applications unless they know what data type to look for. Example: Data placed into the clipboard by ``pygame.scrap.put("my_data_type", byte_data)`` can only be accessed by applications which query the clipboard for the ``"my_data_type"`` data type. @@ -125,9 +103,7 @@ For an example of how the scrap module works refer to the examples page .. versionaddedold:: 1.8 .. note:: - The scrap module is currently only supported for Windows, X11 and Mac OS X. - On Mac OS X only text works at the moment - other types may be supported in - future releases. + Non-text data is only supported on Windows. On other platforms only text is supported. .. function:: init @@ -221,8 +197,8 @@ For an example of how the scrap module works refer to the examples page Places data for a given clipboard type into the clipboard. The data must be a string buffer. The type is a string identifying the type of data to be placed into the clipboard. This can be one of the predefined - ``pygame.SCRAP_PBM``, ``pygame.SCRAP_PPM``, ``pygame.SCRAP_BMP`` or - ``pygame.SCRAP_TEXT`` values or a user defined string identifier. + ``pygame.SCRAP_BMP`` or ``pygame.SCRAP_TEXT`` values or a user defined + string identifier. :param string type: type identifier of the data to be placed into the clipboard diff --git a/src_c/scrap_sdl2.c b/src_c/scrap_sdl2.c index 5de1f4cdbc..642fa432df 100644 --- a/src_c/scrap_sdl2.c +++ b/src_c/scrap_sdl2.c @@ -8,16 +8,30 @@ #define PYGAME_SCRAP_FREE_STRING 1 -char *pygame_scrap_plaintext_type = "text/plain;charset=utf-8"; +char *pygame_scrap_plaintext_type = "text/plain"; +char *pygame_scrap_utf8text_type = "text/plain;charset=utf-8"; char **pygame_scrap_types; int pygame_scrap_contains(char *type) { - return (strcmp(type, pygame_scrap_plaintext_type) == 0) && + return (strcmp(type, pygame_scrap_plaintext_type) == 0 || + strcmp(type, pygame_scrap_utf8text_type) == 0) && SDL_HasClipboardText(); } +bool +_pg_is_ascii_str(const char *str) +{ + while (*str) { + if ((unsigned char)*str > 127) { + return false; + } + str++; + } + return true; +} + char * pygame_scrap_get(char *type, size_t *count) { @@ -28,11 +42,18 @@ pygame_scrap_get(char *type, size_t *count) return RAISE(pgExc_SDLError, "scrap system not initialized."); } - if (strcmp(type, pygame_scrap_plaintext_type) == 0) { + int is_ascii = strcmp(type, pygame_scrap_plaintext_type) == 0; + if (is_ascii || strcmp(type, pygame_scrap_utf8text_type) == 0) { clipboard = SDL_GetClipboardText(); if (clipboard != NULL) { - *count = strlen(clipboard); - retval = strdup(clipboard); + if (is_ascii && !_pg_is_ascii_str(clipboard)) { + *count = 0; + retval = NULL; + } + else { + *count = strlen(clipboard); + retval = strdup(clipboard); + } SDL_free(clipboard); return retval; } @@ -56,13 +77,14 @@ pygame_scrap_init(void) { SDL_Init(SDL_INIT_VIDEO); - pygame_scrap_types = malloc(sizeof(char *) * 2); + pygame_scrap_types = malloc(sizeof(char *) * 3); if (!pygame_scrap_types) { return 0; } pygame_scrap_types[0] = pygame_scrap_plaintext_type; - pygame_scrap_types[1] = NULL; + pygame_scrap_types[1] = pygame_scrap_utf8text_type; + pygame_scrap_types[2] = NULL; _scrapinitialized = 1; return _scrapinitialized; @@ -82,7 +104,8 @@ pygame_scrap_put(char *type, Py_ssize_t srclen, char *src) return 0; } - if (strcmp(type, pygame_scrap_plaintext_type) == 0) { + if (strcmp(type, pygame_scrap_plaintext_type) == 0 || + strcmp(type, pygame_scrap_utf8text_type) == 0) { if (SDL_SetClipboardText(src) == 0) { return 1; } diff --git a/test/scrap_test.py b/test/scrap_test.py index a62d31c6ea..e7dfa4efdf 100644 --- a/test/scrap_test.py +++ b/test/scrap_test.py @@ -1,4 +1,5 @@ import os +import platform import sys import unittest @@ -51,6 +52,10 @@ def todo_test_get(self): """Ensures get works as expected.""" self.fail() + @unittest.skipIf( + platform.system() != "Windows", + "scrap features are broken on non windows platforms", + ) def test_get__owned_empty_type(self): """Ensures get works when there is no data of the requested type in the clipboard and the clipboard is owned by the pygame application. @@ -95,7 +100,10 @@ def test_put__text(self): self.assertEqual(scrap.get(pygame.SCRAP_TEXT), b"Another String") - @unittest.skipIf("pygame.image" not in sys.modules, "requires pygame.image module") + @unittest.skipIf( + platform.system() != "Windows", + "scrap features are broken on non windows platforms", + ) def test_put__bmp_image(self): """Ensures put can place a BMP image into the clipboard.""" sf = pygame.image.load(trunk_relative_path("examples/data/asprite.bmp")) @@ -104,6 +112,10 @@ def test_put__bmp_image(self): self.assertEqual(scrap.get(pygame.SCRAP_BMP), expected_bytes) + @unittest.skipIf( + platform.system() != "Windows", + "scrap features are broken on non windows platforms", + ) def test_put(self): """Ensures put can place data into the clipboard when using a user defined type identifier. @@ -205,59 +217,6 @@ def test_lost__not_owned(self): self.assertTrue(lost) -class X11InteractiveTest(unittest.TestCase): - __tags__ = ["ignore", "subprocess_ignore"] - try: - pygame.display.init() - except Exception: - pass - else: - if pygame.display.get_driver() == "x11": - __tags__ = ["interactive"] - pygame.display.quit() - - def test_issue_223(self): - """PATCH: pygame.scrap on X11, fix copying into PRIMARY selection - - Copying into theX11 PRIMARY selection (mouse copy/paste) would not - work due to a confusion between content type and clipboard type. - - """ - - from pygame import display, event, freetype - from pygame.locals import KEYDOWN, QUIT, SCRAP_SELECTION, SCRAP_TEXT, K_y - - success = False - freetype.init() - font = freetype.Font(None, 24) - display.init() - display.set_caption("Interactive X11 Paste Test") - screen = display.set_mode((600, 200)) - screen.fill(pygame.Color("white")) - text = "Scrap put() succeeded." - msg = ( - "Some text has been placed into the X11 clipboard." - " Please click the center mouse button in an open" - " text window to retrieve it." - '\n\nDid you get "{}"? (y/n)' - ).format(text) - word_wrap(screen, msg, font, 6) - display.flip() - event.pump() - scrap.init() - scrap.set_mode(SCRAP_SELECTION) - scrap.put(SCRAP_TEXT, text.encode("UTF-8")) - while True: - e = event.wait() - if e.type == QUIT: - break - if e.type == KEYDOWN: - success = e.key == K_y - break - pygame.display.quit() - self.assertTrue(success) - - def word_wrap(surf, text, font, margin=0, color=(0, 0, 0)): font.origin = True surf_width, surf_height = surf.get_size()