mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-30 02:16:06 +00:00
[bcat/news/web/am] Implement news applet, proper TLV return, external web browser URL and qlaunch app sorting (#3308)
This pulls eden releases changelog & text from our github releases. We don't store the msgpack file but rather generate them in-memory for the News Applet. Uses cache folder. Files generated are: - cache/news/github_releases.json - cache/news/eden_logo.jpg - cache/news/news_read Additional changes: - Proper TLV returning for online web applet, to open external URL - Add applet type `LHub` to properly close, as it also uses TLV return - qlaunch app sorting, adds another cached .json to track last launched app timestamps and sort them accordingly Co-authored-by: crueter <crueter@eden-emu.dev> Co-authored-by: DraVee <dravee@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3308 Reviewed-by: MaranBr <maranbr@eden-emu.dev> Reviewed-by: DraVee <dravee@eden-emu.dev> Reviewed-by: Lizzie <lizzie@eden-emu.dev> Co-authored-by: Maufeat <sahyno1996@gmail.com> Co-committed-by: Maufeat <sahyno1996@gmail.com>
This commit is contained in:
@@ -94,6 +94,7 @@ enum class AppletId : u32 {
|
||||
LoginShare = 0x18,
|
||||
WebAuth = 0x19,
|
||||
MyPage = 0x1A,
|
||||
Lhub = 0x35
|
||||
};
|
||||
|
||||
enum class AppletProgramId : u64 {
|
||||
|
||||
@@ -236,10 +236,6 @@ WebBrowser::WebBrowser(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||
WebBrowser::~WebBrowser() = default;
|
||||
|
||||
void WebBrowser::Initialize() {
|
||||
if (Settings::values.disable_web_applet) {
|
||||
return;
|
||||
}
|
||||
|
||||
FrontendApplet::Initialize();
|
||||
|
||||
LOG_INFO(Service_AM, "Initializing Web Browser Applet.");
|
||||
@@ -264,6 +260,12 @@ void WebBrowser::Initialize() {
|
||||
LOG_DEBUG(Service_AM, "WebArgHeader: total_tlv_entries={}, shim_kind={}",
|
||||
web_arg_header.total_tlv_entries, web_arg_header.shim_kind);
|
||||
|
||||
if (Settings::values.disable_web_applet &&
|
||||
web_arg_header.shim_kind != ShimKind::Web &&
|
||||
web_arg_header.shim_kind != ShimKind::Lhub) {
|
||||
return;
|
||||
}
|
||||
|
||||
ExtractSharedFonts(system);
|
||||
|
||||
switch (web_arg_header.shim_kind) {
|
||||
@@ -288,6 +290,9 @@ void WebBrowser::Initialize() {
|
||||
case ShimKind::Lobby:
|
||||
InitializeLobby();
|
||||
break;
|
||||
case ShimKind::Lhub:
|
||||
InitializeLhub();
|
||||
break;
|
||||
default:
|
||||
ASSERT_MSG(false, "Invalid ShimKind={}", web_arg_header.shim_kind);
|
||||
break;
|
||||
@@ -303,8 +308,19 @@ void WebBrowser::ExecuteInteractive() {
|
||||
}
|
||||
|
||||
void WebBrowser::Execute() {
|
||||
if (web_arg_header.shim_kind == ShimKind::Web) {
|
||||
ExecuteWeb();
|
||||
return;
|
||||
}
|
||||
|
||||
if (web_arg_header.shim_kind == ShimKind::Lhub) {
|
||||
ExecuteLhub();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Settings::values.disable_web_applet) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, Web Browser Applet is disabled");
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, Web Browser Applet is disabled. shim_kind={}",
|
||||
web_arg_header.shim_kind);
|
||||
WebBrowserExit(WebExitReason::EndButtonPressed);
|
||||
return;
|
||||
}
|
||||
@@ -331,6 +347,9 @@ void WebBrowser::Execute() {
|
||||
case ShimKind::Lobby:
|
||||
ExecuteLobby();
|
||||
break;
|
||||
case ShimKind::Lhub:
|
||||
ExecuteLhub();
|
||||
break;
|
||||
default:
|
||||
ASSERT_MSG(false, "Invalid ShimKind={}", web_arg_header.shim_kind);
|
||||
WebBrowserExit(WebExitReason::EndButtonPressed);
|
||||
@@ -351,17 +370,99 @@ void WebBrowser::ExtractOfflineRomFS() {
|
||||
}
|
||||
|
||||
void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url) {
|
||||
if ((web_arg_header.shim_kind == ShimKind::Share &&
|
||||
const bool use_tlv_output =
|
||||
(web_arg_header.shim_kind == ShimKind::Share &&
|
||||
web_applet_version >= WebAppletVersion::Version196608) ||
|
||||
(web_arg_header.shim_kind == ShimKind::Web &&
|
||||
web_applet_version >= WebAppletVersion::Version524288)) {
|
||||
// TODO: Push Output TLVs instead of a WebCommonReturnValue
|
||||
web_applet_version >= WebAppletVersion::Version524288) ||
|
||||
(web_arg_header.shim_kind == ShimKind::Lhub);
|
||||
|
||||
// https://switchbrew.org/wiki/Internet_Browser#TLVs
|
||||
if (use_tlv_output) {
|
||||
LOG_DEBUG(Service_AM, "Using TLV output: exit_reason={}, last_url={}, last_url_size={}",
|
||||
exit_reason, last_url, last_url.size());
|
||||
|
||||
// storage size for TLVs is 0x2000 bytes (as per switchbrew documentation)
|
||||
constexpr size_t TLV_STORAGE_SIZE = 0x2000;
|
||||
std::vector<u8> out_data(TLV_STORAGE_SIZE, 0);
|
||||
|
||||
size_t current_offset = sizeof(WebArgHeader);
|
||||
u16 tlv_count = 0;
|
||||
|
||||
// align and matchng TLV struct alignment
|
||||
auto align_offset = [](size_t offset) -> size_t {
|
||||
return (offset + 7) & ~static_cast<size_t>(7);
|
||||
};
|
||||
|
||||
// 0x1 ShareExitReason
|
||||
{
|
||||
WebArgOutputTLV tlv{};
|
||||
tlv.output_tlv_type = WebArgOutputTLVType::ShareExitReason;
|
||||
tlv.arg_data_size = sizeof(u32);
|
||||
|
||||
std::memcpy(out_data.data() + current_offset, &tlv, sizeof(WebArgOutputTLV));
|
||||
current_offset += sizeof(WebArgOutputTLV);
|
||||
|
||||
const u32 exit_reason_value = static_cast<u32>(exit_reason);
|
||||
std::memcpy(out_data.data() + current_offset, &exit_reason_value, sizeof(u32));
|
||||
current_offset += sizeof(u32);
|
||||
|
||||
current_offset = align_offset(current_offset);
|
||||
tlv_count++;
|
||||
}
|
||||
|
||||
// 0x2 LastUrl
|
||||
{
|
||||
WebArgOutputTLV tlv{};
|
||||
tlv.output_tlv_type = WebArgOutputTLVType::LastURL;
|
||||
const u16 url_data_size = static_cast<u16>(last_url.size() + 1);
|
||||
tlv.arg_data_size = url_data_size;
|
||||
|
||||
std::memcpy(out_data.data() + current_offset, &tlv, sizeof(WebArgOutputTLV));
|
||||
current_offset += sizeof(WebArgOutputTLV);
|
||||
|
||||
// null terminator
|
||||
std::memcpy(out_data.data() + current_offset, last_url.c_str(), last_url.size() + 1);
|
||||
current_offset += url_data_size;
|
||||
current_offset = align_offset(current_offset);
|
||||
tlv_count++;
|
||||
}
|
||||
|
||||
// 0x3 LastUrlSize
|
||||
{
|
||||
WebArgOutputTLV tlv{};
|
||||
tlv.output_tlv_type = WebArgOutputTLVType::LastURLSize;
|
||||
tlv.arg_data_size = sizeof(u64);
|
||||
|
||||
std::memcpy(out_data.data() + current_offset, &tlv, sizeof(WebArgOutputTLV));
|
||||
current_offset += sizeof(WebArgOutputTLV);
|
||||
|
||||
const u64 url_size = last_url.size();
|
||||
std::memcpy(out_data.data() + current_offset, &url_size, sizeof(u64));
|
||||
current_offset += sizeof(u64);
|
||||
tlv_count++;
|
||||
}
|
||||
|
||||
WebArgHeader out_header{};
|
||||
out_header.total_tlv_entries = tlv_count;
|
||||
out_header.shim_kind = web_arg_header.shim_kind;
|
||||
std::memcpy(out_data.data(), &out_header, sizeof(WebArgHeader));
|
||||
|
||||
LOG_DEBUG(Service_AM, "TLV output: total_size={}, tlv_count={}, used_offset={}",
|
||||
out_data.size(), tlv_count, current_offset);
|
||||
|
||||
complete = true;
|
||||
PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
|
||||
Exit();
|
||||
return;
|
||||
}
|
||||
|
||||
WebCommonReturnValue web_common_return_value;
|
||||
// for old browser, keep old return, use WebCommonReturnValue
|
||||
WebCommonReturnValue web_common_return_value{};
|
||||
|
||||
web_common_return_value.exit_reason = exit_reason;
|
||||
std::memcpy(&web_common_return_value.last_url, last_url.data(), last_url.size());
|
||||
std::memcpy(&web_common_return_value.last_url, last_url.data(),
|
||||
std::min(last_url.size(), web_common_return_value.last_url.size()));
|
||||
web_common_return_value.last_url_size = last_url.size();
|
||||
|
||||
LOG_DEBUG(Service_AM, "WebCommonReturnValue: exit_reason={}, last_url={}, last_url_size={}",
|
||||
@@ -516,4 +617,13 @@ void WebBrowser::ExecuteLobby() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented");
|
||||
WebBrowserExit(WebExitReason::EndButtonPressed);
|
||||
}
|
||||
|
||||
void WebBrowser::InitializeLhub() {}
|
||||
|
||||
void WebBrowser::ExecuteLhub() {
|
||||
LOG_INFO(Service_AM, "(STUBBED) called, Lhub Applet is not implemented");
|
||||
WebBrowserExit(WebExitReason::EndButtonPressed);
|
||||
}
|
||||
|
||||
|
||||
} // namespace Service::AM::Frontend
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -53,6 +56,7 @@ private:
|
||||
void InitializeWeb();
|
||||
void InitializeWifi();
|
||||
void InitializeLobby();
|
||||
void InitializeLhub();
|
||||
|
||||
// Executors for the various types of browser applets
|
||||
void ExecuteShop();
|
||||
@@ -62,6 +66,7 @@ private:
|
||||
void ExecuteWeb();
|
||||
void ExecuteWifi();
|
||||
void ExecuteLobby();
|
||||
void ExecuteLhub();
|
||||
|
||||
const Core::Frontend::WebBrowserApplet& frontend;
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -30,6 +33,7 @@ enum class ShimKind : u32 {
|
||||
Web = 5,
|
||||
Wifi = 6,
|
||||
Lobby = 7,
|
||||
Lhub = 8,
|
||||
};
|
||||
|
||||
enum class WebExitReason : u32 {
|
||||
|
||||
@@ -237,13 +237,15 @@ std::shared_ptr<FrontendApplet> FrontendAppletHolder::GetApplet(std::shared_ptr<
|
||||
case AppletId::OfflineWeb:
|
||||
case AppletId::LoginShare:
|
||||
case AppletId::WebAuth:
|
||||
case AppletId::Lhub:
|
||||
return std::make_shared<WebBrowser>(system, applet, mode, *frontend.web_browser);
|
||||
case AppletId::PhotoViewer:
|
||||
return std::make_shared<PhotoViewer>(system, applet, mode, *frontend.photo_viewer);
|
||||
case AppletId::NetConnect:
|
||||
return std::make_shared<NetConnect>(system, applet, mode, *frontend.net_connect);
|
||||
default:
|
||||
LOG_ERROR(Service_AM, "No backend implementation exists for applet_id={:02X}. Falling back to stub applet", static_cast<u8>(id));
|
||||
LOG_ERROR(Service_AM, "No backend implementation exists for applet_id={:02X} program_id={:016X}"
|
||||
"Falling back to stub applet", static_cast<u8>(id), applet->program_id);
|
||||
return std::make_shared<StubApplet>(system, applet, id, mode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "core/hle/service/am/window_system.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/launch_timestamp_cache.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
@@ -72,6 +73,7 @@ IApplicationCreator::~IApplicationCreator() = default;
|
||||
Result IApplicationCreator::CreateApplication(
|
||||
Out<SharedPointer<IApplicationAccessor>> out_application_accessor, u64 application_id) {
|
||||
LOG_INFO(Service_NS, "called, application_id={:016X}", application_id);
|
||||
Core::LaunchTimestampCache::SaveLaunchTimestamp(application_id);
|
||||
R_RETURN(
|
||||
CreateGuestApplication(out_application_accessor, system, m_window_system, application_id));
|
||||
}
|
||||
@@ -103,6 +105,7 @@ Result IApplicationCreator::CreateSystemApplication(
|
||||
|
||||
*out_application_accessor =
|
||||
std::make_shared<IApplicationAccessor>(system, applet, m_window_system);
|
||||
Core::LaunchTimestampCache::SaveLaunchTimestamp(application_id);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user