1 /*
2 pygame - Python Game Library
3 Copyright (C) 2000-2001 Pete Shinners
4 Copyright (C) 2008 Marcus von Appen
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public
17 License along with this library; if not, write to the Free
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 Pete Shinners
21 pete@shinners.org
22 */
23
24 /*
25 * internal surface locking support for python objects
26 */
27 #define PYGAMEAPI_SURFLOCK_INTERNAL
28
29 #include "pygame.h"
30
31 #include "pgcompat.h"
32
33 static int
34 pgSurface_Lock(pgSurfaceObject *);
35 static int
36 pgSurface_Unlock(pgSurfaceObject *);
37 static int
38 pgSurface_LockBy(pgSurfaceObject *, PyObject *);
39 static int
40 pgSurface_UnlockBy(pgSurfaceObject *, PyObject *);
41
42 static void
43 _lifelock_dealloc(PyObject *);
44
45 static void
pgSurface_Prep(pgSurfaceObject * surfobj)46 pgSurface_Prep(pgSurfaceObject *surfobj)
47 {
48 struct pgSubSurface_Data *data = ((pgSurfaceObject *)surfobj)->subsurface;
49 if (data != NULL) {
50 SDL_Surface *surf = pgSurface_AsSurface(surfobj);
51 SDL_Surface *owner = pgSurface_AsSurface(data->owner);
52 pgSurface_LockBy((pgSurfaceObject *)data->owner, (PyObject *)surfobj);
53 surf->pixels = ((char *)owner->pixels) + data->pixeloffset;
54 }
55 }
56
57 static void
pgSurface_Unprep(pgSurfaceObject * surfobj)58 pgSurface_Unprep(pgSurfaceObject *surfobj)
59 {
60 struct pgSubSurface_Data *data = ((pgSurfaceObject *)surfobj)->subsurface;
61 if (data != NULL) {
62 pgSurface_UnlockBy((pgSurfaceObject *)data->owner,
63 (PyObject *)surfobj);
64 }
65 }
66
67 static int
pgSurface_Lock(pgSurfaceObject * surfobj)68 pgSurface_Lock(pgSurfaceObject *surfobj)
69 {
70 return pgSurface_LockBy(surfobj, (PyObject *)surfobj);
71 }
72
73 static int
pgSurface_Unlock(pgSurfaceObject * surfobj)74 pgSurface_Unlock(pgSurfaceObject *surfobj)
75 {
76 return pgSurface_UnlockBy(surfobj, (PyObject *)surfobj);
77 }
78
79 static int
pgSurface_LockBy(pgSurfaceObject * surfobj,PyObject * lockobj)80 pgSurface_LockBy(pgSurfaceObject *surfobj, PyObject *lockobj)
81 {
82 PyObject *ref;
83 pgSurfaceObject *surf = (pgSurfaceObject *)surfobj;
84
85 if (surf->locklist == NULL) {
86 surf->locklist = PyList_New(0);
87 if (surf->locklist == NULL) {
88 return 0;
89 }
90 }
91 ref = PyWeakref_NewRef(lockobj, NULL);
92 if (ref == NULL) {
93 return 0;
94 }
95 if (ref == Py_None) {
96 Py_DECREF(ref);
97 return 0;
98 }
99 if (0 != PyList_Append(surf->locklist, ref)) {
100 Py_DECREF(ref);
101 return 0; /* Exception already set. */
102 }
103 Py_DECREF(ref);
104
105 if (surf->subsurface != NULL) {
106 pgSurface_Prep(surfobj);
107 }
108 if (SDL_LockSurface(surf->surf) == -1) {
109 PyErr_SetString(PyExc_RuntimeError, "error locking surface");
110 return 0;
111 }
112 return 1;
113 }
114
115 static int
pgSurface_UnlockBy(pgSurfaceObject * surfobj,PyObject * lockobj)116 pgSurface_UnlockBy(pgSurfaceObject *surfobj, PyObject *lockobj)
117 {
118 pgSurfaceObject *surf = (pgSurfaceObject *)surfobj;
119 int found = 0;
120 int noerror = 1;
121
122 if (surf->locklist != NULL) {
123 PyObject *item, *ref;
124 Py_ssize_t len = PyList_Size(surf->locklist);
125 while (--len >= 0 && !found) {
126 item = PyList_GetItem(surf->locklist, len);
127 ref = PyWeakref_GetObject(item);
128 if (ref == lockobj) {
129 if (PySequence_DelItem(surf->locklist, len) == -1) {
130 return 0;
131 }
132 else {
133 found = 1;
134 }
135 }
136 }
137
138 /* Clear dead references */
139 len = PyList_Size(surf->locklist);
140 while (--len >= 0) {
141 item = PyList_GetItem(surf->locklist, len);
142 ref = PyWeakref_GetObject(item);
143 if (ref == Py_None) {
144 if (PySequence_DelItem(surf->locklist, len) == -1) {
145 noerror = 0;
146 }
147 else {
148 found++;
149 }
150 }
151 }
152 }
153
154 if (!found) {
155 return noerror;
156 }
157
158 /* Release all found locks. */
159 while (found > 0) {
160 if (surf->surf != NULL) {
161 SDL_UnlockSurface(surf->surf);
162 }
163 if (surf->subsurface != NULL) {
164 pgSurface_Unprep(surfobj);
165 }
166 found--;
167 }
168
169 return noerror;
170 }
171
172 static PyTypeObject pgLifetimeLock_Type = {
173 PyVarObject_HEAD_INIT(NULL,0)
174 "SurfLifeLock", /* name */
175 sizeof(pgLifetimeLockObject), /* basic size */
176 0, /* tp_itemsize */
177 _lifelock_dealloc, /* tp_dealloc*/
178 0, /* tp_print */
179 NULL, /* tp_getattr */
180 NULL, /* tp_setattr */
181 NULL, /* tp_compare */
182 NULL, /* tp_repr */
183 NULL, /* tp_as_number */
184 NULL, /* tp_as_sequence */
185 NULL, /* tp_as_mapping */
186 NULL, /* tp_hash */
187 NULL, /* tp_call */
188 NULL, /* tp_str */
189 NULL, /* tp_getattro */
190 NULL, /* tp_setattro */
191 NULL, /* tp_as_buffer */
192 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_WEAKREFS,
193 NULL, /* tp_doc */
194 NULL, /* tp_traverse */
195 NULL, /* tp_clear */
196 NULL, /* tp_richcompare */
197 offsetof(pgLifetimeLockObject, weakrefs), /* tp_weaklistoffset */
198 NULL, /* tp_iter */
199 NULL, /* tp_iternext */
200 NULL, /* tp_methods */
201 NULL, /* tp_members */
202 NULL, /* tp_getset */
203 NULL, /* tp_base */
204 NULL, /* tp_dict */
205 NULL, /* tp_descr_get */
206 NULL, /* tp_descr_set */
207 0, /* tp_dictoffset */
208 NULL, /* tp_init */
209 NULL, /* tp_alloc */
210 NULL, /* tp_new */
211 NULL, /* tp_free */
212 NULL, /* tp_is_gc */
213 NULL, /* tp_bases */
214 NULL, /* tp_mro */
215 NULL, /* tp_cache */
216 NULL, /* tp_subclasses */
217 NULL, /* tp_weaklist */
218 NULL /* tp_del */
219 };
220
221 /* lifetimelock object internals */
222 static void
_lifelock_dealloc(PyObject * self)223 _lifelock_dealloc(PyObject *self)
224 {
225 pgLifetimeLockObject *lifelock = (pgLifetimeLockObject *)self;
226
227 if (lifelock->weakrefs != NULL) {
228 PyObject_ClearWeakRefs(self);
229 }
230
231 pgSurface_UnlockBy((pgSurfaceObject *)lifelock->surface,
232 lifelock->lockobj);
233 Py_DECREF(lifelock->surface);
234 PyObject_DEL(self);
235 }
236
237 static PyObject *
pgSurface_LockLifetime(PyObject * surfobj,PyObject * lockobj)238 pgSurface_LockLifetime(PyObject *surfobj, PyObject *lockobj)
239 {
240 pgLifetimeLockObject *life;
241 if (surfobj == NULL) {
242 return RAISE(pgExc_SDLError, SDL_GetError());
243 }
244
245 life = PyObject_NEW(pgLifetimeLockObject, &pgLifetimeLock_Type);
246 if (life != NULL) {
247 life->surface = surfobj;
248 life->lockobj = lockobj;
249 life->weakrefs = NULL;
250 Py_INCREF(surfobj);
251 if (!pgSurface_LockBy((pgSurfaceObject *)surfobj, lockobj)) {
252 return NULL;
253 }
254 }
255 return (PyObject *)life;
256 }
257
258 static PyMethodDef _surflock_methods[] = {{NULL, NULL, 0, NULL}};
259
260 /*DOC*/ static char _surflock_doc[] =
261 /*DOC*/ "Surface locking support";
262
MODINIT_DEFINE(surflock)263 MODINIT_DEFINE(surflock)
264 {
265 PyObject *module, *dict, *apiobj;
266 int ecode;
267 static void *c_api[PYGAMEAPI_SURFLOCK_NUMSLOTS];
268
269 static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT,
270 "surflock",
271 _surflock_doc,
272 -1,
273 _surflock_methods,
274 NULL,
275 NULL,
276 NULL,
277 NULL};
278
279 if (PyType_Ready(&pgLifetimeLock_Type) < 0) {
280 MODINIT_ERROR;
281 }
282
283 /* Create the module and add the functions */
284 module = PyModule_Create(&_module);
285 if (module == NULL) {
286 MODINIT_ERROR;
287 }
288 dict = PyModule_GetDict(module);
289
290 /* export the c api */
291 c_api[0] = &pgLifetimeLock_Type;
292 c_api[1] = pgSurface_Prep;
293 c_api[2] = pgSurface_Unprep;
294 c_api[3] = pgSurface_Lock;
295 c_api[4] = pgSurface_Unlock;
296 c_api[5] = pgSurface_LockBy;
297 c_api[6] = pgSurface_UnlockBy;
298 c_api[7] = pgSurface_LockLifetime;
299 apiobj = encapsulate_api(c_api, "surflock");
300 if (apiobj == NULL) {
301 DECREF_MOD(module);
302 MODINIT_ERROR;
303 }
304 ecode = PyDict_SetItemString(dict, PYGAMEAPI_LOCAL_ENTRY, apiobj);
305 Py_DECREF(apiobj);
306 if (ecode) {
307 DECREF_MOD(module);
308 MODINIT_ERROR;
309 }
310 MODINIT_RETURN(module);
311 }
312