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#include "SDL_internal.h"
22
23#ifdef SDL_VIDEO_DRIVER_DUMMY
24
25/* Dummy SDL video driver implementation; this is just enough to make an
26 * SDL-based application THINK it's got a working video driver, for
27 * applications that call SDL_Init(SDL_INIT_VIDEO) when they don't need it,
28 * and also for use as a collection of stubs when porting SDL to a new
29 * platform for which you haven't yet written a valid video driver.
30 *
31 * This is also a great way to determine bottlenecks: if you think that SDL
32 * is a performance problem for a given platform, enable this driver, and
33 * then see if your application runs faster without video overhead.
34 *
35 * Initial work by Ryan C. Gordon (icculus@icculus.org). A good portion
36 * of this was cut-and-pasted from Stephane Peter's work in the AAlib
37 * SDL video driver. Renamed to "DUMMY" by Sam Lantinga.
38 */
39
40#include "../SDL_sysvideo.h"
41#include "../SDL_pixels_c.h"
42#include "../../events/SDL_events_c.h"
43#ifdef SDL_INPUT_LINUXEV
44#include "../../core/linux/SDL_evdev.h"
45#endif
46
47#include "SDL_nullvideo.h"
48#include "SDL_nullevents_c.h"
49#include "SDL_nullframebuffer_c.h"
50
51#define DUMMYVID_DRIVER_NAME "dummy"
52#define DUMMYVID_DRIVER_EVDEV_NAME "evdev"
53
54// Initialization/Query functions
55static bool DUMMY_VideoInit(SDL_VideoDevice *_this);
56static void DUMMY_VideoQuit(SDL_VideoDevice *_this);
57
58static bool DUMMY_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window)
59{
60 SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, window->pending.x, window->pending.y);
61 return true;
62}
63
64static void DUMMY_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window)
65{
66 SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, window->pending.w, window->pending.h);
67}
68
69// DUMMY driver bootstrap functions
70
71static bool DUMMY_Available(const char *enable_hint)
72{
73 const char *hint = SDL_GetHint(SDL_HINT_VIDEO_DRIVER);
74 if (hint) {
75 if (SDL_strcmp(hint, enable_hint) == 0) {
76 return true;
77 }
78 }
79 return false;
80}
81
82static void DUMMY_DeleteDevice(SDL_VideoDevice *device)
83{
84 SDL_free(device);
85}
86
87static SDL_VideoDevice *DUMMY_InternalCreateDevice(const char *enable_hint)
88{
89 SDL_VideoDevice *device;
90
91 if (!DUMMY_Available(enable_hint)) {
92 return NULL;
93 }
94
95 // Initialize all variables that we clean on shutdown
96 device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
97 if (!device) {
98 return NULL;
99 }
100 device->is_dummy = true;
101
102 // Set the function pointers
103 device->VideoInit = DUMMY_VideoInit;
104 device->VideoQuit = DUMMY_VideoQuit;
105 device->PumpEvents = DUMMY_PumpEvents;
106 device->SetWindowSize = DUMMY_SetWindowSize;
107 device->SetWindowPosition = DUMMY_SetWindowPosition;
108 device->CreateWindowFramebuffer = SDL_DUMMY_CreateWindowFramebuffer;
109 device->UpdateWindowFramebuffer = SDL_DUMMY_UpdateWindowFramebuffer;
110 device->DestroyWindowFramebuffer = SDL_DUMMY_DestroyWindowFramebuffer;
111 device->free = DUMMY_DeleteDevice;
112
113 return device;
114}
115
116static SDL_VideoDevice *DUMMY_CreateDevice(void)
117{
118 return DUMMY_InternalCreateDevice(DUMMYVID_DRIVER_NAME);
119}
120
121VideoBootStrap DUMMY_bootstrap = {
122 DUMMYVID_DRIVER_NAME, "SDL dummy video driver",
123 DUMMY_CreateDevice,
124 NULL, // no ShowMessageBox implementation
125 false
126};
127
128#ifdef SDL_INPUT_LINUXEV
129
130static void DUMMY_EVDEV_Poll(SDL_VideoDevice *_this)
131{
132 (void)_this;
133 SDL_EVDEV_Poll();
134}
135
136static SDL_VideoDevice *DUMMY_EVDEV_CreateDevice(void)
137{
138 SDL_VideoDevice *device = DUMMY_InternalCreateDevice(DUMMYVID_DRIVER_EVDEV_NAME);
139 if (device) {
140 device->PumpEvents = DUMMY_EVDEV_Poll;
141 }
142 return device;
143}
144
145VideoBootStrap DUMMY_evdev_bootstrap = {
146 DUMMYVID_DRIVER_EVDEV_NAME, "SDL dummy video driver with evdev",
147 DUMMY_EVDEV_CreateDevice,
148 NULL, // no ShowMessageBox implementation
149 false
150};
151
152#endif // SDL_INPUT_LINUXEV
153
154bool DUMMY_VideoInit(SDL_VideoDevice *_this)
155{
156 SDL_DisplayMode mode;
157
158 // Use a fake 32-bpp desktop mode
159 SDL_zero(mode);
160 mode.format = SDL_PIXELFORMAT_XRGB8888;
161 mode.w = 1024;
162 mode.h = 768;
163 if (SDL_AddBasicVideoDisplay(&mode) == 0) {
164 return false;
165 }
166
167#ifdef SDL_INPUT_LINUXEV
168 SDL_EVDEV_Init();
169#endif
170
171 // We're done!
172 return true;
173}
174
175void DUMMY_VideoQuit(SDL_VideoDevice *_this)
176{
177#ifdef SDL_INPUT_LINUXEV
178 SDL_EVDEV_Quit();
179#endif
180}
181
182#endif // SDL_VIDEO_DRIVER_DUMMY
183