sdl_con.c 33.7 KB
Newer Older
Deucе's avatar
Deucе committed
1
#include <math.h>
2
#include <stdarg.h>
Deucе's avatar
Deucе committed
3
#include <stdbool.h>
4
#include <stdio.h>		/* NULL */
deuce's avatar
deuce committed
5
#include <stdlib.h>
6 7 8 9
#include <string.h>

#include "gen_defs.h"
#include "genwrap.h"
10
#include "dirwrap.h"
11
#include "xpbeep.h"
deuce's avatar
deuce committed
12
#include "threadwrap.h"
13 14 15
#ifdef __unix__
#include <xp_dl.h>
#endif
16

17 18 19 20 21 22 23
#if (defined CIOLIB_IMPORTS)
 #undef CIOLIB_IMPORTS
#endif
#if (defined CIOLIB_EXPORTS)
 #undef CIOLIB_EXPORTS
#endif

24
#include "ciolib.h"
25
#include "utf8_codepages.h"
26
#include "vidmodes.h"
27
#define BITMAP_CIOLIB_DRIVER
deuce's avatar
deuce committed
28
#include "bitmap_con.h"
29
#include "scale.h"
30

31
#include "SDL.h"
deuce's avatar
deuce committed
32 33 34

#include "sdlfuncs.h"

deuce's avatar
deuce committed
35 36 37 38 39 40
int bitmap_width,bitmap_height;

/* 256 bytes so I can cheat */
unsigned char		sdl_keybuf[256];		/* Keyboard buffer */
unsigned char		sdl_key=0;				/* Index into keybuf for next key in buffer */
unsigned char		sdl_keynext=0;			/* Index into keybuf for next free position */
41

42
int sdl_exitcode=0;
43

44 45
bool internal_scaling = true;	// Protected by the win mutex

46
SDL_Window	*win=NULL;
deuce's avatar
deuce committed
47
SDL_Cursor	*curs=NULL;
48 49
SDL_Renderer	*renderer=NULL;
SDL_Texture	*texture=NULL;
50
pthread_mutex_t win_mutex;
51
SDL_Surface	*sdl_icon=NULL;
52

53 54 55
sem_t sdl_ufunc_ret;
sem_t sdl_ufunc_rec;
pthread_mutex_t sdl_ufunc_mtx;
deuce's avatar
deuce committed
56
int sdl_ufunc_retval;
57

58
sem_t sdl_flush_sem;
59 60
int pending_updates=0;

61
int fullscreen=0;
62

deuce's avatar
deuce committed
63
int	sdl_init_good=0;
64 65
pthread_mutex_t sdl_keylock;
sem_t sdl_key_pending;
deuce's avatar
deuce committed
66
static unsigned int sdl_pending_mousekeys=0;
67

68 69
static struct video_stats cvstat;

70 71 72 73 74 75 76 77
struct sdl_keyvals {
	int	keysym
		,key
		,shift
		,ctrl
		,alt;
};

78
static pthread_mutex_t sdl_headlock;
79 80
static struct rectlist *update_list = NULL;
static struct rectlist *update_list_tail = NULL;
81 82

enum {
83
	 SDL_USEREVENT_FLUSH
84
	,SDL_USEREVENT_SETTITLE
85
	,SDL_USEREVENT_SETNAME
86
	,SDL_USEREVENT_SETICON
87 88 89
	,SDL_USEREVENT_SETVIDMODE
	,SDL_USEREVENT_SHOWMOUSE
	,SDL_USEREVENT_HIDEMOUSE
90
	,SDL_USEREVENT_INIT
91
	,SDL_USEREVENT_QUIT
92
	,SDL_USEREVENT_GETWINPOS
deuce's avatar
deuce committed
93
	,SDL_USEREVENT_MOUSEPOINTER
94 95 96 97 98 99 100 101
};

const struct sdl_keyvals sdl_keyval[] =
{
	{SDLK_BACKSPACE, 0x08, 0x08, 0x7f, 0x0e00},
	{SDLK_TAB, 0x09, 0x0f00, 0x9400, 0xa500},
	{SDLK_RETURN, 0x0d, 0x0d, 0x0a, 0xa600},
	{SDLK_ESCAPE, 0x1b, 0x1b, 0x1b, 0x0100},
102
	{SDLK_SPACE, 0x20, 0x20, 0x0300, 0x20},
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
	{SDLK_0, '0', ')', 0, 0x8100},
	{SDLK_1, '1', '!', 0, 0x7800},
	{SDLK_2, '2', '@', 0x0300, 0x7900},
	{SDLK_3, '3', '#', 0, 0x7a00},
	{SDLK_4, '4', '$', 0, 0x7b00},
	{SDLK_5, '5', '%', 0, 0x7c00},
	{SDLK_6, '6', '^', 0x1e, 0x7d00},
	{SDLK_7, '7', '&', 0, 0x7e00},
	{SDLK_8, '8', '*', 0, 0x7f00},
	{SDLK_9, '9', '(', 0, 0x8000},
	{SDLK_a, 'a', 'A', 0x01, 0x1e00},
	{SDLK_b, 'b', 'B', 0x02, 0x3000},
	{SDLK_c, 'c', 'C', 0x03, 0x2e00},
	{SDLK_d, 'd', 'D', 0x04, 0x2000},
	{SDLK_e, 'e', 'E', 0x05, 0x1200},
	{SDLK_f, 'f', 'F', 0x06, 0x2100},
	{SDLK_g, 'g', 'G', 0x07, 0x2200},
	{SDLK_h, 'h', 'H', 0x08, 0x2300},
	{SDLK_i, 'i', 'I', 0x09, 0x1700},
	{SDLK_j, 'j', 'J', 0x0a, 0x2400},
	{SDLK_k, 'k', 'K', 0x0b, 0x2500},
	{SDLK_l, 'l', 'L', 0x0c, 0x2600},
	{SDLK_m, 'm', 'M', 0x0d, 0x3200},
	{SDLK_n, 'n', 'N', 0x0e, 0x3100},
	{SDLK_o, 'o', 'O', 0x0f, 0x1800},
	{SDLK_p, 'p', 'P', 0x10, 0x1900},
	{SDLK_q, 'q', 'Q', 0x11, 0x1000},
	{SDLK_r, 'r', 'R', 0x12, 0x1300},
	{SDLK_s, 's', 'S', 0x13, 0x1f00},
	{SDLK_t, 't', 'T', 0x14, 0x1400},
	{SDLK_u, 'u', 'U', 0x15, 0x1600},
	{SDLK_v, 'v', 'V', 0x16, 0x2f00},
	{SDLK_w, 'w', 'W', 0x17, 0x1100},
	{SDLK_x, 'x', 'X', 0x18, 0x2d00},
	{SDLK_y, 'y', 'Y', 0x19, 0x1500},
	{SDLK_z, 'z', 'Z', 0x1a, 0x2c00},
	{SDLK_PAGEUP, 0x4900, 0x4900, 0x8400, 0x9900},
	{SDLK_PAGEDOWN, 0x5100, 0x5100, 0x7600, 0xa100},
	{SDLK_END, 0x4f00, 0x4f00, 0x7500, 0x9f00},
	{SDLK_HOME, 0x4700, 0x4700, 0x7700, 0x9700},
	{SDLK_LEFT, 0x4b00, 0x4b00, 0x7300, 0x9b00},
	{SDLK_UP, 0x4800, 0x4800, 0x8d00, 0x9800},
	{SDLK_RIGHT, 0x4d00, 0x4d00, 0x7400, 0x9d00},
	{SDLK_DOWN, 0x5000, 0x5000, 0x9100, 0xa000},
147 148
	{SDLK_INSERT, CIO_KEY_IC, CIO_KEY_SHIFT_IC, CIO_KEY_CTRL_IC, CIO_KEY_ALT_IC},
	{SDLK_DELETE, CIO_KEY_DC, CIO_KEY_SHIFT_DC, CIO_KEY_CTRL_DC, CIO_KEY_ALT_DC},
149 150 151 152 153 154 155 156 157 158
	{SDLK_KP_0, 0x5200, 0x5200, 0x9200, 0},
	{SDLK_KP_1, 0x4f00, 0x4f00, 0x7500, 0},
	{SDLK_KP_2, 0x5000, 0x5000, 0x9100, 0},
	{SDLK_KP_3, 0x5100, 0x5100, 0x7600, 0},
	{SDLK_KP_4, 0x4b00, 0x4b00, 0x7300, 0},
	{SDLK_KP_5, 0x4c00, 0x4c00, 0x8f00, 0},
	{SDLK_KP_6, 0x4d00, 0x4d00, 0x7400, 0},
	{SDLK_KP_7, 0x4700, 0x4700, 0x7700, 0},
	{SDLK_KP_8, 0x4800, 0x4800, 0x8d00, 0},
	{SDLK_KP_9, 0x4900, 0x4900, 0x8400, 0},
159 160 161
	{SDLK_KP_MULTIPLY, '*', '*', 0x9600, 0x3700},
	{SDLK_KP_PLUS, '+', '+', 0x9000, 0x4e00},
	{SDLK_KP_MINUS, '-', '-', 0x8e00, 0x4a00},
162
	{SDLK_KP_PERIOD, 0x7f, 0x7f, 0x5300, 0x9300},
163
	{SDLK_KP_DIVIDE, '/', '/', 0x9500, 0xa400},
164
	{SDLK_KP_ENTER, 0x0d, 0x0d, 0x0a, 0xa600},
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
	{SDLK_F1, 0x3b00, 0x5400, 0x5e00, 0x6800},
	{SDLK_F2, 0x3c00, 0x5500, 0x5f00, 0x6900},
	{SDLK_F3, 0x3d00, 0x5600, 0x6000, 0x6a00},
	{SDLK_F4, 0x3e00, 0x5700, 0x6100, 0x6b00},
	{SDLK_F5, 0x3f00, 0x5800, 0x6200, 0x6c00},
	{SDLK_F6, 0x4000, 0x5900, 0x6300, 0x6d00},
	{SDLK_F7, 0x4100, 0x5a00, 0x6400, 0x6e00},
	{SDLK_F8, 0x4200, 0x5b00, 0x6500, 0x6f00},
	{SDLK_F9, 0x4300, 0x5c00, 0x6600, 0x7000},
	{SDLK_F10, 0x4400, 0x5d00, 0x6700, 0x7100},
	{SDLK_F11, 0x8500, 0x8700, 0x8900, 0x8b00},
	{SDLK_F12, 0x8600, 0x8800, 0x8a00, 0x8c00},
	{SDLK_BACKSLASH, '\\', '|', 0x1c, 0x2b00},
	{SDLK_SLASH, '/', '?', 0, 0x3500},
	{SDLK_MINUS, '-', '_', 0x1f, 0x8200},
	{SDLK_EQUALS, '=', '+', 0, 0x8300},
	{SDLK_LEFTBRACKET, '[', '{', 0x1b, 0x1a00},
	{SDLK_RIGHTBRACKET, ']', '}', 0x1d, 0x1b00},
	{SDLK_SEMICOLON, ';', ':', 0, 0x2700},
184
	{SDLK_QUOTE, '\'', '"', 0, 0x2800},
185 186 187 188 189
	{SDLK_COMMA, ',', '<', 0, 0x3300},
	{SDLK_PERIOD, '.', '>', 0, 0x3400},
	{SDLK_BACKQUOTE, '`', '~', 0, 0x2900},
	{0, 0, 0, 0, 0}	/** END **/
};
190

deuce's avatar
deuce committed
191
void sdl_video_event_thread(void *data);
deuce's avatar
deuce committed
192

deuce's avatar
deuce committed
193
static void sdl_user_func(int func, ...)
194 195
{
	va_list argptr;
196
	SDL_Event	ev;
197
	int rv;
198

199 200 201 202
	ev.type=SDL_USEREVENT;
	ev.user.data1=NULL;
	ev.user.data2=NULL;
	ev.user.code=func;
203
	pthread_mutex_lock(&sdl_ufunc_mtx);
204
	while (1) {
205
		va_start(argptr, func);
206 207 208 209
		switch(func) {
			case SDL_USEREVENT_SETICON:
				ev.user.data1=va_arg(argptr, void *);
				if((ev.user.data2=(unsigned long *)malloc(sizeof(unsigned long)))==NULL) {
210
					pthread_mutex_unlock(&sdl_ufunc_mtx);
211 212 213 214 215 216 217 218
					va_end(argptr);
					return;
				}
				*(unsigned long *)ev.user.data2=va_arg(argptr, unsigned long);
				break;
			case SDL_USEREVENT_SETNAME:
			case SDL_USEREVENT_SETTITLE:
				if((ev.user.data1=strdup(va_arg(argptr, char *)))==NULL) {
219
					pthread_mutex_unlock(&sdl_ufunc_mtx);
220 221 222 223
					va_end(argptr);
					return;
				}
				break;
deuce's avatar
deuce committed
224 225 226
			case SDL_USEREVENT_MOUSEPOINTER:
				ev.user.data1 = (void *)(intptr_t)va_arg(argptr, int);
				break;
227 228 229 230 231
			case SDL_USEREVENT_SHOWMOUSE:
			case SDL_USEREVENT_HIDEMOUSE:
			case SDL_USEREVENT_FLUSH:
				break;
			default:
deuce's avatar
deuce committed
232
				va_end(argptr);
233
				return;
234
		}
235
		va_end(argptr);
deuce's avatar
deuce committed
236
		while((rv = sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT))!=1)
237 238 239
			YIELD();
		break;
	}
240
	pthread_mutex_unlock(&sdl_ufunc_mtx);
241 242
}

243
/* Called from main thread only */
deuce's avatar
deuce committed
244
static int sdl_user_func_ret(int func, ...)
245
{
246
	int rv;
247 248 249 250 251 252 253 254
	va_list argptr;
	SDL_Event	ev;

	ev.type=SDL_USEREVENT;
	ev.user.data1=NULL;
	ev.user.data2=NULL;
	ev.user.code=func;
	va_start(argptr, func);
255
	pthread_mutex_lock(&sdl_ufunc_mtx);
256
	/* Drain the swamp */
257 258
	while(1) {
		switch(func) {
259 260 261 262
			case SDL_USEREVENT_GETWINPOS:
				ev.user.data1 = va_arg(argptr, void *);
				ev.user.data2 = va_arg(argptr, void *);
				// Fallthrough
263 264 265
			case SDL_USEREVENT_SETVIDMODE:
			case SDL_USEREVENT_INIT:
			case SDL_USEREVENT_QUIT:
deuce's avatar
deuce committed
266
				while(sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)!=1)
267 268
					YIELD();
				break;
269
			default:
270
				pthread_mutex_unlock(&sdl_ufunc_mtx);
deuce's avatar
deuce committed
271
				va_end(argptr);
272
				return -1;
273
		}
274
		rv = sem_wait(&sdl_ufunc_ret);
275
		if(rv==0)
276
			break;
277
	}
278
	pthread_mutex_unlock(&sdl_ufunc_mtx);
279 280 281 282
	va_end(argptr);
	return(sdl_ufunc_retval);
}

283
void exit_sdl_con(void)
284
{
285 286 287
	// Avoid calling exit(0) from an atexit() function...
	ciolib_reaper = 0;
	sdl_user_func_ret(SDL_USEREVENT_QUIT);
288 289
}

290 291
void sdl_copytext(const char *text, size_t buflen)
{
deuce's avatar
deuce committed
292
	sdl.SetClipboardText(text);
293 294 295 296
}

char *sdl_getcliptext(void)
{
deuce's avatar
deuce committed
297 298
	uint8_t *u8;
	u8 = (uint8_t *)sdl.GetClipboardText();
deuce's avatar
deuce committed
299
	char *ret = strdup((char *)u8);
300 301
	sdl.free(u8);
	return ret;
302 303
}

304
void sdl_drawrect(struct rectlist *data)
305
{
deuce's avatar
deuce committed
306
	if(sdl_init_good) {
307
		data->next = NULL;
308
		pthread_mutex_lock(&sdl_headlock);
309
		if (update_list == NULL)
310
			update_list = update_list_tail = data;
311 312 313
		else {
			update_list_tail->next = data;
			update_list_tail = data;
314
		}
315
		pthread_mutex_unlock(&sdl_headlock);
316
	}
deuce's avatar
deuce committed
317
	else
deuce's avatar
deuce committed
318
		bitmap_drv_free_rect(data);
319 320
}

321 322
void sdl_flush(void)
{
323
	sdl_user_func(SDL_USEREVENT_FLUSH);
324 325
}

deuce's avatar
deuce committed
326
static int sdl_init_mode(int mode)
327
{
328
	int oldcols;
329

330 331 332 333 334 335 336 337 338
	if (mode != CIOLIB_MODE_CUSTOM) {
		pthread_mutex_lock(&vstatlock);
		if (mode == vstat.mode) {
			pthread_mutex_unlock(&vstatlock);
			return 0;
		}
		pthread_mutex_unlock(&vstatlock);
	}

339
	sdl_user_func(SDL_USEREVENT_FLUSH);
340

341
	pthread_mutex_lock(&blinker_lock);
342
	pthread_mutex_lock(&vstatlock);
deuce's avatar
deuce committed
343
	oldcols = cvstat.cols;
344
	bitmap_drv_init_mode(mode, &bitmap_width, &bitmap_height);
345 346
	vstat.winwidth = ((double)cvstat.winwidth / (cvstat.scrnwidth)) * (vstat.scrnwidth);
	vstat.winheight = ((double)cvstat.winheight / (cvstat.scrnheight * cvstat.vmultiplier)) * (vstat.scrnheight * vstat.vmultiplier);
deuce's avatar
deuce committed
347
	if (oldcols != vstat.cols) {
348 349 350 351 352 353 354 355
		if (oldcols == 0) {
			if (ciolib_initial_window_width > 0)
				vstat.winwidth = ciolib_initial_window_width;
			if (ciolib_initial_window_height > 0)
				vstat.winheight = ciolib_initial_window_height;
			if (vstat.cols == 40)
				oldcols = 40;
		}
356
		if (oldcols == 40) {
deuce's avatar
deuce committed
357
			vstat.winwidth /= 2;
358 359 360
			vstat.winheight /= 2;
		}
		if (vstat.cols == 40) {
deuce's avatar
deuce committed
361
			vstat.winwidth *= 2;
362 363
			vstat.winheight *= 2;
		}
364
	}
365 366 367 368
	if (vstat.winwidth < vstat.scrnwidth)
		vstat.winwidth = vstat.scrnwidth;
	if (vstat.winheight < vstat.scrnheight)
		vstat.winheight = vstat.scrnheight;
369 370
	if(vstat.vmultiplier < 1)
		vstat.vmultiplier = 1;
371

372 373
	cvstat = vstat;
	pthread_mutex_unlock(&vstatlock);
374
	pthread_mutex_unlock(&blinker_lock);
375

376
	sdl_user_func_ret(SDL_USEREVENT_SETVIDMODE);
377

378
	return(0);
379 380
}

381
/* Called from main thread only (Passes Event) */
382
int sdl_init(int mode)
383
{
384
	bitmap_drv_init(sdl_drawrect, sdl_flush);
385

386 387
	if(mode==CIOLIB_MODE_SDL_FULLSCREEN)
		fullscreen=1;
388
	// Needs to be *after* bitmap_drv_init()
deuce's avatar
deuce committed
389
#if defined(__DARWIN__)
390
	sem_post(&startsdl_sem);
deuce's avatar
deuce committed
391
#else
deuce's avatar
deuce committed
392
	_beginthread(sdl_video_event_thread, 0, NULL);
deuce's avatar
deuce committed
393
#endif
394
	sdl_user_func_ret(SDL_USEREVENT_INIT);
395
	sdl_init_mode(3);
396

deuce's avatar
deuce committed
397 398
	if(sdl_init_good) {
		cio_api.mode=fullscreen?CIOLIB_MODE_SDL_FULLSCREEN:CIOLIB_MODE_SDL;
deuce's avatar
deuce committed
399
#ifdef _WIN32
400
		FreeConsole();
deuce's avatar
deuce committed
401
#endif
402
		cio_api.options |= CONIO_OPT_PALETTE_SETTING | CONIO_OPT_SET_TITLE | CONIO_OPT_SET_NAME | CONIO_OPT_SET_ICON;
403
		return(0);
deuce's avatar
deuce committed
404
	}
405

406
	ciolib_reaper = 0;
407
	sdl_user_func_ret(SDL_USEREVENT_QUIT);
408
	return(-1);
409 410
}

deuce's avatar
deuce committed
411 412 413 414 415 416
void sdl_setwinsize_locked(int w, int h)
{
	if (w > 16384)
		w = 16384;
	if (h > 16384)
		h = 16384;
417 418 419 420
	if (w < cvstat.scrnwidth)
		w = cvstat.scrnwidth;
	if (h < cvstat.scrnheight)
		h = cvstat.scrnheight;
deuce's avatar
deuce committed
421 422 423 424 425
	cvstat.winwidth = vstat.winwidth = w;
	cvstat.winheight = vstat.winheight = h;
}

void sdl_setwinsize(int w, int h)
426
{
427
	pthread_mutex_lock(&vstatlock);
deuce's avatar
deuce committed
428
	sdl_setwinsize_locked(w, h);
429
	pthread_mutex_unlock(&vstatlock);
430 431
}

deuce's avatar
deuce committed
432
void sdl_setwinposition(int x, int y)
433
{
434
	pthread_mutex_lock(&win_mutex);
deuce's avatar
deuce committed
435
	sdl.SetWindowPosition(win, x, y);
436
	pthread_mutex_unlock(&win_mutex);
deuce's avatar
deuce committed
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
}

void sdl_getwinsize_locked(int *w, int *h)
{
	if (w)
		*w = cvstat.winwidth;
	if (h)
		*h = cvstat.winheight;
}

void sdl_getwinsize(int *w, int *h)
{
	pthread_mutex_lock(&vstatlock);
	sdl_getwinsize_locked(w, h);
	pthread_mutex_unlock(&vstatlock);
452 453
}

454 455 456 457 458
/* Called from main thread only */
int sdl_kbhit(void)
{
	int ret;

459
	pthread_mutex_lock(&sdl_keylock);
460
	ret=(sdl_key!=sdl_keynext);
461
	pthread_mutex_unlock(&sdl_keylock);
462 463 464 465 466 467 468 469
	return(ret);
}

/* Called from main thread only */
int sdl_getch(void)
{
	int ch;

470 471
	sem_wait(&sdl_key_pending);
	pthread_mutex_lock(&sdl_keylock);
472 473

	/* This always frees up space in keybuf for one more char */
474
	ch=sdl_keybuf[sdl_key++];
475
	/* If we have missed mouse keys, tack them on to the end of the buffer now */
476
	if(sdl_pending_mousekeys) {
477 478 479 480
		if(sdl_pending_mousekeys & 1)	/* Odd number... second char */
	       	sdl_keybuf[sdl_keynext++]=CIO_KEY_MOUSE >> 8;
		else							/* Even number... first char */
	        sdl_keybuf[sdl_keynext++]=CIO_KEY_MOUSE & 0xff;
481
        sem_post(&sdl_key_pending);
482 483
		sdl_pending_mousekeys--;
	}
484
	pthread_mutex_unlock(&sdl_keylock);
485 486 487 488 489 490 491 492 493
	return(ch);
}

/* Called from main thread only */
void sdl_textmode(int mode)
{
	sdl_init_mode(mode);
}

494 495 496 497 498 499 500
/* Called from main thread only (Passes Event) */
int sdl_setname(const char *name)
{
	sdl_user_func(SDL_USEREVENT_SETNAME,name);
	return(0);
}

501 502 503 504 505 506 507
/* Called from main thread only (Passes Event) */
int sdl_seticon(const void *icon, unsigned long size)
{
	sdl_user_func(SDL_USEREVENT_SETICON,icon,size);
	return(0);
}

508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
/* Called from main thread only (Passes Event) */
int sdl_settitle(const char *title)
{
	sdl_user_func(SDL_USEREVENT_SETTITLE,title);
	return(0);
}

int sdl_showmouse(void)
{
	sdl_user_func(SDL_USEREVENT_SHOWMOUSE);
	return(1);
}

int sdl_hidemouse(void)
{
	sdl_user_func(SDL_USEREVENT_HIDEMOUSE);
deuce's avatar
deuce committed
524
	return(0);
525 526
}

527 528
int sdl_get_window_info(int *width, int *height, int *xpos, int *ypos)
{
deuce's avatar
deuce committed
529
	int wx, wy;
530

531
	if (xpos || ypos) {
532
		sdl_user_func_ret(SDL_USEREVENT_GETWINPOS, &wx, &wy);
533 534 535 536 537 538 539 540 541 542 543 544 545 546
		if(xpos)
			*xpos=wx;
		if(ypos)
			*ypos=wy;
	}

	if (width || height) {
		pthread_mutex_lock(&vstatlock);
		if(width)
			*width=cvstat.winwidth;
		if(height)
			*height=cvstat.winheight;
		pthread_mutex_unlock(&vstatlock);
	}
547 548

	return(1);
549 550
}

deuce's avatar
deuce committed
551
static void setup_surfaces_locked(void)
552
{
553
	int		flags=0;
554
	SDL_Event	ev;
deuce's avatar
deuce committed
555
	int charwidth, charheight, cols, rows, vmultiplier;
556
	SDL_Texture *newtexture;
557 558
	int idealh;
	int idealmh;
559 560

	if(fullscreen)
561
		flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
562
	else
563
		flags |= SDL_WINDOW_RESIZABLE;
564

565
	pthread_mutex_lock(&win_mutex);
566 567 568 569 570
	charwidth = cvstat.charwidth;
	charheight = cvstat.charheight;
	cols = cvstat.cols;
	rows = cvstat.rows;
	vmultiplier = cvstat.vmultiplier;
Deucе's avatar
Deucе committed
571 572
	idealh = lround((long double)cvstat.winwidth * cvstat.scale_denominator / cvstat.scale_numerator * cvstat.scrnheight / cvstat.scrnwidth);
	idealmh = lround((long double)cvstat.scrnwidth * cvstat.scale_denominator / cvstat.scale_numerator * cvstat.scrnheight / cvstat.scrnwidth);
573 574
	internal_scaling = true;
	sdl.SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
575

576 577
	if (win == NULL) {
		// SDL2: This is slow sometimes... not sure why.
578
		if (sdl.CreateWindowAndRenderer(cvstat.winwidth, idealh, flags, &win, &renderer) == 0) {
579
			sdl.RenderClear(renderer);
580
			newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cvstat.winwidth, idealh);
581

582 583
			if (texture) 
				sdl.DestroyTexture(texture);
584
			texture = newtexture;
585 586 587 588
		}
		else {
			win = NULL;
			renderer = NULL;
589
		}
590
	}
591
	else {
592
		sdl.SetWindowMinimumSize(win, cvstat.scrnwidth, idealmh);
593
		sdl.SetWindowSize(win, cvstat.winwidth, idealh);
594
		newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cvstat.winwidth, idealh);
595 596
		sdl.RenderClear(renderer);
		if (texture)
597
			sdl.DestroyTexture(texture);
598
		texture = newtexture;
599
	}
600
	sdl.SetWindowMinimumSize(win, cvstat.scrnwidth, idealmh);
601

602
	if(win!=NULL) {
603
		bitmap_drv_request_pixels();
604 605 606 607
	}
	else if(sdl_init_good) {
		ev.type=SDL_QUIT;
		sdl_exitcode=1;
deuce's avatar
deuce committed
608
		sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
609
	}
610
	pthread_mutex_unlock(&win_mutex);
611 612
}

deuce's avatar
deuce committed
613 614 615 616 617 618 619
static void setup_surfaces(void)
{
	pthread_mutex_lock(&vstatlock);
	setup_surfaces_locked();
	pthread_mutex_unlock(&vstatlock);
}

620
/* Called from event thread only */
deuce's avatar
deuce committed
621
static void sdl_add_key(unsigned int keyval)
622 623 624
{
	if(keyval==0xa600) {
		fullscreen=!fullscreen;
625
		cio_api.mode=fullscreen?CIOLIB_MODE_SDL_FULLSCREEN:CIOLIB_MODE_SDL;
deuce's avatar
deuce committed
626
		sdl.SetWindowFullscreen(win, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
627
		setup_surfaces();
628 629 630
		return;
	}
	if(keyval <= 0xffff) {
631
		pthread_mutex_lock(&sdl_keylock);
632
		if(sdl_keynext+1==sdl_key) {
633
			beep();
634
			pthread_mutex_unlock(&sdl_keylock);
635 636 637
			return;
		}
		if((sdl_keynext+2==sdl_key) && keyval > 0xff) {
638
			if(keyval==CIO_KEY_MOUSE)
639
				sdl_pending_mousekeys+=2;
640
			else
641
				beep();
642
			pthread_mutex_unlock(&sdl_keylock);
643 644 645
			return;
		}
		sdl_keybuf[sdl_keynext++]=keyval & 0xff;
646
		sem_post(&sdl_key_pending);
647 648
		if(keyval>0xff) {
			sdl_keybuf[sdl_keynext++]=keyval >> 8;
649
			sem_post(&sdl_key_pending);
650
		}
651
		pthread_mutex_unlock(&sdl_keylock);
652 653 654 655
	}
}

/* Called from event thread only */
656
static unsigned int sdl_get_char_code(unsigned int keysym, unsigned int mod)
657
{
deuce's avatar
deuce committed
658 659 660
	int expect;
	int i;

deuce's avatar
deuce committed
661 662 663 664 665
	/* We don't handle META */
	if (mod & KMOD_GUI)
		return(0x0001ffff);

	/* Glah! */
deuce's avatar
deuce committed
666
#ifdef __DARWIN__
667 668
	if(keysym==0x7f && !(mod & KMOD_CTRL)) {
		keysym=0x08;
669
		keysym=SDLK_BACKSPACE;
deuce's avatar
deuce committed
670 671
	}
#endif
672

673 674 675 676
	/* Find the SDL keysym */
	for(i=0;sdl_keyval[i].keysym;i++) {
		if(sdl_keyval[i].keysym==keysym) {
			/* KeySym found in table */
deuce's avatar
deuce committed
677

678 679 680 681 682 683
			/*
			 * Using the modifiers, look up the expected scan code.
			 */
			if(mod & KMOD_CTRL)
				expect=sdl_keyval[i].ctrl;
			else if(mod & KMOD_SHIFT) {
684
				if((mod & KMOD_CAPS) && keysym != '\t')
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
					expect=sdl_keyval[i].key;
				else
					expect=sdl_keyval[i].shift;
			}
			else {
				if(mod & KMOD_CAPS && (toupper(sdl_keyval[i].key) == sdl_keyval[i].shift))
					expect=sdl_keyval[i].shift;
				else
					expect=sdl_keyval[i].key;
			}

			/*
			 * Now handle the ALT case so that expect will
			 * be what we expect to return
			 */
			if(mod & KMOD_ALT) {
				/* Yes, this is a "normal" ALT combo */
				if(keysym==expect)
					return(sdl_keyval[i].alt);
704

705 706
				/* AltGr apparently... give up */
				return(0x0001ffff);
707
			}
708 709

			return(expect);
710
		}
deuce's avatar
deuce committed
711
	}
712
	/*
deuce's avatar
deuce committed
713
	 * Well, we can't find it in our table, or it's a regular key.
714
	 */
deuce's avatar
deuce committed
715 716 717 718 719 720 721 722 723 724 725
	if(keysym > 0 && keysym < 128) {
		if (isalpha(keysym)) {
			/*
			 * If CAPS and SHIFT are not in the same state,
			 * upper-case.
			 */
			if(!!(mod & KMOD_CAPS) != !!(mod & KMOD_SHIFT))
				return toupper(keysym);
		}
		return keysym;
	}
726 727 728

	/* Give up.  It's not working out for us. */
	return(0x0001ffff);
729 730
}

731 732 733 734 735 736
static void
sdl_add_keys(uint8_t *utf8s)
{
	char *chars;
	char *p;

737
	chars = utf8_to_cp(getcodepage(), utf8s, '\x00', strlen((char *)utf8s), NULL);
738 739 740 741 742 743 744 745
	if (chars) {
		for (p = chars; *p; p++) {
			sdl_add_key(*((uint8_t *)p));
		}
		free(chars);
	}
}

746
/* Mouse event/keyboard thread */
deuce's avatar
deuce committed
747
static void sdl_mouse_thread(void *data)
748
{
deuce's avatar
deuce committed
749
	SetThreadName("SDL Mouse");
750 751 752 753 754 755
	while(1) {
		if(mouse_wait())
			sdl_add_key(CIO_KEY_MOUSE);
	}
}

deuce's avatar
deuce committed
756
static int win_to_text_xpos(int winpos)
deuce's avatar
deuce committed
757
{
758 759
	int ret;

deuce's avatar
deuce committed
760 761 762 763 764 765 766
	pthread_mutex_lock(&vstatlock);
	ret = winpos/(((float)cvstat.winwidth)/cvstat.cols)+1;
	if (ret > cvstat.cols)
		ret = cvstat.cols;
	if (ret < 1)
		ret = 1;
	pthread_mutex_unlock(&vstatlock);
767
	return ret;
deuce's avatar
deuce committed
768 769
}

deuce's avatar
deuce committed
770
static int win_to_text_ypos(int winpos)
deuce's avatar
deuce committed
771
{
772
	int ret;
773

deuce's avatar
deuce committed
774 775 776 777 778 779 780
	pthread_mutex_lock(&vstatlock);
	ret = winpos/(((float)cvstat.winheight)/cvstat.rows)+1;
	if (ret > cvstat.rows)
		ret = cvstat.rows;
	if (ret < 1)
		ret = 1;
	pthread_mutex_unlock(&vstatlock);
781
	return ret;
deuce's avatar
deuce committed
782 783
}

784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
static int win_to_res_xpos(int winpos)
{
	int ret;

	pthread_mutex_lock(&vstatlock);
	ret = winpos * (cvstat.scrnwidth) / cvstat.winwidth;
	pthread_mutex_unlock(&vstatlock);
	return ret;
}

static int win_to_res_ypos(int winpos)
{
	int ret;

	pthread_mutex_lock(&vstatlock);
	ret = winpos * (cvstat.scrnheight) / cvstat.winheight;
	pthread_mutex_unlock(&vstatlock);
	return ret;
}

deuce's avatar
deuce committed
804
void sdl_video_event_thread(void *data)
805 806
{
	SDL_Event	ev;
807
	int		block_text = 0;
Deucе's avatar
Deucе committed
808 809
	static SDL_Keycode last_sym = SDLK_UNKNOWN;
	static Uint16 last_mod = 0;
deuce's avatar
deuce committed
810

811
	while(1) {
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
		if(sdl.WaitEventTimeout(&ev, 1)!=1)
			continue;
		switch (ev.type) {
			case SDL_KEYDOWN:			/* Keypress */
				last_mod = ev.key.keysym.mod;
				last_sym = ev.key.keysym.sym;
				if ((ev.key.keysym.mod & (KMOD_CTRL|KMOD_ALT|KMOD_GUI)) && !(ev.key.keysym.mod & KMOD_MODE)) {
					block_text = 1;
					if ((ev.key.keysym.mod & KMOD_ALT) &&
					    (ev.key.keysym.sym == SDLK_LEFT ||
					     ev.key.keysym.sym == SDLK_RIGHT ||
					     ev.key.keysym.sym == SDLK_UP ||
					     ev.key.keysym.sym == SDLK_DOWN)) {
						int w, h;

						// Don't allow ALT-DIR to change size when maximized...
						if ((sdl.GetWindowFlags(win) & SDL_WINDOW_MAXIMIZED) == 0) {
							pthread_mutex_lock(&vstatlock);
							w = cvstat.winwidth;
							h = cvstat.winheight;
							switch(ev.key.keysym.sym) {
								case SDLK_LEFT:
									if (w % (cvstat.scrnwidth)) {
										w = w - w % cvstat.scrnwidth;
									}
									else {
										w -= cvstat.scrnwidth;
										if (w < cvstat.scrnwidth)
											w = cvstat.scrnwidth;
									}
									break;
								case SDLK_RIGHT:
									w = (w - w % cvstat.scrnwidth) + cvstat.scrnwidth;
									break;
								case SDLK_UP:
									if (h % (cvstat.scrnheight * cvstat.vmultiplier)) {
										h = h - h % (cvstat.scrnheight * cvstat.vmultiplier);
									}
									else {
										h -= (cvstat.scrnheight * cvstat.vmultiplier);
										if (h < (cvstat.scrnheight * cvstat.vmultiplier))
											h = cvstat.scrnheight * cvstat.vmultiplier;
									}
									break;
								case SDLK_DOWN:
									h = (h - h % (cvstat.scrnheight * cvstat.vmultiplier)) + (cvstat.scrnheight * cvstat.vmultiplier);
									break;
859
							}
860 861 862 863 864 865 866 867
							if (w > 16384 || h > 16384)
								beep();
							else {
								cvstat.winwidth = w;
								cvstat.winheight = h;
							}
							setup_surfaces_locked();
							pthread_mutex_unlock(&vstatlock);
deuce's avatar
deuce committed
868
						}
Deucе's avatar
Deucе committed
869 870
						break;
					}
871 872 873
				}
				if (ev.key.keysym.mod & KMOD_RALT) {	// Possible AltGr, let textinput sort it out...
					block_text = 0;
874
					break;
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910
				}
				if ((ev.key.keysym.mod & KMOD_SHIFT) && (ev.key.keysym.sym == '\t'))
					block_text = 1;
				if (block_text || ev.key.keysym.sym < 0 || ev.key.keysym.sym > 127) {
					// NUMLOCK makes 
					if ((ev.key.keysym.mod & KMOD_NUM) && ((ev.key.keysym.sym >= SDLK_KP_1 && ev.key.keysym.sym <= SDLK_KP_0)
					    || ev.key.keysym.sym == SDLK_KP_DIVIDE
					    || ev.key.keysym.sym == SDLK_KP_MULTIPLY
					    || ev.key.keysym.sym == SDLK_KP_MINUS
					    || ev.key.keysym.sym == SDLK_KP_PLUS
					    || ev.key.keysym.sym == SDLK_KP_PERIOD))
						break;
					sdl_add_key(sdl_get_char_code(ev.key.keysym.sym, ev.key.keysym.mod));
				}
				else if (!isprint(ev.key.keysym.sym)) {
					if (ev.key.keysym.sym < 128)
						sdl_add_key(ev.key.keysym.sym);
				}
				break;
			case SDL_TEXTINPUT:
				if (!block_text) {
					unsigned int charcode = sdl_get_char_code(last_sym, last_mod & ~(KMOD_ALT));
					// If the key is exactly what we would expect, use sdl_get_char_code()
					if (*(uint8_t *)ev.text.text == charcode)
						sdl_add_key(sdl_get_char_code(last_sym, last_mod));
					else
						sdl_add_keys((uint8_t *)ev.text.text);
				}
				break;
			case SDL_KEYUP:
				last_mod = ev.key.keysym.mod;
				if (!(ev.key.keysym.mod & (KMOD_CTRL|KMOD_ALT|KMOD_GUI)))
					block_text = 0;
				break;
			case SDL_MOUSEMOTION:
				if(!ciolib_mouse_initialized)
911
					break;
912 913 914