mirror of
https://github.com/XorTroll/uLaunch
synced 2024-11-22 11:53:06 +00:00
Fully fix menu logic and UI issues
This commit is contained in:
parent
79de9de4a1
commit
bb0f03fbc8
16 changed files with 334 additions and 252 deletions
|
@ -24,4 +24,5 @@ namespace am
|
||||||
Result ApplicationSetForeground();
|
Result ApplicationSetForeground();
|
||||||
Result ApplicationSend(void *data, size_t size, AppletLaunchParameterKind kind = AppletLaunchParameterKind_UserChannel);
|
Result ApplicationSend(void *data, size_t size, AppletLaunchParameterKind kind = AppletLaunchParameterKind_UserChannel);
|
||||||
u64 ApplicationGetId();
|
u64 ApplicationGetId();
|
||||||
|
Result ApplicationGetResult();
|
||||||
}
|
}
|
|
@ -106,6 +106,7 @@ namespace cfg
|
||||||
void SaveConfig(Config &cfg);
|
void SaveConfig(Config &cfg);
|
||||||
|
|
||||||
void SaveRecord(TitleRecord &record);
|
void SaveRecord(TitleRecord &record);
|
||||||
|
void RemoveRecord(TitleRecord &record);
|
||||||
bool MoveRecordTo(TitleList &list, TitleRecord record, std::string folder);
|
bool MoveRecordTo(TitleList &list, TitleRecord record, std::string folder);
|
||||||
TitleFolder &FindFolderByName(TitleList &list, std::string name);
|
TitleFolder &FindFolderByName(TitleList &list, std::string name);
|
||||||
bool ExistsRecord(TitleList &list, TitleRecord record);
|
bool ExistsRecord(TitleList &list, TitleRecord record);
|
||||||
|
|
|
@ -6,4 +6,5 @@ namespace os
|
||||||
{
|
{
|
||||||
u32 GetBatteryLevel();
|
u32 GetBatteryLevel();
|
||||||
bool IsConsoleCharging();
|
bool IsConsoleCharging();
|
||||||
|
std::string GetFirmwareVersion();
|
||||||
}
|
}
|
|
@ -50,9 +50,10 @@ static constexpr size_t RawRGBAScreenBufferSize = 1280 * 720 * 4;
|
||||||
} \
|
} \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define STLITER_FINDWITHCONDITION(stl_item, var_name, cond) std::find_if(stl_item.begin(), stl_item.end(), [&](auto &var_name){ return (cond); });
|
#define STL_FIND_IF(stl_item, var_name, cond) std::find_if(stl_item.begin(), stl_item.end(), [&](const auto &var_name){ return (cond); });
|
||||||
#define STLITER_ISFOUND(stl_item, find_ret) (find_ret != stl_item.end())
|
#define STL_FOUND(stl_item, find_ret) (find_ret != stl_item.end())
|
||||||
#define STLITER_UNWRAP(find_ret) (*find_ret)
|
#define STL_UNWRAP(find_ret) (*find_ret)
|
||||||
|
#define STL_REMOVE_IF(stl_item, var_name, cond) stl_item.erase(std::remove_if(stl_item.begin(), stl_item.end(), [&](const auto &var_name){ return (cond); }), stl_item.end());
|
||||||
|
|
||||||
template<typename ...Args>
|
template<typename ...Args>
|
||||||
using ResultWith = std::tuple<Result, Args...>;
|
using ResultWith = std::tuple<Result, Args...>;
|
||||||
|
|
|
@ -257,7 +257,10 @@ namespace cfg
|
||||||
if(record.json_name.empty()) record.json_name = jsonname;
|
if(record.json_name.empty()) record.json_name = jsonname;
|
||||||
json += "/" + jsonname;
|
json += "/" + jsonname;
|
||||||
entry["nro_path"] = record.nro_target.nro_path;
|
entry["nro_path"] = record.nro_target.nro_path;
|
||||||
if(strcmp(record.nro_target.nro_path, record.nro_target.argv) != 0) entry["nro_argv"] = record.nro_target.argv;
|
if(strlen(record.nro_target.argv))
|
||||||
|
{
|
||||||
|
if(strcmp(record.nro_target.nro_path, record.nro_target.argv) != 0) entry["nro_argv"] = record.nro_target.argv;
|
||||||
|
}
|
||||||
if(!record.icon.empty()) entry["icon"] = record.icon;
|
if(!record.icon.empty()) entry["icon"] = record.icon;
|
||||||
}
|
}
|
||||||
else if((TitleType)record.title_type == TitleType::Installed)
|
else if((TitleType)record.title_type == TitleType::Installed)
|
||||||
|
@ -277,6 +280,28 @@ namespace cfg
|
||||||
ofs.close();
|
ofs.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RemoveRecord(TitleRecord &record)
|
||||||
|
{
|
||||||
|
// Prepare JSON path
|
||||||
|
std::string basepath = Q_ENTRIES_PATH;
|
||||||
|
std::string json = basepath;
|
||||||
|
if((TitleType)record.title_type == TitleType::Homebrew)
|
||||||
|
{
|
||||||
|
auto jsonname = std::to_string(fs::GetFileSize(record.nro_target.nro_path)) + ".json";
|
||||||
|
if(record.json_name.empty()) record.json_name = jsonname;
|
||||||
|
json += "/" + jsonname;
|
||||||
|
}
|
||||||
|
else if((TitleType)record.title_type == TitleType::Installed)
|
||||||
|
{
|
||||||
|
auto strappid = util::FormatApplicationId(record.app_id);
|
||||||
|
auto jsonname = strappid + ".json";
|
||||||
|
if(record.json_name.empty()) record.json_name = jsonname;
|
||||||
|
json += "/" + jsonname;
|
||||||
|
}
|
||||||
|
if(!record.json_name.empty()) json = basepath + "/" + record.json_name;
|
||||||
|
fs::DeleteFile(json);
|
||||||
|
}
|
||||||
|
|
||||||
bool MoveTitleToDirectory(TitleList &list, u64 app_id, std::string folder)
|
bool MoveTitleToDirectory(TitleList &list, u64 app_id, std::string folder)
|
||||||
{
|
{
|
||||||
bool title_found = false;
|
bool title_found = false;
|
||||||
|
@ -284,11 +309,11 @@ namespace cfg
|
||||||
std::string recjson;
|
std::string recjson;
|
||||||
|
|
||||||
// Search in root first
|
// Search in root first
|
||||||
auto find = STLITER_FINDWITHCONDITION(list.root.titles, tit, (tit.app_id == app_id));
|
auto find = STL_FIND_IF(list.root.titles, tit, (tit.app_id == app_id));
|
||||||
if(STLITER_ISFOUND(list.root.titles, find))
|
if(STL_FOUND(list.root.titles, find))
|
||||||
{
|
{
|
||||||
if(folder.empty()) return true; // It is already on root...?
|
if(folder.empty()) return true; // It is already on root...?
|
||||||
recjson = STLITER_UNWRAP(find).json_name;
|
recjson = STL_UNWRAP(find).json_name;
|
||||||
|
|
||||||
list.root.titles.erase(find);
|
list.root.titles.erase(find);
|
||||||
title_found = true;
|
title_found = true;
|
||||||
|
@ -298,11 +323,11 @@ namespace cfg
|
||||||
{
|
{
|
||||||
for(auto &fld: list.folders)
|
for(auto &fld: list.folders)
|
||||||
{
|
{
|
||||||
auto find = STLITER_FINDWITHCONDITION(fld.titles, entry, (entry.app_id == app_id));
|
auto find = STL_FIND_IF(fld.titles, entry, (entry.app_id == app_id));
|
||||||
if(STLITER_ISFOUND(fld.titles, find))
|
if(STL_FOUND(fld.titles, find))
|
||||||
{
|
{
|
||||||
if(fld.name == folder) return true; // It is already on that folder...?
|
if(fld.name == folder) return true; // It is already on that folder...?
|
||||||
recjson = STLITER_UNWRAP(find).json_name;
|
recjson = STL_UNWRAP(find).json_name;
|
||||||
|
|
||||||
fld.titles.erase(find);
|
fld.titles.erase(find);
|
||||||
title_found = true;
|
title_found = true;
|
||||||
|
@ -325,10 +350,10 @@ namespace cfg
|
||||||
}
|
}
|
||||||
else // Add it to the new folder
|
else // Add it to the new folder
|
||||||
{
|
{
|
||||||
auto find2 = STLITER_FINDWITHCONDITION(list.folders, fld, (fld.name == folder));
|
auto find2 = STL_FIND_IF(list.folders, fld, (fld.name == folder));
|
||||||
if(STLITER_ISFOUND(list.folders, find2))
|
if(STL_FOUND(list.folders, find2))
|
||||||
{
|
{
|
||||||
STLITER_UNWRAP(find2).titles.push_back(title);
|
STL_UNWRAP(find2).titles.push_back(title);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -354,11 +379,11 @@ namespace cfg
|
||||||
// Search in root first
|
// Search in root first
|
||||||
if((TitleType)record.title_type == TitleType::Installed)
|
if((TitleType)record.title_type == TitleType::Installed)
|
||||||
{
|
{
|
||||||
auto find = STLITER_FINDWITHCONDITION(list.root.titles, tit, (tit.title_type == record.title_type) && (tit.app_id == record.app_id));
|
auto find = STL_FIND_IF(list.root.titles, tit, (tit.title_type == record.title_type) && (tit.app_id == record.app_id));
|
||||||
if(STLITER_ISFOUND(list.root.titles, find))
|
if(STL_FOUND(list.root.titles, find))
|
||||||
{
|
{
|
||||||
if(folder.empty()) return true; // It is already on root...?
|
if(folder.empty()) return true; // It is already on root...?
|
||||||
recjson = STLITER_UNWRAP(find).json_name;
|
recjson = STL_UNWRAP(find).json_name;
|
||||||
|
|
||||||
list.root.titles.erase(find);
|
list.root.titles.erase(find);
|
||||||
title_found = true;
|
title_found = true;
|
||||||
|
@ -366,11 +391,11 @@ namespace cfg
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto find = STLITER_FINDWITHCONDITION(list.root.titles, tit, (tit.title_type == record.title_type) && (strcmp(tit.nro_target.nro_path, record.nro_target.nro_path) == 0));
|
auto find = STL_FIND_IF(list.root.titles, tit, (tit.title_type == record.title_type) && (strcmp(tit.nro_target.nro_path, record.nro_target.nro_path) == 0));
|
||||||
if(STLITER_ISFOUND(list.root.titles, find))
|
if(STL_FOUND(list.root.titles, find))
|
||||||
{
|
{
|
||||||
if(folder.empty()) return true; // It is already on root...?
|
if(folder.empty()) return true; // It is already on root...?
|
||||||
recjson = STLITER_UNWRAP(find).json_name;
|
recjson = STL_UNWRAP(find).json_name;
|
||||||
|
|
||||||
list.root.titles.erase(find);
|
list.root.titles.erase(find);
|
||||||
title_found = true;
|
title_found = true;
|
||||||
|
@ -383,11 +408,11 @@ namespace cfg
|
||||||
{
|
{
|
||||||
if((TitleType)record.title_type == TitleType::Installed)
|
if((TitleType)record.title_type == TitleType::Installed)
|
||||||
{
|
{
|
||||||
auto find = STLITER_FINDWITHCONDITION(fld.titles, tit, (tit.title_type == record.title_type) && (tit.app_id == record.app_id));
|
auto find = STL_FIND_IF(fld.titles, tit, (tit.title_type == record.title_type) && (tit.app_id == record.app_id));
|
||||||
if(STLITER_ISFOUND(fld.titles, find))
|
if(STL_FOUND(fld.titles, find))
|
||||||
{
|
{
|
||||||
if(fld.name == folder) return true; // It is already on that folder...?
|
if(fld.name == folder) return true; // It is already on that folder...?
|
||||||
recjson = STLITER_UNWRAP(find).json_name;
|
recjson = STL_UNWRAP(find).json_name;
|
||||||
|
|
||||||
fld.titles.erase(find);
|
fld.titles.erase(find);
|
||||||
title_found = true;
|
title_found = true;
|
||||||
|
@ -396,11 +421,11 @@ namespace cfg
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto find = STLITER_FINDWITHCONDITION(fld.titles, tit, (tit.title_type == record.title_type) && (strcmp(tit.nro_target.nro_path, record.nro_target.nro_path) == 0));
|
auto find = STL_FIND_IF(fld.titles, tit, (tit.title_type == record.title_type) && (strcmp(tit.nro_target.nro_path, record.nro_target.nro_path) == 0));
|
||||||
if(STLITER_ISFOUND(fld.titles, find))
|
if(STL_FOUND(fld.titles, find))
|
||||||
{
|
{
|
||||||
if(fld.name == folder) return true; // It is already on that folder...?
|
if(fld.name == folder) return true; // It is already on that folder...?
|
||||||
recjson = STLITER_UNWRAP(find).json_name;
|
recjson = STL_UNWRAP(find).json_name;
|
||||||
|
|
||||||
fld.titles.erase(find);
|
fld.titles.erase(find);
|
||||||
title_found = true;
|
title_found = true;
|
||||||
|
@ -422,10 +447,10 @@ namespace cfg
|
||||||
}
|
}
|
||||||
else // Add it to the new folder
|
else // Add it to the new folder
|
||||||
{
|
{
|
||||||
auto find2 = STLITER_FINDWITHCONDITION(list.folders, fld, (fld.name == folder));
|
auto find2 = STL_FIND_IF(list.folders, fld, (fld.name == folder));
|
||||||
if(STLITER_ISFOUND(list.folders, find2))
|
if(STL_FOUND(list.folders, find2))
|
||||||
{
|
{
|
||||||
STLITER_UNWRAP(find2).titles.push_back(title);
|
STL_UNWRAP(find2).titles.push_back(title);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -446,10 +471,10 @@ namespace cfg
|
||||||
{
|
{
|
||||||
if(!name.empty())
|
if(!name.empty())
|
||||||
{
|
{
|
||||||
auto f = STLITER_FINDWITHCONDITION(list.folders, fld, (fld.name == name));
|
auto f = STL_FIND_IF(list.folders, fld, (fld.name == name));
|
||||||
if(STLITER_ISFOUND(list.folders, f))
|
if(STL_FOUND(list.folders, f))
|
||||||
{
|
{
|
||||||
return STLITER_UNWRAP(f);
|
return STL_UNWRAP(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list.root;
|
return list.root;
|
||||||
|
@ -464,18 +489,18 @@ namespace cfg
|
||||||
// Search in root first
|
// Search in root first
|
||||||
if((TitleType)record.title_type == TitleType::Installed)
|
if((TitleType)record.title_type == TitleType::Installed)
|
||||||
{
|
{
|
||||||
auto find = STLITER_FINDWITHCONDITION(list.root.titles, tit, (tit.title_type == record.title_type) && (tit.app_id == record.app_id));
|
auto find = STL_FIND_IF(list.root.titles, tit, (tit.title_type == record.title_type) && (tit.app_id == record.app_id));
|
||||||
if(STLITER_ISFOUND(list.root.titles, find))
|
if(STL_FOUND(list.root.titles, find))
|
||||||
{
|
{
|
||||||
if(!STLITER_UNWRAP(find).json_name.empty()) title_found = true;
|
if(!STL_UNWRAP(find).json_name.empty()) title_found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto find = STLITER_FINDWITHCONDITION(list.root.titles, tit, (tit.title_type == record.title_type) && (strcmp(tit.nro_target.nro_path, record.nro_target.nro_path) == 0));
|
auto find = STL_FIND_IF(list.root.titles, tit, (tit.title_type == record.title_type) && (strcmp(tit.nro_target.nro_path, record.nro_target.nro_path) == 0));
|
||||||
if(STLITER_ISFOUND(list.root.titles, find))
|
if(STL_FOUND(list.root.titles, find))
|
||||||
{
|
{
|
||||||
if(!STLITER_UNWRAP(find).json_name.empty()) title_found = true;
|
if(!STL_UNWRAP(find).json_name.empty()) title_found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,10 +510,10 @@ namespace cfg
|
||||||
{
|
{
|
||||||
if((TitleType)record.title_type == TitleType::Installed)
|
if((TitleType)record.title_type == TitleType::Installed)
|
||||||
{
|
{
|
||||||
auto find = STLITER_FINDWITHCONDITION(fld.titles, tit, (tit.title_type == record.title_type) && (tit.app_id == record.app_id));
|
auto find = STL_FIND_IF(fld.titles, tit, (tit.title_type == record.title_type) && (tit.app_id == record.app_id));
|
||||||
if(STLITER_ISFOUND(fld.titles, find))
|
if(STL_FOUND(fld.titles, find))
|
||||||
{
|
{
|
||||||
if(!STLITER_UNWRAP(find).json_name.empty())
|
if(!STL_UNWRAP(find).json_name.empty())
|
||||||
{
|
{
|
||||||
title_found = true;
|
title_found = true;
|
||||||
break;
|
break;
|
||||||
|
@ -497,10 +522,10 @@ namespace cfg
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto find = STLITER_FINDWITHCONDITION(fld.titles, tit, (tit.title_type == record.title_type) && (strcmp(tit.nro_target.nro_path, record.nro_target.nro_path) == 0));
|
auto find = STL_FIND_IF(fld.titles, tit, (tit.title_type == record.title_type) && (strcmp(tit.nro_target.nro_path, record.nro_target.nro_path) == 0));
|
||||||
if(STLITER_ISFOUND(fld.titles, find))
|
if(STL_FOUND(fld.titles, find))
|
||||||
{
|
{
|
||||||
if(!STLITER_UNWRAP(find).json_name.empty())
|
if(!STL_UNWRAP(find).json_name.empty())
|
||||||
{
|
{
|
||||||
title_found = true;
|
title_found = true;
|
||||||
break;
|
break;
|
||||||
|
@ -550,16 +575,16 @@ namespace cfg
|
||||||
rec.app_id = appid;
|
rec.app_id = appid;
|
||||||
rec.title_type = (u32)TitleType::Installed;
|
rec.title_type = (u32)TitleType::Installed;
|
||||||
|
|
||||||
auto find = STLITER_FINDWITHCONDITION(list.root.titles, tit, (tit.app_id == appid));
|
auto find = STL_FIND_IF(list.root.titles, tit, (tit.app_id == appid));
|
||||||
if(STLITER_ISFOUND(list.root.titles, find))
|
if(STL_FOUND(list.root.titles, find))
|
||||||
{
|
{
|
||||||
list.root.titles.erase(find);
|
list.root.titles.erase(find);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto find2 = STLITER_FINDWITHCONDITION(list.folders, fld, (fld.name == folder));
|
auto find2 = STL_FIND_IF(list.folders, fld, (fld.name == folder));
|
||||||
if(STLITER_ISFOUND(list.folders, find2))
|
if(STL_FOUND(list.folders, find2))
|
||||||
{
|
{
|
||||||
STLITER_UNWRAP(find2).titles.push_back(rec);
|
STL_UNWRAP(find2).titles.push_back(rec);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -590,8 +615,8 @@ namespace cfg
|
||||||
if(folder.empty()) list.root.titles.push_back(rec);
|
if(folder.empty()) list.root.titles.push_back(rec);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto find = STLITER_FINDWITHCONDITION(list.folders, fld, (fld.name == folder));
|
auto find = STL_FIND_IF(list.folders, fld, (fld.name == folder));
|
||||||
if(STLITER_ISFOUND(list.folders, find)) STLITER_UNWRAP(find).titles.push_back(rec);
|
if(STL_FOUND(list.folders, find)) STL_UNWRAP(find).titles.push_back(rec);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TitleFolder fld = {};
|
TitleFolder fld = {};
|
||||||
|
|
|
@ -15,4 +15,11 @@ namespace os
|
||||||
psmGetChargerType(&cht);
|
psmGetChargerType(&cht);
|
||||||
return (cht > ChargerType_None);
|
return (cht > ChargerType_None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetFirmwareVersion()
|
||||||
|
{
|
||||||
|
SetSysFirmwareVersion fwver;
|
||||||
|
setsysGetFirmwareVersion(&fwver);
|
||||||
|
return std::string(fwver.display_version);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -61,8 +61,6 @@ namespace ui
|
||||||
bool warnshown;
|
bool warnshown;
|
||||||
bool homebrew_mode;
|
bool homebrew_mode;
|
||||||
u8 minalpha;
|
u8 minalpha;
|
||||||
u32 root_idx;
|
|
||||||
u32 root_baseidx;
|
|
||||||
u32 mode;
|
u32 mode;
|
||||||
s32 rawalpha;
|
s32 rawalpha;
|
||||||
pu::audio::Sfx sfxTitleLaunch;
|
pu::audio::Sfx sfxTitleLaunch;
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 2 KiB |
|
@ -14,20 +14,25 @@ extern "C"
|
||||||
size_t __nx_heap_size = 0x10000000; // 256MB heap - now we can use as much as we want from the applet pool ;)
|
size_t __nx_heap_size = 0x10000000; // 256MB heap - now we can use as much as we want from the applet pool ;)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Some global vars
|
||||||
|
|
||||||
ui::QMenuApplication::Ref qapp;
|
ui::QMenuApplication::Ref qapp;
|
||||||
cfg::TitleList list;
|
cfg::TitleList list;
|
||||||
std::vector<cfg::TitleRecord> homebrew;
|
std::vector<cfg::TitleRecord> homebrew;
|
||||||
cfg::Config config;
|
cfg::Config config;
|
||||||
cfg::ProcessedTheme theme;
|
cfg::ProcessedTheme theme;
|
||||||
|
u8 *app_buf;
|
||||||
|
|
||||||
namespace qmenu
|
namespace qmenu
|
||||||
{
|
{
|
||||||
void Initialize(bool cache_homebrew)
|
void Initialize()
|
||||||
{
|
{
|
||||||
accountInitialize();
|
accountInitialize();
|
||||||
nsInitialize();
|
nsInitialize();
|
||||||
nifmInitialize();
|
nifmInitialize();
|
||||||
psmInitialize();
|
psmInitialize();
|
||||||
|
setsysInitialize();
|
||||||
|
|
||||||
db::Mount();
|
db::Mount();
|
||||||
fs::CreateDirectory(Q_BASE_DB_DIR);
|
fs::CreateDirectory(Q_BASE_DB_DIR);
|
||||||
fs::CreateDirectory(Q_BASE_SD_DIR);
|
fs::CreateDirectory(Q_BASE_SD_DIR);
|
||||||
|
@ -37,10 +42,11 @@ namespace qmenu
|
||||||
fs::CreateDirectory(Q_BASE_SD_DIR "/user");
|
fs::CreateDirectory(Q_BASE_SD_DIR "/user");
|
||||||
fs::CreateDirectory(Q_BASE_SD_DIR "/nro");
|
fs::CreateDirectory(Q_BASE_SD_DIR "/nro");
|
||||||
db::Commit();
|
db::Commit();
|
||||||
|
|
||||||
am::QMenu_InitializeDaemonService();
|
am::QMenu_InitializeDaemonService();
|
||||||
|
|
||||||
// Cache all homebrew (is this too slow...?)
|
// Cache all homebrew (is this too slow...?)
|
||||||
homebrew = cfg::QueryAllHomebrew(cache_homebrew);
|
homebrew = cfg::QueryAllHomebrew(true);
|
||||||
|
|
||||||
// Load menu config
|
// Load menu config
|
||||||
config = cfg::EnsureConfig();
|
config = cfg::EnsureConfig();
|
||||||
|
@ -53,7 +59,10 @@ namespace qmenu
|
||||||
void Exit()
|
void Exit()
|
||||||
{
|
{
|
||||||
am::QMenu_FinalizeDaemonService();
|
am::QMenu_FinalizeDaemonService();
|
||||||
|
|
||||||
db::Unmount();
|
db::Unmount();
|
||||||
|
|
||||||
|
setsysExit();
|
||||||
psmExit();
|
psmExit();
|
||||||
nifmExit();
|
nifmExit();
|
||||||
nsExit();
|
nsExit();
|
||||||
|
@ -61,15 +70,13 @@ namespace qmenu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *app_buf;
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
auto [rc, smode] = am::QMenu_ProcessInput();
|
auto [rc, smode] = am::QMenu_ProcessInput();
|
||||||
if(R_SUCCEEDED(rc))
|
if(R_SUCCEEDED(rc))
|
||||||
{
|
{
|
||||||
app_buf = new u8[RawRGBAScreenBufferSize]();
|
app_buf = new u8[RawRGBAScreenBufferSize]();
|
||||||
qmenu::Initialize(smode == am::QMenuStartMode::StartupScreen); // Cache homebrew only on first launch
|
qmenu::Initialize();
|
||||||
auto [_rc, menulist] = cfg::LoadTitleList(true);
|
auto [_rc, menulist] = cfg::LoadTitleList(true);
|
||||||
list = menulist;
|
list = menulist;
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,6 @@ namespace ui
|
||||||
this->susptr = raw;
|
this->susptr = raw;
|
||||||
this->mode = 0;
|
this->mode = 0;
|
||||||
this->rawalpha = 255;
|
this->rawalpha = 255;
|
||||||
this->root_idx = 0;
|
|
||||||
this->root_baseidx = 0;
|
|
||||||
this->last_hasconn = false;
|
this->last_hasconn = false;
|
||||||
this->last_batterylvl = 0;
|
this->last_batterylvl = 0;
|
||||||
this->last_charge = false;
|
this->last_charge = false;
|
||||||
|
@ -111,131 +109,166 @@ namespace ui
|
||||||
|
|
||||||
void MenuLayout::menu_Click(u64 down, u32 index)
|
void MenuLayout::menu_Click(u64 down, u32 index)
|
||||||
{
|
{
|
||||||
if(index == 0)
|
if((down & KEY_A) || (down & KEY_X) || (down & KEY_Y))
|
||||||
{
|
{
|
||||||
if(down & KEY_A)
|
if(index == 0)
|
||||||
{
|
{
|
||||||
if(this->homebrew_mode)
|
if(down & KEY_A)
|
||||||
{
|
{
|
||||||
am::QMenuCommandWriter writer(am::QDaemonMessage::LaunchHomebrewLibApplet);
|
if(this->homebrew_mode)
|
||||||
hb::TargetInput ipt = {};
|
|
||||||
strcpy(ipt.nro_path, "sdmc:/hbmenu.nro"); // Launch normal hbmenu
|
|
||||||
strcpy(ipt.argv, "sdmc:/hbmenu.nro");
|
|
||||||
writer.Write<hb::TargetInput>(ipt);
|
|
||||||
writer.FinishWrite();
|
|
||||||
|
|
||||||
pu::audio::Play(this->sfxTitleLaunch);
|
|
||||||
qapp->StopPlayBGM();
|
|
||||||
qapp->CloseWithFadeOut();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qapp->CreateShowDialog("All", "All titles...", {"Ok"}, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
u32 realidx = index - 1;
|
|
||||||
if(this->homebrew_mode)
|
|
||||||
{
|
|
||||||
auto hb = homebrew[realidx];
|
|
||||||
if(down & KEY_A) this->HandleHomebrewLaunch(hb);
|
|
||||||
else if(down & KEY_X)
|
|
||||||
{
|
|
||||||
auto sopt = qapp->CreateShowDialog("Add to menu", "Would you like to add this homebrew to the main menu?", { "Yes", "Cancel" }, true);
|
|
||||||
if(sopt == 0)
|
|
||||||
{
|
{
|
||||||
if(cfg::ExistsRecord(list, hb)) qapp->CreateShowDialog("Add to menu", "The homebrew is alredy in the main menu.\nNothing was added nor removed.", { "Ok" }, true);
|
am::QMenuCommandWriter writer(am::QDaemonMessage::LaunchHomebrewLibApplet);
|
||||||
else
|
hb::TargetInput ipt = {};
|
||||||
{
|
strcpy(ipt.nro_path, "sdmc:/hbmenu.nro"); // Launch normal hbmenu
|
||||||
cfg::SaveRecord(hb);
|
strcpy(ipt.argv, "sdmc:/hbmenu.nro");
|
||||||
list.root.titles.push_back(hb);
|
writer.Write<hb::TargetInput>(ipt);
|
||||||
qapp->CreateShowDialog("Add to menu", "The homebrew was successfully added to the main menu.", { "Ok" }, true);
|
writer.FinishWrite();
|
||||||
}
|
|
||||||
|
pu::audio::Play(this->sfxTitleLaunch);
|
||||||
|
qapp->StopPlayBGM();
|
||||||
|
qapp->CloseWithFadeOut();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qapp->CreateShowDialog("All", "All titles...", {"Ok"}, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto &folder = cfg::FindFolderByName(list, this->curfolder);
|
u32 realidx = index - 1;
|
||||||
if(realidx < folder.titles.size())
|
if(this->homebrew_mode)
|
||||||
{
|
{
|
||||||
auto title = folder.titles[realidx];
|
auto hb = homebrew[realidx];
|
||||||
if(down & KEY_A)
|
if(down & KEY_A) this->HandleHomebrewLaunch(hb);
|
||||||
{
|
|
||||||
if(!qapp->IsSuspended())
|
|
||||||
{
|
|
||||||
if((cfg::TitleType)title.title_type == cfg::TitleType::Homebrew) this->HandleHomebrewLaunch(title);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
am::QMenuCommandWriter writer(am::QDaemonMessage::LaunchApplication);
|
|
||||||
writer.Write<u64>(title.app_id);
|
|
||||||
writer.FinishWrite();
|
|
||||||
|
|
||||||
am::QMenuCommandResultReader reader;
|
|
||||||
if(reader && R_SUCCEEDED(reader.GetReadResult()))
|
|
||||||
{
|
|
||||||
pu::audio::Play(this->sfxTitleLaunch);
|
|
||||||
qapp->StopPlayBGM();
|
|
||||||
qapp->CloseWithFadeOut();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto rc = reader.GetReadResult();
|
|
||||||
qapp->CreateShowDialog("Title launch", "An error ocurred attempting to launch the title:\n" + util::FormatResultDisplay(rc) + " (" + util::FormatResultHex(rc) + ")", { "Ok" }, true);
|
|
||||||
}
|
|
||||||
reader.FinishRead();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if((cfg::TitleType)title.title_type == cfg::TitleType::Homebrew)
|
|
||||||
{
|
|
||||||
if(std::string(title.nro_target.nro_path) == qapp->GetSuspendedHomebrewPath())
|
|
||||||
{
|
|
||||||
if(this->mode == 1) this->mode = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(title.app_id == qapp->GetSuspendedApplicationId())
|
|
||||||
{
|
|
||||||
if(this->mode == 1) this->mode = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(down & KEY_X)
|
else if(down & KEY_X)
|
||||||
{
|
{
|
||||||
if(qapp->IsSuspended())
|
if(qapp->IsSuspended())
|
||||||
{
|
{
|
||||||
if((cfg::TitleType)title.title_type == cfg::TitleType::Homebrew)
|
if(std::string(hb.nro_target.nro_path) == qapp->GetSuspendedHomebrewPath()) this->HandleCloseSuspended();
|
||||||
{
|
|
||||||
if(std::string(title.nro_target.nro_path) == qapp->GetSuspendedHomebrewPath()) this->HandleCloseSuspended();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(title.app_id == qapp->GetSuspendedApplicationId()) this->HandleCloseSuspended();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(down & KEY_Y)
|
else if(down & KEY_Y)
|
||||||
{
|
{
|
||||||
if(this->HandleFolderChange(title))
|
auto sopt = qapp->CreateShowDialog("Add to menu", "Would you like to add this homebrew to the main menu?", { "Yes", "Cancel" }, true);
|
||||||
|
if(sopt == 0)
|
||||||
{
|
{
|
||||||
this->MoveFolder(this->curfolder, true);
|
if(cfg::ExistsRecord(list, hb)) qapp->CreateShowDialog("Add to menu", "The homebrew is already in the main menu.\nNothing was added nor removed.\n\nYou can remove it from main menu itself.", { "Ok" }, true);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cfg::SaveRecord(hb);
|
||||||
|
list.root.titles.push_back(hb);
|
||||||
|
qapp->CreateShowDialog("Add to menu", "The homebrew was successfully added to the main menu.", { "Ok" }, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto foldr = list.folders[realidx - folder.titles.size()];
|
auto &folder = cfg::FindFolderByName(list, this->curfolder);
|
||||||
if(down & KEY_A)
|
if(realidx < folder.titles.size())
|
||||||
{
|
{
|
||||||
this->MoveFolder(foldr.name, true);
|
auto title = folder.titles[realidx];
|
||||||
|
if(down & KEY_A)
|
||||||
|
{
|
||||||
|
if(!qapp->IsSuspended())
|
||||||
|
{
|
||||||
|
if((cfg::TitleType)title.title_type == cfg::TitleType::Homebrew) this->HandleHomebrewLaunch(title);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
am::QMenuCommandWriter writer(am::QDaemonMessage::LaunchApplication);
|
||||||
|
writer.Write<u64>(title.app_id);
|
||||||
|
writer.FinishWrite();
|
||||||
|
|
||||||
|
am::QMenuCommandResultReader reader;
|
||||||
|
if(reader && R_SUCCEEDED(reader.GetReadResult()))
|
||||||
|
{
|
||||||
|
pu::audio::Play(this->sfxTitleLaunch);
|
||||||
|
qapp->StopPlayBGM();
|
||||||
|
qapp->CloseWithFadeOut();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto rc = reader.GetReadResult();
|
||||||
|
qapp->CreateShowDialog("Title launch", "An error ocurred attempting to launch the title:\n" + util::FormatResultDisplay(rc) + " (" + util::FormatResultHex(rc) + ")", { "Ok" }, true);
|
||||||
|
}
|
||||||
|
reader.FinishRead();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if((cfg::TitleType)title.title_type == cfg::TitleType::Homebrew)
|
||||||
|
{
|
||||||
|
if(std::string(title.nro_target.nro_path) == qapp->GetSuspendedHomebrewPath())
|
||||||
|
{
|
||||||
|
if(this->mode == 1) this->mode = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(title.app_id == qapp->GetSuspendedApplicationId())
|
||||||
|
{
|
||||||
|
if(this->mode == 1) this->mode = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(down & KEY_X)
|
||||||
|
{
|
||||||
|
if(qapp->IsSuspended())
|
||||||
|
{
|
||||||
|
if((cfg::TitleType)title.title_type == cfg::TitleType::Homebrew)
|
||||||
|
{
|
||||||
|
if(std::string(title.nro_target.nro_path) == qapp->GetSuspendedHomebrewPath()) this->HandleCloseSuspended();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(title.app_id == qapp->GetSuspendedApplicationId()) this->HandleCloseSuspended();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(down & KEY_Y)
|
||||||
|
{
|
||||||
|
if((cfg::TitleType)title.title_type == cfg::TitleType::Homebrew)
|
||||||
|
{
|
||||||
|
auto sopt = qapp->CreateShowDialog("Entry options", "What would you like to do with the selected entry?", { "Move to/from folder", "Remove", "Cancel" }, true);
|
||||||
|
if(sopt == 0)
|
||||||
|
{
|
||||||
|
if(this->HandleFolderChange(title))
|
||||||
|
{
|
||||||
|
this->MoveFolder(this->curfolder, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(sopt == 1)
|
||||||
|
{
|
||||||
|
auto sopt2 = qapp->CreateShowDialog("Remove entry", "Would you like to remove this entry from main menu?\nThis homebrew will still be launchable from the homebrew menu.", { "Yes", "No" }, true);
|
||||||
|
if(sopt2 == 0)
|
||||||
|
{
|
||||||
|
cfg::RemoveRecord(title);
|
||||||
|
folder.titles.erase(folder.titles.begin() + realidx);
|
||||||
|
qapp->CreateShowDialog("Remove entry", "The entry was successfully removed.", { "Ok" }, true);
|
||||||
|
this->MoveFolder(this->curfolder, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(this->HandleFolderChange(title))
|
||||||
|
{
|
||||||
|
this->MoveFolder(this->curfolder, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto foldr = list.folders[realidx - folder.titles.size()];
|
||||||
|
if(down & KEY_A)
|
||||||
|
{
|
||||||
|
this->MoveFolder(foldr.name, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -326,62 +359,45 @@ namespace ui
|
||||||
{
|
{
|
||||||
if(fade) qapp->FadeOut();
|
if(fade) qapp->FadeOut();
|
||||||
|
|
||||||
if(this->homebrew_mode)
|
auto itm_list = homebrew;
|
||||||
|
if(!this->homebrew_mode)
|
||||||
{
|
{
|
||||||
this->itemsMenu->ClearItems();
|
|
||||||
this->itemsMenu->AddItem(cfg::ProcessedThemeResource(theme, "ui/Hbmenu.png"));
|
|
||||||
for(auto itm: homebrew)
|
|
||||||
{
|
|
||||||
this->itemsMenu->AddItem(cfg::GetRecordIconPath(itm));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(this->curfolder.empty())
|
|
||||||
{
|
|
||||||
// Moving from root to a folder, let's save the indexes we were on
|
|
||||||
this->root_idx = itemsMenu->GetSelectedItem();
|
|
||||||
this->root_baseidx = itemsMenu->GetBaseItemIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &folder = cfg::FindFolderByName(list, name);
|
auto &folder = cfg::FindFolderByName(list, name);
|
||||||
this->itemsMenu->ClearItems();
|
itm_list = folder.titles;
|
||||||
|
}
|
||||||
|
|
||||||
// Add first item for all titles menu
|
this->itemsMenu->ClearItems();
|
||||||
this->itemsMenu->AddItem(cfg::ProcessedThemeResource(theme, "ui/AllTitles.png"));
|
auto initial_itm = cfg::ProcessedThemeResource(theme, "ui/AllTitles.png");
|
||||||
u32 tmpidx = 0;
|
if(this->homebrew_mode) initial_itm = cfg::ProcessedThemeResource(theme, "ui/Hbmenu.png");
|
||||||
for(auto itm: folder.titles)
|
this->itemsMenu->AddItem(initial_itm);
|
||||||
|
|
||||||
|
u32 tmpidx = 0;
|
||||||
|
for(auto itm: itm_list)
|
||||||
|
{
|
||||||
|
if((cfg::TitleType)itm.title_type == cfg::TitleType::Installed)
|
||||||
{
|
{
|
||||||
if((cfg::TitleType)itm.title_type == cfg::TitleType::Installed)
|
if(qapp->IsTitleSuspended()) if(qapp->GetSuspendedApplicationId() == itm.app_id) this->itemsMenu->SetSuspendedItem(tmpidx + 1); // Skip initial item
|
||||||
{
|
|
||||||
if(qapp->IsTitleSuspended()) if(qapp->GetSuspendedApplicationId() == itm.app_id) this->itemsMenu->SetSuspendedItem(tmpidx + 1); // 1st item is always "all titles"!
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(qapp->IsHomebrewSuspended()) if(qapp->GetSuspendedHomebrewPath() == std::string(itm.nro_target.nro_path)) this->itemsMenu->SetSuspendedItem(tmpidx + 1); // 1st item is always "all titles"!
|
|
||||||
}
|
|
||||||
this->itemsMenu->AddItem(cfg::GetRecordIconPath(itm));
|
|
||||||
tmpidx++;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(qapp->IsHomebrewSuspended()) if(qapp->GetSuspendedHomebrewPath() == std::string(itm.nro_target.nro_path)) this->itemsMenu->SetSuspendedItem(tmpidx + 1); // Skip initial item
|
||||||
|
}
|
||||||
|
this->itemsMenu->AddItem(cfg::GetRecordIconPath(itm));
|
||||||
|
tmpidx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this->homebrew_mode) // Only normal menu has folders
|
||||||
|
{
|
||||||
if(name.empty())
|
if(name.empty())
|
||||||
{
|
{
|
||||||
std::vector<cfg::TitleFolder> folders;
|
STL_REMOVE_IF(list.folders, fldr, (fldr.titles.empty())) // Remove empty folders
|
||||||
for(auto folder: list.folders)
|
for(auto folder: list.folders) this->itemsMenu->AddItem(cfg::ProcessedThemeResource(theme, "ui/Folder.png"));
|
||||||
{
|
|
||||||
if(!folder.titles.empty())
|
|
||||||
{
|
|
||||||
folders.push_back(folder);
|
|
||||||
this->itemsMenu->AddItem(cfg::ProcessedThemeResource(theme, "ui/Folder.png"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list.folders = folders;
|
|
||||||
this->itemsMenu->SetBasePositions(this->root_idx, this->root_baseidx);
|
|
||||||
}
|
}
|
||||||
this->itemsMenu->UpdateBorderIcons();
|
|
||||||
|
|
||||||
this->curfolder = name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->itemsMenu->UpdateBorderIcons();
|
||||||
|
if(!this->homebrew_mode) this->curfolder = name;
|
||||||
|
|
||||||
if(fade) qapp->FadeIn();
|
if(fade) qapp->FadeIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,6 +584,7 @@ namespace ui
|
||||||
swkbdConfigSetHeaderText(&swkbd, "Enter directory name");
|
swkbdConfigSetHeaderText(&swkbd, "Enter directory name");
|
||||||
char dir[500] = {0};
|
char dir[500] = {0};
|
||||||
auto rc = swkbdShow(&swkbd, dir, 500);
|
auto rc = swkbdShow(&swkbd, dir, 500);
|
||||||
|
swkbdClose(&swkbd);
|
||||||
if(R_SUCCEEDED(rc))
|
if(R_SUCCEEDED(rc))
|
||||||
{
|
{
|
||||||
changedone = cfg::MoveRecordTo(list, rec, std::string(dir));
|
changedone = cfg::MoveRecordTo(list, rec, std::string(dir));
|
||||||
|
@ -575,7 +592,7 @@ namespace ui
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto sopt = qapp->CreateShowDialog("Title move", "Would you like to move this entry outside the folder?", { "Yes", "Cancel" }, true);
|
auto sopt = qapp->CreateShowDialog("Entry move", "Would you like to move this entry outside the folder?", { "Yes", "Cancel" }, true);
|
||||||
if(sopt == 0)
|
if(sopt == 0)
|
||||||
{
|
{
|
||||||
changedone = cfg::MoveRecordTo(list, rec, "");
|
changedone = cfg::MoveRecordTo(list, rec, "");
|
||||||
|
@ -652,6 +669,7 @@ namespace ui
|
||||||
swkbdConfigSetHeaderText(&swkbd, "Enter web page URL");
|
swkbdConfigSetHeaderText(&swkbd, "Enter web page URL");
|
||||||
char url[500] = {0};
|
char url[500] = {0};
|
||||||
auto rc = swkbdShow(&swkbd, url, 500);
|
auto rc = swkbdShow(&swkbd, url, 500);
|
||||||
|
swkbdClose(&swkbd);
|
||||||
if(R_SUCCEEDED(rc))
|
if(R_SUCCEEDED(rc))
|
||||||
{
|
{
|
||||||
WebCommonConfig web = {};
|
WebCommonConfig web = {};
|
||||||
|
|
|
@ -139,7 +139,10 @@ namespace ui
|
||||||
void SideMenu::ClearItems()
|
void SideMenu::ClearItems()
|
||||||
{
|
{
|
||||||
this->icons.clear();
|
this->icons.clear();
|
||||||
for(auto &ricon: this->ricons) pu::ui::render::DeleteTexture(ricon);
|
for(auto ricon: this->ricons)
|
||||||
|
{
|
||||||
|
if(ricon != NULL) pu::ui::render::DeleteTexture(ricon);
|
||||||
|
}
|
||||||
this->ricons.clear();
|
this->ricons.clear();
|
||||||
this->selitm = 0;
|
this->selitm = 0;
|
||||||
this->baseiconidx = 0;
|
this->baseiconidx = 0;
|
||||||
|
|
|
@ -85,13 +85,13 @@ namespace ui
|
||||||
swkbdConfigSetHeaderText(&swkbd, "Input user password");
|
swkbdConfigSetHeaderText(&swkbd, "Input user password");
|
||||||
char inpass[0x10] = {0};
|
char inpass[0x10] = {0};
|
||||||
auto rc = swkbdShow(&swkbd, inpass, 0x10);
|
auto rc = swkbdShow(&swkbd, inpass, 0x10);
|
||||||
|
swkbdClose(&swkbd);
|
||||||
if(R_SUCCEEDED(rc))
|
if(R_SUCCEEDED(rc))
|
||||||
{
|
{
|
||||||
auto rc = db::TryLogUser(uid, std::string(inpass));
|
auto rc = db::TryLogUser(uid, std::string(inpass));
|
||||||
if(R_FAILED(rc)) qapp->CreateShowDialog("Login", "Invalid password. Please try again.", {"Ok"}, true);
|
if(R_FAILED(rc)) qapp->CreateShowDialog("Login", "Invalid password. Please try again.", {"Ok"}, true);
|
||||||
else login_ok = true;
|
else login_ok = true;
|
||||||
}
|
}
|
||||||
swkbdClose(&swkbd);
|
|
||||||
}
|
}
|
||||||
else login_ok = true;
|
else login_ok = true;
|
||||||
if(login_ok)
|
if(login_ok)
|
||||||
|
|
10
Makefile
10
Makefile
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
export Q_VERSION := dev
|
export Q_VERSION := dev
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all dev clean
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@$(MAKE) -C SystemAppletQDaemon/
|
@$(MAKE) -C SystemAppletQDaemon/
|
||||||
|
@ -15,6 +15,14 @@ all:
|
||||||
@cp -r $(CURDIR)/LibraryAppletQHbTarget/Out $(CURDIR)/SdOut/titles/0100000000001009
|
@cp -r $(CURDIR)/LibraryAppletQHbTarget/Out $(CURDIR)/SdOut/titles/0100000000001009
|
||||||
@cp -r $(CURDIR)/SystemApplicationQHbTarget/Out $(CURDIR)/SdOut/titles/01008BB00013C000
|
@cp -r $(CURDIR)/SystemApplicationQHbTarget/Out $(CURDIR)/SdOut/titles/01008BB00013C000
|
||||||
|
|
||||||
|
setdev:
|
||||||
|
$(eval export Q_DEV := 1)
|
||||||
|
@echo
|
||||||
|
@echo IMPORTANT! Building in development mode - do not treat this build as release...
|
||||||
|
@echo
|
||||||
|
|
||||||
|
dev: setdev all
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@rm -rf $(CURDIR)/SdOut
|
@rm -rf $(CURDIR)/SdOut
|
||||||
@$(MAKE) clean -C SystemAppletQDaemon/
|
@$(MAKE) clean -C SystemAppletQDaemon/
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
uLaunch is a very ambicious project, consisting on two custom library applets, a custom system application and a custom system applet, in order to replace the console's **HOME menu** with a custom, homebrew-orienteed one.
|
uLaunch is a very ambicious project, consisting on two custom library applets, a custom system application and a custom system applet, in order to replace the console's **HOME menu** with a custom, homebrew-orienteed one.
|
||||||
|
|
||||||
|
No, this isn't any kind of HOME menu extension, injection, patch, etc. uLaunch is a **complete** reimplementation, 100% open-source, which also takes over eShop and Mii applets and flog system title, for its extended functionality.
|
||||||
|
|
||||||
## **NOTE:** the project is still a work-in-progress. Check what's left to do before release [here](TODO.md)!
|
## **NOTE:** the project is still a work-in-progress. Check what's left to do before release [here](TODO.md)!
|
||||||
|
|
||||||
- The project is licensed as **GPLv2**.
|
- The project is licensed as **GPLv2**.
|
||||||
|
|
|
@ -34,6 +34,10 @@ CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||||
|
|
||||||
CFLAGS += $(INCLUDE) -D__SWITCH__ -DQ_VERSION=\"$(Q_VERSION)\"
|
CFLAGS += $(INCLUDE) -D__SWITCH__ -DQ_VERSION=\"$(Q_VERSION)\"
|
||||||
|
|
||||||
|
ifeq ($(Q_DEV),1)
|
||||||
|
CFLAGS += -DQ_DEV
|
||||||
|
endif
|
||||||
|
|
||||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
|
||||||
|
|
||||||
ASFLAGS := -g $(ARCH)
|
ASFLAGS := -g $(ARCH)
|
||||||
|
|
|
@ -13,7 +13,11 @@
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
u32 __nx_applet_type = AppletType_SystemApplet;
|
u32 __nx_applet_type = AppletType_SystemApplet;
|
||||||
size_t __nx_heap_size = 0x3000000;//0x1000000;
|
#ifdef Q_DEV
|
||||||
|
size_t __nx_heap_size = 0x3000000; // Dev uses 3x heap (48MB, still pretty low) for debug console
|
||||||
|
#else
|
||||||
|
size_t __nx_heap_size = 0x1000000;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *app_buf;
|
u8 *app_buf;
|
||||||
|
@ -286,52 +290,54 @@ namespace qdaemon
|
||||||
app_buf = new u8[RawRGBAScreenBufferSize]();
|
app_buf = new u8[RawRGBAScreenBufferSize]();
|
||||||
fs::CreateDirectory(Q_BASE_SD_DIR);
|
fs::CreateDirectory(Q_BASE_SD_DIR);
|
||||||
|
|
||||||
// Debug testing mode
|
#ifdef Q_DEV
|
||||||
consoleInit(NULL);
|
// Debug testing mode
|
||||||
CONSOLE_FMT("Welcome to QDaemon's debug mode!")
|
consoleInit(NULL);
|
||||||
CONSOLE_FMT("")
|
CONSOLE_FMT("Welcome to QDaemon's debug mode!")
|
||||||
CONSOLE_FMT("(A) -> Dump system save data to sd:/<q>/save_dump")
|
CONSOLE_FMT("")
|
||||||
CONSOLE_FMT("(B) -> Delete everything in save data (except official HOME menu's content)")
|
CONSOLE_FMT("(A) -> Dump system save data to sd:/<q>/save_dump")
|
||||||
CONSOLE_FMT("(X) -> Reboot system")
|
CONSOLE_FMT("(B) -> Delete everything in save data (except official HOME menu's content)")
|
||||||
CONSOLE_FMT("(Y) -> Continue to QMenu (proceed launch)")
|
CONSOLE_FMT("(X) -> Reboot system")
|
||||||
CONSOLE_FMT("")
|
CONSOLE_FMT("(Y) -> Continue to QMenu (proceed launch)")
|
||||||
|
CONSOLE_FMT("")
|
||||||
|
|
||||||
while(true)
|
while(true)
|
||||||
{
|
|
||||||
hidScanInput();
|
|
||||||
auto k = hidKeysDown(CONTROLLER_P1_AUTO);
|
|
||||||
if(k & KEY_A)
|
|
||||||
{
|
{
|
||||||
db::Mount();
|
hidScanInput();
|
||||||
fs::CopyDirectory(Q_DB_MOUNT_NAME ":/", Q_BASE_SD_DIR "/save_dump");
|
auto k = hidKeysDown(CONTROLLER_P1_AUTO);
|
||||||
db::Unmount();
|
if(k & KEY_A)
|
||||||
CONSOLE_FMT(" - Dump done.")
|
{
|
||||||
|
db::Mount();
|
||||||
|
fs::CopyDirectory(Q_DB_MOUNT_NAME ":/", Q_BASE_SD_DIR "/save_dump");
|
||||||
|
db::Unmount();
|
||||||
|
CONSOLE_FMT(" - Dump done.")
|
||||||
|
}
|
||||||
|
else if(k & KEY_B)
|
||||||
|
{
|
||||||
|
db::Mount();
|
||||||
|
fs::DeleteDirectory(Q_BASE_DB_DIR);
|
||||||
|
fs::CreateDirectory(Q_BASE_DB_DIR);
|
||||||
|
db::Commit();
|
||||||
|
db::Unmount();
|
||||||
|
CONSOLE_FMT(" - Cleanup done.")
|
||||||
|
}
|
||||||
|
else if(k & KEY_X)
|
||||||
|
{
|
||||||
|
CONSOLE_FMT(" - Rebooting...")
|
||||||
|
svcSleepThread(200'000'000);
|
||||||
|
appletStartRebootSequence();
|
||||||
|
}
|
||||||
|
else if(k & KEY_Y)
|
||||||
|
{
|
||||||
|
CONSOLE_FMT(" - Proceeding with launch...")
|
||||||
|
svcSleepThread(500'000'000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
svcSleepThread(10'000'000);
|
||||||
}
|
}
|
||||||
else if(k & KEY_B)
|
|
||||||
{
|
|
||||||
db::Mount();
|
|
||||||
fs::DeleteDirectory(Q_BASE_DB_DIR);
|
|
||||||
fs::CreateDirectory(Q_BASE_DB_DIR);
|
|
||||||
db::Commit();
|
|
||||||
db::Unmount();
|
|
||||||
CONSOLE_FMT(" - Cleanup done.")
|
|
||||||
}
|
|
||||||
else if(k & KEY_X)
|
|
||||||
{
|
|
||||||
CONSOLE_FMT(" - Rebooting...")
|
|
||||||
svcSleepThread(200'000'000);
|
|
||||||
appletStartRebootSequence();
|
|
||||||
}
|
|
||||||
else if(k & KEY_Y)
|
|
||||||
{
|
|
||||||
CONSOLE_FMT(" - Proceeding with launch...")
|
|
||||||
svcSleepThread(500'000'000);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
svcSleepThread(10'000'000);
|
|
||||||
}
|
|
||||||
|
|
||||||
consoleExit(NULL);
|
consoleExit(NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
svcSleepThread(100'000'000); // Wait for proper moment
|
svcSleepThread(100'000'000); // Wait for proper moment
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue