44
55#include < chrono>
66#include < csignal>
7+ #include < cstdlib>
78#include < cstdio>
89#include < cstring>
910#include < mutex>
@@ -38,6 +39,82 @@ const char* opt_rom = NULL;
3839int game_state = 0 ;
3940bool running = true ;
4041
42+ void ConfigureSDLVideoDriverForHeadlessLinux ()
43+ {
44+ #if defined(__linux__) && !defined(__ANDROID__)
45+ if (std::getenv (" SDL_VIDEODRIVER" ) == nullptr && std::getenv (" DISPLAY" ) == nullptr &&
46+ std::getenv (" WAYLAND_DISPLAY" ) == nullptr )
47+ {
48+ setenv (" SDL_VIDEODRIVER" , " kmsdrm" , 0 );
49+ }
50+ #endif
51+ }
52+
53+ bool ResolveWindowPositionForScreen (int screenIndex, int offsetX, int offsetY, int * pResolvedX, int * pResolvedY)
54+ {
55+ if (pResolvedX == nullptr || pResolvedY == nullptr )
56+ {
57+ return false ;
58+ }
59+
60+ if (screenIndex < 0 )
61+ {
62+ *pResolvedX = offsetX;
63+ *pResolvedY = offsetY;
64+ return true ;
65+ }
66+
67+ int numDisplays = 0 ;
68+ SDL_DisplayID* pDisplays = SDL_GetDisplays (&numDisplays);
69+ if (pDisplays == nullptr )
70+ {
71+ return false ;
72+ }
73+
74+ const bool validDisplay = screenIndex < numDisplays;
75+ SDL_DisplayID displayId = 0 ;
76+ if (validDisplay)
77+ {
78+ displayId = pDisplays[screenIndex];
79+ }
80+ SDL_free (pDisplays);
81+
82+ if (!validDisplay)
83+ {
84+ SDL_SetError (" Invalid screen index %d" , screenIndex);
85+ return false ;
86+ }
87+
88+ SDL_Rect displayBounds;
89+ if (!SDL_GetDisplayBounds (displayId, &displayBounds))
90+ {
91+ return false ;
92+ }
93+
94+ *pResolvedX = displayBounds.x + offsetX;
95+ *pResolvedY = displayBounds.y + offsetY;
96+ return true ;
97+ }
98+
99+ bool PositionWindowOnScreen (SDL_Window* pWindow, int screenIndex, int offsetX = 0 , int offsetY = 0 )
100+ {
101+ if (pWindow == nullptr || screenIndex < 0 )
102+ {
103+ return true ;
104+ }
105+
106+ int resolvedX = 0 ;
107+ int resolvedY = 0 ;
108+ if (!ResolveWindowPositionForScreen (screenIndex, offsetX, offsetY, &resolvedX, &resolvedY))
109+ {
110+ return false ;
111+ }
112+
113+ SDL_SetWindowPosition (pWindow, resolvedX, resolvedY);
114+ while (!SDL_SyncWindow (pWindow));
115+ return true ;
116+ }
117+
41118uint32_t currentThreadId = 0 ;
42119std::mutex threadMutex;
43120uint32_t disconnectOtherClients = 0 ;
@@ -105,6 +182,14 @@ static struct cag_option options[] = {
105182 .access_name = " virtual-dmd-screen" ,
106183 .value_name = " VALUE" ,
107184 .description = " Show virtual DMD on a specific screen" },
185+ {.identifier = ' T' ,
186+ .access_name = " virtual-dmd-x" ,
187+ .value_name = " VALUE" ,
188+ .description = " Virtual DMD x position relative to the selected screen" },
189+ {.identifier = ' U' ,
190+ .access_name = " virtual-dmd-y" ,
191+ .value_name = " VALUE" ,
192+ .description = " Virtual DMD y position relative to the selected screen" },
108193 {.identifier = ' S' ,
109194 .access_name = " virtual-dmd-scale" ,
110195 .value_name = NULL ,
@@ -189,6 +274,8 @@ int main(int argc, char* argv[])
189274 uint16_t opt_virtual_dmd_width = 1280 ;
190275 uint16_t opt_virtual_dmd_height = 320 ;
191276 int8_t opt_virtual_dmd_screen = -1 ;
277+ int opt_virtual_dmd_x = SDL_WINDOWPOS_UNDEFINED;
278+ int opt_virtual_dmd_y = SDL_WINDOWPOS_UNDEFINED;
192279 DMDUtil::SDLDMD* pVirtualDMD = nullptr ;
193280 uint32_t threadId = 0 ;
194281
@@ -247,6 +334,12 @@ int main(int argc, char* argv[])
247334 case ' R' :
248335 opt_virtual_dmd_screen = atoi (cag_option_get_value (&cag_context));
249336 break ;
337+ case ' T' :
338+ opt_virtual_dmd_x = atoi (cag_option_get_value (&cag_context));
339+ break ;
340+ case ' U' :
341+ opt_virtual_dmd_y = atoi (cag_option_get_value (&cag_context));
342+ break ;
250343 case ' S' :
251344 opt_virtual_dmd_scale = true ;
252345 break ;
@@ -275,11 +368,7 @@ int main(int argc, char* argv[])
275368
276369 if (opt_translite || opt_virtual_dmd)
277370 {
278- // Set the SDL video driver for Linux framebuffer
279- #ifdef __linux__
280- setenv (" SDL_VIDEODRIVER" , " KMSDRM" , 1 );
281- #endif
282-
371+ ConfigureSDLVideoDriverForHeadlessLinux ();
283372 if (!SDL_Init (SDL_INIT_VIDEO))
284373 {
285374 printf (" SDL_Init Error: %s\n " , SDL_GetError ());
@@ -297,8 +386,14 @@ int main(int argc, char* argv[])
297386 return SDL_APP_FAILURE;
298387 }
299388
300- SDL_SetWindowPosition (pTransliteWindow, 0 , 0 );
301- while (!SDL_SyncWindow (pTransliteWindow));
389+ if (!PositionWindowOnScreen (pTransliteWindow, opt_translite_screen))
390+ {
391+ printf (" Failed to position translite window: %s\n " , SDL_GetError ());
392+ SDL_DestroyRenderer (pTransliteRenderer);
393+ SDL_DestroyWindow (pTransliteWindow);
394+ SDL_Quit ();
395+ return 1 ;
396+ }
302397
303398 pTransliteTexture = IMG_LoadTexture (pTransliteRenderer, opt_translite);
304399 if (!pTransliteTexture)
@@ -361,7 +456,8 @@ int main(int argc, char* argv[])
361456 {
362457 pVirtualDMD = DMDUtil::CreateSDLDMD (*pDmd, " PPUC DMD" , opt_virtual_dmd_width, opt_virtual_dmd_height,
363458 opt_virtual_dmd_window ? SDL_WINDOW_BORDERLESS : SDL_WINDOW_FULLSCREEN,
364- opt_virtual_dmd_hd ? 256 : 128 , opt_virtual_dmd_hd ? 64 : 32 );
459+ opt_virtual_dmd_hd ? 256 : 128 , opt_virtual_dmd_hd ? 64 : 32 ,
460+ opt_virtual_dmd_screen, opt_virtual_dmd_x, opt_virtual_dmd_y);
365461
366462 if (!pVirtualDMD)
367463 {
0 commit comments