Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

sdl_con.c 45.6 KB
Newer Older
1 2 3 4
#if (defined(__MACH__) && defined(__APPLE__))
#include <Carbon/Carbon.h>
#endif

5 6
#include <stdarg.h>
#include <stdio.h>		/* NULL */
deuce's avatar
deuce committed
7
#include <stdlib.h>
8 9 10 11
#include <string.h>

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

19 20 21 22 23 24 25
#if (defined CIOLIB_IMPORTS)
 #undef CIOLIB_IMPORTS
#endif
#if (defined CIOLIB_EXPORTS)
 #undef CIOLIB_EXPORTS
#endif

26
#include "ciolib.h"
27
#include "keys.h"
28
#include "vidmodes.h"
29
#include "allfonts.h"
deuce's avatar
deuce committed
30
#include "bitmap_con.h"
31

32
#include "SDL.h"
deuce's avatar
deuce committed
33
#include "SDL_thread.h"
deuce's avatar
deuce committed
34 35 36

#include "sdlfuncs.h"

deuce's avatar
deuce committed
37 38 39 40 41 42
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 */
43

44
int sdl_exitcode=0;
45

deuce's avatar
deuce committed
46
SDL_Surface	*win=NULL;
47
SDL_Surface	*sdl_icon=NULL;
deuce's avatar
deuce committed
48
SDL_Surface	*new_rect=NULL;
49

deuce's avatar
deuce committed
50 51 52 53
/* *nix copy/paste stuff */
SDL_sem	*sdl_pastebuf_set;
SDL_sem	*sdl_pastebuf_copied;
SDL_mutex	*sdl_copybuf_mutex;
54
static SDL_Thread *mouse_thread;
deuce's avatar
deuce committed
55 56 57 58 59
char *sdl_copybuf=NULL;
char *sdl_pastebuf=NULL;

SDL_sem *sdl_ufunc_ret;
int sdl_ufunc_retval;
60
SDL_mutex	*funcret_mutex;
61

62 63 64
SDL_sem	*sdl_flush_sem;
int pending_updates=0;

65
int fullscreen=0;
66

67
SDL_sem	*sdl_init_complete;
deuce's avatar
deuce committed
68 69 70 71
int	sdl_init_good=0;
SDL_mutex *sdl_keylock;
SDL_sem *sdl_key_pending;
static unsigned int sdl_pending_mousekeys=0;
72
Uint32	sdl_dac_default[sizeof(dac_default)/sizeof(struct dac_colors)];
73 74 75
SDL_Rect	*upd_rects=NULL;
int			rectspace=0;
int			rectsused=0;
76

deuce's avatar
deuce committed
77 78 79 80
struct yuv_settings {
	int			enabled;
	int			win_width;
	int			win_height;
deuce's avatar
deuce committed
81 82
	int			screen_width;
	int			screen_height;
83
	int			changed;
deuce's avatar
deuce committed
84
	int			best_format;
deuce's avatar
deuce committed
85
	SDL_Overlay	*overlay;
86
	SDL_mutex	*mutex;
deuce's avatar
deuce committed
87 88 89
	Uint8		colours[sizeof(dac_default)/sizeof(struct dac_colors)][3];
};

deuce's avatar
deuce committed
90
static struct yuv_settings yuv={0,0,0,0,0,0,0,NULL,NULL};
deuce's avatar
deuce committed
91

92 93 94 95 96 97 98 99
struct sdl_keyvals {
	int	keysym
		,key
		,shift
		,ctrl
		,alt;
};

deuce's avatar
deuce committed
100 101 102 103 104 105
struct update_rect {
	int		x;
	int		y;
	int		width;
	int		height;
	unsigned char *data;
106 107 108 109
};

enum {
	 SDL_USEREVENT_UPDATERECT
110
	,SDL_USEREVENT_FLUSH
111
	,SDL_USEREVENT_SETTITLE
112
	,SDL_USEREVENT_SETNAME
113
	,SDL_USEREVENT_SETICON
114 115 116
	,SDL_USEREVENT_SETVIDMODE
	,SDL_USEREVENT_SHOWMOUSE
	,SDL_USEREVENT_HIDEMOUSE
117
	,SDL_USEREVENT_INIT
118 119
	,SDL_USEREVENT_COPY
	,SDL_USEREVENT_PASTE
120
	,SDL_USEREVENT_QUIT
121 122 123 124 125 126 127 128
};

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},
129
	{SDLK_SPACE, 0x20, 0x20, 0x0300, 0x20},
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
	{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},
	{SDLK_INSERT, 0x5200, 0x5200, 0x9200, 0xa200},
	{SDLK_DELETE, 0x5300, 0x5300, 0x9300, 0xa300},
	{SDLK_KP0, 0x5200, 0x5200, 0x9200, 0},
	{SDLK_KP1, 0x4f00, 0x4f00, 0x7500, 0},
	{SDLK_KP2, 0x5000, 0x5000, 0x9100, 0},
	{SDLK_KP3, 0x5100, 0x5100, 0x7600, 0},
	{SDLK_KP4, 0x4b00, 0x4b00, 0x7300, 0},
	{SDLK_KP5, 0x4c00, 0x4c00, 0x8f00, 0},
	{SDLK_KP6, 0x4d00, 0x4d00, 0x7400, 0},
	{SDLK_KP7, 0x4700, 0x4700, 0x7700, 0},
	{SDLK_KP8, 0x4800, 0x4800, 0x8d00, 0},
	{SDLK_KP9, 0x4900, 0x4900, 0x8400, 0},
	{SDLK_KP_MULTIPLY, '*', '*', 0x9600, 0x3700},
	{SDLK_KP_PLUS, '+', '+', 0x9000, 0x4e00},
	{SDLK_KP_MINUS, '-', '-', 0x8e00, 0x4a00},
189
	{SDLK_KP_PERIOD, 0x7f, 0x7f, 0x5300, 0x9300},
190
	{SDLK_KP_DIVIDE, '/', '/', 0x9500, 0xa400},
191
	{SDLK_KP_ENTER, 0x0d, 0x0d, 0x0a, 0xa600},
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
	{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},
211
	{SDLK_QUOTE, '\'', '"', 0, 0x2800},
212 213 214 215 216
	{SDLK_COMMA, ',', '<', 0, 0x3300},
	{SDLK_PERIOD, '.', '>', 0, 0x3400},
	{SDLK_BACKQUOTE, '`', '~', 0, 0x2900},
	{0, 0, 0, 0, 0}	/** END **/
};
217

218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
#if !defined(NO_X) && defined(__unix__)
#include "SDL_syswm.h"

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>

#define CONSOLE_CLIPBOARD	XA_PRIMARY

int sdl_x11available=0;

/* X functions */
struct x11 {
	int		(*XFree)		(void *data);
	Window	(*XGetSelectionOwner)	(Display*, Atom);
	int		(*XConvertSelection)	(Display*, Atom, Atom, Atom, Window, Time);
	int		(*XGetWindowProperty)	(Display*, Window, Atom, long, long, Bool, Atom, Atom*, int*, unsigned long *, unsigned long *, unsigned char **);
	int		(*XChangeProperty)		(Display*, Window, Atom, Atom, int, int, _Xconst unsigned char*, int);
	Status	(*XSendEvent)	(Display*, Window, Bool, long, XEvent*);
	int		(*XSetSelectionOwner)	(Display*, Atom, Window, Time);
};
struct x11 sdl_x11;
#endif

deuce's avatar
deuce committed
243 244 245 246 247 248 249 250 251
void RGBtoYUV(Uint8 r, Uint8 g, Uint8 b, Uint8 *yuv_array, int monochrome, int luminance)
{
    if (monochrome)
    {
#if 0 /* these are the two formulas that I found on the FourCC site... */
        yuv_array[0] = 0.299*r + 0.587*g + 0.114*b;
        yuv_array[1] = 128;
        yuv_array[2] = 128;
#else
252
        yuv_array[0] = (Uint8)((0.257 * r) + (0.504 * g) + (0.098 * b) + 16);
deuce's avatar
deuce committed
253 254 255 256 257 258 259 260 261 262 263
        yuv_array[1] = 128;
        yuv_array[2] = 128;
#endif
    }
    else
    {
#if 0 /* these are the two formulas that I found on the FourCC site... */
        yuv_array[0] = 0.299*r + 0.587*g + 0.114*b;
        yuv_array[1] = (b-yuv[0])*0.565 + 128;
        yuv_array[2] = (r-yuv[0])*0.713 + 128;
#else
264 265 266
        yuv_array[0] = (Uint8)((0.257 * r) + (0.504 * g) + (0.098 * b) + 16);
        yuv_array[1] = (Uint8)(128 - (0.148 * r) - (0.291 * g) + (0.439 * b));
        yuv_array[2] = (Uint8)(128 + (0.439 * r) - (0.368 * g) - (0.071 * b));
deuce's avatar
deuce committed
267 268 269 270 271 272 273
#endif
    }

    if (luminance!=100)
        yuv_array[0]=yuv_array[0]*luminance/100;
}

274
void yuv_fillrect(SDL_Overlay *overlay, SDL_Rect *r, int dac_entry)
deuce's avatar
deuce committed
275
{
276 277 278
	int uplane,vplane;					/* Planar formats */
	int y0pack, y1pack, u0pack, v0pack;	/* Packed formats */

279 280
	if(!overlay)
		return;
deuce's avatar
deuce committed
281 282 283 284 285 286
	if(r->x > overlay->w || r->y > overlay->h)
		return;
	if(r->x + r->w > overlay->w)
		r->w=overlay->w-r->x;
	if(r->y + r->h > overlay->h)
		r->h=overlay->h-r->y;
287 288 289
	yuv.changed=1;
	switch(overlay->format) {
		case SDL_IYUV_OVERLAY:
deuce's avatar
deuce committed
290
			/* YUV 4:2:0 NxM Y followed by (N/2)x(M/2) U and V (12bpp) */
291 292 293 294
			uplane=1;
			vplane=2;
			goto planar;
		case SDL_YV12_OVERLAY:
deuce's avatar
deuce committed
295
			/* YUV 4:2:0 NxM Y followed by (N/2)x(M/2) V and U (12bpp) */
296
			vplane=1;
deuce's avatar
deuce committed
297
			uplane=2;
298 299
			goto planar;
		case SDL_YUY2_OVERLAY:
deuce's avatar
deuce committed
300
			/* YUV 4:2:2 Y0,U0,Y1,V0 (16bpp) */
301 302
			y0pack=0;
			u0pack=1;
deuce's avatar
deuce committed
303
			y1pack=2;
304 305 306
			v0pack=3;
			goto packed;
		case SDL_UYVY_OVERLAY:
deuce's avatar
deuce committed
307
			/* YUV 4:2:2 U0,Y0,V0,Y1 (16bpp)  */
308
			u0pack=0;
deuce's avatar
deuce committed
309
			y0pack=1;
310
			v0pack=2;
deuce's avatar
deuce committed
311
			y1pack=3;
312 313
			goto packed;
		case SDL_YVYU_OVERLAY:
deuce's avatar
deuce committed
314
			/* YUV 4:2:2 Y0,V0,Y1,U0 (16bpp)  */
315
			y0pack=0;
deuce's avatar
deuce committed
316
			v0pack=1;
317 318 319 320 321 322 323
			y1pack=2;
			u0pack=3;
			goto packed;
	}
	return;

planar:
deuce's avatar
deuce committed
324
	{
deuce's avatar
deuce committed
325
		int y;
326 327 328 329 330 331 332 333 334 335 336 337
		Uint8 *Y,*U,*V;
		int odd_line;
		int uvlen=(r->w)>>1;
		int uvoffset=overlay->pitches[1]*((r->y+1)>>1)+((r->x+1)>>1);

		odd_line=(r->y)&1;
		Y=overlay->pixels[0]+overlay->pitches[0]*(r->y)+(r->x);
		U=overlay->pixels[uplane]+uvoffset;
		V=overlay->pixels[vplane]+uvoffset;
		for(y=0; y<r->h; y++)
		{
			memset(Y, yuv.colours[dac_entry][0], r->w);
deuce's avatar
deuce committed
338
			/* Increment every line */
339 340
			Y+=overlay->pitches[0];
			if(odd_line) {
deuce's avatar
deuce committed
341
				/* Increment on odd lines */
342 343 344 345 346 347 348
				U+=overlay->pitches[uplane];
				V+=overlay->pitches[vplane];
			}
			else {
				memset(U, yuv.colours[dac_entry][1], uvlen);
				memset(V, yuv.colours[dac_entry][2], uvlen);
			}
deuce's avatar
deuce committed
349
			odd_line = !odd_line;
deuce's avatar
deuce committed
350
		}
351 352 353 354 355 356
	}
	return;
packed:
	{
		int x,y;
		Uint32 colour;
deuce's avatar
deuce committed
357
		Uint8 *colour_array=(Uint8 *)&colour;
358 359 360 361 362 363 364
		Uint32 *offset;

		colour_array[y0pack]=yuv.colours[dac_entry][0];
		colour_array[y1pack]=yuv.colours[dac_entry][0];
		colour_array[u0pack]=yuv.colours[dac_entry][1];
		colour_array[v0pack]=yuv.colours[dac_entry][2];
		offset=(Uint32 *)(overlay->pixels[0]+overlay->pitches[0]*(r->y));
deuce's avatar
deuce committed
365
		offset+=(r->x>>1);
366 367 368
		for(y=0; y<r->h; y++)
		{
			for(x=0; x<r->w; x+=2)
deuce's avatar
deuce committed
369
				offset[x>>1]=colour;
deuce's avatar
deuce committed
370
			offset+=overlay->pitches[0]>>2;
deuce's avatar
deuce committed
371
		}
deuce's avatar
deuce committed
372
	}
373
	return;
deuce's avatar
deuce committed
374 375
}

376 377 378
void sdl_user_func(int func, ...)
{
	va_list argptr;
379
	SDL_Event	ev;
380

381 382 383 384
	ev.type=SDL_USEREVENT;
	ev.user.data1=NULL;
	ev.user.data2=NULL;
	ev.user.code=func;
385 386
	va_start(argptr, func);
	switch(func) {
387
		case SDL_USEREVENT_SETICON:
388 389
			ev.user.data1=va_arg(argptr, void *);
			if((ev.user.data2=(unsigned long *)malloc(sizeof(unsigned long)))==NULL) {
390 391 392
				va_end(argptr);
				return;
			}
393 394
			*(unsigned long *)ev.user.data2=va_arg(argptr, unsigned long);
			while(sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, 0xffffffff)!=1);
395
			break;
396
		case SDL_USEREVENT_SETNAME:
397
		case SDL_USEREVENT_SETTITLE:
398
			if((ev.user.data1=strdup(va_arg(argptr, char *)))==NULL) {
399 400 401
				va_end(argptr);
				return;
			}
402
			while(sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, 0xffffffff)!=1);
403
			break;
404
		case SDL_USEREVENT_UPDATERECT:
405 406
			ev.user.data1=va_arg(argptr, struct update_rect *);
			while(sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, 0xffffffff)!=1);
407
			break;
408 409
		case SDL_USEREVENT_COPY:
		case SDL_USEREVENT_PASTE:
410 411
		case SDL_USEREVENT_SHOWMOUSE:
		case SDL_USEREVENT_HIDEMOUSE:
412
			while(sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, 0xffffffff)!=1);
413
			break;
414 415 416 417
	}
	va_end(argptr);
}

418 419 420 421 422 423 424
/* Called from main thread only */
int sdl_user_func_ret(int func, ...)
{
	va_list argptr;
	SDL_Event	ev;
	int		passed=FALSE;

425
	sdl.mutexP(funcret_mutex);
426 427 428 429 430 431
	ev.type=SDL_USEREVENT;
	ev.user.data1=NULL;
	ev.user.data2=NULL;
	ev.user.code=func;
	va_start(argptr, func);
	switch(func) {
432
		case SDL_USEREVENT_SETVIDMODE:
433
		case SDL_USEREVENT_FLUSH:
434
		case SDL_USEREVENT_INIT:
435 436 437 438
		case SDL_USEREVENT_QUIT:
			while(sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, 0xffffffff)!=1);
			passed=TRUE;
			break;
439
	}
440
	if(passed) {
441
		sdl.SemWait(sdl_ufunc_ret);
442
	}
443 444 445
	else
		sdl_ufunc_retval=-1;
	va_end(argptr);
446
	sdl.mutexV(funcret_mutex);
447 448 449
	return(sdl_ufunc_retval);
}

450 451 452 453 454
void exit_sdl_con(void)
{
	sdl_user_func_ret(SDL_USEREVENT_QUIT);
}

455
int sdl_using_directx=0;
456
int sdl_using_quartz=0;
457
int sdl_using_x11=0;
458 459 460

void sdl_copytext(const char *text, size_t buflen)
{
461
#if (defined(__MACH__) && defined(__APPLE__))
462
	if(!sdl_using_x11) {
deuce's avatar
deuce committed
463
		sdl.mutexP(sdl_copybuf_mutex);
464 465 466 467 468 469
		FREE_AND_NULL(sdl_copybuf);

		sdl_copybuf=(char *)malloc(buflen+1);
		if(sdl_copybuf!=NULL) {
			strcpy(sdl_copybuf, text);
			sdl_user_func(SDL_USEREVENT_COPY,0,0,0,0);
470
		}
deuce's avatar
deuce committed
471
		sdl.mutexV(sdl_copybuf_mutex);
472 473 474 475
		return;
	}
#endif

476
#if !defined(NO_X) && defined(__unix__)
477
	if(sdl_x11available && sdl_using_x11) {
deuce's avatar
deuce committed
478
		sdl.mutexP(sdl_copybuf_mutex);
479 480 481 482 483 484 485
		FREE_AND_NULL(sdl_copybuf);

		sdl_copybuf=(char *)malloc(buflen+1);
		if(sdl_copybuf!=NULL) {
			strcpy(sdl_copybuf, text);
			sdl_user_func(SDL_USEREVENT_COPY,0,0,0,0);
		}
deuce's avatar
deuce committed
486
		sdl.mutexV(sdl_copybuf_mutex);
487
		return;
488 489 490
	}
#endif

deuce's avatar
deuce committed
491
	sdl.mutexP(sdl_copybuf_mutex);
492 493
	FREE_AND_NULL(sdl_copybuf);

deuce's avatar
deuce committed
494
	sdl_copybuf=strdup(text);
deuce's avatar
deuce committed
495
	sdl.mutexV(sdl_copybuf_mutex);
496 497 498 499 500 501 502
	return;
}

char *sdl_getcliptext(void)
{
	char *ret=NULL;

503
#if (defined(__MACH__) && defined(__APPLE__))
504
	if(!sdl_using_x11) {
505
		sdl_user_func(SDL_USEREVENT_PASTE,0,0,0,0);
deuce's avatar
deuce committed
506
		sdl.SemWait(sdl_pastebuf_set);
507 508 509 510
		if(sdl_pastebuf!=NULL) {
			ret=(char *)malloc(strlen(sdl_pastebuf)+1);
			if(ret!=NULL)
				strcpy(ret,sdl_pastebuf);
511
		}
512
		else
deuce's avatar
deuce committed
513
			ret=NULL;
514
		sdl.SemPost(sdl_pastebuf_copied);
515
		return(ret);
516

517 518 519
	}
#endif

520
#if !defined(NO_X) && defined(__unix__)
521
	if(sdl_x11available && sdl_using_x11) {
522
		sdl_user_func(SDL_USEREVENT_PASTE,0,0,0,0);
deuce's avatar
deuce committed
523
		sdl.SemWait(sdl_pastebuf_set);
524 525 526 527 528
		if(sdl_pastebuf!=NULL) {
			ret=(char *)malloc(strlen(sdl_pastebuf)+1);
			if(ret!=NULL)
				strcpy(ret,sdl_pastebuf);
		}
529 530 531
		else
			ret=NULL;
		sdl.SemPost(sdl_pastebuf_copied);
532
		return(ret);
533 534
	}
#endif
deuce's avatar
deuce committed
535
	sdl.mutexP(sdl_copybuf_mutex);
deuce's avatar
deuce committed
536 537
	if(sdl_copybuf)
		ret=strdup(sdl_copybuf);
deuce's avatar
deuce committed
538
	sdl.mutexV(sdl_copybuf_mutex);
539 540 541
	return(ret);
}

deuce's avatar
deuce committed
542
void sdl_drawrect(int xoffset,int yoffset,int width,int height,unsigned char *data)
543
{
deuce's avatar
deuce committed
544 545 546
	struct update_rect *rect;

	if(sdl_init_good) {
deuce's avatar
deuce committed
547
		rect=(struct update_rect *)malloc(sizeof(struct update_rect));
deuce's avatar
deuce committed
548 549 550 551 552
		rect->x=xoffset;
		rect->y=yoffset;
		rect->width=width;
		rect->height=height;
		rect->data=data;
553
		sdl_user_func(SDL_USEREVENT_UPDATERECT, rect);
554
	}
deuce's avatar
deuce committed
555
	else
deuce's avatar
deuce committed
556
		free(data);
557 558
}

559 560
void sdl_flush(void)
{
deuce's avatar
deuce committed
561
	if(rectsused || yuv.enabled)
562
		sdl_user_func_ret(SDL_USEREVENT_FLUSH);
563 564
}

565
int sdl_init_mode(int mode)
566
{
567
    int oldcols=vstat.cols;
568

569 570
	sdl_user_func_ret(SDL_USEREVENT_FLUSH);

deuce's avatar
deuce committed
571
	bitmap_init_mode(mode, &bitmap_width, &bitmap_height);
572

573
	/* Deal with 40 col doubling */
deuce's avatar
deuce committed
574 575 576 577 578 579 580 581 582 583
	if(yuv.enabled) {
		vstat.scaling=2;
	}
	else {
		if(oldcols != vstat.cols) {
			if(oldcols == 40)
				vstat.scaling /= 2;
			if(vstat.cols == 40)
				vstat.scaling *= 2;
		}
584 585 586 587 588
	}

	if(vstat.scaling < 1)
		vstat.scaling = 1;

589
	sdl_user_func_ret(SDL_USEREVENT_SETVIDMODE);
590 591 592 593

    return(0);
}

594
/* Called from main thread only (Passes Event) */
595
int sdl_init(int mode)
596
{
597
#if !defined(NO_X) && defined(__unix__)
598 599
	dll_handle	dl;
	const char *libnames[2]={"X11", NULL};
600 601
#endif

602 603
	if(init_sdl_video()) {
		fprintf(stderr, "SDL Video Init Failed\n");
deuce's avatar
deuce committed
604
		return(-1);
605
	}
deuce's avatar
deuce committed
606

607
	bitmap_init(sdl_drawrect, sdl_flush);
608

609 610
	if(mode==CIOLIB_MODE_SDL_FULLSCREEN)
		fullscreen=1;
deuce's avatar
deuce committed
611
	if(mode==CIOLIB_MODE_SDL_YUV)
deuce's avatar
deuce committed
612 613 614 615 616
		yuv.enabled=1;
	if(mode==CIOLIB_MODE_SDL_YUV_FULLSCREEN) {
		yuv.enabled=1;
		fullscreen=1;
	}
deuce's avatar
deuce committed
617 618
#if (SDL_MAJOR_VERSION > 1) || (SDL_MINOR_VERSION > 2) || (SDL_PATCHLEVEL > 9)
	if(yuv.enabled) {
deuce's avatar
deuce committed
619
		const SDL_version	*linked=sdl.Linked_Version();
620 621 622 623
		if(linked->major > 1 || linked->minor > 2 || linked->patch > 9) {
			yuv.screen_width=sdl.initial_videoinfo.current_w;
			yuv.screen_height=sdl.initial_videoinfo.current_h;
		}
deuce's avatar
deuce committed
624 625
	}
#endif
626
	sdl_init_mode(3);
627 628
	if(yuv.enabled && yuv.overlay==NULL) {
		fprintf(stderr, "YUV Enabled, but overlay is NULL\n");
629
		sdl_init_good=0;
630
	}
631
	sdl_user_func_ret(SDL_USEREVENT_INIT);
632

deuce's avatar
deuce committed
633 634
	if(sdl_init_good) {
		cio_api.mode=fullscreen?CIOLIB_MODE_SDL_FULLSCREEN:CIOLIB_MODE_SDL;
deuce's avatar
deuce committed
635
#ifdef _WIN32
636
		FreeConsole();
637 638
#endif
#if !defined(NO_X) && defined(__unix__)
639
		dl=xp_dlopen(libnames,RTLD_LAZY|RTLD_GLOBAL,7);
640
		if(dl!=NULL) {
641
			sdl_x11available=TRUE;
642 643
			if(sdl_x11available && (sdl_x11.XFree=xp_dlsym(dl,XFree))==NULL) {
				xp_dlclose(dl);
644 645
				sdl_x11available=FALSE;
			}
646 647
			if(sdl_x11available && (sdl_x11.XGetSelectionOwner=xp_dlsym(dl,XGetSelectionOwner))==NULL) {
				xp_dlclose(dl);
648 649
				sdl_x11available=FALSE;
			}
650 651
			if(sdl_x11available && (sdl_x11.XConvertSelection=xp_dlsym(dl,XConvertSelection))==NULL) {
				xp_dlclose(dl);
652 653
				sdl_x11available=FALSE;
			}
654 655
			if(sdl_x11available && (sdl_x11.XGetWindowProperty=xp_dlsym(dl,XGetWindowProperty))==NULL) {
				xp_dlclose(dl);
656 657
				sdl_x11available=FALSE;
			}
658 659
			if(sdl_x11available && (sdl_x11.XChangeProperty=xp_dlsym(dl,XChangeProperty))==NULL) {
				xp_dlclose(dl);
660 661
				sdl_x11available=FALSE;
			}
662 663
			if(sdl_x11available && (sdl_x11.XSendEvent=xp_dlsym(dl,XSendEvent))==NULL) {
				xp_dlclose(dl);
664 665
				sdl_x11available=FALSE;
			}
666 667
			if(sdl_x11available && (sdl_x11.XSetSelectionOwner=xp_dlsym(dl,XSetSelectionOwner))==NULL) {
				xp_dlclose(dl);
668 669 670 671
				sdl_x11available=FALSE;
			}
		}
		if(sdl_x11available)
deuce's avatar
deuce committed
672
			sdl.EventState(SDL_SYSWMEVENT, SDL_ENABLE);
deuce's avatar
deuce committed
673
#endif
674
		return(0);
deuce's avatar
deuce committed
675
	}
676 677

	return(-1);
678 679 680 681 682 683 684
}

/* Called from main thread only */
int sdl_kbhit(void)
{
	int ret;

deuce's avatar
deuce committed
685
	sdl.mutexP(sdl_keylock);
686
	ret=(sdl_key!=sdl_keynext);
deuce's avatar
deuce committed
687
	sdl.mutexV(sdl_keylock);
688 689 690 691 692 693 694 695
	return(ret);
}

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

deuce's avatar
deuce committed
696 697
	sdl.SemWait(sdl_key_pending);
	sdl.mutexP(sdl_keylock);
698 699

	/* This always frees up space in keybuf for one more char */
700
	ch=sdl_keybuf[sdl_key++];
701
	/* If we have missed mouse keys, tack them on to the end of the buffer now */
702
	if(sdl_pending_mousekeys) {
703 704 705 706
		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;
707 708 709
        sdl.SemPost(sdl_key_pending);
		sdl_pending_mousekeys--;
	}
deuce's avatar
deuce committed
710
	sdl.mutexV(sdl_keylock);
711 712 713 714 715 716 717 718 719
	return(ch);
}

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

720 721 722 723 724 725 726
/* Called from main thread only (Passes Event) */
int sdl_setname(const char *name)
{
	sdl_user_func(SDL_USEREVENT_SETNAME,name);
	return(0);
}

727 728 729 730 731 732 733
/* 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);
}

734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
/* 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
750
	return(0);
751 752
}

753 754 755
int sdl_get_window_info(int *width, int *height, int *xpos, int *ypos)
{
	if(width)
deuce's avatar
deuce committed
756
		*width=win->h;
757
	if(height)
deuce's avatar
deuce committed
758
		*height=win->h;
759 760 761 762 763 764 765 766
	if(xpos)
		*xpos=-1;
	if(ypos)
		*ypos=-1;
	
	return(0);
}

deuce's avatar
deuce committed
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
/* Called from events thread only */
int sdl_setup_colours(SDL_Surface *surf)
{
	int i;
	int ret=0;
	SDL_Color	co[sizeof(dac_default)/sizeof(struct dac_colors)];

	for(i=0; i<(sizeof(dac_default)/sizeof(struct dac_colors)); i++) {
		co[i].r=dac_default[i].red;
		co[i].g=dac_default[i].green;
		co[i].b=dac_default[i].blue;
	}
	sdl.SetColors(surf, co, 0, sizeof(dac_default)/sizeof(struct dac_colors));

	for(i=0; i<(sizeof(dac_default)/sizeof(struct dac_colors)); i++) {
		sdl_dac_default[i]=sdl.MapRGB(win->format, co[i].r, co[i].g, co[i].b);
	}
	return(ret);
}

int sdl_setup_yuv_colours(void)
{
	int i;
	int ret=0;

	if(yuv.enabled) {
		for(i=0; i<(sizeof(dac_default)/sizeof(struct dac_colors)); i++) {
			RGBtoYUV(dac_default[i].red, dac_default[i].green, dac_default[i].blue, &(yuv.colours[i][0]), 0, 100);
		}
	}
	return(ret);
}

800 801 802 803 804 805 806 807 808 809 810 811 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 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894
void setup_surfaces(void)
{
	int		char_width=vstat.charwidth*vstat.cols*vstat.scaling;
	int		char_height=vstat.charheight*vstat.rows*vstat.scaling;
	int		flags=SDL_HWSURFACE|SDL_ANYFORMAT;
	SDL_Surface	*tmp_rect;
	SDL_Event	ev;

	if(fullscreen)
		flags |= SDL_FULLSCREEN;
	else
		flags |= SDL_RESIZABLE;

	if(yuv.enabled) {
		if(!yuv.win_width)
			yuv.win_width=vstat.charwidth*vstat.cols;
		if(!yuv.win_height)
			yuv.win_height=vstat.charheight*vstat.rows;
		if(fullscreen && yuv.screen_width && yuv.screen_height)
			win=sdl.SetVideoMode(yuv.screen_width,yuv.screen_height,0,flags);
		else
			win=sdl.SetVideoMode(yuv.win_width,yuv.win_height,0,flags);
	}
	else
		win=sdl.SetVideoMode(char_width,char_height,8,flags);

	if(win!=NULL) {
		if(new_rect)
			sdl.FreeSurface(new_rect);
		new_rect=NULL;
		tmp_rect=sdl.CreateRGBSurface(SDL_HWSURFACE
				, char_width
				, char_height
				, 8, 0, 0, 0, 0);
		if(tmp_rect) {
			if(yuv.enabled) {
				new_rect=tmp_rect;
			}
			else {
				new_rect=sdl.DisplayFormat(tmp_rect);
				sdl.FreeSurface(tmp_rect);
			}
		}
		if(yuv.enabled) {
			if(yuv.overlay) {
				sdl.UnlockYUVOverlay(yuv.overlay);
				sdl.mutexV(yuv.mutex);
				sdl.FreeYUVOverlay(yuv.overlay);
			}
			if(yuv.best_format==0) {
				yuv.overlay=sdl.CreateYUVOverlay(char_width,char_height, SDL_YV12_OVERLAY, win);
				if(yuv.overlay)
					yuv.best_format=yuv.overlay->format;
				if(yuv.overlay==NULL || !yuv.overlay->hw_overlay) {
					sdl.FreeYUVOverlay(yuv.overlay);
					yuv.overlay=sdl.CreateYUVOverlay(char_width,char_height, SDL_YUY2_OVERLAY, win);
					if(yuv.overlay)
						yuv.best_format=yuv.overlay->format;
					if(yuv.overlay==NULL || !yuv.overlay->hw_overlay) {
						sdl.FreeYUVOverlay(yuv.overlay);
						yuv.overlay=sdl.CreateYUVOverlay(char_width,char_height, SDL_YVYU_OVERLAY, win);
						if(yuv.overlay)
							yuv.best_format=yuv.overlay->format;
						if(yuv.overlay==NULL || !yuv.overlay->hw_overlay) {
							sdl.FreeYUVOverlay(yuv.overlay);
							yuv.overlay=sdl.CreateYUVOverlay(char_width,char_height, SDL_UYVY_OVERLAY, win);
							if(yuv.overlay)
								yuv.best_format=yuv.overlay->format;
							if(yuv.overlay==NULL || !yuv.overlay->hw_overlay) {
								sdl.FreeYUVOverlay(yuv.overlay);
								yuv.overlay=sdl.CreateYUVOverlay(char_width,char_height, SDL_IYUV_OVERLAY, win);
								if(yuv.overlay)
									yuv.best_format=yuv.overlay->format;
							}
						}
					}
				}
				if(yuv.overlay)
					sdl.FreeYUVOverlay(yuv.overlay);
			}
			yuv.overlay=sdl.CreateYUVOverlay(char_width,char_height, yuv.best_format, win);
			sdl.mutexP(yuv.mutex);
			sdl.LockYUVOverlay(yuv.overlay);
			sdl_setup_yuv_colours();
		}
		sdl_setup_colours(new_rect);
		sdl_setup_colours(win);
	}
	else if(sdl_init_good) {
		ev.type=SDL_QUIT;
		sdl_exitcode=1;
		sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, 0xffffffff);
	}
}

895 896 897 898 899
/* Called from event thread only */
void sdl_add_key(unsigned int keyval)
{
	if(keyval==0xa600) {
		fullscreen=!fullscreen;
900 901 902 903 904 905
		if(yuv.enabled)
			cio_api.mode=fullscreen?CIOLIB_MODE_SDL_YUV_FULLSCREEN:CIOLIB_MODE_SDL_YUV;
		else
			cio_api.mode=fullscreen?CIOLIB_MODE_SDL_FULLSCREEN:CIOLIB_MODE_SDL;
		setup_surfaces();
		force_redraws++;
906 907 908
		return;
	}
	if(keyval <= 0xffff) {
deuce's avatar
deuce committed
909
		sdl.mutexP(sdl_keylock);
910
		if(sdl_keynext+1==sdl_key) {
911
			beep();
deuce's avatar
deuce committed
912
			sdl.mutexV(sdl_keylock);
913 914 915
			return;
		}
		if((sdl_keynext+2==sdl_key) && keyval > 0xff) {
916
			if(keyval==CIO_KEY_MOUSE)
917
				sdl_pending_mousekeys+=2;
918
			else
919
				beep();
deuce's avatar
deuce committed
920
			sdl.mutexV(sdl_keylock);
921 922 923
			return;
		}
		sdl_keybuf[sdl_keynext++]=keyval & 0xff;
deuce's avatar
deuce committed
924
		sdl.SemPost(sdl_key_pending);
925 926
		if(keyval>0xff) {
			sdl_keybuf[sdl_keynext++]=keyval >> 8;
deuce's avatar
deuce committed
927
			sdl.SemPost(sdl_key_pending);
928
		}
deuce's avatar
deuce committed
929
		sdl.mutexV(sdl_keylock);
930 931 932
	}
}

933 934
unsigned int cp437_convert(unsigned int unicode)
{
935
	if(unicode < 0x80)
deuce's avatar
deuce committed
936
		return(unicode);
937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108