From 1242eddfb2959397d126041e19d29366532d6241 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Deuc=D0=B5?= <shurd@sasktel.net>
Date: Tue, 6 Jun 2023 18:56:22 -0400
Subject: [PATCH] Add fullscreen GDI startup mode.

---
 src/conio/ciolib.c      |   1 +
 src/conio/ciolib.h      |   1 +
 src/conio/win32gdi.c    | 111 ++++++++++++++++++++++++++++++----------
 src/syncterm/bbslist.c  |  15 +++---
 src/syncterm/syncterm.c |  42 +++++++++------
 5 files changed, 122 insertions(+), 48 deletions(-)

diff --git a/src/conio/ciolib.c b/src/conio/ciolib.c
index 220144ffb9..0deeb80471 100644
--- a/src/conio/ciolib.c
+++ b/src/conio/ciolib.c
@@ -521,6 +521,7 @@ CIOLIBEXPORT int initciolib(int mode)
 
 #if defined(WITH_GDI)
 		case CIOLIB_MODE_GDI:
+		case CIOLIB_MODE_GDI_FULLSCREEN:
 			try_gdi_init(mode);
 			break;
 #endif
diff --git a/src/conio/ciolib.h b/src/conio/ciolib.h
index 9e4e2d2fa5..3a80614ae8 100644
--- a/src/conio/ciolib.h
+++ b/src/conio/ciolib.h
@@ -80,6 +80,7 @@ enum {
 	,CIOLIB_MODE_SDL
 	,CIOLIB_MODE_SDL_FULLSCREEN
 	,CIOLIB_MODE_GDI
+	,CIOLIB_MODE_GDI_FULLSCREEN
 };
 
 enum ciolib_mouse_ptr {
diff --git a/src/conio/win32gdi.c b/src/conio/win32gdi.c
index fb27ce6e53..7b5b5d216a 100644
--- a/src/conio/win32gdi.c
+++ b/src/conio/win32gdi.c
@@ -19,6 +19,7 @@ static bool maximized = false;
 static uint16_t winxpos, winypos;
 static const DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_VISIBLE;
 static const DWORD fs_style = WS_POPUP | WS_VISIBLE;
+#define STYLE (fullscreen ? fs_style : style)
 static HCURSOR cursor;
 static HANDLE init_sem;
 static int xoff, yoff;
@@ -66,6 +67,8 @@ static pthread_mutex_t stypelock;
 
 // Internal implementation
 
+static bool get_monitor_size_pos(int *w, int *h, int *xpos, int *ypos);
+
 static LPWSTR
 utf8_to_utf16(const uint8_t *str8, int buflen)
 {
@@ -181,7 +184,9 @@ UnadjustWindowSize(int *w, int *h)
 	RECT r = {0};
 	bool ret;
 
-	ret = AdjustWindowRect(&r, style, FALSE);
+	if (fullscreen)
+		return true;
+	ret = AdjustWindowRect(&r, STYLE, FALSE);
 	if (ret) {
 		*w += r.left - r.right;
 		*h += r.top - r.bottom;
@@ -482,17 +487,42 @@ gdi_handle_activate(HWND hwnd, WPARAM wParam)
 }
 
 static bool
-gdi_get_monitor_size(int *w, int *h)
+get_monitor_size_pos(int *w, int *h, int *xpos, int *ypos)
 {
+	bool primary = false;
+	bool ret = false;
 	HMONITOR mon;
 	MONITORINFO mi;
-	bool ret;
 
-	mon = MonitorFromWindow(win, MONITOR_DEFAULTTOPRIMARY);
-	mi.cbSize = sizeof(mi);
-	ret = GetMonitorInfoW(mon, &mi);
-	*w = mi.rcWork.right - mi.rcWork.left;
-	*h = mi.rcWork.bottom - mi.rcWork.top;
+	if (!primary && win == NULL)
+		primary = true;
+	mon = MonitorFromWindow(win, primary ? MONITOR_DEFAULTTOPRIMARY : MONITOR_DEFAULTTONEAREST);
+	if (mon) {
+		mi.cbSize = sizeof(mi);
+		ret = GetMonitorInfoW(mon, &mi);
+		if (ret) {
+			if (fullscreen) {
+				if (w)
+					*w = mi.rcMonitor.right - mi.rcMonitor.left;
+				if (h)
+					*h = mi.rcMonitor.bottom - mi.rcMonitor.top;
+				if (xpos)
+					*xpos = mi.rcMonitor.left;
+				if (ypos)
+					*ypos = mi.rcMonitor.top;
+			}
+			else {
+				if (w)
+					*w = mi.rcWork.right - mi.rcWork.left;
+				if (h)
+					*h = mi.rcWork.bottom - mi.rcWork.top;
+				if (xpos)
+					*xpos = mi.rcWork.left;
+				if (ypos)
+						*ypos = mi.rcWork.top;
+			}
+		}
+	}
 	return ret;
 }
 
@@ -505,7 +535,7 @@ handle_wm_getminmaxinfo(MINMAXINFO *inf)
 	double mult;
 	RECT r;
 
-	gdi_get_monitor_size(&monw, &monh);
+	get_monitor_size_pos(&monw, &monh, NULL, NULL);
 	maxw = monw;
 	maxh = monh;
 	UnadjustWindowSize(&maxw, &maxh);
@@ -519,7 +549,7 @@ handle_wm_getminmaxinfo(MINMAXINFO *inf)
 	r.left = 0;
 	r.right = maxw;
 	r.bottom = maxh;
-	AdjustWindowRect(&r, style, FALSE);
+	AdjustWindowRect(&r, STYLE, FALSE);
 	inf->ptMaxTrackSize.x = r.right - r.left;
 	inf->ptMaxTrackSize.y = r.bottom - r.top;
 	inf->ptMaxSize.x = inf->ptMaxTrackSize.x;
@@ -531,7 +561,7 @@ handle_wm_getminmaxinfo(MINMAXINFO *inf)
 	r.left = 0;
 	r.right = minw;
 	r.bottom = minh;
-	AdjustWindowRect(&r, style, FALSE);
+	AdjustWindowRect(&r, STYLE, FALSE);
 	inf->ptMinTrackSize.x = r.right - r.left;
 	inf->ptMinTrackSize.y = r.bottom - r.top;
 
@@ -609,8 +639,7 @@ gdi_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
 			r.right = wParam;
 			r.bottom = lParam;
 			pthread_mutex_unlock(&vstatlock);
-			if (!fullscreen)
-				AdjustWindowRect(&r, style, FALSE);
+			AdjustWindowRect(&r, STYLE, FALSE);
 			SetWindowPos(win, NULL, 0, 0, r.right - r.left, r.bottom - r.top, SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER);
 			return true;
 		case WM_USER_SETPOS:
@@ -628,7 +657,7 @@ gdi_snap(bool grow)
 
 	if (maximized || fullscreen)
 		return;
-	gdi_get_monitor_size(&mw, &mh);
+	get_monitor_size_pos(&mw, &mh, NULL, NULL);
 	UnadjustWindowSize(&mw, &mh);
 	pthread_mutex_lock(&vstatlock);
 	bitmap_snap(grow, mw, mh);
@@ -642,7 +671,7 @@ gdi_snap(bool grow)
 #define WMOD_SHIFT    8
 #define WMOD_LSHIFT  16
 #define WMOD_RSHIFT  32
-bool
+static bool
 magic_message(MSG msg)
 {
 	static uint8_t mods = 0;
@@ -716,7 +745,7 @@ magic_message(MSG msg)
 											pthread_mutex_lock(&vstatlock);
 											window_scaling = vstat.scaling;
 											pthread_mutex_unlock(&vstatlock);
-											SetWindowLongPtr(win, GWL_STYLE, fs_style);
+											SetWindowLongPtr(win, GWL_STYLE, STYLE);
 											PostMessageW(win, WM_USER_SETPOS, mi.rcMonitor.left, mi.rcMonitor.top);
 											PostMessageW(win, WM_USER_SETSIZE, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top);
 										}
@@ -730,7 +759,7 @@ magic_message(MSG msg)
 									int w, h;
 
 									bitmap_get_scaled_win_size(window_scaling, &w, &h, 0, 0);
-									SetWindowLongPtr(win, GWL_STYLE, style);
+									SetWindowLongPtr(win, GWL_STYLE, STYLE);
 									PostMessageW(win, WM_USER_SETSIZE, w, h);
 									PostMessageW(win, WM_USER_SETPOS, window_left, window_top);
 								}
@@ -773,9 +802,14 @@ gdi_thread(void *arg)
 	MSG  msg;
 	RECT r;
 	ATOM cl;
+	int wx = CW_USEDEFAULT;
+	int wy = CW_USEDEFAULT;
+	int mode = (int)arg;
 
 	SetThreadName("GDI Events");
 
+	if (mode == CIOLIB_MODE_GDI_FULLSCREEN)
+		fullscreen = true;
 	wc.style = CS_HREDRAW | CS_VREDRAW;
 	wc.lpfnWndProc   = gdi_WndProc;
 	// This is actually required or the link will fail (it can be overwritten though)
@@ -797,6 +831,13 @@ gdi_thread(void *arg)
 	pthread_mutex_lock(&vstatlock);
 	if (ciolib_initial_scaling != 0) {
 		bitmap_get_scaled_win_size(ciolib_initial_scaling, &vstat.winwidth, &vstat.winheight, 0, 0);
+		vstat.scaling = ciolib_initial_scaling;
+	}
+	if (fullscreen) {
+		if (get_monitor_size_pos(&vstat.winwidth, &vstat.winheight, &wx, &wy))
+			vstat.scaling = bitmap_double_mult_inside(vstat.winwidth, vstat.winheight);
+		else
+			fullscreen = false;
 	}
 	stype = ciolib_initial_scaling_type;
 	// Now make the inside of the window the size we want (sigh)
@@ -804,12 +845,16 @@ gdi_thread(void *arg)
 	r.right = vstat.winwidth;
 	r.bottom = vstat.winheight;
 	pthread_mutex_unlock(&vstatlock);
-	AdjustWindowRect(&r, style, FALSE);
-	win = CreateWindowW(wc.lpszClassName, L"SyncConsole", style, CW_USEDEFAULT, SW_SHOWNORMAL, r.right - r.left, r.bottom - r.top, NULL, NULL, NULL, NULL);
+	AdjustWindowRect(&r, STYLE, FALSE);
+	win = CreateWindowW(wc.lpszClassName, L"SyncConsole", STYLE, wx, wy, r.right - r.left, r.bottom - r.top, NULL, NULL, NULL, NULL);
 	if (win == NULL)
 		goto fail;
 	// No failing after this...
 	init_success = true;
+	if (fullscreen)
+		cio_api.mode = CIOLIB_MODE_GDI_FULLSCREEN;
+	else
+		cio_api.mode = CIOLIB_MODE_GDI;
 	ReleaseSemaphore(init_sem, 1, NULL);
 
 	while (GetMessage(&msg, NULL, 0, 0)) {
@@ -875,9 +920,13 @@ gdi_textmode(int mode)
 	}
 
 	pthread_mutex_lock(&vstatlock);
-	gdi_get_monitor_size(&mw, &mh);
+	get_monitor_size_pos(&mw, &mh, NULL, NULL);
 	UnadjustWindowSize(&mw, &mh);
 	bitmap_drv_init_mode(mode, NULL, NULL, mw, mh);
+	if (fullscreen) {
+		vstat.winwidth = mw;
+		vstat.winheight = mh;
+	}
 	gdi_setwinsize(vstat.winwidth, vstat.winheight);
 	pthread_mutex_unlock(&vstatlock);
 	bitmap_drv_request_pixels();
@@ -1067,11 +1116,11 @@ gdi_init(int mode)
 	else if (SetProcessDPIAware) {
 		SetProcessDPIAware();
 	}
-	_beginthread(gdi_mouse_thread, 0, NULL);
-	_beginthread(gdi_thread, 0, NULL);
+	_beginthread(gdi_thread, 0, (void *)(intptr_t)mode);
 	WaitForSingleObject(init_sem, INFINITE);
 	CloseHandle(init_sem);
 	if (init_success) {
+		_beginthread(gdi_mouse_thread, 0, NULL);
 		gdi_textmode(ciolib_initial_mode);
 
 		cio_api.mode=CIOLIB_MODE_GDI;
@@ -1158,7 +1207,10 @@ gdi_setwinposition(int x, int y)
 void
 gdi_setwinsize(int w, int h)
 {
-	PostMessageW(win, WM_USER_SETSIZE, w, h);
+	if (fullscreen)
+		window_scaling = bitmap_double_mult_inside(w, h);
+	else
+		PostMessageW(win, WM_USER_SETSIZE, w, h);
 }
 
 double
@@ -1177,10 +1229,15 @@ gdi_setscaling(double newval)
 {
 	int w, h;
 
-	pthread_mutex_lock(&vstatlock);
-	bitmap_get_scaled_win_size(newval, &w, &h, 0, 0);
-	pthread_mutex_unlock(&vstatlock);
-	gdi_setwinsize(w, h);
+	if (fullscreen) {
+		window_scaling = newval;
+	}
+	else {
+		pthread_mutex_lock(&vstatlock);
+		bitmap_get_scaled_win_size(newval, &w, &h, 0, 0);
+		pthread_mutex_unlock(&vstatlock);
+		gdi_setwinsize(w, h);
+	}
 }
 
 enum ciolib_scaling
diff --git a/src/syncterm/bbslist.c b/src/syncterm/bbslist.c
index 830c8db17c..8f3877644e 100644
--- a/src/syncterm/bbslist.c
+++ b/src/syncterm/bbslist.c
@@ -1911,7 +1911,7 @@ change_settings(int connected)
 #ifdef __unix__
 				    "~ Curses ~\n"
 				    "        Use text output using the Curses library.  This mode should work\n"
-				    "        from any terminal, however, high and low ASCII will not work\n"
+				    "        from any terminal, however, high and low ASCII may not work\n"
 				    "        correctly.\n\n"
 				    "~ Curses on cp437 Device ~\n"
 				    "        As above, but assumes that the current terminal is configured to\n"
@@ -1925,8 +1925,7 @@ change_settings(int connected)
 #if defined(__unix__) && !defined(NO_X)
 				    "~ X11 ~\n"
 				    "        Uses the Xlib library directly for graphical output.  This is\n"
-				    "        the graphical mode most likely to work when using X11.  This\n"
-				    "        mode supports font changes.\n\n"
+				    "        the graphical mode most likely to work when using X11.\n\n"
 				    "~ X11 Fullscreen ~\n"
 				    "        As above, but starts in full-screen mode rather than a window\n\n"
 #endif
@@ -1936,15 +1935,19 @@ change_settings(int connected)
 				    "        affect the look of the output and some low ASCII characters are\n"
 				    "        not displayable.  When in a window, blinking text is displayed\n"
 				    "        with a high-intensity background rather than blinking.  In\n"
-				    "        full-screen mode, blinking works correctly.\n\n"
+				    "        full-screen mode (where available), blinking works correctly.\n\n"
 #endif
 #if defined(WITH_SDL) || defined(WITH_SDL_AUDIO)
 				    "~ SDL ~\n"
 				    "        Makes use of the SDL graphics library for graphical output.\n"
-				    "        This output mode allows switching to full-screen mode but is\n"
-				    "        otherwise identical to X11 mode.\n\n"
 				    "~ SDL Fullscreen ~\n"
 				    "        As above, but starts in full-screen mode rather than a window\n\n"
+#endif
+#if defined(WITH_GDI)
+				    "~ GDI ~\n"
+				    "        Native Windows graphics library for graphical output.\n"
+				    "~ GDI Fullscreen ~\n"
+				    "        As above, but starts in full-screen mode rather than a window\n\n"
 #endif
 				;
 				switch (i = uifc.list(WIN_SAV, 0, 0, 0, &j, NULL, "Video Output Mode", output_types)) {
diff --git a/src/syncterm/syncterm.c b/src/syncterm/syncterm.c
index fc4cf96992..f8b548fe01 100644
--- a/src/syncterm/syncterm.c
+++ b/src/syncterm/syncterm.c
@@ -101,17 +101,18 @@ char *usage =
     "-e# =  set escape delay to #msec\n"
     "-h  =  use SSH mode if URL does not include the scheme\n"
     "-iX =  set interface mode to X (default=auto) where X is one of:\n"
-    "       S[W|F] = SDL surface mode W for windowed and F for fullscreen\n"
+    "       A = ANSI mode\n"
 #ifdef __unix__
-    "       X[W|F] = X11 mode W for windowed and F for fullscreen\n"
     "       C = Curses mode\n"
-    "       I = Curses mode with forced ASCII charset\n"
     "       F = Curses mode with forced IBM charset\n"
+    "       I = Curses mode with forced ASCII charset\n"
+    "       S[W|F] = SDL surface mode W for windowed and F for fullscreen\n"
+    "       X[W|F] = X11 mode W for windowed and F for fullscreen\n"
 #else
+    "       G[W|F] = Win32 GDI (graphics) mode W for windowed and F for fullscreen\n"
+    "       S[W|F] = SDL surface mode W for windowed and F for fullscreen\n"
     "       W = Win32 console (text) mode\n"
-    "       G = Win32 GDI (graphics) mode\n"
 #endif
-    "       A = ANSI mode\n"
     "-l# =  set screen lines to # (default=auto-detect)\n"
     "-n/path/to/ini = specify a config ini path\n"
     "-q  =  Quiet mode (Hide various popups such as this during a connect)\n"
@@ -771,15 +772,16 @@ char *output_types[] = {
 #endif
 #if defined(WITH_GDI)
 	, "GDI"
+	, "GDI Fullscreen"
 #endif
 	, NULL
 };
 int   output_map[] = {
 	CIOLIB_MODE_AUTO
 #ifdef __unix__
-	, CIOLIB_MODE_CURSES,
-	CIOLIB_MODE_CURSES_IBM,
-	CIOLIB_MODE_CURSES_ASCII
+	, CIOLIB_MODE_CURSES
+	, CIOLIB_MODE_CURSES_IBM
+	, CIOLIB_MODE_CURSES_ASCII
 #endif
 	, CIOLIB_MODE_ANSI
 #if defined(__unix__) && !defined(NO_X)
@@ -787,16 +789,16 @@ int   output_map[] = {
 	, CIOLIB_MODE_X_FULLSCREEN
 #endif
 #ifdef _WIN32
-	, CIOLIB_MODE_CONIO,
-	CIOLIB_MODE_CONIO_FULLSCREEN
+	, CIOLIB_MODE_CONIO
+	, CIOLIB_MODE_CONIO_FULLSCREEN
 #endif
 #if defined(WITH_SDL) || defined(WITH_SDL_AUDIO)
-	, CIOLIB_MODE_SDL,
-	CIOLIB_MODE_SDL_FULLSCREEN
+	, CIOLIB_MODE_SDL
+	, CIOLIB_MODE_SDL_FULLSCREEN
 #endif
 #ifdef WITH_GDI
-	, CIOLIB_MODE_GDI,
-	CIOLIB_MODE_GDI
+	, CIOLIB_MODE_GDI
+	, CIOLIB_MODE_GDI_FULLSCREEN
 #endif
 	, 0
 };
@@ -813,6 +815,7 @@ char *output_descrs[] = {
 	"SDL",
 	"SDL Fullscreen",
 	"GDI",
+	"GDI Fullscreen",
 	NULL
 };
 
@@ -829,6 +832,7 @@ char *output_enum[] = {
 	"SDL",
 	"SDLFullscreen",
 	"GDI",
+	"GDIFullscreen",
 	NULL
 };
 
@@ -1626,7 +1630,15 @@ main(int argc, char **argv)
 							ciolib_mode = CIOLIB_MODE_CURSES_IBM;
 							break;
 						case 'G':
-							ciolib_mode = CIOLIB_MODE_GDI;
+							switch (toupper(argv[i][3])) {
+								case 0:
+								case 'W':
+									ciolib_mode = CIOLIB_MODE_GDI;
+									break;
+								case 'F':
+									ciolib_mode = CIOLIB_MODE_GDI_FULLSCREEN;
+									break;
+							}
 							break;
 						case 'I':
 							ciolib_mode = CIOLIB_MODE_CURSES_ASCII;
-- 
GitLab