From 7deeaa06152723723617043ca07882008f48c0ca Mon Sep 17 00:00:00 2001
From: JPersson77 <jorgen.persson@gmail.com>
Date: Mon, 1 Jul 2024 08:31:03 +0200
Subject: [PATCH] Add "delayed" shutdown timing

---
 Common/common_app_define.h                    |   2 +-
 Common/preferences.cpp                        |   8 +++--
 Common/preferences.h                          |   6 +++-
 Common/restart_strings.h                      |   2 ++
 LGTV Companion Service/main.cpp               |   4 +--
 LGTV Companion Setup/Product.wxs              |   2 +-
 LGTV Companion UI/LGTV Companion UI.rc        | Bin 45168 -> 45168 bytes
 LGTV Companion UI/LGTV Companion UI.vcxproj   |   1 +
 .../LGTV Companion UI.vcxproj.filters         |   3 ++
 LGTV Companion UI/lgtv_companion_ui.cpp       |  33 ++++++++++++++----
 LGTV Companion User/Daemon.cpp                |   6 ++++
 11 files changed, 54 insertions(+), 13 deletions(-)

diff --git a/Common/common_app_define.h b/Common/common_app_define.h
index 171a0dd..18a5a70 100644
--- a/Common/common_app_define.h
+++ b/Common/common_app_define.h
@@ -2,7 +2,7 @@
 
 // common application definitions
 #define			APPNAME							L"LGTV Companion"
-#define         APP_VERSION                     L"4.0.3"
+#define         APP_VERSION                     L"4.0.5"
 #define			CONFIG_FILE						L"config.json"
 #define			LOG_FILE						L"log.txt"
 #define			WINDOW_CLASS_UNIQUE				L"YOLOx0x0x0181818"
diff --git a/Common/preferences.cpp b/Common/preferences.cpp
index e71c7bc..1fa19ae 100644
--- a/Common/preferences.cpp
+++ b/Common/preferences.cpp
@@ -34,6 +34,7 @@ using			json = nlohmann::json;
 #define         JSON_EXTERNAL_API				"ExternalAPI"
 #define			JSON_MUTE_SPEAKERS				"MuteSpeakers"
 #define			JSON_TIMING_PRESHUTDOWN			"TimingPreshutdown"
+#define			JSON_TIMING_SHUTDOWN			"TimingShutdown"
 #define			JSON_DEVICE_NAME				"Name"
 #define			JSON_DEVICE_IP					"IP"
 #define			JSON_DEVICE_UNIQUEKEY			"UniqueDeviceKey"
@@ -224,7 +225,10 @@ Preferences::Preferences(std::wstring configuration_file_name)
 					// Shutdown timing
 					j = jsonPrefs[JSON_PREFS_NODE][JSON_TIMING_PRESHUTDOWN];
 					if (!j.empty() && j.is_boolean())
-						preshutdown_timing_ = j.get<bool>();
+						shutdown_timing_ = j.get<bool>() ? 1 : 0;
+					j = jsonPrefs[JSON_PREFS_NODE][JSON_TIMING_SHUTDOWN];
+					if (!j.empty() && j.is_number())
+						shutdown_timing_ = j.get<int>();
 					// User idle mode whitelist
 					j = jsonPrefs[JSON_PREFS_NODE][JSON_WHITELIST];
 					if (!j.empty() && j.size() > 0)
@@ -412,7 +416,7 @@ bool Preferences::Preferences::writeToDisk(void)
 	prefs[JSON_PREFS_NODE][JSON_REMOTESTREAM_MODE] = (bool)remote_streaming_host_prefer_power_off_;
 	prefs[JSON_PREFS_NODE][JSON_EXTERNAL_API] = (bool)external_api_support_;
 	prefs[JSON_PREFS_NODE][JSON_MUTE_SPEAKERS] = (bool)user_idle_mode_mute_speakers_;
-	prefs[JSON_PREFS_NODE][JSON_TIMING_PRESHUTDOWN] = (bool)preshutdown_timing_;
+	prefs[JSON_PREFS_NODE][JSON_TIMING_SHUTDOWN] = (int)shutdown_timing_;
 	
 	if (event_log_restart_strings_custom_.size() > 0)
 		for (auto& item : event_log_restart_strings_custom_)
diff --git a/Common/preferences.h b/Common/preferences.h
index 4b0eb5b..3cce33a 100644
--- a/Common/preferences.h
+++ b/Common/preferences.h
@@ -5,6 +5,10 @@
 #include <nlohmann/json.hpp>
 #include "../Common/device.h"
 
+#define PREFS_SHUTDOWN_TIMING_DEFAULT		0
+#define PREFS_SHUTDOWN_TIMING_EARLY			1
+#define PREFS_SHUTDOWN_TIMING_DELAYED		2
+
 // Preferences management
 class Preferences : public std::enable_shared_from_this<Preferences>
 {
@@ -42,7 +46,7 @@ class Preferences : public std::enable_shared_from_this<Preferences>
 	bool								remote_streaming_host_support_ = false;
 	bool								remote_streaming_host_prefer_power_off_ = true;
 	bool								external_api_support_ = false;
-	bool								preshutdown_timing_ = false;
+	int									shutdown_timing_ = PREFS_SHUTDOWN_TIMING_DEFAULT;
 	std::string							data_path_;
 	std::vector<Device>					devices_;
 	nlohmann::json						lg_api_commands_json;
diff --git a/Common/restart_strings.h b/Common/restart_strings.h
index e066a7e..4b627f2 100644
--- a/Common/restart_strings.h
+++ b/Common/restart_strings.h
@@ -2,6 +2,7 @@ R"(
 {
   "Restart" : [
     "restart",
+    "Redémarrer",
     "redémarrer",
     "starta om",
     "reiniciar",
@@ -40,6 +41,7 @@ R"(
     "shutdown",
     "power off",
     "arrêter",
+    "s’arrêter.",
     "se mettre hors tension",
     "se mettre hors tension.",
     "stäng av",
diff --git a/LGTV Companion Service/main.cpp b/LGTV Companion Service/main.cpp
index da6d6c4..67e54cc 100644
--- a/LGTV Companion Service/main.cpp	
+++ b/LGTV Companion Service/main.cpp	
@@ -353,7 +353,7 @@ VOID SvcReportStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHi
 	context.service_status.dwWaitHint = dwWaitHint;
 	if (dwCurrentState == SERVICE_START_PENDING)
 		context.service_status.dwControlsAccepted = 0;
-	else context.service_status.dwControlsAccepted = context.prefs->preshutdown_timing_ ? SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PRESHUTDOWN | SERVICE_ACCEPT_POWEREVENT : SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT;
+	else context.service_status.dwControlsAccepted = context.prefs->shutdown_timing_ == PREFS_SHUTDOWN_TIMING_EARLY ? SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PRESHUTDOWN | SERVICE_ACCEPT_POWEREVENT : SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT;
 	if ((dwCurrentState == SERVICE_RUNNING) ||
 		(dwCurrentState == SERVICE_STOPPED))
 		context.service_status.dwCheckPoint = 0;
@@ -399,7 +399,7 @@ VOID WINAPI SvcMain(DWORD dwArgc, LPTSTR* lpszArgv)
 		&context,                                           //Context
 		(EVT_SUBSCRIBE_CALLBACK)SvcEventLogSubscribeCallback,            //callback
 		EvtSubscribeToFutureEvents);
-	SetProcessShutdownParameters(prefs.preshutdown_timing_ ? 0x100 : 0x3FF, SHUTDOWN_NORETRY);
+	SetProcessShutdownParameters(prefs.shutdown_timing_ == PREFS_SHUTDOWN_TIMING_EARLY? 0x100 : 0x3FF, SHUTDOWN_NORETRY);
 	SvcReportStatus(SERVICE_RUNNING, NO_ERROR, 0, context);
 	SvcReportEvent(EVENTLOG_INFORMATION_TYPE, L"The service has started.");
 	lgtv_companion.systemEvent(EVENT_SYSTEM_BOOT);
diff --git a/LGTV Companion Setup/Product.wxs b/LGTV Companion Setup/Product.wxs
index a215153..d0e4dab 100644
--- a/LGTV Companion Setup/Product.wxs	
+++ b/LGTV Companion Setup/Product.wxs	
@@ -3,7 +3,7 @@
 <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" 
      xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
   <?define LGTV Companion Service_TargetDir=$(var.LGTV Companion Service.TargetDir)?><?define LGTV Companion UI_TargetDir=$(var.LGTV Companion UI.TargetDir)?>
-	<Product Id="524C2902-608C-467D-8A87-0F2638E5888A" Name="LGTV Companion" Language="1033" Version="4.0.3" Manufacturer="J Persson" UpgradeCode="0BA17E5B-11CE-491D-B1A1-05DD2D9F610A">
+	<Product Id="D86DF48E-4ECE-4248-9C66-C971B8C44FB7" Name="LGTV Companion" Language="1033" Version="4.0.5" Manufacturer="J Persson" UpgradeCode="0BA17E5B-11CE-491D-B1A1-05DD2D9F610A">
 		<Package Id="*" InstallerVersion="301" Compressed="yes" InstallScope="perMachine" Platform='x64' Description="LGTV Companion installer" InstallPrivileges="elevated" AdminImage="yes"/>
     <Media Id="1" Cabinet="LGTVapp.cab" EmbedCab="yes" />
 
diff --git a/LGTV Companion UI/LGTV Companion UI.rc b/LGTV Companion UI/LGTV Companion UI.rc
index 1ee298380dee3f244b3c8c72e1b835b01ec9ee82..a6bbeb32e2f6026821de4930fb0414966a4b278e 100644
GIT binary patch
delta 47
zcmezHfa${nrVYOg_{|th7<3pc7)*hrIfLQkM3ae=KZsauzG7$~&TPzJxS8EEGaUeh
CT@L5~

delta 47
zcmezHfa${nrVYOg_{|wi7<3pc7)*hr8H3^EM3ae=KZsauzG7$~&TPV9vYFj8GaUeh
CgAVKf

diff --git a/LGTV Companion UI/LGTV Companion UI.vcxproj b/LGTV Companion UI/LGTV Companion UI.vcxproj
index 1b8cf5c..2cc40a6 100644
--- a/LGTV Companion UI/LGTV Companion UI.vcxproj	
+++ b/LGTV Companion UI/LGTV Companion UI.vcxproj	
@@ -160,6 +160,7 @@
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\Common\ipc.cpp" />
+    <ClCompile Include="..\Common\log.cpp" />
     <ClCompile Include="..\Common\preferences.cpp" />
     <ClCompile Include="..\Common\tools.cpp" />
     <ClCompile Include="lgtv_companion_ui.cpp" />
diff --git a/LGTV Companion UI/LGTV Companion UI.vcxproj.filters b/LGTV Companion UI/LGTV Companion UI.vcxproj.filters
index 78fb311..09bc2bb 100644
--- a/LGTV Companion UI/LGTV Companion UI.vcxproj.filters	
+++ b/LGTV Companion UI/LGTV Companion UI.vcxproj.filters	
@@ -53,6 +53,9 @@
     <ClCompile Include="..\Common\tools.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\Common\log.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="LGTV Companion UI.rc">
diff --git a/LGTV Companion UI/lgtv_companion_ui.cpp b/LGTV Companion UI/lgtv_companion_ui.cpp
index 73e4ca6..6fd97e3 100644
--- a/LGTV Companion UI/lgtv_companion_ui.cpp	
+++ b/LGTV Companion UI/lgtv_companion_ui.cpp	
@@ -97,6 +97,7 @@ COPYRIGHT
 #include <Iphlpapi.h>
 #include <ws2tcpip.h>
 #include "resource.h"
+#include "../Common/log.h"
 
 #pragma comment(lib, "Comctl32.lib")
 #pragma comment(lib, "wevtapi.lib")
@@ -161,6 +162,7 @@ bool									ResetAPIkeys = false;
 std::vector<Preferences::ProcessList>	WhitelistTemp;
 std::vector<Preferences::ProcessList>	ExclusionsTemp;
 std::shared_ptr<IpcClient>				pPipeClient;
+std::shared_ptr<Logging>				logger;
 
 Preferences								Prefs(CONFIG_FILE);
 
@@ -209,6 +211,10 @@ int APIENTRY wWinMain(_In_ HINSTANCE Instance,
 	}
 	Prefs.topology_support_ = bTop ? Prefs.topology_support_ : false;
 
+	std::wstring file = tools::widen(Prefs.data_path_);
+	file += L"ui_log.txt";
+	logger = std::make_shared<Logging>(0, file);
+
 	// Initiate PipeClient IPC
 	pPipeClient = std::make_shared<IpcClient>(PIPENAME, ipcCallback, (LPVOID)NULL);
 
@@ -1429,7 +1435,9 @@ LRESULT CALLBACK WndOptionsProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l
 		SendMessage(GetDlgItem(hWnd, IDC_COMBO_TIMING), (UINT)CB_ADDSTRING, (WPARAM)0, (LPARAM)s.c_str());
 		s = L"Early";
 		SendMessage(GetDlgItem(hWnd, IDC_COMBO_TIMING), (UINT)CB_ADDSTRING, (WPARAM)0, (LPARAM)s.c_str());
-		SendMessage(GetDlgItem(hWnd, IDC_COMBO_TIMING), (UINT)CB_SETCURSEL, (WPARAM)Prefs.preshutdown_timing_ ? 1 : 0, (LPARAM)0);
+		s = L"Delayed";
+		SendMessage(GetDlgItem(hWnd, IDC_COMBO_TIMING), (UINT)CB_ADDSTRING, (WPARAM)0, (LPARAM)s.c_str());
+		SendMessage(GetDlgItem(hWnd, IDC_COMBO_TIMING), (UINT)CB_SETCURSEL, (WPARAM)Prefs.shutdown_timing_, (LPARAM)0);
 
 		SendMessage(GetDlgItem(hWnd, IDC_COMBO_LOG), (UINT)CB_RESETCONTENT, (WPARAM)0, (LPARAM)0);
 		s = L"Off";
@@ -1681,10 +1689,12 @@ LRESULT CALLBACK WndOptionsProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l
 						Prefs.remote_streaming_host_prefer_power_off_ = true;
 
 					int selection_timing = (int)(SendMessage(GetDlgItem(hWnd, IDC_COMBO_TIMING), (UINT)CB_GETCURSEL, (WPARAM)0, (LPARAM)0));
-					if (selection_timing == 1)
-						Prefs.preshutdown_timing_ = true;
+					if (selection_timing == 2)
+						Prefs.shutdown_timing_ = PREFS_SHUTDOWN_TIMING_DELAYED; 
+					else if (selection_timing == 1)
+						Prefs.shutdown_timing_ = PREFS_SHUTDOWN_TIMING_EARLY;
 					else
-						Prefs.preshutdown_timing_ = false;
+						Prefs.shutdown_timing_ = PREFS_SHUTDOWN_TIMING_DEFAULT;
 
 					int count = ListView_GetItemCount(GetDlgItem(hWnd, IDC_LIST));
 					Prefs.event_log_restart_strings_custom_.clear();
@@ -3060,6 +3070,7 @@ static BOOL CALLBACK meproc(HMONITOR hMonitor, HDC hdc, LPRECT lprcMonitor, LPAR
 	ZeroMemory(&mi, sizeof(mi));
 	mi.cbSize = sizeof(mi);
 	GetMonitorInfo(hMonitor, &mi);
+	logger->debug("Topology", "callback...");
 	isError = GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &requiredPaths, &requiredModes);
 	if (isError)
 	{
@@ -3069,6 +3080,7 @@ static BOOL CALLBACK meproc(HMONITOR hMonitor, HDC hdc, LPRECT lprcMonitor, LPAR
 	paths.resize(requiredPaths);
 	modes.resize(requiredModes);
 
+	logger->debug("Topology", "QueryDisplayConfig");
 	isError = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &requiredPaths, paths.data(), &requiredModes, modes.data(), NULL);
 	if (isError)
 	{
@@ -3077,6 +3089,7 @@ static BOOL CALLBACK meproc(HMONITOR hMonitor, HDC hdc, LPRECT lprcMonitor, LPAR
 	}
 	paths.resize(requiredPaths);
 	modes.resize(requiredModes);
+	logger->debug("Topology", "Iterate paths");
 
 	for (auto& p : paths)
 	{
@@ -3088,6 +3101,12 @@ static BOOL CALLBACK meproc(HMONITOR hMonitor, HDC hdc, LPRECT lprcMonitor, LPAR
 		sourceName.header.id = p.sourceInfo.id;
 
 		DisplayConfigGetDeviceInfo(&sourceName.header);
+		std::wstring logmessage = L"monitorinfo: ";
+		logmessage += mi.szDevice;
+		logger->debug("Topology", tools::narrow(logmessage));
+		logmessage = L"source: ";
+		logmessage += sourceName.viewGdiDeviceName;
+		logger->debug("Topology", tools::narrow(logmessage));
 		if (wcscmp(mi.szDevice, sourceName.viewGdiDeviceName) == 0)
 		{
 			DISPLAYCONFIG_TARGET_DEVICE_NAME name;
@@ -3096,11 +3115,13 @@ static BOOL CALLBACK meproc(HMONITOR hMonitor, HDC hdc, LPRECT lprcMonitor, LPAR
 			name.header.adapterId = p.sourceInfo.adapterId;
 			name.header.id = p.targetInfo.id;
 			DisplayConfigGetDeviceInfo(&name.header);
-
 			std::wstring FriendlyName = tools::tolower(name.monitorFriendlyDeviceName);
-//			transform(FriendlyName.begin(), FriendlyName.end(), FriendlyName.begin(), ::tolower);
+			logmessage = L"friendly name: ";
+			logmessage += FriendlyName;
+			logger->debug("Topology", tools::narrow(logmessage));
 			if (FriendlyName.find(L"lg tv") != std::wstring::npos)
 			{
+				logger->debug("Topology", "Match!");
 				DisplayInfo di;
 				di.monitorinfo = mi;
 				di.hMonitor = hMonitor;
diff --git a/LGTV Companion User/Daemon.cpp b/LGTV Companion User/Daemon.cpp
index 3862d1f..1136264 100644
--- a/LGTV Companion User/Daemon.cpp	
+++ b/LGTV Companion User/Daemon.cpp	
@@ -667,6 +667,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 		default:break;
 		}
 	}break;
+	case WM_QUERYENDSESSION:
+	{
+		if(Prefs.shutdown_timing_ == PREFS_SHUTDOWN_TIMING_DELAYED)
+			Sleep(1500);
+		return false; // because it is a dialog
+	}break;
 	case WM_POWERBROADCAST:
 	{
 		switch (wParam)