sdl_con.c 31.5 KB
Newer Older
1
2
#include <stdarg.h>
#include <stdio.h>		/* NULL */
deuce's avatar
deuce committed
3
#include <stdlib.h>
4
5
6
7
#include <string.h>

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

15
16
17
18
19
20
21
#if (defined CIOLIB_IMPORTS)
 #undef CIOLIB_IMPORTS
#endif
#if (defined CIOLIB_EXPORTS)
 #undef CIOLIB_EXPORTS
#endif

22
#include "ciolib.h"
23
#include "utf8_codepages.h"
24
#include "vidmodes.h"
25
#define BITMAP_CIOLIB_DRIVER
deuce's avatar
deuce committed
26
#include "bitmap_con.h"
27

28
#include "SDL.h"
deuce's avatar
deuce committed
29
30
31

#include "sdlfuncs.h"

deuce's avatar
deuce committed
32
33
34
35
36
37
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 */
38

39
int sdl_exitcode=0;
40

41
SDL_Window	*win=NULL;
deuce's avatar
deuce committed
42
SDL_Cursor	*curs=NULL;
43
44
SDL_Renderer	*renderer=NULL;
SDL_Texture	*texture=NULL;
45
pthread_mutex_t win_mutex;
46
SDL_Surface	*sdl_icon=NULL;
47

48
49
50
sem_t sdl_ufunc_ret;
sem_t sdl_ufunc_rec;
pthread_mutex_t sdl_ufunc_mtx;
deuce's avatar
deuce committed
51
int sdl_ufunc_retval;
52

53
sem_t sdl_flush_sem;
54
55
int pending_updates=0;

56
int fullscreen=0;
57

deuce's avatar
deuce committed
58
int	sdl_init_good=0;
59
60
pthread_mutex_t sdl_keylock;
sem_t sdl_key_pending;
deuce's avatar
deuce committed
61
static unsigned int sdl_pending_mousekeys=0;
62

63
64
static struct video_stats cvstat;

65
66
67
68
69
70
71
72
struct sdl_keyvals {
	int	keysym
		,key
		,shift
		,ctrl
		,alt;
};

73
static pthread_mutex_t sdl_headlock;
74
75
static struct rectlist *update_list = NULL;
static struct rectlist *update_list_tail = NULL;
76
77

enum {
78
	 SDL_USEREVENT_FLUSH
79
	,SDL_USEREVENT_SETTITLE
80
	,SDL_USEREVENT_SETNAME
81
	,SDL_USEREVENT_SETICON
82
83
84
	,SDL_USEREVENT_SETVIDMODE
	,SDL_USEREVENT_SHOWMOUSE
	,SDL_USEREVENT_HIDEMOUSE
85
	,SDL_USEREVENT_INIT
86
	,SDL_USEREVENT_QUIT
87
	,SDL_USEREVENT_GETWINPOS
deuce's avatar
deuce committed
88
	,SDL_USEREVENT_MOUSEPOINTER
89
90
91
92
93
94
95
96
};

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},
97
	{SDLK_SPACE, 0x20, 0x20, 0x0300, 0x20},
98
99
100
101
102
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
	{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},
142
143
	{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},
144
145
146
147
148
149
150
151
152
153
	{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},
154
155
156
	{SDLK_KP_MULTIPLY, '*', '*', 0x9600, 0x3700},
	{SDLK_KP_PLUS, '+', '+', 0x9000, 0x4e00},
	{SDLK_KP_MINUS, '-', '-', 0x8e00, 0x4a00},
157
	{SDLK_KP_PERIOD, 0x7f, 0x7f, 0x5300, 0x9300},
158
	{SDLK_KP_DIVIDE, '/', '/', 0x9500, 0xa400},
159
	{SDLK_KP_ENTER, 0x0d, 0x0d, 0x0a, 0xa600},
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
	{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},
179
	{SDLK_QUOTE, '\'', '"', 0, 0x2800},
180
181
182
183
184
	{SDLK_COMMA, ',', '<', 0, 0x3300},
	{SDLK_PERIOD, '.', '>', 0, 0x3400},
	{SDLK_BACKQUOTE, '`', '~', 0, 0x2900},
	{0, 0, 0, 0, 0}	/** END **/
};
185

deuce's avatar
deuce committed
186
void sdl_video_event_thread(void *data);
deuce's avatar
deuce committed
187

deuce's avatar
deuce committed
188
static void sdl_user_func(int func, ...)
189
190
{
	va_list argptr;
191
	SDL_Event	ev;
192
	int rv;
193

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

238
/* Called from main thread only */
deuce's avatar
deuce committed
239
static int sdl_user_func_ret(int func, ...)
240
{
241
	int rv;
242
243
244
245
246
247
248
249
	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);
250
	pthread_mutex_lock(&sdl_ufunc_mtx);
251
	/* Drain the swamp */
252
253
	while(1) {
		switch(func) {
254
255
256
257
			case SDL_USEREVENT_GETWINPOS:
				ev.user.data1 = va_arg(argptr, void *);
				ev.user.data2 = va_arg(argptr, void *);
				// Fallthrough
258
259
260
			case SDL_USEREVENT_SETVIDMODE:
			case SDL_USEREVENT_INIT:
			case SDL_USEREVENT_QUIT:
deuce's avatar
deuce committed
261
				while(sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)!=1)
262
263
					YIELD();
				break;
264
			default:
265
				pthread_mutex_unlock(&sdl_ufunc_mtx);
deuce's avatar
deuce committed
266
				va_end(argptr);
267
				return -1;
268
		}
269
		rv = sem_wait(&sdl_ufunc_ret);
270
		if(rv==0)
271
			break;
272
	}
273
	pthread_mutex_unlock(&sdl_ufunc_mtx);
274
275
276
277
	va_end(argptr);
	return(sdl_ufunc_retval);
}

278
void exit_sdl_con(void)
279
{
280
281
282
	// Avoid calling exit(0) from an atexit() function...
	ciolib_reaper = 0;
	sdl_user_func_ret(SDL_USEREVENT_QUIT);
283
284
}

285
286
void sdl_copytext(const char *text, size_t buflen)
{
deuce's avatar
deuce committed
287
	sdl.SetClipboardText(text);
288
289
290
291
}

char *sdl_getcliptext(void)
{
deuce's avatar
deuce committed
292
293
	uint8_t *u8;
	u8 = (uint8_t *)sdl.GetClipboardText();
deuce's avatar
deuce committed
294
	char *ret = strdup((char *)u8);
295
296
	sdl.free(u8);
	return ret;
297
298
}

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

316
317
void sdl_flush(void)
{
318
	sdl_user_func(SDL_USEREVENT_FLUSH);
319
320
}

deuce's avatar
deuce committed
321
static int sdl_init_mode(int mode)
322
{
323
	int oldcols;
324

325
326
327
328
329
330
331
332
333
	if (mode != CIOLIB_MODE_CUSTOM) {
		pthread_mutex_lock(&vstatlock);
		if (mode == vstat.mode) {
			pthread_mutex_unlock(&vstatlock);
			return 0;
		}
		pthread_mutex_unlock(&vstatlock);
	}

334
	sdl_user_func(SDL_USEREVENT_FLUSH);
335

336
	pthread_mutex_lock(&blinker_lock);
337
	pthread_mutex_lock(&vstatlock);
deuce's avatar
deuce committed
338
	oldcols = cvstat.cols;
339
	bitmap_drv_init_mode(mode, &bitmap_width, &bitmap_height);
340
341
	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
342
	if (oldcols != vstat.cols) {
343
344
345
346
347
348
349
350
		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;
		}
351
		if (oldcols == 40) {
deuce's avatar
deuce committed
352
			vstat.winwidth /= 2;
353
354
355
			vstat.winheight /= 2;
		}
		if (vstat.cols == 40) {
deuce's avatar
deuce committed
356
			vstat.winwidth *= 2;
357
358
			vstat.winheight *= 2;
		}
359
	}
360
361
362
363
	if (vstat.winwidth < vstat.scrnwidth)
		vstat.winwidth = vstat.scrnwidth;
	if (vstat.winheight < vstat.scrnheight)
		vstat.winheight = vstat.scrnheight;
364
365
	if(vstat.vmultiplier < 1)
		vstat.vmultiplier = 1;
366

367
368
	cvstat = vstat;
	pthread_mutex_unlock(&vstatlock);
369
	pthread_mutex_unlock(&blinker_lock);
370

371
	sdl_user_func_ret(SDL_USEREVENT_SETVIDMODE);
372

373
	return(0);
374
375
}

376
/* Called from main thread only (Passes Event) */
377
int sdl_init(int mode)
378
{
379
	bitmap_drv_init(sdl_drawrect, sdl_flush);
380

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

deuce's avatar
deuce committed
392
393
	if(sdl_init_good) {
		cio_api.mode=fullscreen?CIOLIB_MODE_SDL_FULLSCREEN:CIOLIB_MODE_SDL;
deuce's avatar
deuce committed
394
#ifdef _WIN32
395
		FreeConsole();
deuce's avatar
deuce committed
396
#endif
397
		cio_api.options |= CONIO_OPT_PALETTE_SETTING | CONIO_OPT_SET_TITLE | CONIO_OPT_SET_NAME | CONIO_OPT_SET_ICON;
398
		return(0);
deuce's avatar
deuce committed
399
	}
400

401
	ciolib_reaper = 0;
402
	sdl_user_func_ret(SDL_USEREVENT_QUIT);
403
	return(-1);
404
405
}

deuce's avatar
deuce committed
406
407
408
409
410
411
void sdl_setwinsize_locked(int w, int h)
{
	if (w > 16384)
		w = 16384;
	if (h > 16384)
		h = 16384;
412
413
414
415
	if (w < cvstat.scrnwidth)
		w = cvstat.scrnwidth;
	if (h < cvstat.scrnheight)
		h = cvstat.scrnheight;
deuce's avatar
deuce committed
416
417
418
419
420
	cvstat.winwidth = vstat.winwidth = w;
	cvstat.winheight = vstat.winheight = h;
}

void sdl_setwinsize(int w, int h)
421
{
422
	pthread_mutex_lock(&vstatlock);
deuce's avatar
deuce committed
423
	sdl_setwinsize_locked(w, h);
424
	pthread_mutex_unlock(&vstatlock);
425
426
}

deuce's avatar
deuce committed
427
void sdl_setwinposition(int x, int y)
428
{
429
	pthread_mutex_lock(&win_mutex);
deuce's avatar
deuce committed
430
	sdl.SetWindowPosition(win, x, y);
431
	pthread_mutex_unlock(&win_mutex);
deuce's avatar
deuce committed
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
}

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);
447
448
}

449
450
451
452
453
/* Called from main thread only */
int sdl_kbhit(void)
{
	int ret;

454
	pthread_mutex_lock(&sdl_keylock);
455
	ret=(sdl_key!=sdl_keynext);
456
	pthread_mutex_unlock(&sdl_keylock);
457
458
459
460
461
462
463
464
	return(ret);
}

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

465
466
	sem_wait(&sdl_key_pending);
	pthread_mutex_lock(&sdl_keylock);
467
468

	/* This always frees up space in keybuf for one more char */
469
	ch=sdl_keybuf[sdl_key++];
470
	/* If we have missed mouse keys, tack them on to the end of the buffer now */
471
	if(sdl_pending_mousekeys) {
472
473
474
475
		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;
476
        sem_post(&sdl_key_pending);
477
478
		sdl_pending_mousekeys--;
	}
479
	pthread_mutex_unlock(&sdl_keylock);
480
481
482
483
484
485
486
487
488
	return(ch);
}

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

489
490
491
492
493
494
495
/* Called from main thread only (Passes Event) */
int sdl_setname(const char *name)
{
	sdl_user_func(SDL_USEREVENT_SETNAME,name);
	return(0);
}

496
497
498
499
500
501
502
/* 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);
}

503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
/* 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
519
	return(0);
520
521
}

522
523
int sdl_get_window_info(int *width, int *height, int *xpos, int *ypos)
{
deuce's avatar
deuce committed
524
	int wx, wy;
525

526
	if (xpos || ypos) {
527
		sdl_user_func_ret(SDL_USEREVENT_GETWINPOS, &wx, &wy);
528
529
530
531
532
533
534
535
536
537
538
539
540
541
		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);
	}
542
543

	return(1);
544
545
}

deuce's avatar
deuce committed
546
static void setup_surfaces_locked(void)
547
{
548
	int		flags=0;
549
	SDL_Event	ev;
deuce's avatar
deuce committed
550
	int charwidth, charheight, cols, rows, vmultiplier;
551
	SDL_Texture *newtexture;
552
553

	if(fullscreen)
554
		flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
555
	else
556
		flags |= SDL_WINDOW_RESIZABLE;
557

558
	pthread_mutex_lock(&win_mutex);
559
560
561
562
563
	charwidth = cvstat.charwidth;
	charheight = cvstat.charheight;
	cols = cvstat.cols;
	rows = cvstat.rows;
	vmultiplier = cvstat.vmultiplier;
564

565
566
	if (win == NULL) {
		// SDL2: This is slow sometimes... not sure why.
deuce's avatar
deuce committed
567
		if (sdl.CreateWindowAndRenderer(cvstat.winwidth, cvstat.winheight, flags, &win, &renderer) == 0) {
568
			sdl.RenderClear(renderer);
569
			newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cvstat.scrnwidth, cvstat.scrnheight);
570

571
572
			if (texture) 
				sdl.DestroyTexture(texture);
573
			texture = newtexture;
574
575
576
577
		}
		else {
			win = NULL;
			renderer = NULL;
578
		}
579
	}
580
	else {
581
		sdl.SetWindowMinimumSize(win, cvstat.scrnwidth, cvstat.scrnheight);
deuce's avatar
deuce committed
582
		sdl.SetWindowSize(win, cvstat.winwidth, cvstat.winheight);
583
		newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cvstat.scrnwidth, cvstat.scrnheight);
584
585
		sdl.RenderClear(renderer);
		if (texture)
586
			sdl.DestroyTexture(texture);
587
		texture = newtexture;
588
	}
589
	sdl.SetWindowMinimumSize(win, cvstat.scrnwidth, cvstat.scrnheight);
590

591
	if(win!=NULL) {
592
		bitmap_drv_request_pixels();
593
594
595
596
	}
	else if(sdl_init_good) {
		ev.type=SDL_QUIT;
		sdl_exitcode=1;
deuce's avatar
deuce committed
597
		sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
598
	}
599
	pthread_mutex_unlock(&win_mutex);
600
601
}

deuce's avatar
deuce committed
602
603
604
605
606
607
608
static void setup_surfaces(void)
{
	pthread_mutex_lock(&vstatlock);
	setup_surfaces_locked();
	pthread_mutex_unlock(&vstatlock);
}

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

/* Called from event thread only */
645
static unsigned int sdl_get_char_code(unsigned int keysym, unsigned int mod)
646
{
deuce's avatar
deuce committed
647
648
649
	int expect;
	int i;

deuce's avatar
deuce committed
650
651
652
653
654
	/* We don't handle META */
	if (mod & KMOD_GUI)
		return(0x0001ffff);

	/* Glah! */
deuce's avatar
deuce committed
655
#ifdef __DARWIN__
656
657
	if(keysym==0x7f && !(mod & KMOD_CTRL)) {
		keysym=0x08;
658
		keysym=SDLK_BACKSPACE;
deuce's avatar
deuce committed
659
660
	}
#endif
661

662
663
664
665
	/* 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
666

667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
			/*
			 * Using the modifiers, look up the expected scan code.
			 */
			if(mod & KMOD_CTRL)
				expect=sdl_keyval[i].ctrl;
			else if(mod & KMOD_SHIFT) {
				if(mod & KMOD_CAPS)
					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);
693

694
695
				/* AltGr apparently... give up */
				return(0x0001ffff);
696
			}
697
698

			return(expect);
699
		}
deuce's avatar
deuce committed
700
	}
701
	/*
deuce's avatar
deuce committed
702
	 * Well, we can't find it in our table, or it's a regular key.
703
	 */
deuce's avatar
deuce committed
704
705
706
707
708
709
710
711
712
713
714
	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;
	}
715
716
717

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

720
721
722
723
724
725
static void
sdl_add_keys(uint8_t *utf8s)
{
	char *chars;
	char *p;

726
	chars = utf8_to_cp(getcodepage(), utf8s, '\x00', strlen((char *)utf8s), NULL);
727
728
729
730
731
732
733
734
	if (chars) {
		for (p = chars; *p; p++) {
			sdl_add_key(*((uint8_t *)p));
		}
		free(chars);
	}
}

735
/* Mouse event/keyboard thread */
deuce's avatar
deuce committed
736
static void sdl_mouse_thread(void *data)
737
{
deuce's avatar
deuce committed
738
	SetThreadName("SDL Mouse");
739
740
741
742
743
744
	while(1) {
		if(mouse_wait())
			sdl_add_key(CIO_KEY_MOUSE);
	}
}

deuce's avatar
deuce committed
745
static int win_to_text_xpos(int winpos)
deuce's avatar
deuce committed
746
{
747
748
	int ret;

deuce's avatar
deuce committed
749
750
751
752
753
754
755
	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);
756
	return ret;
deuce's avatar
deuce committed
757
758
}

deuce's avatar
deuce committed
759
static int win_to_text_ypos(int winpos)
deuce's avatar
deuce committed
760
{
761
	int ret;
762

deuce's avatar
deuce committed
763
764
765
766
767
768
769
	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);
770
	return ret;
deuce's avatar
deuce committed
771
772
}

773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
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
793
void sdl_video_event_thread(void *data)
794
795
{
	SDL_Event	ev;
796
797
	int		old_w, old_h;
	int		block_text = 0;
deuce's avatar
deuce committed
798

deuce's avatar
deuce committed
799
800
801
802
	pthread_mutex_lock(&vstatlock);
	old_w = cvstat.winwidth;
	old_h = cvstat.winheight;
	pthread_mutex_unlock(&vstatlock);
803
804
805

	while(1) {
		if(sdl.WaitEventTimeout(&ev, 1)!=1) {
deuce's avatar
deuce committed
806
807
808
809
810
811
812
			pthread_mutex_lock(&vstatlock);
			if (cvstat.winwidth != old_w || cvstat.winheight != old_h) {
				sdl_setwinsize_locked(cvstat.winwidth, cvstat.winheight);
				setup_surfaces_locked();
				old_w = cvstat.winwidth;
				old_h = cvstat.winheight;
				sdl_getwinsize_locked(&cvstat.winwidth, &cvstat.winheight);
deuce's avatar
deuce committed
813
			}
deuce's avatar
deuce committed
814
			pthread_mutex_unlock(&vstatlock);
815
816
817
818
		}
		else {
			switch (ev.type) {
				case SDL_KEYDOWN:			/* Keypress */
819
					if ((ev.key.keysym.mod & (KMOD_CTRL|KMOD_ALT|KMOD_GUI)) && !(ev.key.keysym.mod & KMOD_MODE)) {
820
821
822
823
824
825
826
						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;
827
828
829
830
831
832
833
834
835
836

							// 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;
837
838
										}
										else {
839
840
841
											w -= cvstat.scrnwidth;
											if (w < cvstat.scrnwidth)
												w = cvstat.scrnwidth;
842
										}
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
										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:
										if (cvstat.scale_denominator != cvstat.scale_numerator) {
											if (h % (cvstat.scrnheight * cvstat.vmultiplier) == 0) {
												h = h * cvstat.scale_denominator / cvstat.scale_numerator;
											}
											else {
												h = (h - h % (cvstat.scrnheight * cvstat.vmultiplier)) + (cvstat.scrnheight * cvstat.vmultiplier);
											}
										}
										else
											h = (h - h % (cvstat.scrnheight * cvstat.vmultiplier)) + (cvstat.scrnheight * cvstat.vmultiplier);
										break;
								}
								if (w > 16384 || h > 16384)
									beep();
								else {
									cvstat.winwidth = w;
									cvstat.winheight = h;
								}
								pthread_mutex_unlock(&vstatlock);
877
878
							}
							break;
deuce's avatar
deuce committed
879
						}
880
					}
deuce's avatar
deuce committed
881
					if (block_text || ev.key.keysym.sym < 0 || ev.key.keysym.sym > 127) {
882
						// NUMLOCK makes 
Deucе's avatar
Deucе committed
883
884
885
886
887
888
						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))
889
							break;
890
						sdl_add_key(sdl_get_char_code(ev.key.keysym.sym, ev.key.keysym.mod));
891
892
					}
					else if (!isprint(ev.key.keysym.sym)) {
Deucе's avatar
Deucе committed
893

deuce's avatar
deuce committed
894
						if (ev.key.keysym.sym < 128)
895
							sdl_add_key(ev.key.keysym.sym);
896
					}
897
					break;
898
899
900
901
902
903
904
				case SDL_TEXTINPUT:
					if (!block_text)
						sdl_add_keys((uint8_t *)ev.text.text);
					break;
				case SDL_KEYUP:
					if (!(ev.key.keysym.mod & (KMOD_CTRL|KMOD_ALT|KMOD_GUI)))
						block_text = 0;
905
906
907
					break;
				case SDL_MOUSEMOTION:
					if(!ciolib_mouse_initialized)
908
						break;
909
					ciomouse_gotevent(CIOLIB_MOUSE_MOVE,win_to_text_xpos(ev.motion.x),win_to_text_ypos(ev.motion.y), win_to_res_xpos(ev.motion.x), win_to_res_ypos(ev.motion.y));
910
911
912
					break;
				case SDL_MOUSEBUTTONDOWN:
					if(!ciolib_mouse_initialized)
913
						break;
914
915
					switch(ev.button.button) {
						case SDL_BUTTON_LEFT:
916
							ciomouse_gotevent(CIOLIB_BUTTON_PRESS(1),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y), win_to_res_xpos(ev.button.x), win_to_res_ypos(ev.button.y));
917
							break;
918
						case SDL_BUTTON_MIDDLE:
919
							ciomouse_gotevent(CIOLIB_BUTTON_PRESS(2),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y), win_to_res_xpos(ev.button.x), win_to_res_ypos(ev.button.y));
920
							break;
921
						case SDL_BUTTON_RIGHT:
922
							ciomouse_gotevent(CIOLIB_BUTTON_PRESS(3),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y), win_to_res_xpos(ev.button.x), win_to_res_ypos(ev.button.y));
923
							break;
924
925
					}
					break;
926
927
928
929
				case SDL_MOUSEWHEEL:
					if (!ciolib_mouse_initialized)
						break;
					if (ev.wheel.y) {
930
#if (SDL_MINOR_VERSION > 0) || (SDL_PATCHLEVEL > 3)
931
932
						if (ev.wheel.direction == SDL_MOUSEWHEEL_FLIPPED)
							ev.wheel.y = 0 - ev.wheel.y;
933
#endif
934
						if (ev.wheel.y > 0)
935
							ciomouse_gotevent(CIOLIB_BUTTON_PRESS(4), -1, -1, -1, -1);
936
						if (ev.wheel.y < 0)
937
							ciomouse_gotevent(CIOLIB_BUTTON_PRESS(5), -1, -1, -1, -1);
938
939
					}
					break;
940
941
				case SDL_MOUSEBUTTONUP:
					if(!ciolib_mouse_initialized)
deuce's avatar
deuce committed
942
						break;
943
944
					switch(ev.button.button) {
						case SDL_BUTTON_LEFT:
945
							ciomouse_gotevent(CIOLIB_BUTTON_RELEASE(1),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y), win_to_res_xpos(ev.button.x), win_to_res_ypos(ev.button.y));
946
947
							break;
						case SDL_BUTTON_MIDDLE:
948
							ciomouse_gotevent(CIOLIB_BUTTON_RELEASE(2),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y), win_to_res_xpos(ev.button.x), win_to_res_ypos(ev.button.y));
949
950
							break;
						case SDL_BUTTON_RIGHT:
951
							ciomouse_gotevent(CIOLIB_BUTTON_RELEASE(3),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y), win_to_res_xpos(ev.button.x), win_to_res_ypos(ev.button.y));
952
953
954
955
956
957
958
959
960
961
							break;
					}
					break;
				case SDL_QUIT:
					/*
					 * SDL2: Do we still need the reaper?
					 * This is what exit()s programs when the
					 * X is hit.
					 */
					if (ciolib_reaper)
962
						sdl_user_func(SDL_USEREVENT_QUIT);
963
964
965
966
967
968
969
970
					else
						sdl_add_key(CIO_KEY_QUIT);
					break;
				case SDL_WINDOWEVENT:
					switch(ev.window.event) {
						case SDL_WINDOWEVENT_SIZE_CHANGED:
							// SDL2: User resized window
						case SDL_WINDOWEVENT_RESIZED:
971
972
973
							{
								// SDL2: Something resized window
								const char *newh;
deuce's avatar
deuce committed
974
975

								pthread_mutex_lock(&vstatlock);
976
								if ((ev.window.data1 % cvstat.scrnwidth) || (ev.window.data2 % cvstat.scrnheight))
977
978
979
									newh = "2";
								else
									newh = "0";
980
								pthread_mutex_lock(&win_mutex);
981
982
								if (ev.window.event == SDL_WINDOWEVENT_RESIZED)
									sdl.GetWindowSize(win, &cvstat.winwidth, &cvstat.winheight);
983
								if (strcmp(newh, sdl.GetHint(SDL_HINT_RENDER_SCALE_QUALITY))) {
984
									SDL_Texture *newtexture;
985
									sdl.SetHint(SDL_HINT_RENDER_SCALE_QUALITY, newh);
986
									newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cvstat.scrnwidth, cvstat.scrnheight);
987
									sdl.RenderClear(renderer);
988
989
990
									if (texture)
										sdl.DestroyTexture(texture);
									texture = newtexture;
991
992
									bitmap_drv_request_pixels();
								}
993
								pthread_mutex_unlock(&win_mutex);
deuce's avatar
deuce committed
994
								pthread_mutex_unlock(&vstatlock);
995
								break;
deuce's avatar