SDL-1.2: atari:video:gem: center fullscreen surfaces smaller than the desktop

From dea2aaaa543c1416574cd76bc6fcb2096dd0b3aa Mon Sep 17 00:00:00 2001
From: Miro Kropacek <[EMAIL REDACTED]>
Date: Thu, 24 Sep 2026 11:32:40 +1000
Subject: [PATCH] atari:video:gem: center fullscreen surfaces smaller than the
 desktop

Such a surface used to be drawn in the top left corner. Fullscreen mode
also gets the input focus now, the AES sends no WM_TOPPED for it.
---
 src/video/gem/SDL_gemevents.c |  8 ++++++
 src/video/gem/SDL_gemvideo.c  | 53 ++++++++++++++++++++++++++++-------
 2 files changed, 51 insertions(+), 10 deletions(-)

diff --git a/src/video/gem/SDL_gemevents.c b/src/video/gem/SDL_gemevents.c
index 00e8a6aa..37e324ab 100644
--- a/src/video/gem/SDL_gemevents.c
+++ b/src/video/gem/SDL_gemevents.c
@@ -380,6 +380,14 @@ static void do_mouse_motion(_THIS, short mx, short my)
 		y2 = GEM_work.g_y;
 		w2 = GEM_work.g_w;
 		h2 = GEM_work.g_h;
+	} else if (GEM_fullscreen && this->screen) {
+		/* A fullscreen surface smaller than the screen is centered, report
+		 * coordinates relative to it and not to the screen
+		 */
+		x2 = this->offset_x;
+		y2 = this->offset_y;
+		w2 = this->screen->w;
+		h2 = this->screen->h;
 	}
 
 	if (GEM_MouseGrabbed(this)) {
diff --git a/src/video/gem/SDL_gemvideo.c b/src/video/gem/SDL_gemvideo.c
index 2d14819b..9459ef98 100644
--- a/src/video/gem/SDL_gemvideo.c
+++ b/src/video/gem/SDL_gemvideo.c
@@ -189,6 +189,11 @@ static SDL_VideoDevice *GEM_CreateDevice(int devindex)
 	device->FreeHWSurface = GEM_FreeHWSurface;
 	device->ToggleFullScreen = NULL;
 
+	/* A fullscreen surface smaller than the desktop is supported, it is
+	 * placed inside a screen sized surface by SDL_SetVideoMode()
+	 */
+	device->handles_any_size = 1;
+
 	/* Window manager */
 	device->SetCaption = GEM_SetCaption;
 	device->SetIcon = GEM_SetIcon;
@@ -667,6 +672,12 @@ static SDL_Surface *GEM_SetVideoMode(_THIS, SDL_Surface *current,
 			SDL_SetError("%dx%d mode is too large", width, height);
 			return(NULL);
 		}
+
+		/* Hand back a screen sized surface, SDL_SetVideoMode() shrinks it to
+		 * the asked dimensions and centers it using surface->offset
+		 */
+		width = VDI_w;
+		height = VDI_h;
 	}
 
 	/*--- Allocate the new pixel format for the screen ---*/
@@ -744,6 +755,11 @@ static SDL_Surface *GEM_SetVideoMode(_THIS, SDL_Surface *current,
 		}
 
 		GEM_fullscreen = SDL_TRUE;
+
+		/* We own the screen, so we own the input as well: the AES sends
+		 * no WM_TOPPED to tell us so
+		 */
+		SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
 	} else {
 		int old_win_type;
 		GRECT gr;
@@ -838,6 +854,9 @@ static SDL_Surface *GEM_SetVideoMode(_THIS, SDL_Surface *current,
 	/* Set up the new mode framebuffer */
 	current->w = width;
 	current->h = height;
+	current->offset = 0;
+	this->offset_x = 0;
+	this->offset_y = 0;
 	if (use_shadow1) {
 		current->pixels = GEM_buffer1;
 		current->pitch = width * VDI_pixelsize;
@@ -934,15 +953,18 @@ static void GEM_UpdateRectsFullscreen(_THIS, int numrects, SDL_Rect *rects)
 		short blitcoords[8];
 		int surf_width;
 
+		/* The buffer covers the whole screen, the rectangles are given in
+		 * screen coordinates
+		 */
 		/* Need to be a multiple of 16 pixels */
-		surf_width=surface->w;
+		surf_width=VDI_w;
 		if ((surf_width & 15) != 0) {
 			surf_width = (surf_width | 15) + 1;
 		}
 
 		mfdb_src.fd_addr=surface->pixels;
 		mfdb_src.fd_w=surf_width;
-		mfdb_src.fd_h=surface->h;
+		mfdb_src.fd_h=VDI_h;
 		mfdb_src.fd_wdwidth= (surface->pitch/VDI_pixelsize) >> 4;
 		mfdb_src.fd_nplanes=surface->format->BitsPerPixel;
 		mfdb_src.fd_stand=
@@ -1000,8 +1022,11 @@ static int GEM_FlipHWSurfaceFullscreen(_THIS, SDL_Surface *surface)
 {
 	int surf_width;
 
+	/* The buffer covers the whole screen and the surface is centered inside
+	 * it, so source and destination share the same coordinates
+	 */
 	/* Need to be a multiple of 16 pixels */
-	surf_width=surface->w;
+	surf_width=VDI_w;
 	if ((surf_width & 15) != 0) {
 		surf_width = (surf_width | 15) + 1;
 	}
@@ -1009,6 +1034,7 @@ static int GEM_FlipHWSurfaceFullscreen(_THIS, SDL_Surface *surface)
 	if (GEM_bufops & (B2S_C2P_1TO2|B2S_C2P_1TOS)) {
 		void *destscr;
 		int destpitch;
+		int x1,x2;
 
 		if (GEM_bufops & B2S_C2P_1TOS) {
 			destscr = VDI_screen;
@@ -1018,10 +1044,17 @@ static int GEM_FlipHWSurfaceFullscreen(_THIS, SDL_Surface *surface)
 			destpitch = surface->pitch;
 		}
 
+		/* c2p writes whole groups of 16 pixels */
+		x1 = this->offset_x & ~15;
+		x2 = this->offset_x + surface->w;
+		if (x2 & 15) {
+			x2 = (x2 | 15) +1;
+		}
+
 		SDL_Atari_C2pConvert(
 			surface->pixels, destscr,
-			0, 0,
-			surf_width, surface->h,
+			x1, this->offset_y,
+			x2-x1, surface->h,
 			SDL_FALSE, 8,
 			surface->pitch, destpitch
 		);
@@ -1032,7 +1065,7 @@ static int GEM_FlipHWSurfaceFullscreen(_THIS, SDL_Surface *surface)
 		short blitcoords[8];
 
 		mfdb_src.fd_w=surf_width;
-		mfdb_src.fd_h=surface->h;
+		mfdb_src.fd_h=VDI_h;
 		mfdb_src.fd_wdwidth=mfdb_src.fd_w >> 4;
 		mfdb_src.fd_nplanes=surface->format->BitsPerPixel;
 		mfdb_src.fd_stand=
@@ -1045,10 +1078,10 @@ static int GEM_FlipHWSurfaceFullscreen(_THIS, SDL_Surface *surface)
 			mfdb_src.fd_addr=GEM_buffer2;
 		}
 
-		blitcoords[0] = blitcoords[4] = 0;
-		blitcoords[1] = blitcoords[5] = 0;
-		blitcoords[2] = blitcoords[6] = surface->w - 1;
-		blitcoords[3] = blitcoords[7] = surface->h - 1;
+		blitcoords[0] = blitcoords[4] = this->offset_x;
+		blitcoords[1] = blitcoords[5] = this->offset_y;
+		blitcoords[2] = blitcoords[6] = this->offset_x + surface->w - 1;
+		blitcoords[3] = blitcoords[7] = this->offset_y + surface->h - 1;
 
 		vro_cpyfm(VDI_handle, S_ONLY, blitcoords, &mfdb_src, &VDI_dst_mfdb);
 	}