1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22/* Ported from original test/common.c file. */
23#include <SDL3/SDL_test.h>
24
25#define SDL_MAIN_NOIMPL
26#define SDL_MAIN_USE_CALLBACKS
27#include <SDL3/SDL_main.h>
28
29static const char *common_usage[] = {
30 "[-h | --help]",
31 "[--trackmem]",
32 "[--randmem]",
33 "[--info all|video|modes|render|event|event_motion]",
34 "[--log all|error|system|audio|video|render|input]",
35 NULL
36};
37
38static const char *video_usage[] = {
39 "[--always-on-top]",
40 "[--aspect min-max]",
41 "[--auto-scale-content]",
42 "[--center | --position X,Y]",
43 "[--confine-cursor X,Y,W,H]",
44 "[--depth N]",
45 "[--display N]",
46 "[--flash-on-focus-loss]",
47 "[--fullscreen | --fullscreen-desktop | --windows N]",
48 "[--geometry WxH]",
49 "[--gldebug]",
50 "[--grab]",
51 "[--hidden]",
52 "[--hide-cursor]",
53 "[--high-pixel-density]",
54 "[--icon icon.bmp]",
55 "[--input-focus]",
56 "[--keyboard-grab]",
57 "[--logical-presentation disabled|match|stretch|letterbox|overscan|integer_scale]",
58 "[--logical WxH]",
59 "[--max-geometry WxH]",
60 "[--maximize]",
61 "[--metal-window | --opengl-window | --vulkan-window]",
62 "[--min-geometry WxH]",
63 "[--minimize]",
64 "[--mouse-focus]",
65 "[--noframe]",
66 "[--refresh R]",
67 "[--renderer driver]",
68 "[--resizable]",
69 "[--scale N]",
70 "[--title title]",
71 "[--transparent]",
72 "[--usable-bounds]",
73 "[--utility]",
74 "[--video driver]",
75 "[--gpu driver]",
76 "[--vsync]",
77 NULL
78};
79
80/* !!! FIXME: Float32? Sint32? */
81static const char *audio_usage[] = {
82 "[--audio driver]",
83 "[--rate N]",
84 "[--format U8|S8|S16|S16LE|S16BE|S32|S32LE|S32BE|F32|F32LE|F32BE]",
85 "[--channels N]",
86 NULL
87};
88
89static void SDL_snprintfcat(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
90{
91 size_t length = SDL_strlen(text);
92 va_list ap;
93
94 va_start(ap, fmt);
95 text += length;
96 maxlen -= length;
97 (void)SDL_vsnprintf(text, maxlen, fmt, ap);
98 va_end(ap);
99}
100
101static void SDLCALL SDLTest_CommonArgParserFinalize(void *data)
102{
103 SDLTest_CommonState *state = data;
104
105 if (!(state->flags & SDL_INIT_VIDEO)) {
106 state->video_argparser.usage = NULL;
107 }
108 if (!(state->flags & SDL_INIT_AUDIO)) {
109 state->audio_argparser.usage = NULL;
110 }
111}
112
113#define SEARCHARG(dim) \
114 while (*(dim) && *(dim) != ',') { \
115 ++(dim); \
116 } \
117 if (!*(dim)) { \
118 return -1; \
119 } \
120 *(dim)++ = '\0';
121
122static int SDLCALL SDLTest_CommonStateParseCommonArguments(void *data, char **argv, int index)
123{
124 SDLTest_CommonState *state = data;
125
126 if ((SDL_strcasecmp(argv[index], "-h") == 0) || (SDL_strcasecmp(argv[index], "--help") == 0)) {
127 /* Print the usage message */
128 return -1;
129 }
130 if (SDL_strcasecmp(argv[index], "--trackmem") == 0) {
131 /* Already handled in SDLTest_CommonCreateState() */
132 return 1;
133 }
134 if (SDL_strcasecmp(argv[index], "--randmem") == 0) {
135 /* Already handled in SDLTest_CommonCreateState() */
136 return 1;
137 }
138 if (SDL_strcasecmp(argv[index], "--log") == 0) {
139 ++index;
140 if (!argv[index]) {
141 return -1;
142 }
143 if (SDL_strcasecmp(argv[index], "all") == 0) {
144 SDL_SetLogPriorities(SDL_LOG_PRIORITY_VERBOSE);
145 return 2;
146 }
147 if (SDL_strcasecmp(argv[index], "system") == 0) {
148 SDL_SetLogPriority(SDL_LOG_CATEGORY_SYSTEM, SDL_LOG_PRIORITY_VERBOSE);
149 return 2;
150 }
151 if (SDL_strcasecmp(argv[index], "audio") == 0) {
152 SDL_SetLogPriority(SDL_LOG_CATEGORY_AUDIO, SDL_LOG_PRIORITY_VERBOSE);
153 return 2;
154 }
155 if (SDL_strcasecmp(argv[index], "video") == 0) {
156 SDL_SetLogPriority(SDL_LOG_CATEGORY_VIDEO, SDL_LOG_PRIORITY_VERBOSE);
157 return 2;
158 }
159 if (SDL_strcasecmp(argv[index], "render") == 0) {
160 SDL_SetLogPriority(SDL_LOG_CATEGORY_RENDER, SDL_LOG_PRIORITY_VERBOSE);
161 return 2;
162 }
163 if (SDL_strcasecmp(argv[index], "input") == 0) {
164 SDL_SetLogPriority(SDL_LOG_CATEGORY_INPUT, SDL_LOG_PRIORITY_VERBOSE);
165 return 2;
166 }
167 return -1;
168 }
169
170 if (SDL_strcasecmp(argv[index], "--info") == 0) {
171 ++index;
172 if (!argv[index]) {
173 return -1;
174 }
175 if (SDL_strcasecmp(argv[index], "all") == 0) {
176 state->verbose |=
177 (VERBOSE_VIDEO | VERBOSE_MODES | VERBOSE_RENDER |
178 VERBOSE_EVENT);
179 return 2;
180 }
181 if (SDL_strcasecmp(argv[index], "video") == 0) {
182 state->verbose |= VERBOSE_VIDEO;
183 return 2;
184 }
185 if (SDL_strcasecmp(argv[index], "modes") == 0) {
186 state->verbose |= VERBOSE_MODES;
187 return 2;
188 }
189 if (SDL_strcasecmp(argv[index], "render") == 0) {
190 state->verbose |= VERBOSE_RENDER;
191 return 2;
192 }
193 if (SDL_strcasecmp(argv[index], "event") == 0) {
194 state->verbose |= VERBOSE_EVENT;
195 return 2;
196 }
197 if (SDL_strcasecmp(argv[index], "event_motion") == 0) {
198 state->verbose |= (VERBOSE_EVENT | VERBOSE_MOTION);
199 return 2;
200 }
201 return -1;
202 }
203 if (SDL_strcmp(argv[index], "-NSDocumentRevisionsDebugMode") == 0) {
204 /* Debug flag sent by Xcode */
205 return 2;
206 }
207 return 0;
208}
209
210static int SDLCALL SDLTest_CommonStateParseVideoArguments(void *data, char **argv, int index)
211{
212 SDLTest_CommonState *state = data;
213
214 if (!(state->flags & SDL_INIT_VIDEO)) {
215 return 0;
216 }
217
218 if (SDL_strcasecmp(argv[index], "--video") == 0) {
219 ++index;
220 if (!argv[index]) {
221 return -1;
222 }
223 state->videodriver = argv[index];
224 SDL_SetHint(SDL_HINT_VIDEO_DRIVER, state->videodriver);
225 return 2;
226 }
227 if (SDL_strcasecmp(argv[index], "--renderer") == 0) {
228 ++index;
229 if (!argv[index]) {
230 return -1;
231 }
232 state->renderdriver = argv[index];
233 SDL_SetHint(SDL_HINT_RENDER_DRIVER, state->renderdriver);
234 return 2;
235 }
236 if (SDL_strcasecmp(argv[index], "--gldebug") == 0) {
237 state->gl_debug = 1;
238 return 1;
239 }
240 if (SDL_strcasecmp(argv[index], "--display") == 0) {
241 ++index;
242 if (!argv[index]) {
243 return -1;
244 }
245 state->display_index = SDL_atoi(argv[index]);
246 return 2;
247 }
248 if (SDL_strcasecmp(argv[index], "--metal-window") == 0) {
249 state->window_flags |= SDL_WINDOW_METAL;
250 return 1;
251 }
252 if (SDL_strcasecmp(argv[index], "--opengl-window") == 0) {
253 state->window_flags |= SDL_WINDOW_OPENGL;
254 return 1;
255 }
256 if (SDL_strcasecmp(argv[index], "--vulkan-window") == 0) {
257 state->window_flags |= SDL_WINDOW_VULKAN;
258 return 1;
259 }
260 if (SDL_strcasecmp(argv[index], "--fullscreen") == 0) {
261 state->window_flags |= SDL_WINDOW_FULLSCREEN;
262 state->fullscreen_exclusive = true;
263 state->num_windows = 1;
264 return 1;
265 }
266 if (SDL_strcasecmp(argv[index], "--fullscreen-desktop") == 0) {
267 state->window_flags |= SDL_WINDOW_FULLSCREEN;
268 state->fullscreen_exclusive = false;
269 state->num_windows = 1;
270 return 1;
271 }
272 if (SDL_strcasecmp(argv[index], "--windows") == 0) {
273 ++index;
274 if (!argv[index] || !SDL_isdigit((unsigned char) *argv[index])) {
275 return -1;
276 }
277 if (!(state->window_flags & SDL_WINDOW_FULLSCREEN)) {
278 state->num_windows = SDL_atoi(argv[index]);
279 }
280 return 2;
281 }
282 if (SDL_strcasecmp(argv[index], "--title") == 0) {
283 ++index;
284 if (!argv[index]) {
285 return -1;
286 }
287 state->window_title = argv[index];
288 return 2;
289 }
290 if (SDL_strcasecmp(argv[index], "--icon") == 0) {
291 ++index;
292 if (!argv[index]) {
293 return -1;
294 }
295 state->window_icon = argv[index];
296 return 2;
297 }
298 if (SDL_strcasecmp(argv[index], "--center") == 0) {
299 state->window_x = SDL_WINDOWPOS_CENTERED;
300 state->window_y = SDL_WINDOWPOS_CENTERED;
301 return 1;
302 }
303 if (SDL_strcasecmp(argv[index], "--position") == 0) {
304 char *x, *y;
305 ++index;
306 if (!argv[index]) {
307 return -1;
308 }
309 x = argv[index];
310 y = argv[index];
311 while (*y && *y != ',') {
312 ++y;
313 }
314 if (!*y) {
315 return -1;
316 }
317 *y++ = '\0';
318 state->window_x = SDL_atoi(x);
319 state->window_y = SDL_atoi(y);
320 return 2;
321 }
322 if (SDL_strcasecmp(argv[index], "--confine-cursor") == 0) {
323 char *x, *y, *w, *h;
324 ++index;
325 if (!argv[index]) {
326 return -1;
327 }
328 x = argv[index];
329 y = argv[index];
330 SEARCHARG(y)
331 w = y;
332 SEARCHARG(w)
333 h = w;
334 SEARCHARG(h)
335 state->confine.x = SDL_atoi(x);
336 state->confine.y = SDL_atoi(y);
337 state->confine.w = SDL_atoi(w);
338 state->confine.h = SDL_atoi(h);
339 return 2;
340 }
341 if (SDL_strcasecmp(argv[index], "--usable-bounds") == 0) {
342 state->fill_usable_bounds = true;
343 return 1;
344 }
345 if (SDL_strcasecmp(argv[index], "--geometry") == 0) {
346 char *w, *h;
347 ++index;
348 if (!argv[index]) {
349 return -1;
350 }
351 w = argv[index];
352 h = argv[index];
353 while (*h && *h != 'x') {
354 ++h;
355 }
356 if (!*h) {
357 return -1;
358 }
359 *h++ = '\0';
360 state->window_w = SDL_atoi(w);
361 state->window_h = SDL_atoi(h);
362 return 2;
363 }
364 if (SDL_strcasecmp(argv[index], "--min-geometry") == 0) {
365 char *w, *h;
366 ++index;
367 if (!argv[index]) {
368 return -1;
369 }
370 w = argv[index];
371 h = argv[index];
372 while (*h && *h != 'x') {
373 ++h;
374 }
375 if (!*h) {
376 return -1;
377 }
378 *h++ = '\0';
379 state->window_minW = SDL_atoi(w);
380 state->window_minH = SDL_atoi(h);
381 return 2;
382 }
383 if (SDL_strcasecmp(argv[index], "--max-geometry") == 0) {
384 char *w, *h;
385 ++index;
386 if (!argv[index]) {
387 return -1;
388 }
389 w = argv[index];
390 h = argv[index];
391 while (*h && *h != 'x') {
392 ++h;
393 }
394 if (!*h) {
395 return -1;
396 }
397 *h++ = '\0';
398 state->window_maxW = SDL_atoi(w);
399 state->window_maxH = SDL_atoi(h);
400 return 2;
401 }
402 if (SDL_strcasecmp(argv[index], "--aspect") == 0) {
403 char *min_aspect, *max_aspect;
404 ++index;
405 if (!argv[index]) {
406 return -1;
407 }
408 min_aspect = argv[index];
409 max_aspect = argv[index];
410 while (*max_aspect && *max_aspect != '-') {
411 ++max_aspect;
412 }
413 if (*max_aspect) {
414 *max_aspect++ = '\0';
415 } else {
416 max_aspect = min_aspect;
417 }
418 state->window_min_aspect = (float)SDL_atof(min_aspect);
419 state->window_max_aspect = (float)SDL_atof(max_aspect);
420 return 2;
421 }
422 if (SDL_strcasecmp(argv[index], "--logical") == 0) {
423 char *w, *h;
424 ++index;
425 if (!argv[index]) {
426 return -1;
427 }
428 w = argv[index];
429 h = argv[index];
430 while (*h && *h != 'x') {
431 ++h;
432 }
433 if (!*h) {
434 return -1;
435 }
436 *h++ = '\0';
437 state->logical_w = SDL_atoi(w);
438 state->logical_h = SDL_atoi(h);
439 return 2;
440 }
441 if (SDL_strcasecmp(argv[index], "--high-pixel-density") == 0) {
442 state->window_flags |= SDL_WINDOW_HIGH_PIXEL_DENSITY;
443 return 1;
444 }
445 if (SDL_strcasecmp(argv[index], "--auto-scale-content") == 0) {
446 state->auto_scale_content = true;
447
448 if (state->logical_presentation == SDL_LOGICAL_PRESENTATION_DISABLED) {
449 state->logical_presentation = SDL_LOGICAL_PRESENTATION_STRETCH;
450 }
451 return 1;
452 }
453 if (SDL_strcasecmp(argv[index], "--logical-presentation") == 0) {
454 ++index;
455 if (!argv[index]) {
456 return -1;
457 }
458 if (SDL_strcasecmp(argv[index], "disabled") == 0) {
459 state->logical_presentation = SDL_LOGICAL_PRESENTATION_DISABLED;
460 return 2;
461 }
462 if (SDL_strcasecmp(argv[index], "stretch") == 0) {
463 state->logical_presentation = SDL_LOGICAL_PRESENTATION_STRETCH;
464 return 2;
465 }
466 if (SDL_strcasecmp(argv[index], "letterbox") == 0) {
467 state->logical_presentation = SDL_LOGICAL_PRESENTATION_LETTERBOX;
468 return 2;
469 }
470 if (SDL_strcasecmp(argv[index], "overscan") == 0) {
471 state->logical_presentation = SDL_LOGICAL_PRESENTATION_OVERSCAN;
472 return 2;
473 }
474 if (SDL_strcasecmp(argv[index], "integer_scale") == 0) {
475 state->logical_presentation = SDL_LOGICAL_PRESENTATION_INTEGER_SCALE;
476 return 2;
477 }
478 return -1;
479 }
480 if (SDL_strcasecmp(argv[index], "--scale") == 0) {
481 ++index;
482 if (!argv[index]) {
483 return -1;
484 }
485 state->scale = (float) SDL_atof(argv[index]);
486 return 2;
487 }
488 if (SDL_strcasecmp(argv[index], "--depth") == 0) {
489 ++index;
490 if (!argv[index]) {
491 return -1;
492 }
493 state->depth = SDL_atoi(argv[index]);
494 return 2;
495 }
496 if (SDL_strcasecmp(argv[index], "--refresh") == 0) {
497 ++index;
498 if (!argv[index]) {
499 return -1;
500 }
501 state->refresh_rate = (float) SDL_atof(argv[index]);
502 return 2;
503 }
504 if (SDL_strcasecmp(argv[index], "--vsync") == 0) {
505 state->render_vsync = 1;
506 return 1;
507 }
508 if (SDL_strcasecmp(argv[index], "--noframe") == 0) {
509 state->window_flags |= SDL_WINDOW_BORDERLESS;
510 return 1;
511 }
512 if (SDL_strcasecmp(argv[index], "--resizable") == 0) {
513 state->window_flags |= SDL_WINDOW_RESIZABLE;
514 return 1;
515 }
516 if (SDL_strcasecmp(argv[index], "--transparent") == 0) {
517 state->window_flags |= SDL_WINDOW_TRANSPARENT;
518 return 1;
519 }
520 if (SDL_strcasecmp(argv[index], "--always-on-top") == 0) {
521 state->window_flags |= SDL_WINDOW_ALWAYS_ON_TOP;
522 return 1;
523 }
524 if (SDL_strcasecmp(argv[index], "--minimize") == 0) {
525 state->window_flags |= SDL_WINDOW_MINIMIZED;
526 return 1;
527 }
528 if (SDL_strcasecmp(argv[index], "--maximize") == 0) {
529 state->window_flags |= SDL_WINDOW_MAXIMIZED;
530 return 1;
531 }
532 if (SDL_strcasecmp(argv[index], "--hidden") == 0) {
533 state->window_flags |= SDL_WINDOW_HIDDEN;
534 return 1;
535 }
536 if (SDL_strcasecmp(argv[index], "--input-focus") == 0) {
537 state->window_flags |= SDL_WINDOW_INPUT_FOCUS;
538 return 1;
539 }
540 if (SDL_strcasecmp(argv[index], "--mouse-focus") == 0) {
541 state->window_flags |= SDL_WINDOW_MOUSE_FOCUS;
542 return 1;
543 }
544 if (SDL_strcasecmp(argv[index], "--flash-on-focus-loss") == 0) {
545 state->flash_on_focus_loss = true;
546 return 1;
547 }
548 if (SDL_strcasecmp(argv[index], "--grab") == 0) {
549 state->window_flags |= SDL_WINDOW_MOUSE_GRABBED;
550 return 1;
551 }
552 if (SDL_strcasecmp(argv[index], "--keyboard-grab") == 0) {
553 state->window_flags |= SDL_WINDOW_KEYBOARD_GRABBED;
554 return 1;
555 }
556 if (SDL_strcasecmp(argv[index], "--utility") == 0) {
557 state->window_flags |= SDL_WINDOW_UTILITY;
558 return 1;
559 }
560 if (SDL_strcasecmp(argv[index], "--hide-cursor") == 0) {
561 state->hide_cursor = true;
562 return 1;
563 }
564 if (SDL_strcasecmp(argv[index], "--gpu") == 0) {
565 ++index;
566 if (!argv[index]) {
567 return -1;
568 }
569 state->gpudriver = argv[index];
570 SDL_SetHint(SDL_HINT_GPU_DRIVER, state->gpudriver);
571 return 2;
572 }
573 return 0;
574}
575
576static int SDLCALL SDLTest_CommonStateParseAudioArguments(void *data, char **argv, int index)
577{
578 SDLTest_CommonState *state = data;
579
580 if (!(state->flags & SDL_INIT_AUDIO)) {
581 return 0;
582 }
583 if (SDL_strcasecmp(argv[index], "--audio") == 0) {
584 ++index;
585 if (!argv[index]) {
586 return -1;
587 }
588 state->audiodriver = argv[index];
589 SDL_SetHint(SDL_HINT_AUDIO_DRIVER, state->audiodriver);
590 return 2;
591 }
592 if (SDL_strcasecmp(argv[index], "--rate") == 0) {
593 ++index;
594 if (!argv[index]) {
595 return -1;
596 }
597 state->audio_freq = SDL_atoi(argv[index]);
598 return 2;
599 }
600 if (SDL_strcasecmp(argv[index], "--format") == 0) {
601 ++index;
602 if (!argv[index]) {
603 return -1;
604 }
605 if (SDL_strcasecmp(argv[index], "U8") == 0) {
606 state->audio_format = SDL_AUDIO_U8;
607 return 2;
608 }
609 if (SDL_strcasecmp(argv[index], "S8") == 0) {
610 state->audio_format = SDL_AUDIO_S8;
611 return 2;
612 }
613 if (SDL_strcasecmp(argv[index], "S16") == 0) {
614 state->audio_format = SDL_AUDIO_S16;
615 return 2;
616 }
617 if (SDL_strcasecmp(argv[index], "S16LE") == 0) {
618 state->audio_format = SDL_AUDIO_S16LE;
619 return 2;
620 }
621 if (SDL_strcasecmp(argv[index], "S16BE") == 0) {
622 state->audio_format = SDL_AUDIO_S16BE;
623 return 2;
624 }
625 if (SDL_strcasecmp(argv[index], "S32") == 0) {
626 state->audio_format = SDL_AUDIO_S32;
627 return 2;
628 }
629 if (SDL_strcasecmp(argv[index], "S32LE") == 0) {
630 state->audio_format = SDL_AUDIO_S32LE;
631 return 2;
632 }
633 if (SDL_strcasecmp(argv[index], "S32BE") == 0) {
634 state->audio_format = SDL_AUDIO_S32BE;
635 return 2;
636 }
637 if (SDL_strcasecmp(argv[index], "F32") == 0) {
638 state->audio_format = SDL_AUDIO_F32;
639 return 2;
640 }
641 if (SDL_strcasecmp(argv[index], "F32LE") == 0) {
642 state->audio_format = SDL_AUDIO_F32LE;
643 return 2;
644 }
645 if (SDL_strcasecmp(argv[index], "F32BE") == 0) {
646 state->audio_format = SDL_AUDIO_F32BE;
647 return 2;
648 }
649 return -1;
650 }
651 if (SDL_strcasecmp(argv[index], "--channels") == 0) {
652 ++index;
653 if (!argv[index]) {
654 return -1;
655 }
656 state->audio_channels = (Uint8) SDL_atoi(argv[index]);
657 return 2;
658 }
659 return 0;
660}
661
662SDLTest_CommonState *SDLTest_CommonCreateState(char **argv, SDL_InitFlags flags)
663{
664 int i;
665 SDLTest_CommonState *state;
666
667 /* Do this first so we catch all allocations */
668 for (i = 1; argv[i]; ++i) {
669 if (SDL_strcasecmp(argv[i], "--trackmem") == 0) {
670 SDLTest_TrackAllocations();
671 } else if (SDL_strcasecmp(argv[i], "--randmem") == 0) {
672 SDLTest_RandFillAllocations();
673 }
674 }
675
676 state = (SDLTest_CommonState *)SDL_calloc(1, sizeof(*state));
677 if (!state) {
678 return NULL;
679 }
680
681 /* Initialize some defaults */
682 state->argv = argv;
683 state->flags = flags;
684 state->window_title = argv[0];
685 state->window_flags = SDL_WINDOW_HIDDEN;
686 state->window_x = SDL_WINDOWPOS_UNDEFINED;
687 state->window_y = SDL_WINDOWPOS_UNDEFINED;
688 state->window_w = DEFAULT_WINDOW_WIDTH;
689 state->window_h = DEFAULT_WINDOW_HEIGHT;
690 state->logical_presentation = SDL_LOGICAL_PRESENTATION_DISABLED;
691 state->num_windows = 1;
692 state->audio_freq = 22050;
693 state->audio_format = SDL_AUDIO_S16;
694 state->audio_channels = 2;
695
696 /* Set some very sane GL defaults */
697 state->gl_red_size = 8;
698 state->gl_green_size = 8;
699 state->gl_blue_size = 8;
700 state->gl_alpha_size = 8;
701 state->gl_buffer_size = 0;
702 state->gl_depth_size = 16;
703 state->gl_stencil_size = 0;
704 state->gl_double_buffer = 1;
705 state->gl_accum_red_size = 0;
706 state->gl_accum_green_size = 0;
707 state->gl_accum_blue_size = 0;
708 state->gl_accum_alpha_size = 0;
709 state->gl_stereo = 0;
710 state->gl_multisamplebuffers = 0;
711 state->gl_multisamplesamples = 0;
712 state->gl_retained_backing = 1;
713 state->gl_accelerated = -1;
714 state->gl_debug = 0;
715
716 state->common_argparser.parse_arguments = SDLTest_CommonStateParseCommonArguments;
717 state->common_argparser.finalize = SDLTest_CommonArgParserFinalize;
718 state->common_argparser.usage = common_usage;
719 state->common_argparser.data = state;
720 state->common_argparser.next = &state->video_argparser;
721
722 state->video_argparser.parse_arguments = SDLTest_CommonStateParseVideoArguments;
723 state->video_argparser.finalize = NULL;
724 state->video_argparser.usage = video_usage;
725 state->video_argparser.data = state;
726 state->video_argparser.next = &state->audio_argparser;
727
728 state->audio_argparser.parse_arguments = SDLTest_CommonStateParseAudioArguments;
729 state->audio_argparser.finalize = NULL;
730 state->audio_argparser.usage = audio_usage;
731 state->audio_argparser.data = state;
732
733 state->argparser = &state->common_argparser;
734
735 return state;
736}
737
738void SDLTest_CommonDestroyState(SDLTest_CommonState *state) {
739 SDL_free(state);
740 SDLTest_LogAllocations();
741}
742
743int SDLTest_CommonArg(SDLTest_CommonState *state, int index)
744{
745 SDLTest_ArgumentParser *argparser = state->argparser;
746
747 /* Go back and parse arguments as we go */
748 while (argparser) {
749 if (argparser->parse_arguments) {
750 int consumed = argparser->parse_arguments(argparser->data, state->argv, index);
751 if (consumed != 0) {
752 return consumed;
753 }
754 }
755 argparser = argparser->next;
756 }
757 return 0;
758}
759
760void SDLTest_CommonLogUsage(SDLTest_CommonState *state, const char *argv0, const char **options)
761{
762 SDLTest_ArgumentParser *argparser;
763
764 SDL_Log("USAGE: %s", argv0);
765
766 for (argparser = state->argparser; argparser; argparser = argparser->next) {
767 if (argparser->finalize) {
768 argparser->finalize(argparser->data);
769 }
770 if (argparser->usage) {
771 int i;
772 for (i = 0; argparser->usage[i] != NULL; i++) {
773 SDL_Log(" %s", argparser->usage[i]);
774 }
775 }
776 }
777 if (options) {
778 int i;
779 for (i = 0; options[i] != NULL; i++) {
780 SDL_Log(" %s", options[i]);
781 }
782 }
783}
784
785bool SDLTest_CommonDefaultArgs(SDLTest_CommonState *state, int argc, char **argv)
786{
787 int i = 1;
788 while (i < argc) {
789 const int consumed = SDLTest_CommonArg(state, i);
790 if (consumed <= 0) {
791 SDLTest_CommonLogUsage(state, argv[0], NULL);
792 return false;
793 }
794 i += consumed;
795 }
796 return true;
797}
798
799static void SDLTest_PrintDisplayOrientation(char *text, size_t maxlen, SDL_DisplayOrientation orientation)
800{
801 switch (orientation) {
802 case SDL_ORIENTATION_UNKNOWN:
803 SDL_snprintfcat(text, maxlen, "UNKNOWN");
804 break;
805 case SDL_ORIENTATION_LANDSCAPE:
806 SDL_snprintfcat(text, maxlen, "LANDSCAPE");
807 break;
808 case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
809 SDL_snprintfcat(text, maxlen, "LANDSCAPE_FLIPPED");
810 break;
811 case SDL_ORIENTATION_PORTRAIT:
812 SDL_snprintfcat(text, maxlen, "PORTRAIT");
813 break;
814 case SDL_ORIENTATION_PORTRAIT_FLIPPED:
815 SDL_snprintfcat(text, maxlen, "PORTRAIT_FLIPPED");
816 break;
817 default:
818 SDL_snprintfcat(text, maxlen, "0x%8.8x", orientation);
819 break;
820 }
821}
822
823static void SDLTest_PrintWindowFlag(char *text, size_t maxlen, SDL_WindowFlags flag)
824{
825 switch (flag) {
826 case SDL_WINDOW_FULLSCREEN:
827 SDL_snprintfcat(text, maxlen, "FULLSCREEN");
828 break;
829 case SDL_WINDOW_OPENGL:
830 SDL_snprintfcat(text, maxlen, "OPENGL");
831 break;
832 case SDL_WINDOW_OCCLUDED:
833 SDL_snprintfcat(text, maxlen, "OCCLUDED");
834 break;
835 case SDL_WINDOW_HIDDEN:
836 SDL_snprintfcat(text, maxlen, "HIDDEN");
837 break;
838 case SDL_WINDOW_BORDERLESS:
839 SDL_snprintfcat(text, maxlen, "BORDERLESS");
840 break;
841 case SDL_WINDOW_RESIZABLE:
842 SDL_snprintfcat(text, maxlen, "RESIZABLE");
843 break;
844 case SDL_WINDOW_MINIMIZED:
845 SDL_snprintfcat(text, maxlen, "MINIMIZED");
846 break;
847 case SDL_WINDOW_MAXIMIZED:
848 SDL_snprintfcat(text, maxlen, "MAXIMIZED");
849 break;
850 case SDL_WINDOW_MOUSE_GRABBED:
851 SDL_snprintfcat(text, maxlen, "MOUSE_GRABBED");
852 break;
853 case SDL_WINDOW_INPUT_FOCUS:
854 SDL_snprintfcat(text, maxlen, "INPUT_FOCUS");
855 break;
856 case SDL_WINDOW_MOUSE_FOCUS:
857 SDL_snprintfcat(text, maxlen, "MOUSE_FOCUS");
858 break;
859 case SDL_WINDOW_EXTERNAL:
860 SDL_snprintfcat(text, maxlen, "EXTERNAL");
861 break;
862 case SDL_WINDOW_MODAL:
863 SDL_snprintfcat(text, maxlen, "MODAL");
864 break;
865 case SDL_WINDOW_HIGH_PIXEL_DENSITY:
866 SDL_snprintfcat(text, maxlen, "HIGH_PIXEL_DENSITY");
867 break;
868 case SDL_WINDOW_MOUSE_CAPTURE:
869 SDL_snprintfcat(text, maxlen, "MOUSE_CAPTURE");
870 break;
871 case SDL_WINDOW_MOUSE_RELATIVE_MODE:
872 SDL_snprintfcat(text, maxlen, "MOUSE_RELATIVE_MODE");
873 break;
874 case SDL_WINDOW_ALWAYS_ON_TOP:
875 SDL_snprintfcat(text, maxlen, "ALWAYS_ON_TOP");
876 break;
877 case SDL_WINDOW_UTILITY:
878 SDL_snprintfcat(text, maxlen, "UTILITY");
879 break;
880 case SDL_WINDOW_TOOLTIP:
881 SDL_snprintfcat(text, maxlen, "TOOLTIP");
882 break;
883 case SDL_WINDOW_POPUP_MENU:
884 SDL_snprintfcat(text, maxlen, "POPUP_MENU");
885 break;
886 case SDL_WINDOW_KEYBOARD_GRABBED:
887 SDL_snprintfcat(text, maxlen, "KEYBOARD_GRABBED");
888 break;
889 case SDL_WINDOW_VULKAN:
890 SDL_snprintfcat(text, maxlen, "VULKAN");
891 break;
892 case SDL_WINDOW_METAL:
893 SDL_snprintfcat(text, maxlen, "METAL");
894 break;
895 case SDL_WINDOW_TRANSPARENT:
896 SDL_snprintfcat(text, maxlen, "TRANSPARENT");
897 break;
898 case SDL_WINDOW_NOT_FOCUSABLE:
899 SDL_snprintfcat(text, maxlen, "NOT_FOCUSABLE");
900 break;
901 default:
902 SDL_snprintfcat(text, maxlen, "0x%16.16" SDL_PRIx64, flag);
903 break;
904 }
905}
906
907static void SDLTest_PrintWindowFlags(char *text, size_t maxlen, SDL_WindowFlags flags)
908{
909 const SDL_WindowFlags window_flags[] = {
910 SDL_WINDOW_FULLSCREEN,
911 SDL_WINDOW_OPENGL,
912 SDL_WINDOW_OCCLUDED,
913 SDL_WINDOW_HIDDEN,
914 SDL_WINDOW_BORDERLESS,
915 SDL_WINDOW_RESIZABLE,
916 SDL_WINDOW_MINIMIZED,
917 SDL_WINDOW_MAXIMIZED,
918 SDL_WINDOW_MOUSE_GRABBED,
919 SDL_WINDOW_INPUT_FOCUS,
920 SDL_WINDOW_MOUSE_FOCUS,
921 SDL_WINDOW_EXTERNAL,
922 SDL_WINDOW_MODAL,
923 SDL_WINDOW_HIGH_PIXEL_DENSITY,
924 SDL_WINDOW_MOUSE_CAPTURE,
925 SDL_WINDOW_MOUSE_RELATIVE_MODE,
926 SDL_WINDOW_ALWAYS_ON_TOP,
927 SDL_WINDOW_UTILITY,
928 SDL_WINDOW_TOOLTIP,
929 SDL_WINDOW_POPUP_MENU,
930 SDL_WINDOW_KEYBOARD_GRABBED,
931 SDL_WINDOW_VULKAN,
932 SDL_WINDOW_METAL,
933 SDL_WINDOW_TRANSPARENT,
934 SDL_WINDOW_NOT_FOCUSABLE
935 };
936
937 int i;
938 int count = 0;
939 for (i = 0; i < (sizeof(window_flags) / sizeof(window_flags[0])); ++i) {
940 const SDL_WindowFlags flag = window_flags[i];
941 if ((flags & flag) == flag) {
942 if (count > 0) {
943 SDL_snprintfcat(text, maxlen, " | ");
944 }
945 SDLTest_PrintWindowFlag(text, maxlen, flag);
946 ++count;
947 }
948 }
949}
950
951static void SDLTest_PrintModStateFlag(char *text, size_t maxlen, SDL_Keymod flag)
952{
953 switch (flag) {
954 case SDL_KMOD_LSHIFT:
955 SDL_snprintfcat(text, maxlen, "LSHIFT");
956 break;
957 case SDL_KMOD_RSHIFT:
958 SDL_snprintfcat(text, maxlen, "RSHIFT");
959 break;
960 case SDL_KMOD_LEVEL5:
961 SDL_snprintfcat(text, maxlen, "LEVEL5");
962 break;
963 case SDL_KMOD_LCTRL:
964 SDL_snprintfcat(text, maxlen, "LCTRL");
965 break;
966 case SDL_KMOD_RCTRL:
967 SDL_snprintfcat(text, maxlen, "RCTRL");
968 break;
969 case SDL_KMOD_LALT:
970 SDL_snprintfcat(text, maxlen, "LALT");
971 break;
972 case SDL_KMOD_RALT:
973 SDL_snprintfcat(text, maxlen, "RALT");
974 break;
975 case SDL_KMOD_LGUI:
976 SDL_snprintfcat(text, maxlen, "LGUI");
977 break;
978 case SDL_KMOD_RGUI:
979 SDL_snprintfcat(text, maxlen, "RGUI");
980 break;
981 case SDL_KMOD_NUM:
982 SDL_snprintfcat(text, maxlen, "NUM");
983 break;
984 case SDL_KMOD_CAPS:
985 SDL_snprintfcat(text, maxlen, "CAPS");
986 break;
987 case SDL_KMOD_MODE:
988 SDL_snprintfcat(text, maxlen, "MODE");
989 break;
990 case SDL_KMOD_SCROLL:
991 SDL_snprintfcat(text, maxlen, "SCROLL");
992 break;
993 default:
994 SDL_snprintfcat(text, maxlen, "0x%8.8x", (unsigned int) flag);
995 break;
996 }
997}
998
999static void SDLTest_PrintModState(char *text, size_t maxlen, SDL_Keymod keymod)
1000{
1001 const SDL_Keymod kmod_flags[] = {
1002 SDL_KMOD_LSHIFT,
1003 SDL_KMOD_RSHIFT,
1004 SDL_KMOD_LEVEL5,
1005 SDL_KMOD_LCTRL,
1006 SDL_KMOD_RCTRL,
1007 SDL_KMOD_LALT,
1008 SDL_KMOD_RALT,
1009 SDL_KMOD_LGUI,
1010 SDL_KMOD_RGUI,
1011 SDL_KMOD_NUM,
1012 SDL_KMOD_CAPS,
1013 SDL_KMOD_MODE,
1014 SDL_KMOD_SCROLL
1015 };
1016
1017 int i;
1018 int count = 0;
1019 for (i = 0; i < SDL_arraysize(kmod_flags); ++i) {
1020 const SDL_Keymod flag = kmod_flags[i];
1021 if ((keymod & flag) == flag) {
1022 if (count > 0) {
1023 SDL_snprintfcat(text, maxlen, " | ");
1024 }
1025 SDLTest_PrintModStateFlag(text, maxlen, flag);
1026 ++count;
1027 }
1028 }
1029}
1030
1031static void SDLTest_PrintButtonMask(char *text, size_t maxlen, SDL_MouseButtonFlags flags)
1032{
1033 int i;
1034 int count = 0;
1035 for (i = 1; i <= 32; ++i) {
1036 const Uint32 flag = SDL_BUTTON_MASK(i);
1037 if ((flags & flag) == flag) {
1038 if (count > 0) {
1039 SDL_snprintfcat(text, maxlen, " | ");
1040 }
1041 SDL_snprintfcat(text, maxlen, "SDL_BUTTON_MASK(%d)", i);
1042 ++count;
1043 }
1044 }
1045}
1046
1047static void SDLTest_PrintPixelFormat(char *text, size_t maxlen, Uint32 format)
1048{
1049 const char *name = SDL_GetPixelFormatName(format);
1050 if (name) {
1051 if (SDL_strncmp(name, "SDL_PIXELFORMAT_", 16) == 0) {
1052 name += 16;
1053 }
1054 SDL_snprintfcat(text, maxlen, name);
1055 } else {
1056 SDL_snprintfcat(text, maxlen, "0x%8.8x", format);
1057 }
1058}
1059
1060static void SDLTest_PrintLogicalPresentation(char *text, size_t maxlen, SDL_RendererLogicalPresentation logical_presentation)
1061{
1062 switch (logical_presentation) {
1063 case SDL_LOGICAL_PRESENTATION_DISABLED:
1064 SDL_snprintfcat(text, maxlen, "DISABLED");
1065 break;
1066 case SDL_LOGICAL_PRESENTATION_STRETCH:
1067 SDL_snprintfcat(text, maxlen, "STRETCH");
1068 break;
1069 case SDL_LOGICAL_PRESENTATION_LETTERBOX:
1070 SDL_snprintfcat(text, maxlen, "LETTERBOX");
1071 break;
1072 case SDL_LOGICAL_PRESENTATION_OVERSCAN:
1073 SDL_snprintfcat(text, maxlen, "OVERSCAN");
1074 break;
1075 case SDL_LOGICAL_PRESENTATION_INTEGER_SCALE:
1076 SDL_snprintfcat(text, maxlen, "INTEGER_SCALE");
1077 break;
1078 default:
1079 SDL_snprintfcat(text, maxlen, "0x%8.8x", logical_presentation);
1080 break;
1081 }
1082}
1083
1084static void SDLTest_PrintRenderer(SDL_Renderer *renderer)
1085{
1086 const char *name;
1087 int i;
1088 char text[1024];
1089 int max_texture_size;
1090 const SDL_PixelFormat *texture_formats;
1091
1092 name = SDL_GetRendererName(renderer);
1093
1094 SDL_Log(" Renderer %s:", name);
1095 if (SDL_strcmp(name, "gpu") == 0) {
1096 SDL_GPUDevice *device = SDL_GetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_GPU_DEVICE_POINTER, NULL);
1097 SDL_Log(" Driver: %s", SDL_GetGPUDeviceDriver(device));
1098 }
1099 SDL_Log(" VSync: %d", (int)SDL_GetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_VSYNC_NUMBER, 0));
1100
1101 texture_formats = (const SDL_PixelFormat *)SDL_GetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_TEXTURE_FORMATS_POINTER, NULL);
1102 if (texture_formats) {
1103 (void)SDL_snprintf(text, sizeof(text), " Texture formats: ");
1104 for (i = 0; texture_formats[i]; ++i) {
1105 if (i > 0) {
1106 SDL_snprintfcat(text, sizeof(text), ", ");
1107 }
1108 SDLTest_PrintPixelFormat(text, sizeof(text), texture_formats[i]);
1109 }
1110 SDL_Log("%s", text);
1111 }
1112
1113 max_texture_size = (int)SDL_GetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 0);
1114 if (max_texture_size) {
1115 SDL_Log(" Max Texture Size: %dx%d", max_texture_size, max_texture_size);
1116 }
1117}
1118
1119static SDL_Surface *SDLTest_LoadIcon(const char *file)
1120{
1121 SDL_Surface *icon;
1122
1123 /* Load the icon surface */
1124 icon = SDL_LoadBMP(file);
1125 if (!icon) {
1126 SDL_Log("Couldn't load %s: %s", file, SDL_GetError());
1127 return NULL;
1128 }
1129
1130 if (icon->format == SDL_PIXELFORMAT_INDEX8) {
1131 /* Set the colorkey */
1132 SDL_SetSurfaceColorKey(icon, 1, *((Uint8 *)icon->pixels));
1133 }
1134
1135 return icon;
1136}
1137
1138static SDL_HitTestResult SDLCALL SDLTest_ExampleHitTestCallback(SDL_Window *win, const SDL_Point *area, void *data)
1139{
1140 int w, h;
1141 const int RESIZE_BORDER = 8;
1142 const int DRAGGABLE_TITLE = 32;
1143
1144 /*SDL_Log("Hit test point %d,%d", area->x, area->y);*/
1145
1146 SDL_GetWindowSize(win, &w, &h);
1147
1148 if (area->x < RESIZE_BORDER) {
1149 if (area->y < RESIZE_BORDER) {
1150 SDL_Log("SDL_HITTEST_RESIZE_TOPLEFT");
1151 return SDL_HITTEST_RESIZE_TOPLEFT;
1152 } else if (area->y >= (h - RESIZE_BORDER)) {
1153 SDL_Log("SDL_HITTEST_RESIZE_BOTTOMLEFT");
1154 return SDL_HITTEST_RESIZE_BOTTOMLEFT;
1155 } else {
1156 SDL_Log("SDL_HITTEST_RESIZE_LEFT");
1157 return SDL_HITTEST_RESIZE_LEFT;
1158 }
1159 } else if (area->x >= (w - RESIZE_BORDER)) {
1160 if (area->y < RESIZE_BORDER) {
1161 SDL_Log("SDL_HITTEST_RESIZE_TOPRIGHT");
1162 return SDL_HITTEST_RESIZE_TOPRIGHT;
1163 } else if (area->y >= (h - RESIZE_BORDER)) {
1164 SDL_Log("SDL_HITTEST_RESIZE_BOTTOMRIGHT");
1165 return SDL_HITTEST_RESIZE_BOTTOMRIGHT;
1166 } else {
1167 SDL_Log("SDL_HITTEST_RESIZE_RIGHT");
1168 return SDL_HITTEST_RESIZE_RIGHT;
1169 }
1170 } else if (area->y >= (h - RESIZE_BORDER)) {
1171 SDL_Log("SDL_HITTEST_RESIZE_BOTTOM");
1172 return SDL_HITTEST_RESIZE_BOTTOM;
1173 } else if (area->y < RESIZE_BORDER) {
1174 SDL_Log("SDL_HITTEST_RESIZE_TOP");
1175 return SDL_HITTEST_RESIZE_TOP;
1176 } else if (area->y < DRAGGABLE_TITLE) {
1177 SDL_Log("SDL_HITTEST_DRAGGABLE");
1178 return SDL_HITTEST_DRAGGABLE;
1179 }
1180 return SDL_HITTEST_NORMAL;
1181}
1182
1183bool SDLTest_CommonInit(SDLTest_CommonState *state)
1184{
1185 int i, j, m, n, w, h;
1186 char text[1024];
1187
1188 if (state->flags & SDL_INIT_VIDEO) {
1189 if (state->verbose & VERBOSE_VIDEO) {
1190 n = SDL_GetNumVideoDrivers();
1191 if (n == 0) {
1192 SDL_Log("No built-in video drivers");
1193 } else {
1194 (void)SDL_snprintf(text, sizeof(text), "Built-in video drivers:");
1195 for (i = 0; i < n; ++i) {
1196 if (i > 0) {
1197 SDL_snprintfcat(text, sizeof(text), ",");
1198 }
1199 SDL_snprintfcat(text, sizeof(text), " %s", SDL_GetVideoDriver(i));
1200 }
1201 SDL_Log("%s", text);
1202 }
1203 }
1204 if (!SDL_InitSubSystem(SDL_INIT_VIDEO)) {
1205 SDL_Log("Couldn't initialize video driver: %s",
1206 SDL_GetError());
1207 return false;
1208 }
1209 if (state->verbose & VERBOSE_VIDEO) {
1210 SDL_Log("Video driver: %s",
1211 SDL_GetCurrentVideoDriver());
1212 }
1213
1214 /* Upload GL settings */
1215 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, state->gl_red_size);
1216 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, state->gl_green_size);
1217 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, state->gl_blue_size);
1218 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, state->gl_alpha_size);
1219 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, state->gl_double_buffer);
1220 SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, state->gl_buffer_size);
1221 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, state->gl_depth_size);
1222 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, state->gl_stencil_size);
1223 SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, state->gl_accum_red_size);
1224 SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, state->gl_accum_green_size);
1225 SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE, state->gl_accum_blue_size);
1226 SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, state->gl_accum_alpha_size);
1227 SDL_GL_SetAttribute(SDL_GL_STEREO, state->gl_stereo);
1228 SDL_GL_SetAttribute(SDL_GL_CONTEXT_RELEASE_BEHAVIOR, state->gl_release_behavior);
1229 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, state->gl_multisamplebuffers);
1230 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, state->gl_multisamplesamples);
1231 if (state->gl_accelerated >= 0) {
1232 SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL,
1233 state->gl_accelerated);
1234 }
1235 SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, state->gl_retained_backing);
1236 if (state->gl_major_version) {
1237 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, state->gl_major_version);
1238 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, state->gl_minor_version);
1239 }
1240 if (state->gl_debug) {
1241 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
1242 }
1243 if (state->gl_profile_mask) {
1244 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, state->gl_profile_mask);
1245 }
1246
1247 if (state->verbose & VERBOSE_MODES) {
1248 SDL_DisplayID *displays;
1249 SDL_Rect bounds, usablebounds;
1250 SDL_DisplayMode **modes;
1251 const SDL_DisplayMode *mode;
1252 int bpp;
1253 Uint32 Rmask, Gmask, Bmask, Amask;
1254#ifdef SDL_VIDEO_DRIVER_WINDOWS
1255 int adapterIndex = 0;
1256 int outputIndex = 0;
1257#endif
1258 displays = SDL_GetDisplays(&n);
1259 SDL_Log("Number of displays: %d", n);
1260 for (i = 0; i < n; ++i) {
1261 SDL_DisplayID displayID = displays[i];
1262 SDL_Log("Display %" SDL_PRIu32 ": %s", displayID, SDL_GetDisplayName(displayID));
1263
1264 SDL_zero(bounds);
1265 SDL_GetDisplayBounds(displayID, &bounds);
1266
1267 SDL_zero(usablebounds);
1268 SDL_GetDisplayUsableBounds(displayID, &usablebounds);
1269
1270 SDL_Log("Bounds: %dx%d at %d,%d", bounds.w, bounds.h, bounds.x, bounds.y);
1271 SDL_Log("Usable bounds: %dx%d at %d,%d", usablebounds.w, usablebounds.h, usablebounds.x, usablebounds.y);
1272
1273 mode = SDL_GetDesktopDisplayMode(displayID);
1274 SDL_GetMasksForPixelFormat(mode->format, &bpp, &Rmask, &Gmask,
1275 &Bmask, &Amask);
1276 SDL_Log(" Desktop mode: %dx%d@%gx %gHz, %d bits-per-pixel (%s)",
1277 mode->w, mode->h, mode->pixel_density, mode->refresh_rate, bpp,
1278 SDL_GetPixelFormatName(mode->format));
1279 if (Rmask || Gmask || Bmask) {
1280 SDL_Log(" Red Mask = 0x%.8" SDL_PRIx32, Rmask);
1281 SDL_Log(" Green Mask = 0x%.8" SDL_PRIx32, Gmask);
1282 SDL_Log(" Blue Mask = 0x%.8" SDL_PRIx32, Bmask);
1283 if (Amask) {
1284 SDL_Log(" Alpha Mask = 0x%.8" SDL_PRIx32, Amask);
1285 }
1286 }
1287
1288 /* Print available fullscreen video modes */
1289 modes = SDL_GetFullscreenDisplayModes(displayID, &m);
1290 if (m == 0) {
1291 SDL_Log("No available fullscreen video modes");
1292 } else {
1293 SDL_Log(" Fullscreen video modes:");
1294 for (j = 0; j < m; ++j) {
1295 mode = modes[j];
1296 SDL_GetMasksForPixelFormat(mode->format, &bpp, &Rmask,
1297 &Gmask, &Bmask, &Amask);
1298 SDL_Log(" Mode %d: %dx%d@%gx %gHz, %d bits-per-pixel (%s)",
1299 j, mode->w, mode->h, mode->pixel_density, mode->refresh_rate, bpp,
1300 SDL_GetPixelFormatName(mode->format));
1301 if (Rmask || Gmask || Bmask) {
1302 SDL_Log(" Red Mask = 0x%.8" SDL_PRIx32,
1303 Rmask);
1304 SDL_Log(" Green Mask = 0x%.8" SDL_PRIx32,
1305 Gmask);
1306 SDL_Log(" Blue Mask = 0x%.8" SDL_PRIx32,
1307 Bmask);
1308 if (Amask) {
1309 SDL_Log(" Alpha Mask = 0x%.8" SDL_PRIx32, Amask);
1310 }
1311 }
1312 }
1313 }
1314 SDL_free(modes);
1315
1316#if defined(SDL_VIDEO_DRIVER_WINDOWS) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
1317 /* Print the D3D9 adapter index */
1318 adapterIndex = SDL_GetDirect3D9AdapterIndex(displayID);
1319 SDL_Log("D3D9 Adapter Index: %d", adapterIndex);
1320
1321 /* Print the DXGI adapter and output indices */
1322 SDL_GetDXGIOutputInfo(displayID, &adapterIndex, &outputIndex);
1323 SDL_Log("DXGI Adapter Index: %d Output Index: %d", adapterIndex, outputIndex);
1324#endif
1325 }
1326 SDL_free(displays);
1327 }
1328
1329 if (state->verbose & VERBOSE_RENDER) {
1330 n = SDL_GetNumRenderDrivers();
1331 if (n == 0) {
1332 SDL_Log("No built-in render drivers");
1333 } else {
1334 SDL_Log("Built-in render drivers:");
1335 for (i = 0; i < n; ++i) {
1336 SDL_Log(" %s", SDL_GetRenderDriver(i));
1337 }
1338 }
1339 }
1340
1341 state->displayID = SDL_GetPrimaryDisplay();
1342 if (state->display_index > 0) {
1343 SDL_DisplayID *displays = SDL_GetDisplays(&n);
1344 if (state->display_index < n) {
1345 state->displayID = displays[state->display_index];
1346 }
1347 SDL_free(displays);
1348
1349 if (SDL_WINDOWPOS_ISUNDEFINED(state->window_x)) {
1350 state->window_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(state->displayID);
1351 state->window_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(state->displayID);
1352 } else if (SDL_WINDOWPOS_ISCENTERED(state->window_x)) {
1353 state->window_x = SDL_WINDOWPOS_CENTERED_DISPLAY(state->displayID);
1354 state->window_y = SDL_WINDOWPOS_CENTERED_DISPLAY(state->displayID);
1355 }
1356 }
1357
1358 {
1359 bool include_high_density_modes = false;
1360 if (state->window_flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
1361 include_high_density_modes = true;
1362 }
1363 SDL_GetClosestFullscreenDisplayMode(state->displayID, state->window_w, state->window_h, state->refresh_rate, include_high_density_modes, &state->fullscreen_mode);
1364 }
1365
1366 state->windows =
1367 (SDL_Window **)SDL_calloc(state->num_windows,
1368 sizeof(*state->windows));
1369 state->renderers =
1370 (SDL_Renderer **)SDL_calloc(state->num_windows,
1371 sizeof(*state->renderers));
1372 state->targets =
1373 (SDL_Texture **)SDL_calloc(state->num_windows,
1374 sizeof(*state->targets));
1375 if (!state->windows || !state->renderers) {
1376 SDL_Log("Out of memory!");
1377 return false;
1378 }
1379 for (i = 0; i < state->num_windows; ++i) {
1380 char title[1024];
1381 SDL_Rect r;
1382 SDL_PropertiesID props;
1383
1384 if (state->fill_usable_bounds) {
1385 SDL_GetDisplayUsableBounds(state->displayID, &r);
1386 } else {
1387 r.x = state->window_x;
1388 r.y = state->window_y;
1389 r.w = state->window_w;
1390 r.h = state->window_h;
1391 if (state->auto_scale_content) {
1392 float scale = SDL_GetDisplayContentScale(state->displayID);
1393 r.w = (int)SDL_ceilf(r.w * scale);
1394 r.h = (int)SDL_ceilf(r.h * scale);
1395 }
1396 }
1397
1398 if (state->num_windows > 1) {
1399 (void)SDL_snprintf(title, SDL_arraysize(title), "%s %d",
1400 state->window_title, i + 1);
1401 } else {
1402 SDL_strlcpy(title, state->window_title, SDL_arraysize(title));
1403 }
1404 props = SDL_CreateProperties();
1405 SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, title);
1406 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, r.x);
1407 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, r.y);
1408 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, r.w);
1409 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, r.h);
1410 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER, state->window_flags);
1411 state->windows[i] = SDL_CreateWindowWithProperties(props);
1412 SDL_DestroyProperties(props);
1413 if (!state->windows[i]) {
1414 SDL_Log("Couldn't create window: %s",
1415 SDL_GetError());
1416 return false;
1417 }
1418 if (state->window_minW || state->window_minH) {
1419 SDL_SetWindowMinimumSize(state->windows[i], state->window_minW, state->window_minH);
1420 }
1421 if (state->window_maxW || state->window_maxH) {
1422 SDL_SetWindowMaximumSize(state->windows[i], state->window_maxW, state->window_maxH);
1423 }
1424 if (state->window_min_aspect != 0.f || state->window_max_aspect != 0.f) {
1425 SDL_SetWindowAspectRatio(state->windows[i], state->window_min_aspect, state->window_max_aspect);
1426 }
1427 SDL_GetWindowSize(state->windows[i], &w, &h);
1428 if (!(state->window_flags & SDL_WINDOW_RESIZABLE) && (w != r.w || h != r.h)) {
1429 SDL_Log("Window requested size %dx%d, got %dx%d", r.w, r.h, w, h);
1430 state->window_w = w;
1431 state->window_h = h;
1432 }
1433 if (state->window_flags & SDL_WINDOW_FULLSCREEN) {
1434 if (state->fullscreen_exclusive) {
1435 SDL_SetWindowFullscreenMode(state->windows[i], &state->fullscreen_mode);
1436 }
1437 SDL_SetWindowFullscreen(state->windows[i], true);
1438 }
1439
1440 /* Add resize/drag areas for windows that are borderless and resizable */
1441 if ((state->window_flags & (SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS)) ==
1442 (SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS)) {
1443 SDL_SetWindowHitTest(state->windows[i], SDLTest_ExampleHitTestCallback, NULL);
1444 }
1445
1446 if (state->window_icon) {
1447 SDL_Surface *icon = SDLTest_LoadIcon(state->window_icon);
1448 if (icon) {
1449 SDL_SetWindowIcon(state->windows[i], icon);
1450 SDL_DestroySurface(icon);
1451 }
1452 }
1453
1454 if (!SDL_RectEmpty(&state->confine)) {
1455 SDL_SetWindowMouseRect(state->windows[i], &state->confine);
1456 }
1457
1458 if (!state->skip_renderer && (state->renderdriver || !(state->window_flags & (SDL_WINDOW_OPENGL | SDL_WINDOW_VULKAN | SDL_WINDOW_METAL)))) {
1459 state->renderers[i] = SDL_CreateRenderer(state->windows[i], state->renderdriver);
1460 if (!state->renderers[i]) {
1461 SDL_Log("Couldn't create renderer: %s",
1462 SDL_GetError());
1463 return false;
1464 }
1465 if (state->logical_w == 0 || state->logical_h == 0) {
1466 state->logical_w = state->window_w;
1467 state->logical_h = state->window_h;
1468 }
1469 if (state->render_vsync) {
1470 SDL_SetRenderVSync(state->renderers[i], state->render_vsync);
1471 }
1472 if (!SDL_SetRenderLogicalPresentation(state->renderers[i], state->logical_w, state->logical_h, state->logical_presentation)) {
1473 SDL_Log("Couldn't set logical presentation: %s", SDL_GetError());
1474 return false;
1475 }
1476 if (state->scale != 0.0f) {
1477 SDL_SetRenderScale(state->renderers[i], state->scale, state->scale);
1478 }
1479 if (state->verbose & VERBOSE_RENDER) {
1480 SDL_Log("Current renderer:");
1481 SDLTest_PrintRenderer(state->renderers[i]);
1482 }
1483 }
1484
1485 SDL_ShowWindow(state->windows[i]);
1486 }
1487 if (state->hide_cursor) {
1488 SDL_HideCursor();
1489 }
1490 }
1491
1492 if (state->flags & SDL_INIT_AUDIO) {
1493 if (state->verbose & VERBOSE_AUDIO) {
1494 n = SDL_GetNumAudioDrivers();
1495 if (n == 0) {
1496 SDL_Log("No built-in audio drivers");
1497 } else {
1498 (void)SDL_snprintf(text, sizeof(text), "Built-in audio drivers:");
1499 for (i = 0; i < n; ++i) {
1500 if (i > 0) {
1501 SDL_snprintfcat(text, sizeof(text), ",");
1502 }
1503 SDL_snprintfcat(text, sizeof(text), " %s", SDL_GetAudioDriver(i));
1504 }
1505 SDL_Log("%s", text);
1506 }
1507 }
1508 if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
1509 SDL_Log("Couldn't initialize audio driver: %s",
1510 SDL_GetError());
1511 return false;
1512 }
1513 if (state->verbose & VERBOSE_AUDIO) {
1514 SDL_Log("Audio driver: %s",
1515 SDL_GetCurrentAudioDriver());
1516 }
1517
1518 const SDL_AudioSpec spec = { state->audio_format, state->audio_channels, state->audio_freq };
1519 state->audio_id = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec);
1520 if (!state->audio_id) {
1521 SDL_Log("Couldn't open audio: %s", SDL_GetError());
1522 return false;
1523 }
1524 }
1525
1526 if (state->flags & SDL_INIT_CAMERA) {
1527 SDL_InitSubSystem(SDL_INIT_CAMERA);
1528 }
1529
1530 return true;
1531}
1532
1533static const char *SystemThemeName(void)
1534{
1535 switch (SDL_GetSystemTheme()) {
1536#define CASE(X) \
1537 case SDL_SYSTEM_THEME_##X: \
1538 return #X
1539 CASE(UNKNOWN);
1540 CASE(LIGHT);
1541 CASE(DARK);
1542#undef CASE
1543 default:
1544 return "???";
1545 }
1546}
1547
1548static const char *DisplayOrientationName(int orientation)
1549{
1550 switch (orientation) {
1551#define CASE(X) \
1552 case SDL_ORIENTATION_##X: \
1553 return #X
1554 CASE(UNKNOWN);
1555 CASE(LANDSCAPE);
1556 CASE(LANDSCAPE_FLIPPED);
1557 CASE(PORTRAIT);
1558 CASE(PORTRAIT_FLIPPED);
1559#undef CASE
1560 default:
1561 return "???";
1562 }
1563}
1564
1565static const char *GamepadAxisName(const SDL_GamepadAxis axis)
1566{
1567 switch (axis) {
1568#define AXIS_CASE(ax) \
1569 case SDL_GAMEPAD_AXIS_##ax: \
1570 return #ax
1571 AXIS_CASE(INVALID);
1572 AXIS_CASE(LEFTX);
1573 AXIS_CASE(LEFTY);
1574 AXIS_CASE(RIGHTX);
1575 AXIS_CASE(RIGHTY);
1576 AXIS_CASE(LEFT_TRIGGER);
1577 AXIS_CASE(RIGHT_TRIGGER);
1578#undef AXIS_CASE
1579 default:
1580 return "???";
1581 }
1582}
1583
1584static const char *GamepadButtonName(const SDL_GamepadButton button)
1585{
1586 switch (button) {
1587#define BUTTON_CASE(btn) \
1588 case SDL_GAMEPAD_BUTTON_##btn: \
1589 return #btn
1590 BUTTON_CASE(INVALID);
1591 BUTTON_CASE(SOUTH);
1592 BUTTON_CASE(EAST);
1593 BUTTON_CASE(WEST);
1594 BUTTON_CASE(NORTH);
1595 BUTTON_CASE(BACK);
1596 BUTTON_CASE(GUIDE);
1597 BUTTON_CASE(START);
1598 BUTTON_CASE(LEFT_STICK);
1599 BUTTON_CASE(RIGHT_STICK);
1600 BUTTON_CASE(LEFT_SHOULDER);
1601 BUTTON_CASE(RIGHT_SHOULDER);
1602 BUTTON_CASE(DPAD_UP);
1603 BUTTON_CASE(DPAD_DOWN);
1604 BUTTON_CASE(DPAD_LEFT);
1605 BUTTON_CASE(DPAD_RIGHT);
1606#undef BUTTON_CASE
1607 default:
1608 return "???";
1609 }
1610}
1611
1612void SDLTest_PrintEvent(const SDL_Event *event)
1613{
1614 switch (event->type) {
1615 case SDL_EVENT_SYSTEM_THEME_CHANGED:
1616 SDL_Log("SDL EVENT: System theme changed to %s", SystemThemeName());
1617 break;
1618 case SDL_EVENT_DISPLAY_ADDED:
1619 SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " attached",
1620 event->display.displayID);
1621 break;
1622 case SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED:
1623 {
1624 float scale = SDL_GetDisplayContentScale(event->display.displayID);
1625 SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " changed content scale to %d%%",
1626 event->display.displayID, (int)(scale * 100.0f));
1627 }
1628 break;
1629 case SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED:
1630 SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " desktop mode changed to %" SDL_PRIs32 "x%" SDL_PRIs32,
1631 event->display.displayID, event->display.data1, event->display.data2);
1632 break;
1633 case SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED:
1634 SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " current mode changed to %" SDL_PRIs32 "x%" SDL_PRIs32,
1635 event->display.displayID, event->display.data1, event->display.data2);
1636 break;
1637 case SDL_EVENT_DISPLAY_MOVED:
1638 SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " changed position",
1639 event->display.displayID);
1640 break;
1641 case SDL_EVENT_DISPLAY_ORIENTATION:
1642 SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " changed orientation to %s",
1643 event->display.displayID, DisplayOrientationName(event->display.data1));
1644 break;
1645 case SDL_EVENT_DISPLAY_REMOVED:
1646 SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " removed",
1647 event->display.displayID);
1648 break;
1649 case SDL_EVENT_WINDOW_SHOWN:
1650 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " shown", event->window.windowID);
1651 break;
1652 case SDL_EVENT_WINDOW_HIDDEN:
1653 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " hidden", event->window.windowID);
1654 break;
1655 case SDL_EVENT_WINDOW_EXPOSED:
1656 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " exposed", event->window.windowID);
1657 break;
1658 case SDL_EVENT_WINDOW_MOVED:
1659 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " moved to %" SDL_PRIs32 ",%" SDL_PRIs32,
1660 event->window.windowID, event->window.data1, event->window.data2);
1661 break;
1662 case SDL_EVENT_WINDOW_RESIZED:
1663 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " resized to %" SDL_PRIs32 "x%" SDL_PRIs32,
1664 event->window.windowID, event->window.data1, event->window.data2);
1665 break;
1666 case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
1667 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " changed pixel size to %" SDL_PRIs32 "x%" SDL_PRIs32,
1668 event->window.windowID, event->window.data1, event->window.data2);
1669 break;
1670 case SDL_EVENT_WINDOW_METAL_VIEW_RESIZED:
1671 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " changed metal view size",
1672 event->window.windowID);
1673 break;
1674 case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED: {
1675 SDL_Rect rect;
1676
1677 SDL_GetWindowSafeArea(SDL_GetWindowFromEvent(event), &rect);
1678 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " changed safe area to: %d,%d %dx%d",
1679 event->window.windowID, rect.x, rect.y, rect.w, rect.h);
1680 break;
1681 }
1682 case SDL_EVENT_WINDOW_MINIMIZED:
1683 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " minimized", event->window.windowID);
1684 break;
1685 case SDL_EVENT_WINDOW_MAXIMIZED:
1686 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " maximized", event->window.windowID);
1687 break;
1688 case SDL_EVENT_WINDOW_RESTORED:
1689 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " restored", event->window.windowID);
1690 break;
1691 case SDL_EVENT_WINDOW_MOUSE_ENTER:
1692 SDL_Log("SDL EVENT: Mouse entered window %" SDL_PRIu32, event->window.windowID);
1693 break;
1694 case SDL_EVENT_WINDOW_MOUSE_LEAVE:
1695 SDL_Log("SDL EVENT: Mouse left window %" SDL_PRIu32, event->window.windowID);
1696 break;
1697 case SDL_EVENT_WINDOW_FOCUS_GAINED:
1698 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " gained keyboard focus",
1699 event->window.windowID);
1700 break;
1701 case SDL_EVENT_WINDOW_FOCUS_LOST:
1702 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " lost keyboard focus",
1703 event->window.windowID);
1704 break;
1705 case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
1706 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " closed", event->window.windowID);
1707 break;
1708 case SDL_EVENT_WINDOW_HIT_TEST:
1709 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " hit test", event->window.windowID);
1710 break;
1711 case SDL_EVENT_WINDOW_ICCPROF_CHANGED:
1712 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " ICC profile changed", event->window.windowID);
1713 break;
1714 case SDL_EVENT_WINDOW_DISPLAY_CHANGED:
1715 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " display changed to %" SDL_PRIs32, event->window.windowID, event->window.data1);
1716 break;
1717 case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED:
1718 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " display scale changed to %d%%", event->window.windowID, (int)(SDL_GetWindowDisplayScale(SDL_GetWindowFromEvent(event)) * 100.0f));
1719 break;
1720 case SDL_EVENT_WINDOW_OCCLUDED:
1721 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " occluded", event->window.windowID);
1722 break;
1723 case SDL_EVENT_WINDOW_ENTER_FULLSCREEN:
1724 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " entered fullscreen", event->window.windowID);
1725 break;
1726 case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN:
1727 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " left fullscreen", event->window.windowID);
1728 break;
1729 case SDL_EVENT_WINDOW_DESTROYED:
1730 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " destroyed", event->window.windowID);
1731 break;
1732 case SDL_EVENT_WINDOW_HDR_STATE_CHANGED:
1733 SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " HDR %s", event->window.windowID, event->window.data1 ? "enabled" : "disabled");
1734 break;
1735 case SDL_EVENT_KEYBOARD_ADDED:
1736 SDL_Log("SDL EVENT: Keyboard %" SDL_PRIu32 " attached",
1737 event->kdevice.which);
1738 break;
1739 case SDL_EVENT_KEYBOARD_REMOVED:
1740 SDL_Log("SDL EVENT: Keyboard %" SDL_PRIu32 " removed",
1741 event->kdevice.which);
1742 break;
1743 case SDL_EVENT_KEY_DOWN:
1744 case SDL_EVENT_KEY_UP: {
1745 char modstr[64];
1746 if (event->key.mod) {
1747 modstr[0] = '\0';
1748 SDLTest_PrintModState(modstr, sizeof (modstr), event->key.mod);
1749 } else {
1750 SDL_strlcpy(modstr, "NONE", sizeof (modstr));
1751 }
1752
1753 SDL_Log("SDL EVENT: Keyboard: key %s in window %" SDL_PRIu32 ": scancode 0x%08X = %s, keycode 0x%08" SDL_PRIX32 " = %s, mods = %s",
1754 (event->type == SDL_EVENT_KEY_DOWN) ? "pressed" : "released",
1755 event->key.windowID,
1756 event->key.scancode,
1757 SDL_GetScancodeName(event->key.scancode),
1758 event->key.key, SDL_GetKeyName(event->key.key),
1759 modstr);
1760 break;
1761 }
1762 case SDL_EVENT_TEXT_EDITING:
1763 SDL_Log("SDL EVENT: Keyboard: text editing \"%s\" in window %" SDL_PRIu32,
1764 event->edit.text, event->edit.windowID);
1765 break;
1766 case SDL_EVENT_TEXT_EDITING_CANDIDATES:
1767 SDL_Log("SDL EVENT: Keyboard: text editing candidates in window %" SDL_PRIu32,
1768 event->edit.windowID);
1769 break;
1770 case SDL_EVENT_TEXT_INPUT:
1771 SDL_Log("SDL EVENT: Keyboard: text input \"%s\" in window %" SDL_PRIu32,
1772 event->text.text, event->text.windowID);
1773 break;
1774 case SDL_EVENT_KEYMAP_CHANGED:
1775 SDL_Log("SDL EVENT: Keymap changed");
1776 break;
1777 case SDL_EVENT_MOUSE_ADDED:
1778 SDL_Log("SDL EVENT: Mouse %" SDL_PRIu32 " attached",
1779 event->mdevice.which);
1780 break;
1781 case SDL_EVENT_MOUSE_REMOVED:
1782 SDL_Log("SDL EVENT: Mouse %" SDL_PRIu32 " removed",
1783 event->mdevice.which);
1784 break;
1785 case SDL_EVENT_MOUSE_MOTION:
1786 SDL_Log("SDL EVENT: Mouse: moved to %g,%g (%g,%g) in window %" SDL_PRIu32,
1787 event->motion.x, event->motion.y,
1788 event->motion.xrel, event->motion.yrel,
1789 event->motion.windowID);
1790 break;
1791 case SDL_EVENT_MOUSE_BUTTON_DOWN:
1792 SDL_Log("SDL EVENT: Mouse: button %d pressed at %g,%g with click count %d in window %" SDL_PRIu32,
1793 event->button.button, event->button.x, event->button.y, event->button.clicks,
1794 event->button.windowID);
1795 break;
1796 case SDL_EVENT_MOUSE_BUTTON_UP:
1797 SDL_Log("SDL EVENT: Mouse: button %d released at %g,%g with click count %d in window %" SDL_PRIu32,
1798 event->button.button, event->button.x, event->button.y, event->button.clicks,
1799 event->button.windowID);
1800 break;
1801 case SDL_EVENT_MOUSE_WHEEL:
1802 SDL_Log("SDL EVENT: Mouse: wheel scrolled %g in x and %g in y (reversed: %d) in window %" SDL_PRIu32,
1803 event->wheel.x, event->wheel.y, event->wheel.direction, event->wheel.windowID);
1804 break;
1805 case SDL_EVENT_JOYSTICK_ADDED:
1806 SDL_Log("SDL EVENT: Joystick %" SDL_PRIu32 " attached",
1807 event->jdevice.which);
1808 break;
1809 case SDL_EVENT_JOYSTICK_REMOVED:
1810 SDL_Log("SDL EVENT: Joystick %" SDL_PRIu32 " removed",
1811 event->jdevice.which);
1812 break;
1813 case SDL_EVENT_JOYSTICK_AXIS_MOTION:
1814 SDL_Log("SDL EVENT: Joystick %" SDL_PRIu32 " axis %d value: %d",
1815 event->jaxis.which,
1816 event->jaxis.axis,
1817 event->jaxis.value);
1818 break;
1819 case SDL_EVENT_JOYSTICK_BALL_MOTION:
1820 SDL_Log("SDL EVENT: Joystick %" SDL_PRIs32 ": ball %d moved by %d,%d",
1821 event->jball.which, event->jball.ball, event->jball.xrel,
1822 event->jball.yrel);
1823 break;
1824 case SDL_EVENT_JOYSTICK_HAT_MOTION:
1825 {
1826 const char *position = "UNKNOWN";
1827 switch (event->jhat.value) {
1828 case SDL_HAT_CENTERED:
1829 position = "CENTER";
1830 break;
1831 case SDL_HAT_UP:
1832 position = "UP";
1833 break;
1834 case SDL_HAT_RIGHTUP:
1835 position = "RIGHTUP";
1836 break;
1837 case SDL_HAT_RIGHT:
1838 position = "RIGHT";
1839 break;
1840 case SDL_HAT_RIGHTDOWN:
1841 position = "RIGHTDOWN";
1842 break;
1843 case SDL_HAT_DOWN:
1844 position = "DOWN";
1845 break;
1846 case SDL_HAT_LEFTDOWN:
1847 position = "LEFTDOWN";
1848 break;
1849 case SDL_HAT_LEFT:
1850 position = "LEFT";
1851 break;
1852 case SDL_HAT_LEFTUP:
1853 position = "LEFTUP";
1854 break;
1855 }
1856 SDL_Log("SDL EVENT: Joystick %" SDL_PRIu32 ": hat %d moved to %s",
1857 event->jhat.which, event->jhat.hat, position);
1858 } break;
1859 case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
1860 SDL_Log("SDL EVENT: Joystick %" SDL_PRIu32 ": button %d pressed",
1861 event->jbutton.which, event->jbutton.button);
1862 break;
1863 case SDL_EVENT_JOYSTICK_BUTTON_UP:
1864 SDL_Log("SDL EVENT: Joystick %" SDL_PRIu32 ": button %d released",
1865 event->jbutton.which, event->jbutton.button);
1866 break;
1867 case SDL_EVENT_JOYSTICK_BATTERY_UPDATED:
1868 SDL_Log("SDL EVENT: Joystick %" SDL_PRIu32 ": battery at %d percent",
1869 event->jbattery.which, event->jbattery.percent);
1870 break;
1871 case SDL_EVENT_GAMEPAD_ADDED:
1872 SDL_Log("SDL EVENT: Gamepad %" SDL_PRIu32 " attached",
1873 event->gdevice.which);
1874 break;
1875 case SDL_EVENT_GAMEPAD_REMOVED:
1876 SDL_Log("SDL EVENT: Gamepad %" SDL_PRIu32 " removed",
1877 event->gdevice.which);
1878 break;
1879 case SDL_EVENT_GAMEPAD_REMAPPED:
1880 SDL_Log("SDL EVENT: Gamepad %" SDL_PRIu32 " mapping changed",
1881 event->gdevice.which);
1882 break;
1883 case SDL_EVENT_GAMEPAD_AXIS_MOTION:
1884 SDL_Log("SDL EVENT: Gamepad %" SDL_PRIu32 " axis %d ('%s') value: %d",
1885 event->gaxis.which,
1886 event->gaxis.axis,
1887 GamepadAxisName((SDL_GamepadAxis)event->gaxis.axis),
1888 event->gaxis.value);
1889 break;
1890 case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
1891 SDL_Log("SDL EVENT: Gamepad %" SDL_PRIu32 "button %d ('%s') down",
1892 event->gbutton.which, event->gbutton.button,
1893 GamepadButtonName((SDL_GamepadButton)event->gbutton.button));
1894 break;
1895 case SDL_EVENT_GAMEPAD_BUTTON_UP:
1896 SDL_Log("SDL EVENT: Gamepad %" SDL_PRIu32 " button %d ('%s') up",
1897 event->gbutton.which, event->gbutton.button,
1898 GamepadButtonName((SDL_GamepadButton)event->gbutton.button));
1899 break;
1900 case SDL_EVENT_CLIPBOARD_UPDATE:
1901 SDL_Log("SDL EVENT: Clipboard updated");
1902 break;
1903
1904 case SDL_EVENT_FINGER_MOTION:
1905 SDL_Log("SDL EVENT: Finger: motion touch=%" SDL_PRIu64 ", finger=%" SDL_PRIu64 ", x=%f, y=%f, dx=%f, dy=%f, pressure=%f",
1906 event->tfinger.touchID,
1907 event->tfinger.fingerID,
1908 event->tfinger.x, event->tfinger.y,
1909 event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure);
1910 break;
1911 case SDL_EVENT_FINGER_DOWN:
1912 case SDL_EVENT_FINGER_UP:
1913 case SDL_EVENT_FINGER_CANCELED:
1914 SDL_Log("SDL EVENT: Finger: %s touch=%" SDL_PRIu64 ", finger=%" SDL_PRIu64 ", x=%f, y=%f, dx=%f, dy=%f, pressure=%f",
1915 (event->type == SDL_EVENT_FINGER_DOWN) ? "down" :
1916 (event->type == SDL_EVENT_FINGER_UP) ? "up" : "cancel",
1917 event->tfinger.touchID,
1918 event->tfinger.fingerID,
1919 event->tfinger.x, event->tfinger.y,
1920 event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure);
1921 break;
1922
1923 case SDL_EVENT_RENDER_TARGETS_RESET:
1924 SDL_Log("SDL EVENT: render targets reset in window %" SDL_PRIu32, event->render.windowID);
1925 break;
1926 case SDL_EVENT_RENDER_DEVICE_RESET:
1927 SDL_Log("SDL EVENT: render device reset in window %" SDL_PRIu32, event->render.windowID);
1928 break;
1929 case SDL_EVENT_RENDER_DEVICE_LOST:
1930 SDL_Log("SDL EVENT: render device lost in window %" SDL_PRIu32, event->render.windowID);
1931 break;
1932
1933 case SDL_EVENT_TERMINATING:
1934 SDL_Log("SDL EVENT: App terminating");
1935 break;
1936 case SDL_EVENT_LOW_MEMORY:
1937 SDL_Log("SDL EVENT: App running low on memory");
1938 break;
1939 case SDL_EVENT_WILL_ENTER_BACKGROUND:
1940 SDL_Log("SDL EVENT: App will enter the background");
1941 break;
1942 case SDL_EVENT_DID_ENTER_BACKGROUND:
1943 SDL_Log("SDL EVENT: App entered the background");
1944 break;
1945 case SDL_EVENT_WILL_ENTER_FOREGROUND:
1946 SDL_Log("SDL EVENT: App will enter the foreground");
1947 break;
1948 case SDL_EVENT_DID_ENTER_FOREGROUND:
1949 SDL_Log("SDL EVENT: App entered the foreground");
1950 break;
1951 case SDL_EVENT_DROP_BEGIN:
1952 SDL_Log("SDL EVENT: Drag and drop beginning in window %" SDL_PRIu32, event->drop.windowID);
1953 break;
1954 case SDL_EVENT_DROP_POSITION:
1955 SDL_Log("SDL EVENT: Drag and drop moving in window %" SDL_PRIu32 ": %g,%g", event->drop.windowID, event->drop.x, event->drop.y);
1956 break;
1957 case SDL_EVENT_DROP_FILE:
1958 SDL_Log("SDL EVENT: Drag and drop file in window %" SDL_PRIu32 ": '%s'", event->drop.windowID, event->drop.data);
1959 break;
1960 case SDL_EVENT_DROP_TEXT:
1961 SDL_Log("SDL EVENT: Drag and drop text in window %" SDL_PRIu32 ": '%s'", event->drop.windowID, event->drop.data);
1962 break;
1963 case SDL_EVENT_DROP_COMPLETE:
1964 SDL_Log("SDL EVENT: Drag and drop ending");
1965 break;
1966 case SDL_EVENT_AUDIO_DEVICE_ADDED:
1967 SDL_Log("SDL EVENT: Audio %s device %" SDL_PRIu32 " available",
1968 event->adevice.recording ? "recording" : "playback",
1969 event->adevice.which);
1970 break;
1971 case SDL_EVENT_AUDIO_DEVICE_REMOVED:
1972 SDL_Log("SDL EVENT: Audio %s device %" SDL_PRIu32 " removed",
1973 event->adevice.recording ? "recording" : "playback",
1974 event->adevice.which);
1975 break;
1976 case SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED:
1977 SDL_Log("SDL EVENT: Audio %s device %" SDL_PRIu32 " format changed",
1978 event->adevice.recording ? "recording" : "playback",
1979 event->adevice.which);
1980 break;
1981 case SDL_EVENT_CAMERA_DEVICE_ADDED:
1982 SDL_Log("SDL EVENT: Camera device %" SDL_PRIu32 " available",
1983 event->cdevice.which);
1984 break;
1985 case SDL_EVENT_CAMERA_DEVICE_REMOVED:
1986 SDL_Log("SDL EVENT: Camera device %" SDL_PRIu32 " removed",
1987 event->cdevice.which);
1988 break;
1989 case SDL_EVENT_CAMERA_DEVICE_APPROVED:
1990 SDL_Log("SDL EVENT: Camera device %" SDL_PRIu32 " permission granted",
1991 event->cdevice.which);
1992 break;
1993 case SDL_EVENT_CAMERA_DEVICE_DENIED:
1994 SDL_Log("SDL EVENT: Camera device %" SDL_PRIu32 " permission denied",
1995 event->cdevice.which);
1996 break;
1997 case SDL_EVENT_SENSOR_UPDATE:
1998 SDL_Log("SDL EVENT: Sensor update for %" SDL_PRIu32,
1999 event->sensor.which);
2000 break;
2001 case SDL_EVENT_PEN_PROXIMITY_IN:
2002 SDL_Log("SDL EVENT: Pen %" SDL_PRIu32 " entered proximity",
2003 event->pproximity.which);
2004 break;
2005 case SDL_EVENT_PEN_PROXIMITY_OUT:
2006 SDL_Log("SDL EVENT: Pen %" SDL_PRIu32 " left proximity",
2007 event->ptouch.which);
2008 break;
2009 case SDL_EVENT_PEN_DOWN:
2010 SDL_Log("SDL EVENT: Pen %" SDL_PRIu32 " touched down at %g,%g",
2011 event->ptouch.which, event->ptouch.x, event->ptouch.y);
2012 break;
2013 case SDL_EVENT_PEN_UP:
2014 SDL_Log("SDL EVENT: Pen %" SDL_PRIu32 " lifted off at %g,%g",
2015 event->ptouch.which, event->ptouch.x, event->ptouch.y);
2016 break;
2017 case SDL_EVENT_PEN_BUTTON_DOWN:
2018 SDL_Log("SDL EVENT: Pen %" SDL_PRIu32 " button %d pressed at %g,%g",
2019 event->pbutton.which, event->pbutton.button, event->pbutton.x, event->pbutton.y);
2020 break;
2021 case SDL_EVENT_PEN_BUTTON_UP:
2022 SDL_Log("SDL EVENT: Pen %" SDL_PRIu32 " button %d released at %g,%g",
2023 event->pbutton.which, event->pbutton.button, event->pbutton.x, event->pbutton.y);
2024 break;
2025 case SDL_EVENT_PEN_MOTION:
2026 SDL_Log("SDL EVENT: Pen %" SDL_PRIu32 " moved to %g,%g",
2027 event->pmotion.which, event->pmotion.x, event->pmotion.y);
2028 break;
2029 case SDL_EVENT_PEN_AXIS:
2030 SDL_Log("SDL EVENT: Pen %" SDL_PRIu32 " axis %d changed to %.2f",
2031 event->paxis.which, event->paxis.axis, event->paxis.value);
2032 break;
2033 case SDL_EVENT_LOCALE_CHANGED:
2034 SDL_Log("SDL EVENT: Locale changed");
2035 break;
2036 case SDL_EVENT_QUIT:
2037 SDL_Log("SDL EVENT: Quit requested");
2038 break;
2039 case SDL_EVENT_USER:
2040 SDL_Log("SDL EVENT: User event %" SDL_PRIs32, event->user.code);
2041 break;
2042 default:
2043 SDL_Log("Unknown event 0x%4.4" SDL_PRIx32, event->type);
2044 break;
2045 }
2046}
2047
2048#define SCREENSHOT_FILE "screenshot.bmp"
2049
2050typedef struct
2051{
2052 void *image;
2053 size_t size;
2054} SDLTest_ClipboardData;
2055
2056static void SDLCALL SDLTest_ScreenShotClipboardCleanup(void *context)
2057{
2058 SDLTest_ClipboardData *data = (SDLTest_ClipboardData *)context;
2059
2060 SDL_Log("Cleaning up screenshot image data");
2061
2062 if (data->image) {
2063 SDL_free(data->image);
2064 }
2065 SDL_free(data);
2066}
2067
2068static const void * SDLCALL SDLTest_ScreenShotClipboardProvider(void *context, const char *mime_type, size_t *size)
2069{
2070 SDLTest_ClipboardData *data = (SDLTest_ClipboardData *)context;
2071
2072 if (SDL_strncmp(mime_type, "text", 4) == 0) {
2073 SDL_Log("Providing screenshot title to clipboard!");
2074
2075 /* Return "Test screenshot" */
2076 *size = 15;
2077 return "Test screenshot (but this isn't part of it)";
2078 }
2079
2080 SDL_Log("Providing screenshot image to clipboard!");
2081
2082 if (!data->image) {
2083 SDL_IOStream *file;
2084
2085 file = SDL_IOFromFile(SCREENSHOT_FILE, "r");
2086 if (file) {
2087 size_t length = (size_t)SDL_GetIOSize(file);
2088 void *image = SDL_malloc(length);
2089 if (image) {
2090 if (SDL_ReadIO(file, image, length) != length) {
2091 SDL_Log("Couldn't read %s: %s", SCREENSHOT_FILE, SDL_GetError());
2092 SDL_free(image);
2093 image = NULL;
2094 }
2095 }
2096 SDL_CloseIO(file);
2097
2098 if (image) {
2099 data->image = image;
2100 data->size = length;
2101 }
2102 } else {
2103 SDL_Log("Couldn't load %s: %s", SCREENSHOT_FILE, SDL_GetError());
2104 }
2105 }
2106
2107 *size = data->size;
2108 return data->image;
2109}
2110
2111static void SDLTest_CopyScreenShot(SDL_Renderer *renderer)
2112{
2113 SDL_Surface *surface;
2114 const char *image_formats[] = {
2115 "text/plain;charset=utf-8",
2116 "image/bmp"
2117 };
2118 SDLTest_ClipboardData *clipboard_data;
2119
2120 if (!renderer) {
2121 return;
2122 }
2123
2124 surface = SDL_RenderReadPixels(renderer, NULL);
2125 if (!surface) {
2126 SDL_Log("Couldn't read screen: %s", SDL_GetError());
2127 return;
2128 }
2129
2130 if (!SDL_SaveBMP(surface, SCREENSHOT_FILE)) {
2131 SDL_Log("Couldn't save %s: %s", SCREENSHOT_FILE, SDL_GetError());
2132 SDL_DestroySurface(surface);
2133 return;
2134 }
2135 SDL_DestroySurface(surface);
2136
2137 clipboard_data = (SDLTest_ClipboardData *)SDL_calloc(1, sizeof(*clipboard_data));
2138 if (!clipboard_data) {
2139 SDL_Log("Couldn't allocate clipboard data");
2140 return;
2141 }
2142 SDL_SetClipboardData(SDLTest_ScreenShotClipboardProvider, SDLTest_ScreenShotClipboardCleanup, clipboard_data, image_formats, SDL_arraysize(image_formats));
2143 SDL_Log("Saved screenshot to %s and clipboard", SCREENSHOT_FILE);
2144}
2145
2146static void SDLTest_PasteScreenShot(void)
2147{
2148 const char *image_formats[] = {
2149 "image/bmp",
2150 "image/png",
2151 "image/tiff",
2152 };
2153 size_t i;
2154
2155 for (i = 0; i < SDL_arraysize(image_formats); ++i) {
2156 size_t size;
2157 void *data = SDL_GetClipboardData(image_formats[i], &size);
2158 if (data) {
2159 char filename[16];
2160 SDL_IOStream *file;
2161
2162 SDL_snprintf(filename, sizeof(filename), "clipboard.%s", image_formats[i] + 6);
2163 file = SDL_IOFromFile(filename, "w");
2164 if (file) {
2165 SDL_Log("Writing clipboard image to %s", filename);
2166 SDL_WriteIO(file, data, size);
2167 SDL_CloseIO(file);
2168 }
2169 SDL_free(data);
2170 return;
2171 }
2172 }
2173 SDL_Log("No supported screenshot data in the clipboard");
2174}
2175
2176static void FullscreenTo(SDLTest_CommonState *state, int index, int windowId)
2177{
2178 int num_displays;
2179 SDL_DisplayID *displays;
2180 SDL_Window *window;
2181 SDL_WindowFlags flags;
2182 const SDL_DisplayMode *mode;
2183 struct SDL_Rect rect = { 0, 0, 0, 0 };
2184
2185 displays = SDL_GetDisplays(&num_displays);
2186 if (displays && index < num_displays) {
2187 window = SDL_GetWindowFromID(windowId);
2188 if (window) {
2189 SDL_GetDisplayBounds(displays[index], &rect);
2190
2191 flags = SDL_GetWindowFlags(window);
2192 if (flags & SDL_WINDOW_FULLSCREEN) {
2193 SDL_SetWindowFullscreen(window, false);
2194 SDL_Delay(15);
2195 }
2196
2197 mode = SDL_GetWindowFullscreenMode(window);
2198 if (mode) {
2199 /* Try to set the existing mode on the new display */
2200 SDL_DisplayMode new_mode;
2201
2202 SDL_memcpy(&new_mode, mode, sizeof(new_mode));
2203 new_mode.displayID = displays[index];
2204 if (!SDL_SetWindowFullscreenMode(window, &new_mode)) {
2205 /* Try again with a default mode */
2206 bool include_high_density_modes = false;
2207 if (state->window_flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
2208 include_high_density_modes = true;
2209 }
2210 if (SDL_GetClosestFullscreenDisplayMode(displays[index], state->window_w, state->window_h, state->refresh_rate, include_high_density_modes, &new_mode)) {
2211 SDL_SetWindowFullscreenMode(window, &new_mode);
2212 }
2213 }
2214 }
2215 if (!mode) {
2216 SDL_SetWindowPosition(window, rect.x, rect.y);
2217 }
2218 SDL_SetWindowFullscreen(window, true);
2219 }
2220 }
2221 SDL_free(displays);
2222}
2223
2224SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const SDL_Event *event)
2225{
2226 int i;
2227
2228 if (state->verbose & VERBOSE_EVENT) {
2229 if ((event->type != SDL_EVENT_MOUSE_MOTION &&
2230 event->type != SDL_EVENT_FINGER_MOTION &&
2231 event->type != SDL_EVENT_PEN_MOTION &&
2232 event->type != SDL_EVENT_PEN_AXIS &&
2233 event->type != SDL_EVENT_JOYSTICK_AXIS_MOTION) ||
2234 (state->verbose & VERBOSE_MOTION)) {
2235 SDLTest_PrintEvent(event);
2236 }
2237 }
2238
2239 switch (event->type) {
2240 case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED:
2241 if (state->auto_scale_content) {
2242 SDL_Window *window = SDL_GetWindowFromEvent(event);
2243 if (window) {
2244 float scale = SDL_GetDisplayContentScale(SDL_GetDisplayForWindow(window));
2245 int w = state->window_w;
2246 int h = state->window_h;
2247
2248 w = (int)SDL_ceilf(w * scale);
2249 h = (int)SDL_ceilf(h * scale);
2250 SDL_SetWindowSize(window, w, h);
2251 }
2252 }
2253 break;
2254 case SDL_EVENT_WINDOW_FOCUS_LOST:
2255 if (state->flash_on_focus_loss) {
2256 SDL_Window *window = SDL_GetWindowFromEvent(event);
2257 if (window) {
2258 SDL_FlashWindow(window, SDL_FLASH_UNTIL_FOCUSED);
2259 }
2260 }
2261 break;
2262 case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
2263 {
2264 SDL_Window *window = SDL_GetWindowFromEvent(event);
2265 if (window) {
2266 SDL_HideWindow(window);
2267 }
2268 break;
2269 }
2270 case SDL_EVENT_KEY_DOWN:
2271 {
2272 bool withControl = !!(event->key.mod & SDL_KMOD_CTRL);
2273 bool withShift = !!(event->key.mod & SDL_KMOD_SHIFT);
2274 bool withAlt = !!(event->key.mod & SDL_KMOD_ALT);
2275
2276 switch (event->key.key) {
2277 /* Add hotkeys here */
2278 case SDLK_PRINTSCREEN:
2279 {
2280 SDL_Window *window = SDL_GetWindowFromEvent(event);
2281 if (window) {
2282 for (i = 0; i < state->num_windows; ++i) {
2283 if (window == state->windows[i]) {
2284 SDLTest_CopyScreenShot(state->renderers[i]);
2285 }
2286 }
2287 }
2288 } break;
2289 case SDLK_EQUALS:
2290 if (withControl) {
2291 /* Ctrl-+ double the size of the window */
2292 SDL_Window *window = SDL_GetWindowFromEvent(event);
2293 if (window) {
2294 int w, h;
2295 SDL_GetWindowSize(window, &w, &h);
2296 SDL_SetWindowSize(window, w * 2, h * 2);
2297 }
2298 }
2299 break;
2300 case SDLK_MINUS:
2301 if (withControl) {
2302 /* Ctrl-- half the size of the window */
2303 SDL_Window *window = SDL_GetWindowFromEvent(event);
2304 if (window) {
2305 int w, h;
2306 SDL_GetWindowSize(window, &w, &h);
2307 SDL_SetWindowSize(window, w / 2, h / 2);
2308 }
2309 }
2310 break;
2311 case SDLK_UP:
2312 case SDLK_DOWN:
2313 case SDLK_LEFT:
2314 case SDLK_RIGHT:
2315 if (withAlt) {
2316 /* Alt-Up/Down/Left/Right switches between displays */
2317 SDL_Window *window = SDL_GetWindowFromEvent(event);
2318 if (window) {
2319 int num_displays;
2320 const SDL_DisplayID *displays = SDL_GetDisplays(&num_displays);
2321 if (displays) {
2322 SDL_DisplayID displayID = SDL_GetDisplayForWindow(window);
2323 int current_index = -1;
2324
2325 for (i = 0; i < num_displays; ++i) {
2326 if (displayID == displays[i]) {
2327 current_index = i;
2328 break;
2329 }
2330 }
2331 if (current_index >= 0) {
2332 SDL_DisplayID dest;
2333 if (event->key.key == SDLK_UP || event->key.key == SDLK_LEFT) {
2334 dest = displays[(current_index + num_displays - 1) % num_displays];
2335 } else {
2336 dest = displays[(current_index + num_displays + 1) % num_displays];
2337 }
2338 SDL_Log("Centering on display (%" SDL_PRIu32 ")", dest);
2339 SDL_SetWindowPosition(window,
2340 SDL_WINDOWPOS_CENTERED_DISPLAY(dest),
2341 SDL_WINDOWPOS_CENTERED_DISPLAY(dest));
2342 }
2343 }
2344 }
2345 }
2346 if (withShift) {
2347 /* Shift-Up/Down/Left/Right shift the window by 100px */
2348 SDL_Window *window = SDL_GetWindowFromEvent(event);
2349 if (window) {
2350 const int delta = 100;
2351 int x, y;
2352 SDL_GetWindowPosition(window, &x, &y);
2353
2354 if (event->key.key == SDLK_UP) {
2355 y -= delta;
2356 }
2357 if (event->key.key == SDLK_DOWN) {
2358 y += delta;
2359 }
2360 if (event->key.key == SDLK_LEFT) {
2361 x -= delta;
2362 }
2363 if (event->key.key == SDLK_RIGHT) {
2364 x += delta;
2365 }
2366
2367 SDL_Log("Setting position to (%d, %d)", x, y);
2368 SDL_SetWindowPosition(window, x, y);
2369 }
2370 }
2371 break;
2372 case SDLK_O:
2373 if (withControl) {
2374 /* Ctrl-O (or Ctrl-Shift-O) changes window opacity. */
2375 SDL_Window *window = SDL_GetWindowFromEvent(event);
2376 if (window) {
2377 float opacity = SDL_GetWindowOpacity(window);
2378 if (withShift) {
2379 opacity += 0.20f;
2380 } else {
2381 opacity -= 0.20f;
2382 }
2383 SDL_SetWindowOpacity(window, opacity);
2384 }
2385 }
2386 break;
2387 case SDLK_H:
2388 if (withControl) {
2389 /* Ctrl-H changes cursor visibility. */
2390 if (SDL_CursorVisible()) {
2391 SDL_HideCursor();
2392 } else {
2393 SDL_ShowCursor();
2394 }
2395 }
2396 break;
2397 case SDLK_C:
2398 if (withAlt) {
2399 /* Alt-C copy awesome text to the primary selection! */
2400 SDL_SetPrimarySelectionText("SDL rocks!\nYou know it!");
2401 SDL_Log("Copied text to primary selection");
2402
2403 } else if (withControl) {
2404 if (withShift) {
2405 /* Ctrl-Shift-C copy screenshot! */
2406 SDL_Window *window = SDL_GetWindowFromEvent(event);
2407 if (window) {
2408 for (i = 0; i < state->num_windows; ++i) {
2409 if (window == state->windows[i]) {
2410 SDLTest_CopyScreenShot(state->renderers[i]);
2411 }
2412 }
2413 }
2414 } else {
2415 /* Ctrl-C copy awesome text! */
2416 SDL_SetClipboardText("SDL rocks!\nYou know it!");
2417 SDL_Log("Copied text to clipboard");
2418 }
2419 break;
2420 }
2421 break;
2422 case SDLK_V:
2423 if (withAlt) {
2424 /* Alt-V paste awesome text from the primary selection! */
2425 char *text = SDL_GetPrimarySelectionText();
2426 if (*text) {
2427 SDL_Log("Primary selection: %s", text);
2428 } else {
2429 SDL_Log("Primary selection is empty");
2430 }
2431 SDL_free(text);
2432
2433 } else if (withControl) {
2434 if (withShift) {
2435 /* Ctrl-Shift-V paste screenshot! */
2436 SDLTest_PasteScreenShot();
2437 } else {
2438 /* Ctrl-V paste awesome text! */
2439 char *text = SDL_GetClipboardText();
2440 if (*text) {
2441 SDL_Log("Clipboard: %s", text);
2442 } else {
2443 SDL_Log("Clipboard is empty");
2444 }
2445 SDL_free(text);
2446 }
2447 }
2448 break;
2449 case SDLK_F:
2450 if (withControl) {
2451 /* Ctrl-F flash the window */
2452 SDL_Window *window = SDL_GetWindowFromEvent(event);
2453 if (window) {
2454 SDL_FlashWindow(window, SDL_FLASH_BRIEFLY);
2455 }
2456 }
2457 break;
2458 case SDLK_G:
2459 if (withControl) {
2460 /* Ctrl-G toggle mouse grab */
2461 SDL_Window *window = SDL_GetWindowFromEvent(event);
2462 if (window) {
2463 SDL_SetWindowMouseGrab(window, !SDL_GetWindowMouseGrab(window));
2464 }
2465 }
2466 break;
2467 case SDLK_K:
2468 if (withControl) {
2469 /* Ctrl-K toggle keyboard grab */
2470 SDL_Window *window = SDL_GetWindowFromEvent(event);
2471 if (window) {
2472 SDL_SetWindowKeyboardGrab(window, !SDL_GetWindowKeyboardGrab(window));
2473 }
2474 }
2475 break;
2476 case SDLK_M:
2477 if (withControl) {
2478 /* Ctrl-M maximize */
2479 SDL_Window *window = SDL_GetWindowFromEvent(event);
2480 if (window) {
2481 SDL_WindowFlags flags = SDL_GetWindowFlags(window);
2482 if (!(flags & SDL_WINDOW_RESIZABLE)) {
2483 SDL_SetWindowResizable(window, true);
2484 }
2485 if (flags & SDL_WINDOW_MAXIMIZED) {
2486 SDL_RestoreWindow(window);
2487 } else {
2488 SDL_MaximizeWindow(window);
2489 }
2490 if (!(flags & SDL_WINDOW_RESIZABLE)) {
2491 SDL_SetWindowResizable(window, false);
2492 }
2493 }
2494 }
2495 if (withShift) {
2496 SDL_Window *window = SDL_GetWindowFromEvent(event);
2497 if (window) {
2498 const bool shouldCapture = !(SDL_GetWindowFlags(window) & SDL_WINDOW_MOUSE_CAPTURE);
2499 const bool rc = SDL_CaptureMouse(shouldCapture);
2500 SDL_Log("%sapturing mouse %s!", shouldCapture ? "C" : "Unc", rc ? "succeeded" : "failed");
2501 }
2502 }
2503 break;
2504 case SDLK_R:
2505 if (withControl) {
2506 /* Ctrl-R toggle mouse relative mode */
2507 SDL_Window *window = SDL_GetWindowFromEvent(event);
2508 if (window) {
2509 SDL_SetWindowRelativeMouseMode(window, !SDL_GetWindowRelativeMouseMode(window));
2510 }
2511 }
2512 break;
2513 case SDLK_T:
2514 if (withControl) {
2515 /* Ctrl-T toggle topmost mode */
2516 SDL_Window *window = SDL_GetWindowFromEvent(event);
2517 if (window) {
2518 SDL_WindowFlags flags = SDL_GetWindowFlags(window);
2519 if (flags & SDL_WINDOW_ALWAYS_ON_TOP) {
2520 SDL_SetWindowAlwaysOnTop(window, false);
2521 } else {
2522 SDL_SetWindowAlwaysOnTop(window, true);
2523 }
2524 }
2525 }
2526 break;
2527 case SDLK_Z:
2528 if (withControl) {
2529 /* Ctrl-Z minimize */
2530 SDL_Window *window = SDL_GetWindowFromEvent(event);
2531 if (window) {
2532 SDL_MinimizeWindow(window);
2533 }
2534 }
2535 break;
2536 case SDLK_RETURN:
2537 if (withControl) {
2538 /* Ctrl-Enter toggle fullscreen */
2539 SDL_Window *window = SDL_GetWindowFromEvent(event);
2540 if (window) {
2541 SDL_WindowFlags flags = SDL_GetWindowFlags(window);
2542 if (!(flags & SDL_WINDOW_FULLSCREEN) ||
2543 !SDL_GetWindowFullscreenMode(window)) {
2544 SDL_SetWindowFullscreenMode(window, &state->fullscreen_mode);
2545 SDL_SetWindowFullscreen(window, true);
2546 } else {
2547 SDL_SetWindowFullscreen(window, false);
2548 }
2549 }
2550 } else if (withAlt) {
2551 /* Alt-Enter toggle fullscreen desktop */
2552 SDL_Window *window = SDL_GetWindowFromEvent(event);
2553 if (window) {
2554 SDL_WindowFlags flags = SDL_GetWindowFlags(window);
2555 if (!(flags & SDL_WINDOW_FULLSCREEN) ||
2556 SDL_GetWindowFullscreenMode(window)) {
2557 SDL_SetWindowFullscreenMode(window, NULL);
2558 SDL_SetWindowFullscreen(window, true);
2559 } else {
2560 SDL_SetWindowFullscreen(window, false);
2561 }
2562 }
2563 }
2564
2565 break;
2566 case SDLK_B:
2567 if (withControl) {
2568 /* Ctrl-B toggle window border */
2569 SDL_Window *window = SDL_GetWindowFromEvent(event);
2570 if (window) {
2571 const SDL_WindowFlags flags = SDL_GetWindowFlags(window);
2572 const bool b = (flags & SDL_WINDOW_BORDERLESS) ? true : false;
2573 SDL_SetWindowBordered(window, b);
2574 }
2575 }
2576 break;
2577 case SDLK_A:
2578 if (withControl) {
2579 /* Ctrl-A toggle aspect ratio */
2580 SDL_Window *window = SDL_GetWindowFromEvent(event);
2581 if (window) {
2582 float min_aspect = 0.0f, max_aspect = 0.0f;
2583
2584 SDL_GetWindowAspectRatio(window, &min_aspect, &max_aspect);
2585 if (min_aspect > 0.0f || max_aspect > 0.0f) {
2586 min_aspect = 0.0f;
2587 max_aspect = 0.0f;
2588 } else {
2589 min_aspect = 1.0f;
2590 max_aspect = 1.0f;
2591 }
2592 SDL_SetWindowAspectRatio(window, min_aspect, max_aspect);
2593 }
2594 }
2595 break;
2596 case SDLK_0:
2597 if (withControl) {
2598 SDL_Window *window = SDL_GetWindowFromEvent(event);
2599 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "Test Message", "You're awesome!", window);
2600 }
2601 break;
2602 case SDLK_1:
2603 if (withControl) {
2604 FullscreenTo(state, 0, event->key.windowID);
2605 }
2606 break;
2607 case SDLK_2:
2608 if (withControl) {
2609 FullscreenTo(state, 1, event->key.windowID);
2610 }
2611 break;
2612 case SDLK_ESCAPE:
2613 return SDL_APP_SUCCESS;
2614 default:
2615 break;
2616 }
2617 break;
2618 }
2619 case SDL_EVENT_QUIT:
2620 return SDL_APP_SUCCESS;
2621 default:
2622 break;
2623 }
2624
2625 return SDL_APP_CONTINUE;
2626}
2627
2628void SDLTest_CommonEvent(SDLTest_CommonState *state, SDL_Event *event, int *done)
2629{
2630 if (SDLTest_CommonEventMainCallbacks(state, event) != SDL_APP_CONTINUE) {
2631 *done = 1;
2632 }
2633}
2634
2635void SDLTest_CommonQuit(SDLTest_CommonState *state)
2636{
2637 if (state) {
2638 int i;
2639
2640 if (state->targets) {
2641 for (i = 0; i < state->num_windows; ++i) {
2642 if (state->targets[i]) {
2643 SDL_DestroyTexture(state->targets[i]);
2644 }
2645 }
2646 SDL_free(state->targets);
2647 }
2648 if (state->renderers) {
2649 for (i = 0; i < state->num_windows; ++i) {
2650 if (state->renderers[i]) {
2651 SDL_DestroyRenderer(state->renderers[i]);
2652 }
2653 }
2654 SDL_free(state->renderers);
2655 }
2656 if (state->windows) {
2657 for (i = 0; i < state->num_windows; i++) {
2658 SDL_DestroyWindow(state->windows[i]);
2659 }
2660 SDL_free(state->windows);
2661 }
2662 }
2663 SDL_Quit();
2664 SDLTest_CommonDestroyState(state);
2665}
2666
2667void SDLTest_CommonDrawWindowInfo(SDL_Renderer *renderer, SDL_Window *window, float *usedHeight)
2668{
2669 char text[1024];
2670 float textY = 0.0f;
2671 const int lineHeight = 10;
2672 int x, y, w, h;
2673 float fx, fy;
2674 SDL_Rect rect;
2675 const SDL_DisplayMode *mode;
2676 float scaleX, scaleY;
2677 SDL_MouseButtonFlags flags;
2678 SDL_DisplayID windowDisplayID = SDL_GetDisplayForWindow(window);
2679 const char *name;
2680 SDL_RendererLogicalPresentation logical_presentation;
2681
2682 /* Video */
2683
2684 SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
2685 SDLTest_DrawString(renderer, 0.0f, textY, "-- Video --");
2686 textY += lineHeight;
2687
2688 SDL_SetRenderDrawColor(renderer, 170, 170, 170, 255);
2689
2690 (void)SDL_snprintf(text, sizeof(text), "SDL_GetCurrentVideoDriver: %s", SDL_GetCurrentVideoDriver());
2691 SDLTest_DrawString(renderer, 0.0f, textY, text);
2692 textY += lineHeight;
2693
2694 /* Renderer */
2695
2696 SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
2697 SDLTest_DrawString(renderer, 0.0f, textY, "-- Renderer --");
2698 textY += lineHeight;
2699
2700 SDL_SetRenderDrawColor(renderer, 170, 170, 170, 255);
2701
2702 name = SDL_GetRendererName(renderer);
2703 (void)SDL_snprintf(text, sizeof(text), "SDL_GetRendererName: %s", name);
2704 SDLTest_DrawString(renderer, 0.0f, textY, text);
2705 textY += lineHeight;
2706
2707 if (SDL_GetRenderOutputSize(renderer, &w, &h)) {
2708 (void)SDL_snprintf(text, sizeof(text), "SDL_GetRenderOutputSize: %dx%d", w, h);
2709 SDLTest_DrawString(renderer, 0.0f, textY, text);
2710 textY += lineHeight;
2711 }
2712
2713 if (SDL_GetCurrentRenderOutputSize(renderer, &w, &h)) {
2714 (void)SDL_snprintf(text, sizeof(text), "SDL_GetCurrentRenderOutputSize: %dx%d", w, h);
2715 SDLTest_DrawString(renderer, 0.0f, textY, text);
2716 textY += lineHeight;
2717 }
2718
2719 SDL_GetRenderViewport(renderer, &rect);
2720 (void)SDL_snprintf(text, sizeof(text), "SDL_GetRenderViewport: %d,%d, %dx%d",
2721 rect.x, rect.y, rect.w, rect.h);
2722 SDLTest_DrawString(renderer, 0.0f, textY, text);
2723 textY += lineHeight;
2724
2725 SDL_GetRenderScale(renderer, &scaleX, &scaleY);
2726 (void)SDL_snprintf(text, sizeof(text), "SDL_GetRenderScale: %g,%g",
2727 scaleX, scaleY);
2728 SDLTest_DrawString(renderer, 0.0f, textY, text);
2729 textY += lineHeight;
2730
2731 SDL_GetRenderLogicalPresentation(renderer, &w, &h, &logical_presentation);
2732 (void)SDL_snprintf(text, sizeof(text), "SDL_GetRenderLogicalPresentation: %dx%d ", w, h);
2733 SDLTest_PrintLogicalPresentation(text, sizeof(text), logical_presentation);
2734 textY += lineHeight;
2735
2736 /* Window */
2737
2738 SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
2739 SDLTest_DrawString(renderer, 0.0f, textY, "-- Window --");
2740 textY += lineHeight;
2741
2742 SDL_SetRenderDrawColor(renderer, 170, 170, 170, 255);
2743
2744 SDL_GetWindowPosition(window, &x, &y);
2745 (void)SDL_snprintf(text, sizeof(text), "SDL_GetWindowPosition: %d,%d", x, y);
2746 SDLTest_DrawString(renderer, 0.0f, textY, text);
2747 textY += lineHeight;
2748
2749 SDL_GetWindowSize(window, &w, &h);
2750 (void)SDL_snprintf(text, sizeof(text), "SDL_GetWindowSize: %dx%d", w, h);
2751 SDLTest_DrawString(renderer, 0.0f, textY, text);
2752 textY += lineHeight;
2753
2754 SDL_GetWindowSafeArea(window, &rect);
2755 (void)SDL_snprintf(text, sizeof(text), "SDL_GetWindowSafeArea: %d,%d %dx%d", rect.x, rect.y, rect.w, rect.h);
2756 SDLTest_DrawString(renderer, 0.0f, textY, text);
2757 textY += lineHeight;
2758
2759 (void)SDL_snprintf(text, sizeof(text), "SDL_GetWindowFlags: ");
2760 SDLTest_PrintWindowFlags(text, sizeof(text), SDL_GetWindowFlags(window));
2761 SDLTest_DrawString(renderer, 0.0f, textY, text);
2762 textY += lineHeight;
2763
2764 mode = SDL_GetWindowFullscreenMode(window);
2765 if (mode) {
2766 (void)SDL_snprintf(text, sizeof(text), "SDL_GetWindowFullscreenMode: %dx%d@%gx %gHz, (%s)",
2767 mode->w, mode->h, mode->pixel_density, mode->refresh_rate, SDL_GetPixelFormatName(mode->format));
2768 SDLTest_DrawString(renderer, 0.0f, textY, text);
2769 textY += lineHeight;
2770 }
2771
2772 /* Display */
2773
2774 SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
2775 SDLTest_DrawString(renderer, 0.0f, textY, "-- Display --");
2776 textY += lineHeight;
2777
2778 SDL_SetRenderDrawColor(renderer, 170, 170, 170, 255);
2779
2780 (void)SDL_snprintf(text, sizeof(text), "SDL_GetDisplayForWindow: %" SDL_PRIu32, windowDisplayID);
2781 SDLTest_DrawString(renderer, 0.0f, textY, text);
2782 textY += lineHeight;
2783
2784 (void)SDL_snprintf(text, sizeof(text), "SDL_GetDisplayName: %s", SDL_GetDisplayName(windowDisplayID));
2785 SDLTest_DrawString(renderer, 0.0f, textY, text);
2786 textY += lineHeight;
2787
2788 if (SDL_GetDisplayBounds(windowDisplayID, &rect)) {
2789 (void)SDL_snprintf(text, sizeof(text), "SDL_GetDisplayBounds: %d,%d, %dx%d",
2790 rect.x, rect.y, rect.w, rect.h);
2791 SDLTest_DrawString(renderer, 0.0f, textY, text);
2792 textY += lineHeight;
2793 }
2794
2795 mode = SDL_GetCurrentDisplayMode(windowDisplayID);
2796 if (mode) {
2797 (void)SDL_snprintf(text, sizeof(text), "SDL_GetCurrentDisplayMode: %dx%d@%gx %gHz, (%s)",
2798 mode->w, mode->h, mode->pixel_density, mode->refresh_rate, SDL_GetPixelFormatName(mode->format));
2799 SDLTest_DrawString(renderer, 0.0f, textY, text);
2800 textY += lineHeight;
2801 }
2802
2803 mode = SDL_GetDesktopDisplayMode(windowDisplayID);
2804 if (mode) {
2805 (void)SDL_snprintf(text, sizeof(text), "SDL_GetDesktopDisplayMode: %dx%d@%gx %gHz, (%s)",
2806 mode->w, mode->h, mode->pixel_density, mode->refresh_rate, SDL_GetPixelFormatName(mode->format));
2807 SDLTest_DrawString(renderer, 0.0f, textY, text);
2808 textY += lineHeight;
2809 }
2810
2811 (void)SDL_snprintf(text, sizeof(text), "SDL_GetNaturalDisplayOrientation: ");
2812 SDLTest_PrintDisplayOrientation(text, sizeof(text), SDL_GetNaturalDisplayOrientation(windowDisplayID));
2813 SDLTest_DrawString(renderer, 0.0f, textY, text);
2814 textY += lineHeight;
2815
2816 (void)SDL_snprintf(text, sizeof(text), "SDL_GetCurrentDisplayOrientation: ");
2817 SDLTest_PrintDisplayOrientation(text, sizeof(text), SDL_GetCurrentDisplayOrientation(windowDisplayID));
2818 SDLTest_DrawString(renderer, 0.0f, textY, text);
2819 textY += lineHeight;
2820
2821 (void)SDL_snprintf(text, sizeof(text), "SDL_GetDisplayContentScale: %g", SDL_GetDisplayContentScale(windowDisplayID));
2822 SDLTest_DrawString(renderer, 0.0f, textY, text);
2823 textY += lineHeight;
2824
2825 /* Mouse */
2826
2827 SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
2828 SDLTest_DrawString(renderer, 0.0f, textY, "-- Mouse --");
2829 textY += lineHeight;
2830
2831 SDL_SetRenderDrawColor(renderer, 170, 170, 170, 255);
2832
2833 flags = SDL_GetMouseState(&fx, &fy);
2834 (void)SDL_snprintf(text, sizeof(text), "SDL_GetMouseState: %g,%g ", fx, fy);
2835 SDLTest_PrintButtonMask(text, sizeof(text), flags);
2836 SDLTest_DrawString(renderer, 0.0f, textY, text);
2837 textY += lineHeight;
2838
2839 flags = SDL_GetGlobalMouseState(&fx, &fy);
2840 (void)SDL_snprintf(text, sizeof(text), "SDL_GetGlobalMouseState: %g,%g ", fx, fy);
2841 SDLTest_PrintButtonMask(text, sizeof(text), flags);
2842 SDLTest_DrawString(renderer, 0.0f, textY, text);
2843 textY += lineHeight;
2844
2845 /* Keyboard */
2846
2847 SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
2848 SDLTest_DrawString(renderer, 0, textY, "-- Keyboard --");
2849 textY += lineHeight;
2850
2851 SDL_SetRenderDrawColor(renderer, 170, 170, 170, 255);
2852
2853 (void)SDL_snprintf(text, sizeof(text), "SDL_GetModState: ");
2854 SDLTest_PrintModState(text, sizeof(text), SDL_GetModState());
2855 SDLTest_DrawString(renderer, 0, textY, text);
2856 textY += lineHeight;
2857
2858 if (usedHeight) {
2859 *usedHeight = textY;
2860 }
2861}
2862