diff --git a/firmware/target/hosted/sdl/button-sdl.c b/firmware/target/hosted/sdl/button-sdl.c index cfe08de1d2..e9fc03792c 100644 --- a/firmware/target/hosted/sdl/button-sdl.c +++ b/firmware/target/hosted/sdl/button-sdl.c @@ -85,20 +85,21 @@ bool remote_button_hold(void) { static void button_event(int key, bool pressed); extern bool debug_wps; extern bool mapping; -static void gui_message_loop(void) + +void gui_message_loop(void) { SDL_Event event; static int x,y,xybutton = 0; - if (SDL_PollEvent(&event)) + while (SDL_WaitEvent(&event)) { + sim_enter_irq_handler(); switch(event.type) { case SDL_KEYDOWN: - button_event(event.key.keysym.sym, true); - break; case SDL_KEYUP: - button_event(event.key.keysym.sym, false); + button_event(event.key.keysym.sym, event.type == SDL_KEYDOWN); + break; case SDL_MOUSEBUTTONDOWN: switch ( event.button.button ) { #ifdef HAVE_SCROLLWHEEL @@ -174,6 +175,7 @@ static void gui_message_loop(void) case SDL_QUIT: { + sim_exit_irq_handler(); exit(EXIT_SUCCESS); break; } @@ -181,6 +183,7 @@ static void gui_message_loop(void) /*printf("Unhandled event\n"); */ break; } + sim_exit_irq_handler(); } } @@ -1502,7 +1505,6 @@ int button_read_device(void) return BUTTON_NONE; else #endif - gui_message_loop(); return btn; } diff --git a/firmware/target/hosted/sdl/system-sdl.c b/firmware/target/hosted/sdl/system-sdl.c index 693e8d1b57..3d67de425b 100644 --- a/firmware/target/hosted/sdl/system-sdl.c +++ b/firmware/target/hosted/sdl/system-sdl.c @@ -70,14 +70,37 @@ void sys_poweroff(void) SDL_Quit(); } -void system_init(void) +/* + * Button read loop */ +void gui_message_loop(void); + +/* + * This callback let's the main thread run again after SDL has been initialized + **/ +static uint32_t cond_signal(uint32_t interval, void *param) { + (void)interval; + SDL_cond *c = (SDL_cond*)param; + /* remove timer, CondSignal returns 0 on success */ + return SDL_CondSignal(c); +} + +/* + * This thread will read the buttons in an interrupt like fashion, and + * also initializes SDL_INIT_VIDEO and the surfaces + * + * it must be done in the same thread (at least on windows) because events only + * work in the thread which called SDL_Init(SubSystem) with SDL_INIT_VIDEO + * + * This is an SDL thread and relies on preemptive behavoir of the host + **/ +static int sdl_event_thread(void * param) +{ + SDL_InitSubSystem(SDL_INIT_VIDEO); + SDL_Surface *picture_surface; int width, height; - if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER)) - panicf("%s", SDL_GetError()); - /* Try and load the background image. If it fails go without */ if (background) { picture_surface = SDL_LoadBMP("UI256.bmp"); @@ -122,10 +145,43 @@ void system_init(void) sim_lcd_remote_init(); #endif - if (background && picture_surface != NULL) { + if (background && picture_surface != NULL) SDL_BlitSurface(picture_surface, NULL, gui_surface, NULL); - SDL_UpdateRect(gui_surface, 0, 0, 0, 0); - } + + /* calling SDL_CondSignal() right away here doesn't work reliably so + * post-pone it a bit */ + SDL_AddTimer(100, cond_signal, param); + /* + * finally enter the button loop */ + while(1) + gui_message_loop(); + + return 0; +} + + +void system_init(void) +{ + SDL_cond *c; + SDL_mutex *m; + if (SDL_Init(SDL_INIT_TIMER)) + panicf("%s", SDL_GetError()); + atexit(SDL_Quit); + + c = SDL_CreateCond(); + m = SDL_CreateMutex(); + + SDL_CreateThread(sdl_event_thread, c); + + /* Lock mutex and wait for sdl_event_thread to run so that it can + * initialize the surfaces and video subsystem needed for SDL events */ + SDL_LockMutex(m); + SDL_CondWait(c, m); + SDL_UnlockMutex(m); + + /* cleanup */ + SDL_DestroyCond(c); + SDL_DestroyMutex(m); } void system_exception_wait(void) @@ -138,6 +194,7 @@ void system_reboot(void) sim_thread_exception_wait(); } + void sys_handle_argv(int argc, char *argv[]) { if (argc >= 1) diff --git a/firmware/target/hosted/sdl/system-sdl.h b/firmware/target/hosted/sdl/system-sdl.h index 917e6e89da..ad7aa709ab 100644 --- a/firmware/target/hosted/sdl/system-sdl.h +++ b/firmware/target/hosted/sdl/system-sdl.h @@ -44,6 +44,7 @@ void sim_exit_irq_handler(void); void sim_kernel_shutdown(void); void sys_poweroff(void); void sys_handle_argv(int argc, char *argv[]); +void gui_message_loop(void); extern bool background; /* True if the background image is enabled */ extern int display_zoom;