Newer
Older
#include <stdarg.h>
#include <stdio.h> /* NULL */
#include <string.h>
#include "gen_defs.h"
#include "genwrap.h"
#include "dirwrap.h"
#ifdef __unix__
#include <xp_dl.h>
#endif
#if (defined CIOLIB_IMPORTS)
#undef CIOLIB_IMPORTS
#endif
#if (defined CIOLIB_EXPORTS)
#undef CIOLIB_EXPORTS
#endif
#include "ciolib.h"
#include "utf8_codepages.h"
#include "vidmodes.h"
#define BITMAP_CIOLIB_DRIVER
#include "SDL.h"
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 */
SDL_Renderer *renderer=NULL;
SDL_Texture *texture=NULL;
pthread_mutex_t win_mutex;
sem_t sdl_ufunc_ret;
sem_t sdl_ufunc_rec;
pthread_mutex_t sdl_ufunc_mtx;
sem_t sdl_flush_sem;
pthread_mutex_t sdl_keylock;
sem_t sdl_key_pending;
static struct video_stats cvstat;
struct sdl_keyvals {
int keysym
,key
,shift
,ctrl
,alt;
};
static pthread_mutex_t sdl_headlock;
static struct rectlist *update_list = NULL;
static struct rectlist *update_list_tail = NULL;
SDL_USEREVENT_FLUSH
,SDL_USEREVENT_SETTITLE
,SDL_USEREVENT_SETNAME
,SDL_USEREVENT_SETVIDMODE
,SDL_USEREVENT_SHOWMOUSE
,SDL_USEREVENT_HIDEMOUSE
,SDL_USEREVENT_GETWINPOS
};
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},
{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},
{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},
{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},
{SDLK_KP_MULTIPLY, '*', '*', 0x9600, 0x3700},
{SDLK_KP_PLUS, '+', '+', 0x9000, 0x4e00},
{SDLK_KP_MINUS, '-', '-', 0x8e00, 0x4a00},
{SDLK_KP_PERIOD, 0x7f, 0x7f, 0x5300, 0x9300},
{SDLK_KP_DIVIDE, '/', '/', 0x9500, 0xa400},
{SDLK_KP_ENTER, 0x0d, 0x0d, 0x0a, 0xa600},
{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},
{SDLK_QUOTE, '\'', '"', 0, 0x2800},
{SDLK_COMMA, ',', '<', 0, 0x3300},
{SDLK_PERIOD, '.', '>', 0, 0x3400},
{SDLK_BACKQUOTE, '`', '~', 0, 0x2900},
{0, 0, 0, 0, 0} /** END **/
};
{
va_list argptr;
ev.type=SDL_USEREVENT;
ev.user.data1=NULL;
ev.user.data2=NULL;
ev.user.code=func;
pthread_mutex_lock(&sdl_ufunc_mtx);
switch(func) {
case SDL_USEREVENT_SETICON:
ev.user.data1=va_arg(argptr, void *);
if((ev.user.data2=(unsigned long *)malloc(sizeof(unsigned long)))==NULL) {
pthread_mutex_unlock(&sdl_ufunc_mtx);
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) {
pthread_mutex_unlock(&sdl_ufunc_mtx);
va_end(argptr);
return;
}
break;
case SDL_USEREVENT_MOUSEPOINTER:
ev.user.data1 = (void *)(intptr_t)va_arg(argptr, int);
break;
case SDL_USEREVENT_SHOWMOUSE:
case SDL_USEREVENT_HIDEMOUSE:
case SDL_USEREVENT_FLUSH:
break;
default:
while((rv = sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT))!=1)
YIELD();
break;
}
pthread_mutex_unlock(&sdl_ufunc_mtx);
/* Called from main thread only */
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);
pthread_mutex_lock(&sdl_ufunc_mtx);
/* Drain the swamp */
while(1) {
switch(func) {
case SDL_USEREVENT_GETWINPOS:
ev.user.data1 = va_arg(argptr, void *);
ev.user.data2 = va_arg(argptr, void *);
// Fallthrough
case SDL_USEREVENT_SETVIDMODE:
case SDL_USEREVENT_INIT:
case SDL_USEREVENT_QUIT:
while(sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)!=1)
YIELD();
break;
pthread_mutex_unlock(&sdl_ufunc_mtx);
rv = sem_wait(&sdl_ufunc_ret);
if(rv==0)
pthread_mutex_unlock(&sdl_ufunc_mtx);
va_end(argptr);
return(sdl_ufunc_retval);
}
void exit_sdl_con(void)
// Avoid calling exit(0) from an atexit() function...
ciolib_reaper = 0;
sdl_user_func_ret(SDL_USEREVENT_QUIT);
void sdl_copytext(const char *text, size_t buflen)
{
}
char *sdl_getcliptext(void)
{
uint8_t *u8;
u8 = (uint8_t *)sdl.GetClipboardText();
sdl.free(u8);
return ret;
void sdl_drawrect(struct rectlist *data)
data->next = NULL;
pthread_mutex_lock(&sdl_headlock);
if (update_list == NULL)
update_list = update_list_tail = data;
else {
update_list_tail->next = data;
update_list_tail = data;
pthread_mutex_unlock(&sdl_headlock);
sdl_user_func(SDL_USEREVENT_FLUSH);
int oldcols;
if (mode != CIOLIB_MODE_CUSTOM) {
pthread_mutex_lock(&vstatlock);
if (mode == vstat.mode) {
pthread_mutex_unlock(&vstatlock);
return 0;
}
pthread_mutex_unlock(&vstatlock);
}
sdl_user_func(SDL_USEREVENT_FLUSH);
pthread_mutex_lock(&blinker_lock);
bitmap_drv_init_mode(mode, &bitmap_width, &bitmap_height);
vstat.winwidth = ((double)cvstat.winwidth / (cvstat.cols * cvstat.charwidth)) * (vstat.cols * vstat.charwidth);
vstat.winheight = ((double)cvstat.winheight / (cvstat.rows * cvstat.charheight * cvstat.vmultiplier)) * (vstat.rows * vstat.charheight * vstat.vmultiplier);
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;
}
if (oldcols == 40) {
vstat.winheight /= 2;
}
if (vstat.cols == 40) {
vstat.winheight *= 2;
}
if (vstat.winwidth < vstat.charwidth * vstat.cols)
vstat.winwidth = vstat.charwidth * vstat.cols;
if (vstat.winheight < vstat.charheight * vstat.rows)
vstat.winheight = vstat.charheight * vstat.rows;
if(vstat.vmultiplier < 1)
vstat.vmultiplier = 1;
cvstat = vstat;
pthread_mutex_unlock(&vstatlock);
pthread_mutex_unlock(&blinker_lock);
sdl_user_func_ret(SDL_USEREVENT_SETVIDMODE);
return(0);
/* Called from main thread only (Passes Event) */
bitmap_drv_init(sdl_drawrect, sdl_flush);
if(mode==CIOLIB_MODE_SDL_FULLSCREEN)
fullscreen=1;
// Needs to be *after* bitmap_drv_init()
sem_post(&startsdl_sem);
sdl_user_func_ret(SDL_USEREVENT_INIT);
if(sdl_init_good) {
cio_api.mode=fullscreen?CIOLIB_MODE_SDL_FULLSCREEN:CIOLIB_MODE_SDL;
FreeConsole();
cio_api.options |= CONIO_OPT_PALETTE_SETTING | CONIO_OPT_SET_TITLE | CONIO_OPT_SET_NAME | CONIO_OPT_SET_ICON;
ciolib_reaper = 0;
sdl_user_func_ret(SDL_USEREVENT_QUIT);
void sdl_setwinsize_locked(int w, int h)
{
if (w > 16384)
w = 16384;
if (h > 16384)
h = 16384;
if (w < cvstat.charwidth * cvstat.cols)
w = cvstat.charwidth * cvstat.cols;
if (h < cvstat.charheight * cvstat.rows)
h = cvstat.charheight * cvstat.rows;
cvstat.winwidth = vstat.winwidth = w;
cvstat.winheight = vstat.winheight = h;
}
void sdl_setwinsize(int w, int h)
pthread_mutex_unlock(&vstatlock);
pthread_mutex_lock(&win_mutex);
pthread_mutex_unlock(&win_mutex);
}
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);
/* Called from main thread only */
int sdl_kbhit(void)
{
int ret;
pthread_mutex_lock(&sdl_keylock);
ret=(sdl_key!=sdl_keynext);
pthread_mutex_unlock(&sdl_keylock);
return(ret);
}
/* Called from main thread only */
int sdl_getch(void)
{
int ch;
sem_wait(&sdl_key_pending);
pthread_mutex_lock(&sdl_keylock);
/* This always frees up space in keybuf for one more char */
ch=sdl_keybuf[sdl_key++];
/* If we have missed mouse keys, tack them on to the end of the buffer now */
if(sdl_pending_mousekeys) {
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;
sem_post(&sdl_key_pending);
sdl_pending_mousekeys--;
}
pthread_mutex_unlock(&sdl_keylock);
return(ch);
}
/* Called from main thread only */
void sdl_textmode(int mode)
{
sdl_init_mode(mode);
}
/* Called from main thread only (Passes Event) */
int sdl_setname(const char *name)
{
sdl_user_func(SDL_USEREVENT_SETNAME,name);
return(0);
}
/* 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);
}
/* 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);
int sdl_get_window_info(int *width, int *height, int *xpos, int *ypos)
{
if (xpos || ypos) {
sdl_user_func_ret(SDL_USEREVENT_GETWINPOS, &wx, &wy);
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);
}
return(1);
SDL_Texture *newtexture;
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
flags |= SDL_WINDOW_RESIZABLE;
pthread_mutex_lock(&win_mutex);
charwidth = cvstat.charwidth;
charheight = cvstat.charheight;
cols = cvstat.cols;
rows = cvstat.rows;
vmultiplier = cvstat.vmultiplier;
if (win == NULL) {
// SDL2: This is slow sometimes... not sure why.
if (sdl.CreateWindowAndRenderer(cvstat.winwidth, cvstat.winheight, flags, &win, &renderer) == 0) {
sdl.RenderClear(renderer);
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, charwidth*cols, charheight*rows);
if (texture)
sdl.DestroyTexture(texture);
texture = newtexture;
}
else {
win = NULL;
renderer = NULL;
sdl.SetWindowMinimumSize(win, cvstat.charwidth * cvstat.cols, cvstat.charheight * cvstat.rows);
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, charwidth*cols, charheight*rows);
sdl.RenderClear(renderer);
if (texture)
sdl.DestroyTexture(texture);
texture = newtexture;
sdl.SetWindowMinimumSize(win, cvstat.charwidth * cvstat.cols, cvstat.charheight * cvstat.rows);
bitmap_drv_request_pixels();
}
else if(sdl_init_good) {
ev.type=SDL_QUIT;
sdl_exitcode=1;
sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
pthread_mutex_unlock(&win_mutex);
static void setup_surfaces(void)
{
pthread_mutex_lock(&vstatlock);
setup_surfaces_locked();
pthread_mutex_unlock(&vstatlock);
}
/* Called from event thread only */
{
if(keyval==0xa600) {
fullscreen=!fullscreen;
cio_api.mode=fullscreen?CIOLIB_MODE_SDL_FULLSCREEN:CIOLIB_MODE_SDL;
sdl.SetWindowFullscreen(win, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
return;
}
if(keyval <= 0xffff) {
pthread_mutex_lock(&sdl_keylock);
if(sdl_keynext+1==sdl_key) {
pthread_mutex_unlock(&sdl_keylock);
return;
}
if((sdl_keynext+2==sdl_key) && keyval > 0xff) {
if(keyval==CIO_KEY_MOUSE)
sdl_pending_mousekeys+=2;
else
pthread_mutex_unlock(&sdl_keylock);
return;
}
sdl_keybuf[sdl_keynext++]=keyval & 0xff;
sem_post(&sdl_key_pending);
if(keyval>0xff) {
sdl_keybuf[sdl_keynext++]=keyval >> 8;
sem_post(&sdl_key_pending);
pthread_mutex_unlock(&sdl_keylock);
}
}
/* Called from event thread only */
static unsigned int sdl_get_char_code(unsigned int keysym, unsigned int mod)
/* We don't handle META */
if (mod & KMOD_GUI)
return(0x0001ffff);
/* Glah! */
if(keysym==0x7f && !(mod & KMOD_CTRL)) {
keysym=0x08;
/* Find the SDL keysym */
for(i=0;sdl_keyval[i].keysym;i++) {
if(sdl_keyval[i].keysym==keysym) {
/* KeySym found in table */
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);
/* AltGr apparently... give up */
return(0x0001ffff);
return(expect);
* Well, we can't find it in our table, or it's a regular key.
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;
}
/* Give up. It's not working out for us. */
return(0x0001ffff);
static void
sdl_add_keys(uint8_t *utf8s)
{
char *chars;
char *p;
chars = utf8_to_cp(getcodepage(), utf8s, '\x00', strlen((char *)utf8s), NULL);
if (chars) {
for (p = chars; *p; p++) {
sdl_add_key(*((uint8_t *)p));
}
free(chars);
}
}
/* Mouse event/keyboard thread */
while(1) {
if(mouse_wait())
sdl_add_key(CIO_KEY_MOUSE);
}
}
int ret;
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);
int ret;
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);
{
SDL_Event ev;
int old_w, old_h;
int block_text = 0;
pthread_mutex_lock(&vstatlock);
old_w = cvstat.winwidth;
old_h = cvstat.winheight;
pthread_mutex_unlock(&vstatlock);
while(1) {
if(sdl.WaitEventTimeout(&ev, 1)!=1) {
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);
}
else {
switch (ev.type) {
case SDL_KEYDOWN: /* Keypress */
if ((ev.key.keysym.mod & (KMOD_CTRL|KMOD_ALT|KMOD_GUI)) && !(ev.key.keysym.mod & KMOD_MODE)) {
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
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;
pthread_mutex_lock(&vstatlock);
w = cvstat.winwidth;
h = cvstat.winheight;
switch(ev.key.keysym.sym) {
case SDLK_LEFT:
if (w % (cvstat.charwidth * cvstat.cols)) {
w = w - w % (cvstat.charwidth * cvstat.cols);
}
else {
w -= (cvstat.charwidth * cvstat.cols);
if (w < (cvstat.charwidth * cvstat.cols))
w = cvstat.charwidth * cvstat.cols;
}
break;
case SDLK_RIGHT:
w = (w - w % (cvstat.charwidth * cvstat.cols)) + (cvstat.charwidth * cvstat.cols);
break;
case SDLK_UP:
if (h % (cvstat.charheight * cvstat.rows * cvstat.vmultiplier)) {
h = h - h % (cvstat.charheight * cvstat.rows * cvstat.vmultiplier);
}
else {
h -= (cvstat.charheight * cvstat.rows * cvstat.vmultiplier);
if (h < (cvstat.charheight * cvstat.rows * cvstat.vmultiplier))
h = cvstat.charheight * cvstat.rows * cvstat.vmultiplier;
}
break;
case SDLK_DOWN:
h = (h - h % (cvstat.charheight * cvstat.rows * cvstat.vmultiplier)) + (cvstat.charheight * cvstat.rows * cvstat.vmultiplier);
break;
}
if (w > 16384 || h > 16384)
beep();
else {
cvstat.winwidth = w;
cvstat.winheight = h;
}
pthread_mutex_unlock(&vstatlock);
break;
if (block_text || ev.key.keysym.sym < 0 || ev.key.keysym.sym > 127) {
// NUMLOCK makes
if ((ev.key.keysym.mod & KMOD_NUM) && ((ev.key.keysym.sym >= SDLK_KP_1 && ev.key.keysym.sym <= SDLK_KP_0) || ev.key.keysym.sym == SDLK_KP_PERIOD))
break;
sdl_add_key(sdl_get_char_code(ev.key.keysym.sym, ev.key.keysym.mod));
}
else if (!isprint(ev.key.keysym.sym)) {
sdl_add_key(ev.key.keysym.sym);
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;
break;
case SDL_MOUSEMOTION:
if(!ciolib_mouse_initialized)
ciomouse_gotevent(CIOLIB_MOUSE_MOVE,win_to_text_xpos(ev.motion.x),win_to_text_ypos(ev.motion.y));
break;
case SDL_MOUSEBUTTONDOWN:
if(!ciolib_mouse_initialized)
switch(ev.button.button) {
case SDL_BUTTON_LEFT:
ciomouse_gotevent(CIOLIB_BUTTON_PRESS(1),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y));
break;
case SDL_BUTTON_MIDDLE:
ciomouse_gotevent(CIOLIB_BUTTON_PRESS(2),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y));
break;
case SDL_BUTTON_RIGHT:
ciomouse_gotevent(CIOLIB_BUTTON_PRESS(3),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y));
break;
case SDL_MOUSEWHEEL:
if (!ciolib_mouse_initialized)
break;
if (ev.wheel.y) {
#if (SDL_MINOR_VERSION > 0) || (SDL_PATCHLEVEL > 3)
if (ev.wheel.direction == SDL_MOUSEWHEEL_FLIPPED)
ev.wheel.y = 0 - ev.wheel.y;
if (ev.wheel.y > 0)
ciomouse_gotevent(CIOLIB_BUTTON_PRESS(4), -1, -1);
if (ev.wheel.y < 0)
ciomouse_gotevent(CIOLIB_BUTTON_PRESS(5), -1, -1);
}
break;
case SDL_MOUSEBUTTONUP:
if(!ciolib_mouse_initialized)
switch(ev.button.button) {
case SDL_BUTTON_LEFT:
ciomouse_gotevent(CIOLIB_BUTTON_RELEASE(1),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y));
break;
case SDL_BUTTON_MIDDLE:
ciomouse_gotevent(CIOLIB_BUTTON_RELEASE(2),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y));
break;
case SDL_BUTTON_RIGHT:
ciomouse_gotevent(CIOLIB_BUTTON_RELEASE(3),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y));
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)
sdl_user_func(SDL_USEREVENT_QUIT);
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:
{
// SDL2: Something resized window
const char *newh;
if ((ev.window.data1 % (cvstat.charwidth * cvstat.cols)) || (ev.window.data2 % (cvstat.charheight * cvstat.rows)))
newh = "2";
else
newh = "0";
pthread_mutex_lock(&win_mutex);
if (ev.window.event == SDL_WINDOWEVENT_RESIZED)
sdl.GetWindowSize(win, &cvstat.winwidth, &cvstat.winheight);
if (strcmp(newh, sdl.GetHint(SDL_HINT_RENDER_SCALE_QUALITY))) {
SDL_Texture *newtexture;
sdl.SetHint(SDL_HINT_RENDER_SCALE_QUALITY, newh);
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cvstat.charwidth*cvstat.cols, cvstat.charheight*cvstat.rows);
sdl.RenderClear(renderer);
if (texture)
sdl.DestroyTexture(texture);
texture = newtexture;
bitmap_drv_request_pixels();
}
pthread_mutex_unlock(&win_mutex);
break;
case SDL_WINDOWEVENT_EXPOSED:
break;
}
break;
case SDL_USEREVENT: {
struct rectlist *list;
struct rectlist *old_next;
switch(ev.user.code) {
case SDL_USEREVENT_QUIT:
sdl_ufunc_retval=0;
if (ciolib_reaper)
exit(0);
sem_post(&sdl_ufunc_ret);
case SDL_USEREVENT_FLUSH:
pthread_mutex_lock(&win_mutex);
pthread_mutex_lock(&sdl_headlock);
list = update_list;
update_list = update_list_tail = NULL;
pthread_mutex_unlock(&sdl_headlock);
if (list->next == NULL) {
src.x = 0;
src.y = 0;
src.w = list->rect.width;
src.h = list->rect.height;
sdl.QueryTexture(texture, NULL, NULL, &tw, &th);
sdl.LockTexture(texture, &src, &pixels, &pitch);
if (pitch != list->rect.width * sizeof(list->data[0])) {
// If this happens, we need to copy a row at a time...
for (row = 0; row < list->rect.height && row < th; row++) {
if (pitch < list->rect.width * sizeof(list->data[0]))
memcpy(pixels, &list->data[list->rect.width * row], pitch);
else
memcpy(pixels, &list->data[list->rect.width * row], list->rect.width * sizeof(list->data[0]));
pixels = (void *)((char*)pixels + pitch);
}
}
else {
int ch = list->rect.height;
if (ch > th)
ch = th;
memcpy(pixels, list->data, list->rect.width * ch * sizeof(list->data[0]));
}
sdl.RenderCopy(renderer, texture, &src, NULL);
bitmap_drv_free_rect(list);
sdl.RenderPresent(renderer);
}
pthread_mutex_unlock(&win_mutex);
break;
case SDL_USEREVENT_SETNAME:
pthread_mutex_lock(&win_mutex);
sdl.SetWindowTitle(win, (char *)ev.user.data1);
pthread_mutex_unlock(&win_mutex);
free(ev.user.data1);
break;
case SDL_USEREVENT_SETICON:
if(sdl_icon != NULL)
sdl.FreeSurface(sdl_icon);
sdl_icon=sdl.CreateRGBSurfaceFrom(ev.user.data1
, *(unsigned long *)ev.user.data2
, *(unsigned long *)ev.user.data2
, 32
, *(unsigned long *)ev.user.data2*4
, *(DWORD *)"\377\0\0\0"
, *(DWORD *)"\0\377\0\0"
, *(DWORD *)"\0\0\377\0"
, *(DWORD *)"\0\0\0\377"
);
pthread_mutex_lock(&win_mutex);
sdl.SetWindowIcon(win, sdl_icon);
pthread_mutex_unlock(&win_mutex);
free(ev.user.data2);
break;
case SDL_USEREVENT_SETTITLE:
pthread_mutex_lock(&win_mutex);
sdl.SetWindowTitle(win, (char *)ev.user.data1);
pthread_mutex_unlock(&win_mutex);
free(ev.user.data1);
break;
case SDL_USEREVENT_SETVIDMODE:
pthread_mutex_lock(&vstatlock);
setup_surfaces_locked();
old_w = cvstat.winwidth;
old_h = cvstat.winheight;
pthread_mutex_unlock(&vstatlock);
sem_post(&sdl_ufunc_ret);
break;
case SDL_USEREVENT_HIDEMOUSE:
sdl.ShowCursor(SDL_DISABLE);
break;
case SDL_USEREVENT_SHOWMOUSE:
sdl.ShowCursor(SDL_ENABLE);
break;
case SDL_USEREVENT_INIT:
if(!sdl_init_good) {
if(sdl.WasInit(SDL_INIT_VIDEO)==SDL_INIT_VIDEO) {
pthread_mutex_lock(&win_mutex);
pthread_mutex_unlock(&win_mutex);
}
sdl_ufunc_retval=0;
sem_post(&sdl_ufunc_ret);
case SDL_USEREVENT_GETWINPOS:
sdl.GetWindowPosition(win, ev.user.data1, ev.user.data2);
sem_post(&sdl_ufunc_ret);
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
break;
case SDL_USEREVENT_MOUSEPOINTER:
{
int cid = INT_MIN;
SDL_Cursor *oc = curs;
switch((intptr_t)ev.user.data1) {
case CIOLIB_MOUSEPTR_ARROW:
break; // Default
case CIOLIB_MOUSEPTR_BAR:
cid = SDL_SYSTEM_CURSOR_IBEAM;
break;
}
if (cid == INT_MIN) {
sdl.SetCursor(sdl.GetDefaultCursor());
curs = NULL;
}
else {
curs = sdl.CreateSystemCursor(cid);
if (curs == NULL)
sdl.SetCursor(sdl.GetDefaultCursor());
else
sdl.SetCursor(curs);
}
if (oc)
sdl.FreeCursor(oc);
break;
}
}
break;
}
case SDL_SYSWMEVENT: /* ToDo... This is where Copy/Paste needs doing */
/* Ignore this stuff */
case SDL_JOYAXISMOTION:
case SDL_JOYBALLMOTION:
case SDL_JOYHATMOTION:
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
default:
break;
}
}
}
int sdl_initciolib(int mode)
{
#if defined(__DARWIN__)
if (initsdl_ret) {
#else
if(init_sdl_video()) {
fprintf(stderr,"SDL Video Initialization Failed\n");
return(-1);
sem_init(&sdl_key_pending, 0, 0);
sem_init(&sdl_ufunc_ret, 0, 0);
sem_init(&sdl_ufunc_rec, 0, 0);
pthread_mutex_init(&sdl_ufunc_mtx, NULL);
pthread_mutex_init(&sdl_headlock, NULL);
pthread_mutex_init(&win_mutex, NULL);
pthread_mutex_init(&sdl_keylock, NULL);
return(sdl_init(mode));
}
void
sdl_beep(void)
{
static unsigned char wave[2206];
if (wave[2205] == 0) {
xptone_makewave(440, wave, 2205, WAVE_SHAPE_SINE_SAW_HARM);
wave[2205] = 1;
}
xp_play_sample(wave, 2205, TRUE);
}