shithub: npe

Download patch

ref: 4ded9d708d8caec3b5b1c48c8887e8e3a838d669
parent: 1882a2e5945c9003187dd2b9a897572eee32a9e7
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Thu Mar 18 12:04:58 EDT 2021

sdl2: reorganize more, fix audio opening too late

--- a/include/npe/SDL2/SDL.h
+++ b/include/npe/SDL2/SDL.h
@@ -8,7 +8,6 @@
 #pragma lib "libnpe_sdl2.a"
 
 #include <npe.h>
-#include <keyboard.h>
 
 typedef u8int Uint8;
 typedef u16int Uint16;
@@ -15,7 +14,10 @@
 typedef u32int Uint32;
 typedef enum {SDL_FALSE, SDL_TRUE} SDL_bool;
 
-#include "SDL2/SDL_audio.h"
+#include <SDL2/SDL_keycode.h>
+#include <SDL2/SDL_scancode.h>
+#include <SDL2/SDL_audio.h>
+#include <SDL2/SDL_events.h>
 
 typedef struct SDL_Window SDL_Window;
 typedef struct SDL_Renderer SDL_Renderer;
@@ -22,10 +24,6 @@
 typedef struct SDL_Texture SDL_Texture;
 typedef struct SDL_Surface SDL_Surface;
 typedef struct SDL_Rect SDL_Rect;
-typedef int SDL_Keycode;
-typedef int SDL_Scancode;
-typedef int SDL_Keymod;
-typedef struct SDL_Event SDL_Event;
 typedef int SDL_BlendMode;
 typedef struct SDL_Thread SDL_Thread;
 typedef int (*SDL_ThreadFunction)(void *);
@@ -50,7 +48,6 @@
 SDL_bool SDL_HasSSE(void);
 SDL_bool SDL_HasSSE2(void);
 int SDL_Init(int);
-int SDL_EventState(Uint32, int);
 SDL_Keymod SDL_GetModState(void);
 int SDL_ShowCursor(int toggle);
 u64int SDL_GetPerformanceFrequency(void);
@@ -62,7 +59,6 @@
 int SDL_SetClipboardText(char *);
 void SDL_SetThreadPriority(int);
 SDL_bool SDL_HasClipboardText(void);
-int SDL_PollEvent(SDL_Event *event);
 void SDL_RestoreWindow(SDL_Window *window);
 void SDL_RaiseWindow(SDL_Window *window);
 int SDL_UpdateTexture(SDL_Texture *texture, SDL_Rect *rect, void *pixels, int pitch);
@@ -84,7 +80,6 @@
 int SDL_UnlockSurface(SDL_Surface *surface);
 int SDL_SetSurfaceBlendMode(SDL_Surface *surface, SDL_BlendMode blendMode);
 SDL_Cursor *SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y);
-int SDL_PushEvent(SDL_Event *event);
 void SDL_WarpMouseInWindow(SDL_Window *window, int x, int y);
 void SDL_RenderGetScale(SDL_Renderer *renderer, float *scaleX, float *scaleY);
 void SDL_GetWindowSize(SDL_Window *window, int *w, int *h);
@@ -171,8 +166,6 @@
 	SDL_RENDERER_ACCELERATED = 0,
 	SDL_RENDERER_PRESENTVSYNC = 0,
 
-	SDL_TEXTINPUTEVENT_TEXT_SIZE = UTFmax,
-
 	/* FIXME steal from rio and add missing? */
 	SDL_SYSTEM_CURSOR_ARROW = 0,
 	SDL_SYSTEM_CURSOR_IBEAM,
@@ -186,215 +179,6 @@
 };
 
 enum {
-	/* these HAVE to be in this order for notes to work in ft2-clone */
-	SDL_SCANCODE_UNKNOWN,
-	SDL_SCANCODE_A = 0x04,
-	SDL_SCANCODE_B,
-	SDL_SCANCODE_C,
-	SDL_SCANCODE_D,
-	SDL_SCANCODE_E,
-	SDL_SCANCODE_F,
-	SDL_SCANCODE_G,
-	SDL_SCANCODE_H,
-	SDL_SCANCODE_I,
-	SDL_SCANCODE_J,
-	SDL_SCANCODE_K,
-	SDL_SCANCODE_L,
-	SDL_SCANCODE_M,
-	SDL_SCANCODE_N,
-	SDL_SCANCODE_O,
-	SDL_SCANCODE_P,
-	SDL_SCANCODE_Q,
-	SDL_SCANCODE_R,
-	SDL_SCANCODE_S,
-	SDL_SCANCODE_T,
-	SDL_SCANCODE_U,
-	SDL_SCANCODE_V,
-	SDL_SCANCODE_W,
-	SDL_SCANCODE_X,
-	SDL_SCANCODE_Y,
-	SDL_SCANCODE_Z,
-	SDL_SCANCODE_1,
-	SDL_SCANCODE_2,
-	SDL_SCANCODE_3,
-	SDL_SCANCODE_4,
-	SDL_SCANCODE_5,
-	SDL_SCANCODE_6,
-	SDL_SCANCODE_7,
-	SDL_SCANCODE_8,
-	SDL_SCANCODE_9,
-	SDL_SCANCODE_0,
-	SDL_SCANCODE_RETURN,
-	SDL_SCANCODE_ESCAPE,
-	SDL_SCANCODE_BACKSPACE,
-	SDL_SCANCODE_TAB,
-	SDL_SCANCODE_SPACE,
-	SDL_SCANCODE_MINUS,
-	SDL_SCANCODE_EQUALS,
-	SDL_SCANCODE_LEFTBRACKET,
-	SDL_SCANCODE_RIGHTBRACKET,
-	SDL_SCANCODE_BACKSLASH,
-	SDL_SCANCODE_NONUSHASH,
-	SDL_SCANCODE_SEMICOLON,
-	SDL_SCANCODE_APOSTROPHE,
-	SDL_SCANCODE_GRAVE,
-	SDL_SCANCODE_SLASH,
-	SDL_SCANCODE_CAPSLOCK,
-	SDL_SCANCODE_F1,
-	SDL_SCANCODE_F2,
-	SDL_SCANCODE_F3,
-	SDL_SCANCODE_F4,
-	SDL_SCANCODE_F5,
-	SDL_SCANCODE_F6,
-	SDL_SCANCODE_F7,
-	SDL_SCANCODE_F8,
-	SDL_SCANCODE_F9,
-	SDL_SCANCODE_F10,
-	SDL_SCANCODE_F11,
-	SDL_SCANCODE_F12,
-	SDL_SCANCODE_PRINTSCREEN,
-	SDL_SCANCODE_SCROLLLOCK,
-	SDL_SCANCODE_PAUSE,
-	SDL_SCANCODE_INSERT,
-	SDL_SCANCODE_HOME,
-	SDL_SCANCODE_PAGEUP,
-	SDL_SCANCODE_DELETE,
-	SDL_SCANCODE_END,
-	SDL_SCANCODE_PAGEDOWN,
-	SDL_SCANCODE_RIGHT,
-	SDL_SCANCODE_LEFT,
-	SDL_SCANCODE_DOWN,
-	SDL_SCANCODE_UP,
-	SDL_SCANCODE_NUMLOCKCLEAR,
-	SDL_SCANCODE_KP_DIVIDE,
-	SDL_SCANCODE_KP_MULTIPLY,
-	SDL_SCANCODE_KP_MINUS,
-	SDL_SCANCODE_KP_PLUS,
-	SDL_SCANCODE_KP_ENTER,
-	SDL_SCANCODE_KP_1,
-	SDL_SCANCODE_KP_2,
-	SDL_SCANCODE_KP_3,
-	SDL_SCANCODE_KP_4,
-	SDL_SCANCODE_KP_5,
-	SDL_SCANCODE_KP_6,
-	SDL_SCANCODE_KP_7,
-	SDL_SCANCODE_KP_8,
-	SDL_SCANCODE_KP_9,
-	SDL_SCANCODE_KP_0,
-	SDL_SCANCODE_KP_PERIOD,
-	SDL_SCANCODE_NONUSBACKSLASH,
-
-	SDL_SCANCODE_MENU = 0x76,
-
-	SDL_SCANCODE_MUTE = 0x7f,
-	SDL_SCANCODE_VOLUMEUP,
-	SDL_SCANCODE_VOLUMEDOWN,
-
-	SDL_SCANCODE_LCTRL = 0xe0,
-	SDL_SCANCODE_LSHIFT,
-	SDL_SCANCODE_LALT,
-	SDL_SCANCODE_LGUI,
-	SDL_SCANCODE_RCTRL,
-	SDL_SCANCODE_RSHIFT,
-	SDL_SCANCODE_RALT,
-	SDL_SCANCODE_RGUI,
-
-	SDL_SCANCODE_MODE = 0x101,
-	SDL_SCANCODE_AUDIOMUTE = 0x106,
-
-	SDLK_a = 'a',
-	SDLK_b,
-	SDLK_c,
-	SDLK_d,
-	SDLK_e,
-	SDLK_f,
-	SDLK_g,
-	SDLK_h,
-	SDLK_i,
-	SDLK_j,
-	SDLK_k,
-	SDLK_l,
-	SDLK_m,
-	SDLK_n,
-	SDLK_o,
-	SDLK_p,
-	SDLK_q,
-	SDLK_r,
-	SDLK_s,
-	SDLK_t,
-	SDLK_u,
-	SDLK_v,
-	SDLK_w,
-	SDLK_x,
-	SDLK_y,
-	SDLK_z,
-	SDLK_0 = '0',
-	SDLK_1,
-	SDLK_2,
-	SDLK_3,
-	SDLK_4,
-	SDLK_5,
-	SDLK_6,
-	SDLK_7,
-	SDLK_8,
-	SDLK_9,
-	SDLK_DELETE = Kdel,
-	SDLK_RETURN = '\n',
-	SDLK_ESCAPE = Kesc,
-	SDLK_LESS = '<',
-	SDLK_SPACE = ' ',
-	SDLK_TAB = '\t',
-	SDLK_LEFT = Kleft,
-	SDLK_RIGHT = Kright,
-	SDLK_DOWN = Kdown,
-	SDLK_UP = Kup,
-	SDLK_F1 = KF|1,
-	SDLK_F2,
-	SDLK_F3,
-	SDLK_F4,
-	SDLK_F5,
-	SDLK_F6,
-	SDLK_F7,
-	SDLK_F8,
-	SDLK_F9,
-	SDLK_F10,
-	SDLK_F11,
-	SDLK_F12,
-	SDLK_INSERT = Kins,
-	SDLK_PAGEUP = Kpgup,
-	SDLK_PAGEDOWN = Kpgdown,
-	SDLK_HOME = Khome,
-	SDLK_END = Kend,
-	SDLK_BACKSPACE = Kbs,
-	SDLK_MINUS = '-',
-	SDLK_PLUS = '+',
-	SDLK_EQUALS = '=',
-	SDLK_UNDERSCORE = '_',
-
-	SDLK_LALT = Kalt,
-	SDLK_RALT = Kaltgr, /* FIXME what about keyboards without it? */
-	/* FIXME no distinction */
-	SDLK_LSHIFT = Kshift,
-	SDLK_RSHIFT = SDLK_LSHIFT,
-	SDLK_LCTRL = Kctl,
-	SDLK_RCTRL = '>', /* FIXME this is a hack */
-
-	/* FIXME not bound to anything */
-	SDLK_UNKNOWN = -99999,
-	SDLK_CAPSLOCK,
-	SDLK_KP_ENTER,
-
-	/* FIXME no distinction */
-	KMOD_LSHIFT = 1<<0,
-	KMOD_RSHIFT = KMOD_LSHIFT,
-	KMOD_LCTRL = 1<<1,
-	KMOD_RCTRL = KMOD_LCTRL,
-	KMOD_LALT = 1<<2,
-	KMOD_RALT = KMOD_LALT,
-	KMOD_LGUI = 1<<3,
-	KMOD_RGUI = KMOD_LGUI,
-	KMOD_CAPS = 1<<4,
-
 	SDL_KEYDOWN = 0,
 	SDL_KEYUP,
 	SDL_MOUSEBUTTONDOWN,
@@ -442,38 +226,6 @@
 	int w, h;
 	int pitch;
 	uchar pixels[];
-};
-
-struct SDL_Event {
-	int type;
-	union {
-		struct {
-			int event;
-		}window;
-		struct {
-			struct {
-				SDL_Scancode scancode;
-				SDL_Keycode sym;
-			}keysym;
-			int repeat;
-		}key;
-		struct {
-			int x, y;
-			int button;
-		}button;
-		struct {
-			int x, y;
-		}motion;
-		struct {
-			char text[SDL_TEXTINPUTEVENT_TEXT_SIZE+1];
-		}text;
-		struct {
-			int x, y;
-		}wheel;
-		struct {
-			char *file;
-		}drop;
-	};
 };
 
 struct SDL_DisplayMode
--- /dev/null
+++ b/include/npe/SDL2/SDL_events.h
@@ -1,0 +1,46 @@
+#ifndef _npe_SDL_events_h_
+#define _npe_SDL_events_h_
+
+enum {
+	SDL_TEXTINPUTEVENT_TEXT_SIZE = UTFmax,
+};
+
+typedef struct SDL_Event SDL_Event;
+
+struct SDL_Event {
+	int type;
+	union {
+		struct {
+			int event;
+		}window;
+		struct {
+			struct {
+				SDL_Scancode scancode;
+				SDL_Keycode sym;
+			}keysym;
+			int repeat;
+		}key;
+		struct {
+			int x, y;
+			int button;
+		}button;
+		struct {
+			int x, y;
+		}motion;
+		struct {
+			char text[SDL_TEXTINPUTEVENT_TEXT_SIZE+1];
+		}text;
+		struct {
+			int x, y;
+		}wheel;
+		struct {
+			char *file;
+		}drop;
+	};
+};
+
+int SDL_EventState(Uint32, int);
+int SDL_PollEvent(SDL_Event *event);
+int SDL_PushEvent(SDL_Event *event);
+
+#endif
--- /dev/null
+++ b/include/npe/SDL2/SDL_keycode.h
@@ -1,0 +1,105 @@
+#ifndef _npe_SDL_keycode_h_
+#define _npe_SDL_keycode_h_
+
+#include <keyboard.h>
+
+typedef int SDL_Keycode;
+typedef int SDL_Keymod;
+
+enum {
+	SDLK_a = 'a',
+	SDLK_b,
+	SDLK_c,
+	SDLK_d,
+	SDLK_e,
+	SDLK_f,
+	SDLK_g,
+	SDLK_h,
+	SDLK_i,
+	SDLK_j,
+	SDLK_k,
+	SDLK_l,
+	SDLK_m,
+	SDLK_n,
+	SDLK_o,
+	SDLK_p,
+	SDLK_q,
+	SDLK_r,
+	SDLK_s,
+	SDLK_t,
+	SDLK_u,
+	SDLK_v,
+	SDLK_w,
+	SDLK_x,
+	SDLK_y,
+	SDLK_z,
+	SDLK_0 = '0',
+	SDLK_1,
+	SDLK_2,
+	SDLK_3,
+	SDLK_4,
+	SDLK_5,
+	SDLK_6,
+	SDLK_7,
+	SDLK_8,
+	SDLK_9,
+	SDLK_DELETE = Kdel,
+	SDLK_RETURN = '\n',
+	SDLK_ESCAPE = Kesc,
+	SDLK_LESS = '<',
+	SDLK_SPACE = ' ',
+	SDLK_TAB = '\t',
+	SDLK_LEFT = Kleft,
+	SDLK_RIGHT = Kright,
+	SDLK_DOWN = Kdown,
+	SDLK_UP = Kup,
+	SDLK_F1 = KF|1,
+	SDLK_F2,
+	SDLK_F3,
+	SDLK_F4,
+	SDLK_F5,
+	SDLK_F6,
+	SDLK_F7,
+	SDLK_F8,
+	SDLK_F9,
+	SDLK_F10,
+	SDLK_F11,
+	SDLK_F12,
+
+	SDLK_INSERT = Kins,
+	SDLK_PAGEUP = Kpgup,
+	SDLK_PAGEDOWN = Kpgdown,
+	SDLK_HOME = Khome,
+	SDLK_END = Kend,
+	SDLK_BACKSPACE = Kbs,
+	SDLK_MINUS = '-',
+	SDLK_PLUS = '+',
+	SDLK_EQUALS = '=',
+	SDLK_UNDERSCORE = '_',
+
+	SDLK_LALT = Kalt,
+	SDLK_RALT = Kaltgr, /* FIXME what about keyboards without it? */
+	/* FIXME no distinction */
+	SDLK_LSHIFT = Kshift,
+	SDLK_RSHIFT = SDLK_LSHIFT,
+	SDLK_LCTRL = Kctl,
+	SDLK_RCTRL = '>', /* FIXME this is a hack */
+
+	/* FIXME not bound to anything */
+	SDLK_UNKNOWN = -99999,
+	SDLK_CAPSLOCK,
+	SDLK_KP_ENTER,
+
+	/* FIXME no distinction */
+	KMOD_LSHIFT = 1<<0,
+	KMOD_RSHIFT = KMOD_LSHIFT,
+	KMOD_LCTRL = 1<<1,
+	KMOD_RCTRL = KMOD_LCTRL,
+	KMOD_LALT = 1<<2,
+	KMOD_RALT = KMOD_LALT,
+	KMOD_LGUI = 1<<3,
+	KMOD_RGUI = KMOD_LGUI,
+	KMOD_CAPS = 1<<4,
+};
+
+#endif
--- /dev/null
+++ b/include/npe/SDL2/SDL_scancode.h
@@ -1,0 +1,124 @@
+#ifndef _npe_SDL_scancode_h_
+#define _npe_SDL_scancode_h_
+
+typedef int SDL_Scancode;
+
+enum {
+	/* these HAVE to be in this order for notes to work in ft2-clone */
+	SDL_SCANCODE_UNKNOWN,
+	SDL_SCANCODE_A = 0x04,
+	SDL_SCANCODE_B,
+	SDL_SCANCODE_C,
+	SDL_SCANCODE_D,
+	SDL_SCANCODE_E,
+	SDL_SCANCODE_F,
+	SDL_SCANCODE_G,
+	SDL_SCANCODE_H,
+	SDL_SCANCODE_I,
+	SDL_SCANCODE_J,
+	SDL_SCANCODE_K,
+	SDL_SCANCODE_L,
+	SDL_SCANCODE_M,
+	SDL_SCANCODE_N,
+	SDL_SCANCODE_O,
+	SDL_SCANCODE_P,
+	SDL_SCANCODE_Q,
+	SDL_SCANCODE_R,
+	SDL_SCANCODE_S,
+	SDL_SCANCODE_T,
+	SDL_SCANCODE_U,
+	SDL_SCANCODE_V,
+	SDL_SCANCODE_W,
+	SDL_SCANCODE_X,
+	SDL_SCANCODE_Y,
+	SDL_SCANCODE_Z,
+	SDL_SCANCODE_1,
+	SDL_SCANCODE_2,
+	SDL_SCANCODE_3,
+	SDL_SCANCODE_4,
+	SDL_SCANCODE_5,
+	SDL_SCANCODE_6,
+	SDL_SCANCODE_7,
+	SDL_SCANCODE_8,
+	SDL_SCANCODE_9,
+	SDL_SCANCODE_0,
+	SDL_SCANCODE_RETURN,
+	SDL_SCANCODE_ESCAPE,
+	SDL_SCANCODE_BACKSPACE,
+	SDL_SCANCODE_TAB,
+	SDL_SCANCODE_SPACE,
+	SDL_SCANCODE_MINUS,
+	SDL_SCANCODE_EQUALS,
+	SDL_SCANCODE_LEFTBRACKET,
+	SDL_SCANCODE_RIGHTBRACKET,
+	SDL_SCANCODE_BACKSLASH,
+	SDL_SCANCODE_NONUSHASH,
+	SDL_SCANCODE_SEMICOLON,
+	SDL_SCANCODE_APOSTROPHE,
+	SDL_SCANCODE_GRAVE,
+	SDL_SCANCODE_SLASH,
+	SDL_SCANCODE_CAPSLOCK,
+	SDL_SCANCODE_F1,
+	SDL_SCANCODE_F2,
+	SDL_SCANCODE_F3,
+	SDL_SCANCODE_F4,
+	SDL_SCANCODE_F5,
+	SDL_SCANCODE_F6,
+	SDL_SCANCODE_F7,
+	SDL_SCANCODE_F8,
+	SDL_SCANCODE_F9,
+	SDL_SCANCODE_F10,
+	SDL_SCANCODE_F11,
+	SDL_SCANCODE_F12,
+	SDL_SCANCODE_PRINTSCREEN,
+	SDL_SCANCODE_SCROLLLOCK,
+	SDL_SCANCODE_PAUSE,
+	SDL_SCANCODE_INSERT,
+	SDL_SCANCODE_HOME,
+	SDL_SCANCODE_PAGEUP,
+	SDL_SCANCODE_DELETE,
+	SDL_SCANCODE_END,
+	SDL_SCANCODE_PAGEDOWN,
+	SDL_SCANCODE_RIGHT,
+	SDL_SCANCODE_LEFT,
+	SDL_SCANCODE_DOWN,
+	SDL_SCANCODE_UP,
+	SDL_SCANCODE_NUMLOCKCLEAR,
+	SDL_SCANCODE_KP_DIVIDE,
+	SDL_SCANCODE_KP_MULTIPLY,
+	SDL_SCANCODE_KP_MINUS,
+	SDL_SCANCODE_KP_PLUS,
+	SDL_SCANCODE_KP_ENTER,
+	SDL_SCANCODE_KP_1,
+	SDL_SCANCODE_KP_2,
+	SDL_SCANCODE_KP_3,
+	SDL_SCANCODE_KP_4,
+	SDL_SCANCODE_KP_5,
+	SDL_SCANCODE_KP_6,
+	SDL_SCANCODE_KP_7,
+	SDL_SCANCODE_KP_8,
+	SDL_SCANCODE_KP_9,
+	SDL_SCANCODE_KP_0,
+	SDL_SCANCODE_KP_PERIOD,
+	SDL_SCANCODE_NONUSBACKSLASH,
+
+	SDL_SCANCODE_MENU = 0x76,
+
+	SDL_SCANCODE_MUTE = 0x7f,
+	SDL_SCANCODE_VOLUMEUP,
+	SDL_SCANCODE_VOLUMEDOWN,
+
+	SDL_SCANCODE_LCTRL = 0xe0,
+	SDL_SCANCODE_LSHIFT,
+	SDL_SCANCODE_LALT,
+	SDL_SCANCODE_LGUI,
+	SDL_SCANCODE_RCTRL,
+	SDL_SCANCODE_RSHIFT,
+	SDL_SCANCODE_RALT,
+	SDL_SCANCODE_RGUI,
+
+	SDL_SCANCODE_MODE = 0x101,
+	SDL_SCANCODE_AUDIOMUTE = 0x106,
+};
+
+#endif
--- /dev/null
+++ b/libnpe_sdl2/_sdl.h
@@ -1,0 +1,16 @@
+struct npe_sdl {
+	Mousectl *mctl;
+	Mouse m, om;
+	int hints;
+	int mredraw;
+	int fullredraw;
+	int textinput;
+};
+
+enum {
+	Altf4noclose = 1<<0,
+};
+
+extern struct npe_sdl npe_sdl;
+
+int npe_init_input(void);
--- a/libnpe_sdl2/audio.c
+++ b/libnpe_sdl2/audio.c
@@ -99,8 +99,10 @@
 			break;
 	}
 
+	lock(a);
 	(a->mode == OWRITE ? write : read)(a->fd, a->buf, 0);
 	chanclose(a->wait);
+	unlock(a);
 
 	threadexits(nil);
 }
@@ -188,12 +190,13 @@
 	}
 
 	a->paused = 1;
+	a->pid = -1;
 	a->pidconv = -1;
 	if(have->freq != 44100 || have->format != AUDIO_S16 || have->channels != 2){
+		if((fd = open(a->name, a->mode)) < 0)
+			goto err;
 		pipe(p);
-		if((a->pidconv = rfork(RFPROC|RFFDG|RFNOTEG|RFCENVG)) == 0){
-			if((fd = open("/dev/audio", a->mode)) < 0)
-				exits("%r");
+		if((a->pidconv = rfork(RFPROC|RFNOTEG|RFFDG|RFCENVG)) == 0){
 			dup(fd, rec ? 0 : 1); close(fd);
 			dup(p[0], rec ? 1 : 0); close(p[0]);
 			close(p[1]);
@@ -203,10 +206,12 @@
 				exits("%r");
 		}else if(a->pidconv < 0){
 			werrstr("pcmconv: %r");
+			close(fd);
 			goto err;
 		}
 		a->fd = p[1];
 		close(p[0]);
+		close(fd);
 	}else if(a->fd < 0 && (a->fd = open("/dev/audio", a->mode|OCEXEC)) < 0)
 		goto err;
 
@@ -213,8 +218,10 @@
 	return id;
 err:
 	werrstr("SDL_OpenAudioDevice: %r");
-	close(a->fd);
-	a->fd = -1;
+	if(a->fd >= 0){
+		close(a->fd);
+		a->fd = -1;
+	}
 	free(a->buf);
 	a->buf = nil;
 	chanfree(a->wait);
@@ -239,8 +246,7 @@
 		close(a->fd);
 	unlock(a);
 
-	if(a->pid >= 0)
-		recvul(a->wait);
+	recvul(a->wait);
 	chanfree(a->wait);
 
 	free(a->buf);
--- /dev/null
+++ b/libnpe_sdl2/events.c
@@ -1,0 +1,318 @@
+#include <SDL2/SDL.h>
+#include <draw.h>
+#include <mouse.h>
+#include "_sdl.h"
+
+enum {
+	/* FIXME missing plumber→dropfile */
+	Ckey,
+	Ckeytype,
+	Cmouse,
+	Cresize,
+	Numchan,
+
+	Rdown = 0,
+	Rup,
+	Rrepeat,
+};
+
+static int kmod;
+static Rune rune;
+static Keyboardctl kctl;
+
+static Alt salt[Numchan+1] = {
+	[Ckey] = { nil, &rune, CHANRCV },
+	[Ckeytype] = { nil, nil, CHANNOP },
+	[Cmouse] = { nil, &npe_sdl.m, CHANRCV },
+	[Cresize] = { nil, nil, CHANRCV },
+	[Numchan] = { nil, nil, CHANNOBLK },
+};
+
+static int rune2scancode(Rune r);
+static void kbdproc(void *);
+
+int
+npe_init_input(void)
+{
+	if((npe_sdl.mctl = initmouse(nil, screen)) == nil)
+		return -1;
+
+	salt[Ckey].c = chancreate(sizeof(Rune), 20);
+	salt[Ckeytype].c = chancreate(sizeof(int), 20);
+	salt[Cmouse].c = npe_sdl.mctl->c;
+	salt[Cresize].c = npe_sdl.mctl->resizec;
+	kctl.c = salt[Ckey].c; /* for enter() */
+
+	if(salt[Ckey].c == nil || salt[Ckeytype].c == nil || proccreate(kbdproc, nil, 4096) < 0)
+		return -1;
+
+	return 0;
+}
+
+SDL_Keymod
+SDL_GetModState(void)
+{
+	return kmod;
+}
+
+int
+SDL_EventState(Uint32, int)
+{
+	return 0;
+}
+
+int
+SDL_PushEvent(SDL_Event *event)
+{
+	/* FIXME does it matter? */
+	USED(event);
+	return -1;
+}
+
+int
+SDL_PollEvent(SDL_Event *e)
+{
+	int t, down;
+
+	if(e == nil) /* FIXME need to buffer the event so it won't get lost */
+		return 0;
+
+	switch(alt(salt)){
+	case Ckey:
+		recv(salt[Ckeytype].c, &t);
+		if(npe_sdl.textinput && rune >= 0x20 && (rune < KF || rune >= KF+0x1000)){
+			if(t != Rrepeat)
+				break;
+			e->type = SDL_TEXTINPUT;
+			e->text.text[runetochar(e->text.text, &rune)] = 0;
+		}else if((npe_sdl.hints & Altf4noclose) == 0 && (kmod & KMOD_LALT) != 0 && rune == (KF|4)){
+			e->type = SDL_QUIT;
+			return 1;
+		}else if(npe_sdl.textinput && t == Rdown){
+			break;
+		}else{
+			e->type = (t == Rup) ? SDL_KEYUP : SDL_KEYDOWN;
+			e->key.repeat = !npe_sdl.textinput && t == Rrepeat;
+			e->key.keysym.scancode = rune2scancode(rune);
+			e->key.keysym.sym = rune;
+		}
+		return 1;
+
+	case Cmouse:
+		e->motion.x = npe_sdl.m.xy.x - screen->r.min.x;
+		e->motion.y = npe_sdl.m.xy.y - screen->r.min.y;
+		if(!eqpt(npe_sdl.m.xy, npe_sdl.om.xy)){
+			npe_sdl.mredraw = 1;
+			if(npe_sdl.m.buttons == npe_sdl.om.buttons){
+				e->type = SDL_MOUSEMOTION;
+				return 1;
+			}
+		}
+		if(npe_sdl.m.buttons == npe_sdl.om.buttons)
+			break;
+		/* FIXME there is a lot of hope for multiple buttons to never change its state at the same time */
+		if((down = (npe_sdl.m.buttons & 1)) != (npe_sdl.om.buttons & 1)){ /* left */
+			e->type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
+			e->button.button = SDL_BUTTON_LEFT;
+			npe_sdl.om.buttons = (npe_sdl.om.buttons & ~1) | (npe_sdl.m.buttons & 1);
+			return 1;
+		}
+		if((down = (npe_sdl.m.buttons & 2)) != (npe_sdl.om.buttons & 2)){ /* middle */
+			e->type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
+			e->button.button = SDL_BUTTON_MIDDLE;
+			npe_sdl.om.buttons = (npe_sdl.om.buttons & ~2) | (npe_sdl.m.buttons & 2);
+			return 1;
+		}
+		if((down = (npe_sdl.m.buttons & 4)) != (npe_sdl.om.buttons & 4)){ /* right */
+			e->type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
+			e->button.button = SDL_BUTTON_RIGHT;
+			npe_sdl.om.buttons = (npe_sdl.om.buttons & ~4) | (npe_sdl.m.buttons & 4);
+			return 1;
+		}
+		if(npe_sdl.m.buttons & (8|16)){
+			e->type = SDL_MOUSEWHEEL;
+			e->wheel.x = 0;
+			e->wheel.y = (npe_sdl.m.buttons & 8) ? -1 : 1;
+			return 1;
+		}
+		break;
+
+	case Cresize:
+		npe_sdl.fullredraw = 1;
+		if(getwindow(display, Refnone) < 0){
+			fprint(2, "%r\n");
+			/* FIXME do something here? */
+			//threadexitsall(nil);
+		}
+		e->type = SDL_WINDOWEVENT;
+		e->window.event = SDL_WINDOWEVENT_EXPOSED;
+		return 1;
+	}
+
+	return 0;
+}
+
+static int
+rune2scancode(Rune r)
+{
+	if(r >= 'a' && r <= 'z')
+		return r - 'a' + SDL_SCANCODE_A;
+	if(r >= '1' && r <= '9')
+		return r - '1' + SDL_SCANCODE_1;
+	if(r == '0')  return SDL_SCANCODE_0;
+	if(r == '\n') return SDL_SCANCODE_RETURN;
+	if(r == Kesc) return SDL_SCANCODE_ESCAPE;
+	if(r == Kbs)  return SDL_SCANCODE_BACKSPACE;
+	if(r == '\t') return SDL_SCANCODE_TAB;
+	if(r == ' ')  return SDL_SCANCODE_SPACE;
+	if(r == '-')  return SDL_SCANCODE_MINUS;
+	if(r == '=')  return SDL_SCANCODE_EQUALS;
+	if(r == '[')  return SDL_SCANCODE_LEFTBRACKET;
+	if(r == ']')  return SDL_SCANCODE_RIGHTBRACKET;
+	if(r == '\\') return SDL_SCANCODE_BACKSLASH;
+	if(r == ';')  return SDL_SCANCODE_SEMICOLON;
+	if(r == '\'') return SDL_SCANCODE_APOSTROPHE;
+	if(r == '/')  return SDL_SCANCODE_SLASH;
+
+	if(r == Kright) return SDL_SCANCODE_RIGHT;
+	if(r == Kleft) return SDL_SCANCODE_LEFT;
+	if(r == Kdown) return SDL_SCANCODE_DOWN;
+	if(r == Kup) return SDL_SCANCODE_UP;
+	if(r == Kins) return SDL_SCANCODE_INSERT;
+	if(r == Khome) return SDL_SCANCODE_HOME;
+	if(r == Kpgup) return SDL_SCANCODE_PAGEUP;
+	if(r == Kdel) return SDL_SCANCODE_DELETE;
+	if(r == Kend) return SDL_SCANCODE_END;
+	if(r == Kpgdown) return SDL_SCANCODE_PAGEDOWN;
+	if(r == Kctl) return SDL_SCANCODE_LCTRL;
+	if(r == Kshift) return SDL_SCANCODE_LSHIFT;
+	if(r == Kalt) return SDL_SCANCODE_LALT;
+	if(r == Kmod4) return SDL_SCANCODE_LGUI;
+
+	if(r >= (KF|1) && r <= (KF|12)) return SDL_SCANCODE_F1 + r - (KF|1);
+
+/* FIXME
+	SDL_SCANCODE_PRINTSCREEN = 0x46,
+	SDL_SCANCODE_SCROLLLOCK,
+	SDL_SCANCODE_NUMLOCKCLEAR,
+	SDL_SCANCODE_KP_DIVIDE,
+	SDL_SCANCODE_KP_MULTIPLY,
+	SDL_SCANCODE_KP_MINUS,
+	SDL_SCANCODE_KP_PLUS,
+	SDL_SCANCODE_KP_ENTER,
+	SDL_SCANCODE_KP_1,
+	SDL_SCANCODE_KP_2,
+	SDL_SCANCODE_KP_3,
+	SDL_SCANCODE_KP_4,
+	SDL_SCANCODE_KP_5,
+	SDL_SCANCODE_KP_6,
+	SDL_SCANCODE_KP_7,
+	SDL_SCANCODE_KP_8,
+	SDL_SCANCODE_KP_9,
+	SDL_SCANCODE_KP_0,
+	SDL_SCANCODE_KP_PERIOD,
+	SDL_SCANCODE_NONUSBACKSLASH,
+	SDL_SCANCODE_NONUSHASH,
+*/
+	/* FIXME there are some missing */
+
+	if(r == L'`' || r == L'´') /* FIXME this is most likely wrong */
+		return SDL_SCANCODE_GRAVE;
+
+	return r;
+}
+
+static void
+kbdproc(void *)
+{
+	char buf[128], buf2[128], *s;
+	int kfd, n, kbin, t;
+	Rune r, o;
+
+	threadsetname("kbdproc");
+	if((kfd = open("/dev/kbd", OREAD|OCEXEC)) < 0)
+		sysfatal("/dev/kbd: %r");
+	kbin = open("/dev/kbin", OWRITE|OCEXEC);
+
+	buf2[0] = 0;
+	buf2[1] = 0;
+	buf[0] = 0;
+	kmod = 0;
+	o = 0;
+	for(;;){
+		if(buf[0] != 0){
+			n = strlen(buf)+1;
+			memmove(buf, buf+n, sizeof(buf)-n);
+		}
+		if(buf[0] == 0){
+			n = read(kfd, buf, sizeof(buf)-1);
+			if(n <= 0)
+				break;
+			buf[n-1] = 0;
+			buf[n] = 0;
+		}
+
+		switch(buf[0]){
+		case 'c':
+			if(chartorune(&r, buf+1) > 0 && r != Runeerror){
+				t = Rrepeat;
+				if(!npe_sdl.textinput)
+					r = tolowerrune(r);
+				if(npe_sdl.textinput || o != r){
+					send(salt[Ckey].c, &r);
+					send(salt[Ckeytype].c, &t);
+				}
+				o = 0;
+			}
+		default:
+			continue;
+
+		case 'k':
+			s = buf+1;
+			while(*s){
+				s += chartorune(&r, s);
+				if(utfrune(buf2+1, r) == nil){
+					if(r == Kalt){
+						/* magic trick: write Alt scancode to disable the "compose" mode */
+						/* FIXME: does this work in both native AND drawterm? */
+						write(kbin, "\x46", 1);
+						kmod |= KMOD_LALT;
+					}else if (r == Kshift)
+						kmod |= KMOD_LSHIFT;
+					else if(r == Kctl)
+						kmod |= KMOD_LCTRL;
+					else{
+						t = Rdown;
+						send(salt[Ckey].c, &r);
+						send(salt[Ckeytype].c, &t);
+						o = r;
+					}
+				}
+			}
+			break;
+
+		case 'K':
+			s = buf2+1;
+			while(*s){
+				s += chartorune(&r, s);
+				if(utfrune(buf+1, r) == nil){
+					if(r == Kalt)
+						kmod &= ~KMOD_LALT;
+					else if(r == Kshift)
+						kmod &= ~KMOD_LSHIFT;
+					else if(r == Kctl)
+						kmod &= ~KMOD_LCTRL;
+					else{
+						t = Rup;
+						send(salt[Ckey].c, &r);
+						send(salt[Ckeytype].c, &t);
+					}
+				}
+			}
+			break;
+		}
+		strcpy(buf2, buf);
+	}
+
+	threadexits(nil);
+}
--- a/libnpe_sdl2/mkfile
+++ b/libnpe_sdl2/mkfile
@@ -7,6 +7,7 @@
 
 OFILES=\
 	audio.$O\
+	events.$O\
 	sdl2.$O\
 
 UPDATE=\
--- a/libnpe_sdl2/sdl2.c
+++ b/libnpe_sdl2/sdl2.c
@@ -9,22 +9,8 @@
 #include <SDL2/SDL.h>
 #include <sys/stat.h>
 #include "_npe.h"
+#include "_sdl.h"
 
-enum {
-	/* FIXME missing plumber→dropfile */
-	Ckey,
-	Ckeytype,
-	Cmouse,
-	Cresize,
-	Numchan,
-
-	Rdown = 0,
-	Rup,
-	Rrepeat,
-
-	Altf4noclose = 1<<0,
-};
-
 struct SDL_Window {
 	int dummy;
 };
@@ -60,25 +46,18 @@
 
 static SDL_Window onewin;
 static SDL_Renderer oneren;
-static int kmod;
-static Mouse mouse, oldmouse;
-static Rune rune;
-static Mousectl *mctl;
-static Keyboardctl kctl;
 static Memimage *back;
 static u8int *backcopy;
 static Image *front;
 static int logiw, logih;
 static int physw, physh;
-static int forceredraw = 1;
 static SDL_Cursor *oldcursor, *cursor;
-static int mouseredraw = 0;
 static int showcursor = SDL_ENABLE;
-static int textinput;
 static char basepath[PATH_MAX];
 static u32int renddrawcol = DBlack;
-static int hints;
 
+struct npe_sdl npe_sdl = {0};
+
 static Cursor nocursor = {
 	{0, 0},
 	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -93,109 +72,7 @@
 	},
 };
 
-static Alt salt[Numchan+1] = {
-	[Ckey] = { nil, &rune, CHANRCV },
-	[Ckeytype] = { nil, nil, CHANNOP },
-	[Cmouse] = { nil, &mouse, CHANRCV },
-	[Cresize] = { nil, nil, CHANRCV },
-	[Numchan] = { nil, nil, CHANNOBLK },
-};
 
-static void
-kbdproc(void *)
-{
-	char buf[128], buf2[128], *s;
-	int kfd, n, kbin, t;
-	Rune r, o;
-
-	threadsetname("kbdproc");
-	if((kfd = open("/dev/kbd", OREAD|OCEXEC)) < 0)
-		sysfatal("/dev/kbd: %r");
-	kbin = open("/dev/kbin", OWRITE|OCEXEC);
-
-	buf2[0] = 0;
-	buf2[1] = 0;
-	buf[0] = 0;
-	kmod = 0;
-	o = 0;
-	for(;;){
-		if(buf[0] != 0){
-			n = strlen(buf)+1;
-			memmove(buf, buf+n, sizeof(buf)-n);
-		}
-		if(buf[0] == 0){
-			n = read(kfd, buf, sizeof(buf)-1);
-			if(n <= 0)
-				break;
-			buf[n-1] = 0;
-			buf[n] = 0;
-		}
-
-		switch(buf[0]){
-		case 'c':
-			if(chartorune(&r, buf+1) > 0 && r != Runeerror){
-				t = Rrepeat;
-				if(!textinput)
-					r = tolowerrune(r);
-				if(textinput || o != r){
-					send(salt[Ckey].c, &r);
-					send(salt[Ckeytype].c, &t);
-				}
-				o = 0;
-			}
-		default:
-			continue;
-
-		case 'k':
-			s = buf+1;
-			while(*s){
-				s += chartorune(&r, s);
-				if(utfrune(buf2+1, r) == nil){
-					if(r == Kalt){
-						/* magic trick: write Alt scancode to disable the "compose" mode */
-						/* FIXME: does this work in both native AND drawterm? */
-						write(kbin, "\x46", 1);
-						kmod |= KMOD_LALT;
-					}else if (r == Kshift)
-						kmod |= KMOD_LSHIFT;
-					else if(r == Kctl)
-						kmod |= KMOD_LCTRL;
-					else{
-						t = Rdown;
-						send(salt[Ckey].c, &r);
-						send(salt[Ckeytype].c, &t);
-						o = r;
-					}
-				}
-			}
-			break;
-
-		case 'K':
-			s = buf2+1;
-			while(*s){
-				s += chartorune(&r, s);
-				if(utfrune(buf+1, r) == nil){
-					if(r == Kalt)
-						kmod &= ~KMOD_LALT;
-					else if(r == Kshift)
-						kmod &= ~KMOD_LSHIFT;
-					else if(r == Kctl)
-						kmod &= ~KMOD_LCTRL;
-					else{
-						t = Rup;
-						send(salt[Ckey].c, &r);
-						send(salt[Ckeytype].c, &t);
-					}
-				}
-			}
-			break;
-		}
-		strcpy(buf2, buf);
-	}
-
-	threadexits(nil);
-}
-
 int
 SDL_Init(int mask)
 {
@@ -212,18 +89,9 @@
 		goto err;
 	if(initdraw(nil, nil, argv0) < 0)
 		goto err;
-	if((mctl = initmouse(nil, screen)) == nil)
+	if(npe_init_input() != 0)
 		goto err;
 
-	salt[Ckey].c = chancreate(sizeof(Rune), 20);
-	salt[Ckeytype].c = chancreate(sizeof(int), 20);
-	salt[Cmouse].c = mctl->c;
-	salt[Cresize].c = mctl->resizec;
-	kctl.c = salt[Ckey].c; /* for enter() */
-
-	if(salt[Ckey].c == nil || salt[Ckeytype].c == nil || proccreate(kbdproc, nil, 4096) < 0)
-		goto err;
-
 	return 0;
 err:
 	werrstr("SDL_Init: %r");
@@ -231,18 +99,6 @@
 }
 
 int
-SDL_EventState(Uint32, int)
-{
-	return 0;
-}
-
-SDL_Keymod
-SDL_GetModState(void)
-{
-	return kmod;
-}
-
-int
 SDL_ShowCursor(int toggle)
 {
 	if(toggle == SDL_QUERY)
@@ -249,7 +105,7 @@
 		return showcursor;
 
 	showcursor = toggle == SDL_ENABLE;
-	setcursor(mctl, (cursor == nil && showcursor) ? nil : &nocursor);
+	setcursor(npe_sdl.mctl, (cursor == nil && showcursor) ? nil : &nocursor);
 
 	return showcursor;
 }
@@ -634,8 +490,8 @@
 {
 	if(cursor != c){
 		cursor = c;
-		mouseredraw = 1;
-		setcursor(mctl, (cursor == nil && showcursor) ? nil : &nocursor);
+		npe_sdl.mredraw = 1;
+		setcursor(npe_sdl.mctl, (cursor == nil && showcursor) ? nil : &nocursor);
 	}
 }
 
@@ -650,171 +506,10 @@
 	}
 }
 
-static int
-rune2scancode(Rune r)
-{
-	if(r >= 'a' && r <= 'z')
-		return r - 'a' + SDL_SCANCODE_A;
-	if(r >= '1' && r <= '9')
-		return r - '1' + SDL_SCANCODE_1;
-	if(r == '0')  return SDL_SCANCODE_0;
-	if(r == '\n') return SDL_SCANCODE_RETURN;
-	if(r == Kesc) return SDL_SCANCODE_ESCAPE;
-	if(r == Kbs)  return SDL_SCANCODE_BACKSPACE;
-	if(r == '\t') return SDL_SCANCODE_TAB;
-	if(r == ' ')  return SDL_SCANCODE_SPACE;
-	if(r == '-')  return SDL_SCANCODE_MINUS;
-	if(r == '=')  return SDL_SCANCODE_EQUALS;
-	if(r == '[')  return SDL_SCANCODE_LEFTBRACKET;
-	if(r == ']')  return SDL_SCANCODE_RIGHTBRACKET;
-	if(r == '\\') return SDL_SCANCODE_BACKSLASH;
-	if(r == ';')  return SDL_SCANCODE_SEMICOLON;
-	if(r == '\'') return SDL_SCANCODE_APOSTROPHE;
-	if(r == '/')  return SDL_SCANCODE_SLASH;
-
-	if(r == Kright) return SDL_SCANCODE_RIGHT;
-	if(r == Kleft) return SDL_SCANCODE_LEFT;
-	if(r == Kdown) return SDL_SCANCODE_DOWN;
-	if(r == Kup) return SDL_SCANCODE_UP;
-	if(r == Kins) return SDL_SCANCODE_INSERT;
-	if(r == Khome) return SDL_SCANCODE_HOME;
-	if(r == Kpgup) return SDL_SCANCODE_PAGEUP;
-	if(r == Kdel) return SDL_SCANCODE_DELETE;
-	if(r == Kend) return SDL_SCANCODE_END;
-	if(r == Kpgdown) return SDL_SCANCODE_PAGEDOWN;
-	if(r == Kctl) return SDL_SCANCODE_LCTRL;
-	if(r == Kshift) return SDL_SCANCODE_LSHIFT;
-	if(r == Kalt) return SDL_SCANCODE_LALT;
-	if(r == Kmod4) return SDL_SCANCODE_LGUI;
-
-	if(r >= (KF|1) && r <= (KF|12)) return SDL_SCANCODE_F1 + r - (KF|1);
-
-/* FIXME
-	SDL_SCANCODE_PRINTSCREEN = 0x46,
-	SDL_SCANCODE_SCROLLLOCK,
-	SDL_SCANCODE_NUMLOCKCLEAR,
-	SDL_SCANCODE_KP_DIVIDE,
-	SDL_SCANCODE_KP_MULTIPLY,
-	SDL_SCANCODE_KP_MINUS,
-	SDL_SCANCODE_KP_PLUS,
-	SDL_SCANCODE_KP_ENTER,
-	SDL_SCANCODE_KP_1,
-	SDL_SCANCODE_KP_2,
-	SDL_SCANCODE_KP_3,
-	SDL_SCANCODE_KP_4,
-	SDL_SCANCODE_KP_5,
-	SDL_SCANCODE_KP_6,
-	SDL_SCANCODE_KP_7,
-	SDL_SCANCODE_KP_8,
-	SDL_SCANCODE_KP_9,
-	SDL_SCANCODE_KP_0,
-	SDL_SCANCODE_KP_PERIOD,
-	SDL_SCANCODE_NONUSBACKSLASH,
-	SDL_SCANCODE_NONUSHASH,
-*/
-	/* FIXME there are some missing */
-
-	if(r == L'`' || r == L'´') /* FIXME this is most likely wrong */
-		return SDL_SCANCODE_GRAVE;
-
-	return r;
-}
-
-int
-SDL_PollEvent(SDL_Event *e)
-{
-	int t, down;
-
-	if(e == nil) /* FIXME need to buffer the event so it won't get lost */
-		return 0;
-
-	switch(alt(salt)){
-	case Ckey:
-		recv(salt[Ckeytype].c, &t);
-		if(textinput && rune >= 0x20 && (rune < KF || rune >= KF+0x1000)){
-			if(t != Rrepeat)
-				break;
-			e->type = SDL_TEXTINPUT;
-			e->text.text[runetochar(e->text.text, &rune)] = 0;
-		}else if((hints & Altf4noclose) == 0 && (kmod & KMOD_LALT) != 0 && rune == (KF|4)){
-			e->type = SDL_QUIT;
-			return 1;
-		}else if(textinput && t == Rdown){
-			break;
-		}else{
-			e->type = (t == Rup) ? SDL_KEYUP : SDL_KEYDOWN;
-			e->key.repeat = !textinput && t == Rrepeat;
-			e->key.keysym.scancode = rune2scancode(rune);
-			e->key.keysym.sym = rune;
-		}
-		return 1;
-
-	case Cmouse:
-		e->motion.x = mouse.xy.x - screen->r.min.x;
-		e->motion.y = mouse.xy.y - screen->r.min.y;
-		if(!eqpt(mouse.xy, oldmouse.xy)){
-			mouseredraw = 1;
-			if(mouse.buttons == oldmouse.buttons){
-				e->type = SDL_MOUSEMOTION;
-				return 1;
-			}
-		}
-		if(mouse.buttons == oldmouse.buttons)
-			break;
-		/* FIXME there is a lot of hope for multiple buttons to never change its state at the same time */
-		if((down = (mouse.buttons & 1)) != (oldmouse.buttons & 1)){ /* left */
-			e->type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
-			e->button.button = SDL_BUTTON_LEFT;
-			oldmouse.buttons = (oldmouse.buttons & ~1) | (mouse.buttons & 1);
-			return 1;
-		}
-		if((down = (mouse.buttons & 2)) != (oldmouse.buttons & 2)){ /* middle */
-			e->type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
-			e->button.button = SDL_BUTTON_MIDDLE;
-			oldmouse.buttons = (oldmouse.buttons & ~2) | (mouse.buttons & 2);
-			return 1;
-		}
-		if((down = (mouse.buttons & 4)) != (oldmouse.buttons & 4)){ /* right */
-			e->type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
-			e->button.button = SDL_BUTTON_RIGHT;
-			oldmouse.buttons = (oldmouse.buttons & ~4) | (mouse.buttons & 4);
-			return 1;
-		}
-		if(mouse.buttons & (8|16)){
-			e->type = SDL_MOUSEWHEEL;
-			e->wheel.x = 0;
-			e->wheel.y = (mouse.buttons & 8) ? -1 : 1;
-			return 1;
-		}
-		break;
-
-	case Cresize:
-		forceredraw = 1;
-		if(getwindow(display, Refnone) < 0){
-			fprint(2, "%r\n");
-			/* FIXME do something here? */
-			//threadexitsall(nil);
-		}
-		e->type = SDL_WINDOWEVENT;
-		e->window.event = SDL_WINDOWEVENT_EXPOSED;
-		return 1;
-	}
-
-	return 0;
-}
-
-int
-SDL_PushEvent(SDL_Event *event)
-{
-	/* FIXME does it matter? */
-	USED(event);
-	return -1;
-}
-
 void
 SDL_WarpMouseInWindow(SDL_Window *, int x, int y)
 {
-	moveto(mctl, Pt(screen->r.min.x+x, screen->r.min.y+y));
+	moveto(npe_sdl.mctl, Pt(screen->r.min.x+x, screen->r.min.y+y));
 }
 
 Uint32
@@ -823,16 +518,16 @@
 	Uint32 b;
 
 	if(x != nil)
-		*x = mouse.xy.x;
+		*x = npe_sdl.m.xy.x;
 	if(y != nil)
-		*y = mouse.xy.y;
+		*y = npe_sdl.m.xy.y;
 
 	b = 0;
-	if(mouse.buttons & 1)
+	if(npe_sdl.m.buttons & 1)
 		b |= SDL_BUTTON_LMASK;
-	if(mouse.buttons & 2)
+	if(npe_sdl.m.buttons & 2)
 		b |= SDL_BUTTON_MMASK;
-	if(mouse.buttons & 4)
+	if(npe_sdl.m.buttons & 4)
 		b |= SDL_BUTTON_RMASK;
 
 	return b;
@@ -845,9 +540,9 @@
 
 	b = SDL_GetGlobalMouseState(nil, nil);
 	if(x != nil)
-		*x = (mouse.xy.x - screen->r.min.x) * logiw / physw;
+		*x = (npe_sdl.m.xy.x - screen->r.min.x) * logiw / physw;
 	if(y != nil)
-		*y = (mouse.xy.y - screen->r.min.y) * logih / physh;
+		*y = (npe_sdl.m.xy.y - screen->r.min.y) * logih / physh;
 
 	return b;
 }
@@ -885,19 +580,19 @@
 SDL_bool
 SDL_IsTextInputActive(void)
 {
-	return textinput;
+	return npe_sdl.textinput;
 }
 
 void
 SDL_StartTextInput(void)
 {
-	textinput = SDL_TRUE;
+	npe_sdl.textinput = SDL_TRUE;
 }
 
 void
 SDL_StopTextInput(void)
 {
-	textinput = SDL_FALSE;
+	npe_sdl.textinput = SDL_FALSE;
 }
 
 void
@@ -975,7 +670,7 @@
 	static u32int *b;
 	uchar *rb;
 
-	if(!forceredraw && (forceredraw = memcmp(backcopy, byteaddr(back, ZP), logiw*logih*4)) == 0 && !mouseredraw)
+	if(!npe_sdl.fullredraw && (npe_sdl.fullredraw = memcmp(backcopy, byteaddr(back, ZP), logiw*logih*4)) == 0 && !npe_sdl.mredraw)
 		return;
 
 	r = Rect(0, 0, physw, physh);
@@ -989,7 +684,7 @@
 		fprint(2, "SDL_RenderPresent: %r\n");
 		return;
 	}
-	if(forceredraw || front == nil){
+	if(npe_sdl.fullredraw || front == nil){
 		rb = resize((u32int*)byteaddr(back, ZP), Dx(back->r), Dy(back->r), b, physw, physh);
 		if(front == nil && (front = allocimage(display, r, XRGB32, 0, DNofill)) == nil){
 			fprint(2, "SDL_RenderPresent: %r\n");
@@ -1002,10 +697,10 @@
 	}
 
 	if(cursor != nil && showcursor){
-		r.min = subpt(mouse.xy, cursor->hot);
+		r.min = subpt(npe_sdl.m.xy, cursor->hot);
 		r.max = addpt(r.min, cursor->i->r.max);
-		if(!forceredraw && oldcursor != nil){
-			clipr.min = subpt(oldmouse.xy, oldcursor->hot);
+		if(!npe_sdl.fullredraw && oldcursor != nil){
+			clipr.min = subpt(npe_sdl.om.xy, oldcursor->hot);
 			clipr.max = addpt(clipr.min, oldcursor->i->r.max);
 			combinerect(&clipr, r);
 			replclipr(screen, 0, clipr);
@@ -1014,17 +709,17 @@
 	draw(screen, screen->r, front, nil, ZP);
 	if(cursor != nil && showcursor)
 		draw(screen, r, cursor->i, cursor->m, ZP);
-	mouseredraw = 0;
-	oldmouse.xy = mouse.xy;
+	npe_sdl.mredraw = 0;
+	npe_sdl.om.xy = npe_sdl.m.xy;
 	oldcursor = cursor;
 
 	flushimage(display, 1);
 
-	if(forceredraw)
+	if(npe_sdl.fullredraw)
 		memmove(backcopy, byteaddr(back, ZP), logiw*logih*4);
 	else
 		replclipr(screen, 0, screen->r);
-	forceredraw = 0;
+	npe_sdl.fullredraw = 0;
 }
 
 Uint32
@@ -1040,7 +735,7 @@
 	if(logiw != w || logih != h){
 		logiw = w;
 		logih = h;
-		forceredraw = 1;
+		npe_sdl.fullredraw = 1;
 	}
 
 	return 0;
@@ -1070,7 +765,7 @@
 			close(f);
 			if(n > 0){
 				getwindow(display, Refnone);
-				forceredraw = 1;
+				npe_sdl.fullredraw = 1;
 			}
 		}
 	}
@@ -1109,7 +804,7 @@
 		close(f);
 		if(n > 0){
 			getwindow(display, Refnone);
-			forceredraw = 1;
+			npe_sdl.fullredraw = 1;
 		}
 	}
 }
@@ -1167,7 +862,7 @@
 {
 	/* FIXME anyone cares about name="SDL_RENDER_SCALE_QUALITY" value="(best|nearest)"? */
 	if(strcmp(name, SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4) == 0){
-		hints = (hints & ~Altf4noclose) | (atoi(value) ? Altf4noclose : 0);
+		npe_sdl.hints = (npe_sdl.hints & ~Altf4noclose) | (atoi(value) ? Altf4noclose : 0);
 		return SDL_TRUE;
 	}