2019-04-19 11:32:13 -05:00
// 19 april 2019
# include "uipriv.h"
2020-05-09 01:04:51 -05:00
# include "testhooks.h"
2019-04-19 11:32:13 -05:00
2020-05-09 00:24:40 -05:00
enum {
stateUninitialized ,
stateBeforeMain ,
stateInMain ,
stateQuitting ,
stateAfterMain ,
stateError ,
} ;
static int state = stateUninitialized ;
# define initialized() (state != stateUninitialized && state != stateError)
2019-04-19 11:32:13 -05:00
2020-05-09 01:04:51 -05:00
bool testHookInitShouldFail = false ;
void uiprivTestHookSetInitShouldFailArtificially ( bool shouldFail )
{
testHookInitShouldFail = shouldFail ;
}
2019-05-29 20:10:44 -05:00
bool uiInit ( void * options , uiInitError * err )
2019-04-19 11:32:13 -05:00
{
2020-05-09 00:24:40 -05:00
if ( state ! = stateUninitialized ) {
uiprivProgrammerErrorMultipleCalls ( uiprivFunc ) ;
state = stateError ;
2019-05-29 20:10:44 -05:00
return false ;
2020-05-09 00:24:40 -05:00
}
if ( options ! = NULL ) {
uiprivProgrammerErrorBadInitOptions ( uiprivFunc ) ;
state = stateError ;
2019-05-29 20:10:44 -05:00
return false ;
2020-05-09 00:24:40 -05:00
}
if ( err = = NULL ) {
uiprivProgrammerErrorNullPointer ( " uiInitError " , uiprivFunc ) ;
state = stateError ;
return false ;
}
if ( err - > Size ! = sizeof ( uiInitError ) ) {
uiprivProgrammerErrorWrongStructSize ( err - > Size , " uiInitError " , uiprivFunc ) ;
state = stateError ;
return false ;
}
2019-04-19 11:32:13 -05:00
2020-05-09 01:04:51 -05:00
if ( testHookInitShouldFail ) {
state = stateError ;
return uiprivInitReturnErrorf ( err , " general failure " ) ;
}
2020-05-09 00:24:40 -05:00
if ( ! uiprivSysInit ( options , err ) ) {
state = stateError ;
2019-05-29 20:10:44 -05:00
return false ;
2020-05-09 00:24:40 -05:00
}
state = stateBeforeMain ;
2019-05-29 20:10:44 -05:00
return true ;
2019-04-19 11:32:13 -05:00
}
2019-06-01 10:40:16 -05:00
bool uiprivInitReturnErrorf ( uiInitError * err , const char * fmt , . . . )
2019-04-21 13:49:16 -05:00
{
2019-05-30 00:16:33 -05:00
int n ;
2019-04-21 13:49:16 -05:00
va_list ap ;
2019-06-01 10:40:16 -05:00
va_start ( ap , fmt ) ;
n = uiprivVsnprintf ( err - > Message , 256 , fmt , ap ) ;
2019-04-21 13:49:16 -05:00
va_end ( ap ) ;
2020-02-09 12:37:45 -06:00
if ( n < 0 ) {
2019-05-30 00:16:33 -05:00
uiprivInternalError ( " encoding error returning initialization error; this means something is very very wrong with libui itself " ) ;
2020-02-09 12:37:45 -06:00
abort ( ) ; // TODO handle this scenario more gracefully
}
2019-05-30 00:16:33 -05:00
if ( n > = 256 ) {
// the formatted message is too long; truncate it
err - > Message [ 252 ] = ' . ' ;
err - > Message [ 253 ] = ' . ' ;
err - > Message [ 254 ] = ' . ' ;
err - > Message [ 255 ] = ' \0 ' ;
}
2019-05-29 20:10:44 -05:00
return false ;
2019-04-21 13:49:16 -05:00
}
2019-05-28 20:54:13 -05:00
2020-05-09 00:24:40 -05:00
void uiMain ( void )
{
if ( ! uiprivCheckInitializedAndThread ( ) )
return ;
if ( state ! = stateBeforeMain ) {
uiprivProgrammerErrorMultipleCalls ( uiprivFunc ) ;
return ;
}
state = stateInMain ;
uiprivSysMain ( ) ;
state = stateAfterMain ;
}
void uiQuit ( void )
{
if ( ! uiprivCheckInitializedAndThread ( ) )
return ;
if ( state = = stateQuitting | | state = = stateAfterMain ) {
uiprivProgrammerErrorMultipleCalls ( uiprivFunc ) ;
return ;
}
if ( state ! = stateInMain ) {
// the above handle the other states, so stateBeforeMain is what's left
uiprivProgrammerErrorQuitBeforeMain ( uiprivFunc ) ;
return ;
}
state = stateQuitting ;
uiprivSysQuit ( ) ;
}
2019-05-30 00:39:43 -05:00
void uiQueueMain ( void ( * f ) ( void * data ) , void * data )
{
2020-05-09 00:24:40 -05:00
if ( ! initialized ( ) ) {
2019-06-02 07:35:40 -05:00
uiprivProgrammerErrorNotInitialized ( uiprivFunc ) ;
2019-05-30 00:39:43 -05:00
return ;
}
uiprivSysQueueMain ( f , data ) ;
}
2019-05-28 20:54:13 -05:00
bool uiprivCheckInitializedAndThreadImpl ( const char * func )
{
// While it does seem risky to not lock this, if this changes during the execution of this function it means only that it was changed from a different thread, and since it can only change from false to true, an error will be reported anyway.
2020-05-09 00:24:40 -05:00
if ( ! initialized ( ) ) {
2019-06-02 07:35:40 -05:00
uiprivProgrammerErrorNotInitialized ( func ) ;
2019-05-28 20:54:13 -05:00
return false ;
}
if ( ! uiprivSysCheckThread ( ) ) {
2019-06-02 07:35:40 -05:00
uiprivProgrammerErrorWrongThread ( func ) ;
2019-05-28 20:54:13 -05:00
return false ;
}
return true ;
}