Skip to content
Snippets Groups Projects
Commit 42f906f9 authored by Deucе's avatar Deucе :ok_hand_tone4:
Browse files

Default to building with GDI

Add setwinsize and setwinpos
Move blit from rect into gdi_thread
Add beep support
Add (non-functional) settitle support
Support ciolib scaling in addition to GDI scaling
Add window-size snapping
Support -iG in SyncTERM

GDI is still the second-least preferred mode, so auto mode will only
use it if the windows console somehow fails.  But at least people
can play with it.
parent 62e2280e
No related branches found
No related tags found
1 merge request!463MRC mods by Codefenix (2024-10-20)
Pipeline #4152 passed
......@@ -63,7 +63,7 @@ ifneq ($(os),win32)
else
NO_X := 1
CIOLIB-MT_CFLAGS += -DDISABLE_X11=1
ifdef WITH_GDI
ifndef WITHOUT_GDI
CIOLIB-MT_LIBS += -lgdi32
CIOLIB-MT_CFLAGS += -DWITH_GDI
endif
......
......@@ -5,7 +5,7 @@ include $(SRC_ROOT)/build/Common.gmake # defines clean and output directory rule
CFLAGS += $(XPDEV-MT_CFLAGS) $(HASH_CFLAGS) $(ENCODE_CFLAGS) $(CIOLIB-MT_CFLAGS)
ifeq ($(os),win32)
ifdef WITH_GDI
ifndef WITHOUT_GDI
OBJS += $(MTOBJODIR)$(DIRSEP)win32gdi$(OFILE)
endif
OBJS += $(MTOBJODIR)$(DIRSEP)SDL_win32_main$(OFILE)
......
......@@ -177,9 +177,6 @@ static int try_gdi_init(int mode)
cio_api.kbhit=gdi_kbhit;
cio_api.getch=gdi_getch;
cio_api.textmode=gdi_textmode;
cio_api.showmouse=gdi_showmouse;
cio_api.hidemouse=gdi_hidemouse;
cio_api.setname=gdi_setname;
cio_api.seticon=gdi_seticon;
cio_api.settitle=gdi_settitle;
cio_api.copytext=gdi_copytext;
......@@ -459,9 +456,6 @@ CIOLIBEXPORT int initciolib(int mode)
#ifndef NO_X
if(!try_x_init(mode))
#endif
#if defined(WITH_GDI)
if (!try_gdi_init(mode))
#endif
#if defined(WITH_SDL)
if(!try_sdl_init(CIOLIB_MODE_SDL))
#endif
......@@ -470,7 +464,10 @@ CIOLIBEXPORT int initciolib(int mode)
#else
if(!try_curses_init(mode))
#endif
try_ansi_init(mode);
#if defined(WITH_GDI)
if (!try_gdi_init(mode))
#endif
try_ansi_init(mode);
break;
#ifdef _WIN32
case CIOLIB_MODE_CONIO:
......@@ -500,6 +497,12 @@ CIOLIBEXPORT int initciolib(int mode)
try_sdl_init(mode);
break;
#endif
#if defined(WITH_GDI)
case CIOLIB_MODE_GDI:
try_gdi_init(mode);
break;
#endif
}
if(cio_api.mode==CIOLIB_MODE_AUTO) {
fprintf(stderr,"CIOLIB initialization failed!\n");
......
......@@ -212,6 +212,19 @@ release_buffer(struct graphics_buffer *buf)
free_list = buf;
}
void
calc_scaling_factors(int *x, int *y, int winwidth, int winheight, int aspect_width, int aspect_height, int scrnwidth, int scrnheight)
{
aspect_fix_low(&winwidth, &winheight, aspect_width, aspect_height);
aspect_reverse(&winwidth, &winheight, scrnwidth, scrnheight, aspect_width, aspect_height);
*x = winwidth / scrnwidth;
*y = winheight / scrnheight;
if (*x < 1 || *x > 14)
*x = 1;
if (*y < 1 || *y > 14)
*y = 1;
}
struct graphics_buffer *
do_scale(struct rectlist* rect, int xscale, int yscale, int aspect_width, int aspect_height)
{
......
......@@ -20,3 +20,4 @@ void aspect_correct(int *x, int *y, int aspect_width, int aspect_height);
void aspect_reverse(int *x, int *y, int scrnwidth, int scrnheight, int aspect_width, int aspect_height);
void aspect_fix(int *x, int *y, int aspect_width, int aspect_height);
void aspect_fix_low(int *x, int *y, int aspect_width, int aspect_height);
void calc_scaling_factors(int *x, int *y, int winwidth, int winheight, int aspect_width, int aspect_height, int scrnwidth, int scrnheight);
......@@ -352,16 +352,7 @@ window_can_scale_internally(struct video_stats *vs)
static void
internal_scaling_factors(int *x, int *y, struct video_stats *vs)
{
int winwidth = vs->winwidth;
int winheight = vs->winheight;
aspect_fix_low(&winwidth, &winheight, vs->aspect_width, vs->aspect_height);
aspect_reverse(&winwidth, &winheight, vs->scrnwidth, vs->scrnheight, vs->aspect_width, vs->aspect_height);
*x = winwidth / vs->scrnwidth;
*y = winheight / vs->scrnheight;
if (*x < 1 || *x > 14)
*x = 1;
if (*y < 1 || *y > 14)
*y = 1;
calc_scaling_factors(x, y, vs->winwidth, vs->winheight, vs->aspect_width, vs->aspect_height, vs->scrnwidth, vs->scrnheight);
}
static int sdl_init_mode(int mode)
......
#include <windows.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
......@@ -11,8 +13,10 @@
static HWND win;
static HANDLE rch;
static HANDLE wch;
static bool maximized = false;
static uint8_t *title;
static uint16_t winxpos, winypos;
static const DWORD style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
#define WM_USER_INVALIDATE WM_USER
#define WM_USER_SETSIZE (WM_USER + 1)
......@@ -42,7 +46,9 @@ static struct rectlist *update_list_tail = NULL;
static struct rectlist *last = NULL;
static struct rectlist *next = NULL;
static pthread_mutex_t gdi_headlock;
static pthread_mutex_t winpos_lock;
static pthread_mutex_t rect_lock;
static bool ciolib_scaling = false;
// Internal implementation
......@@ -50,6 +56,7 @@ static struct rectlist *
get_rect(void)
{
struct rectlist *ret;
pthread_mutex_lock(&rect_lock);
if (next != NULL) {
if (last != NULL)
......@@ -104,69 +111,246 @@ sp_to_codepoint(uint16_t high, uint16_t low)
return (high - 0xd800) * 0x400 + (low - 0xdc00) + 0x10000;
}
static LRESULT CALLBACK
gdi_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
// vstatlock must be held
static void
set_ciolib_scaling(void)
{
int w, h;
int fw, fh;
w = vstat.winwidth;
h = vstat.winheight;
aspect_fix_low(&w, &h, vstat.aspect_width, vstat.aspect_height);
fw = w;
fh = h;
aspect_reverse(&w, &h, vstat.scrnwidth, vstat.scrnheight, vstat.aspect_width, vstat.aspect_height);
if ((fw == w) || (fh == h)) {
if (fw > vstat.winwidth || fh > vstat.winheight)
ciolib_scaling = false;
else
ciolib_scaling = true;
}
else
ciolib_scaling = false;
}
static bool
UnadjustWindowSize(int *w, int *h)
{
RECT r = {0};
bool ret;
ret = AdjustWindowRect(&r, style, FALSE);
if (ret) {
w += r.left - r.right;
h += r.top - r.bottom;
}
return ret;
}
static LRESULT
gdi_handle_wm_size(WPARAM wParam, LPARAM lParam)
{
RECT r;
int w, h;
switch (wParam) {
case SIZE_MAXIMIZED:
maximized = true;
break;
case SIZE_MINIMIZED:
case SIZE_RESTORED:
maximized = false;
break;
}
if (wParam == SIZE_MINIMIZED)
return 0;
w = lParam & 0xffff;
h = (lParam >> 16) & 0xffff;
UnadjustWindowSize(&w, &h);
pthread_mutex_lock(&vstatlock);
vstat.winwidth = w;
vstat.winheight = h;
set_ciolib_scaling();
pthread_mutex_unlock(&vstatlock);
return 0;
}
static LRESULT
gdi_handle_wm_paint(HWND hwnd)
{
static HDC memDC = NULL;
PAINTSTRUCT ps;
struct rectlist *list;
HBITMAP di;
static HDC memDC = NULL;
WPARAM highpair;
HDC winDC;
int w,h;
int aw,ah;
int sw,sh;
int xscale, yscale;
struct graphics_buffer *gb;
void *data;
list = get_rect();
if (list == NULL)
return 0;
pthread_mutex_lock(&vstatlock);
w = vstat.winwidth;
h = vstat.winheight;
aw = vstat.aspect_width;
ah = vstat.aspect_height;
sw = vstat.scrnwidth;
sh = vstat.scrnheight;
pthread_mutex_unlock(&vstatlock);
if (ciolib_scaling) {
calc_scaling_factors(&xscale, &yscale, w, h, aw, ah, sw, sh);
gb = do_scale(list, xscale, yscale, aw, ah);
b5hdr.bV5Width = gb->w;
b5hdr.bV5Height = -gb->h;
b5hdr.bV5SizeImage = gb->w * gb->h * 4;
data = gb->data;
}
else {
b5hdr.bV5Width = list->rect.width;
b5hdr.bV5Height = -list->rect.height;
b5hdr.bV5SizeImage = list->rect.width * list->rect.height * 4;
data = list->data;
}
winDC = BeginPaint(hwnd, &ps);
if (memDC == NULL)
memDC = CreateCompatibleDC(winDC);
// Scale...
di = CreateDIBitmap(winDC, (BITMAPINFOHEADER *)&b5hdr, CBM_INIT, data, (BITMAPINFO *)&b5hdr, 0/*DIB_RGB_COLORS*/);
di = SelectObject(memDC, di);
if (ciolib_scaling) {
BitBlt(winDC, 0, 0, w, h, memDC, 0, 0, SRCCOPY);
}
else {
StretchBlt(winDC, 0, 0, w, h, memDC, 0, 0, list->rect.width, list->rect.height, SRCCOPY);
}
EndPaint(hwnd, &ps);
di = SelectObject(memDC, di);
DeleteObject(di);
if (ciolib_scaling) {
release_buffer(gb);
}
return 0;
}
static LRESULT
gdi_handle_wm_char(WPARAM wParam, LPARAM lParam)
{
static WPARAM highpair;
uint32_t cp;
uint8_t ch;
uint16_t repeat;
uint16_t i;
bool alt;
HDC winDC;
struct rectlist *list;
int w,h;
repeat = lParam & 0xffff;
alt = lParam & (1 << 29);
if (IS_HIGH_SURROGATE(wParam)) {
highpair = wParam;
return 0;
}
else if (IS_LOW_SURROGATE(wParam)) {
cp = sp_to_codepoint(highpair, wParam);
}
else {
cp = wParam;
}
// Translate from unicode to codepage...
ch = cpchar_from_unicode_cpoint(getcodepage(), cp, 0);
if (ch) {
for (i = 0; i < repeat; i++)
add_key(ch);
}
return 0;
}
static LRESULT CALLBACK
gdi_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_PAINT:
list = get_rect();
if (list == NULL)
return 0;
winDC = BeginPaint(hwnd, &ps);
if (memDC == NULL)
memDC = CreateCompatibleDC(winDC);
b5hdr.bV5Width = list->rect.width;
b5hdr.bV5Height = -list->rect.height;
b5hdr.bV5SizeImage = list->rect.width * list->rect.height * 4;
di = CreateDIBitmap(winDC, (BITMAPINFOHEADER *)&b5hdr, CBM_INIT, list->data, (BITMAPINFO *)&b5hdr, 0/*DIB_RGB_COLORS*/);
di = SelectObject(memDC, di);
pthread_mutex_lock(&vstatlock);
w = vstat.winwidth;
h = vstat.winheight;
pthread_mutex_unlock(&vstatlock);
StretchBlt(winDC, 0, 0, w, h, memDC, 0, 0, list->rect.width, list->rect.height, SRCCOPY);
di = SelectObject(memDC, di);
DeleteObject(di);
EndPaint(hwnd, &ps);
return gdi_handle_wm_paint(hwnd);
case WM_CHAR:
return gdi_handle_wm_char(wParam, lParam);
case WM_MOVE:
pthread_mutex_lock(&winpos_lock);
winxpos = lParam & 0xffff;
winypos = (lParam >> 16) & 0xffff;
pthread_mutex_unlock(&winpos_lock);
return 0;
case WM_SIZE:
return gdi_handle_wm_size(wParam, lParam);
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_CHAR:
repeat = lParam & 0xffff;
alt = lParam & (1 << 29);
if (IS_HIGH_SURROGATE(wParam)) {
highpair = wParam;
return 0;
}
else if (IS_LOW_SURROGATE(wParam)) {
cp = sp_to_codepoint(highpair, wParam);
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
static void
gdi_snap(bool grow)
{
bool wc;
int w, h;
if (maximized)
return;
pthread_mutex_lock(&vstatlock);
w = vstat.winwidth;
h = vstat.winheight;
aspect_fix(&w, &h, vstat.aspect_width, vstat.aspect_height);
if (vstat.aspect_width == 0 || vstat.aspect_height == 0)
wc = true;
else
wc = lround((double)(h * vstat.aspect_width) / vstat.aspect_height * vstat.scrnwidth / vstat.scrnheight) > w;
if (grow) {
if (wc)
w = (w - w % vstat.scrnwidth) + vstat.scrnwidth;
else
h = (h - h % vstat.scrnheight) + vstat.scrnheight;
}
else {
if (wc) {
if (w % (vstat.scrnwidth)) {
w = w - w % vstat.scrnwidth;
}
else {
cp = wParam;
w -= vstat.scrnwidth;
if (w < vstat.scrnwidth)
w = vstat.scrnwidth;
}
// Translate from unicode to codepage...
ch = cpchar_from_unicode_cpoint(getcodepage(), cp, 0);
if (ch) {
for (i = 0; i < repeat; i++)
add_key(ch);
}
else {
if (h % (vstat.scrnheight)) {
h = h - h % vstat.scrnheight;
}
return 0;
else {
h -= vstat.scrnheight;
if (h < vstat.scrnheight)
h = vstat.scrnheight;
}
}
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
if (wc)
h = INT_MAX;
else
w = INT_MAX;
aspect_fix(&w, &h, vstat.aspect_width, vstat.aspect_height);
if (w > 16384 || h > 16384)
gdi_beep();
else {
vstat.winwidth = w;
vstat.winheight = h;
set_ciolib_scaling();
gdi_setwinsize(w, h);
}
pthread_mutex_unlock(&vstatlock);
}
#define WMOD_CTRL 1
......@@ -185,6 +369,7 @@ magic_message(MSG msg)
RECT r;
switch(msg.message) {
// User messages
case WM_USER_INVALIDATE:
InvalidateRect(win, NULL, FALSE);
return true;
......@@ -194,13 +379,16 @@ magic_message(MSG msg)
r.left = r.top = 0;
r.right = vstat.winwidth = msg.wParam;
r.bottom = vstat.winheight = msg.lParam;
set_ciolib_scaling();
pthread_mutex_unlock(&vstatlock);
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 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:
SetWindowPos(win, NULL, msg.wParam, msg.lParam, 0, 0, SWP_NOSIZE|SWP_NOOWNERZORDER|SWP_NOZORDER);
return true;
// Keyboard stuff
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
......@@ -233,13 +421,19 @@ magic_message(MSG msg)
return false;
}
if (msg.message == WM_KEYUP)
if (msg.message == WM_KEYUP || msg.message == WM_SYSKEYUP)
return false;
for (i = 0; keyval[i].VirtualKeyCode != 0; i++) {
if (keyval[i].VirtualKeyCode == msg.wParam) {
if (msg.lParam & (1 << 29)) {
if (keyval[i].ALT > 255) {
if (keyval[i].VirtualKeyCode == VK_LEFT) {
gdi_snap(false);
}
else if (keyval[i].VirtualKeyCode == VK_RIGHT) {
gdi_snap(true);
}
add_key(keyval[i].ALT);
return true;
}
......@@ -266,8 +460,6 @@ magic_message(MSG msg)
}
}
break;
case WM_PAINT:
break;
}
return false;
......@@ -298,8 +490,8 @@ gdi_thread(void *arg)
r.right = vstat.winwidth;
r.bottom = vstat.winheight;
pthread_mutex_unlock(&vstatlock);
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW | WS_VISIBLE, FALSE);
win = CreateWindowW(wc.lpszClassName, L"SyncConsole", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, r.right - r.left, r.bottom - r.top, NULL, NULL, wc.hInstance, NULL);
AdjustWindowRect(&r, style, FALSE);
win = CreateWindowW(wc.lpszClassName, L"SyncConsole", style, CW_USEDEFAULT, CW_USEDEFAULT, r.right - r.left, r.bottom - r.top, NULL, NULL, wc.hInstance, NULL);
while (GetMessage(&msg, NULL, 0, 0)) {
if (!magic_message(msg)) {
......@@ -389,7 +581,8 @@ gdi_textmode(int mode)
vstat.winwidth = vstat.scrnwidth;
if (vstat.winheight < vstat.scrnheight)
vstat.winheight = vstat.scrnheight;
// TODO: This is called before there's a window...
// TODO? This is called before there's a window...
set_ciolib_scaling();
gdi_setwinsize(vstat.winwidth, vstat.winheight);
pthread_mutex_unlock(&vstatlock);
bitmap_drv_request_pixels();
......@@ -397,11 +590,6 @@ gdi_textmode(int mode)
return;
}
void
gdi_setname(const char *name)
{
}
void
gdi_settitle(const char *newTitle)
{
......@@ -421,33 +609,39 @@ gdi_settitle(const char *newTitle)
void
gdi_seticon(const void *icon, unsigned long size)
{
// TODO
}
void
gdi_copytext(const char *text, size_t buflen)
{
// TODO
}
char *
gdi_getcliptext(void)
{
// TODO
return NULL;
}
int
gdi_get_window_info(int *width, int *height, int *xpos, int *ypos)
{
WINDOWPLACEMENT wp;
pthread_mutex_lock(&vstatlock);
if(width)
*width=vstat.winwidth;
if(height)
*height=vstat.winheight;
// TODO
pthread_mutex_unlock(&vstatlock);
pthread_mutex_lock(&winpos_lock);
if(xpos)
*xpos=0;
*xpos=winxpos;
if(ypos)
*ypos=0;
pthread_mutex_unlock(&vstatlock);
*ypos=winypos;
pthread_mutex_unlock(&winpos_lock);
return(1);
}
......@@ -463,7 +657,7 @@ gdi_init(int mode)
_beginthread(gdi_thread, 0, NULL);
cio_api.mode=CIOLIB_MODE_GDI;
//FreeConsole();
FreeConsole();
cio_api.options |= CONIO_OPT_PALETTE_SETTING | CONIO_OPT_SET_TITLE | CONIO_OPT_SET_NAME | CONIO_OPT_SET_ICON;
return(0);
}
......@@ -472,6 +666,7 @@ int
gdi_initciolib(int mode)
{
pthread_mutex_init(&gdi_headlock, NULL);
pthread_mutex_init(&winpos_lock, NULL);
pthread_mutex_init(&rect_lock, NULL);
return(gdi_init(mode));
......@@ -512,32 +707,10 @@ gdi_flush(void)
}
}
void
gdi_setscaling(int newval)
{
}
int
gdi_getscaling(void)
{
return 1;
}
int
gdi_mousepointer(enum ciolib_mouse_ptr type)
{
return 0;
}
int
gdi_showmouse(void)
{
return 1;
}
int
gdi_hidemouse(void)
{
// TODO
return 0;
}
......
......@@ -7,7 +7,6 @@ int gdi_kbhit(void);
int gdi_getch(void);
void gdi_beep(void);
void gdi_textmode(int mode);
void gdi_setname(const char *name);
void gdi_settitle(const char *title);
void gdi_seticon(const void *icon, unsigned long size);
void gdi_copytext(const char *text, size_t buflen);
......@@ -17,11 +16,7 @@ int gdi_init(int mode);
int gdi_initciolib(int mode);
void gdi_drawrect(struct rectlist *data);
void gdi_flush(void);
void gdi_setscaling(int newval);
int gdi_getscaling(void);
int gdi_mousepointer(enum ciolib_mouse_ptr type);
int gdi_showmouse(void);
int gdi_hidemouse(void);
void gdi_setwinposition(int x, int y);
void gdi_setwinsize(int w, int h);
......
......@@ -101,7 +101,8 @@ char *usage =
" I = Curses mode with forced ASCII charset\n"
" F = Curses mode with forced IBM charset\n"
#else
" W[F] = Win32 native mode, F for fullscreen\n"
" W[F] = Win32 console (text) mode, F for fullscreen\n"
" G = Win32 GDI (graphics) mode\n"
#endif
" A = ANSI mode\n"
"-l# = set screen lines to # (default=auto-detect)\n"
......@@ -1606,6 +1607,9 @@ main(int argc, char **argv)
case 'F':
ciolib_mode = CIOLIB_MODE_CURSES_IBM;
break;
case 'G':
ciolib_mode = CIOLIB_MODE_GDI;
break;
case 'I':
ciolib_mode = CIOLIB_MODE_CURSES_ASCII;
break;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment