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-02-09 07:33:18 +01:00
|
|
|
|
void debug(int Line, const char* Format, ...) {
|
|
|
|
|
if (debugLock==0) LWP_MutexInit(&debugLock, false);
|
2009-09-27 20:19:53 +02:00
|
|
|
|
|
2010-02-09 07:33:18 +01:00
|
|
|
|
LWP_MutexLock(debugLock);
|
|
|
|
|
|
|
|
|
|
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-02-09 07:33:18 +01:00
|
|
|
|
#define DEBUG(format, ...)
|
2009-09-27 20:19:53 +02:00
|
|
|
|
|
2010-02-09 07:33:18 +01:00
|
|
|
|
static void *memdup(const void* src, size_t len) {
|
|
|
|
|
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-02-09 07:33:18 +01:00
|
|
|
|
void *GuiImageAsyncThread(void *arg) {
|
|
|
|
|
while (!Quit) {
|
|
|
|
|
LWP_MutexLock(ListLock);
|
|
|
|
|
if (List.size()) {
|
|
|
|
|
LWP_MutexLock(InUseLock);
|
2009-09-27 20:19:53 +02:00
|
|
|
|
|
2010-02-09 07:33:18 +01:00
|
|
|
|
InUse = List.front();
|
|
|
|
|
List.erase(List.begin());
|
2009-09-27 20:19:53 +02:00
|
|
|
|
|
2010-02-09 07:33:18 +01:00
|
|
|
|
LWP_MutexUnlock(ListLock);
|
2009-09-27 20:19:53 +02:00
|
|
|
|
|
2010-02-09 07:33:18 +01: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 07:33:18 +01:00
|
|
|
|
static u32 GuiImageAsyncThreadInit() {
|
|
|
|
|
if (0 == ThreadCount++) {
|
|
|
|
|
CanSleep = false;
|
|
|
|
|
LWP_MutexInit(&ListLock, false);
|
|
|
|
|
LWP_MutexInit(&InUseLock, false);
|
|
|
|
|
LWP_CreateThread(&Thread, GuiImageAsyncThread, NULL, NULL, 0, 75);
|
2009-09-27 20:19:53 +02:00
|
|
|
|
// while(!CanSleep)
|
|
|
|
|
// usleep(20);
|
2010-02-09 07:33:18 +01:00
|
|
|
|
}
|
|
|
|
|
return ThreadCount;
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
2010-02-09 07:33:18 +01:00
|
|
|
|
static u32 GuiImageAsyncThreadExit() {
|
|
|
|
|
if (--ThreadCount == 0) {
|
|
|
|
|
Quit = true;
|
|
|
|
|
LWP_ResumeThread(Thread);
|
2009-09-27 20:19:53 +02:00
|
|
|
|
// while(Quit)
|
|
|
|
|
// usleep(20);
|
2010-02-09 07:33:18 +01:00
|
|
|
|
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-02-09 07:33:18 +01:00
|
|
|
|
static void GuiImageAsyncThread_AddImage(GuiImageAsync* Image) {
|
|
|
|
|
LWP_MutexLock(ListLock);
|
|
|
|
|
List.push_back(Image);
|
|
|
|
|
LWP_MutexUnlock(ListLock);
|
|
|
|
|
CanSleep = false;
|
2009-09-27 20:19:53 +02:00
|
|
|
|
// if(LWP_ThreadIsSuspended(Thread))
|
2010-02-09 07:33:18 +01:00
|
|
|
|
LWP_ResumeThread(Thread);
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
2010-02-09 07:33:18 +01:00
|
|
|
|
static void GuiImageAsyncThread_RemoveImage(GuiImageAsync* Image) {
|
|
|
|
|
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-02-09 07:33:18 +01:00
|
|
|
|
GuiImageData *StdImageLoaderCallback(void *arg) {
|
|
|
|
|
return new GuiImageData((char*)arg, NULL);
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GuiImageAsync::GuiImageAsync(const char *Filename, GuiImageData * PreloadImg) :
|
2010-02-09 07:33:18 +01:00
|
|
|
|
GuiImage(PreloadImg),
|
|
|
|
|
loadet_imgdata(NULL),
|
|
|
|
|
callback(StdImageLoaderCallback),
|
|
|
|
|
arg(strdup(Filename)) {
|
|
|
|
|
GuiImageAsyncThreadInit();
|
|
|
|
|
GuiImageAsyncThread_AddImage(this);
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
|
|
|
|
GuiImageAsync::GuiImageAsync(ImageLoaderCallback Callback, void *Arg, int ArgLen, GuiImageData * PreloadImg) :
|
2010-02-09 07:33:18 +01:00
|
|
|
|
GuiImage(PreloadImg),
|
|
|
|
|
loadet_imgdata(NULL),
|
|
|
|
|
callback(Callback),
|
|
|
|
|
arg(memdup(Arg, ArgLen)) {
|
|
|
|
|
DEBUG("Constructor %p", this);
|
|
|
|
|
GuiImageAsyncThreadInit();
|
|
|
|
|
GuiImageAsyncThread_AddImage(this);
|
2009-09-27 20:19:53 +02:00
|
|
|
|
}
|
2010-02-09 07:33:18 +01:00
|
|
|
|
GuiImageAsync::~GuiImageAsync() {
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|