- filter homebrew launcher itself from the list of homebrews (issue 13)

- fixed random freeze caused from multi threaded access to elements list in a frame (issue 6)
- changed maximum depth of ELF file searching to 1 sub-directory only
- fixed wrong homebrew buttons order display in some cases (issue 15)
- bump hbl version to 1.3
This commit is contained in:
dimok789 2016-11-04 20:47:39 +01:00
parent 7cfd09726d
commit b6d29714c7
10 changed files with 140 additions and 40 deletions

View File

@ -2,8 +2,8 @@
<app version="1"> <app version="1">
<name>Homebrew Launcher</name> <name>Homebrew Launcher</name>
<coder>Dimok</coder> <coder>Dimok</coder>
<version>1.2</version> <version>1.3</version>
<release_date>20160402210000</release_date> <release_date>20161104210000</release_date>
<short_description>WiiU Homebrew Launcher</short_description> <short_description>WiiU Homebrew Launcher</short_description>
<long_description>Loads WiiU homebrew from SD card and from network. <long_description>Loads WiiU homebrew from SD card and from network.

View File

@ -7,7 +7,7 @@ extern "C" {
#include "os_defs.h" #include "os_defs.h"
#define HBL_VERSION "v1.2" #define HBL_VERSION "v1.3"
#define CAFE_OS_SD_PATH "/vol/external01" #define CAFE_OS_SD_PATH "/vol/external01"
#define SD_PATH "sd:" #define SD_PATH "sd:"

View File

@ -39,11 +39,12 @@ DirList::DirList()
{ {
Flags = 0; Flags = 0;
Filter = 0; Filter = 0;
Depth = 0;
} }
DirList::DirList(const std::string & path, const char *filter, u32 flags) DirList::DirList(const std::string & path, const char *filter, u32 flags, u32 maxDepth)
{ {
this->LoadPath(path, filter, flags); this->LoadPath(path, filter, flags, maxDepth);
this->SortList(); this->SortList();
} }
@ -52,12 +53,13 @@ DirList::~DirList()
ClearList(); ClearList();
} }
bool DirList::LoadPath(const std::string & folder, const char *filter, u32 flags) bool DirList::LoadPath(const std::string & folder, const char *filter, u32 flags, u32 maxDepth)
{ {
if(folder.empty()) return false; if(folder.empty()) return false;
Flags = flags; Flags = flags;
Filter = filter; Filter = filter;
Depth = maxDepth;
std::string folderpath(folder); std::string folderpath(folder);
u32 length = folderpath.size(); u32 length = folderpath.size();
@ -69,6 +71,10 @@ bool DirList::LoadPath(const std::string & folder, const char *filter, u32 flags
if(length > 0 && folderpath[length-1] == '/') if(length > 0 && folderpath[length-1] == '/')
folderpath.erase(length-1); folderpath.erase(length-1);
//! add root slash if missing
if(folderpath.find('/') == std::string::npos)
folderpath += '/';
return InternalLoadPath(folderpath); return InternalLoadPath(folderpath);
} }
@ -94,14 +100,17 @@ bool DirList::InternalLoadPath(std::string &folderpath)
if(strcmp(filename,".") == 0 || strcmp(filename,"..") == 0) if(strcmp(filename,".") == 0 || strcmp(filename,"..") == 0)
continue; continue;
if(Flags & CheckSubfolders) if((Flags & CheckSubfolders) && (Depth > 0))
{ {
int length = folderpath.size(); int length = folderpath.size();
if(length > 2 && folderpath[length-1] != '/') if(length > 2 && folderpath[length-1] != '/')
folderpath += '/'; folderpath += '/';
folderpath += filename; folderpath += filename;
Depth--;
InternalLoadPath(folderpath); InternalLoadPath(folderpath);
folderpath.erase(length); folderpath.erase(length);
Depth++;
} }
if(!(Flags & Dirs)) if(!(Flags & Dirs))

View File

@ -29,7 +29,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <gctypes.h> #include "common/types.h"
typedef struct typedef struct
{ {
@ -45,11 +45,11 @@ public:
//!\param path Path from where to load the filelist of all files //!\param path Path from where to load the filelist of all files
//!\param filter A fileext that needs to be filtered //!\param filter A fileext that needs to be filtered
//!\param flags search/filter flags from the enum //!\param flags search/filter flags from the enum
DirList(const std::string & path, const char *filter = NULL, u32 flags = Files | Dirs); DirList(const std::string & path, const char *filter = NULL, u32 flags = Files | Dirs, u32 maxDepth = 0xffffffff);
//!Destructor //!Destructor
virtual ~DirList(); virtual ~DirList();
//! Load all the files from a directory //! Load all the files from a directory
bool LoadPath(const std::string & path, const char *filter = NULL, u32 flags = Files | Dirs); bool LoadPath(const std::string & path, const char *filter = NULL, u32 flags = Files | Dirs, u32 maxDepth = 0xffffffff);
//! Get a filename of the list //! Get a filename of the list
//!\param list index //!\param list index
const char * GetFilename(int index) const; const char * GetFilename(int index) const;
@ -88,6 +88,7 @@ protected:
inline bool valid(u32 pos) const { return (pos < FileInfo.size()); }; inline bool valid(u32 pos) const { return (pos < FileInfo.size()); };
u32 Flags; u32 Flags;
u32 Depth;
const char *Filter; const char *Filter;
std::vector<DirEntry> FileInfo; std::vector<DirEntry> FileInfo;
}; };

View File

@ -51,9 +51,16 @@ void GuiFrame::append(GuiElement* e)
if (e == NULL) if (e == NULL)
return; return;
remove(e); e->setParent(this);
elements.push_back(e);
e->setParent(this); ListChangeElement elem;
elem.addElement = true;
elem.position = -1;
elem.element = e;
queueMutex.lock();
listChangeQueue.push(elem);
queueMutex.unlock();
} }
void GuiFrame::insert(GuiElement* e, u32 index) void GuiFrame::insert(GuiElement* e, u32 index)
@ -61,9 +68,16 @@ void GuiFrame::insert(GuiElement* e, u32 index)
if (e == NULL || (index >= elements.size())) if (e == NULL || (index >= elements.size()))
return; return;
remove(e); e->setParent(this);
elements.insert(elements.begin()+index, e);
e->setParent(this); ListChangeElement elem;
elem.addElement = true;
elem.position = index;
elem.element = e;
queueMutex.lock();
listChangeQueue.push(elem);
queueMutex.unlock();
} }
void GuiFrame::remove(GuiElement* e) void GuiFrame::remove(GuiElement* e)
@ -71,14 +85,14 @@ void GuiFrame::remove(GuiElement* e)
if (e == NULL) if (e == NULL)
return; return;
for (u32 i = 0; i < elements.size(); ++i) ListChangeElement elem;
{ elem.addElement = false;
if(e == elements[i]) elem.position = -1;
{ elem.element = e;
elements.erase(elements.begin()+i);
break; queueMutex.lock();
} listChangeQueue.push(elem);
} queueMutex.unlock();
} }
void GuiFrame::removeAll() void GuiFrame::removeAll()
@ -185,18 +199,21 @@ void GuiFrame::draw(CVideo * v)
void GuiFrame::updateEffects() void GuiFrame::updateEffects()
{ {
if(!this->isVisible() && parentElement) if(this->isVisible() || parentElement)
return; {
GuiElement::updateEffects();
GuiElement::updateEffects(); //! render appended items next frame but allow stop of render if size is reached
u32 size = elements.size();
//! render appended items next frame but allow stop of render if size is reached for (u32 i = 0; i < size && i < elements.size(); ++i)
u32 size = elements.size(); {
elements[i]->updateEffects();
}
}
for (u32 i = 0; i < size && i < elements.size(); ++i) //! at the end of main loop which this function represents append pending elements
{ updateElementList();
elements[i]->updateEffects();
}
} }
void GuiFrame::update(GuiController * c) void GuiFrame::update(GuiController * c)
@ -212,3 +229,39 @@ void GuiFrame::update(GuiController * c)
elements[i]->update(c); elements[i]->update(c);
} }
} }
void GuiFrame::updateElementList(void)
{
if(listChangeQueue.empty() == false)
{
queueMutex.lock();
while(!listChangeQueue.empty())
{
ListChangeElement & listChange = listChangeQueue.front();
for (u32 i = 0; i < elements.size(); ++i)
{
if(listChange.element == elements[i])
{
elements.erase(elements.begin()+i);
break;
}
}
if(listChange.addElement)
{
if(listChange.position >= 0)
{
elements.insert(elements.begin()+listChange.position, listChange.element);
}
else
{
elements.push_back(listChange.element);
}
}
listChangeQueue.pop();
}
queueMutex.unlock();
}
}

View File

@ -91,6 +91,17 @@ class GuiFrame : public GuiElement
bool dim; //! Enable/disable dim of a window only bool dim; //! Enable/disable dim of a window only
GuiFrame *parent; //!< Parent Window GuiFrame *parent; //!< Parent Window
std::vector<GuiElement*> elements; //!< Contains all elements within the GuiFrame std::vector<GuiElement*> elements; //!< Contains all elements within the GuiFrame
void updateElementList(void);
struct ListChangeElement
{
bool addElement;
int position;
GuiElement *element;
};
std::queue<ListChangeElement> listChangeQueue;
CMutex queueMutex;
}; };
#endif #endif

View File

@ -52,15 +52,15 @@ HomebrewWindow::HomebrewWindow(int w, int h)
currentLeftPosition = 0; currentLeftPosition = 0;
listOffset = 0; listOffset = 0;
DirList dirList("sd:/wiiu/apps", ".elf", DirList::Files | DirList::CheckSubfolders); DirList dirList("sd:/wiiu/apps", ".elf", DirList::Files | DirList::CheckSubfolders, 1);
dirList.SortList(); dirList.SortList();
for(int i = 0; i < dirList.GetFilecount(); i++) for(int i = 0; i < dirList.GetFilecount(); i++)
{ {
//! skip our own application in the listing //! skip our own application in the listing
//!if(strcasecmp(dirList.GetFilename(i), "homebrew_launcher.elf") == 0) if(strcasecmp(dirList.GetFilename(i), "homebrew_launcher.elf") == 0)
//! continue; continue;
//! skip hidden linux and mac files //! skip hidden linux and mac files
if(dirList.GetFilename(i)[0] == '.' || dirList.GetFilename(i)[0] == '_') if(dirList.GetFilename(i)[0] == '.' || dirList.GetFilename(i)[0] == '_')
@ -124,8 +124,8 @@ HomebrewWindow::HomebrewWindow(int w, int h)
homebrewButtons[idx].button->setLabel(homebrewButtons[idx].nameLabel, 0); homebrewButtons[idx].button->setLabel(homebrewButtons[idx].nameLabel, 0);
homebrewButtons[idx].button->setLabel(homebrewButtons[idx].descriptionLabel, 1); homebrewButtons[idx].button->setLabel(homebrewButtons[idx].descriptionLabel, 1);
homebrewButtons[idx].button->setIcon(homebrewButtons[idx].iconImg); homebrewButtons[idx].button->setIcon(homebrewButtons[idx].iconImg);
float fXOffset = (i / MAX_BUTTONS_ON_PAGE) * width; float fXOffset = (idx / MAX_BUTTONS_ON_PAGE) * width;
float fYOffset = (homebrewButtons[idx].image->getHeight() + 20.0f) * 1.5f - (homebrewButtons[idx].image->getHeight() + 20) * (i % MAX_BUTTONS_ON_PAGE); float fYOffset = (homebrewButtons[idx].image->getHeight() + 20.0f) * 1.5f - (homebrewButtons[idx].image->getHeight() + 20) * (idx % MAX_BUTTONS_ON_PAGE);
homebrewButtons[idx].button->setPosition(currentLeftPosition + fXOffset, fYOffset); homebrewButtons[idx].button->setPosition(currentLeftPosition + fXOffset, fYOffset);
homebrewButtons[idx].button->setTrigger(&touchTrigger); homebrewButtons[idx].button->setTrigger(&touchTrigger);
homebrewButtons[idx].button->setTrigger(&wpadTouchTrigger); homebrewButtons[idx].button->setTrigger(&wpadTouchTrigger);

View File

@ -24,6 +24,8 @@ ProgressWindow::ProgressWindow(const std::string & title)
, progressImageBlack(bgImage.getWidth(), bgImage.getHeight()/2, (GX2Color){0, 0, 0, 255}) , progressImageBlack(bgImage.getWidth(), bgImage.getHeight()/2, (GX2Color){0, 0, 0, 255})
, progressImageColored(bgImage.getWidth(), bgImage.getHeight()/2, (GX2Color){0, 0, 0, 255}) , progressImageColored(bgImage.getWidth(), bgImage.getHeight()/2, (GX2Color){0, 0, 0, 255})
{ {
titleChanged = false;
currentTitle = title;
width = bgImage.getWidth(); width = bgImage.getWidth();
height = bgImage.getHeight(); height = bgImage.getHeight();
@ -42,7 +44,7 @@ ProgressWindow::ProgressWindow(const std::string & title)
titleText.setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); titleText.setAlignment(ALIGN_LEFT | ALIGN_MIDDLE);
titleText.setPosition(50, 0); titleText.setPosition(50, 0);
titleText.setBlurGlowColor(5.0f, glm::vec4(0.0, 0.0, 0.0f, 1.0f)); titleText.setBlurGlowColor(5.0f, glm::vec4(0.0, 0.0, 0.0f, 1.0f));
titleText.setText(title.c_str()); titleText.setText(currentTitle.c_str());
append(&titleText); append(&titleText);
progressImageColored.setParent(&progressImageBlack); progressImageColored.setParent(&progressImageBlack);
@ -58,10 +60,26 @@ ProgressWindow::~ProgressWindow()
void ProgressWindow::setTitle(const std::string & title) void ProgressWindow::setTitle(const std::string & title)
{ {
titleText.setText(title.c_str()); titleMutex.lock();
currentTitle = title;
titleChanged = true;
titleMutex.unlock();
} }
void ProgressWindow::setProgress(f32 percent) void ProgressWindow::setProgress(f32 percent)
{ {
progressImageColored.setSize(percent * 0.01f * progressImageBlack.getWidth(), progressImageColored.getHeight()); progressImageColored.setSize(percent * 0.01f * progressImageBlack.getWidth(), progressImageColored.getHeight());
} }
void ProgressWindow::draw(CVideo * v)
{
if(titleChanged)
{
titleMutex.lock();
titleChanged = false;
titleText.setText(currentTitle.c_str());
titleMutex.unlock();
}
GuiFrame::draw(v);
}

View File

@ -28,6 +28,7 @@ public:
void setProgress(f32 percent); void setProgress(f32 percent);
void setTitle(const std::string & title); void setTitle(const std::string & title);
private: private:
void draw(CVideo * v);
GuiText titleText; GuiText titleText;
GuiImageData *bgImageData; GuiImageData *bgImageData;
@ -37,6 +38,10 @@ private:
GuiTrigger touchTrigger; GuiTrigger touchTrigger;
GuiTrigger wpadTouchTrigger; GuiTrigger wpadTouchTrigger;
bool titleChanged;
std::string currentTitle;
CMutex titleMutex;
}; };
#endif //_PROGRESS_WINDOW_H_ #endif //_PROGRESS_WINDOW_H_

View File

@ -79,6 +79,9 @@ void TcpReceiver::executeThread()
int result = loadToMemory(clientSocket, ipAddress); int result = loadToMemory(clientSocket, ipAddress);
serverReceiveFinished(this, ipAddress, result); serverReceiveFinished(this, ipAddress, result);
socketclose(clientSocket); socketclose(clientSocket);
if(result > 0)
break;
} }
else else
{ {