mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-11-01 02:54:30 +01:00
Only the Windows installer and the deb registered the scheme, so after extension verification the browser could not return to a portable zip or AppImage copy and the link had to be pasted. On launch the runners now point the per-user handler at the running copy when it does not already start it (HKCU\Software\Classes\mornye on Windows, a GIO x-scheme-handler default on Linux, using $APPIMAGE for AppImages).
117 lines
4.2 KiB
C++
117 lines
4.2 KiB
C++
#include <flutter/dart_project.h>
|
|
#include <flutter/flutter_view_controller.h>
|
|
#include <shobjidl.h>
|
|
#include <windows.h>
|
|
|
|
#include <string>
|
|
|
|
#include "app_links/app_links_plugin_c_api.h"
|
|
#include "flutter_window.h"
|
|
#include "utils.h"
|
|
|
|
namespace {
|
|
|
|
// Per user session, so two signed-in users each get their own instance.
|
|
constexpr wchar_t kSingleInstanceMutex[] = L"Local\\com.zarz.mornye.instance";
|
|
|
|
// Same ID as the installer's Start Menu shortcut (windows/installer), so the
|
|
// taskbar groups the window with its pinned shortcut.
|
|
constexpr wchar_t kAppUserModelId[] = L"com.zarz.mornye";
|
|
|
|
constexpr wchar_t kUrlSchemeKey[] = L"Software\\Classes\\mornye";
|
|
constexpr wchar_t kUrlCommandKey[] =
|
|
L"Software\\Classes\\mornye\\shell\\open\\command";
|
|
|
|
void SetUserRegistryString(const wchar_t* key, const wchar_t* name,
|
|
const std::wstring& value) {
|
|
::RegSetKeyValueW(HKEY_CURRENT_USER, key, name, REG_SZ, value.c_str(),
|
|
static_cast<DWORD>((value.size() + 1) * sizeof(wchar_t)));
|
|
}
|
|
|
|
// The installer registers mornye://, but a portable copy has no installer,
|
|
// so the browser could not hand an extension callback back to it. Points
|
|
// the per-user handler at this executable unless it already does.
|
|
void RegisterUrlScheme() {
|
|
wchar_t path[MAX_PATH];
|
|
const DWORD length = ::GetModuleFileNameW(nullptr, path, MAX_PATH);
|
|
if (length == 0 || length == MAX_PATH) return;
|
|
const std::wstring executable = L"\"" + std::wstring(path) + L"\"";
|
|
const std::wstring command = executable + L" \"%1\"";
|
|
|
|
wchar_t current[MAX_PATH + 16];
|
|
DWORD size = sizeof(current);
|
|
if (::RegGetValueW(HKEY_CURRENT_USER, kUrlCommandKey, nullptr,
|
|
RRF_RT_REG_SZ, nullptr, current,
|
|
&size) == ERROR_SUCCESS &&
|
|
::_wcsicmp(current, command.c_str()) == 0) {
|
|
return;
|
|
}
|
|
SetUserRegistryString(kUrlSchemeKey, nullptr, L"URL:Mornye Protocol");
|
|
SetUserRegistryString(kUrlSchemeKey, L"URL Protocol", L"");
|
|
SetUserRegistryString(L"Software\\Classes\\mornye\\DefaultIcon", nullptr,
|
|
executable + L",0");
|
|
SetUserRegistryString(kUrlCommandKey, nullptr, command);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
|
_In_ wchar_t *command_line, _In_ int show_command) {
|
|
// Single instance. A second launch (for example a mornye:// callback from
|
|
// the browser: the installer and RegisterUrlScheme register
|
|
// `"mornye.exe" "%1"` under HKCU\Software\Classes\mornye) hands its URL
|
|
// to the running window with WM_COPYDATA, raises that window and exits.
|
|
// The installer closes the app before it replaces files, so a
|
|
// /RELAUNCH=1 start finds no instance.
|
|
HANDLE instance_mutex =
|
|
::CreateMutexW(nullptr, TRUE, kSingleInstanceMutex);
|
|
if (instance_mutex != nullptr && ::GetLastError() == ERROR_ALREADY_EXISTS) {
|
|
// False while the first instance has not created its window yet; the
|
|
// URL is then lost, as for any launch during startup.
|
|
SendAppLinkToInstance();
|
|
::CloseHandle(instance_mutex);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
::SetCurrentProcessExplicitAppUserModelID(kAppUserModelId);
|
|
RegisterUrlScheme();
|
|
|
|
// Attach to console when present (e.g., 'flutter run') or create a
|
|
// new console when running with a debugger.
|
|
if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
|
|
CreateAndAttachConsole();
|
|
}
|
|
|
|
// Initialize COM, so that it is available for use in the library and/or
|
|
// plugins.
|
|
::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
|
|
|
flutter::DartProject project(L"data");
|
|
|
|
std::vector<std::string> command_line_arguments =
|
|
GetCommandLineArguments();
|
|
|
|
project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
|
|
|
|
FlutterWindow window(project);
|
|
Win32Window::Point origin(10, 10);
|
|
Win32Window::Size size(1280, 800);
|
|
if (!window.Create(L"Mornye", origin, size)) {
|
|
return EXIT_FAILURE;
|
|
}
|
|
window.SetQuitOnClose(true);
|
|
|
|
::MSG msg;
|
|
while (::GetMessage(&msg, nullptr, 0, 0)) {
|
|
::TranslateMessage(&msg);
|
|
::DispatchMessage(&msg);
|
|
}
|
|
|
|
::CoUninitialize();
|
|
if (instance_mutex != nullptr) {
|
|
::ReleaseMutex(instance_mutex);
|
|
::CloseHandle(instance_mutex);
|
|
}
|
|
return EXIT_SUCCESS;
|
|
}
|