Restore the start menu shortcut as a proper launcher for the UI and service
This commit is contained in:
@@ -764,6 +764,20 @@ if(WIN32) # see options at: https://cmake.org/cmake/help/latest/cpack_gen/nsis.h
|
|||||||
NoDelete:
|
NoDelete:
|
||||||
")
|
")
|
||||||
|
|
||||||
|
# Adding an option for the start menu
|
||||||
|
set(CPACK_NSIS_MODIFY_PATH "OFF")
|
||||||
|
set(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
|
||||||
|
# This will be shown on the installed apps Windows settings
|
||||||
|
set(CPACK_NSIS_INSTALLED_ICON_NAME "${CMAKE_PROJECT_NAME}.exe")
|
||||||
|
set(CPACK_NSIS_CREATE_ICONS_EXTRA
|
||||||
|
"${CPACK_NSIS_CREATE_ICONS_EXTRA}
|
||||||
|
CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\${CMAKE_PROJECT_NAME}.lnk' \
|
||||||
|
'\$INSTDIR\\\\${CMAKE_PROJECT_NAME}.exe' '--shortcut'
|
||||||
|
")
|
||||||
|
set(CPACK_NSIS_DELETE_ICONS_EXTRA
|
||||||
|
"${CPACK_NSIS_DELETE_ICONS_EXTRA}
|
||||||
|
Delete '\$SMPROGRAMS\\\\$MUI_TEMP\\\\${CMAKE_PROJECT_NAME}.lnk'
|
||||||
|
")
|
||||||
|
|
||||||
# Checking for previous installed versions
|
# Checking for previous installed versions
|
||||||
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL "ON")
|
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL "ON")
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
#include "platform/common.h"
|
#include "platform/common.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <shellapi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
|
||||||
@@ -1091,6 +1095,8 @@ namespace config {
|
|||||||
int
|
int
|
||||||
parse(int argc, char *argv[]) {
|
parse(int argc, char *argv[]) {
|
||||||
std::unordered_map<std::string, std::string> cmd_vars;
|
std::unordered_map<std::string, std::string> cmd_vars;
|
||||||
|
bool shortcut_launch = false;
|
||||||
|
bool service_admin_launch = false;
|
||||||
|
|
||||||
for (auto x = 1; x < argc; ++x) {
|
for (auto x = 1; x < argc; ++x) {
|
||||||
auto line = argv[x];
|
auto line = argv[x];
|
||||||
@@ -1099,6 +1105,12 @@ namespace config {
|
|||||||
print_help(*argv);
|
print_help(*argv);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
else if (line == "--shortcut"sv) {
|
||||||
|
shortcut_launch = true;
|
||||||
|
}
|
||||||
|
else if (line == "--shortcut-admin"sv) {
|
||||||
|
service_admin_launch = true;
|
||||||
|
}
|
||||||
else if (*line == '-') {
|
else if (*line == '-') {
|
||||||
if (*(line + 1) == '-') {
|
if (*(line + 1) == '-') {
|
||||||
sunshine.cmd.name = line + 2;
|
sunshine.cmd.name = line + 2;
|
||||||
@@ -1156,6 +1168,51 @@ namespace config {
|
|||||||
|
|
||||||
apply_config(std::move(vars));
|
apply_config(std::move(vars));
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// We have to wait until the config is loaded to handle these launches,
|
||||||
|
// because we need to have the correct base port loaded in our config.
|
||||||
|
if (service_admin_launch) {
|
||||||
|
// This is a relaunch as admin to start the service
|
||||||
|
service_ctrl::start_service();
|
||||||
|
|
||||||
|
// Always return 1 to ensure Sunshine doesn't start normally
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (shortcut_launch) {
|
||||||
|
if (!service_ctrl::is_service_running()) {
|
||||||
|
// If the service isn't running, relaunch ourselves as admin to start it
|
||||||
|
WCHAR executable[MAX_PATH];
|
||||||
|
GetModuleFileNameW(NULL, executable, ARRAYSIZE(executable));
|
||||||
|
|
||||||
|
SHELLEXECUTEINFOW shell_exec_info {};
|
||||||
|
shell_exec_info.cbSize = sizeof(shell_exec_info);
|
||||||
|
shell_exec_info.fMask = SEE_MASK_NOASYNC | SEE_MASK_NO_CONSOLE | SEE_MASK_NOCLOSEPROCESS;
|
||||||
|
shell_exec_info.lpVerb = L"runas";
|
||||||
|
shell_exec_info.lpFile = executable;
|
||||||
|
shell_exec_info.lpParameters = L"--shortcut-admin";
|
||||||
|
shell_exec_info.nShow = SW_NORMAL;
|
||||||
|
if (!ShellExecuteExW(&shell_exec_info)) {
|
||||||
|
auto winerr = GetLastError();
|
||||||
|
std::cout << "Error: ShellExecuteEx() failed:"sv << winerr << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the elevated process to finish starting the service
|
||||||
|
WaitForSingleObject(shell_exec_info.hProcess, INFINITE);
|
||||||
|
CloseHandle(shell_exec_info.hProcess);
|
||||||
|
|
||||||
|
// Wait for the UI to be ready for connections
|
||||||
|
service_ctrl::wait_for_ui_ready();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Launch the web UI
|
||||||
|
launch_ui();
|
||||||
|
|
||||||
|
// Always return 1 to ensure Sunshine doesn't start normally
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} // namespace config
|
} // namespace config
|
||||||
|
|||||||
207
src/main.cpp
207
src/main.cpp
@@ -34,6 +34,10 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#include <libavutil/log.h>
|
#include <libavutil/log.h>
|
||||||
#include <rs.h>
|
#include <rs.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <iphlpapi.h>
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
safe::mail_t mail::man;
|
safe::mail_t mail::man;
|
||||||
@@ -141,6 +145,209 @@ namespace lifetime {
|
|||||||
}
|
}
|
||||||
} // namespace lifetime
|
} // namespace lifetime
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
namespace service_ctrl {
|
||||||
|
class service_controller {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Constructor for service_controller class
|
||||||
|
* @param service_desired_access SERVICE_* desired access flags
|
||||||
|
*/
|
||||||
|
service_controller(DWORD service_desired_access) {
|
||||||
|
scm_handle = OpenSCManagerA(nullptr, nullptr, SC_MANAGER_CONNECT);
|
||||||
|
if (!scm_handle) {
|
||||||
|
auto winerr = GetLastError();
|
||||||
|
BOOST_LOG(error) << "OpenSCManager() failed: "sv << winerr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
service_handle = OpenServiceA(scm_handle, "SunshineSvc", service_desired_access);
|
||||||
|
if (!service_handle) {
|
||||||
|
auto winerr = GetLastError();
|
||||||
|
BOOST_LOG(error) << "OpenService() failed: "sv << winerr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~service_controller() {
|
||||||
|
if (service_handle) {
|
||||||
|
CloseServiceHandle(service_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scm_handle) {
|
||||||
|
CloseServiceHandle(scm_handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Asynchronously starts the Sunshine service
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
start_service() {
|
||||||
|
if (!service_handle) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!StartServiceA(service_handle, 0, nullptr)) {
|
||||||
|
auto winerr = GetLastError();
|
||||||
|
if (winerr != ERROR_SERVICE_ALREADY_RUNNING) {
|
||||||
|
BOOST_LOG(error) << "StartService() failed: "sv << winerr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Query the service status
|
||||||
|
* @param status The SERVICE_STATUS struct to populate
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
query_service_status(SERVICE_STATUS &status) {
|
||||||
|
if (!service_handle) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!QueryServiceStatus(service_handle, &status)) {
|
||||||
|
auto winerr = GetLastError();
|
||||||
|
BOOST_LOG(error) << "QueryServiceStatus() failed: "sv << winerr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SC_HANDLE scm_handle = NULL;
|
||||||
|
SC_HANDLE service_handle = NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if the service is running
|
||||||
|
*
|
||||||
|
* EXAMPLES:
|
||||||
|
* ```cpp
|
||||||
|
* is_service_running();
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
is_service_running() {
|
||||||
|
service_controller sc { SERVICE_QUERY_STATUS };
|
||||||
|
|
||||||
|
SERVICE_STATUS status;
|
||||||
|
if (!sc.query_service_status(status)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status.dwCurrentState == SERVICE_RUNNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start the service and wait for startup to complete
|
||||||
|
*
|
||||||
|
* EXAMPLES:
|
||||||
|
* ```cpp
|
||||||
|
* start_service();
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
start_service() {
|
||||||
|
service_controller sc { SERVICE_QUERY_STATUS | SERVICE_START };
|
||||||
|
|
||||||
|
std::cout << "Starting Sunshine..."sv;
|
||||||
|
|
||||||
|
// This operation is asynchronous, so we must wait for it to complete
|
||||||
|
if (!sc.start_service()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SERVICE_STATUS status;
|
||||||
|
do {
|
||||||
|
Sleep(1000);
|
||||||
|
std::cout << '.';
|
||||||
|
} while (sc.query_service_status(status) && status.dwCurrentState == SERVICE_START_PENDING);
|
||||||
|
|
||||||
|
if (status.dwCurrentState != SERVICE_RUNNING) {
|
||||||
|
BOOST_LOG(error) << SERVICE_NAME " failed to start: "sv << status.dwWin32ExitCode;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wait for the UI to be ready after Sunshine startup
|
||||||
|
*
|
||||||
|
* EXAMPLES:
|
||||||
|
* ```cpp
|
||||||
|
* wait_for_ui_ready();
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
wait_for_ui_ready() {
|
||||||
|
std::cout << "Waiting for Web UI to be ready...";
|
||||||
|
|
||||||
|
// Wait up to 30 seconds for the web UI to start
|
||||||
|
for (int i = 0; i < 30; i++) {
|
||||||
|
PMIB_TCPTABLE tcp_table = nullptr;
|
||||||
|
ULONG table_size = 0;
|
||||||
|
ULONG err;
|
||||||
|
|
||||||
|
auto fg = util::fail_guard([&tcp_table]() {
|
||||||
|
free(tcp_table);
|
||||||
|
});
|
||||||
|
|
||||||
|
do {
|
||||||
|
// Query all open TCP sockets to look for our web UI port
|
||||||
|
err = GetTcpTable(tcp_table, &table_size, false);
|
||||||
|
if (err == ERROR_INSUFFICIENT_BUFFER) {
|
||||||
|
free(tcp_table);
|
||||||
|
tcp_table = (PMIB_TCPTABLE) malloc(table_size);
|
||||||
|
}
|
||||||
|
} while (err == ERROR_INSUFFICIENT_BUFFER);
|
||||||
|
|
||||||
|
if (err != NO_ERROR) {
|
||||||
|
BOOST_LOG(error) << "Failed to query TCP table: "sv << err;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t port_nbo = htons(map_port(confighttp::PORT_HTTPS));
|
||||||
|
for (DWORD i = 0; i < tcp_table->dwNumEntries; i++) {
|
||||||
|
auto &entry = tcp_table->table[i];
|
||||||
|
|
||||||
|
// Look for our port in the listening state
|
||||||
|
if (entry.dwLocalPort == port_nbo && entry.dwState == MIB_TCP_STATE_LISTEN) {
|
||||||
|
std::cout << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Sleep(1000);
|
||||||
|
std::cout << '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "timed out"sv << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} // namespace service_ctrl
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Launch the Web UI
|
||||||
|
*
|
||||||
|
* EXAMPLES:
|
||||||
|
* ```cpp
|
||||||
|
* launch_ui();
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
launch_ui() {
|
||||||
|
std::string url = "https://localhost:" + std::to_string(map_port(confighttp::PORT_HTTPS));
|
||||||
|
platf::open_url(url);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Flush the log.
|
* @brief Flush the log.
|
||||||
*
|
*
|
||||||
|
|||||||
15
src/main.h
15
src/main.h
@@ -40,6 +40,8 @@ int
|
|||||||
write_file(const char *path, const std::string_view &contents);
|
write_file(const char *path, const std::string_view &contents);
|
||||||
std::uint16_t
|
std::uint16_t
|
||||||
map_port(int port);
|
map_port(int port);
|
||||||
|
void
|
||||||
|
launch_ui();
|
||||||
|
|
||||||
// namespaces
|
// namespaces
|
||||||
namespace mail {
|
namespace mail {
|
||||||
@@ -73,4 +75,17 @@ namespace lifetime {
|
|||||||
get_argv();
|
get_argv();
|
||||||
} // namespace lifetime
|
} // namespace lifetime
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
namespace service_ctrl {
|
||||||
|
bool
|
||||||
|
is_service_running();
|
||||||
|
|
||||||
|
bool
|
||||||
|
start_service();
|
||||||
|
|
||||||
|
bool
|
||||||
|
wait_for_ui_ready();
|
||||||
|
} // namespace service_ctrl
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // SUNSHINE_MAIN_H
|
#endif // SUNSHINE_MAIN_H
|
||||||
|
|||||||
@@ -423,6 +423,13 @@ namespace platf {
|
|||||||
std::unique_ptr<deinit_t>
|
std::unique_ptr<deinit_t>
|
||||||
enable_socket_qos(uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type);
|
enable_socket_qos(uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Open a url in the default web browser.
|
||||||
|
* @param url The url to open.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
open_url(const std::string &url);
|
||||||
|
|
||||||
input_t
|
input_t
|
||||||
input();
|
input();
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -178,6 +178,28 @@ namespace platf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Open a url in the default web browser.
|
||||||
|
* @param url The url to open.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
open_url(const std::string &url) {
|
||||||
|
// set working dir to user home directory
|
||||||
|
auto working_dir = boost::filesystem::path(std::getenv("HOME"));
|
||||||
|
std::string cmd = R"(xdg-open ")" + url + R"(")";
|
||||||
|
|
||||||
|
boost::process::environment _env = boost::this_process::environment();
|
||||||
|
std::error_code ec;
|
||||||
|
auto child = run_command(false, cmd, working_dir, _env, nullptr, ec, nullptr);
|
||||||
|
if (ec) {
|
||||||
|
BOOST_LOG(warning) << "Couldn't open url ["sv << url << "]: System: "sv << ec.message();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BOOST_LOG(info) << "Opened url ["sv << url << "]"sv;
|
||||||
|
child.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
adjust_thread_priority(thread_priority_e priority) {
|
adjust_thread_priority(thread_priority_e priority) {
|
||||||
// Unimplemented
|
// Unimplemented
|
||||||
|
|||||||
@@ -178,6 +178,27 @@ namespace platf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Open a url in the default web browser.
|
||||||
|
* @param url The url to open.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
open_url(const std::string &url) {
|
||||||
|
boost::filesystem::path working_dir;
|
||||||
|
std::string cmd = R"(open ")" + url + R"(")";
|
||||||
|
|
||||||
|
boost::process::environment _env = boost::this_process::environment();
|
||||||
|
std::error_code ec;
|
||||||
|
auto child = run_command(false, cmd, working_dir, _env, nullptr, ec, nullptr);
|
||||||
|
if (ec) {
|
||||||
|
BOOST_LOG(warning) << "Couldn't open url ["sv << url << "]: System: "sv << ec.message();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BOOST_LOG(info) << "Opened url ["sv << url << "]"sv;
|
||||||
|
child.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
adjust_thread_priority(thread_priority_e priority) {
|
adjust_thread_priority(thread_priority_e priority) {
|
||||||
// Unimplemented
|
// Unimplemented
|
||||||
|
|||||||
@@ -651,6 +651,31 @@ namespace platf {
|
|||||||
return create_boost_child_from_results(ret, cmd, ec, process_info, group);
|
return create_boost_child_from_results(ret, cmd, ec, process_info, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Open a url in the default web browser.
|
||||||
|
* @param url The url to open.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
open_url(const std::string &url) {
|
||||||
|
// set working dir to Windows system directory
|
||||||
|
auto working_dir = boost::filesystem::path(std::getenv("SystemRoot"));
|
||||||
|
|
||||||
|
// this isn't ideal as it briefly shows a command window
|
||||||
|
// but start a command built into cmd, not an executable
|
||||||
|
std::string cmd = R"(cmd /C "start )" + url + R"(")";
|
||||||
|
|
||||||
|
boost::process::environment _env = boost::this_process::environment();
|
||||||
|
std::error_code ec;
|
||||||
|
auto child = run_command(false, cmd, working_dir, _env, nullptr, ec, nullptr);
|
||||||
|
if (ec) {
|
||||||
|
BOOST_LOG(warning) << "Couldn't open url ["sv << url << "]: System: "sv << ec.message();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BOOST_LOG(info) << "Opened url ["sv << url << "]"sv;
|
||||||
|
child.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
adjust_thread_priority(thread_priority_e priority) {
|
adjust_thread_priority(thread_priority_e priority) {
|
||||||
int win32_priority;
|
int win32_priority;
|
||||||
|
|||||||
@@ -36,42 +36,6 @@ using namespace std::literals;
|
|||||||
// system_tray namespace
|
// system_tray namespace
|
||||||
namespace system_tray {
|
namespace system_tray {
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Open a url in the default web browser.
|
|
||||||
* @param url The url to open.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
open_url(const std::string &url) {
|
|
||||||
boost::filesystem::path working_dir;
|
|
||||||
|
|
||||||
// if windows
|
|
||||||
#if defined(_WIN32)
|
|
||||||
// set working dir to Windows system directory
|
|
||||||
working_dir = boost::filesystem::path(std::getenv("SystemRoot"));
|
|
||||||
|
|
||||||
// this isn't ideal as it briefly shows a command window
|
|
||||||
// but start a command built into cmd, not an executable
|
|
||||||
std::string cmd = R"(cmd /C "start )" + url + R"(")";
|
|
||||||
#elif defined(__linux__) || defined(linux) || defined(__linux)
|
|
||||||
// set working dir to user home directory
|
|
||||||
working_dir = boost::filesystem::path(std::getenv("HOME"));
|
|
||||||
std::string cmd = R"(xdg-open ")" + url + R"(")";
|
|
||||||
#elif defined(__APPLE__) || defined(__MACH__)
|
|
||||||
std::string cmd = R"(open ")" + url + R"(")";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
boost::process::environment _env = boost::this_process::environment();
|
|
||||||
std::error_code ec;
|
|
||||||
auto child = platf::run_command(false, cmd, working_dir, _env, nullptr, ec, nullptr);
|
|
||||||
if (ec) {
|
|
||||||
BOOST_LOG(warning) << "Couldn't open url ["sv << url << "]: System: "sv << ec.message();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
BOOST_LOG(info) << "Opened url ["sv << url << "]"sv;
|
|
||||||
child.detach();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Callback for opening the UI from the system tray.
|
* @brief Callback for opening the UI from the system tray.
|
||||||
* @param item The tray menu item.
|
* @param item The tray menu item.
|
||||||
@@ -79,12 +43,7 @@ namespace system_tray {
|
|||||||
void
|
void
|
||||||
tray_open_ui_cb(struct tray_menu *item) {
|
tray_open_ui_cb(struct tray_menu *item) {
|
||||||
BOOST_LOG(info) << "Opening UI from system tray"sv;
|
BOOST_LOG(info) << "Opening UI from system tray"sv;
|
||||||
|
launch_ui();
|
||||||
// create the url with the port
|
|
||||||
std::string url = "https://localhost:" + std::to_string(map_port(confighttp::PORT_HTTPS));
|
|
||||||
|
|
||||||
// open the url in the default web browser
|
|
||||||
open_url(url);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,7 +52,7 @@ namespace system_tray {
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
tray_donate_github_cb(struct tray_menu *item) {
|
tray_donate_github_cb(struct tray_menu *item) {
|
||||||
open_url("https://github.com/sponsors/LizardByte");
|
platf::open_url("https://github.com/sponsors/LizardByte");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -102,7 +61,7 @@ namespace system_tray {
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
tray_donate_mee6_cb(struct tray_menu *item) {
|
tray_donate_mee6_cb(struct tray_menu *item) {
|
||||||
open_url("https://mee6.xyz/m/804382334370578482");
|
platf::open_url("https://mee6.xyz/m/804382334370578482");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,7 +70,7 @@ namespace system_tray {
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
tray_donate_patreon_cb(struct tray_menu *item) {
|
tray_donate_patreon_cb(struct tray_menu *item) {
|
||||||
open_url("https://www.patreon.com/LizardByte");
|
platf::open_url("https://www.patreon.com/LizardByte");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -120,7 +79,7 @@ namespace system_tray {
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
tray_donate_paypal_cb(struct tray_menu *item) {
|
tray_donate_paypal_cb(struct tray_menu *item) {
|
||||||
open_url("https://www.paypal.com/paypalme/ReenigneArcher");
|
platf::open_url("https://www.paypal.com/paypalme/ReenigneArcher");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user