1 /*
2 pygame - Python Game Library
3 Copyright (C) 2000-2001 Pete Shinners
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Pete Shinners
20 pete@shinners.org
21 */
22
23 /*
24 * pygame display module
25 */
26 #define PYGAMEAPI_DISPLAY_INTERNAL
27 #include "pygame.h"
28
29 #include "pgcompat.h"
30 #include "pgopengl.h"
31
32 #include "doc/display_doc.h"
33
34 #include <SDL_syswm.h>
35
36 static PyTypeObject pgVidInfo_Type;
37
38
39 static PyObject *
40 pgVidInfo_New(const pg_VideoInfo *info);
41
42 static SDL_Renderer *pg_renderer = NULL;
43 static SDL_Texture *pg_texture = NULL;
44
45 typedef struct _display_state_s {
46 char *title;
47 PyObject *icon;
48 Uint16 *gamma_ramp;
49 SDL_GLContext gl_context;
50 int toggle_windowed_w;
51 int toggle_windowed_h;
52 Uint8 using_gl; /* using an OPENGL display without renderer */
53 Uint8 scaled_gl;
54 int scaled_gl_w;
55 int scaled_gl_h;
56 int fullscreen_backup_x;
57 int fullscreen_backup_y;
58 SDL_bool auto_resize;
59 } _DisplayState;
60
61 static int
62 pg_flip_internal(_DisplayState *state);
63
64 #ifndef PYPY_VERSION
65 static struct PyModuleDef _module;
66 #define DISPLAY_MOD_STATE(mod) ((_DisplayState *)PyModule_GetState(mod))
67 #define DISPLAY_STATE DISPLAY_MOD_STATE(PyState_FindModule(&_module))
68 #else /* PYPY_VERSION */
69 static struct PyModuleDef _module;
70 static _DisplayState _modstate = {0};
71 #define DISPLAY_MOD_STATE(mod) (&_modstate)
72 #define DISPLAY_STATE DISPLAY_MOD_STATE(0)
73 #endif /* PYPY_VERSION */
74
75 static void
_display_state_cleanup(_DisplayState * state)76 _display_state_cleanup(_DisplayState *state)
77 {
78 if (state->title) {
79 free(state->title);
80 state->title = NULL;
81 }
82 if (state->icon) {
83 Py_XDECREF(state->icon);
84 state->icon = NULL;
85 }
86 if (state->gl_context) {
87 SDL_GL_DeleteContext(state->gl_context);
88 state->gl_context = NULL;
89 }
90 if (state->gamma_ramp) {
91 free(state->gamma_ramp);
92 state->gamma_ramp = NULL;
93 }
94 }
95
96
97 static char *icon_defaultname = "pygame_icon.bmp";
98 static char *pkgdatamodule_name = "pygame.pkgdata";
99 static char *imagemodule_name = "pygame.image";
100 static char *resourcefunc_name = "getResource";
101 static char *load_basicfunc_name = "load_basic";
102
103 static void
pg_close_file(PyObject * fileobj)104 pg_close_file(PyObject *fileobj)
105 {
106 PyObject *result = PyObject_CallMethod(fileobj, "close", NULL);
107 if (result) {
108 Py_DECREF(result);
109 }
110 else {
111 PyErr_Clear();
112 }
113 }
114
115 static PyObject *
pg_display_resource(char * filename)116 pg_display_resource(char *filename)
117 {
118 PyObject *imagemodule = NULL;
119 PyObject *load_basicfunc = NULL;
120 PyObject *pkgdatamodule = NULL;
121 PyObject *resourcefunc = NULL;
122 PyObject *fresult = NULL;
123 PyObject *result = NULL;
124 PyObject *name = NULL;
125
126 pkgdatamodule = PyImport_ImportModule(pkgdatamodule_name);
127 if (!pkgdatamodule)
128 goto display_resource_end;
129
130 resourcefunc = PyObject_GetAttrString(pkgdatamodule, resourcefunc_name);
131 if (!resourcefunc)
132 goto display_resource_end;
133
134 imagemodule = PyImport_ImportModule(imagemodule_name);
135 if (!imagemodule)
136 goto display_resource_end;
137
138 load_basicfunc = PyObject_GetAttrString(imagemodule, load_basicfunc_name);
139 if (!load_basicfunc)
140 goto display_resource_end;
141
142 fresult = PyObject_CallFunction(resourcefunc, "s", filename);
143 if (!fresult)
144 goto display_resource_end;
145
146 name = PyObject_GetAttrString(fresult, "name");
147 if (name != NULL) {
148 if (Text_Check(name)) {
149 pg_close_file(fresult);
150 Py_DECREF(fresult);
151 fresult = name;
152 name = NULL;
153 }
154 }
155 else {
156 PyErr_Clear();
157 }
158
159 result = PyObject_CallFunction(load_basicfunc, "O", fresult);
160 if (!result)
161 goto display_resource_end;
162
163 display_resource_end:
164 Py_XDECREF(pkgdatamodule);
165 Py_XDECREF(resourcefunc);
166 Py_XDECREF(imagemodule);
167 Py_XDECREF(load_basicfunc);
168 Py_XDECREF(fresult);
169 Py_XDECREF(name);
170 return result;
171 }
172
173 /* init routines */
174 static PyObject *
pg_display_quit(PyObject * self)175 pg_display_quit(PyObject *self)
176 {
177 _DisplayState *state = DISPLAY_STATE;
178 _display_state_cleanup(state);
179 if (pg_GetDefaultWindowSurface()) {
180 pgSurface_AsSurface(pg_GetDefaultWindowSurface()) = NULL;
181 pg_SetDefaultWindowSurface(NULL);
182 pg_SetDefaultWindow(NULL);
183 }
184
185 pg_mod_autoquit(IMPPREFIX "event");
186 pg_mod_autoquit(IMPPREFIX "time");
187
188 if (SDL_WasInit(SDL_INIT_VIDEO)) {
189 SDL_QuitSubSystem(SDL_INIT_VIDEO);
190 }
191 Py_RETURN_NONE;
192 }
193
194 static int
_pg_mac_display_init(void)195 _pg_mac_display_init(void)
196 {
197 #if defined(__APPLE__) && defined(darwin)
198 PyObject *module, *rval;
199 int status;
200
201 module = PyImport_ImportModule("pygame.macosx");
202 if (!module)
203 return 0;
204
205 rval = PyObject_CallMethod(module, "Video_AutoInit", "");
206 Py_DECREF(module);
207 if (!rval)
208 return 0;
209
210 status = PyObject_IsTrue(rval);
211 Py_DECREF(rval);
212 if (status != 1)
213 return 0;
214 #endif /* Mac */
215 return 1;
216 }
217
218 static PyObject *
pg_display_init(PyObject * self)219 pg_display_init(PyObject *self)
220 {
221
222 const char *drivername;
223 /* Compatibility:
224 * windib video driver was renamed in SDL2, and we don't want it to fail.
225 */
226 drivername = SDL_getenv("SDL_VIDEODRIVER");
227 if (drivername && !SDL_strncasecmp("windib", drivername, SDL_strlen(drivername))) {
228 SDL_setenv("SDL_VIDEODRIVER", "windows", 1);
229 }
230 if (!SDL_WasInit(SDL_INIT_VIDEO)) {
231 if (!_pg_mac_display_init())
232 return NULL;
233
234 if (SDL_InitSubSystem(SDL_INIT_VIDEO))
235 return RAISE(pgExc_SDLError, SDL_GetError());
236
237 }
238
239 if (!pg_mod_autoinit(IMPPREFIX "time"))
240 return NULL;
241 if (!pg_mod_autoinit(IMPPREFIX "event"))
242 return NULL;
243
244 Py_RETURN_NONE;
245 }
246
247 static PyObject *
pg_get_init(PyObject * self)248 pg_get_init(PyObject *self)
249 {
250 return PyBool_FromLong(SDL_WasInit(SDL_INIT_VIDEO) != 0);
251 }
252
253 static PyObject *
pg_get_active(PyObject * self)254 pg_get_active(PyObject *self)
255 {
256 Uint32 flags = SDL_GetWindowFlags(pg_GetDefaultWindow());
257 return PyBool_FromLong((flags & SDL_WINDOW_SHOWN) &&
258 !(flags & SDL_WINDOW_MINIMIZED));
259 }
260
261 /* vidinfo object */
262 static void
pg_vidinfo_dealloc(PyObject * self)263 pg_vidinfo_dealloc(PyObject *self)
264 {
265 PyObject_DEL(self);
266 }
267
268 static PyObject *
pg_vidinfo_getattr(PyObject * self,char * name)269 pg_vidinfo_getattr(PyObject *self, char *name)
270 {
271 pg_VideoInfo *info = &((pgVidInfoObject *)self)->info;
272
273 int current_w = -1;
274 int current_h = -1;
275
276 SDL_version versioninfo;
277 SDL_VERSION(&versioninfo);
278
279 if (versioninfo.major > 1 ||
280 (versioninfo.minor >= 2 && versioninfo.patch >= 10)) {
281 current_w = info->current_w;
282 current_h = info->current_h;
283 }
284
285 if (!strcmp(name, "hw"))
286 return PyInt_FromLong(info->hw_available);
287 else if (!strcmp(name, "wm"))
288 return PyInt_FromLong(info->wm_available);
289 else if (!strcmp(name, "blit_hw"))
290 return PyInt_FromLong(info->blit_hw);
291 else if (!strcmp(name, "blit_hw_CC"))
292 return PyInt_FromLong(info->blit_hw_CC);
293 else if (!strcmp(name, "blit_hw_A"))
294 return PyInt_FromLong(info->blit_hw_A);
295 else if (!strcmp(name, "blit_sw"))
296 return PyInt_FromLong(info->blit_hw);
297 else if (!strcmp(name, "blit_sw_CC"))
298 return PyInt_FromLong(info->blit_hw_CC);
299 else if (!strcmp(name, "blit_sw_A"))
300 return PyInt_FromLong(info->blit_hw_A);
301 else if (!strcmp(name, "blit_fill"))
302 return PyInt_FromLong(info->blit_fill);
303 else if (!strcmp(name, "video_mem"))
304 return PyInt_FromLong(info->video_mem);
305 else if (!strcmp(name, "bitsize"))
306 return PyInt_FromLong(info->vfmt->BitsPerPixel);
307 else if (!strcmp(name, "bytesize"))
308 return PyInt_FromLong(info->vfmt->BytesPerPixel);
309 else if (!strcmp(name, "masks"))
310 return Py_BuildValue("(iiii)", info->vfmt->Rmask, info->vfmt->Gmask,
311 info->vfmt->Bmask, info->vfmt->Amask);
312 else if (!strcmp(name, "shifts"))
313 return Py_BuildValue("(iiii)", info->vfmt->Rshift, info->vfmt->Gshift,
314 info->vfmt->Bshift, info->vfmt->Ashift);
315 else if (!strcmp(name, "losses"))
316 return Py_BuildValue("(iiii)", info->vfmt->Rloss, info->vfmt->Gloss,
317 info->vfmt->Bloss, info->vfmt->Aloss);
318 else if (!strcmp(name, "current_h"))
319 return PyInt_FromLong(current_h);
320 else if (!strcmp(name, "current_w"))
321 return PyInt_FromLong(current_w);
322
323 return RAISE(PyExc_AttributeError, "does not exist in vidinfo");
324 }
325
326 PyObject *
pg_vidinfo_str(PyObject * self)327 pg_vidinfo_str(PyObject *self)
328 {
329 char str[1024];
330 int current_w = -1;
331 int current_h = -1;
332 pg_VideoInfo *info = &((pgVidInfoObject *)self)->info;
333
334 SDL_version versioninfo;
335 SDL_VERSION(&versioninfo);
336
337 if (versioninfo.major > 1 ||
338 (versioninfo.minor >= 2 && versioninfo.patch >= 10)) {
339 current_w = info->current_w;
340 current_h = info->current_h;
341 }
342
343 sprintf(str,
344 "<VideoInfo(hw = %d, wm = %d,video_mem = %d\n"
345 " blit_hw = %d, blit_hw_CC = %d, blit_hw_A = %d,\n"
346 " blit_sw = %d, blit_sw_CC = %d, blit_sw_A = %d,\n"
347 " bitsize = %d, bytesize = %d,\n"
348 " masks = (%d, %d, %d, %d),\n"
349 " shifts = (%d, %d, %d, %d),\n"
350 " losses = (%d, %d, %d, %d),\n"
351 " current_w = %d, current_h = %d\n"
352 ">\n",
353 info->hw_available, info->wm_available, info->video_mem,
354 info->blit_hw, info->blit_hw_CC, info->blit_hw_A, info->blit_sw,
355 info->blit_sw_CC, info->blit_sw_A, info->vfmt->BitsPerPixel,
356 info->vfmt->BytesPerPixel, info->vfmt->Rmask, info->vfmt->Gmask,
357 info->vfmt->Bmask, info->vfmt->Amask, info->vfmt->Rshift,
358 info->vfmt->Gshift, info->vfmt->Bshift, info->vfmt->Ashift,
359 info->vfmt->Rloss, info->vfmt->Gloss, info->vfmt->Bloss,
360 info->vfmt->Aloss, current_w, current_h);
361 return Text_FromUTF8(str);
362 }
363
364 static PyTypeObject pgVidInfo_Type = {
365 PyVarObject_HEAD_INIT(NULL,0)
366 "VidInfo", /*name*/
367 sizeof(pgVidInfoObject), /*basic size*/
368 0, /*itemsize*/
369 pg_vidinfo_dealloc, /*dealloc*/
370 0, /*print*/
371 pg_vidinfo_getattr, /*getattr*/
372 NULL, /*setattr*/
373 NULL, /*compare*/
374 pg_vidinfo_str, /*repr*/
375 NULL, /*as_number*/
376 NULL, /*as_sequence*/
377 NULL, /*as_mapping*/
378 (hashfunc)NULL, /*hash*/
379 (ternaryfunc)NULL, /*call*/
380 (reprfunc)NULL, /*str*/
381 };
382
383 static PyObject *
pgVidInfo_New(const pg_VideoInfo * i)384 pgVidInfo_New(const pg_VideoInfo *i)
385 {
386 pgVidInfoObject *info;
387 if (!i)
388 return RAISE(pgExc_SDLError, SDL_GetError());
389 info = PyObject_NEW(pgVidInfoObject, &pgVidInfo_Type);
390 if (!info)
391 return NULL;
392 info->info = *i;
393 info->info.vfmt = &info->info.vfmt_data;
394 return (PyObject *)info;
395 }
396
397 static pg_VideoInfo *
pg_GetVideoInfo(pg_VideoInfo * info)398 pg_GetVideoInfo(pg_VideoInfo *info)
399 {
400 SDL_DisplayMode mode;
401 SDL_PixelFormat *tempformat;
402 Uint32 formatenum;
403 pgSurfaceObject *winsurfobj;
404 SDL_Surface *winsurf;
405
406 #pragma PG_WARN(hardcoding wm_available to 1)
407 #pragma PG_WARN(setting available video RAM to 0 KB)
408
409 memset(info, 0, sizeof(pg_VideoInfo));
410 info->wm_available = 1;
411
412 winsurfobj = pg_GetDefaultWindowSurface();
413 if (winsurfobj) {
414 winsurf = pgSurface_AsSurface(winsurfobj);
415 info->current_w = winsurf->w;
416 info->current_h = winsurf->h;
417 info->vfmt_data = *(winsurf->format);
418 info->vfmt = &info->vfmt_data;
419 }
420 else {
421 if (SDL_GetCurrentDisplayMode(0, &mode) == 0) {
422 info->current_w = mode.w;
423 info->current_h = mode.h;
424 formatenum = mode.format;
425 }
426 else {
427 info->current_w = -1;
428 info->current_h = -1;
429 formatenum = SDL_PIXELFORMAT_UNKNOWN;
430 }
431
432 if ((tempformat = SDL_AllocFormat(formatenum))) {
433 info->vfmt_data = *tempformat;
434 info->vfmt = &info->vfmt_data;
435 SDL_FreeFormat(tempformat);
436 }
437 else {
438 PyErr_SetString(pgExc_SDLError, SDL_GetError());
439 return (pg_VideoInfo *)NULL;
440 }
441 }
442
443 return info;
444 }
445
446 static PyObject *
pgInfo(PyObject * self)447 pgInfo(PyObject *self)
448 {
449 pg_VideoInfo info;
450 VIDEO_INIT_CHECK();
451 return pgVidInfo_New(pg_GetVideoInfo(&info));
452 }
453
454 static PyObject *
pg_get_wm_info(PyObject * self)455 pg_get_wm_info(PyObject *self)
456 {
457 PyObject *dict;
458 PyObject *tmp;
459 SDL_SysWMinfo info;
460 SDL_Window *win;
461
462 VIDEO_INIT_CHECK();
463
464 SDL_VERSION(&(info.version))
465 dict = PyDict_New();
466 if (!dict)
467 return NULL;
468
469
470 win = pg_GetDefaultWindow();
471 if (!win)
472 return dict;
473 if (!SDL_GetWindowWMInfo(win, &info))
474 return dict;
475
476 #if defined(SDL_VIDEO_DRIVER_WINDOWS)
477 tmp = PyLong_FromLong((long)info.info.win.window);
478 PyDict_SetItemString(dict, "window", tmp);
479 Py_DECREF(tmp);
480
481 tmp = PyLong_FromLong((long)info.info.win.hdc);
482 PyDict_SetItemString(dict, "hdc", tmp);
483 Py_DECREF(tmp);
484
485 tmp = PyLong_FromLong((long)info.info.win.hinstance);
486 PyDict_SetItemString(dict, "hinstance", tmp);
487 Py_DECREF(tmp);
488 #endif
489 #if defined(SDL_VIDEO_DRIVER_WINRT)
490 tmp = PyCapsule_New(info.info.winrt.window, "window", NULL);
491 PyDict_SetItemString(dict, "window", tmp);
492 Py_DECREF(tmp);
493 #endif
494 #if defined(SDL_VIDEO_DRIVER_X11)
495 tmp = PyInt_FromLong(info.info.x11.window);
496 PyDict_SetItemString(dict, "window", tmp);
497 Py_DECREF(tmp);
498
499 tmp = PyCapsule_New(info.info.x11.display, "display", NULL);
500 PyDict_SetItemString(dict, "display", tmp);
501 Py_DECREF(tmp);
502 #endif
503 #if defined(SDL_VIDEO_DRIVER_DIRECTFB)
504 tmp = PyCapsule_New(info.info.dfb.dfb, "dfb", NULL);
505 PyDict_SetItemString(dict, "dfb", tmp);
506 Py_DECREF(tmp);
507
508 tmp = PyCapsule_New(info.info.dfb.window, "window", NULL);
509 PyDict_SetItemString(dict, "window", tmp);
510 Py_DECREF(tmp);
511
512 tmp = PyCapsule_New(info.info.dfb.surface, "surface", NULL);
513 PyDict_SetItemString(dict, "surface", tmp);
514 Py_DECREF(tmp);
515 #endif
516 #if defined(SDL_VIDEO_DRIVER_COCOA)
517 tmp = PyCapsule_New(info.info.cocoa.window, "window", NULL);
518 PyDict_SetItemString(dict, "window", tmp);
519 Py_DECREF(tmp);
520 #endif
521 #if defined(SDL_VIDEO_DRIVER_UIKIT)
522 tmp = PyCapsule_New(info.info.uikit.window, "window", NULL);
523 PyDict_SetItemString(dict, "window", tmp);
524 Py_DECREF(tmp);
525
526 tmp = PyLong_FromLong(info.info.uikit.framebuffer);
527 PyDict_SetItemString(dict, "framebuffer", tmp);
528 Py_DECREF(tmp);
529
530 tmp = PyLong_FromLong(info.info.uikit.colorbuffer);
531 PyDict_SetItemString(dict, "colorbuffer", tmp);
532 Py_DECREF(tmp);
533
534 tmp = PyLong_FromLong(info.info.uikit.resolveFramebuffer);
535 PyDict_SetItemString(dict, "resolveFramebuffer", tmp);
536 Py_DECREF(tmp);
537 #endif
538 #if defined(SDL_VIDEO_DRIVER_WAYLAND)
539 tmp = PyCapsule_New(info.info.wl.display, "display", NULL);
540 PyDict_SetItemString(dict, "display", tmp);
541 Py_DECREF(tmp);
542
543 tmp = PyCapsule_New(info.info.wl.surface, "surface", NULL);
544 PyDict_SetItemString(dict, "surface", tmp);
545 Py_DECREF(tmp);
546
547 tmp = PyCapsule_New(info.info.wl.shell_surface, "shell_surface", NULL);
548 PyDict_SetItemString(dict, "shell_surface", tmp);
549 Py_DECREF(tmp);
550 #endif
551 #if defined(SDL_VIDEO_DRIVER_MIR) /* no longer available, left for API/ABI \
552 compatibility. Remove in 2.1! */
553 tmp = PyCapsule_New(info.info.mir.connection, "connection", NULL);
554 PyDict_SetItemString(dict, "connection", tmp);
555 Py_DECREF(tmp);
556
557 tmp = PyCapsule_New(info.info.mir.surface, "surface", NULL);
558 PyDict_SetItemString(dict, "surface", tmp);
559 Py_DECREF(tmp);
560 #endif
561 #if defined(SDL_VIDEO_DRIVER_ANDROID)
562 tmp = PyCapsule_New(info.info.android.window, "window", NULL);
563 PyDict_SetItemString(dict, "window", tmp);
564 Py_DECREF(tmp);
565
566 tmp = PyLong_FromLong((long)info.info.android.surface);
567 PyDict_SetItemString(dict, "surface", tmp);
568 Py_DECREF(tmp);
569 #endif
570 #if defined(SDL_VIDEO_DRIVER_VIVANTE)
571 tmp = PyLong_FromLong((long)info.info.vivante.display);
572 PyDict_SetItemString(dict, "display", tmp);
573 Py_DECREF(tmp);
574
575 tmp = PyLong_FromLong((long)info.info.vivante.window);
576 PyDict_SetItemString(dict, "window", tmp);
577 Py_DECREF(tmp);
578 #endif
579
580
581 return dict;
582 }
583
584 /* display functions */
585 static PyObject *
pg_get_driver(PyObject * self)586 pg_get_driver(PyObject *self)
587 {
588 const char *name = NULL;
589 VIDEO_INIT_CHECK();
590 name = SDL_GetCurrentVideoDriver();
591 if (!name)
592 Py_RETURN_NONE;
593 return Text_FromUTF8(name);
594 }
595
596 static PyObject *
pg_get_surface(PyObject * self)597 pg_get_surface(PyObject *self)
598 {
599 _DisplayState *state = DISPLAY_MOD_STATE(self);
600 SDL_Window *win = pg_GetDefaultWindow();
601
602 if (pg_renderer!=NULL || state->using_gl) {
603 pgSurfaceObject *surface = pg_GetDefaultWindowSurface();
604 if (!surface)
605 Py_RETURN_NONE;
606 Py_INCREF(surface);
607 return (PyObject *)surface;
608 }
609 else if (win==NULL) {
610 Py_RETURN_NONE;
611 }
612 else {
613 SDL_Surface *sdl_surface = SDL_GetWindowSurface(win);
614 pgSurfaceObject *old_surface = pg_GetDefaultWindowSurface();
615 if (sdl_surface != old_surface->surf) {
616 pgSurfaceObject *new_surface = pgSurface_New2(sdl_surface, SDL_FALSE);
617 if (!new_surface)
618 return NULL;
619 pg_SetDefaultWindowSurface(new_surface);
620 Py_INCREF((PyObject *)new_surface);
621 return (PyObject *)new_surface;
622 }
623 Py_INCREF(old_surface);
624 return (PyObject *)old_surface;
625 }
626 return NULL;
627 }
628
629 static PyObject *
pg_gl_set_attribute(PyObject * self,PyObject * arg)630 pg_gl_set_attribute(PyObject *self, PyObject *arg)
631 {
632 int flag, value, result;
633 VIDEO_INIT_CHECK();
634 if (!PyArg_ParseTuple(arg, "ii", &flag, &value))
635 return NULL;
636 if (flag == -1) /*an undefined/unsupported val, ignore*/
637 Py_RETURN_NONE;
638 result = SDL_GL_SetAttribute(flag, value);
639 if (result == -1)
640 return RAISE(pgExc_SDLError, SDL_GetError());
641 Py_RETURN_NONE;
642 }
643
644 static PyObject *
pg_gl_get_attribute(PyObject * self,PyObject * arg)645 pg_gl_get_attribute(PyObject *self, PyObject *arg)
646 {
647 int flag, value, result;
648 VIDEO_INIT_CHECK();
649 if (!PyArg_ParseTuple(arg, "i", &flag))
650 return NULL;
651 result = SDL_GL_GetAttribute(flag, &value);
652 if (result == -1)
653 return RAISE(pgExc_SDLError, SDL_GetError());
654 return PyInt_FromLong(value);
655 }
656
657
658 /*
659 ** Looks at the SDL1 environment variables:
660 ** - SDL_VIDEO_WINDOW_POS
661 * "x,y"
662 * "center"
663 ** - SDL_VIDEO_CENTERED
664 * if set the window should be centered.
665 *
666 * Returns:
667 * 0 if we do not want to position the window.
668 * 1 if we set the x and y.
669 * x, and y are set to the x and y.
670 * center_window is set to 0.
671 * 2 if we want the window centered.
672 * center_window is set to 1.
673 */
674 int
_get_video_window_pos(int * x,int * y,int * center_window)675 _get_video_window_pos(int *x, int *y, int *center_window)
676 {
677 const char *sdl_video_window_pos = SDL_getenv("SDL_VIDEO_WINDOW_POS");
678 const char *sdl_video_centered = SDL_getenv("SDL_VIDEO_CENTERED");
679 int xx, yy;
680 if (sdl_video_window_pos) {
681 if (SDL_sscanf(sdl_video_window_pos, "%d,%d", &xx, &yy) == 2) {
682 *x = xx;
683 *y = yy;
684 *center_window = 0;
685 return 1;
686 }
687 if (SDL_strcmp(sdl_video_window_pos, "center") == 0) {
688 sdl_video_centered = sdl_video_window_pos;
689 }
690 }
691 if (sdl_video_centered) {
692 *center_window = 1;
693 return 2;
694 }
695 return 0;
696 }
697
698 static int SDLCALL
pg_ResizeEventWatch(void * userdata,SDL_Event * event)699 pg_ResizeEventWatch(void *userdata, SDL_Event *event) {
700 SDL_Window *pygame_window;
701 PyObject *self;
702 _DisplayState *state;
703 SDL_Window *window;
704
705 if (event->type != SDL_WINDOWEVENT)
706 return 0;
707
708 self= (PyObject *) userdata;
709 pygame_window = pg_GetDefaultWindow();
710 state = DISPLAY_MOD_STATE(self);
711
712 window = SDL_GetWindowFromID(event->window.windowID);
713 if (window != pygame_window)
714 return 0;
715
716 if (pg_renderer!=NULL) {
717 #if (SDL_VERSION_ATLEAST(2, 0, 5))
718
719 if (event->window.event == SDL_WINDOWEVENT_MAXIMIZED) {
720 SDL_RenderSetIntegerScale(pg_renderer,
721 SDL_FALSE);
722 }
723 if (event->window.event == SDL_WINDOWEVENT_RESTORED) {
724 SDL_RenderSetIntegerScale(pg_renderer,
725 !(SDL_GetHintBoolean("SDL_HINT_RENDER_SCALE_QUALITY",SDL_FALSE)));
726 }
727 #endif
728 return 0;
729 }
730
731 if (state->using_gl) {
732 if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
733
734 GL_glViewport_Func p_glViewport = (GL_glViewport_Func)SDL_GL_GetProcAddress("glViewport");
735 int wnew=event->window.data1;
736 int hnew=event->window.data2;
737 SDL_GL_MakeCurrent(pygame_window, state->gl_context);
738 if (state->scaled_gl) {
739 float saved_aspect_ratio =
740 ((float)state->scaled_gl_w) / (float)state->scaled_gl_h;
741 float window_aspect_ratio = ((float)wnew) / (float)hnew;
742
743 if (window_aspect_ratio > saved_aspect_ratio) {
744 int width = (int)(hnew * saved_aspect_ratio);
745 p_glViewport((wnew - width) / 2, 0, width, hnew);
746 }
747 else {
748 p_glViewport(0, 0, wnew, (int)(wnew / saved_aspect_ratio));
749 }
750 }
751 else {
752 p_glViewport(0, 0, wnew, hnew);
753 }
754 }
755 return 0;
756 }
757
758 if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
759 if (window == pygame_window) {
760 SDL_Surface *sdl_surface = SDL_GetWindowSurface(window);
761 pgSurfaceObject *old_surface = pg_GetDefaultWindowSurface();
762 if (sdl_surface != old_surface->surf) {
763 old_surface->surf=sdl_surface;
764 }
765 }
766 }
767 return 0;
768 }
769
770 static PyObject *
pg_display_set_autoresize(PyObject * self,PyObject * args)771 pg_display_set_autoresize(PyObject *self, PyObject *args)
772 {
773 SDL_bool do_resize;
774 _DisplayState *state = DISPLAY_MOD_STATE(self);
775
776 if (!PyArg_ParseTuple(args, "p", &do_resize))
777 return NULL;
778
779 state->auto_resize=do_resize;
780 SDL_DelEventWatch(pg_ResizeEventWatch, self);
781
782 if(do_resize) {
783 SDL_AddEventWatch(pg_ResizeEventWatch, self);
784 Py_RETURN_TRUE;
785 }
786 else {
787 Py_RETURN_FALSE;
788 }
789 }
790
791
792 int
_get_display(SDL_Window * win)793 _get_display(SDL_Window *win)
794 {
795 char *display_env = SDL_getenv("PYGAME_DISPLAY");
796 int display = 0; /* default display 0 */
797
798 if (win != NULL) {
799 display = SDL_GetWindowDisplayIndex(win);
800 return display;
801 }
802 else if (display_env != NULL) {
803 display = SDL_atoi(display_env);
804 return display;
805 }
806 /* On e.g. Linux X11, checking the mouse pointer requires that the
807 * video subsystem is initialized to avoid crashes.
808 *
809 * Note that we do not bother raising an error here; the condition will
810 * be rechecked after parsing the arguments and the function will throw
811 * the relevant error there.
812 */
813 else if (SDL_WasInit(SDL_INIT_VIDEO)) {
814 /* get currently "active" desktop, containing mouse ptr */
815 int num_displays, i;
816 SDL_Rect display_bounds;
817 SDL_Point mouse_position;
818 SDL_GetGlobalMouseState(&mouse_position.x, &mouse_position.y);
819 num_displays = SDL_GetNumVideoDisplays();
820
821 for (i = 0; i < num_displays; i++) {
822 if (SDL_GetDisplayBounds(i, &display_bounds) == 0) {
823 if (SDL_PointInRect(&mouse_position, &display_bounds)) {
824 display = i;
825 break;
826 }
827 }
828 }
829 }
830 return display;
831 }
832
833 static PyObject *
pg_set_mode(PyObject * self,PyObject * arg,PyObject * kwds)834 pg_set_mode(PyObject *self, PyObject *arg, PyObject *kwds)
835 {
836 static const char *const DefaultTitle = "pygame window";
837
838 _DisplayState *state = DISPLAY_MOD_STATE(self);
839 SDL_Window *win = pg_GetDefaultWindow();
840 pgSurfaceObject *surface = pg_GetDefaultWindowSurface();
841 SDL_Surface *surf = NULL;
842 SDL_Surface *newownedsurf = NULL;
843 int depth = 0;
844 int flags = 0;
845 int w, h;
846 PyObject *size = NULL;
847 int vsync = SDL_FALSE;
848 /* display will get overwritten by ParseTupleAndKeywords only if display
849 parameter is given. By default, put the new window on the same
850 screen as the old one */
851 int display = _get_display(win);
852 char *title = state->title;
853 int init_flip = 0;
854 char *scale_env;
855
856 char *keywords[] = {"size", "flags", "depth", "display", "vsync", NULL};
857
858 scale_env = SDL_getenv("PYGAME_FORCE_SCALE");
859
860 if (!PyArg_ParseTupleAndKeywords(arg, kwds, "|Oiiii", keywords, &size,
861 &flags, &depth, &display, &vsync))
862 return NULL;
863
864 if (scale_env != NULL) {
865 flags |= PGS_SCALED;
866 if (strcmp(scale_env, "photo") == 0) {
867 SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "best",
868 SDL_HINT_NORMAL);
869 }
870 }
871
872 if (size != NULL) {
873 if (!pg_TwoIntsFromObj(size, &w, &h))
874 return RAISE(PyExc_TypeError, "size must be two numbers");
875 if (w < 0 || h < 0)
876 return RAISE(pgExc_SDLError, "Cannot set negative sized display mode");
877 }
878 else {
879 w = 0;
880 h = 0;
881 }
882
883 if (!SDL_WasInit(SDL_INIT_VIDEO)) {
884 /* note SDL works special like this too */
885 if (!pg_display_init(NULL))
886 return NULL;
887 }
888
889 state->using_gl = (flags & PGS_OPENGL) != 0;
890 state->scaled_gl = state->using_gl && (flags & PGS_SCALED) != 0;
891
892 if (state->scaled_gl) {
893 if (PyErr_WarnEx(PyExc_FutureWarning,
894 "SCALED|OPENGL is experimental and subject to change",
895 1) != 0)
896 return NULL;
897 }
898
899 if (!state->title) {
900 state->title = malloc((strlen(DefaultTitle) + 1) * sizeof(char));
901 if (!state->title)
902 return PyErr_NoMemory();
903 strcpy(state->title, DefaultTitle);
904 title = state->title;
905 }
906
907 // if (vsync && !(flags & (PGS_SCALED | PGS_OPENGL))) {
908 // return RAISE(pgExc_SDLError,
909 // "vsync needs either SCALED or OPENGL flag");
910 // }
911
912 /* set these only in toggle_fullscreen, clear on set_mode */
913 state->toggle_windowed_w = 0;
914 state->toggle_windowed_h = 0;
915
916 if (pg_texture) {
917 SDL_DestroyTexture(pg_texture);
918 pg_texture = NULL;
919 }
920
921 if (pg_renderer) {
922 SDL_DestroyRenderer(pg_renderer);
923 pg_renderer = NULL;
924 }
925
926 SDL_DelEventWatch(pg_ResizeEventWatch, self);
927
928 {
929 Uint32 sdl_flags = 0;
930 SDL_DisplayMode display_mode;
931
932 if (SDL_GetDesktopDisplayMode(display, &display_mode) != 0) {
933 return RAISE(pgExc_SDLError, SDL_GetError());
934 }
935
936 if (w == 0 && h == 0 && !(flags & PGS_SCALED)) {
937 /* We are free to choose a resolution in this case, so we can
938 avoid changing the physical resolution. This used to default
939 to the max supported by the monitor, but we can use current
940 desktop resolution without breaking compatibility. */
941 w = display_mode.w;
942 h = display_mode.h;
943 }
944
945 if (flags & PGS_FULLSCREEN) {
946 if (flags & PGS_SCALED) {
947 sdl_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
948 }
949 else if (w == display_mode.w && h == display_mode.h) {
950 /* No need to change physical resolution.
951 Borderless fullscreen is preferred when possible */
952 sdl_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
953 }
954 else {
955 sdl_flags |= SDL_WINDOW_FULLSCREEN;
956 }
957 }
958
959 if (flags & PGS_SCALED) {
960 if (w == 0 || h == 0)
961 return RAISE(pgExc_SDLError,
962 "Cannot set 0 sized SCALED display mode");
963 }
964
965 if (flags & PGS_OPENGL)
966 sdl_flags |= SDL_WINDOW_OPENGL;
967 if (flags & PGS_NOFRAME)
968 sdl_flags |= SDL_WINDOW_BORDERLESS;
969 if (flags & PGS_RESIZABLE) {
970 sdl_flags |= SDL_WINDOW_RESIZABLE;
971 if(state->auto_resize)
972 SDL_AddEventWatch(pg_ResizeEventWatch, self);
973 }
974 if (flags & PGS_SHOWN)
975 sdl_flags |= SDL_WINDOW_SHOWN;
976 if (flags & PGS_HIDDEN)
977 sdl_flags |= SDL_WINDOW_HIDDEN;
978 if (!(sdl_flags & SDL_WINDOW_HIDDEN))
979 sdl_flags |= SDL_WINDOW_SHOWN;
980 if (flags & PGS_OPENGL) {
981 /* Must be called before creating context */
982 if (flags & PGS_DOUBLEBUF) {
983 flags &= ~PGS_DOUBLEBUF;
984 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
985 }
986 else
987 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
988 }
989
990 #pragma PG_WARN(Not setting bpp ?)
991 #pragma PG_WARN(Add mode stuff.)
992 {
993 int w_1 = w, h_1 = h;
994 int scale = 1;
995 int center_window = 0;
996 int x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(display);
997 int y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(display);
998
999 _get_video_window_pos(&x, &y, ¢er_window);
1000 if (center_window) {
1001 x = SDL_WINDOWPOS_CENTERED_DISPLAY(display);
1002 y = SDL_WINDOWPOS_CENTERED_DISPLAY(display);
1003 }
1004
1005 if (win) {
1006 if (SDL_GetWindowDisplayIndex(win) == display) {
1007 // fullscreen windows don't hold window x and y as needed
1008 if (SDL_GetWindowFlags(win) & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) {
1009 x = state->fullscreen_backup_x;
1010 y = state->fullscreen_backup_y;
1011
1012 // if the program goes into fullscreen first the "saved x and y" are "undefined position"
1013 // that should be interpreted as a cue to center the window
1014 if (x == SDL_WINDOWPOS_UNDEFINED_DISPLAY(display))
1015 x = SDL_WINDOWPOS_CENTERED_DISPLAY(display);
1016 if (y == SDL_WINDOWPOS_UNDEFINED_DISPLAY(display))
1017 y = SDL_WINDOWPOS_CENTERED_DISPLAY(display);
1018 }
1019 else {
1020 SDL_GetWindowPosition(win, &x, &y);
1021 }
1022
1023 }
1024 if (!(flags & PGS_OPENGL) !=
1025 !(SDL_GetWindowFlags(win) & SDL_WINDOW_OPENGL)) {
1026 pg_SetDefaultWindow(NULL);
1027 win = NULL;
1028 }
1029 }
1030
1031 if (flags & PGS_SCALED && !(flags & PGS_FULLSCREEN)) {
1032 SDL_Rect display_bounds;
1033 int fractional_scaling = SDL_FALSE;
1034
1035 #if (SDL_VERSION_ATLEAST(2, 0, 5))
1036 if (0 !=
1037 SDL_GetDisplayUsableBounds(display, &display_bounds)) {
1038 return RAISE(pgExc_SDLError, SDL_GetError());
1039 }
1040 #else
1041 display_bounds.w = display_mode.w - 80;
1042 display_bounds.h = display_mode.h - 30;
1043 #endif
1044
1045 #if (SDL_VERSION_ATLEAST(2, 0, 5))
1046 if (SDL_GetHintBoolean("SDL_HINT_RENDER_SCALE_QUALITY",
1047 SDL_FALSE))
1048 fractional_scaling = SDL_TRUE;
1049 #endif
1050 if (state->scaled_gl)
1051 fractional_scaling = SDL_TRUE;
1052
1053 if (fractional_scaling) {
1054 float aspect_ratio = ((float)w) / (float)h;
1055
1056 w_1 = display_bounds.w;
1057 h_1 = display_bounds.h;
1058
1059 if (((float)w_1) / (float)h_1 > aspect_ratio) {
1060 w_1 = h_1 * aspect_ratio;
1061 }
1062 else {
1063 h_1 = w_1 / aspect_ratio;
1064 }
1065 }
1066 else {
1067 int xscale, yscale;
1068
1069 xscale = display_bounds.w / w;
1070 yscale = display_bounds.h / h;
1071
1072 scale = xscale < yscale ? xscale : yscale;
1073
1074 if (scale < 1)
1075 scale = 1;
1076
1077 w_1 = w * scale;
1078 h_1 = h * scale;
1079 }
1080 }
1081
1082 // SDL doesn't preserve window position in fullscreen mode
1083 // However, windows coming out of fullscreen need these to go back into the correct position
1084 if (sdl_flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) {
1085 state->fullscreen_backup_x = x;
1086 state->fullscreen_backup_y = y;
1087 }
1088
1089 if (!win) {
1090 /*open window*/
1091 win = SDL_CreateWindow(title, x, y, w_1, h_1, sdl_flags);
1092 if (!win)
1093 return RAISE(pgExc_SDLError, SDL_GetError());
1094 init_flip = 1;
1095 }
1096 else {
1097 /* set min size to (1,1) to erase any previously set min size
1098 * relevant for windows leaving SCALED, which sets a min size
1099 * only relevant on Windows, I believe.
1100 * See https://github.com/pygame/pygame/issues/2327 */
1101 SDL_SetWindowMinimumSize(win, 1, 1);
1102
1103 /* change existing window.
1104 this invalidates the display surface*/
1105 SDL_SetWindowTitle(win, title);
1106 SDL_SetWindowSize(win, w_1, h_1);
1107
1108 #if (SDL_VERSION_ATLEAST(2, 0, 5))
1109 SDL_SetWindowResizable(win, flags & PGS_RESIZABLE);
1110 #endif
1111 SDL_SetWindowBordered(win, (flags & PGS_NOFRAME) == 0);
1112
1113 if ((flags & PGS_SHOWN) || !(flags & PGS_HIDDEN))
1114 SDL_ShowWindow(win);
1115 else if (flags & PGS_HIDDEN)
1116 SDL_HideWindow(win);
1117
1118 if (0 !=
1119 SDL_SetWindowFullscreen(
1120 win, sdl_flags & (SDL_WINDOW_FULLSCREEN |
1121 SDL_WINDOW_FULLSCREEN_DESKTOP))) {
1122 return RAISE(pgExc_SDLError, SDL_GetError());
1123 }
1124
1125 SDL_SetWindowPosition(win, x, y);
1126
1127 assert(surface);
1128 }
1129 }
1130
1131 if (state->using_gl) {
1132 if (!state->gl_context) {
1133 state->gl_context = SDL_GL_CreateContext(win);
1134 if (!state->gl_context) {
1135 _display_state_cleanup(state);
1136 PyErr_SetString(pgExc_SDLError, SDL_GetError());
1137 goto DESTROY_WINDOW;
1138 }
1139 /* SDL_GetWindowSurface can not be used when using GL.
1140 According to https://wiki.libsdl.org/SDL_GetWindowSurface
1141
1142 So we make a fake surface.
1143 */
1144 surf = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
1145 0xff << 16, 0xff << 8, 0xff, 0);
1146 newownedsurf = surf;
1147 }
1148 else {
1149 surf = pgSurface_AsSurface(surface);
1150 }
1151 if (flags & PGS_SCALED) {
1152 state->scaled_gl_w = w;
1153 state->scaled_gl_h = h;
1154 }
1155
1156 /* Even if this succeeds, we can never *really* know if vsync
1157 actually works. There may be screen tearing, blocking double
1158 buffering, triple buffering, render-offloading where the driver
1159 for the on-board graphics *doesn't* have vsync enabled, or cases
1160 where the driver lies to us because the user has configured
1161 vsync to be aways on or always off, or vsync is on by default
1162 for the whole desktop because of wayland GL compositing. */
1163 if (vsync) {
1164 if (SDL_GL_SetSwapInterval(-1) != 0) {
1165 if (PyErr_WarnEx(PyExc_Warning,
1166 "adaptive vsync for OpenGL not "
1167 "available, trying regular",
1168 1) != 0) {
1169 _display_state_cleanup(state);
1170 goto DESTROY_WINDOW;
1171 }
1172 if (SDL_GL_SetSwapInterval(1) != 0) {
1173 if (PyErr_WarnEx(PyExc_Warning,
1174 "regular vsync for OpenGL *also* not "
1175 "available",
1176 1) != 0) {
1177 _display_state_cleanup(state);
1178 goto DESTROY_WINDOW;
1179 }
1180 }
1181 }
1182 }
1183 else {
1184 SDL_GL_SetSwapInterval(0);
1185 }
1186 }
1187 else {
1188 if (state->gl_context) {
1189 SDL_GL_DeleteContext(state->gl_context);
1190 state->gl_context = NULL;
1191 }
1192
1193 if (flags & PGS_SCALED) {
1194 if (pg_renderer == NULL) {
1195 SDL_RendererInfo info;
1196
1197 SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY,
1198 "nearest", SDL_HINT_DEFAULT);
1199
1200 if (vsync) {
1201 pg_renderer = SDL_CreateRenderer(
1202 win, -1, SDL_RENDERER_PRESENTVSYNC);
1203 }
1204 else {
1205 pg_renderer = SDL_CreateRenderer(win, -1, 0);
1206 }
1207
1208 if (pg_renderer == NULL) {
1209 return RAISE(pgExc_SDLError,
1210 "failed to create renderer");
1211 }
1212
1213 #if (SDL_VERSION_ATLEAST(2, 0, 5))
1214
1215 /* use whole screen with uneven pixels on fullscreen,
1216 exact scale otherwise.
1217 we chose the window size for this to work */
1218 SDL_RenderSetIntegerScale(
1219 pg_renderer,
1220 !(flags & PGS_FULLSCREEN ||
1221 SDL_GetHintBoolean("SDL_HINT_RENDER_SCALE_QUALITY",
1222 SDL_FALSE)));
1223 #endif
1224 SDL_RenderSetLogicalSize(pg_renderer, w, h);
1225 /* this must be called after creating the renderer!*/
1226 SDL_SetWindowMinimumSize(win, w, h);
1227
1228 SDL_GetRendererInfo(pg_renderer, &info);
1229 if (vsync && !(info.flags & SDL_RENDERER_PRESENTVSYNC)) {
1230 if (PyErr_WarnEx(PyExc_Warning,
1231 "could not enable vsync", 1) != 0) {
1232 _display_state_cleanup(state);
1233 goto DESTROY_WINDOW;
1234 }
1235 }
1236 if (!(info.flags & SDL_RENDERER_ACCELERATED)) {
1237 if (PyErr_WarnEx(PyExc_Warning,
1238 "no fast renderer available",
1239 1) != 0) {
1240 _display_state_cleanup(state);
1241 goto DESTROY_WINDOW;
1242 }
1243 }
1244
1245 pg_texture = SDL_CreateTexture(
1246 pg_renderer, SDL_PIXELFORMAT_ARGB8888,
1247 SDL_TEXTUREACCESS_STREAMING, w, h);
1248 }
1249 surf = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
1250 0xff << 16, 0xff << 8, 0xff, 0);
1251 newownedsurf = surf;
1252 }
1253 else {
1254 surf = SDL_GetWindowSurface(win);
1255 }
1256 }
1257 if (state->gamma_ramp) {
1258 int result = SDL_SetWindowGammaRamp(win, state->gamma_ramp,
1259 state->gamma_ramp + 256,
1260 state->gamma_ramp + 512);
1261 if (result) /* SDL Error? */
1262 {
1263 /* Discard a possibly faulty gamma ramp. */
1264 _display_state_cleanup(state);
1265
1266 /* Recover error, then destroy the window */
1267 PyErr_SetString(pgExc_SDLError, SDL_GetError());
1268 goto DESTROY_WINDOW;
1269 }
1270 }
1271
1272 if (state->using_gl && pg_renderer != NULL) {
1273 _display_state_cleanup(state);
1274 PyErr_SetString(
1275 pgExc_SDLError,
1276 "GL context and SDL_Renderer created at the same time");
1277 goto DESTROY_WINDOW;
1278 }
1279
1280 if (!surf) {
1281 _display_state_cleanup(state);
1282 PyErr_SetString(pgExc_SDLError, SDL_GetError());
1283 goto DESTROY_WINDOW;
1284 }
1285 if (!surface) {
1286 surface = pgSurface_New2(surf, newownedsurf != NULL);
1287 }
1288 else {
1289 pgSurface_SetSurface(surface, surf, newownedsurf != NULL);
1290 Py_INCREF(surface);
1291 }
1292 if (!surface) {
1293 if (newownedsurf)
1294 SDL_FreeSurface(newownedsurf);
1295 _display_state_cleanup(state);
1296 goto DESTROY_WINDOW;
1297 }
1298
1299 /*no errors; make the window available*/
1300 pg_SetDefaultWindow(win);
1301 pg_SetDefaultWindowSurface(surface);
1302 Py_DECREF(surface);
1303
1304 /* ensure window is initially black */
1305 if (init_flip)
1306 pg_flip_internal(state);
1307 }
1308
1309 /*set the window icon*/
1310 if (!state->icon) {
1311 state->icon = pg_display_resource(icon_defaultname);
1312 if (!state->icon)
1313 PyErr_Clear();
1314 else {
1315 SDL_SetColorKey(pgSurface_AsSurface(state->icon), SDL_TRUE, 0);
1316 }
1317 }
1318 if (state->icon)
1319 SDL_SetWindowIcon(win, pgSurface_AsSurface(state->icon));
1320
1321 /*probably won't do much, but can't hurt, and might help*/
1322 SDL_PumpEvents();
1323
1324 /*return the window's surface (screen)*/
1325 Py_INCREF(surface);
1326 return (PyObject *)surface;
1327
1328 DESTROY_WINDOW:
1329
1330 if (win == pg_GetDefaultWindow())
1331 pg_SetDefaultWindow(NULL);
1332 else if (win)
1333 SDL_DestroyWindow(win);
1334 return NULL;
1335 }
1336
1337 static int
_pg_get_default_display_masks(int bpp,Uint32 * Rmask,Uint32 * Gmask,Uint32 * Bmask)1338 _pg_get_default_display_masks(int bpp, Uint32 *Rmask, Uint32 *Gmask,
1339 Uint32 *Bmask)
1340 {
1341 switch (bpp) {
1342 case 8:
1343 *Rmask = 0;
1344 *Gmask = 0;
1345 *Bmask = 0;
1346 break;
1347 case 12:
1348 *Rmask = 0xFF >> 4 << 8;
1349 *Gmask = 0xFF >> 4 << 4;
1350 *Bmask = 0xFF >> 4;
1351 break;
1352 case 15:
1353 *Rmask = 0xFF >> 3 << 10;
1354 *Gmask = 0xFF >> 3 << 5;
1355 *Bmask = 0xFF >> 3;
1356 break;
1357 case 16:
1358 *Rmask = 0xFF >> 3 << 11;
1359 *Gmask = 0xFF >> 2 << 5;
1360 *Bmask = 0xFF >> 3;
1361 break;
1362 case 24:
1363 case 32:
1364 *Rmask = 0xFF << 16;
1365 *Gmask = 0xFF << 8;
1366 *Bmask = 0xFF;
1367 break;
1368 default:
1369 PyErr_SetString(PyExc_ValueError, "nonstandard bit depth given");
1370 return -1;
1371 }
1372 return 0;
1373 }
1374
1375 static PyObject *
pg_window_size(PyObject * self)1376 pg_window_size(PyObject *self)
1377 {
1378 SDL_Window *win = pg_GetDefaultWindow();
1379 int w, h;
1380 if (!win)
1381 return RAISE(pgExc_SDLError, "No open window");
1382 SDL_GetWindowSize(win, &w, &h);
1383 return Py_BuildValue("(ii)", w, h);
1384 }
1385
1386 static PyObject *
pg_mode_ok(PyObject * self,PyObject * args,PyObject * kwds)1387 pg_mode_ok(PyObject *self, PyObject *args, PyObject *kwds)
1388 {
1389 SDL_DisplayMode desired, closest;
1390 int bpp = 0;
1391 int flags = SDL_SWSURFACE;
1392 int display_index = 0;
1393
1394 char *keywords[] = {"size", "flags", "depth", "display", NULL};
1395
1396 VIDEO_INIT_CHECK();
1397
1398 if (!PyArg_ParseTupleAndKeywords(args, kwds, "(ii)|iii", keywords,
1399 &desired.w, &desired.h, &flags, &bpp,
1400 &display_index)) {
1401 return NULL;
1402 }
1403 if (display_index < 0 || display_index >= SDL_GetNumVideoDisplays()) {
1404 return RAISE(PyExc_ValueError,
1405 "The display index must be between 0"
1406 " and the number of displays.");
1407 }
1408 #pragma PG_WARN(Ignoring most flags)
1409
1410 desired.driverdata = 0;
1411 desired.refresh_rate = 0;
1412
1413 if (bpp == 0) {
1414 desired.format = 0;
1415 }
1416 else {
1417 Uint32 Rmask, Gmask, Bmask;
1418 if (_pg_get_default_display_masks(bpp, &Rmask, &Gmask, &Bmask)) {
1419 PyErr_Clear();
1420 return PyInt_FromLong((long)0);
1421 }
1422 desired.format =
1423 SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, 0);
1424 }
1425 if (!SDL_GetClosestDisplayMode(display_index, &desired, &closest)) {
1426 if (flags & PGS_FULLSCREEN)
1427 return PyInt_FromLong((long)0);
1428 closest.format = desired.format;
1429 }
1430 if ((flags & PGS_FULLSCREEN) &&
1431 (closest.w != desired.w || closest.h != desired.h))
1432 return PyInt_FromLong((long)0);
1433 return PyInt_FromLong(SDL_BITSPERPIXEL(closest.format));
1434 }
1435
1436 static PyObject *
pg_list_modes(PyObject * self,PyObject * args,PyObject * kwds)1437 pg_list_modes(PyObject *self, PyObject *args, PyObject *kwds)
1438 {
1439 SDL_DisplayMode mode;
1440 int nummodes;
1441 int bpp = 0;
1442 int flags = PGS_FULLSCREEN;
1443 int display_index = 0;
1444 int last_width = -1, last_height = -1;
1445 PyObject *list, *size;
1446 int i;
1447
1448 char *keywords[] = {"depth", "flags", "display", NULL};
1449
1450 VIDEO_INIT_CHECK();
1451
1452 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|bii", keywords, &bpp,
1453 &flags, &display_index)) {
1454 return NULL;
1455 }
1456
1457 if (display_index < 0 || display_index >= SDL_GetNumVideoDisplays()) {
1458 return RAISE(PyExc_ValueError,
1459 "The display index must be between 0"
1460 " and the number of displays.");
1461 }
1462 #pragma PG_WARN(Ignoring flags)
1463
1464 if (bpp == 0) {
1465 SDL_DisplayMode curmode;
1466 if (SDL_GetCurrentDisplayMode(display_index, &curmode))
1467 return RAISE(pgExc_SDLError, SDL_GetError());
1468 bpp = SDL_BITSPERPIXEL(curmode.format);
1469 }
1470
1471 nummodes = SDL_GetNumDisplayModes(display_index);
1472 if (nummodes < 0)
1473 return RAISE(pgExc_SDLError, SDL_GetError());
1474
1475 if (!(list = PyList_New(0)))
1476 return NULL;
1477
1478 for (i = 0; i < nummodes; i++) {
1479 if (SDL_GetDisplayMode(display_index, i, &mode) < 0) {
1480 Py_DECREF(list);
1481 return RAISE(pgExc_SDLError, SDL_GetError());
1482 }
1483 /* use reasonable defaults (cf. SDL_video.c) */
1484 if (!mode.format)
1485 mode.format = SDL_PIXELFORMAT_RGB888;
1486 if (!mode.w)
1487 mode.w = 640;
1488 if (!mode.h)
1489 mode.h = 480;
1490 if (SDL_BITSPERPIXEL(mode.format) != bpp)
1491 continue;
1492 if (last_width == mode.w && last_height == mode.h && last_width != -1) {
1493 continue;
1494 }
1495 if (!(size = Py_BuildValue("(ii)", mode.w, mode.h))) {
1496 Py_DECREF(list);
1497 return NULL;
1498 }
1499 last_width = mode.w;
1500 last_height = mode.h;
1501 if (0 != PyList_Append(list, size)) {
1502 Py_DECREF(list);
1503 Py_DECREF(size);
1504 return NULL; /* Exception already set. */
1505 }
1506 Py_DECREF(size);
1507 }
1508 return list;
1509 }
1510
1511 static int
pg_flip_internal(_DisplayState * state)1512 pg_flip_internal(_DisplayState *state)
1513 {
1514 SDL_Window *win = pg_GetDefaultWindow();
1515 int status = 0;
1516
1517 /* Same check as VIDEO_INIT_CHECK() but returns -1 instead of NULL on
1518 * fail. */
1519 if (!SDL_WasInit(SDL_INIT_VIDEO)) {
1520 PyErr_SetString(pgExc_SDLError, "video system not initialized");
1521 return -1;
1522 }
1523
1524 if (!win) {
1525 PyErr_SetString(pgExc_SDLError, "Display mode not set");
1526 return -1;
1527 }
1528
1529 Py_BEGIN_ALLOW_THREADS;
1530 if (state->using_gl) {
1531 SDL_GL_SwapWindow(win);
1532 }
1533 else {
1534 if (pg_renderer != NULL) {
1535 SDL_Surface *screen =
1536 pgSurface_AsSurface(pg_GetDefaultWindowSurface());
1537 SDL_UpdateTexture(pg_texture, NULL, screen->pixels, screen->pitch);
1538 SDL_RenderClear(pg_renderer);
1539 SDL_RenderCopy(pg_renderer, pg_texture, NULL, NULL);
1540 SDL_RenderPresent(pg_renderer);
1541 }
1542 else {
1543 /* Force a re-initialization of the surface in case it
1544 * has been resized to avoid "please call SDL_GetWindowSurface"
1545 * errors that the programmer cannot fix
1546 */
1547 pgSurfaceObject *screen = pg_GetDefaultWindowSurface();
1548 SDL_Surface *new_surface = SDL_GetWindowSurface(win);
1549
1550 if (new_surface != ((pgSurfaceObject *)screen)->surf) {
1551 screen->surf = new_surface;
1552 }
1553 status = SDL_UpdateWindowSurface(win);
1554 }
1555 }
1556 Py_END_ALLOW_THREADS;
1557
1558 if (status < 0) {
1559 PyErr_SetString(pgExc_SDLError, SDL_GetError());
1560 return -1;
1561 }
1562
1563 return 0;
1564 }
1565
1566 static PyObject *
pg_flip(PyObject * self)1567 pg_flip(PyObject *self)
1568 {
1569 if (pg_flip_internal(DISPLAY_MOD_STATE(self)) < 0) {
1570 return NULL;
1571 }
1572 Py_RETURN_NONE;
1573 }
1574
1575 static PyObject *
pg_num_displays(PyObject * self)1576 pg_num_displays(PyObject *self)
1577 {
1578 int ret = SDL_GetNumVideoDisplays();
1579 if (ret < 0)
1580 return RAISE(pgExc_SDLError, SDL_GetError());
1581 return PyInt_FromLong(ret);
1582 }
1583
1584
1585 /*BAD things happen when out-of-bound rects go to updaterect*/
1586 static SDL_Rect *
pg_screencroprect(GAME_Rect * r,int w,int h,SDL_Rect * cur)1587 pg_screencroprect(GAME_Rect *r, int w, int h, SDL_Rect *cur)
1588 {
1589 if (r->x > w || r->y > h || (r->x + r->w) <= 0 || (r->y + r->h) <= 0)
1590 return 0;
1591 else {
1592 int right = MIN(r->x + r->w, w);
1593 int bottom = MIN(r->y + r->h, h);
1594 cur->x = (short)MAX(r->x, 0);
1595 cur->y = (short)MAX(r->y, 0);
1596 cur->w = (unsigned short)right - cur->x;
1597 cur->h = (unsigned short)bottom - cur->y;
1598 }
1599 return cur;
1600 }
1601
1602 static PyObject *
pg_update(PyObject * self,PyObject * arg)1603 pg_update(PyObject *self, PyObject *arg)
1604 {
1605 SDL_Window *win = pg_GetDefaultWindow();
1606 _DisplayState *state = DISPLAY_MOD_STATE(self);
1607 GAME_Rect *gr, temp = {0};
1608 int wide, high;
1609 PyObject *obj;
1610
1611 VIDEO_INIT_CHECK();
1612
1613 if (!win)
1614 return RAISE(pgExc_SDLError, "Display mode not set");
1615 if (pg_renderer != NULL) {
1616 return pg_flip(self);
1617 }
1618 SDL_GetWindowSize(win, &wide, &high);
1619
1620 if (state->using_gl)
1621 return RAISE(pgExc_SDLError, "Cannot update an OPENGL display");
1622
1623 /*determine type of argument we got*/
1624 if (PyTuple_Size(arg) == 0) {
1625 return pg_flip(self);
1626 }
1627 else {
1628 obj = PyTuple_GET_ITEM(arg, 0);
1629 if (obj == Py_None)
1630 gr = &temp;
1631 else {
1632 gr = pgRect_FromObject(arg, &temp);
1633 if (!gr)
1634 PyErr_Clear();
1635 else if (gr != &temp) {
1636 memcpy(&temp, gr, sizeof(temp));
1637 gr = &temp;
1638 }
1639 }
1640 }
1641
1642 if (gr) {
1643 SDL_Rect sdlr;
1644
1645 if (pg_screencroprect(gr, wide, high, &sdlr))
1646 SDL_UpdateWindowSurfaceRects(win, &sdlr, 1);
1647 }
1648 else {
1649 PyObject *seq;
1650 PyObject *r;
1651 Py_ssize_t loop, num;
1652 int count;
1653 SDL_Rect *rects;
1654 if (PyTuple_Size(arg) != 1)
1655 return RAISE(
1656 PyExc_ValueError,
1657 "update requires a rectstyle or sequence of recstyles");
1658 seq = PyTuple_GET_ITEM(arg, 0);
1659 if (!seq || !PySequence_Check(seq))
1660 return RAISE(
1661 PyExc_ValueError,
1662 "update requires a rectstyle or sequence of recstyles");
1663
1664 num = PySequence_Length(seq);
1665 rects = PyMem_New(SDL_Rect, num);
1666 if (!rects)
1667 return NULL;
1668 count = 0;
1669 for (loop = 0; loop < num; ++loop) {
1670 SDL_Rect *cur_rect = (rects + count);
1671
1672 /*get rect from the sequence*/
1673 r = PySequence_GetItem(seq, loop);
1674 if (r == Py_None) {
1675 Py_DECREF(r);
1676 continue;
1677 }
1678 gr = pgRect_FromObject(r, &temp);
1679 Py_XDECREF(r);
1680 if (!gr) {
1681 PyMem_Free((char *)rects);
1682 return RAISE(PyExc_ValueError,
1683 "update_rects requires a single list of rects");
1684 }
1685
1686 if (gr->w < 1 && gr->h < 1)
1687 continue;
1688
1689 /*bail out if rect not onscreen*/
1690 if (!pg_screencroprect(gr, wide, high, cur_rect))
1691 continue;
1692
1693 ++count;
1694 }
1695
1696 if (count) {
1697 Py_BEGIN_ALLOW_THREADS;
1698 SDL_UpdateWindowSurfaceRects(win, rects, count);
1699 Py_END_ALLOW_THREADS;
1700 }
1701
1702 PyMem_Free((char *)rects);
1703 }
1704 Py_RETURN_NONE;
1705 }
1706
1707 static PyObject *
pg_set_palette(PyObject * self,PyObject * args)1708 pg_set_palette(PyObject *self, PyObject *args)
1709 {
1710 pgSurfaceObject *surface = pg_GetDefaultWindowSurface();
1711 SDL_Surface *surf;
1712 SDL_Palette *pal;
1713 SDL_Color *colors;
1714 PyObject *list, *item = NULL;
1715 int i, len;
1716 int r, g, b;
1717
1718 VIDEO_INIT_CHECK();
1719 if (!PyArg_ParseTuple(args, "|O", &list))
1720 return NULL;
1721 if (!surface)
1722 return RAISE(pgExc_SDLError, "No display mode is set");
1723 Py_INCREF(surface);
1724 surf = pgSurface_AsSurface(surface);
1725 pal = surf->format->palette;
1726 if (surf->format->BytesPerPixel != 1 || !pal) {
1727 Py_DECREF(surface);
1728 return RAISE(pgExc_SDLError, "Display mode is not colormapped");
1729 }
1730
1731 if (!list) {
1732 Py_DECREF(surface);
1733 Py_RETURN_NONE;
1734 }
1735
1736 if (!PySequence_Check(list)) {
1737 Py_DECREF(surface);
1738 return RAISE(PyExc_ValueError, "Argument must be a sequence type");
1739 }
1740
1741 len = MIN(pal->ncolors, PySequence_Length(list));
1742
1743 colors = (SDL_Color *)malloc(len * sizeof(SDL_Color));
1744 if (!colors) {
1745 Py_DECREF(surface);
1746 return PyErr_NoMemory();
1747 }
1748
1749 for (i = 0; i < len; i++) {
1750 item = PySequence_GetItem(list, i);
1751 if (!PySequence_Check(item) || PySequence_Length(item) != 3) {
1752 Py_DECREF(item);
1753 free((char *)colors);
1754 Py_DECREF(surface);
1755 return RAISE(PyExc_TypeError,
1756 "takes a sequence of sequence of RGB");
1757 }
1758 if (!pg_IntFromObjIndex(item, 0, &r) ||
1759 !pg_IntFromObjIndex(item, 1, &g) ||
1760 !pg_IntFromObjIndex(item, 2, &b)) {
1761 Py_DECREF(item);
1762 free((char *)colors);
1763 Py_DECREF(surface);
1764 return RAISE(PyExc_TypeError,
1765 "RGB sequence must contain numeric values");
1766 }
1767
1768 colors[i].r = (unsigned char)r;
1769 colors[i].g = (unsigned char)g;
1770 colors[i].b = (unsigned char)b;
1771 colors[i].a = SDL_ALPHA_OPAQUE;
1772
1773 Py_DECREF(item);
1774 }
1775
1776 pal = SDL_AllocPalette(len);
1777 if (!pal) {
1778 free((char *)colors);
1779 Py_DECREF(surface);
1780 return RAISE(pgExc_SDLError, SDL_GetError());
1781 }
1782 if (!SDL_SetPaletteColors(pal, colors, 0, len)) {
1783 SDL_FreePalette(pal);
1784 free((char *)colors);
1785 Py_DECREF(surface);
1786 return RAISE(pgExc_SDLError, SDL_GetError());
1787 }
1788
1789 SDL_SetSurfacePalette(surf, pal);
1790 SDL_FreePalette(pal);
1791 free((char *)colors);
1792 Py_DECREF(surface);
1793 Py_RETURN_NONE;
1794 }
1795
1796 static PyObject *
pg_set_gamma(PyObject * self,PyObject * arg)1797 pg_set_gamma(PyObject *self, PyObject *arg)
1798 {
1799 float r, g, b;
1800 int result = 0;
1801 _DisplayState *state = DISPLAY_MOD_STATE(self);
1802 SDL_Window *win = pg_GetDefaultWindow();
1803 Uint16 *gamma_ramp;
1804
1805 if (!PyArg_ParseTuple(arg, "f|ff", &r, &g, &b))
1806 return NULL;
1807 if (PyTuple_Size(arg) == 1)
1808 g = b = r;
1809 VIDEO_INIT_CHECK();
1810
1811 gamma_ramp = (Uint16 *)malloc((3 * 256) * sizeof(Uint16));
1812 if (!gamma_ramp)
1813 return PyErr_NoMemory();
1814 SDL_CalculateGammaRamp(r, gamma_ramp);
1815 SDL_CalculateGammaRamp(g, gamma_ramp + 256);
1816 SDL_CalculateGammaRamp(b, gamma_ramp + 512);
1817 if (win) {
1818 result = SDL_SetWindowGammaRamp(win, gamma_ramp, gamma_ramp + 256,
1819 gamma_ramp + 512);
1820 if (result) {
1821 /* Discard a possibly faulty gamma ramp */
1822 free(gamma_ramp);
1823 gamma_ramp = NULL;
1824 }
1825 }
1826 if (gamma_ramp) {
1827 if (state->gamma_ramp)
1828 free(state->gamma_ramp);
1829 state->gamma_ramp = gamma_ramp;
1830 }
1831 return PyBool_FromLong(result == 0);
1832 }
1833
1834
1835 static int
pg_convert_to_uint16(PyObject * python_array,Uint16 * c_uint16_array)1836 pg_convert_to_uint16(PyObject *python_array, Uint16 *c_uint16_array)
1837 {
1838 int i;
1839 PyObject *item;
1840
1841 if (!c_uint16_array) {
1842 PyErr_SetString(PyExc_RuntimeError,
1843 "Memory not allocated for c_uint16_array.");
1844 return 0;
1845 }
1846 if (!PySequence_Check(python_array)) {
1847 PyErr_SetString(PyExc_TypeError, "Array must be sequence type");
1848 return 0;
1849 }
1850 if (PySequence_Size(python_array) != 256) {
1851 PyErr_SetString(PyExc_ValueError,
1852 "gamma ramp must be 256 elements long");
1853 return 0;
1854 }
1855 for (i = 0; i < 256; i++) {
1856 item = PySequence_GetItem(python_array, i);
1857 if (!PyInt_Check(item)) {
1858 PyErr_SetString(PyExc_ValueError,
1859 "gamma ramp must contain integer elements");
1860 return 0;
1861 }
1862 c_uint16_array[i] = (Uint16)PyInt_AsLong(item);
1863 Py_XDECREF(item);
1864 }
1865 return 1;
1866 }
1867
1868 static PyObject *
pg_set_gamma_ramp(PyObject * self,PyObject * arg)1869 pg_set_gamma_ramp(PyObject *self, PyObject *arg)
1870 {
1871 _DisplayState *state = DISPLAY_MOD_STATE(self);
1872 SDL_Window *win = pg_GetDefaultWindow();
1873 Uint16 *gamma_ramp = (Uint16 *)malloc((3 * 256) * sizeof(Uint16));
1874 Uint16 *r, *g, *b;
1875 int result = 0;
1876 if (!gamma_ramp)
1877 return PyErr_NoMemory();
1878 r = gamma_ramp;
1879 g = gamma_ramp + 256;
1880 b = gamma_ramp + 512;
1881 if (!PyArg_ParseTuple(arg, "O&O&O&", pg_convert_to_uint16, r,
1882 pg_convert_to_uint16, g, pg_convert_to_uint16, b)) {
1883 free(gamma_ramp);
1884 return NULL;
1885 }
1886 VIDEO_INIT_CHECK();
1887 if (win) {
1888 result = SDL_SetWindowGammaRamp(win, gamma_ramp, gamma_ramp + 256,
1889 gamma_ramp + 512);
1890 if (result) {
1891 /* Discard a possibly faulty gamma ramp */
1892 free(gamma_ramp);
1893 gamma_ramp = NULL;
1894 }
1895 }
1896 if (gamma_ramp) {
1897 if (state->gamma_ramp)
1898 free(state->gamma_ramp);
1899 state->gamma_ramp = gamma_ramp;
1900 }
1901 return PyBool_FromLong(result == 0);
1902 }
1903
1904 static PyObject *
pg_set_caption(PyObject * self,PyObject * arg)1905 pg_set_caption(PyObject *self, PyObject *arg)
1906 {
1907 _DisplayState *state = DISPLAY_MOD_STATE(self);
1908 SDL_Window *win = pg_GetDefaultWindow();
1909 char *title, *icontitle = NULL;
1910 if (!PyArg_ParseTuple(arg, "es|es", "UTF-8", &title, "UTF-8", &icontitle))
1911 return NULL;
1912
1913 if (state->title)
1914 free(state->title);
1915 state->title = (char *)malloc((strlen(title) + 1) * sizeof(char));
1916 if (!state->title) {
1917 PyErr_NoMemory();
1918 goto error;
1919 }
1920 strcpy(state->title, title);
1921 if (win)
1922 SDL_SetWindowTitle(win, title);
1923 /* TODO: icon title? */
1924
1925 PyMem_Free(title);
1926 PyMem_Free(icontitle);
1927 Py_RETURN_NONE;
1928
1929 error:
1930 PyMem_Free(title);
1931 PyMem_Free(icontitle);
1932 return NULL;
1933 }
1934
1935 static PyObject *
pg_get_caption(PyObject * self)1936 pg_get_caption(PyObject *self)
1937 {
1938 _DisplayState *state = DISPLAY_MOD_STATE(self);
1939 SDL_Window *win = pg_GetDefaultWindow();
1940 const char *title = win ? SDL_GetWindowTitle(win) : state->title;
1941
1942 if (title && *title) {
1943 PyObject *titleObj = Text_FromUTF8(title);
1944 PyObject *ret = PyTuple_Pack(2, titleObj, titleObj);
1945 Py_DECREF(titleObj);
1946 /* TODO: icon title? */
1947 return ret;
1948 }
1949 return PyTuple_New(0);
1950 }
1951
1952 static PyObject *
pg_set_icon(PyObject * self,PyObject * arg)1953 pg_set_icon(PyObject *self, PyObject *arg)
1954 {
1955 _DisplayState *state = DISPLAY_MOD_STATE(self);
1956 SDL_Window *win = pg_GetDefaultWindow();
1957 PyObject *surface;
1958 if (!PyArg_ParseTuple(arg, "O!", &pgSurface_Type, &surface))
1959 return NULL;
1960
1961 if (!SDL_WasInit(SDL_INIT_VIDEO)) {
1962 if (!pg_display_init(NULL))
1963 return NULL;
1964 }
1965 Py_INCREF(surface);
1966 Py_XDECREF(state->icon);
1967 state->icon = surface;
1968 if (win)
1969 SDL_SetWindowIcon(win, pgSurface_AsSurface(surface));
1970 Py_RETURN_NONE;
1971 }
1972
1973 static PyObject *
pg_iconify(PyObject * self)1974 pg_iconify(PyObject *self)
1975 {
1976 SDL_Window *win = pg_GetDefaultWindow();
1977 VIDEO_INIT_CHECK();
1978 if (!win)
1979 return RAISE(pgExc_SDLError, "No open window");
1980 SDL_MinimizeWindow(win);
1981 return PyBool_FromLong(1);
1982 }
1983
1984 /* This is only here for debugging purposes. Games should not rely on the
1985 * implementation details of specific renderers, only on the documented
1986 * behaviour of SDL_Renderer. It's fine to debug-print which renderer a game is
1987 * running on, or to inform the user when the game is not running with HW
1988 * acceleration, but openGL can still be available without HW acceleration. */
1989 static PyObject *
pg_get_scaled_renderer_info(PyObject * self)1990 pg_get_scaled_renderer_info(PyObject *self)
1991 {
1992 SDL_Window *win = pg_GetDefaultWindow();
1993 SDL_RendererInfo r_info;
1994
1995 VIDEO_INIT_CHECK();
1996 if (!win)
1997 return RAISE(pgExc_SDLError, "No open window");
1998
1999 if (pg_renderer != NULL) {
2000 if (SDL_GetRendererInfo(pg_renderer, &r_info) == 0) {
2001 return PyTuple_Pack(2, PyUnicode_FromString(r_info.name),
2002 PyLong_FromLong(r_info.flags));
2003 }
2004 else {
2005 Py_RETURN_NONE;
2006 }
2007 }
2008 else {
2009 Py_RETURN_NONE;
2010 }
2011 }
2012
2013 static PyObject *
pg_get_desktop_screen_sizes(PyObject * self)2014 pg_get_desktop_screen_sizes(PyObject *self)
2015 {
2016 int display_count, i;
2017 SDL_DisplayMode dm;
2018 PyObject *result;
2019
2020 VIDEO_INIT_CHECK();
2021
2022 display_count = SDL_GetNumVideoDisplays();
2023
2024 result = PyList_New(display_count);
2025 if (result == NULL) {
2026 Py_RETURN_NONE;
2027 }
2028 for (i = 0; i < display_count; i++) {
2029 if (SDL_GetDesktopDisplayMode(i, &dm) != 0) {
2030 Py_RETURN_NONE;
2031 }
2032 if (PyList_SetItem(result, i,
2033 PyTuple_Pack(2, PyLong_FromLong(dm.w),
2034 PyLong_FromLong(dm.h))) != 0) {
2035 Py_RETURN_NONE;
2036 }
2037 }
2038 return result;
2039 }
2040
2041 static PyObject *
pg_is_fullscreen(PyObject * self)2042 pg_is_fullscreen(PyObject *self)
2043 {
2044 SDL_Window *win = pg_GetDefaultWindow();
2045 int flags;
2046
2047 VIDEO_INIT_CHECK();
2048 if (!win)
2049 return RAISE(pgExc_SDLError, "No open window");
2050
2051 flags = SDL_GetWindowFlags(win) & SDL_WINDOW_FULLSCREEN_DESKTOP;
2052
2053 if (flags & SDL_WINDOW_FULLSCREEN)
2054 Py_RETURN_TRUE;
2055 else
2056 Py_RETURN_FALSE;
2057 }
2058
2059 static PyObject *
pg_toggle_fullscreen(PyObject * self,PyObject * args)2060 pg_toggle_fullscreen(PyObject *self, PyObject *args)
2061 {
2062 SDL_Window *win = pg_GetDefaultWindow();
2063 int result, flags;
2064 int window_w, window_h, w, h, window_display;
2065 SDL_DisplayMode display_mode;
2066 pgSurfaceObject *display_surface;
2067 _DisplayState *state = DISPLAY_MOD_STATE(self);
2068 GL_glViewport_Func p_glViewport = NULL;
2069 SDL_SysWMinfo wm_info;
2070 SDL_RendererInfo r_info;
2071
2072 VIDEO_INIT_CHECK();
2073 if (!win)
2074 return RAISE(pgExc_SDLError, "No open window");
2075
2076 flags = SDL_GetWindowFlags(win) & SDL_WINDOW_FULLSCREEN_DESKTOP;
2077 /* SDL_WINDOW_FULLSCREEN_DESKTOP includes SDL_WINDOW_FULLSCREEN */
2078
2079 SDL_VERSION(&wm_info.version);
2080 if (!SDL_GetWindowWMInfo(win, &wm_info)) {
2081 return RAISE(pgExc_SDLError, SDL_GetError());
2082 }
2083
2084 if (state->using_gl && pg_renderer != NULL) {
2085 return RAISE(pgExc_SDLError,
2086 "OPENGL and SDL_Renderer active at the same time");
2087 }
2088
2089 if (pg_renderer != NULL) {
2090 if (SDL_GetRendererInfo(pg_renderer, &r_info) != 0) {
2091 return RAISE(pgExc_SDLError, SDL_GetError());
2092 }
2093 }
2094
2095 switch (wm_info.subsystem) {
2096 // if we get this to work correctly with more systems, move them here
2097 case SDL_SYSWM_WINDOWS:
2098 case SDL_SYSWM_X11:
2099 case SDL_SYSWM_COCOA:
2100 #if SDL_VERSION_ATLEAST(2, 0, 2)
2101 case SDL_SYSWM_WAYLAND:
2102 #endif
2103 break;
2104
2105 // These probably have fullscreen/windowed, but not tested yet.
2106 // before merge, this section should be handled by moving items
2107 // into the "supported" category, or returning early.
2108
2109 #if SDL_VERSION_ATLEAST(2, 0, 3)
2110 case SDL_SYSWM_WINRT: // currently not supported by pygame?
2111 #endif
2112 return PyInt_FromLong(-1);
2113
2114 // On these platforms, everything is fullscreen at all times anyway
2115 // So we silently fail
2116 // In the future, add consoles like xbone/switch here
2117 case SDL_SYSWM_DIRECTFB:
2118 case SDL_SYSWM_UIKIT: // iOS currently not supported by pygame
2119 #if SDL_VERSION_ATLEAST(2, 0, 4)
2120 case SDL_SYSWM_ANDROID: // currently not supported by pygame
2121 #endif
2122 if (PyErr_WarnEx(PyExc_Warning,
2123 "cannot leave FULLSCREEN on this platform",
2124 1) != 0) {
2125 return NULL;
2126 }
2127 return PyInt_FromLong(-1);
2128
2129 // Untested and unsupported platforms
2130 #if SDL_VERSION_ATLEAST(2, 0, 2)
2131 case SDL_SYSWM_MIR: // nobody uses mir any more, wayland has won
2132 #endif
2133 #if SDL_VERSION_ATLEAST(2, 0, 5)
2134 case SDL_SYSWM_VIVANTE:
2135 #endif
2136 case SDL_SYSWM_UNKNOWN:
2137 default:
2138 return RAISE(pgExc_SDLError, "Unsupported platform");
2139 }
2140
2141 display_surface = pg_GetDefaultWindowSurface();
2142
2143 // could also take the size of the old display surface
2144 SDL_GetWindowSize(win, &window_w, &window_h);
2145 window_display = SDL_GetWindowDisplayIndex(win);
2146 if (SDL_GetDesktopDisplayMode(window_display, &display_mode) != 0) {
2147 return RAISE(pgExc_SDLError, SDL_GetError());
2148 }
2149
2150 /*
2151 if (pg_renderer != NULL) {
2152 SDL_RenderGetLogicalSize(pg_renderer, &w, &h);
2153 } else
2154 */
2155 if (state->using_gl) {
2156 p_glViewport = (GL_glViewport_Func)SDL_GL_GetProcAddress("glViewport");
2157 SDL_GL_GetDrawableSize(win, &w, &h);
2158 }
2159 else {
2160 w = display_surface->surf->w;
2161 h = display_surface->surf->h;
2162 }
2163
2164 if (flags & SDL_WINDOW_FULLSCREEN) {
2165 /* TOGGLE FULLSCREEN OFF */
2166
2167 if (pg_renderer != NULL) {
2168 int scale = 1;
2169 int xscale, yscale;
2170
2171 xscale = window_w / w;
2172 yscale = window_h / h;
2173 scale = xscale < yscale ? xscale : yscale;
2174 if (scale < 1) {
2175 scale = 1;
2176 }
2177 result = SDL_SetWindowFullscreen(win, 0);
2178 if (result != 0) {
2179 return RAISE(pgExc_SDLError, SDL_GetError());
2180 }
2181 SDL_SetWindowSize(win, w * scale, h * scale);
2182
2183 if (r_info.flags & SDL_RENDERER_SOFTWARE &&
2184 wm_info.subsystem == SDL_SYSWM_X11) {
2185 /* display surface lost? */
2186 SDL_DestroyTexture(pg_texture);
2187 SDL_DestroyRenderer(pg_renderer);
2188 pg_renderer =
2189 SDL_CreateRenderer(win, -1, SDL_RENDERER_SOFTWARE);
2190 pg_texture =
2191 SDL_CreateTexture(pg_renderer, SDL_PIXELFORMAT_ARGB8888,
2192 SDL_TEXTUREACCESS_STREAMING, w, h);
2193 }
2194 SDL_RenderSetLogicalSize(pg_renderer, w, h);
2195
2196 #if (SDL_VERSION_ATLEAST(2, 0, 5))
2197 /* use exact integer scale in windowed mode */
2198 SDL_RenderSetIntegerScale(
2199 pg_renderer, !SDL_GetHintBoolean(
2200 "SDL_HINT_RENDER_SCALE_QUALITY", SDL_FALSE));
2201 #endif
2202 SDL_SetWindowMinimumSize(win, w, h);
2203 }
2204 else if (state->using_gl) {
2205 /* this is literally the only place where state->toggle_windowed_w
2206 * should ever be read. We only use it because with GL, there is no
2207 * display surface we can query for dimensions. */
2208 result = SDL_SetWindowFullscreen(win, 0);
2209 if (result != 0) {
2210 return RAISE(pgExc_SDLError, SDL_GetError());
2211 }
2212 SDL_GL_MakeCurrent(win, state->gl_context);
2213 if (state->toggle_windowed_w > 0 && state->toggle_windowed_h > 0) {
2214 if (state->scaled_gl) {
2215 float saved_aspect_ratio =
2216 ((float)state->toggle_windowed_w) /
2217 (float)state->toggle_windowed_h;
2218 float window_aspect_ratio =
2219 ((float)display_mode.w) / (float)display_mode.h;
2220
2221 if (window_aspect_ratio > saved_aspect_ratio) {
2222 int width = (int)(state->toggle_windowed_h *
2223 saved_aspect_ratio);
2224 p_glViewport((state->toggle_windowed_w - width) / 2, 0,
2225 width, state->toggle_windowed_h);
2226 }
2227 else {
2228 p_glViewport(0, 0, state->toggle_windowed_w,
2229 (int)(state->toggle_windowed_w /
2230 saved_aspect_ratio));
2231 }
2232 }
2233 else {
2234 p_glViewport(0, 0, state->toggle_windowed_w,
2235 state->toggle_windowed_h);
2236 }
2237 }
2238 }
2239 else if ((flags & SDL_WINDOW_FULLSCREEN_DESKTOP) ==
2240 SDL_WINDOW_FULLSCREEN_DESKTOP) {
2241 result = SDL_SetWindowFullscreen(win, 0);
2242 if (result != 0) {
2243 return RAISE(pgExc_SDLError, SDL_GetError());
2244 }
2245 display_surface->surf = SDL_GetWindowSurface(win);
2246 }
2247 else if (wm_info.subsystem == SDL_SYSWM_X11) {
2248 /* This is a HACK, specifically to work around faulty behaviour of
2249 * SDL_SetWindowFullscreen on X11 when switching out of fullscreen
2250 * would change the physical resolution of the display back to the
2251 * desktop resolution in SDL 2.0.8 (unsure about other versions).
2252 * The display surface gets messed up, so we re-create the window.
2253 * This is only relevant in the non-GL case. */
2254 int wx = SDL_WINDOWPOS_UNDEFINED_DISPLAY(window_display);
2255 int wy = SDL_WINDOWPOS_UNDEFINED_DISPLAY(window_display);
2256 if (PyErr_WarnEx(PyExc_Warning,
2257 "re-creating window in toggle_fullscreen",
2258 1) != 0) {
2259 return NULL;
2260 }
2261 win = SDL_CreateWindow(state->title, wx, wy, w, h, 0);
2262 if (win == NULL) {
2263 return RAISE(pgExc_SDLError, SDL_GetError());
2264 }
2265 else {
2266 result = 0;
2267 }
2268 display_surface->surf = SDL_GetWindowSurface(win);
2269 pg_SetDefaultWindow(win);
2270 }
2271 else {
2272 result = SDL_SetWindowFullscreen(win, 0);
2273 if (result != 0) {
2274 return RAISE(pgExc_SDLError, SDL_GetError());
2275 }
2276 display_surface->surf = SDL_GetWindowSurface(win);
2277 }
2278 state->toggle_windowed_w = 0;
2279 state->toggle_windowed_h = 0;
2280 }
2281 else {
2282 /* TOGGLE FULLSCREEN ON */
2283
2284 state->toggle_windowed_w = w;
2285 state->toggle_windowed_h = h;
2286 if (pg_renderer != NULL) {
2287 result =
2288 SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN_DESKTOP);
2289 if (result != 0) {
2290 return RAISE(pgExc_SDLError, SDL_GetError());
2291 }
2292 if (r_info.flags & SDL_RENDERER_SOFTWARE &&
2293 wm_info.subsystem == SDL_SYSWM_X11) {
2294 if (PyErr_WarnEx(
2295 PyExc_Warning,
2296 "recreating software renderer in toggle_fullscreen",
2297 1) != 0) {
2298 return NULL;
2299 }
2300 /* display surface lost? only on x11? */
2301 SDL_DestroyTexture(pg_texture);
2302 SDL_DestroyRenderer(pg_renderer);
2303 pg_renderer =
2304 SDL_CreateRenderer(win, -1, SDL_RENDERER_SOFTWARE);
2305 pg_texture =
2306 SDL_CreateTexture(pg_renderer, SDL_PIXELFORMAT_ARGB8888,
2307 SDL_TEXTUREACCESS_STREAMING, w, h);
2308 }
2309
2310 SDL_RenderSetLogicalSize(pg_renderer, w, h);
2311 #if (SDL_VERSION_ATLEAST(2, 0, 5))
2312 SDL_RenderSetIntegerScale(pg_renderer, SDL_FALSE);
2313 #endif
2314 }
2315 else if (state->using_gl) {
2316 result =
2317 SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN_DESKTOP);
2318 if (result != 0) {
2319 return RAISE(pgExc_SDLError, SDL_GetError());
2320 }
2321 SDL_GL_MakeCurrent(win, state->gl_context);
2322 if (state->scaled_gl) {
2323 float saved_aspect_ratio =
2324 ((float)state->scaled_gl_w) / (float)state->scaled_gl_h;
2325 float window_aspect_ratio =
2326 ((float)display_mode.w) / (float)display_mode.h;
2327
2328 if (window_aspect_ratio > saved_aspect_ratio) {
2329 int width = (int)(display_mode.h * saved_aspect_ratio);
2330 p_glViewport((display_mode.w - width) / 2, 0, width,
2331 display_mode.h);
2332 }
2333 else {
2334 p_glViewport(0, 0, display_mode.w,
2335 (int)(display_mode.w / saved_aspect_ratio));
2336 }
2337 }
2338 else {
2339 p_glViewport(0, 0, display_mode.w, display_mode.h);
2340 }
2341 }
2342 else if (w == display_mode.w && h == display_mode.h) {
2343 result =
2344 SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN_DESKTOP);
2345 if (result != 0) {
2346 return RAISE(pgExc_SDLError, SDL_GetError());
2347 }
2348 display_surface->surf = SDL_GetWindowSurface(win);
2349 }
2350 else if (wm_info.subsystem == SDL_SYSWM_WAYLAND) {
2351 if (PyErr_WarnEx(PyExc_Warning,
2352 "skipping toggle_fullscreen on wayland",
2353 1) != 0) {
2354 return NULL;
2355 }
2356 return PyInt_FromLong(-1);
2357 }
2358 else {
2359 result = SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN);
2360 if (result != 0) {
2361 return RAISE(pgExc_SDLError, SDL_GetError());
2362 }
2363 display_surface->surf = SDL_GetWindowSurface(win);
2364 if (w != display_surface->surf->w ||
2365 h != display_surface->surf->h) {
2366 int wx = SDL_WINDOWPOS_UNDEFINED_DISPLAY(window_display);
2367 int wy = SDL_WINDOWPOS_UNDEFINED_DISPLAY(window_display);
2368 win = SDL_CreateWindow(state->title, wx, wy, w, h, 0);
2369 if (win == NULL) {
2370 return RAISE(pgExc_SDLError, SDL_GetError());
2371 }
2372 display_surface->surf = SDL_GetWindowSurface(win);
2373 pg_SetDefaultWindow(win);
2374 if (PyErr_WarnEx(PyExc_Warning,
2375 "re-creating window in toggle_fullscreen",
2376 1) != 0) {
2377 return NULL;
2378 }
2379 return PyInt_FromLong(-1);
2380 }
2381 }
2382 }
2383 return PyInt_FromLong(result != 0);
2384 }
2385
2386 /* This API is provisional, and, not finalised, and should not be documented
2387 * in any user-facing docs until we are sure when this is safe to call and when
2388 * it should raise an exception */
2389 static PyObject *
pg_display_resize_event(PyObject * self,PyObject * event)2390 pg_display_resize_event(PyObject *self, PyObject *event)
2391 {
2392 /* Call this from your game if you want to use RESIZABLE with SCALED
2393 * TODO: Document, handle bad args, bail on FULLSCREEN
2394 */
2395 int wnew = PyLong_AsLong(PyObject_GetAttrString(event, "w"));
2396 int hnew = PyLong_AsLong(PyObject_GetAttrString(event, "h"));
2397 SDL_Window *win = pg_GetDefaultWindow();
2398 int flags;
2399 int window_w, window_h, w, h, window_display, result;
2400 SDL_DisplayMode display_mode;
2401 _DisplayState *state = DISPLAY_MOD_STATE(self);
2402 GL_glViewport_Func p_glViewport = NULL;
2403
2404 VIDEO_INIT_CHECK();
2405 if (!win)
2406 return RAISE(pgExc_SDLError, "No open window");
2407
2408 flags = SDL_GetWindowFlags(win) &
2409 (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP);
2410
2411 if (flags) {
2412 return PyInt_FromLong(-1);
2413 }
2414
2415 // could also take the size of the old display surface
2416 SDL_GetWindowSize(win, &window_w, &window_h);
2417 window_display = SDL_GetWindowDisplayIndex(win);
2418 if (SDL_GetDesktopDisplayMode(window_display, &display_mode) != 0) {
2419 return RAISE(pgExc_SDLError, SDL_GetError());
2420 }
2421
2422 if (state->using_gl) {
2423 p_glViewport = (GL_glViewport_Func)SDL_GL_GetProcAddress("glViewport");
2424 SDL_SetWindowSize(win, wnew, hnew);
2425 SDL_GL_MakeCurrent(win, state->gl_context);
2426 if (state->scaled_gl) {
2427 float saved_aspect_ratio =
2428 ((float)state->scaled_gl_w) / (float)state->scaled_gl_h;
2429 float window_aspect_ratio = ((float)wnew) / (float)hnew;
2430
2431 if (window_aspect_ratio > saved_aspect_ratio) {
2432 int width = (int)(hnew * saved_aspect_ratio);
2433 p_glViewport((wnew - width) / 2, 0, width, hnew);
2434 }
2435 else {
2436 p_glViewport(0, 0, wnew, (int)(wnew / saved_aspect_ratio));
2437 }
2438 }
2439 else {
2440 p_glViewport(0, 0, wnew, hnew);
2441 }
2442 }
2443 else if (pg_renderer != NULL) {
2444 SDL_RenderGetLogicalSize(pg_renderer, &w, &h);
2445 SDL_SetWindowSize(win, (w > wnew) ? w : wnew, (h > hnew) ? h : hnew);
2446 result = SDL_RenderSetLogicalSize(pg_renderer, w, h);
2447 if (result != 0) {
2448 return RAISE(pgExc_SDLError, SDL_GetError());
2449 }
2450 }
2451 else {
2452 /* do not do anything that would invalidate a display surface! */
2453 return PyInt_FromLong(-1);
2454 }
2455 Py_RETURN_FALSE;
2456 }
2457
2458
2459
2460 static PyObject *
pg_get_allow_screensaver(PyObject * self)2461 pg_get_allow_screensaver(PyObject *self) {
2462 /* SDL_IsScreenSaverEnabled() unconditionally returns SDL_True if
2463 * the video system is not initialized. Therefore we insist on
2464 * the video being initialized before calling it.
2465 */
2466 VIDEO_INIT_CHECK();
2467 return PyBool_FromLong(SDL_IsScreenSaverEnabled() == SDL_TRUE);
2468 }
2469
2470 static PyObject *
pg_set_allow_screensaver(PyObject * self,PyObject * arg,PyObject * kwargs)2471 pg_set_allow_screensaver(PyObject *self, PyObject *arg, PyObject *kwargs) {
2472 int val = 1;
2473 static char *keywords[] = {"value", NULL};
2474
2475 if (!PyArg_ParseTupleAndKeywords(arg, kwargs, "|i", keywords, &val)) {
2476 return NULL;
2477 }
2478
2479 VIDEO_INIT_CHECK();
2480 if (val) {
2481 SDL_EnableScreenSaver();
2482 } else {
2483 SDL_DisableScreenSaver();
2484 }
2485
2486 Py_RETURN_NONE;
2487 }
2488
2489 static PyMethodDef _pg_display_methods[] = {
2490 {"init", (PyCFunction)pg_display_init, METH_NOARGS, DOC_PYGAMEDISPLAYINIT},
2491 {"quit", (PyCFunction)pg_display_quit, METH_NOARGS, DOC_PYGAMEDISPLAYQUIT},
2492 {"get_init", (PyCFunction)pg_get_init, METH_NOARGS, DOC_PYGAMEDISPLAYGETINIT},
2493 {"get_active", (PyCFunction)pg_get_active, METH_NOARGS, DOC_PYGAMEDISPLAYGETACTIVE},
2494
2495 /* { "set_driver", set_driver, 1, doc_set_driver }, */
2496 {"get_driver", (PyCFunction)pg_get_driver, METH_NOARGS,
2497 DOC_PYGAMEDISPLAYGETDRIVER},
2498 {"get_wm_info", (PyCFunction)pg_get_wm_info, METH_NOARGS,
2499 DOC_PYGAMEDISPLAYGETWMINFO},
2500 {"Info", (PyCFunction)pgInfo, METH_NOARGS, DOC_PYGAMEDISPLAYINFO},
2501 {"get_surface", (PyCFunction)pg_get_surface, METH_NOARGS, DOC_PYGAMEDISPLAYGETSURFACE},
2502 {"get_window_size", (PyCFunction)pg_window_size, METH_NOARGS,
2503 DOC_PYGAMEDISPLAYGETWINDOWSIZE},
2504
2505 {"set_mode", (PyCFunction)pg_set_mode, METH_VARARGS | METH_KEYWORDS,
2506 DOC_PYGAMEDISPLAYSETMODE},
2507 {"mode_ok", (PyCFunction)pg_mode_ok, METH_VARARGS | METH_KEYWORDS,
2508 DOC_PYGAMEDISPLAYMODEOK},
2509 {"list_modes", (PyCFunction)pg_list_modes, METH_VARARGS | METH_KEYWORDS,
2510 DOC_PYGAMEDISPLAYLISTMODES},
2511 {"get_num_displays", (PyCFunction)pg_num_displays, METH_NOARGS,
2512 DOC_PYGAMEDISPLAYGETNUMDISPLAYS},
2513
2514 {"flip", (PyCFunction)pg_flip, METH_NOARGS, DOC_PYGAMEDISPLAYFLIP},
2515 {"update", (PyCFunction)pg_update, METH_VARARGS, DOC_PYGAMEDISPLAYUPDATE},
2516
2517 {"set_palette", pg_set_palette, METH_VARARGS, DOC_PYGAMEDISPLAYSETPALETTE},
2518 {"set_gamma", pg_set_gamma, METH_VARARGS, DOC_PYGAMEDISPLAYSETGAMMA},
2519 {"set_gamma_ramp", pg_set_gamma_ramp, METH_VARARGS,
2520 DOC_PYGAMEDISPLAYSETGAMMARAMP},
2521
2522 {"set_caption", pg_set_caption, METH_VARARGS, DOC_PYGAMEDISPLAYSETCAPTION},
2523 {"get_caption", (PyCFunction)pg_get_caption, METH_NOARGS, DOC_PYGAMEDISPLAYGETCAPTION},
2524 {"set_icon", pg_set_icon, METH_VARARGS, DOC_PYGAMEDISPLAYSETICON},
2525
2526 {"iconify", (PyCFunction)pg_iconify, METH_NOARGS, DOC_PYGAMEDISPLAYICONIFY},
2527 {"toggle_fullscreen", (PyCFunction)pg_toggle_fullscreen, METH_NOARGS,
2528 DOC_PYGAMEDISPLAYTOGGLEFULLSCREEN},
2529
2530 {"_set_autoresize", (PyCFunction)pg_display_set_autoresize
2531 , METH_VARARGS, "provisional API, subject to change"},
2532 {"_resize_event", (PyCFunction)pg_display_resize_event, METH_O,
2533 "DEPRECATED, never officially supported, kept only for compatibility with release candidate"},
2534 {"_get_renderer_info", (PyCFunction)pg_get_scaled_renderer_info,
2535 METH_NOARGS, "provisional API, subject to change"},
2536 {"get_desktop_sizes", (PyCFunction)pg_get_desktop_screen_sizes,
2537 METH_NOARGS, DOC_PYGAMEDISPLAYGETDESKTOPSIZES},
2538 {"is_fullscreen", (PyCFunction)pg_is_fullscreen, METH_NOARGS,
2539 "provisional API, subject to change"},
2540
2541 {"gl_set_attribute", pg_gl_set_attribute, METH_VARARGS,
2542 DOC_PYGAMEDISPLAYGLSETATTRIBUTE},
2543 {"gl_get_attribute", pg_gl_get_attribute, METH_VARARGS,
2544 DOC_PYGAMEDISPLAYGLGETATTRIBUTE},
2545
2546 {"get_allow_screensaver", (PyCFunction)pg_get_allow_screensaver, METH_NOARGS,
2547 DOC_PYGAMEDISPLAYGETALLOWSCREENSAVER},
2548 {"set_allow_screensaver", (PyCFunction)pg_set_allow_screensaver, METH_VARARGS | METH_KEYWORDS,
2549 DOC_PYGAMEDISPLAYSETALLOWSCREENSAVER},
2550
2551 {NULL, NULL, 0, NULL}};
2552
2553 #ifndef PYPY_VERSION
2554 static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT,
2555 "display",
2556 DOC_PYGAMEDISPLAY,
2557 sizeof(_DisplayState),
2558 _pg_display_methods,
2559 #pragma PG_WARN(At some point should add GC slot functions.)
2560 NULL,
2561 NULL,
2562 NULL,
2563 NULL};
2564 #else /* PYPY_VERSION */
2565 static struct PyModuleDef _module = {
2566 PyModuleDef_HEAD_INIT,
2567 "display",
2568 DOC_PYGAMEDISPLAY,
2569 -1, /* PyModule_GetState() not implemented */
2570 _pg_display_methods,
2571 NULL,
2572 NULL,
2573 NULL,
2574 NULL};
2575 #endif /* PYPY_VERSION */
2576
MODINIT_DEFINE(display)2577 MODINIT_DEFINE(display)
2578 {
2579 PyObject *module;
2580 _DisplayState *state;
2581
2582 /* imported needed apis; Do this first so if there is an error
2583 the module is not loaded.
2584 */
2585 import_pygame_base();
2586 if (PyErr_Occurred()) {
2587 MODINIT_ERROR;
2588 }
2589 import_pygame_rect();
2590 if (PyErr_Occurred()) {
2591 MODINIT_ERROR;
2592 }
2593 import_pygame_surface();
2594 if (PyErr_Occurred()) {
2595 MODINIT_ERROR;
2596 }
2597
2598 /* type preparation */
2599 if (PyType_Ready(&pgVidInfo_Type) < 0) {
2600 MODINIT_ERROR;
2601 }
2602
2603 /* create the module */
2604 module = PyModule_Create(&_module);
2605 if (module == NULL) {
2606 MODINIT_ERROR;
2607 }
2608 state = DISPLAY_MOD_STATE(module);
2609 state->title = NULL;
2610 state->icon = NULL;
2611 state->gamma_ramp = NULL;
2612 state->using_gl = 0;
2613 state->auto_resize = SDL_TRUE;
2614
2615 MODINIT_RETURN(module);
2616 }
2617