Skip to content

Commit 7e91c13

Browse files
committed
Fix ascii scrap on sdl2 backend, docs/tests fixes
1 parent c951503 commit 7e91c13

File tree

3 files changed

+52
-94
lines changed

3 files changed

+52
-94
lines changed

docs/reST/ref/scrap.rst

Lines changed: 8 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -77,43 +77,21 @@ data (MIME) types are defined and registered:
7777

7878
::
7979

80-
pygame string
81-
constant value description
82-
--------------------------------------------------
83-
SCRAP_TEXT "text/plain" plain text
84-
SCRAP_BMP "image/bmp" BMP encoded image data
85-
SCRAP_PBM "image/pbm" PBM encoded image data
86-
SCRAP_PPM "image/ppm" PPM encoded image data
87-
88-
``pygame.SCRAP_PPM``, ``pygame.SCRAP_PBM`` and ``pygame.SCRAP_BMP`` are
89-
suitable for surface buffers to be shared with other applications.
90-
``pygame.SCRAP_TEXT`` is an alias for the plain text clipboard type.
91-
92-
Depending on the platform, additional types are automatically registered when
93-
data is placed into the clipboard to guarantee a consistent sharing behaviour
94-
with other applications. The following listed types can be used as strings to
95-
be passed to the respective :mod:`pygame.scrap` module functions.
80+
"text/plain" Plain text (also accessible via the SCRAP_TEXT constant)
81+
"text/plain;charset=utf-8" UTF-8 encoded text
9682

9783
For **Windows** platforms, these additional types are supported automatically
9884
and resolve to their internal definitions:
9985

10086
::
10187

102-
"text/plain;charset=utf-8" UTF-8 encoded text
88+
"image/bmp" BMP encoded image data (also accessible via the SCRAP_BMP constant)
10389
"audio/wav" WAV encoded audio
10490
"image/tiff" TIFF encoded image data
10591

106-
For **X11** platforms, these additional types are supported automatically and
107-
resolve to their internal definitions:
108-
109-
::
110-
111-
"text/plain;charset=utf-8" UTF-8 encoded text
112-
"UTF8_STRING" UTF-8 encoded text
113-
"COMPOUND_TEXT" COMPOUND text
11492

115-
User defined types can be used, but the data might not be accessible by other
116-
applications unless they know what data type to look for.
93+
User defined types can be used on **Windows**, but the data might not be
94+
accessible by other applications unless they know what data type to look for.
11795
Example: Data placed into the clipboard by
11896
``pygame.scrap.put("my_data_type", byte_data)`` can only be accessed by
11997
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
125103
.. versionaddedold:: 1.8
126104

127105
.. note::
128-
The scrap module is currently only supported for Windows, X11 and Mac OS X.
129-
On Mac OS X only text works at the moment - other types may be supported in
130-
future releases.
106+
Non-text data is only supported on Windows. On other platforms only text is supported.
131107

132108
.. function:: init
133109

@@ -221,8 +197,8 @@ For an example of how the scrap module works refer to the examples page
221197
Places data for a given clipboard type into the clipboard. The data must
222198
be a string buffer. The type is a string identifying the type of data to be
223199
placed into the clipboard. This can be one of the predefined
224-
``pygame.SCRAP_PBM``, ``pygame.SCRAP_PPM``, ``pygame.SCRAP_BMP`` or
225-
``pygame.SCRAP_TEXT`` values or a user defined string identifier.
200+
``pygame.SCRAP_BMP`` or ``pygame.SCRAP_TEXT`` values or a user defined
201+
string identifier.
226202

227203
:param string type: type identifier of the data to be placed into the
228204
clipboard

src_c/scrap_sdl2.c

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,30 @@
88

99
#define PYGAME_SCRAP_FREE_STRING 1
1010

11-
char *pygame_scrap_plaintext_type = "text/plain;charset=utf-8";
11+
char *pygame_scrap_plaintext_type = "text/plain";
12+
char *pygame_scrap_utf8text_type = "text/plain;charset=utf-8";
1213
char **pygame_scrap_types;
1314

1415
int
1516
pygame_scrap_contains(char *type)
1617
{
17-
return (strcmp(type, pygame_scrap_plaintext_type) == 0) &&
18+
return (strcmp(type, pygame_scrap_plaintext_type) == 0 ||
19+
strcmp(type, pygame_scrap_utf8text_type) == 0) &&
1820
SDL_HasClipboardText();
1921
}
2022

23+
bool
24+
_pg_is_ascii_str(const char *str)
25+
{
26+
while (*str) {
27+
if ((unsigned char)*str > 127) {
28+
return false;
29+
}
30+
str++;
31+
}
32+
return true;
33+
}
34+
2135
char *
2236
pygame_scrap_get(char *type, size_t *count)
2337
{
@@ -28,11 +42,18 @@ pygame_scrap_get(char *type, size_t *count)
2842
return RAISE(pgExc_SDLError, "scrap system not initialized.");
2943
}
3044

31-
if (strcmp(type, pygame_scrap_plaintext_type) == 0) {
45+
int is_ascii = strcmp(type, pygame_scrap_plaintext_type) == 0;
46+
if (is_ascii || strcmp(type, pygame_scrap_utf8text_type) == 0) {
3247
clipboard = SDL_GetClipboardText();
3348
if (clipboard != NULL) {
34-
*count = strlen(clipboard);
35-
retval = strdup(clipboard);
49+
if (is_ascii && !_pg_is_ascii_str(clipboard)) {
50+
*count = 0;
51+
retval = NULL;
52+
}
53+
else {
54+
*count = strlen(clipboard);
55+
retval = strdup(clipboard);
56+
}
3657
SDL_free(clipboard);
3758
return retval;
3859
}
@@ -56,13 +77,14 @@ pygame_scrap_init(void)
5677
{
5778
SDL_Init(SDL_INIT_VIDEO);
5879

59-
pygame_scrap_types = malloc(sizeof(char *) * 2);
80+
pygame_scrap_types = malloc(sizeof(char *) * 3);
6081
if (!pygame_scrap_types) {
6182
return 0;
6283
}
6384

6485
pygame_scrap_types[0] = pygame_scrap_plaintext_type;
65-
pygame_scrap_types[1] = NULL;
86+
pygame_scrap_types[1] = pygame_scrap_utf8text_type;
87+
pygame_scrap_types[2] = NULL;
6688

6789
_scrapinitialized = 1;
6890
return _scrapinitialized;
@@ -82,7 +104,8 @@ pygame_scrap_put(char *type, Py_ssize_t srclen, char *src)
82104
return 0;
83105
}
84106

85-
if (strcmp(type, pygame_scrap_plaintext_type) == 0) {
107+
if (strcmp(type, pygame_scrap_plaintext_type) ||
108+
strcmp(type, pygame_scrap_utf8text_type) == 0) {
86109
if (SDL_SetClipboardText(src) == 0) {
87110
return 1;
88111
}

test/scrap_test.py

Lines changed: 13 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import platform
23
import sys
34
import unittest
45

@@ -51,6 +52,10 @@ def todo_test_get(self):
5152
"""Ensures get works as expected."""
5253
self.fail()
5354

55+
@unittest.skipIf(
56+
platform.system() != "Windows",
57+
"scrap features are broken on non windows platforms",
58+
)
5459
def test_get__owned_empty_type(self):
5560
"""Ensures get works when there is no data of the requested type
5661
in the clipboard and the clipboard is owned by the pygame application.
@@ -95,7 +100,10 @@ def test_put__text(self):
95100

96101
self.assertEqual(scrap.get(pygame.SCRAP_TEXT), b"Another String")
97102

98-
@unittest.skipIf("pygame.image" not in sys.modules, "requires pygame.image module")
103+
@unittest.skipIf(
104+
platform.system() != "Windows",
105+
"scrap features are broken on non windows platforms",
106+
)
99107
def test_put__bmp_image(self):
100108
"""Ensures put can place a BMP image into the clipboard."""
101109
sf = pygame.image.load(trunk_relative_path("examples/data/asprite.bmp"))
@@ -104,6 +112,10 @@ def test_put__bmp_image(self):
104112

105113
self.assertEqual(scrap.get(pygame.SCRAP_BMP), expected_bytes)
106114

115+
@unittest.skipIf(
116+
platform.system() != "Windows",
117+
"scrap features are broken on non windows platforms",
118+
)
107119
def test_put(self):
108120
"""Ensures put can place data into the clipboard
109121
when using a user defined type identifier.
@@ -205,59 +217,6 @@ def test_lost__not_owned(self):
205217
self.assertTrue(lost)
206218

207219

208-
class X11InteractiveTest(unittest.TestCase):
209-
__tags__ = ["ignore", "subprocess_ignore"]
210-
try:
211-
pygame.display.init()
212-
except Exception:
213-
pass
214-
else:
215-
if pygame.display.get_driver() == "x11":
216-
__tags__ = ["interactive"]
217-
pygame.display.quit()
218-
219-
def test_issue_223(self):
220-
"""PATCH: pygame.scrap on X11, fix copying into PRIMARY selection
221-
222-
Copying into theX11 PRIMARY selection (mouse copy/paste) would not
223-
work due to a confusion between content type and clipboard type.
224-
225-
"""
226-
227-
from pygame import display, event, freetype
228-
from pygame.locals import KEYDOWN, QUIT, SCRAP_SELECTION, SCRAP_TEXT, K_y
229-
230-
success = False
231-
freetype.init()
232-
font = freetype.Font(None, 24)
233-
display.init()
234-
display.set_caption("Interactive X11 Paste Test")
235-
screen = display.set_mode((600, 200))
236-
screen.fill(pygame.Color("white"))
237-
text = "Scrap put() succeeded."
238-
msg = (
239-
"Some text has been placed into the X11 clipboard."
240-
" Please click the center mouse button in an open"
241-
" text window to retrieve it."
242-
'\n\nDid you get "{}"? (y/n)'
243-
).format(text)
244-
word_wrap(screen, msg, font, 6)
245-
display.flip()
246-
event.pump()
247-
scrap.init()
248-
scrap.set_mode(SCRAP_SELECTION)
249-
scrap.put(SCRAP_TEXT, text.encode("UTF-8"))
250-
while True:
251-
e = event.wait()
252-
if e.type == QUIT:
253-
break
254-
if e.type == KEYDOWN:
255-
success = e.key == K_y
256-
break
257-
pygame.display.quit()
258-
self.assertTrue(success)
259-
260-
261220
def word_wrap(surf, text, font, margin=0, color=(0, 0, 0)):
262221
font.origin = True
263222
surf_width, surf_height = surf.get_size()

0 commit comments

Comments
 (0)