2009-09-27 20:19:53 +02:00
|
|
|
|
/****************************************************************************
|
|
|
|
|
* libwiigui
|
|
|
|
|
*
|
|
|
|
|
* Tantric 2009
|
|
|
|
|
*
|
|
|
|
|
* gui_imagea_sync.cpp
|
|
|
|
|
*
|
|
|
|
|
* GUI class definitions
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "gui.h"
|
|
|
|
|
//#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include "gui_image_async.h"
|
|
|
|
|
static mutex_t debugLock = LWP_MUTEX_NULL;
|
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
|
void debug( int Line, const char* Format, ... )
|
2010-02-09 11:59:55 +01:00
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
|
if ( debugLock == 0 ) LWP_MutexInit( &debugLock, false );
|
2009-09-27 20:19:53 +02:00
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
|
LWP_MutexLock( debugLock );
|
2010-05-29 17:43:19 +02:00
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
|
FILE *fp = fopen( "SD:/debug.txt", "a" );
|
|
|
|
|
if ( fp )
|
|
|
|
|
{
|
|
|
|
|
char theTime[10];
|
|
|
|
|
time_t rawtime = time( 0 ); //this fixes code dump caused by the clock
|
|
|
|
|
struct tm * timeinfo = localtime ( &rawtime );
|
|
|
|
|
strftime( theTime, sizeof( theTime ), "%H:%M:%S", timeinfo );
|
|
|
|
|
char format[10+strlen( Format )+strlen( theTime )];
|
|
|
|
|
sprintf( format, "%s %i - %s\n", theTime, Line, Format );
|
|
|
|
|
va_list va;
|
|
|
|
|
va_start( va, Format );
|
|
|
|
|
vfprintf( fp, format, va );
|
|
|
|
|
va_end( va );
|
|
|
|
|
fclose( fp );
|
|
|
|
|
}
|
|
|
|
|
LWP_MutexUnlock( debugLock );
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
|
|
|
|
//#define DEBUG(format, ...) debug(__LINE__, format, ##__VA_ARGS__)
|
2010-05-29 17:43:19 +02:00
|
|
|
|
#define DEBUG(format, ...)
|
2009-09-27 20:19:53 +02:00
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
|
static void *memdup( const void* src, size_t len )
|
2010-02-09 11:59:55 +01:00
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
|
void *dst = malloc( len );
|
|
|
|
|
if ( dst ) memcpy( dst, src, len );
|
|
|
|
|
return dst;
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
|
|
|
|
static std::vector<GuiImageAsync *> List;
|
|
|
|
|
static u32 ThreadCount = 0;
|
|
|
|
|
static lwp_t Thread = LWP_THREAD_NULL;
|
|
|
|
|
static mutex_t ListLock = LWP_MUTEX_NULL;
|
|
|
|
|
static mutex_t InUseLock = LWP_MUTEX_NULL;
|
|
|
|
|
static GuiImageAsync *InUse = NULL;
|
|
|
|
|
static bool Quit = false;
|
|
|
|
|
static bool CanSleep = true;
|
2010-09-19 01:16:05 +02:00
|
|
|
|
void *GuiImageAsyncThread( void *arg )
|
2010-02-09 11:59:55 +01:00
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
|
while ( !Quit )
|
|
|
|
|
{
|
|
|
|
|
LWP_MutexLock( ListLock );
|
|
|
|
|
if ( List.size() )
|
|
|
|
|
{
|
|
|
|
|
LWP_MutexLock( InUseLock );
|
2009-09-27 20:19:53 +02:00
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
|
InUse = List.front();
|
|
|
|
|
List.erase( List.begin() );
|
2009-09-27 20:19:53 +02:00
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
|
LWP_MutexUnlock( ListLock );
|
2009-09-27 20:19:53 +02:00
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
|
if ( InUse )
|
|
|
|
|
{
|
|
|
|
|
GuiImageData *data = InUse->callback( InUse->arg );
|
|
|
|
|
InUse->loadet_imgdata = data;
|
|
|
|
|
if ( InUse->loadet_imgdata && InUse->loadet_imgdata->GetImage() )
|
|
|
|
|
{
|
|
|
|
|
// InUse->SetImage(InUse->loadet_imgdata); can<61>t use here. There can occur a deadlock
|
|
|
|
|
// Sets the image directly without lock. This is not fine, but it prevents a deadlock
|
|
|
|
|
InUse->image = InUse->loadet_imgdata->GetImage();
|
|
|
|
|
InUse->width = InUse->loadet_imgdata->GetWidth();
|
|
|
|
|
InUse->height = InUse->loadet_imgdata->GetHeight();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InUse = NULL;
|
|
|
|
|
LWP_MutexUnlock( InUseLock );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LWP_MutexUnlock( ListLock );
|
|
|
|
|
if ( !Quit && CanSleep )
|
|
|
|
|
LWP_SuspendThread( Thread );
|
|
|
|
|
}
|
|
|
|
|
CanSleep = true;
|
|
|
|
|
}
|
|
|
|
|
Quit = false;
|
|
|
|
|
return NULL;
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
|
static u32 GuiImageAsyncThreadInit()
|
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
|
if ( 0 == ThreadCount++ )
|
|
|
|
|
{
|
|
|
|
|
CanSleep = false;
|
|
|
|
|
LWP_MutexInit( &ListLock, false );
|
|
|
|
|
LWP_MutexInit( &InUseLock, false );
|
|
|
|
|
LWP_CreateThread( &Thread, GuiImageAsyncThread, NULL, NULL, 16384, 75 );
|
|
|
|
|
// while(!CanSleep)
|
|
|
|
|
// usleep(20);
|
|
|
|
|
}
|
|
|
|
|
return ThreadCount;
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
2010-02-09 11:59:55 +01:00
|
|
|
|
static u32 GuiImageAsyncThreadExit()
|
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
|
if ( --ThreadCount == 0 )
|
|
|
|
|
{
|
|
|
|
|
Quit = true;
|
|
|
|
|
LWP_ResumeThread( Thread );
|
|
|
|
|
// while(Quit)
|
|
|
|
|
// usleep(20);
|
|
|
|
|
LWP_JoinThread( Thread, NULL );
|
|
|
|
|
LWP_MutexDestroy( ListLock );
|
|
|
|
|
LWP_MutexDestroy( InUseLock );
|
|
|
|
|
Thread = LWP_THREAD_NULL;
|
|
|
|
|
ListLock = LWP_MUTEX_NULL;
|
|
|
|
|
InUseLock = LWP_MUTEX_NULL;
|
|
|
|
|
}
|
|
|
|
|
return ThreadCount;
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
|
static void GuiImageAsyncThread_AddImage( GuiImageAsync* Image )
|
2010-02-09 11:59:55 +01:00
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
|
LWP_MutexLock( ListLock );
|
|
|
|
|
List.push_back( Image );
|
|
|
|
|
LWP_MutexUnlock( ListLock );
|
|
|
|
|
CanSleep = false;
|
|
|
|
|
// if(LWP_ThreadIsSuspended(Thread))
|
|
|
|
|
LWP_ResumeThread( Thread );
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
2010-09-19 01:16:05 +02:00
|
|
|
|
static void GuiImageAsyncThread_RemoveImage( GuiImageAsync* Image )
|
2010-02-09 11:59:55 +01:00
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
|
LWP_MutexLock( ListLock );
|
|
|
|
|
for ( std::vector<GuiImageAsync *>::iterator iter = List.begin(); iter != List.end(); iter++ )
|
|
|
|
|
{
|
|
|
|
|
if ( *iter == Image )
|
|
|
|
|
{
|
|
|
|
|
List.erase( iter );
|
|
|
|
|
LWP_MutexUnlock( ListLock );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( InUse == Image )
|
|
|
|
|
{
|
|
|
|
|
LWP_MutexLock( InUseLock );
|
|
|
|
|
LWP_MutexUnlock( InUseLock );
|
|
|
|
|
}
|
|
|
|
|
LWP_MutexUnlock( ListLock );
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor for the GuiImageAsync class.
|
|
|
|
|
*/
|
2010-09-19 01:16:05 +02:00
|
|
|
|
GuiImageData *StdImageLoaderCallback( void *arg )
|
2010-02-09 11:59:55 +01:00
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
|
return new GuiImageData( ( char* )arg, NULL );
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
|
GuiImageAsync::GuiImageAsync( const char *Filename, GuiImageData * PreloadImg ) :
|
|
|
|
|
GuiImage( PreloadImg ),
|
|
|
|
|
loadet_imgdata( NULL ),
|
|
|
|
|
callback( StdImageLoaderCallback ),
|
|
|
|
|
arg( strdup( Filename ) )
|
2010-02-09 11:59:55 +01:00
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
|
GuiImageAsyncThreadInit();
|
|
|
|
|
GuiImageAsyncThread_AddImage( this );
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
2010-09-19 01:16:05 +02:00
|
|
|
|
GuiImageAsync::GuiImageAsync( ImageLoaderCallback Callback, void *Arg, int ArgLen, GuiImageData * PreloadImg ) :
|
|
|
|
|
GuiImage( PreloadImg ),
|
|
|
|
|
loadet_imgdata( NULL ),
|
|
|
|
|
callback( Callback ),
|
|
|
|
|
arg( memdup( Arg, ArgLen ) )
|
2010-02-09 11:59:55 +01:00
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
|
DEBUG( "Constructor %p", this );
|
|
|
|
|
GuiImageAsyncThreadInit();
|
|
|
|
|
GuiImageAsyncThread_AddImage( this );
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
2010-02-09 11:59:55 +01:00
|
|
|
|
GuiImageAsync::~GuiImageAsync()
|
|
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
|
GuiImageAsyncThread_RemoveImage( this );
|
|
|
|
|
GuiImageAsyncThreadExit();
|
|
|
|
|
DEBUG( "Deconstructor %p (loadet_imgdata=%p)", this, loadet_imgdata );
|
|
|
|
|
if ( loadet_imgdata ) delete loadet_imgdata;
|
|
|
|
|
if ( arg ) free( arg );
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
|
|
|
|
|