sdl_con.c 32.2 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
			/*
			 * Using the modifiers, look up the expected scan code.
			 */
			if(mod & KMOD_CTRL)
				expect=sdl_keyval[i].ctrl;
			else if(mod & KMOD_SHIFT) {
673
				if((mod & KMOD_CAPS) && keysym != '\t')
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
					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;
Deucе's avatar
Deucе committed
798
799
	static SDL_Keycode last_sym = SDLK_UNKNOWN;
	static Uint16 last_mod = 0;
deuce's avatar
deuce committed
800

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

	while(1) {
		if(sdl.WaitEventTimeout(&ev, 1)!=1) {
deuce's avatar
deuce committed
808
809
810
811
812
813
814
			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
815
			}
deuce's avatar
deuce committed
816
			pthread_mutex_unlock(&vstatlock);
817
818
819
820
		}
		else {
			switch (ev.type) {
				case SDL_KEYDOWN:			/* Keypress */
Deucе's avatar
Deucе committed
821
822
					last_mod = ev.key.keysym.mod;
					last_sym = ev.key.keysym.sym;
823
					if ((ev.key.keysym.mod & (KMOD_CTRL|KMOD_ALT|KMOD_GUI)) && !(ev.key.keysym.mod & KMOD_MODE)) {
824
825
826
827
828
829
830
						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;
831
832
833
834
835
836
837
838
839
840

							// 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;
841
842
										}
										else {
843
844
845
											w -= cvstat.scrnwidth;
											if (w < cvstat.scrnwidth)
												w = cvstat.scrnwidth;
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
877
878
879
880
										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);
881
882
							}
							break;
deuce's avatar
deuce committed
883
						}
884
					}
Deucе's avatar
Deucе committed
885
886
887
888
					if (ev.key.keysym.mod & KMOD_RALT) {	// Possible AltGr, let textinput sort it out...
						block_text = 0;
						break;
					}
889
890
					if ((ev.key.keysym.mod & KMOD_SHIFT) && (ev.key.keysym.sym == '\t'))
						block_text = 1;
deuce's avatar
deuce committed
891
					if (block_text || ev.key.keysym.sym < 0 || ev.key.keysym.sym > 127) {
892
						// NUMLOCK makes 
Deucе's avatar
Deucе committed
893
894
895
896
897
898
						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))
899
							break;
900
						sdl_add_key(sdl_get_char_code(ev.key.keysym.sym, ev.key.keysym.mod));
901
902
					}
					else if (!isprint(ev.key.keysym.sym)) {
deuce's avatar
deuce committed
903
						if (ev.key.keysym.sym < 128)
904
							sdl_add_key(ev.key.keysym.sym);
905
					}
906
					break;
907
				case SDL_TEXTINPUT:
Deucе's avatar
Deucе committed
908
909
910
911
912
913
914
915
					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);
					}
916
917
					break;
				case SDL_KEYUP:
Deucе's avatar
Deucе committed
918
					last_mod = ev.key.keysym.mod;
919
920
					if (!(ev.key.keysym.mod & (KMOD_CTRL|KMOD_ALT|KMOD_GUI)))
						block_text = 0;
921
922
923
					break;
				case SDL_MOUSEMOTION:
					if(!ciolib_mouse_initialized)
924
						break;
925
					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));
926
927
928
					break;
				case SDL_MOUSEBUTTONDOWN:
					if(!ciolib_mouse_initialized)
929
						break;
930
931
					switch(ev.button.button) {
						case SDL_BUTTON_LEFT:
932
							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));
933
							break;
934
						case SDL_BUTTON_MIDDLE:
935
							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));
936
							break;
937
						case SDL_BUTTON_RIGHT:
938
							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));
939
							break;
940
941
					}
					break;
942
943
944
945
				case SDL_MOUSEWHEEL:
					if (!ciolib_mouse_initialized)
						break;
					if (ev.wheel.y) {
946
#if (SDL_MINOR_VERSION > 0) || (SDL_PATCHLEVEL > 3)
947
948
						if (ev.wheel.direction == SDL_MOUSEWHEEL_FLIPPED)
							ev.wheel.y = 0 - ev.wheel.y;
949
#endif
950
						if (ev.wheel.y > 0)
951
							ciomouse_gotevent(CIOLIB_BUTTON_PRESS(4), -1, -1, -1, -1);
952
						if (ev.wheel.y < 0)
953
							ciomouse_gotevent(CIOLIB_BUTTON_PRESS(5), -1, -1, -1, -1);
954
955
					}
					break;
956
957
				case SDL_MOUSEBUTTONUP:
					if(!ciolib_mouse_initialized)
deuce's avatar
deuce committed
958
						break;
959
960
					switch(ev.button.button) {
						case SDL_BUTTON_LEFT:
961
							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));
962
963
							break;
						case SDL_BUTTON_MIDDLE:
964
							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));
965
966
							break;
						case SDL_BUTTON_RIGHT:
967
							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));
968
969
970
971
972
973
974
975
976
977
							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)
978
						sdl_user_func(SDL_USEREVENT_QUIT);
979
980
981
982
983
984
985
986
					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:
987
988
989
							{
								// SDL2: Something resized window
								const char *newh;
deuce's avatar
deuce committed
990
991

								pthread_mutex_lock(&vstatlock);
992
								if ((ev.window.data1 % cvstat.scrnwidth) || (ev.window.data2 % cvstat.scrnheight))
993
994
995
									newh = "2";
								else
									newh = "0";
996
								pthread_mutex_lock(&win_mutex);
997
998
								if (ev.window.event == SDL_WINDOWEVENT_RESIZED)
									sdl.GetWindowSize(win, &cvstat.winwidth, &cvstat.winheight);