mirror of
https://github.com/XorTroll/uLaunch
synced 2024-11-10 14:34:13 +00:00
Changes, add IPC code, start with themes
This commit is contained in:
parent
0340098246
commit
5eaf42fe5e
21 changed files with 317 additions and 216 deletions
|
@ -20,4 +20,5 @@ namespace am
|
|||
Result ApplicationStart(u64 app_id, bool system, u128 user_id);
|
||||
bool ApplicationHasForeground();
|
||||
Result ApplicationSetForeground();
|
||||
u64 ApplicationGetId();
|
||||
}
|
|
@ -25,7 +25,7 @@ namespace am
|
|||
LaunchApplication,
|
||||
ResumeApplication,
|
||||
TerminateApplication,
|
||||
GetLatestMessage,
|
||||
GetSuspendedApplicationId
|
||||
};
|
||||
|
||||
Result QDaemon_LaunchQMenu(QMenuStartMode mode);
|
||||
|
|
|
@ -14,6 +14,8 @@ namespace fs
|
|||
void DeleteDirectory(std::string path);
|
||||
void DeleteFile(std::string path);
|
||||
|
||||
bool WriteFile(std::string path, void *data, size_t size, bool overwrite);
|
||||
bool ReadFile(std::string path, void *data, size_t size);
|
||||
size_t GetFileSize(std::string path);
|
||||
|
||||
void ForEachFileIn(std::string dir, std::function<void(std::string name, std::string path)> fn);
|
||||
|
|
|
@ -22,7 +22,8 @@ using JSON = nlohmann::json;
|
|||
#define Q_BASE_DIR "reqwrite"
|
||||
#define Q_BASE_SD_DIR "sdmc:/" Q_BASE_DIR
|
||||
#define Q_DB_MOUNT_NAME "qsave"
|
||||
#define Q_BASE_DB_DIR Q_DB_MOUNT_NAME ":/" Q_BASE_DIR
|
||||
#define Q_DB_MOUNT_PATH Q_DB_MOUNT_NAME ":/"
|
||||
#define Q_BASE_DB_DIR Q_DB_MOUNT_PATH Q_BASE_DIR
|
||||
|
||||
#define Q_MENU_JSON Q_BASE_SD_DIR "/menu.json"
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace am
|
|||
{
|
||||
extern bool home_focus;
|
||||
AppletApplication app_holder;
|
||||
bool launched;
|
||||
u64 latest_appid;
|
||||
|
||||
bool ApplicationIsActive()
|
||||
{
|
||||
|
@ -45,6 +45,8 @@ namespace am
|
|||
R_TRY(appletApplicationStart(&app_holder));
|
||||
R_TRY(ApplicationSetForeground());
|
||||
|
||||
latest_appid = app_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -59,4 +61,9 @@ namespace am
|
|||
if(R_SUCCEEDED(rc)) home_focus = false;
|
||||
return rc;
|
||||
}
|
||||
|
||||
u64 ApplicationGetId()
|
||||
{
|
||||
return latest_appid;
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
#include <util/util_JSON.hpp>
|
||||
#include <util/util_String.hpp>
|
||||
#include <fs/fs_Stdio.hpp>
|
||||
#include <db/db_Save.hpp>
|
||||
#include <util/util_Convert.hpp>
|
||||
|
||||
namespace cfg
|
||||
|
@ -160,13 +161,7 @@ namespace cfg
|
|||
fseek(f, hdr.size + ahdr.icon.size, SEEK_SET);
|
||||
if(fread(iconbuf, ahdr.icon.size, 1, f) == 1)
|
||||
{
|
||||
fs::DeleteFile(nroimg);
|
||||
FILE *iconf = fopen(nroimg.c_str(), "wb");
|
||||
if(iconf)
|
||||
{
|
||||
fwrite(iconbuf, 1, ahdr.icon.size, iconf);
|
||||
fclose(iconf);
|
||||
}
|
||||
fs::WriteFile(nroimg, iconbuf, ahdr.icon.size, true);
|
||||
}
|
||||
delete[] iconbuf;
|
||||
}
|
||||
|
@ -200,108 +195,6 @@ namespace cfg
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Search SD card for installed title extensions or homebrew accessors
|
||||
fs::ForEachFileIn(Q_BASE_SD_DIR "/entries", [&](std::string name, std::string path)
|
||||
{
|
||||
if(util::StringEndsWith(name, ".json"))
|
||||
{
|
||||
auto [rc, json] = util::LoadJSONFromFile(path);
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
TitleType type = (TitleType)json.value("type", 0u);
|
||||
if(type == TitleType::Installed)
|
||||
{
|
||||
std::string appidstr = json.value("application_id", "");
|
||||
if(!appidstr.empty())
|
||||
{
|
||||
std::string folder = json.value("folder", "");
|
||||
u64 appid = util::Get64FromString(appidstr);
|
||||
if(appid > 0)
|
||||
{
|
||||
if(!folder.empty()) MoveTitleToDirectory(list, appid, folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(type == TitleType::Homebrew)
|
||||
{
|
||||
std::string nropath = json.value("nro_path", "");
|
||||
if(!nropath.empty())
|
||||
{
|
||||
TitleRecord rec = {};
|
||||
rec.title_type = (u32)type;
|
||||
rec.nro_path = "sdmc:";
|
||||
if(nropath.front() != '/') rec.nro_path += "/";
|
||||
rec.nro_path += nropath;
|
||||
std::string folder = json.value("folder", "");
|
||||
rec.sub_folder = folder;
|
||||
if(cache)
|
||||
{
|
||||
auto nroimg = GetNROCacheIconPath(rec.nro_path);
|
||||
FILE *f = fopen(rec.nro_path.c_str(), "rb");
|
||||
if(f)
|
||||
{
|
||||
NroStart st = {};
|
||||
if(fread(&st, sizeof(NroStart), 1, f) == 1)
|
||||
{
|
||||
NroHeader hdr = {};
|
||||
if(fread(&hdr, sizeof(NroHeader), 1, f) == 1)
|
||||
{
|
||||
fseek(f, hdr.size, SEEK_SET);
|
||||
NroAssetHeader ahdr = {};
|
||||
if(fread(&ahdr, sizeof(NroAssetHeader), 1, f) == 1)
|
||||
{
|
||||
if(ahdr.magic == NROASSETHEADER_MAGIC)
|
||||
{
|
||||
if(ahdr.icon.size > 0)
|
||||
{
|
||||
u8 *iconbuf = new u8[ahdr.icon.size]();
|
||||
fseek(f, hdr.size + ahdr.icon.size, SEEK_SET);
|
||||
if(fread(iconbuf, ahdr.icon.size, 1, f) == 1)
|
||||
{
|
||||
fs::DeleteFile(nroimg);
|
||||
FILE *iconf = fopen(nroimg.c_str(), "wb");
|
||||
if(iconf)
|
||||
{
|
||||
fwrite(iconbuf, 1, ahdr.icon.size, iconf);
|
||||
fclose(iconf);
|
||||
}
|
||||
}
|
||||
delete[] iconbuf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
if(folder.empty())
|
||||
{
|
||||
list.root.titles.push_back(rec);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto find = STLITER_FINDWITHCONDITION(list.folders, fld, (fld.name == folder));
|
||||
if(STLITER_ISFOUND(list.folders, find))
|
||||
{
|
||||
STLITER_UNWRAP(find).titles.push_back(rec);
|
||||
}
|
||||
else
|
||||
{
|
||||
TitleFolder fld = {};
|
||||
fld.name = folder;
|
||||
fld.titles.push_back(rec);
|
||||
list.folders.push_back(fld);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return SuccessResultWith(list);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,13 +33,7 @@ namespace db
|
|||
auto filename = GetUserPasswordFilePath(user_id);
|
||||
if(fs::ExistsFile(filename))
|
||||
{
|
||||
FILE *f = fopen(filename.c_str(), "rb");
|
||||
if(f)
|
||||
{
|
||||
fread(&pb, 1, sizeof(PassBlock), f);
|
||||
fclose(f);
|
||||
return SuccessResultWith(pb);
|
||||
}
|
||||
if(fs::ReadFile(filename, &pb, sizeof(pb))) return SuccessResultWith(pb);
|
||||
}
|
||||
return MakeResultWith(0xdead, pb);
|
||||
}
|
||||
|
@ -54,30 +48,16 @@ namespace db
|
|||
{
|
||||
std::string pwd;
|
||||
auto filename = GetUserPasswordFilePath(user_id);
|
||||
if(fs::ExistsFile(filename))
|
||||
{
|
||||
FILE *f = fopen(filename.c_str(), "rb");
|
||||
if(f)
|
||||
{
|
||||
fclose(f);
|
||||
return 0xdead;
|
||||
}
|
||||
}
|
||||
fs::DeleteFile(filename);
|
||||
FILE *f = fopen(filename.c_str(), "wb");
|
||||
if(f)
|
||||
{
|
||||
if(fs::ExistsFile(filename)) return 0xdead;
|
||||
|
||||
if((password.length() > 15) || (password.empty())) return 0xdead1;
|
||||
PassBlock pb = {};
|
||||
memcpy(&pb.uid, &user_id, sizeof(u128));
|
||||
char tmppass[0x10] = {0};
|
||||
strcpy(tmppass, password.c_str());
|
||||
sha256CalculateHash(pb.pass_sha, tmppass, 0x10);
|
||||
fwrite(&pb, 1, sizeof(PassBlock), f);
|
||||
fclose(f);
|
||||
Commit();
|
||||
}
|
||||
else return 0xdead2;
|
||||
|
||||
if(!fs::WriteFile(filename, &pb, sizeof(pb), true)) return 0xdead2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
#include <fs/fs_Stdio.hpp>
|
||||
#include <util/util_String.hpp>
|
||||
#include <db/db_Save.hpp>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
#define FS_COMMIT_IF_DB_PATH(path) db::Commit();
|
||||
|
||||
static bool ExistsImpl(size_t st_mode, std::string path)
|
||||
{
|
||||
struct stat st;
|
||||
|
@ -21,26 +25,56 @@ namespace fs
|
|||
void CreateDirectory(std::string path)
|
||||
{
|
||||
mkdir(path.c_str(), 777);
|
||||
FS_COMMIT_IF_DB_PATH(path)
|
||||
}
|
||||
|
||||
void CreateFile(std::string path)
|
||||
{
|
||||
fsdevCreateFile(path.c_str(), 0, 0);
|
||||
FS_COMMIT_IF_DB_PATH(path)
|
||||
}
|
||||
|
||||
void CreateConcatenationFile(std::string path)
|
||||
{
|
||||
fsdevCreateFile(path.c_str(), 0, FS_CREATE_BIG_FILE);
|
||||
FS_COMMIT_IF_DB_PATH(path)
|
||||
}
|
||||
|
||||
void DeleteDirectory(std::string path)
|
||||
{
|
||||
fsdevDeleteDirectoryRecursively(path.c_str());
|
||||
FS_COMMIT_IF_DB_PATH(path)
|
||||
}
|
||||
|
||||
void DeleteFile(std::string path)
|
||||
{
|
||||
remove(path.c_str());
|
||||
FS_COMMIT_IF_DB_PATH(path)
|
||||
}
|
||||
|
||||
bool WriteFile(std::string path, void *data, size_t size, bool overwrite)
|
||||
{
|
||||
FILE *f = fopen(path.c_str(), overwrite ? "wb" : "ab+");
|
||||
if(f)
|
||||
{
|
||||
fwrite(data, 1, size, f);
|
||||
fclose(f);
|
||||
FS_COMMIT_IF_DB_PATH(path)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReadFile(std::string path, void *data, size_t size)
|
||||
{
|
||||
FILE *f = fopen(path.c_str(), "rb");
|
||||
if(f)
|
||||
{
|
||||
fread(data, 1, size, f);
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t GetFileSize(std::string path)
|
||||
|
@ -86,6 +120,8 @@ namespace fs
|
|||
void MoveFile(std::string p1, std::string p2)
|
||||
{
|
||||
rename(p1.c_str(), p2.c_str());
|
||||
FS_COMMIT_IF_DB_PATH(p1)
|
||||
FS_COMMIT_IF_DB_PATH(p2)
|
||||
}
|
||||
|
||||
void CopyFile(std::string p, std::string np)
|
||||
|
@ -111,6 +147,7 @@ namespace fs
|
|||
}
|
||||
delete[] tmp;
|
||||
fclose(outf);
|
||||
FS_COMMIT_IF_DB_PATH(np)
|
||||
}
|
||||
fclose(inf);
|
||||
}
|
||||
|
|
|
@ -38,15 +38,10 @@ namespace os
|
|||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
auto iconcache = GetIconCacheImagePath(uidbuf[i]);
|
||||
fs::DeleteFile(iconcache);
|
||||
FILE *f = fopen(iconcache.c_str(), "wb");
|
||||
if(f)
|
||||
{
|
||||
fwrite(imgbuf, 1, imgsz, f);
|
||||
fclose(f);
|
||||
}
|
||||
fs::WriteFile(iconcache, imgbuf, imgsz, true);
|
||||
}
|
||||
}
|
||||
accountProfileClose(&prof);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,12 +25,8 @@ namespace os
|
|||
{
|
||||
auto fname = cfg::GetTitleCacheIconPath(rec.app_id);
|
||||
fs::DeleteFile(fname);
|
||||
FILE *f = fopen(fname.c_str(), "wb");
|
||||
if(f)
|
||||
{
|
||||
fwrite(control.icon, 1, sizeof(control.icon), f);
|
||||
fclose(f);
|
||||
}
|
||||
db::Commit();
|
||||
fs::WriteFile(fname, control.icon, sizeof(control.icon), true);
|
||||
}
|
||||
}
|
||||
titles.push_back(rec);
|
||||
|
|
BIN
LibraryAppletQMenu/RomFs/default/ui/AllTitles.png
Normal file
BIN
LibraryAppletQMenu/RomFs/default/ui/AllTitles.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.8 KiB |
BIN
LibraryAppletQMenu/RomFs/default/ui/Folder.png
Normal file
BIN
LibraryAppletQMenu/RomFs/default/ui/Folder.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.8 KiB |
|
@ -24,6 +24,12 @@ namespace qmenu
|
|||
accountInitialize();
|
||||
nsInitialize();
|
||||
db::Mount();
|
||||
fs::CreateDirectory(Q_BASE_DB_DIR);
|
||||
fs::CreateDirectory(Q_BASE_SD_DIR);
|
||||
fs::CreateDirectory(Q_BASE_SD_DIR "/title");
|
||||
fs::CreateDirectory(Q_BASE_SD_DIR "/user");
|
||||
fs::CreateDirectory(Q_BASE_SD_DIR "/nro");
|
||||
db::Commit();
|
||||
am::QMenu_InitializeDaemonService();
|
||||
}
|
||||
|
||||
|
@ -38,25 +44,10 @@ namespace qmenu
|
|||
|
||||
u8 *app_buf;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void userAppInit(void)
|
||||
{
|
||||
qmenu::Initialize();
|
||||
}
|
||||
|
||||
void userAppExit(void)
|
||||
{
|
||||
delete[] app_buf;
|
||||
qmenu::Exit();
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
app_buf = new u8[1280 * 720 * 4]();
|
||||
fs::CreateDirectory(Q_BASE_DB_DIR);
|
||||
fs::CreateDirectory(Q_BASE_DB_DIR "/user");
|
||||
qmenu::Initialize();
|
||||
auto [_rc, menulist] = cfg::LoadTitleList(true);
|
||||
list = menulist;
|
||||
|
||||
|
@ -70,10 +61,11 @@ int main()
|
|||
|
||||
if(smode == am::QMenuStartMode::MenuApplicationSuspended)
|
||||
{
|
||||
/*
|
||||
auto app_id = reader.Read<u64>();
|
||||
qapp->SetSuspendedApplicationId(app_id);
|
||||
*/
|
||||
am::QMenuCommandWriter writer(am::QDaemonMessage::GetSuspendedApplicationId);
|
||||
writer.FinishWrite();
|
||||
am::QMenuCommandResultReader reader;
|
||||
if(reader) qapp->SetSuspendedApplicationId(reader.Read<u64>());
|
||||
reader.FinishRead();
|
||||
|
||||
FILE *f = fopen(Q_BASE_SD_DIR "/temp-suspended.rgba", "rb");
|
||||
if(f)
|
||||
|
@ -91,5 +83,8 @@ int main()
|
|||
}
|
||||
}
|
||||
|
||||
delete[] app_buf;
|
||||
qmenu::Exit();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -20,6 +20,10 @@ namespace ui
|
|||
this->Add(this->bgSuspendedRaw);
|
||||
|
||||
this->itemsMenu = SideMenu::New(pu::ui::Color(0, 120, 255, 255), pu::ui::Color());
|
||||
|
||||
// Add first item for all titles menu
|
||||
this->itemsMenu->AddItem("romfs:/default/ui/AllTitles.png");
|
||||
|
||||
for(auto itm: list.root.titles)
|
||||
{
|
||||
std::string iconpth;
|
||||
|
@ -29,7 +33,8 @@ namespace ui
|
|||
}
|
||||
for(auto folder: list.folders)
|
||||
{
|
||||
this->itemsMenu->AddItem("romfs:/Test.jpg");
|
||||
// TODO: folder logic
|
||||
this->itemsMenu->AddItem("romfs:/default/Folder.png");
|
||||
}
|
||||
this->itemsMenu->SetOnItemSelected(std::bind(&MenuLayout::menu_Click, this, std::placeholders::_1));
|
||||
this->Add(this->itemsMenu);
|
||||
|
@ -39,9 +44,16 @@ namespace ui
|
|||
|
||||
void MenuLayout::menu_Click(u32 index)
|
||||
{
|
||||
if(index < list.root.titles.size())
|
||||
if(index == 0)
|
||||
{
|
||||
auto title = list.root.titles[index];
|
||||
qapp->CreateShowDialog("A", "All titles", {"Ok"}, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 realidx = index - 1;
|
||||
if(realidx < list.root.titles.size())
|
||||
{
|
||||
auto title = list.root.titles[realidx];
|
||||
if(!qapp->IsTitleSuspended())
|
||||
{
|
||||
am::QMenuCommandWriter writer(am::QDaemonMessage::LaunchApplication);
|
||||
|
@ -65,10 +77,11 @@ namespace ui
|
|||
}
|
||||
else
|
||||
{
|
||||
auto folder = list.folders[index - list.root.titles.size()];
|
||||
auto folder = list.folders[realidx - list.root.titles.size()];
|
||||
qapp->CreateShowDialog("Folder", folder.name, {"Ok"}, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MenuLayout::OnInput(u64 down, u64 up, u64 held, pu::ui::Touch pos)
|
||||
{
|
||||
|
@ -88,19 +101,6 @@ namespace ui
|
|||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
if(down & KEY_X)
|
||||
{
|
||||
auto [rc, msg] = am::QMenu_GetLatestQMenuMessage();
|
||||
qapp->CreateShowDialog("HOME SWEET HOME", "0x" + util::FormatApplicationId((u32)msg), {"Ok"}, true);
|
||||
if(qapp->IsTitleSuspended())
|
||||
{
|
||||
if(this->mode == 1) this->mode = 2;
|
||||
}
|
||||
else while(this->itemsMenu->GetSelectedItem() > 0) this->itemsMenu->HandleMoveLeft();
|
||||
}
|
||||
*/
|
||||
|
||||
if(this->susptr != NULL)
|
||||
{
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace ui
|
|||
{
|
||||
void QMenuApplication::OnLoad()
|
||||
{
|
||||
pu::ui::render::SetDefaultFont("romfs:/Gilroy-Bold.ttf");
|
||||
pu::ui::render::SetDefaultFont("romfs:/default/ui/Font.ttf");
|
||||
|
||||
this->startupLayout = StartupLayout::New(pu::ui::Color(10, 120, 255, 255));
|
||||
this->menuLayout = MenuLayout::New(app_buf);
|
||||
|
|
28
SystemAppletQDaemon/Include/ipc/ipc_IDaemonService.hpp
Normal file
28
SystemAppletQDaemon/Include/ipc/ipc_IDaemonService.hpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
#pragma once
|
||||
#include <q_Include.hpp>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ipc
|
||||
{
|
||||
class IDaemonService : public IServiceObject
|
||||
{
|
||||
private:
|
||||
|
||||
enum class CommandId
|
||||
{
|
||||
GetLatestMessage = 0
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Result GetLatestMessage(Out<u32> msg);
|
||||
|
||||
public:
|
||||
|
||||
DEFINE_SERVICE_DISPATCH_TABLE
|
||||
{
|
||||
MAKE_SERVICE_COMMAND_META(IDaemonService, GetLatestMessage)
|
||||
};
|
||||
};
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
extern "C"
|
||||
{
|
||||
u32 __nx_applet_type = AppletType_SystemApplet;
|
||||
size_t __nx_heap_size = 0x1000000;
|
||||
size_t __nx_heap_size = 0x3000000;//0x1000000;
|
||||
}
|
||||
|
||||
void CommonSleepHandle()
|
||||
|
@ -187,6 +187,23 @@ void HandleQMenuMessage()
|
|||
}
|
||||
break;
|
||||
}
|
||||
case am::QDaemonMessage::GetSuspendedApplicationId:
|
||||
{
|
||||
reader.FinishRead();
|
||||
|
||||
if(am::ApplicationIsActive())
|
||||
{
|
||||
am::QDaemonCommandResultWriter res(0);
|
||||
res.Write<u64>(am::ApplicationGetId());
|
||||
res.FinishWrite();
|
||||
}
|
||||
else
|
||||
{
|
||||
am::QDaemonCommandResultWriter res(0xDEAD1);
|
||||
res.FinishWrite();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -201,6 +218,53 @@ namespace qdaemon
|
|||
app_buf = new u8[1280 * 720 * 4]();
|
||||
fs::CreateDirectory(Q_BASE_SD_DIR);
|
||||
|
||||
// Debug testing mode
|
||||
consoleInit(NULL);
|
||||
CONSOLE_FMT("Welcome to QDaemon's debug mode!")
|
||||
CONSOLE_FMT("")
|
||||
CONSOLE_FMT("(A) -> Dump system save data to sd:/<q>/save_dump")
|
||||
CONSOLE_FMT("(B) -> Delete everything in save data (except official HOME menu's content)")
|
||||
CONSOLE_FMT("(X) -> Reboot system")
|
||||
CONSOLE_FMT("(Y) -> Continue to QMenu (proceed launch)")
|
||||
CONSOLE_FMT("")
|
||||
|
||||
while(true)
|
||||
{
|
||||
hidScanInput();
|
||||
auto k = hidKeysDown(CONTROLLER_P1_AUTO);
|
||||
if(k & KEY_A)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
consoleExit(NULL);
|
||||
|
||||
svcSleepThread(100'000'000); // Wait for proper moment
|
||||
}
|
||||
|
||||
|
|
16
SystemAppletQDaemon/Source/ipc/ipc_IDaemonService.cpp
Normal file
16
SystemAppletQDaemon/Source/ipc/ipc_IDaemonService.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include <ipc/ipc_IDaemonService.hpp>
|
||||
#include <am/am_QCommunications.hpp>
|
||||
|
||||
extern HosMutex latestqlock;
|
||||
extern am::QMenuMessage latestqmenumsg;
|
||||
|
||||
namespace ipc
|
||||
{
|
||||
Result IDaemonService::GetLatestMessage(Out<u32> msg)
|
||||
{
|
||||
std::scoped_lock lck(latestqlock);
|
||||
msg.SetValue((u32)latestqmenumsg);
|
||||
latestqmenumsg = am::QMenuMessage::Invalid;
|
||||
return 0;
|
||||
}
|
||||
}
|
85
Themes.md
Normal file
85
Themes.md
Normal file
|
@ -0,0 +1,85 @@
|
|||
# Theme system
|
||||
|
||||
## **IMPORTANT!** Don't use this system yet. Wait until this warning is removed (when the system is finally decided)
|
||||
|
||||
> Current theme format version: none (unreleased yet)
|
||||
|
||||
Themes consist on plain directories replacing RomFs content.
|
||||
|
||||
A valid theme must, at least, contain a `/theme` subdirectory and a `/theme/Manifest.json` within it (icon or actual modifications aren't neccessary)
|
||||
|
||||
**Important note:** any content (sound or UI) not found in the theme will be loaded from the default config, thus there is no need to provide every file (for instance, when making UI-only or sound-only changes)
|
||||
|
||||
## Metadata
|
||||
|
||||
Metadata is stored inside `/theme` directory. It is required for the theme to be recognized as a valid one.
|
||||
|
||||
- `theme/Manifest.json` -> JSON containing theme information
|
||||
|
||||
Demo JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "My awesome theme",
|
||||
"version": 0,
|
||||
"release": "0.1",
|
||||
"description": "This is a really cool theme, check it out!",
|
||||
"author": "XorTroll"
|
||||
}
|
||||
```
|
||||
|
||||
Properties:
|
||||
|
||||
- **name**: Theme name
|
||||
|
||||
- **version**: Theme format version (qlaunch updates might introduce changes to themes, thus a new format version would be out).
|
||||
|
||||
- **release**: Theme version string
|
||||
|
||||
- **description**: Theme description
|
||||
|
||||
- **author**: Theme author name(s)
|
||||
|
||||
- `theme/Icon(.png?)` -> Icon (which size and format shall we use?)
|
||||
|
||||
## Sound
|
||||
|
||||
Sound consists on custom *background music* and *sound effects* via files inside `/sound`.
|
||||
|
||||
- `sound/BGM.mp3` -> MP3 file to replace with custom music
|
||||
|
||||
- `sound/BGM.json` -> JSON file with BGM settings
|
||||
|
||||
Demo JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"loop": true,
|
||||
"fade_in": true,
|
||||
"fade_out": false
|
||||
}
|
||||
```
|
||||
|
||||
Properties:
|
||||
|
||||
- **loop**: Whether to replay the MP3 file again, after it finishes
|
||||
|
||||
- **fade_in**: Whether starting the music should apply a fade-in effect.
|
||||
|
||||
- **fade_out**: Whether stopping the music should apply a fade-out effect.
|
||||
|
||||
Note: returning to/launching a title/applet and returning back to HOME menu will restart the music.
|
||||
|
||||
> *TODO: Sound effects*
|
||||
|
||||
## UI
|
||||
|
||||
Can be customized via files in `/ui`.
|
||||
|
||||
- `ui/Font.ttf` -> TTF font used for all the UI.
|
||||
|
||||
- `ui/AllTitles.png` -> 256x256 icon for the "all titles" entry in the main menu.
|
||||
|
||||
- `ui/Folder.png` -> 256x256 icon for folders in the main menu.
|
||||
|
||||
> *TODO: more customizable stuff*
|
1
libstratosphere
Submodule
1
libstratosphere
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 8bae7b4a78f8fe5061596f354e38ecd0238cdaed
|
Loading…
Reference in a new issue